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