Fequal_including_properties fix
[bpt/emacs.git] / src / w32proc.c
index ea16f26..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.
 
@@ -30,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>
@@ -41,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
 
@@ -563,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;
@@ -601,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)
     {
@@ -861,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);
@@ -911,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)
     {
@@ -1073,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;
@@ -1088,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 ();
 
@@ -1118,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;
@@ -1182,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)
@@ -1427,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,
@@ -1617,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)
@@ -1625,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
@@ -1663,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
@@ -1671,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
@@ -1789,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
@@ -1960,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))
       {
@@ -1986,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
          {
@@ -2086,6 +2079,11 @@ count_children:
     {
       if (timeout)
        Sleep (timeout_ms);
+      if (noninteractive)
+       {
+         if (handle_file_notifications (NULL))
+           return 1;
+       }
       return 0;
     }
 
@@ -2112,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
@@ -2218,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)
     {
@@ -2240,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];
@@ -2647,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);
@@ -2664,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);
@@ -2676,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
@@ -2687,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,
@@ -3074,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);
        }
     }
@@ -3092,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)));
 }
 
 
@@ -3106,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)
@@ -3128,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 ();
@@ -3138,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,