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