]> git.wh0rd.org - fontconfig.git/blobdiff - src/fcxml.c
[fcxml] Embed 8 static FcPStack objects in FcConfigParse
[fontconfig.git] / src / fcxml.c
index 539e57fafb66b3567bc1cdc8ebfb5a2179b47c69..e6d16f3d4812b57137ce7be3b3e65b942e4ae155 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $RCSId: xc/lib/fontconfig/src/fcxml.c,v 1.21 2002/08/22 18:53:22 keithp Exp $
+ * fontconfig/src/fcxml.c
  *
  * Copyright © 2002 Keith Packard
  *
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include <stdarg.h>
 #include "fcint.h"
+#include <fcntl.h>
+#include <stdarg.h>
 #include <dirent.h>
 
+#ifdef ENABLE_LIBXML2
+
+#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 */
+
 #ifndef HAVE_XMLPARSE_H
 #define HAVE_XMLPARSE_H 0
 #endif
@@ -36,6 +50,8 @@
 #include <expat.h>
 #endif
 
+#endif /* ENABLE_LIBXML2 */
+
 #ifdef _WIN32
 #define STRICT
 #include <windows.h>
@@ -49,7 +65,6 @@ FcTestDestroy (FcTest *test)
     if (test->next)
        FcTestDestroy (test->next);
     FcExprDestroy (test->expr);
-    FcStrFree ((FcChar8 *) test->field);
     FcMemFree (FC_MEM_TEST, sizeof (FcTest));
     free (test);
 }
@@ -146,7 +161,7 @@ FcExprCreateField (const char *field)
     {
        FcMemAlloc (FC_MEM_EXPR, sizeof (FcExpr));
        e->op = FcOpField;
-       e->u.field = (char *) FcStrCopy ((FcChar8 *) field);
+       e->u.object = FcObjectFromName (field);
     }
     return e;
 }
@@ -202,7 +217,6 @@ FcExprDestroy (FcExpr *e)
     case FcOpBool:
        break;
     case FcOpField:
-       FcStrFree ((FcChar8 *) e->u.field);
        break;
     case FcOpConst:
        FcStrFree (e->u.constant);
