]> git.wh0rd.org - fontconfig.git/blobdiff - src/fcxml.c
Bug 44826 - <alias> must contain only a single <family>
[fontconfig.git] / src / fcxml.c
index e265fa53ff620b92e966d5af63261138d957a2f2..ff30b7bbdaff398971803913619b757ae24a83df 100644 (file)
@@ -1,73 +1,67 @@
 /*
- * $XFree86: xc/lib/fontconfig/src/fcxml.c,v 1.17 2002/07/31 01:36:37 keithp Exp $
+ * fontconfig/src/fcxml.c
  *
- * 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
  * 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
+ * documentation, and that the name of the author(s) not be used in
  * advertising or publicity pertaining to distribution of the software without
- * specific, written prior permission.  Keith Packard makes no
+ * specific, written prior permission.  The authors make 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,
+ * THE AUTHOR(S) 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
+ * EVENT SHALL THE AUTHOR(S) 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 <fcntl.h>
+#include <stdarg.h>
+#include <dirent.h>
 
-#ifndef HAVE_EXPAT
-#define HAVE_EXPAT 1
-#endif
+#ifdef ENABLE_LIBXML2
 
-#ifndef HAVE_XML2
-#define HAVE_XML2 0
-#endif
+#include <libxml/parser.h>
+
+#define XML_Char                       xmlChar
+#define XML_Parser                     xmlParserCtxtPtr
+#define XML_ParserFree                 xmlFreeParserCtxt
+#define XML_GetCurrentLineNumber       xmlSAX2GetLineNumber
+#define XML_GetErrorCode               xmlCtxtGetLastError
+#define XML_ErrorString(Error)         (Error)->message
+
+#else /* ENABLE_LIBXML2 */
 
-#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"
-#endif
+#endif /* ENABLE_LIBXML2 */
 
-FcTest *
-FcTestCreate (FcMatchKind   kind, 
-             FcQual        qual,
-             const FcChar8 *field,
-             FcOp          compare,
-             FcExpr        *expr)
-{
-    FcTest     *test = (FcTest *) malloc (sizeof (FcTest));
+#ifdef _WIN32
+#define _WIN32_WINNT 0x0500
+#define STRICT
+#include <windows.h>
+#undef STRICT
+#include <mbstring.h>
+#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;
-}
+static void
+FcExprDestroy (FcExpr *e);
 
 void
 FcTestDestroy (FcTest *test)
@@ -75,15 +69,14 @@ FcTestDestroy (FcTest *test)
     if (test->next)
        FcTestDestroy (test->next);
     FcExprDestroy (test->expr);
-    FcStrFree ((FcChar8 *) test->field);
+    FcMemFree (FC_MEM_TEST, sizeof (FcTest));
     free (test);
 }
 
