From 6f27f42e6140030715075aa3bd3e5cc9e2fdc6f1 Mon Sep 17 00:00:00 2001 From: Akira TAGOH Date: Mon, 29 Mar 2021 21:25:21 +0900 Subject: Add support for XDG_DATA_DIRS Add dirs from XDG_DATA_DIRS when appears in fonts.conf Fixes https://gitlab.freedesktop.org/fontconfig/fontconfig/-/issues/271 --- src/fccfg.c | 59 +++++++++++++++++++++++++++++++++++++ src/fcint.h | 6 ++++ src/fcstr.c | 39 ++++++++++++++++++++---- src/fcxml.c | 98 ++++++++++++++++++++++++++++++++++++++++++------------------- 4 files changed, 166 insertions(+), 36 deletions(-) diff --git a/src/fccfg.c b/src/fccfg.c index 462c423..21fc9b1 100644 --- a/src/fccfg.c +++ b/src/fccfg.c @@ -2614,6 +2614,65 @@ FcConfigXdgDataHome (void) return ret; } +FcStrSet * +FcConfigXdgDataDirs (void) +{ + const char *env = getenv ("XDG_DATA_DIRS"); + FcStrSet *ret = FcStrSetCreate (); + + if (env) + { + FcChar8 *ee, *e = ee = FcStrCopy ((const FcChar8 *) env); + + /* We don't intentionally use FC_SEARCH_PATH_SEPARATOR here because of: + * The directories in $XDG_DATA_DIRS should be seperated with a colon ':'. + * in doc. + */ + while (e) + { + FcChar8 *p = (FcChar8 *) strchr ((const char *) e, ':'); + FcChar8 *s; + size_t len; + + if (!p) + { + s = FcStrCopy (e); + e = NULL; + } + else + { + *p = 0; + s = FcStrCopy (e); + e = p + 1; + } + len = strlen ((const char *) s); + if (s[len - 1] == FC_DIR_SEPARATOR) + { + do + { + len--; + } + while (len > 1 && s[len - 1] == FC_DIR_SEPARATOR); + s[len] = 0; + } + FcStrSetAdd (ret, s); + FcStrFree (s); + } + FcStrFree (ee); + } + else + { + /* From spec doc at https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html#variables + * + * If $XDG_DATA_DIRS is either not set or empty, a value equal to /usr/local/share/:/usr/share/ should be used. + */ + FcStrSetAdd (ret, (const FcChar8 *) "/usr/local/share"); + FcStrSetAdd (ret, (const FcChar8 *) "/usr/share"); + } + + return ret; +} + FcBool FcConfigEnableHome (FcBool enable) { diff --git a/src/fcint.h b/src/fcint.h index 2d4a2c4..4150a05 100644 --- a/src/fcint.h +++ b/src/fcint.h @@ -664,6 +664,9 @@ FcConfigXdgConfigHome (void); FcPrivate FcChar8 * FcConfigXdgDataHome (void); +FcPrivate FcStrSet * +FcConfigXdgDataDirs (void); + FcPrivate FcExpr * FcConfigAllocExpr (FcConfig *config); @@ -1257,6 +1260,9 @@ FcIsFsMtimeBroken (const FcChar8 *dir); FcPrivate FcStrSet * FcStrSetCreateEx (unsigned int control); +FcPrivate FcBool +FcStrSetInsert (FcStrSet *set, const FcChar8 *s, int pos); + FcPrivate FcBool FcStrSetAddLangs (FcStrSet *strs, const char *languages); diff --git a/src/fcstr.c b/src/fcstr.c index 8971b71..765f711 100644 --- a/src/fcstr.c +++ b/src/fcstr.c @@ -1252,7 +1252,7 @@ _FcStrSetGrow (FcStrSet *set, int growElements) } static FcBool -_FcStrSetAppend (FcStrSet *set, FcChar8 *s) +_FcStrSetInsert (FcStrSet *set, FcChar8 *s, int pos) { if (!FcStrSetHasControlBit (set, FCSS_ALLOW_DUPLICATES)) { @@ -1268,8 +1268,21 @@ _FcStrSetAppend (FcStrSet *set, FcChar8 *s) if (!_FcStrSetGrow(set, growElements)) return FcFalse; } - set->strs[set->num++] = s; - set->strs[set->num] = 0; + if (pos >= set->num) + { + set->strs[set->num++] = s; + set->strs[set->num] = 0; + } + else + { + int i; + + set->num++; + set->strs[set->num] = 0; + for (i = set->num - 1; i > pos; i--) + set->strs[i] = set->strs[i - 1]; + set->strs[pos] = s; + } return FcTrue; } @@ -1354,7 +1367,21 @@ FcStrSetAdd (FcStrSet *set, const FcChar8 *s) FcChar8 *new = FcStrCopy (s); if (!new) return FcFalse; - if (!_FcStrSetAppend (set, new)) + if (!_FcStrSetInsert (set, new, set->num)) + { + FcStrFree (new); + return FcFalse; + } + return FcTrue; +} + +FcBool +FcStrSetInsert (FcStrSet *set, const FcChar8 *s, int pos) +{ + FcChar8 *new = FcStrCopy (s); + if (!new) + return FcFalse; + if (!_FcStrSetInsert (set, new, pos)) { FcStrFree (new); return FcFalse; @@ -1368,7 +1395,7 @@ FcStrSetAddTriple (FcStrSet *set, const FcChar8 *a, const FcChar8 *b, const FcCh FcChar8 *new = FcStrMakeTriple (a, b, c); if (!new) return FcFalse; - if (!_FcStrSetAppend (set, new)) + if (!_FcStrSetInsert (set, new, set->num)) { FcStrFree (new); return FcFalse; @@ -1403,7 +1430,7 @@ FcStrSetAddFilename (FcStrSet *set, const FcChar8 *s) FcChar8 *new = FcStrCopyFilename (s); if (!new) return FcFalse; - if (!_FcStrSetAppend (set, new)) + if (!_FcStrSetInsert (set, new, set->num)) { FcStrFree (new); return FcFalse; diff --git a/src/fcxml.c b/src/fcxml.c index 9efe157..0db318c 100644 --- a/src/fcxml.c +++ b/src/fcxml.c @@ -1285,20 +1285,22 @@ FcConfigGetAttribute (FcConfigParse *parse, const char *attr) return 0; } -static FcChar8 * -_get_real_path_from_prefix(FcConfigParse *parse, const FcChar8 *path, const FcChar8 *prefix) +static FcStrSet * +_get_real_paths_from_prefix(FcConfigParse *parse, const FcChar8 *path, const FcChar8 *prefix) { #ifdef _WIN32 FcChar8 buffer[1000] = { 0 }; #endif FcChar8 *parent = NULL, *retval = NULL; + FcStrSet *e = NULL; if (prefix) { if (FcStrCmp (prefix, (const FcChar8 *) "xdg") == 0) { parent = FcConfigXdgDataHome (); - if (!parent) + e = FcConfigXdgDataDirs (); + if (!parent || !e) { /* Home directory might be disabled */ return NULL; @@ -1388,8 +1390,28 @@ _get_real_path_from_prefix(FcConfigParse *parse, const FcChar8 *path, const FcCh { retval = FcStrdup (path); } + if (!e) + e = FcStrSetCreate (); + else + { + FcChar8 *s; + int i; - return retval; + for (i = 0; i < e->num; i++) + { + s = FcStrBuildFilename (e->strs[i], path, NULL); + FcStrFree (e->strs[i]); + e->strs[i] = s; + } + } + if (!FcStrSetInsert (e, retval, 0)) + { + FcStrSetDestroy (e); + e = NULL; + } + FcStrFree (retval); + + return e; } static void @@ -2062,7 +2084,7 @@ static void FcParseRemapDir (FcConfigParse *parse) { const FcChar8 *path, *attr, *data, *salt; - FcChar8 *prefix = NULL; + FcStrSet *prefix_dirs = NULL; data = FcStrBufDoneStatic (&parse->pstack->str); if (!data) @@ -2083,20 +2105,28 @@ FcParseRemapDir (FcConfigParse *parse) } attr = FcConfigGetAttribute (parse, "prefix"); salt = FcConfigGetAttribute (parse, "salt"); - prefix = _get_real_path_from_prefix (parse, data, attr); - if (!prefix || prefix[0] == 0) + prefix_dirs = _get_real_paths_from_prefix (parse, data, attr); + if (prefix_dirs) { - /* nop */ - } - else if (!parse->scanOnly && (!FcStrUsesHome (prefix) || FcConfigHome ())) - { - if (!FcConfigAddFontDir (parse->config, prefix, path, salt)) - FcConfigMessage (parse, FcSevereError, "out of memory; cannot create remap data for %s as %s", prefix, path); - } - FcStrBufDestroy (&parse->pstack->str); + FcStrList *l = FcStrListCreate (prefix_dirs); + FcChar8 *prefix; - if (prefix) - FcStrFree (prefix); + FcStrSetDestroy (prefix_dirs); + while ((prefix = FcStrListNext (l))) + { + if (!prefix || prefix[0] == 0) + { + /* nop */ + } + else if (!parse->scanOnly && (!FcStrUsesHome (prefix) || FcConfigHome ())) + { + if (!FcConfigAddFontDir (parse->config, prefix, path, salt)) + FcConfigMessage (parse, FcSevereError, "out of memory; cannot create remap data for %s as %s", prefix, path); + } + FcStrBufDestroy (&parse->pstack->str); + } + FcStrListDone (l); + } } static void @@ -2250,7 +2280,7 @@ static void FcParseDir (FcConfigParse *parse) { const FcChar8 *attr, *data, *salt; - FcChar8 *prefix = NULL; + FcStrSet *prefix_dirs = NULL; data = FcStrBufDoneStatic (&parse->pstack->str); if (!data) @@ -2265,20 +2295,28 @@ FcParseDir (FcConfigParse *parse) } attr = FcConfigGetAttribute (parse, "prefix"); salt = FcConfigGetAttribute (parse, "salt"); - prefix = _get_real_path_from_prefix (parse, data, attr); - if (!prefix || prefix[0] == 0) - { - /* nop */ - } - else if (!parse->scanOnly && (!FcStrUsesHome (prefix) || FcConfigHome ())) + prefix_dirs = _get_real_paths_from_prefix (parse, data, attr); + if (prefix_dirs) { - if (!FcConfigAddFontDir (parse->config, prefix, NULL, salt)) - FcConfigMessage (parse, FcSevereError, "out of memory; cannot add directory %s", prefix); - } - FcStrBufDestroy (&parse->pstack->str); + FcStrList *l = FcStrListCreate (prefix_dirs); + FcChar8 *prefix; - if (prefix) - FcStrFree (prefix); + FcStrSetDestroy (prefix_dirs); + while ((prefix = FcStrListNext (l))) + { + if (!prefix || prefix[0] == 0) + { + /* nop */ + } + else if (!parse->scanOnly && (!FcStrUsesHome (prefix) || FcConfigHome ())) + { + if (!FcConfigAddFontDir (parse->config, prefix, NULL, salt)) + FcConfigMessage (parse, FcSevereError, "out of memory; cannot add directory %s", prefix); + } + FcStrBufDestroy (&parse->pstack->str); + } + FcStrListDone (l); + } } static void -- cgit v1.2.3