@@ -253,7 +267,6 @@ FcEditDestroy (FcEdit *e)
 {
     if (e->next)
        FcEditDestroy (e->next);
-    FcStrFree ((FcChar8 *) e->field);
     if (e->expr)
        FcExprDestroy (e->expr);
     free (e);
@@ -269,6 +282,7 @@ typedef enum _FcElement {
     FcElementNone,
     FcElementFontconfig,
     FcElementDir,
+    FcElementCacheDir,
     FcElementCache,
     FcElementInclude,
     FcElementConfig,
@@ -323,72 +337,73 @@ typedef enum _FcElement {
     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 },
+    { "bool",          FcElementBool },
+    { "charset",       FcElementCharset },
+    { "name",          FcElementName },
+    { "const",         FcElementConst },
+    { "or",            FcElementOr },
+    { "and",           FcElementAnd },
+    { "eq",            FcElementEq },
+    { "not_eq",                FcElementNotEq },
+    { "less",          FcElementLess },
+    { "less_eq",       FcElementLessEq },
+    { "more",          FcElementMore },
+    { "more_eq",       FcElementMoreEq },
+    { "contains",      FcElementContains },
+    { "not_contains",  FcElementNotContains },
+    { "plus",          FcElementPlus },
+    { "minus",         FcElementMinus },
+    { "times",         FcElementTimes },
+    { "divide",                FcElementDivide },
+    { "not",           FcElementNot },
+    { "if",            FcElementIf },
+    { "floor",         FcElementFloor },
+    { "ceil",          FcElementCeil },
+    { "round",         FcElementRound },
+    { "trunc",         FcElementTrunc },
+};
+#define NUM_ELEMENT_MAPS (int) (sizeof fcElementMap / sizeof fcElementMap[0])
+
 static FcElement
 FcElementMap (const XML_Char *name)
 {
-    static struct {
-       char        *name;
-       FcElement   element;
-    } fcElementMap[] = {
-       { "fontconfig", FcElementFontconfig },
-       { "dir",        FcElementDir },
-       { "cache",      FcElementCache },
-       { "include",    FcElementInclude },
-       { "config",     FcElementConfig },
-       { "match",      FcElementMatch },
-       { "alias",      FcElementAlias },
-       
-       { "blank",      FcElementBlank },
-       { "rescan",     FcElementRescan },
-
-       { "prefer",     FcElementPrefer },
-       { "accept",     FcElementAccept },
-       { "default",    FcElementDefault },
-       { "family",     FcElementFamily },
-
-       { "selectfont", FcElementSelectfont },
-       { "acceptfont", FcElementAcceptfont },
-       { "rejectfont", FcElementRejectfont },
-       { "glob",       FcElementGlob },
-       { "pattern",    FcElementPattern },
-       { "patelt",     FcElementPatelt },
-
-       { "test",       FcElementTest },
-       { "edit",       FcElementEdit },
-       { "int",        FcElementInt },
-       { "double",     FcElementDouble },
-       { "string",     FcElementString },
-       { "matrix",     FcElementMatrix },
-       { "bool",       FcElementBool },
-       { "charset",    FcElementCharset },
-       { "name",       FcElementName },
-       { "const",      FcElementConst },
-       { "or",         FcElementOr },
-       { "and",        FcElementAnd },
-       { "eq",         FcElementEq },
-       { "not_eq",     FcElementNotEq },
-       { "less",       FcElementLess },
-       { "less_eq",    FcElementLessEq },
-       { "more",       FcElementMore },
-       { "more_eq",    FcElementMoreEq },
-       { "contains",   FcElementContains },
-       { "not_contains",FcElementNotContains },
-       { "plus",       FcElementPlus },
-       { "minus",      FcElementMinus },
-       { "times",      FcElementTimes },
-       { "divide",     FcElementDivide },
-       { "not",        FcElementNot },
-       { "if",         FcElementIf },
-       { "floor",      FcElementFloor },
-       { "ceil",       FcElementCeil },
-       { "round",      FcElementRound },
-       { "trunc",      FcElementTrunc },
-       
-       { 0,            0 }
-    };
 
     int            i;
-    for (i = 0; fcElementMap[i].name; i++)
+    for (i = 0; i < NUM_ELEMENT_MAPS; i++)
        if (!strcmp ((char *) name, fcElementMap[i].name))
            return fcElementMap[i].element;
     return FcElementUnknown;
@@ -435,7 +450,7 @@ typedef struct _FcVStack {
        int             integer;
        double          _double;
        FcMatrix        *matrix;
-       FcBool          bool;
+       FcBool          bool_;
 
        FcTest          *test;
        FcQual          qual;
@@ -454,6 +469,8 @@ typedef struct _FcConfigParse {
     const FcChar8   *name;
     FcConfig       *config;
     XML_Parser     parser;
+    int             pstack_static_used;
+    FcPStack        pstack_static[8];
 } FcConfigParse;
 
 typedef enum _FcConfigSeverity {
@@ -461,9 +478,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);
@@ -477,10 +494,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;
     }
@@ -492,7 +509,7 @@ FcConfigMessage (FcConfigParse *parse, FcConfigSeverity severe, char *fmt, ...)
 }
 
 
-static char *
+static const char *
 FcTypeName (FcType type)
 {
     switch (type) {
@@ -530,6 +547,8 @@ FcTypecheckValue (FcConfigParse *parse, FcType value, FcType 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));
     }
@@ -541,6 +560,10 @@ FcTypecheckExpr (FcConfigParse *parse, FcExpr *expr, FcType type)
     const FcObjectType *o;
     const FcConstant   *c;
     
+    /* If parsing the expression failed, some nodes may be NULL */
+    if (!expr)
+       return;
+
     switch (expr->op) {
     case FcOpInteger:
     case FcOpDouble:
@@ -561,7 +584,7 @@ FcTypecheckExpr (FcConfigParse *parse, FcExpr *expr, FcType type)
     case FcOpNil:
        break;
     case FcOpField:
-       o = FcNameGetObjectType (expr->u.field);
+       o = FcNameGetObjectType (FcObjectName (expr->u.object));
        if (o)
            FcTypecheckValue (parse, o->type, type);
        break;
@@ -573,6 +596,10 @@ FcTypecheckExpr (FcConfigParse *parse, FcExpr *expr, FcType type)
            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);
@@ -637,10 +664,10 @@ FcTestCreate (FcConfigParse *parse,
        test->next = 0;
        test->kind = kind;
        test->qual = qual;
-       test->field = (char *) FcStrCopy (field);
+       test->object = FcObjectFromName ((const char *) field);
        test->op = compare;
        test->expr = expr;
-       o = FcNameGetObjectType (test->field);
+       o = FcNameGetObjectType (FcObjectName (test->object));
        if (o)
            FcTypecheckExpr (parse, expr, o->type);
     }
@@ -649,7 +676,7 @@ FcTestCreate (FcConfigParse *parse,
 
 static FcEdit *
 FcEditCreate (FcConfigParse    *parse,
-             const char        *field,
+             FcObject          object,
              FcOp              op,
              FcExpr            *expr,
              FcValueBinding    binding)
@@ -661,11 +688,11 @@ FcEditCreate (FcConfigParse       *parse,
        const FcObjectType      *o;
 
        e->next = 0;
-       e->field = field;   /* already saved in grammar */
+       e->object = object;
        e->op = op;
        e->expr = expr;
        e->binding = binding;
-       o = FcNameGetObjectType (e->field);
+       o = FcNameGetObjectType (FcObjectName (e->object));
        if (o)
            FcTypecheckExpr (parse, expr, o->type);
     }
@@ -796,12 +823,12 @@ FcVStackPushMatrix (FcConfigParse *parse, FcMatrix *matrix)
 }
 
 static FcBool
-FcVStackPushBool (FcConfigParse *parse, FcBool bool)
+FcVStackPushBool (FcConfigParse *parse, FcBool bool_)
 {
     FcVStack    *vstack = FcVStackCreate ();
     if (!vstack)
        return FcFalse;
-    vstack->u.bool = bool;
+    vstack->u.bool_ = bool_;
     vstack->tag = FcVStackBool;
     FcVStackPush (parse, vstack);
     return FcTrue;
@@ -904,7 +931,6 @@ FcVStackElements (FcConfigParse *parse)
 static FcChar8 **
 FcConfigSaveAttr (const XML_Char **attr)
 {
-    int                n;
     int                slen;
     int                i;
     FcChar8    **new;
@@ -914,11 +940,15 @@ FcConfigSaveAttr (const XML_Char **attr)
        return 0;
     slen = 0;
     for (i = 0; attr[i]; i++)
-       slen += strlen (attr[i]) + 1;
-    n = i;
+       slen += strlen ((char *) attr[i]) + 1;
+    if (i == 0)
+       return 0;
     new = malloc ((i + 1) * sizeof (FcChar8 *) + 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++)
@@ -934,21 +964,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;
-    FcMemAlloc (FC_MEM_PSTACK, sizeof (FcPStack));
-    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);
     FcStrBufInit (&new->str, 0, 0);
     parse->pstack = new;
     return FcTrue;
@@ -973,8 +1003,14 @@ FcPStackPop (FcConfigParse *parse)
        FcMemFree (FC_MEM_ATTR, 1); /* size is to expensive */
        free (old->attr);
     }
-    FcMemFree (FC_MEM_PSTACK, sizeof (FcPStack));
-    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;
 }
 
