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