]> git.wh0rd.org - fontconfig.git/blobdiff - src/fcxml.c
Merge with HEAD and finish the GCC 4 cleanups (no more warnings!)
[fontconfig.git] / src / fcxml.c
index 91d8d3fb91f9db1a6ee20b6e18e3762b6494fb44..7a48628f96b97a7d9ce7079ea8bf3f23fe07dde7 100644 (file)
@@ -1,7 +1,7 @@
 /*
- * $XFree86: xc/lib/fontconfig/src/fcxml.c,v 1.12 2002/06/19 20:08:22 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_EXPAT
-#define HAVE_EXPAT 1
-#endif
-
-#ifndef HAVE_XML2
-#define HAVE_XML2 0
-#endif
-
-#if HAVE_EXPAT
 #ifndef HAVE_XMLPARSE_H
 #define HAVE_XMLPARSE_H 0
 #endif
+
 #if HAVE_XMLPARSE_H
 #include <xmlparse.h>
 #else
 #include <expat.h>
 #endif
-#endif
 
-#if HAVE_XML2
-#include "fclibxml2.h"
+#ifdef _WIN32
+#define STRICT
+#include <windows.h>
+#undef STRICT
 #endif
 
-FcTest *
-FcTestCreate (FcQual qual, const FcChar8 *field, FcOp compare, FcExpr *expr)
-{
-    FcTest     *test = (FcTest *) malloc (sizeof (FcTest));
-
-    if (test)
-    {
-       test->next = 0;
-       test->qual = qual;
-       test->field = (char *) FcStrCopy (field);
-       test->op = compare;
-       test->expr = expr;
-    }
-    return test;
-}
 
 void
 FcTestDestroy (FcTest *test)
@@ -71,6 +50,7 @@ FcTestDestroy (FcTest *test)
        FcTestDestroy (test->next);
     FcExprDestroy (test->expr);
     FcStrFree ((FcChar8 *) test->field);
+    FcMemFree (FC_MEM_TEST, sizeof (FcTest));
     free (test);
 }
 
@@ -81,6 +61,7 @@ FcExprCreateInteger (int i)
 
     if (e)
     {
+       FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
        e->op = FcOpInteger;
        e->u.ival = i;
     }
@@ -94,6 +75,7 @@ FcExprCreateDouble (double d)
 
     if (e)
     {
+       FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
        e->op = FcOpDouble;
        e->u.dval = d;
     }
@@ -107,6 +89,7 @@ FcExprCreateString (const FcChar8 *s)
 
     if (e)
     {
+       FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
        e->op = FcOpString;
        e->u.sval = FcStrCopy (s);
     }
@@ -120,6 +103,7 @@ FcExprCreateMatrix (const FcMatrix *m)
 
     if (e)
     {
+       FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
        e->op = FcOpMatrix;
        e->u.mval = FcMatrixCopy (m);
     }
@@ -133,6 +117,7 @@ FcExprCreateBool (FcBool b)
 
     if (e)
     {
+       FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
        e->op = FcOpBool;
        e->u.bval = b;
     }
@@ -146,6 +131,7 @@ FcExprCreateNil (void)
 
     if (e)
     {
+       FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
        e->op = FcOpNil;
     }
     return e;
@@ -158,6 +144,7 @@ FcExprCreateField (const char *field)
 
     if (e)
     {
+       FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
        e->op = FcOpField;
        e->u.field = (char *) FcStrCopy ((FcChar8 *) field);
     }
@@ -171,6 +158,7 @@ FcExprCreateConst (const FcChar8 *constant)
 
     if (e)
     {
+       FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
        e->op = FcOpConst;
        e->u.constant = FcStrCopy (constant);
     }
@@ -184,6 +172,7 @@ FcExprCreateOp (FcExpr *left, FcOp op, FcExpr *right)
 
     if (e)
     {
+       FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
        e->op = op;
        e->u.tree.left = left;
        e->u.tree.right = right;
@@ -194,6 +183,8 @@ FcExprCreateOp (FcExpr *left, FcOp op, FcExpr *right)
 void
 FcExprDestroy (FcExpr *e)
 {
+    if (!e)
+       return;
     switch (e->op) {
     case FcOpInteger:
        break;
@@ -226,12 +217,14 @@ FcExprDestroy (FcExpr *e)
     case FcOpOr:
     case FcOpAnd:
     case FcOpEqual:
-    case FcOpContains:
     case FcOpNotEqual:
     case FcOpLess:
     case FcOpLessEqual:
     case FcOpMore:
     case FcOpMoreEqual:
+    case FcOpContains:
+    case FcOpListing:
+    case FcOpNotContains:
     case FcOpPlus:
     case FcOpMinus:
     case FcOpTimes:
@@ -241,30 +234,20 @@ FcExprDestroy (FcExpr *e)
        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)
-{
-    FcEdit *e = (FcEdit *) malloc (sizeof (FcEdit));
-
-    if (e)
-    {
-       e->next = 0;
-       e->field = field;   /* already saved in grammar */
-       e->op = op;
-       e->expr = expr;
-    }
-    return e;
-}
-
 void
 FcEditDestroy (FcEdit *e)
 {
@@ -273,6 +256,7 @@ FcEditDestroy (FcEdit *e)
     FcStrFree ((FcChar8 *) e->field);
     if (e->expr)
        FcExprDestroy (e->expr);
+    free (e);
 }
 
 char *
