Commit bc5e487f authored by Keith Packard's avatar Keith Packard
Browse files

Pass directory information around in FcCache structure. Freeze charsets.

Instead of passing directory information around in separate variables,
collect it all in an FcCache structure. Numerous internal and tool
interfaces changed as a result of this.

Charsets are now pre-frozen before being serialized. This causes them to
share across multiple fonts in the same cache.
parent aec8c90b
......@@ -128,15 +128,17 @@ nsubdirs (FcStrSet *set)
}
static int
scanDirs (FcStrList *list, FcConfig *config, char *program, FcBool force, FcBool really_force, FcBool verbose)
scanDirs (FcStrList *list, FcConfig *config, FcBool force, FcBool really_force, FcBool verbose)
{
int ret = 0;
const FcChar8 *dir;
FcFontSet *set;
FcStrSet *subdirs;
FcStrList *sublist;
FcCache *cache;
struct stat statb;
FcBool was_valid;
int i;
/*
* Now scan all of the directories into separate databases
......@@ -146,7 +148,7 @@ scanDirs (FcStrList *list, FcConfig *config, char *program, FcBool force, FcBool
{
if (verbose)
{
printf ("%s: \"%s\": ", program, dir);
printf ("%s: ", dir);
fflush (stdout);
}
......@@ -164,22 +166,6 @@ scanDirs (FcStrList *list, FcConfig *config, char *program, FcBool force, FcBool
continue;
}
set = FcFontSetCreate ();
if (!set)
{
fprintf (stderr, "%s: Can't create font set\n", dir);
ret++;
continue;
}
subdirs = FcStrSetCreate ();
if (!subdirs)
{
fprintf (stderr, "%s: Can't create directory set\n", dir);
ret++;
FcFontSetDestroy (set);
continue;
}
if (access ((char *) dir, W_OK) < 0)
{
switch (errno) {
......@@ -187,8 +173,6 @@ scanDirs (FcStrList *list, FcConfig *config, char *program, FcBool force, FcBool
case ENOTDIR:
if (verbose)
printf ("skipping, no such directory\n");
FcFontSetDestroy (set);
FcStrSetDestroy (subdirs);
continue;
case EACCES:
case EROFS:
......@@ -201,8 +185,6 @@ scanDirs (FcStrList *list, FcConfig *config, char *program, FcBool force, FcBool
perror ("");
ret++;
FcFontSetDestroy (set);
FcStrSetDestroy (subdirs);
continue;
}
}
......@@ -210,44 +192,50 @@ scanDirs (FcStrList *list, FcConfig *config, char *program, FcBool force, FcBool
{
fprintf (stderr, "\"%s\": ", dir);
perror ("");
FcFontSetDestroy (set);
FcStrSetDestroy (subdirs);
ret++;
continue;
}
if (!S_ISDIR (statb.st_mode))
{
fprintf (stderr, "\"%s\": not a directory, skipping\n", dir);
FcFontSetDestroy (set);
FcStrSetDestroy (subdirs);
continue;
}
if (really_force)
FcDirCacheUnlink (dir, config);
if (!force)
was_valid = FcDirCacheValid (dir);
cache = NULL;
was_valid = FcFalse;
if (!force) {
cache = FcDirCacheLoad (dir, config, NULL);
if (cache)
was_valid = FcTrue;
}
if (!FcDirScanConfig (set, subdirs, FcConfigGetBlanks (config), dir, force, config))
if (!cache)
{
fprintf (stderr, "%s: error scanning\n", dir);
FcFontSetDestroy (set);
FcStrSetDestroy (subdirs);
ret++;
continue;
cache = FcDirCacheRead (dir, FcTrue, config);
if (!cache)
{
fprintf (stderr, "%s: error scanning\n", dir);
ret++;
continue;
}
}
if (!force && was_valid)
set = FcCacheSet (cache);
if (was_valid)
{
if (verbose)
printf ("skipping, %d fonts, %d dirs\n",
set->nfont, nsubdirs(subdirs));
set->nfont, cache->dirs_count);
}
else
{
if (verbose)
printf ("caching, %d fonts, %d dirs\n",
set->nfont, nsubdirs (subdirs));
set->nfont, cache->dirs_count);
if (!FcDirCacheValid (dir))
{
......@@ -256,43 +244,36 @@ scanDirs (FcStrList *list, FcConfig *config, char *program, FcBool force, FcBool
ret++;
}
}
FcFontSetDestroy (set);
subdirs = FcStrSetCreate ();
if (!subdirs)
{
fprintf (stderr, "%s: Can't create subdir set\n", dir);
ret++;
FcDirCacheUnload (cache);
continue;
}
for (i = 0; i < cache->dirs_count; i++)
FcStrSetAdd (subdirs, FcCacheSubdir (cache, i));
FcDirCacheUnload (cache);
sublist = FcStrListCreate (subdirs);
FcStrSetDestroy (subdirs);
if (!sublist)
{
fprintf (stderr, "%s: Can't create subdir list\n", dir);
ret++;
FcDirCacheUnload (cache);
continue;
}
FcStrSetAdd (processed_dirs, dir);
ret += scanDirs (sublist, config, program, force, really_force, verbose);
ret += scanDirs (sublist, config, force, really_force, verbose);
}
FcStrListDone (list);
return ret;
}
FcCache *
FcCacheFileMap (const FcChar8 *file, struct stat *file_stat)
{
FcCache *cache;
int fd;
fd = open (file, O_RDONLY | O_BINARY);
if (fd < 0)
return NULL;
if (fstat (fd, file_stat) < 0) {
close (fd);
return NULL;
}
if (FcDirCacheLoad (fd, file_stat->st_size, &cache)) {
close (fd);
return cache;
}
close (fd);
return NULL;
}
static FcBool
cleanCacheDirectory (FcConfig *config, FcChar8 *dir, FcBool verbose)
{
......@@ -309,9 +290,11 @@ cleanCacheDirectory (FcConfig *config, FcChar8 *dir, FcBool verbose)
if (access ((char *) dir, W_OK|X_OK) != 0)
{
if (verbose)
printf ("%s: skipping unwritable cache directory\n", dir);
printf ("%s: not cleaning unwritable cache directory\n", dir);
return FcTrue;
}
if (verbose)
printf ("%s: cleaning cache directory\n", dir);
d = opendir (dir);
if (!d)
{
......@@ -332,7 +315,7 @@ cleanCacheDirectory (FcConfig *config, FcChar8 *dir, FcBool verbose)
ret = FcFalse;
break;
}
cache = FcCacheFileMap (file_name, &file_stat);
cache = FcDirCacheLoadFile (file_name, &file_stat);
if (!cache)
{
fprintf (stderr, "%s: invalid cache file: %s\n", dir, ent->d_name);
......@@ -478,7 +461,7 @@ main (int argc, char **argv)
return 1;
}
ret = scanDirs (list, config, argv[0], force, really_force, verbose);
ret = scanDirs (list, config, force, really_force, verbose);
FcStrSetDestroy (processed_dirs);
......
......@@ -81,7 +81,7 @@ extern int optind, opterr, optopt;
#endif
static FcBool
FcCacheWriteChars (FILE *f, const FcChar8 *chars)
write_chars (FILE *f, const FcChar8 *chars)
{
FcChar8 c;
while ((c = *chars++))
......@@ -101,7 +101,7 @@ FcCacheWriteChars (FILE *f, const FcChar8 *chars)
}
static FcBool
FcCacheWriteUlong (FILE *f, unsigned long t)
write_ulong (FILE *f, unsigned long t)
{
int pow;
unsigned long temp, digit;
......@@ -126,18 +126,18 @@ FcCacheWriteUlong (FILE *f, unsigned long t)
}
static FcBool
FcCacheWriteInt (FILE *f, int i)
write_int (FILE *f, int i)
{
return FcCacheWriteUlong (f, (unsigned long) i);
return write_ulong (f, (unsigned long) i);
}
static FcBool
FcCacheWriteStringOld (FILE *f, const FcChar8 *string)
write_string (FILE *f, const FcChar8 *string)
{
if (PUTC ('"', f) == EOF)
return FcFalse;
if (!FcCacheWriteChars (f, string))
if (!write_chars (f, string))
return FcFalse;
if (PUTC ('"', f) == EOF)
return FcFalse;
......@@ -168,30 +168,12 @@ usage (char *program)
exit (1);
}
static int
FcCacheFileOpen (char *cache_file, off_t *size)
{
int fd;
struct stat file_stat;
fd = open(cache_file, O_RDONLY | O_BINARY);
if (fd < 0)
return -1;
if (fstat (fd, &file_stat) < 0) {
close (fd);
return -1;
}
*size = file_stat.st_size;
return fd;
}
/*
* return the path from the directory containing 'cache' to 'file'
*/
static const FcChar8 *
FcFileBaseName (const char *cache, const FcChar8 *file)
file_base_name (const char *cache, const FcChar8 *file)
{
const FcChar8 *cache_slash;
int cache_len = strlen (cache);
......@@ -201,8 +183,8 @@ FcFileBaseName (const char *cache, const FcChar8 *file)
return file;
}
FcBool
FcCachePrintSet (FcFontSet *set, FcStrSet *dirs, char *base_name, FcBool verbose)
static FcBool
cache_print_set (FcFontSet *set, FcStrSet *dirs, char *base_name, FcBool verbose)
{
FcPattern *font;
FcChar8 *name, *dir;
......@@ -219,16 +201,16 @@ FcCachePrintSet (FcFontSet *set, FcStrSet *dirs, char *base_name, FcBool verbose
while ((dir = FcStrListNext (list)))
{
base = FcFileBaseName (base_name, dir);
if (!FcCacheWriteStringOld (stdout, base))
base = file_base_name (base_name, dir);
if (!write_string (stdout, base))
goto bail3;
if (PUTC (' ', stdout) == EOF)
goto bail3;
if (!FcCacheWriteInt (stdout, 0))
if (!write_int (stdout, 0))
goto bail3;
if (PUTC (' ', stdout) == EOF)
goto bail3;
if (!FcCacheWriteStringOld (stdout, FC_FONT_FILE_DIR))
if (!write_string (stdout, FC_FONT_FILE_DIR))
goto bail3;
if (PUTC ('\n', stdout) == EOF)
goto bail3;
......@@ -243,21 +225,21 @@ FcCachePrintSet (FcFontSet *set, FcStrSet *dirs, char *base_name, FcBool verbose
if (FcPatternGetString (font, FC_FILE, 0, (FcChar8 **) &file) != FcResultMatch)
goto bail3;
base = FcFileBaseName (base_name, file);
base = file_base_name (base_name, file);
if (FcPatternGetInteger (font, FC_INDEX, 0, &id) != FcResultMatch)
goto bail3;
if (!FcCacheWriteStringOld (stdout, base))
if (!write_string (stdout, base))
goto bail3;
if (PUTC (' ', stdout) == EOF)
goto bail3;
if (!FcCacheWriteInt (stdout, id))
if (!write_int (stdout, id))
goto bail3;
if (PUTC (' ', stdout) == EOF)
goto bail3;
name = FcNameUnparse (font);
if (!name)
goto bail3;
ret = FcCacheWriteStringOld (stdout, name);
ret = write_string (stdout, name);
FcStrFree (name);
if (!ret)
goto bail3;
......@@ -277,28 +259,6 @@ bail2:
return FcFalse;
}
FcCache *
FcCacheFileMap (const FcChar8 *file)
{
FcCache *cache;
int fd;
struct stat file_stat;
fd = open (file, O_RDONLY | O_BINARY);
if (fd < 0)
return NULL;
if (fstat (fd, &file_stat) < 0) {
close (fd);
return NULL;
}
if (!FcDirCacheLoad (fd, file_stat.st_size, &cache)) {
close (fd);
return NULL;
}
close (fd);
return cache;
}
int
main (int argc, char **argv)
{
......@@ -399,11 +359,12 @@ main (int argc, char **argv)
off_t size;
intptr_t *cache_dirs;
FcChar8 *cache_file = NULL;
struct stat file_stat;
if (FcFileIsDir (arg))
cache = FcDirCacheMap (arg, config, &cache_file);
cache = FcDirCacheLoad (arg, config, &cache_file);
else
cache = FcCacheFileMap (arg);
cache = FcDirCacheLoadFile (arg, &file_stat);
if (!cache)
{
perror ((char *) arg);
......@@ -433,11 +394,11 @@ main (int argc, char **argv)
FcCacheDir(cache), cache_file ? cache_file : arg);
first = FcFalse;
}
FcCachePrintSet (fs, dirs, FcCacheDir (cache), verbose);
cache_print_set (fs, dirs, FcCacheDir (cache), verbose);
FcStrSetDestroy (dirs);
FcDirCacheUnmap (cache);
FcDirCacheUnload (cache);
if (cache_file)
FcStrFree (cache_file);
}
......
......@@ -24,19 +24,6 @@
#include "fcint.h"
/* stub definitions for declarations from fcint.h.. */
int * _fcBankId = 0, * _fcBankIdx = 0;
FcValueList ** _fcValueLists = 0;
FcPatternElt ** _fcPatternElts = 0;
int FcDebugVal = 0;
int
FcCacheBankToIndexMTF (int bank)
{
return 0;
}
/* end stub definitions */
static int
rawindex (const FcGlyphName *gn);
......
......@@ -112,81 +112,19 @@ FcDirCacheUnlink (const FcChar8 *dir, FcConfig *config)
}
static int
FcCacheReadDirs (FcConfig * config,
FcStrList *list, FcFontSet * set, FcStrSet *processed_dirs)
FcDirCacheOpenFile (const FcChar8 *cache_file, struct stat *file_stat)
{
int ret = 0;
FcChar8 *dir;
FcStrSet *subdirs;
FcStrList *sublist;
int fd;
/*
* Read in the results from 'list'.
*/
while ((dir = FcStrListNext (list)))
fd = open((char *) cache_file, O_RDONLY | O_BINARY);
if (fd < 0)
return fd;
if (fstat (fd, file_stat) < 0)
{
if (!FcConfigAcceptFilename (config, dir))
continue;
/* Skip this directory if already updated
* to avoid the looped directories via symlinks
* Clearly a dir not in fonts.conf shouldn't be globally cached.
*/
if (FcStrSetMember (processed_dirs, dir))
continue;
if (!FcStrSetAdd (processed_dirs, dir))
continue;
subdirs = FcStrSetCreate ();
if (!subdirs)
{
fprintf (stderr, "Can't create directory set\n");
ret++;
continue;
}
FcDirScanConfig (set, subdirs,
config->blanks, dir, FcFalse, config);
sublist = FcStrListCreate (subdirs);
FcStrSetDestroy (subdirs);
if (!sublist)
{
fprintf (stderr, "Can't create subdir list in \"%s\"\n", dir);
ret++;
continue;
}
ret += FcCacheReadDirs (config, sublist, set, processed_dirs);
close (fd);
return -1;
}
FcStrListDone (list);
return ret;
}
FcFontSet *
FcCacheRead (FcConfig *config)
{
FcFontSet *s = FcFontSetCreate();
FcStrSet *processed_dirs;
if (!s)
return 0;
processed_dirs = FcStrSetCreate();
if (!processed_dirs)
goto bail;
if (FcCacheReadDirs (config, FcConfigGetConfigDirs (config), s, processed_dirs))
goto bail1;
FcStrSetDestroy (processed_dirs);
return s;
bail1:
FcStrSetDestroy (processed_dirs);
bail:
FcFontSetDestroy (s);
return 0;
return fd;
}
/*
......@@ -220,10 +158,9 @@ FcDirCacheProcess (FcConfig *config, const FcChar8 *dir,
FcChar8 *cache_hashed = FcStrPlus (cache_dir, cache_base);
if (!cache_hashed)
break;
fd = open((char *) cache_hashed, O_RDONLY | O_BINARY);
fd = FcDirCacheOpenFile (cache_hashed, &file_stat);
if (fd >= 0) {
if (fstat (fd, &file_stat) >= 0 &&
dir_stat.st_mtime <= file_stat.st_mtime)
if (dir_stat.st_mtime <= file_stat.st_mtime)
{
ret = (*callback) (fd, file_stat.st_size, closure);
if (ret)
......@@ -245,44 +182,56 @@ FcDirCacheProcess (FcConfig *config, const FcChar8 *dir,
return ret;
}
FcBool
FcDirCacheLoad (int fd, off_t size, void *closure)
#define FC_CACHE_MIN_MMAP 1024
/*
* Map a cache file into memory
*/
static FcCache *
FcDirCacheMapFd (int fd, off_t size)
{
FcCache *cache;
FcCache *cache = NULL;
FcBool allocated = FcFalse;
if (size < sizeof (FcCache))
return FcFalse;
return NULL;
/*
* For small cache files, just read them into memory
*/
if (size >= FC_CACHE_MIN_MMAP)
{
#if defined(HAVE_MMAP) || defined(__CYGWIN__)
cache = mmap (0, size, PROT_READ, MAP_SHARED, fd, 0);
cache = mmap (0, size, PROT_READ, MAP_SHARED, fd, 0);
#elif defined(_WIN32)
{
HANDLE hFileMap;
cache = NULL;
hFileMap = CreateFileMapping((HANDLE) _get_osfhandle(fd), NULL,
PAGE_READONLY, 0, 0, NULL);
if (hFileMap != NULL)
{
cache = MapViewOfFile (hFileMap, FILE_MAP_READ, 0, 0, size);
CloseHandle (hFileMap);
HANDLE hFileMap;
cache = NULL;
hFileMap = CreateFileMapping((HANDLE) _get_osfhandle(fd), NULL,
PAGE_READONLY, 0, 0, NULL);
if (hFileMap != NULL)
{
cache = MapViewOfFile (hFileMap, FILE_MAP_READ, 0, 0, size);
CloseHandle (hFileMap);
}
}
}
#endif
}
if (!cache)
{
cache = malloc (size);
if (!cache)
return FcFalse;
return NULL;
if (read (fd, cache, size) != size)
{
free (cache);
return FcFalse;
return NULL;
}
allocated = FcTrue;
}
if (cache->magic != FC_CACHE_MAGIC ||
if (cache->magic != FC_CACHE_MAGIC_MMAP ||
cache->version != FC_CACHE_CONTENT_VERSION ||
cache->size != size)
{
if (allocated)
......@@ -295,74 +244,76 @@ FcDirCacheLoad (int fd, off_t size, void *closure)
UnmapViewOfFile (cache);
#endif
}
return FcFalse;
return NULL;
}
/* Mark allocated caches so they're freed rather than unmapped */
if (allocated)
cache->magic = FC_CACHE_MAGIC_COPY;
cache->magic = FC_CACHE_MAGIC_ALLOC;
return cache;
}
void
FcDirCacheUnload (FcCache *cache)