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