Add support for XDG_DATA_DIRS

Add dirs from XDG_DATA_DIRS when <dir prefix="xdg"> appears in fonts.conf

Fixes https://gitlab.freedesktop.org/fontconfig/fontconfig/-/issues/271
This commit is contained in:
Akira TAGOH 2021-03-29 21:25:21 +09:00
parent b03140c14e
commit 6f27f42e61
4 changed files with 166 additions and 36 deletions

View File

@ -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)
{

View File

@ -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);

View File

@ -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;

View File

@ -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)
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, 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