]> git.wh0rd.org - fontconfig.git/blobdiff - src/fcdir.c
Sort directory entries while scanning them from disk; prevents Heisenbugs
[fontconfig.git] / src / fcdir.c
index 42aaf74ea6ed333ff84fab8615935e5b2b0369a0..ad64ca83c21b896d07bc538348c6ae03d93147d4 100644 (file)
@@ -1,7 +1,7 @@
 /*
- * $XFree86: xc/lib/fontconfig/src/fcdir.c,v 1.9 2002/08/31 22:17:32 keithp Exp $
+ * $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
@@ -25,7 +25,7 @@
 #include "fcint.h"
 #include <dirent.h>
 
-static FcBool
+FcBool
 FcFileIsDir (const FcChar8 *file)
 {
     struct stat            statb;
@@ -36,12 +36,13 @@ FcFileIsDir (const FcChar8 *file)
 }
 
 FcBool
-FcFileScan (FcFontSet      *set,
-           FcStrSet        *dirs,
-           FcGlobalCache   *cache,
-           FcBlanks        *blanks,
-           const FcChar8   *file,
-           FcBool          force)
+FcFileScanConfig (FcFontSet    *set,
+                 FcStrSet      *dirs,
+                 FcGlobalCache *cache,
+                 FcBlanks      *blanks,
+                 const FcChar8 *file,
+                 FcBool        force,
+                 FcConfig      *config)
 {
     int                        id;
     FcChar8            *name;
@@ -53,6 +54,9 @@ FcFileScan (FcFontSet     *set,
     FcGlobalCacheDir   *cache_dir;
     FcBool             need_scan;
     
+    if (config && !FcConfigAcceptFilename (config, file))
+       return FcTrue;
+
     if (force)
        cache = 0;
     id = 0;
@@ -70,7 +74,7 @@ FcFileScan (FcFontSet     *set,
                /*
                 * Found a cache entry for the file
                 */
