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