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; 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 FcBool
FcConfigEnableHome (FcBool enable) FcConfigEnableHome (FcBool enable)
{ {

View File

@ -664,6 +664,9 @@ FcConfigXdgConfigHome (void);
FcPrivate FcChar8 * FcPrivate FcChar8 *
FcConfigXdgDataHome (void); FcConfigXdgDataHome (void);
FcPrivate FcStrSet *
FcConfigXdgDataDirs (void);
FcPrivate FcExpr * FcPrivate FcExpr *
FcConfigAllocExpr (FcConfig *config); FcConfigAllocExpr (FcConfig *config);
@ -1257,6 +1260,9 @@ FcIsFsMtimeBroken (const FcChar8 *dir);
FcPrivate FcStrSet * FcPrivate FcStrSet *
FcStrSetCreateEx (unsigned int control); FcStrSetCreateEx (unsigned int control);
FcPrivate FcBool
FcStrSetInsert (FcStrSet *set, const FcChar8 *s, int pos);
FcPrivate FcBool FcPrivate FcBool
FcStrSetAddLangs (FcStrSet *strs, const char *languages); FcStrSetAddLangs (FcStrSet *strs, const char *languages);

View File

@ -1252,7 +1252,7 @@ _FcStrSetGrow (FcStrSet *set, int growElements)
} }
static FcBool static FcBool
_FcStrSetAppend (FcStrSet *set, FcChar8 *s) _FcStrSetInsert (FcStrSet *set, FcChar8 *s, int pos)
{ {
if (!FcStrSetHasControlBit (set, FCSS_ALLOW_DUPLICATES)) if (!FcStrSetHasControlBit (set, FCSS_ALLOW_DUPLICATES))
{ {
@ -1268,8 +1268,21 @@ _FcStrSetAppend (FcStrSet *set, FcChar8 *s)
if (!_FcStrSetGrow(set, growElements)) if (!_FcStrSetGrow(set, growElements))
return FcFalse; return FcFalse;
} }
set->strs[set->num++] = s; if (pos >= set->num)
set->strs[set->num] = 0; {
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; return FcTrue;
} }
@ -1354,7 +1367,21 @@ FcStrSetAdd (FcStrSet *set, const FcChar8 *s)
FcChar8 *new = FcStrCopy (s); FcChar8 *new = FcStrCopy (s);
if (!new) if (!new)
return FcFalse; 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); FcStrFree (new);
return FcFalse; return FcFalse;
@ -1368,7 +1395,7 @@ FcStrSetAddTriple (FcStrSet *set, const FcChar8 *a, const FcChar8 *b, const FcCh
FcChar8 *new = FcStrMakeTriple (a, b, c); FcChar8 *new = FcStrMakeTriple (a, b, c);
if (!new) if (!new)
return FcFalse; return FcFalse;
if (!_FcStrSetAppend (set, new)) if (!_FcStrSetInsert (set, new, set->num))
{ {
FcStrFree (new); FcStrFree (new);
return FcFalse; return FcFalse;
@ -1403,7 +1430,7 @@ FcStrSetAddFilename (FcStrSet *set, const FcChar8 *s)
FcChar8 *new = FcStrCopyFilename (s); FcChar8 *new = FcStrCopyFilename (s);
if (!new) if (!new)
return FcFalse; return FcFalse;
if (!_FcStrSetAppend (set, new)) if (!_FcStrSetInsert (set, new, set->num))
{ {
FcStrFree (new); FcStrFree (new);
return FcFalse; return FcFalse;

View File

@ -1285,20 +1285,22 @@ FcConfigGetAttribute (FcConfigParse *parse, const char *attr)
return 0; return 0;
} }
static FcChar8 * static FcStrSet *
_get_real_path_from_prefix(FcConfigParse *parse, const FcChar8 *path, const FcChar8 *prefix) _get_real_paths_from_prefix(FcConfigParse *parse, const FcChar8 *path, const FcChar8 *prefix)
{ {
#ifdef _WIN32 #ifdef _WIN32
FcChar8 buffer[1000] = { 0 }; FcChar8 buffer[1000] = { 0 };
#endif #endif
FcChar8 *parent = NULL, *retval = NULL; FcChar8 *parent = NULL, *retval = NULL;
FcStrSet *e = NULL;
if (prefix) if (prefix)
{ {
if (FcStrCmp (prefix, (const FcChar8 *) "xdg") == 0) if (FcStrCmp (prefix, (const FcChar8 *) "xdg") == 0)
{ {
parent = FcConfigXdgDataHome (); parent = FcConfigXdgDataHome ();
if (!parent) e = FcConfigXdgDataDirs ();
if (!parent || !e)
{ {
/* Home directory might be disabled */ /* Home directory might be disabled */
return NULL; return NULL;
@ -1388,8 +1390,28 @@ _get_real_path_from_prefix(FcConfigParse *parse, const FcChar8 *path, const FcCh
{ {
retval = FcStrdup (path); 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 static void
@ -2062,7 +2084,7 @@ static void
FcParseRemapDir (FcConfigParse *parse) FcParseRemapDir (FcConfigParse *parse)
{ {
const FcChar8 *path, *attr, *data, *salt; const FcChar8 *path, *attr, *data, *salt;
FcChar8 *prefix = NULL; FcStrSet *prefix_dirs = NULL;
data = FcStrBufDoneStatic (&parse->pstack->str); data = FcStrBufDoneStatic (&parse->pstack->str);
if (!data) if (!data)
@ -2083,20 +2105,28 @@ FcParseRemapDir (FcConfigParse *parse)
} }
attr = FcConfigGetAttribute (parse, "prefix"); attr = FcConfigGetAttribute (parse, "prefix");
salt = FcConfigGetAttribute (parse, "salt"); salt = FcConfigGetAttribute (parse, "salt");
prefix = _get_real_path_from_prefix (parse, data, attr); prefix_dirs = _get_real_paths_from_prefix (parse, data, attr);
if (!prefix || prefix[0] == 0) if (prefix_dirs)
{ {
/* nop */ FcStrList *l = FcStrListCreate (prefix_dirs);
} FcChar8 *prefix;
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);
if (prefix) FcStrSetDestroy (prefix_dirs);
FcStrFree (prefix); 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 static void
@ -2250,7 +2280,7 @@ static void
FcParseDir (FcConfigParse *parse) FcParseDir (FcConfigParse *parse)
{ {
const FcChar8 *attr, *data, *salt; const FcChar8 *attr, *data, *salt;
FcChar8 *prefix = NULL; FcStrSet *prefix_dirs = NULL;
data = FcStrBufDoneStatic (&parse->pstack->str); data = FcStrBufDoneStatic (&parse->pstack->str);
if (!data) if (!data)
@ -2265,20 +2295,28 @@ FcParseDir (FcConfigParse *parse)
} }
attr = FcConfigGetAttribute (parse, "prefix"); attr = FcConfigGetAttribute (parse, "prefix");
salt = FcConfigGetAttribute (parse, "salt"); salt = FcConfigGetAttribute (parse, "salt");
prefix = _get_real_path_from_prefix (parse, data, attr); prefix_dirs = _get_real_paths_from_prefix (parse, data, attr);
if (!prefix || prefix[0] == 0) if (prefix_dirs)
{ {
/* nop */ FcStrList *l = FcStrListCreate (prefix_dirs);
} FcChar8 *prefix;
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);
if (prefix) FcStrSetDestroy (prefix_dirs);
FcStrFree (prefix); 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 static void