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