]> code.delx.au - gnu-emacs/blobdiff - src/w32proc.c
Minor tweaks of copying text properties when padding strings
[gnu-emacs] / src / w32proc.c
index 7d982f831e259a30c3d99408dafda882e2ced14b..11a121f7c0928f398be0d3b9333ffb10bf3ae884 100644 (file)
@@ -1,13 +1,13 @@
 /* Process support for GNU Emacs on the Microsoft Windows API.
 
 /* Process support for GNU Emacs on the Microsoft Windows API.
 
-Copyright (C) 1992, 1995, 1999-2015 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
 
 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
 
 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 <http://www.gnu.org/licenses/>.  */
 #include <ctype.h>
 #include <io.h>
 #include <fcntl.h>
 #include <ctype.h>
 #include <io.h>
 #include <fcntl.h>
+#include <unistd.h>
 #include <signal.h>
 #include <sys/file.h>
 #include <mbstring.h>
 #include <signal.h>
 #include <sys/file.h>
 #include <mbstring.h>
@@ -44,11 +45,6 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #undef kill
 
 #include <windows.h>
 #undef kill
 
 #include <windows.h>
-#if defined(__GNUC__) && !defined(__MINGW64__)
-/* This definition is missing from mingw.org headers, but not MinGW64
-   headers. */
-extern BOOL WINAPI IsValidLocale (LCID, DWORD);
-#endif
 
 #ifdef HAVE_LANGINFO_CODESET
 #include <nl_types.h>
 
 #ifdef HAVE_LANGINFO_CODESET
 #include <nl_types.h>
@@ -59,12 +55,9 @@ extern BOOL WINAPI IsValidLocale (LCID, DWORD);
 #include "w32.h"
 #include "w32common.h"
 #include "w32heap.h"
 #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 "syssignal.h"
 #include "w32term.h"
-#include "dispextern.h"                /* for xstrcasecmp */
 #include "coding.h"
 
 #define RVA_TO_PTR(var,section,filedata) \
 #include "coding.h"
 
 #define RVA_TO_PTR(var,section,filedata) \
@@ -72,6 +65,10 @@ extern BOOL WINAPI IsValidLocale (LCID, DWORD);
            + ((DWORD_PTR)(var) - (section)->VirtualAddress)            \
            + (filedata).file_base))
 
            + ((DWORD_PTR)(var) - (section)->VirtualAddress)            \
            + (filedata).file_base))
 
+extern BOOL g_b_init_compare_string_w;
+int sys_select (int, SELECT_TYPE *, SELECT_TYPE *, SELECT_TYPE *,
+               struct timespec *, void *);
+
 /* Signal handlers...SIG_DFL == 0 so this is initialized correctly.  */
 static signal_handler sig_handlers[NSIG];
 
 /* Signal handlers...SIG_DFL == 0 so this is initialized correctly.  */
 static signal_handler sig_handlers[NSIG];
 
@@ -806,7 +803,7 @@ alarm (int seconds)
    etc.
 
    Both these arrays reference each other: there's a member of
    etc.
 
    Both these arrays reference each other: there's a member of
-   child_process structure that records the file corresponding
+   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.
 
    descriptor, and there's a member of filedesc structure that holds a
    pointer to the corresponding child_process.
 
@@ -817,13 +814,13 @@ alarm (int seconds)
    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
    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 will then fail with EMFILE or EAGAIN.)
+   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
 
    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 'select' emulation in sys_select, as follows:
+   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
 
      . Initially, the reader thread is waiting for the char_consumed
        event to become signaled by sys_select, which is an indication
@@ -841,8 +838,8 @@ alarm (int seconds)
 
    When the subprocess exits or the network/serial stream is closed,
    the reader thread sets the status accordingly and exits.  It also
 
    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 ststus to STATUS_READ_ERROR
-   and/or the char_avail and char_consumed event handles are NULL;
+   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.
    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.
@@ -863,8 +860,8 @@ alarm (int seconds)
 
    If file descriptor zero (stdin) doesn't have its bit set in the
    'rfds' argument to sys_select, the function always watches for
 
    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 return when the user presses
-   C-g.
+   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
 
    Having collected the handles to watch, sys_select calls
    WaitForMultipleObjects to wait for any one of them to become
@@ -1527,22 +1524,25 @@ waitpid (pid_t pid, int *status, int options)
 
 /* Implementation note: This function works with file names encoded in
    the current ANSI codepage.  */
 
 /* 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,
 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 * 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;
 
   /* 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))
   *is_gui_app = FALSE;
 
   if (!open_input_file (&executable, filename))
-    return;
+    return -1;
 
   p = strrchr (filename, '.');
 
 
   p = strrchr (filename, '.');
 
@@ -1560,7 +1560,8 @@ w32_executable_type (char * filename,
         extension, which is defined in the registry.  */
       p = egetenv ("COMSPEC");
       if (p)
         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
     {
     }
   else
     {
@@ -1613,29 +1614,40 @@ w32_executable_type (char * filename,
 #endif
           if (data_dir)
             {
 #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_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++)
                 {
 
               for ( ; imports->Name; imports++)
                 {
+                 IMAGE_SECTION_HEADER * section =
+                   rva_to_section (imports->Name, nt_header);
                   char * dllname = RVA_TO_PTR (imports->Name, section,
                                                executable);
 
                   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;
                     }
                   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;
+                   }
                 }
             }
        }
                 }
             }
        }
@@ -1643,6 +1655,7 @@ w32_executable_type (char * filename,
 
 unwind:
   close_file_data (&executable);
 
 unwind:
   close_file_data (&executable);
+  return retval;
 }
 
 static int
 }
 
 static int
@@ -1701,7 +1714,7 @@ sys_spawnve (int mode, char *cmdname, char **argv, char **envp)
   int arglen, numenv;
   pid_t pid;
   child_process *cp;
   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.  */
   int do_quoting = 0;
   /* We pass our process ID to our children by setting up an environment
      variable in their environment.  */
@@ -1712,10 +1725,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.
      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.  */
      so this list is conditionally modified below.  */
-  char *sepchars = " \t*?";
-  /* This is for native w32 apps; modified below for Cygwin apps.  */
+  const char *sepchars = " \t*?";
+  /* This is for native w32 apps; modified below for Cygwin/MSUS apps.  */
   char escape_char = '\\';
   char cmdname_a[MAX_PATH];
 
   char escape_char = '\\';
   char cmdname_a[MAX_PATH];
 
