]> git.wh0rd.org - fontconfig.git/commitdiff
2006-08-04 Keith Packard (keithp@keithp.com) reviewed by: plam
authorPatrick Lam <plam@MIT.EDU>
Fri, 4 Aug 2006 16:13:00 +0000 (16:13 +0000)
committerPatrick Lam <plam@MIT.EDU>
Fri, 4 Aug 2006 16:13:00 +0000 (16:13 +0000)
Make cache directories configurable. Simplify and correct some code which
    deals with per-directory caches.

15 files changed:
ChangeLog
configure.in
fc-cache/fc-cache.c
fontconfig/fontconfig.h
fonts.conf.in
fonts.dtd
src/Makefile.am
src/fccache.c
src/fccfg.c
src/fcdir.c
src/fcinit.c
src/fcint.h
src/fcxml.c
test/fonts.conf.in
test/run-test.sh

index d8e64040fe341b8e154c732f623ac39ec0a3d87b..5e4b1f43e08c178c482e5e0ca581cadd747860d4 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,27 @@
+2006-08-04  Keith Packard  (keithp@keithp.com)
+       reviewed by: plam
+
+       * configure.in:
+       * fonts.conf.in:
+       * fonts.dtd:
+       * fc-cache/fc-cache.c (scanDirs):
+       * fontconfig/fontconfig.h:
+       * src/Makefile.am:
+       * src/fcint.h:
+       * src/fccache.c (FcDirCacheValid, FcDirHasCurrentArch, 
+                        FcDirCacheUnlink, FcDirCacheBasename,
+                        FcCacheReadDirs, FcDirCacheOpen, FcDirCacheRead,
+                        FcMakeDirectory, FcDirCacheWrite):
+       * src/fccfg.c (FcConfigCreate, FcConfigDestroy, FcConfigAddCacheDir,
+                      FcConfigGetCacheDirs):
+       * src/fcdir.c (FcDirScanConfig, FcDirSave):
+       * src/fcinit.c (FcInitFallbackConfig):
+       * src/fcxml.c (fcElementMap, FcEndElement):
+       * test/fonts.conf.in, test/run-test.sh:
+
+       Make cache directories configurable.  Simplify and correct
+       some code which deals with per-directory caches.
+
 2006-07-19  Jon Burgess  (jburgess@uklinux.net)
         reviewed by: plam
 
index acdc1f1dc9c6976c62b2d2552ecb57b0edf85b6a..a3d2c77ca86eb76e00bc0a23cb71e5ce46f2b113 100644 (file)
@@ -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 5e4ada40c0ad91eaa49457e42d681b722cfef7ed..8519388cf37576021876ff8c321cc69a826cc9cc 100644 (file)
@@ -230,7 +230,8 @@ scanDirs (FcStrList *list, FcConfig *config, char *program, FcBool force, FcBool
            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 *config, char *program, FcBool force, FcBool
 
            /* 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 2ddd42fa2982ddf2d6f7035ebd95365d40117828..8ef2f7c4da38c6e6e3e897d5c4130be6866596b0 100644 (file)
@@ -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 3329d7ade55ed5f90531ef905b54e696f4c99310..035ee32cfeb5139263cbe2a3ed167ef017ed0aa9 100644 (file)
        @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 6c9a33df41560db3f87efe68e81a0047cf5df4eb..cd016d3ca9035a10750eccd58b16504bf739c003 100644 (file)
--- a/fonts.dtd
+++ b/fonts.dtd
 <!ELEMENT cache (#PCDATA)>
 <!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
index 01c9c5ef0de94eebbe40294dc0455d17145867bc..5d144bc11485793b7a8d5958a4e31b29431767f6 100644 (file)
@@ -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 a653085e1c3fce5a2bb3c6dfceda7d4194315afe..eb0b64729af5017ba59732329ba0fa765ab61df0 100644 (file)
 #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);
@@ -748,7 +745,7 @@ FcCacheCopyOld (int fd, int fd_orig, off_t start)
  * 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;
@@ -756,7 +753,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;
@@ -782,7 +779,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;
@@ -790,7 +787,7 @@ FcDirCacheHasCurrentArch (const FcChar8 *dir)
     FcCache    metadata;
     char       subdirName[FC_MAX_FILE_LEN + 1 + 12 + 1];
 
-    fd = FcDirCacheOpen (dir);
+    fd = FcDirCacheOpen (config, dir, NULL);
     if (fd < 0)
        goto bail;
 
@@ -827,57 +824,81 @@ FcDirCacheHasCurrentArch (const FcChar8 *dir)
     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
@@ -949,8 +970,8 @@ FcCacheReadDirs (FcConfig * config, FcGlobalCache * cache,
            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 */
@@ -1009,87 +1030,53 @@ FcCacheRead (FcConfig *config, FcGlobalCache * cache)
     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;
 }
@@ -1104,7 +1091,7 @@ FcDirCacheRead (FcFontSet * set, FcStrSet * dirs, const FcChar8 *dir, FcConfig *
     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;
 
@@ -1278,56 +1265,77 @@ FcDirCacheProduce (FcFontSet *set, FcCache *metadata)
     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);
 
@@ -1455,7 +1463,6 @@ FcDirCacheWrite (FcFontSet *set, FcStrSet *dirs, const FcChar8 *dir)
     FcAtomicDestroy (atomic);
  bail1:
     FcStrFree ((FcChar8 *)cache_hashed);
- bail0:
     if (current_dir_block)
         free (current_dir_block);
     return FcFalse;
index 32e0084d9d3894b475f95e2db5611521afd3d76e..8eb82e5a3cac0f7611f4b5ca009ea0a9e834d00e 100644 (file)
@@ -100,13 +100,17 @@ FcConfigCreate (void)
            if (!FcConfigSetCache (config, cache_dir))
            {
                FcStrFree (cache_dir);
-               goto bail6;
+               goto bail8;
            }
            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);
@@ -512,6 +519,25 @@ FcConfigGetFontDirs (FcConfig      *config)
     return FcStrListCreate (config->fontDirs);
 }
 
+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 4463b3130cceba58000af27378d3708b2c3853e8..1545955255ac41139e5c8e1f935b1349a2b89a5d 100644 (file)
@@ -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 ac6dad7996f04cd5b2c7cae3dc581e457c2f04a4..8f60cd8cd2637254927f51c137ee0b89bd649e8a 100644 (file)
@@ -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 6d8ae5ddb1b2b789bcf6dbc0f28aa35cc4b4981f..6a61b3912e8b5c3565672b3a83814a790b96ea76 100644 (file)
@@ -388,6 +388,10 @@ struct _FcConfig {
      * of configured directories
      */
     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);
@@ -508,6 +512,13 @@ FcBool
 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 243819300e3136695923cc6b221dac718ce50c16..c5c90656dbec37fb5435882cba6201ad891ed03a 100644 (file)
@@ -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_Char *name)
        }
        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 492e36faa3366889f1b0d8a69463e0ee4867bd66..5ad85c9e3456fb35cb8e79911b005c3dfae779f5 100644 (file)
@@ -1,4 +1,5 @@
 <fontconfig>
 <dir>@FONTDIR@</dir>
 <cache>@CACHEFILE@</cache>
+<cachedir>@CACHEDIR@</cachedir>
 </fontconfig>
index 428503b3f1f61761679b87e88da6688e6f120ae1..8b817c084a39dc21785d7bf01250c35bdeb326a0 100644 (file)
@@ -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