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