@@ -1732,20 +1745,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)
     {
      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;
       program = build_string (cmdname);
       full = Qnil;
-      GCPRO1 (program);
       openp (Vexec_path, program, Vexec_suffixes, &full, make_number (X_OK), 0);
       openp (Vexec_path, program, Vexec_suffixes, &full, make_number (X_OK), 0);
-      UNGCPRO;
       if (NILP (full))
        {
          errno = EINVAL;
          return -1;
        }
       program = ENCODE_FILE (full);
       if (NILP (full))
        {
          errno = EINVAL;
          return -1;
        }
       program = ENCODE_FILE (full);
-      cmdname = SDATA (program);
+      cmdname = SSDATA (program);
     }
   else
     {
     }
   else
     {
@@ -1767,7 +1776,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.  */
   /* 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;
     {
       errno = ENOENT;
       return -1;
@@ -1776,15 +1785,17 @@ sys_spawnve (int mode, char *cmdname, char **argv, char **envp)
   cmdname = cmdname_a;
   argv[0] = cmdname;
 
   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.  */
 
      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,
 
   /* On Windows 95, if cmdname is a DOS app, we invoke a helper
      application to start it by specifying the helper app as cmdname,
@@ -1795,9 +1806,27 @@ sys_spawnve (int mode, char *cmdname, char **argv, char **envp)
 
       cmdname = alloca (MAX_PATH);
       if (egetenv ("CMDPROXY"))
 
       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
       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.  */
 
       /* Can't use unixtodos_filename here, since that needs its file
         name argument encoded in UTF-8.  */
@@ -1844,10 +1873,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
       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 '";
 
   if (escape_char == '"')
     sepchars = "\r\n\t\f '";
 
@@ -1865,7 +1894,7 @@ sys_spawnve (int mode, char *cmdname, char **argv, char **envp)
       for ( ; *p; p++)
        {
          if (escape_char == '"' && *p == '\\')
       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 == '"')
            {
            arglen++;
          else if (*p == '"')
            {
@@ -2032,10 +2061,11 @@ sys_spawnve (int mode, char *cmdname, char **argv, char **envp)
   return pid;
 }
 
   return pid;
 }
 
-/* Emulate the select call
+/* Emulate the select call.
    Wait for available input on any of the given rfds, or timeout if
    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
 
    For simplicity, we detect the death of child processes here and
    synchronously call the SIGCHLD handler.  Since it is possible for
@@ -2147,7 +2177,7 @@ sys_select (int nfds, SELECT_TYPE *rfds, SELECT_TYPE *wfds, SELECT_TYPE *efds,
            cp = fd_info[i].cp;
            if (FD_ISSET (i, &owfds)
                && cp
            cp = fd_info[i].cp;
            if (FD_ISSET (i, &owfds)
                && cp
-               && (fd_info[i].flags && FILE_CONNECT) == 0)
+               && (fd_info[i].flags & FILE_CONNECT) == 0)
              {
                DebPrint (("sys_select: fd %d is in wfds, but FILE_CONNECT is reset!\n", i));
                cp = NULL;
              {
                DebPrint (("sys_select: fd %d is in wfds, but FILE_CONNECT is reset!\n", i));
                cp = NULL;
@@ -2784,7 +2814,6 @@ set_process_dir (char * dir)
 /* From w32.c */
 extern HANDLE winsock_lib;
 extern BOOL term_winsock (void);
 /* From w32.c */
 extern HANDLE winsock_lib;
 extern BOOL term_winsock (void);
-extern BOOL init_winsock (int load_now);
 
 DEFUN ("w32-has-winsock", Fw32_has_winsock, Sw32_has_winsock, 0, 1, 0,
        doc: /* Test for presence of the Windows socket library `winsock'.
 
 DEFUN ("w32-has-winsock", Fw32_has_winsock, Sw32_has_winsock, 0, 1, 0,
        doc: /* Test for presence of the Windows socket library `winsock'.
@@ -2849,7 +2878,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.  */
   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;
 
                              shortname, MAX_PATH) == 0)
     return Qnil;
 
@@ -2879,7 +2908,7 @@ All path elements in FILENAME are converted to their long names.  */)
   /* first expand it.  */
   filename = Fexpand_file_name (filename, Qnil);
 
   /* 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;
 
                              MAX_UTF8_PATH))
     return Qnil;
 
@@ -2946,6 +2975,59 @@ If successful, the return value is t, otherwise nil.  */)
   return result;
 }
 
   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 *
 #ifdef HAVE_LANGINFO_CODESET
 /* Emulation of nl_langinfo.  Used in fns.c:Flocale_info.  */
 char *
