]> git.wh0rd.org - fontconfig.git/blobdiff - src/fcdir.c
Overhaul the serialization system to create one mmapable file per directory
[fontconfig.git] / src / fcdir.c
index a49cb54bbcf309e30f1047a082bdbb8e5dc49e12..4f69f228bc0688fb98fb65df81b13d3a597f3fb1 100644 (file)
@@ -1,7 +1,7 @@
 /*
- * $XFree86: $
+ * $RCSId: xc/lib/fontconfig/src/fcdir.c,v 1.9 2002/08/31 22:17:32 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
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include <sys/types.h>
-#include <dirent.h>
-#include <stdlib.h>
-#include <string.h>
 #include "fcint.h"
+#include <dirent.h>
 
-#define FC_INVALID_FONT_FILE "."
+FcBool
+FcFileIsDir (const FcChar8 *file)
+{
+    struct stat            statb;
+
+    if (stat ((const char *) file, &statb) != 0)
+       return FcFalse;
+    return S_ISDIR(statb.st_mode);
+}
 
 FcBool
-FcFileScan (FcFontSet  *set,
-           FcFileCache *cache,
-           FcBlanks    *blanks,
-           const char  *file,
-           FcBool      force)
+FcFileScanConfig (FcFontSet    *set,
+                 FcStrSet      *dirs,
+                 FcGlobalCache *cache,
+                 FcBlanks      *blanks,
+                 const FcChar8 *file,
+                 FcBool        force,
+                 FcConfig      *config)
 {
-    int                    id;
-    char           *name;
-    FcPattern      *font;
-    FcBool         ret = FcTrue;
-    int                    count;
+    int                        id;
+#if 0
+    FcChar8            *name;
+    FcGlobalCacheFile  *cache_file;
+    FcGlobalCacheDir   *cache_dir;
+#endif
+    FcPattern          *font;
+    FcBool             ret = FcTrue;
+    FcBool             isDir;
+    int                        count = 0;
+    FcBool             need_scan;
     
+    if (config && !FcConfigAcceptFilename (config, file))
+       return FcTrue;
+
+    if (force)
+       cache = 0;
     id = 0;
     do
     {
-       if (!force && cache)
-           name = FcFileCacheFind (cache, file, id, &count);
-       else
-           name = 0;
-       if (name)
+       need_scan = FcTrue;
+       font = 0;
+#if 0
+       /*
+        * Check the cache
+        */
+       if (cache)
        {
-           /* "." means the file doesn't contain a font */
-           if (strcmp (name, FC_INVALID_FONT_FILE) != 0)
+           if ((cache_file = FcGlobalCacheFileGet (cache, file, id, &count)))
            {
-               font = FcNameParse (name);
-               if (font)
-                   FcPatternAddString (font, FC_FILE, file);
+               /*
+                * Found a cache entry for the file
+                */
+               if (FcGlobalCacheCheckTime (file, &cache_file->info))
+               {
+                   name = cache_file->name;
+                   need_scan = FcFalse;
+                   FcGlobalCacheReferenced (cache, &cache_file->info);
+                   /* "." means the file doesn't contain a font */
+                   if (FcStrCmp (name, FC_FONT_FILE_INVALID) != 0)
+                   {
+                       font = FcNameParse (name);
+                       if (font)
+                           if (!FcPatternAddString (font, FC_FILE, file))
+                               ret = FcFalse;
+                   }
+               }
+           }
+           else if ((cache_dir = FcGlobalCacheDirGet (cache, file,
+                                                      strlen ((const char *) file),
+                                                      FcFalse)))
+           {
+               if (FcGlobalCacheCheckTime (cache_dir->info.file, 
+                                           &cache_dir->info))
+               {
+                   font = 0;
+                   need_scan = FcFalse;
+                   FcGlobalCacheReferenced (cache, &cache_dir->info);
+                   if (!FcStrSetAdd (dirs, file))
+                       ret = FcFalse;
+               }
            }
-           else
-               font = 0;
        }
