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