@@ -3256,16 +3338,16 @@ yield nil.  */)
   (Lisp_Object cp)
 {
   CHARSETINFO info;
   (Lisp_Object cp)
 {
   CHARSETINFO info;
-  DWORD dwcp;
+  DWORD_PTR dwcp;
 
   CHECK_NUMBER (cp);
 
   if (!IsValidCodePage (XINT (cp)))
     return Qnil;
 
 
   CHECK_NUMBER (cp);
 
   if (!IsValidCodePage (XINT (cp)))
     return Qnil;
 
-  /* Going through a temporary DWORD variable avoids compiler warning
+  /* Going through a temporary DWORD_PTR variable avoids compiler warning
      about cast to pointer from integer of different size, when
      about cast to pointer from integer of different size, when
-     building --with-wide-int.  */
+     building --with-wide-int or building for 64bit.  */
   dwcp = XINT (cp);
   if (TranslateCharsetInfo ((DWORD *) dwcp, &info, TCI_SRCCODEPAGE))
     return make_number (info.ciCharset);
   dwcp = XINT (cp);
   if (TranslateCharsetInfo ((DWORD *) dwcp, &info, TCI_SRCCODEPAGE))
     return make_number (info.ciCharset);
@@ -3421,13 +3503,16 @@ get_lcid (const char *locale_name)
   return found_lcid;
 }
 
   return found_lcid;
 }
 
-#ifndef _NSLCMPERROR
-# define _NSLCMPERROR INT_MAX
+#ifndef _NLSCMPERROR
+# define _NLSCMPERROR INT_MAX
 #endif
 #ifndef LINGUISTIC_IGNORECASE
 # define LINGUISTIC_IGNORECASE  0x00000010
 #endif
 
 #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)
 int
 w32_compare_strings (const char *s1, const char *s2, char *locname,
                     int ignore_case)
@@ -3435,8 +3520,7 @@ w32_compare_strings (const char *s1, const char *s2, char *locname,
   LCID lcid = GetThreadLocale ();
   wchar_t *string1_w, *string2_w;
   int val, needed;
   LCID lcid = GetThreadLocale ();
   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;
   DWORD flags = 0;
 
   USE_SAFE_ALLOCA;
@@ -3452,14 +3536,15 @@ w32_compare_strings (const char *s1, const char *s2, char *locname,
     {
       if (os_subtype == OS_9X)
        {
     {
       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.  */
          if (!pCompareStringW)
            {
              errno = EINVAL;
              /* This return value is compatible with wcscoll and
                 other MS CRT functions.  */
-             return _NSLCMPERROR;
+             return _NLSCMPERROR;
            }
        }
       else
            }
        }
       else
@@ -3478,7 +3563,7 @@ w32_compare_strings (const char *s1, const char *s2, char *locname,
   else
     {
       errno = EINVAL;
   else
     {
       errno = EINVAL;
-      return _NSLCMPERROR;
+      return _NLSCMPERROR;
     }
 
   needed = pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, s2, -1, NULL, 0);
     }
 
   needed = pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, s2, -1, NULL, 0);
@@ -3492,7 +3577,7 @@ w32_compare_strings (const char *s1, const char *s2, char *locname,
     {
       SAFE_FREE ();
       errno = EINVAL;
     {
       SAFE_FREE ();
       errno = EINVAL;
-      return _NSLCMPERROR;
+      return _NLSCMPERROR;
     }
 
   if (locname)
     }
 
   if (locname)
@@ -3529,7 +3614,7 @@ w32_compare_strings (const char *s1, const char *s2, char *locname,
   if (!val)
     {
       errno = EINVAL;
   if (!val)
     {
       errno = EINVAL;
-      return _NSLCMPERROR;
+      return _NLSCMPERROR;
     }
   return val - 2;
 }
     }
   return val - 2;
 }
@@ -3540,6 +3625,9 @@ syms_of_ntproc (void)
 {
   DEFSYM (Qhigh, "high");
   DEFSYM (Qlow, "low");
 {
   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);
 
   defsubr (&Sw32_has_winsock);
   defsubr (&Sw32_unload_winsock);
@@ -3547,6 +3635,7 @@ syms_of_ntproc (void)
   defsubr (&Sw32_short_file_name);
   defsubr (&Sw32_long_file_name);
   defsubr (&Sw32_set_process_priority);
   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);
   defsubr (&Sw32_get_locale_info);
   defsubr (&Sw32_get_current_locale_id);
   defsubr (&Sw32_get_default_locale_id);
@@ -3611,6 +3700,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;
 
 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.
   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.