mirror of https://github.com/OpenTTD/OpenTTD
Add: [Win32] Native natural sort implementation.
parent
2b662b448c
commit
f4394debdc
|
@ -28,6 +28,7 @@
|
||||||
#include "../../crashlog.h"
|
#include "../../crashlog.h"
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#include "../../language.h"
|
||||||
|
|
||||||
/* Due to TCHAR, strncat and strncpy have to remain (for a while). */
|
/* Due to TCHAR, strncat and strncpy have to remain (for a while). */
|
||||||
#include "../../safeguards.h"
|
#include "../../safeguards.h"
|
||||||
|
@ -739,6 +740,70 @@ uint GetCPUCoreCount()
|
||||||
return info.dwNumberOfProcessors;
|
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
|
#ifdef _MSC_VER
|
||||||
/* Code from MSDN: https://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx */
|
/* Code from MSDN: https://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx */
|
||||||
const DWORD MS_VC_EXCEPTION = 0x406D1388;
|
const DWORD MS_VC_EXCEPTION = 0x406D1388;
|
||||||
|
|
|
@ -45,4 +45,7 @@ void SetWin32ThreadName(DWORD dwThreadID, const char* threadName);
|
||||||
static inline void SetWin32ThreadName(DWORD dwThreadID, const char* threadName) {}
|
static inline void SetWin32ThreadName(DWORD dwThreadID, const char* threadName) {}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
void Win32SetCurrentLocaleName(const char *iso_code);
|
||||||
|
int OTTDStringCompare(const char *s1, const char *s2);
|
||||||
|
|
||||||
#endif /* WIN32_H */
|
#endif /* WIN32_H */
|
||||||
|
|
|
@ -25,6 +25,10 @@
|
||||||
#include <errno.h> // required by vsnprintf implementation for MSVC
|
#include <errno.h> // required by vsnprintf implementation for MSVC
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
#include "os/windows/win32.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef WITH_ICU_SORT
|
#ifdef WITH_ICU_SORT
|
||||||
/* Required by strnatcmp. */
|
/* Required by strnatcmp. */
|
||||||
#include <unicode/ustring.h>
|
#include <unicode/ustring.h>
|
||||||
|
@ -572,15 +576,20 @@ int strnatcmp(const char *s1, const char *s2, bool ignore_garbage_at_front)
|
||||||
s1 = SkipGarbage(s1);
|
s1 = SkipGarbage(s1);
|
||||||
s2 = SkipGarbage(s2);
|
s2 = SkipGarbage(s2);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef WITH_ICU_SORT
|
#ifdef WITH_ICU_SORT
|
||||||
if (_current_collator != NULL) {
|
if (_current_collator != NULL) {
|
||||||
UErrorCode status = U_ZERO_ERROR;
|
UErrorCode status = U_ZERO_ERROR;
|
||||||
int result = _current_collator->compareUTF8(s1, s2, status);
|
int result = _current_collator->compareUTF8(s1, s2, status);
|
||||||
if (U_SUCCESS(status)) return result;
|
if (U_SUCCESS(status)) return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* WITH_ICU_SORT */
|
#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. */
|
/* Do a normal comparison if ICU is missing or if we cannot create a collator. */
|
||||||
return strcasecmp(s1, s2);
|
return strcasecmp(s1, s2);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1788,6 +1788,11 @@ bool ReadLanguagePack(const LanguageMetadata *lang)
|
||||||
strecpy(_config_language_file, c_file, lastof(_config_language_file));
|
strecpy(_config_language_file, c_file, lastof(_config_language_file));
|
||||||
SetCurrentGrfLangID(_current_language->newgrflangid);
|
SetCurrentGrfLangID(_current_language->newgrflangid);
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
extern void Win32SetCurrentLocaleName(const char *iso_code);
|
||||||
|
Win32SetCurrentLocaleName(_current_language->isocode);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef WITH_ICU_SORT
|
#ifdef WITH_ICU_SORT
|
||||||
/* Delete previous collator. */
|
/* Delete previous collator. */
|
||||||
if (_current_collator != NULL) {
|
if (_current_collator != NULL) {
|
||||||
|
|
Loading…
Reference in New Issue