fcxml.c revision b09479dc
12c393a42Smrg/*
2a6844aabSmrg * fontconfig/src/fcxml.c
32c393a42Smrg *
42c393a42Smrg * Copyright © 2002 Keith Packard
52c393a42Smrg *
62c393a42Smrg * Permission to use, copy, modify, distribute, and sell this software and its
72c393a42Smrg * documentation for any purpose is hereby granted without fee, provided that
82c393a42Smrg * the above copyright notice appear in all copies and that both that
92c393a42Smrg * copyright notice and this permission notice appear in supporting
10ca08ab68Smrg * documentation, and that the name of the author(s) not be used in
112c393a42Smrg * advertising or publicity pertaining to distribution of the software without
12ca08ab68Smrg * specific, written prior permission.  The authors make no
132c393a42Smrg * representations about the suitability of this software for any purpose.  It
142c393a42Smrg * is provided "as is" without express or implied warranty.
152c393a42Smrg *
16a6844aabSmrg * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
172c393a42Smrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18a6844aabSmrg * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR
192c393a42Smrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
202c393a42Smrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
212c393a42Smrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
222c393a42Smrg * PERFORMANCE OF THIS SOFTWARE.
232c393a42Smrg */
242c393a42Smrg
252c393a42Smrg#include "fcint.h"
262c393a42Smrg#include <fcntl.h>
272c393a42Smrg#include <stdarg.h>
282c393a42Smrg#include <dirent.h>
292c393a42Smrg
302c393a42Smrg#ifdef ENABLE_LIBXML2
312c393a42Smrg
322c393a42Smrg#include <libxml/parser.h>
332c393a42Smrg
342c393a42Smrg#define XML_Char			xmlChar
352c393a42Smrg#define XML_Parser			xmlParserCtxtPtr
362c393a42Smrg#define XML_ParserFree			xmlFreeParserCtxt
372c393a42Smrg#define XML_GetCurrentLineNumber	xmlSAX2GetLineNumber
382c393a42Smrg#define XML_GetErrorCode		xmlCtxtGetLastError
392c393a42Smrg#define XML_ErrorString(Error)		(Error)->message
402c393a42Smrg
412c393a42Smrg#else /* ENABLE_LIBXML2 */
422c393a42Smrg
432c393a42Smrg#ifndef HAVE_XMLPARSE_H
442c393a42Smrg#define HAVE_XMLPARSE_H 0
452c393a42Smrg#endif
462c393a42Smrg
472c393a42Smrg#if HAVE_XMLPARSE_H
482c393a42Smrg#include <xmlparse.h>
492c393a42Smrg#else
502c393a42Smrg#include <expat.h>
512c393a42Smrg#endif
522c393a42Smrg
532c393a42Smrg#endif /* ENABLE_LIBXML2 */
542c393a42Smrg
552c393a42Smrg#ifdef _WIN32
56a6844aabSmrg#include <mbstring.h>
572c393a42Smrg#endif
582c393a42Smrg
59a6844aabSmrgstatic void
60a6844aabSmrgFcExprDestroy (FcExpr *e);
612c393a42Smrg
622c393a42Smrgvoid
632c393a42SmrgFcTestDestroy (FcTest *test)
642c393a42Smrg{
652c393a42Smrg    FcExprDestroy (test->expr);
662c393a42Smrg    free (test);
672c393a42Smrg}
682c393a42Smrg
696fc018e4Smrgvoid
706fc018e4SmrgFcRuleDestroy (FcRule *rule)
716fc018e4Smrg{
726fc018e4Smrg    FcRule *n = rule->next;
736fc018e4Smrg
746fc018e4Smrg    switch (rule->type) {
756fc018e4Smrg    case FcRuleTest:
766fc018e4Smrg	FcTestDestroy (rule->u.test);
776fc018e4Smrg	break;
786fc018e4Smrg    case FcRuleEdit:
796fc018e4Smrg	FcEditDestroy (rule->u.edit);
806fc018e4Smrg	break;
816fc018e4Smrg    default:
826fc018e4Smrg	break;
836fc018e4Smrg    }
846fc018e4Smrg    free (rule);
856fc018e4Smrg    if (n)
866fc018e4Smrg	FcRuleDestroy (n);
876fc018e4Smrg}
886fc018e4Smrg
89a6844aabSmrgstatic FcExpr *
90a6844aabSmrgFcExprCreateInteger (FcConfig *config, int i)
912c393a42Smrg{
92a6844aabSmrg    FcExpr *e = FcConfigAllocExpr (config);
932c393a42Smrg    if (e)
942c393a42Smrg    {
952c393a42Smrg	e->op = FcOpInteger;
962c393a42Smrg	e->u.ival = i;
972c393a42Smrg    }
982c393a42Smrg    return e;
992c393a42Smrg}
1002c393a42Smrg
101a6844aabSmrgstatic FcExpr *
102a6844aabSmrgFcExprCreateDouble (FcConfig *config, double d)
1032c393a42Smrg{
104a6844aabSmrg    FcExpr *e = FcConfigAllocExpr (config);
1052c393a42Smrg    if (e)
1062c393a42Smrg    {
1072c393a42Smrg	e->op = FcOpDouble;
1082c393a42Smrg	e->u.dval = d;
1092c393a42Smrg    }
1102c393a42Smrg    return e;
1112c393a42Smrg}
1122c393a42Smrg
113a6844aabSmrgstatic FcExpr *
114a6844aabSmrgFcExprCreateString (FcConfig *config, const FcChar8 *s)
1152c393a42Smrg{
116a6844aabSmrg    FcExpr *e = FcConfigAllocExpr (config);
1172c393a42Smrg    if (e)
1182c393a42Smrg    {
1192c393a42Smrg	e->op = FcOpString;
120c9710b42Smrg	e->u.sval = FcStrdup (s);
1212c393a42Smrg    }
1222c393a42Smrg    return e;
1232c393a42Smrg}
1242c393a42Smrg
125c9710b42Smrgstatic FcExprMatrix *
126c9710b42SmrgFcExprMatrixCopyShallow (const FcExprMatrix *matrix)
127c9710b42Smrg{
128c9710b42Smrg  FcExprMatrix *m = malloc (sizeof (FcExprMatrix));
129c9710b42Smrg  if (m)
130c9710b42Smrg  {
131c9710b42Smrg    *m = *matrix;
132c9710b42Smrg  }
133c9710b42Smrg  return m;
134c9710b42Smrg}
135c9710b42Smrg
136c9710b42Smrgstatic void
137c9710b42SmrgFcExprMatrixFreeShallow (FcExprMatrix *m)
138c9710b42Smrg{
139c9710b42Smrg  if (!m)
140c9710b42Smrg    return;
141c9710b42Smrg
142c9710b42Smrg  free (m);
143c9710b42Smrg}
144c9710b42Smrg
145c9710b42Smrgstatic void
146c9710b42SmrgFcExprMatrixFree (FcExprMatrix *m)
147c9710b42Smrg{
148c9710b42Smrg  if (!m)
149c9710b42Smrg    return;
150c9710b42Smrg
151c9710b42Smrg  FcExprDestroy (m->xx);
152c9710b42Smrg  FcExprDestroy (m->xy);
153c9710b42Smrg  FcExprDestroy (m->yx);
154c9710b42Smrg  FcExprDestroy (m->yy);
155c9710b42Smrg
156c9710b42Smrg  free (m);
157c9710b42Smrg}
158c9710b42Smrg
159a6844aabSmrgstatic FcExpr *
160c9710b42SmrgFcExprCreateMatrix (FcConfig *config, const FcExprMatrix *matrix)
1612c393a42Smrg{
162a6844aabSmrg    FcExpr *e = FcConfigAllocExpr (config);
1632c393a42Smrg    if (e)
1642c393a42Smrg    {
1652c393a42Smrg	e->op = FcOpMatrix;
166c9710b42Smrg	e->u.mexpr = FcExprMatrixCopyShallow (matrix);
1672c393a42Smrg    }
1682c393a42Smrg    return e;
1692c393a42Smrg}
1702c393a42Smrg
171a6844aabSmrgstatic FcExpr *
172a6844aabSmrgFcExprCreateBool (FcConfig *config, FcBool b)
1732c393a42Smrg{
174a6844aabSmrg    FcExpr *e = FcConfigAllocExpr (config);
1752c393a42Smrg    if (e)
1762c393a42Smrg    {
1772c393a42Smrg	e->op = FcOpBool;
1782c393a42Smrg	e->u.bval = b;
1792c393a42Smrg    }
1802c393a42Smrg    return e;
1812c393a42Smrg}
1822c393a42Smrg
183ca08ab68Smrgstatic FcExpr *
184ca08ab68SmrgFcExprCreateCharSet (FcConfig *config, FcCharSet *charset)
185ca08ab68Smrg{
186ca08ab68Smrg    FcExpr *e = FcConfigAllocExpr (config);
187ca08ab68Smrg    if (e)
188ca08ab68Smrg    {
189ca08ab68Smrg	e->op = FcOpCharSet;
190ca08ab68Smrg	e->u.cval = FcCharSetCopy (charset);
191ca08ab68Smrg    }
192ca08ab68Smrg    return e;
193ca08ab68Smrg}
194ca08ab68Smrg
195ca08ab68Smrgstatic FcExpr *
196ca08ab68SmrgFcExprCreateLangSet (FcConfig *config, FcLangSet *langset)
197ca08ab68Smrg{
198ca08ab68Smrg    FcExpr *e = FcConfigAllocExpr (config);
199ca08ab68Smrg    if (e)
200ca08ab68Smrg    {
201ca08ab68Smrg	e->op = FcOpLangSet;
202ca08ab68Smrg	e->u.lval = FcLangSetCopy (langset);
203ca08ab68Smrg    }
204ca08ab68Smrg    return e;
205ca08ab68Smrg}
206ca08ab68Smrg
207a6844aabSmrgstatic FcExpr *
208c9710b42SmrgFcExprCreateName (FcConfig *config, FcExprName name)
2092c393a42Smrg{
210a6844aabSmrg    FcExpr *e = FcConfigAllocExpr (config);
2112c393a42Smrg    if (e)
2122c393a42Smrg    {
2132c393a42Smrg	e->op = FcOpField;
214c9710b42Smrg	e->u.name = name;
2152c393a42Smrg    }
2162c393a42Smrg    return e;
2172c393a42Smrg}
2182c393a42Smrg
219a6844aabSmrgstatic FcExpr *
220a6844aabSmrgFcExprCreateConst (FcConfig *config, const FcChar8 *constant)
2212c393a42Smrg{
222a6844aabSmrg    FcExpr *e = FcConfigAllocExpr (config);
2232c393a42Smrg    if (e)
2242c393a42Smrg    {
2252c393a42Smrg	e->op = FcOpConst;
226c9710b42Smrg	e->u.constant = FcStrdup (constant);
2272c393a42Smrg    }
2282c393a42Smrg    return e;
2292c393a42Smrg}
2302c393a42Smrg
231a6844aabSmrgstatic FcExpr *
232a6844aabSmrgFcExprCreateOp (FcConfig *config, FcExpr *left, FcOp op, FcExpr *right)
2332c393a42Smrg{
234a6844aabSmrg    FcExpr *e = FcConfigAllocExpr (config);
2352c393a42Smrg    if (e)
2362c393a42Smrg    {
2372c393a42Smrg	e->op = op;
2382c393a42Smrg	e->u.tree.left = left;
2392c393a42Smrg	e->u.tree.right = right;
2402c393a42Smrg    }
2412c393a42Smrg    return e;
2422c393a42Smrg}
2432c393a42Smrg
244a6844aabSmrgstatic void
2452c393a42SmrgFcExprDestroy (FcExpr *e)
2462c393a42Smrg{
2472c393a42Smrg    if (!e)
2482c393a42Smrg	return;
249ca08ab68Smrg    switch (FC_OP_GET_OP (e->op)) {
2502c393a42Smrg    case FcOpInteger:
2512c393a42Smrg	break;
2522c393a42Smrg    case FcOpDouble:
2532c393a42Smrg	break;
2542c393a42Smrg    case FcOpString:
255c9710b42Smrg	FcFree (e->u.sval);
2562c393a42Smrg	break;
2572c393a42Smrg    case FcOpMatrix:
258c9710b42Smrg	FcExprMatrixFree (e->u.mexpr);
2592c393a42Smrg	break;
260ca08ab68Smrg    case FcOpRange:
261ca08ab68Smrg	break;
2622c393a42Smrg    case FcOpCharSet:
2632c393a42Smrg	FcCharSetDestroy (e->u.cval);
2642c393a42Smrg	break;
265ca08ab68Smrg    case FcOpLangSet:
266ca08ab68Smrg	FcLangSetDestroy (e->u.lval);
267ca08ab68Smrg	break;
2682c393a42Smrg    case FcOpBool:
2692c393a42Smrg	break;
2702c393a42Smrg    case FcOpField:
2712c393a42Smrg	break;
2722c393a42Smrg    case FcOpConst:
273c9710b42Smrg	FcFree (e->u.constant);
2742c393a42Smrg	break;
2752c393a42Smrg    case FcOpAssign:
2762c393a42Smrg    case FcOpAssignReplace:
2772c393a42Smrg    case FcOpPrepend:
2782c393a42Smrg    case FcOpPrependFirst:
2792c393a42Smrg    case FcOpAppend:
2802c393a42Smrg    case FcOpAppendLast:
281c9710b42Smrg    case FcOpDelete:
282c9710b42Smrg    case FcOpDeleteAll:
2832c393a42Smrg	break;
2842c393a42Smrg    case FcOpOr:
2852c393a42Smrg    case FcOpAnd:
2862c393a42Smrg    case FcOpEqual:
2872c393a42Smrg    case FcOpNotEqual:
2882c393a42Smrg    case FcOpLess:
2892c393a42Smrg    case FcOpLessEqual:
2902c393a42Smrg    case FcOpMore:
2912c393a42Smrg    case FcOpMoreEqual:
2922c393a42Smrg    case FcOpContains:
2932c393a42Smrg    case FcOpListing:
2942c393a42Smrg    case FcOpNotContains:
2952c393a42Smrg    case FcOpPlus:
2962c393a42Smrg    case FcOpMinus:
2972c393a42Smrg    case FcOpTimes:
2982c393a42Smrg    case FcOpDivide:
2992c393a42Smrg    case FcOpQuest:
3002c393a42Smrg    case FcOpComma:
3012c393a42Smrg	FcExprDestroy (e->u.tree.right);
3022c393a42Smrg	/* fall through */
3032c393a42Smrg    case FcOpNot:
3042c393a42Smrg    case FcOpFloor:
3052c393a42Smrg    case FcOpCeil:
3062c393a42Smrg    case FcOpRound:
3072c393a42Smrg    case FcOpTrunc:
3082c393a42Smrg	FcExprDestroy (e->u.tree.left);
3092c393a42Smrg	break;
3102c393a42Smrg    case FcOpNil:
3112c393a42Smrg    case FcOpInvalid:
3122c393a42Smrg	break;
3132c393a42Smrg    }
314a6844aabSmrg
315a6844aabSmrg    e->op = FcOpNil;
3162c393a42Smrg}
3172c393a42Smrg
3182c393a42Smrgvoid
3192c393a42SmrgFcEditDestroy (FcEdit *e)
3202c393a42Smrg{
3212c393a42Smrg    if (e->expr)
3222c393a42Smrg	FcExprDestroy (e->expr);
3232c393a42Smrg    free (e);
3242c393a42Smrg}
3252c393a42Smrg
3262c393a42Smrgtypedef enum _FcElement {
3272c393a42Smrg    FcElementNone,
3282c393a42Smrg    FcElementFontconfig,
3292c393a42Smrg    FcElementDir,
3302c393a42Smrg    FcElementCacheDir,
3312c393a42Smrg    FcElementCache,
3322c393a42Smrg    FcElementInclude,
3332c393a42Smrg    FcElementConfig,
3342c393a42Smrg    FcElementMatch,
3352c393a42Smrg    FcElementAlias,
3362c393a42Smrg
3372c393a42Smrg    FcElementBlank,
3382c393a42Smrg    FcElementRescan,
3392c393a42Smrg
3402c393a42Smrg    FcElementPrefer,
3412c393a42Smrg    FcElementAccept,
3422c393a42Smrg    FcElementDefault,
3432c393a42Smrg    FcElementFamily,
3442c393a42Smrg
3452c393a42Smrg    FcElementSelectfont,
3462c393a42Smrg    FcElementAcceptfont,
3472c393a42Smrg    FcElementRejectfont,
3482c393a42Smrg    FcElementGlob,
3492c393a42Smrg    FcElementPattern,
3502c393a42Smrg    FcElementPatelt,
3512c393a42Smrg
3522c393a42Smrg    FcElementTest,
3532c393a42Smrg    FcElementEdit,
3542c393a42Smrg    FcElementInt,
3552c393a42Smrg    FcElementDouble,
3562c393a42Smrg    FcElementString,
3572c393a42Smrg    FcElementMatrix,
358ca08ab68Smrg    FcElementRange,
3592c393a42Smrg    FcElementBool,
360ca08ab68Smrg    FcElementCharSet,
361ca08ab68Smrg    FcElementLangSet,
3622c393a42Smrg    FcElementName,
3632c393a42Smrg    FcElementConst,
3642c393a42Smrg    FcElementOr,
3652c393a42Smrg    FcElementAnd,
3662c393a42Smrg    FcElementEq,
3672c393a42Smrg    FcElementNotEq,
3682c393a42Smrg    FcElementLess,
3692c393a42Smrg    FcElementLessEq,
3702c393a42Smrg    FcElementMore,
3712c393a42Smrg    FcElementMoreEq,
3722c393a42Smrg    FcElementContains,
3732c393a42Smrg    FcElementNotContains,
3742c393a42Smrg    FcElementPlus,
3752c393a42Smrg    FcElementMinus,
3762c393a42Smrg    FcElementTimes,
3772c393a42Smrg    FcElementDivide,
3782c393a42Smrg    FcElementNot,
3792c393a42Smrg    FcElementIf,
3802c393a42Smrg    FcElementFloor,
3812c393a42Smrg    FcElementCeil,
3822c393a42Smrg    FcElementRound,
3832c393a42Smrg    FcElementTrunc,
3842c393a42Smrg    FcElementUnknown
3852c393a42Smrg} FcElement;
3862c393a42Smrg
3872c393a42Smrgstatic const struct {
3882c393a42Smrg    const char  name[16];
3892c393a42Smrg    FcElement   element;
3902c393a42Smrg} fcElementMap[] = {
3912c393a42Smrg    { "fontconfig",	FcElementFontconfig },
3922c393a42Smrg    { "dir",		FcElementDir },
3932c393a42Smrg    { "cachedir",	FcElementCacheDir },
3942c393a42Smrg    { "cache",		FcElementCache },
3952c393a42Smrg    { "include",	FcElementInclude },
3962c393a42Smrg    { "config",		FcElementConfig },
3972c393a42Smrg    { "match",		FcElementMatch },
3982c393a42Smrg    { "alias",		FcElementAlias },
399ca08ab68Smrg
4002c393a42Smrg    { "blank",		FcElementBlank },
4012c393a42Smrg    { "rescan",		FcElementRescan },
4022c393a42Smrg
4032c393a42Smrg    { "prefer",		FcElementPrefer },
4042c393a42Smrg    { "accept",		FcElementAccept },
4052c393a42Smrg    { "default",	FcElementDefault },
4062c393a42Smrg    { "family",		FcElementFamily },
4072c393a42Smrg
4082c393a42Smrg    { "selectfont",	FcElementSelectfont },
4092c393a42Smrg    { "acceptfont",	FcElementAcceptfont },
4102c393a42Smrg    { "rejectfont",	FcElementRejectfont },
4112c393a42Smrg    { "glob",		FcElementGlob },
4122c393a42Smrg    { "pattern",	FcElementPattern },
4132c393a42Smrg    { "patelt",		FcElementPatelt },
4142c393a42Smrg
4152c393a42Smrg    { "test",		FcElementTest },
4162c393a42Smrg    { "edit",		FcElementEdit },
4172c393a42Smrg    { "int",		FcElementInt },
4182c393a42Smrg    { "double",		FcElementDouble },
4192c393a42Smrg    { "string",		FcElementString },
4202c393a42Smrg    { "matrix",		FcElementMatrix },
421ca08ab68Smrg    { "range",		FcElementRange },
4222c393a42Smrg    { "bool",		FcElementBool },
423ca08ab68Smrg    { "charset",	FcElementCharSet },
424ca08ab68Smrg    { "langset",	FcElementLangSet },
4252c393a42Smrg    { "name",		FcElementName },
4262c393a42Smrg    { "const",		FcElementConst },
4272c393a42Smrg    { "or",		FcElementOr },
4282c393a42Smrg    { "and",		FcElementAnd },
4292c393a42Smrg    { "eq",		FcElementEq },
4302c393a42Smrg    { "not_eq",		FcElementNotEq },
4312c393a42Smrg    { "less",		FcElementLess },
4322c393a42Smrg    { "less_eq",	FcElementLessEq },
4332c393a42Smrg    { "more",		FcElementMore },
4342c393a42Smrg    { "more_eq",	FcElementMoreEq },
4352c393a42Smrg    { "contains",	FcElementContains },
4362c393a42Smrg    { "not_contains",	FcElementNotContains },
4372c393a42Smrg    { "plus",		FcElementPlus },
4382c393a42Smrg    { "minus",		FcElementMinus },
4392c393a42Smrg    { "times",		FcElementTimes },
4402c393a42Smrg    { "divide",		FcElementDivide },
4412c393a42Smrg    { "not",		FcElementNot },
4422c393a42Smrg    { "if",		FcElementIf },
4432c393a42Smrg    { "floor",		FcElementFloor },
4442c393a42Smrg    { "ceil",		FcElementCeil },
4452c393a42Smrg    { "round",		FcElementRound },
4462c393a42Smrg    { "trunc",		FcElementTrunc },
4472c393a42Smrg};
4482c393a42Smrg#define NUM_ELEMENT_MAPS (int) (sizeof fcElementMap / sizeof fcElementMap[0])
4492c393a42Smrg
4502c393a42Smrgstatic FcElement
4512c393a42SmrgFcElementMap (const XML_Char *name)
4522c393a42Smrg{
4532c393a42Smrg
4542c393a42Smrg    int	    i;
4552c393a42Smrg    for (i = 0; i < NUM_ELEMENT_MAPS; i++)
4562c393a42Smrg	if (!strcmp ((char *) name, fcElementMap[i].name))
4572c393a42Smrg	    return fcElementMap[i].element;
4582c393a42Smrg    return FcElementUnknown;
4592c393a42Smrg}
4602c393a42Smrg
4612c393a42Smrgtypedef struct _FcPStack {
4622c393a42Smrg    struct _FcPStack   *prev;
4632c393a42Smrg    FcElement		element;
4642c393a42Smrg    FcChar8		**attr;
4652c393a42Smrg    FcStrBuf		str;
466a6844aabSmrg    FcChar8            *attr_buf_static[16];
4672c393a42Smrg} FcPStack;
468ca08ab68Smrg
4692c393a42Smrgtypedef enum _FcVStackTag {
4702c393a42Smrg    FcVStackNone,
4712c393a42Smrg
4722c393a42Smrg    FcVStackString,
4732c393a42Smrg    FcVStackFamily,
4742c393a42Smrg    FcVStackConstant,
4752c393a42Smrg    FcVStackGlob,
476c9710b42Smrg    FcVStackName,
4772c393a42Smrg    FcVStackPattern,
478ca08ab68Smrg
4792c393a42Smrg    FcVStackPrefer,
4802c393a42Smrg    FcVStackAccept,
4812c393a42Smrg    FcVStackDefault,
482ca08ab68Smrg
4832c393a42Smrg    FcVStackInteger,
4842c393a42Smrg    FcVStackDouble,
4852c393a42Smrg    FcVStackMatrix,
486ca08ab68Smrg    FcVStackRange,
4872c393a42Smrg    FcVStackBool,
488ca08ab68Smrg    FcVStackCharSet,
489ca08ab68Smrg    FcVStackLangSet,
490ca08ab68Smrg
4912c393a42Smrg    FcVStackTest,
4922c393a42Smrg    FcVStackExpr,
4932c393a42Smrg    FcVStackEdit
4942c393a42Smrg} FcVStackTag;
4952c393a42Smrg
4962c393a42Smrgtypedef struct _FcVStack {
4972c393a42Smrg    struct _FcVStack	*prev;
4982c393a42Smrg    FcPStack		*pstack;	/* related parse element */
4992c393a42Smrg    FcVStackTag		tag;
5002c393a42Smrg    union {
5012c393a42Smrg	FcChar8		*string;
5022c393a42Smrg
5032c393a42Smrg	int		integer;
5042c393a42Smrg	double		_double;
505c9710b42Smrg	FcExprMatrix	*matrix;
506ca08ab68Smrg	FcRange		range;
507a6844aabSmrg	FcBool		bool_;
508ca08ab68Smrg	FcCharSet	*charset;
509ca08ab68Smrg	FcLangSet	*langset;
510c9710b42Smrg	FcExprName	name;
5112c393a42Smrg
5122c393a42Smrg	FcTest		*test;
5132c393a42Smrg	FcQual		qual;
5142c393a42Smrg	FcOp		op;
5152c393a42Smrg	FcExpr		*expr;
5162c393a42Smrg	FcEdit		*edit;
5172c393a42Smrg
5182c393a42Smrg	FcPattern	*pattern;
5192c393a42Smrg    } u;
5202c393a42Smrg} FcVStack;
5212c393a42Smrg
5222c393a42Smrgtypedef struct _FcConfigParse {
5232c393a42Smrg    FcPStack	    *pstack;
5242c393a42Smrg    FcVStack	    *vstack;
5252c393a42Smrg    FcBool	    error;
5262c393a42Smrg    const FcChar8   *name;
5272c393a42Smrg    FcConfig	    *config;
5282c393a42Smrg    XML_Parser	    parser;
529c9710b42Smrg    unsigned int    pstack_static_used;
530a6844aabSmrg    FcPStack        pstack_static[8];
531c9710b42Smrg    unsigned int    vstack_static_used;
532a6844aabSmrg    FcVStack        vstack_static[64];
5332c393a42Smrg} FcConfigParse;
5342c393a42Smrg
5352c393a42Smrgtypedef enum _FcConfigSeverity {
5362c393a42Smrg    FcSevereInfo, FcSevereWarning, FcSevereError
5372c393a42Smrg} FcConfigSeverity;
5382c393a42Smrg
5392c393a42Smrgstatic void
5402c393a42SmrgFcConfigMessage (FcConfigParse *parse, FcConfigSeverity severe, const char *fmt, ...)
5412c393a42Smrg{
5422c393a42Smrg    const char	*s = "unknown";
5432c393a42Smrg    va_list	args;
5442c393a42Smrg
5452c393a42Smrg    va_start (args, fmt);
5462c393a42Smrg
5472c393a42Smrg    switch (severe) {
5482c393a42Smrg    case FcSevereInfo: s = "info"; break;
5492c393a42Smrg    case FcSevereWarning: s = "warning"; break;
5502c393a42Smrg    case FcSevereError: s = "error"; break;
5512c393a42Smrg    }
5522c393a42Smrg    if (parse)
5532c393a42Smrg    {
5542c393a42Smrg	if (parse->name)
5552c393a42Smrg	    fprintf (stderr, "Fontconfig %s: \"%s\", line %d: ", s,
5562c393a42Smrg		     parse->name, (int)XML_GetCurrentLineNumber (parse->parser));
5572c393a42Smrg	else
5582c393a42Smrg	    fprintf (stderr, "Fontconfig %s: line %d: ", s,
5592c393a42Smrg		     (int)XML_GetCurrentLineNumber (parse->parser));
5602c393a42Smrg	if (severe >= FcSevereError)
5612c393a42Smrg	    parse->error = FcTrue;
5622c393a42Smrg    }
5632c393a42Smrg    else
5642c393a42Smrg	fprintf (stderr, "Fontconfig %s: ", s);
5652c393a42Smrg    vfprintf (stderr, fmt, args);
5662c393a42Smrg    fprintf (stderr, "\n");
5672c393a42Smrg    va_end (args);
5682c393a42Smrg}
5692c393a42Smrg
5702c393a42Smrg
571c9710b42Smrgstatic FcExpr *
572c9710b42SmrgFcPopExpr (FcConfigParse *parse);
573c9710b42Smrg
574c9710b42Smrg
5752c393a42Smrgstatic const char *
5762c393a42SmrgFcTypeName (FcType type)
5772c393a42Smrg{
5782c393a42Smrg    switch (type) {
5792c393a42Smrg    case FcTypeVoid:
5802c393a42Smrg	return "void";
5812c393a42Smrg    case FcTypeInteger:
5822c393a42Smrg    case FcTypeDouble:
5832c393a42Smrg	return "number";
5842c393a42Smrg    case FcTypeString:
5852c393a42Smrg	return "string";
5862c393a42Smrg    case FcTypeBool:
5872c393a42Smrg	return "bool";
5882c393a42Smrg    case FcTypeMatrix:
5892c393a42Smrg	return "matrix";
5902c393a42Smrg    case FcTypeCharSet:
5912c393a42Smrg	return "charset";
5922c393a42Smrg    case FcTypeFTFace:
5932c393a42Smrg	return "FT_Face";
5942c393a42Smrg    case FcTypeLangSet:
5952c393a42Smrg	return "langset";
5962c393a42Smrg    default:
5972c393a42Smrg	return "unknown";
5982c393a42Smrg    }
5992c393a42Smrg}
6002c393a42Smrg
6012c393a42Smrgstatic void
6022c393a42SmrgFcTypecheckValue (FcConfigParse *parse, FcType value, FcType type)
6032c393a42Smrg{
6042c393a42Smrg    if (value == FcTypeInteger)
6052c393a42Smrg	value = FcTypeDouble;
6062c393a42Smrg    if (type == FcTypeInteger)
6072c393a42Smrg	type = FcTypeDouble;
6082c393a42Smrg    if (value != type)
6092c393a42Smrg    {
6102c393a42Smrg	if ((value == FcTypeLangSet && type == FcTypeString) ||
6112c393a42Smrg	    (value == FcTypeString && type == FcTypeLangSet))
6122c393a42Smrg	    return;
613b09479dcSmrg	if (type ==  FcTypeUnknown)
6142c393a42Smrg	    return;
615c9710b42Smrg	/* It's perfectly fine to use user-define elements in expressions,
616c9710b42Smrg	 * so don't warn in that case. */
617b09479dcSmrg	if (value == FcTypeUnknown)
618c9710b42Smrg	    return;
6192c393a42Smrg	FcConfigMessage (parse, FcSevereWarning, "saw %s, expected %s",
6202c393a42Smrg			 FcTypeName (value), FcTypeName (type));
6212c393a42Smrg    }
6222c393a42Smrg}
6232c393a42Smrg
6242c393a42Smrgstatic void
6252c393a42SmrgFcTypecheckExpr (FcConfigParse *parse, FcExpr *expr, FcType type)
6262c393a42Smrg{
6272c393a42Smrg    const FcObjectType	*o;
6282c393a42Smrg    const FcConstant	*c;
629ca08ab68Smrg
6302c393a42Smrg    /* If parsing the expression failed, some nodes may be NULL */
6312c393a42Smrg    if (!expr)
6322c393a42Smrg	return;
6332c393a42Smrg
634ca08ab68Smrg    switch (FC_OP_GET_OP (expr->op)) {
6352c393a42Smrg    case FcOpInteger:
6362c393a42Smrg    case FcOpDouble:
6372c393a42Smrg	FcTypecheckValue (parse, FcTypeDouble, type);
6382c393a42Smrg	break;
6392c393a42Smrg    case FcOpString:
6402c393a42Smrg	FcTypecheckValue (parse, FcTypeString, type);
6412c393a42Smrg	break;
6422c393a42Smrg    case FcOpMatrix:
6432c393a42Smrg	FcTypecheckValue (parse, FcTypeMatrix, type);
6442c393a42Smrg	break;
6452c393a42Smrg    case FcOpBool:
6462c393a42Smrg	FcTypecheckValue (parse, FcTypeBool, type);
6472c393a42Smrg	break;
6482c393a42Smrg    case FcOpCharSet:
6492c393a42Smrg	FcTypecheckValue (parse, FcTypeCharSet, type);
6502c393a42Smrg	break;
651ca08ab68Smrg    case FcOpLangSet:
652ca08ab68Smrg	FcTypecheckValue (parse, FcTypeLangSet, type);
653ca08ab68Smrg	break;
6542c393a42Smrg    case FcOpNil:
6552c393a42Smrg	break;
6562c393a42Smrg    case FcOpField:
657c9710b42Smrg	o = FcNameGetObjectType (FcObjectName (expr->u.name.object));
6582c393a42Smrg	if (o)
6592c393a42Smrg	    FcTypecheckValue (parse, o->type, type);
6602c393a42Smrg	break;
6612c393a42Smrg    case FcOpConst:
6622c393a42Smrg	c = FcNameGetConstant (expr->u.constant);
6632c393a42Smrg	if (c)
6642c393a42Smrg	{
6652c393a42Smrg	    o = FcNameGetObjectType (c->object);
6662c393a42Smrg	    if (o)
6672c393a42Smrg		FcTypecheckValue (parse, o->type, type);
6682c393a42Smrg	}
669ca08ab68Smrg        else
670ca08ab68Smrg            FcConfigMessage (parse, FcSevereWarning,
6712c393a42Smrg                             "invalid constant used : %s",
6722c393a42Smrg                             expr->u.constant);
6732c393a42Smrg	break;
6742c393a42Smrg    case FcOpQuest:
6752c393a42Smrg	FcTypecheckExpr (parse, expr->u.tree.left, FcTypeBool);
6762c393a42Smrg	FcTypecheckExpr (parse, expr->u.tree.right->u.tree.left, type);
6772c393a42Smrg	FcTypecheckExpr (parse, expr->u.tree.right->u.tree.right, type);
6782c393a42Smrg	break;
6792c393a42Smrg    case FcOpAssign:
6802c393a42Smrg    case FcOpAssignReplace:
6812c393a42Smrg	break;
6822c393a42Smrg    case FcOpEqual:
6832c393a42Smrg    case FcOpNotEqual:
6842c393a42Smrg    case FcOpLess:
6852c393a42Smrg    case FcOpLessEqual:
6862c393a42Smrg    case FcOpMore:
6872c393a42Smrg    case FcOpMoreEqual:
6882c393a42Smrg    case FcOpContains:
6892c393a42Smrg    case FcOpNotContains:
6902c393a42Smrg    case FcOpListing:
6912c393a42Smrg	FcTypecheckValue (parse, FcTypeBool, type);
6922c393a42Smrg	break;
6932c393a42Smrg    case FcOpComma:
6942c393a42Smrg    case FcOpOr:
6952c393a42Smrg    case FcOpAnd:
6962c393a42Smrg    case FcOpPlus:
6972c393a42Smrg    case FcOpMinus:
6982c393a42Smrg    case FcOpTimes:
6992c393a42Smrg    case FcOpDivide:
7002c393a42Smrg	FcTypecheckExpr (parse, expr->u.tree.left, type);
7012c393a42Smrg	FcTypecheckExpr (parse, expr->u.tree.right, type);
7022c393a42Smrg	break;
7032c393a42Smrg    case FcOpNot:
7042c393a42Smrg	FcTypecheckValue (parse, FcTypeBool, type);
7052c393a42Smrg	FcTypecheckExpr (parse, expr->u.tree.left, FcTypeBool);
7062c393a42Smrg	break;
7072c393a42Smrg    case FcOpFloor:
7082c393a42Smrg    case FcOpCeil:
7092c393a42Smrg    case FcOpRound:
7102c393a42Smrg    case FcOpTrunc:
7112c393a42Smrg	FcTypecheckValue (parse, FcTypeDouble, type);
7122c393a42Smrg	FcTypecheckExpr (parse, expr->u.tree.left, FcTypeDouble);
7132c393a42Smrg	break;
7142c393a42Smrg    default:
7152c393a42Smrg	break;
7162c393a42Smrg    }
7172c393a42Smrg}
7182c393a42Smrg
7192c393a42Smrgstatic FcTest *
7202c393a42SmrgFcTestCreate (FcConfigParse *parse,
721ca08ab68Smrg	      FcMatchKind   kind,
7222c393a42Smrg	      FcQual	    qual,
7232c393a42Smrg	      const FcChar8 *field,
7246fc018e4Smrg	      unsigned int  compare,
7252c393a42Smrg	      FcExpr	    *expr)
7262c393a42Smrg{
7272c393a42Smrg    FcTest	*test = (FcTest *) malloc (sizeof (FcTest));
7282c393a42Smrg
7292c393a42Smrg    if (test)
7302c393a42Smrg    {
7312c393a42Smrg	const FcObjectType	*o;
7322c393a42Smrg
7332c393a42Smrg	test->kind = kind;
7342c393a42Smrg	test->qual = qual;
7352c393a42Smrg	test->object = FcObjectFromName ((const char *) field);
7362c393a42Smrg	test->op = compare;
7372c393a42Smrg	test->expr = expr;
7382c393a42Smrg	o = FcNameGetObjectType (FcObjectName (test->object));
7392c393a42Smrg	if (o)
7402c393a42Smrg	    FcTypecheckExpr (parse, expr, o->type);
7412c393a42Smrg    }
7422c393a42Smrg    return test;
7432c393a42Smrg}
7442c393a42Smrg
7452c393a42Smrgstatic FcEdit *
7462c393a42SmrgFcEditCreate (FcConfigParse	*parse,
7472c393a42Smrg	      FcObject		object,
7482c393a42Smrg	      FcOp		op,
7492c393a42Smrg	      FcExpr		*expr,
7502c393a42Smrg	      FcValueBinding	binding)
7512c393a42Smrg{
7522c393a42Smrg    FcEdit *e = (FcEdit *) malloc (sizeof (FcEdit));
7532c393a42Smrg
7542c393a42Smrg    if (e)
7552c393a42Smrg    {
7562c393a42Smrg	const FcObjectType	*o;
7572c393a42Smrg
7582c393a42Smrg	e->object = object;
7592c393a42Smrg	e->op = op;
7602c393a42Smrg	e->expr = expr;
7612c393a42Smrg	e->binding = binding;
7622c393a42Smrg	o = FcNameGetObjectType (FcObjectName (e->object));
7632c393a42Smrg	if (o)
7642c393a42Smrg	    FcTypecheckExpr (parse, expr, o->type);
7652c393a42Smrg    }
7662c393a42Smrg    return e;
7672c393a42Smrg}
7682c393a42Smrg
7696fc018e4Smrgstatic FcRule *
7706fc018e4SmrgFcRuleCreate (FcRuleType type,
7716fc018e4Smrg	      void       *p)
7726fc018e4Smrg{
7736fc018e4Smrg    FcRule *r = (FcRule *) malloc (sizeof (FcRule));
7746fc018e4Smrg
7756fc018e4Smrg    if (!r)
7766fc018e4Smrg	return NULL;
7776fc018e4Smrg
7786fc018e4Smrg    r->next = NULL;
7796fc018e4Smrg    r->type = type;
7806fc018e4Smrg    switch (type)
7816fc018e4Smrg    {
7826fc018e4Smrg    case FcRuleTest:
7836fc018e4Smrg	r->u.test = (FcTest *) p;
7846fc018e4Smrg	break;
7856fc018e4Smrg    case FcRuleEdit:
7866fc018e4Smrg	r->u.edit = (FcEdit *) p;
7876fc018e4Smrg	break;
7886fc018e4Smrg    default:
7896fc018e4Smrg	free (r);
7906fc018e4Smrg	r = NULL;
7916fc018e4Smrg	break;
7926fc018e4Smrg    }
7936fc018e4Smrg
7946fc018e4Smrg    return r;
7956fc018e4Smrg}
7966fc018e4Smrg
7972c393a42Smrgstatic FcVStack *
798a6844aabSmrgFcVStackCreateAndPush (FcConfigParse *parse)
7992c393a42Smrg{
8002c393a42Smrg    FcVStack    *new;
8012c393a42Smrg
802a6844aabSmrg    if (parse->vstack_static_used < sizeof (parse->vstack_static) / sizeof (parse->vstack_static[0]))
803a6844aabSmrg	new = &parse->vstack_static[parse->vstack_static_used++];
804a6844aabSmrg    else
805a6844aabSmrg    {
806a6844aabSmrg	new = malloc (sizeof (FcVStack));
807a6844aabSmrg	if (!new)
808a6844aabSmrg	    return 0;
809a6844aabSmrg    }
8102c393a42Smrg    new->tag = FcVStackNone;
8112c393a42Smrg    new->prev = 0;
8122c393a42Smrg
813a6844aabSmrg    new->prev = parse->vstack;
814a6844aabSmrg    new->pstack = parse->pstack ? parse->pstack->prev : 0;
815a6844aabSmrg    parse->vstack = new;
8162c393a42Smrg
817a6844aabSmrg    return new;
8182c393a42Smrg}
8192c393a42Smrg
8202c393a42Smrgstatic FcBool
8212c393a42SmrgFcVStackPushString (FcConfigParse *parse, FcVStackTag tag, FcChar8 *string)
8222c393a42Smrg{
823a6844aabSmrg    FcVStack    *vstack = FcVStackCreateAndPush (parse);
8242c393a42Smrg    if (!vstack)
8252c393a42Smrg	return FcFalse;
8262c393a42Smrg    vstack->u.string = string;
8272c393a42Smrg    vstack->tag = tag;
8282c393a42Smrg    return FcTrue;
8292c393a42Smrg}
8302c393a42Smrg
8312c393a42Smrgstatic FcBool
8322c393a42SmrgFcVStackPushInteger (FcConfigParse *parse, int integer)
8332c393a42Smrg{
834a6844aabSmrg    FcVStack    *vstack = FcVStackCreateAndPush (parse);
8352c393a42Smrg    if (!vstack)
8362c393a42Smrg	return FcFalse;
8372c393a42Smrg    vstack->u.integer = integer;
8382c393a42Smrg    vstack->tag = FcVStackInteger;
8392c393a42Smrg    return FcTrue;
8402c393a42Smrg}
8412c393a42Smrg
8422c393a42Smrgstatic FcBool
8432c393a42SmrgFcVStackPushDouble (FcConfigParse *parse, double _double)
8442c393a42Smrg{
845a6844aabSmrg    FcVStack    *vstack = FcVStackCreateAndPush (parse);
8462c393a42Smrg    if (!vstack)
8472c393a42Smrg	return FcFalse;
8482c393a42Smrg    vstack->u._double = _double;
8492c393a42Smrg    vstack->tag = FcVStackDouble;
8502c393a42Smrg    return FcTrue;
8512c393a42Smrg}
8522c393a42Smrg
8532c393a42Smrgstatic FcBool
854c9710b42SmrgFcVStackPushMatrix (FcConfigParse *parse, FcExprMatrix *matrix)
8552c393a42Smrg{
856a6844aabSmrg    FcVStack    *vstack;
857a6844aabSmrg    vstack = FcVStackCreateAndPush (parse);
858a6844aabSmrg    if (!vstack)
859a6844aabSmrg	return FcFalse;
860c9710b42Smrg    vstack->u.matrix = FcExprMatrixCopyShallow (matrix);
8612c393a42Smrg    vstack->tag = FcVStackMatrix;
8622c393a42Smrg    return FcTrue;
8632c393a42Smrg}
8642c393a42Smrg
865ca08ab68Smrgstatic FcBool
866ca08ab68SmrgFcVStackPushRange (FcConfigParse *parse, FcRange *range)
867ca08ab68Smrg{
868ca08ab68Smrg    FcVStack	*vstack = FcVStackCreateAndPush (parse);
869ca08ab68Smrg    if (!vstack)
870ca08ab68Smrg	return FcFalse;
871ca08ab68Smrg    vstack->u.range.begin = range->begin;
872ca08ab68Smrg    vstack->u.range.end = range->end;
873ca08ab68Smrg    vstack->tag = FcVStackRange;
874ca08ab68Smrg    return FcTrue;
875ca08ab68Smrg}
876ca08ab68Smrg
8772c393a42Smrgstatic FcBool
878a6844aabSmrgFcVStackPushBool (FcConfigParse *parse, FcBool bool_)
8792c393a42Smrg{
880a6844aabSmrg    FcVStack    *vstack = FcVStackCreateAndPush (parse);
8812c393a42Smrg    if (!vstack)
8822c393a42Smrg	return FcFalse;
883a6844aabSmrg    vstack->u.bool_ = bool_;
8842c393a42Smrg    vstack->tag = FcVStackBool;
8852c393a42Smrg    return FcTrue;
8862c393a42Smrg}
8872c393a42Smrg
888ca08ab68Smrgstatic FcBool
889ca08ab68SmrgFcVStackPushCharSet (FcConfigParse *parse, FcCharSet *charset)
890ca08ab68Smrg{
891ca08ab68Smrg    FcVStack	*vstack;
892ca08ab68Smrg    if (!charset)
893ca08ab68Smrg	return FcFalse;
894ca08ab68Smrg    vstack = FcVStackCreateAndPush (parse);
895ca08ab68Smrg    if (!vstack)
896ca08ab68Smrg	return FcFalse;
897ca08ab68Smrg    vstack->u.charset = charset;
898ca08ab68Smrg    vstack->tag = FcVStackCharSet;
899ca08ab68Smrg    return FcTrue;
900ca08ab68Smrg}
901ca08ab68Smrg
902ca08ab68Smrgstatic FcBool
903ca08ab68SmrgFcVStackPushLangSet (FcConfigParse *parse, FcLangSet *langset)
904ca08ab68Smrg{
905ca08ab68Smrg    FcVStack	*vstack;
906ca08ab68Smrg    if (!langset)
907ca08ab68Smrg	return FcFalse;
908ca08ab68Smrg    vstack = FcVStackCreateAndPush (parse);
909ca08ab68Smrg    if (!vstack)
910ca08ab68Smrg	return FcFalse;
911ca08ab68Smrg    vstack->u.langset = langset;
912ca08ab68Smrg    vstack->tag = FcVStackLangSet;
913ca08ab68Smrg    return FcTrue;
914ca08ab68Smrg}
915ca08ab68Smrg
916c9710b42Smrgstatic FcBool
917c9710b42SmrgFcVStackPushName (FcConfigParse *parse, FcMatchKind kind, FcObject object)
918c9710b42Smrg{
919c9710b42Smrg    FcVStack    *vstack = FcVStackCreateAndPush (parse);
920c9710b42Smrg    if (!vstack)
921c9710b42Smrg	return FcFalse;
922c9710b42Smrg    vstack->u.name.object = object;
923c9710b42Smrg    vstack->u.name.kind = kind;
924c9710b42Smrg    vstack->tag = FcVStackName;
925c9710b42Smrg    return FcTrue;
926c9710b42Smrg}
927c9710b42Smrg
9282c393a42Smrgstatic FcBool
9292c393a42SmrgFcVStackPushTest (FcConfigParse *parse, FcTest *test)
9302c393a42Smrg{
931a6844aabSmrg    FcVStack    *vstack = FcVStackCreateAndPush (parse);
9322c393a42Smrg    if (!vstack)
9332c393a42Smrg	return FcFalse;
9342c393a42Smrg    vstack->u.test = test;
9352c393a42Smrg    vstack->tag = FcVStackTest;
9362c393a42Smrg    return FcTrue;
9372c393a42Smrg}
9382c393a42Smrg
9392c393a42Smrgstatic FcBool
9402c393a42SmrgFcVStackPushExpr (FcConfigParse *parse, FcVStackTag tag, FcExpr *expr)
9412c393a42Smrg{
942a6844aabSmrg    FcVStack    *vstack = FcVStackCreateAndPush (parse);
9432c393a42Smrg    if (!vstack)
9442c393a42Smrg	return FcFalse;
9452c393a42Smrg    vstack->u.expr = expr;
9462c393a42Smrg    vstack->tag = tag;
9472c393a42Smrg    return FcTrue;
9482c393a42Smrg}
9492c393a42Smrg
9502c393a42Smrgstatic FcBool
9512c393a42SmrgFcVStackPushEdit (FcConfigParse *parse, FcEdit *edit)
9522c393a42Smrg{
953a6844aabSmrg    FcVStack    *vstack = FcVStackCreateAndPush (parse);
9542c393a42Smrg    if (!vstack)
9552c393a42Smrg	return FcFalse;
9562c393a42Smrg    vstack->u.edit = edit;
9572c393a42Smrg    vstack->tag = FcVStackEdit;
9582c393a42Smrg    return FcTrue;
9592c393a42Smrg}
9602c393a42Smrg
9612c393a42Smrgstatic FcBool
9622c393a42SmrgFcVStackPushPattern (FcConfigParse *parse, FcPattern *pattern)
9632c393a42Smrg{
964a6844aabSmrg    FcVStack    *vstack = FcVStackCreateAndPush (parse);
9652c393a42Smrg    if (!vstack)
9662c393a42Smrg	return FcFalse;
9672c393a42Smrg    vstack->u.pattern = pattern;
9682c393a42Smrg    vstack->tag = FcVStackPattern;
9692c393a42Smrg    return FcTrue;
9702c393a42Smrg}
9712c393a42Smrg
9722c393a42Smrgstatic FcVStack *
9732c393a42SmrgFcVStackFetch (FcConfigParse *parse, int off)
9742c393a42Smrg{
9752c393a42Smrg    FcVStack    *vstack;
9762c393a42Smrg
9772c393a42Smrg    for (vstack = parse->vstack; vstack && off-- > 0; vstack = vstack->prev);
9782c393a42Smrg    return vstack;
9792c393a42Smrg}
9802c393a42Smrg
981a6844aabSmrgstatic FcVStack *
982a6844aabSmrgFcVStackPeek (FcConfigParse *parse)
9832c393a42Smrg{
984a6844aabSmrg    FcVStack	*vstack = parse->vstack;
985a6844aabSmrg
986a6844aabSmrg    return vstack && vstack->pstack == parse->pstack ? vstack : 0;
9872c393a42Smrg}
9882c393a42Smrg
989a6844aabSmrgstatic void
990a6844aabSmrgFcVStackPopAndDestroy (FcConfigParse *parse)
9912c393a42Smrg{
9922c393a42Smrg    FcVStack	*vstack = parse->vstack;
993ca08ab68Smrg
9942c393a42Smrg    if (!vstack || vstack->pstack != parse->pstack)
995a6844aabSmrg	return;
996a6844aabSmrg
9972c393a42Smrg    parse->vstack = vstack->prev;
998a6844aabSmrg
999a6844aabSmrg    switch (vstack->tag) {
1000a6844aabSmrg    case FcVStackNone:
1001a6844aabSmrg	break;
1002c9710b42Smrg    case FcVStackName:
1003c9710b42Smrg	break;
1004a6844aabSmrg    case FcVStackFamily:
1005a6844aabSmrg	break;
1006a6844aabSmrg    case FcVStackString:
1007a6844aabSmrg    case FcVStackConstant:
1008a6844aabSmrg    case FcVStackGlob:
1009a6844aabSmrg	FcStrFree (vstack->u.string);
1010a6844aabSmrg	break;
1011a6844aabSmrg    case FcVStackPattern:
1012a6844aabSmrg	FcPatternDestroy (vstack->u.pattern);
1013a6844aabSmrg	break;
1014a6844aabSmrg    case FcVStackInteger:
1015a6844aabSmrg    case FcVStackDouble:
1016a6844aabSmrg	break;
1017a6844aabSmrg    case FcVStackMatrix:
1018c9710b42Smrg	FcExprMatrixFreeShallow (vstack->u.matrix);
1019a6844aabSmrg	break;
1020ca08ab68Smrg    case FcVStackRange:
1021a6844aabSmrg    case FcVStackBool:
1022a6844aabSmrg	break;
1023ca08ab68Smrg    case FcVStackCharSet:
1024ca08ab68Smrg	FcCharSetDestroy (vstack->u.charset);
1025ca08ab68Smrg	break;
1026ca08ab68Smrg    case FcVStackLangSet:
1027ca08ab68Smrg	FcLangSetDestroy (vstack->u.langset);
1028ca08ab68Smrg	break;
1029a6844aabSmrg    case FcVStackTest:
1030a6844aabSmrg	FcTestDestroy (vstack->u.test);
1031a6844aabSmrg	break;
1032a6844aabSmrg    case FcVStackExpr:
1033a6844aabSmrg    case FcVStackPrefer:
1034a6844aabSmrg    case FcVStackAccept:
1035a6844aabSmrg    case FcVStackDefault:
1036a6844aabSmrg	FcExprDestroy (vstack->u.expr);
1037a6844aabSmrg	break;
1038a6844aabSmrg    case FcVStackEdit:
1039a6844aabSmrg	FcEditDestroy (vstack->u.edit);
1040a6844aabSmrg	break;
1041a6844aabSmrg    }
1042a6844aabSmrg
1043a6844aabSmrg    if (vstack == &parse->vstack_static[parse->vstack_static_used - 1])
1044a6844aabSmrg	parse->vstack_static_used--;
1045a6844aabSmrg    else
1046a6844aabSmrg	free (vstack);
1047a6844aabSmrg}
1048a6844aabSmrg
1049a6844aabSmrgstatic void
1050a6844aabSmrgFcVStackClear (FcConfigParse *parse)
1051a6844aabSmrg{
1052a6844aabSmrg    while (FcVStackPeek (parse))
1053a6844aabSmrg	FcVStackPopAndDestroy (parse);
10542c393a42Smrg}
10552c393a42Smrg
10562c393a42Smrgstatic int
10572c393a42SmrgFcVStackElements (FcConfigParse *parse)
10582c393a42Smrg{
10592c393a42Smrg    int		h = 0;
10602c393a42Smrg    FcVStack	*vstack = parse->vstack;
10612c393a42Smrg    while (vstack && vstack->pstack == parse->pstack)
10622c393a42Smrg    {
10632c393a42Smrg	h++;
10642c393a42Smrg	vstack = vstack->prev;
10652c393a42Smrg    }
10662c393a42Smrg    return h;
10672c393a42Smrg}
10682c393a42Smrg
10692c393a42Smrgstatic FcChar8 **
1070a6844aabSmrgFcConfigSaveAttr (const XML_Char **attr, FcChar8 **buf, int size_bytes)
10712c393a42Smrg{
10722c393a42Smrg    int		slen;
10732c393a42Smrg    int		i;
10742c393a42Smrg    FcChar8	**new;
10752c393a42Smrg    FcChar8	*s;
10762c393a42Smrg
10772c393a42Smrg    if (!attr)
10782c393a42Smrg	return 0;
10792c393a42Smrg    slen = 0;
10802c393a42Smrg    for (i = 0; attr[i]; i++)
10812c393a42Smrg	slen += strlen ((char *) attr[i]) + 1;
1082a6844aabSmrg    if (i == 0)
10832c393a42Smrg	return 0;
1084a6844aabSmrg    slen += (i + 1) * sizeof (FcChar8 *);
1085a6844aabSmrg    if (slen <= size_bytes)
1086a6844aabSmrg	new = buf;
1087a6844aabSmrg    else
1088a6844aabSmrg    {
1089a6844aabSmrg	new = malloc (slen);
1090a6844aabSmrg	if (!new)
1091a6844aabSmrg	{
1092a6844aabSmrg	    FcConfigMessage (0, FcSevereError, "out of memory");
1093a6844aabSmrg	    return 0;
1094a6844aabSmrg	}
1095a6844aabSmrg    }
10962c393a42Smrg    s = (FcChar8 *) (new + (i + 1));
10972c393a42Smrg    for (i = 0; attr[i]; i++)
10982c393a42Smrg    {
10992c393a42Smrg	new[i] = s;
11002c393a42Smrg	strcpy ((char *) s, (char *) attr[i]);
11012c393a42Smrg	s += strlen ((char *) s) + 1;
11022c393a42Smrg    }
11032c393a42Smrg    new[i] = 0;
11042c393a42Smrg    return new;
11052c393a42Smrg}
11062c393a42Smrg
11072c393a42Smrgstatic FcBool
11082c393a42SmrgFcPStackPush (FcConfigParse *parse, FcElement element, const XML_Char **attr)
11092c393a42Smrg{
1110a6844aabSmrg    FcPStack   *new;
11112c393a42Smrg
1112a6844aabSmrg    if (parse->pstack_static_used < sizeof (parse->pstack_static) / sizeof (parse->pstack_static[0]))
1113a6844aabSmrg	new = &parse->pstack_static[parse->pstack_static_used++];
1114a6844aabSmrg    else
11152c393a42Smrg    {
1116a6844aabSmrg	new = malloc (sizeof (FcPStack));
1117a6844aabSmrg	if (!new)
11182c393a42Smrg	    return FcFalse;
11192c393a42Smrg    }
1120a6844aabSmrg
1121a6844aabSmrg    new->prev = parse->pstack;
1122a6844aabSmrg    new->element = element;
1123a6844aabSmrg    new->attr = FcConfigSaveAttr (attr, new->attr_buf_static, sizeof (new->attr_buf_static));
11242c393a42Smrg    FcStrBufInit (&new->str, 0, 0);
11252c393a42Smrg    parse->pstack = new;
11262c393a42Smrg    return FcTrue;
11272c393a42Smrg}
11282c393a42Smrg
11292c393a42Smrgstatic FcBool
11302c393a42SmrgFcPStackPop (FcConfigParse *parse)
11312c393a42Smrg{
11322c393a42Smrg    FcPStack   *old;
1133ca08ab68Smrg
1134ca08ab68Smrg    if (!parse->pstack)
11352c393a42Smrg    {
11362c393a42Smrg	FcConfigMessage (parse, FcSevereError, "mismatching element");
11372c393a42Smrg	return FcFalse;
11382c393a42Smrg    }
1139c9710b42Smrg
1140c9710b42Smrg    if (parse->pstack->attr)
1141c9710b42Smrg    {
1142c9710b42Smrg	/* Warn about unused attrs. */
1143c9710b42Smrg	FcChar8 **attrs = parse->pstack->attr;
1144c9710b42Smrg	while (*attrs)
1145c9710b42Smrg	{
1146c9710b42Smrg	    if (attrs[0][0])
1147c9710b42Smrg	    {
1148c9710b42Smrg		FcConfigMessage (parse, FcSevereError, "invalid attribute '%s'", attrs[0]);
1149c9710b42Smrg	    }
1150c9710b42Smrg	    attrs += 2;
1151c9710b42Smrg	}
1152c9710b42Smrg    }
1153c9710b42Smrg
11542c393a42Smrg    FcVStackClear (parse);
11552c393a42Smrg    old = parse->pstack;
11562c393a42Smrg    parse->pstack = old->prev;
11572c393a42Smrg    FcStrBufDestroy (&old->str);
1158c9710b42Smrg
1159a6844aabSmrg    if (old->attr && old->attr != old->attr_buf_static)
11602c393a42Smrg	free (old->attr);
1161a6844aabSmrg
1162a6844aabSmrg    if (old == &parse->pstack_static[parse->pstack_static_used - 1])
1163a6844aabSmrg	parse->pstack_static_used--;
1164a6844aabSmrg    else
1165a6844aabSmrg	free (old);
11662c393a42Smrg    return FcTrue;
11672c393a42Smrg}
11682c393a42Smrg
11692c393a42Smrgstatic FcBool
1170c9710b42SmrgFcConfigParseInit (FcConfigParse *parse, const FcChar8 *name, FcConfig *config, XML_Parser parser)
11712c393a42Smrg{
11722c393a42Smrg    parse->pstack = 0;
1173a6844aabSmrg    parse->pstack_static_used = 0;
11742c393a42Smrg    parse->vstack = 0;
1175a6844aabSmrg    parse->vstack_static_used = 0;
11762c393a42Smrg    parse->error = FcFalse;
11772c393a42Smrg    parse->name = name;
11782c393a42Smrg    parse->config = config;
11792c393a42Smrg    parse->parser = parser;
11802c393a42Smrg    return FcTrue;
11812c393a42Smrg}
11822c393a42Smrg
11832c393a42Smrgstatic void
11842c393a42SmrgFcConfigCleanup (FcConfigParse	*parse)
11852c393a42Smrg{
11862c393a42Smrg    while (parse->pstack)
11872c393a42Smrg	FcPStackPop (parse);
11882c393a42Smrg}
11892c393a42Smrg
11902c393a42Smrgstatic const FcChar8 *
11912c393a42SmrgFcConfigGetAttribute (FcConfigParse *parse, const char *attr)
11922c393a42Smrg{
11932c393a42Smrg    FcChar8 **attrs;
11942c393a42Smrg    if (!parse->pstack)
11952c393a42Smrg	return 0;
11962c393a42Smrg
11972c393a42Smrg    attrs = parse->pstack->attr;
11982c393a42Smrg    if (!attrs)
11992c393a42Smrg        return 0;
12002c393a42Smrg
12012c393a42Smrg    while (*attrs)
12022c393a42Smrg    {
12032c393a42Smrg	if (!strcmp ((char *) *attrs, attr))
1204c9710b42Smrg	{
1205c9710b42Smrg	    attrs[0][0] = '\0'; /* Mark as used. */
12062c393a42Smrg	    return attrs[1];
1207c9710b42Smrg	}
12082c393a42Smrg	attrs += 2;
12092c393a42Smrg    }
12102c393a42Smrg    return 0;
12112c393a42Smrg}
12122c393a42Smrg
12132c393a42Smrgstatic void
12142c393a42SmrgFcStartElement(void *userData, const XML_Char *name, const XML_Char **attr)
12152c393a42Smrg{
12162c393a42Smrg    FcConfigParse   *parse = userData;
12172c393a42Smrg    FcElement	    element;
1218ca08ab68Smrg
12192c393a42Smrg    element = FcElementMap (name);
12202c393a42Smrg    if (element == FcElementUnknown)
12212c393a42Smrg	FcConfigMessage (parse, FcSevereWarning, "unknown element \"%s\"", name);
1222ca08ab68Smrg
12232c393a42Smrg    if (!FcPStackPush (parse, element, attr))
12242c393a42Smrg    {
12252c393a42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
12262c393a42Smrg	return;
12272c393a42Smrg    }
12282c393a42Smrg    return;
12292c393a42Smrg}
12302c393a42Smrg
12312c393a42Smrgstatic void
12322c393a42SmrgFcParseBlank (FcConfigParse *parse)
12332c393a42Smrg{
1234ca08ab68Smrg    int		n = FcVStackElements (parse);
1235ca08ab68Smrg    FcChar32	i;
12362c393a42Smrg    while (n-- > 0)
12372c393a42Smrg    {
12382c393a42Smrg	FcVStack    *v = FcVStackFetch (parse, n);
1239ca08ab68Smrg	if (!parse->config->blanks)
12402c393a42Smrg	{
1241ca08ab68Smrg	    parse->config->blanks = FcBlanksCreate ();
12422c393a42Smrg	    if (!parse->config->blanks)
1243ca08ab68Smrg		goto bail;
1244ca08ab68Smrg	}
1245c9710b42Smrg	switch ((int) v->tag) {
1246ca08ab68Smrg	case FcVStackInteger:
12472c393a42Smrg	    if (!FcBlanksAdd (parse->config->blanks, v->u.integer))
1248ca08ab68Smrg		goto bail;
1249ca08ab68Smrg	    break;
1250ca08ab68Smrg	case FcVStackRange:
1251ca08ab68Smrg	    if (v->u.range.begin <= v->u.range.end)
12522c393a42Smrg	    {
1253ca08ab68Smrg	      for (i = v->u.range.begin; i <= v->u.range.end; i++)
1254ca08ab68Smrg	      {
1255ca08ab68Smrg		  if (!FcBlanksAdd (parse->config->blanks, i))
1256ca08ab68Smrg		      goto bail;
1257ca08ab68Smrg	      }
12582c393a42Smrg	    }
1259ca08ab68Smrg	    break;
1260ca08ab68Smrg	default:
1261ca08ab68Smrg	    FcConfigMessage (parse, FcSevereError, "invalid element in blank");
1262ca08ab68Smrg	    break;
12632c393a42Smrg	}
12642c393a42Smrg    }
1265ca08ab68Smrg    return;
1266ca08ab68Smrg  bail:
1267ca08ab68Smrg    FcConfigMessage (parse, FcSevereError, "out of memory");
12682c393a42Smrg}
12692c393a42Smrg
12702c393a42Smrgstatic void
12712c393a42SmrgFcParseRescan (FcConfigParse *parse)
12722c393a42Smrg{
12732c393a42Smrg    int	    n = FcVStackElements (parse);
12742c393a42Smrg    while (n-- > 0)
12752c393a42Smrg    {
12762c393a42Smrg	FcVStack    *v = FcVStackFetch (parse, n);
12772c393a42Smrg	if (v->tag != FcVStackInteger)
12782c393a42Smrg	    FcConfigMessage (parse, FcSevereWarning, "non-integer rescan");
12792c393a42Smrg	else
12802c393a42Smrg	    parse->config->rescanInterval = v->u.integer;
12812c393a42Smrg    }
12822c393a42Smrg}
12832c393a42Smrg
12842c393a42Smrgstatic void
12852c393a42SmrgFcParseInt (FcConfigParse *parse)
12862c393a42Smrg{
12872c393a42Smrg    FcChar8 *s, *end;
12882c393a42Smrg    int	    l;
1289ca08ab68Smrg
12902c393a42Smrg    if (!parse->pstack)
12912c393a42Smrg	return;
1292a6844aabSmrg    s = FcStrBufDoneStatic (&parse->pstack->str);
12932c393a42Smrg    if (!s)
12942c393a42Smrg    {
12952c393a42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
12962c393a42Smrg	return;
12972c393a42Smrg    }
12982c393a42Smrg    end = 0;
12992c393a42Smrg    l = (int) strtol ((char *) s, (char **)&end, 0);
13002c393a42Smrg    if (end != s + strlen ((char *) s))
13012c393a42Smrg	FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid integer", s);
13022c393a42Smrg    else
13032c393a42Smrg	FcVStackPushInteger (parse, l);
1304a6844aabSmrg    FcStrBufDestroy (&parse->pstack->str);
13052c393a42Smrg}
13062c393a42Smrg
13072c393a42Smrg/*
1308ca08ab68Smrg * idea copied from glib g_ascii_strtod with
1309ca08ab68Smrg * permission of the author (Alexander Larsson)
13102c393a42Smrg */
13112c393a42Smrg
13122c393a42Smrg#include <locale.h>
13132c393a42Smrg
1314ca08ab68Smrgstatic double
13152c393a42SmrgFcStrtod (char *s, char **end)
13162c393a42Smrg{
13172c393a42Smrg    struct lconv    *locale_data;
13182c393a42Smrg    char	    *dot;
13192c393a42Smrg    double	    v;
13202c393a42Smrg
13212c393a42Smrg    /*
13222c393a42Smrg     * Have to swap the decimal point to match the current locale
13232c393a42Smrg     * if that locale doesn't use 0x2e
13242c393a42Smrg     */
13252c393a42Smrg    if ((dot = strchr (s, 0x2e)) &&
13262c393a42Smrg	(locale_data = localeconv ()) &&
13272c393a42Smrg	(locale_data->decimal_point[0] != 0x2e ||
13282c393a42Smrg	 locale_data->decimal_point[1] != 0))
13292c393a42Smrg    {
13302c393a42Smrg	char	buf[128];
13312c393a42Smrg	int	slen = strlen (s);
13322c393a42Smrg	int	dlen = strlen (locale_data->decimal_point);
13332c393a42Smrg
13342c393a42Smrg	if (slen + dlen > (int) sizeof (buf))
13352c393a42Smrg	{
13362c393a42Smrg	    if (end)
13372c393a42Smrg		*end = s;
13382c393a42Smrg	    v = 0;
13392c393a42Smrg	}
13402c393a42Smrg	else
13412c393a42Smrg	{
13422c393a42Smrg	    char	*buf_end;
13432c393a42Smrg	    /* mantissa */
13442c393a42Smrg	    strncpy (buf, s, dot - s);
13452c393a42Smrg	    /* decimal point */
13462c393a42Smrg	    strcpy (buf + (dot - s), locale_data->decimal_point);
13472c393a42Smrg	    /* rest of number */
13482c393a42Smrg	    strcpy (buf + (dot - s) + dlen, dot + 1);
13492c393a42Smrg	    buf_end = 0;
13502c393a42Smrg	    v = strtod (buf, &buf_end);
13512c393a42Smrg	    if (buf_end) {
13522c393a42Smrg		buf_end = s + (buf_end - buf);
13532c393a42Smrg		if (buf_end > dot)
13542c393a42Smrg		    buf_end -= dlen - 1;
13552c393a42Smrg	    }
13562c393a42Smrg	    if (end)
13572c393a42Smrg		*end = buf_end;
13582c393a42Smrg	}
13592c393a42Smrg    }
13602c393a42Smrg    else
13612c393a42Smrg	v = strtod (s, end);
13622c393a42Smrg    return v;
13632c393a42Smrg}
13642c393a42Smrg
13652c393a42Smrgstatic void
13662c393a42SmrgFcParseDouble (FcConfigParse *parse)
13672c393a42Smrg{
13682c393a42Smrg    FcChar8 *s, *end;
13692c393a42Smrg    double  d;
1370ca08ab68Smrg
13712c393a42Smrg    if (!parse->pstack)
13722c393a42Smrg	return;
1373a6844aabSmrg    s = FcStrBufDoneStatic (&parse->pstack->str);
13742c393a42Smrg    if (!s)
13752c393a42Smrg    {
13762c393a42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
13772c393a42Smrg	return;
13782c393a42Smrg    }
13792c393a42Smrg    end = 0;
13802c393a42Smrg    d = FcStrtod ((char *) s, (char **)&end);
13812c393a42Smrg    if (end != s + strlen ((char *) s))
13822c393a42Smrg	FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid double", s);
13832c393a42Smrg    else
13842c393a42Smrg	FcVStackPushDouble (parse, d);
1385a6844aabSmrg    FcStrBufDestroy (&parse->pstack->str);
13862c393a42Smrg}
13872c393a42Smrg
13882c393a42Smrgstatic void
13892c393a42SmrgFcParseString (FcConfigParse *parse, FcVStackTag tag)
13902c393a42Smrg{
13912c393a42Smrg    FcChar8 *s;
1392ca08ab68Smrg
13932c393a42Smrg    if (!parse->pstack)
13942c393a42Smrg	return;
13952c393a42Smrg    s = FcStrBufDone (&parse->pstack->str);
13962c393a42Smrg    if (!s)
13972c393a42Smrg    {
13982c393a42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
13992c393a42Smrg	return;
14002c393a42Smrg    }
14012c393a42Smrg    if (!FcVStackPushString (parse, tag, s))
14022c393a42Smrg	FcStrFree (s);
14032c393a42Smrg}
14042c393a42Smrg
14052c393a42Smrgstatic void
1406c9710b42SmrgFcParseName (FcConfigParse *parse)
14072c393a42Smrg{
1408c9710b42Smrg    const FcChar8   *kind_string;
1409c9710b42Smrg    FcMatchKind	    kind;
1410c9710b42Smrg    FcChar8 *s;
1411c9710b42Smrg    FcObject object;
1412ca08ab68Smrg
1413c9710b42Smrg    kind_string = FcConfigGetAttribute (parse, "target");
1414c9710b42Smrg    if (!kind_string)
1415c9710b42Smrg	kind = FcMatchDefault;
1416c9710b42Smrg    else
14172c393a42Smrg    {
1418c9710b42Smrg	if (!strcmp ((char *) kind_string, "pattern"))
1419c9710b42Smrg	    kind = FcMatchPattern;
1420c9710b42Smrg	else if (!strcmp ((char *) kind_string, "font"))
1421c9710b42Smrg	    kind = FcMatchFont;
1422c9710b42Smrg	else if (!strcmp ((char *) kind_string, "default"))
1423c9710b42Smrg	    kind = FcMatchDefault;
1424c9710b42Smrg	else
1425c9710b42Smrg	{
1426c9710b42Smrg	    FcConfigMessage (parse, FcSevereWarning, "invalid name target \"%s\"", kind_string);
1427c9710b42Smrg	    return;
14282c393a42Smrg	}
14292c393a42Smrg    }
1430c9710b42Smrg
1431c9710b42Smrg    if (!parse->pstack)
1432c9710b42Smrg	return;
1433c9710b42Smrg    s = FcStrBufDone (&parse->pstack->str);
1434c9710b42Smrg    if (!s)
1435c9710b42Smrg    {
1436c9710b42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
1437c9710b42Smrg	return;
1438c9710b42Smrg    }
1439c9710b42Smrg    object = FcObjectFromName ((const char *) s);
1440c9710b42Smrg
1441c9710b42Smrg    FcVStackPushName (parse, kind, object);
1442c9710b42Smrg
1443c9710b42Smrg    FcStrFree (s);
1444c9710b42Smrg}
1445c9710b42Smrg
1446c9710b42Smrgstatic void
1447c9710b42SmrgFcParseMatrix (FcConfigParse *parse)
1448c9710b42Smrg{
1449c9710b42Smrg    FcExprMatrix m;
1450c9710b42Smrg
1451c9710b42Smrg    m.yy = FcPopExpr (parse);
1452c9710b42Smrg    m.yx = FcPopExpr (parse);
1453c9710b42Smrg    m.xy = FcPopExpr (parse);
1454c9710b42Smrg    m.xx = FcPopExpr (parse);
1455c9710b42Smrg
1456c9710b42Smrg    if (FcPopExpr (parse))
1457c9710b42Smrg      FcConfigMessage (parse, FcSevereError, "wrong number of matrix elements");
14582c393a42Smrg    else
1459c9710b42Smrg      FcVStackPushMatrix (parse, &m);
14602c393a42Smrg}
14612c393a42Smrg
1462ca08ab68Smrgstatic void
1463ca08ab68SmrgFcParseRange (FcConfigParse *parse)
1464ca08ab68Smrg{
1465ca08ab68Smrg    FcVStack	*vstack;
1466c9710b42Smrg    FcRange	r = {0, 0};
1467ca08ab68Smrg    FcChar32	n;
1468ca08ab68Smrg    int		count = 1;
1469ca08ab68Smrg
1470ca08ab68Smrg    while ((vstack = FcVStackPeek (parse)))
1471ca08ab68Smrg    {
1472ca08ab68Smrg	if (count < 0)
1473ca08ab68Smrg	{
1474ca08ab68Smrg	    FcConfigMessage (parse, FcSevereError, "too many elements in range");
1475ca08ab68Smrg	    return;
1476ca08ab68Smrg	}
1477c9710b42Smrg	switch ((int) vstack->tag) {
1478ca08ab68Smrg	case FcVStackInteger:
1479ca08ab68Smrg	    n = vstack->u.integer;
1480ca08ab68Smrg	    break;
1481ca08ab68Smrg	default:
1482ca08ab68Smrg	    FcConfigMessage (parse, FcSevereError, "invalid element in range");
1483ca08ab68Smrg	    n = 0;
1484ca08ab68Smrg	    break;
1485ca08ab68Smrg	}
1486ca08ab68Smrg	if (count == 1)
1487ca08ab68Smrg	    r.end = n;
1488ca08ab68Smrg	else
1489ca08ab68Smrg	    r.begin = n;
1490ca08ab68Smrg	count--;
1491ca08ab68Smrg	FcVStackPopAndDestroy (parse);
1492ca08ab68Smrg    }
1493ca08ab68Smrg    if (count < 0)
1494ca08ab68Smrg    {
1495ca08ab68Smrg	if (r.begin > r.end)
1496ca08ab68Smrg	{
1497ca08ab68Smrg	    FcConfigMessage (parse, FcSevereError, "invalid range");
1498ca08ab68Smrg	    return;
1499ca08ab68Smrg	}
1500ca08ab68Smrg	FcVStackPushRange (parse, &r);
1501ca08ab68Smrg    }
1502ca08ab68Smrg    else
1503ca08ab68Smrg	FcConfigMessage (parse, FcSevereError, "invalid range");
1504ca08ab68Smrg}
1505ca08ab68Smrg
15062c393a42Smrgstatic FcBool
1507a6844aabSmrgFcConfigLexBool (FcConfigParse *parse, const FcChar8 *bool_)
15082c393a42Smrg{
15092c393a42Smrg    FcBool  result = FcFalse;
15102c393a42Smrg
1511a6844aabSmrg    if (!FcNameBool (bool_, &result))
15122c393a42Smrg	FcConfigMessage (parse, FcSevereWarning, "\"%s\" is not known boolean",
1513a6844aabSmrg			 bool_);
15142c393a42Smrg    return result;
15152c393a42Smrg}
15162c393a42Smrg
15172c393a42Smrgstatic void
15182c393a42SmrgFcParseBool (FcConfigParse *parse)
15192c393a42Smrg{
15202c393a42Smrg    FcChar8 *s;
15212c393a42Smrg
15222c393a42Smrg    if (!parse->pstack)
15232c393a42Smrg	return;
1524a6844aabSmrg    s = FcStrBufDoneStatic (&parse->pstack->str);
15252c393a42Smrg    if (!s)
15262c393a42Smrg    {
15272c393a42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
15282c393a42Smrg	return;
15292c393a42Smrg    }
15302c393a42Smrg    FcVStackPushBool (parse, FcConfigLexBool (parse, s));
1531a6844aabSmrg    FcStrBufDestroy (&parse->pstack->str);
15322c393a42Smrg}
15332c393a42Smrg
1534ca08ab68Smrgstatic void
1535ca08ab68SmrgFcParseCharSet (FcConfigParse *parse)
1536ca08ab68Smrg{
1537ca08ab68Smrg    FcVStack	*vstack;
1538ca08ab68Smrg    FcCharSet	*charset = FcCharSetCreate ();
1539ca08ab68Smrg    FcChar32	i;
1540ca08ab68Smrg    int n = 0;
1541ca08ab68Smrg
1542ca08ab68Smrg    while ((vstack = FcVStackPeek (parse)))
1543ca08ab68Smrg    {
1544c9710b42Smrg	switch ((int) vstack->tag) {
1545ca08ab68Smrg	case FcVStackInteger:
1546ca08ab68Smrg	    if (!FcCharSetAddChar (charset, vstack->u.integer))
1547ca08ab68Smrg	    {
1548ca08ab68Smrg		FcConfigMessage (parse, FcSevereWarning, "invalid character: 0x%04x", vstack->u.integer);
1549ca08ab68Smrg	    }
1550ca08ab68Smrg	    else
1551ca08ab68Smrg		n++;
1552ca08ab68Smrg	    break;
1553ca08ab68Smrg	case FcVStackRange:
1554ca08ab68Smrg	    if (vstack->u.range.begin <= vstack->u.range.end)
1555ca08ab68Smrg	    {
1556ca08ab68Smrg	      for (i = vstack->u.range.begin; i <= vstack->u.range.end; i++)
1557ca08ab68Smrg	      {
1558ca08ab68Smrg		  if (!FcCharSetAddChar (charset, i))
1559ca08ab68Smrg		  {
1560ca08ab68Smrg		      FcConfigMessage (parse, FcSevereWarning, "invalid character: 0x%04x", i);
1561ca08ab68Smrg		  }
1562ca08ab68Smrg		  else
1563ca08ab68Smrg		      n++;
1564ca08ab68Smrg	      }
1565ca08ab68Smrg	    }
1566ca08ab68Smrg	    break;
1567ca08ab68Smrg	default:
1568ca08ab68Smrg		FcConfigMessage (parse, FcSevereError, "invalid element in charset");
1569ca08ab68Smrg		break;
1570ca08ab68Smrg	}
1571ca08ab68Smrg	FcVStackPopAndDestroy (parse);
1572ca08ab68Smrg    }
1573ca08ab68Smrg    if (n > 0)
1574ca08ab68Smrg	    FcVStackPushCharSet (parse, charset);
1575ca08ab68Smrg    else
1576ca08ab68Smrg	    FcCharSetDestroy (charset);
1577ca08ab68Smrg}
1578ca08ab68Smrg
1579ca08ab68Smrgstatic void
1580ca08ab68SmrgFcParseLangSet (FcConfigParse *parse)
1581ca08ab68Smrg{
1582ca08ab68Smrg    FcVStack	*vstack;
1583ca08ab68Smrg    FcLangSet	*langset = FcLangSetCreate ();
1584ca08ab68Smrg    int n = 0;
1585ca08ab68Smrg
1586ca08ab68Smrg    while ((vstack = FcVStackPeek (parse)))
1587ca08ab68Smrg    {
1588c9710b42Smrg	switch ((int) vstack->tag) {
1589ca08ab68Smrg	case FcVStackString:
1590ca08ab68Smrg	    if (!FcLangSetAdd (langset, vstack->u.string))
1591ca08ab68Smrg	    {
1592ca08ab68Smrg		FcConfigMessage (parse, FcSevereWarning, "invalid langset: %s", vstack->u.string);
1593ca08ab68Smrg	    }
1594ca08ab68Smrg	    else
1595ca08ab68Smrg		n++;
1596ca08ab68Smrg	    break;
1597ca08ab68Smrg	default:
1598ca08ab68Smrg		FcConfigMessage (parse, FcSevereError, "invalid element in langset");
1599ca08ab68Smrg		break;
1600ca08ab68Smrg	}
1601ca08ab68Smrg	FcVStackPopAndDestroy (parse);
1602ca08ab68Smrg    }
1603ca08ab68Smrg    if (n > 0)
1604ca08ab68Smrg	    FcVStackPushLangSet (parse, langset);
1605ca08ab68Smrg    else
1606ca08ab68Smrg	    FcLangSetDestroy (langset);
1607ca08ab68Smrg}
1608ca08ab68Smrg
16092c393a42Smrgstatic FcBool
16102c393a42SmrgFcConfigLexBinding (FcConfigParse   *parse,
16112c393a42Smrg		    const FcChar8   *binding_string,
16122c393a42Smrg		    FcValueBinding  *binding_ret)
16132c393a42Smrg{
16142c393a42Smrg    FcValueBinding binding;
1615ca08ab68Smrg
16162c393a42Smrg    if (!binding_string)
16172c393a42Smrg	binding = FcValueBindingWeak;
16182c393a42Smrg    else
16192c393a42Smrg    {
16202c393a42Smrg	if (!strcmp ((char *) binding_string, "weak"))
16212c393a42Smrg	    binding = FcValueBindingWeak;
16222c393a42Smrg	else if (!strcmp ((char *) binding_string, "strong"))
16232c393a42Smrg	    binding = FcValueBindingStrong;
16242c393a42Smrg	else if (!strcmp ((char *) binding_string, "same"))
16252c393a42Smrg	    binding = FcValueBindingSame;
16262c393a42Smrg	else
16272c393a42Smrg	{
16282c393a42Smrg	    FcConfigMessage (parse, FcSevereWarning, "invalid binding \"%s\"", binding_string);
16292c393a42Smrg	    return FcFalse;
16302c393a42Smrg	}
16312c393a42Smrg    }
16322c393a42Smrg    *binding_ret = binding;
16332c393a42Smrg    return FcTrue;
16342c393a42Smrg}
16352c393a42Smrg
16362c393a42Smrgstatic void
16372c393a42SmrgFcParseFamilies (FcConfigParse *parse, FcVStackTag tag)
16382c393a42Smrg{
16392c393a42Smrg    FcVStack	*vstack;
16402c393a42Smrg    FcExpr	*left, *expr = 0, *new;
16412c393a42Smrg
1642a6844aabSmrg    while ((vstack = FcVStackPeek (parse)))
16432c393a42Smrg    {
16442c393a42Smrg	if (vstack->tag != FcVStackFamily)
16452c393a42Smrg	{
16462c393a42Smrg	    FcConfigMessage (parse, FcSevereWarning, "non-family");
1647a6844aabSmrg	    FcVStackPopAndDestroy (parse);
16482c393a42Smrg	    continue;
16492c393a42Smrg	}
16502c393a42Smrg	left = vstack->u.expr;
16512c393a42Smrg	vstack->tag = FcVStackNone;
1652a6844aabSmrg	FcVStackPopAndDestroy (parse);
16532c393a42Smrg	if (expr)
16542c393a42Smrg	{
1655a6844aabSmrg	    new = FcExprCreateOp (parse->config, left, FcOpComma, expr);
16562c393a42Smrg	    if (!new)
16572c393a42Smrg	    {
16582c393a42Smrg		FcConfigMessage (parse, FcSevereError, "out of memory");
16592c393a42Smrg		FcExprDestroy (left);
16602c393a42Smrg		FcExprDestroy (expr);
16612c393a42Smrg		break;
16622c393a42Smrg	    }
16632c393a42Smrg	    expr = new;
16642c393a42Smrg	}
16652c393a42Smrg	else
16662c393a42Smrg	    expr = left;
16672c393a42Smrg    }
16682c393a42Smrg    if (expr)
16692c393a42Smrg    {
16702c393a42Smrg	if (!FcVStackPushExpr (parse, tag, expr))
16712c393a42Smrg	{
16722c393a42Smrg	    FcConfigMessage (parse, FcSevereError, "out of memory");
16732c393a42Smrg            FcExprDestroy (expr);
16742c393a42Smrg	}
16752c393a42Smrg    }
16762c393a42Smrg}
16772c393a42Smrg
16782c393a42Smrgstatic void
16792c393a42SmrgFcParseFamily (FcConfigParse *parse)
16802c393a42Smrg{
16812c393a42Smrg    FcChar8 *s;
16822c393a42Smrg    FcExpr  *expr;
16832c393a42Smrg
16842c393a42Smrg    if (!parse->pstack)
16852c393a42Smrg	return;
1686a6844aabSmrg    s = FcStrBufDoneStatic (&parse->pstack->str);
16872c393a42Smrg    if (!s)
16882c393a42Smrg    {
16892c393a42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
16902c393a42Smrg	return;
16912c393a42Smrg    }
1692a6844aabSmrg    expr = FcExprCreateString (parse->config, s);
1693a6844aabSmrg    FcStrBufDestroy (&parse->pstack->str);
16942c393a42Smrg    if (expr)
16952c393a42Smrg	FcVStackPushExpr (parse, FcVStackFamily, expr);
16962c393a42Smrg}
16972c393a42Smrg
16982c393a42Smrgstatic void
16992c393a42SmrgFcParseAlias (FcConfigParse *parse)
17002c393a42Smrg{
17012c393a42Smrg    FcExpr	*family = 0, *accept = 0, *prefer = 0, *def = 0, *new = 0;
17026fc018e4Smrg    FcEdit	*edit = 0;
17032c393a42Smrg    FcVStack	*vstack;
17046fc018e4Smrg    FcRule	*rule = NULL, *r;
17052c393a42Smrg    FcValueBinding  binding;
17062c393a42Smrg
17072c393a42Smrg    if (!FcConfigLexBinding (parse, FcConfigGetAttribute (parse, "binding"), &binding))
17082c393a42Smrg	return;
1709a6844aabSmrg    while ((vstack = FcVStackPeek (parse)))
17102c393a42Smrg    {
1711c9710b42Smrg	switch ((int) vstack->tag) {
17122c393a42Smrg	case FcVStackFamily:
17132c393a42Smrg	    if (family)
17142c393a42Smrg	    {
1715ca08ab68Smrg		FcConfigMessage (parse, FcSevereWarning, "Having multiple <family> in <alias> isn't supported and may not work as expected");
1716a6844aabSmrg		new = FcExprCreateOp (parse->config, vstack->u.expr, FcOpComma, family);
17172c393a42Smrg		if (!new)
17182c393a42Smrg		    FcConfigMessage (parse, FcSevereError, "out of memory");
17192c393a42Smrg		else
17202c393a42Smrg		    family = new;
17212c393a42Smrg	    }
17222c393a42Smrg	    else
17232c393a42Smrg		new = vstack->u.expr;
17242c393a42Smrg	    if (new)
17252c393a42Smrg	    {
17262c393a42Smrg		family = new;
17272c393a42Smrg		vstack->tag = FcVStackNone;
17282c393a42Smrg	    }
17292c393a42Smrg	    break;
17302c393a42Smrg	case FcVStackPrefer:
17312c393a42Smrg	    if (prefer)
17322c393a42Smrg		FcExprDestroy (prefer);
17332c393a42Smrg	    prefer = vstack->u.expr;
17342c393a42Smrg	    vstack->tag = FcVStackNone;
17352c393a42Smrg	    break;
17362c393a42Smrg	case FcVStackAccept:
17372c393a42Smrg	    if (accept)
17382c393a42Smrg		FcExprDestroy (accept);
17392c393a42Smrg	    accept = vstack->u.expr;
17402c393a42Smrg	    vstack->tag = FcVStackNone;
17412c393a42Smrg	    break;
17422c393a42Smrg	case FcVStackDefault:
17432c393a42Smrg	    if (def)
17442c393a42Smrg		FcExprDestroy (def);
17452c393a42Smrg	    def = vstack->u.expr;
17462c393a42Smrg	    vstack->tag = FcVStackNone;
17472c393a42Smrg	    break;
1748ca08ab68Smrg	case FcVStackTest:
17496fc018e4Smrg	    if (rule)
17506fc018e4Smrg	    {
17516fc018e4Smrg		r = FcRuleCreate (FcRuleTest, vstack->u.test);
17526fc018e4Smrg		r->next = rule;
17536fc018e4Smrg		rule = r;
17546fc018e4Smrg	    }
17556fc018e4Smrg	    else
17566fc018e4Smrg		rule = FcRuleCreate (FcRuleTest, vstack->u.test);
1757ca08ab68Smrg	    vstack->tag = FcVStackNone;
1758ca08ab68Smrg	    break;
17592c393a42Smrg	default:
17602c393a42Smrg	    FcConfigMessage (parse, FcSevereWarning, "bad alias");
17612c393a42Smrg	    break;
17622c393a42Smrg	}
1763a6844aabSmrg	FcVStackPopAndDestroy (parse);
17642c393a42Smrg    }
17652c393a42Smrg    if (!family)
17662c393a42Smrg    {
17672c393a42Smrg	FcConfigMessage (parse, FcSevereError, "missing family in alias");
17682c393a42Smrg	if (prefer)
17692c393a42Smrg	    FcExprDestroy (prefer);
17702c393a42Smrg	if (accept)
17712c393a42Smrg	    FcExprDestroy (accept);
17722c393a42Smrg	if (def)
17732c393a42Smrg	    FcExprDestroy (def);
17746fc018e4Smrg	if (rule)
17756fc018e4Smrg	    FcRuleDestroy (rule);
17762c393a42Smrg	return;
17772c393a42Smrg    }
17786fc018e4Smrg    if (!prefer &&
17796fc018e4Smrg	!accept &&
17806fc018e4Smrg	!def)
17816fc018e4Smrg    {
17826fc018e4Smrg	FcExprDestroy (family);
17836fc018e4Smrg	return;
17846fc018e4Smrg    }
17856fc018e4Smrg    else
17866fc018e4Smrg    {
17876fc018e4Smrg	FcTest *t = FcTestCreate (parse, FcMatchPattern,
17886fc018e4Smrg				  FcQualAny,
17896fc018e4Smrg				  (FcChar8 *) FC_FAMILY,
17906fc018e4Smrg				  FC_OP (FcOpEqual, FcOpFlagIgnoreBlanks),
17916fc018e4Smrg				  family);
17926fc018e4Smrg	if (rule)
17936fc018e4Smrg	{
17946fc018e4Smrg	    for (r = rule; r->next; r = r->next);
17956fc018e4Smrg	    r->next = FcRuleCreate (FcRuleTest, t);
17966fc018e4Smrg	    r = r->next;
17976fc018e4Smrg	}
17986fc018e4Smrg	else
17996fc018e4Smrg	{
18006fc018e4Smrg	    r = rule = FcRuleCreate (FcRuleTest, t);
18016fc018e4Smrg	}
18026fc018e4Smrg    }
18032c393a42Smrg    if (prefer)
18042c393a42Smrg    {
1805ca08ab68Smrg	edit = FcEditCreate (parse,
18062c393a42Smrg			     FC_FAMILY_OBJECT,
18072c393a42Smrg			     FcOpPrepend,
18082c393a42Smrg			     prefer,
18092c393a42Smrg			     binding);
18106fc018e4Smrg	if (!edit)
18112c393a42Smrg	    FcExprDestroy (prefer);
18126fc018e4Smrg	else
18136fc018e4Smrg	{
18146fc018e4Smrg	    r->next = FcRuleCreate (FcRuleEdit, edit);
18156fc018e4Smrg	    r = r->next;
18166fc018e4Smrg	}
18172c393a42Smrg    }
18182c393a42Smrg    if (accept)
18192c393a42Smrg    {
18202c393a42Smrg	edit = FcEditCreate (parse,
18212c393a42Smrg			     FC_FAMILY_OBJECT,
18222c393a42Smrg			     FcOpAppend,
18232c393a42Smrg			     accept,
18242c393a42Smrg			     binding);
18256fc018e4Smrg	if (!edit)
18262c393a42Smrg	    FcExprDestroy (accept);
18276fc018e4Smrg	else
18286fc018e4Smrg	{
18296fc018e4Smrg	    r->next = FcRuleCreate (FcRuleEdit, edit);
18306fc018e4Smrg	    r = r->next;
18316fc018e4Smrg	}
18322c393a42Smrg    }
18332c393a42Smrg    if (def)
18342c393a42Smrg    {
18352c393a42Smrg	edit = FcEditCreate (parse,
18362c393a42Smrg			     FC_FAMILY_OBJECT,
18372c393a42Smrg			     FcOpAppendLast,
18382c393a42Smrg			     def,
18392c393a42Smrg			     binding);
18406fc018e4Smrg	if (!edit)
18412c393a42Smrg	    FcExprDestroy (def);
18426fc018e4Smrg	else
1843ca08ab68Smrg	{
18446fc018e4Smrg	    r->next = FcRuleCreate (FcRuleEdit, edit);
18456fc018e4Smrg	    r = r->next;
1846ca08ab68Smrg	}
18472c393a42Smrg    }
18486fc018e4Smrg    if (!FcConfigAddRule (parse->config, rule, FcMatchPattern))
18496fc018e4Smrg	FcRuleDestroy (rule);
18502c393a42Smrg}
18512c393a42Smrg
18522c393a42Smrgstatic FcExpr *
18532c393a42SmrgFcPopExpr (FcConfigParse *parse)
18542c393a42Smrg{
1855a6844aabSmrg    FcVStack	*vstack = FcVStackPeek (parse);
18562c393a42Smrg    FcExpr	*expr = 0;
18572c393a42Smrg    if (!vstack)
18582c393a42Smrg	return 0;
1859c9710b42Smrg    switch ((int) vstack->tag) {
18602c393a42Smrg    case FcVStackNone:
18612c393a42Smrg	break;
18622c393a42Smrg    case FcVStackString:
18632c393a42Smrg    case FcVStackFamily:
1864a6844aabSmrg	expr = FcExprCreateString (parse->config, vstack->u.string);
18652c393a42Smrg	break;
1866c9710b42Smrg    case FcVStackName:
1867c9710b42Smrg	expr = FcExprCreateName (parse->config, vstack->u.name);
18682c393a42Smrg	break;
18692c393a42Smrg    case FcVStackConstant:
1870a6844aabSmrg	expr = FcExprCreateConst (parse->config, vstack->u.string);
18712c393a42Smrg	break;
18722c393a42Smrg    case FcVStackGlob:
18732c393a42Smrg	/* XXX: What's the correct action here? (CDW) */
18742c393a42Smrg	break;
18752c393a42Smrg    case FcVStackPrefer:
18762c393a42Smrg    case FcVStackAccept:
18772c393a42Smrg    case FcVStackDefault:
18782c393a42Smrg	expr = vstack->u.expr;
18792c393a42Smrg	vstack->tag = FcVStackNone;
18802c393a42Smrg	break;
18812c393a42Smrg    case FcVStackInteger:
1882a6844aabSmrg	expr = FcExprCreateInteger (parse->config, vstack->u.integer);
18832c393a42Smrg	break;
18842c393a42Smrg    case FcVStackDouble:
1885a6844aabSmrg	expr = FcExprCreateDouble (parse->config, vstack->u._double);
18862c393a42Smrg	break;
18872c393a42Smrg    case FcVStackMatrix:
1888a6844aabSmrg	expr = FcExprCreateMatrix (parse->config, vstack->u.matrix);
18892c393a42Smrg	break;
1890ca08ab68Smrg    case FcVStackRange:
1891ca08ab68Smrg	break;
18922c393a42Smrg    case FcVStackBool:
1893a6844aabSmrg	expr = FcExprCreateBool (parse->config, vstack->u.bool_);
18942c393a42Smrg	break;
1895ca08ab68Smrg    case FcVStackCharSet:
1896ca08ab68Smrg	expr = FcExprCreateCharSet (parse->config, vstack->u.charset);
1897ca08ab68Smrg	break;
1898ca08ab68Smrg    case FcVStackLangSet:
1899ca08ab68Smrg	expr = FcExprCreateLangSet (parse->config, vstack->u.langset);
1900ca08ab68Smrg	break;
19012c393a42Smrg    case FcVStackTest:
19022c393a42Smrg	break;
19032c393a42Smrg    case FcVStackExpr:
19042c393a42Smrg	expr = vstack->u.expr;
19052c393a42Smrg	vstack->tag = FcVStackNone;
19062c393a42Smrg	break;
19072c393a42Smrg    case FcVStackEdit:
19082c393a42Smrg	break;
19092c393a42Smrg    default:
19102c393a42Smrg	break;
19112c393a42Smrg    }
1912a6844aabSmrg    FcVStackPopAndDestroy (parse);
19132c393a42Smrg    return expr;
19142c393a42Smrg}
19152c393a42Smrg
19162c393a42Smrg/*
19172c393a42Smrg * This builds a tree of binary operations.  Note
19182c393a42Smrg * that every operator is defined so that if only
19192c393a42Smrg * a single operand is contained, the value of the
19202c393a42Smrg * whole expression is the value of the operand.
19212c393a42Smrg *
19222c393a42Smrg * This code reduces in that case to returning that
19232c393a42Smrg * operand.
19242c393a42Smrg */
19252c393a42Smrgstatic FcExpr *
19262c393a42SmrgFcPopBinary (FcConfigParse *parse, FcOp op)
19272c393a42Smrg{
19282c393a42Smrg    FcExpr  *left, *expr = 0, *new;
19292c393a42Smrg
19302c393a42Smrg    while ((left = FcPopExpr (parse)))
19312c393a42Smrg    {
19322c393a42Smrg	if (expr)
19332c393a42Smrg	{
1934a6844aabSmrg	    new = FcExprCreateOp (parse->config, left, op, expr);
19352c393a42Smrg	    if (!new)
19362c393a42Smrg	    {
19372c393a42Smrg		FcConfigMessage (parse, FcSevereError, "out of memory");
19382c393a42Smrg		FcExprDestroy (left);
19392c393a42Smrg		FcExprDestroy (expr);
19402c393a42Smrg		return 0;
19412c393a42Smrg	    }
19422c393a42Smrg	    expr = new;
19432c393a42Smrg	}
19442c393a42Smrg	else
19452c393a42Smrg	    expr = left;
19462c393a42Smrg    }
19472c393a42Smrg    return expr;
19482c393a42Smrg}
19492c393a42Smrg
19502c393a42Smrgstatic void
19512c393a42SmrgFcParseBinary (FcConfigParse *parse, FcOp op)
19522c393a42Smrg{
19532c393a42Smrg    FcExpr  *expr = FcPopBinary (parse, op);
19542c393a42Smrg    if (expr)
19552c393a42Smrg	FcVStackPushExpr (parse, FcVStackExpr, expr);
19562c393a42Smrg}
19572c393a42Smrg
19582c393a42Smrg/*
19592c393a42Smrg * This builds a a unary operator, it consumes only
19602c393a42Smrg * a single operand
19612c393a42Smrg */
19622c393a42Smrg
19632c393a42Smrgstatic FcExpr *
19642c393a42SmrgFcPopUnary (FcConfigParse *parse, FcOp op)
19652c393a42Smrg{
19662c393a42Smrg    FcExpr  *operand, *new = 0;
19672c393a42Smrg
19682c393a42Smrg    if ((operand = FcPopExpr (parse)))
19692c393a42Smrg    {
1970a6844aabSmrg	new = FcExprCreateOp (parse->config, operand, op, 0);
19712c393a42Smrg	if (!new)
19722c393a42Smrg	{
19732c393a42Smrg	    FcExprDestroy (operand);
19742c393a42Smrg	    FcConfigMessage (parse, FcSevereError, "out of memory");
19752c393a42Smrg	}
19762c393a42Smrg    }
19772c393a42Smrg    return new;
19782c393a42Smrg}
19792c393a42Smrg
19802c393a42Smrgstatic void
19812c393a42SmrgFcParseUnary (FcConfigParse *parse, FcOp op)
19822c393a42Smrg{
19832c393a42Smrg    FcExpr  *expr = FcPopUnary (parse, op);
19842c393a42Smrg    if (expr)
19852c393a42Smrg	FcVStackPushExpr (parse, FcVStackExpr, expr);
19862c393a42Smrg}
19872c393a42Smrg
1988ca08ab68Smrgstatic void
1989ca08ab68SmrgFcParseDir (FcConfigParse *parse)
1990ca08ab68Smrg{
1991ca08ab68Smrg    const FcChar8 *attr, *data;
1992c9710b42Smrg    FcChar8 *prefix = NULL, *p;
1993ca08ab68Smrg#ifdef _WIN32
1994ca08ab68Smrg    FcChar8         buffer[1000];
1995ca08ab68Smrg#endif
1996ca08ab68Smrg
1997ca08ab68Smrg    attr = FcConfigGetAttribute (parse, "prefix");
1998ca08ab68Smrg    if (attr && FcStrCmp (attr, (const FcChar8 *)"xdg") == 0)
1999ca08ab68Smrg	prefix = FcConfigXdgDataHome ();
2000ca08ab68Smrg    data = FcStrBufDoneStatic (&parse->pstack->str);
2001ca08ab68Smrg    if (!data)
2002ca08ab68Smrg    {
2003ca08ab68Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
2004c9710b42Smrg	data = prefix;
2005ca08ab68Smrg	goto bail;
2006ca08ab68Smrg    }
2007ca08ab68Smrg    if (prefix)
2008ca08ab68Smrg    {
2009ca08ab68Smrg	size_t plen = strlen ((const char *)prefix);
2010ca08ab68Smrg	size_t dlen = strlen ((const char *)data);
2011ca08ab68Smrg
2012c9710b42Smrg	p = realloc (prefix, plen + 1 + dlen + 1);
2013c9710b42Smrg	if (!p)
2014ca08ab68Smrg	{
2015ca08ab68Smrg	    FcConfigMessage (parse, FcSevereError, "out of memory");
2016ca08ab68Smrg	    goto bail;
2017ca08ab68Smrg	}
2018c9710b42Smrg	prefix = p;
2019ca08ab68Smrg	prefix[plen] = FC_DIR_SEPARATOR;
2020ca08ab68Smrg	memcpy (&prefix[plen + 1], data, dlen);
2021ca08ab68Smrg	prefix[plen + 1 + dlen] = 0;
2022ca08ab68Smrg	data = prefix;
2023ca08ab68Smrg    }
2024ca08ab68Smrg#ifdef _WIN32
2025ca08ab68Smrg    if (strcmp ((const char *) data, "CUSTOMFONTDIR") == 0)
2026ca08ab68Smrg    {
2027c9710b42Smrg	FcChar8 *p;
2028ca08ab68Smrg	data = buffer;
2029ca08ab68Smrg	if (!GetModuleFileName (NULL, (LPCH) buffer, sizeof (buffer) - 20))
2030ca08ab68Smrg	{
2031ca08ab68Smrg	    FcConfigMessage (parse, FcSevereError, "GetModuleFileName failed");
2032ca08ab68Smrg	    goto bail;
2033ca08ab68Smrg	}
2034ca08ab68Smrg	/*
2035ca08ab68Smrg	 * Must use the multi-byte aware function to search
2036ca08ab68Smrg	 * for backslash because East Asian double-byte code
2037ca08ab68Smrg	 * pages have characters with backslash as the second
2038ca08ab68Smrg	 * byte.
2039ca08ab68Smrg	 */
2040ca08ab68Smrg	p = _mbsrchr (data, '\\');
2041ca08ab68Smrg	if (p) *p = '\0';
2042c9710b42Smrg	strcat ((char *) data, "\\fonts");
2043ca08ab68Smrg    }
2044ca08ab68Smrg    else if (strcmp ((const char *) data, "APPSHAREFONTDIR") == 0)
2045ca08ab68Smrg    {
2046c9710b42Smrg	FcChar8 *p;
2047ca08ab68Smrg	data = buffer;
2048ca08ab68Smrg	if (!GetModuleFileName (NULL, (LPCH) buffer, sizeof (buffer) - 20))
2049ca08ab68Smrg	{
2050ca08ab68Smrg	    FcConfigMessage (parse, FcSevereError, "GetModuleFileName failed");
2051ca08ab68Smrg	    goto bail;
2052ca08ab68Smrg	}
2053ca08ab68Smrg	p = _mbsrchr (data, '\\');
2054ca08ab68Smrg	if (p) *p = '\0';
2055c9710b42Smrg	strcat ((char *) data, "\\..\\share\\fonts");
2056ca08ab68Smrg    }
2057ca08ab68Smrg    else if (strcmp ((const char *) data, "WINDOWSFONTDIR") == 0)
2058ca08ab68Smrg    {
2059ca08ab68Smrg	int rc;
2060ca08ab68Smrg	data = buffer;
2061ca08ab68Smrg	rc = pGetSystemWindowsDirectory ((LPSTR) buffer, sizeof (buffer) - 20);
2062ca08ab68Smrg	if (rc == 0 || rc > sizeof (buffer) - 20)
2063ca08ab68Smrg	{
2064ca08ab68Smrg	    FcConfigMessage (parse, FcSevereError, "GetSystemWindowsDirectory failed");
2065ca08ab68Smrg	    goto bail;
2066ca08ab68Smrg	}
2067ca08ab68Smrg	if (data [strlen ((const char *) data) - 1] != '\\')
2068c9710b42Smrg	    strcat ((char *) data, "\\");
2069c9710b42Smrg	strcat ((char *) data, "fonts");
2070ca08ab68Smrg    }
2071ca08ab68Smrg#endif
2072ca08ab68Smrg    if (strlen ((char *) data) == 0)
2073ca08ab68Smrg	FcConfigMessage (parse, FcSevereWarning, "empty font directory name ignored");
2074ca08ab68Smrg    else if (!FcStrUsesHome (data) || FcConfigHome ())
2075ca08ab68Smrg    {
2076ca08ab68Smrg	if (!FcConfigAddDir (parse->config, data))
2077ca08ab68Smrg	    FcConfigMessage (parse, FcSevereError, "out of memory; cannot add directory %s", data);
2078ca08ab68Smrg    }
2079ca08ab68Smrg    FcStrBufDestroy (&parse->pstack->str);
2080ca08ab68Smrg
2081ca08ab68Smrg  bail:
2082ca08ab68Smrg    if (prefix)
2083ca08ab68Smrg	FcStrFree (prefix);
2084ca08ab68Smrg}
2085ca08ab68Smrg
2086ca08ab68Smrgstatic void
2087ca08ab68SmrgFcParseCacheDir (FcConfigParse *parse)
2088ca08ab68Smrg{
2089ca08ab68Smrg    const FcChar8 *attr;
2090c9710b42Smrg    FcChar8 *prefix = NULL, *p, *data;
2091ca08ab68Smrg
2092ca08ab68Smrg    attr = FcConfigGetAttribute (parse, "prefix");
2093ca08ab68Smrg    if (attr && FcStrCmp (attr, (const FcChar8 *)"xdg") == 0)
2094ca08ab68Smrg	prefix = FcConfigXdgCacheHome ();
2095ca08ab68Smrg    data = FcStrBufDone (&parse->pstack->str);
2096ca08ab68Smrg    if (!data)
2097ca08ab68Smrg    {
2098ca08ab68Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
2099ca08ab68Smrg	goto bail;
2100ca08ab68Smrg    }
2101ca08ab68Smrg    if (prefix)
2102ca08ab68Smrg    {
2103ca08ab68Smrg	size_t plen = strlen ((const char *)prefix);
2104ca08ab68Smrg	size_t dlen = strlen ((const char *)data);
2105ca08ab68Smrg
2106c9710b42Smrg	p = realloc (prefix, plen + 1 + dlen + 1);
2107c9710b42Smrg	if (!p)
2108ca08ab68Smrg	{
2109ca08ab68Smrg	    FcConfigMessage (parse, FcSevereError, "out of memory");
2110c9710b42Smrg	    data = prefix;
2111ca08ab68Smrg	    goto bail;
2112ca08ab68Smrg	}
2113c9710b42Smrg	prefix = p;
2114ca08ab68Smrg	prefix[plen] = FC_DIR_SEPARATOR;
2115ca08ab68Smrg	memcpy (&prefix[plen + 1], data, dlen);
2116ca08ab68Smrg	prefix[plen + 1 + dlen] = 0;
2117ca08ab68Smrg	FcStrFree (data);
2118ca08ab68Smrg	data = prefix;
2119ca08ab68Smrg    }
2120ca08ab68Smrg#ifdef _WIN32
2121ca08ab68Smrg    if (strcmp ((const char *) data, "WINDOWSTEMPDIR_FONTCONFIG_CACHE") == 0)
2122ca08ab68Smrg    {
2123ca08ab68Smrg	int rc;
2124ca08ab68Smrg	FcStrFree (data);
2125ca08ab68Smrg	data = malloc (1000);
2126ca08ab68Smrg	if (!data)
2127ca08ab68Smrg	{
2128ca08ab68Smrg	    FcConfigMessage (parse, FcSevereError, "out of memory");
2129ca08ab68Smrg	    goto bail;
2130ca08ab68Smrg	}
2131ca08ab68Smrg	rc = GetTempPath (800, (LPSTR) data);
2132ca08ab68Smrg	if (rc == 0 || rc > 800)
2133ca08ab68Smrg	{
2134ca08ab68Smrg	    FcConfigMessage (parse, FcSevereError, "GetTempPath failed");
2135ca08ab68Smrg	    goto bail;
2136ca08ab68Smrg	}
2137ca08ab68Smrg	if (data [strlen ((const char *) data) - 1] != '\\')
2138c9710b42Smrg	    strcat ((char *) data, "\\");
2139c9710b42Smrg	strcat ((char *) data, "fontconfig\\cache");
2140ca08ab68Smrg    }
2141ca08ab68Smrg    else if (strcmp ((const char *) data, "LOCAL_APPDATA_FONTCONFIG_CACHE") == 0)
2142ca08ab68Smrg    {
2143ca08ab68Smrg	char szFPath[MAX_PATH + 1];
2144ca08ab68Smrg	size_t len;
2145ca08ab68Smrg
2146ca08ab68Smrg	if (!(pSHGetFolderPathA && SUCCEEDED(pSHGetFolderPathA(NULL, /* CSIDL_LOCAL_APPDATA */ 28, NULL, 0, szFPath))))
2147ca08ab68Smrg	{
2148ca08ab68Smrg	    FcConfigMessage (parse, FcSevereError, "SHGetFolderPathA failed");
2149ca08ab68Smrg	    goto bail;
2150ca08ab68Smrg	}
2151ca08ab68Smrg	strncat(szFPath, "\\fontconfig\\cache", MAX_PATH - 1 - strlen(szFPath));
2152ca08ab68Smrg	len = strlen(szFPath) + 1;
2153ca08ab68Smrg	FcStrFree (data);
2154ca08ab68Smrg	data = malloc(len);
2155ca08ab68Smrg	if (!data)
2156ca08ab68Smrg	{
2157ca08ab68Smrg	    FcConfigMessage (parse, FcSevereError, "out of memory");
2158ca08ab68Smrg	    goto bail;
2159ca08ab68Smrg	}
2160ca08ab68Smrg	strncpy((char *) data, szFPath, len);
2161ca08ab68Smrg    }
2162ca08ab68Smrg#endif
2163ca08ab68Smrg    if (strlen ((char *) data) == 0)
2164ca08ab68Smrg	FcConfigMessage (parse, FcSevereWarning, "empty cache directory name ignored");
2165ca08ab68Smrg    else if (!FcStrUsesHome (data) || FcConfigHome ())
2166ca08ab68Smrg    {
2167ca08ab68Smrg	if (!FcConfigAddCacheDir (parse->config, data))
2168ca08ab68Smrg	    FcConfigMessage (parse, FcSevereError, "out of memory; cannot add cache directory %s", data);
2169ca08ab68Smrg    }
2170ca08ab68Smrg    FcStrBufDestroy (&parse->pstack->str);
2171ca08ab68Smrg
2172ca08ab68Smrg  bail:
2173ca08ab68Smrg    if (data)
2174ca08ab68Smrg	FcStrFree (data);
2175ca08ab68Smrg}
2176ca08ab68Smrg
21772c393a42Smrgstatic void
21782c393a42SmrgFcParseInclude (FcConfigParse *parse)
21792c393a42Smrg{
21802c393a42Smrg    FcChar8	    *s;
2181ca08ab68Smrg    const FcChar8   *attr;
21822c393a42Smrg    FcBool	    ignore_missing = FcFalse;
2183ca08ab68Smrg    FcBool	    deprecated = FcFalse;
2184c9710b42Smrg    FcChar8	    *prefix = NULL, *p;
21856fc018e4Smrg    static FcChar8  *userdir = NULL;
21866fc018e4Smrg    static FcChar8  *userconf = NULL;
2187ca08ab68Smrg
2188a6844aabSmrg    s = FcStrBufDoneStatic (&parse->pstack->str);
21892c393a42Smrg    if (!s)
21902c393a42Smrg    {
21912c393a42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
2192ca08ab68Smrg	goto bail;
21932c393a42Smrg    }
2194ca08ab68Smrg    attr = FcConfigGetAttribute (parse, "ignore_missing");
2195ca08ab68Smrg    if (attr && FcConfigLexBool (parse, (FcChar8 *) attr) == FcTrue)
21962c393a42Smrg	ignore_missing = FcTrue;
2197ca08ab68Smrg    attr = FcConfigGetAttribute (parse, "deprecated");
2198ca08ab68Smrg    if (attr && FcConfigLexBool (parse, (FcChar8 *) attr) == FcTrue)
2199ca08ab68Smrg        deprecated = FcTrue;
2200ca08ab68Smrg    attr = FcConfigGetAttribute (parse, "prefix");
2201ca08ab68Smrg    if (attr && FcStrCmp (attr, (const FcChar8 *)"xdg") == 0)
2202ca08ab68Smrg	prefix = FcConfigXdgConfigHome ();
2203ca08ab68Smrg    if (prefix)
2204ca08ab68Smrg    {
2205ca08ab68Smrg	size_t plen = strlen ((const char *)prefix);
2206ca08ab68Smrg	size_t dlen = strlen ((const char *)s);
2207ca08ab68Smrg
2208c9710b42Smrg	p = realloc (prefix, plen + 1 + dlen + 1);
2209c9710b42Smrg	if (!p)
2210ca08ab68Smrg	{
2211ca08ab68Smrg	    FcConfigMessage (parse, FcSevereError, "out of memory");
2212ca08ab68Smrg	    goto bail;
2213ca08ab68Smrg	}
2214c9710b42Smrg	prefix = p;
2215ca08ab68Smrg	prefix[plen] = FC_DIR_SEPARATOR;
2216ca08ab68Smrg	memcpy (&prefix[plen + 1], s, dlen);
2217ca08ab68Smrg	prefix[plen + 1 + dlen] = 0;
2218ca08ab68Smrg	s = prefix;
22196fc018e4Smrg	if (FcFileIsDir (s))
22206fc018e4Smrg	{
22216fc018e4Smrg	userdir:
22226fc018e4Smrg	    if (!userdir)
22236fc018e4Smrg		userdir = FcStrdup (s);
22246fc018e4Smrg	}
22256fc018e4Smrg	else if (FcFileIsFile (s))
22266fc018e4Smrg	{
22276fc018e4Smrg	userconf:
22286fc018e4Smrg	    if (!userconf)
22296fc018e4Smrg		userconf = FcStrdup (s);
22306fc018e4Smrg	}
22316fc018e4Smrg	else
22326fc018e4Smrg	{
22336fc018e4Smrg	    /* No config dir nor file on the XDG directory spec compliant place
22346fc018e4Smrg	     * so need to guess what it is supposed to be.
22356fc018e4Smrg	     */
22366fc018e4Smrg	    if (FcStrStr (s, (const FcChar8 *)"conf.d") != NULL)
22376fc018e4Smrg		goto userdir;
22386fc018e4Smrg	    else
22396fc018e4Smrg		goto userconf;
22406fc018e4Smrg	}
2241ca08ab68Smrg    }
22422c393a42Smrg    if (!FcConfigParseAndLoad (parse->config, s, !ignore_missing))
22432c393a42Smrg	parse->error = FcTrue;
22446fc018e4Smrg#ifndef _WIN32
2245ca08ab68Smrg    else
2246ca08ab68Smrg    {
2247ca08ab68Smrg        FcChar8 *filename;
22486fc018e4Smrg	static FcBool warn_conf = FcFalse, warn_confd = FcFalse;
2249ca08ab68Smrg
2250ca08ab68Smrg        filename = FcConfigFilename(s);
2251c9710b42Smrg	if (deprecated == FcTrue &&
2252c9710b42Smrg	    filename != NULL &&
2253c9710b42Smrg	    !FcFileIsLink (filename))
2254c9710b42Smrg	{
22556fc018e4Smrg	    if (FcFileIsDir (filename))
22566fc018e4Smrg	    {
22576fc018e4Smrg		FcChar8 *parent = FcStrDirname (userdir);
22586fc018e4Smrg
22596fc018e4Smrg		if (!FcFileIsDir (parent))
22606fc018e4Smrg		    FcMakeDirectory (parent);
22616fc018e4Smrg		FcStrFree (parent);
22626fc018e4Smrg		if (FcFileIsDir (userdir) ||
22636fc018e4Smrg		    rename ((const char *)filename, (const char *)userdir) != 0 ||
22646fc018e4Smrg		    symlink ((const char *)userdir, (const char *)filename) != 0)
22656fc018e4Smrg		{
22666fc018e4Smrg		    if (!warn_confd)
22676fc018e4Smrg		    {
22686fc018e4Smrg			FcConfigMessage (parse, FcSevereWarning, "reading configurations from %s is deprecated. please move it to %s manually", s, userdir);
22696fc018e4Smrg			warn_confd = FcTrue;
22706fc018e4Smrg		    }
22716fc018e4Smrg		}
22726fc018e4Smrg	    }
22736fc018e4Smrg	    else
22746fc018e4Smrg	    {
22756fc018e4Smrg		FcChar8 *parent = FcStrDirname (userconf);
22766fc018e4Smrg
22776fc018e4Smrg		if (!FcFileIsDir (parent))
22786fc018e4Smrg		    FcMakeDirectory (parent);
22796fc018e4Smrg		FcStrFree (parent);
22806fc018e4Smrg		if (FcFileIsFile (userconf) ||
22816fc018e4Smrg		    rename ((const char *)filename, (const char *)userconf) != 0 ||
22826fc018e4Smrg		    symlink ((const char *)userconf, (const char *)filename) != 0)
22836fc018e4Smrg		{
22846fc018e4Smrg		    if (!warn_conf)
22856fc018e4Smrg		    {
22866fc018e4Smrg			FcConfigMessage (parse, FcSevereWarning, "reading configurations from %s is deprecated. please move it to %s manually", s, userconf);
22876fc018e4Smrg			warn_conf = FcTrue;
22886fc018e4Smrg		    }
22896fc018e4Smrg		}
22906fc018e4Smrg	    }
2291ca08ab68Smrg        }
2292ca08ab68Smrg        if(filename)
2293ca08ab68Smrg            FcStrFree(filename);
2294ca08ab68Smrg    }
22956fc018e4Smrg#endif
2296a6844aabSmrg    FcStrBufDestroy (&parse->pstack->str);
2297ca08ab68Smrg
2298ca08ab68Smrg  bail:
2299ca08ab68Smrg    if (prefix)
2300ca08ab68Smrg	FcStrFree (prefix);
23012c393a42Smrg}
23022c393a42Smrg
23032c393a42Smrgtypedef struct _FcOpMap {
23042c393a42Smrg    char    name[16];
23052c393a42Smrg    FcOp    op;
23062c393a42Smrg} FcOpMap;
23072c393a42Smrg
23082c393a42Smrgstatic FcOp
23092c393a42SmrgFcConfigLexOp (const FcChar8 *op, const FcOpMap	*map, int nmap)
23102c393a42Smrg{
23112c393a42Smrg    int	i;
23122c393a42Smrg
23132c393a42Smrg    for (i = 0; i < nmap; i++)
2314ca08ab68Smrg	if (!strcmp ((char *) op, map[i].name))
23152c393a42Smrg	    return map[i].op;
23162c393a42Smrg    return FcOpInvalid;
23172c393a42Smrg}
23182c393a42Smrg
23192c393a42Smrgstatic const FcOpMap fcCompareOps[] = {
23202c393a42Smrg    { "eq",		FcOpEqual	    },
23212c393a42Smrg    { "not_eq",		FcOpNotEqual	    },
23222c393a42Smrg    { "less",		FcOpLess	    },
23232c393a42Smrg    { "less_eq",	FcOpLessEqual	    },
23242c393a42Smrg    { "more",		FcOpMore	    },
23252c393a42Smrg    { "more_eq",	FcOpMoreEqual	    },
23262c393a42Smrg    { "contains",	FcOpContains	    },
23272c393a42Smrg    { "not_contains",	FcOpNotContains	    }
23282c393a42Smrg};
23292c393a42Smrg
23302c393a42Smrg#define NUM_COMPARE_OPS	(int) (sizeof fcCompareOps / sizeof fcCompareOps[0])
23312c393a42Smrg
23322c393a42Smrgstatic FcOp
23332c393a42SmrgFcConfigLexCompare (const FcChar8 *compare)
23342c393a42Smrg{
23352c393a42Smrg    return FcConfigLexOp (compare, fcCompareOps, NUM_COMPARE_OPS);
23362c393a42Smrg}
23372c393a42Smrg
23382c393a42Smrgstatic void
23392c393a42SmrgFcParseTest (FcConfigParse *parse)
23402c393a42Smrg{
23412c393a42Smrg    const FcChar8   *kind_string;
23422c393a42Smrg    FcMatchKind	    kind;
23432c393a42Smrg    const FcChar8   *qual_string;
23442c393a42Smrg    FcQual	    qual;
23452c393a42Smrg    const FcChar8   *name;
23462c393a42Smrg    const FcChar8   *compare_string;
23472c393a42Smrg    FcOp	    compare;
23482c393a42Smrg    FcExpr	    *expr;
23492c393a42Smrg    FcTest	    *test;
2350ca08ab68Smrg    const FcChar8   *iblanks_string;
2351ca08ab68Smrg    int              flags = 0;
23522c393a42Smrg
23532c393a42Smrg    kind_string = FcConfigGetAttribute (parse, "target");
23542c393a42Smrg    if (!kind_string)
23552c393a42Smrg	kind = FcMatchDefault;
23562c393a42Smrg    else
23572c393a42Smrg    {
23582c393a42Smrg	if (!strcmp ((char *) kind_string, "pattern"))
23592c393a42Smrg	    kind = FcMatchPattern;
23602c393a42Smrg	else if (!strcmp ((char *) kind_string, "font"))
23612c393a42Smrg	    kind = FcMatchFont;
23622c393a42Smrg	else if (!strcmp ((char *) kind_string, "scan"))
23632c393a42Smrg	    kind = FcMatchScan;
23642c393a42Smrg	else if (!strcmp ((char *) kind_string, "default"))
23652c393a42Smrg	    kind = FcMatchDefault;
23662c393a42Smrg	else
23672c393a42Smrg	{
23682c393a42Smrg	    FcConfigMessage (parse, FcSevereWarning, "invalid test target \"%s\"", kind_string);
23692c393a42Smrg	    return;
23702c393a42Smrg	}
23712c393a42Smrg    }
23722c393a42Smrg    qual_string = FcConfigGetAttribute (parse, "qual");
23732c393a42Smrg    if (!qual_string)
23742c393a42Smrg	qual = FcQualAny;
23752c393a42Smrg    else
23762c393a42Smrg    {
23772c393a42Smrg	if (!strcmp ((char *) qual_string, "any"))
23782c393a42Smrg	    qual = FcQualAny;
23792c393a42Smrg	else if (!strcmp ((char *) qual_string, "all"))
23802c393a42Smrg	    qual = FcQualAll;
23812c393a42Smrg	else if (!strcmp ((char *) qual_string, "first"))
23822c393a42Smrg	    qual = FcQualFirst;
23832c393a42Smrg	else if (!strcmp ((char *) qual_string, "not_first"))
23842c393a42Smrg	    qual = FcQualNotFirst;
23852c393a42Smrg	else
23862c393a42Smrg	{
23872c393a42Smrg	    FcConfigMessage (parse, FcSevereWarning, "invalid test qual \"%s\"", qual_string);
23882c393a42Smrg	    return;
23892c393a42Smrg	}
23902c393a42Smrg    }
23912c393a42Smrg    name = FcConfigGetAttribute (parse, "name");
23922c393a42Smrg    if (!name)
23932c393a42Smrg    {
23942c393a42Smrg	FcConfigMessage (parse, FcSevereWarning, "missing test name");
23952c393a42Smrg	return;
23962c393a42Smrg    }
23972c393a42Smrg    compare_string = FcConfigGetAttribute (parse, "compare");
23982c393a42Smrg    if (!compare_string)
23992c393a42Smrg	compare = FcOpEqual;
24002c393a42Smrg    else
24012c393a42Smrg    {
24022c393a42Smrg	compare = FcConfigLexCompare (compare_string);
24032c393a42Smrg	if (compare == FcOpInvalid)
24042c393a42Smrg	{
24052c393a42Smrg	    FcConfigMessage (parse, FcSevereWarning, "invalid test compare \"%s\"", compare_string);
24062c393a42Smrg	    return;
24072c393a42Smrg	}
24082c393a42Smrg    }
2409ca08ab68Smrg    iblanks_string = FcConfigGetAttribute (parse, "ignore-blanks");
2410ca08ab68Smrg    if (iblanks_string)
2411ca08ab68Smrg    {
2412ca08ab68Smrg	FcBool f = FcFalse;
2413ca08ab68Smrg
2414ca08ab68Smrg	if (!FcNameBool (iblanks_string, &f))
2415ca08ab68Smrg	{
2416ca08ab68Smrg	    FcConfigMessage (parse,
2417ca08ab68Smrg			     FcSevereWarning,
2418ca08ab68Smrg			     "invalid test ignore-blanks \"%s\"", iblanks_string);
2419ca08ab68Smrg	}
2420ca08ab68Smrg	if (f)
2421ca08ab68Smrg	    flags |= FcOpFlagIgnoreBlanks;
2422ca08ab68Smrg    }
24232c393a42Smrg    expr = FcPopBinary (parse, FcOpComma);
24242c393a42Smrg    if (!expr)
24252c393a42Smrg    {
24262c393a42Smrg	FcConfigMessage (parse, FcSevereWarning, "missing test expression");
24272c393a42Smrg	return;
24282c393a42Smrg    }
2429ca08ab68Smrg    if (expr->op == FcOpComma)
2430ca08ab68Smrg    {
2431ca08ab68Smrg	FcConfigMessage (parse, FcSevereWarning, "Having multiple values in <test> isn't supported and may not work as expected");
2432ca08ab68Smrg    }
2433ca08ab68Smrg    test = FcTestCreate (parse, kind, qual, name, FC_OP (compare, flags), expr);
24342c393a42Smrg    if (!test)
24352c393a42Smrg    {
24362c393a42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
24372c393a42Smrg	return;
24382c393a42Smrg    }
24392c393a42Smrg    FcVStackPushTest (parse, test);
24402c393a42Smrg}
24412c393a42Smrg
24422c393a42Smrgstatic const FcOpMap fcModeOps[] = {
24432c393a42Smrg    { "assign",		FcOpAssign	    },
24442c393a42Smrg    { "assign_replace",	FcOpAssignReplace   },
24452c393a42Smrg    { "prepend",	FcOpPrepend	    },
24462c393a42Smrg    { "prepend_first",	FcOpPrependFirst    },
24472c393a42Smrg    { "append",		FcOpAppend	    },
24482c393a42Smrg    { "append_last",	FcOpAppendLast	    },
2449c9710b42Smrg    { "delete",		FcOpDelete	    },
2450c9710b42Smrg    { "delete_all",	FcOpDeleteAll	    },
24512c393a42Smrg};
24522c393a42Smrg
24532c393a42Smrg#define NUM_MODE_OPS (int) (sizeof fcModeOps / sizeof fcModeOps[0])
24542c393a42Smrg
24552c393a42Smrgstatic FcOp
24562c393a42SmrgFcConfigLexMode (const FcChar8 *mode)
24572c393a42Smrg{
24582c393a42Smrg    return FcConfigLexOp (mode, fcModeOps, NUM_MODE_OPS);
24592c393a42Smrg}
24602c393a42Smrg
24612c393a42Smrgstatic void
24622c393a42SmrgFcParseEdit (FcConfigParse *parse)
24632c393a42Smrg{
24642c393a42Smrg    const FcChar8   *name;
24652c393a42Smrg    const FcChar8   *mode_string;
24662c393a42Smrg    FcOp	    mode;
24672c393a42Smrg    FcValueBinding  binding;
24682c393a42Smrg    FcExpr	    *expr;
24692c393a42Smrg    FcEdit	    *edit;
24702c393a42Smrg
24712c393a42Smrg    name = FcConfigGetAttribute (parse, "name");
24722c393a42Smrg    if (!name)
24732c393a42Smrg    {
24742c393a42Smrg	FcConfigMessage (parse, FcSevereWarning, "missing edit name");
24752c393a42Smrg	return;
24762c393a42Smrg    }
24772c393a42Smrg    mode_string = FcConfigGetAttribute (parse, "mode");
24782c393a42Smrg    if (!mode_string)
24792c393a42Smrg	mode = FcOpAssign;
24802c393a42Smrg    else
24812c393a42Smrg    {
24822c393a42Smrg	mode = FcConfigLexMode (mode_string);
24832c393a42Smrg	if (mode == FcOpInvalid)
24842c393a42Smrg	{
24852c393a42Smrg	    FcConfigMessage (parse, FcSevereWarning, "invalid edit mode \"%s\"", mode_string);
24862c393a42Smrg	    return;
24872c393a42Smrg	}
24882c393a42Smrg    }
24892c393a42Smrg    if (!FcConfigLexBinding (parse, FcConfigGetAttribute (parse, "binding"), &binding))
24902c393a42Smrg	return;
24912c393a42Smrg
24922c393a42Smrg    expr = FcPopBinary (parse, FcOpComma);
2493c9710b42Smrg    if ((mode == FcOpDelete || mode == FcOpDeleteAll) &&
2494c9710b42Smrg	expr != NULL)
2495c9710b42Smrg    {
2496c9710b42Smrg	FcConfigMessage (parse, FcSevereWarning, "Expression doesn't take any effects for delete and delete_all");
2497c9710b42Smrg	FcExprDestroy (expr);
2498c9710b42Smrg	expr = NULL;
2499c9710b42Smrg    }
25002c393a42Smrg    edit = FcEditCreate (parse, FcObjectFromName ((char *) name),
25012c393a42Smrg			 mode, expr, binding);
25022c393a42Smrg    if (!edit)
25032c393a42Smrg    {
25042c393a42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
25052c393a42Smrg	FcExprDestroy (expr);
25062c393a42Smrg	return;
25072c393a42Smrg    }
25082c393a42Smrg    if (!FcVStackPushEdit (parse, edit))
25092c393a42Smrg	FcEditDestroy (edit);
25102c393a42Smrg}
25112c393a42Smrg
25122c393a42Smrgstatic void
25132c393a42SmrgFcParseMatch (FcConfigParse *parse)
25142c393a42Smrg{
25152c393a42Smrg    const FcChar8   *kind_name;
25162c393a42Smrg    FcMatchKind	    kind;
25172c393a42Smrg    FcVStack	    *vstack;
25186fc018e4Smrg    FcRule	    *rule = NULL, *r;
25192c393a42Smrg
25202c393a42Smrg    kind_name = FcConfigGetAttribute (parse, "target");
25212c393a42Smrg    if (!kind_name)
25222c393a42Smrg	kind = FcMatchPattern;
25232c393a42Smrg    else
25242c393a42Smrg    {
25252c393a42Smrg	if (!strcmp ((char *) kind_name, "pattern"))
25262c393a42Smrg	    kind = FcMatchPattern;
25272c393a42Smrg	else if (!strcmp ((char *) kind_name, "font"))
25282c393a42Smrg	    kind = FcMatchFont;
25292c393a42Smrg	else if (!strcmp ((char *) kind_name, "scan"))
25302c393a42Smrg	    kind = FcMatchScan;
25312c393a42Smrg	else
25322c393a42Smrg	{
25332c393a42Smrg	    FcConfigMessage (parse, FcSevereWarning, "invalid match target \"%s\"", kind_name);
25342c393a42Smrg	    return;
25352c393a42Smrg	}
25362c393a42Smrg    }
2537a6844aabSmrg    while ((vstack = FcVStackPeek (parse)))
25382c393a42Smrg    {
2539c9710b42Smrg	switch ((int) vstack->tag) {
25402c393a42Smrg	case FcVStackTest:
25416fc018e4Smrg	    r = FcRuleCreate (FcRuleTest, vstack->u.test);
25426fc018e4Smrg	    if (rule)
25436fc018e4Smrg		r->next = rule;
25446fc018e4Smrg	    rule = r;
25452c393a42Smrg	    vstack->tag = FcVStackNone;
25462c393a42Smrg	    break;
25472c393a42Smrg	case FcVStackEdit:
25486fc018e4Smrg	    if (kind == FcMatchScan && vstack->u.edit->object > FC_MAX_BASE_OBJECT)
25492c393a42Smrg	    {
2550ca08ab68Smrg		FcConfigMessage (parse, FcSevereError,
25512c393a42Smrg				 "<match target=\"scan\"> cannot edit user-defined object \"%s\"",
25526fc018e4Smrg				 FcObjectName(vstack->u.edit->object));
25536fc018e4Smrg		if (rule)
25546fc018e4Smrg		    FcRuleDestroy (rule);
25556fc018e4Smrg		return;
25562c393a42Smrg	    }
25576fc018e4Smrg	    r = FcRuleCreate (FcRuleEdit, vstack->u.edit);
25586fc018e4Smrg	    if (rule)
25596fc018e4Smrg		r->next = rule;
25606fc018e4Smrg	    rule = r;
25616fc018e4Smrg	    vstack->tag = FcVStackNone;
25622c393a42Smrg	    break;
25632c393a42Smrg	default:
25642c393a42Smrg	    FcConfigMessage (parse, FcSevereWarning, "invalid match element");
25652c393a42Smrg	    break;
25662c393a42Smrg	}
2567a6844aabSmrg	FcVStackPopAndDestroy (parse);
25682c393a42Smrg    }
2569b09479dcSmrg    if (!rule)
2570b09479dcSmrg    {
2571b09479dcSmrg	FcConfigMessage (parse, FcSevereWarning, "No <test> nor <edit> elements in <match>");
2572b09479dcSmrg	return;
2573b09479dcSmrg    }
25746fc018e4Smrg    if (!FcConfigAddRule (parse->config, rule, kind))
25752c393a42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
25762c393a42Smrg}
25772c393a42Smrg
25782c393a42Smrgstatic void
25792c393a42SmrgFcParseAcceptRejectFont (FcConfigParse *parse, FcElement element)
25802c393a42Smrg{
25812c393a42Smrg    FcVStack	*vstack;
25822c393a42Smrg
2583a6844aabSmrg    while ((vstack = FcVStackPeek (parse)))
25842c393a42Smrg    {
2585c9710b42Smrg	switch ((int) vstack->tag) {
25862c393a42Smrg	case FcVStackGlob:
2587ca08ab68Smrg	    if (!FcConfigGlobAdd (parse->config,
25882c393a42Smrg				  vstack->u.string,
25892c393a42Smrg				  element == FcElementAcceptfont))
25902c393a42Smrg	    {
25912c393a42Smrg		FcConfigMessage (parse, FcSevereError, "out of memory");
25922c393a42Smrg	    }
25932c393a42Smrg	    break;
25942c393a42Smrg	case FcVStackPattern:
25952c393a42Smrg	    if (!FcConfigPatternsAdd (parse->config,
25962c393a42Smrg				      vstack->u.pattern,
25972c393a42Smrg				      element == FcElementAcceptfont))
25982c393a42Smrg	    {
25992c393a42Smrg		FcConfigMessage (parse, FcSevereError, "out of memory");
26002c393a42Smrg	    }
26012c393a42Smrg	    else
26022c393a42Smrg		vstack->tag = FcVStackNone;
26032c393a42Smrg	    break;
26042c393a42Smrg	default:
26052c393a42Smrg	    FcConfigMessage (parse, FcSevereWarning, "bad font selector");
26062c393a42Smrg	    break;
26072c393a42Smrg	}
2608a6844aabSmrg	FcVStackPopAndDestroy (parse);
26092c393a42Smrg    }
26102c393a42Smrg}
26112c393a42Smrg
26122c393a42Smrg
26132c393a42Smrgstatic FcValue
26142c393a42SmrgFcPopValue (FcConfigParse *parse)
26152c393a42Smrg{
2616a6844aabSmrg    FcVStack	*vstack = FcVStackPeek (parse);
26172c393a42Smrg    FcValue	value;
2618ca08ab68Smrg
26192c393a42Smrg    value.type = FcTypeVoid;
2620ca08ab68Smrg
26212c393a42Smrg    if (!vstack)
26222c393a42Smrg	return value;
2623ca08ab68Smrg
2624c9710b42Smrg    switch ((int) vstack->tag) {
26252c393a42Smrg    case FcVStackString:
2626c9710b42Smrg	value.u.s = FcStrdup (vstack->u.string);
26272c393a42Smrg	if (value.u.s)
26282c393a42Smrg	    value.type = FcTypeString;
26292c393a42Smrg	break;
26302c393a42Smrg    case FcVStackConstant:
26312c393a42Smrg	if (FcNameConstant (vstack->u.string, &value.u.i))
26322c393a42Smrg	    value.type = FcTypeInteger;
26332c393a42Smrg	break;
26342c393a42Smrg    case FcVStackInteger:
26352c393a42Smrg	value.u.i = vstack->u.integer;
26362c393a42Smrg	value.type = FcTypeInteger;
26372c393a42Smrg	break;
26382c393a42Smrg    case FcVStackDouble:
26392c393a42Smrg	value.u.d = vstack->u._double;
2640c9710b42Smrg	value.type = FcTypeDouble;
26412c393a42Smrg	break;
26422c393a42Smrg    case FcVStackBool:
2643a6844aabSmrg	value.u.b = vstack->u.bool_;
26442c393a42Smrg	value.type = FcTypeBool;
26452c393a42Smrg	break;
2646ca08ab68Smrg    case FcVStackCharSet:
2647ca08ab68Smrg	value.u.c = FcCharSetCopy (vstack->u.charset);
2648ca08ab68Smrg	if (value.u.c)
2649ca08ab68Smrg	    value.type = FcTypeCharSet;
2650ca08ab68Smrg	break;
2651ca08ab68Smrg    case FcVStackLangSet:
2652ca08ab68Smrg	value.u.l = FcLangSetCopy (vstack->u.langset);
2653ca08ab68Smrg	if (value.u.l)
2654ca08ab68Smrg	    value.type = FcTypeLangSet;
2655ca08ab68Smrg	break;
26562c393a42Smrg    default:
2657ca08ab68Smrg	FcConfigMessage (parse, FcSevereWarning, "unknown pattern element %d",
26582c393a42Smrg			 vstack->tag);
26592c393a42Smrg	break;
26602c393a42Smrg    }
2661a6844aabSmrg    FcVStackPopAndDestroy (parse);
2662ca08ab68Smrg
26632c393a42Smrg    return value;
26642c393a42Smrg}
26652c393a42Smrg
26662c393a42Smrgstatic void
26672c393a42SmrgFcParsePatelt (FcConfigParse *parse)
26682c393a42Smrg{
26692c393a42Smrg    FcValue	value;
26702c393a42Smrg    FcPattern	*pattern = FcPatternCreate ();
26712c393a42Smrg    const char	*name;
26722c393a42Smrg
26732c393a42Smrg    if (!pattern)
26742c393a42Smrg    {
26752c393a42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
26762c393a42Smrg	return;
26772c393a42Smrg    }
26782c393a42Smrg
26792c393a42Smrg    name = (char *) FcConfigGetAttribute (parse, "name");
26802c393a42Smrg    if (!name)
26812c393a42Smrg    {
26822c393a42Smrg	FcConfigMessage (parse, FcSevereWarning, "missing pattern element name");
26832c393a42Smrg	FcPatternDestroy (pattern);
26842c393a42Smrg	return;
26852c393a42Smrg    }
2686ca08ab68Smrg
26872c393a42Smrg    for (;;)
26882c393a42Smrg    {
26892c393a42Smrg	value = FcPopValue (parse);
26902c393a42Smrg	if (value.type == FcTypeVoid)
26912c393a42Smrg	    break;
26922c393a42Smrg	if (!FcPatternAdd (pattern, name, value, FcTrue))
26932c393a42Smrg	{
26942c393a42Smrg	    FcConfigMessage (parse, FcSevereError, "out of memory");
2695a6844aabSmrg            FcValueDestroy(value);
26962c393a42Smrg	    break;
26972c393a42Smrg	}
2698a6844aabSmrg        FcValueDestroy(value);
26992c393a42Smrg    }
27002c393a42Smrg
27012c393a42Smrg    FcVStackPushPattern (parse, pattern);
27022c393a42Smrg}
27032c393a42Smrg
27042c393a42Smrgstatic void
27052c393a42SmrgFcParsePattern (FcConfigParse *parse)
27062c393a42Smrg{
27072c393a42Smrg    FcVStack	*vstack;
27082c393a42Smrg    FcPattern	*pattern = FcPatternCreate ();
27092c393a42Smrg
27102c393a42Smrg    if (!pattern)
27112c393a42Smrg    {
27122c393a42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
27132c393a42Smrg	return;
27142c393a42Smrg    }
27152c393a42Smrg
2716a6844aabSmrg    while ((vstack = FcVStackPeek (parse)))
27172c393a42Smrg    {
2718c9710b42Smrg	switch ((int) vstack->tag) {
27192c393a42Smrg	case FcVStackPattern:
27202c393a42Smrg	    if (!FcPatternAppend (pattern, vstack->u.pattern))
27212c393a42Smrg	    {
27222c393a42Smrg		FcConfigMessage (parse, FcSevereError, "out of memory");
27232c393a42Smrg		FcPatternDestroy (pattern);
27242c393a42Smrg		return;
27252c393a42Smrg	    }
27262c393a42Smrg	    break;
27272c393a42Smrg	default:
27282c393a42Smrg	    FcConfigMessage (parse, FcSevereWarning, "unknown pattern element");
27292c393a42Smrg	    break;
27302c393a42Smrg	}
2731a6844aabSmrg	FcVStackPopAndDestroy (parse);
27322c393a42Smrg    }
27332c393a42Smrg
27342c393a42Smrg    FcVStackPushPattern (parse, pattern);
27352c393a42Smrg}
27362c393a42Smrg
27372c393a42Smrgstatic void
2738c9710b42SmrgFcEndElement(void *userData, const XML_Char *name FC_UNUSED)
27392c393a42Smrg{
27402c393a42Smrg    FcConfigParse   *parse = userData;
27412c393a42Smrg    FcChar8	    *data;
2742a6844aabSmrg
27432c393a42Smrg    if (!parse->pstack)
27442c393a42Smrg	return;
27452c393a42Smrg    switch (parse->pstack->element) {
27462c393a42Smrg    case FcElementNone:
27472c393a42Smrg	break;
27482c393a42Smrg    case FcElementFontconfig:
27492c393a42Smrg	break;
27502c393a42Smrg    case FcElementDir:
2751ca08ab68Smrg	FcParseDir (parse);
27522c393a42Smrg	break;
27532c393a42Smrg    case FcElementCacheDir:
2754ca08ab68Smrg	FcParseCacheDir (parse);
27552c393a42Smrg	break;
27562c393a42Smrg    case FcElementCache:
2757a6844aabSmrg	data = FcStrBufDoneStatic (&parse->pstack->str);
27582c393a42Smrg	if (!data)
27592c393a42Smrg	{
27602c393a42Smrg	    FcConfigMessage (parse, FcSevereError, "out of memory");
27612c393a42Smrg	    break;
27622c393a42Smrg	}
27632c393a42Smrg	/* discard this data; no longer used */
2764a6844aabSmrg	FcStrBufDestroy (&parse->pstack->str);
27652c393a42Smrg	break;
27662c393a42Smrg    case FcElementInclude:
27672c393a42Smrg	FcParseInclude (parse);
27682c393a42Smrg	break;
27692c393a42Smrg    case FcElementConfig:
27702c393a42Smrg	break;
27712c393a42Smrg    case FcElementMatch:
27722c393a42Smrg	FcParseMatch (parse);
27732c393a42Smrg	break;
27742c393a42Smrg    case FcElementAlias:
27752c393a42Smrg	FcParseAlias (parse);
27762c393a42Smrg	break;
27772c393a42Smrg
27782c393a42Smrg    case FcElementBlank:
27792c393a42Smrg	FcParseBlank (parse);
27802c393a42Smrg	break;
27812c393a42Smrg    case FcElementRescan:
27822c393a42Smrg	FcParseRescan (parse);
27832c393a42Smrg	break;
27842c393a42Smrg
27852c393a42Smrg    case FcElementPrefer:
27862c393a42Smrg	FcParseFamilies (parse, FcVStackPrefer);
27872c393a42Smrg	break;
27882c393a42Smrg    case FcElementAccept:
27892c393a42Smrg	FcParseFamilies (parse, FcVStackAccept);
27902c393a42Smrg	break;
27912c393a42Smrg    case FcElementDefault:
27922c393a42Smrg	FcParseFamilies (parse, FcVStackDefault);
27932c393a42Smrg	break;
27942c393a42Smrg    case FcElementFamily:
27952c393a42Smrg	FcParseFamily (parse);
27962c393a42Smrg	break;
27972c393a42Smrg
27982c393a42Smrg    case FcElementTest:
27992c393a42Smrg	FcParseTest (parse);
28002c393a42Smrg	break;
28012c393a42Smrg    case FcElementEdit:
28022c393a42Smrg	FcParseEdit (parse);
28032c393a42Smrg	break;
28042c393a42Smrg
28052c393a42Smrg    case FcElementInt:
28062c393a42Smrg	FcParseInt (parse);
28072c393a42Smrg	break;
28082c393a42Smrg    case FcElementDouble:
28092c393a42Smrg	FcParseDouble (parse);
28102c393a42Smrg	break;
28112c393a42Smrg    case FcElementString:
28122c393a42Smrg	FcParseString (parse, FcVStackString);
28132c393a42Smrg	break;
28142c393a42Smrg    case FcElementMatrix:
28152c393a42Smrg	FcParseMatrix (parse);
28162c393a42Smrg	break;
2817ca08ab68Smrg    case FcElementRange:
2818ca08ab68Smrg	FcParseRange (parse);
2819ca08ab68Smrg	break;
28202c393a42Smrg    case FcElementBool:
28212c393a42Smrg	FcParseBool (parse);
28222c393a42Smrg	break;
2823ca08ab68Smrg    case FcElementCharSet:
2824ca08ab68Smrg	FcParseCharSet (parse);
2825ca08ab68Smrg	break;
2826ca08ab68Smrg    case FcElementLangSet:
2827ca08ab68Smrg	FcParseLangSet (parse);
28282c393a42Smrg	break;
28292c393a42Smrg    case FcElementSelectfont:
28302c393a42Smrg	break;
28312c393a42Smrg    case FcElementAcceptfont:
28322c393a42Smrg    case FcElementRejectfont:
28332c393a42Smrg	FcParseAcceptRejectFont (parse, parse->pstack->element);
28342c393a42Smrg	break;
28352c393a42Smrg    case FcElementGlob:
28362c393a42Smrg	FcParseString (parse, FcVStackGlob);
28372c393a42Smrg	break;
28382c393a42Smrg    case FcElementPattern:
28392c393a42Smrg	FcParsePattern (parse);
28402c393a42Smrg	break;
28412c393a42Smrg    case FcElementPatelt:
28422c393a42Smrg	FcParsePatelt (parse);
28432c393a42Smrg	break;
28442c393a42Smrg    case FcElementName:
2845c9710b42Smrg	FcParseName (parse);
28462c393a42Smrg	break;
28472c393a42Smrg    case FcElementConst:
28482c393a42Smrg	FcParseString (parse, FcVStackConstant);
28492c393a42Smrg	break;
28502c393a42Smrg    case FcElementOr:
28512c393a42Smrg	FcParseBinary (parse, FcOpOr);
28522c393a42Smrg	break;
28532c393a42Smrg    case FcElementAnd:
28542c393a42Smrg	FcParseBinary (parse, FcOpAnd);
28552c393a42Smrg	break;
28562c393a42Smrg    case FcElementEq:
28572c393a42Smrg	FcParseBinary (parse, FcOpEqual);
28582c393a42Smrg	break;
28592c393a42Smrg    case FcElementNotEq:
28602c393a42Smrg	FcParseBinary (parse, FcOpNotEqual);
28612c393a42Smrg	break;
28622c393a42Smrg    case FcElementLess:
28632c393a42Smrg	FcParseBinary (parse, FcOpLess);
28642c393a42Smrg	break;
28652c393a42Smrg    case FcElementLessEq:
28662c393a42Smrg	FcParseBinary (parse, FcOpLessEqual);
28672c393a42Smrg	break;
28682c393a42Smrg    case FcElementMore:
28692c393a42Smrg	FcParseBinary (parse, FcOpMore);
28702c393a42Smrg	break;
28712c393a42Smrg    case FcElementMoreEq:
28722c393a42Smrg	FcParseBinary (parse, FcOpMoreEqual);
28732c393a42Smrg	break;
28742c393a42Smrg    case FcElementContains:
28752c393a42Smrg	FcParseBinary (parse, FcOpContains);
28762c393a42Smrg	break;
28772c393a42Smrg    case FcElementNotContains:
28782c393a42Smrg	FcParseBinary (parse, FcOpNotContains);
28792c393a42Smrg	break;
28802c393a42Smrg    case FcElementPlus:
28812c393a42Smrg	FcParseBinary (parse, FcOpPlus);
28822c393a42Smrg	break;
28832c393a42Smrg    case FcElementMinus:
28842c393a42Smrg	FcParseBinary (parse, FcOpMinus);
28852c393a42Smrg	break;
28862c393a42Smrg    case FcElementTimes:
28872c393a42Smrg	FcParseBinary (parse, FcOpTimes);
28882c393a42Smrg	break;
28892c393a42Smrg    case FcElementDivide:
28902c393a42Smrg	FcParseBinary (parse, FcOpDivide);
28912c393a42Smrg	break;
28922c393a42Smrg    case FcElementNot:
28932c393a42Smrg	FcParseUnary (parse, FcOpNot);
28942c393a42Smrg	break;
28952c393a42Smrg    case FcElementIf:
28962c393a42Smrg	FcParseBinary (parse, FcOpQuest);
28972c393a42Smrg	break;
28982c393a42Smrg    case FcElementFloor:
28992c393a42Smrg	FcParseUnary (parse, FcOpFloor);
29002c393a42Smrg	break;
29012c393a42Smrg    case FcElementCeil:
29022c393a42Smrg	FcParseUnary (parse, FcOpCeil);
29032c393a42Smrg	break;
29042c393a42Smrg    case FcElementRound:
29052c393a42Smrg	FcParseUnary (parse, FcOpRound);
29062c393a42Smrg	break;
29072c393a42Smrg    case FcElementTrunc:
29082c393a42Smrg	FcParseUnary (parse, FcOpTrunc);
29092c393a42Smrg	break;
29102c393a42Smrg    case FcElementUnknown:
29112c393a42Smrg	break;
29122c393a42Smrg    }
29132c393a42Smrg    (void) FcPStackPop (parse);
29142c393a42Smrg}
29152c393a42Smrg
29162c393a42Smrgstatic void
29172c393a42SmrgFcCharacterData (void *userData, const XML_Char *s, int len)
29182c393a42Smrg{
29192c393a42Smrg    FcConfigParse   *parse = userData;
2920ca08ab68Smrg
29212c393a42Smrg    if (!parse->pstack)
29222c393a42Smrg	return;
29232c393a42Smrg    if (!FcStrBufData (&parse->pstack->str, (FcChar8 *) s, len))
29242c393a42Smrg	FcConfigMessage (parse, FcSevereError, "out of memory");
29252c393a42Smrg}
29262c393a42Smrg
29272c393a42Smrgstatic void
29282c393a42SmrgFcStartDoctypeDecl (void	    *userData,
29292c393a42Smrg		    const XML_Char  *doctypeName,
2930c9710b42Smrg		    const XML_Char  *sysid FC_UNUSED,
2931c9710b42Smrg		    const XML_Char  *pubid FC_UNUSED,
2932c9710b42Smrg		    int		    has_internal_subset FC_UNUSED)
29332c393a42Smrg{
29342c393a42Smrg    FcConfigParse   *parse = userData;
29352c393a42Smrg
29362c393a42Smrg    if (strcmp ((char *) doctypeName, "fontconfig") != 0)
29372c393a42Smrg	FcConfigMessage (parse, FcSevereError, "invalid doctype \"%s\"", doctypeName);
29382c393a42Smrg}
29392c393a42Smrg
29402c393a42Smrg#ifdef ENABLE_LIBXML2
29412c393a42Smrg
29422c393a42Smrgstatic void
29432c393a42SmrgFcInternalSubsetDecl (void            *userData,
29442c393a42Smrg		      const XML_Char  *doctypeName,
29452c393a42Smrg		      const XML_Char  *sysid,
29462c393a42Smrg		      const XML_Char  *pubid)
29472c393a42Smrg{
29482c393a42Smrg    FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 1);
29492c393a42Smrg}
29502c393a42Smrg
29512c393a42Smrgstatic void
29522c393a42SmrgFcExternalSubsetDecl (void            *userData,
29532c393a42Smrg		      const XML_Char  *doctypeName,
29542c393a42Smrg		      const XML_Char  *sysid,
29552c393a42Smrg		      const XML_Char  *pubid)
29562c393a42Smrg{
29572c393a42Smrg    FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 0);
29582c393a42Smrg}
29592c393a42Smrg
29602c393a42Smrg#else /* ENABLE_LIBXML2 */
29612c393a42Smrg
29622c393a42Smrgstatic void
2963c9710b42SmrgFcEndDoctypeDecl (void *userData FC_UNUSED)
29642c393a42Smrg{
29652c393a42Smrg}
29662c393a42Smrg
29672c393a42Smrg#endif /* ENABLE_LIBXML2 */
29682c393a42Smrg
29692c393a42Smrgstatic int
29702c393a42SmrgFcSortCmpStr (const void *a, const void *b)
29712c393a42Smrg{
29722c393a42Smrg    const FcChar8    *as = *((FcChar8 **) a);
29732c393a42Smrg    const FcChar8    *bs = *((FcChar8 **) b);
29742c393a42Smrg    return FcStrCmp (as, bs);
29752c393a42Smrg}
29762c393a42Smrg
29772c393a42Smrgstatic FcBool
29782c393a42SmrgFcConfigParseAndLoadDir (FcConfig	*config,
29792c393a42Smrg			 const FcChar8	*name,
29802c393a42Smrg			 const FcChar8	*dir,
29812c393a42Smrg			 FcBool		complain)
29822c393a42Smrg{
29832c393a42Smrg    DIR		    *d;
29842c393a42Smrg    struct dirent   *e;
29852c393a42Smrg    FcBool	    ret = FcTrue;
29862c393a42Smrg    FcChar8	    *file;
29872c393a42Smrg    FcChar8	    *base;
29882c393a42Smrg    FcStrSet	    *files;
29892c393a42Smrg
29902c393a42Smrg    d = opendir ((char *) dir);
29912c393a42Smrg    if (!d)
29922c393a42Smrg    {
29932c393a42Smrg	if (complain)
29942c393a42Smrg	    FcConfigMessage (0, FcSevereError, "Cannot open config dir \"%s\"",
29952c393a42Smrg			     name);
29962c393a42Smrg	ret = FcFalse;
29972c393a42Smrg	goto bail0;
29982c393a42Smrg    }
29992c393a42Smrg    /* freed below */
30002c393a42Smrg    file = (FcChar8 *) malloc (strlen ((char *) dir) + 1 + FC_MAX_FILE_LEN + 1);
30012c393a42Smrg    if (!file)
30022c393a42Smrg    {
30032c393a42Smrg	ret = FcFalse;
30042c393a42Smrg	goto bail1;
30052c393a42Smrg    }
3006ca08ab68Smrg
30072c393a42Smrg    strcpy ((char *) file, (char *) dir);
30082c393a42Smrg    strcat ((char *) file, "/");
30092c393a42Smrg    base = file + strlen ((char *) file);
3010ca08ab68Smrg
30112c393a42Smrg    files = FcStrSetCreate ();
30122c393a42Smrg    if (!files)
30132c393a42Smrg    {
30142c393a42Smrg	ret = FcFalse;
30152c393a42Smrg	goto bail2;
30162c393a42Smrg    }
3017ca08ab68Smrg
30182c393a42Smrg    if (FcDebug () & FC_DBG_CONFIG)
30192c393a42Smrg	printf ("\tScanning config dir %s\n", dir);
30202c393a42Smrg
30212c393a42Smrg    while (ret && (e = readdir (d)))
30222c393a42Smrg    {
30232c393a42Smrg	int d_len;
30242c393a42Smrg#define TAIL	    ".conf"
30252c393a42Smrg#define TAIL_LEN    5
30262c393a42Smrg	/*
30272c393a42Smrg	 * Add all files of the form [0-9]*.conf
30282c393a42Smrg	 */
30292c393a42Smrg	if ('0' <= e->d_name[0] && e->d_name[0] <= '9' &&
30302c393a42Smrg	    (d_len = strlen (e->d_name)) < FC_MAX_FILE_LEN &&
30312c393a42Smrg	    d_len > TAIL_LEN &&
30322c393a42Smrg	    strcmp (e->d_name + d_len - TAIL_LEN, TAIL) == 0)
30332c393a42Smrg	{
30342c393a42Smrg	    strcpy ((char *) base, (char *) e->d_name);
30352c393a42Smrg	    if (!FcStrSetAdd (files, file))
30362c393a42Smrg	    {
30372c393a42Smrg		ret = FcFalse;
30382c393a42Smrg		goto bail3;
30392c393a42Smrg	    }
30402c393a42Smrg	}
30412c393a42Smrg    }
30422c393a42Smrg    if (ret)
30432c393a42Smrg    {
30442c393a42Smrg	int i;
3045ca08ab68Smrg	qsort (files->strs, files->num, sizeof (FcChar8 *),
30462c393a42Smrg	       (int (*)(const void *, const void *)) FcSortCmpStr);
30472c393a42Smrg	for (i = 0; ret && i < files->num; i++)
30482c393a42Smrg	    ret = FcConfigParseAndLoad (config, files->strs[i], complain);
30492c393a42Smrg    }
30502c393a42Smrgbail3:
30512c393a42Smrg    FcStrSetDestroy (files);
30522c393a42Smrgbail2:
30532c393a42Smrg    free (file);
30542c393a42Smrgbail1:
30552c393a42Smrg    closedir (d);
30562c393a42Smrgbail0:
30572c393a42Smrg    return ret || !complain;
30582c393a42Smrg}
30592c393a42Smrg
3060ca08ab68Smrg#ifdef _WIN32
3061ca08ab68SmrgpfnGetSystemWindowsDirectory pGetSystemWindowsDirectory = NULL;
3062ca08ab68SmrgpfnSHGetFolderPathA pSHGetFolderPathA = NULL;
3063ca08ab68Smrg#endif
3064ca08ab68Smrg
30652c393a42SmrgFcBool
30662c393a42SmrgFcConfigParseAndLoad (FcConfig	    *config,
30672c393a42Smrg		      const FcChar8 *name,
30682c393a42Smrg		      FcBool	    complain)
30692c393a42Smrg{
30702c393a42Smrg
30712c393a42Smrg    XML_Parser	    p;
30722c393a42Smrg    FcChar8	    *filename;
30732c393a42Smrg    int		    fd;
30742c393a42Smrg    int		    len;
30752c393a42Smrg    FcConfigParse   parse;
30762c393a42Smrg    FcBool	    error = FcTrue;
3077ca08ab68Smrg
30782c393a42Smrg#ifdef ENABLE_LIBXML2
30792c393a42Smrg    xmlSAXHandler   sax;
30802c393a42Smrg    char            buf[BUFSIZ];
30812c393a42Smrg#else
30822c393a42Smrg    void	    *buf;
30832c393a42Smrg#endif
3084ca08ab68Smrg
3085ca08ab68Smrg#ifdef _WIN32
3086ca08ab68Smrg    if (!pGetSystemWindowsDirectory)
3087ca08ab68Smrg    {
3088ca08ab68Smrg        HMODULE hk32 = GetModuleHandleA("kernel32.dll");
3089ca08ab68Smrg        if (!(pGetSystemWindowsDirectory = (pfnGetSystemWindowsDirectory) GetProcAddress(hk32, "GetSystemWindowsDirectoryA")))
3090ca08ab68Smrg            pGetSystemWindowsDirectory = (pfnGetSystemWindowsDirectory) GetWindowsDirectory;
3091ca08ab68Smrg    }
3092ca08ab68Smrg    if (!pSHGetFolderPathA)
3093ca08ab68Smrg    {
3094ca08ab68Smrg        HMODULE hSh = LoadLibraryA("shfolder.dll");
3095ca08ab68Smrg        /* the check is done later, because there is no provided fallback */
3096ca08ab68Smrg        if (hSh)
3097ca08ab68Smrg            pSHGetFolderPathA = (pfnSHGetFolderPathA) GetProcAddress(hSh, "SHGetFolderPathA");
3098ca08ab68Smrg    }
3099ca08ab68Smrg#endif
3100ca08ab68Smrg
31012c393a42Smrg    filename = FcConfigFilename (name);
31022c393a42Smrg    if (!filename)
31032c393a42Smrg	goto bail0;
3104ca08ab68Smrg
31052c393a42Smrg    if (FcStrSetMember (config->configFiles, filename))
31062c393a42Smrg    {
31072c393a42Smrg        FcStrFree (filename);
31082c393a42Smrg        return FcTrue;
31092c393a42Smrg    }
31102c393a42Smrg
31112c393a42Smrg    if (!FcStrSetAdd (config->configFiles, filename))
31122c393a42Smrg    {
31132c393a42Smrg	FcStrFree (filename);
31142c393a42Smrg	goto bail0;
31152c393a42Smrg    }
31162c393a42Smrg
31172c393a42Smrg    if (FcFileIsDir (filename))
31182c393a42Smrg    {
31192c393a42Smrg	FcBool ret = FcConfigParseAndLoadDir (config, name, filename, complain);
31202c393a42Smrg	FcStrFree (filename);
31212c393a42Smrg	return ret;
31222c393a42Smrg    }
31232c393a42Smrg
31242c393a42Smrg    if (FcDebug () & FC_DBG_CONFIG)
31252c393a42Smrg	printf ("\tLoading config file %s\n", filename);
31262c393a42Smrg
3127c9710b42Smrg    fd = FcOpen ((char *) filename, O_RDONLY);
3128ca08ab68Smrg    if (fd == -1) {
31292c393a42Smrg	FcStrFree (filename);
31302c393a42Smrg	goto bail0;
31312c393a42Smrg    }
3132ca08ab68Smrg
31332c393a42Smrg#ifdef ENABLE_LIBXML2
31342c393a42Smrg    memset(&sax, 0, sizeof(sax));
31352c393a42Smrg
31362c393a42Smrg    sax.internalSubset = FcInternalSubsetDecl;
31372c393a42Smrg    sax.externalSubset = FcExternalSubsetDecl;
31382c393a42Smrg    sax.startElement = FcStartElement;
31392c393a42Smrg    sax.endElement = FcEndElement;
31402c393a42Smrg    sax.characters = FcCharacterData;
31412c393a42Smrg
31422c393a42Smrg    p = xmlCreatePushParserCtxt (&sax, &parse, NULL, 0, (const char *) filename);
31432c393a42Smrg#else
31442c393a42Smrg    p = XML_ParserCreate ("UTF-8");
31452c393a42Smrg#endif
31462c393a42Smrg    FcStrFree (filename);
31472c393a42Smrg
31482c393a42Smrg    if (!p)
31492c393a42Smrg	goto bail1;
31502c393a42Smrg
3151c9710b42Smrg    if (!FcConfigParseInit (&parse, name, config, p))
31522c393a42Smrg	goto bail2;
31532c393a42Smrg
31542c393a42Smrg#ifndef ENABLE_LIBXML2
31552c393a42Smrg
31562c393a42Smrg    XML_SetUserData (p, &parse);
3157ca08ab68Smrg
31582c393a42Smrg    XML_SetDoctypeDeclHandler (p, FcStartDoctypeDecl, FcEndDoctypeDecl);
31592c393a42Smrg    XML_SetElementHandler (p, FcStartElement, FcEndElement);
31602c393a42Smrg    XML_SetCharacterDataHandler (p, FcCharacterData);
31612c393a42Smrg
31622c393a42Smrg#endif /* ENABLE_LIBXML2 */
31632c393a42Smrg
31642c393a42Smrg    do {
31652c393a42Smrg#ifndef ENABLE_LIBXML2
31662c393a42Smrg	buf = XML_GetBuffer (p, BUFSIZ);
31672c393a42Smrg	if (!buf)
31682c393a42Smrg	{
31692c393a42Smrg	    FcConfigMessage (&parse, FcSevereError, "cannot get parse buffer");
31702c393a42Smrg	    goto bail3;
31712c393a42Smrg	}
31722c393a42Smrg#endif
31732c393a42Smrg	len = read (fd, buf, BUFSIZ);
31742c393a42Smrg	if (len < 0)
31752c393a42Smrg	{
31762c393a42Smrg	    FcConfigMessage (&parse, FcSevereError, "failed reading config file");
31772c393a42Smrg	    goto bail3;
31782c393a42Smrg	}
31792c393a42Smrg
31802c393a42Smrg#ifdef ENABLE_LIBXML2
31812c393a42Smrg	if (xmlParseChunk (p, buf, len, len == 0))
31822c393a42Smrg#else
31832c393a42Smrg	if (!XML_ParseBuffer (p, len, len == 0))
31842c393a42Smrg#endif
31852c393a42Smrg	{
3186ca08ab68Smrg	    FcConfigMessage (&parse, FcSevereError, "%s",
31872c393a42Smrg			   XML_ErrorString (XML_GetErrorCode (p)));
31882c393a42Smrg	    goto bail3;
31892c393a42Smrg	}
31902c393a42Smrg    } while (len != 0);
31912c393a42Smrg    error = parse.error;
31922c393a42Smrgbail3:
31932c393a42Smrg    FcConfigCleanup (&parse);
31942c393a42Smrgbail2:
31952c393a42Smrg    XML_ParserFree (p);
31962c393a42Smrgbail1:
31972c393a42Smrg    close (fd);
31982c393a42Smrg    fd = -1;
31992c393a42Smrgbail0:
32002c393a42Smrg    if (error && complain)
32012c393a42Smrg    {
32022c393a42Smrg	if (name)
32032c393a42Smrg	    FcConfigMessage (0, FcSevereError, "Cannot load config file \"%s\"", name);
32042c393a42Smrg	else
32052c393a42Smrg	    FcConfigMessage (0, FcSevereError, "Cannot load default config file");
32062c393a42Smrg	return FcFalse;
32072c393a42Smrg    }
32082c393a42Smrg    return FcTrue;
32092c393a42Smrg}
32102c393a42Smrg#define __fcxml__
32112c393a42Smrg#include "fcaliastail.h"
32122c393a42Smrg#undef __fcxml__
3213