fcxml.c revision ca08ab68
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    FcMemFree (FC_MEM_TEST, sizeof (FcTest));
692c393a42Smrg    free (test);
702c393a42Smrg}
712c393a42Smrg
72a6844aabSmrgstatic FcExpr *
73a6844aabSmrgFcExprCreateInteger (FcConfig *config, int i)
742c393a42Smrg{
75a6844aabSmrg    FcExpr *e = FcConfigAllocExpr (config);
762c393a42Smrg    if (e)
772c393a42Smrg    {
782c393a42Smrg	e->op = FcOpInteger;
792c393a42Smrg	e->u.ival = i;
802c393a42Smrg    }
812c393a42Smrg    return e;
822c393a42Smrg}
832c393a42Smrg
84a6844aabSmrgstatic FcExpr *
85a6844aabSmrgFcExprCreateDouble (FcConfig *config, double d)
862c393a42Smrg{
87a6844aabSmrg    FcExpr *e = FcConfigAllocExpr (config);
882c393a42Smrg    if (e)
892c393a42Smrg    {
902c393a42Smrg	e->op = FcOpDouble;
912c393a42Smrg	e->u.dval = d;
922c393a42Smrg    }
932c393a42Smrg    return e;
942c393a42Smrg}
952c393a42Smrg
96a6844aabSmrgstatic FcExpr *
97a6844aabSmrgFcExprCreateString (FcConfig *config, const FcChar8 *s)
982c393a42Smrg{
99a6844aabSmrg    FcExpr *e = FcConfigAllocExpr (config);
1002c393a42Smrg    if (e)
1012c393a42Smrg    {
1022c393a42Smrg	e->op = FcOpString;
103ca08ab68Smrg	e->u.sval = FcSharedStr (s);
1042c393a42Smrg    }
1052c393a42Smrg    return e;
1062c393a42Smrg}
1072c393a42Smrg
108a6844aabSmrgstatic FcExpr *
109a6844aabSmrgFcExprCreateMatrix (FcConfig *config, const FcMatrix *m)
1102c393a42Smrg{
111a6844aabSmrg    FcExpr *e = FcConfigAllocExpr (config);
1122c393a42Smrg    if (e)
1132c393a42Smrg    {
1142c393a42Smrg	e->op = FcOpMatrix;
1152c393a42Smrg	e->u.mval = FcMatrixCopy (m);
1162c393a42Smrg    }
1172c393a42Smrg    return e;
1182c393a42Smrg}
1192c393a42Smrg
120a6844aabSmrgstatic FcExpr *
121a6844aabSmrgFcExprCreateBool (FcConfig *config, FcBool b)
1222c393a42Smrg{
123a6844aabSmrg    FcExpr *e = FcConfigAllocExpr (config);
1242c393a42Smrg    if (e)
1252c393a42Smrg    {
1262c393a42Smrg	e->op = FcOpBool;
1272c393a42Smrg	e->u.bval = b;
1282c393a42Smrg    }
1292c393a42Smrg    return e;
1302c393a42Smrg}
1312c393a42Smrg
132ca08ab68Smrgstatic FcExpr *
133ca08ab68SmrgFcExprCreateCharSet (FcConfig *config, FcCharSet *charset)
134ca08ab68Smrg{
135ca08ab68Smrg    FcExpr *e = FcConfigAllocExpr (config);
136ca08ab68Smrg    if (e)
137ca08ab68Smrg    {
138ca08ab68Smrg	e->op = FcOpCharSet;
139ca08ab68Smrg	e->u.cval = FcCharSetCopy (charset);
140ca08ab68Smrg    }
141ca08ab68Smrg    return e;
142ca08ab68Smrg}
143ca08ab68Smrg
144ca08ab68Smrgstatic FcExpr *
145ca08ab68SmrgFcExprCreateLangSet (FcConfig *config, FcLangSet *langset)
146ca08ab68Smrg{
147ca08ab68Smrg    FcExpr *e = FcConfigAllocExpr (config);
148ca08ab68Smrg    if (e)
149ca08ab68Smrg    {
150ca08ab68Smrg	e->op = FcOpLangSet;
151ca08ab68Smrg	e->u.lval = FcLangSetCopy (langset);
152ca08ab68Smrg    }
153ca08ab68Smrg    return e;
154ca08ab68Smrg}
155ca08ab68Smrg
156a6844aabSmrgstatic FcExpr *
157a6844aabSmrgFcExprCreateField (FcConfig *config, const char *field)
1582c393a42Smrg{
159a6844aabSmrg    FcExpr *e = FcConfigAllocExpr (config);
1602c393a42Smrg    if (e)
1612c393a42Smrg    {
1622c393a42Smrg	e->op = FcOpField;
1632c393a42Smrg	e->u.object = FcObjectFromName (field);
1642c393a42Smrg    }
1652c393a42Smrg    return e;
1662c393a42Smrg}
1672c393a42Smrg
168a6844aabSmrgstatic FcExpr *
169a6844aabSmrgFcExprCreateConst (FcConfig *config, const FcChar8 *constant)
1702c393a42Smrg{
171a6844aabSmrg    FcExpr *e = FcConfigAllocExpr (config);
1722c393a42Smrg    if (e)
1732c393a42Smrg    {
1742c393a42Smrg	e->op = FcOpConst;
175ca08ab68Smrg	e->u.constant = FcSharedStr (constant);
1762c393a42Smrg    }
1772c393a42Smrg    return e;
1782c393a42Smrg}
1792c393a42Smrg
180a6844aabSmrgstatic FcExpr *
181a6844aabSmrgFcExprCreateOp (FcConfig *config, FcExpr *left, FcOp op, FcExpr *right)
1822c393a42Smrg{
183a6844aabSmrg    FcExpr *e = FcConfigAllocExpr (config);
1842c393a42Smrg    if (e)
1852c393a42Smrg    {
1862c393a42Smrg	e->op = op;
1872c393a42Smrg	e->u.tree.left = left;
1882c393a42Smrg	e->u.tree.right = right;
1892c393a42Smrg    }
1902c393a42Smrg    return e;
1912c393a42Smrg}
1922c393a42Smrg
193a6844aabSmrgstatic void
1942c393a42SmrgFcExprDestroy (FcExpr *e)
1952c393a42Smrg{
1962c393a42Smrg    if (!e)
1972c393a42Smrg	return;
198ca08ab68Smrg    switch (FC_OP_GET_OP (e->op)) {
1992c393a42Smrg    case FcOpInteger:
2002c393a42Smrg	break;
2012c393a42Smrg    case FcOpDouble:
2022c393a42Smrg	break;
2032c393a42Smrg    case FcOpString:
204ca08ab68Smrg	FcSharedStrFree (e->u.sval);
2052c393a42Smrg	break;
2062c393a42Smrg    case FcOpMatrix:
2072c393a42Smrg	FcMatrixFree (e->u.mval);
2082c393a42Smrg	break;
209ca08ab68Smrg    case FcOpRange:
210ca08ab68Smrg	break;
2112c393a42Smrg    case FcOpCharSet:
2122c393a42Smrg	FcCharSetDestroy (e->u.cval);
2132c393a42Smrg	break;
214ca08ab68Smrg    case FcOpLangSet:
215ca08ab68Smrg	FcLangSetDestroy (e->u.lval);
216ca08ab68Smrg	break;
2172c393a42Smrg    case FcOpBool:
2182c393a42Smrg	break;
2192c393a42Smrg    case FcOpField:
2202c393a42Smrg	break;
2212c393a42Smrg    case FcOpConst:
222ca08ab68Smrg	FcSharedStrFree (e->u.constant);
2232c393a42Smrg	break;
2242c393a42Smrg    case FcOpAssign:
2252c393a42Smrg    case FcOpAssignReplace:
2262c393a42Smrg    case FcOpPrepend:
2272c393a42Smrg    case FcOpPrependFirst:
2282c393a42Smrg    case FcOpAppend:
2292c393a42Smrg    case FcOpAppendLast:
2302c393a42Smrg	break;
2312c393a42Smrg    case FcOpOr:
2322c393a42Smrg    case FcOpAnd:
2332c393a42Smrg    case FcOpEqual:
2342c393a42Smrg    case FcOpNotEqual:
2352c393a42Smrg    case FcOpLess:
2362c393a42Smrg    case FcOpLessEqual:
2372c393a42Smrg    case FcOpMore:
2382c393a42Smrg    case FcOpMoreEqual:
2392c393a42Smrg    case FcOpContains:
2402c393a42Smrg    case FcOpListing:
2412c393a42Smrg    case FcOpNotContains:
2422c393a42Smrg    case FcOpPlus:
2432c393a42Smrg    case FcOpMinus:
2442c393a42Smrg    case FcOpTimes:
2452c393a42Smrg    case FcOpDivide:
2462c393a42Smrg    case FcOpQuest:
2472c393a42Smrg    case FcOpComma:
2482c393a42Smrg	FcExprDestroy (e->u.tree.right);
2492c393a42Smrg	/* fall through */
2502c393a42Smrg    case FcOpNot:
2512c393a42Smrg    case FcOpFloor:
2522c393a42Smrg    case FcOpCeil:
2532c393a42Smrg    case FcOpRound:
2542c393a42Smrg    case FcOpTrunc:
2552c393a42Smrg	FcExprDestroy (e->u.tree.left);
2562c393a42Smrg	break;
2572c393a42Smrg    case FcOpNil:
2582c393a42Smrg    case FcOpInvalid:
2592c393a42Smrg	break;
2602c393a42Smrg    }
261a6844aabSmrg
262a6844aabSmrg    e->op = FcOpNil;
2632c393a42Smrg}
2642c393a42Smrg
2652c393a42Smrgvoid
2662c393a42SmrgFcEditDestroy (FcEdit *e)
2672c393a42Smrg{
2682c393a42Smrg    if (e->next)
2692c393a42Smrg	FcEditDestroy (e->next);
2702c393a42Smrg    if (e->expr)
2712c393a42Smrg	FcExprDestroy (e->expr);
2722c393a42Smrg    free (e);
2732c393a42Smrg}
2742c393a42Smrg
2752c393a42Smrgtypedef enum _FcElement {
2762c393a42Smrg    FcElementNone,
2772c393a42Smrg    FcElementFontconfig,
2782c393a42Smrg    FcElementDir,
2792c393a42Smrg    FcElementCacheDir,
2802c393a42Smrg    FcElementCache,
2812c393a42Smrg    FcElementInclude,
2822c393a42Smrg    FcElementConfig,
2832c393a42Smrg    FcElementMatch,
2842c393a42Smrg    FcElementAlias,
2852c393a42Smrg
2862c393a42Smrg    FcElementBlank,
2872c393a42Smrg    FcElementRescan,
2882c393a42Smrg
2892c393a42Smrg    FcElementPrefer,
2902c393a42Smrg    FcElementAccept,
2912c393a42Smrg    FcElementDefault,
2922c393a42Smrg    FcElementFamily,
2932c393a42Smrg
2942c393a42Smrg    FcElementSelectfont,
2952c393a42Smrg    FcElementAcceptfont,
2962c393a42Smrg    FcElementRejectfont,
2972c393a42Smrg    FcElementGlob,
2982c393a42Smrg    FcElementPattern,
2992c393a42Smrg    FcElementPatelt,
3002c393a42Smrg
3012c393a42Smrg    FcElementTest,
3022c393a42Smrg    FcElementEdit,
3032c393a42Smrg    FcElementInt,
3042c393a42Smrg    FcElementDouble,
3052c393a42Smrg    FcElementString,
3062c393a42Smrg    FcElementMatrix,
307ca08ab68Smrg    FcElementRange,
3082c393a42Smrg    FcElementBool,
309ca08ab68Smrg    FcElementCharSet,
310ca08ab68Smrg    FcElementLangSet,
3112c393a42Smrg    FcElementName,
3122c393a42Smrg    FcElementConst,
3132c393a42Smrg    FcElementOr,
3142c393a42Smrg    FcElementAnd,
3152c393a42Smrg    FcElementEq,
3162c393a42Smrg    FcElementNotEq,
3172c393a42Smrg    FcElementLess,
3182c393a42Smrg    FcElementLessEq,
3192c393a42Smrg    FcElementMore,
3202c393a42Smrg    FcElementMoreEq,
3212c393a42Smrg    FcElementContains,
3222c393a42Smrg    FcElementNotContains,
3232c393a42Smrg    FcElementPlus,
3242c393a42Smrg    FcElementMinus,
3252c393a42Smrg    FcElementTimes,
3262c393a42Smrg    FcElementDivide,
3272c393a42Smrg    FcElementNot,
3282c393a42Smrg    FcElementIf,
3292c393a42Smrg    FcElementFloor,
3302c393a42Smrg    FcElementCeil,
3312c393a42Smrg    FcElementRound,
3322c393a42Smrg    FcElementTrunc,
3332c393a42Smrg    FcElementUnknown
3342c393a42Smrg} FcElement;
3352c393a42Smrg
3362c393a42Smrgstatic const struct {
3372c393a42Smrg    const char  name[16];
3382c393a42Smrg    FcElement   element;
3392c393a42Smrg} fcElementMap[] = {
3402c393a42Smrg    { "fontconfig",	FcElementFontconfig },
3412c393a42Smrg    { "dir",		FcElementDir },
3422c393a42Smrg    { "cachedir",	FcElementCacheDir },
3432c393a42Smrg    { "cache",		FcElementCache },
3442c393a42Smrg    { "include",	FcElementInclude },
3452c393a42Smrg    { "config",		FcElementConfig },
3462c393a42Smrg    { "match",		FcElementMatch },
3472c393a42Smrg    { "alias",		FcElementAlias },
348ca08ab68Smrg
3492c393a42Smrg    { "blank",		FcElementBlank },
3502c393a42Smrg    { "rescan",		FcElementRescan },
3512c393a42Smrg
3522c393a42Smrg    { "prefer",		FcElementPrefer },
3532c393a42Smrg    { "accept",		FcElementAccept },
3542c393a42Smrg    { "default",	FcElementDefault },
3552c393a42Smrg    { "family",		FcElementFamily },
3562c393a42Smrg
3572c393a42Smrg    { "selectfont",	FcElementSelectfont },
3582c393a42Smrg    { "acceptfont",	FcElementAcceptfont },
3592c393a42Smrg    { "rejectfont",	FcElementRejectfont },
3602c393a42Smrg    { "glob",		FcElementGlob },
3612c393a42Smrg    { "pattern",	FcElementPattern },
3622c393a42Smrg    { "patelt",		FcElementPatelt },
3632c393a42Smrg
3642c393a42Smrg    { "test",		FcElementTest },
3652c393a42Smrg    { "edit",		FcElementEdit },
3662c393a42Smrg    { "int",		FcElementInt },
3672c393a42Smrg    { "double",		FcElementDouble },
3682c393a42Smrg    { "string",		FcElementString },
3692c393a42Smrg    { "matrix",		FcElementMatrix },
370ca08ab68Smrg    { "range",		FcElementRange },
3712c393a42Smrg    { "bool",		FcElementBool },
372ca08ab68Smrg    { "charset",	FcElementCharSet },
373ca08ab68Smrg    { "langset",	FcElementLangSet },
3742c393a42Smrg    { "name",		FcElementName },
3752c393a42Smrg    { "const",		FcElementConst },
3762c393a42Smrg    { "or",		FcElementOr },
3772c393a42Smrg    { "and",		FcElementAnd },
3782c393a42Smrg    { "eq",		FcElementEq },
3792c393a42Smrg    { "not_eq",		FcElementNotEq },
3802c393a42Smrg    { "less",		FcElementLess },
3812c393a42Smrg    { "less_eq",	FcElementLessEq },
3822c393a42Smrg    { "more",		FcElementMore },
3832c393a42Smrg    { "more_eq",	FcElementMoreEq },
3842c393a42Smrg    { "contains",	FcElementContains },
3852c393a42Smrg    { "not_contains",	FcElementNotContains },
3862c393a42Smrg    { "plus",		FcElementPlus },
3872c393a42Smrg    { "minus",		FcElementMinus },
3882c393a42Smrg    { "times",		FcElementTimes },
3892c393a42Smrg    { "divide",		FcElementDivide },
3902c393a42Smrg    { "not",		FcElementNot },
3912c393a42Smrg    { "if",		FcElementIf },
3922c393a42Smrg    { "floor",		FcElementFloor },
3932c393a42Smrg    { "ceil",		FcElementCeil },
3942c393a42Smrg    { "round",		FcElementRound },
3952c393a42Smrg    { "trunc",		FcElementTrunc },
3962c393a42Smrg};
3972c393a42Smrg#define NUM_ELEMENT_MAPS (int) (sizeof fcElementMap / sizeof fcElementMap[0])
3982c393a42Smrg
3992c393a42Smrgstatic FcElement
4002c393a42SmrgFcElementMap (const XML_Char *name)
4012c393a42Smrg{
4022c393a42Smrg
4032c393a42Smrg    int	    i;
4042c393a42Smrg    for (i = 0; i < NUM_ELEMENT_MAPS; i++)
4052c393a42Smrg	if (!strcmp ((char *) name, fcElementMap[i].name))
4062c393a42Smrg	    return fcElementMap[i].element;
4072c393a42Smrg    return FcElementUnknown;
4082c393a42Smrg}
4092c393a42Smrg
4102c393a42Smrgtypedef struct _FcPStack {
4112c393a42Smrg    struct _FcPStack   *prev;
4122c393a42Smrg    FcElement		element;
4132c393a42Smrg    FcChar8		**attr;
4142c393a42Smrg    FcStrBuf		str;
415a6844aabSmrg    FcChar8            *attr_buf_static[16];
4162c393a42Smrg} FcPStack;
417ca08ab68Smrg
4182c393a42Smrgtypedef enum _FcVStackTag {
4192c393a42Smrg    FcVStackNone,
4202c393a42Smrg
4212c393a42Smrg    FcVStackString,
4222c393a42Smrg    FcVStackFamily,
4232c393a42Smrg    FcVStackField,
4242c393a42Smrg    FcVStackConstant,
4252c393a42Smrg    FcVStackGlob,
4262c393a42Smrg    FcVStackPattern,
427ca08ab68Smrg
4282c393a42Smrg    FcVStackPrefer,
4292c393a42Smrg    FcVStackAccept,
4302c393a42Smrg    FcVStackDefault,
431ca08ab68Smrg
4322c393a42Smrg    FcVStackInteger,
4332c393a42Smrg    FcVStackDouble,
4342c393a42Smrg    FcVStackMatrix,
435ca08ab68Smrg    FcVStackRange,
4362c393a42Smrg    FcVStackBool,
437ca08ab68Smrg    FcVStackCharSet,
438ca08ab68Smrg    FcVStackLangSet,
439ca08ab68Smrg
4402c393a42Smrg    FcVStackTest,
4412c393a42Smrg    FcVStackExpr,
4422c393a42Smrg    FcVStackEdit
4432c393a42Smrg} FcVStackTag;
4442c393a42Smrg
4452c393a42Smrgtypedef struct _FcVStack {
4462c393a42Smrg    struct _FcVStack	*prev;
4472c393a42Smrg    FcPStack		*pstack;	/* related parse element */
4482c393a42Smrg    FcVStackTag		tag;
4492c393a42Smrg    union {
4502c393a42Smrg	FcChar8		*string;
4512c393a42Smrg
4522c393a42Smrg	int		integer;
4532c393a42Smrg	double		_double;
4542c393a42Smrg	FcMatrix	*matrix;
455ca08ab68Smrg	FcRange		range;
456a6844aabSmrg	FcBool		bool_;
457ca08ab68Smrg	FcCharSet	*charset;
458ca08ab68Smrg	FcLangSet	*langset;
4592c393a42Smrg
4602c393a42Smrg	FcTest		*test;
4612c393a42Smrg	FcQual		qual;
4622c393a42Smrg	FcOp		op;
4632c393a42Smrg	FcExpr		*expr;
4642c393a42Smrg	FcEdit		*edit;
4652c393a42Smrg
4662c393a42Smrg	FcPattern	*pattern;
4672c393a42Smrg    } u;
4682c393a42Smrg} FcVStack;
4692c393a42Smrg
4702c393a42Smrgtypedef struct _FcConfigParse {
4712c393a42Smrg    FcPStack	    *pstack;
4722c393a42Smrg    FcVStack	    *vstack;
4732c393a42Smrg    FcBool	    error;
4742c393a42Smrg    const FcChar8   *name;
4752c393a42Smrg    FcConfig	    *config;
4762c393a42Smrg    XML_Parser	    parser;
477a6844aabSmrg    int             pstack_static_used;
478a6844aabSmrg    FcPStack        pstack_static[8];
479a6844aabSmrg    int             vstack_static_used;
480a6844aabSmrg    FcVStack        vstack_static[64];
4812c393a42Smrg} FcConfigParse;
4822c393a42Smrg
4832c393a42Smrgtypedef enum _FcConfigSeverity {
4842c393a42Smrg    FcSevereInfo, FcSevereWarning, FcSevereError
4852c393a42Smrg} FcConfigSeverity;
4862c393a42Smrg
4872c393a42Smrgstatic void
4882c393a42SmrgFcConfigMessage (FcConfigParse *parse, FcConfigSeverity severe, const char *fmt, ...)
4892c393a42Smrg{
4902c393a42Smrg    const char	*s = "unknown";
4912c393a42Smrg    va_list	args;
4922c393a42Smrg
4932c393a42Smrg    va_start (args, fmt);
4942c393a42Smrg
4952c393a42Smrg    switch (severe) {
4962c393a42Smrg    case FcSevereInfo: s = "info"; break;
4972c393a42Smrg    case FcSevereWarning: s = "warning"; break;
4982c393a42Smrg    case FcSevereError: s = "error"; break;
4992c393a42Smrg    }
5002c393a42Smrg    if (parse)
5012c393a42Smrg    {
5022c393a42Smrg	if (parse->name)
5032c393a42Smrg	    fprintf (stderr, "Fontconfig %s: \"%s\", line %d: ", s,
5042c393a42Smrg		     parse->name, (int)XML_GetCurrentLineNumber (parse->parser));
5052c393a42Smrg	else
5062c393a42Smrg	    fprintf (stderr, "Fontconfig %s: line %d: ", s,
5072c393a42Smrg		     (int)XML_GetCurrentLineNumber (parse->parser));
5082c393a42Smrg	if (severe >= FcSevereError)
5092c393a42Smrg	    parse->error = FcTrue;
5102c393a42Smrg    }
5112c393a42Smrg    else
5122c393a42Smrg	fprintf (stderr, "Fontconfig %s: ", s);
5132c393a42Smrg    vfprintf (stderr, fmt, args);
5142c393a42Smrg    fprintf (stderr, "\n");
5152c393a42Smrg    va_end (args);
5162c393a42Smrg}
5172c393a42Smrg
5182c393a42Smrg
5192c393a42Smrgstatic const char *
5202c393a42SmrgFcTypeName (FcType type)
5212c393a42Smrg{
5222c393a42Smrg    switch (type) {
5232c393a42Smrg    case FcTypeVoid:
5242c393a42Smrg	return "void";
5252c393a42Smrg    case FcTypeInteger:
5262c393a42Smrg    case FcTypeDouble:
5272c393a42Smrg	return "number";
5282c393a42Smrg    case FcTypeString:
5292c393a42Smrg	return "string";
5302c393a42Smrg    case FcTypeBool:
5312c393a42Smrg	return "bool";
5322c393a42Smrg    case FcTypeMatrix:
5332c393a42Smrg	return "matrix";
5342c393a42Smrg    case FcTypeCharSet:
5352c393a42Smrg	return "charset";
5362c393a42Smrg    case FcTypeFTFace:
5372c393a42Smrg	return "FT_Face";
5382c393a42Smrg    case FcTypeLangSet:
5392c393a42Smrg	return "langset";
5402c393a42Smrg    default:
5412c393a42Smrg	return "unknown";
5422c393a42Smrg    }
5432c393a42Smrg}
5442c393a42Smrg
5452c393a42Smrgstatic void
5462c393a42SmrgFcTypecheckValue (FcConfigParse *parse, FcType value, FcType type)
5472c393a42Smrg{
5482c393a42Smrg    if (value == FcTypeInteger)
5492c393a42Smrg	value = FcTypeDouble;
5502c393a42Smrg    if (type == FcTypeInteger)
5512c393a42Smrg	type = FcTypeDouble;
5522c393a42Smrg    if (value != type)
5532c393a42Smrg    {
5542c393a42Smrg	if ((value == FcTypeLangSet && type == FcTypeString) ||
5552c393a42Smrg	    (value == FcTypeString && type == FcTypeLangSet))
5562c393a42Smrg	    return;
5572c393a42Smrg	if (type == (FcType) -1)
5582c393a42Smrg	    return;
5592c393a42Smrg	FcConfigMessage (parse, FcSevereWarning, "saw %s, expected %s",
5602c393a42Smrg			 FcTypeName (value), FcTypeName (type));
5612c393a42Smrg    }
5622c393a42Smrg}
5632c393a42Smrg
5642c393a42Smrgstatic void
5652c393a42SmrgFcTypecheckExpr (FcConfigParse *parse, FcExpr *expr, FcType type)
5662c393a42Smrg{
5672c393a42Smrg    const FcObjectType	*o;
5682c393a42Smrg    const FcConstant	*c;
569ca08ab68Smrg
5702c393a42Smrg    /* If parsing the expression failed, some nodes may be NULL */
5712c393a42Smrg    if (!expr)
5722c393a42Smrg	return;
5732c393a42Smrg
574ca08ab68Smrg    switch (FC_OP_GET_OP (expr->op)) {
5752c393a42Smrg    case FcOpInteger:
5762c393a42Smrg    case FcOpDouble:
5772c393a42Smrg	FcTypecheckValue (parse, FcTypeDouble, type);
5782c393a42Smrg	break;
5792c393a42Smrg    case FcOpString:
5802c393a42Smrg	FcTypecheckValue (parse, FcTypeString, type);
5812c393a42Smrg	break;
5822c393a42Smrg    case FcOpMatrix:
5832c393a42Smrg	FcTypecheckValue (parse, FcTypeMatrix, type);
5842c393a42Smrg	break;
5852c393a42Smrg    case FcOpBool:
5862c393a42Smrg	FcTypecheckValue (parse, FcTypeBool, type);
5872c393a42Smrg	break;
5882c393a42Smrg    case FcOpCharSet:
5892c393a42Smrg	FcTypecheckValue (parse, FcTypeCharSet, type);
5902c393a42Smrg	break;
591ca08ab68Smrg    case FcOpLangSet:
592ca08ab68Smrg	FcTypecheckValue (parse, FcTypeLangSet, type);
593ca08ab68Smrg	break;
5942c393a42Smrg    case FcOpNil:
5952c393a42Smrg	break;
5962c393a42Smrg    case FcOpField:
5972c393a42Smrg	o = FcNameGetObjectType (FcObjectName (expr->u.object));
5982c393a42Smrg	if (o)
5992c393a42Smrg	    FcTypecheckValue (parse, o->type, type);
6002c393a42Smrg	break;
6012c393a42Smrg    case FcOpConst:
6022c393a42Smrg	c = FcNameGetConstant (expr->u.constant);
6032c393a42Smrg	if (c)
6042c393a42Smrg	{
6052c393a42Smrg	    o = FcNameGetObjectType (c->object);
6062c393a42Smrg	    if (o)
6072c393a42Smrg		FcTypecheckValue (parse, o->type, type);
6082c393a42Smrg	}
609ca08ab68Smrg        else
610ca08ab68Smrg            FcConfigMessage (parse, FcSevereWarning,
6112c393a42Smrg                             "invalid constant used : %s",
6122c393a42Smrg                             expr->u.constant);
6132c393a42Smrg	break;
6142c393a42Smrg    case FcOpQuest:
6152c393a42Smrg	FcTypecheckExpr (parse, expr->u.tree.left, FcTypeBool);
6162c393a42Smrg	FcTypecheckExpr (parse, expr->u.tree.right->u.tree.left, type);
6172c393a42Smrg	FcTypecheckExpr (parse, expr->u.tree.right->u.tree.right, type);
6182c393a42Smrg	break;
6192c393a42Smrg    case FcOpAssign:
6202c393a42Smrg    case FcOpAssignReplace:
6212c393a42Smrg	break;
6222c393a42Smrg    case FcOpEqual:
6232c393a42Smrg    case FcOpNotEqual:
6242c393a42Smrg    case FcOpLess:
6252c393a42Smrg    case FcOpLessEqual:
6262c393a42Smrg    case FcOpMore:
6272c393a42Smrg    case FcOpMoreEqual:
6282c393a42Smrg    case FcOpContains:
6292c393a42Smrg    case FcOpNotContains:
6302c393a42Smrg    case FcOpListing:
6312c393a42Smrg	FcTypecheckValue (parse, FcTypeBool, type);
6322c393a42Smrg	break;
6332c393a42Smrg    case FcOpComma:
6342c393a42Smrg    case FcOpOr:
6352c393a42Smrg    case FcOpAnd:
6362c393a42Smrg    case FcOpPlus:
6372c393a42Smrg    case FcOpMinus:
6382c393a42Smrg    case FcOpTimes:
6392c393a42Smrg    case FcOpDivide:
6402c393a42Smrg	FcTypecheckExpr (parse, expr->u.tree.left, type);
6412c393a42Smrg	FcTypecheckExpr (parse, expr->u.tree.right, type);
6422c393a42Smrg	break;
6432c393a42Smrg    case FcOpNot:
6442c393a42Smrg	FcTypecheckValue (parse, FcTypeBool, type);
6452c393a42Smrg	FcTypecheckExpr (parse, expr->u.tree.left, FcTypeBool);
6462c393a42Smrg	break;
6472c393a42Smrg    case FcOpFloor:
6482c393a42Smrg    case FcOpCeil:
6492c393a42Smrg    case FcOpRound:
6502c393a42Smrg    case FcOpTrunc:
6512c393a42Smrg	FcTypecheckValue (parse, FcTypeDouble, type);
6522c393a42Smrg	FcTypecheckExpr (parse, expr->u.tree.left, FcTypeDouble);
6532c393a42Smrg	break;
6542c393a42Smrg    default:
6552c393a42Smrg	break;
6562c393a42Smrg    }
6572c393a42Smrg}
6582c393a42Smrg
6592c393a42Smrgstatic FcTest *
6602c393a42SmrgFcTestCreate (FcConfigParse *parse,
661ca08ab68Smrg	      FcMatchKind   kind,
6622c393a42Smrg	      FcQual	    qual,
6632c393a42Smrg	      const FcChar8 *field,
6642c393a42Smrg	      FcOp	    compare,
6652c393a42Smrg	      FcExpr	    *expr)
6662c393a42Smrg{
6672c393a42Smrg    FcTest	*test = (FcTest *) malloc (sizeof (FcTest));
6682c393a42Smrg
6692c393a42Smrg    if (test)
6702c393a42Smrg    {
6712c393a42Smrg	const FcObjectType	*o;
6722c393a42Smrg
6732c393a42Smrg	FcMemAlloc (FC_MEM_TEST, sizeof (FcTest));
6742c393a42Smrg	test->next = 0;
6752c393a42Smrg	test->kind = kind;
6762c393a42Smrg	test->qual = qual;
6772c393a42Smrg	test->object = FcObjectFromName ((const char *) field);
6782c393a42Smrg	test->op = compare;
6792c393a42Smrg	test->expr = expr;
6802c393a42Smrg	o = FcNameGetObjectType (FcObjectName (test->object));
6812c393a42Smrg	if (o)
6822c393a42Smrg	    FcTypecheckExpr (parse, expr, o->type);
6832c393a42Smrg    }
6842c393a42Smrg    return test;
6852c393a42Smrg}
6862c393a42Smrg
6872c393a42Smrgstatic FcEdit *
6882c393a42SmrgFcEditCreate (FcConfigParse	*parse,
6892c393a42Smrg	      FcObject		object,
6902c393a42Smrg	      FcOp		op,
6912c393a42Smrg	      FcExpr		*expr,
6922c393a42Smrg	      FcValueBinding	binding)
6932c393a42Smrg{
6942c393a42Smrg    FcEdit *e = (FcEdit *) malloc (sizeof (FcEdit));
6952c393a42Smrg
6962c393a42Smrg    if (e)
6972c393a42Smrg    {
6982c393a42Smrg	const FcObjectType	*o;
6992c393a42Smrg
7002c393a42Smrg	e->next = 0;
7012c393a42Smrg	e->object = object;
7022c393a42Smrg	e->op = op;
7032c393a42Smrg	e->expr = expr;
7042c393a42Smrg	e->binding = binding;
7052c393a42Smrg	o = FcNameGetObjectType (FcObjectName (e->object));
7062c393a42Smrg	if (o)
7072c393a42Smrg	    FcTypecheckExpr (parse, expr, o->type);
7082c393a42Smrg    }
7092c393a42Smrg    return e;
7102c393a42Smrg}
7112c393a42Smrg
7122c393a42Smrgstatic FcVStack *
713a6844aabSmrgFcVStackCreateAndPush (FcConfigParse *parse)
7142c393a42Smrg{
7152c393a42Smrg    FcVStack    *new;
7162c393a42Smrg
717a6844aabSmrg    if (parse->vstack_static_used < sizeof (parse->vstack_static) / sizeof (parse->vstack_static[0]))
718a6844aabSmrg	new = &parse->vstack_static[parse->vstack_static_used++];
719a6844aabSmrg    else
720a6844aabSmrg    {
721a6844aabSmrg	new = malloc (sizeof (FcVStack));
722a6844aabSmrg	if (!new)
723a6844aabSmrg	    return 0;
724a6844aabSmrg	FcMemAlloc (FC_MEM_VSTACK, sizeof (FcVStack));
725a6844aabSmrg    }
7262c393a42Smrg    new->tag = FcVStackNone;
7272c393a42Smrg    new->prev = 0;
7282c393a42Smrg
729a6844aabSmrg    new->prev = parse->vstack;
730a6844aabSmrg    new->pstack = parse->pstack ? parse->pstack->prev : 0;
731a6844aabSmrg    parse->vstack = new;
7322c393a42Smrg
733a6844aabSmrg    return new;
7342c393a42Smrg}
7352c393a42Smrg
7362c393a42Smrgstatic FcBool
7372c393a42SmrgFcVStackPushString (FcConfigParse *parse, FcVStackTag tag, FcChar8 *string)
7382c393a42Smrg{
739a6844aabSmrg    FcVStack    *vstack = FcVStackCreateAndPush (parse);
7402c393a42Smrg    if (!vstack)
7412c393a42Smrg	return FcFalse;
7422c393a42Smrg    vstack->u.string = string;
7432c393a42Smrg    vstack->tag = tag;
7442c393a42Smrg    return FcTrue;
7452c393a42Smrg}
7462c393a42Smrg
7472c393a42Smrgstatic FcBool
7482c393a42SmrgFcVStackPushInteger (FcConfigParse *parse, int integer)
7492c393a42Smrg{
750a6844aabSmrg    FcVStack    *vstack = FcVStackCreateAndPush (parse);
7512c393a42Smrg    if (!vstack)
7522c393a42Smrg	return FcFalse;
7532c393a42Smrg    vstack->u.integer = integer;
7542c393a42Smrg    vstack->tag = FcVStackInteger;
7552c393a42Smrg    return FcTrue;
7562c393a42Smrg}
7572c393a42Smrg
7582c393a42Smrgstatic FcBool
7592c393a42SmrgFcVStackPushDouble (FcConfigParse *parse, double _double)
7602c393a42Smrg{
761a6844aabSmrg    FcVStack    *vstack = FcVStackCreateAndPush (parse);
7622c393a42Smrg    if (!vstack)
7632c393a42Smrg	return FcFalse;
7642c393a42Smrg    vstack->u._double = _double;
7652c393a42Smrg    vstack->tag = FcVStackDouble;
7662c393a42Smrg    return FcTrue;
7672c393a42Smrg}
7682c393a42Smrg
7692c393a42Smrgstatic FcBool
7702c393a42SmrgFcVStackPushMatrix (FcConfigParse *parse, FcMatrix *matrix)
7712c393a42Smrg{
772a6844aabSmrg    FcVStack    *vstack;
7732c393a42Smrg    matrix = FcMatrixCopy (matrix);
7742c393a42Smrg    if (!matrix)
7752c393a42Smrg	return FcFalse;
776a6844aabSmrg    vstack = FcVStackCreateAndPush (parse);
777a6844aabSmrg    if (!vstack)
778a6844aabSmrg	return FcFalse;
7792c393a42Smrg    vstack->u.matrix = matrix;
7802c393a42Smrg    vstack->tag = FcVStackMatrix;
7812c393a42Smrg    return FcTrue;
7822c393a42Smrg}
7832c393a42Smrg
784ca08ab68Smrgstatic FcBool
785ca08ab68SmrgFcVStackPushRange (FcConfigParse *parse, FcRange *range)
786ca08ab68Smrg{
787ca08ab68Smrg    FcVStack	*vstack = FcVStackCreateAndPush (parse);
788ca08ab68Smrg    if (!vstack)
789ca08ab68Smrg	return FcFalse;
790ca08ab68Smrg    vstack->u.range.begin = range->begin;
791ca08ab68Smrg    vstack->u.range.end = range->end;
792ca08ab68Smrg    vstack->tag = FcVStackRange;
793ca08ab68Smrg    return FcTrue;
794ca08ab68Smrg}
795ca08ab68Smrg
7962c393a42Smrgstatic FcBool
797a6844aabSmrgFcVStackPushBool (FcConfigParse *parse, FcBool bool_)
7982c393a42Smrg{
799a6844aabSmrg    FcVStack    *vstack = FcVStackCreateAndPush (parse);
8002c393a42Smrg    if (!vstack)
8012c393a42Smrg	return FcFalse;
802a6844aabSmrg    vstack->u.bool_ = bool_;
8032c393a42Smrg    vstack->tag = FcVStackBool;
8042c393a42Smrg    return FcTrue;
8052c393a42Smrg}
8062c393a42Smrg
807ca08ab68Smrgstatic FcBool
808ca08ab68SmrgFcVStackPushCharSet (FcConfigParse *parse, FcCharSet *charset)
809ca08ab68Smrg{
810ca08ab68Smrg    FcVStack	*vstack;
811ca08ab68Smrg    if (!charset)
812ca08ab68Smrg	return FcFalse;
813ca08ab68Smrg    vstack = FcVStackCreateAndPush (parse);
814ca08ab68Smrg    if (!vstack)
815ca08ab68Smrg	return FcFalse;
816ca08ab68Smrg    vstack->u.charset = charset;
817ca08ab68Smrg    vstack->tag = FcVStackCharSet;
818ca08ab68Smrg    return FcTrue;
819ca08ab68Smrg}
820ca08ab68Smrg
821ca08ab68Smrgstatic FcBool
822ca08ab68SmrgFcVStackPushLangSet (FcConfigParse *parse, FcLangSet *langset)
823ca08ab68Smrg{
824ca08ab68Smrg    FcVStack	*vstack;
825ca08ab68Smrg    if (!langset)
826ca08ab68Smrg	return FcFalse;
827ca08ab68Smrg    vstack = FcVStackCreateAndPush (parse);
828ca08ab68Smrg    if (!vstack)
829ca08ab68Smrg	return FcFalse;
830ca08ab68Smrg    vstack->u.langset = langset;
831ca08ab68Smrg    vstack->tag = FcVStackLangSet;
832ca08ab68Smrg    return FcTrue;
833ca08ab68Smrg}
834ca08ab68Smrg
8352c393a42Smrgstatic FcBool
8362c393a42SmrgFcVStackPushTest (FcConfigParse *parse, FcTest *test)
8372c393a42Smrg{
838a6844aabSmrg    FcVStack    *vstack = FcVStackCreateAndPush (parse);
8392c393a42Smrg    if (!vstack)
8402c393a42Smrg	return FcFalse;
8412c393a42Smrg    vstack->u.test = test;
8422c393a42Smrg    vstack->tag = FcVStackTest;
8432c393a42Smrg    return FcTrue;
8442c393a42Smrg}
8452c393a42Smrg
8462c393a42Smrgstatic FcBool
8472c393a42SmrgFcVStackPushExpr (FcConfigParse *parse, FcVStackTag tag, FcExpr *expr)
8482c393a42Smrg{
849a6844aabSmrg    FcVStack    *vstack = FcVStackCreateAndPush (parse);
8502c393a42Smrg    if (!vstack)
8512c393a42Smrg	return FcFalse;
8522c393a42Smrg    vstack->u.expr = expr;
8532c393a42Smrg    vstack->tag = tag;
8542c393a42Smrg    return FcTrue;
8552c393a42Smrg}
8562c393a42Smrg
8572c393a42Smrgstatic FcBool
8582c393a42SmrgFcVStackPushEdit (FcConfigParse *parse, FcEdit *edit)
8592c393a42Smrg{
860a6844aabSmrg    FcVStack    *vstack = FcVStackCreateAndPush (parse);
8612c393a42Smrg    if (!vstack)
8622c393a42Smrg	return FcFalse;
8632c393a42Smrg    vstack->u.edit = edit;
8642c393a42Smrg    vstack->tag = FcVStackEdit;
8652c393a42Smrg    return FcTrue;
8662c393a42Smrg}
8672c393a42Smrg
8682c393a42Smrgstatic FcBool
8692c393a42SmrgFcVStackPushPattern (FcConfigParse *parse, FcPattern *pattern)
8702c393a42Smrg{
871a6844aabSmrg    FcVStack    *vstack = FcVStackCreateAndPush (parse);
8722c393a42Smrg    if (!vstack)
8732c393a42Smrg	return FcFalse;
8742c393a42Smrg    vstack->u.pattern = pattern;
8752c393a42Smrg    vstack->tag = FcVStackPattern;
8762c393a42Smrg    return FcTrue;
8772c393a42Smrg}
8782c393a42Smrg
8792c393a42Smrgstatic FcVStack *
8802c393a42SmrgFcVStackFetch (FcConfigParse *parse, int off)
8812c393a42Smrg{
8822c393a42Smrg    FcVStack    *vstack;
8832c393a42Smrg
8842c393a42Smrg    for (vstack = parse->vstack; vstack && off-- > 0; vstack = vstack->prev);
8852c393a42Smrg    return vstack;
8862c393a42Smrg}
8872c393a42Smrg
888a6844aabSmrgstatic FcVStack *
889a6844aabSmrgFcVStackPeek (FcConfigParse *parse)
8902c393a42Smrg{
891a6844aabSmrg    FcVStack	*vstack = parse->vstack;
892a6844aabSmrg
893a6844aabSmrg    return vstack && vstack->pstack == parse->pstack ? vstack : 0;
8942c393a42Smrg}
8952c393a42Smrg
896a6844aabSmrgstatic void
897a6844aabSmrgFcVStackPopAndDestroy (FcConfigParse *parse)
8982c393a42Smrg{
8992c393a42Smrg    FcVStack	*vstack = parse->vstack;
900ca08ab68Smrg
9012c393a42Smrg    if (!vstack || vstack->pstack != parse->pstack)
902a6844aabSmrg	return;
903a6844aabSmrg
9042c393a42Smrg    parse->vstack = vstack->prev;
905a6844aabSmrg
906a6844aabSmrg    switch (vstack->tag) {
907a6844aabSmrg    case FcVStackNone:
908a6844aabSmrg	break;
909a6844aabSmrg    case FcVStackFamily:
910a6844aabSmrg	break;
911a6844aabSmrg    case FcVStackString:
912a6844aabSmrg    case FcVStackField:
913a6844aabSmrg    case FcVStackConstant:
914a6844aabSmrg    case FcVStackGlob:
915a6844aabSmrg	FcStrFree (vstack->u.string);
916a6844aabSmrg	break;
917a6844aabSmrg    case FcVStackPattern:
918a6844aabSmrg	FcPatternDestroy (vstack->u.pattern);
919a6844aabSmrg	break;
920a6844aabSmrg    case FcVStackInteger:
921a6844aabSmrg    case FcVStackDouble:
922a6844aabSmrg	break;
923a6844aabSmrg    case FcVStackMatrix:
924a6844aabSmrg	FcMatrixFree (vstack->u.matrix);
925a6844aabSmrg	break;
926ca08ab68Smrg    case FcVStackRange:
927a6844aabSmrg    case FcVStackBool:
928a6844aabSmrg	break;
929ca08ab68Smrg    case FcVStackCharSet:
930ca08ab68Smrg	FcCharSetDestroy (vstack->u.charset);
931ca08ab68Smrg	break;
932ca08ab68Smrg    case FcVStackLangSet:
933ca08ab68Smrg	FcLangSetDestroy (vstack->u.langset);
934ca08ab68Smrg	break;
935a6844aabSmrg    case FcVStackTest:
936a6844aabSmrg	FcTestDestroy (vstack->u.test);
937a6844aabSmrg	break;
938a6844aabSmrg    case FcVStackExpr:
939a6844aabSmrg    case FcVStackPrefer:
940a6844aabSmrg    case FcVStackAccept:
941a6844aabSmrg    case FcVStackDefault:
942a6844aabSmrg	FcExprDestroy (vstack->u.expr);
943a6844aabSmrg	break;
944a6844aabSmrg    case FcVStackEdit:
945a6844aabSmrg	FcEditDestroy (vstack->u.edit);
946a6844aabSmrg	break;
947a6844aabSmrg    }
948a6844aabSmrg
949a6844aabSmrg    if (vstack == &parse->vstack_static[parse->vstack_static_used - 1])
950a6844aabSmrg	parse->vstack_static_used--;
951a6844aabSmrg    else
952a6844aabSmrg    {
953a6844aabSmrg	FcMemFree (FC_MEM_VSTACK, sizeof (FcVStack));
954a6844aabSmrg	free (vstack);
955a6844aabSmrg    }
956a6844aabSmrg}
957a6844aabSmrg
958a6844aabSmrgstatic void
959a6844aabSmrgFcVStackClear (FcConfigParse *parse)
960a6844aabSmrg{
961a6844aabSmrg    while (FcVStackPeek (parse))
962a6844aabSmrg	FcVStackPopAndDestroy (parse);
9632c393a42Smrg}
9642c393a42Smrg
9652c393a42Smrgstatic int
9662c393a42SmrgFcVStackElements (FcConfigParse *parse)
9672c393a42Smrg{
9682c393a42Smrg    int		h = 0;
9692c393a42Smrg    FcVStack	*vstack = parse->vstack;
9702c393a42Smrg    while (vstack && vstack->pstack == parse->pstack)
9712c393a42Smrg    {
9722c393a42Smrg	h++;
9732c393a42Smrg	vstack = vstack->prev;
9742c393a42Smrg    }
9752c393a42Smrg    return h;
9762c393a42Smrg}
9772c393a42Smrg
9782c393a42Smrgstatic FcChar8 **
979a6844aabSmrgFcConfigSaveAttr (const XML_Char **attr, FcChar8 **buf, int size_bytes)
9802c393a42Smrg{
9812c393a42Smrg    int		slen;
9822c393a42Smrg    int		i;
9832c393a42Smrg    FcChar8	**new;
9842c393a42Smrg    FcChar8	*s;
9852c393a42Smrg
9862c393a42Smrg    if (!attr)
9872c393a42Smrg	return 0;
9882c393a42Smrg    slen = 0;
9892c393a42Smrg    for (i = 0; attr[i]; i++)
9902c393a42Smrg	slen += strlen ((char *) attr[i]) + 1;
991a6844aabSmrg    if (i == 0)
9922c393a42Smrg	return 0;
993a6844aabSmrg    slen += (i + 1) * sizeof (FcChar8 *);
994a6844aabSmrg    if (slen <= size_bytes)
995a6844aabSmrg	new = buf;
996a6844aabSmrg    else
997a6844aabSmrg    {
998a6844aabSmrg	new = malloc (slen);
999a6844aabSmrg	if (!new)
1000a6844aabSmrg	{
1001a6844aabSmrg	    FcConfigMessage (0, FcSevereError, "out of memory");
1002a6844aabSmrg	    return 0;
1003a6844aabSmrg	}
1004a6844aabSmrg	FcMemAlloc (FC_MEM_ATTR, 1);    /* size is too expensive */
1005a6844aabSmrg    }
10062c393a42Smrg    s = (FcChar8 *) (new + (i + 1));
10072c393a42Smrg    for (i = 0; attr[i]; i++)
10082c393a42Smrg    {
10092c393a42Smrg	new[i] = s;
10102c393a42Smrg	strcpy ((char *) s, (char *) attr[i]);
10112c393a42Smrg	s += strlen ((char *) s) + 1;
10122c393a42Smrg    }
10132c393a42Smrg    new[i] = 0;
10142c393a42Smrg    return new;
10152c393a42Smrg}
10162c393a42Smrg
10172c393a42Smrgstatic FcBool
10182c393a42SmrgFcPStackPush (FcConfigParse *parse, FcElement element, const XML_Char **attr)
10192c393a42Smrg{
1020a6844aabSmrg    FcPStack   *new;
10212c393a42Smrg
1022a6844aabSmrg    if (parse->pstack_static_used < sizeof (parse->pstack_static) / sizeof (parse->pstack_static[0]))
1023a6844aabSmrg	new = &parse->pstack_static[parse->pstack_static_used++];
1024a6844aabSmrg    else
10252c393a42Smrg    {
1026a6844aabSmrg	new = malloc (sizeof (FcPStack));
1027a6844aabSmrg	if (!new)
10282c393a42Smrg	    return FcFalse;
1029a6844aabSmrg	FcMemAlloc (FC_MEM_PSTACK, sizeof (FcPStack));
10302c393a42Smrg    }
1031a6844aabSmrg
1032a6844aabSmrg    new->prev = parse->pstack;
1033a6844aabSmrg    new->element = element;
1034a6844aabSmrg    new->attr = FcConfigSaveAttr (attr, new->attr_buf_static, sizeof (new->attr_buf_static));
10352c393a42Smrg    FcStrBufInit (&new->str, 0, 0);
10362c393a42Smrg    parse->pstack = new;
10372c393a42Smrg    return FcTrue;
10382c393a42Smrg}
10392c393a42Smrg
10402c393a42Smrgstatic FcBool
10412c393a42SmrgFcPStackPop (FcConfigParse *parse)
10422c393a42Smrg{
10432c393a42Smrg    FcPStack   *old;
1044ca08ab68Smrg
1045ca08ab68Smrg    if (!parse->pstack)
10462c393a42Smrg    {
10472c393a42Smrg	FcConfigMessage (parse, FcSevereError, "mismatching element");
10482c393a42Smrg	return FcFalse;
10492c393a42Smrg    }
10502c393a42Smrg    FcVStackClear (parse);
10512c393a42Smrg    old = parse->pstack;
10522c393a42Smrg    parse->pstack = old->prev;
10532c393a42Smrg    FcStrBufDestroy (&old->str);
1054a6844aabSmrg    if (old->attr && old->attr != old->attr_buf_static)
10552c393a42Smrg    {
10562c393a42Smrg	FcMemFree (FC_MEM_ATTR, 1); /* size is to expensive */
10572c393a42Smrg	free (old->attr);
10582c393a42Smrg    }
1059a6844aabSmrg
1060a6844aabSmrg    if (old == &parse->pstack_static[parse->pstack_static_used - 1])
1061a6844aabSmrg	parse->pstack_static_used--;
1062a6844aabSmrg    else
1063a6844aabSmrg    {
1064a6844aabSmrg	FcMemFree (FC_MEM_PSTACK, sizeof (FcPStack));
1065a6844aabSmrg	free (old);
1066a6844aabSmrg    }
10672c393a42Smrg    return FcTrue;
10682c393a42Smrg}
10692c393a42Smrg
10702c393a42Smrgstatic FcBool
10712c393a42SmrgFcConfigInit (FcConfigParse *parse, const FcChar8 *name, FcConfig *config, XML_Parser parser)
10722c393a42Smrg{
10732c393a42Smrg    parse->pstack = 0;
1074a6844aabSmrg    parse->pstack_static_used = 0;
10752c393a42Smrg    parse->vstack = 0;
1076a6844aabSmrg    parse->vstack_static_used = 0;
10772c393a42Smrg    parse->error = FcFalse;
10782c393a42Smrg    parse->name = name;
10792c393a42Smrg    parse->config = config;
10802c393a42Smrg    parse->parser = parser;
10812c393a42Smrg    return FcTrue;
10822c393a42Smrg}
10832c393a42Smrg
10842c393a42Smrgstatic void
10852c393a42SmrgFcConfigCleanup (FcConfigParse	*parse)
10862c393a42Smrg{
10872c393a42Smrg    while (parse->pstack)
10882c393a42Smrg	FcPStackPop (parse);
10892c393a42Smrg}
10902c393a42Smrg
10912c393a42Smrgstatic const FcChar8 *
10922c393a42SmrgFcConfigGetAttribute (FcConfigParse *parse, const char *attr)
10932c393a42Smrg{
10942c393a42Smrg    FcChar8 **attrs;
10952c393a42Smrg    if (!parse->pstack)
10962c393a42Smrg	return 0;
10972c393a42Smrg
10982c393a42Smrg    attrs = parse->pstack->attr;
10992c393a42Smrg    if (!attrs)
11002c393a42Smrg        return 0;
11012c393a42Smrg
11022c393a42Smrg    while (*attrs)
11032c393a42Smrg    {
11042c393a42Smrg	if (!strcmp ((char *) *attrs, attr))
11052c393a42Smrg	    return attrs[1];
11062c393a42Smrg	attrs += 2;
11072c393a42Smrg    }
11082c393a42Smrg    return 0;
11092c393a42Smrg}
11102c393a42Smrg
11112c393a42Smrgstatic void
11122c393a42SmrgFcStartElement(void *userData, const XML_Char *name, const XML_Char **attr)
11132c393a42Smrg{
11142c393a42Smrg    FcConfigParse   *parse = userData;
11152c393a42Smrg    FcElement	    element;
1116ca08ab68Smrg
11172c393a42Smrg    element = FcElementMap (name);
11182c393a42Smrg    if (element == FcElementUnknown)
11192c393a42Smrg	FcConfigMessage (parse, FcSevereWarning, "unknown element \"%s\"", name);
1120ca08ab68Smrg
11212c393a42Smrg    if (!FcPStackPush (parse, element, attr))
11222c393a42Smrg    {
11232c393a42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
11242c393a42Smrg	return;
11252c393a42Smrg    }
11262c393a42Smrg    return;
11272c393a42Smrg}
11282c393a42Smrg
11292c393a42Smrgstatic void
11302c393a42SmrgFcParseBlank (FcConfigParse *parse)
11312c393a42Smrg{
1132ca08ab68Smrg    int		n = FcVStackElements (parse);
1133ca08ab68Smrg    FcChar32	i;
11342c393a42Smrg    while (n-- > 0)
11352c393a42Smrg    {
11362c393a42Smrg	FcVStack    *v = FcVStackFetch (parse, n);
1137ca08ab68Smrg	if (!parse->config->blanks)
11382c393a42Smrg	{
1139ca08ab68Smrg	    parse->config->blanks = FcBlanksCreate ();
11402c393a42Smrg	    if (!parse->config->blanks)
1141ca08ab68Smrg		goto bail;
1142ca08ab68Smrg	}
1143ca08ab68Smrg	switch (v->tag) {
1144ca08ab68Smrg	case FcVStackInteger:
11452c393a42Smrg	    if (!FcBlanksAdd (parse->config->blanks, v->u.integer))
1146ca08ab68Smrg		goto bail;
1147ca08ab68Smrg	    break;
1148ca08ab68Smrg	case FcVStackRange:
1149ca08ab68Smrg	    if (v->u.range.begin <= v->u.range.end)
11502c393a42Smrg	    {
1151ca08ab68Smrg	      for (i = v->u.range.begin; i <= v->u.range.end; i++)
1152ca08ab68Smrg	      {
1153ca08ab68Smrg		  if (!FcBlanksAdd (parse->config->blanks, i))
1154ca08ab68Smrg		      goto bail;
1155ca08ab68Smrg	      }
11562c393a42Smrg	    }
1157ca08ab68Smrg	    break;
1158ca08ab68Smrg	default:
1159ca08ab68Smrg	    FcConfigMessage (parse, FcSevereError, "invalid element in blank");
1160ca08ab68Smrg	    break;
11612c393a42Smrg	}
11622c393a42Smrg    }
1163ca08ab68Smrg    return;
1164ca08ab68Smrg  bail:
1165ca08ab68Smrg    FcConfigMessage (parse, FcSevereError, "out of memory");
11662c393a42Smrg}
11672c393a42Smrg
11682c393a42Smrgstatic void
11692c393a42SmrgFcParseRescan (FcConfigParse *parse)
11702c393a42Smrg{
11712c393a42Smrg    int	    n = FcVStackElements (parse);
11722c393a42Smrg    while (n-- > 0)
11732c393a42Smrg    {
11742c393a42Smrg	FcVStack    *v = FcVStackFetch (parse, n);
11752c393a42Smrg	if (v->tag != FcVStackInteger)
11762c393a42Smrg	    FcConfigMessage (parse, FcSevereWarning, "non-integer rescan");
11772c393a42Smrg	else
11782c393a42Smrg	    parse->config->rescanInterval = v->u.integer;
11792c393a42Smrg    }
11802c393a42Smrg}
11812c393a42Smrg
11822c393a42Smrgstatic void
11832c393a42SmrgFcParseInt (FcConfigParse *parse)
11842c393a42Smrg{
11852c393a42Smrg    FcChar8 *s, *end;
11862c393a42Smrg    int	    l;
1187ca08ab68Smrg
11882c393a42Smrg    if (!parse->pstack)
11892c393a42Smrg	return;
1190a6844aabSmrg    s = FcStrBufDoneStatic (&parse->pstack->str);
11912c393a42Smrg    if (!s)
11922c393a42Smrg    {
11932c393a42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
11942c393a42Smrg	return;
11952c393a42Smrg    }
11962c393a42Smrg    end = 0;
11972c393a42Smrg    l = (int) strtol ((char *) s, (char **)&end, 0);
11982c393a42Smrg    if (end != s + strlen ((char *) s))
11992c393a42Smrg	FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid integer", s);
12002c393a42Smrg    else
12012c393a42Smrg	FcVStackPushInteger (parse, l);
1202a6844aabSmrg    FcStrBufDestroy (&parse->pstack->str);
12032c393a42Smrg}
12042c393a42Smrg
12052c393a42Smrg/*
1206ca08ab68Smrg * idea copied from glib g_ascii_strtod with
1207ca08ab68Smrg * permission of the author (Alexander Larsson)
12082c393a42Smrg */
12092c393a42Smrg
12102c393a42Smrg#include <locale.h>
12112c393a42Smrg
1212ca08ab68Smrgstatic double
12132c393a42SmrgFcStrtod (char *s, char **end)
12142c393a42Smrg{
12152c393a42Smrg    struct lconv    *locale_data;
12162c393a42Smrg    char	    *dot;
12172c393a42Smrg    double	    v;
12182c393a42Smrg
12192c393a42Smrg    /*
12202c393a42Smrg     * Have to swap the decimal point to match the current locale
12212c393a42Smrg     * if that locale doesn't use 0x2e
12222c393a42Smrg     */
12232c393a42Smrg    if ((dot = strchr (s, 0x2e)) &&
12242c393a42Smrg	(locale_data = localeconv ()) &&
12252c393a42Smrg	(locale_data->decimal_point[0] != 0x2e ||
12262c393a42Smrg	 locale_data->decimal_point[1] != 0))
12272c393a42Smrg    {
12282c393a42Smrg	char	buf[128];
12292c393a42Smrg	int	slen = strlen (s);
12302c393a42Smrg	int	dlen = strlen (locale_data->decimal_point);
12312c393a42Smrg
12322c393a42Smrg	if (slen + dlen > (int) sizeof (buf))
12332c393a42Smrg	{
12342c393a42Smrg	    if (end)
12352c393a42Smrg		*end = s;
12362c393a42Smrg	    v = 0;
12372c393a42Smrg	}
12382c393a42Smrg	else
12392c393a42Smrg	{
12402c393a42Smrg	    char	*buf_end;
12412c393a42Smrg	    /* mantissa */
12422c393a42Smrg	    strncpy (buf, s, dot - s);
12432c393a42Smrg	    /* decimal point */
12442c393a42Smrg	    strcpy (buf + (dot - s), locale_data->decimal_point);
12452c393a42Smrg	    /* rest of number */
12462c393a42Smrg	    strcpy (buf + (dot - s) + dlen, dot + 1);
12472c393a42Smrg	    buf_end = 0;
12482c393a42Smrg	    v = strtod (buf, &buf_end);
12492c393a42Smrg	    if (buf_end) {
12502c393a42Smrg		buf_end = s + (buf_end - buf);
12512c393a42Smrg		if (buf_end > dot)
12522c393a42Smrg		    buf_end -= dlen - 1;
12532c393a42Smrg	    }
12542c393a42Smrg	    if (end)
12552c393a42Smrg		*end = buf_end;
12562c393a42Smrg	}
12572c393a42Smrg    }
12582c393a42Smrg    else
12592c393a42Smrg	v = strtod (s, end);
12602c393a42Smrg    return v;
12612c393a42Smrg}
12622c393a42Smrg
12632c393a42Smrgstatic void
12642c393a42SmrgFcParseDouble (FcConfigParse *parse)
12652c393a42Smrg{
12662c393a42Smrg    FcChar8 *s, *end;
12672c393a42Smrg    double  d;
1268ca08ab68Smrg
12692c393a42Smrg    if (!parse->pstack)
12702c393a42Smrg	return;
1271a6844aabSmrg    s = FcStrBufDoneStatic (&parse->pstack->str);
12722c393a42Smrg    if (!s)
12732c393a42Smrg    {
12742c393a42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
12752c393a42Smrg	return;
12762c393a42Smrg    }
12772c393a42Smrg    end = 0;
12782c393a42Smrg    d = FcStrtod ((char *) s, (char **)&end);
12792c393a42Smrg    if (end != s + strlen ((char *) s))
12802c393a42Smrg	FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid double", s);
12812c393a42Smrg    else
12822c393a42Smrg	FcVStackPushDouble (parse, d);
1283a6844aabSmrg    FcStrBufDestroy (&parse->pstack->str);
12842c393a42Smrg}
12852c393a42Smrg
12862c393a42Smrgstatic void
12872c393a42SmrgFcParseString (FcConfigParse *parse, FcVStackTag tag)
12882c393a42Smrg{
12892c393a42Smrg    FcChar8 *s;
1290ca08ab68Smrg
12912c393a42Smrg    if (!parse->pstack)
12922c393a42Smrg	return;
12932c393a42Smrg    s = FcStrBufDone (&parse->pstack->str);
12942c393a42Smrg    if (!s)
12952c393a42Smrg    {
12962c393a42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
12972c393a42Smrg	return;
12982c393a42Smrg    }
12992c393a42Smrg    if (!FcVStackPushString (parse, tag, s))
13002c393a42Smrg	FcStrFree (s);
13012c393a42Smrg}
13022c393a42Smrg
13032c393a42Smrgstatic void
13042c393a42SmrgFcParseMatrix (FcConfigParse *parse)
13052c393a42Smrg{
13062c393a42Smrg    FcVStack	*vstack;
13072c393a42Smrg    enum { m_done, m_xx, m_xy, m_yx, m_yy } matrix_state = m_yy;
13082c393a42Smrg    FcMatrix	m;
1309ca08ab68Smrg
1310a6844aabSmrg    while ((vstack = FcVStackPeek (parse)))
13112c393a42Smrg    {
13122c393a42Smrg	double	v;
13132c393a42Smrg	switch (vstack->tag) {
13142c393a42Smrg	case FcVStackInteger:
13152c393a42Smrg	    v = vstack->u.integer;
13162c393a42Smrg	    break;
13172c393a42Smrg	case FcVStackDouble:
13182c393a42Smrg	    v = vstack->u._double;
13192c393a42Smrg	    break;
13202c393a42Smrg	default:
13212c393a42Smrg	    FcConfigMessage (parse, FcSevereError, "non-double matrix element");
13222c393a42Smrg	    v = 1.0;
13232c393a42Smrg	    break;
13242c393a42Smrg	}
13252c393a42Smrg	switch (matrix_state) {
13262c393a42Smrg	case m_xx: m.xx = v; break;
13272c393a42Smrg	case m_xy: m.xy = v; break;
13282c393a42Smrg	case m_yx: m.yx = v; break;
13292c393a42Smrg	case m_yy: m.yy = v; break;
13302c393a42Smrg	default: break;
13312c393a42Smrg	}
1332a6844aabSmrg	FcVStackPopAndDestroy (parse);
13332c393a42Smrg	matrix_state--;
13342c393a42Smrg    }
13352c393a42Smrg    if (matrix_state != m_done)
13362c393a42Smrg	FcConfigMessage (parse, FcSevereError, "wrong number of matrix elements");
13372c393a42Smrg    else
13382c393a42Smrg	FcVStackPushMatrix (parse, &m);
13392c393a42Smrg}
13402c393a42Smrg
1341ca08ab68Smrgstatic void
1342ca08ab68SmrgFcParseRange (FcConfigParse *parse)
1343ca08ab68Smrg{
1344ca08ab68Smrg    FcVStack	*vstack;
1345ca08ab68Smrg    FcRange	r;
1346ca08ab68Smrg    FcChar32	n;
1347ca08ab68Smrg    int		count = 1;
1348ca08ab68Smrg
1349ca08ab68Smrg    while ((vstack = FcVStackPeek (parse)))
1350ca08ab68Smrg    {
1351ca08ab68Smrg	if (count < 0)
1352ca08ab68Smrg	{
1353ca08ab68Smrg	    FcConfigMessage (parse, FcSevereError, "too many elements in range");
1354ca08ab68Smrg	    return;
1355ca08ab68Smrg	}
1356ca08ab68Smrg	switch (vstack->tag) {
1357ca08ab68Smrg	case FcVStackInteger:
1358ca08ab68Smrg	    n = vstack->u.integer;
1359ca08ab68Smrg	    break;
1360ca08ab68Smrg	default:
1361ca08ab68Smrg	    FcConfigMessage (parse, FcSevereError, "invalid element in range");
1362ca08ab68Smrg	    n = 0;
1363ca08ab68Smrg	    break;
1364ca08ab68Smrg	}
1365ca08ab68Smrg	if (count == 1)
1366ca08ab68Smrg	    r.end = n;
1367ca08ab68Smrg	else
1368ca08ab68Smrg	    r.begin = n;
1369ca08ab68Smrg	count--;
1370ca08ab68Smrg	FcVStackPopAndDestroy (parse);
1371ca08ab68Smrg    }
1372ca08ab68Smrg    if (count < 0)
1373ca08ab68Smrg    {
1374ca08ab68Smrg	if (r.begin > r.end)
1375ca08ab68Smrg	{
1376ca08ab68Smrg	    FcConfigMessage (parse, FcSevereError, "invalid range");
1377ca08ab68Smrg	    return;
1378ca08ab68Smrg	}
1379ca08ab68Smrg	FcVStackPushRange (parse, &r);
1380ca08ab68Smrg    }
1381ca08ab68Smrg    else
1382ca08ab68Smrg	FcConfigMessage (parse, FcSevereError, "invalid range");
1383ca08ab68Smrg}
1384ca08ab68Smrg
13852c393a42Smrgstatic FcBool
1386a6844aabSmrgFcConfigLexBool (FcConfigParse *parse, const FcChar8 *bool_)
13872c393a42Smrg{
13882c393a42Smrg    FcBool  result = FcFalse;
13892c393a42Smrg
1390a6844aabSmrg    if (!FcNameBool (bool_, &result))
13912c393a42Smrg	FcConfigMessage (parse, FcSevereWarning, "\"%s\" is not known boolean",
1392a6844aabSmrg			 bool_);
13932c393a42Smrg    return result;
13942c393a42Smrg}
13952c393a42Smrg
13962c393a42Smrgstatic void
13972c393a42SmrgFcParseBool (FcConfigParse *parse)
13982c393a42Smrg{
13992c393a42Smrg    FcChar8 *s;
14002c393a42Smrg
14012c393a42Smrg    if (!parse->pstack)
14022c393a42Smrg	return;
1403a6844aabSmrg    s = FcStrBufDoneStatic (&parse->pstack->str);
14042c393a42Smrg    if (!s)
14052c393a42Smrg    {
14062c393a42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
14072c393a42Smrg	return;
14082c393a42Smrg    }
14092c393a42Smrg    FcVStackPushBool (parse, FcConfigLexBool (parse, s));
1410a6844aabSmrg    FcStrBufDestroy (&parse->pstack->str);
14112c393a42Smrg}
14122c393a42Smrg
1413ca08ab68Smrgstatic void
1414ca08ab68SmrgFcParseCharSet (FcConfigParse *parse)
1415ca08ab68Smrg{
1416ca08ab68Smrg    FcVStack	*vstack;
1417ca08ab68Smrg    FcCharSet	*charset = FcCharSetCreate ();
1418ca08ab68Smrg    FcChar32	i;
1419ca08ab68Smrg    int n = 0;
1420ca08ab68Smrg
1421ca08ab68Smrg    while ((vstack = FcVStackPeek (parse)))
1422ca08ab68Smrg    {
1423ca08ab68Smrg	switch (vstack->tag) {
1424ca08ab68Smrg	case FcVStackInteger:
1425ca08ab68Smrg	    if (!FcCharSetAddChar (charset, vstack->u.integer))
1426ca08ab68Smrg	    {
1427ca08ab68Smrg		FcConfigMessage (parse, FcSevereWarning, "invalid character: 0x%04x", vstack->u.integer);
1428ca08ab68Smrg	    }
1429ca08ab68Smrg	    else
1430ca08ab68Smrg		n++;
1431ca08ab68Smrg	    break;
1432ca08ab68Smrg	case FcVStackRange:
1433ca08ab68Smrg	    if (vstack->u.range.begin <= vstack->u.range.end)
1434ca08ab68Smrg	    {
1435ca08ab68Smrg	      for (i = vstack->u.range.begin; i <= vstack->u.range.end; i++)
1436ca08ab68Smrg	      {
1437ca08ab68Smrg		  if (!FcCharSetAddChar (charset, i))
1438ca08ab68Smrg		  {
1439ca08ab68Smrg		      FcConfigMessage (parse, FcSevereWarning, "invalid character: 0x%04x", i);
1440ca08ab68Smrg		  }
1441ca08ab68Smrg		  else
1442ca08ab68Smrg		      n++;
1443ca08ab68Smrg	      }
1444ca08ab68Smrg	    }
1445ca08ab68Smrg	    break;
1446ca08ab68Smrg	default:
1447ca08ab68Smrg		FcConfigMessage (parse, FcSevereError, "invalid element in charset");
1448ca08ab68Smrg		break;
1449ca08ab68Smrg	}
1450ca08ab68Smrg	FcVStackPopAndDestroy (parse);
1451ca08ab68Smrg    }
1452ca08ab68Smrg    if (n > 0)
1453ca08ab68Smrg	    FcVStackPushCharSet (parse, charset);
1454ca08ab68Smrg    else
1455ca08ab68Smrg	    FcCharSetDestroy (charset);
1456ca08ab68Smrg}
1457ca08ab68Smrg
1458ca08ab68Smrgstatic void
1459ca08ab68SmrgFcParseLangSet (FcConfigParse *parse)
1460ca08ab68Smrg{
1461ca08ab68Smrg    FcVStack	*vstack;
1462ca08ab68Smrg    FcLangSet	*langset = FcLangSetCreate ();
1463ca08ab68Smrg    int n = 0;
1464ca08ab68Smrg
1465ca08ab68Smrg    while ((vstack = FcVStackPeek (parse)))
1466ca08ab68Smrg    {
1467ca08ab68Smrg	switch (vstack->tag) {
1468ca08ab68Smrg	case FcVStackString:
1469ca08ab68Smrg	    if (!FcLangSetAdd (langset, vstack->u.string))
1470ca08ab68Smrg	    {
1471ca08ab68Smrg		FcConfigMessage (parse, FcSevereWarning, "invalid langset: %s", vstack->u.string);
1472ca08ab68Smrg	    }
1473ca08ab68Smrg	    else
1474ca08ab68Smrg		n++;
1475ca08ab68Smrg	    break;
1476ca08ab68Smrg	default:
1477ca08ab68Smrg		FcConfigMessage (parse, FcSevereError, "invalid element in langset");
1478ca08ab68Smrg		break;
1479ca08ab68Smrg	}
1480ca08ab68Smrg	FcVStackPopAndDestroy (parse);
1481ca08ab68Smrg    }
1482ca08ab68Smrg    if (n > 0)
1483ca08ab68Smrg	    FcVStackPushLangSet (parse, langset);
1484ca08ab68Smrg    else
1485ca08ab68Smrg	    FcLangSetDestroy (langset);
1486ca08ab68Smrg}
1487ca08ab68Smrg
14882c393a42Smrgstatic FcBool
14892c393a42SmrgFcConfigLexBinding (FcConfigParse   *parse,
14902c393a42Smrg		    const FcChar8   *binding_string,
14912c393a42Smrg		    FcValueBinding  *binding_ret)
14922c393a42Smrg{
14932c393a42Smrg    FcValueBinding binding;
1494ca08ab68Smrg
14952c393a42Smrg    if (!binding_string)
14962c393a42Smrg	binding = FcValueBindingWeak;
14972c393a42Smrg    else
14982c393a42Smrg    {
14992c393a42Smrg	if (!strcmp ((char *) binding_string, "weak"))
15002c393a42Smrg	    binding = FcValueBindingWeak;
15012c393a42Smrg	else if (!strcmp ((char *) binding_string, "strong"))
15022c393a42Smrg	    binding = FcValueBindingStrong;
15032c393a42Smrg	else if (!strcmp ((char *) binding_string, "same"))
15042c393a42Smrg	    binding = FcValueBindingSame;
15052c393a42Smrg	else
15062c393a42Smrg	{
15072c393a42Smrg	    FcConfigMessage (parse, FcSevereWarning, "invalid binding \"%s\"", binding_string);
15082c393a42Smrg	    return FcFalse;
15092c393a42Smrg	}
15102c393a42Smrg    }
15112c393a42Smrg    *binding_ret = binding;
15122c393a42Smrg    return FcTrue;
15132c393a42Smrg}
15142c393a42Smrg
15152c393a42Smrgstatic void
15162c393a42SmrgFcParseFamilies (FcConfigParse *parse, FcVStackTag tag)
15172c393a42Smrg{
15182c393a42Smrg    FcVStack	*vstack;
15192c393a42Smrg    FcExpr	*left, *expr = 0, *new;
15202c393a42Smrg
1521a6844aabSmrg    while ((vstack = FcVStackPeek (parse)))
15222c393a42Smrg    {
15232c393a42Smrg	if (vstack->tag != FcVStackFamily)
15242c393a42Smrg	{
15252c393a42Smrg	    FcConfigMessage (parse, FcSevereWarning, "non-family");
1526a6844aabSmrg	    FcVStackPopAndDestroy (parse);
15272c393a42Smrg	    continue;
15282c393a42Smrg	}
15292c393a42Smrg	left = vstack->u.expr;
15302c393a42Smrg	vstack->tag = FcVStackNone;
1531a6844aabSmrg	FcVStackPopAndDestroy (parse);
15322c393a42Smrg	if (expr)
15332c393a42Smrg	{
1534a6844aabSmrg	    new = FcExprCreateOp (parse->config, left, FcOpComma, expr);
15352c393a42Smrg	    if (!new)
15362c393a42Smrg	    {
15372c393a42Smrg		FcConfigMessage (parse, FcSevereError, "out of memory");
15382c393a42Smrg		FcExprDestroy (left);
15392c393a42Smrg		FcExprDestroy (expr);
15402c393a42Smrg		break;
15412c393a42Smrg	    }
15422c393a42Smrg	    expr = new;
15432c393a42Smrg	}
15442c393a42Smrg	else
15452c393a42Smrg	    expr = left;
15462c393a42Smrg    }
15472c393a42Smrg    if (expr)
15482c393a42Smrg    {
15492c393a42Smrg	if (!FcVStackPushExpr (parse, tag, expr))
15502c393a42Smrg	{
15512c393a42Smrg	    FcConfigMessage (parse, FcSevereError, "out of memory");
15522c393a42Smrg            FcExprDestroy (expr);
15532c393a42Smrg	}
15542c393a42Smrg    }
15552c393a42Smrg}
15562c393a42Smrg
15572c393a42Smrgstatic void
15582c393a42SmrgFcParseFamily (FcConfigParse *parse)
15592c393a42Smrg{
15602c393a42Smrg    FcChar8 *s;
15612c393a42Smrg    FcExpr  *expr;
15622c393a42Smrg
15632c393a42Smrg    if (!parse->pstack)
15642c393a42Smrg	return;
1565a6844aabSmrg    s = FcStrBufDoneStatic (&parse->pstack->str);
15662c393a42Smrg    if (!s)
15672c393a42Smrg    {
15682c393a42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
15692c393a42Smrg	return;
15702c393a42Smrg    }
1571a6844aabSmrg    expr = FcExprCreateString (parse->config, s);
1572a6844aabSmrg    FcStrBufDestroy (&parse->pstack->str);
15732c393a42Smrg    if (expr)
15742c393a42Smrg	FcVStackPushExpr (parse, FcVStackFamily, expr);
15752c393a42Smrg}
15762c393a42Smrg
15772c393a42Smrgstatic void
15782c393a42SmrgFcParseAlias (FcConfigParse *parse)
15792c393a42Smrg{
15802c393a42Smrg    FcExpr	*family = 0, *accept = 0, *prefer = 0, *def = 0, *new = 0;
15812c393a42Smrg    FcEdit	*edit = 0, *next;
15822c393a42Smrg    FcVStack	*vstack;
1583ca08ab68Smrg    FcTest	*test = NULL;
15842c393a42Smrg    FcValueBinding  binding;
15852c393a42Smrg
15862c393a42Smrg    if (!FcConfigLexBinding (parse, FcConfigGetAttribute (parse, "binding"), &binding))
15872c393a42Smrg	return;
1588a6844aabSmrg    while ((vstack = FcVStackPeek (parse)))
15892c393a42Smrg    {
15902c393a42Smrg	switch (vstack->tag) {
15912c393a42Smrg	case FcVStackFamily:
15922c393a42Smrg	    if (family)
15932c393a42Smrg	    {
1594ca08ab68Smrg		FcConfigMessage (parse, FcSevereWarning, "Having multiple <family> in <alias> isn't supported and may not work as expected");
1595a6844aabSmrg		new = FcExprCreateOp (parse->config, vstack->u.expr, FcOpComma, family);
15962c393a42Smrg		if (!new)
15972c393a42Smrg		    FcConfigMessage (parse, FcSevereError, "out of memory");
15982c393a42Smrg		else
15992c393a42Smrg		    family = new;
16002c393a42Smrg	    }
16012c393a42Smrg	    else
16022c393a42Smrg		new = vstack->u.expr;
16032c393a42Smrg	    if (new)
16042c393a42Smrg	    {
16052c393a42Smrg		family = new;
16062c393a42Smrg		vstack->tag = FcVStackNone;
16072c393a42Smrg	    }
16082c393a42Smrg	    break;
16092c393a42Smrg	case FcVStackPrefer:
16102c393a42Smrg	    if (prefer)
16112c393a42Smrg		FcExprDestroy (prefer);
16122c393a42Smrg	    prefer = vstack->u.expr;
16132c393a42Smrg	    vstack->tag = FcVStackNone;
16142c393a42Smrg	    break;
16152c393a42Smrg	case FcVStackAccept:
16162c393a42Smrg	    if (accept)
16172c393a42Smrg		FcExprDestroy (accept);
16182c393a42Smrg	    accept = vstack->u.expr;
16192c393a42Smrg	    vstack->tag = FcVStackNone;
16202c393a42Smrg	    break;
16212c393a42Smrg	case FcVStackDefault:
16222c393a42Smrg	    if (def)
16232c393a42Smrg		FcExprDestroy (def);
16242c393a42Smrg	    def = vstack->u.expr;
16252c393a42Smrg	    vstack->tag = FcVStackNone;
16262c393a42Smrg	    break;
1627ca08ab68Smrg	case FcVStackTest:
1628ca08ab68Smrg	    vstack->u.test->next = test;
1629ca08ab68Smrg	    test = vstack->u.test;
1630ca08ab68Smrg	    vstack->tag = FcVStackNone;
1631ca08ab68Smrg	    break;
16322c393a42Smrg	default:
16332c393a42Smrg	    FcConfigMessage (parse, FcSevereWarning, "bad alias");
16342c393a42Smrg	    break;
16352c393a42Smrg	}
1636a6844aabSmrg	FcVStackPopAndDestroy (parse);
16372c393a42Smrg    }
16382c393a42Smrg    if (!family)
16392c393a42Smrg    {
16402c393a42Smrg	FcConfigMessage (parse, FcSevereError, "missing family in alias");
16412c393a42Smrg	if (prefer)
16422c393a42Smrg	    FcExprDestroy (prefer);
16432c393a42Smrg	if (accept)
16442c393a42Smrg	    FcExprDestroy (accept);
16452c393a42Smrg	if (def)
16462c393a42Smrg	    FcExprDestroy (def);
16472c393a42Smrg	return;
16482c393a42Smrg    }
16492c393a42Smrg    if (prefer)
16502c393a42Smrg    {
1651ca08ab68Smrg	edit = FcEditCreate (parse,
16522c393a42Smrg			     FC_FAMILY_OBJECT,
16532c393a42Smrg			     FcOpPrepend,
16542c393a42Smrg			     prefer,
16552c393a42Smrg			     binding);
16562c393a42Smrg	if (edit)
16572c393a42Smrg	    edit->next = 0;
16582c393a42Smrg	else
16592c393a42Smrg	    FcExprDestroy (prefer);
16602c393a42Smrg    }
16612c393a42Smrg    if (accept)
16622c393a42Smrg    {
16632c393a42Smrg	next = edit;
16642c393a42Smrg	edit = FcEditCreate (parse,
16652c393a42Smrg			     FC_FAMILY_OBJECT,
16662c393a42Smrg			     FcOpAppend,
16672c393a42Smrg			     accept,
16682c393a42Smrg			     binding);
16692c393a42Smrg	if (edit)
16702c393a42Smrg	    edit->next = next;
16712c393a42Smrg	else
16722c393a42Smrg	    FcExprDestroy (accept);
16732c393a42Smrg    }
16742c393a42Smrg    if (def)
16752c393a42Smrg    {
16762c393a42Smrg	next = edit;
16772c393a42Smrg	edit = FcEditCreate (parse,
16782c393a42Smrg			     FC_FAMILY_OBJECT,
16792c393a42Smrg			     FcOpAppendLast,
16802c393a42Smrg			     def,
16812c393a42Smrg			     binding);
16822c393a42Smrg	if (edit)
16832c393a42Smrg	    edit->next = next;
16842c393a42Smrg	else
16852c393a42Smrg	    FcExprDestroy (def);
16862c393a42Smrg    }
16872c393a42Smrg    if (edit)
16882c393a42Smrg    {
1689ca08ab68Smrg	FcTest *t = FcTestCreate (parse, FcMatchPattern,
1690ca08ab68Smrg				  FcQualAny,
1691ca08ab68Smrg				  (FcChar8 *) FC_FAMILY,
1692ca08ab68Smrg				  FC_OP (FcOpEqual, FcOpFlagIgnoreBlanks),
1693ca08ab68Smrg				  family);
1694ca08ab68Smrg	if (test)
1695ca08ab68Smrg	{
1696ca08ab68Smrg	    FcTest *p = test;
1697ca08ab68Smrg
1698ca08ab68Smrg	    while (p->next)
1699ca08ab68Smrg		p = p->next;
1700ca08ab68Smrg	    p->next = t;
1701ca08ab68Smrg	}
1702ca08ab68Smrg	else
1703ca08ab68Smrg	    test = t;
17042c393a42Smrg	if (test)
17052c393a42Smrg	    if (!FcConfigAddEdit (parse->config, test, edit, FcMatchPattern))
17062c393a42Smrg		FcTestDestroy (test);
17072c393a42Smrg    }
17082c393a42Smrg    else
17092c393a42Smrg	FcExprDestroy (family);
17102c393a42Smrg}
17112c393a42Smrg
17122c393a42Smrgstatic FcExpr *
17132c393a42SmrgFcPopExpr (FcConfigParse *parse)
17142c393a42Smrg{
1715a6844aabSmrg    FcVStack	*vstack = FcVStackPeek (parse);
17162c393a42Smrg    FcExpr	*expr = 0;
17172c393a42Smrg    if (!vstack)
17182c393a42Smrg	return 0;
17192c393a42Smrg    switch (vstack->tag) {
17202c393a42Smrg    case FcVStackNone:
17212c393a42Smrg	break;
17222c393a42Smrg    case FcVStackString:
17232c393a42Smrg    case FcVStackFamily:
1724a6844aabSmrg	expr = FcExprCreateString (parse->config, vstack->u.string);
17252c393a42Smrg	break;
17262c393a42Smrg    case FcVStackField:
1727a6844aabSmrg	expr = FcExprCreateField (parse->config, (char *) vstack->u.string);
17282c393a42Smrg	break;
17292c393a42Smrg    case FcVStackConstant:
1730a6844aabSmrg	expr = FcExprCreateConst (parse->config, vstack->u.string);
17312c393a42Smrg	break;
17322c393a42Smrg    case FcVStackGlob:
17332c393a42Smrg	/* XXX: What's the correct action here? (CDW) */
17342c393a42Smrg	break;
17352c393a42Smrg    case FcVStackPrefer:
17362c393a42Smrg    case FcVStackAccept:
17372c393a42Smrg    case FcVStackDefault:
17382c393a42Smrg	expr = vstack->u.expr;
17392c393a42Smrg	vstack->tag = FcVStackNone;
17402c393a42Smrg	break;
17412c393a42Smrg    case FcVStackInteger:
1742a6844aabSmrg	expr = FcExprCreateInteger (parse->config, vstack->u.integer);
17432c393a42Smrg	break;
17442c393a42Smrg    case FcVStackDouble:
1745a6844aabSmrg	expr = FcExprCreateDouble (parse->config, vstack->u._double);
17462c393a42Smrg	break;
17472c393a42Smrg    case FcVStackMatrix:
1748a6844aabSmrg	expr = FcExprCreateMatrix (parse->config, vstack->u.matrix);
17492c393a42Smrg	break;
1750ca08ab68Smrg    case FcVStackRange:
1751ca08ab68Smrg	break;
17522c393a42Smrg    case FcVStackBool:
1753a6844aabSmrg	expr = FcExprCreateBool (parse->config, vstack->u.bool_);
17542c393a42Smrg	break;
1755ca08ab68Smrg    case FcVStackCharSet:
1756ca08ab68Smrg	expr = FcExprCreateCharSet (parse->config, vstack->u.charset);
1757ca08ab68Smrg	break;
1758ca08ab68Smrg    case FcVStackLangSet:
1759ca08ab68Smrg	expr = FcExprCreateLangSet (parse->config, vstack->u.langset);
1760ca08ab68Smrg	break;
17612c393a42Smrg    case FcVStackTest:
17622c393a42Smrg	break;
17632c393a42Smrg    case FcVStackExpr:
17642c393a42Smrg	expr = vstack->u.expr;
17652c393a42Smrg	vstack->tag = FcVStackNone;
17662c393a42Smrg	break;
17672c393a42Smrg    case FcVStackEdit:
17682c393a42Smrg	break;
17692c393a42Smrg    default:
17702c393a42Smrg	break;
17712c393a42Smrg    }
1772a6844aabSmrg    FcVStackPopAndDestroy (parse);
17732c393a42Smrg    return expr;
17742c393a42Smrg}
17752c393a42Smrg
17762c393a42Smrg/*
17772c393a42Smrg * This builds a tree of binary operations.  Note
17782c393a42Smrg * that every operator is defined so that if only
17792c393a42Smrg * a single operand is contained, the value of the
17802c393a42Smrg * whole expression is the value of the operand.
17812c393a42Smrg *
17822c393a42Smrg * This code reduces in that case to returning that
17832c393a42Smrg * operand.
17842c393a42Smrg */
17852c393a42Smrgstatic FcExpr *
17862c393a42SmrgFcPopBinary (FcConfigParse *parse, FcOp op)
17872c393a42Smrg{
17882c393a42Smrg    FcExpr  *left, *expr = 0, *new;
17892c393a42Smrg
17902c393a42Smrg    while ((left = FcPopExpr (parse)))
17912c393a42Smrg    {
17922c393a42Smrg	if (expr)
17932c393a42Smrg	{
1794a6844aabSmrg	    new = FcExprCreateOp (parse->config, left, op, expr);
17952c393a42Smrg	    if (!new)
17962c393a42Smrg	    {
17972c393a42Smrg		FcConfigMessage (parse, FcSevereError, "out of memory");
17982c393a42Smrg		FcExprDestroy (left);
17992c393a42Smrg		FcExprDestroy (expr);
18002c393a42Smrg		return 0;
18012c393a42Smrg	    }
18022c393a42Smrg	    expr = new;
18032c393a42Smrg	}
18042c393a42Smrg	else
18052c393a42Smrg	    expr = left;
18062c393a42Smrg    }
18072c393a42Smrg    return expr;
18082c393a42Smrg}
18092c393a42Smrg
18102c393a42Smrgstatic void
18112c393a42SmrgFcParseBinary (FcConfigParse *parse, FcOp op)
18122c393a42Smrg{
18132c393a42Smrg    FcExpr  *expr = FcPopBinary (parse, op);
18142c393a42Smrg    if (expr)
18152c393a42Smrg	FcVStackPushExpr (parse, FcVStackExpr, expr);
18162c393a42Smrg}
18172c393a42Smrg
18182c393a42Smrg/*
18192c393a42Smrg * This builds a a unary operator, it consumes only
18202c393a42Smrg * a single operand
18212c393a42Smrg */
18222c393a42Smrg
18232c393a42Smrgstatic FcExpr *
18242c393a42SmrgFcPopUnary (FcConfigParse *parse, FcOp op)
18252c393a42Smrg{
18262c393a42Smrg    FcExpr  *operand, *new = 0;
18272c393a42Smrg
18282c393a42Smrg    if ((operand = FcPopExpr (parse)))
18292c393a42Smrg    {
1830a6844aabSmrg	new = FcExprCreateOp (parse->config, operand, op, 0);
18312c393a42Smrg	if (!new)
18322c393a42Smrg	{
18332c393a42Smrg	    FcExprDestroy (operand);
18342c393a42Smrg	    FcConfigMessage (parse, FcSevereError, "out of memory");
18352c393a42Smrg	}
18362c393a42Smrg    }
18372c393a42Smrg    return new;
18382c393a42Smrg}
18392c393a42Smrg
18402c393a42Smrgstatic void
18412c393a42SmrgFcParseUnary (FcConfigParse *parse, FcOp op)
18422c393a42Smrg{
18432c393a42Smrg    FcExpr  *expr = FcPopUnary (parse, op);
18442c393a42Smrg    if (expr)
18452c393a42Smrg	FcVStackPushExpr (parse, FcVStackExpr, expr);
18462c393a42Smrg}
18472c393a42Smrg
1848ca08ab68Smrgstatic void
1849ca08ab68SmrgFcParseDir (FcConfigParse *parse)
1850ca08ab68Smrg{
1851ca08ab68Smrg    const FcChar8 *attr, *data;
1852ca08ab68Smrg    FcChar8 *prefix = NULL;
1853ca08ab68Smrg#ifdef _WIN32
1854ca08ab68Smrg    FcChar8         buffer[1000];
1855ca08ab68Smrg#endif
1856ca08ab68Smrg
1857ca08ab68Smrg    attr = FcConfigGetAttribute (parse, "prefix");
1858ca08ab68Smrg    if (attr && FcStrCmp (attr, (const FcChar8 *)"xdg") == 0)
1859ca08ab68Smrg	prefix = FcConfigXdgDataHome ();
1860ca08ab68Smrg    data = FcStrBufDoneStatic (&parse->pstack->str);
1861ca08ab68Smrg    if (!data)
1862ca08ab68Smrg    {
1863ca08ab68Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
1864ca08ab68Smrg	goto bail;
1865ca08ab68Smrg    }
1866ca08ab68Smrg    if (prefix)
1867ca08ab68Smrg    {
1868ca08ab68Smrg	size_t plen = strlen ((const char *)prefix);
1869ca08ab68Smrg	size_t dlen = strlen ((const char *)data);
1870ca08ab68Smrg
1871ca08ab68Smrg	FcMemFree (FC_MEM_STRING, plen + 1);
1872ca08ab68Smrg	prefix = realloc (prefix, plen + 1 + dlen + 1);
1873ca08ab68Smrg	if (!prefix)
1874ca08ab68Smrg	{
1875ca08ab68Smrg	    FcConfigMessage (parse, FcSevereError, "out of memory");
1876ca08ab68Smrg	    goto bail;
1877ca08ab68Smrg	}
1878ca08ab68Smrg	FcMemAlloc (FC_MEM_STRING, plen + 1 + dlen + 1);
1879ca08ab68Smrg	prefix[plen] = FC_DIR_SEPARATOR;
1880ca08ab68Smrg	memcpy (&prefix[plen + 1], data, dlen);
1881ca08ab68Smrg	prefix[plen + 1 + dlen] = 0;
1882ca08ab68Smrg	data = prefix;
1883ca08ab68Smrg    }
1884ca08ab68Smrg#ifdef _WIN32
1885ca08ab68Smrg    if (strcmp ((const char *) data, "CUSTOMFONTDIR") == 0)
1886ca08ab68Smrg    {
1887ca08ab68Smrg	char *p;
1888ca08ab68Smrg	data = buffer;
1889ca08ab68Smrg	if (!GetModuleFileName (NULL, (LPCH) buffer, sizeof (buffer) - 20))
1890ca08ab68Smrg	{
1891ca08ab68Smrg	    FcConfigMessage (parse, FcSevereError, "GetModuleFileName failed");
1892ca08ab68Smrg	    goto bail;
1893ca08ab68Smrg	}
1894ca08ab68Smrg	/*
1895ca08ab68Smrg	 * Must use the multi-byte aware function to search
1896ca08ab68Smrg	 * for backslash because East Asian double-byte code
1897ca08ab68Smrg	 * pages have characters with backslash as the second
1898ca08ab68Smrg	 * byte.
1899ca08ab68Smrg	 */
1900ca08ab68Smrg	p = _mbsrchr (data, '\\');
1901ca08ab68Smrg	if (p) *p = '\0';
1902ca08ab68Smrg	strcat (data, "\\fonts");
1903ca08ab68Smrg    }
1904ca08ab68Smrg    else if (strcmp ((const char *) data, "APPSHAREFONTDIR") == 0)
1905ca08ab68Smrg    {
1906ca08ab68Smrg	char *p;
1907ca08ab68Smrg	data = buffer;
1908ca08ab68Smrg	if (!GetModuleFileName (NULL, (LPCH) buffer, sizeof (buffer) - 20))
1909ca08ab68Smrg	{
1910ca08ab68Smrg	    FcConfigMessage (parse, FcSevereError, "GetModuleFileName failed");
1911ca08ab68Smrg	    goto bail;
1912ca08ab68Smrg	}
1913ca08ab68Smrg	p = _mbsrchr (data, '\\');
1914ca08ab68Smrg	if (p) *p = '\0';
1915ca08ab68Smrg	strcat (data, "\\..\\share\\fonts");
1916ca08ab68Smrg    }
1917ca08ab68Smrg    else if (strcmp ((const char *) data, "WINDOWSFONTDIR") == 0)
1918ca08ab68Smrg    {
1919ca08ab68Smrg	int rc;
1920ca08ab68Smrg	data = buffer;
1921ca08ab68Smrg	rc = pGetSystemWindowsDirectory ((LPSTR) buffer, sizeof (buffer) - 20);
1922ca08ab68Smrg	if (rc == 0 || rc > sizeof (buffer) - 20)
1923ca08ab68Smrg	{
1924ca08ab68Smrg	    FcConfigMessage (parse, FcSevereError, "GetSystemWindowsDirectory failed");
1925ca08ab68Smrg	    goto bail;
1926ca08ab68Smrg	}
1927ca08ab68Smrg	if (data [strlen ((const char *) data) - 1] != '\\')
1928ca08ab68Smrg	    strcat (data, "\\");
1929ca08ab68Smrg	strcat (data, "fonts");
1930ca08ab68Smrg    }
1931ca08ab68Smrg#endif
1932ca08ab68Smrg    if (strlen ((char *) data) == 0)
1933ca08ab68Smrg	FcConfigMessage (parse, FcSevereWarning, "empty font directory name ignored");
1934ca08ab68Smrg    else if (!FcStrUsesHome (data) || FcConfigHome ())
1935ca08ab68Smrg    {
1936ca08ab68Smrg	if (!FcConfigAddDir (parse->config, data))
1937ca08ab68Smrg	    FcConfigMessage (parse, FcSevereError, "out of memory; cannot add directory %s", data);
1938ca08ab68Smrg    }
1939ca08ab68Smrg    FcStrBufDestroy (&parse->pstack->str);
1940ca08ab68Smrg
1941ca08ab68Smrg  bail:
1942ca08ab68Smrg    if (prefix)
1943ca08ab68Smrg	FcStrFree (prefix);
1944ca08ab68Smrg}
1945ca08ab68Smrg
1946ca08ab68Smrgstatic void
1947ca08ab68SmrgFcParseCacheDir (FcConfigParse *parse)
1948ca08ab68Smrg{
1949ca08ab68Smrg    const FcChar8 *attr;
1950ca08ab68Smrg    FcChar8 *prefix = NULL, *data;
1951ca08ab68Smrg
1952ca08ab68Smrg    attr = FcConfigGetAttribute (parse, "prefix");
1953ca08ab68Smrg    if (attr && FcStrCmp (attr, (const FcChar8 *)"xdg") == 0)
1954ca08ab68Smrg	prefix = FcConfigXdgCacheHome ();
1955ca08ab68Smrg    data = FcStrBufDone (&parse->pstack->str);
1956ca08ab68Smrg    if (!data)
1957ca08ab68Smrg    {
1958ca08ab68Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
1959ca08ab68Smrg	goto bail;
1960ca08ab68Smrg    }
1961ca08ab68Smrg    if (prefix)
1962ca08ab68Smrg    {
1963ca08ab68Smrg	size_t plen = strlen ((const char *)prefix);
1964ca08ab68Smrg	size_t dlen = strlen ((const char *)data);
1965ca08ab68Smrg
1966ca08ab68Smrg	FcMemFree (FC_MEM_STRING, plen + 1);
1967ca08ab68Smrg	prefix = realloc (prefix, plen + 1 + dlen + 1);
1968ca08ab68Smrg	if (!prefix)
1969ca08ab68Smrg	{
1970ca08ab68Smrg	    FcConfigMessage (parse, FcSevereError, "out of memory");
1971ca08ab68Smrg	    goto bail;
1972ca08ab68Smrg	}
1973ca08ab68Smrg	FcMemAlloc (FC_MEM_STRING, plen + 1 + dlen + 1);
1974ca08ab68Smrg	prefix[plen] = FC_DIR_SEPARATOR;
1975ca08ab68Smrg	memcpy (&prefix[plen + 1], data, dlen);
1976ca08ab68Smrg	prefix[plen + 1 + dlen] = 0;
1977ca08ab68Smrg	FcStrFree (data);
1978ca08ab68Smrg	data = prefix;
1979ca08ab68Smrg    }
1980ca08ab68Smrg#ifdef _WIN32
1981ca08ab68Smrg    if (strcmp ((const char *) data, "WINDOWSTEMPDIR_FONTCONFIG_CACHE") == 0)
1982ca08ab68Smrg    {
1983ca08ab68Smrg	int rc;
1984ca08ab68Smrg	FcStrFree (data);
1985ca08ab68Smrg	data = malloc (1000);
1986ca08ab68Smrg	if (!data)
1987ca08ab68Smrg	{
1988ca08ab68Smrg	    FcConfigMessage (parse, FcSevereError, "out of memory");
1989ca08ab68Smrg	    goto bail;
1990ca08ab68Smrg	}
1991ca08ab68Smrg	FcMemAlloc (FC_MEM_STRING, 1000);
1992ca08ab68Smrg	rc = GetTempPath (800, (LPSTR) data);
1993ca08ab68Smrg	if (rc == 0 || rc > 800)
1994ca08ab68Smrg	{
1995ca08ab68Smrg	    FcConfigMessage (parse, FcSevereError, "GetTempPath failed");
1996ca08ab68Smrg	    goto bail;
1997ca08ab68Smrg	}
1998ca08ab68Smrg	if (data [strlen ((const char *) data) - 1] != '\\')
1999ca08ab68Smrg	    strcat (data, "\\");
2000ca08ab68Smrg	strcat (data, "fontconfig\\cache");
2001ca08ab68Smrg    }
2002ca08ab68Smrg    else if (strcmp ((const char *) data, "LOCAL_APPDATA_FONTCONFIG_CACHE") == 0)
2003ca08ab68Smrg    {
2004ca08ab68Smrg	char szFPath[MAX_PATH + 1];
2005ca08ab68Smrg	size_t len;
2006ca08ab68Smrg
2007ca08ab68Smrg	if (!(pSHGetFolderPathA && SUCCEEDED(pSHGetFolderPathA(NULL, /* CSIDL_LOCAL_APPDATA */ 28, NULL, 0, szFPath))))
2008ca08ab68Smrg	{
2009ca08ab68Smrg	    FcConfigMessage (parse, FcSevereError, "SHGetFolderPathA failed");
2010ca08ab68Smrg	    goto bail;
2011ca08ab68Smrg	}
2012ca08ab68Smrg	strncat(szFPath, "\\fontconfig\\cache", MAX_PATH - 1 - strlen(szFPath));
2013ca08ab68Smrg	len = strlen(szFPath) + 1;
2014ca08ab68Smrg	FcStrFree (data);
2015ca08ab68Smrg	data = malloc(len);
2016ca08ab68Smrg	if (!data)
2017ca08ab68Smrg	{
2018ca08ab68Smrg	    FcConfigMessage (parse, FcSevereError, "out of memory");
2019ca08ab68Smrg	    goto bail;
2020ca08ab68Smrg	}
2021ca08ab68Smrg	FcMemAlloc (FC_MEM_STRING, len);
2022ca08ab68Smrg	strncpy((char *) data, szFPath, len);
2023ca08ab68Smrg    }
2024ca08ab68Smrg#endif
2025ca08ab68Smrg    if (strlen ((char *) data) == 0)
2026ca08ab68Smrg	FcConfigMessage (parse, FcSevereWarning, "empty cache directory name ignored");
2027ca08ab68Smrg    else if (!FcStrUsesHome (data) || FcConfigHome ())
2028ca08ab68Smrg    {
2029ca08ab68Smrg	if (!FcConfigAddCacheDir (parse->config, data))
2030ca08ab68Smrg	    FcConfigMessage (parse, FcSevereError, "out of memory; cannot add cache directory %s", data);
2031ca08ab68Smrg    }
2032ca08ab68Smrg    FcStrBufDestroy (&parse->pstack->str);
2033ca08ab68Smrg
2034ca08ab68Smrg  bail:
2035ca08ab68Smrg    if (data)
2036ca08ab68Smrg	FcStrFree (data);
2037ca08ab68Smrg}
2038ca08ab68Smrg
20392c393a42Smrgstatic void
20402c393a42SmrgFcParseInclude (FcConfigParse *parse)
20412c393a42Smrg{
20422c393a42Smrg    FcChar8	    *s;
2043ca08ab68Smrg    const FcChar8   *attr;
20442c393a42Smrg    FcBool	    ignore_missing = FcFalse;
2045ca08ab68Smrg    FcBool	    deprecated = FcFalse;
2046ca08ab68Smrg    FcChar8	    *prefix = NULL;
2047ca08ab68Smrg
2048a6844aabSmrg    s = FcStrBufDoneStatic (&parse->pstack->str);
20492c393a42Smrg    if (!s)
20502c393a42Smrg    {
20512c393a42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
2052ca08ab68Smrg	goto bail;
20532c393a42Smrg    }
2054ca08ab68Smrg    attr = FcConfigGetAttribute (parse, "ignore_missing");
2055ca08ab68Smrg    if (attr && FcConfigLexBool (parse, (FcChar8 *) attr) == FcTrue)
20562c393a42Smrg	ignore_missing = FcTrue;
2057ca08ab68Smrg    attr = FcConfigGetAttribute (parse, "deprecated");
2058ca08ab68Smrg    if (attr && FcConfigLexBool (parse, (FcChar8 *) attr) == FcTrue)
2059ca08ab68Smrg        deprecated = FcTrue;
2060ca08ab68Smrg    attr = FcConfigGetAttribute (parse, "prefix");
2061ca08ab68Smrg    if (attr && FcStrCmp (attr, (const FcChar8 *)"xdg") == 0)
2062ca08ab68Smrg	prefix = FcConfigXdgConfigHome ();
2063ca08ab68Smrg    if (prefix)
2064ca08ab68Smrg    {
2065ca08ab68Smrg	size_t plen = strlen ((const char *)prefix);
2066ca08ab68Smrg	size_t dlen = strlen ((const char *)s);
2067ca08ab68Smrg
2068ca08ab68Smrg	FcMemFree (FC_MEM_STRING, plen + 1);
2069ca08ab68Smrg	prefix = realloc (prefix, plen + 1 + dlen + 1);
2070ca08ab68Smrg	if (!prefix)
2071ca08ab68Smrg	{
2072ca08ab68Smrg	    FcConfigMessage (parse, FcSevereError, "out of memory");
2073ca08ab68Smrg	    goto bail;
2074ca08ab68Smrg	}
2075ca08ab68Smrg	FcMemAlloc (FC_MEM_STRING, plen + 1 + dlen + 1);
2076ca08ab68Smrg	prefix[plen] = FC_DIR_SEPARATOR;
2077ca08ab68Smrg	memcpy (&prefix[plen + 1], s, dlen);
2078ca08ab68Smrg	prefix[plen + 1 + dlen] = 0;
2079ca08ab68Smrg	s = prefix;
2080ca08ab68Smrg    }
20812c393a42Smrg    if (!FcConfigParseAndLoad (parse->config, s, !ignore_missing))
20822c393a42Smrg	parse->error = FcTrue;
2083ca08ab68Smrg    else
2084ca08ab68Smrg    {
2085ca08ab68Smrg        FcChar8 *filename;
2086ca08ab68Smrg
2087ca08ab68Smrg        filename = FcConfigFilename(s);
2088ca08ab68Smrg        if ((deprecated == FcTrue) && filename)
2089ca08ab68Smrg        {
2090ca08ab68Smrg            FcConfigMessage (parse, FcSevereWarning, "reading configurations from %s is deprecated.", s);
2091ca08ab68Smrg        }
2092ca08ab68Smrg        if(filename)
2093ca08ab68Smrg            FcStrFree(filename);
2094ca08ab68Smrg    }
2095a6844aabSmrg    FcStrBufDestroy (&parse->pstack->str);
2096ca08ab68Smrg
2097ca08ab68Smrg  bail:
2098ca08ab68Smrg    if (prefix)
2099ca08ab68Smrg	FcStrFree (prefix);
21002c393a42Smrg}
21012c393a42Smrg
21022c393a42Smrgtypedef struct _FcOpMap {
21032c393a42Smrg    char    name[16];
21042c393a42Smrg    FcOp    op;
21052c393a42Smrg} FcOpMap;
21062c393a42Smrg
21072c393a42Smrgstatic FcOp
21082c393a42SmrgFcConfigLexOp (const FcChar8 *op, const FcOpMap	*map, int nmap)
21092c393a42Smrg{
21102c393a42Smrg    int	i;
21112c393a42Smrg
21122c393a42Smrg    for (i = 0; i < nmap; i++)
2113ca08ab68Smrg	if (!strcmp ((char *) op, map[i].name))
21142c393a42Smrg	    return map[i].op;
21152c393a42Smrg    return FcOpInvalid;
21162c393a42Smrg}
21172c393a42Smrg
21182c393a42Smrgstatic const FcOpMap fcCompareOps[] = {
21192c393a42Smrg    { "eq",		FcOpEqual	    },
21202c393a42Smrg    { "not_eq",		FcOpNotEqual	    },
21212c393a42Smrg    { "less",		FcOpLess	    },
21222c393a42Smrg    { "less_eq",	FcOpLessEqual	    },
21232c393a42Smrg    { "more",		FcOpMore	    },
21242c393a42Smrg    { "more_eq",	FcOpMoreEqual	    },
21252c393a42Smrg    { "contains",	FcOpContains	    },
21262c393a42Smrg    { "not_contains",	FcOpNotContains	    }
21272c393a42Smrg};
21282c393a42Smrg
21292c393a42Smrg#define NUM_COMPARE_OPS	(int) (sizeof fcCompareOps / sizeof fcCompareOps[0])
21302c393a42Smrg
21312c393a42Smrgstatic FcOp
21322c393a42SmrgFcConfigLexCompare (const FcChar8 *compare)
21332c393a42Smrg{
21342c393a42Smrg    return FcConfigLexOp (compare, fcCompareOps, NUM_COMPARE_OPS);
21352c393a42Smrg}
21362c393a42Smrg
21372c393a42Smrgstatic void
21382c393a42SmrgFcParseTest (FcConfigParse *parse)
21392c393a42Smrg{
21402c393a42Smrg    const FcChar8   *kind_string;
21412c393a42Smrg    FcMatchKind	    kind;
21422c393a42Smrg    const FcChar8   *qual_string;
21432c393a42Smrg    FcQual	    qual;
21442c393a42Smrg    const FcChar8   *name;
21452c393a42Smrg    const FcChar8   *compare_string;
21462c393a42Smrg    FcOp	    compare;
21472c393a42Smrg    FcExpr	    *expr;
21482c393a42Smrg    FcTest	    *test;
2149ca08ab68Smrg    const FcChar8   *iblanks_string;
2150ca08ab68Smrg    int              flags = 0;
21512c393a42Smrg
21522c393a42Smrg    kind_string = FcConfigGetAttribute (parse, "target");
21532c393a42Smrg    if (!kind_string)
21542c393a42Smrg	kind = FcMatchDefault;
21552c393a42Smrg    else
21562c393a42Smrg    {
21572c393a42Smrg	if (!strcmp ((char *) kind_string, "pattern"))
21582c393a42Smrg	    kind = FcMatchPattern;
21592c393a42Smrg	else if (!strcmp ((char *) kind_string, "font"))
21602c393a42Smrg	    kind = FcMatchFont;
21612c393a42Smrg	else if (!strcmp ((char *) kind_string, "scan"))
21622c393a42Smrg	    kind = FcMatchScan;
21632c393a42Smrg	else if (!strcmp ((char *) kind_string, "default"))
21642c393a42Smrg	    kind = FcMatchDefault;
21652c393a42Smrg	else
21662c393a42Smrg	{
21672c393a42Smrg	    FcConfigMessage (parse, FcSevereWarning, "invalid test target \"%s\"", kind_string);
21682c393a42Smrg	    return;
21692c393a42Smrg	}
21702c393a42Smrg    }
21712c393a42Smrg    qual_string = FcConfigGetAttribute (parse, "qual");
21722c393a42Smrg    if (!qual_string)
21732c393a42Smrg	qual = FcQualAny;
21742c393a42Smrg    else
21752c393a42Smrg    {
21762c393a42Smrg	if (!strcmp ((char *) qual_string, "any"))
21772c393a42Smrg	    qual = FcQualAny;
21782c393a42Smrg	else if (!strcmp ((char *) qual_string, "all"))
21792c393a42Smrg	    qual = FcQualAll;
21802c393a42Smrg	else if (!strcmp ((char *) qual_string, "first"))
21812c393a42Smrg	    qual = FcQualFirst;
21822c393a42Smrg	else if (!strcmp ((char *) qual_string, "not_first"))
21832c393a42Smrg	    qual = FcQualNotFirst;
21842c393a42Smrg	else
21852c393a42Smrg	{
21862c393a42Smrg	    FcConfigMessage (parse, FcSevereWarning, "invalid test qual \"%s\"", qual_string);
21872c393a42Smrg	    return;
21882c393a42Smrg	}
21892c393a42Smrg    }
21902c393a42Smrg    name = FcConfigGetAttribute (parse, "name");
21912c393a42Smrg    if (!name)
21922c393a42Smrg    {
21932c393a42Smrg	FcConfigMessage (parse, FcSevereWarning, "missing test name");
21942c393a42Smrg	return;
21952c393a42Smrg    }
21962c393a42Smrg    compare_string = FcConfigGetAttribute (parse, "compare");
21972c393a42Smrg    if (!compare_string)
21982c393a42Smrg	compare = FcOpEqual;
21992c393a42Smrg    else
22002c393a42Smrg    {
22012c393a42Smrg	compare = FcConfigLexCompare (compare_string);
22022c393a42Smrg	if (compare == FcOpInvalid)
22032c393a42Smrg	{
22042c393a42Smrg	    FcConfigMessage (parse, FcSevereWarning, "invalid test compare \"%s\"", compare_string);
22052c393a42Smrg	    return;
22062c393a42Smrg	}
22072c393a42Smrg    }
2208ca08ab68Smrg    iblanks_string = FcConfigGetAttribute (parse, "ignore-blanks");
2209ca08ab68Smrg    if (iblanks_string)
2210ca08ab68Smrg    {
2211ca08ab68Smrg	FcBool f = FcFalse;
2212ca08ab68Smrg
2213ca08ab68Smrg	if (!FcNameBool (iblanks_string, &f))
2214ca08ab68Smrg	{
2215ca08ab68Smrg	    FcConfigMessage (parse,
2216ca08ab68Smrg			     FcSevereWarning,
2217ca08ab68Smrg			     "invalid test ignore-blanks \"%s\"", iblanks_string);
2218ca08ab68Smrg	}
2219ca08ab68Smrg	if (f)
2220ca08ab68Smrg	    flags |= FcOpFlagIgnoreBlanks;
2221ca08ab68Smrg    }
22222c393a42Smrg    expr = FcPopBinary (parse, FcOpComma);
22232c393a42Smrg    if (!expr)
22242c393a42Smrg    {
22252c393a42Smrg	FcConfigMessage (parse, FcSevereWarning, "missing test expression");
22262c393a42Smrg	return;
22272c393a42Smrg    }
2228ca08ab68Smrg    if (expr->op == FcOpComma)
2229ca08ab68Smrg    {
2230ca08ab68Smrg	FcConfigMessage (parse, FcSevereWarning, "Having multiple values in <test> isn't supported and may not work as expected");
2231ca08ab68Smrg    }
2232ca08ab68Smrg    test = FcTestCreate (parse, kind, qual, name, FC_OP (compare, flags), expr);
22332c393a42Smrg    if (!test)
22342c393a42Smrg    {
22352c393a42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
22362c393a42Smrg	return;
22372c393a42Smrg    }
22382c393a42Smrg    FcVStackPushTest (parse, test);
22392c393a42Smrg}
22402c393a42Smrg
22412c393a42Smrgstatic const FcOpMap fcModeOps[] = {
22422c393a42Smrg    { "assign",		FcOpAssign	    },
22432c393a42Smrg    { "assign_replace",	FcOpAssignReplace   },
22442c393a42Smrg    { "prepend",	FcOpPrepend	    },
22452c393a42Smrg    { "prepend_first",	FcOpPrependFirst    },
22462c393a42Smrg    { "append",		FcOpAppend	    },
22472c393a42Smrg    { "append_last",	FcOpAppendLast	    },
22482c393a42Smrg};
22492c393a42Smrg
22502c393a42Smrg#define NUM_MODE_OPS (int) (sizeof fcModeOps / sizeof fcModeOps[0])
22512c393a42Smrg
22522c393a42Smrgstatic FcOp
22532c393a42SmrgFcConfigLexMode (const FcChar8 *mode)
22542c393a42Smrg{
22552c393a42Smrg    return FcConfigLexOp (mode, fcModeOps, NUM_MODE_OPS);
22562c393a42Smrg}
22572c393a42Smrg
22582c393a42Smrgstatic void
22592c393a42SmrgFcParseEdit (FcConfigParse *parse)
22602c393a42Smrg{
22612c393a42Smrg    const FcChar8   *name;
22622c393a42Smrg    const FcChar8   *mode_string;
22632c393a42Smrg    FcOp	    mode;
22642c393a42Smrg    FcValueBinding  binding;
22652c393a42Smrg    FcExpr	    *expr;
22662c393a42Smrg    FcEdit	    *edit;
22672c393a42Smrg
22682c393a42Smrg    name = FcConfigGetAttribute (parse, "name");
22692c393a42Smrg    if (!name)
22702c393a42Smrg    {
22712c393a42Smrg	FcConfigMessage (parse, FcSevereWarning, "missing edit name");
22722c393a42Smrg	return;
22732c393a42Smrg    }
22742c393a42Smrg    mode_string = FcConfigGetAttribute (parse, "mode");
22752c393a42Smrg    if (!mode_string)
22762c393a42Smrg	mode = FcOpAssign;
22772c393a42Smrg    else
22782c393a42Smrg    {
22792c393a42Smrg	mode = FcConfigLexMode (mode_string);
22802c393a42Smrg	if (mode == FcOpInvalid)
22812c393a42Smrg	{
22822c393a42Smrg	    FcConfigMessage (parse, FcSevereWarning, "invalid edit mode \"%s\"", mode_string);
22832c393a42Smrg	    return;
22842c393a42Smrg	}
22852c393a42Smrg    }
22862c393a42Smrg    if (!FcConfigLexBinding (parse, FcConfigGetAttribute (parse, "binding"), &binding))
22872c393a42Smrg	return;
22882c393a42Smrg
22892c393a42Smrg    expr = FcPopBinary (parse, FcOpComma);
22902c393a42Smrg    edit = FcEditCreate (parse, FcObjectFromName ((char *) name),
22912c393a42Smrg			 mode, expr, binding);
22922c393a42Smrg    if (!edit)
22932c393a42Smrg    {
22942c393a42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
22952c393a42Smrg	FcExprDestroy (expr);
22962c393a42Smrg	return;
22972c393a42Smrg    }
22982c393a42Smrg    if (!FcVStackPushEdit (parse, edit))
22992c393a42Smrg	FcEditDestroy (edit);
23002c393a42Smrg}
23012c393a42Smrg
23022c393a42Smrgstatic void
23032c393a42SmrgFcParseMatch (FcConfigParse *parse)
23042c393a42Smrg{
23052c393a42Smrg    const FcChar8   *kind_name;
23062c393a42Smrg    FcMatchKind	    kind;
23072c393a42Smrg    FcTest	    *test = 0;
23082c393a42Smrg    FcEdit	    *edit = 0;
23092c393a42Smrg    FcVStack	    *vstack;
23102c393a42Smrg
23112c393a42Smrg    kind_name = FcConfigGetAttribute (parse, "target");
23122c393a42Smrg    if (!kind_name)
23132c393a42Smrg	kind = FcMatchPattern;
23142c393a42Smrg    else
23152c393a42Smrg    {
23162c393a42Smrg	if (!strcmp ((char *) kind_name, "pattern"))
23172c393a42Smrg	    kind = FcMatchPattern;
23182c393a42Smrg	else if (!strcmp ((char *) kind_name, "font"))
23192c393a42Smrg	    kind = FcMatchFont;
23202c393a42Smrg	else if (!strcmp ((char *) kind_name, "scan"))
23212c393a42Smrg	    kind = FcMatchScan;
23222c393a42Smrg	else
23232c393a42Smrg	{
23242c393a42Smrg	    FcConfigMessage (parse, FcSevereWarning, "invalid match target \"%s\"", kind_name);
23252c393a42Smrg	    return;
23262c393a42Smrg	}
23272c393a42Smrg    }
2328a6844aabSmrg    while ((vstack = FcVStackPeek (parse)))
23292c393a42Smrg    {
23302c393a42Smrg	switch (vstack->tag) {
23312c393a42Smrg	case FcVStackTest:
23322c393a42Smrg	    vstack->u.test->next = test;
23332c393a42Smrg	    test = vstack->u.test;
23342c393a42Smrg	    vstack->tag = FcVStackNone;
23352c393a42Smrg	    break;
23362c393a42Smrg	case FcVStackEdit:
23372c393a42Smrg	    vstack->u.edit->next = edit;
23382c393a42Smrg	    edit = vstack->u.edit;
23392c393a42Smrg	    vstack->tag = FcVStackNone;
23402c393a42Smrg	    if (kind == FcMatchScan && edit->object > FC_MAX_BASE_OBJECT)
23412c393a42Smrg	    {
2342ca08ab68Smrg		FcConfigMessage (parse, FcSevereError,
23432c393a42Smrg				 "<match target=\"scan\"> cannot edit user-defined object \"%s\"",
23442c393a42Smrg				 FcObjectName(edit->object));
23452c393a42Smrg	    }
23462c393a42Smrg	    break;
23472c393a42Smrg	default:
23482c393a42Smrg	    FcConfigMessage (parse, FcSevereWarning, "invalid match element");
23492c393a42Smrg	    break;
23502c393a42Smrg	}
2351a6844aabSmrg	FcVStackPopAndDestroy (parse);
23522c393a42Smrg    }
23532c393a42Smrg    if (!FcConfigAddEdit (parse->config, test, edit, kind))
23542c393a42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
23552c393a42Smrg}
23562c393a42Smrg
23572c393a42Smrgstatic void
23582c393a42SmrgFcParseAcceptRejectFont (FcConfigParse *parse, FcElement element)
23592c393a42Smrg{
23602c393a42Smrg    FcVStack	*vstack;
23612c393a42Smrg
2362a6844aabSmrg    while ((vstack = FcVStackPeek (parse)))
23632c393a42Smrg    {
23642c393a42Smrg	switch (vstack->tag) {
23652c393a42Smrg	case FcVStackGlob:
2366ca08ab68Smrg	    if (!FcConfigGlobAdd (parse->config,
23672c393a42Smrg				  vstack->u.string,
23682c393a42Smrg				  element == FcElementAcceptfont))
23692c393a42Smrg	    {
23702c393a42Smrg		FcConfigMessage (parse, FcSevereError, "out of memory");
23712c393a42Smrg	    }
23722c393a42Smrg	    break;
23732c393a42Smrg	case FcVStackPattern:
23742c393a42Smrg	    if (!FcConfigPatternsAdd (parse->config,
23752c393a42Smrg				      vstack->u.pattern,
23762c393a42Smrg				      element == FcElementAcceptfont))
23772c393a42Smrg	    {
23782c393a42Smrg		FcConfigMessage (parse, FcSevereError, "out of memory");
23792c393a42Smrg	    }
23802c393a42Smrg	    else
23812c393a42Smrg		vstack->tag = FcVStackNone;
23822c393a42Smrg	    break;
23832c393a42Smrg	default:
23842c393a42Smrg	    FcConfigMessage (parse, FcSevereWarning, "bad font selector");
23852c393a42Smrg	    break;
23862c393a42Smrg	}
2387a6844aabSmrg	FcVStackPopAndDestroy (parse);
23882c393a42Smrg    }
23892c393a42Smrg}
23902c393a42Smrg
23912c393a42Smrg
23922c393a42Smrgstatic FcValue
23932c393a42SmrgFcPopValue (FcConfigParse *parse)
23942c393a42Smrg{
2395a6844aabSmrg    FcVStack	*vstack = FcVStackPeek (parse);
23962c393a42Smrg    FcValue	value;
2397ca08ab68Smrg
23982c393a42Smrg    value.type = FcTypeVoid;
2399ca08ab68Smrg
24002c393a42Smrg    if (!vstack)
24012c393a42Smrg	return value;
2402ca08ab68Smrg
24032c393a42Smrg    switch (vstack->tag) {
24042c393a42Smrg    case FcVStackString:
2405ca08ab68Smrg	value.u.s = FcSharedStr (vstack->u.string);
24062c393a42Smrg	if (value.u.s)
24072c393a42Smrg	    value.type = FcTypeString;
24082c393a42Smrg	break;
24092c393a42Smrg    case FcVStackConstant:
24102c393a42Smrg	if (FcNameConstant (vstack->u.string, &value.u.i))
24112c393a42Smrg	    value.type = FcTypeInteger;
24122c393a42Smrg	break;
24132c393a42Smrg    case FcVStackInteger:
24142c393a42Smrg	value.u.i = vstack->u.integer;
24152c393a42Smrg	value.type = FcTypeInteger;
24162c393a42Smrg	break;
24172c393a42Smrg    case FcVStackDouble:
24182c393a42Smrg	value.u.d = vstack->u._double;
24192c393a42Smrg	value.type = FcTypeInteger;
24202c393a42Smrg	break;
24212c393a42Smrg    case FcVStackMatrix:
24222c393a42Smrg	value.u.m = FcMatrixCopy (vstack->u.matrix);
24232c393a42Smrg	if (value.u.m)
24242c393a42Smrg	    value.type = FcTypeMatrix;
24252c393a42Smrg	break;
24262c393a42Smrg    case FcVStackBool:
2427a6844aabSmrg	value.u.b = vstack->u.bool_;
24282c393a42Smrg	value.type = FcTypeBool;
24292c393a42Smrg	break;
2430ca08ab68Smrg    case FcVStackCharSet:
2431ca08ab68Smrg	value.u.c = FcCharSetCopy (vstack->u.charset);
2432ca08ab68Smrg	if (value.u.c)
2433ca08ab68Smrg	    value.type = FcTypeCharSet;
2434ca08ab68Smrg	break;
2435ca08ab68Smrg    case FcVStackLangSet:
2436ca08ab68Smrg	value.u.l = FcLangSetCopy (vstack->u.langset);
2437ca08ab68Smrg	if (value.u.l)
2438ca08ab68Smrg	    value.type = FcTypeLangSet;
2439ca08ab68Smrg	break;
24402c393a42Smrg    default:
2441ca08ab68Smrg	FcConfigMessage (parse, FcSevereWarning, "unknown pattern element %d",
24422c393a42Smrg			 vstack->tag);
24432c393a42Smrg	break;
24442c393a42Smrg    }
2445a6844aabSmrg    FcVStackPopAndDestroy (parse);
2446ca08ab68Smrg
24472c393a42Smrg    return value;
24482c393a42Smrg}
24492c393a42Smrg
24502c393a42Smrgstatic void
24512c393a42SmrgFcParsePatelt (FcConfigParse *parse)
24522c393a42Smrg{
24532c393a42Smrg    FcValue	value;
24542c393a42Smrg    FcPattern	*pattern = FcPatternCreate ();
24552c393a42Smrg    const char	*name;
24562c393a42Smrg
24572c393a42Smrg    if (!pattern)
24582c393a42Smrg    {
24592c393a42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
24602c393a42Smrg	return;
24612c393a42Smrg    }
24622c393a42Smrg
24632c393a42Smrg    name = (char *) FcConfigGetAttribute (parse, "name");
24642c393a42Smrg    if (!name)
24652c393a42Smrg    {
24662c393a42Smrg	FcConfigMessage (parse, FcSevereWarning, "missing pattern element name");
24672c393a42Smrg	FcPatternDestroy (pattern);
24682c393a42Smrg	return;
24692c393a42Smrg    }
2470ca08ab68Smrg
24712c393a42Smrg    for (;;)
24722c393a42Smrg    {
24732c393a42Smrg	value = FcPopValue (parse);
24742c393a42Smrg	if (value.type == FcTypeVoid)
24752c393a42Smrg	    break;
24762c393a42Smrg	if (!FcPatternAdd (pattern, name, value, FcTrue))
24772c393a42Smrg	{
24782c393a42Smrg	    FcConfigMessage (parse, FcSevereError, "out of memory");
2479a6844aabSmrg            FcValueDestroy(value);
24802c393a42Smrg	    break;
24812c393a42Smrg	}
2482a6844aabSmrg        FcValueDestroy(value);
24832c393a42Smrg    }
24842c393a42Smrg
24852c393a42Smrg    FcVStackPushPattern (parse, pattern);
24862c393a42Smrg}
24872c393a42Smrg
24882c393a42Smrgstatic void
24892c393a42SmrgFcParsePattern (FcConfigParse *parse)
24902c393a42Smrg{
24912c393a42Smrg    FcVStack	*vstack;
24922c393a42Smrg    FcPattern	*pattern = FcPatternCreate ();
24932c393a42Smrg
24942c393a42Smrg    if (!pattern)
24952c393a42Smrg    {
24962c393a42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
24972c393a42Smrg	return;
24982c393a42Smrg    }
24992c393a42Smrg
2500a6844aabSmrg    while ((vstack = FcVStackPeek (parse)))
25012c393a42Smrg    {
25022c393a42Smrg	switch (vstack->tag) {
25032c393a42Smrg	case FcVStackPattern:
25042c393a42Smrg	    if (!FcPatternAppend (pattern, vstack->u.pattern))
25052c393a42Smrg	    {
25062c393a42Smrg		FcConfigMessage (parse, FcSevereError, "out of memory");
25072c393a42Smrg		FcPatternDestroy (pattern);
25082c393a42Smrg		return;
25092c393a42Smrg	    }
25102c393a42Smrg	    break;
25112c393a42Smrg	default:
25122c393a42Smrg	    FcConfigMessage (parse, FcSevereWarning, "unknown pattern element");
25132c393a42Smrg	    break;
25142c393a42Smrg	}
2515a6844aabSmrg	FcVStackPopAndDestroy (parse);
25162c393a42Smrg    }
25172c393a42Smrg
25182c393a42Smrg    FcVStackPushPattern (parse, pattern);
25192c393a42Smrg}
25202c393a42Smrg
25212c393a42Smrgstatic void
25222c393a42SmrgFcEndElement(void *userData, const XML_Char *name)
25232c393a42Smrg{
25242c393a42Smrg    FcConfigParse   *parse = userData;
25252c393a42Smrg    FcChar8	    *data;
2526a6844aabSmrg
25272c393a42Smrg    if (!parse->pstack)
25282c393a42Smrg	return;
25292c393a42Smrg    switch (parse->pstack->element) {
25302c393a42Smrg    case FcElementNone:
25312c393a42Smrg	break;
25322c393a42Smrg    case FcElementFontconfig:
25332c393a42Smrg	break;
25342c393a42Smrg    case FcElementDir:
2535ca08ab68Smrg	FcParseDir (parse);
25362c393a42Smrg	break;
25372c393a42Smrg    case FcElementCacheDir:
2538ca08ab68Smrg	FcParseCacheDir (parse);
25392c393a42Smrg	break;
25402c393a42Smrg    case FcElementCache:
2541a6844aabSmrg	data = FcStrBufDoneStatic (&parse->pstack->str);
25422c393a42Smrg	if (!data)
25432c393a42Smrg	{
25442c393a42Smrg	    FcConfigMessage (parse, FcSevereError, "out of memory");
25452c393a42Smrg	    break;
25462c393a42Smrg	}
25472c393a42Smrg	/* discard this data; no longer used */
2548a6844aabSmrg	FcStrBufDestroy (&parse->pstack->str);
25492c393a42Smrg	break;
25502c393a42Smrg    case FcElementInclude:
25512c393a42Smrg	FcParseInclude (parse);
25522c393a42Smrg	break;
25532c393a42Smrg    case FcElementConfig:
25542c393a42Smrg	break;
25552c393a42Smrg    case FcElementMatch:
25562c393a42Smrg	FcParseMatch (parse);
25572c393a42Smrg	break;
25582c393a42Smrg    case FcElementAlias:
25592c393a42Smrg	FcParseAlias (parse);
25602c393a42Smrg	break;
25612c393a42Smrg
25622c393a42Smrg    case FcElementBlank:
25632c393a42Smrg	FcParseBlank (parse);
25642c393a42Smrg	break;
25652c393a42Smrg    case FcElementRescan:
25662c393a42Smrg	FcParseRescan (parse);
25672c393a42Smrg	break;
25682c393a42Smrg
25692c393a42Smrg    case FcElementPrefer:
25702c393a42Smrg	FcParseFamilies (parse, FcVStackPrefer);
25712c393a42Smrg	break;
25722c393a42Smrg    case FcElementAccept:
25732c393a42Smrg	FcParseFamilies (parse, FcVStackAccept);
25742c393a42Smrg	break;
25752c393a42Smrg    case FcElementDefault:
25762c393a42Smrg	FcParseFamilies (parse, FcVStackDefault);
25772c393a42Smrg	break;
25782c393a42Smrg    case FcElementFamily:
25792c393a42Smrg	FcParseFamily (parse);
25802c393a42Smrg	break;
25812c393a42Smrg
25822c393a42Smrg    case FcElementTest:
25832c393a42Smrg	FcParseTest (parse);
25842c393a42Smrg	break;
25852c393a42Smrg    case FcElementEdit:
25862c393a42Smrg	FcParseEdit (parse);
25872c393a42Smrg	break;
25882c393a42Smrg
25892c393a42Smrg    case FcElementInt:
25902c393a42Smrg	FcParseInt (parse);
25912c393a42Smrg	break;
25922c393a42Smrg    case FcElementDouble:
25932c393a42Smrg	FcParseDouble (parse);
25942c393a42Smrg	break;
25952c393a42Smrg    case FcElementString:
25962c393a42Smrg	FcParseString (parse, FcVStackString);
25972c393a42Smrg	break;
25982c393a42Smrg    case FcElementMatrix:
25992c393a42Smrg	FcParseMatrix (parse);
26002c393a42Smrg	break;
2601ca08ab68Smrg    case FcElementRange:
2602ca08ab68Smrg	FcParseRange (parse);
2603ca08ab68Smrg	break;
26042c393a42Smrg    case FcElementBool:
26052c393a42Smrg	FcParseBool (parse);
26062c393a42Smrg	break;
2607ca08ab68Smrg    case FcElementCharSet:
2608ca08ab68Smrg	FcParseCharSet (parse);
2609ca08ab68Smrg	break;
2610ca08ab68Smrg    case FcElementLangSet:
2611ca08ab68Smrg	FcParseLangSet (parse);
26122c393a42Smrg	break;
26132c393a42Smrg    case FcElementSelectfont:
26142c393a42Smrg	break;
26152c393a42Smrg    case FcElementAcceptfont:
26162c393a42Smrg    case FcElementRejectfont:
26172c393a42Smrg	FcParseAcceptRejectFont (parse, parse->pstack->element);
26182c393a42Smrg	break;
26192c393a42Smrg    case FcElementGlob:
26202c393a42Smrg	FcParseString (parse, FcVStackGlob);
26212c393a42Smrg	break;
26222c393a42Smrg    case FcElementPattern:
26232c393a42Smrg	FcParsePattern (parse);
26242c393a42Smrg	break;
26252c393a42Smrg    case FcElementPatelt:
26262c393a42Smrg	FcParsePatelt (parse);
26272c393a42Smrg	break;
26282c393a42Smrg    case FcElementName:
26292c393a42Smrg	FcParseString (parse, FcVStackField);
26302c393a42Smrg	break;
26312c393a42Smrg    case FcElementConst:
26322c393a42Smrg	FcParseString (parse, FcVStackConstant);
26332c393a42Smrg	break;
26342c393a42Smrg    case FcElementOr:
26352c393a42Smrg	FcParseBinary (parse, FcOpOr);
26362c393a42Smrg	break;
26372c393a42Smrg    case FcElementAnd:
26382c393a42Smrg	FcParseBinary (parse, FcOpAnd);
26392c393a42Smrg	break;
26402c393a42Smrg    case FcElementEq:
26412c393a42Smrg	FcParseBinary (parse, FcOpEqual);
26422c393a42Smrg	break;
26432c393a42Smrg    case FcElementNotEq:
26442c393a42Smrg	FcParseBinary (parse, FcOpNotEqual);
26452c393a42Smrg	break;
26462c393a42Smrg    case FcElementLess:
26472c393a42Smrg	FcParseBinary (parse, FcOpLess);
26482c393a42Smrg	break;
26492c393a42Smrg    case FcElementLessEq:
26502c393a42Smrg	FcParseBinary (parse, FcOpLessEqual);
26512c393a42Smrg	break;
26522c393a42Smrg    case FcElementMore:
26532c393a42Smrg	FcParseBinary (parse, FcOpMore);
26542c393a42Smrg	break;
26552c393a42Smrg    case FcElementMoreEq:
26562c393a42Smrg	FcParseBinary (parse, FcOpMoreEqual);
26572c393a42Smrg	break;
26582c393a42Smrg    case FcElementContains:
26592c393a42Smrg	FcParseBinary (parse, FcOpContains);
26602c393a42Smrg	break;
26612c393a42Smrg    case FcElementNotContains:
26622c393a42Smrg	FcParseBinary (parse, FcOpNotContains);
26632c393a42Smrg	break;
26642c393a42Smrg    case FcElementPlus:
26652c393a42Smrg	FcParseBinary (parse, FcOpPlus);
26662c393a42Smrg	break;
26672c393a42Smrg    case FcElementMinus:
26682c393a42Smrg	FcParseBinary (parse, FcOpMinus);
26692c393a42Smrg	break;
26702c393a42Smrg    case FcElementTimes:
26712c393a42Smrg	FcParseBinary (parse, FcOpTimes);
26722c393a42Smrg	break;
26732c393a42Smrg    case FcElementDivide:
26742c393a42Smrg	FcParseBinary (parse, FcOpDivide);
26752c393a42Smrg	break;
26762c393a42Smrg    case FcElementNot:
26772c393a42Smrg	FcParseUnary (parse, FcOpNot);
26782c393a42Smrg	break;
26792c393a42Smrg    case FcElementIf:
26802c393a42Smrg	FcParseBinary (parse, FcOpQuest);
26812c393a42Smrg	break;
26822c393a42Smrg    case FcElementFloor:
26832c393a42Smrg	FcParseUnary (parse, FcOpFloor);
26842c393a42Smrg	break;
26852c393a42Smrg    case FcElementCeil:
26862c393a42Smrg	FcParseUnary (parse, FcOpCeil);
26872c393a42Smrg	break;
26882c393a42Smrg    case FcElementRound:
26892c393a42Smrg	FcParseUnary (parse, FcOpRound);
26902c393a42Smrg	break;
26912c393a42Smrg    case FcElementTrunc:
26922c393a42Smrg	FcParseUnary (parse, FcOpTrunc);
26932c393a42Smrg	break;
26942c393a42Smrg    case FcElementUnknown:
26952c393a42Smrg	break;
26962c393a42Smrg    }
26972c393a42Smrg    (void) FcPStackPop (parse);
26982c393a42Smrg}
26992c393a42Smrg
27002c393a42Smrgstatic void
27012c393a42SmrgFcCharacterData (void *userData, const XML_Char *s, int len)
27022c393a42Smrg{
27032c393a42Smrg    FcConfigParse   *parse = userData;
2704ca08ab68Smrg
27052c393a42Smrg    if (!parse->pstack)
27062c393a42Smrg	return;
27072c393a42Smrg    if (!FcStrBufData (&parse->pstack->str, (FcChar8 *) s, len))
27082c393a42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
27092c393a42Smrg}
27102c393a42Smrg
27112c393a42Smrgstatic void
27122c393a42SmrgFcStartDoctypeDecl (void	    *userData,
27132c393a42Smrg		    const XML_Char  *doctypeName,
27142c393a42Smrg		    const XML_Char  *sysid,
27152c393a42Smrg		    const XML_Char  *pubid,
27162c393a42Smrg		    int		    has_internal_subset)
27172c393a42Smrg{
27182c393a42Smrg    FcConfigParse   *parse = userData;
27192c393a42Smrg
27202c393a42Smrg    if (strcmp ((char *) doctypeName, "fontconfig") != 0)
27212c393a42Smrg	FcConfigMessage (parse, FcSevereError, "invalid doctype \"%s\"", doctypeName);
27222c393a42Smrg}
27232c393a42Smrg
27242c393a42Smrg#ifdef ENABLE_LIBXML2
27252c393a42Smrg
27262c393a42Smrgstatic void
27272c393a42SmrgFcInternalSubsetDecl (void            *userData,
27282c393a42Smrg		      const XML_Char  *doctypeName,
27292c393a42Smrg		      const XML_Char  *sysid,
27302c393a42Smrg		      const XML_Char  *pubid)
27312c393a42Smrg{
27322c393a42Smrg    FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 1);
27332c393a42Smrg}
27342c393a42Smrg
27352c393a42Smrgstatic void
27362c393a42SmrgFcExternalSubsetDecl (void            *userData,
27372c393a42Smrg		      const XML_Char  *doctypeName,
27382c393a42Smrg		      const XML_Char  *sysid,
27392c393a42Smrg		      const XML_Char  *pubid)
27402c393a42Smrg{
27412c393a42Smrg    FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 0);
27422c393a42Smrg}
27432c393a42Smrg
27442c393a42Smrg#else /* ENABLE_LIBXML2 */
27452c393a42Smrg
27462c393a42Smrgstatic void
27472c393a42SmrgFcEndDoctypeDecl (void *userData)
27482c393a42Smrg{
27492c393a42Smrg}
27502c393a42Smrg
27512c393a42Smrg#endif /* ENABLE_LIBXML2 */
27522c393a42Smrg
27532c393a42Smrgstatic int
27542c393a42SmrgFcSortCmpStr (const void *a, const void *b)
27552c393a42Smrg{
27562c393a42Smrg    const FcChar8    *as = *((FcChar8 **) a);
27572c393a42Smrg    const FcChar8    *bs = *((FcChar8 **) b);
27582c393a42Smrg    return FcStrCmp (as, bs);
27592c393a42Smrg}
27602c393a42Smrg
27612c393a42Smrgstatic FcBool
27622c393a42SmrgFcConfigParseAndLoadDir (FcConfig	*config,
27632c393a42Smrg			 const FcChar8	*name,
27642c393a42Smrg			 const FcChar8	*dir,
27652c393a42Smrg			 FcBool		complain)
27662c393a42Smrg{
27672c393a42Smrg    DIR		    *d;
27682c393a42Smrg    struct dirent   *e;
27692c393a42Smrg    FcBool	    ret = FcTrue;
27702c393a42Smrg    FcChar8	    *file;
27712c393a42Smrg    FcChar8	    *base;
27722c393a42Smrg    FcStrSet	    *files;
27732c393a42Smrg
27742c393a42Smrg    d = opendir ((char *) dir);
27752c393a42Smrg    if (!d)
27762c393a42Smrg    {
27772c393a42Smrg	if (complain)
27782c393a42Smrg	    FcConfigMessage (0, FcSevereError, "Cannot open config dir \"%s\"",
27792c393a42Smrg			     name);
27802c393a42Smrg	ret = FcFalse;
27812c393a42Smrg	goto bail0;
27822c393a42Smrg    }
27832c393a42Smrg    /* freed below */
27842c393a42Smrg    file = (FcChar8 *) malloc (strlen ((char *) dir) + 1 + FC_MAX_FILE_LEN + 1);
27852c393a42Smrg    if (!file)
27862c393a42Smrg    {
27872c393a42Smrg	ret = FcFalse;
27882c393a42Smrg	goto bail1;
27892c393a42Smrg    }
2790ca08ab68Smrg
27912c393a42Smrg    strcpy ((char *) file, (char *) dir);
27922c393a42Smrg    strcat ((char *) file, "/");
27932c393a42Smrg    base = file + strlen ((char *) file);
2794ca08ab68Smrg
27952c393a42Smrg    files = FcStrSetCreate ();
27962c393a42Smrg    if (!files)
27972c393a42Smrg    {
27982c393a42Smrg	ret = FcFalse;
27992c393a42Smrg	goto bail2;
28002c393a42Smrg    }
2801ca08ab68Smrg
28022c393a42Smrg    if (FcDebug () & FC_DBG_CONFIG)
28032c393a42Smrg	printf ("\tScanning config dir %s\n", dir);
28042c393a42Smrg
28052c393a42Smrg    while (ret && (e = readdir (d)))
28062c393a42Smrg    {
28072c393a42Smrg	int d_len;
28082c393a42Smrg#define TAIL	    ".conf"
28092c393a42Smrg#define TAIL_LEN    5
28102c393a42Smrg	/*
28112c393a42Smrg	 * Add all files of the form [0-9]*.conf
28122c393a42Smrg	 */
28132c393a42Smrg	if ('0' <= e->d_name[0] && e->d_name[0] <= '9' &&
28142c393a42Smrg	    (d_len = strlen (e->d_name)) < FC_MAX_FILE_LEN &&
28152c393a42Smrg	    d_len > TAIL_LEN &&
28162c393a42Smrg	    strcmp (e->d_name + d_len - TAIL_LEN, TAIL) == 0)
28172c393a42Smrg	{
28182c393a42Smrg	    strcpy ((char *) base, (char *) e->d_name);
28192c393a42Smrg	    if (!FcStrSetAdd (files, file))
28202c393a42Smrg	    {
28212c393a42Smrg		ret = FcFalse;
28222c393a42Smrg		goto bail3;
28232c393a42Smrg	    }
28242c393a42Smrg	}
28252c393a42Smrg    }
28262c393a42Smrg    if (ret)
28272c393a42Smrg    {
28282c393a42Smrg	int i;
2829ca08ab68Smrg	qsort (files->strs, files->num, sizeof (FcChar8 *),
28302c393a42Smrg	       (int (*)(const void *, const void *)) FcSortCmpStr);
28312c393a42Smrg	for (i = 0; ret && i < files->num; i++)
28322c393a42Smrg	    ret = FcConfigParseAndLoad (config, files->strs[i], complain);
28332c393a42Smrg    }
28342c393a42Smrgbail3:
28352c393a42Smrg    FcStrSetDestroy (files);
28362c393a42Smrgbail2:
28372c393a42Smrg    free (file);
28382c393a42Smrgbail1:
28392c393a42Smrg    closedir (d);
28402c393a42Smrgbail0:
28412c393a42Smrg    return ret || !complain;
28422c393a42Smrg}
28432c393a42Smrg
2844ca08ab68Smrg#ifdef _WIN32
2845ca08ab68SmrgpfnGetSystemWindowsDirectory pGetSystemWindowsDirectory = NULL;
2846ca08ab68SmrgpfnSHGetFolderPathA pSHGetFolderPathA = NULL;
2847ca08ab68Smrg#endif
2848ca08ab68Smrg
28492c393a42SmrgFcBool
28502c393a42SmrgFcConfigParseAndLoad (FcConfig	    *config,
28512c393a42Smrg		      const FcChar8 *name,
28522c393a42Smrg		      FcBool	    complain)
28532c393a42Smrg{
28542c393a42Smrg
28552c393a42Smrg    XML_Parser	    p;
28562c393a42Smrg    FcChar8	    *filename;
28572c393a42Smrg    int		    fd;
28582c393a42Smrg    int		    len;
28592c393a42Smrg    FcConfigParse   parse;
28602c393a42Smrg    FcBool	    error = FcTrue;
2861ca08ab68Smrg
28622c393a42Smrg#ifdef ENABLE_LIBXML2
28632c393a42Smrg    xmlSAXHandler   sax;
28642c393a42Smrg    char            buf[BUFSIZ];
28652c393a42Smrg#else
28662c393a42Smrg    void	    *buf;
28672c393a42Smrg#endif
2868ca08ab68Smrg
2869ca08ab68Smrg#ifdef _WIN32
2870ca08ab68Smrg    if (!pGetSystemWindowsDirectory)
2871ca08ab68Smrg    {
2872ca08ab68Smrg        HMODULE hk32 = GetModuleHandleA("kernel32.dll");
2873ca08ab68Smrg        if (!(pGetSystemWindowsDirectory = (pfnGetSystemWindowsDirectory) GetProcAddress(hk32, "GetSystemWindowsDirectoryA")))
2874ca08ab68Smrg            pGetSystemWindowsDirectory = (pfnGetSystemWindowsDirectory) GetWindowsDirectory;
2875ca08ab68Smrg    }
2876ca08ab68Smrg    if (!pSHGetFolderPathA)
2877ca08ab68Smrg    {
2878ca08ab68Smrg        HMODULE hSh = LoadLibraryA("shfolder.dll");
2879ca08ab68Smrg        /* the check is done later, because there is no provided fallback */
2880ca08ab68Smrg        if (hSh)
2881ca08ab68Smrg            pSHGetFolderPathA = (pfnSHGetFolderPathA) GetProcAddress(hSh, "SHGetFolderPathA");
2882ca08ab68Smrg    }
2883ca08ab68Smrg#endif
2884ca08ab68Smrg
28852c393a42Smrg    filename = FcConfigFilename (name);
28862c393a42Smrg    if (!filename)
28872c393a42Smrg	goto bail0;
2888ca08ab68Smrg
28892c393a42Smrg    if (FcStrSetMember (config->configFiles, filename))
28902c393a42Smrg    {
28912c393a42Smrg        FcStrFree (filename);
28922c393a42Smrg        return FcTrue;
28932c393a42Smrg    }
28942c393a42Smrg
28952c393a42Smrg    if (!FcStrSetAdd (config->configFiles, filename))
28962c393a42Smrg    {
28972c393a42Smrg	FcStrFree (filename);
28982c393a42Smrg	goto bail0;
28992c393a42Smrg    }
29002c393a42Smrg
29012c393a42Smrg    if (FcFileIsDir (filename))
29022c393a42Smrg    {
29032c393a42Smrg	FcBool ret = FcConfigParseAndLoadDir (config, name, filename, complain);
29042c393a42Smrg	FcStrFree (filename);
29052c393a42Smrg	return ret;
29062c393a42Smrg    }
29072c393a42Smrg
29082c393a42Smrg    if (FcDebug () & FC_DBG_CONFIG)
29092c393a42Smrg	printf ("\tLoading config file %s\n", filename);
29102c393a42Smrg
29112c393a42Smrg    fd = open ((char *) filename, O_RDONLY);
2912ca08ab68Smrg    if (fd == -1) {
29132c393a42Smrg	FcStrFree (filename);
29142c393a42Smrg	goto bail0;
29152c393a42Smrg    }
2916ca08ab68Smrg
29172c393a42Smrg#ifdef ENABLE_LIBXML2
29182c393a42Smrg    memset(&sax, 0, sizeof(sax));
29192c393a42Smrg
29202c393a42Smrg    sax.internalSubset = FcInternalSubsetDecl;
29212c393a42Smrg    sax.externalSubset = FcExternalSubsetDecl;
29222c393a42Smrg    sax.startElement = FcStartElement;
29232c393a42Smrg    sax.endElement = FcEndElement;
29242c393a42Smrg    sax.characters = FcCharacterData;
29252c393a42Smrg
29262c393a42Smrg    p = xmlCreatePushParserCtxt (&sax, &parse, NULL, 0, (const char *) filename);
29272c393a42Smrg#else
29282c393a42Smrg    p = XML_ParserCreate ("UTF-8");
29292c393a42Smrg#endif
29302c393a42Smrg    FcStrFree (filename);
29312c393a42Smrg
29322c393a42Smrg    if (!p)
29332c393a42Smrg	goto bail1;
29342c393a42Smrg
29352c393a42Smrg    if (!FcConfigInit (&parse, name, config, p))
29362c393a42Smrg	goto bail2;
29372c393a42Smrg
29382c393a42Smrg#ifndef ENABLE_LIBXML2
29392c393a42Smrg
29402c393a42Smrg    XML_SetUserData (p, &parse);
2941ca08ab68Smrg
29422c393a42Smrg    XML_SetDoctypeDeclHandler (p, FcStartDoctypeDecl, FcEndDoctypeDecl);
29432c393a42Smrg    XML_SetElementHandler (p, FcStartElement, FcEndElement);
29442c393a42Smrg    XML_SetCharacterDataHandler (p, FcCharacterData);
29452c393a42Smrg
29462c393a42Smrg#endif /* ENABLE_LIBXML2 */
29472c393a42Smrg
29482c393a42Smrg    do {
29492c393a42Smrg#ifndef ENABLE_LIBXML2
29502c393a42Smrg	buf = XML_GetBuffer (p, BUFSIZ);
29512c393a42Smrg	if (!buf)
29522c393a42Smrg	{
29532c393a42Smrg	    FcConfigMessage (&parse, FcSevereError, "cannot get parse buffer");
29542c393a42Smrg	    goto bail3;
29552c393a42Smrg	}
29562c393a42Smrg#endif
29572c393a42Smrg	len = read (fd, buf, BUFSIZ);
29582c393a42Smrg	if (len < 0)
29592c393a42Smrg	{
29602c393a42Smrg	    FcConfigMessage (&parse, FcSevereError, "failed reading config file");
29612c393a42Smrg	    goto bail3;
29622c393a42Smrg	}
29632c393a42Smrg
29642c393a42Smrg#ifdef ENABLE_LIBXML2
29652c393a42Smrg	if (xmlParseChunk (p, buf, len, len == 0))
29662c393a42Smrg#else
29672c393a42Smrg	if (!XML_ParseBuffer (p, len, len == 0))
29682c393a42Smrg#endif
29692c393a42Smrg	{
2970ca08ab68Smrg	    FcConfigMessage (&parse, FcSevereError, "%s",
29712c393a42Smrg			   XML_ErrorString (XML_GetErrorCode (p)));
29722c393a42Smrg	    goto bail3;
29732c393a42Smrg	}
29742c393a42Smrg    } while (len != 0);
29752c393a42Smrg    error = parse.error;
29762c393a42Smrgbail3:
29772c393a42Smrg    FcConfigCleanup (&parse);
29782c393a42Smrgbail2:
29792c393a42Smrg    XML_ParserFree (p);
29802c393a42Smrgbail1:
29812c393a42Smrg    close (fd);
29822c393a42Smrg    fd = -1;
29832c393a42Smrgbail0:
29842c393a42Smrg    if (error && complain)
29852c393a42Smrg    {
29862c393a42Smrg	if (name)
29872c393a42Smrg	    FcConfigMessage (0, FcSevereError, "Cannot load config file \"%s\"", name);
29882c393a42Smrg	else
29892c393a42Smrg	    FcConfigMessage (0, FcSevereError, "Cannot load default config file");
29902c393a42Smrg	return FcFalse;
29912c393a42Smrg    }
29922c393a42Smrg    return FcTrue;
29932c393a42Smrg}
29942c393a42Smrg#define __fcxml__
29952c393a42Smrg#include "fcaliastail.h"
29962c393a42Smrg#undef __fcxml__
2997