Fix more gcc4 warnings:
[platform/upstream/fontconfig.git] / fc-lang / fc-lang.c
1 /*
2  * $RCSId: xc/lib/fontconfig/fc-lang/fc-lang.c,v 1.3 2002/08/22 07:36:43 keithp Exp $
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  * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18  * EVENT SHALL KEITH PACKARD 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 "fcint.h"
26 #include "fccharset.c"
27 #include "fcstr.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 int
51 FcCacheBankToIndex (int bank)
52 {
53     return -1;
54 }
55
56 FcChar8 *
57 FcConfigHome (void)
58 {
59     return (FcChar8 *) getenv ("HOME");
60 }
61
62 static void 
63 fatal (const char *file, int lineno, const char *msg)
64 {
65     if (lineno)
66         fprintf (stderr, "%s:%d: %s\n", file, lineno, msg);
67     else
68         fprintf (stderr, "%s:%d: %s\n", file, lineno, msg);
69     exit (1);
70 }
71
72 static char *
73 get_line (FILE *f, char *line, int *lineno)
74 {
75     char    *hash;
76     if (!fgets (line, 1024, f))
77         return 0;
78     ++(*lineno);
79     hash = strchr (line, '#');
80     if (hash)
81         *hash = '\0';
82     if (line[0] == '\0' || line[0] == '\n' || line[0] == '\032' || line[0] == '\r')
83         return get_line (f, line, lineno);
84     return line;
85 }
86
87 char    *dir = 0;
88
89 static FILE *
90 scanopen (char *file)
91 {
92     FILE    *f;
93
94     f = fopen (file, "r");
95     if (!f && dir)
96     {
97         char    path[1024];
98         
99         strcpy (path, dir);
100         strcat (path, "/");
101         strcat (path, file);
102         f = fopen (path, "r");
103     }
104     return f;
105 }
106
107 /*
108  * build a single charset from a source file
109  *
110  * The file format is quite simple, either
111  * a single hex value or a pair separated with a dash
112  *
113  * Comments begin with '#'
114  */
115
116 static FcCharSet *
117 scan (FILE *f, char *file)
118 {
119     FcCharSet   *c = 0;
120     FcCharSet   *n;
121     int         start, end, ucs4;
122     char        line[1024];
123     int         lineno = 0;
124
125     while (get_line (f, line, &lineno))
126     {
127         if (!strncmp (line, "include", 7))
128         {
129             file = strchr (line, ' ');
130             while (*file == ' ')
131                 file++;
132             end = strlen (file);
133             if (file[end-1] == '\n')
134                 file[end-1] = '\0';
135             f = scanopen (file);
136             if (!f)
137                 fatal (file, 0, "can't open");
138             c = scan (f, file);
139             fclose (f);
140             return c;
141         }
142         if (strchr (line, '-'))
143         {
144             if (sscanf (line, "%x-%x", &start, &end) != 2)
145                 fatal (file, lineno, "parse error");
146         }
147         else
148         {
149             if (sscanf (line, "%x", &start) != 1)
150                 fatal (file, lineno, "parse error");
151             end = start;
152         }
153         if (!c)
154             c = FcCharSetCreate ();
155         for (ucs4 = start; ucs4 <= end; ucs4++)
156         {
157             if (!FcCharSetAddChar (c, ucs4))
158                 fatal (file, lineno, "out of memory");
159         }
160     }
161     n = FcCharSetFreeze (c);
162     FcCharSetDestroy (c);
163     return n;
164 }
165
166 /*
167  * Convert a file name into a name suitable for C declarations
168  */
169 static char *
170 get_name (char *file)
171 {
172     char    *name;
173     char    *dot;
174
175     dot = strchr (file, '.');
176     if (!dot)
177         dot = file + strlen(file);
178     name = malloc (dot - file + 1);
179     strncpy (name, file, dot - file);
180     name[dot-file] = '\0';
181     return name;
182 }
183
184 /*
185  * Convert a C name into a language name
186  */
187 static char *
188 get_lang (char *name)
189 {
190     char    *lang = malloc (strlen (name) + 1);
191     char    *l = lang;
192     char    c;
193
194     while ((c = *name++))
195     {
196         if (isupper ((int) (unsigned char) c))
197             c = tolower ((int) (unsigned char) c);
198         if (c == '_')
199             c = '-';
200         if (c == ' ')
201             continue;
202         *l++ = c;
203     }
204     *l++ = '\0';
205     return lang;
206 }
207
208 static int compare (const void *a, const void *b)
209 {
210     const FcChar8    *const *as = a, *const *bs = b;
211     return FcStrCmpIgnoreCase (*as, *bs);
212 }
213
214 #define MAX_LANG            1024
215 #define MAX_LANG_SET_MAP    ((MAX_LANG + 31) / 32)
216
217 #define BitSet(map, id)   ((map)[(id)>>5] |= ((FcChar32) 1 << ((id) & 0x1f)))
218 #define BitGet(map, id)   ((map)[(id)>>5] >> ((id) & 0x1f)) & 1)
219
220 int
221 main (int argc, char **argv)
222 {
223     char        *files[MAX_LANG];
224     FcCharSet   *sets[MAX_LANG];
225     int         duplicate[MAX_LANG];
226     int         country[MAX_LANG];
227     char        *names[MAX_LANG];
228     char        *langs[MAX_LANG];
229     FILE        *f;
230     int         ncountry = 0;
231     int         i = 0;
232     int         argi;
233     FcCharLeaf  **leaves;
234     int         total_leaves = 0;
235     int         l, sl, tl;
236     int         c;
237     char        line[1024];
238     FcChar32    map[MAX_LANG_SET_MAP];
239     int         num_lang_set_map;
240     int         setRangeStart[26];
241     int         setRangeEnd[26];
242     FcChar8     setRangeChar;
243     
244     argi = 1;
245     while (argv[argi])
246     {
247         if (!strcmp (argv[argi], "-d"))
248         {
249             argi++;
250             dir = argv[argi++];
251             continue;
252         }
253         if (i == MAX_LANG)
254             fatal (argv[0], 0, "Too many languages");
255         files[i++] = argv[argi++];
256     }
257     files[i] = 0;
258     qsort (files, i, sizeof (char *), compare);
259     i = 0;
260     while (files[i])
261     {
262         f = scanopen (files[i]);
263         if (!f)
264             fatal (files[i], 0, strerror (errno));
265         sets[i] = scan (f, files[i]);
266         names[i] = get_name (files[i]);
267         langs[i] = get_lang(names[i]);
268         if (strchr (langs[i], '-'))
269             country[ncountry++] = i;
270
271         total_leaves += sets[i]->num;
272         i++;
273         fclose (f);
274     }
275     sets[i] = 0;
276     leaves = malloc (total_leaves * sizeof (FcCharLeaf *));
277     tl = 0;
278     /*
279      * Find unique leaves
280      */
281     for (i = 0; sets[i]; i++)
282     {
283         for (sl = 0; sl < sets[i]->num; sl++)
284         {
285             for (l = 0; l < tl; l++)
286                 if (leaves[l] == FcCharSetGetLeaf(sets[i], sl))
287                     break;
288             if (l == tl)
289                 leaves[tl++] = FcCharSetGetLeaf(sets[i], sl);
290         }
291     }
292
293     /*
294      * Scan the input until the marker is found
295      */
296     
297     while (fgets (line, sizeof (line), stdin))
298     {
299         if (!strncmp (line, "@@@", 3))
300             break;
301         fputs (line, stdout);
302     }
303     
304     printf ("/* total size: %d unique leaves: %d */\n\n",
305             total_leaves, tl);
306     /*
307      * Dump leaves
308      */
309     printf ("static const FcCharLeaf    leaves[%d] = {\n", tl);
310     for (l = 0; l < tl; l++)
311     {
312         printf ("    { { /* %d */", l);
313         for (i = 0; i < 256/32; i++)
314         {
315             if (i % 4 == 0)
316                 printf ("\n   ");
317             printf (" 0x%08x,", leaves[l]->map[i]);
318         }
319         printf ("\n    } },\n");
320     }
321     printf ("};\n\n");
322     printf ("#define L(n) ((FcCharLeaf *) &leaves[n])\n\n");
323
324     /*
325      * Find duplicate charsets
326      */
327     duplicate[0] = -1;
328     for (i = 1; sets[i]; i++)
329     {
330         int j;
331
332         duplicate[i] = -1;
333         for (j = 0; j < i; j++)
334             if (sets[j] == sets[i])
335             {
336                 duplicate[i] = j;
337                 break;
338             }
339     }
340
341     /*
342      * Find ranges for each letter for faster searching
343      */
344     setRangeChar = 'a';
345     for (i = 0; sets[i]; i++)
346     {
347         char    c = names[i][0];
348         
349         while (setRangeChar <= c && c <= 'z')
350             setRangeStart[setRangeChar++ - 'a'] = i;
351     }
352     for (setRangeChar = 'a'; setRangeChar < 'z'; setRangeChar++)
353         setRangeEnd[setRangeChar - 'a'] = setRangeStart[setRangeChar+1-'a'] - 1;
354     setRangeEnd[setRangeChar - 'a'] = i - 1;
355     
356     /*
357      * Dump arrays
358      */
359     for (i = 0; sets[i]; i++)
360     {
361         int n;
362         
363         if (duplicate[i] >= 0)
364             continue;
365         printf ("static const FcCharLeaf *leaves_%s[%d] = {\n",
366                 names[i], sets[i]->num);
367         for (n = 0; n < sets[i]->num; n++)
368         {
369             if (n % 8 == 0)
370                 printf ("   ");
371             for (l = 0; l < tl; l++)
372                 if (leaves[l] == FcCharSetGetLeaf(sets[i], n))
373                     break;
374             if (l == tl)
375                 fatal (names[i], 0, "can't find leaf");
376             printf (" L(%3d),", l);
377             if (n % 8 == 7)
378                 printf ("\n");
379         }
380         if (n % 8 != 0)
381             printf ("\n");
382         printf ("};\n\n");
383         
384
385         printf ("static const FcChar16 numbers_%s[%d] = {\n",
386                 names[i], sets[i]->num);
387         for (n = 0; n < sets[i]->num; n++)
388         {
389             if (n % 8 == 0)
390                 printf ("   ");
391             printf (" 0x%04x,", FcCharSetGetNumbers(sets[i])[n]);
392             if (n % 8 == 7)
393                 printf ("\n");
394         }
395         if (n % 8 != 0)
396             printf ("\n");
397         printf ("};\n\n");
398     }
399     printf ("#undef L\n\n");
400     
401     /*
402      * Dump sets
403      */
404
405     printf ("static const FcLangCharSet  fcLangCharSets[] = {\n");
406     for (i = 0; sets[i]; i++)
407     {
408         int     j = duplicate[i];
409
410         if (j < 0)
411             j = i;
412         printf ("    { (FcChar8 *) \"%s\",\n"
413                 "      { FC_REF_CONSTANT, %d, FC_BANK_DYNAMIC, "
414                 "{ { (FcCharLeaf **) leaves_%s, "
415                 "(FcChar16 *) numbers_%s } } } },\n",
416                 langs[i],
417                 sets[j]->num, names[j], names[j]);
418     }
419     printf ("};\n\n");
420     printf ("#define NUM_LANG_CHAR_SET  %d\n", i);
421     num_lang_set_map = (i + 31) / 32;
422     printf ("#define NUM_LANG_SET_MAP   %d\n", num_lang_set_map);
423     /*
424      * Dump indices with country codes
425      */
426     if (ncountry)
427     {
428         int     ncountry_ent = 0;
429         printf ("\n");
430         printf ("static const FcChar32 fcLangCountrySets[][NUM_LANG_SET_MAP] = {\n");
431         for (c = 0; c < ncountry; c++)
432         {
433             i = country[c];
434             if (i >= 0)
435             {
436                 int l = strchr (langs[i], '-') - langs[i];
437                 int d, k;
438
439                 for (k = 0; k < num_lang_set_map; k++)
440                     map[k] = 0;
441
442                 BitSet (map, i);
443                 for (d = c + 1; d < ncountry; d++)
444                 {
445                     int j = country[d];
446                     if (j >= 0 && !strncmp (langs[j], langs[i], l))
447                     {
448                         BitSet(map, j);
449                         country[d] = -1;
450                     }
451                 }
452                 printf ("    {");
453                 for (k = 0; k < num_lang_set_map; k++)
454                     printf (" 0x%08x,", map[k]);
455                 printf (" }, /* %*.*s */\n",
456                         l, l, langs[i]);
457                 ++ncountry_ent;
458             }
459         }
460         printf ("};\n\n");
461         printf ("#define NUM_COUNTRY_SET %d\n", ncountry_ent);
462     }
463     
464
465     /*
466      * Dump sets start/finish for the fastpath
467      */
468     printf ("static const FcLangCharSetRange  fcLangCharSetRanges[] = {\n");
469     for (setRangeChar = 'a'; setRangeChar <= 'z' ; setRangeChar++)
470     {
471         printf ("    { %d, %d }, /* %c */\n",
472                 setRangeStart[setRangeChar - 'a'],
473                 setRangeEnd[setRangeChar - 'a'], setRangeChar);
474     }
475     printf ("};\n\n");
476  
477     while (fgets (line, sizeof (line), stdin))
478         fputs (line, stdout);
479     
480     fflush (stdout);
481     exit (ferror (stdout));
482 }