Re-scan font directories only when it contains subdirs
[platform/upstream/fontconfig.git] / src / fccfg.c
index 01d381c..6377fd7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $RCSId: xc/lib/fontconfig/src/fccfg.c,v 1.23 2002/08/31 22:17:32 keithp Exp $
+ * fontconfig/src/fccfg.c
  *
  * Copyright © 2000 Keith Packard
  *
@@ -7,36 +7,65 @@
  * 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.
  */
 
+/* Objects MT-safe for readonly access. */
+
 #include "fcint.h"
 #include <dirent.h>
 #include <sys/types.h>
 
-#if defined (_WIN32) && (defined (PIC) || defined (DLL_EXPORT))
-#define STRICT
-#include <windows.h>
-#undef STRICT
-#endif
-
 #if defined (_WIN32) && !defined (R_OK)
 #define R_OK 4
 #endif
 
-FcConfig    *_fcConfig;
+static FcConfig    *_fcConfig; /* MT-safe */
+
+static FcConfig *
+FcConfigEnsure (void)
+{
+    FcConfig   *config;
+retry:
+    config = fc_atomic_ptr_get (&_fcConfig);
+    if (!config)
+    {
+       config = FcInitLoadConfigAndFonts ();
+
+       if (!fc_atomic_ptr_cmpexch (&_fcConfig, NULL, config)) {
+           FcConfigDestroy (config);
+           goto retry;
+       }
+    }
+    return config;
+}
+
+FcBool
+FcConfigInit (void)
+{
+  return FcConfigEnsure () ? FcTrue : FcFalse;
+}
+
+void
+FcConfigFini (void)
+{
+    FcConfig *cfg = fc_atomic_ptr_get (&_fcConfig);
+    if (cfg && fc_atomic_ptr_cmpexch (&_fcConfig, cfg, NULL))
+       FcConfigDestroy (cfg);
+}
+
 
 FcConfig *
 FcConfigCreate (void)
@@ -47,20 +76,19 @@ FcConfigCreate (void)
     config = malloc (sizeof (FcConfig));
     if (!config)
        goto bail0;
-    FcMemAlloc (FC_MEM_CONFIG, sizeof (FcConfig));
-    
+
     config->configDirs = FcStrSetCreate ();
     if (!config->configDirs)
        goto bail1;
-    
+
     config->configFiles = FcStrSetCreate ();
     if (!config->configFiles)
        goto bail2;
-    
+
     config->fontDirs = FcStrSetCreate ();
     if (!config->fontDirs)
        goto bail3;
-    
+
     config->acceptGlobs = FcStrSetCreate ();
     if (!config->acceptGlobs)
        goto bail4;
@@ -72,7 +100,7 @@ FcConfigCreate (void)
     config->acceptPatterns = FcFontSetCreate ();
     if (!config->acceptPatterns)
        goto bail6;
-    
+
     config->rejectPatterns = FcFontSetCreate ();
     if (!config->rejectPatterns)
        goto bail7;
@@ -80,7 +108,7 @@ FcConfigCreate (void)
     config->cacheDirs = FcStrSetCreate ();
     if (!config->cacheDirs)
        goto bail8;
-    
+
     config->blanks = 0;
 
     config->substPattern = 0;
@@ -91,8 +119,14 @@ FcConfigCreate (void)
        config->fonts[set] = 0;
 
     config->rescanTime = time(0);
-    config->rescanInterval = 30;    
-    
+    config->rescanInterval = 30;
+
+    config->expr_pool = NULL;
+
+    config->sysRoot = NULL;
+
+    FcRefInit (&config->ref, 1);
+
     return config;
 
 bail8:
@@ -111,7 +145,6 @@ bail2:
     FcStrSetDestroy (config->configDirs);
 bail1:
     free (config);
-    FcMemFree (FC_MEM_CONFIG, sizeof (FcConfig));
 bail0:
     return 0;
 }
@@ -127,7 +160,7 @@ FcConfigNewestFile (FcStrSet *files)
     if (list)
     {
        while ((file = FcStrListNext (list)))
-           if (stat ((char *) file, &statb) == 0)
+           if (FcStat (file, &statb) == 0)
                if (!newest.set || statb.st_mtime - newest.time > 0)
                {
                    newest.set = FcTrue;
@@ -138,23 +171,10 @@ FcConfigNewestFile (FcStrSet *files)
     return newest;
 }
 
-FcFileTime
-FcConfigModifiedTime (FcConfig *config)
-{
-    if (!config)
-    {
-       FcFileTime v = { 0, FcFalse };
-       config = FcConfigGetCurrent ();
-       if (!config)
-           return v;
-    }
-    return FcConfigNewestFile (config->configFiles);
-}
-
 FcBool
 FcConfigUptoDate (FcConfig *config)
 {
-    FcFileTime config_time, font_time;
+    FcFileTime config_time, config_dir_time, font_time;
     time_t     now = time(0);
     if (!config)
     {
@@ -163,11 +183,24 @@ FcConfigUptoDate (FcConfig *config)
            return FcFalse;
     }
     config_time = FcConfigNewestFile (config->configFiles);
+    config_dir_time = FcConfigNewestFile (config->configDirs);
     font_time = FcConfigNewestFile (config->fontDirs);
     if ((config_time.set && config_time.time - config->rescanTime > 0) ||
+       (config_dir_time.set && (config_dir_time.time - config->rescanTime) > 0) ||
        (font_time.set && (font_time.time - config->rescanTime) > 0))
     {
-       return FcFalse;
+       /* We need to check for potential clock problems here (OLPC ticket #6046) */
+       if ((config_time.set && (config_time.time - now) > 0) ||
+       (config_dir_time.set && (config_dir_time.time - now) > 0) ||
+        (font_time.set && (font_time.time - now) > 0))
+       {
+           fprintf (stderr,
+                    "Fontconfig warning: Directory/file mtime in the future. New fonts may not be detected.\n");
+           config->rescanTime = now;
+           return FcTrue;
+       }
+       else
+           return FcFalse;
     }
     config->rescanTime = now;
     return FcTrue;
@@ -177,27 +210,61 @@ static void
 FcSubstDestroy (FcSubst *s)
 {
     FcSubst *n;
-    
+
     while (s)
     {
        n = s->next;
-       if (s->test)
-           FcTestDestroy (s->test);
-       if (s->edit)
-           FcEditDestroy (s->edit);
+       if (s->rule)
+           FcRuleDestroy (s->rule);
        free (s);
-       FcMemFree (FC_MEM_SUBST, sizeof (FcSubst));
        s = n;
     }
 }
 
+FcExpr *
+FcConfigAllocExpr (FcConfig *config)
+{
+    if (!config->expr_pool || config->expr_pool->next == config->expr_pool->end)
+    {
+       FcExprPage *new_page;
+
+       new_page = malloc (sizeof (FcExprPage));
+       if (!new_page)
+           return 0;
+
+       new_page->next_page = config->expr_pool;
+       new_page->next = new_page->exprs;
+       config->expr_pool = new_page;
+    }
+
+    return config->expr_pool->next++;
+}
+
+FcConfig *
+FcConfigReference (FcConfig *config)
+{
+    if (!config)
+    {
+       config = FcConfigGetCurrent ();
+       if (!config)
+           return 0;
+    }
+
+    FcRefInc (&config->ref);
+
+    return config;
+}
+
 void
 FcConfigDestroy (FcConfig *config)
 {
     FcSetName  set;
+    FcExprPage *page;
 
-    if (config == _fcConfig)
-       _fcConfig = 0;
+    if (FcRefDec (&config->ref) != 1)
+       return;
+
+    (void) fc_atomic_ptr_cmpexch (&_fcConfig, config, NULL);
 
     FcStrSetDestroy (config->configDirs);
     FcStrSetDestroy (config->fontDirs);
@@ -218,8 +285,17 @@ FcConfigDestroy (FcConfig *config)
        if (config->fonts[set])
            FcFontSetDestroy (config->fonts[set]);
 
+    page = config->expr_pool;
+    while (page)
+    {
+      FcExprPage *next = page->next_page;
+      free (page);
+      page = next;
+    }
+    if (config->sysRoot)
+       FcStrFree (config->sysRoot);
+
     free (config);
-    FcMemFree (FC_MEM_CONFIG, sizeof (FcConfig));
 }
 
 /*
@@ -227,7 +303,8 @@ FcConfigDestroy (FcConfig *config)
  */
 
 FcBool
-FcConfigAddCache (FcConfig *config, FcCache *cache)
+FcConfigAddCache (FcConfig *config, FcCache *cache,
+                 FcSetName set, FcStrSet *dirSet)
 {
     FcFontSet  *fs;
     intptr_t   *dirs;
@@ -262,8 +339,8 @@ FcConfigAddCache (FcConfig *config, FcCache *cache)
            if (!FcConfigAcceptFont (config, font))
                continue;
                
-           nref++;
-           FcFontSetAdd (config->fonts[FcSetSystem], font);
+           if (FcFontSetAdd (config->fonts[set], font))
+               nref++;
        }
        FcDirCacheReference (cache, nref);
     }
@@ -278,12 +355,37 @@ FcConfigAddCache (FcConfig *config, FcCache *cache)
        {
            FcChar8     *dir = FcOffsetToPtr (dirs, dirs[i], FcChar8);
            if (FcConfigAcceptFilename (config, dir))
-               FcConfigAddFontDir (config, dir);
+               FcStrSetAddFilename (dirSet, dir);
        }
     }
     return FcTrue;
 }
 
