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.
|
||||
@@
|
||||
|
||||
@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 *
|
||||
@FUNC@ FcLangSetGetLangs
|
||||
@TYPE1@ const FcLangSet * @ARG1@ ls
|
||||
|
|
|
@ -57,6 +57,12 @@ FcCacheObjectDereference (void *object)
|
|||
{
|
||||
}
|
||||
|
||||
FcPrivate FcChar8 *
|
||||
FcLangNormalize (const FcChar8 *lang)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int FcDebugVal;
|
||||
|
||||
FcChar8 *
|
||||
|
|
|
@ -497,6 +497,9 @@ FcPublic void
|
|||
FcFontSetPrint (const FcFontSet *s);
|
||||
|
||||
/* fcdefault.c */
|
||||
FcPublic FcStrSet *
|
||||
FcGetDefaultLangs (void);
|
||||
|
||||
FcPublic void
|
||||
FcDefaultSubstitute (FcPattern *pattern);
|
||||
|
||||
|
|
102
src/fcdefault.c
102
src/fcdefault.c
|
@ -23,7 +23,7 @@
|
|||
*/
|
||||
|
||||
#include "fcint.h"
|
||||
#include <locale.h>
|
||||
#include <string.h>
|
||||
|
||||
static const struct {
|
||||
FcObject field;
|
||||
|
@ -39,81 +39,45 @@ static const struct {
|
|||
|
||||
#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 *
|
||||
FcGetDefaultLang (void)
|
||||
{
|
||||
static char lang_local [128] = {0};
|
||||
char *ctype;
|
||||
char *territory;
|
||||
char *after;
|
||||
int lang_len, territory_len;
|
||||
static FcChar8 lang_local[128] = {0};
|
||||
FcStrSet *langs;
|
||||
|
||||
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"))
|
||||
if (!lang_local[0])
|
||||
{
|
||||
ctype = getenv ("LC_ALL");
|
||||
if (!ctype)
|
||||
{
|
||||
ctype = getenv ("LC_CTYPE");
|
||||
if (!ctype)
|
||||
ctype = getenv ("LANG");
|
||||
}
|
||||
langs = FcGetDefaultLangs ();
|
||||
strncpy ((char *)lang_local, (const char *)langs->strs[0], 127);
|
||||
lang_local[127] = 0;
|
||||
FcStrSetDestroy (langs);
|
||||
}
|
||||
|
||||
/* ignore missing or empty ctype */
|
||||
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;
|
||||
return lang_local;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -816,6 +816,9 @@ FcPrivate FcLangSet *
|
|||
FcFreeTypeLangSet (const FcCharSet *charset,
|
||||
const FcChar8 *exclusiveLang);
|
||||
|
||||
FcPrivate FcChar8 *
|
||||
FcLangNormalize (const FcChar8 *lang);
|
||||
|
||||
FcPrivate FcLangResult
|
||||
FcLangCompare (const FcChar8 *s1, const FcChar8 *s2);
|
||||
|
||||
|
@ -1039,6 +1042,9 @@ FcPrivate FcBool
|
|||
FcIsFsMtimeBroken (const FcChar8 *dir);
|
||||
|
||||
/* fcstr.c */
|
||||
FcPrivate FcBool
|
||||
FcStrSetAddLangs (FcStrSet *strs, const char *languages);
|
||||
|
||||
FcPrivate void
|
||||
FcStrSetSort (FcStrSet * set);
|
||||
|
||||
|
|
159
src/fclang.c
159
src/fclang.c
|
@ -22,6 +22,7 @@
|
|||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "fcint.h"
|
||||
#include "fcftint.h"
|
||||
|
||||
|
@ -43,6 +44,9 @@ struct _FcLangSet {
|
|||
FcChar32 map[NUM_LANG_SET_MAP];
|
||||
};
|
||||
|
||||
static int FcLangSetIndex (const FcChar8 *lang);
|
||||
|
||||
|
||||
static void
|
||||
FcLangSetBitSet (FcLangSet *ls,
|
||||
unsigned int id)
|
||||
|
@ -173,6 +177,161 @@ FcFreeTypeLangSet (const FcCharSet *charset,
|
|||
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')
|
||||
|
||||
FcLangResult
|
||||
|
|
44
src/fcstr.c
44
src/fcstr.c
|
@ -1176,6 +1176,50 @@ FcStrSetAddFilename (FcStrSet *set, const FcChar8 *s)
|
|||
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
|
||||
FcStrSetDel (FcStrSet *set, const FcChar8 *s)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue