diff options
Diffstat (limited to 'src/w32proc.c')
| -rw-r--r-- | src/w32proc.c | 214 |
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. */ |
| 2909 | Lisp_Object Vw32_valid_locale_ids; | 2919 | Lisp_Object Vw32_valid_locale_ids; |
| 2910 | 2920 | ||
| 2911 | static BOOL CALLBACK | 2921 | static BOOL CALLBACK ALIGN_STACK |
| 2912 | enum_locale_fn (LPTSTR localeNum) | 2922 | enum_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. */ |
| 2973 | Lisp_Object Vw32_valid_codepages; | 2983 | Lisp_Object Vw32_valid_codepages; |
| 2974 | 2984 | ||
| 2975 | static BOOL CALLBACK | 2985 | static BOOL CALLBACK ALIGN_STACK |
| 2976 | enum_codepage_fn (LPTSTR codepageNum) | 2986 | enum_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 | ||
| 3162 | static LCID found_lcid; | ||
| 3163 | static char lname[3 * LOCALE_NAME_MAX_LENGTH + 1 + 1]; | ||
| 3164 | |||
| 3165 | /* Callback function for EnumLocales. */ | ||
| 3166 | static BOOL CALLBACK | ||
| 3167 | get_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. */ | ||
| 3204 | static LCID | ||
| 3205 | get_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 | |||
| 3235 | int | ||
| 3236 | w32_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 | ||
| 3148 | void | 3342 | void |
| 3149 | syms_of_ntproc (void) | 3343 | syms_of_ntproc (void) |
| @@ -3254,6 +3448,20 @@ Any other non-nil value means do this even on remote and removable drives | |||
| 3254 | where the performance impact may be noticeable even on modern hardware. */); | 3448 | where 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. | ||
| 3454 | On Posix platforms, `string-collate-lessp' and `string-collate-equalp' | ||
| 3455 | ignore punctuation characters when they compare strings, if the | ||
| 3456 | locale's codeset is UTF-8, as in \"en_US.UTF-8\". Binding this option | ||
| 3457 | to a non-nil value will achieve a similar effect on MS-Windows, where | ||
| 3458 | locales with UTF-8 codeset are not supported. | ||
| 3459 | |||
| 3460 | Note that setting this to non-nil will also ignore blanks and symbols | ||
| 3461 | in the strings. So do NOT use this option when comparing file names | ||
| 3462 | for 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 | } |