+static FcBool
+FcConfigAddDirList (FcConfig *config, FcSetName set, FcStrSet *dirSet)
+{
+    FcStrList      *dirlist;
+    FcChar8        *dir;
+    FcCache        *cache;
+
+    dirlist = FcStrListCreate (dirSet);
+    if (!dirlist)
+        return FcFalse;
+       
+    while ((dir = FcStrListNext (dirlist)))
+    {
+       if (FcDebug () & FC_DBG_FONTSET)
+           printf ("adding fonts from%s\n", dir);
+       cache = FcDirCacheRead (dir, FcFalse, config);
+       if (!cache)
+           continue;
+       FcConfigAddCache (config, cache, set, dirSet);
+       FcDirCacheUnload (cache);
+    }
+    FcStrListDone (dirlist);
+    return FcTrue;
+}
+
 /*
  * Scan the current list of directories in the configuration
  * and build the set of available fonts.
@@ -293,9 +395,6 @@ FcBool
 FcConfigBuildFonts (FcConfig *config)
 {
     FcFontSet      *fonts;
-    FcStrList      *dirlist;
-    FcChar8        *dir;
-    FcCache        *cache;
 
     if (!config)
     {
@@ -306,55 +405,45 @@ FcConfigBuildFonts (FcConfig *config)
        
     fonts = FcFontSetCreate ();
     if (!fonts)
-       goto bail;
-    
+       return FcFalse;
+
     FcConfigSetFonts (config, fonts, FcSetSystem);
-    
-    dirlist = FcStrListCreate (config->fontDirs);
-    if (!dirlist)
-        goto bail;
-       
-    while ((dir = FcStrListNext (dirlist)))
-    {
-       if (FcDebug () & FC_DBG_FONTSET)
-           printf ("adding fonts from%s\n", dir);
-       cache = FcDirCacheRead (dir, FcFalse, config);
-       if (!cache)
-           continue;
-       FcConfigAddCache (config, cache);
-       FcDirCacheUnload (cache);
-    }
-    
-    FcStrListDone (dirlist);
-    
+
+    if (!FcConfigAddDirList (config, FcSetSystem, config->fontDirs))
+       return FcFalse;
     if (FcDebug () & FC_DBG_FONTSET)
        FcFontSetPrint (fonts);
-
     return FcTrue;
-bail:
-    return FcFalse;
 }
 
 FcBool
 FcConfigSetCurrent (FcConfig *config)
 {
-    if (!config->fonts)
+    FcConfig *cfg;
+
+retry:
+    cfg = fc_atomic_ptr_get (&_fcConfig);
+
+    if (config == cfg)
+       return FcTrue;
+
+    if (config && !config->fonts[FcSetSystem])
        if (!FcConfigBuildFonts (config))
            return FcFalse;
 
-    if (_fcConfig)
-       FcConfigDestroy (_fcConfig);
-    _fcConfig = config;
+    if (!fc_atomic_ptr_cmpexch (&_fcConfig, cfg, config))
+       goto retry;
+
+    if (cfg)
+       FcConfigDestroy (cfg);
+
     return FcTrue;
 }
 
 FcConfig *
 FcConfigGetCurrent (void)
 {
-    if (!_fcConfig)
-       if (!FcInit ())
-           return 0;
-    return _fcConfig;
+    return FcConfigEnsure ();
 }
 
 FcBool
@@ -387,7 +476,7 @@ FcBool
 FcConfigAddDir (FcConfig           *config,
                const FcChar8       *d)
 {
-    return (FcConfigAddConfigDir (config, d) && 
+    return (FcConfigAddConfigDir (config, d) &&
            FcConfigAddFontDir (config, d));
 }
 
@@ -411,7 +500,7 @@ FcConfigAddCacheDir (FcConfig           *config,
 }
 
 FcStrList *
-FcConfigGetCacheDirs (FcConfig *config)
+FcConfigGetCacheDirs (const FcConfig *config)
 {
     if (!config)
     {
@@ -421,17 +510,17 @@ FcConfigGetCacheDirs (FcConfig    *config)
     }
     return FcStrListCreate (config->cacheDirs);
 }
-    
+
 FcBool
 FcConfigAddConfigFile (FcConfig            *config,
                       const FcChar8   *f)
 {
     FcBool     ret;
     FcChar8    *file = FcConfigFilename (f);
-    
+
     if (!file)
        return FcFalse;
-    
+
     ret = FcStrSetAdd (config->configFiles, file);
     FcStrFree (file);
     return ret;
@@ -450,7 +539,7 @@ FcConfigGetConfigFiles (FcConfig    *config)
 }
 
 FcChar8 *
-FcConfigGetCache (FcConfig  *config)
+FcConfigGetCache (FcConfig  *config FC_UNUSED)
 {
     return NULL;
 }
@@ -495,7 +584,7 @@ FcConfigAddBlank (FcConfig  *config,
                  FcChar32      blank)
 {
     FcBlanks   *b, *freeme = 0;
-    
+
     b = config->blanks;
     if (!b)
     {
@@ -514,7 +603,7 @@ FcConfigAddBlank (FcConfig  *config,
 }
 
 int
-FcConfigGetRescanInverval (FcConfig *config)
+FcConfigGetRescanInterval (FcConfig *config)
 {
     if (!config)
     {
@@ -526,7 +615,7 @@ FcConfigGetRescanInverval (FcConfig *config)
 }
 
 FcBool
-FcConfigSetRescanInverval (FcConfig *config, int rescanInterval)
+FcConfigSetRescanInterval (FcConfig *config, int rescanInterval)
 {
     if (!config)
     {
@@ -538,16 +627,32 @@ FcConfigSetRescanInverval (FcConfig *config, int rescanInterval)
     return FcTrue;
 }
 
+/*
+ * A couple of typos escaped into the library
+ */
+int
+FcConfigGetRescanInverval (FcConfig *config)
+{
+    return FcConfigGetRescanInterval (config);
+}
+
 FcBool
