]> git.wh0rd.org - fontconfig.git/blame - src/fcpat.c
Reviewed by: Keith Packard <keithp@keithp.com>
[fontconfig.git] / src / fcpat.c
CommitLineData
24330d27 1/*
4bd4418a 2 * $RCSId: xc/lib/fontconfig/src/fcpat.c,v 1.18 2002/09/18 17:11:46 tsi 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 <stdlib.h>
26#include <string.h>
d8d73958 27#include <assert.h>
24330d27
KP
28#include "fcint.h"
29
30FcPattern *
31FcPatternCreate (void)
32{
33 FcPattern *p;
34
35 p = (FcPattern *) malloc (sizeof (FcPattern));
36 if (!p)
37 return 0;
38 FcMemAlloc (FC_MEM_PATTERN, sizeof (FcPattern));
39 p->num = 0;
40 p->size = 0;
41 p->elts = 0;
6f6563ed 42 p->ref = 1;
24330d27
KP
43 return p;
44}
45
46void
47FcValueDestroy (FcValue v)
48{
49 switch (v.type) {
50 case FcTypeString:
51 FcStrFree ((FcChar8 *) v.u.s);
52 break;
53 case FcTypeMatrix:
54 FcMatrixFree ((FcMatrix *) v.u.m);
55 break;
56 case FcTypeCharSet:
57 FcCharSetDestroy ((FcCharSet *) v.u.c);
58 break;
d8d73958
KP
59 case FcTypeLangSet:
60 FcLangSetDestroy ((FcLangSet *) v.u.l);
61 break;
24330d27
KP
62 default:
63 break;
64 }
65}
66
67FcValue
68FcValueSave (FcValue v)
69{
70 switch (v.type) {
71 case FcTypeString:
72 v.u.s = FcStrCopy (v.u.s);
73 if (!v.u.s)
74 v.type = FcTypeVoid;
75 break;
76 case FcTypeMatrix:
77 v.u.m = FcMatrixCopy (v.u.m);
78 if (!v.u.m)
79 v.type = FcTypeVoid;
80 break;
81 case FcTypeCharSet:
82 v.u.c = FcCharSetCopy ((FcCharSet *) v.u.c);
83 if (!v.u.c)
84 v.type = FcTypeVoid;
85 break;
d8d73958
KP
86 case FcTypeLangSet:
87 v.u.l = FcLangSetCopy (v.u.l);
88 if (!v.u.l)
89 v.type = FcTypeVoid;
90 break;
24330d27
KP
91 default:
92 break;
93 }
94 return v;
95}
96
97void
98FcValueListDestroy (FcValueList *l)
99{
100 FcValueList *next;
101 for (; l; l = next)
102 {
103 switch (l->value.type) {
104 case FcTypeString:
105 FcStrFree ((FcChar8 *) l->value.u.s);
106 break;
107 case FcTypeMatrix:
108 FcMatrixFree ((FcMatrix *) l->value.u.m);
109 break;
110 case FcTypeCharSet:
111 FcCharSetDestroy ((FcCharSet *) l->value.u.c);
112 break;
d8d73958
KP
113 case FcTypeLangSet:
114 FcLangSetDestroy ((FcLangSet *) l->value.u.l);
115 break;
24330d27
KP
116 default:
117 break;
118 }
119 next = l->next;
120 FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList));
121 free (l);
122 }
123}
124
0ab36ca8
KP
125FcBool
126FcValueEqual (FcValue va, FcValue vb)
127{
128 if (va.type != vb.type)
129 {
130 if (va.type == FcTypeInteger)
131 {
132 va.type = FcTypeDouble;
133 va.u.d = va.u.i;
134 }
135 if (vb.type == FcTypeInteger)
136 {
137 vb.type = FcTypeDouble;
138 vb.u.d = vb.u.i;
139 }
140 if (va.type != vb.type)
141 return FcFalse;
142 }
143 switch (va.type) {
144 case FcTypeVoid:
145 return FcTrue;
146 case FcTypeInteger:
147 return va.u.i == vb.u.i;
148 case FcTypeDouble:
149 return va.u.d == vb.u.d;
150 case FcTypeString:
151 return FcStrCmpIgnoreCase (va.u.s, vb.u.s) == 0;
152 case FcTypeBool:
153 return va.u.b == vb.u.b;
154 case FcTypeMatrix:
155 return FcMatrixEqual (va.u.m, vb.u.m);
156 case FcTypeCharSet:
157 return FcCharSetEqual (va.u.c, vb.u.c);
be094850
KP
158 case FcTypeFTFace:
159 return va.u.f == vb.u.f;
d8d73958
KP
160 case FcTypeLangSet:
161 return FcLangSetEqual (va.u.l, vb.u.l);
0ab36ca8
KP
162 }
163 return FcFalse;
164}
165
d0f07b8d
KP
166static FcChar32
167FcDoubleHash (double d)
168{
169 if (d < 0)
170 d = -d;
171 if (d > 0xffffffff)
172 d = 0xffffffff;
173 return (FcChar32) d;
174}
175
176static FcChar32
177FcStringHash (const FcChar8 *s)
178{
179 FcChar8 c;
180 FcChar32 h = 0;
181
182 if (s)
183 while ((c = *s++))
184 h = ((h << 1) | (h >> 31)) ^ c;
185 return h;
186}
187
188static FcChar32
189FcValueHash (FcValue v)
190{
191 switch (v.type) {
192 case FcTypeVoid:
193 return 0;
194 case FcTypeInteger:
195 return (FcChar32) v.u.i;
196 case FcTypeDouble:
197 return FcDoubleHash (v.u.d);
198 case FcTypeString:
199 return FcStringHash (v.u.s);
200 case FcTypeBool:
201 return (FcChar32) v.u.b;
202 case FcTypeMatrix:
203 return (FcDoubleHash (v.u.m->xx) ^
204 FcDoubleHash (v.u.m->xy) ^
205 FcDoubleHash (v.u.m->yx) ^
206 FcDoubleHash (v.u.m->yy));
207 case FcTypeCharSet:
208 return (FcChar32) v.u.c->num;
209 case FcTypeFTFace:
210 return FcStringHash ((const FcChar8 *) ((FT_Face) v.u.f)->family_name) ^
211 FcStringHash ((const FcChar8 *) ((FT_Face) v.u.f)->style_name);
d8d73958
KP
212 case FcTypeLangSet:
213 return FcLangSetHash (v.u.l);
d0f07b8d
KP
214 }
215 return FcFalse;
216}
217
0ab36ca8
KP
218static FcBool
219FcValueListEqual (FcValueList *la, FcValueList *lb)
220{
d8d73958
KP
221 if (la == lb)
222 return FcTrue;
223
0ab36ca8
KP
224 while (la && lb)
225 {
226 if (!FcValueEqual (la->value, lb->value))
227 return FcFalse;
228 la = la->next;
229 lb = lb->next;
230 }
231 if (la || lb)
232 return FcFalse;
233 return FcTrue;
234}
235
d0f07b8d
KP
236static FcChar32
237FcValueListHash (FcValueList *l)
238{
239 FcChar32 hash = 0;
240
241 while (l)
242 {
243 hash = ((hash << 1) | (hash >> 31)) ^ FcValueHash (l->value);
244 l = l->next;
245 }
246 return hash;
247}
248
24330d27
KP
249void
250FcPatternDestroy (FcPattern *p)
251{
252 int i;
253
d8d73958 254 if (p->ref == FC_REF_CONSTANT || --p->ref > 0)
6f6563ed
KP
255 return;
256
24330d27
KP
257 for (i = 0; i < p->num; i++)
258 FcValueListDestroy (p->elts[i].values);
259
260 p->num = 0;
261 if (p->elts)
262 {
263 FcMemFree (FC_MEM_PATELT, p->size * sizeof (FcPatternElt));
264 free (p->elts);
265 p->elts = 0;
266 }
267 p->size = 0;
268 FcMemFree (FC_MEM_PATTERN, sizeof (FcPattern));
269 free (p);
270}
271
d8d73958
KP
272#define FC_VALUE_LIST_HASH_SIZE 257
273#define FC_PATTERN_HASH_SIZE 67
274
275typedef struct _FcValueListEnt FcValueListEnt;
276
277struct _FcValueListEnt {
278 FcValueListEnt *next;
d8d73958 279 FcValueList *list;
05336fd8 280 FcChar32 hash, pad;
d8d73958
KP
281};
282
2d79b586
KP
283typedef union _FcValueListAlign {
284 FcValueListEnt ent;
285 FcValueList list;
286} FcValueListAlign;
287
d8d73958
KP
288static int FcValueListFrozenCount[FcTypeLangSet + 1];
289static int FcValueListFrozenBytes[FcTypeLangSet + 1];
290static char *FcValueListFrozenName[] = {
291 "Void",
292 "Integer",
293 "Double",
294 "String",
295 "Bool",
296 "Matrix",
297 "CharSet",
298 "FTFace",
299 "LangSet"
300};
301
302void
303FcValueListReport (void);
304
305void
306FcValueListReport (void)
307{
308 FcType t;
309
310 printf ("Fc Frozen Values:\n");
311 printf ("\t%8s %9s %9s\n", "Type", "Count", "Bytes");
312 for (t = FcTypeVoid; t <= FcTypeLangSet; t++)
313 printf ("\t%8s %9d %9d\n", FcValueListFrozenName[t],
314 FcValueListFrozenCount[t], FcValueListFrozenBytes[t]);
315}
316
317static FcValueListEnt *
318FcValueListEntCreate (FcValueList *h)
319{
2d79b586 320 FcValueListAlign *ea;
d8d73958
KP
321 FcValueListEnt *e;
322 FcValueList *l, *new;
323 int n;
d8d73958
KP
324 int size;
325
326 n = 0;
327 for (l = h; l; l = l->next)
d8d73958 328 n++;
1c52c0f0 329 size = sizeof (FcValueListAlign) + n * sizeof (FcValueList);
d8d73958
KP
330 FcValueListFrozenCount[h->value.type]++;
331 FcValueListFrozenBytes[h->value.type] += size;
2d79b586
KP
332 ea = malloc (size);
333 if (!ea)
d8d73958
KP
334 return 0;
335 FcMemAlloc (FC_MEM_VALLIST, size);
2d79b586
KP
336 e = &ea->ent;
337 e->list = (FcValueList *) (ea + 1);
d8d73958 338 new = e->list;
05336fd8 339 for (l = h; l; l = l->next, new++)
d8d73958
KP
340 {
341 if (l->value.type == FcTypeString)
342 {
343 new->value.type = FcTypeString;
1c52c0f0 344 new->value.u.s = FcObjectStaticName (l->value.u.s);
d8d73958
KP
345 }
346 else
05336fd8 347 {
1c52c0f0 348 new->value = FcValueSave (l->value);
05336fd8 349 }
d8d73958
KP
350 new->binding = l->binding;
351 if (l->next)
352 new->next = new + 1;
353 else
354 new->next = 0;
355 }
356 return e;
357}
358
34cd0514
CW
359static void
360FcValueListEntDestroy (FcValueListEnt *e)
361{
362 FcValueList *l;
363
364 FcValueListFrozenCount[e->list->value.type]--;
365
366 /* XXX: We should perform these two operations with "size" as
367 computed in FcValueListEntCreate, but we don't have access to
368 that value here. Without this, the FcValueListFrozenBytes
369 values will be wrong as will the FcMemFree counts.
370
371 FcValueListFrozenBytes[e->list->value.type] -= size;
372 FcMemFree (FC_MEM_VALLIST, size);
373 */
374
375 for (l = e->list; l; l = l->next)
376 {
377 if (l->value.type != FcTypeString)
378 FcValueDestroy (l->value);
379 }
380 /* XXX: Are we being too chummy with the implementation here to
381 free(e) when it was actually the enclosing FcValueListAlign
382 that was allocated? */
383 free (e);
384}
385
d8d73958
KP
386static int FcValueListTotal;
387static int FcValueListUsed;
388
34cd0514
CW
389static FcValueListEnt *FcValueListHashTable[FC_VALUE_LIST_HASH_SIZE];
390
d8d73958
KP
391static FcValueList *
392FcValueListFreeze (FcValueList *l)
393{
d8d73958 394 FcChar32 hash = FcValueListHash (l);
34cd0514 395 FcValueListEnt **bucket = &FcValueListHashTable[hash % FC_VALUE_LIST_HASH_SIZE];
d8d73958
KP
396 FcValueListEnt *ent;
397
398 FcValueListTotal++;
399 for (ent = *bucket; ent; ent = ent->next)
400 {
401 if (ent->hash == hash && FcValueListEqual (ent->list, l))
402 return ent->list;
403 }
404
405 ent = FcValueListEntCreate (l);
406 if (!ent)
407 return 0;
408
409 FcValueListUsed++;
410 ent->hash = hash;
411 ent->next = *bucket;
412 *bucket = ent;
413 return ent->list;
414}
415
34cd0514
CW
416static void
417FcValueListThawAll (void)
418{
419 int i;
420 FcValueListEnt *ent, *next;
421
422 for (i = 0; i < FC_VALUE_LIST_HASH_SIZE; i++)
423 {
424 for (ent = FcValueListHashTable[i]; ent; ent = next)
425 {
426 next = ent->next;
427 FcValueListEntDestroy (ent);
428 }
429 FcValueListHashTable[i] = 0;
430 }
431
432 FcValueListTotal = 0;
433 FcValueListUsed = 0;
434}
435
d8d73958
KP
436static FcChar32
437FcPatternBaseHash (FcPattern *b)
438{
439 FcChar32 hash = b->num;
440 int i;
441
442 for (i = 0; i < b->num; i++)
d1bec8c6 443 hash = ((hash << 1) | (hash >> 31)) ^ ((long) b->elts[i].values);
d8d73958
KP
444 return hash;
445}
446
447typedef struct _FcPatternEnt FcPatternEnt;
448
449struct _FcPatternEnt {
450 FcPatternEnt *next;
451 FcChar32 hash;
452 FcPattern pattern;
453};
454
455static int FcPatternTotal;
456static int FcPatternUsed;
457
34cd0514
CW
458static FcPatternEnt *FcPatternHashTable[FC_VALUE_LIST_HASH_SIZE];
459
d8d73958
KP
460static FcPattern *
461FcPatternBaseFreeze (FcPattern *b)
462{
d8d73958 463 FcChar32 hash = FcPatternBaseHash (b);
34cd0514 464 FcPatternEnt **bucket = &FcPatternHashTable[hash % FC_VALUE_LIST_HASH_SIZE];
d8d73958
KP
465 FcPatternEnt *ent;
466 int i;
d8d73958
KP
467 int size;
468
469 FcPatternTotal++;
470 for (ent = *bucket; ent; ent = ent->next)
471 {
472 if (ent->hash == hash && b->num == ent->pattern.num)
473 {
474 for (i = 0; i < b->num; i++)
475 {
1c52c0f0 476 if (b->elts[i].object != ent->pattern.elts[i].object)
d8d73958
KP
477 break;
478 if (b->elts[i].values != ent->pattern.elts[i].values)
479 break;
480 }
481 if (i == b->num)
482 return &ent->pattern;
483 }
484 }
485
486 /*
1c52c0f0 487 * Compute size of pattern + elts
d8d73958 488 */
1c52c0f0 489 size = sizeof (FcPatternEnt) + b->num*sizeof (FcPatternElt);
d8d73958
KP
490 ent = malloc (size);
491 if (!ent)
492 return 0;
493
494 FcMemAlloc (FC_MEM_PATTERN, size);
495 FcPatternUsed++;
496
497 ent->pattern.elts = (FcPatternElt *) (ent + 1);
498 ent->pattern.num = b->num;
499 ent->pattern.size = b->num;
500 ent->pattern.ref = FC_REF_CONSTANT;
501
d8d73958
KP
502 for (i = 0; i < b->num; i++)
503 {
504 ent->pattern.elts[i].values = b->elts[i].values;
1c52c0f0 505 ent->pattern.elts[i].object = b->elts[i].object;
d8d73958
KP
506 }
507
508 ent->hash = hash;
509 ent->next = *bucket;
510 *bucket = ent;
511 return &ent->pattern;
512}
513
34cd0514
CW
514static void
515FcPatternBaseThawAll (void)
516{
517 int i;
518 FcPatternEnt *ent, *next;
519
520 for (i = 0; i < FC_VALUE_LIST_HASH_SIZE; i++)
521 {
522 for (ent = FcPatternHashTable[i]; ent; ent = next)
523 {
524 next = ent->next;
525 free (ent);
526 }
527 FcPatternHashTable[i] = 0;
528 }
529
530 FcPatternTotal = 0;
531 FcPatternUsed = 0;
532}
533
d8d73958
KP
534FcPattern *
535FcPatternFreeze (FcPattern *p)
536{
537 FcPattern *b, *n = 0;
538 int size;
539 int i;
540
541 size = sizeof (FcPattern) + p->num * sizeof (FcPatternElt);
542 b = (FcPattern *) malloc (size);
543 if (!b)
544 return 0;
9dac3c59 545 FcMemAlloc (FC_MEM_PATTERN, size);
d8d73958
KP
546 b->num = p->num;
547 b->size = b->num;
548 b->ref = 1;
549 b->elts = (FcPatternElt *) (b + 1);
550 /*
551 * Freeze object lists
552 */
553 for (i = 0; i < p->num; i++)
554 {
555 b->elts[i].object = p->elts[i].object;
556 b->elts[i].values = FcValueListFreeze (p->elts[i].values);
557 if (!b->elts[i].values)
558 goto bail;
559 }
560 /*
561 * Freeze base
562 */
563 n = FcPatternBaseFreeze (b);
564#ifdef CHATTY
565 if (FcDebug() & FC_DBG_MEMORY)
566 {
567 printf ("ValueLists: total %9d used %9d\n", FcValueListTotal, FcValueListUsed);
568 printf ("Patterns: total %9d used %9d\n", FcPatternTotal, FcPatternUsed);
569 }
570#endif
571bail:
572 free (b);
573#ifdef DEBUG
574 assert (FcPatternEqual (n, p));
575#endif
576 return n;
577}
578
34cd0514
CW
579void
580FcPatternThawAll (void)
581{
582 FcPatternBaseThawAll ();
583 FcValueListThawAll ();
584}
585
e9be9cd1
KP
586static int
587FcPatternPosition (const FcPattern *p, const char *object)
24330d27 588{
e9be9cd1 589 int low, high, mid, c;
0ab36ca8 590
0ab36ca8 591 low = 0;
e9be9cd1
KP
592 high = p->num - 1;
593 c = 1;
594 mid = 0;
595 while (low <= high)
24330d27 596 {
e9be9cd1
KP
597 mid = (low + high) >> 1;
598 c = strcmp (p->elts[mid].object, object);
599 if (c == 0)
600 return mid;
601 if (c < 0)
602 low = mid + 1;
0ab36ca8 603 else
e9be9cd1 604 high = mid - 1;
24330d27 605 }
e9be9cd1
KP
606 if (c < 0)
607 mid++;
608 return -(mid + 1);
609}
24330d27 610
e9be9cd1
KP
611FcPatternElt *
612FcPatternFindElt (const FcPattern *p, const char *object)
613{
614 int i = FcPatternPosition (p, object);
615 if (i < 0)
0ab36ca8 616 return 0;
e9be9cd1
KP
617 return &p->elts[i];
618}
24330d27 619
e9be9cd1
KP
620FcPatternElt *
621FcPatternInsertElt (FcPattern *p, const char *object)
622{
623 int i;
624 FcPatternElt *e;
625
626 i = FcPatternPosition (p, object);
627 if (i < 0)
24330d27 628 {
e9be9cd1
KP
629 i = -i - 1;
630
631 /* grow array */
632 if (p->num + 1 >= p->size)
24330d27 633 {
e9be9cd1
KP
634 int s = p->size + 16;
635 if (p->elts)
636 e = (FcPatternElt *) realloc (p->elts, s * sizeof (FcPatternElt));
637 else
638 e = (FcPatternElt *) malloc (s * sizeof (FcPatternElt));
639 if (!e)
640 return FcFalse;
641 p->elts = e;
642 if (p->size)
643 FcMemFree (FC_MEM_PATELT, p->size * sizeof (FcPatternElt));
644 FcMemAlloc (FC_MEM_PATELT, s * sizeof (FcPatternElt));
645 while (p->size < s)
646 {
647 p->elts[p->size].object = 0;
648 p->elts[p->size].values = 0;
649 p->size++;
650 }
24330d27 651 }
e9be9cd1
KP
652
653 /* move elts up */
654 memmove (p->elts + i + 1,
655 p->elts + i,
656 sizeof (FcPatternElt) *
657 (p->num - i));
658
659 /* bump count */
660 p->num++;
661
1c52c0f0 662 p->elts[i].object = FcObjectStaticName (object);
e9be9cd1 663 p->elts[i].values = 0;
24330d27
KP
664 }
665
24330d27
KP
666 return &p->elts[i];
667}
668
0ab36ca8 669FcBool
e9be9cd1 670FcPatternEqual (const FcPattern *pa, const FcPattern *pb)
0ab36ca8
KP
671{
672 int i;
673
bd724c85
KP
674 if (pa == pb)
675 return FcTrue;
676
0ab36ca8
KP
677 if (pa->num != pb->num)
678 return FcFalse;
679 for (i = 0; i < pa->num; i++)
680 {
1c52c0f0 681 if (pa->elts[i].object != pb->elts[i].object)
0ab36ca8
KP
682 return FcFalse;
683 if (!FcValueListEqual (pa->elts[i].values, pb->elts[i].values))
684 return FcFalse;
685 }
686 return FcTrue;
687}
688
d0f07b8d
KP
689FcChar32
690FcPatternHash (const FcPattern *p)
691{
692 int i;
693 FcChar32 h = 0;
694
695 for (i = 0; i < p->num; i++)
696 {
697 h = (((h << 1) | (h >> 31)) ^
698 FcStringHash ((const FcChar8 *) p->elts[i].object) ^
699 FcValueListHash (p->elts[i].values));
700 }
701 return h;
702}
703
e9be9cd1
KP
704FcBool
705FcPatternEqualSubset (const FcPattern *pa, const FcPattern *pb, const FcObjectSet *os)
706{
707 FcPatternElt *ea, *eb;
708 int i;
709
710 for (i = 0; i < os->nobject; i++)
711 {
712 ea = FcPatternFindElt (pa, os->objects[i]);
713 eb = FcPatternFindElt (pb, os->objects[i]);
714 if (ea)
715 {
716 if (!eb)
717 return FcFalse;
718 if (!FcValueListEqual (ea->values, eb->values))
719 return FcFalse;
720 }
721 else
722 {
723 if (eb)
724 return FcFalse;
725 }
726 }
727 return FcTrue;
728}
729
24330d27 730FcBool
82f4243f
KP
731FcPatternAddWithBinding (FcPattern *p,
732 const char *object,
733 FcValue value,
734 FcValueBinding binding,
735 FcBool append)
24330d27
KP
736{
737 FcPatternElt *e;
738 FcValueList *new, **prev;
739
d8d73958
KP
740 if (p->ref == FC_REF_CONSTANT)
741 goto bail0;
742
24330d27
KP
743 new = (FcValueList *) malloc (sizeof (FcValueList));
744 if (!new)
745 goto bail0;
746
747 FcMemAlloc (FC_MEM_VALLIST, sizeof (FcValueList));
748 /* dup string */
749 value = FcValueSave (value);
750 if (value.type == FcTypeVoid)
751 goto bail1;
752
753 new->value = value;
82f4243f 754 new->binding = binding;
24330d27
KP
755 new->next = 0;
756
e9be9cd1 757 e = FcPatternInsertElt (p, object);
24330d27
KP
758 if (!e)
759 goto bail2;
760
761 if (append)
762 {
763 for (prev = &e->values; *prev; prev = &(*prev)->next);
764 *prev = new;
765 }
766 else
767 {
768 new->next = e->values;
769 e->values = new;
770 }
771
772 return FcTrue;
773
774bail2:
775 switch (value.type) {
776 case FcTypeString:
777 FcStrFree ((FcChar8 *) value.u.s);
778 break;
779 case FcTypeMatrix:
780 FcMatrixFree ((FcMatrix *) value.u.m);
781 break;
782 case FcTypeCharSet:
783 FcCharSetDestroy ((FcCharSet *) value.u.c);
784 break;
d8d73958
KP
785 case FcTypeLangSet:
786 FcLangSetDestroy ((FcLangSet *) value.u.l);
787 break;
24330d27
KP
788 default:
789 break;
790 }
791bail1:
792 FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList));
793 free (new);
794bail0:
795 return FcFalse;
796}
797
82f4243f
KP
798FcBool
799FcPatternAdd (FcPattern *p, const char *object, FcValue value, FcBool append)
800{
801 return FcPatternAddWithBinding (p, object, value, FcValueBindingStrong, append);
802}
803
804FcBool
805FcPatternAddWeak (FcPattern *p, const char *object, FcValue value, FcBool append)
806{
807 return FcPatternAddWithBinding (p, object, value, FcValueBindingWeak, append);
808}
809
24330d27
KP
810FcBool
811FcPatternDel (FcPattern *p, const char *object)
812{
813 FcPatternElt *e;
814 int i;
815
e9be9cd1 816 e = FcPatternFindElt (p, object);
24330d27
KP
817 if (!e)
818 return FcFalse;
819
820 i = e - p->elts;
821
822 /* destroy value */
823 FcValueListDestroy (e->values);
824
825 /* shuffle existing ones down */
826 memmove (e, e+1, (p->elts + p->num - (e + 1)) * sizeof (FcPatternElt));
827 p->num--;
828 p->elts[p->num].object = 0;
829 p->elts[p->num].values = 0;
830 return FcTrue;
831}
832
4f27c1c0
KP
833FcBool
834FcPatternRemove (FcPattern *p, const char *object, int id)
835{
836 FcPatternElt *e;
837 FcValueList **prev, *l;
838
839 e = FcPatternFindElt (p, object);
840 if (!e)
841 return FcFalse;
842 for (prev = &e->values; (l = *prev); prev = &l->next)
843 {
844 if (!id)
845 {
846 *prev = l->next;
847 l->next = 0;
848 FcValueListDestroy (l);
849 if (!e->values)
850 FcPatternDel (p, object);
851 return FcTrue;
852 }
853 id--;
854 }
855 return FcFalse;
856}
857
24330d27
KP
858FcBool
859FcPatternAddInteger (FcPattern *p, const char *object, int i)
860{
861 FcValue v;
862
863 v.type = FcTypeInteger;
864 v.u.i = i;
865 return FcPatternAdd (p, object, v, FcTrue);
866}
867
868FcBool
869FcPatternAddDouble (FcPattern *p, const char *object, double d)
870{
871 FcValue v;
872
873 v.type = FcTypeDouble;
874 v.u.d = d;
875 return FcPatternAdd (p, object, v, FcTrue);
876}
877
878
879FcBool
ccb3e93b 880FcPatternAddString (FcPattern *p, const char *object, const FcChar8 *s)
24330d27
KP
881{
882 FcValue v;
883
884 v.type = FcTypeString;
ccb3e93b 885 v.u.s = s;
24330d27
KP
886 return FcPatternAdd (p, object, v, FcTrue);
887}
888
889FcBool
890FcPatternAddMatrix (FcPattern *p, const char *object, const FcMatrix *s)
891{
892 FcValue v;
893
894 v.type = FcTypeMatrix;
895 v.u.m = (FcMatrix *) s;
896 return FcPatternAdd (p, object, v, FcTrue);
897}
898
899
900FcBool
901FcPatternAddBool (FcPattern *p, const char *object, FcBool b)
902{
903 FcValue v;
904
905 v.type = FcTypeBool;
906 v.u.b = b;
907 return FcPatternAdd (p, object, v, FcTrue);
908}
909
910FcBool
911FcPatternAddCharSet (FcPattern *p, const char *object, const FcCharSet *c)
912{
913 FcValue v;
914
915 v.type = FcTypeCharSet;
916 v.u.c = (FcCharSet *) c;
917 return FcPatternAdd (p, object, v, FcTrue);
918}
919
be094850
KP
920FcBool
921FcPatternAddFTFace (FcPattern *p, const char *object, const FT_Face f)
922{
923 FcValue v;
924
925 v.type = FcTypeFTFace;
926 v.u.f = (void *) f;
927 return FcPatternAdd (p, object, v, FcTrue);
928}
929
d8d73958
KP
930FcBool
931FcPatternAddLangSet (FcPattern *p, const char *object, const FcLangSet *ls)
932{
933 FcValue v;
934
935 v.type = FcTypeLangSet;
936 v.u.l = (FcLangSet *) ls;
937 return FcPatternAdd (p, object, v, FcTrue);
938}
939
24330d27 940FcResult
bff80114 941FcPatternGet (const FcPattern *p, const char *object, int id, FcValue *v)
24330d27
KP
942{
943 FcPatternElt *e;
944 FcValueList *l;
945
e9be9cd1 946 e = FcPatternFindElt (p, object);
24330d27
KP
947 if (!e)
948 return FcResultNoMatch;
949 for (l = e->values; l; l = l->next)
950 {
951 if (!id)
952 {
953 *v = l->value;
954 return FcResultMatch;
955 }
956 id--;
957 }
958 return FcResultNoId;
959}
960
961FcResult
bff80114 962FcPatternGetInteger (const FcPattern *p, const char *object, int id, int *i)
24330d27
KP
963{
964 FcValue v;
965 FcResult r;
966
967 r = FcPatternGet (p, object, id, &v);
968 if (r != FcResultMatch)
969 return r;
970 switch (v.type) {
971 case FcTypeDouble:
972 *i = (int) v.u.d;
973 break;
974 case FcTypeInteger:
975 *i = v.u.i;
976 break;
977 default:
978 return FcResultTypeMismatch;
979 }
980 return FcResultMatch;
981}
982
983FcResult
bff80114 984FcPatternGetDouble (const FcPattern *p, const char *object, int id, double *d)
24330d27
KP
985{
986 FcValue v;
987 FcResult r;
988
989 r = FcPatternGet (p, object, id, &v);
990 if (r != FcResultMatch)
991 return r;
992 switch (v.type) {
993 case FcTypeDouble:
994 *d = v.u.d;
995 break;
996 case FcTypeInteger:
997 *d = (double) v.u.i;
998 break;
999 default:
1000 return FcResultTypeMismatch;
1001 }
1002 return FcResultMatch;
1003}
1004
1005FcResult
bff80114 1006FcPatternGetString (const FcPattern *p, const char *object, int id, FcChar8 ** s)
24330d27
KP
1007{
1008 FcValue v;
1009 FcResult r;
1010
1011 r = FcPatternGet (p, object, id, &v);
1012 if (r != FcResultMatch)
1013 return r;
1014 if (v.type != FcTypeString)
1015 return FcResultTypeMismatch;
aae6f7d4 1016 *s = (FcChar8 *) v.u.s;
24330d27
KP
1017 return FcResultMatch;
1018}
1019
1020FcResult
bff80114 1021FcPatternGetMatrix(const FcPattern *p, const char *object, int id, FcMatrix **m)
24330d27
KP
1022{
1023 FcValue v;
1024 FcResult r;
1025
1026 r = FcPatternGet (p, object, id, &v);
1027 if (r != FcResultMatch)
1028 return r;
1029 if (v.type != FcTypeMatrix)
1030 return FcResultTypeMismatch;
1031 *m = (FcMatrix *) v.u.m;
1032 return FcResultMatch;
1033}
1034
1035
1036FcResult
bff80114 1037FcPatternGetBool(const FcPattern *p, const char *object, int id, FcBool *b)
24330d27
KP
1038{
1039 FcValue v;
1040 FcResult r;
1041
1042 r = FcPatternGet (p, object, id, &v);
1043 if (r != FcResultMatch)
1044 return r;
1045 if (v.type != FcTypeBool)
1046 return FcResultTypeMismatch;
1047 *b = v.u.b;
1048 return FcResultMatch;
1049}
1050
1051FcResult
bff80114 1052FcPatternGetCharSet(const FcPattern *p, const char *object, int id, FcCharSet **c)
24330d27
KP
1053{
1054 FcValue v;
1055 FcResult r;
1056
1057 r = FcPatternGet (p, object, id, &v);
1058 if (r != FcResultMatch)
1059 return r;
1060 if (v.type != FcTypeCharSet)
1061 return FcResultTypeMismatch;
1062 *c = (FcCharSet *) v.u.c;
1063 return FcResultMatch;
1064}
1065
be094850 1066FcResult
bff80114 1067FcPatternGetFTFace(const FcPattern *p, const char *object, int id, FT_Face *f)
be094850
KP
1068{
1069 FcValue v;
1070 FcResult r;
1071
1072 r = FcPatternGet (p, object, id, &v);
1073 if (r != FcResultMatch)
1074 return r;
1075 if (v.type != FcTypeFTFace)
1076 return FcResultTypeMismatch;
1077 *f = (FT_Face) v.u.f;
1078 return FcResultMatch;
1079}
1080
d8d73958 1081FcResult
bff80114 1082FcPatternGetLangSet(const FcPattern *p, const char *object, int id, FcLangSet **ls)
d8d73958
KP
1083{
1084 FcValue v;
1085 FcResult r;
1086
1087 r = FcPatternGet (p, object, id, &v);
1088 if (r != FcResultMatch)
1089 return r;
1090 if (v.type != FcTypeLangSet)
1091 return FcResultTypeMismatch;
1092 *ls = (FcLangSet *) v.u.l;
1093 return FcResultMatch;
1094}
1095
24330d27 1096FcPattern *
bff80114 1097FcPatternDuplicate (const FcPattern *orig)
24330d27
KP
1098{
1099 FcPattern *new;
1100 int i;
1101 FcValueList *l;
1102
1103 new = FcPatternCreate ();
1104 if (!new)
1105 goto bail0;
1106
1107 for (i = 0; i < orig->num; i++)
1108 {
1109 for (l = orig->elts[i].values; l; l = l->next)
1110 if (!FcPatternAdd (new, orig->elts[i].object, l->value, FcTrue))
1111 goto bail1;
1112 }
1113
1114 return new;
1115
1116bail1:
1117 FcPatternDestroy (new);
1118bail0:
1119 return 0;
1120}
1121
6f6563ed
KP
1122void
1123FcPatternReference (FcPattern *p)
1124{
d8d73958
KP
1125 if (p->ref != FC_REF_CONSTANT)
1126 p->ref++;
6f6563ed
KP
1127}
1128
24330d27
KP
1129FcPattern *
1130FcPatternVaBuild (FcPattern *orig, va_list va)
1131{
1132 FcPattern *ret;
1133
1134 FcPatternVapBuild (ret, orig, va);
1135 return ret;
1136}
1137
1138FcPattern *
1139FcPatternBuild (FcPattern *orig, ...)
1140{
1141 va_list va;
1142
1143 va_start (va, orig);
1144 FcPatternVapBuild (orig, orig, va);
1145 va_end (va);
1146 return orig;
1147}
4f27c1c0
KP
1148
1149/*
1150 * Add all of the elements in 's' to 'p'
1151 */
1152FcBool
1153FcPatternAppend (FcPattern *p, FcPattern *s)
1154{
1155 int i;
1156 FcPatternElt *e;
1157 FcValueList *v;
1158
1159 for (i = 0; i < s->num; i++)
1160 {
1161 e = &s->elts[i];
1162 for (v = e->values; v; v = v->next)
1163 {
1164 if (!FcPatternAddWithBinding (p, e->object,
1165 v->value, v->binding, FcTrue))
1166 return FcFalse;
1167 }
1168 }
1169 return FcTrue;
1170}
1171
1172const char *
1173FcObjectStaticName (const char *name)
1174{
1175#define OBJECT_HASH_SIZE 31
1176 static struct objectBucket {
1177 struct objectBucket *next;
1178 FcChar32 hash;
1179 } *buckets[OBJECT_HASH_SIZE];
1180 FcChar32 hash = FcStringHash ((const FcChar8 *) name);
1181 struct objectBucket **p;
1182 struct objectBucket *b;
1c52c0f0 1183 int size;
4f27c1c0
KP
1184
1185 for (p = &buckets[hash % OBJECT_HASH_SIZE]; (b = *p); p = &(b->next))
1186 if (b->hash == hash && !strcmp (name, (char *) (b + 1)))
1187 return (char *) (b + 1);
1c52c0f0
KP
1188 size = sizeof (struct objectBucket) + strlen (name) + 1;
1189 b = malloc (size);
1190 FcMemAlloc (FC_MEM_STATICSTR, size);
4f27c1c0
KP
1191 if (!b)
1192 return NULL;
1193 b->next = 0;
1194 b->hash = hash;
1195 strcpy ((char *) (b + 1), name);
1196 *p = b;
1197 return (char *) (b + 1);
1198}