/*
- * $XFree86: xc/lib/fontconfig/src/fcxml.c,v 1.20 2002/08/20 23:17:03 keithp Exp $
+ * $RCSId: xc/lib/fontconfig/src/fcxml.c,v 1.21 2002/08/22 18:53:22 keithp Exp $
*
- * Copyright © 2002 Keith Packard, member of The XFree86 Project, Inc.
+ * Copyright © 2002 Keith Packard
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
#include <stdarg.h>
#include "fcint.h"
+#include <dirent.h>
#ifndef HAVE_XMLPARSE_H
#define HAVE_XMLPARSE_H 0
#include <expat.h>
#endif
-FcTest *
-FcTestCreate (FcMatchKind kind,
- FcQual qual,
- const FcChar8 *field,
- FcOp compare,
- FcExpr *expr)
-{
- FcTest *test = (FcTest *) malloc (sizeof (FcTest));
+#ifdef _WIN32
+#define STRICT
+#include <windows.h>
+#undef STRICT
+#endif
- if (test)
- {
- test->next = 0;
- test->kind = kind;
- test->qual = qual;
- test->field = (char *) FcStrCopy (field);
- test->op = compare;
- test->expr = expr;
- }
- return test;
-}
void
FcTestDestroy (FcTest *test)
FcTestDestroy (test->next);
FcExprDestroy (test->expr);
FcStrFree ((FcChar8 *) test->field);
+ FcMemFree (FC_MEM_TEST, sizeof (FcTest));
free (test);
}
if (e)
{
+ FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
e->op = FcOpInteger;
e->u.ival = i;
}
if (e)
{
+ FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
e->op = FcOpDouble;
e->u.dval = d;
}
if (e)
{
+ FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
e->op = FcOpString;
e->u.sval = FcStrCopy (s);
}
if (e)
{
+ FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
e->op = FcOpMatrix;
e->u.mval = FcMatrixCopy (m);
}
if (e)
{
+ FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
e->op = FcOpBool;
e->u.bval = b;
}
if (e)
{
+ FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
e->op = FcOpNil;
}
return e;
if (e)
{
+ FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
e->op = FcOpField;
e->u.field = (char *) FcStrCopy ((FcChar8 *) field);
}
if (e)
{
+ FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
e->op = FcOpConst;
e->u.constant = FcStrCopy (constant);
}
if (e)
{
+ FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
e->op = op;
e->u.tree.left = left;
e->u.tree.right = right;
void
FcExprDestroy (FcExpr *e)
{
+ if (!e)
+ return;
switch (e->op) {
case FcOpInteger:
break;
case FcOpMore:
case FcOpMoreEqual:
case FcOpContains:
+ case FcOpListing:
case FcOpNotContains:
case FcOpPlus:
case FcOpMinus:
FcExprDestroy (e->u.tree.right);
/* fall through */
case FcOpNot:
+ case FcOpFloor:
+ case FcOpCeil:
+ case FcOpRound:
+ case FcOpTrunc:
FcExprDestroy (e->u.tree.left);
break;
case FcOpNil:
case FcOpInvalid:
break;
}
+ FcMemFree (FC_MEM_EXPR, sizeof (FcExpr));
free (e);
}
-FcEdit *
-FcEditCreate (const char *field, FcOp op, FcExpr *expr, FcValueBinding binding)
-{
- FcEdit *e = (FcEdit *) malloc (sizeof (FcEdit));
-
- if (e)
- {
- e->next = 0;
- e->field = field; /* already saved in grammar */
- e->op = op;
- e->expr = expr;
- e->binding = binding;
- }
- return e;
-}
-
void
FcEditDestroy (FcEdit *e)
{
FcStrFree ((FcChar8 *) e->field);
if (e->expr)
FcExprDestroy (e->expr);
+ free (e);
}
char *
FcElementDefault,
FcElementFamily,
+ FcElementSelectfont,
+ FcElementAcceptfont,
+ FcElementRejectfont,
+ FcElementGlob,
+ FcElementPattern,
+ FcElementPatelt,
+
FcElementTest,
FcElementEdit,
FcElementInt,
FcElementDivide,
FcElementNot,
FcElementIf,
+ FcElementFloor,
+ FcElementCeil,
+ FcElementRound,
+ FcElementTrunc,
FcElementUnknown
} FcElement;
+static struct {
+ const char name[16];
+ 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 },
+};
+#define NUM_ELEMENT_MAPS (int) (sizeof fcElementMap / sizeof fcElementMap[0])
+
static FcElement
FcElementMap (const XML_Char *name)
{
- static struct {
- char *name;
- FcElement element;
- } fcElementMap[] = {
- { "fontconfig", FcElementFontconfig },
- { "dir", FcElementDir },
- { "cache", FcElementCache },
- { "include", FcElementInclude },
- { "config", FcElementConfig },
- { "match", FcElementMatch },
- { "alias", FcElementAlias },
-
- { "blank", FcElementBlank },
- { "rescan", FcElementRescan },
-
- { "prefer", FcElementPrefer },
- { "accept", FcElementAccept },
- { "default", FcElementDefault },
- { "family", FcElementFamily },
-
- { "test", FcElementTest },
- { "edit", FcElementEdit },
- { "int", FcElementInt },
- { "double", FcElementDouble },
- { "string", FcElementString },
- { "matrix", FcElementMatrix },
- { "bool", FcElementBool },
- { "charset", FcElementCharset },
- { "name", FcElementName },
- { "const", FcElementConst },
- { "or", FcElementOr },
- { "and", FcElementAnd },
- { "eq", FcElementEq },
- { "not_eq", FcElementNotEq },
- { "less", FcElementLess },
- { "less_eq", FcElementLessEq },
- { "more", FcElementMore },
- { "more_eq", FcElementMoreEq },
- { "contains", FcElementContains },
- { "not_contains",FcElementNotContains },
- { "plus", FcElementPlus },
- { "minus", FcElementMinus },
- { "times", FcElementTimes },
- { "divide", FcElementDivide },
- { "not", FcElementNot },
- { "if", FcElementIf },
-
- { 0, 0 }
- };
int i;
- for (i = 0; fcElementMap[i].name; i++)
+ for (i = 0; i < NUM_ELEMENT_MAPS; i++)
if (!strcmp ((char *) name, fcElementMap[i].name))
return fcElementMap[i].element;
return FcElementUnknown;
FcVStackFamily,
FcVStackField,
FcVStackConstant,
+ FcVStackGlob,
+ FcVStackPattern,
FcVStackPrefer,
FcVStackAccept,
FcOp op;
FcExpr *expr;
FcEdit *edit;
+
+ FcPattern *pattern;
} u;
} FcVStack;
} FcConfigSeverity;
static void
-FcConfigMessage (FcConfigParse *parse, FcConfigSeverity severe, char *fmt, ...)
+FcConfigMessage (FcConfigParse *parse, FcConfigSeverity severe, const char *fmt, ...)
{
- char *s = "unknown";
+ const char *s = "unknown";
va_list args;
va_start (args, fmt);
va_end (args);
}
+
+static const char *
+FcTypeName (FcType type)
+{
+ switch (type) {
+ case FcTypeVoid:
+ return "void";
+ case FcTypeInteger:
+ case FcTypeDouble:
+ return "number";
+ case FcTypeString:
+ return "string";
+ case FcTypeBool:
+ return "bool";
+ case FcTypeMatrix:
+ return "matrix";
+ case FcTypeCharSet:
+ return "charset";
+ case FcTypeFTFace:
+ return "FT_Face";
+ case FcTypeLangSet:
+ return "langset";
+ default:
+ return "unknown";
+ }
+}
+
+static void
+FcTypecheckValue (FcConfigParse *parse, FcType value, FcType type)
+{
+ if (value == FcTypeInteger)
+ value = FcTypeDouble;
+ if (type == FcTypeInteger)
+ type = FcTypeDouble;
+ if (value != type)
+ {
+ if ((value == FcTypeLangSet && type == FcTypeString) ||
+ (value == FcTypeString && type == FcTypeLangSet))
+ return;
+ 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)
{
new = malloc (sizeof (FcVStack));
if (!new)
return 0;
+ FcMemAlloc (FC_MEM_VSTACK, sizeof (FcVStack));
new->tag = FcVStackNone;
new->prev = 0;
return new;
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;
FcEditDestroy (vstack->u.edit);
break;
}
+ FcMemFree (FC_MEM_VSTACK, sizeof (FcVStack));
free (vstack);
}
}
return FcTrue;
}
+static FcBool
+FcVStackPushPattern (FcConfigParse *parse, FcPattern *pattern)
+{
+ FcVStack *vstack = FcVStackCreate ();
+ if (!vstack)
+ return FcFalse;
+ vstack->u.pattern = pattern;
+ vstack->tag = FcVStackPattern;
+ FcVStackPush (parse, vstack);
+ return FcTrue;
+}
+
static FcVStack *
FcVStackFetch (FcConfigParse *parse, int off)
{
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++)
{
if (!new)
return FcFalse;
+ FcMemAlloc (FC_MEM_PSTACK, sizeof (FcPStack));
new->prev = parse->pstack;
new->element = element;
if (attr)
parse->pstack = old->prev;
FcStrBufDestroy (&old->str);
if (old->attr)
+ {
+ FcMemFree (FC_MEM_ATTR, 1); /* size is to expensive */
free (old->attr);
+ }
+ FcMemFree (FC_MEM_PSTACK, sizeof (FcPStack));
free (old);
return FcTrue;
}
}
static const FcChar8 *
-FcConfigGetAttribute (FcConfigParse *parse, char *attr)
+FcConfigGetAttribute (FcConfigParse *parse, const char *attr)
{
FcChar8 **attrs;
if (!parse->pstack)
int slen = strlen (s);
int dlen = strlen (locale_data->decimal_point);
- if (slen + dlen > sizeof (buf))
+ if (slen + dlen > (int) sizeof (buf))
{
if (end)
*end = s;
strcpy (buf + (dot - s) + dlen, dot + 1);
buf_end = 0;
v = strtod (buf, &buf_end);
- if (buf_end)
+ if (buf_end) {
buf_end = s + (buf_end - buf);
+ if (buf_end > dot)
+ buf_end -= dlen - 1;
+ }
if (end)
*end = buf_end;
}
}
static FcBool
-FcConfigLexBool (const FcChar8 *bool)
+FcConfigLexBool (FcConfigParse *parse, const FcChar8 *bool)
{
- if (*bool == 't' || *bool == 'T')
- return FcTrue;
- if (*bool == 'y' || *bool == 'Y')
- return FcTrue;
- if (*bool == '1')
- return FcTrue;
- return FcFalse;
+ FcBool result = FcFalse;
+
+ if (!FcNameBool (bool, &result))
+ FcConfigMessage (parse, FcSevereWarning, "\"%s\" is not known boolean",
+ bool);
+ return result;
}
static void
FcConfigMessage (parse, FcSevereError, "out of memory");
return;
}
- FcVStackPushBool (parse, FcConfigLexBool (s));
+ FcVStackPushBool (parse, FcConfigLexBool (parse, s));
FcStrFree (s);
}
}
if (prefer)
{
- edit = FcEditCreate (FcConfigSaveField ("family"),
+ edit = FcEditCreate (parse,
+ FcConfigSaveField ("family"),
FcOpPrepend,
prefer,
FcValueBindingWeak);
if (accept)
{
next = edit;
- edit = FcEditCreate (FcConfigSaveField ("family"),
+ edit = FcEditCreate (parse,
+ FcConfigSaveField ("family"),
FcOpAppend,
accept,
FcValueBindingWeak);
if (def)
{
next = edit;
- edit = FcEditCreate (FcConfigSaveField ("family"),
+ edit = FcEditCreate (parse,
+ FcConfigSaveField ("family"),
FcOpAppendLast,
def,
FcValueBindingWeak);
}
if (edit)
{
- test = FcTestCreate (FcMatchPattern,
+ test = FcTestCreate (parse, FcMatchPattern,
FcQualAny,
(FcChar8 *) FC_FAMILY,
FcOpEqual,
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:
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 *
-FcPopExprs (FcConfigParse *parse, FcOp op)
+FcPopBinary (FcConfigParse *parse, FcOp op)
{
FcExpr *left, *expr = 0, *new;
}
static void
-FcParseExpr (FcConfigParse *parse, FcOp op)
+FcParseBinary (FcConfigParse *parse, FcOp op)
{
- FcExpr *expr = FcPopExprs (parse, 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);
}
return;
}
i = FcConfigGetAttribute (parse, "ignore_missing");
- if (i && FcConfigLexBool ((FcChar8 *) i) == FcTrue)
+ if (i && FcConfigLexBool (parse, (FcChar8 *) i) == FcTrue)
ignore_missing = FcTrue;
if (!FcConfigParseAndLoad (parse->config, s, !ignore_missing))
parse->error = FcTrue;
- free (s);
+ FcStrFree (s);
}
typedef struct _FcOpMap {
- char *name;
+ char name[16];
FcOp op;
} FcOpMap;
{ "not_contains", FcOpNotContains }
};
-#define NUM_COMPARE_OPS (sizeof fcCompareOps / sizeof fcCompareOps[0])
+#define NUM_COMPARE_OPS (int) (sizeof fcCompareOps / sizeof fcCompareOps[0])
static FcOp
FcConfigLexCompare (const FcChar8 *compare)
return;
}
}
- expr = FcPopExprs (parse, FcOpComma);
+ expr = FcPopBinary (parse, FcOpComma);
if (!expr)
{
FcConfigMessage (parse, FcSevereWarning, "missing test expression");
return;
}
- test = FcTestCreate (kind, qual, name, compare, expr);
+ test = FcTestCreate (parse, kind, qual, name, compare, expr);
if (!test)
{
FcConfigMessage (parse, FcSevereError, "out of memory");
{ "append_last", FcOpAppendLast },
};
-#define NUM_MODE_OPS (sizeof fcModeOps / sizeof fcModeOps[0])
+#define NUM_MODE_OPS (int) (sizeof fcModeOps / sizeof fcModeOps[0])
static FcOp
FcConfigLexMode (const FcChar8 *mode)
binding = FcValueBindingWeak;
else if (!strcmp ((char *) binding_string, "strong"))
binding = FcValueBindingStrong;
+ else if (!strcmp ((char *) binding_string, "same"))
+ binding = FcValueBindingSame;
else
{
FcConfigMessage (parse, FcSevereWarning, "invalid edit binding \"%s\"", binding_string);
return;
}
}
- expr = FcPopExprs (parse, FcOpComma);
- edit = FcEditCreate ((char *) FcStrCopy (name), mode, expr, binding);
+ expr = FcPopBinary (parse, FcOpComma);
+ edit = FcEditCreate (parse, (char *) FcStrCopy (name), mode, expr, binding);
if (!edit)
{
FcConfigMessage (parse, FcSevereError, "out of memory");
FcConfigMessage (parse, FcSevereError, "out of memory");
}
+static void
+FcParseAcceptRejectFont (FcConfigParse *parse, FcElement element)
+{
+ FcVStack *vstack;
+
+ while ((vstack = FcVStackPop (parse)))
+ {
+ switch (vstack->tag) {
+ case FcVStackGlob:
+ if (!FcConfigGlobAdd (parse->config,
+ vstack->u.string,
+ element == FcElementAcceptfont))
+ {
+ FcConfigMessage (parse, FcSevereError, "out of memory");
+ }
+ break;
+ case FcVStackPattern:
+ if (!FcConfigPatternsAdd (parse->config,
+ vstack->u.pattern,
+ element == FcElementAcceptfont))
+ {
+ FcConfigMessage (parse, FcSevereError, "out of memory");
+ }
+ else
+ vstack->tag = FcVStackNone;
+ break;
+ default:
+ FcConfigMessage (parse, FcSevereWarning, "bad font selector");
+ break;
+ }
+ FcVStackDestroy (vstack);
+ }
+}
+
+
+static FcValue
+FcPopValue (FcConfigParse *parse)
+{
+ FcVStack *vstack = FcVStackPop (parse);
+ FcValue value;
+
+ value.type = FcTypeVoid;
+
+ if (!vstack)
+ return value;
+
+ switch (vstack->tag) {
+ case FcVStackString:
+ value.u.s = FcStrCopy (vstack->u.string);
+ if (value.u.s)
+ value.type = FcTypeString;
+ break;
+ case FcVStackConstant:
+ if (FcNameConstant (vstack->u.string, &value.u.i))
+ value.type = FcTypeInteger;
+ break;
+ case FcVStackInteger:
+ value.u.i = vstack->u.integer;
+ value.type = FcTypeInteger;
+ break;
+ case FcVStackDouble:
+ value.u.d = vstack->u._double;
+ value.type = FcTypeInteger;
+ break;
+ case FcVStackMatrix:
+ value.u.m = FcMatrixCopy (vstack->u.matrix);
+ if (value.u.m)
+ value.type = FcTypeMatrix;
+ break;
+ case FcVStackBool:
+ value.u.b = vstack->u.bool;
+ value.type = FcTypeBool;
+ break;
+ default:
+ FcConfigMessage (parse, FcSevereWarning, "unknown pattern element %d",
+ vstack->tag);
+ break;
+ }
+ FcVStackDestroy (vstack);
+
+ return value;
+}
+
+static void
+FcParsePatelt (FcConfigParse *parse)
+{
+ FcValue value;
+ FcPattern *pattern = FcPatternCreate ();
+ const char *name;
+
+ if (!pattern)
+ {
+ FcConfigMessage (parse, FcSevereError, "out of memory");
+ return;
+ }
+
+ name = (char *) 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)
{
FcConfigMessage (parse, FcSevereError, "out of memory");
break;
}
- if (!FcConfigAddDir (parse->config, data))
- FcConfigMessage (parse, FcSevereError, "out of memory");
- free (data);
+#ifdef _WIN32
+ if (strcmp (data, "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);
FcConfigMessage (parse, FcSevereError, "out of memory");
break;
}
- if (!FcConfigSetCache (parse->config, data))
- FcConfigMessage (parse, FcSevereError, "out of memory");
- free (data);
+ if (!FcStrUsesHome (data) || FcConfigHome ())
+ {
+ if (!FcConfigSetCache (parse->config, data))
+ FcConfigMessage (parse, FcSevereError, "out of memory");
+ }
+ FcStrFree (data);
break;
case FcElementInclude:
FcParseInclude (parse);
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;
FcParseString (parse, FcVStackConstant);
break;
case FcElementOr:
- FcParseExpr (parse, FcOpOr);
+ FcParseBinary (parse, FcOpOr);
break;
case FcElementAnd:
- FcParseExpr (parse, FcOpAnd);
+ FcParseBinary (parse, FcOpAnd);
break;
case FcElementEq:
- FcParseExpr (parse, FcOpEqual);
+ FcParseBinary (parse, FcOpEqual);
break;
case FcElementNotEq:
- FcParseExpr (parse, FcOpNotEqual);
+ FcParseBinary (parse, FcOpNotEqual);
break;
case FcElementLess:
- FcParseExpr (parse, FcOpLess);
+ FcParseBinary (parse, FcOpLess);
break;
case FcElementLessEq:
- FcParseExpr (parse, FcOpLessEqual);
+ FcParseBinary (parse, FcOpLessEqual);
break;
case FcElementMore:
- FcParseExpr (parse, FcOpMore);
+ FcParseBinary (parse, FcOpMore);
break;
case FcElementMoreEq:
- FcParseExpr (parse, FcOpMoreEqual);
+ FcParseBinary (parse, FcOpMoreEqual);
break;
case FcElementContains:
- FcParseExpr (parse, FcOpContains);
+ FcParseBinary (parse, FcOpContains);
break;
case FcElementNotContains:
- FcParseExpr (parse, FcOpNotContains);
+ FcParseBinary (parse, FcOpNotContains);
break;
case FcElementPlus:
- FcParseExpr (parse, FcOpPlus);
+ FcParseBinary (parse, FcOpPlus);
break;
case FcElementMinus:
- FcParseExpr (parse, FcOpMinus);
+ FcParseBinary (parse, FcOpMinus);
break;
case FcElementTimes:
- FcParseExpr (parse, FcOpTimes);
+ FcParseBinary (parse, FcOpTimes);
break;
case FcElementDivide:
- FcParseExpr (parse, FcOpDivide);
+ FcParseBinary (parse, FcOpDivide);
break;
case FcElementNot:
- FcParseExpr (parse, FcOpNot);
+ FcParseUnary (parse, FcOpNot);
break;
case FcElementIf:
- FcParseExpr (parse, FcOpQuest);
+ FcParseBinary (parse, FcOpQuest);
+ break;
+ case FcElementFloor:
+ FcParseUnary (parse, FcOpFloor);
+ break;
+ case FcElementCeil:
+ FcParseUnary (parse, FcOpCeil);
+ break;
+ case FcElementRound:
+ FcParseUnary (parse, FcOpRound);
+ break;
+ case FcElementTrunc:
+ FcParseUnary (parse, FcOpTrunc);
break;
case FcElementUnknown:
break;
{
}
+static FcBool
+FcConfigParseAndLoadDir (FcConfig *config,
+ const FcChar8 *name,
+ const FcChar8 *dir,
+ FcBool complain)
+{
+ DIR *d;
+ struct dirent *e;
+ FcBool ret = FcTrue;
+ FcChar8 *file;
+ FcChar8 *base;
+ FcStrSet *files;
+
+ d = opendir ((char *) dir);
+ if (!d)
+ {
+ if (complain)
+ FcConfigMessage (0, FcSevereError, "Cannot open config dir \"%s\"",
+ name);
+ ret = FcFalse;
+ goto bail0;
+ }
+ /* freed below */
+ file = (FcChar8 *) malloc (strlen ((char *) dir) + 1 + FC_MAX_FILE_LEN + 1);
+ if (!file)
+ {
+ ret = FcFalse;
+ goto bail1;
+ }
+
+ strcpy ((char *) file, (char *) dir);
+ strcat ((char *) file, "/");
+ base = file + strlen ((char *) file);
+
+ files = FcStrSetCreate ();
+ if (!files)
+ {
+ ret = FcFalse;
+ goto bail2;
+ }
+
+ if (FcDebug () & FC_DBG_CONFIG)
+ printf ("\tScanning config dir %s\n", dir);
+
+ while (ret && (e = readdir (d)))
+ {
+ int d_len;
+#define TAIL ".conf"
+#define TAIL_LEN 5
+ /*
+ * Add all files of the form [0-9]*.conf
+ */
+ if ('0' <= e->d_name[0] && e->d_name[0] <= '9' &&
+ (d_len = strlen (e->d_name)) < FC_MAX_FILE_LEN &&
+ d_len > TAIL_LEN &&
+ strcmp (e->d_name + d_len - TAIL_LEN, TAIL) == 0)
+ {
+ strcpy ((char *) base, (char *) e->d_name);
+ if (!FcStrSetAdd (files, file))
+ {
+ ret = FcFalse;
+ goto bail3;
+ }
+ }
+ }
+ if (ret)
+ {
+ int i;
+ qsort (files->strs, files->num, sizeof (FcChar8 *),
+ (int (*)(const void *, const void *)) FcStrCmp);
+ for (i = 0; ret && i < files->num; i++)
+ ret = FcConfigParseAndLoad (config, files->strs[i], complain);
+ }
+bail3:
+ FcStrSetDestroy (files);
+bail2:
+ free (file);
+bail1:
+ closedir (d);
+bail0:
+ return ret || !complain;
+}
+
FcBool
FcConfigParseAndLoad (FcConfig *config,
const FcChar8 *name,
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");
- free (filename);
+ FcStrFree (filename);
if (!f)
goto bail0;
XML_ParserFree (p);
bail1:
fclose (f);
+ f = NULL;
bail0:
if (error && complain)
{