]> git.wh0rd.org Git - fontconfig.git/blob - src/fcpat.c
Fix structure alignment and array wlk bugs
[fontconfig.git] / src / fcpat.c
1 /*
2  * $XFree86: xc/lib/fontconfig/src/fcpat.c,v 1.16tsi Exp $
3  *
4  * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc.
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>
27 #include <assert.h>
28 #include "fcint.h"
29
30 FcPattern *
31 FcPatternCreate (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;
42     p->ref = 1;
43     return p;
44 }
45
46 void
47 FcValueDestroy (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;
59     case FcTypeLangSet:
60         FcLangSetDestroy ((FcLangSet *) v.u.l);
61         break;
62     default:
63         break;
64     }
65 }
66
67 FcValue
68 FcValueSave (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;
86     case FcTypeLangSet:
87         v.u.l = FcLangSetCopy (v.u.l);
88         if (!v.u.l)
89             v.type = FcTypeVoid;
90         break;
91     default:
92         break;
93     }
94     return v;
95 }
96
97 void
98 FcValueListDestroy (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;
113         case FcTypeLangSet:
114             FcLangSetDestroy ((FcLangSet *) l->value.u.l);
115             break;
116         default:
117             break;
118         }
119         next = l->next;
120         FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList));
121         free (l);
122     }
123 }
124
125 FcBool
126 FcValueEqual (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);
158     case FcTypeFTFace:
159         return va.u.f == vb.u.f;
160     case FcTypeLangSet:
161         return FcLangSetEqual (va.u.l, vb.u.l);
162     }
163     return FcFalse;
164 }
165
166 static FcChar32
167 FcDoubleHash (double d)
168 {
169     if (d < 0)
170         d = -d;
171     if (d > 0xffffffff)
172         d = 0xffffffff;
173     return (FcChar32) d;
174 }
175
176 static FcChar32
177 FcStringHash (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
188 static FcChar32
189 FcValueHash (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);
212     case FcTypeLangSet:
213         return FcLangSetHash (v.u.l);
214     }
215     return FcFalse;
216 }
217
218 static FcBool
219 FcValueListEqual (FcValueList *la, FcValueList *lb)
220 {
221     if (la == lb)
222         return FcTrue;
223
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
236 static FcChar32
237 FcValueListHash (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
249 void
250 FcPatternDestroy (FcPattern *p)
251 {
252     int             i;
253     
254     if (p->ref == FC_REF_CONSTANT || --p->ref > 0)
255         return;
256
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
272 #define FC_VALUE_LIST_HASH_SIZE     257
273 #define FC_PATTERN_HASH_SIZE        67
274
275 typedef struct _FcValueListEnt FcValueListEnt;
276
277 struct _FcValueListEnt {
278     FcValueListEnt  *next;
279     FcValueList     *list;
280     FcChar32        hash, pad;
281 };
282
283 static int          FcValueListFrozenCount[FcTypeLangSet + 1];
284 static int          FcValueListFrozenBytes[FcTypeLangSet + 1];
285 static char         *FcValueListFrozenName[] = {
286     "Void", 
287     "Integer", 
288     "Double", 
289     "String", 
290     "Bool",
291     "Matrix",
292     "CharSet",
293     "FTFace",
294     "LangSet"
295 };
296
297 void
298 FcValueListReport (void);
299     
300 void
301 FcValueListReport (void)
302 {
303     FcType  t;
304
305     printf ("Fc Frozen Values:\n");
306     printf ("\t%8s %9s %9s\n", "Type", "Count", "Bytes");
307     for (t = FcTypeVoid; t <= FcTypeLangSet; t++)
308         printf ("\t%8s %9d %9d\n", FcValueListFrozenName[t],
309                 FcValueListFrozenCount[t], FcValueListFrozenBytes[t]);
310 }
311
312 static FcValueListEnt *
313 FcValueListEntCreate (FcValueList *h)
314 {
315     FcValueListEnt  *e;
316     FcValueList     *l, *new;
317     int             n;
318     int             string_size = 0;
319     FcChar8         *strs;
320     int             size;
321
322     n = 0;
323     for (l = h; l; l = l->next)
324     {
325         if (l->value.type == FcTypeString)
326             string_size += strlen ((char *) l->value.u.s) + 1;
327         n++;
328     }
329     size = sizeof (FcValueListEnt) + n * sizeof (FcValueList) + string_size;
330     FcValueListFrozenCount[h->value.type]++;
331     FcValueListFrozenBytes[h->value.type] += size;
332     e = malloc (size);
333     if (!e)
334         return 0;
335     FcMemAlloc (FC_MEM_VALLIST, size);
336     e->list = (FcValueList *) (e + 1);
337     strs = (FcChar8 *) (e->list + n);
338     new = e->list;
339     for (l = h; l; l = l->next, new++)
340     {
341         if (l->value.type == FcTypeString)
342         {
343             new->value.type = FcTypeString;
344             new->value.u.s = strs;
345             strcpy ((char *) strs, (char *) l->value.u.s);
346             strs += strlen ((char *) strs) + 1;
347         }
348         else
349         {
350             new->value = l->value;
351             new->value = FcValueSave (new->value);
352         }
353         new->binding = l->binding;
354         if (l->next)
355             new->next = new + 1;
356         else
357             new->next = 0;
358     }
359     return e;
360 }
361
362 static int      FcValueListTotal;
363 static int      FcValueListUsed;
364
365 static FcValueList *
366 FcValueListFreeze (FcValueList *l)
367 {
368     static FcValueListEnt   *hashTable[FC_VALUE_LIST_HASH_SIZE];
369     FcChar32                hash = FcValueListHash (l);
370     FcValueListEnt          **bucket = &hashTable[hash % FC_VALUE_LIST_HASH_SIZE];
371     FcValueListEnt          *ent;
372
373     FcValueListTotal++;
374     for (ent = *bucket; ent; ent = ent->next)
375     {
376         if (ent->hash == hash && FcValueListEqual (ent->list, l))
377             return ent->list;
378     }
379
380     ent = FcValueListEntCreate (l);
381     if (!ent)
382         return 0;
383
384     FcValueListUsed++;
385     ent->hash = hash;
386     ent->next = *bucket;
387     *bucket = ent;
388     return ent->list;
389 }
390
391 static FcChar32
392 FcPatternBaseHash (FcPattern *b)
393 {
394     FcChar32    hash = b->num;
395     int         i;
396
397     for (i = 0; i < b->num; i++)
398         hash = ((hash << 1) | (hash >> 31)) ^ ((FcChar32) b->elts[i].values);
399     return hash;
400 }
401
402 typedef struct _FcPatternEnt FcPatternEnt;
403
404 struct _FcPatternEnt {
405     FcPatternEnt    *next;
406     FcChar32        hash;
407     FcPattern       pattern;
408 };
409
410 static int      FcPatternTotal;
411 static int      FcPatternUsed;
412
413 static FcPattern *
414 FcPatternBaseFreeze (FcPattern *b)
415 {
416     static FcPatternEnt *hashTable[FC_VALUE_LIST_HASH_SIZE];
417     FcChar32            hash = FcPatternBaseHash (b);
418     FcPatternEnt        **bucket = &hashTable[hash % FC_VALUE_LIST_HASH_SIZE];
419     FcPatternEnt        *ent;
420     int                 i;
421     char                *objects;
422     int                 size_objects;
423     int                 size;
424
425     FcPatternTotal++;
426     for (ent = *bucket; ent; ent = ent->next)
427     {
428         if (ent->hash == hash && b->num == ent->pattern.num)
429         {
430             for (i = 0; i < b->num; i++)
431             {
432                 if (strcmp (b->elts[i].object, ent->pattern.elts[i].object))
433                     break;
434                 if (b->elts[i].values != ent->pattern.elts[i].values)
435                     break;
436             }
437             if (i == b->num)
438                 return &ent->pattern;
439         }
440     }
441
442     /*
443      * Compute size of pattern + elts + object names
444      */
445     size_objects = 0;
446     for (i = 0; i < b->num; i++)
447         size_objects += strlen (b->elts[i].object) + 1;
448
449     size = sizeof (FcPatternEnt) + b->num*sizeof (FcPatternElt) + size_objects;
450     ent = malloc (size);
451     if (!ent)
452         return 0;
453
454     FcMemAlloc (FC_MEM_PATTERN, size);
455     FcPatternUsed++;
456
457     ent->pattern.elts = (FcPatternElt *) (ent + 1);
458     ent->pattern.num = b->num;
459     ent->pattern.size = b->num;
460     ent->pattern.ref = FC_REF_CONSTANT;
461
462     objects = (char *) (ent->pattern.elts + b->num);
463     for (i = 0; i < b->num; i++)
464     {
465         ent->pattern.elts[i].values = b->elts[i].values;
466         strcpy (objects, b->elts[i].object);
467         ent->pattern.elts[i].object = objects;
468         objects += strlen (objects) + 1;
469     }
470
471     ent->hash = hash;
472     ent->next = *bucket;
473     *bucket = ent;
474     return &ent->pattern;
475 }
476
477 FcPattern *
478 FcPatternFreeze (FcPattern *p)
479 {
480     FcPattern   *b, *n = 0;
481     int         size;
482     int         i;
483     
484     size = sizeof (FcPattern) + p->num * sizeof (FcPatternElt);
485     b = (FcPattern *) malloc (size);
486     if (!b)
487         return 0;
488     FcMemAlloc (FC_MEM_PATTERN, size);
489     b->num = p->num;
490     b->size = b->num;
491     b->ref = 1;
492     b->elts = (FcPatternElt *) (b + 1);
493     /*
494      * Freeze object lists
495      */
496     for (i = 0; i < p->num; i++)
497     {
498         b->elts[i].object = p->elts[i].object;
499         b->elts[i].values = FcValueListFreeze (p->elts[i].values);
500         if (!b->elts[i].values)
501             goto bail;
502     }
503     /*
504      * Freeze base
505      */
506     n = FcPatternBaseFreeze (b);
507 #ifdef CHATTY
508     if (FcDebug() & FC_DBG_MEMORY)
509     {
510         printf ("ValueLists: total %9d used %9d\n", FcValueListTotal, FcValueListUsed);
511         printf ("Patterns:   total %9d used %9d\n", FcPatternTotal, FcPatternUsed);
512     }
513 #endif
514 bail:
515     free (b);
516 #ifdef DEBUG
517     assert (FcPatternEqual (n, p));
518 #endif
519     return n;
520 }
521
522 static int
523 FcPatternPosition (const FcPattern *p, const char *object)
524 {
525     int     low, high, mid, c;
526
527     low = 0;
528     high = p->num - 1;
529     c = 1;
530     mid = 0;
531     while (low <= high)
532     {
533         mid = (low + high) >> 1;
534         c = strcmp (p->elts[mid].object, object);
535         if (c == 0)
536             return mid;
537         if (c < 0)
538             low = mid + 1;
539         else
540             high = mid - 1;
541     }
542     if (c < 0)
543         mid++;
544     return -(mid + 1);
545 }
546
547 FcPatternElt *
548 FcPatternFindElt (const FcPattern *p, const char *object)
549 {
550     int     i = FcPatternPosition (p, object);
551     if (i < 0)
552         return 0;
553     return &p->elts[i];
554 }
555
556 FcPatternElt *
557 FcPatternInsertElt (FcPattern *p, const char *object)
558 {
559     int             i;
560     FcPatternElt   *e;
561     
562     i = FcPatternPosition (p, object);
563     if (i < 0)
564     {
565         i = -i - 1;
566     
567         /* grow array */
568         if (p->num + 1 >= p->size)
569         {
570             int s = p->size + 16;
571             if (p->elts)
572                 e = (FcPatternElt *) realloc (p->elts, s * sizeof (FcPatternElt));
573             else
574                 e = (FcPatternElt *) malloc (s * sizeof (FcPatternElt));
575             if (!e)
576                 return FcFalse;
577             p->elts = e;
578             if (p->size)
579                 FcMemFree (FC_MEM_PATELT, p->size * sizeof (FcPatternElt));
580             FcMemAlloc (FC_MEM_PATELT, s * sizeof (FcPatternElt));
581             while (p->size < s)
582             {
583                 p->elts[p->size].object = 0;
584                 p->elts[p->size].values = 0;
585                 p->size++;
586             }
587         }
588         
589         /* move elts up */
590         memmove (p->elts + i + 1,
591                  p->elts + i,
592                  sizeof (FcPatternElt) *
593                  (p->num - i));
594                  
595         /* bump count */
596         p->num++;
597         
598         p->elts[i].object = object;
599         p->elts[i].values = 0;
600     }
601     
602     return &p->elts[i];
603 }
604
605 FcBool
606 FcPatternEqual (const FcPattern *pa, const FcPattern *pb)
607 {
608     int i;
609
610     if (pa == pb)
611         return FcTrue;
612
613     if (pa->num != pb->num)
614         return FcFalse;
615     for (i = 0; i < pa->num; i++)
616     {
617         if (strcmp (pa->elts[i].object, pb->elts[i].object) != 0)
618             return FcFalse;
619         if (!FcValueListEqual (pa->elts[i].values, pb->elts[i].values))
620             return FcFalse;
621     }
622     return FcTrue;
623 }
624
625 FcChar32
626 FcPatternHash (const FcPattern *p)
627 {
628     int         i;
629     FcChar32    h = 0;
630
631     for (i = 0; i < p->num; i++)
632     {
633         h = (((h << 1) | (h >> 31)) ^ 
634              FcStringHash ((const FcChar8 *) p->elts[i].object) ^
635              FcValueListHash (p->elts[i].values));
636     }
637     return h;
638 }
639
640 FcBool
641 FcPatternEqualSubset (const FcPattern *pa, const FcPattern *pb, const FcObjectSet *os)
642 {
643     FcPatternElt    *ea, *eb;
644     int             i;
645     
646     for (i = 0; i < os->nobject; i++)
647     {
648         ea = FcPatternFindElt (pa, os->objects[i]);
649         eb = FcPatternFindElt (pb, os->objects[i]);
650         if (ea)
651         {
652             if (!eb)
653                 return FcFalse;
654             if (!FcValueListEqual (ea->values, eb->values))
655                 return FcFalse;
656         }
657         else
658         {
659             if (eb)
660                 return FcFalse;
661         }
662     }
663     return FcTrue;
664 }
665
666 FcBool
667 FcPatternAddWithBinding  (FcPattern         *p,
668                           const char        *object,
669                           FcValue           value,
670                           FcValueBinding    binding,
671                           FcBool            append)
672 {
673     FcPatternElt   *e;
674     FcValueList    *new, **prev;
675
676     if (p->ref == FC_REF_CONSTANT)
677         goto bail0;
678
679     new = (FcValueList *) malloc (sizeof (FcValueList));
680     if (!new)
681         goto bail0;
682
683     FcMemAlloc (FC_MEM_VALLIST, sizeof (FcValueList));
684     /* dup string */
685     value = FcValueSave (value);
686     if (value.type == FcTypeVoid)
687         goto bail1;
688
689     new->value = value;
690     new->binding = binding;
691     new->next = 0;
692     
693     e = FcPatternInsertElt (p, object);
694     if (!e)
695         goto bail2;
696     
697     if (append)
698     {
699         for (prev = &e->values; *prev; prev = &(*prev)->next);
700         *prev = new;
701     }
702     else
703     {
704         new->next = e->values;
705         e->values = new;
706     }
707     
708     return FcTrue;
709
710 bail2:    
711     switch (value.type) {
712     case FcTypeString:
713         FcStrFree ((FcChar8 *) value.u.s);
714         break;
715     case FcTypeMatrix:
716         FcMatrixFree ((FcMatrix *) value.u.m);
717         break;
718     case FcTypeCharSet:
719         FcCharSetDestroy ((FcCharSet *) value.u.c);
720         break;
721     case FcTypeLangSet:
722         FcLangSetDestroy ((FcLangSet *) value.u.l);
723         break;
724     default:
725         break;
726     }
727 bail1:
728     FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList));
729     free (new);
730 bail0:
731     return FcFalse;
732 }
733
734 FcBool
735 FcPatternAdd (FcPattern *p, const char *object, FcValue value, FcBool append)
736 {
737     return FcPatternAddWithBinding (p, object, value, FcValueBindingStrong, append);
738 }
739
740 FcBool
741 FcPatternAddWeak  (FcPattern *p, const char *object, FcValue value, FcBool append)
742 {
743     return FcPatternAddWithBinding (p, object, value, FcValueBindingWeak, append);
744 }
745
746 FcBool
747 FcPatternDel (FcPattern *p, const char *object)
748 {
749     FcPatternElt   *e;
750     int             i;
751
752     e = FcPatternFindElt (p, object);
753     if (!e)
754         return FcFalse;
755
756     i = e - p->elts;
757     
758     /* destroy value */
759     FcValueListDestroy (e->values);
760     
761     /* shuffle existing ones down */
762     memmove (e, e+1, (p->elts + p->num - (e + 1)) * sizeof (FcPatternElt));
763     p->num--;
764     p->elts[p->num].object = 0;
765     p->elts[p->num].values = 0;
766     return FcTrue;
767 }
768
769 FcBool
770 FcPatternAddInteger (FcPattern *p, const char *object, int i)
771 {
772     FcValue     v;
773
774     v.type = FcTypeInteger;
775     v.u.i = i;
776     return FcPatternAdd (p, object, v, FcTrue);
777 }
778
779 FcBool
780 FcPatternAddDouble (FcPattern *p, const char *object, double d)
781 {
782     FcValue     v;
783
784     v.type = FcTypeDouble;
785     v.u.d = d;
786     return FcPatternAdd (p, object, v, FcTrue);
787 }
788
789
790 FcBool
791 FcPatternAddString (FcPattern *p, const char *object, const FcChar8 *s)
792 {
793     FcValue     v;
794
795     v.type = FcTypeString;
796     v.u.s = s;
797     return FcPatternAdd (p, object, v, FcTrue);
798 }
799
800 FcBool
801 FcPatternAddMatrix (FcPattern *p, const char *object, const FcMatrix *s)
802 {
803     FcValue     v;
804
805     v.type = FcTypeMatrix;
806     v.u.m = (FcMatrix *) s;
807     return FcPatternAdd (p, object, v, FcTrue);
808 }
809
810
811 FcBool
812 FcPatternAddBool (FcPattern *p, const char *object, FcBool b)
813 {
814     FcValue     v;
815
816     v.type = FcTypeBool;
817     v.u.b = b;
818     return FcPatternAdd (p, object, v, FcTrue);
819 }
820
821 FcBool
822 FcPatternAddCharSet (FcPattern *p, const char *object, const FcCharSet *c)
823 {
824     FcValue     v;
825
826     v.type = FcTypeCharSet;
827     v.u.c = (FcCharSet *) c;
828     return FcPatternAdd (p, object, v, FcTrue);
829 }
830
831 FcBool
832 FcPatternAddFTFace (FcPattern *p, const char *object, const FT_Face f)
833 {
834     FcValue     v;
835
836     v.type = FcTypeFTFace;
837     v.u.f = (void *) f;
838     return FcPatternAdd (p, object, v, FcTrue);
839 }
840
841 FcBool
842 FcPatternAddLangSet (FcPattern *p, const char *object, const FcLangSet *ls)
843 {
844     FcValue     v;
845
846     v.type = FcTypeLangSet;
847     v.u.l = (FcLangSet *) ls;
848     return FcPatternAdd (p, object, v, FcTrue);
849 }
850
851 FcResult
852 FcPatternGet (FcPattern *p, const char *object, int id, FcValue *v)
853 {
854     FcPatternElt   *e;
855     FcValueList    *l;
856
857     e = FcPatternFindElt (p, object);
858     if (!e)
859         return FcResultNoMatch;
860     for (l = e->values; l; l = l->next)
861     {
862         if (!id)
863         {
864             *v = l->value;
865             return FcResultMatch;
866         }
867         id--;
868     }
869     return FcResultNoId;
870 }
871
872 FcResult
873 FcPatternGetInteger (FcPattern *p, const char *object, int id, int *i)
874 {
875     FcValue     v;
876     FcResult    r;
877
878     r = FcPatternGet (p, object, id, &v);
879     if (r != FcResultMatch)
880         return r;
881     switch (v.type) {
882     case FcTypeDouble:
883         *i = (int) v.u.d;
884         break;
885     case FcTypeInteger:
886         *i = v.u.i;
887         break;
888     default:
889         return FcResultTypeMismatch;
890     }
891     return FcResultMatch;
892 }
893
894 FcResult
895 FcPatternGetDouble (FcPattern *p, const char *object, int id, double *d)
896 {
897     FcValue     v;
898     FcResult    r;
899
900     r = FcPatternGet (p, object, id, &v);
901     if (r != FcResultMatch)
902         return r;
903     switch (v.type) {
904     case FcTypeDouble:
905         *d = v.u.d;
906         break;
907     case FcTypeInteger:
908         *d = (double) v.u.i;
909         break;
910     default:
911         return FcResultTypeMismatch;
912     }
913     return FcResultMatch;
914 }
915
916 FcResult
917 FcPatternGetString (FcPattern *p, const char *object, int id, FcChar8 ** s)
918 {
919     FcValue     v;
920     FcResult    r;
921
922     r = FcPatternGet (p, object, id, &v);
923     if (r != FcResultMatch)
924         return r;
925     if (v.type != FcTypeString)
926         return FcResultTypeMismatch;
927     *s = (FcChar8 *) v.u.s;
928     return FcResultMatch;
929 }
930
931 FcResult
932 FcPatternGetMatrix (FcPattern *p, const char *object, int id, FcMatrix **m)
933 {
934     FcValue     v;
935     FcResult    r;
936
937     r = FcPatternGet (p, object, id, &v);
938     if (r != FcResultMatch)
939         return r;
940     if (v.type != FcTypeMatrix)
941         return FcResultTypeMismatch;
942     *m = (FcMatrix *) v.u.m;
943     return FcResultMatch;
944 }
945
946
947 FcResult
948 FcPatternGetBool (FcPattern *p, const char *object, int id, FcBool *b)
949 {
950     FcValue     v;
951     FcResult    r;
952
953     r = FcPatternGet (p, object, id, &v);
954     if (r != FcResultMatch)
955         return r;
956     if (v.type != FcTypeBool)
957         return FcResultTypeMismatch;
958     *b = v.u.b;
959     return FcResultMatch;
960 }
961
962 FcResult
963 FcPatternGetCharSet (FcPattern *p, const char *object, int id, FcCharSet **c)
964 {
965     FcValue     v;
966     FcResult    r;
967
968     r = FcPatternGet (p, object, id, &v);
969     if (r != FcResultMatch)
970         return r;
971     if (v.type != FcTypeCharSet)
972         return FcResultTypeMismatch;
973     *c = (FcCharSet *) v.u.c;
974     return FcResultMatch;
975 }
976
977 FcResult
978 FcPatternGetFTFace (FcPattern *p, const char *object, int id, FT_Face *f)
979 {
980     FcValue     v;
981     FcResult    r;
982
983     r = FcPatternGet (p, object, id, &v);
984     if (r != FcResultMatch)
985         return r;
986     if (v.type != FcTypeFTFace)
987         return FcResultTypeMismatch;
988     *f = (FT_Face) v.u.f;
989     return FcResultMatch;
990 }
991
992 FcResult
993 FcPatternGetLangSet (FcPattern *p, const char *object, int id, FcLangSet **ls)
994 {
995     FcValue     v;
996     FcResult    r;
997
998     r = FcPatternGet (p, object, id, &v);
999     if (r != FcResultMatch)
1000         return r;
1001     if (v.type != FcTypeLangSet)
1002         return FcResultTypeMismatch;
1003     *ls = (FcLangSet *) v.u.l;
1004     return FcResultMatch;
1005 }
1006
1007 FcPattern *
1008 FcPatternDuplicate (FcPattern *orig)
1009 {
1010     FcPattern       *new;
1011     int             i;
1012     FcValueList    *l;
1013
1014     new = FcPatternCreate ();
1015     if (!new)
1016         goto bail0;
1017
1018     for (i = 0; i < orig->num; i++)
1019     {
1020         for (l = orig->elts[i].values; l; l = l->next)
1021             if (!FcPatternAdd (new, orig->elts[i].object, l->value, FcTrue))
1022                 goto bail1;
1023     }
1024
1025     return new;
1026
1027 bail1:
1028     FcPatternDestroy (new);
1029 bail0:
1030     return 0;
1031 }
1032
1033 void
1034 FcPatternReference (FcPattern *p)
1035 {
1036     if (p->ref != FC_REF_CONSTANT)
1037         p->ref++;
1038 }
1039
1040 FcPattern *
1041 FcPatternVaBuild (FcPattern *orig, va_list va)
1042 {
1043     FcPattern   *ret;
1044     
1045     FcPatternVapBuild (ret, orig, va);
1046     return ret;
1047 }
1048
1049 FcPattern *
1050 FcPatternBuild (FcPattern *orig, ...)
1051 {
1052     va_list     va;
1053     
1054     va_start (va, orig);
1055     FcPatternVapBuild (orig, orig, va);
1056     va_end (va);
1057     return orig;
1058 }