]> git.wh0rd.org Git - fontconfig.git/blob - src/fcxml.c
Only add a config file to the set of config files once.
[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         else 
592             FcConfigMessage (parse, FcSevereWarning, 
593                              "invalid constant used : %s",
594                              expr->u.constant);
595         break;
596     case FcOpQuest:
597         FcTypecheckExpr (parse, expr->u.tree.left, FcTypeBool);
598         FcTypecheckExpr (parse, expr->u.tree.right->u.tree.left, type);
599         FcTypecheckExpr (parse, expr->u.tree.right->u.tree.right, type);
600         break;
601     case FcOpAssign:
602     case FcOpAssignReplace:
603         break;
604     case FcOpEqual:
605     case FcOpNotEqual:
606     case FcOpLess:
607     case FcOpLessEqual:
608     case FcOpMore:
609     case FcOpMoreEqual:
610     case FcOpContains:
611     case FcOpNotContains:
612     case FcOpListing:
613         FcTypecheckValue (parse, FcTypeBool, type);
614         break;
615     case FcOpComma:
616     case FcOpOr:
617     case FcOpAnd:
618     case FcOpPlus:
619     case FcOpMinus:
620     case FcOpTimes:
621     case FcOpDivide:
622         FcTypecheckExpr (parse, expr->u.tree.left, type);
623         FcTypecheckExpr (parse, expr->u.tree.right, type);
624         break;
625     case FcOpNot:
626         FcTypecheckValue (parse, FcTypeBool, type);
627         FcTypecheckExpr (parse, expr->u.tree.left, FcTypeBool);
628         break;
629     case FcOpFloor:
630     case FcOpCeil:
631     case FcOpRound:
632     case FcOpTrunc:
633         FcTypecheckValue (parse, FcTypeDouble, type);
634         FcTypecheckExpr (parse, expr->u.tree.left, FcTypeDouble);
635         break;
636     default:
637         break;
638     }
639 }
640
641 static FcTest *
642 FcTestCreate (FcConfigParse *parse,
643               FcMatchKind   kind, 
644               FcQual        qual,
645               const FcChar8 *field,
646               FcOp          compare,
647               FcExpr        *expr)
648 {
649     FcTest      *test = (FcTest *) malloc (sizeof (FcTest));
650
651     if (test)
652     {
653         const FcObjectType      *o;
654         
655         FcMemAlloc (FC_MEM_TEST, sizeof (FcTest));
656         test->next = 0;
657         test->kind = kind;
658         test->qual = qual;
659         test->field = (char *) FcStrCopy (field);
660         test->op = compare;
661         test->expr = expr;
662         o = FcNameGetObjectType (test->field);
663         if (o)
664             FcTypecheckExpr (parse, expr, o->type);
665     }
666     return test;
667 }
668
669 static FcEdit *
670 FcEditCreate (FcConfigParse     *parse,
671               const char        *field,
672               FcOp              op,
673               FcExpr            *expr,
674               FcValueBinding    binding)
675 {
676     FcEdit *e = (FcEdit *) malloc (sizeof (FcEdit));
677
678     if (e)
679     {
680         const FcObjectType      *o;
681
682         e->next = 0;
683         e->field = field;   /* already saved in grammar */
684         e->op = op;
685         e->expr = expr;
686         e->binding = binding;
687         o = FcNameGetObjectType (e->field);
688         if (o)
689             FcTypecheckExpr (parse, expr, o->type);
690     }
691     return e;
692 }
693
694 static void
695 FcVStackPush (FcConfigParse *parse, FcVStack *vstack)
696 {
697     vstack->prev = parse->vstack;
698     vstack->pstack = parse->pstack ? parse->pstack->prev : 0;
699     parse->vstack = vstack;
700 }
701
702 static FcVStack *
703 FcVStackCreate (void)
704 {
705     FcVStack    *new;
706
707     new = malloc (sizeof (FcVStack));
708     if (!new)
709         return 0;
710     FcMemAlloc (FC_MEM_VSTACK, sizeof (FcVStack));
711     new->tag = FcVStackNone;
712     new->prev = 0;
713     return new;
714 }
715
716 static void
717 FcVStackDestroy (FcVStack *vstack)
718 {
719     FcVStack    *prev;
720
721     for (; vstack; vstack = prev)
722     {
723         prev = vstack->prev;
724         switch (vstack->tag) {
725         case FcVStackNone:
726             break;
727         case FcVStackString:
728         case FcVStackFamily:
729         case FcVStackField:
730         case FcVStackConstant:
731         case FcVStackGlob:
732             FcStrFree (vstack->u.string);
733             break;
734         case FcVStackPattern:
735             FcPatternDestroy (vstack->u.pattern);
736             break;
737         case FcVStackInteger:
738         case FcVStackDouble:
739             break;
740         case FcVStackMatrix:
741             FcMatrixFree (vstack->u.matrix);
742             break;
743         case FcVStackBool:
744             break;
745         case FcVStackTest:
746             FcTestDestroy (vstack->u.test);
747             break;
748         case FcVStackExpr:
749         case FcVStackPrefer:
750         case FcVStackAccept:
751         case FcVStackDefault:
752             FcExprDestroy (vstack->u.expr);
753             break;
754         case FcVStackEdit:
755             FcEditDestroy (vstack->u.edit);
756             break;
757         }
758         FcMemFree (FC_MEM_VSTACK, sizeof (FcVStack));
759         free (vstack);
760     }
761 }
762
763 static FcBool
764 FcVStackPushString (FcConfigParse *parse, FcVStackTag tag, FcChar8 *string)
765 {
766     FcVStack    *vstack = FcVStackCreate ();
767     if (!vstack)
768         return FcFalse;
769     vstack->u.string = string;
770     vstack->tag = tag;
771     FcVStackPush (parse, vstack);
772     return FcTrue;
773 }
774
775 static FcBool
776 FcVStackPushInteger (FcConfigParse *parse, int integer)
777 {
778     FcVStack    *vstack = FcVStackCreate ();
779     if (!vstack)
780         return FcFalse;
781     vstack->u.integer = integer;
782     vstack->tag = FcVStackInteger;
783     FcVStackPush (parse, vstack);
784     return FcTrue;
785 }
786
787 static FcBool
788 FcVStackPushDouble (FcConfigParse *parse, double _double)
789 {
790     FcVStack    *vstack = FcVStackCreate ();
791     if (!vstack)
792         return FcFalse;
793     vstack->u._double = _double;
794     vstack->tag = FcVStackDouble;
795     FcVStackPush (parse, vstack);
796     return FcTrue;
797 }
798
799 static FcBool
800 FcVStackPushMatrix (FcConfigParse *parse, FcMatrix *matrix)
801 {
802     FcVStack    *vstack = FcVStackCreate ();
803     if (!vstack)
804         return FcFalse;
805     matrix = FcMatrixCopy (matrix);
806     if (!matrix)
807     {
808         FcVStackDestroy (vstack);
809         return FcFalse;
810     }
811     vstack->u.matrix = matrix;
812     vstack->tag = FcVStackMatrix;
813     FcVStackPush (parse, vstack);
814     return FcTrue;
815 }
816
817 static FcBool
818 FcVStackPushBool (FcConfigParse *parse, FcBool bool)
819 {
820     FcVStack    *vstack = FcVStackCreate ();
821     if (!vstack)
822         return FcFalse;
823     vstack->u.bool = bool;
824     vstack->tag = FcVStackBool;
825     FcVStackPush (parse, vstack);
826     return FcTrue;
827 }
828
829 static FcBool
830 FcVStackPushTest (FcConfigParse *parse, FcTest *test)
831 {
832     FcVStack    *vstack = FcVStackCreate ();
833     if (!vstack)
834         return FcFalse;
835     vstack->u.test = test;
836     vstack->tag = FcVStackTest;
837     FcVStackPush (parse, vstack);
838     return FcTrue;
839 }
840
841 static FcBool
842 FcVStackPushExpr (FcConfigParse *parse, FcVStackTag tag, FcExpr *expr)
843 {
844     FcVStack    *vstack = FcVStackCreate ();
845     if (!vstack)
846         return FcFalse;
847     vstack->u.expr = expr;
848     vstack->tag = tag;
849     FcVStackPush (parse, vstack);
850     return FcTrue;
851 }
852
853 static FcBool
854 FcVStackPushEdit (FcConfigParse *parse, FcEdit *edit)
855 {
856     FcVStack    *vstack = FcVStackCreate ();
857     if (!vstack)
858         return FcFalse;
859     vstack->u.edit = edit;
860     vstack->tag = FcVStackEdit;
861     FcVStackPush (parse, vstack);
862     return FcTrue;
863 }
864
865 static FcBool
866 FcVStackPushPattern (FcConfigParse *parse, FcPattern *pattern)
867 {
868     FcVStack    *vstack = FcVStackCreate ();
869     if (!vstack)
870         return FcFalse;
871     vstack->u.pattern = pattern;
872     vstack->tag = FcVStackPattern;
873     FcVStackPush (parse, vstack);
874     return FcTrue;
875 }
876
877 static FcVStack *
878 FcVStackFetch (FcConfigParse *parse, int off)
879 {
880     FcVStack    *vstack;
881
882     for (vstack = parse->vstack; vstack && off-- > 0; vstack = vstack->prev);
883     return vstack;
884 }
885
886 static void
887 FcVStackClear (FcConfigParse *parse)
888 {
889     while (parse->vstack && parse->vstack->pstack == parse->pstack)
890     {
891         FcVStack    *vstack = parse->vstack;
892         parse->vstack = vstack->prev;
893         vstack->prev = 0;
894         FcVStackDestroy (vstack);
895     }
896 }
897
898 static FcVStack *
899 FcVStackPop (FcConfigParse *parse)
900 {
901     FcVStack    *vstack = parse->vstack;
902     
903     if (!vstack || vstack->pstack != parse->pstack)
904         return 0;
905     parse->vstack = vstack->prev;
906     vstack->prev = 0;
907     return vstack;
908 }
909
910 static int
911 FcVStackElements (FcConfigParse *parse)
912 {
913     int         h = 0;
914     FcVStack    *vstack = parse->vstack;
915     while (vstack && vstack->pstack == parse->pstack)
916     {
917         h++;
918         vstack = vstack->prev;
919     }
920     return h;
921 }
922
923 static FcChar8 **
924 FcConfigSaveAttr (const XML_Char **attr)
925 {
926     int         n;
927     int         slen;
928     int         i;
929     FcChar8     **new;
930     FcChar8     *s;
931
932     if (!attr)
933         return 0;
934     slen = 0;
935     for (i = 0; attr[i]; i++)
936         slen += strlen ((char *) attr[i]) + 1;
937     n = i;
938     new = malloc ((i + 1) * sizeof (FcChar8 *) + slen);
939     if (!new)
940         return 0;
941     FcMemAlloc (FC_MEM_ATTR, 1);    /* size is too expensive */
942     s = (FcChar8 *) (new + (i + 1));
943     for (i = 0; attr[i]; i++)
944     {
945         new[i] = s;
946         strcpy ((char *) s, (char *) attr[i]);
947         s += strlen ((char *) s) + 1;
948     }
949     new[i] = 0;
950     return new;
951 }
952
953 static FcBool
954 FcPStackPush (FcConfigParse *parse, FcElement element, const XML_Char **attr)
955 {
956     FcPStack   *new = malloc (sizeof (FcPStack));
957
958     if (!new)
959         return FcFalse;
960     FcMemAlloc (FC_MEM_PSTACK, sizeof (FcPStack));
961     new->prev = parse->pstack;
962     new->element = element;
963     if (attr)
964     {
965         new->attr = FcConfigSaveAttr (attr);
966         if (!new->attr)
967             FcConfigMessage (parse, FcSevereError, "out of memory");
968     }
969     else
970         new->attr = 0;
971     FcStrBufInit (&new->str, 0, 0);
972     parse->pstack = new;
973     return FcTrue;
974 }
975
976 static FcBool
977 FcPStackPop (FcConfigParse *parse)
978 {
979     FcPStack   *old;
980     
981     if (!parse->pstack) 
982     {
983         FcConfigMessage (parse, FcSevereError, "mismatching element");
984         return FcFalse;
985     }
986     FcVStackClear (parse);
987     old = parse->pstack;
988     parse->pstack = old->prev;
989     FcStrBufDestroy (&old->str);
990     if (old->attr)
991     {
992         FcMemFree (FC_MEM_ATTR, 1); /* size is to expensive */
993         free (old->attr);
994     }
995     FcMemFree (FC_MEM_PSTACK, sizeof (FcPStack));
996     free (old);
997     return FcTrue;
998 }
999
1000 static FcBool
1001 FcConfigInit (FcConfigParse *parse, const FcChar8 *name, FcConfig *config, XML_Parser parser)
1002 {
1003     parse->pstack = 0;
1004     parse->vstack = 0;
1005     parse->error = FcFalse;
1006     parse->name = name;
1007     parse->config = config;
1008     parse->parser = parser;
1009     return FcTrue;
1010 }
1011
1012 static void
1013 FcConfigCleanup (FcConfigParse  *parse)
1014 {
1015     while (parse->pstack)
1016         FcPStackPop (parse);
1017 }
1018
1019 static const FcChar8 *
1020 FcConfigGetAttribute (FcConfigParse *parse, const char *attr)
1021 {
1022     FcChar8 **attrs;
1023     if (!parse->pstack)
1024         return 0;
1025
1026     attrs = parse->pstack->attr;
1027     while (*attrs)
1028     {
1029         if (!strcmp ((char *) *attrs, attr))
1030             return attrs[1];
1031         attrs += 2;
1032     }
1033     return 0;
1034 }
1035
1036 static void
1037 FcStartElement(void *userData, const XML_Char *name, const XML_Char **attr)
1038 {
1039     FcConfigParse   *parse = userData;
1040     FcElement       element;
1041     
1042     element = FcElementMap (name);
1043     if (element == FcElementUnknown)
1044         FcConfigMessage (parse, FcSevereWarning, "unknown element \"%s\"", name);
1045     
1046     if (!FcPStackPush (parse, element, attr))
1047     {
1048         FcConfigMessage (parse, FcSevereError, "out of memory");
1049         return;
1050     }
1051     return;
1052 }
1053
1054 static void
1055 FcParseBlank (FcConfigParse *parse)
1056 {
1057     int     n = FcVStackElements (parse);
1058     while (n-- > 0)
1059     {
1060         FcVStack    *v = FcVStackFetch (parse, n);
1061         if (v->tag != FcVStackInteger)
1062             FcConfigMessage (parse, FcSevereError, "non-integer blank");
1063         else
1064         {
1065             if (!parse->config->blanks)
1066             {
1067                 parse->config->blanks = FcBlanksCreate ();
1068                 if (!parse->config->blanks)
1069                 {
1070                     FcConfigMessage (parse, FcSevereError, "out of memory");
1071                     break;
1072                 }
1073             }
1074             if (!FcBlanksAdd (parse->config->blanks, v->u.integer))
1075             {
1076                 FcConfigMessage (parse, FcSevereError, "out of memory");
1077                 break;
1078             }
1079         }
1080     }
1081 }
1082
1083 static void
1084 FcParseRescan (FcConfigParse *parse)
1085 {
1086     int     n = FcVStackElements (parse);
1087     while (n-- > 0)
1088     {
1089         FcVStack    *v = FcVStackFetch (parse, n);
1090         if (v->tag != FcVStackInteger)
1091             FcConfigMessage (parse, FcSevereWarning, "non-integer rescan");
1092         else
1093             parse->config->rescanInterval = v->u.integer;
1094     }
1095 }
1096
1097 static void
1098 FcParseInt (FcConfigParse *parse)
1099 {
1100     FcChar8 *s, *end;
1101     int     l;
1102     
1103     if (!parse->pstack)
1104         return;
1105     s = FcStrBufDone (&parse->pstack->str);
1106     if (!s)
1107     {
1108         FcConfigMessage (parse, FcSevereError, "out of memory");
1109         return;
1110     }
1111     end = 0;
1112     l = (int) strtol ((char *) s, (char **)&end, 0);
1113     if (end != s + strlen ((char *) s))
1114         FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid integer", s);
1115     else
1116         FcVStackPushInteger (parse, l);
1117     FcStrFree (s);
1118 }
1119
1120 /*
1121  * idea copied from glib g_ascii_strtod with 
1122  * permission of the author (Alexander Larsson) 
1123  */
1124
1125 #include <locale.h>
1126
1127 static double 
1128 FcStrtod (char *s, char **end)
1129 {
1130     struct lconv    *locale_data;
1131     char            *dot;
1132     double          v;
1133
1134     /*
1135      * Have to swap the decimal point to match the current locale
1136      * if that locale doesn't use 0x2e
1137      */
1138     if ((dot = strchr (s, 0x2e)) &&
1139         (locale_data = localeconv ()) &&
1140         (locale_data->decimal_point[0] != 0x2e ||
1141          locale_data->decimal_point[1] != 0))
1142     {
1143         char    buf[128];
1144         int     slen = strlen (s);
1145         int     dlen = strlen (locale_data->decimal_point);
1146         
1147         if (slen + dlen > (int) sizeof (buf))
1148         {
1149             if (end)
1150                 *end = s;
1151             v = 0;
1152         }
1153         else
1154         {
1155             char        *buf_end;
1156             /* mantissa */
1157             strncpy (buf, s, dot - s);
1158             /* decimal point */
1159             strcpy (buf + (dot - s), locale_data->decimal_point);
1160             /* rest of number */
1161             strcpy (buf + (dot - s) + dlen, dot + 1);
1162             buf_end = 0;
1163             v = strtod (buf, &buf_end);
1164             if (buf_end) {
1165                 buf_end = s + (buf_end - buf);
1166                 if (buf_end > dot)
1167                     buf_end -= dlen - 1;
1168             }
1169             if (end)
1170                 *end = buf_end;
1171         }
1172     }
1173     else
1174         v = strtod (s, end);
1175     return v;
1176 }
1177
1178 static void
1179 FcParseDouble (FcConfigParse *parse)
1180 {
1181     FcChar8 *s, *end;
1182     double  d;
1183     
1184     if (!parse->pstack)
1185         return;
1186     s = FcStrBufDone (&parse->pstack->str);
1187     if (!s)
1188     {
1189         FcConfigMessage (parse, FcSevereError, "out of memory");
1190         return;
1191     }
1192     end = 0;
1193     d = FcStrtod ((char *) s, (char **)&end);
1194     if (end != s + strlen ((char *) s))
1195         FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid double", s);
1196     else
1197         FcVStackPushDouble (parse, d);
1198     FcStrFree (s);
1199 }
1200
1201 static void
1202 FcParseString (FcConfigParse *parse, FcVStackTag tag)
1203 {
1204     FcChar8 *s;
1205     
1206     if (!parse->pstack)
1207         return;
1208     s = FcStrBufDone (&parse->pstack->str);
1209     if (!s)
1210     {
1211         FcConfigMessage (parse, FcSevereError, "out of memory");
1212         return;
1213     }
1214     if (!FcVStackPushString (parse, tag, s))
1215         FcStrFree (s);
1216 }
1217
1218 static void
1219 FcParseMatrix (FcConfigParse *parse)
1220 {
1221     FcVStack    *vstack;
1222     enum { m_done, m_xx, m_xy, m_yx, m_yy } matrix_state = m_yy;
1223     FcMatrix    m;
1224     
1225     while ((vstack = FcVStackPop (parse)))
1226     {
1227         double  v;
1228         switch (vstack->tag) {
1229         case FcVStackInteger:
1230             v = vstack->u.integer;
1231             break;
1232         case FcVStackDouble:
1233             v = vstack->u._double;
1234             break;
1235         default:
1236             FcConfigMessage (parse, FcSevereError, "non-double matrix element");
1237             v = 1.0;
1238             break;
1239         }
1240         switch (matrix_state) {
1241         case m_xx: m.xx = v; break;
1242         case m_xy: m.xy = v; break;
1243         case m_yx: m.yx = v; break;
1244         case m_yy: m.yy = v; break;
1245         default: break;
1246         }
1247         FcVStackDestroy (vstack);
1248         matrix_state--;
1249     }
1250     if (matrix_state != m_done)
1251         FcConfigMessage (parse, FcSevereError, "wrong number of matrix elements");
1252     else
1253         FcVStackPushMatrix (parse, &m);
1254 }
1255
1256 static FcBool
1257 FcConfigLexBool (FcConfigParse *parse, const FcChar8 *bool)
1258 {
1259     FcBool  result = FcFalse;
1260
1261     if (!FcNameBool (bool, &result))
1262         FcConfigMessage (parse, FcSevereWarning, "\"%s\" is not known boolean",
1263                          bool);
1264     return result;
1265 }
1266
1267 static void
1268 FcParseBool (FcConfigParse *parse)
1269 {
1270     FcChar8 *s;
1271
1272     if (!parse->pstack)
1273         return;
1274     s = FcStrBufDone (&parse->pstack->str);
1275     if (!s)
1276     {
1277         FcConfigMessage (parse, FcSevereError, "out of memory");
1278         return;
1279     }
1280     FcVStackPushBool (parse, FcConfigLexBool (parse, s));
1281     FcStrFree (s);
1282 }
1283
1284 static void
1285 FcParseFamilies (FcConfigParse *parse, FcVStackTag tag)
1286 {
1287     FcVStack    *vstack;
1288     FcExpr      *left, *expr = 0, *new;
1289
1290     while ((vstack = FcVStackPop (parse)))
1291     {
1292         if (vstack->tag != FcVStackFamily)
1293         {
1294             FcConfigMessage (parse, FcSevereWarning, "non-family");
1295             FcVStackDestroy (vstack);
1296             continue;
1297         }
1298         left = vstack->u.expr;
1299         vstack->tag = FcVStackNone;
1300         FcVStackDestroy (vstack);
1301         if (expr)
1302         {
1303             new = FcExprCreateOp (left, FcOpComma, expr);
1304             if (!new)
1305             {
1306                 FcConfigMessage (parse, FcSevereError, "out of memory");
1307                 FcExprDestroy (left);
1308                 FcExprDestroy (expr);
1309                 break;
1310             }
1311             expr = new;
1312         }
1313         else
1314             expr = left;
1315     }
1316     if (expr)
1317     {
1318         if (!FcVStackPushExpr (parse, tag, expr))
1319         {
1320             FcConfigMessage (parse, FcSevereError, "out of memory");
1321             if (expr)
1322                 FcExprDestroy (expr);
1323         }
1324     }
1325 }
1326
1327 static void
1328 FcParseFamily (FcConfigParse *parse)
1329 {
1330     FcChar8 *s;
1331     FcExpr  *expr;
1332
1333     if (!parse->pstack)
1334         return;
1335     s = FcStrBufDone (&parse->pstack->str);
1336     if (!s)
1337     {
1338         FcConfigMessage (parse, FcSevereError, "out of memory");
1339         return;
1340     }
1341     expr = FcExprCreateString (s);
1342     FcStrFree (s);
1343     if (expr)
1344         FcVStackPushExpr (parse, FcVStackFamily, expr);
1345 }
1346
1347 static void
1348 FcParseAlias (FcConfigParse *parse)
1349 {
1350     FcExpr      *family = 0, *accept = 0, *prefer = 0, *def = 0, *new = 0;
1351     FcEdit      *edit = 0, *next;
1352     FcVStack    *vstack;
1353     FcTest      *test;
1354
1355     while ((vstack = FcVStackPop (parse))) 
1356     {
1357         switch (vstack->tag) {
1358         case FcVStackFamily:
1359             if (family)
1360             {
1361                 new = FcExprCreateOp (vstack->u.expr, FcOpComma, family);
1362                 if (!new)
1363                     FcConfigMessage (parse, FcSevereError, "out of memory");
1364                 else
1365                     family = new;
1366             }
1367             else
1368                 new = vstack->u.expr;
1369             if (new)
1370             {
1371                 family = new;
1372                 vstack->tag = FcVStackNone;
1373             }
1374             break;
1375         case FcVStackPrefer:
1376             if (prefer)
1377                 FcExprDestroy (prefer);
1378             prefer = vstack->u.expr;
1379             vstack->tag = FcVStackNone;
1380             break;
1381         case FcVStackAccept:
1382             if (accept)
1383                 FcExprDestroy (accept);
1384             accept = vstack->u.expr;
1385             vstack->tag = FcVStackNone;
1386             break;
1387         case FcVStackDefault:
1388             if (def)
1389                 FcExprDestroy (def);
1390             def = vstack->u.expr;
1391             vstack->tag = FcVStackNone;
1392             break;
1393         default:
1394             FcConfigMessage (parse, FcSevereWarning, "bad alias");
1395             break;
1396         }
1397         FcVStackDestroy (vstack);
1398     }
1399     if (!family)
1400     {
1401         FcConfigMessage (parse, FcSevereError, "missing family in alias");
1402         if (prefer)
1403             FcExprDestroy (prefer);
1404         if (accept)
1405             FcExprDestroy (accept);
1406         if (def)
1407             FcExprDestroy (def);
1408         return;
1409     }
1410     if (prefer)
1411     {
1412         edit = FcEditCreate (parse, 
1413                              FcConfigSaveField ("family"),
1414                              FcOpPrepend,
1415                              prefer,
1416                              FcValueBindingWeak);
1417         if (edit)
1418             edit->next = 0;
1419         else
1420             FcExprDestroy (prefer);
1421     }
1422     if (accept)
1423     {
1424         next = edit;
1425         edit = FcEditCreate (parse,
1426                              FcConfigSaveField ("family"),
1427                              FcOpAppend,
1428                              accept,
1429                              FcValueBindingWeak);
1430         if (edit)
1431             edit->next = next;
1432         else
1433             FcExprDestroy (accept);
1434     }
1435     if (def)
1436     {
1437         next = edit;
1438         edit = FcEditCreate (parse,
1439                              FcConfigSaveField ("family"),
1440                              FcOpAppendLast,
1441                              def,
1442                              FcValueBindingWeak);
1443         if (edit)
1444             edit->next = next;
1445         else
1446             FcExprDestroy (def);
1447     }
1448     if (edit)
1449     {
1450         test = FcTestCreate (parse, FcMatchPattern,
1451                              FcQualAny,
1452                              (FcChar8 *) FC_FAMILY,
1453                              FcOpEqual,
1454                              family);
1455         if (test)
1456             if (!FcConfigAddEdit (parse->config, test, edit, FcMatchPattern))
1457                 FcTestDestroy (test);
1458     }
1459     else
1460         FcExprDestroy (family);
1461 }
1462
1463 static FcExpr *
1464 FcPopExpr (FcConfigParse *parse)
1465 {
1466     FcVStack    *vstack = FcVStackPop (parse);
1467     FcExpr      *expr = 0;
1468     if (!vstack)
1469         return 0;
1470     switch (vstack->tag) {
1471     case FcVStackNone:
1472         break;
1473     case FcVStackString:
1474     case FcVStackFamily:
1475         expr = FcExprCreateString (vstack->u.string);
1476         break;
1477     case FcVStackField:
1478         expr = FcExprCreateField ((char *) vstack->u.string);
1479         break;
1480     case FcVStackConstant:
1481         expr = FcExprCreateConst (vstack->u.string);
1482         break;
1483     case FcVStackGlob:
1484         /* XXX: What's the correct action here? (CDW) */
1485         break;
1486     case FcVStackPrefer:
1487     case FcVStackAccept:
1488     case FcVStackDefault:
1489         expr = vstack->u.expr;
1490         vstack->tag = FcVStackNone;
1491         break;
1492     case FcVStackInteger:
1493         expr = FcExprCreateInteger (vstack->u.integer);
1494         break;
1495     case FcVStackDouble:
1496         expr = FcExprCreateDouble (vstack->u._double);
1497         break;
1498     case FcVStackMatrix:
1499         expr = FcExprCreateMatrix (vstack->u.matrix);
1500         break;
1501     case FcVStackBool:
1502         expr = FcExprCreateBool (vstack->u.bool);
1503         break;
1504     case FcVStackTest:
1505         break;
1506     case FcVStackExpr:
1507         expr = vstack->u.expr;
1508         vstack->tag = FcVStackNone;
1509         break;
1510     case FcVStackEdit:
1511         break;
1512     default:
1513         break;
1514     }
1515     FcVStackDestroy (vstack);
1516     return expr;
1517 }
1518
1519 /*
1520  * This builds a tree of binary operations.  Note
1521  * that every operator is defined so that if only
1522  * a single operand is contained, the value of the
1523  * whole expression is the value of the operand.
1524  *
1525  * This code reduces in that case to returning that
1526  * operand.
1527  */
1528 static FcExpr *
1529 FcPopBinary (FcConfigParse *parse, FcOp op)
1530 {
1531     FcExpr  *left, *expr = 0, *new;
1532
1533     while ((left = FcPopExpr (parse)))
1534     {
1535         if (expr)
1536         {
1537             new = FcExprCreateOp (left, op, expr);
1538             if (!new)
1539             {
1540                 FcConfigMessage (parse, FcSevereError, "out of memory");
1541                 FcExprDestroy (left);
1542                 FcExprDestroy (expr);
1543                 break;
1544             }
1545             expr = new;
1546         }
1547         else
1548             expr = left;
1549     }
1550     return expr;
1551 }
1552
1553 static void
1554 FcParseBinary (FcConfigParse *parse, FcOp op)
1555 {
1556     FcExpr  *expr = FcPopBinary (parse, op);
1557     if (expr)
1558         FcVStackPushExpr (parse, FcVStackExpr, expr);
1559 }
1560
1561 /*
1562  * This builds a a unary operator, it consumes only
1563  * a single operand
1564  */
1565
1566 static FcExpr *
1567 FcPopUnary (FcConfigParse *parse, FcOp op)
1568 {
1569     FcExpr  *operand, *new = 0;
1570
1571     if ((operand = FcPopExpr (parse)))
1572     {
1573         new = FcExprCreateOp (operand, op, 0);
1574         if (!new)
1575         {
1576             FcExprDestroy (operand);
1577             FcConfigMessage (parse, FcSevereError, "out of memory");
1578         }
1579     }
1580     return new;
1581 }
1582
1583 static void
1584 FcParseUnary (FcConfigParse *parse, FcOp op)
1585 {
1586     FcExpr  *expr = FcPopUnary (parse, op);
1587     if (expr)
1588         FcVStackPushExpr (parse, FcVStackExpr, expr);
1589 }
1590
1591 static void
1592 FcParseInclude (FcConfigParse *parse)
1593 {
1594     FcChar8         *s;
1595     const FcChar8   *i;
1596     FcBool          ignore_missing = FcFalse;
1597     
1598     s = FcStrBufDone (&parse->pstack->str);
1599     if (!s)
1600     {
1601         FcConfigMessage (parse, FcSevereError, "out of memory");
1602         return;
1603     }
1604     i = FcConfigGetAttribute (parse, "ignore_missing");
1605     if (i && FcConfigLexBool (parse, (FcChar8 *) i) == FcTrue)
1606         ignore_missing = FcTrue;
1607     if (!FcConfigParseAndLoad (parse->config, s, !ignore_missing))
1608         parse->error = FcTrue;
1609     FcStrFree (s);
1610 }
1611
1612 typedef struct _FcOpMap {
1613     char    name[16];
1614     FcOp    op;
1615 } FcOpMap;
1616
1617 static FcOp
1618 FcConfigLexOp (const FcChar8 *op, const FcOpMap *map, int nmap)
1619 {
1620     int i;
1621
1622     for (i = 0; i < nmap; i++)
1623         if (!strcmp ((char *) op, map[i].name)) 
1624             return map[i].op;
1625     return FcOpInvalid;
1626 }
1627
1628 static const FcOpMap fcCompareOps[] = {
1629     { "eq",             FcOpEqual           },
1630     { "not_eq",         FcOpNotEqual        },
1631     { "less",           FcOpLess            },
1632     { "less_eq",        FcOpLessEqual       },
1633     { "more",           FcOpMore            },
1634     { "more_eq",        FcOpMoreEqual       },
1635     { "contains",       FcOpContains        },
1636     { "not_contains",   FcOpNotContains     }
1637 };
1638
1639 #define NUM_COMPARE_OPS (int) (sizeof fcCompareOps / sizeof fcCompareOps[0])
1640
1641 static FcOp
1642 FcConfigLexCompare (const FcChar8 *compare)
1643 {
1644     return FcConfigLexOp (compare, fcCompareOps, NUM_COMPARE_OPS);
1645 }
1646
1647
1648 static void
1649 FcParseTest (FcConfigParse *parse)
1650 {
1651     const FcChar8   *kind_string;
1652     FcMatchKind     kind;
1653     const FcChar8   *qual_string;
1654     FcQual          qual;
1655     const FcChar8   *name;
1656     const FcChar8   *compare_string;
1657     FcOp            compare;
1658     FcExpr          *expr;
1659     FcTest          *test;
1660
1661     kind_string = FcConfigGetAttribute (parse, "target");
1662     if (!kind_string)
1663         kind = FcMatchDefault;
1664     else
1665     {
1666         if (!strcmp ((char *) kind_string, "pattern"))
1667             kind = FcMatchPattern;
1668         else if (!strcmp ((char *) kind_string, "font"))
1669             kind = FcMatchFont;
1670         else if (!strcmp ((char *) kind_string, "default"))
1671             kind = FcMatchDefault;
1672         else
1673         {
1674             FcConfigMessage (parse, FcSevereWarning, "invalid test target \"%s\"", kind_string);
1675             return;
1676         }
1677     }
1678     qual_string = FcConfigGetAttribute (parse, "qual");
1679     if (!qual_string)
1680         qual = FcQualAny;
1681     else
1682     {
1683         if (!strcmp ((char *) qual_string, "any"))
1684             qual = FcQualAny;
1685         else if (!strcmp ((char *) qual_string, "all"))
1686             qual = FcQualAll;
1687         else if (!strcmp ((char *) qual_string, "first"))
1688             qual = FcQualFirst;
1689         else if (!strcmp ((char *) qual_string, "not_first"))
1690             qual = FcQualNotFirst;
1691         else
1692         {
1693             FcConfigMessage (parse, FcSevereWarning, "invalid test qual \"%s\"", qual_string);
1694             return;
1695         }
1696     }
1697     name = FcConfigGetAttribute (parse, "name");
1698     if (!name)
1699     {
1700         FcConfigMessage (parse, FcSevereWarning, "missing test name");
1701         return;
1702     }
1703     compare_string = FcConfigGetAttribute (parse, "compare");
1704     if (!compare_string)
1705         compare = FcOpEqual;
1706     else
1707     {
1708         compare = FcConfigLexCompare (compare_string);
1709         if (compare == FcOpInvalid)
1710         {
1711             FcConfigMessage (parse, FcSevereWarning, "invalid test compare \"%s\"", compare_string);
1712             return;
1713         }
1714     }
1715     expr = FcPopBinary (parse, FcOpComma);
1716     if (!expr)
1717     {
1718         FcConfigMessage (parse, FcSevereWarning, "missing test expression");
1719         return;
1720     }
1721     test = FcTestCreate (parse, kind, qual, name, compare, expr);
1722     if (!test)
1723     {
1724         FcConfigMessage (parse, FcSevereError, "out of memory");
1725         return;
1726     }
1727     FcVStackPushTest (parse, test);
1728 }
1729
1730 static const FcOpMap fcModeOps[] = {
1731     { "assign",         FcOpAssign          },
1732     { "assign_replace", FcOpAssignReplace   },
1733     { "prepend",        FcOpPrepend         },
1734     { "prepend_first",  FcOpPrependFirst    },
1735     { "append",         FcOpAppend          },
1736     { "append_last",    FcOpAppendLast      },
1737 };
1738
1739 #define NUM_MODE_OPS (int) (sizeof fcModeOps / sizeof fcModeOps[0])
1740
1741 static FcOp
1742 FcConfigLexMode (const FcChar8 *mode)
1743 {
1744     return FcConfigLexOp (mode, fcModeOps, NUM_MODE_OPS);
1745 }
1746
1747 static void
1748 FcParseEdit (FcConfigParse *parse)
1749 {
1750     const FcChar8   *name;
1751     const FcChar8   *mode_string;
1752     const FcChar8   *binding_string;
1753     FcOp            mode;
1754     FcValueBinding  binding;
1755     FcExpr          *expr;
1756     FcEdit          *edit;
1757
1758     name = FcConfigGetAttribute (parse, "name");
1759     if (!name)
1760     {
1761         FcConfigMessage (parse, FcSevereWarning, "missing edit name");
1762         return;
1763     }
1764     mode_string = FcConfigGetAttribute (parse, "mode");
1765     if (!mode_string)
1766         mode = FcOpAssign;
1767     else
1768     {
1769         mode = FcConfigLexMode (mode_string);
1770         if (mode == FcOpInvalid)
1771         {
1772             FcConfigMessage (parse, FcSevereWarning, "invalid edit mode \"%s\"", mode_string);
1773             return;
1774         }
1775     }
1776     binding_string = FcConfigGetAttribute (parse, "binding");
1777     if (!binding_string)
1778         binding = FcValueBindingWeak;
1779     else
1780     {
1781         if (!strcmp ((char *) binding_string, "weak"))
1782             binding = FcValueBindingWeak;
1783         else if (!strcmp ((char *) binding_string, "strong"))
1784             binding = FcValueBindingStrong;
1785         else if (!strcmp ((char *) binding_string, "same"))
1786             binding = FcValueBindingSame;
1787         else
1788         {
1789             FcConfigMessage (parse, FcSevereWarning, "invalid edit binding \"%s\"", binding_string);
1790             return;
1791         }
1792     }
1793     expr = FcPopBinary (parse, FcOpComma);
1794     edit = FcEditCreate (parse, (char *) FcStrCopy (name), mode, expr, binding);
1795     if (!edit)
1796     {
1797         FcConfigMessage (parse, FcSevereError, "out of memory");
1798         FcExprDestroy (expr);
1799         return;
1800     }
1801     if (!FcVStackPushEdit (parse, edit))
1802         FcEditDestroy (edit);
1803 }
1804
1805 static void
1806 FcParseMatch (FcConfigParse *parse)
1807 {
1808     const FcChar8   *kind_name;
1809     FcMatchKind     kind;
1810     FcTest          *test = 0;
1811     FcEdit          *edit = 0;
1812     FcVStack        *vstack;
1813
1814     kind_name = FcConfigGetAttribute (parse, "target");
1815     if (!kind_name)
1816         kind = FcMatchPattern;
1817     else
1818     {
1819         if (!strcmp ((char *) kind_name, "pattern"))
1820             kind = FcMatchPattern;
1821         else if (!strcmp ((char *) kind_name, "font"))
1822             kind = FcMatchFont;
1823         else
1824         {
1825             FcConfigMessage (parse, FcSevereWarning, "invalid match target \"%s\"", kind_name);
1826             return;
1827         }
1828     }
1829     while ((vstack = FcVStackPop (parse)))
1830     {
1831         switch (vstack->tag) {
1832         case FcVStackTest:
1833             vstack->u.test->next = test;
1834             test = vstack->u.test;
1835             vstack->tag = FcVStackNone;
1836             break;
1837         case FcVStackEdit:
1838             vstack->u.edit->next = edit;
1839             edit = vstack->u.edit;
1840             vstack->tag = FcVStackNone;
1841             break;
1842         default:
1843             FcConfigMessage (parse, FcSevereWarning, "invalid match element");
1844             break;
1845         }
1846         FcVStackDestroy (vstack);
1847     }
1848     if (!FcConfigAddEdit (parse->config, test, edit, kind))
1849         FcConfigMessage (parse, FcSevereError, "out of memory");
1850 }
1851
1852 static void
1853 FcParseAcceptRejectFont (FcConfigParse *parse, FcElement element)
1854 {
1855     FcVStack    *vstack;
1856
1857     while ((vstack = FcVStackPop (parse)))
1858     {
1859         switch (vstack->tag) {
1860         case FcVStackGlob:
1861             if (!FcConfigGlobAdd (parse->config, 
1862                                   vstack->u.string,
1863                                   element == FcElementAcceptfont))
1864             {
1865                 FcConfigMessage (parse, FcSevereError, "out of memory");
1866             }
1867             break;
1868         case FcVStackPattern:
1869             if (!FcConfigPatternsAdd (parse->config,
1870                                       vstack->u.pattern,
1871                                       element == FcElementAcceptfont))
1872             {
1873                 FcConfigMessage (parse, FcSevereError, "out of memory");
1874             }
1875             else
1876                 vstack->tag = FcVStackNone;
1877             break;
1878         default:
1879             FcConfigMessage (parse, FcSevereWarning, "bad font selector");
1880             break;
1881         }
1882         FcVStackDestroy (vstack);
1883     }
1884 }
1885
1886
1887 static FcValue
1888 FcPopValue (FcConfigParse *parse)
1889 {
1890     FcVStack    *vstack = FcVStackPop (parse);
1891     FcValue     value;
1892     
1893     value.type = FcTypeVoid;
1894     
1895     if (!vstack)
1896         return value;
1897     
1898     switch (vstack->tag) {
1899     case FcVStackString:
1900         value.u.s = FcStrCopy (vstack->u.string);
1901         if (value.u.s)
1902             value.type = FcTypeString;
1903         break;
1904     case FcVStackConstant:
1905         if (FcNameConstant (vstack->u.string, &value.u.i))
1906             value.type = FcTypeInteger;
1907         break;
1908     case FcVStackInteger:
1909         value.u.i = vstack->u.integer;
1910         value.type = FcTypeInteger;
1911         break;
1912     case FcVStackDouble:
1913         value.u.d = vstack->u._double;
1914         value.type = FcTypeInteger;
1915         break;
1916     case FcVStackMatrix:
1917         value.u.m = FcMatrixCopy (vstack->u.matrix);
1918         if (value.u.m)
1919             value.type = FcTypeMatrix;
1920         break;
1921     case FcVStackBool:
1922         value.u.b = vstack->u.bool;
1923         value.type = FcTypeBool;
1924         break;
1925     default:
1926         FcConfigMessage (parse, FcSevereWarning, "unknown pattern element %d", 
1927                          vstack->tag);
1928         break;
1929     }
1930     FcVStackDestroy (vstack);
1931     
1932     return value;
1933 }
1934
1935 static void
1936 FcParsePatelt (FcConfigParse *parse)
1937 {
1938     FcValue     value;
1939     FcPattern   *pattern = FcPatternCreate ();
1940     const char  *name;
1941
1942     if (!pattern)
1943     {
1944         FcConfigMessage (parse, FcSevereError, "out of memory");
1945         return;
1946     }
1947
1948     name = (char *) FcConfigGetAttribute (parse, "name");
1949     if (!name)
1950     {
1951         FcConfigMessage (parse, FcSevereWarning, "missing pattern element name");
1952         return;
1953     }
1954     
1955     for (;;)
1956     {
1957         value = FcPopValue (parse);
1958         if (value.type == FcTypeVoid)
1959             break;
1960         if (!FcPatternAdd (pattern, name, value, FcTrue))
1961         {
1962             FcConfigMessage (parse, FcSevereError, "out of memory");
1963             break;
1964         }
1965     }
1966
1967     FcVStackPushPattern (parse, pattern);
1968 }
1969
1970 static void
1971 FcParsePattern (FcConfigParse *parse)
1972 {
1973     FcVStack    *vstack;
1974     FcPattern   *pattern = FcPatternCreate ();
1975
1976     if (!pattern)
1977     {
1978         FcConfigMessage (parse, FcSevereError, "out of memory");
1979         return;
1980     }
1981         
1982     while ((vstack = FcVStackPop (parse)))
1983     {
1984         switch (vstack->tag) {
1985         case FcVStackPattern:
1986             if (!FcPatternAppend (pattern, vstack->u.pattern))
1987             {
1988                 FcConfigMessage (parse, FcSevereError, "out of memory");
1989                 return;
1990             }
1991             break;
1992         default:
1993             FcConfigMessage (parse, FcSevereWarning, "unknown pattern element");
1994             break;
1995         }
1996         FcVStackDestroy (vstack);
1997     }
1998
1999     FcVStackPushPattern (parse, pattern);
2000 }
2001
2002 static void
2003 FcEndElement(void *userData, const XML_Char *name)
2004 {
2005     FcConfigParse   *parse = userData;
2006     FcChar8         *data;
2007     
2008     if (!parse->pstack)
2009         return;
2010     switch (parse->pstack->element) {
2011     case FcElementNone:
2012         break;
2013     case FcElementFontconfig:
2014         break;
2015     case FcElementDir:
2016         data = FcStrBufDone (&parse->pstack->str);
2017         if (!data)
2018         {
2019             FcConfigMessage (parse, FcSevereError, "out of memory");
2020             break;
2021         }
2022 #ifdef _WIN32
2023         if (strcmp (data, "WINDOWSFONTDIR") == 0)
2024         {
2025             int rc;
2026             FcStrFree (data);
2027             data = malloc (1000);
2028             if (!data)
2029             {
2030                 FcConfigMessage (parse, FcSevereError, "out of memory");
2031                 break;
2032             }
2033             FcMemAlloc (FC_MEM_STRING, 1000);
2034             rc = GetWindowsDirectory (data, 800);
2035             if (rc == 0 || rc > 800)
2036             {
2037                 FcConfigMessage (parse, FcSevereError, "GetWindowsDirectory failed");
2038                 FcStrFree (data);
2039                 break;
2040             }
2041             if (data [strlen (data) - 1] != '\\')
2042                 strcat (data, "\\");
2043             strcat (data, "fonts");
2044         }
2045 #endif
2046         if (!FcStrUsesHome (data) || FcConfigHome ())
2047         {
2048             if (!FcConfigAddDir (parse->config, data))
2049                 FcConfigMessage (parse, FcSevereError, "out of memory");
2050         }
2051         FcStrFree (data);
2052         break;
2053     case FcElementCache:
2054         data = FcStrBufDone (&parse->pstack->str);
2055         if (!data)
2056         {
2057             FcConfigMessage (parse, FcSevereError, "out of memory");
2058             break;
2059         }
2060         if (!FcStrUsesHome (data) || FcConfigHome ())
2061         {
2062             if (!FcConfigSetCache (parse->config, data))
2063                 FcConfigMessage (parse, FcSevereError, "out of memory");
2064         }
2065         FcStrFree (data);
2066         break;
2067     case FcElementInclude:
2068         FcParseInclude (parse);
2069         break;
2070     case FcElementConfig:
2071         break;
2072     case FcElementMatch:
2073         FcParseMatch (parse);
2074         break;
2075     case FcElementAlias:
2076         FcParseAlias (parse);
2077         break;
2078
2079     case FcElementBlank:
2080         FcParseBlank (parse);
2081         break;
2082     case FcElementRescan:
2083         FcParseRescan (parse);
2084         break;
2085         
2086     case FcElementPrefer:
2087         FcParseFamilies (parse, FcVStackPrefer);
2088         break;
2089     case FcElementAccept:
2090         FcParseFamilies (parse, FcVStackAccept);
2091         break;
2092     case FcElementDefault:
2093         FcParseFamilies (parse, FcVStackDefault);
2094         break;
2095     case FcElementFamily:
2096         FcParseFamily (parse);
2097         break;
2098
2099     case FcElementTest:
2100         FcParseTest (parse);
2101         break;
2102     case FcElementEdit:
2103         FcParseEdit (parse);
2104         break;
2105
2106     case FcElementInt:
2107         FcParseInt (parse);
2108         break;
2109     case FcElementDouble:
2110         FcParseDouble (parse);
2111         break;
2112     case FcElementString:
2113         FcParseString (parse, FcVStackString);
2114         break;
2115     case FcElementMatrix:
2116         FcParseMatrix (parse);
2117         break;
2118     case FcElementBool:
2119         FcParseBool (parse);
2120         break;
2121     case FcElementCharset:
2122 /*      FcParseCharset (parse); */
2123         break;
2124     case FcElementSelectfont:
2125         break;
2126     case FcElementAcceptfont:
2127     case FcElementRejectfont:
2128         FcParseAcceptRejectFont (parse, parse->pstack->element);
2129         break;
2130     case FcElementGlob:
2131         FcParseString (parse, FcVStackGlob);
2132         break;
2133     case FcElementPattern:
2134         FcParsePattern (parse);
2135         break;
2136     case FcElementPatelt:
2137         FcParsePatelt (parse);
2138         break;
2139     case FcElementName:
2140         FcParseString (parse, FcVStackField);
2141         break;
2142     case FcElementConst:
2143         FcParseString (parse, FcVStackConstant);
2144         break;
2145     case FcElementOr:
2146         FcParseBinary (parse, FcOpOr);
2147         break;
2148     case FcElementAnd:
2149         FcParseBinary (parse, FcOpAnd);
2150         break;
2151     case FcElementEq:
2152         FcParseBinary (parse, FcOpEqual);
2153         break;
2154     case FcElementNotEq:
2155         FcParseBinary (parse, FcOpNotEqual);
2156         break;
2157     case FcElementLess:
2158         FcParseBinary (parse, FcOpLess);
2159         break;
2160     case FcElementLessEq:
2161         FcParseBinary (parse, FcOpLessEqual);
2162         break;
2163     case FcElementMore:
2164         FcParseBinary (parse, FcOpMore);
2165         break;
2166     case FcElementMoreEq:
2167         FcParseBinary (parse, FcOpMoreEqual);
2168         break;
2169     case FcElementContains:
2170         FcParseBinary (parse, FcOpContains);
2171         break;
2172     case FcElementNotContains:
2173         FcParseBinary (parse, FcOpNotContains);
2174         break;
2175     case FcElementPlus:
2176         FcParseBinary (parse, FcOpPlus);
2177         break;
2178     case FcElementMinus:
2179         FcParseBinary (parse, FcOpMinus);
2180         break;
2181     case FcElementTimes:
2182         FcParseBinary (parse, FcOpTimes);
2183         break;
2184     case FcElementDivide:
2185         FcParseBinary (parse, FcOpDivide);
2186         break;
2187     case FcElementNot:
2188         FcParseUnary (parse, FcOpNot);
2189         break;
2190     case FcElementIf:
2191         FcParseBinary (parse, FcOpQuest);
2192         break;
2193     case FcElementFloor:
2194         FcParseUnary (parse, FcOpFloor);
2195         break;
2196     case FcElementCeil:
2197         FcParseUnary (parse, FcOpCeil);
2198         break;
2199     case FcElementRound:
2200         FcParseUnary (parse, FcOpRound);
2201         break;
2202     case FcElementTrunc:
2203         FcParseUnary (parse, FcOpTrunc);
2204         break;
2205     case FcElementUnknown:
2206         break;
2207     }
2208     (void) FcPStackPop (parse);
2209 }
2210
2211 static void
2212 FcCharacterData (void *userData, const XML_Char *s, int len)
2213 {
2214     FcConfigParse   *parse = userData;
2215     
2216     if (!parse->pstack)
2217         return;
2218     if (!FcStrBufData (&parse->pstack->str, (FcChar8 *) s, len))
2219         FcConfigMessage (parse, FcSevereError, "out of memory");
2220 }
2221
2222 static void
2223 FcStartDoctypeDecl (void            *userData,
2224                     const XML_Char  *doctypeName,
2225                     const XML_Char  *sysid,
2226                     const XML_Char  *pubid,
2227                     int             has_internal_subset)
2228 {
2229     FcConfigParse   *parse = userData;
2230
2231     if (strcmp ((char *) doctypeName, "fontconfig") != 0)
2232         FcConfigMessage (parse, FcSevereError, "invalid doctype \"%s\"", doctypeName);
2233 }
2234
2235 #if ENABLE_LIBXML2
2236
2237 static void
2238 FcInternalSubsetDecl (void            *userData,
2239                       const XML_Char  *doctypeName,
2240                       const XML_Char  *sysid,
2241                       const XML_Char  *pubid)
2242 {
2243     FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 1);
2244 }
2245
2246 static void
2247 FcExternalSubsetDecl (void            *userData,
2248                       const XML_Char  *doctypeName,
2249                       const XML_Char  *sysid,
2250                       const XML_Char  *pubid)
2251 {
2252     FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 0);
2253 }
2254
2255 #else /* ENABLE_LIBXML2 */
2256
2257 static void
2258 FcEndDoctypeDecl (void *userData)
2259 {
2260 }
2261
2262 #endif /* ENABLE_LIBXML2 */
2263
2264 static FcBool
2265 FcConfigParseAndLoadDir (FcConfig       *config,
2266                          const FcChar8  *name,
2267                          const FcChar8  *dir,
2268                          FcBool         complain)
2269 {
2270     DIR             *d;
2271     struct dirent   *e;
2272     FcBool          ret = FcTrue;
2273     FcChar8         *file;
2274     FcChar8         *base;
2275     FcStrSet        *files;
2276
2277     d = opendir ((char *) dir);
2278     if (!d)
2279     {
2280         if (complain)
2281             FcConfigMessage (0, FcSevereError, "Cannot open config dir \"%s\"",
2282                              name);
2283         ret = FcFalse;
2284         goto bail0;
2285     }
2286     /* freed below */
2287     file = (FcChar8 *) malloc (strlen ((char *) dir) + 1 + FC_MAX_FILE_LEN + 1);
2288     if (!file)
2289     {
2290         ret = FcFalse;
2291         goto bail1;
2292     }
2293     
2294     strcpy ((char *) file, (char *) dir);
2295     strcat ((char *) file, "/");
2296     base = file + strlen ((char *) file);
2297     
2298     files = FcStrSetCreate ();
2299     if (!files)
2300     {
2301         ret = FcFalse;
2302         goto bail2;
2303     }
2304     
2305     if (FcDebug () & FC_DBG_CONFIG)
2306         printf ("\tScanning config dir %s\n", dir);
2307         
2308     while (ret && (e = readdir (d)))
2309     {
2310         int d_len;
2311 #define TAIL        ".conf"
2312 #define TAIL_LEN    5
2313         /*
2314          * Add all files of the form [0-9]*.conf
2315          */
2316         if ('0' <= e->d_name[0] && e->d_name[0] <= '9' &&
2317             (d_len = strlen (e->d_name)) < FC_MAX_FILE_LEN &&
2318             d_len > TAIL_LEN &&
2319             strcmp (e->d_name + d_len - TAIL_LEN, TAIL) == 0)
2320         {
2321             strcpy ((char *) base, (char *) e->d_name);
2322             if (!FcStrSetAdd (files, file))
2323             {
2324                 ret = FcFalse;
2325                 goto bail3;
2326             }
2327         }
2328     }
2329     if (ret)
2330     {
2331         int i;
2332         qsort (files->strs, files->num, sizeof (FcChar8 *), 
2333                (int (*)(const void *, const void *)) FcStrCmp);
2334         for (i = 0; ret && i < files->num; i++)
2335             ret = FcConfigParseAndLoad (config, files->strs[i], complain);
2336     }
2337 bail3:
2338     FcStrSetDestroy (files);
2339 bail2:
2340     free (file);
2341 bail1:
2342     closedir (d);
2343 bail0:
2344     return ret || !complain;
2345 }
2346
2347 FcBool
2348 FcConfigParseAndLoad (FcConfig      *config,
2349                       const FcChar8 *name,
2350                       FcBool        complain)
2351 {
2352
2353     XML_Parser      p;
2354     FcChar8         *filename;
2355     FILE            *f;
2356     int             len;
2357     FcConfigParse   parse;
2358     FcBool          error = FcTrue;
2359     
2360 #if ENABLE_LIBXML2
2361     xmlSAXHandler   sax;
2362     char            buf[BUFSIZ];
2363 #else
2364     void            *buf;
2365 #endif
2366     
2367     filename = FcConfigFilename (name);
2368     if (!filename)
2369         goto bail0;
2370     
2371     if (FcStrSetMember (config->configFiles, filename))
2372     {
2373         FcStrFree (filename);
2374         return FcTrue;
2375     }
2376
2377     if (!FcStrSetAdd (config->configFiles, filename))
2378     {
2379         FcStrFree (filename);
2380         goto bail0;
2381     }
2382
2383     if (FcFileIsDir (filename))
2384     {
2385         FcBool ret = FcConfigParseAndLoadDir (config, name, filename, complain);
2386         FcStrFree (filename);
2387         return ret;
2388     }
2389
2390     if (FcDebug () & FC_DBG_CONFIG)
2391         printf ("\tLoading config file %s\n", filename);
2392
2393     f = fopen ((char *) filename, "r");
2394     if (!f) { 
2395         FcStrFree (filename);
2396         goto bail0;
2397     }
2398     
2399 #if ENABLE_LIBXML2
2400     memset(&sax, 0, sizeof(sax));
2401
2402     sax.internalSubset = FcInternalSubsetDecl;
2403     sax.externalSubset = FcExternalSubsetDecl;
2404     sax.startElement = FcStartElement;
2405     sax.endElement = FcEndElement;
2406     sax.characters = FcCharacterData;
2407
2408     p = xmlCreatePushParserCtxt (&sax, &parse, NULL, 0, (const char *) filename);
2409 #else
2410     p = XML_ParserCreate ("UTF-8");
2411 #endif
2412     FcStrFree (filename);
2413
2414     if (!p)
2415         goto bail1;
2416
2417     if (!FcConfigInit (&parse, name, config, p))
2418         goto bail2;
2419
2420 #if !ENABLE_LIBXML2
2421
2422     XML_SetUserData (p, &parse);
2423     
2424     XML_SetDoctypeDeclHandler (p, FcStartDoctypeDecl, FcEndDoctypeDecl);
2425     XML_SetElementHandler (p, FcStartElement, FcEndElement);
2426     XML_SetCharacterDataHandler (p, FcCharacterData);
2427         
2428 #endif /* ENABLE_LIBXML2 */
2429
2430     do {
2431 #if !ENABLE_LIBXML2
2432         buf = XML_GetBuffer (p, BUFSIZ);
2433         if (!buf)
2434         {
2435             FcConfigMessage (&parse, FcSevereError, "cannot get parse buffer");
2436             goto bail3;
2437         }
2438 #endif
2439         len = fread (buf, 1, BUFSIZ, f);
2440         if (len < 0)
2441         {
2442             FcConfigMessage (&parse, FcSevereError, "failed reading config file");
2443             goto bail3;
2444         }
2445
2446 #if ENABLE_LIBXML2
2447         if (xmlParseChunk (p, buf, len, len == 0))
2448 #else
2449         if (!XML_ParseBuffer (p, len, len == 0))
2450 #endif
2451         {
2452             FcConfigMessage (&parse, FcSevereError, "%s", 
2453                            XML_ErrorString (XML_GetErrorCode (p)));
2454             goto bail3;
2455         }
2456     } while (len != 0);
2457     error = parse.error;
2458 bail3:
2459     FcConfigCleanup (&parse);
2460 bail2:
2461     XML_ParserFree (p);
2462 bail1:
2463     fclose (f);
2464     f = NULL;
2465 bail0:
2466     if (error && complain)
2467     {
2468         if (name)
2469             FcConfigMessage (0, FcSevereError, "Cannot load config file \"%s\"", name);
2470         else
2471             FcConfigMessage (0, FcSevereError, "Cannot load default config file");
2472         return FcFalse;
2473     }
2474     return FcTrue;
2475 }