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