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