-       else
+#endif
+       /*
+        * Nothing in the cache, scan the file
+        */
+       if (need_scan)
        {
            if (FcDebug () & FC_DBG_SCAN)
            {
@@ -72,27 +121,33 @@ FcFileScan (FcFontSet      *set,
            font = FcFreeTypeQuery (file, id, blanks, &count);
            if (FcDebug () & FC_DBG_SCAN)
                printf ("done\n");
-           if (!force && cache)
+           isDir = FcFalse;
+           if (!font && FcFileIsDir (file))
            {
-               if (font)
-               {
-                   FcChar8     *unparse;
+               isDir = FcTrue;
+               ret = FcStrSetAdd (dirs, file);
+           }
+#if 0
+           /*
+            * Update the cache
+            */
+           if (cache && font)
+           {
+               FcChar8 *unparse;
 
-                   unparse = FcNameUnparse (font);
-                   if (unparse)
-                   {
-                       (void) FcFileCacheUpdate (cache, file, id, unparse);
-                       free (unparse);
-                   }
-               }
-               else
+               unparse = FcNameUnparse (font);
+               if (unparse)
                {
-                   /* negative cache files not containing fonts */
-                   FcFileCacheUpdate (cache, file, id, FC_INVALID_FONT_FILE);
+                   (void) FcGlobalCacheUpdate (cache, file, id, unparse);
+                   FcStrFree (unparse);
                }
            }
+#endif
        }
-       if (font)
+       /*
+        * Add the font
+        */
+       if (font && (!config || FcConfigAcceptFont (config, font)))
        {
            if (!FcFontSetAdd (set, font))
            {
@@ -101,78 +156,135 @@ FcFileScan (FcFontSet    *set,
                ret = FcFalse;
            }
        }
+       else if (font)
+           FcPatternDestroy (font);
        id++;
     } while (font && ret && id < count);
     return ret;
 }
 
 FcBool
-FcDirScan (FcFontSet   *set,
-          FcFileCache  *cache,
-          FcBlanks     *blanks,
-          const char   *dir,
-          FcBool       force)
+FcFileScan (FcFontSet      *set,
+           FcStrSet        *dirs,
+           FcGlobalCache   *cache,
+           FcBlanks        *blanks,
+           const FcChar8   *file,
+           FcBool          force)
 {
-    DIR                    *d;
-    struct dirent   *e;
-    char           *file;
-    char           *base;
-    FcBool         ret = FcTrue;
+    return FcFileScanConfig (set, dirs, cache, blanks, file, force, 0);
+}
 
-    file = (char *) malloc (strlen (dir) + 1 + 256 + 1);
-    if (!file)
-       return FcFalse;
+/*
+ * Scan 'dir', adding font files to 'set' and
+ * subdirectories to 'dirs'
+ */
+
+FcBool
+FcDirScanConfig (FcFontSet     *set,
+                FcStrSet       *dirs,
+                FcGlobalCache  *cache,
+                FcBlanks       *blanks,
+                const FcChar8  *dir,
+                FcBool         force,
+                FcConfig       *config)
+{
+    DIR                        *d;
+    struct dirent      *e;
+    FcChar8            *file;
+    FcChar8            *base;
+    FcBool             ret = FcTrue;
+
+    if (config && !FcConfigAcceptFilename (config, dir))
+       return FcTrue;
 
-    strcpy (file, dir);
-    strcat (file, "/");
-    base = file + strlen (file);
     if (!force)
     {
-       strcpy (base, FC_DIR_CACHE_FILE);
-       
-       if (FcFileCacheReadDir (set, file))
+#if 0
+       /*
+        * Check fonts.cache-<version> file
+        */
+       if (FcDirCacheReadDir (set, dirs, dir, config))
        {
-           free (file);
+           if (cache)
+               FcGlobalCacheReferenceSubdir (cache, dir);
            return FcTrue;
        }
+    
+       /*
+        * Check ~/.fonts.cache-<version> file
+        */
+       if (cache && FcGlobalCacheScanDir (set, dirs, cache, dir, config))
+           return FcTrue;
+#endif
     }
     
-    d = opendir (dir);
+    /* freed below */
+    file = (FcChar8 *) malloc (strlen ((char *) dir) + 1 + FC_MAX_FILE_LEN + 1);
+    if (!file)
+       return FcFalse;
+
+    strcpy ((char *) file, (char *) dir);
+    strcat ((char *) file, "/");
+    base = file + strlen ((char *) file);
+    
+    if (FcDebug () & FC_DBG_SCAN)
+       printf ("\tScanning dir %s\n", dir);
+       
+    d = opendir ((char *) dir);
+    
     if (!d)
     {
        free (file);
+       /* Don't complain about missing directories */
+       if (errno == ENOENT)
+           return FcTrue;
        return FcFalse;
     }
     while (ret && (e = readdir (d)))
     {
-       if (e->d_name[0] != '.')
+       if (e->d_name[0] != '.' && strlen (e->d_name) < FC_MAX_FILE_LEN)
        {
-           strcpy (base, e->d_name);
-           FcFileScan (set, cache, blanks, file, force);
+           strcpy ((char *) base, (char *) e->d_name);
+           ret = FcFileScanConfig (set, dirs, cache, blanks, file, force, config);
        }
     }
     free (file);
     closedir (d);
+    /*
+     * Now that the directory has been scanned,
+     * add the cache entry 
+     */
+#if 0
+    if (ret && cache)
+       FcGlobalCacheUpdate (cache, dir, 0, 0);
+#endif
+       
     return ret;
 }
 
 FcBool
-FcDirSave (FcFontSet *set, const char *dir)
+FcDirScan (FcFontSet       *set,
+          FcStrSet         *dirs,
+          FcGlobalCache    *cache,
+          FcBlanks         *blanks,
+          const FcChar8    *dir,
+          FcBool           force)
 {
-    char           *file;
-    char           *base;
-    FcBool         ret;
-    
-    file = (char *) malloc (strlen (dir) + 1 + 256 + 1);
-    if (!file)
-       return FcFalse;
-
-    strcpy (file, dir);
-    strcat (file, "/");
-    base = file + strlen (file);
-    strcpy (base, FC_DIR_CACHE_FILE);
-    ret = FcFileCacheWriteDir (set, file);
-    free (file);
-    return ret;
+    return FcDirScanConfig (set, dirs, cache, blanks, dir, force, 0);
 }
 
+FcBool
+FcDirSave (FcFontSet *set, const FcChar8 *dir)
+{
+    static int rand_state = 0;
+    int bank;
+
+    if (!rand_state) 
+       rand_state = time(0L);
+    bank = rand_r(&rand_state);
+
+    while (FcCacheHaveBank(bank))
+       bank = rand_r(&rand_state);
+
+    return FcDirCacheWrite (bank, set, dir);
+}