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