guile-elisp bootstrap part (C)
[bpt/emacs.git] / src / w32.c
index ebd1dff..76b12ad 100644 (file)
--- a/src/w32.c
+++ b/src/w32.c
@@ -73,9 +73,11 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include <grp.h>
 
 /* MinGW64 (_W64) defines these in its _mingw.h.  */
-#if defined(__GNUC__) && !defined(_W64)
-#define _ANONYMOUS_UNION
-#define _ANONYMOUS_STRUCT
+#ifndef _ANONYMOUS_UNION
+# define _ANONYMOUS_UNION
+#endif
+#ifndef _ANONYMOUS_STRUCT
+# define _ANONYMOUS_STRUCT
 #endif
 #include <windows.h>
 /* Some versions of compiler define MEMORYSTATUSEX, some don't, so we
@@ -478,6 +480,9 @@ typedef DWORD (WINAPI *GetAdaptersInfo_Proc) (
     PIP_ADAPTER_INFO pAdapterInfo,
     PULONG pOutBufLen);
 
+int (WINAPI *pMultiByteToWideChar)(UINT,DWORD,LPCSTR,int,LPWSTR,int);
+int (WINAPI *pWideCharToMultiByte)(UINT,DWORD,LPCWSTR,int,LPSTR,int,LPCSTR,LPBOOL);
+
   /* ** A utility function ** */
 static BOOL
 is_windows_9x (void)
