diff options
author | Michael Lutz <michi@icosahedron.de> | 2018-04-29 00:34:01 +0200 |
---|---|---|
committer | Michael Lutz <michi@icosahedron.de> | 2018-06-06 21:37:09 +0200 |
commit | f4394debdc092487d603f95716a026a5c8834f8c (patch) | |
tree | db4865150cfd88422f279d6fa5213ab11e27beab /src | |
parent | 2b662b448cd020886c00ff7ec800d7bd7cb008fa (diff) | |
download | openttd-f4394debdc092487d603f95716a026a5c8834f8c.tar.xz |
Add: [Win32] Native natural sort implementation.
Diffstat (limited to 'src')
-rw-r--r-- | src/os/windows/win32.cpp | 65 | ||||
-rw-r--r-- | src/os/windows/win32.h | 3 | ||||
-rw-r--r-- | src/string.cpp | 11 | ||||
-rw-r--r-- | src/strings.cpp | 5 |
4 files changed, 83 insertions, 1 deletions
diff --git a/src/os/windows/win32.cpp b/src/os/windows/win32.cpp index 8a90db4f7..2d853037f 100644 --- a/src/os/windows/win32.cpp +++ b/src/os/windows/win32.cpp @@ -28,6 +28,7 @@ #include "../../crashlog.h" #include <errno.h> #include <sys/stat.h> +#include "../../language.h" /* Due to TCHAR, strncat and strncpy have to remain (for a while). */ #include "../../safeguards.h" @@ -739,6 +740,70 @@ uint GetCPUCoreCount() return info.dwNumberOfProcessors; } + +static WCHAR _cur_iso_locale[16] = L""; + +void Win32SetCurrentLocaleName(const char *iso_code) +{ + /* Convert the iso code into the format that windows expects. */ + char iso[16]; + if (strcmp(iso_code, "zh_TW") == 0) { + strecpy(iso, "zh-Hant", lastof(iso)); + } else if (strcmp(iso_code, "zh_CN") == 0) { + strecpy(iso, "zh-Hans", lastof(iso)); + } else { + /* Windows expects a '-' between language and country code, but we use a '_'. */ + strecpy(iso, iso_code, lastof(iso)); + for (char *c = iso; *c != '\0'; c++) { + if (*c == '_') *c = '-'; + } + } + + MultiByteToWideChar(CP_UTF8, 0, iso, -1, _cur_iso_locale, lengthof(_cur_iso_locale)); +} + +int OTTDStringCompare(const char *s1, const char *s2) +{ + typedef int (WINAPI *PFNCOMPARESTRINGEX)(LPCWSTR, DWORD, LPCWCH, int, LPCWCH, int, LPVOID, LPVOID, LPARAM); + static PFNCOMPARESTRINGEX _CompareStringEx = NULL; + static bool first_time = true; + +#ifndef SORT_DIGITSASNUMBERS +# define SORT_DIGITSASNUMBERS 0x00000008 // use digits as numbers sort method +#endif +#ifndef LINGUISTIC_IGNORECASE +# define LINGUISTIC_IGNORECASE 0x00000010 // linguistically appropriate 'ignore case' +#endif + + if (first_time) { + _CompareStringEx = (PFNCOMPARESTRINGEX)GetProcAddress(GetModuleHandle(_T("Kernel32")), "CompareStringEx"); + first_time = false; + } + + if (_CompareStringEx != NULL) { + /* CompareStringEx takes UTF-16 strings, even in ANSI-builds. */ + int len_s1 = MultiByteToWideChar(CP_UTF8, 0, s1, -1, NULL, 0); + int len_s2 = MultiByteToWideChar(CP_UTF8, 0, s2, -1, NULL, 0); + + if (len_s1 != 0 && len_s2 != 0) { + LPWSTR str_s1 = AllocaM(WCHAR, len_s1); + LPWSTR str_s2 = AllocaM(WCHAR, len_s2); + + MultiByteToWideChar(CP_UTF8, 0, s1, -1, str_s1, len_s1); + MultiByteToWideChar(CP_UTF8, 0, s2, -1, str_s2, len_s2); + + int result = _CompareStringEx(_cur_iso_locale, LINGUISTIC_IGNORECASE | SORT_DIGITSASNUMBERS, str_s1, -1, str_s2, -1, NULL, NULL, 0); + if (result != 0) return result; + } + } + + TCHAR s1_buf[512], s2_buf[512]; + convert_to_fs(s1, s1_buf, lengthof(s1_buf)); + convert_to_fs(s2, s2_buf, lengthof(s2_buf)); + + return CompareString(MAKELCID(_current_language->winlangid, SORT_DEFAULT), NORM_IGNORECASE, s1_buf, -1, s2_buf, -1); +} + #ifdef _MSC_VER /* Code from MSDN: https://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx */ const DWORD MS_VC_EXCEPTION = 0x406D1388; diff --git a/src/os/windows/win32.h b/src/os/windows/win32.h index 16632f6e9..4f813c4a6 100644 --- a/src/os/windows/win32.h +++ b/src/os/windows/win32.h @@ -45,4 +45,7 @@ void SetWin32ThreadName(DWORD dwThreadID, const char* threadName); static inline void SetWin32ThreadName(DWORD dwThreadID, const char* threadName) {} #endif +void Win32SetCurrentLocaleName(const char *iso_code); +int OTTDStringCompare(const char *s1, const char *s2); + #endif /* WIN32_H */ diff --git a/src/string.cpp b/src/string.cpp index 6306e6f75..170334792 100644 --- a/src/string.cpp +++ b/src/string.cpp @@ -25,6 +25,10 @@ #include <errno.h> // required by vsnprintf implementation for MSVC #endif +#ifdef WIN32 +#include "os/windows/win32.h" +#endif + #ifdef WITH_ICU_SORT /* Required by strnatcmp. */ #include <unicode/ustring.h> @@ -572,15 +576,20 @@ int strnatcmp(const char *s1, const char *s2, bool ignore_garbage_at_front) s1 = SkipGarbage(s1); s2 = SkipGarbage(s2); } + #ifdef WITH_ICU_SORT if (_current_collator != NULL) { UErrorCode status = U_ZERO_ERROR; int result = _current_collator->compareUTF8(s1, s2, status); if (U_SUCCESS(status)) return result; } - #endif /* WITH_ICU_SORT */ +#if defined(WIN32) && !defined(STRGEN) && !defined(SETTINGSGEN) + int res = OTTDStringCompare(s1, s2); + if (res != 0) return res - 2; // Convert to normal C return values. +#endif + /* Do a normal comparison if ICU is missing or if we cannot create a collator. */ return strcasecmp(s1, s2); } diff --git a/src/strings.cpp b/src/strings.cpp index fd45e6a0b..4ababcc5a 100644 --- a/src/strings.cpp +++ b/src/strings.cpp @@ -1788,6 +1788,11 @@ bool ReadLanguagePack(const LanguageMetadata *lang) strecpy(_config_language_file, c_file, lastof(_config_language_file)); SetCurrentGrfLangID(_current_language->newgrflangid); +#ifdef WIN32 + extern void Win32SetCurrentLocaleName(const char *iso_code); + Win32SetCurrentLocaleName(_current_language->isocode); +#endif + #ifdef WITH_ICU_SORT /* Delete previous collator. */ if (_current_collator != NULL) { |