Fix sign-compare warnings
[platform/upstream/fontconfig.git] / src / fcname.c
1 /*
2  * fontconfig/src/fcname.c
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 the author(s) not be used in
11  * advertising or publicity pertaining to distribution of the software without
12  * specific, written prior permission.  The authors make 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 "fcint.h"
26 #include <ctype.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <stdio.h>
30
31 /*
32  * Please do not change this list, it is used to initialize the object
33  * list in this order to match the FC_foo_OBJECT constants. Those
34  * constants are written into cache files.
35  */
36
37 static const FcObjectType _FcBaseObjectTypes[] = {
38     { FC_FAMILY,        FcTypeString, },    /* 1 */
39     { FC_FAMILYLANG,    FcTypeString, },
40     { FC_STYLE,         FcTypeString, },
41     { FC_STYLELANG,     FcTypeString, },
42     { FC_FULLNAME,      FcTypeString, },
43     { FC_FULLNAMELANG,  FcTypeString, },
44     { FC_SLANT,         FcTypeInteger, },
45     { FC_WEIGHT,        FcTypeInteger, },
46     { FC_WIDTH,         FcTypeInteger, },
47     { FC_SIZE,          FcTypeDouble, },
48     { FC_ASPECT,        FcTypeDouble, },
49     { FC_PIXEL_SIZE,    FcTypeDouble, },
50     { FC_SPACING,       FcTypeInteger, },
51     { FC_FOUNDRY,       FcTypeString, },
52     { FC_ANTIALIAS,     FcTypeBool, },
53     { FC_HINT_STYLE,    FcTypeInteger, },
54     { FC_HINTING,       FcTypeBool, },
55     { FC_VERTICAL_LAYOUT,   FcTypeBool, },
56     { FC_AUTOHINT,      FcTypeBool, },
57     { FC_GLOBAL_ADVANCE,    FcTypeBool, },      /* deprecated */
58     { FC_FILE,          FcTypeString, },
59     { FC_INDEX,         FcTypeInteger, },
60     { FC_RASTERIZER,    FcTypeString, },
61     { FC_OUTLINE,       FcTypeBool, },
62     { FC_SCALABLE,      FcTypeBool, },
63     { FC_DPI,           FcTypeDouble },
64     { FC_RGBA,          FcTypeInteger, },
65     { FC_SCALE,         FcTypeDouble, },
66     { FC_MINSPACE,      FcTypeBool, },
67     { FC_CHAR_WIDTH,    FcTypeInteger },
68     { FC_CHAR_HEIGHT,   FcTypeInteger },
69     { FC_MATRIX,        FcTypeMatrix },
70     { FC_CHARSET,       FcTypeCharSet },
71     { FC_LANG,          FcTypeLangSet },
72     { FC_FONTVERSION,   FcTypeInteger },
73     { FC_CAPABILITY,    FcTypeString },
74     { FC_FONTFORMAT,    FcTypeString },
75     { FC_EMBOLDEN,      FcTypeBool },
76     { FC_EMBEDDED_BITMAP,   FcTypeBool },
77     { FC_DECORATIVE,    FcTypeBool },
78     { FC_LCD_FILTER,    FcTypeInteger }, /* 41 */
79     { FC_NAMELANG,      FcTypeString }, /* 42 */
80 };
81
82 #define NUM_OBJECT_TYPES    (sizeof _FcBaseObjectTypes / sizeof _FcBaseObjectTypes[0])
83
84 typedef struct _FcObjectTypeList    FcObjectTypeList;
85
86 struct _FcObjectTypeList {
87     const FcObjectTypeList  *next;
88     const FcObjectType      *types;
89     int                     ntypes;
90 };
91
92 static const FcObjectTypeList _FcBaseObjectTypesList = {
93     0,
94     _FcBaseObjectTypes,
95     NUM_OBJECT_TYPES,
96 };
97
98 static const FcObjectTypeList   *_FcObjectTypes = &_FcBaseObjectTypesList;
99
100 #define OBJECT_HASH_SIZE    31
101
102 typedef struct _FcObjectBucket {
103     struct _FcObjectBucket  *next;
104     FcChar32                hash;
105     FcObject                id;
106 } FcObjectBucket;
107
108 static FcObjectBucket   *FcObjectBuckets[OBJECT_HASH_SIZE];
109
110 static FcObjectType     *FcObjects = (FcObjectType *) _FcBaseObjectTypes;
111 static int              FcObjectsNumber = NUM_OBJECT_TYPES;
112 static int              FcObjectsSize = 0;
113 static FcBool           FcObjectsInited;
114
115 static FcObjectType *
116 FcObjectInsert (const char *name, FcType type)
117 {
118     FcObjectType    *o;
119     if (FcObjectsNumber >= FcObjectsSize)
120     {
121         int             newsize = FcObjectsNumber * 2;
122         FcObjectType    *newobjects;
123         
124         if (FcObjectsSize)
125             newobjects = realloc (FcObjects, newsize * sizeof (FcObjectType));
126         else
127         {
128             newobjects = malloc (newsize * sizeof (FcObjectType));
129             if (newobjects)
130                 memcpy (newobjects, FcObjects,
131                         FcObjectsNumber * sizeof (FcObjectType));
132         }
133         if (!newobjects)
134             return NULL;
135         FcObjects = newobjects;
136         FcObjectsSize = newsize;
137     }
138     o = &FcObjects[FcObjectsNumber];
139     o->object = name;
140     o->type = type;
141     ++FcObjectsNumber;
142     return o;
143 }
144
145 static FcObject
146 FcObjectId (FcObjectType *o)
147 {
148     return o - FcObjects + 1;
149 }
150
151 static FcObjectType *
152 FcObjectFindByName (const char *object, FcBool insert)
153 {
154     FcChar32        hash = FcStringHash ((const FcChar8 *) object);
155     FcObjectBucket  **p;
156     FcObjectBucket  *b;
157     FcObjectType    *o;
158
159     if (!FcObjectsInited)
160         FcObjectInit ();
161     for (p = &FcObjectBuckets[hash%OBJECT_HASH_SIZE]; (b = *p); p = &(b->next))
162     {
163         o = FcObjects + b->id - 1;
164         if (b->hash == hash && !strcmp (object, (o->object)))
165             return o;
166     }
167     if (!insert)
168         return NULL;
169     /*
170      * Hook it into the hash chain
171      */
172     b = malloc (sizeof(FcObjectBucket));
173     if (!b)
174         return NULL;
175     object = (const char *) FcStrCopy ((FcChar8 *) object);
176     if (!object) {
177         free (b);
178         return NULL;
179     }
180     o = FcObjectInsert (object, -1);
181     b->next = NULL;
182     b->hash = hash;
183     b->id = FcObjectId (o);
184     *p = b;
185     return o;
186 }
187
188 static FcObjectType *
189 FcObjectFindById (FcObject object)
190 {
191     if (1 <= object && object <= FcObjectsNumber)
192         return FcObjects + object - 1;
193     return NULL;
194 }
195
196 static FcBool
197 FcObjectHashInsert (const FcObjectType *object, FcBool copy)
198 {
199     FcChar32        hash = FcStringHash ((const FcChar8 *) object->object);
200     FcObjectBucket  **p;
201     FcObjectBucket  *b;
202     FcObjectType    *o;
203
204     if (!FcObjectsInited)
205         FcObjectInit ();
206     for (p = &FcObjectBuckets[hash%OBJECT_HASH_SIZE]; (b = *p); p = &(b->next))
207     {
208         o = FcObjects + b->id - 1;
209         if (b->hash == hash && !strcmp (object->object, o->object))
210             return FcFalse;
211     }
212     /*
213      * Hook it into the hash chain
214      */
215     b = malloc (sizeof(FcObjectBucket));
216     if (!b)
217         return FcFalse;
218     if (copy)
219     {
220         o = FcObjectInsert (object->object, object->type);
221         if (!o)
222         {
223             free (b);
224             return FcFalse;
225         }
226     }
227     else
228         o = (FcObjectType *) object;
229     b->next = NULL;
230     b->hash = hash;
231     b->id = FcObjectId (o);
232     *p = b;
233     return FcTrue;
234 }
235
236 static void
237 FcObjectHashRemove (const FcObjectType *object, FcBool cleanobj)
238 {
239     FcChar32        hash = FcStringHash ((const FcChar8 *) object->object);
240     FcObjectBucket  **p;
241     FcObjectBucket  *b;
242     FcObjectType    *o;
243
244     if (!FcObjectsInited)
245         FcObjectInit ();
246     for (p = &FcObjectBuckets[hash%OBJECT_HASH_SIZE]; (b = *p); p = &(b->next))
247     {
248         o = FcObjects + b->id - 1;
249         if (b->hash == hash && !strcmp (object->object, o->object))
250         {
251             *p = b->next;
252             free (b);
253             if (cleanobj)
254             {
255                 /* Clean up object array */
256                 o->object = NULL;
257                 o->type = -1;
258                 while (FcObjects[FcObjectsNumber-1].object == NULL)
259                     --FcObjectsNumber;
260             }
261             break;
262         }
263     }
264 }
265
266 FcBool
267 FcNameRegisterObjectTypes (const FcObjectType *types, int ntypes)
268 {
269     int i;
270
271     for (i = 0; i < ntypes; i++)
272         if (!FcObjectHashInsert (&types[i], FcTrue))
273             return FcFalse;
274     return FcTrue;
275 }
276
277 FcBool
278 FcNameUnregisterObjectTypes (const FcObjectType *types, int ntypes)
279 {
280     int i;
281
282     for (i = 0; i < ntypes; i++)
283         FcObjectHashRemove (&types[i], FcTrue);
284     return FcTrue;
285 }
286
287 const FcObjectType *
288 FcNameGetObjectType (const char *object)
289 {
290     return FcObjectFindByName (object, FcFalse);
291 }
292
293 FcBool
294 FcObjectValidType (FcObject object, FcType type)
295 {
296     FcObjectType    *t = FcObjectFindById (object);
297
298     if (t) {
299         switch ((int) t->type) {
300         case FcTypeDouble:
301         case FcTypeInteger:
302             if (type == FcTypeDouble || type == FcTypeInteger)
303                 return FcTrue;
304             break;
305         case FcTypeLangSet:
306             if (type == FcTypeLangSet || type == FcTypeString)
307                 return FcTrue;
308             break;
309         default:
310             if (t->type == (unsigned int) -1 || type == t->type)
311                 return FcTrue;
312             break;
313         }
314         return FcFalse;
315     }
316     return FcTrue;
317 }
318
319 FcObject
320 FcObjectFromName (const char * name)
321 {
322     FcObjectType    *o = FcObjectFindByName (name, FcTrue);
323
324     if (o)
325         return FcObjectId (o);
326     return 0;
327 }
328
329 FcObjectSet *
330 FcObjectGetSet (void)
331 {
332     int         i;
333     FcObjectSet *os = NULL;
334
335
336     os = FcObjectSetCreate ();
337     for (i = 0; i < FcObjectsNumber; i++)
338         FcObjectSetAdd (os, FcObjects[i].object);
339
340     return os;
341 }
342
343 FcBool
344 FcObjectInit (void)
345 {
346     unsigned int        i;
347
348     if (FcObjectsInited)
349         return FcTrue;
350
351     FcObjectsInited = FcTrue;
352     for (i = 0; i < NUM_OBJECT_TYPES; i++)
353         if (!FcObjectHashInsert (&_FcBaseObjectTypes[i], FcFalse))
354             return FcFalse;
355     return FcTrue;
356 }
357
358 void
359 FcObjectFini (void)
360 {
361     int             i;
362     FcObjectBucket  *b, *next;
363
364     for (i = 0; i < OBJECT_HASH_SIZE; i++)
365     {
366         for (b = FcObjectBuckets[i]; b; b = next)
367         {
368             next = b->next;
369             free (b);
370         }
371         FcObjectBuckets[i] = 0;
372     }
373     for (i = 0; i < FcObjectsNumber; i++)
374         if (FcObjects[i].type == (unsigned int) -1)
375             free ((void*) FcObjects[i].object);
376     if (FcObjects != _FcBaseObjectTypes)
377         free (FcObjects);
378     FcObjects = (FcObjectType *) _FcBaseObjectTypes;
379     FcObjectsNumber = NUM_OBJECT_TYPES;
380     FcObjectsSize = 0;
381     FcObjectsInited = FcFalse;
382 }
383
384 const char *
385 FcObjectName (FcObject object)
386 {
387     FcObjectType    *o = FcObjectFindById (object);
388
389     if (o)
390         return o->object;
391     return NULL;
392 }
393
394 static const FcConstant _FcBaseConstants[] = {
395     { (FcChar8 *) "thin",           "weight",   FC_WEIGHT_THIN, },
396     { (FcChar8 *) "extralight",     "weight",   FC_WEIGHT_EXTRALIGHT, },
397     { (FcChar8 *) "ultralight",     "weight",   FC_WEIGHT_EXTRALIGHT, },
398     { (FcChar8 *) "light",          "weight",   FC_WEIGHT_LIGHT, },
399     { (FcChar8 *) "book",           "weight",   FC_WEIGHT_BOOK, },
400     { (FcChar8 *) "regular",        "weight",   FC_WEIGHT_REGULAR, },
401     { (FcChar8 *) "medium",         "weight",   FC_WEIGHT_MEDIUM, },
402     { (FcChar8 *) "demibold",       "weight",   FC_WEIGHT_DEMIBOLD, },
403     { (FcChar8 *) "semibold",       "weight",   FC_WEIGHT_DEMIBOLD, },
404     { (FcChar8 *) "bold",           "weight",   FC_WEIGHT_BOLD, },
405     { (FcChar8 *) "extrabold",      "weight",   FC_WEIGHT_EXTRABOLD, },
406     { (FcChar8 *) "ultrabold",      "weight",   FC_WEIGHT_EXTRABOLD, },
407     { (FcChar8 *) "black",          "weight",   FC_WEIGHT_BLACK, },
408     { (FcChar8 *) "heavy",          "weight",   FC_WEIGHT_HEAVY, },
409
410     { (FcChar8 *) "roman",          "slant",    FC_SLANT_ROMAN, },
411     { (FcChar8 *) "italic",         "slant",    FC_SLANT_ITALIC, },
412     { (FcChar8 *) "oblique",        "slant",    FC_SLANT_OBLIQUE, },
413
414     { (FcChar8 *) "ultracondensed", "width",    FC_WIDTH_ULTRACONDENSED },
415     { (FcChar8 *) "extracondensed", "width",    FC_WIDTH_EXTRACONDENSED },
416     { (FcChar8 *) "condensed",      "width",    FC_WIDTH_CONDENSED },
417     { (FcChar8 *) "semicondensed", "width",     FC_WIDTH_SEMICONDENSED },
418     { (FcChar8 *) "normal",         "width",    FC_WIDTH_NORMAL },
419     { (FcChar8 *) "semiexpanded",   "width",    FC_WIDTH_SEMIEXPANDED },
420     { (FcChar8 *) "expanded",       "width",    FC_WIDTH_EXPANDED },
421     { (FcChar8 *) "extraexpanded",  "width",    FC_WIDTH_EXTRAEXPANDED },
422     { (FcChar8 *) "ultraexpanded",  "width",    FC_WIDTH_ULTRAEXPANDED },
423
424     { (FcChar8 *) "proportional",   "spacing",  FC_PROPORTIONAL, },
425     { (FcChar8 *) "dual",           "spacing",  FC_DUAL, },
426     { (FcChar8 *) "mono",           "spacing",  FC_MONO, },
427     { (FcChar8 *) "charcell",       "spacing",  FC_CHARCELL, },
428
429     { (FcChar8 *) "unknown",        "rgba",         FC_RGBA_UNKNOWN },
430     { (FcChar8 *) "rgb",            "rgba",         FC_RGBA_RGB, },
431     { (FcChar8 *) "bgr",            "rgba",         FC_RGBA_BGR, },
432     { (FcChar8 *) "vrgb",           "rgba",         FC_RGBA_VRGB },
433     { (FcChar8 *) "vbgr",           "rgba",         FC_RGBA_VBGR },
434     { (FcChar8 *) "none",           "rgba",         FC_RGBA_NONE },
435
436     { (FcChar8 *) "hintnone",       "hintstyle",   FC_HINT_NONE },
437     { (FcChar8 *) "hintslight",     "hintstyle",   FC_HINT_SLIGHT },
438     { (FcChar8 *) "hintmedium",     "hintstyle",   FC_HINT_MEDIUM },
439     { (FcChar8 *) "hintfull",       "hintstyle",   FC_HINT_FULL },
440
441     { (FcChar8 *) "antialias",      "antialias",    FcTrue },
442     { (FcChar8 *) "hinting",        "hinting",      FcTrue },
443     { (FcChar8 *) "verticallayout", "verticallayout",   FcTrue },
444     { (FcChar8 *) "autohint",       "autohint",     FcTrue },
445     { (FcChar8 *) "globaladvance",  "globaladvance",    FcTrue }, /* deprecated */
446     { (FcChar8 *) "outline",        "outline",      FcTrue },
447     { (FcChar8 *) "scalable",       "scalable",     FcTrue },
448     { (FcChar8 *) "minspace",       "minspace",     FcTrue },
449     { (FcChar8 *) "embolden",       "embolden",     FcTrue },
450     { (FcChar8 *) "embeddedbitmap", "embeddedbitmap",   FcTrue },
451     { (FcChar8 *) "decorative",     "decorative",   FcTrue },
452     { (FcChar8 *) "lcdnone",        "lcdfilter",    FC_LCD_NONE },
453     { (FcChar8 *) "lcddefault",     "lcdfilter",    FC_LCD_DEFAULT },
454     { (FcChar8 *) "lcdlight",       "lcdfilter",    FC_LCD_LIGHT },
455     { (FcChar8 *) "lcdlegacy",      "lcdfilter",    FC_LCD_LEGACY },
456 };
457
458 #define NUM_FC_CONSTANTS   (sizeof _FcBaseConstants/sizeof _FcBaseConstants[0])
459
460 typedef struct _FcConstantList FcConstantList;
461
462 struct _FcConstantList {
463     const FcConstantList    *next;
464     const FcConstant        *consts;
465     int                     nconsts;
466 };
467
468 static const FcConstantList _FcBaseConstantList = {
469     0,
470     _FcBaseConstants,
471     NUM_FC_CONSTANTS
472 };
473
474 static const FcConstantList     *_FcConstants = &_FcBaseConstantList;
475
476 FcBool
477 FcNameRegisterConstants (const FcConstant *consts, int nconsts)
478 {
479     FcConstantList      *l;
480
481     l = (FcConstantList *) malloc (sizeof (FcConstantList));
482     if (!l)
483         return FcFalse;
484     FcMemAlloc (FC_MEM_CONSTANT, sizeof (FcConstantList));
485     l->consts = consts;
486     l->nconsts = nconsts;
487     l->next = _FcConstants;
488     _FcConstants = l;
489     return FcTrue;
490 }
491
492 FcBool
493 FcNameUnregisterConstants (const FcConstant *consts, int nconsts)
494 {
495     const FcConstantList        *l, **prev;
496
497     for (prev = &_FcConstants;
498          (l = *prev);
499          prev = (const FcConstantList **) &(l->next))
500     {
501         if (l->consts == consts && l->nconsts == nconsts)
502         {
503             *prev = l->next;
504             FcMemFree (FC_MEM_CONSTANT, sizeof (FcConstantList));
505             free ((void *) l);
506             return FcTrue;
507         }
508     }
509     return FcFalse;
510 }
511
512 const FcConstant *
513 FcNameGetConstant (const FcChar8 *string)
514 {
515     const FcConstantList    *l;
516     int                     i;
517
518     for (l = _FcConstants; l; l = l->next)
519     {
520         for (i = 0; i < l->nconsts; i++)
521             if (!FcStrCmpIgnoreCase (string, l->consts[i].name))
522                 return &l->consts[i];
523     }
524     return 0;
525 }
526
527 FcBool
528 FcNameConstant (const FcChar8 *string, int *result)
529 {
530     const FcConstant    *c;
531
532     if ((c = FcNameGetConstant(string)))
533     {
534         *result = c->value;
535         return FcTrue;
536     }
537     return FcFalse;
538 }
539
540 FcBool
541 FcNameBool (const FcChar8 *v, FcBool *result)
542 {
543     char    c0, c1;
544
545     c0 = *v;
546     c0 = FcToLower (c0);
547     if (c0 == 't' || c0 == 'y' || c0 == '1')
548     {
549         *result = FcTrue;
550         return FcTrue;
551     }
552     if (c0 == 'f' || c0 == 'n' || c0 == '0')
553     {
554         *result = FcFalse;
555         return FcTrue;
556     }
557     if (c0 == 'o')
558     {
559         c1 = v[1];
560         c1 = FcToLower (c1);
561         if (c1 == 'n')
562         {
563             *result = FcTrue;
564             return FcTrue;
565         }
566         if (c1 == 'f')
567         {
568             *result = FcFalse;
569             return FcTrue;
570         }
571     }
572     return FcFalse;
573 }
574
575 static FcValue
576 FcNameConvert (FcType type, FcChar8 *string)
577 {
578     FcValue     v;
579     FcMatrix    m;
580
581     v.type = type;
582     switch ((int) v.type) {
583     case FcTypeInteger:
584         if (!FcNameConstant (string, &v.u.i))
585             v.u.i = atoi ((char *) string);
586         break;
587     case FcTypeString:
588         v.u.s = FcSharedStr (string);
589         if (!v.u.s)
590             v.type = FcTypeVoid;
591         break;
592     case FcTypeBool:
593         if (!FcNameBool (string, &v.u.b))
594             v.u.b = FcFalse;
595         break;
596     case FcTypeDouble:
597         v.u.d = strtod ((char *) string, 0);
598         break;
599     case FcTypeMatrix:
600         sscanf ((char *) string, "%lg %lg %lg %lg", &m.xx, &m.xy, &m.yx, &m.yy);
601         v.u.m = FcMatrixCopy (&m);
602         break;
603     case FcTypeCharSet:
604         v.u.c = FcNameParseCharSet (string);
605         if (!v.u.c)
606             v.type = FcTypeVoid;
607         break;
608     case FcTypeLangSet:
609         v.u.l = FcNameParseLangSet (string);
610         if (!v.u.l)
611             v.type = FcTypeVoid;
612         break;
613     default:
614         break;
615     }
616     return v;
617 }
618
619 static const FcChar8 *
620 FcNameFindNext (const FcChar8 *cur, const char *delim, FcChar8 *save, FcChar8 *last)
621 {
622     FcChar8    c;
623
624     while ((c = *cur))
625     {
626         if (c == '\\')
627         {
628             ++cur;
629             if (!(c = *cur))
630                 break;
631         }
632         else if (strchr (delim, c))
633             break;
634         ++cur;
635         *save++ = c;
636     }
637     *save = 0;
638     *last = *cur;
639     if (*cur)
640         cur++;
641     return cur;
642 }
643
644 FcPattern *
645 FcNameParse (const FcChar8 *name)
646 {
647     FcChar8             *save;
648     FcPattern           *pat;
649     double              d;
650     FcChar8             *e;
651     FcChar8             delim;
652     FcValue             v;
653     const FcObjectType  *t;
654     const FcConstant    *c;
655
656     /* freed below */
657     save = malloc (strlen ((char *) name) + 1);
658     if (!save)
659         goto bail0;
660     pat = FcPatternCreate ();
661     if (!pat)
662         goto bail1;
663
664     for (;;)
665     {
666         name = FcNameFindNext (name, "-,:", save, &delim);
667         if (save[0])
668         {
669             if (!FcPatternAddString (pat, FC_FAMILY, save))
670                 goto bail2;
671         }
672         if (delim != ',')
673             break;
674     }
675     if (delim == '-')
676     {
677         for (;;)
678         {
679             name = FcNameFindNext (name, "-,:", save, &delim);
680             d = strtod ((char *) save, (char **) &e);
681             if (e != save)
682             {
683                 if (!FcPatternAddDouble (pat, FC_SIZE, d))
684                     goto bail2;
685             }
686             if (delim != ',')
687                 break;
688         }
689     }
690     while (delim == ':')
691     {
692         name = FcNameFindNext (name, "=_:", save, &delim);
693         if (save[0])
694         {
695             if (delim == '=' || delim == '_')
696             {
697                 t = FcNameGetObjectType ((char *) save);
698                 for (;;)
699                 {
700                     name = FcNameFindNext (name, ":,", save, &delim);
701                     if (t)
702                     {
703                         v = FcNameConvert (t->type, save);
704                         if (!FcPatternAdd (pat, t->object, v, FcTrue))
705                         {
706                             FcValueDestroy (v);
707                             goto bail2;
708                         }
709                         FcValueDestroy (v);
710                     }
711                     if (delim != ',')
712                         break;
713                 }
714             }
715             else
716             {
717                 if ((c = FcNameGetConstant (save)))
718                 {
719                     t = FcNameGetObjectType ((char *) c->object);
720                     switch ((int) t->type) {
721                     case FcTypeInteger:
722                     case FcTypeDouble:
723                         if (!FcPatternAddInteger (pat, c->object, c->value))
724                             goto bail2;
725                         break;
726                     case FcTypeBool:
727                         if (!FcPatternAddBool (pat, c->object, c->value))
728                             goto bail2;
729                         break;
730                     default:
731                         break;
732                     }
733                 }
734             }
735         }
736     }
737
738     free (save);
739     return pat;
740
741 bail2:
742     FcPatternDestroy (pat);
743 bail1:
744     free (save);
745 bail0:
746     return 0;
747 }
748 static FcBool
749 FcNameUnparseString (FcStrBuf       *buf,
750                      const FcChar8  *string,
751                      const FcChar8  *escape)
752 {
753     FcChar8 c;
754     while ((c = *string++))
755     {
756         if (escape && strchr ((char *) escape, (char) c))
757         {
758             if (!FcStrBufChar (buf, escape[0]))
759                 return FcFalse;
760         }
761         if (!FcStrBufChar (buf, c))
762             return FcFalse;
763     }
764     return FcTrue;
765 }
766
767 FcBool
768 FcNameUnparseValue (FcStrBuf    *buf,
769                     FcValue     *v0,
770                     FcChar8     *escape)
771 {
772     FcChar8     temp[1024];
773     FcValue v = FcValueCanonicalize(v0);
774
775     switch (v.type) {
776     case FcTypeVoid:
777         return FcTrue;
778     case FcTypeInteger:
779         sprintf ((char *) temp, "%d", v.u.i);
780         return FcNameUnparseString (buf, temp, 0);
781     case FcTypeDouble:
782         sprintf ((char *) temp, "%g", v.u.d);
783         return FcNameUnparseString (buf, temp, 0);
784     case FcTypeString:
785         return FcNameUnparseString (buf, v.u.s, escape);
786     case FcTypeBool:
787         return FcNameUnparseString (buf, v.u.b ? (FcChar8 *) "True" : (FcChar8 *) "False", 0);
788     case FcTypeMatrix:
789         sprintf ((char *) temp, "%g %g %g %g",
790                  v.u.m->xx, v.u.m->xy, v.u.m->yx, v.u.m->yy);
791         return FcNameUnparseString (buf, temp, 0);
792     case FcTypeCharSet:
793         return FcNameUnparseCharSet (buf, v.u.c);
794     case FcTypeLangSet:
795         return FcNameUnparseLangSet (buf, v.u.l);
796     case FcTypeFTFace:
797         return FcTrue;
798     }
799     return FcFalse;
800 }
801
802 FcBool
803 FcNameUnparseValueList (FcStrBuf        *buf,
804                         FcValueListPtr  v,
805                         FcChar8         *escape)
806 {
807     while (v)
808     {
809         if (!FcNameUnparseValue (buf, &v->value, escape))
810             return FcFalse;
811         if ((v = FcValueListNext(v)) != NULL)
812             if (!FcNameUnparseString (buf, (FcChar8 *) ",", 0))
813                 return FcFalse;
814     }
815     return FcTrue;
816 }
817
818 #define FC_ESCAPE_FIXED    "\\-:,"
819 #define FC_ESCAPE_VARIABLE "\\=_:,"
820
821 FcChar8 *
822 FcNameUnparse (FcPattern *pat)
823 {
824     return FcNameUnparseEscaped (pat, FcTrue);
825 }
826
827 FcChar8 *
828 FcNameUnparseEscaped (FcPattern *pat, FcBool escape)
829 {
830     FcStrBuf                buf;
831     FcChar8                 buf_static[8192];
832     int                     i;
833     FcPatternElt            *e;
834     const FcObjectTypeList  *l;
835     const FcObjectType      *o;
836
837     FcStrBufInit (&buf, buf_static, sizeof (buf_static));
838     e = FcPatternObjectFindElt (pat, FC_FAMILY_OBJECT);
839     if (e)
840     {
841         if (!FcNameUnparseValueList (&buf, FcPatternEltValues(e), escape ? (FcChar8 *) FC_ESCAPE_FIXED : 0))
842             goto bail0;
843     }
844     e = FcPatternObjectFindElt (pat, FC_SIZE_OBJECT);
845     if (e)
846     {
847         if (!FcNameUnparseString (&buf, (FcChar8 *) "-", 0))
848             goto bail0;
849         if (!FcNameUnparseValueList (&buf, FcPatternEltValues(e), escape ? (FcChar8 *) FC_ESCAPE_FIXED : 0))
850             goto bail0;
851     }
852     for (l = _FcObjectTypes; l; l = l->next)
853     {
854         for (i = 0; i < l->ntypes; i++)
855         {
856             o = &l->types[i];
857             if (!strcmp (o->object, FC_FAMILY) ||
858                 !strcmp (o->object, FC_SIZE))
859                 continue;
860         
861             e = FcPatternObjectFindElt (pat, FcObjectFromName (o->object));
862             if (e)
863             {
864                 if (!FcNameUnparseString (&buf, (FcChar8 *) ":", 0))
865                     goto bail0;
866                 if (!FcNameUnparseString (&buf, (FcChar8 *) o->object, escape ? (FcChar8 *) FC_ESCAPE_VARIABLE : 0))
867                     goto bail0;
868                 if (!FcNameUnparseString (&buf, (FcChar8 *) "=", 0))
869                     goto bail0;
870                 if (!FcNameUnparseValueList (&buf, FcPatternEltValues(e), escape ?
871                                              (FcChar8 *) FC_ESCAPE_VARIABLE : 0))
872                     goto bail0;
873             }
874         }
875     }
876     return FcStrBufDone (&buf);
877 bail0:
878     FcStrBufDestroy (&buf);
879     return 0;
880 }
881 #define __fcname__
882 #include "fcaliastail.h"
883 #undef __fcname__