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:
Akira TAGOH 2012-03-29 20:25:20 +09:00
parent 1b692d8ab9
commit bbc8fb5ba7
7 changed files with 260 additions and 69 deletions

View File

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

View File

@ -57,6 +57,12 @@ FcCacheObjectDereference (void *object)
{
}
FcPrivate FcChar8 *
FcLangNormalize (const FcChar8 *lang)
{
return NULL;
}
int FcDebugVal;
FcChar8 *

View File

@ -497,6 +497,9 @@ FcPublic void
FcFontSetPrint (const FcFontSet *s);
/* fcdefault.c */
FcPublic FcStrSet *
FcGetDefaultLangs (void);
FcPublic void
FcDefaultSubstitute (FcPattern *pattern);

View File

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

View File

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

View File

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

View File

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