diff options
Diffstat (limited to 'src/w32proc.c')
-rw-r--r-- | src/w32proc.c | 225 |
1 files changed, 216 insertions, 9 deletions
diff --git a/src/w32proc.c b/src/w32proc.c index 96f11657892..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/>. */ #include <signal.h> #include <sys/file.h> #include <mbstring.h> +#include <locale.h> /* must include CRT headers *before* config.h */ #include <config.h> @@ -1604,6 +1605,15 @@ sys_spawnve (int mode, char *cmdname, char **argv, char **envp) program = ENCODE_FILE (full); cmdname = SDATA (program); } + else + { + char *p = alloca (strlen (cmdname) + 1); + + /* Don't change the command name we were passed by our caller + (unixtodos_filename below will destructively mirror forward + slashes). */ + cmdname = strcpy (p, cmdname); + } /* make sure argv[0] and cmdname are both in DOS format */ unixtodos_filename (cmdname); @@ -1646,7 +1656,7 @@ sys_spawnve (int mode, char *cmdname, char **argv, char **envp) strcpy (cmdname, egetenv ("CMDPROXY")); else { - strcpy (cmdname, SDATA (Vinvocation_directory)); + lispstpcpy (cmdname, Vinvocation_directory); strcat (cmdname, "cmdproxy.exe"); } @@ -1772,12 +1782,12 @@ sys_spawnve (int mode, char *cmdname, char **argv, char **envp) if (need_quotes) { int escape_char_run = 0; - char * first; - char * last; + /* char * first; */ + /* char * last; */ p = *targ; - first = p; - last = p + strlen (p) - 1; + /* first = p; */ + /* last = p + strlen (p) - 1; */ *parg++ = '"'; #if 0 /* This version does not escape quotes if they occur at the @@ -2249,10 +2259,9 @@ static BOOL CALLBACK find_child_console (HWND hwnd, LPARAM arg) { child_process * cp = (child_process *) arg; - DWORD thread_id; DWORD process_id; - thread_id = GetWindowThreadProcessId (hwnd, &process_id); + GetWindowThreadProcessId (hwnd, &process_id); if (process_id == cp->procinfo.dwProcessId) { char window_class[32]; @@ -2909,7 +2918,7 @@ int_from_hex (char * s) function isn't given a context pointer. */ Lisp_Object Vw32_valid_locale_ids; -static BOOL CALLBACK +static BOOL CALLBACK ALIGN_STACK enum_locale_fn (LPTSTR localeNum) { DWORD id = int_from_hex (localeNum); @@ -2973,7 +2982,7 @@ If successful, the new locale id is returned, otherwise nil. */) function isn't given a context pointer. */ Lisp_Object Vw32_valid_codepages; -static BOOL CALLBACK +static BOOL CALLBACK ALIGN_STACK enum_codepage_fn (LPTSTR codepageNum) { DWORD id = atoi (codepageNum); @@ -3145,6 +3154,190 @@ If successful, the new layout id is returned, otherwise nil. */) return Fw32_get_keyboard_layout (); } +/* Two variables to interface between get_lcid and the EnumLocales + callback function below. */ +#ifndef LOCALE_NAME_MAX_LENGTH +# define LOCALE_NAME_MAX_LENGTH 85 +#endif +static LCID found_lcid; +static char lname[3 * LOCALE_NAME_MAX_LENGTH + 1 + 1]; + +/* Callback function for EnumLocales. */ +static BOOL CALLBACK +get_lcid_callback (LPTSTR locale_num_str) +{ + char *endp; + char locval[2 * LOCALE_NAME_MAX_LENGTH + 1 + 1]; + LCID try_lcid = strtoul (locale_num_str, &endp, 16); + + if (GetLocaleInfo (try_lcid, LOCALE_SABBREVLANGNAME, + locval, LOCALE_NAME_MAX_LENGTH)) + { + /* This is for when they only specify the language, as in "ENU". */ + if (stricmp (locval, lname) == 0) + { + found_lcid = try_lcid; + return FALSE; + } + strcat (locval, "_"); + if (GetLocaleInfo (try_lcid, LOCALE_SABBREVCTRYNAME, + locval + strlen (locval), LOCALE_NAME_MAX_LENGTH)) + { + size_t locval_len = strlen (locval); + + if (strnicmp (locval, lname, locval_len) == 0 + && (lname[locval_len] == '.' + || lname[locval_len] == '\0')) + { + found_lcid = try_lcid; + return FALSE; + } + } + } + return TRUE; +} + +/* Return the Locale ID (LCID) number given the locale's name, a + string, in LOCALE_NAME. This works by enumerating all the locales + supported by the system, until we find one whose name matches + LOCALE_NAME. */ +static LCID +get_lcid (const char *locale_name) +{ + /* A simple cache. */ + static LCID last_lcid; + static char last_locale[1000]; + + /* The code below is not thread-safe, as it uses static variables. + But this function is called only from the Lisp thread. */ + if (last_lcid > 0 && strcmp (locale_name, last_locale) == 0) + return last_lcid; + + strncpy (lname, locale_name, sizeof (lname) - 1); + lname[sizeof (lname) - 1] = '\0'; + found_lcid = 0; + EnumSystemLocales (get_lcid_callback, LCID_SUPPORTED); + if (found_lcid > 0) + { + last_lcid = found_lcid; + strcpy (last_locale, locale_name); + } + return found_lcid; +} + +#ifndef _NSLCMPERROR +# define _NSLCMPERROR INT_MAX +#endif +#ifndef LINGUISTIC_IGNORECASE +# define LINGUISTIC_IGNORECASE 0x00000010 +#endif + +int +w32_compare_strings (const char *s1, const char *s2, char *locname, + int ignore_case) +{ + LCID lcid = GetThreadLocale (); + wchar_t *string1_w, *string2_w; + int val, needed; + extern BOOL g_b_init_compare_string_w; + static int (WINAPI *pCompareStringW)(LCID, DWORD, LPCWSTR, int, LPCWSTR, int); + DWORD flags = 0; + + USE_SAFE_ALLOCA; + + /* The LCID machinery doesn't seem to support the "C" locale, so we + need to do that by hand. */ + if (locname + && ((locname[0] == 'C' && (locname[1] == '\0' || locname[1] == '.')) + || strcmp (locname, "POSIX") == 0)) + return (ignore_case ? stricmp (s1, s2) : strcmp (s1, s2)); + + if (!g_b_init_compare_string_w) + { + if (os_subtype == OS_9X) + { + pCompareStringW = GetProcAddress (LoadLibrary ("Unicows.dll"), + "CompareStringW"); + if (!pCompareStringW) + { + errno = EINVAL; + /* This return value is compatible with wcscoll and + other MS CRT functions. */ + return _NSLCMPERROR; + } + } + else + pCompareStringW = CompareStringW; + + g_b_init_compare_string_w = 1; + } + + needed = pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, s1, -1, NULL, 0); + if (needed > 0) + { + SAFE_NALLOCA (string1_w, 1, needed + 1); + pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, s1, -1, + string1_w, needed); + } + else + { + errno = EINVAL; + return _NSLCMPERROR; + } + + needed = pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, s2, -1, NULL, 0); + if (needed > 0) + { + SAFE_NALLOCA (string2_w, 1, needed + 1); + pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, s2, -1, + string2_w, needed); + } + else + { + SAFE_FREE (); + errno = EINVAL; + return _NSLCMPERROR; + } + + if (locname) + { + /* Convert locale name string to LCID. We don't want to use + LocaleNameToLCID because (a) it is only available since + Vista, and (b) it doesn't accept locale names returned by + 'setlocale' and 'GetLocaleInfo'. */ + LCID new_lcid = get_lcid (locname); + + if (new_lcid > 0) + lcid = new_lcid; + else + error ("Invalid locale %s: Invalid argument", locname); + } + + if (ignore_case) + { + /* NORM_IGNORECASE ignores any tertiary distinction, not just + case variants. LINGUISTIC_IGNORECASE is more selective, and + is sensitive to the locale's language, but it is not + available before Vista. */ + if (w32_major_version >= 6) + flags |= LINGUISTIC_IGNORECASE; + else + flags |= NORM_IGNORECASE; + } + /* This approximates what glibc collation functions do when the + locale's codeset is UTF-8. */ + if (!NILP (Vw32_collate_ignore_punctuation)) + flags |= NORM_IGNORESYMBOLS; + val = pCompareStringW (lcid, flags, string1_w, -1, string2_w, -1); + SAFE_FREE (); + if (!val) + { + errno = EINVAL; + return _NSLCMPERROR; + } + return val - 2; +} + void syms_of_ntproc (void) @@ -3255,6 +3448,20 @@ Any other non-nil value means do this even on remote and removable drives where the performance impact may be noticeable even on modern hardware. */); Vw32_get_true_file_attributes = Qlocal; + DEFVAR_LISP ("w32-collate-ignore-punctuation", + Vw32_collate_ignore_punctuation, + doc: /* Non-nil causes string collation functions ignore punctuation on MS-Windows. +On Posix platforms, `string-collate-lessp' and `string-collate-equalp' +ignore punctuation characters when they compare strings, if the +locale's codeset is UTF-8, as in \"en_US.UTF-8\". Binding this option +to a non-nil value will achieve a similar effect on MS-Windows, where +locales with UTF-8 codeset are not supported. + +Note that setting this to non-nil will also ignore blanks and symbols +in the strings. So do NOT use this option when comparing file names +for equality, only when you need to sort them. */); + Vw32_collate_ignore_punctuation = Qnil; + staticpro (&Vw32_valid_locale_ids); staticpro (&Vw32_valid_codepages); } |