]> git.wh0rd.org Git - 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 }