@@ -982,6 +1018,7 @@ 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->error = FcFalse;
     parse->name = name;
@@ -998,13 +1035,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))
@@ -1083,7 +1123,7 @@ FcParseInt (FcConfigParse *parse)
     
     if (!parse->pstack)
        return;
-    s = FcStrBufDone (&parse->pstack->str);
+    s = FcStrBufDoneStatic (&parse->pstack->str);
     if (!s)
     {
        FcConfigMessage (parse, FcSevereError, "out of memory");
@@ -1095,7 +1135,7 @@ FcParseInt (FcConfigParse *parse)
        FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid integer", s);
     else
        FcVStackPushInteger (parse, l);
-    FcStrFree (s);
+    FcStrBufDestroy (&parse->pstack->str);
 }
 
 /*
@@ -1125,7 +1165,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;
@@ -1164,7 +1204,7 @@ FcParseDouble (FcConfigParse *parse)
     
     if (!parse->pstack)
        return;
-    s = FcStrBufDone (&parse->pstack->str);
+    s = FcStrBufDoneStatic (&parse->pstack->str);
     if (!s)
     {
        FcConfigMessage (parse, FcSevereError, "out of memory");
@@ -1176,7 +1216,7 @@ FcParseDouble (FcConfigParse *parse)
        FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid double", s);
     else
        FcVStackPushDouble (parse, d);
-    FcStrFree (s);
+    FcStrBufDestroy (&parse->pstack->str);
 }
 
 static void
@@ -1235,13 +1275,13 @@ FcParseMatrix (FcConfigParse *parse)
 }
 
 static FcBool
-FcConfigLexBool (FcConfigParse *parse, const FcChar8 *bool)
+FcConfigLexBool (FcConfigParse *parse, const FcChar8 *bool_)
 {
     FcBool  result = FcFalse;
 
-    if (!FcNameBool (bool, &result))
+    if (!FcNameBool (bool_, &result))
        FcConfigMessage (parse, FcSevereWarning, "\"%s\" is not known boolean",
-                        bool);
+                        bool_);
     return result;
 }
 
@@ -1252,14 +1292,41 @@ 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 (parse, s));
-    FcStrFree (s);
+    FcStrBufDestroy (&parse->pstack->str);
+}
+
+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
@@ -1299,8 +1366,7 @@ FcParseFamilies (FcConfigParse *parse, FcVStackTag tag)
        if (!FcVStackPushExpr (parse, tag, expr))
        {
            FcConfigMessage (parse, FcSevereError, "out of memory");
-           if (expr)
-               FcExprDestroy (expr);
+            FcExprDestroy (expr);
        }
     }
 }
@@ -1313,14 +1379,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);
+    FcStrBufDestroy (&parse->pstack->str);
     if (expr)
        FcVStackPushExpr (parse, FcVStackFamily, expr);
 }
@@ -1332,7 +1398,10 @@ FcParseAlias (FcConfigParse *parse)
     FcEdit     *edit = 0, *next;
     FcVStack   *vstack;
     FcTest     *test;
+    FcValueBinding  binding;
 
+    if (!FcConfigLexBinding (parse, FcConfigGetAttribute (parse, "binding"), &binding))
+       return;
     while ((vstack = FcVStackPop (parse))) 
     {
        switch (vstack->tag) {
@@ -1391,10 +1460,10 @@ FcParseAlias (FcConfigParse *parse)
     if (prefer)
     {
        edit = FcEditCreate (parse, 
-                            FcConfigSaveField ("family"),
+                            FC_FAMILY_OBJECT,
                             FcOpPrepend,
                             prefer,
-                            FcValueBindingWeak);
+                            binding);
        if (edit)
            edit->next = 0;
        else
@@ -1404,10 +1473,10 @@ FcParseAlias (FcConfigParse *parse)
     {
        next = edit;
        edit = FcEditCreate (parse,
-                            FcConfigSaveField ("family"),
+                            FC_FAMILY_OBJECT,
                             FcOpAppend,
                             accept,
-                            FcValueBindingWeak);
+                            binding);
        if (edit)
            edit->next = next;
        else
@@ -1417,10 +1486,10 @@ FcParseAlias (FcConfigParse *parse)
     {
        next = edit;
        edit = FcEditCreate (parse,
-                            FcConfigSaveField ("family"),
+                            FC_FAMILY_OBJECT,
                             FcOpAppendLast,
                             def,
-                            FcValueBindingWeak);
+                            binding);
        if (edit)
            edit->next = next;
        else
@@ -1480,7 +1549,7 @@ FcPopExpr (FcConfigParse *parse)
        expr = FcExprCreateMatrix (vstack->u.matrix);
        break;
     case FcVStackBool:
-       expr = FcExprCreateBool (vstack->u.bool);
+       expr = FcExprCreateBool (vstack->u.bool_);
        break;
     case FcVStackTest:
        break;
@@ -1521,7 +1590,7 @@ FcPopBinary (FcConfigParse *parse, FcOp op)
                FcConfigMessage (parse, FcSevereError, "out of memory");
                FcExprDestroy (left);
                FcExprDestroy (expr);
-               break;
+               return 0;
            }
            expr = new;
        }
@@ -1576,7 +1645,7 @@ FcParseInclude (FcConfigParse *parse)
     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");
@@ -1587,11 +1656,11 @@ FcParseInclude (FcConfigParse *parse)
        ignore_missing = FcTrue;
     if (!FcConfigParseAndLoad (parse->config, s, !ignore_missing))
        parse->error = FcTrue;
-    FcStrFree (s);
+    FcStrBufDestroy (&parse->pstack->str);
 }
 
 typedef struct _FcOpMap {
-    char    *name;
+    char    name[16];
     FcOp    op;
 } FcOpMap;
 
@@ -1617,7 +1686,7 @@ static const FcOpMap fcCompareOps[] = {
     { "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)
@@ -1625,7 +1694,6 @@ FcConfigLexCompare (const FcChar8 *compare)
     return FcConfigLexOp (compare, fcCompareOps, NUM_COMPARE_OPS);
 }
 
-
 static void
 FcParseTest (FcConfigParse *parse)
 {
@@ -1648,6 +1716,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
@@ -1717,7 +1787,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)
@@ -1730,7 +1800,6 @@ FcParseEdit (FcConfigParse *parse)
 {
     const FcChar8   *name;
     const FcChar8   *mode_string;
-    const FcChar8   *binding_string;
     FcOp           mode;
     FcValueBinding  binding;
     FcExpr         *expr;
@@ -1754,25 +1823,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 if (!strcmp ((char *) binding_string, "same"))
-           binding = FcValueBindingSame;
-       else
-       {
-           FcConfigMessage (parse, FcSevereWarning, "invalid edit binding \"%s\"", binding_string);
-           return;
-       }
-    }
+    if (!FcConfigLexBinding (parse, FcConfigGetAttribute (parse, "binding"), &binding))
+       return;
+
     expr = FcPopBinary (parse, FcOpComma);
-    edit = FcEditCreate (parse, (char *) FcStrCopy (name), mode, expr, binding);
+    edit = FcEditCreate (parse, FcObjectFromName ((char *) name),
+                        mode, expr, binding);
     if (!edit)
     {
        FcConfigMessage (parse, FcSevereError, "out of memory");
@@ -1801,6 +1857,8 @@ 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);
@@ -1819,6 +1877,12 @@ 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");
@@ -1900,7 +1964,7 @@ FcPopValue (FcConfigParse *parse)
            value.type = FcTypeMatrix;
        break;
     case FcVStackBool:
-       value.u.b = vstack->u.bool;
+       value.u.b = vstack->u.bool_;
        value.type = FcTypeBool;
        break;
     default:
@@ -1926,10 +1990,11 @@ FcParsePatelt (FcConfigParse *parse)
        return;
     }
 
-    name = FcConfigGetAttribute (parse, "name");
+    name = (char *) FcConfigGetAttribute (parse, "name");
     if (!name)
     {
        FcConfigMessage (parse, FcSevereWarning, "missing pattern element name");
+       FcPatternDestroy (pattern);
        return;
     }
     
@@ -1941,8 +2006,10 @@ FcParsePatelt (FcConfigParse *parse)
        if (!FcPatternAdd (pattern, name, value, FcTrue))
        {
            FcConfigMessage (parse, FcSevereError, "out of memory");
+            FcValueDestroy(value);
            break;
        }
+        FcValueDestroy(value);
     }
 
     FcVStackPushPattern (parse, pattern);
@@ -1967,6 +2034,7 @@ FcParsePattern (FcConfigParse *parse)
            if (!FcPatternAppend (pattern, vstack->u.pattern))
            {
                FcConfigMessage (parse, FcSevereError, "out of memory");
+               FcPatternDestroy (pattern);
                return;
            }
            break;
@@ -1994,14 +2062,56 @@ 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;
        }
 #ifdef _WIN32
-       if (strcmp (data, "WINDOWSFONTDIR") == 0)
+       if (strcmp (data, "CUSTOMFONTDIR") == 0)
+       {
+               char *p;
+               FcStrFree (data);
+               data = malloc (1000);
+               if (!data)
+               {
+                       FcConfigMessage (parse, FcSevereError, "out of memory");
+                       break;
+               }
+               FcMemAlloc (FC_MEM_STRING, 1000);
+               if(!GetModuleFileName(NULL, data, 1000))
+               {
+                       FcConfigMessage (parse, FcSevereError, "GetModuleFileName failed");
+                       FcStrFree (data);
+                       break;
+               }
+               p = strrchr (data, '\\');
+               if (p) *p = '\0';
+               strcat (data, "\\fonts");
+       }
+       else if (strcmp (data, "APPSHAREFONTDIR") == 0)
+       {
+               char *p;
+               FcStrFree (data);
+               data = malloc (1000);
+               if (!data)
+               {
+                       FcConfigMessage (parse, FcSevereError, "out of memory");
+                       break;
+               }
+               FcMemAlloc (FC_MEM_STRING, 1000);
+               if(!GetModuleFileName(NULL, data, 1000))
+               {
+                       FcConfigMessage (parse, FcSevereError, "GetModuleFileName failed");
+                       FcStrFree (data);
+                       break;
+               }
+               p = strrchr (data, '\\');
+               if (p) *p = '\0';
+               strcat (data, "\\..\\share\\fonts");
+       }
+       else if (strcmp (data, "WINDOWSFONTDIR") == 0)
        {
            int rc;
            FcStrFree (data);
@@ -2024,27 +2134,64 @@ FcEndElement(void *userData, const XML_Char *name)
            strcat (data, "fonts");
        }
 #endif
-       if (!FcStrUsesHome (data) || FcConfigHome ())
+       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");
+               FcConfigMessage (parse, FcSevereError, "out of memory; cannot add directory %s", data);
        }
-       FcStrFree (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 (!FcStrUsesHome (data) || FcConfigHome ())
+#ifdef _WIN32
+       if (strcmp (data, "WINDOWSTEMPDIR_FONTCONFIG_CACHE") == 0)
        {
-           if (!FcConfigSetCache (parse->config, data))
+           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, "GetWindowsDirectory 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");
+           break;
+       }
+       /* discard this data; no longer used */
+       FcStrBufDestroy (&parse->pstack->str);
+       break;
     case FcElementInclude:
        FcParseInclude (parse);
        break;
