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