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