@@ -1543,8 +1548,8 @@ codepage_for_filenames (CPINFO *cp_info)
 int
 filename_to_utf16 (const char *fn_in, wchar_t *fn_out)
 {
-  int result = MultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, fn_in, -1,
-                                   fn_out, MAX_PATH);
+  int result = pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, fn_in, -1,
+                                    fn_out, MAX_PATH);
 
   if (!result)
     {
@@ -1570,8 +1575,8 @@ filename_to_utf16 (const char *fn_in, wchar_t *fn_out)
 int
 filename_from_utf16 (const wchar_t *fn_in, char *fn_out)
 {
-  int result = WideCharToMultiByte (CP_UTF8, 0, fn_in, -1,
-                                   fn_out, MAX_UTF8_PATH, NULL, NULL);
+  int result = pWideCharToMultiByte (CP_UTF8, 0, fn_in, -1,
+                                    fn_out, MAX_UTF8_PATH, NULL, NULL);
 
   if (!result)
     {
@@ -1604,8 +1609,8 @@ filename_to_ansi (const char *fn_in, char *fn_out)
       int result;
       int codepage = codepage_for_filenames (NULL);
 
-      result  = WideCharToMultiByte (codepage, 0, fn_utf16, -1,
-                                    fn_out, MAX_PATH, NULL, NULL);
+      result  = pWideCharToMultiByte (codepage, 0, fn_utf16, -1,
+                                     fn_out, MAX_PATH, NULL, NULL);
       if (!result)
        {
          DWORD err = GetLastError ();
@@ -1634,8 +1639,8 @@ filename_from_ansi (const char *fn_in, char *fn_out)
 {
   wchar_t fn_utf16[MAX_PATH];
   int codepage = codepage_for_filenames (NULL);
-  int result = MultiByteToWideChar (codepage, MB_ERR_INVALID_CHARS, fn_in, -1,
-                                   fn_utf16, MAX_PATH);
+  int result = pMultiByteToWideChar (codepage, MB_ERR_INVALID_CHARS, fn_in, -1,
+                                    fn_utf16, MAX_PATH);
 
   if (!result)
     {
@@ -1704,7 +1709,7 @@ static unsigned num_of_processors;
 /* We maintain 1-sec samples for the last 16 minutes in a circular buffer.  */
 static struct load_sample samples[16*60];
 static int first_idx = -1, last_idx = -1;
-static int max_idx = sizeof (samples) / sizeof (samples[0]);
+static int max_idx = ARRAYELTS (samples);
 
 static int
 buf_next (int from)
@@ -2410,7 +2415,6 @@ unsetenv (const char *name)
 {
   char *var;
   size_t name_len;
-  int retval;
 
   if (name == NULL || *name == '\0' || strchr (name, '=') != NULL)
     {
@@ -2509,7 +2513,7 @@ init_environment (char ** argv)
 
   int i;
 
-  const int imax = sizeof (tempdirs) / sizeof (tempdirs[0]);
+  const int imax = ARRAYELTS (tempdirs);
 
   /* Implementation note: This function explicitly works with ANSI
      file names, not with UTF-8 encoded file names.  This is because
@@ -2582,7 +2586,7 @@ init_environment (char ** argv)
       {"LANG", NULL},
     };
 
-#define N_ENV_VARS sizeof (dflt_envvars)/sizeof (dflt_envvars[0])
+#define N_ENV_VARS ARRAYELTS (dflt_envvars)
 
     /* We need to copy dflt_envvars[] and work on the copy because we
        don't want the dumped Emacs to inherit the values of
@@ -3343,7 +3347,7 @@ sys_opendir (const char *filename)
        return NULL;
     }
 
-  if (!(dirp = (DIR *) malloc (sizeof (DIR))))
+  if (!(dirp = xmalloc (sizeof (DIR))))
     return NULL;
 
   dirp->dd_fd = 0;
@@ -4033,8 +4037,8 @@ sys_link (const char * old, const char * new)
       /* We used to pass MB_PRECOMPOSED as the 2nd arg here, but MSDN
         indicates that flag is unsupported for CP_UTF8, and OTOH says
         it is the default anyway.  */
-      wlen = MultiByteToWideChar (CP_UTF8, 0, newname, -1,
-                                 data.wid.cStreamName, MAX_PATH);
+      wlen = pMultiByteToWideChar (CP_UTF8, 0, newname, -1,
+                                  data.wid.cStreamName, MAX_PATH);
       if (wlen > 0)
        {
          LPVOID context = NULL;
@@ -4742,10 +4746,9 @@ stat_worker (const char * path, struct stat * buf, int follow_symlinks)
       return -1;
     }
 
-  /* Remove trailing directory separator, unless name is the root
-     directory of a drive or UNC volume in which case ensure there
-     is a trailing separator. */
   len = strlen (name);
+  /* Allocate 1 extra byte so that we could append a slash to a root
+     directory, down below.  */
   name = strcpy (alloca (len + 2), name);
 
   /* Avoid a somewhat costly call to is_symlink if the filesystem
@@ -4960,6 +4963,7 @@ stat_worker (const char * path, struct stat * buf, int follow_symlinks)
        }
       else if (rootdir)
        {
+         /* Make sure root directories end in a slash.  */
          if (!IS_DIRECTORY_SEP (name[len-1]))
            strcat (name, "\\");
          if (GetDriveType (name) < 2)
@@ -4975,6 +4979,8 @@ stat_worker (const char * path, struct stat * buf, int follow_symlinks)
        {
          int have_wfd = -1;
 
+         /* Make sure non-root directories do NOT end in a slash,
+            otherwise FindFirstFile might fail.  */
          if (IS_DIRECTORY_SEP (name[len-1]))
            name[len - 1] = 0;
 
@@ -5135,7 +5141,10 @@ fstatat (int fd, char const *name, struct stat *st, int flags)
 
   if (fd != AT_FDCWD)
     {
-      if (_snprintf (fullname, sizeof fullname, "%s/%s", dir_pathname, name)
+      char lastc = dir_pathname[strlen (dir_pathname) - 1];
+
+      if (_snprintf (fullname, sizeof fullname, "%s%s%s",
+                    dir_pathname, IS_DIRECTORY_SEP (lastc) ? "" : "/", name)
          < 0)
        {
          errno = ENAMETOOLONG;
@@ -5346,11 +5355,6 @@ utime (const char *name, struct utimbuf *times)
   return 0;
 }
 
-/* Emacs expects us to support the traditional octal form of the mode
-   bits, which is not what msvcrt.dll wants.  */
-
-#define WRITE_USER 00200
-
 int
 sys_umask (int mode)
 {
@@ -5362,14 +5366,14 @@ sys_umask (int mode)
      at all.  */
   /* FIXME: if the GROUP and OTHER bits are reset, we should use ACLs
      to prevent access by other users on NTFS.  */
-  if ((mode & WRITE_USER) != 0)
+  if ((mode & S_IWRITE) != 0)
     arg |= S_IWRITE;
 
   retval = _umask (arg);
   /* Merge into the return value the bits they've set the last time,
      which msvcrt.dll ignores and never returns.  Emacs insists on its
      notion of mask being identical to what we return.  */
-  retval |= (current_mask & ~WRITE_USER);
+  retval |= (current_mask & ~S_IWRITE);
   current_mask = mode;
 
   return retval;
@@ -8694,6 +8698,13 @@ w32_delayed_load (Lisp_Object library_id)
                               /* Possibly truncated */
                               ? make_specified_string (name, -1, len, 1)
                               : Qnil);
+               /* This prevents thread start and end notifications
+                  from being sent to the DLL, for every thread we
+                  start.  We don't need those notifications because
+                  threads we create never use any of these DLLs, only
+                  the main thread uses them.  This is supposed to
+                  speed up thread creation.  */
+               DisableThreadLibraryCalls (dll_handle);
                break;
              }
          }
@@ -8749,22 +8760,22 @@ check_windows_init_file (void)
                   "not unpacked properly.\nSee the README.W32 file in the "
                   "top-level Emacs directory for more information.",
                   init_file_name, load_path);
-         needed = MultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, buffer,
-                                       -1, NULL, 0);
+         needed = pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, buffer,
+                                        -1, NULL, 0);
          if (needed > 0)
            {
              wchar_t *msg_w = alloca ((needed + 1) * sizeof (wchar_t));
 
-             MultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, buffer, -1,
-                                  msg_w, needed);
-             needed = WideCharToMultiByte (CP_ACP, 0, msg_w, -1,
-                                           NULL, 0, NULL, NULL);
+             pMultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, buffer, -1,
+                                   msg_w, needed);
+             needed = pWideCharToMultiByte (CP_ACP, 0, msg_w, -1,
+                                            NULL, 0, NULL, NULL);
              if (needed > 0)
                {
                  char *msg_a = alloca (needed + 1);
 
-                 WideCharToMultiByte (CP_ACP, 0, msg_w, -1, msg_a, needed,
-                                      NULL, NULL);
+                 pWideCharToMultiByte (CP_ACP, 0, msg_w, -1, msg_a, needed,
+                                       NULL, NULL);
                  msg = msg_a;
                }
            }
@@ -8932,7 +8943,17 @@ maybe_load_unicows_dll (void)
     {
       HANDLE ret = LoadLibrary ("Unicows.dll");
       if (ret)
-       return ret;
+       {
+         /* These two functions are present on Windows 9X as stubs
+            that always fail.  We need the real implementations from
+            UNICOWS.DLL, so we must call these functions through
+            pointers, and assign the correct addresses to these
+            pointers at program startup (see emacs.c, which calls
+            this function early on).  */
+         pMultiByteToWideChar = GetProcAddress (ret, "MultiByteToWideChar");
+         pWideCharToMultiByte = GetProcAddress (ret, "WideCharToMultiByte");
+         return ret;
+       }
       else
        {
          int button;
@@ -8954,7 +8975,14 @@ maybe_load_unicows_dll (void)
        }
     }
   else
-    return LoadLibrary ("Gdi32.dll");
+    {
+      /* On NT family of Windows, these two functions are always
+        linked in, so we just assign their addresses to the 2
+        pointers; no need for the LoadLibrary dance.  */
+      pMultiByteToWideChar = MultiByteToWideChar;
+      pWideCharToMultiByte = WideCharToMultiByte;
+      return LoadLibrary ("Gdi32.dll");
+    }
 }
 
 /*
@@ -9229,8 +9257,6 @@ ssize_t
 emacs_gnutls_pull (gnutls_transport_ptr_t p, void* buf, size_t sz)
 {
   int n, err;
-  SELECT_TYPE fdset;
-  struct timespec timeout;
   struct Lisp_Process *process = (struct Lisp_Process *)p;
   int fd = process->infd;