Fix build issue on Debian/kFreeBSD 7.0
[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     static FcChar8  *userdir = NULL;
2186     static FcChar8  *userconf = NULL;
2187
2188     s = FcStrBufDoneStatic (&parse->pstack->str);
2189     if (!s)
2190     {
2191         FcConfigMessage (parse, FcSevereError, "out of memory");
2192         goto bail;
2193     }
2194     attr = FcConfigGetAttribute (parse, "ignore_missing");
2195     if (attr && FcConfigLexBool (parse, (FcChar8 *) attr) == FcTrue)
2196         ignore_missing = FcTrue;
2197     attr = FcConfigGetAttribute (parse, "deprecated");
2198     if (attr && FcConfigLexBool (parse, (FcChar8 *) attr) == FcTrue)
2199         deprecated = FcTrue;
2200     attr = FcConfigGetAttribute (parse, "prefix");
2201     if (attr && FcStrCmp (attr, (const FcChar8 *)"xdg") == 0)
2202         prefix = FcConfigXdgConfigHome ();
2203     if (prefix)
2204     {
2205         size_t plen = strlen ((const char *)prefix);
2206         size_t dlen = strlen ((const char *)s);
2207
2208         p = realloc (prefix, plen + 1 + dlen + 1);
2209         if (!p)
2210         {
2211             FcConfigMessage (parse, FcSevereError, "out of memory");
2212             goto bail;
2213         }
2214         prefix = p;
2215         prefix[plen] = FC_DIR_SEPARATOR;
2216         memcpy (&prefix[plen + 1], s, dlen);
2217         prefix[plen + 1 + dlen] = 0;
2218         s = prefix;
2219         if (FcFileIsDir (s))
2220         {
2221         userdir:
2222             if (!userdir)
2223                 userdir = FcStrdup (s);
2224         }
2225         else if (FcFileIsFile (s))
2226         {
2227         userconf:
2228             if (!userconf)
2229                 userconf = FcStrdup (s);
2230         }
2231         else
2232         {
2233             /* No config dir nor file on the XDG directory spec compliant place
2234              * so need to guess what it is supposed to be.
2235              */
2236             if (FcStrStr (s, (const FcChar8 *)"conf.d") != NULL)
2237                 goto userdir;
2238             else
2239                 goto userconf;
2240         }
2241     }
2242     if (!FcConfigParseAndLoad (parse->config, s, !ignore_missing))
2243         parse->error = FcTrue;
2244 #ifndef _WIN32
2245     else
2246     {
2247         FcChar8 *filename;
2248         static FcBool warn_conf = FcFalse, warn_confd = FcFalse;
2249
2250         filename = FcConfigFilename(s);
2251         if (deprecated == FcTrue &&
2252             filename != NULL &&
2253             !FcFileIsLink (filename))
2254         {
2255             if (FcFileIsDir (filename))
2256             {
2257                 FcChar8 *parent = FcStrDirname (userdir);
2258
2259                 if (!FcFileIsDir (parent))
2260                     FcMakeDirectory (parent);
2261                 FcStrFree (parent);
2262                 if (FcFileIsDir (userdir) ||
2263                     rename ((const char *)filename, (const char *)userdir) != 0 ||
2264                     symlink ((const char *)userdir, (const char *)filename) != 0)
2265                 {
2266                     if (!warn_confd)
2267                     {
2268                         FcConfigMessage (parse, FcSevereWarning, "reading configurations from %s is deprecated. please move it to %s manually", s, userdir);
2269                         warn_confd = FcTrue;
2270                     }
2271                 }
2272             }
2273             else
2274             {
2275                 FcChar8 *parent = FcStrDirname (userconf);
2276
2277                 if (!FcFileIsDir (parent))
2278                     FcMakeDirectory (parent);
2279                 FcStrFree (parent);
2280                 if (FcFileIsFile (userconf) ||
2281                     rename ((const char *)filename, (const char *)userconf) != 0 ||
2282                     symlink ((const char *)userconf, (const char *)filename) != 0)
2283                 {
2284                     if (!warn_conf)
2285                     {
2286                         FcConfigMessage (parse, FcSevereWarning, "reading configurations from %s is deprecated. please move it to %s manually", s, userconf);
2287                         warn_conf = FcTrue;
2288                     }
2289                 }
2290             }
2291         }
2292         if(filename)
2293             FcStrFree(filename);
2294     }
2295 #endif
2296     FcStrBufDestroy (&parse->pstack->str);
2297
2298   bail:
2299     if (prefix)
2300         FcStrFree (prefix);
2301 }
2302
2303 typedef struct _FcOpMap {
2304     char    name[16];
2305     FcOp    op;
2306 } FcOpMap;
2307
2308 static FcOp
2309 FcConfigLexOp (const FcChar8 *op, const FcOpMap *map, int nmap)
2310 {
2311     int i;
2312
2313     for (i = 0; i < nmap; i++)
2314         if (!strcmp ((char *) op, map[i].name))
2315             return map[i].op;
2316     return FcOpInvalid;
2317 }
2318
2319 static const FcOpMap fcCompareOps[] = {
2320     { "eq",             FcOpEqual           },
2321     { "not_eq",         FcOpNotEqual        },
2322     { "less",           FcOpLess            },
2323     { "less_eq",        FcOpLessEqual       },
2324     { "more",           FcOpMore            },
2325     { "more_eq",        FcOpMoreEqual       },
2326     { "contains",       FcOpContains        },
2327     { "not_contains",   FcOpNotContains     }
2328 };
2329
2330 #define NUM_COMPARE_OPS (int) (sizeof fcCompareOps / sizeof fcCompareOps[0])
2331
2332 static FcOp
2333 FcConfigLexCompare (const FcChar8 *compare)
2334 {
2335     return FcConfigLexOp (compare, fcCompareOps, NUM_COMPARE_OPS);
2336 }
2337
2338 static void
2339 FcParseTest (FcConfigParse *parse)
2340 {
2341     const FcChar8   *kind_string;
2342     FcMatchKind     kind;
2343     const FcChar8   *qual_string;
2344     FcQual          qual;
2345     const FcChar8   *name;
2346     const FcChar8   *compare_string;
2347     FcOp            compare;
2348     FcExpr          *expr;
2349     FcTest          *test;
2350     const FcChar8   *iblanks_string;
2351     int              flags = 0;
2352
2353     kind_string = FcConfigGetAttribute (parse, "target");
2354     if (!kind_string)
2355         kind = FcMatchDefault;
2356     else
2357     {
2358         if (!strcmp ((char *) kind_string, "pattern"))
2359             kind = FcMatchPattern;
2360         else if (!strcmp ((char *) kind_string, "font"))
2361             kind = FcMatchFont;
2362         else if (!strcmp ((char *) kind_string, "scan"))
2363             kind = FcMatchScan;
2364         else if (!strcmp ((char *) kind_string, "default"))
2365             kind = FcMatchDefault;
2366         else
2367         {
2368             FcConfigMessage (parse, FcSevereWarning, "invalid test target \"%s\"", kind_string);
2369             return;
2370         }
2371     }
2372     qual_string = FcConfigGetAttribute (parse, "qual");
2373     if (!qual_string)
2374         qual = FcQualAny;
2375     else
2376     {
2377         if (!strcmp ((char *) qual_string, "any"))
2378             qual = FcQualAny;
2379         else if (!strcmp ((char *) qual_string, "all"))
2380             qual = FcQualAll;
2381         else if (!strcmp ((char *) qual_string, "first"))
2382             qual = FcQualFirst;
2383         else if (!strcmp ((char *) qual_string, "not_first"))
2384             qual = FcQualNotFirst;
2385         else
2386         {
2387             FcConfigMessage (parse, FcSevereWarning, "invalid test qual \"%s\"", qual_string);
2388             return;
2389         }
2390     }
2391     name = FcConfigGetAttribute (parse, "name");
2392     if (!name)
2393     {
2394         FcConfigMessage (parse, FcSevereWarning, "missing test name");
2395         return;
2396     }
2397     compare_string = FcConfigGetAttribute (parse, "compare");
2398     if (!compare_string)
2399         compare = FcOpEqual;
2400     else
2401     {
2402         compare = FcConfigLexCompare (compare_string);
2403         if (compare == FcOpInvalid)
2404         {
2405             FcConfigMessage (parse, FcSevereWarning, "invalid test compare \"%s\"", compare_string);
2406             return;
2407         }
2408     }
2409     iblanks_string = FcConfigGetAttribute (parse, "ignore-blanks");
2410     if (iblanks_string)
2411     {
2412         FcBool f = FcFalse;
2413
2414         if (!FcNameBool (iblanks_string, &f))
2415         {
2416             FcConfigMessage (parse,
2417                              FcSevereWarning,
2418                              "invalid test ignore-blanks \"%s\"", iblanks_string);
2419         }
2420         if (f)
2421             flags |= FcOpFlagIgnoreBlanks;
2422     }
2423     expr = FcPopBinary (parse, FcOpComma);
2424     if (!expr)
2425     {
2426         FcConfigMessage (parse, FcSevereWarning, "missing test expression");
2427         return;
2428     }
2429     if (expr->op == FcOpComma)
2430     {
2431         FcConfigMessage (parse, FcSevereWarning, "Having multiple values in <test> isn't supported and may not work as expected");
2432     }
2433     test = FcTestCreate (parse, kind, qual, name, FC_OP (compare, flags), expr);
2434     if (!test)
2435     {
2436         FcConfigMessage (parse, FcSevereError, "out of memory");
2437         return;
2438     }
2439     FcVStackPushTest (parse, test);
2440 }
2441
2442 static const FcOpMap fcModeOps[] = {
2443     { "assign",         FcOpAssign          },
2444     { "assign_replace", FcOpAssignReplace   },
2445     { "prepend",        FcOpPrepend         },
2446     { "prepend_first",  FcOpPrependFirst    },
2447     { "append",         FcOpAppend          },
2448     { "append_last",    FcOpAppendLast      },
2449     { "delete",         FcOpDelete          },
2450     { "delete_all",     FcOpDeleteAll       },
2451 };
2452
2453 #define NUM_MODE_OPS (int) (sizeof fcModeOps / sizeof fcModeOps[0])
2454
2455 static FcOp
2456 FcConfigLexMode (const FcChar8 *mode)
2457 {
2458     return FcConfigLexOp (mode, fcModeOps, NUM_MODE_OPS);
2459 }
2460
2461 static void
2462 FcParseEdit (FcConfigParse *parse)
2463 {
2464     const FcChar8   *name;
2465     const FcChar8   *mode_string;
2466     FcOp            mode;
2467     FcValueBinding  binding;
2468     FcExpr          *expr;
2469     FcEdit          *edit;
2470
2471     name = FcConfigGetAttribute (parse, "name");
2472     if (!name)
2473     {
2474         FcConfigMessage (parse, FcSevereWarning, "missing edit name");
2475         return;
2476     }
2477     mode_string = FcConfigGetAttribute (parse, "mode");
2478     if (!mode_string)
2479         mode = FcOpAssign;
2480     else
2481     {
2482         mode = FcConfigLexMode (mode_string);
2483         if (mode == FcOpInvalid)
2484         {
2485             FcConfigMessage (parse, FcSevereWarning, "invalid edit mode \"%s\"", mode_string);
2486             return;
2487         }
2488     }
2489     if (!FcConfigLexBinding (parse, FcConfigGetAttribute (parse, "binding"), &binding))
2490         return;
2491
2492     expr = FcPopBinary (parse, FcOpComma);
2493     if ((mode == FcOpDelete || mode == FcOpDeleteAll) &&
2494         expr != NULL)
2495     {
2496         FcConfigMessage (parse, FcSevereWarning, "Expression doesn't take any effects for delete and delete_all");
2497         FcExprDestroy (expr);
2498         expr = NULL;
2499     }
2500     edit = FcEditCreate (parse, FcObjectFromName ((char *) name),
2501                          mode, expr, binding);
2502     if (!edit)
2503     {
2504         FcConfigMessage (parse, FcSevereError, "out of memory");
2505         FcExprDestroy (expr);
2506         return;
2507     }
2508     if (!FcVStackPushEdit (parse, edit))
2509         FcEditDestroy (edit);
2510 }
2511
2512 static void
2513 FcParseMatch (FcConfigParse *parse)
2514 {
2515     const FcChar8   *kind_name;
2516     FcMatchKind     kind;
2517     FcVStack        *vstack;
2518     FcRule          *rule = NULL, *r;
2519
2520     kind_name = FcConfigGetAttribute (parse, "target");
2521     if (!kind_name)
2522         kind = FcMatchPattern;
2523     else
2524     {
2525         if (!strcmp ((char *) kind_name, "pattern"))
2526             kind = FcMatchPattern;
2527         else if (!strcmp ((char *) kind_name, "font"))
2528             kind = FcMatchFont;
2529         else if (!strcmp ((char *) kind_name, "scan"))
2530             kind = FcMatchScan;
2531         else
2532         {
2533             FcConfigMessage (parse, FcSevereWarning, "invalid match target \"%s\"", kind_name);
2534             return;
2535         }
2536     }
2537     while ((vstack = FcVStackPeek (parse)))
2538     {
2539         switch ((int) vstack->tag) {
2540         case FcVStackTest:
2541             r = FcRuleCreate (FcRuleTest, vstack->u.test);
2542             if (rule)
2543                 r->next = rule;
2544             rule = r;
2545             vstack->tag = FcVStackNone;
2546             break;
2547         case FcVStackEdit:
2548             if (kind == FcMatchScan && vstack->u.edit->object > FC_MAX_BASE_OBJECT)
2549             {
2550                 FcConfigMessage (parse, FcSevereError,
2551                                  "<match target=\"scan\"> cannot edit user-defined object \"%s\"",
2552                                  FcObjectName(vstack->u.edit->object));
2553                 if (rule)
2554                     FcRuleDestroy (rule);
2555                 return;
2556             }
2557             r = FcRuleCreate (FcRuleEdit, vstack->u.edit);
2558             if (rule)
2559                 r->next = rule;
2560             rule = r;
2561             vstack->tag = FcVStackNone;
2562             break;
2563         default:
2564             FcConfigMessage (parse, FcSevereWarning, "invalid match element");
2565             break;
2566         }
2567         FcVStackPopAndDestroy (parse);
2568     }
2569     if (!FcConfigAddRule (parse->config, rule, kind))
2570         FcConfigMessage (parse, FcSevereError, "out of memory");
2571 }
2572
2573 static void
2574 FcParseAcceptRejectFont (FcConfigParse *parse, FcElement element)
2575 {
2576     FcVStack    *vstack;
2577
2578     while ((vstack = FcVStackPeek (parse)))
2579     {
2580         switch ((int) vstack->tag) {
2581         case FcVStackGlob:
2582             if (!FcConfigGlobAdd (parse->config,
2583                                   vstack->u.string,
2584                                   element == FcElementAcceptfont))
2585             {
2586                 FcConfigMessage (parse, FcSevereError, "out of memory");
2587             }
2588             break;
2589         case FcVStackPattern:
2590             if (!FcConfigPatternsAdd (parse->config,
2591                                       vstack->u.pattern,
2592                                       element == FcElementAcceptfont))
2593             {
2594                 FcConfigMessage (parse, FcSevereError, "out of memory");
2595             }
2596             else
2597                 vstack->tag = FcVStackNone;
2598             break;
2599         default:
2600             FcConfigMessage (parse, FcSevereWarning, "bad font selector");
2601             break;
2602         }
2603         FcVStackPopAndDestroy (parse);
2604     }
2605 }
2606
2607
2608 static FcValue
2609 FcPopValue (FcConfigParse *parse)
2610 {
2611     FcVStack    *vstack = FcVStackPeek (parse);
2612     FcValue     value;
2613
2614     value.type = FcTypeVoid;
2615
2616     if (!vstack)
2617         return value;
2618
2619     switch ((int) vstack->tag) {
2620     case FcVStackString:
2621         value.u.s = FcStrdup (vstack->u.string);
2622         if (value.u.s)
2623             value.type = FcTypeString;
2624         break;
2625     case FcVStackConstant:
2626         if (FcNameConstant (vstack->u.string, &value.u.i))
2627             value.type = FcTypeInteger;
2628         break;
2629     case FcVStackInteger:
2630         value.u.i = vstack->u.integer;
2631         value.type = FcTypeInteger;
2632         break;
2633     case FcVStackDouble:
2634         value.u.d = vstack->u._double;
2635         value.type = FcTypeDouble;
2636         break;
2637     case FcVStackBool:
2638         value.u.b = vstack->u.bool_;
2639         value.type = FcTypeBool;
2640         break;
2641     case FcVStackCharSet:
2642         value.u.c = FcCharSetCopy (vstack->u.charset);
2643         if (value.u.c)
2644             value.type = FcTypeCharSet;
2645         break;
2646     case FcVStackLangSet:
2647         value.u.l = FcLangSetCopy (vstack->u.langset);
2648         if (value.u.l)
2649             value.type = FcTypeLangSet;
2650         break;
2651     default:
2652         FcConfigMessage (parse, FcSevereWarning, "unknown pattern element %d",
2653                          vstack->tag);
2654         break;
2655     }
2656     FcVStackPopAndDestroy (parse);
2657
2658     return value;
2659 }
2660
2661 static void
2662 FcParsePatelt (FcConfigParse *parse)
2663 {
2664     FcValue     value;
2665     FcPattern   *pattern = FcPatternCreate ();
2666     const char  *name;
2667
2668     if (!pattern)
2669     {
2670         FcConfigMessage (parse, FcSevereError, "out of memory");
2671         return;
2672     }
2673
2674     name = (char *) FcConfigGetAttribute (parse, "name");
2675     if (!name)
2676     {
2677         FcConfigMessage (parse, FcSevereWarning, "missing pattern element name");
2678         FcPatternDestroy (pattern);
2679         return;
2680     }
2681
2682     for (;;)
2683     {
2684         value = FcPopValue (parse);
2685         if (value.type == FcTypeVoid)
2686             break;
2687         if (!FcPatternAdd (pattern, name, value, FcTrue))
2688         {
2689             FcConfigMessage (parse, FcSevereError, "out of memory");
2690             FcValueDestroy(value);
2691             break;
2692         }
2693         FcValueDestroy(value);
2694     }
2695
2696     FcVStackPushPattern (parse, pattern);
2697 }
2698
2699 static void
2700 FcParsePattern (FcConfigParse *parse)
2701 {
2702     FcVStack    *vstack;
2703     FcPattern   *pattern = FcPatternCreate ();
2704
2705     if (!pattern)
2706     {
2707         FcConfigMessage (parse, FcSevereError, "out of memory");
2708         return;
2709     }
2710         
2711     while ((vstack = FcVStackPeek (parse)))
2712     {
2713         switch ((int) vstack->tag) {
2714         case FcVStackPattern:
2715             if (!FcPatternAppend (pattern, vstack->u.pattern))
2716             {
2717                 FcConfigMessage (parse, FcSevereError, "out of memory");
2718                 FcPatternDestroy (pattern);
2719                 return;
2720             }
2721             break;
2722         default:
2723             FcConfigMessage (parse, FcSevereWarning, "unknown pattern element");
2724             break;
2725         }
2726         FcVStackPopAndDestroy (parse);
2727     }
2728
2729     FcVStackPushPattern (parse, pattern);
2730 }
2731
2732 static void
2733 FcEndElement(void *userData, const XML_Char *name FC_UNUSED)
2734 {
2735     FcConfigParse   *parse = userData;
2736     FcChar8         *data;
2737
2738     if (!parse->pstack)
2739         return;
2740     switch (parse->pstack->element) {
2741     case FcElementNone:
2742         break;
2743     case FcElementFontconfig:
2744         break;
2745     case FcElementDir:
2746         FcParseDir (parse);
2747         break;
2748     case FcElementCacheDir:
2749         FcParseCacheDir (parse);
2750         break;
2751     case FcElementCache:
2752         data = FcStrBufDoneStatic (&parse->pstack->str);
2753         if (!data)
2754         {
2755             FcConfigMessage (parse, FcSevereError, "out of memory");
2756             break;
2757         }
2758         /* discard this data; no longer used */
2759         FcStrBufDestroy (&parse->pstack->str);
2760         break;
2761     case FcElementInclude:
2762         FcParseInclude (parse);
2763         break;
2764     case FcElementConfig:
2765         break;
2766     case FcElementMatch:
2767         FcParseMatch (parse);
2768         break;
2769     case FcElementAlias:
2770         FcParseAlias (parse);
2771         break;
2772
2773     case FcElementBlank:
2774         FcParseBlank (parse);
2775         break;
2776     case FcElementRescan:
2777         FcParseRescan (parse);
2778         break;
2779         
2780     case FcElementPrefer:
2781         FcParseFamilies (parse, FcVStackPrefer);
2782         break;
2783     case FcElementAccept:
2784         FcParseFamilies (parse, FcVStackAccept);
2785         break;
2786     case FcElementDefault:
2787         FcParseFamilies (parse, FcVStackDefault);
2788         break;
2789     case FcElementFamily:
2790         FcParseFamily (parse);
2791         break;
2792
2793     case FcElementTest:
2794         FcParseTest (parse);
2795         break;
2796     case FcElementEdit:
2797         FcParseEdit (parse);
2798         break;
2799
2800     case FcElementInt:
2801         FcParseInt (parse);
2802         break;
2803     case FcElementDouble:
2804         FcParseDouble (parse);
2805         break;
2806     case FcElementString:
2807         FcParseString (parse, FcVStackString);
2808         break;
2809     case FcElementMatrix:
2810         FcParseMatrix (parse);
2811         break;
2812     case FcElementRange:
2813         FcParseRange (parse);
2814         break;
2815     case FcElementBool:
2816         FcParseBool (parse);
2817         break;
2818     case FcElementCharSet:
2819         FcParseCharSet (parse);
2820         break;
2821     case FcElementLangSet:
2822         FcParseLangSet (parse);
2823         break;
2824     case FcElementSelectfont:
2825         break;
2826     case FcElementAcceptfont:
2827     case FcElementRejectfont:
2828         FcParseAcceptRejectFont (parse, parse->pstack->element);
2829         break;
2830     case FcElementGlob:
2831         FcParseString (parse, FcVStackGlob);
2832         break;
2833     case FcElementPattern:
2834         FcParsePattern (parse);
2835         break;
2836     case FcElementPatelt:
2837         FcParsePatelt (parse);
2838         break;
2839     case FcElementName:
2840         FcParseName (parse);
2841         break;
2842     case FcElementConst:
2843         FcParseString (parse, FcVStackConstant);
2844         break;
2845     case FcElementOr:
2846         FcParseBinary (parse, FcOpOr);
2847         break;
2848     case FcElementAnd:
2849         FcParseBinary (parse, FcOpAnd);
2850         break;
2851     case FcElementEq:
2852         FcParseBinary (parse, FcOpEqual);
2853         break;
2854     case FcElementNotEq:
2855         FcParseBinary (parse, FcOpNotEqual);
2856         break;
2857     case FcElementLess:
2858         FcParseBinary (parse, FcOpLess);
2859         break;
2860     case FcElementLessEq:
2861         FcParseBinary (parse, FcOpLessEqual);
2862         break;
2863     case FcElementMore:
2864         FcParseBinary (parse, FcOpMore);
2865         break;
2866     case FcElementMoreEq:
2867         FcParseBinary (parse, FcOpMoreEqual);
2868         break;
2869     case FcElementContains:
2870         FcParseBinary (parse, FcOpContains);
2871         break;
2872     case FcElementNotContains:
2873         FcParseBinary (parse, FcOpNotContains);
2874         break;
2875     case FcElementPlus:
2876         FcParseBinary (parse, FcOpPlus);
2877         break;
2878     case FcElementMinus:
2879         FcParseBinary (parse, FcOpMinus);
2880         break;
2881     case FcElementTimes:
2882         FcParseBinary (parse, FcOpTimes);
2883         break;
2884     case FcElementDivide:
2885         FcParseBinary (parse, FcOpDivide);
2886         break;
2887     case FcElementNot:
2888         FcParseUnary (parse, FcOpNot);
2889         break;
2890     case FcElementIf:
2891         FcParseBinary (parse, FcOpQuest);
2892         break;
2893     case FcElementFloor:
2894         FcParseUnary (parse, FcOpFloor);
2895         break;
2896     case FcElementCeil:
2897         FcParseUnary (parse, FcOpCeil);
2898         break;
2899     case FcElementRound:
2900         FcParseUnary (parse, FcOpRound);
2901         break;
2902     case FcElementTrunc:
2903         FcParseUnary (parse, FcOpTrunc);
2904         break;
2905     case FcElementUnknown:
2906         break;
2907     }
2908     (void) FcPStackPop (parse);
2909 }
2910
2911 static void
2912 FcCharacterData (void *userData, const XML_Char *s, int len)
2913 {
2914     FcConfigParse   *parse = userData;
2915
2916     if (!parse->pstack)
2917         return;
2918     if (!FcStrBufData (&parse->pstack->str, (FcChar8 *) s, len))
2919         FcConfigMessage (parse, FcSevereError, "out of memory");
2920 }
2921
2922 static void
2923 FcStartDoctypeDecl (void            *userData,
2924                     const XML_Char  *doctypeName,
2925                     const XML_Char  *sysid FC_UNUSED,
2926                     const XML_Char  *pubid FC_UNUSED,
2927                     int             has_internal_subset FC_UNUSED)
2928 {
2929     FcConfigParse   *parse = userData;
2930
2931     if (strcmp ((char *) doctypeName, "fontconfig") != 0)
2932         FcConfigMessage (parse, FcSevereError, "invalid doctype \"%s\"", doctypeName);
2933 }
2934
2935 #ifdef ENABLE_LIBXML2
2936
2937 static void
2938 FcInternalSubsetDecl (void            *userData,
2939                       const XML_Char  *doctypeName,
2940                       const XML_Char  *sysid,
2941                       const XML_Char  *pubid)
2942 {
2943     FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 1);
2944 }
2945
2946 static void
2947 FcExternalSubsetDecl (void            *userData,
2948                       const XML_Char  *doctypeName,
2949                       const XML_Char  *sysid,
2950                       const XML_Char  *pubid)
2951 {
2952     FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 0);
2953 }
2954
2955 #else /* ENABLE_LIBXML2 */
2956
2957 static void
2958 FcEndDoctypeDecl (void *userData FC_UNUSED)
2959 {
2960 }
2961
2962 #endif /* ENABLE_LIBXML2 */
2963
2964 static int
2965 FcSortCmpStr (const void *a, const void *b)
2966 {
2967     const FcChar8    *as = *((FcChar8 **) a);
2968     const FcChar8    *bs = *((FcChar8 **) b);
2969     return FcStrCmp (as, bs);
2970 }
2971
2972 static FcBool
2973 FcConfigParseAndLoadDir (FcConfig       *config,
2974                          const FcChar8  *name,
2975                          const FcChar8  *dir,
2976                          FcBool         complain)
2977 {
2978     DIR             *d;
2979     struct dirent   *e;
2980     FcBool          ret = FcTrue;
2981     FcChar8         *file;
2982     FcChar8         *base;
2983     FcStrSet        *files;
2984
2985     d = opendir ((char *) dir);
2986     if (!d)
2987     {
2988         if (complain)
2989             FcConfigMessage (0, FcSevereError, "Cannot open config dir \"%s\"",
2990                              name);
2991         ret = FcFalse;
2992         goto bail0;
2993     }
2994     /* freed below */
2995     file = (FcChar8 *) malloc (strlen ((char *) dir) + 1 + FC_MAX_FILE_LEN + 1);
2996     if (!file)
2997     {
2998         ret = FcFalse;
2999         goto bail1;
3000     }
3001
3002     strcpy ((char *) file, (char *) dir);
3003     strcat ((char *) file, "/");
3004     base = file + strlen ((char *) file);
3005
3006     files = FcStrSetCreate ();
3007     if (!files)
3008     {
3009         ret = FcFalse;
3010         goto bail2;
3011     }
3012
3013     if (FcDebug () & FC_DBG_CONFIG)
3014         printf ("\tScanning config dir %s\n", dir);
3015         
3016     while (ret && (e = readdir (d)))
3017     {
3018         int d_len;
3019 #define TAIL        ".conf"
3020 #define TAIL_LEN    5
3021         /*
3022          * Add all files of the form [0-9]*.conf
3023          */
3024         if ('0' <= e->d_name[0] && e->d_name[0] <= '9' &&
3025             (d_len = strlen (e->d_name)) < FC_MAX_FILE_LEN &&
3026             d_len > TAIL_LEN &&
3027             strcmp (e->d_name + d_len - TAIL_LEN, TAIL) == 0)
3028         {
3029             strcpy ((char *) base, (char *) e->d_name);
3030             if (!FcStrSetAdd (files, file))
3031             {
3032                 ret = FcFalse;
3033                 goto bail3;
3034             }
3035         }
3036     }
3037     if (ret)
3038     {
3039         int i;
3040         qsort (files->strs, files->num, sizeof (FcChar8 *),
3041                (int (*)(const void *, const void *)) FcSortCmpStr);
3042         for (i = 0; ret && i < files->num; i++)
3043             ret = FcConfigParseAndLoad (config, files->strs[i], complain);
3044     }
3045 bail3:
3046     FcStrSetDestroy (files);
3047 bail2:
3048     free (file);
3049 bail1:
3050     closedir (d);
3051 bail0:
3052     return ret || !complain;
3053 }
3054
3055 #ifdef _WIN32
3056 pfnGetSystemWindowsDirectory pGetSystemWindowsDirectory = NULL;
3057 pfnSHGetFolderPathA pSHGetFolderPathA = NULL;
3058 #endif
3059
3060 FcBool
3061 FcConfigParseAndLoad (FcConfig      *config,
3062                       const FcChar8 *name,
3063                       FcBool        complain)
3064 {
3065
3066     XML_Parser      p;
3067     FcChar8         *filename;
3068     int             fd;
3069     int             len;
3070     FcConfigParse   parse;
3071     FcBool          error = FcTrue;
3072
3073 #ifdef ENABLE_LIBXML2
3074     xmlSAXHandler   sax;
3075     char            buf[BUFSIZ];
3076 #else
3077     void            *buf;
3078 #endif
3079
3080 #ifdef _WIN32
3081     if (!pGetSystemWindowsDirectory)
3082     {
3083         HMODULE hk32 = GetModuleHandleA("kernel32.dll");
3084         if (!(pGetSystemWindowsDirectory = (pfnGetSystemWindowsDirectory) GetProcAddress(hk32, "GetSystemWindowsDirectoryA")))
3085             pGetSystemWindowsDirectory = (pfnGetSystemWindowsDirectory) GetWindowsDirectory;
3086     }
3087     if (!pSHGetFolderPathA)
3088     {
3089         HMODULE hSh = LoadLibraryA("shfolder.dll");
3090         /* the check is done later, because there is no provided fallback */
3091         if (hSh)
3092             pSHGetFolderPathA = (pfnSHGetFolderPathA) GetProcAddress(hSh, "SHGetFolderPathA");
3093     }
3094 #endif
3095
3096     filename = FcConfigFilename (name);
3097     if (!filename)
3098         goto bail0;
3099
3100     if (FcStrSetMember (config->configFiles, filename))
3101     {
3102         FcStrFree (filename);
3103         return FcTrue;
3104     }
3105
3106     if (!FcStrSetAdd (config->configFiles, filename))
3107     {
3108         FcStrFree (filename);
3109         goto bail0;
3110     }
3111
3112     if (FcFileIsDir (filename))
3113     {
3114         FcBool ret = FcConfigParseAndLoadDir (config, name, filename, complain);
3115         FcStrFree (filename);
3116         return ret;
3117     }
3118
3119     if (FcDebug () & FC_DBG_CONFIG)
3120         printf ("\tLoading config file %s\n", filename);
3121
3122     fd = FcOpen ((char *) filename, O_RDONLY);
3123     if (fd == -1) {
3124         FcStrFree (filename);
3125         goto bail0;
3126     }
3127
3128 #ifdef ENABLE_LIBXML2
3129     memset(&sax, 0, sizeof(sax));
3130
3131     sax.internalSubset = FcInternalSubsetDecl;
3132     sax.externalSubset = FcExternalSubsetDecl;
3133     sax.startElement = FcStartElement;
3134     sax.endElement = FcEndElement;
3135     sax.characters = FcCharacterData;
3136
3137     p = xmlCreatePushParserCtxt (&sax, &parse, NULL, 0, (const char *) filename);
3138 #else
3139     p = XML_ParserCreate ("UTF-8");
3140 #endif
3141     FcStrFree (filename);
3142
3143     if (!p)
3144         goto bail1;
3145
3146     if (!FcConfigParseInit (&parse, name, config, p))
3147         goto bail2;
3148
3149 #ifndef ENABLE_LIBXML2
3150
3151     XML_SetUserData (p, &parse);
3152
3153     XML_SetDoctypeDeclHandler (p, FcStartDoctypeDecl, FcEndDoctypeDecl);
3154     XML_SetElementHandler (p, FcStartElement, FcEndElement);
3155     XML_SetCharacterDataHandler (p, FcCharacterData);
3156         
3157 #endif /* ENABLE_LIBXML2 */
3158
3159     do {
3160 #ifndef ENABLE_LIBXML2
3161         buf = XML_GetBuffer (p, BUFSIZ);
3162         if (!buf)
3163         {
3164             FcConfigMessage (&parse, FcSevereError, "cannot get parse buffer");
3165             goto bail3;
3166         }
3167 #endif
3168         len = read (fd, buf, BUFSIZ);
3169         if (len < 0)
3170         {
3171             FcConfigMessage (&parse, FcSevereError, "failed reading config file");
3172             goto bail3;
3173         }
3174
3175 #ifdef ENABLE_LIBXML2
3176         if (xmlParseChunk (p, buf, len, len == 0))
3177 #else
3178         if (!XML_ParseBuffer (p, len, len == 0))
3179 #endif
3180         {
3181             FcConfigMessage (&parse, FcSevereError, "%s",
3182                            XML_ErrorString (XML_GetErrorCode (p)));
3183             goto bail3;
3184         }
3185     } while (len != 0);
3186     error = parse.error;
3187 bail3:
3188     FcConfigCleanup (&parse);
3189 bail2:
3190     XML_ParserFree (p);
3191 bail1:
3192     close (fd);
3193     fd = -1;
3194 bail0:
3195     if (error && complain)
3196     {
3197         if (name)
3198             FcConfigMessage (0, FcSevereError, "Cannot load config file \"%s\"", name);
3199         else
3200             FcConfigMessage (0, FcSevereError, "Cannot load default config file");
3201         return FcFalse;
3202     }
3203     return FcTrue;
3204 }
3205 #define __fcxml__
3206 #include "fcaliastail.h"
3207 #undef __fcxml__