Fix doc-string of pop-to-buffer-same-window. (Bug#15492)
[bpt/emacs.git] / src / w32.c
index 0fa5970..1dcf46b 100644 (file)
--- a/src/w32.c
+++ b/src/w32.c
@@ -47,7 +47,6 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #undef fopen
 #undef link
 #undef mkdir
-#undef mktemp
 #undef open
 #undef rename
 #undef rmdir
@@ -65,6 +64,7 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #undef localtime
 
 #include "lisp.h"
+#include "epaths.h"    /* for SHELL */
 
 #include <pwd.h>
 #include <grp.h>
@@ -89,6 +89,21 @@ typedef struct _MEMORY_STATUS_EX {
   DWORDLONG ullAvailExtendedVirtual;
 } MEMORY_STATUS_EX,*LPMEMORY_STATUS_EX;
 
+/* These are here so that GDB would know about these data types.  This
+   allows to attach GDB to Emacs when a fatal exception is triggered
+   and Windows pops up the "application needs to be closed" dialog.
+   At that point, _gnu_exception_handler, the top-level exception
+   handler installed by the MinGW startup code, is somewhere on the
+   call-stack of the main thread, so going to that call frame and
+   looking at the argument to _gnu_exception_handler, which is a
+   PEXCEPTION_POINTERS pointer, can reveal the exception code
+   (excptr->ExceptionRecord->ExceptionCode) and the address where the
+   exception happened (excptr->ExceptionRecord->ExceptionAddress), as
+   well as some additional information specific to the exception.  */
+PEXCEPTION_POINTERS excptr;
+PEXCEPTION_RECORD excprec;
+PCONTEXT ctxrec;
+
 #include <lmcons.h>
 #include <shlobj.h>
 
@@ -232,7 +247,9 @@ static BOOL WINAPI revert_to_self (void);
 extern int sys_access (const char *, int);
 extern void *e_malloc (size_t);
 extern int sys_select (int, SELECT_TYPE *, SELECT_TYPE *, SELECT_TYPE *,
-                      EMACS_TIME *, void *);
+                      struct timespec *, void *);
+extern int sys_dup (int);
+
 
 
 \f
@@ -2018,7 +2035,7 @@ init_environment (char ** argv)
       {"PRELOAD_WINSOCK", NULL},
       {"emacs_dir", "C:/emacs"},
       {"EMACSLOADPATH", NULL},
-      {"SHELL", "%emacs_dir%/bin/cmdproxy.exe"},
+      {"SHELL", "cmdproxy.exe"}, /* perhaps it is somewhere on PATH */
       {"EMACSDATA", NULL},
       {"EMACSPATH", NULL},
       {"INFOPATH", NULL},
@@ -2094,9 +2111,12 @@ init_environment (char ** argv)
        emacs_abort ();
       *p = 0;
 
-      if ((p = _mbsrchr (modname, '\\')) && xstrcasecmp (p, "\\bin") == 0)
+      if ((p = _mbsrchr (modname, '\\'))
+         /* From bin means installed Emacs, from src means uninstalled.  */
+         && (xstrcasecmp (p, "\\bin") == 0 || xstrcasecmp (p, "\\src") == 0))
        {
          char buf[SET_ENV_BUF_SIZE];
+         int within_build_tree = xstrcasecmp (p, "\\src") == 0;
 
          *p = 0;
          for (p = modname; *p; p = CharNext (p))
@@ -2104,6 +2124,15 @@ init_environment (char ** argv)
 
          _snprintf (buf, sizeof (buf)-1, "emacs_dir=%s", modname);
          _putenv (strdup (buf));
+         /* If we are running from the Posix-like build tree, define
+            SHELL to point to our own cmdproxy.  The loop below will
+            then disregard PATH_EXEC and the default value.  */
+         if (within_build_tree)
+           {
+             _snprintf (buf, sizeof (buf) - 1,
+                        "SHELL=%s/nt/cmdproxy.exe", modname);
+             _putenv (strdup (buf));
+           }
        }
       /* Handle running emacs from the build directory: src/oo-spd/i386/  */
 
