mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-05-31 22:04:04 -06:00
Core: LanguageInfo completely refactored
git-svn-id: svn://ultimatepp.org/upp/trunk@1810 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
parent
acd590d240
commit
4e19e35baa
9 changed files with 956 additions and 1005 deletions
|
|
@ -107,6 +107,7 @@ file
|
|||
t.h,
|
||||
Lang.h,
|
||||
Lang.cpp,
|
||||
LangInfo.cpp,
|
||||
lcid.txt,
|
||||
"Other files" readonly separator,
|
||||
Parser.h,
|
||||
|
|
|
|||
|
|
@ -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<int, LCID> 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::WildcardCompare> LanguageInfo::GetWildcardCompare(const wchar *wildcard_text) const
|
||||
{
|
||||
return new DefaultWildcardCompare(wildcard_text);
|
||||
}
|
||||
|
||||
typedef ArrayMap<int, LanguageInfo> LanguageInfoMap;
|
||||
GLOBAL_VAR(LanguageInfoMap, LanguageInfo::Map)
|
||||
static StaticMutex sMapMutex;
|
||||
|
||||
void LanguageInfo::Register(One<LanguageInfo> 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<WildcardCompare> 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<LanguageInfo::WildcardCompare> 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
|
||||
|
|
|
|||
|
|
@ -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<WildcardCompare> GetWildcardCompare(const wchar *wildcard_text) const;
|
||||
|
||||
static ArrayMap<int, LanguageInfo>& Map();
|
||||
static void Register(One<LanguageInfo> 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 ----------------
|
||||
|
||||
|
|
|
|||
869
uppsrc/Core/LangInfo.cpp
Normal file
869
uppsrc/Core/LangInfo.cpp
Normal file
|
|
@ -0,0 +1,869 @@
|
|||
#include "Core.h"
|
||||
|
||||
#ifdef PLATFORM_WIN32
|
||||
#include <wingdi.h>
|
||||
#include <winnls.h>
|
||||
#endif
|
||||
#ifdef PLATFORM_POSIX
|
||||
#include <locale.h>
|
||||
#include <langinfo.h>
|
||||
#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<int, LanguageInfo>& LangMap()
|
||||
{
|
||||
static ArrayMap<int, LanguageInfo> x;
|
||||
return x;
|
||||
}
|
||||
|
||||
StaticMutex sLanguageInfoMutex;
|
||||
|
||||
const LanguageInfo& GetLanguageInfo(int lang)
|
||||
{
|
||||
Mutex::Lock __(sLanguageInfoMutex);
|
||||
ArrayMap<int, LanguageInfo>& 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<int, LanguageInfo>& 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",
|
||||
};
|
||||
|
||||
};
|
||||
|
|
@ -1266,8 +1266,7 @@ FDECLP(find, SS, GroupString)
|
|||
|
||||
static inline bool ClikeSS(WString s, WString m)
|
||||
{
|
||||
One<LanguageInfo::WildcardCompare> wc = GetLanguageInfo().GetWildcardCompare(m);
|
||||
return wc && wc->Matches(s);
|
||||
return WildcardCompare(m).Matches(s);
|
||||
}
|
||||
|
||||
FDECLP(like, SS, GroupString)
|
||||
|
|
|
|||
|
|
@ -2090,11 +2090,11 @@ DataSet DataTableColumn::GetRange(Value min, Value max)
|
|||
DataSet DataTableColumn::GetLike(WString mask)
|
||||
{
|
||||
Vector<int> done = row_index->GetIndex();
|
||||
One<LanguageInfo::WildcardCompare> 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());
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue