Bug 32853 - Export API to get the default language
Add a new API FcGetDefaultLangs() to export the string sets of the default languages.
This commit is contained in:
parent
1b692d8ab9
commit
bbc8fb5ba7
|
@ -153,6 +153,15 @@ function returns FcLangDifferentTerritory. If <parameter>ls</parameter>
|
||||||
has no matching language, this function returns FcLangDifferentLang.
|
has no matching language, this function returns FcLangDifferentLang.
|
||||||
@@
|
@@
|
||||||
|
|
||||||
|
@RET@ FcStrSet *
|
||||||
|
@FUNC@ FcGetDefaultLangs
|
||||||
|
@TYPE1@ void
|
||||||
|
@PURPOSE@ Get the default languages list
|
||||||
|
@DESC@
|
||||||
|
Returns a string set of the default languages according to the environment variables on the system.
|
||||||
|
This function looks for them in order of FC_LANG, LC_ALL, LC_CTYPE and LANG then.
|
||||||
|
If there are no valid values in those environment variables, "en" will be set as fallback.
|
||||||
|
|
||||||
@RET@ FcStrSet *
|
@RET@ FcStrSet *
|
||||||
@FUNC@ FcLangSetGetLangs
|
@FUNC@ FcLangSetGetLangs
|
||||||
@TYPE1@ const FcLangSet * @ARG1@ ls
|
@TYPE1@ const FcLangSet * @ARG1@ ls
|
||||||
|
|
|
@ -57,6 +57,12 @@ FcCacheObjectDereference (void *object)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FcPrivate FcChar8 *
|
||||||
|
FcLangNormalize (const FcChar8 *lang)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
int FcDebugVal;
|
int FcDebugVal;
|
||||||
|
|
||||||
FcChar8 *
|
FcChar8 *
|
||||||
|
|
|
@ -497,6 +497,9 @@ FcPublic void
|
||||||
FcFontSetPrint (const FcFontSet *s);
|
FcFontSetPrint (const FcFontSet *s);
|
||||||
|
|
||||||
/* fcdefault.c */
|
/* fcdefault.c */
|
||||||
|
FcPublic FcStrSet *
|
||||||
|
FcGetDefaultLangs (void);
|
||||||
|
|
||||||
FcPublic void
|
FcPublic void
|
||||||
FcDefaultSubstitute (FcPattern *pattern);
|
FcDefaultSubstitute (FcPattern *pattern);
|
||||||
|
|
||||||
|
|
102
src/fcdefault.c
102
src/fcdefault.c
|
@ -23,7 +23,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "fcint.h"
|
#include "fcint.h"
|
||||||
#include <locale.h>
|
#include <string.h>
|
||||||
|
|
||||||
static const struct {
|
static const struct {
|
||||||
FcObject field;
|
FcObject field;
|
||||||
|
@ -39,81 +39,45 @@ static const struct {
|
||||||
|
|
||||||
#define NUM_FC_BOOL_DEFAULTS (int) (sizeof FcBoolDefaults / sizeof FcBoolDefaults[0])
|
#define NUM_FC_BOOL_DEFAULTS (int) (sizeof FcBoolDefaults / sizeof FcBoolDefaults[0])
|
||||||
|
|
||||||
|
FcStrSet *
|
||||||
|
FcGetDefaultLangs (void)
|
||||||
|
{
|
||||||
|
FcStrSet *result = FcStrSetCreate ();
|
||||||
|
char *langs;
|
||||||
|
|
||||||
|
langs = getenv ("FC_LANG");
|
||||||
|
if (!langs)
|
||||||
|
langs = getenv ("LC_ALL");
|
||||||
|
if (!langs)
|
||||||
|
langs = getenv ("LC_CTYPE");
|
||||||
|
if (!langs)
|
||||||
|
langs = getenv ("LANG");
|
||||||
|
if (langs)
|
||||||
|
{
|
||||||
|
if (!FcStrSetAddLangs (result, langs))
|
||||||
|
FcStrSetAdd (result, (const FcChar8 *) "en");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
FcStrSetAdd (result, (const FcChar8 *) "en");
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
FcChar8 *
|
FcChar8 *
|
||||||
FcGetDefaultLang (void)
|
FcGetDefaultLang (void)
|
||||||
{
|
{
|
||||||
static char lang_local [128] = {0};
|
static FcChar8 lang_local[128] = {0};
|
||||||
char *ctype;
|
FcStrSet *langs;
|
||||||
char *territory;
|
|
||||||
char *after;
|
|
||||||
int lang_len, territory_len;
|
|
||||||
|
|
||||||
if (lang_local [0])
|
if (!lang_local[0])
|
||||||
return (FcChar8 *) lang_local;
|
|
||||||
|
|
||||||
ctype = setlocale (LC_CTYPE, NULL);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Check if setlocale (LC_ALL, "") has been called
|
|
||||||
*/
|
|
||||||
if (!ctype || !strcmp (ctype, "C"))
|
|
||||||
{
|
{
|
||||||
ctype = getenv ("LC_ALL");
|
langs = FcGetDefaultLangs ();
|
||||||
if (!ctype)
|
strncpy ((char *)lang_local, (const char *)langs->strs[0], 127);
|
||||||
{
|
lang_local[127] = 0;
|
||||||
ctype = getenv ("LC_CTYPE");
|
FcStrSetDestroy (langs);
|
||||||
if (!ctype)
|
|
||||||
ctype = getenv ("LANG");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ignore missing or empty ctype */
|
return lang_local;
|
||||||
if (ctype && *ctype != '\0')
|
|
||||||
{
|
|
||||||
territory = strchr (ctype, '_');
|
|
||||||
if (territory)
|
|
||||||
{
|
|
||||||
lang_len = territory - ctype;
|
|
||||||
territory = territory + 1;
|
|
||||||
after = strchr (territory, '.');
|
|
||||||
if (!after)
|
|
||||||
{
|
|
||||||
after = strchr (territory, '@');
|
|
||||||
if (!after)
|
|
||||||
after = territory + strlen (territory);
|
|
||||||
}
|
|
||||||
territory_len = after - territory;
|
|
||||||
if (lang_len + 1 + territory_len + 1 <= (int) sizeof (lang_local))
|
|
||||||
{
|
|
||||||
strncpy (lang_local, ctype, lang_len);
|
|
||||||
lang_local[lang_len] = '-';
|
|
||||||
strncpy (lang_local + lang_len + 1, territory, territory_len);
|
|
||||||
lang_local[lang_len + 1 + territory_len] = '\0';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
after = strchr (ctype, '.');
|
|
||||||
if (!after)
|
|
||||||
{
|
|
||||||
after = strchr (ctype, '@');
|
|
||||||
if (!after)
|
|
||||||
after = ctype + strlen (ctype);
|
|
||||||
}
|
|
||||||
lang_len = after - ctype;
|
|
||||||
if (lang_len + 1 <= (int) sizeof (lang_local))
|
|
||||||
{
|
|
||||||
strncpy (lang_local, ctype, lang_len);
|
|
||||||
lang_local[lang_len] = '\0';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* set default lang to en */
|
|
||||||
if (!lang_local [0])
|
|
||||||
strcpy (lang_local, "en");
|
|
||||||
|
|
||||||
return (FcChar8 *) lang_local;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -816,6 +816,9 @@ FcPrivate FcLangSet *
|
||||||
FcFreeTypeLangSet (const FcCharSet *charset,
|
FcFreeTypeLangSet (const FcCharSet *charset,
|
||||||
const FcChar8 *exclusiveLang);
|
const FcChar8 *exclusiveLang);
|
||||||
|
|
||||||
|
FcPrivate FcChar8 *
|
||||||
|
FcLangNormalize (const FcChar8 *lang);
|
||||||
|
|
||||||
FcPrivate FcLangResult
|
FcPrivate FcLangResult
|
||||||
FcLangCompare (const FcChar8 *s1, const FcChar8 *s2);
|
FcLangCompare (const FcChar8 *s1, const FcChar8 *s2);
|
||||||
|
|
||||||
|
@ -1039,6 +1042,9 @@ FcPrivate FcBool
|
||||||
FcIsFsMtimeBroken (const FcChar8 *dir);
|
FcIsFsMtimeBroken (const FcChar8 *dir);
|
||||||
|
|
||||||
/* fcstr.c */
|
/* fcstr.c */
|
||||||
|
FcPrivate FcBool
|
||||||
|
FcStrSetAddLangs (FcStrSet *strs, const char *languages);
|
||||||
|
|
||||||
FcPrivate void
|
FcPrivate void
|
||||||
FcStrSetSort (FcStrSet * set);
|
FcStrSetSort (FcStrSet * set);
|
||||||
|
|
||||||
|
|
159
src/fclang.c
159
src/fclang.c
|
@ -22,6 +22,7 @@
|
||||||
* PERFORMANCE OF THIS SOFTWARE.
|
* PERFORMANCE OF THIS SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
#include "fcint.h"
|
#include "fcint.h"
|
||||||
#include "fcftint.h"
|
#include "fcftint.h"
|
||||||
|
|
||||||
|
@ -43,6 +44,9 @@ struct _FcLangSet {
|
||||||
FcChar32 map[NUM_LANG_SET_MAP];
|
FcChar32 map[NUM_LANG_SET_MAP];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int FcLangSetIndex (const FcChar8 *lang);
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
FcLangSetBitSet (FcLangSet *ls,
|
FcLangSetBitSet (FcLangSet *ls,
|
||||||
unsigned int id)
|
unsigned int id)
|
||||||
|
@ -173,6 +177,161 @@ FcFreeTypeLangSet (const FcCharSet *charset,
|
||||||
return ls;
|
return ls;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FcChar8 *
|
||||||
|
FcLangNormalize (const FcChar8 *lang)
|
||||||
|
{
|
||||||
|
FcChar8 *result = NULL, *s, *orig;
|
||||||
|
char *territory, *encoding, *modifier;
|
||||||
|
size_t llen, tlen = 0, mlen = 0;
|
||||||
|
|
||||||
|
if (!lang || !*lang)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (FcStrCmpIgnoreCase (lang, (const FcChar8 *)"C") == 0 ||
|
||||||
|
FcStrCmpIgnoreCase (lang, (const FcChar8 *)"POSIX") == 0)
|
||||||
|
{
|
||||||
|
result = FcStrCopy ((const FcChar8 *)"en");
|
||||||
|
goto bail;
|
||||||
|
}
|
||||||
|
|
||||||
|
s = FcStrCopy (lang);
|
||||||
|
if (!s)
|
||||||
|
goto bail;
|
||||||
|
|
||||||
|
/* from the comments in glibc:
|
||||||
|
*
|
||||||
|
* LOCALE can consist of up to four recognized parts for the XPG syntax:
|
||||||
|
*
|
||||||
|
* language[_territory[.codeset]][@modifier]
|
||||||
|
*
|
||||||
|
* Beside the first all of them are allowed to be missing. If the
|
||||||
|
* full specified locale is not found, the less specific one are
|
||||||
|
* looked for. The various part will be stripped off according to
|
||||||
|
* the following order:
|
||||||
|
* (1) codeset
|
||||||
|
* (2) normalized codeset
|
||||||
|
* (3) territory
|
||||||
|
* (4) modifier
|
||||||
|
*
|
||||||
|
* So since we don't take care of the codeset part here, what patterns
|
||||||
|
* we need to deal with is:
|
||||||
|
*
|
||||||
|
* 1. language_territory@modifier
|
||||||
|
* 2. language@modifier
|
||||||
|
* 3. language
|
||||||
|
*
|
||||||
|
* then. and maybe no need to try language_territory here.
|
||||||
|
*/
|
||||||
|
modifier = strchr ((const char *) s, '@');
|
||||||
|
if (modifier)
|
||||||
|
{
|
||||||
|
*modifier = 0;
|
||||||
|
modifier++;
|
||||||
|
mlen = strlen (modifier);
|
||||||
|
}
|
||||||
|
encoding = strchr ((const char *) s, '.');
|
||||||
|
if (encoding)
|
||||||
|
{
|
||||||
|
*encoding = 0;
|
||||||
|
encoding++;
|
||||||
|
if (modifier)
|
||||||
|
{
|
||||||
|
memmove (encoding, modifier, mlen + 1);
|
||||||
|
modifier = encoding;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
territory = strchr ((const char *) s, '_');
|
||||||
|
if (!territory)
|
||||||
|
territory = strchr ((const char *) s, '-');
|
||||||
|
if (territory)
|
||||||
|
{
|
||||||
|
*territory = 0;
|
||||||
|
territory++;
|
||||||
|
tlen = strlen (territory);
|
||||||
|
}
|
||||||
|
llen = strlen ((const char *) s);
|
||||||
|
if (llen < 2 || llen > 3)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "Fontconfig warning: ignoring %s: not a valid language tag\n",
|
||||||
|
lang);
|
||||||
|
goto bail0;
|
||||||
|
}
|
||||||
|
if (territory && (tlen < 2 || tlen > 3))
|
||||||
|
{
|
||||||
|
fprintf (stderr, "Fontconfig warning: ignoring %s: not a valid region tag\n",
|
||||||
|
lang);
|
||||||
|
goto bail0;
|
||||||
|
}
|
||||||
|
if (territory)
|
||||||
|
territory[-1] = '-';
|
||||||
|
if (modifier)
|
||||||
|
modifier[-1] = '@';
|
||||||
|
orig = FcStrDowncase (s);
|
||||||
|
if (!orig)
|
||||||
|
goto bail0;
|
||||||
|
if (territory)
|
||||||
|
{
|
||||||
|
if (FcDebug () & FC_DBG_LANGSET)
|
||||||
|
printf("Checking the existence of %s.orth\n", s);
|
||||||
|
if (FcLangSetIndex (s) < 0)
|
||||||
|
{
|
||||||
|
memmove (territory - 1, territory + tlen, (mlen > 0 ? mlen + 1 : 0) + 1);
|
||||||
|
if (modifier)
|
||||||
|
modifier = territory;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = s;
|
||||||
|
s = NULL;
|
||||||
|
goto bail1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (modifier)
|
||||||
|
{
|
||||||
|
if (FcDebug () & FC_DBG_LANGSET)
|
||||||
|
printf("Checking the existence of %s.orth\n", s);
|
||||||
|
if (FcLangSetIndex (s) < 0)
|
||||||
|
modifier[-1] = 0;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = s;
|
||||||
|
s = NULL;
|
||||||
|
goto bail1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (FcDebug () & FC_DBG_LANGSET)
|
||||||
|
printf("Checking the existence of %s.orth\n", s);
|
||||||
|
if (FcLangSetIndex (s) < 0)
|
||||||
|
{
|
||||||
|
/* there seems no languages matched in orth.
|
||||||
|
* add the language as is for fallback.
|
||||||
|
*/
|
||||||
|
result = orig;
|
||||||
|
orig = NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = s;
|
||||||
|
s = NULL;
|
||||||
|
}
|
||||||
|
bail1:
|
||||||
|
if (orig)
|
||||||
|
free (orig);
|
||||||
|
bail0:
|
||||||
|
if (s)
|
||||||
|
free (s);
|
||||||
|
bail:
|
||||||
|
if (FcDebug () & FC_DBG_LANGSET)
|
||||||
|
{
|
||||||
|
if (result)
|
||||||
|
printf ("normalized: %s -> %s\n", lang, result);
|
||||||
|
else
|
||||||
|
printf ("Unable to normalize %s\n", lang);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
#define FcLangEnd(c) ((c) == '-' || (c) == '\0')
|
#define FcLangEnd(c) ((c) == '-' || (c) == '\0')
|
||||||
|
|
||||||
FcLangResult
|
FcLangResult
|
||||||
|
|
44
src/fcstr.c
44
src/fcstr.c
|
@ -1176,6 +1176,50 @@ FcStrSetAddFilename (FcStrSet *set, const FcChar8 *s)
|
||||||
return FcTrue;
|
return FcTrue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FcBool
|
||||||
|
FcStrSetAddLangs (FcStrSet *strs, const char *languages)
|
||||||
|
{
|
||||||
|
const char *p = languages, *next;
|
||||||
|
FcChar8 lang[128] = {0}, *normalized_lang;
|
||||||
|
size_t len;
|
||||||
|
FcBool ret = FcFalse;
|
||||||
|
|
||||||
|
if (!languages)
|
||||||
|
return FcFalse;
|
||||||
|
|
||||||
|
while ((next = strchr (p, ':')))
|
||||||
|
{
|
||||||
|
len = next - p;
|
||||||
|
len = FC_MIN (len, 128);
|
||||||
|
strncpy ((char *) lang, p, len);
|
||||||
|
lang[len] = 0;
|
||||||
|
/* ignore an empty item */
|
||||||
|
if (*lang)
|
||||||
|
{
|
||||||
|
normalized_lang = FcLangNormalize ((const FcChar8 *) lang);
|
||||||
|
if (normalized_lang)
|
||||||
|
{
|
||||||
|
FcStrSetAdd (strs, normalized_lang);
|
||||||
|
free (normalized_lang);
|
||||||
|
ret = FcTrue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p = next + 1;
|
||||||
|
}
|
||||||
|
if (*p)
|
||||||
|
{
|
||||||
|
normalized_lang = FcLangNormalize ((const FcChar8 *) p);
|
||||||
|
if (normalized_lang)
|
||||||
|
{
|
||||||
|
FcStrSetAdd (strs, normalized_lang);
|
||||||
|
free (normalized_lang);
|
||||||
|
ret = FcTrue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
FcBool
|
FcBool
|
||||||
FcStrSetDel (FcStrSet *set, const FcChar8 *s)
|
FcStrSetDel (FcStrSet *set, const FcChar8 *s)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue