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