From c2e7c611cbef33e9f93fbb110cd8df61abec67d7 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Mon, 18 Feb 2002 22:29:28 +0000 Subject: [PATCH] Switch fontconfig from libxml2 to expat --- src/Imakefile | 3 +- src/fccharset.c | 12 +- src/fcdbg.c | 20 +- src/fcint.h | 34 +- src/fcname.c | 98 +-- src/fcstr.c | 92 ++- src/fcxml.c | 1916 +++++++++++++++++++++++++++++++---------------- 7 files changed, 1402 insertions(+), 773 deletions(-) diff --git a/src/Imakefile b/src/Imakefile index baf27eb..ffda2fa 100644 --- a/src/Imakefile +++ b/src/Imakefile @@ -25,7 +25,8 @@ INCLUDES=$(FREETYPE2INCLUDES) $(LIBXML2INCLUDES) -I.. DEFINES=-DFC_FALLBACK_FONTS='"$(FALLBACK_FONTS)"' -REQUIREDLIBS=$(LDPRELIBS) $(FREETYPE2LIB) $(LIBXML2LIB) +EXPATLIB=-lexpat +REQUIREDLIBS=$(LDPRELIBS) $(FREETYPE2LIB) $(EXPATLIB) SRCS=fcblanks.c fccache.c fccfg.c fccharset.c fcdbg.c fcdefault.c fcdir.c \ fcfreetype.c fcfs.c fcinit.c fclist.c fcmatch.c fcmatrix.c fcname.c \ diff --git a/src/fccharset.c b/src/fccharset.c index 918f5ba..4652309 100644 --- a/src/fccharset.c +++ b/src/fccharset.c @@ -1,5 +1,5 @@ /* - * $XFree86: $ + * $XFree86: xc/lib/fontconfig/src/fccharset.c,v 1.2 2002/02/15 06:01:28 keithp Exp $ * * Copyright © 2001 Keith Packard, member of The XFree86 Project, Inc. * @@ -646,12 +646,12 @@ FcCharSetParseValue (FcChar8 *string, FcChar32 *value) } static FcBool -FcCharSetUnparseValue (FcNameBuf *buf, FcChar32 value) +FcCharSetUnparseValue (FcStrBuf *buf, FcChar32 value) { int i; if (value == 0) { - return FcNameBufChar (buf, ' '); + return FcStrBufChar (buf, ' '); } else { @@ -664,7 +664,7 @@ FcCharSetUnparseValue (FcNameBuf *buf, FcChar32 value) value /= 85; } for (i = 0; i < 5; i++) - if (!FcNameBufChar (buf, *s++)) + if (!FcStrBufChar (buf, *s++)) return FcFalse; } return FcTrue; @@ -704,7 +704,7 @@ bail0: } FcBool -FcNameUnparseCharSet (FcNameBuf *buf, const FcCharSet *c) +FcNameUnparseCharSet (FcStrBuf *buf, const FcCharSet *c) { FcCharSetIter ci; int i; @@ -729,7 +729,7 @@ FcNameUnparseCharSet (FcNameBuf *buf, const FcCharSet *c) FcCharSetIter ci, checki; /* null terminate for parser */ - FcNameBufChar (buf, '\0'); + FcStrBufChar (buf, '\0'); /* step back over null for life after test */ buf->len--; check = FcNameParseCharSet (buf->buf + len); diff --git a/src/fcdbg.c b/src/fcdbg.c index 78af630..53789d2 100644 --- a/src/fcdbg.c +++ b/src/fcdbg.c @@ -135,7 +135,10 @@ FcExprPrint (FcExpr *expr) expr->u.mval->yx, expr->u.mval->yy); case FcOpBool: printf ("%s", expr->u.bval ? "true" : "false"); break; + case FcOpCharSet: printf ("charset\n"); break; + case FcOpNil: printf ("nil\n"); case FcOpField: printf ("%s", expr->u.field); break; + case FcOpConst: printf ("%s", expr->u.constant); break; case FcOpQuest: FcExprPrint (expr->u.tree.left); printf (" quest "); @@ -143,6 +146,12 @@ FcExprPrint (FcExpr *expr) printf (" colon "); FcExprPrint (expr->u.tree.right->u.tree.right); break; + case FcOpAssign: + case FcOpAssignReplace: + case FcOpPrependFirst: + case FcOpPrepend: + case FcOpAppend: + case FcOpAppendLast: case FcOpOr: case FcOpAnd: case FcOpEqual: @@ -156,9 +165,16 @@ FcExprPrint (FcExpr *expr) case FcOpMinus: case FcOpTimes: case FcOpDivide: + case FcOpComma: FcExprPrint (expr->u.tree.left); printf (" "); switch (expr->op) { + case FcOpAssign: printf ("Assign"); break; + case FcOpAssignReplace: printf ("AssignReplace"); break; + case FcOpPrependFirst: printf ("PrependFirst"); break; + case FcOpPrepend: printf ("Prepend"); break; + case FcOpAppend: printf ("Append"); break; + case FcOpAppendLast: printf ("AppendLast"); break; case FcOpOr: printf ("Or"); break; case FcOpAnd: printf ("And"); break; case FcOpEqual: printf ("Equal"); break; @@ -172,6 +188,7 @@ FcExprPrint (FcExpr *expr) case FcOpMinus: printf ("Minus"); break; case FcOpTimes: printf ("Times"); break; case FcOpDivide: printf ("Divide"); break; + case FcOpComma: printf ("Comma"); break; default: break; } printf (" "); @@ -181,8 +198,7 @@ FcExprPrint (FcExpr *expr) printf ("Not "); FcExprPrint (expr->u.tree.left); break; - default: - break; + case FcOpInvalid: printf ("Invalid"); break; } } diff --git a/src/fcint.h b/src/fcint.h index 2d9b13f..dfdca44 100644 --- a/src/fcint.h +++ b/src/fcint.h @@ -1,5 +1,5 @@ /* - * $XFree86: $ + * $XFree86: xc/lib/fontconfig/src/fcint.h,v 1.2 2002/02/15 06:01:28 keithp Exp $ * * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc. * @@ -33,10 +33,8 @@ #include #include #include -#include #include #include -#include #ifdef HAVE_CONFIG_H #include #endif @@ -175,13 +173,13 @@ struct _FcCharSet { FcCharNode node; }; -typedef struct _FcNameBuf { +typedef struct _FcStrBuf { FcChar8 *buf; FcBool allocated; FcBool failed; int len; int size; -} FcNameBuf; +} FcStrBuf; typedef struct _FcFileCacheEnt { struct _FcFileCacheEnt *next; @@ -315,7 +313,7 @@ FcConfigCompareValue (const FcValue m, /* fccharset.c */ FcBool -FcNameUnparseCharSet (FcNameBuf *buf, const FcCharSet *c); +FcNameUnparseCharSet (FcStrBuf *buf, const FcCharSet *c); FcCharSet * FcNameParseCharSet (FcChar8 *string); @@ -372,7 +370,7 @@ char * FcConfigSaveField (const char *field); FcTest * -FcTestCreate (FcQual qual, const char *field, FcOp compare, FcExpr *expr); +FcTestCreate (FcQual qual, const FcChar8 *field, FcOp compare, FcExpr *expr); void FcTestDestroy (FcTest *test); @@ -434,10 +432,10 @@ FcBool FcNameBool (FcChar8 *v, FcBool *result); FcBool -FcNameBufChar (FcNameBuf *buf, FcChar8 c); +FcStrBufChar (FcStrBuf *buf, FcChar8 c); FcBool -FcNameBufString (FcNameBuf *buf, const FcChar8 *s); +FcStrBufString (FcStrBuf *buf, const FcChar8 *s); /* fcpat.c */ void @@ -459,4 +457,22 @@ FcStrPlus (const FcChar8 *s1, const FcChar8 *s2); void FcStrFree (FcChar8 *s); +void +FcStrBufInit (FcStrBuf *buf, FcChar8 *init, int size); + +void +FcStrBufDestroy (FcStrBuf *buf); + +FcChar8 * +FcStrBufDone (FcStrBuf *buf); + +FcBool +FcStrBufChar (FcStrBuf *buf, FcChar8 c); + +FcBool +FcStrBufString (FcStrBuf *buf, const FcChar8 *s); + +FcBool +FcStrBufData (FcStrBuf *buf, const FcChar8 *s, int len); + #endif /* _FC_INT_H_ */ diff --git a/src/fcname.c b/src/fcname.c index 784171c..57a72c8 100644 --- a/src/fcname.c +++ b/src/fcname.c @@ -1,5 +1,5 @@ /* - * $XFree86: xc/lib/Fc/xftname.c,v 1.10 2001/03/30 18:50:18 keithp Exp $ + * $XFree86: xc/lib/fontconfig/src/fcname.c,v 1.2 2002/02/15 06:01:28 keithp Exp $ * * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc. * @@ -418,86 +418,8 @@ bail1: bail0: return 0; } - -static void -FcNameBufInit (FcNameBuf *buf, FcChar8 *init, int size) -{ - buf->buf = init; - buf->allocated = FcFalse; - buf->failed = FcFalse; - buf->len = 0; - buf->size = size; -} - -static void -FcNameBufDestroy (FcNameBuf *buf) -{ - if (buf->allocated) - free (buf->buf); -} - -static FcChar8 * -FcNameBufDone (FcNameBuf *buf) -{ - FcChar8 *ret; - - ret = malloc (buf->len + 1); - if (ret) - { - memcpy (ret, buf->buf, buf->len); - ret[buf->len] = '\0'; - } - FcNameBufDestroy (buf); - return ret; -} - -FcBool -FcNameBufChar (FcNameBuf *buf, FcChar8 c) -{ - if (buf->len == buf->size) - { - FcChar8 *new; - int size; - - if (buf->allocated) - { - size = buf->size * 2; - new = realloc (buf->buf, size); - } - else - { - size = buf->size + 1024; - new = malloc (size); - if (new) - { - buf->allocated = FcTrue; - memcpy (new, buf->buf, buf->len); - } - } - if (!new) - { - buf->failed = FcTrue; - return FcFalse; - } - buf->size = size; - buf->buf = new; - } - buf->buf[buf->len++] = c; - return FcTrue; -} - -FcBool -FcNameBufString (FcNameBuf *buf, const FcChar8 *s) -{ - FcChar8 c; - while ((c = *s++)) - if (!FcNameBufChar (buf, c)) - return FcFalse; - return FcTrue; -} - static FcBool -FcNameUnparseString (FcNameBuf *buf, +FcNameUnparseString (FcStrBuf *buf, const FcChar8 *string, const FcChar8 *escape) { @@ -506,17 +428,17 @@ FcNameUnparseString (FcNameBuf *buf, { if (escape && strchr ((char *) escape, (char) c)) { - if (!FcNameBufChar (buf, escape[0])) + if (!FcStrBufChar (buf, escape[0])) return FcFalse; } - if (!FcNameBufChar (buf, c)) + if (!FcStrBufChar (buf, c)) return FcFalse; } return FcTrue; } static FcBool -FcNameUnparseValue (FcNameBuf *buf, +FcNameUnparseValue (FcStrBuf *buf, FcValue v, FcChar8 *escape) { @@ -546,7 +468,7 @@ FcNameUnparseValue (FcNameBuf *buf, } static FcBool -FcNameUnparseValueList (FcNameBuf *buf, +FcNameUnparseValueList (FcStrBuf *buf, FcValueList *v, FcChar8 *escape) { @@ -567,14 +489,14 @@ FcNameUnparseValueList (FcNameBuf *buf, FcChar8 * FcNameUnparse (FcPattern *pat) { - FcNameBuf buf; + FcStrBuf buf; FcChar8 buf_static[8192]; int i; FcPatternElt *e; const FcObjectTypeList *l; const FcObjectType *o; - FcNameBufInit (&buf, buf_static, sizeof (buf_static)); + FcStrBufInit (&buf, buf_static, sizeof (buf_static)); e = FcPatternFind (pat, FC_FAMILY, FcFalse); if (e) { @@ -614,8 +536,8 @@ FcNameUnparse (FcPattern *pat) } } } - return FcNameBufDone (&buf); + return FcStrBufDone (&buf); bail0: - FcNameBufDestroy (&buf); + FcStrBufDestroy (&buf); return 0; } diff --git a/src/fcstr.c b/src/fcstr.c index de6b266..6cf7d70 100644 --- a/src/fcstr.c +++ b/src/fcstr.c @@ -1,5 +1,5 @@ /* - * $XFree86: $ + * $XFree86: xc/lib/fontconfig/src/fcstr.c,v 1.2 2002/02/15 06:01:28 keithp Exp $ * * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc. * @@ -186,3 +186,93 @@ FcUtf8Len (FcChar8 *string, *wchar = 1; return FcTrue; } + +void +FcStrBufInit (FcStrBuf *buf, FcChar8 *init, int size) +{ + buf->buf = init; + buf->allocated = FcFalse; + buf->failed = FcFalse; + buf->len = 0; + buf->size = size; +} + +void +FcStrBufDestroy (FcStrBuf *buf) +{ + if (buf->allocated) + { + free (buf->buf); + FcStrBufInit (buf, 0, 0); + } +} + +FcChar8 * +FcStrBufDone (FcStrBuf *buf) +{ + FcChar8 *ret; + + ret = malloc (buf->len + 1); + if (ret) + { + memcpy (ret, buf->buf, buf->len); + ret[buf->len] = '\0'; + } + FcStrBufDestroy (buf); + return ret; +} + +FcBool +FcStrBufChar (FcStrBuf *buf, FcChar8 c) +{ + if (buf->len == buf->size) + { + FcChar8 *new; + int size; + + if (buf->allocated) + { + size = buf->size * 2; + new = realloc (buf->buf, size); + } + else + { + size = buf->size + 1024; + new = malloc (size); + if (new) + { + buf->allocated = FcTrue; + memcpy (new, buf->buf, buf->len); + } + } + if (!new) + { + buf->failed = FcTrue; + return FcFalse; + } + buf->size = size; + buf->buf = new; + } + buf->buf[buf->len++] = c; + return FcTrue; +} + +FcBool +FcStrBufString (FcStrBuf *buf, const FcChar8 *s) +{ + FcChar8 c; + while ((c = *s++)) + if (!FcStrBufChar (buf, c)) + return FcFalse; + return FcTrue; +} + +FcBool +FcStrBufData (FcStrBuf *buf, const FcChar8 *s, int len) +{ + while (len-- > 0) + if (!FcStrBufChar (buf, *s++)) + return FcFalse; + return FcTrue; +} + diff --git a/src/fcxml.c b/src/fcxml.c index e7725cc..f31a93f 100644 --- a/src/fcxml.c +++ b/src/fcxml.c @@ -1,5 +1,5 @@ /* - * $XFree86: $ + * $XFree86: xc/lib/fontconfig/src/fcxml.c,v 1.2 2002/02/15 06:01:28 keithp Exp $ * * Copyright © 2002 Keith Packard, member of The XFree86 Project, Inc. * @@ -23,52 +23,19 @@ */ #include +#include #include "fcint.h" -static xmlParserInputPtr -FcEntityLoader (const char *url, const char *id, xmlParserCtxtPtr ctxt) -{ - xmlParserInputPtr ret; - FcChar8 *file; - - file = FcConfigFilename ((FcChar8 *) url); - if (!file) - return 0; - ret = xmlNewInputFromFile (ctxt, (char *) file); - free (file); - return ret; -} - -xmlDocPtr -FcConfigLoad (const FcChar8 *file) -{ - xmlDocPtr doc; - xmlExternalEntityLoader previous; - - previous = xmlGetExternalEntityLoader (); - xmlSetExternalEntityLoader (FcEntityLoader); - doc = xmlParseFile ((char *) file); - xmlSetExternalEntityLoader (previous); - return doc; -} - -#if 0 -int -FcConfigSave (char *file, xmlDocPtr doc) -{ -} -#endif - FcTest * -FcTestCreate (FcQual qual, const char *field, FcOp compare, FcExpr *expr) +FcTestCreate (FcQual qual, const FcChar8 *field, FcOp compare, FcExpr *expr) { - FcTest *test = (FcTest *) malloc (sizeof (FcTest));; + FcTest *test = (FcTest *) malloc (sizeof (FcTest)); if (test) { test->next = 0; test->qual = qual; - test->field = (char *) FcStrCopy ((FcChar8 *) field); + test->field = (char *) FcStrCopy (field); test->op = compare; test->expr = expr; } @@ -292,99 +259,651 @@ FcConfigSaveField (const char *field) return (char *) FcStrCopy ((FcChar8 *) field); } +typedef enum _FcElement { + FcElementNone, + FcElementFontconfig, + FcElementDir, + FcElementCache, + FcElementInclude, + FcElementConfig, + FcElementMatch, + FcElementAlias, + + FcElementBlank, + + FcElementPrefer, + FcElementAccept, + FcElementDefault, + FcElementFamily, + + FcElementTest, + FcElementEdit, + FcElementInt, + FcElementDouble, + FcElementString, + FcElementMatrix, + FcElementBool, + FcElementCharset, + FcElementName, + FcElementConst, + FcElementOr, + FcElementAnd, + FcElementEq, + FcElementNotEq, + FcElementLess, + FcElementLessEq, + FcElementMore, + FcElementMoreEq, + FcElementPlus, + FcElementMinus, + FcElementTimes, + FcElementDivide, + FcElementNot, + FcElementIf, + FcElementUnknown +} FcElement; + +static FcElement +FcElementMap (const XML_Char *name) +{ + static struct { + char *name; + FcElement element; + } fcElementMap[] = { + { "fontconfig", FcElementFontconfig }, + { "dir", FcElementDir }, + { "cache", FcElementCache }, + { "include", FcElementInclude }, + { "config", FcElementConfig }, + { "match", FcElementMatch }, + { "alias", FcElementAlias }, + + { "blank", FcElementBlank }, + + { "prefer", FcElementPrefer }, + { "accept", FcElementAccept }, + { "default", FcElementDefault }, + { "family", FcElementFamily }, + + { "test", FcElementTest }, + { "edit", FcElementEdit }, + { "int", FcElementInt }, + { "double", FcElementDouble }, + { "string", FcElementString }, + { "matrix", FcElementMatrix }, + { "bool", FcElementBool }, + { "charset", FcElementCharset }, + { "name", FcElementName }, + { "const", FcElementConst }, + { "or", FcElementOr }, + { "and", FcElementAnd }, + { "eq", FcElementEq }, + { "not_eq", FcElementNotEq }, + { "less", FcElementLess }, + { "less_eq", FcElementLessEq }, + { "more", FcElementMore }, + { "more_eq", FcElementMoreEq }, + { "plus", FcElementPlus }, + { "minus", FcElementMinus }, + { "times", FcElementTimes }, + { "divide", FcElementDivide }, + { "not", FcElementNot }, + { "if", FcElementIf }, + + { 0, 0 } + }; + + int i; + for (i = 0; fcElementMap[i].name; i++) + if (!strcmp ((char *) name, fcElementMap[i].name)) + return fcElementMap[i].element; + return FcElementUnknown; +} + +typedef struct _FcPStack { + struct _FcPStack *prev; + FcElement element; + FcChar8 **attr; + FcStrBuf str; +} FcPStack; + +typedef enum _FcVStackTag { + FcVStackNone, + + FcVStackString, + FcVStackFamily, + FcVStackField, + FcVStackConstant, + + FcVStackPrefer, + FcVStackAccept, + FcVStackDefault, + + FcVStackInteger, + FcVStackDouble, + FcVStackMatrix, + FcVStackBool, + + FcVStackTest, + FcVStackExpr, + FcVStackEdit +} FcVStackTag; + +typedef struct _FcVStack { + struct _FcVStack *prev; + FcPStack *pstack; /* related parse element */ + FcVStackTag tag; + union { + FcChar8 *string; + + int integer; + double _double; + FcMatrix *matrix; + FcBool bool; + + FcTest *test; + FcQual qual; + FcOp op; + FcExpr *expr; + FcEdit *edit; + } u; +} FcVStack; + +typedef struct _FcConfigParse { + FcPStack *pstack; + FcVStack *vstack; + FcBool error; + const FcChar8 *name; + FcConfig *config; + XML_Parser parser; +} FcConfigParse; + static void -FcConfigParseError (char *fmt, ...) +FcConfigError (FcConfigParse *parse, char *fmt, ...) { va_list args; va_start (args, fmt); - fprintf (stderr, "font configuration error: "); + if (parse) + { + if (parse->name) + fprintf (stderr, "Fontconfig error: \"%s\", line %d: ", + parse->name, XML_GetCurrentLineNumber (parse->parser)); + else + fprintf (stderr, "Fontconfig error: line %d: ", + XML_GetCurrentLineNumber (parse->parser)); + parse->error = FcTrue; + } + else + fprintf (stderr, "Fontconfig error: "); vfprintf (stderr, fmt, args); fprintf (stderr, "\n"); va_end (args); } -static xmlChar * -FcConfigContent (xmlDocPtr doc, - xmlNodePtr node) +static void +FcVStackPush (FcConfigParse *parse, FcVStack *vstack) { - xmlChar *content; - - content = xmlNodeListGetString (doc, node->children, 1); - if (!content) - { - FcConfigParseError ("<%s> must have content", - node->name); - return FcFalse; - } - return content; + vstack->prev = parse->vstack; + vstack->pstack = parse->pstack ? parse->pstack->prev : 0; + parse->vstack = vstack; } -static xmlChar * -FcConfigAttr (xmlDocPtr doc, - xmlAttrPtr attr) +static FcVStack * +FcVStackCreate (void) { - xmlChar *content; - - content = xmlNodeListGetString (doc, attr->children, 1); - if (!content) - { - FcConfigParseError ("attribute %s must have a value", - attr->name); - return FcFalse; - } - return content; + FcVStack *new; + + new = malloc (sizeof (FcVStack)); + if (!new) + return 0; + new->tag = FcVStackNone; + new->prev = 0; + return new; } -static struct { - char *name; - FcOp op; -} fcOps[] = { - { "int", FcOpInteger }, - { "double", FcOpDouble }, - { "string", FcOpString }, - { "matrix", FcOpMatrix }, - { "bool", FcOpBool }, - { "charset", FcOpCharSet }, - { "name", FcOpField }, - { "const", FcOpConst }, - { "field", FcOpField }, - { "if", FcOpQuest }, - { "or", FcOpOr }, - { "and", FcOpAnd }, - { "eq", FcOpEqual }, - { "not_eq", FcOpNotEqual }, - { "less", FcOpLess }, - { "less_eq", FcOpLessEqual }, - { "more", FcOpMore }, - { "more_eq", FcOpMoreEqual }, - { "plus", FcOpPlus }, - { "minus", FcOpMinus }, - { "times", FcOpTimes }, - { "divide", FcOpDivide }, - { "not", FcOpNot }, - { "assign", FcOpAssign }, - { "assign_replace", FcOpAssignReplace }, - { "prepend", FcOpPrepend }, - { "prepend_first", FcOpPrependFirst }, - { "append", FcOpAppend }, - { "append_last", FcOpAppendLast }, -}; - -#define NUM_OPS (sizeof fcOps / sizeof fcOps[0]) - -static FcOp -FcConfigLexOp (const xmlChar *op) +static void +FcVStackDestroy (FcVStack *vstack) { - int i; + FcVStack *prev; - for (i = 0; i < NUM_OPS; i++) - if (!strcmp (op, fcOps[i].name)) return fcOps[i].op; - return FcOpInvalid; + for (; vstack; vstack = prev) + { + prev = vstack->prev; + switch (vstack->tag) { + case FcVStackNone: + break; + case FcVStackString: + case FcVStackFamily: + case FcVStackField: + case FcVStackConstant: + FcStrFree (vstack->u.string); + break; + case FcVStackInteger: + case FcVStackDouble: + break; + case FcVStackMatrix: + FcMatrixFree (vstack->u.matrix); + break; + case FcVStackBool: + break; + case FcVStackTest: + FcTestDestroy (vstack->u.test); + break; + case FcVStackExpr: + case FcVStackPrefer: + case FcVStackAccept: + case FcVStackDefault: + FcExprDestroy (vstack->u.expr); + break; + case FcVStackEdit: + FcEditDestroy (vstack->u.edit); + break; + } + free (vstack); + } } static FcBool -FcConfigLexBool (const xmlChar *bool) +FcVStackPushString (FcConfigParse *parse, FcVStackTag tag, FcChar8 *string) +{ + FcVStack *vstack = FcVStackCreate (); + if (!vstack) + return FcFalse; + vstack->u.string = string; + vstack->tag = tag; + FcVStackPush (parse, vstack); + return FcTrue; +} + +static FcBool +FcVStackPushInteger (FcConfigParse *parse, int integer) +{ + FcVStack *vstack = FcVStackCreate (); + if (!vstack) + return FcFalse; + vstack->u.integer = integer; + vstack->tag = FcVStackInteger; + FcVStackPush (parse, vstack); + return FcTrue; +} + +static FcBool +FcVStackPushDouble (FcConfigParse *parse, double _double) +{ + FcVStack *vstack = FcVStackCreate (); + if (!vstack) + return FcFalse; + vstack->u._double = _double; + vstack->tag = FcVStackDouble; + FcVStackPush (parse, vstack); + return FcTrue; +} + +static FcBool +FcVStackPushMatrix (FcConfigParse *parse, FcMatrix *matrix) +{ + FcVStack *vstack = FcVStackCreate (); + if (!vstack) + return FcFalse; + matrix = FcMatrixCopy (matrix); + if (!matrix) + { + FcVStackDestroy (vstack); + return FcFalse; + } + vstack->u.matrix = matrix; + vstack->tag = FcVStackMatrix; + FcVStackPush (parse, vstack); + return FcTrue; +} + +static FcBool +FcVStackPushBool (FcConfigParse *parse, FcBool bool) +{ + FcVStack *vstack = FcVStackCreate (); + if (!vstack) + return FcFalse; + vstack->u.bool = bool; + vstack->tag = FcVStackBool; + FcVStackPush (parse, vstack); + return FcTrue; +} + +static FcBool +FcVStackPushTest (FcConfigParse *parse, FcTest *test) +{ + FcVStack *vstack = FcVStackCreate (); + if (!vstack) + return FcFalse; + vstack->u.test = test; + vstack->tag = FcVStackTest; + FcVStackPush (parse, vstack); + return FcTrue; +} + +static FcBool +FcVStackPushExpr (FcConfigParse *parse, FcVStackTag tag, FcExpr *expr) +{ + FcVStack *vstack = FcVStackCreate (); + if (!vstack) + return FcFalse; + vstack->u.expr = expr; + vstack->tag = tag; + FcVStackPush (parse, vstack); + return FcTrue; +} + +static FcBool +FcVStackPushEdit (FcConfigParse *parse, FcEdit *edit) +{ + FcVStack *vstack = FcVStackCreate (); + if (!vstack) + return FcFalse; + vstack->u.edit = edit; + vstack->tag = FcVStackEdit; + FcVStackPush (parse, vstack); + return FcTrue; +} + +static FcVStack * +FcVStackFetch (FcConfigParse *parse, int off) +{ + FcVStack *vstack; + + for (vstack = parse->vstack; vstack && off-- > 0; vstack = vstack->prev); + return vstack; +} + +static void +FcVStackClear (FcConfigParse *parse) +{ + while (parse->vstack && parse->vstack->pstack == parse->pstack) + { + FcVStack *vstack = parse->vstack; + parse->vstack = vstack->prev; + vstack->prev = 0; + FcVStackDestroy (vstack); + } +} + +static FcVStack * +FcVStackPop (FcConfigParse *parse) +{ + FcVStack *vstack = parse->vstack; + + if (!vstack || vstack->pstack != parse->pstack) + return 0; + parse->vstack = vstack->prev; + vstack->prev = 0; + return vstack; +} + +static int +FcVStackElements (FcConfigParse *parse) +{ + int h = 0; + FcVStack *vstack = parse->vstack; + while (vstack && vstack->pstack == parse->pstack) + { + h++; + vstack = vstack->prev; + } + return h; +} + +static FcChar8 ** +FcConfigSaveAttr (const XML_Char **attr) +{ + int n; + int slen; + int i; + FcChar8 **new; + FcChar8 *s; + + if (!attr) + return 0; + slen = 0; + for (i = 0; attr[i]; i++) + slen += strlen (attr[i]) + 1; + n = i; + new = malloc ((i + 1) * sizeof (FcChar8 *) + slen); + if (!new) + return 0; + s = (FcChar8 *) (new + (i + 1)); + for (i = 0; attr[i]; i++) + { + new[i] = s; + strcpy ((char *) s, (char *) attr[i]); + s += strlen ((char *) s) + 1; + } + new[i] = 0; + return new; +} + +static FcBool +FcPStackPush (FcConfigParse *parse, FcElement element, const XML_Char **attr) +{ + FcPStack *new = malloc (sizeof (FcPStack)); + + if (!new) + return FcFalse; + new->prev = parse->pstack; + new->element = element; + if (attr) + { + new->attr = FcConfigSaveAttr (attr); + if (!new->attr) + FcConfigError (parse, "out of memory"); + } + else + new->attr = 0; + FcStrBufInit (&new->str, 0, 0); + parse->pstack = new; + return FcTrue; +} + +static FcBool +FcPStackPop (FcConfigParse *parse) +{ + FcPStack *old; + + if (!parse->pstack) + { + FcConfigError (parse, "mismatching element"); + return FcFalse; + } + FcVStackClear (parse); + old = parse->pstack; + parse->pstack = old->prev; + FcStrBufDestroy (&old->str); + if (old->attr) + free (old->attr); + free (old); + return FcTrue; +} + +static FcBool +FcConfigInit (FcConfigParse *parse, const FcChar8 *name, FcConfig *config, XML_Parser parser) +{ + parse->pstack = 0; + parse->vstack = 0; + parse->error = FcFalse; + parse->name = name; + parse->config = config; + parse->parser = parser; + return FcTrue; +} + +static void +FcConfigCleanup (FcConfigParse *parse) +{ + while (parse->pstack) + FcPStackPop (parse); +} + +static const FcChar8 * +FcConfigGetAttribute (FcConfigParse *parse, char *attr) +{ + FcChar8 **attrs; + if (!parse->pstack) + return 0; + + attrs = parse->pstack->attr; + while (*attrs) + { + if (!strcmp ((char *) *attrs, attr)) + return attrs[1]; + attrs += 2; + } + return 0; +} + +static void +FcStartElement(void *userData, const XML_Char *name, const XML_Char **attr) +{ + FcConfigParse *parse = userData; + FcElement element; + + element = FcElementMap (name); + if (element == FcElementUnknown) + { + FcConfigError (parse, "unknown element \"%s\"", name); + return; + } + + if (!FcPStackPush (parse, element, attr)) + { + FcConfigError (parse, "out of memory"); + return; + } + return; +} + +static void +FcParseBlank (FcConfigParse *parse) +{ + int n = FcVStackElements (parse); + while (n-- > 0) + { + FcVStack *v = FcVStackFetch (parse, n); + if (v->tag != FcVStackInteger) + FcConfigError (parse, "non-integer blank"); + else + { + if (!parse->config->blanks) + { + parse->config->blanks = FcBlanksCreate (); + if (!parse->config->blanks) + { + FcConfigError (parse, "out of memory"); + break; + } + } + if (!FcBlanksAdd (parse->config->blanks, v->u.integer)) + { + FcConfigError (parse, "out of memory"); + break; + } + } + } +} + +static void +FcParseInt (FcConfigParse *parse) +{ + FcChar8 *s, *end; + int l; + + if (!parse->pstack) + return; + s = FcStrBufDone (&parse->pstack->str); + if (!s) + { + FcConfigError (parse, "out of memory"); + return; + } + end = 0; + l = (int) strtol ((char *) s, (char **)&end, 0); + if (end != s + strlen ((char *) s)) + FcConfigError (parse, "\"%s\": not a valid integer", s); + else + FcVStackPushInteger (parse, l); + FcStrFree (s); +} + +static void +FcParseDouble (FcConfigParse *parse) +{ + FcChar8 *s, *end; + double d; + + if (!parse->pstack) + return; + s = FcStrBufDone (&parse->pstack->str); + if (!s) + { + FcConfigError (parse, "out of memory"); + return; + } + end = 0; + d = strtod ((char *) s, (char **)&end); + if (end != s + strlen ((char *) s)) + FcConfigError (parse, "\"%s\": not a valid double", s); + else + FcVStackPushDouble (parse, d); + FcStrFree (s); +} + +static void +FcParseString (FcConfigParse *parse, FcVStackTag tag) +{ + FcChar8 *s; + + if (!parse->pstack) + return; + s = FcStrBufDone (&parse->pstack->str); + if (!s) + { + FcConfigError (parse, "out of memory"); + return; + } + if (!FcVStackPushString (parse, tag, s)) + FcStrFree (s); +} + +static void +FcParseMatrix (FcConfigParse *parse) +{ + FcVStack *vstack; + enum { m_done, m_xx, m_xy, m_yx, m_yy } matrix_state = m_yy; + FcMatrix m; + + while ((vstack = FcVStackPop (parse))) + { + if (vstack->tag != FcVStackDouble) + FcConfigError (parse, "non-double matrix element"); + else + { + double v = vstack->u._double; + 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; + } + matrix_state--; + } + } + if (matrix_state != m_done) + FcConfigError (parse, "wrong number of matrix elements"); + else + FcVStackPushMatrix (parse, &m); +} + +static FcBool +FcConfigLexBool (const FcChar8 *bool) { if (*bool == 't' || *bool == 'T') return FcTrue; @@ -395,525 +914,131 @@ FcConfigLexBool (const xmlChar *bool) return FcFalse; } -static FcBool -FcConfigParseDir (FcConfig *config, - xmlDocPtr doc, - xmlNodePtr dir) +static void +FcParseBool (FcConfigParse *parse) { - xmlChar *content = FcConfigContent (doc, dir); + FcChar8 *s; - if (!content) - return FcFalse; - return FcConfigAddDir (config, (FcChar8 *) content); -} - -static FcBool -FcConfigParseCache (FcConfig *config, - xmlDocPtr doc, - xmlNodePtr dir) -{ - xmlChar *content = FcConfigContent (doc, dir); - - if (!content) - return FcFalse; - return FcConfigSetCache (config, (FcChar8 *) content); -} - -static FcBool -FcConfigParseInclude (FcConfig *config, - xmlDocPtr doc, - xmlNodePtr inc) -{ - xmlChar *content = FcConfigContent (doc, inc); - xmlAttr *attr; - FcBool complain = FcTrue; - - if (!content) - return FcFalse; - - for (attr = inc->properties; attr; attr = attr->next) + if (!parse->pstack) + return; + s = FcStrBufDone (&parse->pstack->str); + if (!s) { - if (attr->type != XML_ATTRIBUTE_NODE) - continue; - if (!strcmp (attr->name, "ignore_missing")) - complain = !FcConfigLexBool (FcConfigAttr (doc, attr)); + FcConfigError (parse, "out of memory"); + return; } - return FcConfigParseAndLoad (config, (FcChar8 *) content, complain); + FcVStackPushBool (parse, FcConfigLexBool (s)); + FcStrFree (s); } -static FcBool -FcConfigParseBlank (FcConfig *config, - xmlDocPtr doc, - xmlNodePtr blank) +static void +FcParseFamilies (FcConfigParse *parse, FcVStackTag tag) { - xmlNode *node; - FcChar32 ucs4; + FcVStack *vstack; + FcExpr *left, *expr = 0, *new; - for (node = blank->children; node; node = node->next) + while ((vstack = FcVStackPop (parse))) { - if (node->type != XML_ELEMENT_NODE) - continue; - if (!strcmp (node->name, "int")) + if (vstack->tag != FcVStackFamily) { - ucs4 = (FcChar32) strtol ((char *) FcConfigContent (doc, node), 0, 0); - if (!config->blanks) + FcConfigError (parse, "non-family"); + break; + } + left = vstack->u.expr; + vstack->tag = FcVStackNone; + FcVStackDestroy (vstack); + if (expr) + { + new = FcExprCreateOp (left, FcOpComma, expr); + if (!new) { - config->blanks = FcBlanksCreate (); - if (!config->blanks) - break; - } - if (!FcBlanksAdd (config->blanks, ucs4)) + FcConfigError (parse, "out of memory"); + FcExprDestroy (left); + FcExprDestroy (expr); break; - } - } - if (node) - return FcFalse; - return FcTrue; -} - -static FcBool -FcConfigParseConfig (FcConfig *config, - xmlDocPtr doc, - xmlNodePtr cfg) -{ - xmlNode *node; - - for (node = cfg->children; node; node = node->next) - { - if (node->type != XML_ELEMENT_NODE) - continue; - if (!strcmp (node->name, "blank")) - { - if (!FcConfigParseBlank (config, doc, node)) - break; - } - } - if (node) - return FcFalse; - return FcTrue; -} - -static FcMatrix * -FcConfigParseMatrix (xmlDocPtr doc, - xmlNodePtr node) -{ - static FcMatrix m; - enum { m_xx, m_xy, m_yx, m_yy, m_done } matrix_state = m_xx; - double v; - xmlChar *text; - - FcMatrixInit (&m); - - for (; node; node = node->next) - { - if (node->type != XML_ELEMENT_NODE) - continue; - if (strcmp (node->name, "double")) - continue; - text = FcConfigContent (doc, node); - if (!text) - continue; - v = strtod ((char *) text, 0); - 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; - } - matrix_state++; - } - - return &m; -} - -static FcExpr * -FcConfigParseExpr (xmlDocPtr doc, - xmlNodePtr expr) -{ - FcOp op = FcConfigLexOp (expr->name); - xmlNodePtr node; - FcExpr *l = 0, *e = 0, *r = 0, *c = 0; - - switch (op) { - case FcOpInteger: - l = FcExprCreateInteger (strtol ((char *) FcConfigContent (doc, expr), 0, 0)); - break; - case FcOpDouble: - l = FcExprCreateDouble (strtod ((char *) FcConfigContent (doc, expr), 0)); - break; - case FcOpString: - l = FcExprCreateString ((FcChar8 *) FcConfigContent (doc, expr)); - break; - case FcOpMatrix: - l = FcExprCreateMatrix (FcConfigParseMatrix (doc, expr)); - break; - case FcOpBool: - l = FcExprCreateBool (FcConfigLexBool(FcConfigContent (doc, expr))); - break; - case FcOpCharSet: - /* not sure what to do here yet */ - break; - case FcOpField: - l = FcExprCreateField ((char *) FcConfigContent (doc, expr)); - break; - case FcOpConst: - l = FcExprCreateConst ((FcChar8 *) FcConfigContent (doc, expr)); - break; - case FcOpQuest: - for (node = expr->children; node; node = node->next) - { - if (node->type != XML_ELEMENT_NODE) - continue; - e = FcConfigParseExpr (doc, node); - if (!e) - break; - if (!l) - l = e; - else if (!c) - c = e; - else if (!r) - r = e; - else - FcExprDestroy (e); - } - e = 0; - if (!node && l && c && r) - { - e = FcExprCreateOp (c, FcOpQuest, r); - if (e) - { - r = e; - c = 0; - e = FcExprCreateOp (l, FcOpQuest, r); } - if (!e) - node = expr->children; - } - if (node || !l || !c || !r || !e) - { - if (l) - FcExprDestroy (l); - if (c) - FcExprDestroy (c); - if (r) - FcExprDestroy (r); - return 0; - } - break; - default: - for (node = expr->children; node; node = node->next) - { - if (node->type != XML_ELEMENT_NODE) - continue; - e = FcConfigParseExpr (doc, node); - if (!e) - break; - if (!l) - l = e; - else - { - r = e; - e = FcExprCreateOp (l, op, r); - if (!e) - { - FcExprDestroy (r); - break; - } - l = e; - } - } - if (node || !l) - { - if (l) - FcExprDestroy (l); - return 0; - } - /* - * Special case for unary ops - */ - if (!r) - { - e = FcExprCreateOp (l, op, 0); - if (!e) - { - FcExprDestroy (l); - return 0; - } - } - break; - - case FcOpInvalid: - return 0; - } - return l; -} - -static FcTest * -FcConfigParseTest (xmlDocPtr doc, - xmlNodePtr test) -{ - xmlNodePtr node; - xmlAttrPtr attr; - FcQual qual = FcQualAny; - FcOp op = FcOpEqual; - xmlChar *field = 0; - FcExpr *expr = 0; - - for (attr = test->properties; attr; attr = attr->next) - { - if (attr->type != XML_ATTRIBUTE_NODE) - continue; - if (!strcmp (attr->name, "qual")) - { - xmlChar *qual_name = FcConfigAttr (doc, attr); - if (!qual_name) - ; - else if (!FcStrCmpIgnoreCase ((FcChar8 *) qual_name, (FcChar8 *) "any")) - qual = FcQualAny; - else if (!FcStrCmpIgnoreCase ((FcChar8 *) qual_name, (FcChar8 *) "all")) - qual = FcQualAll; - } - else if (!FcStrCmpIgnoreCase ((FcChar8 *) attr->name, (FcChar8 *) "name")) - { - field = FcConfigAttr (doc, attr); - } - else if (!FcStrCmpIgnoreCase ((FcChar8 *) attr->name, (FcChar8 *) "compare")) - { - xmlChar *compare = FcConfigAttr (doc, attr); - - if (!compare || (op = FcConfigLexOp (compare)) == FcOpInvalid) - { - FcConfigParseError ("Invalid comparison %s", - compare ? (char *) compare : ""); - return 0; - } - } - } - if (attr) - return 0; - - for (node = test->children; node; node = node->next) - { - if (node->type != XML_ELEMENT_NODE) - continue; - expr = FcConfigParseExpr (doc, node); - if (!expr) - return 0; - break; - } - - if (!expr) - { - FcConfigParseError ("Missing test expression"); - return 0; - } - - return FcTestCreate (qual, (char *) field, op, expr); -} - -static FcExpr * -FcConfigParseExprList (xmlDocPtr doc, - xmlNodePtr expr) -{ - FcExpr *l, *e, *r; - - if (!expr) - return 0; - - e = FcConfigParseExprList (doc, expr->next); - - if (expr->type == XML_ELEMENT_NODE) - { - r = e; - l = FcConfigParseExpr (doc, expr); - if (!l) - goto bail; - if (r) - { - e = FcExprCreateOp (l, FcOpComma, r); - if (!e) - goto bail; + expr = new; } else - e = l; + expr = left; } - - return e; -bail: - if (l) - FcExprDestroy (l); - if (r) - FcExprDestroy (r); - return 0; -} - -static FcEdit * -FcConfigParseEdit (xmlDocPtr doc, - xmlNodePtr edit) -{ - xmlAttrPtr attr; - xmlChar *name = 0; - FcOp mode = FcOpAssign; - FcExpr *e; - FcEdit *ed; - - for (attr = edit->properties; attr; attr = attr->next) - { - if (attr->type != XML_ATTRIBUTE_NODE) - continue; - if (!FcStrCmpIgnoreCase ((FcChar8 *) attr->name, (FcChar8 *) "name")) - name = FcConfigAttr (doc, attr); - else if (!FcStrCmpIgnoreCase ((FcChar8 *) attr->name, (FcChar8 *) "mode")) - mode = FcConfigLexOp (FcConfigAttr (doc, attr)); - } - - e = FcConfigParseExprList (doc, edit->children); - - ed = FcEditCreate ((char *) name, mode, e); - if (!ed) - FcExprDestroy (e); - return ed; -} - -static FcBool -FcConfigParseMatch (FcConfig *config, - xmlDocPtr doc, - xmlNodePtr match) -{ - xmlNodePtr node; - xmlAttrPtr attr; - FcTest *tests = 0, **prevTest = &tests, *test; - FcEdit *edits = 0, **prevEdit = &edits, *edit; - FcMatchKind kind = FcMatchPattern; - FcBool found_kind = FcFalse; - - for (node = match->children; node; node = node->next) - { - if (node->type != XML_ELEMENT_NODE) - continue; - if (!FcStrCmpIgnoreCase ((FcChar8 *) node->name, (FcChar8 *) "test")) - { - test = FcConfigParseTest (doc, node); - if (!test) - break; - *prevTest = test; - prevTest = &test->next; - } - else if (!FcStrCmpIgnoreCase ((FcChar8 *) node->name, (FcChar8 *) "edit")) - { - edit = FcConfigParseEdit (doc, node); - if (!edit) - break; - *prevEdit = edit; - prevEdit = &edit->next; - } - } - - for (attr = match->properties; attr; attr = attr->next) - { - if (attr->type != XML_ATTRIBUTE_NODE) - continue; - if (!FcStrCmpIgnoreCase ((FcChar8 *) attr->name, (FcChar8 *) "target")) - { - xmlChar *target = FcConfigAttr (doc, attr); - if (!target) - { - FcConfigParseError ("Missing match target"); - break; - } - else if (!FcStrCmpIgnoreCase ((FcChar8 *) target, (FcChar8 *) "pattern")) - { - kind = FcMatchPattern; - found_kind = FcTrue; - } - else if (!FcStrCmpIgnoreCase ((FcChar8 *) target, (FcChar8 *) "font")) - { - kind = FcMatchFont; - found_kind = FcTrue; - } - } - } - - if (node || attr || !found_kind || - !FcConfigAddEdit (config, tests, edits, kind)) - { - if (tests) - FcTestDestroy (tests); - if (edits) - FcEditDestroy (edits); - return FcFalse; - } - - return FcTrue; -} - -static FcExpr * -FcConfigParseFamilies (xmlDocPtr doc, - xmlNodePtr family) -{ - FcExpr *next = 0, *this = 0, *expr = 0; - - if (!family) - return 0; - next = FcConfigParseFamilies (doc, family->next); - - if (family->type == XML_ELEMENT_NODE && - !FcStrCmpIgnoreCase ((FcChar8 *) family->name, (FcChar8 *) "family")) - { - this = FcExprCreateString ((FcChar8 *) FcConfigContent (doc, family)); - if (!this) - goto bail; - if (next) - { - expr = FcExprCreateOp (this, FcOpComma, next); - if (!expr) - goto bail; - } - else - expr = this; - } - else - expr = next; - return expr; - -bail: if (expr) - FcExprDestroy (expr); - if (this) - FcExprDestroy (this); - if (next) - FcExprDestroy (next); - return 0; + { + if (!FcVStackPushExpr (parse, tag, expr)) + { + FcConfigError (parse, "out of memory"); + if (expr) + FcExprDestroy (expr); + } + } } -static FcBool -FcConfigParseAlias (FcConfig *config, - xmlDocPtr doc, - xmlNodePtr alias) +static void +FcParseFamily (FcConfigParse *parse) { - xmlNodePtr node; - FcExpr *prefer = 0, *accept = 0, *def = 0; - FcExpr *family = 0; + FcChar8 *s; + FcExpr *expr; + + if (!parse->pstack) + return; + s = FcStrBufDone (&parse->pstack->str); + if (!s) + { + FcConfigError (parse, "out of memory"); + return; + } + expr = FcExprCreateString (s); + FcStrFree (s); + if (expr) + FcVStackPushExpr (parse, FcVStackFamily, expr); +} + +static void +FcParseAlias (FcConfigParse *parse) +{ + FcExpr *family = 0, *accept = 0, *prefer = 0, *def = 0; FcEdit *edit = 0, *next; + FcVStack *vstack; FcTest *test; - for (node = alias->children; node; node = node->next) + while ((vstack = FcVStackPop (parse))) { - if (node->type != XML_ELEMENT_NODE) - continue; - if (!FcStrCmpIgnoreCase ((FcChar8 *) node->name, (FcChar8 *) "family")) - family = FcExprCreateString ((FcChar8 *) FcConfigContent (doc, node)); - else if (!FcStrCmpIgnoreCase ((FcChar8 *) node->name, (FcChar8 *) "prefer")) - prefer = FcConfigParseFamilies (doc, node->children); - else if (!FcStrCmpIgnoreCase ((FcChar8 *) node->name, (FcChar8 *) "accept")) - accept = FcConfigParseFamilies (doc, node->children); - else if (!FcStrCmpIgnoreCase ((FcChar8 *) node->name, (FcChar8 *) "default")) - def = FcConfigParseFamilies (doc, node->children); + switch (vstack->tag) { + case FcVStackFamily: + if (family) + FcExprDestroy (family); + family = vstack->u.expr; + 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: + FcConfigError (parse, "bad alias"); + break; + } + FcVStackDestroy (vstack); } if (!family) - return FcFalse; - + { + FcConfigError (parse, "missing family in alias"); + return; + } if (prefer) { edit = FcEditCreate (FcConfigSaveField ("family"), @@ -921,6 +1046,8 @@ FcConfigParseAlias (FcConfig *config, prefer); if (edit) edit->next = 0; + else + FcExprDestroy (prefer); } if (accept) { @@ -930,6 +1057,8 @@ FcConfigParseAlias (FcConfig *config, accept); if (edit) edit->next = next; + else + FcExprDestroy (accept); } if (def) { @@ -939,96 +1068,551 @@ FcConfigParseAlias (FcConfig *config, def); if (edit) edit->next = next; + else + FcExprDestroy (def); } if (edit) { test = FcTestCreate (FcQualAny, - FcConfigSaveField ("family"), + FcStrCopy ((FcChar8 *) "family"), FcOpEqual, family); if (test) - FcConfigAddEdit (config, test, edit, FcMatchPattern); + if (!FcConfigAddEdit (parse->config, test, edit, FcMatchPattern)) + FcTestDestroy (test); } - return FcTrue; + else + FcExprDestroy (family); } -FcBool -FcConfigParse (FcConfig *config, - xmlDocPtr doc) +static FcExpr * +FcPopExpr (FcConfigParse *parse) { - xmlNodePtr cur; - xmlNodePtr node; - - cur = xmlDocGetRootElement (doc); + FcVStack *vstack = FcVStackPop (parse); + FcExpr *expr = 0; + if (!vstack) + return 0; + switch (vstack->tag) { + case FcVStackNone: + break; + case FcVStackString: + case FcVStackFamily: + case FcVStackField: + case FcVStackConstant: + expr = FcExprCreateString (vstack->u.string); + break; + case FcVStackPrefer: + case FcVStackAccept: + case FcVStackDefault: + expr = vstack->u.expr; + vstack->tag = FcVStackNone; + break; + case FcVStackInteger: + expr = FcExprCreateInteger (vstack->u.integer); + break; + case FcVStackDouble: + expr = FcExprCreateDouble (vstack->u._double); + break; + case FcVStackMatrix: + expr = FcExprCreateMatrix (vstack->u.matrix); + break; + case FcVStackBool: + expr = FcExprCreateBool (vstack->u.bool); + break; + case FcVStackTest: + break; + case FcVStackExpr: + expr = vstack->u.expr; + break; + case FcVStackEdit: + break; + } + FcVStackDestroy (vstack); + return expr; +} - for (node = cur->children; node; node = node->next) +static FcExpr * +FcPopExprs (FcConfigParse *parse, FcOp op) +{ + FcExpr *left, *expr = 0, *new; + + while ((left = FcPopExpr (parse))) { - if (node->type != XML_ELEMENT_NODE) - continue; - if (!FcStrCmpIgnoreCase ((FcChar8 *) node->name, (FcChar8 *) "dir")) + if (expr) { - if (!FcConfigParseDir (config, doc, node)) - break; - } - else if (!FcStrCmpIgnoreCase ((FcChar8 *) node->name, (FcChar8 *) "cache")) - { - if (!FcConfigParseCache (config, doc, node)) - break; - } - else if (!FcStrCmpIgnoreCase ((FcChar8 *) node->name, (FcChar8 *) "include")) - { - if (!FcConfigParseInclude (config, doc, node)) - break; - } - else if (!FcStrCmpIgnoreCase ((FcChar8 *) node->name, (FcChar8 *) "config")) - { - if (!FcConfigParseConfig (config, doc, node)) - break; - } - else if (!FcStrCmpIgnoreCase ((FcChar8 *) node->name, (FcChar8 *) "match")) - { - if (!FcConfigParseMatch (config, doc, node)) - break; - } - else if (!FcStrCmpIgnoreCase ((FcChar8 *) node->name, (FcChar8 *) "alias")) - { - if (!FcConfigParseAlias (config, doc, node)) + new = FcExprCreateOp (left, op, expr); + if (!new) + { + FcConfigError (parse, "out of memory"); + FcExprDestroy (left); + FcExprDestroy (expr); break; + } + expr = new; } else - { - FcConfigParseError ("invalid element %s", node->name); - break; - } + expr = left; } - if (node) - return FcFalse; - return FcTrue; + return expr; +} + +static void +FcParseExpr (FcConfigParse *parse, FcOp op) +{ + FcExpr *expr = FcPopExprs (parse, op); + if (expr) + FcVStackPushExpr (parse, FcVStackExpr, expr); +} + +static void +FcParseInclude (FcConfigParse *parse) +{ + FcChar8 *s; + const FcChar8 *i; + FcBool ignore_missing = FcFalse; + + s = FcStrBufDone (&parse->pstack->str); + if (!s) + { + FcConfigError (parse, "out of memory"); + return; + } + i = FcConfigGetAttribute (parse, "ignore_missing"); + if (i && FcConfigLexBool ((FcChar8 *) i) == FcTrue) + ignore_missing = FcTrue; + if (!FcConfigParseAndLoad (parse->config, s, ignore_missing)) + parse->error = FcTrue; + free (s); +} + +typedef struct _FcOpMap { + char *name; + FcOp op; +} FcOpMap; + +static FcOp +FcConfigLexOp (const FcChar8 *op, const FcOpMap *map, int nmap) +{ + int i; + + for (i = 0; i < nmap; i++) + if (!strcmp ((char *) op, map[i].name)) + return map[i].op; + return FcOpInvalid; +} + +static const FcOpMap fcCompareOps[] = { + { "eq", FcOpEqual }, + { "not_eq", FcOpNotEqual }, + { "less", FcOpLess }, + { "less_eq", FcOpLessEqual }, + { "more", FcOpMore }, + { "more_eq", FcOpMoreEqual } +}; + +#define NUM_COMPARE_OPS (sizeof fcCompareOps / sizeof fcCompareOps[0]) + +static FcOp +FcConfigLexCompare (const FcChar8 *compare) +{ + return FcConfigLexOp (compare, fcCompareOps, NUM_COMPARE_OPS); +} + + +static void +FcParseTest (FcConfigParse *parse) +{ + const FcChar8 *qual_string; + FcQual qual; + const FcChar8 *name; + const FcChar8 *compare_string; + FcOp compare; + FcExpr *expr; + FcTest *test; + + 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 + { + FcConfigError (parse, "invalid test qual \"%s\"", qual_string); + return; + } + } + name = FcConfigGetAttribute (parse, "name"); + if (!name) + { + FcConfigError (parse, "missing test name"); + return; + } + compare_string = FcConfigGetAttribute (parse, "compare"); + if (!compare_string) + compare = FcOpEqual; + else + { + compare = FcConfigLexCompare (compare_string); + if (compare == FcOpInvalid) + { + FcConfigError (parse, "invalid test compare \"%s\"", compare_string); + return; + } + } + expr = FcPopExpr (parse); + if (!expr) + { + FcConfigError (parse, "missing test expression"); + return; + } + test = FcTestCreate (qual, name, compare, expr); + if (!test) + { + FcConfigError (parse, "out of memory"); + return; + } + FcVStackPushTest (parse, test); +} + +static const FcOpMap fcModeOps[] = { + { "assign", FcOpAssign }, + { "assign_replace", FcOpAssignReplace }, + { "prepend", FcOpPrepend }, + { "prepend_first", FcOpPrependFirst }, + { "append", FcOpAppend }, + { "append_last", FcOpAppendLast }, +}; + +#define NUM_MODE_OPS (sizeof fcModeOps / sizeof fcModeOps[0]) + +static FcOp +FcConfigLexMode (const FcChar8 *mode) +{ + return FcConfigLexOp (mode, fcModeOps, NUM_MODE_OPS); +} + +static void +FcParseEdit (FcConfigParse *parse) +{ + const FcChar8 *name; + const FcChar8 *mode_string; + FcOp mode; + FcExpr *expr; + FcEdit *edit; + + name = FcConfigGetAttribute (parse, "name"); + if (!name) + { + FcConfigError (parse, "missing edit name"); + return; + } + mode_string = FcConfigGetAttribute (parse, "mode"); + if (!mode_string) + mode = FcOpEqual; + else + { + mode = FcConfigLexMode (mode_string); + if (mode == FcOpInvalid) + { + FcConfigError (parse, "invalid edit mode \"%s\"", mode_string); + return; + } + } + expr = FcPopExprs (parse, FcOpComma); + edit = FcEditCreate ((char *) FcStrCopy (name), mode, expr); + if (!edit) + { + FcConfigError (parse, "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 + { + FcConfigError (parse, "invalid match target \"%s\"", kind_name); + return; + } + } + while ((vstack = FcVStackPop (parse))) + { + switch (vstack->tag) { + case FcVStackTest: + vstack->u.test->next = test; + test = vstack->u.test; + vstack->tag = FcVStackNone; + break; + case FcVStackEdit: + vstack->u.edit->next = edit; + edit = vstack->u.edit; + vstack->tag = FcVStackNone; + break; + default: + FcConfigError (parse, "invalid match element"); + break; + } + FcVStackDestroy (vstack); + } + if (!FcConfigAddEdit (parse->config, test, edit, kind)) + FcConfigError (parse, "out of memory"); +} + +static void +FcEndElement(void *userData, const XML_Char *name) +{ + FcConfigParse *parse = userData; + FcChar8 *data; + + if (!parse->pstack) + return; + switch (parse->pstack->element) { + case FcElementNone: + break; + case FcElementFontconfig: + break; + case FcElementDir: + data = FcStrBufDone (&parse->pstack->str); + if (!data) + { + FcConfigError (parse, "out of memory"); + break; + } + if (!FcConfigAddDir (parse->config, data)) + FcConfigError (parse, "out of memory"); + free (data); + break; + case FcElementCache: + data = FcStrBufDone (&parse->pstack->str); + if (!data) + { + FcConfigError (parse, "out of memory"); + break; + } + if (!FcConfigSetCache (parse->config, data)) + FcConfigError (parse, "out of memory"); + free (data); + break; + case FcElementInclude: + FcParseInclude (parse); + break; + case FcElementConfig: + break; + case FcElementMatch: + FcParseMatch (parse); + break; + case FcElementAlias: + FcParseAlias (parse); + break; + + case FcElementBlank: + FcParseBlank (parse); + break; + + case FcElementPrefer: + FcParseFamilies (parse, FcVStackPrefer); + break; + case FcElementAccept: + FcParseFamilies (parse, FcVStackAccept); + break; + case FcElementDefault: + FcParseFamilies (parse, FcVStackDefault); + break; + case FcElementFamily: + FcParseFamily (parse); + break; + + case FcElementTest: + FcParseTest (parse); + break; + case FcElementEdit: + FcParseEdit (parse); + break; + + case FcElementInt: + FcParseInt (parse); + break; + case FcElementDouble: + FcParseDouble (parse); + break; + case FcElementString: + FcParseString (parse, FcVStackString); + break; + case FcElementMatrix: + FcParseMatrix (parse); + break; + case FcElementBool: + FcParseBool (parse); + break; + case FcElementCharset: +/* FcParseCharset (parse); */ + break; + + case FcElementName: + FcParseString (parse, FcVStackField); + break; + case FcElementConst: + FcParseString (parse, FcVStackConstant); + break; + case FcElementOr: + FcParseExpr (parse, FcOpOr); + break; + case FcElementAnd: + FcParseExpr (parse, FcOpAnd); + break; + case FcElementEq: + FcParseExpr (parse, FcOpEqual); + break; + case FcElementNotEq: + FcParseExpr (parse, FcOpNotEqual); + break; + case FcElementLess: + FcParseExpr (parse, FcOpLess); + break; + case FcElementLessEq: + FcParseExpr (parse, FcOpLessEqual); + break; + case FcElementMore: + FcParseExpr (parse, FcOpMore); + break; + case FcElementMoreEq: + FcParseExpr (parse, FcOpMoreEqual); + break; + case FcElementPlus: + FcParseExpr (parse, FcOpPlus); + break; + case FcElementMinus: + FcParseExpr (parse, FcOpMinus); + break; + case FcElementTimes: + FcParseExpr (parse, FcOpTimes); + break; + case FcElementDivide: + FcParseExpr (parse, FcOpDivide); + break; + case FcElementNot: + FcParseExpr (parse, FcOpNot); + break; + case FcElementIf: + FcParseExpr (parse, FcOpQuest); + 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)) + FcConfigError (parse, "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) + FcConfigError (parse, "invalid doctype \"%s\"", doctypeName); +} + +static void +FcEndDoctypeDecl (void *userData) +{ } FcBool FcConfigParseAndLoad (FcConfig *config, - const FcChar8 *file, + const FcChar8 *name, FcBool complain) { - xmlDocPtr doc; - FcBool ret; - doc = FcConfigLoad (file); - if (doc) + XML_Parser p; + FcChar8 *filename; + FILE *f; + int len; + void *buf; + FcConfigParse parse; + FcBool error = FcTrue; + + filename = FcConfigFilename (name); + if (!filename) + goto bail0; + f = fopen ((char *) filename, "r"); + free (filename); + if (!f) + goto bail0; + + p = XML_ParserCreate ("UTF-8"); + if (!p) + goto bail1; + + if (!FcConfigInit (&parse, name, config, p)) + goto bail2; + + XML_SetUserData (p, &parse); + + XML_SetDoctypeDeclHandler (p, FcStartDoctypeDecl, FcEndDoctypeDecl); + XML_SetElementHandler (p, FcStartElement, FcEndElement); + XML_SetCharacterDataHandler (p, FcCharacterData); + + do { + buf = XML_GetBuffer (p, BUFSIZ); + if (!buf) + goto bail3; + len = fread (buf, 1, BUFSIZ, f); + if (len < 0) + goto bail3; + if (!XML_ParseBuffer (p, len, len == 0)) + goto bail3; + } while (len != 0); + error = parse.error; +bail3: + FcConfigCleanup (&parse); +bail2: + XML_ParserFree (p); +bail1: + fclose (f); +bail0: + if (error && complain) { - ret = FcConfigAddConfigFile (config, file); - if (ret) - ret = FcConfigParse (config, doc); - xmlFreeDoc (doc); - return ret; - } - if (complain) - { - if (file) - FcConfigParseError ("Cannot load config file \"%s\"", file); + if (name) + FcConfigError (0, "Cannot load config file \"%s\"", name); else - FcConfigParseError ("Cannot load default config file"); + FcConfigError (0, "Cannot load default config file"); return FcFalse; } return FcTrue;