Minor
[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 = FcStrdup (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 = FcStrdup (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         FcFree (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         FcFree (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
1096     if (parse->pstack->attr)
1097     {
1098         /* Warn about unused attrs. */
1099         FcChar8 **attrs = parse->pstack->attr;
1100         while (*attrs)
1101         {
1102             if (attrs[0][0])
1103             {
1104                 FcConfigMessage (parse, FcSevereError, "invalid attribute '%s'", attrs[0]);
1105             }
1106             attrs += 2;
1107         }
1108     }
1109
1110     FcVStackClear (parse);
1111     old = parse->pstack;
1112     parse->pstack = old->prev;
1113     FcStrBufDestroy (&old->str);
1114
1115     if (old->attr && old->attr != old->attr_buf_static)
1116         free (old->attr);
1117
1118     if (old == &parse->pstack_static[parse->pstack_static_used - 1])
1119         parse->pstack_static_used--;
1120     else
1121         free (old);
1122     return FcTrue;
1123 }
1124
1125 static FcBool
1126 FcConfigParseInit (FcConfigParse *parse, const FcChar8 *name, FcConfig *config, XML_Parser parser)
1127 {
1128     parse->pstack = 0;
1129     parse->pstack_static_used = 0;
1130     parse->vstack = 0;
1131     parse->vstack_static_used = 0;
1132     parse->error = FcFalse;
1133     parse->name = name;
1134     parse->config = config;
1135     parse->parser = parser;
1136     return FcTrue;
1137 }
1138
1139 static void
1140 FcConfigCleanup (FcConfigParse  *parse)
1141 {
1142     while (parse->pstack)
1143         FcPStackPop (parse);
1144 }
1145
1146 static const FcChar8 *
1147 FcConfigGetAttribute (FcConfigParse *parse, const char *attr)
1148 {
1149     FcChar8 **attrs;
1150     if (!parse->pstack)
1151         return 0;
1152
1153     attrs = parse->pstack->attr;
1154     if (!attrs)
1155         return 0;
1156
1157     while (*attrs)
1158     {
1159         if (!strcmp ((char *) *attrs, attr))
1160         {
1161             attrs[0][0] = '\0'; /* Mark as used. */
1162             return attrs[1];
1163         }
1164         attrs += 2;
1165     }
1166     return 0;
1167 }
1168
1169 static void
1170 FcStartElement(void *userData, const XML_Char *name, const XML_Char **attr)
1171 {
1172     FcConfigParse   *parse = userData;
1173     FcElement       element;
1174
1175     element = FcElementMap (name);
1176     if (element == FcElementUnknown)
1177         FcConfigMessage (parse, FcSevereWarning, "unknown element \"%s\"", name);
1178
1179     if (!FcPStackPush (parse, element, attr))
1180     {
1181         FcConfigMessage (parse, FcSevereError, "out of memory");
1182         return;
1183     }
1184     return;
1185 }
1186
1187 static void
1188 FcParseBlank (FcConfigParse *parse)
1189 {
1190     int         n = FcVStackElements (parse);
1191     FcChar32    i;
1192     while (n-- > 0)
1193     {
1194         FcVStack    *v = FcVStackFetch (parse, n);
1195         if (!parse->config->blanks)
1196         {
1197             parse->config->blanks = FcBlanksCreate ();
1198             if (!parse->config->blanks)
1199                 goto bail;
1200         }
1201         switch ((int) v->tag) {
1202         case FcVStackInteger:
1203             if (!FcBlanksAdd (parse->config->blanks, v->u.integer))
1204                 goto bail;
1205             break;
1206         case FcVStackRange:
1207             if (v->u.range.begin <= v->u.range.end)
1208             {
1209               for (i = v->u.range.begin; i <= v->u.range.end; i++)
1210               {
1211                   if (!FcBlanksAdd (parse->config->blanks, i))
1212                       goto bail;
1213               }
1214             }
1215             break;
1216         default:
1217             FcConfigMessage (parse, FcSevereError, "invalid element in blank");
1218             break;
1219         }
1220     }
1221     return;
1222   bail:
1223     FcConfigMessage (parse, FcSevereError, "out of memory");
1224 }
1225
1226 static void
1227 FcParseRescan (FcConfigParse *parse)
1228 {
1229     int     n = FcVStackElements (parse);
1230     while (n-- > 0)
1231     {
1232         FcVStack    *v = FcVStackFetch (parse, n);
1233         if (v->tag != FcVStackInteger)
1234             FcConfigMessage (parse, FcSevereWarning, "non-integer rescan");
1235         else
1236             parse->config->rescanInterval = v->u.integer;
1237     }
1238 }
1239
1240 static void
1241 FcParseInt (FcConfigParse *parse)
1242 {
1243     FcChar8 *s, *end;
1244     int     l;
1245
1246     if (!parse->pstack)
1247         return;
1248     s = FcStrBufDoneStatic (&parse->pstack->str);
1249     if (!s)
1250     {
1251         FcConfigMessage (parse, FcSevereError, "out of memory");
1252         return;
1253     }
1254     end = 0;
1255     l = (int) strtol ((char *) s, (char **)&end, 0);
1256     if (end != s + strlen ((char *) s))
1257         FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid integer", s);
1258     else
1259         FcVStackPushInteger (parse, l);
1260     FcStrBufDestroy (&parse->pstack->str);
1261 }
1262
1263 /*
1264  * idea copied from glib g_ascii_strtod with
1265  * permission of the author (Alexander Larsson)
1266  */
1267
1268 #include <locale.h>
1269
1270 static double
1271 FcStrtod (char *s, char **end)
1272 {
1273     struct lconv    *locale_data;
1274     char            *dot;
1275     double          v;
1276
1277     /*
1278      * Have to swap the decimal point to match the current locale
1279      * if that locale doesn't use 0x2e
1280      */
1281     if ((dot = strchr (s, 0x2e)) &&
1282         (locale_data = localeconv ()) &&
1283         (locale_data->decimal_point[0] != 0x2e ||
1284          locale_data->decimal_point[1] != 0))
1285     {
1286         char    buf[128];
1287         int     slen = strlen (s);
1288         int     dlen = strlen (locale_data->decimal_point);
1289         
1290         if (slen + dlen > (int) sizeof (buf))
1291         {
1292             if (end)
1293                 *end = s;
1294             v = 0;
1295         }
1296         else
1297         {
1298             char        *buf_end;
1299             /* mantissa */
1300             strncpy (buf, s, dot - s);
1301             /* decimal point */
1302             strcpy (buf + (dot - s), locale_data->decimal_point);
1303             /* rest of number */
1304             strcpy (buf + (dot - s) + dlen, dot + 1);
1305             buf_end = 0;
1306             v = strtod (buf, &buf_end);
1307             if (buf_end) {
1308                 buf_end = s + (buf_end - buf);
1309                 if (buf_end > dot)
1310                     buf_end -= dlen - 1;
1311             }
1312             if (end)
1313                 *end = buf_end;
1314         }
1315     }
1316     else
1317         v = strtod (s, end);
1318     return v;
1319 }
1320
1321 static void
1322 FcParseDouble (FcConfigParse *parse)
1323 {
1324     FcChar8 *s, *end;
1325     double  d;
1326
1327     if (!parse->pstack)
1328         return;
1329     s = FcStrBufDoneStatic (&parse->pstack->str);
1330     if (!s)
1331     {
1332         FcConfigMessage (parse, FcSevereError, "out of memory");
1333         return;
1334     }
1335     end = 0;
1336     d = FcStrtod ((char *) s, (char **)&end);
1337     if (end != s + strlen ((char *) s))
1338         FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid double", s);
1339     else
1340         FcVStackPushDouble (parse, d);
1341     FcStrBufDestroy (&parse->pstack->str);
1342 }
1343
1344 static void
1345 FcParseString (FcConfigParse *parse, FcVStackTag tag)
1346 {
1347     FcChar8 *s;
1348
1349     if (!parse->pstack)
1350         return;
1351     s = FcStrBufDone (&parse->pstack->str);
1352     if (!s)
1353     {
1354         FcConfigMessage (parse, FcSevereError, "out of memory");
1355         return;
1356     }
1357     if (!FcVStackPushString (parse, tag, s))
1358         FcStrFree (s);
1359 }
1360
1361 static void
1362 FcParseName (FcConfigParse *parse)
1363 {
1364     const FcChar8   *kind_string;
1365     FcMatchKind     kind;
1366     FcChar8 *s;
1367     FcObject object;
1368
1369     kind_string = FcConfigGetAttribute (parse, "target");
1370     if (!kind_string)
1371         kind = FcMatchDefault;
1372     else
1373     {
1374         if (!strcmp ((char *) kind_string, "pattern"))
1375             kind = FcMatchPattern;
1376         else if (!strcmp ((char *) kind_string, "font"))
1377             kind = FcMatchFont;
1378         else if (!strcmp ((char *) kind_string, "default"))
1379             kind = FcMatchDefault;
1380         else
1381         {
1382             FcConfigMessage (parse, FcSevereWarning, "invalid name target \"%s\"", kind_string);
1383             return;
1384         }
1385     }
1386
1387     if (!parse->pstack)
1388         return;
1389     s = FcStrBufDone (&parse->pstack->str);
1390     if (!s)
1391     {
1392         FcConfigMessage (parse, FcSevereError, "out of memory");
1393         return;
1394     }
1395     object = FcObjectFromName ((const char *) s);
1396
1397     FcVStackPushName (parse, kind, object);
1398
1399     FcStrFree (s);
1400 }
1401
1402 static void
1403 FcParseMatrix (FcConfigParse *parse)
1404 {
1405     FcExprMatrix m;
1406
1407     m.yy = FcPopExpr (parse);
1408     m.yx = FcPopExpr (parse);
1409     m.xy = FcPopExpr (parse);
1410     m.xx = FcPopExpr (parse);
1411
1412     if (FcPopExpr (parse))
1413       FcConfigMessage (parse, FcSevereError, "wrong number of matrix elements");
1414     else
1415       FcVStackPushMatrix (parse, &m);
1416 }
1417
1418 static void
1419 FcParseRange (FcConfigParse *parse)
1420 {
1421     FcVStack    *vstack;
1422     FcRange     r;
1423     FcChar32    n;
1424     int         count = 1;
1425
1426     while ((vstack = FcVStackPeek (parse)))
1427     {
1428         if (count < 0)
1429         {
1430             FcConfigMessage (parse, FcSevereError, "too many elements in range");
1431             return;
1432         }
1433         switch ((int) vstack->tag) {
1434         case FcVStackInteger:
1435             n = vstack->u.integer;
1436             break;
1437         default:
1438             FcConfigMessage (parse, FcSevereError, "invalid element in range");
1439             n = 0;
1440             break;
1441         }
1442         if (count == 1)
1443             r.end = n;
1444         else
1445             r.begin = n;
1446         count--;
1447         FcVStackPopAndDestroy (parse);
1448     }
1449     if (count < 0)
1450     {
1451         if (r.begin > r.end)
1452         {
1453             FcConfigMessage (parse, FcSevereError, "invalid range");
1454             return;
1455         }
1456         FcVStackPushRange (parse, &r);
1457     }
1458     else
1459         FcConfigMessage (parse, FcSevereError, "invalid range");
1460 }
1461
1462 static FcBool
1463 FcConfigLexBool (FcConfigParse *parse, const FcChar8 *bool_)
1464 {
1465     FcBool  result = FcFalse;
1466
1467     if (!FcNameBool (bool_, &result))
1468         FcConfigMessage (parse, FcSevereWarning, "\"%s\" is not known boolean",
1469                          bool_);
1470     return result;
1471 }
1472
1473 static void
1474 FcParseBool (FcConfigParse *parse)
1475 {
1476     FcChar8 *s;
1477
1478     if (!parse->pstack)
1479         return;
1480     s = FcStrBufDoneStatic (&parse->pstack->str);
1481     if (!s)
1482     {
1483         FcConfigMessage (parse, FcSevereError, "out of memory");
1484         return;
1485     }
1486     FcVStackPushBool (parse, FcConfigLexBool (parse, s));
1487     FcStrBufDestroy (&parse->pstack->str);
1488 }
1489
1490 static void
1491 FcParseCharSet (FcConfigParse *parse)
1492 {
1493     FcVStack    *vstack;
1494     FcCharSet   *charset = FcCharSetCreate ();
1495     FcChar32    i;
1496     int n = 0;
1497
1498     while ((vstack = FcVStackPeek (parse)))
1499     {
1500         switch ((int) vstack->tag) {
1501         case FcVStackInteger:
1502             if (!FcCharSetAddChar (charset, vstack->u.integer))
1503             {
1504                 FcConfigMessage (parse, FcSevereWarning, "invalid character: 0x%04x", vstack->u.integer);
1505             }
1506             else
1507                 n++;
1508             break;
1509         case FcVStackRange:
1510             if (vstack->u.range.begin <= vstack->u.range.end)
1511             {
1512               for (i = vstack->u.range.begin; i <= vstack->u.range.end; i++)
1513               {
1514                   if (!FcCharSetAddChar (charset, i))
1515                   {
1516                       FcConfigMessage (parse, FcSevereWarning, "invalid character: 0x%04x", i);
1517                   }
1518                   else
1519                       n++;
1520               }
1521             }
1522             break;
1523         default:
1524                 FcConfigMessage (parse, FcSevereError, "invalid element in charset");
1525                 break;
1526         }
1527         FcVStackPopAndDestroy (parse);
1528     }
1529     if (n > 0)
1530             FcVStackPushCharSet (parse, charset);
1531     else
1532             FcCharSetDestroy (charset);
1533 }
1534
1535 static void
1536 FcParseLangSet (FcConfigParse *parse)
1537 {
1538     FcVStack    *vstack;
1539     FcLangSet   *langset = FcLangSetCreate ();
1540     int n = 0;
1541
1542     while ((vstack = FcVStackPeek (parse)))
1543     {
1544         switch ((int) vstack->tag) {
1545         case FcVStackString:
1546             if (!FcLangSetAdd (langset, vstack->u.string))
1547             {
1548                 FcConfigMessage (parse, FcSevereWarning, "invalid langset: %s", vstack->u.string);
1549             }
1550             else
1551                 n++;
1552             break;
1553         default:
1554                 FcConfigMessage (parse, FcSevereError, "invalid element in langset");
1555                 break;
1556         }
1557         FcVStackPopAndDestroy (parse);
1558     }
1559     if (n > 0)
1560             FcVStackPushLangSet (parse, langset);
1561     else
1562             FcLangSetDestroy (langset);
1563 }
1564
1565 static FcBool
1566 FcConfigLexBinding (FcConfigParse   *parse,
1567                     const FcChar8   *binding_string,
1568                     FcValueBinding  *binding_ret)
1569 {
1570     FcValueBinding binding;
1571
1572     if (!binding_string)
1573         binding = FcValueBindingWeak;
1574     else
1575     {
1576         if (!strcmp ((char *) binding_string, "weak"))
1577             binding = FcValueBindingWeak;
1578         else if (!strcmp ((char *) binding_string, "strong"))
1579             binding = FcValueBindingStrong;
1580         else if (!strcmp ((char *) binding_string, "same"))
1581             binding = FcValueBindingSame;
1582         else
1583         {
1584             FcConfigMessage (parse, FcSevereWarning, "invalid binding \"%s\"", binding_string);
1585             return FcFalse;
1586         }
1587     }
1588     *binding_ret = binding;
1589     return FcTrue;
1590 }
1591
1592 static void
1593 FcParseFamilies (FcConfigParse *parse, FcVStackTag tag)
1594 {
1595     FcVStack    *vstack;
1596     FcExpr      *left, *expr = 0, *new;
1597
1598     while ((vstack = FcVStackPeek (parse)))
1599     {
1600         if (vstack->tag != FcVStackFamily)
1601         {
1602             FcConfigMessage (parse, FcSevereWarning, "non-family");
1603             FcVStackPopAndDestroy (parse);
1604             continue;
1605         }
1606         left = vstack->u.expr;
1607         vstack->tag = FcVStackNone;
1608         FcVStackPopAndDestroy (parse);
1609         if (expr)
1610         {
1611             new = FcExprCreateOp (parse->config, left, FcOpComma, expr);
1612             if (!new)
1613             {
1614                 FcConfigMessage (parse, FcSevereError, "out of memory");
1615                 FcExprDestroy (left);
1616                 FcExprDestroy (expr);
1617                 break;
1618             }
1619             expr = new;
1620         }
1621         else
1622             expr = left;
1623     }
1624     if (expr)
1625     {
1626         if (!FcVStackPushExpr (parse, tag, expr))
1627         {
1628             FcConfigMessage (parse, FcSevereError, "out of memory");
1629             FcExprDestroy (expr);
1630         }
1631     }
1632 }
1633
1634 static void
1635 FcParseFamily (FcConfigParse *parse)
1636 {
1637     FcChar8 *s;
1638     FcExpr  *expr;
1639
1640     if (!parse->pstack)
1641         return;
1642     s = FcStrBufDoneStatic (&parse->pstack->str);
1643     if (!s)
1644     {
1645         FcConfigMessage (parse, FcSevereError, "out of memory");
1646         return;
1647     }
1648     expr = FcExprCreateString (parse->config, s);
1649     FcStrBufDestroy (&parse->pstack->str);
1650     if (expr)
1651         FcVStackPushExpr (parse, FcVStackFamily, expr);
1652 }
1653
1654 static void
1655 FcParseAlias (FcConfigParse *parse)
1656 {
1657     FcExpr      *family = 0, *accept = 0, *prefer = 0, *def = 0, *new = 0;
1658     FcEdit      *edit = 0, *next;
1659     FcVStack    *vstack;
1660     FcTest      *test = NULL;
1661     FcValueBinding  binding;
1662
1663     if (!FcConfigLexBinding (parse, FcConfigGetAttribute (parse, "binding"), &binding))
1664         return;
1665     while ((vstack = FcVStackPeek (parse)))
1666     {
1667         switch ((int) vstack->tag) {
1668         case FcVStackFamily:
1669             if (family)
1670             {
1671                 FcConfigMessage (parse, FcSevereWarning, "Having multiple <family> in <alias> isn't supported and may not work as expected");
1672                 new = FcExprCreateOp (parse->config, vstack->u.expr, FcOpComma, family);
1673                 if (!new)
1674                     FcConfigMessage (parse, FcSevereError, "out of memory");
1675                 else
1676                     family = new;
1677             }
1678             else
1679                 new = vstack->u.expr;
1680             if (new)
1681             {
1682                 family = new;
1683                 vstack->tag = FcVStackNone;
1684             }
1685             break;
1686         case FcVStackPrefer:
1687             if (prefer)
1688                 FcExprDestroy (prefer);
1689             prefer = vstack->u.expr;
1690             vstack->tag = FcVStackNone;
1691             break;
1692         case FcVStackAccept:
1693             if (accept)
1694                 FcExprDestroy (accept);
1695             accept = vstack->u.expr;
1696             vstack->tag = FcVStackNone;
1697             break;
1698         case FcVStackDefault:
1699             if (def)
1700                 FcExprDestroy (def);
1701             def = vstack->u.expr;
1702             vstack->tag = FcVStackNone;
1703             break;
1704         case FcVStackTest:
1705             vstack->u.test->next = test;
1706             test = vstack->u.test;
1707             vstack->tag = FcVStackNone;
1708             break;
1709         default:
1710             FcConfigMessage (parse, FcSevereWarning, "bad alias");
1711             break;
1712         }
1713         FcVStackPopAndDestroy (parse);
1714     }
1715     if (!family)
1716     {
1717         FcConfigMessage (parse, FcSevereError, "missing family in alias");
1718         if (prefer)
1719             FcExprDestroy (prefer);
1720         if (accept)
1721             FcExprDestroy (accept);
1722         if (def)
1723             FcExprDestroy (def);
1724         return;
1725     }
1726     if (prefer)
1727     {
1728         edit = FcEditCreate (parse,
1729                              FC_FAMILY_OBJECT,
1730                              FcOpPrepend,
1731                              prefer,
1732                              binding);
1733         if (edit)
1734             edit->next = 0;
1735         else
1736             FcExprDestroy (prefer);
1737     }
1738     if (accept)
1739     {
1740         next = edit;
1741         edit = FcEditCreate (parse,
1742                              FC_FAMILY_OBJECT,
1743                              FcOpAppend,
1744                              accept,
1745                              binding);
1746         if (edit)
1747             edit->next = next;
1748         else
1749             FcExprDestroy (accept);
1750     }
1751     if (def)
1752     {
1753         next = edit;
1754         edit = FcEditCreate (parse,
1755                              FC_FAMILY_OBJECT,
1756                              FcOpAppendLast,
1757                              def,
1758                              binding);
1759         if (edit)
1760             edit->next = next;
1761         else
1762             FcExprDestroy (def);
1763     }
1764     if (edit)
1765     {
1766         FcTest *t = FcTestCreate (parse, FcMatchPattern,
1767                                   FcQualAny,
1768                                   (FcChar8 *) FC_FAMILY,
1769                                   FC_OP (FcOpEqual, FcOpFlagIgnoreBlanks),
1770                                   family);
1771         if (test)
1772         {
1773             FcTest *p = test;
1774
1775             while (p->next)
1776                 p = p->next;
1777             p->next = t;
1778         }
1779         else
1780             test = t;
1781         if (test)
1782             if (!FcConfigAddEdit (parse->config, test, edit, FcMatchPattern))
1783                 FcTestDestroy (test);
1784     }
1785     else
1786         FcExprDestroy (family);
1787 }
1788
1789 static FcExpr *
1790 FcPopExpr (FcConfigParse *parse)
1791 {
1792     FcVStack    *vstack = FcVStackPeek (parse);
1793     FcExpr      *expr = 0;
1794     if (!vstack)
1795         return 0;
1796     switch ((int) vstack->tag) {
1797     case FcVStackNone:
1798         break;
1799     case FcVStackString:
1800     case FcVStackFamily:
1801         expr = FcExprCreateString (parse->config, vstack->u.string);
1802         break;
1803     case FcVStackName:
1804         expr = FcExprCreateName (parse->config, vstack->u.name);
1805         break;
1806     case FcVStackConstant:
1807         expr = FcExprCreateConst (parse->config, vstack->u.string);
1808         break;
1809     case FcVStackGlob:
1810         /* XXX: What's the correct action here? (CDW) */
1811         break;
1812     case FcVStackPrefer:
1813     case FcVStackAccept:
1814     case FcVStackDefault:
1815         expr = vstack->u.expr;
1816         vstack->tag = FcVStackNone;
1817         break;
1818     case FcVStackInteger:
1819         expr = FcExprCreateInteger (parse->config, vstack->u.integer);
1820         break;
1821     case FcVStackDouble:
1822         expr = FcExprCreateDouble (parse->config, vstack->u._double);
1823         break;
1824     case FcVStackMatrix:
1825         expr = FcExprCreateMatrix (parse->config, vstack->u.matrix);
1826         break;
1827     case FcVStackRange:
1828         break;
1829     case FcVStackBool:
1830         expr = FcExprCreateBool (parse->config, vstack->u.bool_);
1831         break;
1832     case FcVStackCharSet:
1833         expr = FcExprCreateCharSet (parse->config, vstack->u.charset);
1834         break;
1835     case FcVStackLangSet:
1836         expr = FcExprCreateLangSet (parse->config, vstack->u.langset);
1837         break;
1838     case FcVStackTest:
1839         break;
1840     case FcVStackExpr:
1841         expr = vstack->u.expr;
1842         vstack->tag = FcVStackNone;
1843         break;
1844     case FcVStackEdit:
1845         break;
1846     default:
1847         break;
1848     }
1849     FcVStackPopAndDestroy (parse);
1850     return expr;
1851 }
1852
1853 /*
1854  * This builds a tree of binary operations.  Note
1855  * that every operator is defined so that if only
1856  * a single operand is contained, the value of the
1857  * whole expression is the value of the operand.
1858  *
1859  * This code reduces in that case to returning that
1860  * operand.
1861  */
1862 static FcExpr *
1863 FcPopBinary (FcConfigParse *parse, FcOp op)
1864 {
1865     FcExpr  *left, *expr = 0, *new;
1866
1867     while ((left = FcPopExpr (parse)))
1868     {
1869         if (expr)
1870         {
1871             new = FcExprCreateOp (parse->config, left, op, expr);
1872             if (!new)
1873             {
1874                 FcConfigMessage (parse, FcSevereError, "out of memory");
1875                 FcExprDestroy (left);
1876                 FcExprDestroy (expr);
1877                 return 0;
1878             }
1879             expr = new;
1880         }
1881         else
1882             expr = left;
1883     }
1884     return expr;
1885 }
1886
1887 static void
1888 FcParseBinary (FcConfigParse *parse, FcOp op)
1889 {
1890     FcExpr  *expr = FcPopBinary (parse, op);
1891     if (expr)
1892         FcVStackPushExpr (parse, FcVStackExpr, expr);
1893 }
1894
1895 /*
1896  * This builds a a unary operator, it consumes only
1897  * a single operand
1898  */
1899
1900 static FcExpr *
1901 FcPopUnary (FcConfigParse *parse, FcOp op)
1902 {
1903     FcExpr  *operand, *new = 0;
1904
1905     if ((operand = FcPopExpr (parse)))
1906     {
1907         new = FcExprCreateOp (parse->config, operand, op, 0);
1908         if (!new)
1909         {
1910             FcExprDestroy (operand);
1911             FcConfigMessage (parse, FcSevereError, "out of memory");
1912         }
1913     }
1914     return new;
1915 }
1916
1917 static void
1918 FcParseUnary (FcConfigParse *parse, FcOp op)
1919 {
1920     FcExpr  *expr = FcPopUnary (parse, op);
1921     if (expr)
1922         FcVStackPushExpr (parse, FcVStackExpr, expr);
1923 }
1924
1925 static void
1926 FcParseDir (FcConfigParse *parse)
1927 {
1928     const FcChar8 *attr, *data;
1929     FcChar8 *prefix = NULL, *p;
1930 #ifdef _WIN32
1931     FcChar8         buffer[1000];
1932 #endif
1933
1934     attr = FcConfigGetAttribute (parse, "prefix");
1935     if (attr && FcStrCmp (attr, (const FcChar8 *)"xdg") == 0)
1936         prefix = FcConfigXdgDataHome ();
1937     data = FcStrBufDoneStatic (&parse->pstack->str);
1938     if (!data)
1939     {
1940         FcConfigMessage (parse, FcSevereError, "out of memory");
1941         data = prefix;
1942         goto bail;
1943     }
1944     if (prefix)
1945     {
1946         size_t plen = strlen ((const char *)prefix);
1947         size_t dlen = strlen ((const char *)data);
1948
1949         p = realloc (prefix, plen + 1 + dlen + 1);
1950         if (!p)
1951         {
1952             FcConfigMessage (parse, FcSevereError, "out of memory");
1953             goto bail;
1954         }
1955         prefix = p;
1956         prefix[plen] = FC_DIR_SEPARATOR;
1957         memcpy (&prefix[plen + 1], data, dlen);
1958         prefix[plen + 1 + dlen] = 0;
1959         data = prefix;
1960     }
1961 #ifdef _WIN32
1962     if (strcmp ((const char *) data, "CUSTOMFONTDIR") == 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         /*
1972          * Must use the multi-byte aware function to search
1973          * for backslash because East Asian double-byte code
1974          * pages have characters with backslash as the second
1975          * byte.
1976          */
1977         p = _mbsrchr (data, '\\');
1978         if (p) *p = '\0';
1979         strcat (data, "\\fonts");
1980     }
1981     else if (strcmp ((const char *) data, "APPSHAREFONTDIR") == 0)
1982     {
1983         char *p;
1984         data = buffer;
1985         if (!GetModuleFileName (NULL, (LPCH) buffer, sizeof (buffer) - 20))
1986         {
1987             FcConfigMessage (parse, FcSevereError, "GetModuleFileName failed");
1988             goto bail;
1989         }
1990         p = _mbsrchr (data, '\\');
1991         if (p) *p = '\0';
1992         strcat (data, "\\..\\share\\fonts");
1993     }
1994     else if (strcmp ((const char *) data, "WINDOWSFONTDIR") == 0)
1995     {
1996         int rc;
1997         data = buffer;
1998         rc = pGetSystemWindowsDirectory ((LPSTR) buffer, sizeof (buffer) - 20);
1999         if (rc == 0 || rc > sizeof (buffer) - 20)
2000         {
2001             FcConfigMessage (parse, FcSevereError, "GetSystemWindowsDirectory failed");
2002             goto bail;
2003         }
2004         if (data [strlen ((const char *) data) - 1] != '\\')
2005             strcat (data, "\\");
2006         strcat (data, "fonts");
2007     }
2008 #endif
2009     if (strlen ((char *) data) == 0)
2010         FcConfigMessage (parse, FcSevereWarning, "empty font directory name ignored");
2011     else if (!FcStrUsesHome (data) || FcConfigHome ())
2012     {
2013         if (!FcConfigAddDir (parse->config, data))
2014             FcConfigMessage (parse, FcSevereError, "out of memory; cannot add directory %s", data);
2015     }
2016     FcStrBufDestroy (&parse->pstack->str);
2017
2018   bail:
2019     if (prefix)
2020         FcStrFree (prefix);
2021 }
2022
2023 static void
2024 FcParseCacheDir (FcConfigParse *parse)
2025 {
2026     const FcChar8 *attr;
2027     FcChar8 *prefix = NULL, *p, *data;
2028
2029     attr = FcConfigGetAttribute (parse, "prefix");
2030     if (attr && FcStrCmp (attr, (const FcChar8 *)"xdg") == 0)
2031         prefix = FcConfigXdgCacheHome ();
2032     data = FcStrBufDone (&parse->pstack->str);
2033     if (!data)
2034     {
2035         FcConfigMessage (parse, FcSevereError, "out of memory");
2036         goto bail;
2037     }
2038     if (prefix)
2039     {
2040         size_t plen = strlen ((const char *)prefix);
2041         size_t dlen = strlen ((const char *)data);
2042
2043         p = realloc (prefix, plen + 1 + dlen + 1);
2044         if (!p)
2045         {
2046             FcConfigMessage (parse, FcSevereError, "out of memory");
2047             data = prefix;
2048             goto bail;
2049         }
2050         prefix = p;
2051         prefix[plen] = FC_DIR_SEPARATOR;
2052         memcpy (&prefix[plen + 1], data, dlen);
2053         prefix[plen + 1 + dlen] = 0;
2054         FcStrFree (data);
2055         data = prefix;
2056     }
2057 #ifdef _WIN32
2058     if (strcmp ((const char *) data, "WINDOWSTEMPDIR_FONTCONFIG_CACHE") == 0)
2059     {
2060         int rc;
2061         FcStrFree (data);
2062         data = malloc (1000);
2063         if (!data)
2064         {
2065             FcConfigMessage (parse, FcSevereError, "out of memory");
2066             goto bail;
2067         }
2068         rc = GetTempPath (800, (LPSTR) data);
2069         if (rc == 0 || rc > 800)
2070         {
2071             FcConfigMessage (parse, FcSevereError, "GetTempPath failed");
2072             goto bail;
2073         }
2074         if (data [strlen ((const char *) data) - 1] != '\\')
2075             strcat (data, "\\");
2076         strcat (data, "fontconfig\\cache");
2077     }
2078     else if (strcmp ((const char *) data, "LOCAL_APPDATA_FONTCONFIG_CACHE") == 0)
2079     {
2080         char szFPath[MAX_PATH + 1];
2081         size_t len;
2082
2083         if (!(pSHGetFolderPathA && SUCCEEDED(pSHGetFolderPathA(NULL, /* CSIDL_LOCAL_APPDATA */ 28, NULL, 0, szFPath))))
2084         {
2085             FcConfigMessage (parse, FcSevereError, "SHGetFolderPathA failed");
2086             goto bail;
2087         }
2088         strncat(szFPath, "\\fontconfig\\cache", MAX_PATH - 1 - strlen(szFPath));
2089         len = strlen(szFPath) + 1;
2090         FcStrFree (data);
2091         data = malloc(len);
2092         if (!data)
2093         {
2094             FcConfigMessage (parse, FcSevereError, "out of memory");
2095             goto bail;
2096         }
2097         strncpy((char *) data, szFPath, len);
2098     }
2099 #endif
2100     if (strlen ((char *) data) == 0)
2101         FcConfigMessage (parse, FcSevereWarning, "empty cache directory name ignored");
2102     else if (!FcStrUsesHome (data) || FcConfigHome ())
2103     {
2104         if (!FcConfigAddCacheDir (parse->config, data))
2105             FcConfigMessage (parse, FcSevereError, "out of memory; cannot add cache directory %s", data);
2106     }
2107     FcStrBufDestroy (&parse->pstack->str);
2108
2109   bail:
2110     if (data)
2111         FcStrFree (data);
2112 }
2113
2114 static void
2115 FcParseInclude (FcConfigParse *parse)
2116 {
2117     FcChar8         *s;
2118     const FcChar8   *attr;
2119     FcBool          ignore_missing = FcFalse;
2120     FcBool          deprecated = FcFalse;
2121     FcChar8         *prefix = NULL, *p;
2122
2123     s = FcStrBufDoneStatic (&parse->pstack->str);
2124     if (!s)
2125     {
2126         FcConfigMessage (parse, FcSevereError, "out of memory");
2127         goto bail;
2128     }
2129     attr = FcConfigGetAttribute (parse, "ignore_missing");
2130     if (attr && FcConfigLexBool (parse, (FcChar8 *) attr) == FcTrue)
2131         ignore_missing = FcTrue;
2132     attr = FcConfigGetAttribute (parse, "deprecated");
2133     if (attr && FcConfigLexBool (parse, (FcChar8 *) attr) == FcTrue)
2134         deprecated = FcTrue;
2135     attr = FcConfigGetAttribute (parse, "prefix");
2136     if (attr && FcStrCmp (attr, (const FcChar8 *)"xdg") == 0)
2137         prefix = FcConfigXdgConfigHome ();
2138     if (prefix)
2139     {
2140         size_t plen = strlen ((const char *)prefix);
2141         size_t dlen = strlen ((const char *)s);
2142
2143         p = realloc (prefix, plen + 1 + dlen + 1);
2144         if (!p)
2145         {
2146             FcConfigMessage (parse, FcSevereError, "out of memory");
2147             goto bail;
2148         }
2149         prefix = p;
2150         prefix[plen] = FC_DIR_SEPARATOR;
2151         memcpy (&prefix[plen + 1], s, dlen);
2152         prefix[plen + 1 + dlen] = 0;
2153         s = prefix;
2154     }
2155     if (!FcConfigParseAndLoad (parse->config, s, !ignore_missing))
2156         parse->error = FcTrue;
2157     else
2158     {
2159         FcChar8 *filename;
2160
2161         filename = FcConfigFilename(s);
2162         if (deprecated == FcTrue &&
2163             filename != NULL &&
2164             !FcFileIsLink (filename))
2165         {
2166             FcConfigMessage (parse, FcSevereWarning, "reading configurations from %s is deprecated.", s);
2167         }
2168         if(filename)
2169             FcStrFree(filename);
2170     }
2171     FcStrBufDestroy (&parse->pstack->str);
2172
2173   bail:
2174     if (prefix)
2175         FcStrFree (prefix);
2176 }
2177
2178 typedef struct _FcOpMap {
2179     char    name[16];
2180     FcOp    op;
2181 } FcOpMap;
2182
2183 static FcOp
2184 FcConfigLexOp (const FcChar8 *op, const FcOpMap *map, int nmap)
2185 {
2186     int i;
2187
2188     for (i = 0; i < nmap; i++)
2189         if (!strcmp ((char *) op, map[i].name))
2190             return map[i].op;
2191     return FcOpInvalid;
2192 }
2193
2194 static const FcOpMap fcCompareOps[] = {
2195     { "eq",             FcOpEqual           },
2196     { "not_eq",         FcOpNotEqual        },
2197     { "less",           FcOpLess            },
2198     { "less_eq",        FcOpLessEqual       },
2199     { "more",           FcOpMore            },
2200     { "more_eq",        FcOpMoreEqual       },
2201     { "contains",       FcOpContains        },
2202     { "not_contains",   FcOpNotContains     }
2203 };
2204
2205 #define NUM_COMPARE_OPS (int) (sizeof fcCompareOps / sizeof fcCompareOps[0])
2206
2207 static FcOp
2208 FcConfigLexCompare (const FcChar8 *compare)
2209 {
2210     return FcConfigLexOp (compare, fcCompareOps, NUM_COMPARE_OPS);
2211 }
2212
2213 static void
2214 FcParseTest (FcConfigParse *parse)
2215 {
2216     const FcChar8   *kind_string;
2217     FcMatchKind     kind;
2218     const FcChar8   *qual_string;
2219     FcQual          qual;
2220     const FcChar8   *name;
2221     const FcChar8   *compare_string;
2222     FcOp            compare;
2223     FcExpr          *expr;
2224     FcTest          *test;
2225     const FcChar8   *iblanks_string;
2226     int              flags = 0;
2227
2228     kind_string = FcConfigGetAttribute (parse, "target");
2229     if (!kind_string)
2230         kind = FcMatchDefault;
2231     else
2232     {
2233         if (!strcmp ((char *) kind_string, "pattern"))
2234             kind = FcMatchPattern;
2235         else if (!strcmp ((char *) kind_string, "font"))
2236             kind = FcMatchFont;
2237         else if (!strcmp ((char *) kind_string, "scan"))
2238             kind = FcMatchScan;
2239         else if (!strcmp ((char *) kind_string, "default"))
2240             kind = FcMatchDefault;
2241         else
2242         {
2243             FcConfigMessage (parse, FcSevereWarning, "invalid test target \"%s\"", kind_string);
2244             return;
2245         }
2246     }
2247     qual_string = FcConfigGetAttribute (parse, "qual");
2248     if (!qual_string)
2249         qual = FcQualAny;
2250     else
2251     {
2252         if (!strcmp ((char *) qual_string, "any"))
2253             qual = FcQualAny;
2254         else if (!strcmp ((char *) qual_string, "all"))
2255             qual = FcQualAll;
2256         else if (!strcmp ((char *) qual_string, "first"))
2257             qual = FcQualFirst;
2258         else if (!strcmp ((char *) qual_string, "not_first"))
2259             qual = FcQualNotFirst;
2260         else
2261         {
2262             FcConfigMessage (parse, FcSevereWarning, "invalid test qual \"%s\"", qual_string);
2263             return;
2264         }
2265     }
2266     name = FcConfigGetAttribute (parse, "name");
2267     if (!name)
2268     {
2269         FcConfigMessage (parse, FcSevereWarning, "missing test name");
2270         return;
2271     }
2272     compare_string = FcConfigGetAttribute (parse, "compare");
2273     if (!compare_string)
2274         compare = FcOpEqual;
2275     else
2276     {
2277         compare = FcConfigLexCompare (compare_string);
2278         if (compare == FcOpInvalid)
2279         {
2280             FcConfigMessage (parse, FcSevereWarning, "invalid test compare \"%s\"", compare_string);
2281             return;
2282         }
2283     }
2284     iblanks_string = FcConfigGetAttribute (parse, "ignore-blanks");
2285     if (iblanks_string)
2286     {
2287         FcBool f = FcFalse;
2288
2289         if (!FcNameBool (iblanks_string, &f))
2290         {
2291             FcConfigMessage (parse,
2292                              FcSevereWarning,
2293                              "invalid test ignore-blanks \"%s\"", iblanks_string);
2294         }
2295         if (f)
2296             flags |= FcOpFlagIgnoreBlanks;
2297     }
2298     expr = FcPopBinary (parse, FcOpComma);
2299     if (!expr)
2300     {
2301         FcConfigMessage (parse, FcSevereWarning, "missing test expression");
2302         return;
2303     }
2304     if (expr->op == FcOpComma)
2305     {
2306         FcConfigMessage (parse, FcSevereWarning, "Having multiple values in <test> isn't supported and may not work as expected");
2307     }
2308     test = FcTestCreate (parse, kind, qual, name, FC_OP (compare, flags), expr);
2309     if (!test)
2310     {
2311         FcConfigMessage (parse, FcSevereError, "out of memory");
2312         return;
2313     }
2314     FcVStackPushTest (parse, test);
2315 }
2316
2317 static const FcOpMap fcModeOps[] = {
2318     { "assign",         FcOpAssign          },
2319     { "assign_replace", FcOpAssignReplace   },
2320     { "prepend",        FcOpPrepend         },
2321     { "prepend_first",  FcOpPrependFirst    },
2322     { "append",         FcOpAppend          },
2323     { "append_last",    FcOpAppendLast      },
2324 };
2325
2326 #define NUM_MODE_OPS (int) (sizeof fcModeOps / sizeof fcModeOps[0])
2327
2328 static FcOp
2329 FcConfigLexMode (const FcChar8 *mode)
2330 {
2331     return FcConfigLexOp (mode, fcModeOps, NUM_MODE_OPS);
2332 }
2333
2334 static void
2335 FcParseEdit (FcConfigParse *parse)
2336 {
2337     const FcChar8   *name;
2338     const FcChar8   *mode_string;
2339     FcOp            mode;
2340     FcValueBinding  binding;
2341     FcExpr          *expr;
2342     FcEdit          *edit;
2343
2344     name = FcConfigGetAttribute (parse, "name");
2345     if (!name)
2346     {
2347         FcConfigMessage (parse, FcSevereWarning, "missing edit name");
2348         return;
2349     }
2350     mode_string = FcConfigGetAttribute (parse, "mode");
2351     if (!mode_string)
2352         mode = FcOpAssign;
2353     else
2354     {
2355         mode = FcConfigLexMode (mode_string);
2356         if (mode == FcOpInvalid)
2357         {
2358             FcConfigMessage (parse, FcSevereWarning, "invalid edit mode \"%s\"", mode_string);
2359             return;
2360         }
2361     }
2362     if (!FcConfigLexBinding (parse, FcConfigGetAttribute (parse, "binding"), &binding))
2363         return;
2364
2365     expr = FcPopBinary (parse, FcOpComma);
2366     edit = FcEditCreate (parse, FcObjectFromName ((char *) name),
2367                          mode, expr, binding);
2368     if (!edit)
2369     {
2370         FcConfigMessage (parse, FcSevereError, "out of memory");
2371         FcExprDestroy (expr);
2372         return;
2373     }
2374     if (!FcVStackPushEdit (parse, edit))
2375         FcEditDestroy (edit);
2376 }
2377
2378 static void
2379 FcParseMatch (FcConfigParse *parse)
2380 {
2381     const FcChar8   *kind_name;
2382     FcMatchKind     kind;
2383     FcTest          *test = 0;
2384     FcEdit          *edit = 0;
2385     FcVStack        *vstack;
2386
2387     kind_name = FcConfigGetAttribute (parse, "target");
2388     if (!kind_name)
2389         kind = FcMatchPattern;
2390     else
2391     {
2392         if (!strcmp ((char *) kind_name, "pattern"))
2393             kind = FcMatchPattern;
2394         else if (!strcmp ((char *) kind_name, "font"))
2395             kind = FcMatchFont;
2396         else if (!strcmp ((char *) kind_name, "scan"))
2397             kind = FcMatchScan;
2398         else
2399         {
2400             FcConfigMessage (parse, FcSevereWarning, "invalid match target \"%s\"", kind_name);
2401             return;
2402         }
2403     }
2404     while ((vstack = FcVStackPeek (parse)))
2405     {
2406         switch ((int) vstack->tag) {
2407         case FcVStackTest:
2408             vstack->u.test->next = test;
2409             test = vstack->u.test;
2410             vstack->tag = FcVStackNone;
2411             break;
2412         case FcVStackEdit:
2413             vstack->u.edit->next = edit;
2414             edit = vstack->u.edit;
2415             vstack->tag = FcVStackNone;
2416             if (kind == FcMatchScan && edit->object > FC_MAX_BASE_OBJECT)
2417             {
2418                 FcConfigMessage (parse, FcSevereError,
2419                                  "<match target=\"scan\"> cannot edit user-defined object \"%s\"",
2420                                  FcObjectName(edit->object));
2421             }
2422             break;
2423         default:
2424             FcConfigMessage (parse, FcSevereWarning, "invalid match element");
2425             break;
2426         }
2427         FcVStackPopAndDestroy (parse);
2428     }
2429     if (!FcConfigAddEdit (parse->config, test, edit, kind))
2430         FcConfigMessage (parse, FcSevereError, "out of memory");
2431 }
2432
2433 static void
2434 FcParseAcceptRejectFont (FcConfigParse *parse, FcElement element)
2435 {
2436     FcVStack    *vstack;
2437
2438     while ((vstack = FcVStackPeek (parse)))
2439     {
2440         switch ((int) vstack->tag) {
2441         case FcVStackGlob:
2442             if (!FcConfigGlobAdd (parse->config,
2443                                   vstack->u.string,
2444                                   element == FcElementAcceptfont))
2445             {
2446                 FcConfigMessage (parse, FcSevereError, "out of memory");
2447             }
2448             break;
2449         case FcVStackPattern:
2450             if (!FcConfigPatternsAdd (parse->config,
2451                                       vstack->u.pattern,
2452                                       element == FcElementAcceptfont))
2453             {
2454                 FcConfigMessage (parse, FcSevereError, "out of memory");
2455             }
2456             else
2457                 vstack->tag = FcVStackNone;
2458             break;
2459         default:
2460             FcConfigMessage (parse, FcSevereWarning, "bad font selector");
2461             break;
2462         }
2463         FcVStackPopAndDestroy (parse);
2464     }
2465 }
2466
2467
2468 static FcValue
2469 FcPopValue (FcConfigParse *parse)
2470 {
2471     FcVStack    *vstack = FcVStackPeek (parse);
2472     FcValue     value;
2473
2474     value.type = FcTypeVoid;
2475
2476     if (!vstack)
2477         return value;
2478
2479     switch ((int) vstack->tag) {
2480     case FcVStackString:
2481         value.u.s = FcStrdup (vstack->u.string);
2482         if (value.u.s)
2483             value.type = FcTypeString;
2484         break;
2485     case FcVStackConstant:
2486         if (FcNameConstant (vstack->u.string, &value.u.i))
2487             value.type = FcTypeInteger;
2488         break;
2489     case FcVStackInteger:
2490         value.u.i = vstack->u.integer;
2491         value.type = FcTypeInteger;
2492         break;
2493     case FcVStackDouble:
2494         value.u.d = vstack->u._double;
2495         value.type = FcTypeDouble;
2496         break;
2497     case FcVStackBool:
2498         value.u.b = vstack->u.bool_;
2499         value.type = FcTypeBool;
2500         break;
2501     case FcVStackCharSet:
2502         value.u.c = FcCharSetCopy (vstack->u.charset);
2503         if (value.u.c)
2504             value.type = FcTypeCharSet;
2505         break;
2506     case FcVStackLangSet:
2507         value.u.l = FcLangSetCopy (vstack->u.langset);
2508         if (value.u.l)
2509             value.type = FcTypeLangSet;
2510         break;
2511     default:
2512         FcConfigMessage (parse, FcSevereWarning, "unknown pattern element %d",
2513                          vstack->tag);
2514         break;
2515     }
2516     FcVStackPopAndDestroy (parse);
2517
2518     return value;
2519 }
2520
2521 static void
2522 FcParsePatelt (FcConfigParse *parse)
2523 {
2524     FcValue     value;
2525     FcPattern   *pattern = FcPatternCreate ();
2526     const char  *name;
2527
2528     if (!pattern)
2529     {
2530         FcConfigMessage (parse, FcSevereError, "out of memory");
2531         return;
2532     }
2533
2534     name = (char *) FcConfigGetAttribute (parse, "name");
2535     if (!name)
2536     {
2537         FcConfigMessage (parse, FcSevereWarning, "missing pattern element name");
2538         FcPatternDestroy (pattern);
2539         return;
2540     }
2541
2542     for (;;)
2543     {
2544         value = FcPopValue (parse);
2545         if (value.type == FcTypeVoid)
2546             break;
2547         if (!FcPatternAdd (pattern, name, value, FcTrue))
2548         {
2549             FcConfigMessage (parse, FcSevereError, "out of memory");
2550             FcValueDestroy(value);
2551             break;
2552         }
2553         FcValueDestroy(value);
2554     }
2555
2556     FcVStackPushPattern (parse, pattern);
2557 }
2558
2559 static void
2560 FcParsePattern (FcConfigParse *parse)
2561 {
2562     FcVStack    *vstack;
2563     FcPattern   *pattern = FcPatternCreate ();
2564
2565     if (!pattern)
2566     {
2567         FcConfigMessage (parse, FcSevereError, "out of memory");
2568         return;
2569     }
2570         
2571     while ((vstack = FcVStackPeek (parse)))
2572     {
2573         switch ((int) vstack->tag) {
2574         case FcVStackPattern:
2575             if (!FcPatternAppend (pattern, vstack->u.pattern))
2576             {
2577                 FcConfigMessage (parse, FcSevereError, "out of memory");
2578                 FcPatternDestroy (pattern);
2579                 return;
2580             }
2581             break;
2582         default:
2583             FcConfigMessage (parse, FcSevereWarning, "unknown pattern element");
2584             break;
2585         }
2586         FcVStackPopAndDestroy (parse);
2587     }
2588
2589     FcVStackPushPattern (parse, pattern);
2590 }
2591
2592 static void
2593 FcEndElement(void *userData, const XML_Char *name FC_UNUSED)
2594 {
2595     FcConfigParse   *parse = userData;
2596     FcChar8         *data;
2597
2598     if (!parse->pstack)
2599         return;
2600     switch (parse->pstack->element) {
2601     case FcElementNone:
2602         break;
2603     case FcElementFontconfig:
2604         break;
2605     case FcElementDir:
2606         FcParseDir (parse);
2607         break;
2608     case FcElementCacheDir:
2609         FcParseCacheDir (parse);
2610         break;
2611     case FcElementCache:
2612         data = FcStrBufDoneStatic (&parse->pstack->str);
2613         if (!data)
2614         {
2615             FcConfigMessage (parse, FcSevereError, "out of memory");
2616             break;
2617         }
2618         /* discard this data; no longer used */
2619         FcStrBufDestroy (&parse->pstack->str);
2620         break;
2621     case FcElementInclude:
2622         FcParseInclude (parse);
2623         break;
2624     case FcElementConfig:
2625         break;
2626     case FcElementMatch:
2627         FcParseMatch (parse);
2628         break;
2629     case FcElementAlias:
2630         FcParseAlias (parse);
2631         break;
2632
2633     case FcElementBlank:
2634         FcParseBlank (parse);
2635         break;
2636     case FcElementRescan:
2637         FcParseRescan (parse);
2638         break;
2639         
2640     case FcElementPrefer:
2641         FcParseFamilies (parse, FcVStackPrefer);
2642         break;
2643     case FcElementAccept:
2644         FcParseFamilies (parse, FcVStackAccept);
2645         break;
2646     case FcElementDefault:
2647         FcParseFamilies (parse, FcVStackDefault);
2648         break;
2649     case FcElementFamily:
2650         FcParseFamily (parse);
2651         break;
2652
2653     case FcElementTest:
2654         FcParseTest (parse);
2655         break;
2656     case FcElementEdit:
2657         FcParseEdit (parse);
2658         break;
2659
2660     case FcElementInt:
2661         FcParseInt (parse);
2662         break;
2663     case FcElementDouble:
2664         FcParseDouble (parse);
2665         break;
2666     case FcElementString:
2667         FcParseString (parse, FcVStackString);
2668         break;
2669     case FcElementMatrix:
2670         FcParseMatrix (parse);
2671         break;
2672     case FcElementRange:
2673         FcParseRange (parse);
2674         break;
2675     case FcElementBool:
2676         FcParseBool (parse);
2677         break;
2678     case FcElementCharSet:
2679         FcParseCharSet (parse);
2680         break;
2681     case FcElementLangSet:
2682         FcParseLangSet (parse);
2683         break;
2684     case FcElementSelectfont:
2685         break;
2686     case FcElementAcceptfont:
2687     case FcElementRejectfont:
2688         FcParseAcceptRejectFont (parse, parse->pstack->element);
2689         break;
2690     case FcElementGlob:
2691         FcParseString (parse, FcVStackGlob);
2692         break;
2693     case FcElementPattern:
2694         FcParsePattern (parse);
2695         break;
2696     case FcElementPatelt:
2697         FcParsePatelt (parse);
2698         break;
2699     case FcElementName:
2700         FcParseName (parse);
2701         break;
2702     case FcElementConst:
2703         FcParseString (parse, FcVStackConstant);
2704         break;
2705     case FcElementOr:
2706         FcParseBinary (parse, FcOpOr);
2707         break;
2708     case FcElementAnd:
2709         FcParseBinary (parse, FcOpAnd);
2710         break;
2711     case FcElementEq:
2712         FcParseBinary (parse, FcOpEqual);
2713         break;
2714     case FcElementNotEq:
2715         FcParseBinary (parse, FcOpNotEqual);
2716         break;
2717     case FcElementLess:
2718         FcParseBinary (parse, FcOpLess);
2719         break;
2720     case FcElementLessEq:
2721         FcParseBinary (parse, FcOpLessEqual);
2722         break;
2723     case FcElementMore:
2724         FcParseBinary (parse, FcOpMore);
2725         break;
2726     case FcElementMoreEq:
2727         FcParseBinary (parse, FcOpMoreEqual);
2728         break;
2729     case FcElementContains:
2730         FcParseBinary (parse, FcOpContains);
2731         break;
2732     case FcElementNotContains:
2733         FcParseBinary (parse, FcOpNotContains);
2734         break;
2735     case FcElementPlus:
2736         FcParseBinary (parse, FcOpPlus);
2737         break;
2738     case FcElementMinus:
2739         FcParseBinary (parse, FcOpMinus);
2740         break;
2741     case FcElementTimes:
2742         FcParseBinary (parse, FcOpTimes);
2743         break;
2744     case FcElementDivide:
2745         FcParseBinary (parse, FcOpDivide);
2746         break;
2747     case FcElementNot:
2748         FcParseUnary (parse, FcOpNot);
2749         break;
2750     case FcElementIf:
2751         FcParseBinary (parse, FcOpQuest);
2752         break;
2753     case FcElementFloor:
2754         FcParseUnary (parse, FcOpFloor);
2755         break;
2756     case FcElementCeil:
2757         FcParseUnary (parse, FcOpCeil);
2758         break;
2759     case FcElementRound:
2760         FcParseUnary (parse, FcOpRound);
2761         break;
2762     case FcElementTrunc:
2763         FcParseUnary (parse, FcOpTrunc);
2764         break;
2765     case FcElementUnknown:
2766         break;
2767     }
2768     (void) FcPStackPop (parse);
2769 }
2770
2771 static void
2772 FcCharacterData (void *userData, const XML_Char *s, int len)
2773 {
2774     FcConfigParse   *parse = userData;
2775
2776     if (!parse->pstack)
2777         return;
2778     if (!FcStrBufData (&parse->pstack->str, (FcChar8 *) s, len))
2779         FcConfigMessage (parse, FcSevereError, "out of memory");
2780 }
2781
2782 static void
2783 FcStartDoctypeDecl (void            *userData,
2784                     const XML_Char  *doctypeName,
2785                     const XML_Char  *sysid FC_UNUSED,
2786                     const XML_Char  *pubid FC_UNUSED,
2787                     int             has_internal_subset FC_UNUSED)
2788 {
2789     FcConfigParse   *parse = userData;
2790
2791     if (strcmp ((char *) doctypeName, "fontconfig") != 0)
2792         FcConfigMessage (parse, FcSevereError, "invalid doctype \"%s\"", doctypeName);
2793 }
2794
2795 #ifdef ENABLE_LIBXML2
2796
2797 static void
2798 FcInternalSubsetDecl (void            *userData,
2799                       const XML_Char  *doctypeName,
2800                       const XML_Char  *sysid,
2801                       const XML_Char  *pubid)
2802 {
2803     FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 1);
2804 }
2805
2806 static void
2807 FcExternalSubsetDecl (void            *userData,
2808                       const XML_Char  *doctypeName,
2809                       const XML_Char  *sysid,
2810                       const XML_Char  *pubid)
2811 {
2812     FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 0);
2813 }
2814
2815 #else /* ENABLE_LIBXML2 */
2816
2817 static void
2818 FcEndDoctypeDecl (void *userData FC_UNUSED)
2819 {
2820 }
2821
2822 #endif /* ENABLE_LIBXML2 */
2823
2824 static int
2825 FcSortCmpStr (const void *a, const void *b)
2826 {
2827     const FcChar8    *as = *((FcChar8 **) a);
2828     const FcChar8    *bs = *((FcChar8 **) b);
2829     return FcStrCmp (as, bs);
2830 }
2831
2832 static FcBool
2833 FcConfigParseAndLoadDir (FcConfig       *config,
2834                          const FcChar8  *name,
2835                          const FcChar8  *dir,
2836                          FcBool         complain)
2837 {
2838     DIR             *d;
2839     struct dirent   *e;
2840     FcBool          ret = FcTrue;
2841     FcChar8         *file;
2842     FcChar8         *base;
2843     FcStrSet        *files;
2844
2845     d = opendir ((char *) dir);
2846     if (!d)
2847     {
2848         if (complain)
2849             FcConfigMessage (0, FcSevereError, "Cannot open config dir \"%s\"",
2850                              name);
2851         ret = FcFalse;
2852         goto bail0;
2853     }
2854     /* freed below */
2855     file = (FcChar8 *) malloc (strlen ((char *) dir) + 1 + FC_MAX_FILE_LEN + 1);
2856     if (!file)
2857     {
2858         ret = FcFalse;
2859         goto bail1;
2860     }
2861
2862     strcpy ((char *) file, (char *) dir);
2863     strcat ((char *) file, "/");
2864     base = file + strlen ((char *) file);
2865
2866     files = FcStrSetCreate ();
2867     if (!files)
2868     {
2869         ret = FcFalse;
2870         goto bail2;
2871     }
2872
2873     if (FcDebug () & FC_DBG_CONFIG)
2874         printf ("\tScanning config dir %s\n", dir);
2875         
2876     while (ret && (e = readdir (d)))
2877     {
2878         int d_len;
2879 #define TAIL        ".conf"
2880 #define TAIL_LEN    5
2881         /*
2882          * Add all files of the form [0-9]*.conf
2883          */
2884         if ('0' <= e->d_name[0] && e->d_name[0] <= '9' &&
2885             (d_len = strlen (e->d_name)) < FC_MAX_FILE_LEN &&
2886             d_len > TAIL_LEN &&
2887             strcmp (e->d_name + d_len - TAIL_LEN, TAIL) == 0)
2888         {
2889             strcpy ((char *) base, (char *) e->d_name);
2890             if (!FcStrSetAdd (files, file))
2891             {
2892                 ret = FcFalse;
2893                 goto bail3;
2894             }
2895         }
2896     }
2897     if (ret)
2898     {
2899         int i;
2900         qsort (files->strs, files->num, sizeof (FcChar8 *),
2901                (int (*)(const void *, const void *)) FcSortCmpStr);
2902         for (i = 0; ret && i < files->num; i++)
2903             ret = FcConfigParseAndLoad (config, files->strs[i], complain);
2904     }
2905 bail3:
2906     FcStrSetDestroy (files);
2907 bail2:
2908     free (file);
2909 bail1:
2910     closedir (d);
2911 bail0:
2912     return ret || !complain;
2913 }
2914
2915 #ifdef _WIN32
2916 pfnGetSystemWindowsDirectory pGetSystemWindowsDirectory = NULL;
2917 pfnSHGetFolderPathA pSHGetFolderPathA = NULL;
2918 #endif
2919
2920 FcBool
2921 FcConfigParseAndLoad (FcConfig      *config,
2922                       const FcChar8 *name,
2923                       FcBool        complain)
2924 {
2925
2926     XML_Parser      p;
2927     FcChar8         *filename;
2928     int             fd;
2929     int             len;
2930     FcConfigParse   parse;
2931     FcBool          error = FcTrue;
2932
2933 #ifdef ENABLE_LIBXML2
2934     xmlSAXHandler   sax;
2935     char            buf[BUFSIZ];
2936 #else
2937     void            *buf;
2938 #endif
2939
2940 #ifdef _WIN32
2941     if (!pGetSystemWindowsDirectory)
2942     {
2943         HMODULE hk32 = GetModuleHandleA("kernel32.dll");
2944         if (!(pGetSystemWindowsDirectory = (pfnGetSystemWindowsDirectory) GetProcAddress(hk32, "GetSystemWindowsDirectoryA")))
2945             pGetSystemWindowsDirectory = (pfnGetSystemWindowsDirectory) GetWindowsDirectory;
2946     }
2947     if (!pSHGetFolderPathA)
2948     {
2949         HMODULE hSh = LoadLibraryA("shfolder.dll");
2950         /* the check is done later, because there is no provided fallback */
2951         if (hSh)
2952             pSHGetFolderPathA = (pfnSHGetFolderPathA) GetProcAddress(hSh, "SHGetFolderPathA");
2953     }
2954 #endif
2955
2956     filename = FcConfigFilename (name);
2957     if (!filename)
2958         goto bail0;
2959
2960     if (FcStrSetMember (config->configFiles, filename))
2961     {
2962         FcStrFree (filename);
2963         return FcTrue;
2964     }
2965
2966     if (!FcStrSetAdd (config->configFiles, filename))
2967     {
2968         FcStrFree (filename);
2969         goto bail0;
2970     }
2971
2972     if (FcFileIsDir (filename))
2973     {
2974         FcBool ret = FcConfigParseAndLoadDir (config, name, filename, complain);
2975         FcStrFree (filename);
2976         return ret;
2977     }
2978
2979     if (FcDebug () & FC_DBG_CONFIG)
2980         printf ("\tLoading config file %s\n", filename);
2981
2982     fd = open ((char *) filename, O_RDONLY);
2983     if (fd == -1) {
2984         FcStrFree (filename);
2985         goto bail0;
2986     }
2987
2988 #ifdef ENABLE_LIBXML2
2989     memset(&sax, 0, sizeof(sax));
2990
2991     sax.internalSubset = FcInternalSubsetDecl;
2992     sax.externalSubset = FcExternalSubsetDecl;
2993     sax.startElement = FcStartElement;
2994     sax.endElement = FcEndElement;
2995     sax.characters = FcCharacterData;
2996
2997     p = xmlCreatePushParserCtxt (&sax, &parse, NULL, 0, (const char *) filename);
2998 #else
2999     p = XML_ParserCreate ("UTF-8");
3000 #endif
3001     FcStrFree (filename);
3002
3003     if (!p)
3004         goto bail1;
3005
3006     if (!FcConfigParseInit (&parse, name, config, p))
3007         goto bail2;
3008
3009 #ifndef ENABLE_LIBXML2
3010
3011     XML_SetUserData (p, &parse);
3012
3013     XML_SetDoctypeDeclHandler (p, FcStartDoctypeDecl, FcEndDoctypeDecl);
3014     XML_SetElementHandler (p, FcStartElement, FcEndElement);
3015     XML_SetCharacterDataHandler (p, FcCharacterData);
3016         
3017 #endif /* ENABLE_LIBXML2 */
3018
3019     do {
3020 #ifndef ENABLE_LIBXML2
3021         buf = XML_GetBuffer (p, BUFSIZ);
3022         if (!buf)
3023         {
3024             FcConfigMessage (&parse, FcSevereError, "cannot get parse buffer");
3025             goto bail3;
3026         }
3027 #endif
3028         len = read (fd, buf, BUFSIZ);
3029         if (len < 0)
3030         {
3031             FcConfigMessage (&parse, FcSevereError, "failed reading config file");
3032             goto bail3;
3033         }
3034
3035 #ifdef ENABLE_LIBXML2
3036         if (xmlParseChunk (p, buf, len, len == 0))
3037 #else
3038         if (!XML_ParseBuffer (p, len, len == 0))
3039 #endif
3040         {
3041             FcConfigMessage (&parse, FcSevereError, "%s",
3042                            XML_ErrorString (XML_GetErrorCode (p)));
3043             goto bail3;
3044         }
3045     } while (len != 0);
3046     error = parse.error;
3047 bail3:
3048     FcConfigCleanup (&parse);
3049 bail2:
3050     XML_ParserFree (p);
3051 bail1:
3052     close (fd);
3053     fd = -1;
3054 bail0:
3055     if (error && complain)
3056     {
3057         if (name)
3058             FcConfigMessage (0, FcSevereError, "Cannot load config file \"%s\"", name);
3059         else
3060             FcConfigMessage (0, FcSevereError, "Cannot load default config file");
3061         return FcFalse;
3062     }
3063     return FcTrue;
3064 }
3065 #define __fcxml__
3066 #include "fcaliastail.h"
3067 #undef __fcxml__