]> git.wh0rd.org - fontconfig.git/blobdiff - src/fccache.c
Change files from ISO-Latin-1 to UTF-8
[fontconfig.git] / src / fccache.c
index 3bf0de9c3fcfb4c0066058c602d99c6eecb482e9..9e47e86121d7901604027141fa7fea1db14f61a4 100644 (file)
@@ -1,7 +1,7 @@
 /*
- * $XFree86: xc/lib/fontconfig/src/fccache.c,v 1.12 2002/08/22 07:36:44 keithp Exp $
+ * $RCSId: xc/lib/fontconfig/src/fccache.c,v 1.12 2002/08/22 07:36:44 keithp Exp $
  *
- * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc.
+ * Copyright © 2000 Keith Packard
  *
  * Permission to use, copy, modify, distribute, and sell this software and its
  * documentation for any purpose is hereby granted without fee, provided that
@@ -188,9 +188,19 @@ FcCacheWritePath (FILE *f, const FcChar8 *dir, const FcChar8 *file)
     if (dir)
        if (!FcCacheWriteChars (f, dir))
            return FcFalse;
+#ifdef _WIN32
+    if (dir &&
+       dir[strlen((const char *) dir) - 1] != '/' &&
+       dir[strlen((const char *) dir) - 1] != '\\')
+    {
+       if (!FcCacheWriteChars (f, "\\"))
+           return FcFalse;
+    }
+#else
     if (dir && dir[strlen((const char *) dir) - 1] != '/')
        if (PUTC ('/', f) == EOF)
            return FcFalse;
+#endif
     if (!FcCacheWriteChars (f, file))
        return FcFalse;
     if (PUTC ('"', f) == EOF)
@@ -241,7 +251,8 @@ FcCacheFontSetAdd (FcFontSet            *set,
                   const FcChar8    *dir,
                   int              dir_len,
                   const FcChar8    *file,
-                  const FcChar8    *name)
+                  const FcChar8    *name,
+                  FcConfig         *config)
 {
     FcChar8    path_buf[8192], *path;
     int                len;
@@ -258,10 +269,17 @@ FcCacheFontSetAdd (FcFontSet          *set,
            return FcFalse;
     }
     strncpy ((char *) path, (const char *) dir, dir_len);
+#ifdef _WIN32
+    if (dir[dir_len - 1] != '/' && dir[dir_len - 1] != '\\' )
+       path[dir_len++] = '\\';
+#else
     if (dir[dir_len - 1] != '/')
        path[dir_len++] = '/';
+#endif
     strcpy ((char *) path + dir_len, (const char *) file);
-    if (!FcStrCmp (name, FC_FONT_FILE_DIR))
+    if (config && !FcConfigAcceptFilename (config, path))
+       ret = FcTrue;
+    else if (!FcStrCmp (name, FC_FONT_FILE_DIR))
     {
        if (FcDebug () & FC_DBG_CACHEV)
            printf (" dir cache dir \"%s\"\n", path);
@@ -279,7 +297,7 @@ FcCacheFontSetAdd (FcFontSet            *set,
            if (FcDebug () & FC_DBG_CACHEV)
                printf (" dir cache file \"%s\"\n", file);
            ret = FcPatternAddString (font, FC_FILE, path);
-           if (ret)
+           if (ret && (!config || FcConfigAcceptFont (config, font)))
            {
                frozen = FcPatternFreeze (font);
                ret = (frozen != 0);
@@ -295,28 +313,28 @@ FcCacheFontSetAdd (FcFontSet          *set,
 }
 
 static unsigned int
-FcCacheHash (const FcChar8 *string)
+FcCacheHash (const FcChar8 *string, int len)
 {
     unsigned int    h = 0;
     FcChar8        c;
 
-    while ((c = *string++))
+    while (len-- && (c = *string++))
        h = (h << 1) ^ c;
-    return 0;
+    return h;
 }
 
 /*
  * Verify the saved timestamp for a file
  */
 FcBool
