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