merge trunk
[bpt/emacs.git] / src / w32.c
index ed86b12..7d63c73 100644 (file)
--- a/src/w32.c
+++ b/src/w32.c
@@ -29,10 +29,10 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include <ctype.h>
 #include <signal.h>
 #include <sys/file.h>
+#include <time.h>      /* must be before nt/inc/sys/time.h, for MinGW64 */
 #include <sys/time.h>
 #include <sys/utime.h>
 #include <math.h>
-#include <time.h>
 
 /* must include CRT headers *before* config.h */
 
@@ -65,11 +65,13 @@ 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>
 
-#ifdef __GNUC__
+/* MinGW64 (_W64) defines these in its _mingw.h.  */
+#if defined(__GNUC__) && !defined(_W64)
 #define _ANONYMOUS_UNION
 #define _ANONYMOUS_STRUCT
 #endif
@@ -96,6 +98,7 @@ typedef struct _MEMORY_STATUS_EX {
 #ifndef _MSC_VER
 #include <w32api.h>
 #endif
+#if _WIN32_WINNT < 0x0500
 #if !defined (__MINGW32__) || __W32API_MAJOR_VERSION < 3 || (__W32API_MAJOR_VERSION == 3 && __W32API_MINOR_VERSION < 15)
 /* This either is not in psapi.h or guarded by higher value of
    _WIN32_WINNT than what we use.  w32api supplied with MinGW 3.15
@@ -114,6 +117,7 @@ typedef struct _PROCESS_MEMORY_COUNTERS_EX {
   SIZE_T PrivateUsage;
 } PROCESS_MEMORY_COUNTERS_EX,*PPROCESS_MEMORY_COUNTERS_EX;
 #endif
+#endif
 
 #include <winioctl.h>
 #include <aclapi.h>
@@ -127,11 +131,11 @@ typedef struct _PROCESS_MEMORY_COUNTERS_EX {
 #define SDDL_REVISION_1        1
 #endif /* SDDL_REVISION_1 */
 
-#ifdef _MSC_VER
-/* MSVC doesn't provide the definition of REPARSE_DATA_BUFFER and the
-   associated macros, except on ntifs.h, which cannot be included
-   because it triggers conflicts with other Windows API headers.  So
-   we define it here by hand.  */
+#if defined(_MSC_VER) || defined(_W64)
+/* MSVC and MinGW64 don't provide the definition of
+   REPARSE_DATA_BUFFER and the associated macros, except on ntifs.h,
+   which cannot be included because it triggers conflicts with other
+   Windows API headers.  So we define it here by hand.  */
 
 typedef struct _REPARSE_DATA_BUFFER {
     ULONG  ReparseTag;
@@ -171,9 +175,12 @@ typedef struct _REPARSE_DATA_BUFFER {
 #ifndef CTL_CODE
 #define CTL_CODE(t,f,m,a)       (((t)<<16)|((a)<<14)|((f)<<2)|(m))
 #endif
+/* MinGW64 defines FSCTL_GET_REPARSE_POINT on winioctl.h.  */
+#ifndef FSCTL_GET_REPARSE_POINT
 #define FSCTL_GET_REPARSE_POINT \
   CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED, FILE_ANY_ACCESS)
 #endif
+#endif
 
 /* TCP connection support.  */
 #include <sys/socket.h>
@@ -2012,7 +2019,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},
@@ -2088,9 +2095,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))
@@ -2098,6 +2108,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/  */
 
@@ -2133,16 +2152,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"),
@@ -2388,8 +2451,8 @@ get_emacs_configuration_options (void)
 #include <sys/timeb.h>
 
 /* Emulate gettimeofday (Ulrich Leodolter, 1/11/95).  */
-void
-gettimeofday (struct timeval *tv, struct timezone *tz)
+int
+gettimeofday (struct timeval *restrict tv, struct timezone *restrict tz)
 {
   struct _timeb tb;
   _ftime (&tb);
@@ -2407,6 +2470,7 @@ gettimeofday (struct timeval *tv, struct timezone *tz)
       tz->tz_minuteswest = tb.timezone;        /* minutes west of Greenwich  */
       tz->tz_dsttime = tb.dstflag;     /* type of dst correction  */
     }
+  return 0;
 }
 
 /* Emulate fdutimens.  */
