fcxml.c revision a6844aab
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
102c393a42Smrg * documentation, and that the name of Keith Packard not be used in
112c393a42Smrg * advertising or publicity pertaining to distribution of the software without
122c393a42Smrg * specific, written prior permission.  Keith Packard makes 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#define _WIN32_WINNT 0x0500
572c393a42Smrg#define STRICT
582c393a42Smrg#include <windows.h>
592c393a42Smrg#undef STRICT
60a6844aabSmrg#include <mbstring.h>
612c393a42Smrg#endif
622c393a42Smrg
63a6844aabSmrgstatic void
64a6844aabSmrgFcExprDestroy (FcExpr *e);
652c393a42Smrg
662c393a42Smrgvoid
672c393a42SmrgFcTestDestroy (FcTest *test)
682c393a42Smrg{
692c393a42Smrg    if (test->next)
702c393a42Smrg	FcTestDestroy (test->next);
712c393a42Smrg    FcExprDestroy (test->expr);
722c393a42Smrg    FcMemFree (FC_MEM_TEST, sizeof (FcTest));
732c393a42Smrg    free (test);
742c393a42Smrg}
752c393a42Smrg
76a6844aabSmrgstatic FcExpr *
77a6844aabSmrgFcExprCreateInteger (FcConfig *config, int i)
782c393a42Smrg{
79a6844aabSmrg    FcExpr *e = FcConfigAllocExpr (config);
802c393a42Smrg    if (e)
812c393a42Smrg    {
822c393a42Smrg	e->op = FcOpInteger;
832c393a42Smrg	e->u.ival = i;
842c393a42Smrg    }
852c393a42Smrg    return e;
862c393a42Smrg}
872c393a42Smrg
88a6844aabSmrgstatic FcExpr *
89a6844aabSmrgFcExprCreateDouble (FcConfig *config, double d)
902c393a42Smrg{
91a6844aabSmrg    FcExpr *e = FcConfigAllocExpr (config);
922c393a42Smrg    if (e)
932c393a42Smrg    {
942c393a42Smrg	e->op = FcOpDouble;
952c393a42Smrg	e->u.dval = d;
962c393a42Smrg    }
972c393a42Smrg    return e;
982c393a42Smrg}
992c393a42Smrg
100a6844aabSmrgstatic FcExpr *
101a6844aabSmrgFcExprCreateString (FcConfig *config, const FcChar8 *s)
1022c393a42Smrg{
103a6844aabSmrg    FcExpr *e = FcConfigAllocExpr (config);
1042c393a42Smrg    if (e)
1052c393a42Smrg    {
1062c393a42Smrg	e->op = FcOpString;
107a6844aabSmrg	e->u.sval = FcStrStaticName (s);
1082c393a42Smrg    }
1092c393a42Smrg    return e;
1102c393a42Smrg}
1112c393a42Smrg
112a6844aabSmrgstatic FcExpr *
113a6844aabSmrgFcExprCreateMatrix (FcConfig *config, const FcMatrix *m)
1142c393a42Smrg{
115a6844aabSmrg    FcExpr *e = FcConfigAllocExpr (config);
1162c393a42Smrg    if (e)
1172c393a42Smrg    {
1182c393a42Smrg	e->op = FcOpMatrix;
1192c393a42Smrg	e->u.mval = FcMatrixCopy (m);
1202c393a42Smrg    }
1212c393a42Smrg    return e;
1222c393a42Smrg}
1232c393a42Smrg
124a6844aabSmrgstatic FcExpr *
125a6844aabSmrgFcExprCreateBool (FcConfig *config, FcBool b)
1262c393a42Smrg{
127a6844aabSmrg    FcExpr *e = FcConfigAllocExpr (config);
1282c393a42Smrg    if (e)
1292c393a42Smrg    {
1302c393a42Smrg	e->op = FcOpBool;
1312c393a42Smrg	e->u.bval = b;
1322c393a42Smrg    }
1332c393a42Smrg    return e;
1342c393a42Smrg}
1352c393a42Smrg
136a6844aabSmrgstatic FcExpr *
137a6844aabSmrgFcExprCreateField (FcConfig *config, const char *field)
1382c393a42Smrg{
139a6844aabSmrg    FcExpr *e = FcConfigAllocExpr (config);
1402c393a42Smrg    if (e)
1412c393a42Smrg    {
1422c393a42Smrg	e->op = FcOpField;
1432c393a42Smrg	e->u.object = FcObjectFromName (field);
1442c393a42Smrg    }
1452c393a42Smrg    return e;
1462c393a42Smrg}
1472c393a42Smrg
148a6844aabSmrgstatic FcExpr *
149a6844aabSmrgFcExprCreateConst (FcConfig *config, const FcChar8 *constant)
1502c393a42Smrg{
151a6844aabSmrg    FcExpr *e = FcConfigAllocExpr (config);
1522c393a42Smrg    if (e)
1532c393a42Smrg    {
1542c393a42Smrg	e->op = FcOpConst;
155a6844aabSmrg	e->u.constant = FcStrStaticName (constant);
1562c393a42Smrg    }
1572c393a42Smrg    return e;
1582c393a42Smrg}
1592c393a42Smrg
160a6844aabSmrgstatic FcExpr *
161a6844aabSmrgFcExprCreateOp (FcConfig *config, FcExpr *left, FcOp op, FcExpr *right)
1622c393a42Smrg{
163a6844aabSmrg    FcExpr *e = FcConfigAllocExpr (config);
1642c393a42Smrg    if (e)
1652c393a42Smrg    {
1662c393a42Smrg	e->op = op;
1672c393a42Smrg	e->u.tree.left = left;
1682c393a42Smrg	e->u.tree.right = right;
1692c393a42Smrg    }
1702c393a42Smrg    return e;
1712c393a42Smrg}
1722c393a42Smrg
173a6844aabSmrgstatic void
1742c393a42SmrgFcExprDestroy (FcExpr *e)
1752c393a42Smrg{
1762c393a42Smrg    if (!e)
1772c393a42Smrg	return;
1782c393a42Smrg    switch (e->op) {
1792c393a42Smrg    case FcOpInteger:
1802c393a42Smrg	break;
1812c393a42Smrg    case FcOpDouble:
1822c393a42Smrg	break;
1832c393a42Smrg    case FcOpString:
1842c393a42Smrg	break;
1852c393a42Smrg    case FcOpMatrix:
1862c393a42Smrg	FcMatrixFree (e->u.mval);
1872c393a42Smrg	break;
1882c393a42Smrg    case FcOpCharSet:
1892c393a42Smrg	FcCharSetDestroy (e->u.cval);
1902c393a42Smrg	break;
1912c393a42Smrg    case FcOpBool:
1922c393a42Smrg	break;
1932c393a42Smrg    case FcOpField:
1942c393a42Smrg	break;
1952c393a42Smrg    case FcOpConst:
1962c393a42Smrg	break;
1972c393a42Smrg    case FcOpAssign:
1982c393a42Smrg    case FcOpAssignReplace:
1992c393a42Smrg    case FcOpPrepend:
2002c393a42Smrg    case FcOpPrependFirst:
2012c393a42Smrg    case FcOpAppend:
2022c393a42Smrg    case FcOpAppendLast:
2032c393a42Smrg	break;
2042c393a42Smrg    case FcOpOr:
2052c393a42Smrg    case FcOpAnd:
2062c393a42Smrg    case FcOpEqual:
2072c393a42Smrg    case FcOpNotEqual:
2082c393a42Smrg    case FcOpLess:
2092c393a42Smrg    case FcOpLessEqual:
2102c393a42Smrg    case FcOpMore:
2112c393a42Smrg    case FcOpMoreEqual:
2122c393a42Smrg    case FcOpContains:
2132c393a42Smrg    case FcOpListing:
2142c393a42Smrg    case FcOpNotContains:
2152c393a42Smrg    case FcOpPlus:
2162c393a42Smrg    case FcOpMinus:
2172c393a42Smrg    case FcOpTimes:
2182c393a42Smrg    case FcOpDivide:
2192c393a42Smrg    case FcOpQuest:
2202c393a42Smrg    case FcOpComma:
2212c393a42Smrg	FcExprDestroy (e->u.tree.right);
2222c393a42Smrg	/* fall through */
2232c393a42Smrg    case FcOpNot:
2242c393a42Smrg    case FcOpFloor:
2252c393a42Smrg    case FcOpCeil:
2262c393a42Smrg    case FcOpRound:
2272c393a42Smrg    case FcOpTrunc:
2282c393a42Smrg	FcExprDestroy (e->u.tree.left);
2292c393a42Smrg	break;
2302c393a42Smrg    case FcOpNil:
2312c393a42Smrg    case FcOpInvalid:
2322c393a42Smrg	break;
2332c393a42Smrg    }
234a6844aabSmrg
235a6844aabSmrg    e->op = FcOpNil;
2362c393a42Smrg}
2372c393a42Smrg
2382c393a42Smrgvoid
2392c393a42SmrgFcEditDestroy (FcEdit *e)
2402c393a42Smrg{
2412c393a42Smrg    if (e->next)
2422c393a42Smrg	FcEditDestroy (e->next);
2432c393a42Smrg    if (e->expr)
2442c393a42Smrg	FcExprDestroy (e->expr);
2452c393a42Smrg    free (e);
2462c393a42Smrg}
2472c393a42Smrg
2482c393a42Smrgtypedef enum _FcElement {
2492c393a42Smrg    FcElementNone,
2502c393a42Smrg    FcElementFontconfig,
2512c393a42Smrg    FcElementDir,
2522c393a42Smrg    FcElementCacheDir,
2532c393a42Smrg    FcElementCache,
2542c393a42Smrg    FcElementInclude,
2552c393a42Smrg    FcElementConfig,
2562c393a42Smrg    FcElementMatch,
2572c393a42Smrg    FcElementAlias,
2582c393a42Smrg
2592c393a42Smrg    FcElementBlank,
2602c393a42Smrg    FcElementRescan,
2612c393a42Smrg
2622c393a42Smrg    FcElementPrefer,
2632c393a42Smrg    FcElementAccept,
2642c393a42Smrg    FcElementDefault,
2652c393a42Smrg    FcElementFamily,
2662c393a42Smrg
2672c393a42Smrg    FcElementSelectfont,
2682c393a42Smrg    FcElementAcceptfont,
2692c393a42Smrg    FcElementRejectfont,
2702c393a42Smrg    FcElementGlob,
2712c393a42Smrg    FcElementPattern,
2722c393a42Smrg    FcElementPatelt,
2732c393a42Smrg
2742c393a42Smrg    FcElementTest,
2752c393a42Smrg    FcElementEdit,
2762c393a42Smrg    FcElementInt,
2772c393a42Smrg    FcElementDouble,
2782c393a42Smrg    FcElementString,
2792c393a42Smrg    FcElementMatrix,
2802c393a42Smrg    FcElementBool,
2812c393a42Smrg    FcElementCharset,
2822c393a42Smrg    FcElementName,
2832c393a42Smrg    FcElementConst,
2842c393a42Smrg    FcElementOr,
2852c393a42Smrg    FcElementAnd,
2862c393a42Smrg    FcElementEq,
2872c393a42Smrg    FcElementNotEq,
2882c393a42Smrg    FcElementLess,
2892c393a42Smrg    FcElementLessEq,
2902c393a42Smrg    FcElementMore,
2912c393a42Smrg    FcElementMoreEq,
2922c393a42Smrg    FcElementContains,
2932c393a42Smrg    FcElementNotContains,
2942c393a42Smrg    FcElementPlus,
2952c393a42Smrg    FcElementMinus,
2962c393a42Smrg    FcElementTimes,
2972c393a42Smrg    FcElementDivide,
2982c393a42Smrg    FcElementNot,
2992c393a42Smrg    FcElementIf,
3002c393a42Smrg    FcElementFloor,
3012c393a42Smrg    FcElementCeil,
3022c393a42Smrg    FcElementRound,
3032c393a42Smrg    FcElementTrunc,
3042c393a42Smrg    FcElementUnknown
3052c393a42Smrg} FcElement;
3062c393a42Smrg
3072c393a42Smrgstatic const struct {
3082c393a42Smrg    const char  name[16];
3092c393a42Smrg    FcElement   element;
3102c393a42Smrg} fcElementMap[] = {
3112c393a42Smrg    { "fontconfig",	FcElementFontconfig },
3122c393a42Smrg    { "dir",		FcElementDir },
3132c393a42Smrg    { "cachedir",	FcElementCacheDir },
3142c393a42Smrg    { "cache",		FcElementCache },
3152c393a42Smrg    { "include",	FcElementInclude },
3162c393a42Smrg    { "config",		FcElementConfig },
3172c393a42Smrg    { "match",		FcElementMatch },
3182c393a42Smrg    { "alias",		FcElementAlias },
3192c393a42Smrg
3202c393a42Smrg    { "blank",		FcElementBlank },
3212c393a42Smrg    { "rescan",		FcElementRescan },
3222c393a42Smrg
3232c393a42Smrg    { "prefer",		FcElementPrefer },
3242c393a42Smrg    { "accept",		FcElementAccept },
3252c393a42Smrg    { "default",	FcElementDefault },
3262c393a42Smrg    { "family",		FcElementFamily },
3272c393a42Smrg
3282c393a42Smrg    { "selectfont",	FcElementSelectfont },
3292c393a42Smrg    { "acceptfont",	FcElementAcceptfont },
3302c393a42Smrg    { "rejectfont",	FcElementRejectfont },
3312c393a42Smrg    { "glob",		FcElementGlob },
3322c393a42Smrg    { "pattern",	FcElementPattern },
3332c393a42Smrg    { "patelt",		FcElementPatelt },
3342c393a42Smrg
3352c393a42Smrg    { "test",		FcElementTest },
3362c393a42Smrg    { "edit",		FcElementEdit },
3372c393a42Smrg    { "int",		FcElementInt },
3382c393a42Smrg    { "double",		FcElementDouble },
3392c393a42Smrg    { "string",		FcElementString },
3402c393a42Smrg    { "matrix",		FcElementMatrix },
3412c393a42Smrg    { "bool",		FcElementBool },
3422c393a42Smrg    { "charset",	FcElementCharset },
3432c393a42Smrg    { "name",		FcElementName },
3442c393a42Smrg    { "const",		FcElementConst },
3452c393a42Smrg    { "or",		FcElementOr },
3462c393a42Smrg    { "and",		FcElementAnd },
3472c393a42Smrg    { "eq",		FcElementEq },
3482c393a42Smrg    { "not_eq",		FcElementNotEq },
3492c393a42Smrg    { "less",		FcElementLess },
3502c393a42Smrg    { "less_eq",	FcElementLessEq },
3512c393a42Smrg    { "more",		FcElementMore },
3522c393a42Smrg    { "more_eq",	FcElementMoreEq },
3532c393a42Smrg    { "contains",	FcElementContains },
3542c393a42Smrg    { "not_contains",	FcElementNotContains },
3552c393a42Smrg    { "plus",		FcElementPlus },
3562c393a42Smrg    { "minus",		FcElementMinus },
3572c393a42Smrg    { "times",		FcElementTimes },
3582c393a42Smrg    { "divide",		FcElementDivide },
3592c393a42Smrg    { "not",		FcElementNot },
3602c393a42Smrg    { "if",		FcElementIf },
3612c393a42Smrg    { "floor",		FcElementFloor },
3622c393a42Smrg    { "ceil",		FcElementCeil },
3632c393a42Smrg    { "round",		FcElementRound },
3642c393a42Smrg    { "trunc",		FcElementTrunc },
3652c393a42Smrg};
3662c393a42Smrg#define NUM_ELEMENT_MAPS (int) (sizeof fcElementMap / sizeof fcElementMap[0])
3672c393a42Smrg
3682c393a42Smrgstatic FcElement
3692c393a42SmrgFcElementMap (const XML_Char *name)
3702c393a42Smrg{
3712c393a42Smrg
3722c393a42Smrg    int	    i;
3732c393a42Smrg    for (i = 0; i < NUM_ELEMENT_MAPS; i++)
3742c393a42Smrg	if (!strcmp ((char *) name, fcElementMap[i].name))
3752c393a42Smrg	    return fcElementMap[i].element;
3762c393a42Smrg    return FcElementUnknown;
3772c393a42Smrg}
3782c393a42Smrg
3792c393a42Smrgtypedef struct _FcPStack {
3802c393a42Smrg    struct _FcPStack   *prev;
3812c393a42Smrg    FcElement		element;
3822c393a42Smrg    FcChar8		**attr;
3832c393a42Smrg    FcStrBuf		str;
384a6844aabSmrg    FcChar8            *attr_buf_static[16];
3852c393a42Smrg} FcPStack;
3862c393a42Smrg
3872c393a42Smrgtypedef enum _FcVStackTag {
3882c393a42Smrg    FcVStackNone,
3892c393a42Smrg
3902c393a42Smrg    FcVStackString,
3912c393a42Smrg    FcVStackFamily,
3922c393a42Smrg    FcVStackField,
3932c393a42Smrg    FcVStackConstant,
3942c393a42Smrg    FcVStackGlob,
3952c393a42Smrg    FcVStackPattern,
3962c393a42Smrg
3972c393a42Smrg    FcVStackPrefer,
3982c393a42Smrg    FcVStackAccept,
3992c393a42Smrg    FcVStackDefault,
4002c393a42Smrg
4012c393a42Smrg    FcVStackInteger,
4022c393a42Smrg    FcVStackDouble,
4032c393a42Smrg    FcVStackMatrix,
4042c393a42Smrg    FcVStackBool,
4052c393a42Smrg
4062c393a42Smrg    FcVStackTest,
4072c393a42Smrg    FcVStackExpr,
4082c393a42Smrg    FcVStackEdit
4092c393a42Smrg} FcVStackTag;
4102c393a42Smrg
4112c393a42Smrgtypedef struct _FcVStack {
4122c393a42Smrg    struct _FcVStack	*prev;
4132c393a42Smrg    FcPStack		*pstack;	/* related parse element */
4142c393a42Smrg    FcVStackTag		tag;
4152c393a42Smrg    union {
4162c393a42Smrg	FcChar8		*string;
4172c393a42Smrg
4182c393a42Smrg	int		integer;
4192c393a42Smrg	double		_double;
4202c393a42Smrg	FcMatrix	*matrix;
421a6844aabSmrg	FcBool		bool_;
4222c393a42Smrg
4232c393a42Smrg	FcTest		*test;
4242c393a42Smrg	FcQual		qual;
4252c393a42Smrg	FcOp		op;
4262c393a42Smrg	FcExpr		*expr;
4272c393a42Smrg	FcEdit		*edit;
4282c393a42Smrg
4292c393a42Smrg	FcPattern	*pattern;
4302c393a42Smrg    } u;
4312c393a42Smrg} FcVStack;
4322c393a42Smrg
4332c393a42Smrgtypedef struct _FcConfigParse {
4342c393a42Smrg    FcPStack	    *pstack;
4352c393a42Smrg    FcVStack	    *vstack;
4362c393a42Smrg    FcBool	    error;
4372c393a42Smrg    const FcChar8   *name;
4382c393a42Smrg    FcConfig	    *config;
4392c393a42Smrg    XML_Parser	    parser;
440a6844aabSmrg    int             pstack_static_used;
441a6844aabSmrg    FcPStack        pstack_static[8];
442a6844aabSmrg    int             vstack_static_used;
443a6844aabSmrg    FcVStack        vstack_static[64];
4442c393a42Smrg} FcConfigParse;
4452c393a42Smrg
4462c393a42Smrgtypedef enum _FcConfigSeverity {
4472c393a42Smrg    FcSevereInfo, FcSevereWarning, FcSevereError
4482c393a42Smrg} FcConfigSeverity;
4492c393a42Smrg
4502c393a42Smrgstatic void
4512c393a42SmrgFcConfigMessage (FcConfigParse *parse, FcConfigSeverity severe, const char *fmt, ...)
4522c393a42Smrg{
4532c393a42Smrg    const char	*s = "unknown";
4542c393a42Smrg    va_list	args;
4552c393a42Smrg
4562c393a42Smrg    va_start (args, fmt);
4572c393a42Smrg
4582c393a42Smrg    switch (severe) {
4592c393a42Smrg    case FcSevereInfo: s = "info"; break;
4602c393a42Smrg    case FcSevereWarning: s = "warning"; break;
4612c393a42Smrg    case FcSevereError: s = "error"; break;
4622c393a42Smrg    }
4632c393a42Smrg    if (parse)
4642c393a42Smrg    {
4652c393a42Smrg	if (parse->name)
4662c393a42Smrg	    fprintf (stderr, "Fontconfig %s: \"%s\", line %d: ", s,
4672c393a42Smrg		     parse->name, (int)XML_GetCurrentLineNumber (parse->parser));
4682c393a42Smrg	else
4692c393a42Smrg	    fprintf (stderr, "Fontconfig %s: line %d: ", s,
4702c393a42Smrg		     (int)XML_GetCurrentLineNumber (parse->parser));
4712c393a42Smrg	if (severe >= FcSevereError)
4722c393a42Smrg	    parse->error = FcTrue;
4732c393a42Smrg    }
4742c393a42Smrg    else
4752c393a42Smrg	fprintf (stderr, "Fontconfig %s: ", s);
4762c393a42Smrg    vfprintf (stderr, fmt, args);
4772c393a42Smrg    fprintf (stderr, "\n");
4782c393a42Smrg    va_end (args);
4792c393a42Smrg}
4802c393a42Smrg
4812c393a42Smrg
4822c393a42Smrgstatic const char *
4832c393a42SmrgFcTypeName (FcType type)
4842c393a42Smrg{
4852c393a42Smrg    switch (type) {
4862c393a42Smrg    case FcTypeVoid:
4872c393a42Smrg	return "void";
4882c393a42Smrg    case FcTypeInteger:
4892c393a42Smrg    case FcTypeDouble:
4902c393a42Smrg	return "number";
4912c393a42Smrg    case FcTypeString:
4922c393a42Smrg	return "string";
4932c393a42Smrg    case FcTypeBool:
4942c393a42Smrg	return "bool";
4952c393a42Smrg    case FcTypeMatrix:
4962c393a42Smrg	return "matrix";
4972c393a42Smrg    case FcTypeCharSet:
4982c393a42Smrg	return "charset";
4992c393a42Smrg    case FcTypeFTFace:
5002c393a42Smrg	return "FT_Face";
5012c393a42Smrg    case FcTypeLangSet:
5022c393a42Smrg	return "langset";
5032c393a42Smrg    default:
5042c393a42Smrg	return "unknown";
5052c393a42Smrg    }
5062c393a42Smrg}
5072c393a42Smrg
5082c393a42Smrgstatic void
5092c393a42SmrgFcTypecheckValue (FcConfigParse *parse, FcType value, FcType type)
5102c393a42Smrg{
5112c393a42Smrg    if (value == FcTypeInteger)
5122c393a42Smrg	value = FcTypeDouble;
5132c393a42Smrg    if (type == FcTypeInteger)
5142c393a42Smrg	type = FcTypeDouble;
5152c393a42Smrg    if (value != type)
5162c393a42Smrg    {
5172c393a42Smrg	if ((value == FcTypeLangSet && type == FcTypeString) ||
5182c393a42Smrg	    (value == FcTypeString && type == FcTypeLangSet))
5192c393a42Smrg	    return;
5202c393a42Smrg	if (type == (FcType) -1)
5212c393a42Smrg	    return;
5222c393a42Smrg	FcConfigMessage (parse, FcSevereWarning, "saw %s, expected %s",
5232c393a42Smrg			 FcTypeName (value), FcTypeName (type));
5242c393a42Smrg    }
5252c393a42Smrg}
5262c393a42Smrg
5272c393a42Smrgstatic void
5282c393a42SmrgFcTypecheckExpr (FcConfigParse *parse, FcExpr *expr, FcType type)
5292c393a42Smrg{
5302c393a42Smrg    const FcObjectType	*o;
5312c393a42Smrg    const FcConstant	*c;
5322c393a42Smrg
5332c393a42Smrg    /* If parsing the expression failed, some nodes may be NULL */
5342c393a42Smrg    if (!expr)
5352c393a42Smrg	return;
5362c393a42Smrg
5372c393a42Smrg    switch (expr->op) {
5382c393a42Smrg    case FcOpInteger:
5392c393a42Smrg    case FcOpDouble:
5402c393a42Smrg	FcTypecheckValue (parse, FcTypeDouble, type);
5412c393a42Smrg	break;
5422c393a42Smrg    case FcOpString:
5432c393a42Smrg	FcTypecheckValue (parse, FcTypeString, type);
5442c393a42Smrg	break;
5452c393a42Smrg    case FcOpMatrix:
5462c393a42Smrg	FcTypecheckValue (parse, FcTypeMatrix, type);
5472c393a42Smrg	break;
5482c393a42Smrg    case FcOpBool:
5492c393a42Smrg	FcTypecheckValue (parse, FcTypeBool, type);
5502c393a42Smrg	break;
5512c393a42Smrg    case FcOpCharSet:
5522c393a42Smrg	FcTypecheckValue (parse, FcTypeCharSet, type);
5532c393a42Smrg	break;
5542c393a42Smrg    case FcOpNil:
5552c393a42Smrg	break;
5562c393a42Smrg    case FcOpField:
5572c393a42Smrg	o = FcNameGetObjectType (FcObjectName (expr->u.object));
5582c393a42Smrg	if (o)
5592c393a42Smrg	    FcTypecheckValue (parse, o->type, type);
5602c393a42Smrg	break;
5612c393a42Smrg    case FcOpConst:
5622c393a42Smrg	c = FcNameGetConstant (expr->u.constant);
5632c393a42Smrg	if (c)
5642c393a42Smrg	{
5652c393a42Smrg	    o = FcNameGetObjectType (c->object);
5662c393a42Smrg	    if (o)
5672c393a42Smrg		FcTypecheckValue (parse, o->type, type);
5682c393a42Smrg	}
5692c393a42Smrg        else
5702c393a42Smrg            FcConfigMessage (parse, FcSevereWarning,
5712c393a42Smrg                             "invalid constant used : %s",
5722c393a42Smrg                             expr->u.constant);
5732c393a42Smrg	break;
5742c393a42Smrg    case FcOpQuest:
5752c393a42Smrg	FcTypecheckExpr (parse, expr->u.tree.left, FcTypeBool);
5762c393a42Smrg	FcTypecheckExpr (parse, expr->u.tree.right->u.tree.left, type);
5772c393a42Smrg	FcTypecheckExpr (parse, expr->u.tree.right->u.tree.right, type);
5782c393a42Smrg	break;
5792c393a42Smrg    case FcOpAssign:
5802c393a42Smrg    case FcOpAssignReplace:
5812c393a42Smrg	break;
5822c393a42Smrg    case FcOpEqual:
5832c393a42Smrg    case FcOpNotEqual:
5842c393a42Smrg    case FcOpLess:
5852c393a42Smrg    case FcOpLessEqual:
5862c393a42Smrg    case FcOpMore:
5872c393a42Smrg    case FcOpMoreEqual:
5882c393a42Smrg    case FcOpContains:
5892c393a42Smrg    case FcOpNotContains:
5902c393a42Smrg    case FcOpListing:
5912c393a42Smrg	FcTypecheckValue (parse, FcTypeBool, type);
5922c393a42Smrg	break;
5932c393a42Smrg    case FcOpComma:
5942c393a42Smrg    case FcOpOr:
5952c393a42Smrg    case FcOpAnd:
5962c393a42Smrg    case FcOpPlus:
5972c393a42Smrg    case FcOpMinus:
5982c393a42Smrg    case FcOpTimes:
5992c393a42Smrg    case FcOpDivide:
6002c393a42Smrg	FcTypecheckExpr (parse, expr->u.tree.left, type);
6012c393a42Smrg	FcTypecheckExpr (parse, expr->u.tree.right, type);
6022c393a42Smrg	break;
6032c393a42Smrg    case FcOpNot:
6042c393a42Smrg	FcTypecheckValue (parse, FcTypeBool, type);
6052c393a42Smrg	FcTypecheckExpr (parse, expr->u.tree.left, FcTypeBool);
6062c393a42Smrg	break;
6072c393a42Smrg    case FcOpFloor:
6082c393a42Smrg    case FcOpCeil:
6092c393a42Smrg    case FcOpRound:
6102c393a42Smrg    case FcOpTrunc:
6112c393a42Smrg	FcTypecheckValue (parse, FcTypeDouble, type);
6122c393a42Smrg	FcTypecheckExpr (parse, expr->u.tree.left, FcTypeDouble);
6132c393a42Smrg	break;
6142c393a42Smrg    default:
6152c393a42Smrg	break;
6162c393a42Smrg    }
6172c393a42Smrg}
6182c393a42Smrg
6192c393a42Smrgstatic FcTest *
6202c393a42SmrgFcTestCreate (FcConfigParse *parse,
6212c393a42Smrg	      FcMatchKind   kind,
6222c393a42Smrg	      FcQual	    qual,
6232c393a42Smrg	      const FcChar8 *field,
6242c393a42Smrg	      FcOp	    compare,
6252c393a42Smrg	      FcExpr	    *expr)
6262c393a42Smrg{
6272c393a42Smrg    FcTest	*test = (FcTest *) malloc (sizeof (FcTest));
6282c393a42Smrg
6292c393a42Smrg    if (test)
6302c393a42Smrg    {
6312c393a42Smrg	const FcObjectType	*o;
6322c393a42Smrg
6332c393a42Smrg	FcMemAlloc (FC_MEM_TEST, sizeof (FcTest));
6342c393a42Smrg	test->next = 0;
6352c393a42Smrg	test->kind = kind;
6362c393a42Smrg	test->qual = qual;
6372c393a42Smrg	test->object = FcObjectFromName ((const char *) field);
6382c393a42Smrg	test->op = compare;
6392c393a42Smrg	test->expr = expr;
6402c393a42Smrg	o = FcNameGetObjectType (FcObjectName (test->object));
6412c393a42Smrg	if (o)
6422c393a42Smrg	    FcTypecheckExpr (parse, expr, o->type);
6432c393a42Smrg    }
6442c393a42Smrg    return test;
6452c393a42Smrg}
6462c393a42Smrg
6472c393a42Smrgstatic FcEdit *
6482c393a42SmrgFcEditCreate (FcConfigParse	*parse,
6492c393a42Smrg	      FcObject		object,
6502c393a42Smrg	      FcOp		op,
6512c393a42Smrg	      FcExpr		*expr,
6522c393a42Smrg	      FcValueBinding	binding)
6532c393a42Smrg{
6542c393a42Smrg    FcEdit *e = (FcEdit *) malloc (sizeof (FcEdit));
6552c393a42Smrg
6562c393a42Smrg    if (e)
6572c393a42Smrg    {
6582c393a42Smrg	const FcObjectType	*o;
6592c393a42Smrg
6602c393a42Smrg	e->next = 0;
6612c393a42Smrg	e->object = object;
6622c393a42Smrg	e->op = op;
6632c393a42Smrg	e->expr = expr;
6642c393a42Smrg	e->binding = binding;
6652c393a42Smrg	o = FcNameGetObjectType (FcObjectName (e->object));
6662c393a42Smrg	if (o)
6672c393a42Smrg	    FcTypecheckExpr (parse, expr, o->type);
6682c393a42Smrg    }
6692c393a42Smrg    return e;
6702c393a42Smrg}
6712c393a42Smrg
6722c393a42Smrgstatic FcVStack *
673a6844aabSmrgFcVStackCreateAndPush (FcConfigParse *parse)
6742c393a42Smrg{
6752c393a42Smrg    FcVStack    *new;
6762c393a42Smrg
677a6844aabSmrg    if (parse->vstack_static_used < sizeof (parse->vstack_static) / sizeof (parse->vstack_static[0]))
678a6844aabSmrg	new = &parse->vstack_static[parse->vstack_static_used++];
679a6844aabSmrg    else
680a6844aabSmrg    {
681a6844aabSmrg	new = malloc (sizeof (FcVStack));
682a6844aabSmrg	if (!new)
683a6844aabSmrg	    return 0;
684a6844aabSmrg	FcMemAlloc (FC_MEM_VSTACK, sizeof (FcVStack));
685a6844aabSmrg    }
6862c393a42Smrg    new->tag = FcVStackNone;
6872c393a42Smrg    new->prev = 0;
6882c393a42Smrg
689a6844aabSmrg    new->prev = parse->vstack;
690a6844aabSmrg    new->pstack = parse->pstack ? parse->pstack->prev : 0;
691a6844aabSmrg    parse->vstack = new;
6922c393a42Smrg
693a6844aabSmrg    return new;
6942c393a42Smrg}
6952c393a42Smrg
6962c393a42Smrgstatic FcBool
6972c393a42SmrgFcVStackPushString (FcConfigParse *parse, FcVStackTag tag, FcChar8 *string)
6982c393a42Smrg{
699a6844aabSmrg    FcVStack    *vstack = FcVStackCreateAndPush (parse);
7002c393a42Smrg    if (!vstack)
7012c393a42Smrg	return FcFalse;
7022c393a42Smrg    vstack->u.string = string;
7032c393a42Smrg    vstack->tag = tag;
7042c393a42Smrg    return FcTrue;
7052c393a42Smrg}
7062c393a42Smrg
7072c393a42Smrgstatic FcBool
7082c393a42SmrgFcVStackPushInteger (FcConfigParse *parse, int integer)
7092c393a42Smrg{
710a6844aabSmrg    FcVStack    *vstack = FcVStackCreateAndPush (parse);
7112c393a42Smrg    if (!vstack)
7122c393a42Smrg	return FcFalse;
7132c393a42Smrg    vstack->u.integer = integer;
7142c393a42Smrg    vstack->tag = FcVStackInteger;
7152c393a42Smrg    return FcTrue;
7162c393a42Smrg}
7172c393a42Smrg
7182c393a42Smrgstatic FcBool
7192c393a42SmrgFcVStackPushDouble (FcConfigParse *parse, double _double)
7202c393a42Smrg{
721a6844aabSmrg    FcVStack    *vstack = FcVStackCreateAndPush (parse);
7222c393a42Smrg    if (!vstack)
7232c393a42Smrg	return FcFalse;
7242c393a42Smrg    vstack->u._double = _double;
7252c393a42Smrg    vstack->tag = FcVStackDouble;
7262c393a42Smrg    return FcTrue;
7272c393a42Smrg}
7282c393a42Smrg
7292c393a42Smrgstatic FcBool
7302c393a42SmrgFcVStackPushMatrix (FcConfigParse *parse, FcMatrix *matrix)
7312c393a42Smrg{
732a6844aabSmrg    FcVStack    *vstack;
7332c393a42Smrg    matrix = FcMatrixCopy (matrix);
7342c393a42Smrg    if (!matrix)
7352c393a42Smrg	return FcFalse;
736a6844aabSmrg    vstack = FcVStackCreateAndPush (parse);
737a6844aabSmrg    if (!vstack)
738a6844aabSmrg	return FcFalse;
7392c393a42Smrg    vstack->u.matrix = matrix;
7402c393a42Smrg    vstack->tag = FcVStackMatrix;
7412c393a42Smrg    return FcTrue;
7422c393a42Smrg}
7432c393a42Smrg
7442c393a42Smrgstatic FcBool
745a6844aabSmrgFcVStackPushBool (FcConfigParse *parse, FcBool bool_)
7462c393a42Smrg{
747a6844aabSmrg    FcVStack    *vstack = FcVStackCreateAndPush (parse);
7482c393a42Smrg    if (!vstack)
7492c393a42Smrg	return FcFalse;
750a6844aabSmrg    vstack->u.bool_ = bool_;
7512c393a42Smrg    vstack->tag = FcVStackBool;
7522c393a42Smrg    return FcTrue;
7532c393a42Smrg}
7542c393a42Smrg
7552c393a42Smrgstatic FcBool
7562c393a42SmrgFcVStackPushTest (FcConfigParse *parse, FcTest *test)
7572c393a42Smrg{
758a6844aabSmrg    FcVStack    *vstack = FcVStackCreateAndPush (parse);
7592c393a42Smrg    if (!vstack)
7602c393a42Smrg	return FcFalse;
7612c393a42Smrg    vstack->u.test = test;
7622c393a42Smrg    vstack->tag = FcVStackTest;
7632c393a42Smrg    return FcTrue;
7642c393a42Smrg}
7652c393a42Smrg
7662c393a42Smrgstatic FcBool
7672c393a42SmrgFcVStackPushExpr (FcConfigParse *parse, FcVStackTag tag, FcExpr *expr)
7682c393a42Smrg{
769a6844aabSmrg    FcVStack    *vstack = FcVStackCreateAndPush (parse);
7702c393a42Smrg    if (!vstack)
7712c393a42Smrg	return FcFalse;
7722c393a42Smrg    vstack->u.expr = expr;
7732c393a42Smrg    vstack->tag = tag;
7742c393a42Smrg    return FcTrue;
7752c393a42Smrg}
7762c393a42Smrg
7772c393a42Smrgstatic FcBool
7782c393a42SmrgFcVStackPushEdit (FcConfigParse *parse, FcEdit *edit)
7792c393a42Smrg{
780a6844aabSmrg    FcVStack    *vstack = FcVStackCreateAndPush (parse);
7812c393a42Smrg    if (!vstack)
7822c393a42Smrg	return FcFalse;
7832c393a42Smrg    vstack->u.edit = edit;
7842c393a42Smrg    vstack->tag = FcVStackEdit;
7852c393a42Smrg    return FcTrue;
7862c393a42Smrg}
7872c393a42Smrg
7882c393a42Smrgstatic FcBool
7892c393a42SmrgFcVStackPushPattern (FcConfigParse *parse, FcPattern *pattern)
7902c393a42Smrg{
791a6844aabSmrg    FcVStack    *vstack = FcVStackCreateAndPush (parse);
7922c393a42Smrg    if (!vstack)
7932c393a42Smrg	return FcFalse;
7942c393a42Smrg    vstack->u.pattern = pattern;
7952c393a42Smrg    vstack->tag = FcVStackPattern;
7962c393a42Smrg    return FcTrue;
7972c393a42Smrg}
7982c393a42Smrg
7992c393a42Smrgstatic FcVStack *
8002c393a42SmrgFcVStackFetch (FcConfigParse *parse, int off)
8012c393a42Smrg{
8022c393a42Smrg    FcVStack    *vstack;
8032c393a42Smrg
8042c393a42Smrg    for (vstack = parse->vstack; vstack && off-- > 0; vstack = vstack->prev);
8052c393a42Smrg    return vstack;
8062c393a42Smrg}
8072c393a42Smrg
808a6844aabSmrgstatic FcVStack *
809a6844aabSmrgFcVStackPeek (FcConfigParse *parse)
8102c393a42Smrg{
811a6844aabSmrg    FcVStack	*vstack = parse->vstack;
812a6844aabSmrg
813a6844aabSmrg    return vstack && vstack->pstack == parse->pstack ? vstack : 0;
8142c393a42Smrg}
8152c393a42Smrg
816a6844aabSmrgstatic void
817a6844aabSmrgFcVStackPopAndDestroy (FcConfigParse *parse)
8182c393a42Smrg{
8192c393a42Smrg    FcVStack	*vstack = parse->vstack;
8202c393a42Smrg
8212c393a42Smrg    if (!vstack || vstack->pstack != parse->pstack)
822a6844aabSmrg	return;
823a6844aabSmrg
8242c393a42Smrg    parse->vstack = vstack->prev;
825a6844aabSmrg
826a6844aabSmrg    switch (vstack->tag) {
827a6844aabSmrg    case FcVStackNone:
828a6844aabSmrg	break;
829a6844aabSmrg    case FcVStackFamily:
830a6844aabSmrg	break;
831a6844aabSmrg    case FcVStackString:
832a6844aabSmrg    case FcVStackField:
833a6844aabSmrg    case FcVStackConstant:
834a6844aabSmrg    case FcVStackGlob:
835a6844aabSmrg	FcStrFree (vstack->u.string);
836a6844aabSmrg	break;
837a6844aabSmrg    case FcVStackPattern:
838a6844aabSmrg	FcPatternDestroy (vstack->u.pattern);
839a6844aabSmrg	break;
840a6844aabSmrg    case FcVStackInteger:
841a6844aabSmrg    case FcVStackDouble:
842a6844aabSmrg	break;
843a6844aabSmrg    case FcVStackMatrix:
844a6844aabSmrg	FcMatrixFree (vstack->u.matrix);
845a6844aabSmrg	break;
846a6844aabSmrg    case FcVStackBool:
847a6844aabSmrg	break;
848a6844aabSmrg    case FcVStackTest:
849a6844aabSmrg	FcTestDestroy (vstack->u.test);
850a6844aabSmrg	break;
851a6844aabSmrg    case FcVStackExpr:
852a6844aabSmrg    case FcVStackPrefer:
853a6844aabSmrg    case FcVStackAccept:
854a6844aabSmrg    case FcVStackDefault:
855a6844aabSmrg	FcExprDestroy (vstack->u.expr);
856a6844aabSmrg	break;
857a6844aabSmrg    case FcVStackEdit:
858a6844aabSmrg	FcEditDestroy (vstack->u.edit);
859a6844aabSmrg	break;
860a6844aabSmrg    }
861a6844aabSmrg
862a6844aabSmrg    if (vstack == &parse->vstack_static[parse->vstack_static_used - 1])
863a6844aabSmrg	parse->vstack_static_used--;
864a6844aabSmrg    else
865a6844aabSmrg    {
866a6844aabSmrg	FcMemFree (FC_MEM_VSTACK, sizeof (FcVStack));
867a6844aabSmrg	free (vstack);
868a6844aabSmrg    }
869a6844aabSmrg}
870a6844aabSmrg
871a6844aabSmrgstatic void
872a6844aabSmrgFcVStackClear (FcConfigParse *parse)
873a6844aabSmrg{
874a6844aabSmrg    while (FcVStackPeek (parse))
875a6844aabSmrg	FcVStackPopAndDestroy (parse);
8762c393a42Smrg}
8772c393a42Smrg
8782c393a42Smrgstatic int
8792c393a42SmrgFcVStackElements (FcConfigParse *parse)
8802c393a42Smrg{
8812c393a42Smrg    int		h = 0;
8822c393a42Smrg    FcVStack	*vstack = parse->vstack;
8832c393a42Smrg    while (vstack && vstack->pstack == parse->pstack)
8842c393a42Smrg    {
8852c393a42Smrg	h++;
8862c393a42Smrg	vstack = vstack->prev;
8872c393a42Smrg    }
8882c393a42Smrg    return h;
8892c393a42Smrg}
8902c393a42Smrg
8912c393a42Smrgstatic FcChar8 **
892a6844aabSmrgFcConfigSaveAttr (const XML_Char **attr, FcChar8 **buf, int size_bytes)
8932c393a42Smrg{
8942c393a42Smrg    int		slen;
8952c393a42Smrg    int		i;
8962c393a42Smrg    FcChar8	**new;
8972c393a42Smrg    FcChar8	*s;
8982c393a42Smrg
8992c393a42Smrg    if (!attr)
9002c393a42Smrg	return 0;
9012c393a42Smrg    slen = 0;
9022c393a42Smrg    for (i = 0; attr[i]; i++)
9032c393a42Smrg	slen += strlen ((char *) attr[i]) + 1;
904a6844aabSmrg    if (i == 0)
9052c393a42Smrg	return 0;
906a6844aabSmrg    slen += (i + 1) * sizeof (FcChar8 *);
907a6844aabSmrg    if (slen <= size_bytes)
908a6844aabSmrg	new = buf;
909a6844aabSmrg    else
910a6844aabSmrg    {
911a6844aabSmrg	new = malloc (slen);
912a6844aabSmrg	if (!new)
913a6844aabSmrg	{
914a6844aabSmrg	    FcConfigMessage (0, FcSevereError, "out of memory");
915a6844aabSmrg	    return 0;
916a6844aabSmrg	}
917a6844aabSmrg	FcMemAlloc (FC_MEM_ATTR, 1);    /* size is too expensive */
918a6844aabSmrg    }
9192c393a42Smrg    s = (FcChar8 *) (new + (i + 1));
9202c393a42Smrg    for (i = 0; attr[i]; i++)
9212c393a42Smrg    {
9222c393a42Smrg	new[i] = s;
9232c393a42Smrg	strcpy ((char *) s, (char *) attr[i]);
9242c393a42Smrg	s += strlen ((char *) s) + 1;
9252c393a42Smrg    }
9262c393a42Smrg    new[i] = 0;
9272c393a42Smrg    return new;
9282c393a42Smrg}
9292c393a42Smrg
9302c393a42Smrgstatic FcBool
9312c393a42SmrgFcPStackPush (FcConfigParse *parse, FcElement element, const XML_Char **attr)
9322c393a42Smrg{
933a6844aabSmrg    FcPStack   *new;
9342c393a42Smrg
935a6844aabSmrg    if (parse->pstack_static_used < sizeof (parse->pstack_static) / sizeof (parse->pstack_static[0]))
936a6844aabSmrg	new = &parse->pstack_static[parse->pstack_static_used++];
937a6844aabSmrg    else
9382c393a42Smrg    {
939a6844aabSmrg	new = malloc (sizeof (FcPStack));
940a6844aabSmrg	if (!new)
9412c393a42Smrg	    return FcFalse;
942a6844aabSmrg	FcMemAlloc (FC_MEM_PSTACK, sizeof (FcPStack));
9432c393a42Smrg    }
944a6844aabSmrg
945a6844aabSmrg    new->prev = parse->pstack;
946a6844aabSmrg    new->element = element;
947a6844aabSmrg    new->attr = FcConfigSaveAttr (attr, new->attr_buf_static, sizeof (new->attr_buf_static));
9482c393a42Smrg    FcStrBufInit (&new->str, 0, 0);
9492c393a42Smrg    parse->pstack = new;
9502c393a42Smrg    return FcTrue;
9512c393a42Smrg}
9522c393a42Smrg
9532c393a42Smrgstatic FcBool
9542c393a42SmrgFcPStackPop (FcConfigParse *parse)
9552c393a42Smrg{
9562c393a42Smrg    FcPStack   *old;
9572c393a42Smrg
9582c393a42Smrg    if (!parse->pstack)
9592c393a42Smrg    {
9602c393a42Smrg	FcConfigMessage (parse, FcSevereError, "mismatching element");
9612c393a42Smrg	return FcFalse;
9622c393a42Smrg    }
9632c393a42Smrg    FcVStackClear (parse);
9642c393a42Smrg    old = parse->pstack;
9652c393a42Smrg    parse->pstack = old->prev;
9662c393a42Smrg    FcStrBufDestroy (&old->str);
967a6844aabSmrg    if (old->attr && old->attr != old->attr_buf_static)
9682c393a42Smrg    {
9692c393a42Smrg	FcMemFree (FC_MEM_ATTR, 1); /* size is to expensive */
9702c393a42Smrg	free (old->attr);
9712c393a42Smrg    }
972a6844aabSmrg
973a6844aabSmrg    if (old == &parse->pstack_static[parse->pstack_static_used - 1])
974a6844aabSmrg	parse->pstack_static_used--;
975a6844aabSmrg    else
976a6844aabSmrg    {
977a6844aabSmrg	FcMemFree (FC_MEM_PSTACK, sizeof (FcPStack));
978a6844aabSmrg	free (old);
979a6844aabSmrg    }
9802c393a42Smrg    return FcTrue;
9812c393a42Smrg}
9822c393a42Smrg
9832c393a42Smrgstatic FcBool
9842c393a42SmrgFcConfigInit (FcConfigParse *parse, const FcChar8 *name, FcConfig *config, XML_Parser parser)
9852c393a42Smrg{
9862c393a42Smrg    parse->pstack = 0;
987a6844aabSmrg    parse->pstack_static_used = 0;
9882c393a42Smrg    parse->vstack = 0;
989a6844aabSmrg    parse->vstack_static_used = 0;
9902c393a42Smrg    parse->error = FcFalse;
9912c393a42Smrg    parse->name = name;
9922c393a42Smrg    parse->config = config;
9932c393a42Smrg    parse->parser = parser;
9942c393a42Smrg    return FcTrue;
9952c393a42Smrg}
9962c393a42Smrg
9972c393a42Smrgstatic void
9982c393a42SmrgFcConfigCleanup (FcConfigParse	*parse)
9992c393a42Smrg{
10002c393a42Smrg    while (parse->pstack)
10012c393a42Smrg	FcPStackPop (parse);
10022c393a42Smrg}
10032c393a42Smrg
10042c393a42Smrgstatic const FcChar8 *
10052c393a42SmrgFcConfigGetAttribute (FcConfigParse *parse, const char *attr)
10062c393a42Smrg{
10072c393a42Smrg    FcChar8 **attrs;
10082c393a42Smrg    if (!parse->pstack)
10092c393a42Smrg	return 0;
10102c393a42Smrg
10112c393a42Smrg    attrs = parse->pstack->attr;
10122c393a42Smrg    if (!attrs)
10132c393a42Smrg        return 0;
10142c393a42Smrg
10152c393a42Smrg    while (*attrs)
10162c393a42Smrg    {
10172c393a42Smrg	if (!strcmp ((char *) *attrs, attr))
10182c393a42Smrg	    return attrs[1];
10192c393a42Smrg	attrs += 2;
10202c393a42Smrg    }
10212c393a42Smrg    return 0;
10222c393a42Smrg}
10232c393a42Smrg
10242c393a42Smrgstatic void
10252c393a42SmrgFcStartElement(void *userData, const XML_Char *name, const XML_Char **attr)
10262c393a42Smrg{
10272c393a42Smrg    FcConfigParse   *parse = userData;
10282c393a42Smrg    FcElement	    element;
10292c393a42Smrg
10302c393a42Smrg    element = FcElementMap (name);
10312c393a42Smrg    if (element == FcElementUnknown)
10322c393a42Smrg	FcConfigMessage (parse, FcSevereWarning, "unknown element \"%s\"", name);
10332c393a42Smrg
10342c393a42Smrg    if (!FcPStackPush (parse, element, attr))
10352c393a42Smrg    {
10362c393a42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
10372c393a42Smrg	return;
10382c393a42Smrg    }
10392c393a42Smrg    return;
10402c393a42Smrg}
10412c393a42Smrg
10422c393a42Smrgstatic void
10432c393a42SmrgFcParseBlank (FcConfigParse *parse)
10442c393a42Smrg{
10452c393a42Smrg    int	    n = FcVStackElements (parse);
10462c393a42Smrg    while (n-- > 0)
10472c393a42Smrg    {
10482c393a42Smrg	FcVStack    *v = FcVStackFetch (parse, n);
10492c393a42Smrg	if (v->tag != FcVStackInteger)
10502c393a42Smrg	    FcConfigMessage (parse, FcSevereError, "non-integer blank");
10512c393a42Smrg	else
10522c393a42Smrg	{
10532c393a42Smrg	    if (!parse->config->blanks)
10542c393a42Smrg	    {
10552c393a42Smrg		parse->config->blanks = FcBlanksCreate ();
10562c393a42Smrg		if (!parse->config->blanks)
10572c393a42Smrg		{
10582c393a42Smrg		    FcConfigMessage (parse, FcSevereError, "out of memory");
10592c393a42Smrg		    break;
10602c393a42Smrg		}
10612c393a42Smrg	    }
10622c393a42Smrg	    if (!FcBlanksAdd (parse->config->blanks, v->u.integer))
10632c393a42Smrg	    {
10642c393a42Smrg		FcConfigMessage (parse, FcSevereError, "out of memory");
10652c393a42Smrg		break;
10662c393a42Smrg	    }
10672c393a42Smrg	}
10682c393a42Smrg    }
10692c393a42Smrg}
10702c393a42Smrg
10712c393a42Smrgstatic void
10722c393a42SmrgFcParseRescan (FcConfigParse *parse)
10732c393a42Smrg{
10742c393a42Smrg    int	    n = FcVStackElements (parse);
10752c393a42Smrg    while (n-- > 0)
10762c393a42Smrg    {
10772c393a42Smrg	FcVStack    *v = FcVStackFetch (parse, n);
10782c393a42Smrg	if (v->tag != FcVStackInteger)
10792c393a42Smrg	    FcConfigMessage (parse, FcSevereWarning, "non-integer rescan");
10802c393a42Smrg	else
10812c393a42Smrg	    parse->config->rescanInterval = v->u.integer;
10822c393a42Smrg    }
10832c393a42Smrg}
10842c393a42Smrg
10852c393a42Smrgstatic void
10862c393a42SmrgFcParseInt (FcConfigParse *parse)
10872c393a42Smrg{
10882c393a42Smrg    FcChar8 *s, *end;
10892c393a42Smrg    int	    l;
10902c393a42Smrg
10912c393a42Smrg    if (!parse->pstack)
10922c393a42Smrg	return;
1093a6844aabSmrg    s = FcStrBufDoneStatic (&parse->pstack->str);
10942c393a42Smrg    if (!s)
10952c393a42Smrg    {
10962c393a42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
10972c393a42Smrg	return;
10982c393a42Smrg    }
10992c393a42Smrg    end = 0;
11002c393a42Smrg    l = (int) strtol ((char *) s, (char **)&end, 0);
11012c393a42Smrg    if (end != s + strlen ((char *) s))
11022c393a42Smrg	FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid integer", s);
11032c393a42Smrg    else
11042c393a42Smrg	FcVStackPushInteger (parse, l);
1105a6844aabSmrg    FcStrBufDestroy (&parse->pstack->str);
11062c393a42Smrg}
11072c393a42Smrg
11082c393a42Smrg/*
11092c393a42Smrg * idea copied from glib g_ascii_strtod with
11102c393a42Smrg * permission of the author (Alexander Larsson)
11112c393a42Smrg */
11122c393a42Smrg
11132c393a42Smrg#include <locale.h>
11142c393a42Smrg
11152c393a42Smrgstatic double
11162c393a42SmrgFcStrtod (char *s, char **end)
11172c393a42Smrg{
11182c393a42Smrg    struct lconv    *locale_data;
11192c393a42Smrg    char	    *dot;
11202c393a42Smrg    double	    v;
11212c393a42Smrg
11222c393a42Smrg    /*
11232c393a42Smrg     * Have to swap the decimal point to match the current locale
11242c393a42Smrg     * if that locale doesn't use 0x2e
11252c393a42Smrg     */
11262c393a42Smrg    if ((dot = strchr (s, 0x2e)) &&
11272c393a42Smrg	(locale_data = localeconv ()) &&
11282c393a42Smrg	(locale_data->decimal_point[0] != 0x2e ||
11292c393a42Smrg	 locale_data->decimal_point[1] != 0))
11302c393a42Smrg    {
11312c393a42Smrg	char	buf[128];
11322c393a42Smrg	int	slen = strlen (s);
11332c393a42Smrg	int	dlen = strlen (locale_data->decimal_point);
11342c393a42Smrg
11352c393a42Smrg	if (slen + dlen > (int) sizeof (buf))
11362c393a42Smrg	{
11372c393a42Smrg	    if (end)
11382c393a42Smrg		*end = s;
11392c393a42Smrg	    v = 0;
11402c393a42Smrg	}
11412c393a42Smrg	else
11422c393a42Smrg	{
11432c393a42Smrg	    char	*buf_end;
11442c393a42Smrg	    /* mantissa */
11452c393a42Smrg	    strncpy (buf, s, dot - s);
11462c393a42Smrg	    /* decimal point */
11472c393a42Smrg	    strcpy (buf + (dot - s), locale_data->decimal_point);
11482c393a42Smrg	    /* rest of number */
11492c393a42Smrg	    strcpy (buf + (dot - s) + dlen, dot + 1);
11502c393a42Smrg	    buf_end = 0;
11512c393a42Smrg	    v = strtod (buf, &buf_end);
11522c393a42Smrg	    if (buf_end) {
11532c393a42Smrg		buf_end = s + (buf_end - buf);
11542c393a42Smrg		if (buf_end > dot)
11552c393a42Smrg		    buf_end -= dlen - 1;
11562c393a42Smrg	    }
11572c393a42Smrg	    if (end)
11582c393a42Smrg		*end = buf_end;
11592c393a42Smrg	}
11602c393a42Smrg    }
11612c393a42Smrg    else
11622c393a42Smrg	v = strtod (s, end);
11632c393a42Smrg    return v;
11642c393a42Smrg}
11652c393a42Smrg
11662c393a42Smrgstatic void
11672c393a42SmrgFcParseDouble (FcConfigParse *parse)
11682c393a42Smrg{
11692c393a42Smrg    FcChar8 *s, *end;
11702c393a42Smrg    double  d;
11712c393a42Smrg
11722c393a42Smrg    if (!parse->pstack)
11732c393a42Smrg	return;
1174a6844aabSmrg    s = FcStrBufDoneStatic (&parse->pstack->str);
11752c393a42Smrg    if (!s)
11762c393a42Smrg    {
11772c393a42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
11782c393a42Smrg	return;
11792c393a42Smrg    }
11802c393a42Smrg    end = 0;
11812c393a42Smrg    d = FcStrtod ((char *) s, (char **)&end);
11822c393a42Smrg    if (end != s + strlen ((char *) s))
11832c393a42Smrg	FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid double", s);
11842c393a42Smrg    else
11852c393a42Smrg	FcVStackPushDouble (parse, d);
1186a6844aabSmrg    FcStrBufDestroy (&parse->pstack->str);
11872c393a42Smrg}
11882c393a42Smrg
11892c393a42Smrgstatic void
11902c393a42SmrgFcParseString (FcConfigParse *parse, FcVStackTag tag)
11912c393a42Smrg{
11922c393a42Smrg    FcChar8 *s;
11932c393a42Smrg
11942c393a42Smrg    if (!parse->pstack)
11952c393a42Smrg	return;
11962c393a42Smrg    s = FcStrBufDone (&parse->pstack->str);
11972c393a42Smrg    if (!s)
11982c393a42Smrg    {
11992c393a42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
12002c393a42Smrg	return;
12012c393a42Smrg    }
12022c393a42Smrg    if (!FcVStackPushString (parse, tag, s))
12032c393a42Smrg	FcStrFree (s);
12042c393a42Smrg}
12052c393a42Smrg
12062c393a42Smrgstatic void
12072c393a42SmrgFcParseMatrix (FcConfigParse *parse)
12082c393a42Smrg{
12092c393a42Smrg    FcVStack	*vstack;
12102c393a42Smrg    enum { m_done, m_xx, m_xy, m_yx, m_yy } matrix_state = m_yy;
12112c393a42Smrg    FcMatrix	m;
12122c393a42Smrg
1213a6844aabSmrg    while ((vstack = FcVStackPeek (parse)))
12142c393a42Smrg    {
12152c393a42Smrg	double	v;
12162c393a42Smrg	switch (vstack->tag) {
12172c393a42Smrg	case FcVStackInteger:
12182c393a42Smrg	    v = vstack->u.integer;
12192c393a42Smrg	    break;
12202c393a42Smrg	case FcVStackDouble:
12212c393a42Smrg	    v = vstack->u._double;
12222c393a42Smrg	    break;
12232c393a42Smrg	default:
12242c393a42Smrg	    FcConfigMessage (parse, FcSevereError, "non-double matrix element");
12252c393a42Smrg	    v = 1.0;
12262c393a42Smrg	    break;
12272c393a42Smrg	}
12282c393a42Smrg	switch (matrix_state) {
12292c393a42Smrg	case m_xx: m.xx = v; break;
12302c393a42Smrg	case m_xy: m.xy = v; break;
12312c393a42Smrg	case m_yx: m.yx = v; break;
12322c393a42Smrg	case m_yy: m.yy = v; break;
12332c393a42Smrg	default: break;
12342c393a42Smrg	}
1235a6844aabSmrg	FcVStackPopAndDestroy (parse);
12362c393a42Smrg	matrix_state--;
12372c393a42Smrg    }
12382c393a42Smrg    if (matrix_state != m_done)
12392c393a42Smrg	FcConfigMessage (parse, FcSevereError, "wrong number of matrix elements");
12402c393a42Smrg    else
12412c393a42Smrg	FcVStackPushMatrix (parse, &m);
12422c393a42Smrg}
12432c393a42Smrg
12442c393a42Smrgstatic FcBool
1245a6844aabSmrgFcConfigLexBool (FcConfigParse *parse, const FcChar8 *bool_)
12462c393a42Smrg{
12472c393a42Smrg    FcBool  result = FcFalse;
12482c393a42Smrg
1249a6844aabSmrg    if (!FcNameBool (bool_, &result))
12502c393a42Smrg	FcConfigMessage (parse, FcSevereWarning, "\"%s\" is not known boolean",
1251a6844aabSmrg			 bool_);
12522c393a42Smrg    return result;
12532c393a42Smrg}
12542c393a42Smrg
12552c393a42Smrgstatic void
12562c393a42SmrgFcParseBool (FcConfigParse *parse)
12572c393a42Smrg{
12582c393a42Smrg    FcChar8 *s;
12592c393a42Smrg
12602c393a42Smrg    if (!parse->pstack)
12612c393a42Smrg	return;
1262a6844aabSmrg    s = FcStrBufDoneStatic (&parse->pstack->str);
12632c393a42Smrg    if (!s)
12642c393a42Smrg    {
12652c393a42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
12662c393a42Smrg	return;
12672c393a42Smrg    }
12682c393a42Smrg    FcVStackPushBool (parse, FcConfigLexBool (parse, s));
1269a6844aabSmrg    FcStrBufDestroy (&parse->pstack->str);
12702c393a42Smrg}
12712c393a42Smrg
12722c393a42Smrgstatic FcBool
12732c393a42SmrgFcConfigLexBinding (FcConfigParse   *parse,
12742c393a42Smrg		    const FcChar8   *binding_string,
12752c393a42Smrg		    FcValueBinding  *binding_ret)
12762c393a42Smrg{
12772c393a42Smrg    FcValueBinding binding;
12782c393a42Smrg
12792c393a42Smrg    if (!binding_string)
12802c393a42Smrg	binding = FcValueBindingWeak;
12812c393a42Smrg    else
12822c393a42Smrg    {
12832c393a42Smrg	if (!strcmp ((char *) binding_string, "weak"))
12842c393a42Smrg	    binding = FcValueBindingWeak;
12852c393a42Smrg	else if (!strcmp ((char *) binding_string, "strong"))
12862c393a42Smrg	    binding = FcValueBindingStrong;
12872c393a42Smrg	else if (!strcmp ((char *) binding_string, "same"))
12882c393a42Smrg	    binding = FcValueBindingSame;
12892c393a42Smrg	else
12902c393a42Smrg	{
12912c393a42Smrg	    FcConfigMessage (parse, FcSevereWarning, "invalid binding \"%s\"", binding_string);
12922c393a42Smrg	    return FcFalse;
12932c393a42Smrg	}
12942c393a42Smrg    }
12952c393a42Smrg    *binding_ret = binding;
12962c393a42Smrg    return FcTrue;
12972c393a42Smrg}
12982c393a42Smrg
12992c393a42Smrgstatic void
13002c393a42SmrgFcParseFamilies (FcConfigParse *parse, FcVStackTag tag)
13012c393a42Smrg{
13022c393a42Smrg    FcVStack	*vstack;
13032c393a42Smrg    FcExpr	*left, *expr = 0, *new;
13042c393a42Smrg
1305a6844aabSmrg    while ((vstack = FcVStackPeek (parse)))
13062c393a42Smrg    {
13072c393a42Smrg	if (vstack->tag != FcVStackFamily)
13082c393a42Smrg	{
13092c393a42Smrg	    FcConfigMessage (parse, FcSevereWarning, "non-family");
1310a6844aabSmrg	    FcVStackPopAndDestroy (parse);
13112c393a42Smrg	    continue;
13122c393a42Smrg	}
13132c393a42Smrg	left = vstack->u.expr;
13142c393a42Smrg	vstack->tag = FcVStackNone;
1315a6844aabSmrg	FcVStackPopAndDestroy (parse);
13162c393a42Smrg	if (expr)
13172c393a42Smrg	{
1318a6844aabSmrg	    new = FcExprCreateOp (parse->config, left, FcOpComma, expr);
13192c393a42Smrg	    if (!new)
13202c393a42Smrg	    {
13212c393a42Smrg		FcConfigMessage (parse, FcSevereError, "out of memory");
13222c393a42Smrg		FcExprDestroy (left);
13232c393a42Smrg		FcExprDestroy (expr);
13242c393a42Smrg		break;
13252c393a42Smrg	    }
13262c393a42Smrg	    expr = new;
13272c393a42Smrg	}
13282c393a42Smrg	else
13292c393a42Smrg	    expr = left;
13302c393a42Smrg    }
13312c393a42Smrg    if (expr)
13322c393a42Smrg    {
13332c393a42Smrg	if (!FcVStackPushExpr (parse, tag, expr))
13342c393a42Smrg	{
13352c393a42Smrg	    FcConfigMessage (parse, FcSevereError, "out of memory");
13362c393a42Smrg            FcExprDestroy (expr);
13372c393a42Smrg	}
13382c393a42Smrg    }
13392c393a42Smrg}
13402c393a42Smrg
13412c393a42Smrgstatic void
13422c393a42SmrgFcParseFamily (FcConfigParse *parse)
13432c393a42Smrg{
13442c393a42Smrg    FcChar8 *s;
13452c393a42Smrg    FcExpr  *expr;
13462c393a42Smrg
13472c393a42Smrg    if (!parse->pstack)
13482c393a42Smrg	return;
1349a6844aabSmrg    s = FcStrBufDoneStatic (&parse->pstack->str);
13502c393a42Smrg    if (!s)
13512c393a42Smrg    {
13522c393a42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
13532c393a42Smrg	return;
13542c393a42Smrg    }
1355a6844aabSmrg    expr = FcExprCreateString (parse->config, s);
1356a6844aabSmrg    FcStrBufDestroy (&parse->pstack->str);
13572c393a42Smrg    if (expr)
13582c393a42Smrg	FcVStackPushExpr (parse, FcVStackFamily, expr);
13592c393a42Smrg}
13602c393a42Smrg
13612c393a42Smrgstatic void
13622c393a42SmrgFcParseAlias (FcConfigParse *parse)
13632c393a42Smrg{
13642c393a42Smrg    FcExpr	*family = 0, *accept = 0, *prefer = 0, *def = 0, *new = 0;
13652c393a42Smrg    FcEdit	*edit = 0, *next;
13662c393a42Smrg    FcVStack	*vstack;
13672c393a42Smrg    FcTest	*test;
13682c393a42Smrg    FcValueBinding  binding;
13692c393a42Smrg
13702c393a42Smrg    if (!FcConfigLexBinding (parse, FcConfigGetAttribute (parse, "binding"), &binding))
13712c393a42Smrg	return;
1372a6844aabSmrg    while ((vstack = FcVStackPeek (parse)))
13732c393a42Smrg    {
13742c393a42Smrg	switch (vstack->tag) {
13752c393a42Smrg	case FcVStackFamily:
13762c393a42Smrg	    if (family)
13772c393a42Smrg	    {
1378a6844aabSmrg		new = FcExprCreateOp (parse->config, vstack->u.expr, FcOpComma, family);
13792c393a42Smrg		if (!new)
13802c393a42Smrg		    FcConfigMessage (parse, FcSevereError, "out of memory");
13812c393a42Smrg		else
13822c393a42Smrg		    family = new;
13832c393a42Smrg	    }
13842c393a42Smrg	    else
13852c393a42Smrg		new = vstack->u.expr;
13862c393a42Smrg	    if (new)
13872c393a42Smrg	    {
13882c393a42Smrg		family = new;
13892c393a42Smrg		vstack->tag = FcVStackNone;
13902c393a42Smrg	    }
13912c393a42Smrg	    break;
13922c393a42Smrg	case FcVStackPrefer:
13932c393a42Smrg	    if (prefer)
13942c393a42Smrg		FcExprDestroy (prefer);
13952c393a42Smrg	    prefer = vstack->u.expr;
13962c393a42Smrg	    vstack->tag = FcVStackNone;
13972c393a42Smrg	    break;
13982c393a42Smrg	case FcVStackAccept:
13992c393a42Smrg	    if (accept)
14002c393a42Smrg		FcExprDestroy (accept);
14012c393a42Smrg	    accept = vstack->u.expr;
14022c393a42Smrg	    vstack->tag = FcVStackNone;
14032c393a42Smrg	    break;
14042c393a42Smrg	case FcVStackDefault:
14052c393a42Smrg	    if (def)
14062c393a42Smrg		FcExprDestroy (def);
14072c393a42Smrg	    def = vstack->u.expr;
14082c393a42Smrg	    vstack->tag = FcVStackNone;
14092c393a42Smrg	    break;
14102c393a42Smrg	default:
14112c393a42Smrg	    FcConfigMessage (parse, FcSevereWarning, "bad alias");
14122c393a42Smrg	    break;
14132c393a42Smrg	}
1414a6844aabSmrg	FcVStackPopAndDestroy (parse);
14152c393a42Smrg    }
14162c393a42Smrg    if (!family)
14172c393a42Smrg    {
14182c393a42Smrg	FcConfigMessage (parse, FcSevereError, "missing family in alias");
14192c393a42Smrg	if (prefer)
14202c393a42Smrg	    FcExprDestroy (prefer);
14212c393a42Smrg	if (accept)
14222c393a42Smrg	    FcExprDestroy (accept);
14232c393a42Smrg	if (def)
14242c393a42Smrg	    FcExprDestroy (def);
14252c393a42Smrg	return;
14262c393a42Smrg    }
14272c393a42Smrg    if (prefer)
14282c393a42Smrg    {
14292c393a42Smrg	edit = FcEditCreate (parse,
14302c393a42Smrg			     FC_FAMILY_OBJECT,
14312c393a42Smrg			     FcOpPrepend,
14322c393a42Smrg			     prefer,
14332c393a42Smrg			     binding);
14342c393a42Smrg	if (edit)
14352c393a42Smrg	    edit->next = 0;
14362c393a42Smrg	else
14372c393a42Smrg	    FcExprDestroy (prefer);
14382c393a42Smrg    }
14392c393a42Smrg    if (accept)
14402c393a42Smrg    {
14412c393a42Smrg	next = edit;
14422c393a42Smrg	edit = FcEditCreate (parse,
14432c393a42Smrg			     FC_FAMILY_OBJECT,
14442c393a42Smrg			     FcOpAppend,
14452c393a42Smrg			     accept,
14462c393a42Smrg			     binding);
14472c393a42Smrg	if (edit)
14482c393a42Smrg	    edit->next = next;
14492c393a42Smrg	else
14502c393a42Smrg	    FcExprDestroy (accept);
14512c393a42Smrg    }
14522c393a42Smrg    if (def)
14532c393a42Smrg    {
14542c393a42Smrg	next = edit;
14552c393a42Smrg	edit = FcEditCreate (parse,
14562c393a42Smrg			     FC_FAMILY_OBJECT,
14572c393a42Smrg			     FcOpAppendLast,
14582c393a42Smrg			     def,
14592c393a42Smrg			     binding);
14602c393a42Smrg	if (edit)
14612c393a42Smrg	    edit->next = next;
14622c393a42Smrg	else
14632c393a42Smrg	    FcExprDestroy (def);
14642c393a42Smrg    }
14652c393a42Smrg    if (edit)
14662c393a42Smrg    {
14672c393a42Smrg	test = FcTestCreate (parse, FcMatchPattern,
14682c393a42Smrg			     FcQualAny,
14692c393a42Smrg			     (FcChar8 *) FC_FAMILY,
14702c393a42Smrg			     FcOpEqual,
14712c393a42Smrg			     family);
14722c393a42Smrg	if (test)
14732c393a42Smrg	    if (!FcConfigAddEdit (parse->config, test, edit, FcMatchPattern))
14742c393a42Smrg		FcTestDestroy (test);
14752c393a42Smrg    }
14762c393a42Smrg    else
14772c393a42Smrg	FcExprDestroy (family);
14782c393a42Smrg}
14792c393a42Smrg
14802c393a42Smrgstatic FcExpr *
14812c393a42SmrgFcPopExpr (FcConfigParse *parse)
14822c393a42Smrg{
1483a6844aabSmrg    FcVStack	*vstack = FcVStackPeek (parse);
14842c393a42Smrg    FcExpr	*expr = 0;
14852c393a42Smrg    if (!vstack)
14862c393a42Smrg	return 0;
14872c393a42Smrg    switch (vstack->tag) {
14882c393a42Smrg    case FcVStackNone:
14892c393a42Smrg	break;
14902c393a42Smrg    case FcVStackString:
14912c393a42Smrg    case FcVStackFamily:
1492a6844aabSmrg	expr = FcExprCreateString (parse->config, vstack->u.string);
14932c393a42Smrg	break;
14942c393a42Smrg    case FcVStackField:
1495a6844aabSmrg	expr = FcExprCreateField (parse->config, (char *) vstack->u.string);
14962c393a42Smrg	break;
14972c393a42Smrg    case FcVStackConstant:
1498a6844aabSmrg	expr = FcExprCreateConst (parse->config, vstack->u.string);
14992c393a42Smrg	break;
15002c393a42Smrg    case FcVStackGlob:
15012c393a42Smrg	/* XXX: What's the correct action here? (CDW) */
15022c393a42Smrg	break;
15032c393a42Smrg    case FcVStackPrefer:
15042c393a42Smrg    case FcVStackAccept:
15052c393a42Smrg    case FcVStackDefault:
15062c393a42Smrg	expr = vstack->u.expr;
15072c393a42Smrg	vstack->tag = FcVStackNone;
15082c393a42Smrg	break;
15092c393a42Smrg    case FcVStackInteger:
1510a6844aabSmrg	expr = FcExprCreateInteger (parse->config, vstack->u.integer);
15112c393a42Smrg	break;
15122c393a42Smrg    case FcVStackDouble:
1513a6844aabSmrg	expr = FcExprCreateDouble (parse->config, vstack->u._double);
15142c393a42Smrg	break;
15152c393a42Smrg    case FcVStackMatrix:
1516a6844aabSmrg	expr = FcExprCreateMatrix (parse->config, vstack->u.matrix);
15172c393a42Smrg	break;
15182c393a42Smrg    case FcVStackBool:
1519a6844aabSmrg	expr = FcExprCreateBool (parse->config, vstack->u.bool_);
15202c393a42Smrg	break;
15212c393a42Smrg    case FcVStackTest:
15222c393a42Smrg	break;
15232c393a42Smrg    case FcVStackExpr:
15242c393a42Smrg	expr = vstack->u.expr;
15252c393a42Smrg	vstack->tag = FcVStackNone;
15262c393a42Smrg	break;
15272c393a42Smrg    case FcVStackEdit:
15282c393a42Smrg	break;
15292c393a42Smrg    default:
15302c393a42Smrg	break;
15312c393a42Smrg    }
1532a6844aabSmrg    FcVStackPopAndDestroy (parse);
15332c393a42Smrg    return expr;
15342c393a42Smrg}
15352c393a42Smrg
15362c393a42Smrg/*
15372c393a42Smrg * This builds a tree of binary operations.  Note
15382c393a42Smrg * that every operator is defined so that if only
15392c393a42Smrg * a single operand is contained, the value of the
15402c393a42Smrg * whole expression is the value of the operand.
15412c393a42Smrg *
15422c393a42Smrg * This code reduces in that case to returning that
15432c393a42Smrg * operand.
15442c393a42Smrg */
15452c393a42Smrgstatic FcExpr *
15462c393a42SmrgFcPopBinary (FcConfigParse *parse, FcOp op)
15472c393a42Smrg{
15482c393a42Smrg    FcExpr  *left, *expr = 0, *new;
15492c393a42Smrg
15502c393a42Smrg    while ((left = FcPopExpr (parse)))
15512c393a42Smrg    {
15522c393a42Smrg	if (expr)
15532c393a42Smrg	{
1554a6844aabSmrg	    new = FcExprCreateOp (parse->config, left, op, expr);
15552c393a42Smrg	    if (!new)
15562c393a42Smrg	    {
15572c393a42Smrg		FcConfigMessage (parse, FcSevereError, "out of memory");
15582c393a42Smrg		FcExprDestroy (left);
15592c393a42Smrg		FcExprDestroy (expr);
15602c393a42Smrg		return 0;
15612c393a42Smrg	    }
15622c393a42Smrg	    expr = new;
15632c393a42Smrg	}
15642c393a42Smrg	else
15652c393a42Smrg	    expr = left;
15662c393a42Smrg    }
15672c393a42Smrg    return expr;
15682c393a42Smrg}
15692c393a42Smrg
15702c393a42Smrgstatic void
15712c393a42SmrgFcParseBinary (FcConfigParse *parse, FcOp op)
15722c393a42Smrg{
15732c393a42Smrg    FcExpr  *expr = FcPopBinary (parse, op);
15742c393a42Smrg    if (expr)
15752c393a42Smrg	FcVStackPushExpr (parse, FcVStackExpr, expr);
15762c393a42Smrg}
15772c393a42Smrg
15782c393a42Smrg/*
15792c393a42Smrg * This builds a a unary operator, it consumes only
15802c393a42Smrg * a single operand
15812c393a42Smrg */
15822c393a42Smrg
15832c393a42Smrgstatic FcExpr *
15842c393a42SmrgFcPopUnary (FcConfigParse *parse, FcOp op)
15852c393a42Smrg{
15862c393a42Smrg    FcExpr  *operand, *new = 0;
15872c393a42Smrg
15882c393a42Smrg    if ((operand = FcPopExpr (parse)))
15892c393a42Smrg    {
1590a6844aabSmrg	new = FcExprCreateOp (parse->config, operand, op, 0);
15912c393a42Smrg	if (!new)
15922c393a42Smrg	{
15932c393a42Smrg	    FcExprDestroy (operand);
15942c393a42Smrg	    FcConfigMessage (parse, FcSevereError, "out of memory");
15952c393a42Smrg	}
15962c393a42Smrg    }
15972c393a42Smrg    return new;
15982c393a42Smrg}
15992c393a42Smrg
16002c393a42Smrgstatic void
16012c393a42SmrgFcParseUnary (FcConfigParse *parse, FcOp op)
16022c393a42Smrg{
16032c393a42Smrg    FcExpr  *expr = FcPopUnary (parse, op);
16042c393a42Smrg    if (expr)
16052c393a42Smrg	FcVStackPushExpr (parse, FcVStackExpr, expr);
16062c393a42Smrg}
16072c393a42Smrg
16082c393a42Smrgstatic void
16092c393a42SmrgFcParseInclude (FcConfigParse *parse)
16102c393a42Smrg{
16112c393a42Smrg    FcChar8	    *s;
16122c393a42Smrg    const FcChar8   *i;
16132c393a42Smrg    FcBool	    ignore_missing = FcFalse;
16142c393a42Smrg
1615a6844aabSmrg    s = FcStrBufDoneStatic (&parse->pstack->str);
16162c393a42Smrg    if (!s)
16172c393a42Smrg    {
16182c393a42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
16192c393a42Smrg	return;
16202c393a42Smrg    }
16212c393a42Smrg    i = FcConfigGetAttribute (parse, "ignore_missing");
16222c393a42Smrg    if (i && FcConfigLexBool (parse, (FcChar8 *) i) == FcTrue)
16232c393a42Smrg	ignore_missing = FcTrue;
16242c393a42Smrg    if (!FcConfigParseAndLoad (parse->config, s, !ignore_missing))
16252c393a42Smrg	parse->error = FcTrue;
1626a6844aabSmrg    FcStrBufDestroy (&parse->pstack->str);
16272c393a42Smrg}
16282c393a42Smrg
16292c393a42Smrgtypedef struct _FcOpMap {
16302c393a42Smrg    char    name[16];
16312c393a42Smrg    FcOp    op;
16322c393a42Smrg} FcOpMap;
16332c393a42Smrg
16342c393a42Smrgstatic FcOp
16352c393a42SmrgFcConfigLexOp (const FcChar8 *op, const FcOpMap	*map, int nmap)
16362c393a42Smrg{
16372c393a42Smrg    int	i;
16382c393a42Smrg
16392c393a42Smrg    for (i = 0; i < nmap; i++)
16402c393a42Smrg	if (!strcmp ((char *) op, map[i].name))
16412c393a42Smrg	    return map[i].op;
16422c393a42Smrg    return FcOpInvalid;
16432c393a42Smrg}
16442c393a42Smrg
16452c393a42Smrgstatic const FcOpMap fcCompareOps[] = {
16462c393a42Smrg    { "eq",		FcOpEqual	    },
16472c393a42Smrg    { "not_eq",		FcOpNotEqual	    },
16482c393a42Smrg    { "less",		FcOpLess	    },
16492c393a42Smrg    { "less_eq",	FcOpLessEqual	    },
16502c393a42Smrg    { "more",		FcOpMore	    },
16512c393a42Smrg    { "more_eq",	FcOpMoreEqual	    },
16522c393a42Smrg    { "contains",	FcOpContains	    },
16532c393a42Smrg    { "not_contains",	FcOpNotContains	    }
16542c393a42Smrg};
16552c393a42Smrg
16562c393a42Smrg#define NUM_COMPARE_OPS	(int) (sizeof fcCompareOps / sizeof fcCompareOps[0])
16572c393a42Smrg
16582c393a42Smrgstatic FcOp
16592c393a42SmrgFcConfigLexCompare (const FcChar8 *compare)
16602c393a42Smrg{
16612c393a42Smrg    return FcConfigLexOp (compare, fcCompareOps, NUM_COMPARE_OPS);
16622c393a42Smrg}
16632c393a42Smrg
16642c393a42Smrgstatic void
16652c393a42SmrgFcParseTest (FcConfigParse *parse)
16662c393a42Smrg{
16672c393a42Smrg    const FcChar8   *kind_string;
16682c393a42Smrg    FcMatchKind	    kind;
16692c393a42Smrg    const FcChar8   *qual_string;
16702c393a42Smrg    FcQual	    qual;
16712c393a42Smrg    const FcChar8   *name;
16722c393a42Smrg    const FcChar8   *compare_string;
16732c393a42Smrg    FcOp	    compare;
16742c393a42Smrg    FcExpr	    *expr;
16752c393a42Smrg    FcTest	    *test;
16762c393a42Smrg
16772c393a42Smrg    kind_string = FcConfigGetAttribute (parse, "target");
16782c393a42Smrg    if (!kind_string)
16792c393a42Smrg	kind = FcMatchDefault;
16802c393a42Smrg    else
16812c393a42Smrg    {
16822c393a42Smrg	if (!strcmp ((char *) kind_string, "pattern"))
16832c393a42Smrg	    kind = FcMatchPattern;
16842c393a42Smrg	else if (!strcmp ((char *) kind_string, "font"))
16852c393a42Smrg	    kind = FcMatchFont;
16862c393a42Smrg	else if (!strcmp ((char *) kind_string, "scan"))
16872c393a42Smrg	    kind = FcMatchScan;
16882c393a42Smrg	else if (!strcmp ((char *) kind_string, "default"))
16892c393a42Smrg	    kind = FcMatchDefault;
16902c393a42Smrg	else
16912c393a42Smrg	{
16922c393a42Smrg	    FcConfigMessage (parse, FcSevereWarning, "invalid test target \"%s\"", kind_string);
16932c393a42Smrg	    return;
16942c393a42Smrg	}
16952c393a42Smrg    }
16962c393a42Smrg    qual_string = FcConfigGetAttribute (parse, "qual");
16972c393a42Smrg    if (!qual_string)
16982c393a42Smrg	qual = FcQualAny;
16992c393a42Smrg    else
17002c393a42Smrg    {
17012c393a42Smrg	if (!strcmp ((char *) qual_string, "any"))
17022c393a42Smrg	    qual = FcQualAny;
17032c393a42Smrg	else if (!strcmp ((char *) qual_string, "all"))
17042c393a42Smrg	    qual = FcQualAll;
17052c393a42Smrg	else if (!strcmp ((char *) qual_string, "first"))
17062c393a42Smrg	    qual = FcQualFirst;
17072c393a42Smrg	else if (!strcmp ((char *) qual_string, "not_first"))
17082c393a42Smrg	    qual = FcQualNotFirst;
17092c393a42Smrg	else
17102c393a42Smrg	{
17112c393a42Smrg	    FcConfigMessage (parse, FcSevereWarning, "invalid test qual \"%s\"", qual_string);
17122c393a42Smrg	    return;
17132c393a42Smrg	}
17142c393a42Smrg    }
17152c393a42Smrg    name = FcConfigGetAttribute (parse, "name");
17162c393a42Smrg    if (!name)
17172c393a42Smrg    {
17182c393a42Smrg	FcConfigMessage (parse, FcSevereWarning, "missing test name");
17192c393a42Smrg	return;
17202c393a42Smrg    }
17212c393a42Smrg    compare_string = FcConfigGetAttribute (parse, "compare");
17222c393a42Smrg    if (!compare_string)
17232c393a42Smrg	compare = FcOpEqual;
17242c393a42Smrg    else
17252c393a42Smrg    {
17262c393a42Smrg	compare = FcConfigLexCompare (compare_string);
17272c393a42Smrg	if (compare == FcOpInvalid)
17282c393a42Smrg	{
17292c393a42Smrg	    FcConfigMessage (parse, FcSevereWarning, "invalid test compare \"%s\"", compare_string);
17302c393a42Smrg	    return;
17312c393a42Smrg	}
17322c393a42Smrg    }
17332c393a42Smrg    expr = FcPopBinary (parse, FcOpComma);
17342c393a42Smrg    if (!expr)
17352c393a42Smrg    {
17362c393a42Smrg	FcConfigMessage (parse, FcSevereWarning, "missing test expression");
17372c393a42Smrg	return;
17382c393a42Smrg    }
17392c393a42Smrg    test = FcTestCreate (parse, kind, qual, name, compare, expr);
17402c393a42Smrg    if (!test)
17412c393a42Smrg    {
17422c393a42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
17432c393a42Smrg	return;
17442c393a42Smrg    }
17452c393a42Smrg    FcVStackPushTest (parse, test);
17462c393a42Smrg}
17472c393a42Smrg
17482c393a42Smrgstatic const FcOpMap fcModeOps[] = {
17492c393a42Smrg    { "assign",		FcOpAssign	    },
17502c393a42Smrg    { "assign_replace",	FcOpAssignReplace   },
17512c393a42Smrg    { "prepend",	FcOpPrepend	    },
17522c393a42Smrg    { "prepend_first",	FcOpPrependFirst    },
17532c393a42Smrg    { "append",		FcOpAppend	    },
17542c393a42Smrg    { "append_last",	FcOpAppendLast	    },
17552c393a42Smrg};
17562c393a42Smrg
17572c393a42Smrg#define NUM_MODE_OPS (int) (sizeof fcModeOps / sizeof fcModeOps[0])
17582c393a42Smrg
17592c393a42Smrgstatic FcOp
17602c393a42SmrgFcConfigLexMode (const FcChar8 *mode)
17612c393a42Smrg{
17622c393a42Smrg    return FcConfigLexOp (mode, fcModeOps, NUM_MODE_OPS);
17632c393a42Smrg}
17642c393a42Smrg
17652c393a42Smrgstatic void
17662c393a42SmrgFcParseEdit (FcConfigParse *parse)
17672c393a42Smrg{
17682c393a42Smrg    const FcChar8   *name;
17692c393a42Smrg    const FcChar8   *mode_string;
17702c393a42Smrg    FcOp	    mode;
17712c393a42Smrg    FcValueBinding  binding;
17722c393a42Smrg    FcExpr	    *expr;
17732c393a42Smrg    FcEdit	    *edit;
17742c393a42Smrg
17752c393a42Smrg    name = FcConfigGetAttribute (parse, "name");
17762c393a42Smrg    if (!name)
17772c393a42Smrg    {
17782c393a42Smrg	FcConfigMessage (parse, FcSevereWarning, "missing edit name");
17792c393a42Smrg	return;
17802c393a42Smrg    }
17812c393a42Smrg    mode_string = FcConfigGetAttribute (parse, "mode");
17822c393a42Smrg    if (!mode_string)
17832c393a42Smrg	mode = FcOpAssign;
17842c393a42Smrg    else
17852c393a42Smrg    {
17862c393a42Smrg	mode = FcConfigLexMode (mode_string);
17872c393a42Smrg	if (mode == FcOpInvalid)
17882c393a42Smrg	{
17892c393a42Smrg	    FcConfigMessage (parse, FcSevereWarning, "invalid edit mode \"%s\"", mode_string);
17902c393a42Smrg	    return;
17912c393a42Smrg	}
17922c393a42Smrg    }
17932c393a42Smrg    if (!FcConfigLexBinding (parse, FcConfigGetAttribute (parse, "binding"), &binding))
17942c393a42Smrg	return;
17952c393a42Smrg
17962c393a42Smrg    expr = FcPopBinary (parse, FcOpComma);
17972c393a42Smrg    edit = FcEditCreate (parse, FcObjectFromName ((char *) name),
17982c393a42Smrg			 mode, expr, binding);
17992c393a42Smrg    if (!edit)
18002c393a42Smrg    {
18012c393a42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
18022c393a42Smrg	FcExprDestroy (expr);
18032c393a42Smrg	return;
18042c393a42Smrg    }
18052c393a42Smrg    if (!FcVStackPushEdit (parse, edit))
18062c393a42Smrg	FcEditDestroy (edit);
18072c393a42Smrg}
18082c393a42Smrg
18092c393a42Smrgstatic void
18102c393a42SmrgFcParseMatch (FcConfigParse *parse)
18112c393a42Smrg{
18122c393a42Smrg    const FcChar8   *kind_name;
18132c393a42Smrg    FcMatchKind	    kind;
18142c393a42Smrg    FcTest	    *test = 0;
18152c393a42Smrg    FcEdit	    *edit = 0;
18162c393a42Smrg    FcVStack	    *vstack;
18172c393a42Smrg
18182c393a42Smrg    kind_name = FcConfigGetAttribute (parse, "target");
18192c393a42Smrg    if (!kind_name)
18202c393a42Smrg	kind = FcMatchPattern;
18212c393a42Smrg    else
18222c393a42Smrg    {
18232c393a42Smrg	if (!strcmp ((char *) kind_name, "pattern"))
18242c393a42Smrg	    kind = FcMatchPattern;
18252c393a42Smrg	else if (!strcmp ((char *) kind_name, "font"))
18262c393a42Smrg	    kind = FcMatchFont;
18272c393a42Smrg	else if (!strcmp ((char *) kind_name, "scan"))
18282c393a42Smrg	    kind = FcMatchScan;
18292c393a42Smrg	else
18302c393a42Smrg	{
18312c393a42Smrg	    FcConfigMessage (parse, FcSevereWarning, "invalid match target \"%s\"", kind_name);
18322c393a42Smrg	    return;
18332c393a42Smrg	}
18342c393a42Smrg    }
1835a6844aabSmrg    while ((vstack = FcVStackPeek (parse)))
18362c393a42Smrg    {
18372c393a42Smrg	switch (vstack->tag) {
18382c393a42Smrg	case FcVStackTest:
18392c393a42Smrg	    vstack->u.test->next = test;
18402c393a42Smrg	    test = vstack->u.test;
18412c393a42Smrg	    vstack->tag = FcVStackNone;
18422c393a42Smrg	    break;
18432c393a42Smrg	case FcVStackEdit:
18442c393a42Smrg	    vstack->u.edit->next = edit;
18452c393a42Smrg	    edit = vstack->u.edit;
18462c393a42Smrg	    vstack->tag = FcVStackNone;
18472c393a42Smrg	    if (kind == FcMatchScan && edit->object > FC_MAX_BASE_OBJECT)
18482c393a42Smrg	    {
18492c393a42Smrg		FcConfigMessage (parse, FcSevereError,
18502c393a42Smrg				 "<match target=\"scan\"> cannot edit user-defined object \"%s\"",
18512c393a42Smrg				 FcObjectName(edit->object));
18522c393a42Smrg	    }
18532c393a42Smrg	    break;
18542c393a42Smrg	default:
18552c393a42Smrg	    FcConfigMessage (parse, FcSevereWarning, "invalid match element");
18562c393a42Smrg	    break;
18572c393a42Smrg	}
1858a6844aabSmrg	FcVStackPopAndDestroy (parse);
18592c393a42Smrg    }
18602c393a42Smrg    if (!FcConfigAddEdit (parse->config, test, edit, kind))
18612c393a42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
18622c393a42Smrg}
18632c393a42Smrg
18642c393a42Smrgstatic void
18652c393a42SmrgFcParseAcceptRejectFont (FcConfigParse *parse, FcElement element)
18662c393a42Smrg{
18672c393a42Smrg    FcVStack	*vstack;
18682c393a42Smrg
1869a6844aabSmrg    while ((vstack = FcVStackPeek (parse)))
18702c393a42Smrg    {
18712c393a42Smrg	switch (vstack->tag) {
18722c393a42Smrg	case FcVStackGlob:
18732c393a42Smrg	    if (!FcConfigGlobAdd (parse->config,
18742c393a42Smrg				  vstack->u.string,
18752c393a42Smrg				  element == FcElementAcceptfont))
18762c393a42Smrg	    {
18772c393a42Smrg		FcConfigMessage (parse, FcSevereError, "out of memory");
18782c393a42Smrg	    }
18792c393a42Smrg	    break;
18802c393a42Smrg	case FcVStackPattern:
18812c393a42Smrg	    if (!FcConfigPatternsAdd (parse->config,
18822c393a42Smrg				      vstack->u.pattern,
18832c393a42Smrg				      element == FcElementAcceptfont))
18842c393a42Smrg	    {
18852c393a42Smrg		FcConfigMessage (parse, FcSevereError, "out of memory");
18862c393a42Smrg	    }
18872c393a42Smrg	    else
18882c393a42Smrg		vstack->tag = FcVStackNone;
18892c393a42Smrg	    break;
18902c393a42Smrg	default:
18912c393a42Smrg	    FcConfigMessage (parse, FcSevereWarning, "bad font selector");
18922c393a42Smrg	    break;
18932c393a42Smrg	}
1894a6844aabSmrg	FcVStackPopAndDestroy (parse);
18952c393a42Smrg    }
18962c393a42Smrg}
18972c393a42Smrg
18982c393a42Smrg
18992c393a42Smrgstatic FcValue
19002c393a42SmrgFcPopValue (FcConfigParse *parse)
19012c393a42Smrg{
1902a6844aabSmrg    FcVStack	*vstack = FcVStackPeek (parse);
19032c393a42Smrg    FcValue	value;
19042c393a42Smrg
19052c393a42Smrg    value.type = FcTypeVoid;
19062c393a42Smrg
19072c393a42Smrg    if (!vstack)
19082c393a42Smrg	return value;
19092c393a42Smrg
19102c393a42Smrg    switch (vstack->tag) {
19112c393a42Smrg    case FcVStackString:
1912a6844aabSmrg	value.u.s = FcStrStaticName (vstack->u.string);
19132c393a42Smrg	if (value.u.s)
19142c393a42Smrg	    value.type = FcTypeString;
19152c393a42Smrg	break;
19162c393a42Smrg    case FcVStackConstant:
19172c393a42Smrg	if (FcNameConstant (vstack->u.string, &value.u.i))
19182c393a42Smrg	    value.type = FcTypeInteger;
19192c393a42Smrg	break;
19202c393a42Smrg    case FcVStackInteger:
19212c393a42Smrg	value.u.i = vstack->u.integer;
19222c393a42Smrg	value.type = FcTypeInteger;
19232c393a42Smrg	break;
19242c393a42Smrg    case FcVStackDouble:
19252c393a42Smrg	value.u.d = vstack->u._double;
19262c393a42Smrg	value.type = FcTypeInteger;
19272c393a42Smrg	break;
19282c393a42Smrg    case FcVStackMatrix:
19292c393a42Smrg	value.u.m = FcMatrixCopy (vstack->u.matrix);
19302c393a42Smrg	if (value.u.m)
19312c393a42Smrg	    value.type = FcTypeMatrix;
19322c393a42Smrg	break;
19332c393a42Smrg    case FcVStackBool:
1934a6844aabSmrg	value.u.b = vstack->u.bool_;
19352c393a42Smrg	value.type = FcTypeBool;
19362c393a42Smrg	break;
19372c393a42Smrg    default:
19382c393a42Smrg	FcConfigMessage (parse, FcSevereWarning, "unknown pattern element %d",
19392c393a42Smrg			 vstack->tag);
19402c393a42Smrg	break;
19412c393a42Smrg    }
1942a6844aabSmrg    FcVStackPopAndDestroy (parse);
19432c393a42Smrg
19442c393a42Smrg    return value;
19452c393a42Smrg}
19462c393a42Smrg
19472c393a42Smrgstatic void
19482c393a42SmrgFcParsePatelt (FcConfigParse *parse)
19492c393a42Smrg{
19502c393a42Smrg    FcValue	value;
19512c393a42Smrg    FcPattern	*pattern = FcPatternCreate ();
19522c393a42Smrg    const char	*name;
19532c393a42Smrg
19542c393a42Smrg    if (!pattern)
19552c393a42Smrg    {
19562c393a42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
19572c393a42Smrg	return;
19582c393a42Smrg    }
19592c393a42Smrg
19602c393a42Smrg    name = (char *) FcConfigGetAttribute (parse, "name");
19612c393a42Smrg    if (!name)
19622c393a42Smrg    {
19632c393a42Smrg	FcConfigMessage (parse, FcSevereWarning, "missing pattern element name");
19642c393a42Smrg	FcPatternDestroy (pattern);
19652c393a42Smrg	return;
19662c393a42Smrg    }
19672c393a42Smrg
19682c393a42Smrg    for (;;)
19692c393a42Smrg    {
19702c393a42Smrg	value = FcPopValue (parse);
19712c393a42Smrg	if (value.type == FcTypeVoid)
19722c393a42Smrg	    break;
19732c393a42Smrg	if (!FcPatternAdd (pattern, name, value, FcTrue))
19742c393a42Smrg	{
19752c393a42Smrg	    FcConfigMessage (parse, FcSevereError, "out of memory");
1976a6844aabSmrg            FcValueDestroy(value);
19772c393a42Smrg	    break;
19782c393a42Smrg	}
1979a6844aabSmrg        FcValueDestroy(value);
19802c393a42Smrg    }
19812c393a42Smrg
19822c393a42Smrg    FcVStackPushPattern (parse, pattern);
19832c393a42Smrg}
19842c393a42Smrg
19852c393a42Smrgstatic void
19862c393a42SmrgFcParsePattern (FcConfigParse *parse)
19872c393a42Smrg{
19882c393a42Smrg    FcVStack	*vstack;
19892c393a42Smrg    FcPattern	*pattern = FcPatternCreate ();
19902c393a42Smrg
19912c393a42Smrg    if (!pattern)
19922c393a42Smrg    {
19932c393a42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
19942c393a42Smrg	return;
19952c393a42Smrg    }
19962c393a42Smrg
1997a6844aabSmrg    while ((vstack = FcVStackPeek (parse)))
19982c393a42Smrg    {
19992c393a42Smrg	switch (vstack->tag) {
20002c393a42Smrg	case FcVStackPattern:
20012c393a42Smrg	    if (!FcPatternAppend (pattern, vstack->u.pattern))
20022c393a42Smrg	    {
20032c393a42Smrg		FcConfigMessage (parse, FcSevereError, "out of memory");
20042c393a42Smrg		FcPatternDestroy (pattern);
20052c393a42Smrg		return;
20062c393a42Smrg	    }
20072c393a42Smrg	    break;
20082c393a42Smrg	default:
20092c393a42Smrg	    FcConfigMessage (parse, FcSevereWarning, "unknown pattern element");
20102c393a42Smrg	    break;
20112c393a42Smrg	}
2012a6844aabSmrg	FcVStackPopAndDestroy (parse);
20132c393a42Smrg    }
20142c393a42Smrg
20152c393a42Smrg    FcVStackPushPattern (parse, pattern);
20162c393a42Smrg}
20172c393a42Smrg
20182c393a42Smrgstatic void
20192c393a42SmrgFcEndElement(void *userData, const XML_Char *name)
20202c393a42Smrg{
20212c393a42Smrg    FcConfigParse   *parse = userData;
20222c393a42Smrg    FcChar8	    *data;
2023a6844aabSmrg#ifdef _WIN32
2024a6844aabSmrg    FcChar8         buffer[1000];
2025a6844aabSmrg#endif
2026a6844aabSmrg
20272c393a42Smrg    if (!parse->pstack)
20282c393a42Smrg	return;
20292c393a42Smrg    switch (parse->pstack->element) {
20302c393a42Smrg    case FcElementNone:
20312c393a42Smrg	break;
20322c393a42Smrg    case FcElementFontconfig:
20332c393a42Smrg	break;
20342c393a42Smrg    case FcElementDir:
2035a6844aabSmrg	data = FcStrBufDoneStatic (&parse->pstack->str);
20362c393a42Smrg	if (!data)
20372c393a42Smrg	{
20382c393a42Smrg	    FcConfigMessage (parse, FcSevereError, "out of memory");
20392c393a42Smrg	    break;
20402c393a42Smrg	}
20412c393a42Smrg#ifdef _WIN32
20422c393a42Smrg	if (strcmp (data, "CUSTOMFONTDIR") == 0)
20432c393a42Smrg	{
2044a6844aabSmrg		char *p;
2045a6844aabSmrg		data = buffer;
2046a6844aabSmrg		if (!GetModuleFileName (NULL, buffer, sizeof (buffer) - 20))
20472c393a42Smrg		{
2048a6844aabSmrg			FcConfigMessage (parse, FcSevereError, "GetModuleFileName failed");
20492c393a42Smrg			break;
20502c393a42Smrg		}
2051a6844aabSmrg		/*
2052a6844aabSmrg		 * Must use the multi-byte aware function to search
2053a6844aabSmrg		 * for backslash because East Asian double-byte code
2054a6844aabSmrg		 * pages have characters with backslash as the second
2055a6844aabSmrg		 * byte.
2056a6844aabSmrg		 */
2057a6844aabSmrg		p = _mbsrchr (data, '\\');
2058a6844aabSmrg		if (p) *p = '\0';
2059a6844aabSmrg		strcat (data, "\\fonts");
2060a6844aabSmrg	}
2061a6844aabSmrg	else if (strcmp (data, "APPSHAREFONTDIR") == 0)
2062a6844aabSmrg	{
2063a6844aabSmrg		char *p;
2064a6844aabSmrg		data = buffer;
2065a6844aabSmrg		if (!GetModuleFileName (NULL, buffer, sizeof (buffer) - 20))
20662c393a42Smrg		{
20672c393a42Smrg			FcConfigMessage (parse, FcSevereError, "GetModuleFileName failed");
20682c393a42Smrg			break;
20692c393a42Smrg		}
2070a6844aabSmrg		p = _mbsrchr (data, '\\');
20712c393a42Smrg		if (p) *p = '\0';
2072a6844aabSmrg		strcat (data, "\\..\\share\\fonts");
20732c393a42Smrg	}
20742c393a42Smrg	else if (strcmp (data, "WINDOWSFONTDIR") == 0)
20752c393a42Smrg	{
20762c393a42Smrg	    int rc;
2077a6844aabSmrg	    data = buffer;
2078a6844aabSmrg#if _WIN32_WINNT >= 0x0500
2079a6844aabSmrg	    rc = GetSystemWindowsDirectory (buffer, sizeof (buffer) - 20);
2080a6844aabSmrg#else
2081a6844aabSmrg	    rc = GetWindowsDirectory (buffer, sizeof (buffer) - 20);
2082a6844aabSmrg#endif
2083a6844aabSmrg	    if (rc == 0 || rc > sizeof (buffer) - 20)
20842c393a42Smrg	    {
2085a6844aabSmrg		FcConfigMessage (parse, FcSevereError, "GetSystemWindowsDirectory failed");
20862c393a42Smrg		break;
20872c393a42Smrg	    }
20882c393a42Smrg	    if (data [strlen (data) - 1] != '\\')
20892c393a42Smrg		strcat (data, "\\");
20902c393a42Smrg	    strcat (data, "fonts");
20912c393a42Smrg	}
20922c393a42Smrg#endif
20932c393a42Smrg	if (strlen ((char *) data) == 0)
20942c393a42Smrg	    FcConfigMessage (parse, FcSevereWarning, "empty font directory name ignored");
20952c393a42Smrg	else if (!FcStrUsesHome (data) || FcConfigHome ())
20962c393a42Smrg	{
20972c393a42Smrg	    if (!FcConfigAddDir (parse->config, data))
20982c393a42Smrg		FcConfigMessage (parse, FcSevereError, "out of memory; cannot add directory %s", data);
20992c393a42Smrg	}
2100a6844aabSmrg	FcStrBufDestroy (&parse->pstack->str);
21012c393a42Smrg	break;
21022c393a42Smrg    case FcElementCacheDir:
21032c393a42Smrg	data = FcStrBufDone (&parse->pstack->str);
21042c393a42Smrg	if (!data)
21052c393a42Smrg	{
21062c393a42Smrg	    FcConfigMessage (parse, FcSevereError, "out of memory");
21072c393a42Smrg	    break;
21082c393a42Smrg	}
21092c393a42Smrg#ifdef _WIN32
21102c393a42Smrg	if (strcmp (data, "WINDOWSTEMPDIR_FONTCONFIG_CACHE") == 0)
21112c393a42Smrg	{
21122c393a42Smrg	    int rc;
21132c393a42Smrg	    FcStrFree (data);
21142c393a42Smrg	    data = malloc (1000);
21152c393a42Smrg	    if (!data)
21162c393a42Smrg	    {
21172c393a42Smrg		FcConfigMessage (parse, FcSevereError, "out of memory");
21182c393a42Smrg		break;
21192c393a42Smrg	    }
21202c393a42Smrg	    FcMemAlloc (FC_MEM_STRING, 1000);
21212c393a42Smrg	    rc = GetTempPath (800, data);
21222c393a42Smrg	    if (rc == 0 || rc > 800)
21232c393a42Smrg	    {
2124a6844aabSmrg		FcConfigMessage (parse, FcSevereError, "GetTempPath failed");
21252c393a42Smrg		FcStrFree (data);
21262c393a42Smrg		break;
21272c393a42Smrg	    }
21282c393a42Smrg	    if (data [strlen (data) - 1] != '\\')
21292c393a42Smrg		strcat (data, "\\");
21302c393a42Smrg	    strcat (data, "fontconfig\\cache");
21312c393a42Smrg	}
21322c393a42Smrg#endif
21332c393a42Smrg	if (!FcStrUsesHome (data) || FcConfigHome ())
21342c393a42Smrg	{
21352c393a42Smrg	    if (!FcConfigAddCacheDir (parse->config, data))
21362c393a42Smrg		FcConfigMessage (parse, FcSevereError, "out of memory; cannot add cache directory %s", data);
21372c393a42Smrg	}
21382c393a42Smrg	FcStrFree (data);
21392c393a42Smrg	break;
21402c393a42Smrg
21412c393a42Smrg    case FcElementCache:
2142a6844aabSmrg	data = FcStrBufDoneStatic (&parse->pstack->str);
21432c393a42Smrg	if (!data)
21442c393a42Smrg	{
21452c393a42Smrg	    FcConfigMessage (parse, FcSevereError, "out of memory");
21462c393a42Smrg	    break;
21472c393a42Smrg	}
21482c393a42Smrg	/* discard this data; no longer used */
2149a6844aabSmrg	FcStrBufDestroy (&parse->pstack->str);
21502c393a42Smrg	break;
21512c393a42Smrg    case FcElementInclude:
21522c393a42Smrg	FcParseInclude (parse);
21532c393a42Smrg	break;
21542c393a42Smrg    case FcElementConfig:
21552c393a42Smrg	break;
21562c393a42Smrg    case FcElementMatch:
21572c393a42Smrg	FcParseMatch (parse);
21582c393a42Smrg	break;
21592c393a42Smrg    case FcElementAlias:
21602c393a42Smrg	FcParseAlias (parse);
21612c393a42Smrg	break;
21622c393a42Smrg
21632c393a42Smrg    case FcElementBlank:
21642c393a42Smrg	FcParseBlank (parse);
21652c393a42Smrg	break;
21662c393a42Smrg    case FcElementRescan:
21672c393a42Smrg	FcParseRescan (parse);
21682c393a42Smrg	break;
21692c393a42Smrg
21702c393a42Smrg    case FcElementPrefer:
21712c393a42Smrg	FcParseFamilies (parse, FcVStackPrefer);
21722c393a42Smrg	break;
21732c393a42Smrg    case FcElementAccept:
21742c393a42Smrg	FcParseFamilies (parse, FcVStackAccept);
21752c393a42Smrg	break;
21762c393a42Smrg    case FcElementDefault:
21772c393a42Smrg	FcParseFamilies (parse, FcVStackDefault);
21782c393a42Smrg	break;
21792c393a42Smrg    case FcElementFamily:
21802c393a42Smrg	FcParseFamily (parse);
21812c393a42Smrg	break;
21822c393a42Smrg
21832c393a42Smrg    case FcElementTest:
21842c393a42Smrg	FcParseTest (parse);
21852c393a42Smrg	break;
21862c393a42Smrg    case FcElementEdit:
21872c393a42Smrg	FcParseEdit (parse);
21882c393a42Smrg	break;
21892c393a42Smrg
21902c393a42Smrg    case FcElementInt:
21912c393a42Smrg	FcParseInt (parse);
21922c393a42Smrg	break;
21932c393a42Smrg    case FcElementDouble:
21942c393a42Smrg	FcParseDouble (parse);
21952c393a42Smrg	break;
21962c393a42Smrg    case FcElementString:
21972c393a42Smrg	FcParseString (parse, FcVStackString);
21982c393a42Smrg	break;
21992c393a42Smrg    case FcElementMatrix:
22002c393a42Smrg	FcParseMatrix (parse);
22012c393a42Smrg	break;
22022c393a42Smrg    case FcElementBool:
22032c393a42Smrg	FcParseBool (parse);
22042c393a42Smrg	break;
22052c393a42Smrg    case FcElementCharset:
22062c393a42Smrg/*	FcParseCharset (parse); */
22072c393a42Smrg	break;
22082c393a42Smrg    case FcElementSelectfont:
22092c393a42Smrg	break;
22102c393a42Smrg    case FcElementAcceptfont:
22112c393a42Smrg    case FcElementRejectfont:
22122c393a42Smrg	FcParseAcceptRejectFont (parse, parse->pstack->element);
22132c393a42Smrg	break;
22142c393a42Smrg    case FcElementGlob:
22152c393a42Smrg	FcParseString (parse, FcVStackGlob);
22162c393a42Smrg	break;
22172c393a42Smrg    case FcElementPattern:
22182c393a42Smrg	FcParsePattern (parse);
22192c393a42Smrg	break;
22202c393a42Smrg    case FcElementPatelt:
22212c393a42Smrg	FcParsePatelt (parse);
22222c393a42Smrg	break;
22232c393a42Smrg    case FcElementName:
22242c393a42Smrg	FcParseString (parse, FcVStackField);
22252c393a42Smrg	break;
22262c393a42Smrg    case FcElementConst:
22272c393a42Smrg	FcParseString (parse, FcVStackConstant);
22282c393a42Smrg	break;
22292c393a42Smrg    case FcElementOr:
22302c393a42Smrg	FcParseBinary (parse, FcOpOr);
22312c393a42Smrg	break;
22322c393a42Smrg    case FcElementAnd:
22332c393a42Smrg	FcParseBinary (parse, FcOpAnd);
22342c393a42Smrg	break;
22352c393a42Smrg    case FcElementEq:
22362c393a42Smrg	FcParseBinary (parse, FcOpEqual);
22372c393a42Smrg	break;
22382c393a42Smrg    case FcElementNotEq:
22392c393a42Smrg	FcParseBinary (parse, FcOpNotEqual);
22402c393a42Smrg	break;
22412c393a42Smrg    case FcElementLess:
22422c393a42Smrg	FcParseBinary (parse, FcOpLess);
22432c393a42Smrg	break;
22442c393a42Smrg    case FcElementLessEq:
22452c393a42Smrg	FcParseBinary (parse, FcOpLessEqual);
22462c393a42Smrg	break;
22472c393a42Smrg    case FcElementMore:
22482c393a42Smrg	FcParseBinary (parse, FcOpMore);
22492c393a42Smrg	break;
22502c393a42Smrg    case FcElementMoreEq:
22512c393a42Smrg	FcParseBinary (parse, FcOpMoreEqual);
22522c393a42Smrg	break;
22532c393a42Smrg    case FcElementContains:
22542c393a42Smrg	FcParseBinary (parse, FcOpContains);
22552c393a42Smrg	break;
22562c393a42Smrg    case FcElementNotContains:
22572c393a42Smrg	FcParseBinary (parse, FcOpNotContains);
22582c393a42Smrg	break;
22592c393a42Smrg    case FcElementPlus:
22602c393a42Smrg	FcParseBinary (parse, FcOpPlus);
22612c393a42Smrg	break;
22622c393a42Smrg    case FcElementMinus:
22632c393a42Smrg	FcParseBinary (parse, FcOpMinus);
22642c393a42Smrg	break;
22652c393a42Smrg    case FcElementTimes:
22662c393a42Smrg	FcParseBinary (parse, FcOpTimes);
22672c393a42Smrg	break;
22682c393a42Smrg    case FcElementDivide:
22692c393a42Smrg	FcParseBinary (parse, FcOpDivide);
22702c393a42Smrg	break;
22712c393a42Smrg    case FcElementNot:
22722c393a42Smrg	FcParseUnary (parse, FcOpNot);
22732c393a42Smrg	break;
22742c393a42Smrg    case FcElementIf:
22752c393a42Smrg	FcParseBinary (parse, FcOpQuest);
22762c393a42Smrg	break;
22772c393a42Smrg    case FcElementFloor:
22782c393a42Smrg	FcParseUnary (parse, FcOpFloor);
22792c393a42Smrg	break;
22802c393a42Smrg    case FcElementCeil:
22812c393a42Smrg	FcParseUnary (parse, FcOpCeil);
22822c393a42Smrg	break;
22832c393a42Smrg    case FcElementRound:
22842c393a42Smrg	FcParseUnary (parse, FcOpRound);
22852c393a42Smrg	break;
22862c393a42Smrg    case FcElementTrunc:
22872c393a42Smrg	FcParseUnary (parse, FcOpTrunc);
22882c393a42Smrg	break;
22892c393a42Smrg    case FcElementUnknown:
22902c393a42Smrg	break;
22912c393a42Smrg    }
22922c393a42Smrg    (void) FcPStackPop (parse);
22932c393a42Smrg}
22942c393a42Smrg
22952c393a42Smrgstatic void
22962c393a42SmrgFcCharacterData (void *userData, const XML_Char *s, int len)
22972c393a42Smrg{
22982c393a42Smrg    FcConfigParse   *parse = userData;
22992c393a42Smrg
23002c393a42Smrg    if (!parse->pstack)
23012c393a42Smrg	return;
23022c393a42Smrg    if (!FcStrBufData (&parse->pstack->str, (FcChar8 *) s, len))
23032c393a42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
23042c393a42Smrg}
23052c393a42Smrg
23062c393a42Smrgstatic void
23072c393a42SmrgFcStartDoctypeDecl (void	    *userData,
23082c393a42Smrg		    const XML_Char  *doctypeName,
23092c393a42Smrg		    const XML_Char  *sysid,
23102c393a42Smrg		    const XML_Char  *pubid,
23112c393a42Smrg		    int		    has_internal_subset)
23122c393a42Smrg{
23132c393a42Smrg    FcConfigParse   *parse = userData;
23142c393a42Smrg
23152c393a42Smrg    if (strcmp ((char *) doctypeName, "fontconfig") != 0)
23162c393a42Smrg	FcConfigMessage (parse, FcSevereError, "invalid doctype \"%s\"", doctypeName);
23172c393a42Smrg}
23182c393a42Smrg
23192c393a42Smrg#ifdef ENABLE_LIBXML2
23202c393a42Smrg
23212c393a42Smrgstatic void
23222c393a42SmrgFcInternalSubsetDecl (void            *userData,
23232c393a42Smrg		      const XML_Char  *doctypeName,
23242c393a42Smrg		      const XML_Char  *sysid,
23252c393a42Smrg		      const XML_Char  *pubid)
23262c393a42Smrg{
23272c393a42Smrg    FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 1);
23282c393a42Smrg}
23292c393a42Smrg
23302c393a42Smrgstatic void
23312c393a42SmrgFcExternalSubsetDecl (void            *userData,
23322c393a42Smrg		      const XML_Char  *doctypeName,
23332c393a42Smrg		      const XML_Char  *sysid,
23342c393a42Smrg		      const XML_Char  *pubid)
23352c393a42Smrg{
23362c393a42Smrg    FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 0);
23372c393a42Smrg}
23382c393a42Smrg
23392c393a42Smrg#else /* ENABLE_LIBXML2 */
23402c393a42Smrg
23412c393a42Smrgstatic void
23422c393a42SmrgFcEndDoctypeDecl (void *userData)
23432c393a42Smrg{
23442c393a42Smrg}
23452c393a42Smrg
23462c393a42Smrg#endif /* ENABLE_LIBXML2 */
23472c393a42Smrg
23482c393a42Smrgstatic int
23492c393a42SmrgFcSortCmpStr (const void *a, const void *b)
23502c393a42Smrg{
23512c393a42Smrg    const FcChar8    *as = *((FcChar8 **) a);
23522c393a42Smrg    const FcChar8    *bs = *((FcChar8 **) b);
23532c393a42Smrg    return FcStrCmp (as, bs);
23542c393a42Smrg}
23552c393a42Smrg
23562c393a42Smrgstatic FcBool
23572c393a42SmrgFcConfigParseAndLoadDir (FcConfig	*config,
23582c393a42Smrg			 const FcChar8	*name,
23592c393a42Smrg			 const FcChar8	*dir,
23602c393a42Smrg			 FcBool		complain)
23612c393a42Smrg{
23622c393a42Smrg    DIR		    *d;
23632c393a42Smrg    struct dirent   *e;
23642c393a42Smrg    FcBool	    ret = FcTrue;
23652c393a42Smrg    FcChar8	    *file;
23662c393a42Smrg    FcChar8	    *base;
23672c393a42Smrg    FcStrSet	    *files;
23682c393a42Smrg
23692c393a42Smrg    d = opendir ((char *) dir);
23702c393a42Smrg    if (!d)
23712c393a42Smrg    {
23722c393a42Smrg	if (complain)
23732c393a42Smrg	    FcConfigMessage (0, FcSevereError, "Cannot open config dir \"%s\"",
23742c393a42Smrg			     name);
23752c393a42Smrg	ret = FcFalse;
23762c393a42Smrg	goto bail0;
23772c393a42Smrg    }
23782c393a42Smrg    /* freed below */
23792c393a42Smrg    file = (FcChar8 *) malloc (strlen ((char *) dir) + 1 + FC_MAX_FILE_LEN + 1);
23802c393a42Smrg    if (!file)
23812c393a42Smrg    {
23822c393a42Smrg	ret = FcFalse;
23832c393a42Smrg	goto bail1;
23842c393a42Smrg    }
23852c393a42Smrg
23862c393a42Smrg    strcpy ((char *) file, (char *) dir);
23872c393a42Smrg    strcat ((char *) file, "/");
23882c393a42Smrg    base = file + strlen ((char *) file);
23892c393a42Smrg
23902c393a42Smrg    files = FcStrSetCreate ();
23912c393a42Smrg    if (!files)
23922c393a42Smrg    {
23932c393a42Smrg	ret = FcFalse;
23942c393a42Smrg	goto bail2;
23952c393a42Smrg    }
23962c393a42Smrg
23972c393a42Smrg    if (FcDebug () & FC_DBG_CONFIG)
23982c393a42Smrg	printf ("\tScanning config dir %s\n", dir);
23992c393a42Smrg
24002c393a42Smrg    while (ret && (e = readdir (d)))
24012c393a42Smrg    {
24022c393a42Smrg	int d_len;
24032c393a42Smrg#define TAIL	    ".conf"
24042c393a42Smrg#define TAIL_LEN    5
24052c393a42Smrg	/*
24062c393a42Smrg	 * Add all files of the form [0-9]*.conf
24072c393a42Smrg	 */
24082c393a42Smrg	if ('0' <= e->d_name[0] && e->d_name[0] <= '9' &&
24092c393a42Smrg	    (d_len = strlen (e->d_name)) < FC_MAX_FILE_LEN &&
24102c393a42Smrg	    d_len > TAIL_LEN &&
24112c393a42Smrg	    strcmp (e->d_name + d_len - TAIL_LEN, TAIL) == 0)
24122c393a42Smrg	{
24132c393a42Smrg	    strcpy ((char *) base, (char *) e->d_name);
24142c393a42Smrg	    if (!FcStrSetAdd (files, file))
24152c393a42Smrg	    {
24162c393a42Smrg		ret = FcFalse;
24172c393a42Smrg		goto bail3;
24182c393a42Smrg	    }
24192c393a42Smrg	}
24202c393a42Smrg    }
24212c393a42Smrg    if (ret)
24222c393a42Smrg    {
24232c393a42Smrg	int i;
24242c393a42Smrg	qsort (files->strs, files->num, sizeof (FcChar8 *),
24252c393a42Smrg	       (int (*)(const void *, const void *)) FcSortCmpStr);
24262c393a42Smrg	for (i = 0; ret && i < files->num; i++)
24272c393a42Smrg	    ret = FcConfigParseAndLoad (config, files->strs[i], complain);
24282c393a42Smrg    }
24292c393a42Smrgbail3:
24302c393a42Smrg    FcStrSetDestroy (files);
24312c393a42Smrgbail2:
24322c393a42Smrg    free (file);
24332c393a42Smrgbail1:
24342c393a42Smrg    closedir (d);
24352c393a42Smrgbail0:
24362c393a42Smrg    return ret || !complain;
24372c393a42Smrg}
24382c393a42Smrg
24392c393a42SmrgFcBool
24402c393a42SmrgFcConfigParseAndLoad (FcConfig	    *config,
24412c393a42Smrg		      const FcChar8 *name,
24422c393a42Smrg		      FcBool	    complain)
24432c393a42Smrg{
24442c393a42Smrg
24452c393a42Smrg    XML_Parser	    p;
24462c393a42Smrg    FcChar8	    *filename;
24472c393a42Smrg    int		    fd;
24482c393a42Smrg    int		    len;
24492c393a42Smrg    FcConfigParse   parse;
24502c393a42Smrg    FcBool	    error = FcTrue;
24512c393a42Smrg
24522c393a42Smrg#ifdef ENABLE_LIBXML2
24532c393a42Smrg    xmlSAXHandler   sax;
24542c393a42Smrg    char            buf[BUFSIZ];
24552c393a42Smrg#else
24562c393a42Smrg    void	    *buf;
24572c393a42Smrg#endif
24582c393a42Smrg
24592c393a42Smrg    filename = FcConfigFilename (name);
24602c393a42Smrg    if (!filename)
24612c393a42Smrg	goto bail0;
24622c393a42Smrg
24632c393a42Smrg    if (FcStrSetMember (config->configFiles, filename))
24642c393a42Smrg    {
24652c393a42Smrg        FcStrFree (filename);
24662c393a42Smrg        return FcTrue;
24672c393a42Smrg    }
24682c393a42Smrg
24692c393a42Smrg    if (!FcStrSetAdd (config->configFiles, filename))
24702c393a42Smrg    {
24712c393a42Smrg	FcStrFree (filename);
24722c393a42Smrg	goto bail0;
24732c393a42Smrg    }
24742c393a42Smrg
24752c393a42Smrg    if (FcFileIsDir (filename))
24762c393a42Smrg    {
24772c393a42Smrg	FcBool ret = FcConfigParseAndLoadDir (config, name, filename, complain);
24782c393a42Smrg	FcStrFree (filename);
24792c393a42Smrg	return ret;
24802c393a42Smrg    }
24812c393a42Smrg
24822c393a42Smrg    if (FcDebug () & FC_DBG_CONFIG)
24832c393a42Smrg	printf ("\tLoading config file %s\n", filename);
24842c393a42Smrg
24852c393a42Smrg    fd = open ((char *) filename, O_RDONLY);
24862c393a42Smrg    if (fd == -1) {
24872c393a42Smrg	FcStrFree (filename);
24882c393a42Smrg	goto bail0;
24892c393a42Smrg    }
24902c393a42Smrg
24912c393a42Smrg#ifdef ENABLE_LIBXML2
24922c393a42Smrg    memset(&sax, 0, sizeof(sax));
24932c393a42Smrg
24942c393a42Smrg    sax.internalSubset = FcInternalSubsetDecl;
24952c393a42Smrg    sax.externalSubset = FcExternalSubsetDecl;
24962c393a42Smrg    sax.startElement = FcStartElement;
24972c393a42Smrg    sax.endElement = FcEndElement;
24982c393a42Smrg    sax.characters = FcCharacterData;
24992c393a42Smrg
25002c393a42Smrg    p = xmlCreatePushParserCtxt (&sax, &parse, NULL, 0, (const char *) filename);
25012c393a42Smrg#else
25022c393a42Smrg    p = XML_ParserCreate ("UTF-8");
25032c393a42Smrg#endif
25042c393a42Smrg    FcStrFree (filename);
25052c393a42Smrg
25062c393a42Smrg    if (!p)
25072c393a42Smrg	goto bail1;
25082c393a42Smrg
25092c393a42Smrg    if (!FcConfigInit (&parse, name, config, p))
25102c393a42Smrg	goto bail2;
25112c393a42Smrg
25122c393a42Smrg#ifndef ENABLE_LIBXML2
25132c393a42Smrg
25142c393a42Smrg    XML_SetUserData (p, &parse);
25152c393a42Smrg
25162c393a42Smrg    XML_SetDoctypeDeclHandler (p, FcStartDoctypeDecl, FcEndDoctypeDecl);
25172c393a42Smrg    XML_SetElementHandler (p, FcStartElement, FcEndElement);
25182c393a42Smrg    XML_SetCharacterDataHandler (p, FcCharacterData);
25192c393a42Smrg
25202c393a42Smrg#endif /* ENABLE_LIBXML2 */
25212c393a42Smrg
25222c393a42Smrg    do {
25232c393a42Smrg#ifndef ENABLE_LIBXML2
25242c393a42Smrg	buf = XML_GetBuffer (p, BUFSIZ);
25252c393a42Smrg	if (!buf)
25262c393a42Smrg	{
25272c393a42Smrg	    FcConfigMessage (&parse, FcSevereError, "cannot get parse buffer");
25282c393a42Smrg	    goto bail3;
25292c393a42Smrg	}
25302c393a42Smrg#endif
25312c393a42Smrg	len = read (fd, buf, BUFSIZ);
25322c393a42Smrg	if (len < 0)
25332c393a42Smrg	{
25342c393a42Smrg	    FcConfigMessage (&parse, FcSevereError, "failed reading config file");
25352c393a42Smrg	    goto bail3;
25362c393a42Smrg	}
25372c393a42Smrg
25382c393a42Smrg#ifdef ENABLE_LIBXML2
25392c393a42Smrg	if (xmlParseChunk (p, buf, len, len == 0))
25402c393a42Smrg#else
25412c393a42Smrg	if (!XML_ParseBuffer (p, len, len == 0))
25422c393a42Smrg#endif
25432c393a42Smrg	{
25442c393a42Smrg	    FcConfigMessage (&parse, FcSevereError, "%s",
25452c393a42Smrg			   XML_ErrorString (XML_GetErrorCode (p)));
25462c393a42Smrg	    goto bail3;
25472c393a42Smrg	}
25482c393a42Smrg    } while (len != 0);
25492c393a42Smrg    error = parse.error;
25502c393a42Smrgbail3:
25512c393a42Smrg    FcConfigCleanup (&parse);
25522c393a42Smrgbail2:
25532c393a42Smrg    XML_ParserFree (p);
25542c393a42Smrgbail1:
25552c393a42Smrg    close (fd);
25562c393a42Smrg    fd = -1;
25572c393a42Smrgbail0:
25582c393a42Smrg    if (error && complain)
25592c393a42Smrg    {
25602c393a42Smrg	if (name)
25612c393a42Smrg	    FcConfigMessage (0, FcSevereError, "Cannot load config file \"%s\"", name);
25622c393a42Smrg	else
25632c393a42Smrg	    FcConfigMessage (0, FcSevereError, "Cannot load default config file");
25642c393a42Smrg	return FcFalse;
25652c393a42Smrg    }
25662c393a42Smrg    return FcTrue;
25672c393a42Smrg}
25682c393a42Smrg#define __fcxml__
25692c393a42Smrg#include "fcaliastail.h"
25702c393a42Smrg#undef __fcxml__
2571