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