summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKeith Packard <keithp@keithp.com>2005-01-28 23:55:14 +0000
committerKeith Packard <keithp@keithp.com>2005-01-28 23:55:14 +0000
commitca60d2b5c503cb58ed235cbdd82ac623cda307ff (patch)
tree58ca40e8c2afd16460c4d58fee30b6ccf5e1b8c8
parent59e149e757795a7c0ec66c35b551a66e0da42098 (diff)
downloadfontconfig-ca60d2b5c503cb58ed235cbdd82ac623cda307ff.tar.gz
Polite typechecking for test and edit expressions. Helps catch errors in
the font configuration.
-rw-r--r--ChangeLog10
-rw-r--r--src/fcint.h12
-rw-r--r--src/fcname.c2
-rw-r--r--src/fcxml.c252
4 files changed, 211 insertions, 65 deletions
diff --git a/ChangeLog b/ChangeLog
index 1204864..0143203 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2005-01-28 Keith Packard <keithp@keithp.com>
+
+ * src/fcint.h:
+ * src/fcname.c: (FcNameBool):
+ * src/fcxml.c: (FcTypeName), (FcTypecheckValue), (FcTypecheckExpr),
+ (FcTestCreate), (FcEditCreate), (FcConfigLexBool), (FcParseBool),
+ (FcParseAlias), (FcParseInclude), (FcParseTest), (FcParseEdit):
+ Polite typechecking for test and edit expressions. Helps
+ catch errors in the font configuration.
+
2005-01-15 Alan Coopersmith <alan.coopersmith@sun.com>
reviewed by: Keith Packard <keithp@keithp.com>
diff --git a/src/fcint.h b/src/fcint.h
index 4dca3c5..24bf246 100644
--- a/src/fcint.h
+++ b/src/fcint.h
@@ -609,13 +609,6 @@ FcConfigerror (char *fmt, ...);
char *
FcConfigSaveField (const char *field);
-FcTest *
-FcTestCreate (FcMatchKind kind,
- FcQual qual,
- const FcChar8 *field,
- FcOp compare,
- FcExpr *expr);
-
void
FcTestDestroy (FcTest *test);
@@ -649,9 +642,6 @@ FcExprCreateOp (FcExpr *left, FcOp op, FcExpr *right);
void
FcExprDestroy (FcExpr *e);
-FcEdit *
-FcEditCreate (const char *field, FcOp op, FcExpr *expr, FcValueBinding binding);
-
void
FcEditDestroy (FcEdit *e);
@@ -697,7 +687,7 @@ FcListPatternMatchAny (const FcPattern *p,
/* fcname.c */
FcBool
-FcNameBool (FcChar8 *v, FcBool *result);
+FcNameBool (const FcChar8 *v, FcBool *result);
/* fcpat.c */
void
diff --git a/src/fcname.c b/src/fcname.c
index 2abf949..1cce324 100644
--- a/src/fcname.c
+++ b/src/fcname.c
@@ -274,7 +274,7 @@ FcNameConstant (FcChar8 *string, int *result)
}
FcBool
-FcNameBool (FcChar8 *v, FcBool *result)
+FcNameBool (const FcChar8 *v, FcBool *result)
{
char c0, c1;
diff --git a/src/fcxml.c b/src/fcxml.c
index f5cbdf4..539e57f 100644
--- a/src/fcxml.c
+++ b/src/fcxml.c
@@ -42,27 +42,6 @@
#undef STRICT
#endif
-FcTest *
-FcTestCreate (FcMatchKind kind,
- FcQual qual,
- const FcChar8 *field,
- FcOp compare,
- FcExpr *expr)
-{
- FcTest *test = (FcTest *) malloc (sizeof (FcTest));
-
- if (test)
- {
- 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;
- }
- return test;
-}
void
FcTestDestroy (FcTest *test)
@@ -269,22 +248,6 @@ FcExprDestroy (FcExpr *e)
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)
{
@@ -528,6 +491,187 @@ FcConfigMessage (FcConfigParse *parse, FcConfigSeverity severe, char *fmt, ...)
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)
{
@@ -1091,15 +1235,14 @@ FcParseMatrix (FcConfigParse *parse)
}
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
@@ -1115,7 +1258,7 @@ FcParseBool (FcConfigParse *parse)
FcConfigMessage (parse, FcSevereError, "out of memory");
return;
}
- FcVStackPushBool (parse, FcConfigLexBool (s));
+ FcVStackPushBool (parse, FcConfigLexBool (parse, s));
FcStrFree (s);
}
@@ -1247,7 +1390,8 @@ FcParseAlias (FcConfigParse *parse)
}
if (prefer)
{
- edit = FcEditCreate (FcConfigSaveField ("family"),
+ edit = FcEditCreate (parse,
+ FcConfigSaveField ("family"),
FcOpPrepend,
prefer,
FcValueBindingWeak);
@@ -1259,7 +1403,8 @@ FcParseAlias (FcConfigParse *parse)
if (accept)
{
next = edit;
- edit = FcEditCreate (FcConfigSaveField ("family"),
+ edit = FcEditCreate (parse,
+ FcConfigSaveField ("family"),
FcOpAppend,
accept,
FcValueBindingWeak);
@@ -1271,7 +1416,8 @@ FcParseAlias (FcConfigParse *parse)
if (def)
{
next = edit;
- edit = FcEditCreate (FcConfigSaveField ("family"),
+ edit = FcEditCreate (parse,
+ FcConfigSaveField ("family"),
FcOpAppendLast,
def,
FcValueBindingWeak);
@@ -1282,7 +1428,7 @@ FcParseAlias (FcConfigParse *parse)
}
if (edit)
{
- test = FcTestCreate (FcMatchPattern,
+ test = FcTestCreate (parse, FcMatchPattern,
FcQualAny,
(FcChar8 *) FC_FAMILY,
FcOpEqual,
@@ -1437,7 +1583,7 @@ FcParseInclude (FcConfigParse *parse)
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;
@@ -1553,7 +1699,7 @@ FcParseTest (FcConfigParse *parse)
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");
@@ -1626,7 +1772,7 @@ FcParseEdit (FcConfigParse *parse)
}
}
expr = FcPopBinary (parse, FcOpComma);
- edit = FcEditCreate ((char *) FcStrCopy (name), mode, expr, binding);
+ edit = FcEditCreate (parse, (char *) FcStrCopy (name), mode, expr, binding);
if (!edit)
{
FcConfigMessage (parse, FcSevereError, "out of memory");