/* 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)
{
cp->pid = -1;
cp->procinfo.hProcess = NULL;
cp->status = STATUS_READ_ERROR;
- cp->input_file = NULL;
- cp->pending_deletion = 0;
/* use manual reset event so that select() will function properly */
cp->char_avail = CreateEvent (NULL, TRUE, FALSE, NULL);
if (!CHILD_ACTIVE (cp) && cp->procinfo.hProcess == NULL)
return;
- /* Delete the child's temporary input file, if any, that is pending
- deletion. */
- if (cp->input_file)
- {
- if (cp->pending_deletion)
- {
- if (unlink (cp->input_file))
- DebPrint (("delete_child.unlink (%s) failed, errno: %d\n",
- cp->input_file, errno));
- cp->pending_deletion = 0;
- }
- xfree (cp->input_file);
- cp->input_file = NULL;
- }
-
/* reap thread if necessary */
if (cp->thrd)
{
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;
fd_info[fd].cp = cp;
}
-/* Record INFILE as an input file for process PID. */
-void
-record_infile (pid_t pid, char *infile)
-{
- child_process *cp;
-
- /* INFILE should never be NULL, since xstrdup would have signaled
- memory full condition in that case, see callproc.c where this
- function is called. */
- eassert (infile);
-
- cp = find_child_pid ((DWORD)pid);
- if (cp == NULL)
- {
- DebPrint (("record_infile is unable to find pid %lu\n", pid));
- return;
- }
-
- cp->input_file = infile;
-}
-
-/* Mark the input file INFILE of the corresponding subprocess as
- temporary, to be deleted when the subprocess exits. */
-void
-record_pending_deletion (char *infile)
-{
- child_process *cp;
-
- eassert (infile);
-
- for (cp = child_procs + (child_proc_count-1); cp >= child_procs; cp--)
- if (CHILD_ACTIVE (cp)
- && cp->input_file && xstrcasecmp (cp->input_file, infile) == 0)
- {
- cp->pending_deletion = 1;
- break;
- }
-}
-
/* Called from waitpid when a process exits. */
static void
reap_subprocess (child_process *cp)
# 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];
filename = Fexpand_file_name (filename, Qnil);
/* luckily, this returns the short version of each element in the path. */
- if (GetShortPathName (SDATA (ENCODE_FILE (filename)), shortname, MAX_PATH) == 0)
+ if (w32_get_short_filename (SDATA (ENCODE_FILE (filename)),
+ shortname, MAX_PATH) == 0)
return Qnil;
- dostounix_filename (shortname, 0);
+ dostounix_filename (shortname);
/* No need to DECODE_FILE, because 8.3 names are pure ASCII. */
return build_string (shortname);
All path elements in FILENAME are converted to their long names. */)
(Lisp_Object filename)
{
- char longname[ MAX_PATH ];
+ char longname[ MAX_UTF8_PATH ];
int drive_only = 0;
CHECK_STRING (filename);
/* first expand it. */
filename = Fexpand_file_name (filename, Qnil);
- if (!w32_get_long_filename (SDATA (ENCODE_FILE (filename)), longname, MAX_PATH))
+ if (!w32_get_long_filename (SDATA (ENCODE_FILE (filename)), longname,
+ MAX_UTF8_PATH))
return Qnil;
- dostounix_filename (longname, 0);
+ dostounix_filename (longname);
/* If we were passed only a drive, make sure that a slash is not appended
for consistency with directories. Allow for drive mapping via SUBST
if (drive_only && longname[1] == ':' && longname[2] == '/' && !longname[3])
longname[2] = '\0';
- return DECODE_FILE (build_string (longname));
+ return DECODE_FILE (build_unibyte_string (longname));
}
DEFUN ("w32-set-process-priority", Fw32_set_process_priority,
{
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,