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