X-Git-Url: https://git.wh0rd.org/?p=fontconfig.git;a=blobdiff_plain;f=src%2Ffcxml.c;h=ff30b7bbdaff398971803913619b757ae24a83df;hp=ef116d05aa08d4c749734defee29094f75c3a525;hb=HEAD;hpb=d0f07b8d582499fdc6fa0ca6c5e2ef3727baddae diff --git a/src/fcxml.c b/src/fcxml.c index ef116d0..ff30b7b 100644 --- a/src/fcxml.c +++ b/src/fcxml.c @@ -1,68 +1,67 @@ /* - * $XFree86: xc/lib/fontconfig/src/fcxml.c,v 1.8 2002/05/22 04:12:35 keithp Exp $ + * fontconfig/src/fcxml.c * - * Copyright © 2002 Keith Packard, member of The XFree86 Project, Inc. + * 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 + * 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. Keith Packard makes no + * 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. * - * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * THE AUTHOR(S) 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 + * 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 #include "fcint.h" +#include +#include +#include -#ifndef HAVE_EXPAT -#define HAVE_EXPAT 1 -#endif +#ifdef ENABLE_LIBXML2 -#ifndef HAVE_XML2 -#define HAVE_XML2 0 -#endif +#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 */ -#if HAVE_EXPAT #ifndef HAVE_XMLPARSE_H #define HAVE_XMLPARSE_H 0 #endif + #if HAVE_XMLPARSE_H #include #else #include #endif -#endif -#if HAVE_XML2 -#include "fclibxml2.h" -#endif +#endif /* ENABLE_LIBXML2 */ -FcTest * -FcTestCreate (FcQual qual, const FcChar8 *field, FcOp compare, FcExpr *expr) -{ - FcTest *test = (FcTest *) malloc (sizeof (FcTest)); +#ifdef _WIN32 +#define _WIN32_WINNT 0x0500 +#define STRICT +#include +#undef STRICT +#include +#endif - if (test) - { - test->next = 0; - test->qual = qual; - test->field = (char *) FcStrCopy (field); - test->op = compare; - test->expr = expr; - } - return test; -} +static void +FcExprDestroy (FcExpr *e); void FcTestDestroy (FcTest *test) @@ -70,15 +69,14 @@ 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) +static FcExpr * +FcExprCreateInteger (FcConfig *config, int i) { - FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr)); - + FcExpr *e = FcConfigAllocExpr (config); if (e) { e->op = FcOpInteger; @@ -87,11 +85,10 @@ FcExprCreateInteger (int i) return e; } -FcExpr * -FcExprCreateDouble (double d) +static FcExpr * +FcExprCreateDouble (FcConfig *config, double d) { - FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr)); - + FcExpr *e = FcConfigAllocExpr (config); if (e) { e->op = FcOpDouble; @@ -100,24 +97,22 @@ FcExprCreateDouble (double d) return e; } -FcExpr * -FcExprCreateString (const FcChar8 *s) +static FcExpr * +FcExprCreateString (FcConfig *config, const FcChar8 *s) { - FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr)); - + FcExpr *e = FcConfigAllocExpr (config); if (e) { e->op = FcOpString; - e->u.sval = FcStrCopy (s); + e->u.sval = FcStrStaticName (s); } return e; } -FcExpr * -FcExprCreateMatrix (const FcMatrix *m) +static FcExpr * +FcExprCreateMatrix (FcConfig *config, const FcMatrix *m) { - FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr)); - + FcExpr *e = FcConfigAllocExpr (config); if (e) { e->op = FcOpMatrix; @@ -126,11 +121,10 @@ FcExprCreateMatrix (const FcMatrix *m) return e; } -FcExpr * -FcExprCreateBool (FcBool b) +static FcExpr * +FcExprCreateBool (FcConfig *config, FcBool b) { - FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr)); - + FcExpr *e = FcConfigAllocExpr (config); if (e) { e->op = FcOpBool; @@ -139,49 +133,58 @@ FcExprCreateBool (FcBool b) return e; } -FcExpr * -FcExprCreateNil (void) +static FcExpr * +FcExprCreateCharSet (FcConfig *config, FcCharSet *charset) { - FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr)); - + FcExpr *e = FcConfigAllocExpr (config); if (e) { - e->op = FcOpNil; + e->op = FcOpCharSet; + e->u.cval = FcCharSetCopy (charset); } return e; } -FcExpr * -FcExprCreateField (const char *field) +static FcExpr * +FcExprCreateLangSet (FcConfig *config, FcLangSet *langset) { - FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr)); + 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.field = (char *) FcStrCopy ((FcChar8 *) field); + e->u.object = FcObjectFromName (field); } return e; } -FcExpr * -FcExprCreateConst (const FcChar8 *constant) +static FcExpr * +FcExprCreateConst (FcConfig *config, const FcChar8 *constant) { - FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr)); - + FcExpr *e = FcConfigAllocExpr (config); if (e) { e->op = FcOpConst; - e->u.constant = FcStrCopy (constant); + e->u.constant = FcStrStaticName (constant); } return e; } -FcExpr * -FcExprCreateOp (FcExpr *left, FcOp op, FcExpr *right) +static FcExpr * +FcExprCreateOp (FcConfig *config, FcExpr *left, FcOp op, FcExpr *right) { - FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr)); - + FcExpr *e = FcConfigAllocExpr (config); if (e) { e->op = op; @@ -191,30 +194,34 @@ FcExprCreateOp (FcExpr *left, FcOp op, FcExpr *right) return e; } -void +static 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 FcOpRange: + break; case FcOpCharSet: FcCharSetDestroy (e->u.cval); break; + case FcOpLangSet: + FcLangSetDestroy (e->u.lval); + break; case FcOpBool: break; case FcOpField: - FcStrFree ((FcChar8 *) e->u.field); break; case FcOpConst: - FcStrFree (e->u.constant); break; case FcOpAssign: case FcOpAssignReplace: @@ -226,12 +233,14 @@ FcExprDestroy (FcExpr *e) case FcOpOr: case FcOpAnd: case FcOpEqual: - case FcOpContains: case FcOpNotEqual: case FcOpLess: case FcOpLessEqual: case FcOpMore: case FcOpMoreEqual: + case FcOpContains: + case FcOpListing: + case FcOpNotContains: case FcOpPlus: case FcOpMinus: case FcOpTimes: @@ -241,28 +250,18 @@ FcExprDestroy (FcExpr *e) 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; } - free (e); -} - -FcEdit * -FcEditCreate (const char *field, FcOp op, FcExpr *expr) -{ - FcEdit *e = (FcEdit *) malloc (sizeof (FcEdit)); - if (e) - { - e->next = 0; - e->field = field; /* already saved in grammar */ - e->op = op; - e->expr = expr; - } - return e; + e->op = FcOpNil; } void @@ -270,21 +269,16 @@ FcEditDestroy (FcEdit *e) { if (e->next) FcEditDestroy (e->next); - FcStrFree ((FcChar8 *) e->field); if (e->expr) FcExprDestroy (e->expr); -} - -char * -FcConfigSaveField (const char *field) -{ - return (char *) FcStrCopy ((FcChar8 *) field); + free (e); } typedef enum _FcElement { FcElementNone, FcElementFontconfig, FcElementDir, + FcElementCacheDir, FcElementCache, FcElementInclude, FcElementConfig, @@ -299,14 +293,23 @@ typedef enum _FcElement { FcElementDefault, FcElementFamily, + FcElementSelectfont, + FcElementAcceptfont, + FcElementRejectfont, + FcElementGlob, + FcElementPattern, + FcElementPatelt, + FcElementTest, FcElementEdit, FcElementInt, FcElementDouble, FcElementString, FcElementMatrix, + FcElementRange, FcElementBool, - FcElementCharset, + FcElementCharSet, + FcElementLangSet, FcElementName, FcElementConst, FcElementOr, @@ -317,68 +320,90 @@ typedef enum _FcElement { 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) { - 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 }, - - { "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 }, - { "plus", FcElementPlus }, - { "minus", FcElementMinus }, - { "times", FcElementTimes }, - { "divide", FcElementDivide }, - { "not", FcElementNot }, - { "if", FcElementIf }, - - { 0, 0 } - }; int i; - for (i = 0; fcElementMap[i].name; i++) + for (i = 0; i < NUM_ELEMENT_MAPS; i++) if (!strcmp ((char *) name, fcElementMap[i].name)) return fcElementMap[i].element; return FcElementUnknown; @@ -389,8 +414,9 @@ typedef struct _FcPStack { FcElement element; FcChar8 **attr; FcStrBuf str; + FcChar8 *attr_buf_static[16]; } FcPStack; - + typedef enum _FcVStackTag { FcVStackNone, @@ -398,16 +424,21 @@ typedef enum _FcVStackTag { FcVStackFamily, FcVStackField, FcVStackConstant, - + FcVStackGlob, + FcVStackPattern, + FcVStackPrefer, FcVStackAccept, FcVStackDefault, - + FcVStackInteger, FcVStackDouble, FcVStackMatrix, + FcVStackRange, FcVStackBool, - + FcVStackCharSet, + FcVStackLangSet, + FcVStackTest, FcVStackExpr, FcVStackEdit @@ -423,13 +454,18 @@ typedef struct _FcVStack { int integer; double _double; FcMatrix *matrix; - FcBool bool; + FcRange range; + FcBool bool_; + FcCharSet *charset; + FcLangSet *langset; FcTest *test; FcQual qual; FcOp op; FcExpr *expr; FcEdit *edit; + + FcPattern *pattern; } u; } FcVStack; @@ -440,6 +476,10 @@ typedef struct _FcConfigParse { 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 { @@ -447,9 +487,9 @@ typedef enum _FcConfigSeverity { } FcConfigSeverity; static void -FcConfigMessage (FcConfigParse *parse, FcConfigSeverity severe, char *fmt, ...) +FcConfigMessage (FcConfigParse *parse, FcConfigSeverity severe, const char *fmt, ...) { - char *s = "unknown"; + const char *s = "unknown"; va_list args; va_start (args, fmt); @@ -463,10 +503,10 @@ FcConfigMessage (FcConfigParse *parse, FcConfigSeverity severe, char *fmt, ...) { if (parse->name) fprintf (stderr, "Fontconfig %s: \"%s\", line %d: ", s, - parse->name, XML_GetCurrentLineNumber (parse->parser)); + parse->name, (int)XML_GetCurrentLineNumber (parse->parser)); else fprintf (stderr, "Fontconfig %s: line %d: ", s, - XML_GetCurrentLineNumber (parse->parser)); + (int)XML_GetCurrentLineNumber (parse->parser)); if (severe >= FcSevereError) parse->error = FcTrue; } @@ -477,168 +517,364 @@ FcConfigMessage (FcConfigParse *parse, FcConfigSeverity severe, char *fmt, ...) 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 -FcVStackPush (FcConfigParse *parse, FcVStack *vstack) +FcTypecheckValue (FcConfigParse *parse, FcType value, FcType type) { - vstack->prev = parse->vstack; - vstack->pstack = parse->pstack ? parse->pstack->prev : 0; - parse->vstack = vstack; + 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 FcVStack * -FcVStackCreate (void) +static void +FcTypecheckExpr (FcConfigParse *parse, FcExpr *expr, FcType type) { - FcVStack *new; + const FcObjectType *o; + const FcConstant *c; - new = malloc (sizeof (FcVStack)); - if (!new) - return 0; - new->tag = FcVStackNone; - new->prev = 0; - return new; + /* 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 void -FcVStackDestroy (FcVStack *vstack) +static FcTest * +FcTestCreate (FcConfigParse *parse, + FcMatchKind kind, + FcQual qual, + const FcChar8 *field, + FcOp compare, + FcExpr *expr) { - FcVStack *prev; + FcTest *test = (FcTest *) malloc (sizeof (FcTest)); - for (; vstack; vstack = prev) + if (test) { - prev = vstack->prev; - switch (vstack->tag) { - case FcVStackNone: - break; - case FcVStackString: - case FcVStackFamily: - case FcVStackField: - case FcVStackConstant: - FcStrFree (vstack->u.string); - 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; - } - free (vstack); + 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 = FcVStackCreate (); + FcVStack *vstack = FcVStackCreateAndPush (parse); 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 (); + FcVStack *vstack = FcVStackCreateAndPush (parse); 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 (); + FcVStack *vstack = FcVStackCreateAndPush (parse); 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; + FcVStack *vstack; matrix = FcMatrixCopy (matrix); if (!matrix) - { - FcVStackDestroy (vstack); return FcFalse; - } + vstack = FcVStackCreateAndPush (parse); + if (!vstack) + return FcFalse; vstack->u.matrix = matrix; vstack->tag = FcVStackMatrix; - FcVStackPush (parse, vstack); return FcTrue; } static FcBool -FcVStackPushBool (FcConfigParse *parse, FcBool bool) +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 = FcVStackCreate (); + FcVStack *vstack = FcVStackCreateAndPush (parse); if (!vstack) return FcFalse; - vstack->u.bool = bool; + vstack->u.bool_ = bool_; vstack->tag = FcVStackBool; - FcVStackPush (parse, vstack); + 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 = FcVStackCreate (); + FcVStack *vstack = FcVStackCreateAndPush (parse); 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 (); + FcVStack *vstack = FcVStackCreateAndPush (parse); 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 (); + FcVStack *vstack = FcVStackCreateAndPush (parse); 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 = FcVStackCreateAndPush (parse); + if (!vstack) + return FcFalse; + vstack->u.pattern = pattern; + vstack->tag = FcVStackPattern; return FcTrue; } @@ -651,35 +887,88 @@ FcVStackFetch (FcConfigParse *parse, int off) return vstack; } -static void -FcVStackClear (FcConfigParse *parse) +static FcVStack * +FcVStackPeek (FcConfigParse *parse) { - while (parse->vstack && parse->vstack->pstack == parse->pstack) - { - FcVStack *vstack = parse->vstack; - parse->vstack = vstack->prev; - vstack->prev = 0; - FcVStackDestroy (vstack); - } + FcVStack *vstack = parse->vstack; + + return vstack && vstack->pstack == parse->pstack ? vstack : 0; } -static FcVStack * -FcVStackPop (FcConfigParse *parse) +static void +FcVStackPopAndDestroy (FcConfigParse *parse) { FcVStack *vstack = parse->vstack; - + if (!vstack || vstack->pstack != parse->pstack) - return 0; + return; + parse->vstack = vstack->prev; - vstack->prev = 0; - return vstack; -} -static int -FcVStackElements (FcConfigParse *parse) -{ - int h = 0; - FcVStack *vstack = parse->vstack; + 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++; @@ -689,9 +978,8 @@ FcVStackElements (FcConfigParse *parse) } static FcChar8 ** -FcConfigSaveAttr (const XML_Char **attr) +FcConfigSaveAttr (const XML_Char **attr, FcChar8 **buf, int size_bytes) { - int n; int slen; int i; FcChar8 **new; @@ -701,11 +989,22 @@ FcConfigSaveAttr (const XML_Char **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) + 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++) { @@ -720,20 +1019,21 @@ FcConfigSaveAttr (const XML_Char **attr) static FcBool FcPStackPush (FcConfigParse *parse, FcElement element, const XML_Char **attr) { - FcPStack *new = malloc (sizeof (FcPStack)); + FcPStack *new; - if (!new) - return FcFalse; - new->prev = parse->pstack; - new->element = element; - if (attr) + if (parse->pstack_static_used < sizeof (parse->pstack_static) / sizeof (parse->pstack_static[0])) + new = &parse->pstack_static[parse->pstack_static_used++]; + else { - new->attr = FcConfigSaveAttr (attr); - if (!new->attr) - FcConfigMessage (parse, FcSevereError, "out of memory"); + new = malloc (sizeof (FcPStack)); + if (!new) + return FcFalse; + FcMemAlloc (FC_MEM_PSTACK, sizeof (FcPStack)); } - else - new->attr = 0; + + 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; @@ -743,8 +1043,8 @@ static FcBool FcPStackPop (FcConfigParse *parse) { FcPStack *old; - - if (!parse->pstack) + + if (!parse->pstack) { FcConfigMessage (parse, FcSevereError, "mismatching element"); return FcFalse; @@ -753,9 +1053,19 @@ FcPStackPop (FcConfigParse *parse) old = parse->pstack; parse->pstack = old->prev; FcStrBufDestroy (&old->str); - if (old->attr) + if (old->attr && old->attr != old->attr_buf_static) + { + FcMemFree (FC_MEM_ATTR, 1); /* size is to expensive */ free (old->attr); - free (old); + } + + 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; } @@ -763,7 +1073,9 @@ 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; @@ -779,13 +1091,16 @@ FcConfigCleanup (FcConfigParse *parse) } static const FcChar8 * -FcConfigGetAttribute (FcConfigParse *parse, char *attr) +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)) @@ -800,11 +1115,11 @@ 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"); @@ -816,30 +1131,40 @@ FcStartElement(void *userData, const XML_Char *name, const XML_Char **attr) static void FcParseBlank (FcConfigParse *parse) { - int n = FcVStackElements (parse); + int n = FcVStackElements (parse); + FcChar32 i; 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) - { - parse->config->blanks = FcBlanksCreate (); - if (!parse->config->blanks) - { - FcConfigMessage (parse, FcSevereError, "out of memory"); - break; - } - } + 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) { - FcConfigMessage (parse, FcSevereError, "out of memory"); - break; + 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 @@ -861,10 +1186,10 @@ FcParseInt (FcConfigParse *parse) { FcChar8 *s, *end; int l; - + if (!parse->pstack) return; - s = FcStrBufDone (&parse->pstack->str); + s = FcStrBufDoneStatic (&parse->pstack->str); if (!s) { FcConfigMessage (parse, FcSevereError, "out of memory"); @@ -876,7 +1201,65 @@ FcParseInt (FcConfigParse *parse) FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid integer", s); else FcVStackPushInteger (parse, l); - FcStrFree (s); + 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 @@ -884,29 +1267,29 @@ FcParseDouble (FcConfigParse *parse) { FcChar8 *s, *end; double d; - + if (!parse->pstack) return; - s = FcStrBufDone (&parse->pstack->str); + s = FcStrBufDoneStatic (&parse->pstack->str); if (!s) { FcConfigMessage (parse, FcSevereError, "out of memory"); return; } end = 0; - d = strtod ((char *) s, (char **)&end); + 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); + FcStrBufDestroy (&parse->pstack->str); } static void FcParseString (FcConfigParse *parse, FcVStackTag tag) { FcChar8 *s; - + if (!parse->pstack) return; s = FcStrBufDone (&parse->pstack->str); @@ -925,8 +1308,8 @@ 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))) + + while ((vstack = FcVStackPeek (parse))) { double v; switch (vstack->tag) { @@ -948,6 +1331,7 @@ FcParseMatrix (FcConfigParse *parse) case m_yy: m.yy = v; break; default: break; } + FcVStackPopAndDestroy (parse); matrix_state--; } if (matrix_state != m_done) @@ -956,16 +1340,58 @@ FcParseMatrix (FcConfigParse *parse) 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 (const FcChar8 *bool) +FcConfigLexBool (FcConfigParse *parse, const FcChar8 *bool_) { - if (*bool == 't' || *bool == 'T') - return FcTrue; - if (*bool == 'y' || *bool == 'Y') - return FcTrue; - if (*bool == '1') - return FcTrue; - return FcFalse; + FcBool result = FcFalse; + + if (!FcNameBool (bool_, &result)) + FcConfigMessage (parse, FcSevereWarning, "\"%s\" is not known boolean", + bool_); + return result; } static void @@ -975,14 +1401,116 @@ FcParseBool (FcConfigParse *parse) if (!parse->pstack) return; - s = FcStrBufDone (&parse->pstack->str); + s = FcStrBufDoneStatic (&parse->pstack->str); if (!s) { FcConfigMessage (parse, FcSevereError, "out of memory"); return; } - FcVStackPushBool (parse, FcConfigLexBool (s)); - FcStrFree (s); + 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 @@ -991,20 +1519,20 @@ FcParseFamilies (FcConfigParse *parse, FcVStackTag tag) FcVStack *vstack; FcExpr *left, *expr = 0, *new; - while ((vstack = FcVStackPop (parse))) + while ((vstack = FcVStackPeek (parse))) { if (vstack->tag != FcVStackFamily) { FcConfigMessage (parse, FcSevereWarning, "non-family"); - FcVStackDestroy (vstack); + FcVStackPopAndDestroy (parse); continue; } left = vstack->u.expr; vstack->tag = FcVStackNone; - FcVStackDestroy (vstack); + FcVStackPopAndDestroy (parse); if (expr) { - new = FcExprCreateOp (left, FcOpComma, expr); + new = FcExprCreateOp (parse->config, left, FcOpComma, expr); if (!new) { FcConfigMessage (parse, FcSevereError, "out of memory"); @@ -1022,8 +1550,7 @@ FcParseFamilies (FcConfigParse *parse, FcVStackTag tag) if (!FcVStackPushExpr (parse, tag, expr)) { FcConfigMessage (parse, FcSevereError, "out of memory"); - if (expr) - FcExprDestroy (expr); + FcExprDestroy (expr); } } } @@ -1036,14 +1563,14 @@ FcParseFamily (FcConfigParse *parse) if (!parse->pstack) return; - s = FcStrBufDone (&parse->pstack->str); + s = FcStrBufDoneStatic (&parse->pstack->str); if (!s) { FcConfigMessage (parse, FcSevereError, "out of memory"); return; } - expr = FcExprCreateString (s); - FcStrFree (s); + expr = FcExprCreateString (parse->config, s); + FcStrBufDestroy (&parse->pstack->str); if (expr) FcVStackPushExpr (parse, FcVStackFamily, expr); } @@ -1055,14 +1582,17 @@ FcParseAlias (FcConfigParse *parse) FcEdit *edit = 0, *next; FcVStack *vstack; FcTest *test; + FcValueBinding binding; - while ((vstack = FcVStackPop (parse))) + if (!FcConfigLexBinding (parse, FcConfigGetAttribute (parse, "binding"), &binding)) + return; + while ((vstack = FcVStackPeek (parse))) { switch (vstack->tag) { case FcVStackFamily: if (family) { - new = FcExprCreateOp (vstack->u.expr, FcOpComma, family); + new = FcExprCreateOp (parse->config, vstack->u.expr, FcOpComma, family); if (!new) FcConfigMessage (parse, FcSevereError, "out of memory"); else @@ -1098,7 +1628,7 @@ FcParseAlias (FcConfigParse *parse) FcConfigMessage (parse, FcSevereWarning, "bad alias"); break; } - FcVStackDestroy (vstack); + FcVStackPopAndDestroy (parse); } if (!family) { @@ -1113,9 +1643,11 @@ FcParseAlias (FcConfigParse *parse) } if (prefer) { - edit = FcEditCreate (FcConfigSaveField ("family"), + edit = FcEditCreate (parse, + FC_FAMILY_OBJECT, FcOpPrepend, - prefer); + prefer, + binding); if (edit) edit->next = 0; else @@ -1124,9 +1656,11 @@ FcParseAlias (FcConfigParse *parse) if (accept) { next = edit; - edit = FcEditCreate (FcConfigSaveField ("family"), + edit = FcEditCreate (parse, + FC_FAMILY_OBJECT, FcOpAppend, - accept); + accept, + binding); if (edit) edit->next = next; else @@ -1135,9 +1669,11 @@ FcParseAlias (FcConfigParse *parse) if (def) { next = edit; - edit = FcEditCreate (FcConfigSaveField ("family"), - FcOpAppendLast, - def); + edit = FcEditCreate (parse, + FC_FAMILY_OBJECT, + FcOpAppendLast, + def, + binding); if (edit) edit->next = next; else @@ -1145,8 +1681,9 @@ FcParseAlias (FcConfigParse *parse) } if (edit) { - test = FcTestCreate (FcQualAny, - FC_FAMILY, + test = FcTestCreate (parse, FcMatchPattern, + FcQualAny, + (FcChar8 *) FC_FAMILY, FcOpEqual, family); if (test) @@ -1160,7 +1697,7 @@ FcParseAlias (FcConfigParse *parse) static FcExpr * FcPopExpr (FcConfigParse *parse) { - FcVStack *vstack = FcVStackPop (parse); + FcVStack *vstack = FcVStackPeek (parse); FcExpr *expr = 0; if (!vstack) return 0; @@ -1169,13 +1706,16 @@ FcPopExpr (FcConfigParse *parse) break; case FcVStackString: case FcVStackFamily: - expr = FcExprCreateString (vstack->u.string); + expr = FcExprCreateString (parse->config, vstack->u.string); break; case FcVStackField: - expr = FcExprCreateField ((char *) vstack->u.string); + expr = FcExprCreateField (parse->config, (char *) vstack->u.string); break; case FcVStackConstant: - expr = FcExprCreateConst (vstack->u.string); + expr = FcExprCreateConst (parse->config, vstack->u.string); + break; + case FcVStackGlob: + /* XXX: What's the correct action here? (CDW) */ break; case FcVStackPrefer: case FcVStackAccept: @@ -1184,16 +1724,24 @@ FcPopExpr (FcConfigParse *parse) vstack->tag = FcVStackNone; break; case FcVStackInteger: - expr = FcExprCreateInteger (vstack->u.integer); + expr = FcExprCreateInteger (parse->config, vstack->u.integer); break; case FcVStackDouble: - expr = FcExprCreateDouble (vstack->u._double); + expr = FcExprCreateDouble (parse->config, vstack->u._double); break; case FcVStackMatrix: - expr = FcExprCreateMatrix (vstack->u.matrix); + expr = FcExprCreateMatrix (parse->config, vstack->u.matrix); + break; + case FcVStackRange: break; case FcVStackBool: - expr = FcExprCreateBool (vstack->u.bool); + 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; @@ -1203,13 +1751,24 @@ FcPopExpr (FcConfigParse *parse) break; case FcVStackEdit: break; + default: + break; } - FcVStackDestroy (vstack); + 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 * -FcPopExprs (FcConfigParse *parse, FcOp op) +FcPopBinary (FcConfigParse *parse, FcOp op) { FcExpr *left, *expr = 0, *new; @@ -1217,13 +1776,13 @@ FcPopExprs (FcConfigParse *parse, FcOp op) { if (expr) { - new = FcExprCreateOp (left, op, expr); + new = FcExprCreateOp (parse->config, left, op, expr); if (!new) { FcConfigMessage (parse, FcSevereError, "out of memory"); FcExprDestroy (left); FcExprDestroy (expr); - break; + return 0; } expr = new; } @@ -1234,9 +1793,39 @@ FcPopExprs (FcConfigParse *parse, FcOp op) } static void -FcParseExpr (FcConfigParse *parse, FcOp op) +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 = FcPopExprs (parse, op); + FcExpr *expr = FcPopUnary (parse, op); if (expr) FcVStackPushExpr (parse, FcVStackExpr, expr); } @@ -1247,23 +1836,23 @@ FcParseInclude (FcConfigParse *parse) FcChar8 *s; const FcChar8 *i; FcBool ignore_missing = FcFalse; - - s = FcStrBufDone (&parse->pstack->str); + + s = FcStrBufDoneStatic (&parse->pstack->str); if (!s) { FcConfigMessage (parse, FcSevereError, "out of memory"); return; } i = FcConfigGetAttribute (parse, "ignore_missing"); - if (i && FcConfigLexBool ((FcChar8 *) i) == FcTrue) + if (i && FcConfigLexBool (parse, (FcChar8 *) i) == FcTrue) ignore_missing = FcTrue; if (!FcConfigParseAndLoad (parse->config, s, !ignore_missing)) parse->error = FcTrue; - free (s); + FcStrBufDestroy (&parse->pstack->str); } typedef struct _FcOpMap { - char *name; + char name[16]; FcOp op; } FcOpMap; @@ -1273,7 +1862,7 @@ FcConfigLexOp (const FcChar8 *op, const FcOpMap *map, int nmap) int i; for (i = 0; i < nmap; i++) - if (!strcmp ((char *) op, map[i].name)) + if (!strcmp ((char *) op, map[i].name)) return map[i].op; return FcOpInvalid; } @@ -1284,10 +1873,12 @@ static const FcOpMap fcCompareOps[] = { { "less", FcOpLess }, { "less_eq", FcOpLessEqual }, { "more", FcOpMore }, - { "more_eq", FcOpMoreEqual } + { "more_eq", FcOpMoreEqual }, + { "contains", FcOpContains }, + { "not_contains", FcOpNotContains } }; -#define NUM_COMPARE_OPS (sizeof fcCompareOps / sizeof fcCompareOps[0]) +#define NUM_COMPARE_OPS (int) (sizeof fcCompareOps / sizeof fcCompareOps[0]) static FcOp FcConfigLexCompare (const FcChar8 *compare) @@ -1295,10 +1886,11 @@ 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; @@ -1307,6 +1899,25 @@ FcParseTest (FcConfigParse *parse) 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; @@ -1316,17 +1927,21 @@ FcParseTest (FcConfigParse *parse) 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); - qual = FcQualAny; + return; } } name = FcConfigGetAttribute (parse, "name"); if (!name) { FcConfigMessage (parse, FcSevereWarning, "missing test name"); - name = (FcChar8 *) FC_FAMILY; + return; } compare_string = FcConfigGetAttribute (parse, "compare"); if (!compare_string) @@ -1337,16 +1952,16 @@ FcParseTest (FcConfigParse *parse) if (compare == FcOpInvalid) { FcConfigMessage (parse, FcSevereWarning, "invalid test compare \"%s\"", compare_string); - compare = FcOpEqual; + return; } } - expr = FcPopExprs (parse, FcOpComma); + expr = FcPopBinary (parse, FcOpComma); if (!expr) { FcConfigMessage (parse, FcSevereWarning, "missing test expression"); return; } - test = FcTestCreate (qual, name, compare, expr); + test = FcTestCreate (parse, kind, qual, name, compare, expr); if (!test) { FcConfigMessage (parse, FcSevereError, "out of memory"); @@ -1364,7 +1979,7 @@ static const FcOpMap fcModeOps[] = { { "append_last", FcOpAppendLast }, }; -#define NUM_MODE_OPS (sizeof fcModeOps / sizeof fcModeOps[0]) +#define NUM_MODE_OPS (int) (sizeof fcModeOps / sizeof fcModeOps[0]) static FcOp FcConfigLexMode (const FcChar8 *mode) @@ -1378,6 +1993,7 @@ FcParseEdit (FcConfigParse *parse) const FcChar8 *name; const FcChar8 *mode_string; FcOp mode; + FcValueBinding binding; FcExpr *expr; FcEdit *edit; @@ -1385,7 +2001,7 @@ FcParseEdit (FcConfigParse *parse) if (!name) { FcConfigMessage (parse, FcSevereWarning, "missing edit name"); - name = (FcChar8 *) FC_FAMILY; + return; } mode_string = FcConfigGetAttribute (parse, "mode"); if (!mode_string) @@ -1396,11 +2012,15 @@ FcParseEdit (FcConfigParse *parse) if (mode == FcOpInvalid) { FcConfigMessage (parse, FcSevereWarning, "invalid edit mode \"%s\"", mode_string); - mode = FcOpAssign; + return; } } - expr = FcPopExprs (parse, FcOpComma); - edit = FcEditCreate ((char *) FcStrCopy (name), mode, expr); + 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"); @@ -1429,13 +2049,15 @@ FcParseMatch (FcConfigParse *parse) 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); - kind = FcMatchPattern; + return; } } - while ((vstack = FcVStackPop (parse))) + while ((vstack = FcVStackPeek (parse))) { switch (vstack->tag) { case FcVStackTest: @@ -1447,23 +2069,196 @@ FcParseMatch (FcConfigParse *parse) 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; } - FcVStackDestroy (vstack); + 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) { @@ -1472,26 +2267,121 @@ FcEndElement(void *userData, const XML_Char *name) case FcElementFontconfig: break; case FcElementDir: - data = FcStrBufDone (&parse->pstack->str); + data = FcStrBufDoneStatic (&parse->pstack->str); if (!data) { FcConfigMessage (parse, FcSevereError, "out of memory"); break; } - if (!FcConfigAddDir (parse->config, data)) - FcConfigMessage (parse, FcSevereError, "out of memory"); - free (data); +#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 FcElementCache: + case FcElementCacheDir: data = FcStrBufDone (&parse->pstack->str); if (!data) { FcConfigMessage (parse, FcSevereError, "out of memory"); break; } - if (!FcConfigSetCache (parse->config, data)) +#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"); - free (data); + break; + } + /* discard this data; no longer used */ + FcStrBufDestroy (&parse->pstack->str); break; case FcElementInclude: FcParseInclude (parse); @@ -1544,13 +2434,33 @@ FcEndElement(void *userData, const XML_Char *name) case FcElementMatrix: FcParseMatrix (parse); break; + case FcElementRange: + FcParseRange (parse); + break; case FcElementBool: FcParseBool (parse); break; - case FcElementCharset: -/* FcParseCharset (parse); */ + 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; @@ -1558,46 +2468,64 @@ FcEndElement(void *userData, const XML_Char *name) FcParseString (parse, FcVStackConstant); break; case FcElementOr: - FcParseExpr (parse, FcOpOr); + FcParseBinary (parse, FcOpOr); break; case FcElementAnd: - FcParseExpr (parse, FcOpAnd); + FcParseBinary (parse, FcOpAnd); break; case FcElementEq: - FcParseExpr (parse, FcOpEqual); + FcParseBinary (parse, FcOpEqual); break; case FcElementNotEq: - FcParseExpr (parse, FcOpNotEqual); + FcParseBinary (parse, FcOpNotEqual); break; case FcElementLess: - FcParseExpr (parse, FcOpLess); + FcParseBinary (parse, FcOpLess); break; case FcElementLessEq: - FcParseExpr (parse, FcOpLessEqual); + FcParseBinary (parse, FcOpLessEqual); break; case FcElementMore: - FcParseExpr (parse, FcOpMore); + FcParseBinary (parse, FcOpMore); break; case FcElementMoreEq: - FcParseExpr (parse, FcOpMoreEqual); + FcParseBinary (parse, FcOpMoreEqual); + break; + case FcElementContains: + FcParseBinary (parse, FcOpContains); + break; + case FcElementNotContains: + FcParseBinary (parse, FcOpNotContains); break; case FcElementPlus: - FcParseExpr (parse, FcOpPlus); + FcParseBinary (parse, FcOpPlus); break; case FcElementMinus: - FcParseExpr (parse, FcOpMinus); + FcParseBinary (parse, FcOpMinus); break; case FcElementTimes: - FcParseExpr (parse, FcOpTimes); + FcParseBinary (parse, FcOpTimes); break; case FcElementDivide: - FcParseExpr (parse, FcOpDivide); + FcParseBinary (parse, FcOpDivide); break; case FcElementNot: - FcParseExpr (parse, FcOpNot); + FcParseUnary (parse, FcOpNot); break; case FcElementIf: - FcParseExpr (parse, FcOpQuest); + 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; @@ -1609,7 +2537,7 @@ 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)) @@ -1629,11 +2557,126 @@ FcStartDoctypeDecl (void *userData, 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, @@ -1642,49 +2685,104 @@ FcConfigParseAndLoad (FcConfig *config, XML_Parser p; FcChar8 *filename; - FILE *f; + int fd; int len; - void *buf; FcConfigParse parse; FcBool error = FcTrue; - + +#ifdef ENABLE_LIBXML2 + xmlSAXHandler sax; + char buf[BUFSIZ]; +#else + void *buf; +#endif + filename = FcConfigFilename (name); if (!filename) goto bail0; - f = fopen ((char *) filename, "r"); - free (filename); - if (!f) + + 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; } - len = fread (buf, 1, BUFSIZ, f); +#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", + FcConfigMessage (&parse, FcSevereError, "%s", XML_ErrorString (XML_GetErrorCode (p))); goto bail3; } @@ -1695,7 +2793,8 @@ bail3: bail2: XML_ParserFree (p); bail1: - fclose (f); + close (fd); + fd = -1; bail0: if (error && complain) { @@ -1707,3 +2806,6 @@ bail0: } return FcTrue; } +#define __fcxml__ +#include "fcaliastail.h" +#undef __fcxml__