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