]> git.wh0rd.org Git - fontconfig.git/blob - src/fcxml.c
Rework cache files to use offsets for all data structures.
[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     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.object = FcObjectFromName (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         break;
221     case FcOpConst:
222         FcStrFree (e->u.constant);
223         break;
224     case FcOpAssign:
225     case FcOpAssignReplace:
226     case FcOpPrepend:
227     case FcOpPrependFirst:
228     case FcOpAppend:
229     case FcOpAppendLast:
230         break;
231     case FcOpOr:
232     case FcOpAnd:
233     case FcOpEqual:
234     case FcOpNotEqual:
235     case FcOpLess:
236     case FcOpLessEqual:
237     case FcOpMore:
238     case FcOpMoreEqual:
239     case FcOpContains:
240     case FcOpListing:
241     case FcOpNotContains:
242     case FcOpPlus:
243     case FcOpMinus:
244     case FcOpTimes:
245     case FcOpDivide:
246     case FcOpQuest:
247     case FcOpComma:
248         FcExprDestroy (e->u.tree.right);
249         /* fall through */
250     case FcOpNot:
251     case FcOpFloor:
252     case FcOpCeil:
253     case FcOpRound:
254     case FcOpTrunc:
255         FcExprDestroy (e->u.tree.left);
256         break;
257     case FcOpNil:
258     case FcOpInvalid:
259         break;
260     }
261     FcMemFree (FC_MEM_EXPR, sizeof (FcExpr));
262     free (e);
263 }
264
265 void
266 FcEditDestroy (FcEdit *e)
267 {
268     if (e->next)
269         FcEditDestroy (e->next);
270     if (e->expr)
271         FcExprDestroy (e->expr);
272     free (e);
273 }
274
275 char *
276 FcConfigSaveField (const char *field)
277 {
278     return (char *) FcStrCopy ((FcChar8 *) field);
279 }
280
281 typedef enum _FcElement {
282     FcElementNone,
283     FcElementFontconfig,
284     FcElementDir,
285     FcElementCacheDir,
286     FcElementCache,
287     FcElementInclude,
288     FcElementConfig,
289     FcElementMatch,
290     FcElementAlias,
291         
292     FcElementBlank,
293     FcElementRescan,
294
295     FcElementPrefer,
296     FcElementAccept,
297     FcElementDefault,
298     FcElementFamily,
299
300     FcElementSelectfont,
301     FcElementAcceptfont,
302     FcElementRejectfont,
303     FcElementGlob,
304     FcElementPattern,
305     FcElementPatelt,
306
307     FcElementTest,
308     FcElementEdit,
309     FcElementInt,
310     FcElementDouble,
311     FcElementString,
312     FcElementMatrix,
313     FcElementBool,
314     FcElementCharset,
315     FcElementName,
316     FcElementConst,
317     FcElementOr,
318     FcElementAnd,
319     FcElementEq,
320     FcElementNotEq,
321     FcElementLess,
322     FcElementLessEq,
323     FcElementMore,
324     FcElementMoreEq,
325     FcElementContains,
326     FcElementNotContains,
327     FcElementPlus,
328     FcElementMinus,
329     FcElementTimes,
330     FcElementDivide,
331     FcElementNot,
332     FcElementIf,
333     FcElementFloor,
334     FcElementCeil,
335     FcElementRound,
336     FcElementTrunc,
337     FcElementUnknown
338 } FcElement;
339
340 static const struct {
341     const char  name[16];
342     FcElement   element;
343 } fcElementMap[] = {
344     { "fontconfig",     FcElementFontconfig },
345     { "dir",            FcElementDir },
346     { "cachedir",       FcElementCacheDir },
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, (int)XML_GetCurrentLineNumber (parse->parser));
496         else
497             fprintf (stderr, "Fontconfig %s: line %d: ", s,
498                      (int)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 (FcObjectName (expr->u.object));
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->object = FcObjectFromName ((const char *) field);
660         test->op = compare;
661         test->expr = expr;
662         o = FcNameGetObjectType (FcObjectName (test->object));
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->object = FcObjectFromName (field);
684         e->op = op;
685         e->expr = expr;
686         e->binding = binding;
687         o = FcNameGetObjectType (FcObjectName (e->object));
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         slen;
927     int         i;
928     FcChar8     **new;
929     FcChar8     *s;
930
931     if (!attr)
932         return 0;
933     slen = 0;
934     for (i = 0; attr[i]; i++)
935         slen += strlen ((char *) attr[i]) + 1;
936     new = malloc ((i + 1) * sizeof (FcChar8 *) + slen);
937     if (!new)
938         return 0;
939     FcMemAlloc (FC_MEM_ATTR, 1);    /* size is too expensive */
940     s = (FcChar8 *) (new + (i + 1));
941     for (i = 0; attr[i]; i++)
942     {
943         new[i] = s;
944         strcpy ((char *) s, (char *) attr[i]);
945         s += strlen ((char *) s) + 1;
946     }
947     new[i] = 0;
948     return new;
949 }
950
951 static FcBool
952 FcPStackPush (FcConfigParse *parse, FcElement element, const XML_Char **attr)
953 {
954     FcPStack   *new = malloc (sizeof (FcPStack));
955
956     if (!new)
957         return FcFalse;
958     FcMemAlloc (FC_MEM_PSTACK, sizeof (FcPStack));
959     new->prev = parse->pstack;
960     new->element = element;
961     if (attr)
962     {
963         new->attr = FcConfigSaveAttr (attr);
964         if (!new->attr)
965             FcConfigMessage (parse, FcSevereError, "out of memory");
966     }
967     else
968         new->attr = 0;
969     FcStrBufInit (&new->str, 0, 0);
970     parse->pstack = new;
971     return FcTrue;
972 }
973
974 static FcBool
975 FcPStackPop (FcConfigParse *parse)
976 {
977     FcPStack   *old;
978     
979     if (!parse->pstack) 
980     {
981         FcConfigMessage (parse, FcSevereError, "mismatching element");
982         return FcFalse;
983     }
984     FcVStackClear (parse);
985     old = parse->pstack;
986     parse->pstack = old->prev;
987     FcStrBufDestroy (&old->str);
988     if (old->attr)
989     {
990         FcMemFree (FC_MEM_ATTR, 1); /* size is to expensive */
991         free (old->attr);
992     }
993     FcMemFree (FC_MEM_PSTACK, sizeof (FcPStack));
994     free (old);
995     return FcTrue;
996 }
997
998 static FcBool
999 FcConfigInit (FcConfigParse *parse, const FcChar8 *name, FcConfig *config, XML_Parser parser)
1000 {
1001     parse->pstack = 0;
1002     parse->vstack = 0;
1003     parse->error = FcFalse;
1004     parse->name = name;
1005     parse->config = config;
1006     parse->parser = parser;
1007     return FcTrue;
1008 }
1009
1010 static void
1011 FcConfigCleanup (FcConfigParse  *parse)
1012 {
1013     while (parse->pstack)
1014         FcPStackPop (parse);
1015 }
1016
1017 static const FcChar8 *
1018 FcConfigGetAttribute (FcConfigParse *parse, const char *attr)
1019 {
1020     FcChar8 **attrs;
1021     if (!parse->pstack)
1022         return 0;
1023
1024     attrs = parse->pstack->attr;
1025     if (!attrs)
1026         return 0;
1027
1028     while (*attrs)
1029     {
1030         if (!strcmp ((char *) *attrs, attr))
1031             return attrs[1];
1032         attrs += 2;
1033     }
1034     return 0;
1035 }
1036
1037 static void
1038 FcStartElement(void *userData, const XML_Char *name, const XML_Char **attr)
1039 {
1040     FcConfigParse   *parse = userData;
1041     FcElement       element;
1042     
1043     element = FcElementMap (name);
1044     if (element == FcElementUnknown)
1045         FcConfigMessage (parse, FcSevereWarning, "unknown element \"%s\"", name);
1046     
1047     if (!FcPStackPush (parse, element, attr))
1048     {
1049         FcConfigMessage (parse, FcSevereError, "out of memory");
1050         return;
1051     }
1052     return;
1053 }
1054
1055 static void
1056 FcParseBlank (FcConfigParse *parse)
1057 {
1058     int     n = FcVStackElements (parse);
1059     while (n-- > 0)
1060     {
1061         FcVStack    *v = FcVStackFetch (parse, n);
1062         if (v->tag != FcVStackInteger)
1063             FcConfigMessage (parse, FcSevereError, "non-integer blank");
1064         else
1065         {
1066             if (!parse->config->blanks)
1067             {
1068                 parse->config->blanks = FcBlanksCreate ();
1069                 if (!parse->config->blanks)
1070                 {
1071                     FcConfigMessage (parse, FcSevereError, "out of memory");
1072                     break;
1073                 }
1074             }
1075             if (!FcBlanksAdd (parse->config->blanks, v->u.integer))
1076             {
1077                 FcConfigMessage (parse, FcSevereError, "out of memory");
1078                 break;
1079             }
1080         }
1081     }
1082 }
1083
1084 static void
1085 FcParseRescan (FcConfigParse *parse)
1086 {
1087     int     n = FcVStackElements (parse);
1088     while (n-- > 0)
1089     {
1090         FcVStack    *v = FcVStackFetch (parse, n);
1091         if (v->tag != FcVStackInteger)
1092             FcConfigMessage (parse, FcSevereWarning, "non-integer rescan");
1093         else
1094             parse->config->rescanInterval = v->u.integer;
1095     }
1096 }
1097
1098 static void
1099 FcParseInt (FcConfigParse *parse)
1100 {
1101     FcChar8 *s, *end;
1102     int     l;
1103     
1104     if (!parse->pstack)
1105         return;
1106     s = FcStrBufDone (&parse->pstack->str);
1107     if (!s)
1108     {
1109         FcConfigMessage (parse, FcSevereError, "out of memory");
1110         return;
1111     }
1112     end = 0;
1113     l = (int) strtol ((char *) s, (char **)&end, 0);
1114     if (end != s + strlen ((char *) s))
1115         FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid integer", s);
1116     else
1117         FcVStackPushInteger (parse, l);
1118     FcStrFree (s);
1119 }
1120
1121 /*
1122  * idea copied from glib g_ascii_strtod with 
1123  * permission of the author (Alexander Larsson) 
1124  */
1125
1126 #include <locale.h>
1127
1128 static double 
1129 FcStrtod (char *s, char **end)
1130 {
1131     struct lconv    *locale_data;
1132     char            *dot;
1133     double          v;
1134
1135     /*
1136      * Have to swap the decimal point to match the current locale
1137      * if that locale doesn't use 0x2e
1138      */
1139     if ((dot = strchr (s, 0x2e)) &&
1140         (locale_data = localeconv ()) &&
1141         (locale_data->decimal_point[0] != 0x2e ||
1142          locale_data->decimal_point[1] != 0))
1143     {
1144         char    buf[128];
1145         int     slen = strlen (s);
1146         int     dlen = strlen (locale_data->decimal_point);
1147         
1148         if (slen + dlen > (int) sizeof (buf))
1149         {
1150             if (end)
1151                 *end = s;
1152             v = 0;
1153         }
1154         else
1155         {
1156             char        *buf_end;
1157             /* mantissa */
1158             strncpy (buf, s, dot - s);
1159             /* decimal point */
1160             strcpy (buf + (dot - s), locale_data->decimal_point);
1161             /* rest of number */
1162             strcpy (buf + (dot - s) + dlen, dot + 1);
1163             buf_end = 0;
1164             v = strtod (buf, &buf_end);
1165             if (buf_end) {
1166                 buf_end = s + (buf_end - buf);
1167                 if (buf_end > dot)
1168                     buf_end -= dlen - 1;
1169             }
1170             if (end)
1171                 *end = buf_end;
1172         }
1173     }
1174     else
1175         v = strtod (s, end);
1176     return v;
1177 }
1178
1179 static void
1180 FcParseDouble (FcConfigParse *parse)
1181 {
1182     FcChar8 *s, *end;
1183     double  d;
1184     
1185     if (!parse->pstack)
1186         return;
1187     s = FcStrBufDone (&parse->pstack->str);
1188     if (!s)
1189     {
1190         FcConfigMessage (parse, FcSevereError, "out of memory");
1191         return;
1192     }
1193     end = 0;
1194     d = FcStrtod ((char *) s, (char **)&end);
1195     if (end != s + strlen ((char *) s))
1196         FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid double", s);
1197     else
1198         FcVStackPushDouble (parse, d);
1199     FcStrFree (s);
1200 }
1201
1202 static void
1203 FcParseString (FcConfigParse *parse, FcVStackTag tag)
1204 {
1205     FcChar8 *s;
1206     
1207     if (!parse->pstack)
1208         return;
1209     s = FcStrBufDone (&parse->pstack->str);
1210     if (!s)
1211     {
1212         FcConfigMessage (parse, FcSevereError, "out of memory");
1213         return;
1214     }
1215     if (!FcVStackPushString (parse, tag, s))
1216         FcStrFree (s);
1217 }
1218
1219 static void
1220 FcParseMatrix (FcConfigParse *parse)
1221 {
1222     FcVStack    *vstack;
1223     enum { m_done, m_xx, m_xy, m_yx, m_yy } matrix_state = m_yy;
1224     FcMatrix    m;
1225     
1226     while ((vstack = FcVStackPop (parse)))
1227     {
1228         double  v;
1229         switch (vstack->tag) {
1230         case FcVStackInteger:
1231             v = vstack->u.integer;
1232             break;
1233         case FcVStackDouble:
1234             v = vstack->u._double;
1235             break;
1236         default:
1237             FcConfigMessage (parse, FcSevereError, "non-double matrix element");
1238             v = 1.0;
1239             break;
1240         }
1241         switch (matrix_state) {
1242         case m_xx: m.xx = v; break;
1243         case m_xy: m.xy = v; break;
1244         case m_yx: m.yx = v; break;
1245         case m_yy: m.yy = v; break;
1246         default: break;
1247         }
1248         FcVStackDestroy (vstack);
1249         matrix_state--;
1250     }
1251     if (matrix_state != m_done)
1252         FcConfigMessage (parse, FcSevereError, "wrong number of matrix elements");
1253     else
1254         FcVStackPushMatrix (parse, &m);
1255 }
1256
1257 static FcBool
1258 FcConfigLexBool (FcConfigParse *parse, const FcChar8 *bool)
1259 {
1260     FcBool  result = FcFalse;
1261
1262     if (!FcNameBool (bool, &result))
1263         FcConfigMessage (parse, FcSevereWarning, "\"%s\" is not known boolean",
1264                          bool);
1265     return result;
1266 }
1267
1268 static void
1269 FcParseBool (FcConfigParse *parse)
1270 {
1271     FcChar8 *s;
1272
1273     if (!parse->pstack)
1274         return;
1275     s = FcStrBufDone (&parse->pstack->str);
1276     if (!s)
1277     {
1278         FcConfigMessage (parse, FcSevereError, "out of memory");
1279         return;
1280     }
1281     FcVStackPushBool (parse, FcConfigLexBool (parse, s));
1282     FcStrFree (s);
1283 }
1284
1285 static void
1286 FcParseFamilies (FcConfigParse *parse, FcVStackTag tag)
1287 {
1288     FcVStack    *vstack;
1289     FcExpr      *left, *expr = 0, *new;
1290
1291     while ((vstack = FcVStackPop (parse)))
1292     {
1293         if (vstack->tag != FcVStackFamily)
1294         {
1295             FcConfigMessage (parse, FcSevereWarning, "non-family");
1296             FcVStackDestroy (vstack);
1297             continue;
1298         }
1299         left = vstack->u.expr;
1300         vstack->tag = FcVStackNone;
1301         FcVStackDestroy (vstack);
1302         if (expr)
1303         {
1304             new = FcExprCreateOp (left, FcOpComma, expr);
1305             if (!new)
1306             {
1307                 FcConfigMessage (parse, FcSevereError, "out of memory");
1308                 FcExprDestroy (left);
1309                 FcExprDestroy (expr);
1310                 break;
1311             }
1312             expr = new;
1313         }
1314         else
1315             expr = left;
1316     }
1317     if (expr)
1318     {
1319         if (!FcVStackPushExpr (parse, tag, expr))
1320         {
1321             FcConfigMessage (parse, FcSevereError, "out of memory");
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                 return 0;
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         FcPatternDestroy (pattern);
1953         return;
1954     }
1955     
1956     for (;;)
1957     {
1958         value = FcPopValue (parse);
1959         if (value.type == FcTypeVoid)
1960             break;
1961         if (!FcPatternAdd (pattern, name, value, FcTrue))
1962         {
1963             FcConfigMessage (parse, FcSevereError, "out of memory");
1964             break;
1965         }
1966     }
1967
1968     FcVStackPushPattern (parse, pattern);
1969 }
1970
1971 static void
1972 FcParsePattern (FcConfigParse *parse)
1973 {
1974     FcVStack    *vstack;
1975     FcPattern   *pattern = FcPatternCreate ();
1976
1977     if (!pattern)
1978     {
1979         FcConfigMessage (parse, FcSevereError, "out of memory");
1980         return;
1981     }
1982         
1983     while ((vstack = FcVStackPop (parse)))
1984     {
1985         switch (vstack->tag) {
1986         case FcVStackPattern:
1987             if (!FcPatternAppend (pattern, vstack->u.pattern))
1988             {
1989                 FcConfigMessage (parse, FcSevereError, "out of memory");
1990                 FcPatternDestroy (pattern);
1991                 return;
1992             }
1993             break;
1994         default:
1995             FcConfigMessage (parse, FcSevereWarning, "unknown pattern element");
1996             break;
1997         }
1998         FcVStackDestroy (vstack);
1999     }
2000
2001     FcVStackPushPattern (parse, pattern);
2002 }
2003
2004 static void
2005 FcEndElement(void *userData, const XML_Char *name)
2006 {
2007     FcConfigParse   *parse = userData;
2008     FcChar8         *data;
2009     
2010     if (!parse->pstack)
2011         return;
2012     switch (parse->pstack->element) {
2013     case FcElementNone:
2014         break;
2015     case FcElementFontconfig:
2016         break;
2017     case FcElementDir:
2018         data = FcStrBufDone (&parse->pstack->str);
2019         if (!data)
2020         {
2021             FcConfigMessage (parse, FcSevereError, "out of memory");
2022             break;
2023         }
2024 #ifdef _WIN32
2025         if (strcmp (data, "WINDOWSFONTDIR") == 0)
2026         {
2027             int rc;
2028             FcStrFree (data);
2029             data = malloc (1000);
2030             if (!data)
2031             {
2032                 FcConfigMessage (parse, FcSevereError, "out of memory");
2033                 break;
2034             }
2035             FcMemAlloc (FC_MEM_STRING, 1000);
2036             rc = GetWindowsDirectory (data, 800);
2037             if (rc == 0 || rc > 800)
2038             {
2039                 FcConfigMessage (parse, FcSevereError, "GetWindowsDirectory failed");
2040                 FcStrFree (data);
2041                 break;
2042             }
2043             if (data [strlen (data) - 1] != '\\')
2044                 strcat (data, "\\");
2045             strcat (data, "fonts");
2046         }
2047 #endif
2048         if (!FcStrUsesHome (data) || FcConfigHome ())
2049         {
2050             if (!FcConfigAddDir (parse->config, data))
2051                 FcConfigMessage (parse, FcSevereError, "out of memory; cannot add directory %s", data);
2052         }
2053         FcStrFree (data);
2054         break;
2055     case FcElementCacheDir:
2056         data = FcStrBufDone (&parse->pstack->str);
2057         if (!data)
2058         {
2059             FcConfigMessage (parse, FcSevereError, "out of memory");
2060             break;
2061         }
2062         if (!FcStrUsesHome (data) || FcConfigHome ())
2063         {
2064             if (!FcConfigAddCacheDir (parse->config, data))
2065                 FcConfigMessage (parse, FcSevereError, "out of memory; cannot add cache directory %s", data);
2066         }
2067         FcStrFree (data);
2068         break;
2069         
2070     case FcElementCache:
2071         data = FcStrBufDone (&parse->pstack->str);
2072         if (!data)
2073         {
2074             FcConfigMessage (parse, FcSevereError, "out of memory");
2075             break;
2076         }
2077         if (!FcStrUsesHome (data) || FcConfigHome ())
2078         {
2079             if (!FcConfigSetCache (parse->config, data))
2080                 FcConfigMessage (parse, FcSevereError, "out of memory");
2081         }
2082         FcStrFree (data);
2083         break;
2084     case FcElementInclude:
2085         FcParseInclude (parse);
2086         break;
2087     case FcElementConfig:
2088         break;
2089     case FcElementMatch:
2090         FcParseMatch (parse);
2091         break;
2092     case FcElementAlias:
2093         FcParseAlias (parse);
2094         break;
2095
2096     case FcElementBlank:
2097         FcParseBlank (parse);
2098         break;
2099     case FcElementRescan:
2100         FcParseRescan (parse);
2101         break;
2102         
2103     case FcElementPrefer:
2104         FcParseFamilies (parse, FcVStackPrefer);
2105         break;
2106     case FcElementAccept:
2107         FcParseFamilies (parse, FcVStackAccept);
2108         break;
2109     case FcElementDefault:
2110         FcParseFamilies (parse, FcVStackDefault);
2111         break;
2112     case FcElementFamily:
2113         FcParseFamily (parse);
2114         break;
2115
2116     case FcElementTest:
2117         FcParseTest (parse);
2118         break;
2119     case FcElementEdit:
2120         FcParseEdit (parse);
2121         break;
2122
2123     case FcElementInt:
2124         FcParseInt (parse);
2125         break;
2126     case FcElementDouble:
2127         FcParseDouble (parse);
2128         break;
2129     case FcElementString:
2130         FcParseString (parse, FcVStackString);
2131         break;
2132     case FcElementMatrix:
2133         FcParseMatrix (parse);
2134         break;
2135     case FcElementBool:
2136         FcParseBool (parse);
2137         break;
2138     case FcElementCharset:
2139 /*      FcParseCharset (parse); */
2140         break;
2141     case FcElementSelectfont:
2142         break;
2143     case FcElementAcceptfont:
2144     case FcElementRejectfont:
2145         FcParseAcceptRejectFont (parse, parse->pstack->element);
2146         break;
2147     case FcElementGlob:
2148         FcParseString (parse, FcVStackGlob);
2149         break;
2150     case FcElementPattern:
2151         FcParsePattern (parse);
2152         break;
2153     case FcElementPatelt:
2154         FcParsePatelt (parse);
2155         break;
2156     case FcElementName:
2157         FcParseString (parse, FcVStackField);
2158         break;
2159     case FcElementConst:
2160         FcParseString (parse, FcVStackConstant);
2161         break;
2162     case FcElementOr:
2163         FcParseBinary (parse, FcOpOr);
2164         break;
2165     case FcElementAnd:
2166         FcParseBinary (parse, FcOpAnd);
2167         break;
2168     case FcElementEq:
2169         FcParseBinary (parse, FcOpEqual);
2170         break;
2171     case FcElementNotEq:
2172         FcParseBinary (parse, FcOpNotEqual);
2173         break;
2174     case FcElementLess:
2175         FcParseBinary (parse, FcOpLess);
2176         break;
2177     case FcElementLessEq:
2178         FcParseBinary (parse, FcOpLessEqual);
2179         break;
2180     case FcElementMore:
2181         FcParseBinary (parse, FcOpMore);
2182         break;
2183     case FcElementMoreEq:
2184         FcParseBinary (parse, FcOpMoreEqual);
2185         break;
2186     case FcElementContains:
2187         FcParseBinary (parse, FcOpContains);
2188         break;
2189     case FcElementNotContains:
2190         FcParseBinary (parse, FcOpNotContains);
2191         break;
2192     case FcElementPlus:
2193         FcParseBinary (parse, FcOpPlus);
2194         break;
2195     case FcElementMinus:
2196         FcParseBinary (parse, FcOpMinus);
2197         break;
2198     case FcElementTimes:
2199         FcParseBinary (parse, FcOpTimes);
2200         break;
2201     case FcElementDivide:
2202         FcParseBinary (parse, FcOpDivide);
2203         break;
2204     case FcElementNot:
2205         FcParseUnary (parse, FcOpNot);
2206         break;
2207     case FcElementIf:
2208         FcParseBinary (parse, FcOpQuest);
2209         break;
2210     case FcElementFloor:
2211         FcParseUnary (parse, FcOpFloor);
2212         break;
2213     case FcElementCeil:
2214         FcParseUnary (parse, FcOpCeil);
2215         break;
2216     case FcElementRound:
2217         FcParseUnary (parse, FcOpRound);
2218         break;
2219     case FcElementTrunc:
2220         FcParseUnary (parse, FcOpTrunc);
2221         break;
2222     case FcElementUnknown:
2223         break;
2224     }
2225     (void) FcPStackPop (parse);
2226 }
2227
2228 static void
2229 FcCharacterData (void *userData, const XML_Char *s, int len)
2230 {
2231     FcConfigParse   *parse = userData;
2232     
2233     if (!parse->pstack)
2234         return;
2235     if (!FcStrBufData (&parse->pstack->str, (FcChar8 *) s, len))
2236         FcConfigMessage (parse, FcSevereError, "out of memory");
2237 }
2238
2239 static void
2240 FcStartDoctypeDecl (void            *userData,
2241                     const XML_Char  *doctypeName,
2242                     const XML_Char  *sysid,
2243                     const XML_Char  *pubid,
2244                     int             has_internal_subset)
2245 {
2246     FcConfigParse   *parse = userData;
2247
2248     if (strcmp ((char *) doctypeName, "fontconfig") != 0)
2249         FcConfigMessage (parse, FcSevereError, "invalid doctype \"%s\"", doctypeName);
2250 }
2251
2252 #ifdef ENABLE_LIBXML2
2253
2254 static void
2255 FcInternalSubsetDecl (void            *userData,
2256                       const XML_Char  *doctypeName,
2257                       const XML_Char  *sysid,
2258                       const XML_Char  *pubid)
2259 {
2260     FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 1);
2261 }
2262
2263 static void
2264 FcExternalSubsetDecl (void            *userData,
2265                       const XML_Char  *doctypeName,
2266                       const XML_Char  *sysid,
2267                       const XML_Char  *pubid)
2268 {
2269     FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 0);
2270 }
2271
2272 #else /* ENABLE_LIBXML2 */
2273
2274 static void
2275 FcEndDoctypeDecl (void *userData)
2276 {
2277 }
2278
2279 #endif /* ENABLE_LIBXML2 */
2280
2281 static FcBool
2282 FcConfigParseAndLoadDir (FcConfig       *config,
2283                          const FcChar8  *name,
2284                          const FcChar8  *dir,
2285                          FcBool         complain)
2286 {
2287     DIR             *d;
2288     struct dirent   *e;
2289     FcBool          ret = FcTrue;
2290     FcChar8         *file;
2291     FcChar8         *base;
2292     FcStrSet        *files;
2293
2294     d = opendir ((char *) dir);
2295     if (!d)
2296     {
2297         if (complain)
2298             FcConfigMessage (0, FcSevereError, "Cannot open config dir \"%s\"",
2299                              name);
2300         ret = FcFalse;
2301         goto bail0;
2302     }
2303     /* freed below */
2304     file = (FcChar8 *) malloc (strlen ((char *) dir) + 1 + FC_MAX_FILE_LEN + 1);
2305     if (!file)
2306     {
2307         ret = FcFalse;
2308         goto bail1;
2309     }
2310     
2311     strcpy ((char *) file, (char *) dir);
2312     strcat ((char *) file, "/");
2313     base = file + strlen ((char *) file);
2314     
2315     files = FcStrSetCreate ();
2316     if (!files)
2317     {
2318         ret = FcFalse;
2319         goto bail2;
2320     }
2321     
2322     if (FcDebug () & FC_DBG_CONFIG)
2323         printf ("\tScanning config dir %s\n", dir);
2324         
2325     while (ret && (e = readdir (d)))
2326     {
2327         int d_len;
2328 #define TAIL        ".conf"
2329 #define TAIL_LEN    5
2330         /*
2331          * Add all files of the form [0-9]*.conf
2332          */
2333         if ('0' <= e->d_name[0] && e->d_name[0] <= '9' &&
2334             (d_len = strlen (e->d_name)) < FC_MAX_FILE_LEN &&
2335             d_len > TAIL_LEN &&
2336             strcmp (e->d_name + d_len - TAIL_LEN, TAIL) == 0)
2337         {
2338             strcpy ((char *) base, (char *) e->d_name);
2339             if (!FcStrSetAdd (files, file))
2340             {
2341                 ret = FcFalse;
2342                 goto bail3;
2343             }
2344         }
2345     }
2346     if (ret)
2347     {
2348         int i;
2349         qsort (files->strs, files->num, sizeof (FcChar8 *), 
2350                (int (*)(const void *, const void *)) FcStrCmp);
2351         for (i = 0; ret && i < files->num; i++)
2352             ret = FcConfigParseAndLoad (config, files->strs[i], complain);
2353     }
2354 bail3:
2355     FcStrSetDestroy (files);
2356 bail2:
2357     free (file);
2358 bail1:
2359     closedir (d);
2360 bail0:
2361     return ret || !complain;
2362 }
2363
2364 FcBool
2365 FcConfigParseAndLoad (FcConfig      *config,
2366                       const FcChar8 *name,
2367                       FcBool        complain)
2368 {
2369
2370     XML_Parser      p;
2371     FcChar8         *filename;
2372     int             fd;
2373     int             len;
2374     FcConfigParse   parse;
2375     FcBool          error = FcTrue;
2376     
2377 #ifdef ENABLE_LIBXML2
2378     xmlSAXHandler   sax;
2379     char            buf[BUFSIZ];
2380 #else
2381     void            *buf;
2382 #endif
2383     
2384     filename = FcConfigFilename (name);
2385     if (!filename)
2386         goto bail0;
2387     
2388     if (FcStrSetMember (config->configFiles, filename))
2389     {
2390         FcStrFree (filename);
2391         return FcTrue;
2392     }
2393
2394     if (!FcStrSetAdd (config->configFiles, filename))
2395     {
2396         FcStrFree (filename);
2397         goto bail0;
2398     }
2399
2400     if (FcFileIsDir (filename))
2401     {
2402         FcBool ret = FcConfigParseAndLoadDir (config, name, filename, complain);
2403         FcStrFree (filename);
2404         return ret;
2405     }
2406
2407     if (FcDebug () & FC_DBG_CONFIG)
2408         printf ("\tLoading config file %s\n", filename);
2409
2410     fd = open ((char *) filename, O_RDONLY);
2411     if (fd == -1) { 
2412         FcStrFree (filename);
2413         goto bail0;
2414     }
2415     
2416 #ifdef ENABLE_LIBXML2
2417     memset(&sax, 0, sizeof(sax));
2418
2419     sax.internalSubset = FcInternalSubsetDecl;
2420     sax.externalSubset = FcExternalSubsetDecl;
2421     sax.startElement = FcStartElement;
2422     sax.endElement = FcEndElement;
2423     sax.characters = FcCharacterData;
2424
2425     p = xmlCreatePushParserCtxt (&sax, &parse, NULL, 0, (const char *) filename);
2426 #else
2427     p = XML_ParserCreate ("UTF-8");
2428 #endif
2429     FcStrFree (filename);
2430
2431     if (!p)
2432         goto bail1;
2433
2434     if (!FcConfigInit (&parse, name, config, p))
2435         goto bail2;
2436
2437 #ifndef ENABLE_LIBXML2
2438
2439     XML_SetUserData (p, &parse);
2440     
2441     XML_SetDoctypeDeclHandler (p, FcStartDoctypeDecl, FcEndDoctypeDecl);
2442     XML_SetElementHandler (p, FcStartElement, FcEndElement);
2443     XML_SetCharacterDataHandler (p, FcCharacterData);
2444         
2445 #endif /* ENABLE_LIBXML2 */
2446
2447     do {
2448 #ifndef ENABLE_LIBXML2
2449         buf = XML_GetBuffer (p, BUFSIZ);
2450         if (!buf)
2451         {
2452             FcConfigMessage (&parse, FcSevereError, "cannot get parse buffer");
2453             goto bail3;
2454         }
2455 #endif
2456         len = read (fd, buf, BUFSIZ);
2457         if (len < 0)
2458         {
2459             FcConfigMessage (&parse, FcSevereError, "failed reading config file");
2460             goto bail3;
2461         }
2462
2463 #ifdef ENABLE_LIBXML2
2464         if (xmlParseChunk (p, buf, len, len == 0))
2465 #else
2466         if (!XML_ParseBuffer (p, len, len == 0))
2467 #endif
2468         {
2469             FcConfigMessage (&parse, FcSevereError, "%s", 
2470                            XML_ErrorString (XML_GetErrorCode (p)));
2471             goto bail3;
2472         }
2473     } while (len != 0);
2474     error = parse.error;
2475 bail3:
2476     FcConfigCleanup (&parse);
2477 bail2:
2478     XML_ParserFree (p);
2479 bail1:
2480     close (fd);
2481     fd = -1;
2482 bail0:
2483     if (error && complain)
2484     {
2485         if (name)
2486             FcConfigMessage (0, FcSevereError, "Cannot load config file \"%s\"", name);
2487         else
2488             FcConfigMessage (0, FcSevereError, "Cannot load default config file");
2489         return FcFalse;
2490     }
2491     return FcTrue;
2492 }