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