diff options
| author | Eli Zaretskii | 2014-08-25 18:55:46 +0300 |
|---|---|---|
| committer | Eli Zaretskii | 2014-08-25 18:55:46 +0300 |
| commit | 015ea0ffdb4f446e3bd263fe5e42b35aafdf1e5b (patch) | |
| tree | 0242e9b0aa25996e40802ee33aa6929efc3effae /src | |
| parent | 8661ebaa6c0ef3f9517c5288855657b274c723d6 (diff) | |
| download | emacs-015ea0ffdb4f446e3bd263fe5e42b35aafdf1e5b.tar.gz emacs-015ea0ffdb4f446e3bd263fe5e42b35aafdf1e5b.zip | |
Implement locale-sensitive string collation for MS-Windows. (Bug#18051)
src/w32proc.c (get_lcid_callback, get_lcid, w32_compare_strings):
New functions.
src/w32.h (w32_compare_strings): Add prototype.
src/w32.c <g_b_init_compare_string_w>: New global flag.
(globals_of_w32): Initialize it.
src/sysdep.c (str_collate) [WINDOWSNT]: Implementation for MS-Windows.
src/fns.c (Fstring_collate_lessp, Fstring_collate_equalp)
[WINDOWSNT]: Call str_collate on MS-Windows.
etc/NEWS: Mention that string-collate-* functions are supported on
MS-Windows as well.
Diffstat (limited to 'src')
| -rw-r--r-- | src/ChangeLog | 16 | ||||
| -rw-r--r-- | src/fns.c | 12 | ||||
| -rw-r--r-- | src/sysdep.c | 12 | ||||
| -rw-r--r-- | src/w32.c | 3 | ||||
| -rw-r--r-- | src/w32.h | 3 | ||||
| -rw-r--r-- | src/w32proc.c | 154 |
6 files changed, 194 insertions, 6 deletions
diff --git a/src/ChangeLog b/src/ChangeLog index efd469ad053..bb678dc4843 100644 --- a/src/ChangeLog +++ b/src/ChangeLog | |||
| @@ -1,3 +1,19 @@ | |||
| 1 | 2014-08-25 Eli Zaretskii <eliz@gnu.org> | ||
| 2 | |||
| 3 | Implement locale-sensitive string collation for MS-Windows. | ||
| 4 | * w32proc.c (get_lcid_callback, get_lcid, w32_compare_strings): | ||
| 5 | New functions. (Bug#18051) | ||
| 6 | |||
| 7 | * w32.h (w32_compare_strings): Add prototype. | ||
| 8 | |||
| 9 | * w32.c <g_b_init_compare_string_w>: New global flag. | ||
| 10 | (globals_of_w32): Initialize it. | ||
| 11 | |||
| 12 | * sysdep.c (str_collate) [WINDOWSNT]: Implementation for MS-Windows. | ||
| 13 | |||
| 14 | * fns.c (Fstring_collate_lessp, Fstring_collate_equalp) | ||
| 15 | [WINDOWSNT]: Call str_collate on MS-Windows. | ||
| 16 | |||
| 1 | 2014-08-25 Dmitry Antipov <dmantipov@yandex.ru> | 17 | 2014-08-25 Dmitry Antipov <dmantipov@yandex.ru> |
| 2 | 18 | ||
| 3 | One more minor cleanup of font subsystem. | 19 | One more minor cleanup of font subsystem. |
| @@ -364,7 +364,7 @@ If the environment variable \"LC_COLLATE\" is set in `process-environment', | |||
| 364 | it overrides the setting of your current locale. */) | 364 | it overrides the setting of your current locale. */) |
| 365 | (Lisp_Object s1, Lisp_Object s2) | 365 | (Lisp_Object s1, Lisp_Object s2) |
| 366 | { | 366 | { |
| 367 | #ifdef __STDC_ISO_10646__ | 367 | #if defined __STDC_ISO_10646__ || defined WINDOWSNT |
| 368 | /* Check parameters. */ | 368 | /* Check parameters. */ |
| 369 | if (SYMBOLP (s1)) | 369 | if (SYMBOLP (s1)) |
| 370 | s1 = SYMBOL_NAME (s1); | 370 | s1 = SYMBOL_NAME (s1); |
| @@ -375,9 +375,9 @@ it overrides the setting of your current locale. */) | |||
| 375 | 375 | ||
| 376 | return (str_collate (s1, s2) < 0) ? Qt : Qnil; | 376 | return (str_collate (s1, s2) < 0) ? Qt : Qnil; |
| 377 | 377 | ||
| 378 | #else | 378 | #else /* !__STDC_ISO_10646__, !WINDOWSNT */ |
| 379 | return Fstring_lessp (s1, s2); | 379 | return Fstring_lessp (s1, s2); |
| 380 | #endif /* __STDC_ISO_10646__ */ | 380 | #endif /* !__STDC_ISO_10646__, !WINDOWSNT */ |
| 381 | } | 381 | } |
| 382 | 382 | ||
| 383 | DEFUN ("string-collate-equalp", Fstring_collate_equalp, Sstring_collate_equalp, 2, 2, 0, | 383 | DEFUN ("string-collate-equalp", Fstring_collate_equalp, Sstring_collate_equalp, 2, 2, 0, |
| @@ -401,7 +401,7 @@ If the environment variable \"LC_COLLATE\" is set in `process-environment', | |||
| 401 | it overrides the setting of your current locale. */) | 401 | it overrides the setting of your current locale. */) |
| 402 | (Lisp_Object s1, Lisp_Object s2) | 402 | (Lisp_Object s1, Lisp_Object s2) |
| 403 | { | 403 | { |
| 404 | #ifdef __STDC_ISO_10646__ | 404 | #if defined __STDC_ISO_10646__ || defined WINDOWSNT |
| 405 | /* Check parameters. */ | 405 | /* Check parameters. */ |
| 406 | if (SYMBOLP (s1)) | 406 | if (SYMBOLP (s1)) |
| 407 | s1 = SYMBOL_NAME (s1); | 407 | s1 = SYMBOL_NAME (s1); |
| @@ -412,9 +412,9 @@ it overrides the setting of your current locale. */) | |||
| 412 | 412 | ||
| 413 | return (str_collate (s1, s2) == 0) ? Qt : Qnil; | 413 | return (str_collate (s1, s2) == 0) ? Qt : Qnil; |
| 414 | 414 | ||
| 415 | #else | 415 | #else /* !__STDC_ISO_10646__, !WINDOWSNT */ |
| 416 | return Fstring_equal (s1, s2); | 416 | return Fstring_equal (s1, s2); |
| 417 | #endif /* __STDC_ISO_10646__ */ | 417 | #endif /* !__STDC_ISO_10646__, !WINDOWSNT */ |
| 418 | } | 418 | } |
| 419 | 419 | ||
| 420 | static Lisp_Object concat (ptrdiff_t nargs, Lisp_Object *args, | 420 | static Lisp_Object concat (ptrdiff_t nargs, Lisp_Object *args, |
diff --git a/src/sysdep.c b/src/sysdep.c index 856d668bb71..25bec264f46 100644 --- a/src/sysdep.c +++ b/src/sysdep.c | |||
| @@ -3592,3 +3592,15 @@ str_collate (Lisp_Object s1, Lisp_Object s2) | |||
| 3592 | return res; | 3592 | return res; |
| 3593 | } | 3593 | } |
| 3594 | #endif /* __STDC_ISO_10646__ */ | 3594 | #endif /* __STDC_ISO_10646__ */ |
| 3595 | |||
| 3596 | #ifdef WINDOWSNT | ||
| 3597 | ptrdiff_t | ||
| 3598 | str_collate (Lisp_Object s1, Lisp_Object s2) | ||
| 3599 | { | ||
| 3600 | Lisp_Object lc_collate = | ||
| 3601 | Fgetenv_internal (build_string ("LC_COLLATE"), Vprocess_environment); | ||
| 3602 | char *loc = STRINGP (lc_collate) ? SSDATA (lc_collate) : NULL; | ||
| 3603 | |||
| 3604 | return w32_compare_strings (SDATA (s1), SDATA (s2), loc); | ||
| 3605 | } | ||
| 3606 | #endif /* WINDOWSNT */ | ||
| @@ -309,6 +309,8 @@ static BOOL g_b_init_set_named_security_info_w; | |||
| 309 | static BOOL g_b_init_set_named_security_info_a; | 309 | static BOOL g_b_init_set_named_security_info_a; |
| 310 | static BOOL g_b_init_get_adapters_info; | 310 | static BOOL g_b_init_get_adapters_info; |
| 311 | 311 | ||
| 312 | BOOL g_b_init_compare_string_w; | ||
| 313 | |||
| 312 | /* | 314 | /* |
| 313 | BEGIN: Wrapper functions around OpenProcessToken | 315 | BEGIN: Wrapper functions around OpenProcessToken |
| 314 | and other functions in advapi32.dll that are only | 316 | and other functions in advapi32.dll that are only |
| @@ -9068,6 +9070,7 @@ globals_of_w32 (void) | |||
| 9068 | g_b_init_set_named_security_info_w = 0; | 9070 | g_b_init_set_named_security_info_w = 0; |
| 9069 | g_b_init_set_named_security_info_a = 0; | 9071 | g_b_init_set_named_security_info_a = 0; |
| 9070 | g_b_init_get_adapters_info = 0; | 9072 | g_b_init_get_adapters_info = 0; |
| 9073 | g_b_init_compare_string_w = 0; | ||
| 9071 | num_of_processors = 0; | 9074 | num_of_processors = 0; |
| 9072 | /* The following sets a handler for shutdown notifications for | 9075 | /* The following sets a handler for shutdown notifications for |
| 9073 | console apps. This actually applies to Emacs in both console and | 9076 | console apps. This actually applies to Emacs in both console and |
| @@ -210,6 +210,9 @@ extern int sys_link (const char *, const char *); | |||
| 210 | extern int w32_memory_info (unsigned long long *, unsigned long long *, | 210 | extern int w32_memory_info (unsigned long long *, unsigned long long *, |
| 211 | unsigned long long *, unsigned long long *); | 211 | unsigned long long *, unsigned long long *); |
| 212 | 212 | ||
| 213 | /* Compare 2 UTF-8 strings in locale-dependent fashion. */ | ||
| 214 | extern int w32_compare_strings (const char *, const char *, char *); | ||
| 215 | |||
| 213 | #ifdef HAVE_GNUTLS | 216 | #ifdef HAVE_GNUTLS |
| 214 | #include <gnutls/gnutls.h> | 217 | #include <gnutls/gnutls.h> |
| 215 | 218 | ||
diff --git a/src/w32proc.c b/src/w32proc.c index 426a656f566..ed62de02433 100644 --- a/src/w32proc.c +++ b/src/w32proc.c | |||
| @@ -32,6 +32,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ | |||
| 32 | #include <signal.h> | 32 | #include <signal.h> |
| 33 | #include <sys/file.h> | 33 | #include <sys/file.h> |
| 34 | #include <mbstring.h> | 34 | #include <mbstring.h> |
| 35 | #include <locale.h> | ||
| 35 | 36 | ||
| 36 | /* must include CRT headers *before* config.h */ | 37 | /* must include CRT headers *before* config.h */ |
| 37 | #include <config.h> | 38 | #include <config.h> |
| @@ -3144,6 +3145,159 @@ If successful, the new layout id is returned, otherwise nil. */) | |||
| 3144 | return Fw32_get_keyboard_layout (); | 3145 | return Fw32_get_keyboard_layout (); |
| 3145 | } | 3146 | } |
| 3146 | 3147 | ||
| 3148 | /* Two variables to interface between get_lcid and the EnumLocales | ||
| 3149 | callback function below. */ | ||
| 3150 | #ifndef LOCALE_NAME_MAX_LENGTH | ||
| 3151 | # define LOCALE_NAME_MAX_LENGTH 85 | ||
| 3152 | #endif | ||
| 3153 | static LCID found_lcid; | ||
| 3154 | static char lname[3 * LOCALE_NAME_MAX_LENGTH + 1 + 1]; | ||
| 3155 | |||
| 3156 | /* Callback function for EnumLocales. */ | ||
| 3157 | static BOOL CALLBACK | ||
| 3158 | get_lcid_callback (LPTSTR locale_num_str) | ||
| 3159 | { | ||
| 3160 | char *endp; | ||
| 3161 | char locval[2 * LOCALE_NAME_MAX_LENGTH + 1 + 1]; | ||
| 3162 | LCID try_lcid = strtoul (locale_num_str, &endp, 16); | ||
| 3163 | |||
| 3164 | if (GetLocaleInfo (try_lcid, LOCALE_SABBREVLANGNAME, | ||
| 3165 | locval, LOCALE_NAME_MAX_LENGTH)) | ||
| 3166 | { | ||
| 3167 | strcat (locval, "_"); | ||
| 3168 | if (GetLocaleInfo (try_lcid, LOCALE_SABBREVCTRYNAME, | ||
| 3169 | locval + strlen (locval), LOCALE_NAME_MAX_LENGTH)) | ||
| 3170 | { | ||
| 3171 | size_t locval_len = strlen (locval); | ||
| 3172 | |||
| 3173 | if (strnicmp (locval, lname, locval_len) == 0 | ||
| 3174 | && (lname[locval_len] == '.' | ||
| 3175 | || lname[locval_len] == '\0')) | ||
| 3176 | { | ||
| 3177 | found_lcid = try_lcid; | ||
| 3178 | return FALSE; | ||
| 3179 | } | ||
| 3180 | } | ||
| 3181 | } | ||
| 3182 | return TRUE; | ||
| 3183 | } | ||
| 3184 | |||
| 3185 | /* Return the Locale ID (LCID) number given the locale's name, a | ||
| 3186 | string, in LOCALE_NAME. This works by enumerating all the locales | ||
| 3187 | supported by the system, until we find one whose name matches | ||
| 3188 | LOCALE_NAME. */ | ||
| 3189 | static LCID | ||
| 3190 | get_lcid (const char *locale_name) | ||
| 3191 | { | ||
| 3192 | /* A simple cache. */ | ||
| 3193 | static LCID last_lcid; | ||
| 3194 | static char last_locale[1000]; | ||
| 3195 | |||
| 3196 | /* The code below is not thread-safe, as it uses static variables. | ||
| 3197 | But this function is called only from the Lisp thread. */ | ||
| 3198 | if (last_lcid > 0 && strcmp (locale_name, last_locale) == 0) | ||
| 3199 | return last_lcid; | ||
| 3200 | |||
| 3201 | strncpy (lname, locale_name, sizeof (lname) - 1); | ||
| 3202 | lname[sizeof (lname) - 1] = '\0'; | ||
| 3203 | found_lcid = 0; | ||
| 3204 | EnumSystemLocales (get_lcid_callback, LCID_SUPPORTED); | ||
| 3205 | if (found_lcid > 0) | ||
| 3206 | { | ||
| 3207 | last_lcid = found_lcid; | ||
| 3208 | strcpy (last_locale, locale_name); | ||
| 3209 | } | ||
| 3210 | return found_lcid; | ||
| 3211 | } | ||
| 3212 | |||
| 3213 | #ifndef _NSLCMPERROR | ||
| 3214 | # define _NSLCMPERROR INT_MAX | ||
| 3215 | #endif | ||
| 3216 | |||
| 3217 | int | ||
| 3218 | w32_compare_strings (const char *s1, const char *s2, char *locname) | ||
| 3219 | { | ||
| 3220 | LCID lcid = GetThreadLocale (); | ||
| 3221 | wchar_t *string1_w, *string2_w; | ||
| 3222 | int val, needed; | ||
| 3223 | extern BOOL g_b_init_compare_string_w; | ||
| 3224 | static int (WINAPI *pCompareStringW)(LCID, DWORD, LPCWSTR, int, LPCWSTR, int); | ||
| 3225 | |||
| 3226 | USE_SAFE_ALLOCA; | ||
| 3227 | |||
| 3228 | if (!g_b_init_compare_string_w) | ||
| 3229 | { | ||
| 3230 | if (os_subtype == OS_9X) | ||
| 3231 | { | ||
| 3232 | pCompareStringW = GetProcAddress (LoadLibrary ("Unicows.dll"), | ||
| 3233 | "CompareStringW"); | ||
| 3234 | if (!pCompareStringW) | ||
| 3235 | { | ||
| 3236 | errno = EINVAL; | ||
| 3237 | /* This return value is compatible with wcscoll and | ||
| 3238 | other MS CRT functions. */ | ||
| 3239 | return _NSLCMPERROR; | ||
| 3240 | } | ||
| 3241 | } | ||
| 3242 | else | ||
| 3243 | pCompareStringW = CompareStringW; | ||
| 3244 | |||
| 3245 | g_b_init_compare_string_w = 1; | ||
| 3246 | } | ||
| 3247 | |||
| 3248 | needed = pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, s1, -1, NULL, 0); | ||
| 3249 | if (needed > 0) | ||
| 3250 | { | ||
| 3251 | SAFE_NALLOCA (string1_w, 1, needed + 1); | ||
| 3252 | pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, s1, -1, | ||
| 3253 | string1_w, needed); | ||
| 3254 | } | ||
| 3255 | else | ||
| 3256 | { | ||
| 3257 | errno = EINVAL; | ||
| 3258 | return _NSLCMPERROR; | ||
| 3259 | } | ||
| 3260 | |||
| 3261 | needed = pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, s2, -1, NULL, 0); | ||
| 3262 | if (needed > 0) | ||
| 3263 | { | ||
| 3264 | SAFE_NALLOCA (string2_w, 1, needed + 1); | ||
| 3265 | pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, s2, -1, | ||
| 3266 | string2_w, needed); | ||
| 3267 | } | ||
| 3268 | else | ||
| 3269 | { | ||
| 3270 | SAFE_FREE (); | ||
| 3271 | errno = EINVAL; | ||
| 3272 | return _NSLCMPERROR; | ||
| 3273 | } | ||
| 3274 | |||
| 3275 | if (locname) | ||
| 3276 | { | ||
| 3277 | /* Convert locale name string to LCID. We don't want to use | ||
| 3278 | LocaleNameToLCID because (a) it is only available since | ||
| 3279 | Vista, and (b) it doesn't accept locale names returned by | ||
| 3280 | 'setlocale' and 'GetLocaleInfo'. */ | ||
| 3281 | LCID new_lcid = get_lcid (locname); | ||
| 3282 | |||
| 3283 | if (new_lcid > 0) | ||
| 3284 | lcid = new_lcid; | ||
| 3285 | } | ||
| 3286 | |||
| 3287 | /* FIXME: Need a way to control the FLAGS argument, perhaps via the | ||
| 3288 | CODESET part of LOCNAME. In particular, ls-lisp will want | ||
| 3289 | NORM_IGNORESYMBOLS and sometimes LINGUISTIC_IGNORECASE or | ||
| 3290 | NORM_IGNORECASE. */ | ||
| 3291 | val = pCompareStringW (lcid, 0, string1_w, -1, string2_w, -1); | ||
| 3292 | SAFE_FREE (); | ||
| 3293 | if (!val) | ||
| 3294 | { | ||
| 3295 | errno = EINVAL; | ||
| 3296 | return _NSLCMPERROR; | ||
| 3297 | } | ||
| 3298 | return val - 2; | ||
| 3299 | } | ||
| 3300 | |||
| 3147 | 3301 | ||
| 3148 | void | 3302 | void |
| 3149 | syms_of_ntproc (void) | 3303 | syms_of_ntproc (void) |