]> git.wh0rd.org - fontconfig.git/blob - src/fcxml.c
Various config changes plus a couple of optimizations from Owen
[fontconfig.git] / src / fcxml.c
1 /*
2 * $XFree86: xc/lib/fontconfig/src/fcxml.c,v 1.18 2002/08/11 18:10:42 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 matrix_state--;
1000 }
1001 if (matrix_state != m_done)
1002 FcConfigMessage (parse, FcSevereError, "wrong number of matrix elements");
1003 else
1004 FcVStackPushMatrix (parse, &m);
1005 }
1006
1007 static FcBool
1008 FcConfigLexBool (const FcChar8 *bool)
1009 {
1010 if (*bool == 't' || *bool == 'T')
1011 return FcTrue;
1012 if (*bool == 'y' || *bool == 'Y')
1013 return FcTrue;
1014 if (*bool == '1')
1015 return FcTrue;
1016 return FcFalse;
1017 }
1018
1019 static void
1020 FcParseBool (FcConfigParse *parse)
1021 {
1022 FcChar8 *s;
1023
1024 if (!parse->pstack)
1025 return;
1026 s = FcStrBufDone (&parse->pstack->str);
1027 if (!s)
1028 {
1029 FcConfigMessage (parse, FcSevereError, "out of memory");
1030 return;
1031 }
1032 FcVStackPushBool (parse, FcConfigLexBool (s));
1033 FcStrFree (s);
1034 }
1035
1036 static void
1037 FcParseFamilies (FcConfigParse *parse, FcVStackTag tag)
1038 {
1039 FcVStack *vstack;
1040 FcExpr *left, *expr = 0, *new;
1041
1042 while ((vstack = FcVStackPop (parse)))
1043 {
1044 if (vstack->tag != FcVStackFamily)
1045 {
1046 FcConfigMessage (parse, FcSevereWarning, "non-family");
1047 FcVStackDestroy (vstack);
1048 continue;
1049 }
1050 left = vstack->u.expr;
1051 vstack->tag = FcVStackNone;
1052 FcVStackDestroy (vstack);
1053 if (expr)
1054 {
1055 new = FcExprCreateOp (left, FcOpComma, expr);
1056 if (!new)
1057 {
1058 FcConfigMessage (parse, FcSevereError, "out of memory");
1059 FcExprDestroy (left);
1060 FcExprDestroy (expr);
1061 break;
1062 }
1063 expr = new;
1064 }
1065 else
1066 expr = left;
1067 }
1068 if (expr)
1069 {
1070 if (!FcVStackPushExpr (parse, tag, expr))
1071 {
1072 FcConfigMessage (parse, FcSevereError, "out of memory");
1073 if (expr)
1074 FcExprDestroy (expr);
1075 }
1076 }
1077 }
1078
1079 static void
1080 FcParseFamily (FcConfigParse *parse)
1081 {
1082 FcChar8 *s;
1083 FcExpr *expr;
1084
1085 if (!parse->pstack)
1086 return;
1087 s = FcStrBufDone (&parse->pstack->str);
1088 if (!s)
1089 {
1090 FcConfigMessage (parse, FcSevereError, "out of memory");
1091 return;
1092 }
1093 expr = FcExprCreateString (s);
1094 FcStrFree (s);
1095 if (expr)
1096 FcVStackPushExpr (parse, FcVStackFamily, expr);
1097 }
1098
1099 static void
1100 FcParseAlias (FcConfigParse *parse)
1101 {
1102 FcExpr *family = 0, *accept = 0, *prefer = 0, *def = 0, *new = 0;
1103 FcEdit *edit = 0, *next;
1104 FcVStack *vstack;
1105 FcTest *test;
1106
1107 while ((vstack = FcVStackPop (parse)))
1108 {
1109 switch (vstack->tag) {
1110 case FcVStackFamily:
1111 if (family)
1112 {
1113 new = FcExprCreateOp (vstack->u.expr, FcOpComma, family);
1114 if (!new)
1115 FcConfigMessage (parse, FcSevereError, "out of memory");
1116 else
1117 family = new;
1118 }
1119 else
1120 new = vstack->u.expr;
1121 if (new)
1122 {
1123 family = new;
1124 vstack->tag = FcVStackNone;
1125 }
1126 break;
1127 case FcVStackPrefer:
1128 if (prefer)
1129 FcExprDestroy (prefer);
1130 prefer = vstack->u.expr;
1131 vstack->tag = FcVStackNone;
1132 break;
1133 case FcVStackAccept:
1134 if (accept)
1135 FcExprDestroy (accept);
1136 accept = vstack->u.expr;
1137 vstack->tag = FcVStackNone;
1138 break;
1139 case FcVStackDefault:
1140 if (def)
1141 FcExprDestroy (def);
1142 def = vstack->u.expr;
1143 vstack->tag = FcVStackNone;
1144 break;
1145 default:
1146 FcConfigMessage (parse, FcSevereWarning, "bad alias");
1147 break;
1148 }
1149 FcVStackDestroy (vstack);
1150 }
1151 if (!family)
1152 {
1153 FcConfigMessage (parse, FcSevereError, "missing family in alias");
1154 if (prefer)
1155 FcExprDestroy (prefer);
1156 if (accept)
1157 FcExprDestroy (accept);
1158 if (def)
1159 FcExprDestroy (def);
1160 return;
1161 }
1162 if (prefer)
1163 {
1164 edit = FcEditCreate (FcConfigSaveField ("family"),
1165 FcOpPrepend,
1166 prefer,
1167 FcValueBindingWeak);
1168 if (edit)
1169 edit->next = 0;
1170 else
1171 FcExprDestroy (prefer);
1172 }
1173 if (accept)
1174 {
1175 next = edit;
1176 edit = FcEditCreate (FcConfigSaveField ("family"),
1177 FcOpAppend,
1178 accept,
1179 FcValueBindingWeak);
1180 if (edit)
1181 edit->next = next;
1182 else
1183 FcExprDestroy (accept);
1184 }
1185 if (def)
1186 {
1187 next = edit;
1188 edit = FcEditCreate (FcConfigSaveField ("family"),
1189 FcOpAppendLast,
1190 def,
1191 FcValueBindingWeak);
1192 if (edit)
1193 edit->next = next;
1194 else
1195 FcExprDestroy (def);
1196 }
1197 if (edit)
1198 {
1199 test = FcTestCreate (FcMatchPattern,
1200 FcQualAny,
1201 (FcChar8 *) FC_FAMILY,
1202 FcOpEqual,
1203 family);
1204 if (test)
1205 if (!FcConfigAddEdit (parse->config, test, edit, FcMatchPattern))
1206 FcTestDestroy (test);
1207 }
1208 else
1209 FcExprDestroy (family);
1210 }
1211
1212 static FcExpr *
1213 FcPopExpr (FcConfigParse *parse)
1214 {
1215 FcVStack *vstack = FcVStackPop (parse);
1216 FcExpr *expr = 0;
1217 if (!vstack)
1218 return 0;
1219 switch (vstack->tag) {
1220 case FcVStackNone:
1221 break;
1222 case FcVStackString:
1223 case FcVStackFamily:
1224 expr = FcExprCreateString (vstack->u.string);
1225 break;
1226 case FcVStackField:
1227 expr = FcExprCreateField ((char *) vstack->u.string);
1228 break;
1229 case FcVStackConstant:
1230 expr = FcExprCreateConst (vstack->u.string);
1231 break;
1232 case FcVStackPrefer:
1233 case FcVStackAccept:
1234 case FcVStackDefault:
1235 expr = vstack->u.expr;
1236 vstack->tag = FcVStackNone;
1237 break;
1238 case FcVStackInteger:
1239 expr = FcExprCreateInteger (vstack->u.integer);
1240 break;
1241 case FcVStackDouble:
1242 expr = FcExprCreateDouble (vstack->u._double);
1243 break;
1244 case FcVStackMatrix:
1245 expr = FcExprCreateMatrix (vstack->u.matrix);
1246 break;
1247 case FcVStackBool:
1248 expr = FcExprCreateBool (vstack->u.bool);
1249 break;
1250 case FcVStackTest:
1251 break;
1252 case FcVStackExpr:
1253 expr = vstack->u.expr;
1254 vstack->tag = FcVStackNone;
1255 break;
1256 case FcVStackEdit:
1257 break;
1258 }
1259 FcVStackDestroy (vstack);
1260 return expr;
1261 }
1262
1263 static FcExpr *
1264 FcPopExprs (FcConfigParse *parse, FcOp op)
1265 {
1266 FcExpr *left, *expr = 0, *new;
1267
1268 while ((left = FcPopExpr (parse)))
1269 {
1270 if (expr)
1271 {
1272 new = FcExprCreateOp (left, op, expr);
1273 if (!new)
1274 {
1275 FcConfigMessage (parse, FcSevereError, "out of memory");
1276 FcExprDestroy (left);
1277 FcExprDestroy (expr);
1278 break;
1279 }
1280 expr = new;
1281 }
1282 else
1283 expr = left;
1284 }
1285 return expr;
1286 }
1287
1288 static void
1289 FcParseExpr (FcConfigParse *parse, FcOp op)
1290 {
1291 FcExpr *expr = FcPopExprs (parse, op);
1292 if (expr)
1293 FcVStackPushExpr (parse, FcVStackExpr, expr);
1294 }
1295
1296 static void
1297 FcParseInclude (FcConfigParse *parse)
1298 {
1299 FcChar8 *s;
1300 const FcChar8 *i;
1301 FcBool ignore_missing = FcFalse;
1302
1303 s = FcStrBufDone (&parse->pstack->str);
1304 if (!s)
1305 {
1306 FcConfigMessage (parse, FcSevereError, "out of memory");
1307 return;
1308 }
1309 i = FcConfigGetAttribute (parse, "ignore_missing");
1310 if (i && FcConfigLexBool ((FcChar8 *) i) == FcTrue)
1311 ignore_missing = FcTrue;
1312 if (!FcConfigParseAndLoad (parse->config, s, !ignore_missing))
1313 parse->error = FcTrue;
1314 free (s);
1315 }
1316
1317 typedef struct _FcOpMap {
1318 char *name;
1319 FcOp op;
1320 } FcOpMap;
1321
1322 static FcOp
1323 FcConfigLexOp (const FcChar8 *op, const FcOpMap *map, int nmap)
1324 {
1325 int i;
1326
1327 for (i = 0; i < nmap; i++)
1328 if (!strcmp ((char *) op, map[i].name))
1329 return map[i].op;
1330 return FcOpInvalid;
1331 }
1332
1333 static const FcOpMap fcCompareOps[] = {
1334 { "eq", FcOpEqual },
1335 { "not_eq", FcOpNotEqual },
1336 { "less", FcOpLess },
1337 { "less_eq", FcOpLessEqual },
1338 { "more", FcOpMore },
1339 { "more_eq", FcOpMoreEqual }
1340 };
1341
1342 #define NUM_COMPARE_OPS (sizeof fcCompareOps / sizeof fcCompareOps[0])
1343
1344 static FcOp
1345 FcConfigLexCompare (const FcChar8 *compare)
1346 {
1347 return FcConfigLexOp (compare, fcCompareOps, NUM_COMPARE_OPS);
1348 }
1349
1350
1351 static void
1352 FcParseTest (FcConfigParse *parse)
1353 {
1354 const FcChar8 *kind_string;
1355 FcMatchKind kind;
1356 const FcChar8 *qual_string;
1357 FcQual qual;
1358 const FcChar8 *name;
1359 const FcChar8 *compare_string;
1360 FcOp compare;
1361 FcExpr *expr;
1362 FcTest *test;
1363
1364 kind_string = FcConfigGetAttribute (parse, "target");
1365 if (!kind_string)
1366 kind = FcMatchDefault;
1367 else
1368 {
1369 if (!strcmp ((char *) kind_string, "pattern"))
1370 kind = FcMatchPattern;
1371 else if (!strcmp ((char *) kind_string, "font"))
1372 kind = FcMatchFont;
1373 else if (!strcmp ((char *) kind_string, "default"))
1374 kind = FcMatchDefault;
1375 else
1376 {
1377 FcConfigMessage (parse, FcSevereWarning, "invalid test target \"%s\"", kind_string);
1378 return;
1379 }
1380 }
1381 qual_string = FcConfigGetAttribute (parse, "qual");
1382 if (!qual_string)
1383 qual = FcQualAny;
1384 else
1385 {
1386 if (!strcmp ((char *) qual_string, "any"))
1387 qual = FcQualAny;
1388 else if (!strcmp ((char *) qual_string, "all"))
1389 qual = FcQualAll;
1390 else if (!strcmp ((char *) qual_string, "first"))
1391 qual = FcQualFirst;
1392 else if (!strcmp ((char *) qual_string, "not_first"))
1393 qual = FcQualNotFirst;
1394 else
1395 {
1396 FcConfigMessage (parse, FcSevereWarning, "invalid test qual \"%s\"", qual_string);
1397 return;
1398 }
1399 }
1400 name = FcConfigGetAttribute (parse, "name");
1401 if (!name)
1402 {
1403 FcConfigMessage (parse, FcSevereWarning, "missing test name");
1404 return;
1405 }
1406 compare_string = FcConfigGetAttribute (parse, "compare");
1407 if (!compare_string)
1408 compare = FcOpEqual;
1409 else
1410 {
1411 compare = FcConfigLexCompare (compare_string);
1412 if (compare == FcOpInvalid)
1413 {
1414 FcConfigMessage (parse, FcSevereWarning, "invalid test compare \"%s\"", compare_string);
1415 return;
1416 }
1417 }
1418 expr = FcPopExprs (parse, FcOpComma);
1419 if (!expr)
1420 {
1421 FcConfigMessage (parse, FcSevereWarning, "missing test expression");
1422 return;
1423 }
1424 test = FcTestCreate (kind, qual, name, compare, expr);
1425 if (!test)
1426 {
1427 FcConfigMessage (parse, FcSevereError, "out of memory");
1428 return;
1429 }
1430 FcVStackPushTest (parse, test);
1431 }
1432
1433 static const FcOpMap fcModeOps[] = {
1434 { "assign", FcOpAssign },
1435 { "assign_replace", FcOpAssignReplace },
1436 { "prepend", FcOpPrepend },
1437 { "prepend_first", FcOpPrependFirst },
1438 { "append", FcOpAppend },
1439 { "append_last", FcOpAppendLast },
1440 };
1441
1442 #define NUM_MODE_OPS (sizeof fcModeOps / sizeof fcModeOps[0])
1443
1444 static FcOp
1445 FcConfigLexMode (const FcChar8 *mode)
1446 {
1447 return FcConfigLexOp (mode, fcModeOps, NUM_MODE_OPS);
1448 }
1449
1450 static void
1451 FcParseEdit (FcConfigParse *parse)
1452 {
1453 const FcChar8 *name;
1454 const FcChar8 *mode_string;
1455 const FcChar8 *binding_string;
1456 FcOp mode;
1457 FcValueBinding binding;
1458 FcExpr *expr;
1459 FcEdit *edit;
1460
1461 name = FcConfigGetAttribute (parse, "name");
1462 if (!name)
1463 {
1464 FcConfigMessage (parse, FcSevereWarning, "missing edit name");
1465 return;
1466 }
1467 mode_string = FcConfigGetAttribute (parse, "mode");
1468 if (!mode_string)
1469 mode = FcOpAssign;
1470 else
1471 {
1472 mode = FcConfigLexMode (mode_string);
1473 if (mode == FcOpInvalid)
1474 {
1475 FcConfigMessage (parse, FcSevereWarning, "invalid edit mode \"%s\"", mode_string);
1476 return;
1477 }
1478 }
1479 binding_string = FcConfigGetAttribute (parse, "binding");
1480 if (!binding_string)
1481 binding = FcValueBindingWeak;
1482 else
1483 {
1484 if (!strcmp ((char *) binding_string, "weak"))
1485 binding = FcValueBindingWeak;
1486 else if (!strcmp ((char *) binding_string, "strong"))
1487 binding = FcValueBindingStrong;
1488 else
1489 {
1490 FcConfigMessage (parse, FcSevereWarning, "invalid edit binding \"%s\"", binding_string);
1491 return;
1492 }
1493 }
1494 expr = FcPopExprs (parse, FcOpComma);
1495 edit = FcEditCreate ((char *) FcStrCopy (name), mode, expr, binding);
1496 if (!edit)
1497 {
1498 FcConfigMessage (parse, FcSevereError, "out of memory");
1499 FcExprDestroy (expr);
1500 return;
1501 }
1502 if (!FcVStackPushEdit (parse, edit))
1503 FcEditDestroy (edit);
1504 }
1505
1506 static void
1507 FcParseMatch (FcConfigParse *parse)
1508 {
1509 const FcChar8 *kind_name;
1510 FcMatchKind kind;
1511 FcTest *test = 0;
1512 FcEdit *edit = 0;
1513 FcVStack *vstack;
1514
1515 kind_name = FcConfigGetAttribute (parse, "target");
1516 if (!kind_name)
1517 kind = FcMatchPattern;
1518 else
1519 {
1520 if (!strcmp ((char *) kind_name, "pattern"))
1521 kind = FcMatchPattern;
1522 else if (!strcmp ((char *) kind_name, "font"))
1523 kind = FcMatchFont;
1524 else
1525 {
1526 FcConfigMessage (parse, FcSevereWarning, "invalid match target \"%s\"", kind_name);
1527 return;
1528 }
1529 }
1530 while ((vstack = FcVStackPop (parse)))
1531 {
1532 switch (vstack->tag) {
1533 case FcVStackTest:
1534 vstack->u.test->next = test;
1535 test = vstack->u.test;
1536 vstack->tag = FcVStackNone;
1537 break;
1538 case FcVStackEdit:
1539 vstack->u.edit->next = edit;
1540 edit = vstack->u.edit;
1541 vstack->tag = FcVStackNone;
1542 break;
1543 default:
1544 FcConfigMessage (parse, FcSevereWarning, "invalid match element");
1545 break;
1546 }
1547 FcVStackDestroy (vstack);
1548 }
1549 if (!FcConfigAddEdit (parse->config, test, edit, kind))
1550 FcConfigMessage (parse, FcSevereError, "out of memory");
1551 }
1552
1553 static void
1554 FcEndElement(void *userData, const XML_Char *name)
1555 {
1556 FcConfigParse *parse = userData;
1557 FcChar8 *data;
1558
1559 if (!parse->pstack)
1560 return;
1561 switch (parse->pstack->element) {
1562 case FcElementNone:
1563 break;
1564 case FcElementFontconfig:
1565 break;
1566 case FcElementDir:
1567 data = FcStrBufDone (&parse->pstack->str);
1568 if (!data)
1569 {
1570 FcConfigMessage (parse, FcSevereError, "out of memory");
1571 break;
1572 }
1573 if (!FcConfigAddDir (parse->config, data))
1574 FcConfigMessage (parse, FcSevereError, "out of memory");
1575 free (data);
1576 break;
1577 case FcElementCache:
1578 data = FcStrBufDone (&parse->pstack->str);
1579 if (!data)
1580 {
1581 FcConfigMessage (parse, FcSevereError, "out of memory");
1582 break;
1583 }
1584 if (!FcConfigSetCache (parse->config, data))
1585 FcConfigMessage (parse, FcSevereError, "out of memory");
1586 free (data);
1587 break;
1588 case FcElementInclude:
1589 FcParseInclude (parse);
1590 break;
1591 case FcElementConfig:
1592 break;
1593 case FcElementMatch:
1594 FcParseMatch (parse);
1595 break;
1596 case FcElementAlias:
1597 FcParseAlias (parse);
1598 break;
1599
1600 case FcElementBlank:
1601 FcParseBlank (parse);
1602 break;
1603 case FcElementRescan:
1604 FcParseRescan (parse);
1605 break;
1606
1607 case FcElementPrefer:
1608 FcParseFamilies (parse, FcVStackPrefer);
1609 break;
1610 case FcElementAccept:
1611 FcParseFamilies (parse, FcVStackAccept);
1612 break;
1613 case FcElementDefault:
1614 FcParseFamilies (parse, FcVStackDefault);
1615 break;
1616 case FcElementFamily:
1617 FcParseFamily (parse);
1618 break;
1619
1620 case FcElementTest:
1621 FcParseTest (parse);
1622 break;
1623 case FcElementEdit:
1624 FcParseEdit (parse);
1625 break;
1626
1627 case FcElementInt:
1628 FcParseInt (parse);
1629 break;
1630 case FcElementDouble:
1631 FcParseDouble (parse);
1632 break;
1633 case FcElementString:
1634 FcParseString (parse, FcVStackString);
1635 break;
1636 case FcElementMatrix:
1637 FcParseMatrix (parse);
1638 break;
1639 case FcElementBool:
1640 FcParseBool (parse);
1641 break;
1642 case FcElementCharset:
1643 /* FcParseCharset (parse); */
1644 break;
1645
1646 case FcElementName:
1647 FcParseString (parse, FcVStackField);
1648 break;
1649 case FcElementConst:
1650 FcParseString (parse, FcVStackConstant);
1651 break;
1652 case FcElementOr:
1653 FcParseExpr (parse, FcOpOr);
1654 break;
1655 case FcElementAnd:
1656 FcParseExpr (parse, FcOpAnd);
1657 break;
1658 case FcElementEq:
1659 FcParseExpr (parse, FcOpEqual);
1660 break;
1661 case FcElementNotEq:
1662 FcParseExpr (parse, FcOpNotEqual);
1663 break;
1664 case FcElementLess:
1665 FcParseExpr (parse, FcOpLess);
1666 break;
1667 case FcElementLessEq:
1668 FcParseExpr (parse, FcOpLessEqual);
1669 break;
1670 case FcElementMore:
1671 FcParseExpr (parse, FcOpMore);
1672 break;
1673 case FcElementMoreEq:
1674 FcParseExpr (parse, FcOpMoreEqual);
1675 break;
1676 case FcElementPlus:
1677 FcParseExpr (parse, FcOpPlus);
1678 break;
1679 case FcElementMinus:
1680 FcParseExpr (parse, FcOpMinus);
1681 break;
1682 case FcElementTimes:
1683 FcParseExpr (parse, FcOpTimes);
1684 break;
1685 case FcElementDivide:
1686 FcParseExpr (parse, FcOpDivide);
1687 break;
1688 case FcElementNot:
1689 FcParseExpr (parse, FcOpNot);
1690 break;
1691 case FcElementIf:
1692 FcParseExpr (parse, FcOpQuest);
1693 break;
1694 case FcElementUnknown:
1695 break;
1696 }
1697 (void) FcPStackPop (parse);
1698 }
1699
1700 static void
1701 FcCharacterData (void *userData, const XML_Char *s, int len)
1702 {
1703 FcConfigParse *parse = userData;
1704
1705 if (!parse->pstack)
1706 return;
1707 if (!FcStrBufData (&parse->pstack->str, (FcChar8 *) s, len))
1708 FcConfigMessage (parse, FcSevereError, "out of memory");
1709 }
1710
1711 static void
1712 FcStartDoctypeDecl (void *userData,
1713 const XML_Char *doctypeName,
1714 const XML_Char *sysid,
1715 const XML_Char *pubid,
1716 int has_internal_subset)
1717 {
1718 FcConfigParse *parse = userData;
1719
1720 if (strcmp ((char *) doctypeName, "fontconfig") != 0)
1721 FcConfigMessage (parse, FcSevereError, "invalid doctype \"%s\"", doctypeName);
1722 }
1723
1724 static void
1725 FcEndDoctypeDecl (void *userData)
1726 {
1727 }
1728
1729 FcBool
1730 FcConfigParseAndLoad (FcConfig *config,
1731 const FcChar8 *name,
1732 FcBool complain)
1733 {
1734
1735 XML_Parser p;
1736 FcChar8 *filename;
1737 FILE *f;
1738 int len;
1739 void *buf;
1740 FcConfigParse parse;
1741 FcBool error = FcTrue;
1742
1743 filename = FcConfigFilename (name);
1744 if (!filename)
1745 goto bail0;
1746
1747 if (!FcStrSetAdd (config->configFiles, filename))
1748 goto bail0;
1749
1750 f = fopen ((char *) filename, "r");
1751 free (filename);
1752 if (!f)
1753 goto bail0;
1754
1755 p = XML_ParserCreate ("UTF-8");
1756 if (!p)
1757 goto bail1;
1758
1759 if (!FcConfigInit (&parse, name, config, p))
1760 goto bail2;
1761
1762 XML_SetUserData (p, &parse);
1763
1764 XML_SetDoctypeDeclHandler (p, FcStartDoctypeDecl, FcEndDoctypeDecl);
1765 XML_SetElementHandler (p, FcStartElement, FcEndElement);
1766 XML_SetCharacterDataHandler (p, FcCharacterData);
1767
1768 do {
1769 buf = XML_GetBuffer (p, BUFSIZ);
1770 if (!buf)
1771 {
1772 FcConfigMessage (&parse, FcSevereError, "cannot get parse buffer");
1773 goto bail3;
1774 }
1775 len = fread (buf, 1, BUFSIZ, f);
1776 if (len < 0)
1777 {
1778 FcConfigMessage (&parse, FcSevereError, "failed reading config file");
1779 goto bail3;
1780 }
1781 if (!XML_ParseBuffer (p, len, len == 0))
1782 {
1783 FcConfigMessage (&parse, FcSevereError, "%s",
1784 XML_ErrorString (XML_GetErrorCode (p)));
1785 goto bail3;
1786 }
1787 } while (len != 0);
1788 error = parse.error;
1789 bail3:
1790 FcConfigCleanup (&parse);
1791 bail2:
1792 XML_ParserFree (p);
1793 bail1:
1794 fclose (f);
1795 bail0:
1796 if (error && complain)
1797 {
1798 if (name)
1799 FcConfigMessage (0, FcSevereError, "Cannot load config file \"%s\"", name);
1800 else
1801 FcConfigMessage (0, FcSevereError, "Cannot load default config file");
1802 return FcFalse;
1803 }
1804 return FcTrue;
1805 }