Build AFM data for core PostScript fonts into WINEPS.
[wine] / dlls / wineps / mkagl.c
1 #include <sys/types.h>
2 #include <dirent.h>
3 #include <string.h>
4 #include <malloc.h>
5 #include <stdlib.h>
6 #include <stdio.h>
7 #include <ctype.h>
8
9
10 /*
11  *  The array of glyph information
12  */
13  
14 typedef struct
15 {
16     int         UV;
17     int         index;          /* in PSDRV_AGLGlyphNames */
18     const char  *name;
19     const char  *comment;
20
21 } GLYPHINFO;
22
23 static GLYPHINFO    glyphs[1500];
24 static int          num_glyphs = 0;
25
26
27 /*
28  *  Functions to search and sort the array
29  */
30  
31 static int cmp_by_UV(const void *a, const void *b)
32 {
33     return ((const GLYPHINFO *)a)->UV - ((const GLYPHINFO *)b)->UV;
34 }
35
36 static int cmp_by_name(const void *a, const void *b)
37 {
38     return strcmp(((const GLYPHINFO *)a)->name, ((const GLYPHINFO *)b)->name);
39 }
40
41 inline static void sort_by_UV()
42 {
43     qsort(glyphs, num_glyphs, sizeof(GLYPHINFO), cmp_by_UV);
44 }
45
46 inline static void sort_by_name()
47 {
48     qsort(glyphs, num_glyphs, sizeof(GLYPHINFO), cmp_by_name);
49 }
50
51 inline static GLYPHINFO *search_by_name(const char *name)
52 {
53     GLYPHINFO   gi;
54     
55     gi.name = name;
56     
57     return (GLYPHINFO *)bsearch(&gi, glyphs, num_glyphs, sizeof(GLYPHINFO),
58             cmp_by_name);
59 }
60
61
62 /*
63  *  Use the 'optimal' combination of tabs and spaces to position the cursor
64  */
65  
66 inline static void fcpto(FILE *f, int newpos, int curpos)
67 {
68     int newtpos = newpos & ~7;
69     int curtpos = curpos & ~7;
70     
71     while (curtpos < newtpos)
72     {
73         fputc('\t', f);
74         curtpos += 8;
75         curpos = curtpos;
76     }
77     
78     while (curpos < newpos)
79     {
80         fputc(' ', f);
81         ++curpos;
82     }
83 }
84
85 inline static void cpto(int newpos, int curpos)
86 {
87     fcpto(stdout, newpos, curpos);
88 }
89
90
91 /*
92  *  Make main() look "purty"
93  */
94  
95 inline static void double_space(FILE *f)
96 {
97     fputc('\n', f);
98 }
99
100 inline static void triple_space(FILE *f)
101 {
102     fputc('\n', f);  fputc('\n', f);
103 }
104
105
106 /*
107  *  Read the Adobe Glyph List from 'glyphlist.txt'
108  */
109  
110 static void read_agl()
111 {
112     FILE    *f = fopen("glyphlist.txt", "r");
113     char    linebuf[256], namebuf[128], commbuf[128];
114     
115     if (f == NULL)
116     {
117         fprintf(stderr, "Error opening glyphlist.txt\n");
118         exit(__LINE__);
119     }
120     
121     while (fgets(linebuf, sizeof(linebuf), f) != NULL)
122     {
123         unsigned int    UV;
124     
125         if (linebuf[0] == '#')
126             continue;
127             
128         sscanf(linebuf, "%X;%[^;];%[^\n]", &UV, namebuf, commbuf);
129         
130         glyphs[num_glyphs].UV = (int)UV;
131         glyphs[num_glyphs].name = strdup(namebuf);
132         glyphs[num_glyphs].comment = strdup(commbuf);
133         
134         if (glyphs[num_glyphs].name == NULL ||
135                 glyphs[num_glyphs].comment == NULL)
136         {
137             fprintf(stderr, "Memory allocation failure\n");
138             exit(__LINE__);
139         }
140         
141         ++num_glyphs;
142     }
143     
144     fclose(f);
145     
146     if (num_glyphs != 1051)
147     {
148         fprintf(stderr, "Read %i glyphs\n", num_glyphs);
149         exit(__LINE__);
150     }
151 }
152
153
154 /*
155  *  Read glyph names from all AFM files in current directory
156  */
157  
158 static void read_afms()
159 {
160     DIR             *d = opendir(".");
161     struct dirent   *de;
162     
163     if (d == NULL)
164     {
165         fprintf(stderr, "Error opening current directory\n");
166         exit(__LINE__);
167     }
168     
169     while ((de = readdir(d)) != NULL)
170     {
171         FILE    *f;
172         char    *cp, linebuf[256], font_family[128];
173         int     i, num_metrics;
174         
175         cp = strrchr(de->d_name, '.');                  /* Does it end in   */
176         if (cp == NULL || strcasecmp(cp, ".afm") != 0)  /*   .afm or .AFM?  */
177             continue;
178             
179         f = fopen(de->d_name, "r");
180         if (f == NULL)
181         {
182             fprintf(stderr, "Error opening %s\n", de->d_name);
183             exit(__LINE__);
184         }
185         
186         while (1)
187         {
188             if (fgets(linebuf, sizeof(linebuf), f) == NULL)
189             {
190                 fprintf(stderr, "FamilyName not found in %s\n", de->d_name);
191                 exit(__LINE__);
192             }
193             
194             if (strncmp(linebuf, "FamilyName ", 11) == 0)
195                 break;
196         }
197         
198         sscanf(linebuf, "FamilyName %[^\r\n]", font_family);
199         
200         while (1)
201         {
202             if (fgets(linebuf, sizeof(linebuf), f) == NULL)
203             {
204                 fprintf(stderr, "StartCharMetrics not found in %s\n",
205                         de->d_name);
206                 exit(__LINE__);
207             }
208             
209             if (strncmp(linebuf, "StartCharMetrics ", 17) == 0)
210                 break;
211         }
212         
213         sscanf(linebuf, "StartCharMetrics %i", &num_metrics);
214         
215         for (i = 0; i < num_metrics; ++i)
216         {
217             char    namebuf[128];
218         
219             if (fgets(linebuf, sizeof(linebuf), f) == NULL)
220             {
221                 fprintf(stderr, "Unexpected EOF after %i glyphs in %s\n", i,
222                         de->d_name);
223                 exit(__LINE__);
224             }
225             
226             cp = strchr(linebuf, 'N');
227             if (cp == NULL || strlen(cp) < 3)
228             {
229                 fprintf(stderr, "Parse error after %i glyphs in %s\n", i,
230                         de->d_name);
231                 exit(__LINE__);
232             }
233             
234             sscanf(cp, "N %s", namebuf);
235             if (search_by_name(namebuf) != NULL)
236                 continue;
237                 
238             sprintf(linebuf, "FONT FAMILY;%s", font_family);
239                 
240             glyphs[num_glyphs].UV = -1;
241             glyphs[num_glyphs].name = strdup(namebuf);
242             glyphs[num_glyphs].comment = strdup(linebuf);
243             
244             if (glyphs[num_glyphs].name == NULL ||
245                     glyphs[num_glyphs].comment == NULL)
246             {
247                 fprintf(stderr, "Memory allocation failure\n");
248                 exit(__LINE__);
249             }
250             
251             ++num_glyphs;
252             
253             sort_by_name();
254         }
255         
256         fclose(f);
257     }
258     
259     closedir(d);
260 }
261
262
263 /*
264  *  Write opening comments, etc.
265  */
266  
267 static void write_header(FILE *f)
268 {
269     int i;
270
271     fputc('/', f);
272     for (i = 0; i < 79; ++i)
273         fputc('*', f);
274     fputs("\n"
275             " *\n"
276             " *\tAdobe Glyph List data for the Wine PostScript driver\n"
277             " *\n"
278             " *\tCopyright 2001 Ian Pilcher\n"
279             " *\n"
280             " *\n"
281             " *\tThis data is derived from the Adobe Glyph list at\n"
282             " *\n"
283             " *\t    "
284             "http://partners.adobe.com/asn/developer/type/glyphlist.txt\n"
285             " *\n"
286             " *\tand the Adobe Font Metrics files at\n"
287             " *\n"
288             " *\t    "
289             "ftp://ftp.adobe.com/pub/adobe/type/win/all/afmfiles/base35/\n"
290             " *\n"
291             " *\twhich are Copyright 1985-1998 Adobe Systems Incorporated.\n"
292             " *\n"
293             " */\n"
294             "\n"
295             "#include \"psdrv.h\"\n", f);
296 }
297
298 /*
299  *  Write the array of GLYPHNAME structures (also populates indexes)
300  */
301  
302 static void write_glyph_names(FILE *f)
303 {
304     int i, num_names = 0, index = 0;
305     
306     for (i = 0; i < num_glyphs; ++i)
307         if (i == 0 || strcmp(glyphs[i - 1].name, glyphs[i].name) != 0)
308             ++num_names;
309     
310     fputs(  "/*\n"
311             " *  Every glyph name in the AGL and the 39 core PostScript fonts\n"
312             " */\n"
313             "\n", f);
314             
315     fprintf(f, "const INT PSDRV_AGLGlyphNamesSize = %i;\n\n", num_names);
316     
317     fprintf(f, "GLYPHNAME PSDRV_AGLGlyphNames[%i] =\n{\n", num_names);
318     
319     for (i = 0; i < num_glyphs - 1; ++i)
320     {
321         int cp = 0;
322         
323         if (i == 0 || strcmp(glyphs[i - 1].name, glyphs[i].name) != 0)
324         {
325             cp = fprintf(f, "    { -1, \"%s\" },", glyphs[i].name);
326             glyphs[i].index = index;
327             ++index;
328         }
329         else
330         {
331             glyphs[i].index = index - 1;
332         }
333         
334         fcpto(f, 36, cp);
335         
336         fprintf(f, "/* %s */\n", glyphs[i].comment);
337     }
338     
339     glyphs[i].index = index;
340     fcpto(f, 36, fprintf(f, "    { -1, \"%s\" }", glyphs[i].name));
341     fprintf(f, "/* %s */\n};\n", glyphs[i].comment);
342 }
343
344
345 /*
346  *  Write the AGL encoding vector
347  */
348  
349 static void write_encoding(FILE *f)
350 {
351     int i, size = 0;
352     
353     for (i = 0; i < num_glyphs; ++i)
354         if (glyphs[i].UV != -1)
355             ++size;                     /* better be 1051! */
356             
357     sort_by_UV();
358             
359     fputs(  "/*\n"
360             " *  The AGL encoding vector, sorted by Unicode value\n"
361             " */\n"
362             "\n", f);
363             
364     fprintf(f, "static const UNICODEGLYPH encoding[%i] = \n{\n", size);
365     
366     for (i = 0; i < num_glyphs - 1; ++i)
367     {
368         if (glyphs[i].UV == -1)
369             continue;
370             
371         fprintf(f, "    { 0x%.4x, PSDRV_AGLGlyphNames + %4i },\t/* %s */\n",
372                 glyphs[i].UV, glyphs[i].index, glyphs[i].name);
373     }
374     
375     fprintf(f, "    { 0x%.4x, PSDRV_AGLGlyphNames + %4i }\t/* %s */\n};\n\n",
376             glyphs[i].UV, glyphs[i].index, glyphs[i].name);
377             
378     fprintf(f, "UNICODEVECTOR PSDRV_AdobeGlyphList = { %i, encoding };\n",
379             size);
380 }
381     
382
383 /*
384  *  Do it!
385  */
386  
387 int main(int argc, char *argv[])
388 {
389     FILE    *f;
390
391     read_agl();
392     read_afms();
393     
394     if (argc < 2)
395     {
396         f = stdout;
397     }
398     else
399     {
400         f = fopen(argv[1], "w");
401         if (f == NULL)
402         {
403             fprintf(stderr, "Error opening %s for writing\n", argv[1]);
404             exit(__LINE__);
405         }
406     }
407     
408     write_header(f);
409     triple_space(f);
410     write_glyph_names(f);
411     triple_space(f);
412     write_encoding(f);
413     
414     return 0;
415 }