@@ -2213,11 +2360,43 @@ 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,
@@ -2264,11 +2443,16 @@ FcConfigParseAndLoadDir (FcConfig       *config,
        
     while (ret && (e = readdir (d)))
     {
+       int d_len;
+#define TAIL       ".conf"
+#define TAIL_LEN    5
        /*
-        * Add all files of the form [0-9]*
+        * Add all files of the form [0-9]*.conf
         */
        if ('0' <= e->d_name[0] && e->d_name[0] <= '9' &&
-           strlen (e->d_name) < FC_MAX_FILE_LEN)
+           (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))
@@ -2282,7 +2466,7 @@ FcConfigParseAndLoadDir (FcConfig *config,
     {
        int i;
        qsort (files->strs, files->num, sizeof (FcChar8 *), 
-              (int (*)(const void *, const void *)) FcStrCmp);
+              (int (*)(const void *, const void *)) FcSortCmpStr);
        for (i = 0; ret && i < files->num; i++)
            ret = FcConfigParseAndLoad (config, files->strs[i], complain);
     }
@@ -2304,16 +2488,28 @@ 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);
@@ -2330,38 +2526,64 @@ FcConfigParseAndLoad (FcConfig      *config,
     if (FcDebug () & FC_DBG_CONFIG)
        printf ("\tLoading config file %s\n", filename);
 
-    f = fopen ((char *) filename, "r");
-    FcStrFree (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", 
                           XML_ErrorString (XML_GetErrorCode (p)));
@@ -2374,7 +2596,8 @@ bail3:
 bail2:
     XML_ParserFree (p);
 bail1:
-    fclose (f);
+    close (fd);
+    fd = -1;
 bail0:
     if (error && complain)
     {
@@ -2386,3 +2609,6 @@ bail0:
     }
     return FcTrue;
 }
+#define __fcxml__
+#include "fcaliastail.h"
+#undef __fcxml__