]> git.wh0rd.org - 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 }