fcxml.c revision c9710b42
12c393a42Smrg/*
2a6844aabSmrg * fontconfig/src/fcxml.c
32c393a42Smrg *
42c393a42Smrg * Copyright © 2002 Keith Packard
52c393a42Smrg *
62c393a42Smrg * Permission to use, copy, modify, distribute, and sell this software and its
72c393a42Smrg * documentation for any purpose is hereby granted without fee, provided that
82c393a42Smrg * the above copyright notice appear in all copies and that both that
92c393a42Smrg * copyright notice and this permission notice appear in supporting
10ca08ab68Smrg * documentation, and that the name of the author(s) not be used in
112c393a42Smrg * advertising or publicity pertaining to distribution of the software without
12ca08ab68Smrg * specific, written prior permission.  The authors make no
132c393a42Smrg * representations about the suitability of this software for any purpose.  It
142c393a42Smrg * is provided "as is" without express or implied warranty.
152c393a42Smrg *
16a6844aabSmrg * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
172c393a42Smrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18a6844aabSmrg * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR
192c393a42Smrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
202c393a42Smrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
212c393a42Smrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
222c393a42Smrg * PERFORMANCE OF THIS SOFTWARE.
232c393a42Smrg */
242c393a42Smrg
252c393a42Smrg#include "fcint.h"
262c393a42Smrg#include <fcntl.h>
272c393a42Smrg#include <stdarg.h>
282c393a42Smrg#include <dirent.h>
292c393a42Smrg
302c393a42Smrg#ifdef ENABLE_LIBXML2
312c393a42Smrg
322c393a42Smrg#include <libxml/parser.h>
332c393a42Smrg
342c393a42Smrg#define XML_Char			xmlChar
352c393a42Smrg#define XML_Parser			xmlParserCtxtPtr
362c393a42Smrg#define XML_ParserFree			xmlFreeParserCtxt
372c393a42Smrg#define XML_GetCurrentLineNumber	xmlSAX2GetLineNumber
382c393a42Smrg#define XML_GetErrorCode		xmlCtxtGetLastError
392c393a42Smrg#define XML_ErrorString(Error)		(Error)->message
402c393a42Smrg
412c393a42Smrg#else /* ENABLE_LIBXML2 */
422c393a42Smrg
432c393a42Smrg#ifndef HAVE_XMLPARSE_H
442c393a42Smrg#define HAVE_XMLPARSE_H 0
452c393a42Smrg#endif
462c393a42Smrg
472c393a42Smrg#if HAVE_XMLPARSE_H
482c393a42Smrg#include <xmlparse.h>
492c393a42Smrg#else
502c393a42Smrg#include <expat.h>
512c393a42Smrg#endif
522c393a42Smrg
532c393a42Smrg#endif /* ENABLE_LIBXML2 */
542c393a42Smrg
552c393a42Smrg#ifdef _WIN32
56a6844aabSmrg#include <mbstring.h>
572c393a42Smrg#endif
582c393a42Smrg
59a6844aabSmrgstatic void
60a6844aabSmrgFcExprDestroy (FcExpr *e);
612c393a42Smrg
622c393a42Smrgvoid
632c393a42SmrgFcTestDestroy (FcTest *test)
642c393a42Smrg{
652c393a42Smrg    if (test->next)
662c393a42Smrg	FcTestDestroy (test->next);
672c393a42Smrg    FcExprDestroy (test->expr);
682c393a42Smrg    free (test);
692c393a42Smrg}
702c393a42Smrg
71a6844aabSmrgstatic FcExpr *
72a6844aabSmrgFcExprCreateInteger (FcConfig *config, int i)
732c393a42Smrg{
74a6844aabSmrg    FcExpr *e = FcConfigAllocExpr (config);
752c393a42Smrg    if (e)
762c393a42Smrg    {
772c393a42Smrg	e->op = FcOpInteger;
782c393a42Smrg	e->u.ival = i;
792c393a42Smrg    }
802c393a42Smrg    return e;
812c393a42Smrg}
822c393a42Smrg
83a6844aabSmrgstatic FcExpr *
84a6844aabSmrgFcExprCreateDouble (FcConfig *config, double d)
852c393a42Smrg{
86a6844aabSmrg    FcExpr *e = FcConfigAllocExpr (config);
872c393a42Smrg    if (e)
882c393a42Smrg    {
892c393a42Smrg	e->op = FcOpDouble;
902c393a42Smrg	e->u.dval = d;
912c393a42Smrg    }
922c393a42Smrg    return e;
932c393a42Smrg}
942c393a42Smrg
95a6844aabSmrgstatic FcExpr *
96a6844aabSmrgFcExprCreateString (FcConfig *config, const FcChar8 *s)
972c393a42Smrg{
98a6844aabSmrg    FcExpr *e = FcConfigAllocExpr (config);
992c393a42Smrg    if (e)
1002c393a42Smrg    {
1012c393a42Smrg	e->op = FcOpString;
102c9710b42Smrg	e->u.sval = FcStrdup (s);
1032c393a42Smrg    }
1042c393a42Smrg    return e;
1052c393a42Smrg}
1062c393a42Smrg
107c9710b42Smrgstatic FcExprMatrix *
108c9710b42SmrgFcExprMatrixCopyShallow (const FcExprMatrix *matrix)
109c9710b42Smrg{
110c9710b42Smrg  FcExprMatrix *m = malloc (sizeof (FcExprMatrix));
111c9710b42Smrg  if (m)
112c9710b42Smrg  {
113c9710b42Smrg    *m = *matrix;
114c9710b42Smrg  }
115c9710b42Smrg  return m;
116c9710b42Smrg}
117c9710b42Smrg
118c9710b42Smrgstatic void
119c9710b42SmrgFcExprMatrixFreeShallow (FcExprMatrix *m)
120c9710b42Smrg{
121c9710b42Smrg  if (!m)
122c9710b42Smrg    return;
123c9710b42Smrg
124c9710b42Smrg  free (m);
125c9710b42Smrg}
126c9710b42Smrg
127c9710b42Smrgstatic void
128c9710b42SmrgFcExprMatrixFree (FcExprMatrix *m)
129c9710b42Smrg{
130c9710b42Smrg  if (!m)
131c9710b42Smrg    return;
132c9710b42Smrg
133c9710b42Smrg  FcExprDestroy (m->xx);
134c9710b42Smrg  FcExprDestroy (m->xy);
135c9710b42Smrg  FcExprDestroy (m->yx);
136c9710b42Smrg  FcExprDestroy (m->yy);
137c9710b42Smrg
138c9710b42Smrg  free (m);
139c9710b42Smrg}
140c9710b42Smrg
141a6844aabSmrgstatic FcExpr *
142c9710b42SmrgFcExprCreateMatrix (FcConfig *config, const FcExprMatrix *matrix)
1432c393a42Smrg{
144a6844aabSmrg    FcExpr *e = FcConfigAllocExpr (config);
1452c393a42Smrg    if (e)
1462c393a42Smrg    {
1472c393a42Smrg	e->op = FcOpMatrix;
148c9710b42Smrg	e->u.mexpr = FcExprMatrixCopyShallow (matrix);
1492c393a42Smrg    }
1502c393a42Smrg    return e;
1512c393a42Smrg}
1522c393a42Smrg
153a6844aabSmrgstatic FcExpr *
154a6844aabSmrgFcExprCreateBool (FcConfig *config, FcBool b)
1552c393a42Smrg{
156a6844aabSmrg    FcExpr *e = FcConfigAllocExpr (config);
1572c393a42Smrg    if (e)
1582c393a42Smrg    {
1592c393a42Smrg	e->op = FcOpBool;
1602c393a42Smrg	e->u.bval = b;
1612c393a42Smrg    }
1622c393a42Smrg    return e;
1632c393a42Smrg}
1642c393a42Smrg
165ca08ab68Smrgstatic FcExpr *
166ca08ab68SmrgFcExprCreateCharSet (FcConfig *config, FcCharSet *charset)
167ca08ab68Smrg{
168ca08ab68Smrg    FcExpr *e = FcConfigAllocExpr (config);
169ca08ab68Smrg    if (e)
170ca08ab68Smrg    {
171ca08ab68Smrg	e->op = FcOpCharSet;
172ca08ab68Smrg	e->u.cval = FcCharSetCopy (charset);
173ca08ab68Smrg    }
174ca08ab68Smrg    return e;
175ca08ab68Smrg}
176ca08ab68Smrg
177ca08ab68Smrgstatic FcExpr *
178ca08ab68SmrgFcExprCreateLangSet (FcConfig *config, FcLangSet *langset)
179ca08ab68Smrg{
180ca08ab68Smrg    FcExpr *e = FcConfigAllocExpr (config);
181ca08ab68Smrg    if (e)
182ca08ab68Smrg    {
183ca08ab68Smrg	e->op = FcOpLangSet;
184ca08ab68Smrg	e->u.lval = FcLangSetCopy (langset);
185ca08ab68Smrg    }
186ca08ab68Smrg    return e;
187ca08ab68Smrg}
188ca08ab68Smrg
189a6844aabSmrgstatic FcExpr *
190c9710b42SmrgFcExprCreateName (FcConfig *config, FcExprName name)
1912c393a42Smrg{
192a6844aabSmrg    FcExpr *e = FcConfigAllocExpr (config);
1932c393a42Smrg    if (e)
1942c393a42Smrg    {
1952c393a42Smrg	e->op = FcOpField;
196c9710b42Smrg	e->u.name = name;
1972c393a42Smrg    }
1982c393a42Smrg    return e;
1992c393a42Smrg}
2002c393a42Smrg
201a6844aabSmrgstatic FcExpr *
202a6844aabSmrgFcExprCreateConst (FcConfig *config, const FcChar8 *constant)
2032c393a42Smrg{
204a6844aabSmrg    FcExpr *e = FcConfigAllocExpr (config);
2052c393a42Smrg    if (e)
2062c393a42Smrg    {
2072c393a42Smrg	e->op = FcOpConst;
208c9710b42Smrg	e->u.constant = FcStrdup (constant);
2092c393a42Smrg    }
2102c393a42Smrg    return e;
2112c393a42Smrg}
2122c393a42Smrg
213a6844aabSmrgstatic FcExpr *
214a6844aabSmrgFcExprCreateOp (FcConfig *config, FcExpr *left, FcOp op, FcExpr *right)
2152c393a42Smrg{
216a6844aabSmrg    FcExpr *e = FcConfigAllocExpr (config);
2172c393a42Smrg    if (e)
2182c393a42Smrg    {
2192c393a42Smrg	e->op = op;
2202c393a42Smrg	e->u.tree.left = left;
2212c393a42Smrg	e->u.tree.right = right;
2222c393a42Smrg    }
2232c393a42Smrg    return e;
2242c393a42Smrg}
2252c393a42Smrg
226a6844aabSmrgstatic void
2272c393a42SmrgFcExprDestroy (FcExpr *e)
2282c393a42Smrg{
2292c393a42Smrg    if (!e)
2302c393a42Smrg	return;
231ca08ab68Smrg    switch (FC_OP_GET_OP (e->op)) {
2322c393a42Smrg    case FcOpInteger:
2332c393a42Smrg	break;
2342c393a42Smrg    case FcOpDouble:
2352c393a42Smrg	break;
2362c393a42Smrg    case FcOpString:
237c9710b42Smrg	FcFree (e->u.sval);
2382c393a42Smrg	break;
2392c393a42Smrg    case FcOpMatrix:
240c9710b42Smrg	FcExprMatrixFree (e->u.mexpr);
2412c393a42Smrg	break;
242ca08ab68Smrg    case FcOpRange:
243ca08ab68Smrg	break;
2442c393a42Smrg    case FcOpCharSet:
2452c393a42Smrg	FcCharSetDestroy (e->u.cval);
2462c393a42Smrg	break;
247ca08ab68Smrg    case FcOpLangSet:
248ca08ab68Smrg	FcLangSetDestroy (e->u.lval);
249ca08ab68Smrg	break;
2502c393a42Smrg    case FcOpBool:
2512c393a42Smrg	break;
2522c393a42Smrg    case FcOpField:
2532c393a42Smrg	break;
2542c393a42Smrg    case FcOpConst:
255c9710b42Smrg	FcFree (e->u.constant);
2562c393a42Smrg	break;
2572c393a42Smrg    case FcOpAssign:
2582c393a42Smrg    case FcOpAssignReplace:
2592c393a42Smrg    case FcOpPrepend:
2602c393a42Smrg    case FcOpPrependFirst:
2612c393a42Smrg    case FcOpAppend:
2622c393a42Smrg    case FcOpAppendLast:
263c9710b42Smrg    case FcOpDelete:
264c9710b42Smrg    case FcOpDeleteAll:
2652c393a42Smrg	break;
2662c393a42Smrg    case FcOpOr:
2672c393a42Smrg    case FcOpAnd:
2682c393a42Smrg    case FcOpEqual:
2692c393a42Smrg    case FcOpNotEqual:
2702c393a42Smrg    case FcOpLess:
2712c393a42Smrg    case FcOpLessEqual:
2722c393a42Smrg    case FcOpMore:
2732c393a42Smrg    case FcOpMoreEqual:
2742c393a42Smrg    case FcOpContains:
2752c393a42Smrg    case FcOpListing:
2762c393a42Smrg    case FcOpNotContains:
2772c393a42Smrg    case FcOpPlus:
2782c393a42Smrg    case FcOpMinus:
2792c393a42Smrg    case FcOpTimes:
2802c393a42Smrg    case FcOpDivide:
2812c393a42Smrg    case FcOpQuest:
2822c393a42Smrg    case FcOpComma:
2832c393a42Smrg	FcExprDestroy (e->u.tree.right);
2842c393a42Smrg	/* fall through */
2852c393a42Smrg    case FcOpNot:
2862c393a42Smrg    case FcOpFloor:
2872c393a42Smrg    case FcOpCeil:
2882c393a42Smrg    case FcOpRound:
2892c393a42Smrg    case FcOpTrunc:
2902c393a42Smrg	FcExprDestroy (e->u.tree.left);
2912c393a42Smrg	break;
2922c393a42Smrg    case FcOpNil:
2932c393a42Smrg    case FcOpInvalid:
2942c393a42Smrg	break;
2952c393a42Smrg    }
296a6844aabSmrg
297a6844aabSmrg    e->op = FcOpNil;
2982c393a42Smrg}
2992c393a42Smrg
3002c393a42Smrgvoid
3012c393a42SmrgFcEditDestroy (FcEdit *e)
3022c393a42Smrg{
3032c393a42Smrg    if (e->next)
3042c393a42Smrg	FcEditDestroy (e->next);
3052c393a42Smrg    if (e->expr)
3062c393a42Smrg	FcExprDestroy (e->expr);
3072c393a42Smrg    free (e);
3082c393a42Smrg}
3092c393a42Smrg
3102c393a42Smrgtypedef enum _FcElement {
3112c393a42Smrg    FcElementNone,
3122c393a42Smrg    FcElementFontconfig,
3132c393a42Smrg    FcElementDir,
3142c393a42Smrg    FcElementCacheDir,
3152c393a42Smrg    FcElementCache,
3162c393a42Smrg    FcElementInclude,
3172c393a42Smrg    FcElementConfig,
3182c393a42Smrg    FcElementMatch,
3192c393a42Smrg    FcElementAlias,
3202c393a42Smrg
3212c393a42Smrg    FcElementBlank,
3222c393a42Smrg    FcElementRescan,
3232c393a42Smrg
3242c393a42Smrg    FcElementPrefer,
3252c393a42Smrg    FcElementAccept,
3262c393a42Smrg    FcElementDefault,
3272c393a42Smrg    FcElementFamily,
3282c393a42Smrg
3292c393a42Smrg    FcElementSelectfont,
3302c393a42Smrg    FcElementAcceptfont,
3312c393a42Smrg    FcElementRejectfont,
3322c393a42Smrg    FcElementGlob,
3332c393a42Smrg    FcElementPattern,
3342c393a42Smrg    FcElementPatelt,
3352c393a42Smrg
3362c393a42Smrg    FcElementTest,
3372c393a42Smrg    FcElementEdit,
3382c393a42Smrg    FcElementInt,
3392c393a42Smrg    FcElementDouble,
3402c393a42Smrg    FcElementString,
3412c393a42Smrg    FcElementMatrix,
342ca08ab68Smrg    FcElementRange,
3432c393a42Smrg    FcElementBool,
344ca08ab68Smrg    FcElementCharSet,
345ca08ab68Smrg    FcElementLangSet,
3462c393a42Smrg    FcElementName,
3472c393a42Smrg    FcElementConst,
3482c393a42Smrg    FcElementOr,
3492c393a42Smrg    FcElementAnd,
3502c393a42Smrg    FcElementEq,
3512c393a42Smrg    FcElementNotEq,
3522c393a42Smrg    FcElementLess,
3532c393a42Smrg    FcElementLessEq,
3542c393a42Smrg    FcElementMore,
3552c393a42Smrg    FcElementMoreEq,
3562c393a42Smrg    FcElementContains,
3572c393a42Smrg    FcElementNotContains,
3582c393a42Smrg    FcElementPlus,
3592c393a42Smrg    FcElementMinus,
3602c393a42Smrg    FcElementTimes,
3612c393a42Smrg    FcElementDivide,
3622c393a42Smrg    FcElementNot,
3632c393a42Smrg    FcElementIf,
3642c393a42Smrg    FcElementFloor,
3652c393a42Smrg    FcElementCeil,
3662c393a42Smrg    FcElementRound,
3672c393a42Smrg    FcElementTrunc,
3682c393a42Smrg    FcElementUnknown
3692c393a42Smrg} FcElement;
3702c393a42Smrg
3712c393a42Smrgstatic const struct {
3722c393a42Smrg    const char  name[16];
3732c393a42Smrg    FcElement   element;
3742c393a42Smrg} fcElementMap[] = {
3752c393a42Smrg    { "fontconfig",	FcElementFontconfig },
3762c393a42Smrg    { "dir",		FcElementDir },
3772c393a42Smrg    { "cachedir",	FcElementCacheDir },
3782c393a42Smrg    { "cache",		FcElementCache },
3792c393a42Smrg    { "include",	FcElementInclude },
3802c393a42Smrg    { "config",		FcElementConfig },
3812c393a42Smrg    { "match",		FcElementMatch },
3822c393a42Smrg    { "alias",		FcElementAlias },
383ca08ab68Smrg
3842c393a42Smrg    { "blank",		FcElementBlank },
3852c393a42Smrg    { "rescan",		FcElementRescan },
3862c393a42Smrg
3872c393a42Smrg    { "prefer",		FcElementPrefer },
3882c393a42Smrg    { "accept",		FcElementAccept },
3892c393a42Smrg    { "default",	FcElementDefault },
3902c393a42Smrg    { "family",		FcElementFamily },
3912c393a42Smrg
3922c393a42Smrg    { "selectfont",	FcElementSelectfont },
3932c393a42Smrg    { "acceptfont",	FcElementAcceptfont },
3942c393a42Smrg    { "rejectfont",	FcElementRejectfont },
3952c393a42Smrg    { "glob",		FcElementGlob },
3962c393a42Smrg    { "pattern",	FcElementPattern },
3972c393a42Smrg    { "patelt",		FcElementPatelt },
3982c393a42Smrg
3992c393a42Smrg    { "test",		FcElementTest },
4002c393a42Smrg    { "edit",		FcElementEdit },
4012c393a42Smrg    { "int",		FcElementInt },
4022c393a42Smrg    { "double",		FcElementDouble },
4032c393a42Smrg    { "string",		FcElementString },
4042c393a42Smrg    { "matrix",		FcElementMatrix },
405ca08ab68Smrg    { "range",		FcElementRange },
4062c393a42Smrg    { "bool",		FcElementBool },
407ca08ab68Smrg    { "charset",	FcElementCharSet },
408ca08ab68Smrg    { "langset",	FcElementLangSet },
4092c393a42Smrg    { "name",		FcElementName },
4102c393a42Smrg    { "const",		FcElementConst },
4112c393a42Smrg    { "or",		FcElementOr },
4122c393a42Smrg    { "and",		FcElementAnd },
4132c393a42Smrg    { "eq",		FcElementEq },
4142c393a42Smrg    { "not_eq",		FcElementNotEq },
4152c393a42Smrg    { "less",		FcElementLess },
4162c393a42Smrg    { "less_eq",	FcElementLessEq },
4172c393a42Smrg    { "more",		FcElementMore },
4182c393a42Smrg    { "more_eq",	FcElementMoreEq },
4192c393a42Smrg    { "contains",	FcElementContains },
4202c393a42Smrg    { "not_contains",	FcElementNotContains },
4212c393a42Smrg    { "plus",		FcElementPlus },
4222c393a42Smrg    { "minus",		FcElementMinus },
4232c393a42Smrg    { "times",		FcElementTimes },
4242c393a42Smrg    { "divide",		FcElementDivide },
4252c393a42Smrg    { "not",		FcElementNot },
4262c393a42Smrg    { "if",		FcElementIf },
4272c393a42Smrg    { "floor",		FcElementFloor },
4282c393a42Smrg    { "ceil",		FcElementCeil },
4292c393a42Smrg    { "round",		FcElementRound },
4302c393a42Smrg    { "trunc",		FcElementTrunc },
4312c393a42Smrg};
4322c393a42Smrg#define NUM_ELEMENT_MAPS (int) (sizeof fcElementMap / sizeof fcElementMap[0])
4332c393a42Smrg
4342c393a42Smrgstatic FcElement
4352c393a42SmrgFcElementMap (const XML_Char *name)
4362c393a42Smrg{
4372c393a42Smrg
4382c393a42Smrg    int	    i;
4392c393a42Smrg    for (i = 0; i < NUM_ELEMENT_MAPS; i++)
4402c393a42Smrg	if (!strcmp ((char *) name, fcElementMap[i].name))
4412c393a42Smrg	    return fcElementMap[i].element;
4422c393a42Smrg    return FcElementUnknown;
4432c393a42Smrg}
4442c393a42Smrg
4452c393a42Smrgtypedef struct _FcPStack {
4462c393a42Smrg    struct _FcPStack   *prev;
4472c393a42Smrg    FcElement		element;
4482c393a42Smrg    FcChar8		**attr;
4492c393a42Smrg    FcStrBuf		str;
450a6844aabSmrg    FcChar8            *attr_buf_static[16];
4512c393a42Smrg} FcPStack;
452ca08ab68Smrg
4532c393a42Smrgtypedef enum _FcVStackTag {
4542c393a42Smrg    FcVStackNone,
4552c393a42Smrg
4562c393a42Smrg    FcVStackString,
4572c393a42Smrg    FcVStackFamily,
4582c393a42Smrg    FcVStackConstant,
4592c393a42Smrg    FcVStackGlob,
460c9710b42Smrg    FcVStackName,
4612c393a42Smrg    FcVStackPattern,
462ca08ab68Smrg
4632c393a42Smrg    FcVStackPrefer,
4642c393a42Smrg    FcVStackAccept,
4652c393a42Smrg    FcVStackDefault,
466ca08ab68Smrg
4672c393a42Smrg    FcVStackInteger,
4682c393a42Smrg    FcVStackDouble,
4692c393a42Smrg    FcVStackMatrix,
470ca08ab68Smrg    FcVStackRange,
4712c393a42Smrg    FcVStackBool,
472ca08ab68Smrg    FcVStackCharSet,
473ca08ab68Smrg    FcVStackLangSet,
474ca08ab68Smrg
4752c393a42Smrg    FcVStackTest,
4762c393a42Smrg    FcVStackExpr,
4772c393a42Smrg    FcVStackEdit
4782c393a42Smrg} FcVStackTag;
4792c393a42Smrg
4802c393a42Smrgtypedef struct _FcVStack {
4812c393a42Smrg    struct _FcVStack	*prev;
4822c393a42Smrg    FcPStack		*pstack;	/* related parse element */
4832c393a42Smrg    FcVStackTag		tag;
4842c393a42Smrg    union {
4852c393a42Smrg	FcChar8		*string;
4862c393a42Smrg
4872c393a42Smrg	int		integer;
4882c393a42Smrg	double		_double;
489c9710b42Smrg	FcExprMatrix	*matrix;
490ca08ab68Smrg	FcRange		range;
491a6844aabSmrg	FcBool		bool_;
492ca08ab68Smrg	FcCharSet	*charset;
493ca08ab68Smrg	FcLangSet	*langset;
494c9710b42Smrg	FcExprName	name;
4952c393a42Smrg
4962c393a42Smrg	FcTest		*test;
4972c393a42Smrg	FcQual		qual;
4982c393a42Smrg	FcOp		op;
4992c393a42Smrg	FcExpr		*expr;
5002c393a42Smrg	FcEdit		*edit;
5012c393a42Smrg
5022c393a42Smrg	FcPattern	*pattern;
5032c393a42Smrg    } u;
5042c393a42Smrg} FcVStack;
5052c393a42Smrg
5062c393a42Smrgtypedef struct _FcConfigParse {
5072c393a42Smrg    FcPStack	    *pstack;
5082c393a42Smrg    FcVStack	    *vstack;
5092c393a42Smrg    FcBool	    error;
5102c393a42Smrg    const FcChar8   *name;
5112c393a42Smrg    FcConfig	    *config;
5122c393a42Smrg    XML_Parser	    parser;
513c9710b42Smrg    unsigned int    pstack_static_used;
514a6844aabSmrg    FcPStack        pstack_static[8];
515c9710b42Smrg    unsigned int    vstack_static_used;
516a6844aabSmrg    FcVStack        vstack_static[64];
5172c393a42Smrg} FcConfigParse;
5182c393a42Smrg
5192c393a42Smrgtypedef enum _FcConfigSeverity {
5202c393a42Smrg    FcSevereInfo, FcSevereWarning, FcSevereError
5212c393a42Smrg} FcConfigSeverity;
5222c393a42Smrg
5232c393a42Smrgstatic void
5242c393a42SmrgFcConfigMessage (FcConfigParse *parse, FcConfigSeverity severe, const char *fmt, ...)
5252c393a42Smrg{
5262c393a42Smrg    const char	*s = "unknown";
5272c393a42Smrg    va_list	args;
5282c393a42Smrg
5292c393a42Smrg    va_start (args, fmt);
5302c393a42Smrg
5312c393a42Smrg    switch (severe) {
5322c393a42Smrg    case FcSevereInfo: s = "info"; break;
5332c393a42Smrg    case FcSevereWarning: s = "warning"; break;
5342c393a42Smrg    case FcSevereError: s = "error"; break;
5352c393a42Smrg    }
5362c393a42Smrg    if (parse)
5372c393a42Smrg    {
5382c393a42Smrg	if (parse->name)
5392c393a42Smrg	    fprintf (stderr, "Fontconfig %s: \"%s\", line %d: ", s,
5402c393a42Smrg		     parse->name, (int)XML_GetCurrentLineNumber (parse->parser));
5412c393a42Smrg	else
5422c393a42Smrg	    fprintf (stderr, "Fontconfig %s: line %d: ", s,
5432c393a42Smrg		     (int)XML_GetCurrentLineNumber (parse->parser));
5442c393a42Smrg	if (severe >= FcSevereError)
5452c393a42Smrg	    parse->error = FcTrue;
5462c393a42Smrg    }
5472c393a42Smrg    else
5482c393a42Smrg	fprintf (stderr, "Fontconfig %s: ", s);
5492c393a42Smrg    vfprintf (stderr, fmt, args);
5502c393a42Smrg    fprintf (stderr, "\n");
5512c393a42Smrg    va_end (args);
5522c393a42Smrg}
5532c393a42Smrg
5542c393a42Smrg
555c9710b42Smrgstatic FcExpr *
556c9710b42SmrgFcPopExpr (FcConfigParse *parse);
557c9710b42Smrg
558c9710b42Smrg
5592c393a42Smrgstatic const char *
5602c393a42SmrgFcTypeName (FcType type)
5612c393a42Smrg{
5622c393a42Smrg    switch (type) {
5632c393a42Smrg    case FcTypeVoid:
5642c393a42Smrg	return "void";
5652c393a42Smrg    case FcTypeInteger:
5662c393a42Smrg    case FcTypeDouble:
5672c393a42Smrg	return "number";
5682c393a42Smrg    case FcTypeString:
5692c393a42Smrg	return "string";
5702c393a42Smrg    case FcTypeBool:
5712c393a42Smrg	return "bool";
5722c393a42Smrg    case FcTypeMatrix:
5732c393a42Smrg	return "matrix";
5742c393a42Smrg    case FcTypeCharSet:
5752c393a42Smrg	return "charset";
5762c393a42Smrg    case FcTypeFTFace:
5772c393a42Smrg	return "FT_Face";
5782c393a42Smrg    case FcTypeLangSet:
5792c393a42Smrg	return "langset";
5802c393a42Smrg    default:
5812c393a42Smrg	return "unknown";
5822c393a42Smrg    }
5832c393a42Smrg}
5842c393a42Smrg
5852c393a42Smrgstatic void
5862c393a42SmrgFcTypecheckValue (FcConfigParse *parse, FcType value, FcType type)
5872c393a42Smrg{
5882c393a42Smrg    if (value == FcTypeInteger)
5892c393a42Smrg	value = FcTypeDouble;
5902c393a42Smrg    if (type == FcTypeInteger)
5912c393a42Smrg	type = FcTypeDouble;
5922c393a42Smrg    if (value != type)
5932c393a42Smrg    {
5942c393a42Smrg	if ((value == FcTypeLangSet && type == FcTypeString) ||
5952c393a42Smrg	    (value == FcTypeString && type == FcTypeLangSet))
5962c393a42Smrg	    return;
5972c393a42Smrg	if (type == (FcType) -1)
5982c393a42Smrg	    return;
599c9710b42Smrg	/* It's perfectly fine to use user-define elements in expressions,
600c9710b42Smrg	 * so don't warn in that case. */
601c9710b42Smrg	if (value == (FcType) -1)
602c9710b42Smrg	    return;
6032c393a42Smrg	FcConfigMessage (parse, FcSevereWarning, "saw %s, expected %s",
6042c393a42Smrg			 FcTypeName (value), FcTypeName (type));
6052c393a42Smrg    }
6062c393a42Smrg}
6072c393a42Smrg
6082c393a42Smrgstatic void
6092c393a42SmrgFcTypecheckExpr (FcConfigParse *parse, FcExpr *expr, FcType type)
6102c393a42Smrg{
6112c393a42Smrg    const FcObjectType	*o;
6122c393a42Smrg    const FcConstant	*c;
613ca08ab68Smrg
6142c393a42Smrg    /* If parsing the expression failed, some nodes may be NULL */
6152c393a42Smrg    if (!expr)
6162c393a42Smrg	return;
6172c393a42Smrg
618ca08ab68Smrg    switch (FC_OP_GET_OP (expr->op)) {
6192c393a42Smrg    case FcOpInteger:
6202c393a42Smrg    case FcOpDouble:
6212c393a42Smrg	FcTypecheckValue (parse, FcTypeDouble, type);
6222c393a42Smrg	break;
6232c393a42Smrg    case FcOpString:
6242c393a42Smrg	FcTypecheckValue (parse, FcTypeString, type);
6252c393a42Smrg	break;
6262c393a42Smrg    case FcOpMatrix:
6272c393a42Smrg	FcTypecheckValue (parse, FcTypeMatrix, type);
6282c393a42Smrg	break;
6292c393a42Smrg    case FcOpBool:
6302c393a42Smrg	FcTypecheckValue (parse, FcTypeBool, type);
6312c393a42Smrg	break;
6322c393a42Smrg    case FcOpCharSet:
6332c393a42Smrg	FcTypecheckValue (parse, FcTypeCharSet, type);
6342c393a42Smrg	break;
635ca08ab68Smrg    case FcOpLangSet:
636ca08ab68Smrg	FcTypecheckValue (parse, FcTypeLangSet, type);
637ca08ab68Smrg	break;
6382c393a42Smrg    case FcOpNil:
6392c393a42Smrg	break;
6402c393a42Smrg    case FcOpField:
641c9710b42Smrg	o = FcNameGetObjectType (FcObjectName (expr->u.name.object));
6422c393a42Smrg	if (o)
6432c393a42Smrg	    FcTypecheckValue (parse, o->type, type);
6442c393a42Smrg	break;
6452c393a42Smrg    case FcOpConst:
6462c393a42Smrg	c = FcNameGetConstant (expr->u.constant);
6472c393a42Smrg	if (c)
6482c393a42Smrg	{
6492c393a42Smrg	    o = FcNameGetObjectType (c->object);
6502c393a42Smrg	    if (o)
6512c393a42Smrg		FcTypecheckValue (parse, o->type, type);
6522c393a42Smrg	}
653ca08ab68Smrg        else
654ca08ab68Smrg            FcConfigMessage (parse, FcSevereWarning,
6552c393a42Smrg                             "invalid constant used : %s",
6562c393a42Smrg                             expr->u.constant);
6572c393a42Smrg	break;
6582c393a42Smrg    case FcOpQuest:
6592c393a42Smrg	FcTypecheckExpr (parse, expr->u.tree.left, FcTypeBool);
6602c393a42Smrg	FcTypecheckExpr (parse, expr->u.tree.right->u.tree.left, type);
6612c393a42Smrg	FcTypecheckExpr (parse, expr->u.tree.right->u.tree.right, type);
6622c393a42Smrg	break;
6632c393a42Smrg    case FcOpAssign:
6642c393a42Smrg    case FcOpAssignReplace:
6652c393a42Smrg	break;
6662c393a42Smrg    case FcOpEqual:
6672c393a42Smrg    case FcOpNotEqual:
6682c393a42Smrg    case FcOpLess:
6692c393a42Smrg    case FcOpLessEqual:
6702c393a42Smrg    case FcOpMore:
6712c393a42Smrg    case FcOpMoreEqual:
6722c393a42Smrg    case FcOpContains:
6732c393a42Smrg    case FcOpNotContains:
6742c393a42Smrg    case FcOpListing:
6752c393a42Smrg	FcTypecheckValue (parse, FcTypeBool, type);
6762c393a42Smrg	break;
6772c393a42Smrg    case FcOpComma:
6782c393a42Smrg    case FcOpOr:
6792c393a42Smrg    case FcOpAnd:
6802c393a42Smrg    case FcOpPlus:
6812c393a42Smrg    case FcOpMinus:
6822c393a42Smrg    case FcOpTimes:
6832c393a42Smrg    case FcOpDivide:
6842c393a42Smrg	FcTypecheckExpr (parse, expr->u.tree.left, type);
6852c393a42Smrg	FcTypecheckExpr (parse, expr->u.tree.right, type);
6862c393a42Smrg	break;
6872c393a42Smrg    case FcOpNot:
6882c393a42Smrg	FcTypecheckValue (parse, FcTypeBool, type);
6892c393a42Smrg	FcTypecheckExpr (parse, expr->u.tree.left, FcTypeBool);
6902c393a42Smrg	break;
6912c393a42Smrg    case FcOpFloor:
6922c393a42Smrg    case FcOpCeil:
6932c393a42Smrg    case FcOpRound:
6942c393a42Smrg    case FcOpTrunc:
6952c393a42Smrg	FcTypecheckValue (parse, FcTypeDouble, type);
6962c393a42Smrg	FcTypecheckExpr (parse, expr->u.tree.left, FcTypeDouble);
6972c393a42Smrg	break;
6982c393a42Smrg    default:
6992c393a42Smrg	break;
7002c393a42Smrg    }
7012c393a42Smrg}
7022c393a42Smrg
7032c393a42Smrgstatic FcTest *
7042c393a42SmrgFcTestCreate (FcConfigParse *parse,
705ca08ab68Smrg	      FcMatchKind   kind,
7062c393a42Smrg	      FcQual	    qual,
7072c393a42Smrg	      const FcChar8 *field,
7082c393a42Smrg	      FcOp	    compare,
7092c393a42Smrg	      FcExpr	    *expr)
7102c393a42Smrg{
7112c393a42Smrg    FcTest	*test = (FcTest *) malloc (sizeof (FcTest));
7122c393a42Smrg
7132c393a42Smrg    if (test)
7142c393a42Smrg    {
7152c393a42Smrg	const FcObjectType	*o;
7162c393a42Smrg
7172c393a42Smrg	test->next = 0;
7182c393a42Smrg	test->kind = kind;
7192c393a42Smrg	test->qual = qual;
7202c393a42Smrg	test->object = FcObjectFromName ((const char *) field);
7212c393a42Smrg	test->op = compare;
7222c393a42Smrg	test->expr = expr;
7232c393a42Smrg	o = FcNameGetObjectType (FcObjectName (test->object));
7242c393a42Smrg	if (o)
7252c393a42Smrg	    FcTypecheckExpr (parse, expr, o->type);
7262c393a42Smrg    }
7272c393a42Smrg    return test;
7282c393a42Smrg}
7292c393a42Smrg
7302c393a42Smrgstatic FcEdit *
7312c393a42SmrgFcEditCreate (FcConfigParse	*parse,
7322c393a42Smrg	      FcObject		object,
7332c393a42Smrg	      FcOp		op,
7342c393a42Smrg	      FcExpr		*expr,
7352c393a42Smrg	      FcValueBinding	binding)
7362c393a42Smrg{
7372c393a42Smrg    FcEdit *e = (FcEdit *) malloc (sizeof (FcEdit));
7382c393a42Smrg
7392c393a42Smrg    if (e)
7402c393a42Smrg    {
7412c393a42Smrg	const FcObjectType	*o;
7422c393a42Smrg
7432c393a42Smrg	e->next = 0;
7442c393a42Smrg	e->object = object;
7452c393a42Smrg	e->op = op;
7462c393a42Smrg	e->expr = expr;
7472c393a42Smrg	e->binding = binding;
7482c393a42Smrg	o = FcNameGetObjectType (FcObjectName (e->object));
7492c393a42Smrg	if (o)
7502c393a42Smrg	    FcTypecheckExpr (parse, expr, o->type);
7512c393a42Smrg    }
7522c393a42Smrg    return e;
7532c393a42Smrg}
7542c393a42Smrg
7552c393a42Smrgstatic FcVStack *
756a6844aabSmrgFcVStackCreateAndPush (FcConfigParse *parse)
7572c393a42Smrg{
7582c393a42Smrg    FcVStack    *new;
7592c393a42Smrg
760a6844aabSmrg    if (parse->vstack_static_used < sizeof (parse->vstack_static) / sizeof (parse->vstack_static[0]))
761a6844aabSmrg	new = &parse->vstack_static[parse->vstack_static_used++];
762a6844aabSmrg    else
763a6844aabSmrg    {
764a6844aabSmrg	new = malloc (sizeof (FcVStack));
765a6844aabSmrg	if (!new)
766a6844aabSmrg	    return 0;
767a6844aabSmrg    }
7682c393a42Smrg    new->tag = FcVStackNone;
7692c393a42Smrg    new->prev = 0;
7702c393a42Smrg
771a6844aabSmrg    new->prev = parse->vstack;
772a6844aabSmrg    new->pstack = parse->pstack ? parse->pstack->prev : 0;
773a6844aabSmrg    parse->vstack = new;
7742c393a42Smrg
775a6844aabSmrg    return new;
7762c393a42Smrg}
7772c393a42Smrg
7782c393a42Smrgstatic FcBool
7792c393a42SmrgFcVStackPushString (FcConfigParse *parse, FcVStackTag tag, FcChar8 *string)
7802c393a42Smrg{
781a6844aabSmrg    FcVStack    *vstack = FcVStackCreateAndPush (parse);
7822c393a42Smrg    if (!vstack)
7832c393a42Smrg	return FcFalse;
7842c393a42Smrg    vstack->u.string = string;
7852c393a42Smrg    vstack->tag = tag;
7862c393a42Smrg    return FcTrue;
7872c393a42Smrg}
7882c393a42Smrg
7892c393a42Smrgstatic FcBool
7902c393a42SmrgFcVStackPushInteger (FcConfigParse *parse, int integer)
7912c393a42Smrg{
792a6844aabSmrg    FcVStack    *vstack = FcVStackCreateAndPush (parse);
7932c393a42Smrg    if (!vstack)
7942c393a42Smrg	return FcFalse;
7952c393a42Smrg    vstack->u.integer = integer;
7962c393a42Smrg    vstack->tag = FcVStackInteger;
7972c393a42Smrg    return FcTrue;
7982c393a42Smrg}
7992c393a42Smrg
8002c393a42Smrgstatic FcBool
8012c393a42SmrgFcVStackPushDouble (FcConfigParse *parse, double _double)
8022c393a42Smrg{
803a6844aabSmrg    FcVStack    *vstack = FcVStackCreateAndPush (parse);
8042c393a42Smrg    if (!vstack)
8052c393a42Smrg	return FcFalse;
8062c393a42Smrg    vstack->u._double = _double;
8072c393a42Smrg    vstack->tag = FcVStackDouble;
8082c393a42Smrg    return FcTrue;
8092c393a42Smrg}
8102c393a42Smrg
8112c393a42Smrgstatic FcBool
812c9710b42SmrgFcVStackPushMatrix (FcConfigParse *parse, FcExprMatrix *matrix)
8132c393a42Smrg{
814a6844aabSmrg    FcVStack    *vstack;
815a6844aabSmrg    vstack = FcVStackCreateAndPush (parse);
816a6844aabSmrg    if (!vstack)
817a6844aabSmrg	return FcFalse;
818c9710b42Smrg    vstack->u.matrix = FcExprMatrixCopyShallow (matrix);
8192c393a42Smrg    vstack->tag = FcVStackMatrix;
8202c393a42Smrg    return FcTrue;
8212c393a42Smrg}
8222c393a42Smrg
823ca08ab68Smrgstatic FcBool
824ca08ab68SmrgFcVStackPushRange (FcConfigParse *parse, FcRange *range)
825ca08ab68Smrg{
826ca08ab68Smrg    FcVStack	*vstack = FcVStackCreateAndPush (parse);
827ca08ab68Smrg    if (!vstack)
828ca08ab68Smrg	return FcFalse;
829ca08ab68Smrg    vstack->u.range.begin = range->begin;
830ca08ab68Smrg    vstack->u.range.end = range->end;
831ca08ab68Smrg    vstack->tag = FcVStackRange;
832ca08ab68Smrg    return FcTrue;
833ca08ab68Smrg}
834ca08ab68Smrg
8352c393a42Smrgstatic FcBool
836a6844aabSmrgFcVStackPushBool (FcConfigParse *parse, FcBool bool_)
8372c393a42Smrg{
838a6844aabSmrg    FcVStack    *vstack = FcVStackCreateAndPush (parse);
8392c393a42Smrg    if (!vstack)
8402c393a42Smrg	return FcFalse;
841a6844aabSmrg    vstack->u.bool_ = bool_;
8422c393a42Smrg    vstack->tag = FcVStackBool;
8432c393a42Smrg    return FcTrue;
8442c393a42Smrg}
8452c393a42Smrg
846ca08ab68Smrgstatic FcBool
847ca08ab68SmrgFcVStackPushCharSet (FcConfigParse *parse, FcCharSet *charset)
848ca08ab68Smrg{
849ca08ab68Smrg    FcVStack	*vstack;
850ca08ab68Smrg    if (!charset)
851ca08ab68Smrg	return FcFalse;
852ca08ab68Smrg    vstack = FcVStackCreateAndPush (parse);
853ca08ab68Smrg    if (!vstack)
854ca08ab68Smrg	return FcFalse;
855ca08ab68Smrg    vstack->u.charset = charset;
856ca08ab68Smrg    vstack->tag = FcVStackCharSet;
857ca08ab68Smrg    return FcTrue;
858ca08ab68Smrg}
859ca08ab68Smrg
860ca08ab68Smrgstatic FcBool
861ca08ab68SmrgFcVStackPushLangSet (FcConfigParse *parse, FcLangSet *langset)
862ca08ab68Smrg{
863ca08ab68Smrg    FcVStack	*vstack;
864ca08ab68Smrg    if (!langset)
865ca08ab68Smrg	return FcFalse;
866ca08ab68Smrg    vstack = FcVStackCreateAndPush (parse);
867ca08ab68Smrg    if (!vstack)
868ca08ab68Smrg	return FcFalse;
869ca08ab68Smrg    vstack->u.langset = langset;
870ca08ab68Smrg    vstack->tag = FcVStackLangSet;
871ca08ab68Smrg    return FcTrue;
872ca08ab68Smrg}
873ca08ab68Smrg
874c9710b42Smrgstatic FcBool
875c9710b42SmrgFcVStackPushName (FcConfigParse *parse, FcMatchKind kind, FcObject object)
876c9710b42Smrg{
877c9710b42Smrg    FcVStack    *vstack = FcVStackCreateAndPush (parse);
878c9710b42Smrg    if (!vstack)
879c9710b42Smrg	return FcFalse;
880c9710b42Smrg    vstack->u.name.object = object;
881c9710b42Smrg    vstack->u.name.kind = kind;
882c9710b42Smrg    vstack->tag = FcVStackName;
883c9710b42Smrg    return FcTrue;
884c9710b42Smrg}
885c9710b42Smrg
8862c393a42Smrgstatic FcBool
8872c393a42SmrgFcVStackPushTest (FcConfigParse *parse, FcTest *test)
8882c393a42Smrg{
889a6844aabSmrg    FcVStack    *vstack = FcVStackCreateAndPush (parse);
8902c393a42Smrg    if (!vstack)
8912c393a42Smrg	return FcFalse;
8922c393a42Smrg    vstack->u.test = test;
8932c393a42Smrg    vstack->tag = FcVStackTest;
8942c393a42Smrg    return FcTrue;
8952c393a42Smrg}
8962c393a42Smrg
8972c393a42Smrgstatic FcBool
8982c393a42SmrgFcVStackPushExpr (FcConfigParse *parse, FcVStackTag tag, FcExpr *expr)
8992c393a42Smrg{
900a6844aabSmrg    FcVStack    *vstack = FcVStackCreateAndPush (parse);
9012c393a42Smrg    if (!vstack)
9022c393a42Smrg	return FcFalse;
9032c393a42Smrg    vstack->u.expr = expr;
9042c393a42Smrg    vstack->tag = tag;
9052c393a42Smrg    return FcTrue;
9062c393a42Smrg}
9072c393a42Smrg
9082c393a42Smrgstatic FcBool
9092c393a42SmrgFcVStackPushEdit (FcConfigParse *parse, FcEdit *edit)
9102c393a42Smrg{
911a6844aabSmrg    FcVStack    *vstack = FcVStackCreateAndPush (parse);
9122c393a42Smrg    if (!vstack)
9132c393a42Smrg	return FcFalse;
9142c393a42Smrg    vstack->u.edit = edit;
9152c393a42Smrg    vstack->tag = FcVStackEdit;
9162c393a42Smrg    return FcTrue;
9172c393a42Smrg}
9182c393a42Smrg
9192c393a42Smrgstatic FcBool
9202c393a42SmrgFcVStackPushPattern (FcConfigParse *parse, FcPattern *pattern)
9212c393a42Smrg{
922a6844aabSmrg    FcVStack    *vstack = FcVStackCreateAndPush (parse);
9232c393a42Smrg    if (!vstack)
9242c393a42Smrg	return FcFalse;
9252c393a42Smrg    vstack->u.pattern = pattern;
9262c393a42Smrg    vstack->tag = FcVStackPattern;
9272c393a42Smrg    return FcTrue;
9282c393a42Smrg}
9292c393a42Smrg
9302c393a42Smrgstatic FcVStack *
9312c393a42SmrgFcVStackFetch (FcConfigParse *parse, int off)
9322c393a42Smrg{
9332c393a42Smrg    FcVStack    *vstack;
9342c393a42Smrg
9352c393a42Smrg    for (vstack = parse->vstack; vstack && off-- > 0; vstack = vstack->prev);
9362c393a42Smrg    return vstack;
9372c393a42Smrg}
9382c393a42Smrg
939a6844aabSmrgstatic FcVStack *
940a6844aabSmrgFcVStackPeek (FcConfigParse *parse)
9412c393a42Smrg{
942a6844aabSmrg    FcVStack	*vstack = parse->vstack;
943a6844aabSmrg
944a6844aabSmrg    return vstack && vstack->pstack == parse->pstack ? vstack : 0;
9452c393a42Smrg}
9462c393a42Smrg
947a6844aabSmrgstatic void
948a6844aabSmrgFcVStackPopAndDestroy (FcConfigParse *parse)
9492c393a42Smrg{
9502c393a42Smrg    FcVStack	*vstack = parse->vstack;
951ca08ab68Smrg
9522c393a42Smrg    if (!vstack || vstack->pstack != parse->pstack)
953a6844aabSmrg	return;
954a6844aabSmrg
9552c393a42Smrg    parse->vstack = vstack->prev;
956a6844aabSmrg
957a6844aabSmrg    switch (vstack->tag) {
958a6844aabSmrg    case FcVStackNone:
959a6844aabSmrg	break;
960c9710b42Smrg    case FcVStackName:
961c9710b42Smrg	break;
962a6844aabSmrg    case FcVStackFamily:
963a6844aabSmrg	break;
964a6844aabSmrg    case FcVStackString:
965a6844aabSmrg    case FcVStackConstant:
966a6844aabSmrg    case FcVStackGlob:
967a6844aabSmrg	FcStrFree (vstack->u.string);
968a6844aabSmrg	break;
969a6844aabSmrg    case FcVStackPattern:
970a6844aabSmrg	FcPatternDestroy (vstack->u.pattern);
971a6844aabSmrg	break;
972a6844aabSmrg    case FcVStackInteger:
973a6844aabSmrg    case FcVStackDouble:
974a6844aabSmrg	break;
975a6844aabSmrg    case FcVStackMatrix:
976c9710b42Smrg	FcExprMatrixFreeShallow (vstack->u.matrix);
977a6844aabSmrg	break;
978ca08ab68Smrg    case FcVStackRange:
979a6844aabSmrg    case FcVStackBool:
980a6844aabSmrg	break;
981ca08ab68Smrg    case FcVStackCharSet:
982ca08ab68Smrg	FcCharSetDestroy (vstack->u.charset);
983ca08ab68Smrg	break;
984ca08ab68Smrg    case FcVStackLangSet:
985ca08ab68Smrg	FcLangSetDestroy (vstack->u.langset);
986ca08ab68Smrg	break;
987a6844aabSmrg    case FcVStackTest:
988a6844aabSmrg	FcTestDestroy (vstack->u.test);
989a6844aabSmrg	break;
990a6844aabSmrg    case FcVStackExpr:
991a6844aabSmrg    case FcVStackPrefer:
992a6844aabSmrg    case FcVStackAccept:
993a6844aabSmrg    case FcVStackDefault:
994a6844aabSmrg	FcExprDestroy (vstack->u.expr);
995a6844aabSmrg	break;
996a6844aabSmrg    case FcVStackEdit:
997a6844aabSmrg	FcEditDestroy (vstack->u.edit);
998a6844aabSmrg	break;
999a6844aabSmrg    }
1000a6844aabSmrg
1001a6844aabSmrg    if (vstack == &parse->vstack_static[parse->vstack_static_used - 1])
1002a6844aabSmrg	parse->vstack_static_used--;
1003a6844aabSmrg    else
1004a6844aabSmrg	free (vstack);
1005a6844aabSmrg}
1006a6844aabSmrg
1007a6844aabSmrgstatic void
1008a6844aabSmrgFcVStackClear (FcConfigParse *parse)
1009a6844aabSmrg{
1010a6844aabSmrg    while (FcVStackPeek (parse))
1011a6844aabSmrg	FcVStackPopAndDestroy (parse);
10122c393a42Smrg}
10132c393a42Smrg
10142c393a42Smrgstatic int
10152c393a42SmrgFcVStackElements (FcConfigParse *parse)
10162c393a42Smrg{
10172c393a42Smrg    int		h = 0;
10182c393a42Smrg    FcVStack	*vstack = parse->vstack;
10192c393a42Smrg    while (vstack && vstack->pstack == parse->pstack)
10202c393a42Smrg    {
10212c393a42Smrg	h++;
10222c393a42Smrg	vstack = vstack->prev;
10232c393a42Smrg    }
10242c393a42Smrg    return h;
10252c393a42Smrg}
10262c393a42Smrg
10272c393a42Smrgstatic FcChar8 **
1028a6844aabSmrgFcConfigSaveAttr (const XML_Char **attr, FcChar8 **buf, int size_bytes)
10292c393a42Smrg{
10302c393a42Smrg    int		slen;
10312c393a42Smrg    int		i;
10322c393a42Smrg    FcChar8	**new;
10332c393a42Smrg    FcChar8	*s;
10342c393a42Smrg
10352c393a42Smrg    if (!attr)
10362c393a42Smrg	return 0;
10372c393a42Smrg    slen = 0;
10382c393a42Smrg    for (i = 0; attr[i]; i++)
10392c393a42Smrg	slen += strlen ((char *) attr[i]) + 1;
1040a6844aabSmrg    if (i == 0)
10412c393a42Smrg	return 0;
1042a6844aabSmrg    slen += (i + 1) * sizeof (FcChar8 *);
1043a6844aabSmrg    if (slen <= size_bytes)
1044a6844aabSmrg	new = buf;
1045a6844aabSmrg    else
1046a6844aabSmrg    {
1047a6844aabSmrg	new = malloc (slen);
1048a6844aabSmrg	if (!new)
1049a6844aabSmrg	{
1050a6844aabSmrg	    FcConfigMessage (0, FcSevereError, "out of memory");
1051a6844aabSmrg	    return 0;
1052a6844aabSmrg	}
1053a6844aabSmrg    }
10542c393a42Smrg    s = (FcChar8 *) (new + (i + 1));
10552c393a42Smrg    for (i = 0; attr[i]; i++)
10562c393a42Smrg    {
10572c393a42Smrg	new[i] = s;
10582c393a42Smrg	strcpy ((char *) s, (char *) attr[i]);
10592c393a42Smrg	s += strlen ((char *) s) + 1;
10602c393a42Smrg    }
10612c393a42Smrg    new[i] = 0;
10622c393a42Smrg    return new;
10632c393a42Smrg}
10642c393a42Smrg
10652c393a42Smrgstatic FcBool
10662c393a42SmrgFcPStackPush (FcConfigParse *parse, FcElement element, const XML_Char **attr)
10672c393a42Smrg{
1068a6844aabSmrg    FcPStack   *new;
10692c393a42Smrg
1070a6844aabSmrg    if (parse->pstack_static_used < sizeof (parse->pstack_static) / sizeof (parse->pstack_static[0]))
1071a6844aabSmrg	new = &parse->pstack_static[parse->pstack_static_used++];
1072a6844aabSmrg    else
10732c393a42Smrg    {
1074a6844aabSmrg	new = malloc (sizeof (FcPStack));
1075a6844aabSmrg	if (!new)
10762c393a42Smrg	    return FcFalse;
10772c393a42Smrg    }
1078a6844aabSmrg
1079a6844aabSmrg    new->prev = parse->pstack;
1080a6844aabSmrg    new->element = element;
1081a6844aabSmrg    new->attr = FcConfigSaveAttr (attr, new->attr_buf_static, sizeof (new->attr_buf_static));
10822c393a42Smrg    FcStrBufInit (&new->str, 0, 0);
10832c393a42Smrg    parse->pstack = new;
10842c393a42Smrg    return FcTrue;
10852c393a42Smrg}
10862c393a42Smrg
10872c393a42Smrgstatic FcBool
10882c393a42SmrgFcPStackPop (FcConfigParse *parse)
10892c393a42Smrg{
10902c393a42Smrg    FcPStack   *old;
1091ca08ab68Smrg
1092ca08ab68Smrg    if (!parse->pstack)
10932c393a42Smrg    {
10942c393a42Smrg	FcConfigMessage (parse, FcSevereError, "mismatching element");
10952c393a42Smrg	return FcFalse;
10962c393a42Smrg    }
1097c9710b42Smrg
1098c9710b42Smrg    if (parse->pstack->attr)
1099c9710b42Smrg    {
1100c9710b42Smrg	/* Warn about unused attrs. */
1101c9710b42Smrg	FcChar8 **attrs = parse->pstack->attr;
1102c9710b42Smrg	while (*attrs)
1103c9710b42Smrg	{
1104c9710b42Smrg	    if (attrs[0][0])
1105c9710b42Smrg	    {
1106c9710b42Smrg		FcConfigMessage (parse, FcSevereError, "invalid attribute '%s'", attrs[0]);
1107c9710b42Smrg	    }
1108c9710b42Smrg	    attrs += 2;
1109c9710b42Smrg	}
1110c9710b42Smrg    }
1111c9710b42Smrg
11122c393a42Smrg    FcVStackClear (parse);
11132c393a42Smrg    old = parse->pstack;
11142c393a42Smrg    parse->pstack = old->prev;
11152c393a42Smrg    FcStrBufDestroy (&old->str);
1116c9710b42Smrg
1117a6844aabSmrg    if (old->attr && old->attr != old->attr_buf_static)
11182c393a42Smrg	free (old->attr);
1119a6844aabSmrg
1120a6844aabSmrg    if (old == &parse->pstack_static[parse->pstack_static_used - 1])
1121a6844aabSmrg	parse->pstack_static_used--;
1122a6844aabSmrg    else
1123a6844aabSmrg	free (old);
11242c393a42Smrg    return FcTrue;
11252c393a42Smrg}
11262c393a42Smrg
11272c393a42Smrgstatic FcBool
1128c9710b42SmrgFcConfigParseInit (FcConfigParse *parse, const FcChar8 *name, FcConfig *config, XML_Parser parser)
11292c393a42Smrg{
11302c393a42Smrg    parse->pstack = 0;
1131a6844aabSmrg    parse->pstack_static_used = 0;
11322c393a42Smrg    parse->vstack = 0;
1133a6844aabSmrg    parse->vstack_static_used = 0;
11342c393a42Smrg    parse->error = FcFalse;
11352c393a42Smrg    parse->name = name;
11362c393a42Smrg    parse->config = config;
11372c393a42Smrg    parse->parser = parser;
11382c393a42Smrg    return FcTrue;
11392c393a42Smrg}
11402c393a42Smrg
11412c393a42Smrgstatic void
11422c393a42SmrgFcConfigCleanup (FcConfigParse	*parse)
11432c393a42Smrg{
11442c393a42Smrg    while (parse->pstack)
11452c393a42Smrg	FcPStackPop (parse);
11462c393a42Smrg}
11472c393a42Smrg
11482c393a42Smrgstatic const FcChar8 *
11492c393a42SmrgFcConfigGetAttribute (FcConfigParse *parse, const char *attr)
11502c393a42Smrg{
11512c393a42Smrg    FcChar8 **attrs;
11522c393a42Smrg    if (!parse->pstack)
11532c393a42Smrg	return 0;
11542c393a42Smrg
11552c393a42Smrg    attrs = parse->pstack->attr;
11562c393a42Smrg    if (!attrs)
11572c393a42Smrg        return 0;
11582c393a42Smrg
11592c393a42Smrg    while (*attrs)
11602c393a42Smrg    {
11612c393a42Smrg	if (!strcmp ((char *) *attrs, attr))
1162c9710b42Smrg	{
1163c9710b42Smrg	    attrs[0][0] = '\0'; /* Mark as used. */
11642c393a42Smrg	    return attrs[1];
1165c9710b42Smrg	}
11662c393a42Smrg	attrs += 2;
11672c393a42Smrg    }
11682c393a42Smrg    return 0;
11692c393a42Smrg}
11702c393a42Smrg
11712c393a42Smrgstatic void
11722c393a42SmrgFcStartElement(void *userData, const XML_Char *name, const XML_Char **attr)
11732c393a42Smrg{
11742c393a42Smrg    FcConfigParse   *parse = userData;
11752c393a42Smrg    FcElement	    element;
1176ca08ab68Smrg
11772c393a42Smrg    element = FcElementMap (name);
11782c393a42Smrg    if (element == FcElementUnknown)
11792c393a42Smrg	FcConfigMessage (parse, FcSevereWarning, "unknown element \"%s\"", name);
1180ca08ab68Smrg
11812c393a42Smrg    if (!FcPStackPush (parse, element, attr))
11822c393a42Smrg    {
11832c393a42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
11842c393a42Smrg	return;
11852c393a42Smrg    }
11862c393a42Smrg    return;
11872c393a42Smrg}
11882c393a42Smrg
11892c393a42Smrgstatic void
11902c393a42SmrgFcParseBlank (FcConfigParse *parse)
11912c393a42Smrg{
1192ca08ab68Smrg    int		n = FcVStackElements (parse);
1193ca08ab68Smrg    FcChar32	i;
11942c393a42Smrg    while (n-- > 0)
11952c393a42Smrg    {
11962c393a42Smrg	FcVStack    *v = FcVStackFetch (parse, n);
1197ca08ab68Smrg	if (!parse->config->blanks)
11982c393a42Smrg	{
1199ca08ab68Smrg	    parse->config->blanks = FcBlanksCreate ();
12002c393a42Smrg	    if (!parse->config->blanks)
1201ca08ab68Smrg		goto bail;
1202ca08ab68Smrg	}
1203c9710b42Smrg	switch ((int) v->tag) {
1204ca08ab68Smrg	case FcVStackInteger:
12052c393a42Smrg	    if (!FcBlanksAdd (parse->config->blanks, v->u.integer))
1206ca08ab68Smrg		goto bail;
1207ca08ab68Smrg	    break;
1208ca08ab68Smrg	case FcVStackRange:
1209ca08ab68Smrg	    if (v->u.range.begin <= v->u.range.end)
12102c393a42Smrg	    {
1211ca08ab68Smrg	      for (i = v->u.range.begin; i <= v->u.range.end; i++)
1212ca08ab68Smrg	      {
1213ca08ab68Smrg		  if (!FcBlanksAdd (parse->config->blanks, i))
1214ca08ab68Smrg		      goto bail;
1215ca08ab68Smrg	      }
12162c393a42Smrg	    }
1217ca08ab68Smrg	    break;
1218ca08ab68Smrg	default:
1219ca08ab68Smrg	    FcConfigMessage (parse, FcSevereError, "invalid element in blank");
1220ca08ab68Smrg	    break;
12212c393a42Smrg	}
12222c393a42Smrg    }
1223ca08ab68Smrg    return;
1224ca08ab68Smrg  bail:
1225ca08ab68Smrg    FcConfigMessage (parse, FcSevereError, "out of memory");
12262c393a42Smrg}
12272c393a42Smrg
12282c393a42Smrgstatic void
12292c393a42SmrgFcParseRescan (FcConfigParse *parse)
12302c393a42Smrg{
12312c393a42Smrg    int	    n = FcVStackElements (parse);
12322c393a42Smrg    while (n-- > 0)
12332c393a42Smrg    {
12342c393a42Smrg	FcVStack    *v = FcVStackFetch (parse, n);
12352c393a42Smrg	if (v->tag != FcVStackInteger)
12362c393a42Smrg	    FcConfigMessage (parse, FcSevereWarning, "non-integer rescan");
12372c393a42Smrg	else
12382c393a42Smrg	    parse->config->rescanInterval = v->u.integer;
12392c393a42Smrg    }
12402c393a42Smrg}
12412c393a42Smrg
12422c393a42Smrgstatic void
12432c393a42SmrgFcParseInt (FcConfigParse *parse)
12442c393a42Smrg{
12452c393a42Smrg    FcChar8 *s, *end;
12462c393a42Smrg    int	    l;
1247ca08ab68Smrg
12482c393a42Smrg    if (!parse->pstack)
12492c393a42Smrg	return;
1250a6844aabSmrg    s = FcStrBufDoneStatic (&parse->pstack->str);
12512c393a42Smrg    if (!s)
12522c393a42Smrg    {
12532c393a42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
12542c393a42Smrg	return;
12552c393a42Smrg    }
12562c393a42Smrg    end = 0;
12572c393a42Smrg    l = (int) strtol ((char *) s, (char **)&end, 0);
12582c393a42Smrg    if (end != s + strlen ((char *) s))
12592c393a42Smrg	FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid integer", s);
12602c393a42Smrg    else
12612c393a42Smrg	FcVStackPushInteger (parse, l);
1262a6844aabSmrg    FcStrBufDestroy (&parse->pstack->str);
12632c393a42Smrg}
12642c393a42Smrg
12652c393a42Smrg/*
1266ca08ab68Smrg * idea copied from glib g_ascii_strtod with
1267ca08ab68Smrg * permission of the author (Alexander Larsson)
12682c393a42Smrg */
12692c393a42Smrg
12702c393a42Smrg#include <locale.h>
12712c393a42Smrg
1272ca08ab68Smrgstatic double
12732c393a42SmrgFcStrtod (char *s, char **end)
12742c393a42Smrg{
12752c393a42Smrg    struct lconv    *locale_data;
12762c393a42Smrg    char	    *dot;
12772c393a42Smrg    double	    v;
12782c393a42Smrg
12792c393a42Smrg    /*
12802c393a42Smrg     * Have to swap the decimal point to match the current locale
12812c393a42Smrg     * if that locale doesn't use 0x2e
12822c393a42Smrg     */
12832c393a42Smrg    if ((dot = strchr (s, 0x2e)) &&
12842c393a42Smrg	(locale_data = localeconv ()) &&
12852c393a42Smrg	(locale_data->decimal_point[0] != 0x2e ||
12862c393a42Smrg	 locale_data->decimal_point[1] != 0))
12872c393a42Smrg    {
12882c393a42Smrg	char	buf[128];
12892c393a42Smrg	int	slen = strlen (s);
12902c393a42Smrg	int	dlen = strlen (locale_data->decimal_point);
12912c393a42Smrg
12922c393a42Smrg	if (slen + dlen > (int) sizeof (buf))
12932c393a42Smrg	{
12942c393a42Smrg	    if (end)
12952c393a42Smrg		*end = s;
12962c393a42Smrg	    v = 0;
12972c393a42Smrg	}
12982c393a42Smrg	else
12992c393a42Smrg	{
13002c393a42Smrg	    char	*buf_end;
13012c393a42Smrg	    /* mantissa */
13022c393a42Smrg	    strncpy (buf, s, dot - s);
13032c393a42Smrg	    /* decimal point */
13042c393a42Smrg	    strcpy (buf + (dot - s), locale_data->decimal_point);
13052c393a42Smrg	    /* rest of number */
13062c393a42Smrg	    strcpy (buf + (dot - s) + dlen, dot + 1);
13072c393a42Smrg	    buf_end = 0;
13082c393a42Smrg	    v = strtod (buf, &buf_end);
13092c393a42Smrg	    if (buf_end) {
13102c393a42Smrg		buf_end = s + (buf_end - buf);
13112c393a42Smrg		if (buf_end > dot)
13122c393a42Smrg		    buf_end -= dlen - 1;
13132c393a42Smrg	    }
13142c393a42Smrg	    if (end)
13152c393a42Smrg		*end = buf_end;
13162c393a42Smrg	}
13172c393a42Smrg    }
13182c393a42Smrg    else
13192c393a42Smrg	v = strtod (s, end);
13202c393a42Smrg    return v;
13212c393a42Smrg}
13222c393a42Smrg
13232c393a42Smrgstatic void
13242c393a42SmrgFcParseDouble (FcConfigParse *parse)
13252c393a42Smrg{
13262c393a42Smrg    FcChar8 *s, *end;
13272c393a42Smrg    double  d;
1328ca08ab68Smrg
13292c393a42Smrg    if (!parse->pstack)
13302c393a42Smrg	return;
1331a6844aabSmrg    s = FcStrBufDoneStatic (&parse->pstack->str);
13322c393a42Smrg    if (!s)
13332c393a42Smrg    {
13342c393a42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
13352c393a42Smrg	return;
13362c393a42Smrg    }
13372c393a42Smrg    end = 0;
13382c393a42Smrg    d = FcStrtod ((char *) s, (char **)&end);
13392c393a42Smrg    if (end != s + strlen ((char *) s))
13402c393a42Smrg	FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid double", s);
13412c393a42Smrg    else
13422c393a42Smrg	FcVStackPushDouble (parse, d);
1343a6844aabSmrg    FcStrBufDestroy (&parse->pstack->str);
13442c393a42Smrg}
13452c393a42Smrg
13462c393a42Smrgstatic void
13472c393a42SmrgFcParseString (FcConfigParse *parse, FcVStackTag tag)
13482c393a42Smrg{
13492c393a42Smrg    FcChar8 *s;
1350ca08ab68Smrg
13512c393a42Smrg    if (!parse->pstack)
13522c393a42Smrg	return;
13532c393a42Smrg    s = FcStrBufDone (&parse->pstack->str);
13542c393a42Smrg    if (!s)
13552c393a42Smrg    {
13562c393a42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
13572c393a42Smrg	return;
13582c393a42Smrg    }
13592c393a42Smrg    if (!FcVStackPushString (parse, tag, s))
13602c393a42Smrg	FcStrFree (s);
13612c393a42Smrg}
13622c393a42Smrg
13632c393a42Smrgstatic void
1364c9710b42SmrgFcParseName (FcConfigParse *parse)
13652c393a42Smrg{
1366c9710b42Smrg    const FcChar8   *kind_string;
1367c9710b42Smrg    FcMatchKind	    kind;
1368c9710b42Smrg    FcChar8 *s;
1369c9710b42Smrg    FcObject object;
1370ca08ab68Smrg
1371c9710b42Smrg    kind_string = FcConfigGetAttribute (parse, "target");
1372c9710b42Smrg    if (!kind_string)
1373c9710b42Smrg	kind = FcMatchDefault;
1374c9710b42Smrg    else
13752c393a42Smrg    {
1376c9710b42Smrg	if (!strcmp ((char *) kind_string, "pattern"))
1377c9710b42Smrg	    kind = FcMatchPattern;
1378c9710b42Smrg	else if (!strcmp ((char *) kind_string, "font"))
1379c9710b42Smrg	    kind = FcMatchFont;
1380c9710b42Smrg	else if (!strcmp ((char *) kind_string, "default"))
1381c9710b42Smrg	    kind = FcMatchDefault;
1382c9710b42Smrg	else
1383c9710b42Smrg	{
1384c9710b42Smrg	    FcConfigMessage (parse, FcSevereWarning, "invalid name target \"%s\"", kind_string);
1385c9710b42Smrg	    return;
13862c393a42Smrg	}
13872c393a42Smrg    }
1388c9710b42Smrg
1389c9710b42Smrg    if (!parse->pstack)
1390c9710b42Smrg	return;
1391c9710b42Smrg    s = FcStrBufDone (&parse->pstack->str);
1392c9710b42Smrg    if (!s)
1393c9710b42Smrg    {
1394c9710b42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
1395c9710b42Smrg	return;
1396c9710b42Smrg    }
1397c9710b42Smrg    object = FcObjectFromName ((const char *) s);
1398c9710b42Smrg
1399c9710b42Smrg    FcVStackPushName (parse, kind, object);
1400c9710b42Smrg
1401c9710b42Smrg    FcStrFree (s);
1402c9710b42Smrg}
1403c9710b42Smrg
1404c9710b42Smrgstatic void
1405c9710b42SmrgFcParseMatrix (FcConfigParse *parse)
1406c9710b42Smrg{
1407c9710b42Smrg    FcExprMatrix m;
1408c9710b42Smrg
1409c9710b42Smrg    m.yy = FcPopExpr (parse);
1410c9710b42Smrg    m.yx = FcPopExpr (parse);
1411c9710b42Smrg    m.xy = FcPopExpr (parse);
1412c9710b42Smrg    m.xx = FcPopExpr (parse);
1413c9710b42Smrg
1414c9710b42Smrg    if (FcPopExpr (parse))
1415c9710b42Smrg      FcConfigMessage (parse, FcSevereError, "wrong number of matrix elements");
14162c393a42Smrg    else
1417c9710b42Smrg      FcVStackPushMatrix (parse, &m);
14182c393a42Smrg}
14192c393a42Smrg
1420ca08ab68Smrgstatic void
1421ca08ab68SmrgFcParseRange (FcConfigParse *parse)
1422ca08ab68Smrg{
1423ca08ab68Smrg    FcVStack	*vstack;
1424c9710b42Smrg    FcRange	r = {0, 0};
1425ca08ab68Smrg    FcChar32	n;
1426ca08ab68Smrg    int		count = 1;
1427ca08ab68Smrg
1428ca08ab68Smrg    while ((vstack = FcVStackPeek (parse)))
1429ca08ab68Smrg    {
1430ca08ab68Smrg	if (count < 0)
1431ca08ab68Smrg	{
1432ca08ab68Smrg	    FcConfigMessage (parse, FcSevereError, "too many elements in range");
1433ca08ab68Smrg	    return;
1434ca08ab68Smrg	}
1435c9710b42Smrg	switch ((int) vstack->tag) {
1436ca08ab68Smrg	case FcVStackInteger:
1437ca08ab68Smrg	    n = vstack->u.integer;
1438ca08ab68Smrg	    break;
1439ca08ab68Smrg	default:
1440ca08ab68Smrg	    FcConfigMessage (parse, FcSevereError, "invalid element in range");
1441ca08ab68Smrg	    n = 0;
1442ca08ab68Smrg	    break;
1443ca08ab68Smrg	}
1444ca08ab68Smrg	if (count == 1)
1445ca08ab68Smrg	    r.end = n;
1446ca08ab68Smrg	else
1447ca08ab68Smrg	    r.begin = n;
1448ca08ab68Smrg	count--;
1449ca08ab68Smrg	FcVStackPopAndDestroy (parse);
1450ca08ab68Smrg    }
1451ca08ab68Smrg    if (count < 0)
1452ca08ab68Smrg    {
1453ca08ab68Smrg	if (r.begin > r.end)
1454ca08ab68Smrg	{
1455ca08ab68Smrg	    FcConfigMessage (parse, FcSevereError, "invalid range");
1456ca08ab68Smrg	    return;
1457ca08ab68Smrg	}
1458ca08ab68Smrg	FcVStackPushRange (parse, &r);
1459ca08ab68Smrg    }
1460ca08ab68Smrg    else
1461ca08ab68Smrg	FcConfigMessage (parse, FcSevereError, "invalid range");
1462ca08ab68Smrg}
1463ca08ab68Smrg
14642c393a42Smrgstatic FcBool
1465a6844aabSmrgFcConfigLexBool (FcConfigParse *parse, const FcChar8 *bool_)
14662c393a42Smrg{
14672c393a42Smrg    FcBool  result = FcFalse;
14682c393a42Smrg
1469a6844aabSmrg    if (!FcNameBool (bool_, &result))
14702c393a42Smrg	FcConfigMessage (parse, FcSevereWarning, "\"%s\" is not known boolean",
1471a6844aabSmrg			 bool_);
14722c393a42Smrg    return result;
14732c393a42Smrg}
14742c393a42Smrg
14752c393a42Smrgstatic void
14762c393a42SmrgFcParseBool (FcConfigParse *parse)
14772c393a42Smrg{
14782c393a42Smrg    FcChar8 *s;
14792c393a42Smrg
14802c393a42Smrg    if (!parse->pstack)
14812c393a42Smrg	return;
1482a6844aabSmrg    s = FcStrBufDoneStatic (&parse->pstack->str);
14832c393a42Smrg    if (!s)
14842c393a42Smrg    {
14852c393a42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
14862c393a42Smrg	return;
14872c393a42Smrg    }
14882c393a42Smrg    FcVStackPushBool (parse, FcConfigLexBool (parse, s));
1489a6844aabSmrg    FcStrBufDestroy (&parse->pstack->str);
14902c393a42Smrg}
14912c393a42Smrg
1492ca08ab68Smrgstatic void
1493ca08ab68SmrgFcParseCharSet (FcConfigParse *parse)
1494ca08ab68Smrg{
1495ca08ab68Smrg    FcVStack	*vstack;
1496ca08ab68Smrg    FcCharSet	*charset = FcCharSetCreate ();
1497ca08ab68Smrg    FcChar32	i;
1498ca08ab68Smrg    int n = 0;
1499ca08ab68Smrg
1500ca08ab68Smrg    while ((vstack = FcVStackPeek (parse)))
1501ca08ab68Smrg    {
1502c9710b42Smrg	switch ((int) vstack->tag) {
1503ca08ab68Smrg	case FcVStackInteger:
1504ca08ab68Smrg	    if (!FcCharSetAddChar (charset, vstack->u.integer))
1505ca08ab68Smrg	    {
1506ca08ab68Smrg		FcConfigMessage (parse, FcSevereWarning, "invalid character: 0x%04x", vstack->u.integer);
1507ca08ab68Smrg	    }
1508ca08ab68Smrg	    else
1509ca08ab68Smrg		n++;
1510ca08ab68Smrg	    break;
1511ca08ab68Smrg	case FcVStackRange:
1512ca08ab68Smrg	    if (vstack->u.range.begin <= vstack->u.range.end)
1513ca08ab68Smrg	    {
1514ca08ab68Smrg	      for (i = vstack->u.range.begin; i <= vstack->u.range.end; i++)
1515ca08ab68Smrg	      {
1516ca08ab68Smrg		  if (!FcCharSetAddChar (charset, i))
1517ca08ab68Smrg		  {
1518ca08ab68Smrg		      FcConfigMessage (parse, FcSevereWarning, "invalid character: 0x%04x", i);
1519ca08ab68Smrg		  }
1520ca08ab68Smrg		  else
1521ca08ab68Smrg		      n++;
1522ca08ab68Smrg	      }
1523ca08ab68Smrg	    }
1524ca08ab68Smrg	    break;
1525ca08ab68Smrg	default:
1526ca08ab68Smrg		FcConfigMessage (parse, FcSevereError, "invalid element in charset");
1527ca08ab68Smrg		break;
1528ca08ab68Smrg	}
1529ca08ab68Smrg	FcVStackPopAndDestroy (parse);
1530ca08ab68Smrg    }
1531ca08ab68Smrg    if (n > 0)
1532ca08ab68Smrg	    FcVStackPushCharSet (parse, charset);
1533ca08ab68Smrg    else
1534ca08ab68Smrg	    FcCharSetDestroy (charset);
1535ca08ab68Smrg}
1536ca08ab68Smrg
1537ca08ab68Smrgstatic void
1538ca08ab68SmrgFcParseLangSet (FcConfigParse *parse)
1539ca08ab68Smrg{
1540ca08ab68Smrg    FcVStack	*vstack;
1541ca08ab68Smrg    FcLangSet	*langset = FcLangSetCreate ();
1542ca08ab68Smrg    int n = 0;
1543ca08ab68Smrg
1544ca08ab68Smrg    while ((vstack = FcVStackPeek (parse)))
1545ca08ab68Smrg    {
1546c9710b42Smrg	switch ((int) vstack->tag) {
1547ca08ab68Smrg	case FcVStackString:
1548ca08ab68Smrg	    if (!FcLangSetAdd (langset, vstack->u.string))
1549ca08ab68Smrg	    {
1550ca08ab68Smrg		FcConfigMessage (parse, FcSevereWarning, "invalid langset: %s", vstack->u.string);
1551ca08ab68Smrg	    }
1552ca08ab68Smrg	    else
1553ca08ab68Smrg		n++;
1554ca08ab68Smrg	    break;
1555ca08ab68Smrg	default:
1556ca08ab68Smrg		FcConfigMessage (parse, FcSevereError, "invalid element in langset");
1557ca08ab68Smrg		break;
1558ca08ab68Smrg	}
1559ca08ab68Smrg	FcVStackPopAndDestroy (parse);
1560ca08ab68Smrg    }
1561ca08ab68Smrg    if (n > 0)
1562ca08ab68Smrg	    FcVStackPushLangSet (parse, langset);
1563ca08ab68Smrg    else
1564ca08ab68Smrg	    FcLangSetDestroy (langset);
1565ca08ab68Smrg}
1566ca08ab68Smrg
15672c393a42Smrgstatic FcBool
15682c393a42SmrgFcConfigLexBinding (FcConfigParse   *parse,
15692c393a42Smrg		    const FcChar8   *binding_string,
15702c393a42Smrg		    FcValueBinding  *binding_ret)
15712c393a42Smrg{
15722c393a42Smrg    FcValueBinding binding;
1573ca08ab68Smrg
15742c393a42Smrg    if (!binding_string)
15752c393a42Smrg	binding = FcValueBindingWeak;
15762c393a42Smrg    else
15772c393a42Smrg    {
15782c393a42Smrg	if (!strcmp ((char *) binding_string, "weak"))
15792c393a42Smrg	    binding = FcValueBindingWeak;
15802c393a42Smrg	else if (!strcmp ((char *) binding_string, "strong"))
15812c393a42Smrg	    binding = FcValueBindingStrong;
15822c393a42Smrg	else if (!strcmp ((char *) binding_string, "same"))
15832c393a42Smrg	    binding = FcValueBindingSame;
15842c393a42Smrg	else
15852c393a42Smrg	{
15862c393a42Smrg	    FcConfigMessage (parse, FcSevereWarning, "invalid binding \"%s\"", binding_string);
15872c393a42Smrg	    return FcFalse;
15882c393a42Smrg	}
15892c393a42Smrg    }
15902c393a42Smrg    *binding_ret = binding;
15912c393a42Smrg    return FcTrue;
15922c393a42Smrg}
15932c393a42Smrg
15942c393a42Smrgstatic void
15952c393a42SmrgFcParseFamilies (FcConfigParse *parse, FcVStackTag tag)
15962c393a42Smrg{
15972c393a42Smrg    FcVStack	*vstack;
15982c393a42Smrg    FcExpr	*left, *expr = 0, *new;
15992c393a42Smrg
1600a6844aabSmrg    while ((vstack = FcVStackPeek (parse)))
16012c393a42Smrg    {
16022c393a42Smrg	if (vstack->tag != FcVStackFamily)
16032c393a42Smrg	{
16042c393a42Smrg	    FcConfigMessage (parse, FcSevereWarning, "non-family");
1605a6844aabSmrg	    FcVStackPopAndDestroy (parse);
16062c393a42Smrg	    continue;
16072c393a42Smrg	}
16082c393a42Smrg	left = vstack->u.expr;
16092c393a42Smrg	vstack->tag = FcVStackNone;
1610a6844aabSmrg	FcVStackPopAndDestroy (parse);
16112c393a42Smrg	if (expr)
16122c393a42Smrg	{
1613a6844aabSmrg	    new = FcExprCreateOp (parse->config, left, FcOpComma, expr);
16142c393a42Smrg	    if (!new)
16152c393a42Smrg	    {
16162c393a42Smrg		FcConfigMessage (parse, FcSevereError, "out of memory");
16172c393a42Smrg		FcExprDestroy (left);
16182c393a42Smrg		FcExprDestroy (expr);
16192c393a42Smrg		break;
16202c393a42Smrg	    }
16212c393a42Smrg	    expr = new;
16222c393a42Smrg	}
16232c393a42Smrg	else
16242c393a42Smrg	    expr = left;
16252c393a42Smrg    }
16262c393a42Smrg    if (expr)
16272c393a42Smrg    {
16282c393a42Smrg	if (!FcVStackPushExpr (parse, tag, expr))
16292c393a42Smrg	{
16302c393a42Smrg	    FcConfigMessage (parse, FcSevereError, "out of memory");
16312c393a42Smrg            FcExprDestroy (expr);
16322c393a42Smrg	}
16332c393a42Smrg    }
16342c393a42Smrg}
16352c393a42Smrg
16362c393a42Smrgstatic void
16372c393a42SmrgFcParseFamily (FcConfigParse *parse)
16382c393a42Smrg{
16392c393a42Smrg    FcChar8 *s;
16402c393a42Smrg    FcExpr  *expr;
16412c393a42Smrg
16422c393a42Smrg    if (!parse->pstack)
16432c393a42Smrg	return;
1644a6844aabSmrg    s = FcStrBufDoneStatic (&parse->pstack->str);
16452c393a42Smrg    if (!s)
16462c393a42Smrg    {
16472c393a42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
16482c393a42Smrg	return;
16492c393a42Smrg    }
1650a6844aabSmrg    expr = FcExprCreateString (parse->config, s);
1651a6844aabSmrg    FcStrBufDestroy (&parse->pstack->str);
16522c393a42Smrg    if (expr)
16532c393a42Smrg	FcVStackPushExpr (parse, FcVStackFamily, expr);
16542c393a42Smrg}
16552c393a42Smrg
16562c393a42Smrgstatic void
16572c393a42SmrgFcParseAlias (FcConfigParse *parse)
16582c393a42Smrg{
16592c393a42Smrg    FcExpr	*family = 0, *accept = 0, *prefer = 0, *def = 0, *new = 0;
16602c393a42Smrg    FcEdit	*edit = 0, *next;
16612c393a42Smrg    FcVStack	*vstack;
1662ca08ab68Smrg    FcTest	*test = NULL;
16632c393a42Smrg    FcValueBinding  binding;
16642c393a42Smrg
16652c393a42Smrg    if (!FcConfigLexBinding (parse, FcConfigGetAttribute (parse, "binding"), &binding))
16662c393a42Smrg	return;
1667a6844aabSmrg    while ((vstack = FcVStackPeek (parse)))
16682c393a42Smrg    {
1669c9710b42Smrg	switch ((int) vstack->tag) {
16702c393a42Smrg	case FcVStackFamily:
16712c393a42Smrg	    if (family)
16722c393a42Smrg	    {
1673ca08ab68Smrg		FcConfigMessage (parse, FcSevereWarning, "Having multiple <family> in <alias> isn't supported and may not work as expected");
1674a6844aabSmrg		new = FcExprCreateOp (parse->config, vstack->u.expr, FcOpComma, family);
16752c393a42Smrg		if (!new)
16762c393a42Smrg		    FcConfigMessage (parse, FcSevereError, "out of memory");
16772c393a42Smrg		else
16782c393a42Smrg		    family = new;
16792c393a42Smrg	    }
16802c393a42Smrg	    else
16812c393a42Smrg		new = vstack->u.expr;
16822c393a42Smrg	    if (new)
16832c393a42Smrg	    {
16842c393a42Smrg		family = new;
16852c393a42Smrg		vstack->tag = FcVStackNone;
16862c393a42Smrg	    }
16872c393a42Smrg	    break;
16882c393a42Smrg	case FcVStackPrefer:
16892c393a42Smrg	    if (prefer)
16902c393a42Smrg		FcExprDestroy (prefer);
16912c393a42Smrg	    prefer = vstack->u.expr;
16922c393a42Smrg	    vstack->tag = FcVStackNone;
16932c393a42Smrg	    break;
16942c393a42Smrg	case FcVStackAccept:
16952c393a42Smrg	    if (accept)
16962c393a42Smrg		FcExprDestroy (accept);
16972c393a42Smrg	    accept = vstack->u.expr;
16982c393a42Smrg	    vstack->tag = FcVStackNone;
16992c393a42Smrg	    break;
17002c393a42Smrg	case FcVStackDefault:
17012c393a42Smrg	    if (def)
17022c393a42Smrg		FcExprDestroy (def);
17032c393a42Smrg	    def = vstack->u.expr;
17042c393a42Smrg	    vstack->tag = FcVStackNone;
17052c393a42Smrg	    break;
1706ca08ab68Smrg	case FcVStackTest:
1707ca08ab68Smrg	    vstack->u.test->next = test;
1708ca08ab68Smrg	    test = vstack->u.test;
1709ca08ab68Smrg	    vstack->tag = FcVStackNone;
1710ca08ab68Smrg	    break;
17112c393a42Smrg	default:
17122c393a42Smrg	    FcConfigMessage (parse, FcSevereWarning, "bad alias");
17132c393a42Smrg	    break;
17142c393a42Smrg	}
1715a6844aabSmrg	FcVStackPopAndDestroy (parse);
17162c393a42Smrg    }
17172c393a42Smrg    if (!family)
17182c393a42Smrg    {
17192c393a42Smrg	FcConfigMessage (parse, FcSevereError, "missing family in alias");
17202c393a42Smrg	if (prefer)
17212c393a42Smrg	    FcExprDestroy (prefer);
17222c393a42Smrg	if (accept)
17232c393a42Smrg	    FcExprDestroy (accept);
17242c393a42Smrg	if (def)
17252c393a42Smrg	    FcExprDestroy (def);
17262c393a42Smrg	return;
17272c393a42Smrg    }
17282c393a42Smrg    if (prefer)
17292c393a42Smrg    {
1730ca08ab68Smrg	edit = FcEditCreate (parse,
17312c393a42Smrg			     FC_FAMILY_OBJECT,
17322c393a42Smrg			     FcOpPrepend,
17332c393a42Smrg			     prefer,
17342c393a42Smrg			     binding);
17352c393a42Smrg	if (edit)
17362c393a42Smrg	    edit->next = 0;
17372c393a42Smrg	else
17382c393a42Smrg	    FcExprDestroy (prefer);
17392c393a42Smrg    }
17402c393a42Smrg    if (accept)
17412c393a42Smrg    {
17422c393a42Smrg	next = edit;
17432c393a42Smrg	edit = FcEditCreate (parse,
17442c393a42Smrg			     FC_FAMILY_OBJECT,
17452c393a42Smrg			     FcOpAppend,
17462c393a42Smrg			     accept,
17472c393a42Smrg			     binding);
17482c393a42Smrg	if (edit)
17492c393a42Smrg	    edit->next = next;
17502c393a42Smrg	else
17512c393a42Smrg	    FcExprDestroy (accept);
17522c393a42Smrg    }
17532c393a42Smrg    if (def)
17542c393a42Smrg    {
17552c393a42Smrg	next = edit;
17562c393a42Smrg	edit = FcEditCreate (parse,
17572c393a42Smrg			     FC_FAMILY_OBJECT,
17582c393a42Smrg			     FcOpAppendLast,
17592c393a42Smrg			     def,
17602c393a42Smrg			     binding);
17612c393a42Smrg	if (edit)
17622c393a42Smrg	    edit->next = next;
17632c393a42Smrg	else
17642c393a42Smrg	    FcExprDestroy (def);
17652c393a42Smrg    }
17662c393a42Smrg    if (edit)
17672c393a42Smrg    {
1768ca08ab68Smrg	FcTest *t = FcTestCreate (parse, FcMatchPattern,
1769ca08ab68Smrg				  FcQualAny,
1770ca08ab68Smrg				  (FcChar8 *) FC_FAMILY,
1771ca08ab68Smrg				  FC_OP (FcOpEqual, FcOpFlagIgnoreBlanks),
1772ca08ab68Smrg				  family);
1773ca08ab68Smrg	if (test)
1774ca08ab68Smrg	{
1775ca08ab68Smrg	    FcTest *p = test;
1776ca08ab68Smrg
1777ca08ab68Smrg	    while (p->next)
1778ca08ab68Smrg		p = p->next;
1779ca08ab68Smrg	    p->next = t;
1780ca08ab68Smrg	}
1781ca08ab68Smrg	else
1782ca08ab68Smrg	    test = t;
17832c393a42Smrg	if (test)
17842c393a42Smrg	    if (!FcConfigAddEdit (parse->config, test, edit, FcMatchPattern))
17852c393a42Smrg		FcTestDestroy (test);
17862c393a42Smrg    }
17872c393a42Smrg    else
17882c393a42Smrg	FcExprDestroy (family);
17892c393a42Smrg}
17902c393a42Smrg
17912c393a42Smrgstatic FcExpr *
17922c393a42SmrgFcPopExpr (FcConfigParse *parse)
17932c393a42Smrg{
1794a6844aabSmrg    FcVStack	*vstack = FcVStackPeek (parse);
17952c393a42Smrg    FcExpr	*expr = 0;
17962c393a42Smrg    if (!vstack)
17972c393a42Smrg	return 0;
1798c9710b42Smrg    switch ((int) vstack->tag) {
17992c393a42Smrg    case FcVStackNone:
18002c393a42Smrg	break;
18012c393a42Smrg    case FcVStackString:
18022c393a42Smrg    case FcVStackFamily:
1803a6844aabSmrg	expr = FcExprCreateString (parse->config, vstack->u.string);
18042c393a42Smrg	break;
1805c9710b42Smrg    case FcVStackName:
1806c9710b42Smrg	expr = FcExprCreateName (parse->config, vstack->u.name);
18072c393a42Smrg	break;
18082c393a42Smrg    case FcVStackConstant:
1809a6844aabSmrg	expr = FcExprCreateConst (parse->config, vstack->u.string);
18102c393a42Smrg	break;
18112c393a42Smrg    case FcVStackGlob:
18122c393a42Smrg	/* XXX: What's the correct action here? (CDW) */
18132c393a42Smrg	break;
18142c393a42Smrg    case FcVStackPrefer:
18152c393a42Smrg    case FcVStackAccept:
18162c393a42Smrg    case FcVStackDefault:
18172c393a42Smrg	expr = vstack->u.expr;
18182c393a42Smrg	vstack->tag = FcVStackNone;
18192c393a42Smrg	break;
18202c393a42Smrg    case FcVStackInteger:
1821a6844aabSmrg	expr = FcExprCreateInteger (parse->config, vstack->u.integer);
18222c393a42Smrg	break;
18232c393a42Smrg    case FcVStackDouble:
1824a6844aabSmrg	expr = FcExprCreateDouble (parse->config, vstack->u._double);
18252c393a42Smrg	break;
18262c393a42Smrg    case FcVStackMatrix:
1827a6844aabSmrg	expr = FcExprCreateMatrix (parse->config, vstack->u.matrix);
18282c393a42Smrg	break;
1829ca08ab68Smrg    case FcVStackRange:
1830ca08ab68Smrg	break;
18312c393a42Smrg    case FcVStackBool:
1832a6844aabSmrg	expr = FcExprCreateBool (parse->config, vstack->u.bool_);
18332c393a42Smrg	break;
1834ca08ab68Smrg    case FcVStackCharSet:
1835ca08ab68Smrg	expr = FcExprCreateCharSet (parse->config, vstack->u.charset);
1836ca08ab68Smrg	break;
1837ca08ab68Smrg    case FcVStackLangSet:
1838ca08ab68Smrg	expr = FcExprCreateLangSet (parse->config, vstack->u.langset);
1839ca08ab68Smrg	break;
18402c393a42Smrg    case FcVStackTest:
18412c393a42Smrg	break;
18422c393a42Smrg    case FcVStackExpr:
18432c393a42Smrg	expr = vstack->u.expr;
18442c393a42Smrg	vstack->tag = FcVStackNone;
18452c393a42Smrg	break;
18462c393a42Smrg    case FcVStackEdit:
18472c393a42Smrg	break;
18482c393a42Smrg    default:
18492c393a42Smrg	break;
18502c393a42Smrg    }
1851a6844aabSmrg    FcVStackPopAndDestroy (parse);
18522c393a42Smrg    return expr;
18532c393a42Smrg}
18542c393a42Smrg
18552c393a42Smrg/*
18562c393a42Smrg * This builds a tree of binary operations.  Note
18572c393a42Smrg * that every operator is defined so that if only
18582c393a42Smrg * a single operand is contained, the value of the
18592c393a42Smrg * whole expression is the value of the operand.
18602c393a42Smrg *
18612c393a42Smrg * This code reduces in that case to returning that
18622c393a42Smrg * operand.
18632c393a42Smrg */
18642c393a42Smrgstatic FcExpr *
18652c393a42SmrgFcPopBinary (FcConfigParse *parse, FcOp op)
18662c393a42Smrg{
18672c393a42Smrg    FcExpr  *left, *expr = 0, *new;
18682c393a42Smrg
18692c393a42Smrg    while ((left = FcPopExpr (parse)))
18702c393a42Smrg    {
18712c393a42Smrg	if (expr)
18722c393a42Smrg	{
1873a6844aabSmrg	    new = FcExprCreateOp (parse->config, left, op, expr);
18742c393a42Smrg	    if (!new)
18752c393a42Smrg	    {
18762c393a42Smrg		FcConfigMessage (parse, FcSevereError, "out of memory");
18772c393a42Smrg		FcExprDestroy (left);
18782c393a42Smrg		FcExprDestroy (expr);
18792c393a42Smrg		return 0;
18802c393a42Smrg	    }
18812c393a42Smrg	    expr = new;
18822c393a42Smrg	}
18832c393a42Smrg	else
18842c393a42Smrg	    expr = left;
18852c393a42Smrg    }
18862c393a42Smrg    return expr;
18872c393a42Smrg}
18882c393a42Smrg
18892c393a42Smrgstatic void
18902c393a42SmrgFcParseBinary (FcConfigParse *parse, FcOp op)
18912c393a42Smrg{
18922c393a42Smrg    FcExpr  *expr = FcPopBinary (parse, op);
18932c393a42Smrg    if (expr)
18942c393a42Smrg	FcVStackPushExpr (parse, FcVStackExpr, expr);
18952c393a42Smrg}
18962c393a42Smrg
18972c393a42Smrg/*
18982c393a42Smrg * This builds a a unary operator, it consumes only
18992c393a42Smrg * a single operand
19002c393a42Smrg */
19012c393a42Smrg
19022c393a42Smrgstatic FcExpr *
19032c393a42SmrgFcPopUnary (FcConfigParse *parse, FcOp op)
19042c393a42Smrg{
19052c393a42Smrg    FcExpr  *operand, *new = 0;
19062c393a42Smrg
19072c393a42Smrg    if ((operand = FcPopExpr (parse)))
19082c393a42Smrg    {
1909a6844aabSmrg	new = FcExprCreateOp (parse->config, operand, op, 0);
19102c393a42Smrg	if (!new)
19112c393a42Smrg	{
19122c393a42Smrg	    FcExprDestroy (operand);
19132c393a42Smrg	    FcConfigMessage (parse, FcSevereError, "out of memory");
19142c393a42Smrg	}
19152c393a42Smrg    }
19162c393a42Smrg    return new;
19172c393a42Smrg}
19182c393a42Smrg
19192c393a42Smrgstatic void
19202c393a42SmrgFcParseUnary (FcConfigParse *parse, FcOp op)
19212c393a42Smrg{
19222c393a42Smrg    FcExpr  *expr = FcPopUnary (parse, op);
19232c393a42Smrg    if (expr)
19242c393a42Smrg	FcVStackPushExpr (parse, FcVStackExpr, expr);
19252c393a42Smrg}
19262c393a42Smrg
1927ca08ab68Smrgstatic void
1928ca08ab68SmrgFcParseDir (FcConfigParse *parse)
1929ca08ab68Smrg{
1930ca08ab68Smrg    const FcChar8 *attr, *data;
1931c9710b42Smrg    FcChar8 *prefix = NULL, *p;
1932ca08ab68Smrg#ifdef _WIN32
1933ca08ab68Smrg    FcChar8         buffer[1000];
1934ca08ab68Smrg#endif
1935ca08ab68Smrg
1936ca08ab68Smrg    attr = FcConfigGetAttribute (parse, "prefix");
1937ca08ab68Smrg    if (attr && FcStrCmp (attr, (const FcChar8 *)"xdg") == 0)
1938ca08ab68Smrg	prefix = FcConfigXdgDataHome ();
1939ca08ab68Smrg    data = FcStrBufDoneStatic (&parse->pstack->str);
1940ca08ab68Smrg    if (!data)
1941ca08ab68Smrg    {
1942ca08ab68Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
1943c9710b42Smrg	data = prefix;
1944ca08ab68Smrg	goto bail;
1945ca08ab68Smrg    }
1946ca08ab68Smrg    if (prefix)
1947ca08ab68Smrg    {
1948ca08ab68Smrg	size_t plen = strlen ((const char *)prefix);
1949ca08ab68Smrg	size_t dlen = strlen ((const char *)data);
1950ca08ab68Smrg
1951c9710b42Smrg	p = realloc (prefix, plen + 1 + dlen + 1);
1952c9710b42Smrg	if (!p)
1953ca08ab68Smrg	{
1954ca08ab68Smrg	    FcConfigMessage (parse, FcSevereError, "out of memory");
1955ca08ab68Smrg	    goto bail;
1956ca08ab68Smrg	}
1957c9710b42Smrg	prefix = p;
1958ca08ab68Smrg	prefix[plen] = FC_DIR_SEPARATOR;
1959ca08ab68Smrg	memcpy (&prefix[plen + 1], data, dlen);
1960ca08ab68Smrg	prefix[plen + 1 + dlen] = 0;
1961ca08ab68Smrg	data = prefix;
1962ca08ab68Smrg    }
1963ca08ab68Smrg#ifdef _WIN32
1964ca08ab68Smrg    if (strcmp ((const char *) data, "CUSTOMFONTDIR") == 0)
1965ca08ab68Smrg    {
1966c9710b42Smrg	FcChar8 *p;
1967ca08ab68Smrg	data = buffer;
1968ca08ab68Smrg	if (!GetModuleFileName (NULL, (LPCH) buffer, sizeof (buffer) - 20))
1969ca08ab68Smrg	{
1970ca08ab68Smrg	    FcConfigMessage (parse, FcSevereError, "GetModuleFileName failed");
1971ca08ab68Smrg	    goto bail;
1972ca08ab68Smrg	}
1973ca08ab68Smrg	/*
1974ca08ab68Smrg	 * Must use the multi-byte aware function to search
1975ca08ab68Smrg	 * for backslash because East Asian double-byte code
1976ca08ab68Smrg	 * pages have characters with backslash as the second
1977ca08ab68Smrg	 * byte.
1978ca08ab68Smrg	 */
1979ca08ab68Smrg	p = _mbsrchr (data, '\\');
1980ca08ab68Smrg	if (p) *p = '\0';
1981c9710b42Smrg	strcat ((char *) data, "\\fonts");
1982ca08ab68Smrg    }
1983ca08ab68Smrg    else if (strcmp ((const char *) data, "APPSHAREFONTDIR") == 0)
1984ca08ab68Smrg    {
1985c9710b42Smrg	FcChar8 *p;
1986ca08ab68Smrg	data = buffer;
1987ca08ab68Smrg	if (!GetModuleFileName (NULL, (LPCH) buffer, sizeof (buffer) - 20))
1988ca08ab68Smrg	{
1989ca08ab68Smrg	    FcConfigMessage (parse, FcSevereError, "GetModuleFileName failed");
1990ca08ab68Smrg	    goto bail;
1991ca08ab68Smrg	}
1992ca08ab68Smrg	p = _mbsrchr (data, '\\');
1993ca08ab68Smrg	if (p) *p = '\0';
1994c9710b42Smrg	strcat ((char *) data, "\\..\\share\\fonts");
1995ca08ab68Smrg    }
1996ca08ab68Smrg    else if (strcmp ((const char *) data, "WINDOWSFONTDIR") == 0)
1997ca08ab68Smrg    {
1998ca08ab68Smrg	int rc;
1999ca08ab68Smrg	data = buffer;
2000ca08ab68Smrg	rc = pGetSystemWindowsDirectory ((LPSTR) buffer, sizeof (buffer) - 20);
2001ca08ab68Smrg	if (rc == 0 || rc > sizeof (buffer) - 20)
2002ca08ab68Smrg	{
2003ca08ab68Smrg	    FcConfigMessage (parse, FcSevereError, "GetSystemWindowsDirectory failed");
2004ca08ab68Smrg	    goto bail;
2005ca08ab68Smrg	}
2006ca08ab68Smrg	if (data [strlen ((const char *) data) - 1] != '\\')
2007c9710b42Smrg	    strcat ((char *) data, "\\");
2008c9710b42Smrg	strcat ((char *) data, "fonts");
2009ca08ab68Smrg    }
2010ca08ab68Smrg#endif
2011ca08ab68Smrg    if (strlen ((char *) data) == 0)
2012ca08ab68Smrg	FcConfigMessage (parse, FcSevereWarning, "empty font directory name ignored");
2013ca08ab68Smrg    else if (!FcStrUsesHome (data) || FcConfigHome ())
2014ca08ab68Smrg    {
2015ca08ab68Smrg	if (!FcConfigAddDir (parse->config, data))
2016ca08ab68Smrg	    FcConfigMessage (parse, FcSevereError, "out of memory; cannot add directory %s", data);
2017ca08ab68Smrg    }
2018ca08ab68Smrg    FcStrBufDestroy (&parse->pstack->str);
2019ca08ab68Smrg
2020ca08ab68Smrg  bail:
2021ca08ab68Smrg    if (prefix)
2022ca08ab68Smrg	FcStrFree (prefix);
2023ca08ab68Smrg}
2024ca08ab68Smrg
2025ca08ab68Smrgstatic void
2026ca08ab68SmrgFcParseCacheDir (FcConfigParse *parse)
2027ca08ab68Smrg{
2028ca08ab68Smrg    const FcChar8 *attr;
2029c9710b42Smrg    FcChar8 *prefix = NULL, *p, *data;
2030ca08ab68Smrg
2031ca08ab68Smrg    attr = FcConfigGetAttribute (parse, "prefix");
2032ca08ab68Smrg    if (attr && FcStrCmp (attr, (const FcChar8 *)"xdg") == 0)
2033ca08ab68Smrg	prefix = FcConfigXdgCacheHome ();
2034ca08ab68Smrg    data = FcStrBufDone (&parse->pstack->str);
2035ca08ab68Smrg    if (!data)
2036ca08ab68Smrg    {
2037ca08ab68Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
2038ca08ab68Smrg	goto bail;
2039ca08ab68Smrg    }
2040ca08ab68Smrg    if (prefix)
2041ca08ab68Smrg    {
2042ca08ab68Smrg	size_t plen = strlen ((const char *)prefix);
2043ca08ab68Smrg	size_t dlen = strlen ((const char *)data);
2044ca08ab68Smrg
2045c9710b42Smrg	p = realloc (prefix, plen + 1 + dlen + 1);
2046c9710b42Smrg	if (!p)
2047ca08ab68Smrg	{
2048ca08ab68Smrg	    FcConfigMessage (parse, FcSevereError, "out of memory");
2049c9710b42Smrg	    data = prefix;
2050ca08ab68Smrg	    goto bail;
2051ca08ab68Smrg	}
2052c9710b42Smrg	prefix = p;
2053ca08ab68Smrg	prefix[plen] = FC_DIR_SEPARATOR;
2054ca08ab68Smrg	memcpy (&prefix[plen + 1], data, dlen);
2055ca08ab68Smrg	prefix[plen + 1 + dlen] = 0;
2056ca08ab68Smrg	FcStrFree (data);
2057ca08ab68Smrg	data = prefix;
2058ca08ab68Smrg    }
2059ca08ab68Smrg#ifdef _WIN32
2060ca08ab68Smrg    if (strcmp ((const char *) data, "WINDOWSTEMPDIR_FONTCONFIG_CACHE") == 0)
2061ca08ab68Smrg    {
2062ca08ab68Smrg	int rc;
2063ca08ab68Smrg	FcStrFree (data);
2064ca08ab68Smrg	data = malloc (1000);
2065ca08ab68Smrg	if (!data)
2066ca08ab68Smrg	{
2067ca08ab68Smrg	    FcConfigMessage (parse, FcSevereError, "out of memory");
2068ca08ab68Smrg	    goto bail;
2069ca08ab68Smrg	}
2070ca08ab68Smrg	rc = GetTempPath (800, (LPSTR) data);
2071ca08ab68Smrg	if (rc == 0 || rc > 800)
2072ca08ab68Smrg	{
2073ca08ab68Smrg	    FcConfigMessage (parse, FcSevereError, "GetTempPath failed");
2074ca08ab68Smrg	    goto bail;
2075ca08ab68Smrg	}
2076ca08ab68Smrg	if (data [strlen ((const char *) data) - 1] != '\\')
2077c9710b42Smrg	    strcat ((char *) data, "\\");
2078c9710b42Smrg	strcat ((char *) data, "fontconfig\\cache");
2079ca08ab68Smrg    }
2080ca08ab68Smrg    else if (strcmp ((const char *) data, "LOCAL_APPDATA_FONTCONFIG_CACHE") == 0)
2081ca08ab68Smrg    {
2082ca08ab68Smrg	char szFPath[MAX_PATH + 1];
2083ca08ab68Smrg	size_t len;
2084ca08ab68Smrg
2085ca08ab68Smrg	if (!(pSHGetFolderPathA && SUCCEEDED(pSHGetFolderPathA(NULL, /* CSIDL_LOCAL_APPDATA */ 28, NULL, 0, szFPath))))
2086ca08ab68Smrg	{
2087ca08ab68Smrg	    FcConfigMessage (parse, FcSevereError, "SHGetFolderPathA failed");
2088ca08ab68Smrg	    goto bail;
2089ca08ab68Smrg	}
2090ca08ab68Smrg	strncat(szFPath, "\\fontconfig\\cache", MAX_PATH - 1 - strlen(szFPath));
2091ca08ab68Smrg	len = strlen(szFPath) + 1;
2092ca08ab68Smrg	FcStrFree (data);
2093ca08ab68Smrg	data = malloc(len);
2094ca08ab68Smrg	if (!data)
2095ca08ab68Smrg	{
2096ca08ab68Smrg	    FcConfigMessage (parse, FcSevereError, "out of memory");
2097ca08ab68Smrg	    goto bail;
2098ca08ab68Smrg	}
2099ca08ab68Smrg	strncpy((char *) data, szFPath, len);
2100ca08ab68Smrg    }
2101ca08ab68Smrg#endif
2102ca08ab68Smrg    if (strlen ((char *) data) == 0)
2103ca08ab68Smrg	FcConfigMessage (parse, FcSevereWarning, "empty cache directory name ignored");
2104ca08ab68Smrg    else if (!FcStrUsesHome (data) || FcConfigHome ())
2105ca08ab68Smrg    {
2106ca08ab68Smrg	if (!FcConfigAddCacheDir (parse->config, data))
2107ca08ab68Smrg	    FcConfigMessage (parse, FcSevereError, "out of memory; cannot add cache directory %s", data);
2108ca08ab68Smrg    }
2109ca08ab68Smrg    FcStrBufDestroy (&parse->pstack->str);
2110ca08ab68Smrg
2111ca08ab68Smrg  bail:
2112ca08ab68Smrg    if (data)
2113ca08ab68Smrg	FcStrFree (data);
2114ca08ab68Smrg}
2115ca08ab68Smrg
21162c393a42Smrgstatic void
21172c393a42SmrgFcParseInclude (FcConfigParse *parse)
21182c393a42Smrg{
21192c393a42Smrg    FcChar8	    *s;
2120ca08ab68Smrg    const FcChar8   *attr;
21212c393a42Smrg    FcBool	    ignore_missing = FcFalse;
2122ca08ab68Smrg    FcBool	    deprecated = FcFalse;
2123c9710b42Smrg    FcChar8	    *prefix = NULL, *p;
2124ca08ab68Smrg
2125a6844aabSmrg    s = FcStrBufDoneStatic (&parse->pstack->str);
21262c393a42Smrg    if (!s)
21272c393a42Smrg    {
21282c393a42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
2129ca08ab68Smrg	goto bail;
21302c393a42Smrg    }
2131ca08ab68Smrg    attr = FcConfigGetAttribute (parse, "ignore_missing");
2132ca08ab68Smrg    if (attr && FcConfigLexBool (parse, (FcChar8 *) attr) == FcTrue)
21332c393a42Smrg	ignore_missing = FcTrue;
2134ca08ab68Smrg    attr = FcConfigGetAttribute (parse, "deprecated");
2135ca08ab68Smrg    if (attr && FcConfigLexBool (parse, (FcChar8 *) attr) == FcTrue)
2136ca08ab68Smrg        deprecated = FcTrue;
2137ca08ab68Smrg    attr = FcConfigGetAttribute (parse, "prefix");
2138ca08ab68Smrg    if (attr && FcStrCmp (attr, (const FcChar8 *)"xdg") == 0)
2139ca08ab68Smrg	prefix = FcConfigXdgConfigHome ();
2140ca08ab68Smrg    if (prefix)
2141ca08ab68Smrg    {
2142ca08ab68Smrg	size_t plen = strlen ((const char *)prefix);
2143ca08ab68Smrg	size_t dlen = strlen ((const char *)s);
2144ca08ab68Smrg
2145c9710b42Smrg	p = realloc (prefix, plen + 1 + dlen + 1);
2146c9710b42Smrg	if (!p)
2147ca08ab68Smrg	{
2148ca08ab68Smrg	    FcConfigMessage (parse, FcSevereError, "out of memory");
2149ca08ab68Smrg	    goto bail;
2150ca08ab68Smrg	}
2151c9710b42Smrg	prefix = p;
2152ca08ab68Smrg	prefix[plen] = FC_DIR_SEPARATOR;
2153ca08ab68Smrg	memcpy (&prefix[plen + 1], s, dlen);
2154ca08ab68Smrg	prefix[plen + 1 + dlen] = 0;
2155ca08ab68Smrg	s = prefix;
2156ca08ab68Smrg    }
21572c393a42Smrg    if (!FcConfigParseAndLoad (parse->config, s, !ignore_missing))
21582c393a42Smrg	parse->error = FcTrue;
2159ca08ab68Smrg    else
2160ca08ab68Smrg    {
2161ca08ab68Smrg        FcChar8 *filename;
2162ca08ab68Smrg
2163ca08ab68Smrg        filename = FcConfigFilename(s);
2164c9710b42Smrg	if (deprecated == FcTrue &&
2165c9710b42Smrg	    filename != NULL &&
2166c9710b42Smrg	    !FcFileIsLink (filename))
2167c9710b42Smrg	{
2168ca08ab68Smrg            FcConfigMessage (parse, FcSevereWarning, "reading configurations from %s is deprecated.", s);
2169ca08ab68Smrg        }
2170ca08ab68Smrg        if(filename)
2171ca08ab68Smrg            FcStrFree(filename);
2172ca08ab68Smrg    }
2173a6844aabSmrg    FcStrBufDestroy (&parse->pstack->str);
2174ca08ab68Smrg
2175ca08ab68Smrg  bail:
2176ca08ab68Smrg    if (prefix)
2177ca08ab68Smrg	FcStrFree (prefix);
21782c393a42Smrg}
21792c393a42Smrg
21802c393a42Smrgtypedef struct _FcOpMap {
21812c393a42Smrg    char    name[16];
21822c393a42Smrg    FcOp    op;
21832c393a42Smrg} FcOpMap;
21842c393a42Smrg
21852c393a42Smrgstatic FcOp
21862c393a42SmrgFcConfigLexOp (const FcChar8 *op, const FcOpMap	*map, int nmap)
21872c393a42Smrg{
21882c393a42Smrg    int	i;
21892c393a42Smrg
21902c393a42Smrg    for (i = 0; i < nmap; i++)
2191ca08ab68Smrg	if (!strcmp ((char *) op, map[i].name))
21922c393a42Smrg	    return map[i].op;
21932c393a42Smrg    return FcOpInvalid;
21942c393a42Smrg}
21952c393a42Smrg
21962c393a42Smrgstatic const FcOpMap fcCompareOps[] = {
21972c393a42Smrg    { "eq",		FcOpEqual	    },
21982c393a42Smrg    { "not_eq",		FcOpNotEqual	    },
21992c393a42Smrg    { "less",		FcOpLess	    },
22002c393a42Smrg    { "less_eq",	FcOpLessEqual	    },
22012c393a42Smrg    { "more",		FcOpMore	    },
22022c393a42Smrg    { "more_eq",	FcOpMoreEqual	    },
22032c393a42Smrg    { "contains",	FcOpContains	    },
22042c393a42Smrg    { "not_contains",	FcOpNotContains	    }
22052c393a42Smrg};
22062c393a42Smrg
22072c393a42Smrg#define NUM_COMPARE_OPS	(int) (sizeof fcCompareOps / sizeof fcCompareOps[0])
22082c393a42Smrg
22092c393a42Smrgstatic FcOp
22102c393a42SmrgFcConfigLexCompare (const FcChar8 *compare)
22112c393a42Smrg{
22122c393a42Smrg    return FcConfigLexOp (compare, fcCompareOps, NUM_COMPARE_OPS);
22132c393a42Smrg}
22142c393a42Smrg
22152c393a42Smrgstatic void
22162c393a42SmrgFcParseTest (FcConfigParse *parse)
22172c393a42Smrg{
22182c393a42Smrg    const FcChar8   *kind_string;
22192c393a42Smrg    FcMatchKind	    kind;
22202c393a42Smrg    const FcChar8   *qual_string;
22212c393a42Smrg    FcQual	    qual;
22222c393a42Smrg    const FcChar8   *name;
22232c393a42Smrg    const FcChar8   *compare_string;
22242c393a42Smrg    FcOp	    compare;
22252c393a42Smrg    FcExpr	    *expr;
22262c393a42Smrg    FcTest	    *test;
2227ca08ab68Smrg    const FcChar8   *iblanks_string;
2228ca08ab68Smrg    int              flags = 0;
22292c393a42Smrg
22302c393a42Smrg    kind_string = FcConfigGetAttribute (parse, "target");
22312c393a42Smrg    if (!kind_string)
22322c393a42Smrg	kind = FcMatchDefault;
22332c393a42Smrg    else
22342c393a42Smrg    {
22352c393a42Smrg	if (!strcmp ((char *) kind_string, "pattern"))
22362c393a42Smrg	    kind = FcMatchPattern;
22372c393a42Smrg	else if (!strcmp ((char *) kind_string, "font"))
22382c393a42Smrg	    kind = FcMatchFont;
22392c393a42Smrg	else if (!strcmp ((char *) kind_string, "scan"))
22402c393a42Smrg	    kind = FcMatchScan;
22412c393a42Smrg	else if (!strcmp ((char *) kind_string, "default"))
22422c393a42Smrg	    kind = FcMatchDefault;
22432c393a42Smrg	else
22442c393a42Smrg	{
22452c393a42Smrg	    FcConfigMessage (parse, FcSevereWarning, "invalid test target \"%s\"", kind_string);
22462c393a42Smrg	    return;
22472c393a42Smrg	}
22482c393a42Smrg    }
22492c393a42Smrg    qual_string = FcConfigGetAttribute (parse, "qual");
22502c393a42Smrg    if (!qual_string)
22512c393a42Smrg	qual = FcQualAny;
22522c393a42Smrg    else
22532c393a42Smrg    {
22542c393a42Smrg	if (!strcmp ((char *) qual_string, "any"))
22552c393a42Smrg	    qual = FcQualAny;
22562c393a42Smrg	else if (!strcmp ((char *) qual_string, "all"))
22572c393a42Smrg	    qual = FcQualAll;
22582c393a42Smrg	else if (!strcmp ((char *) qual_string, "first"))
22592c393a42Smrg	    qual = FcQualFirst;
22602c393a42Smrg	else if (!strcmp ((char *) qual_string, "not_first"))
22612c393a42Smrg	    qual = FcQualNotFirst;
22622c393a42Smrg	else
22632c393a42Smrg	{
22642c393a42Smrg	    FcConfigMessage (parse, FcSevereWarning, "invalid test qual \"%s\"", qual_string);
22652c393a42Smrg	    return;
22662c393a42Smrg	}
22672c393a42Smrg    }
22682c393a42Smrg    name = FcConfigGetAttribute (parse, "name");
22692c393a42Smrg    if (!name)
22702c393a42Smrg    {
22712c393a42Smrg	FcConfigMessage (parse, FcSevereWarning, "missing test name");
22722c393a42Smrg	return;
22732c393a42Smrg    }
22742c393a42Smrg    compare_string = FcConfigGetAttribute (parse, "compare");
22752c393a42Smrg    if (!compare_string)
22762c393a42Smrg	compare = FcOpEqual;
22772c393a42Smrg    else
22782c393a42Smrg    {
22792c393a42Smrg	compare = FcConfigLexCompare (compare_string);
22802c393a42Smrg	if (compare == FcOpInvalid)
22812c393a42Smrg	{
22822c393a42Smrg	    FcConfigMessage (parse, FcSevereWarning, "invalid test compare \"%s\"", compare_string);
22832c393a42Smrg	    return;
22842c393a42Smrg	}
22852c393a42Smrg    }
2286ca08ab68Smrg    iblanks_string = FcConfigGetAttribute (parse, "ignore-blanks");
2287ca08ab68Smrg    if (iblanks_string)
2288ca08ab68Smrg    {
2289ca08ab68Smrg	FcBool f = FcFalse;
2290ca08ab68Smrg
2291ca08ab68Smrg	if (!FcNameBool (iblanks_string, &f))
2292ca08ab68Smrg	{
2293ca08ab68Smrg	    FcConfigMessage (parse,
2294ca08ab68Smrg			     FcSevereWarning,
2295ca08ab68Smrg			     "invalid test ignore-blanks \"%s\"", iblanks_string);
2296ca08ab68Smrg	}
2297ca08ab68Smrg	if (f)
2298ca08ab68Smrg	    flags |= FcOpFlagIgnoreBlanks;
2299ca08ab68Smrg    }
23002c393a42Smrg    expr = FcPopBinary (parse, FcOpComma);
23012c393a42Smrg    if (!expr)
23022c393a42Smrg    {
23032c393a42Smrg	FcConfigMessage (parse, FcSevereWarning, "missing test expression");
23042c393a42Smrg	return;
23052c393a42Smrg    }
2306ca08ab68Smrg    if (expr->op == FcOpComma)
2307ca08ab68Smrg    {
2308ca08ab68Smrg	FcConfigMessage (parse, FcSevereWarning, "Having multiple values in <test> isn't supported and may not work as expected");
2309ca08ab68Smrg    }
2310ca08ab68Smrg    test = FcTestCreate (parse, kind, qual, name, FC_OP (compare, flags), expr);
23112c393a42Smrg    if (!test)
23122c393a42Smrg    {
23132c393a42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
23142c393a42Smrg	return;
23152c393a42Smrg    }
23162c393a42Smrg    FcVStackPushTest (parse, test);
23172c393a42Smrg}
23182c393a42Smrg
23192c393a42Smrgstatic const FcOpMap fcModeOps[] = {
23202c393a42Smrg    { "assign",		FcOpAssign	    },
23212c393a42Smrg    { "assign_replace",	FcOpAssignReplace   },
23222c393a42Smrg    { "prepend",	FcOpPrepend	    },
23232c393a42Smrg    { "prepend_first",	FcOpPrependFirst    },
23242c393a42Smrg    { "append",		FcOpAppend	    },
23252c393a42Smrg    { "append_last",	FcOpAppendLast	    },
2326c9710b42Smrg    { "delete",		FcOpDelete	    },
2327c9710b42Smrg    { "delete_all",	FcOpDeleteAll	    },
23282c393a42Smrg};
23292c393a42Smrg
23302c393a42Smrg#define NUM_MODE_OPS (int) (sizeof fcModeOps / sizeof fcModeOps[0])
23312c393a42Smrg
23322c393a42Smrgstatic FcOp
23332c393a42SmrgFcConfigLexMode (const FcChar8 *mode)
23342c393a42Smrg{
23352c393a42Smrg    return FcConfigLexOp (mode, fcModeOps, NUM_MODE_OPS);
23362c393a42Smrg}
23372c393a42Smrg
23382c393a42Smrgstatic void
23392c393a42SmrgFcParseEdit (FcConfigParse *parse)
23402c393a42Smrg{
23412c393a42Smrg    const FcChar8   *name;
23422c393a42Smrg    const FcChar8   *mode_string;
23432c393a42Smrg    FcOp	    mode;
23442c393a42Smrg    FcValueBinding  binding;
23452c393a42Smrg    FcExpr	    *expr;
23462c393a42Smrg    FcEdit	    *edit;
23472c393a42Smrg
23482c393a42Smrg    name = FcConfigGetAttribute (parse, "name");
23492c393a42Smrg    if (!name)
23502c393a42Smrg    {
23512c393a42Smrg	FcConfigMessage (parse, FcSevereWarning, "missing edit name");
23522c393a42Smrg	return;
23532c393a42Smrg    }
23542c393a42Smrg    mode_string = FcConfigGetAttribute (parse, "mode");
23552c393a42Smrg    if (!mode_string)
23562c393a42Smrg	mode = FcOpAssign;
23572c393a42Smrg    else
23582c393a42Smrg    {
23592c393a42Smrg	mode = FcConfigLexMode (mode_string);
23602c393a42Smrg	if (mode == FcOpInvalid)
23612c393a42Smrg	{
23622c393a42Smrg	    FcConfigMessage (parse, FcSevereWarning, "invalid edit mode \"%s\"", mode_string);
23632c393a42Smrg	    return;
23642c393a42Smrg	}
23652c393a42Smrg    }
23662c393a42Smrg    if (!FcConfigLexBinding (parse, FcConfigGetAttribute (parse, "binding"), &binding))
23672c393a42Smrg	return;
23682c393a42Smrg
23692c393a42Smrg    expr = FcPopBinary (parse, FcOpComma);
2370c9710b42Smrg    if ((mode == FcOpDelete || mode == FcOpDeleteAll) &&
2371c9710b42Smrg	expr != NULL)
2372c9710b42Smrg    {
2373c9710b42Smrg	FcConfigMessage (parse, FcSevereWarning, "Expression doesn't take any effects for delete and delete_all");
2374c9710b42Smrg	FcExprDestroy (expr);
2375c9710b42Smrg	expr = NULL;
2376c9710b42Smrg    }
23772c393a42Smrg    edit = FcEditCreate (parse, FcObjectFromName ((char *) name),
23782c393a42Smrg			 mode, expr, binding);
23792c393a42Smrg    if (!edit)
23802c393a42Smrg    {
23812c393a42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
23822c393a42Smrg	FcExprDestroy (expr);
23832c393a42Smrg	return;
23842c393a42Smrg    }
23852c393a42Smrg    if (!FcVStackPushEdit (parse, edit))
23862c393a42Smrg	FcEditDestroy (edit);
23872c393a42Smrg}
23882c393a42Smrg
2389c9710b42Smrgtypedef struct FcSubstStack {
2390c9710b42Smrg    FcTest *test;
2391c9710b42Smrg    FcEdit *edit;
2392c9710b42Smrg} FcSubstStack;
2393c9710b42Smrg
23942c393a42Smrgstatic void
23952c393a42SmrgFcParseMatch (FcConfigParse *parse)
23962c393a42Smrg{
23972c393a42Smrg    const FcChar8   *kind_name;
23982c393a42Smrg    FcMatchKind	    kind;
23992c393a42Smrg    FcTest	    *test = 0;
24002c393a42Smrg    FcEdit	    *edit = 0;
24012c393a42Smrg    FcVStack	    *vstack;
2402c9710b42Smrg    FcBool           tested = FcFalse;
2403c9710b42Smrg    FcSubstStack    *sstack = NULL;
2404c9710b42Smrg    int              len, pos = 0;
24052c393a42Smrg
24062c393a42Smrg    kind_name = FcConfigGetAttribute (parse, "target");
24072c393a42Smrg    if (!kind_name)
24082c393a42Smrg	kind = FcMatchPattern;
24092c393a42Smrg    else
24102c393a42Smrg    {
24112c393a42Smrg	if (!strcmp ((char *) kind_name, "pattern"))
24122c393a42Smrg	    kind = FcMatchPattern;
24132c393a42Smrg	else if (!strcmp ((char *) kind_name, "font"))
24142c393a42Smrg	    kind = FcMatchFont;
24152c393a42Smrg	else if (!strcmp ((char *) kind_name, "scan"))
24162c393a42Smrg	    kind = FcMatchScan;
24172c393a42Smrg	else
24182c393a42Smrg	{
24192c393a42Smrg	    FcConfigMessage (parse, FcSevereWarning, "invalid match target \"%s\"", kind_name);
24202c393a42Smrg	    return;
24212c393a42Smrg	}
24222c393a42Smrg    }
2423c9710b42Smrg    len = FcVStackElements(parse);
2424c9710b42Smrg    if (len > 0)
2425c9710b42Smrg    {
2426c9710b42Smrg	sstack = malloc (sizeof (FcSubstStack) * (len + 1));
2427c9710b42Smrg	if (!sstack)
2428c9710b42Smrg	{
2429c9710b42Smrg	    FcConfigMessage (parse, FcSevereError, "out of memory");
2430c9710b42Smrg	    return;
2431c9710b42Smrg	}
2432c9710b42Smrg    }
2433a6844aabSmrg    while ((vstack = FcVStackPeek (parse)))
24342c393a42Smrg    {
2435c9710b42Smrg	switch ((int) vstack->tag) {
24362c393a42Smrg	case FcVStackTest:
24372c393a42Smrg	    vstack->u.test->next = test;
24382c393a42Smrg	    test = vstack->u.test;
24392c393a42Smrg	    vstack->tag = FcVStackNone;
2440c9710b42Smrg	    tested = FcTrue;
24412c393a42Smrg	    break;
24422c393a42Smrg	case FcVStackEdit:
2443c9710b42Smrg	    /* due to the reverse traversal, <edit> node appears faster than
2444c9710b42Smrg	     * <test> node if any. so we have to deal with it here rather than
2445c9710b42Smrg	     * the above in FcVStackTest, and put recipes in reverse order.
2446c9710b42Smrg	     */
2447c9710b42Smrg	    if (tested)
2448c9710b42Smrg	    {
2449c9710b42Smrg		sstack[pos].test = test;
2450c9710b42Smrg		sstack[pos].edit = edit;
2451c9710b42Smrg		pos++;
2452c9710b42Smrg		test = NULL;
2453c9710b42Smrg		edit = NULL;
2454c9710b42Smrg		tested = FcFalse;
2455c9710b42Smrg	    }
24562c393a42Smrg	    vstack->u.edit->next = edit;
24572c393a42Smrg	    edit = vstack->u.edit;
24582c393a42Smrg	    vstack->tag = FcVStackNone;
24592c393a42Smrg	    if (kind == FcMatchScan && edit->object > FC_MAX_BASE_OBJECT)
24602c393a42Smrg	    {
2461ca08ab68Smrg		FcConfigMessage (parse, FcSevereError,
24622c393a42Smrg				 "<match target=\"scan\"> cannot edit user-defined object \"%s\"",
24632c393a42Smrg				 FcObjectName(edit->object));
24642c393a42Smrg	    }
24652c393a42Smrg	    break;
24662c393a42Smrg	default:
24672c393a42Smrg	    FcConfigMessage (parse, FcSevereWarning, "invalid match element");
24682c393a42Smrg	    break;
24692c393a42Smrg	}
2470a6844aabSmrg	FcVStackPopAndDestroy (parse);
24712c393a42Smrg    }
24722c393a42Smrg    if (!FcConfigAddEdit (parse->config, test, edit, kind))
24732c393a42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
2474c9710b42Smrg    if (sstack)
2475c9710b42Smrg    {
2476c9710b42Smrg	int i;
2477c9710b42Smrg
2478c9710b42Smrg	for (i = 0; i < pos; i++)
2479c9710b42Smrg	{
2480c9710b42Smrg	    if (!FcConfigAddEdit (parse->config, sstack[pos - i - 1].test, sstack[pos - i - 1].edit, kind))
2481c9710b42Smrg	    {
2482c9710b42Smrg		FcConfigMessage (parse, FcSevereError, "out of memory");
2483c9710b42Smrg		return;
2484c9710b42Smrg	    }
2485c9710b42Smrg	}
2486c9710b42Smrg	free (sstack);
2487c9710b42Smrg    }
24882c393a42Smrg}
24892c393a42Smrg
24902c393a42Smrgstatic void
24912c393a42SmrgFcParseAcceptRejectFont (FcConfigParse *parse, FcElement element)
24922c393a42Smrg{
24932c393a42Smrg    FcVStack	*vstack;
24942c393a42Smrg
2495a6844aabSmrg    while ((vstack = FcVStackPeek (parse)))
24962c393a42Smrg    {
2497c9710b42Smrg	switch ((int) vstack->tag) {
24982c393a42Smrg	case FcVStackGlob:
2499ca08ab68Smrg	    if (!FcConfigGlobAdd (parse->config,
25002c393a42Smrg				  vstack->u.string,
25012c393a42Smrg				  element == FcElementAcceptfont))
25022c393a42Smrg	    {
25032c393a42Smrg		FcConfigMessage (parse, FcSevereError, "out of memory");
25042c393a42Smrg	    }
25052c393a42Smrg	    break;
25062c393a42Smrg	case FcVStackPattern:
25072c393a42Smrg	    if (!FcConfigPatternsAdd (parse->config,
25082c393a42Smrg				      vstack->u.pattern,
25092c393a42Smrg				      element == FcElementAcceptfont))
25102c393a42Smrg	    {
25112c393a42Smrg		FcConfigMessage (parse, FcSevereError, "out of memory");
25122c393a42Smrg	    }
25132c393a42Smrg	    else
25142c393a42Smrg		vstack->tag = FcVStackNone;
25152c393a42Smrg	    break;
25162c393a42Smrg	default:
25172c393a42Smrg	    FcConfigMessage (parse, FcSevereWarning, "bad font selector");
25182c393a42Smrg	    break;
25192c393a42Smrg	}
2520a6844aabSmrg	FcVStackPopAndDestroy (parse);
25212c393a42Smrg    }
25222c393a42Smrg}
25232c393a42Smrg
25242c393a42Smrg
25252c393a42Smrgstatic FcValue
25262c393a42SmrgFcPopValue (FcConfigParse *parse)
25272c393a42Smrg{
2528a6844aabSmrg    FcVStack	*vstack = FcVStackPeek (parse);
25292c393a42Smrg    FcValue	value;
2530ca08ab68Smrg
25312c393a42Smrg    value.type = FcTypeVoid;
2532ca08ab68Smrg
25332c393a42Smrg    if (!vstack)
25342c393a42Smrg	return value;
2535ca08ab68Smrg
2536c9710b42Smrg    switch ((int) vstack->tag) {
25372c393a42Smrg    case FcVStackString:
2538c9710b42Smrg	value.u.s = FcStrdup (vstack->u.string);
25392c393a42Smrg	if (value.u.s)
25402c393a42Smrg	    value.type = FcTypeString;
25412c393a42Smrg	break;
25422c393a42Smrg    case FcVStackConstant:
25432c393a42Smrg	if (FcNameConstant (vstack->u.string, &value.u.i))
25442c393a42Smrg	    value.type = FcTypeInteger;
25452c393a42Smrg	break;
25462c393a42Smrg    case FcVStackInteger:
25472c393a42Smrg	value.u.i = vstack->u.integer;
25482c393a42Smrg	value.type = FcTypeInteger;
25492c393a42Smrg	break;
25502c393a42Smrg    case FcVStackDouble:
25512c393a42Smrg	value.u.d = vstack->u._double;
2552c9710b42Smrg	value.type = FcTypeDouble;
25532c393a42Smrg	break;
25542c393a42Smrg    case FcVStackBool:
2555a6844aabSmrg	value.u.b = vstack->u.bool_;
25562c393a42Smrg	value.type = FcTypeBool;
25572c393a42Smrg	break;
2558ca08ab68Smrg    case FcVStackCharSet:
2559ca08ab68Smrg	value.u.c = FcCharSetCopy (vstack->u.charset);
2560ca08ab68Smrg	if (value.u.c)
2561ca08ab68Smrg	    value.type = FcTypeCharSet;
2562ca08ab68Smrg	break;
2563ca08ab68Smrg    case FcVStackLangSet:
2564ca08ab68Smrg	value.u.l = FcLangSetCopy (vstack->u.langset);
2565ca08ab68Smrg	if (value.u.l)
2566ca08ab68Smrg	    value.type = FcTypeLangSet;
2567ca08ab68Smrg	break;
25682c393a42Smrg    default:
2569ca08ab68Smrg	FcConfigMessage (parse, FcSevereWarning, "unknown pattern element %d",
25702c393a42Smrg			 vstack->tag);
25712c393a42Smrg	break;
25722c393a42Smrg    }
2573a6844aabSmrg    FcVStackPopAndDestroy (parse);
2574ca08ab68Smrg
25752c393a42Smrg    return value;
25762c393a42Smrg}
25772c393a42Smrg
25782c393a42Smrgstatic void
25792c393a42SmrgFcParsePatelt (FcConfigParse *parse)
25802c393a42Smrg{
25812c393a42Smrg    FcValue	value;
25822c393a42Smrg    FcPattern	*pattern = FcPatternCreate ();
25832c393a42Smrg    const char	*name;
25842c393a42Smrg
25852c393a42Smrg    if (!pattern)
25862c393a42Smrg    {
25872c393a42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
25882c393a42Smrg	return;
25892c393a42Smrg    }
25902c393a42Smrg
25912c393a42Smrg    name = (char *) FcConfigGetAttribute (parse, "name");
25922c393a42Smrg    if (!name)
25932c393a42Smrg    {
25942c393a42Smrg	FcConfigMessage (parse, FcSevereWarning, "missing pattern element name");
25952c393a42Smrg	FcPatternDestroy (pattern);
25962c393a42Smrg	return;
25972c393a42Smrg    }
2598ca08ab68Smrg
25992c393a42Smrg    for (;;)
26002c393a42Smrg    {
26012c393a42Smrg	value = FcPopValue (parse);
26022c393a42Smrg	if (value.type == FcTypeVoid)
26032c393a42Smrg	    break;
26042c393a42Smrg	if (!FcPatternAdd (pattern, name, value, FcTrue))
26052c393a42Smrg	{
26062c393a42Smrg	    FcConfigMessage (parse, FcSevereError, "out of memory");
2607a6844aabSmrg            FcValueDestroy(value);
26082c393a42Smrg	    break;
26092c393a42Smrg	}
2610a6844aabSmrg        FcValueDestroy(value);
26112c393a42Smrg    }
26122c393a42Smrg
26132c393a42Smrg    FcVStackPushPattern (parse, pattern);
26142c393a42Smrg}
26152c393a42Smrg
26162c393a42Smrgstatic void
26172c393a42SmrgFcParsePattern (FcConfigParse *parse)
26182c393a42Smrg{
26192c393a42Smrg    FcVStack	*vstack;
26202c393a42Smrg    FcPattern	*pattern = FcPatternCreate ();
26212c393a42Smrg
26222c393a42Smrg    if (!pattern)
26232c393a42Smrg    {
26242c393a42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
26252c393a42Smrg	return;
26262c393a42Smrg    }
26272c393a42Smrg
2628a6844aabSmrg    while ((vstack = FcVStackPeek (parse)))
26292c393a42Smrg    {
2630c9710b42Smrg	switch ((int) vstack->tag) {
26312c393a42Smrg	case FcVStackPattern:
26322c393a42Smrg	    if (!FcPatternAppend (pattern, vstack->u.pattern))
26332c393a42Smrg	    {
26342c393a42Smrg		FcConfigMessage (parse, FcSevereError, "out of memory");
26352c393a42Smrg		FcPatternDestroy (pattern);
26362c393a42Smrg		return;
26372c393a42Smrg	    }
26382c393a42Smrg	    break;
26392c393a42Smrg	default:
26402c393a42Smrg	    FcConfigMessage (parse, FcSevereWarning, "unknown pattern element");
26412c393a42Smrg	    break;
26422c393a42Smrg	}
2643a6844aabSmrg	FcVStackPopAndDestroy (parse);
26442c393a42Smrg    }
26452c393a42Smrg
26462c393a42Smrg    FcVStackPushPattern (parse, pattern);
26472c393a42Smrg}
26482c393a42Smrg
26492c393a42Smrgstatic void
2650c9710b42SmrgFcEndElement(void *userData, const XML_Char *name FC_UNUSED)
26512c393a42Smrg{
26522c393a42Smrg    FcConfigParse   *parse = userData;
26532c393a42Smrg    FcChar8	    *data;
2654a6844aabSmrg
26552c393a42Smrg    if (!parse->pstack)
26562c393a42Smrg	return;
26572c393a42Smrg    switch (parse->pstack->element) {
26582c393a42Smrg    case FcElementNone:
26592c393a42Smrg	break;
26602c393a42Smrg    case FcElementFontconfig:
26612c393a42Smrg	break;
26622c393a42Smrg    case FcElementDir:
2663ca08ab68Smrg	FcParseDir (parse);
26642c393a42Smrg	break;
26652c393a42Smrg    case FcElementCacheDir:
2666ca08ab68Smrg	FcParseCacheDir (parse);
26672c393a42Smrg	break;
26682c393a42Smrg    case FcElementCache:
2669a6844aabSmrg	data = FcStrBufDoneStatic (&parse->pstack->str);
26702c393a42Smrg	if (!data)
26712c393a42Smrg	{
26722c393a42Smrg	    FcConfigMessage (parse, FcSevereError, "out of memory");
26732c393a42Smrg	    break;
26742c393a42Smrg	}
26752c393a42Smrg	/* discard this data; no longer used */
2676a6844aabSmrg	FcStrBufDestroy (&parse->pstack->str);
26772c393a42Smrg	break;
26782c393a42Smrg    case FcElementInclude:
26792c393a42Smrg	FcParseInclude (parse);
26802c393a42Smrg	break;
26812c393a42Smrg    case FcElementConfig:
26822c393a42Smrg	break;
26832c393a42Smrg    case FcElementMatch:
26842c393a42Smrg	FcParseMatch (parse);
26852c393a42Smrg	break;
26862c393a42Smrg    case FcElementAlias:
26872c393a42Smrg	FcParseAlias (parse);
26882c393a42Smrg	break;
26892c393a42Smrg
26902c393a42Smrg    case FcElementBlank:
26912c393a42Smrg	FcParseBlank (parse);
26922c393a42Smrg	break;
26932c393a42Smrg    case FcElementRescan:
26942c393a42Smrg	FcParseRescan (parse);
26952c393a42Smrg	break;
26962c393a42Smrg
26972c393a42Smrg    case FcElementPrefer:
26982c393a42Smrg	FcParseFamilies (parse, FcVStackPrefer);
26992c393a42Smrg	break;
27002c393a42Smrg    case FcElementAccept:
27012c393a42Smrg	FcParseFamilies (parse, FcVStackAccept);
27022c393a42Smrg	break;
27032c393a42Smrg    case FcElementDefault:
27042c393a42Smrg	FcParseFamilies (parse, FcVStackDefault);
27052c393a42Smrg	break;
27062c393a42Smrg    case FcElementFamily:
27072c393a42Smrg	FcParseFamily (parse);
27082c393a42Smrg	break;
27092c393a42Smrg
27102c393a42Smrg    case FcElementTest:
27112c393a42Smrg	FcParseTest (parse);
27122c393a42Smrg	break;
27132c393a42Smrg    case FcElementEdit:
27142c393a42Smrg	FcParseEdit (parse);
27152c393a42Smrg	break;
27162c393a42Smrg
27172c393a42Smrg    case FcElementInt:
27182c393a42Smrg	FcParseInt (parse);
27192c393a42Smrg	break;
27202c393a42Smrg    case FcElementDouble:
27212c393a42Smrg	FcParseDouble (parse);
27222c393a42Smrg	break;
27232c393a42Smrg    case FcElementString:
27242c393a42Smrg	FcParseString (parse, FcVStackString);
27252c393a42Smrg	break;
27262c393a42Smrg    case FcElementMatrix:
27272c393a42Smrg	FcParseMatrix (parse);
27282c393a42Smrg	break;
2729ca08ab68Smrg    case FcElementRange:
2730ca08ab68Smrg	FcParseRange (parse);
2731ca08ab68Smrg	break;
27322c393a42Smrg    case FcElementBool:
27332c393a42Smrg	FcParseBool (parse);
27342c393a42Smrg	break;
2735ca08ab68Smrg    case FcElementCharSet:
2736ca08ab68Smrg	FcParseCharSet (parse);
2737ca08ab68Smrg	break;
2738ca08ab68Smrg    case FcElementLangSet:
2739ca08ab68Smrg	FcParseLangSet (parse);
27402c393a42Smrg	break;
27412c393a42Smrg    case FcElementSelectfont:
27422c393a42Smrg	break;
27432c393a42Smrg    case FcElementAcceptfont:
27442c393a42Smrg    case FcElementRejectfont:
27452c393a42Smrg	FcParseAcceptRejectFont (parse, parse->pstack->element);
27462c393a42Smrg	break;
27472c393a42Smrg    case FcElementGlob:
27482c393a42Smrg	FcParseString (parse, FcVStackGlob);
27492c393a42Smrg	break;
27502c393a42Smrg    case FcElementPattern:
27512c393a42Smrg	FcParsePattern (parse);
27522c393a42Smrg	break;
27532c393a42Smrg    case FcElementPatelt:
27542c393a42Smrg	FcParsePatelt (parse);
27552c393a42Smrg	break;
27562c393a42Smrg    case FcElementName:
2757c9710b42Smrg	FcParseName (parse);
27582c393a42Smrg	break;
27592c393a42Smrg    case FcElementConst:
27602c393a42Smrg	FcParseString (parse, FcVStackConstant);
27612c393a42Smrg	break;
27622c393a42Smrg    case FcElementOr:
27632c393a42Smrg	FcParseBinary (parse, FcOpOr);
27642c393a42Smrg	break;
27652c393a42Smrg    case FcElementAnd:
27662c393a42Smrg	FcParseBinary (parse, FcOpAnd);
27672c393a42Smrg	break;
27682c393a42Smrg    case FcElementEq:
27692c393a42Smrg	FcParseBinary (parse, FcOpEqual);
27702c393a42Smrg	break;
27712c393a42Smrg    case FcElementNotEq:
27722c393a42Smrg	FcParseBinary (parse, FcOpNotEqual);
27732c393a42Smrg	break;
27742c393a42Smrg    case FcElementLess:
27752c393a42Smrg	FcParseBinary (parse, FcOpLess);
27762c393a42Smrg	break;
27772c393a42Smrg    case FcElementLessEq:
27782c393a42Smrg	FcParseBinary (parse, FcOpLessEqual);
27792c393a42Smrg	break;
27802c393a42Smrg    case FcElementMore:
27812c393a42Smrg	FcParseBinary (parse, FcOpMore);
27822c393a42Smrg	break;
27832c393a42Smrg    case FcElementMoreEq:
27842c393a42Smrg	FcParseBinary (parse, FcOpMoreEqual);
27852c393a42Smrg	break;
27862c393a42Smrg    case FcElementContains:
27872c393a42Smrg	FcParseBinary (parse, FcOpContains);
27882c393a42Smrg	break;
27892c393a42Smrg    case FcElementNotContains:
27902c393a42Smrg	FcParseBinary (parse, FcOpNotContains);
27912c393a42Smrg	break;
27922c393a42Smrg    case FcElementPlus:
27932c393a42Smrg	FcParseBinary (parse, FcOpPlus);
27942c393a42Smrg	break;
27952c393a42Smrg    case FcElementMinus:
27962c393a42Smrg	FcParseBinary (parse, FcOpMinus);
27972c393a42Smrg	break;
27982c393a42Smrg    case FcElementTimes:
27992c393a42Smrg	FcParseBinary (parse, FcOpTimes);
28002c393a42Smrg	break;
28012c393a42Smrg    case FcElementDivide:
28022c393a42Smrg	FcParseBinary (parse, FcOpDivide);
28032c393a42Smrg	break;
28042c393a42Smrg    case FcElementNot:
28052c393a42Smrg	FcParseUnary (parse, FcOpNot);
28062c393a42Smrg	break;
28072c393a42Smrg    case FcElementIf:
28082c393a42Smrg	FcParseBinary (parse, FcOpQuest);
28092c393a42Smrg	break;
28102c393a42Smrg    case FcElementFloor:
28112c393a42Smrg	FcParseUnary (parse, FcOpFloor);
28122c393a42Smrg	break;
28132c393a42Smrg    case FcElementCeil:
28142c393a42Smrg	FcParseUnary (parse, FcOpCeil);
28152c393a42Smrg	break;
28162c393a42Smrg    case FcElementRound:
28172c393a42Smrg	FcParseUnary (parse, FcOpRound);
28182c393a42Smrg	break;
28192c393a42Smrg    case FcElementTrunc:
28202c393a42Smrg	FcParseUnary (parse, FcOpTrunc);
28212c393a42Smrg	break;
28222c393a42Smrg    case FcElementUnknown:
28232c393a42Smrg	break;
28242c393a42Smrg    }
28252c393a42Smrg    (void) FcPStackPop (parse);
28262c393a42Smrg}
28272c393a42Smrg
28282c393a42Smrgstatic void
28292c393a42SmrgFcCharacterData (void *userData, const XML_Char *s, int len)
28302c393a42Smrg{
28312c393a42Smrg    FcConfigParse   *parse = userData;
2832ca08ab68Smrg
28332c393a42Smrg    if (!parse->pstack)
28342c393a42Smrg	return;
28352c393a42Smrg    if (!FcStrBufData (&parse->pstack->str, (FcChar8 *) s, len))
28362c393a42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
28372c393a42Smrg}
28382c393a42Smrg
28392c393a42Smrgstatic void
28402c393a42SmrgFcStartDoctypeDecl (void	    *userData,
28412c393a42Smrg		    const XML_Char  *doctypeName,
2842c9710b42Smrg		    const XML_Char  *sysid FC_UNUSED,
2843c9710b42Smrg		    const XML_Char  *pubid FC_UNUSED,
2844c9710b42Smrg		    int		    has_internal_subset FC_UNUSED)
28452c393a42Smrg{
28462c393a42Smrg    FcConfigParse   *parse = userData;
28472c393a42Smrg
28482c393a42Smrg    if (strcmp ((char *) doctypeName, "fontconfig") != 0)
28492c393a42Smrg	FcConfigMessage (parse, FcSevereError, "invalid doctype \"%s\"", doctypeName);
28502c393a42Smrg}
28512c393a42Smrg
28522c393a42Smrg#ifdef ENABLE_LIBXML2
28532c393a42Smrg
28542c393a42Smrgstatic void
28552c393a42SmrgFcInternalSubsetDecl (void            *userData,
28562c393a42Smrg		      const XML_Char  *doctypeName,
28572c393a42Smrg		      const XML_Char  *sysid,
28582c393a42Smrg		      const XML_Char  *pubid)
28592c393a42Smrg{
28602c393a42Smrg    FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 1);
28612c393a42Smrg}
28622c393a42Smrg
28632c393a42Smrgstatic void
28642c393a42SmrgFcExternalSubsetDecl (void            *userData,
28652c393a42Smrg		      const XML_Char  *doctypeName,
28662c393a42Smrg		      const XML_Char  *sysid,
28672c393a42Smrg		      const XML_Char  *pubid)
28682c393a42Smrg{
28692c393a42Smrg    FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 0);
28702c393a42Smrg}
28712c393a42Smrg
28722c393a42Smrg#else /* ENABLE_LIBXML2 */
28732c393a42Smrg
28742c393a42Smrgstatic void
2875c9710b42SmrgFcEndDoctypeDecl (void *userData FC_UNUSED)
28762c393a42Smrg{
28772c393a42Smrg}
28782c393a42Smrg
28792c393a42Smrg#endif /* ENABLE_LIBXML2 */
28802c393a42Smrg
28812c393a42Smrgstatic int
28822c393a42SmrgFcSortCmpStr (const void *a, const void *b)
28832c393a42Smrg{
28842c393a42Smrg    const FcChar8    *as = *((FcChar8 **) a);
28852c393a42Smrg    const FcChar8    *bs = *((FcChar8 **) b);
28862c393a42Smrg    return FcStrCmp (as, bs);
28872c393a42Smrg}
28882c393a42Smrg
28892c393a42Smrgstatic FcBool
28902c393a42SmrgFcConfigParseAndLoadDir (FcConfig	*config,
28912c393a42Smrg			 const FcChar8	*name,
28922c393a42Smrg			 const FcChar8	*dir,
28932c393a42Smrg			 FcBool		complain)
28942c393a42Smrg{
28952c393a42Smrg    DIR		    *d;
28962c393a42Smrg    struct dirent   *e;
28972c393a42Smrg    FcBool	    ret = FcTrue;
28982c393a42Smrg    FcChar8	    *file;
28992c393a42Smrg    FcChar8	    *base;
29002c393a42Smrg    FcStrSet	    *files;
29012c393a42Smrg
29022c393a42Smrg    d = opendir ((char *) dir);
29032c393a42Smrg    if (!d)
29042c393a42Smrg    {
29052c393a42Smrg	if (complain)
29062c393a42Smrg	    FcConfigMessage (0, FcSevereError, "Cannot open config dir \"%s\"",
29072c393a42Smrg			     name);
29082c393a42Smrg	ret = FcFalse;
29092c393a42Smrg	goto bail0;
29102c393a42Smrg    }
29112c393a42Smrg    /* freed below */
29122c393a42Smrg    file = (FcChar8 *) malloc (strlen ((char *) dir) + 1 + FC_MAX_FILE_LEN + 1);
29132c393a42Smrg    if (!file)
29142c393a42Smrg    {
29152c393a42Smrg	ret = FcFalse;
29162c393a42Smrg	goto bail1;
29172c393a42Smrg    }
2918ca08ab68Smrg
29192c393a42Smrg    strcpy ((char *) file, (char *) dir);
29202c393a42Smrg    strcat ((char *) file, "/");
29212c393a42Smrg    base = file + strlen ((char *) file);
2922ca08ab68Smrg
29232c393a42Smrg    files = FcStrSetCreate ();
29242c393a42Smrg    if (!files)
29252c393a42Smrg    {
29262c393a42Smrg	ret = FcFalse;
29272c393a42Smrg	goto bail2;
29282c393a42Smrg    }
2929ca08ab68Smrg
29302c393a42Smrg    if (FcDebug () & FC_DBG_CONFIG)
29312c393a42Smrg	printf ("\tScanning config dir %s\n", dir);
29322c393a42Smrg
29332c393a42Smrg    while (ret && (e = readdir (d)))
29342c393a42Smrg    {
29352c393a42Smrg	int d_len;
29362c393a42Smrg#define TAIL	    ".conf"
29372c393a42Smrg#define TAIL_LEN    5
29382c393a42Smrg	/*
29392c393a42Smrg	 * Add all files of the form [0-9]*.conf
29402c393a42Smrg	 */
29412c393a42Smrg	if ('0' <= e->d_name[0] && e->d_name[0] <= '9' &&
29422c393a42Smrg	    (d_len = strlen (e->d_name)) < FC_MAX_FILE_LEN &&
29432c393a42Smrg	    d_len > TAIL_LEN &&
29442c393a42Smrg	    strcmp (e->d_name + d_len - TAIL_LEN, TAIL) == 0)
29452c393a42Smrg	{
29462c393a42Smrg	    strcpy ((char *) base, (char *) e->d_name);
29472c393a42Smrg	    if (!FcStrSetAdd (files, file))
29482c393a42Smrg	    {
29492c393a42Smrg		ret = FcFalse;
29502c393a42Smrg		goto bail3;
29512c393a42Smrg	    }
29522c393a42Smrg	}
29532c393a42Smrg    }
29542c393a42Smrg    if (ret)
29552c393a42Smrg    {
29562c393a42Smrg	int i;
2957ca08ab68Smrg	qsort (files->strs, files->num, sizeof (FcChar8 *),
29582c393a42Smrg	       (int (*)(const void *, const void *)) FcSortCmpStr);
29592c393a42Smrg	for (i = 0; ret && i < files->num; i++)
29602c393a42Smrg	    ret = FcConfigParseAndLoad (config, files->strs[i], complain);
29612c393a42Smrg    }
29622c393a42Smrgbail3:
29632c393a42Smrg    FcStrSetDestroy (files);
29642c393a42Smrgbail2:
29652c393a42Smrg    free (file);
29662c393a42Smrgbail1:
29672c393a42Smrg    closedir (d);
29682c393a42Smrgbail0:
29692c393a42Smrg    return ret || !complain;
29702c393a42Smrg}
29712c393a42Smrg
2972ca08ab68Smrg#ifdef _WIN32
2973ca08ab68SmrgpfnGetSystemWindowsDirectory pGetSystemWindowsDirectory = NULL;
2974ca08ab68SmrgpfnSHGetFolderPathA pSHGetFolderPathA = NULL;
2975ca08ab68Smrg#endif
2976ca08ab68Smrg
29772c393a42SmrgFcBool
29782c393a42SmrgFcConfigParseAndLoad (FcConfig	    *config,
29792c393a42Smrg		      const FcChar8 *name,
29802c393a42Smrg		      FcBool	    complain)
29812c393a42Smrg{
29822c393a42Smrg
29832c393a42Smrg    XML_Parser	    p;
29842c393a42Smrg    FcChar8	    *filename;
29852c393a42Smrg    int		    fd;
29862c393a42Smrg    int		    len;
29872c393a42Smrg    FcConfigParse   parse;
29882c393a42Smrg    FcBool	    error = FcTrue;
2989ca08ab68Smrg
29902c393a42Smrg#ifdef ENABLE_LIBXML2
29912c393a42Smrg    xmlSAXHandler   sax;
29922c393a42Smrg    char            buf[BUFSIZ];
29932c393a42Smrg#else
29942c393a42Smrg    void	    *buf;
29952c393a42Smrg#endif
2996ca08ab68Smrg
2997ca08ab68Smrg#ifdef _WIN32
2998ca08ab68Smrg    if (!pGetSystemWindowsDirectory)
2999ca08ab68Smrg    {
3000ca08ab68Smrg        HMODULE hk32 = GetModuleHandleA("kernel32.dll");
3001ca08ab68Smrg        if (!(pGetSystemWindowsDirectory = (pfnGetSystemWindowsDirectory) GetProcAddress(hk32, "GetSystemWindowsDirectoryA")))
3002ca08ab68Smrg            pGetSystemWindowsDirectory = (pfnGetSystemWindowsDirectory) GetWindowsDirectory;
3003ca08ab68Smrg    }
3004ca08ab68Smrg    if (!pSHGetFolderPathA)
3005ca08ab68Smrg    {
3006ca08ab68Smrg        HMODULE hSh = LoadLibraryA("shfolder.dll");
3007ca08ab68Smrg        /* the check is done later, because there is no provided fallback */
3008ca08ab68Smrg        if (hSh)
3009ca08ab68Smrg            pSHGetFolderPathA = (pfnSHGetFolderPathA) GetProcAddress(hSh, "SHGetFolderPathA");
3010ca08ab68Smrg    }
3011ca08ab68Smrg#endif
3012ca08ab68Smrg
30132c393a42Smrg    filename = FcConfigFilename (name);
30142c393a42Smrg    if (!filename)
30152c393a42Smrg	goto bail0;
3016ca08ab68Smrg
30172c393a42Smrg    if (FcStrSetMember (config->configFiles, filename))
30182c393a42Smrg    {
30192c393a42Smrg        FcStrFree (filename);
30202c393a42Smrg        return FcTrue;
30212c393a42Smrg    }
30222c393a42Smrg
30232c393a42Smrg    if (!FcStrSetAdd (config->configFiles, filename))
30242c393a42Smrg    {
30252c393a42Smrg	FcStrFree (filename);
30262c393a42Smrg	goto bail0;
30272c393a42Smrg    }
30282c393a42Smrg
30292c393a42Smrg    if (FcFileIsDir (filename))
30302c393a42Smrg    {
30312c393a42Smrg	FcBool ret = FcConfigParseAndLoadDir (config, name, filename, complain);
30322c393a42Smrg	FcStrFree (filename);
30332c393a42Smrg	return ret;
30342c393a42Smrg    }
30352c393a42Smrg
30362c393a42Smrg    if (FcDebug () & FC_DBG_CONFIG)
30372c393a42Smrg	printf ("\tLoading config file %s\n", filename);
30382c393a42Smrg
3039c9710b42Smrg    fd = FcOpen ((char *) filename, O_RDONLY);
3040ca08ab68Smrg    if (fd == -1) {
30412c393a42Smrg	FcStrFree (filename);
30422c393a42Smrg	goto bail0;
30432c393a42Smrg    }
3044ca08ab68Smrg
30452c393a42Smrg#ifdef ENABLE_LIBXML2
30462c393a42Smrg    memset(&sax, 0, sizeof(sax));
30472c393a42Smrg
30482c393a42Smrg    sax.internalSubset = FcInternalSubsetDecl;
30492c393a42Smrg    sax.externalSubset = FcExternalSubsetDecl;
30502c393a42Smrg    sax.startElement = FcStartElement;
30512c393a42Smrg    sax.endElement = FcEndElement;
30522c393a42Smrg    sax.characters = FcCharacterData;
30532c393a42Smrg
30542c393a42Smrg    p = xmlCreatePushParserCtxt (&sax, &parse, NULL, 0, (const char *) filename);
30552c393a42Smrg#else
30562c393a42Smrg    p = XML_ParserCreate ("UTF-8");
30572c393a42Smrg#endif
30582c393a42Smrg    FcStrFree (filename);
30592c393a42Smrg
30602c393a42Smrg    if (!p)
30612c393a42Smrg	goto bail1;
30622c393a42Smrg
3063c9710b42Smrg    if (!FcConfigParseInit (&parse, name, config, p))
30642c393a42Smrg	goto bail2;
30652c393a42Smrg
30662c393a42Smrg#ifndef ENABLE_LIBXML2
30672c393a42Smrg
30682c393a42Smrg    XML_SetUserData (p, &parse);
3069ca08ab68Smrg
30702c393a42Smrg    XML_SetDoctypeDeclHandler (p, FcStartDoctypeDecl, FcEndDoctypeDecl);
30712c393a42Smrg    XML_SetElementHandler (p, FcStartElement, FcEndElement);
30722c393a42Smrg    XML_SetCharacterDataHandler (p, FcCharacterData);
30732c393a42Smrg
30742c393a42Smrg#endif /* ENABLE_LIBXML2 */
30752c393a42Smrg
30762c393a42Smrg    do {
30772c393a42Smrg#ifndef ENABLE_LIBXML2
30782c393a42Smrg	buf = XML_GetBuffer (p, BUFSIZ);
30792c393a42Smrg	if (!buf)
30802c393a42Smrg	{
30812c393a42Smrg	    FcConfigMessage (&parse, FcSevereError, "cannot get parse buffer");
30822c393a42Smrg	    goto bail3;
30832c393a42Smrg	}
30842c393a42Smrg#endif
30852c393a42Smrg	len = read (fd, buf, BUFSIZ);
30862c393a42Smrg	if (len < 0)
30872c393a42Smrg	{
30882c393a42Smrg	    FcConfigMessage (&parse, FcSevereError, "failed reading config file");
30892c393a42Smrg	    goto bail3;
30902c393a42Smrg	}
30912c393a42Smrg
30922c393a42Smrg#ifdef ENABLE_LIBXML2
30932c393a42Smrg	if (xmlParseChunk (p, buf, len, len == 0))
30942c393a42Smrg#else
30952c393a42Smrg	if (!XML_ParseBuffer (p, len, len == 0))
30962c393a42Smrg#endif
30972c393a42Smrg	{
3098ca08ab68Smrg	    FcConfigMessage (&parse, FcSevereError, "%s",
30992c393a42Smrg			   XML_ErrorString (XML_GetErrorCode (p)));
31002c393a42Smrg	    goto bail3;
31012c393a42Smrg	}
31022c393a42Smrg    } while (len != 0);
31032c393a42Smrg    error = parse.error;
31042c393a42Smrgbail3:
31052c393a42Smrg    FcConfigCleanup (&parse);
31062c393a42Smrgbail2:
31072c393a42Smrg    XML_ParserFree (p);
31082c393a42Smrgbail1:
31092c393a42Smrg    close (fd);
31102c393a42Smrg    fd = -1;
31112c393a42Smrgbail0:
31122c393a42Smrg    if (error && complain)
31132c393a42Smrg    {
31142c393a42Smrg	if (name)
31152c393a42Smrg	    FcConfigMessage (0, FcSevereError, "Cannot load config file \"%s\"", name);
31162c393a42Smrg	else
31172c393a42Smrg	    FcConfigMessage (0, FcSevereError, "Cannot load default config file");
31182c393a42Smrg	return FcFalse;
31192c393a42Smrg    }
31202c393a42Smrg    return FcTrue;
31212c393a42Smrg}
31222c393a42Smrg#define __fcxml__
31232c393a42Smrg#include "fcaliastail.h"
31242c393a42Smrg#undef __fcxml__
3125