Leave room for null terminators in arrays
[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 (!rule)
2570     {
2571         FcConfigMessage (parse, FcSevereWarning, "No <test> nor <edit> elements in <match>");
2572         return;
2573     }
2574     if (!FcConfigAddRule (parse->config, rule, kind))
2575         FcConfigMessage (parse, FcSevereError, "out of memory");
2576 }
2577
2578 static void
2579 FcParseAcceptRejectFont (FcConfigParse *parse, FcElement element)
2580 {
2581     FcVStack    *vstack;
2582
2583     while ((vstack = FcVStackPeek (parse)))
2584     {
2585         switch ((int) vstack->tag) {
2586         case FcVStackGlob:
2587             if (!FcConfigGlobAdd (parse->config,
2588                                   vstack->u.string,
2589                                   element == FcElementAcceptfont))
2590             {
2591                 FcConfigMessage (parse, FcSevereError, "out of memory");
2592             }
2593             break;
2594         case FcVStackPattern:
2595             if (!FcConfigPatternsAdd (parse->config,
2596                                       vstack->u.pattern,
2597                                       element == FcElementAcceptfont))
2598             {
2599                 FcConfigMessage (parse, FcSevereError, "out of memory");
2600             }
2601             else
2602                 vstack->tag = FcVStackNone;
2603             break;
2604         default:
2605             FcConfigMessage (parse, FcSevereWarning, "bad font selector");
2606             break;
2607         }
2608         FcVStackPopAndDestroy (parse);
2609     }
2610 }
2611
2612
2613 static FcValue
2614 FcPopValue (FcConfigParse *parse)
2615 {
2616     FcVStack    *vstack = FcVStackPeek (parse);
2617     FcValue     value;
2618
2619     value.type = FcTypeVoid;
2620
2621     if (!vstack)
2622         return value;
2623
2624     switch ((int) vstack->tag) {
2625     case FcVStackString:
2626         value.u.s = FcStrdup (vstack->u.string);
2627         if (value.u.s)
2628             value.type = FcTypeString;
2629         break;
2630     case FcVStackConstant:
2631         if (FcNameConstant (vstack->u.string, &value.u.i))
2632             value.type = FcTypeInteger;
2633         break;
2634     case FcVStackInteger:
2635         value.u.i = vstack->u.integer;
2636         value.type = FcTypeInteger;
2637         break;
2638     case FcVStackDouble:
2639         value.u.d = vstack->u._double;
2640         value.type = FcTypeDouble;
2641         break;
2642     case FcVStackBool:
2643         value.u.b = vstack->u.bool_;
2644         value.type = FcTypeBool;
2645         break;
2646     case FcVStackCharSet:
2647         value.u.c = FcCharSetCopy (vstack->u.charset);
2648         if (value.u.c)
2649             value.type = FcTypeCharSet;
2650         break;
2651     case FcVStackLangSet:
2652         value.u.l = FcLangSetCopy (vstack->u.langset);
2653         if (value.u.l)
2654             value.type = FcTypeLangSet;
2655         break;
2656     default:
2657         FcConfigMessage (parse, FcSevereWarning, "unknown pattern element %d",
2658                          vstack->tag);
2659         break;
2660     }
2661     FcVStackPopAndDestroy (parse);
2662
2663     return value;
2664 }
2665
2666 static void
2667 FcParsePatelt (FcConfigParse *parse)
2668 {
2669     FcValue     value;
2670     FcPattern   *pattern = FcPatternCreate ();
2671     const char  *name;
2672
2673     if (!pattern)
2674     {
2675         FcConfigMessage (parse, FcSevereError, "out of memory");
2676         return;
2677     }
2678
2679     name = (char *) FcConfigGetAttribute (parse, "name");
2680     if (!name)
2681     {
2682         FcConfigMessage (parse, FcSevereWarning, "missing pattern element name");
2683         FcPatternDestroy (pattern);
2684         return;
2685     }
2686
2687     for (;;)
2688     {
2689         value = FcPopValue (parse);
2690         if (value.type == FcTypeVoid)
2691             break;
2692         if (!FcPatternAdd (pattern, name, value, FcTrue))
2693         {
2694             FcConfigMessage (parse, FcSevereError, "out of memory");
2695             FcValueDestroy(value);
2696             break;
2697         }
2698         FcValueDestroy(value);
2699     }
2700
2701     FcVStackPushPattern (parse, pattern);
2702 }
2703
2704 static void
2705 FcParsePattern (FcConfigParse *parse)
2706 {
2707     FcVStack    *vstack;
2708     FcPattern   *pattern = FcPatternCreate ();
2709
2710     if (!pattern)
2711     {
2712         FcConfigMessage (parse, FcSevereError, "out of memory");
2713         return;
2714     }
2715         
2716     while ((vstack = FcVStackPeek (parse)))
2717     {
2718         switch ((int) vstack->tag) {
2719         case FcVStackPattern:
2720             if (!FcPatternAppend (pattern, vstack->u.pattern))
2721             {
2722                 FcConfigMessage (parse, FcSevereError, "out of memory");
2723                 FcPatternDestroy (pattern);
2724                 return;
2725             }
2726             break;
2727         default:
2728             FcConfigMessage (parse, FcSevereWarning, "unknown pattern element");
2729             break;
2730         }
2731         FcVStackPopAndDestroy (parse);
2732     }
2733
2734     FcVStackPushPattern (parse, pattern);
2735 }
2736
2737 static void
2738 FcEndElement(void *userData, const XML_Char *name FC_UNUSED)
2739 {
2740     FcConfigParse   *parse = userData;
2741     FcChar8         *data;
2742
2743     if (!parse->pstack)
2744         return;
2745     switch (parse->pstack->element) {
2746     case FcElementNone:
2747         break;
2748     case FcElementFontconfig:
2749         break;
2750     case FcElementDir:
2751         FcParseDir (parse);
2752         break;
2753     case FcElementCacheDir:
2754         FcParseCacheDir (parse);
2755         break;
2756     case FcElementCache:
2757         data = FcStrBufDoneStatic (&parse->pstack->str);
2758         if (!data)
2759         {
2760             FcConfigMessage (parse, FcSevereError, "out of memory");
2761             break;
2762         }
2763         /* discard this data; no longer used */
2764         FcStrBufDestroy (&parse->pstack->str);
2765         break;
2766     case FcElementInclude:
2767         FcParseInclude (parse);
2768         break;
2769     case FcElementConfig:
2770         break;
2771     case FcElementMatch:
2772         FcParseMatch (parse);
2773         break;
2774     case FcElementAlias:
2775         FcParseAlias (parse);
2776         break;
2777
2778     case FcElementBlank:
2779         FcParseBlank (parse);
2780         break;
2781     case FcElementRescan:
2782         FcParseRescan (parse);
2783         break;
2784         
2785     case FcElementPrefer:
2786         FcParseFamilies (parse, FcVStackPrefer);
2787         break;
2788     case FcElementAccept:
2789         FcParseFamilies (parse, FcVStackAccept);
2790         break;
2791     case FcElementDefault:
2792         FcParseFamilies (parse, FcVStackDefault);
2793         break;
2794     case FcElementFamily:
2795         FcParseFamily (parse);
2796         break;
2797
2798     case FcElementTest:
2799         FcParseTest (parse);
2800         break;
2801     case FcElementEdit:
2802         FcParseEdit (parse);
2803         break;
2804
2805     case FcElementInt:
2806         FcParseInt (parse);
2807         break;
2808     case FcElementDouble:
2809         FcParseDouble (parse);
2810         break;
2811     case FcElementString:
2812         FcParseString (parse, FcVStackString);
2813         break;
2814     case FcElementMatrix:
2815         FcParseMatrix (parse);
2816         break;
2817     case FcElementRange:
2818         FcParseRange (parse);
2819         break;
2820     case FcElementBool:
2821         FcParseBool (parse);
2822         break;
2823     case FcElementCharSet:
2824         FcParseCharSet (parse);
2825         break;
2826     case FcElementLangSet:
2827         FcParseLangSet (parse);
2828         break;
2829     case FcElementSelectfont:
2830         break;
2831     case FcElementAcceptfont:
2832     case FcElementRejectfont:
2833         FcParseAcceptRejectFont (parse, parse->pstack->element);
2834         break;
2835     case FcElementGlob:
2836         FcParseString (parse, FcVStackGlob);
2837         break;
2838     case FcElementPattern:
2839         FcParsePattern (parse);
2840         break;
2841     case FcElementPatelt:
2842         FcParsePatelt (parse);
2843         break;
2844     case FcElementName:
2845         FcParseName (parse);
2846         break;
2847     case FcElementConst:
2848         FcParseString (parse, FcVStackConstant);
2849         break;
2850     case FcElementOr:
2851         FcParseBinary (parse, FcOpOr);
2852         break;
2853     case FcElementAnd:
2854         FcParseBinary (parse, FcOpAnd);
2855         break;
2856     case FcElementEq:
2857         FcParseBinary (parse, FcOpEqual);
2858         break;
2859     case FcElementNotEq:
2860         FcParseBinary (parse, FcOpNotEqual);
2861         break;
2862     case FcElementLess:
2863         FcParseBinary (parse, FcOpLess);
2864         break;
2865     case FcElementLessEq:
2866         FcParseBinary (parse, FcOpLessEqual);
2867         break;
2868     case FcElementMore:
2869         FcParseBinary (parse, FcOpMore);
2870         break;
2871     case FcElementMoreEq:
2872         FcParseBinary (parse, FcOpMoreEqual);
2873         break;
2874     case FcElementContains:
2875         FcParseBinary (parse, FcOpContains);
2876         break;
2877     case FcElementNotContains:
2878         FcParseBinary (parse, FcOpNotContains);
2879         break;
2880     case FcElementPlus:
2881         FcParseBinary (parse, FcOpPlus);
2882         break;
2883     case FcElementMinus:
2884         FcParseBinary (parse, FcOpMinus);
2885         break;
2886     case FcElementTimes:
2887         FcParseBinary (parse, FcOpTimes);
2888         break;
2889     case FcElementDivide:
2890         FcParseBinary (parse, FcOpDivide);
2891         break;
2892     case FcElementNot:
2893         FcParseUnary (parse, FcOpNot);
2894         break;
2895     case FcElementIf:
2896         FcParseBinary (parse, FcOpQuest);
2897         break;
2898     case FcElementFloor:
2899         FcParseUnary (parse, FcOpFloor);
2900         break;
2901     case FcElementCeil:
2902         FcParseUnary (parse, FcOpCeil);
2903         break;
2904     case FcElementRound:
2905         FcParseUnary (parse, FcOpRound);
2906         break;
2907     case FcElementTrunc:
2908         FcParseUnary (parse, FcOpTrunc);
2909         break;
2910     case FcElementUnknown:
2911         break;
2912     }
2913     (void) FcPStackPop (parse);
2914 }
2915
2916 static void
2917 FcCharacterData (void *userData, const XML_Char *s, int len)
2918 {
2919     FcConfigParse   *parse = userData;
2920
2921     if (!parse->pstack)
2922         return;
2923     if (!FcStrBufData (&parse->pstack->str, (FcChar8 *) s, len))
2924         FcConfigMessage (parse, FcSevereError, "out of memory");
2925 }
2926
2927 static void
2928 FcStartDoctypeDecl (void            *userData,
2929                     const XML_Char  *doctypeName,
2930                     const XML_Char  *sysid FC_UNUSED,
2931                     const XML_Char  *pubid FC_UNUSED,
2932                     int             has_internal_subset FC_UNUSED)
2933 {
2934     FcConfigParse   *parse = userData;
2935
2936     if (strcmp ((char *) doctypeName, "fontconfig") != 0)
2937         FcConfigMessage (parse, FcSevereError, "invalid doctype \"%s\"", doctypeName);
2938 }
2939
2940 #ifdef ENABLE_LIBXML2
2941
2942 static void
2943 FcInternalSubsetDecl (void            *userData,
2944                       const XML_Char  *doctypeName,
2945                       const XML_Char  *sysid,
2946                       const XML_Char  *pubid)
2947 {
2948     FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 1);
2949 }
2950
2951 static void
2952 FcExternalSubsetDecl (void            *userData,
2953                       const XML_Char  *doctypeName,
2954                       const XML_Char  *sysid,
2955                       const XML_Char  *pubid)
2956 {
2957     FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 0);
2958 }
2959
2960 #else /* ENABLE_LIBXML2 */
2961
2962 static void
2963 FcEndDoctypeDecl (void *userData FC_UNUSED)
2964 {
2965 }
2966
2967 #endif /* ENABLE_LIBXML2 */
2968
2969 static int
2970 FcSortCmpStr (const void *a, const void *b)
2971 {
2972     const FcChar8    *as = *((FcChar8 **) a);
2973     const FcChar8    *bs = *((FcChar8 **) b);
2974     return FcStrCmp (as, bs);
2975 }
2976
2977 static FcBool
2978 FcConfigParseAndLoadDir (FcConfig       *config,
2979                          const FcChar8  *name,
2980                          const FcChar8  *dir,
2981                          FcBool         complain)
2982 {
2983     DIR             *d;
2984     struct dirent   *e;
2985     FcBool          ret = FcTrue;
2986     FcChar8         *file;
2987     FcChar8         *base;
2988     FcStrSet        *files;
2989
2990     d = opendir ((char *) dir);
2991     if (!d)
2992     {
2993         if (complain)
2994             FcConfigMessage (0, FcSevereError, "Cannot open config dir \"%s\"",
2995                              name);
2996         ret = FcFalse;
2997         goto bail0;
2998     }
2999     /* freed below */
3000     file = (FcChar8 *) malloc (strlen ((char *) dir) + 1 + FC_MAX_FILE_LEN + 1);
3001     if (!file)
3002     {
3003         ret = FcFalse;
3004         goto bail1;
3005     }
3006
3007     strcpy ((char *) file, (char *) dir);
3008     strcat ((char *) file, "/");
3009     base = file + strlen ((char *) file);
3010
3011     files = FcStrSetCreate ();
3012     if (!files)
3013     {
3014         ret = FcFalse;
3015         goto bail2;
3016     }
3017
3018     if (FcDebug () & FC_DBG_CONFIG)
3019         printf ("\tScanning config dir %s\n", dir);
3020         
3021     while (ret && (e = readdir (d)))
3022     {
3023         int d_len;
3024 #define TAIL        ".conf"
3025 #define TAIL_LEN    5
3026         /*
3027          * Add all files of the form [0-9]*.conf
3028          */
3029         if ('0' <= e->d_name[0] && e->d_name[0] <= '9' &&
3030             (d_len = strlen (e->d_name)) < FC_MAX_FILE_LEN &&
3031             d_len > TAIL_LEN &&
3032             strcmp (e->d_name + d_len - TAIL_LEN, TAIL) == 0)
3033         {
3034             strcpy ((char *) base, (char *) e->d_name);
3035             if (!FcStrSetAdd (files, file))
3036             {
3037                 ret = FcFalse;
3038                 goto bail3;
3039             }
3040         }
3041     }
3042     if (ret)
3043     {
3044         int i;
3045         qsort (files->strs, files->num, sizeof (FcChar8 *),
3046                (int (*)(const void *, const void *)) FcSortCmpStr);
3047         for (i = 0; ret && i < files->num; i++)
3048             ret = FcConfigParseAndLoad (config, files->strs[i], complain);
3049     }
3050 bail3:
3051     FcStrSetDestroy (files);
3052 bail2:
3053     free (file);
3054 bail1:
3055     closedir (d);
3056 bail0:
3057     return ret || !complain;
3058 }
3059
3060 #ifdef _WIN32
3061 pfnGetSystemWindowsDirectory pGetSystemWindowsDirectory = NULL;
3062 pfnSHGetFolderPathA pSHGetFolderPathA = NULL;
3063 #endif
3064
3065 FcBool
3066 FcConfigParseAndLoad (FcConfig      *config,
3067                       const FcChar8 *name,
3068                       FcBool        complain)
3069 {
3070
3071     XML_Parser      p;
3072     FcChar8         *filename;
3073     int             fd;
3074     int             len;
3075     FcConfigParse   parse;
3076     FcBool          error = FcTrue;
3077
3078 #ifdef ENABLE_LIBXML2
3079     xmlSAXHandler   sax;
3080     char            buf[BUFSIZ];
3081 #else
3082     void            *buf;
3083 #endif
3084
3085 #ifdef _WIN32
3086     if (!pGetSystemWindowsDirectory)
3087     {
3088         HMODULE hk32 = GetModuleHandleA("kernel32.dll");
3089         if (!(pGetSystemWindowsDirectory = (pfnGetSystemWindowsDirectory) GetProcAddress(hk32, "GetSystemWindowsDirectoryA")))
3090             pGetSystemWindowsDirectory = (pfnGetSystemWindowsDirectory) GetWindowsDirectory;
3091     }
3092     if (!pSHGetFolderPathA)
3093     {
3094         HMODULE hSh = LoadLibraryA("shfolder.dll");
3095         /* the check is done later, because there is no provided fallback */
3096         if (hSh)
3097             pSHGetFolderPathA = (pfnSHGetFolderPathA) GetProcAddress(hSh, "SHGetFolderPathA");
3098     }
3099 #endif
3100
3101     filename = FcConfigFilename (name);
3102     if (!filename)
3103         goto bail0;
3104
3105     if (FcStrSetMember (config->configFiles, filename))
3106     {
3107         FcStrFree (filename);
3108         return FcTrue;
3109     }
3110
3111     if (!FcStrSetAdd (config->configFiles, filename))
3112     {
3113         FcStrFree (filename);
3114         goto bail0;
3115     }
3116
3117     if (FcFileIsDir (filename))
3118     {
3119         FcBool ret = FcConfigParseAndLoadDir (config, name, filename, complain);
3120         FcStrFree (filename);
3121         return ret;
3122     }
3123
3124     if (FcDebug () & FC_DBG_CONFIG)
3125         printf ("\tLoading config file %s\n", filename);
3126
3127     fd = FcOpen ((char *) filename, O_RDONLY);
3128     if (fd == -1) {
3129         FcStrFree (filename);
3130         goto bail0;
3131     }
3132
3133 #ifdef ENABLE_LIBXML2
3134     memset(&sax, 0, sizeof(sax));
3135
3136     sax.internalSubset = FcInternalSubsetDecl;
3137     sax.externalSubset = FcExternalSubsetDecl;
3138     sax.startElement = FcStartElement;
3139     sax.endElement = FcEndElement;
3140     sax.characters = FcCharacterData;
3141
3142     p = xmlCreatePushParserCtxt (&sax, &parse, NULL, 0, (const char *) filename);
3143 #else
3144     p = XML_ParserCreate ("UTF-8");
3145 #endif
3146     FcStrFree (filename);
3147
3148     if (!p)
3149         goto bail1;
3150
3151     if (!FcConfigParseInit (&parse, name, config, p))
3152         goto bail2;
3153
3154 #ifndef ENABLE_LIBXML2
3155
3156     XML_SetUserData (p, &parse);
3157
3158     XML_SetDoctypeDeclHandler (p, FcStartDoctypeDecl, FcEndDoctypeDecl);
3159     XML_SetElementHandler (p, FcStartElement, FcEndElement);
3160     XML_SetCharacterDataHandler (p, FcCharacterData);
3161         
3162 #endif /* ENABLE_LIBXML2 */
3163
3164     do {
3165 #ifndef ENABLE_LIBXML2
3166         buf = XML_GetBuffer (p, BUFSIZ);
3167         if (!buf)
3168         {
3169             FcConfigMessage (&parse, FcSevereError, "cannot get parse buffer");
3170             goto bail3;
3171         }
3172 #endif
3173         len = read (fd, buf, BUFSIZ);
3174         if (len < 0)
3175         {
3176             FcConfigMessage (&parse, FcSevereError, "failed reading config file");
3177             goto bail3;
3178         }
3179
3180 #ifdef ENABLE_LIBXML2
3181         if (xmlParseChunk (p, buf, len, len == 0))
3182 #else
3183         if (!XML_ParseBuffer (p, len, len == 0))
3184 #endif
3185         {
3186             FcConfigMessage (&parse, FcSevereError, "%s",
3187                            XML_ErrorString (XML_GetErrorCode (p)));
3188             goto bail3;
3189         }
3190     } while (len != 0);
3191     error = parse.error;
3192 bail3:
3193     FcConfigCleanup (&parse);
3194 bail2:
3195     XML_ParserFree (p);
3196 bail1:
3197     close (fd);
3198     fd = -1;
3199 bail0:
3200     if (error && complain)
3201     {
3202         if (name)
3203             FcConfigMessage (0, FcSevereError, "Cannot load config file \"%s\"", name);
3204         else
3205             FcConfigMessage (0, FcSevereError, "Cannot load default config file");
3206         return FcFalse;
3207     }
3208     return FcTrue;
3209 }
3210 #define __fcxml__
3211 #include "fcaliastail.h"
3212 #undef __fcxml__