fcxml.c revision 953daeba
12c393a42Smrg/*
2a6844aabSmrg * fontconfig/src/fcxml.c
32c393a42Smrg *
42c393a42Smrg * Copyright © 2002 Keith Packard
52c393a42Smrg *
62c393a42Smrg * Permission to use, copy, modify, distribute, and sell this software and its
72c393a42Smrg * documentation for any purpose is hereby granted without fee, provided that
82c393a42Smrg * the above copyright notice appear in all copies and that both that
92c393a42Smrg * copyright notice and this permission notice appear in supporting
10ca08ab68Smrg * documentation, and that the name of the author(s) not be used in
112c393a42Smrg * advertising or publicity pertaining to distribution of the software without
12ca08ab68Smrg * specific, written prior permission.  The authors make no
132c393a42Smrg * representations about the suitability of this software for any purpose.  It
142c393a42Smrg * is provided "as is" without express or implied warranty.
152c393a42Smrg *
16a6844aabSmrg * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
172c393a42Smrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18a6844aabSmrg * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR
192c393a42Smrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
202c393a42Smrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
212c393a42Smrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
222c393a42Smrg * PERFORMANCE OF THIS SOFTWARE.
232c393a42Smrg */
242c393a42Smrg
252c393a42Smrg#include "fcint.h"
262c393a42Smrg#include <fcntl.h>
272c393a42Smrg#include <stdarg.h>
282c393a42Smrg#include <dirent.h>
292c393a42Smrg
302c393a42Smrg#ifdef ENABLE_LIBXML2
312c393a42Smrg
322c393a42Smrg#include <libxml/parser.h>
332c393a42Smrg
342c393a42Smrg#define XML_Char			xmlChar
352c393a42Smrg#define XML_Parser			xmlParserCtxtPtr
362c393a42Smrg#define XML_ParserFree			xmlFreeParserCtxt
372c393a42Smrg#define XML_GetCurrentLineNumber	xmlSAX2GetLineNumber
382c393a42Smrg#define XML_GetErrorCode		xmlCtxtGetLastError
392c393a42Smrg#define XML_ErrorString(Error)		(Error)->message
402c393a42Smrg
412c393a42Smrg#else /* ENABLE_LIBXML2 */
422c393a42Smrg
432c393a42Smrg#ifndef HAVE_XMLPARSE_H
442c393a42Smrg#define HAVE_XMLPARSE_H 0
452c393a42Smrg#endif
462c393a42Smrg
472c393a42Smrg#if HAVE_XMLPARSE_H
482c393a42Smrg#include <xmlparse.h>
492c393a42Smrg#else
502c393a42Smrg#include <expat.h>
512c393a42Smrg#endif
522c393a42Smrg
532c393a42Smrg#endif /* ENABLE_LIBXML2 */
542c393a42Smrg
552c393a42Smrg#ifdef _WIN32
56a6844aabSmrg#include <mbstring.h>
57953daebaSmrgextern FcChar8 fontconfig_instprefix[];
582c393a42Smrg#endif
592c393a42Smrg
60953daebaSmrgstatic FcChar8  *__fc_userdir = NULL;
61953daebaSmrgstatic FcChar8  *__fc_userconf = NULL;
62953daebaSmrg
63a6844aabSmrgstatic void
64a6844aabSmrgFcExprDestroy (FcExpr *e);
652c393a42Smrg
662c393a42Smrgvoid
672c393a42SmrgFcTestDestroy (FcTest *test)
682c393a42Smrg{
692c393a42Smrg    FcExprDestroy (test->expr);
702c393a42Smrg    free (test);
712c393a42Smrg}
722c393a42Smrg
736fc018e4Smrgvoid
746fc018e4SmrgFcRuleDestroy (FcRule *rule)
756fc018e4Smrg{
766fc018e4Smrg    FcRule *n = rule->next;
776fc018e4Smrg
786fc018e4Smrg    switch (rule->type) {
796fc018e4Smrg    case FcRuleTest:
806fc018e4Smrg	FcTestDestroy (rule->u.test);
816fc018e4Smrg	break;
826fc018e4Smrg    case FcRuleEdit:
836fc018e4Smrg	FcEditDestroy (rule->u.edit);
846fc018e4Smrg	break;
85953daebaSmrg    case FcRuleUnknown:
866fc018e4Smrg    default:
876fc018e4Smrg	break;
886fc018e4Smrg    }
896fc018e4Smrg    free (rule);
906fc018e4Smrg    if (n)
916fc018e4Smrg	FcRuleDestroy (n);
926fc018e4Smrg}
936fc018e4Smrg
94a6844aabSmrgstatic FcExpr *
95a6844aabSmrgFcExprCreateInteger (FcConfig *config, int i)
962c393a42Smrg{
97a6844aabSmrg    FcExpr *e = FcConfigAllocExpr (config);
982c393a42Smrg    if (e)
992c393a42Smrg    {
1002c393a42Smrg	e->op = FcOpInteger;
1012c393a42Smrg	e->u.ival = i;
1022c393a42Smrg    }
1032c393a42Smrg    return e;
1042c393a42Smrg}
1052c393a42Smrg
106a6844aabSmrgstatic FcExpr *
107a6844aabSmrgFcExprCreateDouble (FcConfig *config, double d)
1082c393a42Smrg{
109a6844aabSmrg    FcExpr *e = FcConfigAllocExpr (config);
1102c393a42Smrg    if (e)
1112c393a42Smrg    {
1122c393a42Smrg	e->op = FcOpDouble;
1132c393a42Smrg	e->u.dval = d;
1142c393a42Smrg    }
1152c393a42Smrg    return e;
1162c393a42Smrg}
1172c393a42Smrg
118a6844aabSmrgstatic FcExpr *
119a6844aabSmrgFcExprCreateString (FcConfig *config, const FcChar8 *s)
1202c393a42Smrg{
121a6844aabSmrg    FcExpr *e = FcConfigAllocExpr (config);
1222c393a42Smrg    if (e)
1232c393a42Smrg    {
1242c393a42Smrg	e->op = FcOpString;
125c9710b42Smrg	e->u.sval = FcStrdup (s);
1262c393a42Smrg    }
1272c393a42Smrg    return e;
1282c393a42Smrg}
1292c393a42Smrg
130c9710b42Smrgstatic FcExprMatrix *
131c9710b42SmrgFcExprMatrixCopyShallow (const FcExprMatrix *matrix)
132c9710b42Smrg{
133c9710b42Smrg  FcExprMatrix *m = malloc (sizeof (FcExprMatrix));
134c9710b42Smrg  if (m)
135c9710b42Smrg  {
136c9710b42Smrg    *m = *matrix;
137c9710b42Smrg  }
138c9710b42Smrg  return m;
139c9710b42Smrg}
140c9710b42Smrg
141c9710b42Smrgstatic void
142c9710b42SmrgFcExprMatrixFreeShallow (FcExprMatrix *m)
143c9710b42Smrg{
144c9710b42Smrg  if (!m)
145c9710b42Smrg    return;
146c9710b42Smrg
147c9710b42Smrg  free (m);
148c9710b42Smrg}
149c9710b42Smrg
150c9710b42Smrgstatic void
151c9710b42SmrgFcExprMatrixFree (FcExprMatrix *m)
152c9710b42Smrg{
153c9710b42Smrg  if (!m)
154c9710b42Smrg    return;
155c9710b42Smrg
156c9710b42Smrg  FcExprDestroy (m->xx);
157c9710b42Smrg  FcExprDestroy (m->xy);
158c9710b42Smrg  FcExprDestroy (m->yx);
159c9710b42Smrg  FcExprDestroy (m->yy);
160c9710b42Smrg
161c9710b42Smrg  free (m);
162c9710b42Smrg}
163c9710b42Smrg
164a6844aabSmrgstatic FcExpr *
165c9710b42SmrgFcExprCreateMatrix (FcConfig *config, const FcExprMatrix *matrix)
1662c393a42Smrg{
167a6844aabSmrg    FcExpr *e = FcConfigAllocExpr (config);
1682c393a42Smrg    if (e)
1692c393a42Smrg    {
1702c393a42Smrg	e->op = FcOpMatrix;
171c9710b42Smrg	e->u.mexpr = FcExprMatrixCopyShallow (matrix);
1722c393a42Smrg    }
1732c393a42Smrg    return e;
1742c393a42Smrg}
1752c393a42Smrg
176953daebaSmrgstatic FcExpr *
177953daebaSmrgFcExprCreateRange (FcConfig *config, FcRange *range)
178953daebaSmrg{
179953daebaSmrg    FcExpr *e = FcConfigAllocExpr (config);
180953daebaSmrg    if (e)
181953daebaSmrg    {
182953daebaSmrg	e->op = FcOpRange;
183953daebaSmrg	e->u.rval = FcRangeCopy (range);
184953daebaSmrg    }
185953daebaSmrg    return e;
186953daebaSmrg}
187953daebaSmrg
188a6844aabSmrgstatic FcExpr *
189a6844aabSmrgFcExprCreateBool (FcConfig *config, FcBool b)
1902c393a42Smrg{
191a6844aabSmrg    FcExpr *e = FcConfigAllocExpr (config);
1922c393a42Smrg    if (e)
1932c393a42Smrg    {
1942c393a42Smrg	e->op = FcOpBool;
1952c393a42Smrg	e->u.bval = b;
1962c393a42Smrg    }
1972c393a42Smrg    return e;
1982c393a42Smrg}
1992c393a42Smrg
200ca08ab68Smrgstatic FcExpr *
201ca08ab68SmrgFcExprCreateCharSet (FcConfig *config, FcCharSet *charset)
202ca08ab68Smrg{
203ca08ab68Smrg    FcExpr *e = FcConfigAllocExpr (config);
204ca08ab68Smrg    if (e)
205ca08ab68Smrg    {
206ca08ab68Smrg	e->op = FcOpCharSet;
207ca08ab68Smrg	e->u.cval = FcCharSetCopy (charset);
208ca08ab68Smrg    }
209ca08ab68Smrg    return e;
210ca08ab68Smrg}
211ca08ab68Smrg
212ca08ab68Smrgstatic FcExpr *
213ca08ab68SmrgFcExprCreateLangSet (FcConfig *config, FcLangSet *langset)
214ca08ab68Smrg{
215ca08ab68Smrg    FcExpr *e = FcConfigAllocExpr (config);
216ca08ab68Smrg    if (e)
217ca08ab68Smrg    {
218ca08ab68Smrg	e->op = FcOpLangSet;
219ca08ab68Smrg	e->u.lval = FcLangSetCopy (langset);
220ca08ab68Smrg    }
221ca08ab68Smrg    return e;
222ca08ab68Smrg}
223ca08ab68Smrg
224a6844aabSmrgstatic FcExpr *
225c9710b42SmrgFcExprCreateName (FcConfig *config, FcExprName name)
2262c393a42Smrg{
227a6844aabSmrg    FcExpr *e = FcConfigAllocExpr (config);
2282c393a42Smrg    if (e)
2292c393a42Smrg    {
2302c393a42Smrg	e->op = FcOpField;
231c9710b42Smrg	e->u.name = name;
2322c393a42Smrg    }
2332c393a42Smrg    return e;
2342c393a42Smrg}
2352c393a42Smrg
236a6844aabSmrgstatic FcExpr *
237a6844aabSmrgFcExprCreateConst (FcConfig *config, const FcChar8 *constant)
2382c393a42Smrg{
239a6844aabSmrg    FcExpr *e = FcConfigAllocExpr (config);
2402c393a42Smrg    if (e)
2412c393a42Smrg    {
2422c393a42Smrg	e->op = FcOpConst;
243c9710b42Smrg	e->u.constant = FcStrdup (constant);
2442c393a42Smrg    }
2452c393a42Smrg    return e;
2462c393a42Smrg}
2472c393a42Smrg
248a6844aabSmrgstatic FcExpr *
249a6844aabSmrgFcExprCreateOp (FcConfig *config, FcExpr *left, FcOp op, FcExpr *right)
2502c393a42Smrg{
251a6844aabSmrg    FcExpr *e = FcConfigAllocExpr (config);
2522c393a42Smrg    if (e)
2532c393a42Smrg    {
2542c393a42Smrg	e->op = op;
2552c393a42Smrg	e->u.tree.left = left;
2562c393a42Smrg	e->u.tree.right = right;
2572c393a42Smrg    }
2582c393a42Smrg    return e;
2592c393a42Smrg}
2602c393a42Smrg
261a6844aabSmrgstatic void
2622c393a42SmrgFcExprDestroy (FcExpr *e)
2632c393a42Smrg{
2642c393a42Smrg    if (!e)
2652c393a42Smrg	return;
266ca08ab68Smrg    switch (FC_OP_GET_OP (e->op)) {
2672c393a42Smrg    case FcOpInteger:
2682c393a42Smrg	break;
2692c393a42Smrg    case FcOpDouble:
2702c393a42Smrg	break;
2712c393a42Smrg    case FcOpString:
272c9710b42Smrg	FcFree (e->u.sval);
2732c393a42Smrg	break;
2742c393a42Smrg    case FcOpMatrix:
275c9710b42Smrg	FcExprMatrixFree (e->u.mexpr);
2762c393a42Smrg	break;
277ca08ab68Smrg    case FcOpRange:
278953daebaSmrg	FcRangeDestroy (e->u.rval);
279ca08ab68Smrg	break;
2802c393a42Smrg    case FcOpCharSet:
2812c393a42Smrg	FcCharSetDestroy (e->u.cval);
2822c393a42Smrg	break;
283ca08ab68Smrg    case FcOpLangSet:
284ca08ab68Smrg	FcLangSetDestroy (e->u.lval);
285ca08ab68Smrg	break;
2862c393a42Smrg    case FcOpBool:
2872c393a42Smrg	break;
2882c393a42Smrg    case FcOpField:
2892c393a42Smrg	break;
2902c393a42Smrg    case FcOpConst:
291c9710b42Smrg	FcFree (e->u.constant);
2922c393a42Smrg	break;
2932c393a42Smrg    case FcOpAssign:
2942c393a42Smrg    case FcOpAssignReplace:
2952c393a42Smrg    case FcOpPrepend:
2962c393a42Smrg    case FcOpPrependFirst:
2972c393a42Smrg    case FcOpAppend:
2982c393a42Smrg    case FcOpAppendLast:
299c9710b42Smrg    case FcOpDelete:
300c9710b42Smrg    case FcOpDeleteAll:
3012c393a42Smrg	break;
3022c393a42Smrg    case FcOpOr:
3032c393a42Smrg    case FcOpAnd:
3042c393a42Smrg    case FcOpEqual:
3052c393a42Smrg    case FcOpNotEqual:
3062c393a42Smrg    case FcOpLess:
3072c393a42Smrg    case FcOpLessEqual:
3082c393a42Smrg    case FcOpMore:
3092c393a42Smrg    case FcOpMoreEqual:
3102c393a42Smrg    case FcOpContains:
3112c393a42Smrg    case FcOpListing:
3122c393a42Smrg    case FcOpNotContains:
3132c393a42Smrg    case FcOpPlus:
3142c393a42Smrg    case FcOpMinus:
3152c393a42Smrg    case FcOpTimes:
3162c393a42Smrg    case FcOpDivide:
3172c393a42Smrg    case FcOpQuest:
3182c393a42Smrg    case FcOpComma:
3192c393a42Smrg	FcExprDestroy (e->u.tree.right);
3202c393a42Smrg	/* fall through */
3212c393a42Smrg    case FcOpNot:
3222c393a42Smrg    case FcOpFloor:
3232c393a42Smrg    case FcOpCeil:
3242c393a42Smrg    case FcOpRound:
3252c393a42Smrg    case FcOpTrunc:
3262c393a42Smrg	FcExprDestroy (e->u.tree.left);
3272c393a42Smrg	break;
3282c393a42Smrg    case FcOpNil:
3292c393a42Smrg    case FcOpInvalid:
3302c393a42Smrg	break;
3312c393a42Smrg    }
332a6844aabSmrg
333a6844aabSmrg    e->op = FcOpNil;
3342c393a42Smrg}
3352c393a42Smrg
3362c393a42Smrgvoid
3372c393a42SmrgFcEditDestroy (FcEdit *e)
3382c393a42Smrg{
3392c393a42Smrg    if (e->expr)
3402c393a42Smrg	FcExprDestroy (e->expr);
3412c393a42Smrg    free (e);
3422c393a42Smrg}
3432c393a42Smrg
3442c393a42Smrgtypedef enum _FcElement {
3452c393a42Smrg    FcElementNone,
3462c393a42Smrg    FcElementFontconfig,
3472c393a42Smrg    FcElementDir,
3482c393a42Smrg    FcElementCacheDir,
3492c393a42Smrg    FcElementCache,
3502c393a42Smrg    FcElementInclude,
3512c393a42Smrg    FcElementConfig,
3522c393a42Smrg    FcElementMatch,
3532c393a42Smrg    FcElementAlias,
3542c393a42Smrg
3552c393a42Smrg    FcElementBlank,
3562c393a42Smrg    FcElementRescan,
3572c393a42Smrg
3582c393a42Smrg    FcElementPrefer,
3592c393a42Smrg    FcElementAccept,
3602c393a42Smrg    FcElementDefault,
3612c393a42Smrg    FcElementFamily,
3622c393a42Smrg
3632c393a42Smrg    FcElementSelectfont,
3642c393a42Smrg    FcElementAcceptfont,
3652c393a42Smrg    FcElementRejectfont,
3662c393a42Smrg    FcElementGlob,
3672c393a42Smrg    FcElementPattern,
3682c393a42Smrg    FcElementPatelt,
3692c393a42Smrg
3702c393a42Smrg    FcElementTest,
3712c393a42Smrg    FcElementEdit,
3722c393a42Smrg    FcElementInt,
3732c393a42Smrg    FcElementDouble,
3742c393a42Smrg    FcElementString,
3752c393a42Smrg    FcElementMatrix,
376ca08ab68Smrg    FcElementRange,
3772c393a42Smrg    FcElementBool,
378ca08ab68Smrg    FcElementCharSet,
379ca08ab68Smrg    FcElementLangSet,
3802c393a42Smrg    FcElementName,
3812c393a42Smrg    FcElementConst,
3822c393a42Smrg    FcElementOr,
3832c393a42Smrg    FcElementAnd,
3842c393a42Smrg    FcElementEq,
3852c393a42Smrg    FcElementNotEq,
3862c393a42Smrg    FcElementLess,
3872c393a42Smrg    FcElementLessEq,
3882c393a42Smrg    FcElementMore,
3892c393a42Smrg    FcElementMoreEq,
3902c393a42Smrg    FcElementContains,
3912c393a42Smrg    FcElementNotContains,
3922c393a42Smrg    FcElementPlus,
3932c393a42Smrg    FcElementMinus,
3942c393a42Smrg    FcElementTimes,
3952c393a42Smrg    FcElementDivide,
3962c393a42Smrg    FcElementNot,
3972c393a42Smrg    FcElementIf,
3982c393a42Smrg    FcElementFloor,
3992c393a42Smrg    FcElementCeil,
4002c393a42Smrg    FcElementRound,
4012c393a42Smrg    FcElementTrunc,
4022c393a42Smrg    FcElementUnknown
4032c393a42Smrg} FcElement;
4042c393a42Smrg
4052c393a42Smrgstatic const struct {
4062c393a42Smrg    const char  name[16];
4072c393a42Smrg    FcElement   element;
4082c393a42Smrg} fcElementMap[] = {
4092c393a42Smrg    { "fontconfig",	FcElementFontconfig },
4102c393a42Smrg    { "dir",		FcElementDir },
4112c393a42Smrg    { "cachedir",	FcElementCacheDir },
4122c393a42Smrg    { "cache",		FcElementCache },
4132c393a42Smrg    { "include",	FcElementInclude },
4142c393a42Smrg    { "config",		FcElementConfig },
4152c393a42Smrg    { "match",		FcElementMatch },
4162c393a42Smrg    { "alias",		FcElementAlias },
417ca08ab68Smrg
4182c393a42Smrg    { "blank",		FcElementBlank },
4192c393a42Smrg    { "rescan",		FcElementRescan },
4202c393a42Smrg
4212c393a42Smrg    { "prefer",		FcElementPrefer },
4222c393a42Smrg    { "accept",		FcElementAccept },
4232c393a42Smrg    { "default",	FcElementDefault },
4242c393a42Smrg    { "family",		FcElementFamily },
4252c393a42Smrg
4262c393a42Smrg    { "selectfont",	FcElementSelectfont },
4272c393a42Smrg    { "acceptfont",	FcElementAcceptfont },
4282c393a42Smrg    { "rejectfont",	FcElementRejectfont },
4292c393a42Smrg    { "glob",		FcElementGlob },
4302c393a42Smrg    { "pattern",	FcElementPattern },
4312c393a42Smrg    { "patelt",		FcElementPatelt },
4322c393a42Smrg
4332c393a42Smrg    { "test",		FcElementTest },
4342c393a42Smrg    { "edit",		FcElementEdit },
4352c393a42Smrg    { "int",		FcElementInt },
4362c393a42Smrg    { "double",		FcElementDouble },
4372c393a42Smrg    { "string",		FcElementString },
4382c393a42Smrg    { "matrix",		FcElementMatrix },
439ca08ab68Smrg    { "range",		FcElementRange },
4402c393a42Smrg    { "bool",		FcElementBool },
441ca08ab68Smrg    { "charset",	FcElementCharSet },
442ca08ab68Smrg    { "langset",	FcElementLangSet },
4432c393a42Smrg    { "name",		FcElementName },
4442c393a42Smrg    { "const",		FcElementConst },
4452c393a42Smrg    { "or",		FcElementOr },
4462c393a42Smrg    { "and",		FcElementAnd },
4472c393a42Smrg    { "eq",		FcElementEq },
4482c393a42Smrg    { "not_eq",		FcElementNotEq },
4492c393a42Smrg    { "less",		FcElementLess },
4502c393a42Smrg    { "less_eq",	FcElementLessEq },
4512c393a42Smrg    { "more",		FcElementMore },
4522c393a42Smrg    { "more_eq",	FcElementMoreEq },
4532c393a42Smrg    { "contains",	FcElementContains },
4542c393a42Smrg    { "not_contains",	FcElementNotContains },
4552c393a42Smrg    { "plus",		FcElementPlus },
4562c393a42Smrg    { "minus",		FcElementMinus },
4572c393a42Smrg    { "times",		FcElementTimes },
4582c393a42Smrg    { "divide",		FcElementDivide },
4592c393a42Smrg    { "not",		FcElementNot },
4602c393a42Smrg    { "if",		FcElementIf },
4612c393a42Smrg    { "floor",		FcElementFloor },
4622c393a42Smrg    { "ceil",		FcElementCeil },
4632c393a42Smrg    { "round",		FcElementRound },
4642c393a42Smrg    { "trunc",		FcElementTrunc },
4652c393a42Smrg};
4662c393a42Smrg#define NUM_ELEMENT_MAPS (int) (sizeof fcElementMap / sizeof fcElementMap[0])
4672c393a42Smrg
4682c393a42Smrgstatic FcElement
4692c393a42SmrgFcElementMap (const XML_Char *name)
4702c393a42Smrg{
4712c393a42Smrg
4722c393a42Smrg    int	    i;
4732c393a42Smrg    for (i = 0; i < NUM_ELEMENT_MAPS; i++)
4742c393a42Smrg	if (!strcmp ((char *) name, fcElementMap[i].name))
4752c393a42Smrg	    return fcElementMap[i].element;
4762c393a42Smrg    return FcElementUnknown;
4772c393a42Smrg}
4782c393a42Smrg
4792c393a42Smrgtypedef struct _FcPStack {
4802c393a42Smrg    struct _FcPStack   *prev;
4812c393a42Smrg    FcElement		element;
4822c393a42Smrg    FcChar8		**attr;
4832c393a42Smrg    FcStrBuf		str;
484a6844aabSmrg    FcChar8            *attr_buf_static[16];
4852c393a42Smrg} FcPStack;
486ca08ab68Smrg
4872c393a42Smrgtypedef enum _FcVStackTag {
4882c393a42Smrg    FcVStackNone,
4892c393a42Smrg
4902c393a42Smrg    FcVStackString,
4912c393a42Smrg    FcVStackFamily,
4922c393a42Smrg    FcVStackConstant,
4932c393a42Smrg    FcVStackGlob,
494c9710b42Smrg    FcVStackName,
4952c393a42Smrg    FcVStackPattern,
496ca08ab68Smrg
4972c393a42Smrg    FcVStackPrefer,
4982c393a42Smrg    FcVStackAccept,
4992c393a42Smrg    FcVStackDefault,
500ca08ab68Smrg
5012c393a42Smrg    FcVStackInteger,
5022c393a42Smrg    FcVStackDouble,
5032c393a42Smrg    FcVStackMatrix,
504ca08ab68Smrg    FcVStackRange,
5052c393a42Smrg    FcVStackBool,
506ca08ab68Smrg    FcVStackCharSet,
507ca08ab68Smrg    FcVStackLangSet,
508ca08ab68Smrg
5092c393a42Smrg    FcVStackTest,
5102c393a42Smrg    FcVStackExpr,
5112c393a42Smrg    FcVStackEdit
5122c393a42Smrg} FcVStackTag;
5132c393a42Smrg
5142c393a42Smrgtypedef struct _FcVStack {
5152c393a42Smrg    struct _FcVStack	*prev;
5162c393a42Smrg    FcPStack		*pstack;	/* related parse element */
5172c393a42Smrg    FcVStackTag		tag;
5182c393a42Smrg    union {
5192c393a42Smrg	FcChar8		*string;
5202c393a42Smrg
5212c393a42Smrg	int		integer;
5222c393a42Smrg	double		_double;
523c9710b42Smrg	FcExprMatrix	*matrix;
524953daebaSmrg	FcRange		*range;
525a6844aabSmrg	FcBool		bool_;
526ca08ab68Smrg	FcCharSet	*charset;
527ca08ab68Smrg	FcLangSet	*langset;
528c9710b42Smrg	FcExprName	name;
5292c393a42Smrg
5302c393a42Smrg	FcTest		*test;
5312c393a42Smrg	FcQual		qual;
5322c393a42Smrg	FcOp		op;
5332c393a42Smrg	FcExpr		*expr;
5342c393a42Smrg	FcEdit		*edit;
5352c393a42Smrg
5362c393a42Smrg	FcPattern	*pattern;
5372c393a42Smrg    } u;
5382c393a42Smrg} FcVStack;
5392c393a42Smrg
5402c393a42Smrgtypedef struct _FcConfigParse {
5412c393a42Smrg    FcPStack	    *pstack;
5422c393a42Smrg    FcVStack	    *vstack;
5432c393a42Smrg    FcBool	    error;
5442c393a42Smrg    const FcChar8   *name;
5452c393a42Smrg    FcConfig	    *config;
5462c393a42Smrg    XML_Parser	    parser;
547c9710b42Smrg    unsigned int    pstack_static_used;
548a6844aabSmrg    FcPStack        pstack_static[8];
549c9710b42Smrg    unsigned int    vstack_static_used;
550a6844aabSmrg    FcVStack        vstack_static[64];
5512c393a42Smrg} FcConfigParse;
5522c393a42Smrg
5532c393a42Smrgtypedef enum _FcConfigSeverity {
5542c393a42Smrg    FcSevereInfo, FcSevereWarning, FcSevereError
5552c393a42Smrg} FcConfigSeverity;
5562c393a42Smrg
5572c393a42Smrgstatic void
5582c393a42SmrgFcConfigMessage (FcConfigParse *parse, FcConfigSeverity severe, const char *fmt, ...)
5592c393a42Smrg{
5602c393a42Smrg    const char	*s = "unknown";
5612c393a42Smrg    va_list	args;
5622c393a42Smrg
5632c393a42Smrg    va_start (args, fmt);
5642c393a42Smrg
5652c393a42Smrg    switch (severe) {
5662c393a42Smrg    case FcSevereInfo: s = "info"; break;
5672c393a42Smrg    case FcSevereWarning: s = "warning"; break;
5682c393a42Smrg    case FcSevereError: s = "error"; break;
5692c393a42Smrg    }
5702c393a42Smrg    if (parse)
5712c393a42Smrg    {
5722c393a42Smrg	if (parse->name)
5732c393a42Smrg	    fprintf (stderr, "Fontconfig %s: \"%s\", line %d: ", s,
5742c393a42Smrg		     parse->name, (int)XML_GetCurrentLineNumber (parse->parser));
5752c393a42Smrg	else
5762c393a42Smrg	    fprintf (stderr, "Fontconfig %s: line %d: ", s,
5772c393a42Smrg		     (int)XML_GetCurrentLineNumber (parse->parser));
5782c393a42Smrg	if (severe >= FcSevereError)
5792c393a42Smrg	    parse->error = FcTrue;
5802c393a42Smrg    }
5812c393a42Smrg    else
5822c393a42Smrg	fprintf (stderr, "Fontconfig %s: ", s);
5832c393a42Smrg    vfprintf (stderr, fmt, args);
5842c393a42Smrg    fprintf (stderr, "\n");
5852c393a42Smrg    va_end (args);
5862c393a42Smrg}
5872c393a42Smrg
5882c393a42Smrg
589c9710b42Smrgstatic FcExpr *
590c9710b42SmrgFcPopExpr (FcConfigParse *parse);
591c9710b42Smrg
592c9710b42Smrg
5932c393a42Smrgstatic const char *
5942c393a42SmrgFcTypeName (FcType type)
5952c393a42Smrg{
5962c393a42Smrg    switch (type) {
5972c393a42Smrg    case FcTypeVoid:
5982c393a42Smrg	return "void";
5992c393a42Smrg    case FcTypeInteger:
6002c393a42Smrg    case FcTypeDouble:
6012c393a42Smrg	return "number";
6022c393a42Smrg    case FcTypeString:
6032c393a42Smrg	return "string";
6042c393a42Smrg    case FcTypeBool:
6052c393a42Smrg	return "bool";
6062c393a42Smrg    case FcTypeMatrix:
6072c393a42Smrg	return "matrix";
6082c393a42Smrg    case FcTypeCharSet:
6092c393a42Smrg	return "charset";
6102c393a42Smrg    case FcTypeFTFace:
6112c393a42Smrg	return "FT_Face";
6122c393a42Smrg    case FcTypeLangSet:
6132c393a42Smrg	return "langset";
614953daebaSmrg    case FcTypeRange:
615953daebaSmrg	return "range";
616953daebaSmrg    case FcTypeUnknown:
6172c393a42Smrg    default:
6182c393a42Smrg	return "unknown";
6192c393a42Smrg    }
6202c393a42Smrg}
6212c393a42Smrg
6222c393a42Smrgstatic void
6232c393a42SmrgFcTypecheckValue (FcConfigParse *parse, FcType value, FcType type)
6242c393a42Smrg{
6252c393a42Smrg    if (value == FcTypeInteger)
6262c393a42Smrg	value = FcTypeDouble;
6272c393a42Smrg    if (type == FcTypeInteger)
6282c393a42Smrg	type = FcTypeDouble;
6292c393a42Smrg    if (value != type)
6302c393a42Smrg    {
6312c393a42Smrg	if ((value == FcTypeLangSet && type == FcTypeString) ||
632953daebaSmrg	    (value == FcTypeString && type == FcTypeLangSet) ||
633953daebaSmrg	    (value == FcTypeInteger && type == FcTypeRange) ||
634953daebaSmrg	    (value == FcTypeDouble && type == FcTypeRange))
6352c393a42Smrg	    return;
636b09479dcSmrg	if (type ==  FcTypeUnknown)
6372c393a42Smrg	    return;
638c9710b42Smrg	/* It's perfectly fine to use user-define elements in expressions,
639c9710b42Smrg	 * so don't warn in that case. */
640b09479dcSmrg	if (value == FcTypeUnknown)
641c9710b42Smrg	    return;
6422c393a42Smrg	FcConfigMessage (parse, FcSevereWarning, "saw %s, expected %s",
6432c393a42Smrg			 FcTypeName (value), FcTypeName (type));
6442c393a42Smrg    }
6452c393a42Smrg}
6462c393a42Smrg
6472c393a42Smrgstatic void
6482c393a42SmrgFcTypecheckExpr (FcConfigParse *parse, FcExpr *expr, FcType type)
6492c393a42Smrg{
6502c393a42Smrg    const FcObjectType	*o;
6512c393a42Smrg    const FcConstant	*c;
652ca08ab68Smrg
6532c393a42Smrg    /* If parsing the expression failed, some nodes may be NULL */
6542c393a42Smrg    if (!expr)
6552c393a42Smrg	return;
6562c393a42Smrg
657ca08ab68Smrg    switch (FC_OP_GET_OP (expr->op)) {
6582c393a42Smrg    case FcOpInteger:
6592c393a42Smrg    case FcOpDouble:
6602c393a42Smrg	FcTypecheckValue (parse, FcTypeDouble, type);
6612c393a42Smrg	break;
6622c393a42Smrg    case FcOpString:
6632c393a42Smrg	FcTypecheckValue (parse, FcTypeString, type);
6642c393a42Smrg	break;
6652c393a42Smrg    case FcOpMatrix:
6662c393a42Smrg	FcTypecheckValue (parse, FcTypeMatrix, type);
6672c393a42Smrg	break;
6682c393a42Smrg    case FcOpBool:
6692c393a42Smrg	FcTypecheckValue (parse, FcTypeBool, type);
6702c393a42Smrg	break;
6712c393a42Smrg    case FcOpCharSet:
6722c393a42Smrg	FcTypecheckValue (parse, FcTypeCharSet, type);
6732c393a42Smrg	break;
674ca08ab68Smrg    case FcOpLangSet:
675ca08ab68Smrg	FcTypecheckValue (parse, FcTypeLangSet, type);
676ca08ab68Smrg	break;
677953daebaSmrg    case FcOpRange:
678953daebaSmrg	FcTypecheckValue (parse, FcTypeRange, type);
679953daebaSmrg	break;
6802c393a42Smrg    case FcOpNil:
6812c393a42Smrg	break;
6822c393a42Smrg    case FcOpField:
683c9710b42Smrg	o = FcNameGetObjectType (FcObjectName (expr->u.name.object));
6842c393a42Smrg	if (o)
6852c393a42Smrg	    FcTypecheckValue (parse, o->type, type);
6862c393a42Smrg	break;
6872c393a42Smrg    case FcOpConst:
6882c393a42Smrg	c = FcNameGetConstant (expr->u.constant);
6892c393a42Smrg	if (c)
6902c393a42Smrg	{
6912c393a42Smrg	    o = FcNameGetObjectType (c->object);
6922c393a42Smrg	    if (o)
6932c393a42Smrg		FcTypecheckValue (parse, o->type, type);
6942c393a42Smrg	}
695ca08ab68Smrg        else
696ca08ab68Smrg            FcConfigMessage (parse, FcSevereWarning,
6972c393a42Smrg                             "invalid constant used : %s",
6982c393a42Smrg                             expr->u.constant);
6992c393a42Smrg	break;
7002c393a42Smrg    case FcOpQuest:
7012c393a42Smrg	FcTypecheckExpr (parse, expr->u.tree.left, FcTypeBool);
7022c393a42Smrg	FcTypecheckExpr (parse, expr->u.tree.right->u.tree.left, type);
7032c393a42Smrg	FcTypecheckExpr (parse, expr->u.tree.right->u.tree.right, type);
7042c393a42Smrg	break;
7052c393a42Smrg    case FcOpAssign:
7062c393a42Smrg    case FcOpAssignReplace:
7072c393a42Smrg	break;
7082c393a42Smrg    case FcOpEqual:
7092c393a42Smrg    case FcOpNotEqual:
7102c393a42Smrg    case FcOpLess:
7112c393a42Smrg    case FcOpLessEqual:
7122c393a42Smrg    case FcOpMore:
7132c393a42Smrg    case FcOpMoreEqual:
7142c393a42Smrg    case FcOpContains:
7152c393a42Smrg    case FcOpNotContains:
7162c393a42Smrg    case FcOpListing:
7172c393a42Smrg	FcTypecheckValue (parse, FcTypeBool, type);
7182c393a42Smrg	break;
7192c393a42Smrg    case FcOpComma:
7202c393a42Smrg    case FcOpOr:
7212c393a42Smrg    case FcOpAnd:
7222c393a42Smrg    case FcOpPlus:
7232c393a42Smrg    case FcOpMinus:
7242c393a42Smrg    case FcOpTimes:
7252c393a42Smrg    case FcOpDivide:
7262c393a42Smrg	FcTypecheckExpr (parse, expr->u.tree.left, type);
7272c393a42Smrg	FcTypecheckExpr (parse, expr->u.tree.right, type);
7282c393a42Smrg	break;
7292c393a42Smrg    case FcOpNot:
7302c393a42Smrg	FcTypecheckValue (parse, FcTypeBool, type);
7312c393a42Smrg	FcTypecheckExpr (parse, expr->u.tree.left, FcTypeBool);
7322c393a42Smrg	break;
7332c393a42Smrg    case FcOpFloor:
7342c393a42Smrg    case FcOpCeil:
7352c393a42Smrg    case FcOpRound:
7362c393a42Smrg    case FcOpTrunc:
7372c393a42Smrg	FcTypecheckValue (parse, FcTypeDouble, type);
7382c393a42Smrg	FcTypecheckExpr (parse, expr->u.tree.left, FcTypeDouble);
7392c393a42Smrg	break;
7402c393a42Smrg    default:
7412c393a42Smrg	break;
7422c393a42Smrg    }
7432c393a42Smrg}
7442c393a42Smrg
7452c393a42Smrgstatic FcTest *
7462c393a42SmrgFcTestCreate (FcConfigParse *parse,
747ca08ab68Smrg	      FcMatchKind   kind,
7482c393a42Smrg	      FcQual	    qual,
7492c393a42Smrg	      const FcChar8 *field,
7506fc018e4Smrg	      unsigned int  compare,
7512c393a42Smrg	      FcExpr	    *expr)
7522c393a42Smrg{
7532c393a42Smrg    FcTest	*test = (FcTest *) malloc (sizeof (FcTest));
7542c393a42Smrg
7552c393a42Smrg    if (test)
7562c393a42Smrg    {
7572c393a42Smrg	const FcObjectType	*o;
7582c393a42Smrg
7592c393a42Smrg	test->kind = kind;
7602c393a42Smrg	test->qual = qual;
7612c393a42Smrg	test->object = FcObjectFromName ((const char *) field);
7622c393a42Smrg	test->op = compare;
7632c393a42Smrg	test->expr = expr;
7642c393a42Smrg	o = FcNameGetObjectType (FcObjectName (test->object));
7652c393a42Smrg	if (o)
7662c393a42Smrg	    FcTypecheckExpr (parse, expr, o->type);
7672c393a42Smrg    }
7682c393a42Smrg    return test;
7692c393a42Smrg}
7702c393a42Smrg
7712c393a42Smrgstatic FcEdit *
7722c393a42SmrgFcEditCreate (FcConfigParse	*parse,
7732c393a42Smrg	      FcObject		object,
7742c393a42Smrg	      FcOp		op,
7752c393a42Smrg	      FcExpr		*expr,
7762c393a42Smrg	      FcValueBinding	binding)
7772c393a42Smrg{
7782c393a42Smrg    FcEdit *e = (FcEdit *) malloc (sizeof (FcEdit));
7792c393a42Smrg
7802c393a42Smrg    if (e)
7812c393a42Smrg    {
7822c393a42Smrg	const FcObjectType	*o;
7832c393a42Smrg
7842c393a42Smrg	e->object = object;
7852c393a42Smrg	e->op = op;
7862c393a42Smrg	e->expr = expr;
7872c393a42Smrg	e->binding = binding;
7882c393a42Smrg	o = FcNameGetObjectType (FcObjectName (e->object));
7892c393a42Smrg	if (o)
7902c393a42Smrg	    FcTypecheckExpr (parse, expr, o->type);
7912c393a42Smrg    }
7922c393a42Smrg    return e;
7932c393a42Smrg}
7942c393a42Smrg
7956fc018e4Smrgstatic FcRule *
7966fc018e4SmrgFcRuleCreate (FcRuleType type,
7976fc018e4Smrg	      void       *p)
7986fc018e4Smrg{
7996fc018e4Smrg    FcRule *r = (FcRule *) malloc (sizeof (FcRule));
8006fc018e4Smrg
8016fc018e4Smrg    if (!r)
8026fc018e4Smrg	return NULL;
8036fc018e4Smrg
8046fc018e4Smrg    r->next = NULL;
8056fc018e4Smrg    r->type = type;
8066fc018e4Smrg    switch (type)
8076fc018e4Smrg    {
8086fc018e4Smrg    case FcRuleTest:
8096fc018e4Smrg	r->u.test = (FcTest *) p;
8106fc018e4Smrg	break;
8116fc018e4Smrg    case FcRuleEdit:
8126fc018e4Smrg	r->u.edit = (FcEdit *) p;
8136fc018e4Smrg	break;
814953daebaSmrg    case FcRuleUnknown:
8156fc018e4Smrg    default:
8166fc018e4Smrg	free (r);
8176fc018e4Smrg	r = NULL;
8186fc018e4Smrg	break;
8196fc018e4Smrg    }
8206fc018e4Smrg
8216fc018e4Smrg    return r;
8226fc018e4Smrg}
8236fc018e4Smrg
8242c393a42Smrgstatic FcVStack *
825a6844aabSmrgFcVStackCreateAndPush (FcConfigParse *parse)
8262c393a42Smrg{
8272c393a42Smrg    FcVStack    *new;
8282c393a42Smrg
829a6844aabSmrg    if (parse->vstack_static_used < sizeof (parse->vstack_static) / sizeof (parse->vstack_static[0]))
830a6844aabSmrg	new = &parse->vstack_static[parse->vstack_static_used++];
831a6844aabSmrg    else
832a6844aabSmrg    {
833a6844aabSmrg	new = malloc (sizeof (FcVStack));
834a6844aabSmrg	if (!new)
835a6844aabSmrg	    return 0;
836a6844aabSmrg    }
8372c393a42Smrg    new->tag = FcVStackNone;
8382c393a42Smrg    new->prev = 0;
8392c393a42Smrg
840a6844aabSmrg    new->prev = parse->vstack;
841a6844aabSmrg    new->pstack = parse->pstack ? parse->pstack->prev : 0;
842a6844aabSmrg    parse->vstack = new;
8432c393a42Smrg
844a6844aabSmrg    return new;
8452c393a42Smrg}
8462c393a42Smrg
8472c393a42Smrgstatic FcBool
8482c393a42SmrgFcVStackPushString (FcConfigParse *parse, FcVStackTag tag, FcChar8 *string)
8492c393a42Smrg{
850a6844aabSmrg    FcVStack    *vstack = FcVStackCreateAndPush (parse);
8512c393a42Smrg    if (!vstack)
8522c393a42Smrg	return FcFalse;
8532c393a42Smrg    vstack->u.string = string;
8542c393a42Smrg    vstack->tag = tag;
8552c393a42Smrg    return FcTrue;
8562c393a42Smrg}
8572c393a42Smrg
8582c393a42Smrgstatic FcBool
8592c393a42SmrgFcVStackPushInteger (FcConfigParse *parse, int integer)
8602c393a42Smrg{
861a6844aabSmrg    FcVStack    *vstack = FcVStackCreateAndPush (parse);
8622c393a42Smrg    if (!vstack)
8632c393a42Smrg	return FcFalse;
8642c393a42Smrg    vstack->u.integer = integer;
8652c393a42Smrg    vstack->tag = FcVStackInteger;
8662c393a42Smrg    return FcTrue;
8672c393a42Smrg}
8682c393a42Smrg
8692c393a42Smrgstatic FcBool
8702c393a42SmrgFcVStackPushDouble (FcConfigParse *parse, double _double)
8712c393a42Smrg{
872a6844aabSmrg    FcVStack    *vstack = FcVStackCreateAndPush (parse);
8732c393a42Smrg    if (!vstack)
8742c393a42Smrg	return FcFalse;
8752c393a42Smrg    vstack->u._double = _double;
8762c393a42Smrg    vstack->tag = FcVStackDouble;
8772c393a42Smrg    return FcTrue;
8782c393a42Smrg}
8792c393a42Smrg
8802c393a42Smrgstatic FcBool
881c9710b42SmrgFcVStackPushMatrix (FcConfigParse *parse, FcExprMatrix *matrix)
8822c393a42Smrg{
883a6844aabSmrg    FcVStack    *vstack;
884a6844aabSmrg    vstack = FcVStackCreateAndPush (parse);
885a6844aabSmrg    if (!vstack)
886a6844aabSmrg	return FcFalse;
887c9710b42Smrg    vstack->u.matrix = FcExprMatrixCopyShallow (matrix);
8882c393a42Smrg    vstack->tag = FcVStackMatrix;
8892c393a42Smrg    return FcTrue;
8902c393a42Smrg}
8912c393a42Smrg
892ca08ab68Smrgstatic FcBool
893ca08ab68SmrgFcVStackPushRange (FcConfigParse *parse, FcRange *range)
894ca08ab68Smrg{
895953daebaSmrg    FcVStack 	*vstack = FcVStackCreateAndPush (parse);
896ca08ab68Smrg    if (!vstack)
897ca08ab68Smrg	return FcFalse;
898953daebaSmrg    vstack->u.range = range;
899ca08ab68Smrg    vstack->tag = FcVStackRange;
900ca08ab68Smrg    return FcTrue;
901ca08ab68Smrg}
902ca08ab68Smrg
9032c393a42Smrgstatic FcBool
904a6844aabSmrgFcVStackPushBool (FcConfigParse *parse, FcBool bool_)
9052c393a42Smrg{
906a6844aabSmrg    FcVStack    *vstack = FcVStackCreateAndPush (parse);
9072c393a42Smrg    if (!vstack)
9082c393a42Smrg	return FcFalse;
909a6844aabSmrg    vstack->u.bool_ = bool_;
9102c393a42Smrg    vstack->tag = FcVStackBool;
9112c393a42Smrg    return FcTrue;
9122c393a42Smrg}
9132c393a42Smrg
914ca08ab68Smrgstatic FcBool
915ca08ab68SmrgFcVStackPushCharSet (FcConfigParse *parse, FcCharSet *charset)
916ca08ab68Smrg{
917ca08ab68Smrg    FcVStack	*vstack;
918ca08ab68Smrg    if (!charset)
919ca08ab68Smrg	return FcFalse;
920ca08ab68Smrg    vstack = FcVStackCreateAndPush (parse);
921ca08ab68Smrg    if (!vstack)
922ca08ab68Smrg	return FcFalse;
923ca08ab68Smrg    vstack->u.charset = charset;
924ca08ab68Smrg    vstack->tag = FcVStackCharSet;
925ca08ab68Smrg    return FcTrue;
926ca08ab68Smrg}
927ca08ab68Smrg
928ca08ab68Smrgstatic FcBool
929ca08ab68SmrgFcVStackPushLangSet (FcConfigParse *parse, FcLangSet *langset)
930ca08ab68Smrg{
931ca08ab68Smrg    FcVStack	*vstack;
932ca08ab68Smrg    if (!langset)
933ca08ab68Smrg	return FcFalse;
934ca08ab68Smrg    vstack = FcVStackCreateAndPush (parse);
935ca08ab68Smrg    if (!vstack)
936ca08ab68Smrg	return FcFalse;
937ca08ab68Smrg    vstack->u.langset = langset;
938ca08ab68Smrg    vstack->tag = FcVStackLangSet;
939ca08ab68Smrg    return FcTrue;
940ca08ab68Smrg}
941ca08ab68Smrg
942c9710b42Smrgstatic FcBool
943c9710b42SmrgFcVStackPushName (FcConfigParse *parse, FcMatchKind kind, FcObject object)
944c9710b42Smrg{
945c9710b42Smrg    FcVStack    *vstack = FcVStackCreateAndPush (parse);
946c9710b42Smrg    if (!vstack)
947c9710b42Smrg	return FcFalse;
948c9710b42Smrg    vstack->u.name.object = object;
949c9710b42Smrg    vstack->u.name.kind = kind;
950c9710b42Smrg    vstack->tag = FcVStackName;
951c9710b42Smrg    return FcTrue;
952c9710b42Smrg}
953c9710b42Smrg
9542c393a42Smrgstatic FcBool
9552c393a42SmrgFcVStackPushTest (FcConfigParse *parse, FcTest *test)
9562c393a42Smrg{
957a6844aabSmrg    FcVStack    *vstack = FcVStackCreateAndPush (parse);
9582c393a42Smrg    if (!vstack)
9592c393a42Smrg	return FcFalse;
9602c393a42Smrg    vstack->u.test = test;
9612c393a42Smrg    vstack->tag = FcVStackTest;
9622c393a42Smrg    return FcTrue;
9632c393a42Smrg}
9642c393a42Smrg
9652c393a42Smrgstatic FcBool
9662c393a42SmrgFcVStackPushExpr (FcConfigParse *parse, FcVStackTag tag, FcExpr *expr)
9672c393a42Smrg{
968a6844aabSmrg    FcVStack    *vstack = FcVStackCreateAndPush (parse);
9692c393a42Smrg    if (!vstack)
9702c393a42Smrg	return FcFalse;
9712c393a42Smrg    vstack->u.expr = expr;
9722c393a42Smrg    vstack->tag = tag;
9732c393a42Smrg    return FcTrue;
9742c393a42Smrg}
9752c393a42Smrg
9762c393a42Smrgstatic FcBool
9772c393a42SmrgFcVStackPushEdit (FcConfigParse *parse, FcEdit *edit)
9782c393a42Smrg{
979a6844aabSmrg    FcVStack    *vstack = FcVStackCreateAndPush (parse);
9802c393a42Smrg    if (!vstack)
9812c393a42Smrg	return FcFalse;
9822c393a42Smrg    vstack->u.edit = edit;
9832c393a42Smrg    vstack->tag = FcVStackEdit;
9842c393a42Smrg    return FcTrue;
9852c393a42Smrg}
9862c393a42Smrg
9872c393a42Smrgstatic FcBool
9882c393a42SmrgFcVStackPushPattern (FcConfigParse *parse, FcPattern *pattern)
9892c393a42Smrg{
990a6844aabSmrg    FcVStack    *vstack = FcVStackCreateAndPush (parse);
9912c393a42Smrg    if (!vstack)
9922c393a42Smrg	return FcFalse;
9932c393a42Smrg    vstack->u.pattern = pattern;
9942c393a42Smrg    vstack->tag = FcVStackPattern;
9952c393a42Smrg    return FcTrue;
9962c393a42Smrg}
9972c393a42Smrg
9982c393a42Smrgstatic FcVStack *
9992c393a42SmrgFcVStackFetch (FcConfigParse *parse, int off)
10002c393a42Smrg{
10012c393a42Smrg    FcVStack    *vstack;
10022c393a42Smrg
10032c393a42Smrg    for (vstack = parse->vstack; vstack && off-- > 0; vstack = vstack->prev);
10042c393a42Smrg    return vstack;
10052c393a42Smrg}
10062c393a42Smrg
1007a6844aabSmrgstatic FcVStack *
1008a6844aabSmrgFcVStackPeek (FcConfigParse *parse)
10092c393a42Smrg{
1010a6844aabSmrg    FcVStack	*vstack = parse->vstack;
1011a6844aabSmrg
1012a6844aabSmrg    return vstack && vstack->pstack == parse->pstack ? vstack : 0;
10132c393a42Smrg}
10142c393a42Smrg
1015a6844aabSmrgstatic void
1016a6844aabSmrgFcVStackPopAndDestroy (FcConfigParse *parse)
10172c393a42Smrg{
10182c393a42Smrg    FcVStack	*vstack = parse->vstack;
1019ca08ab68Smrg
10202c393a42Smrg    if (!vstack || vstack->pstack != parse->pstack)
1021a6844aabSmrg	return;
1022a6844aabSmrg
10232c393a42Smrg    parse->vstack = vstack->prev;
1024a6844aabSmrg
1025a6844aabSmrg    switch (vstack->tag) {
1026a6844aabSmrg    case FcVStackNone:
1027a6844aabSmrg	break;
1028c9710b42Smrg    case FcVStackName:
1029c9710b42Smrg	break;
1030a6844aabSmrg    case FcVStackFamily:
1031a6844aabSmrg	break;
1032a6844aabSmrg    case FcVStackString:
1033a6844aabSmrg    case FcVStackConstant:
1034a6844aabSmrg    case FcVStackGlob:
1035a6844aabSmrg	FcStrFree (vstack->u.string);
1036a6844aabSmrg	break;
1037a6844aabSmrg    case FcVStackPattern:
1038a6844aabSmrg	FcPatternDestroy (vstack->u.pattern);
1039a6844aabSmrg	break;
1040a6844aabSmrg    case FcVStackInteger:
1041a6844aabSmrg    case FcVStackDouble:
1042a6844aabSmrg	break;
1043a6844aabSmrg    case FcVStackMatrix:
1044c9710b42Smrg	FcExprMatrixFreeShallow (vstack->u.matrix);
1045a6844aabSmrg	break;
1046a6844aabSmrg    case FcVStackBool:
1047a6844aabSmrg	break;
1048953daebaSmrg    case FcVStackRange:
1049953daebaSmrg	FcRangeDestroy (vstack->u.range);
1050953daebaSmrg	break;
1051ca08ab68Smrg    case FcVStackCharSet:
1052ca08ab68Smrg	FcCharSetDestroy (vstack->u.charset);
1053ca08ab68Smrg	break;
1054ca08ab68Smrg    case FcVStackLangSet:
1055ca08ab68Smrg	FcLangSetDestroy (vstack->u.langset);
1056ca08ab68Smrg	break;
1057a6844aabSmrg    case FcVStackTest:
1058a6844aabSmrg	FcTestDestroy (vstack->u.test);
1059a6844aabSmrg	break;
1060a6844aabSmrg    case FcVStackExpr:
1061a6844aabSmrg    case FcVStackPrefer:
1062a6844aabSmrg    case FcVStackAccept:
1063a6844aabSmrg    case FcVStackDefault:
1064a6844aabSmrg	FcExprDestroy (vstack->u.expr);
1065a6844aabSmrg	break;
1066a6844aabSmrg    case FcVStackEdit:
1067a6844aabSmrg	FcEditDestroy (vstack->u.edit);
1068a6844aabSmrg	break;
1069a6844aabSmrg    }
1070a6844aabSmrg
1071a6844aabSmrg    if (vstack == &parse->vstack_static[parse->vstack_static_used - 1])
1072a6844aabSmrg	parse->vstack_static_used--;
1073a6844aabSmrg    else
1074a6844aabSmrg	free (vstack);
1075a6844aabSmrg}
1076a6844aabSmrg
1077a6844aabSmrgstatic void
1078a6844aabSmrgFcVStackClear (FcConfigParse *parse)
1079a6844aabSmrg{
1080a6844aabSmrg    while (FcVStackPeek (parse))
1081a6844aabSmrg	FcVStackPopAndDestroy (parse);
10822c393a42Smrg}
10832c393a42Smrg
10842c393a42Smrgstatic int
10852c393a42SmrgFcVStackElements (FcConfigParse *parse)
10862c393a42Smrg{
10872c393a42Smrg    int		h = 0;
10882c393a42Smrg    FcVStack	*vstack = parse->vstack;
10892c393a42Smrg    while (vstack && vstack->pstack == parse->pstack)
10902c393a42Smrg    {
10912c393a42Smrg	h++;
10922c393a42Smrg	vstack = vstack->prev;
10932c393a42Smrg    }
10942c393a42Smrg    return h;
10952c393a42Smrg}
10962c393a42Smrg
10972c393a42Smrgstatic FcChar8 **
1098a6844aabSmrgFcConfigSaveAttr (const XML_Char **attr, FcChar8 **buf, int size_bytes)
10992c393a42Smrg{
11002c393a42Smrg    int		slen;
11012c393a42Smrg    int		i;
11022c393a42Smrg    FcChar8	**new;
11032c393a42Smrg    FcChar8	*s;
11042c393a42Smrg
11052c393a42Smrg    if (!attr)
11062c393a42Smrg	return 0;
11072c393a42Smrg    slen = 0;
11082c393a42Smrg    for (i = 0; attr[i]; i++)
11092c393a42Smrg	slen += strlen ((char *) attr[i]) + 1;
1110a6844aabSmrg    if (i == 0)
11112c393a42Smrg	return 0;
1112a6844aabSmrg    slen += (i + 1) * sizeof (FcChar8 *);
1113a6844aabSmrg    if (slen <= size_bytes)
1114a6844aabSmrg	new = buf;
1115a6844aabSmrg    else
1116a6844aabSmrg    {
1117a6844aabSmrg	new = malloc (slen);
1118a6844aabSmrg	if (!new)
1119a6844aabSmrg	{
1120a6844aabSmrg	    FcConfigMessage (0, FcSevereError, "out of memory");
1121a6844aabSmrg	    return 0;
1122a6844aabSmrg	}
1123a6844aabSmrg    }
11242c393a42Smrg    s = (FcChar8 *) (new + (i + 1));
11252c393a42Smrg    for (i = 0; attr[i]; i++)
11262c393a42Smrg    {
11272c393a42Smrg	new[i] = s;
11282c393a42Smrg	strcpy ((char *) s, (char *) attr[i]);
11292c393a42Smrg	s += strlen ((char *) s) + 1;
11302c393a42Smrg    }
11312c393a42Smrg    new[i] = 0;
11322c393a42Smrg    return new;
11332c393a42Smrg}
11342c393a42Smrg
11352c393a42Smrgstatic FcBool
11362c393a42SmrgFcPStackPush (FcConfigParse *parse, FcElement element, const XML_Char **attr)
11372c393a42Smrg{
1138a6844aabSmrg    FcPStack   *new;
11392c393a42Smrg
1140a6844aabSmrg    if (parse->pstack_static_used < sizeof (parse->pstack_static) / sizeof (parse->pstack_static[0]))
1141a6844aabSmrg	new = &parse->pstack_static[parse->pstack_static_used++];
1142a6844aabSmrg    else
11432c393a42Smrg    {
1144a6844aabSmrg	new = malloc (sizeof (FcPStack));
1145a6844aabSmrg	if (!new)
11462c393a42Smrg	    return FcFalse;
11472c393a42Smrg    }
1148a6844aabSmrg
1149a6844aabSmrg    new->prev = parse->pstack;
1150a6844aabSmrg    new->element = element;
1151a6844aabSmrg    new->attr = FcConfigSaveAttr (attr, new->attr_buf_static, sizeof (new->attr_buf_static));
11522c393a42Smrg    FcStrBufInit (&new->str, 0, 0);
11532c393a42Smrg    parse->pstack = new;
11542c393a42Smrg    return FcTrue;
11552c393a42Smrg}
11562c393a42Smrg
11572c393a42Smrgstatic FcBool
11582c393a42SmrgFcPStackPop (FcConfigParse *parse)
11592c393a42Smrg{
11602c393a42Smrg    FcPStack   *old;
1161ca08ab68Smrg
1162ca08ab68Smrg    if (!parse->pstack)
11632c393a42Smrg    {
11642c393a42Smrg	FcConfigMessage (parse, FcSevereError, "mismatching element");
11652c393a42Smrg	return FcFalse;
11662c393a42Smrg    }
1167c9710b42Smrg
1168c9710b42Smrg    if (parse->pstack->attr)
1169c9710b42Smrg    {
1170c9710b42Smrg	/* Warn about unused attrs. */
1171c9710b42Smrg	FcChar8 **attrs = parse->pstack->attr;
1172c9710b42Smrg	while (*attrs)
1173c9710b42Smrg	{
1174c9710b42Smrg	    if (attrs[0][0])
1175c9710b42Smrg	    {
1176c9710b42Smrg		FcConfigMessage (parse, FcSevereError, "invalid attribute '%s'", attrs[0]);
1177c9710b42Smrg	    }
1178c9710b42Smrg	    attrs += 2;
1179c9710b42Smrg	}
1180c9710b42Smrg    }
1181c9710b42Smrg
11822c393a42Smrg    FcVStackClear (parse);
11832c393a42Smrg    old = parse->pstack;
11842c393a42Smrg    parse->pstack = old->prev;
11852c393a42Smrg    FcStrBufDestroy (&old->str);
1186c9710b42Smrg
1187a6844aabSmrg    if (old->attr && old->attr != old->attr_buf_static)
11882c393a42Smrg	free (old->attr);
1189a6844aabSmrg
1190a6844aabSmrg    if (old == &parse->pstack_static[parse->pstack_static_used - 1])
1191a6844aabSmrg	parse->pstack_static_used--;
1192a6844aabSmrg    else
1193a6844aabSmrg	free (old);
11942c393a42Smrg    return FcTrue;
11952c393a42Smrg}
11962c393a42Smrg
11972c393a42Smrgstatic FcBool
1198c9710b42SmrgFcConfigParseInit (FcConfigParse *parse, const FcChar8 *name, FcConfig *config, XML_Parser parser)
11992c393a42Smrg{
12002c393a42Smrg    parse->pstack = 0;
1201a6844aabSmrg    parse->pstack_static_used = 0;
12022c393a42Smrg    parse->vstack = 0;
1203a6844aabSmrg    parse->vstack_static_used = 0;
12042c393a42Smrg    parse->error = FcFalse;
12052c393a42Smrg    parse->name = name;
12062c393a42Smrg    parse->config = config;
12072c393a42Smrg    parse->parser = parser;
12082c393a42Smrg    return FcTrue;
12092c393a42Smrg}
12102c393a42Smrg
12112c393a42Smrgstatic void
12122c393a42SmrgFcConfigCleanup (FcConfigParse	*parse)
12132c393a42Smrg{
12142c393a42Smrg    while (parse->pstack)
12152c393a42Smrg	FcPStackPop (parse);
12162c393a42Smrg}
12172c393a42Smrg
12182c393a42Smrgstatic const FcChar8 *
12192c393a42SmrgFcConfigGetAttribute (FcConfigParse *parse, const char *attr)
12202c393a42Smrg{
12212c393a42Smrg    FcChar8 **attrs;
12222c393a42Smrg    if (!parse->pstack)
12232c393a42Smrg	return 0;
12242c393a42Smrg
12252c393a42Smrg    attrs = parse->pstack->attr;
12262c393a42Smrg    if (!attrs)
12272c393a42Smrg        return 0;
12282c393a42Smrg
12292c393a42Smrg    while (*attrs)
12302c393a42Smrg    {
12312c393a42Smrg	if (!strcmp ((char *) *attrs, attr))
1232c9710b42Smrg	{
1233c9710b42Smrg	    attrs[0][0] = '\0'; /* Mark as used. */
12342c393a42Smrg	    return attrs[1];
1235c9710b42Smrg	}
12362c393a42Smrg	attrs += 2;
12372c393a42Smrg    }
12382c393a42Smrg    return 0;
12392c393a42Smrg}
12402c393a42Smrg
12412c393a42Smrgstatic void
12422c393a42SmrgFcStartElement(void *userData, const XML_Char *name, const XML_Char **attr)
12432c393a42Smrg{
12442c393a42Smrg    FcConfigParse   *parse = userData;
12452c393a42Smrg    FcElement	    element;
1246ca08ab68Smrg
12472c393a42Smrg    element = FcElementMap (name);
12482c393a42Smrg    if (element == FcElementUnknown)
12492c393a42Smrg	FcConfigMessage (parse, FcSevereWarning, "unknown element \"%s\"", name);
1250ca08ab68Smrg
12512c393a42Smrg    if (!FcPStackPush (parse, element, attr))
12522c393a42Smrg    {
12532c393a42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
12542c393a42Smrg	return;
12552c393a42Smrg    }
12562c393a42Smrg    return;
12572c393a42Smrg}
12582c393a42Smrg
12592c393a42Smrgstatic void
12602c393a42SmrgFcParseBlank (FcConfigParse *parse)
12612c393a42Smrg{
1262ca08ab68Smrg    int		n = FcVStackElements (parse);
1263953daebaSmrg#if 0
1264953daebaSmrg    FcChar32	i, begin, end;
1265953daebaSmrg#endif
1266953daebaSmrg
1267953daebaSmrg    FcConfigMessage (parse, FcSevereWarning, "blank doesn't take any effect anymore. please remove it from your fonts.conf");
12682c393a42Smrg    while (n-- > 0)
12692c393a42Smrg    {
12702c393a42Smrg	FcVStack    *v = FcVStackFetch (parse, n);
1271ca08ab68Smrg	if (!parse->config->blanks)
12722c393a42Smrg	{
1273ca08ab68Smrg	    parse->config->blanks = FcBlanksCreate ();
12742c393a42Smrg	    if (!parse->config->blanks)
1275ca08ab68Smrg		goto bail;
1276ca08ab68Smrg	}
1277c9710b42Smrg	switch ((int) v->tag) {
1278ca08ab68Smrg	case FcVStackInteger:
1279953daebaSmrg#if 0
12802c393a42Smrg	    if (!FcBlanksAdd (parse->config->blanks, v->u.integer))
1281ca08ab68Smrg		goto bail;
1282ca08ab68Smrg	    break;
1283953daebaSmrg#endif
1284ca08ab68Smrg	case FcVStackRange:
1285953daebaSmrg#if 0
1286953daebaSmrg	    begin = (FcChar32) v->u.range->begin;
1287953daebaSmrg	    end = (FcChar32) v->u.range->end;
1288953daebaSmrg	    if (begin <= end)
12892c393a42Smrg	    {
1290953daebaSmrg	      for (i = begin; i <= end; i++)
1291ca08ab68Smrg	      {
1292ca08ab68Smrg		  if (!FcBlanksAdd (parse->config->blanks, i))
1293ca08ab68Smrg		      goto bail;
1294ca08ab68Smrg	      }
12952c393a42Smrg	    }
1296953daebaSmrg#endif
1297ca08ab68Smrg	    break;
1298ca08ab68Smrg	default:
1299ca08ab68Smrg	    FcConfigMessage (parse, FcSevereError, "invalid element in blank");
1300ca08ab68Smrg	    break;
13012c393a42Smrg	}
13022c393a42Smrg    }
1303ca08ab68Smrg    return;
1304ca08ab68Smrg  bail:
1305ca08ab68Smrg    FcConfigMessage (parse, FcSevereError, "out of memory");
13062c393a42Smrg}
13072c393a42Smrg
13082c393a42Smrgstatic void
13092c393a42SmrgFcParseRescan (FcConfigParse *parse)
13102c393a42Smrg{
13112c393a42Smrg    int	    n = FcVStackElements (parse);
13122c393a42Smrg    while (n-- > 0)
13132c393a42Smrg    {
13142c393a42Smrg	FcVStack    *v = FcVStackFetch (parse, n);
13152c393a42Smrg	if (v->tag != FcVStackInteger)
13162c393a42Smrg	    FcConfigMessage (parse, FcSevereWarning, "non-integer rescan");
13172c393a42Smrg	else
13182c393a42Smrg	    parse->config->rescanInterval = v->u.integer;
13192c393a42Smrg    }
13202c393a42Smrg}
13212c393a42Smrg
13222c393a42Smrgstatic void
13232c393a42SmrgFcParseInt (FcConfigParse *parse)
13242c393a42Smrg{
13252c393a42Smrg    FcChar8 *s, *end;
13262c393a42Smrg    int	    l;
1327ca08ab68Smrg
13282c393a42Smrg    if (!parse->pstack)
13292c393a42Smrg	return;
1330a6844aabSmrg    s = FcStrBufDoneStatic (&parse->pstack->str);
13312c393a42Smrg    if (!s)
13322c393a42Smrg    {
13332c393a42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
13342c393a42Smrg	return;
13352c393a42Smrg    }
13362c393a42Smrg    end = 0;
13372c393a42Smrg    l = (int) strtol ((char *) s, (char **)&end, 0);
13382c393a42Smrg    if (end != s + strlen ((char *) s))
13392c393a42Smrg	FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid integer", s);
13402c393a42Smrg    else
13412c393a42Smrg	FcVStackPushInteger (parse, l);
1342a6844aabSmrg    FcStrBufDestroy (&parse->pstack->str);
13432c393a42Smrg}
13442c393a42Smrg
13452c393a42Smrg/*
1346ca08ab68Smrg * idea copied from glib g_ascii_strtod with
1347ca08ab68Smrg * permission of the author (Alexander Larsson)
13482c393a42Smrg */
13492c393a42Smrg
13502c393a42Smrg#include <locale.h>
13512c393a42Smrg
1352ca08ab68Smrgstatic double
13532c393a42SmrgFcStrtod (char *s, char **end)
13542c393a42Smrg{
1355953daebaSmrg#ifndef __BIONIC__
13562c393a42Smrg    struct lconv    *locale_data;
1357953daebaSmrg#endif
1358953daebaSmrg    const char	    *decimal_point;
1359953daebaSmrg    int		    dlen;
13602c393a42Smrg    char	    *dot;
13612c393a42Smrg    double	    v;
13622c393a42Smrg
13632c393a42Smrg    /*
13642c393a42Smrg     * Have to swap the decimal point to match the current locale
13652c393a42Smrg     * if that locale doesn't use 0x2e
13662c393a42Smrg     */
1367953daebaSmrg#ifndef __BIONIC__
1368953daebaSmrg    locale_data = localeconv ();
1369953daebaSmrg    decimal_point = locale_data->decimal_point;
1370953daebaSmrg    dlen = strlen (decimal_point);
1371953daebaSmrg#else
1372953daebaSmrg    decimal_point = ".";
1373953daebaSmrg    dlen = 1;
1374953daebaSmrg#endif
1375953daebaSmrg
13762c393a42Smrg    if ((dot = strchr (s, 0x2e)) &&
1377953daebaSmrg	(decimal_point[0] != 0x2e ||
1378953daebaSmrg	 decimal_point[1] != 0))
13792c393a42Smrg    {
13802c393a42Smrg	char	buf[128];
13812c393a42Smrg	int	slen = strlen (s);
13822c393a42Smrg
13832c393a42Smrg	if (slen + dlen > (int) sizeof (buf))
13842c393a42Smrg	{
13852c393a42Smrg	    if (end)
13862c393a42Smrg		*end = s;
13872c393a42Smrg	    v = 0;
13882c393a42Smrg	}
13892c393a42Smrg	else
13902c393a42Smrg	{
13912c393a42Smrg	    char	*buf_end;
13922c393a42Smrg	    /* mantissa */
13932c393a42Smrg	    strncpy (buf, s, dot - s);
13942c393a42Smrg	    /* decimal point */
1395953daebaSmrg	    strcpy (buf + (dot - s), decimal_point);
13962c393a42Smrg	    /* rest of number */
13972c393a42Smrg	    strcpy (buf + (dot - s) + dlen, dot + 1);
13982c393a42Smrg	    buf_end = 0;
13992c393a42Smrg	    v = strtod (buf, &buf_end);
14002c393a42Smrg	    if (buf_end) {
14012c393a42Smrg		buf_end = s + (buf_end - buf);
14022c393a42Smrg		if (buf_end > dot)
14032c393a42Smrg		    buf_end -= dlen - 1;
14042c393a42Smrg	    }
14052c393a42Smrg	    if (end)
14062c393a42Smrg		*end = buf_end;
14072c393a42Smrg	}
14082c393a42Smrg    }
14092c393a42Smrg    else
14102c393a42Smrg	v = strtod (s, end);
14112c393a42Smrg    return v;
14122c393a42Smrg}
14132c393a42Smrg
14142c393a42Smrgstatic void
14152c393a42SmrgFcParseDouble (FcConfigParse *parse)
14162c393a42Smrg{
14172c393a42Smrg    FcChar8 *s, *end;
14182c393a42Smrg    double  d;
1419ca08ab68Smrg
14202c393a42Smrg    if (!parse->pstack)
14212c393a42Smrg	return;
1422a6844aabSmrg    s = FcStrBufDoneStatic (&parse->pstack->str);
14232c393a42Smrg    if (!s)
14242c393a42Smrg    {
14252c393a42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
14262c393a42Smrg	return;
14272c393a42Smrg    }
14282c393a42Smrg    end = 0;
14292c393a42Smrg    d = FcStrtod ((char *) s, (char **)&end);
14302c393a42Smrg    if (end != s + strlen ((char *) s))
14312c393a42Smrg	FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid double", s);
14322c393a42Smrg    else
14332c393a42Smrg	FcVStackPushDouble (parse, d);
1434a6844aabSmrg    FcStrBufDestroy (&parse->pstack->str);
14352c393a42Smrg}
14362c393a42Smrg
14372c393a42Smrgstatic void
14382c393a42SmrgFcParseString (FcConfigParse *parse, FcVStackTag tag)
14392c393a42Smrg{
14402c393a42Smrg    FcChar8 *s;
1441ca08ab68Smrg
14422c393a42Smrg    if (!parse->pstack)
14432c393a42Smrg	return;
14442c393a42Smrg    s = FcStrBufDone (&parse->pstack->str);
14452c393a42Smrg    if (!s)
14462c393a42Smrg    {
14472c393a42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
14482c393a42Smrg	return;
14492c393a42Smrg    }
14502c393a42Smrg    if (!FcVStackPushString (parse, tag, s))
14512c393a42Smrg	FcStrFree (s);
14522c393a42Smrg}
14532c393a42Smrg
14542c393a42Smrgstatic void
1455c9710b42SmrgFcParseName (FcConfigParse *parse)
14562c393a42Smrg{
1457c9710b42Smrg    const FcChar8   *kind_string;
1458c9710b42Smrg    FcMatchKind	    kind;
1459c9710b42Smrg    FcChar8 *s;
1460c9710b42Smrg    FcObject object;
1461ca08ab68Smrg
1462c9710b42Smrg    kind_string = FcConfigGetAttribute (parse, "target");
1463c9710b42Smrg    if (!kind_string)
1464c9710b42Smrg	kind = FcMatchDefault;
1465c9710b42Smrg    else
14662c393a42Smrg    {
1467c9710b42Smrg	if (!strcmp ((char *) kind_string, "pattern"))
1468c9710b42Smrg	    kind = FcMatchPattern;
1469c9710b42Smrg	else if (!strcmp ((char *) kind_string, "font"))
1470c9710b42Smrg	    kind = FcMatchFont;
1471c9710b42Smrg	else if (!strcmp ((char *) kind_string, "default"))
1472c9710b42Smrg	    kind = FcMatchDefault;
1473c9710b42Smrg	else
1474c9710b42Smrg	{
1475c9710b42Smrg	    FcConfigMessage (parse, FcSevereWarning, "invalid name target \"%s\"", kind_string);
1476c9710b42Smrg	    return;
14772c393a42Smrg	}
14782c393a42Smrg    }
1479c9710b42Smrg
1480c9710b42Smrg    if (!parse->pstack)
1481c9710b42Smrg	return;
1482c9710b42Smrg    s = FcStrBufDone (&parse->pstack->str);
1483c9710b42Smrg    if (!s)
1484c9710b42Smrg    {
1485c9710b42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
1486c9710b42Smrg	return;
1487c9710b42Smrg    }
1488c9710b42Smrg    object = FcObjectFromName ((const char *) s);
1489c9710b42Smrg
1490c9710b42Smrg    FcVStackPushName (parse, kind, object);
1491c9710b42Smrg
1492c9710b42Smrg    FcStrFree (s);
1493c9710b42Smrg}
1494c9710b42Smrg
1495c9710b42Smrgstatic void
1496c9710b42SmrgFcParseMatrix (FcConfigParse *parse)
1497c9710b42Smrg{
1498c9710b42Smrg    FcExprMatrix m;
1499c9710b42Smrg
1500c9710b42Smrg    m.yy = FcPopExpr (parse);
1501c9710b42Smrg    m.yx = FcPopExpr (parse);
1502c9710b42Smrg    m.xy = FcPopExpr (parse);
1503c9710b42Smrg    m.xx = FcPopExpr (parse);
1504c9710b42Smrg
1505c9710b42Smrg    if (FcPopExpr (parse))
1506c9710b42Smrg      FcConfigMessage (parse, FcSevereError, "wrong number of matrix elements");
15072c393a42Smrg    else
1508c9710b42Smrg      FcVStackPushMatrix (parse, &m);
15092c393a42Smrg}
15102c393a42Smrg
1511ca08ab68Smrgstatic void
1512ca08ab68SmrgFcParseRange (FcConfigParse *parse)
1513ca08ab68Smrg{
1514ca08ab68Smrg    FcVStack	*vstack;
1515953daebaSmrg    FcRange	*r;
1516953daebaSmrg    FcChar32	n[2] = {0, 0};
1517ca08ab68Smrg    int		count = 1;
1518953daebaSmrg    double	d[2] = {0.0L, 0.0L};
1519953daebaSmrg    FcBool	dflag = FcFalse;
1520ca08ab68Smrg
1521ca08ab68Smrg    while ((vstack = FcVStackPeek (parse)))
1522ca08ab68Smrg    {
1523ca08ab68Smrg	if (count < 0)
1524ca08ab68Smrg	{
1525ca08ab68Smrg	    FcConfigMessage (parse, FcSevereError, "too many elements in range");
1526ca08ab68Smrg	    return;
1527ca08ab68Smrg	}
1528c9710b42Smrg	switch ((int) vstack->tag) {
1529ca08ab68Smrg	case FcVStackInteger:
1530953daebaSmrg	    if (dflag)
1531953daebaSmrg		d[count] = (double)vstack->u.integer;
1532953daebaSmrg	    else
1533953daebaSmrg		n[count] = vstack->u.integer;
1534953daebaSmrg	    break;
1535953daebaSmrg	case FcVStackDouble:
1536953daebaSmrg	    if (count == 0 && !dflag)
1537953daebaSmrg		d[1] = (double)n[1];
1538953daebaSmrg	    d[count] = vstack->u._double;
1539953daebaSmrg	    dflag = FcTrue;
1540ca08ab68Smrg	    break;
1541ca08ab68Smrg	default:
1542ca08ab68Smrg	    FcConfigMessage (parse, FcSevereError, "invalid element in range");
1543953daebaSmrg	    if (dflag)
1544953daebaSmrg		d[count] = 0.0L;
1545953daebaSmrg	    else
1546953daebaSmrg		n[count] = 0;
1547ca08ab68Smrg	    break;
1548ca08ab68Smrg	}
1549ca08ab68Smrg	count--;
1550ca08ab68Smrg	FcVStackPopAndDestroy (parse);
1551ca08ab68Smrg    }
1552953daebaSmrg    if (count >= 0)
1553ca08ab68Smrg    {
1554953daebaSmrg	FcConfigMessage (parse, FcSevereError, "invalid range");
1555953daebaSmrg	return;
1556953daebaSmrg    }
1557953daebaSmrg    if (dflag)
1558953daebaSmrg    {
1559953daebaSmrg	if (d[0] > d[1])
1560ca08ab68Smrg	{
1561ca08ab68Smrg	    FcConfigMessage (parse, FcSevereError, "invalid range");
1562ca08ab68Smrg	    return;
1563ca08ab68Smrg	}
1564953daebaSmrg	r = FcRangeCreateDouble (d[0], d[1]);
1565ca08ab68Smrg    }
1566ca08ab68Smrg    else
1567953daebaSmrg    {
1568953daebaSmrg	if (n[0] > n[1])
1569953daebaSmrg	{
1570953daebaSmrg	    FcConfigMessage (parse, FcSevereError, "invalid range");
1571953daebaSmrg	    return;
1572953daebaSmrg	}
1573953daebaSmrg	r = FcRangeCreateInteger (n[0], n[1]);
1574953daebaSmrg    }
1575953daebaSmrg    FcVStackPushRange (parse, r);
1576ca08ab68Smrg}
1577ca08ab68Smrg
15782c393a42Smrgstatic FcBool
1579a6844aabSmrgFcConfigLexBool (FcConfigParse *parse, const FcChar8 *bool_)
15802c393a42Smrg{
15812c393a42Smrg    FcBool  result = FcFalse;
15822c393a42Smrg
1583a6844aabSmrg    if (!FcNameBool (bool_, &result))
15842c393a42Smrg	FcConfigMessage (parse, FcSevereWarning, "\"%s\" is not known boolean",
1585a6844aabSmrg			 bool_);
15862c393a42Smrg    return result;
15872c393a42Smrg}
15882c393a42Smrg
15892c393a42Smrgstatic void
15902c393a42SmrgFcParseBool (FcConfigParse *parse)
15912c393a42Smrg{
15922c393a42Smrg    FcChar8 *s;
15932c393a42Smrg
15942c393a42Smrg    if (!parse->pstack)
15952c393a42Smrg	return;
1596a6844aabSmrg    s = FcStrBufDoneStatic (&parse->pstack->str);
15972c393a42Smrg    if (!s)
15982c393a42Smrg    {
15992c393a42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
16002c393a42Smrg	return;
16012c393a42Smrg    }
16022c393a42Smrg    FcVStackPushBool (parse, FcConfigLexBool (parse, s));
1603a6844aabSmrg    FcStrBufDestroy (&parse->pstack->str);
16042c393a42Smrg}
16052c393a42Smrg
1606ca08ab68Smrgstatic void
1607ca08ab68SmrgFcParseCharSet (FcConfigParse *parse)
1608ca08ab68Smrg{
1609ca08ab68Smrg    FcVStack	*vstack;
1610ca08ab68Smrg    FcCharSet	*charset = FcCharSetCreate ();
1611953daebaSmrg    FcChar32	i, begin, end;
1612ca08ab68Smrg    int n = 0;
1613ca08ab68Smrg
1614ca08ab68Smrg    while ((vstack = FcVStackPeek (parse)))
1615ca08ab68Smrg    {
1616c9710b42Smrg	switch ((int) vstack->tag) {
1617ca08ab68Smrg	case FcVStackInteger:
1618ca08ab68Smrg	    if (!FcCharSetAddChar (charset, vstack->u.integer))
1619ca08ab68Smrg	    {
1620ca08ab68Smrg		FcConfigMessage (parse, FcSevereWarning, "invalid character: 0x%04x", vstack->u.integer);
1621ca08ab68Smrg	    }
1622ca08ab68Smrg	    else
1623ca08ab68Smrg		n++;
1624ca08ab68Smrg	    break;
1625ca08ab68Smrg	case FcVStackRange:
1626953daebaSmrg	    begin = (FcChar32) vstack->u.range->begin;
1627953daebaSmrg	    end = (FcChar32) vstack->u.range->end;
1628953daebaSmrg
1629953daebaSmrg	    if (begin <= end)
1630ca08ab68Smrg	    {
1631953daebaSmrg	      for (i = begin; i <= end; i++)
1632ca08ab68Smrg	      {
1633ca08ab68Smrg		  if (!FcCharSetAddChar (charset, i))
1634ca08ab68Smrg		  {
1635ca08ab68Smrg		      FcConfigMessage (parse, FcSevereWarning, "invalid character: 0x%04x", i);
1636ca08ab68Smrg		  }
1637ca08ab68Smrg		  else
1638ca08ab68Smrg		      n++;
1639ca08ab68Smrg	      }
1640ca08ab68Smrg	    }
1641ca08ab68Smrg	    break;
1642ca08ab68Smrg	default:
1643ca08ab68Smrg		FcConfigMessage (parse, FcSevereError, "invalid element in charset");
1644ca08ab68Smrg		break;
1645ca08ab68Smrg	}
1646ca08ab68Smrg	FcVStackPopAndDestroy (parse);
1647ca08ab68Smrg    }
1648ca08ab68Smrg    if (n > 0)
1649ca08ab68Smrg	    FcVStackPushCharSet (parse, charset);
1650ca08ab68Smrg    else
1651ca08ab68Smrg	    FcCharSetDestroy (charset);
1652ca08ab68Smrg}
1653ca08ab68Smrg
1654ca08ab68Smrgstatic void
1655ca08ab68SmrgFcParseLangSet (FcConfigParse *parse)
1656ca08ab68Smrg{
1657ca08ab68Smrg    FcVStack	*vstack;
1658ca08ab68Smrg    FcLangSet	*langset = FcLangSetCreate ();
1659ca08ab68Smrg    int n = 0;
1660ca08ab68Smrg
1661ca08ab68Smrg    while ((vstack = FcVStackPeek (parse)))
1662ca08ab68Smrg    {
1663c9710b42Smrg	switch ((int) vstack->tag) {
1664ca08ab68Smrg	case FcVStackString:
1665ca08ab68Smrg	    if (!FcLangSetAdd (langset, vstack->u.string))
1666ca08ab68Smrg	    {
1667ca08ab68Smrg		FcConfigMessage (parse, FcSevereWarning, "invalid langset: %s", vstack->u.string);
1668ca08ab68Smrg	    }
1669ca08ab68Smrg	    else
1670ca08ab68Smrg		n++;
1671ca08ab68Smrg	    break;
1672ca08ab68Smrg	default:
1673ca08ab68Smrg		FcConfigMessage (parse, FcSevereError, "invalid element in langset");
1674ca08ab68Smrg		break;
1675ca08ab68Smrg	}
1676ca08ab68Smrg	FcVStackPopAndDestroy (parse);
1677ca08ab68Smrg    }
1678ca08ab68Smrg    if (n > 0)
1679ca08ab68Smrg	    FcVStackPushLangSet (parse, langset);
1680ca08ab68Smrg    else
1681ca08ab68Smrg	    FcLangSetDestroy (langset);
1682ca08ab68Smrg}
1683ca08ab68Smrg
16842c393a42Smrgstatic FcBool
16852c393a42SmrgFcConfigLexBinding (FcConfigParse   *parse,
16862c393a42Smrg		    const FcChar8   *binding_string,
16872c393a42Smrg		    FcValueBinding  *binding_ret)
16882c393a42Smrg{
16892c393a42Smrg    FcValueBinding binding;
1690ca08ab68Smrg
16912c393a42Smrg    if (!binding_string)
16922c393a42Smrg	binding = FcValueBindingWeak;
16932c393a42Smrg    else
16942c393a42Smrg    {
16952c393a42Smrg	if (!strcmp ((char *) binding_string, "weak"))
16962c393a42Smrg	    binding = FcValueBindingWeak;
16972c393a42Smrg	else if (!strcmp ((char *) binding_string, "strong"))
16982c393a42Smrg	    binding = FcValueBindingStrong;
16992c393a42Smrg	else if (!strcmp ((char *) binding_string, "same"))
17002c393a42Smrg	    binding = FcValueBindingSame;
17012c393a42Smrg	else
17022c393a42Smrg	{
17032c393a42Smrg	    FcConfigMessage (parse, FcSevereWarning, "invalid binding \"%s\"", binding_string);
17042c393a42Smrg	    return FcFalse;
17052c393a42Smrg	}
17062c393a42Smrg    }
17072c393a42Smrg    *binding_ret = binding;
17082c393a42Smrg    return FcTrue;
17092c393a42Smrg}
17102c393a42Smrg
17112c393a42Smrgstatic void
17122c393a42SmrgFcParseFamilies (FcConfigParse *parse, FcVStackTag tag)
17132c393a42Smrg{
17142c393a42Smrg    FcVStack	*vstack;
17152c393a42Smrg    FcExpr	*left, *expr = 0, *new;
17162c393a42Smrg
1717a6844aabSmrg    while ((vstack = FcVStackPeek (parse)))
17182c393a42Smrg    {
17192c393a42Smrg	if (vstack->tag != FcVStackFamily)
17202c393a42Smrg	{
17212c393a42Smrg	    FcConfigMessage (parse, FcSevereWarning, "non-family");
1722a6844aabSmrg	    FcVStackPopAndDestroy (parse);
17232c393a42Smrg	    continue;
17242c393a42Smrg	}
17252c393a42Smrg	left = vstack->u.expr;
17262c393a42Smrg	vstack->tag = FcVStackNone;
1727a6844aabSmrg	FcVStackPopAndDestroy (parse);
17282c393a42Smrg	if (expr)
17292c393a42Smrg	{
1730a6844aabSmrg	    new = FcExprCreateOp (parse->config, left, FcOpComma, expr);
17312c393a42Smrg	    if (!new)
17322c393a42Smrg	    {
17332c393a42Smrg		FcConfigMessage (parse, FcSevereError, "out of memory");
17342c393a42Smrg		FcExprDestroy (left);
17352c393a42Smrg		FcExprDestroy (expr);
17362c393a42Smrg		break;
17372c393a42Smrg	    }
17382c393a42Smrg	    expr = new;
17392c393a42Smrg	}
17402c393a42Smrg	else
17412c393a42Smrg	    expr = left;
17422c393a42Smrg    }
17432c393a42Smrg    if (expr)
17442c393a42Smrg    {
17452c393a42Smrg	if (!FcVStackPushExpr (parse, tag, expr))
17462c393a42Smrg	{
17472c393a42Smrg	    FcConfigMessage (parse, FcSevereError, "out of memory");
17482c393a42Smrg            FcExprDestroy (expr);
17492c393a42Smrg	}
17502c393a42Smrg    }
17512c393a42Smrg}
17522c393a42Smrg
17532c393a42Smrgstatic void
17542c393a42SmrgFcParseFamily (FcConfigParse *parse)
17552c393a42Smrg{
17562c393a42Smrg    FcChar8 *s;
17572c393a42Smrg    FcExpr  *expr;
17582c393a42Smrg
17592c393a42Smrg    if (!parse->pstack)
17602c393a42Smrg	return;
1761a6844aabSmrg    s = FcStrBufDoneStatic (&parse->pstack->str);
17622c393a42Smrg    if (!s)
17632c393a42Smrg    {
17642c393a42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
17652c393a42Smrg	return;
17662c393a42Smrg    }
1767a6844aabSmrg    expr = FcExprCreateString (parse->config, s);
1768a6844aabSmrg    FcStrBufDestroy (&parse->pstack->str);
17692c393a42Smrg    if (expr)
17702c393a42Smrg	FcVStackPushExpr (parse, FcVStackFamily, expr);
17712c393a42Smrg}
17722c393a42Smrg
17732c393a42Smrgstatic void
17742c393a42SmrgFcParseAlias (FcConfigParse *parse)
17752c393a42Smrg{
17762c393a42Smrg    FcExpr	*family = 0, *accept = 0, *prefer = 0, *def = 0, *new = 0;
17776fc018e4Smrg    FcEdit	*edit = 0;
17782c393a42Smrg    FcVStack	*vstack;
17796fc018e4Smrg    FcRule	*rule = NULL, *r;
17802c393a42Smrg    FcValueBinding  binding;
17812c393a42Smrg
17822c393a42Smrg    if (!FcConfigLexBinding (parse, FcConfigGetAttribute (parse, "binding"), &binding))
17832c393a42Smrg	return;
1784a6844aabSmrg    while ((vstack = FcVStackPeek (parse)))
17852c393a42Smrg    {
1786c9710b42Smrg	switch ((int) vstack->tag) {
17872c393a42Smrg	case FcVStackFamily:
17882c393a42Smrg	    if (family)
17892c393a42Smrg	    {
1790ca08ab68Smrg		FcConfigMessage (parse, FcSevereWarning, "Having multiple <family> in <alias> isn't supported and may not work as expected");
1791a6844aabSmrg		new = FcExprCreateOp (parse->config, vstack->u.expr, FcOpComma, family);
17922c393a42Smrg		if (!new)
17932c393a42Smrg		    FcConfigMessage (parse, FcSevereError, "out of memory");
17942c393a42Smrg		else
17952c393a42Smrg		    family = new;
17962c393a42Smrg	    }
17972c393a42Smrg	    else
17982c393a42Smrg		new = vstack->u.expr;
17992c393a42Smrg	    if (new)
18002c393a42Smrg	    {
18012c393a42Smrg		family = new;
18022c393a42Smrg		vstack->tag = FcVStackNone;
18032c393a42Smrg	    }
18042c393a42Smrg	    break;
18052c393a42Smrg	case FcVStackPrefer:
18062c393a42Smrg	    if (prefer)
18072c393a42Smrg		FcExprDestroy (prefer);
18082c393a42Smrg	    prefer = vstack->u.expr;
18092c393a42Smrg	    vstack->tag = FcVStackNone;
18102c393a42Smrg	    break;
18112c393a42Smrg	case FcVStackAccept:
18122c393a42Smrg	    if (accept)
18132c393a42Smrg		FcExprDestroy (accept);
18142c393a42Smrg	    accept = vstack->u.expr;
18152c393a42Smrg	    vstack->tag = FcVStackNone;
18162c393a42Smrg	    break;
18172c393a42Smrg	case FcVStackDefault:
18182c393a42Smrg	    if (def)
18192c393a42Smrg		FcExprDestroy (def);
18202c393a42Smrg	    def = vstack->u.expr;
18212c393a42Smrg	    vstack->tag = FcVStackNone;
18222c393a42Smrg	    break;
1823ca08ab68Smrg	case FcVStackTest:
18246fc018e4Smrg	    if (rule)
18256fc018e4Smrg	    {
18266fc018e4Smrg		r = FcRuleCreate (FcRuleTest, vstack->u.test);
18276fc018e4Smrg		r->next = rule;
18286fc018e4Smrg		rule = r;
18296fc018e4Smrg	    }
18306fc018e4Smrg	    else
18316fc018e4Smrg		rule = FcRuleCreate (FcRuleTest, vstack->u.test);
1832ca08ab68Smrg	    vstack->tag = FcVStackNone;
1833ca08ab68Smrg	    break;
18342c393a42Smrg	default:
18352c393a42Smrg	    FcConfigMessage (parse, FcSevereWarning, "bad alias");
18362c393a42Smrg	    break;
18372c393a42Smrg	}
1838a6844aabSmrg	FcVStackPopAndDestroy (parse);
18392c393a42Smrg    }
18402c393a42Smrg    if (!family)
18412c393a42Smrg    {
18422c393a42Smrg	FcConfigMessage (parse, FcSevereError, "missing family in alias");
18432c393a42Smrg	if (prefer)
18442c393a42Smrg	    FcExprDestroy (prefer);
18452c393a42Smrg	if (accept)
18462c393a42Smrg	    FcExprDestroy (accept);
18472c393a42Smrg	if (def)
18482c393a42Smrg	    FcExprDestroy (def);
18496fc018e4Smrg	if (rule)
18506fc018e4Smrg	    FcRuleDestroy (rule);
18512c393a42Smrg	return;
18522c393a42Smrg    }
18536fc018e4Smrg    if (!prefer &&
18546fc018e4Smrg	!accept &&
18556fc018e4Smrg	!def)
18566fc018e4Smrg    {
18576fc018e4Smrg	FcExprDestroy (family);
18586fc018e4Smrg	return;
18596fc018e4Smrg    }
18606fc018e4Smrg    else
18616fc018e4Smrg    {
18626fc018e4Smrg	FcTest *t = FcTestCreate (parse, FcMatchPattern,
18636fc018e4Smrg				  FcQualAny,
18646fc018e4Smrg				  (FcChar8 *) FC_FAMILY,
18656fc018e4Smrg				  FC_OP (FcOpEqual, FcOpFlagIgnoreBlanks),
18666fc018e4Smrg				  family);
18676fc018e4Smrg	if (rule)
18686fc018e4Smrg	{
18696fc018e4Smrg	    for (r = rule; r->next; r = r->next);
18706fc018e4Smrg	    r->next = FcRuleCreate (FcRuleTest, t);
18716fc018e4Smrg	    r = r->next;
18726fc018e4Smrg	}
18736fc018e4Smrg	else
18746fc018e4Smrg	{
18756fc018e4Smrg	    r = rule = FcRuleCreate (FcRuleTest, t);
18766fc018e4Smrg	}
18776fc018e4Smrg    }
18782c393a42Smrg    if (prefer)
18792c393a42Smrg    {
1880ca08ab68Smrg	edit = FcEditCreate (parse,
18812c393a42Smrg			     FC_FAMILY_OBJECT,
18822c393a42Smrg			     FcOpPrepend,
18832c393a42Smrg			     prefer,
18842c393a42Smrg			     binding);
18856fc018e4Smrg	if (!edit)
18862c393a42Smrg	    FcExprDestroy (prefer);
18876fc018e4Smrg	else
18886fc018e4Smrg	{
18896fc018e4Smrg	    r->next = FcRuleCreate (FcRuleEdit, edit);
18906fc018e4Smrg	    r = r->next;
18916fc018e4Smrg	}
18922c393a42Smrg    }
18932c393a42Smrg    if (accept)
18942c393a42Smrg    {
18952c393a42Smrg	edit = FcEditCreate (parse,
18962c393a42Smrg			     FC_FAMILY_OBJECT,
18972c393a42Smrg			     FcOpAppend,
18982c393a42Smrg			     accept,
18992c393a42Smrg			     binding);
19006fc018e4Smrg	if (!edit)
19012c393a42Smrg	    FcExprDestroy (accept);
19026fc018e4Smrg	else
19036fc018e4Smrg	{
19046fc018e4Smrg	    r->next = FcRuleCreate (FcRuleEdit, edit);
19056fc018e4Smrg	    r = r->next;
19066fc018e4Smrg	}
19072c393a42Smrg    }
19082c393a42Smrg    if (def)
19092c393a42Smrg    {
19102c393a42Smrg	edit = FcEditCreate (parse,
19112c393a42Smrg			     FC_FAMILY_OBJECT,
19122c393a42Smrg			     FcOpAppendLast,
19132c393a42Smrg			     def,
19142c393a42Smrg			     binding);
19156fc018e4Smrg	if (!edit)
19162c393a42Smrg	    FcExprDestroy (def);
19176fc018e4Smrg	else
1918ca08ab68Smrg	{
19196fc018e4Smrg	    r->next = FcRuleCreate (FcRuleEdit, edit);
19206fc018e4Smrg	    r = r->next;
1921ca08ab68Smrg	}
19222c393a42Smrg    }
19236fc018e4Smrg    if (!FcConfigAddRule (parse->config, rule, FcMatchPattern))
19246fc018e4Smrg	FcRuleDestroy (rule);
19252c393a42Smrg}
19262c393a42Smrg
19272c393a42Smrgstatic FcExpr *
19282c393a42SmrgFcPopExpr (FcConfigParse *parse)
19292c393a42Smrg{
1930a6844aabSmrg    FcVStack	*vstack = FcVStackPeek (parse);
19312c393a42Smrg    FcExpr	*expr = 0;
19322c393a42Smrg    if (!vstack)
19332c393a42Smrg	return 0;
1934c9710b42Smrg    switch ((int) vstack->tag) {
19352c393a42Smrg    case FcVStackNone:
19362c393a42Smrg	break;
19372c393a42Smrg    case FcVStackString:
19382c393a42Smrg    case FcVStackFamily:
1939a6844aabSmrg	expr = FcExprCreateString (parse->config, vstack->u.string);
19402c393a42Smrg	break;
1941c9710b42Smrg    case FcVStackName:
1942c9710b42Smrg	expr = FcExprCreateName (parse->config, vstack->u.name);
19432c393a42Smrg	break;
19442c393a42Smrg    case FcVStackConstant:
1945a6844aabSmrg	expr = FcExprCreateConst (parse->config, vstack->u.string);
19462c393a42Smrg	break;
19472c393a42Smrg    case FcVStackGlob:
19482c393a42Smrg	/* XXX: What's the correct action here? (CDW) */
19492c393a42Smrg	break;
19502c393a42Smrg    case FcVStackPrefer:
19512c393a42Smrg    case FcVStackAccept:
19522c393a42Smrg    case FcVStackDefault:
19532c393a42Smrg	expr = vstack->u.expr;
19542c393a42Smrg	vstack->tag = FcVStackNone;
19552c393a42Smrg	break;
19562c393a42Smrg    case FcVStackInteger:
1957a6844aabSmrg	expr = FcExprCreateInteger (parse->config, vstack->u.integer);
19582c393a42Smrg	break;
19592c393a42Smrg    case FcVStackDouble:
1960a6844aabSmrg	expr = FcExprCreateDouble (parse->config, vstack->u._double);
19612c393a42Smrg	break;
19622c393a42Smrg    case FcVStackMatrix:
1963a6844aabSmrg	expr = FcExprCreateMatrix (parse->config, vstack->u.matrix);
19642c393a42Smrg	break;
1965ca08ab68Smrg    case FcVStackRange:
1966953daebaSmrg	expr = FcExprCreateRange (parse->config, vstack->u.range);
1967ca08ab68Smrg	break;
19682c393a42Smrg    case FcVStackBool:
1969a6844aabSmrg	expr = FcExprCreateBool (parse->config, vstack->u.bool_);
19702c393a42Smrg	break;
1971ca08ab68Smrg    case FcVStackCharSet:
1972ca08ab68Smrg	expr = FcExprCreateCharSet (parse->config, vstack->u.charset);
1973ca08ab68Smrg	break;
1974ca08ab68Smrg    case FcVStackLangSet:
1975ca08ab68Smrg	expr = FcExprCreateLangSet (parse->config, vstack->u.langset);
1976ca08ab68Smrg	break;
19772c393a42Smrg    case FcVStackTest:
19782c393a42Smrg	break;
19792c393a42Smrg    case FcVStackExpr:
19802c393a42Smrg	expr = vstack->u.expr;
19812c393a42Smrg	vstack->tag = FcVStackNone;
19822c393a42Smrg	break;
19832c393a42Smrg    case FcVStackEdit:
19842c393a42Smrg	break;
19852c393a42Smrg    default:
19862c393a42Smrg	break;
19872c393a42Smrg    }
1988a6844aabSmrg    FcVStackPopAndDestroy (parse);
19892c393a42Smrg    return expr;
19902c393a42Smrg}
19912c393a42Smrg
19922c393a42Smrg/*
19932c393a42Smrg * This builds a tree of binary operations.  Note
19942c393a42Smrg * that every operator is defined so that if only
19952c393a42Smrg * a single operand is contained, the value of the
19962c393a42Smrg * whole expression is the value of the operand.
19972c393a42Smrg *
19982c393a42Smrg * This code reduces in that case to returning that
19992c393a42Smrg * operand.
20002c393a42Smrg */
20012c393a42Smrgstatic FcExpr *
20022c393a42SmrgFcPopBinary (FcConfigParse *parse, FcOp op)
20032c393a42Smrg{
20042c393a42Smrg    FcExpr  *left, *expr = 0, *new;
20052c393a42Smrg
20062c393a42Smrg    while ((left = FcPopExpr (parse)))
20072c393a42Smrg    {
20082c393a42Smrg	if (expr)
20092c393a42Smrg	{
2010a6844aabSmrg	    new = FcExprCreateOp (parse->config, left, op, expr);
20112c393a42Smrg	    if (!new)
20122c393a42Smrg	    {
20132c393a42Smrg		FcConfigMessage (parse, FcSevereError, "out of memory");
20142c393a42Smrg		FcExprDestroy (left);
20152c393a42Smrg		FcExprDestroy (expr);
20162c393a42Smrg		return 0;
20172c393a42Smrg	    }
20182c393a42Smrg	    expr = new;
20192c393a42Smrg	}
20202c393a42Smrg	else
20212c393a42Smrg	    expr = left;
20222c393a42Smrg    }
20232c393a42Smrg    return expr;
20242c393a42Smrg}
20252c393a42Smrg
20262c393a42Smrgstatic void
20272c393a42SmrgFcParseBinary (FcConfigParse *parse, FcOp op)
20282c393a42Smrg{
20292c393a42Smrg    FcExpr  *expr = FcPopBinary (parse, op);
20302c393a42Smrg    if (expr)
20312c393a42Smrg	FcVStackPushExpr (parse, FcVStackExpr, expr);
20322c393a42Smrg}
20332c393a42Smrg
20342c393a42Smrg/*
20352c393a42Smrg * This builds a a unary operator, it consumes only
20362c393a42Smrg * a single operand
20372c393a42Smrg */
20382c393a42Smrg
20392c393a42Smrgstatic FcExpr *
20402c393a42SmrgFcPopUnary (FcConfigParse *parse, FcOp op)
20412c393a42Smrg{
20422c393a42Smrg    FcExpr  *operand, *new = 0;
20432c393a42Smrg
20442c393a42Smrg    if ((operand = FcPopExpr (parse)))
20452c393a42Smrg    {
2046a6844aabSmrg	new = FcExprCreateOp (parse->config, operand, op, 0);
20472c393a42Smrg	if (!new)
20482c393a42Smrg	{
20492c393a42Smrg	    FcExprDestroy (operand);
20502c393a42Smrg	    FcConfigMessage (parse, FcSevereError, "out of memory");
20512c393a42Smrg	}
20522c393a42Smrg    }
20532c393a42Smrg    return new;
20542c393a42Smrg}
20552c393a42Smrg
20562c393a42Smrgstatic void
20572c393a42SmrgFcParseUnary (FcConfigParse *parse, FcOp op)
20582c393a42Smrg{
20592c393a42Smrg    FcExpr  *expr = FcPopUnary (parse, op);
20602c393a42Smrg    if (expr)
20612c393a42Smrg	FcVStackPushExpr (parse, FcVStackExpr, expr);
20622c393a42Smrg}
20632c393a42Smrg
2064ca08ab68Smrgstatic void
2065ca08ab68SmrgFcParseDir (FcConfigParse *parse)
2066ca08ab68Smrg{
2067ca08ab68Smrg    const FcChar8 *attr, *data;
2068c9710b42Smrg    FcChar8 *prefix = NULL, *p;
2069ca08ab68Smrg#ifdef _WIN32
2070ca08ab68Smrg    FcChar8         buffer[1000];
2071ca08ab68Smrg#endif
2072ca08ab68Smrg
2073ca08ab68Smrg    attr = FcConfigGetAttribute (parse, "prefix");
2074ca08ab68Smrg    if (attr && FcStrCmp (attr, (const FcChar8 *)"xdg") == 0)
2075953daebaSmrg    {
2076ca08ab68Smrg	prefix = FcConfigXdgDataHome ();
2077953daebaSmrg	/* home directory might be disabled.
2078953daebaSmrg	 * simply ignore this element.
2079953daebaSmrg	 */
2080953daebaSmrg	if (!prefix)
2081953daebaSmrg	    goto bail;
2082953daebaSmrg    }
2083ca08ab68Smrg    data = FcStrBufDoneStatic (&parse->pstack->str);
2084ca08ab68Smrg    if (!data)
2085ca08ab68Smrg    {
2086ca08ab68Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
2087c9710b42Smrg	data = prefix;
2088ca08ab68Smrg	goto bail;
2089ca08ab68Smrg    }
2090ca08ab68Smrg    if (prefix)
2091ca08ab68Smrg    {
2092ca08ab68Smrg	size_t plen = strlen ((const char *)prefix);
2093ca08ab68Smrg	size_t dlen = strlen ((const char *)data);
2094ca08ab68Smrg
2095c9710b42Smrg	p = realloc (prefix, plen + 1 + dlen + 1);
2096c9710b42Smrg	if (!p)
2097ca08ab68Smrg	{
2098ca08ab68Smrg	    FcConfigMessage (parse, FcSevereError, "out of memory");
2099ca08ab68Smrg	    goto bail;
2100ca08ab68Smrg	}
2101c9710b42Smrg	prefix = p;
2102ca08ab68Smrg	prefix[plen] = FC_DIR_SEPARATOR;
2103ca08ab68Smrg	memcpy (&prefix[plen + 1], data, dlen);
2104ca08ab68Smrg	prefix[plen + 1 + dlen] = 0;
2105ca08ab68Smrg	data = prefix;
2106ca08ab68Smrg    }
2107ca08ab68Smrg#ifdef _WIN32
2108ca08ab68Smrg    if (strcmp ((const char *) data, "CUSTOMFONTDIR") == 0)
2109ca08ab68Smrg    {
2110c9710b42Smrg	FcChar8 *p;
2111ca08ab68Smrg	data = buffer;
2112ca08ab68Smrg	if (!GetModuleFileName (NULL, (LPCH) buffer, sizeof (buffer) - 20))
2113ca08ab68Smrg	{
2114ca08ab68Smrg	    FcConfigMessage (parse, FcSevereError, "GetModuleFileName failed");
2115ca08ab68Smrg	    goto bail;
2116ca08ab68Smrg	}
2117ca08ab68Smrg	/*
2118ca08ab68Smrg	 * Must use the multi-byte aware function to search
2119ca08ab68Smrg	 * for backslash because East Asian double-byte code
2120ca08ab68Smrg	 * pages have characters with backslash as the second
2121ca08ab68Smrg	 * byte.
2122ca08ab68Smrg	 */
2123ca08ab68Smrg	p = _mbsrchr (data, '\\');
2124ca08ab68Smrg	if (p) *p = '\0';
2125c9710b42Smrg	strcat ((char *) data, "\\fonts");
2126ca08ab68Smrg    }
2127ca08ab68Smrg    else if (strcmp ((const char *) data, "APPSHAREFONTDIR") == 0)
2128ca08ab68Smrg    {
2129c9710b42Smrg	FcChar8 *p;
2130ca08ab68Smrg	data = buffer;
2131ca08ab68Smrg	if (!GetModuleFileName (NULL, (LPCH) buffer, sizeof (buffer) - 20))
2132ca08ab68Smrg	{
2133ca08ab68Smrg	    FcConfigMessage (parse, FcSevereError, "GetModuleFileName failed");
2134ca08ab68Smrg	    goto bail;
2135ca08ab68Smrg	}
2136ca08ab68Smrg	p = _mbsrchr (data, '\\');
2137ca08ab68Smrg	if (p) *p = '\0';
2138c9710b42Smrg	strcat ((char *) data, "\\..\\share\\fonts");
2139ca08ab68Smrg    }
2140ca08ab68Smrg    else if (strcmp ((const char *) data, "WINDOWSFONTDIR") == 0)
2141ca08ab68Smrg    {
2142ca08ab68Smrg	int rc;
2143ca08ab68Smrg	data = buffer;
2144ca08ab68Smrg	rc = pGetSystemWindowsDirectory ((LPSTR) buffer, sizeof (buffer) - 20);
2145ca08ab68Smrg	if (rc == 0 || rc > sizeof (buffer) - 20)
2146ca08ab68Smrg	{
2147ca08ab68Smrg	    FcConfigMessage (parse, FcSevereError, "GetSystemWindowsDirectory failed");
2148ca08ab68Smrg	    goto bail;
2149ca08ab68Smrg	}
2150ca08ab68Smrg	if (data [strlen ((const char *) data) - 1] != '\\')
2151c9710b42Smrg	    strcat ((char *) data, "\\");
2152c9710b42Smrg	strcat ((char *) data, "fonts");
2153ca08ab68Smrg    }
2154ca08ab68Smrg#endif
2155ca08ab68Smrg    if (strlen ((char *) data) == 0)
2156ca08ab68Smrg	FcConfigMessage (parse, FcSevereWarning, "empty font directory name ignored");
2157ca08ab68Smrg    else if (!FcStrUsesHome (data) || FcConfigHome ())
2158ca08ab68Smrg    {
2159ca08ab68Smrg	if (!FcConfigAddDir (parse->config, data))
2160ca08ab68Smrg	    FcConfigMessage (parse, FcSevereError, "out of memory; cannot add directory %s", data);
2161ca08ab68Smrg    }
2162ca08ab68Smrg    FcStrBufDestroy (&parse->pstack->str);
2163ca08ab68Smrg
2164ca08ab68Smrg  bail:
2165ca08ab68Smrg    if (prefix)
2166ca08ab68Smrg	FcStrFree (prefix);
2167ca08ab68Smrg}
2168ca08ab68Smrg
2169ca08ab68Smrgstatic void
2170ca08ab68SmrgFcParseCacheDir (FcConfigParse *parse)
2171ca08ab68Smrg{
2172ca08ab68Smrg    const FcChar8 *attr;
2173953daebaSmrg    FcChar8 *prefix = NULL, *p, *data = NULL;
2174ca08ab68Smrg
2175ca08ab68Smrg    attr = FcConfigGetAttribute (parse, "prefix");
2176ca08ab68Smrg    if (attr && FcStrCmp (attr, (const FcChar8 *)"xdg") == 0)
2177953daebaSmrg    {
2178ca08ab68Smrg	prefix = FcConfigXdgCacheHome ();
2179953daebaSmrg	/* home directory might be disabled.
2180953daebaSmrg	 * simply ignore this element.
2181953daebaSmrg	 */
2182953daebaSmrg	if (!prefix)
2183953daebaSmrg	    goto bail;
2184953daebaSmrg    }
2185ca08ab68Smrg    data = FcStrBufDone (&parse->pstack->str);
2186ca08ab68Smrg    if (!data)
2187ca08ab68Smrg    {
2188ca08ab68Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
2189ca08ab68Smrg	goto bail;
2190ca08ab68Smrg    }
2191ca08ab68Smrg    if (prefix)
2192ca08ab68Smrg    {
2193ca08ab68Smrg	size_t plen = strlen ((const char *)prefix);
2194ca08ab68Smrg	size_t dlen = strlen ((const char *)data);
2195ca08ab68Smrg
2196c9710b42Smrg	p = realloc (prefix, plen + 1 + dlen + 1);
2197c9710b42Smrg	if (!p)
2198ca08ab68Smrg	{
2199ca08ab68Smrg	    FcConfigMessage (parse, FcSevereError, "out of memory");
2200c9710b42Smrg	    data = prefix;
2201ca08ab68Smrg	    goto bail;
2202ca08ab68Smrg	}
2203c9710b42Smrg	prefix = p;
2204ca08ab68Smrg	prefix[plen] = FC_DIR_SEPARATOR;
2205ca08ab68Smrg	memcpy (&prefix[plen + 1], data, dlen);
2206ca08ab68Smrg	prefix[plen + 1 + dlen] = 0;
2207ca08ab68Smrg	FcStrFree (data);
2208ca08ab68Smrg	data = prefix;
2209ca08ab68Smrg    }
2210ca08ab68Smrg#ifdef _WIN32
2211953daebaSmrg    else if (data[0] == '/' && fontconfig_instprefix[0] != '\0')
2212953daebaSmrg    {
2213953daebaSmrg	size_t plen = strlen ((const char *)fontconfig_instprefix);
2214953daebaSmrg	size_t dlen = strlen ((const char *)data);
2215953daebaSmrg
2216953daebaSmrg	prefix = malloc (plen + 1 + dlen + 1);
2217953daebaSmrg	if (!prefix)
2218953daebaSmrg	{
2219953daebaSmrg	    FcConfigMessage (parse, FcSevereError, "out of memory");
2220953daebaSmrg	    goto bail;
2221953daebaSmrg	}
2222953daebaSmrg	strcpy ((char *) prefix, (char *) fontconfig_instprefix);
2223953daebaSmrg	prefix[plen] = FC_DIR_SEPARATOR;
2224953daebaSmrg	memcpy (&prefix[plen + 1], data, dlen);
2225953daebaSmrg	prefix[plen + 1 + dlen] = 0;
2226953daebaSmrg	FcStrFree (data);
2227953daebaSmrg	data = prefix;
2228953daebaSmrg    }
2229953daebaSmrg    else if (strcmp ((const char *) data, "WINDOWSTEMPDIR_FONTCONFIG_CACHE") == 0)
2230ca08ab68Smrg    {
2231ca08ab68Smrg	int rc;
2232ca08ab68Smrg	FcStrFree (data);
2233ca08ab68Smrg	data = malloc (1000);
2234ca08ab68Smrg	if (!data)
2235ca08ab68Smrg	{
2236ca08ab68Smrg	    FcConfigMessage (parse, FcSevereError, "out of memory");
2237ca08ab68Smrg	    goto bail;
2238ca08ab68Smrg	}
2239ca08ab68Smrg	rc = GetTempPath (800, (LPSTR) data);
2240ca08ab68Smrg	if (rc == 0 || rc > 800)
2241ca08ab68Smrg	{
2242ca08ab68Smrg	    FcConfigMessage (parse, FcSevereError, "GetTempPath failed");
2243ca08ab68Smrg	    goto bail;
2244ca08ab68Smrg	}
2245ca08ab68Smrg	if (data [strlen ((const char *) data) - 1] != '\\')
2246c9710b42Smrg	    strcat ((char *) data, "\\");
2247c9710b42Smrg	strcat ((char *) data, "fontconfig\\cache");
2248ca08ab68Smrg    }
2249ca08ab68Smrg    else if (strcmp ((const char *) data, "LOCAL_APPDATA_FONTCONFIG_CACHE") == 0)
2250ca08ab68Smrg    {
2251ca08ab68Smrg	char szFPath[MAX_PATH + 1];
2252ca08ab68Smrg	size_t len;
2253ca08ab68Smrg
2254ca08ab68Smrg	if (!(pSHGetFolderPathA && SUCCEEDED(pSHGetFolderPathA(NULL, /* CSIDL_LOCAL_APPDATA */ 28, NULL, 0, szFPath))))
2255ca08ab68Smrg	{
2256ca08ab68Smrg	    FcConfigMessage (parse, FcSevereError, "SHGetFolderPathA failed");
2257ca08ab68Smrg	    goto bail;
2258ca08ab68Smrg	}
2259ca08ab68Smrg	strncat(szFPath, "\\fontconfig\\cache", MAX_PATH - 1 - strlen(szFPath));
2260ca08ab68Smrg	len = strlen(szFPath) + 1;
2261ca08ab68Smrg	FcStrFree (data);
2262ca08ab68Smrg	data = malloc(len);
2263ca08ab68Smrg	if (!data)
2264ca08ab68Smrg	{
2265ca08ab68Smrg	    FcConfigMessage (parse, FcSevereError, "out of memory");
2266ca08ab68Smrg	    goto bail;
2267ca08ab68Smrg	}
2268ca08ab68Smrg	strncpy((char *) data, szFPath, len);
2269ca08ab68Smrg    }
2270ca08ab68Smrg#endif
2271ca08ab68Smrg    if (strlen ((char *) data) == 0)
2272ca08ab68Smrg	FcConfigMessage (parse, FcSevereWarning, "empty cache directory name ignored");
2273ca08ab68Smrg    else if (!FcStrUsesHome (data) || FcConfigHome ())
2274ca08ab68Smrg    {
2275ca08ab68Smrg	if (!FcConfigAddCacheDir (parse->config, data))
2276ca08ab68Smrg	    FcConfigMessage (parse, FcSevereError, "out of memory; cannot add cache directory %s", data);
2277ca08ab68Smrg    }
2278ca08ab68Smrg    FcStrBufDestroy (&parse->pstack->str);
2279ca08ab68Smrg
2280ca08ab68Smrg  bail:
2281ca08ab68Smrg    if (data)
2282ca08ab68Smrg	FcStrFree (data);
2283ca08ab68Smrg}
2284ca08ab68Smrg
2285953daebaSmrgvoid
2286953daebaSmrgFcConfigPathFini (void)
2287953daebaSmrg{
2288953daebaSmrg    FcChar8 *s;
2289953daebaSmrg
2290953daebaSmrgretry_dir:
2291953daebaSmrg    s = fc_atomic_ptr_get (&__fc_userdir);
2292953daebaSmrg    if (!fc_atomic_ptr_cmpexch (&__fc_userdir, s, NULL))
2293953daebaSmrg	goto retry_dir;
2294953daebaSmrg    free (s);
2295953daebaSmrg
2296953daebaSmrgretry_conf:
2297953daebaSmrg    s = fc_atomic_ptr_get (&__fc_userconf);
2298953daebaSmrg    if (!fc_atomic_ptr_cmpexch (&__fc_userconf, s, NULL))
2299953daebaSmrg	goto retry_conf;
2300953daebaSmrg    free (s);
2301953daebaSmrg}
2302953daebaSmrg
23032c393a42Smrgstatic void
23042c393a42SmrgFcParseInclude (FcConfigParse *parse)
23052c393a42Smrg{
23062c393a42Smrg    FcChar8	    *s;
2307ca08ab68Smrg    const FcChar8   *attr;
23082c393a42Smrg    FcBool	    ignore_missing = FcFalse;
2309953daebaSmrg#ifndef _WIN32
2310ca08ab68Smrg    FcBool	    deprecated = FcFalse;
2311953daebaSmrg#endif
2312c9710b42Smrg    FcChar8	    *prefix = NULL, *p;
2313953daebaSmrg    FcChar8	    *userdir = NULL, *userconf = NULL;
2314ca08ab68Smrg
2315a6844aabSmrg    s = FcStrBufDoneStatic (&parse->pstack->str);
23162c393a42Smrg    if (!s)
23172c393a42Smrg    {
23182c393a42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
2319ca08ab68Smrg	goto bail;
23202c393a42Smrg    }
2321ca08ab68Smrg    attr = FcConfigGetAttribute (parse, "ignore_missing");
2322ca08ab68Smrg    if (attr && FcConfigLexBool (parse, (FcChar8 *) attr) == FcTrue)
23232c393a42Smrg	ignore_missing = FcTrue;
2324ca08ab68Smrg    attr = FcConfigGetAttribute (parse, "deprecated");
2325953daebaSmrg#ifndef _WIN32
2326ca08ab68Smrg    if (attr && FcConfigLexBool (parse, (FcChar8 *) attr) == FcTrue)
2327ca08ab68Smrg        deprecated = FcTrue;
2328953daebaSmrg#endif
2329ca08ab68Smrg    attr = FcConfigGetAttribute (parse, "prefix");
2330ca08ab68Smrg    if (attr && FcStrCmp (attr, (const FcChar8 *)"xdg") == 0)
2331953daebaSmrg    {
2332ca08ab68Smrg	prefix = FcConfigXdgConfigHome ();
2333953daebaSmrg	/* home directory might be disabled.
2334953daebaSmrg	 * simply ignore this element.
2335953daebaSmrg	 */
2336953daebaSmrg	if (!prefix)
2337953daebaSmrg	    goto bail;
2338953daebaSmrg    }
2339ca08ab68Smrg    if (prefix)
2340ca08ab68Smrg    {
2341ca08ab68Smrg	size_t plen = strlen ((const char *)prefix);
2342ca08ab68Smrg	size_t dlen = strlen ((const char *)s);
2343953daebaSmrg	FcChar8 *u;
2344ca08ab68Smrg
2345c9710b42Smrg	p = realloc (prefix, plen + 1 + dlen + 1);
2346c9710b42Smrg	if (!p)
2347ca08ab68Smrg	{
2348ca08ab68Smrg	    FcConfigMessage (parse, FcSevereError, "out of memory");
2349ca08ab68Smrg	    goto bail;
2350ca08ab68Smrg	}
2351c9710b42Smrg	prefix = p;
2352ca08ab68Smrg	prefix[plen] = FC_DIR_SEPARATOR;
2353ca08ab68Smrg	memcpy (&prefix[plen + 1], s, dlen);
2354ca08ab68Smrg	prefix[plen + 1 + dlen] = 0;
2355ca08ab68Smrg	s = prefix;
23566fc018e4Smrg	if (FcFileIsDir (s))
23576fc018e4Smrg	{
23586fc018e4Smrg	userdir:
2359953daebaSmrg	    userdir = fc_atomic_ptr_get (&__fc_userdir);
23606fc018e4Smrg	    if (!userdir)
2361953daebaSmrg	    {
2362953daebaSmrg		u = FcStrdup (s);
2363953daebaSmrg		if (!fc_atomic_ptr_cmpexch (&__fc_userdir, userdir, u))
2364953daebaSmrg		{
2365953daebaSmrg		    free (u);
2366953daebaSmrg		    goto userdir;
2367953daebaSmrg		}
2368953daebaSmrg		userdir = u;
2369953daebaSmrg	    }
23706fc018e4Smrg	}
23716fc018e4Smrg	else if (FcFileIsFile (s))
23726fc018e4Smrg	{
23736fc018e4Smrg	userconf:
2374953daebaSmrg	    userconf = fc_atomic_ptr_get (&__fc_userconf);
23756fc018e4Smrg	    if (!userconf)
2376953daebaSmrg	    {
2377953daebaSmrg		u = FcStrdup (s);
2378953daebaSmrg		if (!fc_atomic_ptr_cmpexch (&__fc_userconf, userconf, u))
2379953daebaSmrg		{
2380953daebaSmrg		    free (u);
2381953daebaSmrg		    goto userconf;
2382953daebaSmrg		}
2383953daebaSmrg		userconf = u;
2384953daebaSmrg	    }
23856fc018e4Smrg	}
23866fc018e4Smrg	else
23876fc018e4Smrg	{
23886fc018e4Smrg	    /* No config dir nor file on the XDG directory spec compliant place
23896fc018e4Smrg	     * so need to guess what it is supposed to be.
23906fc018e4Smrg	     */
23916fc018e4Smrg	    if (FcStrStr (s, (const FcChar8 *)"conf.d") != NULL)
23926fc018e4Smrg		goto userdir;
23936fc018e4Smrg	    else
23946fc018e4Smrg		goto userconf;
23956fc018e4Smrg	}
2396ca08ab68Smrg    }
23972c393a42Smrg    if (!FcConfigParseAndLoad (parse->config, s, !ignore_missing))
23982c393a42Smrg	parse->error = FcTrue;
23996fc018e4Smrg#ifndef _WIN32
2400ca08ab68Smrg    else
2401ca08ab68Smrg    {
2402ca08ab68Smrg        FcChar8 *filename;
24036fc018e4Smrg	static FcBool warn_conf = FcFalse, warn_confd = FcFalse;
2404ca08ab68Smrg
2405ca08ab68Smrg        filename = FcConfigFilename(s);
2406c9710b42Smrg	if (deprecated == FcTrue &&
2407c9710b42Smrg	    filename != NULL &&
2408953daebaSmrg	    userdir != NULL &&
2409c9710b42Smrg	    !FcFileIsLink (filename))
2410c9710b42Smrg	{
24116fc018e4Smrg	    if (FcFileIsDir (filename))
24126fc018e4Smrg	    {
24136fc018e4Smrg		FcChar8 *parent = FcStrDirname (userdir);
24146fc018e4Smrg
24156fc018e4Smrg		if (!FcFileIsDir (parent))
24166fc018e4Smrg		    FcMakeDirectory (parent);
24176fc018e4Smrg		FcStrFree (parent);
24186fc018e4Smrg		if (FcFileIsDir (userdir) ||
24196fc018e4Smrg		    rename ((const char *)filename, (const char *)userdir) != 0 ||
24206fc018e4Smrg		    symlink ((const char *)userdir, (const char *)filename) != 0)
24216fc018e4Smrg		{
24226fc018e4Smrg		    if (!warn_confd)
24236fc018e4Smrg		    {
24246fc018e4Smrg			FcConfigMessage (parse, FcSevereWarning, "reading configurations from %s is deprecated. please move it to %s manually", s, userdir);
24256fc018e4Smrg			warn_confd = FcTrue;
24266fc018e4Smrg		    }
24276fc018e4Smrg		}
24286fc018e4Smrg	    }
24296fc018e4Smrg	    else
24306fc018e4Smrg	    {
24316fc018e4Smrg		FcChar8 *parent = FcStrDirname (userconf);
24326fc018e4Smrg
24336fc018e4Smrg		if (!FcFileIsDir (parent))
24346fc018e4Smrg		    FcMakeDirectory (parent);
24356fc018e4Smrg		FcStrFree (parent);
24366fc018e4Smrg		if (FcFileIsFile (userconf) ||
24376fc018e4Smrg		    rename ((const char *)filename, (const char *)userconf) != 0 ||
24386fc018e4Smrg		    symlink ((const char *)userconf, (const char *)filename) != 0)
24396fc018e4Smrg		{
24406fc018e4Smrg		    if (!warn_conf)
24416fc018e4Smrg		    {
24426fc018e4Smrg			FcConfigMessage (parse, FcSevereWarning, "reading configurations from %s is deprecated. please move it to %s manually", s, userconf);
24436fc018e4Smrg			warn_conf = FcTrue;
24446fc018e4Smrg		    }
24456fc018e4Smrg		}
24466fc018e4Smrg	    }
2447ca08ab68Smrg        }
2448ca08ab68Smrg        if(filename)
2449ca08ab68Smrg            FcStrFree(filename);
2450ca08ab68Smrg    }
24516fc018e4Smrg#endif
2452a6844aabSmrg    FcStrBufDestroy (&parse->pstack->str);
2453ca08ab68Smrg
2454ca08ab68Smrg  bail:
2455ca08ab68Smrg    if (prefix)
2456ca08ab68Smrg	FcStrFree (prefix);
24572c393a42Smrg}
24582c393a42Smrg
24592c393a42Smrgtypedef struct _FcOpMap {
24602c393a42Smrg    char    name[16];
24612c393a42Smrg    FcOp    op;
24622c393a42Smrg} FcOpMap;
24632c393a42Smrg
24642c393a42Smrgstatic FcOp
24652c393a42SmrgFcConfigLexOp (const FcChar8 *op, const FcOpMap	*map, int nmap)
24662c393a42Smrg{
24672c393a42Smrg    int	i;
24682c393a42Smrg
24692c393a42Smrg    for (i = 0; i < nmap; i++)
2470ca08ab68Smrg	if (!strcmp ((char *) op, map[i].name))
24712c393a42Smrg	    return map[i].op;
24722c393a42Smrg    return FcOpInvalid;
24732c393a42Smrg}
24742c393a42Smrg
24752c393a42Smrgstatic const FcOpMap fcCompareOps[] = {
24762c393a42Smrg    { "eq",		FcOpEqual	    },
24772c393a42Smrg    { "not_eq",		FcOpNotEqual	    },
24782c393a42Smrg    { "less",		FcOpLess	    },
24792c393a42Smrg    { "less_eq",	FcOpLessEqual	    },
24802c393a42Smrg    { "more",		FcOpMore	    },
24812c393a42Smrg    { "more_eq",	FcOpMoreEqual	    },
24822c393a42Smrg    { "contains",	FcOpContains	    },
24832c393a42Smrg    { "not_contains",	FcOpNotContains	    }
24842c393a42Smrg};
24852c393a42Smrg
24862c393a42Smrg#define NUM_COMPARE_OPS	(int) (sizeof fcCompareOps / sizeof fcCompareOps[0])
24872c393a42Smrg
24882c393a42Smrgstatic FcOp
24892c393a42SmrgFcConfigLexCompare (const FcChar8 *compare)
24902c393a42Smrg{
24912c393a42Smrg    return FcConfigLexOp (compare, fcCompareOps, NUM_COMPARE_OPS);
24922c393a42Smrg}
24932c393a42Smrg
24942c393a42Smrgstatic void
24952c393a42SmrgFcParseTest (FcConfigParse *parse)
24962c393a42Smrg{
24972c393a42Smrg    const FcChar8   *kind_string;
24982c393a42Smrg    FcMatchKind	    kind;
24992c393a42Smrg    const FcChar8   *qual_string;
25002c393a42Smrg    FcQual	    qual;
25012c393a42Smrg    const FcChar8   *name;
25022c393a42Smrg    const FcChar8   *compare_string;
25032c393a42Smrg    FcOp	    compare;
25042c393a42Smrg    FcExpr	    *expr;
25052c393a42Smrg    FcTest	    *test;
2506ca08ab68Smrg    const FcChar8   *iblanks_string;
2507ca08ab68Smrg    int              flags = 0;
25082c393a42Smrg
25092c393a42Smrg    kind_string = FcConfigGetAttribute (parse, "target");
25102c393a42Smrg    if (!kind_string)
25112c393a42Smrg	kind = FcMatchDefault;
25122c393a42Smrg    else
25132c393a42Smrg    {
25142c393a42Smrg	if (!strcmp ((char *) kind_string, "pattern"))
25152c393a42Smrg	    kind = FcMatchPattern;
25162c393a42Smrg	else if (!strcmp ((char *) kind_string, "font"))
25172c393a42Smrg	    kind = FcMatchFont;
25182c393a42Smrg	else if (!strcmp ((char *) kind_string, "scan"))
25192c393a42Smrg	    kind = FcMatchScan;
25202c393a42Smrg	else if (!strcmp ((char *) kind_string, "default"))
25212c393a42Smrg	    kind = FcMatchDefault;
25222c393a42Smrg	else
25232c393a42Smrg	{
25242c393a42Smrg	    FcConfigMessage (parse, FcSevereWarning, "invalid test target \"%s\"", kind_string);
25252c393a42Smrg	    return;
25262c393a42Smrg	}
25272c393a42Smrg    }
25282c393a42Smrg    qual_string = FcConfigGetAttribute (parse, "qual");
25292c393a42Smrg    if (!qual_string)
25302c393a42Smrg	qual = FcQualAny;
25312c393a42Smrg    else
25322c393a42Smrg    {
25332c393a42Smrg	if (!strcmp ((char *) qual_string, "any"))
25342c393a42Smrg	    qual = FcQualAny;
25352c393a42Smrg	else if (!strcmp ((char *) qual_string, "all"))
25362c393a42Smrg	    qual = FcQualAll;
25372c393a42Smrg	else if (!strcmp ((char *) qual_string, "first"))
25382c393a42Smrg	    qual = FcQualFirst;
25392c393a42Smrg	else if (!strcmp ((char *) qual_string, "not_first"))
25402c393a42Smrg	    qual = FcQualNotFirst;
25412c393a42Smrg	else
25422c393a42Smrg	{
25432c393a42Smrg	    FcConfigMessage (parse, FcSevereWarning, "invalid test qual \"%s\"", qual_string);
25442c393a42Smrg	    return;
25452c393a42Smrg	}
25462c393a42Smrg    }
25472c393a42Smrg    name = FcConfigGetAttribute (parse, "name");
25482c393a42Smrg    if (!name)
25492c393a42Smrg    {
25502c393a42Smrg	FcConfigMessage (parse, FcSevereWarning, "missing test name");
25512c393a42Smrg	return;
25522c393a42Smrg    }
25532c393a42Smrg    compare_string = FcConfigGetAttribute (parse, "compare");
25542c393a42Smrg    if (!compare_string)
25552c393a42Smrg	compare = FcOpEqual;
25562c393a42Smrg    else
25572c393a42Smrg    {
25582c393a42Smrg	compare = FcConfigLexCompare (compare_string);
25592c393a42Smrg	if (compare == FcOpInvalid)
25602c393a42Smrg	{
25612c393a42Smrg	    FcConfigMessage (parse, FcSevereWarning, "invalid test compare \"%s\"", compare_string);
25622c393a42Smrg	    return;
25632c393a42Smrg	}
25642c393a42Smrg    }
2565ca08ab68Smrg    iblanks_string = FcConfigGetAttribute (parse, "ignore-blanks");
2566ca08ab68Smrg    if (iblanks_string)
2567ca08ab68Smrg    {
2568ca08ab68Smrg	FcBool f = FcFalse;
2569ca08ab68Smrg
2570ca08ab68Smrg	if (!FcNameBool (iblanks_string, &f))
2571ca08ab68Smrg	{
2572ca08ab68Smrg	    FcConfigMessage (parse,
2573ca08ab68Smrg			     FcSevereWarning,
2574ca08ab68Smrg			     "invalid test ignore-blanks \"%s\"", iblanks_string);
2575ca08ab68Smrg	}
2576ca08ab68Smrg	if (f)
2577ca08ab68Smrg	    flags |= FcOpFlagIgnoreBlanks;
2578ca08ab68Smrg    }
25792c393a42Smrg    expr = FcPopBinary (parse, FcOpComma);
25802c393a42Smrg    if (!expr)
25812c393a42Smrg    {
25822c393a42Smrg	FcConfigMessage (parse, FcSevereWarning, "missing test expression");
25832c393a42Smrg	return;
25842c393a42Smrg    }
2585ca08ab68Smrg    if (expr->op == FcOpComma)
2586ca08ab68Smrg    {
2587ca08ab68Smrg	FcConfigMessage (parse, FcSevereWarning, "Having multiple values in <test> isn't supported and may not work as expected");
2588ca08ab68Smrg    }
2589ca08ab68Smrg    test = FcTestCreate (parse, kind, qual, name, FC_OP (compare, flags), expr);
25902c393a42Smrg    if (!test)
25912c393a42Smrg    {
25922c393a42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
25932c393a42Smrg	return;
25942c393a42Smrg    }
25952c393a42Smrg    FcVStackPushTest (parse, test);
25962c393a42Smrg}
25972c393a42Smrg
25982c393a42Smrgstatic const FcOpMap fcModeOps[] = {
25992c393a42Smrg    { "assign",		FcOpAssign	    },
26002c393a42Smrg    { "assign_replace",	FcOpAssignReplace   },
26012c393a42Smrg    { "prepend",	FcOpPrepend	    },
26022c393a42Smrg    { "prepend_first",	FcOpPrependFirst    },
26032c393a42Smrg    { "append",		FcOpAppend	    },
26042c393a42Smrg    { "append_last",	FcOpAppendLast	    },
2605c9710b42Smrg    { "delete",		FcOpDelete	    },
2606c9710b42Smrg    { "delete_all",	FcOpDeleteAll	    },
26072c393a42Smrg};
26082c393a42Smrg
26092c393a42Smrg#define NUM_MODE_OPS (int) (sizeof fcModeOps / sizeof fcModeOps[0])
26102c393a42Smrg
26112c393a42Smrgstatic FcOp
26122c393a42SmrgFcConfigLexMode (const FcChar8 *mode)
26132c393a42Smrg{
26142c393a42Smrg    return FcConfigLexOp (mode, fcModeOps, NUM_MODE_OPS);
26152c393a42Smrg}
26162c393a42Smrg
26172c393a42Smrgstatic void
26182c393a42SmrgFcParseEdit (FcConfigParse *parse)
26192c393a42Smrg{
26202c393a42Smrg    const FcChar8   *name;
26212c393a42Smrg    const FcChar8   *mode_string;
26222c393a42Smrg    FcOp	    mode;
26232c393a42Smrg    FcValueBinding  binding;
26242c393a42Smrg    FcExpr	    *expr;
26252c393a42Smrg    FcEdit	    *edit;
26262c393a42Smrg
26272c393a42Smrg    name = FcConfigGetAttribute (parse, "name");
26282c393a42Smrg    if (!name)
26292c393a42Smrg    {
26302c393a42Smrg	FcConfigMessage (parse, FcSevereWarning, "missing edit name");
26312c393a42Smrg	return;
26322c393a42Smrg    }
26332c393a42Smrg    mode_string = FcConfigGetAttribute (parse, "mode");
26342c393a42Smrg    if (!mode_string)
26352c393a42Smrg	mode = FcOpAssign;
26362c393a42Smrg    else
26372c393a42Smrg    {
26382c393a42Smrg	mode = FcConfigLexMode (mode_string);
26392c393a42Smrg	if (mode == FcOpInvalid)
26402c393a42Smrg	{
26412c393a42Smrg	    FcConfigMessage (parse, FcSevereWarning, "invalid edit mode \"%s\"", mode_string);
26422c393a42Smrg	    return;
26432c393a42Smrg	}
26442c393a42Smrg    }
26452c393a42Smrg    if (!FcConfigLexBinding (parse, FcConfigGetAttribute (parse, "binding"), &binding))
26462c393a42Smrg	return;
26472c393a42Smrg
26482c393a42Smrg    expr = FcPopBinary (parse, FcOpComma);
2649c9710b42Smrg    if ((mode == FcOpDelete || mode == FcOpDeleteAll) &&
2650c9710b42Smrg	expr != NULL)
2651c9710b42Smrg    {
2652c9710b42Smrg	FcConfigMessage (parse, FcSevereWarning, "Expression doesn't take any effects for delete and delete_all");
2653c9710b42Smrg	FcExprDestroy (expr);
2654c9710b42Smrg	expr = NULL;
2655c9710b42Smrg    }
26562c393a42Smrg    edit = FcEditCreate (parse, FcObjectFromName ((char *) name),
26572c393a42Smrg			 mode, expr, binding);
26582c393a42Smrg    if (!edit)
26592c393a42Smrg    {
26602c393a42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
26612c393a42Smrg	FcExprDestroy (expr);
26622c393a42Smrg	return;
26632c393a42Smrg    }
26642c393a42Smrg    if (!FcVStackPushEdit (parse, edit))
26652c393a42Smrg	FcEditDestroy (edit);
26662c393a42Smrg}
26672c393a42Smrg
26682c393a42Smrgstatic void
26692c393a42SmrgFcParseMatch (FcConfigParse *parse)
26702c393a42Smrg{
26712c393a42Smrg    const FcChar8   *kind_name;
26722c393a42Smrg    FcMatchKind	    kind;
26732c393a42Smrg    FcVStack	    *vstack;
26746fc018e4Smrg    FcRule	    *rule = NULL, *r;
26752c393a42Smrg
26762c393a42Smrg    kind_name = FcConfigGetAttribute (parse, "target");
26772c393a42Smrg    if (!kind_name)
26782c393a42Smrg	kind = FcMatchPattern;
26792c393a42Smrg    else
26802c393a42Smrg    {
26812c393a42Smrg	if (!strcmp ((char *) kind_name, "pattern"))
26822c393a42Smrg	    kind = FcMatchPattern;
26832c393a42Smrg	else if (!strcmp ((char *) kind_name, "font"))
26842c393a42Smrg	    kind = FcMatchFont;
26852c393a42Smrg	else if (!strcmp ((char *) kind_name, "scan"))
26862c393a42Smrg	    kind = FcMatchScan;
26872c393a42Smrg	else
26882c393a42Smrg	{
26892c393a42Smrg	    FcConfigMessage (parse, FcSevereWarning, "invalid match target \"%s\"", kind_name);
26902c393a42Smrg	    return;
26912c393a42Smrg	}
26922c393a42Smrg    }
2693a6844aabSmrg    while ((vstack = FcVStackPeek (parse)))
26942c393a42Smrg    {
2695c9710b42Smrg	switch ((int) vstack->tag) {
26962c393a42Smrg	case FcVStackTest:
26976fc018e4Smrg	    r = FcRuleCreate (FcRuleTest, vstack->u.test);
26986fc018e4Smrg	    if (rule)
26996fc018e4Smrg		r->next = rule;
27006fc018e4Smrg	    rule = r;
27012c393a42Smrg	    vstack->tag = FcVStackNone;
27022c393a42Smrg	    break;
27032c393a42Smrg	case FcVStackEdit:
27046fc018e4Smrg	    if (kind == FcMatchScan && vstack->u.edit->object > FC_MAX_BASE_OBJECT)
27052c393a42Smrg	    {
2706ca08ab68Smrg		FcConfigMessage (parse, FcSevereError,
27072c393a42Smrg				 "<match target=\"scan\"> cannot edit user-defined object \"%s\"",
27086fc018e4Smrg				 FcObjectName(vstack->u.edit->object));
27096fc018e4Smrg		if (rule)
27106fc018e4Smrg		    FcRuleDestroy (rule);
27116fc018e4Smrg		return;
27122c393a42Smrg	    }
27136fc018e4Smrg	    r = FcRuleCreate (FcRuleEdit, vstack->u.edit);
27146fc018e4Smrg	    if (rule)
27156fc018e4Smrg		r->next = rule;
27166fc018e4Smrg	    rule = r;
27176fc018e4Smrg	    vstack->tag = FcVStackNone;
27182c393a42Smrg	    break;
27192c393a42Smrg	default:
27202c393a42Smrg	    FcConfigMessage (parse, FcSevereWarning, "invalid match element");
27212c393a42Smrg	    break;
27222c393a42Smrg	}
2723a6844aabSmrg	FcVStackPopAndDestroy (parse);
27242c393a42Smrg    }
2725b09479dcSmrg    if (!rule)
2726b09479dcSmrg    {
2727b09479dcSmrg	FcConfigMessage (parse, FcSevereWarning, "No <test> nor <edit> elements in <match>");
2728b09479dcSmrg	return;
2729b09479dcSmrg    }
27306fc018e4Smrg    if (!FcConfigAddRule (parse->config, rule, kind))
27312c393a42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
27322c393a42Smrg}
27332c393a42Smrg
27342c393a42Smrgstatic void
27352c393a42SmrgFcParseAcceptRejectFont (FcConfigParse *parse, FcElement element)
27362c393a42Smrg{
27372c393a42Smrg    FcVStack	*vstack;
27382c393a42Smrg
2739a6844aabSmrg    while ((vstack = FcVStackPeek (parse)))
27402c393a42Smrg    {
2741c9710b42Smrg	switch ((int) vstack->tag) {
27422c393a42Smrg	case FcVStackGlob:
2743ca08ab68Smrg	    if (!FcConfigGlobAdd (parse->config,
27442c393a42Smrg				  vstack->u.string,
27452c393a42Smrg				  element == FcElementAcceptfont))
27462c393a42Smrg	    {
27472c393a42Smrg		FcConfigMessage (parse, FcSevereError, "out of memory");
27482c393a42Smrg	    }
27492c393a42Smrg	    break;
27502c393a42Smrg	case FcVStackPattern:
27512c393a42Smrg	    if (!FcConfigPatternsAdd (parse->config,
27522c393a42Smrg				      vstack->u.pattern,
27532c393a42Smrg				      element == FcElementAcceptfont))
27542c393a42Smrg	    {
27552c393a42Smrg		FcConfigMessage (parse, FcSevereError, "out of memory");
27562c393a42Smrg	    }
27572c393a42Smrg	    else
27582c393a42Smrg		vstack->tag = FcVStackNone;
27592c393a42Smrg	    break;
27602c393a42Smrg	default:
27612c393a42Smrg	    FcConfigMessage (parse, FcSevereWarning, "bad font selector");
27622c393a42Smrg	    break;
27632c393a42Smrg	}
2764a6844aabSmrg	FcVStackPopAndDestroy (parse);
27652c393a42Smrg    }
27662c393a42Smrg}
27672c393a42Smrg
27682c393a42Smrg
27692c393a42Smrgstatic FcValue
27702c393a42SmrgFcPopValue (FcConfigParse *parse)
27712c393a42Smrg{
2772a6844aabSmrg    FcVStack	*vstack = FcVStackPeek (parse);
27732c393a42Smrg    FcValue	value;
2774ca08ab68Smrg
27752c393a42Smrg    value.type = FcTypeVoid;
2776ca08ab68Smrg
27772c393a42Smrg    if (!vstack)
27782c393a42Smrg	return value;
2779ca08ab68Smrg
2780c9710b42Smrg    switch ((int) vstack->tag) {
27812c393a42Smrg    case FcVStackString:
2782c9710b42Smrg	value.u.s = FcStrdup (vstack->u.string);
27832c393a42Smrg	if (value.u.s)
27842c393a42Smrg	    value.type = FcTypeString;
27852c393a42Smrg	break;
27862c393a42Smrg    case FcVStackConstant:
27872c393a42Smrg	if (FcNameConstant (vstack->u.string, &value.u.i))
27882c393a42Smrg	    value.type = FcTypeInteger;
27892c393a42Smrg	break;
27902c393a42Smrg    case FcVStackInteger:
27912c393a42Smrg	value.u.i = vstack->u.integer;
27922c393a42Smrg	value.type = FcTypeInteger;
27932c393a42Smrg	break;
27942c393a42Smrg    case FcVStackDouble:
27952c393a42Smrg	value.u.d = vstack->u._double;
2796c9710b42Smrg	value.type = FcTypeDouble;
27972c393a42Smrg	break;
27982c393a42Smrg    case FcVStackBool:
2799a6844aabSmrg	value.u.b = vstack->u.bool_;
28002c393a42Smrg	value.type = FcTypeBool;
28012c393a42Smrg	break;
2802ca08ab68Smrg    case FcVStackCharSet:
2803ca08ab68Smrg	value.u.c = FcCharSetCopy (vstack->u.charset);
2804ca08ab68Smrg	if (value.u.c)
2805ca08ab68Smrg	    value.type = FcTypeCharSet;
2806ca08ab68Smrg	break;
2807ca08ab68Smrg    case FcVStackLangSet:
2808ca08ab68Smrg	value.u.l = FcLangSetCopy (vstack->u.langset);
2809ca08ab68Smrg	if (value.u.l)
2810ca08ab68Smrg	    value.type = FcTypeLangSet;
2811ca08ab68Smrg	break;
2812953daebaSmrg    case FcVStackRange:
2813953daebaSmrg	value.u.r = FcRangeCopy (vstack->u.range);
2814953daebaSmrg	if (value.u.r)
2815953daebaSmrg	    value.type = FcTypeRange;
2816953daebaSmrg	break;
28172c393a42Smrg    default:
2818ca08ab68Smrg	FcConfigMessage (parse, FcSevereWarning, "unknown pattern element %d",
28192c393a42Smrg			 vstack->tag);
28202c393a42Smrg	break;
28212c393a42Smrg    }
2822a6844aabSmrg    FcVStackPopAndDestroy (parse);
2823ca08ab68Smrg
28242c393a42Smrg    return value;
28252c393a42Smrg}
28262c393a42Smrg
28272c393a42Smrgstatic void
28282c393a42SmrgFcParsePatelt (FcConfigParse *parse)
28292c393a42Smrg{
28302c393a42Smrg    FcValue	value;
28312c393a42Smrg    FcPattern	*pattern = FcPatternCreate ();
28322c393a42Smrg    const char	*name;
28332c393a42Smrg
28342c393a42Smrg    if (!pattern)
28352c393a42Smrg    {
28362c393a42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
28372c393a42Smrg	return;
28382c393a42Smrg    }
28392c393a42Smrg
28402c393a42Smrg    name = (char *) FcConfigGetAttribute (parse, "name");
28412c393a42Smrg    if (!name)
28422c393a42Smrg    {
28432c393a42Smrg	FcConfigMessage (parse, FcSevereWarning, "missing pattern element name");
28442c393a42Smrg	FcPatternDestroy (pattern);
28452c393a42Smrg	return;
28462c393a42Smrg    }
2847ca08ab68Smrg
28482c393a42Smrg    for (;;)
28492c393a42Smrg    {
28502c393a42Smrg	value = FcPopValue (parse);
28512c393a42Smrg	if (value.type == FcTypeVoid)
28522c393a42Smrg	    break;
28532c393a42Smrg	if (!FcPatternAdd (pattern, name, value, FcTrue))
28542c393a42Smrg	{
28552c393a42Smrg	    FcConfigMessage (parse, FcSevereError, "out of memory");
2856a6844aabSmrg            FcValueDestroy(value);
28572c393a42Smrg	    break;
28582c393a42Smrg	}
2859a6844aabSmrg        FcValueDestroy(value);
28602c393a42Smrg    }
28612c393a42Smrg
28622c393a42Smrg    FcVStackPushPattern (parse, pattern);
28632c393a42Smrg}
28642c393a42Smrg
28652c393a42Smrgstatic void
28662c393a42SmrgFcParsePattern (FcConfigParse *parse)
28672c393a42Smrg{
28682c393a42Smrg    FcVStack	*vstack;
28692c393a42Smrg    FcPattern	*pattern = FcPatternCreate ();
28702c393a42Smrg
28712c393a42Smrg    if (!pattern)
28722c393a42Smrg    {
28732c393a42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
28742c393a42Smrg	return;
28752c393a42Smrg    }
28762c393a42Smrg
2877a6844aabSmrg    while ((vstack = FcVStackPeek (parse)))
28782c393a42Smrg    {
2879c9710b42Smrg	switch ((int) vstack->tag) {
28802c393a42Smrg	case FcVStackPattern:
28812c393a42Smrg	    if (!FcPatternAppend (pattern, vstack->u.pattern))
28822c393a42Smrg	    {
28832c393a42Smrg		FcConfigMessage (parse, FcSevereError, "out of memory");
28842c393a42Smrg		FcPatternDestroy (pattern);
28852c393a42Smrg		return;
28862c393a42Smrg	    }
28872c393a42Smrg	    break;
28882c393a42Smrg	default:
28892c393a42Smrg	    FcConfigMessage (parse, FcSevereWarning, "unknown pattern element");
28902c393a42Smrg	    break;
28912c393a42Smrg	}
2892a6844aabSmrg	FcVStackPopAndDestroy (parse);
28932c393a42Smrg    }
28942c393a42Smrg
28952c393a42Smrg    FcVStackPushPattern (parse, pattern);
28962c393a42Smrg}
28972c393a42Smrg
28982c393a42Smrgstatic void
2899c9710b42SmrgFcEndElement(void *userData, const XML_Char *name FC_UNUSED)
29002c393a42Smrg{
29012c393a42Smrg    FcConfigParse   *parse = userData;
29022c393a42Smrg    FcChar8	    *data;
2903a6844aabSmrg
29042c393a42Smrg    if (!parse->pstack)
29052c393a42Smrg	return;
29062c393a42Smrg    switch (parse->pstack->element) {
29072c393a42Smrg    case FcElementNone:
29082c393a42Smrg	break;
29092c393a42Smrg    case FcElementFontconfig:
29102c393a42Smrg	break;
29112c393a42Smrg    case FcElementDir:
2912ca08ab68Smrg	FcParseDir (parse);
29132c393a42Smrg	break;
29142c393a42Smrg    case FcElementCacheDir:
2915ca08ab68Smrg	FcParseCacheDir (parse);
29162c393a42Smrg	break;
29172c393a42Smrg    case FcElementCache:
2918a6844aabSmrg	data = FcStrBufDoneStatic (&parse->pstack->str);
29192c393a42Smrg	if (!data)
29202c393a42Smrg	{
29212c393a42Smrg	    FcConfigMessage (parse, FcSevereError, "out of memory");
29222c393a42Smrg	    break;
29232c393a42Smrg	}
29242c393a42Smrg	/* discard this data; no longer used */
2925a6844aabSmrg	FcStrBufDestroy (&parse->pstack->str);
29262c393a42Smrg	break;
29272c393a42Smrg    case FcElementInclude:
29282c393a42Smrg	FcParseInclude (parse);
29292c393a42Smrg	break;
29302c393a42Smrg    case FcElementConfig:
29312c393a42Smrg	break;
29322c393a42Smrg    case FcElementMatch:
29332c393a42Smrg	FcParseMatch (parse);
29342c393a42Smrg	break;
29352c393a42Smrg    case FcElementAlias:
29362c393a42Smrg	FcParseAlias (parse);
29372c393a42Smrg	break;
29382c393a42Smrg
29392c393a42Smrg    case FcElementBlank:
29402c393a42Smrg	FcParseBlank (parse);
29412c393a42Smrg	break;
29422c393a42Smrg    case FcElementRescan:
29432c393a42Smrg	FcParseRescan (parse);
29442c393a42Smrg	break;
29452c393a42Smrg
29462c393a42Smrg    case FcElementPrefer:
29472c393a42Smrg	FcParseFamilies (parse, FcVStackPrefer);
29482c393a42Smrg	break;
29492c393a42Smrg    case FcElementAccept:
29502c393a42Smrg	FcParseFamilies (parse, FcVStackAccept);
29512c393a42Smrg	break;
29522c393a42Smrg    case FcElementDefault:
29532c393a42Smrg	FcParseFamilies (parse, FcVStackDefault);
29542c393a42Smrg	break;
29552c393a42Smrg    case FcElementFamily:
29562c393a42Smrg	FcParseFamily (parse);
29572c393a42Smrg	break;
29582c393a42Smrg
29592c393a42Smrg    case FcElementTest:
29602c393a42Smrg	FcParseTest (parse);
29612c393a42Smrg	break;
29622c393a42Smrg    case FcElementEdit:
29632c393a42Smrg	FcParseEdit (parse);
29642c393a42Smrg	break;
29652c393a42Smrg
29662c393a42Smrg    case FcElementInt:
29672c393a42Smrg	FcParseInt (parse);
29682c393a42Smrg	break;
29692c393a42Smrg    case FcElementDouble:
29702c393a42Smrg	FcParseDouble (parse);
29712c393a42Smrg	break;
29722c393a42Smrg    case FcElementString:
29732c393a42Smrg	FcParseString (parse, FcVStackString);
29742c393a42Smrg	break;
29752c393a42Smrg    case FcElementMatrix:
29762c393a42Smrg	FcParseMatrix (parse);
29772c393a42Smrg	break;
2978ca08ab68Smrg    case FcElementRange:
2979ca08ab68Smrg	FcParseRange (parse);
2980ca08ab68Smrg	break;
29812c393a42Smrg    case FcElementBool:
29822c393a42Smrg	FcParseBool (parse);
29832c393a42Smrg	break;
2984ca08ab68Smrg    case FcElementCharSet:
2985ca08ab68Smrg	FcParseCharSet (parse);
2986ca08ab68Smrg	break;
2987ca08ab68Smrg    case FcElementLangSet:
2988ca08ab68Smrg	FcParseLangSet (parse);
29892c393a42Smrg	break;
29902c393a42Smrg    case FcElementSelectfont:
29912c393a42Smrg	break;
29922c393a42Smrg    case FcElementAcceptfont:
29932c393a42Smrg    case FcElementRejectfont:
29942c393a42Smrg	FcParseAcceptRejectFont (parse, parse->pstack->element);
29952c393a42Smrg	break;
29962c393a42Smrg    case FcElementGlob:
29972c393a42Smrg	FcParseString (parse, FcVStackGlob);
29982c393a42Smrg	break;
29992c393a42Smrg    case FcElementPattern:
30002c393a42Smrg	FcParsePattern (parse);
30012c393a42Smrg	break;
30022c393a42Smrg    case FcElementPatelt:
30032c393a42Smrg	FcParsePatelt (parse);
30042c393a42Smrg	break;
30052c393a42Smrg    case FcElementName:
3006c9710b42Smrg	FcParseName (parse);
30072c393a42Smrg	break;
30082c393a42Smrg    case FcElementConst:
30092c393a42Smrg	FcParseString (parse, FcVStackConstant);
30102c393a42Smrg	break;
30112c393a42Smrg    case FcElementOr:
30122c393a42Smrg	FcParseBinary (parse, FcOpOr);
30132c393a42Smrg	break;
30142c393a42Smrg    case FcElementAnd:
30152c393a42Smrg	FcParseBinary (parse, FcOpAnd);
30162c393a42Smrg	break;
30172c393a42Smrg    case FcElementEq:
30182c393a42Smrg	FcParseBinary (parse, FcOpEqual);
30192c393a42Smrg	break;
30202c393a42Smrg    case FcElementNotEq:
30212c393a42Smrg	FcParseBinary (parse, FcOpNotEqual);
30222c393a42Smrg	break;
30232c393a42Smrg    case FcElementLess:
30242c393a42Smrg	FcParseBinary (parse, FcOpLess);
30252c393a42Smrg	break;
30262c393a42Smrg    case FcElementLessEq:
30272c393a42Smrg	FcParseBinary (parse, FcOpLessEqual);
30282c393a42Smrg	break;
30292c393a42Smrg    case FcElementMore:
30302c393a42Smrg	FcParseBinary (parse, FcOpMore);
30312c393a42Smrg	break;
30322c393a42Smrg    case FcElementMoreEq:
30332c393a42Smrg	FcParseBinary (parse, FcOpMoreEqual);
30342c393a42Smrg	break;
30352c393a42Smrg    case FcElementContains:
30362c393a42Smrg	FcParseBinary (parse, FcOpContains);
30372c393a42Smrg	break;
30382c393a42Smrg    case FcElementNotContains:
30392c393a42Smrg	FcParseBinary (parse, FcOpNotContains);
30402c393a42Smrg	break;
30412c393a42Smrg    case FcElementPlus:
30422c393a42Smrg	FcParseBinary (parse, FcOpPlus);
30432c393a42Smrg	break;
30442c393a42Smrg    case FcElementMinus:
30452c393a42Smrg	FcParseBinary (parse, FcOpMinus);
30462c393a42Smrg	break;
30472c393a42Smrg    case FcElementTimes:
30482c393a42Smrg	FcParseBinary (parse, FcOpTimes);
30492c393a42Smrg	break;
30502c393a42Smrg    case FcElementDivide:
30512c393a42Smrg	FcParseBinary (parse, FcOpDivide);
30522c393a42Smrg	break;
30532c393a42Smrg    case FcElementNot:
30542c393a42Smrg	FcParseUnary (parse, FcOpNot);
30552c393a42Smrg	break;
30562c393a42Smrg    case FcElementIf:
30572c393a42Smrg	FcParseBinary (parse, FcOpQuest);
30582c393a42Smrg	break;
30592c393a42Smrg    case FcElementFloor:
30602c393a42Smrg	FcParseUnary (parse, FcOpFloor);
30612c393a42Smrg	break;
30622c393a42Smrg    case FcElementCeil:
30632c393a42Smrg	FcParseUnary (parse, FcOpCeil);
30642c393a42Smrg	break;
30652c393a42Smrg    case FcElementRound:
30662c393a42Smrg	FcParseUnary (parse, FcOpRound);
30672c393a42Smrg	break;
30682c393a42Smrg    case FcElementTrunc:
30692c393a42Smrg	FcParseUnary (parse, FcOpTrunc);
30702c393a42Smrg	break;
30712c393a42Smrg    case FcElementUnknown:
30722c393a42Smrg	break;
30732c393a42Smrg    }
30742c393a42Smrg    (void) FcPStackPop (parse);
30752c393a42Smrg}
30762c393a42Smrg
30772c393a42Smrgstatic void
30782c393a42SmrgFcCharacterData (void *userData, const XML_Char *s, int len)
30792c393a42Smrg{
30802c393a42Smrg    FcConfigParse   *parse = userData;
3081ca08ab68Smrg
30822c393a42Smrg    if (!parse->pstack)
30832c393a42Smrg	return;
30842c393a42Smrg    if (!FcStrBufData (&parse->pstack->str, (FcChar8 *) s, len))
30852c393a42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
30862c393a42Smrg}
30872c393a42Smrg
30882c393a42Smrgstatic void
30892c393a42SmrgFcStartDoctypeDecl (void	    *userData,
30902c393a42Smrg		    const XML_Char  *doctypeName,
3091c9710b42Smrg		    const XML_Char  *sysid FC_UNUSED,
3092c9710b42Smrg		    const XML_Char  *pubid FC_UNUSED,
3093c9710b42Smrg		    int		    has_internal_subset FC_UNUSED)
30942c393a42Smrg{
30952c393a42Smrg    FcConfigParse   *parse = userData;
30962c393a42Smrg
30972c393a42Smrg    if (strcmp ((char *) doctypeName, "fontconfig") != 0)
30982c393a42Smrg	FcConfigMessage (parse, FcSevereError, "invalid doctype \"%s\"", doctypeName);
30992c393a42Smrg}
31002c393a42Smrg
31012c393a42Smrg#ifdef ENABLE_LIBXML2
31022c393a42Smrg
31032c393a42Smrgstatic void
31042c393a42SmrgFcInternalSubsetDecl (void            *userData,
31052c393a42Smrg		      const XML_Char  *doctypeName,
31062c393a42Smrg		      const XML_Char  *sysid,
31072c393a42Smrg		      const XML_Char  *pubid)
31082c393a42Smrg{
31092c393a42Smrg    FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 1);
31102c393a42Smrg}
31112c393a42Smrg
31122c393a42Smrgstatic void
31132c393a42SmrgFcExternalSubsetDecl (void            *userData,
31142c393a42Smrg		      const XML_Char  *doctypeName,
31152c393a42Smrg		      const XML_Char  *sysid,
31162c393a42Smrg		      const XML_Char  *pubid)
31172c393a42Smrg{
31182c393a42Smrg    FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 0);
31192c393a42Smrg}
31202c393a42Smrg
31212c393a42Smrg#else /* ENABLE_LIBXML2 */
31222c393a42Smrg
31232c393a42Smrgstatic void
3124c9710b42SmrgFcEndDoctypeDecl (void *userData FC_UNUSED)
31252c393a42Smrg{
31262c393a42Smrg}
31272c393a42Smrg
31282c393a42Smrg#endif /* ENABLE_LIBXML2 */
31292c393a42Smrg
31302c393a42Smrgstatic int
31312c393a42SmrgFcSortCmpStr (const void *a, const void *b)
31322c393a42Smrg{
31332c393a42Smrg    const FcChar8    *as = *((FcChar8 **) a);
31342c393a42Smrg    const FcChar8    *bs = *((FcChar8 **) b);
31352c393a42Smrg    return FcStrCmp (as, bs);
31362c393a42Smrg}
31372c393a42Smrg
31382c393a42Smrgstatic FcBool
31392c393a42SmrgFcConfigParseAndLoadDir (FcConfig	*config,
31402c393a42Smrg			 const FcChar8	*name,
31412c393a42Smrg			 const FcChar8	*dir,
31422c393a42Smrg			 FcBool		complain)
31432c393a42Smrg{
31442c393a42Smrg    DIR		    *d;
31452c393a42Smrg    struct dirent   *e;
31462c393a42Smrg    FcBool	    ret = FcTrue;
31472c393a42Smrg    FcChar8	    *file;
31482c393a42Smrg    FcChar8	    *base;
31492c393a42Smrg    FcStrSet	    *files;
31502c393a42Smrg
31512c393a42Smrg    d = opendir ((char *) dir);
31522c393a42Smrg    if (!d)
31532c393a42Smrg    {
31542c393a42Smrg	if (complain)
31552c393a42Smrg	    FcConfigMessage (0, FcSevereError, "Cannot open config dir \"%s\"",
31562c393a42Smrg			     name);
31572c393a42Smrg	ret = FcFalse;
31582c393a42Smrg	goto bail0;
31592c393a42Smrg    }
31602c393a42Smrg    /* freed below */
31612c393a42Smrg    file = (FcChar8 *) malloc (strlen ((char *) dir) + 1 + FC_MAX_FILE_LEN + 1);
31622c393a42Smrg    if (!file)
31632c393a42Smrg    {
31642c393a42Smrg	ret = FcFalse;
31652c393a42Smrg	goto bail1;
31662c393a42Smrg    }
3167ca08ab68Smrg
31682c393a42Smrg    strcpy ((char *) file, (char *) dir);
31692c393a42Smrg    strcat ((char *) file, "/");
31702c393a42Smrg    base = file + strlen ((char *) file);
3171ca08ab68Smrg
3172953daebaSmrg    files = FcStrSetCreateEx (FCSS_GROW_BY_64);
31732c393a42Smrg    if (!files)
31742c393a42Smrg    {
31752c393a42Smrg	ret = FcFalse;
31762c393a42Smrg	goto bail2;
31772c393a42Smrg    }
3178ca08ab68Smrg
31792c393a42Smrg    if (FcDebug () & FC_DBG_CONFIG)
31802c393a42Smrg	printf ("\tScanning config dir %s\n", dir);
31812c393a42Smrg
31822c393a42Smrg    while (ret && (e = readdir (d)))
31832c393a42Smrg    {
31842c393a42Smrg	int d_len;
31852c393a42Smrg#define TAIL	    ".conf"
31862c393a42Smrg#define TAIL_LEN    5
31872c393a42Smrg	/*
31882c393a42Smrg	 * Add all files of the form [0-9]*.conf
31892c393a42Smrg	 */
31902c393a42Smrg	if ('0' <= e->d_name[0] && e->d_name[0] <= '9' &&
31912c393a42Smrg	    (d_len = strlen (e->d_name)) < FC_MAX_FILE_LEN &&
31922c393a42Smrg	    d_len > TAIL_LEN &&
31932c393a42Smrg	    strcmp (e->d_name + d_len - TAIL_LEN, TAIL) == 0)
31942c393a42Smrg	{
31952c393a42Smrg	    strcpy ((char *) base, (char *) e->d_name);
31962c393a42Smrg	    if (!FcStrSetAdd (files, file))
31972c393a42Smrg	    {
31982c393a42Smrg		ret = FcFalse;
31992c393a42Smrg		goto bail3;
32002c393a42Smrg	    }
32012c393a42Smrg	}
32022c393a42Smrg    }
32032c393a42Smrg    if (ret)
32042c393a42Smrg    {
32052c393a42Smrg	int i;
3206ca08ab68Smrg	qsort (files->strs, files->num, sizeof (FcChar8 *),
32072c393a42Smrg	       (int (*)(const void *, const void *)) FcSortCmpStr);
32082c393a42Smrg	for (i = 0; ret && i < files->num; i++)
32092c393a42Smrg	    ret = FcConfigParseAndLoad (config, files->strs[i], complain);
32102c393a42Smrg    }
32112c393a42Smrgbail3:
32122c393a42Smrg    FcStrSetDestroy (files);
32132c393a42Smrgbail2:
32142c393a42Smrg    free (file);
32152c393a42Smrgbail1:
32162c393a42Smrg    closedir (d);
32172c393a42Smrgbail0:
32182c393a42Smrg    return ret || !complain;
32192c393a42Smrg}
32202c393a42Smrg
3221ca08ab68Smrg#ifdef _WIN32
3222ca08ab68SmrgpfnGetSystemWindowsDirectory pGetSystemWindowsDirectory = NULL;
3223ca08ab68SmrgpfnSHGetFolderPathA pSHGetFolderPathA = NULL;
3224ca08ab68Smrg#endif
3225ca08ab68Smrg
32262c393a42SmrgFcBool
32272c393a42SmrgFcConfigParseAndLoad (FcConfig	    *config,
32282c393a42Smrg		      const FcChar8 *name,
32292c393a42Smrg		      FcBool	    complain)
32302c393a42Smrg{
32312c393a42Smrg
32322c393a42Smrg    XML_Parser	    p;
3233953daebaSmrg    FcChar8	    *filename, *f;
32342c393a42Smrg    int		    fd;
32352c393a42Smrg    int		    len;
32362c393a42Smrg    FcConfigParse   parse;
32372c393a42Smrg    FcBool	    error = FcTrue;
3238953daebaSmrg    const FcChar8   *sysroot = FcConfigGetSysRoot (config);
3239ca08ab68Smrg
32402c393a42Smrg#ifdef ENABLE_LIBXML2
32412c393a42Smrg    xmlSAXHandler   sax;
32422c393a42Smrg    char            buf[BUFSIZ];
32432c393a42Smrg#else
32442c393a42Smrg    void	    *buf;
32452c393a42Smrg#endif
3246ca08ab68Smrg
3247ca08ab68Smrg#ifdef _WIN32
3248ca08ab68Smrg    if (!pGetSystemWindowsDirectory)
3249ca08ab68Smrg    {
3250ca08ab68Smrg        HMODULE hk32 = GetModuleHandleA("kernel32.dll");
3251ca08ab68Smrg        if (!(pGetSystemWindowsDirectory = (pfnGetSystemWindowsDirectory) GetProcAddress(hk32, "GetSystemWindowsDirectoryA")))
3252ca08ab68Smrg            pGetSystemWindowsDirectory = (pfnGetSystemWindowsDirectory) GetWindowsDirectory;
3253ca08ab68Smrg    }
3254ca08ab68Smrg    if (!pSHGetFolderPathA)
3255ca08ab68Smrg    {
3256ca08ab68Smrg        HMODULE hSh = LoadLibraryA("shfolder.dll");
3257ca08ab68Smrg        /* the check is done later, because there is no provided fallback */
3258ca08ab68Smrg        if (hSh)
3259ca08ab68Smrg            pSHGetFolderPathA = (pfnSHGetFolderPathA) GetProcAddress(hSh, "SHGetFolderPathA");
3260ca08ab68Smrg    }
3261ca08ab68Smrg#endif
3262ca08ab68Smrg
3263953daebaSmrg    f = FcConfigFilename (name);
3264953daebaSmrg    if (!f)
32652c393a42Smrg	goto bail0;
3266953daebaSmrg    if (sysroot)
3267953daebaSmrg	filename = FcStrBuildFilename (sysroot, f, NULL);
3268953daebaSmrg    else
3269953daebaSmrg	filename = FcStrdup (f);
3270953daebaSmrg    FcStrFree (f);
3271ca08ab68Smrg
32722c393a42Smrg    if (FcStrSetMember (config->configFiles, filename))
32732c393a42Smrg    {
32742c393a42Smrg        FcStrFree (filename);
32752c393a42Smrg        return FcTrue;
32762c393a42Smrg    }
32772c393a42Smrg
32782c393a42Smrg    if (!FcStrSetAdd (config->configFiles, filename))
32792c393a42Smrg    {
32802c393a42Smrg	FcStrFree (filename);
32812c393a42Smrg	goto bail0;
32822c393a42Smrg    }
32832c393a42Smrg
32842c393a42Smrg    if (FcFileIsDir (filename))
32852c393a42Smrg    {
32862c393a42Smrg	FcBool ret = FcConfigParseAndLoadDir (config, name, filename, complain);
32872c393a42Smrg	FcStrFree (filename);
32882c393a42Smrg	return ret;
32892c393a42Smrg    }
32902c393a42Smrg
32912c393a42Smrg    if (FcDebug () & FC_DBG_CONFIG)
32922c393a42Smrg	printf ("\tLoading config file %s\n", filename);
32932c393a42Smrg
3294c9710b42Smrg    fd = FcOpen ((char *) filename, O_RDONLY);
3295ca08ab68Smrg    if (fd == -1) {
32962c393a42Smrg	FcStrFree (filename);
32972c393a42Smrg	goto bail0;
32982c393a42Smrg    }
3299ca08ab68Smrg
33002c393a42Smrg#ifdef ENABLE_LIBXML2
33012c393a42Smrg    memset(&sax, 0, sizeof(sax));
33022c393a42Smrg
33032c393a42Smrg    sax.internalSubset = FcInternalSubsetDecl;
33042c393a42Smrg    sax.externalSubset = FcExternalSubsetDecl;
33052c393a42Smrg    sax.startElement = FcStartElement;
33062c393a42Smrg    sax.endElement = FcEndElement;
33072c393a42Smrg    sax.characters = FcCharacterData;
33082c393a42Smrg
33092c393a42Smrg    p = xmlCreatePushParserCtxt (&sax, &parse, NULL, 0, (const char *) filename);
33102c393a42Smrg#else
33112c393a42Smrg    p = XML_ParserCreate ("UTF-8");
33122c393a42Smrg#endif
33132c393a42Smrg    FcStrFree (filename);
33142c393a42Smrg
33152c393a42Smrg    if (!p)
33162c393a42Smrg	goto bail1;
33172c393a42Smrg
3318c9710b42Smrg    if (!FcConfigParseInit (&parse, name, config, p))
33192c393a42Smrg	goto bail2;
33202c393a42Smrg
33212c393a42Smrg#ifndef ENABLE_LIBXML2
33222c393a42Smrg
33232c393a42Smrg    XML_SetUserData (p, &parse);
3324ca08ab68Smrg
33252c393a42Smrg    XML_SetDoctypeDeclHandler (p, FcStartDoctypeDecl, FcEndDoctypeDecl);
33262c393a42Smrg    XML_SetElementHandler (p, FcStartElement, FcEndElement);
33272c393a42Smrg    XML_SetCharacterDataHandler (p, FcCharacterData);
33282c393a42Smrg
33292c393a42Smrg#endif /* ENABLE_LIBXML2 */
33302c393a42Smrg
33312c393a42Smrg    do {
33322c393a42Smrg#ifndef ENABLE_LIBXML2
33332c393a42Smrg	buf = XML_GetBuffer (p, BUFSIZ);
33342c393a42Smrg	if (!buf)
33352c393a42Smrg	{
33362c393a42Smrg	    FcConfigMessage (&parse, FcSevereError, "cannot get parse buffer");
33372c393a42Smrg	    goto bail3;
33382c393a42Smrg	}
33392c393a42Smrg#endif
33402c393a42Smrg	len = read (fd, buf, BUFSIZ);
33412c393a42Smrg	if (len < 0)
33422c393a42Smrg	{
33432c393a42Smrg	    FcConfigMessage (&parse, FcSevereError, "failed reading config file");
33442c393a42Smrg	    goto bail3;
33452c393a42Smrg	}
33462c393a42Smrg
33472c393a42Smrg#ifdef ENABLE_LIBXML2
33482c393a42Smrg	if (xmlParseChunk (p, buf, len, len == 0))
33492c393a42Smrg#else
33502c393a42Smrg	if (!XML_ParseBuffer (p, len, len == 0))
33512c393a42Smrg#endif
33522c393a42Smrg	{
3353ca08ab68Smrg	    FcConfigMessage (&parse, FcSevereError, "%s",
33542c393a42Smrg			   XML_ErrorString (XML_GetErrorCode (p)));
33552c393a42Smrg	    goto bail3;
33562c393a42Smrg	}
33572c393a42Smrg    } while (len != 0);
33582c393a42Smrg    error = parse.error;
33592c393a42Smrgbail3:
33602c393a42Smrg    FcConfigCleanup (&parse);
33612c393a42Smrgbail2:
33622c393a42Smrg    XML_ParserFree (p);
33632c393a42Smrgbail1:
33642c393a42Smrg    close (fd);
33652c393a42Smrg    fd = -1;
33662c393a42Smrgbail0:
33672c393a42Smrg    if (error && complain)
33682c393a42Smrg    {
33692c393a42Smrg	if (name)
33702c393a42Smrg	    FcConfigMessage (0, FcSevereError, "Cannot load config file \"%s\"", name);
33712c393a42Smrg	else
33722c393a42Smrg	    FcConfigMessage (0, FcSevereError, "Cannot load default config file");
33732c393a42Smrg	return FcFalse;
33742c393a42Smrg    }
33752c393a42Smrg    return FcTrue;
33762c393a42Smrg}
33772c393a42Smrg#define __fcxml__
33782c393a42Smrg#include "fcaliastail.h"
33792c393a42Smrg#undef __fcxml__
3380