]> git.wh0rd.org Git - fontconfig.git/blob - src/fcxml.c
Was miscomputing end of string position for FcStrtod in locales with
[fontconfig.git] / src / fcxml.c
1 /*
2  * $RCSId: xc/lib/fontconfig/src/fcxml.c,v 1.21 2002/08/22 18:53:22 keithp Exp $
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 <stdarg.h>
26 #include "fcint.h"
27
28 #ifndef HAVE_XMLPARSE_H
29 #define HAVE_XMLPARSE_H 0
30 #endif
31
32 #if HAVE_XMLPARSE_H
33 #include <xmlparse.h>
34 #else
35 #include <expat.h>
36 #endif
37
38 #ifdef _WIN32
39 #define STRICT
40 #include <windows.h>
41 #undef STRICT
42 #endif
43
44 FcTest *
45 FcTestCreate (FcMatchKind   kind, 
46               FcQual        qual,
47               const FcChar8 *field,
48               FcOp          compare,
49               FcExpr        *expr)
50 {
51     FcTest      *test = (FcTest *) malloc (sizeof (FcTest));
52
53     if (test)
54     {
55         FcMemAlloc (FC_MEM_TEST, sizeof (FcTest));
56         test->next = 0;
57         test->kind = kind;
58         test->qual = qual;
59         test->field = (char *) FcStrCopy (field);
60         test->op = compare;
61         test->expr = expr;
62     }
63     return test;
64 }
65
66 void
67 FcTestDestroy (FcTest *test)
68 {
69     if (test->next)
70         FcTestDestroy (test->next);
71     FcExprDestroy (test->expr);
72     FcStrFree ((FcChar8 *) test->field);
73     FcMemFree (FC_MEM_TEST, sizeof (FcTest));
74     free (test);
75 }
76
77 FcExpr *
78 FcExprCreateInteger (int i)
79 {
80     FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
81
82     if (e)
83     {
84         FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
85         e->op = FcOpInteger;
86         e->u.ival = i;
87     }
88     return e;
89 }
90
91 FcExpr *
92 FcExprCreateDouble (double d)
93 {
94     FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
95
96     if (e)
97     {
98         FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
99         e->op = FcOpDouble;
100         e->u.dval = d;
101     }
102     return e;
103 }
104
105 FcExpr *
106 FcExprCreateString (const FcChar8 *s)
107 {
108     FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
109
110     if (e)
111     {
112         FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
113         e->op = FcOpString;
114         e->u.sval = FcStrCopy (s);
115     }
116     return e;
117 }
118
119 FcExpr *
120 FcExprCreateMatrix (const FcMatrix *m)
121 {
122     FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
123
124     if (e)
125     {
126         FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
127         e->op = FcOpMatrix;
128         e->u.mval = FcMatrixCopy (m);
129     }
130     return e;
131 }
132
133 FcExpr *
134 FcExprCreateBool (FcBool b)
135 {
136     FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
137
138     if (e)
139     {
140         FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
141         e->op = FcOpBool;
142         e->u.bval = b;
143     }
144     return e;
145 }
146
147 FcExpr *
148 FcExprCreateNil (void)
149 {
150     FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
151
152     if (e)
153     {
154         FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
155         e->op = FcOpNil;
156     }
157     return e;
158 }
159
160 FcExpr *
161 FcExprCreateField (const char *field)
162 {
163     FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
164
165     if (e)
166     {
167         FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
168         e->op = FcOpField;
169         e->u.field = (char *) FcStrCopy ((FcChar8 *) field);
170     }
171     return e;
172 }
173
174 FcExpr *
175 FcExprCreateConst (const FcChar8 *constant)
176 {
177     FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
178
179     if (e)
180     {
181         FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
182         e->op = FcOpConst;
183         e->u.constant = FcStrCopy (constant);
184     }
185     return e;
186 }
187
188 FcExpr *
189 FcExprCreateOp (FcExpr *left, FcOp op, FcExpr *right)
190 {
191     FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
192
193     if (e)
194     {
195         FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
196         e->op = op;
197         e->u.tree.left = left;
198         e->u.tree.right = right;
199     }
200     return e;
201 }
202
203 void
204 FcExprDestroy (FcExpr *e)
205 {
206     if (!e)
207         return;
208     switch (e->op) {
209     case FcOpInteger:
210         break;
211     case FcOpDouble:
212         break;
213     case FcOpString:
214         FcStrFree (e->u.sval);
215         break;
216     case FcOpMatrix:
217         FcMatrixFree (e->u.mval);
218         break;
219     case FcOpCharSet:
220         FcCharSetDestroy (e->u.cval);
221         break;
222     case FcOpBool:
223         break;
224     case FcOpField:
225         FcStrFree ((FcChar8 *) e->u.field);
226         break;
227     case FcOpConst:
228         FcStrFree (e->u.constant);
229         break;
230     case FcOpAssign:
231     case FcOpAssignReplace:
232     case FcOpPrepend:
233     case FcOpPrependFirst:
234     case FcOpAppend:
235     case FcOpAppendLast:
236         break;
237     case FcOpOr:
238     case FcOpAnd:
239     case FcOpEqual:
240     case FcOpNotEqual:
241     case FcOpLess:
242     case FcOpLessEqual:
243     case FcOpMore:
244     case FcOpMoreEqual:
245     case FcOpContains:
246     case FcOpNotContains:
247     case FcOpPlus:
248     case FcOpMinus:
249     case FcOpTimes:
250     case FcOpDivide:
251     case FcOpQuest:
252     case FcOpComma:
253         FcExprDestroy (e->u.tree.right);
254         /* fall through */
255     case FcOpNot:
256     case FcOpFloor:
257     case FcOpCeil:
258     case FcOpRound:
259     case FcOpTrunc:
260         FcExprDestroy (e->u.tree.left);
261         break;
262     case FcOpNil:
263     case FcOpInvalid:
264         break;
265     }
266     FcMemFree (FC_MEM_EXPR, sizeof (FcExpr));
267     free (e);
268 }
269
270 FcEdit *
271 FcEditCreate (const char *field, FcOp op, FcExpr *expr, FcValueBinding binding)
272 {
273     FcEdit *e = (FcEdit *) malloc (sizeof (FcEdit));
274
275     if (e)
276     {
277         e->next = 0;
278         e->field = field;   /* already saved in grammar */
279         e->op = op;
280         e->expr = expr;
281         e->binding = binding;
282     }
283     return e;
284 }
285
286 void
287 FcEditDestroy (FcEdit *e)
288 {
289     if (e->next)
290         FcEditDestroy (e->next);
291     FcStrFree ((FcChar8 *) e->field);
292     if (e->expr)
293         FcExprDestroy (e->expr);
294 }
295
296 char *
297 FcConfigSaveField (const char *field)
298 {
299     return (char *) FcStrCopy ((FcChar8 *) field);
300 }
301
302 typedef enum _FcElement {
303     FcElementNone,
304     FcElementFontconfig,
305     FcElementDir,
306     FcElementCache,
307     FcElementInclude,
308     FcElementConfig,
309     FcElementMatch,
310     FcElementAlias,
311         
312     FcElementBlank,
313     FcElementRescan,
314
315     FcElementPrefer,
316     FcElementAccept,
317     FcElementDefault,
318     FcElementFamily,
319
320     FcElementSelectfont,
321     FcElementAcceptfont,
322     FcElementRejectfont,
323     FcElementGlob,
324
325     FcElementTest,
326     FcElementEdit,
327     FcElementInt,
328     FcElementDouble,
329     FcElementString,
330     FcElementMatrix,
331     FcElementBool,
332     FcElementCharset,
333     FcElementName,
334     FcElementConst,
335     FcElementOr,
336     FcElementAnd,
337     FcElementEq,
338     FcElementNotEq,
339     FcElementLess,
340     FcElementLessEq,
341     FcElementMore,
342     FcElementMoreEq,
343     FcElementContains,
344     FcElementNotContains,
345     FcElementPlus,
346     FcElementMinus,
347     FcElementTimes,
348     FcElementDivide,
349     FcElementNot,
350     FcElementIf,
351     FcElementFloor,
352     FcElementCeil,
353     FcElementRound,
354     FcElementTrunc,
355     FcElementUnknown
356 } FcElement;
357
358 static FcElement
359 FcElementMap (const XML_Char *name)
360 {
361     static struct {
362         char        *name;
363         FcElement   element;
364     } fcElementMap[] = {
365         { "fontconfig", FcElementFontconfig },
366         { "dir",        FcElementDir },
367         { "cache",      FcElementCache },
368         { "include",    FcElementInclude },
369         { "config",     FcElementConfig },
370         { "match",      FcElementMatch },
371         { "alias",      FcElementAlias },
372         
373         { "blank",      FcElementBlank },
374         { "rescan",     FcElementRescan },
375
376         { "prefer",     FcElementPrefer },
377         { "accept",     FcElementAccept },
378         { "default",    FcElementDefault },
379         { "family",     FcElementFamily },
380
381         { "selectfont", FcElementSelectfont },
382         { "acceptfont", FcElementAcceptfont },
383         { "rejectfont", FcElementRejectfont },
384         { "glob",       FcElementGlob },
385
386         { "test",       FcElementTest },
387         { "edit",       FcElementEdit },
388         { "int",        FcElementInt },
389         { "double",     FcElementDouble },
390         { "string",     FcElementString },
391         { "matrix",     FcElementMatrix },
392         { "bool",       FcElementBool },
393         { "charset",    FcElementCharset },
394         { "name",       FcElementName },
395         { "const",      FcElementConst },
396         { "or",         FcElementOr },
397         { "and",        FcElementAnd },
398         { "eq",         FcElementEq },
399         { "not_eq",     FcElementNotEq },
400         { "less",       FcElementLess },
401         { "less_eq",    FcElementLessEq },
402         { "more",       FcElementMore },
403         { "more_eq",    FcElementMoreEq },
404         { "contains",   FcElementContains },
405         { "not_contains",FcElementNotContains },
406         { "plus",       FcElementPlus },
407         { "minus",      FcElementMinus },
408         { "times",      FcElementTimes },
409         { "divide",     FcElementDivide },
410         { "not",        FcElementNot },
411         { "if",         FcElementIf },
412         { "floor",      FcElementFloor },
413         { "ceil",       FcElementCeil },
414         { "round",      FcElementRound },
415         { "trunc",      FcElementTrunc },
416         
417         { 0,            0 }
418     };
419
420     int     i;
421     for (i = 0; fcElementMap[i].name; i++)
422         if (!strcmp ((char *) name, fcElementMap[i].name))
423             return fcElementMap[i].element;
424     return FcElementUnknown;
425 }
426
427 typedef struct _FcPStack {
428     struct _FcPStack   *prev;
429     FcElement           element;
430     FcChar8             **attr;
431     FcStrBuf            str;
432 } FcPStack;
433     
434 typedef enum _FcVStackTag {
435     FcVStackNone,
436
437     FcVStackString,
438     FcVStackFamily,
439     FcVStackField,
440     FcVStackConstant,
441     FcVStackGlob,
442     
443     FcVStackPrefer,
444     FcVStackAccept,
445     FcVStackDefault,
446     
447     FcVStackInteger,
448     FcVStackDouble,
449     FcVStackMatrix,
450     FcVStackBool,
451     
452     FcVStackTest,
453     FcVStackExpr,
454     FcVStackEdit
455 } FcVStackTag;
456
457 typedef struct _FcVStack {
458     struct _FcVStack    *prev;
459     FcPStack            *pstack;        /* related parse element */
460     FcVStackTag         tag;
461     union {
462         FcChar8         *string;
463
464         int             integer;
465         double          _double;
466         FcMatrix        *matrix;
467         FcBool          bool;
468
469         FcTest          *test;
470         FcQual          qual;
471         FcOp            op;
472         FcExpr          *expr;
473         FcEdit          *edit;
474     } u;
475 } FcVStack;
476
477 typedef struct _FcConfigParse {
478     FcPStack        *pstack;
479     FcVStack        *vstack;
480     FcBool          error;
481     const FcChar8   *name;
482     FcConfig        *config;
483     XML_Parser      parser;
484 } FcConfigParse;
485
486 typedef enum _FcConfigSeverity {
487     FcSevereInfo, FcSevereWarning, FcSevereError
488 } FcConfigSeverity;
489
490 static void
491 FcConfigMessage (FcConfigParse *parse, FcConfigSeverity severe, char *fmt, ...)
492 {
493     char        *s = "unknown";
494     va_list     args;
495
496     va_start (args, fmt);
497
498     switch (severe) {
499     case FcSevereInfo: s = "info"; break;
500     case FcSevereWarning: s = "warning"; break;
501     case FcSevereError: s = "error"; break;
502     }
503     if (parse)
504     {
505         if (parse->name)
506             fprintf (stderr, "Fontconfig %s: \"%s\", line %d: ", s,
507                      parse->name, XML_GetCurrentLineNumber (parse->parser));
508         else
509             fprintf (stderr, "Fontconfig %s: line %d: ", s,
510                      XML_GetCurrentLineNumber (parse->parser));
511         if (severe >= FcSevereError)
512             parse->error = FcTrue;
513     }
514     else
515         fprintf (stderr, "Fontconfig %s: ", s);
516     vfprintf (stderr, fmt, args);
517     fprintf (stderr, "\n");
518     va_end (args);
519 }
520
521 static void
522 FcVStackPush (FcConfigParse *parse, FcVStack *vstack)
523 {
524     vstack->prev = parse->vstack;
525     vstack->pstack = parse->pstack ? parse->pstack->prev : 0;
526     parse->vstack = vstack;
527 }
528
529 static FcVStack *
530 FcVStackCreate (void)
531 {
532     FcVStack    *new;
533
534     new = malloc (sizeof (FcVStack));
535     if (!new)
536         return 0;
537     FcMemAlloc (FC_MEM_VSTACK, sizeof (FcVStack));
538     new->tag = FcVStackNone;
539     new->prev = 0;
540     return new;
541 }
542
543 static void
544 FcVStackDestroy (FcVStack *vstack)
545 {
546     FcVStack    *prev;
547
548     for (; vstack; vstack = prev)
549     {
550         prev = vstack->prev;
551         switch (vstack->tag) {
552         case FcVStackNone:
553             break;
554         case FcVStackString:
555         case FcVStackFamily:
556         case FcVStackField:
557         case FcVStackConstant:
558         case FcVStackGlob:
559             FcStrFree (vstack->u.string);
560             break;
561         case FcVStackInteger:
562         case FcVStackDouble:
563             break;
564         case FcVStackMatrix:
565             FcMatrixFree (vstack->u.matrix);
566             break;
567         case FcVStackBool:
568             break;
569         case FcVStackTest:
570             FcTestDestroy (vstack->u.test);
571             break;
572         case FcVStackExpr:
573         case FcVStackPrefer:
574         case FcVStackAccept:
575         case FcVStackDefault:
576             FcExprDestroy (vstack->u.expr);
577             break;
578         case FcVStackEdit:
579             FcEditDestroy (vstack->u.edit);
580             break;
581         }
582         FcMemFree (FC_MEM_VSTACK, sizeof (FcVStack));
583         free (vstack);
584     }
585 }
586
587 static FcBool
588 FcVStackPushString (FcConfigParse *parse, FcVStackTag tag, FcChar8 *string)
589 {
590     FcVStack    *vstack = FcVStackCreate ();
591     if (!vstack)
592         return FcFalse;
593     vstack->u.string = string;
594     vstack->tag = tag;
595     FcVStackPush (parse, vstack);
596     return FcTrue;
597 }
598
599 static FcBool
600 FcVStackPushInteger (FcConfigParse *parse, int integer)
601 {
602     FcVStack    *vstack = FcVStackCreate ();
603     if (!vstack)
604         return FcFalse;
605     vstack->u.integer = integer;
606     vstack->tag = FcVStackInteger;
607     FcVStackPush (parse, vstack);
608     return FcTrue;
609 }
610
611 static FcBool
612 FcVStackPushDouble (FcConfigParse *parse, double _double)
613 {
614     FcVStack    *vstack = FcVStackCreate ();
615     if (!vstack)
616         return FcFalse;
617     vstack->u._double = _double;
618     vstack->tag = FcVStackDouble;
619     FcVStackPush (parse, vstack);
620     return FcTrue;
621 }
622
623 static FcBool
624 FcVStackPushMatrix (FcConfigParse *parse, FcMatrix *matrix)
625 {
626     FcVStack    *vstack = FcVStackCreate ();
627     if (!vstack)
628         return FcFalse;
629     matrix = FcMatrixCopy (matrix);
630     if (!matrix)
631     {
632         FcVStackDestroy (vstack);
633         return FcFalse;
634     }
635     vstack->u.matrix = matrix;
636     vstack->tag = FcVStackMatrix;
637     FcVStackPush (parse, vstack);
638     return FcTrue;
639 }
640
641 static FcBool
642 FcVStackPushBool (FcConfigParse *parse, FcBool bool)
643 {
644     FcVStack    *vstack = FcVStackCreate ();
645     if (!vstack)
646         return FcFalse;
647     vstack->u.bool = bool;
648     vstack->tag = FcVStackBool;
649     FcVStackPush (parse, vstack);
650     return FcTrue;
651 }
652
653 static FcBool
654 FcVStackPushTest (FcConfigParse *parse, FcTest *test)
655 {
656     FcVStack    *vstack = FcVStackCreate ();
657     if (!vstack)
658         return FcFalse;
659     vstack->u.test = test;
660     vstack->tag = FcVStackTest;
661     FcVStackPush (parse, vstack);
662     return FcTrue;
663 }
664
665 static FcBool
666 FcVStackPushExpr (FcConfigParse *parse, FcVStackTag tag, FcExpr *expr)
667 {
668     FcVStack    *vstack = FcVStackCreate ();
669     if (!vstack)
670         return FcFalse;
671     vstack->u.expr = expr;
672     vstack->tag = tag;
673     FcVStackPush (parse, vstack);
674     return FcTrue;
675 }
676
677 static FcBool
678 FcVStackPushEdit (FcConfigParse *parse, FcEdit *edit)
679 {
680     FcVStack    *vstack = FcVStackCreate ();
681     if (!vstack)
682         return FcFalse;
683     vstack->u.edit = edit;
684     vstack->tag = FcVStackEdit;
685     FcVStackPush (parse, vstack);
686     return FcTrue;
687 }
688
689 static FcVStack *
690 FcVStackFetch (FcConfigParse *parse, int off)
691 {
692     FcVStack    *vstack;
693
694     for (vstack = parse->vstack; vstack && off-- > 0; vstack = vstack->prev);
695     return vstack;
696 }
697
698 static void
699 FcVStackClear (FcConfigParse *parse)
700 {
701     while (parse->vstack && parse->vstack->pstack == parse->pstack)
702     {
703         FcVStack    *vstack = parse->vstack;
704         parse->vstack = vstack->prev;
705         vstack->prev = 0;
706         FcVStackDestroy (vstack);
707     }
708 }
709
710 static FcVStack *
711 FcVStackPop (FcConfigParse *parse)
712 {
713     FcVStack    *vstack = parse->vstack;
714     
715     if (!vstack || vstack->pstack != parse->pstack)
716         return 0;
717     parse->vstack = vstack->prev;
718     vstack->prev = 0;
719     return vstack;
720 }
721
722 static int
723 FcVStackElements (FcConfigParse *parse)
724 {
725     int         h = 0;
726     FcVStack    *vstack = parse->vstack;
727     while (vstack && vstack->pstack == parse->pstack)
728     {
729         h++;
730         vstack = vstack->prev;
731     }
732     return h;
733 }
734
735 static FcChar8 **
736 FcConfigSaveAttr (const XML_Char **attr)
737 {
738     int         n;
739     int         slen;
740     int         i;
741     FcChar8     **new;
742     FcChar8     *s;
743
744     if (!attr)
745         return 0;
746     slen = 0;
747     for (i = 0; attr[i]; i++)
748         slen += strlen (attr[i]) + 1;
749     n = i;
750     new = malloc ((i + 1) * sizeof (FcChar8 *) + slen);
751     if (!new)
752         return 0;
753     FcMemAlloc (FC_MEM_ATTR, 1);    /* size is too expensive */
754     s = (FcChar8 *) (new + (i + 1));
755     for (i = 0; attr[i]; i++)
756     {
757         new[i] = s;
758         strcpy ((char *) s, (char *) attr[i]);
759         s += strlen ((char *) s) + 1;
760     }
761     new[i] = 0;
762     return new;
763 }
764
765 static FcBool
766 FcPStackPush (FcConfigParse *parse, FcElement element, const XML_Char **attr)
767 {
768     FcPStack   *new = malloc (sizeof (FcPStack));
769
770     if (!new)
771         return FcFalse;
772     FcMemAlloc (FC_MEM_PSTACK, sizeof (FcPStack));
773     new->prev = parse->pstack;
774     new->element = element;
775     if (attr)
776     {
777         new->attr = FcConfigSaveAttr (attr);
778         if (!new->attr)
779             FcConfigMessage (parse, FcSevereError, "out of memory");
780     }
781     else
782         new->attr = 0;
783     FcStrBufInit (&new->str, 0, 0);
784     parse->pstack = new;
785     return FcTrue;
786 }
787
788 static FcBool
789 FcPStackPop (FcConfigParse *parse)
790 {
791     FcPStack   *old;
792     
793     if (!parse->pstack) 
794     {
795         FcConfigMessage (parse, FcSevereError, "mismatching element");
796         return FcFalse;
797     }
798     FcVStackClear (parse);
799     old = parse->pstack;
800     parse->pstack = old->prev;
801     FcStrBufDestroy (&old->str);
802     if (old->attr)
803     {
804         FcMemFree (FC_MEM_ATTR, 1); /* size is to expensive */
805         free (old->attr);
806     }
807     FcMemFree (FC_MEM_PSTACK, sizeof (FcPStack));
808     free (old);
809     return FcTrue;
810 }
811
812 static FcBool
813 FcConfigInit (FcConfigParse *parse, const FcChar8 *name, FcConfig *config, XML_Parser parser)
814 {
815     parse->pstack = 0;
816     parse->vstack = 0;
817     parse->error = FcFalse;
818     parse->name = name;
819     parse->config = config;
820     parse->parser = parser;
821     return FcTrue;
822 }
823
824 static void
825 FcConfigCleanup (FcConfigParse  *parse)
826 {
827     while (parse->pstack)
828         FcPStackPop (parse);
829 }
830
831 static const FcChar8 *
832 FcConfigGetAttribute (FcConfigParse *parse, char *attr)
833 {
834     FcChar8 **attrs;
835     if (!parse->pstack)
836         return 0;
837
838     attrs = parse->pstack->attr;
839     while (*attrs)
840     {
841         if (!strcmp ((char *) *attrs, attr))
842             return attrs[1];
843         attrs += 2;
844     }
845     return 0;
846 }
847
848 static void
849 FcStartElement(void *userData, const XML_Char *name, const XML_Char **attr)
850 {
851     FcConfigParse   *parse = userData;
852     FcElement       element;
853     
854     element = FcElementMap (name);
855     if (element == FcElementUnknown)
856         FcConfigMessage (parse, FcSevereWarning, "unknown element \"%s\"", name);
857     
858     if (!FcPStackPush (parse, element, attr))
859     {
860         FcConfigMessage (parse, FcSevereError, "out of memory");
861         return;
862     }
863     return;
864 }
865
866 static void
867 FcParseBlank (FcConfigParse *parse)
868 {
869     int     n = FcVStackElements (parse);
870     while (n-- > 0)
871     {
872         FcVStack    *v = FcVStackFetch (parse, n);
873         if (v->tag != FcVStackInteger)
874             FcConfigMessage (parse, FcSevereError, "non-integer blank");
875         else
876         {
877             if (!parse->config->blanks)
878             {
879                 parse->config->blanks = FcBlanksCreate ();
880                 if (!parse->config->blanks)
881                 {
882                     FcConfigMessage (parse, FcSevereError, "out of memory");
883                     break;
884                 }
885             }
886             if (!FcBlanksAdd (parse->config->blanks, v->u.integer))
887             {
888                 FcConfigMessage (parse, FcSevereError, "out of memory");
889                 break;
890             }
891         }
892     }
893 }
894
895 static void
896 FcParseRescan (FcConfigParse *parse)
897 {
898     int     n = FcVStackElements (parse);
899     while (n-- > 0)
900     {
901         FcVStack    *v = FcVStackFetch (parse, n);
902         if (v->tag != FcVStackInteger)
903             FcConfigMessage (parse, FcSevereWarning, "non-integer rescan");
904         else
905             parse->config->rescanInterval = v->u.integer;
906     }
907 }
908
909 static void
910 FcParseInt (FcConfigParse *parse)
911 {
912     FcChar8 *s, *end;
913     int     l;
914     
915     if (!parse->pstack)
916         return;
917     s = FcStrBufDone (&parse->pstack->str);
918     if (!s)
919     {
920         FcConfigMessage (parse, FcSevereError, "out of memory");
921         return;
922     }
923     end = 0;
924     l = (int) strtol ((char *) s, (char **)&end, 0);
925     if (end != s + strlen ((char *) s))
926         FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid integer", s);
927     else
928         FcVStackPushInteger (parse, l);
929     FcStrFree (s);
930 }
931
932 /*
933  * idea copied from glib g_ascii_strtod with 
934  * permission of the author (Alexander Larsson) 
935  */
936
937 #include <locale.h>
938
939 static double 
940 FcStrtod (char *s, char **end)
941 {
942     struct lconv    *locale_data;
943     char            *dot;
944     double          v;
945
946     /*
947      * Have to swap the decimal point to match the current locale
948      * if that locale doesn't use 0x2e
949      */
950     if ((dot = strchr (s, 0x2e)) &&
951         (locale_data = localeconv ()) &&
952         (locale_data->decimal_point[0] != 0x2e ||
953          locale_data->decimal_point[1] != 0))
954     {
955         char    buf[128];
956         int     slen = strlen (s);
957         int     dlen = strlen (locale_data->decimal_point);
958         
959         if (slen + dlen > sizeof (buf))
960         {
961             if (end)
962                 *end = s;
963             v = 0;
964         }
965         else
966         {
967             char        *buf_end;
968             /* mantissa */
969             strncpy (buf, s, dot - s);
970             /* decimal point */
971             strcpy (buf + (dot - s), locale_data->decimal_point);
972             /* rest of number */
973             strcpy (buf + (dot - s) + dlen, dot + 1);
974             buf_end = 0;
975             v = strtod (buf, &buf_end);
976             if (buf_end)
977                 buf_end = s + (buf_end - buf) + 1 - dlen;
978             if (end)
979                 *end = buf_end;
980         }
981     }
982     else
983         v = strtod (s, end);
984     return v;
985 }
986
987 static void
988 FcParseDouble (FcConfigParse *parse)
989 {
990     FcChar8 *s, *end;
991     double  d;
992     
993     if (!parse->pstack)
994         return;
995     s = FcStrBufDone (&parse->pstack->str);
996     if (!s)
997     {
998         FcConfigMessage (parse, FcSevereError, "out of memory");
999         return;
1000     }
1001     end = 0;
1002     d = FcStrtod ((char *) s, (char **)&end);
1003     if (end != s + strlen ((char *) s))
1004         FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid double", s);
1005     else
1006         FcVStackPushDouble (parse, d);
1007     FcStrFree (s);
1008 }
1009
1010 static void
1011 FcParseString (FcConfigParse *parse, FcVStackTag tag)
1012 {
1013     FcChar8 *s;
1014     
1015     if (!parse->pstack)
1016         return;
1017     s = FcStrBufDone (&parse->pstack->str);
1018     if (!s)
1019     {
1020         FcConfigMessage (parse, FcSevereError, "out of memory");
1021         return;
1022     }
1023     if (!FcVStackPushString (parse, tag, s))
1024         FcStrFree (s);
1025 }
1026
1027 static void
1028 FcParseMatrix (FcConfigParse *parse)
1029 {
1030     FcVStack    *vstack;
1031     enum { m_done, m_xx, m_xy, m_yx, m_yy } matrix_state = m_yy;
1032     FcMatrix    m;
1033     
1034     while ((vstack = FcVStackPop (parse)))
1035     {
1036         double  v;
1037         switch (vstack->tag) {
1038         case FcVStackInteger:
1039             v = vstack->u.integer;
1040             break;
1041         case FcVStackDouble:
1042             v = vstack->u._double;
1043             break;
1044         default:
1045             FcConfigMessage (parse, FcSevereError, "non-double matrix element");
1046             v = 1.0;
1047             break;
1048         }
1049         switch (matrix_state) {
1050         case m_xx: m.xx = v; break;
1051         case m_xy: m.xy = v; break;
1052         case m_yx: m.yx = v; break;
1053         case m_yy: m.yy = v; break;
1054         default: break;
1055         }
1056         FcVStackDestroy (vstack);
1057         matrix_state--;
1058     }
1059     if (matrix_state != m_done)
1060         FcConfigMessage (parse, FcSevereError, "wrong number of matrix elements");
1061     else
1062         FcVStackPushMatrix (parse, &m);
1063 }
1064
1065 static FcBool
1066 FcConfigLexBool (const FcChar8 *bool)
1067 {
1068     if (*bool == 't' || *bool == 'T')
1069         return FcTrue;
1070     if (*bool == 'y' || *bool == 'Y')
1071         return FcTrue;
1072     if (*bool == '1')
1073         return FcTrue;
1074     return FcFalse;
1075 }
1076
1077 static void
1078 FcParseBool (FcConfigParse *parse)
1079 {
1080     FcChar8 *s;
1081
1082     if (!parse->pstack)
1083         return;
1084     s = FcStrBufDone (&parse->pstack->str);
1085     if (!s)
1086     {
1087         FcConfigMessage (parse, FcSevereError, "out of memory");
1088         return;
1089     }
1090     FcVStackPushBool (parse, FcConfigLexBool (s));
1091     FcStrFree (s);
1092 }
1093
1094 static void
1095 FcParseFamilies (FcConfigParse *parse, FcVStackTag tag)
1096 {
1097     FcVStack    *vstack;
1098     FcExpr      *left, *expr = 0, *new;
1099
1100     while ((vstack = FcVStackPop (parse)))
1101     {
1102         if (vstack->tag != FcVStackFamily)
1103         {
1104             FcConfigMessage (parse, FcSevereWarning, "non-family");
1105             FcVStackDestroy (vstack);
1106             continue;
1107         }
1108         left = vstack->u.expr;
1109         vstack->tag = FcVStackNone;
1110         FcVStackDestroy (vstack);
1111         if (expr)
1112         {
1113             new = FcExprCreateOp (left, FcOpComma, expr);
1114             if (!new)
1115             {
1116                 FcConfigMessage (parse, FcSevereError, "out of memory");
1117                 FcExprDestroy (left);
1118                 FcExprDestroy (expr);
1119                 break;
1120             }
1121             expr = new;
1122         }
1123         else
1124             expr = left;
1125     }
1126     if (expr)
1127     {
1128         if (!FcVStackPushExpr (parse, tag, expr))
1129         {
1130             FcConfigMessage (parse, FcSevereError, "out of memory");
1131             if (expr)
1132                 FcExprDestroy (expr);
1133         }
1134     }
1135 }
1136
1137 static void
1138 FcParseFamily (FcConfigParse *parse)
1139 {
1140     FcChar8 *s;
1141     FcExpr  *expr;
1142
1143     if (!parse->pstack)
1144         return;
1145     s = FcStrBufDone (&parse->pstack->str);
1146     if (!s)
1147     {
1148         FcConfigMessage (parse, FcSevereError, "out of memory");
1149         return;
1150     }
1151     expr = FcExprCreateString (s);
1152     FcStrFree (s);
1153     if (expr)
1154         FcVStackPushExpr (parse, FcVStackFamily, expr);
1155 }
1156
1157 static void
1158 FcParseAlias (FcConfigParse *parse)
1159 {
1160     FcExpr      *family = 0, *accept = 0, *prefer = 0, *def = 0, *new = 0;
1161     FcEdit      *edit = 0, *next;
1162     FcVStack    *vstack;
1163     FcTest      *test;
1164
1165     while ((vstack = FcVStackPop (parse))) 
1166     {
1167         switch (vstack->tag) {
1168         case FcVStackFamily:
1169             if (family)
1170             {
1171                 new = FcExprCreateOp (vstack->u.expr, FcOpComma, family);
1172                 if (!new)
1173                     FcConfigMessage (parse, FcSevereError, "out of memory");
1174                 else
1175                     family = new;
1176             }
1177             else
1178                 new = vstack->u.expr;
1179             if (new)
1180             {
1181                 family = new;
1182                 vstack->tag = FcVStackNone;
1183             }
1184             break;
1185         case FcVStackPrefer:
1186             if (prefer)
1187                 FcExprDestroy (prefer);
1188             prefer = vstack->u.expr;
1189             vstack->tag = FcVStackNone;
1190             break;
1191         case FcVStackAccept:
1192             if (accept)
1193                 FcExprDestroy (accept);
1194             accept = vstack->u.expr;
1195             vstack->tag = FcVStackNone;
1196             break;
1197         case FcVStackDefault:
1198             if (def)
1199                 FcExprDestroy (def);
1200             def = vstack->u.expr;
1201             vstack->tag = FcVStackNone;
1202             break;
1203         default:
1204             FcConfigMessage (parse, FcSevereWarning, "bad alias");
1205             break;
1206         }
1207         FcVStackDestroy (vstack);
1208     }
1209     if (!family)
1210     {
1211         FcConfigMessage (parse, FcSevereError, "missing family in alias");
1212         if (prefer)
1213             FcExprDestroy (prefer);
1214         if (accept)
1215             FcExprDestroy (accept);
1216         if (def)
1217             FcExprDestroy (def);
1218         return;
1219     }
1220     if (prefer)
1221     {
1222         edit = FcEditCreate (FcConfigSaveField ("family"),
1223                              FcOpPrepend,
1224                              prefer,
1225                              FcValueBindingWeak);
1226         if (edit)
1227             edit->next = 0;
1228         else
1229             FcExprDestroy (prefer);
1230     }
1231     if (accept)
1232     {
1233         next = edit;
1234         edit = FcEditCreate (FcConfigSaveField ("family"),
1235                              FcOpAppend,
1236                              accept,
1237                              FcValueBindingWeak);
1238         if (edit)
1239             edit->next = next;
1240         else
1241             FcExprDestroy (accept);
1242     }
1243     if (def)
1244     {
1245         next = edit;
1246         edit = FcEditCreate (FcConfigSaveField ("family"),
1247                              FcOpAppendLast,
1248                              def,
1249                              FcValueBindingWeak);
1250         if (edit)
1251             edit->next = next;
1252         else
1253             FcExprDestroy (def);
1254     }
1255     if (edit)
1256     {
1257         test = FcTestCreate (FcMatchPattern,
1258                              FcQualAny,
1259                              (FcChar8 *) FC_FAMILY,
1260                              FcOpEqual,
1261                              family);
1262         if (test)
1263             if (!FcConfigAddEdit (parse->config, test, edit, FcMatchPattern))
1264                 FcTestDestroy (test);
1265     }
1266     else
1267         FcExprDestroy (family);
1268 }
1269
1270 static FcExpr *
1271 FcPopExpr (FcConfigParse *parse)
1272 {
1273     FcVStack    *vstack = FcVStackPop (parse);
1274     FcExpr      *expr = 0;
1275     if (!vstack)
1276         return 0;
1277     switch (vstack->tag) {
1278     case FcVStackNone:
1279         break;
1280     case FcVStackString:
1281     case FcVStackFamily:
1282         expr = FcExprCreateString (vstack->u.string);
1283         break;
1284     case FcVStackField:
1285         expr = FcExprCreateField ((char *) vstack->u.string);
1286         break;
1287     case FcVStackConstant:
1288         expr = FcExprCreateConst (vstack->u.string);
1289         break;
1290     case FcVStackPrefer:
1291     case FcVStackAccept:
1292     case FcVStackDefault:
1293         expr = vstack->u.expr;
1294         vstack->tag = FcVStackNone;
1295         break;
1296     case FcVStackInteger:
1297         expr = FcExprCreateInteger (vstack->u.integer);
1298         break;
1299     case FcVStackDouble:
1300         expr = FcExprCreateDouble (vstack->u._double);
1301         break;
1302     case FcVStackMatrix:
1303         expr = FcExprCreateMatrix (vstack->u.matrix);
1304         break;
1305     case FcVStackBool:
1306         expr = FcExprCreateBool (vstack->u.bool);
1307         break;
1308     case FcVStackTest:
1309         break;
1310     case FcVStackExpr:
1311         expr = vstack->u.expr;
1312         vstack->tag = FcVStackNone;
1313         break;
1314     case FcVStackEdit:
1315         break;
1316     }
1317     FcVStackDestroy (vstack);
1318     return expr;
1319 }
1320
1321 /*
1322  * This builds a tree of binary operations.  Note
1323  * that every operator is defined so that if only
1324  * a single operand is contained, the value of the
1325  * whole expression is the value of the operand.
1326  *
1327  * This code reduces in that case to returning that
1328  * operand.
1329  */
1330 static FcExpr *
1331 FcPopBinary (FcConfigParse *parse, FcOp op)
1332 {
1333     FcExpr  *left, *expr = 0, *new;
1334
1335     while ((left = FcPopExpr (parse)))
1336     {
1337         if (expr)
1338         {
1339             new = FcExprCreateOp (left, op, expr);
1340             if (!new)
1341             {
1342                 FcConfigMessage (parse, FcSevereError, "out of memory");
1343                 FcExprDestroy (left);
1344                 FcExprDestroy (expr);
1345                 break;
1346             }
1347             expr = new;
1348         }
1349         else
1350             expr = left;
1351     }
1352     return expr;
1353 }
1354
1355 static void
1356 FcParseBinary (FcConfigParse *parse, FcOp op)
1357 {
1358     FcExpr  *expr = FcPopBinary (parse, op);
1359     if (expr)
1360         FcVStackPushExpr (parse, FcVStackExpr, expr);
1361 }
1362
1363 /*
1364  * This builds a a unary operator, it consumes only
1365  * a single operand
1366  */
1367
1368 static FcExpr *
1369 FcPopUnary (FcConfigParse *parse, FcOp op)
1370 {
1371     FcExpr  *operand, *new = 0;
1372
1373     if ((operand = FcPopExpr (parse)))
1374     {
1375         new = FcExprCreateOp (operand, op, 0);
1376         if (!new)
1377         {
1378             FcExprDestroy (operand);
1379             FcConfigMessage (parse, FcSevereError, "out of memory");
1380         }
1381     }
1382     return new;
1383 }
1384
1385 static void
1386 FcParseUnary (FcConfigParse *parse, FcOp op)
1387 {
1388     FcExpr  *expr = FcPopUnary (parse, op);
1389     if (expr)
1390         FcVStackPushExpr (parse, FcVStackExpr, expr);
1391 }
1392
1393 static void
1394 FcParseInclude (FcConfigParse *parse)
1395 {
1396     FcChar8         *s;
1397     const FcChar8   *i;
1398     FcBool          ignore_missing = FcFalse;
1399     
1400     s = FcStrBufDone (&parse->pstack->str);
1401     if (!s)
1402     {
1403         FcConfigMessage (parse, FcSevereError, "out of memory");
1404         return;
1405     }
1406     i = FcConfigGetAttribute (parse, "ignore_missing");
1407     if (i && FcConfigLexBool ((FcChar8 *) i) == FcTrue)
1408         ignore_missing = FcTrue;
1409     if (!FcConfigParseAndLoad (parse->config, s, !ignore_missing))
1410         parse->error = FcTrue;
1411     FcStrFree (s);
1412 }
1413
1414 typedef struct _FcOpMap {
1415     char    *name;
1416     FcOp    op;
1417 } FcOpMap;
1418
1419 static FcOp
1420 FcConfigLexOp (const FcChar8 *op, const FcOpMap *map, int nmap)
1421 {
1422     int i;
1423
1424     for (i = 0; i < nmap; i++)
1425         if (!strcmp ((char *) op, map[i].name)) 
1426             return map[i].op;
1427     return FcOpInvalid;
1428 }
1429
1430 static const FcOpMap fcCompareOps[] = {
1431     { "eq",             FcOpEqual           },
1432     { "not_eq",         FcOpNotEqual        },
1433     { "less",           FcOpLess            },
1434     { "less_eq",        FcOpLessEqual       },
1435     { "more",           FcOpMore            },
1436     { "more_eq",        FcOpMoreEqual       },
1437     { "contains",       FcOpContains        },
1438     { "not_contains",   FcOpNotContains     }
1439 };
1440
1441 #define NUM_COMPARE_OPS (sizeof fcCompareOps / sizeof fcCompareOps[0])
1442
1443 static FcOp
1444 FcConfigLexCompare (const FcChar8 *compare)
1445 {
1446     return FcConfigLexOp (compare, fcCompareOps, NUM_COMPARE_OPS);
1447 }
1448
1449
1450 static void
1451 FcParseTest (FcConfigParse *parse)
1452 {
1453     const FcChar8   *kind_string;
1454     FcMatchKind     kind;
1455     const FcChar8   *qual_string;
1456     FcQual          qual;
1457     const FcChar8   *name;
1458     const FcChar8   *compare_string;
1459     FcOp            compare;
1460     FcExpr          *expr;
1461     FcTest          *test;
1462
1463     kind_string = FcConfigGetAttribute (parse, "target");
1464     if (!kind_string)
1465         kind = FcMatchDefault;
1466     else
1467     {
1468         if (!strcmp ((char *) kind_string, "pattern"))
1469             kind = FcMatchPattern;
1470         else if (!strcmp ((char *) kind_string, "font"))
1471             kind = FcMatchFont;
1472         else if (!strcmp ((char *) kind_string, "default"))
1473             kind = FcMatchDefault;
1474         else
1475         {
1476             FcConfigMessage (parse, FcSevereWarning, "invalid test target \"%s\"", kind_string);
1477             return;
1478         }
1479     }
1480     qual_string = FcConfigGetAttribute (parse, "qual");
1481     if (!qual_string)
1482         qual = FcQualAny;
1483     else
1484     {
1485         if (!strcmp ((char *) qual_string, "any"))
1486             qual = FcQualAny;
1487         else if (!strcmp ((char *) qual_string, "all"))
1488             qual = FcQualAll;
1489         else if (!strcmp ((char *) qual_string, "first"))
1490             qual = FcQualFirst;
1491         else if (!strcmp ((char *) qual_string, "not_first"))
1492             qual = FcQualNotFirst;
1493         else
1494         {
1495             FcConfigMessage (parse, FcSevereWarning, "invalid test qual \"%s\"", qual_string);
1496             return;
1497         }
1498     }
1499     name = FcConfigGetAttribute (parse, "name");
1500     if (!name)
1501     {
1502         FcConfigMessage (parse, FcSevereWarning, "missing test name");
1503         return;
1504     }
1505     compare_string = FcConfigGetAttribute (parse, "compare");
1506     if (!compare_string)
1507         compare = FcOpEqual;
1508     else
1509     {
1510         compare = FcConfigLexCompare (compare_string);
1511         if (compare == FcOpInvalid)
1512         {
1513             FcConfigMessage (parse, FcSevereWarning, "invalid test compare \"%s\"", compare_string);
1514             return;
1515         }
1516     }
1517     expr = FcPopBinary (parse, FcOpComma);
1518     if (!expr)
1519     {
1520         FcConfigMessage (parse, FcSevereWarning, "missing test expression");
1521         return;
1522     }
1523     test = FcTestCreate (kind, qual, name, compare, expr);
1524     if (!test)
1525     {
1526         FcConfigMessage (parse, FcSevereError, "out of memory");
1527         return;
1528     }
1529     FcVStackPushTest (parse, test);
1530 }
1531
1532 static const FcOpMap fcModeOps[] = {
1533     { "assign",         FcOpAssign          },
1534     { "assign_replace", FcOpAssignReplace   },
1535     { "prepend",        FcOpPrepend         },
1536     { "prepend_first",  FcOpPrependFirst    },
1537     { "append",         FcOpAppend          },
1538     { "append_last",    FcOpAppendLast      },
1539 };
1540
1541 #define NUM_MODE_OPS (sizeof fcModeOps / sizeof fcModeOps[0])
1542
1543 static FcOp
1544 FcConfigLexMode (const FcChar8 *mode)
1545 {
1546     return FcConfigLexOp (mode, fcModeOps, NUM_MODE_OPS);
1547 }
1548
1549 static void
1550 FcParseEdit (FcConfigParse *parse)
1551 {
1552     const FcChar8   *name;
1553     const FcChar8   *mode_string;
1554     const FcChar8   *binding_string;
1555     FcOp            mode;
1556     FcValueBinding  binding;
1557     FcExpr          *expr;
1558     FcEdit          *edit;
1559
1560     name = FcConfigGetAttribute (parse, "name");
1561     if (!name)
1562     {
1563         FcConfigMessage (parse, FcSevereWarning, "missing edit name");
1564         return;
1565     }
1566     mode_string = FcConfigGetAttribute (parse, "mode");
1567     if (!mode_string)
1568         mode = FcOpAssign;
1569     else
1570     {
1571         mode = FcConfigLexMode (mode_string);
1572         if (mode == FcOpInvalid)
1573         {
1574             FcConfigMessage (parse, FcSevereWarning, "invalid edit mode \"%s\"", mode_string);
1575             return;
1576         }
1577     }
1578     binding_string = FcConfigGetAttribute (parse, "binding");
1579     if (!binding_string)
1580         binding = FcValueBindingWeak;
1581     else
1582     {
1583         if (!strcmp ((char *) binding_string, "weak"))
1584             binding = FcValueBindingWeak;
1585         else if (!strcmp ((char *) binding_string, "strong"))
1586             binding = FcValueBindingStrong;
1587         else if (!strcmp ((char *) binding_string, "same"))
1588             binding = FcValueBindingSame;
1589         else
1590         {
1591             FcConfigMessage (parse, FcSevereWarning, "invalid edit binding \"%s\"", binding_string);
1592             return;
1593         }
1594     }
1595     expr = FcPopBinary (parse, FcOpComma);
1596     edit = FcEditCreate ((char *) FcStrCopy (name), mode, expr, binding);
1597     if (!edit)
1598     {
1599         FcConfigMessage (parse, FcSevereError, "out of memory");
1600         FcExprDestroy (expr);
1601         return;
1602     }
1603     if (!FcVStackPushEdit (parse, edit))
1604         FcEditDestroy (edit);
1605 }
1606
1607 static void
1608 FcParseMatch (FcConfigParse *parse)
1609 {
1610     const FcChar8   *kind_name;
1611     FcMatchKind     kind;
1612     FcTest          *test = 0;
1613     FcEdit          *edit = 0;
1614     FcVStack        *vstack;
1615
1616     kind_name = FcConfigGetAttribute (parse, "target");
1617     if (!kind_name)
1618         kind = FcMatchPattern;
1619     else
1620     {
1621         if (!strcmp ((char *) kind_name, "pattern"))
1622             kind = FcMatchPattern;
1623         else if (!strcmp ((char *) kind_name, "font"))
1624             kind = FcMatchFont;
1625         else
1626         {
1627             FcConfigMessage (parse, FcSevereWarning, "invalid match target \"%s\"", kind_name);
1628             return;
1629         }
1630     }
1631     while ((vstack = FcVStackPop (parse)))
1632     {
1633         switch (vstack->tag) {
1634         case FcVStackTest:
1635             vstack->u.test->next = test;
1636             test = vstack->u.test;
1637             vstack->tag = FcVStackNone;
1638             break;
1639         case FcVStackEdit:
1640             vstack->u.edit->next = edit;
1641             edit = vstack->u.edit;
1642             vstack->tag = FcVStackNone;
1643             break;
1644         default:
1645             FcConfigMessage (parse, FcSevereWarning, "invalid match element");
1646             break;
1647         }
1648         FcVStackDestroy (vstack);
1649     }
1650     if (!FcConfigAddEdit (parse->config, test, edit, kind))
1651         FcConfigMessage (parse, FcSevereError, "out of memory");
1652 }
1653
1654 static void
1655 FcParseAcceptRejectFont (FcConfigParse *parse, FcElement element)
1656 {
1657     FcVStack    *vstack;
1658
1659     while ((vstack = FcVStackPop (parse)))
1660     {
1661         switch (vstack->tag) {
1662         case FcVStackGlob:
1663             if (!FcConfigGlobAdd (parse->config, 
1664                                   vstack->u.string,
1665                                   element == FcElementAcceptfont))
1666             {
1667                 FcConfigMessage (parse, FcSevereError, "out of memory");
1668             }
1669             break;
1670         default:
1671             FcConfigMessage (parse, FcSevereWarning, "bad font selector");
1672             break;
1673         }
1674         FcVStackDestroy (vstack);
1675     }
1676 }
1677
1678 static void
1679 FcEndElement(void *userData, const XML_Char *name)
1680 {
1681     FcConfigParse   *parse = userData;
1682     FcChar8         *data;
1683     
1684     if (!parse->pstack)
1685         return;
1686     switch (parse->pstack->element) {
1687     case FcElementNone:
1688         break;
1689     case FcElementFontconfig:
1690         break;
1691     case FcElementDir:
1692         data = FcStrBufDone (&parse->pstack->str);
1693         if (!data)
1694         {
1695             FcConfigMessage (parse, FcSevereError, "out of memory");
1696             break;
1697         }
1698 #ifdef _WIN32
1699         if (strcmp (data, "WINDOWSFONTDIR") == 0)
1700         {
1701             int rc;
1702             FcStrFree (data);
1703             data = malloc (1000);
1704             if (!data)
1705             {
1706                 FcConfigMessage (parse, FcSevereError, "out of memory");
1707                 break;
1708             }
1709             FcMemAlloc (FC_MEM_STRING, 1000);
1710             rc = GetWindowsDirectory (data, 800);
1711             if (rc == 0 || rc > 800)
1712             {
1713                 FcConfigMessage (parse, FcSevereError, "GetWindowsDirectory failed");
1714                 FcStrFree (data);
1715                 break;
1716             }
1717             if (data [strlen (data) - 1] != '\\')
1718                 strcat (data, "\\");
1719             strcat (data, "fonts");
1720         }
1721 #endif
1722         if (!FcStrUsesHome (data) || FcConfigHome ())
1723         {
1724             if (!FcConfigAddDir (parse->config, data))
1725                 FcConfigMessage (parse, FcSevereError, "out of memory");
1726         }
1727         FcStrFree (data);
1728         break;
1729     case FcElementCache:
1730         data = FcStrBufDone (&parse->pstack->str);
1731         if (!data)
1732         {
1733             FcConfigMessage (parse, FcSevereError, "out of memory");
1734             break;
1735         }
1736         if (!FcStrUsesHome (data) || FcConfigHome ())
1737         {
1738             if (!FcConfigSetCache (parse->config, data))
1739                 FcConfigMessage (parse, FcSevereError, "out of memory");
1740         }
1741         FcStrFree (data);
1742         break;
1743     case FcElementInclude:
1744         FcParseInclude (parse);
1745         break;
1746     case FcElementConfig:
1747         break;
1748     case FcElementMatch:
1749         FcParseMatch (parse);
1750         break;
1751     case FcElementAlias:
1752         FcParseAlias (parse);
1753         break;
1754
1755     case FcElementBlank:
1756         FcParseBlank (parse);
1757         break;
1758     case FcElementRescan:
1759         FcParseRescan (parse);
1760         break;
1761         
1762     case FcElementPrefer:
1763         FcParseFamilies (parse, FcVStackPrefer);
1764         break;
1765     case FcElementAccept:
1766         FcParseFamilies (parse, FcVStackAccept);
1767         break;
1768     case FcElementDefault:
1769         FcParseFamilies (parse, FcVStackDefault);
1770         break;
1771     case FcElementFamily:
1772         FcParseFamily (parse);
1773         break;
1774
1775     case FcElementTest:
1776         FcParseTest (parse);
1777         break;
1778     case FcElementEdit:
1779         FcParseEdit (parse);
1780         break;
1781
1782     case FcElementInt:
1783         FcParseInt (parse);
1784         break;
1785     case FcElementDouble:
1786         FcParseDouble (parse);
1787         break;
1788     case FcElementString:
1789         FcParseString (parse, FcVStackString);
1790         break;
1791     case FcElementMatrix:
1792         FcParseMatrix (parse);
1793         break;
1794     case FcElementBool:
1795         FcParseBool (parse);
1796         break;
1797     case FcElementCharset:
1798 /*      FcParseCharset (parse); */
1799         break;
1800     case FcElementSelectfont:
1801         break;
1802     case FcElementAcceptfont:
1803     case FcElementRejectfont:
1804         FcParseAcceptRejectFont (parse, parse->pstack->element);
1805         break;
1806     case FcElementGlob:
1807         FcParseString (parse, FcVStackGlob);
1808         break;
1809     case FcElementName:
1810         FcParseString (parse, FcVStackField);
1811         break;
1812     case FcElementConst:
1813         FcParseString (parse, FcVStackConstant);
1814         break;
1815     case FcElementOr:
1816         FcParseBinary (parse, FcOpOr);
1817         break;
1818     case FcElementAnd:
1819         FcParseBinary (parse, FcOpAnd);
1820         break;
1821     case FcElementEq:
1822         FcParseBinary (parse, FcOpEqual);
1823         break;
1824     case FcElementNotEq:
1825         FcParseBinary (parse, FcOpNotEqual);
1826         break;
1827     case FcElementLess:
1828         FcParseBinary (parse, FcOpLess);
1829         break;
1830     case FcElementLessEq:
1831         FcParseBinary (parse, FcOpLessEqual);
1832         break;
1833     case FcElementMore:
1834         FcParseBinary (parse, FcOpMore);
1835         break;
1836     case FcElementMoreEq:
1837         FcParseBinary (parse, FcOpMoreEqual);
1838         break;
1839     case FcElementContains:
1840         FcParseBinary (parse, FcOpContains);
1841         break;
1842     case FcElementNotContains:
1843         FcParseBinary (parse, FcOpNotContains);
1844         break;
1845     case FcElementPlus:
1846         FcParseBinary (parse, FcOpPlus);
1847         break;
1848     case FcElementMinus:
1849         FcParseBinary (parse, FcOpMinus);
1850         break;
1851     case FcElementTimes:
1852         FcParseBinary (parse, FcOpTimes);
1853         break;
1854     case FcElementDivide:
1855         FcParseBinary (parse, FcOpDivide);
1856         break;
1857     case FcElementNot:
1858         FcParseUnary (parse, FcOpNot);
1859         break;
1860     case FcElementIf:
1861         FcParseBinary (parse, FcOpQuest);
1862         break;
1863     case FcElementFloor:
1864         FcParseUnary (parse, FcOpFloor);
1865         break;
1866     case FcElementCeil:
1867         FcParseUnary (parse, FcOpCeil);
1868         break;
1869     case FcElementRound:
1870         FcParseUnary (parse, FcOpRound);
1871         break;
1872     case FcElementTrunc:
1873         FcParseUnary (parse, FcOpTrunc);
1874         break;
1875     case FcElementUnknown:
1876         break;
1877     }
1878     (void) FcPStackPop (parse);
1879 }
1880
1881 static void
1882 FcCharacterData (void *userData, const XML_Char *s, int len)
1883 {
1884     FcConfigParse   *parse = userData;
1885     
1886     if (!parse->pstack)
1887         return;
1888     if (!FcStrBufData (&parse->pstack->str, (FcChar8 *) s, len))
1889         FcConfigMessage (parse, FcSevereError, "out of memory");
1890 }
1891
1892 static void
1893 FcStartDoctypeDecl (void            *userData,
1894                     const XML_Char  *doctypeName,
1895                     const XML_Char  *sysid,
1896                     const XML_Char  *pubid,
1897                     int             has_internal_subset)
1898 {
1899     FcConfigParse   *parse = userData;
1900
1901     if (strcmp ((char *) doctypeName, "fontconfig") != 0)
1902         FcConfigMessage (parse, FcSevereError, "invalid doctype \"%s\"", doctypeName);
1903 }
1904
1905 static void
1906 FcEndDoctypeDecl (void *userData)
1907 {
1908 }
1909
1910 FcBool
1911 FcConfigParseAndLoad (FcConfig      *config,
1912                       const FcChar8 *name,
1913                       FcBool        complain)
1914 {
1915
1916     XML_Parser      p;
1917     FcChar8         *filename;
1918     FILE            *f;
1919     int             len;
1920     void            *buf;
1921     FcConfigParse   parse;
1922     FcBool          error = FcTrue;
1923     
1924     filename = FcConfigFilename (name);
1925     if (!filename)
1926         goto bail0;
1927     
1928     if (!FcStrSetAdd (config->configFiles, filename))
1929     {
1930         FcStrFree (filename);
1931         goto bail0;
1932     }
1933
1934     f = fopen ((char *) filename, "r");
1935     FcStrFree (filename);
1936     if (!f)
1937         goto bail0;
1938     
1939     p = XML_ParserCreate ("UTF-8");
1940     if (!p)
1941         goto bail1;
1942
1943     if (!FcConfigInit (&parse, name, config, p))
1944         goto bail2;
1945
1946     XML_SetUserData (p, &parse);
1947     
1948     XML_SetDoctypeDeclHandler (p, FcStartDoctypeDecl, FcEndDoctypeDecl);
1949     XML_SetElementHandler (p, FcStartElement, FcEndElement);
1950     XML_SetCharacterDataHandler (p, FcCharacterData);
1951         
1952     do {
1953         buf = XML_GetBuffer (p, BUFSIZ);
1954         if (!buf)
1955         {
1956             FcConfigMessage (&parse, FcSevereError, "cannot get parse buffer");
1957             goto bail3;
1958         }
1959         len = fread (buf, 1, BUFSIZ, f);
1960         if (len < 0)
1961         {
1962             FcConfigMessage (&parse, FcSevereError, "failed reading config file");
1963             goto bail3;
1964         }
1965         if (!XML_ParseBuffer (p, len, len == 0))
1966         {
1967             FcConfigMessage (&parse, FcSevereError, "%s", 
1968                            XML_ErrorString (XML_GetErrorCode (p)));
1969             goto bail3;
1970         }
1971     } while (len != 0);
1972     error = parse.error;
1973 bail3:
1974     FcConfigCleanup (&parse);
1975 bail2:
1976     XML_ParserFree (p);
1977 bail1:
1978     fclose (f);
1979 bail0:
1980     if (error && complain)
1981     {
1982         if (name)
1983             FcConfigMessage (0, FcSevereError, "Cannot load config file \"%s\"", name);
1984         else
1985             FcConfigMessage (0, FcSevereError, "Cannot load default config file");
1986         return FcFalse;
1987     }
1988     return FcTrue;
1989 }