fc-cache.c revision 5e61939b
12c393a42Smrg/* 2a6844aabSmrg * fontconfig/fc-cache/fc-cache.c 32c393a42Smrg * 42c393a42Smrg * Copyright © 2002 Keith Packard 52c393a42Smrg * 62c393a42Smrg * Permission to use, copy, modify, distribute, and sell this software and its 72c393a42Smrg * documentation for any purpose is hereby granted without fee, provided that 82c393a42Smrg * the above copyright notice appear in all copies and that both that 92c393a42Smrg * copyright notice and this permission notice appear in supporting 10898dab68Smrg * documentation, and that the name of the author(s) not be used in 112c393a42Smrg * advertising or publicity pertaining to distribution of the software without 12898dab68Smrg * specific, written prior permission. The authors make no 132c393a42Smrg * representations about the suitability of this software for any purpose. It 142c393a42Smrg * is provided "as is" without express or implied warranty. 152c393a42Smrg * 16a6844aabSmrg * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 172c393a42Smrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 18a6844aabSmrg * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR 192c393a42Smrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 202c393a42Smrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 212c393a42Smrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 222c393a42Smrg * PERFORMANCE OF THIS SOFTWARE. 232c393a42Smrg */ 242c393a42Smrg 252c393a42Smrg#ifdef HAVE_CONFIG_H 262c393a42Smrg#include <config.h> 272c393a42Smrg#else 282c393a42Smrg#ifdef linux 292c393a42Smrg#define HAVE_GETOPT_LONG 1 302c393a42Smrg#endif 312c393a42Smrg#define HAVE_GETOPT 1 322c393a42Smrg#endif 332c393a42Smrg 342c393a42Smrg#include <fontconfig/fontconfig.h> 352c393a42Smrg#include <stdio.h> 362c393a42Smrg#include <stdlib.h> 372c393a42Smrg#include <unistd.h> 382c393a42Smrg#include <sys/types.h> 392c393a42Smrg#include <sys/stat.h> 402c393a42Smrg#include <errno.h> 412c393a42Smrg#include <fcntl.h> 422c393a42Smrg#include <dirent.h> 432c393a42Smrg#include <string.h> 442c393a42Smrg 452c393a42Smrg#if defined (_WIN32) 462c393a42Smrg#define STRICT 472c393a42Smrg#include <windows.h> 482c393a42Smrg#define sleep(x) Sleep((x) * 1000) 492c393a42Smrg#undef STRICT 502c393a42Smrg#endif 512c393a42Smrg 522c393a42Smrg#ifndef O_BINARY 532c393a42Smrg#define O_BINARY 0 542c393a42Smrg#endif 552c393a42Smrg 562c393a42Smrg#ifndef HAVE_GETOPT 572c393a42Smrg#define HAVE_GETOPT 0 582c393a42Smrg#endif 592c393a42Smrg#ifndef HAVE_GETOPT_LONG 602c393a42Smrg#define HAVE_GETOPT_LONG 0 612c393a42Smrg#endif 622c393a42Smrg 632c393a42Smrg#if HAVE_GETOPT_LONG 642c393a42Smrg#undef _GNU_SOURCE 652c393a42Smrg#define _GNU_SOURCE 662c393a42Smrg#include <getopt.h> 672c393a42Smrgconst struct option longopts[] = { 682c393a42Smrg {"force", 0, 0, 'f'}, 697f785a56Sjmcneill {"quick", 0, 0, 'q'}, 702c393a42Smrg {"really-force", 0, 0, 'r'}, 715e61939bSmrg {"sysroot", 0, 0, 'y'}, 722c393a42Smrg {"system-only", 0, 0, 's'}, 732c393a42Smrg {"version", 0, 0, 'V'}, 742c393a42Smrg {"verbose", 0, 0, 'v'}, 75a6844aabSmrg {"help", 0, 0, 'h'}, 762c393a42Smrg {NULL,0,0,0}, 772c393a42Smrg}; 782c393a42Smrg#else 792c393a42Smrg#if HAVE_GETOPT 802c393a42Smrgextern char *optarg; 812c393a42Smrgextern int optind, opterr, optopt; 822c393a42Smrg#endif 832c393a42Smrg#endif 842c393a42Smrg 852c393a42Smrgstatic void 86a6844aabSmrgusage (char *program, int error) 872c393a42Smrg{ 88a6844aabSmrg FILE *file = error ? stderr : stdout; 892c393a42Smrg#if HAVE_GETOPT_LONG 905e61939bSmrg fprintf (file, "usage: %s [-fqrsvVh] [--quick] [-y SYSROOT] [--force|--really-force] [--sysroot=SYSROOT] [--system-only] [--verbose] [--version] [--help] [dirs]\n", 912c393a42Smrg program); 922c393a42Smrg#else 935e61939bSmrg fprintf (file, "usage: %s [-fqrsvVh] [-y SYSROOT] [dirs]\n", 942c393a42Smrg program); 952c393a42Smrg#endif 96a6844aabSmrg fprintf (file, "Build font information caches in [dirs]\n" 972c393a42Smrg "(all directories in font configuration by default).\n"); 98a6844aabSmrg fprintf (file, "\n"); 992c393a42Smrg#if HAVE_GETOPT_LONG 1005e61939bSmrg fprintf (file, " -f, --force scan directories with apparently valid caches\n"); 1015e61939bSmrg fprintf (file, " -q, --quick don't sleep before exiting\n"); 1025e61939bSmrg fprintf (file, " -r, --really-force erase all existing caches, then rescan\n"); 1035e61939bSmrg fprintf (file, " -s, --system-only scan system-wide directories only\n"); 1045e61939bSmrg fprintf (file, " -y, --sysroot=SYSROOT prepend SYSROOT to all paths for scanning\n"); 1055e61939bSmrg fprintf (file, " -v, --verbose display status information while busy\n"); 1065e61939bSmrg fprintf (file, " -V, --version display font config version and exit\n"); 1075e61939bSmrg fprintf (file, " -h, --help display this help and exit\n"); 1082c393a42Smrg#else 109a6844aabSmrg fprintf (file, " -f (force) scan directories with apparently valid caches\n"); 1107f785a56Sjmcneill fprintf (file, " -q (quick) don't sleep before exiting\n"); 111a6844aabSmrg fprintf (file, " -r, (really force) erase all existing caches, then rescan\n"); 112a6844aabSmrg fprintf (file, " -s (system) scan system-wide directories only\n"); 1135e61939bSmrg fprintf (file, " -y SYSROOT (sysroot) prepend SYSROOT to all paths for scanning\n"); 114a6844aabSmrg fprintf (file, " -v (verbose) display status information while busy\n"); 115a6844aabSmrg fprintf (file, " -V (version) display font config version and exit\n"); 116a6844aabSmrg fprintf (file, " -h (help) display this help and exit\n"); 1172c393a42Smrg#endif 118a6844aabSmrg exit (error); 1192c393a42Smrg} 1202c393a42Smrg 1212c393a42Smrgstatic FcStrSet *processed_dirs; 1222c393a42Smrg 1232c393a42Smrgstatic int 124898dab68SmrgscanDirs (FcStrList *list, FcConfig *config, FcBool force, FcBool really_force, FcBool verbose, int *changed) 1252c393a42Smrg{ 1262c393a42Smrg int ret = 0; 1272c393a42Smrg const FcChar8 *dir; 1282c393a42Smrg FcStrSet *subdirs; 1292c393a42Smrg FcStrList *sublist; 1302c393a42Smrg FcCache *cache; 1312c393a42Smrg struct stat statb; 1322c393a42Smrg FcBool was_valid; 1332c393a42Smrg int i; 1342c393a42Smrg 1352c393a42Smrg /* 1362c393a42Smrg * Now scan all of the directories into separate databases 1372c393a42Smrg * and write out the results 1382c393a42Smrg */ 1392c393a42Smrg while ((dir = FcStrListNext (list))) 1402c393a42Smrg { 1412c393a42Smrg if (verbose) 1422c393a42Smrg { 1432c393a42Smrg printf ("%s: ", dir); 1442c393a42Smrg fflush (stdout); 1452c393a42Smrg } 1462c393a42Smrg 1472c393a42Smrg if (FcStrSetMember (processed_dirs, dir)) 1482c393a42Smrg { 1492c393a42Smrg if (verbose) 1502c393a42Smrg printf ("skipping, looped directory detected\n"); 1512c393a42Smrg continue; 1522c393a42Smrg } 1532c393a42Smrg 1542c393a42Smrg if (stat ((char *) dir, &statb) == -1) 1552c393a42Smrg { 1562c393a42Smrg switch (errno) { 1572c393a42Smrg case ENOENT: 1582c393a42Smrg case ENOTDIR: 1592c393a42Smrg if (verbose) 1602c393a42Smrg printf ("skipping, no such directory\n"); 1612c393a42Smrg break; 1622c393a42Smrg default: 1632c393a42Smrg fprintf (stderr, "\"%s\": ", dir); 1642c393a42Smrg perror (""); 1652c393a42Smrg ret++; 1662c393a42Smrg break; 1672c393a42Smrg } 1682c393a42Smrg continue; 1692c393a42Smrg } 1702c393a42Smrg 1712c393a42Smrg if (!S_ISDIR (statb.st_mode)) 1722c393a42Smrg { 1732c393a42Smrg fprintf (stderr, "\"%s\": not a directory, skipping\n", dir); 1742c393a42Smrg continue; 1752c393a42Smrg } 1762c393a42Smrg 1772c393a42Smrg if (really_force) 1782c393a42Smrg FcDirCacheUnlink (dir, config); 1792c393a42Smrg 1802c393a42Smrg cache = NULL; 1812c393a42Smrg was_valid = FcFalse; 1822c393a42Smrg if (!force) { 1832c393a42Smrg cache = FcDirCacheLoad (dir, config, NULL); 1842c393a42Smrg if (cache) 1852c393a42Smrg was_valid = FcTrue; 1862c393a42Smrg } 1872c393a42Smrg 1882c393a42Smrg if (!cache) 1892c393a42Smrg { 190898dab68Smrg (*changed)++; 1912c393a42Smrg cache = FcDirCacheRead (dir, FcTrue, config); 1922c393a42Smrg if (!cache) 1932c393a42Smrg { 1942c393a42Smrg fprintf (stderr, "%s: error scanning\n", dir); 1952c393a42Smrg ret++; 1962c393a42Smrg continue; 1972c393a42Smrg } 1982c393a42Smrg } 1992c393a42Smrg 2002c393a42Smrg if (was_valid) 2012c393a42Smrg { 2022c393a42Smrg if (verbose) 2032c393a42Smrg printf ("skipping, existing cache is valid: %d fonts, %d dirs\n", 2042c393a42Smrg FcCacheNumFont (cache), FcCacheNumSubdir (cache)); 2052c393a42Smrg } 2062c393a42Smrg else 2072c393a42Smrg { 2082c393a42Smrg if (verbose) 2092c393a42Smrg printf ("caching, new cache contents: %d fonts, %d dirs\n", 2102c393a42Smrg FcCacheNumFont (cache), FcCacheNumSubdir (cache)); 2112c393a42Smrg 2122c393a42Smrg if (!FcDirCacheValid (dir)) 2132c393a42Smrg { 2142c393a42Smrg fprintf (stderr, "%s: failed to write cache\n", dir); 2152c393a42Smrg (void) FcDirCacheUnlink (dir, config); 2162c393a42Smrg ret++; 2172c393a42Smrg } 2182c393a42Smrg } 2192c393a42Smrg 2202c393a42Smrg subdirs = FcStrSetCreate (); 2212c393a42Smrg if (!subdirs) 2222c393a42Smrg { 2232c393a42Smrg fprintf (stderr, "%s: Can't create subdir set\n", dir); 2242c393a42Smrg ret++; 2252c393a42Smrg FcDirCacheUnload (cache); 2262c393a42Smrg continue; 2272c393a42Smrg } 2282c393a42Smrg for (i = 0; i < FcCacheNumSubdir (cache); i++) 2292c393a42Smrg FcStrSetAdd (subdirs, FcCacheSubdir (cache, i)); 2302c393a42Smrg 2312c393a42Smrg FcDirCacheUnload (cache); 2322c393a42Smrg 2332c393a42Smrg sublist = FcStrListCreate (subdirs); 2342c393a42Smrg FcStrSetDestroy (subdirs); 2352c393a42Smrg if (!sublist) 2362c393a42Smrg { 2372c393a42Smrg fprintf (stderr, "%s: Can't create subdir list\n", dir); 2382c393a42Smrg ret++; 2392c393a42Smrg continue; 2402c393a42Smrg } 2412c393a42Smrg FcStrSetAdd (processed_dirs, dir); 242898dab68Smrg ret += scanDirs (sublist, config, force, really_force, verbose, changed); 2432c393a42Smrg } 2442c393a42Smrg FcStrListDone (list); 2452c393a42Smrg return ret; 2462c393a42Smrg} 2472c393a42Smrg 2482c393a42Smrgstatic FcBool 2492c393a42SmrgcleanCacheDirectories (FcConfig *config, FcBool verbose) 2502c393a42Smrg{ 2512c393a42Smrg FcStrList *cache_dirs = FcConfigGetCacheDirs (config); 2522c393a42Smrg FcChar8 *cache_dir; 2532c393a42Smrg FcBool ret = FcTrue; 2542c393a42Smrg 2552c393a42Smrg if (!cache_dirs) 2562c393a42Smrg return FcFalse; 2572c393a42Smrg while ((cache_dir = FcStrListNext (cache_dirs))) 2582c393a42Smrg { 259898dab68Smrg if (!FcDirCacheClean (cache_dir, verbose)) 2602c393a42Smrg { 2612c393a42Smrg ret = FcFalse; 2622c393a42Smrg break; 2632c393a42Smrg } 2642c393a42Smrg } 2652c393a42Smrg FcStrListDone (cache_dirs); 2662c393a42Smrg return ret; 2672c393a42Smrg} 2682c393a42Smrg 2692c393a42Smrgint 2702c393a42Smrgmain (int argc, char **argv) 2712c393a42Smrg{ 2722c393a42Smrg FcStrSet *dirs; 2732c393a42Smrg FcStrList *list; 2742c393a42Smrg FcBool verbose = FcFalse; 2757f785a56Sjmcneill FcBool quick = FcFalse; 2762c393a42Smrg FcBool force = FcFalse; 2772c393a42Smrg FcBool really_force = FcFalse; 2782c393a42Smrg FcBool systemOnly = FcFalse; 2792c393a42Smrg FcConfig *config; 2805e61939bSmrg FcChar8 *sysroot = NULL; 2812c393a42Smrg int i; 282898dab68Smrg int changed; 2832c393a42Smrg int ret; 2842c393a42Smrg#if HAVE_GETOPT_LONG || HAVE_GETOPT 2852c393a42Smrg int c; 2862c393a42Smrg 2872c393a42Smrg#if HAVE_GETOPT_LONG 2885e61939bSmrg while ((c = getopt_long (argc, argv, "fqrsy:Vvh", longopts, NULL)) != -1) 2892c393a42Smrg#else 2905e61939bSmrg while ((c = getopt (argc, argv, "fqrsy:Vvh")) != -1) 2912c393a42Smrg#endif 2922c393a42Smrg { 2932c393a42Smrg switch (c) { 2942c393a42Smrg case 'r': 2952c393a42Smrg really_force = FcTrue; 2962c393a42Smrg /* fall through */ 2972c393a42Smrg case 'f': 2982c393a42Smrg force = FcTrue; 2992c393a42Smrg break; 3007f785a56Sjmcneill case 'q': 3017f785a56Sjmcneill quick = FcTrue; 3027f785a56Sjmcneill break; 3032c393a42Smrg case 's': 3042c393a42Smrg systemOnly = FcTrue; 3052c393a42Smrg break; 3065e61939bSmrg case 'y': 3075e61939bSmrg sysroot = FcStrCopy ((const FcChar8 *)optarg); 3085e61939bSmrg break; 3092c393a42Smrg case 'V': 3102c393a42Smrg fprintf (stderr, "fontconfig version %d.%d.%d\n", 3112c393a42Smrg FC_MAJOR, FC_MINOR, FC_REVISION); 3122c393a42Smrg exit (0); 3132c393a42Smrg case 'v': 3142c393a42Smrg verbose = FcTrue; 3152c393a42Smrg break; 316a6844aabSmrg case 'h': 317a6844aabSmrg usage (argv[0], 0); 3182c393a42Smrg default: 319a6844aabSmrg usage (argv[0], 1); 3202c393a42Smrg } 3212c393a42Smrg } 3222c393a42Smrg i = optind; 3232c393a42Smrg#else 3242c393a42Smrg i = 1; 3252c393a42Smrg#endif 3262c393a42Smrg 3272c393a42Smrg if (systemOnly) 3282c393a42Smrg FcConfigEnableHome (FcFalse); 3295e61939bSmrg if (sysroot) 3305e61939bSmrg { 3315e61939bSmrg FcConfigSetSysRoot (NULL, sysroot); 3325e61939bSmrg FcStrFree (sysroot); 3335e61939bSmrg config = FcConfigGetCurrent(); 3345e61939bSmrg } 3355e61939bSmrg else 3365e61939bSmrg { 3375e61939bSmrg config = FcInitLoadConfig (); 3385e61939bSmrg } 3392c393a42Smrg if (!config) 3402c393a42Smrg { 3412c393a42Smrg fprintf (stderr, "%s: Can't init font config library\n", argv[0]); 3422c393a42Smrg return 1; 3432c393a42Smrg } 3442c393a42Smrg FcConfigSetCurrent (config); 3452c393a42Smrg 3462c393a42Smrg if (argv[i]) 3472c393a42Smrg { 3482c393a42Smrg dirs = FcStrSetCreate (); 3492c393a42Smrg if (!dirs) 3502c393a42Smrg { 3512c393a42Smrg fprintf (stderr, "%s: Can't create list of directories\n", 3522c393a42Smrg argv[0]); 3532c393a42Smrg return 1; 3542c393a42Smrg } 3552c393a42Smrg while (argv[i]) 3562c393a42Smrg { 3572c393a42Smrg if (!FcStrSetAddFilename (dirs, (FcChar8 *) argv[i])) 3582c393a42Smrg { 3592c393a42Smrg fprintf (stderr, "%s: Can't add directory\n", argv[0]); 3602c393a42Smrg return 1; 3612c393a42Smrg } 3622c393a42Smrg i++; 3632c393a42Smrg } 3642c393a42Smrg list = FcStrListCreate (dirs); 3652c393a42Smrg FcStrSetDestroy (dirs); 3662c393a42Smrg } 3672c393a42Smrg else 3682c393a42Smrg list = FcConfigGetConfigDirs (config); 3692c393a42Smrg 3702c393a42Smrg if ((processed_dirs = FcStrSetCreate()) == NULL) { 3712c393a42Smrg fprintf(stderr, "Cannot malloc\n"); 3722c393a42Smrg return 1; 3732c393a42Smrg } 3742c393a42Smrg 375898dab68Smrg changed = 0; 376898dab68Smrg ret = scanDirs (list, config, force, really_force, verbose, &changed); 377898dab68Smrg 378898dab68Smrg /* 379898dab68Smrg * Try to create CACHEDIR.TAG anyway. 380898dab68Smrg * This expects the fontconfig cache directory already exists. 381898dab68Smrg * If it doesn't, it won't be simply created. 382898dab68Smrg */ 383898dab68Smrg FcCacheCreateTagFile (config); 3842c393a42Smrg 3852c393a42Smrg FcStrSetDestroy (processed_dirs); 3862c393a42Smrg 3872c393a42Smrg cleanCacheDirectories (config, verbose); 3882c393a42Smrg 3892c393a42Smrg /* 3902c393a42Smrg * Now we need to sleep a second (or two, to be extra sure), to make 3912c393a42Smrg * sure that timestamps for changes after this run of fc-cache are later 3922c393a42Smrg * then any timestamps we wrote. We don't use gettimeofday() because 3932c393a42Smrg * sleep(3) can't be interrupted by a signal here -- this isn't in the 3942c393a42Smrg * library, and there aren't any signals flying around here. 3952c393a42Smrg */ 3962c393a42Smrg FcConfigDestroy (config); 3972c393a42Smrg FcFini (); 398898dab68Smrg if (!quick && changed) 399898dab68Smrg sleep (2); 4002c393a42Smrg if (verbose) 4012c393a42Smrg printf ("%s: %s\n", argv[0], ret ? "failed" : "succeeded"); 4022c393a42Smrg return ret; 4032c393a42Smrg} 404