Well, please test if you didn't play with it yet. Thanks, On Fri, Jun 8, 2012 at 4:05 PM, Akira TAGOH <tagoh@xxxxxxxxxxxxxxxxxxxxxx> wrote: > 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 -- Akira TAGOH _______________________________________________ Fontconfig mailing list Fontconfig@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/fontconfig