]> git.wh0rd.org - fontconfig.git/blob - src/fcxml.c
Switch fontconfig from libxml2 to expat
[fontconfig.git] / src / fcxml.c
1 /*
2 * $XFree86: xc/lib/fontconfig/src/fcxml.c,v 1.2 2002/02/15 06:01:28 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 case FcVStackField:
1101 case FcVStackConstant:
1102 expr = FcExprCreateString (vstack->u.string);
1103 break;
1104 case FcVStackPrefer:
1105 case FcVStackAccept:
1106 case FcVStackDefault:
1107 expr = vstack->u.expr;
1108 vstack->tag = FcVStackNone;
1109 break;
1110 case FcVStackInteger:
1111 expr = FcExprCreateInteger (vstack->u.integer);
1112 break;
1113 case FcVStackDouble:
1114 expr = FcExprCreateDouble (vstack->u._double);
1115 break;
1116 case FcVStackMatrix:
1117 expr = FcExprCreateMatrix (vstack->u.matrix);
1118 break;
1119 case FcVStackBool:
1120 expr = FcExprCreateBool (vstack->u.bool);
1121 break;
1122 case FcVStackTest:
1123 break;
1124 case FcVStackExpr:
1125 expr = vstack->u.expr;
1126 break;
1127 case FcVStackEdit:
1128 break;
1129 }
1130 FcVStackDestroy (vstack);
1131 return expr;
1132 }
1133
1134 static FcExpr *
1135 FcPopExprs (FcConfigParse *parse, FcOp op)
1136 {
1137 FcExpr *left, *expr = 0, *new;
1138
1139 while ((left = FcPopExpr (parse)))
1140 {
1141 if (expr)
1142 {
1143 new = FcExprCreateOp (left, op, expr);
1144 if (!new)
1145 {
1146 FcConfigError (parse, "out of memory");
1147 FcExprDestroy (left);
1148 FcExprDestroy (expr);
1149 break;
1150 }
1151 expr = new;
1152 }
1153 else
1154 expr = left;
1155 }
1156 return expr;
1157 }
1158
1159 static void
1160 FcParseExpr (FcConfigParse *parse, FcOp op)
1161 {
1162 FcExpr *expr = FcPopExprs (parse, op);
1163 if (expr)
1164 FcVStackPushExpr (parse, FcVStackExpr, expr);
1165 }
1166
1167 static void
1168 FcParseInclude (FcConfigParse *parse)
1169 {
1170 FcChar8 *s;
1171 const FcChar8 *i;
1172 FcBool ignore_missing = FcFalse;
1173
1174 s = FcStrBufDone (&parse->pstack->str);
1175 if (!s)
1176 {
1177 FcConfigError (parse, "out of memory");
1178 return;
1179 }
1180 i = FcConfigGetAttribute (parse, "ignore_missing");
1181 if (i && FcConfigLexBool ((FcChar8 *) i) == FcTrue)
1182 ignore_missing = FcTrue;
1183 if (!FcConfigParseAndLoad (parse->config, s, ignore_missing))
1184 parse->error = FcTrue;
1185 free (s);
1186 }
1187
1188 typedef struct _FcOpMap {
1189 char *name;
1190 FcOp op;
1191 } FcOpMap;
1192
1193 static FcOp
1194 FcConfigLexOp (const FcChar8 *op, const FcOpMap *map, int nmap)
1195 {
1196 int i;
1197
1198 for (i = 0; i < nmap; i++)
1199 if (!strcmp ((char *) op, map[i].name))
1200 return map[i].op;
1201 return FcOpInvalid;
1202 }
1203
1204 static const FcOpMap fcCompareOps[] = {
1205 { "eq", FcOpEqual },
1206 { "not_eq", FcOpNotEqual },
1207 { "less", FcOpLess },
1208 { "less_eq", FcOpLessEqual },
1209 { "more", FcOpMore },
1210 { "more_eq", FcOpMoreEqual }
1211 };
1212
1213 #define NUM_COMPARE_OPS (sizeof fcCompareOps / sizeof fcCompareOps[0])
1214
1215 static FcOp
1216 FcConfigLexCompare (const FcChar8 *compare)
1217 {
1218 return FcConfigLexOp (compare, fcCompareOps, NUM_COMPARE_OPS);
1219 }
1220
1221
1222 static void
1223 FcParseTest (FcConfigParse *parse)
1224 {
1225 const FcChar8 *qual_string;
1226 FcQual qual;
1227 const FcChar8 *name;
1228 const FcChar8 *compare_string;
1229 FcOp compare;
1230 FcExpr *expr;
1231 FcTest *test;
1232
1233 qual_string = FcConfigGetAttribute (parse, "qual");
1234 if (!qual_string)
1235 qual = FcQualAny;
1236 else
1237 {
1238 if (!strcmp ((char *) qual_string, "any"))
1239 qual = FcQualAny;
1240 else if (!strcmp ((char *) qual_string, "all"))
1241 qual = FcQualAll;
1242 else
1243 {
1244 FcConfigError (parse, "invalid test qual \"%s\"", qual_string);
1245 return;
1246 }
1247 }
1248 name = FcConfigGetAttribute (parse, "name");
1249 if (!name)
1250 {
1251 FcConfigError (parse, "missing test name");
1252 return;
1253 }
1254 compare_string = FcConfigGetAttribute (parse, "compare");
1255 if (!compare_string)
1256 compare = FcOpEqual;
1257 else
1258 {
1259 compare = FcConfigLexCompare (compare_string);
1260 if (compare == FcOpInvalid)
1261 {
1262 FcConfigError (parse, "invalid test compare \"%s\"", compare_string);
1263 return;
1264 }
1265 }
1266 expr = FcPopExpr (parse);
1267 if (!expr)
1268 {
1269 FcConfigError (parse, "missing test expression");
1270 return;
1271 }
1272 test = FcTestCreate (qual, name, compare, expr);
1273 if (!test)
1274 {
1275 FcConfigError (parse, "out of memory");
1276 return;
1277 }
1278 FcVStackPushTest (parse, test);
1279 }
1280
1281 static const FcOpMap fcModeOps[] = {
1282 { "assign", FcOpAssign },
1283 { "assign_replace", FcOpAssignReplace },
1284 { "prepend", FcOpPrepend },
1285 { "prepend_first", FcOpPrependFirst },
1286 { "append", FcOpAppend },
1287 { "append_last", FcOpAppendLast },
1288 };
1289
1290 #define NUM_MODE_OPS (sizeof fcModeOps / sizeof fcModeOps[0])
1291
1292 static FcOp
1293 FcConfigLexMode (const FcChar8 *mode)
1294 {
1295 return FcConfigLexOp (mode, fcModeOps, NUM_MODE_OPS);
1296 }
1297
1298 static void
1299 FcParseEdit (FcConfigParse *parse)
1300 {
1301 const FcChar8 *name;
1302 const FcChar8 *mode_string;
1303 FcOp mode;
1304 FcExpr *expr;
1305 FcEdit *edit;
1306
1307 name = FcConfigGetAttribute (parse, "name");
1308 if (!name)
1309 {
1310 FcConfigError (parse, "missing edit name");
1311 return;
1312 }
1313 mode_string = FcConfigGetAttribute (parse, "mode");
1314 if (!mode_string)
1315 mode = FcOpEqual;
1316 else
1317 {
1318 mode = FcConfigLexMode (mode_string);
1319 if (mode == FcOpInvalid)
1320 {
1321 FcConfigError (parse, "invalid edit mode \"%s\"", mode_string);
1322 return;
1323 }
1324 }
1325 expr = FcPopExprs (parse, FcOpComma);
1326 edit = FcEditCreate ((char *) FcStrCopy (name), mode, expr);
1327 if (!edit)
1328 {
1329 FcConfigError (parse, "out of memory");
1330 FcExprDestroy (expr);
1331 return;
1332 }
1333 if (!FcVStackPushEdit (parse, edit))
1334 FcEditDestroy (edit);
1335 }
1336
1337 static void
1338 FcParseMatch (FcConfigParse *parse)
1339 {
1340 const FcChar8 *kind_name;
1341 FcMatchKind kind;
1342 FcTest *test = 0;
1343 FcEdit *edit = 0;
1344 FcVStack *vstack;
1345
1346 kind_name = FcConfigGetAttribute (parse, "target");
1347 if (!kind_name)
1348 kind = FcMatchPattern;
1349 else
1350 {
1351 if (!strcmp ((char *) kind_name, "pattern"))
1352 kind = FcMatchPattern;
1353 else if (!strcmp ((char *) kind_name, "font"))
1354 kind = FcMatchFont;
1355 else
1356 {
1357 FcConfigError (parse, "invalid match target \"%s\"", kind_name);
1358 return;
1359 }
1360 }
1361 while ((vstack = FcVStackPop (parse)))
1362 {
1363 switch (vstack->tag) {
1364 case FcVStackTest:
1365 vstack->u.test->next = test;
1366 test = vstack->u.test;
1367 vstack->tag = FcVStackNone;
1368 break;
1369 case FcVStackEdit:
1370 vstack->u.edit->next = edit;
1371 edit = vstack->u.edit;
1372 vstack->tag = FcVStackNone;
1373 break;
1374 default:
1375 FcConfigError (parse, "invalid match element");
1376 break;
1377 }
1378 FcVStackDestroy (vstack);
1379 }
1380 if (!FcConfigAddEdit (parse->config, test, edit, kind))
1381 FcConfigError (parse, "out of memory");
1382 }
1383
1384 static void
1385 FcEndElement(void *userData, const XML_Char *name)
1386 {
1387 FcConfigParse *parse = userData;
1388 FcChar8 *data;
1389
1390 if (!parse->pstack)
1391 return;
1392 switch (parse->pstack->element) {
1393 case FcElementNone:
1394 break;
1395 case FcElementFontconfig:
1396 break;
1397 case FcElementDir:
1398 data = FcStrBufDone (&parse->pstack->str);
1399 if (!data)
1400 {
1401 FcConfigError (parse, "out of memory");
1402 break;
1403 }
1404 if (!FcConfigAddDir (parse->config, data))
1405 FcConfigError (parse, "out of memory");
1406 free (data);
1407 break;
1408 case FcElementCache:
1409 data = FcStrBufDone (&parse->pstack->str);
1410 if (!data)
1411 {
1412 FcConfigError (parse, "out of memory");
1413 break;
1414 }
1415 if (!FcConfigSetCache (parse->config, data))
1416 FcConfigError (parse, "out of memory");
1417 free (data);
1418 break;
1419 case FcElementInclude:
1420 FcParseInclude (parse);
1421 break;
1422 case FcElementConfig:
1423 break;
1424 case FcElementMatch:
1425 FcParseMatch (parse);
1426 break;
1427 case FcElementAlias:
1428 FcParseAlias (parse);
1429 break;
1430
1431 case FcElementBlank:
1432 FcParseBlank (parse);
1433 break;
1434
1435 case FcElementPrefer:
1436 FcParseFamilies (parse, FcVStackPrefer);
1437 break;
1438 case FcElementAccept:
1439 FcParseFamilies (parse, FcVStackAccept);
1440 break;
1441 case FcElementDefault:
1442 FcParseFamilies (parse, FcVStackDefault);
1443 break;
1444 case FcElementFamily:
1445 FcParseFamily (parse);
1446 break;
1447
1448 case FcElementTest:
1449 FcParseTest (parse);
1450 break;
1451 case FcElementEdit:
1452 FcParseEdit (parse);
1453 break;
1454
1455 case FcElementInt:
1456 FcParseInt (parse);
1457 break;
1458 case FcElementDouble:
1459 FcParseDouble (parse);
1460 break;
1461 case FcElementString:
1462 FcParseString (parse, FcVStackString);
1463 break;
1464 case FcElementMatrix:
1465 FcParseMatrix (parse);
1466 break;
1467 case FcElementBool:
1468 FcParseBool (parse);
1469 break;
1470 case FcElementCharset:
1471 /* FcParseCharset (parse); */
1472 break;
1473
1474 case FcElementName:
1475 FcParseString (parse, FcVStackField);
1476 break;
1477 case FcElementConst:
1478 FcParseString (parse, FcVStackConstant);
1479 break;
1480 case FcElementOr:
1481 FcParseExpr (parse, FcOpOr);
1482 break;
1483 case FcElementAnd:
1484 FcParseExpr (parse, FcOpAnd);
1485 break;
1486 case FcElementEq:
1487 FcParseExpr (parse, FcOpEqual);
1488 break;
1489 case FcElementNotEq:
1490 FcParseExpr (parse, FcOpNotEqual);
1491 break;
1492 case FcElementLess:
1493 FcParseExpr (parse, FcOpLess);
1494 break;
1495 case FcElementLessEq:
1496 FcParseExpr (parse, FcOpLessEqual);
1497 break;
1498 case FcElementMore:
1499 FcParseExpr (parse, FcOpMore);
1500 break;
1501 case FcElementMoreEq:
1502 FcParseExpr (parse, FcOpMoreEqual);
1503 break;
1504 case FcElementPlus:
1505 FcParseExpr (parse, FcOpPlus);
1506 break;
1507 case FcElementMinus:
1508 FcParseExpr (parse, FcOpMinus);
1509 break;
1510 case FcElementTimes:
1511 FcParseExpr (parse, FcOpTimes);
1512 break;
1513 case FcElementDivide:
1514 FcParseExpr (parse, FcOpDivide);
1515 break;
1516 case FcElementNot:
1517 FcParseExpr (parse, FcOpNot);
1518 break;
1519 case FcElementIf:
1520 FcParseExpr (parse, FcOpQuest);
1521 break;
1522 case FcElementUnknown:
1523 break;
1524 }
1525 (void) FcPStackPop (parse);
1526 }
1527
1528 static void
1529 FcCharacterData (void *userData, const XML_Char *s, int len)
1530 {
1531 FcConfigParse *parse = userData;
1532
1533 if (!parse->pstack)
1534 return;
1535 if (!FcStrBufData (&parse->pstack->str, (FcChar8 *) s, len))
1536 FcConfigError (parse, "out of memory");
1537 }
1538
1539 static void
1540 FcStartDoctypeDecl (void *userData,
1541 const XML_Char *doctypeName,
1542 const XML_Char *sysid,
1543 const XML_Char *pubid,
1544 int has_internal_subset)
1545 {
1546 FcConfigParse *parse = userData;
1547
1548 if (strcmp ((char *) doctypeName, "fontconfig") != 0)
1549 FcConfigError (parse, "invalid doctype \"%s\"", doctypeName);
1550 }
1551
1552 static void
1553 FcEndDoctypeDecl (void *userData)
1554 {
1555 }
1556
1557 FcBool
1558 FcConfigParseAndLoad (FcConfig *config,
1559 const FcChar8 *name,
1560 FcBool complain)
1561 {
1562
1563 XML_Parser p;
1564 FcChar8 *filename;
1565 FILE *f;
1566 int len;
1567 void *buf;
1568 FcConfigParse parse;
1569 FcBool error = FcTrue;
1570
1571 filename = FcConfigFilename (name);
1572 if (!filename)
1573 goto bail0;
1574 f = fopen ((char *) filename, "r");
1575 free (filename);
1576 if (!f)
1577 goto bail0;
1578
1579 p = XML_ParserCreate ("UTF-8");
1580 if (!p)
1581 goto bail1;
1582
1583 if (!FcConfigInit (&parse, name, config, p))
1584 goto bail2;
1585
1586 XML_SetUserData (p, &parse);
1587
1588 XML_SetDoctypeDeclHandler (p, FcStartDoctypeDecl, FcEndDoctypeDecl);
1589 XML_SetElementHandler (p, FcStartElement, FcEndElement);
1590 XML_SetCharacterDataHandler (p, FcCharacterData);
1591
1592 do {
1593 buf = XML_GetBuffer (p, BUFSIZ);
1594 if (!buf)
1595 goto bail3;
1596 len = fread (buf, 1, BUFSIZ, f);
1597 if (len < 0)
1598 goto bail3;
1599 if (!XML_ParseBuffer (p, len, len == 0))
1600 goto bail3;
1601 } while (len != 0);
1602 error = parse.error;
1603 bail3:
1604 FcConfigCleanup (&parse);
1605 bail2:
1606 XML_ParserFree (p);
1607 bail1:
1608 fclose (f);
1609 bail0:
1610 if (error && complain)
1611 {
1612 if (name)
1613 FcConfigError (0, "Cannot load config file \"%s\"", name);
1614 else
1615 FcConfigError (0, "Cannot load default config file");
1616 return FcFalse;
1617 }
1618 return FcTrue;
1619 }