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