[Fontconfig] Sigh. What to do about per-user fonts...

Keith Packard keithp at keithp.com
Fri Apr 28 01:26:30 PDT 2006


On Thu, 2006-04-27 at 18:27 -0700, Patrick Lam wrote:

> Right.  That works best when you don't stick cache files in ~/.fonts
> directly, of course.

Here's just the cache dir piece of the patch, without the magic
avoid-the-rescan stuff added.

It's a huge patch because it rewrites all of the cache file lookup code.
Note that this *also* removes the collision avoidence code, which was
busted. It should still identify collisions and fail to save the cache
file in that case, which should be fairly harmless (just dumping stuff
in the per-user cache). Note that MD5 is a strong hash, so this
'shouldn't happen'.

-keith

Index: configure.in
===================================================================
RCS file: /cvs/fontconfig/fontconfig/configure.in,v
retrieving revision 1.66.2.12
diff -u -p -r1.66.2.12 configure.in
--- configure.in	25 Apr 2006 15:33:07 -0000	1.66.2.12
+++ configure.in	28 Apr 2006 08:15:26 -0000
@@ -1,5 +1,5 @@
 dnl 
-dnl  $Id: configure.in,v 1.66.2.12 2006-04-25 15:33:07 plam Exp $
+dnl  $Id: configure.in,v 1.66.2.12 2006/04/25 15:33:07 plam Exp $
 dnl 
 dnl  Copyright © 2003 Keith Packard
 dnl 
@@ -431,6 +431,22 @@ esac
 
 AC_SUBST(FC_FONTPATH)
 
+#
+# Set default cache directory path
+#
+AC_ARG_WITH(cache-dir,         [ --with-cache-dir=DIR           Use DIR to store cache files (default /var/cache/fontconfig)], fc_cachedir="$withval", fc_cachedir=yes)
+
+case $fc_cachedir in
+no|yes)
+	fc_cachedir=`eval echo "${localstatedir}/cache/"${PACKAGE}`
+	;;
+*)
+	;;
+esac
+AC_SUBST(fc_cachedir)
+FC_CACHEDIR=${fc_cachedir}
+AC_SUBST(FC_CACHEDIR)
+
 FC_FONTDATE=`LC_ALL=C date`
 
 AC_SUBST(FC_FONTDATE)
@@ -516,12 +532,6 @@ fi
 
 AC_SUBST(DOCDIR)
 
