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