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