-FcGlobalCacheCheckTime (FcGlobalCacheInfo *info)
+FcGlobalCacheCheckTime (const FcChar8 *file, FcGlobalCacheInfo *info)
 {
     struct stat            statb;
 
-    if (stat ((char *) info->file, &statb) < 0)
+    if (stat ((char *) file, &statb) < 0)
     {
        if (FcDebug () & FC_DBG_CACHE)
-           printf (" file missing\n");
+           printf (" file %s missing\n", file);
        return FcFalse;
     }
     if (statb.st_mtime != info->time)
@@ -361,7 +379,7 @@ FcFilePathInfoGet (const FcChar8    *path)
     FcFilePathInfo  i;
     FcChar8        *slash;
 
-    slash = (FcChar8 *) strrchr ((const char *) path, '/');
+    slash = FcStrLastSlash (path);
     if (slash)
     {
         i.dir = path;
@@ -376,7 +394,7 @@ FcFilePathInfoGet (const FcChar8    *path)
        i.dir_len = 1;
        i.base = path;
     }
-    i.base_hash = FcCacheHash (i.base);
+    i.base_hash = FcCacheHash (i.base, -1);
     return i;
 }
 
@@ -386,7 +404,7 @@ FcGlobalCacheDirGet (FcGlobalCache  *cache,
                     int            len,
                     FcBool         create_missing)
 {
-    unsigned int       hash = FcCacheHash (dir);
+    unsigned int       hash = FcCacheHash (dir, len);
     FcGlobalCacheDir   *d, **prev;
 
     for (prev = &cache->ents[hash % FC_GLOBAL_CACHE_DIR_HASH_SIZE];
@@ -427,13 +445,29 @@ static FcGlobalCacheInfo *
 FcGlobalCacheDirAdd (FcGlobalCache  *cache,
                     const FcChar8  *dir,
                     time_t         time,
-                    FcBool         replace)
+                    FcBool         replace,
+                    FcBool         create_missing)
 {
     FcGlobalCacheDir   *d;
     FcFilePathInfo     i;
     FcGlobalCacheSubdir        *subdir;
     FcGlobalCacheDir   *parent;
 
+    i = FcFilePathInfoGet (dir);
+    parent = FcGlobalCacheDirGet (cache, i.dir, i.dir_len, create_missing);
+    /*
+     * Tricky here -- directories containing fonts.cache-1 files
+     * need entries only when the parent doesn't have a cache file.
+     * That is, when the parent already exists in the cache, is
+     * referenced and has a "real" timestamp.  The time of 0 is
+     * special and marks directories which got stuck in the
+     * global cache for this very reason.  Yes, it could
+     * use a separate boolean field, and probably should.
+     */
+    if (!parent || (!create_missing && 
+                   (!parent->info.referenced ||
+                   (parent->info.time == 0))))
+       return 0;
     /*
      * Add this directory to the cache
      */
@@ -441,21 +475,14 @@ FcGlobalCacheDirAdd (FcGlobalCache  *cache,
     if (!d)
        return 0;
     d->info.time = time;
-    i = FcFilePathInfoGet (dir);
     /*
      * Add this directory to the subdirectory list of the parent
      */
-    parent = FcGlobalCacheDirGet (cache, i.dir, i.dir_len, FcTrue);
-    if (!parent)
-       return 0;
-    subdir = malloc (sizeof (FcGlobalCacheSubdir) + 
-                    strlen ((const char *) i.base) + 1);
+    subdir = malloc (sizeof (FcGlobalCacheSubdir));
     if (!subdir)
        return 0;
-    FcMemAlloc (FC_MEM_CACHE, sizeof (FcGlobalCacheSubdir) +
-               strlen ((const char *) i.base) + 1);
-    subdir->file = (FcChar8 *) (subdir + 1);
-    strcpy ((char *) subdir->file, (const char *) i.base);
+    FcMemAlloc (FC_MEM_CACHE, sizeof (FcGlobalCacheSubdir));
+    subdir->ent = d;
     subdir->next = parent->subdirs;
     parent->subdirs = subdir;
     return &d->info;
@@ -480,19 +507,43 @@ FcGlobalCacheDirDestroy (FcGlobalCacheDir *d)
     for (s = d->subdirs; s; s = nexts)
     {
        nexts = s->next;
-       FcMemFree (FC_MEM_CACHE, sizeof (FcGlobalCacheSubdir) +
-                  strlen ((char *) s->file) + 1);
+       FcMemFree (FC_MEM_CACHE, sizeof (FcGlobalCacheSubdir));
        free (s);
     }
     FcMemFree (FC_MEM_CACHE, sizeof (FcGlobalCacheDir) + d->len + 1);
     free (d);
 }
 
+/*
+ * If the parent is in the global cache and referenced, add
+ * an entry for 'dir' to the global cache.  This is used
+ * for directories with fonts.cache files
+ */
+
+void
+FcGlobalCacheReferenceSubdir (FcGlobalCache *cache,
+                             const FcChar8 *dir)
+{
+    FcGlobalCacheInfo  *info;
+    info = FcGlobalCacheDirAdd (cache, dir, 0, FcFalse, FcFalse);
+    if (info && !info->referenced)
+    {
+       info->referenced = FcTrue;
+       cache->referenced++;
+    }
+}
+
+/*
+ * Check to see if the global cache contains valid data for 'dir'.
+ * If so, scan the global cache for files and directories in 'dir'.
+ * else, return False.
+ */
 FcBool
 FcGlobalCacheScanDir (FcFontSet                *set,
                      FcStrSet          *dirs,
                      FcGlobalCache     *cache,
-                     const FcChar8     *dir)
+                     const FcChar8     *dir,
+                     FcConfig          *config)
 {
     FcGlobalCacheDir   *d = FcGlobalCacheDirGet (cache, dir,
                                                  strlen ((const char *) dir),
@@ -501,6 +552,7 @@ FcGlobalCacheScanDir (FcFontSet             *set,
     int                        h;
     int                        dir_len;
     FcGlobalCacheSubdir        *subdir;
+    FcBool             any_in_cache = FcFalse;
 
     if (FcDebug() & FC_DBG_CACHE)
        printf ("FcGlobalCacheScanDir %s\n", dir);
@@ -512,40 +564,63 @@ FcGlobalCacheScanDir (FcFontSet           *set,
        return FcFalse;
     }
 
-    if (!FcGlobalCacheCheckTime (&d->info))
+    /*
+     * See if the timestamp recorded in the global cache
+     * matches the directory time, if not, return False
+     */
+    if (!FcGlobalCacheCheckTime (d->info.file, &d->info))
     {
        if (FcDebug () & FC_DBG_CACHE)
            printf ("\tdir cache entry time mismatch\n");
        return FcFalse;
     }
 
+    /*
+     * Add files from 'dir' to the fontset
+     */
     dir_len = strlen ((const char *) dir);
     for (h = 0; h < FC_GLOBAL_CACHE_FILE_HASH_SIZE; h++)
        for (f = d->ents[h]; f; f = f->next)
        {
            if (FcDebug() & FC_DBG_CACHEV)
                printf ("FcGlobalCacheScanDir add file %s\n", f->info.file);
+           any_in_cache = FcTrue;
            if (!FcCacheFontSetAdd (set, dirs, dir, dir_len,
-                                   f->info.file, f->name))
+                                   f->info.file, f->name, config))
            {
                cache->broken = FcTrue;
                return FcFalse;
            }
            FcGlobalCacheReferenced (cache, &f->info);
        }
+    /*
+     * Add directories in 'dir' to 'dirs'
+     */
     for (subdir = d->subdirs; subdir; subdir = subdir->next)
     {
+       FcFilePathInfo  info = FcFilePathInfoGet (subdir->ent->info.file);
+       
+        any_in_cache = FcTrue;
        if (!FcCacheFontSetAdd (set, dirs, dir, dir_len,
-                               subdir->file, FC_FONT_FILE_DIR))
+                               info.base, FC_FONT_FILE_DIR, config))
        {
            cache->broken = FcTrue;
            return FcFalse;
        }
+       FcGlobalCacheReferenced (cache, &subdir->ent->info);
     }
     
     FcGlobalCacheReferenced (cache, &d->info);
 
