diff options
Diffstat (limited to 'nx-X11/extras/fontconfig/src/fcxml.c')
-rw-r--r-- | nx-X11/extras/fontconfig/src/fcxml.c | 2388 |
1 files changed, 2388 insertions, 0 deletions
diff --git a/nx-X11/extras/fontconfig/src/fcxml.c b/nx-X11/extras/fontconfig/src/fcxml.c new file mode 100644 index 000000000..539e57faf --- /dev/null +++ b/nx-X11/extras/fontconfig/src/fcxml.c @@ -0,0 +1,2388 @@ +/* + * $RCSId: xc/lib/fontconfig/src/fcxml.c,v 1.21 2002/08/22 18:53:22 keithp Exp $ + * + * 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 Keith Packard not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. Keith Packard makes no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL KEITH PACKARD 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 <stdarg.h> +#include "fcint.h" +#include <dirent.h> + +#ifndef HAVE_XMLPARSE_H +#define HAVE_XMLPARSE_H 0 +#endif + +#if HAVE_XMLPARSE_H +#include <xmlparse.h> +#else +#include <expat.h> +#endif + +#ifdef _WIN32 +#define STRICT +#include <windows.h> +#undef STRICT +#endif + + +void +FcTestDestroy (FcTest *test) +{ + if (test->next) + FcTestDestroy (test->next); + FcExprDestroy (test->expr); + FcStrFree ((FcChar8 *) test->field); + FcMemFree (FC_MEM_TEST, sizeof (FcTest)); + free (test); +} + +FcExpr * +FcExprCreateInteger (int i) +{ + FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr)); + + if (e) + { + FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr)); + e->op = FcOpInteger; + e->u.ival = i; + } + return e; +} + +FcExpr * +FcExprCreateDouble (double d) +{ + FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr)); + + if (e) + { + FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr)); + e->op = FcOpDouble; + e->u.dval = d; + } + return e; +} + +FcExpr * +FcExprCreateString (const FcChar8 *s) +{ + FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr)); + + if (e) + { + FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr)); + e->op = FcOpString; + e->u.sval = FcStrCopy (s); + } + return e; +} + +FcExpr * +FcExprCreateMatrix (const FcMatrix *m) +{ + FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr)); + + if (e) + { + FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr)); + e->op = FcOpMatrix; + e->u.mval = FcMatrixCopy (m); + } + return e; +} + +FcExpr * +FcExprCreateBool (FcBool b) +{ + FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr)); + + if (e) + { + FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr)); + e->op = FcOpBool; + e->u.bval = b; + } + return e; +} + +FcExpr * +FcExprCreateNil (void) +{ + FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr)); + + if (e) + { + FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr)); + e->op = FcOpNil; + } + return e; +} + +FcExpr * +FcExprCreateField (const char *field) +{ + FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr)); + + if (e) + { + FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr)); + e->op = FcOpField; + e->u.field = (char *) FcStrCopy ((FcChar8 *) field); + } + return e; +} + +FcExpr * +FcExprCreateConst (const FcChar8 *constant) +{ + FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr)); + + if (e) + { + FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr)); + e->op = FcOpConst; + e->u.constant = FcStrCopy (constant); + } + return e; +} + +FcExpr * +FcExprCreateOp (FcExpr *left, FcOp op, FcExpr *right) +{ + FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr)); + + if (e) + { + FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr)); + e->op = op; + e->u.tree.left = left; + e->u.tree.right = right; + } + return e; +} + +void +FcExprDestroy (FcExpr *e) +{ + if (!e) + return; + switch (e->op) { + case FcOpInteger: + break; + case FcOpDouble: + break; + case FcOpString: + FcStrFree (e->u.sval); + break; + case FcOpMatrix: + FcMatrixFree (e->u.mval); + break; + case FcOpCharSet: + FcCharSetDestroy (e->u.cval); + break; + case FcOpBool: + break; + case FcOpField: + FcStrFree ((FcChar8 *) e->u.field); + break; + case FcOpConst: + FcStrFree (e->u.constant); + 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; + } + FcMemFree (FC_MEM_EXPR, sizeof (FcExpr)); + free (e); +} + +void +FcEditDestroy (FcEdit *e) +{ + if (e->next) + FcEditDestroy (e->next); + FcStrFree ((FcChar8 *) e->field); + if (e->expr) + FcExprDestroy (e->expr); + free (e); +} + +char * +FcConfigSaveField (const char *field) +{ + return (char *) FcStrCopy ((FcChar8 *) field); +} + +typedef enum _FcElement { + FcElementNone, + FcElementFontconfig, + FcElementDir, + FcElementCache, + FcElementInclude, + FcElementConfig, + FcElementMatch, + FcElementAlias, + + FcElementBlank, + FcElementRescan, + + FcElementPrefer, + FcElementAccept, + FcElementDefault, + FcElementFamily, + + FcElementSelectfont, + FcElementAcceptfont, + FcElementRejectfont, + FcElementGlob, + FcElementPattern, + FcElementPatelt, + + FcElementTest, + FcElementEdit, + FcElementInt, + FcElementDouble, + FcElementString, + FcElementMatrix, + FcElementBool, + FcElementCharset, + 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 FcElement +FcElementMap (const XML_Char *name) +{ + static struct { + char *name; + FcElement element; + } fcElementMap[] = { + { "fontconfig", FcElementFontconfig }, + { "dir", FcElementDir }, + { "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 }, + { "bool", FcElementBool }, + { "charset", FcElementCharset }, + { "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 }, + + { 0, 0 } + }; + + int i; + for (i = 0; fcElementMap[i].name; 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; +} FcPStack; + +typedef enum _FcVStackTag { + FcVStackNone, + + FcVStackString, + FcVStackFamily, + FcVStackField, + FcVStackConstant, + FcVStackGlob, + FcVStackPattern, + + FcVStackPrefer, + FcVStackAccept, + FcVStackDefault, + + FcVStackInteger, + FcVStackDouble, + FcVStackMatrix, + FcVStackBool, + + 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; + FcBool bool; + + 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; +} FcConfigParse; + +typedef enum _FcConfigSeverity { + FcSevereInfo, FcSevereWarning, FcSevereError +} FcConfigSeverity; + +static void +FcConfigMessage (FcConfigParse *parse, FcConfigSeverity severe, char *fmt, ...) +{ + 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, XML_GetCurrentLineNumber (parse->parser)); + else + fprintf (stderr, "Fontconfig %s: line %d: ", s, + 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 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; + 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; + + 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 FcOpNil: + break; + case FcOpField: + o = FcNameGetObjectType (expr->u.field); + 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); + } + 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->field = (char *) FcStrCopy (field); + test->op = compare; + test->expr = expr; + o = FcNameGetObjectType (test->field); + if (o) + FcTypecheckExpr (parse, expr, o->type); + } + return test; +} + +static FcEdit * +FcEditCreate (FcConfigParse *parse, + const char *field, + FcOp op, + FcExpr *expr, + FcValueBinding binding) +{ + FcEdit *e = (FcEdit *) malloc (sizeof (FcEdit)); + + if (e) + { + const FcObjectType *o; + + e->next = 0; + e->field = field; /* already saved in grammar */ + e->op = op; + e->expr = expr; + e->binding = binding; + o = FcNameGetObjectType (e->field); + if (o) + FcTypecheckExpr (parse, expr, o->type); + } + return e; +} + +static void +FcVStackPush (FcConfigParse *parse, FcVStack *vstack) +{ + vstack->prev = parse->vstack; + vstack->pstack = parse->pstack ? parse->pstack->prev : 0; + parse->vstack = vstack; +} + +static FcVStack * +FcVStackCreate (void) +{ + FcVStack *new; + + new = malloc (sizeof (FcVStack)); + if (!new) + return 0; + FcMemAlloc (FC_MEM_VSTACK, sizeof (FcVStack)); + new->tag = FcVStackNone; + new->prev = 0; + return new; +} + +static void +FcVStackDestroy (FcVStack *vstack) +{ + FcVStack *prev; + + for (; vstack; vstack = prev) + { + prev = vstack->prev; + switch (vstack->tag) { + case FcVStackNone: + break; + case FcVStackString: + case FcVStackFamily: + 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 FcVStackBool: + 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; + } + FcMemFree (FC_MEM_VSTACK, sizeof (FcVStack)); + free (vstack); + } +} + +static FcBool +FcVStackPushString (FcConfigParse *parse, FcVStackTag tag, FcChar8 *string) +{ + FcVStack *vstack = FcVStackCreate (); + if (!vstack) + return FcFalse; + vstack->u.string = string; + vstack->tag = tag; + FcVStackPush (parse, vstack); + return FcTrue; +} + +static FcBool +FcVStackPushInteger (FcConfigParse *parse, int integer) +{ + FcVStack *vstack = FcVStackCreate (); + if (!vstack) + return FcFalse; + vstack->u.integer = integer; + vstack->tag = FcVStackInteger; + FcVStackPush (parse, vstack); + return FcTrue; +} + +static FcBool +FcVStackPushDouble (FcConfigParse *parse, double _double) +{ + FcVStack *vstack = FcVStackCreate (); + if (!vstack) + return FcFalse; + vstack->u._double = _double; + vstack->tag = FcVStackDouble; + FcVStackPush (parse, vstack); + return FcTrue; +} + +static FcBool +FcVStackPushMatrix (FcConfigParse *parse, FcMatrix *matrix) +{ + FcVStack *vstack = FcVStackCreate (); + if (!vstack) + return FcFalse; + matrix = FcMatrixCopy (matrix); + if (!matrix) + { + FcVStackDestroy (vstack); + return FcFalse; + } + vstack->u.matrix = matrix; + vstack->tag = FcVStackMatrix; + FcVStackPush (parse, vstack); + return FcTrue; +} + +static FcBool +FcVStackPushBool (FcConfigParse *parse, FcBool bool) +{ + FcVStack *vstack = FcVStackCreate (); + if (!vstack) + return FcFalse; + vstack->u.bool = bool; + vstack->tag = FcVStackBool; + FcVStackPush (parse, vstack); + return FcTrue; +} + +static FcBool +FcVStackPushTest (FcConfigParse *parse, FcTest *test) +{ + FcVStack *vstack = FcVStackCreate (); + if (!vstack) + return FcFalse; + vstack->u.test = test; + vstack->tag = FcVStackTest; + FcVStackPush (parse, vstack); + return FcTrue; +} + +static FcBool +FcVStackPushExpr (FcConfigParse *parse, FcVStackTag tag, FcExpr *expr) +{ + FcVStack *vstack = FcVStackCreate (); + if (!vstack) + return FcFalse; + vstack->u.expr = expr; + vstack->tag = tag; + FcVStackPush (parse, vstack); + return FcTrue; +} + +static FcBool +FcVStackPushEdit (FcConfigParse *parse, FcEdit *edit) +{ + FcVStack *vstack = FcVStackCreate (); + if (!vstack) + return FcFalse; + vstack->u.edit = edit; + vstack->tag = FcVStackEdit; + FcVStackPush (parse, vstack); + return FcTrue; +} + +static FcBool +FcVStackPushPattern (FcConfigParse *parse, FcPattern *pattern) +{ + FcVStack *vstack = FcVStackCreate (); + if (!vstack) + return FcFalse; + vstack->u.pattern = pattern; + vstack->tag = FcVStackPattern; + FcVStackPush (parse, vstack); + return FcTrue; +} + +static FcVStack * +FcVStackFetch (FcConfigParse *parse, int off) +{ + FcVStack *vstack; + + for (vstack = parse->vstack; vstack && off-- > 0; vstack = vstack->prev); + return vstack; +} + +static void +FcVStackClear (FcConfigParse *parse) +{ + while (parse->vstack && parse->vstack->pstack == parse->pstack) + { + FcVStack *vstack = parse->vstack; + parse->vstack = vstack->prev; + vstack->prev = 0; + FcVStackDestroy (vstack); + } +} + +static FcVStack * +FcVStackPop (FcConfigParse *parse) +{ + FcVStack *vstack = parse->vstack; + + if (!vstack || vstack->pstack != parse->pstack) + return 0; + parse->vstack = vstack->prev; + vstack->prev = 0; + return vstack; +} + +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) +{ + int n; + int slen; + int i; + FcChar8 **new; + FcChar8 *s; + + if (!attr) + return 0; + slen = 0; + for (i = 0; attr[i]; i++) + slen += strlen (attr[i]) + 1; + n = i; + new = malloc ((i + 1) * sizeof (FcChar8 *) + slen); + if (!new) + 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 = malloc (sizeof (FcPStack)); + + if (!new) + return FcFalse; + FcMemAlloc (FC_MEM_PSTACK, sizeof (FcPStack)); + new->prev = parse->pstack; + new->element = element; + if (attr) + { + new->attr = FcConfigSaveAttr (attr); + if (!new->attr) + FcConfigMessage (parse, FcSevereError, "out of memory"); + } + else + new->attr = 0; + 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) + { + FcMemFree (FC_MEM_ATTR, 1); /* size is to expensive */ + free (old->attr); + } + 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->vstack = 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, char *attr) +{ + FcChar8 **attrs; + if (!parse->pstack) + return 0; + + attrs = parse->pstack->attr; + 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); + while (n-- > 0) + { + FcVStack *v = FcVStackFetch (parse, n); + if (v->tag != FcVStackInteger) + FcConfigMessage (parse, FcSevereError, "non-integer blank"); + else + { + if (!parse->config->blanks) + { + parse->config->blanks = FcBlanksCreate (); + if (!parse->config->blanks) + { + FcConfigMessage (parse, FcSevereError, "out of memory"); + break; + } + } + if (!FcBlanksAdd (parse->config->blanks, v->u.integer)) + { + FcConfigMessage (parse, FcSevereError, "out of memory"); + break; + } + } + } +} + +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 = FcStrBufDone (&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); + FcStrFree (s); +} + +/* + * idea copied from glib g_ascii_strtod with + * permission of the author (Alexander Larsson) + */ + +#include <locale.h> + +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 > 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 = FcStrBufDone (&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); + FcStrFree (s); +} + +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 = FcVStackPop (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; + } + FcVStackDestroy (vstack); + matrix_state--; + } + if (matrix_state != m_done) + FcConfigMessage (parse, FcSevereError, "wrong number of matrix elements"); + else + FcVStackPushMatrix (parse, &m); +} + +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 = FcStrBufDone (&parse->pstack->str); + if (!s) + { + FcConfigMessage (parse, FcSevereError, "out of memory"); + return; + } + FcVStackPushBool (parse, FcConfigLexBool (parse, s)); + FcStrFree (s); +} + +static void +FcParseFamilies (FcConfigParse *parse, FcVStackTag tag) +{ + FcVStack *vstack; + FcExpr *left, *expr = 0, *new; + + while ((vstack = FcVStackPop (parse))) + { + if (vstack->tag != FcVStackFamily) + { + FcConfigMessage (parse, FcSevereWarning, "non-family"); + FcVStackDestroy (vstack); + continue; + } + left = vstack->u.expr; + vstack->tag = FcVStackNone; + FcVStackDestroy (vstack); + if (expr) + { + new = FcExprCreateOp (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"); + if (expr) + FcExprDestroy (expr); + } + } +} + +static void +FcParseFamily (FcConfigParse *parse) +{ + FcChar8 *s; + FcExpr *expr; + + if (!parse->pstack) + return; + s = FcStrBufDone (&parse->pstack->str); + if (!s) + { + FcConfigMessage (parse, FcSevereError, "out of memory"); + return; + } + expr = FcExprCreateString (s); + FcStrFree (s); + 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; + + while ((vstack = FcVStackPop (parse))) + { + switch (vstack->tag) { + case FcVStackFamily: + if (family) + { + new = FcExprCreateOp (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; + } + FcVStackDestroy (vstack); + } + 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, + FcConfigSaveField ("family"), + FcOpPrepend, + prefer, + FcValueBindingWeak); + if (edit) + edit->next = 0; + else + FcExprDestroy (prefer); + } + if (accept) + { + next = edit; + edit = FcEditCreate (parse, + FcConfigSaveField ("family"), + FcOpAppend, + accept, + FcValueBindingWeak); + if (edit) + edit->next = next; + else + FcExprDestroy (accept); + } + if (def) + { + next = edit; + edit = FcEditCreate (parse, + FcConfigSaveField ("family"), + FcOpAppendLast, + def, + FcValueBindingWeak); + 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 = FcVStackPop (parse); + FcExpr *expr = 0; + if (!vstack) + return 0; + switch (vstack->tag) { + case FcVStackNone: + break; + case FcVStackString: + case FcVStackFamily: + expr = FcExprCreateString (vstack->u.string); + break; + case FcVStackField: + expr = FcExprCreateField ((char *) vstack->u.string); + break; + case FcVStackConstant: + expr = FcExprCreateConst (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 (vstack->u.integer); + break; + case FcVStackDouble: + expr = FcExprCreateDouble (vstack->u._double); + break; + case FcVStackMatrix: + expr = FcExprCreateMatrix (vstack->u.matrix); + break; + case FcVStackBool: + expr = FcExprCreateBool (vstack->u.bool); + break; + case FcVStackTest: + break; + case FcVStackExpr: + expr = vstack->u.expr; + vstack->tag = FcVStackNone; + break; + case FcVStackEdit: + break; + default: + break; + } + FcVStackDestroy (vstack); + 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 (left, op, expr); + if (!new) + { + FcConfigMessage (parse, FcSevereError, "out of memory"); + FcExprDestroy (left); + FcExprDestroy (expr); + break; + } + 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 (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 = FcStrBufDone (&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; + FcStrFree (s); +} + +typedef struct _FcOpMap { + char *name; + 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 (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, "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 (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; + const FcChar8 *binding_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; + } + } + binding_string = FcConfigGetAttribute (parse, "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 edit binding \"%s\"", binding_string); + return; + } + } + expr = FcPopBinary (parse, FcOpComma); + edit = FcEditCreate (parse, (char *) FcStrCopy (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 + { + FcConfigMessage (parse, FcSevereWarning, "invalid match target \"%s\"", kind_name); + return; + } + } + while ((vstack = FcVStackPop (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; + break; + default: + FcConfigMessage (parse, FcSevereWarning, "invalid match element"); + break; + } + FcVStackDestroy (vstack); + } + if (!FcConfigAddEdit (parse->config, test, edit, kind)) + FcConfigMessage (parse, FcSevereError, "out of memory"); +} + +static void +FcParseAcceptRejectFont (FcConfigParse *parse, FcElement element) +{ + FcVStack *vstack; + + while ((vstack = FcVStackPop (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; + } + FcVStackDestroy (vstack); + } +} + + +static FcValue +FcPopValue (FcConfigParse *parse) +{ + FcVStack *vstack = FcVStackPop (parse); + FcValue value; + + value.type = FcTypeVoid; + + if (!vstack) + return value; + + switch (vstack->tag) { + case FcVStackString: + value.u.s = FcStrCopy (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; + default: + FcConfigMessage (parse, FcSevereWarning, "unknown pattern element %d", + vstack->tag); + break; + } + FcVStackDestroy (vstack); + + 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 = FcConfigGetAttribute (parse, "name"); + if (!name) + { + FcConfigMessage (parse, FcSevereWarning, "missing pattern element name"); + return; + } + + for (;;) + { + value = FcPopValue (parse); + if (value.type == FcTypeVoid) + break; + if (!FcPatternAdd (pattern, name, value, FcTrue)) + { + FcConfigMessage (parse, FcSevereError, "out of memory"); + break; + } + } + + FcVStackPushPattern (parse, pattern); +} + +static void +FcParsePattern (FcConfigParse *parse) +{ + FcVStack *vstack; + FcPattern *pattern = FcPatternCreate (); + + if (!pattern) + { + FcConfigMessage (parse, FcSevereError, "out of memory"); + return; + } + + while ((vstack = FcVStackPop (parse))) + { + switch (vstack->tag) { + case FcVStackPattern: + if (!FcPatternAppend (pattern, vstack->u.pattern)) + { + FcConfigMessage (parse, FcSevereError, "out of memory"); + return; + } + break; + default: + FcConfigMessage (parse, FcSevereWarning, "unknown pattern element"); + break; + } + FcVStackDestroy (vstack); + } + + FcVStackPushPattern (parse, pattern); +} + +static void +FcEndElement(void *userData, const XML_Char *name) +{ + FcConfigParse *parse = userData; + FcChar8 *data; + + if (!parse->pstack) + return; + switch (parse->pstack->element) { + case FcElementNone: + break; + case FcElementFontconfig: + break; + case FcElementDir: + data = FcStrBufDone (&parse->pstack->str); + if (!data) + { + FcConfigMessage (parse, FcSevereError, "out of memory"); + break; + } +#ifdef _WIN32 + if (strcmp (data, "WINDOWSFONTDIR") == 0) + { + int rc; + FcStrFree (data); + data = malloc (1000); + if (!data) + { + FcConfigMessage (parse, FcSevereError, "out of memory"); + break; + } + FcMemAlloc (FC_MEM_STRING, 1000); + rc = GetWindowsDirectory (data, 800); + if (rc == 0 || rc > 800) + { + FcConfigMessage (parse, FcSevereError, "GetWindowsDirectory failed"); + FcStrFree (data); + break; + } + if (data [strlen (data) - 1] != '\\') + strcat (data, "\\"); + strcat (data, "fonts"); + } +#endif + if (!FcStrUsesHome (data) || FcConfigHome ()) + { + if (!FcConfigAddDir (parse->config, data)) + FcConfigMessage (parse, FcSevereError, "out of memory"); + } + FcStrFree (data); + break; + case FcElementCache: + data = FcStrBufDone (&parse->pstack->str); + if (!data) + { + FcConfigMessage (parse, FcSevereError, "out of memory"); + break; + } + if (!FcStrUsesHome (data) || FcConfigHome ()) + { + if (!FcConfigSetCache (parse->config, data)) + FcConfigMessage (parse, FcSevereError, "out of memory"); + } + FcStrFree (data); + 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 FcElementBool: + FcParseBool (parse); + break; + case FcElementCharset: +/* FcParseCharset (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); +} + +static void +FcEndDoctypeDecl (void *userData) +{ +} + +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))) + { + /* + * Add all files of the form [0-9]* + */ + if ('0' <= e->d_name[0] && e->d_name[0] <= '9' && + strlen (e->d_name) < FC_MAX_FILE_LEN) + { + 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 *)) FcStrCmp); + 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; + FILE *f; + int len; + void *buf; + FcConfigParse parse; + FcBool error = FcTrue; + + filename = FcConfigFilename (name); + if (!filename) + goto bail0; + + 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); + + f = fopen ((char *) filename, "r"); + FcStrFree (filename); + if (!f) + goto bail0; + + p = XML_ParserCreate ("UTF-8"); + if (!p) + goto bail1; + + if (!FcConfigInit (&parse, name, config, p)) + goto bail2; + + XML_SetUserData (p, &parse); + + XML_SetDoctypeDeclHandler (p, FcStartDoctypeDecl, FcEndDoctypeDecl); + XML_SetElementHandler (p, FcStartElement, FcEndElement); + XML_SetCharacterDataHandler (p, FcCharacterData); + + do { + buf = XML_GetBuffer (p, BUFSIZ); + if (!buf) + { + FcConfigMessage (&parse, FcSevereError, "cannot get parse buffer"); + goto bail3; + } + len = fread (buf, 1, BUFSIZ, f); + if (len < 0) + { + FcConfigMessage (&parse, FcSevereError, "failed reading config file"); + goto bail3; + } + if (!XML_ParseBuffer (p, len, len == 0)) + { + 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: + fclose (f); +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; +} |