]> git.wh0rd.org - fontconfig.git/blob - src/fcxml.c
More complete memory tracking. Install always overwrites header files
[fontconfig.git] / src / fcxml.c
1 /*
2 * $XFree86: xc/lib/fontconfig/src/fcxml.c,v 1.21 2002/08/22 18:53:22 keithp Exp $
3 *
4 * Copyright © 2002 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 <stdarg.h>
26 #include "fcint.h"
27
28 #ifndef HAVE_XMLPARSE_H
29 #define HAVE_XMLPARSE_H 0
30 #endif
31
32 #if HAVE_XMLPARSE_H
33 #include <xmlparse.h>
34 #else
35 #include <expat.h>
36 #endif
37
38 FcTest *
39 FcTestCreate (FcMatchKind kind,
40 FcQual qual,
41 const FcChar8 *field,
42 FcOp compare,
43 FcExpr *expr)
44 {
45 FcTest *test = (FcTest *) malloc (sizeof (FcTest));
46
47 if (test)
48 {
49 FcMemAlloc (FC_MEM_TEST, sizeof (FcTest));
50 test->next = 0;
51 test->kind = kind;
52 test->qual = qual;
53 test->field = (char *) FcStrCopy (field);
54 test->op = compare;
55 test->expr = expr;
56 }
57 return test;
58 }
59
60 void
61 FcTestDestroy (FcTest *test)
62 {
63 if (test->next)
64 FcTestDestroy (test->next);
65 FcExprDestroy (test->expr);
66 FcStrFree ((FcChar8 *) test->field);
67 FcMemFree (FC_MEM_TEST, sizeof (FcTest));
68 free (test);
69 }
70
71 FcExpr *
72 FcExprCreateInteger (int i)
73 {
74 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
75
76 if (e)
77 {
78 FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
79 e->op = FcOpInteger;
80 e->u.ival = i;
81 }
82 return e;
83 }
84
85 FcExpr *
86 FcExprCreateDouble (double d)
87 {
88 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
89
90 if (e)
91 {
92 FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
93 e->op = FcOpDouble;
94 e->u.dval = d;
95 }
96 return e;
97 }
98
99 FcExpr *
100 FcExprCreateString (const FcChar8 *s)
101 {
102 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
103
104 if (e)
105 {
106 FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
107 e->op = FcOpString;
108 e->u.sval = FcStrCopy (s);
109 }
110 return e;
111 }
112
113 FcExpr *
114 FcExprCreateMatrix (const FcMatrix *m)
115 {
116 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
117
118 if (e)
119 {
120 FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
121 e->op = FcOpMatrix;
122 e->u.mval = FcMatrixCopy (m);
123 }
124 return e;
125 }
126
127 FcExpr *
128 FcExprCreateBool (FcBool b)
129 {
130 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
131
132 if (e)
133 {
134 FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
135 e->op = FcOpBool;
136 e->u.bval = b;
137 }
138 return e;
139 }
140
141 FcExpr *
142 FcExprCreateNil (void)
143 {
144 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
145
146 if (e)
147 {
148 FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
149 e->op = FcOpNil;
150 }
151 return e;
152 }
153
154 FcExpr *
155 FcExprCreateField (const char *field)
156 {
157 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
158
159 if (e)
160 {
161 FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
162 e->op = FcOpField;
163 e->u.field = (char *) FcStrCopy ((FcChar8 *) field);
164 }
165 return e;
166 }
167
168 FcExpr *
169 FcExprCreateConst (const FcChar8 *constant)
170 {
171 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
172
173 if (e)
174 {
175 FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
176 e->op = FcOpConst;
177 e->u.constant = FcStrCopy (constant);
178 }
179 return e;
180 }
181
182 FcExpr *
183 FcExprCreateOp (FcExpr *left, FcOp op, FcExpr *right)
184 {
185 FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
186
187 if (e)
188 {
189 FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
190 e->op = op;
191 e->u.tree.left = left;
192 e->u.tree.right = right;
193 }
194 return e;
195 }
196
197 void
198 FcExprDestroy (FcExpr *e)
199 {
200 switch (e->op) {
201 case FcOpInteger:
202 break;
203 case FcOpDouble:
204 break;
205 case FcOpString:
206 FcStrFree (e->u.sval);
207 break;
208 case FcOpMatrix:
209 FcMatrixFree (e->u.mval);
210 break;
211 case FcOpCharSet:
212 FcCharSetDestroy (e->u.cval);
213 break;
214 case FcOpBool:
215 break;
216 case FcOpField:
217 FcStrFree ((FcChar8 *) e->u.field);
218 break;
219 case FcOpConst:
220 FcStrFree (e->u.constant);
221 break;
222 case FcOpAssign:
223 case FcOpAssignReplace:
224 case FcOpPrepend:
225 case FcOpPrependFirst:
226 case FcOpAppend:
227 case FcOpAppendLast:
228 break;
229 case FcOpOr:
230 case FcOpAnd:
231 case FcOpEqual:
232 case FcOpNotEqual:
233 case FcOpLess:
234 case FcOpLessEqual:
235 case FcOpMore:
236 case FcOpMoreEqual:
237 case FcOpContains:
238 case FcOpNotContains:
239 case FcOpPlus:
240 case FcOpMinus:
241 case FcOpTimes:
242 case FcOpDivide:
243 case FcOpQuest:
244 case FcOpComma:
245 FcExprDestroy (e->u.tree.right);
246 /* fall through */
247 case FcOpNot:
248 FcExprDestroy (e->u.tree.left);
249 break;
250 case FcOpNil:
251 case FcOpInvalid:
252 break;
253 }
254 FcMemFree (FC_MEM_EXPR, sizeof (FcExpr));
255 free (e);
256 }
257
258 FcEdit *
259 FcEditCreate (const char *field, FcOp op, FcExpr *expr, FcValueBinding binding)
260 {
261 FcEdit *e = (FcEdit *) malloc (sizeof (FcEdit));
262
263 if (e)
264 {
265 e->next = 0;
266 e->field = field; /* already saved in grammar */
267 e->op = op;
268 e->expr = expr;
269 e->binding = binding;
270 }
271 return e;
272 }
273
274 void
275 FcEditDestroy (FcEdit *e)
276 {
277 if (e->next)
278 FcEditDestroy (e->next);
279 FcStrFree ((FcChar8 *) e->field);
280 if (e->expr)
281 FcExprDestroy (e->expr);
282 }
283
284 char *
285 FcConfigSaveField (const char *field)
286 {
287 return (char *) FcStrCopy ((FcChar8 *) field);
288 }
289
290 typedef enum _FcElement {
291 FcElementNone,
292 FcElementFontconfig,
293 FcElementDir,
294 FcElementCache,
295 FcElementInclude,
296 FcElementConfig,
297 FcElementMatch,
298 FcElementAlias,
299
300 FcElementBlank,
301 FcElementRescan,
302
303 FcElementPrefer,
304 FcElementAccept,
305 FcElementDefault,
306 FcElementFamily,
307
308 FcElementTest,
309 FcElementEdit,
310 FcElementInt,
311 FcElementDouble,
312 FcElementString,
313 FcElementMatrix,
314 FcElementBool,
315 FcElementCharset,
316 FcElementName,
317 FcElementConst,
318 FcElementOr,
319 FcElementAnd,
320 FcElementEq,
321 FcElementNotEq,
322 FcElementLess,
323 FcElementLessEq,
324 FcElementMore,
325 FcElementMoreEq,
326 FcElementContains,
327 FcElementNotContains,
328 FcElementPlus,
329 FcElementMinus,
330 FcElementTimes,
331 FcElementDivide,
332 FcElementNot,
333 FcElementIf,
334 FcElementUnknown
335 } FcElement;
336
337 static FcElement
338 FcElementMap (const XML_Char *name)
339 {
340 static struct {
341 char *name;
342 FcElement element;
343 } fcElementMap[] = {
344 { "fontconfig", FcElementFontconfig },
345 { "dir", FcElementDir },
346 { "cache", FcElementCache },
347 { "include", FcElementInclude },
348 { "config", FcElementConfig },
349 { "match", FcElementMatch },
350 { "alias", FcElementAlias },
351
352 { "blank", FcElementBlank },
353 { "rescan", FcElementRescan },
354
355 { "prefer", FcElementPrefer },
356 { "accept", FcElementAccept },
357 { "default", FcElementDefault },
358 { "family", FcElementFamily },
359
360 { "test", FcElementTest },
361 { "edit", FcElementEdit },
362 { "int", FcElementInt },
363 { "double", FcElementDouble },
364 { "string", FcElementString },
365 { "matrix", FcElementMatrix },
366 { "bool", FcElementBool },
367 { "charset", FcElementCharset },
368 { "name", FcElementName },
369 { "const", FcElementConst },
370 { "or", FcElementOr },
371 { "and", FcElementAnd },
372 { "eq", FcElementEq },
373 { "not_eq", FcElementNotEq },
374 { "less", FcElementLess },
375 { "less_eq", FcElementLessEq },
376 { "more", FcElementMore },
377 { "more_eq", FcElementMoreEq },
378 { "contains", FcElementContains },
379 { "not_contains",FcElementNotContains },
380 { "plus", FcElementPlus },
381 { "minus", FcElementMinus },
382 { "times", FcElementTimes },
383 { "divide", FcElementDivide },
384 { "not", FcElementNot },
385 { "if", FcElementIf },
386
387 { 0, 0 }
388 };
389
390 int i;
391 for (i = 0; fcElementMap[i].name; i++)
392 if (!strcmp ((char *) name, fcElementMap[i].name))
393 return fcElementMap[i].element;
394 return FcElementUnknown;
395 }
396
397 typedef struct _FcPStack {
398 struct _FcPStack *prev;
399 FcElement element;
400 FcChar8 **attr;
401 FcStrBuf str;
402 } FcPStack;
403
404 typedef enum _FcVStackTag {
405 FcVStackNone,
406
407 FcVStackString,
408 FcVStackFamily,
409 FcVStackField,
410 FcVStackConstant,
411
412 FcVStackPrefer,
413 FcVStackAccept,
414 FcVStackDefault,
415
416 FcVStackInteger,
417 FcVStackDouble,
418 FcVStackMatrix,
419 FcVStackBool,
420
421 FcVStackTest,
422 FcVStackExpr,
423 FcVStackEdit
424 } FcVStackTag;
425
426 typedef struct _FcVStack {
427 struct _FcVStack *prev;
428 FcPStack *pstack; /* related parse element */
429 FcVStackTag tag;
430 union {
431 FcChar8 *string;
432
433 int integer;
434 double _double;
435 FcMatrix *matrix;
436 FcBool bool;
437
438 FcTest *test;
439 FcQual qual;
440 FcOp op;
441 FcExpr *expr;
442 FcEdit *edit;
443 } u;
444 } FcVStack;
445
446 typedef struct _FcConfigParse {
447 FcPStack *pstack;
448 FcVStack *vstack;
449 FcBool error;
450 const FcChar8 *name;
451 FcConfig *config;
452 XML_Parser parser;
453 } FcConfigParse;
454
455 typedef enum _FcConfigSeverity {
456 FcSevereInfo, FcSevereWarning, FcSevereError
457 } FcConfigSeverity;
458
459 static void
460 FcConfigMessage (FcConfigParse *parse, FcConfigSeverity severe, char *fmt, ...)
461 {
462 char *s = "unknown";
463 va_list args;
464
465 va_start (args, fmt);
466
467 switch (severe) {
468 case FcSevereInfo: s = "info"; break;
469 case FcSevereWarning: s = "warning"; break;
470 case FcSevereError: s = "error"; break;
471 }
472 if (parse)
473 {
474 if (parse->name)
475 fprintf (stderr, "Fontconfig %s: \"%s\", line %d: ", s,
476 parse->name, XML_GetCurrentLineNumber (parse->parser));
477 else
478 fprintf (stderr, "Fontconfig %s: line %d: ", s,
479 XML_GetCurrentLineNumber (parse->parser));
480 if (severe >= FcSevereError)
481 parse->error = FcTrue;
482 }
483 else
484 fprintf (stderr, "Fontconfig %s: ", s);
485 vfprintf (stderr, fmt, args);
486 fprintf (stderr, "\n");
487 va_end (args);
488 }
489
490 static void
491 FcVStackPush (FcConfigParse *parse, FcVStack *vstack)
492 {
493 vstack->prev = parse->vstack;
494 vstack->pstack = parse->pstack ? parse->pstack->prev : 0;
495 parse->vstack = vstack;
496 }
497
498 static FcVStack *
499 FcVStackCreate (void)
500 {
501 FcVStack *new;
502
503 new = malloc (sizeof (FcVStack));
504 if (!new)
505 return 0;
506 FcMemAlloc (FC_MEM_VSTACK, sizeof (FcVStack));
507 new->tag = FcVStackNone;
508 new->prev = 0;
509 return new;
510 }
511
512 static void
513 FcVStackDestroy (FcVStack *vstack)
514 {
515 FcVStack *prev;
516
517 for (; vstack; vstack = prev)
518 {
519 prev = vstack->prev;
520 switch (vstack->tag) {
521 case FcVStackNone:
522 break;
523 case FcVStackString:
524 case FcVStackFamily:
525 case FcVStackField:
526 case FcVStackConstant:
527 FcStrFree (vstack->u.string);
528 break;
529 case FcVStackInteger:
530 case FcVStackDouble:
531 break;
532 case FcVStackMatrix:
533 FcMatrixFree (vstack->u.matrix);
534 break;
535 case FcVStackBool:
536 break;
537 case FcVStackTest:
538 FcTestDestroy (vstack->u.test);
539 break;
540 case FcVStackExpr:
541 case FcVStackPrefer:
542 case FcVStackAccept:
543 case FcVStackDefault:
544 FcExprDestroy (vstack->u.expr);
545 break;
546 case FcVStackEdit:
547 FcEditDestroy (vstack->u.edit);
548 break;
549 }
550 FcMemFree (FC_MEM_VSTACK, sizeof (FcVStack));
551 free (vstack);
552 }
553 }
554
555 static FcBool
556 FcVStackPushString (FcConfigParse *parse, FcVStackTag tag, FcChar8 *string)
557 {
558 FcVStack *vstack = FcVStackCreate ();
559 if (!vstack)
560 return FcFalse;
561 vstack->u.string = string;
562 vstack->tag = tag;
563 FcVStackPush (parse, vstack);
564 return FcTrue;
565 }
566
567 static FcBool
568 FcVStackPushInteger (FcConfigParse *parse, int integer)
569 {
570 FcVStack *vstack = FcVStackCreate ();
571 if (!vstack)
572 return FcFalse;
573 vstack->u.integer = integer;
574 vstack->tag = FcVStackInteger;
575 FcVStackPush (parse, vstack);
576 return FcTrue;
577 }
578
579 static FcBool
580 FcVStackPushDouble (FcConfigParse *parse, double _double)
581 {
582 FcVStack *vstack = FcVStackCreate ();
583 if (!vstack)
584 return FcFalse;
585 vstack->u._double = _double;
586 vstack->tag = FcVStackDouble;
587 FcVStackPush (parse, vstack);
588 return FcTrue;
589 }
590
591 static FcBool
592 FcVStackPushMatrix (FcConfigParse *parse, FcMatrix *matrix)
593 {
594 FcVStack *vstack = FcVStackCreate ();
595 if (!vstack)
596 return FcFalse;
597 matrix = FcMatrixCopy (matrix);
598 if (!matrix)
599 {
600 FcVStackDestroy (vstack);
601 return FcFalse;
602 }
603 vstack->u.matrix = matrix;
604 vstack->tag = FcVStackMatrix;
605 FcVStackPush (parse, vstack);
606 return FcTrue;
607 }
608
609 static FcBool
610 FcVStackPushBool (FcConfigParse *parse, FcBool bool)
611 {
612 FcVStack *vstack = FcVStackCreate ();
613 if (!vstack)
614 return FcFalse;
615 vstack->u.bool = bool;
616 vstack->tag = FcVStackBool;
617 FcVStackPush (parse, vstack);
618 return FcTrue;
619 }
620
621 static FcBool
622 FcVStackPushTest (FcConfigParse *parse, FcTest *test)
623 {
624 FcVStack *vstack = FcVStackCreate ();
625 if (!vstack)
626 return FcFalse;
627 vstack->u.test = test;
628 vstack->tag = FcVStackTest;
629 FcVStackPush (parse, vstack);
630 return FcTrue;
631 }
632
633 static FcBool
634 FcVStackPushExpr (FcConfigParse *parse, FcVStackTag tag, FcExpr *expr)
635 {
636 FcVStack *vstack = FcVStackCreate ();
637 if (!vstack)
638 return FcFalse;
639 vstack->u.expr = expr;
640 vstack->tag = tag;
641 FcVStackPush (parse, vstack);
642 return FcTrue;
643 }
644
645 static FcBool
646 FcVStackPushEdit (FcConfigParse *parse, FcEdit *edit)
647 {
648 FcVStack *vstack = FcVStackCreate ();
649 if (!vstack)
650 return FcFalse;
651 vstack->u.edit = edit;
652 vstack->tag = FcVStackEdit;
653 FcVStackPush (parse, vstack);
654 return FcTrue;
655 }
656
657 static FcVStack *
658 FcVStackFetch (FcConfigParse *parse, int off)
659 {
660 FcVStack *vstack;
661
662 for (vstack = parse->vstack; vstack && off-- > 0; vstack = vstack->prev);
663 return vstack;
664 }
665
666 static void
667 FcVStackClear (FcConfigParse *parse)
668 {
669 while (parse->vstack && parse->vstack->pstack == parse->pstack)
670 {
671 FcVStack *vstack = parse->vstack;
672 parse->vstack = vstack->prev;
673 vstack->prev = 0;
674 FcVStackDestroy (vstack);
675 }
676 }
677
678 static FcVStack *
679 FcVStackPop (FcConfigParse *parse)
680 {
681 FcVStack *vstack = parse->vstack;
682
683 if (!vstack || vstack->pstack != parse->pstack)
684 return 0;
685 parse->vstack = vstack->prev;
686 vstack->prev = 0;
687 return vstack;
688 }
689
690 static int
691 FcVStackElements (FcConfigParse *parse)
692 {
693 int h = 0;
694 FcVStack *vstack = parse->vstack;
695 while (vstack && vstack->pstack == parse->pstack)
696 {
697 h++;
698 vstack = vstack->prev;
699 }
700 return h;
701 }
702
703 static FcChar8 **
704 FcConfigSaveAttr (const XML_Char **attr)
705 {
706 int n;
707 int slen;
708 int i;
709 FcChar8 **new;
710 FcChar8 *s;
711
712 if (!attr)
713 return 0;
714 slen = 0;
715 for (i = 0; attr[i]; i++)
716 slen += strlen (attr[i]) + 1;
717 n = i;
718 new = malloc ((i + 1) * sizeof (FcChar8 *) + slen);
719 if (!new)
720 return 0;
721 FcMemAlloc (FC_MEM_ATTR, 1); /* size is too expensive */
722 s = (FcChar8 *) (new + (i + 1));
723 for (i = 0; attr[i]; i++)
724 {
725 new[i] = s;
726 strcpy ((char *) s, (char *) attr[i]);
727 s += strlen ((char *) s) + 1;
728 }
729 new[i] = 0;
730 return new;
731 }
732
733 static FcBool
734 FcPStackPush (FcConfigParse *parse, FcElement element, const XML_Char **attr)
735 {
736 FcPStack *new = malloc (sizeof (FcPStack));
737
738 if (!new)
739 return FcFalse;
740 FcMemAlloc (FC_MEM_PSTACK, sizeof (FcPStack));
741 new->prev = parse->pstack;
742 new->element = element;
743 if (attr)
744 {
745 new->attr = FcConfigSaveAttr (attr);
746 if (!new->attr)
747 FcConfigMessage (parse, FcSevereError, "out of memory");
748 }
749 else
750 new->attr = 0;
751 FcStrBufInit (&new->str, 0, 0);
752 parse->pstack = new;
753 return FcTrue;
754 }
755
756 static FcBool
757 FcPStackPop (FcConfigParse *parse)
758 {
759 FcPStack *old;
760
761 if (!parse->pstack)
762 {
763 FcConfigMessage (parse, FcSevereError, "mismatching element");
764 return FcFalse;
765 }
766 FcVStackClear (parse);
767 old = parse->pstack;
768 parse->pstack = old->prev;
769 FcStrBufDestroy (&old->str);
770 if (old->attr)
771 {
772 FcMemFree (FC_MEM_ATTR, 1); /* size is to expensive */
773 free (old->attr);
774 }
775 FcMemFree (FC_MEM_PSTACK, sizeof (FcPStack));
776 free (old);
777 return FcTrue;
778 }
779
780 static FcBool
781 FcConfigInit (FcConfigParse *parse, const FcChar8 *name, FcConfig *config, XML_Parser parser)
782 {
783 parse->pstack = 0;
784 parse->vstack = 0;
785 parse->error = FcFalse;
786 parse->name = name;
787 parse->config = config;
788 parse->parser = parser;
789 return FcTrue;
790 }
791
792 static void
793 FcConfigCleanup (FcConfigParse *parse)
794 {
795 while (parse->pstack)
796 FcPStackPop (parse);
797 }
798
799 static const FcChar8 *
800 FcConfigGetAttribute (FcConfigParse *parse, char *attr)
801 {
802 FcChar8 **attrs;
803 if (!parse->pstack)
804 return 0;
805
806 attrs = parse->pstack->attr;
807 while (*attrs)
808 {
809 if (!strcmp ((char *) *attrs, attr))
810 return attrs[1];
811 attrs += 2;
812 }
813 return 0;
814 }
815
816 static void
817 FcStartElement(void *userData, const XML_Char *name, const XML_Char **attr)
818 {
819 FcConfigParse *parse = userData;
820 FcElement element;
821
822 element = FcElementMap (name);
823 if (element == FcElementUnknown)
824 FcConfigMessage (parse, FcSevereWarning, "unknown element \"%s\"", name);
825
826 if (!FcPStackPush (parse, element, attr))
827 {
828 FcConfigMessage (parse, FcSevereError, "out of memory");
829 return;
830 }
831 return;
832 }
833
834 static void
835 FcParseBlank (FcConfigParse *parse)
836 {
837 int n = FcVStackElements (parse);
838 while (n-- > 0)
839 {
840 FcVStack *v = FcVStackFetch (parse, n);
841 if (v->tag != FcVStackInteger)
842 FcConfigMessage (parse, FcSevereError, "non-integer blank");
843 else
844 {
845 if (!parse->config->blanks)
846 {
847 parse->config->blanks = FcBlanksCreate ();
848 if (!parse->config->blanks)
849 {
850 FcConfigMessage (parse, FcSevereError, "out of memory");
851 break;
852 }
853 }
854 if (!FcBlanksAdd (parse->config->blanks, v->u.integer))
855 {
856 FcConfigMessage (parse, FcSevereError, "out of memory");
857 break;
858 }
859 }
860 }
861 }
862
863 static void
864 FcParseRescan (FcConfigParse *parse)
865 {
866 int n = FcVStackElements (parse);
867 while (n-- > 0)
868 {
869 FcVStack *v = FcVStackFetch (parse, n);
870 if (v->tag != FcVStackInteger)
871 FcConfigMessage (parse, FcSevereWarning, "non-integer rescan");
872 else
873 parse->config->rescanInterval = v->u.integer;
874 }
875 }
876
877 static void
878 FcParseInt (FcConfigParse *parse)
879 {
880 FcChar8 *s, *end;
881 int l;
882
883 if (!parse->pstack)
884 return;
885 s = FcStrBufDone (&parse->pstack->str);
886 if (!s)
887 {
888 FcConfigMessage (parse, FcSevereError, "out of memory");
889 return;
890 }
891 end = 0;
892 l = (int) strtol ((char *) s, (char **)&end, 0);
893 if (end != s + strlen ((char *) s))
894 FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid integer", s);
895 else
896 FcVStackPushInteger (parse, l);
897 FcStrFree (s);
898 }
899
900 /*
901 * idea copied from glib g_ascii_strtod with
902 * permission of the author (Alexander Larsson)
903 */
904
905 #include <locale.h>
906
907 static double
908 FcStrtod (char *s, char **end)
909 {
910 struct lconv *locale_data;
911 char *dot;
912 double v;
913
914 /*
915 * Have to swap the decimal point to match the current locale
916 * if that locale doesn't use 0x2e
917 */
918 if ((dot = strchr (s, 0x2e)) &&
919 (locale_data = localeconv ()) &&
920 (locale_data->decimal_point[0] != 0x2e ||
921 locale_data->decimal_point[1] != 0))
922 {
923 char buf[128];
924 int slen = strlen (s);
925 int dlen = strlen (locale_data->decimal_point);
926
927 if (slen + dlen > sizeof (buf))
928 {
929 if (end)
930 *end = s;
931 v = 0;
932 }
933 else
934 {
935 char *buf_end;
936 /* mantissa */
937 strncpy (buf, s, dot - s);
938 /* decimal point */
939 strcpy (buf + (dot - s), locale_data->decimal_point);
940 /* rest of number */
941 strcpy (buf + (dot - s) + dlen, dot + 1);
942 buf_end = 0;
943 v = strtod (buf, &buf_end);
944 if (buf_end)
945 buf_end = s + (buf_end - buf);
946 if (end)
947 *end = buf_end;
948 }
949 }
950 else
951 v = strtod (s, end);
952 return v;
953 }
954
955 static void
956 FcParseDouble (FcConfigParse *parse)
957 {
958 FcChar8 *s, *end;
959 double d;
960
961 if (!parse->pstack)
962 return;
963 s = FcStrBufDone (&parse->pstack->str);
964 if (!s)
965 {
966 FcConfigMessage (parse, FcSevereError, "out of memory");
967 return;
968 }
969 end = 0;
970 d = FcStrtod ((char *) s, (char **)&end);
971 if (end != s + strlen ((char *) s))
972 FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid double", s);
973 else
974 FcVStackPushDouble (parse, d);
975 FcStrFree (s);
976 }
977
978 static void
979 FcParseString (FcConfigParse *parse, FcVStackTag tag)
980 {
981 FcChar8 *s;
982
983 if (!parse->pstack)
984 return;
985 s = FcStrBufDone (&parse->pstack->str);
986 if (!s)
987 {
988 FcConfigMessage (parse, FcSevereError, "out of memory");
989 return;
990 }
991 if (!FcVStackPushString (parse, tag, s))
992 FcStrFree (s);
993 }
994
995 static void
996 FcParseMatrix (FcConfigParse *parse)
997 {
998 FcVStack *vstack;
999 enum { m_done, m_xx, m_xy, m_yx, m_yy } matrix_state = m_yy;
1000 FcMatrix m;
1001
1002 while ((vstack = FcVStackPop (parse)))
1003 {
1004 double v;
1005 switch (vstack->tag) {
1006 case FcVStackInteger:
1007 v = vstack->u.integer;
1008 break;
1009 case FcVStackDouble:
1010 v = vstack->u._double;
1011 break;
1012 default:
1013 FcConfigMessage (parse, FcSevereError, "non-double matrix element");
1014 v = 1.0;
1015 break;
1016 }
1017 switch (matrix_state) {
1018 case m_xx: m.xx = v; break;
1019 case m_xy: m.xy = v; break;
1020 case m_yx: m.yx = v; break;
1021 case m_yy: m.yy = v; break;
1022 default: break;
1023 }
1024 FcVStackDestroy (vstack);
1025 matrix_state--;
1026 }
1027 if (matrix_state != m_done)
1028 FcConfigMessage (parse, FcSevereError, "wrong number of matrix elements");
1029 else
1030 FcVStackPushMatrix (parse, &m);
1031 }
1032
1033 static FcBool
1034 FcConfigLexBool (const FcChar8 *bool)
1035 {
1036 if (*bool == 't' || *bool == 'T')
1037 return FcTrue;
1038 if (*bool == 'y' || *bool == 'Y')
1039 return FcTrue;
1040 if (*bool == '1')
1041 return FcTrue;
1042 return FcFalse;
1043 }
1044
1045 static void
1046 FcParseBool (FcConfigParse *parse)
1047 {
1048 FcChar8 *s;
1049
1050 if (!parse->pstack)
1051 return;
1052 s = FcStrBufDone (&parse->pstack->str);
1053 if (!s)
1054 {
1055 FcConfigMessage (parse, FcSevereError, "out of memory");
1056 return;
1057 }
1058 FcVStackPushBool (parse, FcConfigLexBool (s));
1059 FcStrFree (s);
1060 }
1061
1062 static void
1063 FcParseFamilies (FcConfigParse *parse, FcVStackTag tag)
1064 {
1065 FcVStack *vstack;
1066 FcExpr *left, *expr = 0, *new;
1067
1068 while ((vstack = FcVStackPop (parse)))
1069 {
1070 if (vstack->tag != FcVStackFamily)
1071 {
1072 FcConfigMessage (parse, FcSevereWarning, "non-family");
1073 FcVStackDestroy (vstack);
1074 continue;
1075 }
1076 left = vstack->u.expr;
1077 vstack->tag = FcVStackNone;
1078 FcVStackDestroy (vstack);
1079 if (expr)
1080 {
1081 new = FcExprCreateOp (left, FcOpComma, expr);
1082 if (!new)
1083 {
1084 FcConfigMessage (parse, FcSevereError, "out of memory");
1085 FcExprDestroy (left);
1086 FcExprDestroy (expr);
1087 break;
1088 }
1089 expr = new;
1090 }
1091 else
1092 expr = left;
1093 }
1094 if (expr)
1095 {
1096 if (!FcVStackPushExpr (parse, tag, expr))
1097 {
1098 FcConfigMessage (parse, FcSevereError, "out of memory");
1099 if (expr)
1100 FcExprDestroy (expr);
1101 }
1102 }
1103 }
1104
1105 static void
1106 FcParseFamily (FcConfigParse *parse)
1107 {
1108 FcChar8 *s;
1109 FcExpr *expr;
1110
1111 if (!parse->pstack)
1112 return;
1113 s = FcStrBufDone (&parse->pstack->str);
1114 if (!s)
1115 {
1116 FcConfigMessage (parse, FcSevereError, "out of memory");
1117 return;
1118 }
1119 expr = FcExprCreateString (s);
1120 FcStrFree (s);
1121 if (expr)
1122 FcVStackPushExpr (parse, FcVStackFamily, expr);
1123 }
1124
1125 static void
1126 FcParseAlias (FcConfigParse *parse)
1127 {
1128 FcExpr *family = 0, *accept = 0, *prefer = 0, *def = 0, *new = 0;
1129 FcEdit *edit = 0, *next;
1130 FcVStack *vstack;
1131 FcTest *test;
1132
1133 while ((vstack = FcVStackPop (parse)))
1134 {
1135 switch (vstack->tag) {
1136 case FcVStackFamily:
1137 if (family)
1138 {
1139 new = FcExprCreateOp (vstack->u.expr, FcOpComma, family);
1140 if (!new)
1141 FcConfigMessage (parse, FcSevereError, "out of memory");
1142 else
1143 family = new;
1144 }
1145 else
1146 new = vstack->u.expr;
1147 if (new)
1148 {
1149 family = new;
1150 vstack->tag = FcVStackNone;
1151 }
1152 break;
1153 case FcVStackPrefer:
1154 if (prefer)
1155 FcExprDestroy (prefer);
1156 prefer = vstack->u.expr;
1157 vstack->tag = FcVStackNone;
1158 break;
1159 case FcVStackAccept:
1160 if (accept)
1161 FcExprDestroy (accept);
1162 accept = vstack->u.expr;
1163 vstack->tag = FcVStackNone;
1164 break;
1165 case FcVStackDefault:
1166 if (def)
1167 FcExprDestroy (def);
1168 def = vstack->u.expr;
1169 vstack->tag = FcVStackNone;
1170 break;
1171 default:
1172 FcConfigMessage (parse, FcSevereWarning, "bad alias");
1173 break;
1174 }
1175 FcVStackDestroy (vstack);
1176 }
1177 if (!family)
1178 {
1179 FcConfigMessage (parse, FcSevereError, "missing family in alias");
1180 if (prefer)
1181 FcExprDestroy (prefer);
1182 if (accept)
1183 FcExprDestroy (accept);
1184 if (def)
1185 FcExprDestroy (def);
1186 return;
1187 }
1188 if (prefer)
1189 {
1190 edit = FcEditCreate (FcConfigSaveField ("family"),
1191 FcOpPrepend,
1192 prefer,
1193 FcValueBindingWeak);
1194 if (edit)
1195 edit->next = 0;
1196 else
1197 FcExprDestroy (prefer);
1198 }
1199 if (accept)
1200 {
1201 next = edit;
1202 edit = FcEditCreate (FcConfigSaveField ("family"),
1203 FcOpAppend,
1204 accept,
1205 FcValueBindingWeak);
1206 if (edit)
1207 edit->next = next;
1208 else
1209 FcExprDestroy (accept);
1210 }
1211 if (def)
1212 {
1213 next = edit;
1214 edit = FcEditCreate (FcConfigSaveField ("family"),
1215 FcOpAppendLast,
1216 def,
1217 FcValueBindingWeak);
1218 if (edit)
1219 edit->next = next;
1220 else
1221 FcExprDestroy (def);
1222 }
1223 if (edit)
1224 {
1225 test = FcTestCreate (FcMatchPattern,
1226 FcQualAny,
1227 (FcChar8 *) FC_FAMILY,
1228 FcOpEqual,
1229 family);
1230 if (test)
1231 if (!FcConfigAddEdit (parse->config, test, edit, FcMatchPattern))
1232 FcTestDestroy (test);
1233 }
1234 else
1235 FcExprDestroy (family);
1236 }
1237
1238 static FcExpr *
1239 FcPopExpr (FcConfigParse *parse)
1240 {
1241 FcVStack *vstack = FcVStackPop (parse);
1242 FcExpr *expr = 0;
1243 if (!vstack)
1244 return 0;
1245 switch (vstack->tag) {
1246 case FcVStackNone:
1247 break;
1248 case FcVStackString:
1249 case FcVStackFamily:
1250 expr = FcExprCreateString (vstack->u.string);
1251 break;
1252 case FcVStackField:
1253 expr = FcExprCreateField ((char *) vstack->u.string);
1254 break;
1255 case FcVStackConstant:
1256 expr = FcExprCreateConst (vstack->u.string);
1257 break;
1258 case FcVStackPrefer:
1259 case FcVStackAccept:
1260 case FcVStackDefault:
1261 expr = vstack->u.expr;
1262 vstack->tag = FcVStackNone;
1263 break;
1264 case FcVStackInteger:
1265 expr = FcExprCreateInteger (vstack->u.integer);
1266 break;
1267 case FcVStackDouble:
1268 expr = FcExprCreateDouble (vstack->u._double);
1269 break;
1270 case FcVStackMatrix:
1271 expr = FcExprCreateMatrix (vstack->u.matrix);
1272 break;
1273 case FcVStackBool:
1274 expr = FcExprCreateBool (vstack->u.bool);
1275 break;
1276 case FcVStackTest:
1277 break;
1278 case FcVStackExpr:
1279 expr = vstack->u.expr;
1280 vstack->tag = FcVStackNone;
1281 break;
1282 case FcVStackEdit:
1283 break;
1284 }
1285 FcVStackDestroy (vstack);
1286 return expr;
1287 }
1288
1289 static FcExpr *
1290 FcPopExprs (FcConfigParse *parse, FcOp op)
1291 {
1292 FcExpr *left, *expr = 0, *new;
1293
1294 while ((left = FcPopExpr (parse)))
1295 {
1296 if (expr)
1297 {
1298 new = FcExprCreateOp (left, op, expr);
1299 if (!new)
1300 {
1301 FcConfigMessage (parse, FcSevereError, "out of memory");
1302 FcExprDestroy (left);
1303 FcExprDestroy (expr);
1304 break;
1305 }
1306 expr = new;
1307 }
1308 else
1309 expr = left;
1310 }
1311 return expr;
1312 }
1313
1314 static void
1315 FcParseExpr (FcConfigParse *parse, FcOp op)
1316 {
1317 FcExpr *expr = FcPopExprs (parse, op);
1318 if (expr)
1319 FcVStackPushExpr (parse, FcVStackExpr, expr);
1320 }
1321
1322 static void
1323 FcParseInclude (FcConfigParse *parse)
1324 {
1325 FcChar8 *s;
1326 const FcChar8 *i;
1327 FcBool ignore_missing = FcFalse;
1328
1329 s = FcStrBufDone (&parse->pstack->str);
1330 if (!s)
1331 {
1332 FcConfigMessage (parse, FcSevereError, "out of memory");
1333 return;
1334 }
1335 i = FcConfigGetAttribute (parse, "ignore_missing");
1336 if (i && FcConfigLexBool ((FcChar8 *) i) == FcTrue)
1337 ignore_missing = FcTrue;
1338 if (!FcConfigParseAndLoad (parse->config, s, !ignore_missing))
1339 parse->error = FcTrue;
1340 FcStrFree (s);
1341 }
1342
1343 typedef struct _FcOpMap {
1344 char *name;
1345 FcOp op;
1346 } FcOpMap;
1347
1348 static FcOp
1349 FcConfigLexOp (const FcChar8 *op, const FcOpMap *map, int nmap)
1350 {
1351 int i;
1352
1353 for (i = 0; i < nmap; i++)
1354 if (!strcmp ((char *) op, map[i].name))
1355 return map[i].op;
1356 return FcOpInvalid;
1357 }
1358
1359 static const FcOpMap fcCompareOps[] = {
1360 { "eq", FcOpEqual },
1361 { "not_eq", FcOpNotEqual },
1362 { "less", FcOpLess },
1363 { "less_eq", FcOpLessEqual },
1364 { "more", FcOpMore },
1365 { "more_eq", FcOpMoreEqual },
1366 { "contains", FcOpContains },
1367 { "not_contains", FcOpNotContains }
1368 };
1369
1370 #define NUM_COMPARE_OPS (sizeof fcCompareOps / sizeof fcCompareOps[0])
1371
1372 static FcOp
1373 FcConfigLexCompare (const FcChar8 *compare)
1374 {
1375 return FcConfigLexOp (compare, fcCompareOps, NUM_COMPARE_OPS);
1376 }
1377
1378
1379 static void
1380 FcParseTest (FcConfigParse *parse)
1381 {
1382 const FcChar8 *kind_string;
1383 FcMatchKind kind;
1384 const FcChar8 *qual_string;
1385 FcQual qual;
1386 const FcChar8 *name;
1387 const FcChar8 *compare_string;
1388 FcOp compare;
1389 FcExpr *expr;
1390 FcTest *test;
1391
1392 kind_string = FcConfigGetAttribute (parse, "target");
1393 if (!kind_string)
1394 kind = FcMatchDefault;
1395 else
1396 {
1397 if (!strcmp ((char *) kind_string, "pattern"))
1398 kind = FcMatchPattern;
1399 else if (!strcmp ((char *) kind_string, "font"))
1400 kind = FcMatchFont;
1401 else if (!strcmp ((char *) kind_string, "default"))
1402 kind = FcMatchDefault;
1403 else
1404 {
1405 FcConfigMessage (parse, FcSevereWarning, "invalid test target \"%s\"", kind_string);
1406 return;
1407 }
1408 }
1409 qual_string = FcConfigGetAttribute (parse, "qual");
1410 if (!qual_string)
1411 qual = FcQualAny;
1412 else
1413 {
1414 if (!strcmp ((char *) qual_string, "any"))
1415 qual = FcQualAny;
1416 else if (!strcmp ((char *) qual_string, "all"))
1417 qual = FcQualAll;
1418 else if (!strcmp ((char *) qual_string, "first"))
1419 qual = FcQualFirst;
1420 else if (!strcmp ((char *) qual_string, "not_first"))
1421 qual = FcQualNotFirst;
1422 else
1423 {
1424 FcConfigMessage (parse, FcSevereWarning, "invalid test qual \"%s\"", qual_string);
1425 return;
1426 }
1427 }
1428 name = FcConfigGetAttribute (parse, "name");
1429 if (!name)
1430 {
1431 FcConfigMessage (parse, FcSevereWarning, "missing test name");
1432 return;
1433 }
1434 compare_string = FcConfigGetAttribute (parse, "compare");
1435 if (!compare_string)
1436 compare = FcOpEqual;
1437 else
1438 {
1439 compare = FcConfigLexCompare (compare_string);
1440 if (compare == FcOpInvalid)
1441 {
1442 FcConfigMessage (parse, FcSevereWarning, "invalid test compare \"%s\"", compare_string);
1443 return;
1444 }
1445 }
1446 expr = FcPopExprs (parse, FcOpComma);
1447 if (!expr)
1448 {
1449 FcConfigMessage (parse, FcSevereWarning, "missing test expression");
1450 return;
1451 }
1452 test = FcTestCreate (kind, qual, name, compare, expr);
1453 if (!test)
1454 {
1455 FcConfigMessage (parse, FcSevereError, "out of memory");
1456 return;
1457 }
1458 FcVStackPushTest (parse, test);
1459 }
1460
1461 static const FcOpMap fcModeOps[] = {
1462 { "assign", FcOpAssign },
1463 { "assign_replace", FcOpAssignReplace },
1464 { "prepend", FcOpPrepend },
1465 { "prepend_first", FcOpPrependFirst },
1466 { "append", FcOpAppend },
1467 { "append_last", FcOpAppendLast },
1468 };
1469
1470 #define NUM_MODE_OPS (sizeof fcModeOps / sizeof fcModeOps[0])
1471
1472 static FcOp
1473 FcConfigLexMode (const FcChar8 *mode)
1474 {
1475 return FcConfigLexOp (mode, fcModeOps, NUM_MODE_OPS);
1476 }
1477
1478 static void
1479 FcParseEdit (FcConfigParse *parse)
1480 {
1481 const FcChar8 *name;
1482 const FcChar8 *mode_string;
1483 const FcChar8 *binding_string;
1484 FcOp mode;
1485 FcValueBinding binding;
1486 FcExpr *expr;
1487 FcEdit *edit;
1488
1489 name = FcConfigGetAttribute (parse, "name");
1490 if (!name)
1491 {
1492 FcConfigMessage (parse, FcSevereWarning, "missing edit name");
1493 return;
1494 }
1495 mode_string = FcConfigGetAttribute (parse, "mode");
1496 if (!mode_string)
1497 mode = FcOpAssign;
1498 else
1499 {
1500 mode = FcConfigLexMode (mode_string);
1501 if (mode == FcOpInvalid)
1502 {
1503 FcConfigMessage (parse, FcSevereWarning, "invalid edit mode \"%s\"", mode_string);
1504 return;
1505 }
1506 }
1507 binding_string = FcConfigGetAttribute (parse, "binding");
1508 if (!binding_string)
1509 binding = FcValueBindingWeak;
1510 else
1511 {
1512 if (!strcmp ((char *) binding_string, "weak"))
1513 binding = FcValueBindingWeak;
1514 else if (!strcmp ((char *) binding_string, "strong"))
1515 binding = FcValueBindingStrong;
1516 else
1517 {
1518 FcConfigMessage (parse, FcSevereWarning, "invalid edit binding \"%s\"", binding_string);
1519 return;
1520 }
1521 }
1522 expr = FcPopExprs (parse, FcOpComma);
1523 edit = FcEditCreate ((char *) FcStrCopy (name), mode, expr, binding);
1524 if (!edit)
1525 {
1526 FcConfigMessage (parse, FcSevereError, "out of memory");
1527 FcExprDestroy (expr);
1528 return;
1529 }
1530 if (!FcVStackPushEdit (parse, edit))
1531 FcEditDestroy (edit);
1532 }
1533
1534 static void
1535 FcParseMatch (FcConfigParse *parse)
1536 {
1537 const FcChar8 *kind_name;
1538 FcMatchKind kind;
1539 FcTest *test = 0;
1540 FcEdit *edit = 0;
1541 FcVStack *vstack;
1542
1543 kind_name = FcConfigGetAttribute (parse, "target");
1544 if (!kind_name)
1545 kind = FcMatchPattern;
1546 else
1547 {
1548 if (!strcmp ((char *) kind_name, "pattern"))
1549 kind = FcMatchPattern;
1550 else if (!strcmp ((char *) kind_name, "font"))
1551 kind = FcMatchFont;
1552 else
1553 {
1554 FcConfigMessage (parse, FcSevereWarning, "invalid match target \"%s\"", kind_name);
1555 return;
1556 }
1557 }
1558 while ((vstack = FcVStackPop (parse)))
1559 {
1560 switch (vstack->tag) {
1561 case FcVStackTest:
1562 vstack->u.test->next = test;
1563 test = vstack->u.test;
1564 vstack->tag = FcVStackNone;
1565 break;
1566 case FcVStackEdit:
1567 vstack->u.edit->next = edit;
1568 edit = vstack->u.edit;
1569 vstack->tag = FcVStackNone;
1570 break;
1571 default:
1572 FcConfigMessage (parse, FcSevereWarning, "invalid match element");
1573 break;
1574 }
1575 FcVStackDestroy (vstack);
1576 }
1577 if (!FcConfigAddEdit (parse->config, test, edit, kind))
1578 FcConfigMessage (parse, FcSevereError, "out of memory");
1579 }
1580
1581 static void
1582 FcEndElement(void *userData, const XML_Char *name)
1583 {
1584 FcConfigParse *parse = userData;
1585 FcChar8 *data;
1586
1587 if (!parse->pstack)
1588 return;
1589 switch (parse->pstack->element) {
1590 case FcElementNone:
1591 break;
1592 case FcElementFontconfig:
1593 break;
1594 case FcElementDir:
1595 data = FcStrBufDone (&parse->pstack->str);
1596 if (!data)
1597 {
1598 FcConfigMessage (parse, FcSevereError, "out of memory");
1599 break;
1600 }
1601 if (!FcConfigAddDir (parse->config, data))
1602 FcConfigMessage (parse, FcSevereError, "out of memory");
1603 FcStrFree (data);
1604 break;
1605 case FcElementCache:
1606 data = FcStrBufDone (&parse->pstack->str);
1607 if (!data)
1608 {
1609 FcConfigMessage (parse, FcSevereError, "out of memory");
1610 break;
1611 }
1612 if (!FcConfigSetCache (parse->config, data))
1613 FcConfigMessage (parse, FcSevereError, "out of memory");
1614 FcStrFree (data);
1615 break;
1616 case FcElementInclude:
1617 FcParseInclude (parse);
1618 break;
1619 case FcElementConfig:
1620 break;
1621 case FcElementMatch:
1622 FcParseMatch (parse);
1623 break;
1624 case FcElementAlias:
1625 FcParseAlias (parse);
1626 break;
1627
1628 case FcElementBlank:
1629 FcParseBlank (parse);
1630 break;
1631 case FcElementRescan:
1632 FcParseRescan (parse);
1633 break;
1634
1635 case FcElementPrefer:
1636 FcParseFamilies (parse, FcVStackPrefer);
1637 break;
1638 case FcElementAccept:
1639 FcParseFamilies (parse, FcVStackAccept);
1640 break;
1641 case FcElementDefault:
1642 FcParseFamilies (parse, FcVStackDefault);
1643 break;
1644 case FcElementFamily:
1645 FcParseFamily (parse);
1646 break;
1647
1648 case FcElementTest:
1649 FcParseTest (parse);
1650 break;
1651 case FcElementEdit:
1652 FcParseEdit (parse);
1653 break;
1654
1655 case FcElementInt:
1656 FcParseInt (parse);
1657 break;
1658 case FcElementDouble:
1659 FcParseDouble (parse);
1660 break;
1661 case FcElementString:
1662 FcParseString (parse, FcVStackString);
1663 break;
1664 case FcElementMatrix:
1665 FcParseMatrix (parse);
1666 break;
1667 case FcElementBool:
1668 FcParseBool (parse);
1669 break;
1670 case FcElementCharset:
1671 /* FcParseCharset (parse); */
1672 break;
1673
1674 case FcElementName:
1675 FcParseString (parse, FcVStackField);
1676 break;
1677 case FcElementConst:
1678 FcParseString (parse, FcVStackConstant);
1679 break;
1680 case FcElementOr:
1681 FcParseExpr (parse, FcOpOr);
1682 break;
1683 case FcElementAnd:
1684 FcParseExpr (parse, FcOpAnd);
1685 break;
1686 case FcElementEq:
1687 FcParseExpr (parse, FcOpEqual);
1688 break;
1689 case FcElementNotEq:
1690 FcParseExpr (parse, FcOpNotEqual);
1691 break;
1692 case FcElementLess:
1693 FcParseExpr (parse, FcOpLess);
1694 break;
1695 case FcElementLessEq:
1696 FcParseExpr (parse, FcOpLessEqual);
1697 break;
1698 case FcElementMore:
1699 FcParseExpr (parse, FcOpMore);
1700 break;
1701 case FcElementMoreEq:
1702 FcParseExpr (parse, FcOpMoreEqual);
1703 break;
1704 case FcElementContains:
1705 FcParseExpr (parse, FcOpContains);
1706 break;
1707 case FcElementNotContains:
1708 FcParseExpr (parse, FcOpNotContains);
1709 break;
1710 case FcElementPlus:
1711 FcParseExpr (parse, FcOpPlus);
1712 break;
1713 case FcElementMinus:
1714 FcParseExpr (parse, FcOpMinus);
1715 break;
1716 case FcElementTimes:
1717 FcParseExpr (parse, FcOpTimes);
1718 break;
1719 case FcElementDivide:
1720 FcParseExpr (parse, FcOpDivide);
1721 break;
1722 case FcElementNot:
1723 FcParseExpr (parse, FcOpNot);
1724 break;
1725 case FcElementIf:
1726 FcParseExpr (parse, FcOpQuest);
1727 break;
1728 case FcElementUnknown:
1729 break;
1730 }
1731 (void) FcPStackPop (parse);
1732 }
1733
1734 static void
1735 FcCharacterData (void *userData, const XML_Char *s, int len)
1736 {
1737 FcConfigParse *parse = userData;
1738
1739 if (!parse->pstack)
1740 return;
1741 if (!FcStrBufData (&parse->pstack->str, (FcChar8 *) s, len))
1742 FcConfigMessage (parse, FcSevereError, "out of memory");
1743 }
1744
1745 static void
1746 FcStartDoctypeDecl (void *userData,
1747 const XML_Char *doctypeName,
1748 const XML_Char *sysid,
1749 const XML_Char *pubid,
1750 int has_internal_subset)
1751 {
1752 FcConfigParse *parse = userData;
1753
1754 if (strcmp ((char *) doctypeName, "fontconfig") != 0)
1755 FcConfigMessage (parse, FcSevereError, "invalid doctype \"%s\"", doctypeName);
1756 }
1757
1758 static void
1759 FcEndDoctypeDecl (void *userData)
1760 {
1761 }
1762
1763 FcBool
1764 FcConfigParseAndLoad (FcConfig *config,
1765 const FcChar8 *name,
1766 FcBool complain)
1767 {
1768
1769 XML_Parser p;
1770 FcChar8 *filename;
1771 FILE *f;
1772 int len;
1773 void *buf;
1774 FcConfigParse parse;
1775 FcBool error = FcTrue;
1776
1777 filename = FcConfigFilename (name);
1778 if (!filename)
1779 goto bail0;
1780
1781 if (!FcStrSetAdd (config->configFiles, filename))
1782 {
1783 FcStrFree (filename);
1784 goto bail0;
1785 }
1786
1787 f = fopen ((char *) filename, "r");
1788 FcStrFree (filename);
1789 if (!f)
1790 goto bail0;
1791
1792 p = XML_ParserCreate ("UTF-8");
1793 if (!p)
1794 goto bail1;
1795
1796 if (!FcConfigInit (&parse, name, config, p))
1797 goto bail2;
1798
1799 XML_SetUserData (p, &parse);
1800
1801 XML_SetDoctypeDeclHandler (p, FcStartDoctypeDecl, FcEndDoctypeDecl);
1802 XML_SetElementHandler (p, FcStartElement, FcEndElement);
1803 XML_SetCharacterDataHandler (p, FcCharacterData);
1804
1805 do {
1806 buf = XML_GetBuffer (p, BUFSIZ);
1807 if (!buf)
1808 {
1809 FcConfigMessage (&parse, FcSevereError, "cannot get parse buffer");
1810 goto bail3;
1811 }
1812 len = fread (buf, 1, BUFSIZ, f);
1813 if (len < 0)
1814 {
1815 FcConfigMessage (&parse, FcSevereError, "failed reading config file");
1816 goto bail3;
1817 }
1818 if (!XML_ParseBuffer (p, len, len == 0))
1819 {
1820 FcConfigMessage (&parse, FcSevereError, "%s",
1821 XML_ErrorString (XML_GetErrorCode (p)));
1822 goto bail3;
1823 }
1824 } while (len != 0);
1825 error = parse.error;
1826 bail3:
1827 FcConfigCleanup (&parse);
1828 bail2:
1829 XML_ParserFree (p);
1830 bail1:
1831 fclose (f);
1832 bail0:
1833 if (error && complain)
1834 {
1835 if (name)
1836 FcConfigMessage (0, FcSevereError, "Cannot load config file \"%s\"", name);
1837 else
1838 FcConfigMessage (0, FcSevereError, "Cannot load default config file");
1839 return FcFalse;
1840 }
1841 return FcTrue;
1842 }