From dafebc5bb70303f0b5baf0b087cf4d9a64b5c7f0 Mon Sep 17 00:00:00 2001 From: marha Date: Mon, 12 Sep 2011 11:27:51 +0200 Subject: Synchronised line endinge with release branch --- fontconfig/src/fcxml.c | 5614 ++++++++++++++++++++++++------------------------ 1 file changed, 2807 insertions(+), 2807 deletions(-) (limited to 'fontconfig/src/fcxml.c') diff --git a/fontconfig/src/fcxml.c b/fontconfig/src/fcxml.c index 5c4e9bf24..e0bb72874 100644 --- a/fontconfig/src/fcxml.c +++ b/fontconfig/src/fcxml.c @@ -1,2807 +1,2807 @@ -/* - * fontconfig/src/fcxml.c - * - * Copyright © 2002 Keith Packard - * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that - * copyright notice and this permission notice appear in supporting - * documentation, and that the name of the author(s) not be used in - * advertising or publicity pertaining to distribution of the software without - * specific, written prior permission. The authors make no - * representations about the suitability of this software for any purpose. It - * is provided "as is" without express or implied warranty. - * - * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THIS SOFTWARE. - */ - -#include "fcint.h" -#include -#include -#include - -#ifdef ENABLE_LIBXML2 - -#include - -#define XML_Char xmlChar -#define XML_Parser xmlParserCtxtPtr -#define XML_ParserFree xmlFreeParserCtxt -#define XML_GetCurrentLineNumber xmlSAX2GetLineNumber -#define XML_GetErrorCode xmlCtxtGetLastError -#define XML_ErrorString(Error) (Error)->message - -#else /* ENABLE_LIBXML2 */ - -#ifndef HAVE_XMLPARSE_H -#define HAVE_XMLPARSE_H 0 -#endif - -#if HAVE_XMLPARSE_H -#include -#else -#include -#endif - -#endif /* ENABLE_LIBXML2 */ - -#ifdef _WIN32 -#include -#endif - -static void -FcExprDestroy (FcExpr *e); - -void -FcTestDestroy (FcTest *test) -{ - if (test->next) - FcTestDestroy (test->next); - FcExprDestroy (test->expr); - FcMemFree (FC_MEM_TEST, sizeof (FcTest)); - free (test); -} - -static FcExpr * -FcExprCreateInteger (FcConfig *config, int i) -{ - FcExpr *e = FcConfigAllocExpr (config); - if (e) - { - e->op = FcOpInteger; - e->u.ival = i; - } - return e; -} - -static FcExpr * -FcExprCreateDouble (FcConfig *config, double d) -{ - FcExpr *e = FcConfigAllocExpr (config); - if (e) - { - e->op = FcOpDouble; - e->u.dval = d; - } - return e; -} - -static FcExpr * -FcExprCreateString (FcConfig *config, const FcChar8 *s) -{ - FcExpr *e = FcConfigAllocExpr (config); - if (e) - { - e->op = FcOpString; - e->u.sval = FcStrStaticName (s); - } - return e; -} - -static FcExpr * -FcExprCreateMatrix (FcConfig *config, const FcMatrix *m) -{ - FcExpr *e = FcConfigAllocExpr (config); - if (e) - { - e->op = FcOpMatrix; - e->u.mval = FcMatrixCopy (m); - } - return e; -} - -static FcExpr * -FcExprCreateBool (FcConfig *config, FcBool b) -{ - FcExpr *e = FcConfigAllocExpr (config); - if (e) - { - e->op = FcOpBool; - e->u.bval = b; - } - return e; -} - -static FcExpr * -FcExprCreateCharSet (FcConfig *config, FcCharSet *charset) -{ - FcExpr *e = FcConfigAllocExpr (config); - if (e) - { - e->op = FcOpCharSet; - e->u.cval = FcCharSetCopy (charset); - } - return e; -} - -static FcExpr * -FcExprCreateLangSet (FcConfig *config, FcLangSet *langset) -{ - FcExpr *e = FcConfigAllocExpr (config); - if (e) - { - e->op = FcOpLangSet; - e->u.lval = FcLangSetCopy (langset); - } - return e; -} - -static FcExpr * -FcExprCreateField (FcConfig *config, const char *field) -{ - FcExpr *e = FcConfigAllocExpr (config); - if (e) - { - e->op = FcOpField; - e->u.object = FcObjectFromName (field); - } - return e; -} - -static FcExpr * -FcExprCreateConst (FcConfig *config, const FcChar8 *constant) -{ - FcExpr *e = FcConfigAllocExpr (config); - if (e) - { - e->op = FcOpConst; - e->u.constant = FcStrStaticName (constant); - } - return e; -} - -static FcExpr * -FcExprCreateOp (FcConfig *config, FcExpr *left, FcOp op, FcExpr *right) -{ - FcExpr *e = FcConfigAllocExpr (config); - if (e) - { - e->op = op; - e->u.tree.left = left; - e->u.tree.right = right; - } - return e; -} - -static void -FcExprDestroy (FcExpr *e) -{ - if (!e) - return; - switch (e->op) { - case FcOpInteger: - break; - case FcOpDouble: - break; - case FcOpString: - break; - case FcOpMatrix: - FcMatrixFree (e->u.mval); - break; - case FcOpRange: - break; - case FcOpCharSet: - FcCharSetDestroy (e->u.cval); - break; - case FcOpLangSet: - FcLangSetDestroy (e->u.lval); - break; - case FcOpBool: - break; - case FcOpField: - break; - case FcOpConst: - break; - case FcOpAssign: - case FcOpAssignReplace: - case FcOpPrepend: - case FcOpPrependFirst: - case FcOpAppend: - case FcOpAppendLast: - break; - case FcOpOr: - case FcOpAnd: - case FcOpEqual: - case FcOpNotEqual: - case FcOpLess: - case FcOpLessEqual: - case FcOpMore: - case FcOpMoreEqual: - case FcOpContains: - case FcOpListing: - case FcOpNotContains: - case FcOpPlus: - case FcOpMinus: - case FcOpTimes: - case FcOpDivide: - case FcOpQuest: - case FcOpComma: - FcExprDestroy (e->u.tree.right); - /* fall through */ - case FcOpNot: - case FcOpFloor: - case FcOpCeil: - case FcOpRound: - case FcOpTrunc: - FcExprDestroy (e->u.tree.left); - break; - case FcOpNil: - case FcOpInvalid: - break; - } - - e->op = FcOpNil; -} - -void -FcEditDestroy (FcEdit *e) -{ - if (e->next) - FcEditDestroy (e->next); - if (e->expr) - FcExprDestroy (e->expr); - free (e); -} - -typedef enum _FcElement { - FcElementNone, - FcElementFontconfig, - FcElementDir, - FcElementCacheDir, - FcElementCache, - FcElementInclude, - FcElementConfig, - FcElementMatch, - FcElementAlias, - - FcElementBlank, - FcElementRescan, - - FcElementPrefer, - FcElementAccept, - FcElementDefault, - FcElementFamily, - - FcElementSelectfont, - FcElementAcceptfont, - FcElementRejectfont, - FcElementGlob, - FcElementPattern, - FcElementPatelt, - - FcElementTest, - FcElementEdit, - FcElementInt, - FcElementDouble, - FcElementString, - FcElementMatrix, - FcElementRange, - FcElementBool, - FcElementCharSet, - FcElementLangSet, - FcElementName, - FcElementConst, - FcElementOr, - FcElementAnd, - FcElementEq, - FcElementNotEq, - FcElementLess, - FcElementLessEq, - FcElementMore, - FcElementMoreEq, - FcElementContains, - FcElementNotContains, - FcElementPlus, - FcElementMinus, - FcElementTimes, - FcElementDivide, - FcElementNot, - FcElementIf, - FcElementFloor, - FcElementCeil, - FcElementRound, - FcElementTrunc, - FcElementUnknown -} FcElement; - -static const struct { - const char name[16]; - FcElement element; -} fcElementMap[] = { - { "fontconfig", FcElementFontconfig }, - { "dir", FcElementDir }, - { "cachedir", FcElementCacheDir }, - { "cache", FcElementCache }, - { "include", FcElementInclude }, - { "config", FcElementConfig }, - { "match", FcElementMatch }, - { "alias", FcElementAlias }, - - { "blank", FcElementBlank }, - { "rescan", FcElementRescan }, - - { "prefer", FcElementPrefer }, - { "accept", FcElementAccept }, - { "default", FcElementDefault }, - { "family", FcElementFamily }, - - { "selectfont", FcElementSelectfont }, - { "acceptfont", FcElementAcceptfont }, - { "rejectfont", FcElementRejectfont }, - { "glob", FcElementGlob }, - { "pattern", FcElementPattern }, - { "patelt", FcElementPatelt }, - - { "test", FcElementTest }, - { "edit", FcElementEdit }, - { "int", FcElementInt }, - { "double", FcElementDouble }, - { "string", FcElementString }, - { "matrix", FcElementMatrix }, - { "range", FcElementRange }, - { "bool", FcElementBool }, - { "charset", FcElementCharSet }, - { "langset", FcElementLangSet }, - { "name", FcElementName }, - { "const", FcElementConst }, - { "or", FcElementOr }, - { "and", FcElementAnd }, - { "eq", FcElementEq }, - { "not_eq", FcElementNotEq }, - { "less", FcElementLess }, - { "less_eq", FcElementLessEq }, - { "more", FcElementMore }, - { "more_eq", FcElementMoreEq }, - { "contains", FcElementContains }, - { "not_contains", FcElementNotContains }, - { "plus", FcElementPlus }, - { "minus", FcElementMinus }, - { "times", FcElementTimes }, - { "divide", FcElementDivide }, - { "not", FcElementNot }, - { "if", FcElementIf }, - { "floor", FcElementFloor }, - { "ceil", FcElementCeil }, - { "round", FcElementRound }, - { "trunc", FcElementTrunc }, -}; -#define NUM_ELEMENT_MAPS (int) (sizeof fcElementMap / sizeof fcElementMap[0]) - -static FcElement -FcElementMap (const XML_Char *name) -{ - - int i; - for (i = 0; i < NUM_ELEMENT_MAPS; i++) - if (!strcmp ((char *) name, fcElementMap[i].name)) - return fcElementMap[i].element; - return FcElementUnknown; -} - -typedef struct _FcPStack { - struct _FcPStack *prev; - FcElement element; - FcChar8 **attr; - FcStrBuf str; - FcChar8 *attr_buf_static[16]; -} FcPStack; - -typedef enum _FcVStackTag { - FcVStackNone, - - FcVStackString, - FcVStackFamily, - FcVStackField, - FcVStackConstant, - FcVStackGlob, - FcVStackPattern, - - FcVStackPrefer, - FcVStackAccept, - FcVStackDefault, - - FcVStackInteger, - FcVStackDouble, - FcVStackMatrix, - FcVStackRange, - FcVStackBool, - FcVStackCharSet, - FcVStackLangSet, - - FcVStackTest, - FcVStackExpr, - FcVStackEdit -} FcVStackTag; - -typedef struct _FcVStack { - struct _FcVStack *prev; - FcPStack *pstack; /* related parse element */ - FcVStackTag tag; - union { - FcChar8 *string; - - int integer; - double _double; - FcMatrix *matrix; - FcRange range; - FcBool bool_; - FcCharSet *charset; - FcLangSet *langset; - - FcTest *test; - FcQual qual; - FcOp op; - FcExpr *expr; - FcEdit *edit; - - FcPattern *pattern; - } u; -} FcVStack; - -typedef struct _FcConfigParse { - FcPStack *pstack; - FcVStack *vstack; - FcBool error; - const FcChar8 *name; - FcConfig *config; - XML_Parser parser; - int pstack_static_used; - FcPStack pstack_static[8]; - int vstack_static_used; - FcVStack vstack_static[64]; -} FcConfigParse; - -typedef enum _FcConfigSeverity { - FcSevereInfo, FcSevereWarning, FcSevereError -} FcConfigSeverity; - -static void -FcConfigMessage (FcConfigParse *parse, FcConfigSeverity severe, const char *fmt, ...) -{ - const char *s = "unknown"; - va_list args; - - va_start (args, fmt); - - switch (severe) { - case FcSevereInfo: s = "info"; break; - case FcSevereWarning: s = "warning"; break; - case FcSevereError: s = "error"; break; - } - if (parse) - { - if (parse->name) - fprintf (stderr, "Fontconfig %s: \"%s\", line %d: ", s, - parse->name, (int)XML_GetCurrentLineNumber (parse->parser)); - else - fprintf (stderr, "Fontconfig %s: line %d: ", s, - (int)XML_GetCurrentLineNumber (parse->parser)); - if (severe >= FcSevereError) - parse->error = FcTrue; - } - else - fprintf (stderr, "Fontconfig %s: ", s); - vfprintf (stderr, fmt, args); - fprintf (stderr, "\n"); - va_end (args); -} - - -static const char * -FcTypeName (FcType type) -{ - switch (type) { - case FcTypeVoid: - return "void"; - case FcTypeInteger: - case FcTypeDouble: - return "number"; - case FcTypeString: - return "string"; - case FcTypeBool: - return "bool"; - case FcTypeMatrix: - return "matrix"; - case FcTypeCharSet: - return "charset"; - case FcTypeFTFace: - return "FT_Face"; - case FcTypeLangSet: - return "langset"; - default: - return "unknown"; - } -} - -static void -FcTypecheckValue (FcConfigParse *parse, FcType value, FcType type) -{ - if (value == FcTypeInteger) - value = FcTypeDouble; - if (type == FcTypeInteger) - type = FcTypeDouble; - if (value != type) - { - if ((value == FcTypeLangSet && type == FcTypeString) || - (value == FcTypeString && type == FcTypeLangSet)) - return; - if (type == (FcType) -1) - return; - FcConfigMessage (parse, FcSevereWarning, "saw %s, expected %s", - FcTypeName (value), FcTypeName (type)); - } -} - -static void -FcTypecheckExpr (FcConfigParse *parse, FcExpr *expr, FcType type) -{ - const FcObjectType *o; - const FcConstant *c; - - /* If parsing the expression failed, some nodes may be NULL */ - if (!expr) - return; - - switch (expr->op) { - case FcOpInteger: - case FcOpDouble: - FcTypecheckValue (parse, FcTypeDouble, type); - break; - case FcOpString: - FcTypecheckValue (parse, FcTypeString, type); - break; - case FcOpMatrix: - FcTypecheckValue (parse, FcTypeMatrix, type); - break; - case FcOpBool: - FcTypecheckValue (parse, FcTypeBool, type); - break; - case FcOpCharSet: - FcTypecheckValue (parse, FcTypeCharSet, type); - break; - case FcOpLangSet: - FcTypecheckValue (parse, FcTypeLangSet, type); - break; - case FcOpNil: - break; - case FcOpField: - o = FcNameGetObjectType (FcObjectName (expr->u.object)); - if (o) - FcTypecheckValue (parse, o->type, type); - break; - case FcOpConst: - c = FcNameGetConstant (expr->u.constant); - if (c) - { - o = FcNameGetObjectType (c->object); - if (o) - FcTypecheckValue (parse, o->type, type); - } - else - FcConfigMessage (parse, FcSevereWarning, - "invalid constant used : %s", - expr->u.constant); - break; - case FcOpQuest: - FcTypecheckExpr (parse, expr->u.tree.left, FcTypeBool); - FcTypecheckExpr (parse, expr->u.tree.right->u.tree.left, type); - FcTypecheckExpr (parse, expr->u.tree.right->u.tree.right, type); - break; - case FcOpAssign: - case FcOpAssignReplace: - break; - case FcOpEqual: - case FcOpNotEqual: - case FcOpLess: - case FcOpLessEqual: - case FcOpMore: - case FcOpMoreEqual: - case FcOpContains: - case FcOpNotContains: - case FcOpListing: - FcTypecheckValue (parse, FcTypeBool, type); - break; - case FcOpComma: - case FcOpOr: - case FcOpAnd: - case FcOpPlus: - case FcOpMinus: - case FcOpTimes: - case FcOpDivide: - FcTypecheckExpr (parse, expr->u.tree.left, type); - FcTypecheckExpr (parse, expr->u.tree.right, type); - break; - case FcOpNot: - FcTypecheckValue (parse, FcTypeBool, type); - FcTypecheckExpr (parse, expr->u.tree.left, FcTypeBool); - break; - case FcOpFloor: - case FcOpCeil: - case FcOpRound: - case FcOpTrunc: - FcTypecheckValue (parse, FcTypeDouble, type); - FcTypecheckExpr (parse, expr->u.tree.left, FcTypeDouble); - break; - default: - break; - } -} - -static FcTest * -FcTestCreate (FcConfigParse *parse, - FcMatchKind kind, - FcQual qual, - const FcChar8 *field, - FcOp compare, - FcExpr *expr) -{ - FcTest *test = (FcTest *) malloc (sizeof (FcTest)); - - if (test) - { - const FcObjectType *o; - - FcMemAlloc (FC_MEM_TEST, sizeof (FcTest)); - test->next = 0; - test->kind = kind; - test->qual = qual; - test->object = FcObjectFromName ((const char *) field); - test->op = compare; - test->expr = expr; - o = FcNameGetObjectType (FcObjectName (test->object)); - if (o) - FcTypecheckExpr (parse, expr, o->type); - } - return test; -} - -static FcEdit * -FcEditCreate (FcConfigParse *parse, - FcObject object, - FcOp op, - FcExpr *expr, - FcValueBinding binding) -{ - FcEdit *e = (FcEdit *) malloc (sizeof (FcEdit)); - - if (e) - { - const FcObjectType *o; - - e->next = 0; - e->object = object; - e->op = op; - e->expr = expr; - e->binding = binding; - o = FcNameGetObjectType (FcObjectName (e->object)); - if (o) - FcTypecheckExpr (parse, expr, o->type); - } - return e; -} - -static FcVStack * -FcVStackCreateAndPush (FcConfigParse *parse) -{ - FcVStack *new; - - if (parse->vstack_static_used < sizeof (parse->vstack_static) / sizeof (parse->vstack_static[0])) - new = &parse->vstack_static[parse->vstack_static_used++]; - else - { - new = malloc (sizeof (FcVStack)); - if (!new) - return 0; - FcMemAlloc (FC_MEM_VSTACK, sizeof (FcVStack)); - } - new->tag = FcVStackNone; - new->prev = 0; - - new->prev = parse->vstack; - new->pstack = parse->pstack ? parse->pstack->prev : 0; - parse->vstack = new; - - return new; -} - -static FcBool -FcVStackPushString (FcConfigParse *parse, FcVStackTag tag, FcChar8 *string) -{ - FcVStack *vstack = FcVStackCreateAndPush (parse); - if (!vstack) - return FcFalse; - vstack->u.string = string; - vstack->tag = tag; - return FcTrue; -} - -static FcBool -FcVStackPushInteger (FcConfigParse *parse, int integer) -{ - FcVStack *vstack = FcVStackCreateAndPush (parse); - if (!vstack) - return FcFalse; - vstack->u.integer = integer; - vstack->tag = FcVStackInteger; - return FcTrue; -} - -static FcBool -FcVStackPushDouble (FcConfigParse *parse, double _double) -{ - FcVStack *vstack = FcVStackCreateAndPush (parse); - if (!vstack) - return FcFalse; - vstack->u._double = _double; - vstack->tag = FcVStackDouble; - return FcTrue; -} - -static FcBool -FcVStackPushMatrix (FcConfigParse *parse, FcMatrix *matrix) -{ - FcVStack *vstack; - matrix = FcMatrixCopy (matrix); - if (!matrix) - return FcFalse; - vstack = FcVStackCreateAndPush (parse); - if (!vstack) - return FcFalse; - vstack->u.matrix = matrix; - vstack->tag = FcVStackMatrix; - return FcTrue; -} - -static FcBool -FcVStackPushRange (FcConfigParse *parse, FcRange *range) -{ - FcVStack *vstack = FcVStackCreateAndPush (parse); - if (!vstack) - return FcFalse; - vstack->u.range.begin = range->begin; - vstack->u.range.end = range->end; - vstack->tag = FcVStackRange; - return FcTrue; -} - -static FcBool -FcVStackPushBool (FcConfigParse *parse, FcBool bool_) -{ - FcVStack *vstack = FcVStackCreateAndPush (parse); - if (!vstack) - return FcFalse; - vstack->u.bool_ = bool_; - vstack->tag = FcVStackBool; - return FcTrue; -} - -static FcBool -FcVStackPushCharSet (FcConfigParse *parse, FcCharSet *charset) -{ - FcVStack *vstack; - if (!charset) - return FcFalse; - vstack = FcVStackCreateAndPush (parse); - if (!vstack) - return FcFalse; - vstack->u.charset = charset; - vstack->tag = FcVStackCharSet; - return FcTrue; -} - -static FcBool -FcVStackPushLangSet (FcConfigParse *parse, FcLangSet *langset) -{ - FcVStack *vstack; - if (!langset) - return FcFalse; - vstack = FcVStackCreateAndPush (parse); - if (!vstack) - return FcFalse; - vstack->u.langset = langset; - vstack->tag = FcVStackLangSet; - return FcTrue; -} - -static FcBool -FcVStackPushTest (FcConfigParse *parse, FcTest *test) -{ - FcVStack *vstack = FcVStackCreateAndPush (parse); - if (!vstack) - return FcFalse; - vstack->u.test = test; - vstack->tag = FcVStackTest; - return FcTrue; -} - -static FcBool -FcVStackPushExpr (FcConfigParse *parse, FcVStackTag tag, FcExpr *expr) -{ - FcVStack *vstack = FcVStackCreateAndPush (parse); - if (!vstack) - return FcFalse; - vstack->u.expr = expr; - vstack->tag = tag; - return FcTrue; -} - -static FcBool -FcVStackPushEdit (FcConfigParse *parse, FcEdit *edit) -{ - FcVStack *vstack = FcVStackCreateAndPush (parse); - if (!vstack) - return FcFalse; - vstack->u.edit = edit; - vstack->tag = FcVStackEdit; - return FcTrue; -} - -static FcBool -FcVStackPushPattern (FcConfigParse *parse, FcPattern *pattern) -{ - FcVStack *vstack = FcVStackCreateAndPush (parse); - if (!vstack) - return FcFalse; - vstack->u.pattern = pattern; - vstack->tag = FcVStackPattern; - return FcTrue; -} - -static FcVStack * -FcVStackFetch (FcConfigParse *parse, int off) -{ - FcVStack *vstack; - - for (vstack = parse->vstack; vstack && off-- > 0; vstack = vstack->prev); - return vstack; -} - -static FcVStack * -FcVStackPeek (FcConfigParse *parse) -{ - FcVStack *vstack = parse->vstack; - - return vstack && vstack->pstack == parse->pstack ? vstack : 0; -} - -static void -FcVStackPopAndDestroy (FcConfigParse *parse) -{ - FcVStack *vstack = parse->vstack; - - if (!vstack || vstack->pstack != parse->pstack) - return; - - parse->vstack = vstack->prev; - - switch (vstack->tag) { - case FcVStackNone: - break; - case FcVStackFamily: - break; - case FcVStackString: - case FcVStackField: - case FcVStackConstant: - case FcVStackGlob: - FcStrFree (vstack->u.string); - break; - case FcVStackPattern: - FcPatternDestroy (vstack->u.pattern); - break; - case FcVStackInteger: - case FcVStackDouble: - break; - case FcVStackMatrix: - FcMatrixFree (vstack->u.matrix); - break; - case FcVStackRange: - case FcVStackBool: - break; - case FcVStackCharSet: - FcCharSetDestroy (vstack->u.charset); - break; - case FcVStackLangSet: - FcLangSetDestroy (vstack->u.langset); - break; - case FcVStackTest: - FcTestDestroy (vstack->u.test); - break; - case FcVStackExpr: - case FcVStackPrefer: - case FcVStackAccept: - case FcVStackDefault: - FcExprDestroy (vstack->u.expr); - break; - case FcVStackEdit: - FcEditDestroy (vstack->u.edit); - break; - } - - if (vstack == &parse->vstack_static[parse->vstack_static_used - 1]) - parse->vstack_static_used--; - else - { - FcMemFree (FC_MEM_VSTACK, sizeof (FcVStack)); - free (vstack); - } -} - -static void -FcVStackClear (FcConfigParse *parse) -{ - while (FcVStackPeek (parse)) - FcVStackPopAndDestroy (parse); -} - -static int -FcVStackElements (FcConfigParse *parse) -{ - int h = 0; - FcVStack *vstack = parse->vstack; - while (vstack && vstack->pstack == parse->pstack) - { - h++; - vstack = vstack->prev; - } - return h; -} - -static FcChar8 ** -FcConfigSaveAttr (const XML_Char **attr, FcChar8 **buf, int size_bytes) -{ - int slen; - int i; - FcChar8 **new; - FcChar8 *s; - - if (!attr) - return 0; - slen = 0; - for (i = 0; attr[i]; i++) - slen += strlen ((char *) attr[i]) + 1; - if (i == 0) - return 0; - slen += (i + 1) * sizeof (FcChar8 *); - if (slen <= size_bytes) - new = buf; - else - { - new = malloc (slen); - if (!new) - { - FcConfigMessage (0, FcSevereError, "out of memory"); - return 0; - } - FcMemAlloc (FC_MEM_ATTR, 1); /* size is too expensive */ - } - s = (FcChar8 *) (new + (i + 1)); - for (i = 0; attr[i]; i++) - { - new[i] = s; - strcpy ((char *) s, (char *) attr[i]); - s += strlen ((char *) s) + 1; - } - new[i] = 0; - return new; -} - -static FcBool -FcPStackPush (FcConfigParse *parse, FcElement element, const XML_Char **attr) -{ - FcPStack *new; - - if (parse->pstack_static_used < sizeof (parse->pstack_static) / sizeof (parse->pstack_static[0])) - new = &parse->pstack_static[parse->pstack_static_used++]; - else - { - new = malloc (sizeof (FcPStack)); - if (!new) - return FcFalse; - FcMemAlloc (FC_MEM_PSTACK, sizeof (FcPStack)); - } - - new->prev = parse->pstack; - new->element = element; - new->attr = FcConfigSaveAttr (attr, new->attr_buf_static, sizeof (new->attr_buf_static)); - FcStrBufInit (&new->str, 0, 0); - parse->pstack = new; - return FcTrue; -} - -static FcBool -FcPStackPop (FcConfigParse *parse) -{ - FcPStack *old; - - if (!parse->pstack) - { - FcConfigMessage (parse, FcSevereError, "mismatching element"); - return FcFalse; - } - FcVStackClear (parse); - old = parse->pstack; - parse->pstack = old->prev; - FcStrBufDestroy (&old->str); - if (old->attr && old->attr != old->attr_buf_static) - { - FcMemFree (FC_MEM_ATTR, 1); /* size is to expensive */ - free (old->attr); - } - - if (old == &parse->pstack_static[parse->pstack_static_used - 1]) - parse->pstack_static_used--; - else - { - FcMemFree (FC_MEM_PSTACK, sizeof (FcPStack)); - free (old); - } - return FcTrue; -} - -static FcBool -FcConfigInit (FcConfigParse *parse, const FcChar8 *name, FcConfig *config, XML_Parser parser) -{ - parse->pstack = 0; - parse->pstack_static_used = 0; - parse->vstack = 0; - parse->vstack_static_used = 0; - parse->error = FcFalse; - parse->name = name; - parse->config = config; - parse->parser = parser; - return FcTrue; -} - -static void -FcConfigCleanup (FcConfigParse *parse) -{ - while (parse->pstack) - FcPStackPop (parse); -} - -static const FcChar8 * -FcConfigGetAttribute (FcConfigParse *parse, const char *attr) -{ - FcChar8 **attrs; - if (!parse->pstack) - return 0; - - attrs = parse->pstack->attr; - if (!attrs) - return 0; - - while (*attrs) - { - if (!strcmp ((char *) *attrs, attr)) - return attrs[1]; - attrs += 2; - } - return 0; -} - -static void -FcStartElement(void *userData, const XML_Char *name, const XML_Char **attr) -{ - FcConfigParse *parse = userData; - FcElement element; - - element = FcElementMap (name); - if (element == FcElementUnknown) - FcConfigMessage (parse, FcSevereWarning, "unknown element \"%s\"", name); - - if (!FcPStackPush (parse, element, attr)) - { - FcConfigMessage (parse, FcSevereError, "out of memory"); - return; - } - return; -} - -static void -FcParseBlank (FcConfigParse *parse) -{ - int n = FcVStackElements (parse); - FcChar32 i; - while (n-- > 0) - { - FcVStack *v = FcVStackFetch (parse, n); - if (!parse->config->blanks) - { - parse->config->blanks = FcBlanksCreate (); - if (!parse->config->blanks) - goto bail; - } - switch (v->tag) { - case FcVStackInteger: - if (!FcBlanksAdd (parse->config->blanks, v->u.integer)) - goto bail; - break; - case FcVStackRange: - if (v->u.range.begin <= v->u.range.end) - { - for (i = v->u.range.begin; i <= v->u.range.end; i++) - { - if (!FcBlanksAdd (parse->config->blanks, i)) - goto bail; - } - } - break; - default: - FcConfigMessage (parse, FcSevereError, "invalid element in blank"); - break; - } - } - return; - bail: - FcConfigMessage (parse, FcSevereError, "out of memory"); -} - -static void -FcParseRescan (FcConfigParse *parse) -{ - int n = FcVStackElements (parse); - while (n-- > 0) - { - FcVStack *v = FcVStackFetch (parse, n); - if (v->tag != FcVStackInteger) - FcConfigMessage (parse, FcSevereWarning, "non-integer rescan"); - else - parse->config->rescanInterval = v->u.integer; - } -} - -static void -FcParseInt (FcConfigParse *parse) -{ - FcChar8 *s, *end; - int l; - - if (!parse->pstack) - return; - s = FcStrBufDoneStatic (&parse->pstack->str); - if (!s) - { - FcConfigMessage (parse, FcSevereError, "out of memory"); - return; - } - end = 0; - l = (int) strtol ((char *) s, (char **)&end, 0); - if (end != s + strlen ((char *) s)) - FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid integer", s); - else - FcVStackPushInteger (parse, l); - FcStrBufDestroy (&parse->pstack->str); -} - -/* - * idea copied from glib g_ascii_strtod with - * permission of the author (Alexander Larsson) - */ - -#include - -static double -FcStrtod (char *s, char **end) -{ - struct lconv *locale_data; - char *dot; - double v; - - /* - * Have to swap the decimal point to match the current locale - * if that locale doesn't use 0x2e - */ - if ((dot = strchr (s, 0x2e)) && - (locale_data = localeconv ()) && - (locale_data->decimal_point[0] != 0x2e || - locale_data->decimal_point[1] != 0)) - { - char buf[128]; - int slen = strlen (s); - int dlen = strlen (locale_data->decimal_point); - - if (slen + dlen > (int) sizeof (buf)) - { - if (end) - *end = s; - v = 0; - } - else - { - char *buf_end; - /* mantissa */ - strncpy (buf, s, dot - s); - /* decimal point */ - strcpy (buf + (dot - s), locale_data->decimal_point); - /* rest of number */ - strcpy (buf + (dot - s) + dlen, dot + 1); - buf_end = 0; - v = strtod (buf, &buf_end); - if (buf_end) { - buf_end = s + (buf_end - buf); - if (buf_end > dot) - buf_end -= dlen - 1; - } - if (end) - *end = buf_end; - } - } - else - v = strtod (s, end); - return v; -} - -static void -FcParseDouble (FcConfigParse *parse) -{ - FcChar8 *s, *end; - double d; - - if (!parse->pstack) - return; - s = FcStrBufDoneStatic (&parse->pstack->str); - if (!s) - { - FcConfigMessage (parse, FcSevereError, "out of memory"); - return; - } - end = 0; - d = FcStrtod ((char *) s, (char **)&end); - if (end != s + strlen ((char *) s)) - FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid double", s); - else - FcVStackPushDouble (parse, d); - FcStrBufDestroy (&parse->pstack->str); -} - -static void -FcParseString (FcConfigParse *parse, FcVStackTag tag) -{ - FcChar8 *s; - - if (!parse->pstack) - return; - s = FcStrBufDone (&parse->pstack->str); - if (!s) - { - FcConfigMessage (parse, FcSevereError, "out of memory"); - return; - } - if (!FcVStackPushString (parse, tag, s)) - FcStrFree (s); -} - -static void -FcParseMatrix (FcConfigParse *parse) -{ - FcVStack *vstack; - enum { m_done, m_xx, m_xy, m_yx, m_yy } matrix_state = m_yy; - FcMatrix m; - - while ((vstack = FcVStackPeek (parse))) - { - double v; - switch (vstack->tag) { - case FcVStackInteger: - v = vstack->u.integer; - break; - case FcVStackDouble: - v = vstack->u._double; - break; - default: - FcConfigMessage (parse, FcSevereError, "non-double matrix element"); - v = 1.0; - break; - } - switch (matrix_state) { - case m_xx: m.xx = v; break; - case m_xy: m.xy = v; break; - case m_yx: m.yx = v; break; - case m_yy: m.yy = v; break; - default: break; - } - FcVStackPopAndDestroy (parse); - matrix_state--; - } - if (matrix_state != m_done) - FcConfigMessage (parse, FcSevereError, "wrong number of matrix elements"); - else - FcVStackPushMatrix (parse, &m); -} - -static void -FcParseRange (FcConfigParse *parse) -{ - FcVStack *vstack; - FcRange r; - FcChar32 n; - int count = 1; - - while ((vstack = FcVStackPeek (parse))) - { - if (count < 0) - { - FcConfigMessage (parse, FcSevereError, "too many elements in range"); - return; - } - switch (vstack->tag) { - case FcVStackInteger: - n = vstack->u.integer; - break; - default: - FcConfigMessage (parse, FcSevereError, "invalid element in range"); - break; - } - if (count == 1) - r.end = n; - else - r.begin = n; - count--; - FcVStackPopAndDestroy (parse); - } - if (count < 0) - { - if (r.begin > r.end) - { - FcConfigMessage (parse, FcSevereError, "invalid range"); - return; - } - FcVStackPushRange (parse, &r); - } - else - FcConfigMessage (parse, FcSevereError, "invalid range"); -} - -static FcBool -FcConfigLexBool (FcConfigParse *parse, const FcChar8 *bool_) -{ - FcBool result = FcFalse; - - if (!FcNameBool (bool_, &result)) - FcConfigMessage (parse, FcSevereWarning, "\"%s\" is not known boolean", - bool_); - return result; -} - -static void -FcParseBool (FcConfigParse *parse) -{ - FcChar8 *s; - - if (!parse->pstack) - return; - s = FcStrBufDoneStatic (&parse->pstack->str); - if (!s) - { - FcConfigMessage (parse, FcSevereError, "out of memory"); - return; - } - FcVStackPushBool (parse, FcConfigLexBool (parse, s)); - FcStrBufDestroy (&parse->pstack->str); -} - -static void -FcParseCharSet (FcConfigParse *parse) -{ - FcVStack *vstack; - FcCharSet *charset = FcCharSetCreate (); - FcChar32 i; - int n = 0; - - while ((vstack = FcVStackPeek (parse))) - { - switch (vstack->tag) { - case FcVStackInteger: - if (!FcCharSetAddChar (charset, vstack->u.integer)) - { - FcConfigMessage (parse, FcSevereWarning, "invalid character: 0x%04x", vstack->u.integer); - } - else - n++; - break; - case FcVStackRange: - if (vstack->u.range.begin <= vstack->u.range.end) - { - for (i = vstack->u.range.begin; i <= vstack->u.range.end; i++) - { - if (!FcCharSetAddChar (charset, i)) - { - FcConfigMessage (parse, FcSevereWarning, "invalid character: 0x%04x", i); - } - else - n++; - } - } - break; - default: - FcConfigMessage (parse, FcSevereError, "invalid element in charset"); - break; - } - FcVStackPopAndDestroy (parse); - } - if (n > 0) - FcVStackPushCharSet (parse, charset); - else - FcCharSetDestroy (charset); -} - -static void -FcParseLangSet (FcConfigParse *parse) -{ - FcVStack *vstack; - FcLangSet *langset = FcLangSetCreate (); - int n = 0; - - while ((vstack = FcVStackPeek (parse))) - { - switch (vstack->tag) { - case FcVStackString: - if (!FcLangSetAdd (langset, vstack->u.string)) - { - FcConfigMessage (parse, FcSevereWarning, "invalid langset: %s", vstack->u.string); - } - else - n++; - break; - default: - FcConfigMessage (parse, FcSevereError, "invalid element in langset"); - break; - } - FcVStackPopAndDestroy (parse); - } - if (n > 0) - FcVStackPushLangSet (parse, langset); - else - FcLangSetDestroy (langset); -} - -static FcBool -FcConfigLexBinding (FcConfigParse *parse, - const FcChar8 *binding_string, - FcValueBinding *binding_ret) -{ - FcValueBinding binding; - - if (!binding_string) - binding = FcValueBindingWeak; - else - { - if (!strcmp ((char *) binding_string, "weak")) - binding = FcValueBindingWeak; - else if (!strcmp ((char *) binding_string, "strong")) - binding = FcValueBindingStrong; - else if (!strcmp ((char *) binding_string, "same")) - binding = FcValueBindingSame; - else - { - FcConfigMessage (parse, FcSevereWarning, "invalid binding \"%s\"", binding_string); - return FcFalse; - } - } - *binding_ret = binding; - return FcTrue; -} - -static void -FcParseFamilies (FcConfigParse *parse, FcVStackTag tag) -{ - FcVStack *vstack; - FcExpr *left, *expr = 0, *new; - - while ((vstack = FcVStackPeek (parse))) - { - if (vstack->tag != FcVStackFamily) - { - FcConfigMessage (parse, FcSevereWarning, "non-family"); - FcVStackPopAndDestroy (parse); - continue; - } - left = vstack->u.expr; - vstack->tag = FcVStackNone; - FcVStackPopAndDestroy (parse); - if (expr) - { - new = FcExprCreateOp (parse->config, left, FcOpComma, expr); - if (!new) - { - FcConfigMessage (parse, FcSevereError, "out of memory"); - FcExprDestroy (left); - FcExprDestroy (expr); - break; - } - expr = new; - } - else - expr = left; - } - if (expr) - { - if (!FcVStackPushExpr (parse, tag, expr)) - { - FcConfigMessage (parse, FcSevereError, "out of memory"); - FcExprDestroy (expr); - } - } -} - -static void -FcParseFamily (FcConfigParse *parse) -{ - FcChar8 *s; - FcExpr *expr; - - if (!parse->pstack) - return; - s = FcStrBufDoneStatic (&parse->pstack->str); - if (!s) - { - FcConfigMessage (parse, FcSevereError, "out of memory"); - return; - } - expr = FcExprCreateString (parse->config, s); - FcStrBufDestroy (&parse->pstack->str); - if (expr) - FcVStackPushExpr (parse, FcVStackFamily, expr); -} - -static void -FcParseAlias (FcConfigParse *parse) -{ - FcExpr *family = 0, *accept = 0, *prefer = 0, *def = 0, *new = 0; - FcEdit *edit = 0, *next; - FcVStack *vstack; - FcTest *test; - FcValueBinding binding; - - if (!FcConfigLexBinding (parse, FcConfigGetAttribute (parse, "binding"), &binding)) - return; - while ((vstack = FcVStackPeek (parse))) - { - switch (vstack->tag) { - case FcVStackFamily: - if (family) - { - new = FcExprCreateOp (parse->config, vstack->u.expr, FcOpComma, family); - if (!new) - FcConfigMessage (parse, FcSevereError, "out of memory"); - else - family = new; - } - else - new = vstack->u.expr; - if (new) - { - family = new; - vstack->tag = FcVStackNone; - } - break; - case FcVStackPrefer: - if (prefer) - FcExprDestroy (prefer); - prefer = vstack->u.expr; - vstack->tag = FcVStackNone; - break; - case FcVStackAccept: - if (accept) - FcExprDestroy (accept); - accept = vstack->u.expr; - vstack->tag = FcVStackNone; - break; - case FcVStackDefault: - if (def) - FcExprDestroy (def); - def = vstack->u.expr; - vstack->tag = FcVStackNone; - break; - default: - FcConfigMessage (parse, FcSevereWarning, "bad alias"); - break; - } - FcVStackPopAndDestroy (parse); - } - if (!family) - { - FcConfigMessage (parse, FcSevereError, "missing family in alias"); - if (prefer) - FcExprDestroy (prefer); - if (accept) - FcExprDestroy (accept); - if (def) - FcExprDestroy (def); - return; - } - if (prefer) - { - edit = FcEditCreate (parse, - FC_FAMILY_OBJECT, - FcOpPrepend, - prefer, - binding); - if (edit) - edit->next = 0; - else - FcExprDestroy (prefer); - } - if (accept) - { - next = edit; - edit = FcEditCreate (parse, - FC_FAMILY_OBJECT, - FcOpAppend, - accept, - binding); - if (edit) - edit->next = next; - else - FcExprDestroy (accept); - } - if (def) - { - next = edit; - edit = FcEditCreate (parse, - FC_FAMILY_OBJECT, - FcOpAppendLast, - def, - binding); - if (edit) - edit->next = next; - else - FcExprDestroy (def); - } - if (edit) - { - test = FcTestCreate (parse, FcMatchPattern, - FcQualAny, - (FcChar8 *) FC_FAMILY, - FcOpEqual, - family); - if (test) - if (!FcConfigAddEdit (parse->config, test, edit, FcMatchPattern)) - FcTestDestroy (test); - } - else - FcExprDestroy (family); -} - -static FcExpr * -FcPopExpr (FcConfigParse *parse) -{ - FcVStack *vstack = FcVStackPeek (parse); - FcExpr *expr = 0; - if (!vstack) - return 0; - switch (vstack->tag) { - case FcVStackNone: - break; - case FcVStackString: - case FcVStackFamily: - expr = FcExprCreateString (parse->config, vstack->u.string); - break; - case FcVStackField: - expr = FcExprCreateField (parse->config, (char *) vstack->u.string); - break; - case FcVStackConstant: - expr = FcExprCreateConst (parse->config, vstack->u.string); - break; - case FcVStackGlob: - /* XXX: What's the correct action here? (CDW) */ - break; - case FcVStackPrefer: - case FcVStackAccept: - case FcVStackDefault: - expr = vstack->u.expr; - vstack->tag = FcVStackNone; - break; - case FcVStackInteger: - expr = FcExprCreateInteger (parse->config, vstack->u.integer); - break; - case FcVStackDouble: - expr = FcExprCreateDouble (parse->config, vstack->u._double); - break; - case FcVStackMatrix: - expr = FcExprCreateMatrix (parse->config, vstack->u.matrix); - break; - case FcVStackRange: - break; - case FcVStackBool: - expr = FcExprCreateBool (parse->config, vstack->u.bool_); - break; - case FcVStackCharSet: - expr = FcExprCreateCharSet (parse->config, vstack->u.charset); - break; - case FcVStackLangSet: - expr = FcExprCreateLangSet (parse->config, vstack->u.langset); - break; - case FcVStackTest: - break; - case FcVStackExpr: - expr = vstack->u.expr; - vstack->tag = FcVStackNone; - break; - case FcVStackEdit: - break; - default: - break; - } - FcVStackPopAndDestroy (parse); - return expr; -} - -/* - * This builds a tree of binary operations. Note - * that every operator is defined so that if only - * a single operand is contained, the value of the - * whole expression is the value of the operand. - * - * This code reduces in that case to returning that - * operand. - */ -static FcExpr * -FcPopBinary (FcConfigParse *parse, FcOp op) -{ - FcExpr *left, *expr = 0, *new; - - while ((left = FcPopExpr (parse))) - { - if (expr) - { - new = FcExprCreateOp (parse->config, left, op, expr); - if (!new) - { - FcConfigMessage (parse, FcSevereError, "out of memory"); - FcExprDestroy (left); - FcExprDestroy (expr); - return 0; - } - expr = new; - } - else - expr = left; - } - return expr; -} - -static void -FcParseBinary (FcConfigParse *parse, FcOp op) -{ - FcExpr *expr = FcPopBinary (parse, op); - if (expr) - FcVStackPushExpr (parse, FcVStackExpr, expr); -} - -/* - * This builds a a unary operator, it consumes only - * a single operand - */ - -static FcExpr * -FcPopUnary (FcConfigParse *parse, FcOp op) -{ - FcExpr *operand, *new = 0; - - if ((operand = FcPopExpr (parse))) - { - new = FcExprCreateOp (parse->config, operand, op, 0); - if (!new) - { - FcExprDestroy (operand); - FcConfigMessage (parse, FcSevereError, "out of memory"); - } - } - return new; -} - -static void -FcParseUnary (FcConfigParse *parse, FcOp op) -{ - FcExpr *expr = FcPopUnary (parse, op); - if (expr) - FcVStackPushExpr (parse, FcVStackExpr, expr); -} - -static void -FcParseInclude (FcConfigParse *parse) -{ - FcChar8 *s; - const FcChar8 *i; - FcBool ignore_missing = FcFalse; - - s = FcStrBufDoneStatic (&parse->pstack->str); - if (!s) - { - FcConfigMessage (parse, FcSevereError, "out of memory"); - return; - } - i = FcConfigGetAttribute (parse, "ignore_missing"); - if (i && FcConfigLexBool (parse, (FcChar8 *) i) == FcTrue) - ignore_missing = FcTrue; - if (!FcConfigParseAndLoad (parse->config, s, !ignore_missing)) - parse->error = FcTrue; - FcStrBufDestroy (&parse->pstack->str); -} - -typedef struct _FcOpMap { - char name[16]; - FcOp op; -} FcOpMap; - -static FcOp -FcConfigLexOp (const FcChar8 *op, const FcOpMap *map, int nmap) -{ - int i; - - for (i = 0; i < nmap; i++) - if (!strcmp ((char *) op, map[i].name)) - return map[i].op; - return FcOpInvalid; -} - -static const FcOpMap fcCompareOps[] = { - { "eq", FcOpEqual }, - { "not_eq", FcOpNotEqual }, - { "less", FcOpLess }, - { "less_eq", FcOpLessEqual }, - { "more", FcOpMore }, - { "more_eq", FcOpMoreEqual }, - { "contains", FcOpContains }, - { "not_contains", FcOpNotContains } -}; - -#define NUM_COMPARE_OPS (int) (sizeof fcCompareOps / sizeof fcCompareOps[0]) - -static FcOp -FcConfigLexCompare (const FcChar8 *compare) -{ - return FcConfigLexOp (compare, fcCompareOps, NUM_COMPARE_OPS); -} - -static void -FcParseTest (FcConfigParse *parse) -{ - const FcChar8 *kind_string; - FcMatchKind kind; - const FcChar8 *qual_string; - FcQual qual; - const FcChar8 *name; - const FcChar8 *compare_string; - FcOp compare; - FcExpr *expr; - FcTest *test; - - kind_string = FcConfigGetAttribute (parse, "target"); - if (!kind_string) - kind = FcMatchDefault; - else - { - if (!strcmp ((char *) kind_string, "pattern")) - kind = FcMatchPattern; - else if (!strcmp ((char *) kind_string, "font")) - kind = FcMatchFont; - else if (!strcmp ((char *) kind_string, "scan")) - kind = FcMatchScan; - else if (!strcmp ((char *) kind_string, "default")) - kind = FcMatchDefault; - else - { - FcConfigMessage (parse, FcSevereWarning, "invalid test target \"%s\"", kind_string); - return; - } - } - qual_string = FcConfigGetAttribute (parse, "qual"); - if (!qual_string) - qual = FcQualAny; - else - { - if (!strcmp ((char *) qual_string, "any")) - qual = FcQualAny; - else if (!strcmp ((char *) qual_string, "all")) - qual = FcQualAll; - else if (!strcmp ((char *) qual_string, "first")) - qual = FcQualFirst; - else if (!strcmp ((char *) qual_string, "not_first")) - qual = FcQualNotFirst; - else - { - FcConfigMessage (parse, FcSevereWarning, "invalid test qual \"%s\"", qual_string); - return; - } - } - name = FcConfigGetAttribute (parse, "name"); - if (!name) - { - FcConfigMessage (parse, FcSevereWarning, "missing test name"); - return; - } - compare_string = FcConfigGetAttribute (parse, "compare"); - if (!compare_string) - compare = FcOpEqual; - else - { - compare = FcConfigLexCompare (compare_string); - if (compare == FcOpInvalid) - { - FcConfigMessage (parse, FcSevereWarning, "invalid test compare \"%s\"", compare_string); - return; - } - } - expr = FcPopBinary (parse, FcOpComma); - if (!expr) - { - FcConfigMessage (parse, FcSevereWarning, "missing test expression"); - return; - } - test = FcTestCreate (parse, kind, qual, name, compare, expr); - if (!test) - { - FcConfigMessage (parse, FcSevereError, "out of memory"); - return; - } - FcVStackPushTest (parse, test); -} - -static const FcOpMap fcModeOps[] = { - { "assign", FcOpAssign }, - { "assign_replace", FcOpAssignReplace }, - { "prepend", FcOpPrepend }, - { "prepend_first", FcOpPrependFirst }, - { "append", FcOpAppend }, - { "append_last", FcOpAppendLast }, -}; - -#define NUM_MODE_OPS (int) (sizeof fcModeOps / sizeof fcModeOps[0]) - -static FcOp -FcConfigLexMode (const FcChar8 *mode) -{ - return FcConfigLexOp (mode, fcModeOps, NUM_MODE_OPS); -} - -static void -FcParseEdit (FcConfigParse *parse) -{ - const FcChar8 *name; - const FcChar8 *mode_string; - FcOp mode; - FcValueBinding binding; - FcExpr *expr; - FcEdit *edit; - - name = FcConfigGetAttribute (parse, "name"); - if (!name) - { - FcConfigMessage (parse, FcSevereWarning, "missing edit name"); - return; - } - mode_string = FcConfigGetAttribute (parse, "mode"); - if (!mode_string) - mode = FcOpAssign; - else - { - mode = FcConfigLexMode (mode_string); - if (mode == FcOpInvalid) - { - FcConfigMessage (parse, FcSevereWarning, "invalid edit mode \"%s\"", mode_string); - return; - } - } - if (!FcConfigLexBinding (parse, FcConfigGetAttribute (parse, "binding"), &binding)) - return; - - expr = FcPopBinary (parse, FcOpComma); - edit = FcEditCreate (parse, FcObjectFromName ((char *) name), - mode, expr, binding); - if (!edit) - { - FcConfigMessage (parse, FcSevereError, "out of memory"); - FcExprDestroy (expr); - return; - } - if (!FcVStackPushEdit (parse, edit)) - FcEditDestroy (edit); -} - -static void -FcParseMatch (FcConfigParse *parse) -{ - const FcChar8 *kind_name; - FcMatchKind kind; - FcTest *test = 0; - FcEdit *edit = 0; - FcVStack *vstack; - - kind_name = FcConfigGetAttribute (parse, "target"); - if (!kind_name) - kind = FcMatchPattern; - else - { - if (!strcmp ((char *) kind_name, "pattern")) - kind = FcMatchPattern; - else if (!strcmp ((char *) kind_name, "font")) - kind = FcMatchFont; - else if (!strcmp ((char *) kind_name, "scan")) - kind = FcMatchScan; - else - { - FcConfigMessage (parse, FcSevereWarning, "invalid match target \"%s\"", kind_name); - return; - } - } - while ((vstack = FcVStackPeek (parse))) - { - switch (vstack->tag) { - case FcVStackTest: - vstack->u.test->next = test; - test = vstack->u.test; - vstack->tag = FcVStackNone; - break; - case FcVStackEdit: - vstack->u.edit->next = edit; - edit = vstack->u.edit; - vstack->tag = FcVStackNone; - if (kind == FcMatchScan && edit->object > FC_MAX_BASE_OBJECT) - { - FcConfigMessage (parse, FcSevereError, - " cannot edit user-defined object \"%s\"", - FcObjectName(edit->object)); - } - break; - default: - FcConfigMessage (parse, FcSevereWarning, "invalid match element"); - break; - } - FcVStackPopAndDestroy (parse); - } - if (!FcConfigAddEdit (parse->config, test, edit, kind)) - FcConfigMessage (parse, FcSevereError, "out of memory"); -} - -static void -FcParseAcceptRejectFont (FcConfigParse *parse, FcElement element) -{ - FcVStack *vstack; - - while ((vstack = FcVStackPeek (parse))) - { - switch (vstack->tag) { - case FcVStackGlob: - if (!FcConfigGlobAdd (parse->config, - vstack->u.string, - element == FcElementAcceptfont)) - { - FcConfigMessage (parse, FcSevereError, "out of memory"); - } - break; - case FcVStackPattern: - if (!FcConfigPatternsAdd (parse->config, - vstack->u.pattern, - element == FcElementAcceptfont)) - { - FcConfigMessage (parse, FcSevereError, "out of memory"); - } - else - vstack->tag = FcVStackNone; - break; - default: - FcConfigMessage (parse, FcSevereWarning, "bad font selector"); - break; - } - FcVStackPopAndDestroy (parse); - } -} - - -static FcValue -FcPopValue (FcConfigParse *parse) -{ - FcVStack *vstack = FcVStackPeek (parse); - FcValue value; - - value.type = FcTypeVoid; - - if (!vstack) - return value; - - switch (vstack->tag) { - case FcVStackString: - value.u.s = FcStrStaticName (vstack->u.string); - if (value.u.s) - value.type = FcTypeString; - break; - case FcVStackConstant: - if (FcNameConstant (vstack->u.string, &value.u.i)) - value.type = FcTypeInteger; - break; - case FcVStackInteger: - value.u.i = vstack->u.integer; - value.type = FcTypeInteger; - break; - case FcVStackDouble: - value.u.d = vstack->u._double; - value.type = FcTypeInteger; - break; - case FcVStackMatrix: - value.u.m = FcMatrixCopy (vstack->u.matrix); - if (value.u.m) - value.type = FcTypeMatrix; - break; - case FcVStackBool: - value.u.b = vstack->u.bool_; - value.type = FcTypeBool; - break; - case FcVStackCharSet: - value.u.c = FcCharSetCopy (vstack->u.charset); - if (value.u.c) - value.type = FcTypeCharSet; - break; - case FcVStackLangSet: - value.u.l = FcLangSetCopy (vstack->u.langset); - if (value.u.l) - value.type = FcTypeLangSet; - break; - default: - FcConfigMessage (parse, FcSevereWarning, "unknown pattern element %d", - vstack->tag); - break; - } - FcVStackPopAndDestroy (parse); - - return value; -} - -static void -FcParsePatelt (FcConfigParse *parse) -{ - FcValue value; - FcPattern *pattern = FcPatternCreate (); - const char *name; - - if (!pattern) - { - FcConfigMessage (parse, FcSevereError, "out of memory"); - return; - } - - name = (char *) FcConfigGetAttribute (parse, "name"); - if (!name) - { - FcConfigMessage (parse, FcSevereWarning, "missing pattern element name"); - FcPatternDestroy (pattern); - return; - } - - for (;;) - { - value = FcPopValue (parse); - if (value.type == FcTypeVoid) - break; - if (!FcPatternAdd (pattern, name, value, FcTrue)) - { - FcConfigMessage (parse, FcSevereError, "out of memory"); - FcValueDestroy(value); - break; - } - FcValueDestroy(value); - } - - FcVStackPushPattern (parse, pattern); -} - -static void -FcParsePattern (FcConfigParse *parse) -{ - FcVStack *vstack; - FcPattern *pattern = FcPatternCreate (); - - if (!pattern) - { - FcConfigMessage (parse, FcSevereError, "out of memory"); - return; - } - - while ((vstack = FcVStackPeek (parse))) - { - switch (vstack->tag) { - case FcVStackPattern: - if (!FcPatternAppend (pattern, vstack->u.pattern)) - { - FcConfigMessage (parse, FcSevereError, "out of memory"); - FcPatternDestroy (pattern); - return; - } - break; - default: - FcConfigMessage (parse, FcSevereWarning, "unknown pattern element"); - break; - } - FcVStackPopAndDestroy (parse); - } - - FcVStackPushPattern (parse, pattern); -} - -static void -FcEndElement(void *userData, const XML_Char *name) -{ - FcConfigParse *parse = userData; - FcChar8 *data; -#ifdef _WIN32 - FcChar8 buffer[1000]; -#endif - - if (!parse->pstack) - return; - switch (parse->pstack->element) { - case FcElementNone: - break; - case FcElementFontconfig: - break; - case FcElementDir: - data = FcStrBufDoneStatic (&parse->pstack->str); - if (!data) - { - FcConfigMessage (parse, FcSevereError, "out of memory"); - break; - } -#ifdef _WIN32 - if (strcmp (data, "CUSTOMFONTDIR") == 0) - { - char *p; - data = buffer; - if (!GetModuleFileName (NULL, buffer, sizeof (buffer) - 20)) - { - FcConfigMessage (parse, FcSevereError, "GetModuleFileName failed"); - break; - } - /* - * Must use the multi-byte aware function to search - * for backslash because East Asian double-byte code - * pages have characters with backslash as the second - * byte. - */ - p = _mbsrchr (data, '\\'); - if (p) *p = '\0'; - strcat (data, "\\fonts"); - } - else if (strcmp (data, "APPSHAREFONTDIR") == 0) - { - char *p; - data = buffer; - if (!GetModuleFileName (NULL, buffer, sizeof (buffer) - 20)) - { - FcConfigMessage (parse, FcSevereError, "GetModuleFileName failed"); - break; - } - p = _mbsrchr (data, '\\'); - if (p) *p = '\0'; - strcat (data, "\\..\\share\\fonts"); - } - else if (strcmp (data, "WINDOWSFONTDIR") == 0) - { - int rc; - data = buffer; -#if _WIN32_WINNT >= 0x0500 - rc = GetSystemWindowsDirectory (buffer, sizeof (buffer) - 20); -#else - rc = GetWindowsDirectory (buffer, sizeof (buffer) - 20); -#endif - if (rc == 0 || rc > sizeof (buffer) - 20) - { - FcConfigMessage (parse, FcSevereError, "GetSystemWindowsDirectory failed"); - break; - } - if (data [strlen (data) - 1] != '\\') - strcat (data, "\\"); - strcat (data, "fonts"); - } -#endif - if (strlen ((char *) data) == 0) - FcConfigMessage (parse, FcSevereWarning, "empty font directory name ignored"); - else if (!FcStrUsesHome (data) || FcConfigHome ()) - { - if (!FcConfigAddDir (parse->config, data)) - FcConfigMessage (parse, FcSevereError, "out of memory; cannot add directory %s", data); - } - FcStrBufDestroy (&parse->pstack->str); - break; - case FcElementCacheDir: - data = FcStrBufDone (&parse->pstack->str); - if (!data) - { - FcConfigMessage (parse, FcSevereError, "out of memory"); - break; - } -#ifdef _WIN32 - if (strcmp (data, "WINDOWSTEMPDIR_FONTCONFIG_CACHE") == 0) - { - int rc; - FcStrFree (data); - data = malloc (1000); - if (!data) - { - FcConfigMessage (parse, FcSevereError, "out of memory"); - break; - } - FcMemAlloc (FC_MEM_STRING, 1000); - rc = GetTempPath (800, data); - if (rc == 0 || rc > 800) - { - FcConfigMessage (parse, FcSevereError, "GetTempPath failed"); - FcStrFree (data); - break; - } - if (data [strlen (data) - 1] != '\\') - strcat (data, "\\"); - strcat (data, "fontconfig\\cache"); - } -#endif - if (!FcStrUsesHome (data) || FcConfigHome ()) - { - if (!FcConfigAddCacheDir (parse->config, data)) - FcConfigMessage (parse, FcSevereError, "out of memory; cannot add cache directory %s", data); - } - FcStrFree (data); - break; - - case FcElementCache: - data = FcStrBufDoneStatic (&parse->pstack->str); - if (!data) - { - FcConfigMessage (parse, FcSevereError, "out of memory"); - break; - } - /* discard this data; no longer used */ - FcStrBufDestroy (&parse->pstack->str); - break; - case FcElementInclude: - FcParseInclude (parse); - break; - case FcElementConfig: - break; - case FcElementMatch: - FcParseMatch (parse); - break; - case FcElementAlias: - FcParseAlias (parse); - break; - - case FcElementBlank: - FcParseBlank (parse); - break; - case FcElementRescan: - FcParseRescan (parse); - break; - - case FcElementPrefer: - FcParseFamilies (parse, FcVStackPrefer); - break; - case FcElementAccept: - FcParseFamilies (parse, FcVStackAccept); - break; - case FcElementDefault: - FcParseFamilies (parse, FcVStackDefault); - break; - case FcElementFamily: - FcParseFamily (parse); - break; - - case FcElementTest: - FcParseTest (parse); - break; - case FcElementEdit: - FcParseEdit (parse); - break; - - case FcElementInt: - FcParseInt (parse); - break; - case FcElementDouble: - FcParseDouble (parse); - break; - case FcElementString: - FcParseString (parse, FcVStackString); - break; - case FcElementMatrix: - FcParseMatrix (parse); - break; - case FcElementRange: - FcParseRange (parse); - break; - case FcElementBool: - FcParseBool (parse); - break; - case FcElementCharSet: - FcParseCharSet (parse); - break; - case FcElementLangSet: - FcParseLangSet (parse); - break; - case FcElementSelectfont: - break; - case FcElementAcceptfont: - case FcElementRejectfont: - FcParseAcceptRejectFont (parse, parse->pstack->element); - break; - case FcElementGlob: - FcParseString (parse, FcVStackGlob); - break; - case FcElementPattern: - FcParsePattern (parse); - break; - case FcElementPatelt: - FcParsePatelt (parse); - break; - case FcElementName: - FcParseString (parse, FcVStackField); - break; - case FcElementConst: - FcParseString (parse, FcVStackConstant); - break; - case FcElementOr: - FcParseBinary (parse, FcOpOr); - break; - case FcElementAnd: - FcParseBinary (parse, FcOpAnd); - break; - case FcElementEq: - FcParseBinary (parse, FcOpEqual); - break; - case FcElementNotEq: - FcParseBinary (parse, FcOpNotEqual); - break; - case FcElementLess: - FcParseBinary (parse, FcOpLess); - break; - case FcElementLessEq: - FcParseBinary (parse, FcOpLessEqual); - break; - case FcElementMore: - FcParseBinary (parse, FcOpMore); - break; - case FcElementMoreEq: - FcParseBinary (parse, FcOpMoreEqual); - break; - case FcElementContains: - FcParseBinary (parse, FcOpContains); - break; - case FcElementNotContains: - FcParseBinary (parse, FcOpNotContains); - break; - case FcElementPlus: - FcParseBinary (parse, FcOpPlus); - break; - case FcElementMinus: - FcParseBinary (parse, FcOpMinus); - break; - case FcElementTimes: - FcParseBinary (parse, FcOpTimes); - break; - case FcElementDivide: - FcParseBinary (parse, FcOpDivide); - break; - case FcElementNot: - FcParseUnary (parse, FcOpNot); - break; - case FcElementIf: - FcParseBinary (parse, FcOpQuest); - break; - case FcElementFloor: - FcParseUnary (parse, FcOpFloor); - break; - case FcElementCeil: - FcParseUnary (parse, FcOpCeil); - break; - case FcElementRound: - FcParseUnary (parse, FcOpRound); - break; - case FcElementTrunc: - FcParseUnary (parse, FcOpTrunc); - break; - case FcElementUnknown: - break; - } - (void) FcPStackPop (parse); -} - -static void -FcCharacterData (void *userData, const XML_Char *s, int len) -{ - FcConfigParse *parse = userData; - - if (!parse->pstack) - return; - if (!FcStrBufData (&parse->pstack->str, (FcChar8 *) s, len)) - FcConfigMessage (parse, FcSevereError, "out of memory"); -} - -static void -FcStartDoctypeDecl (void *userData, - const XML_Char *doctypeName, - const XML_Char *sysid, - const XML_Char *pubid, - int has_internal_subset) -{ - FcConfigParse *parse = userData; - - if (strcmp ((char *) doctypeName, "fontconfig") != 0) - FcConfigMessage (parse, FcSevereError, "invalid doctype \"%s\"", doctypeName); -} - -#ifdef ENABLE_LIBXML2 - -static void -FcInternalSubsetDecl (void *userData, - const XML_Char *doctypeName, - const XML_Char *sysid, - const XML_Char *pubid) -{ - FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 1); -} - -static void -FcExternalSubsetDecl (void *userData, - const XML_Char *doctypeName, - const XML_Char *sysid, - const XML_Char *pubid) -{ - FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 0); -} - -#else /* ENABLE_LIBXML2 */ - -static void -FcEndDoctypeDecl (void *userData) -{ -} - -#endif /* ENABLE_LIBXML2 */ - -static int -FcSortCmpStr (const void *a, const void *b) -{ - const FcChar8 *as = *((FcChar8 **) a); - const FcChar8 *bs = *((FcChar8 **) b); - return FcStrCmp (as, bs); -} - -static FcBool -FcConfigParseAndLoadDir (FcConfig *config, - const FcChar8 *name, - const FcChar8 *dir, - FcBool complain) -{ - DIR *d; - struct dirent *e; - FcBool ret = FcTrue; - FcChar8 *file; - FcChar8 *base; - FcStrSet *files; - - d = opendir ((char *) dir); - if (!d) - { - if (complain) - FcConfigMessage (0, FcSevereError, "Cannot open config dir \"%s\"", - name); - ret = FcFalse; - goto bail0; - } - /* freed below */ - file = (FcChar8 *) malloc (strlen ((char *) dir) + 1 + FC_MAX_FILE_LEN + 1); - if (!file) - { - ret = FcFalse; - goto bail1; - } - - strcpy ((char *) file, (char *) dir); - strcat ((char *) file, "/"); - base = file + strlen ((char *) file); - - files = FcStrSetCreate (); - if (!files) - { - ret = FcFalse; - goto bail2; - } - - if (FcDebug () & FC_DBG_CONFIG) - printf ("\tScanning config dir %s\n", dir); - - while (ret && (e = readdir (d))) - { - int d_len; -#define TAIL ".conf" -#define TAIL_LEN 5 - /* - * Add all files of the form [0-9]*.conf - */ - if ('0' <= e->d_name[0] && e->d_name[0] <= '9' && - (d_len = strlen (e->d_name)) < FC_MAX_FILE_LEN && - d_len > TAIL_LEN && - strcmp (e->d_name + d_len - TAIL_LEN, TAIL) == 0) - { - strcpy ((char *) base, (char *) e->d_name); - if (!FcStrSetAdd (files, file)) - { - ret = FcFalse; - goto bail3; - } - } - } - if (ret) - { - int i; - qsort (files->strs, files->num, sizeof (FcChar8 *), - (int (*)(const void *, const void *)) FcSortCmpStr); - for (i = 0; ret && i < files->num; i++) - ret = FcConfigParseAndLoad (config, files->strs[i], complain); - } -bail3: - FcStrSetDestroy (files); -bail2: - free (file); -bail1: - closedir (d); -bail0: - return ret || !complain; -} - -FcBool -FcConfigParseAndLoad (FcConfig *config, - const FcChar8 *name, - FcBool complain) -{ - - XML_Parser p; - FcChar8 *filename; - int fd; - int len; - FcConfigParse parse; - FcBool error = FcTrue; - -#ifdef ENABLE_LIBXML2 - xmlSAXHandler sax; - char buf[BUFSIZ]; -#else - void *buf; -#endif - - filename = FcConfigFilename (name); - if (!filename) - goto bail0; - - if (FcStrSetMember (config->configFiles, filename)) - { - FcStrFree (filename); - return FcTrue; - } - - if (!FcStrSetAdd (config->configFiles, filename)) - { - FcStrFree (filename); - goto bail0; - } - - if (FcFileIsDir (filename)) - { - FcBool ret = FcConfigParseAndLoadDir (config, name, filename, complain); - FcStrFree (filename); - return ret; - } - - if (FcDebug () & FC_DBG_CONFIG) - printf ("\tLoading config file %s\n", filename); - - fd = open ((char *) filename, O_RDONLY); - if (fd == -1) { - FcStrFree (filename); - goto bail0; - } - -#ifdef ENABLE_LIBXML2 - memset(&sax, 0, sizeof(sax)); - - sax.internalSubset = FcInternalSubsetDecl; - sax.externalSubset = FcExternalSubsetDecl; - sax.startElement = FcStartElement; - sax.endElement = FcEndElement; - sax.characters = FcCharacterData; - - p = xmlCreatePushParserCtxt (&sax, &parse, NULL, 0, (const char *) filename); -#else - p = XML_ParserCreate ("UTF-8"); -#endif - FcStrFree (filename); - - if (!p) - goto bail1; - - if (!FcConfigInit (&parse, name, config, p)) - goto bail2; - -#ifndef ENABLE_LIBXML2 - - XML_SetUserData (p, &parse); - - XML_SetDoctypeDeclHandler (p, FcStartDoctypeDecl, FcEndDoctypeDecl); - XML_SetElementHandler (p, FcStartElement, FcEndElement); - XML_SetCharacterDataHandler (p, FcCharacterData); - -#endif /* ENABLE_LIBXML2 */ - - do { -#ifndef ENABLE_LIBXML2 - buf = XML_GetBuffer (p, BUFSIZ); - if (!buf) - { - FcConfigMessage (&parse, FcSevereError, "cannot get parse buffer"); - goto bail3; - } -#endif - len = read (fd, buf, BUFSIZ); - if (len < 0) - { - FcConfigMessage (&parse, FcSevereError, "failed reading config file"); - goto bail3; - } - -#ifdef ENABLE_LIBXML2 - if (xmlParseChunk (p, buf, len, len == 0)) -#else - if (!XML_ParseBuffer (p, len, len == 0)) -#endif - { - FcConfigMessage (&parse, FcSevereError, "%s", - XML_ErrorString (XML_GetErrorCode (p))); - goto bail3; - } - } while (len != 0); - error = parse.error; -bail3: - FcConfigCleanup (&parse); -bail2: - XML_ParserFree (p); -bail1: - close (fd); - fd = -1; -bail0: - if (error && complain) - { - if (name) - FcConfigMessage (0, FcSevereError, "Cannot load config file \"%s\"", name); - else - FcConfigMessage (0, FcSevereError, "Cannot load default config file"); - return FcFalse; - } - return FcTrue; -} -#define __fcxml__ -#include "fcaliastail.h" -#undef __fcxml__ +/* + * fontconfig/src/fcxml.c + * + * Copyright © 2002 Keith Packard + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of the author(s) not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. The authors make no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "fcint.h" +#include +#include +#include + +#ifdef ENABLE_LIBXML2 + +#include + +#define XML_Char xmlChar +#define XML_Parser xmlParserCtxtPtr +#define XML_ParserFree xmlFreeParserCtxt +#define XML_GetCurrentLineNumber xmlSAX2GetLineNumber +#define XML_GetErrorCode xmlCtxtGetLastError +#define XML_ErrorString(Error) (Error)->message + +#else /* ENABLE_LIBXML2 */ + +#ifndef HAVE_XMLPARSE_H +#define HAVE_XMLPARSE_H 0 +#endif + +#if HAVE_XMLPARSE_H +#include +#else +#include +#endif + +#endif /* ENABLE_LIBXML2 */ + +#ifdef _WIN32 +#include +#endif + +static void +FcExprDestroy (FcExpr *e); + +void +FcTestDestroy (FcTest *test) +{ + if (test->next) + FcTestDestroy (test->next); + FcExprDestroy (test->expr); + FcMemFree (FC_MEM_TEST, sizeof (FcTest)); + free (test); +} + +static FcExpr * +FcExprCreateInteger (FcConfig *config, int i) +{ + FcExpr *e = FcConfigAllocExpr (config); + if (e) + { + e->op = FcOpInteger; + e->u.ival = i; + } + return e; +} + +static FcExpr * +FcExprCreateDouble (FcConfig *config, double d) +{ + FcExpr *e = FcConfigAllocExpr (config); + if (e) + { + e->op = FcOpDouble; + e->u.dval = d; + } + return e; +} + +static FcExpr * +FcExprCreateString (FcConfig *config, const FcChar8 *s) +{ + FcExpr *e = FcConfigAllocExpr (config); + if (e) + { + e->op = FcOpString; + e->u.sval = FcStrStaticName (s); + } + return e; +} + +static FcExpr * +FcExprCreateMatrix (FcConfig *config, const FcMatrix *m) +{ + FcExpr *e = FcConfigAllocExpr (config); + if (e) + { + e->op = FcOpMatrix; + e->u.mval = FcMatrixCopy (m); + } + return e; +} + +static FcExpr * +FcExprCreateBool (FcConfig *config, FcBool b) +{ + FcExpr *e = FcConfigAllocExpr (config); + if (e) + { + e->op = FcOpBool; + e->u.bval = b; + } + return e; +} + +static FcExpr * +FcExprCreateCharSet (FcConfig *config, FcCharSet *charset) +{ + FcExpr *e = FcConfigAllocExpr (config); + if (e) + { + e->op = FcOpCharSet; + e->u.cval = FcCharSetCopy (charset); + } + return e; +} + +static FcExpr * +FcExprCreateLangSet (FcConfig *config, FcLangSet *langset) +{ + FcExpr *e = FcConfigAllocExpr (config); + if (e) + { + e->op = FcOpLangSet; + e->u.lval = FcLangSetCopy (langset); + } + return e; +} + +static FcExpr * +FcExprCreateField (FcConfig *config, const char *field) +{ + FcExpr *e = FcConfigAllocExpr (config); + if (e) + { + e->op = FcOpField; + e->u.object = FcObjectFromName (field); + } + return e; +} + +static FcExpr * +FcExprCreateConst (FcConfig *config, const FcChar8 *constant) +{ + FcExpr *e = FcConfigAllocExpr (config); + if (e) + { + e->op = FcOpConst; + e->u.constant = FcStrStaticName (constant); + } + return e; +} + +static FcExpr * +FcExprCreateOp (FcConfig *config, FcExpr *left, FcOp op, FcExpr *right) +{ + FcExpr *e = FcConfigAllocExpr (config); + if (e) + { + e->op = op; + e->u.tree.left = left; + e->u.tree.right = right; + } + return e; +} + +static void +FcExprDestroy (FcExpr *e) +{ + if (!e) + return; + switch (e->op) { + case FcOpInteger: + break; + case FcOpDouble: + break; + case FcOpString: + break; + case FcOpMatrix: + FcMatrixFree (e->u.mval); + break; + case FcOpRange: + break; + case FcOpCharSet: + FcCharSetDestroy (e->u.cval); + break; + case FcOpLangSet: + FcLangSetDestroy (e->u.lval); + break; + case FcOpBool: + break; + case FcOpField: + break; + case FcOpConst: + break; + case FcOpAssign: + case FcOpAssignReplace: + case FcOpPrepend: + case FcOpPrependFirst: + case FcOpAppend: + case FcOpAppendLast: + break; + case FcOpOr: + case FcOpAnd: + case FcOpEqual: + case FcOpNotEqual: + case FcOpLess: + case FcOpLessEqual: + case FcOpMore: + case FcOpMoreEqual: + case FcOpContains: + case FcOpListing: + case FcOpNotContains: + case FcOpPlus: + case FcOpMinus: + case FcOpTimes: + case FcOpDivide: + case FcOpQuest: + case FcOpComma: + FcExprDestroy (e->u.tree.right); + /* fall through */ + case FcOpNot: + case FcOpFloor: + case FcOpCeil: + case FcOpRound: + case FcOpTrunc: + FcExprDestroy (e->u.tree.left); + break; + case FcOpNil: + case FcOpInvalid: + break; + } + + e->op = FcOpNil; +} + +void +FcEditDestroy (FcEdit *e) +{ + if (e->next) + FcEditDestroy (e->next); + if (e->expr) + FcExprDestroy (e->expr); + free (e); +} + +typedef enum _FcElement { + FcElementNone, + FcElementFontconfig, + FcElementDir, + FcElementCacheDir, + FcElementCache, + FcElementInclude, + FcElementConfig, + FcElementMatch, + FcElementAlias, + + FcElementBlank, + FcElementRescan, + + FcElementPrefer, + FcElementAccept, + FcElementDefault, + FcElementFamily, + + FcElementSelectfont, + FcElementAcceptfont, + FcElementRejectfont, + FcElementGlob, + FcElementPattern, + FcElementPatelt, + + FcElementTest, + FcElementEdit, + FcElementInt, + FcElementDouble, + FcElementString, + FcElementMatrix, + FcElementRange, + FcElementBool, + FcElementCharSet, + FcElementLangSet, + FcElementName, + FcElementConst, + FcElementOr, + FcElementAnd, + FcElementEq, + FcElementNotEq, + FcElementLess, + FcElementLessEq, + FcElementMore, + FcElementMoreEq, + FcElementContains, + FcElementNotContains, + FcElementPlus, + FcElementMinus, + FcElementTimes, + FcElementDivide, + FcElementNot, + FcElementIf, + FcElementFloor, + FcElementCeil, + FcElementRound, + FcElementTrunc, + FcElementUnknown +} FcElement; + +static const struct { + const char name[16]; + FcElement element; +} fcElementMap[] = { + { "fontconfig", FcElementFontconfig }, + { "dir", FcElementDir }, + { "cachedir", FcElementCacheDir }, + { "cache", FcElementCache }, + { "include", FcElementInclude }, + { "config", FcElementConfig }, + { "match", FcElementMatch }, + { "alias", FcElementAlias }, + + { "blank", FcElementBlank }, + { "rescan", FcElementRescan }, + + { "prefer", FcElementPrefer }, + { "accept", FcElementAccept }, + { "default", FcElementDefault }, + { "family", FcElementFamily }, + + { "selectfont", FcElementSelectfont }, + { "acceptfont", FcElementAcceptfont }, + { "rejectfont", FcElementRejectfont }, + { "glob", FcElementGlob }, + { "pattern", FcElementPattern }, + { "patelt", FcElementPatelt }, + + { "test", FcElementTest }, + { "edit", FcElementEdit }, + { "int", FcElementInt }, + { "double", FcElementDouble }, + { "string", FcElementString }, + { "matrix", FcElementMatrix }, + { "range", FcElementRange }, + { "bool", FcElementBool }, + { "charset", FcElementCharSet }, + { "langset", FcElementLangSet }, + { "name", FcElementName }, + { "const", FcElementConst }, + { "or", FcElementOr }, + { "and", FcElementAnd }, + { "eq", FcElementEq }, + { "not_eq", FcElementNotEq }, + { "less", FcElementLess }, + { "less_eq", FcElementLessEq }, + { "more", FcElementMore }, + { "more_eq", FcElementMoreEq }, + { "contains", FcElementContains }, + { "not_contains", FcElementNotContains }, + { "plus", FcElementPlus }, + { "minus", FcElementMinus }, + { "times", FcElementTimes }, + { "divide", FcElementDivide }, + { "not", FcElementNot }, + { "if", FcElementIf }, + { "floor", FcElementFloor }, + { "ceil", FcElementCeil }, + { "round", FcElementRound }, + { "trunc", FcElementTrunc }, +}; +#define NUM_ELEMENT_MAPS (int) (sizeof fcElementMap / sizeof fcElementMap[0]) + +static FcElement +FcElementMap (const XML_Char *name) +{ + + int i; + for (i = 0; i < NUM_ELEMENT_MAPS; i++) + if (!strcmp ((char *) name, fcElementMap[i].name)) + return fcElementMap[i].element; + return FcElementUnknown; +} + +typedef struct _FcPStack { + struct _FcPStack *prev; + FcElement element; + FcChar8 **attr; + FcStrBuf str; + FcChar8 *attr_buf_static[16]; +} FcPStack; + +typedef enum _FcVStackTag { + FcVStackNone, + + FcVStackString, + FcVStackFamily, + FcVStackField, + FcVStackConstant, + FcVStackGlob, + FcVStackPattern, + + FcVStackPrefer, + FcVStackAccept, + FcVStackDefault, + + FcVStackInteger, + FcVStackDouble, + FcVStackMatrix, + FcVStackRange, + FcVStackBool, + FcVStackCharSet, + FcVStackLangSet, + + FcVStackTest, + FcVStackExpr, + FcVStackEdit +} FcVStackTag; + +typedef struct _FcVStack { + struct _FcVStack *prev; + FcPStack *pstack; /* related parse element */ + FcVStackTag tag; + union { + FcChar8 *string; + + int integer; + double _double; + FcMatrix *matrix; + FcRange range; + FcBool bool_; + FcCharSet *charset; + FcLangSet *langset; + + FcTest *test; + FcQual qual; + FcOp op; + FcExpr *expr; + FcEdit *edit; + + FcPattern *pattern; + } u; +} FcVStack; + +typedef struct _FcConfigParse { + FcPStack *pstack; + FcVStack *vstack; + FcBool error; + const FcChar8 *name; + FcConfig *config; + XML_Parser parser; + int pstack_static_used; + FcPStack pstack_static[8]; + int vstack_static_used; + FcVStack vstack_static[64]; +} FcConfigParse; + +typedef enum _FcConfigSeverity { + FcSevereInfo, FcSevereWarning, FcSevereError +} FcConfigSeverity; + +static void +FcConfigMessage (FcConfigParse *parse, FcConfigSeverity severe, const char *fmt, ...) +{ + const char *s = "unknown"; + va_list args; + + va_start (args, fmt); + + switch (severe) { + case FcSevereInfo: s = "info"; break; + case FcSevereWarning: s = "warning"; break; + case FcSevereError: s = "error"; break; + } + if (parse) + { + if (parse->name) + fprintf (stderr, "Fontconfig %s: \"%s\", line %d: ", s, + parse->name, (int)XML_GetCurrentLineNumber (parse->parser)); + else + fprintf (stderr, "Fontconfig %s: line %d: ", s, + (int)XML_GetCurrentLineNumber (parse->parser)); + if (severe >= FcSevereError) + parse->error = FcTrue; + } + else + fprintf (stderr, "Fontconfig %s: ", s); + vfprintf (stderr, fmt, args); + fprintf (stderr, "\n"); + va_end (args); +} + + +static const char * +FcTypeName (FcType type) +{ + switch (type) { + case FcTypeVoid: + return "void"; + case FcTypeInteger: + case FcTypeDouble: + return "number"; + case FcTypeString: + return "string"; + case FcTypeBool: + return "bool"; + case FcTypeMatrix: + return "matrix"; + case FcTypeCharSet: + return "charset"; + case FcTypeFTFace: + return "FT_Face"; + case FcTypeLangSet: + return "langset"; + default: + return "unknown"; + } +} + +static void +FcTypecheckValue (FcConfigParse *parse, FcType value, FcType type) +{ + if (value == FcTypeInteger) + value = FcTypeDouble; + if (type == FcTypeInteger) + type = FcTypeDouble; + if (value != type) + { + if ((value == FcTypeLangSet && type == FcTypeString) || + (value == FcTypeString && type == FcTypeLangSet)) + return; + if (type == (FcType) -1) + return; + FcConfigMessage (parse, FcSevereWarning, "saw %s, expected %s", + FcTypeName (value), FcTypeName (type)); + } +} + +static void +FcTypecheckExpr (FcConfigParse *parse, FcExpr *expr, FcType type) +{ + const FcObjectType *o; + const FcConstant *c; + + /* If parsing the expression failed, some nodes may be NULL */ + if (!expr) + return; + + switch (expr->op) { + case FcOpInteger: + case FcOpDouble: + FcTypecheckValue (parse, FcTypeDouble, type); + break; + case FcOpString: + FcTypecheckValue (parse, FcTypeString, type); + break; + case FcOpMatrix: + FcTypecheckValue (parse, FcTypeMatrix, type); + break; + case FcOpBool: + FcTypecheckValue (parse, FcTypeBool, type); + break; + case FcOpCharSet: + FcTypecheckValue (parse, FcTypeCharSet, type); + break; + case FcOpLangSet: + FcTypecheckValue (parse, FcTypeLangSet, type); + break; + case FcOpNil: + break; + case FcOpField: + o = FcNameGetObjectType (FcObjectName (expr->u.object)); + if (o) + FcTypecheckValue (parse, o->type, type); + break; + case FcOpConst: + c = FcNameGetConstant (expr->u.constant); + if (c) + { + o = FcNameGetObjectType (c->object); + if (o) + FcTypecheckValue (parse, o->type, type); + } + else + FcConfigMessage (parse, FcSevereWarning, + "invalid constant used : %s", + expr->u.constant); + break; + case FcOpQuest: + FcTypecheckExpr (parse, expr->u.tree.left, FcTypeBool); + FcTypecheckExpr (parse, expr->u.tree.right->u.tree.left, type); + FcTypecheckExpr (parse, expr->u.tree.right->u.tree.right, type); + break; + case FcOpAssign: + case FcOpAssignReplace: + break; + case FcOpEqual: + case FcOpNotEqual: + case FcOpLess: + case FcOpLessEqual: + case FcOpMore: + case FcOpMoreEqual: + case FcOpContains: + case FcOpNotContains: + case FcOpListing: + FcTypecheckValue (parse, FcTypeBool, type); + break; + case FcOpComma: + case FcOpOr: + case FcOpAnd: + case FcOpPlus: + case FcOpMinus: + case FcOpTimes: + case FcOpDivide: + FcTypecheckExpr (parse, expr->u.tree.left, type); + FcTypecheckExpr (parse, expr->u.tree.right, type); + break; + case FcOpNot: + FcTypecheckValue (parse, FcTypeBool, type); + FcTypecheckExpr (parse, expr->u.tree.left, FcTypeBool); + break; + case FcOpFloor: + case FcOpCeil: + case FcOpRound: + case FcOpTrunc: + FcTypecheckValue (parse, FcTypeDouble, type); + FcTypecheckExpr (parse, expr->u.tree.left, FcTypeDouble); + break; + default: + break; + } +} + +static FcTest * +FcTestCreate (FcConfigParse *parse, + FcMatchKind kind, + FcQual qual, + const FcChar8 *field, + FcOp compare, + FcExpr *expr) +{ + FcTest *test = (FcTest *) malloc (sizeof (FcTest)); + + if (test) + { + const FcObjectType *o; + + FcMemAlloc (FC_MEM_TEST, sizeof (FcTest)); + test->next = 0; + test->kind = kind; + test->qual = qual; + test->object = FcObjectFromName ((const char *) field); + test->op = compare; + test->expr = expr; + o = FcNameGetObjectType (FcObjectName (test->object)); + if (o) + FcTypecheckExpr (parse, expr, o->type); + } + return test; +} + +static FcEdit * +FcEditCreate (FcConfigParse *parse, + FcObject object, + FcOp op, + FcExpr *expr, + FcValueBinding binding) +{ + FcEdit *e = (FcEdit *) malloc (sizeof (FcEdit)); + + if (e) + { + const FcObjectType *o; + + e->next = 0; + e->object = object; + e->op = op; + e->expr = expr; + e->binding = binding; + o = FcNameGetObjectType (FcObjectName (e->object)); + if (o) + FcTypecheckExpr (parse, expr, o->type); + } + return e; +} + +static FcVStack * +FcVStackCreateAndPush (FcConfigParse *parse) +{ + FcVStack *new; + + if (parse->vstack_static_used < sizeof (parse->vstack_static) / sizeof (parse->vstack_static[0])) + new = &parse->vstack_static[parse->vstack_static_used++]; + else + { + new = malloc (sizeof (FcVStack)); + if (!new) + return 0; + FcMemAlloc (FC_MEM_VSTACK, sizeof (FcVStack)); + } + new->tag = FcVStackNone; + new->prev = 0; + + new->prev = parse->vstack; + new->pstack = parse->pstack ? parse->pstack->prev : 0; + parse->vstack = new; + + return new; +} + +static FcBool +FcVStackPushString (FcConfigParse *parse, FcVStackTag tag, FcChar8 *string) +{ + FcVStack *vstack = FcVStackCreateAndPush (parse); + if (!vstack) + return FcFalse; + vstack->u.string = string; + vstack->tag = tag; + return FcTrue; +} + +static FcBool +FcVStackPushInteger (FcConfigParse *parse, int integer) +{ + FcVStack *vstack = FcVStackCreateAndPush (parse); + if (!vstack) + return FcFalse; + vstack->u.integer = integer; + vstack->tag = FcVStackInteger; + return FcTrue; +} + +static FcBool +FcVStackPushDouble (FcConfigParse *parse, double _double) +{ + FcVStack *vstack = FcVStackCreateAndPush (parse); + if (!vstack) + return FcFalse; + vstack->u._double = _double; + vstack->tag = FcVStackDouble; + return FcTrue; +} + +static FcBool +FcVStackPushMatrix (FcConfigParse *parse, FcMatrix *matrix) +{ + FcVStack *vstack; + matrix = FcMatrixCopy (matrix); + if (!matrix) + return FcFalse; + vstack = FcVStackCreateAndPush (parse); + if (!vstack) + return FcFalse; + vstack->u.matrix = matrix; + vstack->tag = FcVStackMatrix; + return FcTrue; +} + +static FcBool +FcVStackPushRange (FcConfigParse *parse, FcRange *range) +{ + FcVStack *vstack = FcVStackCreateAndPush (parse); + if (!vstack) + return FcFalse; + vstack->u.range.begin = range->begin; + vstack->u.range.end = range->end; + vstack->tag = FcVStackRange; + return FcTrue; +} + +static FcBool +FcVStackPushBool (FcConfigParse *parse, FcBool bool_) +{ + FcVStack *vstack = FcVStackCreateAndPush (parse); + if (!vstack) + return FcFalse; + vstack->u.bool_ = bool_; + vstack->tag = FcVStackBool; + return FcTrue; +} + +static FcBool +FcVStackPushCharSet (FcConfigParse *parse, FcCharSet *charset) +{ + FcVStack *vstack; + if (!charset) + return FcFalse; + vstack = FcVStackCreateAndPush (parse); + if (!vstack) + return FcFalse; + vstack->u.charset = charset; + vstack->tag = FcVStackCharSet; + return FcTrue; +} + +static FcBool +FcVStackPushLangSet (FcConfigParse *parse, FcLangSet *langset) +{ + FcVStack *vstack; + if (!langset) + return FcFalse; + vstack = FcVStackCreateAndPush (parse); + if (!vstack) + return FcFalse; + vstack->u.langset = langset; + vstack->tag = FcVStackLangSet; + return FcTrue; +} + +static FcBool +FcVStackPushTest (FcConfigParse *parse, FcTest *test) +{ + FcVStack *vstack = FcVStackCreateAndPush (parse); + if (!vstack) + return FcFalse; + vstack->u.test = test; + vstack->tag = FcVStackTest; + return FcTrue; +} + +static FcBool +FcVStackPushExpr (FcConfigParse *parse, FcVStackTag tag, FcExpr *expr) +{ + FcVStack *vstack = FcVStackCreateAndPush (parse); + if (!vstack) + return FcFalse; + vstack->u.expr = expr; + vstack->tag = tag; + return FcTrue; +} + +static FcBool +FcVStackPushEdit (FcConfigParse *parse, FcEdit *edit) +{ + FcVStack *vstack = FcVStackCreateAndPush (parse); + if (!vstack) + return FcFalse; + vstack->u.edit = edit; + vstack->tag = FcVStackEdit; + return FcTrue; +} + +static FcBool +FcVStackPushPattern (FcConfigParse *parse, FcPattern *pattern) +{ + FcVStack *vstack = FcVStackCreateAndPush (parse); + if (!vstack) + return FcFalse; + vstack->u.pattern = pattern; + vstack->tag = FcVStackPattern; + return FcTrue; +} + +static FcVStack * +FcVStackFetch (FcConfigParse *parse, int off) +{ + FcVStack *vstack; + + for (vstack = parse->vstack; vstack && off-- > 0; vstack = vstack->prev); + return vstack; +} + +static FcVStack * +FcVStackPeek (FcConfigParse *parse) +{ + FcVStack *vstack = parse->vstack; + + return vstack && vstack->pstack == parse->pstack ? vstack : 0; +} + +static void +FcVStackPopAndDestroy (FcConfigParse *parse) +{ + FcVStack *vstack = parse->vstack; + + if (!vstack || vstack->pstack != parse->pstack) + return; + + parse->vstack = vstack->prev; + + switch (vstack->tag) { + case FcVStackNone: + break; + case FcVStackFamily: + break; + case FcVStackString: + case FcVStackField: + case FcVStackConstant: + case FcVStackGlob: + FcStrFree (vstack->u.string); + break; + case FcVStackPattern: + FcPatternDestroy (vstack->u.pattern); + break; + case FcVStackInteger: + case FcVStackDouble: + break; + case FcVStackMatrix: + FcMatrixFree (vstack->u.matrix); + break; + case FcVStackRange: + case FcVStackBool: + break; + case FcVStackCharSet: + FcCharSetDestroy (vstack->u.charset); + break; + case FcVStackLangSet: + FcLangSetDestroy (vstack->u.langset); + break; + case FcVStackTest: + FcTestDestroy (vstack->u.test); + break; + case FcVStackExpr: + case FcVStackPrefer: + case FcVStackAccept: + case FcVStackDefault: + FcExprDestroy (vstack->u.expr); + break; + case FcVStackEdit: + FcEditDestroy (vstack->u.edit); + break; + } + + if (vstack == &parse->vstack_static[parse->vstack_static_used - 1]) + parse->vstack_static_used--; + else + { + FcMemFree (FC_MEM_VSTACK, sizeof (FcVStack)); + free (vstack); + } +} + +static void +FcVStackClear (FcConfigParse *parse) +{ + while (FcVStackPeek (parse)) + FcVStackPopAndDestroy (parse); +} + +static int +FcVStackElements (FcConfigParse *parse) +{ + int h = 0; + FcVStack *vstack = parse->vstack; + while (vstack && vstack->pstack == parse->pstack) + { + h++; + vstack = vstack->prev; + } + return h; +} + +static FcChar8 ** +FcConfigSaveAttr (const XML_Char **attr, FcChar8 **buf, int size_bytes) +{ + int slen; + int i; + FcChar8 **new; + FcChar8 *s; + + if (!attr) + return 0; + slen = 0; + for (i = 0; attr[i]; i++) + slen += strlen ((char *) attr[i]) + 1; + if (i == 0) + return 0; + slen += (i + 1) * sizeof (FcChar8 *); + if (slen <= size_bytes) + new = buf; + else + { + new = malloc (slen); + if (!new) + { + FcConfigMessage (0, FcSevereError, "out of memory"); + return 0; + } + FcMemAlloc (FC_MEM_ATTR, 1); /* size is too expensive */ + } + s = (FcChar8 *) (new + (i + 1)); + for (i = 0; attr[i]; i++) + { + new[i] = s; + strcpy ((char *) s, (char *) attr[i]); + s += strlen ((char *) s) + 1; + } + new[i] = 0; + return new; +} + +static FcBool +FcPStackPush (FcConfigParse *parse, FcElement element, const XML_Char **attr) +{ + FcPStack *new; + + if (parse->pstack_static_used < sizeof (parse->pstack_static) / sizeof (parse->pstack_static[0])) + new = &parse->pstack_static[parse->pstack_static_used++]; + else + { + new = malloc (sizeof (FcPStack)); + if (!new) + return FcFalse; + FcMemAlloc (FC_MEM_PSTACK, sizeof (FcPStack)); + } + + new->prev = parse->pstack; + new->element = element; + new->attr = FcConfigSaveAttr (attr, new->attr_buf_static, sizeof (new->attr_buf_static)); + FcStrBufInit (&new->str, 0, 0); + parse->pstack = new; + return FcTrue; +} + +static FcBool +FcPStackPop (FcConfigParse *parse) +{ + FcPStack *old; + + if (!parse->pstack) + { + FcConfigMessage (parse, FcSevereError, "mismatching element"); + return FcFalse; + } + FcVStackClear (parse); + old = parse->pstack; + parse->pstack = old->prev; + FcStrBufDestroy (&old->str); + if (old->attr && old->attr != old->attr_buf_static) + { + FcMemFree (FC_MEM_ATTR, 1); /* size is to expensive */ + free (old->attr); + } + + if (old == &parse->pstack_static[parse->pstack_static_used - 1]) + parse->pstack_static_used--; + else + { + FcMemFree (FC_MEM_PSTACK, sizeof (FcPStack)); + free (old); + } + return FcTrue; +} + +static FcBool +FcConfigInit (FcConfigParse *parse, const FcChar8 *name, FcConfig *config, XML_Parser parser) +{ + parse->pstack = 0; + parse->pstack_static_used = 0; + parse->vstack = 0; + parse->vstack_static_used = 0; + parse->error = FcFalse; + parse->name = name; + parse->config = config; + parse->parser = parser; + return FcTrue; +} + +static void +FcConfigCleanup (FcConfigParse *parse) +{ + while (parse->pstack) + FcPStackPop (parse); +} + +static const FcChar8 * +FcConfigGetAttribute (FcConfigParse *parse, const char *attr) +{ + FcChar8 **attrs; + if (!parse->pstack) + return 0; + + attrs = parse->pstack->attr; + if (!attrs) + return 0; + + while (*attrs) + { + if (!strcmp ((char *) *attrs, attr)) + return attrs[1]; + attrs += 2; + } + return 0; +} + +static void +FcStartElement(void *userData, const XML_Char *name, const XML_Char **attr) +{ + FcConfigParse *parse = userData; + FcElement element; + + element = FcElementMap (name); + if (element == FcElementUnknown) + FcConfigMessage (parse, FcSevereWarning, "unknown element \"%s\"", name); + + if (!FcPStackPush (parse, element, attr)) + { + FcConfigMessage (parse, FcSevereError, "out of memory"); + return; + } + return; +} + +static void +FcParseBlank (FcConfigParse *parse) +{ + int n = FcVStackElements (parse); + FcChar32 i; + while (n-- > 0) + { + FcVStack *v = FcVStackFetch (parse, n); + if (!parse->config->blanks) + { + parse->config->blanks = FcBlanksCreate (); + if (!parse->config->blanks) + goto bail; + } + switch (v->tag) { + case FcVStackInteger: + if (!FcBlanksAdd (parse->config->blanks, v->u.integer)) + goto bail; + break; + case FcVStackRange: + if (v->u.range.begin <= v->u.range.end) + { + for (i = v->u.range.begin; i <= v->u.range.end; i++) + { + if (!FcBlanksAdd (parse->config->blanks, i)) + goto bail; + } + } + break; + default: + FcConfigMessage (parse, FcSevereError, "invalid element in blank"); + break; + } + } + return; + bail: + FcConfigMessage (parse, FcSevereError, "out of memory"); +} + +static void +FcParseRescan (FcConfigParse *parse) +{ + int n = FcVStackElements (parse); + while (n-- > 0) + { + FcVStack *v = FcVStackFetch (parse, n); + if (v->tag != FcVStackInteger) + FcConfigMessage (parse, FcSevereWarning, "non-integer rescan"); + else + parse->config->rescanInterval = v->u.integer; + } +} + +static void +FcParseInt (FcConfigParse *parse) +{ + FcChar8 *s, *end; + int l; + + if (!parse->pstack) + return; + s = FcStrBufDoneStatic (&parse->pstack->str); + if (!s) + { + FcConfigMessage (parse, FcSevereError, "out of memory"); + return; + } + end = 0; + l = (int) strtol ((char *) s, (char **)&end, 0); + if (end != s + strlen ((char *) s)) + FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid integer", s); + else + FcVStackPushInteger (parse, l); + FcStrBufDestroy (&parse->pstack->str); +} + +/* + * idea copied from glib g_ascii_strtod with + * permission of the author (Alexander Larsson) + */ + +#include + +static double +FcStrtod (char *s, char **end) +{ + struct lconv *locale_data; + char *dot; + double v; + + /* + * Have to swap the decimal point to match the current locale + * if that locale doesn't use 0x2e + */ + if ((dot = strchr (s, 0x2e)) && + (locale_data = localeconv ()) && + (locale_data->decimal_point[0] != 0x2e || + locale_data->decimal_point[1] != 0)) + { + char buf[128]; + int slen = strlen (s); + int dlen = strlen (locale_data->decimal_point); + + if (slen + dlen > (int) sizeof (buf)) + { + if (end) + *end = s; + v = 0; + } + else + { + char *buf_end; + /* mantissa */ + strncpy (buf, s, dot - s); + /* decimal point */ + strcpy (buf + (dot - s), locale_data->decimal_point); + /* rest of number */ + strcpy (buf + (dot - s) + dlen, dot + 1); + buf_end = 0; + v = strtod (buf, &buf_end); + if (buf_end) { + buf_end = s + (buf_end - buf); + if (buf_end > dot) + buf_end -= dlen - 1; + } + if (end) + *end = buf_end; + } + } + else + v = strtod (s, end); + return v; +} + +static void +FcParseDouble (FcConfigParse *parse) +{ + FcChar8 *s, *end; + double d; + + if (!parse->pstack) + return; + s = FcStrBufDoneStatic (&parse->pstack->str); + if (!s) + { + FcConfigMessage (parse, FcSevereError, "out of memory"); + return; + } + end = 0; + d = FcStrtod ((char *) s, (char **)&end); + if (end != s + strlen ((char *) s)) + FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid double", s); + else + FcVStackPushDouble (parse, d); + FcStrBufDestroy (&parse->pstack->str); +} + +static void +FcParseString (FcConfigParse *parse, FcVStackTag tag) +{ + FcChar8 *s; + + if (!parse->pstack) + return; + s = FcStrBufDone (&parse->pstack->str); + if (!s) + { + FcConfigMessage (parse, FcSevereError, "out of memory"); + return; + } + if (!FcVStackPushString (parse, tag, s)) + FcStrFree (s); +} + +static void +FcParseMatrix (FcConfigParse *parse) +{ + FcVStack *vstack; + enum { m_done, m_xx, m_xy, m_yx, m_yy } matrix_state = m_yy; + FcMatrix m; + + while ((vstack = FcVStackPeek (parse))) + { + double v; + switch (vstack->tag) { + case FcVStackInteger: + v = vstack->u.integer; + break; + case FcVStackDouble: + v = vstack->u._double; + break; + default: + FcConfigMessage (parse, FcSevereError, "non-double matrix element"); + v = 1.0; + break; + } + switch (matrix_state) { + case m_xx: m.xx = v; break; + case m_xy: m.xy = v; break; + case m_yx: m.yx = v; break; + case m_yy: m.yy = v; break; + default: break; + } + FcVStackPopAndDestroy (parse); + matrix_state--; + } + if (matrix_state != m_done) + FcConfigMessage (parse, FcSevereError, "wrong number of matrix elements"); + else + FcVStackPushMatrix (parse, &m); +} + +static void +FcParseRange (FcConfigParse *parse) +{ + FcVStack *vstack; + FcRange r; + FcChar32 n; + int count = 1; + + while ((vstack = FcVStackPeek (parse))) + { + if (count < 0) + { + FcConfigMessage (parse, FcSevereError, "too many elements in range"); + return; + } + switch (vstack->tag) { + case FcVStackInteger: + n = vstack->u.integer; + break; + default: + FcConfigMessage (parse, FcSevereError, "invalid element in range"); + break; + } + if (count == 1) + r.end = n; + else + r.begin = n; + count--; + FcVStackPopAndDestroy (parse); + } + if (count < 0) + { + if (r.begin > r.end) + { + FcConfigMessage (parse, FcSevereError, "invalid range"); + return; + } + FcVStackPushRange (parse, &r); + } + else + FcConfigMessage (parse, FcSevereError, "invalid range"); +} + +static FcBool +FcConfigLexBool (FcConfigParse *parse, const FcChar8 *bool_) +{ + FcBool result = FcFalse; + + if (!FcNameBool (bool_, &result)) + FcConfigMessage (parse, FcSevereWarning, "\"%s\" is not known boolean", + bool_); + return result; +} + +static void +FcParseBool (FcConfigParse *parse) +{ + FcChar8 *s; + + if (!parse->pstack) + return; + s = FcStrBufDoneStatic (&parse->pstack->str); + if (!s) + { + FcConfigMessage (parse, FcSevereError, "out of memory"); + return; + } + FcVStackPushBool (parse, FcConfigLexBool (parse, s)); + FcStrBufDestroy (&parse->pstack->str); +} + +static void +FcParseCharSet (FcConfigParse *parse) +{ + FcVStack *vstack; + FcCharSet *charset = FcCharSetCreate (); + FcChar32 i; + int n = 0; + + while ((vstack = FcVStackPeek (parse))) + { + switch (vstack->tag) { + case FcVStackInteger: + if (!FcCharSetAddChar (charset, vstack->u.integer)) + { + FcConfigMessage (parse, FcSevereWarning, "invalid character: 0x%04x", vstack->u.integer); + } + else + n++; + break; + case FcVStackRange: + if (vstack->u.range.begin <= vstack->u.range.end) + { + for (i = vstack->u.range.begin; i <= vstack->u.range.end; i++) + { + if (!FcCharSetAddChar (charset, i)) + { + FcConfigMessage (parse, FcSevereWarning, "invalid character: 0x%04x", i); + } + else + n++; + } + } + break; + default: + FcConfigMessage (parse, FcSevereError, "invalid element in charset"); + break; + } + FcVStackPopAndDestroy (parse); + } + if (n > 0) + FcVStackPushCharSet (parse, charset); + else + FcCharSetDestroy (charset); +} + +static void +FcParseLangSet (FcConfigParse *parse) +{ + FcVStack *vstack; + FcLangSet *langset = FcLangSetCreate (); + int n = 0; + + while ((vstack = FcVStackPeek (parse))) + { + switch (vstack->tag) { + case FcVStackString: + if (!FcLangSetAdd (langset, vstack->u.string)) + { + FcConfigMessage (parse, FcSevereWarning, "invalid langset: %s", vstack->u.string); + } + else + n++; + break; + default: + FcConfigMessage (parse, FcSevereError, "invalid element in langset"); + break; + } + FcVStackPopAndDestroy (parse); + } + if (n > 0) + FcVStackPushLangSet (parse, langset); + else + FcLangSetDestroy (langset); +} + +static FcBool +FcConfigLexBinding (FcConfigParse *parse, + const FcChar8 *binding_string, + FcValueBinding *binding_ret) +{ + FcValueBinding binding; + + if (!binding_string) + binding = FcValueBindingWeak; + else + { + if (!strcmp ((char *) binding_string, "weak")) + binding = FcValueBindingWeak; + else if (!strcmp ((char *) binding_string, "strong")) + binding = FcValueBindingStrong; + else if (!strcmp ((char *) binding_string, "same")) + binding = FcValueBindingSame; + else + { + FcConfigMessage (parse, FcSevereWarning, "invalid binding \"%s\"", binding_string); + return FcFalse; + } + } + *binding_ret = binding; + return FcTrue; +} + +static void +FcParseFamilies (FcConfigParse *parse, FcVStackTag tag) +{ + FcVStack *vstack; + FcExpr *left, *expr = 0, *new; + + while ((vstack = FcVStackPeek (parse))) + { + if (vstack->tag != FcVStackFamily) + { + FcConfigMessage (parse, FcSevereWarning, "non-family"); + FcVStackPopAndDestroy (parse); + continue; + } + left = vstack->u.expr; + vstack->tag = FcVStackNone; + FcVStackPopAndDestroy (parse); + if (expr) + { + new = FcExprCreateOp (parse->config, left, FcOpComma, expr); + if (!new) + { + FcConfigMessage (parse, FcSevereError, "out of memory"); + FcExprDestroy (left); + FcExprDestroy (expr); + break; + } + expr = new; + } + else + expr = left; + } + if (expr) + { + if (!FcVStackPushExpr (parse, tag, expr)) + { + FcConfigMessage (parse, FcSevereError, "out of memory"); + FcExprDestroy (expr); + } + } +} + +static void +FcParseFamily (FcConfigParse *parse) +{ + FcChar8 *s; + FcExpr *expr; + + if (!parse->pstack) + return; + s = FcStrBufDoneStatic (&parse->pstack->str); + if (!s) + { + FcConfigMessage (parse, FcSevereError, "out of memory"); + return; + } + expr = FcExprCreateString (parse->config, s); + FcStrBufDestroy (&parse->pstack->str); + if (expr) + FcVStackPushExpr (parse, FcVStackFamily, expr); +} + +static void +FcParseAlias (FcConfigParse *parse) +{ + FcExpr *family = 0, *accept = 0, *prefer = 0, *def = 0, *new = 0; + FcEdit *edit = 0, *next; + FcVStack *vstack; + FcTest *test; + FcValueBinding binding; + + if (!FcConfigLexBinding (parse, FcConfigGetAttribute (parse, "binding"), &binding)) + return; + while ((vstack = FcVStackPeek (parse))) + { + switch (vstack->tag) { + case FcVStackFamily: + if (family) + { + new = FcExprCreateOp (parse->config, vstack->u.expr, FcOpComma, family); + if (!new) + FcConfigMessage (parse, FcSevereError, "out of memory"); + else + family = new; + } + else + new = vstack->u.expr; + if (new) + { + family = new; + vstack->tag = FcVStackNone; + } + break; + case FcVStackPrefer: + if (prefer) + FcExprDestroy (prefer); + prefer = vstack->u.expr; + vstack->tag = FcVStackNone; + break; + case FcVStackAccept: + if (accept) + FcExprDestroy (accept); + accept = vstack->u.expr; + vstack->tag = FcVStackNone; + break; + case FcVStackDefault: + if (def) + FcExprDestroy (def); + def = vstack->u.expr; + vstack->tag = FcVStackNone; + break; + default: + FcConfigMessage (parse, FcSevereWarning, "bad alias"); + break; + } + FcVStackPopAndDestroy (parse); + } + if (!family) + { + FcConfigMessage (parse, FcSevereError, "missing family in alias"); + if (prefer) + FcExprDestroy (prefer); + if (accept) + FcExprDestroy (accept); + if (def) + FcExprDestroy (def); + return; + } + if (prefer) + { + edit = FcEditCreate (parse, + FC_FAMILY_OBJECT, + FcOpPrepend, + prefer, + binding); + if (edit) + edit->next = 0; + else + FcExprDestroy (prefer); + } + if (accept) + { + next = edit; + edit = FcEditCreate (parse, + FC_FAMILY_OBJECT, + FcOpAppend, + accept, + binding); + if (edit) + edit->next = next; + else + FcExprDestroy (accept); + } + if (def) + { + next = edit; + edit = FcEditCreate (parse, + FC_FAMILY_OBJECT, + FcOpAppendLast, + def, + binding); + if (edit) + edit->next = next; + else + FcExprDestroy (def); + } + if (edit) + { + test = FcTestCreate (parse, FcMatchPattern, + FcQualAny, + (FcChar8 *) FC_FAMILY, + FcOpEqual, + family); + if (test) + if (!FcConfigAddEdit (parse->config, test, edit, FcMatchPattern)) + FcTestDestroy (test); + } + else + FcExprDestroy (family); +} + +static FcExpr * +FcPopExpr (FcConfigParse *parse) +{ + FcVStack *vstack = FcVStackPeek (parse); + FcExpr *expr = 0; + if (!vstack) + return 0; + switch (vstack->tag) { + case FcVStackNone: + break; + case FcVStackString: + case FcVStackFamily: + expr = FcExprCreateString (parse->config, vstack->u.string); + break; + case FcVStackField: + expr = FcExprCreateField (parse->config, (char *) vstack->u.string); + break; + case FcVStackConstant: + expr = FcExprCreateConst (parse->config, vstack->u.string); + break; + case FcVStackGlob: + /* XXX: What's the correct action here? (CDW) */ + break; + case FcVStackPrefer: + case FcVStackAccept: + case FcVStackDefault: + expr = vstack->u.expr; + vstack->tag = FcVStackNone; + break; + case FcVStackInteger: + expr = FcExprCreateInteger (parse->config, vstack->u.integer); + break; + case FcVStackDouble: + expr = FcExprCreateDouble (parse->config, vstack->u._double); + break; + case FcVStackMatrix: + expr = FcExprCreateMatrix (parse->config, vstack->u.matrix); + break; + case FcVStackRange: + break; + case FcVStackBool: + expr = FcExprCreateBool (parse->config, vstack->u.bool_); + break; + case FcVStackCharSet: + expr = FcExprCreateCharSet (parse->config, vstack->u.charset); + break; + case FcVStackLangSet: + expr = FcExprCreateLangSet (parse->config, vstack->u.langset); + break; + case FcVStackTest: + break; + case FcVStackExpr: + expr = vstack->u.expr; + vstack->tag = FcVStackNone; + break; + case FcVStackEdit: + break; + default: + break; + } + FcVStackPopAndDestroy (parse); + return expr; +} + +/* + * This builds a tree of binary operations. Note + * that every operator is defined so that if only + * a single operand is contained, the value of the + * whole expression is the value of the operand. + * + * This code reduces in that case to returning that + * operand. + */ +static FcExpr * +FcPopBinary (FcConfigParse *parse, FcOp op) +{ + FcExpr *left, *expr = 0, *new; + + while ((left = FcPopExpr (parse))) + { + if (expr) + { + new = FcExprCreateOp (parse->config, left, op, expr); + if (!new) + { + FcConfigMessage (parse, FcSevereError, "out of memory"); + FcExprDestroy (left); + FcExprDestroy (expr); + return 0; + } + expr = new; + } + else + expr = left; + } + return expr; +} + +static void +FcParseBinary (FcConfigParse *parse, FcOp op) +{ + FcExpr *expr = FcPopBinary (parse, op); + if (expr) + FcVStackPushExpr (parse, FcVStackExpr, expr); +} + +/* + * This builds a a unary operator, it consumes only + * a single operand + */ + +static FcExpr * +FcPopUnary (FcConfigParse *parse, FcOp op) +{ + FcExpr *operand, *new = 0; + + if ((operand = FcPopExpr (parse))) + { + new = FcExprCreateOp (parse->config, operand, op, 0); + if (!new) + { + FcExprDestroy (operand); + FcConfigMessage (parse, FcSevereError, "out of memory"); + } + } + return new; +} + +static void +FcParseUnary (FcConfigParse *parse, FcOp op) +{ + FcExpr *expr = FcPopUnary (parse, op); + if (expr) + FcVStackPushExpr (parse, FcVStackExpr, expr); +} + +static void +FcParseInclude (FcConfigParse *parse) +{ + FcChar8 *s; + const FcChar8 *i; + FcBool ignore_missing = FcFalse; + + s = FcStrBufDoneStatic (&parse->pstack->str); + if (!s) + { + FcConfigMessage (parse, FcSevereError, "out of memory"); + return; + } + i = FcConfigGetAttribute (parse, "ignore_missing"); + if (i && FcConfigLexBool (parse, (FcChar8 *) i) == FcTrue) + ignore_missing = FcTrue; + if (!FcConfigParseAndLoad (parse->config, s, !ignore_missing)) + parse->error = FcTrue; + FcStrBufDestroy (&parse->pstack->str); +} + +typedef struct _FcOpMap { + char name[16]; + FcOp op; +} FcOpMap; + +static FcOp +FcConfigLexOp (const FcChar8 *op, const FcOpMap *map, int nmap) +{ + int i; + + for (i = 0; i < nmap; i++) + if (!strcmp ((char *) op, map[i].name)) + return map[i].op; + return FcOpInvalid; +} + +static const FcOpMap fcCompareOps[] = { + { "eq", FcOpEqual }, + { "not_eq", FcOpNotEqual }, + { "less", FcOpLess }, + { "less_eq", FcOpLessEqual }, + { "more", FcOpMore }, + { "more_eq", FcOpMoreEqual }, + { "contains", FcOpContains }, + { "not_contains", FcOpNotContains } +}; + +#define NUM_COMPARE_OPS (int) (sizeof fcCompareOps / sizeof fcCompareOps[0]) + +static FcOp +FcConfigLexCompare (const FcChar8 *compare) +{ + return FcConfigLexOp (compare, fcCompareOps, NUM_COMPARE_OPS); +} + +static void +FcParseTest (FcConfigParse *parse) +{ + const FcChar8 *kind_string; + FcMatchKind kind; + const FcChar8 *qual_string; + FcQual qual; + const FcChar8 *name; + const FcChar8 *compare_string; + FcOp compare; + FcExpr *expr; + FcTest *test; + + kind_string = FcConfigGetAttribute (parse, "target"); + if (!kind_string) + kind = FcMatchDefault; + else + { + if (!strcmp ((char *) kind_string, "pattern")) + kind = FcMatchPattern; + else if (!strcmp ((char *) kind_string, "font")) + kind = FcMatchFont; + else if (!strcmp ((char *) kind_string, "scan")) + kind = FcMatchScan; + else if (!strcmp ((char *) kind_string, "default")) + kind = FcMatchDefault; + else + { + FcConfigMessage (parse, FcSevereWarning, "invalid test target \"%s\"", kind_string); + return; + } + } + qual_string = FcConfigGetAttribute (parse, "qual"); + if (!qual_string) + qual = FcQualAny; + else + { + if (!strcmp ((char *) qual_string, "any")) + qual = FcQualAny; + else if (!strcmp ((char *) qual_string, "all")) + qual = FcQualAll; + else if (!strcmp ((char *) qual_string, "first")) + qual = FcQualFirst; + else if (!strcmp ((char *) qual_string, "not_first")) + qual = FcQualNotFirst; + else + { + FcConfigMessage (parse, FcSevereWarning, "invalid test qual \"%s\"", qual_string); + return; + } + } + name = FcConfigGetAttribute (parse, "name"); + if (!name) + { + FcConfigMessage (parse, FcSevereWarning, "missing test name"); + return; + } + compare_string = FcConfigGetAttribute (parse, "compare"); + if (!compare_string) + compare = FcOpEqual; + else + { + compare = FcConfigLexCompare (compare_string); + if (compare == FcOpInvalid) + { + FcConfigMessage (parse, FcSevereWarning, "invalid test compare \"%s\"", compare_string); + return; + } + } + expr = FcPopBinary (parse, FcOpComma); + if (!expr) + { + FcConfigMessage (parse, FcSevereWarning, "missing test expression"); + return; + } + test = FcTestCreate (parse, kind, qual, name, compare, expr); + if (!test) + { + FcConfigMessage (parse, FcSevereError, "out of memory"); + return; + } + FcVStackPushTest (parse, test); +} + +static const FcOpMap fcModeOps[] = { + { "assign", FcOpAssign }, + { "assign_replace", FcOpAssignReplace }, + { "prepend", FcOpPrepend }, + { "prepend_first", FcOpPrependFirst }, + { "append", FcOpAppend }, + { "append_last", FcOpAppendLast }, +}; + +#define NUM_MODE_OPS (int) (sizeof fcModeOps / sizeof fcModeOps[0]) + +static FcOp +FcConfigLexMode (const FcChar8 *mode) +{ + return FcConfigLexOp (mode, fcModeOps, NUM_MODE_OPS); +} + +static void +FcParseEdit (FcConfigParse *parse) +{ + const FcChar8 *name; + const FcChar8 *mode_string; + FcOp mode; + FcValueBinding binding; + FcExpr *expr; + FcEdit *edit; + + name = FcConfigGetAttribute (parse, "name"); + if (!name) + { + FcConfigMessage (parse, FcSevereWarning, "missing edit name"); + return; + } + mode_string = FcConfigGetAttribute (parse, "mode"); + if (!mode_string) + mode = FcOpAssign; + else + { + mode = FcConfigLexMode (mode_string); + if (mode == FcOpInvalid) + { + FcConfigMessage (parse, FcSevereWarning, "invalid edit mode \"%s\"", mode_string); + return; + } + } + if (!FcConfigLexBinding (parse, FcConfigGetAttribute (parse, "binding"), &binding)) + return; + + expr = FcPopBinary (parse, FcOpComma); + edit = FcEditCreate (parse, FcObjectFromName ((char *) name), + mode, expr, binding); + if (!edit) + { + FcConfigMessage (parse, FcSevereError, "out of memory"); + FcExprDestroy (expr); + return; + } + if (!FcVStackPushEdit (parse, edit)) + FcEditDestroy (edit); +} + +static void +FcParseMatch (FcConfigParse *parse) +{ + const FcChar8 *kind_name; + FcMatchKind kind; + FcTest *test = 0; + FcEdit *edit = 0; + FcVStack *vstack; + + kind_name = FcConfigGetAttribute (parse, "target"); + if (!kind_name) + kind = FcMatchPattern; + else + { + if (!strcmp ((char *) kind_name, "pattern")) + kind = FcMatchPattern; + else if (!strcmp ((char *) kind_name, "font")) + kind = FcMatchFont; + else if (!strcmp ((char *) kind_name, "scan")) + kind = FcMatchScan; + else + { + FcConfigMessage (parse, FcSevereWarning, "invalid match target \"%s\"", kind_name); + return; + } + } + while ((vstack = FcVStackPeek (parse))) + { + switch (vstack->tag) { + case FcVStackTest: + vstack->u.test->next = test; + test = vstack->u.test; + vstack->tag = FcVStackNone; + break; + case FcVStackEdit: + vstack->u.edit->next = edit; + edit = vstack->u.edit; + vstack->tag = FcVStackNone; + if (kind == FcMatchScan && edit->object > FC_MAX_BASE_OBJECT) + { + FcConfigMessage (parse, FcSevereError, + " cannot edit user-defined object \"%s\"", + FcObjectName(edit->object)); + } + break; + default: + FcConfigMessage (parse, FcSevereWarning, "invalid match element"); + break; + } + FcVStackPopAndDestroy (parse); + } + if (!FcConfigAddEdit (parse->config, test, edit, kind)) + FcConfigMessage (parse, FcSevereError, "out of memory"); +} + +static void +FcParseAcceptRejectFont (FcConfigParse *parse, FcElement element) +{ + FcVStack *vstack; + + while ((vstack = FcVStackPeek (parse))) + { + switch (vstack->tag) { + case FcVStackGlob: + if (!FcConfigGlobAdd (parse->config, + vstack->u.string, + element == FcElementAcceptfont)) + { + FcConfigMessage (parse, FcSevereError, "out of memory"); + } + break; + case FcVStackPattern: + if (!FcConfigPatternsAdd (parse->config, + vstack->u.pattern, + element == FcElementAcceptfont)) + { + FcConfigMessage (parse, FcSevereError, "out of memory"); + } + else + vstack->tag = FcVStackNone; + break; + default: + FcConfigMessage (parse, FcSevereWarning, "bad font selector"); + break; + } + FcVStackPopAndDestroy (parse); + } +} + + +static FcValue +FcPopValue (FcConfigParse *parse) +{ + FcVStack *vstack = FcVStackPeek (parse); + FcValue value; + + value.type = FcTypeVoid; + + if (!vstack) + return value; + + switch (vstack->tag) { + case FcVStackString: + value.u.s = FcStrStaticName (vstack->u.string); + if (value.u.s) + value.type = FcTypeString; + break; + case FcVStackConstant: + if (FcNameConstant (vstack->u.string, &value.u.i)) + value.type = FcTypeInteger; + break; + case FcVStackInteger: + value.u.i = vstack->u.integer; + value.type = FcTypeInteger; + break; + case FcVStackDouble: + value.u.d = vstack->u._double; + value.type = FcTypeInteger; + break; + case FcVStackMatrix: + value.u.m = FcMatrixCopy (vstack->u.matrix); + if (value.u.m) + value.type = FcTypeMatrix; + break; + case FcVStackBool: + value.u.b = vstack->u.bool_; + value.type = FcTypeBool; + break; + case FcVStackCharSet: + value.u.c = FcCharSetCopy (vstack->u.charset); + if (value.u.c) + value.type = FcTypeCharSet; + break; + case FcVStackLangSet: + value.u.l = FcLangSetCopy (vstack->u.langset); + if (value.u.l) + value.type = FcTypeLangSet; + break; + default: + FcConfigMessage (parse, FcSevereWarning, "unknown pattern element %d", + vstack->tag); + break; + } + FcVStackPopAndDestroy (parse); + + return value; +} + +static void +FcParsePatelt (FcConfigParse *parse) +{ + FcValue value; + FcPattern *pattern = FcPatternCreate (); + const char *name; + + if (!pattern) + { + FcConfigMessage (parse, FcSevereError, "out of memory"); + return; + } + + name = (char *) FcConfigGetAttribute (parse, "name"); + if (!name) + { + FcConfigMessage (parse, FcSevereWarning, "missing pattern element name"); + FcPatternDestroy (pattern); + return; + } + + for (;;) + { + value = FcPopValue (parse); + if (value.type == FcTypeVoid) + break; + if (!FcPatternAdd (pattern, name, value, FcTrue)) + { + FcConfigMessage (parse, FcSevereError, "out of memory"); + FcValueDestroy(value); + break; + } + FcValueDestroy(value); + } + + FcVStackPushPattern (parse, pattern); +} + +static void +FcParsePattern (FcConfigParse *parse) +{ + FcVStack *vstack; + FcPattern *pattern = FcPatternCreate (); + + if (!pattern) + { + FcConfigMessage (parse, FcSevereError, "out of memory"); + return; + } + + while ((vstack = FcVStackPeek (parse))) + { + switch (vstack->tag) { + case FcVStackPattern: + if (!FcPatternAppend (pattern, vstack->u.pattern)) + { + FcConfigMessage (parse, FcSevereError, "out of memory"); + FcPatternDestroy (pattern); + return; + } + break; + default: + FcConfigMessage (parse, FcSevereWarning, "unknown pattern element"); + break; + } + FcVStackPopAndDestroy (parse); + } + + FcVStackPushPattern (parse, pattern); +} + +static void +FcEndElement(void *userData, const XML_Char *name) +{ + FcConfigParse *parse = userData; + FcChar8 *data; +#ifdef _WIN32 + FcChar8 buffer[1000]; +#endif + + if (!parse->pstack) + return; + switch (parse->pstack->element) { + case FcElementNone: + break; + case FcElementFontconfig: + break; + case FcElementDir: + data = FcStrBufDoneStatic (&parse->pstack->str); + if (!data) + { + FcConfigMessage (parse, FcSevereError, "out of memory"); + break; + } +#ifdef _WIN32 + if (strcmp (data, "CUSTOMFONTDIR") == 0) + { + char *p; + data = buffer; + if (!GetModuleFileName (NULL, buffer, sizeof (buffer) - 20)) + { + FcConfigMessage (parse, FcSevereError, "GetModuleFileName failed"); + break; + } + /* + * Must use the multi-byte aware function to search + * for backslash because East Asian double-byte code + * pages have characters with backslash as the second + * byte. + */ + p = _mbsrchr (data, '\\'); + if (p) *p = '\0'; + strcat (data, "\\fonts"); + } + else if (strcmp (data, "APPSHAREFONTDIR") == 0) + { + char *p; + data = buffer; + if (!GetModuleFileName (NULL, buffer, sizeof (buffer) - 20)) + { + FcConfigMessage (parse, FcSevereError, "GetModuleFileName failed"); + break; + } + p = _mbsrchr (data, '\\'); + if (p) *p = '\0'; + strcat (data, "\\..\\share\\fonts"); + } + else if (strcmp (data, "WINDOWSFONTDIR") == 0) + { + int rc; + data = buffer; +#if _WIN32_WINNT >= 0x0500 + rc = GetSystemWindowsDirectory (buffer, sizeof (buffer) - 20); +#else + rc = GetWindowsDirectory (buffer, sizeof (buffer) - 20); +#endif + if (rc == 0 || rc > sizeof (buffer) - 20) + { + FcConfigMessage (parse, FcSevereError, "GetSystemWindowsDirectory failed"); + break; + } + if (data [strlen (data) - 1] != '\\') + strcat (data, "\\"); + strcat (data, "fonts"); + } +#endif + if (strlen ((char *) data) == 0) + FcConfigMessage (parse, FcSevereWarning, "empty font directory name ignored"); + else if (!FcStrUsesHome (data) || FcConfigHome ()) + { + if (!FcConfigAddDir (parse->config, data)) + FcConfigMessage (parse, FcSevereError, "out of memory; cannot add directory %s", data); + } + FcStrBufDestroy (&parse->pstack->str); + break; + case FcElementCacheDir: + data = FcStrBufDone (&parse->pstack->str); + if (!data) + { + FcConfigMessage (parse, FcSevereError, "out of memory"); + break; + } +#ifdef _WIN32 + if (strcmp (data, "WINDOWSTEMPDIR_FONTCONFIG_CACHE") == 0) + { + int rc; + FcStrFree (data); + data = malloc (1000); + if (!data) + { + FcConfigMessage (parse, FcSevereError, "out of memory"); + break; + } + FcMemAlloc (FC_MEM_STRING, 1000); + rc = GetTempPath (800, data); + if (rc == 0 || rc > 800) + { + FcConfigMessage (parse, FcSevereError, "GetTempPath failed"); + FcStrFree (data); + break; + } + if (data [strlen (data) - 1] != '\\') + strcat (data, "\\"); + strcat (data, "fontconfig\\cache"); + } +#endif + if (!FcStrUsesHome (data) || FcConfigHome ()) + { + if (!FcConfigAddCacheDir (parse->config, data)) + FcConfigMessage (parse, FcSevereError, "out of memory; cannot add cache directory %s", data); + } + FcStrFree (data); + break; + + case FcElementCache: + data = FcStrBufDoneStatic (&parse->pstack->str); + if (!data) + { + FcConfigMessage (parse, FcSevereError, "out of memory"); + break; + } + /* discard this data; no longer used */ + FcStrBufDestroy (&parse->pstack->str); + break; + case FcElementInclude: + FcParseInclude (parse); + break; + case FcElementConfig: + break; + case FcElementMatch: + FcParseMatch (parse); + break; + case FcElementAlias: + FcParseAlias (parse); + break; + + case FcElementBlank: + FcParseBlank (parse); + break; + case FcElementRescan: + FcParseRescan (parse); + break; + + case FcElementPrefer: + FcParseFamilies (parse, FcVStackPrefer); + break; + case FcElementAccept: + FcParseFamilies (parse, FcVStackAccept); + break; + case FcElementDefault: + FcParseFamilies (parse, FcVStackDefault); + break; + case FcElementFamily: + FcParseFamily (parse); + break; + + case FcElementTest: + FcParseTest (parse); + break; + case FcElementEdit: + FcParseEdit (parse); + break; + + case FcElementInt: + FcParseInt (parse); + break; + case FcElementDouble: + FcParseDouble (parse); + break; + case FcElementString: + FcParseString (parse, FcVStackString); + break; + case FcElementMatrix: + FcParseMatrix (parse); + break; + case FcElementRange: + FcParseRange (parse); + break; + case FcElementBool: + FcParseBool (parse); + break; + case FcElementCharSet: + FcParseCharSet (parse); + break; + case FcElementLangSet: + FcParseLangSet (parse); + break; + case FcElementSelectfont: + break; + case FcElementAcceptfont: + case FcElementRejectfont: + FcParseAcceptRejectFont (parse, parse->pstack->element); + break; + case FcElementGlob: + FcParseString (parse, FcVStackGlob); + break; + case FcElementPattern: + FcParsePattern (parse); + break; + case FcElementPatelt: + FcParsePatelt (parse); + break; + case FcElementName: + FcParseString (parse, FcVStackField); + break; + case FcElementConst: + FcParseString (parse, FcVStackConstant); + break; + case FcElementOr: + FcParseBinary (parse, FcOpOr); + break; + case FcElementAnd: + FcParseBinary (parse, FcOpAnd); + break; + case FcElementEq: + FcParseBinary (parse, FcOpEqual); + break; + case FcElementNotEq: + FcParseBinary (parse, FcOpNotEqual); + break; + case FcElementLess: + FcParseBinary (parse, FcOpLess); + break; + case FcElementLessEq: + FcParseBinary (parse, FcOpLessEqual); + break; + case FcElementMore: + FcParseBinary (parse, FcOpMore); + break; + case FcElementMoreEq: + FcParseBinary (parse, FcOpMoreEqual); + break; + case FcElementContains: + FcParseBinary (parse, FcOpContains); + break; + case FcElementNotContains: + FcParseBinary (parse, FcOpNotContains); + break; + case FcElementPlus: + FcParseBinary (parse, FcOpPlus); + break; + case FcElementMinus: + FcParseBinary (parse, FcOpMinus); + break; + case FcElementTimes: + FcParseBinary (parse, FcOpTimes); + break; + case FcElementDivide: + FcParseBinary (parse, FcOpDivide); + break; + case FcElementNot: + FcParseUnary (parse, FcOpNot); + break; + case FcElementIf: + FcParseBinary (parse, FcOpQuest); + break; + case FcElementFloor: + FcParseUnary (parse, FcOpFloor); + break; + case FcElementCeil: + FcParseUnary (parse, FcOpCeil); + break; + case FcElementRound: + FcParseUnary (parse, FcOpRound); + break; + case FcElementTrunc: + FcParseUnary (parse, FcOpTrunc); + break; + case FcElementUnknown: + break; + } + (void) FcPStackPop (parse); +} + +static void +FcCharacterData (void *userData, const XML_Char *s, int len) +{ + FcConfigParse *parse = userData; + + if (!parse->pstack) + return; + if (!FcStrBufData (&parse->pstack->str, (FcChar8 *) s, len)) + FcConfigMessage (parse, FcSevereError, "out of memory"); +} + +static void +FcStartDoctypeDecl (void *userData, + const XML_Char *doctypeName, + const XML_Char *sysid, + const XML_Char *pubid, + int has_internal_subset) +{ + FcConfigParse *parse = userData; + + if (strcmp ((char *) doctypeName, "fontconfig") != 0) + FcConfigMessage (parse, FcSevereError, "invalid doctype \"%s\"", doctypeName); +} + +#ifdef ENABLE_LIBXML2 + +static void +FcInternalSubsetDecl (void *userData, + const XML_Char *doctypeName, + const XML_Char *sysid, + const XML_Char *pubid) +{ + FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 1); +} + +static void +FcExternalSubsetDecl (void *userData, + const XML_Char *doctypeName, + const XML_Char *sysid, + const XML_Char *pubid) +{ + FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 0); +} + +#else /* ENABLE_LIBXML2 */ + +static void +FcEndDoctypeDecl (void *userData) +{ +} + +#endif /* ENABLE_LIBXML2 */ + +static int +FcSortCmpStr (const void *a, const void *b) +{ + const FcChar8 *as = *((FcChar8 **) a); + const FcChar8 *bs = *((FcChar8 **) b); + return FcStrCmp (as, bs); +} + +static FcBool +FcConfigParseAndLoadDir (FcConfig *config, + const FcChar8 *name, + const FcChar8 *dir, + FcBool complain) +{ + DIR *d; + struct dirent *e; + FcBool ret = FcTrue; + FcChar8 *file; + FcChar8 *base; + FcStrSet *files; + + d = opendir ((char *) dir); + if (!d) + { + if (complain) + FcConfigMessage (0, FcSevereError, "Cannot open config dir \"%s\"", + name); + ret = FcFalse; + goto bail0; + } + /* freed below */ + file = (FcChar8 *) malloc (strlen ((char *) dir) + 1 + FC_MAX_FILE_LEN + 1); + if (!file) + { + ret = FcFalse; + goto bail1; + } + + strcpy ((char *) file, (char *) dir); + strcat ((char *) file, "/"); + base = file + strlen ((char *) file); + + files = FcStrSetCreate (); + if (!files) + { + ret = FcFalse; + goto bail2; + } + + if (FcDebug () & FC_DBG_CONFIG) + printf ("\tScanning config dir %s\n", dir); + + while (ret && (e = readdir (d))) + { + int d_len; +#define TAIL ".conf" +#define TAIL_LEN 5 + /* + * Add all files of the form [0-9]*.conf + */ + if ('0' <= e->d_name[0] && e->d_name[0] <= '9' && + (d_len = strlen (e->d_name)) < FC_MAX_FILE_LEN && + d_len > TAIL_LEN && + strcmp (e->d_name + d_len - TAIL_LEN, TAIL) == 0) + { + strcpy ((char *) base, (char *) e->d_name); + if (!FcStrSetAdd (files, file)) + { + ret = FcFalse; + goto bail3; + } + } + } + if (ret) + { + int i; + qsort (files->strs, files->num, sizeof (FcChar8 *), + (int (*)(const void *, const void *)) FcSortCmpStr); + for (i = 0; ret && i < files->num; i++) + ret = FcConfigParseAndLoad (config, files->strs[i], complain); + } +bail3: + FcStrSetDestroy (files); +bail2: + free (file); +bail1: + closedir (d); +bail0: + return ret || !complain; +} + +FcBool +FcConfigParseAndLoad (FcConfig *config, + const FcChar8 *name, + FcBool complain) +{ + + XML_Parser p; + FcChar8 *filename; + int fd; + int len; + FcConfigParse parse; + FcBool error = FcTrue; + +#ifdef ENABLE_LIBXML2 + xmlSAXHandler sax; + char buf[BUFSIZ]; +#else + void *buf; +#endif + + filename = FcConfigFilename (name); + if (!filename) + goto bail0; + + if (FcStrSetMember (config->configFiles, filename)) + { + FcStrFree (filename); + return FcTrue; + } + + if (!FcStrSetAdd (config->configFiles, filename)) + { + FcStrFree (filename); + goto bail0; + } + + if (FcFileIsDir (filename)) + { + FcBool ret = FcConfigParseAndLoadDir (config, name, filename, complain); + FcStrFree (filename); + return ret; + } + + if (FcDebug () & FC_DBG_CONFIG) + printf ("\tLoading config file %s\n", filename); + + fd = open ((char *) filename, O_RDONLY); + if (fd == -1) { + FcStrFree (filename); + goto bail0; + } + +#ifdef ENABLE_LIBXML2 + memset(&sax, 0, sizeof(sax)); + + sax.internalSubset = FcInternalSubsetDecl; + sax.externalSubset = FcExternalSubsetDecl; + sax.startElement = FcStartElement; + sax.endElement = FcEndElement; + sax.characters = FcCharacterData; + + p = xmlCreatePushParserCtxt (&sax, &parse, NULL, 0, (const char *) filename); +#else + p = XML_ParserCreate ("UTF-8"); +#endif + FcStrFree (filename); + + if (!p) + goto bail1; + + if (!FcConfigInit (&parse, name, config, p)) + goto bail2; + +#ifndef ENABLE_LIBXML2 + + XML_SetUserData (p, &parse); + + XML_SetDoctypeDeclHandler (p, FcStartDoctypeDecl, FcEndDoctypeDecl); + XML_SetElementHandler (p, FcStartElement, FcEndElement); + XML_SetCharacterDataHandler (p, FcCharacterData); + +#endif /* ENABLE_LIBXML2 */ + + do { +#ifndef ENABLE_LIBXML2 + buf = XML_GetBuffer (p, BUFSIZ); + if (!buf) + { + FcConfigMessage (&parse, FcSevereError, "cannot get parse buffer"); + goto bail3; + } +#endif + len = read (fd, buf, BUFSIZ); + if (len < 0) + { + FcConfigMessage (&parse, FcSevereError, "failed reading config file"); + goto bail3; + } + +#ifdef ENABLE_LIBXML2 + if (xmlParseChunk (p, buf, len, len == 0)) +#else + if (!XML_ParseBuffer (p, len, len == 0)) +#endif + { + FcConfigMessage (&parse, FcSevereError, "%s", + XML_ErrorString (XML_GetErrorCode (p))); + goto bail3; + } + } while (len != 0); + error = parse.error; +bail3: + FcConfigCleanup (&parse); +bail2: + XML_ParserFree (p); +bail1: + close (fd); + fd = -1; +bail0: + if (error && complain) + { + if (name) + FcConfigMessage (0, FcSevereError, "Cannot load config file \"%s\"", name); + else + FcConfigMessage (0, FcSevereError, "Cannot load default config file"); + return FcFalse; + } + return FcTrue; +} +#define __fcxml__ +#include "fcaliastail.h" +#undef __fcxml__ -- cgit v1.2.3