]> git.wh0rd.org - fontconfig.git/blame - src/fcname.c
FcCharSetSerialize was using wrong offset for leaves. Make fc-cat work.
[fontconfig.git] / src / fcname.c
CommitLineData
24330d27 1/*
94421e40 2 * $RCSId: xc/lib/fontconfig/src/fcname.c,v 1.15 2002/09/26 00:17:28 keithp Exp $
24330d27 3 *
46b51147 4 * Copyright © 2000 Keith Packard
24330d27
KP
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
f045376c 25#include "fcint.h"
24330d27
KP
26#include <ctype.h>
27#include <stdlib.h>
28#include <string.h>
29#include <stdio.h>
24330d27 30
7f37423d 31/* Please do not revoke any of these bindings. */
5fe09702 32/* The __DUMMY__ object enables callers to distinguish the error return
7ce19673 33 * of FcObjectToPtrLookup from FC_FAMILY's FcObject, which would
5fe09702 34 * otherwise be 0. */
24330d27 35static const FcObjectType _FcBaseObjectTypes[] = {
5fe09702 36 { "__DUMMY__", FcTypeVoid, },
24330d27 37 { FC_FAMILY, FcTypeString, },
4f27c1c0 38 { FC_FAMILYLANG, FcTypeString, },
24330d27 39 { FC_STYLE, FcTypeString, },
4f27c1c0
KP
40 { FC_STYLELANG, FcTypeString, },
41 { FC_FULLNAME, FcTypeString, },
42 { FC_FULLNAMELANG, FcTypeString, },
24330d27
KP
43 { FC_SLANT, FcTypeInteger, },
44 { FC_WEIGHT, FcTypeInteger, },
81fa16c3 45 { FC_WIDTH, FcTypeInteger, },
24330d27 46 { FC_SIZE, FcTypeDouble, },
2a41214a 47 { FC_ASPECT, FcTypeDouble, },
24330d27
KP
48 { FC_PIXEL_SIZE, FcTypeDouble, },
49 { FC_SPACING, FcTypeInteger, },
50 { FC_FOUNDRY, FcTypeString, },
24330d27 51 { FC_ANTIALIAS, FcTypeBool, },
f077d662 52 { FC_HINT_STYLE, FcTypeInteger, },
4c003605
KP
53 { FC_HINTING, FcTypeBool, },
54 { FC_VERTICAL_LAYOUT, FcTypeBool, },
55 { FC_AUTOHINT, FcTypeBool, },
56 { FC_GLOBAL_ADVANCE, FcTypeBool, },
24330d27
KP
57 { FC_FILE, FcTypeString, },
58 { FC_INDEX, FcTypeInteger, },
59 { FC_RASTERIZER, FcTypeString, },
60 { FC_OUTLINE, FcTypeBool, },
61 { FC_SCALABLE, FcTypeBool, },
4c003605 62 { FC_DPI, FcTypeDouble },
24330d27
KP
63 { FC_RGBA, FcTypeInteger, },
64 { FC_SCALE, FcTypeDouble, },
24330d27
KP
65 { FC_MINSPACE, FcTypeBool, },
66 { FC_CHAR_WIDTH, FcTypeInteger },
67 { FC_CHAR_HEIGHT, FcTypeInteger },
68 { FC_MATRIX, FcTypeMatrix },
69 { FC_CHARSET, FcTypeCharSet },
d8d73958 70 { FC_LANG, FcTypeLangSet },
a342e87d 71 { FC_FONTVERSION, FcTypeInteger },
dbf68dd5 72 { FC_CAPABILITY, FcTypeString },
537e3d23 73 { FC_FONTFORMAT, FcTypeString },
414f7202 74 { FC_EMBOLDEN, FcTypeBool },
720298e7 75 { FC_EMBEDDED_BITMAP, FcTypeBool },
24330d27
KP
76};
77
78#define NUM_OBJECT_TYPES (sizeof _FcBaseObjectTypes / sizeof _FcBaseObjectTypes[0])
79
13cdf607
PL
80static FcObjectType * _FcUserObjectNames = 0;
81static int user_obj_alloc = 0;
14143250 82static int next_basic_offset = NUM_OBJECT_TYPES;
13cdf607 83
24330d27
KP
84typedef struct _FcObjectTypeList FcObjectTypeList;
85
86struct _FcObjectTypeList {
87 const FcObjectTypeList *next;
88 const FcObjectType *types;
89 int ntypes;
14143250 90 int basic_offset;
24330d27
KP
91};
92
93static const FcObjectTypeList _FcBaseObjectTypesList = {
94 0,
95 _FcBaseObjectTypes,
9ab79bdf
PL
96 NUM_OBJECT_TYPES,
97 0
24330d27
KP
98};
99
100static const FcObjectTypeList *_FcObjectTypes = &_FcBaseObjectTypesList;
101
102FcBool
103FcNameRegisterObjectTypes (const FcObjectType *types, int ntypes)
104{
105 FcObjectTypeList *l;
106
107 l = (FcObjectTypeList *) malloc (sizeof (FcObjectTypeList));
108 if (!l)
109 return FcFalse;
9dac3c59 110 FcMemAlloc (FC_MEM_OBJECTTYPE, sizeof (FcObjectTypeList));
24330d27
KP
111 l->types = types;
112 l->ntypes = ntypes;
113 l->next = _FcObjectTypes;
14143250
PL
114 l->basic_offset = next_basic_offset;
115 next_basic_offset += ntypes;
24330d27
KP
116 _FcObjectTypes = l;
117 return FcTrue;
118}
119
7f37423d
PL
120static FcBool
121FcNameUnregisterObjectTypesFree (const FcObjectType *types, int ntypes,
122 FcBool do_free)
24330d27
KP
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;
7f37423d
PL
133 if (do_free) {
134 FcMemFree (FC_MEM_OBJECTTYPE, sizeof (FcObjectTypeList));
135 free ((void *) l);
136 }
24330d27
KP
137 return FcTrue;
138 }
139 }
140 return FcFalse;
141}
142
7f37423d
PL
143FcBool
144FcNameUnregisterObjectTypes (const FcObjectType *types, int ntypes)
145{
146 return FcNameUnregisterObjectTypesFree (types, ntypes, FcTrue);
147}
148
24330d27
KP
149const FcObjectType *
150FcNameGetObjectType (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 {
c6103dfb
PL
158 if (l == (FcObjectTypeList*)_FcUserObjectNames)
159 continue;
160
24330d27
KP
161 for (i = 0; i < l->ntypes; i++)
162 {
163 t = &l->types[i];
bc9469ba 164 if (!strcmp (object, t->object))
24330d27
KP
165 return t;
166 }
167 }
168 return 0;
169}
170
13cdf607
PL
171#define OBJECT_HASH_SIZE 31
172struct objectBucket {
173 struct objectBucket *next;
174 FcChar32 hash;
175 int id;
176};
177static struct objectBucket *FcObjectBuckets[OBJECT_HASH_SIZE];
178
14143250
PL
179/* Design constraint: biggest_known_ntypes must never change
180 * after any call to FcNameRegisterObjectTypes. */
13cdf607 181static const FcObjectType *biggest_known_types = _FcBaseObjectTypes;
13cdf607 182static int biggest_known_ntypes = NUM_OBJECT_TYPES;
13cdf607
PL
183
184
7ce19673 185static FcObject
7f37423d 186FcObjectToPtrLookup (const char * object)
4262e0b3 187{
7ce19673 188 FcObject i = 0, n;
4262e0b3 189 const FcObjectTypeList *l;
8cfa0bbc 190 FcObjectType *t = _FcUserObjectNames;
a56e89ab 191 FcBool replace;
7f37423d 192
4262e0b3
PL
193 for (l = _FcObjectTypes; l; l = l->next)
194 {
195 for (i = 0; i < l->ntypes; i++)
196 {
13cdf607 197 t = (FcObjectType *)&l->types[i];
4262e0b3 198 if (!strcmp (object, t->object))
13cdf607 199 {
8cfa0bbc 200 if (l->types == _FcUserObjectNames)
14143250 201 return -i;
13cdf607 202 else
14143250 203 return l->basic_offset + i;
13cdf607 204 }
4262e0b3
PL
205 }
206 }
4262e0b3 207
5fe09702
PL
208 /* We didn't match. Look for the application's FcObjectTypeList
209 * and replace it in-place. */
13cdf607
PL
210 for (l = _FcObjectTypes; l; l = l->next)
211 {
212 if (l->types == _FcUserObjectNames)
213 break;
214 }
7f37423d 215
a56e89ab 216 replace = l && l->types == _FcUserObjectNames;
13cdf607 217 if (!_FcUserObjectNames ||
a56e89ab 218 (replace && user_obj_alloc <= l->ntypes))
13cdf607
PL
219 {
220 int nt = user_obj_alloc + 4;
a56e89ab 221 FcObjectType * tt = realloc (_FcUserObjectNames,
13cdf607 222 nt * sizeof (FcObjectType));
a56e89ab 223 if (!tt)
14143250 224 return 0;
a56e89ab 225 _FcUserObjectNames = tt;
13cdf607
PL
226 user_obj_alloc = nt;
227 }
228
a56e89ab 229 if (replace)
13cdf607
PL
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
8cfa0bbc 239 if (!_FcUserObjectNames)
13cdf607
PL
240 return 0;
241
8cfa0bbc
PL
242 _FcUserObjectNames[n].object = object;
243 _FcUserObjectNames[n].type = FcTypeVoid;
13cdf607 244
14143250 245 return -n;
13cdf607 246}
7f37423d 247
7ce19673
KP
248FcBool
249FcObjectValidType (FcObject object, FcType type)
250{
251 if (object < NUM_OBJECT_TYPES && _FcBaseObjectTypes[object].type != type)
252 return FcFalse;
253 return FcTrue;
254}
255
256FcObject
257FcObjectFromName (const char * name)
7f37423d
PL
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;
23787a8f
PL
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));
7f37423d 272 if (!b)
14143250 273 return 0;
7f37423d
PL
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
282void
283FcObjectStaticNameFini (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
4262e0b3 303const char *
7ce19673 304FcObjectName (FcObject object)
4262e0b3 305{
14143250
PL
306 const FcObjectTypeList *l;
307 int i, j;
308
7ce19673 309 if (object > 0)
14143250 310 {
7ce19673
KP
311 if (object < biggest_known_ntypes)
312 return biggest_known_types[object].object;
14143250
PL
313
314 j = 0;
315 for (l = _FcObjectTypes; l; l = l->next)
316 for (i = 0; i < l->ntypes; i++, j++)
7ce19673 317 if (j == object)
14143250
PL
318 return l->types[i].object;
319 }
320
7ce19673 321 return _FcUserObjectNames[-object].object;
4262e0b3
PL
322}
323
24330d27 324static const FcConstant _FcBaseConstants[] = {
81fa16c3
KP
325 { (FcChar8 *) "thin", "weight", FC_WEIGHT_THIN, },
326 { (FcChar8 *) "extralight", "weight", FC_WEIGHT_EXTRALIGHT, },
327 { (FcChar8 *) "ultralight", "weight", FC_WEIGHT_EXTRALIGHT, },
ccb3e93b 328 { (FcChar8 *) "light", "weight", FC_WEIGHT_LIGHT, },
1f71c4d8 329 { (FcChar8 *) "book", "weight", FC_WEIGHT_BOOK, },
81fa16c3 330 { (FcChar8 *) "regular", "weight", FC_WEIGHT_REGULAR, },
ccb3e93b
KP
331 { (FcChar8 *) "medium", "weight", FC_WEIGHT_MEDIUM, },
332 { (FcChar8 *) "demibold", "weight", FC_WEIGHT_DEMIBOLD, },
81fa16c3 333 { (FcChar8 *) "semibold", "weight", FC_WEIGHT_DEMIBOLD, },
ccb3e93b 334 { (FcChar8 *) "bold", "weight", FC_WEIGHT_BOLD, },
81fa16c3
KP
335 { (FcChar8 *) "extrabold", "weight", FC_WEIGHT_EXTRABOLD, },
336 { (FcChar8 *) "ultrabold", "weight", FC_WEIGHT_EXTRABOLD, },
ccb3e93b
KP
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
81fa16c3
KP
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
ccb3e93b 353 { (FcChar8 *) "proportional", "spacing", FC_PROPORTIONAL, },
a05d257f 354 { (FcChar8 *) "dual", "spacing", FC_DUAL, },
ccb3e93b
KP
355 { (FcChar8 *) "mono", "spacing", FC_MONO, },
356 { (FcChar8 *) "charcell", "spacing", FC_CHARCELL, },
357
1852d490 358 { (FcChar8 *) "unknown", "rgba", FC_RGBA_UNKNOWN },
ccb3e93b
KP
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 },
1852d490 363 { (FcChar8 *) "none", "rgba", FC_RGBA_NONE },
f077d662
OT
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 },
24330d27
KP
369};
370
371#define NUM_FC_CONSTANTS (sizeof _FcBaseConstants/sizeof _FcBaseConstants[0])
372
373typedef struct _FcConstantList FcConstantList;
374
375struct _FcConstantList {
376 const FcConstantList *next;
377 const FcConstant *consts;
378 int nconsts;
379};
380
381static const FcConstantList _FcBaseConstantList = {
382 0,
383 _FcBaseConstants,
384 NUM_FC_CONSTANTS
385};
386
387static const FcConstantList *_FcConstants = &_FcBaseConstantList;
388
389FcBool
390FcNameRegisterConstants (const FcConstant *consts, int nconsts)
391{
392 FcConstantList *l;
393
394 l = (FcConstantList *) malloc (sizeof (FcConstantList));
395 if (!l)
396 return FcFalse;
9dac3c59 397 FcMemAlloc (FC_MEM_CONSTANT, sizeof (FcConstantList));
24330d27
KP
398 l->consts = consts;
399 l->nconsts = nconsts;
400 l->next = _FcConstants;
401 _FcConstants = l;
402 return FcTrue;
403}
404
405FcBool
406FcNameUnregisterConstants (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;
9dac3c59 417 FcMemFree (FC_MEM_CONSTANT, sizeof (FcConstantList));
24330d27
KP
418 free ((void *) l);
419 return FcTrue;
420 }
421 }
422 return FcFalse;
423}
424
425const FcConstant *
ccb3e93b 426FcNameGetConstant (FcChar8 *string)
24330d27
KP
427{
428 const FcConstantList *l;
429 int i;
94421e40 430
24330d27
KP
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
440FcBool
ccb3e93b 441FcNameConstant (FcChar8 *string, int *result)
24330d27
KP
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
453FcBool
ca60d2b5 454FcNameBool (const FcChar8 *v, FcBool *result)
24330d27
KP
455{
456 char c0, c1;
457
458 c0 = *v;
94421e40 459 c0 = FcToLower (c0);
24330d27
KP
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];
94421e40 473 c1 = FcToLower (c1);
24330d27
KP
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
488static FcValue
ccb3e93b 489FcNameConvert (FcType type, FcChar8 *string, FcMatrix *m)
24330d27
KP
490{
491 FcValue v;
492
493 v.type = type;
494 switch (v.type) {
495 case FcTypeInteger:
496 if (!FcNameConstant (string, &v.u.i))
ccb3e93b 497 v.u.i = atoi ((char *) string);
24330d27
KP
498 break;
499 case FcTypeString:
7f37423d 500 v.u.s = FcStrStaticName(string);
24330d27
KP
501 break;
502 case FcTypeBool:
503 if (!FcNameBool (string, &v.u.b))
504 v.u.b = FcFalse;
505 break;
506 case FcTypeDouble:
ccb3e93b 507 v.u.d = strtod ((char *) string, 0);
24330d27
KP
508 break;
509 case FcTypeMatrix:
4262e0b3 510 v.u.m = m;
ccb3e93b 511 sscanf ((char *) string, "%lg %lg %lg %lg", &m->xx, &m->xy, &m->yx, &m->yy);
24330d27
KP
512 break;
513 case FcTypeCharSet:
4262e0b3 514 v.u.c = FcNameParseCharSet (string);
24330d27 515 break;
d8d73958 516 case FcTypeLangSet:
4262e0b3 517 v.u.l = FcNameParseLangSet (string);
d8d73958 518 break;
24330d27
KP
519 default:
520 break;
521 }
522 return v;
523}
524
ccb3e93b
KP
525static const FcChar8 *
526FcNameFindNext (const FcChar8 *cur, const char *delim, FcChar8 *save, FcChar8 *last)
24330d27 527{
ccb3e93b 528 FcChar8 c;
24330d27
KP
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
550FcPattern *
ccb3e93b 551FcNameParse (const FcChar8 *name)
24330d27 552{
ccb3e93b 553 FcChar8 *save;
24330d27
KP
554 FcPattern *pat;
555 double d;
ccb3e93b
KP
556 FcChar8 *e;
557 FcChar8 delim;
24330d27
KP
558 FcValue v;
559 FcMatrix m;
560 const FcObjectType *t;
561 const FcConstant *c;
562
9dac3c59 563 /* freed below */
ccb3e93b 564 save = malloc (strlen ((char *) name) + 1);
24330d27
KP
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);
ccb3e93b 587 d = strtod ((char *) save, (char **) &e);
24330d27
KP
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 {
ccb3e93b 604 t = FcNameGetObjectType ((char *) save);
24330d27
KP
605 for (;;)
606 {
607 name = FcNameFindNext (name, ":,", save, &delim);
5fe09702 608 if (t && strcmp (t->object, _FcBaseObjectTypes[0].object))
24330d27
KP
609 {
610 v = FcNameConvert (t->type, save, &m);
611 if (!FcPatternAdd (pat, t->object, v, FcTrue))
612 {
d8d73958
KP
613 switch (v.type) {
614 case FcTypeCharSet:
4262e0b3 615 FcCharSetDestroy ((FcCharSet *) v.u.c);
d8d73958
KP
616 break;
617 case FcTypeLangSet:
4262e0b3 618 FcLangSetDestroy ((FcLangSet *) v.u.l);
d8d73958
KP
619 break;
620 default:
621 break;
622 }
24330d27
KP
623 goto bail2;
624 }
d8d73958
KP
625 switch (v.type) {
626 case FcTypeCharSet:
4262e0b3 627 FcCharSetDestroy ((FcCharSet *) v.u.c);
d8d73958
KP
628 break;
629 case FcTypeLangSet:
4262e0b3 630 FcLangSetDestroy ((FcLangSet *) v.u.l);
d8d73958
KP
631 break;
632 default:
633 break;
634 }
24330d27
KP
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
654bail2:
655 FcPatternDestroy (pat);
656bail1:
657 free (save);
658bail0:
659 return 0;
660}
24330d27 661static FcBool
c2e7c611 662FcNameUnparseString (FcStrBuf *buf,
24330d27
KP
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 {
c2e7c611 671 if (!FcStrBufChar (buf, escape[0]))
24330d27
KP
672 return FcFalse;
673 }
c2e7c611 674 if (!FcStrBufChar (buf, c))
24330d27
KP
675 return FcFalse;
676 }
677 return FcTrue;
678}
679
680static FcBool
c2e7c611 681FcNameUnparseValue (FcStrBuf *buf,
4262e0b3 682 FcValue *v0,
24330d27
KP
683 FcChar8 *escape)
684{
685 FcChar8 temp[1024];
4262e0b3 686 FcValue v = FcValueCanonicalize(v0);
24330d27
KP
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:
4262e0b3 698 return FcNameUnparseString (buf, v.u.s, escape);
24330d27 699 case FcTypeBool:
ccb3e93b 700 return FcNameUnparseString (buf, v.u.b ? (FcChar8 *) "True" : (FcChar8 *) "False", 0);
24330d27
KP
701 case FcTypeMatrix:
702 sprintf ((char *) temp, "%g %g %g %g",
4262e0b3 703 v.u.m->xx, v.u.m->xy, v.u.m->yx, v.u.m->yy);
24330d27
KP
704 return FcNameUnparseString (buf, temp, 0);
705 case FcTypeCharSet:
4262e0b3 706 return FcNameUnparseCharSet (buf, v.u.c);
d8d73958 707 case FcTypeLangSet:
4262e0b3 708 return FcNameUnparseLangSet (buf, v.u.l);
88c747e2
KP
709 case FcTypeFTFace:
710 return FcTrue;
24330d27
KP
711 }
712 return FcFalse;
713}
714
715static FcBool
c2e7c611 716FcNameUnparseValueList (FcStrBuf *buf,
cd2ec1a9 717 FcValueListPtr v,
ccb3e93b 718 FcChar8 *escape)
24330d27 719{
7ce19673 720 while (v)
24330d27 721 {
7ce19673 722 if (!FcNameUnparseValue (buf, &v->value, escape))
24330d27 723 return FcFalse;
7ce19673 724 if ((v = FcValueListNext(v)) != NULL)
ccb3e93b 725 if (!FcNameUnparseString (buf, (FcChar8 *) ",", 0))
24330d27
KP
726 return FcFalse;
727 }
728 return FcTrue;
729}
730
731#define FC_ESCAPE_FIXED "\\-:,"
732#define FC_ESCAPE_VARIABLE "\\=_:,"
733
734FcChar8 *
735FcNameUnparse (FcPattern *pat)
2fa3f27e
PL
736{
737 return FcNameUnparseEscaped (pat, FcTrue);
738}
739
740FcChar8 *
741FcNameUnparseEscaped (FcPattern *pat, FcBool escape)
24330d27 742{
c2e7c611 743 FcStrBuf buf;
24330d27
KP
744 FcChar8 buf_static[8192];
745 int i;
746 FcPatternElt *e;
747 const FcObjectTypeList *l;
748 const FcObjectType *o;
749
c2e7c611 750 FcStrBufInit (&buf, buf_static, sizeof (buf_static));
7ce19673 751 e = FcPatternObjectFindElt (pat, FC_FAMILY_OBJECT);
24330d27
KP
752 if (e)
753 {
7ce19673 754 if (!FcNameUnparseValueList (&buf, FcPatternEltValues(e), escape ? (FcChar8 *) FC_ESCAPE_FIXED : 0))
24330d27
KP
755 goto bail0;
756 }
7ce19673 757 e = FcPatternObjectFindElt (pat, FC_SIZE_OBJECT);
24330d27
KP
758 if (e)
759 {
ccb3e93b 760 if (!FcNameUnparseString (&buf, (FcChar8 *) "-", 0))
24330d27 761 goto bail0;
7ce19673 762 if (!FcNameUnparseValueList (&buf, FcPatternEltValues(e), escape ? (FcChar8 *) FC_ESCAPE_FIXED : 0))
24330d27
KP
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
7ce19673 775 e = FcPatternObjectFindElt (pat, FcObjectFromName (o->object));
24330d27
KP
776 if (e)
777 {
ccb3e93b 778 if (!FcNameUnparseString (&buf, (FcChar8 *) ":", 0))
24330d27 779 goto bail0;
2fa3f27e 780 if (!FcNameUnparseString (&buf, (FcChar8 *) o->object, escape ? (FcChar8 *) FC_ESCAPE_VARIABLE : 0))
24330d27 781 goto bail0;
ccb3e93b 782 if (!FcNameUnparseString (&buf, (FcChar8 *) "=", 0))
24330d27 783 goto bail0;
7ce19673 784 if (!FcNameUnparseValueList (&buf, FcPatternEltValues(e), escape ?
2fa3f27e 785 (FcChar8 *) FC_ESCAPE_VARIABLE : 0))
24330d27
KP
786 goto bail0;
787 }
788 }
789 }
c2e7c611 790 return FcStrBufDone (&buf);
24330d27 791bail0:
c2e7c611 792 FcStrBufDestroy (&buf);
24330d27
KP
793 return 0;
794}