static FcBool FcConfigAddDirList (FcConfig *config, FcSetName set, FcStrSet *dirSet) { FcStrList *dirlist; FcChar8 *dir; FcCache *cache; FcBool ret = FcFalse; dirlist = FcStrListCreate (dirSet); if (!dirlist) return FcFalse; while ((dir = FcStrListNext (dirlist))) { if (FcDebug () & FC_DBG_FONTSET) printf ("adding fonts from %s\n", dir); cache = FcDirCacheRead (dir, FcFalse, config); if (!cache) continue; FcConfigAddCache (config, cache, set, dirSet); FcDirCacheUnload (cache); ret = FcTrue; } FcStrListDone (dirlist); return ret; }
int main (int argc, char **argv) { int i; int ret = 0; FcFontSet *fs; FcStrSet *dirs; FcStrSet *args = NULL; FcStrList *arglist; FcCache *cache; FcConfig *config; FcChar8 *arg; int verbose = 0; int recurse = 0; FcBool first = FcTrue; #if HAVE_GETOPT_LONG || HAVE_GETOPT int c; #if HAVE_GETOPT_LONG while ((c = getopt_long (argc, argv, "Vvrh", longopts, NULL)) != -1) #else while ((c = getopt (argc, argv, "Vvrh")) != -1) #endif { switch (c) { case 'V': fprintf (stderr, "fontconfig version %d.%d.%d\n", FC_MAJOR, FC_MINOR, FC_REVISION); exit (0); case 'v': verbose++; break; case 'r': recurse++; break; case 'h': usage (argv[0], 0); default: usage (argv[0], 1); } } i = optind; #else i = 1; #endif config = FcInitLoadConfig (); if (!config) { fprintf (stderr, "%s: Can't init font config library\n", argv[0]); return 1; } FcConfigSetCurrent (config); args = FcStrSetCreate (); if (!args) { fprintf (stderr, "%s: malloc failure\n", argv[0]); return 1; } if (i < argc) { for (; i < argc; i++) { if (!FcStrSetAddFilename (args, (const FcChar8 *) argv[i])) { fprintf (stderr, "%s: malloc failure\n", argv[0]); return 1; } } arglist = FcStrListCreate (args); if (!arglist) { fprintf (stderr, "%s: malloc failure\n", argv[0]); return 1; } } else { recurse++; arglist = FcConfigGetFontDirs (config); while ((arg = FcStrListNext (arglist))) if (!FcStrSetAdd (args, arg)) { fprintf (stderr, "%s: malloc failure\n", argv[0]); return 1; } FcStrListDone (arglist); } arglist = FcStrListCreate (args); if (!arglist) { fprintf (stderr, "%s: malloc failure\n", argv[0]); return 1; } while ((arg = FcStrListNext (arglist))) { int j; FcChar8 *cache_file = NULL; struct stat file_stat; if (FcFileIsDir (arg)) cache = FcDirCacheLoad (arg, config, &cache_file); else cache = FcDirCacheLoadFile (arg, &file_stat); if (!cache) { perror ((char *) arg); ret++; continue; } dirs = FcStrSetCreate (); fs = FcCacheCopySet (cache); for (j = 0; j < FcCacheNumSubdir (cache); j++) { FcStrSetAdd (dirs, FcCacheSubdir (cache, j)); if (recurse) FcStrSetAdd (args, FcCacheSubdir (cache, j)); } if (verbose) { if (!first) printf ("\n"); printf ("Directory: %s\nCache: %s\n--------\n", FcCacheDir(cache), cache_file ? cache_file : arg); first = FcFalse; } cache_print_set (fs, dirs, FcCacheDir (cache), verbose); FcStrSetDestroy (dirs); FcFontSetDestroy (fs); FcDirCacheUnload (cache); if (cache_file) FcStrFree (cache_file); } FcFini (); return 0; }
static int scanDirs (FcStrList *list, FcConfig *config, FcBool force, FcBool really_force, FcBool verbose, int *changed) { int ret = 0; const FcChar8 *dir; FcStrSet *subdirs; FcStrList *sublist; FcCache *cache; struct stat statb; FcBool was_valid; int i; /* * Now scan all of the directories into separate databases * and write out the results */ while ((dir = FcStrListNext (list))) { if (verbose) { printf ("%s: ", dir); fflush (stdout); } if (!dir) { if (verbose) printf ("skipping, no such directory\n"); continue; } if (FcStrSetMember (processed_dirs, dir)) { if (verbose) printf ("skipping, looped directory detected\n"); continue; } if (stat ((char *) dir, &statb) == -1) { switch (errno) { case ENOENT: case ENOTDIR: if (verbose) printf ("skipping, no such directory\n"); break; default: fprintf (stderr, "\"%s\": ", dir); perror (""); ret++; break; } continue; } if (!S_ISDIR (statb.st_mode)) { fprintf (stderr, "\"%s\": not a directory, skipping\n", dir); continue; } if (really_force) FcDirCacheUnlink (dir, config); cache = NULL; was_valid = FcFalse; if (!force) { cache = FcDirCacheLoad (dir, config, NULL); if (cache) was_valid = FcTrue; } if (!cache) { (*changed)++; cache = FcDirCacheRead (dir, FcTrue, config); if (!cache) { fprintf (stderr, "%s: error scanning\n", dir); ret++; continue; } } if (was_valid) { if (verbose) printf ("skipping, existing cache is valid: %d fonts, %d dirs\n", FcCacheNumFont (cache), FcCacheNumSubdir (cache)); } else { if (verbose) printf ("caching, new cache contents: %d fonts, %d dirs\n", FcCacheNumFont (cache), FcCacheNumSubdir (cache)); if (!FcDirCacheValid (dir)) { fprintf (stderr, "%s: failed to write cache\n", dir); (void) FcDirCacheUnlink (dir, config); ret++; } } subdirs = FcStrSetCreate (); if (!subdirs) { fprintf (stderr, "%s: Can't create subdir set\n", dir); ret++; FcDirCacheUnload (cache); continue; } for (i = 0; i < FcCacheNumSubdir (cache); 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++; continue; } FcStrSetAdd (processed_dirs, dir); ret += scanDirs (sublist, config, force, really_force, verbose, changed); } FcStrListDone (list); return ret; }
/* * Map a cache file into memory */ static FcCache * FcDirCacheMapFd (FcConfig *config, int fd, struct stat *fd_stat, struct stat *dir_stat) { FcCache *cache; FcBool allocated = FcFalse; if (fd_stat->st_size < (int) sizeof (FcCache)) return NULL; cache = FcCacheFindByStat (fd_stat); if (cache) { if (FcCacheTimeValid (config, cache, dir_stat) && FcCacheDirsValid (config, cache)) return cache; FcDirCacheUnload (cache); cache = NULL; } /* * Large cache files are mmap'ed, smaller cache files are read. This * balances the system cost of mmap against per-process memory usage. */ if (FcCacheIsMmapSafe (fd) && fd_stat->st_size >= FC_CACHE_MIN_MMAP) { #if defined(HAVE_MMAP) || defined(__CYGWIN__) cache = mmap (0, fd_stat->st_size, PROT_READ, MAP_SHARED, fd, 0); #if (HAVE_POSIX_FADVISE) && defined(POSIX_FADV_WILLNEED) posix_fadvise (fd, 0, fd_stat->st_size, POSIX_FADV_WILLNEED); #endif if (cache == MAP_FAILED) cache = NULL; #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, fd_stat->st_size); CloseHandle (hFileMap); } } #endif } if (!cache) { cache = malloc (fd_stat->st_size); if (!cache) return NULL; if (read (fd, cache, fd_stat->st_size) != fd_stat->st_size) { free (cache); return NULL; } allocated = FcTrue; } if (cache->magic != FC_CACHE_MAGIC_MMAP || cache->version < FC_CACHE_VERSION_NUMBER || cache->size != (intptr_t) fd_stat->st_size || !FcCacheTimeValid (config, cache, dir_stat) || !FcCacheDirsValid (config, cache) || !FcCacheInsert (cache, fd_stat)) { if (allocated) free (cache); else { #if defined(HAVE_MMAP) || defined(__CYGWIN__) munmap (cache, fd_stat->st_size); #elif defined(_WIN32) UnmapViewOfFile (cache); #endif } return NULL; } /* Mark allocated caches so they're freed rather than unmapped */ if (allocated) cache->magic = FC_CACHE_MAGIC_ALLOC; return cache; }