Fequal_including_properties fix
[bpt/emacs.git] / src / w32proc.c
index 8458938..13fa24e 100644 (file)
@@ -1,5 +1,6 @@
 /* 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.
 
@@ -21,6 +22,7 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
      Adapted from alarm.c by Tim Fleehart
 */
 
+#include <mingw_time.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <errno.h>
@@ -29,6 +31,7 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include <fcntl.h>
 #include <signal.h>
 #include <sys/file.h>
+#include <mbstring.h>
 
 /* must include CRT headers *before* config.h */
 #include <config.h>
@@ -40,8 +43,9 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #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
 
@@ -562,7 +566,7 @@ init_timers (void)
 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;
@@ -600,7 +604,7 @@ start_timer_thread (int which)
      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)
     {
@@ -860,8 +864,6 @@ new_child (void)
   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);
@@ -910,21 +912,6 @@ delete_child (child_process *cp)
   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)
     {
@@ -990,6 +977,18 @@ find_child_pid (DWORD pid)
   return NULL;
 }
 
+void
+release_listen_threads (void)
+{
+  int i;
+
+  for (i = child_proc_count - 1; i >= 0; i--)
+    {
+      if (CHILD_ACTIVE (&child_procs[i])
+         && (fd_info[child_procs[i].fd].flags & FILE_LISTEN))
+       child_procs[i].status = STATUS_READ_ERROR;
+    }
+}
 
 /* Thread proc for child process and socket reader threads. Each thread
    is normally blocked until woken by select() to check for input by
@@ -1060,14 +1059,15 @@ reader_thread (void *arg)
   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;
@@ -1075,7 +1075,8 @@ create_child (char *exe, char *cmdline, char *env, int is_gui_app,
   SECURITY_DESCRIPTOR sec_desc;
 #endif
   DWORD flags;
-  char dir[ MAXPATHLEN ];
+  char dir[ MAX_PATH ];
+  char *p;
 
   if (cp == NULL) emacs_abort ();
 
@@ -1105,16 +1106,22 @@ create_child (char *exe, char *cmdline, char *env, int is_gui_app,
   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;
@@ -1132,7 +1139,7 @@ create_child (char *exe, char *cmdline, char *env, int is_gui_app,
   return FALSE;
 }
 
-/* create_child doesn't know what emacs' file handle will be for waiting
+/* create_child doesn't know what emacs's file handle will be for waiting
    on output from the child, so we need to make this additional call
    to register the handle with the process
    This way the select emulator knows how to match file handles with
@@ -1169,45 +1176,6 @@ register_child (pid_t pid, int fd)
   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)
@@ -1414,6 +1382,8 @@ waitpid (pid_t pid, int *status, int options)
 # 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,
@@ -1604,6 +1574,7 @@ sys_spawnve (int mode, char *cmdname, char **argv, char **envp)
   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)
@@ -1612,27 +1583,45 @@ sys_spawnve (int mode, char *cmdname, char **argv, char **envp)
       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
@@ -1650,7 +1639,9 @@ sys_spawnve (int mode, char *cmdname, char **argv, char **envp)
      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
@@ -1658,7 +1649,12 @@ sys_spawnve (int mode, char *cmdname, char **argv, char **envp)
          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
@@ -1776,12 +1772,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
@@ -1916,7 +1912,7 @@ extern int proc_buffered_char[];
 
 int
 sys_select (int nfds, SELECT_TYPE *rfds, SELECT_TYPE *wfds, SELECT_TYPE *efds,
-           EMACS_TIME *timeout, void *ignored)
+           struct timespec *timeout, void *ignored)
 {
   SELECT_TYPE orfds;
   DWORD timeout_ms, start_time;
@@ -1947,12 +1943,17 @@ sys_select (int nfds, SELECT_TYPE *rfds, SELECT_TYPE *wfds, SELECT_TYPE *efds,
   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))
       {
@@ -1973,6 +1974,11 @@ sys_select (int nfds, SELECT_TYPE *rfds, SELECT_TYPE *wfds, SELECT_TYPE *efds,
                FD_SET (i, rfds);
                return 1;
              }
+           else if (noninteractive)
+             {
+               if (handle_file_notifications (NULL))
+                 return 1;
+             }
          }
        else
          {
@@ -2073,6 +2079,11 @@ count_children:
     {
       if (timeout)
        Sleep (timeout_ms);
+      if (noninteractive)
+       {
+         if (handle_file_notifications (NULL))
+           return 1;
+       }
       return 0;
     }
 
@@ -2099,6 +2110,11 @@ count_children:
     }
   else if (active == WAIT_TIMEOUT)
     {
+      if (noninteractive)
+       {
+         if (handle_file_notifications (NULL))
+           return 1;
+       }
       return 0;
     }
   else if (active >= WAIT_OBJECT_0
@@ -2205,6 +2221,12 @@ count_children:
          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)
     {
@@ -2227,10 +2249,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];
@@ -2634,10 +2655,11 @@ 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 (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);
@@ -2651,7 +2673,7 @@ If FILENAME does not exist, return nil.
 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);
@@ -2663,10 +2685,11 @@ 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, 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
@@ -2674,7 +2697,7 @@ All path elements in FILENAME are converted to their long names.  */)
   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,
@@ -3061,10 +3084,10 @@ The return value is a list of pairs of language id and layout id.  */)
     {
       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);
        }
     }
@@ -3079,10 +3102,10 @@ DEFUN ("w32-get-keyboard-layout", Fw32_get_keyboard_layout,
 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)));
 }
 
 
@@ -3093,14 +3116,14 @@ The keyboard layout setting affects interpretation of keyboard input.
 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)
@@ -3115,7 +3138,7 @@ If successful, the new layout id is returned, otherwise nil.  */)
            return Qnil;
        }
     }
-  else if (!ActivateKeyboardLayout ((HKL) kl, 0))
+  else if (!ActivateKeyboardLayout (kl, 0))
     return Qnil;
 
   return Fw32_get_keyboard_layout ();
@@ -3125,32 +3148,11 @@ If successful, the new layout id is returned, otherwise nil.  */)
 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,