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