diff --git a/uppsrc/Core/Core.upp b/uppsrc/Core/Core.upp index 9b56ce819..3a5ffc97b 100644 --- a/uppsrc/Core/Core.upp +++ b/uppsrc/Core/Core.upp @@ -107,6 +107,7 @@ file t.h, Lang.h, Lang.cpp, + LangInfo.cpp, lcid.txt, "Other files" readonly separator, Parser.h, diff --git a/uppsrc/Core/Lang.cpp b/uppsrc/Core/Lang.cpp index a68d076ff..46210a9fa 100644 --- a/uppsrc/Core/Lang.cpp +++ b/uppsrc/Core/Lang.cpp @@ -11,7 +11,7 @@ NAMESPACE_UPP -#define LLOG(x) // LOG(x) +#define LLOG(x) LOG(x) String LNGAsText(int d) { @@ -154,84 +154,6 @@ int GetCurrentLanguage() { return sCurrentLanguage; } -#ifdef PLATFORM_WIN32 - -typedef VectorMap LCIDMap; -GLOBAL_VAR(LCIDMap, GetLCIDMap) - -#ifdef PLATFORM_WINCE //TODO? -String GetLocaleInfoA(LCID lcid, LCTYPE lctype) -{ - wchar cbuf[1000]; - ::GetLocaleInfoW(lcid, lctype, cbuf, __countof(cbuf)); - return FromSystemCharset(cbuf); -} -#else -String GetLocaleInfoA(LCID lcid, LCTYPE lctype) -{ - if(IsWinNT()) { - wchar cbuf[1000]; - UnicodeWin32().GetLocaleInfoW(lcid, lctype, cbuf, __countof(cbuf)); - return FromSystemCharsetW(cbuf); - } - else { - char cbuf[1000]; - ::GetLocaleInfoA(lcid, lctype, cbuf, __countof(cbuf)); - return FromSystemCharset(cbuf); - } -} -#endif - -WString GetLocaleInfoW(LCID lcid, LCTYPE lctype) -{ - union { - wchar wbuf[1000]; - char abuf[1000]; - }; - Zero(wbuf); - if(::GetLocaleInfoW(lcid, lctype, (WCHAR *)wbuf, __countof(wbuf))) - return wbuf; -#ifdef PLATFORM_WINCE - return Null; -#else - ::GetLocaleInfoA(lcid, lctype, abuf, __countof(abuf)); - return ToUnicode(abuf, CHARSET_DEFAULT); -#endif -} - -#ifdef PLATFORM_WINCE -static BOOL CALLBACK sEnumLocale(wchar *locale_string) -#else -static BOOL CALLBACK sEnumLocale(char *locale_string) -#endif -{ - LLOG(locale_string); - LCID lcid = stou(locale_string, NULL, 16); -#ifdef PLATFORM_WINCE - wchar buffer[10]; -#else - char buffer[10]; -#endif - ::GetLocaleInfo(lcid, LOCALE_SISO639LANGNAME, buffer, 10); - int language = (ToUpper(buffer[0]) << 24) + (ToUpper(buffer[1]) << 16); - ::GetLocaleInfo(lcid, LOCALE_SISO3166CTRYNAME, buffer, 10); - language += (ToUpper(buffer[0]) << 8) + (ToUpper(buffer[1]) << 0); - LLOG(FormatIntHex(language, 8) << ", " << LNGAsText(language) << "->" << FormatIntHex(lcid, 8)); - GetLCIDMap().GetAdd(language, lcid); - return TRUE; -} - -LCID GetLanguageLCID(int language) -{ - if(language == 0) - return 0x400; - ONCELOCK { - EnumSystemLocales(&sEnumLocale, LCID_SUPPORTED); - } - return GetLCIDMap().Get(language, MAKELCID(MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), SORT_DEFAULT)); -} -#endif - void SetLanguage(int lang) { if(lang != LNG_CURRENT) { sCurrentLanguage = lang; @@ -240,883 +162,13 @@ void SetLanguage(int lang) { SetCurrentLanguage(lang); } -const int *GetAllLanguages() { - static int all_langs[] = { - LNG_('E', 'N', 'U', 'S'), - LNG_('E', 'N', 'G', 'B'), - LNG_('E', 'N', 'A', 'U'), - LNG_('E', 'N', 'C', 'A'), - LNG_('E', 'N', 'N', 'Z'), - LNG_('E', 'N', 'I', 'E'), - LNG_('E', 'N', 'Z', 'A'), - LNG_('E', 'N', 'J', 'M'), - LNG_('E', 'N', 'C', 'B'), - LNG_('E', 'N', 'B', 'Z'), - LNG_('E', 'N', 'T', 'T'), - LNG_('B', 'G', 'B', 'G'), - LNG_('C', 'S', 'C', 'Z'), - LNG_('D', 'A', 'D', 'K'), - LNG_('D', 'E', 'D', 'E'), - LNG_('D', 'E', 'C', 'H'), - LNG_('D', 'E', 'A', 'T'), - LNG_('D', 'E', 'L', 'U'), - LNG_('D', 'E', 'L', 'I'), - LNG_('E', 'L', 'G', 'R'), - LNG_('E', 'S', 'E', 'S'), - LNG_('E', 'S', 'M', 'X'), - LNG_('E', 'S', 'E', 'S'), - LNG_('E', 'S', 'G', 'T'), - LNG_('E', 'S', 'C', 'R'), - LNG_('E', 'S', 'P', 'A'), - LNG_('E', 'S', 'D', 'O'), - LNG_('E', 'S', 'V', 'E'), - LNG_('E', 'S', 'C', 'O'), - LNG_('E', 'S', 'P', 'E'), - LNG_('E', 'S', 'A', 'R'), - LNG_('E', 'S', 'E', 'C'), - LNG_('E', 'S', 'C', 'L'), - LNG_('E', 'S', 'U', 'Y'), - LNG_('E', 'S', 'P', 'Y'), - LNG_('E', 'S', 'B', 'O'), - LNG_('E', 'S', 'S', 'V'), - LNG_('E', 'S', 'H', 'N'), - LNG_('E', 'S', 'N', 'I'), - LNG_('E', 'S', 'P', 'R'), - LNG_('F', 'I', 'F', 'I'), - LNG_('F', 'R', 'F', 'R'), - LNG_('F', 'R', 'B', 'E'), - LNG_('F', 'R', 'C', 'A'), - LNG_('F', 'R', 'C', 'H'), - LNG_('F', 'R', 'L', 'U'), - LNG_('H', 'U', 'H', 'U'), - LNG_('I', 'S', 'I', 'S'), - LNG_('I', 'T', 'I', 'T'), - LNG_('I', 'T', 'C', 'H'), - LNG_('N', 'L', 'N', 'L'), - LNG_('N', 'L', 'B', 'E'), - LNG_('N', 'O', 'N', 'O'), - LNG_('N', 'O', 'N', 'O'), - LNG_('P', 'L', 'P', 'L'), - LNG_('P', 'T', 'B', 'R'), - LNG_('P', 'T', 'P', 'T'), - LNG_('R', 'O', 'R', 'O'), - LNG_('R', 'U', 'R', 'U'), - LNG_('H', 'R', 'H', 'R'), - LNG_('S', 'R', 'S', 'P'), - LNG_('S', 'R', 'S', 'P'), - LNG_('S', 'K', 'S', 'K'), - LNG_('S', 'V', 'S', 'E'), - LNG_('S', 'V', 'F', 'I'), - LNG_('T', 'R', 'T', 'R'), - LNG_('S', 'L', 'S', 'I'), - LNG_('A', 'F', 'Z', 'A'), - LNG_('S', 'Q', 'A', 'L'), - LNG_('E', 'U', 'E', 'S'), - LNG_('B', 'E', 'B', 'Y'), - LNG_('C', 'A', 'E', 'S'), - LNG_('E', 'T', 'E', 'E'), - LNG_('F', 'O', 'F', 'O'), - LNG_('I', 'D', 'I', 'D'), - LNG_('L', 'V', 'L', 'V'), - LNG_('L', 'T', 'L', 'T'), - LNG_('U', 'K', 'U', 'A'), - LNG_('Z', 'H', 'C', 'N'), - LNG_('Z', 'H', 'T', 'W'), - LNG_('K', 'O', 'K', 'R'), - LNG_('J', 'A', 'J', 'P'), - 0 - }; - return all_langs; -} - String GetLangName(int language) { return GetLanguageInfo(language).english_name; } -/* - char buffer[200]; - if(language & 0x1000000) { - language &= 15; - static char *name[] = { - "ANSI", - "RUSSIAN", - "EASTEUROPE", - "GREEK", - "TURKISH", - "BALTIC", - "HEBREW", - "ARABIC" - }; - return String(name[language & 7]) + (language < 8 ? " I" : " II"); - } - return GetLocaleInfo(MAKELCID(language, SORT_DEFAULT), LOCALE_SENGLANGUAGE, buffer, 200) - ? buffer : ""; -*/ - String GetNativeLangName(int language) { return GetLanguageInfo(language).native_name.ToString(); -/* - char buffer[200]; - return GetLocaleInfo(MAKELCID(language, SORT_DEFAULT), LOCALE_SNATIVELANGNAME, buffer, 200) - ? buffer : ~GetLangName(language); -*/ -} - -byte GetLangCharset(int language) { - return GetLanguageInfo(language).charset; -/* - static struct { byte charset; dword codepage; } tab[] = { - { CHARSET_WIN1252, 1252 }, - { CHARSET_WIN1251, 1251 }, - { CHARSET_WIN1250, 1250 }, - { CHARSET_WIN1253, 1253 }, - { CHARSET_WIN1254, 1254 }, - { CHARSET_WIN1257, 1257 }, - { CHARSET_WIN1255, 1255 }, - { CHARSET_WIN1256, 1256 }, -// { SHIFTJIS_CHARSET, 932 }, -// { HANGEUL_CHARSET, 949 }, -// { GB2312_CHARSET, 936 }, -// { CHINESEBIG5_CHARSET, 950 }, - }; - if(language & 0x1000000) - return tab[language & 7].charset; - char buffer[20]; - GetLocaleInfo(MAKELCID(language, SORT_DEFAULT), LOCALE_IDEFAULTANSICODEPAGE, buffer, 20); - int codepage = atoi(buffer); - for(int i = 0; i < __countof(tab); i++) - if(tab[i].codepage == codepage) - return tab[i].charset; - return CHARSET_DEFAULT; -*/ -} -LanguageInfo::LanguageInfo(int lang_) -: language(lang_) -{ - charset = CHARSET_DEFAULT; - -#ifdef PLATFORM_WIN32 - LCID lcid = GetLanguageLCID(lang_); - english_name = GetLocaleInfoA(lcid, LOCALE_SENGLANGUAGE); - native_name = GetLocaleInfoW(lcid, LOCALE_SNATIVELANGNAME); - thousand_separator = GetLocaleInfoA(lcid, LOCALE_STHOUSAND); - decimal_point = GetLocaleInfoA(lcid, LOCALE_SDECIMAL); - static const LCTYPE months[] = - { - LOCALE_SMONTHNAME1, LOCALE_SMONTHNAME2, LOCALE_SMONTHNAME3, - LOCALE_SMONTHNAME4, LOCALE_SMONTHNAME5, LOCALE_SMONTHNAME6, - LOCALE_SMONTHNAME7, LOCALE_SMONTHNAME8, LOCALE_SMONTHNAME9, - LOCALE_SMONTHNAME10, LOCALE_SMONTHNAME11, LOCALE_SMONTHNAME12, - }; - static const LCTYPE smonths[] = - { - LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2, LOCALE_SABBREVMONTHNAME3, - LOCALE_SABBREVMONTHNAME4, LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6, - LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8, LOCALE_SABBREVMONTHNAME9, - LOCALE_SABBREVMONTHNAME10, LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12, - }; - ASSERT(__countof(months) == __countof(month_names)); - int i; - for(i = 0; i < __countof(months); i++) - { - month_names[i] = GetLocaleInfoW(lcid, months[i]); - short_month_names[i] = GetLocaleInfoW(lcid, smonths[i]); - } - static const LCTYPE days[] = - { - LOCALE_SDAYNAME1, LOCALE_SDAYNAME2, LOCALE_SDAYNAME3, LOCALE_SDAYNAME4, - LOCALE_SDAYNAME5, LOCALE_SDAYNAME6, LOCALE_SDAYNAME7, - }; - static const LCTYPE sdays[] = - { - LOCALE_SABBREVDAYNAME1, LOCALE_SABBREVDAYNAME2, LOCALE_SABBREVDAYNAME3, LOCALE_SABBREVDAYNAME4, - LOCALE_SABBREVDAYNAME5, LOCALE_SABBREVDAYNAME6, LOCALE_SABBREVDAYNAME7, - }; - ASSERT(__countof(days) == __countof(day_names)); - for(i = 0; i < __countof(days); i++) - { - day_names[i] = GetLocaleInfoW(lcid, days[i]); - short_day_names[i] = GetLocaleInfoW(lcid, sdays[i]); - } - - static struct { byte charset; dword codepage; } tab[] = - { - { CHARSET_WIN1252, 1252 }, - { CHARSET_WIN1251, 1251 }, - { CHARSET_WIN1250, 1250 }, - { CHARSET_WIN1253, 1253 }, - { CHARSET_WIN1254, 1254 }, - { CHARSET_WIN1257, 1257 }, - { CHARSET_WIN1255, 1255 }, - { CHARSET_WIN1256, 1256 }, -// { SHIFTJIS_CHARSET, 932 }, -// { HANGEUL_CHARSET, 949 }, -// { GB2312_CHARSET, 936 }, -// { CHINESEBIG5_CHARSET, 950 }, - }; - int codepage = atoi(GetLocaleInfoA(lcid, LOCALE_IDEFAULTANSICODEPAGE)); - for(i = 0; i < __countof(tab); i++) - if(tab[i].codepage == codepage) - { - charset = tab[i].charset; - break; - } -#endif - -#ifdef PLATFORM_POSIX - String langtext = LNGAsText(language); - char ltext[6]; - ltext[0] = ToLower(langtext[0]); - ltext[1] = ToLower(langtext[1]); - ltext[2] = '_'; - ltext[3] = ToUpper(langtext[3]); - ltext[4] = ToUpper(langtext[4]); - ltext[5] = 0; - String oldloc = setlocale(LC_ALL, NULL); -// puts(String() << "setting locale " << ltext << ", old locale = " << oldloc); - if(setlocale(LC_ALL, ltext)) - { -// puts(String() << "set locale " << ltext << " succeeded"); - const struct lconv *lc = localeconv(); - decimal_point = lc->decimal_point; - thousand_separator = lc->thousands_sep; - //lc->grouping - controls thousands grouping - static const int months[] = - { - MON_1, MON_2, MON_3, MON_4, MON_5, MON_6, MON_7, MON_8, MON_9, MON_10, MON_11, MON_12, - }; - static const int smonths[] = - { - ABMON_1, ABMON_2, ABMON_3, ABMON_4, ABMON_5, ABMON_6, ABMON_7, ABMON_8, ABMON_9, ABMON_10, ABMON_11, ABMON_12, - }; - ASSERT(__countof(months) == __countof(month_names) && __countof(smonths) == __countof(month_names)); - int i; - for(i = 0; i < __countof(months); i++) - { - month_names[i] = nl_langinfo(months[i]); - short_month_names[i] = nl_langinfo(smonths[i]); - } - static const int days[] = - { // Linux locale starts with Sunday - DAY_2, DAY_3, DAY_4, DAY_5, DAY_6, DAY_7, DAY_1, - }; - static const int sdays[] = - { - ABDAY_2, ABDAY_3, ABDAY_4, ABDAY_5, ABDAY_6, ABDAY_7, ABDAY_1, - }; - ASSERT(__countof(days) == __countof(day_names) && __countof(sdays) == __countof(day_names)); - for(i = 0; i < __countof(days); i++) - { - day_names[i] = nl_langinfo(days[i]); - short_day_names[i] = nl_langinfo(sdays[i]); - } - - setlocale(LC_ALL, oldloc); - } -#endif -} - -String LanguageInfo::ToString() const -{ - String out; - out << "LANGUAGE={" << LNGAsText(language) << "}\n" -#ifdef PLATFORM_WIN32 - << NFormat("LCID={%08x}\n", (int)GetLanguageLCID(language)) -#endif - << "ENGLISH_NAME={" << english_name << "}\n" - "NATIVE_NAME={" << FromUnicode(native_name) << "}\n" - "CHARSET={" << charset << "}\n" - "THOUSAND_SEPARATOR={" << thousand_separator << "}\n" - "DECIMAL_POINT={" << decimal_point << "}\n" - "MONTH_NAMES={\n"; - int i; - for(i = 0; i < __countof(month_names); i++) - out << " {" << FromUnicode(month_names[i]) << "} / {" << FromUnicode(short_month_names[i]) << "}\n"; - out << "}\n" - "DAY_NAMES={\n"; - for(i = 0; i < __countof(day_names); i++) - out << " {" << FromUnicode(day_names[i]) << "} / {" << FromUnicode(short_day_names[i]) << "}\n"; - out << "}\n"; - return out; -} - -static const char *NlsFindDigits(const char *src, String& dest) -{ - if(*src && !IsDigit(*src)) - { - const char *start = src; - while(*++src && !IsDigit(*src)) - ; - dest.Cat(start, (int)(src - start)); - } - return src; -} - -static const char *NlsCopyDigits(const char *src, String& dest, String thousands) -{ - if(IsDigit(*(src = NlsFindDigits(src, dest)))) - { - const char *p = src; - while(IsDigit(*++src)) - ; - int first = ((int)(src - p) + 2) % 3 + 1; - while(p < src) - { - dest.Cat(p, first); - if((p += first) < src) - { - dest.Cat(thousands); - first = 3; - } - } - } - return src; -} - -static String NlsFormatRaw(const char *n, String thousands, String decimals) -{ - if(*n == 0) - return Null; -// puts(String() << "NlsFormatRaw, n = <" << n << ">, thousands <" << thousands << ">, decimal <" << decimals << ">"); - String result; - n = NlsCopyDigits(n, result, thousands); - if(*n == (wchar)'.') - { // decimal separator - n++; - result.Cat(decimals); - const char *s = n; - while(IsDigit(*n)) - n++; - result.Cat(s, (int)(n - s)); - } - if(*(n = NlsCopyDigits(n, result, thousands))) - result.Cat(n); - return result; -} - -String LanguageInfo::FormatInt(int value) const -{ - if(IsNull(value)) - return Null; - String dest; - String is = UPP::FormatInt(value); - const char *p = NlsCopyDigits(is, dest, thousand_separator); - if(*p) - dest.Cat(p); - return dest; -} - -String LanguageInfo::FormatDouble(double value, int digits, int FD_flags, int fill_exp) const -{ - if(IsNull(value)) - return Null; -// puts(String() << "LanguageInfo(" << LNGAsText(language) << "): thousands <" << thousand_separator << ">, decimal <" << decimal_point << ">"); - return NlsFormatRaw(UPP::FormatDouble(value, digits, FD_flags, fill_exp), thousand_separator, decimal_point); -} - -String LanguageInfo::FormatDate(Date date) const -{ - return UPP::FormatDate(date, date_format, language); -} - -String LanguageInfo::FormatTime(Time time) const -{ - return UPP::FormatTime(time, time_format, language); -} - -/* -int LanguageInfo::ScanInt(const char *text, const char **endptr) const -{ - return ScanInt(text, endptr); //!! todo -} -*/ - -/* -double LanguageInfo::ScanDouble(const char *text, const char **endptr) const -{ - return ScanDouble(text, endptr); //!! todo -} -*/ - -/* -Date LanguageInfo::ScanDate(const char *text, const char **endptr, Date base_date) const -{ - return UPP::ScanDate(text, endptr, date_format, language, base_date); -} -*/ - -/* -Time LanguageInfo::ScanTime(const char *text, const char **endptr, Time base_time) const -{ - return UPP::ScanTime(text, endptr, time_format, language, base_time); -} -*/ - -WString LanguageInfo::GetIndexLetter(const wchar *text) const -{ - return IsLetter(*text) ? WString(text, 1) : WString(Null); -} - -static int LangCompareDigits(const wchar *&a, const wchar *&b, const wchar *e1, const wchar *e2) -{ - const wchar *p1 = a, *p2 = b; - while(p1 < e1 && *p1 == '0') - p1++; - while(p2 < e2 && *p2 == '0') - p2++; - const wchar *x1 = p1, *x2 = p2; - while(p1 < e1 && IsDigit(*p1)) - p1++; - while(p2 < e2 && IsDigit(*p2)) - p2++; - if(p1 - x1 != p2 - x2) - return cmp(p1 - x1, p2 - x2); - for(; x1 != p1; x1++, x2++) - if(*x1 != *x2) - return *x1 > *x2 ? 1 : -1; - a = p1; - b = p2; - return 0; -} - -int LanguageInfo::Compare(const wchar *a, const wchar *b, int a_length, int b_length) const -{ - ASSERT(language != LNG_CZECH); // use RegisterLanguageInfoCS to register true czech compare - - int little = 0, middle = 0; - const wchar *p1 = a, *e1 = a + a_length, *p2 = b, *e2 = b + b_length; - - while(p1 < e1 && p2 < e2) - { - wchar c1 = *p1++; - wchar c2 = *p2++; - - int level1 = (IsLetter(c1) ? 3 : IsDigit(c1) ? 2 : c1 == ' ' ? 0 : 1); - int level2 = (IsLetter(c2) ? 3 : IsDigit(c2) ? 2 : c2 == ' ' ? 0 : 1); - if(level1 != level2) - return cmp(level1, level2); - if(level1 <= 1) - { - if(c1 != c2) - return cmp(c1, c2); - continue; - } - if(level1 == 2) - { // digits - const wchar *dp1 = --p1, *dp2 = --p2; - int res = LangCompareDigits(dp1, dp2, e1, e2); - if(res) - return res; - p1 = dp1; - p2 = dp2; - continue; - } - - int u1, u2, i1, i2; - - i1 = ToAscii(u1 = ToUpper(c1)); - i2 = ToAscii(u2 = ToUpper(c2)); - - if(i1 != i2) - return i1 >= i2 ? 1 : -1; - - if(u1 != u2) // different diacritics - if(middle == 0) - middle = u1 - u2; - - if(c1 != c2) // different case - { - if(little == 0) - little = (u1 != c1) - (u2 != c2); - } - } - little += 4 * middle; - if(little == 0) - little = a_length - b_length; - return sgn(little); -} - -/* -static bool ContainsAccents(const wchar *s) -{ - for(; *s; s++) - if(*s != ToAscii(*s)) - return true; - return false; -} -*/ - -class DefaultWildcardCompare : public LanguageInfo::WildcardCompare -{ -public: - DefaultWildcardCompare(const wchar *templ) - { - raw_templ = 0; -// cvt_ascii = true; - if(*templ == 0) - return; -// if((*templ == '.' && templ[1] != 0 && *++templ != '.') || ContainsAccents(templ)) -// cvt_ascii = true; - raw_templ = templ; -// if(cvt_ascii) -// cvt_templ = ToUpper(ToAscii(raw_templ)); -// else - cvt_templ = ToUpper(raw_templ); - } - - virtual bool Matches(const wchar *s) const - { - return !raw_templ || RawMatches(s, cvt_templ); - } - -private: - bool RawMatches(const wchar *s, const wchar *templ) const - { - for(;;) - switch(*templ++) - { - case 0: return true; - case '.': if(*templ == 0) return *s == 0; // force end of string - case '?': if(*s++ == 0) return false; break; - case '*': - do - if(RawMatches(s, templ)) - return true; - while(*s++); - return false; - case '\\': - if(*templ == 0 || *s++ != *templ++) - return false; - break; - - default: -// if(templ[-1] != ToUpper(cvt_ascii ? ToAscii(*s) : *s)) - if(templ[-1] != ToUpper(*s)) - return false; - s++; - break; - } - return true; - } - -private: - const wchar *raw_templ; -// bool cvt_ascii; - WString cvt_templ; -}; - -One LanguageInfo::GetWildcardCompare(const wchar *wildcard_text) const -{ - return new DefaultWildcardCompare(wildcard_text); -} - -typedef ArrayMap LanguageInfoMap; -GLOBAL_VAR(LanguageInfoMap, LanguageInfo::Map) -static StaticMutex sMapMutex; - -void LanguageInfo::Register(One info) -{ - INTERLOCKED_(sMapMutex) { - int lang = info->language; - int f = Map().Find(lang); - if(f >= 0) - Map().Set(f, -info); - else - Map().Add(lang, -info); - } -} - -class LanguageInfoCS : public LanguageInfo -{ -public: - LanguageInfoCS(); - - virtual WString GetIndexLetter(const wchar *text) const; - - virtual int Compare(const wchar *a, const wchar *b, int a_length, int b_length) const; - virtual One GetWildcardCompare(const wchar *wildcard_text) const; - -public: -}; - -LanguageInfoCS::LanguageInfoCS() -: LanguageInfo(LNG_CZECH) -{ - english_name = "Czech"; - native_name = ToUnicode("Česky", CHARSET_WIN1250); // __FILE__CHARSET__ -// charset = CHARSET_WIN1250; -// thousand_separator = L" "; -// decimal_point = L","; -} - -WString LanguageInfoCS::GetIndexLetter(const wchar *s) const -{ - wchar temp[3]; - temp[0] = temp[1] = temp[2] = 0; - if(*s <= 2047 && IsLetter(*s)) // IsLetter - { - temp[0] = ToUpper(*s); - if(s[1] <= 2047 && IsLetter(s[1])) - temp[1] = ToLower(s[1]); - if(temp[0] != 'C' || temp[1] != 'h') - temp[1] = 0; - switch(ToUpper(ToAscii(*s))) - { - case 'A': case 'E': case 'I': case 'N': - case 'O': case 'T': case 'U': case 'Y': - temp[0] = ToAscii(temp[0]); - break; - } - } - return temp; -} - -int LanguageInfoCS::Compare(const wchar *a, const wchar *b, int a_length, int b_length) const -{ - int little = 0, middle = 0; - const wchar *p1 = a, *e1 = a + a_length, *p2 = b, *e2 = b + b_length; - - while(p1 < e1 && p2 < e2) - { - wchar c1 = *p1++; - wchar c2 = *p2++; - - int level1 = (IsLetter(c1) ? 3 : IsDigit(c1) ? 2 : c1 == ' ' ? 0 : 1); - int level2 = (IsLetter(c2) ? 3 : IsDigit(c2) ? 2 : c2 == ' ' ? 0 : 1); - if(level1 != level2) - return cmp(level1, level2); - if(level1 <= 1) - { - if(c1 != c2) - return cmp(c1, c2); - continue; - } - if(level1 == 2) - { // digits - const wchar *dp1 = --p1, *dp2 = --p2; - int res = LangCompareDigits(dp1, dp2, e1, e2); - if(res) - return res; - p1 = dp1; - p2 = dp2; - continue; - } - - int u1, u2, i1, i2; - - if((c1 == 'C' || c1 == 'c') && (p1 < e1 && (*p1 == 'H' || *p1 == 'h'))) - { // CH - i1 = 'H'; - u1 = 65535; - p1++; - } - else - i1 = ToAscii(u1 = ToUpper(c1)); - if((c2 == 'C' || c2 == 'c') && (p2 < e2 && (*p2 == 'H' || *p2 == 'h'))) - { // CH - i2 = 'H'; - u2 = 65535; - p2++; - } - else - i2 = ToAscii(u2 = ToUpper(c2)); - - if(i1 != i2) - return i1 >= i2 ? 1 : -1; - - if(u1 != u2) // different diacritics - switch(i1) - { - case 'A': case 'E': case 'I': case 'N': - case 'O': case 'T': case 'U': case 'Y': - if(middle == 0) - middle = u1 - u2; - continue; - default: - return u1 >= u2 ? 1 : -1; - } - if(c1 != c2) // different case - { - if(little == 0) - - little = (u1 != c1) - (u2 != c2); - } - } - little += 4 * middle; - if(little == 0) - little = a_length - b_length; - return sgn(little); -} - -class WildcardCompareCS : public LanguageInfo::WildcardCompare -{ -public: - WildcardCompareCS(const wchar *templ) - { - raw_templ = 0; -// cvt_ascii = false; - if(*templ == 0) - return; -// if((*templ == '.' && templ[1] != 0 && *++templ != '.') || ContainsAccents(templ)) -// { -// exclude_ch = (ToUpper(*templ) == 'C' && templ[1] == 0); -// cvt_ascii = false; -// } - raw_templ = templ; -// if(cvt_ascii) -// cvt_templ = ToUpper(ToAscii(raw_templ)); -// else - cvt_templ = ToUpper(raw_templ); - } - - virtual bool Matches(const wchar *s) const - { -// if(exclude_ch && *s && (s[1] == 'h' || s[1] == 'H')) -// return false; - return !raw_templ || RawMatches(s, cvt_templ); - } - -private: - bool RawMatches(const wchar *s, const wchar *templ) const - { - for(;;) - switch(*templ++) - { - case 0: return true; - case '.': if(*templ == 0) return *s == 0; // force end of string - case '?': if(*s++ == 0) return false; break; - case '*': - do - if(RawMatches(s, templ)) - return true; - while(*s++); - return false; - case '\\': if(*templ == 0 || *templ++ != *s++) return false; break; - default: if(templ[-1] != ToUpper(*s++)) return false; - break; - } - return true; - } - -private: - const wchar *raw_templ; -// bool exclude_ch; -// bool cvt_ascii; - WString cvt_templ; -}; - -One LanguageInfoCS::GetWildcardCompare(const wchar *wildcard_text) const -{ - return new WildcardCompareCS(wildcard_text); -} - -class LanguageInfoEN : public LanguageInfo -{ -public: - LanguageInfoEN() - : LanguageInfo(LNG_('E', 'N', 'U', 'S')) - { - english_name = "English"; - native_name = ToUnicode("English", CHARSET_DEFAULT); -// thousand_separator = " "; -// decimal_point = "."; - } -}; - -class LanguageInfoGE : public LanguageInfo -{ -public: - LanguageInfoGE() - : LanguageInfo(LNG_('D', 'E', 'D', 'E')) - { - english_name = "German"; - native_name = ToUnicode("Deutsch", CHARSET_WIN1250); - } -}; - -class LanguageInfoFR : public LanguageInfo -{ -public: - LanguageInfoFR() - : LanguageInfo(LNG_('F', 'R', 'F', 'R')) - { - english_name = "Franch"; - native_name = ToUnicode("Francaise", CHARSET_WIN1250); - } -}; - -class LanguageInfoES : public LanguageInfo -{ -public: - LanguageInfoES() - : LanguageInfo(LNG_('E', 'S', 'E', 'S')) - { - english_name = "Spanish"; - native_name = ToUnicode("Espagnnol", CHARSET_WIN1250); - } -}; - -class LanguageInfoRU : public LanguageInfo -{ -public: - LanguageInfoRU() - : LanguageInfo(LNG_('R', 'U', 'R', 'U')) - { - english_name = "Russian"; - native_name = "\xD0\xA0\xD1\x83\xD1\x81\xD1\x81\xD0\xBA\xD0\xB8\xD0\xB9"; - } -}; - -class LanguageInfoUK : public LanguageInfo -{ -public: - LanguageInfoUK() - : LanguageInfo(LNG_('U', 'K', 'U', 'A')) - { - english_name = "Ukrainian"; - native_name = "\xD0\xA3\xD0\xBA\xD1\x80\xD0\xB0\xD1\x97\xD0\xBD\xD1\x81\xD1\x8C\xD0\xBA\xD0\xB0"; - } -}; - -const LanguageInfo& GetLanguageInfo(int lcode) -{ - static bool init_std = false; - if(!init_std) - { - init_std = true; - LanguageInfo::Register(new LanguageInfoCS); - LanguageInfo::Register(new LanguageInfoEN); - LanguageInfo::Register(new LanguageInfoGE); - LanguageInfo::Register(new LanguageInfoFR); - LanguageInfo::Register(new LanguageInfoES); - LanguageInfo::Register(new LanguageInfoRU); - LanguageInfo::Register(new LanguageInfoUK); - } - - static int recent = 0; - LanguageInfo *rinfo = 0; - if(rinfo && lcode == recent) - return *rinfo; - if(lcode == 0) - lcode = GetCurrentLanguage(); //!! todo - decide on default / neutral language code - INTERLOCKED_(sMapMutex) { - LanguageInfoMap& map = LanguageInfo::Map(); - int f = map.Find(lcode); - if(f < 0) - { - f = map.GetCount(); - map.Add(lcode, new LanguageInfo(lcode)); - } - recent = lcode; - return *(rinfo = &map[f]); - } - return *rinfo; -} - -const LanguageInfo& GetLanguageInfo() -{ - return GetLanguageInfo(GetCurrentLanguage()); } END_UPP_NAMESPACE diff --git a/uppsrc/Core/Lang.h b/uppsrc/Core/Lang.h index ebcd67abf..ab067b2c4 100644 --- a/uppsrc/Core/Lang.h +++ b/uppsrc/Core/Lang.h @@ -30,7 +30,7 @@ const int *GetAllLanguages(); String GetLangName(int language); String GetNativeLangName(int language); -byte GetLangCharset(int language); +//byte GetLangCharset(int language); String txtGet(const char *id, int language = LNG_CURRENT); @@ -42,65 +42,54 @@ String GetLocaleInfoA(LCID lcid, LCTYPE lctype); WString GetLocaleInfoW(LCID lcid, LCTYPE lctype); #endif -class LanguageInfo -{ -public: - LanguageInfo(int language); - virtual ~LanguageInfo() {} +class LanguageInfo { + void Set(int language); - String ToString() const; - - virtual String FormatInt(int value) const; - virtual String FormatDouble(double value, int digits, int FD_flags = 0, int fill_exp = 0) const; - virtual String FormatDate(Date date) const; - virtual String FormatTime(Time time) const; - -// virtual int ScanInt(const char *text, const char **endptr) const; -// virtual double ScanDouble(const char *text, const char **endptr) const; -// virtual Date ScanDate(const char *text, const char **endptr, Date base_date = GetSysDate()) const; -// virtual Time ScanTime(const char *text, const char **endptr, Time base_time = GetSysTime()) const; - - virtual WString GetIndexLetter(const wchar *text) const; - - virtual int Compare(const wchar *a, const wchar *b, int a_length, int b_length) const; - int Compare(const wchar *a, const wchar *b) const { return Compare(a, b, wstrlen(a), wstrlen(b)); } - int Compare(WString a, WString b) const { return Compare(a, b, a.GetLength(), b.GetLength()); } - int Compare(const char *a, const char *b) const { return Compare(ToUnicode(a, CHARSET_DEFAULT), ToUnicode(b, CHARSET_DEFAULT)); } - int Compare(String a, String b) const { return Compare(a.ToWString(), b.ToWString()); } - - bool operator () (const wchar *a, const wchar *b) const { return Compare(a, b) < 0; } - bool operator () (WString a, WString b) const { return Compare(a, b) < 0; } - bool operator () (const char *a, const char *b) const { return Compare(a, b) < 0; } - bool operator () (String a, String b) const { return Compare(a, b) < 0; } - - struct WildcardCompare - { - virtual ~WildcardCompare() {} - virtual bool Matches(const wchar *s) const = 0; - }; - - virtual One GetWildcardCompare(const wchar *wildcard_text) const; - - static ArrayMap& Map(); - static void Register(One info); + friend const LanguageInfo& GetLanguageInfo(int lang); public: int language; String english_name; - WString native_name; - byte charset; + String native_name; - String thousand_separator; - String decimal_point; - String date_format; - String time_format; + String thousand_separator, decimal_point; + String date_format, time_format; // (?) + + String month[12], smonth[12], day[7], sday[7]; + int (*compare)(const wchar *a, int alen, const wchar *b, int blen, int lang); + WString (*getindexletter)(const wchar *text, int lang); + + String FormatInt(int value) const; + String FormatDouble(double value, int digits, int FD_flags = 0, int fill_exp = 0) const; + String FormatDate(Date date) const; + String FormatTime(Time time) const; + + WString GetIndexLetter(const wchar *text) const { return (*getindexletter)(text, language); } + int Compare(const wchar *a, int alen, const wchar *b, int blen) const { return (*compare)(a, alen, b, blen, language); } + + int Compare(const wchar *a, const wchar *b) const { return Compare(a, wstrlen(a), b, wstrlen(b)); } + int Compare(WString a, WString b) const { return Compare(a, a.GetLength(), b, b.GetLength()); } + int Compare(const char *a, const char *b) const { return Compare(ToUnicode(a, CHARSET_DEFAULT), ToUnicode(b, CHARSET_DEFAULT)); } + int Compare(String a, String b) const { return Compare(a.ToWString(), b.ToWString()); } + + bool operator()(const wchar *a, const wchar *b) const { return Compare(a, b) < 0; } + bool operator()(WString a, WString b) const { return Compare(a, b) < 0; } + bool operator()(const char *a, const char *b) const { return Compare(a, b) < 0; } + bool operator()(String a, String b) const { return Compare(a, b) < 0; } + + String ToString() const; + +//BWC WString month_names[12], short_month_names[12]; WString day_names[7], short_day_names[7]; + int Compare(const wchar *a, const wchar *b, int alen, int blen) const { return Compare(a, alen, b, blen); } }; -const LanguageInfo& GetLanguageInfo(int lcode); -const LanguageInfo& GetLanguageInfo(); +const LanguageInfo& GetLanguageInfo(int lang); +const LanguageInfo& GetLanguageInfo(); + +void SetLanguageInfo(int lang, const LanguageInfo& lf); // ------ Language internals ---------------- diff --git a/uppsrc/Core/LangInfo.cpp b/uppsrc/Core/LangInfo.cpp new file mode 100644 index 000000000..0fff8085c --- /dev/null +++ b/uppsrc/Core/LangInfo.cpp @@ -0,0 +1,869 @@ +#include "Core.h" + +#ifdef PLATFORM_WIN32 +#include +#include +#endif +#ifdef PLATFORM_POSIX +#include +#include +#endif + +namespace Upp { + +#define LLOG(x) // LOG(x) + +extern int LanguageList[]; +extern const char *LanguageInfoList[]; + +const int *GetAllLanguages() +{ + return LanguageList; +} + +WString DefaultGetIndexLetter(const wchar *text, int) +{ + return IsLetter(*text) ? WString(text, 1) : WString(Null); +} + +static int LangCompareDigits(const wchar *&a, const wchar *&b, const wchar *e1, const wchar *e2) +{ + const wchar *p1 = a, *p2 = b; + while(p1 < e1 && *p1 == '0') + p1++; + while(p2 < e2 && *p2 == '0') + p2++; + const wchar *x1 = p1, *x2 = p2; + while(p1 < e1 && IsDigit(*p1)) + p1++; + while(p2 < e2 && IsDigit(*p2)) + p2++; + if(p1 - x1 != p2 - x2) + return cmp(p1 - x1, p2 - x2); + for(; x1 != p1; x1++, x2++) + if(*x1 != *x2) + return *x1 > *x2 ? 1 : -1; + a = p1; + b = p2; + return 0; +} + +int DefaultLanguageCompare(const wchar *a, int a_length, const wchar *b, int b_length, int) +{ + int little = 0, middle = 0; + const wchar *p1 = a, *e1 = a + a_length, *p2 = b, *e2 = b + b_length; + + while(p1 < e1 && p2 < e2) + { + wchar c1 = *p1++; + wchar c2 = *p2++; + + int level1 = (IsLetter(c1) ? 3 : IsDigit(c1) ? 2 : c1 == ' ' ? 0 : 1); + int level2 = (IsLetter(c2) ? 3 : IsDigit(c2) ? 2 : c2 == ' ' ? 0 : 1); + if(level1 != level2) + return cmp(level1, level2); + if(level1 <= 1) + { + if(c1 != c2) + return cmp(c1, c2); + continue; + } + if(level1 == 2) + { // digits + const wchar *dp1 = --p1, *dp2 = --p2; + int res = LangCompareDigits(dp1, dp2, e1, e2); + if(res) + return res; + p1 = dp1; + p2 = dp2; + continue; + } + + int u1, u2, i1, i2; + + i1 = ToAscii(u1 = ToUpper(c1)); + i2 = ToAscii(u2 = ToUpper(c2)); + + if(i1 != i2) + return i1 >= i2 ? 1 : -1; + + if(u1 != u2) // different diacritics + if(middle == 0) + middle = u1 - u2; + + if(c1 != c2) // different case + { + if(little == 0) + little = (u1 != c1) - (u2 != c2); + } + } + little += 4 * middle; + if(little == 0) + little = a_length - b_length; + return sgn(little); +} + +WString CSCZGetIndexLetter(const wchar *s, int) +{ + wchar temp[3]; + temp[0] = temp[1] = temp[2] = 0; + if(*s <= 2047 && IsLetter(*s)) // IsLetter + { + temp[0] = ToUpper(*s); + if(s[1] <= 2047 && IsLetter(s[1])) + temp[1] = ToLower(s[1]); + if(temp[0] != 'C' || temp[1] != 'h') + temp[1] = 0; + switch(ToUpper(ToAscii(*s))) + { + case 'A': case 'E': case 'I': case 'N': + case 'O': case 'T': case 'U': case 'Y': + temp[0] = ToAscii(temp[0]); + break; + } + } + return temp; +} + +int CSCZLanguageCompare(const wchar *a, int a_length, const wchar *b, int b_length, int) +{ + int little = 0, middle = 0; + const wchar *p1 = a, *e1 = a + a_length, *p2 = b, *e2 = b + b_length; + + while(p1 < e1 && p2 < e2) + { + wchar c1 = *p1++; + wchar c2 = *p2++; + + int level1 = (IsLetter(c1) ? 3 : IsDigit(c1) ? 2 : c1 == ' ' ? 0 : 1); + int level2 = (IsLetter(c2) ? 3 : IsDigit(c2) ? 2 : c2 == ' ' ? 0 : 1); + if(level1 != level2) + return cmp(level1, level2); + if(level1 <= 1) + { + if(c1 != c2) + return cmp(c1, c2); + continue; + } + if(level1 == 2) + { // digits + const wchar *dp1 = --p1, *dp2 = --p2; + int res = LangCompareDigits(dp1, dp2, e1, e2); + if(res) + return res; + p1 = dp1; + p2 = dp2; + continue; + } + + int u1, u2, i1, i2; + + if((c1 == 'C' || c1 == 'c') && (p1 < e1 && (*p1 == 'H' || *p1 == 'h'))) + { // CH + i1 = 'H'; + u1 = 65535; + p1++; + } + else + i1 = ToAscii(u1 = ToUpper(c1)); + if((c2 == 'C' || c2 == 'c') && (p2 < e2 && (*p2 == 'H' || *p2 == 'h'))) + { // CH + i2 = 'H'; + u2 = 65535; + p2++; + } + else + i2 = ToAscii(u2 = ToUpper(c2)); + + if(i1 != i2) + return i1 >= i2 ? 1 : -1; + + if(u1 != u2) // different diacritics + switch(i1) + { + case 'A': case 'E': case 'I': case 'N': + case 'O': case 'T': case 'U': case 'Y': + if(middle == 0) + middle = u1 - u2; + continue; + default: + return u1 >= u2 ? 1 : -1; + } + if(c1 != c2) // different case + { + if(little == 0) + + little = (u1 != c1) - (u2 != c2); + } + } + little += 4 * middle; + if(little == 0) + little = a_length - b_length; + return sgn(little); +} + +#ifdef PLATFORM_WIN32 +#ifdef PLATFORM_WINCE //TODO? +String GetLocaleInfoA(LCID lcid, LCTYPE lctype) +{ + wchar cbuf[1000]; + ::GetLocaleInfoW(lcid, lctype, cbuf, __countof(cbuf)); + return FromSystemCharset(cbuf); +} +#else +String GetLocaleInfoA(LCID lcid, LCTYPE lctype) +{ + if(IsWinNT()) { + wchar cbuf[1000]; + UnicodeWin32().GetLocaleInfoW(lcid, lctype, cbuf, __countof(cbuf)); + return FromSystemCharsetW(cbuf); + } + else { + char cbuf[1000]; + ::GetLocaleInfoA(lcid, lctype, cbuf, __countof(cbuf)); + return FromSystemCharset(cbuf); + } +} +#endif + +WString GetLocaleInfoW(LCID lcid, LCTYPE lctype) +{ + union { + wchar wbuf[1000]; + char abuf[1000]; + }; + Zero(wbuf); + if(::GetLocaleInfoW(lcid, lctype, (WCHAR *)wbuf, __countof(wbuf))) + return wbuf; +#ifdef PLATFORM_WINCE + return Null; +#else + ::GetLocaleInfoA(lcid, lctype, abuf, __countof(abuf)); + return ToUnicode(abuf, CHARSET_DEFAULT); +#endif +} +#endif + +static dword sGetLanguageDetails(int language, String *english_name, String *native_name) +{ + int q = 0; + for(const int *ptr = LanguageList; *ptr; ptr++, q++) + if(*ptr == language) { + const char *f = LanguageInfoList[q]; + const char *a = strchr(f, '\t'); + const char *b = strchr(a + 1, '\t'); + if(english_name) + *english_name = String(f, a); + if(native_name) + *native_name = ToCharset(CHARSET_DEFAULT, String(a + 1, b), CHARSET_UTF8); + return MAKEWORD(b[2], b[1]); + } + return 0; +} + +#ifdef PLATFORM_WIN32 +LCID GetLanguageLCID(int language) +{ + return sGetLanguageDetails(language, NULL, NULL); +} +#endif + +void LanguageInfo::Set(int lang_) +{ + language = lang_; + dword q = sGetLanguageDetails(language, &english_name, &native_name); + if(!q) + return; + + getindexletter = DefaultGetIndexLetter; + compare = DefaultLanguageCompare; + if(language == LNG_('C','S','C','Z')) { + getindexletter = CSCZGetIndexLetter; + compare = CSCZLanguageCompare; + } +#ifdef PLATFORM_WIN32 + LCID lcid = q; + thousand_separator = GetLocaleInfoA(lcid, LOCALE_STHOUSAND); + decimal_point = GetLocaleInfoA(lcid, LOCALE_SDECIMAL); + static const LCTYPE months[] = + { + LOCALE_SMONTHNAME1, LOCALE_SMONTHNAME2, LOCALE_SMONTHNAME3, + LOCALE_SMONTHNAME4, LOCALE_SMONTHNAME5, LOCALE_SMONTHNAME6, + LOCALE_SMONTHNAME7, LOCALE_SMONTHNAME8, LOCALE_SMONTHNAME9, + LOCALE_SMONTHNAME10, LOCALE_SMONTHNAME11, LOCALE_SMONTHNAME12, + }; + static const LCTYPE smonths[] = + { + LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2, LOCALE_SABBREVMONTHNAME3, + LOCALE_SABBREVMONTHNAME4, LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6, + LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8, LOCALE_SABBREVMONTHNAME9, + LOCALE_SABBREVMONTHNAME10, LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12, + }; + ASSERT(__countof(months) == __countof(month_names)); + int i; + for(i = 0; i < __countof(months); i++) + { + month_names[i] = GetLocaleInfoW(lcid, months[i]); + short_month_names[i] = GetLocaleInfoW(lcid, smonths[i]); + } + static const LCTYPE days[] = + { + LOCALE_SDAYNAME1, LOCALE_SDAYNAME2, LOCALE_SDAYNAME3, LOCALE_SDAYNAME4, + LOCALE_SDAYNAME5, LOCALE_SDAYNAME6, LOCALE_SDAYNAME7, + }; + static const LCTYPE sdays[] = + { + LOCALE_SABBREVDAYNAME1, LOCALE_SABBREVDAYNAME2, LOCALE_SABBREVDAYNAME3, LOCALE_SABBREVDAYNAME4, + LOCALE_SABBREVDAYNAME5, LOCALE_SABBREVDAYNAME6, LOCALE_SABBREVDAYNAME7, + }; + ASSERT(__countof(days) == __countof(day_names)); + for(i = 0; i < __countof(days); i++) + { + day_names[i] = GetLocaleInfoW(lcid, days[i]); + short_day_names[i] = GetLocaleInfoW(lcid, sdays[i]); + } +#endif + +#ifdef PLATFORM_POSIX + String langtext = LNGAsText(language); + char ltext[6]; + ltext[0] = ToLower(langtext[0]); + ltext[1] = ToLower(langtext[1]); + ltext[2] = '_'; + ltext[3] = ToUpper(langtext[3]); + ltext[4] = ToUpper(langtext[4]); + ltext[5] = 0; + String oldloc = setlocale(LC_ALL, NULL); + if(setlocale(LC_ALL, ltext)) + { + const struct lconv *lc = localeconv(); + decimal_point = lc->decimal_point; + thousand_separator = lc->thousands_sep; + static const int months[] = + { + MON_1, MON_2, MON_3, MON_4, MON_5, MON_6, MON_7, MON_8, MON_9, MON_10, MON_11, MON_12, + }; + static const int smonths[] = + { + ABMON_1, ABMON_2, ABMON_3, ABMON_4, ABMON_5, ABMON_6, ABMON_7, ABMON_8, ABMON_9, ABMON_10, ABMON_11, ABMON_12, + }; + ASSERT(__countof(months) == __countof(month_names) && __countof(smonths) == __countof(month_names)); + int i; + for(i = 0; i < __countof(months); i++) + { + month_names[i] = nl_langinfo(months[i]); + short_month_names[i] = nl_langinfo(smonths[i]); + } + static const int days[] = + { // Linux locale starts with Sunday + DAY_2, DAY_3, DAY_4, DAY_5, DAY_6, DAY_7, DAY_1, + }; + static const int sdays[] = + { + ABDAY_2, ABDAY_3, ABDAY_4, ABDAY_5, ABDAY_6, ABDAY_7, ABDAY_1, + }; + ASSERT(__countof(days) == __countof(day_names) && __countof(sdays) == __countof(day_names)); + for(i = 0; i < __countof(days); i++) + { + day_names[i] = nl_langinfo(days[i]); + short_day_names[i] = nl_langinfo(sdays[i]); + } + + setlocale(LC_ALL, oldloc); + } +#endif + for(int i = 0; i < 12; i++) { + month[i] = month_names[i].ToString(); + smonth[i] = short_month_names[i].ToString(); + } + for(int i = 0; i < 7; i++) { + day[i] = day_names[i].ToString(); + sday[i] = short_day_names[i].ToString(); + } +} + +String LanguageInfo::ToString() const +{ + String out; + out << "LANGUAGE={" << LNGAsText(language) << "}\n" + << "ENGLISH_NAME={" << english_name << "}\n" + "NATIVE_NAME={" << native_name << "}\n" + "THOUSAND_SEPARATOR={" << thousand_separator << "}\n" + "DECIMAL_POINT={" << decimal_point << "}\n" + "MONTH_NAMES={\n"; + int i; + for(i = 0; i < __countof(month_names); i++) + out << " {" << FromUnicode(month_names[i]) << "} / {" << FromUnicode(short_month_names[i]) << "}\n"; + out << "}\n" + "DAY_NAMES={\n"; + for(i = 0; i < __countof(day_names); i++) + out << " {" << FromUnicode(day_names[i]) << "} / {" << FromUnicode(short_day_names[i]) << "}\n"; + out << "}\n"; + return out; +} + +static const char *NlsFindDigits(const char *src, String& dest) +{ + if(*src && !IsDigit(*src)) + { + const char *start = src; + while(*++src && !IsDigit(*src)) + ; + dest.Cat(start, (int)(src - start)); + } + return src; +} + +static const char *NlsCopyDigits(const char *src, String& dest, String thousands) +{ + if(IsDigit(*(src = NlsFindDigits(src, dest)))) + { + const char *p = src; + while(IsDigit(*++src)) + ; + int first = ((int)(src - p) + 2) % 3 + 1; + while(p < src) + { + dest.Cat(p, first); + if((p += first) < src) + { + dest.Cat(thousands); + first = 3; + } + } + } + return src; +} + +static String NlsFormatRaw(const char *n, String thousands, String decimals) +{ + if(*n == 0) + return Null; +// puts(String() << "NlsFormatRaw, n = <" << n << ">, thousands <" << thousands << ">, decimal <" << decimals << ">"); + String result; + n = NlsCopyDigits(n, result, thousands); + if(*n == (wchar)'.') + { // decimal separator + n++; + result.Cat(decimals); + const char *s = n; + while(IsDigit(*n)) + n++; + result.Cat(s, (int)(n - s)); + } + if(*(n = NlsCopyDigits(n, result, thousands))) + result.Cat(n); + return result; +} + +String LanguageInfo::FormatInt(int value) const +{ + if(IsNull(value)) + return Null; + String dest; + String is = UPP::FormatInt(value); + const char *p = NlsCopyDigits(is, dest, thousand_separator); + if(*p) + dest.Cat(p); + return dest; +} + +String LanguageInfo::FormatDouble(double value, int digits, int FD_flags, int fill_exp) const +{ + if(IsNull(value)) + return Null; + return NlsFormatRaw(UPP::FormatDouble(value, digits, FD_flags, fill_exp), thousand_separator, decimal_point); +} + +String LanguageInfo::FormatDate(Date date) const +{ + return UPP::FormatDate(date, date_format, language); +} + +String LanguageInfo::FormatTime(Time time) const +{ + return UPP::FormatTime(time, time_format, language); +} + +ArrayMap& LangMap() +{ + static ArrayMap x; + return x; +} + +StaticMutex sLanguageInfoMutex; + +const LanguageInfo& GetLanguageInfo(int lang) +{ + Mutex::Lock __(sLanguageInfoMutex); + ArrayMap& m = LangMap(); + int q = m.Find(lang); + if(q >= 0) + return m[q]; + LanguageInfo& f = m.Add(lang); + f.Set(lang); + return f; +} + +const LanguageInfo& GetLanguageInfo() +{ + return GetLanguageInfo(GetCurrentLanguage()); +} + +void SetLanguageInfo(int lang, const LanguageInfo& lf) +{ + Mutex::Lock __(sLanguageInfoMutex); + ArrayMap& m = LangMap(); + m.GetAdd(lang) = lf; +} + +int LanguageList[] = { + LNG_('A','R','S','A'), + LNG_('B','G','B','G'), + LNG_('C','A','E','S'), + LNG_('Z','H','T','W'), + LNG_('C','S','C','Z'), + LNG_('D','A','D','K'), + LNG_('D','E','D','E'), + LNG_('E','L','G','R'), + LNG_('E','N','U','S'), + LNG_('E','S','E','S'), + LNG_('F','I','F','I'), + LNG_('F','R','F','R'), + LNG_('H','E','I','L'), + LNG_('H','U','H','U'), + LNG_('I','S','I','S'), + LNG_('I','T','I','T'), + LNG_('J','A','J','P'), + LNG_('K','O','K','R'), + LNG_('N','L','N','L'), + LNG_('N','B','N','O'), + LNG_('P','L','P','L'), + LNG_('P','T','B','R'), + LNG_('R','O','R','O'), + LNG_('R','U','R','U'), + LNG_('H','R','H','R'), + LNG_('S','K','S','K'), + LNG_('S','Q','A','L'), + LNG_('S','V','S','E'), + LNG_('T','H','T','H'), + LNG_('T','R','T','R'), + LNG_('U','R','P','K'), + LNG_('I','D','I','D'), + LNG_('U','K','U','A'), + LNG_('B','E','B','Y'), + LNG_('S','L','S','I'), + LNG_('E','T','E','E'), + LNG_('L','V','L','V'), + LNG_('L','T','L','T'), + LNG_('F','A','I','R'), + LNG_('V','I','V','N'), + LNG_('H','Y','A','M'), + LNG_('A','Z','A','Z'), + LNG_('E','U','E','S'), + LNG_('M','K','M','K'), + LNG_('A','F','Z','A'), + LNG_('K','A','G','E'), + LNG_('F','O','F','O'), + LNG_('H','I','I','N'), + LNG_('M','S','M','Y'), + LNG_('K','K','K','Z'), + LNG_('K','Y','K','G'), + LNG_('S','W','K','E'), + LNG_('U','Z','U','Z'), + LNG_('T','T','R','U'), + LNG_('P','A','I','N'), + LNG_('G','U','I','N'), + LNG_('T','A','I','N'), + LNG_('T','E','I','N'), + LNG_('K','N','I','N'), + LNG_('M','R','I','N'), + LNG_('S','A','I','N'), + LNG_('M','N','M','N'), + LNG_('G','L','E','S'), + LNG_('K','O','I','N'), + LNG_('S','Y','S','Y'), + LNG_('D','I','M','V'), + LNG_('A','R','I','Q'), + LNG_('Z','H','C','N'), + LNG_('D','E','C','H'), + LNG_('E','N','G','B'), + LNG_('E','S','M','X'), + LNG_('F','R','B','E'), + LNG_('I','T','C','H'), + LNG_('N','L','B','E'), + LNG_('N','N','N','O'), + LNG_('P','T','P','T'), + LNG_('S','R','S','P'), + LNG_('S','V','F','I'), + LNG_('A','Z','A','Z'), + LNG_('M','S','B','N'), + LNG_('U','Z','U','Z'), + LNG_('A','R','E','G'), + LNG_('Z','H','H','K'), + LNG_('D','E','A','T'), + LNG_('E','N','A','U'), + LNG_('E','S','E','S'), + LNG_('F','R','C','A'), + LNG_('S','R','S','P'), + LNG_('A','R','L','Y'), + LNG_('Z','H','S','G'), + LNG_('D','E','L','U'), + LNG_('E','N','C','A'), + LNG_('E','S','G','T'), + LNG_('F','R','C','H'), + LNG_('A','R','D','Z'), + LNG_('Z','H','M','O'), + LNG_('D','E','L','I'), + LNG_('E','N','N','Z'), + LNG_('E','S','C','R'), + LNG_('F','R','L','U'), + LNG_('A','R','M','A'), + LNG_('E','N','I','E'), + LNG_('E','S','P','A'), + LNG_('F','R','M','C'), + LNG_('A','R','T','N'), + LNG_('E','N','Z','A'), + LNG_('E','S','D','O'), + LNG_('A','R','O','M'), + LNG_('E','N','J','M'), + LNG_('E','S','V','E'), + LNG_('A','R','Y','E'), + LNG_('E','N','C','B'), + LNG_('E','S','C','O'), + LNG_('A','R','S','Y'), + LNG_('E','N','B','Z'), + LNG_('E','S','P','E'), + LNG_('A','R','J','O'), + LNG_('E','N','T','T'), + LNG_('E','S','A','R'), + LNG_('A','R','L','B'), + LNG_('E','N','Z','W'), + LNG_('E','S','E','C'), + LNG_('A','R','K','W'), + LNG_('E','N','P','H'), + LNG_('E','S','C','L'), + LNG_('A','R','A','E'), + LNG_('E','S','U','Y'), + LNG_('A','R','B','H'), + LNG_('E','S','P','Y'), + LNG_('A','R','Q','A'), + LNG_('E','S','B','O'), + LNG_('E','S','S','V'), + LNG_('E','S','H','N'), + LNG_('E','S','N','I'), + LNG_('E','S','P','R'), + LNG_('H','R','B','A'), + LNG_('B','S','B','A'), + LNG_('S','R','B','A'), + LNG_('C','Y','G','B'), + LNG_('M','I','N','Z'), + LNG_('M','T','M','T'), + LNG_('Q','U','B','O'), + LNG_('Q','U','E','C'), + LNG_('Q','U','P','E'), + LNG_('T','N','Z','A'), + LNG_('X','H','Z','A'), + LNG_('Z','U','Z','A'), + LNG_('N','S','Z','A'), + LNG_('S','E','N','O'), + LNG_('S','E','S','E'), + LNG_('S','E','F','I'), + LNG_('S','E','N','O'), + LNG_('S','E','S','E'), + LNG_('S','E','N','O'), + LNG_('S','E','S','E'), + LNG_('S','E','F','I'), + LNG_('S','E','F','I'), + LNG_('S','R','B','A'), + LNG_('B','S','B','A'), + LNG_('F','I','P','H'), + LNG_('L','B','L','U'), + LNG_('P','S','A','F'), + LNG_('F','Y','N','L'), + LNG_('A','R','C','L'), + LNG_('N','E','N','P'), + LNG_('I','U','C','A'), + LNG_('G','A','I','E'), + LNG_('M','O','C','A'), + LNG_('R','M','C','H'), + LNG_('B','N','I','N'), + LNG_('M','L','I','N'), + 0 +}; + +const char *LanguageInfoList[] = { + "Arabic\t\330\247\331\204\330\271\330\261\330\250\331\212\330\251\t\004\001", + "Bulgarian\t\320\261\321\212\320\273\320\263\320\260\321\200\321\201\320\272\320\270\t\004\002", + "Catalan\tcatal\303\240\t\004\003", + "Chinese\t\344\270\255\346\226\207(\347\271\201\351\253\224)\t\004\004", + "Czech\t\304\215e\305\241tina\t\004\005", + "Danish\tdansk\t\004\006", + "German\tDeutsch\t\004\a", + "Greek\t\316\265\316\273\316\273\316\267\316\275\316\271\316\272\316\254\t\004\b", + "English\tEnglish\t\004\t", + "Spanish\tespa\303\261ol\t\004\n", + "Finnish\tsuomi\t\004\v", + "French\tfran\303\247ais\t\004\f", + "Hebrew\t\327\242\327\221\327\250\327\231\327\252\t\004\r", + "Hungarian\tMagyar\t\004\016", + "Icelandic\t\303\255slenska\t\004\017", + "Italian\titaliano\t\004\020", + "Japanese\t\346\227\245\346\234\254\350\252\236\t\004\021", + "Korean\t\355\225\234\352\265\255\354\226\264\t\004\022", + "Dutch\tNederlands\t\004\023", + "Norwegian (Bokm\303\245l)\tnorsk (bokm\303\245l)\t\004\024", + "Polish\tpolski\t\004\025", + "Portuguese\tPortugu\303\252s\t\004\026", + "Romanian\trom\303\242n\304\203\t\004\030", + "Russian\t\321\200\321\203\321\201\321\201\320\272\320\270\320\271\t\004\031", + "Croatian\thrvatski\t\004\032", + "Slovak\tsloven\304\215ina\t\004\033", + "Albanian\tshqipe\t\004\034", + "Swedish\tsvenska\t\004\035", + "Thai\t\340\271\204\340\270\227\340\270\242\t\004\036", + "Turkish\tT\303\274rk\303\247e\t\004\037", + "Urdu\t\330\247\331\217\330\261\330\257\331\210\t\004 ", + "Indonesian\tBahasa Indonesia\t\004!", + "Ukrainian\t\321\203\320\272\321\200\320\260\321\227\320\275\321\214\321\201\320\272\320\260\t\004\"", + "Belarusian\t\320\221\320\265\320\273\320\260\321\200\321\203\321\201\320\272\321\226\t\004#", + "Slovenian\tslovenski\t\004$", + "Estonian\teesti\t\004%", + "Latvian\tlatvie\305\241u\t\004&", + "Lithuanian\tlietuvi\305\263\t\004'", + "Farsi\t\331\201\330\247\330\261\330\263\331\211\t\004)", + "Vietnamese\tTi\303\252\314\201ng Vi\303\252\314\243t Nam\t\004*", + "Armenian\t\325\200\325\241\325\265\325\245\326\200\325\245\325\266\t\004+", + "Azeri (Latin)\tAz\311\231rbaycan\302\255\304\261l\304\261\t\004,", + "Basque\teuskara\t\004-", + "FYRO Macedonian\t\320\274\320\260\320\272\320\265\320\264\320\276\320\275\321\201\320\272\320\270 \321\230\320\260\320\267\320\270\320\272\t\004/", + "Afrikaans\tAfrikaans\t\0046", + "Georgian\t\341\203\245\341\203\220\341\203\240\341\203\227\341\203\243\341\203\232\341\203\230\t\0047", + "Faroese\tf\303\270royskt\t\0048", + "Hindi\t\340\244\271\340\244\277\340\244\202\340\244\246\340\245\200\t\0049", + "Malay\tBahasa Malaysia\t\004>", + "Kazakh\t\322\232\320\260\320\267\320\260\322\233\t\004?", + "Kyrgyz\t\320\232\321\213\321\200\320\263\321\213\320\267\t\004@", + "Swahili\tKiswahili\t\004A", + "Uzbek (Latin)\tU'zbek\t\004C", + "Tatar\t\320\242\320\260\321\202\320\260\321\200\t\004D", + "Punjabi\t\340\250\252\340\251\260\340\250\234\340\250\276\340\250\254\340\251\200\t\004F", + "Gujarati\t\340\252\227\340\253\201\340\252\234\340\252\260\340\252\276\340\252\244\340\253\200\t\004G", + "Tamil\t\340\256\244\340\256\256\340\256\277\340\256\264\340\257\215\t\004I", + "Telugu\t\340\260\244\340\261\206\340\260\262\340\261\201\340\260\227\340\261\201\t\004J", + "Kannada\t\340\262\225\340\262\250\340\263\215\340\262\250\340\262\241\t\004K", + "Marathi\t\340\244\256\340\244\260\340\244\276\340\244\240\340\245\200\t\004N", + "Sanskrit\t\340\244\270\340\244\202\340\244\270\340\245\215\340\244\225\340\245\203\340\244\244\t\004O", + "Mongolian\t\320\234\320\276\320\275\320\263\320\276\320\273\302\240\321\205\321\215\320\273\t\004P", + "Galician\tgalego\t\004V", + "Konkani\t\340\244\225\340\245\213\340\244\202\340\244\225\340\244\243\340\245\200\t\004W", + "Syriac\t\334\243\334\230\334\252\334\235\334\235\334\220\t\004Z", + "Divehi\t\336\213\336\250\336\210\336\254\336\200\336\250\336\204\336\246\336\220\336\260\t\004e", + "Arabic\t\330\247\331\204\330\271\330\261\330\250\331\212\330\251\t\b\001", + "Chinese\t\344\270\255\346\226\207(\347\256\200\344\275\223)\t\b\004", + "German\tDeutsch\t\b\a", + "English\tEnglish\t\b\t", + "Spanish\tEspa\303\261ol\t\b\n", + "French\tfran\303\247ais\t\b\f", + "Italian\titaliano\t\b\020", + "Dutch\tNederlands\t\b\023", + "Norwegian (Nynorsk)\tnorsk (nynorsk)\t\b\024", + "Portuguese\tportugu\303\252s\t\b\026", + "Serbian (Latin)\tsrpski\t\b\032", + "Swedish\tsvenska\t\b\035", + "Azeri (Cyrillic)\t\320\220\320\267\323\231\321\200\320\261\320\260\321\230\322\271\320\260\320\275\t\b,", + "Malay\tBahasa Malaysia\t\b>", + "Uzbek (Cyrillic)\t\320\216\320\267\320\261\320\265\320\272\t\bC", + "Arabic\t\330\247\331\204\330\271\330\261\330\250\331\212\330\251\t\f\001", + "Chinese\t\344\270\255\346\226\207(\347\271\201\351\253\224)\t\f\004", + "German\tDeutsch\t\f\a", + "English\tEnglish\t\f\t", + "Spanish\tespa\303\261ol\t\f\n", + "French\tfran\303\247ais\t\f\f", + "Serbian (Cyrillic)\t\321\201\321\200\320\277\321\201\320\272\320\270\t\f\032", + "Arabic\t\330\247\331\204\330\271\330\261\330\250\331\212\330\251\t\020\001", + "Chinese\t\344\270\255\346\226\207(\347\256\200\344\275\223)\t\020\004", + "German\tDeutsch\t\020\a", + "English\tEnglish\t\020\t", + "Spanish\tEspa\303\261ol\t\020\n", + "French\tfran\303\247ais\t\020\f", + "Arabic\t\330\247\331\204\330\271\330\261\330\250\331\212\330\251\t\024\001", + "Chinese\t\344\270\255\346\226\207(\347\256\200\344\275\223)\t\024\004", + "German\tDeutsch\t\024\a", + "English\tEnglish\t\024\t", + "Spanish\tEspa\303\261ol\t\024\n", + "French\tfran\303\247ais\t\024\f", + "Arabic\t\330\247\331\204\330\271\330\261\330\250\331\212\330\251\t\030\001", + "English\tEnglish\t\030\t", + "Spanish\tEspa\303\261ol\t\030\n", + "French\tfran\303\247ais\t\030\f", + "Arabic\t\330\247\331\204\330\271\330\261\330\250\331\212\330\251\t\034\001", + "English\tEnglish\t\034\t", + "Spanish\tEspa\303\261ol\t\034\n", + "Arabic\t\330\247\331\204\330\271\330\261\330\250\331\212\330\251\t \001", + "English\tEnglish\t \t", + "Spanish\tEspa\303\261ol\t \n", + "Arabic\t\330\247\331\204\330\271\330\261\330\250\331\212\330\251\t$\001", + "English\tEnglish\t$\t", + "Spanish\tEspa\303\261ol\t$\n", + "Arabic\t\330\247\331\204\330\271\330\261\330\250\331\212\330\251\t(\001", + "English\tEnglish\t(\t", + "Spanish\tEspa\303\261ol\t(\n", + "Arabic\t\330\247\331\204\330\271\330\261\330\250\331\212\330\251\t,\001", + "English\tEnglish\t,\t", + "Spanish\tEspa\303\261ol\t,\n", + "Arabic\t\330\247\331\204\330\271\330\261\330\250\331\212\330\251\t0\001", + "English\tEnglish\t0\t", + "Spanish\tEspa\303\261ol\t0\n", + "Arabic\t\330\247\331\204\330\271\330\261\330\250\331\212\330\251\t4\001", + "English\tEnglish\t4\t", + "Spanish\tEspa\303\261ol\t4\n", + "Arabic\t\330\247\331\204\330\271\330\261\330\250\331\212\330\251\t8\001", + "Spanish\tEspa\303\261ol\t8\n", + "Arabic\t\330\247\331\204\330\271\330\261\330\250\331\212\330\251\t<\001", + "Spanish\tEspa\303\261ol\t<\n", + "Arabic\t\330\247\331\204\330\271\330\261\330\250\331\212\330\251\t@\001", + "Spanish\tEspa\303\261ol\t@\n", + "Spanish\tEspa\303\261ol\tD\n", + "Spanish\tEspa\303\261ol\tH\n", + "Spanish\tEspa\303\261ol\tL\n", + "Spanish\tEspa\303\261ol\tP\n", + "Croatian\thrvatski\t\020\032", + "Bosnian\tbosanski\t\024\032", + "Serbian (Latin)\tsrpski\t\030\032", + "Welsh\tCymraeg\t\004R", + "Maori\tReo M\304\201ori\t\004\201", + "Maltese\tMalti\t\004:", + "Quechua\trunasimi\t\004k", + "Quechua\trunasimi\t\bk", + "Quechua\trunasimi\t\fk", + "Tswana\tSetswana\t\0042", + "Xhosa\tisiXhosa\t\0044", + "Zulu\tisiZulu\t\0045", + "Northern Sotho\tSesotho sa Leboa\t\004l", + "Sami (Northern)\tdavvis\303\241megiella\t\004;", + "Sami (Northern)\tdavvis\303\241megiella\t\b;", + "Sami (Northern)\tdavvis\303\241megiella\t\f;", + "Sami (Lule)\tjulevus\303\241megiella\t\020;", + "Sami (Lule)\tjulevus\303\241megiella\t\024;", + "Sami (Southern)\t\303\245arjelsaemiengiele\t\030;", + "Sami (Southern)\t\303\245arjelsaemiengiele\t\034;", + "Sami (Skolt)\ts\303\244\303\244m\302\264\307\251i\303\265ll\t ;", + "Sami (Inari)\ts\303\244mikiel\303\242\t$;", + "Serbian (Cyrillic)\t\321\201\321\200\320\277\321\201\320\272\320\270\t\034\032", + "Bosnian (Cyrillic)\t\320\261\320\276\321\201\320\260\320\275\321\201\320\272\320\270\t \032", + "Filipino\tFilipino\t\004d", + "Luxembourgish\tL\303\253tzebuergesch\t\004n", + "Pashto\t\331\276\332\232\330\252\331\210\t\004c", + "Frisian\tFrysk\t\004b", + "Mapudungun\tMapudungun\t\004z", + "Nepali\t\340\244\250\340\245\207\340\244\252\340\244\276\340\244\262\340\245\200\t\004a", + "Inuktitut (Latin)\tInuktitut (Kanatami)\t\b]", + "Irish\tGaeilge\t\b<", + "Mohawk\tKanien'k\303\251ha\t\004|", + "Romansh\tRumantsch\t\004\027", + "Bengali\t\340\246\254\340\246\276\340\246\242\340\246\262\340\246\276\t\004E", + "Malayalam\t\340\264\256\340\264\262\340\264\257\340\264\276\340\264\263\340\264\202\t\004L", +}; + +}; diff --git a/uppsrc/TCore/CalcBasic.cpp b/uppsrc/TCore/CalcBasic.cpp index 9c7706cff..056b165fa 100644 --- a/uppsrc/TCore/CalcBasic.cpp +++ b/uppsrc/TCore/CalcBasic.cpp @@ -1266,8 +1266,7 @@ FDECLP(find, SS, GroupString) static inline bool ClikeSS(WString s, WString m) { - One wc = GetLanguageInfo().GetWildcardCompare(m); - return wc && wc->Matches(s); + return WildcardCompare(m).Matches(s); } FDECLP(like, SS, GroupString) diff --git a/uppsrc/TCore/database.cpp b/uppsrc/TCore/database.cpp index fb7a8a232..980a3b9eb 100644 --- a/uppsrc/TCore/database.cpp +++ b/uppsrc/TCore/database.cpp @@ -2090,11 +2090,11 @@ DataSet DataTableColumn::GetRange(Value min, Value max) DataSet DataTableColumn::GetLike(WString mask) { Vector done = row_index->GetIndex(); - One wcc = GetLanguageInfo().GetWildcardCompare(mask); + WildcardCompare wcc(mask); int *d = done.Begin(); for(const int *s = done.Begin(), *e = done.End(); s < e; s++) { WString value = Get(*s); - if(wcc->Matches(value)) + if(wcc.Matches(value)) *d++ = *s; } done.SetCount(d - done.Begin()); diff --git a/uppsrc/TCore/help.cpp b/uppsrc/TCore/help.cpp index e2ff1dbf0..c62ca0909 100644 --- a/uppsrc/TCore/help.cpp +++ b/uppsrc/TCore/help.cpp @@ -71,9 +71,6 @@ void HelpTopicTouchSeq() { help_topic_seq++; } void HelpTopicInfo::Set(int lang, String tit_, String txt_, String tmo_) { String tmo = tmo_, tit = tit_, txt = txt_; - int cs = GetLangCharset(lang); -// tit.SetCharset(cs); -// txt.SetCharset(cs); int f = language.Find(lang); if(IsNull(tit) && IsNull(txt)) { diff --git a/uppsrc/TCore/util.cpp b/uppsrc/TCore/util.cpp index c7a908d20..ee56d4b61 100644 --- a/uppsrc/TCore/util.cpp +++ b/uppsrc/TCore/util.cpp @@ -1305,4 +1305,36 @@ String GetRelativePath(String fn, String pathlist, String curdir) return fn.Mid(GetRelativePathPos(fn, curdir)); } +WildcardCompare::WildcardCompare(const wchar *templ) +{ + raw_templ = templ; + cvt_templ = ToUpper(raw_templ); +} + +bool WildcardCompare::RawMatches(const wchar *s, const wchar *templ) const +{ + for(;;) + switch(*templ++) + { + case 0: return true; + case '.': if(*templ == 0) return *s == 0; // force end of string + case '?': if(*s++ == 0) return false; break; + case '*': + do + if(RawMatches(s, templ)) + return true; + while(*s++); + return false; + case '\\': + if(*templ == 0 || *templ++ != *s++) + return false; + break; + default: + if(templ[-1] != ToUpper(*s++)) + return false; + break; + } + return true; +} + END_UPP_NAMESPACE diff --git a/uppsrc/TCore/util.h b/uppsrc/TCore/util.h index b71fd0407..5727fbe55 100644 --- a/uppsrc/TCore/util.h +++ b/uppsrc/TCore/util.h @@ -273,4 +273,16 @@ inline unsigned CalcGray(byte r, byte g, byte b) { return b * 26 + g * 153 + r * inline unsigned CalcGray(const byte *p) { return p[0] * 26 + p[1] * 153 + p[2] * 77; } inline unsigned CalcGray(Color c) { return c.GetB() * 26 + c.GetG() * 153 + c.GetR() * 77; } +class WildcardCompare { + WString raw_templ; + WString cvt_templ; + + bool RawMatches(const wchar *s, const wchar *templ) const; + +public: + WildcardCompare(const wchar *templ); + + bool Matches(const wchar *s) const { return raw_templ.GetCount() == 0 || RawMatches(s, cvt_templ); } +}; + END_UPP_NAMESPACE