@@ -299,6 +283,13 @@ typedef enum _FcElement {
     FcElementDefault,
     FcElementFamily,
 
+    FcElementSelectfont,
+    FcElementAcceptfont,
+    FcElementRejectfont,
+    FcElementGlob,
+    FcElementPattern,
+    FcElementPatelt,
+
     FcElementTest,
     FcElementEdit,
     FcElementInt,
@@ -317,12 +308,18 @@ typedef enum _FcElement {
     FcElementLessEq,
     FcElementMore,
     FcElementMoreEq,
+    FcElementContains,
+    FcElementNotContains,
     FcElementPlus,
     FcElementMinus,
     FcElementTimes,
     FcElementDivide,
     FcElementNot,
     FcElementIf,
+    FcElementFloor,
+    FcElementCeil,
+    FcElementRound,
+    FcElementTrunc,
     FcElementUnknown
 } FcElement;
 
@@ -349,6 +346,13 @@ FcElementMap (const XML_Char *name)
        { "default",    FcElementDefault },
        { "family",     FcElementFamily },
 
+       { "selectfont", FcElementSelectfont },
+       { "acceptfont", FcElementAcceptfont },
+       { "rejectfont", FcElementRejectfont },
+       { "glob",       FcElementGlob },
+       { "pattern",    FcElementPattern },
+       { "patelt",     FcElementPatelt },
+
        { "test",       FcElementTest },
        { "edit",       FcElementEdit },
        { "int",        FcElementInt },
@@ -367,12 +371,18 @@ FcElementMap (const XML_Char *name)
        { "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 }
     };
@@ -398,6 +408,8 @@ typedef enum _FcVStackTag {
     FcVStackFamily,
     FcVStackField,
     FcVStackConstant,
+    FcVStackGlob,
+    FcVStackPattern,
     
     FcVStackPrefer,
     FcVStackAccept,
@@ -430,6 +442,8 @@ typedef struct _FcVStack {
        FcOp            op;
        FcExpr          *expr;
        FcEdit          *edit;
+
+       FcPattern       *pattern;
     } u;
 } FcVStack;
 
@@ -477,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)
 {
@@ -493,6 +688,7 @@ FcVStackCreate (void)
     new = malloc (sizeof (FcVStack));
     if (!new)
        return 0;
+    FcMemAlloc (FC_MEM_VSTACK, sizeof (FcVStack));
     new->tag = FcVStackNone;
     new->prev = 0;
     return new;
@@ -513,8 +709,12 @@ FcVStackDestroy (FcVStack *vstack)
        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;
@@ -536,6 +736,7 @@ FcVStackDestroy (FcVStack *vstack)
            FcEditDestroy (vstack->u.edit);
            break;
        }
+       FcMemFree (FC_MEM_VSTACK, sizeof (FcVStack));
        free (vstack);
     }
 }
@@ -642,6 +843,18 @@ FcVStackPushEdit (FcConfigParse *parse, FcEdit *edit)
     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)
 {
@@ -706,6 +919,7 @@ FcConfigSaveAttr (const XML_Char **attr)
     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++)
     {
@@ -724,6 +938,7 @@ FcPStackPush (FcConfigParse *parse, FcElement element, const XML_Char **attr)
 
     if (!new)
        return FcFalse;
+    FcMemAlloc (FC_MEM_PSTACK, sizeof (FcPStack));
     new->prev = parse->pstack;
     new->element = element;
     if (attr)
@@ -754,7 +969,11 @@ FcPStackPop (FcConfigParse *parse)
     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;
 }
@@ -879,6 +1098,64 @@ FcParseInt (FcConfigParse *parse)
     FcStrFree (s);
 }
 
+/*
+ * 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)
 {
@@ -894,7 +1171,7 @@ FcParseDouble (FcConfigParse *parse)
        return;
     }
     end = 0;
-    d = strtod ((char *) s, (char **)&end);
+    d = FcStrtod ((char *) s, (char **)&end);
     if (end != s + strlen ((char *) s))
        FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid double", s);
     else
@@ -948,6 +1225,7 @@ FcParseMatrix (FcConfigParse *parse)
        case m_yy: m.yy = v; break;
        default: break;
        }
+       FcVStackDestroy (vstack);
        matrix_state--;
     }
     if (matrix_state != m_done)
@@ -957,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
@@ -981,7 +1258,7 @@ FcParseBool (FcConfigParse *parse)
        FcConfigMessage (parse, FcSevereError, "out of memory");
        return;
     }
-    FcVStackPushBool (parse, FcConfigLexBool (s));
+    FcVStackPushBool (parse, FcConfigLexBool (parse, s));
     FcStrFree (s);
 }
 
@@ -1113,9 +1390,11 @@ FcParseAlias (FcConfigParse *parse)
     }
     if (prefer)
     {
-       edit = FcEditCreate (FcConfigSaveField ("family"),
+       edit = FcEditCreate (parse, 
+                            FcConfigSaveField ("family"),
                             FcOpPrepend,
-                            prefer);
+                            prefer,
+                            FcValueBindingWeak);
        if (edit)
            edit->next = 0;
        else
@@ -1124,9 +1403,11 @@ FcParseAlias (FcConfigParse *parse)
     if (accept)
     {
        next = edit;
-       edit = FcEditCreate (FcConfigSaveField ("family"),
+       edit = FcEditCreate (parse,
+                            FcConfigSaveField ("family"),
                             FcOpAppend,
-                            accept);
+                            accept,
+                            FcValueBindingWeak);
        if (edit)
            edit->next = next;
        else
@@ -1135,9 +1416,11 @@ FcParseAlias (FcConfigParse *parse)
     if (def)
     {
        next = edit;
-       edit = FcEditCreate (FcConfigSaveField ("family"),
-                             FcOpAppendLast,
-                             def);
+       edit = FcEditCreate (parse,
+                            FcConfigSaveField ("family"),
+                            FcOpAppendLast,
+                            def,
+                            FcValueBindingWeak);
        if (edit)
            edit->next = next;
        else
@@ -1145,7 +1428,8 @@ FcParseAlias (FcConfigParse *parse)
     }
     if (edit)
     {
-       test = FcTestCreate (FcQualAny,
+       test = FcTestCreate (parse, FcMatchPattern,
+                            FcQualAny,
                             (FcChar8 *) FC_FAMILY,
                             FcOpEqual,
                             family);
@@ -1177,6 +1461,9 @@ FcPopExpr (FcConfigParse *parse)
     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:
@@ -1203,13 +1490,24 @@ FcPopExpr (FcConfigParse *parse)
        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;
 
@@ -1234,9 +1532,39 @@ FcPopExprs (FcConfigParse *parse, FcOp op)
 }
 
 static void
-FcParseExpr (FcConfigParse *parse, FcOp op)
+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 = FcPopExprs (parse, op);
+    FcExpr  *expr = FcPopUnary (parse, op);
     if (expr)
        FcVStackPushExpr (parse, FcVStackExpr, expr);
 }
@@ -1255,11 +1583,11 @@ 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;
-    free (s);
+    FcStrFree (s);
 }
 
 typedef struct _FcOpMap {
@@ -1284,7 +1612,9 @@ static const FcOpMap fcCompareOps[] = {
     { "less",          FcOpLess            },
     { "less_eq",       FcOpLessEqual       },
     { "more",          FcOpMore            },
-    { "more_eq",       FcOpMoreEqual       }
+    { "more_eq",       FcOpMoreEqual       },
+    { "contains",      FcOpContains        },
+    { "not_contains",  FcOpNotContains     }
 };
 
 #define NUM_COMPARE_OPS (sizeof fcCompareOps / sizeof fcCompareOps[0])
@@ -1299,6 +1629,8 @@ FcConfigLexCompare (const FcChar8 *compare)
 static void
 FcParseTest (FcConfigParse *parse)
 {
+    const FcChar8   *kind_string;
+    FcMatchKind            kind;
     const FcChar8   *qual_string;
     FcQual         qual;
     const FcChar8   *name;
@@ -1307,6 +1639,23 @@ FcParseTest (FcConfigParse *parse)
     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;
@@ -1323,14 +1672,14 @@ FcParseTest (FcConfigParse *parse)
        else
        {
            FcConfigMessage (parse, FcSevereWarning, "invalid test qual \"%s\"", qual_string);
-           qual = FcQualAny;
+           return;
        }
     }
     name = FcConfigGetAttribute (parse, "name");
     if (!name)
     {
        FcConfigMessage (parse, FcSevereWarning, "missing test name");
-       name = (FcChar8 *) FC_FAMILY;
+       return;
     }
     compare_string = FcConfigGetAttribute (parse, "compare");
     if (!compare_string)
@@ -1341,16 +1690,16 @@ FcParseTest (FcConfigParse *parse)
        if (compare == FcOpInvalid)
        {
            FcConfigMessage (parse, FcSevereWarning, "invalid test compare \"%s\"", compare_string);
-           compare = FcOpEqual;
+           return;
        }
     }
-    expr = FcPopExprs (parse, FcOpComma);
+    expr = FcPopBinary (parse, FcOpComma);
     if (!expr)
     {
        FcConfigMessage (parse, FcSevereWarning, "missing test expression");
        return;
     }
-    test = FcTestCreate (qual, name, compare, expr);
+    test = FcTestCreate (parse, kind, qual, name, compare, expr);
     if (!test)
     {
        FcConfigMessage (parse, FcSevereError, "out of memory");
@@ -1381,7 +1730,9 @@ FcParseEdit (FcConfigParse *parse)
 {
     const FcChar8   *name;
     const FcChar8   *mode_string;
+    const FcChar8   *binding_string;
     FcOp           mode;
+    FcValueBinding  binding;
     FcExpr         *expr;
     FcEdit         *edit;
 
@@ -1389,7 +1740,7 @@ FcParseEdit (FcConfigParse *parse)
     if (!name)
     {
        FcConfigMessage (parse, FcSevereWarning, "missing edit name");
-       name = (FcChar8 *) FC_FAMILY;
+       return;
     }
     mode_string = FcConfigGetAttribute (parse, "mode");
     if (!mode_string)
@@ -1400,11 +1751,28 @@ FcParseEdit (FcConfigParse *parse)
        if (mode == FcOpInvalid)
        {
            FcConfigMessage (parse, FcSevereWarning, "invalid edit mode \"%s\"", mode_string);
-           mode = FcOpAssign;
+           return;
+       }
+    }
+    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;
+       else
+       {
+           FcConfigMessage (parse, FcSevereWarning, "invalid edit binding \"%s\"", binding_string);
+           return;
        }
     }
-    expr = FcPopExprs (parse, FcOpComma);
-    edit = FcEditCreate ((char *) FcStrCopy (name), mode, expr);
+    expr = FcPopBinary (parse, FcOpComma);
+    edit = FcEditCreate (parse, (char *) FcStrCopy (name), mode, expr, binding);
     if (!edit)
     {
        FcConfigMessage (parse, FcSevereError, "out of memory");
@@ -1436,7 +1804,7 @@ FcParseMatch (FcConfigParse *parse)
        else
        {
            FcConfigMessage (parse, FcSevereWarning, "invalid match target \"%s\"", kind_name);
-           kind = FcMatchPattern;
+           return;
        }
     }
     while ((vstack = FcVStackPop (parse)))
@@ -1462,6 +1830,156 @@ FcParseMatch (FcConfigParse *parse)
        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)
 {
@@ -1482,9 +2000,36 @@ 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);
@@ -1493,9 +2038,12 @@ FcEndElement(void *userData, const XML_Char *name)
            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);
@@ -1554,7 +2102,21 @@ FcEndElement(void *userData, const XML_Char *name)
     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;
@@ -1562,46 +2124,64 @@ FcEndElement(void *userData, const XML_Char *name)
        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:
+       FcParseBinary (parse, FcOpContains);
+       break;
+    case FcElementNotContains:
+       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;
@@ -1638,6 +2218,89 @@ FcEndDoctypeDecl (void *userData)
 {
 }
 
+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,
@@ -1655,8 +2318,25 @@ FcConfigParseAndLoad (FcConfig       *config,
     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");
-    free (filename);
+    FcStrFree (filename);
     if (!f)
        goto bail0;
     
@@ -1667,9 +2347,6 @@ FcConfigParseAndLoad (FcConfig        *config,
     if (!FcConfigInit (&parse, name, config, p))
        goto bail2;
 
-    if (!FcConfigAddConfigFile (config, filename))
-       goto bail3;
-
     XML_SetUserData (p, &parse);
     
     XML_SetDoctypeDeclHandler (p, FcStartDoctypeDecl, FcEndDoctypeDecl);
@@ -1703,6 +2380,7 @@ bail2:
     XML_ParserFree (p);
 bail1:
     fclose (f);
+    f = NULL;
 bail0:
     if (error && complain)
     {