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