aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorEli Zaretskii2014-08-25 18:55:46 +0300
committerEli Zaretskii2014-08-25 18:55:46 +0300
commit015ea0ffdb4f446e3bd263fe5e42b35aafdf1e5b (patch)
tree0242e9b0aa25996e40802ee33aa6929efc3effae /src
parent8661ebaa6c0ef3f9517c5288855657b274c723d6 (diff)
downloademacs-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/ChangeLog16
-rw-r--r--src/fns.c12
-rw-r--r--src/sysdep.c12
-rw-r--r--src/w32.c3
-rw-r--r--src/w32.h3
-rw-r--r--src/w32proc.c154
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 @@
12014-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
12014-08-25 Dmitry Antipov <dmantipov@yandex.ru> 172014-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.
diff --git a/src/fns.c b/src/fns.c
index 616b54d193c..2e2acf84b95 100644
--- a/src/fns.c
+++ b/src/fns.c
@@ -364,7 +364,7 @@ If the environment variable \"LC_COLLATE\" is set in `process-environment',
364it overrides the setting of your current locale. */) 364it 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
383DEFUN ("string-collate-equalp", Fstring_collate_equalp, Sstring_collate_equalp, 2, 2, 0, 383DEFUN ("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',
401it overrides the setting of your current locale. */) 401it 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
420static Lisp_Object concat (ptrdiff_t nargs, Lisp_Object *args, 420static 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
3597ptrdiff_t
3598str_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 */
diff --git a/src/w32.c b/src/w32.c
index 7cb9d8960c5..25549d79d7f 100644
--- a/src/w32.c
+++ b/src/w32.c
@@ -309,6 +309,8 @@ static BOOL g_b_init_set_named_security_info_w;
309static BOOL g_b_init_set_named_security_info_a; 309static BOOL g_b_init_set_named_security_info_a;
310static BOOL g_b_init_get_adapters_info; 310static BOOL g_b_init_get_adapters_info;
311 311
312BOOL 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
diff --git a/src/w32.h b/src/w32.h
index 94f7a962833..68ee14c70e3 100644
--- a/src/w32.h
+++ b/src/w32.h
@@ -210,6 +210,9 @@ extern int sys_link (const char *, const char *);
210extern int w32_memory_info (unsigned long long *, unsigned long long *, 210extern 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. */
214extern 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
3153static LCID found_lcid;
3154static char lname[3 * LOCALE_NAME_MAX_LENGTH + 1 + 1];
3155
3156/* Callback function for EnumLocales. */
3157static BOOL CALLBACK
3158get_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. */
3189static LCID
3190get_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
3217int
3218w32_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
3148void 3302void
3149syms_of_ntproc (void) 3303syms_of_ntproc (void)