-FcConfigAddEdit (FcConfig      *config,
-                FcTest         *test,
-                FcEdit         *edit,
+FcConfigSetRescanInverval (FcConfig *config, int rescanInterval)
+{
+    return FcConfigSetRescanInterval (config, rescanInterval);
+}
+
+FcBool
+FcConfigAddRule (FcConfig      *config,
+                FcRule         *rule,
                 FcMatchKind    kind)
 {
     FcSubst    *subst, **prev;
-    FcTest     *t;
-    int                num;
+    FcRule     *r;
+    int                n = 0;
 
+    if (!rule)
+       return FcFalse;
     switch (kind) {
     case FcMatchPattern:
        prev = &config->substPattern;
@@ -564,21 +669,33 @@ FcConfigAddEdit (FcConfig *config,
     subst = (FcSubst *) malloc (sizeof (FcSubst));
     if (!subst)
        return FcFalse;
-    FcMemAlloc (FC_MEM_SUBST, sizeof (FcSubst));
     for (; *prev; prev = &(*prev)->next);
     *prev = subst;
-    subst->next = 0;
-    subst->test = test;
-    subst->edit = edit;
-    num = 0;
-    for (t = test; t; t = t->next)
-    {
-       if (t->kind == FcMatchDefault)
-           t->kind = kind;
-       num++;
-    }
-    if (config->maxObjects < num)
-       config->maxObjects = num;
+    subst->next = NULL;
+    subst->rule = rule;
+    for (r = rule; r; r = r->next)
+    {
+       switch (r->type)
+       {
+       case FcRuleTest:
+           if (r->u.test &&
+               r->u.test->kind == FcMatchDefault)
+               r->u.test->kind = kind;
+
+           if (n < r->u.test->object)
+               n = r->u.test->object;
+           break;
+       case FcRuleEdit:
+           if (n < r->u.edit->object)
+               n = r->u.edit->object;
+           break;
+       default:
+           break;
+       }
+    }
+    n = FC_OBJ_ID (n) - FC_MAX_BASE_OBJECT;
+    if (config->maxObjects < n)
+       config->maxObjects = n;
     if (FcDebug () & FC_DBG_EDIT)
     {
        printf ("Add Subst ");
@@ -587,13 +704,8 @@ FcConfigAddEdit (FcConfig  *config,
     return FcTrue;
 }
 
-typedef struct _FcSubState {
-    FcPatternElt   *elt;
-    FcValueList    *value;
-} FcSubState;
-
 static FcValue
-FcConfigPromote (FcValue v, FcValue u)
+FcConfigPromote (FcValue v, FcValue u, FcValuePromotionBuffer *buf)
 {
     if (v.type == FcTypeInteger)
     {
@@ -605,9 +717,9 @@ FcConfigPromote (FcValue v, FcValue u)
        v.u.m = &FcIdentityMatrix;
        v.type = FcTypeMatrix;
     }
-    else if (v.type == FcTypeString && u.type == FcTypeLangSet)
+    else if (buf && v.type == FcTypeString && u.type == FcTypeLangSet)
     {
-       v.u.l = FcLangSetPromote (v.u.s);
+       v.u.l = FcLangSetPromote (v.u.s, buf);
        v.type = FcTypeLangSet;
     }
     return v;
@@ -615,22 +727,27 @@ FcConfigPromote (FcValue v, FcValue u)
 
 FcBool
 FcConfigCompareValue (const FcValue    *left_o,
-                     FcOp              op,
+                     unsigned int      op_,
                      const FcValue     *right_o)
 {
     FcValue    left = FcValueCanonicalize(left_o);
     FcValue    right = FcValueCanonicalize(right_o);
     FcBool     ret = FcFalse;
-    
-    left = FcConfigPromote (left, right);
-    right = FcConfigPromote (right, left);
-    if (left.type == right.type) 
+    FcOp       op = FC_OP_GET_OP (op_);
+    int                flags = FC_OP_GET_FLAGS (op_);
+    FcValuePromotionBuffer buf1, buf2;
+
+    left = FcConfigPromote (left, right, &buf1);
+    right = FcConfigPromote (right, left, &buf2);
+    if (left.type == right.type)
     {
        switch (left.type) {
+       case FcTypeUnknown:
+           break;      /* No way to guess how to compare for this object */
        case FcTypeInteger:
            break;      /* FcConfigPromote prevents this from happening */
        case FcTypeDouble:
-           switch (op) {
+           switch ((int) op) {
            case FcOpEqual:
            case FcOpContains:
            case FcOpListing:
@@ -640,16 +757,16 @@ FcConfigCompareValue (const FcValue       *left_o,
            case FcOpNotContains:
                ret = left.u.d != right.u.d;
                break;
-           case FcOpLess:    
+           case FcOpLess:
                ret = left.u.d < right.u.d;
                break;
-           case FcOpLessEqual:    
+           case FcOpLessEqual:
                ret = left.u.d <= right.u.d;
                break;
-           case FcOpMore:    
+           case FcOpMore:
                ret = left.u.d > right.u.d;
                break;
-           case FcOpMoreEqual:    
+           case FcOpMoreEqual:
                ret = left.u.d >= right.u.d;
                break;
            default:
@@ -657,8 +774,8 @@ FcConfigCompareValue (const FcValue *left_o,
            }
            break;
        case FcTypeBool:
-           switch (op) {
-           case FcOpEqual:    
+           switch ((int) op) {
+           case FcOpEqual:
            case FcOpContains:
            case FcOpListing:
                ret = left.u.b == right.u.b;
@@ -672,26 +789,32 @@ FcConfigCompareValue (const FcValue       *left_o,
            }
            break;
        case FcTypeString:
-           switch (op) {
-           case FcOpEqual:    
+           switch ((int) op) {
+           case FcOpEqual:
            case FcOpListing:
-               ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) == 0;
+               if (flags & FcOpFlagIgnoreBlanks)
+                   ret = FcStrCmpIgnoreBlanksAndCase (left.u.s, right.u.s) == 0;
+               else
+                   ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) == 0;
                break;
            case FcOpContains:
                ret = FcStrStrIgnoreCase (left.u.s, right.u.s) != 0;
                break;
            case FcOpNotEqual:
-               ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) != 0;
+               if (flags & FcOpFlagIgnoreBlanks)
+                   ret = FcStrCmpIgnoreBlanksAndCase (left.u.s, right.u.s) != 0;
+               else
+                   ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) != 0;
                break;
            case FcOpNotContains:
-               ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) == 0;
+               ret = FcStrStrIgnoreCase (left.u.s, right.u.s) == 0;
                break;
            default:
                break;
            }
            break;
        case FcTypeMatrix:
-           switch (op) {
+           switch ((int) op) {
            case FcOpEqual:
            case FcOpContains:
            case FcOpListing:
@@ -706,7 +829,7 @@ FcConfigCompareValue (const FcValue *left_o,
            }
            break;
        case FcTypeCharSet:
-           switch (op) {
+           switch ((int) op) {
            case FcOpContains:
            case FcOpListing:
                /* left contains right if right is a subset of left */
@@ -727,7 +850,7 @@ FcConfigCompareValue (const FcValue *left_o,
            }
            break;
        case FcTypeLangSet:
-           switch (op) {
+           switch ((int) op) {
            case FcOpContains:
            case FcOpListing:
                ret = FcLangSetContains (left.u.l, right.u.l);
@@ -746,7 +869,7 @@ FcConfigCompareValue (const FcValue *left_o,
            }
            break;
        case FcTypeVoid:
-           switch (op) {
+           switch ((int) op) {
            case FcOpEqual:
            case FcOpContains:
            case FcOpListing:
@@ -757,7 +880,7 @@ FcConfigCompareValue (const FcValue *left_o,
            }
            break;
        case FcTypeFTFace:
-           switch (op) {
+           switch ((int) op) {
            case FcOpEqual:
            case FcOpContains:
            case FcOpListing:
@@ -790,14 +913,14 @@ FcConfigCompareValue (const FcValue       *left_o,
 #define FcDoubleTrunc(d)       ((d) >= 0 ? _FcDoubleFloor (d) : -_FcDoubleFloor (-(d)))
 
 static FcValue
-FcConfigEvaluate (FcPattern *p, FcExpr *e)
+FcConfigEvaluate (FcPattern *p, FcPattern *p_pat, FcMatchKind kind, FcExpr *e)
 {
     FcValue    v, vl, vr;
-    FcResult   r;
     FcMatrix   *m;
     FcChar8     *str;
-    
-    switch (e->op) {
+    FcOp       op = FC_OP_GET_OP (e->op);
+
+    switch ((int) op) {
     case FcOpInteger:
        v.type = FcTypeInteger;
        v.u.i = e->u.ival;
@@ -808,26 +931,63 @@ FcConfigEvaluate (FcPattern *p, FcExpr *e)
        break;
     case FcOpString:
        v.type = FcTypeString;
-       v.u.s = FcStrStaticName(e->u.sval);
+       v.u.s = e->u.sval;
+       v = FcValueSave (v);
        break;
     case FcOpMatrix:
-       v.type = FcTypeMatrix;
-       v.u.m = e->u.mval;
-       v = FcValueSave (v);
+       {
+         FcMatrix m;
+         FcValue xx, xy, yx, yy;
+         v.type = FcTypeMatrix;
+         xx = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->xx), v, NULL);
+         xy = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->xy), v, NULL);
+         yx = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->yx), v, NULL);
+         yy = FcConfigPromote (FcConfigEvaluate (p, p_pat, kind, e->u.mexpr->yy), v, NULL);
+         if (xx.type == FcTypeDouble && xy.type == FcTypeDouble &&
+             yx.type == FcTypeDouble && yy.type == FcTypeDouble)
+         {
+           m.xx = xx.u.d;
+           m.xy = xy.u.d;
+           m.yx = yx.u.d;
+           m.yy = yy.u.d;
+           v.u.m = &m;
+         }
+         else
+           v.type = FcTypeVoid;
+         v = FcValueSave (v);
+       }
        break;
     case FcOpCharSet:
        v.type = FcTypeCharSet;
        v.u.c = e->u.cval;
        v = FcValueSave (v);
        break;
+    case FcOpLangSet:
+       v.type = FcTypeLangSet;
+       v.u.l = e->u.lval;
+       v = FcValueSave (v);
+       break;
     case FcOpBool:
        v.type = FcTypeBool;
        v.u.b = e->u.bval;
        break;
     case FcOpField:
-       r = FcPatternObjectGet (p, e->u.object, 0, &v);
-       if (r != FcResultMatch)
+       if (kind == FcMatchFont && e->u.name.kind == FcMatchPattern)
+       {
+           if (FcResultMatch != FcPatternObjectGet (p_pat, e->u.name.object, 0, &v))
+               v.type = FcTypeVoid;
+       }
+       else if (kind == FcMatchPattern && e->u.name.kind == FcMatchFont)
+       {
+           fprintf (stderr,
+                    "Fontconfig warning: <name> tag has target=\"font\" in a <match target=\"pattern\">.\n");
            v.type = FcTypeVoid;
+       }
+       else
+       {
+           if (FcResultMatch != FcPatternObjectGet (p, e->u.name.object, 0, &v))
+               v.type = FcTypeVoid;
+       }
        v = FcValueSave (v);
        break;
     case FcOpConst:
@@ -837,13 +997,13 @@ FcConfigEvaluate (FcPattern *p, FcExpr *e)
            v.type = FcTypeVoid;
        break;
     case FcOpQuest:
-       vl = FcConfigEvaluate (p, e->u.tree.left);
+       vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
        if (vl.type == FcTypeBool)
        {
            if (vl.u.b)
-               v = FcConfigEvaluate (p, e->u.tree.right->u.tree.left);
+               v = FcConfigEvaluate (p, p_pat, kind, e->u.tree.right->u.tree.left);
            else
-               v = FcConfigEvaluate (p, e->u.tree.right->u.tree.right);
+               v = FcConfigEvaluate (p, p_pat, kind, e->u.tree.right->u.tree.right);
        }
        else
            v.type = FcTypeVoid;
@@ -858,8 +1018,8 @@ FcConfigEvaluate (FcPattern *p, FcExpr *e)
     case FcOpContains:
     case FcOpNotContains:
     case FcOpListing:
-       vl = FcConfigEvaluate (p, e->u.tree.left);
-       vr = FcConfigEvaluate (p, e->u.tree.right);
+       vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
+       vr = FcConfigEvaluate (p, p_pat, kind, e->u.tree.right);
        v.type = FcTypeBool;
        v.u.b = FcConfigCompareValue (&vl, e->op, &vr);
        FcValueDestroy (vl);
@@ -871,33 +1031,33 @@ FcConfigEvaluate (FcPattern *p, FcExpr *e)
     case FcOpMinus:
     case FcOpTimes:
     case FcOpDivide:
-       vl = FcConfigEvaluate (p, e->u.tree.left);
-       vr = FcConfigEvaluate (p, e->u.tree.right);
-       vl = FcConfigPromote (vl, vr);
-       vr = FcConfigPromote (vr, vl);
+       vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
+       vr = FcConfigEvaluate (p, p_pat, kind, e->u.tree.right);
+       vl = FcConfigPromote (vl, vr, NULL);
+       vr = FcConfigPromote (vr, vl, NULL);
        if (vl.type == vr.type)
        {
-           switch (vl.type) {
+           switch ((int) vl.type) {
            case FcTypeDouble:
-               switch (e->op) {
-               case FcOpPlus:     
+               switch ((int) op) {
+               case FcOpPlus:  
                    v.type = FcTypeDouble;
-                   v.u.d = vl.u.d + vr.u.d; 
+                   v.u.d = vl.u.d + vr.u.d;
                    break;
                case FcOpMinus:
                    v.type = FcTypeDouble;
-                   v.u.d = vl.u.d - vr.u.d; 
+                   v.u.d = vl.u.d - vr.u.d;
                    break;
                case FcOpTimes:
                    v.type = FcTypeDouble;
-                   v.u.d = vl.u.d * vr.u.d; 
+                   v.u.d = vl.u.d * vr.u.d;
                    break;
                case FcOpDivide:
                    v.type = FcTypeDouble;
-                   v.u.d = vl.u.d / vr.u.d; 
+                   v.u.d = vl.u.d / vr.u.d;
                    break;
                default:
-                   v.type = FcTypeVoid; 
+                   v.type = FcTypeVoid;
                    break;
                }
                if (v.type == FcTypeDouble &&
@@ -908,7 +1068,7 @@ FcConfigEvaluate (FcPattern *p, FcExpr *e)
                }
                break;
            case FcTypeBool:
-               switch (e->op) {
+               switch ((int) op) {
                case FcOpOr:
                    v.type = FcTypeBool;
                    v.u.b = vl.u.b || vr.u.b;
@@ -918,18 +1078,18 @@ FcConfigEvaluate (FcPattern *p, FcExpr *e)
                    v.u.b = vl.u.b && vr.u.b;
                    break;
                default:
-                   v.type = FcTypeVoid; 
+                   v.type = FcTypeVoid;
                    break;
                }
                break;
            case FcTypeString:
-               switch (e->op) {
+               switch ((int) op) {
                case FcOpPlus:
                    v.type = FcTypeString;
                    str = FcStrPlus (vl.u.s, vr.u.s);
-                   v.u.s = FcStrStaticName (str);
+                   v.u.s = FcStrdup (str);
                    FcStrFree (str);
-                        
+                       
                    if (!v.u.s)
                        v.type = FcTypeVoid;
                    break;
@@ -939,13 +1099,12 @@ FcConfigEvaluate (FcPattern *p, FcExpr *e)
                }
                break;
            case FcTypeMatrix:
-               switch (e->op) {
+               switch ((int) op) {
                case FcOpTimes:
                    v.type = FcTypeMatrix;
                    m = malloc (sizeof (FcMatrix));
                    if (m)
                    {
-                       FcMemAlloc (FC_MEM_MATRIX, sizeof (FcMatrix));
                        FcMatrixMultiply (m, vl.u.m, vr.u.m);
                        v.u.m = m;
                    }
@@ -959,6 +1118,44 @@ FcConfigEvaluate (FcPattern *p, FcExpr *e)
                    break;
                }
                break;
+           case FcTypeCharSet:
+               switch ((int) op) {
+               case FcOpPlus:
+                   v.type = FcTypeCharSet;
+                   v.u.c = FcCharSetUnion (vl.u.c, vr.u.c);
+                   if (!v.u.c)
+                       v.type = FcTypeVoid;
+                   break;
+               case FcOpMinus:
+                   v.type = FcTypeCharSet;
+                   v.u.c = FcCharSetSubtract (vl.u.c, vr.u.c);
+                   if (!v.u.c)
+                       v.type = FcTypeVoid;
+                   break;
+               default:
+                   v.type = FcTypeVoid;
+                   break;
+               }
+               break;
+           case FcTypeLangSet:
+               switch ((int) op) {
+               case FcOpPlus:
+                   v.type = FcTypeLangSet;
+                   v.u.l = FcLangSetUnion (vl.u.l, vr.u.l);
+                   if (!v.u.l)
+                       v.type = FcTypeVoid;
+                   break;
+               case FcOpMinus:
+                   v.type = FcTypeLangSet;
+                   v.u.l = FcLangSetSubtract (vl.u.l, vr.u.l);
+                   if (!v.u.l)
+                       v.type = FcTypeVoid;
+                   break;
+               default:
+                   v.type = FcTypeVoid;
+                   break;
+               }
+               break;
            default:
                v.type = FcTypeVoid;
                break;
@@ -970,8 +1167,8 @@ FcConfigEvaluate (FcPattern *p, FcExpr *e)
        FcValueDestroy (vr);
        break;
     case FcOpNot:
-       vl = FcConfigEvaluate (p, e->u.tree.left);
-       switch (vl.type) {
+       vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
+       switch ((int) vl.type) {
        case FcTypeBool:
            v.type = FcTypeBool;
            v.u.b = !vl.u.b;
@@ -983,8 +1180,8 @@ FcConfigEvaluate (FcPattern *p, FcExpr *e)
        FcValueDestroy (vl);
        break;
     case FcOpFloor:
-       vl = FcConfigEvaluate (p, e->u.tree.left);
-       switch (vl.type) {
+       vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
+       switch ((int) vl.type) {
        case FcTypeInteger:
            v = vl;
            break;
@@ -999,8 +1196,8 @@ FcConfigEvaluate (FcPattern *p, FcExpr *e)
        FcValueDestroy (vl);
        break;
     case FcOpCeil:
-       vl = FcConfigEvaluate (p, e->u.tree.left);
-       switch (vl.type) {
+       vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
+       switch ((int) vl.type) {
        case FcTypeInteger:
            v = vl;
            break;
@@ -1015,8 +1212,8 @@ FcConfigEvaluate (FcPattern *p, FcExpr *e)
        FcValueDestroy (vl);
        break;
     case FcOpRound:
-       vl = FcConfigEvaluate (p, e->u.tree.left);
-       switch (vl.type) {
+       vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
+       switch ((int) vl.type) {
        case FcTypeInteger:
            v = vl;
            break;
@@ -1031,8 +1228,8 @@ FcConfigEvaluate (FcPattern *p, FcExpr *e)
        FcValueDestroy (vl);
        break;
     case FcOpTrunc:
-       vl = FcConfigEvaluate (p, e->u.tree.left);
-       switch (vl.type) {
+       vl = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
+       switch ((int) vl.type) {
        case FcTypeInteger:
            v = vl;
            break;
@@ -1055,6 +1252,8 @@ FcConfigEvaluate (FcPattern *p, FcExpr *e)
 
 static FcValueList *
 FcConfigMatchValueList (FcPattern      *p,
+                       FcPattern       *p_pat,
+                       FcMatchKind      kind,
                        FcTest          *t,
                        FcValueList     *values)
 {
@@ -1062,18 +1261,18 @@ FcConfigMatchValueList (FcPattern       *p,
     FcExpr         *e = t->expr;
     FcValue        value;
     FcValueList            *v;
-    
+
     while (e)
     {
        /* Compute the value of the match expression */
-       if (e->op == FcOpComma)
+       if (FC_OP_GET_OP (e->op) == FcOpComma)
        {
-           value = FcConfigEvaluate (p, e->u.tree.left);
+           value = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
            e = e->u.tree.right;
        }
        else
        {
-           value = FcConfigEvaluate (p, e);
+           value = FcConfigEvaluate (p, p_pat, kind, e);
            e = 0;
        }
 
@@ -1100,24 +1299,23 @@ FcConfigMatchValueList (FcPattern       *p,
 }
 
 static FcValueList *
-FcConfigValues (FcPattern *p, FcExpr *e, FcValueBinding binding)
+FcConfigValues (FcPattern *p, FcPattern *p_pat, FcMatchKind kind, FcExpr *e, FcValueBinding binding)
 {
     FcValueList        *l;
-    
+
     if (!e)
        return 0;
     l = (FcValueList *) malloc (sizeof (FcValueList));
     if (!l)
        return 0;
-    FcMemAlloc (FC_MEM_VALLIST, sizeof (FcValueList));
-    if (e->op == FcOpComma)
+    if (FC_OP_GET_OP (e->op) == FcOpComma)
     {
-       l->value = FcConfigEvaluate (p, e->u.tree.left);
-       l->next = FcConfigValues (p, e->u.tree.right, binding);
+       l->value = FcConfigEvaluate (p, p_pat, kind, e->u.tree.left);
+       l->next = FcConfigValues (p, p_pat, kind, e->u.tree.right, binding);
     }
     else
     {
-       l->value = FcConfigEvaluate (p, e);
+       l->value = FcConfigEvaluate (p, p_pat, kind, e);
        l->next = NULL;
     }
     l->binding = binding;
@@ -1125,7 +1323,6 @@ FcConfigValues (FcPattern *p, FcExpr *e, FcValueBinding binding)
     {
        FcValueList  *next = FcValueListNext(l);
 
-       FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList));
        free (l);
        l = next;
     }
@@ -1137,11 +1334,33 @@ static FcBool
 FcConfigAdd (FcValueListPtr *head,
             FcValueList    *position,
             FcBool         append,
-            FcValueList    *new)
+            FcValueList    *new,
+            FcObject        object)
 {
-    FcValueListPtr  *prev, last, v;
+    FcValueListPtr  *prev, l, last, v;
     FcValueBinding  sameBinding;
-    
+
+    /*
+     * Make sure the stored type is valid for built-in objects
+     */
+    for (l = new; l != NULL; l = FcValueListNext (l))
+    {
+       if (!FcObjectValidType (object, l->value.type))
+       {
+           fprintf (stderr,
+                    "Fontconfig warning: FcPattern object %s does not accept value", FcObjectName (object));
+           FcValuePrintFile (stderr, l->value);
+           fprintf (stderr, "\n");
+
+           if (FcDebug () & FC_DBG_EDIT)
+           {
+               printf ("Not adding\n");
+           }
+
+           return FcFalse;
+       }
+    }
+
     if (position)
        sameBinding = position->binding;
     else
@@ -1154,7 +1373,7 @@ FcConfigAdd (FcValueListPtr *head,
        if (position)
            prev = &position->next;
        else
-           for (prev = head; *prev != NULL; 
+           for (prev = head; *prev != NULL;
                 prev = &(*prev)->next)
                ;
     }
@@ -1162,7 +1381,7 @@ FcConfigAdd (FcValueListPtr *head,
     {
        if (position)
        {
-           for (prev = head; *prev != NULL; 
+           for (prev = head; *prev != NULL;
                 prev = &(*prev)->next)
            {
                if (*prev == position)
@@ -1182,27 +1401,27 @@ FcConfigAdd (FcValueListPtr *head,
     if (FcDebug () & FC_DBG_EDIT)
     {
        printf ("%s list before ", append ? "Append" : "Prepend");
-       FcValueListPrint (*head);
+       FcValueListPrintWithPosition (*head, *prev);
        printf ("\n");
     }
-    
+
     if (new)
     {
        last = new;
        while (last->next != NULL)
            last = last->next;
-    
+
        last->next = *prev;
        *prev = new;
     }
-    
+
     if (FcDebug () & FC_DBG_EDIT)
     {
        printf ("%s list after ", append ? "Append" : "Prepend");
        FcValueListPrint (*head);
        printf ("\n");
     }
-    
+
     return FcTrue;
 }
 
@@ -1233,10 +1452,10 @@ FcConfigPatternAdd (FcPattern   *p,
     if (list)
     {
        FcPatternElt    *e = FcPatternObjectInsertElt (p, object);
-    
+
        if (!e)
            return;
-       FcConfigAdd (&e->values, 0, append, list);
+       FcConfigAdd (&e->values, 0, append, list, object);
     }
 }
 
@@ -1271,13 +1490,17 @@ FcConfigSubstituteWithPat (FcConfig    *config,
                           FcPattern   *p_pat,
                           FcMatchKind kind)
 {
+    FcValue v;
     FcSubst        *s;
-    FcSubState     *st;
-    int                    i;
-    FcTest         *t;
-    FcEdit         *e;
-    FcValueList            *l;
+    FcRule          *r;
+    FcValueList            *l, **value = NULL, *vl;
     FcPattern      *m;
+    FcStrSet       *strs;
+    FcObject       object = FC_INVALID_OBJECT;
+    FcPatternElt    **elt = NULL, *e;
+    int                    i, nobjs;
+    FcBool         retval = FcTrue;
+    FcTest         **tst = NULL;
 
     if (!config)
     {
@@ -1289,6 +1512,28 @@ FcConfigSubstituteWithPat (FcConfig    *config,
     switch (kind) {
     case FcMatchPattern:
        s = config->substPattern;
+       strs = FcGetDefaultLangs ();
+       if (strs)
+       {
+           FcStrList *l = FcStrListCreate (strs);
+           FcChar8 *lang;
+           FcValue v;
+
+           FcStrSetDestroy (strs);
+           while (l && (lang = FcStrListNext (l)))
+           {
+               v.type = FcTypeString;
+               v.u.s = lang;
+               FcPatternObjectAddWithBinding (p, FC_LANG_OBJECT, v, FcValueBindingWeak, FcTrue);
+           }
+           FcStrListDone (l);
+       }
+       if (FcPatternObjectGet (p, FC_PRGNAME_OBJECT, 0, &v) == FcResultNoMatch)
+       {
+           FcChar8 *prgname = FcGetPrgname ();
+           if (prgname)
+               FcPatternObjectAddString (p, FC_PRGNAME_OBJECT, prgname);
+       }
        break;
     case FcMatchFont:
        s = config->substFont;
@@ -1300,10 +1545,25 @@ FcConfigSubstituteWithPat (FcConfig    *config,
        return FcFalse;
     }
 
-    st = (FcSubState *) malloc (config->maxObjects * sizeof (FcSubState));
-    if (!st && config->maxObjects)
-       return FcFalse;
-    FcMemAlloc (FC_MEM_SUBSTATE, config->maxObjects * sizeof (FcSubState));
+    nobjs = FC_MAX_BASE_OBJECT + config->maxObjects + 2;
+    value = (FcValueList **) malloc (SIZEOF_VOID_P * nobjs);
+    if (!value)
+    {
+       retval = FcFalse;
+       goto bail1;
+    }
+    elt = (FcPatternElt **) malloc (SIZEOF_VOID_P * nobjs);
+    if (!elt)
+    {
+       retval = FcFalse;
+       goto bail1;
+    }
+    tst = (FcTest **) malloc (SIZEOF_VOID_P * nobjs);
+    if (!tst)
+    {
+       retval = FcFalse;
+       goto bail1;
+    }
 
     if (FcDebug () & FC_DBG_EDIT)
     {
@@ -1312,191 +1572,199 @@ FcConfigSubstituteWithPat (FcConfig    *config,
     }
     for (; s; s = s->next)
     {
-       /*
-        * Check the tests to see if
-        * they all match the pattern
-        */
-       for (t = s->test, i = 0; t; t = t->next, i++)
+       r = s->rule;
+       for (i = 0; i < nobjs; i++)
        {
-           if (FcDebug () & FC_DBG_EDIT)
-           {
-               printf ("FcConfigSubstitute test ");
-               FcTestPrint (t);
-           }
-           st[i].elt = 0;
-           if (kind == FcMatchFont && t->kind == FcMatchPattern)
-               m = p_pat;
-           else
-               m = p;
-           if (m)
-               st[i].elt = FcPatternObjectFindElt (m, t->object);
-           else
-               st[i].elt = 0;
-           /*
-            * If there's no such field in the font,
-            * then FcQualAll matches while FcQualAny does not
-            */
-           if (!st[i].elt)
-           {
-               if (t->qual == FcQualAll)
+           elt[i] = NULL;
+           value[i] = NULL;
+           tst[i] = NULL;
+       }
+       for (; r; r = r->next)
+       {
+           switch (r->type) {
+           case FcRuleUnknown:
+               /* shouldn't be reached */
+               break;
+           case FcRuleTest:
+               object = FC_OBJ_ID (r->u.test->object);
+               /*
+                * Check the tests to see if
+                * they all match the pattern
+                */
+               if (FcDebug () & FC_DBG_EDIT)
                {
-                   st[i].value = 0;
-                   continue;
+                   printf ("FcConfigSubstitute test ");
+                   FcTestPrint (r->u.test);
                }
+               if (kind == FcMatchFont && r->u.test->kind == FcMatchPattern)
+                   m = p_pat;
                else
-                   break;
-           }
-           /*
-            * Check to see if there is a match, mark the location
-            * to apply match-relative edits
-            */
-           st[i].value = FcConfigMatchValueList (m, t, st[i].elt->values);
-           if (!st[i].value)
-               break;
-           if (t->qual == FcQualFirst && st[i].value != st[i].elt->values)
-               break;
-           if (t->qual == FcQualNotFirst && st[i].value == st[i].elt->values)
-               break;
-       }
-       if (t)
-       {
-           if (FcDebug () & FC_DBG_EDIT)
-               printf ("No match\n");
-           continue;
-       }
-       if (FcDebug () & FC_DBG_EDIT)
-       {
-           printf ("Substitute ");
-           FcSubstPrint (s);
-       }
-       for (e = s->edit; e; e = e->next)
-       {
-           /*
-            * Evaluate the list of expressions
-            */
-           l = FcConfigValues (p, e->expr, e->binding);
-           /*
-            * Locate any test associated with this field, skipping
-            * tests associated with the pattern when substituting in
-            * the font
-            */
-           for (t = s->test, i = 0; t; t = t->next, i++)
-           {
-               if ((t->kind == FcMatchFont || kind == FcMatchPattern) &&
-                   t->object == e->object)
+                   m = p;
+               if (m)
+                   e = FcPatternObjectFindElt (m, r->u.test->object);
+               else
+                   e = NULL;
+               /* different 'kind' won't be the target of edit */
+               if (!elt[object] && kind == r->u.test->kind)
                {
-                   /* 
-                    * KLUDGE - the pattern may have been reallocated or
-                    * things may have been inserted or deleted above
-                    * this element by other edits.  Go back and find
-                    * the element again
-                    */
-                   if (e != s->edit && st[i].elt)
-                       st[i].elt = FcPatternObjectFindElt (p, t->object);
-                   if (!st[i].elt)
-                       t = 0;
-                   break;
+                   elt[object] = e;
+                   tst[object] = r->u.test;
+               }
+               /*
+                * If there's no such field in the font,
+                * then FcQualAll matches while FcQualAny does not
+                */
+               if (!e)
+               {
+                   if (r->u.test->qual == FcQualAll)
+                   {
+                       value[object] = NULL;
+                       continue;
+                   }
+                   else
+                   {
+                       if (FcDebug () & FC_DBG_EDIT)
+                           printf ("No match\n");
+                       goto bail;
+                   }
                }
-           }
-           switch (e->op) {
-           case FcOpAssign:
                /*
-                * If there was a test, then replace the matched
-                * value with the new list of values
+                * Check to see if there is a match, mark the location
+                * to apply match-relative edits
                 */
-               if (t)
+               vl = FcConfigMatchValueList (m, p_pat, kind, r->u.test, e->values);
+               /* different 'kind' won't be the target of edit */
+               if (!value[object] && kind == r->u.test->kind)
+                   value[object] = vl;
+               if (!vl ||
+                   (r->u.test->qual == FcQualFirst && vl != e->values) ||
+                   (r->u.test->qual == FcQualNotFirst && vl == e->values))
                {
-                   FcValueList *thisValue = st[i].value;
-                   FcValueList *nextValue = thisValue;
-                   
+                   if (FcDebug () & FC_DBG_EDIT)
+                       printf ("No match\n");
+                   goto bail;
+               }
+               break;
+           case FcRuleEdit:
+               object = FC_OBJ_ID (r->u.edit->object);
+               if (FcDebug () & FC_DBG_EDIT)
+               {
+                   printf ("Substitute ");
+                   FcEditPrint (r->u.edit);
+                   printf ("\n\n");
+               }
+               /*
+                * Evaluate the list of expressions
+                */
+               l = FcConfigValues (p, p_pat,kind,  r->u.edit->expr, r->u.edit->binding);
+               if (tst[object] && (tst[object]->kind == FcMatchFont || kind == FcMatchPattern))
+                   elt[object] = FcPatternObjectFindElt (p, tst[object]->object);
+
+               switch (FC_OP_GET_OP (r->u.edit->op)) {
+               case FcOpAssign:
                    /*
-                    * Append the new list of values after the current value
+                    * If there was a test, then replace the matched
+                    * value with the new list of values
                     */
-                   FcConfigAdd (&st[i].elt->values, thisValue, FcTrue, l);
+                   if (value[object])
+                   {
+                       FcValueList     *thisValue = value[object];
+                       FcValueList     *nextValue = l;
+
+                       /*
+                        * Append the new list of values after the current value
+                        */
+                       FcConfigAdd (&elt[object]->values, thisValue, FcTrue, l, r->u.edit->object);
+                       /*
+                        * Delete the marked value
+                        */
+                       if (thisValue)
+                           FcConfigDel (&elt[object]->values, thisValue);
+                       /*
+                        * Adjust a pointer into the value list to ensure
+                        * future edits occur at the same place
+                        */
+                       value[object] = nextValue;
+                       break;
+                   }
+                   /* fall through ... */
+               case FcOpAssignReplace:
                    /*
-                    * Delete the marked value
+                    * Delete all of the values and insert
+                    * the new set
                     */
-                    if (thisValue)
-                       FcConfigDel (&st[i].elt->values, thisValue);
+                   FcConfigPatternDel (p, r->u.edit->object);
+                   FcConfigPatternAdd (p, r->u.edit->object, l, FcTrue);
                    /*
-                    * Adjust any pointers into the value list to ensure
-                    * future edits occur at the same place
+                    * Adjust a pointer into the value list as they no
+                    * longer point to anything valid
                     */
-                   for (t = s->test, i = 0; t; t = t->next, i++)
+                   value[object] = NULL;
+                   break;
+               case FcOpPrepend:
+                   if (value[object])
                    {
-                       if (st[i].value == thisValue)
-                           st[i].value = nextValue;
+                       FcConfigAdd (&elt[object]->values, value[object], FcFalse, l, r->u.edit->object);
+                       break;
                    }
+                   /* fall through ... */
+               case FcOpPrependFirst:
+                   FcConfigPatternAdd (p, r->u.edit->object, l, FcFalse);
                    break;
-               }
-               /* fall through ... */
-           case FcOpAssignReplace:
-               /*
-                * Delete all of the values and insert
-                * the new set
-                */
-               FcConfigPatternDel (p, e->object);
-               FcConfigPatternAdd (p, e->object, l, FcTrue);
-               /*
-                * Adjust any pointers into the value list as they no
-                * longer point to anything valid
-                */
-               if (t)
-               {
-                   FcPatternElt    *thisElt = st[i].elt;
-                   for (t = s->test, i = 0; t; t = t->next, i++)
+               case FcOpAppend:
+                   if (value[object])
                    {
-                       if (st[i].elt == thisElt)
-                           st[i].value = 0;
+                       FcConfigAdd (&elt[object]->values, value[object], FcTrue, l, r->u.edit->object);
+                       break;
                    }
-               }
-               break;
-           case FcOpPrepend:
-               if (t)
-               {
-                   FcConfigAdd (&st[i].elt->values, st[i].value, FcFalse, l);
+                   /* fall through ... */
+               case FcOpAppendLast:
+                   FcConfigPatternAdd (p, r->u.edit->object, l, FcTrue);
+                   break;
+               case FcOpDelete:
+                   if (value[object])
+                   {
+                       FcConfigDel (&elt[object]->values, value[object]);
+                       break;
+                   }
+                   /* fall through ... */
+               case FcOpDeleteAll:
+                   FcConfigPatternDel (p, r->u.edit->object);
+                   break;
+               default:
+                   FcValueListDestroy (l);
                    break;
                }
-               /* fall through ... */
-           case FcOpPrependFirst:
-               FcConfigPatternAdd (p, e->object, l, FcFalse);
-               break;
-           case FcOpAppend:
-               if (t)
+               /*
+                * Now go through the pattern and eliminate
+                * any properties without data
+                */
+               FcConfigPatternCanon (p, r->u.edit->object);
+
+               if (FcDebug () & FC_DBG_EDIT)
                {
-                   FcConfigAdd (&st[i].elt->values, st[i].value, FcTrue, l);
-                   break;
+                   printf ("FcConfigSubstitute edit");
+                   FcPatternPrint (p);
                }
-               /* fall through ... */
-           case FcOpAppendLast:
-               FcConfigPatternAdd (p, e->object, l, FcTrue);
-               break;
-           default:
-                FcValueListDestroy (l);
                break;
            }
        }
-       /*
-        * Now go through the pattern and eliminate
-        * any properties without data
-        */
-       for (e = s->edit; e; e = e->next)
-           FcConfigPatternCanon (p, e->object);
-
-       if (FcDebug () & FC_DBG_EDIT)
-       {
-           printf ("FcConfigSubstitute edit");
-           FcPatternPrint (p);
-       }
+    bail:;
     }
-    FcMemFree (FC_MEM_SUBSTATE, config->maxObjects * sizeof (FcSubState));
-    free (st);
     if (FcDebug () & FC_DBG_EDIT)
     {
        printf ("FcConfigSubstitute done");
        FcPatternPrint (p);
     }
-    return FcTrue;
+bail1:
+    if (elt)
+       free (elt);
+    if (value)
+       free (value);
+    if (tst)
+       free (tst);
+
+    return retval;
 }
 
 FcBool
@@ -1507,9 +1775,16 @@ FcConfigSubstitute (FcConfig     *config,
     return FcConfigSubstituteWithPat (config, p, 0, kind);
 }
 
-#if defined (_WIN32) && (defined (PIC) || defined (DLL_EXPORT))
+#if defined (_WIN32)
+
+static FcChar8 fontconfig_path[1000] = ""; /* MT-dontcare */
 
-static FcChar8 fontconfig_path[1000] = "";
+#  if (defined (PIC) || defined (DLL_EXPORT))
+
+BOOL WINAPI
+DllMain (HINSTANCE hinstDLL,
+        DWORD     fdwReason,
+        LPVOID    lpvReserved);
 
 BOOL WINAPI
 DllMain (HINSTANCE hinstDLL,
@@ -1520,7 +1795,7 @@ DllMain (HINSTANCE hinstDLL,
 
   switch (fdwReason) {
   case DLL_PROCESS_ATTACH:
-      if (!GetModuleFileName ((HMODULE) hinstDLL, fontconfig_path,
+      if (!GetModuleFileName ((HMODULE) hinstDLL, (LPCH) fontconfig_path,
                              sizeof (fontconfig_path)))
          break;
 
@@ -1529,31 +1804,31 @@ DllMain (HINSTANCE hinstDLL,
        * "etc/fonts" in there as FONTCONFIG_PATH. Otherwise use the
        * folder where the DLL is as FONTCONFIG_PATH.
        */
-      p = strrchr (fontconfig_path, '\\');
+      p = (FcChar8 *) strrchr ((const char *) fontconfig_path, '\\');
       if (p)
       {
          *p = '\0';
-         p = strrchr (fontconfig_path, '\\');
-         if (p && (FcStrCmpIgnoreCase (p + 1, "bin") == 0 ||
-                   FcStrCmpIgnoreCase (p + 1, "lib") == 0))
+         p = (FcChar8 *) strrchr ((const char *) fontconfig_path, '\\');
+         if (p && (FcStrCmpIgnoreCase (p + 1, (const FcChar8 *) "bin") == 0 ||
+                   FcStrCmpIgnoreCase (p + 1, (const FcChar8 *) "lib") == 0))
              *p = '\0';
-         strcat (fontconfig_path, "\\etc\\fonts");
+         strcat ((char *) fontconfig_path, "\\etc\\fonts");
       }
       else
           fontconfig_path[0] = '\0';
-      
+
       break;
   }
 
   return TRUE;
 }
 
+#  endif /* !PIC */
+
 #undef FONTCONFIG_PATH
 #define FONTCONFIG_PATH fontconfig_path
 
-#else /* !(_WIN32 && PIC) */
-
-#endif /* !(_WIN32 && PIC) */
+#endif /* !_WIN32 */
 
 #ifndef FONTCONFIG_FILE
 #define FONTCONFIG_FILE        "fonts.conf"
@@ -1563,10 +1838,19 @@ static FcChar8 *
 FcConfigFileExists (const FcChar8 *dir, const FcChar8 *file)
 {
     FcChar8    *path;
+    int         size, osize;
 
     if (!dir)
        dir = (FcChar8 *) "";
-    path = malloc (strlen ((char *) dir) + 1 + strlen ((char *) file) + 1);
+
+    osize = strlen ((char *) dir) + 1 + strlen ((char *) file) + 1;
+    /*
+     * workaround valgrind warning because glibc takes advantage of how it knows memory is
+     * allocated to implement strlen by reading in groups of 4
+     */
+    size = (osize + 3) & ~3;
+
+    path = malloc (size);
     if (!path)
        return 0;
 
@@ -1582,14 +1866,16 @@ FcConfigFileExists (const FcChar8 *dir, const FcChar8 *file)
 #else
     if ((!path[0] || path[strlen((char *) path)-1] != '/') && file[0] != '/')
        strcat ((char *) path, "/");
+    else
+       osize--;
 #endif
     strcat ((char *) path, (char *) file);
 
-    FcMemAlloc (FC_MEM_STRING, strlen ((char *) path) + 1);
     if (access ((char *) path, R_OK) == 0)
        return path;
-    
+
     FcStrFree (path);
+
     return 0;
 }
 
@@ -1620,7 +1906,7 @@ FcConfigGetPath (void)
     if (env)
     {
        e = env;
-       while (*e) 
+       while (*e)
        {
            colon = (FcChar8 *) strchr ((char *) e, FC_SEARCH_PATH_SEPARATOR);
            if (!colon)
@@ -1637,7 +1923,18 @@ FcConfigGetPath (void)
            i++;
        }
     }
-    
+
+#ifdef _WIN32
+       if (fontconfig_path[0] == '\0')
+       {
+               char *p;
+               if(!GetModuleFileName(NULL, (LPCH) fontconfig_path, sizeof(fontconfig_path)))
+                       goto bail1;
+               p = strrchr ((const char *) fontconfig_path, '\\');
+               if (p) *p = '\0';
+               strcat ((char *) fontconfig_path, "\\fonts");
+       }
+#endif
     dir = (FcChar8 *) FONTCONFIG_PATH;
     path[i] = malloc (strlen ((char *) dir) + 1);
     if (!path[i])
@@ -1663,7 +1960,7 @@ FcConfigFreePath (FcChar8 **path)
     free (path);
 }
 
-static FcBool  _FcConfigHomeEnabled = FcTrue;
+static FcBool  _FcConfigHomeEnabled = FcTrue; /* MT-goodenough */
 
 FcChar8 *
 FcConfigHome (void)
@@ -1682,6 +1979,81 @@ FcConfigHome (void)
     return 0;
 }
 
+FcChar8 *
+FcConfigXdgCacheHome (void)
+{
+    const char *env = getenv ("XDG_CACHE_HOME");
+    FcChar8 *ret = NULL;
+
+    if (env)
+       ret = FcStrCopy ((const FcChar8 *)env);
+    else
+    {
+       const FcChar8 *home = FcConfigHome ();
+       size_t len = home ? strlen ((const char *)home) : 0;
+
+       ret = malloc (len + 7 + 1);
+       if (ret)
+       {
+           memcpy (ret, home, len);
+           memcpy (&ret[len], FC_DIR_SEPARATOR_S ".cache", 7);
+           ret[len + 7] = 0;
+       }
+    }
+
+    return ret;
+}
+
+FcChar8 *
+FcConfigXdgConfigHome (void)
+{
+    const char *env = getenv ("XDG_CONFIG_HOME");
+    FcChar8 *ret = NULL;
+
+    if (env)
+       ret = FcStrCopy ((const FcChar8 *)env);
+    else
+    {
+       const FcChar8 *home = FcConfigHome ();
+       size_t len = home ? strlen ((const char *)home) : 0;
+
+       ret = malloc (len + 8 + 1);
+       if (ret)
+       {
+           memcpy (ret, home, len);
+           memcpy (&ret[len], FC_DIR_SEPARATOR_S ".config", 8);
+           ret[len + 8] = 0;
+       }
+    }
+
+    return ret;
+}
+
+FcChar8 *
+FcConfigXdgDataHome (void)
+{
+    const char *env = getenv ("XDG_DATA_HOME");
+    FcChar8 *ret = NULL;
+
+    if (env)
+       ret = FcStrCopy ((const FcChar8 *)env);
+    else
+    {
+       const FcChar8 *home = FcConfigHome ();
+       size_t len = home ? strlen ((const char *)home) : 0;
+
+       ret = malloc (len + 13 + 1);
+       if (ret)
+       {
+           memcpy (ret, home, len);
+           memcpy (&ret[len], FC_DIR_SEPARATOR_S ".local" FC_DIR_SEPARATOR_S "share", 13);
+           ret[len + 13] = 0;
+       }
+    }
+
+    return ret;
+}
+
 FcBool
 FcConfigEnableHome (FcBool enable)
 {
@@ -1694,7 +2066,7 @@ FcChar8 *
 FcConfigFilename (const FcChar8 *url)
 {
     FcChar8    *file, *dir, **path, **p;
-    
+
     if (!url || !*url)
     {
        url = (FcChar8 *) getenv ("FONTCONFIG_FILE");
@@ -1728,7 +2100,7 @@ FcConfigFilename (const FcChar8 *url)
     default:
        path = FcConfigGetPath ();
        if (!path)
-           return 0;
+           return NULL;
        for (p = path; *p; p++)
        {
            file = FcConfigFileExists (*p, url);
@@ -1738,6 +2110,7 @@ FcConfigFilename (const FcChar8 *url)
        FcConfigFreePath (path);
        break;
     }
+
     return file;
 }
 
@@ -1764,7 +2137,7 @@ FcConfigAppFontAddFile (FcConfig    *config,
     subdirs = FcStrSetCreate ();
     if (!subdirs)
        return FcFalse;
-    
+
     set = FcConfigGetFonts (config, FcSetApplication);
     if (!set)
     {
@@ -1799,46 +2172,39 @@ FcConfigAppFontAddDir (FcConfig     *config,
                       const FcChar8   *dir)
 {
     FcFontSet  *set;
-    FcStrSet   *subdirs;
-    FcStrList  *sublist;
-    FcChar8    *subdir;
-    
+    FcStrSet   *dirs;
+
     if (!config)
     {
        config = FcConfigGetCurrent ();
        if (!config)
            return FcFalse;
     }
-    subdirs = FcStrSetCreate ();
-    if (!subdirs)
+
+    dirs = FcStrSetCreate ();
+    if (!dirs)
        return FcFalse;
-    
+
     set = FcConfigGetFonts (config, FcSetApplication);
     if (!set)
     {
        set = FcFontSetCreate ();
        if (!set)
        {
-           FcStrSetDestroy (subdirs);
+           FcStrSetDestroy (dirs);
            return FcFalse;
        }
        FcConfigSetFonts (config, set, FcSetApplication);
     }
-    
-    if (!FcDirScanConfig (set, subdirs, config->blanks, dir, FcFalse, config))
+
+    FcStrSetAddFilename (dirs, dir);
+
+    if (!FcConfigAddDirList (config, FcSetApplication, dirs))
     {
-       FcStrSetDestroy (subdirs);
+       FcStrSetDestroy (dirs);
        return FcFalse;
     }
-    if ((sublist = FcStrListCreate (subdirs)))
-    {
-       while ((subdir = FcStrListNext (sublist)))
-       {
-           FcConfigAppFontAddDir (config, subdir);
-       }
-       FcStrListDone (sublist);
-    }
-    FcStrSetDestroy (subdirs);
+    FcStrSetDestroy (dirs);
     return FcTrue;
 }
 
@@ -1870,49 +2236,13 @@ FcConfigGlobAdd (FcConfig       *config,
 }
 
 static FcBool
-FcConfigGlobMatch (const FcChar8    *glob,
-                  const FcChar8    *string)
-{
-    FcChar8    c;
-
-    while ((c = *glob++)) 
-    {
-       switch (c) {
-       case '*':
-           /* short circuit common case */
-           if (!*glob)
-               return FcTrue;
-           /* short circuit another common case */
-           if (strchr ((char *) glob, '*') == 0)
-               string += strlen ((char *) string) - strlen ((char *) glob);
-           while (*string)
-           {
-               if (FcConfigGlobMatch (glob, string))
-                   return FcTrue;
-               string++;
-           }
-           return FcFalse;
-       case '?':
-           if (*string++ == '\0')
-               return FcFalse;
-           break;
-       default:
-           if (*string++ != c)
-               return FcFalse;
-           break;
-       }
-    }
-    return *string == '\0';
-}
-
-static FcBool
 FcConfigGlobsMatch (const FcStrSet     *globs,
                    const FcChar8       *string)
 {
     int        i;
 
     for (i = 0; i < globs->num; i++)
-       if (FcConfigGlobMatch (globs->strs[i], string))
+       if (FcStrGlobMatch (globs->strs[i], string))
            return FcTrue;
     return FcFalse;
 }
@@ -1947,7 +2277,7 @@ FcConfigPatternsMatch (const FcFontSet    *patterns,
                       const FcPattern  *font)
 {
     int i;
-    
+
     for (i = 0; i < patterns->nfont; i++)
        if (FcListPatternMatchAny (patterns->fonts[i], font))
            return FcTrue;
@@ -1964,6 +2294,59 @@ FcConfigAcceptFont (FcConfig         *config,
        return FcFalse;
     return FcTrue;
 }
+
+const FcChar8 *
+FcConfigGetSysRoot (const FcConfig *config)
+{
+    if (!config)
+    {
+       config = FcConfigGetCurrent ();
+       if (!config)
+           return NULL;
+    }
+
+    return config->sysRoot;
+}
+
+void
+FcConfigSetSysRoot (FcConfig      *config,
+                   const FcChar8 *sysroot)
+{
+    FcChar8 *s;
+    FcBool init = FcFalse;
+
+    if (!config)
+    {
+       /* We can't use FcConfigGetCurrent() here to ensure
+        * the sysroot is set prior to initialize FcConfig,
+        * to avoid loading caches from non-sysroot dirs.
+        * So postpone the initialization later.
+        */
+       config = fc_atomic_ptr_get (&_fcConfig);
+       if (!config)
+       {
+           config = FcConfigCreate ();
+           if (!config)
+               return;
+           init = FcTrue;
+       }
+    }
+
+    s = FcStrCopyFilename (sysroot);
+    if (!s)
+       return;
+
+    if (config->sysRoot)
+       FcStrFree (config->sysRoot);
+
+    config->sysRoot = s;
+    if (init)
+    {
+       config = FcInitLoadOwnConfigAndFonts (config);
+       FcConfigSetCurrent (config);
+    }
+}
+
 #define __fccfg__
 #include "fcaliastail.h"
 #undef __fccfg__