@@ -3402,20 +3466,27 @@ int
 sys_open (const char * path, int oflag, int mode)
 {
   const char* mpath = map_w32_filename (path, NULL);
-  /* Try to open file without _O_CREAT, to be able to write to hidden
-     and system files. Force all file handles to be
-     non-inheritable. */
-  int res = _open (mpath, (oflag & ~_O_CREAT) | _O_NOINHERIT, mode);
+  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);
-  if (res >= 0 && res < MAXDESC)
-    fd_info[res].flags = 0;
 
   return res;
 }
 
 int
-sys_rename (const char * oldname, const char * newname)
+fchmod (int fd, mode_t mode)
+{
+  return 0;
+}
+
+int
+sys_rename_replace (const char *oldname, const char *newname, BOOL force)
 {
   BOOL result;
   char temp[MAX_PATH];
@@ -3471,7 +3542,7 @@ sys_rename (const char * oldname, const char * newname)
        return -1;
     }
 
-  /* Emulate Unix behavior - newname is deleted if it already exists
+  /* If FORCE, emulate Unix behavior - newname is deleted if it already exists
      (at least if it is a file; don't do this for directories).
 
      Since we mustn't do this if we are just changing the case of the
@@ -3489,7 +3560,7 @@ sys_rename (const char * oldname, const char * newname)
 
   result = rename (temp, newname);
 
-  if (result < 0)
+  if (result < 0 && force)
     {
       DWORD w32err = GetLastError ();
 
@@ -3528,6 +3599,12 @@ sys_rename (const char * oldname, const char * newname)
   return result;
 }
 
+int
+sys_rename (char const *old, char const *new)
+{
+  return sys_rename_replace (old, new, TRUE);
+}
+
 int
 sys_rmdir (const char * path)
 {
@@ -5567,10 +5644,8 @@ ltime (ULONGLONG time_100ns)
 {
   ULONGLONG time_sec = time_100ns / 10000000;
   int subsec = time_100ns % 10000000;
-  return list4 (make_number (time_sec >> 16),
-               make_number (time_sec & 0xffff),
-               make_number (subsec / 10),
-               make_number (subsec % 10 * 100000));
+  return list4i (time_sec >> 16, time_sec & 0xffff,
+                subsec / 10, subsec % 10 * 100000);
 }
 
 #define U64_TO_LISP_TIME(time) ltime (time)
@@ -7822,47 +7897,26 @@ serial_configure (struct Lisp_Process *p, Lisp_Object contact)
 ssize_t
 emacs_gnutls_pull (gnutls_transport_ptr_t p, void* buf, size_t sz)
 {
-  int n, sc, err;
+  int n, err;
   SELECT_TYPE fdset;
   EMACS_TIME timeout;
   struct Lisp_Process *process = (struct Lisp_Process *)p;
   int fd = process->infd;
 
-  for (;;)
-    {
-      n = sys_read (fd, (char*)buf, sz);
+  n = sys_read (fd, (char*)buf, sz);
 
-      if (n >= 0)
-        return n;
+  if (n >= 0)
+    return n;
 
-      err = errno;
+  err = errno;
 
-      if (err == EWOULDBLOCK)
-        {
-          /* Set a small timeout.  */
-         timeout = make_emacs_time (1, 0);
-          FD_ZERO (&fdset);
-          FD_SET ((int)fd, &fdset);
-
-          /* Use select with the timeout to poll the selector.  */
-          sc = select (fd + 1, &fdset, (SELECT_TYPE *)0, (SELECT_TYPE *)0,
-                       &timeout, NULL);
-
-          if (sc > 0)
-            continue;  /* Try again.  */
-
-          /* Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN.
-             Also accept select return 0 as an indicator to EAGAIN.  */
-          if (sc == 0 || errno == EWOULDBLOCK)
-            err = EAGAIN;
-          else
-            err = errno; /* Other errors are just passed on.  */
-        }
+  /* Translate the WSAEWOULDBLOCK alias EWOULDBLOCK to EAGAIN. */
+  if (err == EWOULDBLOCK)
+    err = EAGAIN;
 
-      emacs_gnutls_transport_set_errno (process->gnutls_state, err);
+  emacs_gnutls_transport_set_errno (process->gnutls_state, err);
 
-      return -1;
-    }
+  return -1;
 }
 
 ssize_t