@@ -2139,16 +2168,60 @@ init_environment (char ** argv)
        if (!getenv (env_vars[i].name))
          {
            int dont_free = 0;
+           char bufc[SET_ENV_BUF_SIZE];
 
            if ((lpval = w32_get_resource (env_vars[i].name, &dwType)) == NULL
                /* Also ignore empty environment variables.  */
                || *lpval == 0)
              {
                xfree (lpval);
-               lpval = env_vars[i].def_value;
-               dwType = REG_EXPAND_SZ;
                dont_free = 1;
-               if (!strcmp (env_vars[i].name, "HOME") && !appdata)
+               if (strcmp (env_vars[i].name, "SHELL") == 0)
+                 {
+                   /* Look for cmdproxy.exe in every directory in
+                      PATH_EXEC.  FIXME: This does not find cmdproxy
+                      in nt/ when we run uninstalled.  */
+                   char fname[MAX_PATH];
+                   const char *pstart = PATH_EXEC, *pend;
+
+                   do {
+                     pend = _mbschr (pstart, ';');
+                     if (!pend)
+                       pend = pstart + strlen (pstart);
+                     /* Be defensive against series of ;;; characters.  */
+                     if (pend > pstart)
+                       {
+                         strncpy (fname, pstart, pend - pstart);
+                         fname[pend - pstart] = '/';
+                         strcpy (&fname[pend - pstart + 1], "cmdproxy.exe");
+                         ExpandEnvironmentStrings ((LPSTR) fname, bufc,
+                                                   sizeof (bufc));
+                         if (check_existing (bufc))
+                           {
+                             lpval = bufc;
+                             dwType = REG_SZ;
+                             break;
+                           }
+                       }
+                     if (*pend)
+                       pstart = pend + 1;
+                     else
+                       pstart = pend;
+                     if (!*pstart)
+                       {
+                         /* If not found in any directory, use the
+                            default as the last resort.  */
+                         lpval = env_vars[i].def_value;
+                         dwType = REG_EXPAND_SZ;
+                       }
+                   } while (*pstart);
+                 }
+               else
+                 {
+                   lpval = env_vars[i].def_value;
+                   dwType = REG_EXPAND_SZ;
+                 }
+               if (strcmp (env_vars[i].name, "HOME") == 0 && !appdata)
                  Vdelayed_warnings_list
                    = Fcons (listn (CONSTYPE_HEAP, 2,
                                    intern ("initialization"),
@@ -2395,7 +2468,7 @@ get_emacs_configuration_options (void)
 
 /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95).  */
 int
-gettimeofday (struct timeval *restrict tv, struct timezone *restrict tz)
+gettimeofday (struct timeval *__restrict tv, struct timezone *__restrict tz)
 {
   struct _timeb tb;
   _ftime (&tb);
@@ -2430,8 +2503,6 @@ gettimeofday (struct timeval *restrict tv, struct timezone *restrict tz)
 int
 fdutimens (int fd, char const *file, struct timespec const timespec[2])
 {
-  struct _utimbuf ut;
-
   if (!timespec)
     {
       errno = ENOSYS;
@@ -2442,12 +2513,28 @@ fdutimens (int fd, char const *file, struct timespec const timespec[2])
       errno = EBADF;
       return -1;
     }
-  ut.actime = timespec[0].tv_sec;
-  ut.modtime = timespec[1].tv_sec;
+  /* _futime's prototype defines 2nd arg as having the type 'struct
+     _utimbuf', while utime needs to accept 'struct utimbuf' for
+     compatibility with Posix.  So we need to use 2 different (but
+     equivalent) types to avoid compiler warnings, sigh.  */
   if (fd >= 0)
-    return _futime (fd, &ut);
+    {
+      struct _utimbuf _ut;
+
+      _ut.actime = timespec[0].tv_sec;
+      _ut.modtime = timespec[1].tv_sec;
+      return _futime (fd, &_ut);
+    }
   else
-    return _utime (file, &ut);
+    {
+      struct utimbuf ut;
+
+      ut.actime = timespec[0].tv_sec;
+      ut.modtime = timespec[1].tv_sec;
+      /* Call 'utime', which is implemented below, not the MS library
+        function, which fails on directories.  */
+      return utime (file, &ut);
+    }
 }
 
 
@@ -3355,25 +3442,46 @@ sys_mkdir (const char * path)
   return _mkdir (map_w32_filename (path, NULL));
 }
 
-/* Because of long name mapping issues, we need to implement this
-   ourselves.  Also, MSVC's _mktemp returns NULL when it can't generate
-   a unique name, instead of setting the input template to an empty
-   string.
+int
+sys_open (const char * path, int oflag, int mode)
+{
+  const char* mpath = map_w32_filename (path, NULL);
+  int res = -1;
 
-   Standard algorithm seems to be use pid or tid with a letter on the
-   front (in place of the 6 X's) and cycle through the letters to find a
-   unique name.  We extend that to allow any reasonable character as the
-   first of the 6 X's.  */
-char *
-sys_mktemp (char * template)
+  /* If possible, try to open file without _O_CREAT, to be able to
+     write to existing hidden and system files.  Force all file
+     handles to be non-inheritable. */
+  if ((oflag & (_O_CREAT | _O_EXCL)) != (_O_CREAT | _O_EXCL))
+    res = _open (mpath, (oflag & ~_O_CREAT) | _O_NOINHERIT, mode);
+  if (res < 0)
+    res = _open (mpath, oflag | _O_NOINHERIT, mode);
+
+  return res;
+}
+
+/* Implementation of mkostemp for MS-Windows, to avoid race conditions
+   when using mktemp.
+
+   Standard algorithm for generating a temporary file name seems to be
+   use pid or tid with a letter on the front (in place of the 6 X's)
+   and cycle through the letters to find a unique name.  We extend
+   that to allow any reasonable character as the first of the 6 X's,
+   so that the number of simultaneously used temporary files will be
+   greater.  */
+
+int
+mkostemp (char * template, int flags)
 {
   char * p;
-  int i;
+  int i, fd = -1;
   unsigned uid = GetCurrentThreadId ();
+  int save_errno = errno;
   static char first_char[] = "abcdefghijklmnopqrstuvwyz0123456789!%-_@#";
 
+  errno = EINVAL;
   if (template == NULL)
-    return NULL;
+    return -1;
+
   p = template + strlen (template);
   i = 5;
   /* replace up to the last 5 X's with uid in decimal */
@@ -3388,38 +3496,22 @@ sys_mktemp (char * template)
       i = 0;
       do
        {
-         int save_errno = errno;
          p[0] = first_char[i];
-         if (faccessat (AT_FDCWD, template, F_OK, AT_EACCESS) < 0)
+         if ((fd = sys_open (template,
+                             flags | _O_CREAT | _O_EXCL | _O_RDWR,
+                             S_IRUSR | S_IWUSR)) >= 0
+             || errno != EEXIST)
            {
-             errno = save_errno;
-             return template;
+             if (fd >= 0)
+               errno = save_errno;
+             return fd;
            }
        }
       while (++i < sizeof (first_char));
     }
 
-  /* Template is badly formed or else we can't generate a unique name,
-     so return empty string */
-  template[0] = 0;
-  return template;
-}
-
-int
-sys_open (const char * path, int oflag, int mode)
-{
-  const char* mpath = map_w32_filename (path, NULL);
-  int res = -1;
-
-  /* If possible, try to open file without _O_CREAT, to be able to
-     write to existing hidden and system files.  Force all file
-     handles to be non-inheritable. */
-  if ((oflag & (_O_CREAT | _O_EXCL)) != (_O_CREAT | _O_EXCL))
-    res = _open (mpath, (oflag & ~_O_CREAT) | _O_NOINHERIT, mode);
-  if (res < 0)
-    res = _open (mpath, oflag | _O_NOINHERIT, mode);
-
-  return res;
+  /* Template is badly formed or else we can't generate a unique name.  */
+  return -1;
 }
 
 int
@@ -3728,12 +3820,6 @@ get_rid (PSID sid)
 
 /* Caching SID and account values for faster lokup.  */
 
-#ifdef __GNUC__
-# define FLEXIBLE_ARRAY_MEMBER
-#else
-# define FLEXIBLE_ARRAY_MEMBER 1
-#endif
-
 struct w32_id {
   unsigned rid;
   struct w32_id *next;
@@ -4429,6 +4515,9 @@ fstat (int desc, struct stat * buf)
   return 0;
 }
 
+/* A version of 'utime' which handles directories as well as
+   files.  */
+
 int
 utime (const char *name, struct utimbuf *times)
 {
@@ -5697,8 +5786,8 @@ system_process_attributes (Lisp_Object pid)
                {
                  /* Decode the command name from locale-specific
                     encoding.  */
-                 cmd_str = make_unibyte_string (pe.szExeFile,
-                                                strlen (pe.szExeFile));
+                 cmd_str = build_unibyte_string (pe.szExeFile);
+
                  decoded_cmd =
                    code_convert_string_norecord (cmd_str,
                                                  Vlocale_coding_system, 0);
@@ -6003,6 +6092,7 @@ term_winsock (void)
 {
   if (winsock_lib != NULL && winsock_inuse == 0)
     {
+      release_listen_threads ();
       /* Not sure what would cause WSAENETDOWN, or even if it can happen
         after WSAStartup returns successfully, but it seems reasonable
         to allow unloading winsock anyway in that case. */
@@ -6668,10 +6758,16 @@ sys_sendto (int s, const char * buf, int len, int flags,
 }
 
 /* Windows does not have an fcntl function.  Provide an implementation
-   solely for making sockets non-blocking.  */
+   good enough for Emacs.  */
 int
 fcntl (int s, int cmd, int options)
 {
+  /* In the w32 Emacs port, fcntl (fd, F_DUPFD_CLOEXEC, fd1) is always
+     invoked in a context where fd1 is closed and all descriptors less
+     than fd1 are open, so sys_dup is an adequate implementation.  */
+  if (cmd == F_DUPFD_CLOEXEC)
+    return sys_dup (s);
+
   if (winsock_lib == NULL)
     {
       errno = ENETDOWN;
@@ -6813,13 +6909,14 @@ sys_dup2 (int src, int dst)
   return rc;
 }
 
-/* Unix pipe() has only one arg */
 int
-sys_pipe (int * phandles)
+pipe2 (int * phandles, int pipe2_flags)
 {
   int rc;
   unsigned flags;
 
+  eassert (pipe2_flags == O_CLOEXEC);
+
   /* make pipe handles non-inheritable; when we spawn a child, we
      replace the relevant handle with an inheritable one.  Also put
      pipes into binary mode; we will do text mode translation ourselves
@@ -6980,7 +7077,12 @@ _sys_wait_accept (int fd)
   rc = pfn_WSAEventSelect (SOCK_HANDLE (fd), hEv, FD_ACCEPT);
   if (rc != SOCKET_ERROR)
     {
-      rc = WaitForSingleObject (hEv, INFINITE);
+      do {
+       rc = WaitForSingleObject (hEv, 500);
+       Sleep (5);
+      } while (rc == WAIT_TIMEOUT
+              && cp->status != STATUS_READ_ERROR
+              && cp->char_avail);
       pfn_WSAEventSelect (SOCK_HANDLE (fd), NULL, 0);
       if (rc == WAIT_OBJECT_0)
        cp->status = STATUS_READ_SUCCEEDED;
@@ -7647,8 +7749,9 @@ globals_of_w32 (void)
 
 /* For make-serial-process  */
 int
-serial_open (char *port)
+serial_open (Lisp_Object port_obj)
 {
+  char *port = SSDATA (port_obj);
   HANDLE hnd;
   child_process *cp;
   int fd = -1;
@@ -7842,7 +7945,7 @@ emacs_gnutls_pull (gnutls_transport_ptr_t p, void* buf, size_t sz)
 {
   int n, err;
   SELECT_TYPE fdset;
-  EMACS_TIME timeout;
+  struct timespec timeout;
   struct Lisp_Process *process = (struct Lisp_Process *)p;
   int fd = process->infd;