fcxml.c revision c9710b42
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 if (test->next) 662c393a42Smrg FcTestDestroy (test->next); 672c393a42Smrg FcExprDestroy (test->expr); 682c393a42Smrg free (test); 692c393a42Smrg} 702c393a42Smrg 71a6844aabSmrgstatic FcExpr * 72a6844aabSmrgFcExprCreateInteger (FcConfig *config, int i) 732c393a42Smrg{ 74a6844aabSmrg FcExpr *e = FcConfigAllocExpr (config); 752c393a42Smrg if (e) 762c393a42Smrg { 772c393a42Smrg e->op = FcOpInteger; 782c393a42Smrg e->u.ival = i; 792c393a42Smrg } 802c393a42Smrg return e; 812c393a42Smrg} 822c393a42Smrg 83a6844aabSmrgstatic FcExpr * 84a6844aabSmrgFcExprCreateDouble (FcConfig *config, double d) 852c393a42Smrg{ 86a6844aabSmrg FcExpr *e = FcConfigAllocExpr (config); 872c393a42Smrg if (e) 882c393a42Smrg { 892c393a42Smrg e->op = FcOpDouble; 902c393a42Smrg e->u.dval = d; 912c393a42Smrg } 922c393a42Smrg return e; 932c393a42Smrg} 942c393a42Smrg 95a6844aabSmrgstatic FcExpr * 96a6844aabSmrgFcExprCreateString (FcConfig *config, const FcChar8 *s) 972c393a42Smrg{ 98a6844aabSmrg FcExpr *e = FcConfigAllocExpr (config); 992c393a42Smrg if (e) 1002c393a42Smrg { 1012c393a42Smrg e->op = FcOpString; 102c9710b42Smrg e->u.sval = FcStrdup (s); 1032c393a42Smrg } 1042c393a42Smrg return e; 1052c393a42Smrg} 1062c393a42Smrg 107c9710b42Smrgstatic FcExprMatrix * 108c9710b42SmrgFcExprMatrixCopyShallow (const FcExprMatrix *matrix) 109c9710b42Smrg{ 110c9710b42Smrg FcExprMatrix *m = malloc (sizeof (FcExprMatrix)); 111c9710b42Smrg if (m) 112c9710b42Smrg { 113c9710b42Smrg *m = *matrix; 114c9710b42Smrg } 115c9710b42Smrg return m; 116c9710b42Smrg} 117c9710b42Smrg 118c9710b42Smrgstatic void 119c9710b42SmrgFcExprMatrixFreeShallow (FcExprMatrix *m) 120c9710b42Smrg{ 121c9710b42Smrg if (!m) 122c9710b42Smrg return; 123c9710b42Smrg 124c9710b42Smrg free (m); 125c9710b42Smrg} 126c9710b42Smrg 127c9710b42Smrgstatic void 128c9710b42SmrgFcExprMatrixFree (FcExprMatrix *m) 129c9710b42Smrg{ 130c9710b42Smrg if (!m) 131c9710b42Smrg return; 132c9710b42Smrg 133c9710b42Smrg FcExprDestroy (m->xx); 134c9710b42Smrg FcExprDestroy (m->xy); 135c9710b42Smrg FcExprDestroy (m->yx); 136c9710b42Smrg FcExprDestroy (m->yy); 137c9710b42Smrg 138c9710b42Smrg free (m); 139c9710b42Smrg} 140c9710b42Smrg 141a6844aabSmrgstatic FcExpr * 142c9710b42SmrgFcExprCreateMatrix (FcConfig *config, const FcExprMatrix *matrix) 1432c393a42Smrg{ 144a6844aabSmrg FcExpr *e = FcConfigAllocExpr (config); 1452c393a42Smrg if (e) 1462c393a42Smrg { 1472c393a42Smrg e->op = FcOpMatrix; 148c9710b42Smrg e->u.mexpr = FcExprMatrixCopyShallow (matrix); 1492c393a42Smrg } 1502c393a42Smrg return e; 1512c393a42Smrg} 1522c393a42Smrg 153a6844aabSmrgstatic FcExpr * 154a6844aabSmrgFcExprCreateBool (FcConfig *config, FcBool b) 1552c393a42Smrg{ 156a6844aabSmrg FcExpr *e = FcConfigAllocExpr (config); 1572c393a42Smrg if (e) 1582c393a42Smrg { 1592c393a42Smrg e->op = FcOpBool; 1602c393a42Smrg e->u.bval = b; 1612c393a42Smrg } 1622c393a42Smrg return e; 1632c393a42Smrg} 1642c393a42Smrg 165ca08ab68Smrgstatic FcExpr * 166ca08ab68SmrgFcExprCreateCharSet (FcConfig *config, FcCharSet *charset) 167ca08ab68Smrg{ 168ca08ab68Smrg FcExpr *e = FcConfigAllocExpr (config); 169ca08ab68Smrg if (e) 170ca08ab68Smrg { 171ca08ab68Smrg e->op = FcOpCharSet; 172ca08ab68Smrg e->u.cval = FcCharSetCopy (charset); 173ca08ab68Smrg } 174ca08ab68Smrg return e; 175ca08ab68Smrg} 176ca08ab68Smrg 177ca08ab68Smrgstatic FcExpr * 178ca08ab68SmrgFcExprCreateLangSet (FcConfig *config, FcLangSet *langset) 179ca08ab68Smrg{ 180ca08ab68Smrg FcExpr *e = FcConfigAllocExpr (config); 181ca08ab68Smrg if (e) 182ca08ab68Smrg { 183ca08ab68Smrg e->op = FcOpLangSet; 184ca08ab68Smrg e->u.lval = FcLangSetCopy (langset); 185ca08ab68Smrg } 186ca08ab68Smrg return e; 187ca08ab68Smrg} 188ca08ab68Smrg 189a6844aabSmrgstatic FcExpr * 190c9710b42SmrgFcExprCreateName (FcConfig *config, FcExprName name) 1912c393a42Smrg{ 192a6844aabSmrg FcExpr *e = FcConfigAllocExpr (config); 1932c393a42Smrg if (e) 1942c393a42Smrg { 1952c393a42Smrg e->op = FcOpField; 196c9710b42Smrg e->u.name = name; 1972c393a42Smrg } 1982c393a42Smrg return e; 1992c393a42Smrg} 2002c393a42Smrg 201a6844aabSmrgstatic FcExpr * 202a6844aabSmrgFcExprCreateConst (FcConfig *config, const FcChar8 *constant) 2032c393a42Smrg{ 204a6844aabSmrg FcExpr *e = FcConfigAllocExpr (config); 2052c393a42Smrg if (e) 2062c393a42Smrg { 2072c393a42Smrg e->op = FcOpConst; 208c9710b42Smrg e->u.constant = FcStrdup (constant); 2092c393a42Smrg } 2102c393a42Smrg return e; 2112c393a42Smrg} 2122c393a42Smrg 213a6844aabSmrgstatic FcExpr * 214a6844aabSmrgFcExprCreateOp (FcConfig *config, FcExpr *left, FcOp op, FcExpr *right) 2152c393a42Smrg{ 216a6844aabSmrg FcExpr *e = FcConfigAllocExpr (config); 2172c393a42Smrg if (e) 2182c393a42Smrg { 2192c393a42Smrg e->op = op; 2202c393a42Smrg e->u.tree.left = left; 2212c393a42Smrg e->u.tree.right = right; 2222c393a42Smrg } 2232c393a42Smrg return e; 2242c393a42Smrg} 2252c393a42Smrg 226a6844aabSmrgstatic void 2272c393a42SmrgFcExprDestroy (FcExpr *e) 2282c393a42Smrg{ 2292c393a42Smrg if (!e) 2302c393a42Smrg return; 231ca08ab68Smrg switch (FC_OP_GET_OP (e->op)) { 2322c393a42Smrg case FcOpInteger: 2332c393a42Smrg break; 2342c393a42Smrg case FcOpDouble: 2352c393a42Smrg break; 2362c393a42Smrg case FcOpString: 237c9710b42Smrg FcFree (e->u.sval); 2382c393a42Smrg break; 2392c393a42Smrg case FcOpMatrix: 240c9710b42Smrg FcExprMatrixFree (e->u.mexpr); 2412c393a42Smrg break; 242ca08ab68Smrg case FcOpRange: 243ca08ab68Smrg break; 2442c393a42Smrg case FcOpCharSet: 2452c393a42Smrg FcCharSetDestroy (e->u.cval); 2462c393a42Smrg break; 247ca08ab68Smrg case FcOpLangSet: 248ca08ab68Smrg FcLangSetDestroy (e->u.lval); 249ca08ab68Smrg break; 2502c393a42Smrg case FcOpBool: 2512c393a42Smrg break; 2522c393a42Smrg case FcOpField: 2532c393a42Smrg break; 2542c393a42Smrg case FcOpConst: 255c9710b42Smrg FcFree (e->u.constant); 2562c393a42Smrg break; 2572c393a42Smrg case FcOpAssign: 2582c393a42Smrg case FcOpAssignReplace: 2592c393a42Smrg case FcOpPrepend: 2602c393a42Smrg case FcOpPrependFirst: 2612c393a42Smrg case FcOpAppend: 2622c393a42Smrg case FcOpAppendLast: 263c9710b42Smrg case FcOpDelete: 264c9710b42Smrg case FcOpDeleteAll: 2652c393a42Smrg break; 2662c393a42Smrg case FcOpOr: 2672c393a42Smrg case FcOpAnd: 2682c393a42Smrg case FcOpEqual: 2692c393a42Smrg case FcOpNotEqual: 2702c393a42Smrg case FcOpLess: 2712c393a42Smrg case FcOpLessEqual: 2722c393a42Smrg case FcOpMore: 2732c393a42Smrg case FcOpMoreEqual: 2742c393a42Smrg case FcOpContains: 2752c393a42Smrg case FcOpListing: 2762c393a42Smrg case FcOpNotContains: 2772c393a42Smrg case FcOpPlus: 2782c393a42Smrg case FcOpMinus: 2792c393a42Smrg case FcOpTimes: 2802c393a42Smrg case FcOpDivide: 2812c393a42Smrg case FcOpQuest: 2822c393a42Smrg case FcOpComma: 2832c393a42Smrg FcExprDestroy (e->u.tree.right); 2842c393a42Smrg /* fall through */ 2852c393a42Smrg case FcOpNot: 2862c393a42Smrg case FcOpFloor: 2872c393a42Smrg case FcOpCeil: 2882c393a42Smrg case FcOpRound: 2892c393a42Smrg case FcOpTrunc: 2902c393a42Smrg FcExprDestroy (e->u.tree.left); 2912c393a42Smrg break; 2922c393a42Smrg case FcOpNil: 2932c393a42Smrg case FcOpInvalid: 2942c393a42Smrg break; 2952c393a42Smrg } 296a6844aabSmrg 297a6844aabSmrg e->op = FcOpNil; 2982c393a42Smrg} 2992c393a42Smrg 3002c393a42Smrgvoid 3012c393a42SmrgFcEditDestroy (FcEdit *e) 3022c393a42Smrg{ 3032c393a42Smrg if (e->next) 3042c393a42Smrg FcEditDestroy (e->next); 3052c393a42Smrg if (e->expr) 3062c393a42Smrg FcExprDestroy (e->expr); 3072c393a42Smrg free (e); 3082c393a42Smrg} 3092c393a42Smrg 3102c393a42Smrgtypedef enum _FcElement { 3112c393a42Smrg FcElementNone, 3122c393a42Smrg FcElementFontconfig, 3132c393a42Smrg FcElementDir, 3142c393a42Smrg FcElementCacheDir, 3152c393a42Smrg FcElementCache, 3162c393a42Smrg FcElementInclude, 3172c393a42Smrg FcElementConfig, 3182c393a42Smrg FcElementMatch, 3192c393a42Smrg FcElementAlias, 3202c393a42Smrg 3212c393a42Smrg FcElementBlank, 3222c393a42Smrg FcElementRescan, 3232c393a42Smrg 3242c393a42Smrg FcElementPrefer, 3252c393a42Smrg FcElementAccept, 3262c393a42Smrg FcElementDefault, 3272c393a42Smrg FcElementFamily, 3282c393a42Smrg 3292c393a42Smrg FcElementSelectfont, 3302c393a42Smrg FcElementAcceptfont, 3312c393a42Smrg FcElementRejectfont, 3322c393a42Smrg FcElementGlob, 3332c393a42Smrg FcElementPattern, 3342c393a42Smrg FcElementPatelt, 3352c393a42Smrg 3362c393a42Smrg FcElementTest, 3372c393a42Smrg FcElementEdit, 3382c393a42Smrg FcElementInt, 3392c393a42Smrg FcElementDouble, 3402c393a42Smrg FcElementString, 3412c393a42Smrg FcElementMatrix, 342ca08ab68Smrg FcElementRange, 3432c393a42Smrg FcElementBool, 344ca08ab68Smrg FcElementCharSet, 345ca08ab68Smrg FcElementLangSet, 3462c393a42Smrg FcElementName, 3472c393a42Smrg FcElementConst, 3482c393a42Smrg FcElementOr, 3492c393a42Smrg FcElementAnd, 3502c393a42Smrg FcElementEq, 3512c393a42Smrg FcElementNotEq, 3522c393a42Smrg FcElementLess, 3532c393a42Smrg FcElementLessEq, 3542c393a42Smrg FcElementMore, 3552c393a42Smrg FcElementMoreEq, 3562c393a42Smrg FcElementContains, 3572c393a42Smrg FcElementNotContains, 3582c393a42Smrg FcElementPlus, 3592c393a42Smrg FcElementMinus, 3602c393a42Smrg FcElementTimes, 3612c393a42Smrg FcElementDivide, 3622c393a42Smrg FcElementNot, 3632c393a42Smrg FcElementIf, 3642c393a42Smrg FcElementFloor, 3652c393a42Smrg FcElementCeil, 3662c393a42Smrg FcElementRound, 3672c393a42Smrg FcElementTrunc, 3682c393a42Smrg FcElementUnknown 3692c393a42Smrg} FcElement; 3702c393a42Smrg 3712c393a42Smrgstatic const struct { 3722c393a42Smrg const char name[16]; 3732c393a42Smrg FcElement element; 3742c393a42Smrg} fcElementMap[] = { 3752c393a42Smrg { "fontconfig", FcElementFontconfig }, 3762c393a42Smrg { "dir", FcElementDir }, 3772c393a42Smrg { "cachedir", FcElementCacheDir }, 3782c393a42Smrg { "cache", FcElementCache }, 3792c393a42Smrg { "include", FcElementInclude }, 3802c393a42Smrg { "config", FcElementConfig }, 3812c393a42Smrg { "match", FcElementMatch }, 3822c393a42Smrg { "alias", FcElementAlias }, 383ca08ab68Smrg 3842c393a42Smrg { "blank", FcElementBlank }, 3852c393a42Smrg { "rescan", FcElementRescan }, 3862c393a42Smrg 3872c393a42Smrg { "prefer", FcElementPrefer }, 3882c393a42Smrg { "accept", FcElementAccept }, 3892c393a42Smrg { "default", FcElementDefault }, 3902c393a42Smrg { "family", FcElementFamily }, 3912c393a42Smrg 3922c393a42Smrg { "selectfont", FcElementSelectfont }, 3932c393a42Smrg { "acceptfont", FcElementAcceptfont }, 3942c393a42Smrg { "rejectfont", FcElementRejectfont }, 3952c393a42Smrg { "glob", FcElementGlob }, 3962c393a42Smrg { "pattern", FcElementPattern }, 3972c393a42Smrg { "patelt", FcElementPatelt }, 3982c393a42Smrg 3992c393a42Smrg { "test", FcElementTest }, 4002c393a42Smrg { "edit", FcElementEdit }, 4012c393a42Smrg { "int", FcElementInt }, 4022c393a42Smrg { "double", FcElementDouble }, 4032c393a42Smrg { "string", FcElementString }, 4042c393a42Smrg { "matrix", FcElementMatrix }, 405ca08ab68Smrg { "range", FcElementRange }, 4062c393a42Smrg { "bool", FcElementBool }, 407ca08ab68Smrg { "charset", FcElementCharSet }, 408ca08ab68Smrg { "langset", FcElementLangSet }, 4092c393a42Smrg { "name", FcElementName }, 4102c393a42Smrg { "const", FcElementConst }, 4112c393a42Smrg { "or", FcElementOr }, 4122c393a42Smrg { "and", FcElementAnd }, 4132c393a42Smrg { "eq", FcElementEq }, 4142c393a42Smrg { "not_eq", FcElementNotEq }, 4152c393a42Smrg { "less", FcElementLess }, 4162c393a42Smrg { "less_eq", FcElementLessEq }, 4172c393a42Smrg { "more", FcElementMore }, 4182c393a42Smrg { "more_eq", FcElementMoreEq }, 4192c393a42Smrg { "contains", FcElementContains }, 4202c393a42Smrg { "not_contains", FcElementNotContains }, 4212c393a42Smrg { "plus", FcElementPlus }, 4222c393a42Smrg { "minus", FcElementMinus }, 4232c393a42Smrg { "times", FcElementTimes }, 4242c393a42Smrg { "divide", FcElementDivide }, 4252c393a42Smrg { "not", FcElementNot }, 4262c393a42Smrg { "if", FcElementIf }, 4272c393a42Smrg { "floor", FcElementFloor }, 4282c393a42Smrg { "ceil", FcElementCeil }, 4292c393a42Smrg { "round", FcElementRound }, 4302c393a42Smrg { "trunc", FcElementTrunc }, 4312c393a42Smrg}; 4322c393a42Smrg#define NUM_ELEMENT_MAPS (int) (sizeof fcElementMap / sizeof fcElementMap[0]) 4332c393a42Smrg 4342c393a42Smrgstatic FcElement 4352c393a42SmrgFcElementMap (const XML_Char *name) 4362c393a42Smrg{ 4372c393a42Smrg 4382c393a42Smrg int i; 4392c393a42Smrg for (i = 0; i < NUM_ELEMENT_MAPS; i++) 4402c393a42Smrg if (!strcmp ((char *) name, fcElementMap[i].name)) 4412c393a42Smrg return fcElementMap[i].element; 4422c393a42Smrg return FcElementUnknown; 4432c393a42Smrg} 4442c393a42Smrg 4452c393a42Smrgtypedef struct _FcPStack { 4462c393a42Smrg struct _FcPStack *prev; 4472c393a42Smrg FcElement element; 4482c393a42Smrg FcChar8 **attr; 4492c393a42Smrg FcStrBuf str; 450a6844aabSmrg FcChar8 *attr_buf_static[16]; 4512c393a42Smrg} FcPStack; 452ca08ab68Smrg 4532c393a42Smrgtypedef enum _FcVStackTag { 4542c393a42Smrg FcVStackNone, 4552c393a42Smrg 4562c393a42Smrg FcVStackString, 4572c393a42Smrg FcVStackFamily, 4582c393a42Smrg FcVStackConstant, 4592c393a42Smrg FcVStackGlob, 460c9710b42Smrg FcVStackName, 4612c393a42Smrg FcVStackPattern, 462ca08ab68Smrg 4632c393a42Smrg FcVStackPrefer, 4642c393a42Smrg FcVStackAccept, 4652c393a42Smrg FcVStackDefault, 466ca08ab68Smrg 4672c393a42Smrg FcVStackInteger, 4682c393a42Smrg FcVStackDouble, 4692c393a42Smrg FcVStackMatrix, 470ca08ab68Smrg FcVStackRange, 4712c393a42Smrg FcVStackBool, 472ca08ab68Smrg FcVStackCharSet, 473ca08ab68Smrg FcVStackLangSet, 474ca08ab68Smrg 4752c393a42Smrg FcVStackTest, 4762c393a42Smrg FcVStackExpr, 4772c393a42Smrg FcVStackEdit 4782c393a42Smrg} FcVStackTag; 4792c393a42Smrg 4802c393a42Smrgtypedef struct _FcVStack { 4812c393a42Smrg struct _FcVStack *prev; 4822c393a42Smrg FcPStack *pstack; /* related parse element */ 4832c393a42Smrg FcVStackTag tag; 4842c393a42Smrg union { 4852c393a42Smrg FcChar8 *string; 4862c393a42Smrg 4872c393a42Smrg int integer; 4882c393a42Smrg double _double; 489c9710b42Smrg FcExprMatrix *matrix; 490ca08ab68Smrg FcRange range; 491a6844aabSmrg FcBool bool_; 492ca08ab68Smrg FcCharSet *charset; 493ca08ab68Smrg FcLangSet *langset; 494c9710b42Smrg FcExprName name; 4952c393a42Smrg 4962c393a42Smrg FcTest *test; 4972c393a42Smrg FcQual qual; 4982c393a42Smrg FcOp op; 4992c393a42Smrg FcExpr *expr; 5002c393a42Smrg FcEdit *edit; 5012c393a42Smrg 5022c393a42Smrg FcPattern *pattern; 5032c393a42Smrg } u; 5042c393a42Smrg} FcVStack; 5052c393a42Smrg 5062c393a42Smrgtypedef struct _FcConfigParse { 5072c393a42Smrg FcPStack *pstack; 5082c393a42Smrg FcVStack *vstack; 5092c393a42Smrg FcBool error; 5102c393a42Smrg const FcChar8 *name; 5112c393a42Smrg FcConfig *config; 5122c393a42Smrg XML_Parser parser; 513c9710b42Smrg unsigned int pstack_static_used; 514a6844aabSmrg FcPStack pstack_static[8]; 515c9710b42Smrg unsigned int vstack_static_used; 516a6844aabSmrg FcVStack vstack_static[64]; 5172c393a42Smrg} FcConfigParse; 5182c393a42Smrg 5192c393a42Smrgtypedef enum _FcConfigSeverity { 5202c393a42Smrg FcSevereInfo, FcSevereWarning, FcSevereError 5212c393a42Smrg} FcConfigSeverity; 5222c393a42Smrg 5232c393a42Smrgstatic void 5242c393a42SmrgFcConfigMessage (FcConfigParse *parse, FcConfigSeverity severe, const char *fmt, ...) 5252c393a42Smrg{ 5262c393a42Smrg const char *s = "unknown"; 5272c393a42Smrg va_list args; 5282c393a42Smrg 5292c393a42Smrg va_start (args, fmt); 5302c393a42Smrg 5312c393a42Smrg switch (severe) { 5322c393a42Smrg case FcSevereInfo: s = "info"; break; 5332c393a42Smrg case FcSevereWarning: s = "warning"; break; 5342c393a42Smrg case FcSevereError: s = "error"; break; 5352c393a42Smrg } 5362c393a42Smrg if (parse) 5372c393a42Smrg { 5382c393a42Smrg if (parse->name) 5392c393a42Smrg fprintf (stderr, "Fontconfig %s: \"%s\", line %d: ", s, 5402c393a42Smrg parse->name, (int)XML_GetCurrentLineNumber (parse->parser)); 5412c393a42Smrg else 5422c393a42Smrg fprintf (stderr, "Fontconfig %s: line %d: ", s, 5432c393a42Smrg (int)XML_GetCurrentLineNumber (parse->parser)); 5442c393a42Smrg if (severe >= FcSevereError) 5452c393a42Smrg parse->error = FcTrue; 5462c393a42Smrg } 5472c393a42Smrg else 5482c393a42Smrg fprintf (stderr, "Fontconfig %s: ", s); 5492c393a42Smrg vfprintf (stderr, fmt, args); 5502c393a42Smrg fprintf (stderr, "\n"); 5512c393a42Smrg va_end (args); 5522c393a42Smrg} 5532c393a42Smrg 5542c393a42Smrg 555c9710b42Smrgstatic FcExpr * 556c9710b42SmrgFcPopExpr (FcConfigParse *parse); 557c9710b42Smrg 558c9710b42Smrg 5592c393a42Smrgstatic const char * 5602c393a42SmrgFcTypeName (FcType type) 5612c393a42Smrg{ 5622c393a42Smrg switch (type) { 5632c393a42Smrg case FcTypeVoid: 5642c393a42Smrg return "void"; 5652c393a42Smrg case FcTypeInteger: 5662c393a42Smrg case FcTypeDouble: 5672c393a42Smrg return "number"; 5682c393a42Smrg case FcTypeString: 5692c393a42Smrg return "string"; 5702c393a42Smrg case FcTypeBool: 5712c393a42Smrg return "bool"; 5722c393a42Smrg case FcTypeMatrix: 5732c393a42Smrg return "matrix"; 5742c393a42Smrg case FcTypeCharSet: 5752c393a42Smrg return "charset"; 5762c393a42Smrg case FcTypeFTFace: 5772c393a42Smrg return "FT_Face"; 5782c393a42Smrg case FcTypeLangSet: 5792c393a42Smrg return "langset"; 5802c393a42Smrg default: 5812c393a42Smrg return "unknown"; 5822c393a42Smrg } 5832c393a42Smrg} 5842c393a42Smrg 5852c393a42Smrgstatic void 5862c393a42SmrgFcTypecheckValue (FcConfigParse *parse, FcType value, FcType type) 5872c393a42Smrg{ 5882c393a42Smrg if (value == FcTypeInteger) 5892c393a42Smrg value = FcTypeDouble; 5902c393a42Smrg if (type == FcTypeInteger) 5912c393a42Smrg type = FcTypeDouble; 5922c393a42Smrg if (value != type) 5932c393a42Smrg { 5942c393a42Smrg if ((value == FcTypeLangSet && type == FcTypeString) || 5952c393a42Smrg (value == FcTypeString && type == FcTypeLangSet)) 5962c393a42Smrg return; 5972c393a42Smrg if (type == (FcType) -1) 5982c393a42Smrg return; 599c9710b42Smrg /* It's perfectly fine to use user-define elements in expressions, 600c9710b42Smrg * so don't warn in that case. */ 601c9710b42Smrg if (value == (FcType) -1) 602c9710b42Smrg return; 6032c393a42Smrg FcConfigMessage (parse, FcSevereWarning, "saw %s, expected %s", 6042c393a42Smrg FcTypeName (value), FcTypeName (type)); 6052c393a42Smrg } 6062c393a42Smrg} 6072c393a42Smrg 6082c393a42Smrgstatic void 6092c393a42SmrgFcTypecheckExpr (FcConfigParse *parse, FcExpr *expr, FcType type) 6102c393a42Smrg{ 6112c393a42Smrg const FcObjectType *o; 6122c393a42Smrg const FcConstant *c; 613ca08ab68Smrg 6142c393a42Smrg /* If parsing the expression failed, some nodes may be NULL */ 6152c393a42Smrg if (!expr) 6162c393a42Smrg return; 6172c393a42Smrg 618ca08ab68Smrg switch (FC_OP_GET_OP (expr->op)) { 6192c393a42Smrg case FcOpInteger: 6202c393a42Smrg case FcOpDouble: 6212c393a42Smrg FcTypecheckValue (parse, FcTypeDouble, type); 6222c393a42Smrg break; 6232c393a42Smrg case FcOpString: 6242c393a42Smrg FcTypecheckValue (parse, FcTypeString, type); 6252c393a42Smrg break; 6262c393a42Smrg case FcOpMatrix: 6272c393a42Smrg FcTypecheckValue (parse, FcTypeMatrix, type); 6282c393a42Smrg break; 6292c393a42Smrg case FcOpBool: 6302c393a42Smrg FcTypecheckValue (parse, FcTypeBool, type); 6312c393a42Smrg break; 6322c393a42Smrg case FcOpCharSet: 6332c393a42Smrg FcTypecheckValue (parse, FcTypeCharSet, type); 6342c393a42Smrg break; 635ca08ab68Smrg case FcOpLangSet: 636ca08ab68Smrg FcTypecheckValue (parse, FcTypeLangSet, type); 637ca08ab68Smrg break; 6382c393a42Smrg case FcOpNil: 6392c393a42Smrg break; 6402c393a42Smrg case FcOpField: 641c9710b42Smrg o = FcNameGetObjectType (FcObjectName (expr->u.name.object)); 6422c393a42Smrg if (o) 6432c393a42Smrg FcTypecheckValue (parse, o->type, type); 6442c393a42Smrg break; 6452c393a42Smrg case FcOpConst: 6462c393a42Smrg c = FcNameGetConstant (expr->u.constant); 6472c393a42Smrg if (c) 6482c393a42Smrg { 6492c393a42Smrg o = FcNameGetObjectType (c->object); 6502c393a42Smrg if (o) 6512c393a42Smrg FcTypecheckValue (parse, o->type, type); 6522c393a42Smrg } 653ca08ab68Smrg else 654ca08ab68Smrg FcConfigMessage (parse, FcSevereWarning, 6552c393a42Smrg "invalid constant used : %s", 6562c393a42Smrg expr->u.constant); 6572c393a42Smrg break; 6582c393a42Smrg case FcOpQuest: 6592c393a42Smrg FcTypecheckExpr (parse, expr->u.tree.left, FcTypeBool); 6602c393a42Smrg FcTypecheckExpr (parse, expr->u.tree.right->u.tree.left, type); 6612c393a42Smrg FcTypecheckExpr (parse, expr->u.tree.right->u.tree.right, type); 6622c393a42Smrg break; 6632c393a42Smrg case FcOpAssign: 6642c393a42Smrg case FcOpAssignReplace: 6652c393a42Smrg break; 6662c393a42Smrg case FcOpEqual: 6672c393a42Smrg case FcOpNotEqual: 6682c393a42Smrg case FcOpLess: 6692c393a42Smrg case FcOpLessEqual: 6702c393a42Smrg case FcOpMore: 6712c393a42Smrg case FcOpMoreEqual: 6722c393a42Smrg case FcOpContains: 6732c393a42Smrg case FcOpNotContains: 6742c393a42Smrg case FcOpListing: 6752c393a42Smrg FcTypecheckValue (parse, FcTypeBool, type); 6762c393a42Smrg break; 6772c393a42Smrg case FcOpComma: 6782c393a42Smrg case FcOpOr: 6792c393a42Smrg case FcOpAnd: 6802c393a42Smrg case FcOpPlus: 6812c393a42Smrg case FcOpMinus: 6822c393a42Smrg case FcOpTimes: 6832c393a42Smrg case FcOpDivide: 6842c393a42Smrg FcTypecheckExpr (parse, expr->u.tree.left, type); 6852c393a42Smrg FcTypecheckExpr (parse, expr->u.tree.right, type); 6862c393a42Smrg break; 6872c393a42Smrg case FcOpNot: 6882c393a42Smrg FcTypecheckValue (parse, FcTypeBool, type); 6892c393a42Smrg FcTypecheckExpr (parse, expr->u.tree.left, FcTypeBool); 6902c393a42Smrg break; 6912c393a42Smrg case FcOpFloor: 6922c393a42Smrg case FcOpCeil: 6932c393a42Smrg case FcOpRound: 6942c393a42Smrg case FcOpTrunc: 6952c393a42Smrg FcTypecheckValue (parse, FcTypeDouble, type); 6962c393a42Smrg FcTypecheckExpr (parse, expr->u.tree.left, FcTypeDouble); 6972c393a42Smrg break; 6982c393a42Smrg default: 6992c393a42Smrg break; 7002c393a42Smrg } 7012c393a42Smrg} 7022c393a42Smrg 7032c393a42Smrgstatic FcTest * 7042c393a42SmrgFcTestCreate (FcConfigParse *parse, 705ca08ab68Smrg FcMatchKind kind, 7062c393a42Smrg FcQual qual, 7072c393a42Smrg const FcChar8 *field, 7082c393a42Smrg FcOp compare, 7092c393a42Smrg FcExpr *expr) 7102c393a42Smrg{ 7112c393a42Smrg FcTest *test = (FcTest *) malloc (sizeof (FcTest)); 7122c393a42Smrg 7132c393a42Smrg if (test) 7142c393a42Smrg { 7152c393a42Smrg const FcObjectType *o; 7162c393a42Smrg 7172c393a42Smrg test->next = 0; 7182c393a42Smrg test->kind = kind; 7192c393a42Smrg test->qual = qual; 7202c393a42Smrg test->object = FcObjectFromName ((const char *) field); 7212c393a42Smrg test->op = compare; 7222c393a42Smrg test->expr = expr; 7232c393a42Smrg o = FcNameGetObjectType (FcObjectName (test->object)); 7242c393a42Smrg if (o) 7252c393a42Smrg FcTypecheckExpr (parse, expr, o->type); 7262c393a42Smrg } 7272c393a42Smrg return test; 7282c393a42Smrg} 7292c393a42Smrg 7302c393a42Smrgstatic FcEdit * 7312c393a42SmrgFcEditCreate (FcConfigParse *parse, 7322c393a42Smrg FcObject object, 7332c393a42Smrg FcOp op, 7342c393a42Smrg FcExpr *expr, 7352c393a42Smrg FcValueBinding binding) 7362c393a42Smrg{ 7372c393a42Smrg FcEdit *e = (FcEdit *) malloc (sizeof (FcEdit)); 7382c393a42Smrg 7392c393a42Smrg if (e) 7402c393a42Smrg { 7412c393a42Smrg const FcObjectType *o; 7422c393a42Smrg 7432c393a42Smrg e->next = 0; 7442c393a42Smrg e->object = object; 7452c393a42Smrg e->op = op; 7462c393a42Smrg e->expr = expr; 7472c393a42Smrg e->binding = binding; 7482c393a42Smrg o = FcNameGetObjectType (FcObjectName (e->object)); 7492c393a42Smrg if (o) 7502c393a42Smrg FcTypecheckExpr (parse, expr, o->type); 7512c393a42Smrg } 7522c393a42Smrg return e; 7532c393a42Smrg} 7542c393a42Smrg 7552c393a42Smrgstatic FcVStack * 756a6844aabSmrgFcVStackCreateAndPush (FcConfigParse *parse) 7572c393a42Smrg{ 7582c393a42Smrg FcVStack *new; 7592c393a42Smrg 760a6844aabSmrg if (parse->vstack_static_used < sizeof (parse->vstack_static) / sizeof (parse->vstack_static[0])) 761a6844aabSmrg new = &parse->vstack_static[parse->vstack_static_used++]; 762a6844aabSmrg else 763a6844aabSmrg { 764a6844aabSmrg new = malloc (sizeof (FcVStack)); 765a6844aabSmrg if (!new) 766a6844aabSmrg return 0; 767a6844aabSmrg } 7682c393a42Smrg new->tag = FcVStackNone; 7692c393a42Smrg new->prev = 0; 7702c393a42Smrg 771a6844aabSmrg new->prev = parse->vstack; 772a6844aabSmrg new->pstack = parse->pstack ? parse->pstack->prev : 0; 773a6844aabSmrg parse->vstack = new; 7742c393a42Smrg 775a6844aabSmrg return new; 7762c393a42Smrg} 7772c393a42Smrg 7782c393a42Smrgstatic FcBool 7792c393a42SmrgFcVStackPushString (FcConfigParse *parse, FcVStackTag tag, FcChar8 *string) 7802c393a42Smrg{ 781a6844aabSmrg FcVStack *vstack = FcVStackCreateAndPush (parse); 7822c393a42Smrg if (!vstack) 7832c393a42Smrg return FcFalse; 7842c393a42Smrg vstack->u.string = string; 7852c393a42Smrg vstack->tag = tag; 7862c393a42Smrg return FcTrue; 7872c393a42Smrg} 7882c393a42Smrg 7892c393a42Smrgstatic FcBool 7902c393a42SmrgFcVStackPushInteger (FcConfigParse *parse, int integer) 7912c393a42Smrg{ 792a6844aabSmrg FcVStack *vstack = FcVStackCreateAndPush (parse); 7932c393a42Smrg if (!vstack) 7942c393a42Smrg return FcFalse; 7952c393a42Smrg vstack->u.integer = integer; 7962c393a42Smrg vstack->tag = FcVStackInteger; 7972c393a42Smrg return FcTrue; 7982c393a42Smrg} 7992c393a42Smrg 8002c393a42Smrgstatic FcBool 8012c393a42SmrgFcVStackPushDouble (FcConfigParse *parse, double _double) 8022c393a42Smrg{ 803a6844aabSmrg FcVStack *vstack = FcVStackCreateAndPush (parse); 8042c393a42Smrg if (!vstack) 8052c393a42Smrg return FcFalse; 8062c393a42Smrg vstack->u._double = _double; 8072c393a42Smrg vstack->tag = FcVStackDouble; 8082c393a42Smrg return FcTrue; 8092c393a42Smrg} 8102c393a42Smrg 8112c393a42Smrgstatic FcBool 812c9710b42SmrgFcVStackPushMatrix (FcConfigParse *parse, FcExprMatrix *matrix) 8132c393a42Smrg{ 814a6844aabSmrg FcVStack *vstack; 815a6844aabSmrg vstack = FcVStackCreateAndPush (parse); 816a6844aabSmrg if (!vstack) 817a6844aabSmrg return FcFalse; 818c9710b42Smrg vstack->u.matrix = FcExprMatrixCopyShallow (matrix); 8192c393a42Smrg vstack->tag = FcVStackMatrix; 8202c393a42Smrg return FcTrue; 8212c393a42Smrg} 8222c393a42Smrg 823ca08ab68Smrgstatic FcBool 824ca08ab68SmrgFcVStackPushRange (FcConfigParse *parse, FcRange *range) 825ca08ab68Smrg{ 826ca08ab68Smrg FcVStack *vstack = FcVStackCreateAndPush (parse); 827ca08ab68Smrg if (!vstack) 828ca08ab68Smrg return FcFalse; 829ca08ab68Smrg vstack->u.range.begin = range->begin; 830ca08ab68Smrg vstack->u.range.end = range->end; 831ca08ab68Smrg vstack->tag = FcVStackRange; 832ca08ab68Smrg return FcTrue; 833ca08ab68Smrg} 834ca08ab68Smrg 8352c393a42Smrgstatic FcBool 836a6844aabSmrgFcVStackPushBool (FcConfigParse *parse, FcBool bool_) 8372c393a42Smrg{ 838a6844aabSmrg FcVStack *vstack = FcVStackCreateAndPush (parse); 8392c393a42Smrg if (!vstack) 8402c393a42Smrg return FcFalse; 841a6844aabSmrg vstack->u.bool_ = bool_; 8422c393a42Smrg vstack->tag = FcVStackBool; 8432c393a42Smrg return FcTrue; 8442c393a42Smrg} 8452c393a42Smrg 846ca08ab68Smrgstatic FcBool 847ca08ab68SmrgFcVStackPushCharSet (FcConfigParse *parse, FcCharSet *charset) 848ca08ab68Smrg{ 849ca08ab68Smrg FcVStack *vstack; 850ca08ab68Smrg if (!charset) 851ca08ab68Smrg return FcFalse; 852ca08ab68Smrg vstack = FcVStackCreateAndPush (parse); 853ca08ab68Smrg if (!vstack) 854ca08ab68Smrg return FcFalse; 855ca08ab68Smrg vstack->u.charset = charset; 856ca08ab68Smrg vstack->tag = FcVStackCharSet; 857ca08ab68Smrg return FcTrue; 858ca08ab68Smrg} 859ca08ab68Smrg 860ca08ab68Smrgstatic FcBool 861ca08ab68SmrgFcVStackPushLangSet (FcConfigParse *parse, FcLangSet *langset) 862ca08ab68Smrg{ 863ca08ab68Smrg FcVStack *vstack; 864ca08ab68Smrg if (!langset) 865ca08ab68Smrg return FcFalse; 866ca08ab68Smrg vstack = FcVStackCreateAndPush (parse); 867ca08ab68Smrg if (!vstack) 868ca08ab68Smrg return FcFalse; 869ca08ab68Smrg vstack->u.langset = langset; 870ca08ab68Smrg vstack->tag = FcVStackLangSet; 871ca08ab68Smrg return FcTrue; 872ca08ab68Smrg} 873ca08ab68Smrg 874c9710b42Smrgstatic FcBool 875c9710b42SmrgFcVStackPushName (FcConfigParse *parse, FcMatchKind kind, FcObject object) 876c9710b42Smrg{ 877c9710b42Smrg FcVStack *vstack = FcVStackCreateAndPush (parse); 878c9710b42Smrg if (!vstack) 879c9710b42Smrg return FcFalse; 880c9710b42Smrg vstack->u.name.object = object; 881c9710b42Smrg vstack->u.name.kind = kind; 882c9710b42Smrg vstack->tag = FcVStackName; 883c9710b42Smrg return FcTrue; 884c9710b42Smrg} 885c9710b42Smrg 8862c393a42Smrgstatic FcBool 8872c393a42SmrgFcVStackPushTest (FcConfigParse *parse, FcTest *test) 8882c393a42Smrg{ 889a6844aabSmrg FcVStack *vstack = FcVStackCreateAndPush (parse); 8902c393a42Smrg if (!vstack) 8912c393a42Smrg return FcFalse; 8922c393a42Smrg vstack->u.test = test; 8932c393a42Smrg vstack->tag = FcVStackTest; 8942c393a42Smrg return FcTrue; 8952c393a42Smrg} 8962c393a42Smrg 8972c393a42Smrgstatic FcBool 8982c393a42SmrgFcVStackPushExpr (FcConfigParse *parse, FcVStackTag tag, FcExpr *expr) 8992c393a42Smrg{ 900a6844aabSmrg FcVStack *vstack = FcVStackCreateAndPush (parse); 9012c393a42Smrg if (!vstack) 9022c393a42Smrg return FcFalse; 9032c393a42Smrg vstack->u.expr = expr; 9042c393a42Smrg vstack->tag = tag; 9052c393a42Smrg return FcTrue; 9062c393a42Smrg} 9072c393a42Smrg 9082c393a42Smrgstatic FcBool 9092c393a42SmrgFcVStackPushEdit (FcConfigParse *parse, FcEdit *edit) 9102c393a42Smrg{ 911a6844aabSmrg FcVStack *vstack = FcVStackCreateAndPush (parse); 9122c393a42Smrg if (!vstack) 9132c393a42Smrg return FcFalse; 9142c393a42Smrg vstack->u.edit = edit; 9152c393a42Smrg vstack->tag = FcVStackEdit; 9162c393a42Smrg return FcTrue; 9172c393a42Smrg} 9182c393a42Smrg 9192c393a42Smrgstatic FcBool 9202c393a42SmrgFcVStackPushPattern (FcConfigParse *parse, FcPattern *pattern) 9212c393a42Smrg{ 922a6844aabSmrg FcVStack *vstack = FcVStackCreateAndPush (parse); 9232c393a42Smrg if (!vstack) 9242c393a42Smrg return FcFalse; 9252c393a42Smrg vstack->u.pattern = pattern; 9262c393a42Smrg vstack->tag = FcVStackPattern; 9272c393a42Smrg return FcTrue; 9282c393a42Smrg} 9292c393a42Smrg 9302c393a42Smrgstatic FcVStack * 9312c393a42SmrgFcVStackFetch (FcConfigParse *parse, int off) 9322c393a42Smrg{ 9332c393a42Smrg FcVStack *vstack; 9342c393a42Smrg 9352c393a42Smrg for (vstack = parse->vstack; vstack && off-- > 0; vstack = vstack->prev); 9362c393a42Smrg return vstack; 9372c393a42Smrg} 9382c393a42Smrg 939a6844aabSmrgstatic FcVStack * 940a6844aabSmrgFcVStackPeek (FcConfigParse *parse) 9412c393a42Smrg{ 942a6844aabSmrg FcVStack *vstack = parse->vstack; 943a6844aabSmrg 944a6844aabSmrg return vstack && vstack->pstack == parse->pstack ? vstack : 0; 9452c393a42Smrg} 9462c393a42Smrg 947a6844aabSmrgstatic void 948a6844aabSmrgFcVStackPopAndDestroy (FcConfigParse *parse) 9492c393a42Smrg{ 9502c393a42Smrg FcVStack *vstack = parse->vstack; 951ca08ab68Smrg 9522c393a42Smrg if (!vstack || vstack->pstack != parse->pstack) 953a6844aabSmrg return; 954a6844aabSmrg 9552c393a42Smrg parse->vstack = vstack->prev; 956a6844aabSmrg 957a6844aabSmrg switch (vstack->tag) { 958a6844aabSmrg case FcVStackNone: 959a6844aabSmrg break; 960c9710b42Smrg case FcVStackName: 961c9710b42Smrg break; 962a6844aabSmrg case FcVStackFamily: 963a6844aabSmrg break; 964a6844aabSmrg case FcVStackString: 965a6844aabSmrg case FcVStackConstant: 966a6844aabSmrg case FcVStackGlob: 967a6844aabSmrg FcStrFree (vstack->u.string); 968a6844aabSmrg break; 969a6844aabSmrg case FcVStackPattern: 970a6844aabSmrg FcPatternDestroy (vstack->u.pattern); 971a6844aabSmrg break; 972a6844aabSmrg case FcVStackInteger: 973a6844aabSmrg case FcVStackDouble: 974a6844aabSmrg break; 975a6844aabSmrg case FcVStackMatrix: 976c9710b42Smrg FcExprMatrixFreeShallow (vstack->u.matrix); 977a6844aabSmrg break; 978ca08ab68Smrg case FcVStackRange: 979a6844aabSmrg case FcVStackBool: 980a6844aabSmrg break; 981ca08ab68Smrg case FcVStackCharSet: 982ca08ab68Smrg FcCharSetDestroy (vstack->u.charset); 983ca08ab68Smrg break; 984ca08ab68Smrg case FcVStackLangSet: 985ca08ab68Smrg FcLangSetDestroy (vstack->u.langset); 986ca08ab68Smrg break; 987a6844aabSmrg case FcVStackTest: 988a6844aabSmrg FcTestDestroy (vstack->u.test); 989a6844aabSmrg break; 990a6844aabSmrg case FcVStackExpr: 991a6844aabSmrg case FcVStackPrefer: 992a6844aabSmrg case FcVStackAccept: 993a6844aabSmrg case FcVStackDefault: 994a6844aabSmrg FcExprDestroy (vstack->u.expr); 995a6844aabSmrg break; 996a6844aabSmrg case FcVStackEdit: 997a6844aabSmrg FcEditDestroy (vstack->u.edit); 998a6844aabSmrg break; 999a6844aabSmrg } 1000a6844aabSmrg 1001a6844aabSmrg if (vstack == &parse->vstack_static[parse->vstack_static_used - 1]) 1002a6844aabSmrg parse->vstack_static_used--; 1003a6844aabSmrg else 1004a6844aabSmrg free (vstack); 1005a6844aabSmrg} 1006a6844aabSmrg 1007a6844aabSmrgstatic void 1008a6844aabSmrgFcVStackClear (FcConfigParse *parse) 1009a6844aabSmrg{ 1010a6844aabSmrg while (FcVStackPeek (parse)) 1011a6844aabSmrg FcVStackPopAndDestroy (parse); 10122c393a42Smrg} 10132c393a42Smrg 10142c393a42Smrgstatic int 10152c393a42SmrgFcVStackElements (FcConfigParse *parse) 10162c393a42Smrg{ 10172c393a42Smrg int h = 0; 10182c393a42Smrg FcVStack *vstack = parse->vstack; 10192c393a42Smrg while (vstack && vstack->pstack == parse->pstack) 10202c393a42Smrg { 10212c393a42Smrg h++; 10222c393a42Smrg vstack = vstack->prev; 10232c393a42Smrg } 10242c393a42Smrg return h; 10252c393a42Smrg} 10262c393a42Smrg 10272c393a42Smrgstatic FcChar8 ** 1028a6844aabSmrgFcConfigSaveAttr (const XML_Char **attr, FcChar8 **buf, int size_bytes) 10292c393a42Smrg{ 10302c393a42Smrg int slen; 10312c393a42Smrg int i; 10322c393a42Smrg FcChar8 **new; 10332c393a42Smrg FcChar8 *s; 10342c393a42Smrg 10352c393a42Smrg if (!attr) 10362c393a42Smrg return 0; 10372c393a42Smrg slen = 0; 10382c393a42Smrg for (i = 0; attr[i]; i++) 10392c393a42Smrg slen += strlen ((char *) attr[i]) + 1; 1040a6844aabSmrg if (i == 0) 10412c393a42Smrg return 0; 1042a6844aabSmrg slen += (i + 1) * sizeof (FcChar8 *); 1043a6844aabSmrg if (slen <= size_bytes) 1044a6844aabSmrg new = buf; 1045a6844aabSmrg else 1046a6844aabSmrg { 1047a6844aabSmrg new = malloc (slen); 1048a6844aabSmrg if (!new) 1049a6844aabSmrg { 1050a6844aabSmrg FcConfigMessage (0, FcSevereError, "out of memory"); 1051a6844aabSmrg return 0; 1052a6844aabSmrg } 1053a6844aabSmrg } 10542c393a42Smrg s = (FcChar8 *) (new + (i + 1)); 10552c393a42Smrg for (i = 0; attr[i]; i++) 10562c393a42Smrg { 10572c393a42Smrg new[i] = s; 10582c393a42Smrg strcpy ((char *) s, (char *) attr[i]); 10592c393a42Smrg s += strlen ((char *) s) + 1; 10602c393a42Smrg } 10612c393a42Smrg new[i] = 0; 10622c393a42Smrg return new; 10632c393a42Smrg} 10642c393a42Smrg 10652c393a42Smrgstatic FcBool 10662c393a42SmrgFcPStackPush (FcConfigParse *parse, FcElement element, const XML_Char **attr) 10672c393a42Smrg{ 1068a6844aabSmrg FcPStack *new; 10692c393a42Smrg 1070a6844aabSmrg if (parse->pstack_static_used < sizeof (parse->pstack_static) / sizeof (parse->pstack_static[0])) 1071a6844aabSmrg new = &parse->pstack_static[parse->pstack_static_used++]; 1072a6844aabSmrg else 10732c393a42Smrg { 1074a6844aabSmrg new = malloc (sizeof (FcPStack)); 1075a6844aabSmrg if (!new) 10762c393a42Smrg return FcFalse; 10772c393a42Smrg } 1078a6844aabSmrg 1079a6844aabSmrg new->prev = parse->pstack; 1080a6844aabSmrg new->element = element; 1081a6844aabSmrg new->attr = FcConfigSaveAttr (attr, new->attr_buf_static, sizeof (new->attr_buf_static)); 10822c393a42Smrg FcStrBufInit (&new->str, 0, 0); 10832c393a42Smrg parse->pstack = new; 10842c393a42Smrg return FcTrue; 10852c393a42Smrg} 10862c393a42Smrg 10872c393a42Smrgstatic FcBool 10882c393a42SmrgFcPStackPop (FcConfigParse *parse) 10892c393a42Smrg{ 10902c393a42Smrg FcPStack *old; 1091ca08ab68Smrg 1092ca08ab68Smrg if (!parse->pstack) 10932c393a42Smrg { 10942c393a42Smrg FcConfigMessage (parse, FcSevereError, "mismatching element"); 10952c393a42Smrg return FcFalse; 10962c393a42Smrg } 1097c9710b42Smrg 1098c9710b42Smrg if (parse->pstack->attr) 1099c9710b42Smrg { 1100c9710b42Smrg /* Warn about unused attrs. */ 1101c9710b42Smrg FcChar8 **attrs = parse->pstack->attr; 1102c9710b42Smrg while (*attrs) 1103c9710b42Smrg { 1104c9710b42Smrg if (attrs[0][0]) 1105c9710b42Smrg { 1106c9710b42Smrg FcConfigMessage (parse, FcSevereError, "invalid attribute '%s'", attrs[0]); 1107c9710b42Smrg } 1108c9710b42Smrg attrs += 2; 1109c9710b42Smrg } 1110c9710b42Smrg } 1111c9710b42Smrg 11122c393a42Smrg FcVStackClear (parse); 11132c393a42Smrg old = parse->pstack; 11142c393a42Smrg parse->pstack = old->prev; 11152c393a42Smrg FcStrBufDestroy (&old->str); 1116c9710b42Smrg 1117a6844aabSmrg if (old->attr && old->attr != old->attr_buf_static) 11182c393a42Smrg free (old->attr); 1119a6844aabSmrg 1120a6844aabSmrg if (old == &parse->pstack_static[parse->pstack_static_used - 1]) 1121a6844aabSmrg parse->pstack_static_used--; 1122a6844aabSmrg else 1123a6844aabSmrg free (old); 11242c393a42Smrg return FcTrue; 11252c393a42Smrg} 11262c393a42Smrg 11272c393a42Smrgstatic FcBool 1128c9710b42SmrgFcConfigParseInit (FcConfigParse *parse, const FcChar8 *name, FcConfig *config, XML_Parser parser) 11292c393a42Smrg{ 11302c393a42Smrg parse->pstack = 0; 1131a6844aabSmrg parse->pstack_static_used = 0; 11322c393a42Smrg parse->vstack = 0; 1133a6844aabSmrg parse->vstack_static_used = 0; 11342c393a42Smrg parse->error = FcFalse; 11352c393a42Smrg parse->name = name; 11362c393a42Smrg parse->config = config; 11372c393a42Smrg parse->parser = parser; 11382c393a42Smrg return FcTrue; 11392c393a42Smrg} 11402c393a42Smrg 11412c393a42Smrgstatic void 11422c393a42SmrgFcConfigCleanup (FcConfigParse *parse) 11432c393a42Smrg{ 11442c393a42Smrg while (parse->pstack) 11452c393a42Smrg FcPStackPop (parse); 11462c393a42Smrg} 11472c393a42Smrg 11482c393a42Smrgstatic const FcChar8 * 11492c393a42SmrgFcConfigGetAttribute (FcConfigParse *parse, const char *attr) 11502c393a42Smrg{ 11512c393a42Smrg FcChar8 **attrs; 11522c393a42Smrg if (!parse->pstack) 11532c393a42Smrg return 0; 11542c393a42Smrg 11552c393a42Smrg attrs = parse->pstack->attr; 11562c393a42Smrg if (!attrs) 11572c393a42Smrg return 0; 11582c393a42Smrg 11592c393a42Smrg while (*attrs) 11602c393a42Smrg { 11612c393a42Smrg if (!strcmp ((char *) *attrs, attr)) 1162c9710b42Smrg { 1163c9710b42Smrg attrs[0][0] = '\0'; /* Mark as used. */ 11642c393a42Smrg return attrs[1]; 1165c9710b42Smrg } 11662c393a42Smrg attrs += 2; 11672c393a42Smrg } 11682c393a42Smrg return 0; 11692c393a42Smrg} 11702c393a42Smrg 11712c393a42Smrgstatic void 11722c393a42SmrgFcStartElement(void *userData, const XML_Char *name, const XML_Char **attr) 11732c393a42Smrg{ 11742c393a42Smrg FcConfigParse *parse = userData; 11752c393a42Smrg FcElement element; 1176ca08ab68Smrg 11772c393a42Smrg element = FcElementMap (name); 11782c393a42Smrg if (element == FcElementUnknown) 11792c393a42Smrg FcConfigMessage (parse, FcSevereWarning, "unknown element \"%s\"", name); 1180ca08ab68Smrg 11812c393a42Smrg if (!FcPStackPush (parse, element, attr)) 11822c393a42Smrg { 11832c393a42Smrg FcConfigMessage (parse, FcSevereError, "out of memory"); 11842c393a42Smrg return; 11852c393a42Smrg } 11862c393a42Smrg return; 11872c393a42Smrg} 11882c393a42Smrg 11892c393a42Smrgstatic void 11902c393a42SmrgFcParseBlank (FcConfigParse *parse) 11912c393a42Smrg{ 1192ca08ab68Smrg int n = FcVStackElements (parse); 1193ca08ab68Smrg FcChar32 i; 11942c393a42Smrg while (n-- > 0) 11952c393a42Smrg { 11962c393a42Smrg FcVStack *v = FcVStackFetch (parse, n); 1197ca08ab68Smrg if (!parse->config->blanks) 11982c393a42Smrg { 1199ca08ab68Smrg parse->config->blanks = FcBlanksCreate (); 12002c393a42Smrg if (!parse->config->blanks) 1201ca08ab68Smrg goto bail; 1202ca08ab68Smrg } 1203c9710b42Smrg switch ((int) v->tag) { 1204ca08ab68Smrg case FcVStackInteger: 12052c393a42Smrg if (!FcBlanksAdd (parse->config->blanks, v->u.integer)) 1206ca08ab68Smrg goto bail; 1207ca08ab68Smrg break; 1208ca08ab68Smrg case FcVStackRange: 1209ca08ab68Smrg if (v->u.range.begin <= v->u.range.end) 12102c393a42Smrg { 1211ca08ab68Smrg for (i = v->u.range.begin; i <= v->u.range.end; i++) 1212ca08ab68Smrg { 1213ca08ab68Smrg if (!FcBlanksAdd (parse->config->blanks, i)) 1214ca08ab68Smrg goto bail; 1215ca08ab68Smrg } 12162c393a42Smrg } 1217ca08ab68Smrg break; 1218ca08ab68Smrg default: 1219ca08ab68Smrg FcConfigMessage (parse, FcSevereError, "invalid element in blank"); 1220ca08ab68Smrg break; 12212c393a42Smrg } 12222c393a42Smrg } 1223ca08ab68Smrg return; 1224ca08ab68Smrg bail: 1225ca08ab68Smrg FcConfigMessage (parse, FcSevereError, "out of memory"); 12262c393a42Smrg} 12272c393a42Smrg 12282c393a42Smrgstatic void 12292c393a42SmrgFcParseRescan (FcConfigParse *parse) 12302c393a42Smrg{ 12312c393a42Smrg int n = FcVStackElements (parse); 12322c393a42Smrg while (n-- > 0) 12332c393a42Smrg { 12342c393a42Smrg FcVStack *v = FcVStackFetch (parse, n); 12352c393a42Smrg if (v->tag != FcVStackInteger) 12362c393a42Smrg FcConfigMessage (parse, FcSevereWarning, "non-integer rescan"); 12372c393a42Smrg else 12382c393a42Smrg parse->config->rescanInterval = v->u.integer; 12392c393a42Smrg } 12402c393a42Smrg} 12412c393a42Smrg 12422c393a42Smrgstatic void 12432c393a42SmrgFcParseInt (FcConfigParse *parse) 12442c393a42Smrg{ 12452c393a42Smrg FcChar8 *s, *end; 12462c393a42Smrg int l; 1247ca08ab68Smrg 12482c393a42Smrg if (!parse->pstack) 12492c393a42Smrg return; 1250a6844aabSmrg s = FcStrBufDoneStatic (&parse->pstack->str); 12512c393a42Smrg if (!s) 12522c393a42Smrg { 12532c393a42Smrg FcConfigMessage (parse, FcSevereError, "out of memory"); 12542c393a42Smrg return; 12552c393a42Smrg } 12562c393a42Smrg end = 0; 12572c393a42Smrg l = (int) strtol ((char *) s, (char **)&end, 0); 12582c393a42Smrg if (end != s + strlen ((char *) s)) 12592c393a42Smrg FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid integer", s); 12602c393a42Smrg else 12612c393a42Smrg FcVStackPushInteger (parse, l); 1262a6844aabSmrg FcStrBufDestroy (&parse->pstack->str); 12632c393a42Smrg} 12642c393a42Smrg 12652c393a42Smrg/* 1266ca08ab68Smrg * idea copied from glib g_ascii_strtod with 1267ca08ab68Smrg * permission of the author (Alexander Larsson) 12682c393a42Smrg */ 12692c393a42Smrg 12702c393a42Smrg#include <locale.h> 12712c393a42Smrg 1272ca08ab68Smrgstatic double 12732c393a42SmrgFcStrtod (char *s, char **end) 12742c393a42Smrg{ 12752c393a42Smrg struct lconv *locale_data; 12762c393a42Smrg char *dot; 12772c393a42Smrg double v; 12782c393a42Smrg 12792c393a42Smrg /* 12802c393a42Smrg * Have to swap the decimal point to match the current locale 12812c393a42Smrg * if that locale doesn't use 0x2e 12822c393a42Smrg */ 12832c393a42Smrg if ((dot = strchr (s, 0x2e)) && 12842c393a42Smrg (locale_data = localeconv ()) && 12852c393a42Smrg (locale_data->decimal_point[0] != 0x2e || 12862c393a42Smrg locale_data->decimal_point[1] != 0)) 12872c393a42Smrg { 12882c393a42Smrg char buf[128]; 12892c393a42Smrg int slen = strlen (s); 12902c393a42Smrg int dlen = strlen (locale_data->decimal_point); 12912c393a42Smrg 12922c393a42Smrg if (slen + dlen > (int) sizeof (buf)) 12932c393a42Smrg { 12942c393a42Smrg if (end) 12952c393a42Smrg *end = s; 12962c393a42Smrg v = 0; 12972c393a42Smrg } 12982c393a42Smrg else 12992c393a42Smrg { 13002c393a42Smrg char *buf_end; 13012c393a42Smrg /* mantissa */ 13022c393a42Smrg strncpy (buf, s, dot - s); 13032c393a42Smrg /* decimal point */ 13042c393a42Smrg strcpy (buf + (dot - s), locale_data->decimal_point); 13052c393a42Smrg /* rest of number */ 13062c393a42Smrg strcpy (buf + (dot - s) + dlen, dot + 1); 13072c393a42Smrg buf_end = 0; 13082c393a42Smrg v = strtod (buf, &buf_end); 13092c393a42Smrg if (buf_end) { 13102c393a42Smrg buf_end = s + (buf_end - buf); 13112c393a42Smrg if (buf_end > dot) 13122c393a42Smrg buf_end -= dlen - 1; 13132c393a42Smrg } 13142c393a42Smrg if (end) 13152c393a42Smrg *end = buf_end; 13162c393a42Smrg } 13172c393a42Smrg } 13182c393a42Smrg else 13192c393a42Smrg v = strtod (s, end); 13202c393a42Smrg return v; 13212c393a42Smrg} 13222c393a42Smrg 13232c393a42Smrgstatic void 13242c393a42SmrgFcParseDouble (FcConfigParse *parse) 13252c393a42Smrg{ 13262c393a42Smrg FcChar8 *s, *end; 13272c393a42Smrg double d; 1328ca08ab68Smrg 13292c393a42Smrg if (!parse->pstack) 13302c393a42Smrg return; 1331a6844aabSmrg s = FcStrBufDoneStatic (&parse->pstack->str); 13322c393a42Smrg if (!s) 13332c393a42Smrg { 13342c393a42Smrg FcConfigMessage (parse, FcSevereError, "out of memory"); 13352c393a42Smrg return; 13362c393a42Smrg } 13372c393a42Smrg end = 0; 13382c393a42Smrg d = FcStrtod ((char *) s, (char **)&end); 13392c393a42Smrg if (end != s + strlen ((char *) s)) 13402c393a42Smrg FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid double", s); 13412c393a42Smrg else 13422c393a42Smrg FcVStackPushDouble (parse, d); 1343a6844aabSmrg FcStrBufDestroy (&parse->pstack->str); 13442c393a42Smrg} 13452c393a42Smrg 13462c393a42Smrgstatic void 13472c393a42SmrgFcParseString (FcConfigParse *parse, FcVStackTag tag) 13482c393a42Smrg{ 13492c393a42Smrg FcChar8 *s; 1350ca08ab68Smrg 13512c393a42Smrg if (!parse->pstack) 13522c393a42Smrg return; 13532c393a42Smrg s = FcStrBufDone (&parse->pstack->str); 13542c393a42Smrg if (!s) 13552c393a42Smrg { 13562c393a42Smrg FcConfigMessage (parse, FcSevereError, "out of memory"); 13572c393a42Smrg return; 13582c393a42Smrg } 13592c393a42Smrg if (!FcVStackPushString (parse, tag, s)) 13602c393a42Smrg FcStrFree (s); 13612c393a42Smrg} 13622c393a42Smrg 13632c393a42Smrgstatic void 1364c9710b42SmrgFcParseName (FcConfigParse *parse) 13652c393a42Smrg{ 1366c9710b42Smrg const FcChar8 *kind_string; 1367c9710b42Smrg FcMatchKind kind; 1368c9710b42Smrg FcChar8 *s; 1369c9710b42Smrg FcObject object; 1370ca08ab68Smrg 1371c9710b42Smrg kind_string = FcConfigGetAttribute (parse, "target"); 1372c9710b42Smrg if (!kind_string) 1373c9710b42Smrg kind = FcMatchDefault; 1374c9710b42Smrg else 13752c393a42Smrg { 1376c9710b42Smrg if (!strcmp ((char *) kind_string, "pattern")) 1377c9710b42Smrg kind = FcMatchPattern; 1378c9710b42Smrg else if (!strcmp ((char *) kind_string, "font")) 1379c9710b42Smrg kind = FcMatchFont; 1380c9710b42Smrg else if (!strcmp ((char *) kind_string, "default")) 1381c9710b42Smrg kind = FcMatchDefault; 1382c9710b42Smrg else 1383c9710b42Smrg { 1384c9710b42Smrg FcConfigMessage (parse, FcSevereWarning, "invalid name target \"%s\"", kind_string); 1385c9710b42Smrg return; 13862c393a42Smrg } 13872c393a42Smrg } 1388c9710b42Smrg 1389c9710b42Smrg if (!parse->pstack) 1390c9710b42Smrg return; 1391c9710b42Smrg s = FcStrBufDone (&parse->pstack->str); 1392c9710b42Smrg if (!s) 1393c9710b42Smrg { 1394c9710b42Smrg FcConfigMessage (parse, FcSevereError, "out of memory"); 1395c9710b42Smrg return; 1396c9710b42Smrg } 1397c9710b42Smrg object = FcObjectFromName ((const char *) s); 1398c9710b42Smrg 1399c9710b42Smrg FcVStackPushName (parse, kind, object); 1400c9710b42Smrg 1401c9710b42Smrg FcStrFree (s); 1402c9710b42Smrg} 1403c9710b42Smrg 1404c9710b42Smrgstatic void 1405c9710b42SmrgFcParseMatrix (FcConfigParse *parse) 1406c9710b42Smrg{ 1407c9710b42Smrg FcExprMatrix m; 1408c9710b42Smrg 1409c9710b42Smrg m.yy = FcPopExpr (parse); 1410c9710b42Smrg m.yx = FcPopExpr (parse); 1411c9710b42Smrg m.xy = FcPopExpr (parse); 1412c9710b42Smrg m.xx = FcPopExpr (parse); 1413c9710b42Smrg 1414c9710b42Smrg if (FcPopExpr (parse)) 1415c9710b42Smrg FcConfigMessage (parse, FcSevereError, "wrong number of matrix elements"); 14162c393a42Smrg else 1417c9710b42Smrg FcVStackPushMatrix (parse, &m); 14182c393a42Smrg} 14192c393a42Smrg 1420ca08ab68Smrgstatic void 1421ca08ab68SmrgFcParseRange (FcConfigParse *parse) 1422ca08ab68Smrg{ 1423ca08ab68Smrg FcVStack *vstack; 1424c9710b42Smrg FcRange r = {0, 0}; 1425ca08ab68Smrg FcChar32 n; 1426ca08ab68Smrg int count = 1; 1427ca08ab68Smrg 1428ca08ab68Smrg while ((vstack = FcVStackPeek (parse))) 1429ca08ab68Smrg { 1430ca08ab68Smrg if (count < 0) 1431ca08ab68Smrg { 1432ca08ab68Smrg FcConfigMessage (parse, FcSevereError, "too many elements in range"); 1433ca08ab68Smrg return; 1434ca08ab68Smrg } 1435c9710b42Smrg switch ((int) vstack->tag) { 1436ca08ab68Smrg case FcVStackInteger: 1437ca08ab68Smrg n = vstack->u.integer; 1438ca08ab68Smrg break; 1439ca08ab68Smrg default: 1440ca08ab68Smrg FcConfigMessage (parse, FcSevereError, "invalid element in range"); 1441ca08ab68Smrg n = 0; 1442ca08ab68Smrg break; 1443ca08ab68Smrg } 1444ca08ab68Smrg if (count == 1) 1445ca08ab68Smrg r.end = n; 1446ca08ab68Smrg else 1447ca08ab68Smrg r.begin = n; 1448ca08ab68Smrg count--; 1449ca08ab68Smrg FcVStackPopAndDestroy (parse); 1450ca08ab68Smrg } 1451ca08ab68Smrg if (count < 0) 1452ca08ab68Smrg { 1453ca08ab68Smrg if (r.begin > r.end) 1454ca08ab68Smrg { 1455ca08ab68Smrg FcConfigMessage (parse, FcSevereError, "invalid range"); 1456ca08ab68Smrg return; 1457ca08ab68Smrg } 1458ca08ab68Smrg FcVStackPushRange (parse, &r); 1459ca08ab68Smrg } 1460ca08ab68Smrg else 1461ca08ab68Smrg FcConfigMessage (parse, FcSevereError, "invalid range"); 1462ca08ab68Smrg} 1463ca08ab68Smrg 14642c393a42Smrgstatic FcBool 1465a6844aabSmrgFcConfigLexBool (FcConfigParse *parse, const FcChar8 *bool_) 14662c393a42Smrg{ 14672c393a42Smrg FcBool result = FcFalse; 14682c393a42Smrg 1469a6844aabSmrg if (!FcNameBool (bool_, &result)) 14702c393a42Smrg FcConfigMessage (parse, FcSevereWarning, "\"%s\" is not known boolean", 1471a6844aabSmrg bool_); 14722c393a42Smrg return result; 14732c393a42Smrg} 14742c393a42Smrg 14752c393a42Smrgstatic void 14762c393a42SmrgFcParseBool (FcConfigParse *parse) 14772c393a42Smrg{ 14782c393a42Smrg FcChar8 *s; 14792c393a42Smrg 14802c393a42Smrg if (!parse->pstack) 14812c393a42Smrg return; 1482a6844aabSmrg s = FcStrBufDoneStatic (&parse->pstack->str); 14832c393a42Smrg if (!s) 14842c393a42Smrg { 14852c393a42Smrg FcConfigMessage (parse, FcSevereError, "out of memory"); 14862c393a42Smrg return; 14872c393a42Smrg } 14882c393a42Smrg FcVStackPushBool (parse, FcConfigLexBool (parse, s)); 1489a6844aabSmrg FcStrBufDestroy (&parse->pstack->str); 14902c393a42Smrg} 14912c393a42Smrg 1492ca08ab68Smrgstatic void 1493ca08ab68SmrgFcParseCharSet (FcConfigParse *parse) 1494ca08ab68Smrg{ 1495ca08ab68Smrg FcVStack *vstack; 1496ca08ab68Smrg FcCharSet *charset = FcCharSetCreate (); 1497ca08ab68Smrg FcChar32 i; 1498ca08ab68Smrg int n = 0; 1499ca08ab68Smrg 1500ca08ab68Smrg while ((vstack = FcVStackPeek (parse))) 1501ca08ab68Smrg { 1502c9710b42Smrg switch ((int) vstack->tag) { 1503ca08ab68Smrg case FcVStackInteger: 1504ca08ab68Smrg if (!FcCharSetAddChar (charset, vstack->u.integer)) 1505ca08ab68Smrg { 1506ca08ab68Smrg FcConfigMessage (parse, FcSevereWarning, "invalid character: 0x%04x", vstack->u.integer); 1507ca08ab68Smrg } 1508ca08ab68Smrg else 1509ca08ab68Smrg n++; 1510ca08ab68Smrg break; 1511ca08ab68Smrg case FcVStackRange: 1512ca08ab68Smrg if (vstack->u.range.begin <= vstack->u.range.end) 1513ca08ab68Smrg { 1514ca08ab68Smrg for (i = vstack->u.range.begin; i <= vstack->u.range.end; i++) 1515ca08ab68Smrg { 1516ca08ab68Smrg if (!FcCharSetAddChar (charset, i)) 1517ca08ab68Smrg { 1518ca08ab68Smrg FcConfigMessage (parse, FcSevereWarning, "invalid character: 0x%04x", i); 1519ca08ab68Smrg } 1520ca08ab68Smrg else 1521ca08ab68Smrg n++; 1522ca08ab68Smrg } 1523ca08ab68Smrg } 1524ca08ab68Smrg break; 1525ca08ab68Smrg default: 1526ca08ab68Smrg FcConfigMessage (parse, FcSevereError, "invalid element in charset"); 1527ca08ab68Smrg break; 1528ca08ab68Smrg } 1529ca08ab68Smrg FcVStackPopAndDestroy (parse); 1530ca08ab68Smrg } 1531ca08ab68Smrg if (n > 0) 1532ca08ab68Smrg FcVStackPushCharSet (parse, charset); 1533ca08ab68Smrg else 1534ca08ab68Smrg FcCharSetDestroy (charset); 1535ca08ab68Smrg} 1536ca08ab68Smrg 1537ca08ab68Smrgstatic void 1538ca08ab68SmrgFcParseLangSet (FcConfigParse *parse) 1539ca08ab68Smrg{ 1540ca08ab68Smrg FcVStack *vstack; 1541ca08ab68Smrg FcLangSet *langset = FcLangSetCreate (); 1542ca08ab68Smrg int n = 0; 1543ca08ab68Smrg 1544ca08ab68Smrg while ((vstack = FcVStackPeek (parse))) 1545ca08ab68Smrg { 1546c9710b42Smrg switch ((int) vstack->tag) { 1547ca08ab68Smrg case FcVStackString: 1548ca08ab68Smrg if (!FcLangSetAdd (langset, vstack->u.string)) 1549ca08ab68Smrg { 1550ca08ab68Smrg FcConfigMessage (parse, FcSevereWarning, "invalid langset: %s", vstack->u.string); 1551ca08ab68Smrg } 1552ca08ab68Smrg else 1553ca08ab68Smrg n++; 1554ca08ab68Smrg break; 1555ca08ab68Smrg default: 1556ca08ab68Smrg FcConfigMessage (parse, FcSevereError, "invalid element in langset"); 1557ca08ab68Smrg break; 1558ca08ab68Smrg } 1559ca08ab68Smrg FcVStackPopAndDestroy (parse); 1560ca08ab68Smrg } 1561ca08ab68Smrg if (n > 0) 1562ca08ab68Smrg FcVStackPushLangSet (parse, langset); 1563ca08ab68Smrg else 1564ca08ab68Smrg FcLangSetDestroy (langset); 1565ca08ab68Smrg} 1566ca08ab68Smrg 15672c393a42Smrgstatic FcBool 15682c393a42SmrgFcConfigLexBinding (FcConfigParse *parse, 15692c393a42Smrg const FcChar8 *binding_string, 15702c393a42Smrg FcValueBinding *binding_ret) 15712c393a42Smrg{ 15722c393a42Smrg FcValueBinding binding; 1573ca08ab68Smrg 15742c393a42Smrg if (!binding_string) 15752c393a42Smrg binding = FcValueBindingWeak; 15762c393a42Smrg else 15772c393a42Smrg { 15782c393a42Smrg if (!strcmp ((char *) binding_string, "weak")) 15792c393a42Smrg binding = FcValueBindingWeak; 15802c393a42Smrg else if (!strcmp ((char *) binding_string, "strong")) 15812c393a42Smrg binding = FcValueBindingStrong; 15822c393a42Smrg else if (!strcmp ((char *) binding_string, "same")) 15832c393a42Smrg binding = FcValueBindingSame; 15842c393a42Smrg else 15852c393a42Smrg { 15862c393a42Smrg FcConfigMessage (parse, FcSevereWarning, "invalid binding \"%s\"", binding_string); 15872c393a42Smrg return FcFalse; 15882c393a42Smrg } 15892c393a42Smrg } 15902c393a42Smrg *binding_ret = binding; 15912c393a42Smrg return FcTrue; 15922c393a42Smrg} 15932c393a42Smrg 15942c393a42Smrgstatic void 15952c393a42SmrgFcParseFamilies (FcConfigParse *parse, FcVStackTag tag) 15962c393a42Smrg{ 15972c393a42Smrg FcVStack *vstack; 15982c393a42Smrg FcExpr *left, *expr = 0, *new; 15992c393a42Smrg 1600a6844aabSmrg while ((vstack = FcVStackPeek (parse))) 16012c393a42Smrg { 16022c393a42Smrg if (vstack->tag != FcVStackFamily) 16032c393a42Smrg { 16042c393a42Smrg FcConfigMessage (parse, FcSevereWarning, "non-family"); 1605a6844aabSmrg FcVStackPopAndDestroy (parse); 16062c393a42Smrg continue; 16072c393a42Smrg } 16082c393a42Smrg left = vstack->u.expr; 16092c393a42Smrg vstack->tag = FcVStackNone; 1610a6844aabSmrg FcVStackPopAndDestroy (parse); 16112c393a42Smrg if (expr) 16122c393a42Smrg { 1613a6844aabSmrg new = FcExprCreateOp (parse->config, left, FcOpComma, expr); 16142c393a42Smrg if (!new) 16152c393a42Smrg { 16162c393a42Smrg FcConfigMessage (parse, FcSevereError, "out of memory"); 16172c393a42Smrg FcExprDestroy (left); 16182c393a42Smrg FcExprDestroy (expr); 16192c393a42Smrg break; 16202c393a42Smrg } 16212c393a42Smrg expr = new; 16222c393a42Smrg } 16232c393a42Smrg else 16242c393a42Smrg expr = left; 16252c393a42Smrg } 16262c393a42Smrg if (expr) 16272c393a42Smrg { 16282c393a42Smrg if (!FcVStackPushExpr (parse, tag, expr)) 16292c393a42Smrg { 16302c393a42Smrg FcConfigMessage (parse, FcSevereError, "out of memory"); 16312c393a42Smrg FcExprDestroy (expr); 16322c393a42Smrg } 16332c393a42Smrg } 16342c393a42Smrg} 16352c393a42Smrg 16362c393a42Smrgstatic void 16372c393a42SmrgFcParseFamily (FcConfigParse *parse) 16382c393a42Smrg{ 16392c393a42Smrg FcChar8 *s; 16402c393a42Smrg FcExpr *expr; 16412c393a42Smrg 16422c393a42Smrg if (!parse->pstack) 16432c393a42Smrg return; 1644a6844aabSmrg s = FcStrBufDoneStatic (&parse->pstack->str); 16452c393a42Smrg if (!s) 16462c393a42Smrg { 16472c393a42Smrg FcConfigMessage (parse, FcSevereError, "out of memory"); 16482c393a42Smrg return; 16492c393a42Smrg } 1650a6844aabSmrg expr = FcExprCreateString (parse->config, s); 1651a6844aabSmrg FcStrBufDestroy (&parse->pstack->str); 16522c393a42Smrg if (expr) 16532c393a42Smrg FcVStackPushExpr (parse, FcVStackFamily, expr); 16542c393a42Smrg} 16552c393a42Smrg 16562c393a42Smrgstatic void 16572c393a42SmrgFcParseAlias (FcConfigParse *parse) 16582c393a42Smrg{ 16592c393a42Smrg FcExpr *family = 0, *accept = 0, *prefer = 0, *def = 0, *new = 0; 16602c393a42Smrg FcEdit *edit = 0, *next; 16612c393a42Smrg FcVStack *vstack; 1662ca08ab68Smrg FcTest *test = NULL; 16632c393a42Smrg FcValueBinding binding; 16642c393a42Smrg 16652c393a42Smrg if (!FcConfigLexBinding (parse, FcConfigGetAttribute (parse, "binding"), &binding)) 16662c393a42Smrg return; 1667a6844aabSmrg while ((vstack = FcVStackPeek (parse))) 16682c393a42Smrg { 1669c9710b42Smrg switch ((int) vstack->tag) { 16702c393a42Smrg case FcVStackFamily: 16712c393a42Smrg if (family) 16722c393a42Smrg { 1673ca08ab68Smrg FcConfigMessage (parse, FcSevereWarning, "Having multiple <family> in <alias> isn't supported and may not work as expected"); 1674a6844aabSmrg new = FcExprCreateOp (parse->config, vstack->u.expr, FcOpComma, family); 16752c393a42Smrg if (!new) 16762c393a42Smrg FcConfigMessage (parse, FcSevereError, "out of memory"); 16772c393a42Smrg else 16782c393a42Smrg family = new; 16792c393a42Smrg } 16802c393a42Smrg else 16812c393a42Smrg new = vstack->u.expr; 16822c393a42Smrg if (new) 16832c393a42Smrg { 16842c393a42Smrg family = new; 16852c393a42Smrg vstack->tag = FcVStackNone; 16862c393a42Smrg } 16872c393a42Smrg break; 16882c393a42Smrg case FcVStackPrefer: 16892c393a42Smrg if (prefer) 16902c393a42Smrg FcExprDestroy (prefer); 16912c393a42Smrg prefer = vstack->u.expr; 16922c393a42Smrg vstack->tag = FcVStackNone; 16932c393a42Smrg break; 16942c393a42Smrg case FcVStackAccept: 16952c393a42Smrg if (accept) 16962c393a42Smrg FcExprDestroy (accept); 16972c393a42Smrg accept = vstack->u.expr; 16982c393a42Smrg vstack->tag = FcVStackNone; 16992c393a42Smrg break; 17002c393a42Smrg case FcVStackDefault: 17012c393a42Smrg if (def) 17022c393a42Smrg FcExprDestroy (def); 17032c393a42Smrg def = vstack->u.expr; 17042c393a42Smrg vstack->tag = FcVStackNone; 17052c393a42Smrg break; 1706ca08ab68Smrg case FcVStackTest: 1707ca08ab68Smrg vstack->u.test->next = test; 1708ca08ab68Smrg test = vstack->u.test; 1709ca08ab68Smrg vstack->tag = FcVStackNone; 1710ca08ab68Smrg break; 17112c393a42Smrg default: 17122c393a42Smrg FcConfigMessage (parse, FcSevereWarning, "bad alias"); 17132c393a42Smrg break; 17142c393a42Smrg } 1715a6844aabSmrg FcVStackPopAndDestroy (parse); 17162c393a42Smrg } 17172c393a42Smrg if (!family) 17182c393a42Smrg { 17192c393a42Smrg FcConfigMessage (parse, FcSevereError, "missing family in alias"); 17202c393a42Smrg if (prefer) 17212c393a42Smrg FcExprDestroy (prefer); 17222c393a42Smrg if (accept) 17232c393a42Smrg FcExprDestroy (accept); 17242c393a42Smrg if (def) 17252c393a42Smrg FcExprDestroy (def); 17262c393a42Smrg return; 17272c393a42Smrg } 17282c393a42Smrg if (prefer) 17292c393a42Smrg { 1730ca08ab68Smrg edit = FcEditCreate (parse, 17312c393a42Smrg FC_FAMILY_OBJECT, 17322c393a42Smrg FcOpPrepend, 17332c393a42Smrg prefer, 17342c393a42Smrg binding); 17352c393a42Smrg if (edit) 17362c393a42Smrg edit->next = 0; 17372c393a42Smrg else 17382c393a42Smrg FcExprDestroy (prefer); 17392c393a42Smrg } 17402c393a42Smrg if (accept) 17412c393a42Smrg { 17422c393a42Smrg next = edit; 17432c393a42Smrg edit = FcEditCreate (parse, 17442c393a42Smrg FC_FAMILY_OBJECT, 17452c393a42Smrg FcOpAppend, 17462c393a42Smrg accept, 17472c393a42Smrg binding); 17482c393a42Smrg if (edit) 17492c393a42Smrg edit->next = next; 17502c393a42Smrg else 17512c393a42Smrg FcExprDestroy (accept); 17522c393a42Smrg } 17532c393a42Smrg if (def) 17542c393a42Smrg { 17552c393a42Smrg next = edit; 17562c393a42Smrg edit = FcEditCreate (parse, 17572c393a42Smrg FC_FAMILY_OBJECT, 17582c393a42Smrg FcOpAppendLast, 17592c393a42Smrg def, 17602c393a42Smrg binding); 17612c393a42Smrg if (edit) 17622c393a42Smrg edit->next = next; 17632c393a42Smrg else 17642c393a42Smrg FcExprDestroy (def); 17652c393a42Smrg } 17662c393a42Smrg if (edit) 17672c393a42Smrg { 1768ca08ab68Smrg FcTest *t = FcTestCreate (parse, FcMatchPattern, 1769ca08ab68Smrg FcQualAny, 1770ca08ab68Smrg (FcChar8 *) FC_FAMILY, 1771ca08ab68Smrg FC_OP (FcOpEqual, FcOpFlagIgnoreBlanks), 1772ca08ab68Smrg family); 1773ca08ab68Smrg if (test) 1774ca08ab68Smrg { 1775ca08ab68Smrg FcTest *p = test; 1776ca08ab68Smrg 1777ca08ab68Smrg while (p->next) 1778ca08ab68Smrg p = p->next; 1779ca08ab68Smrg p->next = t; 1780ca08ab68Smrg } 1781ca08ab68Smrg else 1782ca08ab68Smrg test = t; 17832c393a42Smrg if (test) 17842c393a42Smrg if (!FcConfigAddEdit (parse->config, test, edit, FcMatchPattern)) 17852c393a42Smrg FcTestDestroy (test); 17862c393a42Smrg } 17872c393a42Smrg else 17882c393a42Smrg FcExprDestroy (family); 17892c393a42Smrg} 17902c393a42Smrg 17912c393a42Smrgstatic FcExpr * 17922c393a42SmrgFcPopExpr (FcConfigParse *parse) 17932c393a42Smrg{ 1794a6844aabSmrg FcVStack *vstack = FcVStackPeek (parse); 17952c393a42Smrg FcExpr *expr = 0; 17962c393a42Smrg if (!vstack) 17972c393a42Smrg return 0; 1798c9710b42Smrg switch ((int) vstack->tag) { 17992c393a42Smrg case FcVStackNone: 18002c393a42Smrg break; 18012c393a42Smrg case FcVStackString: 18022c393a42Smrg case FcVStackFamily: 1803a6844aabSmrg expr = FcExprCreateString (parse->config, vstack->u.string); 18042c393a42Smrg break; 1805c9710b42Smrg case FcVStackName: 1806c9710b42Smrg expr = FcExprCreateName (parse->config, vstack->u.name); 18072c393a42Smrg break; 18082c393a42Smrg case FcVStackConstant: 1809a6844aabSmrg expr = FcExprCreateConst (parse->config, vstack->u.string); 18102c393a42Smrg break; 18112c393a42Smrg case FcVStackGlob: 18122c393a42Smrg /* XXX: What's the correct action here? (CDW) */ 18132c393a42Smrg break; 18142c393a42Smrg case FcVStackPrefer: 18152c393a42Smrg case FcVStackAccept: 18162c393a42Smrg case FcVStackDefault: 18172c393a42Smrg expr = vstack->u.expr; 18182c393a42Smrg vstack->tag = FcVStackNone; 18192c393a42Smrg break; 18202c393a42Smrg case FcVStackInteger: 1821a6844aabSmrg expr = FcExprCreateInteger (parse->config, vstack->u.integer); 18222c393a42Smrg break; 18232c393a42Smrg case FcVStackDouble: 1824a6844aabSmrg expr = FcExprCreateDouble (parse->config, vstack->u._double); 18252c393a42Smrg break; 18262c393a42Smrg case FcVStackMatrix: 1827a6844aabSmrg expr = FcExprCreateMatrix (parse->config, vstack->u.matrix); 18282c393a42Smrg break; 1829ca08ab68Smrg case FcVStackRange: 1830ca08ab68Smrg break; 18312c393a42Smrg case FcVStackBool: 1832a6844aabSmrg expr = FcExprCreateBool (parse->config, vstack->u.bool_); 18332c393a42Smrg break; 1834ca08ab68Smrg case FcVStackCharSet: 1835ca08ab68Smrg expr = FcExprCreateCharSet (parse->config, vstack->u.charset); 1836ca08ab68Smrg break; 1837ca08ab68Smrg case FcVStackLangSet: 1838ca08ab68Smrg expr = FcExprCreateLangSet (parse->config, vstack->u.langset); 1839ca08ab68Smrg break; 18402c393a42Smrg case FcVStackTest: 18412c393a42Smrg break; 18422c393a42Smrg case FcVStackExpr: 18432c393a42Smrg expr = vstack->u.expr; 18442c393a42Smrg vstack->tag = FcVStackNone; 18452c393a42Smrg break; 18462c393a42Smrg case FcVStackEdit: 18472c393a42Smrg break; 18482c393a42Smrg default: 18492c393a42Smrg break; 18502c393a42Smrg } 1851a6844aabSmrg FcVStackPopAndDestroy (parse); 18522c393a42Smrg return expr; 18532c393a42Smrg} 18542c393a42Smrg 18552c393a42Smrg/* 18562c393a42Smrg * This builds a tree of binary operations. Note 18572c393a42Smrg * that every operator is defined so that if only 18582c393a42Smrg * a single operand is contained, the value of the 18592c393a42Smrg * whole expression is the value of the operand. 18602c393a42Smrg * 18612c393a42Smrg * This code reduces in that case to returning that 18622c393a42Smrg * operand. 18632c393a42Smrg */ 18642c393a42Smrgstatic FcExpr * 18652c393a42SmrgFcPopBinary (FcConfigParse *parse, FcOp op) 18662c393a42Smrg{ 18672c393a42Smrg FcExpr *left, *expr = 0, *new; 18682c393a42Smrg 18692c393a42Smrg while ((left = FcPopExpr (parse))) 18702c393a42Smrg { 18712c393a42Smrg if (expr) 18722c393a42Smrg { 1873a6844aabSmrg new = FcExprCreateOp (parse->config, left, op, expr); 18742c393a42Smrg if (!new) 18752c393a42Smrg { 18762c393a42Smrg FcConfigMessage (parse, FcSevereError, "out of memory"); 18772c393a42Smrg FcExprDestroy (left); 18782c393a42Smrg FcExprDestroy (expr); 18792c393a42Smrg return 0; 18802c393a42Smrg } 18812c393a42Smrg expr = new; 18822c393a42Smrg } 18832c393a42Smrg else 18842c393a42Smrg expr = left; 18852c393a42Smrg } 18862c393a42Smrg return expr; 18872c393a42Smrg} 18882c393a42Smrg 18892c393a42Smrgstatic void 18902c393a42SmrgFcParseBinary (FcConfigParse *parse, FcOp op) 18912c393a42Smrg{ 18922c393a42Smrg FcExpr *expr = FcPopBinary (parse, op); 18932c393a42Smrg if (expr) 18942c393a42Smrg FcVStackPushExpr (parse, FcVStackExpr, expr); 18952c393a42Smrg} 18962c393a42Smrg 18972c393a42Smrg/* 18982c393a42Smrg * This builds a a unary operator, it consumes only 18992c393a42Smrg * a single operand 19002c393a42Smrg */ 19012c393a42Smrg 19022c393a42Smrgstatic FcExpr * 19032c393a42SmrgFcPopUnary (FcConfigParse *parse, FcOp op) 19042c393a42Smrg{ 19052c393a42Smrg FcExpr *operand, *new = 0; 19062c393a42Smrg 19072c393a42Smrg if ((operand = FcPopExpr (parse))) 19082c393a42Smrg { 1909a6844aabSmrg new = FcExprCreateOp (parse->config, operand, op, 0); 19102c393a42Smrg if (!new) 19112c393a42Smrg { 19122c393a42Smrg FcExprDestroy (operand); 19132c393a42Smrg FcConfigMessage (parse, FcSevereError, "out of memory"); 19142c393a42Smrg } 19152c393a42Smrg } 19162c393a42Smrg return new; 19172c393a42Smrg} 19182c393a42Smrg 19192c393a42Smrgstatic void 19202c393a42SmrgFcParseUnary (FcConfigParse *parse, FcOp op) 19212c393a42Smrg{ 19222c393a42Smrg FcExpr *expr = FcPopUnary (parse, op); 19232c393a42Smrg if (expr) 19242c393a42Smrg FcVStackPushExpr (parse, FcVStackExpr, expr); 19252c393a42Smrg} 19262c393a42Smrg 1927ca08ab68Smrgstatic void 1928ca08ab68SmrgFcParseDir (FcConfigParse *parse) 1929ca08ab68Smrg{ 1930ca08ab68Smrg const FcChar8 *attr, *data; 1931c9710b42Smrg FcChar8 *prefix = NULL, *p; 1932ca08ab68Smrg#ifdef _WIN32 1933ca08ab68Smrg FcChar8 buffer[1000]; 1934ca08ab68Smrg#endif 1935ca08ab68Smrg 1936ca08ab68Smrg attr = FcConfigGetAttribute (parse, "prefix"); 1937ca08ab68Smrg if (attr && FcStrCmp (attr, (const FcChar8 *)"xdg") == 0) 1938ca08ab68Smrg prefix = FcConfigXdgDataHome (); 1939ca08ab68Smrg data = FcStrBufDoneStatic (&parse->pstack->str); 1940ca08ab68Smrg if (!data) 1941ca08ab68Smrg { 1942ca08ab68Smrg FcConfigMessage (parse, FcSevereError, "out of memory"); 1943c9710b42Smrg data = prefix; 1944ca08ab68Smrg goto bail; 1945ca08ab68Smrg } 1946ca08ab68Smrg if (prefix) 1947ca08ab68Smrg { 1948ca08ab68Smrg size_t plen = strlen ((const char *)prefix); 1949ca08ab68Smrg size_t dlen = strlen ((const char *)data); 1950ca08ab68Smrg 1951c9710b42Smrg p = realloc (prefix, plen + 1 + dlen + 1); 1952c9710b42Smrg if (!p) 1953ca08ab68Smrg { 1954ca08ab68Smrg FcConfigMessage (parse, FcSevereError, "out of memory"); 1955ca08ab68Smrg goto bail; 1956ca08ab68Smrg } 1957c9710b42Smrg prefix = p; 1958ca08ab68Smrg prefix[plen] = FC_DIR_SEPARATOR; 1959ca08ab68Smrg memcpy (&prefix[plen + 1], data, dlen); 1960ca08ab68Smrg prefix[plen + 1 + dlen] = 0; 1961ca08ab68Smrg data = prefix; 1962ca08ab68Smrg } 1963ca08ab68Smrg#ifdef _WIN32 1964ca08ab68Smrg if (strcmp ((const char *) data, "CUSTOMFONTDIR") == 0) 1965ca08ab68Smrg { 1966c9710b42Smrg FcChar8 *p; 1967ca08ab68Smrg data = buffer; 1968ca08ab68Smrg if (!GetModuleFileName (NULL, (LPCH) buffer, sizeof (buffer) - 20)) 1969ca08ab68Smrg { 1970ca08ab68Smrg FcConfigMessage (parse, FcSevereError, "GetModuleFileName failed"); 1971ca08ab68Smrg goto bail; 1972ca08ab68Smrg } 1973ca08ab68Smrg /* 1974ca08ab68Smrg * Must use the multi-byte aware function to search 1975ca08ab68Smrg * for backslash because East Asian double-byte code 1976ca08ab68Smrg * pages have characters with backslash as the second 1977ca08ab68Smrg * byte. 1978ca08ab68Smrg */ 1979ca08ab68Smrg p = _mbsrchr (data, '\\'); 1980ca08ab68Smrg if (p) *p = '\0'; 1981c9710b42Smrg strcat ((char *) data, "\\fonts"); 1982ca08ab68Smrg } 1983ca08ab68Smrg else if (strcmp ((const char *) data, "APPSHAREFONTDIR") == 0) 1984ca08ab68Smrg { 1985c9710b42Smrg FcChar8 *p; 1986ca08ab68Smrg data = buffer; 1987ca08ab68Smrg if (!GetModuleFileName (NULL, (LPCH) buffer, sizeof (buffer) - 20)) 1988ca08ab68Smrg { 1989ca08ab68Smrg FcConfigMessage (parse, FcSevereError, "GetModuleFileName failed"); 1990ca08ab68Smrg goto bail; 1991ca08ab68Smrg } 1992ca08ab68Smrg p = _mbsrchr (data, '\\'); 1993ca08ab68Smrg if (p) *p = '\0'; 1994c9710b42Smrg strcat ((char *) data, "\\..\\share\\fonts"); 1995ca08ab68Smrg } 1996ca08ab68Smrg else if (strcmp ((const char *) data, "WINDOWSFONTDIR") == 0) 1997ca08ab68Smrg { 1998ca08ab68Smrg int rc; 1999ca08ab68Smrg data = buffer; 2000ca08ab68Smrg rc = pGetSystemWindowsDirectory ((LPSTR) buffer, sizeof (buffer) - 20); 2001ca08ab68Smrg if (rc == 0 || rc > sizeof (buffer) - 20) 2002ca08ab68Smrg { 2003ca08ab68Smrg FcConfigMessage (parse, FcSevereError, "GetSystemWindowsDirectory failed"); 2004ca08ab68Smrg goto bail; 2005ca08ab68Smrg } 2006ca08ab68Smrg if (data [strlen ((const char *) data) - 1] != '\\') 2007c9710b42Smrg strcat ((char *) data, "\\"); 2008c9710b42Smrg strcat ((char *) data, "fonts"); 2009ca08ab68Smrg } 2010ca08ab68Smrg#endif 2011ca08ab68Smrg if (strlen ((char *) data) == 0) 2012ca08ab68Smrg FcConfigMessage (parse, FcSevereWarning, "empty font directory name ignored"); 2013ca08ab68Smrg else if (!FcStrUsesHome (data) || FcConfigHome ()) 2014ca08ab68Smrg { 2015ca08ab68Smrg if (!FcConfigAddDir (parse->config, data)) 2016ca08ab68Smrg FcConfigMessage (parse, FcSevereError, "out of memory; cannot add directory %s", data); 2017ca08ab68Smrg } 2018ca08ab68Smrg FcStrBufDestroy (&parse->pstack->str); 2019ca08ab68Smrg 2020ca08ab68Smrg bail: 2021ca08ab68Smrg if (prefix) 2022ca08ab68Smrg FcStrFree (prefix); 2023ca08ab68Smrg} 2024ca08ab68Smrg 2025ca08ab68Smrgstatic void 2026ca08ab68SmrgFcParseCacheDir (FcConfigParse *parse) 2027ca08ab68Smrg{ 2028ca08ab68Smrg const FcChar8 *attr; 2029c9710b42Smrg FcChar8 *prefix = NULL, *p, *data; 2030ca08ab68Smrg 2031ca08ab68Smrg attr = FcConfigGetAttribute (parse, "prefix"); 2032ca08ab68Smrg if (attr && FcStrCmp (attr, (const FcChar8 *)"xdg") == 0) 2033ca08ab68Smrg prefix = FcConfigXdgCacheHome (); 2034ca08ab68Smrg data = FcStrBufDone (&parse->pstack->str); 2035ca08ab68Smrg if (!data) 2036ca08ab68Smrg { 2037ca08ab68Smrg FcConfigMessage (parse, FcSevereError, "out of memory"); 2038ca08ab68Smrg goto bail; 2039ca08ab68Smrg } 2040ca08ab68Smrg if (prefix) 2041ca08ab68Smrg { 2042ca08ab68Smrg size_t plen = strlen ((const char *)prefix); 2043ca08ab68Smrg size_t dlen = strlen ((const char *)data); 2044ca08ab68Smrg 2045c9710b42Smrg p = realloc (prefix, plen + 1 + dlen + 1); 2046c9710b42Smrg if (!p) 2047ca08ab68Smrg { 2048ca08ab68Smrg FcConfigMessage (parse, FcSevereError, "out of memory"); 2049c9710b42Smrg data = prefix; 2050ca08ab68Smrg goto bail; 2051ca08ab68Smrg } 2052c9710b42Smrg prefix = p; 2053ca08ab68Smrg prefix[plen] = FC_DIR_SEPARATOR; 2054ca08ab68Smrg memcpy (&prefix[plen + 1], data, dlen); 2055ca08ab68Smrg prefix[plen + 1 + dlen] = 0; 2056ca08ab68Smrg FcStrFree (data); 2057ca08ab68Smrg data = prefix; 2058ca08ab68Smrg } 2059ca08ab68Smrg#ifdef _WIN32 2060ca08ab68Smrg if (strcmp ((const char *) data, "WINDOWSTEMPDIR_FONTCONFIG_CACHE") == 0) 2061ca08ab68Smrg { 2062ca08ab68Smrg int rc; 2063ca08ab68Smrg FcStrFree (data); 2064ca08ab68Smrg data = malloc (1000); 2065ca08ab68Smrg if (!data) 2066ca08ab68Smrg { 2067ca08ab68Smrg FcConfigMessage (parse, FcSevereError, "out of memory"); 2068ca08ab68Smrg goto bail; 2069ca08ab68Smrg } 2070ca08ab68Smrg rc = GetTempPath (800, (LPSTR) data); 2071ca08ab68Smrg if (rc == 0 || rc > 800) 2072ca08ab68Smrg { 2073ca08ab68Smrg FcConfigMessage (parse, FcSevereError, "GetTempPath failed"); 2074ca08ab68Smrg goto bail; 2075ca08ab68Smrg } 2076ca08ab68Smrg if (data [strlen ((const char *) data) - 1] != '\\') 2077c9710b42Smrg strcat ((char *) data, "\\"); 2078c9710b42Smrg strcat ((char *) data, "fontconfig\\cache"); 2079ca08ab68Smrg } 2080ca08ab68Smrg else if (strcmp ((const char *) data, "LOCAL_APPDATA_FONTCONFIG_CACHE") == 0) 2081ca08ab68Smrg { 2082ca08ab68Smrg char szFPath[MAX_PATH + 1]; 2083ca08ab68Smrg size_t len; 2084ca08ab68Smrg 2085ca08ab68Smrg if (!(pSHGetFolderPathA && SUCCEEDED(pSHGetFolderPathA(NULL, /* CSIDL_LOCAL_APPDATA */ 28, NULL, 0, szFPath)))) 2086ca08ab68Smrg { 2087ca08ab68Smrg FcConfigMessage (parse, FcSevereError, "SHGetFolderPathA failed"); 2088ca08ab68Smrg goto bail; 2089ca08ab68Smrg } 2090ca08ab68Smrg strncat(szFPath, "\\fontconfig\\cache", MAX_PATH - 1 - strlen(szFPath)); 2091ca08ab68Smrg len = strlen(szFPath) + 1; 2092ca08ab68Smrg FcStrFree (data); 2093ca08ab68Smrg data = malloc(len); 2094ca08ab68Smrg if (!data) 2095ca08ab68Smrg { 2096ca08ab68Smrg FcConfigMessage (parse, FcSevereError, "out of memory"); 2097ca08ab68Smrg goto bail; 2098ca08ab68Smrg } 2099ca08ab68Smrg strncpy((char *) data, szFPath, len); 2100ca08ab68Smrg } 2101ca08ab68Smrg#endif 2102ca08ab68Smrg if (strlen ((char *) data) == 0) 2103ca08ab68Smrg FcConfigMessage (parse, FcSevereWarning, "empty cache directory name ignored"); 2104ca08ab68Smrg else if (!FcStrUsesHome (data) || FcConfigHome ()) 2105ca08ab68Smrg { 2106ca08ab68Smrg if (!FcConfigAddCacheDir (parse->config, data)) 2107ca08ab68Smrg FcConfigMessage (parse, FcSevereError, "out of memory; cannot add cache directory %s", data); 2108ca08ab68Smrg } 2109ca08ab68Smrg FcStrBufDestroy (&parse->pstack->str); 2110ca08ab68Smrg 2111ca08ab68Smrg bail: 2112ca08ab68Smrg if (data) 2113ca08ab68Smrg FcStrFree (data); 2114ca08ab68Smrg} 2115ca08ab68Smrg 21162c393a42Smrgstatic void 21172c393a42SmrgFcParseInclude (FcConfigParse *parse) 21182c393a42Smrg{ 21192c393a42Smrg FcChar8 *s; 2120ca08ab68Smrg const FcChar8 *attr; 21212c393a42Smrg FcBool ignore_missing = FcFalse; 2122ca08ab68Smrg FcBool deprecated = FcFalse; 2123c9710b42Smrg FcChar8 *prefix = NULL, *p; 2124ca08ab68Smrg 2125a6844aabSmrg s = FcStrBufDoneStatic (&parse->pstack->str); 21262c393a42Smrg if (!s) 21272c393a42Smrg { 21282c393a42Smrg FcConfigMessage (parse, FcSevereError, "out of memory"); 2129ca08ab68Smrg goto bail; 21302c393a42Smrg } 2131ca08ab68Smrg attr = FcConfigGetAttribute (parse, "ignore_missing"); 2132ca08ab68Smrg if (attr && FcConfigLexBool (parse, (FcChar8 *) attr) == FcTrue) 21332c393a42Smrg ignore_missing = FcTrue; 2134ca08ab68Smrg attr = FcConfigGetAttribute (parse, "deprecated"); 2135ca08ab68Smrg if (attr && FcConfigLexBool (parse, (FcChar8 *) attr) == FcTrue) 2136ca08ab68Smrg deprecated = FcTrue; 2137ca08ab68Smrg attr = FcConfigGetAttribute (parse, "prefix"); 2138ca08ab68Smrg if (attr && FcStrCmp (attr, (const FcChar8 *)"xdg") == 0) 2139ca08ab68Smrg prefix = FcConfigXdgConfigHome (); 2140ca08ab68Smrg if (prefix) 2141ca08ab68Smrg { 2142ca08ab68Smrg size_t plen = strlen ((const char *)prefix); 2143ca08ab68Smrg size_t dlen = strlen ((const char *)s); 2144ca08ab68Smrg 2145c9710b42Smrg p = realloc (prefix, plen + 1 + dlen + 1); 2146c9710b42Smrg if (!p) 2147ca08ab68Smrg { 2148ca08ab68Smrg FcConfigMessage (parse, FcSevereError, "out of memory"); 2149ca08ab68Smrg goto bail; 2150ca08ab68Smrg } 2151c9710b42Smrg prefix = p; 2152ca08ab68Smrg prefix[plen] = FC_DIR_SEPARATOR; 2153ca08ab68Smrg memcpy (&prefix[plen + 1], s, dlen); 2154ca08ab68Smrg prefix[plen + 1 + dlen] = 0; 2155ca08ab68Smrg s = prefix; 2156ca08ab68Smrg } 21572c393a42Smrg if (!FcConfigParseAndLoad (parse->config, s, !ignore_missing)) 21582c393a42Smrg parse->error = FcTrue; 2159ca08ab68Smrg else 2160ca08ab68Smrg { 2161ca08ab68Smrg FcChar8 *filename; 2162ca08ab68Smrg 2163ca08ab68Smrg filename = FcConfigFilename(s); 2164c9710b42Smrg if (deprecated == FcTrue && 2165c9710b42Smrg filename != NULL && 2166c9710b42Smrg !FcFileIsLink (filename)) 2167c9710b42Smrg { 2168ca08ab68Smrg FcConfigMessage (parse, FcSevereWarning, "reading configurations from %s is deprecated.", s); 2169ca08ab68Smrg } 2170ca08ab68Smrg if(filename) 2171ca08ab68Smrg FcStrFree(filename); 2172ca08ab68Smrg } 2173a6844aabSmrg FcStrBufDestroy (&parse->pstack->str); 2174ca08ab68Smrg 2175ca08ab68Smrg bail: 2176ca08ab68Smrg if (prefix) 2177ca08ab68Smrg FcStrFree (prefix); 21782c393a42Smrg} 21792c393a42Smrg 21802c393a42Smrgtypedef struct _FcOpMap { 21812c393a42Smrg char name[16]; 21822c393a42Smrg FcOp op; 21832c393a42Smrg} FcOpMap; 21842c393a42Smrg 21852c393a42Smrgstatic FcOp 21862c393a42SmrgFcConfigLexOp (const FcChar8 *op, const FcOpMap *map, int nmap) 21872c393a42Smrg{ 21882c393a42Smrg int i; 21892c393a42Smrg 21902c393a42Smrg for (i = 0; i < nmap; i++) 2191ca08ab68Smrg if (!strcmp ((char *) op, map[i].name)) 21922c393a42Smrg return map[i].op; 21932c393a42Smrg return FcOpInvalid; 21942c393a42Smrg} 21952c393a42Smrg 21962c393a42Smrgstatic const FcOpMap fcCompareOps[] = { 21972c393a42Smrg { "eq", FcOpEqual }, 21982c393a42Smrg { "not_eq", FcOpNotEqual }, 21992c393a42Smrg { "less", FcOpLess }, 22002c393a42Smrg { "less_eq", FcOpLessEqual }, 22012c393a42Smrg { "more", FcOpMore }, 22022c393a42Smrg { "more_eq", FcOpMoreEqual }, 22032c393a42Smrg { "contains", FcOpContains }, 22042c393a42Smrg { "not_contains", FcOpNotContains } 22052c393a42Smrg}; 22062c393a42Smrg 22072c393a42Smrg#define NUM_COMPARE_OPS (int) (sizeof fcCompareOps / sizeof fcCompareOps[0]) 22082c393a42Smrg 22092c393a42Smrgstatic FcOp 22102c393a42SmrgFcConfigLexCompare (const FcChar8 *compare) 22112c393a42Smrg{ 22122c393a42Smrg return FcConfigLexOp (compare, fcCompareOps, NUM_COMPARE_OPS); 22132c393a42Smrg} 22142c393a42Smrg 22152c393a42Smrgstatic void 22162c393a42SmrgFcParseTest (FcConfigParse *parse) 22172c393a42Smrg{ 22182c393a42Smrg const FcChar8 *kind_string; 22192c393a42Smrg FcMatchKind kind; 22202c393a42Smrg const FcChar8 *qual_string; 22212c393a42Smrg FcQual qual; 22222c393a42Smrg const FcChar8 *name; 22232c393a42Smrg const FcChar8 *compare_string; 22242c393a42Smrg FcOp compare; 22252c393a42Smrg FcExpr *expr; 22262c393a42Smrg FcTest *test; 2227ca08ab68Smrg const FcChar8 *iblanks_string; 2228ca08ab68Smrg int flags = 0; 22292c393a42Smrg 22302c393a42Smrg kind_string = FcConfigGetAttribute (parse, "target"); 22312c393a42Smrg if (!kind_string) 22322c393a42Smrg kind = FcMatchDefault; 22332c393a42Smrg else 22342c393a42Smrg { 22352c393a42Smrg if (!strcmp ((char *) kind_string, "pattern")) 22362c393a42Smrg kind = FcMatchPattern; 22372c393a42Smrg else if (!strcmp ((char *) kind_string, "font")) 22382c393a42Smrg kind = FcMatchFont; 22392c393a42Smrg else if (!strcmp ((char *) kind_string, "scan")) 22402c393a42Smrg kind = FcMatchScan; 22412c393a42Smrg else if (!strcmp ((char *) kind_string, "default")) 22422c393a42Smrg kind = FcMatchDefault; 22432c393a42Smrg else 22442c393a42Smrg { 22452c393a42Smrg FcConfigMessage (parse, FcSevereWarning, "invalid test target \"%s\"", kind_string); 22462c393a42Smrg return; 22472c393a42Smrg } 22482c393a42Smrg } 22492c393a42Smrg qual_string = FcConfigGetAttribute (parse, "qual"); 22502c393a42Smrg if (!qual_string) 22512c393a42Smrg qual = FcQualAny; 22522c393a42Smrg else 22532c393a42Smrg { 22542c393a42Smrg if (!strcmp ((char *) qual_string, "any")) 22552c393a42Smrg qual = FcQualAny; 22562c393a42Smrg else if (!strcmp ((char *) qual_string, "all")) 22572c393a42Smrg qual = FcQualAll; 22582c393a42Smrg else if (!strcmp ((char *) qual_string, "first")) 22592c393a42Smrg qual = FcQualFirst; 22602c393a42Smrg else if (!strcmp ((char *) qual_string, "not_first")) 22612c393a42Smrg qual = FcQualNotFirst; 22622c393a42Smrg else 22632c393a42Smrg { 22642c393a42Smrg FcConfigMessage (parse, FcSevereWarning, "invalid test qual \"%s\"", qual_string); 22652c393a42Smrg return; 22662c393a42Smrg } 22672c393a42Smrg } 22682c393a42Smrg name = FcConfigGetAttribute (parse, "name"); 22692c393a42Smrg if (!name) 22702c393a42Smrg { 22712c393a42Smrg FcConfigMessage (parse, FcSevereWarning, "missing test name"); 22722c393a42Smrg return; 22732c393a42Smrg } 22742c393a42Smrg compare_string = FcConfigGetAttribute (parse, "compare"); 22752c393a42Smrg if (!compare_string) 22762c393a42Smrg compare = FcOpEqual; 22772c393a42Smrg else 22782c393a42Smrg { 22792c393a42Smrg compare = FcConfigLexCompare (compare_string); 22802c393a42Smrg if (compare == FcOpInvalid) 22812c393a42Smrg { 22822c393a42Smrg FcConfigMessage (parse, FcSevereWarning, "invalid test compare \"%s\"", compare_string); 22832c393a42Smrg return; 22842c393a42Smrg } 22852c393a42Smrg } 2286ca08ab68Smrg iblanks_string = FcConfigGetAttribute (parse, "ignore-blanks"); 2287ca08ab68Smrg if (iblanks_string) 2288ca08ab68Smrg { 2289ca08ab68Smrg FcBool f = FcFalse; 2290ca08ab68Smrg 2291ca08ab68Smrg if (!FcNameBool (iblanks_string, &f)) 2292ca08ab68Smrg { 2293ca08ab68Smrg FcConfigMessage (parse, 2294ca08ab68Smrg FcSevereWarning, 2295ca08ab68Smrg "invalid test ignore-blanks \"%s\"", iblanks_string); 2296ca08ab68Smrg } 2297ca08ab68Smrg if (f) 2298ca08ab68Smrg flags |= FcOpFlagIgnoreBlanks; 2299ca08ab68Smrg } 23002c393a42Smrg expr = FcPopBinary (parse, FcOpComma); 23012c393a42Smrg if (!expr) 23022c393a42Smrg { 23032c393a42Smrg FcConfigMessage (parse, FcSevereWarning, "missing test expression"); 23042c393a42Smrg return; 23052c393a42Smrg } 2306ca08ab68Smrg if (expr->op == FcOpComma) 2307ca08ab68Smrg { 2308ca08ab68Smrg FcConfigMessage (parse, FcSevereWarning, "Having multiple values in <test> isn't supported and may not work as expected"); 2309ca08ab68Smrg } 2310ca08ab68Smrg test = FcTestCreate (parse, kind, qual, name, FC_OP (compare, flags), expr); 23112c393a42Smrg if (!test) 23122c393a42Smrg { 23132c393a42Smrg FcConfigMessage (parse, FcSevereError, "out of memory"); 23142c393a42Smrg return; 23152c393a42Smrg } 23162c393a42Smrg FcVStackPushTest (parse, test); 23172c393a42Smrg} 23182c393a42Smrg 23192c393a42Smrgstatic const FcOpMap fcModeOps[] = { 23202c393a42Smrg { "assign", FcOpAssign }, 23212c393a42Smrg { "assign_replace", FcOpAssignReplace }, 23222c393a42Smrg { "prepend", FcOpPrepend }, 23232c393a42Smrg { "prepend_first", FcOpPrependFirst }, 23242c393a42Smrg { "append", FcOpAppend }, 23252c393a42Smrg { "append_last", FcOpAppendLast }, 2326c9710b42Smrg { "delete", FcOpDelete }, 2327c9710b42Smrg { "delete_all", FcOpDeleteAll }, 23282c393a42Smrg}; 23292c393a42Smrg 23302c393a42Smrg#define NUM_MODE_OPS (int) (sizeof fcModeOps / sizeof fcModeOps[0]) 23312c393a42Smrg 23322c393a42Smrgstatic FcOp 23332c393a42SmrgFcConfigLexMode (const FcChar8 *mode) 23342c393a42Smrg{ 23352c393a42Smrg return FcConfigLexOp (mode, fcModeOps, NUM_MODE_OPS); 23362c393a42Smrg} 23372c393a42Smrg 23382c393a42Smrgstatic void 23392c393a42SmrgFcParseEdit (FcConfigParse *parse) 23402c393a42Smrg{ 23412c393a42Smrg const FcChar8 *name; 23422c393a42Smrg const FcChar8 *mode_string; 23432c393a42Smrg FcOp mode; 23442c393a42Smrg FcValueBinding binding; 23452c393a42Smrg FcExpr *expr; 23462c393a42Smrg FcEdit *edit; 23472c393a42Smrg 23482c393a42Smrg name = FcConfigGetAttribute (parse, "name"); 23492c393a42Smrg if (!name) 23502c393a42Smrg { 23512c393a42Smrg FcConfigMessage (parse, FcSevereWarning, "missing edit name"); 23522c393a42Smrg return; 23532c393a42Smrg } 23542c393a42Smrg mode_string = FcConfigGetAttribute (parse, "mode"); 23552c393a42Smrg if (!mode_string) 23562c393a42Smrg mode = FcOpAssign; 23572c393a42Smrg else 23582c393a42Smrg { 23592c393a42Smrg mode = FcConfigLexMode (mode_string); 23602c393a42Smrg if (mode == FcOpInvalid) 23612c393a42Smrg { 23622c393a42Smrg FcConfigMessage (parse, FcSevereWarning, "invalid edit mode \"%s\"", mode_string); 23632c393a42Smrg return; 23642c393a42Smrg } 23652c393a42Smrg } 23662c393a42Smrg if (!FcConfigLexBinding (parse, FcConfigGetAttribute (parse, "binding"), &binding)) 23672c393a42Smrg return; 23682c393a42Smrg 23692c393a42Smrg expr = FcPopBinary (parse, FcOpComma); 2370c9710b42Smrg if ((mode == FcOpDelete || mode == FcOpDeleteAll) && 2371c9710b42Smrg expr != NULL) 2372c9710b42Smrg { 2373c9710b42Smrg FcConfigMessage (parse, FcSevereWarning, "Expression doesn't take any effects for delete and delete_all"); 2374c9710b42Smrg FcExprDestroy (expr); 2375c9710b42Smrg expr = NULL; 2376c9710b42Smrg } 23772c393a42Smrg edit = FcEditCreate (parse, FcObjectFromName ((char *) name), 23782c393a42Smrg mode, expr, binding); 23792c393a42Smrg if (!edit) 23802c393a42Smrg { 23812c393a42Smrg FcConfigMessage (parse, FcSevereError, "out of memory"); 23822c393a42Smrg FcExprDestroy (expr); 23832c393a42Smrg return; 23842c393a42Smrg } 23852c393a42Smrg if (!FcVStackPushEdit (parse, edit)) 23862c393a42Smrg FcEditDestroy (edit); 23872c393a42Smrg} 23882c393a42Smrg 2389c9710b42Smrgtypedef struct FcSubstStack { 2390c9710b42Smrg FcTest *test; 2391c9710b42Smrg FcEdit *edit; 2392c9710b42Smrg} FcSubstStack; 2393c9710b42Smrg 23942c393a42Smrgstatic void 23952c393a42SmrgFcParseMatch (FcConfigParse *parse) 23962c393a42Smrg{ 23972c393a42Smrg const FcChar8 *kind_name; 23982c393a42Smrg FcMatchKind kind; 23992c393a42Smrg FcTest *test = 0; 24002c393a42Smrg FcEdit *edit = 0; 24012c393a42Smrg FcVStack *vstack; 2402c9710b42Smrg FcBool tested = FcFalse; 2403c9710b42Smrg FcSubstStack *sstack = NULL; 2404c9710b42Smrg int len, pos = 0; 24052c393a42Smrg 24062c393a42Smrg kind_name = FcConfigGetAttribute (parse, "target"); 24072c393a42Smrg if (!kind_name) 24082c393a42Smrg kind = FcMatchPattern; 24092c393a42Smrg else 24102c393a42Smrg { 24112c393a42Smrg if (!strcmp ((char *) kind_name, "pattern")) 24122c393a42Smrg kind = FcMatchPattern; 24132c393a42Smrg else if (!strcmp ((char *) kind_name, "font")) 24142c393a42Smrg kind = FcMatchFont; 24152c393a42Smrg else if (!strcmp ((char *) kind_name, "scan")) 24162c393a42Smrg kind = FcMatchScan; 24172c393a42Smrg else 24182c393a42Smrg { 24192c393a42Smrg FcConfigMessage (parse, FcSevereWarning, "invalid match target \"%s\"", kind_name); 24202c393a42Smrg return; 24212c393a42Smrg } 24222c393a42Smrg } 2423c9710b42Smrg len = FcVStackElements(parse); 2424c9710b42Smrg if (len > 0) 2425c9710b42Smrg { 2426c9710b42Smrg sstack = malloc (sizeof (FcSubstStack) * (len + 1)); 2427c9710b42Smrg if (!sstack) 2428c9710b42Smrg { 2429c9710b42Smrg FcConfigMessage (parse, FcSevereError, "out of memory"); 2430c9710b42Smrg return; 2431c9710b42Smrg } 2432c9710b42Smrg } 2433a6844aabSmrg while ((vstack = FcVStackPeek (parse))) 24342c393a42Smrg { 2435c9710b42Smrg switch ((int) vstack->tag) { 24362c393a42Smrg case FcVStackTest: 24372c393a42Smrg vstack->u.test->next = test; 24382c393a42Smrg test = vstack->u.test; 24392c393a42Smrg vstack->tag = FcVStackNone; 2440c9710b42Smrg tested = FcTrue; 24412c393a42Smrg break; 24422c393a42Smrg case FcVStackEdit: 2443c9710b42Smrg /* due to the reverse traversal, <edit> node appears faster than 2444c9710b42Smrg * <test> node if any. so we have to deal with it here rather than 2445c9710b42Smrg * the above in FcVStackTest, and put recipes in reverse order. 2446c9710b42Smrg */ 2447c9710b42Smrg if (tested) 2448c9710b42Smrg { 2449c9710b42Smrg sstack[pos].test = test; 2450c9710b42Smrg sstack[pos].edit = edit; 2451c9710b42Smrg pos++; 2452c9710b42Smrg test = NULL; 2453c9710b42Smrg edit = NULL; 2454c9710b42Smrg tested = FcFalse; 2455c9710b42Smrg } 24562c393a42Smrg vstack->u.edit->next = edit; 24572c393a42Smrg edit = vstack->u.edit; 24582c393a42Smrg vstack->tag = FcVStackNone; 24592c393a42Smrg if (kind == FcMatchScan && edit->object > FC_MAX_BASE_OBJECT) 24602c393a42Smrg { 2461ca08ab68Smrg FcConfigMessage (parse, FcSevereError, 24622c393a42Smrg "<match target=\"scan\"> cannot edit user-defined object \"%s\"", 24632c393a42Smrg FcObjectName(edit->object)); 24642c393a42Smrg } 24652c393a42Smrg break; 24662c393a42Smrg default: 24672c393a42Smrg FcConfigMessage (parse, FcSevereWarning, "invalid match element"); 24682c393a42Smrg break; 24692c393a42Smrg } 2470a6844aabSmrg FcVStackPopAndDestroy (parse); 24712c393a42Smrg } 24722c393a42Smrg if (!FcConfigAddEdit (parse->config, test, edit, kind)) 24732c393a42Smrg FcConfigMessage (parse, FcSevereError, "out of memory"); 2474c9710b42Smrg if (sstack) 2475c9710b42Smrg { 2476c9710b42Smrg int i; 2477c9710b42Smrg 2478c9710b42Smrg for (i = 0; i < pos; i++) 2479c9710b42Smrg { 2480c9710b42Smrg if (!FcConfigAddEdit (parse->config, sstack[pos - i - 1].test, sstack[pos - i - 1].edit, kind)) 2481c9710b42Smrg { 2482c9710b42Smrg FcConfigMessage (parse, FcSevereError, "out of memory"); 2483c9710b42Smrg return; 2484c9710b42Smrg } 2485c9710b42Smrg } 2486c9710b42Smrg free (sstack); 2487c9710b42Smrg } 24882c393a42Smrg} 24892c393a42Smrg 24902c393a42Smrgstatic void 24912c393a42SmrgFcParseAcceptRejectFont (FcConfigParse *parse, FcElement element) 24922c393a42Smrg{ 24932c393a42Smrg FcVStack *vstack; 24942c393a42Smrg 2495a6844aabSmrg while ((vstack = FcVStackPeek (parse))) 24962c393a42Smrg { 2497c9710b42Smrg switch ((int) vstack->tag) { 24982c393a42Smrg case FcVStackGlob: 2499ca08ab68Smrg if (!FcConfigGlobAdd (parse->config, 25002c393a42Smrg vstack->u.string, 25012c393a42Smrg element == FcElementAcceptfont)) 25022c393a42Smrg { 25032c393a42Smrg FcConfigMessage (parse, FcSevereError, "out of memory"); 25042c393a42Smrg } 25052c393a42Smrg break; 25062c393a42Smrg case FcVStackPattern: 25072c393a42Smrg if (!FcConfigPatternsAdd (parse->config, 25082c393a42Smrg vstack->u.pattern, 25092c393a42Smrg element == FcElementAcceptfont)) 25102c393a42Smrg { 25112c393a42Smrg FcConfigMessage (parse, FcSevereError, "out of memory"); 25122c393a42Smrg } 25132c393a42Smrg else 25142c393a42Smrg vstack->tag = FcVStackNone; 25152c393a42Smrg break; 25162c393a42Smrg default: 25172c393a42Smrg FcConfigMessage (parse, FcSevereWarning, "bad font selector"); 25182c393a42Smrg break; 25192c393a42Smrg } 2520a6844aabSmrg FcVStackPopAndDestroy (parse); 25212c393a42Smrg } 25222c393a42Smrg} 25232c393a42Smrg 25242c393a42Smrg 25252c393a42Smrgstatic FcValue 25262c393a42SmrgFcPopValue (FcConfigParse *parse) 25272c393a42Smrg{ 2528a6844aabSmrg FcVStack *vstack = FcVStackPeek (parse); 25292c393a42Smrg FcValue value; 2530ca08ab68Smrg 25312c393a42Smrg value.type = FcTypeVoid; 2532ca08ab68Smrg 25332c393a42Smrg if (!vstack) 25342c393a42Smrg return value; 2535ca08ab68Smrg 2536c9710b42Smrg switch ((int) vstack->tag) { 25372c393a42Smrg case FcVStackString: 2538c9710b42Smrg value.u.s = FcStrdup (vstack->u.string); 25392c393a42Smrg if (value.u.s) 25402c393a42Smrg value.type = FcTypeString; 25412c393a42Smrg break; 25422c393a42Smrg case FcVStackConstant: 25432c393a42Smrg if (FcNameConstant (vstack->u.string, &value.u.i)) 25442c393a42Smrg value.type = FcTypeInteger; 25452c393a42Smrg break; 25462c393a42Smrg case FcVStackInteger: 25472c393a42Smrg value.u.i = vstack->u.integer; 25482c393a42Smrg value.type = FcTypeInteger; 25492c393a42Smrg break; 25502c393a42Smrg case FcVStackDouble: 25512c393a42Smrg value.u.d = vstack->u._double; 2552c9710b42Smrg value.type = FcTypeDouble; 25532c393a42Smrg break; 25542c393a42Smrg case FcVStackBool: 2555a6844aabSmrg value.u.b = vstack->u.bool_; 25562c393a42Smrg value.type = FcTypeBool; 25572c393a42Smrg break; 2558ca08ab68Smrg case FcVStackCharSet: 2559ca08ab68Smrg value.u.c = FcCharSetCopy (vstack->u.charset); 2560ca08ab68Smrg if (value.u.c) 2561ca08ab68Smrg value.type = FcTypeCharSet; 2562ca08ab68Smrg break; 2563ca08ab68Smrg case FcVStackLangSet: 2564ca08ab68Smrg value.u.l = FcLangSetCopy (vstack->u.langset); 2565ca08ab68Smrg if (value.u.l) 2566ca08ab68Smrg value.type = FcTypeLangSet; 2567ca08ab68Smrg break; 25682c393a42Smrg default: 2569ca08ab68Smrg FcConfigMessage (parse, FcSevereWarning, "unknown pattern element %d", 25702c393a42Smrg vstack->tag); 25712c393a42Smrg break; 25722c393a42Smrg } 2573a6844aabSmrg FcVStackPopAndDestroy (parse); 2574ca08ab68Smrg 25752c393a42Smrg return value; 25762c393a42Smrg} 25772c393a42Smrg 25782c393a42Smrgstatic void 25792c393a42SmrgFcParsePatelt (FcConfigParse *parse) 25802c393a42Smrg{ 25812c393a42Smrg FcValue value; 25822c393a42Smrg FcPattern *pattern = FcPatternCreate (); 25832c393a42Smrg const char *name; 25842c393a42Smrg 25852c393a42Smrg if (!pattern) 25862c393a42Smrg { 25872c393a42Smrg FcConfigMessage (parse, FcSevereError, "out of memory"); 25882c393a42Smrg return; 25892c393a42Smrg } 25902c393a42Smrg 25912c393a42Smrg name = (char *) FcConfigGetAttribute (parse, "name"); 25922c393a42Smrg if (!name) 25932c393a42Smrg { 25942c393a42Smrg FcConfigMessage (parse, FcSevereWarning, "missing pattern element name"); 25952c393a42Smrg FcPatternDestroy (pattern); 25962c393a42Smrg return; 25972c393a42Smrg } 2598ca08ab68Smrg 25992c393a42Smrg for (;;) 26002c393a42Smrg { 26012c393a42Smrg value = FcPopValue (parse); 26022c393a42Smrg if (value.type == FcTypeVoid) 26032c393a42Smrg break; 26042c393a42Smrg if (!FcPatternAdd (pattern, name, value, FcTrue)) 26052c393a42Smrg { 26062c393a42Smrg FcConfigMessage (parse, FcSevereError, "out of memory"); 2607a6844aabSmrg FcValueDestroy(value); 26082c393a42Smrg break; 26092c393a42Smrg } 2610a6844aabSmrg FcValueDestroy(value); 26112c393a42Smrg } 26122c393a42Smrg 26132c393a42Smrg FcVStackPushPattern (parse, pattern); 26142c393a42Smrg} 26152c393a42Smrg 26162c393a42Smrgstatic void 26172c393a42SmrgFcParsePattern (FcConfigParse *parse) 26182c393a42Smrg{ 26192c393a42Smrg FcVStack *vstack; 26202c393a42Smrg FcPattern *pattern = FcPatternCreate (); 26212c393a42Smrg 26222c393a42Smrg if (!pattern) 26232c393a42Smrg { 26242c393a42Smrg FcConfigMessage (parse, FcSevereError, "out of memory"); 26252c393a42Smrg return; 26262c393a42Smrg } 26272c393a42Smrg 2628a6844aabSmrg while ((vstack = FcVStackPeek (parse))) 26292c393a42Smrg { 2630c9710b42Smrg switch ((int) vstack->tag) { 26312c393a42Smrg case FcVStackPattern: 26322c393a42Smrg if (!FcPatternAppend (pattern, vstack->u.pattern)) 26332c393a42Smrg { 26342c393a42Smrg FcConfigMessage (parse, FcSevereError, "out of memory"); 26352c393a42Smrg FcPatternDestroy (pattern); 26362c393a42Smrg return; 26372c393a42Smrg } 26382c393a42Smrg break; 26392c393a42Smrg default: 26402c393a42Smrg FcConfigMessage (parse, FcSevereWarning, "unknown pattern element"); 26412c393a42Smrg break; 26422c393a42Smrg } 2643a6844aabSmrg FcVStackPopAndDestroy (parse); 26442c393a42Smrg } 26452c393a42Smrg 26462c393a42Smrg FcVStackPushPattern (parse, pattern); 26472c393a42Smrg} 26482c393a42Smrg 26492c393a42Smrgstatic void 2650c9710b42SmrgFcEndElement(void *userData, const XML_Char *name FC_UNUSED) 26512c393a42Smrg{ 26522c393a42Smrg FcConfigParse *parse = userData; 26532c393a42Smrg FcChar8 *data; 2654a6844aabSmrg 26552c393a42Smrg if (!parse->pstack) 26562c393a42Smrg return; 26572c393a42Smrg switch (parse->pstack->element) { 26582c393a42Smrg case FcElementNone: 26592c393a42Smrg break; 26602c393a42Smrg case FcElementFontconfig: 26612c393a42Smrg break; 26622c393a42Smrg case FcElementDir: 2663ca08ab68Smrg FcParseDir (parse); 26642c393a42Smrg break; 26652c393a42Smrg case FcElementCacheDir: 2666ca08ab68Smrg FcParseCacheDir (parse); 26672c393a42Smrg break; 26682c393a42Smrg case FcElementCache: 2669a6844aabSmrg data = FcStrBufDoneStatic (&parse->pstack->str); 26702c393a42Smrg if (!data) 26712c393a42Smrg { 26722c393a42Smrg FcConfigMessage (parse, FcSevereError, "out of memory"); 26732c393a42Smrg break; 26742c393a42Smrg } 26752c393a42Smrg /* discard this data; no longer used */ 2676a6844aabSmrg FcStrBufDestroy (&parse->pstack->str); 26772c393a42Smrg break; 26782c393a42Smrg case FcElementInclude: 26792c393a42Smrg FcParseInclude (parse); 26802c393a42Smrg break; 26812c393a42Smrg case FcElementConfig: 26822c393a42Smrg break; 26832c393a42Smrg case FcElementMatch: 26842c393a42Smrg FcParseMatch (parse); 26852c393a42Smrg break; 26862c393a42Smrg case FcElementAlias: 26872c393a42Smrg FcParseAlias (parse); 26882c393a42Smrg break; 26892c393a42Smrg 26902c393a42Smrg case FcElementBlank: 26912c393a42Smrg FcParseBlank (parse); 26922c393a42Smrg break; 26932c393a42Smrg case FcElementRescan: 26942c393a42Smrg FcParseRescan (parse); 26952c393a42Smrg break; 26962c393a42Smrg 26972c393a42Smrg case FcElementPrefer: 26982c393a42Smrg FcParseFamilies (parse, FcVStackPrefer); 26992c393a42Smrg break; 27002c393a42Smrg case FcElementAccept: 27012c393a42Smrg FcParseFamilies (parse, FcVStackAccept); 27022c393a42Smrg break; 27032c393a42Smrg case FcElementDefault: 27042c393a42Smrg FcParseFamilies (parse, FcVStackDefault); 27052c393a42Smrg break; 27062c393a42Smrg case FcElementFamily: 27072c393a42Smrg FcParseFamily (parse); 27082c393a42Smrg break; 27092c393a42Smrg 27102c393a42Smrg case FcElementTest: 27112c393a42Smrg FcParseTest (parse); 27122c393a42Smrg break; 27132c393a42Smrg case FcElementEdit: 27142c393a42Smrg FcParseEdit (parse); 27152c393a42Smrg break; 27162c393a42Smrg 27172c393a42Smrg case FcElementInt: 27182c393a42Smrg FcParseInt (parse); 27192c393a42Smrg break; 27202c393a42Smrg case FcElementDouble: 27212c393a42Smrg FcParseDouble (parse); 27222c393a42Smrg break; 27232c393a42Smrg case FcElementString: 27242c393a42Smrg FcParseString (parse, FcVStackString); 27252c393a42Smrg break; 27262c393a42Smrg case FcElementMatrix: 27272c393a42Smrg FcParseMatrix (parse); 27282c393a42Smrg break; 2729ca08ab68Smrg case FcElementRange: 2730ca08ab68Smrg FcParseRange (parse); 2731ca08ab68Smrg break; 27322c393a42Smrg case FcElementBool: 27332c393a42Smrg FcParseBool (parse); 27342c393a42Smrg break; 2735ca08ab68Smrg case FcElementCharSet: 2736ca08ab68Smrg FcParseCharSet (parse); 2737ca08ab68Smrg break; 2738ca08ab68Smrg case FcElementLangSet: 2739ca08ab68Smrg FcParseLangSet (parse); 27402c393a42Smrg break; 27412c393a42Smrg case FcElementSelectfont: 27422c393a42Smrg break; 27432c393a42Smrg case FcElementAcceptfont: 27442c393a42Smrg case FcElementRejectfont: 27452c393a42Smrg FcParseAcceptRejectFont (parse, parse->pstack->element); 27462c393a42Smrg break; 27472c393a42Smrg case FcElementGlob: 27482c393a42Smrg FcParseString (parse, FcVStackGlob); 27492c393a42Smrg break; 27502c393a42Smrg case FcElementPattern: 27512c393a42Smrg FcParsePattern (parse); 27522c393a42Smrg break; 27532c393a42Smrg case FcElementPatelt: 27542c393a42Smrg FcParsePatelt (parse); 27552c393a42Smrg break; 27562c393a42Smrg case FcElementName: 2757c9710b42Smrg FcParseName (parse); 27582c393a42Smrg break; 27592c393a42Smrg case FcElementConst: 27602c393a42Smrg FcParseString (parse, FcVStackConstant); 27612c393a42Smrg break; 27622c393a42Smrg case FcElementOr: 27632c393a42Smrg FcParseBinary (parse, FcOpOr); 27642c393a42Smrg break; 27652c393a42Smrg case FcElementAnd: 27662c393a42Smrg FcParseBinary (parse, FcOpAnd); 27672c393a42Smrg break; 27682c393a42Smrg case FcElementEq: 27692c393a42Smrg FcParseBinary (parse, FcOpEqual); 27702c393a42Smrg break; 27712c393a42Smrg case FcElementNotEq: 27722c393a42Smrg FcParseBinary (parse, FcOpNotEqual); 27732c393a42Smrg break; 27742c393a42Smrg case FcElementLess: 27752c393a42Smrg FcParseBinary (parse, FcOpLess); 27762c393a42Smrg break; 27772c393a42Smrg case FcElementLessEq: 27782c393a42Smrg FcParseBinary (parse, FcOpLessEqual); 27792c393a42Smrg break; 27802c393a42Smrg case FcElementMore: 27812c393a42Smrg FcParseBinary (parse, FcOpMore); 27822c393a42Smrg break; 27832c393a42Smrg case FcElementMoreEq: 27842c393a42Smrg FcParseBinary (parse, FcOpMoreEqual); 27852c393a42Smrg break; 27862c393a42Smrg case FcElementContains: 27872c393a42Smrg FcParseBinary (parse, FcOpContains); 27882c393a42Smrg break; 27892c393a42Smrg case FcElementNotContains: 27902c393a42Smrg FcParseBinary (parse, FcOpNotContains); 27912c393a42Smrg break; 27922c393a42Smrg case FcElementPlus: 27932c393a42Smrg FcParseBinary (parse, FcOpPlus); 27942c393a42Smrg break; 27952c393a42Smrg case FcElementMinus: 27962c393a42Smrg FcParseBinary (parse, FcOpMinus); 27972c393a42Smrg break; 27982c393a42Smrg case FcElementTimes: 27992c393a42Smrg FcParseBinary (parse, FcOpTimes); 28002c393a42Smrg break; 28012c393a42Smrg case FcElementDivide: 28022c393a42Smrg FcParseBinary (parse, FcOpDivide); 28032c393a42Smrg break; 28042c393a42Smrg case FcElementNot: 28052c393a42Smrg FcParseUnary (parse, FcOpNot); 28062c393a42Smrg break; 28072c393a42Smrg case FcElementIf: 28082c393a42Smrg FcParseBinary (parse, FcOpQuest); 28092c393a42Smrg break; 28102c393a42Smrg case FcElementFloor: 28112c393a42Smrg FcParseUnary (parse, FcOpFloor); 28122c393a42Smrg break; 28132c393a42Smrg case FcElementCeil: 28142c393a42Smrg FcParseUnary (parse, FcOpCeil); 28152c393a42Smrg break; 28162c393a42Smrg case FcElementRound: 28172c393a42Smrg FcParseUnary (parse, FcOpRound); 28182c393a42Smrg break; 28192c393a42Smrg case FcElementTrunc: 28202c393a42Smrg FcParseUnary (parse, FcOpTrunc); 28212c393a42Smrg break; 28222c393a42Smrg case FcElementUnknown: 28232c393a42Smrg break; 28242c393a42Smrg } 28252c393a42Smrg (void) FcPStackPop (parse); 28262c393a42Smrg} 28272c393a42Smrg 28282c393a42Smrgstatic void 28292c393a42SmrgFcCharacterData (void *userData, const XML_Char *s, int len) 28302c393a42Smrg{ 28312c393a42Smrg FcConfigParse *parse = userData; 2832ca08ab68Smrg 28332c393a42Smrg if (!parse->pstack) 28342c393a42Smrg return; 28352c393a42Smrg if (!FcStrBufData (&parse->pstack->str, (FcChar8 *) s, len)) 28362c393a42Smrg FcConfigMessage (parse, FcSevereError, "out of memory"); 28372c393a42Smrg} 28382c393a42Smrg 28392c393a42Smrgstatic void 28402c393a42SmrgFcStartDoctypeDecl (void *userData, 28412c393a42Smrg const XML_Char *doctypeName, 2842c9710b42Smrg const XML_Char *sysid FC_UNUSED, 2843c9710b42Smrg const XML_Char *pubid FC_UNUSED, 2844c9710b42Smrg int has_internal_subset FC_UNUSED) 28452c393a42Smrg{ 28462c393a42Smrg FcConfigParse *parse = userData; 28472c393a42Smrg 28482c393a42Smrg if (strcmp ((char *) doctypeName, "fontconfig") != 0) 28492c393a42Smrg FcConfigMessage (parse, FcSevereError, "invalid doctype \"%s\"", doctypeName); 28502c393a42Smrg} 28512c393a42Smrg 28522c393a42Smrg#ifdef ENABLE_LIBXML2 28532c393a42Smrg 28542c393a42Smrgstatic void 28552c393a42SmrgFcInternalSubsetDecl (void *userData, 28562c393a42Smrg const XML_Char *doctypeName, 28572c393a42Smrg const XML_Char *sysid, 28582c393a42Smrg const XML_Char *pubid) 28592c393a42Smrg{ 28602c393a42Smrg FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 1); 28612c393a42Smrg} 28622c393a42Smrg 28632c393a42Smrgstatic void 28642c393a42SmrgFcExternalSubsetDecl (void *userData, 28652c393a42Smrg const XML_Char *doctypeName, 28662c393a42Smrg const XML_Char *sysid, 28672c393a42Smrg const XML_Char *pubid) 28682c393a42Smrg{ 28692c393a42Smrg FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 0); 28702c393a42Smrg} 28712c393a42Smrg 28722c393a42Smrg#else /* ENABLE_LIBXML2 */ 28732c393a42Smrg 28742c393a42Smrgstatic void 2875c9710b42SmrgFcEndDoctypeDecl (void *userData FC_UNUSED) 28762c393a42Smrg{ 28772c393a42Smrg} 28782c393a42Smrg 28792c393a42Smrg#endif /* ENABLE_LIBXML2 */ 28802c393a42Smrg 28812c393a42Smrgstatic int 28822c393a42SmrgFcSortCmpStr (const void *a, const void *b) 28832c393a42Smrg{ 28842c393a42Smrg const FcChar8 *as = *((FcChar8 **) a); 28852c393a42Smrg const FcChar8 *bs = *((FcChar8 **) b); 28862c393a42Smrg return FcStrCmp (as, bs); 28872c393a42Smrg} 28882c393a42Smrg 28892c393a42Smrgstatic FcBool 28902c393a42SmrgFcConfigParseAndLoadDir (FcConfig *config, 28912c393a42Smrg const FcChar8 *name, 28922c393a42Smrg const FcChar8 *dir, 28932c393a42Smrg FcBool complain) 28942c393a42Smrg{ 28952c393a42Smrg DIR *d; 28962c393a42Smrg struct dirent *e; 28972c393a42Smrg FcBool ret = FcTrue; 28982c393a42Smrg FcChar8 *file; 28992c393a42Smrg FcChar8 *base; 29002c393a42Smrg FcStrSet *files; 29012c393a42Smrg 29022c393a42Smrg d = opendir ((char *) dir); 29032c393a42Smrg if (!d) 29042c393a42Smrg { 29052c393a42Smrg if (complain) 29062c393a42Smrg FcConfigMessage (0, FcSevereError, "Cannot open config dir \"%s\"", 29072c393a42Smrg name); 29082c393a42Smrg ret = FcFalse; 29092c393a42Smrg goto bail0; 29102c393a42Smrg } 29112c393a42Smrg /* freed below */ 29122c393a42Smrg file = (FcChar8 *) malloc (strlen ((char *) dir) + 1 + FC_MAX_FILE_LEN + 1); 29132c393a42Smrg if (!file) 29142c393a42Smrg { 29152c393a42Smrg ret = FcFalse; 29162c393a42Smrg goto bail1; 29172c393a42Smrg } 2918ca08ab68Smrg 29192c393a42Smrg strcpy ((char *) file, (char *) dir); 29202c393a42Smrg strcat ((char *) file, "/"); 29212c393a42Smrg base = file + strlen ((char *) file); 2922ca08ab68Smrg 29232c393a42Smrg files = FcStrSetCreate (); 29242c393a42Smrg if (!files) 29252c393a42Smrg { 29262c393a42Smrg ret = FcFalse; 29272c393a42Smrg goto bail2; 29282c393a42Smrg } 2929ca08ab68Smrg 29302c393a42Smrg if (FcDebug () & FC_DBG_CONFIG) 29312c393a42Smrg printf ("\tScanning config dir %s\n", dir); 29322c393a42Smrg 29332c393a42Smrg while (ret && (e = readdir (d))) 29342c393a42Smrg { 29352c393a42Smrg int d_len; 29362c393a42Smrg#define TAIL ".conf" 29372c393a42Smrg#define TAIL_LEN 5 29382c393a42Smrg /* 29392c393a42Smrg * Add all files of the form [0-9]*.conf 29402c393a42Smrg */ 29412c393a42Smrg if ('0' <= e->d_name[0] && e->d_name[0] <= '9' && 29422c393a42Smrg (d_len = strlen (e->d_name)) < FC_MAX_FILE_LEN && 29432c393a42Smrg d_len > TAIL_LEN && 29442c393a42Smrg strcmp (e->d_name + d_len - TAIL_LEN, TAIL) == 0) 29452c393a42Smrg { 29462c393a42Smrg strcpy ((char *) base, (char *) e->d_name); 29472c393a42Smrg if (!FcStrSetAdd (files, file)) 29482c393a42Smrg { 29492c393a42Smrg ret = FcFalse; 29502c393a42Smrg goto bail3; 29512c393a42Smrg } 29522c393a42Smrg } 29532c393a42Smrg } 29542c393a42Smrg if (ret) 29552c393a42Smrg { 29562c393a42Smrg int i; 2957ca08ab68Smrg qsort (files->strs, files->num, sizeof (FcChar8 *), 29582c393a42Smrg (int (*)(const void *, const void *)) FcSortCmpStr); 29592c393a42Smrg for (i = 0; ret && i < files->num; i++) 29602c393a42Smrg ret = FcConfigParseAndLoad (config, files->strs[i], complain); 29612c393a42Smrg } 29622c393a42Smrgbail3: 29632c393a42Smrg FcStrSetDestroy (files); 29642c393a42Smrgbail2: 29652c393a42Smrg free (file); 29662c393a42Smrgbail1: 29672c393a42Smrg closedir (d); 29682c393a42Smrgbail0: 29692c393a42Smrg return ret || !complain; 29702c393a42Smrg} 29712c393a42Smrg 2972ca08ab68Smrg#ifdef _WIN32 2973ca08ab68SmrgpfnGetSystemWindowsDirectory pGetSystemWindowsDirectory = NULL; 2974ca08ab68SmrgpfnSHGetFolderPathA pSHGetFolderPathA = NULL; 2975ca08ab68Smrg#endif 2976ca08ab68Smrg 29772c393a42SmrgFcBool 29782c393a42SmrgFcConfigParseAndLoad (FcConfig *config, 29792c393a42Smrg const FcChar8 *name, 29802c393a42Smrg FcBool complain) 29812c393a42Smrg{ 29822c393a42Smrg 29832c393a42Smrg XML_Parser p; 29842c393a42Smrg FcChar8 *filename; 29852c393a42Smrg int fd; 29862c393a42Smrg int len; 29872c393a42Smrg FcConfigParse parse; 29882c393a42Smrg FcBool error = FcTrue; 2989ca08ab68Smrg 29902c393a42Smrg#ifdef ENABLE_LIBXML2 29912c393a42Smrg xmlSAXHandler sax; 29922c393a42Smrg char buf[BUFSIZ]; 29932c393a42Smrg#else 29942c393a42Smrg void *buf; 29952c393a42Smrg#endif 2996ca08ab68Smrg 2997ca08ab68Smrg#ifdef _WIN32 2998ca08ab68Smrg if (!pGetSystemWindowsDirectory) 2999ca08ab68Smrg { 3000ca08ab68Smrg HMODULE hk32 = GetModuleHandleA("kernel32.dll"); 3001ca08ab68Smrg if (!(pGetSystemWindowsDirectory = (pfnGetSystemWindowsDirectory) GetProcAddress(hk32, "GetSystemWindowsDirectoryA"))) 3002ca08ab68Smrg pGetSystemWindowsDirectory = (pfnGetSystemWindowsDirectory) GetWindowsDirectory; 3003ca08ab68Smrg } 3004ca08ab68Smrg if (!pSHGetFolderPathA) 3005ca08ab68Smrg { 3006ca08ab68Smrg HMODULE hSh = LoadLibraryA("shfolder.dll"); 3007ca08ab68Smrg /* the check is done later, because there is no provided fallback */ 3008ca08ab68Smrg if (hSh) 3009ca08ab68Smrg pSHGetFolderPathA = (pfnSHGetFolderPathA) GetProcAddress(hSh, "SHGetFolderPathA"); 3010ca08ab68Smrg } 3011ca08ab68Smrg#endif 3012ca08ab68Smrg 30132c393a42Smrg filename = FcConfigFilename (name); 30142c393a42Smrg if (!filename) 30152c393a42Smrg goto bail0; 3016ca08ab68Smrg 30172c393a42Smrg if (FcStrSetMember (config->configFiles, filename)) 30182c393a42Smrg { 30192c393a42Smrg FcStrFree (filename); 30202c393a42Smrg return FcTrue; 30212c393a42Smrg } 30222c393a42Smrg 30232c393a42Smrg if (!FcStrSetAdd (config->configFiles, filename)) 30242c393a42Smrg { 30252c393a42Smrg FcStrFree (filename); 30262c393a42Smrg goto bail0; 30272c393a42Smrg } 30282c393a42Smrg 30292c393a42Smrg if (FcFileIsDir (filename)) 30302c393a42Smrg { 30312c393a42Smrg FcBool ret = FcConfigParseAndLoadDir (config, name, filename, complain); 30322c393a42Smrg FcStrFree (filename); 30332c393a42Smrg return ret; 30342c393a42Smrg } 30352c393a42Smrg 30362c393a42Smrg if (FcDebug () & FC_DBG_CONFIG) 30372c393a42Smrg printf ("\tLoading config file %s\n", filename); 30382c393a42Smrg 3039c9710b42Smrg fd = FcOpen ((char *) filename, O_RDONLY); 3040ca08ab68Smrg if (fd == -1) { 30412c393a42Smrg FcStrFree (filename); 30422c393a42Smrg goto bail0; 30432c393a42Smrg } 3044ca08ab68Smrg 30452c393a42Smrg#ifdef ENABLE_LIBXML2 30462c393a42Smrg memset(&sax, 0, sizeof(sax)); 30472c393a42Smrg 30482c393a42Smrg sax.internalSubset = FcInternalSubsetDecl; 30492c393a42Smrg sax.externalSubset = FcExternalSubsetDecl; 30502c393a42Smrg sax.startElement = FcStartElement; 30512c393a42Smrg sax.endElement = FcEndElement; 30522c393a42Smrg sax.characters = FcCharacterData; 30532c393a42Smrg 30542c393a42Smrg p = xmlCreatePushParserCtxt (&sax, &parse, NULL, 0, (const char *) filename); 30552c393a42Smrg#else 30562c393a42Smrg p = XML_ParserCreate ("UTF-8"); 30572c393a42Smrg#endif 30582c393a42Smrg FcStrFree (filename); 30592c393a42Smrg 30602c393a42Smrg if (!p) 30612c393a42Smrg goto bail1; 30622c393a42Smrg 3063c9710b42Smrg if (!FcConfigParseInit (&parse, name, config, p)) 30642c393a42Smrg goto bail2; 30652c393a42Smrg 30662c393a42Smrg#ifndef ENABLE_LIBXML2 30672c393a42Smrg 30682c393a42Smrg XML_SetUserData (p, &parse); 3069ca08ab68Smrg 30702c393a42Smrg XML_SetDoctypeDeclHandler (p, FcStartDoctypeDecl, FcEndDoctypeDecl); 30712c393a42Smrg XML_SetElementHandler (p, FcStartElement, FcEndElement); 30722c393a42Smrg XML_SetCharacterDataHandler (p, FcCharacterData); 30732c393a42Smrg 30742c393a42Smrg#endif /* ENABLE_LIBXML2 */ 30752c393a42Smrg 30762c393a42Smrg do { 30772c393a42Smrg#ifndef ENABLE_LIBXML2 30782c393a42Smrg buf = XML_GetBuffer (p, BUFSIZ); 30792c393a42Smrg if (!buf) 30802c393a42Smrg { 30812c393a42Smrg FcConfigMessage (&parse, FcSevereError, "cannot get parse buffer"); 30822c393a42Smrg goto bail3; 30832c393a42Smrg } 30842c393a42Smrg#endif 30852c393a42Smrg len = read (fd, buf, BUFSIZ); 30862c393a42Smrg if (len < 0) 30872c393a42Smrg { 30882c393a42Smrg FcConfigMessage (&parse, FcSevereError, "failed reading config file"); 30892c393a42Smrg goto bail3; 30902c393a42Smrg } 30912c393a42Smrg 30922c393a42Smrg#ifdef ENABLE_LIBXML2 30932c393a42Smrg if (xmlParseChunk (p, buf, len, len == 0)) 30942c393a42Smrg#else 30952c393a42Smrg if (!XML_ParseBuffer (p, len, len == 0)) 30962c393a42Smrg#endif 30972c393a42Smrg { 3098ca08ab68Smrg FcConfigMessage (&parse, FcSevereError, "%s", 30992c393a42Smrg XML_ErrorString (XML_GetErrorCode (p))); 31002c393a42Smrg goto bail3; 31012c393a42Smrg } 31022c393a42Smrg } while (len != 0); 31032c393a42Smrg error = parse.error; 31042c393a42Smrgbail3: 31052c393a42Smrg FcConfigCleanup (&parse); 31062c393a42Smrgbail2: 31072c393a42Smrg XML_ParserFree (p); 31082c393a42Smrgbail1: 31092c393a42Smrg close (fd); 31102c393a42Smrg fd = -1; 31112c393a42Smrgbail0: 31122c393a42Smrg if (error && complain) 31132c393a42Smrg { 31142c393a42Smrg if (name) 31152c393a42Smrg FcConfigMessage (0, FcSevereError, "Cannot load config file \"%s\"", name); 31162c393a42Smrg else 31172c393a42Smrg FcConfigMessage (0, FcSevereError, "Cannot load default config file"); 31182c393a42Smrg return FcFalse; 31192c393a42Smrg } 31202c393a42Smrg return FcTrue; 31212c393a42Smrg} 31222c393a42Smrg#define __fcxml__ 31232c393a42Smrg#include "fcaliastail.h" 31242c393a42Smrg#undef __fcxml__ 3125