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