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