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