]> git.wh0rd.org Git - fontconfig.git/blob - src/fcpat.c
Add FcPatternHash, clean up a few valgrind issues
[fontconfig.git] / src / fcpat.c
1 /*
2  * $XFree86: xc/lib/fontconfig/src/fcpat.c,v 1.6 2002/05/31 23:21:25 keithp 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 "fcint.h"
28
29 FcPattern *
30 FcPatternCreate (void)
31 {
32     FcPattern   *p;
33
34     p = (FcPattern *) malloc (sizeof (FcPattern));
35     if (!p)
36         return 0;
37     FcMemAlloc (FC_MEM_PATTERN, sizeof (FcPattern));
38     p->num = 0;
39     p->size = 0;
40     p->elts = 0;
41     return p;
42 }
43
44 void
45 FcValueDestroy (FcValue v)
46 {
47     switch (v.type) {
48     case FcTypeString:
49         FcStrFree ((FcChar8 *) v.u.s);
50         break;
51     case FcTypeMatrix:
52         FcMatrixFree ((FcMatrix *) v.u.m);
53         break;
54     case FcTypeCharSet:
55         FcCharSetDestroy ((FcCharSet *) v.u.c);
56         break;
57     default:
58         break;
59     }
60 }
61
62 FcValue
63 FcValueSave (FcValue v)
64 {
65     switch (v.type) {
66     case FcTypeString:
67         v.u.s = FcStrCopy (v.u.s);
68         if (!v.u.s)
69             v.type = FcTypeVoid;
70         break;
71     case FcTypeMatrix:
72         v.u.m = FcMatrixCopy (v.u.m);
73         if (!v.u.m)
74             v.type = FcTypeVoid;
75         break;
76     case FcTypeCharSet:
77         v.u.c = FcCharSetCopy ((FcCharSet *) v.u.c);
78         if (!v.u.c)
79             v.type = FcTypeVoid;
80         break;
81     default:
82         break;
83     }
84     return v;
85 }
86
87 void
88 FcValueListDestroy (FcValueList *l)
89 {
90     FcValueList    *next;
91     for (; l; l = next)
92     {
93         switch (l->value.type) {
94         case FcTypeString:
95             FcStrFree ((FcChar8 *) l->value.u.s);
96             break;
97         case FcTypeMatrix:
98             FcMatrixFree ((FcMatrix *) l->value.u.m);
99             break;
100         case FcTypeCharSet:
101             FcCharSetDestroy ((FcCharSet *) l->value.u.c);
102             break;
103         default:
104             break;
105         }
106         next = l->next;
107         FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList));
108         free (l);
109     }
110 }
111
112 FcBool
113 FcValueEqual (FcValue va, FcValue vb)
114 {
115     if (va.type != vb.type)
116     {
117         if (va.type == FcTypeInteger)
118         {
119             va.type = FcTypeDouble;
120             va.u.d = va.u.i;
121         }
122         if (vb.type == FcTypeInteger)
123         {
124             vb.type = FcTypeDouble;
125             vb.u.d = vb.u.i;
126         }
127         if (va.type != vb.type)
128             return FcFalse;
129     }
130     switch (va.type) {
131     case FcTypeVoid:
132         return FcTrue;
133     case FcTypeInteger:
134         return va.u.i == vb.u.i;
135     case FcTypeDouble:
136         return va.u.d == vb.u.d;
137     case FcTypeString:
138         return FcStrCmpIgnoreCase (va.u.s, vb.u.s) == 0;
139     case FcTypeBool:
140         return va.u.b == vb.u.b;
141     case FcTypeMatrix:
142         return FcMatrixEqual (va.u.m, vb.u.m);
143     case FcTypeCharSet:
144         return FcCharSetEqual (va.u.c, vb.u.c);
145     case FcTypeFTFace:
146         return va.u.f == vb.u.f;
147     }
148     return FcFalse;
149 }
150
151 static FcChar32
152 FcDoubleHash (double d)
153 {
154     if (d < 0)
155         d = -d;
156     if (d > 0xffffffff)
157         d = 0xffffffff;
158     return (FcChar32) d;
159 }
160
161 static FcChar32
162 FcStringHash (const FcChar8 *s)
163 {
164     FcChar8     c;
165     FcChar32    h = 0;
166     
167     if (s)
168         while ((c = *s++))
169             h = ((h << 1) | (h >> 31)) ^ c;
170     return h;
171 }
172
173 static FcChar32
174 FcValueHash (FcValue v)
175 {
176     switch (v.type) {
177     case FcTypeVoid:
178         return 0;
179     case FcTypeInteger:
180         return (FcChar32) v.u.i;
181     case FcTypeDouble:
182         return FcDoubleHash (v.u.d);
183     case FcTypeString:
184         return FcStringHash (v.u.s);
185     case FcTypeBool:
186         return (FcChar32) v.u.b;
187     case FcTypeMatrix:
188         return (FcDoubleHash (v.u.m->xx) ^ 
189                 FcDoubleHash (v.u.m->xy) ^ 
190                 FcDoubleHash (v.u.m->yx) ^ 
191                 FcDoubleHash (v.u.m->yy));
192     case FcTypeCharSet:
193         return (FcChar32) v.u.c->num;
194     case FcTypeFTFace:
195         return FcStringHash ((const FcChar8 *) ((FT_Face) v.u.f)->family_name) ^
196                FcStringHash ((const FcChar8 *) ((FT_Face) v.u.f)->style_name);
197     }
198     return FcFalse;
199 }
200
201 static FcBool
202 FcValueListEqual (FcValueList *la, FcValueList *lb)
203 {
204     while (la && lb)
205     {
206         if (!FcValueEqual (la->value, lb->value))
207             return FcFalse;
208         la = la->next;
209         lb = lb->next;
210     }
211     if (la || lb)
212         return FcFalse;
213     return FcTrue;
214 }
215
216 static FcChar32
217 FcValueListHash (FcValueList *l)
218 {
219     FcChar32    hash = 0;
220     
221     while (l)
222     {
223         hash = ((hash << 1) | (hash >> 31)) ^ FcValueHash (l->value);
224         l = l->next;
225     }
226     return hash;
227 }
228
229 void
230 FcPatternDestroy (FcPattern *p)
231 {
232     int             i;
233     
234     for (i = 0; i < p->num; i++)
235         FcValueListDestroy (p->elts[i].values);
236
237     p->num = 0;
238     if (p->elts)
239     {
240         FcMemFree (FC_MEM_PATELT, p->size * sizeof (FcPatternElt));
241         free (p->elts);
242         p->elts = 0;
243     }
244     p->size = 0;
245     FcMemFree (FC_MEM_PATTERN, sizeof (FcPattern));
246     free (p);
247 }
248
249 static int
250 FcPatternPosition (const FcPattern *p, const char *object)
251 {
252     int     low, high, mid, c;
253
254     low = 0;
255     high = p->num - 1;
256     c = 1;
257     mid = 0;
258     while (low <= high)
259     {
260         mid = (low + high) >> 1;
261         c = strcmp (p->elts[mid].object, object);
262         if (c == 0)
263             return mid;
264         if (c < 0)
265             low = mid + 1;
266         else
267             high = mid - 1;
268     }
269     if (c < 0)
270         mid++;
271     return -(mid + 1);
272 }
273
274 FcPatternElt *
275 FcPatternFindElt (const FcPattern *p, const char *object)
276 {
277     int     i = FcPatternPosition (p, object);
278     if (i < 0)
279         return 0;
280     return &p->elts[i];
281 }
282
283 FcPatternElt *
284 FcPatternInsertElt (FcPattern *p, const char *object)
285 {
286     int             i;
287     FcPatternElt   *e;
288     
289     i = FcPatternPosition (p, object);
290     if (i < 0)
291     {
292         i = -i - 1;
293     
294         /* grow array */
295         if (p->num + 1 >= p->size)
296         {
297             int s = p->size + 16;
298             if (p->elts)
299                 e = (FcPatternElt *) realloc (p->elts, s * sizeof (FcPatternElt));
300             else
301                 e = (FcPatternElt *) malloc (s * sizeof (FcPatternElt));
302             if (!e)
303                 return FcFalse;
304             p->elts = e;
305             if (p->size)
306                 FcMemFree (FC_MEM_PATELT, p->size * sizeof (FcPatternElt));
307             FcMemAlloc (FC_MEM_PATELT, s * sizeof (FcPatternElt));
308             while (p->size < s)
309             {
310                 p->elts[p->size].object = 0;
311                 p->elts[p->size].values = 0;
312                 p->size++;
313             }
314         }
315         
316         /* move elts up */
317         memmove (p->elts + i + 1,
318                  p->elts + i,
319                  sizeof (FcPatternElt) *
320                  (p->num - i));
321                  
322         /* bump count */
323         p->num++;
324         
325         p->elts[i].object = object;
326         p->elts[i].values = 0;
327     }
328     
329     return &p->elts[i];
330 }
331
332 FcBool
333 FcPatternEqual (const FcPattern *pa, const FcPattern *pb)
334 {
335     int i;
336
337     if (pa->num != pb->num)
338         return FcFalse;
339     for (i = 0; i < pa->num; i++)
340     {
341         if (strcmp (pa->elts[i].object, pb->elts[i].object) != 0)
342             return FcFalse;
343         if (!FcValueListEqual (pa->elts[i].values, pb->elts[i].values))
344             return FcFalse;
345     }
346     return FcTrue;
347 }
348
349 FcChar32
350 FcPatternHash (const FcPattern *p)
351 {
352     int         i;
353     FcChar32    h = 0;
354
355     for (i = 0; i < p->num; i++)
356     {
357         h = (((h << 1) | (h >> 31)) ^ 
358              FcStringHash ((const FcChar8 *) p->elts[i].object) ^
359              FcValueListHash (p->elts[i].values));
360     }
361     return h;
362 }
363
364 FcBool
365 FcPatternEqualSubset (const FcPattern *pa, const FcPattern *pb, const FcObjectSet *os)
366 {
367     FcPatternElt    *ea, *eb;
368     int             i;
369     
370     for (i = 0; i < os->nobject; i++)
371     {
372         ea = FcPatternFindElt (pa, os->objects[i]);
373         eb = FcPatternFindElt (pb, os->objects[i]);
374         if (ea)
375         {
376             if (!eb)
377                 return FcFalse;
378             if (!FcValueListEqual (ea->values, eb->values))
379                 return FcFalse;
380         }
381         else
382         {
383             if (eb)
384                 return FcFalse;
385         }
386     }
387     return FcTrue;
388 }
389
390 FcBool
391 FcPatternAdd (FcPattern *p, const char *object, FcValue value, FcBool append)
392 {
393     FcPatternElt   *e;
394     FcValueList    *new, **prev;
395
396     new = (FcValueList *) malloc (sizeof (FcValueList));
397     if (!new)
398         goto bail0;
399
400     FcMemAlloc (FC_MEM_VALLIST, sizeof (FcValueList));
401     /* dup string */
402     value = FcValueSave (value);
403     if (value.type == FcTypeVoid)
404         goto bail1;
405
406     new->value = value;
407     new->next = 0;
408     
409     e = FcPatternInsertElt (p, object);
410     if (!e)
411         goto bail2;
412     
413     if (append)
414     {
415         for (prev = &e->values; *prev; prev = &(*prev)->next);
416         *prev = new;
417     }
418     else
419     {
420         new->next = e->values;
421         e->values = new;
422     }
423     
424     return FcTrue;
425
426 bail2:    
427     switch (value.type) {
428     case FcTypeString:
429         FcStrFree ((FcChar8 *) value.u.s);
430         break;
431     case FcTypeMatrix:
432         FcMatrixFree ((FcMatrix *) value.u.m);
433         break;
434     case FcTypeCharSet:
435         FcCharSetDestroy ((FcCharSet *) value.u.c);
436         break;
437     default:
438         break;
439     }
440 bail1:
441     FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList));
442     free (new);
443 bail0:
444     return FcFalse;
445 }
446
447 FcBool
448 FcPatternDel (FcPattern *p, const char *object)
449 {
450     FcPatternElt   *e;
451     int             i;
452
453     e = FcPatternFindElt (p, object);
454     if (!e)
455         return FcFalse;
456
457     i = e - p->elts;
458     
459     /* destroy value */
460     FcValueListDestroy (e->values);
461     
462     /* shuffle existing ones down */
463     memmove (e, e+1, (p->elts + p->num - (e + 1)) * sizeof (FcPatternElt));
464     p->num--;
465     p->elts[p->num].object = 0;
466     p->elts[p->num].values = 0;
467     return FcTrue;
468 }
469
470 FcBool
471 FcPatternAddInteger (FcPattern *p, const char *object, int i)
472 {
473     FcValue     v;
474
475     v.type = FcTypeInteger;
476     v.u.i = i;
477     return FcPatternAdd (p, object, v, FcTrue);
478 }
479
480 FcBool
481 FcPatternAddDouble (FcPattern *p, const char *object, double d)
482 {
483     FcValue     v;
484
485     v.type = FcTypeDouble;
486     v.u.d = d;
487     return FcPatternAdd (p, object, v, FcTrue);
488 }
489
490
491 FcBool
492 FcPatternAddString (FcPattern *p, const char *object, const FcChar8 *s)
493 {
494     FcValue     v;
495
496     v.type = FcTypeString;
497     v.u.s = s;
498     return FcPatternAdd (p, object, v, FcTrue);
499 }
500
501 FcBool
502 FcPatternAddMatrix (FcPattern *p, const char *object, const FcMatrix *s)
503 {
504     FcValue     v;
505
506     v.type = FcTypeMatrix;
507     v.u.m = (FcMatrix *) s;
508     return FcPatternAdd (p, object, v, FcTrue);
509 }
510
511
512 FcBool
513 FcPatternAddBool (FcPattern *p, const char *object, FcBool b)
514 {
515     FcValue     v;
516
517     v.type = FcTypeBool;
518     v.u.b = b;
519     return FcPatternAdd (p, object, v, FcTrue);
520 }
521
522 FcBool
523 FcPatternAddCharSet (FcPattern *p, const char *object, const FcCharSet *c)
524 {
525     FcValue     v;
526
527     v.type = FcTypeCharSet;
528     v.u.c = (FcCharSet *) c;
529     return FcPatternAdd (p, object, v, FcTrue);
530 }
531
532 FcBool
533 FcPatternAddFTFace (FcPattern *p, const char *object, const FT_Face f)
534 {
535     FcValue     v;
536
537     v.type = FcTypeFTFace;
538     v.u.f = (void *) f;
539     return FcPatternAdd (p, object, v, FcTrue);
540 }
541
542 FcResult
543 FcPatternGet (FcPattern *p, const char *object, int id, FcValue *v)
544 {
545     FcPatternElt   *e;
546     FcValueList    *l;
547
548     e = FcPatternFindElt (p, object);
549     if (!e)
550         return FcResultNoMatch;
551     for (l = e->values; l; l = l->next)
552     {
553         if (!id)
554         {
555             *v = l->value;
556             return FcResultMatch;
557         }
558         id--;
559     }
560     return FcResultNoId;
561 }
562
563 FcResult
564 FcPatternGetInteger (FcPattern *p, const char *object, int id, int *i)
565 {
566     FcValue     v;
567     FcResult    r;
568
569     r = FcPatternGet (p, object, id, &v);
570     if (r != FcResultMatch)
571         return r;
572     switch (v.type) {
573     case FcTypeDouble:
574         *i = (int) v.u.d;
575         break;
576     case FcTypeInteger:
577         *i = v.u.i;
578         break;
579     default:
580         return FcResultTypeMismatch;
581     }
582     return FcResultMatch;
583 }
584
585 FcResult
586 FcPatternGetDouble (FcPattern *p, const char *object, int id, double *d)
587 {
588     FcValue     v;
589     FcResult    r;
590
591     r = FcPatternGet (p, object, id, &v);
592     if (r != FcResultMatch)
593         return r;
594     switch (v.type) {
595     case FcTypeDouble:
596         *d = v.u.d;
597         break;
598     case FcTypeInteger:
599         *d = (double) v.u.i;
600         break;
601     default:
602         return FcResultTypeMismatch;
603     }
604     return FcResultMatch;
605 }
606
607 FcResult
608 FcPatternGetString (FcPattern *p, const char *object, int id, FcChar8 ** s)
609 {
610     FcValue     v;
611     FcResult    r;
612
613     r = FcPatternGet (p, object, id, &v);
614     if (r != FcResultMatch)
615         return r;
616     if (v.type != FcTypeString)
617         return FcResultTypeMismatch;
618     *s = (FcChar8 *) v.u.s;
619     return FcResultMatch;
620 }
621
622 FcResult
623 FcPatternGetMatrix (FcPattern *p, const char *object, int id, FcMatrix **m)
624 {
625     FcValue     v;
626     FcResult    r;
627
628     r = FcPatternGet (p, object, id, &v);
629     if (r != FcResultMatch)
630         return r;
631     if (v.type != FcTypeMatrix)
632         return FcResultTypeMismatch;
633     *m = (FcMatrix *) v.u.m;
634     return FcResultMatch;
635 }
636
637
638 FcResult
639 FcPatternGetBool (FcPattern *p, const char *object, int id, FcBool *b)
640 {
641     FcValue     v;
642     FcResult    r;
643
644     r = FcPatternGet (p, object, id, &v);
645     if (r != FcResultMatch)
646         return r;
647     if (v.type != FcTypeBool)
648         return FcResultTypeMismatch;
649     *b = v.u.b;
650     return FcResultMatch;
651 }
652
653 FcResult
654 FcPatternGetCharSet (FcPattern *p, const char *object, int id, FcCharSet **c)
655 {
656     FcValue     v;
657     FcResult    r;
658
659     r = FcPatternGet (p, object, id, &v);
660     if (r != FcResultMatch)
661         return r;
662     if (v.type != FcTypeCharSet)
663         return FcResultTypeMismatch;
664     *c = (FcCharSet *) v.u.c;
665     return FcResultMatch;
666 }
667
668 FcResult
669 FcPatternGetFTFace (FcPattern *p, const char *object, int id, FT_Face *f)
670 {
671     FcValue     v;
672     FcResult    r;
673
674     r = FcPatternGet (p, object, id, &v);
675     if (r != FcResultMatch)
676         return r;
677     if (v.type != FcTypeFTFace)
678         return FcResultTypeMismatch;
679     *f = (FT_Face) v.u.f;
680     return FcResultMatch;
681 }
682
683 FcPattern *
684 FcPatternDuplicate (FcPattern *orig)
685 {
686     FcPattern       *new;
687     int             i;
688     FcValueList    *l;
689
690     new = FcPatternCreate ();
691     if (!new)
692         goto bail0;
693
694     for (i = 0; i < orig->num; i++)
695     {
696         for (l = orig->elts[i].values; l; l = l->next)
697             if (!FcPatternAdd (new, orig->elts[i].object, l->value, FcTrue))
698                 goto bail1;
699     }
700
701     return new;
702
703 bail1:
704     FcPatternDestroy (new);
705 bail0:
706     return 0;
707 }
708
709 FcPattern *
710 FcPatternVaBuild (FcPattern *orig, va_list va)
711 {
712     FcPattern   *ret;
713     
714     FcPatternVapBuild (ret, orig, va);
715     return ret;
716 }
717
718 FcPattern *
719 FcPatternBuild (FcPattern *orig, ...)
720 {
721     va_list     va;
722     
723     va_start (va, orig);
724     FcPatternVapBuild (orig, orig, va);
725     va_end (va);
726     return orig;
727 }