fcxml.c revision a4e54154
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"
26a4e54154Smrg#include <string.h>
272c393a42Smrg#include <fcntl.h>
282c393a42Smrg#include <stdarg.h>
29a4e54154Smrg
30a4e54154Smrg#ifdef HAVE_DIRENT_H
312c393a42Smrg#include <dirent.h>
32a4e54154Smrg#endif
332c393a42Smrg
342c393a42Smrg#ifdef ENABLE_LIBXML2
352c393a42Smrg
362c393a42Smrg#include <libxml/parser.h>
372c393a42Smrg
382c393a42Smrg#define XML_Char			xmlChar
392c393a42Smrg#define XML_Parser			xmlParserCtxtPtr
402c393a42Smrg#define XML_ParserFree			xmlFreeParserCtxt
412c393a42Smrg#define XML_GetCurrentLineNumber	xmlSAX2GetLineNumber
422c393a42Smrg#define XML_GetErrorCode		xmlCtxtGetLastError
432c393a42Smrg#define XML_ErrorString(Error)		(Error)->message
442c393a42Smrg
452c393a42Smrg#else /* ENABLE_LIBXML2 */
462c393a42Smrg
472c393a42Smrg#ifndef HAVE_XMLPARSE_H
482c393a42Smrg#define HAVE_XMLPARSE_H 0
492c393a42Smrg#endif
502c393a42Smrg
512c393a42Smrg#if HAVE_XMLPARSE_H
522c393a42Smrg#include <xmlparse.h>
532c393a42Smrg#else
542c393a42Smrg#include <expat.h>
552c393a42Smrg#endif
562c393a42Smrg
572c393a42Smrg#endif /* ENABLE_LIBXML2 */
582c393a42Smrg
592c393a42Smrg#ifdef _WIN32
60a6844aabSmrg#include <mbstring.h>
61953daebaSmrgextern FcChar8 fontconfig_instprefix[];
62a4e54154SmrgpfnGetSystemWindowsDirectory pGetSystemWindowsDirectory = NULL;
63a4e54154SmrgpfnSHGetFolderPathA pSHGetFolderPathA = NULL;
64a4e54154Smrgstatic void
65a4e54154Smrg_ensureWin32GettersReady();
662c393a42Smrg#endif
672c393a42Smrg
68953daebaSmrgstatic FcChar8  *__fc_userdir = NULL;
69953daebaSmrgstatic FcChar8  *__fc_userconf = NULL;
70953daebaSmrg
71a6844aabSmrgstatic void
72a6844aabSmrgFcExprDestroy (FcExpr *e);
73a32e9e42Smrgstatic FcBool
74a32e9e42Smrg_FcConfigParse (FcConfig	*config,
75a32e9e42Smrg		const FcChar8	*name,
76a32e9e42Smrg		FcBool		complain,
77a32e9e42Smrg		FcBool		load);
782c393a42Smrg
792c393a42Smrgvoid
802c393a42SmrgFcTestDestroy (FcTest *test)
812c393a42Smrg{
822c393a42Smrg    FcExprDestroy (test->expr);
832c393a42Smrg    free (test);
842c393a42Smrg}
852c393a42Smrg
866fc018e4Smrgvoid
876fc018e4SmrgFcRuleDestroy (FcRule *rule)
886fc018e4Smrg{
896fc018e4Smrg    FcRule *n = rule->next;
906fc018e4Smrg
916fc018e4Smrg    switch (rule->type) {
926fc018e4Smrg    case FcRuleTest:
936fc018e4Smrg	FcTestDestroy (rule->u.test);
946fc018e4Smrg	break;
956fc018e4Smrg    case FcRuleEdit:
966fc018e4Smrg	FcEditDestroy (rule->u.edit);
976fc018e4Smrg	break;
98953daebaSmrg    case FcRuleUnknown:
996fc018e4Smrg    default:
1006fc018e4Smrg	break;
1016fc018e4Smrg    }
1026fc018e4Smrg    free (rule);
1036fc018e4Smrg    if (n)
1046fc018e4Smrg	FcRuleDestroy (n);
1056fc018e4Smrg}
1066fc018e4Smrg
107a6844aabSmrgstatic FcExpr *
108a6844aabSmrgFcExprCreateInteger (FcConfig *config, int i)
1092c393a42Smrg{
110a6844aabSmrg    FcExpr *e = FcConfigAllocExpr (config);
1112c393a42Smrg    if (e)
1122c393a42Smrg    {
1132c393a42Smrg	e->op = FcOpInteger;
1142c393a42Smrg	e->u.ival = i;
1152c393a42Smrg    }
1162c393a42Smrg    return e;
1172c393a42Smrg}
1182c393a42Smrg
119a6844aabSmrgstatic FcExpr *
120a6844aabSmrgFcExprCreateDouble (FcConfig *config, double d)
1212c393a42Smrg{
122a6844aabSmrg    FcExpr *e = FcConfigAllocExpr (config);
1232c393a42Smrg    if (e)
1242c393a42Smrg    {
1252c393a42Smrg	e->op = FcOpDouble;
1262c393a42Smrg	e->u.dval = d;
1272c393a42Smrg    }
1282c393a42Smrg    return e;
1292c393a42Smrg}
1302c393a42Smrg
131a6844aabSmrgstatic FcExpr *
132a6844aabSmrgFcExprCreateString (FcConfig *config, const FcChar8 *s)
1332c393a42Smrg{
134a6844aabSmrg    FcExpr *e = FcConfigAllocExpr (config);
1352c393a42Smrg    if (e)
1362c393a42Smrg    {
1372c393a42Smrg	e->op = FcOpString;
138c9710b42Smrg	e->u.sval = FcStrdup (s);
1392c393a42Smrg    }
1402c393a42Smrg    return e;
1412c393a42Smrg}
1422c393a42Smrg
143c9710b42Smrgstatic FcExprMatrix *
144c9710b42SmrgFcExprMatrixCopyShallow (const FcExprMatrix *matrix)
145c9710b42Smrg{
146c9710b42Smrg  FcExprMatrix *m = malloc (sizeof (FcExprMatrix));
147c9710b42Smrg  if (m)
148c9710b42Smrg  {
149c9710b42Smrg    *m = *matrix;
150c9710b42Smrg  }
151c9710b42Smrg  return m;
152c9710b42Smrg}
153c9710b42Smrg
154c9710b42Smrgstatic void
155c9710b42SmrgFcExprMatrixFreeShallow (FcExprMatrix *m)
156c9710b42Smrg{
157c9710b42Smrg  if (!m)
158c9710b42Smrg    return;
159c9710b42Smrg
160c9710b42Smrg  free (m);
161c9710b42Smrg}
162c9710b42Smrg
163c9710b42Smrgstatic void
164c9710b42SmrgFcExprMatrixFree (FcExprMatrix *m)
165c9710b42Smrg{
166c9710b42Smrg  if (!m)
167c9710b42Smrg    return;
168c9710b42Smrg
169c9710b42Smrg  FcExprDestroy (m->xx);
170c9710b42Smrg  FcExprDestroy (m->xy);
171c9710b42Smrg  FcExprDestroy (m->yx);
172c9710b42Smrg  FcExprDestroy (m->yy);
173c9710b42Smrg
174c9710b42Smrg  free (m);
175c9710b42Smrg}
176c9710b42Smrg
177a6844aabSmrgstatic FcExpr *
178c9710b42SmrgFcExprCreateMatrix (FcConfig *config, const FcExprMatrix *matrix)
1792c393a42Smrg{
180a6844aabSmrg    FcExpr *e = FcConfigAllocExpr (config);
1812c393a42Smrg    if (e)
1822c393a42Smrg    {
1832c393a42Smrg	e->op = FcOpMatrix;
184c9710b42Smrg	e->u.mexpr = FcExprMatrixCopyShallow (matrix);
1852c393a42Smrg    }
1862c393a42Smrg    return e;
1872c393a42Smrg}
1882c393a42Smrg
189953daebaSmrgstatic FcExpr *
190953daebaSmrgFcExprCreateRange (FcConfig *config, FcRange *range)
191953daebaSmrg{
192953daebaSmrg    FcExpr *e = FcConfigAllocExpr (config);
193953daebaSmrg    if (e)
194953daebaSmrg    {
195953daebaSmrg	e->op = FcOpRange;
196953daebaSmrg	e->u.rval = FcRangeCopy (range);
197953daebaSmrg    }
198953daebaSmrg    return e;
199953daebaSmrg}
200953daebaSmrg
201a6844aabSmrgstatic FcExpr *
202a6844aabSmrgFcExprCreateBool (FcConfig *config, FcBool b)
2032c393a42Smrg{
204a6844aabSmrg    FcExpr *e = FcConfigAllocExpr (config);
2052c393a42Smrg    if (e)
2062c393a42Smrg    {
2072c393a42Smrg	e->op = FcOpBool;
2082c393a42Smrg	e->u.bval = b;
2092c393a42Smrg    }
2102c393a42Smrg    return e;
2112c393a42Smrg}
2122c393a42Smrg
213ca08ab68Smrgstatic FcExpr *
214ca08ab68SmrgFcExprCreateCharSet (FcConfig *config, FcCharSet *charset)
215ca08ab68Smrg{
216ca08ab68Smrg    FcExpr *e = FcConfigAllocExpr (config);
217ca08ab68Smrg    if (e)
218ca08ab68Smrg    {
219ca08ab68Smrg	e->op = FcOpCharSet;
220ca08ab68Smrg	e->u.cval = FcCharSetCopy (charset);
221ca08ab68Smrg    }
222ca08ab68Smrg    return e;
223ca08ab68Smrg}
224ca08ab68Smrg
225ca08ab68Smrgstatic FcExpr *
226ca08ab68SmrgFcExprCreateLangSet (FcConfig *config, FcLangSet *langset)
227ca08ab68Smrg{
228ca08ab68Smrg    FcExpr *e = FcConfigAllocExpr (config);
229ca08ab68Smrg    if (e)
230ca08ab68Smrg    {
231ca08ab68Smrg	e->op = FcOpLangSet;
232ca08ab68Smrg	e->u.lval = FcLangSetCopy (langset);
233ca08ab68Smrg    }
234ca08ab68Smrg    return e;
235ca08ab68Smrg}
236ca08ab68Smrg
237a6844aabSmrgstatic FcExpr *
238c9710b42SmrgFcExprCreateName (FcConfig *config, FcExprName name)
2392c393a42Smrg{
240a6844aabSmrg    FcExpr *e = FcConfigAllocExpr (config);
2412c393a42Smrg    if (e)
2422c393a42Smrg    {
2432c393a42Smrg	e->op = FcOpField;
244c9710b42Smrg	e->u.name = name;
2452c393a42Smrg    }
2462c393a42Smrg    return e;
2472c393a42Smrg}
2482c393a42Smrg
249a6844aabSmrgstatic FcExpr *
250a6844aabSmrgFcExprCreateConst (FcConfig *config, const FcChar8 *constant)
2512c393a42Smrg{
252a6844aabSmrg    FcExpr *e = FcConfigAllocExpr (config);
2532c393a42Smrg    if (e)
2542c393a42Smrg    {
2552c393a42Smrg	e->op = FcOpConst;
256c9710b42Smrg	e->u.constant = FcStrdup (constant);
2572c393a42Smrg    }
2582c393a42Smrg    return e;
2592c393a42Smrg}
2602c393a42Smrg
261a6844aabSmrgstatic FcExpr *
262a6844aabSmrgFcExprCreateOp (FcConfig *config, FcExpr *left, FcOp op, FcExpr *right)
2632c393a42Smrg{
264a6844aabSmrg    FcExpr *e = FcConfigAllocExpr (config);
2652c393a42Smrg    if (e)
2662c393a42Smrg    {
2672c393a42Smrg	e->op = op;
2682c393a42Smrg	e->u.tree.left = left;
2692c393a42Smrg	e->u.tree.right = right;
2702c393a42Smrg    }
2712c393a42Smrg    return e;
2722c393a42Smrg}
2732c393a42Smrg
274a6844aabSmrgstatic void
2752c393a42SmrgFcExprDestroy (FcExpr *e)
2762c393a42Smrg{
2772c393a42Smrg    if (!e)
2782c393a42Smrg	return;
279ca08ab68Smrg    switch (FC_OP_GET_OP (e->op)) {
2802c393a42Smrg    case FcOpInteger:
2812c393a42Smrg	break;
2822c393a42Smrg    case FcOpDouble:
2832c393a42Smrg	break;
2842c393a42Smrg    case FcOpString:
285c9710b42Smrg	FcFree (e->u.sval);
2862c393a42Smrg	break;
2872c393a42Smrg    case FcOpMatrix:
288c9710b42Smrg	FcExprMatrixFree (e->u.mexpr);
2892c393a42Smrg	break;
290ca08ab68Smrg    case FcOpRange:
291953daebaSmrg	FcRangeDestroy (e->u.rval);
292ca08ab68Smrg	break;
2932c393a42Smrg    case FcOpCharSet:
2942c393a42Smrg	FcCharSetDestroy (e->u.cval);
2952c393a42Smrg	break;
296ca08ab68Smrg    case FcOpLangSet:
297ca08ab68Smrg	FcLangSetDestroy (e->u.lval);
298ca08ab68Smrg	break;
2992c393a42Smrg    case FcOpBool:
3002c393a42Smrg	break;
3012c393a42Smrg    case FcOpField:
3022c393a42Smrg	break;
3032c393a42Smrg    case FcOpConst:
304c9710b42Smrg	FcFree (e->u.constant);
3052c393a42Smrg	break;
3062c393a42Smrg    case FcOpAssign:
3072c393a42Smrg    case FcOpAssignReplace:
3082c393a42Smrg    case FcOpPrepend:
3092c393a42Smrg    case FcOpPrependFirst:
3102c393a42Smrg    case FcOpAppend:
3112c393a42Smrg    case FcOpAppendLast:
312c9710b42Smrg    case FcOpDelete:
313c9710b42Smrg    case FcOpDeleteAll:
3142c393a42Smrg	break;
3152c393a42Smrg    case FcOpOr:
3162c393a42Smrg    case FcOpAnd:
3172c393a42Smrg    case FcOpEqual:
3182c393a42Smrg    case FcOpNotEqual:
3192c393a42Smrg    case FcOpLess:
3202c393a42Smrg    case FcOpLessEqual:
3212c393a42Smrg    case FcOpMore:
3222c393a42Smrg    case FcOpMoreEqual:
3232c393a42Smrg    case FcOpContains:
3242c393a42Smrg    case FcOpListing:
3252c393a42Smrg    case FcOpNotContains:
3262c393a42Smrg    case FcOpPlus:
3272c393a42Smrg    case FcOpMinus:
3282c393a42Smrg    case FcOpTimes:
3292c393a42Smrg    case FcOpDivide:
3302c393a42Smrg    case FcOpQuest:
3312c393a42Smrg    case FcOpComma:
3322c393a42Smrg	FcExprDestroy (e->u.tree.right);
3332c393a42Smrg	/* fall through */
3342c393a42Smrg    case FcOpNot:
3352c393a42Smrg    case FcOpFloor:
3362c393a42Smrg    case FcOpCeil:
3372c393a42Smrg    case FcOpRound:
3382c393a42Smrg    case FcOpTrunc:
3392c393a42Smrg	FcExprDestroy (e->u.tree.left);
3402c393a42Smrg	break;
3412c393a42Smrg    case FcOpNil:
3422c393a42Smrg    case FcOpInvalid:
3432c393a42Smrg	break;
3442c393a42Smrg    }
345a6844aabSmrg
346a6844aabSmrg    e->op = FcOpNil;
3472c393a42Smrg}
3482c393a42Smrg
3492c393a42Smrgvoid
3502c393a42SmrgFcEditDestroy (FcEdit *e)
3512c393a42Smrg{
3522c393a42Smrg    if (e->expr)
3532c393a42Smrg	FcExprDestroy (e->expr);
3542c393a42Smrg    free (e);
3552c393a42Smrg}
3562c393a42Smrg
3572c393a42Smrgtypedef enum _FcElement {
3582c393a42Smrg    FcElementNone,
3592c393a42Smrg    FcElementFontconfig,
3602c393a42Smrg    FcElementDir,
3612c393a42Smrg    FcElementCacheDir,
3622c393a42Smrg    FcElementCache,
3632c393a42Smrg    FcElementInclude,
3642c393a42Smrg    FcElementConfig,
3652c393a42Smrg    FcElementMatch,
3662c393a42Smrg    FcElementAlias,
367a32e9e42Smrg    FcElementDescription,
368a4e54154Smrg    FcElementRemapDir,
369a4e54154Smrg    FcElementResetDirs,
3702c393a42Smrg
3712c393a42Smrg    FcElementRescan,
3722c393a42Smrg
3732c393a42Smrg    FcElementPrefer,
3742c393a42Smrg    FcElementAccept,
3752c393a42Smrg    FcElementDefault,
3762c393a42Smrg    FcElementFamily,
3772c393a42Smrg
3782c393a42Smrg    FcElementSelectfont,
3792c393a42Smrg    FcElementAcceptfont,
3802c393a42Smrg    FcElementRejectfont,
3812c393a42Smrg    FcElementGlob,
3822c393a42Smrg    FcElementPattern,
3832c393a42Smrg    FcElementPatelt,
3842c393a42Smrg
3852c393a42Smrg    FcElementTest,
3862c393a42Smrg    FcElementEdit,
3872c393a42Smrg    FcElementInt,
3882c393a42Smrg    FcElementDouble,
3892c393a42Smrg    FcElementString,
3902c393a42Smrg    FcElementMatrix,
391ca08ab68Smrg    FcElementRange,
3922c393a42Smrg    FcElementBool,
393ca08ab68Smrg    FcElementCharSet,
394ca08ab68Smrg    FcElementLangSet,
3952c393a42Smrg    FcElementName,
3962c393a42Smrg    FcElementConst,
3972c393a42Smrg    FcElementOr,
3982c393a42Smrg    FcElementAnd,
3992c393a42Smrg    FcElementEq,
4002c393a42Smrg    FcElementNotEq,
4012c393a42Smrg    FcElementLess,
4022c393a42Smrg    FcElementLessEq,
4032c393a42Smrg    FcElementMore,
4042c393a42Smrg    FcElementMoreEq,
4052c393a42Smrg    FcElementContains,
4062c393a42Smrg    FcElementNotContains,
4072c393a42Smrg    FcElementPlus,
4082c393a42Smrg    FcElementMinus,
4092c393a42Smrg    FcElementTimes,
4102c393a42Smrg    FcElementDivide,
4112c393a42Smrg    FcElementNot,
4122c393a42Smrg    FcElementIf,
4132c393a42Smrg    FcElementFloor,
4142c393a42Smrg    FcElementCeil,
4152c393a42Smrg    FcElementRound,
4162c393a42Smrg    FcElementTrunc,
4172c393a42Smrg    FcElementUnknown
4182c393a42Smrg} FcElement;
4192c393a42Smrg
4202c393a42Smrgstatic const struct {
4212c393a42Smrg    const char  name[16];
4222c393a42Smrg    FcElement   element;
4232c393a42Smrg} fcElementMap[] = {
4242c393a42Smrg    { "fontconfig",	FcElementFontconfig },
4252c393a42Smrg    { "dir",		FcElementDir },
4262c393a42Smrg    { "cachedir",	FcElementCacheDir },
4272c393a42Smrg    { "cache",		FcElementCache },
4282c393a42Smrg    { "include",	FcElementInclude },
4292c393a42Smrg    { "config",		FcElementConfig },
4302c393a42Smrg    { "match",		FcElementMatch },
4312c393a42Smrg    { "alias",		FcElementAlias },
432a32e9e42Smrg    { "description",	FcElementDescription },
433a4e54154Smrg    { "remap-dir",	FcElementRemapDir },
434a4e54154Smrg    { "reset-dirs",	FcElementResetDirs },
435ca08ab68Smrg
4362c393a42Smrg    { "rescan",		FcElementRescan },
4372c393a42Smrg
4382c393a42Smrg    { "prefer",		FcElementPrefer },
4392c393a42Smrg    { "accept",		FcElementAccept },
4402c393a42Smrg    { "default",	FcElementDefault },
4412c393a42Smrg    { "family",		FcElementFamily },
4422c393a42Smrg
4432c393a42Smrg    { "selectfont",	FcElementSelectfont },
4442c393a42Smrg    { "acceptfont",	FcElementAcceptfont },
4452c393a42Smrg    { "rejectfont",	FcElementRejectfont },
4462c393a42Smrg    { "glob",		FcElementGlob },
4472c393a42Smrg    { "pattern",	FcElementPattern },
4482c393a42Smrg    { "patelt",		FcElementPatelt },
4492c393a42Smrg
4502c393a42Smrg    { "test",		FcElementTest },
4512c393a42Smrg    { "edit",		FcElementEdit },
4522c393a42Smrg    { "int",		FcElementInt },
4532c393a42Smrg    { "double",		FcElementDouble },
4542c393a42Smrg    { "string",		FcElementString },
4552c393a42Smrg    { "matrix",		FcElementMatrix },
456ca08ab68Smrg    { "range",		FcElementRange },
4572c393a42Smrg    { "bool",		FcElementBool },
458ca08ab68Smrg    { "charset",	FcElementCharSet },
459ca08ab68Smrg    { "langset",	FcElementLangSet },
4602c393a42Smrg    { "name",		FcElementName },
4612c393a42Smrg    { "const",		FcElementConst },
4622c393a42Smrg    { "or",		FcElementOr },
4632c393a42Smrg    { "and",		FcElementAnd },
4642c393a42Smrg    { "eq",		FcElementEq },
4652c393a42Smrg    { "not_eq",		FcElementNotEq },
4662c393a42Smrg    { "less",		FcElementLess },
4672c393a42Smrg    { "less_eq",	FcElementLessEq },
4682c393a42Smrg    { "more",		FcElementMore },
4692c393a42Smrg    { "more_eq",	FcElementMoreEq },
4702c393a42Smrg    { "contains",	FcElementContains },
4712c393a42Smrg    { "not_contains",	FcElementNotContains },
4722c393a42Smrg    { "plus",		FcElementPlus },
4732c393a42Smrg    { "minus",		FcElementMinus },
4742c393a42Smrg    { "times",		FcElementTimes },
4752c393a42Smrg    { "divide",		FcElementDivide },
4762c393a42Smrg    { "not",		FcElementNot },
4772c393a42Smrg    { "if",		FcElementIf },
4782c393a42Smrg    { "floor",		FcElementFloor },
4792c393a42Smrg    { "ceil",		FcElementCeil },
4802c393a42Smrg    { "round",		FcElementRound },
4812c393a42Smrg    { "trunc",		FcElementTrunc },
4822c393a42Smrg};
4832c393a42Smrg#define NUM_ELEMENT_MAPS (int) (sizeof fcElementMap / sizeof fcElementMap[0])
4842c393a42Smrg
485a32e9e42Smrgstatic const char *fcElementIgnoreName[16] = {
486a32e9e42Smrg    "its:",
487a32e9e42Smrg    NULL
488a32e9e42Smrg};
489a32e9e42Smrg
4902c393a42Smrgstatic FcElement
4912c393a42SmrgFcElementMap (const XML_Char *name)
4922c393a42Smrg{
4932c393a42Smrg
4942c393a42Smrg    int	    i;
4952c393a42Smrg    for (i = 0; i < NUM_ELEMENT_MAPS; i++)
4962c393a42Smrg	if (!strcmp ((char *) name, fcElementMap[i].name))
4972c393a42Smrg	    return fcElementMap[i].element;
498a32e9e42Smrg    for (i = 0; fcElementIgnoreName[i] != NULL; i++)
499a32e9e42Smrg	if (!strncmp ((char *) name, fcElementIgnoreName[i], strlen (fcElementIgnoreName[i])))
500a32e9e42Smrg	    return FcElementNone;
5012c393a42Smrg    return FcElementUnknown;
5022c393a42Smrg}
5032c393a42Smrg
504a4e54154Smrgstatic const char *
505a4e54154SmrgFcElementReverseMap (FcElement e)
506a4e54154Smrg{
507a4e54154Smrg    int i;
508a4e54154Smrg
509a4e54154Smrg    for (i = 0; i < NUM_ELEMENT_MAPS; i++)
510a4e54154Smrg	if (fcElementMap[i].element == e)
511a4e54154Smrg	    return fcElementMap[i].name;
512a4e54154Smrg
513a4e54154Smrg    return NULL;
514a4e54154Smrg}
515a4e54154Smrg
516a4e54154Smrg
5172c393a42Smrgtypedef struct _FcPStack {
5182c393a42Smrg    struct _FcPStack   *prev;
5192c393a42Smrg    FcElement		element;
5202c393a42Smrg    FcChar8		**attr;
5212c393a42Smrg    FcStrBuf		str;
522a6844aabSmrg    FcChar8            *attr_buf_static[16];
5232c393a42Smrg} FcPStack;
524ca08ab68Smrg
5252c393a42Smrgtypedef enum _FcVStackTag {
5262c393a42Smrg    FcVStackNone,
5272c393a42Smrg
5282c393a42Smrg    FcVStackString,
5292c393a42Smrg    FcVStackFamily,
5302c393a42Smrg    FcVStackConstant,
5312c393a42Smrg    FcVStackGlob,
532c9710b42Smrg    FcVStackName,
5332c393a42Smrg    FcVStackPattern,
534ca08ab68Smrg
5352c393a42Smrg    FcVStackPrefer,
5362c393a42Smrg    FcVStackAccept,
5372c393a42Smrg    FcVStackDefault,
538ca08ab68Smrg
5392c393a42Smrg    FcVStackInteger,
5402c393a42Smrg    FcVStackDouble,
5412c393a42Smrg    FcVStackMatrix,
542ca08ab68Smrg    FcVStackRange,
5432c393a42Smrg    FcVStackBool,
544ca08ab68Smrg    FcVStackCharSet,
545ca08ab68Smrg    FcVStackLangSet,
546ca08ab68Smrg
5472c393a42Smrg    FcVStackTest,
5482c393a42Smrg    FcVStackExpr,
5492c393a42Smrg    FcVStackEdit
5502c393a42Smrg} FcVStackTag;
5512c393a42Smrg
5522c393a42Smrgtypedef struct _FcVStack {
5532c393a42Smrg    struct _FcVStack	*prev;
5542c393a42Smrg    FcPStack		*pstack;	/* related parse element */
5552c393a42Smrg    FcVStackTag		tag;
5562c393a42Smrg    union {
5572c393a42Smrg	FcChar8		*string;
5582c393a42Smrg
5592c393a42Smrg	int		integer;
5602c393a42Smrg	double		_double;
561c9710b42Smrg	FcExprMatrix	*matrix;
562953daebaSmrg	FcRange		*range;
563a6844aabSmrg	FcBool		bool_;
564ca08ab68Smrg	FcCharSet	*charset;
565ca08ab68Smrg	FcLangSet	*langset;
566c9710b42Smrg	FcExprName	name;
5672c393a42Smrg
5682c393a42Smrg	FcTest		*test;
5692c393a42Smrg	FcQual		qual;
5702c393a42Smrg	FcOp		op;
5712c393a42Smrg	FcExpr		*expr;
5722c393a42Smrg	FcEdit		*edit;
5732c393a42Smrg
5742c393a42Smrg	FcPattern	*pattern;
5752c393a42Smrg    } u;
5762c393a42Smrg} FcVStack;
5772c393a42Smrg
5782c393a42Smrgtypedef struct _FcConfigParse {
5792c393a42Smrg    FcPStack	    *pstack;
5802c393a42Smrg    FcVStack	    *vstack;
5812c393a42Smrg    FcBool	    error;
5822c393a42Smrg    const FcChar8   *name;
5832c393a42Smrg    FcConfig	    *config;
584a32e9e42Smrg    FcRuleSet	    *ruleset;
5852c393a42Smrg    XML_Parser	    parser;
586c9710b42Smrg    unsigned int    pstack_static_used;
587a6844aabSmrg    FcPStack        pstack_static[8];
588c9710b42Smrg    unsigned int    vstack_static_used;
589a6844aabSmrg    FcVStack        vstack_static[64];
590a32e9e42Smrg    FcBool          scanOnly;
5912c393a42Smrg} FcConfigParse;
5922c393a42Smrg
5932c393a42Smrgtypedef enum _FcConfigSeverity {
5942c393a42Smrg    FcSevereInfo, FcSevereWarning, FcSevereError
5952c393a42Smrg} FcConfigSeverity;
5962c393a42Smrg
5972c393a42Smrgstatic void
5982c393a42SmrgFcConfigMessage (FcConfigParse *parse, FcConfigSeverity severe, const char *fmt, ...)
5992c393a42Smrg{
6002c393a42Smrg    const char	*s = "unknown";
6012c393a42Smrg    va_list	args;
6022c393a42Smrg
6032c393a42Smrg    va_start (args, fmt);
6042c393a42Smrg
6052c393a42Smrg    switch (severe) {
6062c393a42Smrg    case FcSevereInfo: s = "info"; break;
6072c393a42Smrg    case FcSevereWarning: s = "warning"; break;
6082c393a42Smrg    case FcSevereError: s = "error"; break;
6092c393a42Smrg    }
6102c393a42Smrg    if (parse)
6112c393a42Smrg    {
6122c393a42Smrg	if (parse->name)
6132c393a42Smrg	    fprintf (stderr, "Fontconfig %s: \"%s\", line %d: ", s,
6142c393a42Smrg		     parse->name, (int)XML_GetCurrentLineNumber (parse->parser));
6152c393a42Smrg	else
6162c393a42Smrg	    fprintf (stderr, "Fontconfig %s: line %d: ", s,
6172c393a42Smrg		     (int)XML_GetCurrentLineNumber (parse->parser));
6182c393a42Smrg	if (severe >= FcSevereError)
6192c393a42Smrg	    parse->error = FcTrue;
6202c393a42Smrg    }
6212c393a42Smrg    else
6222c393a42Smrg	fprintf (stderr, "Fontconfig %s: ", s);
6232c393a42Smrg    vfprintf (stderr, fmt, args);
6242c393a42Smrg    fprintf (stderr, "\n");
6252c393a42Smrg    va_end (args);
6262c393a42Smrg}
6272c393a42Smrg
6282c393a42Smrg
629c9710b42Smrgstatic FcExpr *
630c9710b42SmrgFcPopExpr (FcConfigParse *parse);
631c9710b42Smrg
632c9710b42Smrg
6332c393a42Smrgstatic const char *
6342c393a42SmrgFcTypeName (FcType type)
6352c393a42Smrg{
6362c393a42Smrg    switch (type) {
6372c393a42Smrg    case FcTypeVoid:
6382c393a42Smrg	return "void";
6392c393a42Smrg    case FcTypeInteger:
6402c393a42Smrg    case FcTypeDouble:
6412c393a42Smrg	return "number";
6422c393a42Smrg    case FcTypeString:
6432c393a42Smrg	return "string";
6442c393a42Smrg    case FcTypeBool:
6452c393a42Smrg	return "bool";
6462c393a42Smrg    case FcTypeMatrix:
6472c393a42Smrg	return "matrix";
6482c393a42Smrg    case FcTypeCharSet:
6492c393a42Smrg	return "charset";
6502c393a42Smrg    case FcTypeFTFace:
6512c393a42Smrg	return "FT_Face";
6522c393a42Smrg    case FcTypeLangSet:
6532c393a42Smrg	return "langset";
654953daebaSmrg    case FcTypeRange:
655953daebaSmrg	return "range";
656953daebaSmrg    case FcTypeUnknown:
6572c393a42Smrg    default:
6582c393a42Smrg	return "unknown";
6592c393a42Smrg    }
6602c393a42Smrg}
6612c393a42Smrg
6622c393a42Smrgstatic void
6632c393a42SmrgFcTypecheckValue (FcConfigParse *parse, FcType value, FcType type)
6642c393a42Smrg{
6652c393a42Smrg    if (value == FcTypeInteger)
6662c393a42Smrg	value = FcTypeDouble;
6672c393a42Smrg    if (type == FcTypeInteger)
6682c393a42Smrg	type = FcTypeDouble;
6692c393a42Smrg    if (value != type)
6702c393a42Smrg    {
6712c393a42Smrg	if ((value == FcTypeLangSet && type == FcTypeString) ||
672953daebaSmrg	    (value == FcTypeString && type == FcTypeLangSet) ||
673953daebaSmrg	    (value == FcTypeDouble && type == FcTypeRange))
6742c393a42Smrg	    return;
675b09479dcSmrg	if (type ==  FcTypeUnknown)
6762c393a42Smrg	    return;
677c9710b42Smrg	/* It's perfectly fine to use user-define elements in expressions,
678c9710b42Smrg	 * so don't warn in that case. */
679b09479dcSmrg	if (value == FcTypeUnknown)
680c9710b42Smrg	    return;
6812c393a42Smrg	FcConfigMessage (parse, FcSevereWarning, "saw %s, expected %s",
6822c393a42Smrg			 FcTypeName (value), FcTypeName (type));
6832c393a42Smrg    }
6842c393a42Smrg}
6852c393a42Smrg
6862c393a42Smrgstatic void
6872c393a42SmrgFcTypecheckExpr (FcConfigParse *parse, FcExpr *expr, FcType type)
6882c393a42Smrg{
6892c393a42Smrg    const FcObjectType	*o;
6902c393a42Smrg    const FcConstant	*c;
691ca08ab68Smrg
6922c393a42Smrg    /* If parsing the expression failed, some nodes may be NULL */
6932c393a42Smrg    if (!expr)
6942c393a42Smrg	return;
6952c393a42Smrg
696ca08ab68Smrg    switch (FC_OP_GET_OP (expr->op)) {
6972c393a42Smrg    case FcOpInteger:
6982c393a42Smrg    case FcOpDouble:
6992c393a42Smrg	FcTypecheckValue (parse, FcTypeDouble, type);
7002c393a42Smrg	break;
7012c393a42Smrg    case FcOpString:
7022c393a42Smrg	FcTypecheckValue (parse, FcTypeString, type);
7032c393a42Smrg	break;
7042c393a42Smrg    case FcOpMatrix:
7052c393a42Smrg	FcTypecheckValue (parse, FcTypeMatrix, type);
7062c393a42Smrg	break;
7072c393a42Smrg    case FcOpBool:
7082c393a42Smrg	FcTypecheckValue (parse, FcTypeBool, type);
7092c393a42Smrg	break;
7102c393a42Smrg    case FcOpCharSet:
7112c393a42Smrg	FcTypecheckValue (parse, FcTypeCharSet, type);
7122c393a42Smrg	break;
713ca08ab68Smrg    case FcOpLangSet:
714ca08ab68Smrg	FcTypecheckValue (parse, FcTypeLangSet, type);
715ca08ab68Smrg	break;
716953daebaSmrg    case FcOpRange:
717953daebaSmrg	FcTypecheckValue (parse, FcTypeRange, type);
718953daebaSmrg	break;
7192c393a42Smrg    case FcOpNil:
7202c393a42Smrg	break;
7212c393a42Smrg    case FcOpField:
722c9710b42Smrg	o = FcNameGetObjectType (FcObjectName (expr->u.name.object));
7232c393a42Smrg	if (o)
7242c393a42Smrg	    FcTypecheckValue (parse, o->type, type);
7252c393a42Smrg	break;
7262c393a42Smrg    case FcOpConst:
7272c393a42Smrg	c = FcNameGetConstant (expr->u.constant);
7282c393a42Smrg	if (c)
7292c393a42Smrg	{
7302c393a42Smrg	    o = FcNameGetObjectType (c->object);
7312c393a42Smrg	    if (o)
7322c393a42Smrg		FcTypecheckValue (parse, o->type, type);
7332c393a42Smrg	}
734ca08ab68Smrg        else
735ca08ab68Smrg            FcConfigMessage (parse, FcSevereWarning,
7362c393a42Smrg                             "invalid constant used : %s",
7372c393a42Smrg                             expr->u.constant);
7382c393a42Smrg	break;
7392c393a42Smrg    case FcOpQuest:
7402c393a42Smrg	FcTypecheckExpr (parse, expr->u.tree.left, FcTypeBool);
7412c393a42Smrg	FcTypecheckExpr (parse, expr->u.tree.right->u.tree.left, type);
7422c393a42Smrg	FcTypecheckExpr (parse, expr->u.tree.right->u.tree.right, type);
7432c393a42Smrg	break;
7442c393a42Smrg    case FcOpAssign:
7452c393a42Smrg    case FcOpAssignReplace:
7462c393a42Smrg	break;
7472c393a42Smrg    case FcOpEqual:
7482c393a42Smrg    case FcOpNotEqual:
7492c393a42Smrg    case FcOpLess:
7502c393a42Smrg    case FcOpLessEqual:
7512c393a42Smrg    case FcOpMore:
7522c393a42Smrg    case FcOpMoreEqual:
7532c393a42Smrg    case FcOpContains:
7542c393a42Smrg    case FcOpNotContains:
7552c393a42Smrg    case FcOpListing:
7562c393a42Smrg	FcTypecheckValue (parse, FcTypeBool, type);
7572c393a42Smrg	break;
7582c393a42Smrg    case FcOpComma:
7592c393a42Smrg    case FcOpOr:
7602c393a42Smrg    case FcOpAnd:
7612c393a42Smrg    case FcOpPlus:
7622c393a42Smrg    case FcOpMinus:
7632c393a42Smrg    case FcOpTimes:
7642c393a42Smrg    case FcOpDivide:
7652c393a42Smrg	FcTypecheckExpr (parse, expr->u.tree.left, type);
7662c393a42Smrg	FcTypecheckExpr (parse, expr->u.tree.right, type);
7672c393a42Smrg	break;
7682c393a42Smrg    case FcOpNot:
7692c393a42Smrg	FcTypecheckValue (parse, FcTypeBool, type);
7702c393a42Smrg	FcTypecheckExpr (parse, expr->u.tree.left, FcTypeBool);
7712c393a42Smrg	break;
7722c393a42Smrg    case FcOpFloor:
7732c393a42Smrg    case FcOpCeil:
7742c393a42Smrg    case FcOpRound:
7752c393a42Smrg    case FcOpTrunc:
7762c393a42Smrg	FcTypecheckValue (parse, FcTypeDouble, type);
7772c393a42Smrg	FcTypecheckExpr (parse, expr->u.tree.left, FcTypeDouble);
7782c393a42Smrg	break;
7792c393a42Smrg    default:
7802c393a42Smrg	break;
7812c393a42Smrg    }
7822c393a42Smrg}
7832c393a42Smrg
7842c393a42Smrgstatic FcTest *
7852c393a42SmrgFcTestCreate (FcConfigParse *parse,
786ca08ab68Smrg	      FcMatchKind   kind,
7872c393a42Smrg	      FcQual	    qual,
7882c393a42Smrg	      const FcChar8 *field,
7896fc018e4Smrg	      unsigned int  compare,
7902c393a42Smrg	      FcExpr	    *expr)
7912c393a42Smrg{
7922c393a42Smrg    FcTest	*test = (FcTest *) malloc (sizeof (FcTest));
7932c393a42Smrg
7942c393a42Smrg    if (test)
7952c393a42Smrg    {
7962c393a42Smrg	const FcObjectType	*o;
7972c393a42Smrg
7982c393a42Smrg	test->kind = kind;
7992c393a42Smrg	test->qual = qual;
8002c393a42Smrg	test->object = FcObjectFromName ((const char *) field);
8012c393a42Smrg	test->op = compare;
8022c393a42Smrg	test->expr = expr;
8032c393a42Smrg	o = FcNameGetObjectType (FcObjectName (test->object));
8042c393a42Smrg	if (o)
8052c393a42Smrg	    FcTypecheckExpr (parse, expr, o->type);
8062c393a42Smrg    }
8072c393a42Smrg    return test;
8082c393a42Smrg}
8092c393a42Smrg
8102c393a42Smrgstatic FcEdit *
8112c393a42SmrgFcEditCreate (FcConfigParse	*parse,
8122c393a42Smrg	      FcObject		object,
8132c393a42Smrg	      FcOp		op,
8142c393a42Smrg	      FcExpr		*expr,
8152c393a42Smrg	      FcValueBinding	binding)
8162c393a42Smrg{
8172c393a42Smrg    FcEdit *e = (FcEdit *) malloc (sizeof (FcEdit));
8182c393a42Smrg
8192c393a42Smrg    if (e)
8202c393a42Smrg    {
8212c393a42Smrg	const FcObjectType	*o;
8222c393a42Smrg
8232c393a42Smrg	e->object = object;
8242c393a42Smrg	e->op = op;
8252c393a42Smrg	e->expr = expr;
8262c393a42Smrg	e->binding = binding;
8272c393a42Smrg	o = FcNameGetObjectType (FcObjectName (e->object));
8282c393a42Smrg	if (o)
8292c393a42Smrg	    FcTypecheckExpr (parse, expr, o->type);
8302c393a42Smrg    }
8312c393a42Smrg    return e;
8322c393a42Smrg}
8332c393a42Smrg
8346fc018e4Smrgstatic FcRule *
8356fc018e4SmrgFcRuleCreate (FcRuleType type,
8366fc018e4Smrg	      void       *p)
8376fc018e4Smrg{
8386fc018e4Smrg    FcRule *r = (FcRule *) malloc (sizeof (FcRule));
8396fc018e4Smrg
8406fc018e4Smrg    if (!r)
8416fc018e4Smrg	return NULL;
8426fc018e4Smrg
8436fc018e4Smrg    r->next = NULL;
8446fc018e4Smrg    r->type = type;
8456fc018e4Smrg    switch (type)
8466fc018e4Smrg    {
8476fc018e4Smrg    case FcRuleTest:
8486fc018e4Smrg	r->u.test = (FcTest *) p;
8496fc018e4Smrg	break;
8506fc018e4Smrg    case FcRuleEdit:
8516fc018e4Smrg	r->u.edit = (FcEdit *) p;
8526fc018e4Smrg	break;
853953daebaSmrg    case FcRuleUnknown:
8546fc018e4Smrg    default:
8556fc018e4Smrg	free (r);
8566fc018e4Smrg	r = NULL;
8576fc018e4Smrg	break;
8586fc018e4Smrg    }
8596fc018e4Smrg
8606fc018e4Smrg    return r;
8616fc018e4Smrg}
8626fc018e4Smrg
8632c393a42Smrgstatic FcVStack *
864a6844aabSmrgFcVStackCreateAndPush (FcConfigParse *parse)
8652c393a42Smrg{
8662c393a42Smrg    FcVStack    *new;
8672c393a42Smrg
868a6844aabSmrg    if (parse->vstack_static_used < sizeof (parse->vstack_static) / sizeof (parse->vstack_static[0]))
869a6844aabSmrg	new = &parse->vstack_static[parse->vstack_static_used++];
870a6844aabSmrg    else
871a6844aabSmrg    {
872a6844aabSmrg	new = malloc (sizeof (FcVStack));
873a6844aabSmrg	if (!new)
874a6844aabSmrg	    return 0;
875a6844aabSmrg    }
8762c393a42Smrg    new->tag = FcVStackNone;
8772c393a42Smrg    new->prev = 0;
8782c393a42Smrg
879a6844aabSmrg    new->prev = parse->vstack;
880a6844aabSmrg    new->pstack = parse->pstack ? parse->pstack->prev : 0;
881a6844aabSmrg    parse->vstack = new;
8822c393a42Smrg
883a6844aabSmrg    return new;
8842c393a42Smrg}
8852c393a42Smrg
8862c393a42Smrgstatic FcBool
8872c393a42SmrgFcVStackPushString (FcConfigParse *parse, FcVStackTag tag, FcChar8 *string)
8882c393a42Smrg{
889a6844aabSmrg    FcVStack    *vstack = FcVStackCreateAndPush (parse);
8902c393a42Smrg    if (!vstack)
8912c393a42Smrg	return FcFalse;
8922c393a42Smrg    vstack->u.string = string;
8932c393a42Smrg    vstack->tag = tag;
8942c393a42Smrg    return FcTrue;
8952c393a42Smrg}
8962c393a42Smrg
8972c393a42Smrgstatic FcBool
8982c393a42SmrgFcVStackPushInteger (FcConfigParse *parse, int integer)
8992c393a42Smrg{
900a6844aabSmrg    FcVStack    *vstack = FcVStackCreateAndPush (parse);
9012c393a42Smrg    if (!vstack)
9022c393a42Smrg	return FcFalse;
9032c393a42Smrg    vstack->u.integer = integer;
9042c393a42Smrg    vstack->tag = FcVStackInteger;
9052c393a42Smrg    return FcTrue;
9062c393a42Smrg}
9072c393a42Smrg
9082c393a42Smrgstatic FcBool
9092c393a42SmrgFcVStackPushDouble (FcConfigParse *parse, double _double)
9102c393a42Smrg{
911a6844aabSmrg    FcVStack    *vstack = FcVStackCreateAndPush (parse);
9122c393a42Smrg    if (!vstack)
9132c393a42Smrg	return FcFalse;
9142c393a42Smrg    vstack->u._double = _double;
9152c393a42Smrg    vstack->tag = FcVStackDouble;
9162c393a42Smrg    return FcTrue;
9172c393a42Smrg}
9182c393a42Smrg
9192c393a42Smrgstatic FcBool
920c9710b42SmrgFcVStackPushMatrix (FcConfigParse *parse, FcExprMatrix *matrix)
9212c393a42Smrg{
922a6844aabSmrg    FcVStack    *vstack;
923a6844aabSmrg    vstack = FcVStackCreateAndPush (parse);
924a6844aabSmrg    if (!vstack)
925a6844aabSmrg	return FcFalse;
926c9710b42Smrg    vstack->u.matrix = FcExprMatrixCopyShallow (matrix);
9272c393a42Smrg    vstack->tag = FcVStackMatrix;
9282c393a42Smrg    return FcTrue;
9292c393a42Smrg}
9302c393a42Smrg
931ca08ab68Smrgstatic FcBool
932ca08ab68SmrgFcVStackPushRange (FcConfigParse *parse, FcRange *range)
933ca08ab68Smrg{
934953daebaSmrg    FcVStack 	*vstack = FcVStackCreateAndPush (parse);
935ca08ab68Smrg    if (!vstack)
936ca08ab68Smrg	return FcFalse;
937953daebaSmrg    vstack->u.range = range;
938ca08ab68Smrg    vstack->tag = FcVStackRange;
939ca08ab68Smrg    return FcTrue;
940ca08ab68Smrg}
941ca08ab68Smrg
9422c393a42Smrgstatic FcBool
943a6844aabSmrgFcVStackPushBool (FcConfigParse *parse, FcBool bool_)
9442c393a42Smrg{
945a6844aabSmrg    FcVStack    *vstack = FcVStackCreateAndPush (parse);
9462c393a42Smrg    if (!vstack)
9472c393a42Smrg	return FcFalse;
948a6844aabSmrg    vstack->u.bool_ = bool_;
9492c393a42Smrg    vstack->tag = FcVStackBool;
9502c393a42Smrg    return FcTrue;
9512c393a42Smrg}
9522c393a42Smrg
953ca08ab68Smrgstatic FcBool
954ca08ab68SmrgFcVStackPushCharSet (FcConfigParse *parse, FcCharSet *charset)
955ca08ab68Smrg{
956ca08ab68Smrg    FcVStack	*vstack;
957ca08ab68Smrg    if (!charset)
958ca08ab68Smrg	return FcFalse;
959ca08ab68Smrg    vstack = FcVStackCreateAndPush (parse);
960ca08ab68Smrg    if (!vstack)
961ca08ab68Smrg	return FcFalse;
962ca08ab68Smrg    vstack->u.charset = charset;
963ca08ab68Smrg    vstack->tag = FcVStackCharSet;
964ca08ab68Smrg    return FcTrue;
965ca08ab68Smrg}
966ca08ab68Smrg
967ca08ab68Smrgstatic FcBool
968ca08ab68SmrgFcVStackPushLangSet (FcConfigParse *parse, FcLangSet *langset)
969ca08ab68Smrg{
970ca08ab68Smrg    FcVStack	*vstack;
971ca08ab68Smrg    if (!langset)
972ca08ab68Smrg	return FcFalse;
973ca08ab68Smrg    vstack = FcVStackCreateAndPush (parse);
974ca08ab68Smrg    if (!vstack)
975ca08ab68Smrg	return FcFalse;
976ca08ab68Smrg    vstack->u.langset = langset;
977ca08ab68Smrg    vstack->tag = FcVStackLangSet;
978ca08ab68Smrg    return FcTrue;
979ca08ab68Smrg}
980ca08ab68Smrg
981c9710b42Smrgstatic FcBool
982c9710b42SmrgFcVStackPushName (FcConfigParse *parse, FcMatchKind kind, FcObject object)
983c9710b42Smrg{
984c9710b42Smrg    FcVStack    *vstack = FcVStackCreateAndPush (parse);
985c9710b42Smrg    if (!vstack)
986c9710b42Smrg	return FcFalse;
987c9710b42Smrg    vstack->u.name.object = object;
988c9710b42Smrg    vstack->u.name.kind = kind;
989c9710b42Smrg    vstack->tag = FcVStackName;
990c9710b42Smrg    return FcTrue;
991c9710b42Smrg}
992c9710b42Smrg
9932c393a42Smrgstatic FcBool
9942c393a42SmrgFcVStackPushTest (FcConfigParse *parse, FcTest *test)
9952c393a42Smrg{
996a6844aabSmrg    FcVStack    *vstack = FcVStackCreateAndPush (parse);
9972c393a42Smrg    if (!vstack)
9982c393a42Smrg	return FcFalse;
9992c393a42Smrg    vstack->u.test = test;
10002c393a42Smrg    vstack->tag = FcVStackTest;
10012c393a42Smrg    return FcTrue;
10022c393a42Smrg}
10032c393a42Smrg
10042c393a42Smrgstatic FcBool
10052c393a42SmrgFcVStackPushExpr (FcConfigParse *parse, FcVStackTag tag, FcExpr *expr)
10062c393a42Smrg{
1007a6844aabSmrg    FcVStack    *vstack = FcVStackCreateAndPush (parse);
10082c393a42Smrg    if (!vstack)
10092c393a42Smrg	return FcFalse;
10102c393a42Smrg    vstack->u.expr = expr;
10112c393a42Smrg    vstack->tag = tag;
10122c393a42Smrg    return FcTrue;
10132c393a42Smrg}
10142c393a42Smrg
10152c393a42Smrgstatic FcBool
10162c393a42SmrgFcVStackPushEdit (FcConfigParse *parse, FcEdit *edit)
10172c393a42Smrg{
1018a6844aabSmrg    FcVStack    *vstack = FcVStackCreateAndPush (parse);
10192c393a42Smrg    if (!vstack)
10202c393a42Smrg	return FcFalse;
10212c393a42Smrg    vstack->u.edit = edit;
10222c393a42Smrg    vstack->tag = FcVStackEdit;
10232c393a42Smrg    return FcTrue;
10242c393a42Smrg}
10252c393a42Smrg
10262c393a42Smrgstatic FcBool
10272c393a42SmrgFcVStackPushPattern (FcConfigParse *parse, FcPattern *pattern)
10282c393a42Smrg{
1029a6844aabSmrg    FcVStack    *vstack = FcVStackCreateAndPush (parse);
10302c393a42Smrg    if (!vstack)
10312c393a42Smrg	return FcFalse;
10322c393a42Smrg    vstack->u.pattern = pattern;
10332c393a42Smrg    vstack->tag = FcVStackPattern;
10342c393a42Smrg    return FcTrue;
10352c393a42Smrg}
10362c393a42Smrg
10372c393a42Smrgstatic FcVStack *
10382c393a42SmrgFcVStackFetch (FcConfigParse *parse, int off)
10392c393a42Smrg{
10402c393a42Smrg    FcVStack    *vstack;
10412c393a42Smrg
10422c393a42Smrg    for (vstack = parse->vstack; vstack && off-- > 0; vstack = vstack->prev);
10432c393a42Smrg    return vstack;
10442c393a42Smrg}
10452c393a42Smrg
1046a6844aabSmrgstatic FcVStack *
1047a6844aabSmrgFcVStackPeek (FcConfigParse *parse)
10482c393a42Smrg{
1049a6844aabSmrg    FcVStack	*vstack = parse->vstack;
1050a6844aabSmrg
1051a6844aabSmrg    return vstack && vstack->pstack == parse->pstack ? vstack : 0;
10522c393a42Smrg}
10532c393a42Smrg
1054a6844aabSmrgstatic void
1055a6844aabSmrgFcVStackPopAndDestroy (FcConfigParse *parse)
10562c393a42Smrg{
10572c393a42Smrg    FcVStack	*vstack = parse->vstack;
1058ca08ab68Smrg
10592c393a42Smrg    if (!vstack || vstack->pstack != parse->pstack)
1060a6844aabSmrg	return;
1061a6844aabSmrg
10622c393a42Smrg    parse->vstack = vstack->prev;
1063a6844aabSmrg
1064a6844aabSmrg    switch (vstack->tag) {
1065a6844aabSmrg    case FcVStackNone:
1066a6844aabSmrg	break;
1067c9710b42Smrg    case FcVStackName:
1068c9710b42Smrg	break;
1069a6844aabSmrg    case FcVStackFamily:
1070a6844aabSmrg	break;
1071a6844aabSmrg    case FcVStackString:
1072a6844aabSmrg    case FcVStackConstant:
1073a6844aabSmrg    case FcVStackGlob:
1074a6844aabSmrg	FcStrFree (vstack->u.string);
1075a6844aabSmrg	break;
1076a6844aabSmrg    case FcVStackPattern:
1077a6844aabSmrg	FcPatternDestroy (vstack->u.pattern);
1078a6844aabSmrg	break;
1079a6844aabSmrg    case FcVStackInteger:
1080a6844aabSmrg    case FcVStackDouble:
1081a6844aabSmrg	break;
1082a6844aabSmrg    case FcVStackMatrix:
1083c9710b42Smrg	FcExprMatrixFreeShallow (vstack->u.matrix);
1084a6844aabSmrg	break;
1085a6844aabSmrg    case FcVStackBool:
1086a6844aabSmrg	break;
1087953daebaSmrg    case FcVStackRange:
1088953daebaSmrg	FcRangeDestroy (vstack->u.range);
1089953daebaSmrg	break;
1090ca08ab68Smrg    case FcVStackCharSet:
1091ca08ab68Smrg	FcCharSetDestroy (vstack->u.charset);
1092ca08ab68Smrg	break;
1093ca08ab68Smrg    case FcVStackLangSet:
1094ca08ab68Smrg	FcLangSetDestroy (vstack->u.langset);
1095ca08ab68Smrg	break;
1096a6844aabSmrg    case FcVStackTest:
1097a6844aabSmrg	FcTestDestroy (vstack->u.test);
1098a6844aabSmrg	break;
1099a6844aabSmrg    case FcVStackExpr:
1100a6844aabSmrg    case FcVStackPrefer:
1101a6844aabSmrg    case FcVStackAccept:
1102a6844aabSmrg    case FcVStackDefault:
1103a6844aabSmrg	FcExprDestroy (vstack->u.expr);
1104a6844aabSmrg	break;
1105a6844aabSmrg    case FcVStackEdit:
1106a6844aabSmrg	FcEditDestroy (vstack->u.edit);
1107a6844aabSmrg	break;
1108a6844aabSmrg    }
1109a6844aabSmrg
1110a6844aabSmrg    if (vstack == &parse->vstack_static[parse->vstack_static_used - 1])
1111a6844aabSmrg	parse->vstack_static_used--;
1112a6844aabSmrg    else
1113a6844aabSmrg	free (vstack);
1114a6844aabSmrg}
1115a6844aabSmrg
1116a6844aabSmrgstatic void
1117a6844aabSmrgFcVStackClear (FcConfigParse *parse)
1118a6844aabSmrg{
1119a6844aabSmrg    while (FcVStackPeek (parse))
1120a6844aabSmrg	FcVStackPopAndDestroy (parse);
11212c393a42Smrg}
11222c393a42Smrg
11232c393a42Smrgstatic int
11242c393a42SmrgFcVStackElements (FcConfigParse *parse)
11252c393a42Smrg{
11262c393a42Smrg    int		h = 0;
11272c393a42Smrg    FcVStack	*vstack = parse->vstack;
11282c393a42Smrg    while (vstack && vstack->pstack == parse->pstack)
11292c393a42Smrg    {
11302c393a42Smrg	h++;
11312c393a42Smrg	vstack = vstack->prev;
11322c393a42Smrg    }
11332c393a42Smrg    return h;
11342c393a42Smrg}
11352c393a42Smrg
11362c393a42Smrgstatic FcChar8 **
1137a6844aabSmrgFcConfigSaveAttr (const XML_Char **attr, FcChar8 **buf, int size_bytes)
11382c393a42Smrg{
11392c393a42Smrg    int		slen;
11402c393a42Smrg    int		i;
11412c393a42Smrg    FcChar8	**new;
11422c393a42Smrg    FcChar8	*s;
11432c393a42Smrg
11442c393a42Smrg    if (!attr)
11452c393a42Smrg	return 0;
11462c393a42Smrg    slen = 0;
11472c393a42Smrg    for (i = 0; attr[i]; i++)
11482c393a42Smrg	slen += strlen ((char *) attr[i]) + 1;
1149a6844aabSmrg    if (i == 0)
11502c393a42Smrg	return 0;
1151a6844aabSmrg    slen += (i + 1) * sizeof (FcChar8 *);
1152a6844aabSmrg    if (slen <= size_bytes)
1153a6844aabSmrg	new = buf;
1154a6844aabSmrg    else
1155a6844aabSmrg    {
1156a6844aabSmrg	new = malloc (slen);
1157a6844aabSmrg	if (!new)
1158a6844aabSmrg	{
1159a6844aabSmrg	    FcConfigMessage (0, FcSevereError, "out of memory");
1160a6844aabSmrg	    return 0;
1161a6844aabSmrg	}
1162a6844aabSmrg    }
11632c393a42Smrg    s = (FcChar8 *) (new + (i + 1));
11642c393a42Smrg    for (i = 0; attr[i]; i++)
11652c393a42Smrg    {
11662c393a42Smrg	new[i] = s;
11672c393a42Smrg	strcpy ((char *) s, (char *) attr[i]);
11682c393a42Smrg	s += strlen ((char *) s) + 1;
11692c393a42Smrg    }
11702c393a42Smrg    new[i] = 0;
11712c393a42Smrg    return new;
11722c393a42Smrg}
11732c393a42Smrg
11742c393a42Smrgstatic FcBool
11752c393a42SmrgFcPStackPush (FcConfigParse *parse, FcElement element, const XML_Char **attr)
11762c393a42Smrg{
1177a6844aabSmrg    FcPStack   *new;
11782c393a42Smrg
1179a6844aabSmrg    if (parse->pstack_static_used < sizeof (parse->pstack_static) / sizeof (parse->pstack_static[0]))
1180a6844aabSmrg	new = &parse->pstack_static[parse->pstack_static_used++];
1181a6844aabSmrg    else
11822c393a42Smrg    {
1183a6844aabSmrg	new = malloc (sizeof (FcPStack));
1184a6844aabSmrg	if (!new)
11852c393a42Smrg	    return FcFalse;
11862c393a42Smrg    }
1187a6844aabSmrg
1188a6844aabSmrg    new->prev = parse->pstack;
1189a6844aabSmrg    new->element = element;
1190a6844aabSmrg    new->attr = FcConfigSaveAttr (attr, new->attr_buf_static, sizeof (new->attr_buf_static));
11912c393a42Smrg    FcStrBufInit (&new->str, 0, 0);
11922c393a42Smrg    parse->pstack = new;
11932c393a42Smrg    return FcTrue;
11942c393a42Smrg}
11952c393a42Smrg
11962c393a42Smrgstatic FcBool
11972c393a42SmrgFcPStackPop (FcConfigParse *parse)
11982c393a42Smrg{
11992c393a42Smrg    FcPStack   *old;
1200ca08ab68Smrg
1201ca08ab68Smrg    if (!parse->pstack)
12022c393a42Smrg    {
12032c393a42Smrg	FcConfigMessage (parse, FcSevereError, "mismatching element");
12042c393a42Smrg	return FcFalse;
12052c393a42Smrg    }
1206c9710b42Smrg
1207a32e9e42Smrg    /* Don't check the attributes for FcElementNone */
1208a32e9e42Smrg    if (parse->pstack->element != FcElementNone &&
1209a32e9e42Smrg	parse->pstack->attr)
1210c9710b42Smrg    {
1211c9710b42Smrg	/* Warn about unused attrs. */
1212c9710b42Smrg	FcChar8 **attrs = parse->pstack->attr;
1213c9710b42Smrg	while (*attrs)
1214c9710b42Smrg	{
1215c9710b42Smrg	    if (attrs[0][0])
1216c9710b42Smrg	    {
1217a4e54154Smrg		FcConfigMessage (parse, FcSevereWarning, "invalid attribute '%s'", attrs[0]);
1218c9710b42Smrg	    }
1219c9710b42Smrg	    attrs += 2;
1220c9710b42Smrg	}
1221c9710b42Smrg    }
1222c9710b42Smrg
12232c393a42Smrg    FcVStackClear (parse);
12242c393a42Smrg    old = parse->pstack;
12252c393a42Smrg    parse->pstack = old->prev;
12262c393a42Smrg    FcStrBufDestroy (&old->str);
1227c9710b42Smrg
1228a6844aabSmrg    if (old->attr && old->attr != old->attr_buf_static)
12292c393a42Smrg	free (old->attr);
1230a6844aabSmrg
1231a6844aabSmrg    if (old == &parse->pstack_static[parse->pstack_static_used - 1])
1232a6844aabSmrg	parse->pstack_static_used--;
1233a6844aabSmrg    else
1234a6844aabSmrg	free (old);
12352c393a42Smrg    return FcTrue;
12362c393a42Smrg}
12372c393a42Smrg
12382c393a42Smrgstatic FcBool
1239a32e9e42SmrgFcConfigParseInit (FcConfigParse	*parse,
1240a32e9e42Smrg		   const FcChar8	*name,
1241a32e9e42Smrg		   FcConfig		*config,
1242a32e9e42Smrg		   XML_Parser		parser,
1243a32e9e42Smrg		   FcBool		enabled)
12442c393a42Smrg{
12452c393a42Smrg    parse->pstack = 0;
1246a6844aabSmrg    parse->pstack_static_used = 0;
12472c393a42Smrg    parse->vstack = 0;
1248a6844aabSmrg    parse->vstack_static_used = 0;
12492c393a42Smrg    parse->error = FcFalse;
12502c393a42Smrg    parse->name = name;
12512c393a42Smrg    parse->config = config;
1252a32e9e42Smrg    parse->ruleset = FcRuleSetCreate (name);
12532c393a42Smrg    parse->parser = parser;
1254a32e9e42Smrg    parse->scanOnly = !enabled;
1255a32e9e42Smrg    FcRuleSetEnable (parse->ruleset, enabled);
1256a32e9e42Smrg
12572c393a42Smrg    return FcTrue;
12582c393a42Smrg}
12592c393a42Smrg
12602c393a42Smrgstatic void
12612c393a42SmrgFcConfigCleanup (FcConfigParse	*parse)
12622c393a42Smrg{
12632c393a42Smrg    while (parse->pstack)
12642c393a42Smrg	FcPStackPop (parse);
1265a32e9e42Smrg    FcRuleSetDestroy (parse->ruleset);
1266a32e9e42Smrg    parse->ruleset = NULL;
12672c393a42Smrg}
12682c393a42Smrg
12692c393a42Smrgstatic const FcChar8 *
12702c393a42SmrgFcConfigGetAttribute (FcConfigParse *parse, const char *attr)
12712c393a42Smrg{
12722c393a42Smrg    FcChar8 **attrs;
12732c393a42Smrg    if (!parse->pstack)
12742c393a42Smrg	return 0;
12752c393a42Smrg
12762c393a42Smrg    attrs = parse->pstack->attr;
12772c393a42Smrg    if (!attrs)
12782c393a42Smrg        return 0;
12792c393a42Smrg
12802c393a42Smrg    while (*attrs)
12812c393a42Smrg    {
12822c393a42Smrg	if (!strcmp ((char *) *attrs, attr))
1283c9710b42Smrg	{
1284c9710b42Smrg	    attrs[0][0] = '\0'; /* Mark as used. */
12852c393a42Smrg	    return attrs[1];
1286c9710b42Smrg	}
12872c393a42Smrg	attrs += 2;
12882c393a42Smrg    }
12892c393a42Smrg    return 0;
12902c393a42Smrg}
12912c393a42Smrg
1292a4e54154Smrgstatic FcStrSet *
1293a4e54154Smrg_get_real_paths_from_prefix(FcConfigParse *parse, const FcChar8 *path, const FcChar8 *prefix)
1294a4e54154Smrg{
1295a4e54154Smrg#ifdef _WIN32
1296a4e54154Smrg    FcChar8 buffer[1000] = { 0 };
1297a4e54154Smrg#endif
1298a4e54154Smrg    FcChar8 *parent = NULL, *retval = NULL;
1299a4e54154Smrg    FcStrSet *e = NULL;
1300a4e54154Smrg
1301a4e54154Smrg    if (prefix)
1302a4e54154Smrg    {
1303a4e54154Smrg	if (FcStrCmp (prefix, (const FcChar8 *) "xdg") == 0)
1304a4e54154Smrg	{
1305a4e54154Smrg	    parent = FcConfigXdgDataHome ();
1306a4e54154Smrg	    if (!parent)
1307a4e54154Smrg	    {
1308a4e54154Smrg		/* Home directory might be disabled */
1309a4e54154Smrg		return NULL;
1310a4e54154Smrg	    }
1311a4e54154Smrg	    e = FcConfigXdgDataDirs ();
1312a4e54154Smrg	    if (!e)
1313a4e54154Smrg	    {
1314a4e54154Smrg		FcStrFree (parent);
1315a4e54154Smrg		return NULL;
1316a4e54154Smrg	    }
1317a4e54154Smrg	}
1318a4e54154Smrg	else if (FcStrCmp (prefix, (const FcChar8 *) "default") == 0 ||
1319a4e54154Smrg		 FcStrCmp (prefix, (const FcChar8 *) "cwd") == 0)
1320a4e54154Smrg	{
1321a4e54154Smrg	    /* Nothing to do */
1322a4e54154Smrg	}
1323a4e54154Smrg	else if (FcStrCmp (prefix, (const FcChar8 *) "relative") == 0)
1324a4e54154Smrg	{
1325a4e54154Smrg	    FcChar8 *p = FcStrRealPath (parse->name);
1326a4e54154Smrg
1327a4e54154Smrg	    if (!p)
1328a4e54154Smrg		return NULL;
1329a4e54154Smrg	    parent = FcStrDirname (p);
1330a4e54154Smrg	    if (!parent)
1331a4e54154Smrg	    {
1332a4e54154Smrg		free (p);
1333a4e54154Smrg		return NULL;
1334a4e54154Smrg	    }
1335a4e54154Smrg	}
1336a4e54154Smrg    }
1337a4e54154Smrg#ifndef _WIN32
1338a4e54154Smrg    /* For Win32, check this later for dealing with special cases */
1339a4e54154Smrg    else
1340a4e54154Smrg    {
1341a4e54154Smrg	if (!FcStrIsAbsoluteFilename (path) && path[0] != '~')
1342a4e54154Smrg	    FcConfigMessage (parse, FcSevereWarning, "Use of ambiguous path in <%s> element. please add prefix=\"cwd\" if current behavior is desired.", FcElementReverseMap (parse->pstack->element));
1343a4e54154Smrg    }
1344a4e54154Smrg#else
1345a4e54154Smrg    if (strcmp ((const char *) path, "CUSTOMFONTDIR") == 0)
1346a4e54154Smrg    {
1347a4e54154Smrg	FcChar8 *p;
1348a4e54154Smrg	path = buffer;
1349a4e54154Smrg	if (!GetModuleFileName (NULL, (LPCH) buffer, sizeof (buffer) - 20))
1350a4e54154Smrg	{
1351a4e54154Smrg	    FcConfigMessage (parse, FcSevereError, "GetModuleFileName failed");
1352a4e54154Smrg	    return NULL;
1353a4e54154Smrg	}
1354a4e54154Smrg	/*
1355a4e54154Smrg	 * Must use the multi-byte aware function to search
1356a4e54154Smrg	 * for backslash because East Asian double-byte code
1357a4e54154Smrg	 * pages have characters with backslash as the second
1358a4e54154Smrg	 * byte.
1359a4e54154Smrg	 */
1360a4e54154Smrg	p = _mbsrchr (path, '\\');
1361a4e54154Smrg	if (p) *p = '\0';
1362a4e54154Smrg	strcat ((char *) path, "\\fonts");
1363a4e54154Smrg    }
1364a4e54154Smrg    else if (strcmp ((const char *) path, "APPSHAREFONTDIR") == 0)
1365a4e54154Smrg    {
1366a4e54154Smrg	FcChar8 *p;
1367a4e54154Smrg	path = buffer;
1368a4e54154Smrg	if (!GetModuleFileName (NULL, (LPCH) buffer, sizeof (buffer) - 20))
1369a4e54154Smrg	{
1370a4e54154Smrg	    FcConfigMessage (parse, FcSevereError, "GetModuleFileName failed");
1371a4e54154Smrg	    return NULL;
1372a4e54154Smrg	}
1373a4e54154Smrg	p = _mbsrchr (path, '\\');
1374a4e54154Smrg	if (p) *p = '\0';
1375a4e54154Smrg	strcat ((char *) path, "\\..\\share\\fonts");
1376a4e54154Smrg    }
1377a4e54154Smrg    else if (strcmp ((const char *) path, "WINDOWSUSERFONTDIR") == 0)
1378a4e54154Smrg    {
1379a4e54154Smrg        path = buffer;
1380a4e54154Smrg        if (!(pSHGetFolderPathA && SUCCEEDED(pSHGetFolderPathA(NULL, /* CSIDL_LOCAL_APPDATA */ 28, NULL, 0, (char *) buffer))))
1381a4e54154Smrg        {
1382a4e54154Smrg            FcConfigMessage(parse, FcSevereError, "SHGetFolderPathA failed");
1383a4e54154Smrg            return NULL;
1384a4e54154Smrg        }
1385a4e54154Smrg        strcat((char *) path, "\\Microsoft\\Windows\\Fonts");
1386a4e54154Smrg    }
1387a4e54154Smrg    else if (strcmp ((const char *) path, "WINDOWSFONTDIR") == 0)
1388a4e54154Smrg    {
1389a4e54154Smrg	int rc;
1390a4e54154Smrg	path = buffer;
1391a4e54154Smrg	_ensureWin32GettersReady();
1392a4e54154Smrg	rc = pGetSystemWindowsDirectory ((LPSTR) buffer, sizeof (buffer) - 20);
1393a4e54154Smrg	if (rc == 0 || rc > sizeof (buffer) - 20)
1394a4e54154Smrg	{
1395a4e54154Smrg	    FcConfigMessage (parse, FcSevereError, "GetSystemWindowsDirectory failed");
1396a4e54154Smrg	    return NULL;
1397a4e54154Smrg	}
1398a4e54154Smrg	if (path [strlen ((const char *) path) - 1] != '\\')
1399a4e54154Smrg	    strcat ((char *) path, "\\");
1400a4e54154Smrg	strcat ((char *) path, "fonts");
1401a4e54154Smrg    }
1402a4e54154Smrg    else
1403a4e54154Smrg    {
1404a4e54154Smrg	if (!prefix)
1405a4e54154Smrg	{
1406a4e54154Smrg	    if (!FcStrIsAbsoluteFilename (path) && path[0] != '~')
1407a4e54154Smrg		FcConfigMessage (parse, FcSevereWarning, "Use of ambiguous path in <%s> element. please add prefix=\"cwd\" if current behavior is desired.", FcElementReverseMap (parse->pstack->element));
1408a4e54154Smrg	}
1409a4e54154Smrg    }
1410a4e54154Smrg#endif
1411a4e54154Smrg    if (parent)
1412a4e54154Smrg    {
1413a4e54154Smrg	retval = FcStrBuildFilename (parent, path, NULL);
1414a4e54154Smrg	FcStrFree (parent);
1415a4e54154Smrg    }
1416a4e54154Smrg    else
1417a4e54154Smrg    {
1418a4e54154Smrg	retval = FcStrdup (path);
1419a4e54154Smrg    }
1420a4e54154Smrg    if (!e)
1421a4e54154Smrg	e = FcStrSetCreate ();
1422a4e54154Smrg    else
1423a4e54154Smrg    {
1424a4e54154Smrg	FcChar8 *s;
1425a4e54154Smrg	int i;
1426a4e54154Smrg
1427a4e54154Smrg	for (i = 0; i < e->num; i++)
1428a4e54154Smrg	{
1429a4e54154Smrg	    s = FcStrBuildFilename (e->strs[i], path, NULL);
1430a4e54154Smrg	    FcStrFree (e->strs[i]);
1431a4e54154Smrg	    e->strs[i] = s;
1432a4e54154Smrg	}
1433a4e54154Smrg    }
1434a4e54154Smrg    if (!FcStrSetInsert (e, retval, 0))
1435a4e54154Smrg    {
1436a4e54154Smrg	FcStrSetDestroy (e);
1437a4e54154Smrg	e = NULL;
1438a4e54154Smrg    }
1439a4e54154Smrg    FcStrFree (retval);
1440a4e54154Smrg
1441a4e54154Smrg    return e;
1442a4e54154Smrg}
1443a4e54154Smrg
14442c393a42Smrgstatic void
14452c393a42SmrgFcStartElement(void *userData, const XML_Char *name, const XML_Char **attr)
14462c393a42Smrg{
14472c393a42Smrg    FcConfigParse   *parse = userData;
14482c393a42Smrg    FcElement	    element;
1449ca08ab68Smrg
14502c393a42Smrg    element = FcElementMap (name);
14512c393a42Smrg    if (element == FcElementUnknown)
14522c393a42Smrg	FcConfigMessage (parse, FcSevereWarning, "unknown element \"%s\"", name);
1453ca08ab68Smrg
14542c393a42Smrg    if (!FcPStackPush (parse, element, attr))
14552c393a42Smrg    {
14562c393a42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
14572c393a42Smrg	return;
14582c393a42Smrg    }
14592c393a42Smrg    return;
14602c393a42Smrg}
14612c393a42Smrg
14622c393a42Smrgstatic void
14632c393a42SmrgFcParseRescan (FcConfigParse *parse)
14642c393a42Smrg{
14652c393a42Smrg    int	    n = FcVStackElements (parse);
14662c393a42Smrg    while (n-- > 0)
14672c393a42Smrg    {
14682c393a42Smrg	FcVStack    *v = FcVStackFetch (parse, n);
14692c393a42Smrg	if (v->tag != FcVStackInteger)
14702c393a42Smrg	    FcConfigMessage (parse, FcSevereWarning, "non-integer rescan");
14712c393a42Smrg	else
14722c393a42Smrg	    parse->config->rescanInterval = v->u.integer;
14732c393a42Smrg    }
14742c393a42Smrg}
14752c393a42Smrg
14762c393a42Smrgstatic void
14772c393a42SmrgFcParseInt (FcConfigParse *parse)
14782c393a42Smrg{
14792c393a42Smrg    FcChar8 *s, *end;
14802c393a42Smrg    int	    l;
1481ca08ab68Smrg
14822c393a42Smrg    if (!parse->pstack)
14832c393a42Smrg	return;
1484a6844aabSmrg    s = FcStrBufDoneStatic (&parse->pstack->str);
14852c393a42Smrg    if (!s)
14862c393a42Smrg    {
14872c393a42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
14882c393a42Smrg	return;
14892c393a42Smrg    }
14902c393a42Smrg    end = 0;
14912c393a42Smrg    l = (int) strtol ((char *) s, (char **)&end, 0);
14922c393a42Smrg    if (end != s + strlen ((char *) s))
14932c393a42Smrg	FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid integer", s);
14942c393a42Smrg    else
14952c393a42Smrg	FcVStackPushInteger (parse, l);
1496a6844aabSmrg    FcStrBufDestroy (&parse->pstack->str);
14972c393a42Smrg}
14982c393a42Smrg
14992c393a42Smrg/*
1500ca08ab68Smrg * idea copied from glib g_ascii_strtod with
1501ca08ab68Smrg * permission of the author (Alexander Larsson)
15022c393a42Smrg */
15032c393a42Smrg
15042c393a42Smrg#include <locale.h>
15052c393a42Smrg
1506ca08ab68Smrgstatic double
15072c393a42SmrgFcStrtod (char *s, char **end)
15082c393a42Smrg{
1509953daebaSmrg#ifndef __BIONIC__
15102c393a42Smrg    struct lconv    *locale_data;
1511953daebaSmrg#endif
1512953daebaSmrg    const char	    *decimal_point;
1513953daebaSmrg    int		    dlen;
15142c393a42Smrg    char	    *dot;
15152c393a42Smrg    double	    v;
15162c393a42Smrg
15172c393a42Smrg    /*
15182c393a42Smrg     * Have to swap the decimal point to match the current locale
15192c393a42Smrg     * if that locale doesn't use 0x2e
15202c393a42Smrg     */
1521953daebaSmrg#ifndef __BIONIC__
1522953daebaSmrg    locale_data = localeconv ();
1523953daebaSmrg    decimal_point = locale_data->decimal_point;
1524953daebaSmrg    dlen = strlen (decimal_point);
1525953daebaSmrg#else
1526953daebaSmrg    decimal_point = ".";
1527953daebaSmrg    dlen = 1;
1528953daebaSmrg#endif
1529953daebaSmrg
15302c393a42Smrg    if ((dot = strchr (s, 0x2e)) &&
1531953daebaSmrg	(decimal_point[0] != 0x2e ||
1532953daebaSmrg	 decimal_point[1] != 0))
15332c393a42Smrg    {
15342c393a42Smrg	char	buf[128];
15352c393a42Smrg	int	slen = strlen (s);
15362c393a42Smrg
15372c393a42Smrg	if (slen + dlen > (int) sizeof (buf))
15382c393a42Smrg	{
15392c393a42Smrg	    if (end)
15402c393a42Smrg		*end = s;
15412c393a42Smrg	    v = 0;
15422c393a42Smrg	}
15432c393a42Smrg	else
15442c393a42Smrg	{
15452c393a42Smrg	    char	*buf_end;
15462c393a42Smrg	    /* mantissa */
15472c393a42Smrg	    strncpy (buf, s, dot - s);
15482c393a42Smrg	    /* decimal point */
1549953daebaSmrg	    strcpy (buf + (dot - s), decimal_point);
15502c393a42Smrg	    /* rest of number */
15512c393a42Smrg	    strcpy (buf + (dot - s) + dlen, dot + 1);
15522c393a42Smrg	    buf_end = 0;
15532c393a42Smrg	    v = strtod (buf, &buf_end);
15542c393a42Smrg	    if (buf_end) {
15552c393a42Smrg		buf_end = s + (buf_end - buf);
15562c393a42Smrg		if (buf_end > dot)
15572c393a42Smrg		    buf_end -= dlen - 1;
15582c393a42Smrg	    }
15592c393a42Smrg	    if (end)
15602c393a42Smrg		*end = buf_end;
15612c393a42Smrg	}
15622c393a42Smrg    }
15632c393a42Smrg    else
15642c393a42Smrg	v = strtod (s, end);
15652c393a42Smrg    return v;
15662c393a42Smrg}
15672c393a42Smrg
15682c393a42Smrgstatic void
15692c393a42SmrgFcParseDouble (FcConfigParse *parse)
15702c393a42Smrg{
15712c393a42Smrg    FcChar8 *s, *end;
15722c393a42Smrg    double  d;
1573ca08ab68Smrg
15742c393a42Smrg    if (!parse->pstack)
15752c393a42Smrg	return;
1576a6844aabSmrg    s = FcStrBufDoneStatic (&parse->pstack->str);
15772c393a42Smrg    if (!s)
15782c393a42Smrg    {
15792c393a42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
15802c393a42Smrg	return;
15812c393a42Smrg    }
15822c393a42Smrg    end = 0;
15832c393a42Smrg    d = FcStrtod ((char *) s, (char **)&end);
15842c393a42Smrg    if (end != s + strlen ((char *) s))
15852c393a42Smrg	FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid double", s);
15862c393a42Smrg    else
15872c393a42Smrg	FcVStackPushDouble (parse, d);
1588a6844aabSmrg    FcStrBufDestroy (&parse->pstack->str);
15892c393a42Smrg}
15902c393a42Smrg
15912c393a42Smrgstatic void
15922c393a42SmrgFcParseString (FcConfigParse *parse, FcVStackTag tag)
15932c393a42Smrg{
15942c393a42Smrg    FcChar8 *s;
1595ca08ab68Smrg
15962c393a42Smrg    if (!parse->pstack)
15972c393a42Smrg	return;
15982c393a42Smrg    s = FcStrBufDone (&parse->pstack->str);
15992c393a42Smrg    if (!s)
16002c393a42Smrg    {
16012c393a42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
16022c393a42Smrg	return;
16032c393a42Smrg    }
16042c393a42Smrg    if (!FcVStackPushString (parse, tag, s))
16052c393a42Smrg	FcStrFree (s);
16062c393a42Smrg}
16072c393a42Smrg
16082c393a42Smrgstatic void
1609c9710b42SmrgFcParseName (FcConfigParse *parse)
16102c393a42Smrg{
1611c9710b42Smrg    const FcChar8   *kind_string;
1612c9710b42Smrg    FcMatchKind	    kind;
1613c9710b42Smrg    FcChar8 *s;
1614c9710b42Smrg    FcObject object;
1615ca08ab68Smrg
1616c9710b42Smrg    kind_string = FcConfigGetAttribute (parse, "target");
1617c9710b42Smrg    if (!kind_string)
1618c9710b42Smrg	kind = FcMatchDefault;
1619c9710b42Smrg    else
16202c393a42Smrg    {
1621c9710b42Smrg	if (!strcmp ((char *) kind_string, "pattern"))
1622c9710b42Smrg	    kind = FcMatchPattern;
1623c9710b42Smrg	else if (!strcmp ((char *) kind_string, "font"))
1624c9710b42Smrg	    kind = FcMatchFont;
1625c9710b42Smrg	else if (!strcmp ((char *) kind_string, "default"))
1626c9710b42Smrg	    kind = FcMatchDefault;
1627c9710b42Smrg	else
1628c9710b42Smrg	{
1629c9710b42Smrg	    FcConfigMessage (parse, FcSevereWarning, "invalid name target \"%s\"", kind_string);
1630c9710b42Smrg	    return;
16312c393a42Smrg	}
16322c393a42Smrg    }
1633c9710b42Smrg
1634c9710b42Smrg    if (!parse->pstack)
1635c9710b42Smrg	return;
1636c9710b42Smrg    s = FcStrBufDone (&parse->pstack->str);
1637c9710b42Smrg    if (!s)
1638c9710b42Smrg    {
1639c9710b42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
1640c9710b42Smrg	return;
1641c9710b42Smrg    }
1642c9710b42Smrg    object = FcObjectFromName ((const char *) s);
1643c9710b42Smrg
1644c9710b42Smrg    FcVStackPushName (parse, kind, object);
1645c9710b42Smrg
1646c9710b42Smrg    FcStrFree (s);
1647c9710b42Smrg}
1648c9710b42Smrg
1649c9710b42Smrgstatic void
1650c9710b42SmrgFcParseMatrix (FcConfigParse *parse)
1651c9710b42Smrg{
1652c9710b42Smrg    FcExprMatrix m;
1653c9710b42Smrg
1654c9710b42Smrg    m.yy = FcPopExpr (parse);
1655c9710b42Smrg    m.yx = FcPopExpr (parse);
1656c9710b42Smrg    m.xy = FcPopExpr (parse);
1657c9710b42Smrg    m.xx = FcPopExpr (parse);
1658c9710b42Smrg
1659a4e54154Smrg    if (!m.yy || !m.yx || !m.xy || !m.xx)
1660a4e54154Smrg    {
1661a4e54154Smrg	FcConfigMessage (parse, FcSevereWarning, "Missing values in matrix element");
1662a4e54154Smrg	return;
1663a4e54154Smrg    }
1664c9710b42Smrg    if (FcPopExpr (parse))
1665c9710b42Smrg      FcConfigMessage (parse, FcSevereError, "wrong number of matrix elements");
16662c393a42Smrg    else
1667c9710b42Smrg      FcVStackPushMatrix (parse, &m);
16682c393a42Smrg}
16692c393a42Smrg
1670ca08ab68Smrgstatic void
1671ca08ab68SmrgFcParseRange (FcConfigParse *parse)
1672ca08ab68Smrg{
1673ca08ab68Smrg    FcVStack	*vstack;
1674953daebaSmrg    FcRange	*r;
1675953daebaSmrg    FcChar32	n[2] = {0, 0};
1676ca08ab68Smrg    int		count = 1;
1677953daebaSmrg    double	d[2] = {0.0L, 0.0L};
1678953daebaSmrg    FcBool	dflag = FcFalse;
1679ca08ab68Smrg
1680ca08ab68Smrg    while ((vstack = FcVStackPeek (parse)))
1681ca08ab68Smrg    {
1682ca08ab68Smrg	if (count < 0)
1683ca08ab68Smrg	{
1684ca08ab68Smrg	    FcConfigMessage (parse, FcSevereError, "too many elements in range");
1685ca08ab68Smrg	    return;
1686ca08ab68Smrg	}
1687c9710b42Smrg	switch ((int) vstack->tag) {
1688ca08ab68Smrg	case FcVStackInteger:
1689953daebaSmrg	    if (dflag)
1690953daebaSmrg		d[count] = (double)vstack->u.integer;
1691953daebaSmrg	    else
1692953daebaSmrg		n[count] = vstack->u.integer;
1693953daebaSmrg	    break;
1694953daebaSmrg	case FcVStackDouble:
1695953daebaSmrg	    if (count == 0 && !dflag)
1696953daebaSmrg		d[1] = (double)n[1];
1697953daebaSmrg	    d[count] = vstack->u._double;
1698953daebaSmrg	    dflag = FcTrue;
1699ca08ab68Smrg	    break;
1700ca08ab68Smrg	default:
1701ca08ab68Smrg	    FcConfigMessage (parse, FcSevereError, "invalid element in range");
1702953daebaSmrg	    if (dflag)
1703953daebaSmrg		d[count] = 0.0L;
1704953daebaSmrg	    else
1705953daebaSmrg		n[count] = 0;
1706ca08ab68Smrg	    break;
1707ca08ab68Smrg	}
1708ca08ab68Smrg	count--;
1709ca08ab68Smrg	FcVStackPopAndDestroy (parse);
1710ca08ab68Smrg    }
1711953daebaSmrg    if (count >= 0)
1712ca08ab68Smrg    {
1713953daebaSmrg	FcConfigMessage (parse, FcSevereError, "invalid range");
1714953daebaSmrg	return;
1715953daebaSmrg    }
1716953daebaSmrg    if (dflag)
1717953daebaSmrg    {
1718953daebaSmrg	if (d[0] > d[1])
1719ca08ab68Smrg	{
1720ca08ab68Smrg	    FcConfigMessage (parse, FcSevereError, "invalid range");
1721ca08ab68Smrg	    return;
1722ca08ab68Smrg	}
1723953daebaSmrg	r = FcRangeCreateDouble (d[0], d[1]);
1724ca08ab68Smrg    }
1725ca08ab68Smrg    else
1726953daebaSmrg    {
1727953daebaSmrg	if (n[0] > n[1])
1728953daebaSmrg	{
1729953daebaSmrg	    FcConfigMessage (parse, FcSevereError, "invalid range");
1730953daebaSmrg	    return;
1731953daebaSmrg	}
1732953daebaSmrg	r = FcRangeCreateInteger (n[0], n[1]);
1733953daebaSmrg    }
1734953daebaSmrg    FcVStackPushRange (parse, r);
1735ca08ab68Smrg}
1736ca08ab68Smrg
17372c393a42Smrgstatic FcBool
1738a6844aabSmrgFcConfigLexBool (FcConfigParse *parse, const FcChar8 *bool_)
17392c393a42Smrg{
17402c393a42Smrg    FcBool  result = FcFalse;
17412c393a42Smrg
1742a6844aabSmrg    if (!FcNameBool (bool_, &result))
17432c393a42Smrg	FcConfigMessage (parse, FcSevereWarning, "\"%s\" is not known boolean",
1744a6844aabSmrg			 bool_);
17452c393a42Smrg    return result;
17462c393a42Smrg}
17472c393a42Smrg
17482c393a42Smrgstatic void
17492c393a42SmrgFcParseBool (FcConfigParse *parse)
17502c393a42Smrg{
17512c393a42Smrg    FcChar8 *s;
17522c393a42Smrg
17532c393a42Smrg    if (!parse->pstack)
17542c393a42Smrg	return;
1755a6844aabSmrg    s = FcStrBufDoneStatic (&parse->pstack->str);
17562c393a42Smrg    if (!s)
17572c393a42Smrg    {
17582c393a42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
17592c393a42Smrg	return;
17602c393a42Smrg    }
17612c393a42Smrg    FcVStackPushBool (parse, FcConfigLexBool (parse, s));
1762a6844aabSmrg    FcStrBufDestroy (&parse->pstack->str);
17632c393a42Smrg}
17642c393a42Smrg
1765ca08ab68Smrgstatic void
1766ca08ab68SmrgFcParseCharSet (FcConfigParse *parse)
1767ca08ab68Smrg{
1768ca08ab68Smrg    FcVStack	*vstack;
1769ca08ab68Smrg    FcCharSet	*charset = FcCharSetCreate ();
1770953daebaSmrg    FcChar32	i, begin, end;
1771ca08ab68Smrg    int n = 0;
1772ca08ab68Smrg
1773ca08ab68Smrg    while ((vstack = FcVStackPeek (parse)))
1774ca08ab68Smrg    {
1775c9710b42Smrg	switch ((int) vstack->tag) {
1776ca08ab68Smrg	case FcVStackInteger:
1777ca08ab68Smrg	    if (!FcCharSetAddChar (charset, vstack->u.integer))
1778ca08ab68Smrg	    {
1779ca08ab68Smrg		FcConfigMessage (parse, FcSevereWarning, "invalid character: 0x%04x", vstack->u.integer);
1780ca08ab68Smrg	    }
1781ca08ab68Smrg	    else
1782ca08ab68Smrg		n++;
1783ca08ab68Smrg	    break;
1784ca08ab68Smrg	case FcVStackRange:
1785953daebaSmrg	    begin = (FcChar32) vstack->u.range->begin;
1786953daebaSmrg	    end = (FcChar32) vstack->u.range->end;
1787953daebaSmrg
1788953daebaSmrg	    if (begin <= end)
1789ca08ab68Smrg	    {
1790953daebaSmrg	      for (i = begin; i <= end; i++)
1791ca08ab68Smrg	      {
1792ca08ab68Smrg		  if (!FcCharSetAddChar (charset, i))
1793ca08ab68Smrg		  {
1794ca08ab68Smrg		      FcConfigMessage (parse, FcSevereWarning, "invalid character: 0x%04x", i);
1795ca08ab68Smrg		  }
1796ca08ab68Smrg		  else
1797ca08ab68Smrg		      n++;
1798ca08ab68Smrg	      }
1799ca08ab68Smrg	    }
1800ca08ab68Smrg	    break;
1801ca08ab68Smrg	default:
1802ca08ab68Smrg		FcConfigMessage (parse, FcSevereError, "invalid element in charset");
1803ca08ab68Smrg		break;
1804ca08ab68Smrg	}
1805ca08ab68Smrg	FcVStackPopAndDestroy (parse);
1806ca08ab68Smrg    }
1807ca08ab68Smrg    if (n > 0)
1808ca08ab68Smrg	    FcVStackPushCharSet (parse, charset);
1809ca08ab68Smrg    else
1810ca08ab68Smrg	    FcCharSetDestroy (charset);
1811ca08ab68Smrg}
1812ca08ab68Smrg
1813ca08ab68Smrgstatic void
1814ca08ab68SmrgFcParseLangSet (FcConfigParse *parse)
1815ca08ab68Smrg{
1816ca08ab68Smrg    FcVStack	*vstack;
1817ca08ab68Smrg    FcLangSet	*langset = FcLangSetCreate ();
1818ca08ab68Smrg    int n = 0;
1819ca08ab68Smrg
1820ca08ab68Smrg    while ((vstack = FcVStackPeek (parse)))
1821ca08ab68Smrg    {
1822c9710b42Smrg	switch ((int) vstack->tag) {
1823ca08ab68Smrg	case FcVStackString:
1824ca08ab68Smrg	    if (!FcLangSetAdd (langset, vstack->u.string))
1825ca08ab68Smrg	    {
1826ca08ab68Smrg		FcConfigMessage (parse, FcSevereWarning, "invalid langset: %s", vstack->u.string);
1827ca08ab68Smrg	    }
1828ca08ab68Smrg	    else
1829ca08ab68Smrg		n++;
1830ca08ab68Smrg	    break;
1831ca08ab68Smrg	default:
1832ca08ab68Smrg		FcConfigMessage (parse, FcSevereError, "invalid element in langset");
1833ca08ab68Smrg		break;
1834ca08ab68Smrg	}
1835ca08ab68Smrg	FcVStackPopAndDestroy (parse);
1836ca08ab68Smrg    }
1837ca08ab68Smrg    if (n > 0)
1838ca08ab68Smrg	    FcVStackPushLangSet (parse, langset);
1839ca08ab68Smrg    else
1840ca08ab68Smrg	    FcLangSetDestroy (langset);
1841ca08ab68Smrg}
1842ca08ab68Smrg
18432c393a42Smrgstatic FcBool
18442c393a42SmrgFcConfigLexBinding (FcConfigParse   *parse,
18452c393a42Smrg		    const FcChar8   *binding_string,
18462c393a42Smrg		    FcValueBinding  *binding_ret)
18472c393a42Smrg{
18482c393a42Smrg    FcValueBinding binding;
1849ca08ab68Smrg
18502c393a42Smrg    if (!binding_string)
18512c393a42Smrg	binding = FcValueBindingWeak;
18522c393a42Smrg    else
18532c393a42Smrg    {
18542c393a42Smrg	if (!strcmp ((char *) binding_string, "weak"))
18552c393a42Smrg	    binding = FcValueBindingWeak;
18562c393a42Smrg	else if (!strcmp ((char *) binding_string, "strong"))
18572c393a42Smrg	    binding = FcValueBindingStrong;
18582c393a42Smrg	else if (!strcmp ((char *) binding_string, "same"))
18592c393a42Smrg	    binding = FcValueBindingSame;
18602c393a42Smrg	else
18612c393a42Smrg	{
18622c393a42Smrg	    FcConfigMessage (parse, FcSevereWarning, "invalid binding \"%s\"", binding_string);
18632c393a42Smrg	    return FcFalse;
18642c393a42Smrg	}
18652c393a42Smrg    }
18662c393a42Smrg    *binding_ret = binding;
18672c393a42Smrg    return FcTrue;
18682c393a42Smrg}
18692c393a42Smrg
18702c393a42Smrgstatic void
18712c393a42SmrgFcParseFamilies (FcConfigParse *parse, FcVStackTag tag)
18722c393a42Smrg{
18732c393a42Smrg    FcVStack	*vstack;
18742c393a42Smrg    FcExpr	*left, *expr = 0, *new;
18752c393a42Smrg
1876a6844aabSmrg    while ((vstack = FcVStackPeek (parse)))
18772c393a42Smrg    {
18782c393a42Smrg	if (vstack->tag != FcVStackFamily)
18792c393a42Smrg	{
18802c393a42Smrg	    FcConfigMessage (parse, FcSevereWarning, "non-family");
1881a6844aabSmrg	    FcVStackPopAndDestroy (parse);
18822c393a42Smrg	    continue;
18832c393a42Smrg	}
18842c393a42Smrg	left = vstack->u.expr;
18852c393a42Smrg	vstack->tag = FcVStackNone;
1886a6844aabSmrg	FcVStackPopAndDestroy (parse);
18872c393a42Smrg	if (expr)
18882c393a42Smrg	{
1889a6844aabSmrg	    new = FcExprCreateOp (parse->config, left, FcOpComma, expr);
18902c393a42Smrg	    if (!new)
18912c393a42Smrg	    {
18922c393a42Smrg		FcConfigMessage (parse, FcSevereError, "out of memory");
18932c393a42Smrg		FcExprDestroy (left);
18942c393a42Smrg		FcExprDestroy (expr);
18952c393a42Smrg		break;
18962c393a42Smrg	    }
18972c393a42Smrg	    expr = new;
18982c393a42Smrg	}
18992c393a42Smrg	else
19002c393a42Smrg	    expr = left;
19012c393a42Smrg    }
19022c393a42Smrg    if (expr)
19032c393a42Smrg    {
19042c393a42Smrg	if (!FcVStackPushExpr (parse, tag, expr))
19052c393a42Smrg	{
19062c393a42Smrg	    FcConfigMessage (parse, FcSevereError, "out of memory");
19072c393a42Smrg            FcExprDestroy (expr);
19082c393a42Smrg	}
19092c393a42Smrg    }
19102c393a42Smrg}
19112c393a42Smrg
19122c393a42Smrgstatic void
19132c393a42SmrgFcParseFamily (FcConfigParse *parse)
19142c393a42Smrg{
19152c393a42Smrg    FcChar8 *s;
19162c393a42Smrg    FcExpr  *expr;
19172c393a42Smrg
19182c393a42Smrg    if (!parse->pstack)
19192c393a42Smrg	return;
1920a6844aabSmrg    s = FcStrBufDoneStatic (&parse->pstack->str);
19212c393a42Smrg    if (!s)
19222c393a42Smrg    {
19232c393a42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
19242c393a42Smrg	return;
19252c393a42Smrg    }
1926a6844aabSmrg    expr = FcExprCreateString (parse->config, s);
1927a6844aabSmrg    FcStrBufDestroy (&parse->pstack->str);
19282c393a42Smrg    if (expr)
19292c393a42Smrg	FcVStackPushExpr (parse, FcVStackFamily, expr);
19302c393a42Smrg}
19312c393a42Smrg
19322c393a42Smrgstatic void
19332c393a42SmrgFcParseAlias (FcConfigParse *parse)
19342c393a42Smrg{
19352c393a42Smrg    FcExpr	*family = 0, *accept = 0, *prefer = 0, *def = 0, *new = 0;
19366fc018e4Smrg    FcEdit	*edit = 0;
19372c393a42Smrg    FcVStack	*vstack;
19386fc018e4Smrg    FcRule	*rule = NULL, *r;
19392c393a42Smrg    FcValueBinding  binding;
1940a32e9e42Smrg    int		    n;
19412c393a42Smrg
19422c393a42Smrg    if (!FcConfigLexBinding (parse, FcConfigGetAttribute (parse, "binding"), &binding))
19432c393a42Smrg	return;
1944a6844aabSmrg    while ((vstack = FcVStackPeek (parse)))
19452c393a42Smrg    {
1946c9710b42Smrg	switch ((int) vstack->tag) {
19472c393a42Smrg	case FcVStackFamily:
19482c393a42Smrg	    if (family)
19492c393a42Smrg	    {
1950ca08ab68Smrg		FcConfigMessage (parse, FcSevereWarning, "Having multiple <family> in <alias> isn't supported and may not work as expected");
1951a6844aabSmrg		new = FcExprCreateOp (parse->config, vstack->u.expr, FcOpComma, family);
19522c393a42Smrg		if (!new)
19532c393a42Smrg		    FcConfigMessage (parse, FcSevereError, "out of memory");
19542c393a42Smrg		else
19552c393a42Smrg		    family = new;
19562c393a42Smrg	    }
19572c393a42Smrg	    else
19582c393a42Smrg		new = vstack->u.expr;
19592c393a42Smrg	    if (new)
19602c393a42Smrg	    {
19612c393a42Smrg		family = new;
19622c393a42Smrg		vstack->tag = FcVStackNone;
19632c393a42Smrg	    }
19642c393a42Smrg	    break;
19652c393a42Smrg	case FcVStackPrefer:
19662c393a42Smrg	    if (prefer)
19672c393a42Smrg		FcExprDestroy (prefer);
19682c393a42Smrg	    prefer = vstack->u.expr;
19692c393a42Smrg	    vstack->tag = FcVStackNone;
19702c393a42Smrg	    break;
19712c393a42Smrg	case FcVStackAccept:
19722c393a42Smrg	    if (accept)
19732c393a42Smrg		FcExprDestroy (accept);
19742c393a42Smrg	    accept = vstack->u.expr;
19752c393a42Smrg	    vstack->tag = FcVStackNone;
19762c393a42Smrg	    break;
19772c393a42Smrg	case FcVStackDefault:
19782c393a42Smrg	    if (def)
19792c393a42Smrg		FcExprDestroy (def);
19802c393a42Smrg	    def = vstack->u.expr;
19812c393a42Smrg	    vstack->tag = FcVStackNone;
19822c393a42Smrg	    break;
1983ca08ab68Smrg	case FcVStackTest:
19846fc018e4Smrg	    if (rule)
19856fc018e4Smrg	    {
19866fc018e4Smrg		r = FcRuleCreate (FcRuleTest, vstack->u.test);
19876fc018e4Smrg		r->next = rule;
19886fc018e4Smrg		rule = r;
19896fc018e4Smrg	    }
19906fc018e4Smrg	    else
19916fc018e4Smrg		rule = FcRuleCreate (FcRuleTest, vstack->u.test);
1992ca08ab68Smrg	    vstack->tag = FcVStackNone;
1993ca08ab68Smrg	    break;
19942c393a42Smrg	default:
19952c393a42Smrg	    FcConfigMessage (parse, FcSevereWarning, "bad alias");
19962c393a42Smrg	    break;
19972c393a42Smrg	}
1998a6844aabSmrg	FcVStackPopAndDestroy (parse);
19992c393a42Smrg    }
20002c393a42Smrg    if (!family)
20012c393a42Smrg    {
20022c393a42Smrg	FcConfigMessage (parse, FcSevereError, "missing family in alias");
20032c393a42Smrg	if (prefer)
20042c393a42Smrg	    FcExprDestroy (prefer);
20052c393a42Smrg	if (accept)
20062c393a42Smrg	    FcExprDestroy (accept);
20072c393a42Smrg	if (def)
20082c393a42Smrg	    FcExprDestroy (def);
20096fc018e4Smrg	if (rule)
20106fc018e4Smrg	    FcRuleDestroy (rule);
20112c393a42Smrg	return;
20122c393a42Smrg    }
20136fc018e4Smrg    if (!prefer &&
20146fc018e4Smrg	!accept &&
20156fc018e4Smrg	!def)
20166fc018e4Smrg    {
20176fc018e4Smrg	FcExprDestroy (family);
2018a32e9e42Smrg	if (rule)
2019a32e9e42Smrg	    FcRuleDestroy (rule);
20206fc018e4Smrg	return;
20216fc018e4Smrg    }
20226fc018e4Smrg    else
20236fc018e4Smrg    {
20246fc018e4Smrg	FcTest *t = FcTestCreate (parse, FcMatchPattern,
20256fc018e4Smrg				  FcQualAny,
20266fc018e4Smrg				  (FcChar8 *) FC_FAMILY,
20276fc018e4Smrg				  FC_OP (FcOpEqual, FcOpFlagIgnoreBlanks),
20286fc018e4Smrg				  family);
20296fc018e4Smrg	if (rule)
20306fc018e4Smrg	{
20316fc018e4Smrg	    for (r = rule; r->next; r = r->next);
20326fc018e4Smrg	    r->next = FcRuleCreate (FcRuleTest, t);
20336fc018e4Smrg	    r = r->next;
20346fc018e4Smrg	}
20356fc018e4Smrg	else
20366fc018e4Smrg	{
20376fc018e4Smrg	    r = rule = FcRuleCreate (FcRuleTest, t);
20386fc018e4Smrg	}
20396fc018e4Smrg    }
20402c393a42Smrg    if (prefer)
20412c393a42Smrg    {
2042ca08ab68Smrg	edit = FcEditCreate (parse,
20432c393a42Smrg			     FC_FAMILY_OBJECT,
20442c393a42Smrg			     FcOpPrepend,
20452c393a42Smrg			     prefer,
20462c393a42Smrg			     binding);
20476fc018e4Smrg	if (!edit)
20482c393a42Smrg	    FcExprDestroy (prefer);
20496fc018e4Smrg	else
20506fc018e4Smrg	{
20516fc018e4Smrg	    r->next = FcRuleCreate (FcRuleEdit, edit);
20526fc018e4Smrg	    r = r->next;
20536fc018e4Smrg	}
20542c393a42Smrg    }
20552c393a42Smrg    if (accept)
20562c393a42Smrg    {
20572c393a42Smrg	edit = FcEditCreate (parse,
20582c393a42Smrg			     FC_FAMILY_OBJECT,
20592c393a42Smrg			     FcOpAppend,
20602c393a42Smrg			     accept,
20612c393a42Smrg			     binding);
20626fc018e4Smrg	if (!edit)
20632c393a42Smrg	    FcExprDestroy (accept);
20646fc018e4Smrg	else
20656fc018e4Smrg	{
20666fc018e4Smrg	    r->next = FcRuleCreate (FcRuleEdit, edit);
20676fc018e4Smrg	    r = r->next;
20686fc018e4Smrg	}
20692c393a42Smrg    }
20702c393a42Smrg    if (def)
20712c393a42Smrg    {
20722c393a42Smrg	edit = FcEditCreate (parse,
20732c393a42Smrg			     FC_FAMILY_OBJECT,
20742c393a42Smrg			     FcOpAppendLast,
20752c393a42Smrg			     def,
20762c393a42Smrg			     binding);
20776fc018e4Smrg	if (!edit)
20782c393a42Smrg	    FcExprDestroy (def);
20796fc018e4Smrg	else
2080ca08ab68Smrg	{
20816fc018e4Smrg	    r->next = FcRuleCreate (FcRuleEdit, edit);
20826fc018e4Smrg	    r = r->next;
2083ca08ab68Smrg	}
20842c393a42Smrg    }
2085a32e9e42Smrg    if ((n = FcRuleSetAdd (parse->ruleset, rule, FcMatchPattern)) == -1)
20866fc018e4Smrg	FcRuleDestroy (rule);
2087a32e9e42Smrg    else
2088a32e9e42Smrg	if (parse->config->maxObjects < n)
2089a32e9e42Smrg	    parse->config->maxObjects = n;
2090a32e9e42Smrg}
2091a32e9e42Smrg
2092a32e9e42Smrgstatic void
2093a32e9e42SmrgFcParseDescription (FcConfigParse *parse)
2094a32e9e42Smrg{
2095a32e9e42Smrg    const FcChar8 *domain;
2096a32e9e42Smrg    FcChar8 *desc;
2097a32e9e42Smrg
2098a32e9e42Smrg    domain = FcConfigGetAttribute (parse, "domain");
2099a32e9e42Smrg    desc = FcStrBufDone (&parse->pstack->str);
2100a32e9e42Smrg    if (!desc)
2101a32e9e42Smrg    {
2102a32e9e42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
2103a32e9e42Smrg	return;
2104a32e9e42Smrg    }
2105a32e9e42Smrg    FcRuleSetAddDescription (parse->ruleset, domain, desc);
2106a32e9e42Smrg
2107a32e9e42Smrg    FcStrFree (desc);
21082c393a42Smrg}
21092c393a42Smrg
2110a4e54154Smrgstatic void
2111a4e54154SmrgFcParseRemapDir (FcConfigParse *parse)
2112a4e54154Smrg{
2113a4e54154Smrg    const FcChar8 *path, *attr, *data, *salt;
2114a4e54154Smrg    FcStrSet *prefix_dirs = NULL;
2115a4e54154Smrg
2116a4e54154Smrg    data = FcStrBufDoneStatic (&parse->pstack->str);
2117a4e54154Smrg    if (!data)
2118a4e54154Smrg    {
2119a4e54154Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
2120a4e54154Smrg	return;
2121a4e54154Smrg    }
2122a4e54154Smrg    if (data[0] == 0)
2123a4e54154Smrg    {
2124a4e54154Smrg	FcConfigMessage (parse, FcSevereWarning, "empty font directory name for remap ignored");
2125a4e54154Smrg	return;
2126a4e54154Smrg    }
2127a4e54154Smrg    path = FcConfigGetAttribute (parse, "as-path");
2128a4e54154Smrg    if (!path)
2129a4e54154Smrg    {
2130a4e54154Smrg	FcConfigMessage (parse, FcSevereWarning, "Missing as-path in remap-dir");
2131a4e54154Smrg	return;
2132a4e54154Smrg    }
2133a4e54154Smrg    attr = FcConfigGetAttribute (parse, "prefix");
2134a4e54154Smrg    salt = FcConfigGetAttribute (parse, "salt");
2135a4e54154Smrg    prefix_dirs = _get_real_paths_from_prefix (parse, data, attr);
2136a4e54154Smrg    if (prefix_dirs)
2137a4e54154Smrg    {
2138a4e54154Smrg	FcStrList *l = FcStrListCreate (prefix_dirs);
2139a4e54154Smrg	FcChar8 *prefix;
2140a4e54154Smrg
2141a4e54154Smrg	FcStrSetDestroy (prefix_dirs);
2142a4e54154Smrg	while ((prefix = FcStrListNext (l)))
2143a4e54154Smrg	{
2144a4e54154Smrg	    if (!prefix || prefix[0] == 0)
2145a4e54154Smrg	    {
2146a4e54154Smrg		/* nop */
2147a4e54154Smrg	    }
2148a4e54154Smrg	    else if (!parse->scanOnly && (!FcStrUsesHome (prefix) || FcConfigHome ()))
2149a4e54154Smrg	    {
2150a4e54154Smrg		if (!FcConfigAddFontDir (parse->config, prefix, path, salt))
2151a4e54154Smrg		    FcConfigMessage (parse, FcSevereError, "out of memory; cannot create remap data for %s as %s", prefix, path);
2152a4e54154Smrg	    }
2153a4e54154Smrg	    FcStrBufDestroy (&parse->pstack->str);
2154a4e54154Smrg	}
2155a4e54154Smrg	FcStrListDone (l);
2156a4e54154Smrg    }
2157a4e54154Smrg}
2158a4e54154Smrg
2159a4e54154Smrgstatic void
2160a4e54154SmrgFcParseResetDirs (FcConfigParse *parse)
2161a4e54154Smrg{
2162a4e54154Smrg    if (!parse->scanOnly)
2163a4e54154Smrg    {
2164a4e54154Smrg	if (!FcConfigResetFontDirs (parse->config))
2165a4e54154Smrg	    FcConfigMessage (parse, FcSevereError, "Unable to reset fonts dirs");
2166a4e54154Smrg    }
2167a4e54154Smrg}
2168a4e54154Smrg
21692c393a42Smrgstatic FcExpr *
21702c393a42SmrgFcPopExpr (FcConfigParse *parse)
21712c393a42Smrg{
2172a6844aabSmrg    FcVStack	*vstack = FcVStackPeek (parse);
21732c393a42Smrg    FcExpr	*expr = 0;
21742c393a42Smrg    if (!vstack)
21752c393a42Smrg	return 0;
2176c9710b42Smrg    switch ((int) vstack->tag) {
21772c393a42Smrg    case FcVStackNone:
21782c393a42Smrg	break;
21792c393a42Smrg    case FcVStackString:
21802c393a42Smrg    case FcVStackFamily:
2181a6844aabSmrg	expr = FcExprCreateString (parse->config, vstack->u.string);
21822c393a42Smrg	break;
2183c9710b42Smrg    case FcVStackName:
2184c9710b42Smrg	expr = FcExprCreateName (parse->config, vstack->u.name);
21852c393a42Smrg	break;
21862c393a42Smrg    case FcVStackConstant:
2187a6844aabSmrg	expr = FcExprCreateConst (parse->config, vstack->u.string);
21882c393a42Smrg	break;
21892c393a42Smrg    case FcVStackGlob:
21902c393a42Smrg	/* XXX: What's the correct action here? (CDW) */
21912c393a42Smrg	break;
21922c393a42Smrg    case FcVStackPrefer:
21932c393a42Smrg    case FcVStackAccept:
21942c393a42Smrg    case FcVStackDefault:
21952c393a42Smrg	expr = vstack->u.expr;
21962c393a42Smrg	vstack->tag = FcVStackNone;
21972c393a42Smrg	break;
21982c393a42Smrg    case FcVStackInteger:
2199a6844aabSmrg	expr = FcExprCreateInteger (parse->config, vstack->u.integer);
22002c393a42Smrg	break;
22012c393a42Smrg    case FcVStackDouble:
2202a6844aabSmrg	expr = FcExprCreateDouble (parse->config, vstack->u._double);
22032c393a42Smrg	break;
22042c393a42Smrg    case FcVStackMatrix:
2205a6844aabSmrg	expr = FcExprCreateMatrix (parse->config, vstack->u.matrix);
22062c393a42Smrg	break;
2207ca08ab68Smrg    case FcVStackRange:
2208953daebaSmrg	expr = FcExprCreateRange (parse->config, vstack->u.range);
2209ca08ab68Smrg	break;
22102c393a42Smrg    case FcVStackBool:
2211a6844aabSmrg	expr = FcExprCreateBool (parse->config, vstack->u.bool_);
22122c393a42Smrg	break;
2213ca08ab68Smrg    case FcVStackCharSet:
2214ca08ab68Smrg	expr = FcExprCreateCharSet (parse->config, vstack->u.charset);
2215ca08ab68Smrg	break;
2216ca08ab68Smrg    case FcVStackLangSet:
2217ca08ab68Smrg	expr = FcExprCreateLangSet (parse->config, vstack->u.langset);
2218ca08ab68Smrg	break;
22192c393a42Smrg    case FcVStackTest:
22202c393a42Smrg	break;
22212c393a42Smrg    case FcVStackExpr:
22222c393a42Smrg	expr = vstack->u.expr;
22232c393a42Smrg	vstack->tag = FcVStackNone;
22242c393a42Smrg	break;
22252c393a42Smrg    case FcVStackEdit:
22262c393a42Smrg	break;
22272c393a42Smrg    default:
22282c393a42Smrg	break;
22292c393a42Smrg    }
2230a6844aabSmrg    FcVStackPopAndDestroy (parse);
22312c393a42Smrg    return expr;
22322c393a42Smrg}
22332c393a42Smrg
22342c393a42Smrg/*
22352c393a42Smrg * This builds a tree of binary operations.  Note
22362c393a42Smrg * that every operator is defined so that if only
22372c393a42Smrg * a single operand is contained, the value of the
22382c393a42Smrg * whole expression is the value of the operand.
22392c393a42Smrg *
22402c393a42Smrg * This code reduces in that case to returning that
22412c393a42Smrg * operand.
22422c393a42Smrg */
22432c393a42Smrgstatic FcExpr *
22442c393a42SmrgFcPopBinary (FcConfigParse *parse, FcOp op)
22452c393a42Smrg{
22462c393a42Smrg    FcExpr  *left, *expr = 0, *new;
22472c393a42Smrg
22482c393a42Smrg    while ((left = FcPopExpr (parse)))
22492c393a42Smrg    {
22502c393a42Smrg	if (expr)
22512c393a42Smrg	{
2252a6844aabSmrg	    new = FcExprCreateOp (parse->config, left, op, expr);
22532c393a42Smrg	    if (!new)
22542c393a42Smrg	    {
22552c393a42Smrg		FcConfigMessage (parse, FcSevereError, "out of memory");
22562c393a42Smrg		FcExprDestroy (left);
22572c393a42Smrg		FcExprDestroy (expr);
22582c393a42Smrg		return 0;
22592c393a42Smrg	    }
22602c393a42Smrg	    expr = new;
22612c393a42Smrg	}
22622c393a42Smrg	else
22632c393a42Smrg	    expr = left;
22642c393a42Smrg    }
22652c393a42Smrg    return expr;
22662c393a42Smrg}
22672c393a42Smrg
22682c393a42Smrgstatic void
22692c393a42SmrgFcParseBinary (FcConfigParse *parse, FcOp op)
22702c393a42Smrg{
22712c393a42Smrg    FcExpr  *expr = FcPopBinary (parse, op);
22722c393a42Smrg    if (expr)
22732c393a42Smrg	FcVStackPushExpr (parse, FcVStackExpr, expr);
22742c393a42Smrg}
22752c393a42Smrg
22762c393a42Smrg/*
22772c393a42Smrg * This builds a a unary operator, it consumes only
22782c393a42Smrg * a single operand
22792c393a42Smrg */
22802c393a42Smrg
22812c393a42Smrgstatic FcExpr *
22822c393a42SmrgFcPopUnary (FcConfigParse *parse, FcOp op)
22832c393a42Smrg{
22842c393a42Smrg    FcExpr  *operand, *new = 0;
22852c393a42Smrg
22862c393a42Smrg    if ((operand = FcPopExpr (parse)))
22872c393a42Smrg    {
2288a6844aabSmrg	new = FcExprCreateOp (parse->config, operand, op, 0);
22892c393a42Smrg	if (!new)
22902c393a42Smrg	{
22912c393a42Smrg	    FcExprDestroy (operand);
22922c393a42Smrg	    FcConfigMessage (parse, FcSevereError, "out of memory");
22932c393a42Smrg	}
22942c393a42Smrg    }
22952c393a42Smrg    return new;
22962c393a42Smrg}
22972c393a42Smrg
22982c393a42Smrgstatic void
22992c393a42SmrgFcParseUnary (FcConfigParse *parse, FcOp op)
23002c393a42Smrg{
23012c393a42Smrg    FcExpr  *expr = FcPopUnary (parse, op);
23022c393a42Smrg    if (expr)
23032c393a42Smrg	FcVStackPushExpr (parse, FcVStackExpr, expr);
23042c393a42Smrg}
23052c393a42Smrg
2306ca08ab68Smrgstatic void
2307ca08ab68SmrgFcParseDir (FcConfigParse *parse)
2308ca08ab68Smrg{
2309a4e54154Smrg    const FcChar8 *attr, *data, *salt;
2310a4e54154Smrg    FcStrSet *prefix_dirs = NULL;
2311ca08ab68Smrg
2312ca08ab68Smrg    data = FcStrBufDoneStatic (&parse->pstack->str);
2313ca08ab68Smrg    if (!data)
2314ca08ab68Smrg    {
2315ca08ab68Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
2316a4e54154Smrg	return;
2317ca08ab68Smrg    }
2318a4e54154Smrg    if (data[0] == 0)
2319ca08ab68Smrg    {
2320a4e54154Smrg	FcConfigMessage (parse, FcSevereWarning, "empty font directory name ignored");
2321a4e54154Smrg	return;
2322ca08ab68Smrg    }
2323a4e54154Smrg    attr = FcConfigGetAttribute (parse, "prefix");
2324a4e54154Smrg    salt = FcConfigGetAttribute (parse, "salt");
2325a4e54154Smrg    prefix_dirs = _get_real_paths_from_prefix (parse, data, attr);
2326a4e54154Smrg    if (prefix_dirs)
2327ca08ab68Smrg    {
2328a4e54154Smrg	FcStrList *l = FcStrListCreate (prefix_dirs);
2329a4e54154Smrg	FcChar8 *prefix;
2330a4e54154Smrg
2331a4e54154Smrg	FcStrSetDestroy (prefix_dirs);
2332a4e54154Smrg	while ((prefix = FcStrListNext (l)))
2333ca08ab68Smrg	{
2334a4e54154Smrg	    if (!prefix || prefix[0] == 0)
2335a4e54154Smrg	    {
2336a4e54154Smrg		/* nop */
2337a4e54154Smrg	    }
2338a4e54154Smrg	    else if (!parse->scanOnly && (!FcStrUsesHome (prefix) || FcConfigHome ()))
2339a4e54154Smrg	    {
2340a4e54154Smrg		if (!FcConfigAddFontDir (parse->config, prefix, NULL, salt))
2341a4e54154Smrg		    FcConfigMessage (parse, FcSevereError, "out of memory; cannot add directory %s", prefix);
2342a4e54154Smrg	    }
2343a4e54154Smrg	    FcStrBufDestroy (&parse->pstack->str);
2344ca08ab68Smrg	}
2345a4e54154Smrg	FcStrListDone (l);
2346ca08ab68Smrg    }
2347ca08ab68Smrg}
2348ca08ab68Smrg
2349ca08ab68Smrgstatic void
2350ca08ab68SmrgFcParseCacheDir (FcConfigParse *parse)
2351ca08ab68Smrg{
2352ca08ab68Smrg    const FcChar8 *attr;
2353953daebaSmrg    FcChar8 *prefix = NULL, *p, *data = NULL;
2354ca08ab68Smrg
2355ca08ab68Smrg    attr = FcConfigGetAttribute (parse, "prefix");
2356ca08ab68Smrg    if (attr && FcStrCmp (attr, (const FcChar8 *)"xdg") == 0)
2357953daebaSmrg    {
2358ca08ab68Smrg	prefix = FcConfigXdgCacheHome ();
2359953daebaSmrg	/* home directory might be disabled.
2360953daebaSmrg	 * simply ignore this element.
2361953daebaSmrg	 */
2362953daebaSmrg	if (!prefix)
2363953daebaSmrg	    goto bail;
2364953daebaSmrg    }
2365ca08ab68Smrg    data = FcStrBufDone (&parse->pstack->str);
2366ca08ab68Smrg    if (!data)
2367ca08ab68Smrg    {
2368ca08ab68Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
2369a32e9e42Smrg	data = prefix;
2370ca08ab68Smrg	goto bail;
2371ca08ab68Smrg    }
2372a4e54154Smrg    if (data[0] == 0)
2373a4e54154Smrg    {
2374a4e54154Smrg	FcConfigMessage (parse, FcSevereWarning, "empty cache directory name ignored");
2375a4e54154Smrg	FcStrFree (data);
2376a4e54154Smrg	data = prefix;
2377a4e54154Smrg	goto bail;
2378a4e54154Smrg    }
2379ca08ab68Smrg    if (prefix)
2380ca08ab68Smrg    {
2381ca08ab68Smrg	size_t plen = strlen ((const char *)prefix);
2382ca08ab68Smrg	size_t dlen = strlen ((const char *)data);
2383ca08ab68Smrg
2384c9710b42Smrg	p = realloc (prefix, plen + 1 + dlen + 1);
2385c9710b42Smrg	if (!p)
2386ca08ab68Smrg	{
2387ca08ab68Smrg	    FcConfigMessage (parse, FcSevereError, "out of memory");
2388a32e9e42Smrg	    FcStrFree (prefix);
2389ca08ab68Smrg	    goto bail;
2390ca08ab68Smrg	}
2391c9710b42Smrg	prefix = p;
2392ca08ab68Smrg	prefix[plen] = FC_DIR_SEPARATOR;
2393ca08ab68Smrg	memcpy (&prefix[plen + 1], data, dlen);
2394ca08ab68Smrg	prefix[plen + 1 + dlen] = 0;
2395ca08ab68Smrg	FcStrFree (data);
2396ca08ab68Smrg	data = prefix;
2397ca08ab68Smrg    }
2398ca08ab68Smrg#ifdef _WIN32
2399953daebaSmrg    else if (data[0] == '/' && fontconfig_instprefix[0] != '\0')
2400953daebaSmrg    {
2401953daebaSmrg	size_t plen = strlen ((const char *)fontconfig_instprefix);
2402953daebaSmrg	size_t dlen = strlen ((const char *)data);
2403953daebaSmrg
2404953daebaSmrg	prefix = malloc (plen + 1 + dlen + 1);
2405953daebaSmrg	if (!prefix)
2406953daebaSmrg	{
2407953daebaSmrg	    FcConfigMessage (parse, FcSevereError, "out of memory");
2408953daebaSmrg	    goto bail;
2409953daebaSmrg	}
2410953daebaSmrg	strcpy ((char *) prefix, (char *) fontconfig_instprefix);
2411953daebaSmrg	prefix[plen] = FC_DIR_SEPARATOR;
2412953daebaSmrg	memcpy (&prefix[plen + 1], data, dlen);
2413953daebaSmrg	prefix[plen + 1 + dlen] = 0;
2414953daebaSmrg	FcStrFree (data);
2415953daebaSmrg	data = prefix;
2416953daebaSmrg    }
2417953daebaSmrg    else if (strcmp ((const char *) data, "WINDOWSTEMPDIR_FONTCONFIG_CACHE") == 0)
2418ca08ab68Smrg    {
2419ca08ab68Smrg	int rc;
2420a32e9e42Smrg
2421ca08ab68Smrg	FcStrFree (data);
2422ca08ab68Smrg	data = malloc (1000);
2423ca08ab68Smrg	if (!data)
2424ca08ab68Smrg	{
2425ca08ab68Smrg	    FcConfigMessage (parse, FcSevereError, "out of memory");
2426ca08ab68Smrg	    goto bail;
2427ca08ab68Smrg	}
2428ca08ab68Smrg	rc = GetTempPath (800, (LPSTR) data);
2429ca08ab68Smrg	if (rc == 0 || rc > 800)
2430ca08ab68Smrg	{
2431ca08ab68Smrg	    FcConfigMessage (parse, FcSevereError, "GetTempPath failed");
2432ca08ab68Smrg	    goto bail;
2433ca08ab68Smrg	}
2434ca08ab68Smrg	if (data [strlen ((const char *) data) - 1] != '\\')
2435c9710b42Smrg	    strcat ((char *) data, "\\");
2436c9710b42Smrg	strcat ((char *) data, "fontconfig\\cache");
2437ca08ab68Smrg    }
2438ca08ab68Smrg    else if (strcmp ((const char *) data, "LOCAL_APPDATA_FONTCONFIG_CACHE") == 0)
2439ca08ab68Smrg    {
2440ca08ab68Smrg	char szFPath[MAX_PATH + 1];
2441ca08ab68Smrg	size_t len;
2442ca08ab68Smrg
2443ca08ab68Smrg	if (!(pSHGetFolderPathA && SUCCEEDED(pSHGetFolderPathA(NULL, /* CSIDL_LOCAL_APPDATA */ 28, NULL, 0, szFPath))))
2444ca08ab68Smrg	{
2445ca08ab68Smrg	    FcConfigMessage (parse, FcSevereError, "SHGetFolderPathA failed");
2446ca08ab68Smrg	    goto bail;
2447ca08ab68Smrg	}
2448ca08ab68Smrg	strncat(szFPath, "\\fontconfig\\cache", MAX_PATH - 1 - strlen(szFPath));
2449ca08ab68Smrg	len = strlen(szFPath) + 1;
2450ca08ab68Smrg	FcStrFree (data);
2451ca08ab68Smrg	data = malloc(len);
2452ca08ab68Smrg	if (!data)
2453ca08ab68Smrg	{
2454ca08ab68Smrg	    FcConfigMessage (parse, FcSevereError, "out of memory");
2455ca08ab68Smrg	    goto bail;
2456ca08ab68Smrg	}
2457ca08ab68Smrg	strncpy((char *) data, szFPath, len);
2458ca08ab68Smrg    }
2459ca08ab68Smrg#endif
2460ca08ab68Smrg    if (strlen ((char *) data) == 0)
2461ca08ab68Smrg	FcConfigMessage (parse, FcSevereWarning, "empty cache directory name ignored");
2462a32e9e42Smrg    else if (!parse->scanOnly && (!FcStrUsesHome (data) || FcConfigHome ()))
2463ca08ab68Smrg    {
2464ca08ab68Smrg	if (!FcConfigAddCacheDir (parse->config, data))
2465ca08ab68Smrg	    FcConfigMessage (parse, FcSevereError, "out of memory; cannot add cache directory %s", data);
2466ca08ab68Smrg    }
2467ca08ab68Smrg    FcStrBufDestroy (&parse->pstack->str);
2468ca08ab68Smrg
2469ca08ab68Smrg  bail:
2470ca08ab68Smrg    if (data)
2471ca08ab68Smrg	FcStrFree (data);
2472ca08ab68Smrg}
2473ca08ab68Smrg
2474953daebaSmrgvoid
2475953daebaSmrgFcConfigPathFini (void)
2476953daebaSmrg{
2477953daebaSmrg    FcChar8 *s;
2478953daebaSmrg
2479953daebaSmrgretry_dir:
2480953daebaSmrg    s = fc_atomic_ptr_get (&__fc_userdir);
2481953daebaSmrg    if (!fc_atomic_ptr_cmpexch (&__fc_userdir, s, NULL))
2482953daebaSmrg	goto retry_dir;
2483953daebaSmrg    free (s);
2484953daebaSmrg
2485953daebaSmrgretry_conf:
2486953daebaSmrg    s = fc_atomic_ptr_get (&__fc_userconf);
2487953daebaSmrg    if (!fc_atomic_ptr_cmpexch (&__fc_userconf, s, NULL))
2488953daebaSmrg	goto retry_conf;
2489953daebaSmrg    free (s);
2490953daebaSmrg}
2491953daebaSmrg
24922c393a42Smrgstatic void
24932c393a42SmrgFcParseInclude (FcConfigParse *parse)
24942c393a42Smrg{
24952c393a42Smrg    FcChar8	    *s;
2496ca08ab68Smrg    const FcChar8   *attr;
24972c393a42Smrg    FcBool	    ignore_missing = FcFalse;
2498953daebaSmrg#ifndef _WIN32
2499ca08ab68Smrg    FcBool	    deprecated = FcFalse;
2500953daebaSmrg#endif
2501c9710b42Smrg    FcChar8	    *prefix = NULL, *p;
2502953daebaSmrg    FcChar8	    *userdir = NULL, *userconf = NULL;
2503a32e9e42Smrg    FcRuleSet	    *ruleset;
2504a32e9e42Smrg    FcMatchKind	    k;
2505ca08ab68Smrg
2506a6844aabSmrg    s = FcStrBufDoneStatic (&parse->pstack->str);
25072c393a42Smrg    if (!s)
25082c393a42Smrg    {
25092c393a42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
2510ca08ab68Smrg	goto bail;
25112c393a42Smrg    }
2512ca08ab68Smrg    attr = FcConfigGetAttribute (parse, "ignore_missing");
2513ca08ab68Smrg    if (attr && FcConfigLexBool (parse, (FcChar8 *) attr) == FcTrue)
25142c393a42Smrg	ignore_missing = FcTrue;
2515ca08ab68Smrg    attr = FcConfigGetAttribute (parse, "deprecated");
2516953daebaSmrg#ifndef _WIN32
2517ca08ab68Smrg    if (attr && FcConfigLexBool (parse, (FcChar8 *) attr) == FcTrue)
2518ca08ab68Smrg        deprecated = FcTrue;
2519953daebaSmrg#endif
2520ca08ab68Smrg    attr = FcConfigGetAttribute (parse, "prefix");
2521ca08ab68Smrg    if (attr && FcStrCmp (attr, (const FcChar8 *)"xdg") == 0)
2522953daebaSmrg    {
2523ca08ab68Smrg	prefix = FcConfigXdgConfigHome ();
2524953daebaSmrg	/* home directory might be disabled.
2525953daebaSmrg	 * simply ignore this element.
2526953daebaSmrg	 */
2527953daebaSmrg	if (!prefix)
2528953daebaSmrg	    goto bail;
2529953daebaSmrg    }
2530ca08ab68Smrg    if (prefix)
2531ca08ab68Smrg    {
2532ca08ab68Smrg	size_t plen = strlen ((const char *)prefix);
2533ca08ab68Smrg	size_t dlen = strlen ((const char *)s);
2534953daebaSmrg	FcChar8 *u;
2535ca08ab68Smrg
2536c9710b42Smrg	p = realloc (prefix, plen + 1 + dlen + 1);
2537c9710b42Smrg	if (!p)
2538ca08ab68Smrg	{
2539ca08ab68Smrg	    FcConfigMessage (parse, FcSevereError, "out of memory");
2540ca08ab68Smrg	    goto bail;
2541ca08ab68Smrg	}
2542c9710b42Smrg	prefix = p;
2543ca08ab68Smrg	prefix[plen] = FC_DIR_SEPARATOR;
2544ca08ab68Smrg	memcpy (&prefix[plen + 1], s, dlen);
2545ca08ab68Smrg	prefix[plen + 1 + dlen] = 0;
2546ca08ab68Smrg	s = prefix;
25476fc018e4Smrg	if (FcFileIsDir (s))
25486fc018e4Smrg	{
25496fc018e4Smrg	userdir:
2550953daebaSmrg	    userdir = fc_atomic_ptr_get (&__fc_userdir);
25516fc018e4Smrg	    if (!userdir)
2552953daebaSmrg	    {
2553953daebaSmrg		u = FcStrdup (s);
2554953daebaSmrg		if (!fc_atomic_ptr_cmpexch (&__fc_userdir, userdir, u))
2555953daebaSmrg		{
2556953daebaSmrg		    free (u);
2557953daebaSmrg		    goto userdir;
2558953daebaSmrg		}
2559953daebaSmrg		userdir = u;
2560953daebaSmrg	    }
25616fc018e4Smrg	}
25626fc018e4Smrg	else if (FcFileIsFile (s))
25636fc018e4Smrg	{
25646fc018e4Smrg	userconf:
2565953daebaSmrg	    userconf = fc_atomic_ptr_get (&__fc_userconf);
25666fc018e4Smrg	    if (!userconf)
2567953daebaSmrg	    {
2568953daebaSmrg		u = FcStrdup (s);
2569953daebaSmrg		if (!fc_atomic_ptr_cmpexch (&__fc_userconf, userconf, u))
2570953daebaSmrg		{
2571953daebaSmrg		    free (u);
2572953daebaSmrg		    goto userconf;
2573953daebaSmrg		}
2574953daebaSmrg		userconf = u;
2575953daebaSmrg	    }
25766fc018e4Smrg	}
25776fc018e4Smrg	else
25786fc018e4Smrg	{
25796fc018e4Smrg	    /* No config dir nor file on the XDG directory spec compliant place
25806fc018e4Smrg	     * so need to guess what it is supposed to be.
25816fc018e4Smrg	     */
25826fc018e4Smrg	    if (FcStrStr (s, (const FcChar8 *)"conf.d") != NULL)
25836fc018e4Smrg		goto userdir;
25846fc018e4Smrg	    else
25856fc018e4Smrg		goto userconf;
25866fc018e4Smrg	}
2587ca08ab68Smrg    }
2588a32e9e42Smrg    /* flush the ruleset into the queue */
2589a32e9e42Smrg    ruleset = parse->ruleset;
2590a32e9e42Smrg    parse->ruleset = FcRuleSetCreate (ruleset->name);
2591a32e9e42Smrg    FcRuleSetEnable (parse->ruleset, ruleset->enabled);
2592a32e9e42Smrg    FcRuleSetAddDescription (parse->ruleset, ruleset->domain, ruleset->description);
2593a32e9e42Smrg    for (k = FcMatchKindBegin; k < FcMatchKindEnd; k++)
2594a32e9e42Smrg    {
2595a32e9e42Smrg	FcPtrListIter iter;
2596a32e9e42Smrg
2597a32e9e42Smrg	FcPtrListIterInit (ruleset->subst[k], &iter);
2598a32e9e42Smrg	if (FcPtrListIterIsValid (ruleset->subst[k], &iter))
2599a32e9e42Smrg	{
2600a32e9e42Smrg	    FcPtrListIterInitAtLast (parse->config->subst[k], &iter);
2601a32e9e42Smrg	    FcRuleSetReference (ruleset);
2602a32e9e42Smrg	    FcPtrListIterAdd (parse->config->subst[k], &iter, ruleset);
2603a32e9e42Smrg	}
2604a32e9e42Smrg    }
2605a32e9e42Smrg    FcRuleSetDestroy (ruleset);
2606a32e9e42Smrg    if (!_FcConfigParse (parse->config, s, !ignore_missing, !parse->scanOnly))
26072c393a42Smrg	parse->error = FcTrue;
26086fc018e4Smrg#ifndef _WIN32
2609ca08ab68Smrg    else
2610ca08ab68Smrg    {
2611ca08ab68Smrg        FcChar8 *filename;
26126fc018e4Smrg	static FcBool warn_conf = FcFalse, warn_confd = FcFalse;
2613ca08ab68Smrg
2614a4e54154Smrg        filename = FcConfigGetFilename(parse->config, s);
2615c9710b42Smrg	if (deprecated == FcTrue &&
2616c9710b42Smrg	    filename != NULL &&
2617953daebaSmrg	    userdir != NULL &&
2618c9710b42Smrg	    !FcFileIsLink (filename))
2619c9710b42Smrg	{
26206fc018e4Smrg	    if (FcFileIsDir (filename))
26216fc018e4Smrg	    {
26226fc018e4Smrg		FcChar8 *parent = FcStrDirname (userdir);
26236fc018e4Smrg
26246fc018e4Smrg		if (!FcFileIsDir (parent))
26256fc018e4Smrg		    FcMakeDirectory (parent);
26266fc018e4Smrg		FcStrFree (parent);
26276fc018e4Smrg		if (FcFileIsDir (userdir) ||
26286fc018e4Smrg		    rename ((const char *)filename, (const char *)userdir) != 0 ||
26296fc018e4Smrg		    symlink ((const char *)userdir, (const char *)filename) != 0)
26306fc018e4Smrg		{
26316fc018e4Smrg		    if (!warn_confd)
26326fc018e4Smrg		    {
26336fc018e4Smrg			FcConfigMessage (parse, FcSevereWarning, "reading configurations from %s is deprecated. please move it to %s manually", s, userdir);
26346fc018e4Smrg			warn_confd = FcTrue;
26356fc018e4Smrg		    }
26366fc018e4Smrg		}
26376fc018e4Smrg	    }
26386fc018e4Smrg	    else
26396fc018e4Smrg	    {
26406fc018e4Smrg		FcChar8 *parent = FcStrDirname (userconf);
26416fc018e4Smrg
26426fc018e4Smrg		if (!FcFileIsDir (parent))
26436fc018e4Smrg		    FcMakeDirectory (parent);
26446fc018e4Smrg		FcStrFree (parent);
26456fc018e4Smrg		if (FcFileIsFile (userconf) ||
26466fc018e4Smrg		    rename ((const char *)filename, (const char *)userconf) != 0 ||
26476fc018e4Smrg		    symlink ((const char *)userconf, (const char *)filename) != 0)
26486fc018e4Smrg		{
26496fc018e4Smrg		    if (!warn_conf)
26506fc018e4Smrg		    {
26516fc018e4Smrg			FcConfigMessage (parse, FcSevereWarning, "reading configurations from %s is deprecated. please move it to %s manually", s, userconf);
26526fc018e4Smrg			warn_conf = FcTrue;
26536fc018e4Smrg		    }
26546fc018e4Smrg		}
26556fc018e4Smrg	    }
2656ca08ab68Smrg        }
2657ca08ab68Smrg        if(filename)
2658ca08ab68Smrg            FcStrFree(filename);
2659ca08ab68Smrg    }
26606fc018e4Smrg#endif
2661a6844aabSmrg    FcStrBufDestroy (&parse->pstack->str);
2662ca08ab68Smrg
2663ca08ab68Smrg  bail:
2664ca08ab68Smrg    if (prefix)
2665ca08ab68Smrg	FcStrFree (prefix);
26662c393a42Smrg}
26672c393a42Smrg
26682c393a42Smrgtypedef struct _FcOpMap {
26692c393a42Smrg    char    name[16];
26702c393a42Smrg    FcOp    op;
26712c393a42Smrg} FcOpMap;
26722c393a42Smrg
26732c393a42Smrgstatic FcOp
26742c393a42SmrgFcConfigLexOp (const FcChar8 *op, const FcOpMap	*map, int nmap)
26752c393a42Smrg{
26762c393a42Smrg    int	i;
26772c393a42Smrg
26782c393a42Smrg    for (i = 0; i < nmap; i++)
2679ca08ab68Smrg	if (!strcmp ((char *) op, map[i].name))
26802c393a42Smrg	    return map[i].op;
26812c393a42Smrg    return FcOpInvalid;
26822c393a42Smrg}
26832c393a42Smrg
26842c393a42Smrgstatic const FcOpMap fcCompareOps[] = {
26852c393a42Smrg    { "eq",		FcOpEqual	    },
26862c393a42Smrg    { "not_eq",		FcOpNotEqual	    },
26872c393a42Smrg    { "less",		FcOpLess	    },
26882c393a42Smrg    { "less_eq",	FcOpLessEqual	    },
26892c393a42Smrg    { "more",		FcOpMore	    },
26902c393a42Smrg    { "more_eq",	FcOpMoreEqual	    },
26912c393a42Smrg    { "contains",	FcOpContains	    },
26922c393a42Smrg    { "not_contains",	FcOpNotContains	    }
26932c393a42Smrg};
26942c393a42Smrg
26952c393a42Smrg#define NUM_COMPARE_OPS	(int) (sizeof fcCompareOps / sizeof fcCompareOps[0])
26962c393a42Smrg
26972c393a42Smrgstatic FcOp
26982c393a42SmrgFcConfigLexCompare (const FcChar8 *compare)
26992c393a42Smrg{
27002c393a42Smrg    return FcConfigLexOp (compare, fcCompareOps, NUM_COMPARE_OPS);
27012c393a42Smrg}
27022c393a42Smrg
27032c393a42Smrgstatic void
27042c393a42SmrgFcParseTest (FcConfigParse *parse)
27052c393a42Smrg{
27062c393a42Smrg    const FcChar8   *kind_string;
27072c393a42Smrg    FcMatchKind	    kind;
27082c393a42Smrg    const FcChar8   *qual_string;
27092c393a42Smrg    FcQual	    qual;
27102c393a42Smrg    const FcChar8   *name;
27112c393a42Smrg    const FcChar8   *compare_string;
27122c393a42Smrg    FcOp	    compare;
27132c393a42Smrg    FcExpr	    *expr;
27142c393a42Smrg    FcTest	    *test;
2715ca08ab68Smrg    const FcChar8   *iblanks_string;
2716ca08ab68Smrg    int              flags = 0;
27172c393a42Smrg
27182c393a42Smrg    kind_string = FcConfigGetAttribute (parse, "target");
27192c393a42Smrg    if (!kind_string)
27202c393a42Smrg	kind = FcMatchDefault;
27212c393a42Smrg    else
27222c393a42Smrg    {
27232c393a42Smrg	if (!strcmp ((char *) kind_string, "pattern"))
27242c393a42Smrg	    kind = FcMatchPattern;
27252c393a42Smrg	else if (!strcmp ((char *) kind_string, "font"))
27262c393a42Smrg	    kind = FcMatchFont;
27272c393a42Smrg	else if (!strcmp ((char *) kind_string, "scan"))
27282c393a42Smrg	    kind = FcMatchScan;
27292c393a42Smrg	else if (!strcmp ((char *) kind_string, "default"))
27302c393a42Smrg	    kind = FcMatchDefault;
27312c393a42Smrg	else
27322c393a42Smrg	{
27332c393a42Smrg	    FcConfigMessage (parse, FcSevereWarning, "invalid test target \"%s\"", kind_string);
27342c393a42Smrg	    return;
27352c393a42Smrg	}
27362c393a42Smrg    }
27372c393a42Smrg    qual_string = FcConfigGetAttribute (parse, "qual");
27382c393a42Smrg    if (!qual_string)
27392c393a42Smrg	qual = FcQualAny;
27402c393a42Smrg    else
27412c393a42Smrg    {
27422c393a42Smrg	if (!strcmp ((char *) qual_string, "any"))
27432c393a42Smrg	    qual = FcQualAny;
27442c393a42Smrg	else if (!strcmp ((char *) qual_string, "all"))
27452c393a42Smrg	    qual = FcQualAll;
27462c393a42Smrg	else if (!strcmp ((char *) qual_string, "first"))
27472c393a42Smrg	    qual = FcQualFirst;
27482c393a42Smrg	else if (!strcmp ((char *) qual_string, "not_first"))
27492c393a42Smrg	    qual = FcQualNotFirst;
27502c393a42Smrg	else
27512c393a42Smrg	{
27522c393a42Smrg	    FcConfigMessage (parse, FcSevereWarning, "invalid test qual \"%s\"", qual_string);
27532c393a42Smrg	    return;
27542c393a42Smrg	}
27552c393a42Smrg    }
27562c393a42Smrg    name = FcConfigGetAttribute (parse, "name");
27572c393a42Smrg    if (!name)
27582c393a42Smrg    {
27592c393a42Smrg	FcConfigMessage (parse, FcSevereWarning, "missing test name");
27602c393a42Smrg	return;
27612c393a42Smrg    }
27622c393a42Smrg    compare_string = FcConfigGetAttribute (parse, "compare");
27632c393a42Smrg    if (!compare_string)
27642c393a42Smrg	compare = FcOpEqual;
27652c393a42Smrg    else
27662c393a42Smrg    {
27672c393a42Smrg	compare = FcConfigLexCompare (compare_string);
27682c393a42Smrg	if (compare == FcOpInvalid)
27692c393a42Smrg	{
27702c393a42Smrg	    FcConfigMessage (parse, FcSevereWarning, "invalid test compare \"%s\"", compare_string);
27712c393a42Smrg	    return;
27722c393a42Smrg	}
27732c393a42Smrg    }
2774ca08ab68Smrg    iblanks_string = FcConfigGetAttribute (parse, "ignore-blanks");
2775ca08ab68Smrg    if (iblanks_string)
2776ca08ab68Smrg    {
2777ca08ab68Smrg	FcBool f = FcFalse;
2778ca08ab68Smrg
2779ca08ab68Smrg	if (!FcNameBool (iblanks_string, &f))
2780ca08ab68Smrg	{
2781ca08ab68Smrg	    FcConfigMessage (parse,
2782ca08ab68Smrg			     FcSevereWarning,
2783ca08ab68Smrg			     "invalid test ignore-blanks \"%s\"", iblanks_string);
2784ca08ab68Smrg	}
2785ca08ab68Smrg	if (f)
2786ca08ab68Smrg	    flags |= FcOpFlagIgnoreBlanks;
2787ca08ab68Smrg    }
27882c393a42Smrg    expr = FcPopBinary (parse, FcOpComma);
27892c393a42Smrg    if (!expr)
27902c393a42Smrg    {
27912c393a42Smrg	FcConfigMessage (parse, FcSevereWarning, "missing test expression");
27922c393a42Smrg	return;
27932c393a42Smrg    }
2794ca08ab68Smrg    if (expr->op == FcOpComma)
2795ca08ab68Smrg    {
2796ca08ab68Smrg	FcConfigMessage (parse, FcSevereWarning, "Having multiple values in <test> isn't supported and may not work as expected");
2797ca08ab68Smrg    }
2798ca08ab68Smrg    test = FcTestCreate (parse, kind, qual, name, FC_OP (compare, flags), expr);
27992c393a42Smrg    if (!test)
28002c393a42Smrg    {
28012c393a42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
28022c393a42Smrg	return;
28032c393a42Smrg    }
28042c393a42Smrg    FcVStackPushTest (parse, test);
28052c393a42Smrg}
28062c393a42Smrg
28072c393a42Smrgstatic const FcOpMap fcModeOps[] = {
28082c393a42Smrg    { "assign",		FcOpAssign	    },
28092c393a42Smrg    { "assign_replace",	FcOpAssignReplace   },
28102c393a42Smrg    { "prepend",	FcOpPrepend	    },
28112c393a42Smrg    { "prepend_first",	FcOpPrependFirst    },
28122c393a42Smrg    { "append",		FcOpAppend	    },
28132c393a42Smrg    { "append_last",	FcOpAppendLast	    },
2814c9710b42Smrg    { "delete",		FcOpDelete	    },
2815c9710b42Smrg    { "delete_all",	FcOpDeleteAll	    },
28162c393a42Smrg};
28172c393a42Smrg
28182c393a42Smrg#define NUM_MODE_OPS (int) (sizeof fcModeOps / sizeof fcModeOps[0])
28192c393a42Smrg
28202c393a42Smrgstatic FcOp
28212c393a42SmrgFcConfigLexMode (const FcChar8 *mode)
28222c393a42Smrg{
28232c393a42Smrg    return FcConfigLexOp (mode, fcModeOps, NUM_MODE_OPS);
28242c393a42Smrg}
28252c393a42Smrg
28262c393a42Smrgstatic void
28272c393a42SmrgFcParseEdit (FcConfigParse *parse)
28282c393a42Smrg{
28292c393a42Smrg    const FcChar8   *name;
28302c393a42Smrg    const FcChar8   *mode_string;
28312c393a42Smrg    FcOp	    mode;
28322c393a42Smrg    FcValueBinding  binding;
28332c393a42Smrg    FcExpr	    *expr;
28342c393a42Smrg    FcEdit	    *edit;
28352c393a42Smrg
28362c393a42Smrg    name = FcConfigGetAttribute (parse, "name");
28372c393a42Smrg    if (!name)
28382c393a42Smrg    {
28392c393a42Smrg	FcConfigMessage (parse, FcSevereWarning, "missing edit name");
28402c393a42Smrg	return;
28412c393a42Smrg    }
28422c393a42Smrg    mode_string = FcConfigGetAttribute (parse, "mode");
28432c393a42Smrg    if (!mode_string)
28442c393a42Smrg	mode = FcOpAssign;
28452c393a42Smrg    else
28462c393a42Smrg    {
28472c393a42Smrg	mode = FcConfigLexMode (mode_string);
28482c393a42Smrg	if (mode == FcOpInvalid)
28492c393a42Smrg	{
28502c393a42Smrg	    FcConfigMessage (parse, FcSevereWarning, "invalid edit mode \"%s\"", mode_string);
28512c393a42Smrg	    return;
28522c393a42Smrg	}
28532c393a42Smrg    }
28542c393a42Smrg    if (!FcConfigLexBinding (parse, FcConfigGetAttribute (parse, "binding"), &binding))
28552c393a42Smrg	return;
28562c393a42Smrg
28572c393a42Smrg    expr = FcPopBinary (parse, FcOpComma);
2858c9710b42Smrg    if ((mode == FcOpDelete || mode == FcOpDeleteAll) &&
2859c9710b42Smrg	expr != NULL)
2860c9710b42Smrg    {
2861c9710b42Smrg	FcConfigMessage (parse, FcSevereWarning, "Expression doesn't take any effects for delete and delete_all");
2862c9710b42Smrg	FcExprDestroy (expr);
2863c9710b42Smrg	expr = NULL;
2864c9710b42Smrg    }
28652c393a42Smrg    edit = FcEditCreate (parse, FcObjectFromName ((char *) name),
28662c393a42Smrg			 mode, expr, binding);
28672c393a42Smrg    if (!edit)
28682c393a42Smrg    {
28692c393a42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
28702c393a42Smrg	FcExprDestroy (expr);
28712c393a42Smrg	return;
28722c393a42Smrg    }
28732c393a42Smrg    if (!FcVStackPushEdit (parse, edit))
28742c393a42Smrg	FcEditDestroy (edit);
28752c393a42Smrg}
28762c393a42Smrg
28772c393a42Smrgstatic void
28782c393a42SmrgFcParseMatch (FcConfigParse *parse)
28792c393a42Smrg{
28802c393a42Smrg    const FcChar8   *kind_name;
28812c393a42Smrg    FcMatchKind	    kind;
28822c393a42Smrg    FcVStack	    *vstack;
28836fc018e4Smrg    FcRule	    *rule = NULL, *r;
2884a32e9e42Smrg    int		    n;
28852c393a42Smrg
28862c393a42Smrg    kind_name = FcConfigGetAttribute (parse, "target");
28872c393a42Smrg    if (!kind_name)
28882c393a42Smrg	kind = FcMatchPattern;
28892c393a42Smrg    else
28902c393a42Smrg    {
28912c393a42Smrg	if (!strcmp ((char *) kind_name, "pattern"))
28922c393a42Smrg	    kind = FcMatchPattern;
28932c393a42Smrg	else if (!strcmp ((char *) kind_name, "font"))
28942c393a42Smrg	    kind = FcMatchFont;
28952c393a42Smrg	else if (!strcmp ((char *) kind_name, "scan"))
28962c393a42Smrg	    kind = FcMatchScan;
28972c393a42Smrg	else
28982c393a42Smrg	{
28992c393a42Smrg	    FcConfigMessage (parse, FcSevereWarning, "invalid match target \"%s\"", kind_name);
29002c393a42Smrg	    return;
29012c393a42Smrg	}
29022c393a42Smrg    }
2903a6844aabSmrg    while ((vstack = FcVStackPeek (parse)))
29042c393a42Smrg    {
2905c9710b42Smrg	switch ((int) vstack->tag) {
29062c393a42Smrg	case FcVStackTest:
29076fc018e4Smrg	    r = FcRuleCreate (FcRuleTest, vstack->u.test);
29086fc018e4Smrg	    if (rule)
29096fc018e4Smrg		r->next = rule;
29106fc018e4Smrg	    rule = r;
29112c393a42Smrg	    vstack->tag = FcVStackNone;
29122c393a42Smrg	    break;
29132c393a42Smrg	case FcVStackEdit:
29146fc018e4Smrg	    if (kind == FcMatchScan && vstack->u.edit->object > FC_MAX_BASE_OBJECT)
29152c393a42Smrg	    {
2916ca08ab68Smrg		FcConfigMessage (parse, FcSevereError,
29172c393a42Smrg				 "<match target=\"scan\"> cannot edit user-defined object \"%s\"",
29186fc018e4Smrg				 FcObjectName(vstack->u.edit->object));
29196fc018e4Smrg		if (rule)
29206fc018e4Smrg		    FcRuleDestroy (rule);
29216fc018e4Smrg		return;
29222c393a42Smrg	    }
29236fc018e4Smrg	    r = FcRuleCreate (FcRuleEdit, vstack->u.edit);
29246fc018e4Smrg	    if (rule)
29256fc018e4Smrg		r->next = rule;
29266fc018e4Smrg	    rule = r;
29276fc018e4Smrg	    vstack->tag = FcVStackNone;
29282c393a42Smrg	    break;
29292c393a42Smrg	default:
29302c393a42Smrg	    FcConfigMessage (parse, FcSevereWarning, "invalid match element");
29312c393a42Smrg	    break;
29322c393a42Smrg	}
2933a6844aabSmrg	FcVStackPopAndDestroy (parse);
29342c393a42Smrg    }
2935b09479dcSmrg    if (!rule)
2936b09479dcSmrg    {
2937b09479dcSmrg	FcConfigMessage (parse, FcSevereWarning, "No <test> nor <edit> elements in <match>");
2938b09479dcSmrg	return;
2939b09479dcSmrg    }
2940a32e9e42Smrg    if ((n = FcRuleSetAdd (parse->ruleset, rule, kind)) == -1)
2941a32e9e42Smrg    {
29422c393a42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
2943a32e9e42Smrg	FcRuleDestroy (rule);
2944a32e9e42Smrg    }
2945a32e9e42Smrg    else
2946a32e9e42Smrg	if (parse->config->maxObjects < n)
2947a32e9e42Smrg	    parse->config->maxObjects = n;
29482c393a42Smrg}
29492c393a42Smrg
29502c393a42Smrgstatic void
29512c393a42SmrgFcParseAcceptRejectFont (FcConfigParse *parse, FcElement element)
29522c393a42Smrg{
29532c393a42Smrg    FcVStack	*vstack;
29542c393a42Smrg
2955a6844aabSmrg    while ((vstack = FcVStackPeek (parse)))
29562c393a42Smrg    {
2957c9710b42Smrg	switch ((int) vstack->tag) {
29582c393a42Smrg	case FcVStackGlob:
2959a32e9e42Smrg	    if (!parse->scanOnly && !FcConfigGlobAdd (parse->config,
2960a32e9e42Smrg						      vstack->u.string,
2961a32e9e42Smrg						      element == FcElementAcceptfont))
29622c393a42Smrg	    {
29632c393a42Smrg		FcConfigMessage (parse, FcSevereError, "out of memory");
29642c393a42Smrg	    }
2965a32e9e42Smrg	    else
2966a32e9e42Smrg	    {
2967a32e9e42Smrg		if (parse->scanOnly && vstack->u.string)
2968a32e9e42Smrg		{
2969a32e9e42Smrg		    FcStrFree (vstack->u.string);
2970a32e9e42Smrg		    vstack->tag = FcVStackNone;
2971a32e9e42Smrg		}
2972a32e9e42Smrg	    }
29732c393a42Smrg	    break;
29742c393a42Smrg	case FcVStackPattern:
2975a32e9e42Smrg	    if (!parse->scanOnly && !FcConfigPatternsAdd (parse->config,
2976a32e9e42Smrg							  vstack->u.pattern,
2977a32e9e42Smrg							  element == FcElementAcceptfont))
29782c393a42Smrg	    {
29792c393a42Smrg		FcConfigMessage (parse, FcSevereError, "out of memory");
29802c393a42Smrg	    }
29812c393a42Smrg	    else
2982a32e9e42Smrg	    {
2983a32e9e42Smrg		if (parse->scanOnly && vstack->u.pattern)
2984a32e9e42Smrg		    FcPatternDestroy (vstack->u.pattern);
29852c393a42Smrg		vstack->tag = FcVStackNone;
2986a32e9e42Smrg	    }
29872c393a42Smrg	    break;
29882c393a42Smrg	default:
29892c393a42Smrg	    FcConfigMessage (parse, FcSevereWarning, "bad font selector");
29902c393a42Smrg	    break;
29912c393a42Smrg	}
2992a6844aabSmrg	FcVStackPopAndDestroy (parse);
29932c393a42Smrg    }
29942c393a42Smrg}
29952c393a42Smrg
29962c393a42Smrg
29972c393a42Smrgstatic FcValue
29982c393a42SmrgFcPopValue (FcConfigParse *parse)
29992c393a42Smrg{
3000a6844aabSmrg    FcVStack	*vstack = FcVStackPeek (parse);
30012c393a42Smrg    FcValue	value;
3002ca08ab68Smrg
30032c393a42Smrg    value.type = FcTypeVoid;
3004ca08ab68Smrg
30052c393a42Smrg    if (!vstack)
30062c393a42Smrg	return value;
3007ca08ab68Smrg
3008c9710b42Smrg    switch ((int) vstack->tag) {
30092c393a42Smrg    case FcVStackString:
3010c9710b42Smrg	value.u.s = FcStrdup (vstack->u.string);
30112c393a42Smrg	if (value.u.s)
30122c393a42Smrg	    value.type = FcTypeString;
30132c393a42Smrg	break;
30142c393a42Smrg    case FcVStackConstant:
30152c393a42Smrg	if (FcNameConstant (vstack->u.string, &value.u.i))
30162c393a42Smrg	    value.type = FcTypeInteger;
30172c393a42Smrg	break;
30182c393a42Smrg    case FcVStackInteger:
30192c393a42Smrg	value.u.i = vstack->u.integer;
30202c393a42Smrg	value.type = FcTypeInteger;
30212c393a42Smrg	break;
30222c393a42Smrg    case FcVStackDouble:
30232c393a42Smrg	value.u.d = vstack->u._double;
3024c9710b42Smrg	value.type = FcTypeDouble;
30252c393a42Smrg	break;
30262c393a42Smrg    case FcVStackBool:
3027a6844aabSmrg	value.u.b = vstack->u.bool_;
30282c393a42Smrg	value.type = FcTypeBool;
30292c393a42Smrg	break;
3030ca08ab68Smrg    case FcVStackCharSet:
3031ca08ab68Smrg	value.u.c = FcCharSetCopy (vstack->u.charset);
3032ca08ab68Smrg	if (value.u.c)
3033ca08ab68Smrg	    value.type = FcTypeCharSet;
3034ca08ab68Smrg	break;
3035ca08ab68Smrg    case FcVStackLangSet:
3036ca08ab68Smrg	value.u.l = FcLangSetCopy (vstack->u.langset);
3037ca08ab68Smrg	if (value.u.l)
3038ca08ab68Smrg	    value.type = FcTypeLangSet;
3039ca08ab68Smrg	break;
3040953daebaSmrg    case FcVStackRange:
3041953daebaSmrg	value.u.r = FcRangeCopy (vstack->u.range);
3042953daebaSmrg	if (value.u.r)
3043953daebaSmrg	    value.type = FcTypeRange;
3044953daebaSmrg	break;
30452c393a42Smrg    default:
3046ca08ab68Smrg	FcConfigMessage (parse, FcSevereWarning, "unknown pattern element %d",
30472c393a42Smrg			 vstack->tag);
30482c393a42Smrg	break;
30492c393a42Smrg    }
3050a6844aabSmrg    FcVStackPopAndDestroy (parse);
3051ca08ab68Smrg
30522c393a42Smrg    return value;
30532c393a42Smrg}
30542c393a42Smrg
30552c393a42Smrgstatic void
30562c393a42SmrgFcParsePatelt (FcConfigParse *parse)
30572c393a42Smrg{
30582c393a42Smrg    FcValue	value;
30592c393a42Smrg    FcPattern	*pattern = FcPatternCreate ();
30602c393a42Smrg    const char	*name;
30612c393a42Smrg
30622c393a42Smrg    if (!pattern)
30632c393a42Smrg    {
30642c393a42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
30652c393a42Smrg	return;
30662c393a42Smrg    }
30672c393a42Smrg
30682c393a42Smrg    name = (char *) FcConfigGetAttribute (parse, "name");
30692c393a42Smrg    if (!name)
30702c393a42Smrg    {
30712c393a42Smrg	FcConfigMessage (parse, FcSevereWarning, "missing pattern element name");
30722c393a42Smrg	FcPatternDestroy (pattern);
30732c393a42Smrg	return;
30742c393a42Smrg    }
3075ca08ab68Smrg
30762c393a42Smrg    for (;;)
30772c393a42Smrg    {
30782c393a42Smrg	value = FcPopValue (parse);
30792c393a42Smrg	if (value.type == FcTypeVoid)
30802c393a42Smrg	    break;
30812c393a42Smrg	if (!FcPatternAdd (pattern, name, value, FcTrue))
30822c393a42Smrg	{
30832c393a42Smrg	    FcConfigMessage (parse, FcSevereError, "out of memory");
3084a6844aabSmrg            FcValueDestroy(value);
30852c393a42Smrg	    break;
30862c393a42Smrg	}
3087a6844aabSmrg        FcValueDestroy(value);
30882c393a42Smrg    }
30892c393a42Smrg
30902c393a42Smrg    FcVStackPushPattern (parse, pattern);
30912c393a42Smrg}
30922c393a42Smrg
30932c393a42Smrgstatic void
30942c393a42SmrgFcParsePattern (FcConfigParse *parse)
30952c393a42Smrg{
30962c393a42Smrg    FcVStack	*vstack;
30972c393a42Smrg    FcPattern	*pattern = FcPatternCreate ();
30982c393a42Smrg
30992c393a42Smrg    if (!pattern)
31002c393a42Smrg    {
31012c393a42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
31022c393a42Smrg	return;
31032c393a42Smrg    }
31042c393a42Smrg
3105a6844aabSmrg    while ((vstack = FcVStackPeek (parse)))
31062c393a42Smrg    {
3107c9710b42Smrg	switch ((int) vstack->tag) {
31082c393a42Smrg	case FcVStackPattern:
31092c393a42Smrg	    if (!FcPatternAppend (pattern, vstack->u.pattern))
31102c393a42Smrg	    {
31112c393a42Smrg		FcConfigMessage (parse, FcSevereError, "out of memory");
31122c393a42Smrg		FcPatternDestroy (pattern);
31132c393a42Smrg		return;
31142c393a42Smrg	    }
31152c393a42Smrg	    break;
31162c393a42Smrg	default:
31172c393a42Smrg	    FcConfigMessage (parse, FcSevereWarning, "unknown pattern element");
31182c393a42Smrg	    break;
31192c393a42Smrg	}
3120a6844aabSmrg	FcVStackPopAndDestroy (parse);
31212c393a42Smrg    }
31222c393a42Smrg
31232c393a42Smrg    FcVStackPushPattern (parse, pattern);
31242c393a42Smrg}
31252c393a42Smrg
31262c393a42Smrgstatic void
3127c9710b42SmrgFcEndElement(void *userData, const XML_Char *name FC_UNUSED)
31282c393a42Smrg{
31292c393a42Smrg    FcConfigParse   *parse = userData;
31302c393a42Smrg    FcChar8	    *data;
3131a6844aabSmrg
31322c393a42Smrg    if (!parse->pstack)
31332c393a42Smrg	return;
31342c393a42Smrg    switch (parse->pstack->element) {
31352c393a42Smrg    case FcElementNone:
31362c393a42Smrg	break;
31372c393a42Smrg    case FcElementFontconfig:
31382c393a42Smrg	break;
31392c393a42Smrg    case FcElementDir:
3140ca08ab68Smrg	FcParseDir (parse);
31412c393a42Smrg	break;
31422c393a42Smrg    case FcElementCacheDir:
3143ca08ab68Smrg	FcParseCacheDir (parse);
31442c393a42Smrg	break;
31452c393a42Smrg    case FcElementCache:
3146a6844aabSmrg	data = FcStrBufDoneStatic (&parse->pstack->str);
31472c393a42Smrg	if (!data)
31482c393a42Smrg	{
31492c393a42Smrg	    FcConfigMessage (parse, FcSevereError, "out of memory");
31502c393a42Smrg	    break;
31512c393a42Smrg	}
31522c393a42Smrg	/* discard this data; no longer used */
3153a6844aabSmrg	FcStrBufDestroy (&parse->pstack->str);
31542c393a42Smrg	break;
31552c393a42Smrg    case FcElementInclude:
31562c393a42Smrg	FcParseInclude (parse);
31572c393a42Smrg	break;
31582c393a42Smrg    case FcElementConfig:
31592c393a42Smrg	break;
31602c393a42Smrg    case FcElementMatch:
31612c393a42Smrg	FcParseMatch (parse);
31622c393a42Smrg	break;
31632c393a42Smrg    case FcElementAlias:
31642c393a42Smrg	FcParseAlias (parse);
31652c393a42Smrg	break;
3166a32e9e42Smrg    case FcElementDescription:
3167a32e9e42Smrg	FcParseDescription (parse);
31682c393a42Smrg	break;
3169a4e54154Smrg    case FcElementRemapDir:
3170a4e54154Smrg	FcParseRemapDir (parse);
3171a4e54154Smrg	break;
3172a4e54154Smrg    case FcElementResetDirs:
3173a4e54154Smrg	FcParseResetDirs (parse);
3174a4e54154Smrg	break;
3175a32e9e42Smrg
31762c393a42Smrg    case FcElementRescan:
31772c393a42Smrg	FcParseRescan (parse);
31782c393a42Smrg	break;
31792c393a42Smrg
31802c393a42Smrg    case FcElementPrefer:
31812c393a42Smrg	FcParseFamilies (parse, FcVStackPrefer);
31822c393a42Smrg	break;
31832c393a42Smrg    case FcElementAccept:
31842c393a42Smrg	FcParseFamilies (parse, FcVStackAccept);
31852c393a42Smrg	break;
31862c393a42Smrg    case FcElementDefault:
31872c393a42Smrg	FcParseFamilies (parse, FcVStackDefault);
31882c393a42Smrg	break;
31892c393a42Smrg    case FcElementFamily:
31902c393a42Smrg	FcParseFamily (parse);
31912c393a42Smrg	break;
31922c393a42Smrg
31932c393a42Smrg    case FcElementTest:
31942c393a42Smrg	FcParseTest (parse);
31952c393a42Smrg	break;
31962c393a42Smrg    case FcElementEdit:
31972c393a42Smrg	FcParseEdit (parse);
31982c393a42Smrg	break;
31992c393a42Smrg
32002c393a42Smrg    case FcElementInt:
32012c393a42Smrg	FcParseInt (parse);
32022c393a42Smrg	break;
32032c393a42Smrg    case FcElementDouble:
32042c393a42Smrg	FcParseDouble (parse);
32052c393a42Smrg	break;
32062c393a42Smrg    case FcElementString:
32072c393a42Smrg	FcParseString (parse, FcVStackString);
32082c393a42Smrg	break;
32092c393a42Smrg    case FcElementMatrix:
32102c393a42Smrg	FcParseMatrix (parse);
32112c393a42Smrg	break;
3212ca08ab68Smrg    case FcElementRange:
3213ca08ab68Smrg	FcParseRange (parse);
3214ca08ab68Smrg	break;
32152c393a42Smrg    case FcElementBool:
32162c393a42Smrg	FcParseBool (parse);
32172c393a42Smrg	break;
3218ca08ab68Smrg    case FcElementCharSet:
3219ca08ab68Smrg	FcParseCharSet (parse);
3220ca08ab68Smrg	break;
3221ca08ab68Smrg    case FcElementLangSet:
3222ca08ab68Smrg	FcParseLangSet (parse);
32232c393a42Smrg	break;
32242c393a42Smrg    case FcElementSelectfont:
32252c393a42Smrg	break;
32262c393a42Smrg    case FcElementAcceptfont:
32272c393a42Smrg    case FcElementRejectfont:
32282c393a42Smrg	FcParseAcceptRejectFont (parse, parse->pstack->element);
32292c393a42Smrg	break;
32302c393a42Smrg    case FcElementGlob:
32312c393a42Smrg	FcParseString (parse, FcVStackGlob);
32322c393a42Smrg	break;
32332c393a42Smrg    case FcElementPattern:
32342c393a42Smrg	FcParsePattern (parse);
32352c393a42Smrg	break;
32362c393a42Smrg    case FcElementPatelt:
32372c393a42Smrg	FcParsePatelt (parse);
32382c393a42Smrg	break;
32392c393a42Smrg    case FcElementName:
3240c9710b42Smrg	FcParseName (parse);
32412c393a42Smrg	break;
32422c393a42Smrg    case FcElementConst:
32432c393a42Smrg	FcParseString (parse, FcVStackConstant);
32442c393a42Smrg	break;
32452c393a42Smrg    case FcElementOr:
32462c393a42Smrg	FcParseBinary (parse, FcOpOr);
32472c393a42Smrg	break;
32482c393a42Smrg    case FcElementAnd:
32492c393a42Smrg	FcParseBinary (parse, FcOpAnd);
32502c393a42Smrg	break;
32512c393a42Smrg    case FcElementEq:
32522c393a42Smrg	FcParseBinary (parse, FcOpEqual);
32532c393a42Smrg	break;
32542c393a42Smrg    case FcElementNotEq:
32552c393a42Smrg	FcParseBinary (parse, FcOpNotEqual);
32562c393a42Smrg	break;
32572c393a42Smrg    case FcElementLess:
32582c393a42Smrg	FcParseBinary (parse, FcOpLess);
32592c393a42Smrg	break;
32602c393a42Smrg    case FcElementLessEq:
32612c393a42Smrg	FcParseBinary (parse, FcOpLessEqual);
32622c393a42Smrg	break;
32632c393a42Smrg    case FcElementMore:
32642c393a42Smrg	FcParseBinary (parse, FcOpMore);
32652c393a42Smrg	break;
32662c393a42Smrg    case FcElementMoreEq:
32672c393a42Smrg	FcParseBinary (parse, FcOpMoreEqual);
32682c393a42Smrg	break;
32692c393a42Smrg    case FcElementContains:
32702c393a42Smrg	FcParseBinary (parse, FcOpContains);
32712c393a42Smrg	break;
32722c393a42Smrg    case FcElementNotContains:
32732c393a42Smrg	FcParseBinary (parse, FcOpNotContains);
32742c393a42Smrg	break;
32752c393a42Smrg    case FcElementPlus:
32762c393a42Smrg	FcParseBinary (parse, FcOpPlus);
32772c393a42Smrg	break;
32782c393a42Smrg    case FcElementMinus:
32792c393a42Smrg	FcParseBinary (parse, FcOpMinus);
32802c393a42Smrg	break;
32812c393a42Smrg    case FcElementTimes:
32822c393a42Smrg	FcParseBinary (parse, FcOpTimes);
32832c393a42Smrg	break;
32842c393a42Smrg    case FcElementDivide:
32852c393a42Smrg	FcParseBinary (parse, FcOpDivide);
32862c393a42Smrg	break;
32872c393a42Smrg    case FcElementNot:
32882c393a42Smrg	FcParseUnary (parse, FcOpNot);
32892c393a42Smrg	break;
32902c393a42Smrg    case FcElementIf:
32912c393a42Smrg	FcParseBinary (parse, FcOpQuest);
32922c393a42Smrg	break;
32932c393a42Smrg    case FcElementFloor:
32942c393a42Smrg	FcParseUnary (parse, FcOpFloor);
32952c393a42Smrg	break;
32962c393a42Smrg    case FcElementCeil:
32972c393a42Smrg	FcParseUnary (parse, FcOpCeil);
32982c393a42Smrg	break;
32992c393a42Smrg    case FcElementRound:
33002c393a42Smrg	FcParseUnary (parse, FcOpRound);
33012c393a42Smrg	break;
33022c393a42Smrg    case FcElementTrunc:
33032c393a42Smrg	FcParseUnary (parse, FcOpTrunc);
33042c393a42Smrg	break;
33052c393a42Smrg    case FcElementUnknown:
33062c393a42Smrg	break;
33072c393a42Smrg    }
33082c393a42Smrg    (void) FcPStackPop (parse);
33092c393a42Smrg}
33102c393a42Smrg
33112c393a42Smrgstatic void
33122c393a42SmrgFcCharacterData (void *userData, const XML_Char *s, int len)
33132c393a42Smrg{
33142c393a42Smrg    FcConfigParse   *parse = userData;
3315ca08ab68Smrg
33162c393a42Smrg    if (!parse->pstack)
33172c393a42Smrg	return;
33182c393a42Smrg    if (!FcStrBufData (&parse->pstack->str, (FcChar8 *) s, len))
33192c393a42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
33202c393a42Smrg}
33212c393a42Smrg
33222c393a42Smrgstatic void
33232c393a42SmrgFcStartDoctypeDecl (void	    *userData,
33242c393a42Smrg		    const XML_Char  *doctypeName,
3325c9710b42Smrg		    const XML_Char  *sysid FC_UNUSED,
3326c9710b42Smrg		    const XML_Char  *pubid FC_UNUSED,
3327c9710b42Smrg		    int		    has_internal_subset FC_UNUSED)
33282c393a42Smrg{
33292c393a42Smrg    FcConfigParse   *parse = userData;
33302c393a42Smrg
33312c393a42Smrg    if (strcmp ((char *) doctypeName, "fontconfig") != 0)
33322c393a42Smrg	FcConfigMessage (parse, FcSevereError, "invalid doctype \"%s\"", doctypeName);
33332c393a42Smrg}
33342c393a42Smrg
33352c393a42Smrg#ifdef ENABLE_LIBXML2
33362c393a42Smrg
33372c393a42Smrgstatic void
33382c393a42SmrgFcInternalSubsetDecl (void            *userData,
33392c393a42Smrg		      const XML_Char  *doctypeName,
33402c393a42Smrg		      const XML_Char  *sysid,
33412c393a42Smrg		      const XML_Char  *pubid)
33422c393a42Smrg{
33432c393a42Smrg    FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 1);
33442c393a42Smrg}
33452c393a42Smrg
33462c393a42Smrgstatic void
33472c393a42SmrgFcExternalSubsetDecl (void            *userData,
33482c393a42Smrg		      const XML_Char  *doctypeName,
33492c393a42Smrg		      const XML_Char  *sysid,
33502c393a42Smrg		      const XML_Char  *pubid)
33512c393a42Smrg{
33522c393a42Smrg    FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 0);
33532c393a42Smrg}
33542c393a42Smrg
33552c393a42Smrg#else /* ENABLE_LIBXML2 */
33562c393a42Smrg
33572c393a42Smrgstatic void
3358c9710b42SmrgFcEndDoctypeDecl (void *userData FC_UNUSED)
33592c393a42Smrg{
33602c393a42Smrg}
33612c393a42Smrg
33622c393a42Smrg#endif /* ENABLE_LIBXML2 */
33632c393a42Smrg
33642c393a42Smrgstatic int
33652c393a42SmrgFcSortCmpStr (const void *a, const void *b)
33662c393a42Smrg{
33672c393a42Smrg    const FcChar8    *as = *((FcChar8 **) a);
33682c393a42Smrg    const FcChar8    *bs = *((FcChar8 **) b);
33692c393a42Smrg    return FcStrCmp (as, bs);
33702c393a42Smrg}
33712c393a42Smrg
33722c393a42Smrgstatic FcBool
33732c393a42SmrgFcConfigParseAndLoadDir (FcConfig	*config,
33742c393a42Smrg			 const FcChar8	*name,
33752c393a42Smrg			 const FcChar8	*dir,
3376a32e9e42Smrg			 FcBool		complain,
3377a32e9e42Smrg			 FcBool		load)
33782c393a42Smrg{
33792c393a42Smrg    DIR		    *d;
33802c393a42Smrg    struct dirent   *e;
33812c393a42Smrg    FcBool	    ret = FcTrue;
33822c393a42Smrg    FcChar8	    *file;
33832c393a42Smrg    FcChar8	    *base;
33842c393a42Smrg    FcStrSet	    *files;
33852c393a42Smrg
33862c393a42Smrg    d = opendir ((char *) dir);
33872c393a42Smrg    if (!d)
33882c393a42Smrg    {
33892c393a42Smrg	if (complain)
33902c393a42Smrg	    FcConfigMessage (0, FcSevereError, "Cannot open config dir \"%s\"",
33912c393a42Smrg			     name);
33922c393a42Smrg	ret = FcFalse;
33932c393a42Smrg	goto bail0;
33942c393a42Smrg    }
33952c393a42Smrg    /* freed below */
33962c393a42Smrg    file = (FcChar8 *) malloc (strlen ((char *) dir) + 1 + FC_MAX_FILE_LEN + 1);
33972c393a42Smrg    if (!file)
33982c393a42Smrg    {
33992c393a42Smrg	ret = FcFalse;
34002c393a42Smrg	goto bail1;
34012c393a42Smrg    }
3402ca08ab68Smrg
34032c393a42Smrg    strcpy ((char *) file, (char *) dir);
34042c393a42Smrg    strcat ((char *) file, "/");
34052c393a42Smrg    base = file + strlen ((char *) file);
3406ca08ab68Smrg
3407953daebaSmrg    files = FcStrSetCreateEx (FCSS_GROW_BY_64);
34082c393a42Smrg    if (!files)
34092c393a42Smrg    {
34102c393a42Smrg	ret = FcFalse;
34112c393a42Smrg	goto bail2;
34122c393a42Smrg    }
3413ca08ab68Smrg
34142c393a42Smrg    if (FcDebug () & FC_DBG_CONFIG)
34152c393a42Smrg	printf ("\tScanning config dir %s\n", dir);
3416a32e9e42Smrg
3417a32e9e42Smrg    if (load)
3418a32e9e42Smrg	FcConfigAddConfigDir (config, dir);
3419a32e9e42Smrg
34202c393a42Smrg    while (ret && (e = readdir (d)))
34212c393a42Smrg    {
34222c393a42Smrg	int d_len;
34232c393a42Smrg#define TAIL	    ".conf"
34242c393a42Smrg#define TAIL_LEN    5
34252c393a42Smrg	/*
34262c393a42Smrg	 * Add all files of the form [0-9]*.conf
34272c393a42Smrg	 */
3428a4e54154Smrg	d_len = strlen (e->d_name);
34292c393a42Smrg	if ('0' <= e->d_name[0] && e->d_name[0] <= '9' &&
34302c393a42Smrg	    d_len > TAIL_LEN &&
34312c393a42Smrg	    strcmp (e->d_name + d_len - TAIL_LEN, TAIL) == 0)
34322c393a42Smrg	{
34332c393a42Smrg	    strcpy ((char *) base, (char *) e->d_name);
34342c393a42Smrg	    if (!FcStrSetAdd (files, file))
34352c393a42Smrg	    {
34362c393a42Smrg		ret = FcFalse;
34372c393a42Smrg		goto bail3;
34382c393a42Smrg	    }
34392c393a42Smrg	}
34402c393a42Smrg    }
34412c393a42Smrg    if (ret)
34422c393a42Smrg    {
34432c393a42Smrg	int i;
3444ca08ab68Smrg	qsort (files->strs, files->num, sizeof (FcChar8 *),
34452c393a42Smrg	       (int (*)(const void *, const void *)) FcSortCmpStr);
34462c393a42Smrg	for (i = 0; ret && i < files->num; i++)
3447a32e9e42Smrg	    ret = _FcConfigParse (config, files->strs[i], complain, load);
34482c393a42Smrg    }
34492c393a42Smrgbail3:
34502c393a42Smrg    FcStrSetDestroy (files);
34512c393a42Smrgbail2:
34522c393a42Smrg    free (file);
34532c393a42Smrgbail1:
34542c393a42Smrg    closedir (d);
34552c393a42Smrgbail0:
34562c393a42Smrg    return ret || !complain;
34572c393a42Smrg}
34582c393a42Smrg
3459a32e9e42Smrgstatic FcBool
3460a32e9e42SmrgFcConfigParseAndLoadFromMemoryInternal (FcConfig       *config,
3461a32e9e42Smrg					const FcChar8  *filename,
3462a32e9e42Smrg					const FcChar8  *buffer,
3463a32e9e42Smrg					FcBool         complain,
3464a32e9e42Smrg					FcBool         load)
34652c393a42Smrg{
34662c393a42Smrg
34672c393a42Smrg    XML_Parser	    p;
3468a32e9e42Smrg    size_t	    len;
34692c393a42Smrg    FcConfigParse   parse;
34702c393a42Smrg    FcBool	    error = FcTrue;
3471a32e9e42Smrg    FcMatchKind	    k;
3472a32e9e42Smrg    FcPtrListIter   liter;
3473ca08ab68Smrg
34742c393a42Smrg#ifdef ENABLE_LIBXML2
34752c393a42Smrg    xmlSAXHandler   sax;
34762c393a42Smrg#else
3477a32e9e42Smrg    void            *buf;
3478a32e9e42Smrg    const FcChar8   *s;
3479a32e9e42Smrg    size_t	    buflen;
34802c393a42Smrg#endif
3481ca08ab68Smrg
3482a32e9e42Smrg    if (!buffer)
3483a32e9e42Smrg	return FcFalse;
3484a32e9e42Smrg    len = strlen ((const char *) buffer);
34852c393a42Smrg    if (FcDebug () & FC_DBG_CONFIG)
3486a32e9e42Smrg	printf ("\t%s config file from %s\n", load ? "Loading" : "Scanning", filename);
3487ca08ab68Smrg
34882c393a42Smrg#ifdef ENABLE_LIBXML2
34892c393a42Smrg    memset(&sax, 0, sizeof(sax));
34902c393a42Smrg
34912c393a42Smrg    sax.internalSubset = FcInternalSubsetDecl;
34922c393a42Smrg    sax.externalSubset = FcExternalSubsetDecl;
34932c393a42Smrg    sax.startElement = FcStartElement;
34942c393a42Smrg    sax.endElement = FcEndElement;
34952c393a42Smrg    sax.characters = FcCharacterData;
34962c393a42Smrg
34972c393a42Smrg    p = xmlCreatePushParserCtxt (&sax, &parse, NULL, 0, (const char *) filename);
34982c393a42Smrg#else
34992c393a42Smrg    p = XML_ParserCreate ("UTF-8");
35002c393a42Smrg#endif
35012c393a42Smrg
35022c393a42Smrg    if (!p)
35032c393a42Smrg	goto bail1;
35042c393a42Smrg
3505a32e9e42Smrg    if (!FcConfigParseInit (&parse, filename, config, p, load))
35062c393a42Smrg	goto bail2;
35072c393a42Smrg
35082c393a42Smrg#ifndef ENABLE_LIBXML2
35092c393a42Smrg
35102c393a42Smrg    XML_SetUserData (p, &parse);
3511ca08ab68Smrg
35122c393a42Smrg    XML_SetDoctypeDeclHandler (p, FcStartDoctypeDecl, FcEndDoctypeDecl);
35132c393a42Smrg    XML_SetElementHandler (p, FcStartElement, FcEndElement);
35142c393a42Smrg    XML_SetCharacterDataHandler (p, FcCharacterData);
35152c393a42Smrg
35162c393a42Smrg#endif /* ENABLE_LIBXML2 */
35172c393a42Smrg
35182c393a42Smrg#ifndef ENABLE_LIBXML2
3519a32e9e42Smrg    s = buffer;
3520a32e9e42Smrg    do {
35212c393a42Smrg	buf = XML_GetBuffer (p, BUFSIZ);
35222c393a42Smrg	if (!buf)
35232c393a42Smrg	{
35242c393a42Smrg	    FcConfigMessage (&parse, FcSevereError, "cannot get parse buffer");
35252c393a42Smrg	    goto bail3;
35262c393a42Smrg	}
3527a32e9e42Smrg	if (len > BUFSIZ)
35282c393a42Smrg	{
3529a32e9e42Smrg	    buflen = BUFSIZ;
3530a32e9e42Smrg	    len -= BUFSIZ;
35312c393a42Smrg	}
3532a32e9e42Smrg	else
3533a32e9e42Smrg	{
3534a32e9e42Smrg	    buflen = len;
3535a32e9e42Smrg	    len = 0;
3536a32e9e42Smrg	}
3537a32e9e42Smrg	memcpy (buf, s, buflen);
3538a32e9e42Smrg	s = s + buflen;
3539a32e9e42Smrg#endif
35402c393a42Smrg
35412c393a42Smrg#ifdef ENABLE_LIBXML2
3542a32e9e42Smrg	if (xmlParseChunk (p, (const char *)buffer, len, len == 0))
35432c393a42Smrg#else
3544a32e9e42Smrg	if (!XML_ParseBuffer (p, buflen, buflen == 0))
35452c393a42Smrg#endif
35462c393a42Smrg	{
3547ca08ab68Smrg	    FcConfigMessage (&parse, FcSevereError, "%s",
35482c393a42Smrg			   XML_ErrorString (XML_GetErrorCode (p)));
35492c393a42Smrg	    goto bail3;
35502c393a42Smrg	}
3551a32e9e42Smrg#ifndef ENABLE_LIBXML2
3552a32e9e42Smrg    } while (buflen != 0);
3553a32e9e42Smrg#endif
35542c393a42Smrg    error = parse.error;
3555a32e9e42Smrg    if (load)
3556a32e9e42Smrg    {
3557a32e9e42Smrg	for (k = FcMatchKindBegin; k < FcMatchKindEnd; k++)
3558a32e9e42Smrg	{
3559a32e9e42Smrg	    FcPtrListIter iter;
3560a32e9e42Smrg
3561a32e9e42Smrg	    FcPtrListIterInit (parse.ruleset->subst[k], &iter);
3562a32e9e42Smrg	    if (FcPtrListIterIsValid (parse.ruleset->subst[k], &iter))
3563a32e9e42Smrg	    {
3564a32e9e42Smrg		FcPtrListIterInitAtLast (parse.config->subst[k], &iter);
3565a32e9e42Smrg		FcRuleSetReference (parse.ruleset);
3566a32e9e42Smrg		FcPtrListIterAdd (parse.config->subst[k], &iter, parse.ruleset);
3567a32e9e42Smrg	    }
3568a32e9e42Smrg	}
3569a32e9e42Smrg    }
3570a32e9e42Smrg    FcPtrListIterInitAtLast (parse.config->rulesetList, &liter);
3571a32e9e42Smrg    FcRuleSetReference (parse.ruleset);
3572a32e9e42Smrg    FcPtrListIterAdd (parse.config->rulesetList, &liter, parse.ruleset);
35732c393a42Smrgbail3:
35742c393a42Smrg    FcConfigCleanup (&parse);
35752c393a42Smrgbail2:
35762c393a42Smrg    XML_ParserFree (p);
35772c393a42Smrgbail1:
3578a32e9e42Smrg    if (error && complain)
3579a32e9e42Smrg    {
3580a32e9e42Smrg	FcConfigMessage (0, FcSevereError, "Cannot %s config file from %s", load ? "load" : "scan", filename);
3581a32e9e42Smrg	return FcFalse;
3582a32e9e42Smrg    }
3583a32e9e42Smrg    if (FcDebug () & FC_DBG_CONFIG)
3584a32e9e42Smrg	printf ("\t%s config file from %s done\n", load ? "Loading" : "Scanning", filename);
3585a32e9e42Smrg    return FcTrue;
3586a32e9e42Smrg}
3587a32e9e42Smrg
3588a32e9e42Smrgstatic FcBool
3589a32e9e42Smrg_FcConfigParse (FcConfig	*config,
3590a32e9e42Smrg		const FcChar8	*name,
3591a32e9e42Smrg		FcBool		complain,
3592a32e9e42Smrg		FcBool		load)
3593a32e9e42Smrg{
3594a32e9e42Smrg    FcChar8	    *filename = NULL, *realfilename = NULL;
3595a32e9e42Smrg    int		    fd;
3596a32e9e42Smrg    int		    len;
3597a32e9e42Smrg    FcStrBuf	    sbuf;
3598a32e9e42Smrg    char            buf[BUFSIZ];
3599a4e54154Smrg    FcBool	    ret = FcFalse, complain_again = complain;
3600a4e54154Smrg    FcStrBuf	    reason;
3601a32e9e42Smrg
3602a4e54154Smrg    FcStrBufInit (&reason, NULL, 0);
3603a32e9e42Smrg#ifdef _WIN32
3604a4e54154Smrg    _ensureWin32GettersReady();
3605a32e9e42Smrg#endif
3606a32e9e42Smrg
3607a4e54154Smrg    filename = FcConfigGetFilename (config, name);
3608a32e9e42Smrg    if (!filename)
3609a4e54154Smrg    {
3610a4e54154Smrg	FcStrBufString (&reason, (FcChar8 *)"No such file: ");
3611a4e54154Smrg	FcStrBufString (&reason, name ? name : (FcChar8 *)"(null)");
3612a32e9e42Smrg	goto bail0;
3613a4e54154Smrg    }
3614a32e9e42Smrg    realfilename = FcConfigRealFilename (config, name);
3615a32e9e42Smrg    if (!realfilename)
3616a4e54154Smrg    {
3617a4e54154Smrg	FcStrBufString (&reason, (FcChar8 *)"No such realfile: ");
3618a4e54154Smrg	FcStrBufString (&reason, name ? name : (FcChar8 *)"(null)");
3619a32e9e42Smrg	goto bail0;
3620a4e54154Smrg    }
3621a32e9e42Smrg    if (FcStrSetMember (config->availConfigFiles, realfilename))
3622a32e9e42Smrg    {
3623a32e9e42Smrg        FcStrFree (filename);
3624a32e9e42Smrg	FcStrFree (realfilename);
3625a32e9e42Smrg        return FcTrue;
3626a32e9e42Smrg    }
3627a32e9e42Smrg
3628a32e9e42Smrg    if (load)
3629a32e9e42Smrg    {
3630a32e9e42Smrg	if (!FcStrSetAdd (config->configFiles, filename))
3631a32e9e42Smrg	    goto bail0;
3632a32e9e42Smrg    }
3633a32e9e42Smrg    if (!FcStrSetAdd (config->availConfigFiles, realfilename))
3634a32e9e42Smrg	goto bail0;
3635a32e9e42Smrg
3636a32e9e42Smrg    if (FcFileIsDir (realfilename))
3637a32e9e42Smrg    {
3638a32e9e42Smrg	ret = FcConfigParseAndLoadDir (config, name, realfilename, complain, load);
3639a32e9e42Smrg	FcStrFree (filename);
3640a32e9e42Smrg	FcStrFree (realfilename);
3641a32e9e42Smrg	return ret;
3642a32e9e42Smrg    }
3643a32e9e42Smrg
3644a32e9e42Smrg    FcStrBufInit (&sbuf, NULL, 0);
3645a32e9e42Smrg
3646a32e9e42Smrg    fd = FcOpen ((char *) realfilename, O_RDONLY);
3647a32e9e42Smrg    if (fd == -1)
3648a4e54154Smrg    {
3649a4e54154Smrg	FcStrBufString (&reason, (FcChar8 *)"Unable to open ");
3650a4e54154Smrg	FcStrBufString (&reason, realfilename);
3651a32e9e42Smrg	goto bail1;
3652a4e54154Smrg    }
3653a32e9e42Smrg
3654a32e9e42Smrg    do {
3655a32e9e42Smrg	len = read (fd, buf, BUFSIZ);
3656a32e9e42Smrg	if (len < 0)
3657a32e9e42Smrg	{
3658a32e9e42Smrg	    int errno_ = errno;
3659a32e9e42Smrg	    char ebuf[BUFSIZ+1];
3660a32e9e42Smrg
3661a32e9e42Smrg#if HAVE_STRERROR_R
3662a32e9e42Smrg	    strerror_r (errno_, ebuf, BUFSIZ);
3663a32e9e42Smrg#elif HAVE_STRERROR
3664a32e9e42Smrg	    char *tmp = strerror (errno_);
3665a32e9e42Smrg	    size_t len = strlen (tmp);
3666a4e54154Smrg	    memcpy (ebuf, tmp, FC_MIN (BUFSIZ, len));
3667a32e9e42Smrg	    ebuf[FC_MIN (BUFSIZ, len)] = 0;
3668a32e9e42Smrg#else
3669a32e9e42Smrg	    ebuf[0] = 0;
3670a32e9e42Smrg#endif
3671a32e9e42Smrg	    FcConfigMessage (0, FcSevereError, "failed reading config file: %s: %s (errno %d)", realfilename, ebuf, errno_);
3672a32e9e42Smrg	    close (fd);
3673a32e9e42Smrg	    goto bail1;
3674a32e9e42Smrg	}
3675a32e9e42Smrg	FcStrBufData (&sbuf, (const FcChar8 *)buf, len);
3676a32e9e42Smrg    } while (len != 0);
36772c393a42Smrg    close (fd);
3678a32e9e42Smrg
3679a32e9e42Smrg    ret = FcConfigParseAndLoadFromMemoryInternal (config, filename, FcStrBufDoneStatic (&sbuf), complain, load);
3680a4e54154Smrg    complain_again = FcFalse; /* no need to reclaim here */
3681a32e9e42Smrgbail1:
3682a32e9e42Smrg    FcStrBufDestroy (&sbuf);
36832c393a42Smrgbail0:
3684a32e9e42Smrg    if (filename)
3685a32e9e42Smrg	FcStrFree (filename);
3686a32e9e42Smrg    if (realfilename)
3687a32e9e42Smrg	FcStrFree (realfilename);
3688a4e54154Smrg    if (!complain)
3689a4e54154Smrg	return FcTrue;
3690a4e54154Smrg    if (!ret && complain_again)
36912c393a42Smrg    {
36922c393a42Smrg	if (name)
3693a4e54154Smrg	    FcConfigMessage (0, FcSevereError, "Cannot %s config file \"%s\": %s", load ? "load" : "scan", name, FcStrBufDoneStatic (&reason));
36942c393a42Smrg	else
3695a4e54154Smrg	    FcConfigMessage (0, FcSevereError, "Cannot %s default config file: %s", load ? "load" : "scan", FcStrBufDoneStatic (&reason));
3696a4e54154Smrg	FcStrBufDestroy (&reason);
36972c393a42Smrg	return FcFalse;
36982c393a42Smrg    }
3699a4e54154Smrg    FcStrBufDestroy (&reason);
3700a4e54154Smrg    return ret;
37012c393a42Smrg}
3702a32e9e42Smrg
3703a32e9e42SmrgFcBool
3704a32e9e42SmrgFcConfigParseOnly (FcConfig		*config,
3705a32e9e42Smrg		   const FcChar8	*name,
3706a32e9e42Smrg		   FcBool		complain)
3707a32e9e42Smrg{
3708a32e9e42Smrg    return _FcConfigParse (config, name, complain, FcFalse);
3709a32e9e42Smrg}
3710a32e9e42Smrg
3711a32e9e42SmrgFcBool
3712a32e9e42SmrgFcConfigParseAndLoad (FcConfig	    *config,
3713a32e9e42Smrg		      const FcChar8 *name,
3714a32e9e42Smrg		      FcBool	    complain)
3715a32e9e42Smrg{
3716a32e9e42Smrg    return _FcConfigParse (config, name, complain, FcTrue);
3717a32e9e42Smrg}
3718a32e9e42Smrg
3719a32e9e42SmrgFcBool
3720a32e9e42SmrgFcConfigParseAndLoadFromMemory (FcConfig       *config,
3721a32e9e42Smrg				const FcChar8  *buffer,
3722a32e9e42Smrg				FcBool         complain)
3723a32e9e42Smrg{
3724a32e9e42Smrg    return FcConfigParseAndLoadFromMemoryInternal (config, (const FcChar8 *)"memory", buffer, complain, FcTrue);
3725a32e9e42Smrg}
3726a32e9e42Smrg
3727a4e54154Smrg#ifdef _WIN32
3728a4e54154Smrgstatic void
3729a4e54154Smrg_ensureWin32GettersReady()
3730a4e54154Smrg{
3731a4e54154Smrg    if (!pGetSystemWindowsDirectory)
3732a4e54154Smrg    {
3733a4e54154Smrg        HMODULE hk32 = GetModuleHandleA("kernel32.dll");
3734a4e54154Smrg        if (!(pGetSystemWindowsDirectory = (pfnGetSystemWindowsDirectory)GetProcAddress(hk32, "GetSystemWindowsDirectoryA")))
3735a4e54154Smrg            pGetSystemWindowsDirectory = (pfnGetSystemWindowsDirectory)GetWindowsDirectory;
3736a4e54154Smrg    }
3737a4e54154Smrg    if (!pSHGetFolderPathA)
3738a4e54154Smrg    {
3739a4e54154Smrg        HMODULE hSh = LoadLibraryA("shfolder.dll");
3740a4e54154Smrg        /* the check is done later, because there is no provided fallback */
3741a4e54154Smrg        if (hSh)
3742a4e54154Smrg            pSHGetFolderPathA = (pfnSHGetFolderPathA)GetProcAddress(hSh, "SHGetFolderPathA");
3743a4e54154Smrg    }
3744a4e54154Smrg}
3745a4e54154Smrg#endif // _WIN32
3746a4e54154Smrg
37472c393a42Smrg#define __fcxml__
37482c393a42Smrg#include "fcaliastail.h"
37492c393a42Smrg#undef __fcxml__
3750