doc/fclangset.fncs | 9 ++ fc-lang/fc-lang.c | 6 + fontconfig/fontconfig.h | 3 src/fccfg.c | 18 +++++ src/fcdefault.c | 106 +++++++++----------------------- src/fcint.h | 6 + src/fclang.c | 159 ++++++++++++++++++++++++++++++++++++++++++++++++ src/fcstr.c | 44 +++++++++++++ 8 files changed, 278 insertions(+), 73 deletions(-) New commits: commit 07e52eeb097a4e3c147e00ed7a6eb7652a611751 Author: Akira TAGOH <akira@xxxxxxxxx> Date: Fri Jun 8 15:54:48 2012 +0900 fcdefault: no need to set FC_LANG in FcDefaultSubstitute() anymore diff --git a/src/fcdefault.c b/src/fcdefault.c index ce90a88..c6b5669 100644 --- a/src/fcdefault.c +++ b/src/fcdefault.c @@ -126,10 +126,6 @@ FcDefaultSubstitute (FcPattern *pattern) FcPatternObjectAddDouble (pattern, FC_PIXEL_SIZE_OBJECT, size); } - if (FcPatternObjectGet (pattern, FC_LANG_OBJECT, 0, &v) == FcResultNoMatch) - { - FcPatternObjectAddString (pattern, FC_LANG_OBJECT, FcGetDefaultLang ()); - } if (FcPatternObjectGet (pattern, FC_FONTVERSION_OBJECT, 0, &v) == FcResultNoMatch) { FcPatternObjectAddInteger (pattern, FC_FONTVERSION_OBJECT, 0x7fffffff); commit 550fd49d4fb8efab33d1fa1687b1b9bd352202fe Author: Akira TAGOH <akira@xxxxxxxxx> Date: Tue May 22 14:17:10 2012 +0900 Add the default language to the pattern prior to do build the substitution the default language is referred from the FC_LANG environment variable or the current locale diff --git a/src/fccfg.c b/src/fccfg.c index b45d74a..c3d95e8 100644 --- a/src/fccfg.c +++ b/src/fccfg.c @@ -1407,6 +1407,7 @@ FcConfigSubstituteWithPat (FcConfig *config, FcEdit *e; FcValueList *l; FcPattern *m; + FcStrSet *strs; if (!config) { @@ -1434,6 +1435,23 @@ FcConfigSubstituteWithPat (FcConfig *config, return FcFalse; FcMemAlloc (FC_MEM_SUBSTATE, config->maxObjects * sizeof (FcSubState)); + strs = FcGetDefaultLangs (); + if (strs) + { + FcStrList *l = FcStrListCreate (strs); + FcChar8 *lang; + FcValue v; + + FcStrSetDestroy (strs); + while (l && (lang = FcStrListNext (l))) + { + v.type = FcTypeString; + v.u.s = lang; + FcPatternObjectAddWithBinding (p, FC_LANG_OBJECT, v, FcValueBindingWeak, FcTrue); + } + FcStrListDone (l); + } + if (FcDebug () & FC_DBG_EDIT) { printf ("FcConfigSubstitute "); commit 2261a64ce14d692f7c553f46e2158e70400dbc9c Author: Akira TAGOH <akira@xxxxxxxxx> Date: Fri Jun 8 15:47:52 2012 +0900 fcdefault: fallback if the environment variables are empty try to fallback if FC_LANG, LC_ALL, LC_CTYPE and LANG is empty diff --git a/src/fcdefault.c b/src/fcdefault.c index 674374c..ce90a88 100644 --- a/src/fcdefault.c +++ b/src/fcdefault.c @@ -46,13 +46,13 @@ FcGetDefaultLangs (void) char *langs; langs = getenv ("FC_LANG"); - if (!langs) + if (!langs || !langs[0]) langs = getenv ("LC_ALL"); - if (!langs) + if (!langs || !langs[0]) langs = getenv ("LC_CTYPE"); - if (!langs) + if (!langs || !langs[0]) langs = getenv ("LANG"); - if (langs) + if (langs && langs[0]) { if (!FcStrSetAddLangs (result, langs)) FcStrSetAdd (result, (const FcChar8 *) "en"); commit bbc8fb5ba705e5257693f3b266fce12d2f81b50c Author: Akira TAGOH <akira@xxxxxxxxx> Date: Thu Mar 29 20:25:20 2012 +0900 Bug 32853 - Export API to get the default language Add a new API FcGetDefaultLangs() to export the string sets of the default languages. diff --git a/doc/fclangset.fncs b/doc/fclangset.fncs index 0a44b38..e2a40b8 100644 --- a/doc/fclangset.fncs +++ b/doc/fclangset.fncs @@ -154,6 +154,15 @@ 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 @PURPOSE@ get the list of languages in the langset diff --git a/fc-lang/fc-lang.c b/fc-lang/fc-lang.c index 51717f9..93200c4 100644 --- a/fc-lang/fc-lang.c +++ b/fc-lang/fc-lang.c @@ -57,6 +57,12 @@ FcCacheObjectDereference (void *object) { } +FcPrivate FcChar8 * +FcLangNormalize (const FcChar8 *lang) +{ + return NULL; +} + int FcDebugVal; FcChar8 * diff --git a/fontconfig/fontconfig.h b/fontconfig/fontconfig.h index 2671da7..21a476a 100644 --- a/fontconfig/fontconfig.h +++ b/fontconfig/fontconfig.h @@ -497,6 +497,9 @@ FcPublic void FcFontSetPrint (const FcFontSet *s); /* fcdefault.c */ +FcPublic FcStrSet * +FcGetDefaultLangs (void); + FcPublic void FcDefaultSubstitute (FcPattern *pattern); diff --git a/src/fcdefault.c b/src/fcdefault.c index 170a8a4..674374c 100644 --- a/src/fcdefault.c +++ b/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]) -FcChar8 * -FcGetDefaultLang (void) +FcStrSet * +FcGetDefaultLangs (void) { - static char lang_local [128] = {0}; - char *ctype; - char *territory; - char *after; - int lang_len, territory_len; - - 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")) + 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) { - ctype = getenv ("LC_ALL"); - if (!ctype) - { - ctype = getenv ("LC_CTYPE"); - if (!ctype) - ctype = getenv ("LANG"); - } + if (!FcStrSetAddLangs (result, langs)) + FcStrSetAdd (result, (const FcChar8 *) "en"); } + else + FcStrSetAdd (result, (const FcChar8 *) "en"); + + return result; +} - /* ignore missing or empty ctype */ - if (ctype && *ctype != '\0') +FcChar8 * +FcGetDefaultLang (void) +{ + static FcChar8 lang_local[128] = {0}; + FcStrSet *langs; + + if (!lang_local[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'; - } - } + langs = FcGetDefaultLangs (); + strncpy ((char *)lang_local, (const char *)langs->strs[0], 127); + lang_local[127] = 0; + FcStrSetDestroy (langs); } - /* set default lang to en */ - if (!lang_local [0]) - strcpy (lang_local, "en"); - - return (FcChar8 *) lang_local; + return lang_local; } void diff --git a/src/fcint.h b/src/fcint.h index 3d06fc6..7cc4ed2 100644 --- a/src/fcint.h +++ b/src/fcint.h @@ -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); diff --git a/src/fclang.c b/src/fclang.c index be42b58..b7e70fc 100644 --- a/src/fclang.c +++ b/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 diff --git a/src/fcstr.c b/src/fcstr.c index e372af0..c446bcd 100644 --- a/src/fcstr.c +++ b/src/fcstr.c @@ -1177,6 +1177,50 @@ FcStrSetAddFilename (FcStrSet *set, const FcChar8 *s) } 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) { int i; _______________________________________________ Fontconfig mailing list Fontconfig@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/fontconfig