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