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