]> git.wh0rd.org - fontconfig.git/blame - src/fcname.c
Don't free strings that have been returned from FcStrStaticName.
[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
25#include <ctype.h>
26#include <stdlib.h>
27#include <string.h>
28#include <stdio.h>
29#include "fcint.h"
30
7f37423d 31/* Please do not revoke any of these bindings. */
24330d27 32static const FcObjectType _FcBaseObjectTypes[] = {
14143250 33 { "__DUMMY__", FcTypeVoid, },
24330d27 34 { FC_FAMILY, FcTypeString, },
4f27c1c0 35 { FC_FAMILYLANG, FcTypeString, },
24330d27 36 { FC_STYLE, FcTypeString, },
4f27c1c0
KP
37 { FC_STYLELANG, FcTypeString, },
38 { FC_FULLNAME, FcTypeString, },
39 { FC_FULLNAMELANG, FcTypeString, },
24330d27
KP
40 { FC_SLANT, FcTypeInteger, },
41 { FC_WEIGHT, FcTypeInteger, },
81fa16c3 42 { FC_WIDTH, FcTypeInteger, },
24330d27 43 { FC_SIZE, FcTypeDouble, },
2a41214a 44 { FC_ASPECT, FcTypeDouble, },
24330d27
KP
45 { FC_PIXEL_SIZE, FcTypeDouble, },
46 { FC_SPACING, FcTypeInteger, },
47 { FC_FOUNDRY, FcTypeString, },
48/* { FC_CORE, FcTypeBool, }, */
49 { FC_ANTIALIAS, FcTypeBool, },
f077d662 50 { FC_HINT_STYLE, FcTypeInteger, },
4c003605
KP
51 { FC_HINTING, FcTypeBool, },
52 { FC_VERTICAL_LAYOUT, FcTypeBool, },
53 { FC_AUTOHINT, FcTypeBool, },
54 { FC_GLOBAL_ADVANCE, FcTypeBool, },
24330d27
KP
55/* { FC_XLFD, FcTypeString, }, */
56 { FC_FILE, FcTypeString, },
57 { FC_INDEX, FcTypeInteger, },
58 { FC_RASTERIZER, FcTypeString, },
59 { FC_OUTLINE, FcTypeBool, },
60 { FC_SCALABLE, FcTypeBool, },
4c003605 61 { FC_DPI, FcTypeDouble },
24330d27
KP
62 { FC_RGBA, FcTypeInteger, },
63 { FC_SCALE, FcTypeDouble, },
24330d27 64 { FC_MINSPACE, FcTypeBool, },
13cdf607 65/* { FC_RENDER, FcTypeBool, },*/
24330d27
KP
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 {
158 for (i = 0; i < l->ntypes; i++)
159 {
160 t = &l->types[i];
bc9469ba 161 if (!strcmp (object, t->object))
24330d27
KP
162 return t;
163 }
164 }
165 return 0;
166}
167
13cdf607
PL
168#define OBJECT_HASH_SIZE 31
169struct objectBucket {
170 struct objectBucket *next;
171 FcChar32 hash;
172 int id;
173};
174static struct objectBucket *FcObjectBuckets[OBJECT_HASH_SIZE];
175
14143250
PL
176/* Design constraint: biggest_known_ntypes must never change
177 * after any call to FcNameRegisterObjectTypes. */
13cdf607
PL
178static const FcObjectType *biggest_known_types = _FcBaseObjectTypes;
179static FcBool allocated_biggest_known_types;
180static int biggest_known_ntypes = NUM_OBJECT_TYPES;
181static int biggest_known_count = 0;
182static char * biggest_ptr;
183
184
7f37423d
PL
185static FcObjectPtr
186FcObjectToPtrLookup (const char * object)
4262e0b3 187{
13cdf607 188 FcObjectPtr i = 0, n;
4262e0b3 189 const FcObjectTypeList *l;
13cdf607 190 FcObjectType *t = _FcUserObjectNames;
7f37423d 191
4262e0b3
PL
192 for (l = _FcObjectTypes; l; l = l->next)
193 {
194 for (i = 0; i < l->ntypes; i++)
195 {
13cdf607 196 t = (FcObjectType *)&l->types[i];
4262e0b3 197 if (!strcmp (object, t->object))
13cdf607
PL
198 {
199 if (l == (FcObjectTypeList*)_FcUserObjectNames)
14143250 200 return -i;
13cdf607 201 else
14143250 202 return l->basic_offset + i;
13cdf607 203 }
4262e0b3
PL
204 }
205 }
4262e0b3 206
13cdf607
PL
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 }
7f37423d 214
13cdf607
PL
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)
14143250 222 return 0;
13cdf607
PL
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
14143250 252 return -n;
13cdf607 253}
7f37423d
PL
254
255FcObjectPtr
256FcObjectToPtr (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;
23787a8f
PL
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));
7f37423d 271 if (!b)
14143250 272 return 0;
7f37423d
PL
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
281void
282FcObjectStaticNameFini (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
4262e0b3
PL
302const char *
303FcObjectPtrU (FcObjectPtr si)
304{
14143250
PL
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;
4262e0b3
PL
321}
322
323int
7f37423d 324FcObjectNeededBytes ()
4262e0b3 325{
7f37423d
PL
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);
4262e0b3
PL
334}
335
7fd7221e
PL
336int
337FcObjectNeededBytesAlign (void)
338{
339 return __alignof__ (int) + __alignof__ (char);
340}
341
4262e0b3
PL
342void *
343FcObjectDistributeBytes (FcCache * metadata, void * block_ptr)
344{
7fd7221e 345 block_ptr = ALIGN (block_ptr, int);
1c5b6345 346 *(int *)block_ptr = biggest_known_ntypes;
7f37423d 347 block_ptr = (int *) block_ptr + 1;
7fd7221e 348 block_ptr = ALIGN (block_ptr, char);
1c5b6345 349 biggest_ptr = block_ptr;
7f37423d 350 block_ptr = (char *) block_ptr + biggest_known_count;
4262e0b3
PL
351 return block_ptr;
352}
353
7f37423d
PL
354void
355FcObjectSerialize ()
4262e0b3 356{
7f37423d
PL
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 }
4262e0b3
PL
364}
365
7f37423d 366void *
61571f3f 367FcObjectUnserialize (FcCache * metadata, void *block_ptr)
4262e0b3 368{
7f37423d
PL
369 int new_biggest;
370 new_biggest = *(int *)block_ptr;
1c5b6345 371 block_ptr = ALIGN (block_ptr, int);
7f37423d
PL
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 }
1c5b6345 414 block_ptr = ALIGN (block_ptr, char);
7f37423d
PL
415 block_ptr = (char *) block_ptr + biggest_known_count;
416 return block_ptr;
4262e0b3
PL
417}
418
24330d27 419static const FcConstant _FcBaseConstants[] = {
81fa16c3
KP
420 { (FcChar8 *) "thin", "weight", FC_WEIGHT_THIN, },
421 { (FcChar8 *) "extralight", "weight", FC_WEIGHT_EXTRALIGHT, },
422 { (FcChar8 *) "ultralight", "weight", FC_WEIGHT_EXTRALIGHT, },
ccb3e93b 423 { (FcChar8 *) "light", "weight", FC_WEIGHT_LIGHT, },
1f71c4d8 424 { (FcChar8 *) "book", "weight", FC_WEIGHT_BOOK, },
81fa16c3 425 { (FcChar8 *) "regular", "weight", FC_WEIGHT_REGULAR, },
ccb3e93b
KP
426 { (FcChar8 *) "medium", "weight", FC_WEIGHT_MEDIUM, },
427 { (FcChar8 *) "demibold", "weight", FC_WEIGHT_DEMIBOLD, },
81fa16c3 428 { (FcChar8 *) "semibold", "weight", FC_WEIGHT_DEMIBOLD, },
ccb3e93b 429 { (FcChar8 *) "bold", "weight", FC_WEIGHT_BOLD, },
81fa16c3
KP
430 { (FcChar8 *) "extrabold", "weight", FC_WEIGHT_EXTRABOLD, },
431 { (FcChar8 *) "ultrabold", "weight", FC_WEIGHT_EXTRABOLD, },
ccb3e93b
KP
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
81fa16c3
KP
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
ccb3e93b 448 { (FcChar8 *) "proportional", "spacing", FC_PROPORTIONAL, },
a05d257f 449 { (FcChar8 *) "dual", "spacing", FC_DUAL, },
ccb3e93b
KP
450 { (FcChar8 *) "mono", "spacing", FC_MONO, },
451 { (FcChar8 *) "charcell", "spacing", FC_CHARCELL, },
452
1852d490 453 { (FcChar8 *) "unknown", "rgba", FC_RGBA_UNKNOWN },
ccb3e93b
KP
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 },
1852d490 458 { (FcChar8 *) "none", "rgba", FC_RGBA_NONE },
f077d662
OT
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 },
24330d27
KP
464};
465
466#define NUM_FC_CONSTANTS (sizeof _FcBaseConstants/sizeof _FcBaseConstants[0])
467
468typedef struct _FcConstantList FcConstantList;
469
470struct _FcConstantList {
471 const FcConstantList *next;
472 const FcConstant *consts;
473 int nconsts;
474};
475
476static const FcConstantList _FcBaseConstantList = {
477 0,
478 _FcBaseConstants,
479 NUM_FC_CONSTANTS
480};
481
482static const FcConstantList *_FcConstants = &_FcBaseConstantList;
483
484FcBool
485FcNameRegisterConstants (const FcConstant *consts, int nconsts)
486{
487 FcConstantList *l;
488
489 l = (FcConstantList *) malloc (sizeof (FcConstantList));
490 if (!l)
491 return FcFalse;
9dac3c59 492 FcMemAlloc (FC_MEM_CONSTANT, sizeof (FcConstantList));
24330d27
KP
493 l->consts = consts;
494 l->nconsts = nconsts;
495 l->next = _FcConstants;
496 _FcConstants = l;
497 return FcTrue;
498}
499
500FcBool
501FcNameUnregisterConstants (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;
9dac3c59 512 FcMemFree (FC_MEM_CONSTANT, sizeof (FcConstantList));
24330d27
KP
513 free ((void *) l);
514 return FcTrue;
515 }
516 }
517 return FcFalse;
518}
519
520const FcConstant *
ccb3e93b 521FcNameGetConstant (FcChar8 *string)
24330d27
KP
522{
523 const FcConstantList *l;
524 int i;
94421e40 525
24330d27
KP
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
535FcBool
ccb3e93b 536FcNameConstant (FcChar8 *string, int *result)
24330d27
KP
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
548FcBool
ca60d2b5 549FcNameBool (const FcChar8 *v, FcBool *result)
24330d27
KP
550{
551 char c0, c1;
552
553 c0 = *v;
94421e40 554 c0 = FcToLower (c0);
24330d27
KP
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];
94421e40 568 c1 = FcToLower (c1);
24330d27
KP
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
583static FcValue
ccb3e93b 584FcNameConvert (FcType type, FcChar8 *string, FcMatrix *m)
24330d27
KP
585{
586 FcValue v;
587
588 v.type = type;
589 switch (v.type) {
590 case FcTypeInteger:
591 if (!FcNameConstant (string, &v.u.i))
ccb3e93b 592 v.u.i = atoi ((char *) string);
24330d27
KP
593 break;
594 case FcTypeString:
7f37423d 595 v.u.s = FcStrStaticName(string);
24330d27
KP
596 break;
597 case FcTypeBool:
598 if (!FcNameBool (string, &v.u.b))
599 v.u.b = FcFalse;
600 break;
601 case FcTypeDouble:
ccb3e93b 602 v.u.d = strtod ((char *) string, 0);
24330d27
KP
603 break;
604 case FcTypeMatrix:
4262e0b3 605 v.u.m = m;
ccb3e93b 606 sscanf ((char *) string, "%lg %lg %lg %lg", &m->xx, &m->xy, &m->yx, &m->yy);
24330d27
KP
607 break;
608 case FcTypeCharSet:
4262e0b3 609 v.u.c = FcNameParseCharSet (string);
24330d27 610 break;
d8d73958 611 case FcTypeLangSet:
4262e0b3 612 v.u.l = FcNameParseLangSet (string);
d8d73958 613 break;
24330d27
KP
614 default:
615 break;
616 }
617 return v;
618}
619
ccb3e93b
KP
620static const FcChar8 *
621FcNameFindNext (const FcChar8 *cur, const char *delim, FcChar8 *save, FcChar8 *last)
24330d27 622{
ccb3e93b 623 FcChar8 c;
24330d27
KP
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
645FcPattern *
ccb3e93b 646FcNameParse (const FcChar8 *name)
24330d27 647{
ccb3e93b 648 FcChar8 *save;
24330d27
KP
649 FcPattern *pat;
650 double d;
ccb3e93b
KP
651 FcChar8 *e;
652 FcChar8 delim;
24330d27
KP
653 FcValue v;
654 FcMatrix m;
655 const FcObjectType *t;
656 const FcConstant *c;
657
9dac3c59 658 /* freed below */
ccb3e93b 659 save = malloc (strlen ((char *) name) + 1);
24330d27
KP
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);
ccb3e93b 682 d = strtod ((char *) save, (char **) &e);
24330d27
KP
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 {
ccb3e93b 699 t = FcNameGetObjectType ((char *) save);
24330d27
KP
700 for (;;)
701 {
702 name = FcNameFindNext (name, ":,", save, &delim);
c552f59b 703 if (t)
24330d27
KP
704 {
705 v = FcNameConvert (t->type, save, &m);
706 if (!FcPatternAdd (pat, t->object, v, FcTrue))
707 {
d8d73958
KP
708 switch (v.type) {
709 case FcTypeCharSet:
4262e0b3 710 FcCharSetDestroy ((FcCharSet *) v.u.c);
d8d73958
KP
711 break;
712 case FcTypeLangSet:
4262e0b3 713 FcLangSetDestroy ((FcLangSet *) v.u.l);
d8d73958
KP
714 break;
715 default:
716 break;
717 }
24330d27
KP
718 goto bail2;
719 }
d8d73958
KP
720 switch (v.type) {
721 case FcTypeCharSet:
4262e0b3 722 FcCharSetDestroy ((FcCharSet *) v.u.c);
d8d73958
KP
723 break;
724 case FcTypeLangSet:
4262e0b3 725 FcLangSetDestroy ((FcLangSet *) v.u.l);
d8d73958
KP
726 break;
727 default:
728 break;
729 }
24330d27
KP
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
749bail2:
750 FcPatternDestroy (pat);
751bail1:
752 free (save);
753bail0:
754 return 0;
755}
24330d27 756static FcBool
c2e7c611 757FcNameUnparseString (FcStrBuf *buf,
24330d27
KP
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 {
c2e7c611 766 if (!FcStrBufChar (buf, escape[0]))
24330d27
KP
767 return FcFalse;
768 }
c2e7c611 769 if (!FcStrBufChar (buf, c))
24330d27
KP
770 return FcFalse;
771 }
772 return FcTrue;
773}
774
775static FcBool
c2e7c611 776FcNameUnparseValue (FcStrBuf *buf,
4262e0b3 777 FcValue *v0,
24330d27
KP
778 FcChar8 *escape)
779{
780 FcChar8 temp[1024];
4262e0b3 781 FcValue v = FcValueCanonicalize(v0);
24330d27
KP
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:
4262e0b3 793 return FcNameUnparseString (buf, v.u.s, escape);
24330d27 794 case FcTypeBool:
ccb3e93b 795 return FcNameUnparseString (buf, v.u.b ? (FcChar8 *) "True" : (FcChar8 *) "False", 0);
24330d27
KP
796 case FcTypeMatrix:
797 sprintf ((char *) temp, "%g %g %g %g",
4262e0b3 798 v.u.m->xx, v.u.m->xy, v.u.m->yx, v.u.m->yy);
24330d27
KP
799 return FcNameUnparseString (buf, temp, 0);
800 case FcTypeCharSet:
4262e0b3 801 return FcNameUnparseCharSet (buf, v.u.c);
d8d73958 802 case FcTypeLangSet:
4262e0b3 803 return FcNameUnparseLangSet (buf, v.u.l);
88c747e2
KP
804 case FcTypeFTFace:
805 return FcTrue;
24330d27
KP
806 }
807 return FcFalse;
808}
809
810static FcBool
c2e7c611 811FcNameUnparseValueList (FcStrBuf *buf,
cd2ec1a9 812 FcValueListPtr v,
ccb3e93b 813 FcChar8 *escape)
24330d27 814{
cd2ec1a9 815 while (FcValueListPtrU(v))
24330d27 816 {
9ab79bdf 817 if (!FcNameUnparseValue (buf, &FcValueListPtrU(v)->value, escape))
24330d27 818 return FcFalse;
cd2ec1a9 819 if (FcValueListPtrU(v = FcValueListPtrU(v)->next))
ccb3e93b 820 if (!FcNameUnparseString (buf, (FcChar8 *) ",", 0))
24330d27
KP
821 return FcFalse;
822 }
823 return FcTrue;
824}
825
826#define FC_ESCAPE_FIXED "\\-:,"
827#define FC_ESCAPE_VARIABLE "\\=_:,"
828
829FcChar8 *
830FcNameUnparse (FcPattern *pat)
2fa3f27e
PL
831{
832 return FcNameUnparseEscaped (pat, FcTrue);
833}
834
835FcChar8 *
836FcNameUnparseEscaped (FcPattern *pat, FcBool escape)
24330d27 837{
c2e7c611 838 FcStrBuf buf;
24330d27
KP
839 FcChar8 buf_static[8192];
840 int i;
841 FcPatternElt *e;
842 const FcObjectTypeList *l;
843 const FcObjectType *o;
844
c2e7c611 845 FcStrBufInit (&buf, buf_static, sizeof (buf_static));
e9be9cd1 846 e = FcPatternFindElt (pat, FC_FAMILY);
24330d27
KP
847 if (e)
848 {
2fa3f27e 849 if (!FcNameUnparseValueList (&buf, e->values, escape ? (FcChar8 *) FC_ESCAPE_FIXED : 0))
24330d27
KP
850 goto bail0;
851 }
e9be9cd1 852 e = FcPatternFindElt (pat, FC_SIZE);
24330d27
KP
853 if (e)
854 {
ccb3e93b 855 if (!FcNameUnparseString (&buf, (FcChar8 *) "-", 0))
24330d27 856 goto bail0;
2fa3f27e 857 if (!FcNameUnparseValueList (&buf, e->values, escape ? (FcChar8 *) FC_ESCAPE_FIXED : 0))
24330d27
KP
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
e9be9cd1 870 e = FcPatternFindElt (pat, o->object);
24330d27
KP
871 if (e)
872 {
ccb3e93b 873 if (!FcNameUnparseString (&buf, (FcChar8 *) ":", 0))
24330d27 874 goto bail0;
2fa3f27e 875 if (!FcNameUnparseString (&buf, (FcChar8 *) o->object, escape ? (FcChar8 *) FC_ESCAPE_VARIABLE : 0))
24330d27 876 goto bail0;
ccb3e93b 877 if (!FcNameUnparseString (&buf, (FcChar8 *) "=", 0))
24330d27 878 goto bail0;
2fa3f27e
PL
879 if (!FcNameUnparseValueList (&buf, e->values, escape ?
880 (FcChar8 *) FC_ESCAPE_VARIABLE : 0))
24330d27
KP
881 goto bail0;
882 }
883 }
884 }
c2e7c611 885 return FcStrBufDone (&buf);
24330d27 886bail0:
c2e7c611 887 FcStrBufDestroy (&buf);
24330d27
KP
888 return 0;
889}