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