#include "Locale.h"
#if defined VCZH_MSVC
#include <Windows.h>
#elif defined VCZH_GCC
#include <stdio.h>
#include <ctype.h>
#include <wctype.h>
#include <wchar.h>
#endif
namespace
{
using
namespace
collections
;
#if defined VCZH_MSVC
extern
(
const
&
);
BOOL CALLBACK Locale_EnumLocalesProcEx(
_In_ LPWSTR lpLocaleString,
)
{
((
<
>*)
)->
(
(
));
}
BOOL CALLBACK Locale_EnumDateFormatsProcExEx(
_In_ LPWSTR lpDateFormatString,
)
{
((
<
>*)
)->
(
);
}
BOOL CALLBACK EnumTimeFormatsProcEx(
_In_ LPWSTR lpTimeFormatString,
)
{
((
<
>*)
)->
(
);
}
(
const
&
,
const
&
,
)
{
int length=LCMapStringEx(localeName.Buffer(), flag, input.Buffer(), (int)input.Length()+1, NULL, 0, NULL, NULL, NULL);
int
=
(
.
(),
,
.
(), (
int
)
.
()+
1
,
0
,
0
,
0
,
0
,
0
);
<
wchar_t
>
(
length
);
LCMapStringEx(localeName.Buffer(), flag, input.Buffer(), (int)input.Length()+1, &buffer[0], (int)buffer.Count(), NULL, NULL, NULL);
(
.
(),
,
.
(), (
int
)
.
()+
1
, &
buffer
0
], (
int
)
buffer
.
(),
0
,
0
,
0
);
return
&
buffer
0
];
}
(
::
)
{
=
0
;
if(normalization&Locale::IgnoreCase) result|=NORM_IGNORECASE;
if
(
&
::
)
result
|=
0x00000001
;
if(normalization&Locale::IgnoreCaseLinguistic) result|=NORM_IGNORECASE | NORM_LINGUISTIC_CASING;
if
(
&
::
)
result
|=
0x00000001
|
0x08000000
;
if(normalization&Locale::IgnoreKanaType) result|=NORM_IGNOREKANATYPE;
if
(
&
::
)
result
|=
0x00010000
;
if(normalization&Locale::IgnoreNonSpace) result|=NORM_IGNORENONSPACE;
if
(
&
::
)
result
|=
0x00000002
;
if(normalization&Locale::IgnoreSymbol) result|=NORM_IGNORESYMBOLS;
if
(
&
::
)
result
|=
0x00000004
;
if(normalization&Locale::IgnoreWidth) result|=NORM_IGNOREWIDTH;
if
(
&
::
)
result
|=
0x00020000
;
if(normalization&Locale::DigitsAsNumbers) result|=SORT_DIGITSASNUMBERS;
if
(
&
::
)
result
|=
0x00000008
;
if(normalization&Locale::StringSoft) result|=SORT_STRINGSORT;
if
(
&
::
)
result
|=
0x00001000
;
return
result
;
}
#endif
::
(
const
&
)
:localeName(
)
{
}
::
()
{
}
::
()
{
#if defined VCZH_MSVC
return Locale(LOCALE_NAME_INVARIANT);
#elif defined VCZH_GCC
return Locale(L"");
#endif
}
::
()
{
#if defined VCZH_MSVC
wchar_t buffer[LOCALE_NAME_MAX_LENGTH+1]={0};
GetSystemDefaultLocaleName(buffer, LOCALE_NAME_MAX_LENGTH);
GetSystemDefaultLocaleName
(
buffer
,
85
);
return
(
buffer
);
#elif defined VCZH_GCC
return Locale(L"en-US");
#endif
}
::
()
{
#if defined VCZH_MSVC
wchar_t buffer[LOCALE_NAME_MAX_LENGTH+1]={0};
GetUserDefaultLocaleName(buffer, LOCALE_NAME_MAX_LENGTH);
return
(
buffer
);
#elif defined VCZH_GCC
return Locale(L"en-US");
#endif
}
void
::
(
collections
::
<
>&
)
{
#if defined VCZH_MSVC
EnumSystemLocalesEx(&Locale_EnumLocalesProcEx, LOCALE_ALL, (LPARAM)&locales, NULL);
#elif defined VCZH_GCC
locales.Add(Locale(L"en-US"));
#endif
}
const
&
::
()
const
{
return
;
}
void
::
(
collections
::
<
>&
)
const
{
#if defined VCZH_MSVC
EnumDateFormatsExEx(&Locale_EnumDateFormatsProcExEx, localeName.Buffer(), DATE_SHORTDATE, (LPARAM)&formats);
(&
Locale_EnumDateFormatsProcExEx
,
.
(),
0x00000001
, (
)&
);
#elif defined VCZH_GCC
formats.Add(L"MM/dd/yyyy");
formats.Add(L"yyyy-MM-dd");
#endif
}
void
::
(
collections
::
<
>&
)
const
{
#if defined VCZH_MSVC
EnumDateFormatsExEx(&Locale_EnumDateFormatsProcExEx, localeName.Buffer(), DATE_LONGDATE, (LPARAM)&formats);
(&
Locale_EnumDateFormatsProcExEx
,
.
(),
0x00000002
, (
)&
);
#elif defined VCZH_GCC
formats.Add(L"dddd, dd MMMM yyyy");
#endif
}
void
::
(
collections
::
<
>&
)
const
{
#if defined VCZH_MSVC
EnumDateFormatsExEx(&Locale_EnumDateFormatsProcExEx, localeName.Buffer(), DATE_YEARMONTH, (LPARAM)&formats);
(&
Locale_EnumDateFormatsProcExEx
,
.
(),
0x00000008
, (
)&
);
#elif defined VCZH_GCC
formats.Add(L"yyyy MMMM");
#endif
}
void
::
(
collections
::
<
>&
)
const
{
#if defined VCZH_MSVC
(&
,
.
(),
0
, (
)&
);
#elif defined VCZH_GCC
formats.Add(L"HH:mm:ss");
#endif
}
void
::
(
collections
::
<
>&
)
const
{
#if defined VCZH_MSVC
EnumTimeFormatsEx(&EnumTimeFormatsProcEx, localeName.Buffer(), TIME_NOSECONDS, (LPARAM)&formats);
(&
,
.
(),
0x00000002
, (
)&
);
#elif defined VCZH_GCC
formats.Add(L"HH:mm");
formats.Add(L"hh:mm tt");
#endif
}
::
(
const
&
,
)
const
{
#if defined VCZH_MSVC
=
(
);
int length=GetDateFormatEx(localeName.Buffer(), 0, &st, format.Buffer(), NULL, 0, NULL);
int
=
(
.
(),
0
, &
st
,
.
(),
0
,
0
,
0
);
if
(
length
==
0
)
return
L""
;
<
wchar_t
>
(
length
);
GetDateFormatEx(localeName.Buffer(), 0, &st, format.Buffer(), &buffer[0], (int)buffer.Count(), NULL);
(
.
(),
0
, &
st
,
.
(), &
buffer
0
], (
int
)
buffer
.
(),
0
);
return
&
buffer
0
];
#elif defined VCZH_GCC
/*
auto df = L"yyyy,MM,MMM,MMMM,dd,ddd,dddd";
auto ds = L"2000,01,Jan,January,02,Sun,Sunday";
auto tf = L"hh,HH,mm,ss,tt";
auto ts = L"01,13,02,03,PM";
*/
WString result;
const wchar_t* reading = format.Buffer();
while (*reading)
{
if (wcsncmp(reading, L"yyyy", 4) == 0)
{
WString fragment = itow(date.year);
while (fragment.Length() < 4) fragment = L"0" + fragment;
result += fragment;
reading += 4;
}
else if (wcsncmp(reading, L"MMMM", 4) == 0)
{
result += GetLongMonthName(date.month);
reading += 4;
}
else if (wcsncmp(reading, L"MMM", 3) == 0)
{
result += GetShortMonthName(date.month);
reading += 3;
}
else if (wcsncmp(reading, L"MM", 2) == 0)
{
WString fragment = itow(date.month);
while (fragment.Length() < 2) fragment = L"0" + fragment;
result += fragment;
reading += 2;
}
else if (wcsncmp(reading, L"dddd", 4) == 0)
{
result += GetLongDayOfWeekName(date.dayOfWeek);
reading += 4;
}
else if (wcsncmp(reading, L"ddd", 3) == 0)
{
result += GetShortDayOfWeekName(date.dayOfWeek);
reading += 3;
}
else if (wcsncmp(reading, L"dd", 2) == 0)
{
WString fragment = itow(date.day);
while (fragment.Length() < 2) fragment = L"0" + fragment;
result += fragment;
reading += 2;
}
else if (wcsncmp(reading, L"hh", 2) == 0)
{
WString fragment = itow(date.hour > 12 ? date.hour - 12 : date.hour);
while (fragment.Length() < 2) fragment = L"0" + fragment;
result += fragment;
reading += 2;
}
else if (wcsncmp(reading, L"HH", 2) == 0)
{
WString fragment = itow(date.hour);
while (fragment.Length() < 2) fragment = L"0" + fragment;
result += fragment;
reading += 2;
}
else if (wcsncmp(reading, L"mm", 2) == 0)
{
WString fragment = itow(date.minute);
while (fragment.Length() < 2) fragment = L"0" + fragment;
result += fragment;
reading += 2;
}
else if (wcsncmp(reading, L"ss", 2) == 0)
{
WString fragment = itow(date.second);
while (fragment.Length() < 2) fragment = L"0" + fragment;
result += fragment;
reading += 2;
}
else if (wcsncmp(reading, L"tt", 2) == 0)
{
result += date.hour > 12 ? L"PM" : L"AM";
reading += 2;
}
else
{
result += *reading;
reading++;
}
}
return result;
#endif
}
::
(
const
&
,
)
const
{
#if defined VCZH_MSVC
=
(
);
int length=GetTimeFormatEx(localeName.Buffer(), 0, &st, format.Buffer(), NULL, 0);
int
=
(
.
(),
0
, &
st
,
.
(),
0
,
0
);
if
(
length
==
0
)
return
L""
;
<
wchar_t
>
(
length
);
(
.
(),
0
, &
st
,
.
(),&
buffer
0
], (
int
)
buffer
.
());
return
&
buffer
0
];
#elif defined VCZH_GCC
return FormatDate(format, time);
#endif
}
::
(
const
&
)
const
{
#ifdef VCZH_MSVC
int length=GetNumberFormatEx(localeName.Buffer(), 0, number.Buffer(), NULL, NULL, 0);
int
=
(
.
(),
0
,
.
(),
0
,
0
,
0
);
if
(
length
==
0
)
return
L""
;
<
wchar_t
>
(
length
);
GetNumberFormatEx(localeName.Buffer(), 0, number.Buffer(), NULL, &buffer[0], (int)buffer.Count());
(
.
(),
0
,
.
(),
0
, &
buffer
0
], (
int
)
buffer
.
());
return
&
buffer
0
];
#elif defined VCZH_GCC
return number;
#endif
}
::
(
const
&
)
const
{
#ifdef VCZH_MSVC
int length=GetCurrencyFormatEx(localeName.Buffer(), 0, currency.Buffer(), NULL, NULL, 0);
int
=
(
.
(),
0
,
.
(),
0
,
0
,
0
);
if
(
length
==
0
)
return
L""
;
<
wchar_t
>
(
length
);
GetCurrencyFormatEx(localeName.Buffer(), 0, currency.Buffer(), NULL, &buffer[0], (int)buffer.Count());
(
.
(),
0
,
.
(),
0
, &
buffer
0
], (
int
)
buffer
.
());
return
&
buffer
0
];
#elif defined VCZH_GCC
return currency;
#endif
}
::
(
)
const
{
#if defined VCZH_MSVC
return
(
L"ddd"
,
::
(
2000
,
1
,
2
+
));
#elif defined VCZH_GCC
switch(dayOfWeek)
{
case 0: return L"Sun";
case 1: return L"Mon";
case 2: return L"Tue";
case 3: return L"Wed";
case 4: return L"Thu";
case 5: return L"Fri";
case 6: return L"Sat";
}
return L"";
#endif
}
::
(
)
const
{
#if defined VCZH_MSVC
return
(
L"dddd"
,
::
(
2000
,
1
,
2
+
));
#elif defined VCZH_GCC
switch(dayOfWeek)
{
case 0: return L"Sunday";
case 1: return L"Monday";
case 2: return L"Tuesday";
case 3: return L"Wednesday";
case 4: return L"Thursday";
case 5: return L"Friday";
case 6: return L"Saturday";
}
return L"";
#endif
}
::
(
)
const
{
#if defined VCZH_MSVC
return
(
L"MMM"
,
::
(
2000
,
,
1
));
#elif defined VCZH_GCC
switch(month)
{
case 1: return L"Jan";
case 2: return L"Feb";
case 3: return L"Mar";
case 4: return L"Apr";
case 5: return L"May";
case 6: return L"Jun";
case 7: return L"Jul";
case 8: return L"Aug";
case 9: return L"Sep";
case 10: return L"Oct";
case 11: return L"Nov";
case 12: return L"Dec";
}
return L"";
#endif
}
::
(
)
const
{
#if defined VCZH_MSVC
return
(
L"MMMM"
,
::
(
2000
,
,
1
));
#elif defined VCZH_GCC
switch(month)
{
case 1: return L"January";
case 2: return L"February";
case 3: return L"March";
case 4: return L"April";
case 5: return L"May";
case 6: return L"June";
case 7: return L"July";
case 8: return L"August";
case 9: return L"September";
case 10: return L"October";
case 11: return L"November";
case 12: return L"December";
}
return L"";
#endif
}
#ifdef VCZH_MSVC
::
(
const
&
)
const
{
return Transform(localeName, str, LCMAP_FULLWIDTH);
}
::
(
const
&
)
const
{
return Transform(localeName, str, LCMAP_HALFWIDTH);
}
::
(
const
&
)
const
{
return Transform(localeName, str, LCMAP_HIRAGANA);
}
::
(
const
&
)
const
{
return Transform(localeName, str, LCMAP_KATAKANA);
}
#endif
::
(
const
&
)
const
{
#if defined VCZH_MSVC
return Transform(localeName, str, LCMAP_LOWERCASE);
#elif defined VCZH_GCC
return wlower(str);
#endif
}
::
(
const
&
)
const
{
#if defined VCZH_MSVC
return Transform(localeName, str, LCMAP_UPPERCASE);
#elif defined VCZH_GCC
return wupper(str);
#endif
}
::
(
const
&
)
const
{
#if defined VCZH_MSVC
return Transform(localeName, str, LCMAP_LOWERCASE | LCMAP_LINGUISTIC_CASING);
return
(
,
,
0x00000100
|
0x01000000
);
#elif defined VCZH_GCC
return wlower(str);
#endif
}
::
(
const
&
)
const
{
#if defined VCZH_MSVC
return Transform(localeName, str, LCMAP_UPPERCASE | LCMAP_LINGUISTIC_CASING);
return
(
,
,
0x00000200
|
0x01000000
);
#elif defined VCZH_GCC
return wupper(str);
#endif
}
#ifdef VCZH_MSVC
::
(
const
&
)
const
{
return Transform(localeName, str, LCMAP_SIMPLIFIED_CHINESE);
}
::
(
const
&
)
const
{
return Transform(localeName, str, LCMAP_TRADITIONAL_CHINESE);
}
::
(
const
&
)
const
{
return Transform(localeName, str, LCMAP_TITLECASE);
}
#endif
::
(
const
&
,
const
&
,
)
const
{
#if defined VCZH_MSVC
switch(CompareStringEx(localeName.Buffer(), TranslateNormalization(normalization), s1.Buffer(), (int)s1.Length(), s2.Buffer(), (int)s2.Length(), NULL, NULL, NULL))
switch
(
(
.
(),
(
),
.
(), (
int
)
.
(),
.
(), (
int
)
.
(),
0
,
0
,
0
))
{
case CSTR_LESS_THAN: return -1;
case CSTR_GREATER_THAN: return 1;
default
:
return
0
;
}
#elif defined VCZH_GCC
switch(normalization)
{
case Normalization::None:
return wcscmp(s1.Buffer(), s2.Buffer());
case Normalization::IgnoreCase:
return wcscasecmp(s1.Buffer(), s2.Buffer());
default:
return 0;
}
#endif
}
::
(
const
&
,
const
&
)
const
{
#if defined VCZH_MSVC
switch(CompareStringOrdinal(s1.Buffer(), (int)s1.Length(), s2.Buffer(), (int)s2.Length(), FALSE))
switch
(
(
.
(), (
int
)
.
(),
.
(), (
int
)
.
(),
0
))
{
case CSTR_LESS_THAN: return -1;
case CSTR_GREATER_THAN: return 1;
default
:
return
0
;
}
#elif defined VCZH_GCC
return wcscmp(s1.Buffer(), s2.Buffer());
#endif
}
::
(
const
&
,
const
&
)
const
{
#if defined VCZH_MSVC
switch(CompareStringOrdinal(s1.Buffer(), (int)s1.Length(), s2.Buffer(), (int)s2.Length(), TRUE))
switch
(
(
.
(), (
int
)
.
(),
.
(), (
int
)
.
(),
1
))
{
case CSTR_LESS_THAN: return -1;
case CSTR_GREATER_THAN: return 1;
default
:
return
0
;
}
#elif defined VCZH_GCC
return wcscasecmp(s1.Buffer(), s2.Buffer());
#endif
}
collections
::
<
,
>
::
(
const
&
,
const
&
,
)
const
{
#if defined VCZH_MSVC
int
=
0
;
int result=FindNLSStringEx(localeName.Buffer(), FIND_FROMSTART | TranslateNormalization(normalization), text.Buffer(), (int)text.Length(), find.Buffer(), (int)find.Length(), &length, NULL, NULL, NULL);
int
=
(
.
(),
0x00400000
|
(
),
.
(), (
int
)
.
(),
.
(), (
int
)
.
(), &
length
,
0
,
0
,
0
);
return
result
==-
1
?
<
,
>(-
1
,
0
):
<
,
>(
result
,
length
);
#elif defined VCZH_GCC
if(text.Length() < find.Length() || find.Length() == 0)
{
return Pair<vint, vint>(-1, 0);
}
const wchar_t* result = 0;
switch(normalization)
{
case Normalization::None:
{
const wchar_t* reading = text.Buffer();
while(*reading)
{
if (wcsncmp(reading, find.Buffer(), find.Length())==0)
{
result = reading;
break;
}
reading++;
}
}
break;
case Normalization::IgnoreCase:
{
const wchar_t* reading = text.Buffer();
while(*reading)
{
if (wcsncasecmp(reading, find.Buffer(), find.Length())==0)
{
result = reading;
break;
}
reading++;
}
}
break;
}
return result == nullptr ? Pair<vint, vint>(-1, 0) : Pair<vint, vint>(result - text.Buffer(), find.Length());
#endif
}
collections
::
<
,
>
::
(
const
&
,
const
&
,
)
const
{
#if defined VCZH_MSVC
int
=
0
;
int result=FindNLSStringEx(localeName.Buffer(), FIND_FROMEND | TranslateNormalization(normalization), text.Buffer(), (int)text.Length(), find.Buffer(), (int)find.Length(), &length, NULL, NULL, NULL);
int
=
(
.
(),
0x00800000
|
(
),
.
(), (
int
)
.
(),
.
(), (
int
)
.
(), &
length
,
0
,
0
,
0
);
return
result
==-
1
?
<
,
>(-
1
,
0
):
<
,
>(
result
,
length
);
#elif defined VCZH_GCC
if(text.Length() < find.Length() || find.Length() == 0)
{
return Pair<vint, vint>(-1, 0);
}
const wchar_t* result = 0;
switch(normalization)
{
case Normalization::None:
{
const wchar_t* reading = text.Buffer();
while(*reading)
{
if (wcsncmp(reading, find.Buffer(), find.Length())==0)
{
result = reading;
}
reading++;
}
}
break;
case Normalization::IgnoreCase:
{
const wchar_t* reading = text.Buffer();
while(*reading)
{
if (wcsncasecmp(reading, find.Buffer(), find.Length())==0)
{
result = reading;
}
reading++;
}
}
break;
}
return result == nullptr ? Pair<vint, vint>(-1, 0) : Pair<vint, vint>(result - text.Buffer(), find.Length());
#endif
}
bool
::
(
const
&
,
const
&
,
)
const
{
#if defined VCZH_MSVC
int result=FindNLSStringEx(localeName.Buffer(), FIND_STARTSWITH | TranslateNormalization(normalization), text.Buffer(), (int)text.Length(), find.Buffer(), (int)find.Length(), NULL, NULL, NULL, NULL);
int
=
(
.
(),
0x00100000
|
(
),
.
(), (
int
)
.
(),
.
(), (
int
)
.
(),
0
,
0
,
0
,
0
);
return
result
!=-
1
;
#elif defined VCZH_GCC
if(text.Length() < find.Length() || find.Length() == 0)
{
return false;
}
switch(normalization)
{
case Normalization::None:
return wcsncmp(text.Buffer(), find.Buffer(), find.Length()) == 0;
case Normalization::IgnoreCase:
return wcsncasecmp(text.Buffer(), find.Buffer(), find.Length()) == 0;
}
return false;
#endif
}
bool
::
(
const
&
,
const
&
,
)
const
{
#if defined VCZH_MSVC
int result=FindNLSStringEx(localeName.Buffer(), FIND_ENDSWITH | TranslateNormalization(normalization), text.Buffer(), (int)text.Length(), find.Buffer(), (int)find.Length(), NULL, NULL, NULL, NULL);
int
=
(
.
(),
0x00200000
|
(
),
.
(), (
int
)
.
(),
.
(), (
int
)
.
(),
0
,
0
,
0
,
0
);
return
result
!=-
1
;
#elif defined VCZH_GCC
if(text.Length() < find.Length() || find.Length() == 0)
{
return false;
}
switch(normalization)
{
case Normalization::None:
return wcsncmp(text.Buffer() + text.Length() - find.Length(), find.Buffer(), find.Length()) == 0;
case Normalization::IgnoreCase:
return wcsncasecmp(text.Buffer() + text.Length() - find.Length(), find.Buffer(), find.Length()) == 0;
}
return false;
#endif
}
}