X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/1505643bb70ce66e86d6c72902fe7e9199e93606..5f375723216bdf0519316db1d2acf464b80a708f:/src/w32proc.c?ds=inline diff --git a/src/w32proc.c b/src/w32proc.c index c571726d70..4a6f786280 100644 --- a/src/w32proc.c +++ b/src/w32proc.c @@ -1,13 +1,13 @@ /* Process support for GNU Emacs on the Microsoft Windows API. -Copyright (C) 1992, 1995, 1999-2014 Free Software Foundation, Inc. +Copyright (C) 1992, 1995, 1999-2016 Free Software Foundation, Inc. This file is part of GNU Emacs. GNU Emacs is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. +the Free Software Foundation, either version 3 of the License, or (at +your option) any later version. GNU Emacs is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -29,6 +29,7 @@ along with GNU Emacs. If not, see . */ #include #include #include +#include #include #include #include @@ -59,12 +60,9 @@ extern BOOL WINAPI IsValidLocale (LCID, DWORD); #include "w32.h" #include "w32common.h" #include "w32heap.h" -#include "systime.h" -#include "syswait.h" -#include "process.h" +#include "syswait.h" /* for WNOHANG */ #include "syssignal.h" #include "w32term.h" -#include "dispextern.h" /* for xstrcasecmp */ #include "coding.h" #define RVA_TO_PTR(var,section,filedata) \ @@ -72,8 +70,6 @@ extern BOOL WINAPI IsValidLocale (LCID, DWORD); + ((DWORD_PTR)(var) - (section)->VirtualAddress) \ + (filedata).file_base)) -Lisp_Object Qhigh, Qlow; - /* Signal handlers...SIG_DFL == 0 so this is initialized correctly. */ static signal_handler sig_handlers[NSIG]; @@ -788,6 +784,138 @@ alarm (int seconds) #endif } + + +/* Here's an overview of how support for subprocesses and + network/serial streams is implemented on MS-Windows. + + The management of both subprocesses and network/serial streams + circles around the child_procs[] array, which can record up to the + grand total of MAX_CHILDREN (= 32) of these. (The reasons for the + 32 limitation will become clear below.) Each member of + child_procs[] is a child_process structure, defined on w32.h. + + A related data structure is the fd_info[] array, which holds twice + as many members, 64, and records the information about file + descriptors used for communicating with subprocesses and + network/serial devices. Each member of the array is the filedesc + structure, which records the Windows handle for communications, + such as the read end of the pipe to a subprocess, a socket handle, + etc. + + Both these arrays reference each other: there's a member of + child_process structure that records the corresponding file + descriptor, and there's a member of filedesc structure that holds a + pointer to the corresponding child_process. + + Whenever Emacs starts a subprocess or opens a network/serial + stream, the function new_child is called to prepare a new + child_process structure. new_child looks for the first vacant slot + in the child_procs[] array, initializes it, and starts a "reader + thread" that will watch the output of the subprocess/stream and its + status. (If no vacant slot can be found, new_child returns a + failure indication to its caller, and the higher-level Emacs + primitive that called it will then fail with EMFILE or EAGAIN.) + + The reader thread started by new_child communicates with the main + (a.k.a. "Lisp") thread via two event objects and a status, all of + them recorded by the members of the child_process structure in + child_procs[]. The event objects serve as semaphores between the + reader thread and the 'pselect' emulation in sys_select, as follows: + + . Initially, the reader thread is waiting for the char_consumed + event to become signaled by sys_select, which is an indication + for the reader thread to go ahead and try reading more stuff + from the subprocess/stream. + + . The reader thread then attempts to read by calling a + blocking-read function. When the read call returns, either + successfully or with some failure indication, the reader thread + updates the status of the read accordingly, and signals the 2nd + event object, char_avail, on whose handle sys_select is + waiting. This tells sys_select that the file descriptor + allocated for the subprocess or the the stream is ready to be + read from. + + When the subprocess exits or the network/serial stream is closed, + the reader thread sets the status accordingly and exits. It also + exits when the main thread sets the status to STATUS_READ_ERROR + and/or the char_avail and char_consumed event handles become NULL; + this is how delete_child, called by Emacs when a subprocess or a + stream is terminated, terminates the reader thread as part of + deleting the child_process object. + + The sys_select function emulates the Posix 'pselect' function; it + is needed because the Windows 'select' function supports only + network sockets, while Emacs expects 'pselect' to work for any file + descriptor, including pipes and serial streams. + + When sys_select is called, it uses the information in fd_info[] + array to convert the file descriptors which it was asked to watch + into Windows handles. In general, the handle to watch is the + handle of the char_avail event of the child_process structure that + corresponds to the file descriptor. In addition, for subprocesses, + sys_select watches one more handle: the handle for the subprocess, + so that it could emulate the SIGCHLD signal when the subprocess + exits. + + If file descriptor zero (stdin) doesn't have its bit set in the + 'rfds' argument to sys_select, the function always watches for + keyboard interrupts, to be able to interrupt the wait and return + when the user presses C-g. + + Having collected the handles to watch, sys_select calls + WaitForMultipleObjects to wait for any one of them to become + signaled. Since WaitForMultipleObjects can only watch up to 64 + handles, Emacs on Windows is limited to maximum 32 child_process + objects (since a subprocess consumes 2 handles to be watched, see + above). + + When any of the handles become signaled, sys_select does whatever + is appropriate for the corresponding child_process object: + + . If it's a handle to the char_avail event, sys_select marks the + corresponding bit in 'rfds', and Emacs will then read from that + file descriptor. + + . If it's a handle to the process, sys_select calls the SIGCHLD + handler, to inform Emacs of the fact that the subprocess + exited. + + The waitpid emulation works very similar to sys_select, except that + it only watches handles of subprocesses, and doesn't synchronize + with the reader thread. + + Because socket descriptors on Windows are handles, while Emacs + expects them to be file descriptors, all low-level I/O functions, + such as 'read' and 'write', and all socket operations, like + 'connect', 'recvfrom', 'accept', etc., are redirected to the + corresponding 'sys_*' functions, which must convert a file + descriptor to a handle using the fd_info[] array, and then invoke + the corresponding Windows API on the handle. Most of these + redirected 'sys_*' functions are implemented on w32.c. + + When the file descriptor was produced by functions such as 'open', + the corresponding handle is obtained by calling _get_osfhandle. To + produce a file descriptor for a socket handle, which has no file + descriptor as far as Windows is concerned, the function + socket_to_fd opens the null device; the resulting file descriptor + will never be used directly in any I/O API, but serves as an index + into the fd_info[] array, where the socket handle is stored. The + SOCK_HANDLE macro retrieves the handle when given the file + descriptor. + + The function sys_kill emulates the Posix 'kill' functionality to + terminate other processes. It does that by attaching to the + foreground window of the process and sending a Ctrl-C or Ctrl-BREAK + signal to the process; if that doesn't work, then it calls + TerminateProcess to forcibly terminate the process. Note that this + only terminates the immediate process whose PID was passed to + sys_kill; it doesn't terminate the child processes of that process. + This means, for example, that an Emacs subprocess run through a + shell might not be killed, because sys_kill will only terminate the + shell. (In practice, however, such problems are very rare.) */ + /* Defined in which conflicts with the local copy */ #define _P_NOWAIT 1 @@ -1013,7 +1141,9 @@ reader_thread (void *arg) { int rc; - if (cp->fd >= 0 && fd_info[cp->fd].flags & FILE_LISTEN) + if (cp->fd >= 0 && (fd_info[cp->fd].flags & FILE_CONNECT) != 0) + rc = _sys_wait_connect (cp->fd); + else if (cp->fd >= 0 && (fd_info[cp->fd].flags & FILE_LISTEN) != 0) rc = _sys_wait_accept (cp->fd); else rc = _sys_read_ahead (cp->fd); @@ -1033,8 +1163,8 @@ reader_thread (void *arg) return 1; } - if (rc == STATUS_READ_ERROR) - return 1; + if (rc == STATUS_READ_ERROR || rc == STATUS_CONNECT_FAILED) + return 2; /* If the read died, the child has died so let the thread die */ if (rc == STATUS_READ_FAILED) @@ -1395,22 +1525,25 @@ waitpid (pid_t pid, int *status, int options) /* Implementation note: This function works with file names encoded in the current ANSI codepage. */ -static void +static int w32_executable_type (char * filename, int * is_dos_app, int * is_cygnus_app, + int * is_msys_app, int * is_gui_app) { file_data executable; char * p; + int retval = 0; /* Default values in case we can't tell for sure. */ *is_dos_app = FALSE; *is_cygnus_app = FALSE; + *is_msys_app = FALSE; *is_gui_app = FALSE; if (!open_input_file (&executable, filename)) - return; + return -1; p = strrchr (filename, '.'); @@ -1428,7 +1561,8 @@ w32_executable_type (char * filename, extension, which is defined in the registry. */ p = egetenv ("COMSPEC"); if (p) - w32_executable_type (p, is_dos_app, is_cygnus_app, is_gui_app); + retval = w32_executable_type (p, is_dos_app, is_cygnus_app, is_msys_app, + is_gui_app); } else { @@ -1481,29 +1615,40 @@ w32_executable_type (char * filename, #endif if (data_dir) { - /* Look for cygwin.dll in DLL import list. */ + /* Look for Cygwin DLL in the DLL import list. */ IMAGE_DATA_DIRECTORY import_dir = data_dir[IMAGE_DIRECTORY_ENTRY_IMPORT]; - IMAGE_IMPORT_DESCRIPTOR * imports; - IMAGE_SECTION_HEADER * section; - - section = rva_to_section (import_dir.VirtualAddress, nt_header); - imports = RVA_TO_PTR (import_dir.VirtualAddress, section, - executable); + IMAGE_IMPORT_DESCRIPTOR * imports = + RVA_TO_PTR (import_dir.VirtualAddress, + rva_to_section (import_dir.VirtualAddress, + nt_header), + executable); for ( ; imports->Name; imports++) { + IMAGE_SECTION_HEADER * section = + rva_to_section (imports->Name, nt_header); char * dllname = RVA_TO_PTR (imports->Name, section, executable); - /* The exact name of the cygwin dll has changed with - various releases, but hopefully this will be reasonably - future proof. */ + /* The exact name of the Cygwin DLL has changed with + various releases, but hopefully this will be + reasonably future-proof. */ if (strncmp (dllname, "cygwin", 6) == 0) { *is_cygnus_app = TRUE; break; } + else if (strncmp (dllname, "msys-", 5) == 0) + { + /* This catches both MSYS 1.x and MSYS2 + executables (the DLL name is msys-1.0.dll and + msys-2.0.dll, respectively). There doesn't + seem to be a reason to distinguish between + the two, for now. */ + *is_msys_app = TRUE; + break; + } } } } @@ -1511,6 +1656,7 @@ w32_executable_type (char * filename, unwind: close_file_data (&executable); + return retval; } static int @@ -1569,7 +1715,7 @@ sys_spawnve (int mode, char *cmdname, char **argv, char **envp) int arglen, numenv; pid_t pid; child_process *cp; - int is_dos_app, is_cygnus_app, is_gui_app; + int is_dos_app, is_cygnus_app, is_msys_app, is_gui_app; int do_quoting = 0; /* We pass our process ID to our children by setting up an environment variable in their environment. */ @@ -1580,10 +1726,10 @@ sys_spawnve (int mode, char *cmdname, char **argv, char **envp) argument being split into two or more. Arguments with wildcards are also quoted, for consistency with posix platforms, where wildcards are not expanded if we run the program directly without a shell. - Some extra whitespace characters need quoting in Cygwin programs, + Some extra whitespace characters need quoting in Cygwin/MSYS programs, so this list is conditionally modified below. */ char *sepchars = " \t*?"; - /* This is for native w32 apps; modified below for Cygwin apps. */ + /* This is for native w32 apps; modified below for Cygwin/MSUS apps. */ char escape_char = '\\'; char cmdname_a[MAX_PATH]; @@ -1600,20 +1746,16 @@ sys_spawnve (int mode, char *cmdname, char **argv, char **envp) absolute. So we double-check this here, just in case. */ if (faccessat (AT_FDCWD, cmdname, X_OK, AT_EACCESS) != 0) { - struct gcpro gcpro1; - program = build_string (cmdname); full = Qnil; - GCPRO1 (program); openp (Vexec_path, program, Vexec_suffixes, &full, make_number (X_OK), 0); - UNGCPRO; if (NILP (full)) { errno = EINVAL; return -1; } program = ENCODE_FILE (full); - cmdname = SDATA (program); + cmdname = SSDATA (program); } else { @@ -1635,7 +1777,7 @@ sys_spawnve (int mode, char *cmdname, char **argv, char **envp) /* We explicitly require that the command's file name be encodable in the current ANSI codepage, because we will be invoking it via the ANSI APIs. */ - if (_mbspbrk (cmdname_a, "?")) + if (_mbspbrk ((unsigned char *)cmdname_a, (const unsigned char *)"?")) { errno = ENOENT; return -1; @@ -1644,15 +1786,17 @@ sys_spawnve (int mode, char *cmdname, char **argv, char **envp) cmdname = cmdname_a; argv[0] = cmdname; - /* Determine whether program is a 16-bit DOS executable, or a 32-bit Windows - executable that is implicitly linked to the Cygnus dll (implying it - was compiled with the Cygnus GNU toolchain and hence relies on - cygwin.dll to parse the command line - we use this to decide how to - escape quote chars in command line args that must be quoted). + /* Determine whether program is a 16-bit DOS executable, or a 32-bit + Windows executable that is implicitly linked to the Cygnus or + MSYS dll (implying it was compiled with the Cygnus/MSYS GNU + toolchain and hence relies on cygwin.dll or MSYS DLL to parse the + command line - we use this to decide how to escape quote chars in + command line args that must be quoted). Also determine whether it is a GUI app, so that we don't hide its initial window unless specifically requested. */ - w32_executable_type (cmdname, &is_dos_app, &is_cygnus_app, &is_gui_app); + w32_executable_type (cmdname, &is_dos_app, &is_cygnus_app, &is_msys_app, + &is_gui_app); /* On Windows 95, if cmdname is a DOS app, we invoke a helper application to start it by specifying the helper app as cmdname, @@ -1663,9 +1807,27 @@ sys_spawnve (int mode, char *cmdname, char **argv, char **envp) cmdname = alloca (MAX_PATH); if (egetenv ("CMDPROXY")) - strcpy (cmdname, egetenv ("CMDPROXY")); + { + /* Implementation note: since process-environment, where + 'egetenv' looks, is encoded in the system codepage, we + don't need to encode the cmdproxy file name if we get it + from the environment. */ + strcpy (cmdname, egetenv ("CMDPROXY")); + } else - strcpy (lispstpcpy (cmdname, Vinvocation_directory), "cmdproxy.exe"); + { + char *q = lispstpcpy (cmdname, + /* exec-directory needs to be encoded. */ + ansi_encode_filename (Vexec_directory)); + /* If we are run from the source tree, use cmdproxy.exe from + the same source tree. */ + for (p = q - 2; p > cmdname; p = CharPrevA (cmdname, p)) + if (*p == '/') + break; + if (*p == '/' && xstrcasecmp (p, "/lib-src/") == 0) + q = stpcpy (p, "/nt/"); + strcpy (q, "cmdproxy.exe"); + } /* Can't use unixtodos_filename here, since that needs its file name argument encoded in UTF-8. */ @@ -1712,10 +1874,10 @@ sys_spawnve (int mode, char *cmdname, char **argv, char **envp) if (INTEGERP (Vw32_quote_process_args)) escape_char = XINT (Vw32_quote_process_args); else - escape_char = is_cygnus_app ? '"' : '\\'; + escape_char = (is_cygnus_app || is_msys_app) ? '"' : '\\'; } - /* Cygwin apps needs quoting a bit more often. */ + /* Cygwin/MSYS apps need quoting a bit more often. */ if (escape_char == '"') sepchars = "\r\n\t\f '"; @@ -1733,7 +1895,7 @@ sys_spawnve (int mode, char *cmdname, char **argv, char **envp) for ( ; *p; p++) { if (escape_char == '"' && *p == '\\') - /* If it's a Cygwin app, \ needs to be escaped. */ + /* If it's a Cygwin/MSYS app, \ needs to be escaped. */ arglen++; else if (*p == '"') { @@ -1900,10 +2062,11 @@ sys_spawnve (int mode, char *cmdname, char **argv, char **envp) return pid; } -/* Emulate the select call +/* Emulate the select call. Wait for available input on any of the given rfds, or timeout if - a timeout is given and no input is detected - wfds and efds are not supported and must be NULL. + a timeout is given and no input is detected. wfds are supported + only for asynchronous 'connect' calls. efds are not supported + and must be NULL. For simplicity, we detect the death of child processes here and synchronously call the SIGCHLD handler. Since it is possible for @@ -1931,7 +2094,7 @@ int sys_select (int nfds, SELECT_TYPE *rfds, SELECT_TYPE *wfds, SELECT_TYPE *efds, struct timespec *timeout, void *ignored) { - SELECT_TYPE orfds; + SELECT_TYPE orfds, owfds; DWORD timeout_ms, start_time; int i, nh, nc, nr; DWORD active; @@ -1949,15 +2112,27 @@ sys_select (int nfds, SELECT_TYPE *rfds, SELECT_TYPE *wfds, SELECT_TYPE *efds, return 0; } - /* Otherwise, we only handle rfds, so fail otherwise. */ - if (rfds == NULL || wfds != NULL || efds != NULL) + /* Otherwise, we only handle rfds and wfds, so fail otherwise. */ + if ((rfds == NULL && wfds == NULL) || efds != NULL) { errno = EINVAL; return -1; } - orfds = *rfds; - FD_ZERO (rfds); + if (rfds) + { + orfds = *rfds; + FD_ZERO (rfds); + } + else + FD_ZERO (&orfds); + if (wfds) + { + owfds = *wfds; + FD_ZERO (wfds); + } + else + FD_ZERO (&owfds); nr = 0; /* If interrupt_handle is available and valid, always wait on it, to @@ -1972,7 +2147,7 @@ sys_select (int nfds, SELECT_TYPE *rfds, SELECT_TYPE *wfds, SELECT_TYPE *efds, /* Build a list of pipe handles to wait on. */ for (i = 0; i < nfds; i++) - if (FD_ISSET (i, &orfds)) + if (FD_ISSET (i, &orfds) || FD_ISSET (i, &owfds)) { if (i == 0) { @@ -1986,7 +2161,7 @@ sys_select (int nfds, SELECT_TYPE *rfds, SELECT_TYPE *wfds, SELECT_TYPE *efds, /* Check for any emacs-generated input in the queue since it won't be detected in the wait */ - if (detect_input_pending ()) + if (rfds && detect_input_pending ()) { FD_SET (i, rfds); return 1; @@ -2001,6 +2176,13 @@ sys_select (int nfds, SELECT_TYPE *rfds, SELECT_TYPE *wfds, SELECT_TYPE *efds, { /* Child process and socket/comm port input. */ cp = fd_info[i].cp; + if (FD_ISSET (i, &owfds) + && cp + && (fd_info[i].flags & FILE_CONNECT) == 0) + { + DebPrint (("sys_select: fd %d is in wfds, but FILE_CONNECT is reset!\n", i)); + cp = NULL; + } if (cp) { int current_status = cp->status; @@ -2009,6 +2191,8 @@ sys_select (int nfds, SELECT_TYPE *rfds, SELECT_TYPE *wfds, SELECT_TYPE *efds, { /* Tell reader thread which file handle to use. */ cp->fd = i; + /* Zero out the error code. */ + cp->errcode = 0; /* Wake up the reader thread for this process */ cp->status = STATUS_READ_READY; if (!SetEvent (cp->char_consumed)) @@ -2199,7 +2383,7 @@ count_children: if (cp->fd >= 0 && (fd_info[cp->fd].flags & FILE_AT_EOF) == 0) fd_info[cp->fd].flags |= FILE_SEND_SIGCHLD; - /* SIG_DFL for SIGCHLD is ignore */ + /* SIG_DFL for SIGCHLD is ignored */ else if (sig_handlers[SIGCHLD] != SIG_DFL && sig_handlers[SIGCHLD] != SIG_IGN) { @@ -2216,7 +2400,7 @@ count_children: errno = EINTR; return -1; } - else if (fdindex[active] == 0) + else if (rfds && fdindex[active] == 0) { /* Keyboard input available */ FD_SET (0, rfds); @@ -2224,9 +2408,33 @@ count_children: } else { - /* must be a socket or pipe - read ahead should have - completed, either succeeding or failing. */ - FD_SET (fdindex[active], rfds); + /* Must be a socket or pipe - read ahead should have + completed, either succeeding or failing. If this handle + was waiting for an async 'connect', reset the connect + flag, so it could read from now on. */ + if (wfds && (fd_info[fdindex[active]].flags & FILE_CONNECT) != 0) + { + cp = fd_info[fdindex[active]].cp; + if (cp) + { + /* Don't reset the FILE_CONNECT bit and don't + acknowledge the read if the status is + STATUS_CONNECT_FAILED or some other + failure. That's because the thread exits in those + cases, so it doesn't need the ACK, and we want to + keep the FILE_CONNECT bit as evidence that the + connect failed, to be checked in sys_read. */ + if (cp->status == STATUS_READ_SUCCEEDED) + { + fd_info[cp->fd].flags &= ~FILE_CONNECT; + cp->status = STATUS_READ_ACKNOWLEDGED; + } + ResetEvent (cp->char_avail); + } + FD_SET (fdindex[active], wfds); + } + else if (rfds) + FD_SET (fdindex[active], rfds); nr++; } @@ -2672,7 +2880,7 @@ All path elements in FILENAME are converted to their short names. */) filename = Fexpand_file_name (filename, Qnil); /* luckily, this returns the short version of each element in the path. */ - if (w32_get_short_filename (SDATA (ENCODE_FILE (filename)), + if (w32_get_short_filename (SSDATA (ENCODE_FILE (filename)), shortname, MAX_PATH) == 0) return Qnil; @@ -2702,7 +2910,7 @@ All path elements in FILENAME are converted to their long names. */) /* first expand it. */ filename = Fexpand_file_name (filename, Qnil); - if (!w32_get_long_filename (SDATA (ENCODE_FILE (filename)), longname, + if (!w32_get_long_filename (SSDATA (ENCODE_FILE (filename)), longname, MAX_UTF8_PATH)) return Qnil; @@ -2769,6 +2977,59 @@ If successful, the return value is t, otherwise nil. */) return result; } +DEFUN ("w32-application-type", Fw32_application_type, + Sw32_application_type, 1, 1, 0, + doc: /* Return the type of an MS-Windows PROGRAM. + +Knowing the type of an executable could be useful for formatting +file names passed to it or for quoting its command-line arguments. + +PROGRAM should specify an executable file, including the extension. + +The value is one of the following: + +`dos' -- a DOS .com program or some other non-PE executable +`cygwin' -- a Cygwin program that depends on Cygwin DLL +`msys' -- an MSYS 1.x or MSYS2 program +`w32-native' -- a native Windows application +`unknown' -- a file that doesn't exist, or cannot be open, or whose + name is not encodable in the current ANSI codepage. + +Note that for .bat and .cmd batch files the function returns the type +of their command interpreter, as specified by the \"COMSPEC\" +environment variable. + +This function returns `unknown' for programs whose file names +include characters not supported by the current ANSI codepage, as +such programs cannot be invoked by Emacs anyway. */) + (Lisp_Object program) +{ + int is_dos_app, is_cygwin_app, is_msys_app, dummy; + Lisp_Object encoded_progname; + char *progname, progname_a[MAX_PATH]; + + program = Fexpand_file_name (program, Qnil); + encoded_progname = ENCODE_FILE (program); + progname = SSDATA (encoded_progname); + unixtodos_filename (progname); + filename_to_ansi (progname, progname_a); + /* Reject file names that cannot be encoded in the current ANSI + codepage. */ + if (_mbspbrk ((unsigned char *)progname_a, (const unsigned char *)"?")) + return Qunknown; + + if (w32_executable_type (progname_a, &is_dos_app, &is_cygwin_app, + &is_msys_app, &dummy) != 0) + return Qunknown; + if (is_dos_app) + return Qdos; + if (is_cygwin_app) + return Qcygwin; + if (is_msys_app) + return Qmsys; + return Qw32_native; +} + #ifdef HAVE_LANGINFO_CODESET /* Emulation of nl_langinfo. Used in fns.c:Flocale_info. */ char * @@ -3070,17 +3331,27 @@ If successful, the new CP is returned, otherwise nil. */) DEFUN ("w32-get-codepage-charset", Fw32_get_codepage_charset, Sw32_get_codepage_charset, 1, 1, 0, doc: /* Return charset ID corresponding to codepage CP. -Returns nil if the codepage is not valid. */) +Returns nil if the codepage is not valid or its charset ID could +not be determined. + +Note that this function is only guaranteed to work with ANSI +codepages; most console codepages are not supported and will +yield nil. */) (Lisp_Object cp) { CHARSETINFO info; + DWORD_PTR dwcp; CHECK_NUMBER (cp); if (!IsValidCodePage (XINT (cp))) return Qnil; - if (TranslateCharsetInfo ((DWORD *) XINT (cp), &info, TCI_SRCCODEPAGE)) + /* Going through a temporary DWORD_PTR variable avoids compiler warning + about cast to pointer from integer of different size, when + building --with-wide-int or building for 64bit. */ + dwcp = XINT (cp); + if (TranslateCharsetInfo ((DWORD *) dwcp, &info, TCI_SRCCODEPAGE)) return make_number (info.ciCharset); return Qnil; @@ -3139,8 +3410,8 @@ If successful, the new layout id is returned, otherwise nil. */) CHECK_NUMBER_CAR (layout); CHECK_NUMBER_CDR (layout); - kl = (HKL) ((XINT (XCAR (layout)) & 0xffff) - | (XINT (XCDR (layout)) << 16)); + kl = (HKL) (UINT_PTR) ((XINT (XCAR (layout)) & 0xffff) + | (XINT (XCDR (layout)) << 16)); /* Synchronize layout with input thread. */ if (dwWindowsThreadId) @@ -3234,13 +3505,16 @@ get_lcid (const char *locale_name) return found_lcid; } -#ifndef _NSLCMPERROR -# define _NSLCMPERROR INT_MAX +#ifndef _NLSCMPERROR +# define _NLSCMPERROR INT_MAX #endif #ifndef LINGUISTIC_IGNORECASE # define LINGUISTIC_IGNORECASE 0x00000010 #endif +typedef int (WINAPI *CompareStringW_Proc) + (LCID, DWORD, LPCWSTR, int, LPCWSTR, int); + int w32_compare_strings (const char *s1, const char *s2, char *locname, int ignore_case) @@ -3249,7 +3523,7 @@ w32_compare_strings (const char *s1, const char *s2, char *locname, 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); + static CompareStringW_Proc pCompareStringW; DWORD flags = 0; USE_SAFE_ALLOCA; @@ -3265,14 +3539,15 @@ w32_compare_strings (const char *s1, const char *s2, char *locname, { if (os_subtype == OS_9X) { - pCompareStringW = GetProcAddress (LoadLibrary ("Unicows.dll"), - "CompareStringW"); + pCompareStringW = + (CompareStringW_Proc) GetProcAddress (LoadLibrary ("Unicows.dll"), + "CompareStringW"); if (!pCompareStringW) { errno = EINVAL; /* This return value is compatible with wcscoll and other MS CRT functions. */ - return _NSLCMPERROR; + return _NLSCMPERROR; } } else @@ -3291,7 +3566,7 @@ w32_compare_strings (const char *s1, const char *s2, char *locname, else { errno = EINVAL; - return _NSLCMPERROR; + return _NLSCMPERROR; } needed = pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, s2, -1, NULL, 0); @@ -3305,7 +3580,7 @@ w32_compare_strings (const char *s1, const char *s2, char *locname, { SAFE_FREE (); errno = EINVAL; - return _NSLCMPERROR; + return _NLSCMPERROR; } if (locname) @@ -3342,7 +3617,7 @@ w32_compare_strings (const char *s1, const char *s2, char *locname, if (!val) { errno = EINVAL; - return _NSLCMPERROR; + return _NLSCMPERROR; } return val - 2; } @@ -3353,6 +3628,9 @@ syms_of_ntproc (void) { DEFSYM (Qhigh, "high"); DEFSYM (Qlow, "low"); + DEFSYM (Qcygwin, "cygwin"); + DEFSYM (Qmsys, "msys"); + DEFSYM (Qw32_native, "w32-native"); defsubr (&Sw32_has_winsock); defsubr (&Sw32_unload_winsock); @@ -3360,6 +3638,7 @@ syms_of_ntproc (void) defsubr (&Sw32_short_file_name); defsubr (&Sw32_long_file_name); defsubr (&Sw32_set_process_priority); + defsubr (&Sw32_application_type); defsubr (&Sw32_get_locale_info); defsubr (&Sw32_get_current_locale_id); defsubr (&Sw32_get_default_locale_id); @@ -3424,6 +3703,13 @@ of time slices to wait (effectively boosting the priority of the child process temporarily). A value of zero disables waiting entirely. */); w32_pipe_read_delay = 50; + DEFVAR_INT ("w32-pipe-buffer-size", w32_pipe_buffer_size, + doc: /* Size of buffer for pipes created to communicate with subprocesses. +The size is in bytes, and must be non-negative. The default is zero, +which lets the OS use its default size, usually 4KB (4096 bytes). +Any negative value means to use the default value of zero. */); + w32_pipe_buffer_size = 0; + DEFVAR_LISP ("w32-downcase-file-names", Vw32_downcase_file_names, doc: /* Non-nil means convert all-upper case file names to lower case. This applies when performing completions and file name expansion.