/* Process support for GNU Emacs on the Microsoft Windows API.
- Copyright (C) 1992, 1995, 1999-2013 Free Software Foundation, Inc.
+
+Copyright (C) 1992, 1995, 1999-2014 Free Software Foundation, Inc.
This file is part of GNU Emacs.
#include <fcntl.h>
#include <signal.h>
#include <sys/file.h>
+#include <mbstring.h>
/* must include CRT headers *before* config.h */
#include <config.h>
#undef kill
#include <windows.h>
-#ifdef __GNUC__
-/* This definition is missing from mingw32 headers. */
+#if defined(__GNUC__) && !defined(__MINGW64__)
+/* This definition is missing from mingw.org headers, but not MinGW64
+ headers. */
extern BOOL WINAPI IsValidLocale (LCID, DWORD);
#endif
static int
start_timer_thread (int which)
{
- DWORD exit_code;
+ DWORD exit_code, tid;
HANDLE th;
struct itimer_data *itimer =
(which == ITIMER_REAL) ? &real_itimer : &prof_itimer;
the way of threads we start to wait for subprocesses. See also
new_child below. */
itimer->timer_thread = CreateThread (NULL, 64 * 1024, timer_loop,
- (void *)itimer, 0x00010000, NULL);
+ (void *)itimer, 0x00010000, &tid);
if (!itimer->timer_thread)
{
return 0;
}
-/* To avoid Emacs changing directory, we just record here the directory
- the new process should start in. This is set just before calling
- sys_spawnve, and is not generally valid at any other time. */
+/* To avoid Emacs changing directory, we just record here the
+ directory the new process should start in. This is set just before
+ calling sys_spawnve, and is not generally valid at any other time.
+ Note that this directory's name is UTF-8 encoded. */
static char * process_dir;
static BOOL
create_child (char *exe, char *cmdline, char *env, int is_gui_app,
- int * pPid, child_process *cp)
+ pid_t * pPid, child_process *cp)
{
STARTUPINFO start;
SECURITY_ATTRIBUTES sec_attrs;
SECURITY_DESCRIPTOR sec_desc;
#endif
DWORD flags;
- char dir[ MAXPATHLEN ];
+ char dir[ MAX_PATH ];
+ char *p;
if (cp == NULL) emacs_abort ();
sec_attrs.lpSecurityDescriptor = NULL /* &sec_desc */;
sec_attrs.bInheritHandle = FALSE;
- strcpy (dir, process_dir);
- unixtodos_filename (dir);
+ filename_to_ansi (process_dir, dir);
+ /* Can't use unixtodos_filename here, since that needs its file name
+ argument encoded in UTF-8. OTOH, process_dir, which _is_ in
+ UTF-8, points, to the directory computed by our caller, and we
+ don't want to modify that, either. */
+ for (p = dir; *p; p = CharNextA (p))
+ if (*p == '/')
+ *p = '\\';
flags = (!NILP (Vw32_start_process_share_console)
? CREATE_NEW_PROCESS_GROUP
: CREATE_NEW_CONSOLE);
if (NILP (Vw32_start_process_inherit_error_mode))
flags |= CREATE_DEFAULT_ERROR_MODE;
- if (!CreateProcess (exe, cmdline, &sec_attrs, NULL, TRUE,
- flags, env, dir, &start, &cp->procinfo))
+ if (!CreateProcessA (exe, cmdline, &sec_attrs, NULL, TRUE,
+ flags, env, dir, &start, &cp->procinfo))
goto EH_Fail;
cp->pid = (int) cp->procinfo.dwProcessId;
# define IMAGE_OPTIONAL_HEADER32 IMAGE_OPTIONAL_HEADER
#endif
+/* Implementation note: This function works with file names encoded in
+ the current ANSI codepage. */
static void
w32_executable_type (char * filename,
int * is_dos_app,
char *sepchars = " \t*?";
/* This is for native w32 apps; modified below for Cygwin apps. */
char escape_char = '\\';
+ char cmdname_a[MAX_PATH];
/* We don't care about the other modes */
if (mode != _P_NOWAIT)
return -1;
}
- /* Handle executable names without an executable suffix. */
- program = build_string (cmdname);
- if (NILP (Ffile_executable_p (program)))
+ /* Handle executable names without an executable suffix. The caller
+ already searched exec-path and verified the file is executable,
+ but start-process doesn't do that for file names that are already
+ 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));
+ openp (Vexec_path, program, Vexec_suffixes, &full, make_number (X_OK), 0);
UNGCPRO;
if (NILP (full))
{
errno = EINVAL;
return -1;
}
- program = full;
+ program = ENCODE_FILE (full);
+ cmdname = SDATA (program);
}
/* make sure argv[0] and cmdname are both in DOS format */
- cmdname = SDATA (program);
unixtodos_filename (cmdname);
+ /* argv[0] was encoded by caller using ENCODE_FILE, so it is in
+ UTF-8. All the other arguments are encoded by ENCODE_SYSTEM or
+ some such, and are in some ANSI codepage. We need to have
+ argv[0] encoded in ANSI codepage. */
+ filename_to_ansi (cmdname, cmdname_a);
+ /* 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, "?"))
+ {
+ errno = ENOENT;
+ return -1;
+ }
+ /* From here on, CMDNAME is an ANSI-encoded string. */
+ cmdname = cmdname_a;
argv[0] = cmdname;
/* Determine whether program is a 16-bit DOS executable, or a 32-bit Windows
while leaving the real app name as argv[0]. */
if (is_dos_app)
{
- cmdname = alloca (MAXPATHLEN);
+ char *p;
+
+ cmdname = alloca (MAX_PATH);
if (egetenv ("CMDPROXY"))
strcpy (cmdname, egetenv ("CMDPROXY"));
else
strcpy (cmdname, SDATA (Vinvocation_directory));
strcat (cmdname, "cmdproxy.exe");
}
- unixtodos_filename (cmdname);
+
+ /* Can't use unixtodos_filename here, since that needs its file
+ name argument encoded in UTF-8. */
+ for (p = cmdname; *p; p = CharNextA (p))
+ if (*p == '/')
+ *p = '\\';
}
/* we have to do some conjuring here to put argv and envp into the
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
FD_ZERO (rfds);
nr = 0;
- /* Always wait on interrupt_handle, to detect C-g (quit). */
- wait_hnd[0] = interrupt_handle;
- fdindex[0] = -1;
+ /* If interrupt_handle is available and valid, always wait on it, to
+ detect C-g (quit). */
+ nh = 0;
+ if (interrupt_handle && interrupt_handle != INVALID_HANDLE_VALUE)
+ {
+ wait_hnd[0] = interrupt_handle;
+ fdindex[0] = -1;
+ nh++;
+ }
/* Build a list of pipe handles to wait on. */
- nh = 1;
for (i = 0; i < nfds; i++)
if (FD_ISSET (i, &orfds))
{
FD_SET (i, rfds);
return 1;
}
+ else if (noninteractive)
+ {
+ if (handle_file_notifications (NULL))
+ return 1;
+ }
}
else
{
{
if (timeout)
Sleep (timeout_ms);
+ if (noninteractive)
+ {
+ if (handle_file_notifications (NULL))
+ return 1;
+ }
return 0;
}
}
else if (active == WAIT_TIMEOUT)
{
+ if (noninteractive)
+ {
+ if (handle_file_notifications (NULL))
+ return 1;
+ }
return 0;
}
else if (active >= WAIT_OBJECT_0
break;
} while (active < nh + nc);
+ if (noninteractive)
+ {
+ if (handle_file_notifications (NULL))
+ nr++;
+ }
+
/* If no input has arrived and timeout hasn't expired, wait again. */
if (nr == 0)
{
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];
{
while (--num_layouts >= 0)
{
- DWORD kl = (DWORD) layouts[num_layouts];
+ HKL kl = layouts[num_layouts];
- obj = Fcons (Fcons (make_number (kl & 0xffff),
- make_number ((kl >> 16) & 0xffff)),
+ obj = Fcons (Fcons (make_number (LOWORD (kl)),
+ make_number (HIWORD (kl))),
obj);
}
}
The return value is the cons of the language id and the layout id. */)
(void)
{
- DWORD kl = (DWORD) GetKeyboardLayout (dwWindowsThreadId);
+ HKL kl = GetKeyboardLayout (dwWindowsThreadId);
- return Fcons (make_number (kl & 0xffff),
- make_number ((kl >> 16) & 0xffff));
+ return Fcons (make_number (LOWORD (kl)),
+ make_number (HIWORD (kl)));
}
If successful, the new layout id is returned, otherwise nil. */)
(Lisp_Object layout)
{
- DWORD kl;
+ HKL kl;
CHECK_CONS (layout);
CHECK_NUMBER_CAR (layout);
CHECK_NUMBER_CDR (layout);
- kl = (XINT (XCAR (layout)) & 0xffff)
- | (XINT (XCDR (layout)) << 16);
+ kl = (HKL) ((XINT (XCAR (layout)) & 0xffff)
+ | (XINT (XCDR (layout)) << 16));
/* Synchronize layout with input thread. */
if (dwWindowsThreadId)
return Qnil;
}
}
- else if (!ActivateKeyboardLayout ((HKL) kl, 0))
+ else if (!ActivateKeyboardLayout (kl, 0))
return Qnil;
return Fw32_get_keyboard_layout ();
void
syms_of_ntproc (void)
{
+#include "w32proc.x"
+
DEFSYM (Qhigh, "high");
DEFSYM (Qlow, "low");
- defsubr (&Sw32_has_winsock);
- defsubr (&Sw32_unload_winsock);
-
- defsubr (&Sw32_short_file_name);
- defsubr (&Sw32_long_file_name);
- defsubr (&Sw32_set_process_priority);
- defsubr (&Sw32_get_locale_info);
- defsubr (&Sw32_get_current_locale_id);
- defsubr (&Sw32_get_default_locale_id);
- defsubr (&Sw32_get_valid_locale_ids);
- defsubr (&Sw32_set_current_locale);
-
- defsubr (&Sw32_get_console_codepage);
- defsubr (&Sw32_set_console_codepage);
- defsubr (&Sw32_get_console_output_codepage);
- defsubr (&Sw32_set_console_output_codepage);
- defsubr (&Sw32_get_valid_codepages);
- defsubr (&Sw32_get_codepage_charset);
-
- defsubr (&Sw32_get_valid_keyboard_layouts);
- defsubr (&Sw32_get_keyboard_layout);
- defsubr (&Sw32_set_keyboard_layout);
-
DEFVAR_LISP ("w32-quote-process-args", Vw32_quote_process_args,
doc: /* Non-nil enables quoting of process arguments to ensure correct parsing.
Because Windows does not directly pass argv arrays to child processes,