]> git.wh0rd.org Git - fontconfig.git/blob - src/fcxml.c
[fcxml] Embed 8 static FcPStack objects in FcConfigParse
[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 Keith Packard not be used in
11  * advertising or publicity pertaining to distribution of the software without
12  * specific, written prior permission.  Keith Packard makes 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  * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18  * EVENT SHALL KEITH PACKARD 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 #define STRICT
57 #include <windows.h>
58 #undef STRICT
59 #endif
60
61
62 void
63 FcTestDestroy (FcTest *test)
64 {
65     if (test->next)
66         FcTestDestroy (test->next);
67     FcExprDestroy (test->expr);
68     FcMemFree (FC_MEM_TEST, sizeof (FcTest));
69     free (test);
70 }
71
72 FcExpr *
73 FcExprCreateInteger (int i)
74 {
75     FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
76
77     if (e)
78     {
79         FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
80         e->op = FcOpInteger;
81         e->u.ival = i;
82     }
83     return e;
84 }
85
86 FcExpr *
87 FcExprCreateDouble (double d)
88 {
89     FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
90
91     if (e)
92     {
93         FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
94         e->op = FcOpDouble;
95         e->u.dval = d;
96     }
97     return e;
98 }
99
100 FcExpr *
101 FcExprCreateString (const FcChar8 *s)
102 {
103     FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
104
105     if (e)
106     {
107         FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
108         e->op = FcOpString;
109         e->u.sval = FcStrCopy (s);
110     }
111     return e;
112 }
113
114 FcExpr *
115 FcExprCreateMatrix (const FcMatrix *m)
116 {
117     FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
118
119     if (e)
120     {
121         FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
122         e->op = FcOpMatrix;
123         e->u.mval = FcMatrixCopy (m);
124     }
125     return e;
126 }
127
128 FcExpr *
129 FcExprCreateBool (FcBool b)
130 {
131     FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
132
133     if (e)
134     {
135         FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
136         e->op = FcOpBool;
137         e->u.bval = b;
138     }
139     return e;
140 }
141
142 FcExpr *
143 FcExprCreateNil (void)
144 {
145     FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
146
147     if (e)
148     {
149         FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
150         e->op = FcOpNil;
151     }
152     return e;
153 }
154
155 FcExpr *
156 FcExprCreateField (const char *field)
157 {
158     FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
159
160     if (e)
161     {
162         FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
163         e->op = FcOpField;
164         e->u.object = FcObjectFromName (field);
165     }
166     return e;
167 }
168
169 FcExpr *
170 FcExprCreateConst (const FcChar8 *constant)
171 {
172     FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
173
174     if (e)
175     {
176         FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
177         e->op = FcOpConst;
178         e->u.constant = FcStrCopy (constant);
179     }
180     return e;
181 }
182
183 FcExpr *
184 FcExprCreateOp (FcExpr *left, FcOp op, FcExpr *right)
185 {
186     FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
187
188     if (e)
189     {
190         FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
191         e->op = op;
192         e->u.tree.left = left;
193         e->u.tree.right = right;
194     }
195     return e;
196 }
197
198 void
199 FcExprDestroy (FcExpr *e)
200 {
201     if (!e)
202         return;
203     switch (e->op) {
204     case FcOpInteger:
205         break;
206     case FcOpDouble:
207         break;
208     case FcOpString:
209         FcStrFree (e->u.sval);
210         break;
211     case FcOpMatrix:
212         FcMatrixFree (e->u.mval);
213         break;
214     case FcOpCharSet:
215         FcCharSetDestroy (e->u.cval);
216         break;
217     case FcOpBool:
218         break;
219     case FcOpField:
220         break;
221     case FcOpConst:
222         FcStrFree (e->u.constant);
223         break;
224     case FcOpAssign:
225     case FcOpAssignReplace:
226     case FcOpPrepend:
227     case FcOpPrependFirst:
228     case FcOpAppend:
229     case FcOpAppendLast:
230         break;
231     case FcOpOr:
232     case FcOpAnd:
233     case FcOpEqual:
234     case FcOpNotEqual:
235     case FcOpLess:
236     case FcOpLessEqual:
237     case FcOpMore:
238     case FcOpMoreEqual:
239     case FcOpContains:
240     case FcOpListing:
241     case FcOpNotContains:
242     case FcOpPlus:
243     case FcOpMinus:
244     case FcOpTimes:
245     case FcOpDivide:
246     case FcOpQuest:
247     case FcOpComma:
248         FcExprDestroy (e->u.tree.right);
249         /* fall through */
250     case FcOpNot:
251     case FcOpFloor:
252     case FcOpCeil:
253     case FcOpRound:
254     case FcOpTrunc:
255         FcExprDestroy (e->u.tree.left);
256         break;
257     case FcOpNil:
258     case FcOpInvalid:
259         break;
260     }
261     FcMemFree (FC_MEM_EXPR, sizeof (FcExpr));
262     free (e);
263 }
264
265 void
266 FcEditDestroy (FcEdit *e)
267 {
268     if (e->next)
269         FcEditDestroy (e->next);
270     if (e->expr)
271         FcExprDestroy (e->expr);
272     free (e);
273 }
274
275 char *
276 FcConfigSaveField (const char *field)
277 {
278     return (char *) FcStrCopy ((FcChar8 *) field);
279 }
280
281 typedef enum _FcElement {
282     FcElementNone,
283     FcElementFontconfig,
284     FcElementDir,
285     FcElementCacheDir,
286     FcElementCache,
287     FcElementInclude,
288     FcElementConfig,
289     FcElementMatch,
290     FcElementAlias,
291         
292     FcElementBlank,
293     FcElementRescan,
294
295     FcElementPrefer,
296     FcElementAccept,
297     FcElementDefault,
298     FcElementFamily,
299
300     FcElementSelectfont,
301     FcElementAcceptfont,
302     FcElementRejectfont,
303     FcElementGlob,
304     FcElementPattern,
305     FcElementPatelt,
306
307     FcElementTest,
308     FcElementEdit,
309     FcElementInt,
310     FcElementDouble,
311     FcElementString,
312     FcElementMatrix,
313     FcElementBool,
314     FcElementCharset,
315     FcElementName,
316     FcElementConst,
317     FcElementOr,
318     FcElementAnd,
319     FcElementEq,
320     FcElementNotEq,
321     FcElementLess,
322     FcElementLessEq,
323     FcElementMore,
324     FcElementMoreEq,
325     FcElementContains,
326     FcElementNotContains,
327     FcElementPlus,
328     FcElementMinus,
329     FcElementTimes,
330     FcElementDivide,
331     FcElementNot,
332     FcElementIf,
333     FcElementFloor,
334     FcElementCeil,
335     FcElementRound,
336     FcElementTrunc,
337     FcElementUnknown
338 } FcElement;
339
340 static const struct {
341     const char  name[16];
342     FcElement   element;
343 } fcElementMap[] = {
344     { "fontconfig",     FcElementFontconfig },
345     { "dir",            FcElementDir },
346     { "cachedir",       FcElementCacheDir },
347     { "cache",          FcElementCache },
348     { "include",        FcElementInclude },
349     { "config",         FcElementConfig },
350     { "match",          FcElementMatch },
351     { "alias",          FcElementAlias },
352     
353     { "blank",          FcElementBlank },
354     { "rescan",         FcElementRescan },
355
356     { "prefer",         FcElementPrefer },
357     { "accept",         FcElementAccept },
358     { "default",        FcElementDefault },
359     { "family",         FcElementFamily },
360
361     { "selectfont",     FcElementSelectfont },
362     { "acceptfont",     FcElementAcceptfont },
363     { "rejectfont",     FcElementRejectfont },
364     { "glob",           FcElementGlob },
365     { "pattern",        FcElementPattern },
366     { "patelt",         FcElementPatelt },
367
368     { "test",           FcElementTest },
369     { "edit",           FcElementEdit },
370     { "int",            FcElementInt },
371     { "double",         FcElementDouble },
372     { "string",         FcElementString },
373     { "matrix",         FcElementMatrix },
374     { "bool",           FcElementBool },
375     { "charset",        FcElementCharset },
376     { "name",           FcElementName },
377     { "const",          FcElementConst },
378     { "or",             FcElementOr },
379     { "and",            FcElementAnd },
380     { "eq",             FcElementEq },
381     { "not_eq",         FcElementNotEq },
382     { "less",           FcElementLess },
383     { "less_eq",        FcElementLessEq },
384     { "more",           FcElementMore },
385     { "more_eq",        FcElementMoreEq },
386     { "contains",       FcElementContains },
387     { "not_contains",   FcElementNotContains },
388     { "plus",           FcElementPlus },
389     { "minus",          FcElementMinus },
390     { "times",          FcElementTimes },
391     { "divide",         FcElementDivide },
392     { "not",            FcElementNot },
393     { "if",             FcElementIf },
394     { "floor",          FcElementFloor },
395     { "ceil",           FcElementCeil },
396     { "round",          FcElementRound },
397     { "trunc",          FcElementTrunc },
398 };
399 #define NUM_ELEMENT_MAPS (int) (sizeof fcElementMap / sizeof fcElementMap[0])
400
401 static FcElement
402 FcElementMap (const XML_Char *name)
403 {
404
405     int     i;
406     for (i = 0; i < NUM_ELEMENT_MAPS; i++)
407         if (!strcmp ((char *) name, fcElementMap[i].name))
408             return fcElementMap[i].element;
409     return FcElementUnknown;
410 }
411
412 typedef struct _FcPStack {
413     struct _FcPStack   *prev;
414     FcElement           element;
415     FcChar8             **attr;
416     FcStrBuf            str;
417 } FcPStack;
418     
419 typedef enum _FcVStackTag {
420     FcVStackNone,
421
422     FcVStackString,
423     FcVStackFamily,
424     FcVStackField,
425     FcVStackConstant,
426     FcVStackGlob,
427     FcVStackPattern,
428     
429     FcVStackPrefer,
430     FcVStackAccept,
431     FcVStackDefault,
432     
433     FcVStackInteger,
434     FcVStackDouble,
435     FcVStackMatrix,
436     FcVStackBool,
437     
438     FcVStackTest,
439     FcVStackExpr,
440     FcVStackEdit
441 } FcVStackTag;
442
443 typedef struct _FcVStack {
444     struct _FcVStack    *prev;
445     FcPStack            *pstack;        /* related parse element */
446     FcVStackTag         tag;
447     union {
448         FcChar8         *string;
449
450         int             integer;
451         double          _double;
452         FcMatrix        *matrix;
453         FcBool          bool_;
454
455         FcTest          *test;
456         FcQual          qual;
457         FcOp            op;
458         FcExpr          *expr;
459         FcEdit          *edit;
460
461         FcPattern       *pattern;
462     } u;
463 } FcVStack;
464
465 typedef struct _FcConfigParse {
466     FcPStack        *pstack;
467     FcVStack        *vstack;
468     FcBool          error;
469     const FcChar8   *name;
470     FcConfig        *config;
471     XML_Parser      parser;
472     int             pstack_static_used;
473     FcPStack        pstack_static[8];
474 } FcConfigParse;
475
476 typedef enum _FcConfigSeverity {
477     FcSevereInfo, FcSevereWarning, FcSevereError
478 } FcConfigSeverity;
479
480 static void
481 FcConfigMessage (FcConfigParse *parse, FcConfigSeverity severe, const char *fmt, ...)
482 {
483     const char  *s = "unknown";
484     va_list     args;
485
486     va_start (args, fmt);
487
488     switch (severe) {
489     case FcSevereInfo: s = "info"; break;
490     case FcSevereWarning: s = "warning"; break;
491     case FcSevereError: s = "error"; break;
492     }
493     if (parse)
494     {
495         if (parse->name)
496             fprintf (stderr, "Fontconfig %s: \"%s\", line %d: ", s,
497                      parse->name, (int)XML_GetCurrentLineNumber (parse->parser));
498         else
499             fprintf (stderr, "Fontconfig %s: line %d: ", s,
500                      (int)XML_GetCurrentLineNumber (parse->parser));
501         if (severe >= FcSevereError)
502             parse->error = FcTrue;
503     }
504     else
505         fprintf (stderr, "Fontconfig %s: ", s);
506     vfprintf (stderr, fmt, args);
507     fprintf (stderr, "\n");
508     va_end (args);
509 }
510
511
512 static const char *
513 FcTypeName (FcType type)
514 {
515     switch (type) {
516     case FcTypeVoid:
517         return "void";
518     case FcTypeInteger:
519     case FcTypeDouble:
520         return "number";
521     case FcTypeString:
522         return "string";
523     case FcTypeBool:
524         return "bool";
525     case FcTypeMatrix:
526         return "matrix";
527     case FcTypeCharSet:
528         return "charset";
529     case FcTypeFTFace:
530         return "FT_Face";
531     case FcTypeLangSet:
532         return "langset";
533     default:
534         return "unknown";
535     }
536 }
537
538 static void
539 FcTypecheckValue (FcConfigParse *parse, FcType value, FcType type)
540 {
541     if (value == FcTypeInteger)
542         value = FcTypeDouble;
543     if (type == FcTypeInteger)
544         type = FcTypeDouble;
545     if (value != type)
546     {
547         if ((value == FcTypeLangSet && type == FcTypeString) ||
548             (value == FcTypeString && type == FcTypeLangSet))
549             return;
550         if (type == (FcType) -1)
551             return;
552         FcConfigMessage (parse, FcSevereWarning, "saw %s, expected %s",
553                          FcTypeName (value), FcTypeName (type));
554     }
555 }
556
557 static void
558 FcTypecheckExpr (FcConfigParse *parse, FcExpr *expr, FcType type)
559 {
560     const FcObjectType  *o;
561     const FcConstant    *c;
562     
563     /* If parsing the expression failed, some nodes may be NULL */
564     if (!expr)
565         return;
566
567     switch (expr->op) {
568     case FcOpInteger:
569     case FcOpDouble:
570         FcTypecheckValue (parse, FcTypeDouble, type);
571         break;
572     case FcOpString:
573         FcTypecheckValue (parse, FcTypeString, type);
574         break;
575     case FcOpMatrix:
576         FcTypecheckValue (parse, FcTypeMatrix, type);
577         break;
578     case FcOpBool:
579         FcTypecheckValue (parse, FcTypeBool, type);
580         break;
581     case FcOpCharSet:
582         FcTypecheckValue (parse, FcTypeCharSet, type);
583         break;
584     case FcOpNil:
585         break;
586     case FcOpField:
587         o = FcNameGetObjectType (FcObjectName (expr->u.object));
588         if (o)
589             FcTypecheckValue (parse, o->type, type);
590         break;
591     case FcOpConst:
592         c = FcNameGetConstant (expr->u.constant);
593         if (c)
594         {
595             o = FcNameGetObjectType (c->object);
596             if (o)
597                 FcTypecheckValue (parse, o->type, type);
598         }
599         else 
600             FcConfigMessage (parse, FcSevereWarning, 
601                              "invalid constant used : %s",
602                              expr->u.constant);
603         break;
604     case FcOpQuest:
605         FcTypecheckExpr (parse, expr->u.tree.left, FcTypeBool);
606         FcTypecheckExpr (parse, expr->u.tree.right->u.tree.left, type);
607         FcTypecheckExpr (parse, expr->u.tree.right->u.tree.right, type);
608         break;
609     case FcOpAssign:
610     case FcOpAssignReplace:
611         break;
612     case FcOpEqual:
613     case FcOpNotEqual:
614     case FcOpLess:
615     case FcOpLessEqual:
616     case FcOpMore:
617     case FcOpMoreEqual:
618     case FcOpContains:
619     case FcOpNotContains:
620     case FcOpListing:
621         FcTypecheckValue (parse, FcTypeBool, type);
622         break;
623     case FcOpComma:
624     case FcOpOr:
625     case FcOpAnd:
626     case FcOpPlus:
627     case FcOpMinus:
628     case FcOpTimes:
629     case FcOpDivide:
630         FcTypecheckExpr (parse, expr->u.tree.left, type);
631         FcTypecheckExpr (parse, expr->u.tree.right, type);
632         break;
633     case FcOpNot:
634         FcTypecheckValue (parse, FcTypeBool, type);
635         FcTypecheckExpr (parse, expr->u.tree.left, FcTypeBool);
636         break;
637     case FcOpFloor:
638     case FcOpCeil:
639     case FcOpRound:
640     case FcOpTrunc:
641         FcTypecheckValue (parse, FcTypeDouble, type);
642         FcTypecheckExpr (parse, expr->u.tree.left, FcTypeDouble);
643         break;
644     default:
645         break;
646     }
647 }
648
649 static FcTest *
650 FcTestCreate (FcConfigParse *parse,
651               FcMatchKind   kind, 
652               FcQual        qual,
653               const FcChar8 *field,
654               FcOp          compare,
655               FcExpr        *expr)
656 {
657     FcTest      *test = (FcTest *) malloc (sizeof (FcTest));
658
659     if (test)
660     {
661         const FcObjectType      *o;
662         
663         FcMemAlloc (FC_MEM_TEST, sizeof (FcTest));
664         test->next = 0;
665         test->kind = kind;
666         test->qual = qual;
667         test->object = FcObjectFromName ((const char *) field);
668         test->op = compare;
669         test->expr = expr;
670         o = FcNameGetObjectType (FcObjectName (test->object));
671         if (o)
672             FcTypecheckExpr (parse, expr, o->type);
673     }
674     return test;
675 }
676
677 static FcEdit *
678 FcEditCreate (FcConfigParse     *parse,
679               FcObject          object,
680               FcOp              op,
681               FcExpr            *expr,
682               FcValueBinding    binding)
683 {
684     FcEdit *e = (FcEdit *) malloc (sizeof (FcEdit));
685
686     if (e)
687     {
688         const FcObjectType      *o;
689
690         e->next = 0;
691         e->object = object;
692         e->op = op;
693         e->expr = expr;
694         e->binding = binding;
695         o = FcNameGetObjectType (FcObjectName (e->object));
696         if (o)
697             FcTypecheckExpr (parse, expr, o->type);
698     }
699     return e;
700 }
701
702 static void
703 FcVStackPush (FcConfigParse *parse, FcVStack *vstack)
704 {
705     vstack->prev = parse->vstack;
706     vstack->pstack = parse->pstack ? parse->pstack->prev : 0;
707     parse->vstack = vstack;
708 }
709
710 static FcVStack *
711 FcVStackCreate (void)
712 {
713     FcVStack    *new;
714
715     new = malloc (sizeof (FcVStack));
716     if (!new)
717         return 0;
718     FcMemAlloc (FC_MEM_VSTACK, sizeof (FcVStack));
719     new->tag = FcVStackNone;
720     new->prev = 0;
721     return new;
722 }
723
724 static void
725 FcVStackDestroy (FcVStack *vstack)
726 {
727     FcVStack    *prev;
728
729     for (; vstack; vstack = prev)
730     {
731         prev = vstack->prev;
732         switch (vstack->tag) {
733         case FcVStackNone:
734             break;
735         case FcVStackString:
736         case FcVStackFamily:
737         case FcVStackField:
738         case FcVStackConstant:
739         case FcVStackGlob:
740             FcStrFree (vstack->u.string);
741             break;
742         case FcVStackPattern:
743             FcPatternDestroy (vstack->u.pattern);
744             break;
745         case FcVStackInteger:
746         case FcVStackDouble:
747             break;
748         case FcVStackMatrix:
749             FcMatrixFree (vstack->u.matrix);
750             break;
751         case FcVStackBool:
752             break;
753         case FcVStackTest:
754             FcTestDestroy (vstack->u.test);
755             break;
756         case FcVStackExpr:
757         case FcVStackPrefer:
758         case FcVStackAccept:
759         case FcVStackDefault:
760             FcExprDestroy (vstack->u.expr);
761             break;
762         case FcVStackEdit:
763             FcEditDestroy (vstack->u.edit);
764             break;
765         }
766         FcMemFree (FC_MEM_VSTACK, sizeof (FcVStack));
767         free (vstack);
768     }
769 }
770
771 static FcBool
772 FcVStackPushString (FcConfigParse *parse, FcVStackTag tag, FcChar8 *string)
773 {
774     FcVStack    *vstack = FcVStackCreate ();
775     if (!vstack)
776         return FcFalse;
777     vstack->u.string = string;
778     vstack->tag = tag;
779     FcVStackPush (parse, vstack);
780     return FcTrue;
781 }
782
783 static FcBool
784 FcVStackPushInteger (FcConfigParse *parse, int integer)
785 {
786     FcVStack    *vstack = FcVStackCreate ();
787     if (!vstack)
788         return FcFalse;
789     vstack->u.integer = integer;
790     vstack->tag = FcVStackInteger;
791     FcVStackPush (parse, vstack);
792     return FcTrue;
793 }
794
795 static FcBool
796 FcVStackPushDouble (FcConfigParse *parse, double _double)
797 {
798     FcVStack    *vstack = FcVStackCreate ();
799     if (!vstack)
800         return FcFalse;
801     vstack->u._double = _double;
802     vstack->tag = FcVStackDouble;
803     FcVStackPush (parse, vstack);
804     return FcTrue;
805 }
806
807 static FcBool
808 FcVStackPushMatrix (FcConfigParse *parse, FcMatrix *matrix)
809 {
810     FcVStack    *vstack = FcVStackCreate ();
811     if (!vstack)
812         return FcFalse;
813     matrix = FcMatrixCopy (matrix);
814     if (!matrix)
815     {
816         FcVStackDestroy (vstack);
817         return FcFalse;
818     }
819     vstack->u.matrix = matrix;
820     vstack->tag = FcVStackMatrix;
821     FcVStackPush (parse, vstack);
822     return FcTrue;
823 }
824
825 static FcBool
826 FcVStackPushBool (FcConfigParse *parse, FcBool bool_)
827 {
828     FcVStack    *vstack = FcVStackCreate ();
829     if (!vstack)
830         return FcFalse;
831     vstack->u.bool_ = bool_;
832     vstack->tag = FcVStackBool;
833     FcVStackPush (parse, vstack);
834     return FcTrue;
835 }
836
837 static FcBool
838 FcVStackPushTest (FcConfigParse *parse, FcTest *test)
839 {
840     FcVStack    *vstack = FcVStackCreate ();
841     if (!vstack)
842         return FcFalse;
843     vstack->u.test = test;
844     vstack->tag = FcVStackTest;
845     FcVStackPush (parse, vstack);
846     return FcTrue;
847 }
848
849 static FcBool
850 FcVStackPushExpr (FcConfigParse *parse, FcVStackTag tag, FcExpr *expr)
851 {
852     FcVStack    *vstack = FcVStackCreate ();
853     if (!vstack)
854         return FcFalse;
855     vstack->u.expr = expr;
856     vstack->tag = tag;
857     FcVStackPush (parse, vstack);
858     return FcTrue;
859 }
860
861 static FcBool
862 FcVStackPushEdit (FcConfigParse *parse, FcEdit *edit)
863 {
864     FcVStack    *vstack = FcVStackCreate ();
865     if (!vstack)
866         return FcFalse;
867     vstack->u.edit = edit;
868     vstack->tag = FcVStackEdit;
869     FcVStackPush (parse, vstack);
870     return FcTrue;
871 }
872
873 static FcBool
874 FcVStackPushPattern (FcConfigParse *parse, FcPattern *pattern)
875 {
876     FcVStack    *vstack = FcVStackCreate ();
877     if (!vstack)
878         return FcFalse;
879     vstack->u.pattern = pattern;
880     vstack->tag = FcVStackPattern;
881     FcVStackPush (parse, vstack);
882     return FcTrue;
883 }
884
885 static FcVStack *
886 FcVStackFetch (FcConfigParse *parse, int off)
887 {
888     FcVStack    *vstack;
889
890     for (vstack = parse->vstack; vstack && off-- > 0; vstack = vstack->prev);
891     return vstack;
892 }
893
894 static void
895 FcVStackClear (FcConfigParse *parse)
896 {
897     while (parse->vstack && parse->vstack->pstack == parse->pstack)
898     {
899         FcVStack    *vstack = parse->vstack;
900         parse->vstack = vstack->prev;
901         vstack->prev = 0;
902         FcVStackDestroy (vstack);
903     }
904 }
905
906 static FcVStack *
907 FcVStackPop (FcConfigParse *parse)
908 {
909     FcVStack    *vstack = parse->vstack;
910     
911     if (!vstack || vstack->pstack != parse->pstack)
912         return 0;
913     parse->vstack = vstack->prev;
914     vstack->prev = 0;
915     return vstack;
916 }
917
918 static int
919 FcVStackElements (FcConfigParse *parse)
920 {
921     int         h = 0;
922     FcVStack    *vstack = parse->vstack;
923     while (vstack && vstack->pstack == parse->pstack)
924     {
925         h++;
926         vstack = vstack->prev;
927     }
928     return h;
929 }
930
931 static FcChar8 **
932 FcConfigSaveAttr (const XML_Char **attr)
933 {
934     int         slen;
935     int         i;
936     FcChar8     **new;
937     FcChar8     *s;
938
939     if (!attr)
940         return 0;
941     slen = 0;
942     for (i = 0; attr[i]; i++)
943         slen += strlen ((char *) attr[i]) + 1;
944     if (i == 0)
945         return 0;
946     new = malloc ((i + 1) * sizeof (FcChar8 *) + slen);
947     if (!new)
948     {
949         FcConfigMessage (0, FcSevereError, "out of memory");
950         return 0;
951     }
952     FcMemAlloc (FC_MEM_ATTR, 1);    /* size is too expensive */
953     s = (FcChar8 *) (new + (i + 1));
954     for (i = 0; attr[i]; i++)
955     {
956         new[i] = s;
957         strcpy ((char *) s, (char *) attr[i]);
958         s += strlen ((char *) s) + 1;
959     }
960     new[i] = 0;
961     return new;
962 }
963
964 static FcBool
965 FcPStackPush (FcConfigParse *parse, FcElement element, const XML_Char **attr)
966 {
967     FcPStack   *new;
968
969     if (parse->pstack_static_used < sizeof (parse->pstack_static) / sizeof (parse->pstack_static[0]))
970         new = &parse->pstack_static[parse->pstack_static_used++];
971     else
972     {
973         new = malloc (sizeof (FcPStack));
974         if (!new)
975             return FcFalse;
976         FcMemAlloc (FC_MEM_PSTACK, sizeof (FcPStack));
977     }
978
979     new->prev = parse->pstack;
980     new->element = element;
981     new->attr = FcConfigSaveAttr (attr);
982     FcStrBufInit (&new->str, 0, 0);
983     parse->pstack = new;
984     return FcTrue;
985 }
986
987 static FcBool
988 FcPStackPop (FcConfigParse *parse)
989 {
990     FcPStack   *old;
991     
992     if (!parse->pstack) 
993     {
994         FcConfigMessage (parse, FcSevereError, "mismatching element");
995         return FcFalse;
996     }
997     FcVStackClear (parse);
998     old = parse->pstack;
999     parse->pstack = old->prev;
1000     FcStrBufDestroy (&old->str);
1001     if (old->attr)
1002     {
1003         FcMemFree (FC_MEM_ATTR, 1); /* size is to expensive */
1004         free (old->attr);
1005     }
1006
1007     if (old == &parse->pstack_static[parse->pstack_static_used - 1])
1008         parse->pstack_static_used--;
1009     else
1010     {
1011         FcMemFree (FC_MEM_PSTACK, sizeof (FcPStack));
1012         free (old);
1013     }
1014     return FcTrue;
1015 }
1016
1017 static FcBool
1018 FcConfigInit (FcConfigParse *parse, const FcChar8 *name, FcConfig *config, XML_Parser parser)
1019 {
1020     parse->pstack = 0;
1021     parse->pstack_static_used = 0;
1022     parse->vstack = 0;
1023     parse->error = FcFalse;
1024     parse->name = name;
1025     parse->config = config;
1026     parse->parser = parser;
1027     return FcTrue;
1028 }
1029
1030 static void
1031 FcConfigCleanup (FcConfigParse  *parse)
1032 {
1033     while (parse->pstack)
1034         FcPStackPop (parse);
1035 }
1036
1037 static const FcChar8 *
1038 FcConfigGetAttribute (FcConfigParse *parse, const char *attr)
1039 {
1040     FcChar8 **attrs;
1041     if (!parse->pstack)
1042         return 0;
1043
1044     attrs = parse->pstack->attr;
1045     if (!attrs)
1046         return 0;
1047
1048     while (*attrs)
1049     {
1050         if (!strcmp ((char *) *attrs, attr))
1051             return attrs[1];
1052         attrs += 2;
1053     }
1054     return 0;
1055 }
1056
1057 static void
1058 FcStartElement(void *userData, const XML_Char *name, const XML_Char **attr)
1059 {
1060     FcConfigParse   *parse = userData;
1061     FcElement       element;
1062     
1063     element = FcElementMap (name);
1064     if (element == FcElementUnknown)
1065         FcConfigMessage (parse, FcSevereWarning, "unknown element \"%s\"", name);
1066     
1067     if (!FcPStackPush (parse, element, attr))
1068     {
1069         FcConfigMessage (parse, FcSevereError, "out of memory");
1070         return;
1071     }
1072     return;
1073 }
1074
1075 static void
1076 FcParseBlank (FcConfigParse *parse)
1077 {
1078     int     n = FcVStackElements (parse);
1079     while (n-- > 0)
1080     {
1081         FcVStack    *v = FcVStackFetch (parse, n);
1082         if (v->tag != FcVStackInteger)
1083             FcConfigMessage (parse, FcSevereError, "non-integer blank");
1084         else
1085         {
1086             if (!parse->config->blanks)
1087             {
1088                 parse->config->blanks = FcBlanksCreate ();
1089                 if (!parse->config->blanks)
1090                 {
1091                     FcConfigMessage (parse, FcSevereError, "out of memory");
1092                     break;
1093                 }
1094             }
1095             if (!FcBlanksAdd (parse->config->blanks, v->u.integer))
1096             {
1097                 FcConfigMessage (parse, FcSevereError, "out of memory");
1098                 break;
1099             }
1100         }
1101     }
1102 }
1103
1104 static void
1105 FcParseRescan (FcConfigParse *parse)
1106 {
1107     int     n = FcVStackElements (parse);
1108     while (n-- > 0)
1109     {
1110         FcVStack    *v = FcVStackFetch (parse, n);
1111         if (v->tag != FcVStackInteger)
1112             FcConfigMessage (parse, FcSevereWarning, "non-integer rescan");
1113         else
1114             parse->config->rescanInterval = v->u.integer;
1115     }
1116 }
1117
1118 static void
1119 FcParseInt (FcConfigParse *parse)
1120 {
1121     FcChar8 *s, *end;
1122     int     l;
1123     
1124     if (!parse->pstack)
1125         return;
1126     s = FcStrBufDoneStatic (&parse->pstack->str);
1127     if (!s)
1128     {
1129         FcConfigMessage (parse, FcSevereError, "out of memory");
1130         return;
1131     }
1132     end = 0;
1133     l = (int) strtol ((char *) s, (char **)&end, 0);
1134     if (end != s + strlen ((char *) s))
1135         FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid integer", s);
1136     else
1137         FcVStackPushInteger (parse, l);
1138     FcStrBufDestroy (&parse->pstack->str);
1139 }
1140
1141 /*
1142  * idea copied from glib g_ascii_strtod with 
1143  * permission of the author (Alexander Larsson) 
1144  */
1145
1146 #include <locale.h>
1147
1148 static double 
1149 FcStrtod (char *s, char **end)
1150 {
1151     struct lconv    *locale_data;
1152     char            *dot;
1153     double          v;
1154
1155     /*
1156      * Have to swap the decimal point to match the current locale
1157      * if that locale doesn't use 0x2e
1158      */
1159     if ((dot = strchr (s, 0x2e)) &&
1160         (locale_data = localeconv ()) &&
1161         (locale_data->decimal_point[0] != 0x2e ||
1162          locale_data->decimal_point[1] != 0))
1163     {
1164         char    buf[128];
1165         int     slen = strlen (s);
1166         int     dlen = strlen (locale_data->decimal_point);
1167         
1168         if (slen + dlen > (int) sizeof (buf))
1169         {
1170             if (end)
1171                 *end = s;
1172             v = 0;
1173         }
1174         else
1175         {
1176             char        *buf_end;
1177             /* mantissa */
1178             strncpy (buf, s, dot - s);
1179             /* decimal point */
1180             strcpy (buf + (dot - s), locale_data->decimal_point);
1181             /* rest of number */
1182             strcpy (buf + (dot - s) + dlen, dot + 1);
1183             buf_end = 0;
1184             v = strtod (buf, &buf_end);
1185             if (buf_end) {
1186                 buf_end = s + (buf_end - buf);
1187                 if (buf_end > dot)
1188                     buf_end -= dlen - 1;
1189             }
1190             if (end)
1191                 *end = buf_end;
1192         }
1193     }
1194     else
1195         v = strtod (s, end);
1196     return v;
1197 }
1198
1199 static void
1200 FcParseDouble (FcConfigParse *parse)
1201 {
1202     FcChar8 *s, *end;
1203     double  d;
1204     
1205     if (!parse->pstack)
1206         return;
1207     s = FcStrBufDoneStatic (&parse->pstack->str);
1208     if (!s)
1209     {
1210         FcConfigMessage (parse, FcSevereError, "out of memory");
1211         return;
1212     }
1213     end = 0;
1214     d = FcStrtod ((char *) s, (char **)&end);
1215     if (end != s + strlen ((char *) s))
1216         FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid double", s);
1217     else
1218         FcVStackPushDouble (parse, d);
1219     FcStrBufDestroy (&parse->pstack->str);
1220 }
1221
1222 static void
1223 FcParseString (FcConfigParse *parse, FcVStackTag tag)
1224 {
1225     FcChar8 *s;
1226     
1227     if (!parse->pstack)
1228         return;
1229     s = FcStrBufDone (&parse->pstack->str);
1230     if (!s)
1231     {
1232         FcConfigMessage (parse, FcSevereError, "out of memory");
1233         return;
1234     }
1235     if (!FcVStackPushString (parse, tag, s))
1236         FcStrFree (s);
1237 }
1238
1239 static void
1240 FcParseMatrix (FcConfigParse *parse)
1241 {
1242     FcVStack    *vstack;
1243     enum { m_done, m_xx, m_xy, m_yx, m_yy } matrix_state = m_yy;
1244     FcMatrix    m;
1245     
1246     while ((vstack = FcVStackPop (parse)))
1247     {
1248         double  v;
1249         switch (vstack->tag) {
1250         case FcVStackInteger:
1251             v = vstack->u.integer;
1252             break;
1253         case FcVStackDouble:
1254             v = vstack->u._double;
1255             break;
1256         default:
1257             FcConfigMessage (parse, FcSevereError, "non-double matrix element");
1258             v = 1.0;
1259             break;
1260         }
1261         switch (matrix_state) {
1262         case m_xx: m.xx = v; break;
1263         case m_xy: m.xy = v; break;
1264         case m_yx: m.yx = v; break;
1265         case m_yy: m.yy = v; break;
1266         default: break;
1267         }
1268         FcVStackDestroy (vstack);
1269         matrix_state--;
1270     }
1271     if (matrix_state != m_done)
1272         FcConfigMessage (parse, FcSevereError, "wrong number of matrix elements");
1273     else
1274         FcVStackPushMatrix (parse, &m);
1275 }
1276
1277 static FcBool
1278 FcConfigLexBool (FcConfigParse *parse, const FcChar8 *bool_)
1279 {
1280     FcBool  result = FcFalse;
1281
1282     if (!FcNameBool (bool_, &result))
1283         FcConfigMessage (parse, FcSevereWarning, "\"%s\" is not known boolean",
1284                          bool_);
1285     return result;
1286 }
1287
1288 static void
1289 FcParseBool (FcConfigParse *parse)
1290 {
1291     FcChar8 *s;
1292
1293     if (!parse->pstack)
1294         return;
1295     s = FcStrBufDoneStatic (&parse->pstack->str);
1296     if (!s)
1297     {
1298         FcConfigMessage (parse, FcSevereError, "out of memory");
1299         return;
1300     }
1301     FcVStackPushBool (parse, FcConfigLexBool (parse, s));
1302     FcStrBufDestroy (&parse->pstack->str);
1303 }
1304
1305 static FcBool
1306 FcConfigLexBinding (FcConfigParse   *parse,
1307                     const FcChar8   *binding_string,
1308                     FcValueBinding  *binding_ret)
1309 {
1310     FcValueBinding binding;
1311     
1312     if (!binding_string)
1313         binding = FcValueBindingWeak;
1314     else
1315     {
1316         if (!strcmp ((char *) binding_string, "weak"))
1317             binding = FcValueBindingWeak;
1318         else if (!strcmp ((char *) binding_string, "strong"))
1319             binding = FcValueBindingStrong;
1320         else if (!strcmp ((char *) binding_string, "same"))
1321             binding = FcValueBindingSame;
1322         else
1323         {
1324             FcConfigMessage (parse, FcSevereWarning, "invalid binding \"%s\"", binding_string);
1325             return FcFalse;
1326         }
1327     }
1328     *binding_ret = binding;
1329     return FcTrue;
1330 }
1331
1332 static void
1333 FcParseFamilies (FcConfigParse *parse, FcVStackTag tag)
1334 {
1335     FcVStack    *vstack;
1336     FcExpr      *left, *expr = 0, *new;
1337
1338     while ((vstack = FcVStackPop (parse)))
1339     {
1340         if (vstack->tag != FcVStackFamily)
1341         {
1342             FcConfigMessage (parse, FcSevereWarning, "non-family");
1343             FcVStackDestroy (vstack);
1344             continue;
1345         }
1346         left = vstack->u.expr;
1347         vstack->tag = FcVStackNone;
1348         FcVStackDestroy (vstack);
1349         if (expr)
1350         {
1351             new = FcExprCreateOp (left, FcOpComma, expr);
1352             if (!new)
1353             {
1354                 FcConfigMessage (parse, FcSevereError, "out of memory");
1355                 FcExprDestroy (left);
1356                 FcExprDestroy (expr);
1357                 break;
1358             }
1359             expr = new;
1360         }
1361         else
1362             expr = left;
1363     }
1364     if (expr)
1365     {
1366         if (!FcVStackPushExpr (parse, tag, expr))
1367         {
1368             FcConfigMessage (parse, FcSevereError, "out of memory");
1369             FcExprDestroy (expr);
1370         }
1371     }
1372 }
1373
1374 static void
1375 FcParseFamily (FcConfigParse *parse)
1376 {
1377     FcChar8 *s;
1378     FcExpr  *expr;
1379
1380     if (!parse->pstack)
1381         return;
1382     s = FcStrBufDoneStatic (&parse->pstack->str);
1383     if (!s)
1384     {
1385         FcConfigMessage (parse, FcSevereError, "out of memory");
1386         return;
1387     }
1388     expr = FcExprCreateString (s);
1389     FcStrBufDestroy (&parse->pstack->str);
1390     if (expr)
1391         FcVStackPushExpr (parse, FcVStackFamily, expr);
1392 }
1393
1394 static void
1395 FcParseAlias (FcConfigParse *parse)
1396 {
1397     FcExpr      *family = 0, *accept = 0, *prefer = 0, *def = 0, *new = 0;
1398     FcEdit      *edit = 0, *next;
1399     FcVStack    *vstack;
1400     FcTest      *test;
1401     FcValueBinding  binding;
1402
1403     if (!FcConfigLexBinding (parse, FcConfigGetAttribute (parse, "binding"), &binding))
1404         return;
1405     while ((vstack = FcVStackPop (parse))) 
1406     {
1407         switch (vstack->tag) {
1408         case FcVStackFamily:
1409             if (family)
1410             {
1411                 new = FcExprCreateOp (vstack->u.expr, FcOpComma, family);
1412                 if (!new)
1413                     FcConfigMessage (parse, FcSevereError, "out of memory");
1414                 else
1415                     family = new;
1416             }
1417             else
1418                 new = vstack->u.expr;
1419             if (new)
1420             {
1421                 family = new;
1422                 vstack->tag = FcVStackNone;
1423             }
1424             break;
1425         case FcVStackPrefer:
1426             if (prefer)
1427                 FcExprDestroy (prefer);
1428             prefer = vstack->u.expr;
1429             vstack->tag = FcVStackNone;
1430             break;
1431         case FcVStackAccept:
1432             if (accept)
1433                 FcExprDestroy (accept);
1434             accept = vstack->u.expr;
1435             vstack->tag = FcVStackNone;
1436             break;
1437         case FcVStackDefault:
1438             if (def)
1439                 FcExprDestroy (def);
1440             def = vstack->u.expr;
1441             vstack->tag = FcVStackNone;
1442             break;
1443         default:
1444             FcConfigMessage (parse, FcSevereWarning, "bad alias");
1445             break;
1446         }
1447         FcVStackDestroy (vstack);
1448     }
1449     if (!family)
1450     {
1451         FcConfigMessage (parse, FcSevereError, "missing family in alias");
1452         if (prefer)
1453             FcExprDestroy (prefer);
1454         if (accept)
1455             FcExprDestroy (accept);
1456         if (def)
1457             FcExprDestroy (def);
1458         return;
1459     }
1460     if (prefer)
1461     {
1462         edit = FcEditCreate (parse, 
1463                              FC_FAMILY_OBJECT,
1464                              FcOpPrepend,
1465                              prefer,
1466                              binding);
1467         if (edit)
1468             edit->next = 0;
1469         else
1470             FcExprDestroy (prefer);
1471     }
1472     if (accept)
1473     {
1474         next = edit;
1475         edit = FcEditCreate (parse,
1476                              FC_FAMILY_OBJECT,
1477                              FcOpAppend,
1478                              accept,
1479                              binding);
1480         if (edit)
1481             edit->next = next;
1482         else
1483             FcExprDestroy (accept);
1484     }
1485     if (def)
1486     {
1487         next = edit;
1488         edit = FcEditCreate (parse,
1489                              FC_FAMILY_OBJECT,
1490                              FcOpAppendLast,
1491                              def,
1492                              binding);
1493         if (edit)
1494             edit->next = next;
1495         else
1496             FcExprDestroy (def);
1497     }
1498     if (edit)
1499     {
1500         test = FcTestCreate (parse, FcMatchPattern,
1501                              FcQualAny,
1502                              (FcChar8 *) FC_FAMILY,
1503                              FcOpEqual,
1504                              family);
1505         if (test)
1506             if (!FcConfigAddEdit (parse->config, test, edit, FcMatchPattern))
1507                 FcTestDestroy (test);
1508     }
1509     else
1510         FcExprDestroy (family);
1511 }
1512
1513 static FcExpr *
1514 FcPopExpr (FcConfigParse *parse)
1515 {
1516     FcVStack    *vstack = FcVStackPop (parse);
1517     FcExpr      *expr = 0;
1518     if (!vstack)
1519         return 0;
1520     switch (vstack->tag) {
1521     case FcVStackNone:
1522         break;
1523     case FcVStackString:
1524     case FcVStackFamily:
1525         expr = FcExprCreateString (vstack->u.string);
1526         break;
1527     case FcVStackField:
1528         expr = FcExprCreateField ((char *) vstack->u.string);
1529         break;
1530     case FcVStackConstant:
1531         expr = FcExprCreateConst (vstack->u.string);
1532         break;
1533     case FcVStackGlob:
1534         /* XXX: What's the correct action here? (CDW) */
1535         break;
1536     case FcVStackPrefer:
1537     case FcVStackAccept:
1538     case FcVStackDefault:
1539         expr = vstack->u.expr;
1540         vstack->tag = FcVStackNone;
1541         break;
1542     case FcVStackInteger:
1543         expr = FcExprCreateInteger (vstack->u.integer);
1544         break;
1545     case FcVStackDouble:
1546         expr = FcExprCreateDouble (vstack->u._double);
1547         break;
1548     case FcVStackMatrix:
1549         expr = FcExprCreateMatrix (vstack->u.matrix);
1550         break;
1551     case FcVStackBool:
1552         expr = FcExprCreateBool (vstack->u.bool_);
1553         break;
1554     case FcVStackTest:
1555         break;
1556     case FcVStackExpr:
1557         expr = vstack->u.expr;
1558         vstack->tag = FcVStackNone;
1559         break;
1560     case FcVStackEdit:
1561         break;
1562     default:
1563         break;
1564     }
1565     FcVStackDestroy (vstack);
1566     return expr;
1567 }
1568
1569 /*
1570  * This builds a tree of binary operations.  Note
1571  * that every operator is defined so that if only
1572  * a single operand is contained, the value of the
1573  * whole expression is the value of the operand.
1574  *
1575  * This code reduces in that case to returning that
1576  * operand.
1577  */
1578 static FcExpr *
1579 FcPopBinary (FcConfigParse *parse, FcOp op)
1580 {
1581     FcExpr  *left, *expr = 0, *new;
1582
1583     while ((left = FcPopExpr (parse)))
1584     {
1585         if (expr)
1586         {
1587             new = FcExprCreateOp (left, op, expr);
1588             if (!new)
1589             {
1590                 FcConfigMessage (parse, FcSevereError, "out of memory");
1591                 FcExprDestroy (left);
1592                 FcExprDestroy (expr);
1593                 return 0;
1594             }
1595             expr = new;
1596         }
1597         else
1598             expr = left;
1599     }
1600     return expr;
1601 }
1602
1603 static void
1604 FcParseBinary (FcConfigParse *parse, FcOp op)
1605 {
1606     FcExpr  *expr = FcPopBinary (parse, op);
1607     if (expr)
1608         FcVStackPushExpr (parse, FcVStackExpr, expr);
1609 }
1610
1611 /*
1612  * This builds a a unary operator, it consumes only
1613  * a single operand
1614  */
1615
1616 static FcExpr *
1617 FcPopUnary (FcConfigParse *parse, FcOp op)
1618 {
1619     FcExpr  *operand, *new = 0;
1620
1621     if ((operand = FcPopExpr (parse)))
1622     {
1623         new = FcExprCreateOp (operand, op, 0);
1624         if (!new)
1625         {
1626             FcExprDestroy (operand);
1627             FcConfigMessage (parse, FcSevereError, "out of memory");
1628         }
1629     }
1630     return new;
1631 }
1632
1633 static void
1634 FcParseUnary (FcConfigParse *parse, FcOp op)
1635 {
1636     FcExpr  *expr = FcPopUnary (parse, op);
1637     if (expr)
1638         FcVStackPushExpr (parse, FcVStackExpr, expr);
1639 }
1640
1641 static void
1642 FcParseInclude (FcConfigParse *parse)
1643 {
1644     FcChar8         *s;
1645     const FcChar8   *i;
1646     FcBool          ignore_missing = FcFalse;
1647     
1648     s = FcStrBufDoneStatic (&parse->pstack->str);
1649     if (!s)
1650     {
1651         FcConfigMessage (parse, FcSevereError, "out of memory");
1652         return;
1653     }
1654     i = FcConfigGetAttribute (parse, "ignore_missing");
1655     if (i && FcConfigLexBool (parse, (FcChar8 *) i) == FcTrue)
1656         ignore_missing = FcTrue;
1657     if (!FcConfigParseAndLoad (parse->config, s, !ignore_missing))
1658         parse->error = FcTrue;
1659     FcStrBufDestroy (&parse->pstack->str);
1660 }
1661
1662 typedef struct _FcOpMap {
1663     char    name[16];
1664     FcOp    op;
1665 } FcOpMap;
1666
1667 static FcOp
1668 FcConfigLexOp (const FcChar8 *op, const FcOpMap *map, int nmap)
1669 {
1670     int i;
1671
1672     for (i = 0; i < nmap; i++)
1673         if (!strcmp ((char *) op, map[i].name)) 
1674             return map[i].op;
1675     return FcOpInvalid;
1676 }
1677
1678 static const FcOpMap fcCompareOps[] = {
1679     { "eq",             FcOpEqual           },
1680     { "not_eq",         FcOpNotEqual        },
1681     { "less",           FcOpLess            },
1682     { "less_eq",        FcOpLessEqual       },
1683     { "more",           FcOpMore            },
1684     { "more_eq",        FcOpMoreEqual       },
1685     { "contains",       FcOpContains        },
1686     { "not_contains",   FcOpNotContains     }
1687 };
1688
1689 #define NUM_COMPARE_OPS (int) (sizeof fcCompareOps / sizeof fcCompareOps[0])
1690
1691 static FcOp
1692 FcConfigLexCompare (const FcChar8 *compare)
1693 {
1694     return FcConfigLexOp (compare, fcCompareOps, NUM_COMPARE_OPS);
1695 }
1696
1697 static void
1698 FcParseTest (FcConfigParse *parse)
1699 {
1700     const FcChar8   *kind_string;
1701     FcMatchKind     kind;
1702     const FcChar8   *qual_string;
1703     FcQual          qual;
1704     const FcChar8   *name;
1705     const FcChar8   *compare_string;
1706     FcOp            compare;
1707     FcExpr          *expr;
1708     FcTest          *test;
1709
1710     kind_string = FcConfigGetAttribute (parse, "target");
1711     if (!kind_string)
1712         kind = FcMatchDefault;
1713     else
1714     {
1715         if (!strcmp ((char *) kind_string, "pattern"))
1716             kind = FcMatchPattern;
1717         else if (!strcmp ((char *) kind_string, "font"))
1718             kind = FcMatchFont;
1719         else if (!strcmp ((char *) kind_string, "scan"))
1720             kind = FcMatchScan;
1721         else if (!strcmp ((char *) kind_string, "default"))
1722             kind = FcMatchDefault;
1723         else
1724         {
1725             FcConfigMessage (parse, FcSevereWarning, "invalid test target \"%s\"", kind_string);
1726             return;
1727         }
1728     }
1729     qual_string = FcConfigGetAttribute (parse, "qual");
1730     if (!qual_string)
1731         qual = FcQualAny;
1732     else
1733     {
1734         if (!strcmp ((char *) qual_string, "any"))
1735             qual = FcQualAny;
1736         else if (!strcmp ((char *) qual_string, "all"))
1737             qual = FcQualAll;
1738         else if (!strcmp ((char *) qual_string, "first"))
1739             qual = FcQualFirst;
1740         else if (!strcmp ((char *) qual_string, "not_first"))
1741             qual = FcQualNotFirst;
1742         else
1743         {
1744             FcConfigMessage (parse, FcSevereWarning, "invalid test qual \"%s\"", qual_string);
1745             return;
1746         }
1747     }
1748     name = FcConfigGetAttribute (parse, "name");
1749     if (!name)
1750     {
1751         FcConfigMessage (parse, FcSevereWarning, "missing test name");
1752         return;
1753     }
1754     compare_string = FcConfigGetAttribute (parse, "compare");
1755     if (!compare_string)
1756         compare = FcOpEqual;
1757     else
1758     {
1759         compare = FcConfigLexCompare (compare_string);
1760         if (compare == FcOpInvalid)
1761         {
1762             FcConfigMessage (parse, FcSevereWarning, "invalid test compare \"%s\"", compare_string);
1763             return;
1764         }
1765     }
1766     expr = FcPopBinary (parse, FcOpComma);
1767     if (!expr)
1768     {
1769         FcConfigMessage (parse, FcSevereWarning, "missing test expression");
1770         return;
1771     }
1772     test = FcTestCreate (parse, kind, qual, name, compare, expr);
1773     if (!test)
1774     {
1775         FcConfigMessage (parse, FcSevereError, "out of memory");
1776         return;
1777     }
1778     FcVStackPushTest (parse, test);
1779 }
1780
1781 static const FcOpMap fcModeOps[] = {
1782     { "assign",         FcOpAssign          },
1783     { "assign_replace", FcOpAssignReplace   },
1784     { "prepend",        FcOpPrepend         },
1785     { "prepend_first",  FcOpPrependFirst    },
1786     { "append",         FcOpAppend          },
1787     { "append_last",    FcOpAppendLast      },
1788 };
1789
1790 #define NUM_MODE_OPS (int) (sizeof fcModeOps / sizeof fcModeOps[0])
1791
1792 static FcOp
1793 FcConfigLexMode (const FcChar8 *mode)
1794 {
1795     return FcConfigLexOp (mode, fcModeOps, NUM_MODE_OPS);
1796 }
1797
1798 static void
1799 FcParseEdit (FcConfigParse *parse)
1800 {
1801     const FcChar8   *name;
1802     const FcChar8   *mode_string;
1803     FcOp            mode;
1804     FcValueBinding  binding;
1805     FcExpr          *expr;
1806     FcEdit          *edit;
1807
1808     name = FcConfigGetAttribute (parse, "name");
1809     if (!name)
1810     {
1811         FcConfigMessage (parse, FcSevereWarning, "missing edit name");
1812         return;
1813     }
1814     mode_string = FcConfigGetAttribute (parse, "mode");
1815     if (!mode_string)
1816         mode = FcOpAssign;
1817     else
1818     {
1819         mode = FcConfigLexMode (mode_string);
1820         if (mode == FcOpInvalid)
1821         {
1822             FcConfigMessage (parse, FcSevereWarning, "invalid edit mode \"%s\"", mode_string);
1823             return;
1824         }
1825     }
1826     if (!FcConfigLexBinding (parse, FcConfigGetAttribute (parse, "binding"), &binding))
1827         return;
1828
1829     expr = FcPopBinary (parse, FcOpComma);
1830     edit = FcEditCreate (parse, FcObjectFromName ((char *) name),
1831                          mode, expr, binding);
1832     if (!edit)
1833     {
1834         FcConfigMessage (parse, FcSevereError, "out of memory");
1835         FcExprDestroy (expr);
1836         return;
1837     }
1838     if (!FcVStackPushEdit (parse, edit))
1839         FcEditDestroy (edit);
1840 }
1841
1842 static void
1843 FcParseMatch (FcConfigParse *parse)
1844 {
1845     const FcChar8   *kind_name;
1846     FcMatchKind     kind;
1847     FcTest          *test = 0;
1848     FcEdit          *edit = 0;
1849     FcVStack        *vstack;
1850
1851     kind_name = FcConfigGetAttribute (parse, "target");
1852     if (!kind_name)
1853         kind = FcMatchPattern;
1854     else
1855     {
1856         if (!strcmp ((char *) kind_name, "pattern"))
1857             kind = FcMatchPattern;
1858         else if (!strcmp ((char *) kind_name, "font"))
1859             kind = FcMatchFont;
1860         else if (!strcmp ((char *) kind_name, "scan"))
1861             kind = FcMatchScan;
1862         else
1863         {
1864             FcConfigMessage (parse, FcSevereWarning, "invalid match target \"%s\"", kind_name);
1865             return;
1866         }
1867     }
1868     while ((vstack = FcVStackPop (parse)))
1869     {
1870         switch (vstack->tag) {
1871         case FcVStackTest:
1872             vstack->u.test->next = test;
1873             test = vstack->u.test;
1874             vstack->tag = FcVStackNone;
1875             break;
1876         case FcVStackEdit:
1877             vstack->u.edit->next = edit;
1878             edit = vstack->u.edit;
1879             vstack->tag = FcVStackNone;
1880             if (kind == FcMatchScan && edit->object > FC_MAX_BASE_OBJECT)
1881             {
1882                 FcConfigMessage (parse, FcSevereError, 
1883                                  "<match target=\"scan\"> cannot edit user-defined object \"%s\"",
1884                                  FcObjectName(edit->object));
1885             }
1886             break;
1887         default:
1888             FcConfigMessage (parse, FcSevereWarning, "invalid match element");
1889             break;
1890         }
1891         FcVStackDestroy (vstack);
1892     }
1893     if (!FcConfigAddEdit (parse->config, test, edit, kind))
1894         FcConfigMessage (parse, FcSevereError, "out of memory");
1895 }
1896
1897 static void
1898 FcParseAcceptRejectFont (FcConfigParse *parse, FcElement element)
1899 {
1900     FcVStack    *vstack;
1901
1902     while ((vstack = FcVStackPop (parse)))
1903     {
1904         switch (vstack->tag) {
1905         case FcVStackGlob:
1906             if (!FcConfigGlobAdd (parse->config, 
1907                                   vstack->u.string,
1908                                   element == FcElementAcceptfont))
1909             {
1910                 FcConfigMessage (parse, FcSevereError, "out of memory");
1911             }
1912             break;
1913         case FcVStackPattern:
1914             if (!FcConfigPatternsAdd (parse->config,
1915                                       vstack->u.pattern,
1916                                       element == FcElementAcceptfont))
1917             {
1918                 FcConfigMessage (parse, FcSevereError, "out of memory");
1919             }
1920             else
1921                 vstack->tag = FcVStackNone;
1922             break;
1923         default:
1924             FcConfigMessage (parse, FcSevereWarning, "bad font selector");
1925             break;
1926         }
1927         FcVStackDestroy (vstack);
1928     }
1929 }
1930
1931
1932 static FcValue
1933 FcPopValue (FcConfigParse *parse)
1934 {
1935     FcVStack    *vstack = FcVStackPop (parse);
1936     FcValue     value;
1937     
1938     value.type = FcTypeVoid;
1939     
1940     if (!vstack)
1941         return value;
1942     
1943     switch (vstack->tag) {
1944     case FcVStackString:
1945         value.u.s = FcStrCopy (vstack->u.string);
1946         if (value.u.s)
1947             value.type = FcTypeString;
1948         break;
1949     case FcVStackConstant:
1950         if (FcNameConstant (vstack->u.string, &value.u.i))
1951             value.type = FcTypeInteger;
1952         break;
1953     case FcVStackInteger:
1954         value.u.i = vstack->u.integer;
1955         value.type = FcTypeInteger;
1956         break;
1957     case FcVStackDouble:
1958         value.u.d = vstack->u._double;
1959         value.type = FcTypeInteger;
1960         break;
1961     case FcVStackMatrix:
1962         value.u.m = FcMatrixCopy (vstack->u.matrix);
1963         if (value.u.m)
1964             value.type = FcTypeMatrix;
1965         break;
1966     case FcVStackBool:
1967         value.u.b = vstack->u.bool_;
1968         value.type = FcTypeBool;
1969         break;
1970     default:
1971         FcConfigMessage (parse, FcSevereWarning, "unknown pattern element %d", 
1972                          vstack->tag);
1973         break;
1974     }
1975     FcVStackDestroy (vstack);
1976     
1977     return value;
1978 }
1979
1980 static void
1981 FcParsePatelt (FcConfigParse *parse)
1982 {
1983     FcValue     value;
1984     FcPattern   *pattern = FcPatternCreate ();
1985     const char  *name;
1986
1987     if (!pattern)
1988     {
1989         FcConfigMessage (parse, FcSevereError, "out of memory");
1990         return;
1991     }
1992
1993     name = (char *) FcConfigGetAttribute (parse, "name");
1994     if (!name)
1995     {
1996         FcConfigMessage (parse, FcSevereWarning, "missing pattern element name");
1997         FcPatternDestroy (pattern);
1998         return;
1999     }
2000     
2001     for (;;)
2002     {
2003         value = FcPopValue (parse);
2004         if (value.type == FcTypeVoid)
2005             break;
2006         if (!FcPatternAdd (pattern, name, value, FcTrue))
2007         {
2008             FcConfigMessage (parse, FcSevereError, "out of memory");
2009             FcValueDestroy(value);
2010             break;
2011         }
2012         FcValueDestroy(value);
2013     }
2014
2015     FcVStackPushPattern (parse, pattern);
2016 }
2017
2018 static void
2019 FcParsePattern (FcConfigParse *parse)
2020 {
2021     FcVStack    *vstack;
2022     FcPattern   *pattern = FcPatternCreate ();
2023
2024     if (!pattern)
2025     {
2026         FcConfigMessage (parse, FcSevereError, "out of memory");
2027         return;
2028     }
2029         
2030     while ((vstack = FcVStackPop (parse)))
2031     {
2032         switch (vstack->tag) {
2033         case FcVStackPattern:
2034             if (!FcPatternAppend (pattern, vstack->u.pattern))
2035             {
2036                 FcConfigMessage (parse, FcSevereError, "out of memory");
2037                 FcPatternDestroy (pattern);
2038                 return;
2039             }
2040             break;
2041         default:
2042             FcConfigMessage (parse, FcSevereWarning, "unknown pattern element");
2043             break;
2044         }
2045         FcVStackDestroy (vstack);
2046     }
2047
2048     FcVStackPushPattern (parse, pattern);
2049 }
2050
2051 static void
2052 FcEndElement(void *userData, const XML_Char *name)
2053 {
2054     FcConfigParse   *parse = userData;
2055     FcChar8         *data;
2056     
2057     if (!parse->pstack)
2058         return;
2059     switch (parse->pstack->element) {
2060     case FcElementNone:
2061         break;
2062     case FcElementFontconfig:
2063         break;
2064     case FcElementDir:
2065         data = FcStrBufDoneStatic (&parse->pstack->str);
2066         if (!data)
2067         {
2068             FcConfigMessage (parse, FcSevereError, "out of memory");
2069             break;
2070         }
2071 #ifdef _WIN32
2072         if (strcmp (data, "CUSTOMFONTDIR") == 0)
2073         {
2074                 char *p;
2075                 FcStrFree (data);
2076                 data = malloc (1000);
2077                 if (!data)
2078                 {
2079                         FcConfigMessage (parse, FcSevereError, "out of memory");
2080                         break;
2081                 }
2082                 FcMemAlloc (FC_MEM_STRING, 1000);
2083                 if(!GetModuleFileName(NULL, data, 1000))
2084                 {
2085                         FcConfigMessage (parse, FcSevereError, "GetModuleFileName failed");
2086                         FcStrFree (data);
2087                         break;
2088                 }
2089                 p = strrchr (data, '\\');
2090                 if (p) *p = '\0';
2091                 strcat (data, "\\fonts");
2092         }
2093         else if (strcmp (data, "APPSHAREFONTDIR") == 0)
2094         {
2095                 char *p;
2096                 FcStrFree (data);
2097                 data = malloc (1000);
2098                 if (!data)
2099                 {
2100                         FcConfigMessage (parse, FcSevereError, "out of memory");
2101                         break;
2102                 }
2103                 FcMemAlloc (FC_MEM_STRING, 1000);
2104                 if(!GetModuleFileName(NULL, data, 1000))
2105                 {
2106                         FcConfigMessage (parse, FcSevereError, "GetModuleFileName failed");
2107                         FcStrFree (data);
2108                         break;
2109                 }
2110                 p = strrchr (data, '\\');
2111                 if (p) *p = '\0';
2112                 strcat (data, "\\..\\share\\fonts");
2113         }
2114         else if (strcmp (data, "WINDOWSFONTDIR") == 0)
2115         {
2116             int rc;
2117             FcStrFree (data);
2118             data = malloc (1000);
2119             if (!data)
2120             {
2121                 FcConfigMessage (parse, FcSevereError, "out of memory");
2122                 break;
2123             }
2124             FcMemAlloc (FC_MEM_STRING, 1000);
2125             rc = GetWindowsDirectory (data, 800);
2126             if (rc == 0 || rc > 800)
2127             {
2128                 FcConfigMessage (parse, FcSevereError, "GetWindowsDirectory failed");
2129                 FcStrFree (data);
2130                 break;
2131             }
2132             if (data [strlen (data) - 1] != '\\')
2133                 strcat (data, "\\");
2134             strcat (data, "fonts");
2135         }
2136 #endif
2137         if (strlen ((char *) data) == 0)
2138             FcConfigMessage (parse, FcSevereWarning, "empty font directory name ignored");
2139         else if (!FcStrUsesHome (data) || FcConfigHome ())
2140         {
2141             if (!FcConfigAddDir (parse->config, data))
2142                 FcConfigMessage (parse, FcSevereError, "out of memory; cannot add directory %s", data);
2143         }
2144         FcStrBufDestroy (&parse->pstack->str);
2145         break;
2146     case FcElementCacheDir:
2147         data = FcStrBufDone (&parse->pstack->str);
2148         if (!data)
2149         {
2150             FcConfigMessage (parse, FcSevereError, "out of memory");
2151             break;
2152         }
2153 #ifdef _WIN32
2154         if (strcmp (data, "WINDOWSTEMPDIR_FONTCONFIG_CACHE") == 0)
2155         {
2156             int rc;
2157             FcStrFree (data);
2158             data = malloc (1000);
2159             if (!data)
2160             {
2161                 FcConfigMessage (parse, FcSevereError, "out of memory");
2162                 break;
2163             }
2164             FcMemAlloc (FC_MEM_STRING, 1000);
2165             rc = GetTempPath (800, data);
2166             if (rc == 0 || rc > 800)
2167             {
2168                 FcConfigMessage (parse, FcSevereError, "GetWindowsDirectory failed");
2169                 FcStrFree (data);
2170                 break;
2171             }
2172             if (data [strlen (data) - 1] != '\\')
2173                 strcat (data, "\\");
2174             strcat (data, "fontconfig\\cache");
2175         }
2176 #endif
2177         if (!FcStrUsesHome (data) || FcConfigHome ())
2178         {
2179             if (!FcConfigAddCacheDir (parse->config, data))
2180                 FcConfigMessage (parse, FcSevereError, "out of memory; cannot add cache directory %s", data);
2181         }
2182         FcStrFree (data);
2183         break;
2184         
2185     case FcElementCache:
2186         data = FcStrBufDoneStatic (&parse->pstack->str);
2187         if (!data)
2188         {
2189             FcConfigMessage (parse, FcSevereError, "out of memory");
2190             break;
2191         }
2192         /* discard this data; no longer used */
2193         FcStrBufDestroy (&parse->pstack->str);
2194         break;
2195     case FcElementInclude:
2196         FcParseInclude (parse);
2197         break;
2198     case FcElementConfig:
2199         break;
2200     case FcElementMatch:
2201         FcParseMatch (parse);
2202         break;
2203     case FcElementAlias:
2204         FcParseAlias (parse);
2205         break;
2206
2207     case FcElementBlank:
2208         FcParseBlank (parse);
2209         break;
2210     case FcElementRescan:
2211         FcParseRescan (parse);
2212         break;
2213         
2214     case FcElementPrefer:
2215         FcParseFamilies (parse, FcVStackPrefer);
2216         break;
2217     case FcElementAccept:
2218         FcParseFamilies (parse, FcVStackAccept);
2219         break;
2220     case FcElementDefault:
2221         FcParseFamilies (parse, FcVStackDefault);
2222         break;
2223     case FcElementFamily:
2224         FcParseFamily (parse);
2225         break;
2226
2227     case FcElementTest:
2228         FcParseTest (parse);
2229         break;
2230     case FcElementEdit:
2231         FcParseEdit (parse);
2232         break;
2233
2234     case FcElementInt:
2235         FcParseInt (parse);
2236         break;
2237     case FcElementDouble:
2238         FcParseDouble (parse);
2239         break;
2240     case FcElementString:
2241         FcParseString (parse, FcVStackString);
2242         break;
2243     case FcElementMatrix:
2244         FcParseMatrix (parse);
2245         break;
2246     case FcElementBool:
2247         FcParseBool (parse);
2248         break;
2249     case FcElementCharset:
2250 /*      FcParseCharset (parse); */
2251         break;
2252     case FcElementSelectfont:
2253         break;
2254     case FcElementAcceptfont:
2255     case FcElementRejectfont:
2256         FcParseAcceptRejectFont (parse, parse->pstack->element);
2257         break;
2258     case FcElementGlob:
2259         FcParseString (parse, FcVStackGlob);
2260         break;
2261     case FcElementPattern:
2262         FcParsePattern (parse);
2263         break;
2264     case FcElementPatelt:
2265         FcParsePatelt (parse);
2266         break;
2267     case FcElementName:
2268         FcParseString (parse, FcVStackField);
2269         break;
2270     case FcElementConst:
2271         FcParseString (parse, FcVStackConstant);
2272         break;
2273     case FcElementOr:
2274         FcParseBinary (parse, FcOpOr);
2275         break;
2276     case FcElementAnd:
2277         FcParseBinary (parse, FcOpAnd);
2278         break;
2279     case FcElementEq:
2280         FcParseBinary (parse, FcOpEqual);
2281         break;
2282     case FcElementNotEq:
2283         FcParseBinary (parse, FcOpNotEqual);
2284         break;
2285     case FcElementLess:
2286         FcParseBinary (parse, FcOpLess);
2287         break;
2288     case FcElementLessEq:
2289         FcParseBinary (parse, FcOpLessEqual);
2290         break;
2291     case FcElementMore:
2292         FcParseBinary (parse, FcOpMore);
2293         break;
2294     case FcElementMoreEq:
2295         FcParseBinary (parse, FcOpMoreEqual);
2296         break;
2297     case FcElementContains:
2298         FcParseBinary (parse, FcOpContains);
2299         break;
2300     case FcElementNotContains:
2301         FcParseBinary (parse, FcOpNotContains);
2302         break;
2303     case FcElementPlus:
2304         FcParseBinary (parse, FcOpPlus);
2305         break;
2306     case FcElementMinus:
2307         FcParseBinary (parse, FcOpMinus);
2308         break;
2309     case FcElementTimes:
2310         FcParseBinary (parse, FcOpTimes);
2311         break;
2312     case FcElementDivide:
2313         FcParseBinary (parse, FcOpDivide);
2314         break;
2315     case FcElementNot:
2316         FcParseUnary (parse, FcOpNot);
2317         break;
2318     case FcElementIf:
2319         FcParseBinary (parse, FcOpQuest);
2320         break;
2321     case FcElementFloor:
2322         FcParseUnary (parse, FcOpFloor);
2323         break;
2324     case FcElementCeil:
2325         FcParseUnary (parse, FcOpCeil);
2326         break;
2327     case FcElementRound:
2328         FcParseUnary (parse, FcOpRound);
2329         break;
2330     case FcElementTrunc:
2331         FcParseUnary (parse, FcOpTrunc);
2332         break;
2333     case FcElementUnknown:
2334         break;
2335     }
2336     (void) FcPStackPop (parse);
2337 }
2338
2339 static void
2340 FcCharacterData (void *userData, const XML_Char *s, int len)
2341 {
2342     FcConfigParse   *parse = userData;
2343     
2344     if (!parse->pstack)
2345         return;
2346     if (!FcStrBufData (&parse->pstack->str, (FcChar8 *) s, len))
2347         FcConfigMessage (parse, FcSevereError, "out of memory");
2348 }
2349
2350 static void
2351 FcStartDoctypeDecl (void            *userData,
2352                     const XML_Char  *doctypeName,
2353                     const XML_Char  *sysid,
2354                     const XML_Char  *pubid,
2355                     int             has_internal_subset)
2356 {
2357     FcConfigParse   *parse = userData;
2358
2359     if (strcmp ((char *) doctypeName, "fontconfig") != 0)
2360         FcConfigMessage (parse, FcSevereError, "invalid doctype \"%s\"", doctypeName);
2361 }
2362
2363 #ifdef ENABLE_LIBXML2
2364
2365 static void
2366 FcInternalSubsetDecl (void            *userData,
2367                       const XML_Char  *doctypeName,
2368                       const XML_Char  *sysid,
2369                       const XML_Char  *pubid)
2370 {
2371     FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 1);
2372 }
2373
2374 static void
2375 FcExternalSubsetDecl (void            *userData,
2376                       const XML_Char  *doctypeName,
2377                       const XML_Char  *sysid,
2378                       const XML_Char  *pubid)
2379 {
2380     FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 0);
2381 }
2382
2383 #else /* ENABLE_LIBXML2 */
2384
2385 static void
2386 FcEndDoctypeDecl (void *userData)
2387 {
2388 }
2389
2390 #endif /* ENABLE_LIBXML2 */
2391
2392 static int
2393 FcSortCmpStr (const void *a, const void *b)
2394 {
2395     const FcChar8    *as = *((FcChar8 **) a);
2396     const FcChar8    *bs = *((FcChar8 **) b);
2397     return FcStrCmp (as, bs);
2398 }
2399
2400 static FcBool
2401 FcConfigParseAndLoadDir (FcConfig       *config,
2402                          const FcChar8  *name,
2403                          const FcChar8  *dir,
2404                          FcBool         complain)
2405 {
2406     DIR             *d;
2407     struct dirent   *e;
2408     FcBool          ret = FcTrue;
2409     FcChar8         *file;
2410     FcChar8         *base;
2411     FcStrSet        *files;
2412
2413     d = opendir ((char *) dir);
2414     if (!d)
2415     {
2416         if (complain)
2417             FcConfigMessage (0, FcSevereError, "Cannot open config dir \"%s\"",
2418                              name);
2419         ret = FcFalse;
2420         goto bail0;
2421     }
2422     /* freed below */
2423     file = (FcChar8 *) malloc (strlen ((char *) dir) + 1 + FC_MAX_FILE_LEN + 1);
2424     if (!file)
2425     {
2426         ret = FcFalse;
2427         goto bail1;
2428     }
2429     
2430     strcpy ((char *) file, (char *) dir);
2431     strcat ((char *) file, "/");
2432     base = file + strlen ((char *) file);
2433     
2434     files = FcStrSetCreate ();
2435     if (!files)
2436     {
2437         ret = FcFalse;
2438         goto bail2;
2439     }
2440     
2441     if (FcDebug () & FC_DBG_CONFIG)
2442         printf ("\tScanning config dir %s\n", dir);
2443         
2444     while (ret && (e = readdir (d)))
2445     {
2446         int d_len;
2447 #define TAIL        ".conf"
2448 #define TAIL_LEN    5
2449         /*
2450          * Add all files of the form [0-9]*.conf
2451          */
2452         if ('0' <= e->d_name[0] && e->d_name[0] <= '9' &&
2453             (d_len = strlen (e->d_name)) < FC_MAX_FILE_LEN &&
2454             d_len > TAIL_LEN &&
2455             strcmp (e->d_name + d_len - TAIL_LEN, TAIL) == 0)
2456         {
2457             strcpy ((char *) base, (char *) e->d_name);
2458             if (!FcStrSetAdd (files, file))
2459             {
2460                 ret = FcFalse;
2461                 goto bail3;
2462             }
2463         }
2464     }
2465     if (ret)
2466     {
2467         int i;
2468         qsort (files->strs, files->num, sizeof (FcChar8 *), 
2469                (int (*)(const void *, const void *)) FcSortCmpStr);
2470         for (i = 0; ret && i < files->num; i++)
2471             ret = FcConfigParseAndLoad (config, files->strs[i], complain);
2472     }
2473 bail3:
2474     FcStrSetDestroy (files);
2475 bail2:
2476     free (file);
2477 bail1:
2478     closedir (d);
2479 bail0:
2480     return ret || !complain;
2481 }
2482
2483 FcBool
2484 FcConfigParseAndLoad (FcConfig      *config,
2485                       const FcChar8 *name,
2486                       FcBool        complain)
2487 {
2488
2489     XML_Parser      p;
2490     FcChar8         *filename;
2491     int             fd;
2492     int             len;
2493     FcConfigParse   parse;
2494     FcBool          error = FcTrue;
2495     
2496 #ifdef ENABLE_LIBXML2
2497     xmlSAXHandler   sax;
2498     char            buf[BUFSIZ];
2499 #else
2500     void            *buf;
2501 #endif
2502     
2503     filename = FcConfigFilename (name);
2504     if (!filename)
2505         goto bail0;
2506     
2507     if (FcStrSetMember (config->configFiles, filename))
2508     {
2509         FcStrFree (filename);
2510         return FcTrue;
2511     }
2512
2513     if (!FcStrSetAdd (config->configFiles, filename))
2514     {
2515         FcStrFree (filename);
2516         goto bail0;
2517     }
2518
2519     if (FcFileIsDir (filename))
2520     {
2521         FcBool ret = FcConfigParseAndLoadDir (config, name, filename, complain);
2522         FcStrFree (filename);
2523         return ret;
2524     }
2525
2526     if (FcDebug () & FC_DBG_CONFIG)
2527         printf ("\tLoading config file %s\n", filename);
2528
2529     fd = open ((char *) filename, O_RDONLY);
2530     if (fd == -1) { 
2531         FcStrFree (filename);
2532         goto bail0;
2533     }
2534     
2535 #ifdef ENABLE_LIBXML2
2536     memset(&sax, 0, sizeof(sax));
2537
2538     sax.internalSubset = FcInternalSubsetDecl;
2539     sax.externalSubset = FcExternalSubsetDecl;
2540     sax.startElement = FcStartElement;
2541     sax.endElement = FcEndElement;
2542     sax.characters = FcCharacterData;
2543
2544     p = xmlCreatePushParserCtxt (&sax, &parse, NULL, 0, (const char *) filename);
2545 #else
2546     p = XML_ParserCreate ("UTF-8");
2547 #endif
2548     FcStrFree (filename);
2549
2550     if (!p)
2551         goto bail1;
2552
2553     if (!FcConfigInit (&parse, name, config, p))
2554         goto bail2;
2555
2556 #ifndef ENABLE_LIBXML2
2557
2558     XML_SetUserData (p, &parse);
2559     
2560     XML_SetDoctypeDeclHandler (p, FcStartDoctypeDecl, FcEndDoctypeDecl);
2561     XML_SetElementHandler (p, FcStartElement, FcEndElement);
2562     XML_SetCharacterDataHandler (p, FcCharacterData);
2563         
2564 #endif /* ENABLE_LIBXML2 */
2565
2566     do {
2567 #ifndef ENABLE_LIBXML2
2568         buf = XML_GetBuffer (p, BUFSIZ);
2569         if (!buf)
2570         {
2571             FcConfigMessage (&parse, FcSevereError, "cannot get parse buffer");
2572             goto bail3;
2573         }
2574 #endif
2575         len = read (fd, buf, BUFSIZ);
2576         if (len < 0)
2577         {
2578             FcConfigMessage (&parse, FcSevereError, "failed reading config file");
2579             goto bail3;
2580         }
2581
2582 #ifdef ENABLE_LIBXML2
2583         if (xmlParseChunk (p, buf, len, len == 0))
2584 #else
2585         if (!XML_ParseBuffer (p, len, len == 0))
2586 #endif
2587         {
2588             FcConfigMessage (&parse, FcSevereError, "%s", 
2589                            XML_ErrorString (XML_GetErrorCode (p)));
2590             goto bail3;
2591         }
2592     } while (len != 0);
2593     error = parse.error;
2594 bail3:
2595     FcConfigCleanup (&parse);
2596 bail2:
2597     XML_ParserFree (p);
2598 bail1:
2599     close (fd);
2600     fd = -1;
2601 bail0:
2602     if (error && complain)
2603     {
2604         if (name)
2605             FcConfigMessage (0, FcSevereError, "Cannot load config file \"%s\"", name);
2606         else
2607             FcConfigMessage (0, FcSevereError, "Cannot load default config file");
2608         return FcFalse;
2609     }
2610     return FcTrue;
2611 }
2612 #define __fcxml__
2613 #include "fcaliastail.h"
2614 #undef __fcxml__