]> git.wh0rd.org - fontconfig.git/blob - src/fcname.c
Bug 44826 - <alias> must contain only a single <family>
[fontconfig.git] / src / fcname.c
1 /*
2 * fontconfig/src/fcname.c
3 *
4 * Copyright © 2000 Keith Packard
5 *
6 * Permission to use, copy, modify, distribute, and sell this software and its
7 * documentation for any purpose is hereby granted without fee, provided that
8 * the above copyright notice appear in all copies and that both that
9 * copyright notice and this permission notice appear in supporting
10 * documentation, and that the name of the author(s) not be used in
11 * advertising or publicity pertaining to distribution of the software without
12 * specific, written prior permission. The authors make no
13 * representations about the suitability of this software for any purpose. It
14 * is provided "as is" without express or implied warranty.
15 *
16 * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18 * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR
19 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
20 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
21 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
22 * PERFORMANCE OF THIS SOFTWARE.
23 */
24
25 #include "fcint.h"
26 #include <ctype.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <stdio.h>
30
31 /*
32 * Please do not change this list, it is used to initialize the object
33 * list in this order to match the FC_foo_OBJECT constants. Those
34 * constants are written into cache files.
35 */
36
37 static const FcObjectType _FcBaseObjectTypes[] = {
38 { FC_FAMILY, FcTypeString, }, /* 1 */
39 { FC_FAMILYLANG, FcTypeString, },
40 { FC_STYLE, FcTypeString, },
41 { FC_STYLELANG, FcTypeString, },
42 { FC_FULLNAME, FcTypeString, },
43 { FC_FULLNAMELANG, FcTypeString, },
44 { FC_SLANT, FcTypeInteger, },
45 { FC_WEIGHT, FcTypeInteger, },
46 { FC_WIDTH, FcTypeInteger, },
47 { FC_SIZE, FcTypeDouble, },
48 { FC_ASPECT, FcTypeDouble, },
49 { FC_PIXEL_SIZE, FcTypeDouble, },
50 { FC_SPACING, FcTypeInteger, },
51 { FC_FOUNDRY, FcTypeString, },
52 { FC_ANTIALIAS, FcTypeBool, },
53 { FC_HINT_STYLE, FcTypeInteger, },
54 { FC_HINTING, FcTypeBool, },
55 { FC_VERTICAL_LAYOUT, FcTypeBool, },
56 { FC_AUTOHINT, FcTypeBool, },
57 { FC_GLOBAL_ADVANCE, FcTypeBool, },
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 continue;
879
880 e = FcPatternObjectFindElt (pat, FcObjectFromName (o->object));
881 if (e)
882 {
883 if (!FcNameUnparseString (&buf, (FcChar8 *) ":", 0))
884 goto bail0;
885 if (!FcNameUnparseString (&buf, (FcChar8 *) o->object, escape ? (FcChar8 *) FC_ESCAPE_VARIABLE : 0))
886 goto bail0;
887 if (!FcNameUnparseString (&buf, (FcChar8 *) "=", 0))
888 goto bail0;
889 if (!FcNameUnparseValueList (&buf, FcPatternEltValues(e), escape ?
890 (FcChar8 *) FC_ESCAPE_VARIABLE : 0))
891 goto bail0;
892 }
893 }
894 }
895 return FcStrBufDone (&buf);
896 bail0:
897 FcStrBufDestroy (&buf);
898 return 0;
899 }
900 #define __fcname__
901 #include "fcaliastail.h"
902 #undef __fcname__