-FcExpr *
-FcExprCreateInteger (int i)
+static FcExpr *
+FcExprCreateInteger (FcConfig *config, int i)
 {
-    FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
-
+    FcExpr *e = FcConfigAllocExpr (config);
     if (e)
     {
        e->op = FcOpInteger;
@@ -92,11 +85,10 @@ FcExprCreateInteger (int i)
     return e;
 }
 
-FcExpr *
-FcExprCreateDouble (double d)
+static FcExpr *
+FcExprCreateDouble (FcConfig *config, double d)
 {
-    FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
-
+    FcExpr *e = FcConfigAllocExpr (config);
     if (e)
     {
        e->op = FcOpDouble;
@@ -105,24 +97,22 @@ FcExprCreateDouble (double d)
     return e;
 }
 
-FcExpr *
-FcExprCreateString (const FcChar8 *s)
+static FcExpr *
+FcExprCreateString (FcConfig *config, const FcChar8 *s)
 {
-    FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
-
+    FcExpr *e = FcConfigAllocExpr (config);
     if (e)
     {
        e->op = FcOpString;
-       e->u.sval = FcStrCopy (s);
+       e->u.sval = FcStrStaticName (s);
     }
     return e;
 }
 
-FcExpr *
-FcExprCreateMatrix (const FcMatrix *m)
+static FcExpr *
+FcExprCreateMatrix (FcConfig *config, const FcMatrix *m)
 {
-    FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
-
+    FcExpr *e = FcConfigAllocExpr (config);
     if (e)
     {
        e->op = FcOpMatrix;
@@ -131,11 +121,10 @@ FcExprCreateMatrix (const FcMatrix *m)
     return e;
 }
 
-FcExpr *
-FcExprCreateBool (FcBool b)
+static FcExpr *
+FcExprCreateBool (FcConfig *config, FcBool b)
 {
-    FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
-
+    FcExpr *e = FcConfigAllocExpr (config);
     if (e)
     {
        e->op = FcOpBool;
@@ -144,49 +133,58 @@ FcExprCreateBool (FcBool b)
     return e;
 }
 
-FcExpr *
-FcExprCreateNil (void)
+static FcExpr *
+FcExprCreateCharSet (FcConfig *config, FcCharSet *charset)
 {
-    FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
-
+    FcExpr *e = FcConfigAllocExpr (config);
     if (e)
     {
-       e->op = FcOpNil;
+       e->op = FcOpCharSet;
+       e->u.cval = FcCharSetCopy (charset);
     }
     return e;
 }
 
-FcExpr *
-FcExprCreateField (const char *field)
+static FcExpr *
+FcExprCreateLangSet (FcConfig *config, FcLangSet *langset)
 {
-    FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
+    FcExpr *e = FcConfigAllocExpr (config);
+    if (e)
+    {
+       e->op = FcOpLangSet;
+       e->u.lval = FcLangSetCopy (langset);
+    }
+    return e;
+}
 
+static FcExpr *
+FcExprCreateField (FcConfig *config, const char *field)
+{
+    FcExpr *e = FcConfigAllocExpr (config);
     if (e)
     {
        e->op = FcOpField;
-       e->u.field = (char *) FcStrCopy ((FcChar8 *) field);
+       e->u.object = FcObjectFromName (field);
     }
     return e;
 }
 
-FcExpr *
-FcExprCreateConst (const FcChar8 *constant)
+static FcExpr *
+FcExprCreateConst (FcConfig *config, const FcChar8 *constant)
 {
-    FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
-
+    FcExpr *e = FcConfigAllocExpr (config);
     if (e)
     {
        e->op = FcOpConst;
-       e->u.constant = FcStrCopy (constant);
+       e->u.constant = FcStrStaticName (constant);
     }
     return e;
 }
 
-FcExpr *
-FcExprCreateOp (FcExpr *left, FcOp op, FcExpr *right)
+static FcExpr *
+FcExprCreateOp (FcConfig *config, FcExpr *left, FcOp op, FcExpr *right)
 {
-    FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
-
+    FcExpr *e = FcConfigAllocExpr (config);
     if (e)
     {
        e->op = op;
@@ -196,30 +194,34 @@ FcExprCreateOp (FcExpr *left, FcOp op, FcExpr *right)
     return e;
 }
 
-void
+static void
 FcExprDestroy (FcExpr *e)
 {
+    if (!e)
+       return;
     switch (e->op) {
     case FcOpInteger:
        break;
     case FcOpDouble:
        break;
     case FcOpString:
-       FcStrFree (e->u.sval);
        break;
     case FcOpMatrix:
        FcMatrixFree (e->u.mval);
        break;
+    case FcOpRange:
+       break;
     case FcOpCharSet:
        FcCharSetDestroy (e->u.cval);
        break;
+    case FcOpLangSet:
+       FcLangSetDestroy (e->u.lval);
+       break;
     case FcOpBool:
        break;
     case FcOpField:
-       FcStrFree ((FcChar8 *) e->u.field);
        break;
     case FcOpConst:
-       FcStrFree (e->u.constant);
        break;
     case FcOpAssign:
     case FcOpAssignReplace:
@@ -231,12 +233,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:
@@ -246,29 +250,18 @@ 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;
     }
-    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;
+    e->op = FcOpNil;
 }
 
 void
@@ -276,21 +269,16 @@ FcEditDestroy (FcEdit *e)
 {
     if (e->next)
        FcEditDestroy (e->next);
-    FcStrFree ((FcChar8 *) e->field);
     if (e->expr)
        FcExprDestroy (e->expr);
-}
-
-char *
-FcConfigSaveField (const char *field)
-{
-    return (char *) FcStrCopy ((FcChar8 *) field);
+    free (e);
 }
 
 typedef enum _FcElement {
     FcElementNone,
     FcElementFontconfig,
     FcElementDir,
+    FcElementCacheDir,
     FcElementCache,
     FcElementInclude,
     FcElementConfig,
@@ -305,14 +293,23 @@ typedef enum _FcElement {
     FcElementDefault,
     FcElementFamily,
 
+    FcElementSelectfont,
+    FcElementAcceptfont,
+    FcElementRejectfont,
+    FcElementGlob,
+    FcElementPattern,
+    FcElementPatelt,
+
     FcElementTest,
     FcElementEdit,
     FcElementInt,
     FcElementDouble,
     FcElementString,
     FcElementMatrix,
+    FcElementRange,
     FcElementBool,
-    FcElementCharset,
+    FcElementCharSet,
+    FcElementLangSet,
     FcElementName,
     FcElementConst,
     FcElementOr,
@@ -323,68 +320,90 @@ typedef enum _FcElement {
     FcElementLessEq,
     FcElementMore,
     FcElementMoreEq,
+    FcElementContains,
+    FcElementNotContains,
     FcElementPlus,
     FcElementMinus,
     FcElementTimes,
     FcElementDivide,
     FcElementNot,
     FcElementIf,
+    FcElementFloor,
+    FcElementCeil,
+    FcElementRound,
+    FcElementTrunc,
     FcElementUnknown
 } FcElement;
 
+static const struct {
+    const char  name[16];
+    FcElement   element;
+} fcElementMap[] = {
+    { "fontconfig",    FcElementFontconfig },
+    { "dir",           FcElementDir },
+    { "cachedir",      FcElementCacheDir },
+    { "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 },
+    { "range",         FcElementRange },
+    { "bool",          FcElementBool },
+    { "charset",       FcElementCharSet },
+    { "langset",       FcElementLangSet },
+    { "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 },
-       { "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;
@@ -395,8 +414,9 @@ typedef struct _FcPStack {
     FcElement          element;
     FcChar8            **attr;
     FcStrBuf           str;
+    FcChar8            *attr_buf_static[16];
 } FcPStack;
-    
+
 typedef enum _FcVStackTag {
     FcVStackNone,
 
@@ -404,16 +424,21 @@ typedef enum _FcVStackTag {
     FcVStackFamily,
     FcVStackField,
     FcVStackConstant,
-    
+    FcVStackGlob,
+    FcVStackPattern,
+
     FcVStackPrefer,
     FcVStackAccept,
     FcVStackDefault,
-    
+
     FcVStackInteger,
     FcVStackDouble,
     FcVStackMatrix,
+    FcVStackRange,
     FcVStackBool,
-    
+    FcVStackCharSet,
+    FcVStackLangSet,
+
     FcVStackTest,
     FcVStackExpr,
     FcVStackEdit
@@ -429,13 +454,18 @@ typedef struct _FcVStack {
        int             integer;
        double          _double;
        FcMatrix        *matrix;
-       FcBool          bool;
+       FcRange         range;
+       FcBool          bool_;
+       FcCharSet       *charset;
+       FcLangSet       *langset;
 
        FcTest          *test;
        FcQual          qual;
        FcOp            op;
        FcExpr          *expr;
        FcEdit          *edit;
+
+       FcPattern       *pattern;
     } u;
 } FcVStack;
 
@@ -446,6 +476,10 @@ typedef struct _FcConfigParse {
     const FcChar8   *name;
     FcConfig       *config;
     XML_Parser     parser;
+    int             pstack_static_used;
+    FcPStack        pstack_static[8];
+    int             vstack_static_used;
+    FcVStack        vstack_static[64];
 } FcConfigParse;
 
 typedef enum _FcConfigSeverity {
@@ -453,9 +487,9 @@ typedef enum _FcConfigSeverity {
 } 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);
@@ -469,10 +503,10 @@ FcConfigMessage (FcConfigParse *parse, FcConfigSeverity severe, char *fmt, ...)
     {
        if (parse->name)
            fprintf (stderr, "Fontconfig %s: \"%s\", line %d: ", s,
-                    parse->name, XML_GetCurrentLineNumber (parse->parser));
+                    parse->name, (int)XML_GetCurrentLineNumber (parse->parser));
        else
            fprintf (stderr, "Fontconfig %s: line %d: ", s,
-                    XML_GetCurrentLineNumber (parse->parser));
+                    (int)XML_GetCurrentLineNumber (parse->parser));
        if (severe >= FcSevereError)
            parse->error = FcTrue;
     }
@@ -483,168 +517,364 @@ FcConfigMessage (FcConfigParse *parse, FcConfigSeverity severe, char *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
-FcVStackPush (FcConfigParse *parse, FcVStack *vstack)
+FcTypecheckValue (FcConfigParse *parse, FcType value, FcType type)
 {
-    vstack->prev = parse->vstack;
-    vstack->pstack = parse->pstack ? parse->pstack->prev : 0;
-    parse->vstack = vstack;
+    if (value == FcTypeInteger)
+       value = FcTypeDouble;
+    if (type == FcTypeInteger)
+       type = FcTypeDouble;
+    if (value != type)
+    {
+       if ((value == FcTypeLangSet && type == FcTypeString) ||
+           (value == FcTypeString && type == FcTypeLangSet))
+           return;
+       if (type == (FcType) -1)
+           return;
+       FcConfigMessage (parse, FcSevereWarning, "saw %s, expected %s",
+                        FcTypeName (value), FcTypeName (type));
+    }
 }
 
-static FcVStack *
-FcVStackCreate (void)
+static void
+FcTypecheckExpr (FcConfigParse *parse, FcExpr *expr, FcType type)
 {
-    FcVStack    *new;
+    const FcObjectType *o;
+    const FcConstant   *c;
 
-    new = malloc (sizeof (FcVStack));
-    if (!new)
-       return 0;
-    new->tag = FcVStackNone;
-    new->prev = 0;
-    return new;
+    /* If parsing the expression failed, some nodes may be NULL */
+    if (!expr)
+       return;
+
+    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 FcOpLangSet:
+       FcTypecheckValue (parse, FcTypeLangSet, type);
+       break;
+    case FcOpNil:
+       break;
+    case FcOpField:
+       o = FcNameGetObjectType (FcObjectName (expr->u.object));
+       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);
+       }
+        else
+            FcConfigMessage (parse, FcSevereWarning,
+                             "invalid constant used : %s",
+                             expr->u.constant);
+       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 void
-FcVStackDestroy (FcVStack *vstack)
+static FcTest *
+FcTestCreate (FcConfigParse *parse,
+             FcMatchKind   kind,
+             FcQual        qual,
+             const FcChar8 *field,
+             FcOp          compare,
+             FcExpr        *expr)
 {
-    FcVStack    *prev;
+    FcTest     *test = (FcTest *) malloc (sizeof (FcTest));
 
-    for (; vstack; vstack = prev)
+    if (test)
     {
-       prev = vstack->prev;
-       switch (vstack->tag) {
-       case FcVStackNone:
-           break;
-       case FcVStackString:
-       case FcVStackFamily:
-       case FcVStackField:
-       case FcVStackConstant:
-           FcStrFree (vstack->u.string);
-           break;
-       case FcVStackInteger:
-       case FcVStackDouble:
-           break;
-       case FcVStackMatrix:
-           FcMatrixFree (vstack->u.matrix);
-           break;
-       case FcVStackBool:
-           break;
-       case FcVStackTest:
-           FcTestDestroy (vstack->u.test);
-           break;
-       case FcVStackExpr:
-       case FcVStackPrefer:
-       case FcVStackAccept:
-       case FcVStackDefault:
-           FcExprDestroy (vstack->u.expr);
-           break;
-       case FcVStackEdit:
-           FcEditDestroy (vstack->u.edit);
-           break;
-       }
-       free (vstack);
+       const FcObjectType      *o;
+       
+       FcMemAlloc (FC_MEM_TEST, sizeof (FcTest));
+       test->next = 0;
+       test->kind = kind;
+       test->qual = qual;
+       test->object = FcObjectFromName ((const char *) field);
+       test->op = compare;
+       test->expr = expr;
+       o = FcNameGetObjectType (FcObjectName (test->object));
+       if (o)
+           FcTypecheckExpr (parse, expr, o->type);
+    }
+    return test;
+}
+
+static FcEdit *
+FcEditCreate (FcConfigParse    *parse,
+             FcObject          object,
+             FcOp              op,
+             FcExpr            *expr,
+             FcValueBinding    binding)
+{
+    FcEdit *e = (FcEdit *) malloc (sizeof (FcEdit));
+
+    if (e)
+    {
+       const FcObjectType      *o;
+
+       e->next = 0;
+       e->object = object;
+       e->op = op;
+       e->expr = expr;
+       e->binding = binding;
+       o = FcNameGetObjectType (FcObjectName (e->object));
+       if (o)
+           FcTypecheckExpr (parse, expr, o->type);
     }
+    return e;
+}
+
+static FcVStack *
+FcVStackCreateAndPush (FcConfigParse *parse)
+{
+    FcVStack    *new;
+
+    if (parse->vstack_static_used < sizeof (parse->vstack_static) / sizeof (parse->vstack_static[0]))
+       new = &parse->vstack_static[parse->vstack_static_used++];
+    else
+    {
+       new = malloc (sizeof (FcVStack));
+       if (!new)
+           return 0;
+       FcMemAlloc (FC_MEM_VSTACK, sizeof (FcVStack));
+    }
+    new->tag = FcVStackNone;
+    new->prev = 0;
+
+    new->prev = parse->vstack;
+    new->pstack = parse->pstack ? parse->pstack->prev : 0;
+    parse->vstack = new;
+
+    return new;
 }
 
 static FcBool
 FcVStackPushString (FcConfigParse *parse, FcVStackTag tag, FcChar8 *string)
 {
-    FcVStack    *vstack = FcVStackCreate ();
+    FcVStack    *vstack = FcVStackCreateAndPush (parse);
     if (!vstack)
        return FcFalse;
     vstack->u.string = string;
     vstack->tag = tag;
-    FcVStackPush (parse, vstack);
     return FcTrue;
 }
 
 static FcBool
 FcVStackPushInteger (FcConfigParse *parse, int integer)
 {
-    FcVStack    *vstack = FcVStackCreate ();
+    FcVStack    *vstack = FcVStackCreateAndPush (parse);
     if (!vstack)
        return FcFalse;
     vstack->u.integer = integer;
     vstack->tag = FcVStackInteger;
-    FcVStackPush (parse, vstack);
     return FcTrue;
 }
 
 static FcBool
 FcVStackPushDouble (FcConfigParse *parse, double _double)
 {
-    FcVStack    *vstack = FcVStackCreate ();
+    FcVStack    *vstack = FcVStackCreateAndPush (parse);
     if (!vstack)
        return FcFalse;
     vstack->u._double = _double;
     vstack->tag = FcVStackDouble;
-    FcVStackPush (parse, vstack);
     return FcTrue;
 }
 
 static FcBool
 FcVStackPushMatrix (FcConfigParse *parse, FcMatrix *matrix)
 {
-    FcVStack    *vstack = FcVStackCreate ();
-    if (!vstack)
-       return FcFalse;
+    FcVStack    *vstack;
     matrix = FcMatrixCopy (matrix);
     if (!matrix)
-    {
-       FcVStackDestroy (vstack);
        return FcFalse;
-    }
+    vstack = FcVStackCreateAndPush (parse);
+    if (!vstack)
+       return FcFalse;
     vstack->u.matrix = matrix;
     vstack->tag = FcVStackMatrix;
-    FcVStackPush (parse, vstack);
     return FcTrue;
 }
 
 static FcBool
-FcVStackPushBool (FcConfigParse *parse, FcBool bool)
+FcVStackPushRange (FcConfigParse *parse, FcRange *range)
 {
-    FcVStack    *vstack = FcVStackCreate ();
+    FcVStack   *vstack = FcVStackCreateAndPush (parse);
     if (!vstack)
        return FcFalse;
-    vstack->u.bool = bool;
+    vstack->u.range.begin = range->begin;
+    vstack->u.range.end = range->end;
+    vstack->tag = FcVStackRange;
+    return FcTrue;
+}
+
+static FcBool
+FcVStackPushBool (FcConfigParse *parse, FcBool bool_)
+{
+    FcVStack    *vstack = FcVStackCreateAndPush (parse);
+    if (!vstack)
+       return FcFalse;
+    vstack->u.bool_ = bool_;
     vstack->tag = FcVStackBool;
-    FcVStackPush (parse, vstack);
+    return FcTrue;
+}
+
+static FcBool
+FcVStackPushCharSet (FcConfigParse *parse, FcCharSet *charset)
+{
+    FcVStack   *vstack;
+    if (!charset)
+       return FcFalse;
+    vstack = FcVStackCreateAndPush (parse);
+    if (!vstack)
+       return FcFalse;
+    vstack->u.charset = charset;
+    vstack->tag = FcVStackCharSet;
+    return FcTrue;
+}
+
+static FcBool
+FcVStackPushLangSet (FcConfigParse *parse, FcLangSet *langset)
+{
+    FcVStack   *vstack;
+    if (!langset)
+       return FcFalse;
+    vstack = FcVStackCreateAndPush (parse);
+    if (!vstack)
+       return FcFalse;
+    vstack->u.langset = langset;
+    vstack->tag = FcVStackLangSet;
     return FcTrue;
 }
 
 static FcBool
 FcVStackPushTest (FcConfigParse *parse, FcTest *test)
 {
-    FcVStack    *vstack = FcVStackCreate ();
+    FcVStack    *vstack = FcVStackCreateAndPush (parse);
     if (!vstack)
        return FcFalse;
     vstack->u.test = test;
     vstack->tag = FcVStackTest;
-    FcVStackPush (parse, vstack);
     return FcTrue;
 }
 
 static FcBool
 FcVStackPushExpr (FcConfigParse *parse, FcVStackTag tag, FcExpr *expr)
 {
-    FcVStack    *vstack = FcVStackCreate ();
+    FcVStack    *vstack = FcVStackCreateAndPush (parse);
     if (!vstack)
        return FcFalse;
     vstack->u.expr = expr;
     vstack->tag = tag;
-    FcVStackPush (parse, vstack);
     return FcTrue;
 }
 
 static FcBool
 FcVStackPushEdit (FcConfigParse *parse, FcEdit *edit)
 {
-    FcVStack    *vstack = FcVStackCreate ();
+    FcVStack    *vstack = FcVStackCreateAndPush (parse);
     if (!vstack)
        return FcFalse;
     vstack->u.edit = edit;
     vstack->tag = FcVStackEdit;
-    FcVStackPush (parse, vstack);
+    return FcTrue;
+}
+
+static FcBool
+FcVStackPushPattern (FcConfigParse *parse, FcPattern *pattern)
+{
+    FcVStack    *vstack = FcVStackCreateAndPush (parse);
+    if (!vstack)
+       return FcFalse;
+    vstack->u.pattern = pattern;
+    vstack->tag = FcVStackPattern;
     return FcTrue;
 }
 
@@ -657,28 +887,81 @@ FcVStackFetch (FcConfigParse *parse, int off)
     return vstack;
 }
 
-static void
-FcVStackClear (FcConfigParse *parse)
+static FcVStack *
+FcVStackPeek (FcConfigParse *parse)
 {
-    while (parse->vstack && parse->vstack->pstack == parse->pstack)
-    {
-       FcVStack    *vstack = parse->vstack;
-       parse->vstack = vstack->prev;
-       vstack->prev = 0;
-       FcVStackDestroy (vstack);
-    }
+    FcVStack   *vstack = parse->vstack;
+
+    return vstack && vstack->pstack == parse->pstack ? vstack : 0;
 }
 
-static FcVStack *
-FcVStackPop (FcConfigParse *parse)
+static void
+FcVStackPopAndDestroy (FcConfigParse *parse)
 {
     FcVStack   *vstack = parse->vstack;
-    
+
     if (!vstack || vstack->pstack != parse->pstack)
-       return 0;
+       return;
+
     parse->vstack = vstack->prev;
-    vstack->prev = 0;
-    return vstack;
+
+    switch (vstack->tag) {
+    case FcVStackNone:
+       break;
+    case FcVStackFamily:
+       break;
+    case FcVStackString:
+    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 FcVStackRange:
+    case FcVStackBool:
+       break;
+    case FcVStackCharSet:
+       FcCharSetDestroy (vstack->u.charset);
+       break;
+    case FcVStackLangSet:
+       FcLangSetDestroy (vstack->u.langset);
+       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;
+    }
+
+    if (vstack == &parse->vstack_static[parse->vstack_static_used - 1])
+       parse->vstack_static_used--;
+    else
+    {
+       FcMemFree (FC_MEM_VSTACK, sizeof (FcVStack));
+       free (vstack);
+    }
+}
+
+static void
+FcVStackClear (FcConfigParse *parse)
+{
+    while (FcVStackPeek (parse))
+       FcVStackPopAndDestroy (parse);
 }
 
 static int
@@ -695,9 +978,8 @@ FcVStackElements (FcConfigParse *parse)
 }
 
 static FcChar8 **
-FcConfigSaveAttr (const XML_Char **attr)
+FcConfigSaveAttr (const XML_Char **attr, FcChar8 **buf, int size_bytes)
 {
-    int                n;
     int                slen;
     int                i;
     FcChar8    **new;
@@ -707,11 +989,22 @@ FcConfigSaveAttr (const XML_Char **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)
+       slen += strlen ((char *) attr[i]) + 1;
+    if (i == 0)
        return 0;
+    slen += (i + 1) * sizeof (FcChar8 *);
+    if (slen <= size_bytes)
+       new = buf;
+    else
+    {
+       new = malloc (slen);
+       if (!new)
+       {
+           FcConfigMessage (0, FcSevereError, "out of memory");
+           return 0;
+       }
+       FcMemAlloc (FC_MEM_ATTR, 1);    /* size is too expensive */
+    }
     s = (FcChar8 *) (new + (i + 1));
     for (i = 0; attr[i]; i++)
     {
@@ -726,20 +1019,21 @@ FcConfigSaveAttr (const XML_Char **attr)
 static FcBool
 FcPStackPush (FcConfigParse *parse, FcElement element, const XML_Char **attr)
 {
-    FcPStack   *new = malloc (sizeof (FcPStack));
+    FcPStack   *new;
 
-    if (!new)
-       return FcFalse;
-    new->prev = parse->pstack;
-    new->element = element;
-    if (attr)
+    if (parse->pstack_static_used < sizeof (parse->pstack_static) / sizeof (parse->pstack_static[0]))
+       new = &parse->pstack_static[parse->pstack_static_used++];
+    else
     {
-       new->attr = FcConfigSaveAttr (attr);
-       if (!new->attr)
-           FcConfigMessage (parse, FcSevereError, "out of memory");
+       new = malloc (sizeof (FcPStack));
+       if (!new)
+           return FcFalse;
+       FcMemAlloc (FC_MEM_PSTACK, sizeof (FcPStack));
     }
-    else
-       new->attr = 0;
+
+    new->prev = parse->pstack;
+    new->element = element;
+    new->attr = FcConfigSaveAttr (attr, new->attr_buf_static, sizeof (new->attr_buf_static));
     FcStrBufInit (&new->str, 0, 0);
     parse->pstack = new;
     return FcTrue;
@@ -749,8 +1043,8 @@ static FcBool
 FcPStackPop (FcConfigParse *parse)
 {
     FcPStack   *old;
-    
-    if (!parse->pstack) 
+
+    if (!parse->pstack)
     {
        FcConfigMessage (parse, FcSevereError, "mismatching element");
        return FcFalse;
@@ -759,9 +1053,19 @@ FcPStackPop (FcConfigParse *parse)
     old = parse->pstack;
     parse->pstack = old->prev;
     FcStrBufDestroy (&old->str);
-    if (old->attr)
+    if (old->attr && old->attr != old->attr_buf_static)
+    {
+       FcMemFree (FC_MEM_ATTR, 1); /* size is to expensive */
        free (old->attr);
-    free (old);
+    }
+
+    if (old == &parse->pstack_static[parse->pstack_static_used - 1])
+       parse->pstack_static_used--;
+    else
+    {
+       FcMemFree (FC_MEM_PSTACK, sizeof (FcPStack));
+       free (old);
+    }
     return FcTrue;
 }
 
@@ -769,7 +1073,9 @@ static FcBool
 FcConfigInit (FcConfigParse *parse, const FcChar8 *name, FcConfig *config, XML_Parser parser)
 {
     parse->pstack = 0;
+    parse->pstack_static_used = 0;
     parse->vstack = 0;
+    parse->vstack_static_used = 0;
     parse->error = FcFalse;
     parse->name = name;
     parse->config = config;
@@ -785,13 +1091,16 @@ FcConfigCleanup (FcConfigParse   *parse)
 }
 
 static const FcChar8 *
-FcConfigGetAttribute (FcConfigParse *parse, char *attr)
+FcConfigGetAttribute (FcConfigParse *parse, const char *attr)
 {
     FcChar8 **attrs;
     if (!parse->pstack)
        return 0;
 
     attrs = parse->pstack->attr;
+    if (!attrs)
+        return 0;
+
     while (*attrs)
     {
        if (!strcmp ((char *) *attrs, attr))
@@ -806,11 +1115,11 @@ FcStartElement(void *userData, const XML_Char *name, const XML_Char **attr)
 {
     FcConfigParse   *parse = userData;
     FcElement      element;
-    
+
     element = FcElementMap (name);
     if (element == FcElementUnknown)
        FcConfigMessage (parse, FcSevereWarning, "unknown element \"%s\"", name);
-    
+
     if (!FcPStackPush (parse, element, attr))
     {
        FcConfigMessage (parse, FcSevereError, "out of memory");
@@ -822,30 +1131,40 @@ FcStartElement(void *userData, const XML_Char *name, const XML_Char **attr)
 static void
 FcParseBlank (FcConfigParse *parse)
 {
-    int            n = FcVStackElements (parse);
+    int                n = FcVStackElements (parse);
+    FcChar32   i;
     while (n-- > 0)
     {
        FcVStack    *v = FcVStackFetch (parse, n);
-       if (v->tag != FcVStackInteger)
-           FcConfigMessage (parse, FcSevereError, "non-integer blank");
-       else
+       if (!parse->config->blanks)
        {
+           parse->config->blanks = FcBlanksCreate ();
            if (!parse->config->blanks)
-           {
-               parse->config->blanks = FcBlanksCreate ();
-               if (!parse->config->blanks)
-               {
-                   FcConfigMessage (parse, FcSevereError, "out of memory");
-                   break;
-               }
-           }
+               goto bail;
+       }
+       switch (v->tag) {
+       case FcVStackInteger:
            if (!FcBlanksAdd (parse->config->blanks, v->u.integer))
+               goto bail;
+           break;
+       case FcVStackRange:
+           if (v->u.range.begin <= v->u.range.end)
            {
-               FcConfigMessage (parse, FcSevereError, "out of memory");
-               break;
+             for (i = v->u.range.begin; i <= v->u.range.end; i++)
+             {
+                 if (!FcBlanksAdd (parse->config->blanks, i))
+                     goto bail;
+             }
            }
+           break;
+       default:
+           FcConfigMessage (parse, FcSevereError, "invalid element in blank");
+           break;
        }
     }
+    return;
+  bail:
+    FcConfigMessage (parse, FcSevereError, "out of memory");
 }
 
 static void
@@ -867,10 +1186,10 @@ FcParseInt (FcConfigParse *parse)
 {
     FcChar8 *s, *end;
     int            l;
-    
+
     if (!parse->pstack)
        return;
-    s = FcStrBufDone (&parse->pstack->str);
+    s = FcStrBufDoneStatic (&parse->pstack->str);
     if (!s)
     {
        FcConfigMessage (parse, FcSevereError, "out of memory");
@@ -882,17 +1201,17 @@ FcParseInt (FcConfigParse *parse)
        FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid integer", s);
     else
        FcVStackPushInteger (parse, l);
-    FcStrFree (s);
+    FcStrBufDestroy (&parse->pstack->str);
 }
 
 /*
- * idea copied from glib g_ascii_strtod with 
- * permission of the author (Alexander Larsson) 
+ * idea copied from glib g_ascii_strtod with
+ * permission of the author (Alexander Larsson)
  */
 
 #include <locale.h>
 
-static double 
+static double
 FcStrtod (char *s, char **end)
 {
     struct lconv    *locale_data;
@@ -912,7 +1231,7 @@ FcStrtod (char *s, char **end)
        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;
@@ -929,8 +1248,11 @@ FcStrtod (char *s, char **end)
            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;
        }
@@ -945,10 +1267,10 @@ FcParseDouble (FcConfigParse *parse)
 {
     FcChar8 *s, *end;
     double  d;
-    
+
     if (!parse->pstack)
        return;
-    s = FcStrBufDone (&parse->pstack->str);
+    s = FcStrBufDoneStatic (&parse->pstack->str);
     if (!s)
     {
        FcConfigMessage (parse, FcSevereError, "out of memory");
@@ -960,14 +1282,14 @@ FcParseDouble (FcConfigParse *parse)
        FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid double", s);
     else
        FcVStackPushDouble (parse, d);
-    FcStrFree (s);
+    FcStrBufDestroy (&parse->pstack->str);
 }
 
 static void
 FcParseString (FcConfigParse *parse, FcVStackTag tag)
 {
     FcChar8 *s;
-    
+
     if (!parse->pstack)
        return;
     s = FcStrBufDone (&parse->pstack->str);
@@ -986,8 +1308,8 @@ 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)))
+
+    while ((vstack = FcVStackPeek (parse)))
     {
        double  v;
        switch (vstack->tag) {
@@ -1009,6 +1331,7 @@ FcParseMatrix (FcConfigParse *parse)
        case m_yy: m.yy = v; break;
        default: break;
        }
+       FcVStackPopAndDestroy (parse);
        matrix_state--;
     }
     if (matrix_state != m_done)
@@ -1017,16 +1340,58 @@ FcParseMatrix (FcConfigParse *parse)
        FcVStackPushMatrix (parse, &m);
 }
 
+static void
+FcParseRange (FcConfigParse *parse)
+{
+    FcVStack   *vstack;
+    FcRange    r;
+    FcChar32   n;
+    int                count = 1;
+
+    while ((vstack = FcVStackPeek (parse)))
+    {
+       if (count < 0)
+       {
+           FcConfigMessage (parse, FcSevereError, "too many elements in range");
+           return;
+       }
+       switch (vstack->tag) {
+       case FcVStackInteger:
+           n = vstack->u.integer;
+           break;
+       default:
+           FcConfigMessage (parse, FcSevereError, "invalid element in range");
+           break;
+       }
+       if (count == 1)
+           r.end = n;
+       else
+           r.begin = n;
+       count--;
+       FcVStackPopAndDestroy (parse);
+    }
+    if (count < 0)
+    {
+       if (r.begin > r.end)
+       {
+           FcConfigMessage (parse, FcSevereError, "invalid range");
+           return;
+       }
+       FcVStackPushRange (parse, &r);
+    }
+    else
+       FcConfigMessage (parse, FcSevereError, "invalid range");
+}
+
 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
@@ -1036,14 +1401,116 @@ FcParseBool (FcConfigParse *parse)
 
     if (!parse->pstack)
        return;
-    s = FcStrBufDone (&parse->pstack->str);
+    s = FcStrBufDoneStatic (&parse->pstack->str);
     if (!s)
     {
        FcConfigMessage (parse, FcSevereError, "out of memory");
        return;
     }
-    FcVStackPushBool (parse, FcConfigLexBool (s));
-    FcStrFree (s);
+    FcVStackPushBool (parse, FcConfigLexBool (parse, s));
+    FcStrBufDestroy (&parse->pstack->str);
+}
+
+static void
+FcParseCharSet (FcConfigParse *parse)
+{
+    FcVStack   *vstack;
+    FcCharSet  *charset = FcCharSetCreate ();
+    FcChar32   i;
+    int n = 0;
+
+    while ((vstack = FcVStackPeek (parse)))
+    {
+       switch (vstack->tag) {
+       case FcVStackInteger:
+           if (!FcCharSetAddChar (charset, vstack->u.integer))
+           {
+               FcConfigMessage (parse, FcSevereWarning, "invalid character: 0x%04x", vstack->u.integer);
+           }
+           else
+               n++;
+           break;
+       case FcVStackRange:
+           if (vstack->u.range.begin <= vstack->u.range.end)
+           {
+             for (i = vstack->u.range.begin; i <= vstack->u.range.end; i++)
+             {
+                 if (!FcCharSetAddChar (charset, i))
+                 {
+                     FcConfigMessage (parse, FcSevereWarning, "invalid character: 0x%04x", i);
+                 }
+                 else
+                     n++;
+             }
+           }
+           break;
+       default:
+               FcConfigMessage (parse, FcSevereError, "invalid element in charset");
+               break;
+       }
+       FcVStackPopAndDestroy (parse);
+    }
+    if (n > 0)
+           FcVStackPushCharSet (parse, charset);
+    else
+           FcCharSetDestroy (charset);
+}
+
+static void
+FcParseLangSet (FcConfigParse *parse)
+{
+    FcVStack   *vstack;
+    FcLangSet  *langset = FcLangSetCreate ();
+    int n = 0;
+
+    while ((vstack = FcVStackPeek (parse)))
+    {
+       switch (vstack->tag) {
+       case FcVStackString:
+           if (!FcLangSetAdd (langset, vstack->u.string))
+           {
+               FcConfigMessage (parse, FcSevereWarning, "invalid langset: %s", vstack->u.string);
+           }
+           else
+               n++;
+           break;
+       default:
+               FcConfigMessage (parse, FcSevereError, "invalid element in langset");
+               break;
+       }
+       FcVStackPopAndDestroy (parse);
+    }
+    if (n > 0)
+           FcVStackPushLangSet (parse, langset);
+    else
+           FcLangSetDestroy (langset);
+}
+
+static FcBool
+FcConfigLexBinding (FcConfigParse   *parse,
+                   const FcChar8   *binding_string,
+                   FcValueBinding  *binding_ret)
+{
+    FcValueBinding 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 binding \"%s\"", binding_string);
+           return FcFalse;
+       }
+    }
+    *binding_ret = binding;
+    return FcTrue;
 }
 
 static void
@@ -1052,20 +1519,20 @@ FcParseFamilies (FcConfigParse *parse, FcVStackTag tag)
     FcVStack   *vstack;
     FcExpr     *left, *expr = 0, *new;
 
-    while ((vstack = FcVStackPop (parse)))
+    while ((vstack = FcVStackPeek (parse)))
     {
        if (vstack->tag != FcVStackFamily)
        {
            FcConfigMessage (parse, FcSevereWarning, "non-family");
-           FcVStackDestroy (vstack);
+           FcVStackPopAndDestroy (parse);
            continue;
        }
        left = vstack->u.expr;
        vstack->tag = FcVStackNone;
-       FcVStackDestroy (vstack);
+       FcVStackPopAndDestroy (parse);
        if (expr)
        {
-           new = FcExprCreateOp (left, FcOpComma, expr);
+           new = FcExprCreateOp (parse->config, left, FcOpComma, expr);
            if (!new)
            {
                FcConfigMessage (parse, FcSevereError, "out of memory");
@@ -1083,8 +1550,7 @@ FcParseFamilies (FcConfigParse *parse, FcVStackTag tag)
        if (!FcVStackPushExpr (parse, tag, expr))
        {
            FcConfigMessage (parse, FcSevereError, "out of memory");
-           if (expr)
-               FcExprDestroy (expr);
+            FcExprDestroy (expr);
        }
     }
 }
@@ -1097,14 +1563,14 @@ FcParseFamily (FcConfigParse *parse)
 
     if (!parse->pstack)
        return;
-    s = FcStrBufDone (&parse->pstack->str);
+    s = FcStrBufDoneStatic (&parse->pstack->str);
     if (!s)
     {
        FcConfigMessage (parse, FcSevereError, "out of memory");
        return;
     }
-    expr = FcExprCreateString (s);
-    FcStrFree (s);
+    expr = FcExprCreateString (parse->config, s);
+    FcStrBufDestroy (&parse->pstack->str);
     if (expr)
        FcVStackPushExpr (parse, FcVStackFamily, expr);
 }
@@ -1116,14 +1582,17 @@ FcParseAlias (FcConfigParse *parse)
     FcEdit     *edit = 0, *next;
     FcVStack   *vstack;
     FcTest     *test;
+    FcValueBinding  binding;
 
-    while ((vstack = FcVStackPop (parse))) 
+    if (!FcConfigLexBinding (parse, FcConfigGetAttribute (parse, "binding"), &binding))
+       return;
+    while ((vstack = FcVStackPeek (parse)))
     {
        switch (vstack->tag) {
        case FcVStackFamily:
            if (family)
            {
-               new = FcExprCreateOp (vstack->u.expr, FcOpComma, family);
+               new = FcExprCreateOp (parse->config, vstack->u.expr, FcOpComma, family);
                if (!new)
                    FcConfigMessage (parse, FcSevereError, "out of memory");
                else
@@ -1159,7 +1628,7 @@ FcParseAlias (FcConfigParse *parse)
            FcConfigMessage (parse, FcSevereWarning, "bad alias");
            break;
        }
-       FcVStackDestroy (vstack);
+       FcVStackPopAndDestroy (parse);
     }
     if (!family)
     {
@@ -1174,10 +1643,11 @@ FcParseAlias (FcConfigParse *parse)
     }
     if (prefer)
     {
-       edit = FcEditCreate (FcConfigSaveField ("family"),
+       edit = FcEditCreate (parse,
+                            FC_FAMILY_OBJECT,
                             FcOpPrepend,
                             prefer,
-                            FcValueBindingWeak);
+                            binding);
        if (edit)
            edit->next = 0;
        else
@@ -1186,10 +1656,11 @@ FcParseAlias (FcConfigParse *parse)
     if (accept)
     {
        next = edit;
-       edit = FcEditCreate (FcConfigSaveField ("family"),
+       edit = FcEditCreate (parse,
+                            FC_FAMILY_OBJECT,
                             FcOpAppend,
                             accept,
-                            FcValueBindingWeak);
+                            binding);
        if (edit)
            edit->next = next;
        else
@@ -1198,10 +1669,11 @@ FcParseAlias (FcConfigParse *parse)
     if (def)
     {
        next = edit;
-       edit = FcEditCreate (FcConfigSaveField ("family"),
+       edit = FcEditCreate (parse,
+                            FC_FAMILY_OBJECT,
                             FcOpAppendLast,
                             def,
-                            FcValueBindingWeak);
+                            binding);
        if (edit)
            edit->next = next;
        else
@@ -1209,7 +1681,7 @@ FcParseAlias (FcConfigParse *parse)
     }
     if (edit)
     {
-       test = FcTestCreate (FcMatchPattern,
+       test = FcTestCreate (parse, FcMatchPattern,
                             FcQualAny,
                             (FcChar8 *) FC_FAMILY,
                             FcOpEqual,
@@ -1225,7 +1697,7 @@ FcParseAlias (FcConfigParse *parse)
 static FcExpr *
 FcPopExpr (FcConfigParse *parse)
 {
-    FcVStack   *vstack = FcVStackPop (parse);
+    FcVStack   *vstack = FcVStackPeek (parse);
     FcExpr     *expr = 0;
     if (!vstack)
        return 0;
@@ -1234,13 +1706,16 @@ FcPopExpr (FcConfigParse *parse)
        break;
     case FcVStackString:
     case FcVStackFamily:
-       expr = FcExprCreateString (vstack->u.string);
+       expr = FcExprCreateString (parse->config, vstack->u.string);
        break;
     case FcVStackField:
-       expr = FcExprCreateField ((char *) vstack->u.string);
+       expr = FcExprCreateField (parse->config, (char *) vstack->u.string);
        break;
     case FcVStackConstant:
-       expr = FcExprCreateConst (vstack->u.string);
+       expr = FcExprCreateConst (parse->config, vstack->u.string);
+       break;
+    case FcVStackGlob:
+       /* XXX: What's the correct action here? (CDW) */
        break;
     case FcVStackPrefer:
     case FcVStackAccept:
@@ -1249,16 +1724,24 @@ FcPopExpr (FcConfigParse *parse)
        vstack->tag = FcVStackNone;
        break;
     case FcVStackInteger:
-       expr = FcExprCreateInteger (vstack->u.integer);
+       expr = FcExprCreateInteger (parse->config, vstack->u.integer);
        break;
     case FcVStackDouble:
-       expr = FcExprCreateDouble (vstack->u._double);
+       expr = FcExprCreateDouble (parse->config, vstack->u._double);
        break;
     case FcVStackMatrix:
-       expr = FcExprCreateMatrix (vstack->u.matrix);
+       expr = FcExprCreateMatrix (parse->config, vstack->u.matrix);
+       break;
+    case FcVStackRange:
        break;
     case FcVStackBool:
-       expr = FcExprCreateBool (vstack->u.bool);
+       expr = FcExprCreateBool (parse->config, vstack->u.bool_);
+       break;
+    case FcVStackCharSet:
+       expr = FcExprCreateCharSet (parse->config, vstack->u.charset);
+       break;
+    case FcVStackLangSet:
+       expr = FcExprCreateLangSet (parse->config, vstack->u.langset);
        break;
     case FcVStackTest:
        break;
@@ -1268,13 +1751,24 @@ FcPopExpr (FcConfigParse *parse)
        break;
     case FcVStackEdit:
        break;
+    default:
+       break;
     }
-    FcVStackDestroy (vstack);
+    FcVStackPopAndDestroy (parse);
     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;
 
@@ -1282,26 +1776,56 @@ FcPopExprs (FcConfigParse *parse, FcOp op)
     {
        if (expr)
        {
-           new = FcExprCreateOp (left, op, expr);
-           if (!new)
-           {
-               FcConfigMessage (parse, FcSevereError, "out of memory");
-               FcExprDestroy (left);
-               FcExprDestroy (expr);
-               break;
-           }
-           expr = new;
+           new = FcExprCreateOp (parse->config, left, op, expr);
+           if (!new)
+           {
+               FcConfigMessage (parse, FcSevereError, "out of memory");
+               FcExprDestroy (left);
+               FcExprDestroy (expr);
+               return 0;
+           }
+           expr = new;
+       }
+       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 (parse->config, operand, op, 0);
+       if (!new)
+       {
+           FcExprDestroy (operand);
+           FcConfigMessage (parse, FcSevereError, "out of memory");
        }
-       else
-           expr = left;
     }
-    return expr;
+    return new;
 }
 
 static void
-FcParseExpr (FcConfigParse *parse, FcOp op)
+FcParseUnary (FcConfigParse *parse, FcOp op)
 {
-    FcExpr  *expr = FcPopExprs (parse, op);
+    FcExpr  *expr = FcPopUnary (parse, op);
     if (expr)
        FcVStackPushExpr (parse, FcVStackExpr, expr);
 }
@@ -1312,23 +1836,23 @@ FcParseInclude (FcConfigParse *parse)
     FcChar8        *s;
     const FcChar8   *i;
     FcBool         ignore_missing = FcFalse;
-    
-    s = FcStrBufDone (&parse->pstack->str);
+
+    s = FcStrBufDoneStatic (&parse->pstack->str);
     if (!s)
     {
        FcConfigMessage (parse, FcSevereError, "out of memory");
        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);
+    FcStrBufDestroy (&parse->pstack->str);
 }
 
 typedef struct _FcOpMap {
-    char    *name;
+    char    name[16];
     FcOp    op;
 } FcOpMap;
 
@@ -1338,7 +1862,7 @@ FcConfigLexOp (const FcChar8 *op, const FcOpMap   *map, int nmap)
     int        i;
 
     for (i = 0; i < nmap; i++)
-       if (!strcmp ((char *) op, map[i].name)) 
+       if (!strcmp ((char *) op, map[i].name))
            return map[i].op;
     return FcOpInvalid;
 }
@@ -1349,10 +1873,12 @@ 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])
+#define NUM_COMPARE_OPS        (int) (sizeof fcCompareOps / sizeof fcCompareOps[0])
 
 static FcOp
 FcConfigLexCompare (const FcChar8 *compare)
@@ -1360,7 +1886,6 @@ FcConfigLexCompare (const FcChar8 *compare)
     return FcConfigLexOp (compare, fcCompareOps, NUM_COMPARE_OPS);
 }
 
-
 static void
 FcParseTest (FcConfigParse *parse)
 {
@@ -1383,6 +1908,8 @@ FcParseTest (FcConfigParse *parse)
            kind = FcMatchPattern;
        else if (!strcmp ((char *) kind_string, "font"))
            kind = FcMatchFont;
+       else if (!strcmp ((char *) kind_string, "scan"))
+           kind = FcMatchScan;
        else if (!strcmp ((char *) kind_string, "default"))
            kind = FcMatchDefault;
        else
@@ -1428,13 +1955,13 @@ FcParseTest (FcConfigParse *parse)
            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");
@@ -1452,7 +1979,7 @@ static const FcOpMap fcModeOps[] = {
     { "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)
@@ -1465,7 +1992,6 @@ FcParseEdit (FcConfigParse *parse)
 {
     const FcChar8   *name;
     const FcChar8   *mode_string;
-    const FcChar8   *binding_string;
     FcOp           mode;
     FcValueBinding  binding;
     FcExpr         *expr;
@@ -1489,23 +2015,12 @@ FcParseEdit (FcConfigParse *parse)
            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
-       {
-           FcConfigMessage (parse, FcSevereWarning, "invalid edit binding \"%s\"", binding_string);
-           return;
-       }
-    }
-    expr = FcPopExprs (parse, FcOpComma);
-    edit = FcEditCreate ((char *) FcStrCopy (name), mode, expr, binding);
+    if (!FcConfigLexBinding (parse, FcConfigGetAttribute (parse, "binding"), &binding))
+       return;
+
+    expr = FcPopBinary (parse, FcOpComma);
+    edit = FcEditCreate (parse, FcObjectFromName ((char *) name),
+                        mode, expr, binding);
     if (!edit)
     {
        FcConfigMessage (parse, FcSevereError, "out of memory");
@@ -1534,13 +2049,15 @@ FcParseMatch (FcConfigParse *parse)
            kind = FcMatchPattern;
        else if (!strcmp ((char *) kind_name, "font"))
            kind = FcMatchFont;
+       else if (!strcmp ((char *) kind_name, "scan"))
+           kind = FcMatchScan;
        else
        {
            FcConfigMessage (parse, FcSevereWarning, "invalid match target \"%s\"", kind_name);
            return;
        }
     }
-    while ((vstack = FcVStackPop (parse)))
+    while ((vstack = FcVStackPeek (parse)))
     {
        switch (vstack->tag) {
        case FcVStackTest:
@@ -1552,23 +2069,196 @@ FcParseMatch (FcConfigParse *parse)
            vstack->u.edit->next = edit;
            edit = vstack->u.edit;
            vstack->tag = FcVStackNone;
+           if (kind == FcMatchScan && edit->object > FC_MAX_BASE_OBJECT)
+           {
+               FcConfigMessage (parse, FcSevereError,
+                                "<match target=\"scan\"> cannot edit user-defined object \"%s\"",
+                                FcObjectName(edit->object));
+           }
            break;
        default:
            FcConfigMessage (parse, FcSevereWarning, "invalid match element");
            break;
        }
-       FcVStackDestroy (vstack);
+       FcVStackPopAndDestroy (parse);
     }
     if (!FcConfigAddEdit (parse->config, test, edit, kind))
        FcConfigMessage (parse, FcSevereError, "out of memory");
 }
 
+static void
+FcParseAcceptRejectFont (FcConfigParse *parse, FcElement element)
+{
+    FcVStack   *vstack;
+
+    while ((vstack = FcVStackPeek (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;
+       }
+       FcVStackPopAndDestroy (parse);
+    }
+}
+
+
+static FcValue
+FcPopValue (FcConfigParse *parse)
+{
+    FcVStack   *vstack = FcVStackPeek (parse);
+    FcValue    value;
+
+    value.type = FcTypeVoid;
+
+    if (!vstack)
+       return value;
+
+    switch (vstack->tag) {
+    case FcVStackString:
+       value.u.s = FcStrStaticName (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;
+    case FcVStackCharSet:
+       value.u.c = FcCharSetCopy (vstack->u.charset);
+       if (value.u.c)
+           value.type = FcTypeCharSet;
+       break;
+    case FcVStackLangSet:
+       value.u.l = FcLangSetCopy (vstack->u.langset);
+       if (value.u.l)
+           value.type = FcTypeLangSet;
+       break;
+    default:
+       FcConfigMessage (parse, FcSevereWarning, "unknown pattern element %d",
+                        vstack->tag);
+       break;
+    }
+    FcVStackPopAndDestroy (parse);
+
+    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");
+       FcPatternDestroy (pattern);
+       return;
+    }
+
+    for (;;)
+    {
+       value = FcPopValue (parse);
+       if (value.type == FcTypeVoid)
+           break;
+       if (!FcPatternAdd (pattern, name, value, FcTrue))
+       {
+           FcConfigMessage (parse, FcSevereError, "out of memory");
+            FcValueDestroy(value);
+           break;
+       }
+        FcValueDestroy(value);
+    }
+
+    FcVStackPushPattern (parse, pattern);
+}
+
+static void
+FcParsePattern (FcConfigParse *parse)
+{
+    FcVStack   *vstack;
+    FcPattern  *pattern = FcPatternCreate ();
+
+    if (!pattern)
+    {
+       FcConfigMessage (parse, FcSevereError, "out of memory");
+       return;
+    }
+       
+    while ((vstack = FcVStackPeek (parse)))
+    {
+       switch (vstack->tag) {
+       case FcVStackPattern:
+           if (!FcPatternAppend (pattern, vstack->u.pattern))
+           {
+               FcConfigMessage (parse, FcSevereError, "out of memory");
+               FcPatternDestroy (pattern);
+               return;
+           }
+           break;
+       default:
+           FcConfigMessage (parse, FcSevereWarning, "unknown pattern element");
+           break;
+       }
+       FcVStackPopAndDestroy (parse);
+    }
+
+    FcVStackPushPattern (parse, pattern);
+}
+
 static void
 FcEndElement(void *userData, const XML_Char *name)
 {
     FcConfigParse   *parse = userData;
     FcChar8        *data;
-    
+#ifdef _WIN32
+    FcChar8         buffer[1000];
+#endif
+
     if (!parse->pstack)
        return;
     switch (parse->pstack->element) {
@@ -1577,26 +2267,121 @@ FcEndElement(void *userData, const XML_Char *name)
     case FcElementFontconfig:
        break;
     case FcElementDir:
-       data = FcStrBufDone (&parse->pstack->str);
+       data = FcStrBufDoneStatic (&parse->pstack->str);
        if (!data)
        {
            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, "CUSTOMFONTDIR") == 0)
+       {
+               char *p;
+               data = buffer;
+               if (!GetModuleFileName (NULL, buffer, sizeof (buffer) - 20))
+               {
+                       FcConfigMessage (parse, FcSevereError, "GetModuleFileName failed");
+                       break;
+               }
+               /*
+                * Must use the multi-byte aware function to search
+                * for backslash because East Asian double-byte code
+                * pages have characters with backslash as the second
+                * byte.
+                */
+               p = _mbsrchr (data, '\\');
+               if (p) *p = '\0';
+               strcat (data, "\\fonts");
+       }
+       else if (strcmp (data, "APPSHAREFONTDIR") == 0)
+       {
+               char *p;
+               data = buffer;
+               if (!GetModuleFileName (NULL, buffer, sizeof (buffer) - 20))
+               {
+                       FcConfigMessage (parse, FcSevereError, "GetModuleFileName failed");
+                       break;
+               }
+               p = _mbsrchr (data, '\\');
+               if (p) *p = '\0';
+               strcat (data, "\\..\\share\\fonts");
+       }
+       else if (strcmp (data, "WINDOWSFONTDIR") == 0)
+       {
+           int rc;
+           data = buffer;
+#if _WIN32_WINNT >= 0x0500
+           rc = GetSystemWindowsDirectory (buffer, sizeof (buffer) - 20);
+#else
+           rc = GetWindowsDirectory (buffer, sizeof (buffer) - 20);
+#endif
+           if (rc == 0 || rc > sizeof (buffer) - 20)
+           {
+               FcConfigMessage (parse, FcSevereError, "GetSystemWindowsDirectory failed");
+               break;
+           }
+           if (data [strlen (data) - 1] != '\\')
+               strcat (data, "\\");
+           strcat (data, "fonts");
+       }
+#endif
+       if (strlen ((char *) data) == 0)
+           FcConfigMessage (parse, FcSevereWarning, "empty font directory name ignored");
+       else if (!FcStrUsesHome (data) || FcConfigHome ())
+       {
+           if (!FcConfigAddDir (parse->config, data))
+               FcConfigMessage (parse, FcSevereError, "out of memory; cannot add directory %s", data);
+       }
+       FcStrBufDestroy (&parse->pstack->str);
        break;
-    case FcElementCache:
+    case FcElementCacheDir:
        data = FcStrBufDone (&parse->pstack->str);
        if (!data)
        {
            FcConfigMessage (parse, FcSevereError, "out of memory");
            break;
        }
-       if (!FcConfigSetCache (parse->config, data))
+#ifdef _WIN32
+       if (strcmp (data, "WINDOWSTEMPDIR_FONTCONFIG_CACHE") == 0)
+       {
+           int rc;
+           FcStrFree (data);
+           data = malloc (1000);
+           if (!data)
+           {
+               FcConfigMessage (parse, FcSevereError, "out of memory");
+               break;
+           }
+           FcMemAlloc (FC_MEM_STRING, 1000);
+           rc = GetTempPath (800, data);
+           if (rc == 0 || rc > 800)
+           {
+               FcConfigMessage (parse, FcSevereError, "GetTempPath failed");
+               FcStrFree (data);
+               break;
+           }
+           if (data [strlen (data) - 1] != '\\')
+               strcat (data, "\\");
+           strcat (data, "fontconfig\\cache");
+       }
+#endif
+       if (!FcStrUsesHome (data) || FcConfigHome ())
+       {
+           if (!FcConfigAddCacheDir (parse->config, data))
+               FcConfigMessage (parse, FcSevereError, "out of memory; cannot add cache directory %s", data);
+       }
+       FcStrFree (data);
+       break;
+       
+    case FcElementCache:
+       data = FcStrBufDoneStatic (&parse->pstack->str);
+       if (!data)
+       {
            FcConfigMessage (parse, FcSevereError, "out of memory");
-       free (data);
+           break;
+       }
+       /* discard this data; no longer used */
+       FcStrBufDestroy (&parse->pstack->str);
        break;
     case FcElementInclude:
        FcParseInclude (parse);
@@ -1649,13 +2434,33 @@ FcEndElement(void *userData, const XML_Char *name)
     case FcElementMatrix:
        FcParseMatrix (parse);
        break;
+    case FcElementRange:
+       FcParseRange (parse);
+       break;
     case FcElementBool:
        FcParseBool (parse);
        break;
-    case FcElementCharset:
-/*     FcParseCharset (parse); */
+    case FcElementCharSet:
+       FcParseCharSet (parse);
+       break;
+    case FcElementLangSet:
+       FcParseLangSet (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;
@@ -1663,46 +2468,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;
@@ -1714,7 +2537,7 @@ 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))
@@ -1734,11 +2557,126 @@ FcStartDoctypeDecl (void           *userData,
        FcConfigMessage (parse, FcSevereError, "invalid doctype \"%s\"", doctypeName);
 }
 
+#ifdef ENABLE_LIBXML2
+
+static void
+FcInternalSubsetDecl (void            *userData,
+                     const XML_Char  *doctypeName,
+                     const XML_Char  *sysid,
+                     const XML_Char  *pubid)
+{
+    FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 1);
+}
+
+static void
+FcExternalSubsetDecl (void            *userData,
+                     const XML_Char  *doctypeName,
+                     const XML_Char  *sysid,
+                     const XML_Char  *pubid)
+{
+    FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 0);
+}
+
+#else /* ENABLE_LIBXML2 */
+
 static void
 FcEndDoctypeDecl (void *userData)
 {
 }
 
+#endif /* ENABLE_LIBXML2 */
+
+static int
+FcSortCmpStr (const void *a, const void *b)
+{
+    const FcChar8    *as = *((FcChar8 **) a);
+    const FcChar8    *bs = *((FcChar8 **) b);
+    return FcStrCmp (as, bs);
+}
+
+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 *)) FcSortCmpStr);
+       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,
@@ -1747,53 +2685,104 @@ FcConfigParseAndLoad (FcConfig     *config,
 
     XML_Parser     p;
     FcChar8        *filename;
-    FILE           *f;
+    int                    fd;
     int                    len;
-    void           *buf;
     FcConfigParse   parse;
     FcBool         error = FcTrue;
-    
+
+#ifdef ENABLE_LIBXML2
+    xmlSAXHandler   sax;
+    char            buf[BUFSIZ];
+#else
+    void           *buf;
+#endif
+
     filename = FcConfigFilename (name);
     if (!filename)
        goto bail0;
-    
+
+    if (FcStrSetMember (config->configFiles, filename))
+    {
+        FcStrFree (filename);
+        return FcTrue;
+    }
+
     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);
-    if (!f)
+    fd = open ((char *) filename, O_RDONLY);
+    if (fd == -1) {
+       FcStrFree (filename);
        goto bail0;
-    
+    }
+
+#ifdef ENABLE_LIBXML2
+    memset(&sax, 0, sizeof(sax));
+
+    sax.internalSubset = FcInternalSubsetDecl;
+    sax.externalSubset = FcExternalSubsetDecl;
+    sax.startElement = FcStartElement;
+    sax.endElement = FcEndElement;
+    sax.characters = FcCharacterData;
+
+    p = xmlCreatePushParserCtxt (&sax, &parse, NULL, 0, (const char *) filename);
+#else
     p = XML_ParserCreate ("UTF-8");
+#endif
+    FcStrFree (filename);
+
     if (!p)
        goto bail1;
 
     if (!FcConfigInit (&parse, name, config, p))
        goto bail2;
 
+#ifndef ENABLE_LIBXML2
+
     XML_SetUserData (p, &parse);
-    
+
     XML_SetDoctypeDeclHandler (p, FcStartDoctypeDecl, FcEndDoctypeDecl);
     XML_SetElementHandler (p, FcStartElement, FcEndElement);
     XML_SetCharacterDataHandler (p, FcCharacterData);
        
+#endif /* ENABLE_LIBXML2 */
+
     do {
+#ifndef ENABLE_LIBXML2
        buf = XML_GetBuffer (p, BUFSIZ);
        if (!buf)
        {
            FcConfigMessage (&parse, FcSevereError, "cannot get parse buffer");
            goto bail3;
        }
-       len = fread (buf, 1, BUFSIZ, f);
+#endif
+       len = read (fd, buf, BUFSIZ);
        if (len < 0)
        {
            FcConfigMessage (&parse, FcSevereError, "failed reading config file");
            goto bail3;
        }
+
+#ifdef ENABLE_LIBXML2
+       if (xmlParseChunk (p, buf, len, len == 0))
+#else
        if (!XML_ParseBuffer (p, len, len == 0))
+#endif
        {
-           FcConfigMessage (&parse, FcSevereError, "%s", 
+           FcConfigMessage (&parse, FcSevereError, "%s",
                           XML_ErrorString (XML_GetErrorCode (p)));
            goto bail3;
        }
@@ -1804,7 +2793,8 @@ bail3:
 bail2:
     XML_ParserFree (p);
 bail1:
-    fclose (f);
+    close (fd);
+    fd = -1;
 bail0:
     if (error && complain)
     {
@@ -1816,3 +2806,6 @@ bail0:
     }
     return FcTrue;
 }
+#define __fcxml__
+#include "fcaliastail.h"
+#undef __fcxml__