Fix compiler warnings
[platform/upstream/fontconfig.git] / fc-lang / fc-lang.c
1 /*
2  * fontconfig/fc-lang/fc-lang.c
3  *
4  * Copyright © 2002 Keith Packard
5  *
6  * Permission to use, copy, modify, distribute, and sell this software and its
7  * documentation for any purpose is hereby granted without fee, provided that
8  * the above copyright notice appear in all copies and that both that
9  * copyright notice and this permission notice appear in supporting
10  * documentation, and that the name of Keith Packard not be used in
11  * advertising or publicity pertaining to distribution of the software without
12  * specific, written prior permission.  Keith Packard makes no
13  * representations about the suitability of this software for any purpose.  It
14  * is provided "as is" without express or implied warranty.
15  *
16  * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18  * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR
19  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
20  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
21  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
22  * PERFORMANCE OF THIS SOFTWARE.
23  */
24
25 #include "fccharset.c"
26 #include "fcstr.c"
27 #include "fcserialize.c"
28
29 /*
30  * fc-lang
31  *
32  * Read a set of language orthographies and build C declarations for
33  * charsets which can then be used to identify which languages are
34  * supported by a given font.  Note that this uses some utilities
35  * from the fontconfig library, so the necessary file is simply
36  * included in this compilation.  A couple of extra utility
37  * functions are also needed in slightly modified form
38  */
39
40 void
41 FcMemAlloc (int kind, int size)
42 {
43 }
44
45 void
46 FcMemFree (int kind, int size)
47 {
48 }
49
50 FcPrivate void
51 FcCacheObjectReference (void *object)
52 {
53 }
54
55 FcPrivate void
56 FcCacheObjectDereference (void *object)
57 {
58 }
59
60 int FcDebugVal;
61
62 FcChar8 *
63 FcConfigHome (void)
64 {
65     return (FcChar8 *) getenv ("HOME");
66 }
67
68 static void 
69 fatal (const char *file, int lineno, const char *msg)
70 {
71     if (lineno)
72         fprintf (stderr, "%s:%d: %s\n", file, lineno, msg);
73     else
74         fprintf (stderr, "%s: %s\n", file, msg);
75     exit (1);
76 }
77
78 static char *
79 get_line (FILE *f, char *line, int *lineno)
80 {
81     char    *hash;
82     int     end;
83     if (!fgets (line, 1024, f))
84         return 0;
85     ++(*lineno);
86     hash = strchr (line, '#');
87     if (hash)
88         *hash = '\0';
89
90     end = strlen (line);
91     while (end > 0 && isspace (line[end-1]))
92       line[--end] = '\0';
93
94     if (line[0] == '\0' || line[0] == '\n' || line[0] == '\032' || line[0] == '\r')
95         return get_line (f, line, lineno);
96     return line;
97 }
98
99 static char     *dir = 0;
100
101 static FILE *
102 scanopen (char *file)
103 {
104     FILE    *f;
105
106     f = fopen (file, "r");
107     if (!f && dir)
108     {
109         char    path[1024];
110         
111         strcpy (path, dir);
112         strcat (path, "/");
113         strcat (path, file);
114         f = fopen (path, "r");
115     }
116     return f;
117 }
118
119 /*
120  * build a single charset from a source file
121  *
122  * The file format is quite simple, either
123  * a single hex value or a pair separated with a dash
124  *
125  * Comments begin with '#'
126  */
127
128 static const FcCharSet *
129 scan (FILE *f, char *file, FcCharSetFreezer *freezer)
130 {
131     FcCharSet       *c = 0;
132     FcCharSet       *n;
133     int             start, end, ucs4;
134     char            line[1024];
135     int             lineno = 0;
136
137     while (get_line (f, line, &lineno))
138     {
139         if (!strncmp (line, "include", 7))
140         {
141             FILE *included_f;
142             char *included_file;
143             included_file = strchr (line, ' ');
144             if (!included_file)
145                 fatal (file, lineno,
146                        "invalid syntax, expected: include filename");
147             while (isspace(*included_file))
148                 included_file++;
149             included_f = scanopen (included_file);
150             if (!included_f)
151                 fatal (included_file, 0, "can't open");
152             n = scan (included_f, included_file, freezer);
153             fclose (included_f);
154             if (!c)
155                 c = FcCharSetCreate ();
156             if (!FcCharSetMerge (c, n, NULL))
157                 fatal (file, lineno, "out of memory");
158             FcCharSetDestroy (n);
159             continue;
160         }
161         if (strchr (line, '-'))
162         {
163             if (sscanf (line, "%x-%x", &start, &end) != 2)
164                 fatal (file, lineno, "parse error");
165         }
166         else
167         {
168             if (sscanf (line, "%x", &start) != 1)
169                 fatal (file, lineno, "parse error");
170             end = start;
171         }
172         if (!c)
173             c = FcCharSetCreate ();
174         for (ucs4 = start; ucs4 <= end; ucs4++)
175         {
176             if (!FcCharSetAddChar (c, ucs4))
177                 fatal (file, lineno, "out of memory");
178         }
179     }
180     n = FcCharSetFreeze (freezer, c);
181     FcCharSetDestroy (c);
182     return n;
183 }
184
185 /*
186  * Convert a file name into a name suitable for C declarations
187  */
188 static char *
189 get_name (char *file)
190 {
191     char    *name;
192     char    *dot;
193
194     dot = strchr (file, '.');
195     if (!dot)
196         dot = file + strlen(file);
197     name = malloc (dot - file + 1);
198     strncpy (name, file, dot - file);
199     name[dot-file] = '\0';
200     return name;
201 }
202
203 /*
204  * Convert a C name into a language name
205  */
206 static char *
207 get_lang (char *name)
208 {
209     char    *lang = malloc (strlen (name) + 1);
210     char    *l = lang;
211     char    c;
212
213     while ((c = *name++))
214     {
215         if (isupper ((int) (unsigned char) c))
216             c = tolower ((int) (unsigned char) c);
217         if (c == '_')
218             c = '-';
219         if (c == ' ')
220             continue;
221         *l++ = c;
222     }
223     *l++ = '\0';
224     return lang;
225 }
226
227 typedef struct _Entry {
228     int id;
229     char *file;
230 } Entry;
231
232 static int compare (const void *a, const void *b)
233 {
234     const Entry const *as = a, *bs = b;
235     return FcStrCmpIgnoreCase (as->file, bs->file);
236 }
237
238 #define MAX_LANG            1024
239 #define MAX_LANG_SET_MAP    ((MAX_LANG + 31) / 32)
240
241 #define BitSet(map, i)   ((map)[(entries[i].id)>>5] |= ((FcChar32) 1 << ((entries[i].id) & 0x1f)))
242 #define BitGet(map, i)   ((map)[(entries[i].id)>>5] >> ((entries[i].id) & 0x1f)) & 1)
243
244 int
245 main (int argc, char **argv)
246 {
247     static Entry        entries[MAX_LANG];
248     static const FcCharSet      *sets[MAX_LANG];
249     static int          duplicate[MAX_LANG];
250     static int          country[MAX_LANG];
251     static char         *names[MAX_LANG];
252     static char         *langs[MAX_LANG];
253     static int          off[MAX_LANG];
254     FILE        *f;
255     int         ncountry = 0;
256     int         i = 0;
257     int         nsets = 0;
258     int         argi;
259     FcCharLeaf  **leaves;
260     int         total_leaves = 0;
261     int         l, sl, tl, tn;
262     static char         line[1024];
263     static FcChar32     map[MAX_LANG_SET_MAP];
264     int         num_lang_set_map;
265     int         setRangeStart[26];
266     int         setRangeEnd[26];
267     FcChar8     setRangeChar;
268     FcCharSetFreezer    *freezer;
269     
270     freezer = FcCharSetFreezerCreate ();
271     if (!freezer)
272         fatal (argv[0], 0, "out of memory");
273     argi = 1;
274     while (argv[argi])
275     {
276         if (!strcmp (argv[argi], "-d"))
277         {
278             argi++;
279             dir = argv[argi++];
280             continue;
281         }
282         if (i == MAX_LANG)
283             fatal (argv[0], 0, "Too many languages");
284         entries[i].id = i;
285         entries[i].file = argv[argi++];
286         i++;
287     }
288     entries[i].file = 0;
289     qsort (entries, i, sizeof (Entry), compare);
290     i = 0;
291     while (entries[i].file)
292     {
293         f = scanopen (entries[i].file);
294         if (!f)
295             fatal (entries[i].file, 0, strerror (errno));
296         sets[i] = scan (f, entries[i].file, freezer);
297         names[i] = get_name (entries[i].file);
298         langs[i] = get_lang(names[i]);
299         if (strchr (langs[i], '-'))
300             country[ncountry++] = i;
301
302         total_leaves += sets[i]->num;
303         i++;
304         fclose (f);
305     }
306     nsets = i;
307     sets[i] = 0;
308     leaves = malloc (total_leaves * sizeof (FcCharLeaf *));
309     tl = 0;
310     /*
311      * Find unique leaves
312      */
313     for (i = 0; sets[i]; i++)
314     {
315         for (sl = 0; sl < sets[i]->num; sl++)
316         {
317             for (l = 0; l < tl; l++)
318                 if (leaves[l] == FcCharSetLeaf(sets[i], sl))
319                     break;
320             if (l == tl)
321                 leaves[tl++] = FcCharSetLeaf(sets[i], sl);
322         }
323     }
324
325     /*
326      * Scan the input until the marker is found
327      */
328     
329     while (fgets (line, sizeof (line), stdin))
330     {
331         if (!strncmp (line, "@@@", 3))
332             break;
333         fputs (line, stdout);
334     }
335     
336     printf ("/* total size: %d unique leaves: %d */\n\n",
337             total_leaves, tl);
338
339     /*
340      * Find duplicate charsets
341      */
342     duplicate[0] = -1;
343     for (i = 1; sets[i]; i++)
344     {
345         int j;
346
347         duplicate[i] = -1;
348         for (j = 0; j < i; j++)
349             if (sets[j] == sets[i])
350             {
351                 duplicate[i] = j;
352                 break;
353             }
354     }
355
356     tn = 0;
357     for (i = 0; sets[i]; i++) {
358         if (duplicate[i] >= 0)
359             continue;
360         off[i] = tn;
361         tn += sets[i]->num;
362     }
363
364     printf ("#define LEAF0       (%d * sizeof (FcLangCharSet))\n", nsets);
365     printf ("#define OFF0        (LEAF0 + %d * sizeof (FcCharLeaf))\n", tl);
366     printf ("#define NUM0        (OFF0 + %d * sizeof (uintptr_t))\n", tn);
367     printf ("#define SET(n)      (n * sizeof (FcLangCharSet) + offsetof (FcLangCharSet, charset))\n");
368     printf ("#define OFF(s,o)    (OFF0 + o * sizeof (uintptr_t) - SET(s))\n");
369     printf ("#define NUM(s,n)    (NUM0 + n * sizeof (FcChar16) - SET(s))\n");
370     printf ("#define LEAF(o,l)   (LEAF0 + l * sizeof (FcCharLeaf) - (OFF0 + o * sizeof (intptr_t)))\n");
371     printf ("#define fcLangCharSets (fcLangData.langCharSets)\n");
372     printf ("#define fcLangCharSetIndices (fcLangData.langIndices)\n");
373     printf ("#define fcLangCharSetIndicesInv (fcLangData.langIndicesInv)\n");
374     printf ("\n");
375     
376     printf ("static const struct {\n"
377             "    FcLangCharSet  langCharSets[%d];\n"
378             "    FcCharLeaf     leaves[%d];\n"
379             "    uintptr_t      leaf_offsets[%d];\n"
380             "    FcChar16       numbers[%d];\n"
381             "    FcChar%s       langIndices[%d];\n"
382             "    FcChar%s       langIndicesInv[%d];\n"
383             "} fcLangData = {\n",
384             nsets, tl, tn, tn,
385             nsets < 256 ? "8 " : "16", nsets, nsets < 256 ? "8 " : "16", nsets);
386         
387     /*
388      * Dump sets
389      */
390
391     printf ("{\n");
392     for (i = 0; sets[i]; i++)
393     {
394         int     j = duplicate[i];
395
396         if (j < 0)
397             j = i;
398
399         printf ("    { \"%s\", "
400                 " { FC_REF_CONSTANT, %d, OFF(%d,%d), NUM(%d,%d) } }, /* %d */\n",
401                 langs[i],
402                 sets[j]->num, i, off[j], i, off[j], i);
403     }
404     printf ("},\n");
405     
406     /*
407      * Dump leaves
408      */
409     printf ("{\n");
410     for (l = 0; l < tl; l++)
411     {
412         printf ("    { { /* %d */", l);
413         for (i = 0; i < 256/32; i++)
414         {
415             if (i % 4 == 0)
416                 printf ("\n   ");
417             printf (" 0x%08x,", leaves[l]->map[i]);
418         }
419         printf ("\n    } },\n");
420     }
421     printf ("},\n");
422
423     /*
424      * Dump leaves
425      */
426     printf ("{\n");
427     for (i = 0; sets[i]; i++)
428     {
429         int n;
430         
431         if (duplicate[i] >= 0)
432             continue;
433         printf ("    /* %s */\n", names[i]);
434         for (n = 0; n < sets[i]->num; n++)
435         {
436             if (n % 4 == 0)
437                 printf ("   ");
438             for (l = 0; l < tl; l++)
439                 if (leaves[l] == FcCharSetLeaf(sets[i], n))
440                     break;
441             if (l == tl)
442                 fatal (names[i], 0, "can't find leaf");
443             printf (" LEAF(%3d,%3d),", off[i], l);
444             if (n % 4 == 3)
445                 printf ("\n");
446         }
447         if (n % 4 != 0)
448             printf ("\n");
449     }
450     printf ("},\n");
451         
452
453     printf ("{\n");
454     for (i = 0; sets[i]; i++)
455     {
456         int n;
457         
458         if (duplicate[i] >= 0)
459             continue;
460         printf ("    /* %s */\n", names[i]);
461         for (n = 0; n < sets[i]->num; n++)
462         {
463             if (n % 8 == 0)
464                 printf ("   ");
465             printf (" 0x%04x,", FcCharSetNumbers (sets[i])[n]);
466             if (n % 8 == 7)
467                 printf ("\n");
468         }
469         if (n % 8 != 0)
470             printf ("\n");
471     }
472     printf ("},\n");
473
474     /* langIndices */
475     printf ("{\n");
476     for (i = 0; sets[i]; i++)
477     {
478         printf ("    %d, /* %s */\n", entries[i].id, names[i]);
479     }
480     printf ("},\n");
481
482     /* langIndicesInv */
483     printf ("{\n");
484     {
485         static int              entries_inv[MAX_LANG];
486         for (i = 0; sets[i]; i++)
487           entries_inv[entries[i].id] = i;
488         for (i = 0; sets[i]; i++)
489             printf ("    %d, /* %s */\n", entries_inv[i], names[entries_inv[i]]);
490     }
491     printf ("}\n");
492
493     printf ("};\n\n");
494
495     printf ("#define NUM_LANG_CHAR_SET  %d\n", i);
496     num_lang_set_map = (i + 31) / 32;
497     printf ("#define NUM_LANG_SET_MAP   %d\n", num_lang_set_map);
498     /*
499      * Dump indices with country codes
500      */
501     if (ncountry)
502     {
503         int     c;
504         int     ncountry_ent = 0;
505         printf ("\n");
506         printf ("static const FcChar32 fcLangCountrySets[][NUM_LANG_SET_MAP] = {\n");
507         for (c = 0; c < ncountry; c++)
508         {
509             i = country[c];
510             if (i >= 0)
511             {
512                 int lang = strchr (langs[i], '-') - langs[i];
513                 int d, k;
514
515                 for (k = 0; k < num_lang_set_map; k++)
516                     map[k] = 0;
517
518                 BitSet (map, i);
519                 for (d = c + 1; d < ncountry; d++)
520                 {
521                     int j = country[d];
522                     if (j >= 0 && !strncmp (langs[j], langs[i], lang + 1))
523                     {
524                         BitSet(map, j);
525                         country[d] = -1;
526                     }
527                 }
528                 printf ("    {");
529                 for (k = 0; k < num_lang_set_map; k++)
530                     printf (" 0x%08x,", map[k]);
531                 printf (" }, /* %*.*s */\n",
532                         lang, lang, langs[i]);
533                 ++ncountry_ent;
534             }
535         }
536         printf ("};\n\n");
537         printf ("#define NUM_COUNTRY_SET %d\n", ncountry_ent);
538     }
539     
540
541     /*
542      * Find ranges for each letter for faster searching
543      */
544     setRangeChar = 'a';
545     memset(setRangeStart, '\0', sizeof (setRangeStart));
546     memset(setRangeEnd, '\0', sizeof (setRangeEnd));
547     for (i = 0; sets[i]; i++)
548     {
549         char    c = names[i][0];
550         
551         while (setRangeChar <= c && c <= 'z')
552             setRangeStart[setRangeChar++ - 'a'] = i;
553     }
554     for (setRangeChar = 'a'; setRangeChar < 'z'; setRangeChar++)
555         setRangeEnd[setRangeChar - 'a'] = setRangeStart[setRangeChar+1-'a'] - 1;
556     setRangeEnd[setRangeChar - 'a'] = i - 1;
557     
558     /*
559      * Dump sets start/finish for the fastpath
560      */
561     printf ("\n");
562     printf ("static const FcLangCharSetRange  fcLangCharSetRanges[] = {\n");
563         printf ("\n");
564     for (setRangeChar = 'a'; setRangeChar <= 'z' ; setRangeChar++)
565     {
566         printf ("    { %d, %d }, /* %c */\n",
567                 setRangeStart[setRangeChar - 'a'],
568                 setRangeEnd[setRangeChar - 'a'], setRangeChar);
569     }
570     printf ("};\n\n");
571  
572     while (fgets (line, sizeof (line), stdin))
573         fputs (line, stdout);
574     
575     fflush (stdout);
576     exit (ferror (stdout));
577 }