fontconfig/src/fcxml.c

2388 lines
50 KiB
C
Raw Normal View History

2002-02-15 00:34:13 +01:00
/*
2003-03-05 06:51:27 +01:00
* $RCSId: xc/lib/fontconfig/src/fcxml.c,v 1.21 2002/08/22 18:53:22 keithp Exp $
2002-02-15 00:34:13 +01:00
*
2004-12-07 02:14:46 +01:00
* Copyright © 2002 Keith Packard
2002-02-15 00:34:13 +01:00
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of Keith Packard not be used in
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. Keith Packard makes no
* representations about the suitability of this software for any purpose. It
* is provided "as is" without express or implied warranty.
*
* KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include <stdarg.h>
#include "fcint.h"
#include <dirent.h>
#ifndef HAVE_XMLPARSE_H
#define HAVE_XMLPARSE_H 0
#endif
#if HAVE_XMLPARSE_H
#include <xmlparse.h>
#else
#include <expat.h>
#endif
2002-02-15 00:34:13 +01:00
#ifdef _WIN32
#define STRICT
#include <windows.h>
#undef STRICT
#endif
2002-02-15 00:34:13 +01:00
void
FcTestDestroy (FcTest *test)
{
if (test->next)
FcTestDestroy (test->next);
FcExprDestroy (test->expr);
FcStrFree ((FcChar8 *) test->field);
FcMemFree (FC_MEM_TEST, sizeof (FcTest));
2002-02-15 00:34:13 +01:00
free (test);
}
FcExpr *
FcExprCreateInteger (int i)
{
FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
if (e)
{
FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
2002-02-15 00:34:13 +01:00
e->op = FcOpInteger;
e->u.ival = i;
}
return e;
}
FcExpr *
FcExprCreateDouble (double d)
{
FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
if (e)
{
FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
2002-02-15 00:34:13 +01:00
e->op = FcOpDouble;
e->u.dval = d;
}
return e;
}
FcExpr *
FcExprCreateString (const FcChar8 *s)
2002-02-15 00:34:13 +01:00
{
FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
if (e)
{
FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
2002-02-15 00:34:13 +01:00
e->op = FcOpString;
e->u.sval = FcStrCopy (s);
}
return e;
}
FcExpr *
FcExprCreateMatrix (const FcMatrix *m)
{
FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
if (e)
{
FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
2002-02-15 00:34:13 +01:00
e->op = FcOpMatrix;
e->u.mval = FcMatrixCopy (m);
}
return e;
}
FcExpr *
FcExprCreateBool (FcBool b)
{
FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
if (e)
{
FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
2002-02-15 00:34:13 +01:00
e->op = FcOpBool;
e->u.bval = b;
}
return e;
}
FcExpr *
FcExprCreateNil (void)
{
FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
if (e)
{
FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
2002-02-15 00:34:13 +01:00
e->op = FcOpNil;
}
return e;
}
FcExpr *
FcExprCreateField (const char *field)
{
FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
if (e)
{
FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
2002-02-15 00:34:13 +01:00
e->op = FcOpField;
e->u.field = (char *) FcStrCopy ((FcChar8 *) field);
2002-02-15 00:34:13 +01:00
}
return e;
}
FcExpr *
FcExprCreateConst (const FcChar8 *constant)
2002-02-15 00:34:13 +01:00
{
FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
if (e)
{
FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
2002-02-15 00:34:13 +01:00
e->op = FcOpConst;
e->u.constant = FcStrCopy (constant);
}
return e;
}
FcExpr *
FcExprCreateOp (FcExpr *left, FcOp op, FcExpr *right)
{
FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
if (e)
{
FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
2002-02-15 00:34:13 +01:00
e->op = op;
e->u.tree.left = left;
e->u.tree.right = right;
}
return e;
}
void
FcExprDestroy (FcExpr *e)
{
if (!e)
return;
2002-02-15 00:34:13 +01:00
switch (e->op) {
case FcOpInteger:
break;
case FcOpDouble:
break;
case FcOpString:
FcStrFree (e->u.sval);
break;
case FcOpMatrix:
FcMatrixFree (e->u.mval);
break;
case FcOpCharSet:
FcCharSetDestroy (e->u.cval);
break;
case FcOpBool:
break;
case FcOpField:
FcStrFree ((FcChar8 *) e->u.field);
2002-02-15 00:34:13 +01:00
break;
case FcOpConst:
FcStrFree (e->u.constant);
break;
case FcOpAssign:
case FcOpAssignReplace:
case FcOpPrepend:
case FcOpPrependFirst:
case FcOpAppend:
case FcOpAppendLast:
break;
case FcOpOr:
case FcOpAnd:
case FcOpEqual:
case FcOpNotEqual:
case FcOpLess:
case FcOpLessEqual:
case FcOpMore:
case FcOpMoreEqual:
case FcOpContains:
case FcOpListing:
case FcOpNotContains:
2002-02-15 00:34:13 +01:00
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:
2002-02-15 00:34:13 +01:00
FcExprDestroy (e->u.tree.left);
break;
case FcOpNil:
case FcOpInvalid:
break;
}
FcMemFree (FC_MEM_EXPR, sizeof (FcExpr));
2002-02-15 00:34:13 +01:00
free (e);
}
void
FcEditDestroy (FcEdit *e)
{
if (e->next)
FcEditDestroy (e->next);
FcStrFree ((FcChar8 *) e->field);
if (e->expr)
FcExprDestroy (e->expr);
free (e);
2002-02-15 00:34:13 +01:00
}
char *
FcConfigSaveField (const char *field)
{
return (char *) FcStrCopy ((FcChar8 *) field);
2002-02-15 00:34:13 +01:00
}
typedef enum _FcElement {
FcElementNone,
FcElementFontconfig,
FcElementDir,
FcElementCache,
FcElementInclude,
FcElementConfig,
FcElementMatch,
FcElementAlias,
FcElementBlank,
FcElementRescan,
FcElementPrefer,
FcElementAccept,
FcElementDefault,
FcElementFamily,
FcElementSelectfont,
FcElementAcceptfont,
FcElementRejectfont,
FcElementGlob,
FcElementPattern,
FcElementPatelt,
FcElementTest,
FcElementEdit,
FcElementInt,
FcElementDouble,
FcElementString,
FcElementMatrix,
FcElementBool,
FcElementCharset,
FcElementName,
FcElementConst,
FcElementOr,
FcElementAnd,
FcElementEq,
FcElementNotEq,
FcElementLess,
FcElementLessEq,
FcElementMore,
FcElementMoreEq,
FcElementContains,
FcElementNotContains,
FcElementPlus,
FcElementMinus,
FcElementTimes,
FcElementDivide,
FcElementNot,
FcElementIf,
FcElementFloor,
FcElementCeil,
FcElementRound,
FcElementTrunc,
FcElementUnknown
} FcElement;
static FcElement
FcElementMap (const XML_Char *name)
{
static struct {
char *name;
FcElement element;
} fcElementMap[] = {
{ "fontconfig", FcElementFontconfig },
{ "dir", FcElementDir },
{ "cache", FcElementCache },
{ "include", FcElementInclude },
{ "config", FcElementConfig },
{ "match", FcElementMatch },
{ "alias", FcElementAlias },
{ "blank", FcElementBlank },
{ "rescan", FcElementRescan },
{ "prefer", FcElementPrefer },
{ "accept", FcElementAccept },
{ "default", FcElementDefault },
{ "family", FcElementFamily },
{ "selectfont", FcElementSelectfont },
{ "acceptfont", FcElementAcceptfont },
{ "rejectfont", FcElementRejectfont },
{ "glob", FcElementGlob },
{ "pattern", FcElementPattern },
{ "patelt", FcElementPatelt },
{ "test", FcElementTest },
{ "edit", FcElementEdit },
{ "int", FcElementInt },
{ "double", FcElementDouble },
{ "string", FcElementString },
{ "matrix", FcElementMatrix },
{ "bool", FcElementBool },
{ "charset", FcElementCharset },
{ "name", FcElementName },
{ "const", FcElementConst },
{ "or", FcElementOr },
{ "and", FcElementAnd },
{ "eq", FcElementEq },
{ "not_eq", FcElementNotEq },
{ "less", FcElementLess },
{ "less_eq", FcElementLessEq },
{ "more", FcElementMore },
{ "more_eq", FcElementMoreEq },
{ "contains", FcElementContains },
{ "not_contains",FcElementNotContains },
{ "plus", FcElementPlus },
{ "minus", FcElementMinus },
{ "times", FcElementTimes },
{ "divide", FcElementDivide },
{ "not", FcElementNot },
{ "if", FcElementIf },
{ "floor", FcElementFloor },
{ "ceil", FcElementCeil },
{ "round", FcElementRound },
{ "trunc", FcElementTrunc },
{ 0, 0 }
};
int i;
for (i = 0; fcElementMap[i].name; i++)
if (!strcmp ((char *) name, fcElementMap[i].name))
return fcElementMap[i].element;
return FcElementUnknown;
}
typedef struct _FcPStack {
struct _FcPStack *prev;
FcElement element;
FcChar8 **attr;
FcStrBuf str;
} FcPStack;
typedef enum _FcVStackTag {
FcVStackNone,
FcVStackString,
FcVStackFamily,
FcVStackField,
FcVStackConstant,
FcVStackGlob,
FcVStackPattern,
FcVStackPrefer,
FcVStackAccept,
FcVStackDefault,
FcVStackInteger,
FcVStackDouble,
FcVStackMatrix,
FcVStackBool,
FcVStackTest,
FcVStackExpr,
FcVStackEdit
} FcVStackTag;
typedef struct _FcVStack {
struct _FcVStack *prev;
FcPStack *pstack; /* related parse element */
FcVStackTag tag;
union {
FcChar8 *string;
int integer;
double _double;
FcMatrix *matrix;
FcBool bool;
FcTest *test;
FcQual qual;
FcOp op;
FcExpr *expr;
FcEdit *edit;
FcPattern *pattern;
} u;
} FcVStack;
typedef struct _FcConfigParse {
FcPStack *pstack;
FcVStack *vstack;
FcBool error;
const FcChar8 *name;
FcConfig *config;
XML_Parser parser;
} FcConfigParse;
typedef enum _FcConfigSeverity {
FcSevereInfo, FcSevereWarning, FcSevereError
} FcConfigSeverity;
2002-02-15 00:34:13 +01:00
static void
FcConfigMessage (FcConfigParse *parse, FcConfigSeverity severe, char *fmt, ...)
2002-02-15 00:34:13 +01:00
{
char *s = "unknown";
2002-02-15 00:34:13 +01:00
va_list args;
va_start (args, fmt);
switch (severe) {
case FcSevereInfo: s = "info"; break;
case FcSevereWarning: s = "warning"; break;
case FcSevereError: s = "error"; break;
}
if (parse)
{
if (parse->name)
fprintf (stderr, "Fontconfig %s: \"%s\", line %d: ", s,
parse->name, XML_GetCurrentLineNumber (parse->parser));
else
fprintf (stderr, "Fontconfig %s: line %d: ", s,
XML_GetCurrentLineNumber (parse->parser));
if (severe >= FcSevereError)
parse->error = FcTrue;
}
else
fprintf (stderr, "Fontconfig %s: ", s);
2002-02-15 00:34:13 +01:00
vfprintf (stderr, fmt, args);
fprintf (stderr, "\n");
va_end (args);
}
static char *
FcTypeName (FcType type)
{
switch (type) {
case FcTypeVoid:
return "void";
case FcTypeInteger:
case FcTypeDouble:
return "number";
case FcTypeString:
return "string";
case FcTypeBool:
return "bool";
case FcTypeMatrix:
return "matrix";
case FcTypeCharSet:
return "charset";
case FcTypeFTFace:
return "FT_Face";
case FcTypeLangSet:
return "langset";
default:
return "unknown";
}
}
static void
FcTypecheckValue (FcConfigParse *parse, FcType value, FcType type)
{
if (value == FcTypeInteger)
value = FcTypeDouble;
if (type == FcTypeInteger)
type = FcTypeDouble;
if (value != type)
{
if ((value == FcTypeLangSet && type == FcTypeString) ||
(value == FcTypeString && type == FcTypeLangSet))
return;
FcConfigMessage (parse, FcSevereWarning, "saw %s, expected %s",
FcTypeName (value), FcTypeName (type));
}
}
static void
FcTypecheckExpr (FcConfigParse *parse, FcExpr *expr, FcType type)
{
const FcObjectType *o;
const FcConstant *c;
switch (expr->op) {
case FcOpInteger:
case FcOpDouble:
FcTypecheckValue (parse, FcTypeDouble, type);
break;
case FcOpString:
FcTypecheckValue (parse, FcTypeString, type);
break;
case FcOpMatrix:
FcTypecheckValue (parse, FcTypeMatrix, type);
break;
case FcOpBool:
FcTypecheckValue (parse, FcTypeBool, type);
break;
case FcOpCharSet:
FcTypecheckValue (parse, FcTypeCharSet, type);
break;
case FcOpNil:
break;
case FcOpField:
o = FcNameGetObjectType (expr->u.field);
if (o)
FcTypecheckValue (parse, o->type, type);
break;
case FcOpConst:
c = FcNameGetConstant (expr->u.constant);
if (c)
{
o = FcNameGetObjectType (c->object);
if (o)
FcTypecheckValue (parse, o->type, type);
}
break;
case FcOpQuest:
FcTypecheckExpr (parse, expr->u.tree.left, FcTypeBool);
FcTypecheckExpr (parse, expr->u.tree.right->u.tree.left, type);
FcTypecheckExpr (parse, expr->u.tree.right->u.tree.right, type);
break;
case FcOpAssign:
case FcOpAssignReplace:
break;
case FcOpEqual:
case FcOpNotEqual:
case FcOpLess:
case FcOpLessEqual:
case FcOpMore:
case FcOpMoreEqual:
case FcOpContains:
case FcOpNotContains:
case FcOpListing:
FcTypecheckValue (parse, FcTypeBool, type);
break;
case FcOpComma:
case FcOpOr:
case FcOpAnd:
case FcOpPlus:
case FcOpMinus:
case FcOpTimes:
case FcOpDivide:
FcTypecheckExpr (parse, expr->u.tree.left, type);
FcTypecheckExpr (parse, expr->u.tree.right, type);
break;
case FcOpNot:
FcTypecheckValue (parse, FcTypeBool, type);
FcTypecheckExpr (parse, expr->u.tree.left, FcTypeBool);
break;
case FcOpFloor:
case FcOpCeil:
case FcOpRound:
case FcOpTrunc:
FcTypecheckValue (parse, FcTypeDouble, type);
FcTypecheckExpr (parse, expr->u.tree.left, FcTypeDouble);
break;
default:
break;
}
}
static FcTest *
FcTestCreate (FcConfigParse *parse,
FcMatchKind kind,
FcQual qual,
const FcChar8 *field,
FcOp compare,
FcExpr *expr)
{
FcTest *test = (FcTest *) malloc (sizeof (FcTest));
if (test)
{
const FcObjectType *o;
FcMemAlloc (FC_MEM_TEST, sizeof (FcTest));
test->next = 0;
test->kind = kind;
test->qual = qual;
test->field = (char *) FcStrCopy (field);
test->op = compare;
test->expr = expr;
o = FcNameGetObjectType (test->field);
if (o)
FcTypecheckExpr (parse, expr, o->type);
}
return test;
}
static FcEdit *
FcEditCreate (FcConfigParse *parse,
const char *field,
FcOp op,
FcExpr *expr,
FcValueBinding binding)
{
FcEdit *e = (FcEdit *) malloc (sizeof (FcEdit));
if (e)
{
const FcObjectType *o;
e->next = 0;
e->field = field; /* already saved in grammar */
e->op = op;
e->expr = expr;
e->binding = binding;
o = FcNameGetObjectType (e->field);
if (o)
FcTypecheckExpr (parse, expr, o->type);
}
return e;
}
static void
FcVStackPush (FcConfigParse *parse, FcVStack *vstack)
2002-02-15 00:34:13 +01:00
{
vstack->prev = parse->vstack;
vstack->pstack = parse->pstack ? parse->pstack->prev : 0;
parse->vstack = vstack;
2002-02-15 00:34:13 +01:00
}
static FcVStack *
FcVStackCreate (void)
2002-02-15 00:34:13 +01:00
{
FcVStack *new;
2002-02-15 00:34:13 +01:00
new = malloc (sizeof (FcVStack));
if (!new)
return 0;
FcMemAlloc (FC_MEM_VSTACK, sizeof (FcVStack));
new->tag = FcVStackNone;
new->prev = 0;
return new;
}
2002-02-15 00:34:13 +01:00
static void
FcVStackDestroy (FcVStack *vstack)
2002-02-15 00:34:13 +01:00
{
FcVStack *prev;
2002-02-15 00:34:13 +01:00
for (; vstack; vstack = prev)
{
prev = vstack->prev;
switch (vstack->tag) {
case FcVStackNone:
break;
case FcVStackString:
case FcVStackFamily:
case FcVStackField:
case FcVStackConstant:
case FcVStackGlob:
FcStrFree (vstack->u.string);
break;
case FcVStackPattern:
FcPatternDestroy (vstack->u.pattern);
break;
case FcVStackInteger:
case FcVStackDouble:
break;
case FcVStackMatrix:
FcMatrixFree (vstack->u.matrix);
break;
case FcVStackBool:
break;
case FcVStackTest:
FcTestDestroy (vstack->u.test);
break;
case FcVStackExpr:
case FcVStackPrefer:
case FcVStackAccept:
case FcVStackDefault:
FcExprDestroy (vstack->u.expr);
break;
case FcVStackEdit:
FcEditDestroy (vstack->u.edit);
break;
}
FcMemFree (FC_MEM_VSTACK, sizeof (FcVStack));
free (vstack);
}
2002-02-15 00:34:13 +01:00
}
static FcBool
FcVStackPushString (FcConfigParse *parse, FcVStackTag tag, FcChar8 *string)
2002-02-15 00:34:13 +01:00
{
FcVStack *vstack = FcVStackCreate ();
if (!vstack)
return FcFalse;
vstack->u.string = string;
vstack->tag = tag;
FcVStackPush (parse, vstack);
return FcTrue;
2002-02-15 00:34:13 +01:00
}
static FcBool
FcVStackPushInteger (FcConfigParse *parse, int integer)
2002-02-15 00:34:13 +01:00
{
FcVStack *vstack = FcVStackCreate ();
if (!vstack)
2002-02-15 00:34:13 +01:00
return FcFalse;
vstack->u.integer = integer;
vstack->tag = FcVStackInteger;
FcVStackPush (parse, vstack);
return FcTrue;
2002-02-15 00:34:13 +01:00
}
static FcBool
FcVStackPushDouble (FcConfigParse *parse, double _double)
2002-02-15 00:34:13 +01:00
{
FcVStack *vstack = FcVStackCreate ();
if (!vstack)
2002-02-15 00:34:13 +01:00
return FcFalse;
vstack->u._double = _double;
vstack->tag = FcVStackDouble;
FcVStackPush (parse, vstack);
return FcTrue;
2002-02-15 00:34:13 +01:00
}
static FcBool
FcVStackPushMatrix (FcConfigParse *parse, FcMatrix *matrix)
2002-02-15 00:34:13 +01:00
{
FcVStack *vstack = FcVStackCreate ();
if (!vstack)
2002-02-15 00:34:13 +01:00
return FcFalse;
matrix = FcMatrixCopy (matrix);
if (!matrix)
2002-02-15 00:34:13 +01:00
{
FcVStackDestroy (vstack);
return FcFalse;
2002-02-15 00:34:13 +01:00
}
vstack->u.matrix = matrix;
vstack->tag = FcVStackMatrix;
FcVStackPush (parse, vstack);
return FcTrue;
2002-02-15 00:34:13 +01:00
}
static FcBool
FcVStackPushBool (FcConfigParse *parse, FcBool bool)
2002-02-15 00:34:13 +01:00
{
FcVStack *vstack = FcVStackCreate ();
if (!vstack)
return FcFalse;
vstack->u.bool = bool;
vstack->tag = FcVStackBool;
FcVStackPush (parse, vstack);
return FcTrue;
}
2002-02-15 00:34:13 +01:00
static FcBool
FcVStackPushTest (FcConfigParse *parse, FcTest *test)
{
FcVStack *vstack = FcVStackCreate ();
if (!vstack)
2002-02-15 00:34:13 +01:00
return FcFalse;
vstack->u.test = test;
vstack->tag = FcVStackTest;
FcVStackPush (parse, vstack);
2002-02-15 00:34:13 +01:00
return FcTrue;
}
static FcBool
FcVStackPushExpr (FcConfigParse *parse, FcVStackTag tag, FcExpr *expr)
2002-02-15 00:34:13 +01:00
{
FcVStack *vstack = FcVStackCreate ();
if (!vstack)
return FcFalse;
vstack->u.expr = expr;
vstack->tag = tag;
FcVStackPush (parse, vstack);
return FcTrue;
}
2002-02-15 00:34:13 +01:00
static FcBool
FcVStackPushEdit (FcConfigParse *parse, FcEdit *edit)
{
FcVStack *vstack = FcVStackCreate ();
if (!vstack)
2002-02-15 00:34:13 +01:00
return FcFalse;
vstack->u.edit = edit;
vstack->tag = FcVStackEdit;
FcVStackPush (parse, vstack);
2002-02-15 00:34:13 +01:00
return FcTrue;
}
static FcBool
FcVStackPushPattern (FcConfigParse *parse, FcPattern *pattern)
{
FcVStack *vstack = FcVStackCreate ();
if (!vstack)
return FcFalse;
vstack->u.pattern = pattern;
vstack->tag = FcVStackPattern;
FcVStackPush (parse, vstack);
return FcTrue;
}
static FcVStack *
FcVStackFetch (FcConfigParse *parse, int off)
2002-02-15 00:34:13 +01:00
{
FcVStack *vstack;
2002-02-15 00:34:13 +01:00
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)
2002-02-15 00:34:13 +01:00
{
FcVStack *vstack = parse->vstack;
parse->vstack = vstack->prev;
vstack->prev = 0;
FcVStackDestroy (vstack);
2002-02-15 00:34:13 +01:00
}
}
static FcVStack *
FcVStackPop (FcConfigParse *parse)
2002-02-15 00:34:13 +01:00
{
FcVStack *vstack = parse->vstack;
2002-02-15 00:34:13 +01:00
if (!vstack || vstack->pstack != parse->pstack)
2002-02-15 00:34:13 +01:00
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;
2002-02-15 00:34:13 +01:00
}
return h;
2002-02-15 00:34:13 +01:00
}
static FcChar8 **
FcConfigSaveAttr (const XML_Char **attr)
2002-02-15 00:34:13 +01:00
{
int n;
int slen;
int i;
FcChar8 **new;
FcChar8 *s;
2002-02-15 00:34:13 +01:00
if (!attr)
return 0;
slen = 0;
for (i = 0; attr[i]; i++)
slen += strlen (attr[i]) + 1;
n = i;
new = malloc ((i + 1) * sizeof (FcChar8 *) + slen);
if (!new)
return 0;
FcMemAlloc (FC_MEM_ATTR, 1); /* size is too expensive */
s = (FcChar8 *) (new + (i + 1));
for (i = 0; attr[i]; i++)
2002-02-15 00:34:13 +01:00
{
new[i] = s;
strcpy ((char *) s, (char *) attr[i]);
s += strlen ((char *) s) + 1;
2002-02-15 00:34:13 +01:00
}
new[i] = 0;
return new;
}
2002-02-15 00:34:13 +01:00
static FcBool
FcPStackPush (FcConfigParse *parse, FcElement element, const XML_Char **attr)
{
FcPStack *new = malloc (sizeof (FcPStack));
if (!new)
return FcFalse;
FcMemAlloc (FC_MEM_PSTACK, sizeof (FcPStack));
new->prev = parse->pstack;
new->element = element;
if (attr)
2002-02-15 00:34:13 +01:00
{
new->attr = FcConfigSaveAttr (attr);
if (!new->attr)
FcConfigMessage (parse, FcSevereError, "out of memory");
2002-02-15 00:34:13 +01:00
}
else
new->attr = 0;
FcStrBufInit (&new->str, 0, 0);
parse->pstack = new;
return FcTrue;
}
2002-02-15 00:34:13 +01:00
static FcBool
FcPStackPop (FcConfigParse *parse)
{
FcPStack *old;
if (!parse->pstack)
2002-02-15 00:34:13 +01:00
{
FcConfigMessage (parse, FcSevereError, "mismatching element");
return FcFalse;
2002-02-15 00:34:13 +01:00
}
FcVStackClear (parse);
old = parse->pstack;
parse->pstack = old->prev;
FcStrBufDestroy (&old->str);
if (old->attr)
{
FcMemFree (FC_MEM_ATTR, 1); /* size is to expensive */
free (old->attr);
}
FcMemFree (FC_MEM_PSTACK, sizeof (FcPStack));
free (old);
return FcTrue;
2002-02-15 00:34:13 +01:00
}
static FcBool
FcConfigInit (FcConfigParse *parse, const FcChar8 *name, FcConfig *config, XML_Parser parser)
2002-02-15 00:34:13 +01:00
{
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)
2002-02-15 00:34:13 +01:00
return 0;
attrs = parse->pstack->attr;
while (*attrs)
2002-02-15 00:34:13 +01:00
{
if (!strcmp ((char *) *attrs, attr))
return attrs[1];
attrs += 2;
2002-02-15 00:34:13 +01:00
}
return 0;
}
static void
FcStartElement(void *userData, const XML_Char *name, const XML_Char **attr)
2002-02-15 00:34:13 +01:00
{
FcConfigParse *parse = userData;
FcElement element;
element = FcElementMap (name);
if (element == FcElementUnknown)
FcConfigMessage (parse, FcSevereWarning, "unknown element \"%s\"", name);
if (!FcPStackPush (parse, element, attr))
2002-02-15 00:34:13 +01:00
{
FcConfigMessage (parse, FcSevereError, "out of memory");
return;
2002-02-15 00:34:13 +01:00
}
return;
}
2002-02-15 00:34:13 +01:00
static void
FcParseBlank (FcConfigParse *parse)
{
int n = FcVStackElements (parse);
while (n-- > 0)
2002-02-15 00:34:13 +01:00
{
FcVStack *v = FcVStackFetch (parse, n);
if (v->tag != FcVStackInteger)
FcConfigMessage (parse, FcSevereError, "non-integer blank");
else
2002-02-15 00:34:13 +01:00
{
if (!parse->config->blanks)
2002-02-15 00:34:13 +01:00
{
parse->config->blanks = FcBlanksCreate ();
if (!parse->config->blanks)
{
FcConfigMessage (parse, FcSevereError, "out of memory");
break;
}
2002-02-15 00:34:13 +01:00
}
if (!FcBlanksAdd (parse->config->blanks, v->u.integer))
2002-02-15 00:34:13 +01:00
{
FcConfigMessage (parse, FcSevereError, "out of memory");
break;
2002-02-15 00:34:13 +01:00
}
}
}
}
2002-02-15 00:34:13 +01:00
static void
FcParseRescan (FcConfigParse *parse)
{
int n = FcVStackElements (parse);
while (n-- > 0)
{
FcVStack *v = FcVStackFetch (parse, n);
if (v->tag != FcVStackInteger)
FcConfigMessage (parse, FcSevereWarning, "non-integer rescan");
else
parse->config->rescanInterval = v->u.integer;
}
}
static void
FcParseInt (FcConfigParse *parse)
{
FcChar8 *s, *end;
int l;
if (!parse->pstack)
return;
s = FcStrBufDone (&parse->pstack->str);
if (!s)
2002-02-15 00:34:13 +01:00
{
FcConfigMessage (parse, FcSevereError, "out of memory");
return;
2002-02-15 00:34:13 +01:00
}
end = 0;
l = (int) strtol ((char *) s, (char **)&end, 0);
if (end != s + strlen ((char *) s))
FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid integer", s);
else
FcVStackPushInteger (parse, l);
FcStrFree (s);
2002-02-15 00:34:13 +01:00
}
/*
* idea copied from glib g_ascii_strtod with
* permission of the author (Alexander Larsson)
*/
#include <locale.h>
static double
FcStrtod (char *s, char **end)
{
struct lconv *locale_data;
char *dot;
double v;
/*
* Have to swap the decimal point to match the current locale
* if that locale doesn't use 0x2e
*/
if ((dot = strchr (s, 0x2e)) &&
(locale_data = localeconv ()) &&
(locale_data->decimal_point[0] != 0x2e ||
locale_data->decimal_point[1] != 0))
{
char buf[128];
int slen = strlen (s);
int dlen = strlen (locale_data->decimal_point);
if (slen + dlen > sizeof (buf))
{
if (end)
*end = s;
v = 0;
}
else
{
char *buf_end;
/* mantissa */
strncpy (buf, s, dot - s);
/* decimal point */
strcpy (buf + (dot - s), locale_data->decimal_point);
/* rest of number */
strcpy (buf + (dot - s) + dlen, dot + 1);
buf_end = 0;
v = strtod (buf, &buf_end);
if (buf_end) {
buf_end = s + (buf_end - buf);
if (buf_end > dot)
buf_end -= dlen - 1;
}
if (end)
*end = buf_end;
}
}
else
v = strtod (s, end);
return v;
}
static void
FcParseDouble (FcConfigParse *parse)
2002-02-15 00:34:13 +01:00
{
FcChar8 *s, *end;
double d;
2002-02-15 00:34:13 +01:00
if (!parse->pstack)
return;
s = FcStrBufDone (&parse->pstack->str);
if (!s)
2002-02-15 00:34:13 +01:00
{
FcConfigMessage (parse, FcSevereError, "out of memory");
return;
2002-02-15 00:34:13 +01:00
}
end = 0;
d = FcStrtod ((char *) s, (char **)&end);
if (end != s + strlen ((char *) s))
FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid double", s);
2002-02-15 00:34:13 +01:00
else
FcVStackPushDouble (parse, d);
FcStrFree (s);
}
2002-02-15 00:34:13 +01:00
static void
FcParseString (FcConfigParse *parse, FcVStackTag tag)
{
FcChar8 *s;
if (!parse->pstack)
return;
s = FcStrBufDone (&parse->pstack->str);
if (!s)
{
FcConfigMessage (parse, FcSevereError, "out of memory");
return;
}
if (!FcVStackPushString (parse, tag, s))
FcStrFree (s);
}
static void
FcParseMatrix (FcConfigParse *parse)
{
FcVStack *vstack;
enum { m_done, m_xx, m_xy, m_yx, m_yy } matrix_state = m_yy;
FcMatrix m;
while ((vstack = FcVStackPop (parse)))
{
double v;
switch (vstack->tag) {
case FcVStackInteger:
v = vstack->u.integer;
break;
case FcVStackDouble:
v = vstack->u._double;
break;
default:
FcConfigMessage (parse, FcSevereError, "non-double matrix element");
v = 1.0;
break;
}
switch (matrix_state) {
case m_xx: m.xx = v; break;
case m_xy: m.xy = v; break;
case m_yx: m.yx = v; break;
case m_yy: m.yy = v; break;
default: break;
}
FcVStackDestroy (vstack);
matrix_state--;
}
if (matrix_state != m_done)
FcConfigMessage (parse, FcSevereError, "wrong number of matrix elements");
else
FcVStackPushMatrix (parse, &m);
2002-02-15 00:34:13 +01:00
}
static FcBool
FcConfigLexBool (FcConfigParse *parse, const FcChar8 *bool)
{
FcBool result = FcFalse;
if (!FcNameBool (bool, &result))
FcConfigMessage (parse, FcSevereWarning, "\"%s\" is not known boolean",
bool);
return result;
}
static void
FcParseBool (FcConfigParse *parse)
{
FcChar8 *s;
if (!parse->pstack)
return;
s = FcStrBufDone (&parse->pstack->str);
if (!s)
{
FcConfigMessage (parse, FcSevereError, "out of memory");
return;
}
FcVStackPushBool (parse, FcConfigLexBool (parse, s));
FcStrFree (s);
}
static void
FcParseFamilies (FcConfigParse *parse, FcVStackTag tag)
2002-02-15 00:34:13 +01:00
{
FcVStack *vstack;
FcExpr *left, *expr = 0, *new;
while ((vstack = FcVStackPop (parse)))
{
if (vstack->tag != FcVStackFamily)
{
FcConfigMessage (parse, FcSevereWarning, "non-family");
FcVStackDestroy (vstack);
continue;
}
left = vstack->u.expr;
vstack->tag = FcVStackNone;
FcVStackDestroy (vstack);
if (expr)
{
new = FcExprCreateOp (left, FcOpComma, expr);
if (!new)
{
FcConfigMessage (parse, FcSevereError, "out of memory");
FcExprDestroy (left);
FcExprDestroy (expr);
break;
}
expr = new;
}
else
expr = left;
}
if (expr)
{
if (!FcVStackPushExpr (parse, tag, expr))
{
FcConfigMessage (parse, FcSevereError, "out of memory");
if (expr)
FcExprDestroy (expr);
}
}
}
static void
FcParseFamily (FcConfigParse *parse)
{
FcChar8 *s;
FcExpr *expr;
if (!parse->pstack)
return;
s = FcStrBufDone (&parse->pstack->str);
if (!s)
{
FcConfigMessage (parse, FcSevereError, "out of memory");
return;
}
expr = FcExprCreateString (s);
FcStrFree (s);
if (expr)
FcVStackPushExpr (parse, FcVStackFamily, expr);
}
static void
FcParseAlias (FcConfigParse *parse)
{
FcExpr *family = 0, *accept = 0, *prefer = 0, *def = 0, *new = 0;
2002-02-15 00:34:13 +01:00
FcEdit *edit = 0, *next;
FcVStack *vstack;
2002-02-15 00:34:13 +01:00
FcTest *test;
while ((vstack = FcVStackPop (parse)))
2002-02-15 00:34:13 +01:00
{
switch (vstack->tag) {
case FcVStackFamily:
if (family)
{
new = FcExprCreateOp (vstack->u.expr, FcOpComma, family);
if (!new)
FcConfigMessage (parse, FcSevereError, "out of memory");
else
family = new;
}
else
new = vstack->u.expr;
if (new)
{
family = new;
vstack->tag = FcVStackNone;
}
break;
case FcVStackPrefer:
if (prefer)
FcExprDestroy (prefer);
prefer = vstack->u.expr;
vstack->tag = FcVStackNone;
break;
case FcVStackAccept:
if (accept)
FcExprDestroy (accept);
accept = vstack->u.expr;
vstack->tag = FcVStackNone;
break;
case FcVStackDefault:
if (def)
FcExprDestroy (def);
def = vstack->u.expr;
vstack->tag = FcVStackNone;
break;
default:
FcConfigMessage (parse, FcSevereWarning, "bad alias");
break;
}
FcVStackDestroy (vstack);
2002-02-15 00:34:13 +01:00
}
if (!family)
{
FcConfigMessage (parse, FcSevereError, "missing family in alias");
if (prefer)
FcExprDestroy (prefer);
if (accept)
FcExprDestroy (accept);
if (def)
FcExprDestroy (def);
return;
}
2002-02-15 00:34:13 +01:00
if (prefer)
{
edit = FcEditCreate (parse,
FcConfigSaveField ("family"),
2002-02-15 00:34:13 +01:00
FcOpPrepend,
2002-07-31 03:36:37 +02:00
prefer,
FcValueBindingWeak);
2002-02-15 00:34:13 +01:00
if (edit)
edit->next = 0;
else
FcExprDestroy (prefer);
2002-02-15 00:34:13 +01:00
}
if (accept)
{
next = edit;
edit = FcEditCreate (parse,
FcConfigSaveField ("family"),
2002-02-15 00:34:13 +01:00
FcOpAppend,
2002-07-31 03:36:37 +02:00
accept,
FcValueBindingWeak);
2002-02-15 00:34:13 +01:00
if (edit)
edit->next = next;
else
FcExprDestroy (accept);
2002-02-15 00:34:13 +01:00
}
if (def)
{
next = edit;
edit = FcEditCreate (parse,
FcConfigSaveField ("family"),
2002-07-31 03:36:37 +02:00
FcOpAppendLast,
def,
FcValueBindingWeak);
2002-02-15 00:34:13 +01:00
if (edit)
edit->next = next;
else
FcExprDestroy (def);
2002-02-15 00:34:13 +01:00
}
if (edit)
{
test = FcTestCreate (parse, FcMatchPattern,
FcQualAny,
2002-06-18 18:47:33 +02:00
(FcChar8 *) FC_FAMILY,
2002-02-15 00:34:13 +01:00
FcOpEqual,
family);
if (test)
if (!FcConfigAddEdit (parse->config, test, edit, FcMatchPattern))
FcTestDestroy (test);
2002-02-15 00:34:13 +01:00
}
else
FcExprDestroy (family);
2002-02-15 00:34:13 +01:00
}
static FcExpr *
FcPopExpr (FcConfigParse *parse)
2002-02-15 00:34:13 +01:00
{
FcVStack *vstack = FcVStackPop (parse);
FcExpr *expr = 0;
if (!vstack)
return 0;
switch (vstack->tag) {
case FcVStackNone:
break;
case FcVStackString:
case FcVStackFamily:
expr = FcExprCreateString (vstack->u.string);
break;
case FcVStackField:
expr = FcExprCreateField ((char *) vstack->u.string);
break;
case FcVStackConstant:
expr = FcExprCreateConst (vstack->u.string);
break;
case FcVStackGlob:
/* XXX: What's the correct action here? (CDW) */
break;
case FcVStackPrefer:
case FcVStackAccept:
case FcVStackDefault:
expr = vstack->u.expr;
vstack->tag = FcVStackNone;
break;
case FcVStackInteger:
expr = FcExprCreateInteger (vstack->u.integer);
break;
case FcVStackDouble:
expr = FcExprCreateDouble (vstack->u._double);
break;
case FcVStackMatrix:
expr = FcExprCreateMatrix (vstack->u.matrix);
break;
case FcVStackBool:
expr = FcExprCreateBool (vstack->u.bool);
break;
case FcVStackTest:
break;
case FcVStackExpr:
expr = vstack->u.expr;
vstack->tag = FcVStackNone;
break;
case FcVStackEdit:
break;
default:
break;
}
FcVStackDestroy (vstack);
return expr;
}
/*
* This builds a tree of binary operations. Note
* that every operator is defined so that if only
* a single operand is contained, the value of the
* whole expression is the value of the operand.
*
* This code reduces in that case to returning that
* operand.
*/
static FcExpr *
FcPopBinary (FcConfigParse *parse, FcOp op)
{
FcExpr *left, *expr = 0, *new;
2002-02-15 00:34:13 +01:00
while ((left = FcPopExpr (parse)))
2002-02-15 00:34:13 +01:00
{
if (expr)
2002-02-15 00:34:13 +01:00
{
new = FcExprCreateOp (left, op, expr);
if (!new)
{
FcConfigMessage (parse, FcSevereError, "out of memory");
FcExprDestroy (left);
FcExprDestroy (expr);
2002-02-15 00:34:13 +01:00
break;
}
expr = new;
2002-02-15 00:34:13 +01:00
}
else
expr = left;
}
return expr;
}
static void
FcParseBinary (FcConfigParse *parse, FcOp op)
{
FcExpr *expr = FcPopBinary (parse, op);
if (expr)
FcVStackPushExpr (parse, FcVStackExpr, expr);
}
/*
* This builds a a unary operator, it consumes only
* a single operand
*/
static FcExpr *
FcPopUnary (FcConfigParse *parse, FcOp op)
{
FcExpr *operand, *new = 0;
if ((operand = FcPopExpr (parse)))
{
new = FcExprCreateOp (operand, op, 0);
if (!new)
{
FcExprDestroy (operand);
FcConfigMessage (parse, FcSevereError, "out of memory");
}
}
return new;
}
static void
FcParseUnary (FcConfigParse *parse, FcOp op)
{
FcExpr *expr = FcPopUnary (parse, op);
if (expr)
FcVStackPushExpr (parse, FcVStackExpr, expr);
}
static void
FcParseInclude (FcConfigParse *parse)
{
FcChar8 *s;
const FcChar8 *i;
FcBool ignore_missing = FcFalse;
s = FcStrBufDone (&parse->pstack->str);
if (!s)
{
FcConfigMessage (parse, FcSevereError, "out of memory");
return;
}
i = FcConfigGetAttribute (parse, "ignore_missing");
if (i && FcConfigLexBool (parse, (FcChar8 *) i) == FcTrue)
ignore_missing = FcTrue;
if (!FcConfigParseAndLoad (parse->config, s, !ignore_missing))
parse->error = FcTrue;
FcStrFree (s);
}
typedef struct _FcOpMap {
char *name;
FcOp op;
} FcOpMap;
static FcOp
FcConfigLexOp (const FcChar8 *op, const FcOpMap *map, int nmap)
{
int i;
for (i = 0; i < nmap; i++)
if (!strcmp ((char *) op, map[i].name))
return map[i].op;
return FcOpInvalid;
}
static const FcOpMap fcCompareOps[] = {
{ "eq", FcOpEqual },
{ "not_eq", FcOpNotEqual },
{ "less", FcOpLess },
{ "less_eq", FcOpLessEqual },
{ "more", FcOpMore },
{ "more_eq", FcOpMoreEqual },
{ "contains", FcOpContains },
{ "not_contains", FcOpNotContains }
};
#define NUM_COMPARE_OPS (sizeof fcCompareOps / sizeof fcCompareOps[0])
static FcOp
FcConfigLexCompare (const FcChar8 *compare)
{
return FcConfigLexOp (compare, fcCompareOps, NUM_COMPARE_OPS);
}
static void
FcParseTest (FcConfigParse *parse)
{
const FcChar8 *kind_string;
FcMatchKind kind;
const FcChar8 *qual_string;
FcQual qual;
const FcChar8 *name;
const FcChar8 *compare_string;
FcOp compare;
FcExpr *expr;
FcTest *test;
kind_string = FcConfigGetAttribute (parse, "target");
if (!kind_string)
kind = FcMatchDefault;
else
{
if (!strcmp ((char *) kind_string, "pattern"))
kind = FcMatchPattern;
else if (!strcmp ((char *) kind_string, "font"))
kind = FcMatchFont;
else if (!strcmp ((char *) kind_string, "default"))
kind = FcMatchDefault;
else
{
FcConfigMessage (parse, FcSevereWarning, "invalid test target \"%s\"", kind_string);
return;
}
}
qual_string = FcConfigGetAttribute (parse, "qual");
if (!qual_string)
qual = FcQualAny;
else
{
if (!strcmp ((char *) qual_string, "any"))
qual = FcQualAny;
else if (!strcmp ((char *) qual_string, "all"))
qual = FcQualAll;
else if (!strcmp ((char *) qual_string, "first"))
qual = FcQualFirst;
else if (!strcmp ((char *) qual_string, "not_first"))
qual = FcQualNotFirst;
else
2002-02-15 00:34:13 +01:00
{
FcConfigMessage (parse, FcSevereWarning, "invalid test qual \"%s\"", qual_string);
return;
2002-02-15 00:34:13 +01:00
}
}
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)
2002-02-15 00:34:13 +01:00
{
FcConfigMessage (parse, FcSevereWarning, "invalid test compare \"%s\"", compare_string);
return;
2002-02-15 00:34:13 +01:00
}
}
expr = FcPopBinary (parse, FcOpComma);
if (!expr)
{
FcConfigMessage (parse, FcSevereWarning, "missing test expression");
return;
}
test = FcTestCreate (parse, kind, qual, name, compare, expr);
if (!test)
{
FcConfigMessage (parse, FcSevereError, "out of memory");
return;
}
FcVStackPushTest (parse, test);
}
static const FcOpMap fcModeOps[] = {
{ "assign", FcOpAssign },
{ "assign_replace", FcOpAssignReplace },
{ "prepend", FcOpPrepend },
{ "prepend_first", FcOpPrependFirst },
{ "append", FcOpAppend },
{ "append_last", FcOpAppendLast },
};
#define NUM_MODE_OPS (sizeof fcModeOps / sizeof fcModeOps[0])
static FcOp
FcConfigLexMode (const FcChar8 *mode)
{
return FcConfigLexOp (mode, fcModeOps, NUM_MODE_OPS);
}
static void
FcParseEdit (FcConfigParse *parse)
{
const FcChar8 *name;
const FcChar8 *mode_string;
2002-07-31 03:36:37 +02:00
const FcChar8 *binding_string;
FcOp mode;
2002-07-31 03:36:37 +02:00
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)
2002-02-15 00:34:13 +01:00
{
FcConfigMessage (parse, FcSevereWarning, "invalid edit mode \"%s\"", mode_string);
return;
2002-02-15 00:34:13 +01:00
}
}
2002-07-31 03:36:37 +02:00
binding_string = FcConfigGetAttribute (parse, "binding");
if (!binding_string)
binding = FcValueBindingWeak;
else
{
if (!strcmp ((char *) binding_string, "weak"))
binding = FcValueBindingWeak;
else if (!strcmp ((char *) binding_string, "strong"))
binding = FcValueBindingStrong;
else if (!strcmp ((char *) binding_string, "same"))
binding = FcValueBindingSame;
2002-07-31 03:36:37 +02:00
else
{
FcConfigMessage (parse, FcSevereWarning, "invalid edit binding \"%s\"", binding_string);
return;
}
}
expr = FcPopBinary (parse, FcOpComma);
edit = FcEditCreate (parse, (char *) FcStrCopy (name), mode, expr, binding);
if (!edit)
{
FcConfigMessage (parse, FcSevereError, "out of memory");
FcExprDestroy (expr);
return;
}
if (!FcVStackPushEdit (parse, edit))
FcEditDestroy (edit);
}
static void
FcParseMatch (FcConfigParse *parse)
{
const FcChar8 *kind_name;
FcMatchKind kind;
FcTest *test = 0;
FcEdit *edit = 0;
FcVStack *vstack;
kind_name = FcConfigGetAttribute (parse, "target");
if (!kind_name)
kind = FcMatchPattern;
else
{
if (!strcmp ((char *) kind_name, "pattern"))
kind = FcMatchPattern;
else if (!strcmp ((char *) kind_name, "font"))
kind = FcMatchFont;
else
2002-02-15 00:34:13 +01:00
{
FcConfigMessage (parse, FcSevereWarning, "invalid match target \"%s\"", kind_name);
return;
2002-02-15 00:34:13 +01:00
}
}
while ((vstack = FcVStackPop (parse)))
{
switch (vstack->tag) {
case FcVStackTest:
vstack->u.test->next = test;
test = vstack->u.test;
vstack->tag = FcVStackNone;
break;
case FcVStackEdit:
vstack->u.edit->next = edit;
edit = vstack->u.edit;
vstack->tag = FcVStackNone;
break;
default:
FcConfigMessage (parse, FcSevereWarning, "invalid match element");
break;
}
FcVStackDestroy (vstack);
}
if (!FcConfigAddEdit (parse->config, test, edit, kind))
FcConfigMessage (parse, FcSevereError, "out of memory");
}
static void
FcParseAcceptRejectFont (FcConfigParse *parse, FcElement element)
{
FcVStack *vstack;
while ((vstack = FcVStackPop (parse)))
{
switch (vstack->tag) {
case FcVStackGlob:
if (!FcConfigGlobAdd (parse->config,
vstack->u.string,
element == FcElementAcceptfont))
{
FcConfigMessage (parse, FcSevereError, "out of memory");
}
break;
case FcVStackPattern:
if (!FcConfigPatternsAdd (parse->config,
vstack->u.pattern,
element == FcElementAcceptfont))
{
FcConfigMessage (parse, FcSevereError, "out of memory");
}
else
vstack->tag = FcVStackNone;
break;
default:
FcConfigMessage (parse, FcSevereWarning, "bad font selector");
break;
}
FcVStackDestroy (vstack);
}
}
static FcValue
FcPopValue (FcConfigParse *parse)
{
FcVStack *vstack = FcVStackPop (parse);
FcValue value;
value.type = FcTypeVoid;
if (!vstack)
return value;
switch (vstack->tag) {
case FcVStackString:
Add functionality to allow fontconfig data structure serialization. This patch allows the fundamental fontconfig data structures to be serialized. I've converted everything from FcPattern down to be able to use *Ptr objects, which can be either static or dynamic (using a union which either contains a pointer or an index) and replaced storage of pointers in the heap with the appropriate *Ptr object. I then changed all writes of pointers to the heap with a *CreateDynamic call, which creates a dynamic Ptr object pointing to the same object as before. This way, the fundamental fontconfig semantics should be unchanged; I did not have to change external signatures this way, although I did change some internal signatures. When given a *Ptr object, just run *U to get back to a normal pointer; it gives the right answer regardless of whether we're using static or dynamic storage. I've also implemented a Fc*Serialize call. Calling FcFontSetSerialize converts the dynamic FcFontSets contained in the config object to static FcFontSets and also converts its dependencies (e.g. everything you'd need to write to disk) to static objects. Note that you have to call Fc*PrepareSerialize first; this call will count the number of objects that actually needs to be allocated, so that we can avoid realloc. The Fc*Serialize calls then check the static pointers for nullness, and allocate the buffers if necessary. I've tested the execution of fc-list and fc-match after Fc*Serialize and they appear to work the same way.
2005-06-28 05:41:02 +02:00
value.u.si = FcObjectPtrCreateDynamic(FcStrCopy (vstack->u.string));
if (FcObjectPtrU(value.u.si))
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:
Add functionality to allow fontconfig data structure serialization. This patch allows the fundamental fontconfig data structures to be serialized. I've converted everything from FcPattern down to be able to use *Ptr objects, which can be either static or dynamic (using a union which either contains a pointer or an index) and replaced storage of pointers in the heap with the appropriate *Ptr object. I then changed all writes of pointers to the heap with a *CreateDynamic call, which creates a dynamic Ptr object pointing to the same object as before. This way, the fundamental fontconfig semantics should be unchanged; I did not have to change external signatures this way, although I did change some internal signatures. When given a *Ptr object, just run *U to get back to a normal pointer; it gives the right answer regardless of whether we're using static or dynamic storage. I've also implemented a Fc*Serialize call. Calling FcFontSetSerialize converts the dynamic FcFontSets contained in the config object to static FcFontSets and also converts its dependencies (e.g. everything you'd need to write to disk) to static objects. Note that you have to call Fc*PrepareSerialize first; this call will count the number of objects that actually needs to be allocated, so that we can avoid realloc. The Fc*Serialize calls then check the static pointers for nullness, and allocate the buffers if necessary. I've tested the execution of fc-list and fc-match after Fc*Serialize and they appear to work the same way.
2005-06-28 05:41:02 +02:00
value.u.mi = FcMatrixPtrCreateDynamic(FcMatrixCopy (vstack->u.matrix));
if (FcMatrixPtrU(value.u.mi))
value.type = FcTypeMatrix;
break;
case FcVStackBool:
value.u.b = vstack->u.bool;
value.type = FcTypeBool;
break;
default:
FcConfigMessage (parse, FcSevereWarning, "unknown pattern element %d",
vstack->tag);
break;
}
FcVStackDestroy (vstack);
return value;
}
static void
FcParsePatelt (FcConfigParse *parse)
{
FcValue value;
FcPattern *pattern = FcPatternCreate ();
const char *name;
if (!pattern)
{
FcConfigMessage (parse, FcSevereError, "out of memory");
return;
}
name = FcConfigGetAttribute (parse, "name");
if (!name)
{
FcConfigMessage (parse, FcSevereWarning, "missing pattern element name");
return;
}
for (;;)
{
value = FcPopValue (parse);
if (value.type == FcTypeVoid)
break;
if (!FcPatternAdd (pattern, name, value, FcTrue))
{
FcConfigMessage (parse, FcSevereError, "out of memory");
break;
}
}
FcVStackPushPattern (parse, pattern);
}
static void
FcParsePattern (FcConfigParse *parse)
{
FcVStack *vstack;
FcPattern *pattern = FcPatternCreate ();
if (!pattern)
{
FcConfigMessage (parse, FcSevereError, "out of memory");
return;
}
while ((vstack = FcVStackPop (parse)))
{
switch (vstack->tag) {
case FcVStackPattern:
if (!FcPatternAppend (pattern, vstack->u.pattern))
{
FcConfigMessage (parse, FcSevereError, "out of memory");
return;
}
break;
default:
FcConfigMessage (parse, FcSevereWarning, "unknown pattern element");
break;
}
FcVStackDestroy (vstack);
}
FcVStackPushPattern (parse, pattern);
}
static void
FcEndElement(void *userData, const XML_Char *name)
{
FcConfigParse *parse = userData;
FcChar8 *data;
if (!parse->pstack)
return;
switch (parse->pstack->element) {
case FcElementNone:
break;
case FcElementFontconfig:
break;
case FcElementDir:
data = FcStrBufDone (&parse->pstack->str);
if (!data)
2002-02-15 00:34:13 +01:00
{
FcConfigMessage (parse, FcSevereError, "out of memory");
break;
2002-02-15 00:34:13 +01:00
}
#ifdef _WIN32
if (strcmp (data, "WINDOWSFONTDIR") == 0)
{
int rc;
FcStrFree (data);
data = malloc (1000);
if (!data)
{
FcConfigMessage (parse, FcSevereError, "out of memory");
break;
}
FcMemAlloc (FC_MEM_STRING, 1000);
rc = GetWindowsDirectory (data, 800);
if (rc == 0 || rc > 800)
{
FcConfigMessage (parse, FcSevereError, "GetWindowsDirectory failed");
FcStrFree (data);
break;
}
if (data [strlen (data) - 1] != '\\')
strcat (data, "\\");
strcat (data, "fonts");
}
#endif
if (!FcStrUsesHome (data) || FcConfigHome ())
{
if (!FcConfigAddDir (parse->config, data))
FcConfigMessage (parse, FcSevereError, "out of memory");
}
FcStrFree (data);
break;
case FcElementCache:
data = FcStrBufDone (&parse->pstack->str);
if (!data)
2002-02-15 00:34:13 +01:00
{
FcConfigMessage (parse, FcSevereError, "out of memory");
2002-02-15 00:34:13 +01:00
break;
}
if (!FcStrUsesHome (data) || FcConfigHome ())
{
if (!FcConfigSetCache (parse->config, data))
FcConfigMessage (parse, FcSevereError, "out of memory");
}
FcStrFree (data);
break;
case FcElementInclude:
FcParseInclude (parse);
break;
case FcElementConfig:
break;
case FcElementMatch:
FcParseMatch (parse);
break;
case FcElementAlias:
FcParseAlias (parse);
break;
case FcElementBlank:
FcParseBlank (parse);
break;
case FcElementRescan:
FcParseRescan (parse);
break;
case FcElementPrefer:
FcParseFamilies (parse, FcVStackPrefer);
break;
case FcElementAccept:
FcParseFamilies (parse, FcVStackAccept);
break;
case FcElementDefault:
FcParseFamilies (parse, FcVStackDefault);
break;
case FcElementFamily:
FcParseFamily (parse);
break;
case FcElementTest:
FcParseTest (parse);
break;
case FcElementEdit:
FcParseEdit (parse);
break;
case FcElementInt:
FcParseInt (parse);
break;
case FcElementDouble:
FcParseDouble (parse);
break;
case FcElementString:
FcParseString (parse, FcVStackString);
break;
case FcElementMatrix:
FcParseMatrix (parse);
break;
case FcElementBool:
FcParseBool (parse);
break;
case FcElementCharset:
/* FcParseCharset (parse); */
break;
case FcElementSelectfont:
break;
case FcElementAcceptfont:
case FcElementRejectfont:
FcParseAcceptRejectFont (parse, parse->pstack->element);
break;
case FcElementGlob:
FcParseString (parse, FcVStackGlob);
break;
case FcElementPattern:
FcParsePattern (parse);
break;
case FcElementPatelt:
FcParsePatelt (parse);
break;
case FcElementName:
FcParseString (parse, FcVStackField);
break;
case FcElementConst:
FcParseString (parse, FcVStackConstant);
break;
case FcElementOr:
FcParseBinary (parse, FcOpOr);
break;
case FcElementAnd:
FcParseBinary (parse, FcOpAnd);
break;
case FcElementEq:
FcParseBinary (parse, FcOpEqual);
break;
case FcElementNotEq:
FcParseBinary (parse, FcOpNotEqual);
break;
case FcElementLess:
FcParseBinary (parse, FcOpLess);
break;
case FcElementLessEq:
FcParseBinary (parse, FcOpLessEqual);
break;
case FcElementMore:
FcParseBinary (parse, FcOpMore);
break;
case FcElementMoreEq:
FcParseBinary (parse, FcOpMoreEqual);
break;
case FcElementContains:
FcParseBinary (parse, FcOpContains);
break;
case FcElementNotContains:
FcParseBinary (parse, FcOpNotContains);
break;
case FcElementPlus:
FcParseBinary (parse, FcOpPlus);
break;
case FcElementMinus:
FcParseBinary (parse, FcOpMinus);
break;
case FcElementTimes:
FcParseBinary (parse, FcOpTimes);
break;
case FcElementDivide:
FcParseBinary (parse, FcOpDivide);
break;
case FcElementNot:
FcParseUnary (parse, FcOpNot);
break;
case FcElementIf:
FcParseBinary (parse, FcOpQuest);
break;
case FcElementFloor:
FcParseUnary (parse, FcOpFloor);
break;
case FcElementCeil:
FcParseUnary (parse, FcOpCeil);
break;
case FcElementRound:
FcParseUnary (parse, FcOpRound);
break;
case FcElementTrunc:
FcParseUnary (parse, FcOpTrunc);
break;
case FcElementUnknown:
break;
2002-02-15 00:34:13 +01:00
}
(void) FcPStackPop (parse);
}
static void
FcCharacterData (void *userData, const XML_Char *s, int len)
{
FcConfigParse *parse = userData;
if (!parse->pstack)
return;
if (!FcStrBufData (&parse->pstack->str, (FcChar8 *) s, len))
FcConfigMessage (parse, FcSevereError, "out of memory");
}
static void
FcStartDoctypeDecl (void *userData,
const XML_Char *doctypeName,
const XML_Char *sysid,
const XML_Char *pubid,
int has_internal_subset)
{
FcConfigParse *parse = userData;
if (strcmp ((char *) doctypeName, "fontconfig") != 0)
FcConfigMessage (parse, FcSevereError, "invalid doctype \"%s\"", doctypeName);
}
static void
FcEndDoctypeDecl (void *userData)
{
2002-02-15 00:34:13 +01:00
}
static FcBool
FcConfigParseAndLoadDir (FcConfig *config,
const FcChar8 *name,
const FcChar8 *dir,
FcBool complain)
{
DIR *d;
struct dirent *e;
FcBool ret = FcTrue;
FcChar8 *file;
FcChar8 *base;
FcStrSet *files;
d = opendir ((char *) dir);
if (!d)
{
if (complain)
FcConfigMessage (0, FcSevereError, "Cannot open config dir \"%s\"",
name);
ret = FcFalse;
goto bail0;
}
/* freed below */
file = (FcChar8 *) malloc (strlen ((char *) dir) + 1 + FC_MAX_FILE_LEN + 1);
if (!file)
{
ret = FcFalse;
goto bail1;
}
strcpy ((char *) file, (char *) dir);
strcat ((char *) file, "/");
base = file + strlen ((char *) file);
files = FcStrSetCreate ();
if (!files)
{
ret = FcFalse;
goto bail2;
}
if (FcDebug () & FC_DBG_CONFIG)
printf ("\tScanning config dir %s\n", dir);
while (ret && (e = readdir (d)))
{
/*
* Add all files of the form [0-9]*
*/
if ('0' <= e->d_name[0] && e->d_name[0] <= '9' &&
strlen (e->d_name) < FC_MAX_FILE_LEN)
{
strcpy ((char *) base, (char *) e->d_name);
if (!FcStrSetAdd (files, file))
{
ret = FcFalse;
goto bail3;
}
}
}
if (ret)
{
int i;
Add functionality to allow fontconfig data structure serialization. This patch allows the fundamental fontconfig data structures to be serialized. I've converted everything from FcPattern down to be able to use *Ptr objects, which can be either static or dynamic (using a union which either contains a pointer or an index) and replaced storage of pointers in the heap with the appropriate *Ptr object. I then changed all writes of pointers to the heap with a *CreateDynamic call, which creates a dynamic Ptr object pointing to the same object as before. This way, the fundamental fontconfig semantics should be unchanged; I did not have to change external signatures this way, although I did change some internal signatures. When given a *Ptr object, just run *U to get back to a normal pointer; it gives the right answer regardless of whether we're using static or dynamic storage. I've also implemented a Fc*Serialize call. Calling FcFontSetSerialize converts the dynamic FcFontSets contained in the config object to static FcFontSets and also converts its dependencies (e.g. everything you'd need to write to disk) to static objects. Note that you have to call Fc*PrepareSerialize first; this call will count the number of objects that actually needs to be allocated, so that we can avoid realloc. The Fc*Serialize calls then check the static pointers for nullness, and allocate the buffers if necessary. I've tested the execution of fc-list and fc-match after Fc*Serialize and they appear to work the same way.
2005-06-28 05:41:02 +02:00
FcStrSetSort (files);
for (i = 0; ret && i < files->num; i++)
Add functionality to allow fontconfig data structure serialization. This patch allows the fundamental fontconfig data structures to be serialized. I've converted everything from FcPattern down to be able to use *Ptr objects, which can be either static or dynamic (using a union which either contains a pointer or an index) and replaced storage of pointers in the heap with the appropriate *Ptr object. I then changed all writes of pointers to the heap with a *CreateDynamic call, which creates a dynamic Ptr object pointing to the same object as before. This way, the fundamental fontconfig semantics should be unchanged; I did not have to change external signatures this way, although I did change some internal signatures. When given a *Ptr object, just run *U to get back to a normal pointer; it gives the right answer regardless of whether we're using static or dynamic storage. I've also implemented a Fc*Serialize call. Calling FcFontSetSerialize converts the dynamic FcFontSets contained in the config object to static FcFontSets and also converts its dependencies (e.g. everything you'd need to write to disk) to static objects. Note that you have to call Fc*PrepareSerialize first; this call will count the number of objects that actually needs to be allocated, so that we can avoid realloc. The Fc*Serialize calls then check the static pointers for nullness, and allocate the buffers if necessary. I've tested the execution of fc-list and fc-match after Fc*Serialize and they appear to work the same way.
2005-06-28 05:41:02 +02:00
ret = FcConfigParseAndLoad (config, FcStrSetGet(files, i), complain);
}
bail3:
FcStrSetDestroy (files);
bail2:
free (file);
bail1:
closedir (d);
bail0:
return ret || !complain;
}
2002-02-15 00:34:13 +01:00
FcBool
FcConfigParseAndLoad (FcConfig *config,
const FcChar8 *name,
2002-02-15 00:34:13 +01:00
FcBool complain)
{
XML_Parser p;
FcChar8 *filename;
FILE *f;
int len;
void *buf;
FcConfigParse parse;
FcBool error = FcTrue;
filename = FcConfigFilename (name);
if (!filename)
goto bail0;
if (!FcStrSetAdd (config->configFiles, filename))
{
FcStrFree (filename);
goto bail0;
}
if (FcFileIsDir (filename))
{
FcBool ret = FcConfigParseAndLoadDir (config, name, filename, complain);
FcStrFree (filename);
return ret;
}
if (FcDebug () & FC_DBG_CONFIG)
printf ("\tLoading config file %s\n", filename);
f = fopen ((char *) filename, "r");
FcStrFree (filename);
if (!f)
goto bail0;
p = XML_ParserCreate ("UTF-8");
if (!p)
goto bail1;
if (!FcConfigInit (&parse, name, config, p))
goto bail2;
XML_SetUserData (p, &parse);
XML_SetDoctypeDeclHandler (p, FcStartDoctypeDecl, FcEndDoctypeDecl);
XML_SetElementHandler (p, FcStartElement, FcEndElement);
XML_SetCharacterDataHandler (p, FcCharacterData);
do {
buf = XML_GetBuffer (p, BUFSIZ);
if (!buf)
{
FcConfigMessage (&parse, FcSevereError, "cannot get parse buffer");
goto bail3;
}
len = fread (buf, 1, BUFSIZ, f);
if (len < 0)
{
FcConfigMessage (&parse, FcSevereError, "failed reading config file");
goto bail3;
}
if (!XML_ParseBuffer (p, len, len == 0))
{
FcConfigMessage (&parse, FcSevereError, "%s",
XML_ErrorString (XML_GetErrorCode (p)));
goto bail3;
}
} while (len != 0);
error = parse.error;
bail3:
FcConfigCleanup (&parse);
bail2:
XML_ParserFree (p);
bail1:
fclose (f);
bail0:
if (error && complain)
2002-02-15 00:34:13 +01:00
{
if (name)
FcConfigMessage (0, FcSevereError, "Cannot load config file \"%s\"", name);
2002-02-15 00:34:13 +01:00
else
FcConfigMessage (0, FcSevereError, "Cannot load default config file");
2002-02-15 00:34:13 +01:00
return FcFalse;
}
return FcTrue;
}