aboutsummaryrefslogtreecommitdiffstats
path: root/src/w32proc.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/w32proc.c')
-rw-r--r--src/w32proc.c214
1 files changed, 211 insertions, 3 deletions
diff --git a/src/w32proc.c b/src/w32proc.c
index 426a656f566..38452917add 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>
@@ -1604,6 +1605,15 @@ sys_spawnve (int mode, char *cmdname, char **argv, char **envp)
1604 program = ENCODE_FILE (full); 1605 program = ENCODE_FILE (full);
1605 cmdname = SDATA (program); 1606 cmdname = SDATA (program);
1606 } 1607 }
1608 else
1609 {
1610 char *p = alloca (strlen (cmdname) + 1);
1611
1612 /* Don't change the command name we were passed by our caller
1613 (unixtodos_filename below will destructively mirror forward
1614 slashes). */
1615 cmdname = strcpy (p, cmdname);
1616 }
1607 1617
1608 /* make sure argv[0] and cmdname are both in DOS format */ 1618 /* make sure argv[0] and cmdname are both in DOS format */
1609 unixtodos_filename (cmdname); 1619 unixtodos_filename (cmdname);
@@ -1646,7 +1656,7 @@ sys_spawnve (int mode, char *cmdname, char **argv, char **envp)
1646 strcpy (cmdname, egetenv ("CMDPROXY")); 1656 strcpy (cmdname, egetenv ("CMDPROXY"));
1647 else 1657 else
1648 { 1658 {
1649 strcpy (cmdname, SDATA (Vinvocation_directory)); 1659 lispstpcpy (cmdname, Vinvocation_directory);
1650 strcat (cmdname, "cmdproxy.exe"); 1660 strcat (cmdname, "cmdproxy.exe");
1651 } 1661 }
1652 1662
@@ -2908,7 +2918,7 @@ int_from_hex (char * s)
2908 function isn't given a context pointer. */ 2918 function isn't given a context pointer. */
2909Lisp_Object Vw32_valid_locale_ids; 2919Lisp_Object Vw32_valid_locale_ids;
2910 2920
2911static BOOL CALLBACK 2921static BOOL CALLBACK ALIGN_STACK
2912enum_locale_fn (LPTSTR localeNum) 2922enum_locale_fn (LPTSTR localeNum)
2913{ 2923{
2914 DWORD id = int_from_hex (localeNum); 2924 DWORD id = int_from_hex (localeNum);
@@ -2972,7 +2982,7 @@ If successful, the new locale id is returned, otherwise nil. */)
2972 function isn't given a context pointer. */ 2982 function isn't given a context pointer. */
2973Lisp_Object Vw32_valid_codepages; 2983Lisp_Object Vw32_valid_codepages;
2974 2984
2975static BOOL CALLBACK 2985static BOOL CALLBACK ALIGN_STACK
2976enum_codepage_fn (LPTSTR codepageNum) 2986enum_codepage_fn (LPTSTR codepageNum)
2977{ 2987{
2978 DWORD id = atoi (codepageNum); 2988 DWORD id = atoi (codepageNum);
@@ -3144,6 +3154,190 @@ If successful, the new layout id is returned, otherwise nil. */)
3144 return Fw32_get_keyboard_layout (); 3154 return Fw32_get_keyboard_layout ();
3145} 3155}
3146 3156
3157/* Two variables to interface between get_lcid and the EnumLocales
3158 callback function below. */
3159#ifndef LOCALE_NAME_MAX_LENGTH
3160# define LOCALE_NAME_MAX_LENGTH 85
3161#endif
3162static LCID found_lcid;
3163static char lname[3 * LOCALE_NAME_MAX_LENGTH + 1 + 1];
3164
3165/* Callback function for EnumLocales. */
3166static BOOL CALLBACK
3167get_lcid_callback (LPTSTR locale_num_str)
3168{
3169 char *endp;
3170 char locval[2 * LOCALE_NAME_MAX_LENGTH + 1 + 1];
3171 LCID try_lcid = strtoul (locale_num_str, &endp, 16);
3172
3173 if (GetLocaleInfo (try_lcid, LOCALE_SABBREVLANGNAME,
3174 locval, LOCALE_NAME_MAX_LENGTH))
3175 {
3176 /* This is for when they only specify the language, as in "ENU". */
3177 if (stricmp (locval, lname) == 0)
3178 {
3179 found_lcid = try_lcid;
3180 return FALSE;
3181 }
3182 strcat (locval, "_");
3183 if (GetLocaleInfo (try_lcid, LOCALE_SABBREVCTRYNAME,
3184 locval + strlen (locval), LOCALE_NAME_MAX_LENGTH))
3185 {
3186 size_t locval_len = strlen (locval);
3187
3188 if (strnicmp (locval, lname, locval_len) == 0
3189 && (lname[locval_len] == '.'
3190 || lname[locval_len] == '\0'))
3191 {
3192 found_lcid = try_lcid;
3193 return FALSE;
3194 }
3195 }
3196 }
3197 return TRUE;
3198}
3199
3200/* Return the Locale ID (LCID) number given the locale's name, a
3201 string, in LOCALE_NAME. This works by enumerating all the locales
3202 supported by the system, until we find one whose name matches
3203 LOCALE_NAME. */
3204static LCID
3205get_lcid (const char *locale_name)
3206{
3207 /* A simple cache. */
3208 static LCID last_lcid;
3209 static char last_locale[1000];
3210
3211 /* The code below is not thread-safe, as it uses static variables.
3212 But this function is called only from the Lisp thread. */
3213 if (last_lcid > 0 && strcmp (locale_name, last_locale) == 0)
3214 return last_lcid;
3215
3216 strncpy (lname, locale_name, sizeof (lname) - 1);
3217 lname[sizeof (lname) - 1] = '\0';
3218 found_lcid = 0;
3219 EnumSystemLocales (get_lcid_callback, LCID_SUPPORTED);
3220 if (found_lcid > 0)
3221 {
3222 last_lcid = found_lcid;
3223 strcpy (last_locale, locale_name);
3224 }
3225 return found_lcid;
3226}
3227
3228#ifndef _NSLCMPERROR
3229# define _NSLCMPERROR INT_MAX
3230#endif
3231#ifndef LINGUISTIC_IGNORECASE
3232# define LINGUISTIC_IGNORECASE 0x00000010
3233#endif
3234
3235int
3236w32_compare_strings (const char *s1, const char *s2, char *locname,
3237 int ignore_case)
3238{
3239 LCID lcid = GetThreadLocale ();
3240 wchar_t *string1_w, *string2_w;
3241 int val, needed;
3242 extern BOOL g_b_init_compare_string_w;
3243 static int (WINAPI *pCompareStringW)(LCID, DWORD, LPCWSTR, int, LPCWSTR, int);
3244 DWORD flags = 0;
3245
3246 USE_SAFE_ALLOCA;
3247
3248 /* The LCID machinery doesn't seem to support the "C" locale, so we
3249 need to do that by hand. */
3250 if (locname
3251 && ((locname[0] == 'C' && (locname[1] == '\0' || locname[1] == '.'))
3252 || strcmp (locname, "POSIX") == 0))
3253 return (ignore_case ? stricmp (s1, s2) : strcmp (s1, s2));
3254
3255 if (!g_b_init_compare_string_w)
3256 {
3257 if (os_subtype == OS_9X)
3258 {
3259 pCompareStringW = GetProcAddress (LoadLibrary ("Unicows.dll"),
3260 "CompareStringW");
3261 if (!pCompareStringW)
3262 {
3263 errno = EINVAL;
3264 /* This return value is compatible with wcscoll and
3265 other MS CRT functions. */
3266 return _NSLCMPERROR;
3267 }
3268 }
3269 else
3270 pCompareStringW = CompareStringW;
3271
3272 g_b_init_compare_string_w = 1;
3273 }
3274
3275 needed = pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, s1, -1, NULL, 0);
3276 if (needed > 0)
3277 {
3278 SAFE_NALLOCA (string1_w, 1, needed + 1);
3279 pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, s1, -1,
3280 string1_w, needed);
3281 }
3282 else
3283 {
3284 errno = EINVAL;
3285 return _NSLCMPERROR;
3286 }
3287
3288 needed = pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, s2, -1, NULL, 0);
3289 if (needed > 0)
3290 {
3291 SAFE_NALLOCA (string2_w, 1, needed + 1);
3292 pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, s2, -1,
3293 string2_w, needed);
3294 }
3295 else
3296 {
3297 SAFE_FREE ();
3298 errno = EINVAL;
3299 return _NSLCMPERROR;
3300 }
3301
3302 if (locname)
3303 {
3304 /* Convert locale name string to LCID. We don't want to use
3305 LocaleNameToLCID because (a) it is only available since
3306 Vista, and (b) it doesn't accept locale names returned by
3307 'setlocale' and 'GetLocaleInfo'. */
3308 LCID new_lcid = get_lcid (locname);
3309
3310 if (new_lcid > 0)
3311 lcid = new_lcid;
3312 else
3313 error ("Invalid locale %s: Invalid argument", locname);
3314 }
3315
3316 if (ignore_case)
3317 {
3318 /* NORM_IGNORECASE ignores any tertiary distinction, not just
3319 case variants. LINGUISTIC_IGNORECASE is more selective, and
3320 is sensitive to the locale's language, but it is not
3321 available before Vista. */
3322 if (w32_major_version >= 6)
3323 flags |= LINGUISTIC_IGNORECASE;
3324 else
3325 flags |= NORM_IGNORECASE;
3326 }
3327 /* This approximates what glibc collation functions do when the
3328 locale's codeset is UTF-8. */
3329 if (!NILP (Vw32_collate_ignore_punctuation))
3330 flags |= NORM_IGNORESYMBOLS;
3331 val = pCompareStringW (lcid, flags, string1_w, -1, string2_w, -1);
3332 SAFE_FREE ();
3333 if (!val)
3334 {
3335 errno = EINVAL;
3336 return _NSLCMPERROR;
3337 }
3338 return val - 2;
3339}
3340
3147 3341
3148void 3342void
3149syms_of_ntproc (void) 3343syms_of_ntproc (void)
@@ -3254,6 +3448,20 @@ Any other non-nil value means do this even on remote and removable drives
3254where the performance impact may be noticeable even on modern hardware. */); 3448where the performance impact may be noticeable even on modern hardware. */);
3255 Vw32_get_true_file_attributes = Qlocal; 3449 Vw32_get_true_file_attributes = Qlocal;
3256 3450
3451 DEFVAR_LISP ("w32-collate-ignore-punctuation",
3452 Vw32_collate_ignore_punctuation,
3453 doc: /* Non-nil causes string collation functions ignore punctuation on MS-Windows.
3454On Posix platforms, `string-collate-lessp' and `string-collate-equalp'
3455ignore punctuation characters when they compare strings, if the
3456locale's codeset is UTF-8, as in \"en_US.UTF-8\". Binding this option
3457to a non-nil value will achieve a similar effect on MS-Windows, where
3458locales with UTF-8 codeset are not supported.
3459
3460Note that setting this to non-nil will also ignore blanks and symbols
3461in the strings. So do NOT use this option when comparing file names
3462for equality, only when you need to sort them. */);
3463 Vw32_collate_ignore_punctuation = Qnil;
3464
3257 staticpro (&Vw32_valid_locale_ids); 3465 staticpro (&Vw32_valid_locale_ids);
3258 staticpro (&Vw32_valid_codepages); 3466 staticpro (&Vw32_valid_codepages);
3259} 3467}