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