-    return FcTrue;
+    /*
+     * To recover from a bug in previous versions of fontconfig,
+     * return FcFalse if no entries in the cache were found
+     * for this directory.  This will cause any empty directories
+     * to get rescanned every time fontconfig is initialized.  This
+     * might get removed at some point when the older cache files are
+     * presumably fixed.
+     */
+    return any_in_cache;
 }
 
 /*
@@ -577,7 +652,7 @@ FcGlobalCacheFileGet (FcGlobalCache *cache,
        }
     }
     if (count)
-       *count = max;
+       *count = max + 1;
     return match;
 }
     
@@ -714,7 +789,7 @@ FcGlobalCacheLoad (FcGlobalCache    *cache,
        if (FcDebug () & FC_DBG_CACHEV)
            printf ("FcGlobalCacheLoad \"%s\" \"%20.20s\"\n", file, name);
        if (!FcStrCmp (name, FC_FONT_FILE_DIR))
-           info = FcGlobalCacheDirAdd (cache, file, time, FcFalse);
+           info = FcGlobalCacheDirAdd (cache, file, time, FcFalse, FcTrue);
        else
            info = FcGlobalCacheFileAdd (cache, file, id, time, name, FcFalse);
        if (!info)
@@ -754,7 +829,7 @@ FcGlobalCacheUpdate (FcGlobalCache  *cache,
        return FcFalse;
     if (S_ISDIR (statb.st_mode))
        info = FcGlobalCacheDirAdd (cache, file, statb.st_mtime, 
-                                  FcTrue);
+                                   FcTrue, FcTrue);
     else
        info = FcGlobalCacheFileAdd (cache, file, id, statb.st_mtime, 
                                    name, FcTrue);
@@ -784,9 +859,11 @@ FcGlobalCacheSave (FcGlobalCache    *cache,
     if (cache->broken)
        return FcFalse;
 
+#if defined (HAVE_GETUID) && defined (HAVE_GETEUID)
     /* Set-UID programs can't safely update the cache */
     if (getuid () != geteuid ())
        return FcFalse;
