Bug 59456 - Adding a --sysroot like option to fc-cache
authorAkira TAGOH <akira@tagoh.org>
Wed, 6 Feb 2013 10:35:30 +0000 (19:35 +0900)
committerAkira TAGOH <akira@tagoh.org>
Tue, 5 Mar 2013 09:38:50 +0000 (18:38 +0900)
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
fc-cache/fc-cache.c
fontconfig/fontconfig.h
src/fccache.c
src/fccfg.c
src/fcinit.c
src/fcint.h
src/fcstr.c

index 10028b4..0491a56 100644 (file)
@@ -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.
+@@
+
index 2206096..aeb0af2 100644 (file)
@@ -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]);
index ba4ee61..fc0ed1a 100644 (file)
@@ -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);
index 2c63125..9f1c298 100644 (file)
@@ -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);
 }
 
index db878d5..b762376 100644 (file)
@@ -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__
index 2360764..b8d5d06 100644 (file)
@@ -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
  */
index 4eac610..d5a7217 100644 (file)
@@ -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);
@@ -1073,6 +1082,10 @@ FcPrivate FcBool
 FcStrUsesHome (const FcChar8 *s);
 
 FcPrivate FcChar8 *
+FcStrBuildFilename (const FcChar8 *path,
+                   ...);
+
+FcPrivate FcChar8 *
 FcStrLastSlash (const FcChar8  *path);
 
 FcPrivate FcChar32
index 414d6dd..4d11a4c 100644 (file)
@@ -30,6 +30,7 @@
 #include <regex.h>
 #endif
 
+
 /* Objects MT-safe for readonly access. */
 
 FcChar8 *
@@ -864,6 +865,64 @@ FcStrUsesHome (const FcChar8 *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)
 {
     FcChar8 *new;
@@ -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;