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