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