-#
-# Make /var/cache/fontconfig directory available to source code
-#
-
-pkgcachedir='${localstatedir}/cache/'${PACKAGE}
-AC_SUBST(pkgcachedir)
 
 AC_OUTPUT([
 Makefile 
Index: fonts.conf.in
===================================================================
RCS file: /cvs/fontconfig/fontconfig/fonts.conf.in,v
retrieving revision 1.32.2.7
diff -u -p -r1.32.2.7 fonts.conf.in
--- fonts.conf.in	15 Apr 2006 00:25:20 -0000	1.32.2.7
+++ fonts.conf.in	28 Apr 2006 08:18:21 -0000
@@ -27,6 +27,11 @@
 	@FC_FONTPATH@
 	<dir>~/.fonts</dir>
 
+<!-- Font cache directory list -->
+
+	<cachedir>@FC_CACHEDIR@</cachedir>
+	<cachedir>~/.fonts/fontconfig</cachedir>
+
 <!--
   Accept deprecated 'mono' alias, replacing it with 'monospace'
 -->
Index: fonts.dtd
===================================================================
RCS file: /cvs/fontconfig/fontconfig/fonts.dtd,v
retrieving revision 1.11
diff -u -p -r1.11 fonts.dtd
--- fonts.dtd	4 Dec 2004 19:41:10 -0000	1.11
+++ fonts.dtd	28 Apr 2006 06:39:21 -0000
@@ -23,6 +23,18 @@
 <!ATTLIST cache xml:space (default|preserve) 'preserve'>
 
 <!--
+    Add a directory that is searched for font cache files.
+    These hold per-directory cache data and are searched in
+    order for each directory. When writing cache files, the first
+    directory which allows the cache file to be created is used.
+
+    A leading '~' in a directory name is replaced with the users
+    home directory path.
+-->
+<!ELEMENT cachedir (#PCDATA)>
+<!ATTLIST cachedir xml:space (default|preserve) 'preserve'>
+
+<!--
     Reference another configuration file; note that this
     is another complete font configuration file and not
     just a file included by the XML parser.
Index: fc-cache/fc-cache.c
===================================================================
RCS file: /cvs/fontconfig/fontconfig/fc-cache/fc-cache.c,v
retrieving revision 1.17.2.21
diff -u -p -r1.17.2.21 fc-cache.c
--- fc-cache/fc-cache.c	25 Apr 2006 05:57:41 -0000	1.17.2.21
+++ fc-cache/fc-cache.c	28 Apr 2006 07:47:05 -0000
@@ -230,7 +230,8 @@ scanDirs (FcStrList *list, FcConfig *con
 	    ret++;
 	    continue;
 	}
-	if (!force && FcDirCacheValid (dir) && FcDirCacheHasCurrentArch (dir))
+	if (!force && FcDirCacheValid (dir, config) && 
+	    FcDirCacheHasCurrentArch (dir, config))
 	{
 	    if (verbose)
 		printf ("skipping, %d fonts, %d dirs\n",
@@ -244,14 +245,12 @@ scanDirs (FcStrList *list, FcConfig *con
 
 	    /* This is the only reason we can't combine 
 	     * Valid w/HasCurrentArch... */
-            if (!FcDirCacheValid (dir))
+            if (!FcDirCacheValid (dir, config))
                 if (!FcDirCacheUnlink (dir, config))
                     ret++;
 
 	    if (!FcDirSave (set, subdirs, dir))
 	    {
-                if (!ret)
-                    fprintf (stderr, "Caches are currently saved to \"%s\"\n", PKGCACHEDIR);
 		fprintf (stderr, "Can't save cache for \"%s\"\n", dir);
 		ret++;
 	    }
Index: fontconfig/fontconfig.h
===================================================================
RCS file: /cvs/fontconfig/fontconfig/fontconfig/fontconfig.h,v
retrieving revision 1.69.2.21
diff -u -p -r1.69.2.21 fontconfig.h
--- fontconfig/fontconfig.h	19 Apr 2006 16:17:19 -0000	1.69.2.21
+++ fontconfig/fontconfig.h	28 Apr 2006 07:28:41 -0000
@@ -276,10 +276,10 @@ typedef struct _FcStrSet    FcStrSet;
 _FCFUNCPROTOBEGIN
 
 FcBool
-FcDirCacheValid (const FcChar8 *cache_file);
+FcDirCacheValid (const FcChar8 *cache_file, FcConfig *config);
 
 FcBool
-FcDirCacheHasCurrentArch (const FcChar8 *dir);
+FcDirCacheHasCurrentArch (const FcChar8 *dir, FcConfig *config);
 
 FcBool
 FcDirCacheUnlink (const FcChar8 *dir, FcConfig *config);
Index: src/Makefile.am
===================================================================
RCS file: /cvs/fontconfig/fontconfig/src/Makefile.am,v
retrieving revision 1.12.4.7
diff -u -p -r1.12.4.7 Makefile.am
--- src/Makefile.am	25 Apr 2006 15:33:07 -0000	1.12.4.7
+++ src/Makefile.am	28 Apr 2006 04:54:09 -0000
@@ -1,5 +1,5 @@
 #
-# $Id: Makefile.am,v 1.12.4.7 2006-04-25 15:33:07 plam Exp $
+# $Id: Makefile.am,v 1.12.4.7 2006/04/25 15:33:07 plam Exp $
 #
 # Copyright © 2003 Keith Packard
 #
@@ -63,8 +63,6 @@ uninstall-ms-import-lib:
 
 endif
 
-AM_CPPFLAGS = -DPKGCACHEDIR='"${pkgcachedir}"'
-
 INCLUDES = 						\
 	-I$(top_srcdir)					\
 	-I$(top_srcdir)/src				\
@@ -72,6 +70,7 @@ INCLUDES = 						\
 	$(LIBXML2_CFLAGS)				\
 	$(EXPAT_CFLAGS)					\
 	$(WARN_CFLAGS)					\
+	-DFC_CACHEDIR='"$(FC_CACHEDIR)"'		\
 	-DFONTCONFIG_PATH='"$(CONFDIR)"'
 
 EXTRA_DIST = fontconfig.def.in
Index: src/fccache.c
===================================================================
RCS file: /cvs/fontconfig/fontconfig/src/fccache.c,v
retrieving revision 1.23.4.88
diff -u -p -r1.23.4.88 fccache.c
--- src/fccache.c	27 Apr 2006 07:11:44 -0000	1.23.4.88
+++ src/fccache.c	28 Apr 2006 08:05:19 -0000
@@ -45,10 +45,7 @@
 #endif
 
 static int
-FcDirCacheOpen (const FcChar8 * dir);
-
-static char *
-FcDirCacheHashName (const FcChar8 * dir, int collisions);
+FcDirCacheOpen (FcConfig *config, const FcChar8 *dir, FcChar8 **cache_path);
 
 static off_t
 FcCacheSkipToArch (int fd, const char * arch);
@@ -746,7 +743,7 @@ FcCacheCopyOld (int fd, int fd_orig, off
  * cache, and the hashed location has an up-to-date cache.  Oh well,
  * sucks to be you in that case! */
 FcBool
-FcDirCacheValid (const FcChar8 *dir)
+FcDirCacheValid (const FcChar8 *dir, FcConfig *config)
 {
     struct stat file_stat, dir_stat;
     int 	fd;
@@ -754,7 +751,7 @@ FcDirCacheValid (const FcChar8 *dir)
     if (stat ((char *) dir, &dir_stat) < 0)
         return FcFalse;
 
-    fd = FcDirCacheOpen (dir);
+    fd = FcDirCacheOpen (config, dir, NULL);
 
     if (fd < 0)
 	return FcFalse;
@@ -780,7 +777,7 @@ FcDirCacheValid (const FcChar8 *dir)
 /* Assumes that the cache file in 'dir' exists.
  * Checks that the cache has the appropriate arch section. */
 FcBool
-FcDirCacheHasCurrentArch (const FcChar8 *dir)
+FcDirCacheHasCurrentArch (const FcChar8 *dir, FcConfig *config)
 {
     int 	fd;
     off_t	current_arch_start;
@@ -788,7 +785,7 @@ FcDirCacheHasCurrentArch (const FcChar8 
     FcCache	metadata;
     char 	subdirName[FC_MAX_FILE_LEN + 1 + 12 + 1];
 
-    fd = FcDirCacheOpen (dir);
+    fd = FcDirCacheOpen (config, dir, NULL);
     if (fd < 0)
 	goto bail;
 
@@ -825,57 +822,81 @@ FcDirCacheHasCurrentArch (const FcChar8 
     return FcFalse;
 }
 
-FcBool
-FcDirCacheUnlink (const FcChar8 *dir, FcConfig *config)
+#define CACHEBASE_LEN (1 + 32 + sizeof (FC_CACHE_SUFFIX))
+
+static const char bin2hex[] = { '0', '1', '2', '3',
+				'4', '5', '6', '7',
+				'8', '9', 'a', 'b',
+				'c', 'd', 'e', 'f' };
+
+static FcChar8 *
+FcDirCacheBasename (const FcChar8 * dir, FcChar8 cache_base[CACHEBASE_LEN])
 {
-    char	*cache_hashed = 0;
-    int		fd, collisions;
-    struct stat	cache_stat;
-    char	dir_buf[FC_MAX_FILE_LEN];
+    unsigned char 	hash[16];
+    FcChar8		*hex_hash;
+    int			cnt;
+    struct MD5Context 	ctx;
 
-    dir = FcConfigNormalizeFontDir (config, dir);
+    MD5Init (&ctx);
+    MD5Update (&ctx, (unsigned char *)dir, strlen ((char *) dir));
 
-    /* Remove any applicable hashed files. */
-    fd = -1; collisions = 0;
-    do
+    MD5Final (hash, &ctx);
+
+    cache_base[0] = '/';
+    hex_hash = cache_base + 1;
+    for (cnt = 0; cnt < 16; ++cnt)
     {
-	if (cache_hashed)
-	    FcStrFree ((FcChar8 *)cache_hashed);
+	hex_hash[2*cnt  ] = bin2hex[hash[cnt] >> 4];
+	hex_hash[2*cnt+1] = bin2hex[hash[cnt] & 0xf];
+    }
+    hex_hash[2*cnt] = 0;
+    strcat ((char *) cache_base, FC_CACHE_SUFFIX);
 
-	cache_hashed = FcDirCacheHashName (dir, collisions++);
-	if (!cache_hashed)
-	    goto bail;
+    return cache_base;
+}
 
-	if (fd > 0)
-	    close (fd);
-	fd = open(cache_hashed, O_RDONLY | O_BINARY);
-	if (fd == -1)
-	{
-	    FcStrFree ((FcChar8 *)cache_hashed);
-	    return FcTrue;
-	}
+FcBool
+FcDirCacheUnlink (const FcChar8 *dir, FcConfig *config)
+{
+    int		fd = -1;
+    FcChar8	*cache_hashed = NULL;
+    FcChar8	cache_base[CACHEBASE_LEN];
+    FcStrList	*list;
+    FcChar8	*cache_dir;
+    char	dir_buf[FC_MAX_FILE_LEN];
 
-	if (!FcCacheReadString (fd, dir_buf, sizeof (dir_buf)) || !strlen(dir_buf))
-	{
-	    FcStrFree ((FcChar8 *)cache_hashed);
-	    goto bail;
-	}
-    } while (strcmp ((char *) dir_buf, (char *) dir) != 0);
+    dir = FcConfigNormalizeFontDir (config, dir);
 
-    close (fd);
+    FcDirCacheBasename (dir, cache_base);
 
-    if (stat ((char *) cache_hashed, &cache_stat) == 0 &&
-	unlink ((char *)cache_hashed) != 0)
+    list = FcStrListCreate (config->cacheDirs);
+    if (!list)
+        return FcFalse;
+	
+    while ((cache_dir = FcStrListNext (list)))
     {
-	FcStrFree ((FcChar8 *)cache_hashed);
-	goto bail;
+        cache_hashed = FcStrPlus (cache_dir, cache_base);
+        if (!cache_hashed)
+	    break;
+        fd = open((char *) cache_hashed, O_RDONLY | O_BINARY);
+    	FcStrFree (cache_hashed);
+        if (fd >= 0) 
+	{
+	    if (FcCacheReadString (fd, dir_buf, sizeof (dir_buf)) &&
+		strcmp (dir_buf, (char *) dir) == 0)
+	    {
+		close (fd);
+		if (unlink ((char *) cache_hashed) < 0)
+		    break;
+	    } else
+		close (fd);
+	}
     }
-
-    FcStrFree ((FcChar8 *)cache_hashed);
+    FcStrListDone (list);
+    /* return FcFalse if something went wrong */
+    if (cache_dir)
+	return FcFalse;
     return FcTrue;
-
- bail:
-    return FcFalse;
 }
 
 static int
@@ -947,8 +968,8 @@ FcCacheReadDirs (FcConfig * config, FcGl
 	    FcStrSetDestroy (subdirs);
 	    continue;
 	}
-	if (FcDirCacheValid (dir) && 
-	    FcDirCacheHasCurrentArch (dir) && 
+	if (FcDirCacheValid (dir, config) && 
+	    FcDirCacheHasCurrentArch (dir, config) && 
 	    FcDirCacheRead (set, subdirs, dir, config))
 	{
 	    /* if an old entry is found in the global cache, disable it */
@@ -1007,87 +1028,53 @@ FcCacheRead (FcConfig *config, FcGlobalC
     return 0;
 }
 
-static const char bin2hex[] = { '0', '1', '2', '3',
-				'4', '5', '6', '7',
-				'8', '9', 'a', 'b',
-				'c', 'd', 'e', 'f' };
-
-static char *
-FcDirCacheHashName (const FcChar8 * dir, int collisions)
-{
-    unsigned char 	hash[16], hex_hash[33];
-    char 		*cache_hashed;
-    unsigned char	uscore = '_';
-    int			cnt, i;
-    FcChar8 		*tmp;
-    struct MD5Context 	ctx;
-
-    MD5Init (&ctx);
-    MD5Update (&ctx, (unsigned char *)dir, strlen ((char *) dir));
-
-    for (i = 0; i < collisions; i++)
-	MD5Update (&ctx, &uscore, 1);
-
-    MD5Final (hash, &ctx);
-
-    for (cnt = 0; cnt < 16; ++cnt)
-    {
-	hex_hash[2*cnt] = bin2hex[hash[cnt] >> 4];
-	hex_hash[2*cnt+1] = bin2hex[hash[cnt] & 0xf];
-    }
-    hex_hash[32] = 0;
-
-    tmp = FcStrPlus ((FcChar8 *)hex_hash, (FcChar8 *)FC_CACHE_SUFFIX);
-    if (!tmp)
-	return 0;
-
-    cache_hashed = (char *)FcStrPlus ((FcChar8 *)PKGCACHEDIR"/", tmp);
-    free (tmp);
-
-    return cache_hashed;
-}
-
-/* Opens the hashed name for cache_file.
- * This would fail in the unlikely event of a collision and subsequent
- * removal of the file which originally caused the collision. */
+/* Opens the cache file for 'dir' for reading.
+ * This searches the list of cache dirs for the relevant cache file,
+ * returning the first one found.
+ */
 static int
-FcDirCacheOpen (const FcChar8 *dir)
+FcDirCacheOpen (FcConfig *config, const FcChar8 *dir, FcChar8 **cache_path)
 {
-    FcBool	found;
-    int		fd = -1, collisions = 0;
-    char	*cache_hashed;
+    int		fd = -1;
+    FcChar8	*cache_hashed = NULL;
+    FcChar8	cache_base[CACHEBASE_LEN];
+    FcStrList	*list;
+    FcChar8	*cache_dir;
     char	dir_buf[FC_MAX_FILE_LEN];
-    struct stat dir_stat;
 
-    if (stat ((char *)dir, &dir_stat) == -1)
-	return -1;
+    FcDirCacheBasename (dir, cache_base);
 
-    found = FcFalse;
-    do
+    list = FcStrListCreate (config->cacheDirs);
+    if (!list)
+        return -1;
+	
+    while ((cache_dir = FcStrListNext (list)))
     {
-	struct stat 	c;
-
-	if (fd >= 0)
-	    close (fd);
-
-	cache_hashed = FcDirCacheHashName (dir, collisions++);
-	if (!cache_hashed)
-	    return -1;
-
-	fd = open(cache_hashed, O_RDONLY | O_BINARY);
-	FcStrFree ((FcChar8 *)cache_hashed);
-
-	if (fd == -1)
+        cache_hashed = FcStrPlus (cache_dir, cache_base);
+        if (!cache_hashed)
 	    break;
-	if (!FcCacheReadString (fd, dir_buf, sizeof (dir_buf)) || 
-	    !strlen(dir_buf))
+        fd = open((char *) cache_hashed, O_RDONLY | O_BINARY);
+        if (fd >= 0)
 	    break;
+	FcStrFree (cache_hashed);
+    }
+    FcStrListDone (list);
 
-	if (stat ((char *)dir_buf, &c) == -1)
-	    continue;
-
-	found = (c.st_ino == dir_stat.st_ino) && (c.st_dev == dir_stat.st_dev);
-    } while (!found);
+    if (fd < 0)
+	return -1;
+    
+    if (!FcCacheReadString (fd, dir_buf, sizeof (dir_buf)) ||
+	strcmp (dir_buf, (char *) dir) != 0)
+    {
+    	close (fd);
+        FcStrFree (cache_hashed);
+        return -1;
+    }
+    
+    if (cache_path)
+	*cache_path = cache_hashed;
+    else
+	FcStrFree (cache_hashed);
 
     return fd;
 }
@@ -1102,7 +1089,7 @@ FcDirCacheRead (FcFontSet * set, FcStrSe
     off_t 	current_arch_start = 0;
     char 	subdirName[FC_MAX_FILE_LEN + 1 + 12 + 1];
 
-    fd = FcDirCacheOpen (dir);
+    fd = FcDirCacheOpen (config, dir, NULL);
     if (fd < 0)
 	goto bail;
 
@@ -1276,56 +1263,77 @@ FcDirCacheProduce (FcFontSet *set, FcCac
     return 0;
 }
 
+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, W_OK|X_OK) == 0)
+	ret = mkdir ((char *) dir, 0777) == 0;
+    else if (access ((char *) parent, F_OK) == -1)
+	ret = FcMakeDirectory (parent) && (mkdir ((char *) dir, 0777) == 0);
+    else
+	ret = FcFalse;
+    FcStrFree (parent);
+    return ret;
+}
+
 /* write serialized state to the cache file */
 FcBool
-FcDirCacheWrite (FcFontSet *set, FcStrSet *dirs, const FcChar8 *dir)
+FcDirCacheWrite (FcFontSet *set, FcStrSet *dirs, const FcChar8 *dir, FcConfig *config)
 {
-    char	    *cache_hashed;
+    FcChar8	    cache_base[CACHEBASE_LEN];
+    FcChar8	    *cache_hashed;
     int 	    fd, fd_orig, i, dirs_count;
     FcAtomic 	    *atomic;
     FcCache 	    metadata;
     off_t 	    current_arch_start = 0, truncate_to;
-    char	    dir_buf[FC_MAX_FILE_LEN];
-    int		    collisions;
-
+    FcStrList	    *list;
     char            *current_arch_machine_name, * header;
     void 	    *current_dir_block = 0;
+    FcChar8	    *cache_dir;
 
     dir = FcConfigNormalizeFontDir (FcConfigGetCurrent(), dir);
     if (!dir)
 	return FcFalse;
 
-    /* Ensure that we're not trampling a cache for some other dir. */
-    /* This is slightly different from FcDirCacheOpen, since it 
-     * needs the filename, not the file descriptor. */
-    fd = -1; collisions = 0;
-    do
-    {
-	cache_hashed = FcDirCacheHashName (dir, collisions++);
-	if (!cache_hashed)
-	    goto bail0;
-
-	if (fd > 0)
-	    close (fd);
-	fd = open(cache_hashed, O_RDONLY | O_BINARY);
-	if (fd == -1)
-	    break;
-	if(!FcCacheReadString (fd, dir_buf, sizeof (dir_buf)) || !strlen(dir_buf))
-	{
-	    close (fd);
-            FcStrFree ((FcChar8 *)cache_hashed);
-	    continue;
-	}
-	close (fd);
-
-	if (strcmp (dir_buf, (char *) dir) != 0) 
-        {
-            FcStrFree ((FcChar8 *)cache_hashed);
-	    continue;
-        }
+    /*
+     * Check for an existing cache file and dump stuff in the same place
+     */
+    fd = FcDirCacheOpen (config, dir, &cache_hashed);
 
-	break;
-    } while (1);
+    if (fd >= 0)
+	close (fd);
+    else {
+	list = FcStrListCreate (config->cacheDirs);
+	if (!list)
+	    return FcFalse;
+	while ((cache_dir = FcStrListNext (list))) {
+	    if (access ((char *) cache_dir, W_OK|X_OK) == 0)
+		break;
+	    /*
+	     * If the directory doesn't exist, try to create it
+	     */
+	    if (access ((char *) cache_dir, F_OK) == -1) {
+		if (FcMakeDirectory (cache_dir))
+		    break;
+	    }
+	}
+	FcStrListDone (list);
+	if (!cache_dir)
+	    return FcFalse;
+	FcDirCacheBasename (dir, cache_base);
+        cache_hashed = FcStrPlus (cache_dir, cache_base);
+        if (!cache_hashed)
+	    return FcFalse;
+    }
 
     current_dir_block = FcDirCacheProduce (set, &metadata);
 
@@ -1453,7 +1461,6 @@ FcDirCacheWrite (FcFontSet *set, FcStrSe
     FcAtomicDestroy (atomic);
  bail1:
     FcStrFree ((FcChar8 *)cache_hashed);
- bail0:
     if (current_dir_block)
         free (current_dir_block);
     return FcFalse;
Index: src/fccfg.c
===================================================================
RCS file: /cvs/fontconfig/fontconfig/src/fccfg.c,v
retrieving revision 1.49.2.29
diff -u -p -r1.49.2.29 fccfg.c
--- src/fccfg.c	25 Apr 2006 05:57:41 -0000	1.49.2.29
+++ src/fccfg.c	28 Apr 2006 04:49:28 -0000
@@ -22,9 +22,9 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include "fcint.h"
 #include <dirent.h>
 #include <sys/types.h>
+#include "fcint.h"
 
 #if defined (_WIN32) && (defined (PIC) || defined (DLL_EXPORT))
 #define STRICT
@@ -100,13 +100,17 @@ FcConfigCreate (void)
 	    if (!FcConfigSetCache (config, cache_dir))
 	    {
 		FcStrFree (cache_dir);
-		goto bail6;
+		goto bail7;
 	    }
 	    FcStrFree (cache_dir);
 	}
     }
 #endif
 
+    config->cacheDirs = FcStrSetCreate ();
+    if (!config->cacheDirs)
+	goto bail9;
+    
     config->blanks = 0;
 
     config->substPattern = 0;
@@ -120,6 +124,8 @@ FcConfigCreate (void)
     
     return config;
 
+bail9:
+    FcStrFree (config->cache);
 bail8:
     FcFontSetDestroy (config->rejectPatterns);
 bail7:
@@ -226,6 +232,7 @@ FcConfigDestroy (FcConfig *config)
 
     FcStrSetDestroy (config->configDirs);
     FcStrSetDestroy (config->fontDirs);
+    FcStrSetDestroy (config->cacheDirs);
     FcStrSetDestroy (config->configFiles);
     FcStrSetDestroy (config->acceptGlobs);
     FcStrSetDestroy (config->rejectGlobs);
@@ -513,6 +520,25 @@ FcConfigGetFontDirs (FcConfig	*config)
 }
 
 FcBool
+FcConfigAddCacheDir (FcConfig	    *config,
+		     const FcChar8  *d)
+{
+    return FcStrSetAddFilename (config->cacheDirs, d);
+}
+
+FcStrList *
+FcConfigGetCacheDirs (FcConfig	*config)
+{
+    if (!config)
+    {
+	config = FcConfigGetCurrent ();
+	if (!config)
+	    return 0;
+    }
+    return FcStrListCreate (config->cacheDirs);
+}
+    
+FcBool
 FcConfigAddConfigFile (FcConfig	    *config,
 		       const FcChar8   *f)
 {
Index: src/fcdir.c
===================================================================
RCS file: /cvs/fontconfig/fontconfig/src/fcdir.c,v
retrieving revision 1.20.4.19
diff -u -p -r1.20.4.19 fcdir.c
--- src/fcdir.c	10 Apr 2006 16:06:42 -0000	1.20.4.19
+++ src/fcdir.c	28 Apr 2006 07:34:56 -0000
@@ -151,8 +151,8 @@ FcDirScanConfig (FcFontSet	*set,
 	if (cache && FcGlobalCacheReadDir (set, dirs, cache, (char *)dir, config))
 	    return FcTrue;
 
-	if (FcDirCacheValid (dir) && 
-	    FcDirCacheHasCurrentArch (dir) &&
+	if (FcDirCacheValid (dir, config) && 
+	    FcDirCacheHasCurrentArch (dir, config) &&
 	    FcDirCacheRead (set, dirs, dir, config))
 	    return FcTrue;
     }
@@ -277,5 +277,5 @@ FcDirScan (FcFontSet	    *set,
 FcBool
 FcDirSave (FcFontSet *set, FcStrSet * dirs, const FcChar8 *dir)
 {
-    return FcDirCacheWrite (set, dirs, dir);
+    return FcDirCacheWrite (set, dirs, dir, FcConfigGetCurrent ());
 }
Index: src/fcinit.c
===================================================================
RCS file: /cvs/fontconfig/fontconfig/src/fcinit.c,v
retrieving revision 1.12.4.7
diff -u -p -r1.12.4.7 fcinit.c
--- src/fcinit.c	27 Apr 2006 07:54:07 -0000	1.12.4.7
+++ src/fcinit.c	28 Apr 2006 04:52:46 -0000
@@ -35,6 +35,8 @@ FcInitFallbackConfig (void)
 	goto bail0;
     if (!FcConfigAddDir (config, (FcChar8 *) FC_DEFAULT_FONTS))
 	goto bail1;
+    if (!FcConfigAddCacheDir (config, (FcChar8 *) FC_CACHEDIR))
+	goto bail1;
     return config;
 
 bail1:
Index: src/fcint.h
===================================================================
RCS file: /cvs/fontconfig/fontconfig/src/fcint.h,v
retrieving revision 1.47.4.44
diff -u -p -r1.47.4.44 fcint.h
--- src/fcint.h	27 Apr 2006 07:54:07 -0000	1.47.4.44
+++ src/fcint.h	28 Apr 2006 07:33:21 -0000
@@ -389,6 +389,10 @@ struct _FcConfig {
      */
     FcStrSet	*fontDirs;
     /*
+     * List of directories containing cache files.
+     */
+    FcStrSet	*cacheDirs;
+    /*
      * Names of all of the configuration files used
      * to create this configuration
      */
@@ -476,7 +480,7 @@ FcFontSet *
 FcCacheRead (FcConfig *config, FcGlobalCache * cache);
 
 FcBool
-FcDirCacheWrite (FcFontSet *set, FcStrSet * dirs, const FcChar8 *dir);
+FcDirCacheWrite (FcFontSet *set, FcStrSet * dirs, const FcChar8 *dir, FcConfig *config);
 
 FcBool
 FcDirCacheRead (FcFontSet * set, FcStrSet * dirs, const FcChar8 *dir, FcConfig *config);
@@ -509,6 +513,13 @@ FcConfigAddDir (FcConfig	*config,
 		const FcChar8	*d);
 
 FcBool
+FcConfigAddCacheDir (FcConfig	    *config,
+		     const FcChar8  *d);
+
+FcStrList *
+FcConfigGetCacheDirs (FcConfig	*config);
+
+FcBool
 FcConfigAddConfigFile (FcConfig		*config,
 		       const FcChar8	*f);
 
Index: src/fcxml.c
===================================================================
RCS file: /cvs/fontconfig/fontconfig/src/fcxml.c,v
retrieving revision 1.37.4.22
diff -u -p -r1.37.4.22 fcxml.c
--- src/fcxml.c	27 Apr 2006 07:54:07 -0000	1.37.4.22
+++ src/fcxml.c	28 Apr 2006 07:35:24 -0000
@@ -285,6 +285,7 @@ typedef enum _FcElement {
     FcElementNone,
     FcElementFontconfig,
     FcElementDir,
+    FcElementCacheDir,
     FcElementCache,
     FcElementInclude,
     FcElementConfig,
@@ -345,6 +346,7 @@ static const struct {
 } fcElementMap[] = {
     { "fontconfig",	FcElementFontconfig },
     { "dir",		FcElementDir },
+    { "cachedir",	FcElementCacheDir },
     { "cache",		FcElementCache },
     { "include",	FcElementInclude },
     { "config",		FcElementConfig },
@@ -2053,6 +2055,21 @@ FcEndElement(void *userData, const XML_C
 	}
 	FcStrFree (data);
 	break;
+    case FcElementCacheDir:
+	data = FcStrBufDone (&parse->pstack->str);
+	if (!data)
+	{
+	    FcConfigMessage (parse, FcSevereError, "out of memory");
+	    break;
+	}
+	if (!FcStrUsesHome (data) || FcConfigHome ())
+	{
+	    if (!FcConfigAddCacheDir (parse->config, data))
+		FcConfigMessage (parse, FcSevereError, "out of memory; cannot add cache directory %s", data);
+	}
+	FcStrFree (data);
+	break;
+	
     case FcElementCache:
 	data = FcStrBufDone (&parse->pstack->str);
 	if (!data)
Index: test/fonts.conf.in
===================================================================
RCS file: /cvs/fontconfig/fontconfig/test/fonts.conf.in,v
retrieving revision 1.1
diff -u -p -r1.1 fonts.conf.in
--- test/fonts.conf.in	1 Mar 2003 05:54:42 -0000	1.1
+++ test/fonts.conf.in	28 Apr 2006 08:08:01 -0000
@@ -1,4 +1,5 @@
 <fontconfig>
 <dir>@FONTDIR@</dir>
 <cache>@CACHEFILE@</cache>
+<cachedir>@CACHEDIR@</cachedir>
 </fontconfig>
Index: test/run-test.sh
===================================================================
RCS file: /cvs/fontconfig/fontconfig/test/run-test.sh,v
retrieving revision 1.3
diff -u -p -r1.3 run-test.sh
--- test/run-test.sh	27 Oct 2003 10:44:13 -0000	1.3
+++ test/run-test.sh	28 Apr 2006 08:08:19 -0000
@@ -3,6 +3,7 @@ TESTDIR=${srcdir-`pwd`}
 
 FONTDIR=`pwd`/fonts
 CACHEFILE=`pwd`/fonts.cache
+CACHEDIR=`pwd`/cache.dir
 
 ECHO=true
 
@@ -39,7 +40,8 @@ dotest () {
 }
 
 sed "s!@FONTDIR@!$FONTDIR!
-s!@CACHEFILE@!$CACHEFILE!" < $TESTDIR/fonts.conf.in > fonts.conf
+s!@CACHEFILE@!$CACHEFILE!
+s!@CACHEDIR@!$CACHEDIR!" < $TESTDIR/fonts.conf.in > fonts.conf
 
 FONTCONFIG_FILE=`pwd`/fonts.conf
 export FONTCONFIG_FILE
@@ -89,4 +91,4 @@ mkdir $FONTDIR/a
 cp $FONT2 $FONTDIR/a
 check
 
-rm -rf $FONTDIR $CACHEFILE $FONTCONFIG_FILE out
+rm -rf $FONTDIR $CACHEFILE $CACHEDIR $FONTCONFIG_FILE out

-- 
keith.packard at intel.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: This is a digitally signed message part
Url : http://lists.freedesktop.org/archives/fontconfig/attachments/20060428/5b5af386/attachment-0001.pgp


More information about the Fontconfig mailing list