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