[packages/fontconfig] - rel 3; fixes from git

arekm arekm at pld-linux.org
Wed Aug 21 15:24:54 CEST 2013


commit 3ea8a859aeff0dc6f78d475066d50f1fbc9b2816
Author: Arkadiusz Miśkiewicz <arekm at maven.pl>
Date:   Wed Aug 21 15:24:50 2013 +0200

    - rel 3; fixes from git

 fontconfig-git.patch | 1706 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 1706 insertions(+)
---
diff --git a/fontconfig-git.patch b/fontconfig-git.patch
new file mode 100644
index 0000000..bb74d18
--- /dev/null
+++ b/fontconfig-git.patch
@@ -0,0 +1,1706 @@
+diff --git a/conf.d/30-metric-aliases.conf b/conf.d/30-metric-aliases.conf
+index f25052a..0fd0b8a 100644
+--- a/conf.d/30-metric-aliases.conf
++++ b/conf.d/30-metric-aliases.conf
+@@ -230,6 +230,7 @@
+ 	<alias binding="same">
+ 	  <family>Helvetica</family>
+ 	  <accept>
++	  <family>TeX Gyre Heros</family>
+ 	  <family>Nimbus Sans L</family>
+ 	  </accept>
+ 	</alias>
+@@ -237,6 +238,7 @@
+ 	<alias binding="same">
+ 	  <family>Times</family>
+ 	  <accept>
++	  <family>TeX Gyre Termes</family>
+ 	  <family>Nimbus Roman No9 L</family>
+ 	  </accept>
+ 	</alias>
+@@ -253,6 +255,7 @@
+ 	<alias binding="same">
+ 	  <family>Arial</family>
+ 	  <accept>
++	    <family>TeX Gyre Heros</family>
+ 	    <family>Arimo</family>
+ 	    <family>Liberation Sans</family>
+ 	    <family>Albany</family>
+@@ -270,6 +273,7 @@
+ 	<alias binding="same">
+ 	  <family>Times New Roman</family>
+ 	  <accept>
++	    <family>TeX Gyre Termes</family>
+ 	    <family>Tinos</family>
+ 	    <family>Liberation Serif</family>
+ 	    <family>Thorndale</family>
+@@ -278,6 +282,13 @@
+ 	</alias>
+ 
+ 	<alias binding="same">
++	  <family>Georgia</family>
++	  <accept>
++	    <family>Gelasio</family>
++	  </accept>
++	</alias>
++
++	<alias binding="same">
+ 	  <family>Courier New</family>
+ 	  <accept>
+ 	    <family>Cousine</family>
+diff --git a/conf.d/45-latin.conf b/conf.d/45-latin.conf
+index 09fd526..aa62ed4 100644
+--- a/conf.d/45-latin.conf
++++ b/conf.d/45-latin.conf
+@@ -45,6 +45,22 @@
+ 		<family>Thorndale</family>
+ 		<default><family>serif</family></default>
+ 	</alias>
++	<alias>
++		<family>Georgia</family>
++		<default><family>serif</family></default>
++	</alias>
++	<alias>
++		<family>Garamond</family>
++		<default><family>serif</family></default>
++	</alias>
++	<alias>
++		<family>Palatino Linotype</family>
++		<default><family>serif</family></default>
++	</alias>
++	<alias>
++		<family>Trebuchet MS</family>
++		<default><family>serif</family></default>
++	</alias>
+ <!--
+   Sans-serif faces
+  -->
+diff --git a/configure.ac b/configure.ac
+index 0f129db..321fece 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -54,6 +54,9 @@ AC_SUBST(LIBT_VERSION_INFO)
+ LIBT_CURRENT_MINUS_AGE=`expr $LIBT_CURRENT - $LIBT_AGE`
+ AC_SUBST(LIBT_CURRENT_MINUS_AGE)
+ 
++PKGCONFIG_REQUIRES=
++PKGCONFIG_REQUIRES_PRIVATELY=
++
+ dnl ==========================================================================
+ 
+ AC_CONFIG_HEADERS(config.h)
+@@ -161,6 +164,37 @@ AC_LINK_IFELSE([AC_LANG_SOURCE([[
+ 		AC_MSG_RESULT([yes])
+ 		AC_DEFINE([HAVE_POSIX_FADVISE], [1], [Define to 1 if you have the 'posix_fadvise' function.])
+ 	],[AC_MSG_RESULT([no])])
++if test "$os_win32" = "no"; then
++	AC_MSG_CHECKING([for scandir])
++	AC_LINK_IFELSE([AC_LANG_SOURCE([[
++		#include <dirent.h>
++		int comp(const struct dirent **, const struct dirent **);
++		int comp(const struct dirent **a, const struct dirent **b) { return 0; }
++		int main(void) {
++		    struct dirent **d;
++		    return scandir(".", &d, 0, &comp) >= 0;
++		}
++		]])],[
++			AC_MSG_RESULT([yes])
++			AC_DEFINE([HAVE_SCANDIR], [1], [Define to 1 if you have the 'scandir' function.])
++		],[
++			AC_LINK_IFELSE([AC_LANG_SOURCE([[
++				#include <dirent.h>
++				int comp(const void *, const void *);
++				int comp(const void *a, const void *b) { return 0; }
++				int main(void) {
++				    struct dirent **d;
++				    return scandir(".", &d, 0, &comp) >= 0;
++				}
++			]])],[
++				AC_MSG_RESULT([yes])
++				AC_DEFINE([HAVE_SCANDIR_VOID_P], [1], [Define to 1 if you have the 'scandir' function with int (* compar)(const void *, const void *)])
++			],[
++				AC_MSG_ERROR([
++*** No scandir function available.])
++			])
++		])
++fi
+ CFLAGS="$fc_saved_CFLAGS"
+ 
+ #
+@@ -251,13 +285,14 @@ if test "x$enable_iconv" != "xno"; then
+ 		AC_TRY_LINK([#include <iconv.h>],
+ 			[iconv_open ("from", "to");],
+ 			[iconv_type="libiconv"
+-			 use_iconv=1],
++			 use_iconv=1
++			 ICONV_CFLAGS="$libiconv_cflags"
++			 ICONV_LIBS="$libiconv_libs"
++			 ],
+ 			[use_iconv=0])
+ 
+ 		CFLAGS="$iconvsaved_CFLAGS"
+ 		LIBS="$iconvsaved_LIBS"
+-		ICONV_CFLAGS="$libiconv_cflags"
+-		ICONV_LIBS="$libiconv_libs"
+ 	fi
+ 	if test "x$use_iconv" = "x0"; then
+ 		AC_TRY_LINK([#include <iconv.h>],
+@@ -277,6 +312,7 @@ AC_DEFINE_UNQUOTED(USE_ICONV,$use_iconv,[Use iconv.])
+ # Checks for FreeType
+ #
+ PKG_CHECK_MODULES(FREETYPE, freetype2)
++PKGCONFIG_REQUIRES="$PKGCONFIG_REQUIRES freetype2"
+ 
+ AC_SUBST(FREETYPE_LIBS)
+ AC_SUBST(FREETYPE_CFLAGS)
+@@ -336,6 +372,8 @@ if test "$enable_libxml2" != "yes"; then
+ 		else
+ 			EXPAT_LIBS="-lexpat"
+ 		fi
++	else
++		PKGCONFIG_REQUIRES_PRIVATELY="$PKGCONFIG_REQUIRES_PRIVATELY expat"
+ 	fi
+ 
+ 	expatsaved_CPPFLAGS="$CPPFLAGS"
+@@ -377,6 +415,7 @@ AC_ARG_ENABLE(libxml2,
+ 
+ if test "$enable_libxml2" = "yes"; then
+     PKG_CHECK_MODULES([LIBXML2], [libxml-2.0 >= 2.6])
++    PKGCONFIG_REQUIRES_PRIVATELY="$PKGCONFIG_REQUIRES_PRIVATELY libxml-2.0"
+     AC_DEFINE_UNQUOTED(ENABLE_LIBXML2,1,[Use libxml2 instead of Expat])
+ 
+     AC_SUBST(LIBXML2_CFLAGS)
+@@ -684,6 +723,12 @@ dnl include the header file for workaround of miscalculating size on autoconf
+ dnl particularly for fat binaries
+ AH_BOTTOM([#include "config-fixups.h"])
+ 
++dnl
++dnl
++AC_SUBST(PKGCONFIG_REQUIRES)
++AC_SUBST(PKGCONFIG_REQUIRES_PRIVATELY)
++
++dnl
+ AC_CONFIG_FILES([
+ Makefile
+ fontconfig/Makefile
+diff --git a/fontconfig.pc.in b/fontconfig.pc.in
+index 9ef2c27..6e112bb 100644
+--- a/fontconfig.pc.in
++++ b/fontconfig.pc.in
+@@ -11,6 +11,8 @@ cachedir=@fc_cachedir@
+ Name: Fontconfig
+ Description: Font configuration and customization library
+ Version: @VERSION@
++Requires: @PKGCONFIG_REQUIRES@
++Requires.private: @PKGCONFIG_REQUIRES_PRIVATELY@
+ Libs: -L${libdir} -lfontconfig
+-Libs.private: @LIBXML2_LIBS@ @EXPAT_LIBS@ @FREETYPE_LIBS@ @ICONV_LIBS@
+-Cflags: -I${includedir}
++Libs.private: @EXPAT_LIBS@ @FREETYPE_LIBS@ @ICONV_LIBS@ @LIBXML2_LIBS@
++Cflags: -I${includedir} @EXPAT_CFLAGS@ @FREETYPE_CFLAGS@ @ICONV_CFLAGS@ @LIBXML2_CFLAGS@
+diff --git a/fontconfig/fcprivate.h b/fontconfig/fcprivate.h
+index 18b8c08..210c1d8 100644
+--- a/fontconfig/fcprivate.h
++++ b/fontconfig/fcprivate.h
+@@ -48,8 +48,9 @@
+ 	__o__ = va_arg (va, const char *);			    \
+ 	if (!__o__)		    				    \
+ 	    break;		    				    \
+-	__v__.type = va_arg (va, FcType);			    \
++	__v__.type = va_arg (va, int);				    \
+ 	switch (__v__.type) {	    				    \
++	case FcTypeUnknown:					    \
+ 	case FcTypeVoid:					    \
+ 	    goto _FcPatternVapBuild_bail1;       		    \
+ 	case FcTypeInteger:	    				    \
+diff --git a/fontconfig/fontconfig.h b/fontconfig/fontconfig.h
+index 422187b..39d1b1b 100644
+--- a/fontconfig/fontconfig.h
++++ b/fontconfig/fontconfig.h
+@@ -185,6 +185,7 @@ typedef int		FcBool;
+ #define FC_LCD_LEGACY	    3
+ 
+ typedef enum _FcType {
++    FcTypeUnknown = -1,
+     FcTypeVoid,
+     FcTypeInteger,
+     FcTypeDouble,
+diff --git a/src/fccache.c b/src/fccache.c
+index 9f1c298..e02d49e 100644
+--- a/src/fccache.c
++++ b/src/fccache.c
+@@ -830,34 +830,6 @@ bail1:
+     return NULL;
+ }
+ 
+-
+-#ifdef _WIN32
+-#include <direct.h>
+-#define mkdir(path,mode) _mkdir(path)
+-#endif
+-
+-static FcBool
+-FcMakeDirectory (const FcChar8 *dir)
+-{
+-    FcChar8 *parent;
+-    FcBool  ret;
+-
+-    if (strlen ((char *) dir) == 0)
+-	return FcFalse;
+-
+-    parent = FcStrDirname (dir);
+-    if (!parent)
+-	return FcFalse;
+-    if (access ((char *) parent, F_OK) == 0)
+-	ret = mkdir ((char *) dir, 0755) == 0 && chmod ((char *) dir, 0755) == 0;
+-    else if (access ((char *) parent, F_OK) == -1)
+-	ret = FcMakeDirectory (parent) && (mkdir ((char *) dir, 0755) == 0) && chmod ((char *) dir, 0755) == 0;
+-    else
+-	ret = FcFalse;
+-    FcStrFree (parent);
+-    return ret;
+-}
+-
+ /* write serialized state to the cache file */
+ FcBool
+ FcDirCacheWrite (FcCache *cache, FcConfig *config)
+diff --git a/src/fccfg.c b/src/fccfg.c
+index fcdf73e..be738d5 100644
+--- a/src/fccfg.c
++++ b/src/fccfg.c
+@@ -214,10 +214,8 @@ FcSubstDestroy (FcSubst *s)
+     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);
+ 	s = n;
+     }
+@@ -226,20 +224,20 @@ FcSubstDestroy (FcSubst *s)
+ FcExpr *
+ FcConfigAllocExpr (FcConfig *config)
+ {
+-  if (!config->expr_pool || config->expr_pool->next == config->expr_pool->end)
+-  {
+-    FcExprPage *new_page;
++    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 = 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;
+-  }
++	new_page->next_page = config->expr_pool;
++	new_page->next = new_page->exprs;
++	config->expr_pool = new_page;
++    }
+ 
+-  return config->expr_pool->next++;
++    return config->expr_pool->next++;
+ }
+ 
+ FcConfig *
+@@ -644,15 +642,13 @@ FcConfigSetRescanInverval (FcConfig *config, int rescanInterval)
+     return FcConfigSetRescanInterval (config, rescanInterval);
+ }
+ 
+-
+ FcBool
+-FcConfigAddEdit (FcConfig	*config,
+-		 FcTest		*test,
+-		 FcEdit		*edit,
++FcConfigAddRule (FcConfig	*config,
++		 FcRule		*rule,
+ 		 FcMatchKind	kind)
+ {
+     FcSubst	*subst, **prev;
+-    FcTest	*t;
++    FcRule	*r;
+     int		num;
+ 
+     switch (kind) {
+@@ -673,15 +669,27 @@ FcConfigAddEdit (FcConfig	*config,
+ 	return FcFalse;
+     for (; *prev; prev = &(*prev)->next);
+     *prev = subst;
+-    subst->next = 0;
+-    subst->test = test;
+-    subst->edit = edit;
++    subst->next = NULL;
++    subst->rule = rule;
+     num = 0;
+-    for (t = test; t; t = t->next)
++    for (r = rule; r; r = r->next)
+     {
+-	if (t->kind == FcMatchDefault)
+-	    t->kind = kind;
+-	num++;
++	switch (r->type)
++	{
++	case FcRuleTest:
++	    if (r->u.test &&
++		r->u.test->kind == FcMatchDefault)
++		r->u.test->kind = kind;
++	    if (r->u.test->object > FC_MAX_BASE_OBJECT)
++		num++;
++	    break;
++	case FcRuleEdit:
++	    if (r->u.edit->object > FC_MAX_BASE_OBJECT)
++		num++;
++	    break;
++	default:
++	    break;
++	}
+     }
+     if (config->maxObjects < num)
+ 	config->maxObjects = num;
+@@ -721,7 +729,7 @@ FcConfigPromote (FcValue v, FcValue u, FcValuePromotionBuffer *buf)
+ 
+ FcBool
+ FcConfigCompareValue (const FcValue	*left_o,
+-		      FcOp		op_,
++		      unsigned int      op_,
+ 		      const FcValue	*right_o)
+ {
+     FcValue	left = FcValueCanonicalize(left_o);
+@@ -736,6 +744,8 @@ FcConfigCompareValue (const FcValue	*left_o,
+     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:
+@@ -1484,13 +1494,16 @@ FcConfigSubstituteWithPat (FcConfig    *config,
+ {
+     FcValue v;
+     FcSubst	    *s;
+-    FcSubState	    *st;
+-    int		    i;
+-    FcTest	    *t;
+-    FcEdit	    *e;
+-    FcValueList	    *l;
++    FcRule          *r;
++    FcValueList	    *l, **value = NULL;
+     FcPattern	    *m;
+     FcStrSet	    *strs;
++    FcObject	    object = FC_INVALID_OBJECT;
++    FcPatternElt    **elt = NULL;
++    int		    i, nobjs;
++    FcBool	    retval = FcTrue;
++
++#define FC_OBJ_ID(_n_)	((_n_) > FC_MAX_BASE_OBJECT ? ((_n_) - FC_EXT_OBJ_INDEX) : (_n_))
+ 
+     if (!config)
+     {
+@@ -1535,9 +1548,19 @@ FcConfigSubstituteWithPat (FcConfig    *config,
+ 	return FcFalse;
+     }
+ 
+-    st = (FcSubState *) malloc (config->maxObjects * sizeof (FcSubState));
+-    if (!st && config->maxObjects)
+-	return FcFalse;
++    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;
++    }
+ 
+     if (FcDebug () & FC_DBG_EDIT)
+     {
+@@ -1546,200 +1569,185 @@ 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;
++	}
++	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, p_pat, kind, 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, p_pat,kind,  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)
++		    elt[object] = FcPatternObjectFindElt (m, r->u.test->object);
++		/*
++		 * If there's no such field in the font,
++		 * then FcQualAll matches while FcQualAny does not
++		 */
++		if (!elt[object])
+ 		{
+-		    /*
+-		     * 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;
++		    if (r->u.test->qual == FcQualAll)
++		    {
++			value[object] = NULL;
++			continue;
++		    }
++		    else
++		    {
++			if (FcDebug () & FC_DBG_EDIT)
++			    printf ("No match\n");
++			goto bail;
++		    }
+ 		}
+-	    }
+-	    switch (FC_OP_GET_OP (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)
++		value[object] = FcConfigMatchValueList (m, p_pat, kind, r->u.test, elt[object]->values);
++		if (!value[object] ||
++		    (r->u.test->qual == FcQualFirst && value[object] != elt[object]->values) ||
++		    (r->u.test->qual == FcQualNotFirst && value[object] == elt[object]->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);
++
++		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, e->object);
++		    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, e->object);
++		    /* fall through ... */
++		case FcOpAppendLast:
++		    FcConfigPatternAdd (p, r->u.edit->object, l, FcTrue);
+ 		    break;
+-		}
+-		/* fall through ... */
+-	    case FcOpPrependFirst:
+-		FcConfigPatternAdd (p, e->object, l, FcFalse);
+-		break;
+-	    case FcOpAppend:
+-		if (t)
+-		{
+-		    FcConfigAdd (&st[i].elt->values, st[i].value, FcTrue, l, e->object);
++		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 FcOpAppendLast:
+-		FcConfigPatternAdd (p, e->object, l, FcTrue);
+-		break;
+-	    case FcOpDelete:
+-		if (t)
++		/*
++		 * Now go through the pattern and eliminate
++		 * any properties without data
++		 */
++		FcConfigPatternCanon (p, r->u.edit->object);
++
++		if (FcDebug () & FC_DBG_EDIT)
+ 		{
+-		    FcConfigDel (&st[i].elt->values, st[i].value);
+-		    break;
++		    printf ("FcConfigSubstitute edit");
++		    FcPatternPrint (p);
+ 		}
+-		/* fall through ... */
+-	    case FcOpDeleteAll:
+-		FcConfigPatternDel (p, e->object);
+-		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:;
+     }
+-    free (st);
+     if (FcDebug () & FC_DBG_EDIT)
+     {
+ 	printf ("FcConfigSubstitute done");
+ 	FcPatternPrint (p);
+     }
+-    return FcTrue;
++bail1:
++    if (elt)
++	free (elt);
++    if (value)
++	free (value);
++
++#undef FC_OBJ_ID
++
++    return retval;
+ }
+ 
+ FcBool
+diff --git a/src/fccompat.c b/src/fccompat.c
+index a217160..d4f88c8 100644
+--- a/src/fccompat.c
++++ b/src/fccompat.c
+@@ -219,3 +219,30 @@ FcRandom(void)
+ 
+     return result;
+ }
++
++#ifdef _WIN32
++#include <direct.h>
++#define mkdir(path,mode) _mkdir(path)
++#endif
++
++FcBool
++FcMakeDirectory (const FcChar8 *dir)
++{
++    FcChar8 *parent;
++    FcBool  ret;
++
++    if (strlen ((char *) dir) == 0)
++	return FcFalse;
++
++    parent = FcStrDirname (dir);
++    if (!parent)
++	return FcFalse;
++    if (access ((char *) parent, F_OK) == 0)
++	ret = mkdir ((char *) dir, 0755) == 0 && chmod ((char *) dir, 0755) == 0;
++    else if (access ((char *) parent, F_OK) == -1)
++	ret = FcMakeDirectory (parent) && (mkdir ((char *) dir, 0755) == 0) && chmod ((char *) dir, 0755) == 0;
++    else
++	ret = FcFalse;
++    FcStrFree (parent);
++    return ret;
++}
+diff --git a/src/fcdbg.c b/src/fcdbg.c
+index 9d02f5a..d74bc27 100644
+--- a/src/fcdbg.c
++++ b/src/fcdbg.c
+@@ -30,6 +30,9 @@ static void
+ _FcValuePrintFile (FILE *f, const FcValue v)
+ {
+     switch (v.type) {
++    case FcTypeUnknown:
++	fprintf (f, "<unknown>");
++	break;
+     case FcTypeVoid:
+ 	fprintf (f, "<void>");
+ 	break;
+@@ -98,6 +101,10 @@ FcValueBindingPrint (const FcValueListPtr l)
+     case FcValueBindingSame:
+ 	printf ("(=)");
+ 	break;
++    default:
++	/* shouldn't be reached */
++	printf ("(?)");
++	break;
+     }
+ }
+ 
+@@ -420,21 +427,38 @@ FcEditPrint (const FcEdit *edit)
+ void
+ FcSubstPrint (const FcSubst *subst)
+ {
+-    FcEdit	*e;
+-    FcTest	*t;
++    FcRule *r;
++    FcRuleType last_type = FcRuleUnknown;
+ 
+     printf ("match\n");
+-    for (t = subst->test; t; t = t->next)
+-    {
+-	printf ("\t");
+-	FcTestPrint (t);
+-    }
+-    printf ("edit\n");
+-    for (e = subst->edit; e; e = e->next)
++    for (r = subst->rule; r; r = r->next)
+     {
++	if (last_type != r->type)
++	{
++	    switch (r->type) {
++	    case FcRuleTest:
++		printf ("[test]\n");
++		break;
++	    case FcRuleEdit:
++		printf ("[edit]\n");
++		break;
++	    default:
++		break;
++	    }
++	    last_type = r->type;
++	}
+ 	printf ("\t");
+-	FcEditPrint (e);
+-	printf (";\n");
++	switch (r->type) {
++	case FcRuleTest:
++	    FcTestPrint (r->u.test);
++	    break;
++	case FcRuleEdit:
++	    FcEditPrint (r->u.edit);
++	    printf (";\n");
++	    break;
++	default:
++	    break;
++	}
+     }
+     printf ("\n");
+ }
+diff --git a/src/fcdir.c b/src/fcdir.c
+index dc580bb..b040a28 100644
+--- a/src/fcdir.c
++++ b/src/fcdir.c
+@@ -49,6 +49,16 @@ FcFileIsLink (const FcChar8 *file)
+ #endif
+ }
+ 
++FcBool
++FcFileIsFile (const FcChar8 *file)
++{
++    struct stat statb;
++
++    if (FcStat (file, &statb) != 0)
++	return FcFalse;
++    return S_ISREG (statb.st_mode);
++}
++
+ static FcBool
+ FcFileScanFontConfig (FcFontSet		*set,
+ 		      FcBlanks		*blanks,
+diff --git a/src/fchash.c b/src/fchash.c
+index 92585a6..7216bee 100644
+--- a/src/fchash.c
++++ b/src/fchash.c
+@@ -190,14 +190,14 @@ FcHashGetSHA256Digest (const FcChar8 *input_strings,
+     }
+     /* set input size at the end */
+     len *= 8;
+-    block[63 - 0] =  len        & 0xff;
+-    block[63 - 1] = (len >>  8) & 0xff;
+-    block[63 - 2] = (len >> 16) & 0xff;
+-    block[63 - 3] = (len >> 24) & 0xff;
+-    block[63 - 4] = (len >> 32) & 0xff;
+-    block[63 - 5] = (len >> 40) & 0xff;
+-    block[63 - 6] = (len >> 48) & 0xff;
+-    block[63 - 7] = (len >> 56) & 0xff;
++    block[63 - 0] =  (uint64_t)len        & 0xff;
++    block[63 - 1] = ((uint64_t)len >>  8) & 0xff;
++    block[63 - 2] = ((uint64_t)len >> 16) & 0xff;
++    block[63 - 3] = ((uint64_t)len >> 24) & 0xff;
++    block[63 - 4] = ((uint64_t)len >> 32) & 0xff;
++    block[63 - 5] = ((uint64_t)len >> 40) & 0xff;
++    block[63 - 6] = ((uint64_t)len >> 48) & 0xff;
++    block[63 - 7] = ((uint64_t)len >> 56) & 0xff;
+     FcHashComputeSHA256Digest (ret, block);
+ 
+     return FcHashSHA256ToString (ret);
+@@ -226,7 +226,7 @@ FcHashGetSHA256DigestFromFile (const FcChar8 *filename)
+     {
+ 	if ((len = fread (ibuf, sizeof (char), 64, fp)) < 64)
+ 	{
+-	    long v;
++	    uint64_t v;
+ 
+ 	    /* add a padding */
+ 	    memset (&ibuf[len], 0, 64 - len);
+@@ -281,7 +281,7 @@ FcHashGetSHA256DigestFromMemory (const char *fontdata,
+     {
+ 	if ((length - i) < 64)
+ 	{
+-	    long v;
++	    uint64_t v;
+ 	    size_t n;
+ 
+ 	    /* add a padding */
+diff --git a/src/fcint.h b/src/fcint.h
+index 65bf333..ec0c674 100644
+--- a/src/fcint.h
++++ b/src/fcint.h
+@@ -37,6 +37,7 @@
+ #include <ctype.h>
+ #include <assert.h>
+ #include <errno.h>
++#include <limits.h>
+ #include <unistd.h>
+ #include <stddef.h>
+ #include <sys/types.h>
+@@ -85,7 +86,7 @@ extern pfnSHGetFolderPathA pSHGetFolderPathA;
+ #define FC_DBG_CONFIG	1024
+ #define FC_DBG_LANGSET	2048
+ 
+-#define _FC_ASSERT_STATIC1(_line, _cond) typedef int _static_assert_on_line_##_line##_failed[(_cond)?1:-1]
++#define _FC_ASSERT_STATIC1(_line, _cond) typedef int _static_assert_on_line_##_line##_failed[(_cond)?1:-1] FC_UNUSED
+ #define _FC_ASSERT_STATIC0(_line, _cond) _FC_ASSERT_STATIC1 (_line, (_cond))
+ #define FC_ASSERT_STATIC(_cond) _FC_ASSERT_STATIC0 (__LINE__, (_cond))
+ 
+@@ -107,7 +108,9 @@ extern pfnSHGetFolderPathA pSHGetFolderPathA;
+ FC_ASSERT_STATIC (sizeof (FcRef) == sizeof (int));
+ 
+ typedef enum _FcValueBinding {
+-    FcValueBindingWeak, FcValueBindingStrong, FcValueBindingSame
++    FcValueBindingWeak, FcValueBindingStrong, FcValueBindingSame,
++    /* to make sure sizeof (FcValueBinding) == 4 even with -fshort-enums */
++    FcValueBindingEnd = INT_MAX
+ } FcValueBinding;
+ 
+ #define FcStrdup(s) ((FcChar8 *) strdup ((const char *) (s)))
+@@ -171,6 +174,11 @@ typedef struct _FcValueList {
+ 			
+ typedef int FcObject;
+ 
++/* The 1000 is to leave some room for future added internal objects, such
++ * that caches from newer fontconfig can still be used with older fontconfig
++ * without getting confused. */
++#define FC_EXT_OBJ_INDEX	1000
++
+ typedef struct _FcPatternElt *FcPatternEltPtr;
+ 
+ /*
+@@ -271,7 +279,6 @@ typedef enum _FcQual {
+ #define FcMatchDefault	((FcMatchKind) -1)
+ 
+ typedef struct _FcTest {
+-    struct _FcTest	*next;
+     FcMatchKind		kind;
+     FcQual		qual;
+     FcObject		object;
+@@ -280,17 +287,28 @@ typedef struct _FcTest {
+ } FcTest;
+ 
+ typedef struct _FcEdit {
+-    struct _FcEdit *next;
+     FcObject	    object;
+     FcOp	    op;
+     FcExpr	    *expr;
+     FcValueBinding  binding;
+ } FcEdit;
+ 
++typedef enum _FcRuleType {
++    FcRuleUnknown, FcRuleTest, FcRuleEdit
++} FcRuleType;
++
++typedef struct _FcRule {
++    struct _FcRule *next;
++    FcRuleType      type;
++    union {
++	FcTest *test;
++	FcEdit *edit;
++    } u;
++} FcRule;
++
+ typedef struct _FcSubst {
+     struct _FcSubst	*next;
+-    FcTest		*test;
+-    FcEdit		*edit;
++    FcRule		*rule;
+ } FcSubst;
+ 
+ typedef struct _FcCharLeaf {
+@@ -610,10 +628,9 @@ FcPrivate FcBool
+ FcConfigAddBlank (FcConfig	*config,
+ 		  FcChar32    	blank);
+ 
+-FcPrivate FcBool
+-FcConfigAddEdit (FcConfig	*config,
+-		 FcTest		*test,
+-		 FcEdit		*edit,
++FcBool
++FcConfigAddRule (FcConfig	*config,
++		 FcRule		*rule,
+ 		 FcMatchKind	kind);
+ 
+ FcPrivate void
+@@ -623,7 +640,7 @@ FcConfigSetFonts (FcConfig	*config,
+ 
+ FcPrivate FcBool
+ FcConfigCompareValue (const FcValue *m,
+-		      FcOp	    op,
++		      unsigned int   op_,
+ 		      const FcValue *v);
+ 
+ FcPrivate FcBool
+@@ -730,6 +747,9 @@ FcMakeTempfile (char *template);
+ FcPrivate int32_t
+ FcRandom (void);
+ 
++FcPrivate FcBool
++FcMakeDirectory (const FcChar8 *dir);
++
+ /* fcdbg.c */
+ 
+ FcPrivate void
+@@ -788,6 +808,9 @@ FcPrivate FcBool
+ FcFileIsLink (const FcChar8 *file);
+ 
+ FcPrivate FcBool
++FcFileIsFile (const FcChar8 *file);
++
++FcPrivate FcBool
+ FcFileScanConfig (FcFontSet	*set,
+ 		  FcStrSet	*dirs,
+ 		  FcBlanks	*blanks,
+@@ -840,6 +863,9 @@ FcTestDestroy (FcTest *test);
+ FcPrivate void
+ FcEditDestroy (FcEdit *e);
+ 
++void
++FcRuleDestroy (FcRule *rule);
++
+ /* fclang.c */
+ FcPrivate FcLangSet *
+ FcFreeTypeLangSet (const FcCharSet  *charset,
+diff --git a/src/fclist.c b/src/fclist.c
+index b7ae899..c56e24c 100644
+--- a/src/fclist.c
++++ b/src/fclist.c
+@@ -252,6 +252,7 @@ FcListValueHash (FcValue    *value)
+ {
+     FcValue v = FcValueCanonicalize(value);
+     switch (v.type) {
++    case FcTypeUnknown:
+     case FcTypeVoid:
+ 	return 0;
+     case FcTypeInteger:
+diff --git a/src/fcmatch.c b/src/fcmatch.c
+index 10976d6..dec92b9 100644
+--- a/src/fcmatch.c
++++ b/src/fcmatch.c
+@@ -245,6 +245,8 @@ typedef enum _FcMatcherPriorityDummy {
+ typedef enum _FcMatcherPriority {
+     PRI1(HASH),
+     PRI1(FILE),
++    PRI1(FONTFORMAT),
++    PRI1(SCALABLE),
+     PRI1(FOUNDRY),
+     PRI1(CHARSET),
+     PRI_FAMILY_STRONG,
+diff --git a/src/fcname.c b/src/fcname.c
+index 6dd4d49..712b2fa 100644
+--- a/src/fcname.c
++++ b/src/fcname.c
+@@ -76,6 +76,8 @@ FcObjectValidType (FcObject object, FcType type)
+ 
+     if (t) {
+ 	switch ((int) t->type) {
++	case FcTypeUnknown:
++	    return FcTrue;
+ 	case FcTypeDouble:
+ 	case FcTypeInteger:
+ 	    if (type == FcTypeDouble || type == FcTypeInteger)
+@@ -86,7 +88,7 @@ FcObjectValidType (FcObject object, FcType type)
+ 		return FcTrue;
+ 	    break;
+ 	default:
+-	    if (t->type == (unsigned int) -1 || type == t->type)
++	    if (type == t->type)
+ 		return FcTrue;
+ 	    break;
+ 	}
+@@ -318,6 +320,12 @@ FcNameFindNext (const FcChar8 *cur, const char *delim, FcChar8 *save, FcChar8 *l
+ 
+     while ((c = *cur))
+     {
++	if (!isspace (c))
++	    break;
++	++cur;
++    }
++    while ((c = *cur))
++    {
+ 	if (c == '\\')
+ 	{
+ 	    ++cur;
+@@ -468,6 +476,7 @@ FcNameUnparseValue (FcStrBuf	*buf,
+     FcValue v = FcValueCanonicalize(v0);
+ 
+     switch (v.type) {
++    case FcTypeUnknown:
+     case FcTypeVoid:
+ 	return FcTrue;
+     case FcTypeInteger:
+diff --git a/src/fcobjs.c b/src/fcobjs.c
+index 146ca70..bad9824 100644
+--- a/src/fcobjs.c
++++ b/src/fcobjs.c
+@@ -37,7 +37,7 @@ FcObjectTypeLookup (register const char *str, register unsigned int len);
+ /* The 1000 is to leave some room for future added internal objects, such
+  * that caches from newer fontconfig can still be used with older fontconfig
+  * without getting confused. */
+-static fc_atomic_int_t next_id = FC_MAX_BASE_OBJECT + 1000;
++static fc_atomic_int_t next_id = FC_MAX_BASE_OBJECT + FC_EXT_OBJ_INDEX;
+ struct FcObjectOtherTypeInfo {
+     struct FcObjectOtherTypeInfo *next;
+     FcObjectType object;
+@@ -63,7 +63,7 @@ retry:
+ 	    return NULL;
+ 
+ 	ot->object.object = (const char *) FcStrdup (str);
+-	ot->object.type = -1;
++	ot->object.type = FcTypeUnknown;
+ 	ot->id = fc_atomic_int_add (next_id, +1);
+ 	ot->next = ots;
+ 
+diff --git a/src/fcobjs.h b/src/fcobjs.h
+index 682fe6a..87c7319 100644
+--- a/src/fcobjs.h
++++ b/src/fcobjs.h
+@@ -23,7 +23,7 @@ FC_OBJECT (FILE,		FcTypeString,	FcCompareFilename)
+ FC_OBJECT (INDEX,		FcTypeInteger,	NULL)
+ FC_OBJECT (RASTERIZER,		FcTypeString,	FcCompareString)
+ FC_OBJECT (OUTLINE,		FcTypeBool,	FcCompareBool)
+-FC_OBJECT (SCALABLE,		FcTypeBool,	NULL)
++FC_OBJECT (SCALABLE,		FcTypeBool,	FcCompareBool)
+ FC_OBJECT (DPI,			FcTypeDouble,	NULL)
+ FC_OBJECT (RGBA,		FcTypeInteger,	NULL)
+ FC_OBJECT (SCALE,		FcTypeDouble,	NULL)
+@@ -35,7 +35,7 @@ FC_OBJECT (CHARSET,		FcTypeCharSet,	FcCompareCharSet)
+ FC_OBJECT (LANG,		FcTypeLangSet,	FcCompareLang)
+ FC_OBJECT (FONTVERSION,		FcTypeInteger,	FcCompareNumber)
+ FC_OBJECT (CAPABILITY,		FcTypeString,	NULL)
+-FC_OBJECT (FONTFORMAT,		FcTypeString,	NULL)
++FC_OBJECT (FONTFORMAT,		FcTypeString,	FcCompareString)
+ FC_OBJECT (EMBOLDEN,		FcTypeBool,	NULL)
+ FC_OBJECT (EMBEDDED_BITMAP,	FcTypeBool,	NULL)
+ FC_OBJECT (DECORATIVE,		FcTypeBool,	FcCompareBool)
+diff --git a/src/fcpat.c b/src/fcpat.c
+index 25bff64..0614ac2 100644
+--- a/src/fcpat.c
++++ b/src/fcpat.c
+@@ -246,6 +246,8 @@ FcValueEqual (FcValue va, FcValue vb)
+ 	    return FcFalse;
+     }
+     switch (va.type) {
++    case FcTypeUnknown:
++	return FcFalse;	/* don't know how to compare this object */
+     case FcTypeVoid:
+ 	return FcTrue;
+     case FcTypeInteger:
+@@ -294,6 +296,7 @@ static FcChar32
+ FcValueHash (const FcValue *v)
+ {
+     switch (v->type) {
++    case FcTypeUnknown:
+     case FcTypeVoid:
+ 	return 0;
+     case FcTypeInteger:
+@@ -317,7 +320,7 @@ FcValueHash (const FcValue *v)
+     case FcTypeLangSet:
+ 	return FcLangSetHash (FcValueLangSet(v));
+     }
+-    return FcFalse;
++    return 0;
+ }
+ 
+ static FcBool
+diff --git a/src/fcstat.c b/src/fcstat.c
+index 390f45c..ab56aca 100644
+--- a/src/fcstat.c
++++ b/src/fcstat.c
+@@ -164,11 +164,21 @@ FcDirChecksumScandirFilter(const struct dirent *entry)
+ }
+ #endif
+ 
++#ifdef HAVE_SCANDIR
+ static int
+ FcDirChecksumScandirSorter(const struct dirent **lhs, const struct dirent **rhs)
+ {
+     return strcmp((*lhs)->d_name, (*rhs)->d_name);
+ }
++#elif HAVE_SCANDIR_VOID_P
++static int
++FcDirChecksumScandirSorter(const void *a, const void *b)
++{
++    const struct dirent *lhs = a, *rhs = b;
++
++    return strcmp(lhs->d_name, rhs->d_name);
++}
++#endif
+ 
+ static int
+ FcDirChecksum (const FcChar8 *dir, time_t *checksum)
+diff --git a/src/fcxml.c b/src/fcxml.c
+index 470e44f..2cdf0ad 100644
+--- a/src/fcxml.c
++++ b/src/fcxml.c
+@@ -62,12 +62,30 @@ FcExprDestroy (FcExpr *e);
+ void
+ FcTestDestroy (FcTest *test)
+ {
+-    if (test->next)
+-	FcTestDestroy (test->next);
+     FcExprDestroy (test->expr);
+     free (test);
+ }
+ 
++void
++FcRuleDestroy (FcRule *rule)
++{
++    FcRule *n = rule->next;
++
++    switch (rule->type) {
++    case FcRuleTest:
++	FcTestDestroy (rule->u.test);
++	break;
++    case FcRuleEdit:
++	FcEditDestroy (rule->u.edit);
++	break;
++    default:
++	break;
++    }
++    free (rule);
++    if (n)
++	FcRuleDestroy (n);
++}
++
+ static FcExpr *
+ FcExprCreateInteger (FcConfig *config, int i)
+ {
+@@ -300,8 +318,6 @@ FcExprDestroy (FcExpr *e)
+ void
+ FcEditDestroy (FcEdit *e)
+ {
+-    if (e->next)
+-	FcEditDestroy (e->next);
+     if (e->expr)
+ 	FcExprDestroy (e->expr);
+     free (e);
+@@ -705,7 +721,7 @@ FcTestCreate (FcConfigParse *parse,
+ 	      FcMatchKind   kind,
+ 	      FcQual	    qual,
+ 	      const FcChar8 *field,
+-	      FcOp	    compare,
++	      unsigned int  compare,
+ 	      FcExpr	    *expr)
+ {
+     FcTest	*test = (FcTest *) malloc (sizeof (FcTest));
+@@ -714,7 +730,6 @@ FcTestCreate (FcConfigParse *parse,
+     {
+ 	const FcObjectType	*o;
+ 	
+-	test->next = 0;
+ 	test->kind = kind;
+ 	test->qual = qual;
+ 	test->object = FcObjectFromName ((const char *) field);
+@@ -740,7 +755,6 @@ FcEditCreate (FcConfigParse	*parse,
+     {
+ 	const FcObjectType	*o;
+ 
+-	e->next = 0;
+ 	e->object = object;
+ 	e->op = op;
+ 	e->expr = expr;
+@@ -752,6 +766,34 @@ FcEditCreate (FcConfigParse	*parse,
+     return e;
+ }
+ 
++static FcRule *
++FcRuleCreate (FcRuleType type,
++	      void       *p)
++{
++    FcRule *r = (FcRule *) malloc (sizeof (FcRule));
++
++    if (!r)
++	return NULL;
++
++    r->next = NULL;
++    r->type = type;
++    switch (type)
++    {
++    case FcRuleTest:
++	r->u.test = (FcTest *) p;
++	break;
++    case FcRuleEdit:
++	r->u.edit = (FcEdit *) p;
++	break;
++    default:
++	free (r);
++	r = NULL;
++	break;
++    }
++
++    return r;
++}
++
+ static FcVStack *
+ FcVStackCreateAndPush (FcConfigParse *parse)
+ {
+@@ -1657,9 +1699,9 @@ static void
+ FcParseAlias (FcConfigParse *parse)
+ {
+     FcExpr	*family = 0, *accept = 0, *prefer = 0, *def = 0, *new = 0;
+-    FcEdit	*edit = 0, *next;
++    FcEdit	*edit = 0;
+     FcVStack	*vstack;
+-    FcTest	*test = NULL;
++    FcRule	*rule = NULL, *r;
+     FcValueBinding  binding;
+ 
+     if (!FcConfigLexBinding (parse, FcConfigGetAttribute (parse, "binding"), &binding))
+@@ -1704,8 +1746,14 @@ FcParseAlias (FcConfigParse *parse)
+ 	    vstack->tag = FcVStackNone;
+ 	    break;
+ 	case FcVStackTest:
+-	    vstack->u.test->next = test;
+-	    test = vstack->u.test;
++	    if (rule)
++	    {
++		r = FcRuleCreate (FcRuleTest, vstack->u.test);
++		r->next = rule;
++		rule = r;
++	    }
++	    else
++		rule = FcRuleCreate (FcRuleTest, vstack->u.test);
+ 	    vstack->tag = FcVStackNone;
+ 	    break;
+ 	default:
+@@ -1723,8 +1771,35 @@ FcParseAlias (FcConfigParse *parse)
+ 	    FcExprDestroy (accept);
+ 	if (def)
+ 	    FcExprDestroy (def);
++	if (rule)
++	    FcRuleDestroy (rule);
+ 	return;
+     }
++    if (!prefer &&
++	!accept &&
++	!def)
++    {
++	FcExprDestroy (family);
++	return;
++    }
++    else
++    {
++	FcTest *t = FcTestCreate (parse, FcMatchPattern,
++				  FcQualAny,
++				  (FcChar8 *) FC_FAMILY,
++				  FC_OP (FcOpEqual, FcOpFlagIgnoreBlanks),
++				  family);
++	if (rule)
++	{
++	    for (r = rule; r->next; r = r->next);
++	    r->next = FcRuleCreate (FcRuleTest, t);
++	    r = r->next;
++	}
++	else
++	{
++	    r = rule = FcRuleCreate (FcRuleTest, t);
++	}
++    }
+     if (prefer)
+     {
+ 	edit = FcEditCreate (parse,
+@@ -1732,60 +1807,46 @@ FcParseAlias (FcConfigParse *parse)
+ 			     FcOpPrepend,
+ 			     prefer,
+ 			     binding);
+-	if (edit)
+-	    edit->next = 0;
+-	else
++	if (!edit)
+ 	    FcExprDestroy (prefer);
++	else
++	{
++	    r->next = FcRuleCreate (FcRuleEdit, edit);
++	    r = r->next;
++	}
+     }
+     if (accept)
+     {
+-	next = edit;
+ 	edit = FcEditCreate (parse,
+ 			     FC_FAMILY_OBJECT,
+ 			     FcOpAppend,
+ 			     accept,
+ 			     binding);
+-	if (edit)
+-	    edit->next = next;
+-	else
++	if (!edit)
+ 	    FcExprDestroy (accept);
++	else
++	{
++	    r->next = FcRuleCreate (FcRuleEdit, edit);
++	    r = r->next;
++	}
+     }
+     if (def)
+     {
+-	next = edit;
+ 	edit = FcEditCreate (parse,
+ 			     FC_FAMILY_OBJECT,
+ 			     FcOpAppendLast,
+ 			     def,
+ 			     binding);
+-	if (edit)
+-	    edit->next = next;
+-	else
++	if (!edit)
+ 	    FcExprDestroy (def);
+-    }
+-    if (edit)
+-    {
+-	FcTest *t = FcTestCreate (parse, FcMatchPattern,
+-				  FcQualAny,
+-				  (FcChar8 *) FC_FAMILY,
+-				  FC_OP (FcOpEqual, FcOpFlagIgnoreBlanks),
+-				  family);
+-	if (test)
++	else
+ 	{
+-	    FcTest *p = test;
+-
+-	    while (p->next)
+-		p = p->next;
+-	    p->next = t;
++	    r->next = FcRuleCreate (FcRuleEdit, edit);
++	    r = r->next;
+ 	}
+-	else
+-	    test = t;
+-	if (test)
+-	    if (!FcConfigAddEdit (parse->config, test, edit, FcMatchPattern))
+-		FcTestDestroy (test);
+     }
+-    else
+-	FcExprDestroy (family);
++    if (!FcConfigAddRule (parse->config, rule, FcMatchPattern))
++	FcRuleDestroy (rule);
+ }
+ 
+ static FcExpr *
+@@ -2121,6 +2182,8 @@ FcParseInclude (FcConfigParse *parse)
+     FcBool	    ignore_missing = FcFalse;
+     FcBool	    deprecated = FcFalse;
+     FcChar8	    *prefix = NULL, *p;
++    static FcChar8  *userdir = NULL;
++    static FcChar8  *userconf = NULL;
+ 
+     s = FcStrBufDoneStatic (&parse->pstack->str);
+     if (!s)
+@@ -2153,23 +2216,78 @@ FcParseInclude (FcConfigParse *parse)
+ 	memcpy (&prefix[plen + 1], s, dlen);
+ 	prefix[plen + 1 + dlen] = 0;
+ 	s = prefix;
++	if (FcFileIsDir (s))
++	{
++	userdir:
++	    if (!userdir)
++		userdir = FcStrdup (s);
++	}
++	else if (FcFileIsFile (s))
++	{
++	userconf:
++	    if (!userconf)
++		userconf = FcStrdup (s);
++	}
++	else
++	{
++	    /* No config dir nor file on the XDG directory spec compliant place
++	     * so need to guess what it is supposed to be.
++	     */
++	    FcChar8 *parent = FcStrDirname (s);
++
++	    if (!FcFileIsDir (parent))
++		FcMakeDirectory (parent);
++	    FcStrFree (parent);
++	    if (FcStrStr (s, (const FcChar8 *)"conf.d") != NULL)
++		goto userdir;
++	    else
++		goto userconf;
++	}
+     }
+     if (!FcConfigParseAndLoad (parse->config, s, !ignore_missing))
+ 	parse->error = FcTrue;
++#ifndef _WIN32
+     else
+     {
+         FcChar8 *filename;
++	static FcBool warn_conf = FcFalse, warn_confd = FcFalse;
+ 
+         filename = FcConfigFilename(s);
+ 	if (deprecated == FcTrue &&
+ 	    filename != NULL &&
+ 	    !FcFileIsLink (filename))
+ 	{
+-            FcConfigMessage (parse, FcSevereWarning, "reading configurations from %s is deprecated.", s);
++	    if (FcFileIsDir (filename))
++	    {
++		if (FcFileIsDir (userdir) ||
++		    rename ((const char *)filename, (const char *)userdir) != 0 ||
++		    symlink ((const char *)userdir, (const char *)filename) != 0)
++		{
++		    if (!warn_confd)
++		    {
++			FcConfigMessage (parse, FcSevereWarning, "reading configurations from %s is deprecated. please move it to %s manually", s, userdir);
++			warn_confd = FcTrue;
++		    }
++		}
++	    }
++	    else
++	    {
++		if (FcFileIsFile (userconf) ||
++		    rename ((const char *)filename, (const char *)userconf) != 0 ||
++		    symlink ((const char *)userconf, (const char *)filename) != 0)
++		{
++		    if (!warn_conf)
++		    {
++			FcConfigMessage (parse, FcSevereWarning, "reading configurations from %s is deprecated. please move it to %s manually", s, userconf);
++			warn_conf = FcTrue;
++		    }
++		}
++	    }
+         }
+         if(filename)
+             FcStrFree(filename);
+     }
++#endif
+     FcStrBufDestroy (&parse->pstack->str);
+ 
+   bail:
+@@ -2386,22 +2504,14 @@ FcParseEdit (FcConfigParse *parse)
+ 	FcEditDestroy (edit);
+ }
+ 
+-typedef struct FcSubstStack {
+-    FcTest *test;
+-    FcEdit *edit;
+-} FcSubstStack;
+-
+ static void
+ FcParseMatch (FcConfigParse *parse)
+ {
+     const FcChar8   *kind_name;
+     FcMatchKind	    kind;
+-    FcTest	    *test = 0;
+     FcEdit	    *edit = 0;
+     FcVStack	    *vstack;
+-    FcBool           tested = FcFalse;
+-    FcSubstStack    *sstack = NULL;
+-    int              len, pos = 0;
++    FcRule	    *rule = NULL, *r;
+ 
+     kind_name = FcConfigGetAttribute (parse, "target");
+     if (!kind_name)
+@@ -2420,48 +2530,29 @@ FcParseMatch (FcConfigParse *parse)
+ 	    return;
+ 	}
+     }
+-    len = FcVStackElements(parse);
+-    if (len > 0)
+-    {
+-	sstack = malloc (sizeof (FcSubstStack) * (len + 1));
+-	if (!sstack)
+-	{
+-	    FcConfigMessage (parse, FcSevereError, "out of memory");
+-	    return;
+-	}
+-    }
+     while ((vstack = FcVStackPeek (parse)))
+     {
+ 	switch ((int) vstack->tag) {
+ 	case FcVStackTest:
+-	    vstack->u.test->next = test;
+-	    test = vstack->u.test;
++	    r = FcRuleCreate (FcRuleTest, vstack->u.test);
++	    if (rule)
++		r->next = rule;
++	    rule = r;
+ 	    vstack->tag = FcVStackNone;
+-	    tested = FcTrue;
+ 	    break;
+ 	case FcVStackEdit:
+-	    /* due to the reverse traversal, <edit> node appears faster than
+-	     * <test> node if any. so we have to deal with it here rather than
+-	     * the above in FcVStackTest, and put recipes in reverse order.
+-	     */
+-	    if (tested)
+-	    {
+-		sstack[pos].test = test;
+-		sstack[pos].edit = edit;
+-		pos++;
+-		test = NULL;
+-		edit = NULL;
+-		tested = FcFalse;
+-	    }
+-	    vstack->u.edit->next = edit;
+-	    edit = vstack->u.edit;
+-	    vstack->tag = FcVStackNone;
+-	    if (kind == FcMatchScan && edit->object > FC_MAX_BASE_OBJECT)
++	    if (kind == FcMatchScan && vstack->u.edit->object > FC_MAX_BASE_OBJECT)
+ 	    {
+ 		FcConfigMessage (parse, FcSevereError,
+ 				 "<match target=\"scan\"> cannot edit user-defined object \"%s\"",
+ 				 FcObjectName(edit->object));
++		break;
+ 	    }
++	    r = FcRuleCreate (FcRuleEdit, vstack->u.edit);
++	    if (rule)
++		r->next = rule;
++	    rule = r;
++	    vstack->tag = FcVStackNone;
+ 	    break;
+ 	default:
+ 	    FcConfigMessage (parse, FcSevereWarning, "invalid match element");
+@@ -2469,22 +2560,8 @@ FcParseMatch (FcConfigParse *parse)
+ 	}
+ 	FcVStackPopAndDestroy (parse);
+     }
+-    if (!FcConfigAddEdit (parse->config, test, edit, kind))
++    if (!FcConfigAddRule (parse->config, rule, kind))
+ 	FcConfigMessage (parse, FcSevereError, "out of memory");
+-    if (sstack)
+-    {
+-	int i;
+-
+-	for (i = 0; i < pos; i++)
+-	{
+-	    if (!FcConfigAddEdit (parse->config, sstack[pos - i - 1].test, sstack[pos - i - 1].edit, kind))
+-	    {
+-		FcConfigMessage (parse, FcSevereError, "out of memory");
+-		return;
+-	    }
+-	}
+-	free (sstack);
+-    }
+ }
+ 
+ static void
================================================================

---- gitweb:

http://git.pld-linux.org/gitweb.cgi/packages/fontconfig.git/commitdiff/3ea8a859aeff0dc6f78d475066d50f1fbc9b2816




More information about the pld-cvs-commit mailing list