From e96d7760886a3781a46b3271c76af99e15cb0146 Mon Sep 17 00:00:00 2001 From: Akira TAGOH Date: Wed, 6 Feb 2013 19:35:30 +0900 Subject: [PATCH] Bug 59456 - Adding a --sysroot like option to fc-cache Add an ability to set the system root to generate the caches. In order to do this, new APIs, FcConfigGetSysRoot() and FcConfigSetSysRoot() is available. --- doc/fcconfig.fncs | 21 +++++++++ fc-cache/fc-cache.c | 38 +++++++++++----- fontconfig/fontconfig.h | 7 +++ src/fccache.c | 99 ++++++++++++++++++++++++++++------------- src/fccfg.c | 57 ++++++++++++++++++++++++ src/fcinit.c | 30 +++++++++---- src/fcint.h | 15 ++++++- src/fcstr.c | 62 +++++++++++++++++++++++++- 8 files changed, 275 insertions(+), 54 deletions(-) diff --git a/doc/fcconfig.fncs b/doc/fcconfig.fncs index 10028b4..0491a56 100644 --- a/doc/fcconfig.fncs +++ b/doc/fcconfig.fncs @@ -371,3 +371,24 @@ and parsed. If 'complain' is FcFalse, no warning will be displayed if Returns FcFalse if some error occurred while loading the file, either a parse error, semantic error or allocation failure. Otherwise returns FcTrue. @@ + +@RET@ const FcChar8 * +@FUNC@ FcConfigGetSysRoot +@TYPE1@ const FcConfig * @ARG1@ config +@PURPOSE@ Obtain the system root directory +@DESC@ +Obtrains the system root directory in 'config' if available. +@@ + +@RET@ void +@FUNC@ FcConfigSetSysRoot +@TYPE1@ FcConfig * @ARG1@ config +@TYPE2@ const FcChar8 * @ARG2@ sysroot +@PURPOSE@ Set the system root directory +@DESC@ +Set 'sysroot' as the system root directory. fontconfig prepend 'sysroot' +to the cache directories in order to allow people to generate caches at +the build time. Note that this causes changing current config. i.e. +this function calls FcConfigSetCurrent() internally. +@@ + diff --git a/fc-cache/fc-cache.c b/fc-cache/fc-cache.c index 2206096..aeb0af2 100644 --- a/fc-cache/fc-cache.c +++ b/fc-cache/fc-cache.c @@ -67,6 +67,7 @@ const struct option longopts[] = { {"force", 0, 0, 'f'}, {"really-force", 0, 0, 'r'}, + {"sysroot", 0, 0, 'y'}, {"system-only", 0, 0, 's'}, {"version", 0, 0, 'V'}, {"verbose", 0, 0, 'v'}, @@ -85,26 +86,28 @@ usage (char *program, int error) { FILE *file = error ? stderr : stdout; #if HAVE_GETOPT_LONG - fprintf (file, "usage: %s [-frsvVh] [--force|--really-force] [--system-only] [--verbose] [--version] [--help] [dirs]\n", + fprintf (file, "usage: %s [-frsvVh] [-y SYSROOT] [--force|--really-force] [--sysroot=SYSROOT] [--system-only] [--verbose] [--version] [--help] [dirs]\n", program); #else - fprintf (file, "usage: %s [-frsvVh] [dirs]\n", + fprintf (file, "usage: %s [-frsvVh] [-y SYSROOT] [dirs]\n", program); #endif fprintf (file, "Build font information caches in [dirs]\n" "(all directories in font configuration by default).\n"); fprintf (file, "\n"); #if HAVE_GETOPT_LONG - fprintf (file, " -f, --force scan directories with apparently valid caches\n"); - fprintf (file, " -r, --really-force erase all existing caches, then rescan\n"); - fprintf (file, " -s, --system-only scan system-wide directories only\n"); - fprintf (file, " -v, --verbose display status information while busy\n"); - fprintf (file, " -V, --version display font config version and exit\n"); - fprintf (file, " -h, --help display this help and exit\n"); + fprintf (file, " -f, --force scan directories with apparently valid caches\n"); + fprintf (file, " -r, --really-force erase all existing caches, then rescan\n"); + fprintf (file, " -s, --system-only scan system-wide directories only\n"); + fprintf (file, " -y, --sysroot=SYSROOT prepend SYSROOT to all paths for scanning\n"); + fprintf (file, " -v, --verbose display status information while busy\n"); + fprintf (file, " -V, --version display font config version and exit\n"); + fprintf (file, " -h, --help display this help and exit\n"); #else fprintf (file, " -f (force) scan directories with apparently valid caches\n"); fprintf (file, " -r, (really force) erase all existing caches, then rescan\n"); fprintf (file, " -s (system) scan system-wide directories only\n"); + fprintf (file, " -y SYSROOT (sysroot) prepend SYSROOT to all paths for scanning\n"); fprintf (file, " -v (verbose) display status information while busy\n"); fprintf (file, " -V (version) display font config version and exit\n"); fprintf (file, " -h (help) display this help and exit\n"); @@ -270,6 +273,7 @@ main (int argc, char **argv) FcBool really_force = FcFalse; FcBool systemOnly = FcFalse; FcConfig *config; + FcChar8 *sysroot = NULL; int i; int changed; int ret; @@ -277,9 +281,9 @@ main (int argc, char **argv) int c; #if HAVE_GETOPT_LONG - while ((c = getopt_long (argc, argv, "frsVvh", longopts, NULL)) != -1) + while ((c = getopt_long (argc, argv, "frsy:Vvh", longopts, NULL)) != -1) #else - while ((c = getopt (argc, argv, "frsVvh")) != -1) + while ((c = getopt (argc, argv, "frsy:Vvh")) != -1) #endif { switch (c) { @@ -292,6 +296,9 @@ main (int argc, char **argv) case 's': systemOnly = FcTrue; break; + case 'y': + sysroot = FcStrCopy ((const FcChar8 *)optarg); + break; case 'V': fprintf (stderr, "fontconfig version %d.%d.%d\n", FC_MAJOR, FC_MINOR, FC_REVISION); @@ -312,7 +319,16 @@ main (int argc, char **argv) if (systemOnly) FcConfigEnableHome (FcFalse); - config = FcInitLoadConfig (); + if (sysroot) + { + FcConfigSetSysRoot (NULL, sysroot); + FcStrFree (sysroot); + config = FcConfigGetCurrent(); + } + else + { + config = FcInitLoadConfig (); + } if (!config) { fprintf (stderr, "%s: Can't init font config library\n", argv[0]); diff --git a/fontconfig/fontconfig.h b/fontconfig/fontconfig.h index ba4ee61..fc0ed1a 100644 --- a/fontconfig/fontconfig.h +++ b/fontconfig/fontconfig.h @@ -420,6 +420,13 @@ FcConfigSubstitute (FcConfig *config, FcPattern *p, FcMatchKind kind); +FcPublic const FcChar8 * +FcConfigGetSysRoot (const FcConfig *config); + +FcPublic void +FcConfigSetSysRoot (FcConfig *config, + const FcChar8 *sysroot); + /* fccharset.c */ FcPublic FcCharSet* FcCharSetCreate (void); diff --git a/src/fccache.c b/src/fccache.c index 2c63125..9f1c298 100644 --- a/src/fccache.c +++ b/src/fccache.c @@ -124,6 +124,7 @@ FcDirCacheUnlink (const FcChar8 *dir, FcConfig *config) FcChar8 cache_base[CACHEBASE_LEN]; FcStrList *list; FcChar8 *cache_dir; + const FcChar8 *sysroot = FcConfigGetSysRoot (config); FcDirCacheBasename (dir, cache_base); @@ -133,7 +134,10 @@ FcDirCacheUnlink (const FcChar8 *dir, FcConfig *config) while ((cache_dir = FcStrListNext (list))) { - cache_hashed = FcStrPlus (cache_dir, cache_base); + if (sysroot) + cache_hashed = FcStrBuildFilename (sysroot, cache_dir, cache_base, NULL); + else + cache_hashed = FcStrBuildFilename (cache_dir, cache_base, NULL); if (!cache_hashed) break; (void) unlink ((char *) cache_hashed); @@ -197,7 +201,13 @@ FcDirCacheProcess (FcConfig *config, const FcChar8 *dir, while ((cache_dir = FcStrListNext (list))) { - FcChar8 *cache_hashed = FcStrPlus (cache_dir, cache_base); + const FcChar8 *sysroot = FcConfigGetSysRoot (config); + FcChar8 *cache_hashed; + + if (sysroot) + cache_hashed = FcStrBuildFilename (sysroot, cache_dir, cache_base, NULL); + else + cache_hashed = FcStrBuildFilename (cache_dir, cache_base, NULL); if (!cache_hashed) break; fd = FcDirCacheOpenFile (cache_hashed, &file_stat); @@ -859,11 +869,12 @@ FcDirCacheWrite (FcCache *cache, FcConfig *config) FcAtomic *atomic; FcStrList *list; FcChar8 *cache_dir = NULL; - FcChar8 *test_dir; + FcChar8 *test_dir, *d = NULL; FcCacheSkip *skip; struct stat cache_stat; unsigned int magic; int written; + const FcChar8 *sysroot = FcConfigGetSysRoot (config); /* * Write it to the first directory in the list which is writable @@ -872,10 +883,18 @@ FcDirCacheWrite (FcCache *cache, FcConfig *config) list = FcStrListCreate (config->cacheDirs); if (!list) return FcFalse; - while ((test_dir = FcStrListNext (list))) { - if (access ((char *) test_dir, W_OK) == 0) + while ((test_dir = FcStrListNext (list))) + { + if (d) + FcStrFree (d); + if (sysroot) + d = FcStrBuildFilename (sysroot, test_dir, NULL); + else + d = FcStrCopyFilename (test_dir); + + if (access ((char *) d, W_OK) == 0) { - cache_dir = test_dir; + cache_dir = FcStrCopyFilename (d); break; } else @@ -883,35 +902,38 @@ FcDirCacheWrite (FcCache *cache, FcConfig *config) /* * If the directory doesn't exist, try to create it */ - if (access ((char *) test_dir, F_OK) == -1) { - if (FcMakeDirectory (test_dir)) + if (access ((char *) d, F_OK) == -1) { + if (FcMakeDirectory (d)) { - cache_dir = test_dir; + cache_dir = FcStrCopyFilename (d); /* Create CACHEDIR.TAG */ - FcDirCacheCreateTagFile (cache_dir); + FcDirCacheCreateTagFile (d); break; } } /* * Otherwise, try making it writable */ - else if (chmod ((char *) test_dir, 0755) == 0) + else if (chmod ((char *) d, 0755) == 0) { - cache_dir = test_dir; + cache_dir = FcStrCopyFilename (d); /* Try to create CACHEDIR.TAG too */ - FcDirCacheCreateTagFile (cache_dir); + FcDirCacheCreateTagFile (d); break; } } } + if (d) + FcStrFree (d); FcStrListDone (list); if (!cache_dir) return FcFalse; FcDirCacheBasename (dir, cache_base); - cache_hashed = FcStrPlus (cache_dir, cache_base); + cache_hashed = FcStrBuildFilename (cache_dir, cache_base, NULL); if (!cache_hashed) return FcFalse; + FcStrFree (cache_dir); if (FcDebug () & FC_DBG_CACHE) printf ("FcDirCacheWriteDir dir \"%s\" file \"%s\"\n", @@ -989,31 +1011,37 @@ FcDirCacheClean (const FcChar8 *cache_dir, FcBool verbose) { DIR *d; struct dirent *ent; - FcChar8 *dir_base; + FcChar8 *dir; FcBool ret = FcTrue; FcBool remove; FcCache *cache; struct stat target_stat; + const FcChar8 *sysroot; - dir_base = FcStrPlus (cache_dir, (FcChar8 *) FC_DIR_SEPARATOR_S); - if (!dir_base) + /* FIXME: this API needs to support non-current FcConfig */ + sysroot = FcConfigGetSysRoot (NULL); + if (sysroot) + dir = FcStrBuildFilename (sysroot, cache_dir, NULL); + else + dir = FcStrCopyFilename (cache_dir); + if (!dir) { fprintf (stderr, "Fontconfig error: %s: out of memory\n", cache_dir); return FcFalse; } - if (access ((char *) cache_dir, W_OK) != 0) + if (access ((char *) dir, W_OK) != 0) { if (verbose || FcDebug () & FC_DBG_CACHE) - printf ("%s: not cleaning %s cache directory\n", cache_dir, - access ((char *) cache_dir, F_OK) == 0 ? "unwritable" : "non-existent"); + printf ("%s: not cleaning %s cache directory\n", dir, + access ((char *) dir, F_OK) == 0 ? "unwritable" : "non-existent"); goto bail0; } if (verbose || FcDebug () & FC_DBG_CACHE) - printf ("%s: cleaning cache directory\n", cache_dir); - d = opendir ((char *) cache_dir); + printf ("%s: cleaning cache directory\n", dir); + d = opendir ((char *) dir); if (!d) { - perror ((char *) cache_dir); + perror ((char *) dir); ret = FcFalse; goto bail0; } @@ -1030,10 +1058,10 @@ FcDirCacheClean (const FcChar8 *cache_dir, FcBool verbose) strcmp(ent->d_name + 32, "-" FC_ARCHITECTURE FC_CACHE_SUFFIX)) continue; - file_name = FcStrPlus (dir_base, (FcChar8 *) ent->d_name); + file_name = FcStrBuildFilename (dir, (FcChar8 *)ent->d_name, NULL); if (!file_name) { - fprintf (stderr, "Fontconfig error: %s: allocation failure\n", cache_dir); + fprintf (stderr, "Fontconfig error: %s: allocation failure\n", dir); ret = FcFalse; break; } @@ -1042,7 +1070,7 @@ FcDirCacheClean (const FcChar8 *cache_dir, FcBool verbose) if (!cache) { if (verbose || FcDebug () & FC_DBG_CACHE) - printf ("%s: invalid cache file: %s\n", cache_dir, ent->d_name); + printf ("%s: invalid cache file: %s\n", dir, ent->d_name); remove = FcTrue; } else @@ -1052,7 +1080,7 @@ FcDirCacheClean (const FcChar8 *cache_dir, FcBool verbose) { if (verbose || FcDebug () & FC_DBG_CACHE) printf ("%s: %s: missing directory: %s \n", - cache_dir, ent->d_name, target_dir); + dir, ent->d_name, target_dir); remove = FcTrue; } FcDirCacheUnload (cache); @@ -1070,7 +1098,7 @@ FcDirCacheClean (const FcChar8 *cache_dir, FcBool verbose) closedir (d); bail0: - FcStrFree (dir_base); + FcStrFree (dir); return ret; } @@ -1394,7 +1422,7 @@ FcDirCacheCreateTagFile (const FcChar8 *cache_dir) if (access ((char *) cache_dir, W_OK) == 0) { /* Create CACHEDIR.TAG */ - cache_tag = FcStrPlus (cache_dir, (const FcChar8 *) FC_DIR_SEPARATOR_S "CACHEDIR.TAG"); + cache_tag = FcStrBuildFilename (cache_dir, "CACHEDIR.TAG", NULL); if (!cache_tag) return FcFalse; atomic = FcAtomicCreate ((FcChar8 *)cache_tag); @@ -1438,8 +1466,9 @@ FcDirCacheCreateTagFile (const FcChar8 *cache_dir) void FcCacheCreateTagFile (const FcConfig *config) { - FcChar8 *cache_dir = NULL; + FcChar8 *cache_dir = NULL, *d = NULL; FcStrList *list; + const FcChar8 *sysroot = FcConfigGetSysRoot (config); list = FcConfigGetCacheDirs (config); if (!list) @@ -1447,9 +1476,17 @@ FcCacheCreateTagFile (const FcConfig *config) while ((cache_dir = FcStrListNext (list))) { - if (FcDirCacheCreateTagFile (cache_dir)) + if (d) + FcStrFree (d); + if (sysroot) + d = FcStrBuildFilename (sysroot, cache_dir, NULL); + else + d = FcStrCopyFilename (cache_dir); + if (FcDirCacheCreateTagFile (d)) break; } + if (d) + FcStrFree (d); FcStrListDone (list); } diff --git a/src/fccfg.c b/src/fccfg.c index db878d5..b762376 100644 --- a/src/fccfg.c +++ b/src/fccfg.c @@ -123,6 +123,8 @@ FcConfigCreate (void) config->expr_pool = NULL; + config->sysRoot = NULL; + FcRefInit (&config->ref, 1); return config; @@ -292,6 +294,8 @@ FcConfigDestroy (FcConfig *config) free (page); page = next; } + if (config->sysRoot) + FcStrFree (config->sysRoot); free (config); } @@ -2309,6 +2313,59 @@ FcConfigAcceptFont (FcConfig *config, return FcFalse; return FcTrue; } + +const FcChar8 * +FcConfigGetSysRoot (const FcConfig *config) +{ + if (!config) + { + config = FcConfigGetCurrent (); + if (!config) + return NULL; + } + + return config->sysRoot; +} + +void +FcConfigSetSysRoot (FcConfig *config, + const FcChar8 *sysroot) +{ + FcChar8 *s; + FcBool init = FcFalse; + + if (!config) + { + /* We can't use FcConfigGetCurrent() here to ensure + * the sysroot is set prior to initialize FcConfig, + * to avoid loading caches from non-sysroot dirs. + * So postpone the initialization later. + */ + config = fc_atomic_ptr_get (&_fcConfig); + if (!config) + { + config = FcConfigCreate (); + if (!config) + return; + init = FcTrue; + } + } + + s = FcStrCopyFilename (sysroot); + if (!s) + return; + + if (config->sysRoot) + FcStrFree (config->sysRoot); + + config->sysRoot = s; + if (init) + { + config = FcInitLoadOwnConfigAndFonts (config); + FcConfigSetCurrent (config); + } +} + #define __fccfg__ #include "fcaliastail.h" #undef __fccfg__ diff --git a/src/fcinit.c b/src/fcinit.c index 2360764..b8d5d06 100644 --- a/src/fcinit.c +++ b/src/fcinit.c @@ -65,14 +65,16 @@ FcGetVersion (void) * Load the configuration files */ FcConfig * -FcInitLoadConfig (void) +FcInitLoadOwnConfig (FcConfig *config) { - FcConfig *config; + if (!config) + { + config = FcConfigCreate (); + if (!config) + return NULL; + } FcInitDebug (); - config = FcConfigCreate (); - if (!config) - return NULL; if (!FcConfigParseAndLoad (config, 0, FcTrue)) { @@ -120,15 +122,19 @@ FcInitLoadConfig (void) return config; } +FcConfig * +FcInitLoadConfig (void) +{ + return FcInitLoadOwnConfig (NULL); +} + /* * Load the configuration files and scan for available fonts */ FcConfig * -FcInitLoadConfigAndFonts (void) +FcInitLoadOwnConfigAndFonts (FcConfig *config) { - FcConfig *config = FcInitLoadConfig (); - - FcInitDebug (); + config = FcInitLoadOwnConfig (config); if (!config) return 0; if (!FcConfigBuildFonts (config)) @@ -139,6 +145,12 @@ FcInitLoadConfigAndFonts (void) return config; } +FcConfig * +FcInitLoadConfigAndFonts (void) +{ + return FcInitLoadOwnConfigAndFonts (NULL); +} + /* * Initialize the default library configuration */ diff --git a/src/fcint.h b/src/fcint.h index 4eac610..d5a7217 100644 --- a/src/fcint.h +++ b/src/fcint.h @@ -501,7 +501,9 @@ struct _FcConfig { FcRef ref; /* reference count */ - FcExprPage *expr_pool; /* pool of FcExpr's */ + FcExprPage *expr_pool; /* pool of FcExpr's */ + + FcChar8 *sysRoot; /* override the system root directory */ }; typedef struct _FcFileTime { @@ -819,6 +821,13 @@ FcHashGetSHA256Digest (const FcChar8 *input_strings, FcPrivate FcChar8 * FcHashGetSHA256DigestFromFile (const FcChar8 *filename); +/* fcinit.c */ +FcPrivate FcConfig * +FcInitLoadOwnConfig (FcConfig *config); + +FcPrivate FcConfig * +FcInitLoadOwnConfigAndFonts (FcConfig *config); + /* fcxml.c */ FcPrivate void FcTestDestroy (FcTest *test); @@ -1072,6 +1081,10 @@ FcStrContainsWord (const FcChar8 *s1, const FcChar8 *s2); FcPrivate FcBool FcStrUsesHome (const FcChar8 *s); +FcPrivate FcChar8 * +FcStrBuildFilename (const FcChar8 *path, + ...); + FcPrivate FcChar8 * FcStrLastSlash (const FcChar8 *path); diff --git a/src/fcstr.c b/src/fcstr.c index 414d6dd..4d11a4c 100644 --- a/src/fcstr.c +++ b/src/fcstr.c @@ -30,6 +30,7 @@ #include #endif + /* Objects MT-safe for readonly access. */ FcChar8 * @@ -863,6 +864,64 @@ FcStrUsesHome (const FcChar8 *s) return *s == '~'; } +FcChar8 * +FcStrBuildFilename (const FcChar8 *path, + ...) +{ + va_list ap; + FcStrSet *sset = FcStrSetCreate (); + FcStrList *list; + FcChar8 *s, *ret = NULL, *p; + size_t len = 0; + + if (!sset || !path) + return NULL; + + if (!FcStrSetAdd (sset, path)) + goto bail0; + + va_start (ap, path); + while (1) + { + s = (FcChar8 *)va_arg (ap, FcChar8 *); + if (!s) + break; + if (!FcStrSetAdd (sset, s)) + goto bail1; + } + list = FcStrListCreate (sset); + while ((s = FcStrListNext (list))) + { + len += strlen ((const char *)s) + 1; + } + list->n = 0; + ret = malloc (sizeof (FcChar8) * (len + 1)); + if (!ret) + goto bail2; + p = ret; + while ((s = FcStrListNext (list))) + { + if (p != ret) + { + p[0] = FC_DIR_SEPARATOR; + p++; + } + len = strlen ((const char *)s); + memcpy (p, s, len); + p += len; + } + *p = 0; + +bail2: + FcStrListDone (list); +bail1: + va_end (ap); +bail0: + FcStrSetDestroy (sset); + + return ret; +} + FcChar8 * FcStrCopyFilename (const FcChar8 *s) { @@ -1052,8 +1111,7 @@ FcStrCanonFilename (const FcChar8 *s) FcChar8 cwd[FC_MAX_FILE_LEN + 2]; if (getcwd ((char *) cwd, FC_MAX_FILE_LEN) == NULL) return NULL; - strcat ((char *) cwd, "/"); - full = FcStrPlus (cwd, s); + full = FcStrBuildFilename (cwd, s, NULL); file = FcStrCanonAbsoluteFilename (full); FcStrFree (full); return file;