plist module
[bpt/emacs.git] / src / w32.c
index 4e7f77e..76b12ad 100644 (file)
--- a/src/w32.c
+++ b/src/w32.c
@@ -1,6 +1,6 @@
 /* Utility and Unix shadow routines for GNU Emacs on the Microsoft Windows API.
 
-Copyright (C) 1994-1995, 2000-2013 Free Software Foundation, Inc.
+Copyright (C) 1994-1995, 2000-2014 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -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)
@@ -1405,7 +1410,7 @@ w32_valid_pointer_p (void *p, int size)
    conversion back and forth from UTF-8 to UTF-16, then don't: first,
    it was measured to take only a few microseconds on a not-so-fast
    machine, and second, that's exactly what the ANSI APIs we used
-   before do anyway, because they are just thin wrappers around the
+   before did anyway, because they are just thin wrappers around the
    Unicode APIs.)
 
    The variables file-name-coding-system and default-file-name-coding-system
@@ -1432,8 +1437,8 @@ w32_valid_pointer_p (void *p, int size)
 
      For the same reasons, no CRT function or Win32 API can be called
      directly in Emacs sources, without either converting the file
-     name sfrom UTF-8 to either UTF-16 or ANSI codepage, or going
-     through some shadowing function defined here.
+     names from UTF-8 to UTF-16 or ANSI codepage, or going through
+     some shadowing function defined here.
 
    . Environment variables stored in Vprocess_environment are encoded
      in the ANSI codepage, so if getenv/egetenv is used for a variable
@@ -1454,7 +1459,7 @@ w32_valid_pointer_p (void *p, int size)
    . Running subprocesses in non-ASCII directories and with non-ASCII
      file arguments is limited to the current codepage (even though
      Emacs is perfectly capable of finding an executable program file
-     even in a directory whose name cannot be encoded in the current
+     in a directory whose name cannot be encoded in the current
      codepage).  This is because the command-line arguments are
      encoded _before_ they get to the w32-specific level, and the
      encoding is not known in advance (it doesn't have to be the
@@ -1472,8 +1477,8 @@ w32_valid_pointer_p (void *p, int size)
      the current codepage.
 
    . Turning on w32-unicode-filename on Windows 9X (if it at all
-     works) requires UNICOWS.DLL, which is currently loaded only in a
-     GUI session.  */
+     works) requires UNICOWS.DLL, which is thus a requirement even in
+     non-GUI sessions, something the we previously avoided.  */
 
 \f
 
@@ -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;
@@ -6045,7 +6049,7 @@ acl_set_file (const char *fname, acl_type_t type, acl_t acl)
   errno = 0;
   /* SetFileSecurity is deprecated by MS, and sometimes fails when
      DACL inheritance is involved, but it seems to preserve ownership
-     better than SetNamedSecurity, which is important e.g., in
+     better than SetNamedSecurityInfo, which is important e.g., in
      copy-file.  */
   if (!set_file_security (fname, flags, (PSECURITY_DESCRIPTOR)acl))
     {
@@ -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;
                }
            }
@@ -8923,6 +8934,57 @@ shutdown_handler (DWORD type)
   return FALSE;
 }
 
+/* On Windows 9X, load UNICOWS.DLL and return its handle, or die.  On
+   NT, return a handle to GDI32.DLL.  */
+HANDLE
+maybe_load_unicows_dll (void)
+{
+  if (os_subtype == OS_9X)
+    {
+      HANDLE ret = LoadLibrary ("Unicows.dll");
+      if (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;
+
+         button = MessageBox (NULL,
+                              "Emacs cannot load the UNICOWS.DLL library.\n"
+                              "This library is essential for using Emacs\n"
+                              "on this system.  You need to install it.\n\n"
+                              "Emacs will exit when you click OK.",
+                              "Emacs cannot load UNICOWS.DLL",
+                              MB_ICONERROR | MB_TASKMODAL
+                              | MB_SETFOREGROUND | MB_OK);
+         switch (button)
+           {
+           case IDOK:
+           default:
+             exit (1);
+           }
+       }
+    }
+  else
+    {
+      /* 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");
+    }
+}
+
 /*
        globals_of_w32 is used to initialize those global variables that
        must always be initialized on startup even when the global variable
@@ -9195,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;