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