]> git.wh0rd.org Git - fontconfig.git/blob - src/fcxml.c
Use libxml2 if requested (with --enable-libxml2) or if expat is not
[fontconfig.git] / src / fcxml.c
1 /*
2  * $RCSId: xc/lib/fontconfig/src/fcxml.c,v 1.21 2002/08/22 18:53:22 keithp Exp $
3  *
4  * Copyright © 2002 Keith Packard
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 #include <dirent.h>
28
29 #if ENABLE_LIBXML2
30
31 #include <libxml/parser.h>
32
33 #define XML_Char                        xmlChar
34 #define XML_Parser                      xmlParserCtxtPtr
35 #define XML_ParserFree                  xmlFreeParserCtxt
36 #define XML_GetCurrentLineNumber        xmlSAX2GetLineNumber
37 #define XML_GetErrorCode                xmlCtxtGetLastError
38 #define XML_ErrorString(Error)          (Error)->message
39
40 #else /* ENABLE_LIBXML2 */
41
42 #ifndef HAVE_XMLPARSE_H
43 #define HAVE_XMLPARSE_H 0
44 #endif
45
46 #if HAVE_XMLPARSE_H
47 #include <xmlparse.h>
48 #else
49 #include <expat.h>
50 #endif
51
52 #endif /* ENABLE_LIBXML2 */
53
54 #ifdef _WIN32
55 #define STRICT
56 #include <windows.h>
57 #undef STRICT
58 #endif
59
60
61 void
62 FcTestDestroy (FcTest *test)
63 {
64     if (test->next)
65         FcTestDestroy (test->next);
66     FcExprDestroy (test->expr);
67     FcStrFree ((FcChar8 *) test->field);
68     FcMemFree (FC_MEM_TEST, sizeof (FcTest));
69     free (test);
70 }
71
72 FcExpr *
73 FcExprCreateInteger (int i)
74 {
75     FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
76
77     if (e)
78     {
79         FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
80         e->op = FcOpInteger;
81         e->u.ival = i;
82     }
83     return e;
84 }
85
86 FcExpr *
87 FcExprCreateDouble (double d)
88 {
89     FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
90
91     if (e)
92     {
93         FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
94         e->op = FcOpDouble;
95         e->u.dval = d;
96     }
97     return e;
98 }
99
100 FcExpr *
101 FcExprCreateString (const FcChar8 *s)
102 {
103     FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
104
105     if (e)
106     {
107         FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
108         e->op = FcOpString;
109         e->u.sval = FcStrCopy (s);
110     }
111     return e;
112 }
113
114 FcExpr *
115 FcExprCreateMatrix (const FcMatrix *m)
116 {
117     FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
118
119     if (e)
120     {
121         FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
122         e->op = FcOpMatrix;
123         e->u.mval = FcMatrixCopy (m);
124     }
125     return e;
126 }
127
128 FcExpr *
129 FcExprCreateBool (FcBool b)
130 {
131     FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
132
133     if (e)
134     {
135         FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
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         FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
150         e->op = FcOpNil;
151     }
152     return e;
153 }
154
155 FcExpr *
156 FcExprCreateField (const char *field)
157 {
158     FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
159
160     if (e)
161     {
162         FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
163         e->op = FcOpField;
164         e->u.field = (char *) FcStrCopy ((FcChar8 *) field);
165     }
166     return e;
167 }
168
169 FcExpr *
170 FcExprCreateConst (const FcChar8 *constant)
171 {
172     FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
173
174     if (e)
175     {
176         FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
177         e->op = FcOpConst;
178         e->u.constant = FcStrCopy (constant);
179     }
180     return e;
181 }
182
183 FcExpr *
184 FcExprCreateOp (FcExpr *left, FcOp op, FcExpr *right)
185 {
186     FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
187
188     if (e)
189     {
190         FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
191         e->op = op;
192         e->u.tree.left = left;
193         e->u.tree.right = right;
194     }
195     return e;
196 }
197
198 void
199 FcExprDestroy (FcExpr *e)
200 {
201     if (!e)
202         return;
203     switch (e->op) {
204     case FcOpInteger:
205         break;
206     case FcOpDouble:
207         break;
208     case FcOpString:
209         FcStrFree (e->u.sval);
210         break;
211     case FcOpMatrix:
212         FcMatrixFree (e->u.mval);
213         break;
214     case FcOpCharSet:
215         FcCharSetDestroy (e->u.cval);
216         break;
217     case FcOpBool:
218         break;
219     case FcOpField:
220         FcStrFree ((FcChar8 *) e->u.field);
221         break;
222     case FcOpConst:
223         FcStrFree (e->u.constant);
224         break;
225     case FcOpAssign:
226     case FcOpAssignReplace:
227     case FcOpPrepend:
228     case FcOpPrependFirst:
229     case FcOpAppend:
230     case FcOpAppendLast:
231         break;
232     case FcOpOr:
233     case FcOpAnd:
234     case FcOpEqual:
235     case FcOpNotEqual:
236     case FcOpLess:
237     case FcOpLessEqual:
238     case FcOpMore:
239     case FcOpMoreEqual:
240     case FcOpContains:
241     case FcOpListing:
242     case FcOpNotContains:
243     case FcOpPlus:
244     case FcOpMinus:
245     case FcOpTimes:
246     case FcOpDivide:
247     case FcOpQuest:
248     case FcOpComma:
249         FcExprDestroy (e->u.tree.right);
250         /* fall through */
251     case FcOpNot:
252     case FcOpFloor:
253     case FcOpCeil:
254     case FcOpRound:
255     case FcOpTrunc:
256         FcExprDestroy (e->u.tree.left);
257         break;
258     case FcOpNil:
259     case FcOpInvalid:
260         break;
261     }
262     FcMemFree (FC_MEM_EXPR, sizeof (FcExpr));
263     free (e);
264 }
265
266 void
267 FcEditDestroy (FcEdit *e)
268 {
269     if (e->next)
270         FcEditDestroy (e->next);
271     FcStrFree ((FcChar8 *) e->field);
272     if (e->expr)
273         FcExprDestroy (e->expr);
274     free (e);
275 }
276
277 char *
278 FcConfigSaveField (const char *field)
279 {
280     return (char *) FcStrCopy ((FcChar8 *) field);
281 }
282
283 typedef enum _FcElement {
284     FcElementNone,
285     FcElementFontconfig,
286     FcElementDir,
287     FcElementCache,
288     FcElementInclude,
289     FcElementConfig,
290     FcElementMatch,
291     FcElementAlias,
292         
293     FcElementBlank,
294     FcElementRescan,
295
296     FcElementPrefer,
297     FcElementAccept,
298     FcElementDefault,
299     FcElementFamily,
300
301     FcElementSelectfont,
302     FcElementAcceptfont,
303     FcElementRejectfont,
304     FcElementGlob,
305     FcElementPattern,
306     FcElementPatelt,
307
308     FcElementTest,
309     FcElementEdit,
310     FcElementInt,
311     FcElementDouble,
312     FcElementString,
313     FcElementMatrix,
314     FcElementBool,
315     FcElementCharset,
316     FcElementName,
317     FcElementConst,
318     FcElementOr,
319     FcElementAnd,
320     FcElementEq,
321     FcElementNotEq,
322     FcElementLess,
323     FcElementLessEq,
324     FcElementMore,
325     FcElementMoreEq,
326     FcElementContains,
327     FcElementNotContains,
328     FcElementPlus,
329     FcElementMinus,
330     FcElementTimes,
331     FcElementDivide,
332     FcElementNot,
333     FcElementIf,
334     FcElementFloor,
335     FcElementCeil,
336     FcElementRound,
337     FcElementTrunc,
338     FcElementUnknown
339 } FcElement;
340
341 static struct {
342     const char  name[16];
343     FcElement   element;
344 } fcElementMap[] = {
345     { "fontconfig",     FcElementFontconfig },
346     { "dir",            FcElementDir },
347     { "cache",          FcElementCache },
348     { "include",        FcElementInclude },
349     { "config",         FcElementConfig },
350     { "match",          FcElementMatch },
351     { "alias",          FcElementAlias },
352     
353     { "blank",          FcElementBlank },
354     { "rescan",         FcElementRescan },
355
356     { "prefer",         FcElementPrefer },
357     { "accept",         FcElementAccept },
358     { "default",        FcElementDefault },
359     { "family",         FcElementFamily },
360
361     { "selectfont",     FcElementSelectfont },
362     { "acceptfont",     FcElementAcceptfont },
363     { "rejectfont",     FcElementRejectfont },
364     { "glob",           FcElementGlob },
365     { "pattern",        FcElementPattern },
366     { "patelt",         FcElementPatelt },
367
368     { "test",           FcElementTest },
369     { "edit",           FcElementEdit },
370     { "int",            FcElementInt },
371     { "double",         FcElementDouble },
372     { "string",         FcElementString },
373     { "matrix",         FcElementMatrix },
374     { "bool",           FcElementBool },
375     { "charset",        FcElementCharset },
376     { "name",           FcElementName },
377     { "const",          FcElementConst },
378     { "or",             FcElementOr },
379     { "and",            FcElementAnd },
380     { "eq",             FcElementEq },
381     { "not_eq",         FcElementNotEq },
382     { "less",           FcElementLess },
383     { "less_eq",        FcElementLessEq },
384     { "more",           FcElementMore },
385     { "more_eq",        FcElementMoreEq },
386     { "contains",       FcElementContains },
387     { "not_contains",   FcElementNotContains },
388     { "plus",           FcElementPlus },
389     { "minus",          FcElementMinus },
390     { "times",          FcElementTimes },
391     { "divide",         FcElementDivide },
392     { "not",            FcElementNot },
393     { "if",             FcElementIf },
394     { "floor",          FcElementFloor },
395     { "ceil",           FcElementCeil },
396     { "round",          FcElementRound },
397     { "trunc",          FcElementTrunc },
398 };
399 #define NUM_ELEMENT_MAPS (int) (sizeof fcElementMap / sizeof fcElementMap[0])
400
401 static FcElement
402 FcElementMap (const XML_Char *name)
403 {
404
405     int     i;
406     for (i = 0; i < NUM_ELEMENT_MAPS; i++)
407         if (!strcmp ((char *) name, fcElementMap[i].name))
408             return fcElementMap[i].element;
409     return FcElementUnknown;
410 }
411
412 typedef struct _FcPStack {
413     struct _FcPStack   *prev;
414     FcElement           element;
415     FcChar8             **attr;
416     FcStrBuf            str;
417 } FcPStack;
418     
419 typedef enum _FcVStackTag {
420     FcVStackNone,
421
422     FcVStackString,
423     FcVStackFamily,
424     FcVStackField,
425     FcVStackConstant,
426     FcVStackGlob,
427     FcVStackPattern,
428     
429     FcVStackPrefer,
430     FcVStackAccept,
431     FcVStackDefault,
432     
433     FcVStackInteger,
434     FcVStackDouble,
435     FcVStackMatrix,
436     FcVStackBool,
437     
438     FcVStackTest,
439     FcVStackExpr,
440     FcVStackEdit
441 } FcVStackTag;
442
443 typedef struct _FcVStack {
444     struct _FcVStack    *prev;
445     FcPStack            *pstack;        /* related parse element */
446     FcVStackTag         tag;
447     union {
448         FcChar8         *string;
449
450         int             integer;
451         double          _double;
452         FcMatrix        *matrix;
453         FcBool          bool;
454
455         FcTest          *test;
456         FcQual          qual;
457         FcOp            op;
458         FcExpr          *expr;
459         FcEdit          *edit;
460
461         FcPattern       *pattern;
462     } u;
463 } FcVStack;
464
465 typedef struct _FcConfigParse {
466     FcPStack        *pstack;
467     FcVStack        *vstack;
468     FcBool          error;
469     const FcChar8   *name;
470     FcConfig        *config;
471     XML_Parser      parser;
472 } FcConfigParse;
473
474 typedef enum _FcConfigSeverity {
475     FcSevereInfo, FcSevereWarning, FcSevereError
476 } FcConfigSeverity;
477
478 static void
479 FcConfigMessage (FcConfigParse *parse, FcConfigSeverity severe, const char *fmt, ...)
480 {
481     const char  *s = "unknown";
482     va_list     args;
483
484     va_start (args, fmt);
485
486     switch (severe) {
487     case FcSevereInfo: s = "info"; break;
488     case FcSevereWarning: s = "warning"; break;
489     case FcSevereError: s = "error"; break;
490     }
491     if (parse)
492     {
493         if (parse->name)
494             fprintf (stderr, "Fontconfig %s: \"%s\", line %d: ", s,
495                      parse->name, XML_GetCurrentLineNumber (parse->parser));
496         else
497             fprintf (stderr, "Fontconfig %s: line %d: ", s,
498                      XML_GetCurrentLineNumber (parse->parser));
499         if (severe >= FcSevereError)
500             parse->error = FcTrue;
501     }
502     else
503         fprintf (stderr, "Fontconfig %s: ", s);
504     vfprintf (stderr, fmt, args);
505     fprintf (stderr, "\n");
506     va_end (args);
507 }
508
509
510 static const char *
511 FcTypeName (FcType type)
512 {
513     switch (type) {
514     case FcTypeVoid:
515         return "void";
516     case FcTypeInteger:
517     case FcTypeDouble:
518         return "number";
519     case FcTypeString:
520         return "string";
521     case FcTypeBool:
522         return "bool";
523     case FcTypeMatrix:
524         return "matrix";
525     case FcTypeCharSet:
526         return "charset";
527     case FcTypeFTFace:
528         return "FT_Face";
529     case FcTypeLangSet:
530         return "langset";
531     default:
532         return "unknown";
533     }
534 }
535
536 static void
537 FcTypecheckValue (FcConfigParse *parse, FcType value, FcType type)
538 {
539     if (value == FcTypeInteger)
540         value = FcTypeDouble;
541     if (type == FcTypeInteger)
542         type = FcTypeDouble;
543     if (value != type)
544     {
545         if ((value == FcTypeLangSet && type == FcTypeString) ||
546             (value == FcTypeString && type == FcTypeLangSet))
547             return;
548         FcConfigMessage (parse, FcSevereWarning, "saw %s, expected %s",
549                          FcTypeName (value), FcTypeName (type));
550     }
551 }
552
553 static void
554 FcTypecheckExpr (FcConfigParse *parse, FcExpr *expr, FcType type)
555 {
556     const FcObjectType  *o;
557     const FcConstant    *c;
558     
559     switch (expr->op) {
560     case FcOpInteger:
561     case FcOpDouble:
562         FcTypecheckValue (parse, FcTypeDouble, type);
563         break;
564     case FcOpString:
565         FcTypecheckValue (parse, FcTypeString, type);
566         break;
567     case FcOpMatrix:
568         FcTypecheckValue (parse, FcTypeMatrix, type);
569         break;
570     case FcOpBool:
571         FcTypecheckValue (parse, FcTypeBool, type);
572         break;
573     case FcOpCharSet:
574         FcTypecheckValue (parse, FcTypeCharSet, type);
575         break;
576     case FcOpNil:
577         break;
578     case FcOpField:
579         o = FcNameGetObjectType (expr->u.field);
580         if (o)
581             FcTypecheckValue (parse, o->type, type);
582         break;
583     case FcOpConst:
584         c = FcNameGetConstant (expr->u.constant);
585         if (c)
586         {
587             o = FcNameGetObjectType (c->object);
588             if (o)
589                 FcTypecheckValue (parse, o->type, type);
590         }
591         break;
592     case FcOpQuest:
593         FcTypecheckExpr (parse, expr->u.tree.left, FcTypeBool);
594         FcTypecheckExpr (parse, expr->u.tree.right->u.tree.left, type);
595         FcTypecheckExpr (parse, expr->u.tree.right->u.tree.right, type);
596         break;
597     case FcOpAssign:
598     case FcOpAssignReplace:
599         break;
600     case FcOpEqual:
601     case FcOpNotEqual:
602     case FcOpLess:
603     case FcOpLessEqual:
604     case FcOpMore:
605     case FcOpMoreEqual:
606     case FcOpContains:
607     case FcOpNotContains:
608     case FcOpListing:
609         FcTypecheckValue (parse, FcTypeBool, type);
610         break;
611     case FcOpComma:
612     case FcOpOr:
613     case FcOpAnd:
614     case FcOpPlus:
615     case FcOpMinus:
616     case FcOpTimes:
617     case FcOpDivide:
618         FcTypecheckExpr (parse, expr->u.tree.left, type);
619         FcTypecheckExpr (parse, expr->u.tree.right, type);
620         break;
621     case FcOpNot:
622         FcTypecheckValue (parse, FcTypeBool, type);
623         FcTypecheckExpr (parse, expr->u.tree.left, FcTypeBool);
624         break;
625     case FcOpFloor:
626     case FcOpCeil:
627     case FcOpRound:
628     case FcOpTrunc:
629         FcTypecheckValue (parse, FcTypeDouble, type);
630         FcTypecheckExpr (parse, expr->u.tree.left, FcTypeDouble);
631         break;
632     default:
633         break;
634     }
635 }
636
637 static FcTest *
638 FcTestCreate (FcConfigParse *parse,
639               FcMatchKind   kind, 
640               FcQual        qual,
641               const FcChar8 *field,
642               FcOp          compare,
643               FcExpr        *expr)
644 {
645     FcTest      *test = (FcTest *) malloc (sizeof (FcTest));
646
647     if (test)
648     {
649         const FcObjectType      *o;
650         
651         FcMemAlloc (FC_MEM_TEST, sizeof (FcTest));
652         test->next = 0;
653         test->kind = kind;
654         test->qual = qual;
655         test->field = (char *) FcStrCopy (field);
656         test->op = compare;
657         test->expr = expr;
658         o = FcNameGetObjectType (test->field);
659         if (o)
660             FcTypecheckExpr (parse, expr, o->type);
661     }
662     return test;
663 }
664
665 static FcEdit *
666 FcEditCreate (FcConfigParse     *parse,
667               const char        *field,
668               FcOp              op,
669               FcExpr            *expr,
670               FcValueBinding    binding)
671 {
672     FcEdit *e = (FcEdit *) malloc (sizeof (FcEdit));
673
674     if (e)
675     {
676         const FcObjectType      *o;
677
678         e->next = 0;
679         e->field = field;   /* already saved in grammar */
680         e->op = op;
681         e->expr = expr;
682         e->binding = binding;
683         o = FcNameGetObjectType (e->field);
684         if (o)
685             FcTypecheckExpr (parse, expr, o->type);
686     }
687     return e;
688 }
689
690 static void
691 FcVStackPush (FcConfigParse *parse, FcVStack *vstack)
692 {
693     vstack->prev = parse->vstack;
694     vstack->pstack = parse->pstack ? parse->pstack->prev : 0;
695     parse->vstack = vstack;
696 }
697
698 static FcVStack *
699 FcVStackCreate (void)
700 {
701     FcVStack    *new;
702
703     new = malloc (sizeof (FcVStack));
704     if (!new)
705         return 0;
706     FcMemAlloc (FC_MEM_VSTACK, sizeof (FcVStack));
707     new->tag = FcVStackNone;
708     new->prev = 0;
709     return new;
710 }
711
712 static void
713 FcVStackDestroy (FcVStack *vstack)
714 {
715     FcVStack    *prev;
716
717     for (; vstack; vstack = prev)
718     {
719         prev = vstack->prev;
720         switch (vstack->tag) {
721         case FcVStackNone:
722             break;
723         case FcVStackString:
724         case FcVStackFamily:
725         case FcVStackField:
726         case FcVStackConstant:
727         case FcVStackGlob:
728             FcStrFree (vstack->u.string);
729             break;
730         case FcVStackPattern:
731             FcPatternDestroy (vstack->u.pattern);
732             break;
733         case FcVStackInteger:
734         case FcVStackDouble:
735             break;
736         case FcVStackMatrix:
737             FcMatrixFree (vstack->u.matrix);
738             break;
739         case FcVStackBool:
740             break;
741         case FcVStackTest:
742             FcTestDestroy (vstack->u.test);
743             break;
744         case FcVStackExpr:
745         case FcVStackPrefer:
746         case FcVStackAccept:
747         case FcVStackDefault:
748             FcExprDestroy (vstack->u.expr);
749             break;
750         case FcVStackEdit:
751             FcEditDestroy (vstack->u.edit);
752             break;
753         }
754         FcMemFree (FC_MEM_VSTACK, sizeof (FcVStack));
755         free (vstack);
756     }
757 }
758
759 static FcBool
760 FcVStackPushString (FcConfigParse *parse, FcVStackTag tag, FcChar8 *string)
761 {
762     FcVStack    *vstack = FcVStackCreate ();
763     if (!vstack)
764         return FcFalse;
765     vstack->u.string = string;
766     vstack->tag = tag;
767     FcVStackPush (parse, vstack);
768     return FcTrue;
769 }
770
771 static FcBool
772 FcVStackPushInteger (FcConfigParse *parse, int integer)
773 {
774     FcVStack    *vstack = FcVStackCreate ();
775     if (!vstack)
776         return FcFalse;
777     vstack->u.integer = integer;
778     vstack->tag = FcVStackInteger;
779     FcVStackPush (parse, vstack);
780     return FcTrue;
781 }
782
783 static FcBool
784 FcVStackPushDouble (FcConfigParse *parse, double _double)
785 {
786     FcVStack    *vstack = FcVStackCreate ();
787     if (!vstack)
788         return FcFalse;
789     vstack->u._double = _double;
790     vstack->tag = FcVStackDouble;
791     FcVStackPush (parse, vstack);
792     return FcTrue;
793 }
794
795 static FcBool
796 FcVStackPushMatrix (FcConfigParse *parse, FcMatrix *matrix)
797 {
798     FcVStack    *vstack = FcVStackCreate ();
799     if (!vstack)
800         return FcFalse;
801     matrix = FcMatrixCopy (matrix);
802     if (!matrix)
803     {
804         FcVStackDestroy (vstack);
805         return FcFalse;
806     }
807     vstack->u.matrix = matrix;
808     vstack->tag = FcVStackMatrix;
809     FcVStackPush (parse, vstack);
810     return FcTrue;
811 }
812
813 static FcBool
814 FcVStackPushBool (FcConfigParse *parse, FcBool bool)
815 {
816     FcVStack    *vstack = FcVStackCreate ();
817     if (!vstack)
818         return FcFalse;
819     vstack->u.bool = bool;
820     vstack->tag = FcVStackBool;
821     FcVStackPush (parse, vstack);
822     return FcTrue;
823 }
824
825 static FcBool
826 FcVStackPushTest (FcConfigParse *parse, FcTest *test)
827 {
828     FcVStack    *vstack = FcVStackCreate ();
829     if (!vstack)
830         return FcFalse;
831     vstack->u.test = test;
832     vstack->tag = FcVStackTest;
833     FcVStackPush (parse, vstack);
834     return FcTrue;
835 }
836
837 static FcBool
838 FcVStackPushExpr (FcConfigParse *parse, FcVStackTag tag, FcExpr *expr)
839 {
840     FcVStack    *vstack = FcVStackCreate ();
841     if (!vstack)
842         return FcFalse;
843     vstack->u.expr = expr;
844     vstack->tag = tag;
845     FcVStackPush (parse, vstack);
846     return FcTrue;
847 }
848
849 static FcBool
850 FcVStackPushEdit (FcConfigParse *parse, FcEdit *edit)
851 {
852     FcVStack    *vstack = FcVStackCreate ();
853     if (!vstack)
854         return FcFalse;
855     vstack->u.edit = edit;
856     vstack->tag = FcVStackEdit;
857     FcVStackPush (parse, vstack);
858     return FcTrue;
859 }
860
861 static FcBool
862 FcVStackPushPattern (FcConfigParse *parse, FcPattern *pattern)
863 {
864     FcVStack    *vstack = FcVStackCreate ();
865     if (!vstack)
866         return FcFalse;
867     vstack->u.pattern = pattern;
868     vstack->tag = FcVStackPattern;
869     FcVStackPush (parse, vstack);
870     return FcTrue;
871 }
872
873 static FcVStack *
874 FcVStackFetch (FcConfigParse *parse, int off)
875 {
876     FcVStack    *vstack;
877
878     for (vstack = parse->vstack; vstack && off-- > 0; vstack = vstack->prev);
879     return vstack;
880 }
881
882 static void
883 FcVStackClear (FcConfigParse *parse)
884 {
885     while (parse->vstack && parse->vstack->pstack == parse->pstack)
886     {
887         FcVStack    *vstack = parse->vstack;
888         parse->vstack = vstack->prev;
889         vstack->prev = 0;
890         FcVStackDestroy (vstack);
891     }
892 }
893
894 static FcVStack *
895 FcVStackPop (FcConfigParse *parse)
896 {
897     FcVStack    *vstack = parse->vstack;
898     
899     if (!vstack || vstack->pstack != parse->pstack)
900         return 0;
901     parse->vstack = vstack->prev;
902     vstack->prev = 0;
903     return vstack;
904 }
905
906 static int
907 FcVStackElements (FcConfigParse *parse)
908 {
909     int         h = 0;
910     FcVStack    *vstack = parse->vstack;
911     while (vstack && vstack->pstack == parse->pstack)
912     {
913         h++;
914         vstack = vstack->prev;
915     }
916     return h;
917 }
918
919 static FcChar8 **
920 FcConfigSaveAttr (const XML_Char **attr)
921 {
922     int         n;
923     int         slen;
924     int         i;
925     FcChar8     **new;
926     FcChar8     *s;
927
928     if (!attr)
929         return 0;
930     slen = 0;
931     for (i = 0; attr[i]; i++)
932         slen += strlen (attr[i]) + 1;
933     n = i;
934     new = malloc ((i + 1) * sizeof (FcChar8 *) + slen);
935     if (!new)
936         return 0;
937     FcMemAlloc (FC_MEM_ATTR, 1);    /* size is too expensive */
938     s = (FcChar8 *) (new + (i + 1));
939     for (i = 0; attr[i]; i++)
940     {
941         new[i] = s;
942         strcpy ((char *) s, (char *) attr[i]);
943         s += strlen ((char *) s) + 1;
944     }
945     new[i] = 0;
946     return new;
947 }
948
949 static FcBool
950 FcPStackPush (FcConfigParse *parse, FcElement element, const XML_Char **attr)
951 {
952     FcPStack   *new = malloc (sizeof (FcPStack));
953
954     if (!new)
955         return FcFalse;
956     FcMemAlloc (FC_MEM_PSTACK, sizeof (FcPStack));
957     new->prev = parse->pstack;
958     new->element = element;
959     if (attr)
960     {
961         new->attr = FcConfigSaveAttr (attr);
962         if (!new->attr)
963             FcConfigMessage (parse, FcSevereError, "out of memory");
964     }
965     else
966         new->attr = 0;
967     FcStrBufInit (&new->str, 0, 0);
968     parse->pstack = new;
969     return FcTrue;
970 }
971
972 static FcBool
973 FcPStackPop (FcConfigParse *parse)
974 {
975     FcPStack   *old;
976     
977     if (!parse->pstack) 
978     {
979         FcConfigMessage (parse, FcSevereError, "mismatching element");
980         return FcFalse;
981     }
982     FcVStackClear (parse);
983     old = parse->pstack;
984     parse->pstack = old->prev;
985     FcStrBufDestroy (&old->str);
986     if (old->attr)
987     {
988         FcMemFree (FC_MEM_ATTR, 1); /* size is to expensive */
989         free (old->attr);
990     }
991     FcMemFree (FC_MEM_PSTACK, sizeof (FcPStack));
992     free (old);
993     return FcTrue;
994 }
995
996 static FcBool
997 FcConfigInit (FcConfigParse *parse, const FcChar8 *name, FcConfig *config, XML_Parser parser)
998 {
999     parse->pstack = 0;
1000     parse->vstack = 0;
1001     parse->error = FcFalse;
1002     parse->name = name;
1003     parse->config = config;
1004     parse->parser = parser;
1005     return FcTrue;
1006 }
1007
1008 static void
1009 FcConfigCleanup (FcConfigParse  *parse)
1010 {
1011     while (parse->pstack)
1012         FcPStackPop (parse);
1013 }
1014
1015 static const FcChar8 *
1016 FcConfigGetAttribute (FcConfigParse *parse, const char *attr)
1017 {
1018     FcChar8 **attrs;
1019     if (!parse->pstack)
1020         return 0;
1021
1022     attrs = parse->pstack->attr;
1023     while (*attrs)
1024     {
1025         if (!strcmp ((char *) *attrs, attr))
1026             return attrs[1];
1027         attrs += 2;
1028     }
1029     return 0;
1030 }
1031
1032 static void
1033 FcStartElement(void *userData, const XML_Char *name, const XML_Char **attr)
1034 {
1035     FcConfigParse   *parse = userData;
1036     FcElement       element;
1037     
1038     element = FcElementMap (name);
1039     if (element == FcElementUnknown)
1040         FcConfigMessage (parse, FcSevereWarning, "unknown element \"%s\"", name);
1041     
1042     if (!FcPStackPush (parse, element, attr))
1043     {
1044         FcConfigMessage (parse, FcSevereError, "out of memory");
1045         return;
1046     }
1047     return;
1048 }
1049
1050 static void
1051 FcParseBlank (FcConfigParse *parse)
1052 {
1053     int     n = FcVStackElements (parse);
1054     while (n-- > 0)
1055     {
1056         FcVStack    *v = FcVStackFetch (parse, n);
1057         if (v->tag != FcVStackInteger)
1058             FcConfigMessage (parse, FcSevereError, "non-integer blank");
1059         else
1060         {
1061             if (!parse->config->blanks)
1062             {
1063                 parse->config->blanks = FcBlanksCreate ();
1064                 if (!parse->config->blanks)
1065                 {
1066                     FcConfigMessage (parse, FcSevereError, "out of memory");
1067                     break;
1068                 }
1069             }
1070             if (!FcBlanksAdd (parse->config->blanks, v->u.integer))
1071             {
1072                 FcConfigMessage (parse, FcSevereError, "out of memory");
1073                 break;
1074             }
1075         }
1076     }
1077 }
1078
1079 static void
1080 FcParseRescan (FcConfigParse *parse)
1081 {
1082     int     n = FcVStackElements (parse);
1083     while (n-- > 0)
1084     {
1085         FcVStack    *v = FcVStackFetch (parse, n);
1086         if (v->tag != FcVStackInteger)
1087             FcConfigMessage (parse, FcSevereWarning, "non-integer rescan");
1088         else
1089             parse->config->rescanInterval = v->u.integer;
1090     }
1091 }
1092
1093 static void
1094 FcParseInt (FcConfigParse *parse)
1095 {
1096     FcChar8 *s, *end;
1097     int     l;
1098     
1099     if (!parse->pstack)
1100         return;
1101     s = FcStrBufDone (&parse->pstack->str);
1102     if (!s)
1103     {
1104         FcConfigMessage (parse, FcSevereError, "out of memory");
1105         return;
1106     }
1107     end = 0;
1108     l = (int) strtol ((char *) s, (char **)&end, 0);
1109     if (end != s + strlen ((char *) s))
1110         FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid integer", s);
1111     else
1112         FcVStackPushInteger (parse, l);
1113     FcStrFree (s);
1114 }
1115
1116 /*
1117  * idea copied from glib g_ascii_strtod with 
1118  * permission of the author (Alexander Larsson) 
1119  */
1120
1121 #include <locale.h>
1122
1123 static double 
1124 FcStrtod (char *s, char **end)
1125 {
1126     struct lconv    *locale_data;
1127     char            *dot;
1128     double          v;
1129
1130     /*
1131      * Have to swap the decimal point to match the current locale
1132      * if that locale doesn't use 0x2e
1133      */
1134     if ((dot = strchr (s, 0x2e)) &&
1135         (locale_data = localeconv ()) &&
1136         (locale_data->decimal_point[0] != 0x2e ||
1137          locale_data->decimal_point[1] != 0))
1138     {
1139         char    buf[128];
1140         int     slen = strlen (s);
1141         int     dlen = strlen (locale_data->decimal_point);
1142         
1143         if (slen + dlen > (int) sizeof (buf))
1144         {
1145             if (end)
1146                 *end = s;
1147             v = 0;
1148         }
1149         else
1150         {
1151             char        *buf_end;
1152             /* mantissa */
1153             strncpy (buf, s, dot - s);
1154             /* decimal point */
1155             strcpy (buf + (dot - s), locale_data->decimal_point);
1156             /* rest of number */
1157             strcpy (buf + (dot - s) + dlen, dot + 1);
1158             buf_end = 0;
1159             v = strtod (buf, &buf_end);
1160             if (buf_end) {
1161                 buf_end = s + (buf_end - buf);
1162                 if (buf_end > dot)
1163                     buf_end -= dlen - 1;
1164             }
1165             if (end)
1166                 *end = buf_end;
1167         }
1168     }
1169     else
1170         v = strtod (s, end);
1171     return v;
1172 }
1173
1174 static void
1175 FcParseDouble (FcConfigParse *parse)
1176 {
1177     FcChar8 *s, *end;
1178     double  d;
1179     
1180     if (!parse->pstack)
1181         return;
1182     s = FcStrBufDone (&parse->pstack->str);
1183     if (!s)
1184     {
1185         FcConfigMessage (parse, FcSevereError, "out of memory");
1186         return;
1187     }
1188     end = 0;
1189     d = FcStrtod ((char *) s, (char **)&end);
1190     if (end != s + strlen ((char *) s))
1191         FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid double", s);
1192     else
1193         FcVStackPushDouble (parse, d);
1194     FcStrFree (s);
1195 }
1196
1197 static void
1198 FcParseString (FcConfigParse *parse, FcVStackTag tag)
1199 {
1200     FcChar8 *s;
1201     
1202     if (!parse->pstack)
1203         return;
1204     s = FcStrBufDone (&parse->pstack->str);
1205     if (!s)
1206     {
1207         FcConfigMessage (parse, FcSevereError, "out of memory");
1208         return;
1209     }
1210     if (!FcVStackPushString (parse, tag, s))
1211         FcStrFree (s);
1212 }
1213
1214 static void
1215 FcParseMatrix (FcConfigParse *parse)
1216 {
1217     FcVStack    *vstack;
1218     enum { m_done, m_xx, m_xy, m_yx, m_yy } matrix_state = m_yy;
1219     FcMatrix    m;
1220     
1221     while ((vstack = FcVStackPop (parse)))
1222     {
1223         double  v;
1224         switch (vstack->tag) {
1225         case FcVStackInteger:
1226             v = vstack->u.integer;
1227             break;
1228         case FcVStackDouble:
1229             v = vstack->u._double;
1230             break;
1231         default:
1232             FcConfigMessage (parse, FcSevereError, "non-double matrix element");
1233             v = 1.0;
1234             break;
1235         }
1236         switch (matrix_state) {
1237         case m_xx: m.xx = v; break;
1238         case m_xy: m.xy = v; break;
1239         case m_yx: m.yx = v; break;
1240         case m_yy: m.yy = v; break;
1241         default: break;
1242         }
1243         FcVStackDestroy (vstack);
1244         matrix_state--;
1245     }
1246     if (matrix_state != m_done)
1247         FcConfigMessage (parse, FcSevereError, "wrong number of matrix elements");
1248     else
1249         FcVStackPushMatrix (parse, &m);
1250 }
1251
1252 static FcBool
1253 FcConfigLexBool (FcConfigParse *parse, const FcChar8 *bool)
1254 {
1255     FcBool  result = FcFalse;
1256
1257     if (!FcNameBool (bool, &result))
1258         FcConfigMessage (parse, FcSevereWarning, "\"%s\" is not known boolean",
1259                          bool);
1260     return result;
1261 }
1262
1263 static void
1264 FcParseBool (FcConfigParse *parse)
1265 {
1266     FcChar8 *s;
1267
1268     if (!parse->pstack)
1269         return;
1270     s = FcStrBufDone (&parse->pstack->str);
1271     if (!s)
1272     {
1273         FcConfigMessage (parse, FcSevereError, "out of memory");
1274         return;
1275     }
1276     FcVStackPushBool (parse, FcConfigLexBool (parse, s));
1277     FcStrFree (s);
1278 }
1279
1280 static void
1281 FcParseFamilies (FcConfigParse *parse, FcVStackTag tag)
1282 {
1283     FcVStack    *vstack;
1284     FcExpr      *left, *expr = 0, *new;
1285
1286     while ((vstack = FcVStackPop (parse)))
1287     {
1288         if (vstack->tag != FcVStackFamily)
1289         {
1290             FcConfigMessage (parse, FcSevereWarning, "non-family");
1291             FcVStackDestroy (vstack);
1292             continue;
1293         }
1294         left = vstack->u.expr;
1295         vstack->tag = FcVStackNone;
1296         FcVStackDestroy (vstack);
1297         if (expr)
1298         {
1299             new = FcExprCreateOp (left, FcOpComma, expr);
1300             if (!new)
1301             {
1302                 FcConfigMessage (parse, FcSevereError, "out of memory");
1303                 FcExprDestroy (left);
1304                 FcExprDestroy (expr);
1305                 break;
1306             }
1307             expr = new;
1308         }
1309         else
1310             expr = left;
1311     }
1312     if (expr)
1313     {
1314         if (!FcVStackPushExpr (parse, tag, expr))
1315         {
1316             FcConfigMessage (parse, FcSevereError, "out of memory");
1317             if (expr)
1318                 FcExprDestroy (expr);
1319         }
1320     }
1321 }
1322
1323 static void
1324 FcParseFamily (FcConfigParse *parse)
1325 {
1326     FcChar8 *s;
1327     FcExpr  *expr;
1328
1329     if (!parse->pstack)
1330         return;
1331     s = FcStrBufDone (&parse->pstack->str);
1332     if (!s)
1333     {
1334         FcConfigMessage (parse, FcSevereError, "out of memory");
1335         return;
1336     }
1337     expr = FcExprCreateString (s);
1338     FcStrFree (s);
1339     if (expr)
1340         FcVStackPushExpr (parse, FcVStackFamily, expr);
1341 }
1342
1343 static void
1344 FcParseAlias (FcConfigParse *parse)
1345 {
1346     FcExpr      *family = 0, *accept = 0, *prefer = 0, *def = 0, *new = 0;
1347     FcEdit      *edit = 0, *next;
1348     FcVStack    *vstack;
1349     FcTest      *test;
1350
1351     while ((vstack = FcVStackPop (parse))) 
1352     {
1353         switch (vstack->tag) {
1354         case FcVStackFamily:
1355             if (family)
1356             {
1357                 new = FcExprCreateOp (vstack->u.expr, FcOpComma, family);
1358                 if (!new)
1359                     FcConfigMessage (parse, FcSevereError, "out of memory");
1360                 else
1361                     family = new;
1362             }
1363             else
1364                 new = vstack->u.expr;
1365             if (new)
1366             {
1367                 family = new;
1368                 vstack->tag = FcVStackNone;
1369             }
1370             break;
1371         case FcVStackPrefer:
1372             if (prefer)
1373                 FcExprDestroy (prefer);
1374             prefer = vstack->u.expr;
1375             vstack->tag = FcVStackNone;
1376             break;
1377         case FcVStackAccept:
1378             if (accept)
1379                 FcExprDestroy (accept);
1380             accept = vstack->u.expr;
1381             vstack->tag = FcVStackNone;
1382             break;
1383         case FcVStackDefault:
1384             if (def)
1385                 FcExprDestroy (def);
1386             def = vstack->u.expr;
1387             vstack->tag = FcVStackNone;
1388             break;
1389         default:
1390             FcConfigMessage (parse, FcSevereWarning, "bad alias");
1391             break;
1392         }
1393         FcVStackDestroy (vstack);
1394     }
1395     if (!family)
1396     {
1397         FcConfigMessage (parse, FcSevereError, "missing family in alias");
1398         if (prefer)
1399             FcExprDestroy (prefer);
1400         if (accept)
1401             FcExprDestroy (accept);
1402         if (def)
1403             FcExprDestroy (def);
1404         return;
1405     }
1406     if (prefer)
1407     {
1408         edit = FcEditCreate (parse, 
1409                              FcConfigSaveField ("family"),
1410                              FcOpPrepend,
1411                              prefer,
1412                              FcValueBindingWeak);
1413         if (edit)
1414             edit->next = 0;
1415         else
1416             FcExprDestroy (prefer);
1417     }
1418     if (accept)
1419     {
1420         next = edit;
1421         edit = FcEditCreate (parse,
1422                              FcConfigSaveField ("family"),
1423                              FcOpAppend,
1424                              accept,
1425                              FcValueBindingWeak);
1426         if (edit)
1427             edit->next = next;
1428         else
1429             FcExprDestroy (accept);
1430     }
1431     if (def)
1432     {
1433         next = edit;
1434         edit = FcEditCreate (parse,
1435                              FcConfigSaveField ("family"),
1436                              FcOpAppendLast,
1437                              def,
1438                              FcValueBindingWeak);
1439         if (edit)
1440             edit->next = next;
1441         else
1442             FcExprDestroy (def);
1443     }
1444     if (edit)
1445     {
1446         test = FcTestCreate (parse, FcMatchPattern,
1447                              FcQualAny,
1448                              (FcChar8 *) FC_FAMILY,
1449                              FcOpEqual,
1450                              family);
1451         if (test)
1452             if (!FcConfigAddEdit (parse->config, test, edit, FcMatchPattern))
1453                 FcTestDestroy (test);
1454     }
1455     else
1456         FcExprDestroy (family);
1457 }
1458
1459 static FcExpr *
1460 FcPopExpr (FcConfigParse *parse)
1461 {
1462     FcVStack    *vstack = FcVStackPop (parse);
1463     FcExpr      *expr = 0;
1464     if (!vstack)
1465         return 0;
1466     switch (vstack->tag) {
1467     case FcVStackNone:
1468         break;
1469     case FcVStackString:
1470     case FcVStackFamily:
1471         expr = FcExprCreateString (vstack->u.string);
1472         break;
1473     case FcVStackField:
1474         expr = FcExprCreateField ((char *) vstack->u.string);
1475         break;
1476     case FcVStackConstant:
1477         expr = FcExprCreateConst (vstack->u.string);
1478         break;
1479     case FcVStackGlob:
1480         /* XXX: What's the correct action here? (CDW) */
1481         break;
1482     case FcVStackPrefer:
1483     case FcVStackAccept:
1484     case FcVStackDefault:
1485         expr = vstack->u.expr;
1486         vstack->tag = FcVStackNone;
1487         break;
1488     case FcVStackInteger:
1489         expr = FcExprCreateInteger (vstack->u.integer);
1490         break;
1491     case FcVStackDouble:
1492         expr = FcExprCreateDouble (vstack->u._double);
1493         break;
1494     case FcVStackMatrix:
1495         expr = FcExprCreateMatrix (vstack->u.matrix);
1496         break;
1497     case FcVStackBool:
1498         expr = FcExprCreateBool (vstack->u.bool);
1499         break;
1500     case FcVStackTest:
1501         break;
1502     case FcVStackExpr:
1503         expr = vstack->u.expr;
1504         vstack->tag = FcVStackNone;
1505         break;
1506     case FcVStackEdit:
1507         break;
1508     default:
1509         break;
1510     }
1511     FcVStackDestroy (vstack);
1512     return expr;
1513 }
1514
1515 /*
1516  * This builds a tree of binary operations.  Note
1517  * that every operator is defined so that if only
1518  * a single operand is contained, the value of the
1519  * whole expression is the value of the operand.
1520  *
1521  * This code reduces in that case to returning that
1522  * operand.
1523  */
1524 static FcExpr *
1525 FcPopBinary (FcConfigParse *parse, FcOp op)
1526 {
1527     FcExpr  *left, *expr = 0, *new;
1528
1529     while ((left = FcPopExpr (parse)))
1530     {
1531         if (expr)
1532         {
1533             new = FcExprCreateOp (left, op, expr);
1534             if (!new)
1535             {
1536                 FcConfigMessage (parse, FcSevereError, "out of memory");
1537                 FcExprDestroy (left);
1538                 FcExprDestroy (expr);
1539                 break;
1540             }
1541             expr = new;
1542         }
1543         else
1544             expr = left;
1545     }
1546     return expr;
1547 }
1548
1549 static void
1550 FcParseBinary (FcConfigParse *parse, FcOp op)
1551 {
1552     FcExpr  *expr = FcPopBinary (parse, op);
1553     if (expr)
1554         FcVStackPushExpr (parse, FcVStackExpr, expr);
1555 }
1556
1557 /*
1558  * This builds a a unary operator, it consumes only
1559  * a single operand
1560  */
1561
1562 static FcExpr *
1563 FcPopUnary (FcConfigParse *parse, FcOp op)
1564 {
1565     FcExpr  *operand, *new = 0;
1566
1567     if ((operand = FcPopExpr (parse)))
1568     {
1569         new = FcExprCreateOp (operand, op, 0);
1570         if (!new)
1571         {
1572             FcExprDestroy (operand);
1573             FcConfigMessage (parse, FcSevereError, "out of memory");
1574         }
1575     }
1576     return new;
1577 }
1578
1579 static void
1580 FcParseUnary (FcConfigParse *parse, FcOp op)
1581 {
1582     FcExpr  *expr = FcPopUnary (parse, op);
1583     if (expr)
1584         FcVStackPushExpr (parse, FcVStackExpr, expr);
1585 }
1586
1587 static void
1588 FcParseInclude (FcConfigParse *parse)
1589 {
1590     FcChar8         *s;
1591     const FcChar8   *i;
1592     FcBool          ignore_missing = FcFalse;
1593     
1594     s = FcStrBufDone (&parse->pstack->str);
1595     if (!s)
1596     {
1597         FcConfigMessage (parse, FcSevereError, "out of memory");
1598         return;
1599     }
1600     i = FcConfigGetAttribute (parse, "ignore_missing");
1601     if (i && FcConfigLexBool (parse, (FcChar8 *) i) == FcTrue)
1602         ignore_missing = FcTrue;
1603     if (!FcConfigParseAndLoad (parse->config, s, !ignore_missing))
1604         parse->error = FcTrue;
1605     FcStrFree (s);
1606 }
1607
1608 typedef struct _FcOpMap {
1609     char    name[16];
1610     FcOp    op;
1611 } FcOpMap;
1612
1613 static FcOp
1614 FcConfigLexOp (const FcChar8 *op, const FcOpMap *map, int nmap)
1615 {
1616     int i;
1617
1618     for (i = 0; i < nmap; i++)
1619         if (!strcmp ((char *) op, map[i].name)) 
1620             return map[i].op;
1621     return FcOpInvalid;
1622 }
1623
1624 static const FcOpMap fcCompareOps[] = {
1625     { "eq",             FcOpEqual           },
1626     { "not_eq",         FcOpNotEqual        },
1627     { "less",           FcOpLess            },
1628     { "less_eq",        FcOpLessEqual       },
1629     { "more",           FcOpMore            },
1630     { "more_eq",        FcOpMoreEqual       },
1631     { "contains",       FcOpContains        },
1632     { "not_contains",   FcOpNotContains     }
1633 };
1634
1635 #define NUM_COMPARE_OPS (int) (sizeof fcCompareOps / sizeof fcCompareOps[0])
1636
1637 static FcOp
1638 FcConfigLexCompare (const FcChar8 *compare)
1639 {
1640     return FcConfigLexOp (compare, fcCompareOps, NUM_COMPARE_OPS);
1641 }
1642
1643
1644 static void
1645 FcParseTest (FcConfigParse *parse)
1646 {
1647     const FcChar8   *kind_string;
1648     FcMatchKind     kind;
1649     const FcChar8   *qual_string;
1650     FcQual          qual;
1651     const FcChar8   *name;
1652     const FcChar8   *compare_string;
1653     FcOp            compare;
1654     FcExpr          *expr;
1655     FcTest          *test;
1656
1657     kind_string = FcConfigGetAttribute (parse, "target");
1658     if (!kind_string)
1659         kind = FcMatchDefault;
1660     else
1661     {
1662         if (!strcmp ((char *) kind_string, "pattern"))
1663             kind = FcMatchPattern;
1664         else if (!strcmp ((char *) kind_string, "font"))
1665             kind = FcMatchFont;
1666         else if (!strcmp ((char *) kind_string, "default"))
1667             kind = FcMatchDefault;
1668         else
1669         {
1670             FcConfigMessage (parse, FcSevereWarning, "invalid test target \"%s\"", kind_string);
1671             return;
1672         }
1673     }
1674     qual_string = FcConfigGetAttribute (parse, "qual");
1675     if (!qual_string)
1676         qual = FcQualAny;
1677     else
1678     {
1679         if (!strcmp ((char *) qual_string, "any"))
1680             qual = FcQualAny;
1681         else if (!strcmp ((char *) qual_string, "all"))
1682             qual = FcQualAll;
1683         else if (!strcmp ((char *) qual_string, "first"))
1684             qual = FcQualFirst;
1685         else if (!strcmp ((char *) qual_string, "not_first"))
1686             qual = FcQualNotFirst;
1687         else
1688         {
1689             FcConfigMessage (parse, FcSevereWarning, "invalid test qual \"%s\"", qual_string);
1690             return;
1691         }
1692     }
1693     name = FcConfigGetAttribute (parse, "name");
1694     if (!name)
1695     {
1696         FcConfigMessage (parse, FcSevereWarning, "missing test name");
1697         return;
1698     }
1699     compare_string = FcConfigGetAttribute (parse, "compare");
1700     if (!compare_string)
1701         compare = FcOpEqual;
1702     else
1703     {
1704         compare = FcConfigLexCompare (compare_string);
1705         if (compare == FcOpInvalid)
1706         {
1707             FcConfigMessage (parse, FcSevereWarning, "invalid test compare \"%s\"", compare_string);
1708             return;
1709         }
1710     }
1711     expr = FcPopBinary (parse, FcOpComma);
1712     if (!expr)
1713     {
1714         FcConfigMessage (parse, FcSevereWarning, "missing test expression");
1715         return;
1716     }
1717     test = FcTestCreate (parse, kind, qual, name, compare, expr);
1718     if (!test)
1719     {
1720         FcConfigMessage (parse, FcSevereError, "out of memory");
1721         return;
1722     }
1723     FcVStackPushTest (parse, test);
1724 }
1725
1726 static const FcOpMap fcModeOps[] = {
1727     { "assign",         FcOpAssign          },
1728     { "assign_replace", FcOpAssignReplace   },
1729     { "prepend",        FcOpPrepend         },
1730     { "prepend_first",  FcOpPrependFirst    },
1731     { "append",         FcOpAppend          },
1732     { "append_last",    FcOpAppendLast      },
1733 };
1734
1735 #define NUM_MODE_OPS (int) (sizeof fcModeOps / sizeof fcModeOps[0])
1736
1737 static FcOp
1738 FcConfigLexMode (const FcChar8 *mode)
1739 {
1740     return FcConfigLexOp (mode, fcModeOps, NUM_MODE_OPS);
1741 }
1742
1743 static void
1744 FcParseEdit (FcConfigParse *parse)
1745 {
1746     const FcChar8   *name;
1747     const FcChar8   *mode_string;
1748     const FcChar8   *binding_string;
1749     FcOp            mode;
1750     FcValueBinding  binding;
1751     FcExpr          *expr;
1752     FcEdit          *edit;
1753
1754     name = FcConfigGetAttribute (parse, "name");
1755     if (!name)
1756     {
1757         FcConfigMessage (parse, FcSevereWarning, "missing edit name");
1758         return;
1759     }
1760     mode_string = FcConfigGetAttribute (parse, "mode");
1761     if (!mode_string)
1762         mode = FcOpAssign;
1763     else
1764     {
1765         mode = FcConfigLexMode (mode_string);
1766         if (mode == FcOpInvalid)
1767         {
1768             FcConfigMessage (parse, FcSevereWarning, "invalid edit mode \"%s\"", mode_string);
1769             return;
1770         }
1771     }
1772     binding_string = FcConfigGetAttribute (parse, "binding");
1773     if (!binding_string)
1774         binding = FcValueBindingWeak;
1775     else
1776     {
1777         if (!strcmp ((char *) binding_string, "weak"))
1778             binding = FcValueBindingWeak;
1779         else if (!strcmp ((char *) binding_string, "strong"))
1780             binding = FcValueBindingStrong;
1781         else if (!strcmp ((char *) binding_string, "same"))
1782             binding = FcValueBindingSame;
1783         else
1784         {
1785             FcConfigMessage (parse, FcSevereWarning, "invalid edit binding \"%s\"", binding_string);
1786             return;
1787         }
1788     }
1789     expr = FcPopBinary (parse, FcOpComma);
1790     edit = FcEditCreate (parse, (char *) FcStrCopy (name), mode, expr, binding);
1791     if (!edit)
1792     {
1793         FcConfigMessage (parse, FcSevereError, "out of memory");
1794         FcExprDestroy (expr);
1795         return;
1796     }
1797     if (!FcVStackPushEdit (parse, edit))
1798         FcEditDestroy (edit);
1799 }
1800
1801 static void
1802 FcParseMatch (FcConfigParse *parse)
1803 {
1804     const FcChar8   *kind_name;
1805     FcMatchKind     kind;
1806     FcTest          *test = 0;
1807     FcEdit          *edit = 0;
1808     FcVStack        *vstack;
1809
1810     kind_name = FcConfigGetAttribute (parse, "target");
1811     if (!kind_name)
1812         kind = FcMatchPattern;
1813     else
1814     {
1815         if (!strcmp ((char *) kind_name, "pattern"))
1816             kind = FcMatchPattern;
1817         else if (!strcmp ((char *) kind_name, "font"))
1818             kind = FcMatchFont;
1819         else
1820         {
1821             FcConfigMessage (parse, FcSevereWarning, "invalid match target \"%s\"", kind_name);
1822             return;
1823         }
1824     }
1825     while ((vstack = FcVStackPop (parse)))
1826     {
1827         switch (vstack->tag) {
1828         case FcVStackTest:
1829             vstack->u.test->next = test;
1830             test = vstack->u.test;
1831             vstack->tag = FcVStackNone;
1832             break;
1833         case FcVStackEdit:
1834             vstack->u.edit->next = edit;
1835             edit = vstack->u.edit;
1836             vstack->tag = FcVStackNone;
1837             break;
1838         default:
1839             FcConfigMessage (parse, FcSevereWarning, "invalid match element");
1840             break;
1841         }
1842         FcVStackDestroy (vstack);
1843     }
1844     if (!FcConfigAddEdit (parse->config, test, edit, kind))
1845         FcConfigMessage (parse, FcSevereError, "out of memory");
1846 }
1847
1848 static void
1849 FcParseAcceptRejectFont (FcConfigParse *parse, FcElement element)
1850 {
1851     FcVStack    *vstack;
1852
1853     while ((vstack = FcVStackPop (parse)))
1854     {
1855         switch (vstack->tag) {
1856         case FcVStackGlob:
1857             if (!FcConfigGlobAdd (parse->config, 
1858                                   vstack->u.string,
1859                                   element == FcElementAcceptfont))
1860             {
1861                 FcConfigMessage (parse, FcSevereError, "out of memory");
1862             }
1863             break;
1864         case FcVStackPattern:
1865             if (!FcConfigPatternsAdd (parse->config,
1866                                       vstack->u.pattern,
1867                                       element == FcElementAcceptfont))
1868             {
1869                 FcConfigMessage (parse, FcSevereError, "out of memory");
1870             }
1871             else
1872                 vstack->tag = FcVStackNone;
1873             break;
1874         default:
1875             FcConfigMessage (parse, FcSevereWarning, "bad font selector");
1876             break;
1877         }
1878         FcVStackDestroy (vstack);
1879     }
1880 }
1881
1882
1883 static FcValue
1884 FcPopValue (FcConfigParse *parse)
1885 {
1886     FcVStack    *vstack = FcVStackPop (parse);
1887     FcValue     value;
1888     
1889     value.type = FcTypeVoid;
1890     
1891     if (!vstack)
1892         return value;
1893     
1894     switch (vstack->tag) {
1895     case FcVStackString:
1896         value.u.s = FcStrCopy (vstack->u.string);
1897         if (value.u.s)
1898             value.type = FcTypeString;
1899         break;
1900     case FcVStackConstant:
1901         if (FcNameConstant (vstack->u.string, &value.u.i))
1902             value.type = FcTypeInteger;
1903         break;
1904     case FcVStackInteger:
1905         value.u.i = vstack->u.integer;
1906         value.type = FcTypeInteger;
1907         break;
1908     case FcVStackDouble:
1909         value.u.d = vstack->u._double;
1910         value.type = FcTypeInteger;
1911         break;
1912     case FcVStackMatrix:
1913         value.u.m = FcMatrixCopy (vstack->u.matrix);
1914         if (value.u.m)
1915             value.type = FcTypeMatrix;
1916         break;
1917     case FcVStackBool:
1918         value.u.b = vstack->u.bool;
1919         value.type = FcTypeBool;
1920         break;
1921     default:
1922         FcConfigMessage (parse, FcSevereWarning, "unknown pattern element %d", 
1923                          vstack->tag);
1924         break;
1925     }
1926     FcVStackDestroy (vstack);
1927     
1928     return value;
1929 }
1930
1931 static void
1932 FcParsePatelt (FcConfigParse *parse)
1933 {
1934     FcValue     value;
1935     FcPattern   *pattern = FcPatternCreate ();
1936     const char  *name;
1937
1938     if (!pattern)
1939     {
1940         FcConfigMessage (parse, FcSevereError, "out of memory");
1941         return;
1942     }
1943
1944     name = (char *) FcConfigGetAttribute (parse, "name");
1945     if (!name)
1946     {
1947         FcConfigMessage (parse, FcSevereWarning, "missing pattern element name");
1948         return;
1949     }
1950     
1951     for (;;)
1952     {
1953         value = FcPopValue (parse);
1954         if (value.type == FcTypeVoid)
1955             break;
1956         if (!FcPatternAdd (pattern, name, value, FcTrue))
1957         {
1958             FcConfigMessage (parse, FcSevereError, "out of memory");
1959             break;
1960         }
1961     }
1962
1963     FcVStackPushPattern (parse, pattern);
1964 }
1965
1966 static void
1967 FcParsePattern (FcConfigParse *parse)
1968 {
1969     FcVStack    *vstack;
1970     FcPattern   *pattern = FcPatternCreate ();
1971
1972     if (!pattern)
1973     {
1974         FcConfigMessage (parse, FcSevereError, "out of memory");
1975         return;
1976     }
1977         
1978     while ((vstack = FcVStackPop (parse)))
1979     {
1980         switch (vstack->tag) {
1981         case FcVStackPattern:
1982             if (!FcPatternAppend (pattern, vstack->u.pattern))
1983             {
1984                 FcConfigMessage (parse, FcSevereError, "out of memory");
1985                 return;
1986             }
1987             break;
1988         default:
1989             FcConfigMessage (parse, FcSevereWarning, "unknown pattern element");
1990             break;
1991         }
1992         FcVStackDestroy (vstack);
1993     }
1994
1995     FcVStackPushPattern (parse, pattern);
1996 }
1997
1998 static void
1999 FcEndElement(void *userData, const XML_Char *name)
2000 {
2001     FcConfigParse   *parse = userData;
2002     FcChar8         *data;
2003     
2004     if (!parse->pstack)
2005         return;
2006     switch (parse->pstack->element) {
2007     case FcElementNone:
2008         break;
2009     case FcElementFontconfig:
2010         break;
2011     case FcElementDir:
2012         data = FcStrBufDone (&parse->pstack->str);
2013         if (!data)
2014         {
2015             FcConfigMessage (parse, FcSevereError, "out of memory");
2016             break;
2017         }
2018 #ifdef _WIN32
2019         if (strcmp (data, "WINDOWSFONTDIR") == 0)
2020         {
2021             int rc;
2022             FcStrFree (data);
2023             data = malloc (1000);
2024             if (!data)
2025             {
2026                 FcConfigMessage (parse, FcSevereError, "out of memory");
2027                 break;
2028             }
2029             FcMemAlloc (FC_MEM_STRING, 1000);
2030             rc = GetWindowsDirectory (data, 800);
2031             if (rc == 0 || rc > 800)
2032             {
2033                 FcConfigMessage (parse, FcSevereError, "GetWindowsDirectory failed");
2034                 FcStrFree (data);
2035                 break;
2036             }
2037             if (data [strlen (data) - 1] != '\\')
2038                 strcat (data, "\\");
2039             strcat (data, "fonts");
2040         }
2041 #endif
2042         if (!FcStrUsesHome (data) || FcConfigHome ())
2043         {
2044             if (!FcConfigAddDir (parse->config, data))
2045                 FcConfigMessage (parse, FcSevereError, "out of memory");
2046         }
2047         FcStrFree (data);
2048         break;
2049     case FcElementCache:
2050         data = FcStrBufDone (&parse->pstack->str);
2051         if (!data)
2052         {
2053             FcConfigMessage (parse, FcSevereError, "out of memory");
2054             break;
2055         }
2056         if (!FcStrUsesHome (data) || FcConfigHome ())
2057         {
2058             if (!FcConfigSetCache (parse->config, data))
2059                 FcConfigMessage (parse, FcSevereError, "out of memory");
2060         }
2061         FcStrFree (data);
2062         break;
2063     case FcElementInclude:
2064         FcParseInclude (parse);
2065         break;
2066     case FcElementConfig:
2067         break;
2068     case FcElementMatch:
2069         FcParseMatch (parse);
2070         break;
2071     case FcElementAlias:
2072         FcParseAlias (parse);
2073         break;
2074
2075     case FcElementBlank:
2076         FcParseBlank (parse);
2077         break;
2078     case FcElementRescan:
2079         FcParseRescan (parse);
2080         break;
2081         
2082     case FcElementPrefer:
2083         FcParseFamilies (parse, FcVStackPrefer);
2084         break;
2085     case FcElementAccept:
2086         FcParseFamilies (parse, FcVStackAccept);
2087         break;
2088     case FcElementDefault:
2089         FcParseFamilies (parse, FcVStackDefault);
2090         break;
2091     case FcElementFamily:
2092         FcParseFamily (parse);
2093         break;
2094
2095     case FcElementTest:
2096         FcParseTest (parse);
2097         break;
2098     case FcElementEdit:
2099         FcParseEdit (parse);
2100         break;
2101
2102     case FcElementInt:
2103         FcParseInt (parse);
2104         break;
2105     case FcElementDouble:
2106         FcParseDouble (parse);
2107         break;
2108     case FcElementString:
2109         FcParseString (parse, FcVStackString);
2110         break;
2111     case FcElementMatrix:
2112         FcParseMatrix (parse);
2113         break;
2114     case FcElementBool:
2115         FcParseBool (parse);
2116         break;
2117     case FcElementCharset:
2118 /*      FcParseCharset (parse); */
2119         break;
2120     case FcElementSelectfont:
2121         break;
2122     case FcElementAcceptfont:
2123     case FcElementRejectfont:
2124         FcParseAcceptRejectFont (parse, parse->pstack->element);
2125         break;
2126     case FcElementGlob:
2127         FcParseString (parse, FcVStackGlob);
2128         break;
2129     case FcElementPattern:
2130         FcParsePattern (parse);
2131         break;
2132     case FcElementPatelt:
2133         FcParsePatelt (parse);
2134         break;
2135     case FcElementName:
2136         FcParseString (parse, FcVStackField);
2137         break;
2138     case FcElementConst:
2139         FcParseString (parse, FcVStackConstant);
2140         break;
2141     case FcElementOr:
2142         FcParseBinary (parse, FcOpOr);
2143         break;
2144     case FcElementAnd:
2145         FcParseBinary (parse, FcOpAnd);
2146         break;
2147     case FcElementEq:
2148         FcParseBinary (parse, FcOpEqual);
2149         break;
2150     case FcElementNotEq:
2151         FcParseBinary (parse, FcOpNotEqual);
2152         break;
2153     case FcElementLess:
2154         FcParseBinary (parse, FcOpLess);
2155         break;
2156     case FcElementLessEq:
2157         FcParseBinary (parse, FcOpLessEqual);
2158         break;
2159     case FcElementMore:
2160         FcParseBinary (parse, FcOpMore);
2161         break;
2162     case FcElementMoreEq:
2163         FcParseBinary (parse, FcOpMoreEqual);
2164         break;
2165     case FcElementContains:
2166         FcParseBinary (parse, FcOpContains);
2167         break;
2168     case FcElementNotContains:
2169         FcParseBinary (parse, FcOpNotContains);
2170         break;
2171     case FcElementPlus:
2172         FcParseBinary (parse, FcOpPlus);
2173         break;
2174     case FcElementMinus:
2175         FcParseBinary (parse, FcOpMinus);
2176         break;
2177     case FcElementTimes:
2178         FcParseBinary (parse, FcOpTimes);
2179         break;
2180     case FcElementDivide:
2181         FcParseBinary (parse, FcOpDivide);
2182         break;
2183     case FcElementNot:
2184         FcParseUnary (parse, FcOpNot);
2185         break;
2186     case FcElementIf:
2187         FcParseBinary (parse, FcOpQuest);
2188         break;
2189     case FcElementFloor:
2190         FcParseUnary (parse, FcOpFloor);
2191         break;
2192     case FcElementCeil:
2193         FcParseUnary (parse, FcOpCeil);
2194         break;
2195     case FcElementRound:
2196         FcParseUnary (parse, FcOpRound);
2197         break;
2198     case FcElementTrunc:
2199         FcParseUnary (parse, FcOpTrunc);
2200         break;
2201     case FcElementUnknown:
2202         break;
2203     }
2204     (void) FcPStackPop (parse);
2205 }
2206
2207 static void
2208 FcCharacterData (void *userData, const XML_Char *s, int len)
2209 {
2210     FcConfigParse   *parse = userData;
2211     
2212     if (!parse->pstack)
2213         return;
2214     if (!FcStrBufData (&parse->pstack->str, (FcChar8 *) s, len))
2215         FcConfigMessage (parse, FcSevereError, "out of memory");
2216 }
2217
2218 static void
2219 FcStartDoctypeDecl (void            *userData,
2220                     const XML_Char  *doctypeName,
2221                     const XML_Char  *sysid,
2222                     const XML_Char  *pubid,
2223                     int             has_internal_subset)
2224 {
2225     FcConfigParse   *parse = userData;
2226
2227     if (strcmp ((char *) doctypeName, "fontconfig") != 0)
2228         FcConfigMessage (parse, FcSevereError, "invalid doctype \"%s\"", doctypeName);
2229 }
2230
2231 #if ENABLE_LIBXML2
2232
2233 static void
2234 FcInternalSubsetDecl (void            *userData,
2235                       const XML_Char  *doctypeName,
2236                       const XML_Char  *sysid,
2237                       const XML_Char  *pubid)
2238 {
2239     FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 1);
2240 }
2241
2242 static void
2243 FcExternalSubsetDecl (void            *userData,
2244                       const XML_Char  *doctypeName,
2245                       const XML_Char  *sysid,
2246                       const XML_Char  *pubid)
2247 {
2248     FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 0);
2249 }
2250
2251 #else /* ENABLE_LIBXML2 */
2252
2253 static void
2254 FcEndDoctypeDecl (void *userData)
2255 {
2256 }
2257
2258 #endif /* ENABLE_LIBXML2 */
2259
2260 static FcBool
2261 FcConfigParseAndLoadDir (FcConfig       *config,
2262                          const FcChar8  *name,
2263                          const FcChar8  *dir,
2264                          FcBool         complain)
2265 {
2266     DIR             *d;
2267     struct dirent   *e;
2268     FcBool          ret = FcTrue;
2269     FcChar8         *file;
2270     FcChar8         *base;
2271     FcStrSet        *files;
2272
2273     d = opendir ((char *) dir);
2274     if (!d)
2275     {
2276         if (complain)
2277             FcConfigMessage (0, FcSevereError, "Cannot open config dir \"%s\"",
2278                              name);
2279         ret = FcFalse;
2280         goto bail0;
2281     }
2282     /* freed below */
2283     file = (FcChar8 *) malloc (strlen ((char *) dir) + 1 + FC_MAX_FILE_LEN + 1);
2284     if (!file)
2285     {
2286         ret = FcFalse;
2287         goto bail1;
2288     }
2289     
2290     strcpy ((char *) file, (char *) dir);
2291     strcat ((char *) file, "/");
2292     base = file + strlen ((char *) file);
2293     
2294     files = FcStrSetCreate ();
2295     if (!files)
2296     {
2297         ret = FcFalse;
2298         goto bail2;
2299     }
2300     
2301     if (FcDebug () & FC_DBG_CONFIG)
2302         printf ("\tScanning config dir %s\n", dir);
2303         
2304     while (ret && (e = readdir (d)))
2305     {
2306         int d_len;
2307 #define TAIL        ".conf"
2308 #define TAIL_LEN    5
2309         /*
2310          * Add all files of the form [0-9]*.conf
2311          */
2312         if ('0' <= e->d_name[0] && e->d_name[0] <= '9' &&
2313             (d_len = strlen (e->d_name)) < FC_MAX_FILE_LEN &&
2314             d_len > TAIL_LEN &&
2315             strcmp (e->d_name + d_len - TAIL_LEN, TAIL) == 0)
2316         {
2317             strcpy ((char *) base, (char *) e->d_name);
2318             if (!FcStrSetAdd (files, file))
2319             {
2320                 ret = FcFalse;
2321                 goto bail3;
2322             }
2323         }
2324     }
2325     if (ret)
2326     {
2327         int i;
2328         qsort (files->strs, files->num, sizeof (FcChar8 *), 
2329                (int (*)(const void *, const void *)) FcStrCmp);
2330         for (i = 0; ret && i < files->num; i++)
2331             ret = FcConfigParseAndLoad (config, files->strs[i], complain);
2332     }
2333 bail3:
2334     FcStrSetDestroy (files);
2335 bail2:
2336     free (file);
2337 bail1:
2338     closedir (d);
2339 bail0:
2340     return ret || !complain;
2341 }
2342
2343 FcBool
2344 FcConfigParseAndLoad (FcConfig      *config,
2345                       const FcChar8 *name,
2346                       FcBool        complain)
2347 {
2348
2349     XML_Parser      p;
2350     FcChar8         *filename;
2351     FILE            *f;
2352     int             len;
2353     FcConfigParse   parse;
2354     FcBool          error = FcTrue;
2355     
2356 #if ENABLE_LIBXML2
2357     xmlSAXHandler   sax;
2358     char            buf[BUFSIZ];
2359 #else
2360     void            *buf;
2361 #endif
2362     
2363     filename = FcConfigFilename (name);
2364     if (!filename)
2365         goto bail0;
2366     
2367     if (!FcStrSetAdd (config->configFiles, filename))
2368     {
2369         FcStrFree (filename);
2370         goto bail0;
2371     }
2372
2373     if (FcFileIsDir (filename))
2374     {
2375         FcBool ret = FcConfigParseAndLoadDir (config, name, filename, complain);
2376         FcStrFree (filename);
2377         return ret;
2378     }
2379
2380     if (FcDebug () & FC_DBG_CONFIG)
2381         printf ("\tLoading config file %s\n", filename);
2382
2383     f = fopen ((char *) filename, "r");
2384     FcStrFree (filename);
2385     if (!f)
2386         goto bail0;
2387     
2388 #if ENABLE_LIBXML2
2389     memset(&sax, 0, sizeof(sax));
2390
2391     sax.internalSubset = FcInternalSubsetDecl;
2392     sax.externalSubset = FcExternalSubsetDecl;
2393     sax.startElement = FcStartElement;
2394     sax.endElement = FcEndElement;
2395     sax.characters = FcCharacterData;
2396
2397     p = xmlCreatePushParserCtxt (&sax, &parse, NULL, 0, filename);
2398 #else
2399     p = XML_ParserCreate ("UTF-8");
2400 #endif
2401
2402     if (!p)
2403         goto bail1;
2404
2405     if (!FcConfigInit (&parse, name, config, p))
2406         goto bail2;
2407
2408 #if !ENABLE_LIBXML2
2409
2410     XML_SetUserData (p, &parse);
2411     
2412     XML_SetDoctypeDeclHandler (p, FcStartDoctypeDecl, FcEndDoctypeDecl);
2413     XML_SetElementHandler (p, FcStartElement, FcEndElement);
2414     XML_SetCharacterDataHandler (p, FcCharacterData);
2415         
2416 #endif /* ENABLE_LIBXML2 */
2417
2418     do {
2419 #if !ENABLE_LIBXML2
2420         buf = XML_GetBuffer (p, BUFSIZ);
2421         if (!buf)
2422         {
2423             FcConfigMessage (&parse, FcSevereError, "cannot get parse buffer");
2424             goto bail3;
2425         }
2426 #endif
2427         len = fread (buf, 1, BUFSIZ, f);
2428         if (len < 0)
2429         {
2430             FcConfigMessage (&parse, FcSevereError, "failed reading config file");
2431             goto bail3;
2432         }
2433
2434 #if ENABLE_LIBXML2
2435         if (xmlParseChunk (p, buf, len, len == 0))
2436 #else
2437         if (!XML_ParseBuffer (p, len, len == 0))
2438 #endif
2439         {
2440             FcConfigMessage (&parse, FcSevereError, "%s", 
2441                            XML_ErrorString (XML_GetErrorCode (p)));
2442             goto bail3;
2443         }
2444     } while (len != 0);
2445     error = parse.error;
2446 bail3:
2447     FcConfigCleanup (&parse);
2448 bail2:
2449     XML_ParserFree (p);
2450 bail1:
2451     fclose (f);
2452     f = NULL;
2453 bail0:
2454     if (error && complain)
2455     {
2456         if (name)
2457             FcConfigMessage (0, FcSevereError, "Cannot load config file \"%s\"", name);
2458         else
2459             FcConfigMessage (0, FcSevereError, "Cannot load default config file");
2460         return FcFalse;
2461     }
2462     return FcTrue;
2463 }