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