-               if (FcGlobalCacheCheckTime (&cache_file->info))
+               if (FcGlobalCacheCheckTime (file, &cache_file->info))
                {
                    name = cache_file->name;
                    need_scan = FcFalse;
@@ -89,7 +93,8 @@ FcFileScan (FcFontSet     *set,
                                                       strlen ((const char *) file),
                                                       FcFalse)))
            {
-               if (FcGlobalCacheCheckTime (&cache_dir->info))
+               if (FcGlobalCacheCheckTime (cache_dir->info.file, 
+                                           &cache_dir->info))
                {
                    font = 0;
                    need_scan = FcFalse;
@@ -117,8 +122,6 @@ FcFileScan (FcFontSet           *set,
            {
                isDir = FcTrue;
                ret = FcStrSetAdd (dirs, file);
-               if (cache && ret)
-                   FcGlobalCacheUpdate (cache, file, 0, FC_FONT_FILE_DIR);
            }
            /*
             * Update the cache
@@ -138,7 +141,7 @@ FcFileScan (FcFontSet           *set,
        /*
         * Add the font
         */
-       if (font)
+       if (font && (!config || FcConfigAcceptFont (config, font)))
        {
            if (!FcFontSetAdd (set, font))
            {
@@ -147,39 +150,76 @@ FcFileScan (FcFontSet         *set,
                ret = FcFalse;
            }
        }
+       else if (font)
+           FcPatternDestroy (font);
        id++;
     } while (font && ret && id < count);
     return ret;
 }
 
-#define FC_MAX_FILE_LEN            4096
+FcBool
+FcFileScan (FcFontSet      *set,
+           FcStrSet        *dirs,
+           FcGlobalCache   *cache,
+           FcBlanks        *blanks,
+           const FcChar8   *file,
+           FcBool          force)
+{
+    return FcFileScanConfig (set, dirs, cache, blanks, file, force, 0);
+}
+
+/*
+ * Strcmp helper that takes pointers to pointers, copied from qsort(3) manpage
+ */
+
+static int
+cmpstringp(const void *p1, const void *p2)
+{
+    return strcmp(* (char **) p1, * (char **) p2);
+}
+
+/*
+ * Scan 'dir', adding font files to 'set' and
+ * subdirectories to 'dirs'
+ */
 
 FcBool
-FcDirScan (FcFontSet       *set,
-          FcStrSet         *dirs,
-          FcGlobalCache    *cache,
-          FcBlanks         *blanks,
-          const FcChar8    *dir,
-          FcBool           force)
+FcDirScanConfig (FcFontSet     *set,
+                FcStrSet       *dirs,
+                FcGlobalCache  *cache,
+                FcBlanks       *blanks,
+                const FcChar8  *dir,
+                FcBool         force,
+                FcConfig       *config)
 {
     DIR                        *d;
     struct dirent      *e;
+    FcChar8            **dirlist;
+    int                        dirlistlen, dirlistalloc;
     FcChar8            *file;
     FcChar8            *base;
     FcBool             ret = FcTrue;
+    int                        i;
+
+    if (config && !FcConfigAcceptFilename (config, dir))
+       return FcTrue;
 
     if (!force)
     {
        /*
         * Check fonts.cache-<version> file
         */
-       if (FcDirCacheReadDir (set, dirs, dir))
+       if (FcDirCacheReadDir (set, dirs, dir, config))
+       {
+           if (cache)
+               FcGlobalCacheReferenceSubdir (cache, dir);
            return FcTrue;
+       }
     
        /*
         * Check ~/.fonts.cache-<version> file
         */
-       if (cache && FcGlobalCacheScanDir (set, dirs, cache, dir))
+       if (cache && FcGlobalCacheScanDir (set, dirs, cache, dir, config))
            return FcTrue;
     }
     
@@ -192,6 +232,9 @@ FcDirScan (FcFontSet            *set,
     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)
@@ -202,22 +245,63 @@ FcDirScan (FcFontSet          *set,
            return FcTrue;
        return FcFalse;
     }
-    while (ret && (e = readdir (d)))
+    dirlistlen = 0;
+    dirlistalloc = 8;
+    dirlist = malloc(dirlistalloc * sizeof(FcChar8 *));
+    if (!dirlist)
+       return FcFalse;
+    while ((e = readdir (d)))
     {
        if (e->d_name[0] != '.' && strlen (e->d_name) < FC_MAX_FILE_LEN)
        {
-           strcpy ((char *) base, (char *) e->d_name);
-           ret = FcFileScan (set, dirs, cache, blanks, file, force);
+           if (dirlistlen == dirlistalloc)
+           {
+               dirlistalloc *= 2;
+               dirlist = realloc(dirlist, dirlistalloc * sizeof(FcChar8 *));
+               if (!dirlist)
+                   return FcFalse;
+           }
+           dirlist[dirlistlen] = malloc(strlen (e->d_name) + 1);
+           if (!dirlist[dirlistlen])
+               return FcFalse;
+           strcpy(dirlist[dirlistlen], e->d_name);
+           dirlistlen++;
        }
     }
+    qsort(dirlist, dirlistlen, sizeof(FcChar8 *), cmpstringp);
+    i = 0;
+    while (ret && i < dirlistlen)
+    {
+       strcpy ((char *) base, (char *) dirlist[i]);
+       ret = FcFileScanConfig (set, dirs, cache, blanks, file, force, config);
+       i++;
+    }
+    for (i = 0; i < dirlistlen; i++)
+       free(dirlist[i]);
+    free (dirlist);
     free (file);
     closedir (d);
+    /*
+     * Now that the directory has been scanned,
+     * add the cache entry 
+     */
     if (ret && cache)
        FcGlobalCacheUpdate (cache, dir, 0, 0);
        
     return ret;
 }
 
+FcBool
+FcDirScan (FcFontSet       *set,
+          FcStrSet         *dirs,
+          FcGlobalCache    *cache,
+          FcBlanks         *blanks,
+          const FcChar8    *dir,
+          FcBool           force)
+{
+    return FcDirScanConfig (set, dirs, cache, blanks, dir, force, 0);
+}
+
 FcBool
 FcDirSave (FcFontSet *set, FcStrSet *dirs, const FcChar8 *dir)
 {