Polite typechecking for test and edit expressions. Helps catch errors in
[platform/upstream/fontconfig.git] / src / fcname.c
1 /*
2  * $RCSId: xc/lib/fontconfig/src/fcname.c,v 1.15 2002/09/26 00:17:28 keithp Exp $
3  *
4  * Copyright © 2000 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 <ctype.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <stdio.h>
29 #include "fcint.h"
30
31 static const FcObjectType _FcBaseObjectTypes[] = {
32     { FC_FAMILY,        FcTypeString, },
33     { FC_FAMILYLANG,    FcTypeString, },
34     { FC_STYLE,         FcTypeString, },
35     { FC_STYLELANG,     FcTypeString, },
36     { FC_FULLNAME,      FcTypeString, },
37     { FC_FULLNAMELANG,  FcTypeString, },
38     { FC_SLANT,         FcTypeInteger, },
39     { FC_WEIGHT,        FcTypeInteger, },
40     { FC_WIDTH,         FcTypeInteger, },
41     { FC_SIZE,          FcTypeDouble, },
42     { FC_ASPECT,        FcTypeDouble, },
43     { FC_PIXEL_SIZE,    FcTypeDouble, },
44     { FC_SPACING,       FcTypeInteger, },
45     { FC_FOUNDRY,       FcTypeString, },
46 /*    { FC_CORE,                FcTypeBool, }, */
47     { FC_ANTIALIAS,     FcTypeBool, },
48     { FC_HINT_STYLE,    FcTypeInteger, },
49     { FC_HINTING,       FcTypeBool, },
50     { FC_VERTICAL_LAYOUT,   FcTypeBool, },
51     { FC_AUTOHINT,      FcTypeBool, },
52     { FC_GLOBAL_ADVANCE,    FcTypeBool, },
53 /*    { FC_XLFD,                FcTypeString, }, */
54     { FC_FILE,          FcTypeString, },
55     { FC_INDEX,         FcTypeInteger, },
56     { FC_RASTERIZER,    FcTypeString, },
57     { FC_OUTLINE,       FcTypeBool, },
58     { FC_SCALABLE,      FcTypeBool, },
59     { FC_DPI,           FcTypeDouble },
60     { FC_RGBA,          FcTypeInteger, },
61     { FC_SCALE,         FcTypeDouble, },
62 /*    { FC_RENDER,      FcTypeBool, },*/
63     { FC_MINSPACE,      FcTypeBool, },
64     { FC_CHAR_WIDTH,    FcTypeInteger },
65     { FC_CHAR_HEIGHT,   FcTypeInteger },
66     { FC_MATRIX,        FcTypeMatrix },
67     { FC_CHARSET,       FcTypeCharSet },
68     { FC_LANG,          FcTypeLangSet },
69     { FC_FONTVERSION,   FcTypeInteger },
70     { FC_CAPABILITY,    FcTypeString },
71     { FC_FONTFORMAT,    FcTypeString },
72 };
73
74 #define NUM_OBJECT_TYPES    (sizeof _FcBaseObjectTypes / sizeof _FcBaseObjectTypes[0])
75
76 typedef struct _FcObjectTypeList    FcObjectTypeList;
77
78 struct _FcObjectTypeList {
79     const FcObjectTypeList  *next;
80     const FcObjectType      *types;
81     int                     ntypes;
82 };
83
84 static const FcObjectTypeList _FcBaseObjectTypesList = {
85     0,
86     _FcBaseObjectTypes,
87     NUM_OBJECT_TYPES
88 };
89
90 static const FcObjectTypeList   *_FcObjectTypes = &_FcBaseObjectTypesList;
91
92 FcBool
93 FcNameRegisterObjectTypes (const FcObjectType *types, int ntypes)
94 {
95     FcObjectTypeList    *l;
96
97     l = (FcObjectTypeList *) malloc (sizeof (FcObjectTypeList));
98     if (!l)
99         return FcFalse;
100     FcMemAlloc (FC_MEM_OBJECTTYPE, sizeof (FcObjectTypeList));
101     l->types = types;
102     l->ntypes = ntypes;
103     l->next = _FcObjectTypes;
104     _FcObjectTypes = l;
105     return FcTrue;
106 }
107
108 FcBool
109 FcNameUnregisterObjectTypes (const FcObjectType *types, int ntypes)
110 {
111     const FcObjectTypeList      *l, **prev;
112
113     for (prev = &_FcObjectTypes; 
114          (l = *prev); 
115          prev = (const FcObjectTypeList **) &(l->next))
116     {
117         if (l->types == types && l->ntypes == ntypes)
118         {
119             *prev = l->next;
120             FcMemFree (FC_MEM_OBJECTTYPE, sizeof (FcObjectTypeList));
121             free ((void *) l);
122             return FcTrue;
123         }
124     }
125     return FcFalse;
126 }
127
128 const FcObjectType *
129 FcNameGetObjectType (const char *object)
130 {
131     int                     i;
132     const FcObjectTypeList  *l;
133     const FcObjectType      *t;
134     
135     for (l = _FcObjectTypes; l; l = l->next)
136     {
137         for (i = 0; i < l->ntypes; i++)
138         {
139             t = &l->types[i];
140             if (!strcmp (object, t->object))
141                 return t;
142         }
143     }
144     return 0;
145 }
146
147 static const FcConstant _FcBaseConstants[] = {
148     { (FcChar8 *) "thin",           "weight",   FC_WEIGHT_THIN, },
149     { (FcChar8 *) "extralight",     "weight",   FC_WEIGHT_EXTRALIGHT, },
150     { (FcChar8 *) "ultralight",     "weight",   FC_WEIGHT_EXTRALIGHT, },
151     { (FcChar8 *) "light",          "weight",   FC_WEIGHT_LIGHT, },
152     { (FcChar8 *) "book",           "weight",   FC_WEIGHT_BOOK, },
153     { (FcChar8 *) "regular",        "weight",   FC_WEIGHT_REGULAR, },
154     { (FcChar8 *) "medium",         "weight",   FC_WEIGHT_MEDIUM, },
155     { (FcChar8 *) "demibold",       "weight",   FC_WEIGHT_DEMIBOLD, },
156     { (FcChar8 *) "semibold",       "weight",   FC_WEIGHT_DEMIBOLD, },
157     { (FcChar8 *) "bold",           "weight",   FC_WEIGHT_BOLD, },
158     { (FcChar8 *) "extrabold",      "weight",   FC_WEIGHT_EXTRABOLD, },
159     { (FcChar8 *) "ultrabold",      "weight",   FC_WEIGHT_EXTRABOLD, },
160     { (FcChar8 *) "black",          "weight",   FC_WEIGHT_BLACK, },
161
162     { (FcChar8 *) "roman",          "slant",    FC_SLANT_ROMAN, },
163     { (FcChar8 *) "italic",         "slant",    FC_SLANT_ITALIC, },
164     { (FcChar8 *) "oblique",        "slant",    FC_SLANT_OBLIQUE, },
165
166     { (FcChar8 *) "ultracondensed", "width",    FC_WIDTH_ULTRACONDENSED },
167     { (FcChar8 *) "extracondensed", "width",    FC_WIDTH_EXTRACONDENSED },
168     { (FcChar8 *) "condensed",      "width",    FC_WIDTH_CONDENSED },
169     { (FcChar8 *) "semicondensed", "width",     FC_WIDTH_SEMICONDENSED },
170     { (FcChar8 *) "normal",         "width",    FC_WIDTH_NORMAL },
171     { (FcChar8 *) "semiexpanded",   "width",    FC_WIDTH_SEMIEXPANDED },
172     { (FcChar8 *) "expanded",       "width",    FC_WIDTH_EXPANDED },
173     { (FcChar8 *) "extraexpanded",  "width",    FC_WIDTH_EXTRAEXPANDED },
174     { (FcChar8 *) "ultraexpanded",  "width",    FC_WIDTH_ULTRAEXPANDED },
175     
176     { (FcChar8 *) "proportional",   "spacing",  FC_PROPORTIONAL, },
177     { (FcChar8 *) "dual",           "spacing",  FC_DUAL, },
178     { (FcChar8 *) "mono",           "spacing",  FC_MONO, },
179     { (FcChar8 *) "charcell",       "spacing",  FC_CHARCELL, },
180
181     { (FcChar8 *) "unknown",        "rgba",         FC_RGBA_UNKNOWN },
182     { (FcChar8 *) "rgb",            "rgba",         FC_RGBA_RGB, },
183     { (FcChar8 *) "bgr",            "rgba",         FC_RGBA_BGR, },
184     { (FcChar8 *) "vrgb",           "rgba",         FC_RGBA_VRGB },
185     { (FcChar8 *) "vbgr",           "rgba",         FC_RGBA_VBGR },
186     { (FcChar8 *) "none",           "rgba",         FC_RGBA_NONE },
187
188     { (FcChar8 *) "hintnone",       "hintstyle",   FC_HINT_NONE },
189     { (FcChar8 *) "hintslight",     "hintstyle",   FC_HINT_SLIGHT },
190     { (FcChar8 *) "hintmedium",     "hintstyle",   FC_HINT_MEDIUM },
191     { (FcChar8 *) "hintfull",       "hintstyle",   FC_HINT_FULL },
192 };
193
194 #define NUM_FC_CONSTANTS   (sizeof _FcBaseConstants/sizeof _FcBaseConstants[0])
195
196 typedef struct _FcConstantList FcConstantList;
197
198 struct _FcConstantList {
199     const FcConstantList    *next;
200     const FcConstant        *consts;
201     int                     nconsts;
202 };
203
204 static const FcConstantList _FcBaseConstantList = {
205     0,
206     _FcBaseConstants,
207     NUM_FC_CONSTANTS
208 };
209
210 static const FcConstantList     *_FcConstants = &_FcBaseConstantList;
211
212 FcBool
213 FcNameRegisterConstants (const FcConstant *consts, int nconsts)
214 {
215     FcConstantList      *l;
216
217     l = (FcConstantList *) malloc (sizeof (FcConstantList));
218     if (!l)
219         return FcFalse;
220     FcMemAlloc (FC_MEM_CONSTANT, sizeof (FcConstantList));
221     l->consts = consts;
222     l->nconsts = nconsts;
223     l->next = _FcConstants;
224     _FcConstants = l;
225     return FcTrue;
226 }
227
228 FcBool
229 FcNameUnregisterConstants (const FcConstant *consts, int nconsts)
230 {
231     const FcConstantList        *l, **prev;
232
233     for (prev = &_FcConstants; 
234          (l = *prev); 
235          prev = (const FcConstantList **) &(l->next))
236     {
237         if (l->consts == consts && l->nconsts == nconsts)
238         {
239             *prev = l->next;
240             FcMemFree (FC_MEM_CONSTANT, sizeof (FcConstantList));
241             free ((void *) l);
242             return FcTrue;
243         }
244     }
245     return FcFalse;
246 }
247
248 const FcConstant *
249 FcNameGetConstant (FcChar8 *string)
250 {
251     const FcConstantList    *l;
252     int                     i;
253
254     for (l = _FcConstants; l; l = l->next)
255     {
256         for (i = 0; i < l->nconsts; i++)
257             if (!FcStrCmpIgnoreCase (string, l->consts[i].name))
258                 return &l->consts[i];
259     }
260     return 0;
261 }
262
263 FcBool
264 FcNameConstant (FcChar8 *string, int *result)
265 {
266     const FcConstant    *c;
267
268     if ((c = FcNameGetConstant(string)))
269     {
270         *result = c->value;
271         return FcTrue;
272     }
273     return FcFalse;
274 }
275
276 FcBool
277 FcNameBool (const FcChar8 *v, FcBool *result)
278 {
279     char    c0, c1;
280
281     c0 = *v;
282     c0 = FcToLower (c0);
283     if (c0 == 't' || c0 == 'y' || c0 == '1')
284     {
285         *result = FcTrue;
286         return FcTrue;
287     }
288     if (c0 == 'f' || c0 == 'n' || c0 == '0')
289     {
290         *result = FcFalse;
291         return FcTrue;
292     }
293     if (c0 == 'o')
294     {
295         c1 = v[1];
296         c1 = FcToLower (c1);
297         if (c1 == 'n')
298         {
299             *result = FcTrue;
300             return FcTrue;
301         }
302         if (c1 == 'f')
303         {
304             *result = FcFalse;
305             return FcTrue;
306         }
307     }
308     return FcFalse;
309 }
310
311 static FcValue
312 FcNameConvert (FcType type, FcChar8 *string, FcMatrix *m)
313 {
314     FcValue     v;
315
316     v.type = type;
317     switch (v.type) {
318     case FcTypeInteger:
319         if (!FcNameConstant (string, &v.u.i))
320             v.u.i = atoi ((char *) string);
321         break;
322     case FcTypeString:
323         v.u.s = string;
324         break;
325     case FcTypeBool:
326         if (!FcNameBool (string, &v.u.b))
327             v.u.b = FcFalse;
328         break;
329     case FcTypeDouble:
330         v.u.d = strtod ((char *) string, 0);
331         break;
332     case FcTypeMatrix:
333         v.u.m = m;
334         sscanf ((char *) string, "%lg %lg %lg %lg", &m->xx, &m->xy, &m->yx, &m->yy);
335         break;
336     case FcTypeCharSet:
337         v.u.c = FcNameParseCharSet (string);
338         break;
339     case FcTypeLangSet:
340         v.u.l = FcNameParseLangSet (string);
341         break;
342     default:
343         break;
344     }
345     return v;
346 }
347
348 static const FcChar8 *
349 FcNameFindNext (const FcChar8 *cur, const char *delim, FcChar8 *save, FcChar8 *last)
350 {
351     FcChar8    c;
352     
353     while ((c = *cur))
354     {
355         if (c == '\\')
356         {
357             ++cur;
358             if (!(c = *cur))
359                 break;
360         }
361         else if (strchr (delim, c))
362             break;
363         ++cur;
364         *save++ = c;
365     }
366     *save = 0;
367     *last = *cur;
368     if (*cur)
369         cur++;
370     return cur;
371 }
372
373 FcPattern *
374 FcNameParse (const FcChar8 *name)
375 {
376     FcChar8             *save;
377     FcPattern           *pat;
378     double              d;
379     FcChar8             *e;
380     FcChar8             delim;
381     FcValue             v;
382     FcMatrix            m;
383     const FcObjectType  *t;
384     const FcConstant    *c;
385
386     /* freed below */
387     save = malloc (strlen ((char *) name) + 1);
388     if (!save)
389         goto bail0;
390     pat = FcPatternCreate ();
391     if (!pat)
392         goto bail1;
393
394     for (;;)
395     {
396         name = FcNameFindNext (name, "-,:", save, &delim);
397         if (save[0])
398         {
399             if (!FcPatternAddString (pat, FC_FAMILY, save))
400                 goto bail2;
401         }
402         if (delim != ',')
403             break;
404     }
405     if (delim == '-')
406     {
407         for (;;)
408         {
409             name = FcNameFindNext (name, "-,:", save, &delim);
410             d = strtod ((char *) save, (char **) &e);
411             if (e != save)
412             {
413                 if (!FcPatternAddDouble (pat, FC_SIZE, d))
414                     goto bail2;
415             }
416             if (delim != ',')
417                 break;
418         }
419     }
420     while (delim == ':')
421     {
422         name = FcNameFindNext (name, "=_:", save, &delim);
423         if (save[0])
424         {
425             if (delim == '=' || delim == '_')
426             {
427                 t = FcNameGetObjectType ((char *) save);
428                 for (;;)
429                 {
430                     name = FcNameFindNext (name, ":,", save, &delim);
431                     if (t)
432                     {
433                         v = FcNameConvert (t->type, save, &m);
434                         if (!FcPatternAdd (pat, t->object, v, FcTrue))
435                         {
436                             switch (v.type) {
437                             case FcTypeCharSet:
438                                 FcCharSetDestroy ((FcCharSet *) v.u.c);
439                                 break;
440                             case FcTypeLangSet:
441                                 FcLangSetDestroy ((FcLangSet *) v.u.l);
442                                 break;
443                             default:
444                                 break;
445                             }
446                             goto bail2;
447                         }
448                         switch (v.type) {
449                         case FcTypeCharSet:
450                             FcCharSetDestroy ((FcCharSet *) v.u.c);
451                             break;
452                         case FcTypeLangSet:
453                             FcLangSetDestroy ((FcLangSet *) v.u.l);
454                             break;
455                         default:
456                             break;
457                         }
458                     }
459                     if (delim != ',')
460                         break;
461                 }
462             }
463             else
464             {
465                 if ((c = FcNameGetConstant (save)))
466                 {
467                     if (!FcPatternAddInteger (pat, c->object, c->value))
468                         goto bail2;
469                 }
470             }
471         }
472     }
473
474     free (save);
475     return pat;
476
477 bail2:
478     FcPatternDestroy (pat);
479 bail1:
480     free (save);
481 bail0:
482     return 0;
483 }
484 static FcBool
485 FcNameUnparseString (FcStrBuf       *buf, 
486                      const FcChar8  *string,
487                      const FcChar8  *escape)
488 {
489     FcChar8 c;
490     while ((c = *string++))
491     {
492         if (escape && strchr ((char *) escape, (char) c))
493         {
494             if (!FcStrBufChar (buf, escape[0]))
495                 return FcFalse;
496         }
497         if (!FcStrBufChar (buf, c))
498             return FcFalse;
499     }
500     return FcTrue;
501 }
502
503 static FcBool
504 FcNameUnparseValue (FcStrBuf    *buf,
505                     FcValue     v,
506                     FcChar8     *escape)
507 {
508     FcChar8     temp[1024];
509     
510     switch (v.type) {
511     case FcTypeVoid:
512         return FcTrue;
513     case FcTypeInteger:
514         sprintf ((char *) temp, "%d", v.u.i);
515         return FcNameUnparseString (buf, temp, 0);
516     case FcTypeDouble:
517         sprintf ((char *) temp, "%g", v.u.d);
518         return FcNameUnparseString (buf, temp, 0);
519     case FcTypeString:
520         return FcNameUnparseString (buf, v.u.s, escape);
521     case FcTypeBool:
522         return FcNameUnparseString (buf, v.u.b ? (FcChar8 *) "True" : (FcChar8 *) "False", 0);
523     case FcTypeMatrix:
524         sprintf ((char *) temp, "%g %g %g %g", 
525                  v.u.m->xx, v.u.m->xy, v.u.m->yx, v.u.m->yy);
526         return FcNameUnparseString (buf, temp, 0);
527     case FcTypeCharSet:
528         return FcNameUnparseCharSet (buf, v.u.c);
529     case FcTypeLangSet:
530         return FcNameUnparseLangSet (buf, v.u.l);
531     case FcTypeFTFace:
532         return FcTrue;
533     }
534     return FcFalse;
535 }
536
537 static FcBool
538 FcNameUnparseValueList (FcStrBuf        *buf,
539                         FcValueList     *v,
540                         FcChar8         *escape)
541 {
542     while (v)
543     {
544         if (!FcNameUnparseValue (buf, v->value, escape))
545             return FcFalse;
546         if ((v = v->next))
547             if (!FcNameUnparseString (buf, (FcChar8 *) ",", 0))
548                 return FcFalse;
549     }
550     return FcTrue;
551 }
552
553 #define FC_ESCAPE_FIXED    "\\-:,"
554 #define FC_ESCAPE_VARIABLE "\\=_:,"
555
556 FcChar8 *
557 FcNameUnparse (FcPattern *pat)
558 {
559     FcStrBuf                buf;
560     FcChar8                 buf_static[8192];
561     int                     i;
562     FcPatternElt            *e;
563     const FcObjectTypeList  *l;
564     const FcObjectType      *o;
565
566     FcStrBufInit (&buf, buf_static, sizeof (buf_static));
567     e = FcPatternFindElt (pat, FC_FAMILY);
568     if (e)
569     {
570         if (!FcNameUnparseValueList (&buf, e->values, (FcChar8 *) FC_ESCAPE_FIXED))
571             goto bail0;
572     }
573     e = FcPatternFindElt (pat, FC_SIZE);
574     if (e)
575     {
576         if (!FcNameUnparseString (&buf, (FcChar8 *) "-", 0))
577             goto bail0;
578         if (!FcNameUnparseValueList (&buf, e->values, (FcChar8 *) FC_ESCAPE_FIXED))
579             goto bail0;
580     }
581     for (l = _FcObjectTypes; l; l = l->next)
582     {
583         for (i = 0; i < l->ntypes; i++)
584         {
585             o = &l->types[i];
586             if (!strcmp (o->object, FC_FAMILY) || 
587                 !strcmp (o->object, FC_SIZE) ||
588                 !strcmp (o->object, FC_FILE))
589                 continue;
590             
591             e = FcPatternFindElt (pat, o->object);
592             if (e)
593             {
594                 if (!FcNameUnparseString (&buf, (FcChar8 *) ":", 0))
595                     goto bail0;
596                 if (!FcNameUnparseString (&buf, (FcChar8 *) o->object, (FcChar8 *) FC_ESCAPE_VARIABLE))
597                     goto bail0;
598                 if (!FcNameUnparseString (&buf, (FcChar8 *) "=", 0))
599                     goto bail0;
600                 if (!FcNameUnparseValueList (&buf, e->values, 
601                                              (FcChar8 *) FC_ESCAPE_VARIABLE))
602                     goto bail0;
603             }
604         }
605     }
606     return FcStrBufDone (&buf);
607 bail0:
608     FcStrBufDestroy (&buf);
609     return 0;
610 }