]> git.wh0rd.org - fontconfig.git/blame - src/fcpat.c
Make FcOpNotContains use FcStrStr for strings so that it matches semantics
[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
2ff4f076
RB
541 if (p->ref == FC_REF_CONSTANT)
542 return p;
543
d8d73958
KP
544 size = sizeof (FcPattern) + p->num * sizeof (FcPatternElt);
545 b = (FcPattern *) malloc (size);
546 if (!b)
547 return 0;
9dac3c59 548 FcMemAlloc (FC_MEM_PATTERN, size);
d8d73958
KP
549 b->num = p->num;
550 b->size = b->num;
551 b->ref = 1;
552 b->elts = (FcPatternElt *) (b + 1);
553 /*
554 * Freeze object lists
555 */
556 for (i = 0; i < p->num; i++)
557 {
558 b->elts[i].object = p->elts[i].object;
559 b->elts[i].values = FcValueListFreeze (p->elts[i].values);
560 if (!b->elts[i].values)
561 goto bail;
562 }
563 /*
564 * Freeze base
565 */
566 n = FcPatternBaseFreeze (b);
567#ifdef CHATTY
568 if (FcDebug() & FC_DBG_MEMORY)
569 {
570 printf ("ValueLists: total %9d used %9d\n", FcValueListTotal, FcValueListUsed);
571 printf ("Patterns: total %9d used %9d\n", FcPatternTotal, FcPatternUsed);
572 }
573#endif
574bail:
575 free (b);
576#ifdef DEBUG
577 assert (FcPatternEqual (n, p));
578#endif
579 return n;
580}
581
34cd0514
CW
582void
583FcPatternThawAll (void)
584{
585 FcPatternBaseThawAll ();
586 FcValueListThawAll ();
587}
588
e9be9cd1
KP
589static int
590FcPatternPosition (const FcPattern *p, const char *object)
24330d27 591{
e9be9cd1 592 int low, high, mid, c;
0ab36ca8 593
ae7d0f35 594 object = FcObjectStaticName(object);
0ab36ca8 595 low = 0;
e9be9cd1
KP
596 high = p->num - 1;
597 c = 1;
598 mid = 0;
599 while (low <= high)
24330d27 600 {
e9be9cd1 601 mid = (low + high) >> 1;
ae7d0f35 602 c = p->elts[mid].object - object;
e9be9cd1
KP
603 if (c == 0)
604 return mid;
605 if (c < 0)
606 low = mid + 1;
0ab36ca8 607 else
e9be9cd1 608 high = mid - 1;
24330d27 609 }
e9be9cd1
KP
610 if (c < 0)
611 mid++;
612 return -(mid + 1);
613}
24330d27 614
e9be9cd1
KP
615FcPatternElt *
616FcPatternFindElt (const FcPattern *p, const char *object)
617{
618 int i = FcPatternPosition (p, object);
619 if (i < 0)
0ab36ca8 620 return 0;
e9be9cd1
KP
621 return &p->elts[i];
622}
24330d27 623
e9be9cd1
KP
624FcPatternElt *
625FcPatternInsertElt (FcPattern *p, const char *object)
626{
627 int i;
628 FcPatternElt *e;
629
630 i = FcPatternPosition (p, object);
631 if (i < 0)
24330d27 632 {
e9be9cd1
KP
633 i = -i - 1;
634
635 /* grow array */
636 if (p->num + 1 >= p->size)
24330d27 637 {
e9be9cd1
KP
638 int s = p->size + 16;
639 if (p->elts)
640 e = (FcPatternElt *) realloc (p->elts, s * sizeof (FcPatternElt));
641 else
642 e = (FcPatternElt *) malloc (s * sizeof (FcPatternElt));
643 if (!e)
644 return FcFalse;
645 p->elts = e;
646 if (p->size)
647 FcMemFree (FC_MEM_PATELT, p->size * sizeof (FcPatternElt));
648 FcMemAlloc (FC_MEM_PATELT, s * sizeof (FcPatternElt));
649 while (p->size < s)
650 {
651 p->elts[p->size].object = 0;
652 p->elts[p->size].values = 0;
653 p->size++;
654 }
24330d27 655 }
e9be9cd1
KP
656
657 /* move elts up */
658 memmove (p->elts + i + 1,
659 p->elts + i,
660 sizeof (FcPatternElt) *
661 (p->num - i));
662
663 /* bump count */
664 p->num++;
665
1c52c0f0 666 p->elts[i].object = FcObjectStaticName (object);
e9be9cd1 667 p->elts[i].values = 0;
24330d27
KP
668 }
669
24330d27
KP
670 return &p->elts[i];
671}
672
0ab36ca8 673FcBool
e9be9cd1 674FcPatternEqual (const FcPattern *pa, const FcPattern *pb)
0ab36ca8
KP
675{
676 int i;
677
bd724c85
KP
678 if (pa == pb)
679 return FcTrue;
680
0ab36ca8
KP
681 if (pa->num != pb->num)
682 return FcFalse;
683 for (i = 0; i < pa->num; i++)
684 {
1c52c0f0 685 if (pa->elts[i].object != pb->elts[i].object)
0ab36ca8
KP
686 return FcFalse;
687 if (!FcValueListEqual (pa->elts[i].values, pb->elts[i].values))
688 return FcFalse;
689 }
690 return FcTrue;
691}
692
d0f07b8d
KP
693FcChar32
694FcPatternHash (const FcPattern *p)
695{
696 int i;
697 FcChar32 h = 0;
698
699 for (i = 0; i < p->num; i++)
700 {
701 h = (((h << 1) | (h >> 31)) ^
702 FcStringHash ((const FcChar8 *) p->elts[i].object) ^
703 FcValueListHash (p->elts[i].values));
704 }
705 return h;
706}
707
e9be9cd1
KP
708FcBool
709FcPatternEqualSubset (const FcPattern *pa, const FcPattern *pb, const FcObjectSet *os)
710{
711 FcPatternElt *ea, *eb;
712 int i;
713
714 for (i = 0; i < os->nobject; i++)
715 {
716 ea = FcPatternFindElt (pa, os->objects[i]);
717 eb = FcPatternFindElt (pb, os->objects[i]);
718 if (ea)
719 {
720 if (!eb)
721 return FcFalse;
722 if (!FcValueListEqual (ea->values, eb->values))
723 return FcFalse;
724 }
725 else
726 {
727 if (eb)
728 return FcFalse;
729 }
730 }
731 return FcTrue;
732}
733
24330d27 734FcBool
82f4243f
KP
735FcPatternAddWithBinding (FcPattern *p,
736 const char *object,
737 FcValue value,
738 FcValueBinding binding,
739 FcBool append)
24330d27
KP
740{
741 FcPatternElt *e;
742 FcValueList *new, **prev;
743
d8d73958
KP
744 if (p->ref == FC_REF_CONSTANT)
745 goto bail0;
746
24330d27
KP
747 new = (FcValueList *) malloc (sizeof (FcValueList));
748 if (!new)
749 goto bail0;
750
751 FcMemAlloc (FC_MEM_VALLIST, sizeof (FcValueList));
752 /* dup string */
753 value = FcValueSave (value);
754 if (value.type == FcTypeVoid)
755 goto bail1;
756
757 new->value = value;
82f4243f 758 new->binding = binding;
24330d27
KP
759 new->next = 0;
760
e9be9cd1 761 e = FcPatternInsertElt (p, object);
24330d27
KP
762 if (!e)
763 goto bail2;
764
765 if (append)
766 {
767 for (prev = &e->values; *prev; prev = &(*prev)->next);
768 *prev = new;
769 }
770 else
771 {
772 new->next = e->values;
773 e->values = new;
774 }
775
776 return FcTrue;
777
778bail2:
779 switch (value.type) {
780 case FcTypeString:
781 FcStrFree ((FcChar8 *) value.u.s);
782 break;
783 case FcTypeMatrix:
784 FcMatrixFree ((FcMatrix *) value.u.m);
785 break;
786 case FcTypeCharSet:
787 FcCharSetDestroy ((FcCharSet *) value.u.c);
788 break;
d8d73958
KP
789 case FcTypeLangSet:
790 FcLangSetDestroy ((FcLangSet *) value.u.l);
791 break;
24330d27
KP
792 default:
793 break;
794 }
795bail1:
796 FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList));
797 free (new);
798bail0:
799 return FcFalse;
800}
801
82f4243f
KP
802FcBool
803FcPatternAdd (FcPattern *p, const char *object, FcValue value, FcBool append)
804{
805 return FcPatternAddWithBinding (p, object, value, FcValueBindingStrong, append);
806}
807
808FcBool
809FcPatternAddWeak (FcPattern *p, const char *object, FcValue value, FcBool append)
810{
811 return FcPatternAddWithBinding (p, object, value, FcValueBindingWeak, append);
812}
813
24330d27
KP
814FcBool
815FcPatternDel (FcPattern *p, const char *object)
816{
817 FcPatternElt *e;
818 int i;
819
e9be9cd1 820 e = FcPatternFindElt (p, object);
24330d27
KP
821 if (!e)
822 return FcFalse;
823
824 i = e - p->elts;
825
826 /* destroy value */
827 FcValueListDestroy (e->values);
828
829 /* shuffle existing ones down */
830 memmove (e, e+1, (p->elts + p->num - (e + 1)) * sizeof (FcPatternElt));
831 p->num--;
832 p->elts[p->num].object = 0;
833 p->elts[p->num].values = 0;
834 return FcTrue;
835}
836
4f27c1c0
KP
837FcBool
838FcPatternRemove (FcPattern *p, const char *object, int id)
839{
840 FcPatternElt *e;
841 FcValueList **prev, *l;
842
843 e = FcPatternFindElt (p, object);
844 if (!e)
845 return FcFalse;
846 for (prev = &e->values; (l = *prev); prev = &l->next)
847 {
848 if (!id)
849 {
850 *prev = l->next;
851 l->next = 0;
852 FcValueListDestroy (l);
853 if (!e->values)
854 FcPatternDel (p, object);
855 return FcTrue;
856 }
857 id--;
858 }
859 return FcFalse;
860}
861
24330d27
KP
862FcBool
863FcPatternAddInteger (FcPattern *p, const char *object, int i)
864{
865 FcValue v;
866
867 v.type = FcTypeInteger;
868 v.u.i = i;
869 return FcPatternAdd (p, object, v, FcTrue);
870}
871
872FcBool
873FcPatternAddDouble (FcPattern *p, const char *object, double d)
874{
875 FcValue v;
876
877 v.type = FcTypeDouble;
878 v.u.d = d;
879 return FcPatternAdd (p, object, v, FcTrue);
880}
881
882
883FcBool
ccb3e93b 884FcPatternAddString (FcPattern *p, const char *object, const FcChar8 *s)
24330d27
KP
885{
886 FcValue v;
887
888 v.type = FcTypeString;
ccb3e93b 889 v.u.s = s;
24330d27
KP
890 return FcPatternAdd (p, object, v, FcTrue);
891}
892
893FcBool
894FcPatternAddMatrix (FcPattern *p, const char *object, const FcMatrix *s)
895{
896 FcValue v;
897
898 v.type = FcTypeMatrix;
899 v.u.m = (FcMatrix *) s;
900 return FcPatternAdd (p, object, v, FcTrue);
901}
902
903
904FcBool
905FcPatternAddBool (FcPattern *p, const char *object, FcBool b)
906{
907 FcValue v;
908
909 v.type = FcTypeBool;
910 v.u.b = b;
911 return FcPatternAdd (p, object, v, FcTrue);
912}
913
914FcBool
915FcPatternAddCharSet (FcPattern *p, const char *object, const FcCharSet *c)
916{
917 FcValue v;
918
919 v.type = FcTypeCharSet;
920 v.u.c = (FcCharSet *) c;
921 return FcPatternAdd (p, object, v, FcTrue);
922}
923
be094850
KP
924FcBool
925FcPatternAddFTFace (FcPattern *p, const char *object, const FT_Face f)
926{
927 FcValue v;
928
929 v.type = FcTypeFTFace;
930 v.u.f = (void *) f;
931 return FcPatternAdd (p, object, v, FcTrue);
932}
933
d8d73958
KP
934FcBool
935FcPatternAddLangSet (FcPattern *p, const char *object, const FcLangSet *ls)
936{
937 FcValue v;
938
939 v.type = FcTypeLangSet;
940 v.u.l = (FcLangSet *) ls;
941 return FcPatternAdd (p, object, v, FcTrue);
942}
943
24330d27 944FcResult
bff80114 945FcPatternGet (const FcPattern *p, const char *object, int id, FcValue *v)
24330d27
KP
946{
947 FcPatternElt *e;
948 FcValueList *l;
949
e9be9cd1 950 e = FcPatternFindElt (p, object);
24330d27
KP
951 if (!e)
952 return FcResultNoMatch;
953 for (l = e->values; l; l = l->next)
954 {
955 if (!id)
956 {
957 *v = l->value;
958 return FcResultMatch;
959 }
960 id--;
961 }
962 return FcResultNoId;
963}
964
965FcResult
bff80114 966FcPatternGetInteger (const FcPattern *p, const char *object, int id, int *i)
24330d27
KP
967{
968 FcValue v;
969 FcResult r;
970
971 r = FcPatternGet (p, object, id, &v);
972 if (r != FcResultMatch)
973 return r;
974 switch (v.type) {
975 case FcTypeDouble:
976 *i = (int) v.u.d;
977 break;
978 case FcTypeInteger:
979 *i = v.u.i;
980 break;
981 default:
982 return FcResultTypeMismatch;
983 }
984 return FcResultMatch;
985}
986
987FcResult
bff80114 988FcPatternGetDouble (const FcPattern *p, const char *object, int id, double *d)
24330d27
KP
989{
990 FcValue v;
991 FcResult r;
992
993 r = FcPatternGet (p, object, id, &v);
994 if (r != FcResultMatch)
995 return r;
996 switch (v.type) {
997 case FcTypeDouble:
998 *d = v.u.d;
999 break;
1000 case FcTypeInteger:
1001 *d = (double) v.u.i;
1002 break;
1003 default:
1004 return FcResultTypeMismatch;
1005 }
1006 return FcResultMatch;
1007}
1008
1009FcResult
bff80114 1010FcPatternGetString (const FcPattern *p, const char *object, int id, FcChar8 ** s)
24330d27
KP
1011{
1012 FcValue v;
1013 FcResult r;
1014
1015 r = FcPatternGet (p, object, id, &v);
1016 if (r != FcResultMatch)
1017 return r;
1018 if (v.type != FcTypeString)
1019 return FcResultTypeMismatch;
aae6f7d4 1020 *s = (FcChar8 *) v.u.s;
24330d27
KP
1021 return FcResultMatch;
1022}
1023
1024FcResult
bff80114 1025FcPatternGetMatrix(const FcPattern *p, const char *object, int id, FcMatrix **m)
24330d27
KP
1026{
1027 FcValue v;
1028 FcResult r;
1029
1030 r = FcPatternGet (p, object, id, &v);
1031 if (r != FcResultMatch)
1032 return r;
1033 if (v.type != FcTypeMatrix)
1034 return FcResultTypeMismatch;
1035 *m = (FcMatrix *) v.u.m;
1036 return FcResultMatch;
1037}
1038
1039
1040FcResult
bff80114 1041FcPatternGetBool(const FcPattern *p, const char *object, int id, FcBool *b)
24330d27
KP
1042{
1043 FcValue v;
1044 FcResult r;
1045
1046 r = FcPatternGet (p, object, id, &v);
1047 if (r != FcResultMatch)
1048 return r;
1049 if (v.type != FcTypeBool)
1050 return FcResultTypeMismatch;
1051 *b = v.u.b;
1052 return FcResultMatch;
1053}
1054
1055FcResult
bff80114 1056FcPatternGetCharSet(const FcPattern *p, const char *object, int id, FcCharSet **c)
24330d27
KP
1057{
1058 FcValue v;
1059 FcResult r;
1060
1061 r = FcPatternGet (p, object, id, &v);
1062 if (r != FcResultMatch)
1063 return r;
1064 if (v.type != FcTypeCharSet)
1065 return FcResultTypeMismatch;
1066 *c = (FcCharSet *) v.u.c;
1067 return FcResultMatch;
1068}
1069
be094850 1070FcResult
bff80114 1071FcPatternGetFTFace(const FcPattern *p, const char *object, int id, FT_Face *f)
be094850
KP
1072{
1073 FcValue v;
1074 FcResult r;
1075
1076 r = FcPatternGet (p, object, id, &v);
1077 if (r != FcResultMatch)
1078 return r;
1079 if (v.type != FcTypeFTFace)
1080 return FcResultTypeMismatch;
1081 *f = (FT_Face) v.u.f;
1082 return FcResultMatch;
1083}
1084
d8d73958 1085FcResult
bff80114 1086FcPatternGetLangSet(const FcPattern *p, const char *object, int id, FcLangSet **ls)
d8d73958
KP
1087{
1088 FcValue v;
1089 FcResult r;
1090
1091 r = FcPatternGet (p, object, id, &v);
1092 if (r != FcResultMatch)
1093 return r;
1094 if (v.type != FcTypeLangSet)
1095 return FcResultTypeMismatch;
1096 *ls = (FcLangSet *) v.u.l;
1097 return FcResultMatch;
1098}
1099
24330d27 1100FcPattern *
bff80114 1101FcPatternDuplicate (const FcPattern *orig)
24330d27
KP
1102{
1103 FcPattern *new;
1104 int i;
1105 FcValueList *l;
1106
1107 new = FcPatternCreate ();
1108 if (!new)
1109 goto bail0;
1110
1111 for (i = 0; i < orig->num; i++)
1112 {
1113 for (l = orig->elts[i].values; l; l = l->next)
1114 if (!FcPatternAdd (new, orig->elts[i].object, l->value, FcTrue))
1115 goto bail1;
1116 }
1117
1118 return new;
1119
1120bail1:
1121 FcPatternDestroy (new);
1122bail0:
1123 return 0;
1124}
1125
6f6563ed
KP
1126void
1127FcPatternReference (FcPattern *p)
1128{
d8d73958
KP
1129 if (p->ref != FC_REF_CONSTANT)
1130 p->ref++;
6f6563ed
KP
1131}
1132
24330d27
KP
1133FcPattern *
1134FcPatternVaBuild (FcPattern *orig, va_list va)
1135{
1136 FcPattern *ret;
1137
1138 FcPatternVapBuild (ret, orig, va);
1139 return ret;
1140}
1141
1142FcPattern *
1143FcPatternBuild (FcPattern *orig, ...)
1144{
1145 va_list va;
1146
1147 va_start (va, orig);
1148 FcPatternVapBuild (orig, orig, va);
1149 va_end (va);
1150 return orig;
1151}
4f27c1c0
KP
1152
1153/*
1154 * Add all of the elements in 's' to 'p'
1155 */
1156FcBool
1157FcPatternAppend (FcPattern *p, FcPattern *s)
1158{
1159 int i;
1160 FcPatternElt *e;
1161 FcValueList *v;
1162
1163 for (i = 0; i < s->num; i++)
1164 {
1165 e = &s->elts[i];
1166 for (v = e->values; v; v = v->next)
1167 {
1168 if (!FcPatternAddWithBinding (p, e->object,
1169 v->value, v->binding, FcTrue))
1170 return FcFalse;
1171 }
1172 }
1173 return FcTrue;
1174}
1175
1176const char *
1177FcObjectStaticName (const char *name)
1178{
1179#define OBJECT_HASH_SIZE 31
1180 static struct objectBucket {
1181 struct objectBucket *next;
1182 FcChar32 hash;
1183 } *buckets[OBJECT_HASH_SIZE];
1184 FcChar32 hash = FcStringHash ((const FcChar8 *) name);
1185 struct objectBucket **p;
1186 struct objectBucket *b;
1c52c0f0 1187 int size;
4f27c1c0
KP
1188
1189 for (p = &buckets[hash % OBJECT_HASH_SIZE]; (b = *p); p = &(b->next))
1190 if (b->hash == hash && !strcmp (name, (char *) (b + 1)))
1191 return (char *) (b + 1);
1c52c0f0
KP
1192 size = sizeof (struct objectBucket) + strlen (name) + 1;
1193 b = malloc (size);
1194 FcMemAlloc (FC_MEM_STATICSTR, size);
4f27c1c0
KP
1195 if (!b)
1196 return NULL;
1197 b->next = 0;
1198 b->hash = hash;
1199 strcpy ((char *) (b + 1), name);
1200 *p = b;
1201 return (char *) (b + 1);
1202}