]> git.wh0rd.org Git - fontconfig.git/blob - src/fcpat.c
Replace silly avl sort with qsort, add FcPatternEqual
[fontconfig.git] / src / fcpat.c
1 /*
2  * $XFree86: xc/lib/fontconfig/src/fcpat.c,v 1.3 2002/02/19 07:50:44 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     }
146     return FcFalse;
147 }
148
149 static FcBool
150 FcValueListEqual (FcValueList *la, FcValueList *lb)
151 {
152     while (la && lb)
153     {
154         if (!FcValueEqual (la->value, lb->value))
155             return FcFalse;
156         la = la->next;
157         lb = lb->next;
158     }
159     if (la || lb)
160         return FcFalse;
161     return FcTrue;
162 }
163
164 void
165 FcPatternDestroy (FcPattern *p)
166 {
167     int             i;
168     
169     for (i = 0; i < p->num; i++)
170         FcValueListDestroy (p->elts[i].values);
171
172     p->num = 0;
173     if (p->elts)
174     {
175         FcMemFree (FC_MEM_PATELT, p->size * sizeof (FcPatternElt));
176         free (p->elts);
177         p->elts = 0;
178     }
179     p->size = 0;
180     FcMemFree (FC_MEM_PATTERN, sizeof (FcPattern));
181     free (p);
182 }
183
184 FcPatternElt *
185 FcPatternFind (FcPattern *p, const char *object, FcBool insert)
186 {
187     int             i;
188     int             s;
189     FcPatternElt   *e;
190     
191     int             low, high;
192
193     /* match existing */
194     low = 0;
195     high = p->num;
196
197     while (low + 1 < high)
198     {
199         i = (low + high) >> 1;
200         s = FcStrCmpIgnoreCase ((FcChar8 *) object, (FcChar8 *) p->elts[i].object);
201         if (s == 0)
202             return &p->elts[i];
203         if (s < 0)
204             low = i;
205         else
206             high = i;
207     }
208
209     i = low;
210     while (i < high)
211     {
212         s = FcStrCmpIgnoreCase ((FcChar8 *) object, (FcChar8 *) p->elts[i].object);
213         if (s == 0)
214             return &p->elts[i];
215         if (s > 0)
216             break;
217         i++;
218     }
219
220     if (!insert)
221         return 0;
222
223     /* grow array */
224     if (p->num + 1 >= p->size)
225     {
226         s = p->size + 16;
227         if (p->elts)
228             e = (FcPatternElt *) realloc (p->elts, s * sizeof (FcPatternElt));
229         else
230             e = (FcPatternElt *) malloc (s * sizeof (FcPatternElt));
231         if (!e)
232             return FcFalse;
233         p->elts = e;
234         if (p->size)
235             FcMemFree (FC_MEM_PATELT, p->size * sizeof (FcPatternElt));
236         FcMemAlloc (FC_MEM_PATELT, s * sizeof (FcPatternElt));
237         while (p->size < s)
238         {
239             p->elts[p->size].object = 0;
240             p->elts[p->size].values = 0;
241             p->size++;
242         }
243     }
244     
245     /* move elts up */
246     memmove (p->elts + i + 1,
247              p->elts + i,
248              sizeof (FcPatternElt) *
249              (p->num - i));
250              
251     /* bump count */
252     p->num++;
253     
254     p->elts[i].object = object;
255     p->elts[i].values = 0;
256     
257     return &p->elts[i];
258 }
259
260 FcBool
261 FcPatternEqual (FcPattern *pa, FcPattern *pb)
262 {
263     int i;
264
265     if (pa->num != pb->num)
266         return FcFalse;
267     for (i = 0; i < pa->num; i++)
268     {
269         if (FcStrCmpIgnoreCase ((FcChar8 *) pa->elts[i].object,
270                                 (FcChar8 *) pb->elts[i].object) != 0)
271             return FcFalse;
272         if (!FcValueListEqual (pa->elts[i].values, pb->elts[i].values))
273             return FcFalse;
274     }
275     return FcTrue;
276 }
277
278 FcBool
279 FcPatternAdd (FcPattern *p, const char *object, FcValue value, FcBool append)
280 {
281     FcPatternElt   *e;
282     FcValueList    *new, **prev;
283
284     new = (FcValueList *) malloc (sizeof (FcValueList));
285     if (!new)
286         goto bail0;
287
288     FcMemAlloc (FC_MEM_VALLIST, sizeof (FcValueList));
289     /* dup string */
290     value = FcValueSave (value);
291     if (value.type == FcTypeVoid)
292         goto bail1;
293
294     new->value = value;
295     new->next = 0;
296     
297     e = FcPatternFind (p, object, FcTrue);
298     if (!e)
299         goto bail2;
300     
301     if (append)
302     {
303         for (prev = &e->values; *prev; prev = &(*prev)->next);
304         *prev = new;
305     }
306     else
307     {
308         new->next = e->values;
309         e->values = new;
310     }
311     
312     return FcTrue;
313
314 bail2:    
315     switch (value.type) {
316     case FcTypeString:
317         FcStrFree ((FcChar8 *) value.u.s);
318         break;
319     case FcTypeMatrix:
320         FcMatrixFree ((FcMatrix *) value.u.m);
321         break;
322     case FcTypeCharSet:
323         FcCharSetDestroy ((FcCharSet *) value.u.c);
324         break;
325     default:
326         break;
327     }
328 bail1:
329     FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList));
330     free (new);
331 bail0:
332     return FcFalse;
333 }
334
335 FcBool
336 FcPatternDel (FcPattern *p, const char *object)
337 {
338     FcPatternElt   *e;
339     int             i;
340
341     e = FcPatternFind (p, object, FcFalse);
342     if (!e)
343         return FcFalse;
344
345     i = e - p->elts;
346     
347     /* destroy value */
348     FcValueListDestroy (e->values);
349     
350     /* shuffle existing ones down */
351     memmove (e, e+1, (p->elts + p->num - (e + 1)) * sizeof (FcPatternElt));
352     p->num--;
353     p->elts[p->num].object = 0;
354     p->elts[p->num].values = 0;
355     return FcTrue;
356 }
357
358 FcBool
359 FcPatternAddInteger (FcPattern *p, const char *object, int i)
360 {
361     FcValue     v;
362
363     v.type = FcTypeInteger;
364     v.u.i = i;
365     return FcPatternAdd (p, object, v, FcTrue);
366 }
367
368 FcBool
369 FcPatternAddDouble (FcPattern *p, const char *object, double d)
370 {
371     FcValue     v;
372
373     v.type = FcTypeDouble;
374     v.u.d = d;
375     return FcPatternAdd (p, object, v, FcTrue);
376 }
377
378
379 FcBool
380 FcPatternAddString (FcPattern *p, const char *object, const FcChar8 *s)
381 {
382     FcValue     v;
383
384     v.type = FcTypeString;
385     v.u.s = s;
386     return FcPatternAdd (p, object, v, FcTrue);
387 }
388
389 FcBool
390 FcPatternAddMatrix (FcPattern *p, const char *object, const FcMatrix *s)
391 {
392     FcValue     v;
393
394     v.type = FcTypeMatrix;
395     v.u.m = (FcMatrix *) s;
396     return FcPatternAdd (p, object, v, FcTrue);
397 }
398
399
400 FcBool
401 FcPatternAddBool (FcPattern *p, const char *object, FcBool b)
402 {
403     FcValue     v;
404
405     v.type = FcTypeBool;
406     v.u.b = b;
407     return FcPatternAdd (p, object, v, FcTrue);
408 }
409
410 FcBool
411 FcPatternAddCharSet (FcPattern *p, const char *object, const FcCharSet *c)
412 {
413     FcValue     v;
414
415     v.type = FcTypeCharSet;
416     v.u.c = (FcCharSet *) c;
417     return FcPatternAdd (p, object, v, FcTrue);
418 }
419
420 FcResult
421 FcPatternGet (FcPattern *p, const char *object, int id, FcValue *v)
422 {
423     FcPatternElt   *e;
424     FcValueList    *l;
425
426     e = FcPatternFind (p, object, FcFalse);
427     if (!e)
428         return FcResultNoMatch;
429     for (l = e->values; l; l = l->next)
430     {
431         if (!id)
432         {
433             *v = l->value;
434             return FcResultMatch;
435         }
436         id--;
437     }
438     return FcResultNoId;
439 }
440
441 FcResult
442 FcPatternGetInteger (FcPattern *p, const char *object, int id, int *i)
443 {
444     FcValue     v;
445     FcResult    r;
446
447     r = FcPatternGet (p, object, id, &v);
448     if (r != FcResultMatch)
449         return r;
450     switch (v.type) {
451     case FcTypeDouble:
452         *i = (int) v.u.d;
453         break;
454     case FcTypeInteger:
455         *i = v.u.i;
456         break;
457     default:
458         return FcResultTypeMismatch;
459     }
460     return FcResultMatch;
461 }
462
463 FcResult
464 FcPatternGetDouble (FcPattern *p, const char *object, int id, double *d)
465 {
466     FcValue     v;
467     FcResult    r;
468
469     r = FcPatternGet (p, object, id, &v);
470     if (r != FcResultMatch)
471         return r;
472     switch (v.type) {
473     case FcTypeDouble:
474         *d = v.u.d;
475         break;
476     case FcTypeInteger:
477         *d = (double) v.u.i;
478         break;
479     default:
480         return FcResultTypeMismatch;
481     }
482     return FcResultMatch;
483 }
484
485 FcResult
486 FcPatternGetString (FcPattern *p, const char *object, int id, FcChar8 ** s)
487 {
488     FcValue     v;
489     FcResult    r;
490
491     r = FcPatternGet (p, object, id, &v);
492     if (r != FcResultMatch)
493         return r;
494     if (v.type != FcTypeString)
495         return FcResultTypeMismatch;
496     *s = (FcChar8 *) v.u.s;
497     return FcResultMatch;
498 }
499
500 FcResult
501 FcPatternGetMatrix (FcPattern *p, const char *object, int id, FcMatrix **m)
502 {
503     FcValue     v;
504     FcResult    r;
505
506     r = FcPatternGet (p, object, id, &v);
507     if (r != FcResultMatch)
508         return r;
509     if (v.type != FcTypeMatrix)
510         return FcResultTypeMismatch;
511     *m = (FcMatrix *) v.u.m;
512     return FcResultMatch;
513 }
514
515
516 FcResult
517 FcPatternGetBool (FcPattern *p, const char *object, int id, FcBool *b)
518 {
519     FcValue     v;
520     FcResult    r;
521
522     r = FcPatternGet (p, object, id, &v);
523     if (r != FcResultMatch)
524         return r;
525     if (v.type != FcTypeBool)
526         return FcResultTypeMismatch;
527     *b = v.u.b;
528     return FcResultMatch;
529 }
530
531 FcResult
532 FcPatternGetCharSet (FcPattern *p, const char *object, int id, FcCharSet **c)
533 {
534     FcValue     v;
535     FcResult    r;
536
537     r = FcPatternGet (p, object, id, &v);
538     if (r != FcResultMatch)
539         return r;
540     if (v.type != FcTypeCharSet)
541         return FcResultTypeMismatch;
542     *c = (FcCharSet *) v.u.c;
543     return FcResultMatch;
544 }
545
546 FcPattern *
547 FcPatternDuplicate (FcPattern *orig)
548 {
549     FcPattern       *new;
550     int             i;
551     FcValueList    *l;
552
553     new = FcPatternCreate ();
554     if (!new)
555         goto bail0;
556
557     for (i = 0; i < orig->num; i++)
558     {
559         for (l = orig->elts[i].values; l; l = l->next)
560             if (!FcPatternAdd (new, orig->elts[i].object, l->value, FcTrue))
561                 goto bail1;
562     }
563
564     return new;
565
566 bail1:
567     FcPatternDestroy (new);
568 bail0:
569     return 0;
570 }
571
572 FcPattern *
573 FcPatternVaBuild (FcPattern *orig, va_list va)
574 {
575     FcPattern   *ret;
576     
577     FcPatternVapBuild (ret, orig, va);
578     return ret;
579 }
580
581 FcPattern *
582 FcPatternBuild (FcPattern *orig, ...)
583 {
584     va_list     va;
585     
586     va_start (va, orig);
587     FcPatternVapBuild (orig, orig, va);
588     va_end (va);
589     return orig;
590 }