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