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