+#endif
     
     atomic = FcAtomicCreate (cache_file);
     if (!atomic)
@@ -898,7 +975,7 @@ FcDirCacheValid (const FcChar8 *dir)
 }
 
 FcBool
-FcDirCacheReadDir (FcFontSet *set, FcStrSet *dirs, const FcChar8 *dir)
+FcDirCacheReadDir (FcFontSet *set, FcStrSet *dirs, const FcChar8 *dir, FcConfig *config)
 {
     FcChar8        *cache_file = FcStrPlus (dir, (FcChar8 *) "/" FC_DIR_CACHE_FILE);
     FILE           *f;
@@ -943,7 +1020,7 @@ FcDirCacheReadDir (FcFontSet *set, FcStrSet *dirs, const FcChar8 *dir)
           (name = FcCacheReadString (f, name_buf, sizeof (name_buf))))
     {
        if (!FcCacheFontSetAdd (set, dirs, cache_file, dir_len,
-                               file, name))
+                               file, name, config))
            goto bail3;
        if (file != file_buf)
            free (file);
@@ -977,7 +1054,7 @@ FcFileBaseName (const FcChar8 *cache, const FcChar8 *file)
 {
     const FcChar8   *cache_slash;
 
-    cache_slash = (const FcChar8 *) strrchr ((const char *) cache, '/');
+    cache_slash = FcStrLastSlash (cache);
     if (cache_slash && !strncmp ((const char *) cache, (const char *) file,
                                 (cache_slash + 1) - cache))
        return file + ((cache_slash + 1) - cache);