Move declarations to header files.
[bpt/emacs.git] / src / w32.c
index fea1951..f1ed6ae 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 W32 API.
-   Copyright (C) 1994, 1995, 2000, 2001, 2002, 2003, 2004,
-                 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+   Copyright (C) 1994, 1995, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
+                 2007, 2008, 2009, 2010  Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -23,6 +23,7 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include <stddef.h> /* for offsetof */
 #include <stdlib.h>
 #include <stdio.h>
+#include <float.h>     /* for DBL_EPSILON */
 #include <io.h>
 #include <errno.h>
 #include <fcntl.h>
@@ -32,6 +33,8 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include <sys/time.h>
 #include <sys/utime.h>
 #include <mbstring.h>  /* for _mbspbrk */
+#include <math.h>
+#include <setjmp.h>
 
 /* must include CRT headers *before* config.h */
 
@@ -72,9 +75,41 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #define _ANONYMOUS_STRUCT
 #endif
 #include <windows.h>
+/* Some versions of compiler define MEMORYSTATUSEX, some don't, so we
+   use a different name to avoid compilation problems.  */
+typedef struct _MEMORY_STATUS_EX {
+        DWORD dwLength;
+        DWORD dwMemoryLoad;
+        DWORDLONG ullTotalPhys;
+        DWORDLONG ullAvailPhys;
+        DWORDLONG ullTotalPageFile;
+        DWORDLONG ullAvailPageFile;
+        DWORDLONG ullTotalVirtual;
+        DWORDLONG ullAvailVirtual;
+        DWORDLONG ullAvailExtendedVirtual;
+} MEMORY_STATUS_EX,*LPMEMORY_STATUS_EX;
+
 #include <lmcons.h>
 #include <shlobj.h>
 
+#include <tlhelp32.h>
+#include <psapi.h>
+/* This either is not in psapi.h or guarded by higher value of
+   _WIN32_WINNT than what we use.  */
+typedef struct _PROCESS_MEMORY_COUNTERS_EX {
+       DWORD cb;
+       DWORD PageFaultCount;
+       DWORD PeakWorkingSetSize;
+       DWORD WorkingSetSize;
+       DWORD QuotaPeakPagedPoolUsage;
+       DWORD QuotaPagedPoolUsage;
+       DWORD QuotaPeakNonPagedPoolUsage;
+       DWORD QuotaNonPagedPoolUsage;
+       DWORD PagefileUsage;
+       DWORD PeakPagefileUsage;
+       DWORD PrivateUsage;
+} PROCESS_MEMORY_COUNTERS_EX,*PPROCESS_MEMORY_COUNTERS_EX;
+
 #ifdef HAVE_SOCKETS    /* TCP connection support, if kernel can do it */
 #include <sys/socket.h>
 #undef socket
@@ -100,11 +135,16 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include "ndir.h"
 #include "w32heap.h"
 #include "systime.h"
+#include "dispextern.h"                /* for xstrcasecmp */
+#include "coding.h"            /* for Vlocale_coding_system */
+
+/* For serial_configure and serial_open.  */
+#include "process.h"
 
 typedef HRESULT (WINAPI * ShGetFolderPath_fn)
   (IN HWND, IN int, IN HANDLE, IN DWORD, OUT char *);
 
-void globals_of_w32 ();
+void globals_of_w32 (void);
 static DWORD get_rid (PSID);
 
 extern Lisp_Object Vw32_downcase_file_names;
@@ -136,6 +176,21 @@ static BOOL g_b_init_get_file_security;
 static BOOL g_b_init_get_security_descriptor_owner;
 static BOOL g_b_init_get_security_descriptor_group;
 static BOOL g_b_init_is_valid_sid;
+static BOOL g_b_init_create_toolhelp32_snapshot;
+static BOOL g_b_init_process32_first;
+static BOOL g_b_init_process32_next;
+static BOOL g_b_init_open_thread_token;
+static BOOL g_b_init_impersonate_self;
+static BOOL g_b_init_revert_to_self;
+static BOOL g_b_init_get_process_memory_info;
+static BOOL g_b_init_get_process_working_set_size;
+static BOOL g_b_init_global_memory_status;
+static BOOL g_b_init_global_memory_status_ex;
+static BOOL g_b_init_get_length_sid;
+static BOOL g_b_init_equal_sid;
+static BOOL g_b_init_copy_sid;
+static BOOL g_b_init_get_native_system_info;
+static BOOL g_b_init_get_system_times;
 
 /*
   BEGIN: Wrapper functions around OpenProcessToken
@@ -200,18 +255,64 @@ typedef BOOL (WINAPI * GetSecurityDescriptorGroup_Proc) (
     LPBOOL lpbGroupDefaulted);
 typedef BOOL (WINAPI * IsValidSid_Proc) (
     PSID sid);
+typedef HANDLE (WINAPI * CreateToolhelp32Snapshot_Proc) (
+    DWORD dwFlags,
+    DWORD th32ProcessID);
+typedef BOOL (WINAPI * Process32First_Proc) (
+    HANDLE hSnapshot,
+    LPPROCESSENTRY32 lppe);
+typedef BOOL (WINAPI * Process32Next_Proc) (
+    HANDLE hSnapshot,
+    LPPROCESSENTRY32 lppe);
+typedef BOOL (WINAPI * OpenThreadToken_Proc) (
+    HANDLE ThreadHandle,
+    DWORD DesiredAccess,
+    BOOL OpenAsSelf,
+    PHANDLE TokenHandle);
+typedef BOOL (WINAPI * ImpersonateSelf_Proc) (
+    SECURITY_IMPERSONATION_LEVEL ImpersonationLevel);
+typedef BOOL (WINAPI * RevertToSelf_Proc) (void);
+typedef BOOL (WINAPI * GetProcessMemoryInfo_Proc) (
+    HANDLE Process,
+    PPROCESS_MEMORY_COUNTERS ppsmemCounters,
+    DWORD cb);
+typedef BOOL (WINAPI * GetProcessWorkingSetSize_Proc) (
+    HANDLE hProcess,
+    DWORD * lpMinimumWorkingSetSize,
+    DWORD * lpMaximumWorkingSetSize);
+typedef BOOL (WINAPI * GlobalMemoryStatus_Proc) (
+    LPMEMORYSTATUS lpBuffer);
+typedef BOOL (WINAPI * GlobalMemoryStatusEx_Proc) (
+    LPMEMORY_STATUS_EX lpBuffer);
+typedef BOOL (WINAPI * CopySid_Proc) (
+    DWORD nDestinationSidLength,
+    PSID pDestinationSid,
+    PSID pSourceSid);
+typedef BOOL (WINAPI * EqualSid_Proc) (
+    PSID pSid1,
+    PSID pSid2);
+typedef DWORD (WINAPI * GetLengthSid_Proc) (
+    PSID pSid);
+typedef void (WINAPI * GetNativeSystemInfo_Proc) (
+    LPSYSTEM_INFO lpSystemInfo);
+typedef BOOL (WINAPI * GetSystemTimes_Proc) (
+    LPFILETIME lpIdleTime,
+    LPFILETIME lpKernelTime,
+    LPFILETIME lpUserTime);
+
+
 
   /* ** A utility function ** */
 static BOOL
-is_windows_9x ()
+is_windows_9x (void)
 {
   static BOOL s_b_ret=0;
   OSVERSIONINFO os_ver;
   if (g_b_init_is_windows_9x == 0)
     {
       g_b_init_is_windows_9x = 1;
-      ZeroMemory(&os_ver, sizeof(OSVERSIONINFO));
-      os_ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+      ZeroMemory (&os_ver, sizeof (OSVERSIONINFO));
+      os_ver.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
       if (GetVersionEx (&os_ver))
         {
           s_b_ret = (os_ver.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
@@ -224,12 +325,12 @@ is_windows_9x ()
    Returns a list of three integers if the times are provided by the OS
    (NT derivatives), otherwise it returns the result of current-time. */
 Lisp_Object
-w32_get_internal_run_time ()
+w32_get_internal_run_time (void)
 {
   if (get_process_times_fn)
     {
       FILETIME create, exit, kernel, user;
-      HANDLE proc = GetCurrentProcess();
+      HANDLE proc = GetCurrentProcess ();
       if ((*get_process_times_fn) (proc, &create, &exit, &kernel, &user))
         {
           LARGE_INTEGER user_int, kernel_int, total;
@@ -547,12 +648,128 @@ BOOL WINAPI is_valid_sid (
   return (s_pfn_Is_Valid_Sid (sid));
 }
 
+BOOL WINAPI equal_sid (
+    PSID sid1,
+    PSID sid2)
+{
+  static EqualSid_Proc s_pfn_Equal_Sid = NULL;
+  HMODULE hm_advapi32 = NULL;
+  if (is_windows_9x () == TRUE)
+    {
+      return FALSE;
+    }
+  if (g_b_init_equal_sid == 0)
+    {
+      g_b_init_equal_sid = 1;
+      hm_advapi32 = LoadLibrary ("Advapi32.dll");
+      s_pfn_Equal_Sid =
+        (EqualSid_Proc) GetProcAddress (
+            hm_advapi32, "EqualSid");
+    }
+  if (s_pfn_Equal_Sid == NULL)
+    {
+      return FALSE;
+    }
+  return (s_pfn_Equal_Sid (sid1, sid2));
+}
+
+DWORD WINAPI get_length_sid (
+    PSID sid)
+{
+  static GetLengthSid_Proc s_pfn_Get_Length_Sid = NULL;
+  HMODULE hm_advapi32 = NULL;
+  if (is_windows_9x () == TRUE)
+    {
+      return 0;
+    }
+  if (g_b_init_get_length_sid == 0)
+    {
+      g_b_init_get_length_sid = 1;
+      hm_advapi32 = LoadLibrary ("Advapi32.dll");
+      s_pfn_Get_Length_Sid =
+        (GetLengthSid_Proc) GetProcAddress (
+            hm_advapi32, "GetLengthSid");
+    }
+  if (s_pfn_Get_Length_Sid == NULL)
+    {
+      return 0;
+    }
+  return (s_pfn_Get_Length_Sid (sid));
+}
+
+BOOL WINAPI copy_sid (
+    DWORD destlen,
+    PSID dest,
+    PSID src)
+{
+  static CopySid_Proc s_pfn_Copy_Sid = NULL;
+  HMODULE hm_advapi32 = NULL;
+  if (is_windows_9x () == TRUE)
+    {
+      return FALSE;
+    }
+  if (g_b_init_copy_sid == 0)
+    {
+      g_b_init_copy_sid = 1;
+      hm_advapi32 = LoadLibrary ("Advapi32.dll");
+      s_pfn_Copy_Sid =
+        (CopySid_Proc) GetProcAddress (
+            hm_advapi32, "CopySid");
+    }
+  if (s_pfn_Copy_Sid == NULL)
+    {
+      return FALSE;
+    }
+  return (s_pfn_Copy_Sid (destlen, dest, src));
+}
+
 /*
   END: Wrapper functions around OpenProcessToken
   and other functions in advapi32.dll that are only
   supported in Windows NT / 2k / XP
 */
 
+void WINAPI get_native_system_info (
+    LPSYSTEM_INFO lpSystemInfo)
+{
+  static GetNativeSystemInfo_Proc s_pfn_Get_Native_System_Info = NULL;
+  if (is_windows_9x () != TRUE)
+    {
+      if (g_b_init_get_native_system_info == 0)
+       {
+         g_b_init_get_native_system_info = 1;
+         s_pfn_Get_Native_System_Info =
+           (GetNativeSystemInfo_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
+                                                     "GetNativeSystemInfo");
+       }
+      if (s_pfn_Get_Native_System_Info != NULL)
+       s_pfn_Get_Native_System_Info (lpSystemInfo);
+    }
+  else
+    lpSystemInfo->dwNumberOfProcessors = -1;
+}
+
+BOOL WINAPI get_system_times (
+    LPFILETIME lpIdleTime,
+    LPFILETIME lpKernelTime,
+    LPFILETIME lpUserTime)
+{
+  static GetSystemTimes_Proc s_pfn_Get_System_times = NULL;
+  if (is_windows_9x () == TRUE)
+    {
+      return FALSE;
+    }
+  if (g_b_init_get_system_times == 0)
+    {
+      g_b_init_get_system_times = 1;
+      s_pfn_Get_System_times =
+       (GetSystemTimes_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
+                                            "GetSystemTimes");
+    }
+  if (s_pfn_Get_System_times == NULL)
+    return FALSE;
+  return (s_pfn_Get_System_times (lpIdleTime, lpKernelTime, lpUserTime));
+}
 \f
 /* Equivalent of strerror for W32 error codes.  */
 char *
@@ -625,17 +842,160 @@ gethostname (char *buffer, int size)
 #endif /* HAVE_SOCKETS */
 
 /* Emulate getloadavg.  */
+
+struct load_sample {
+  time_t sample_time;
+  ULONGLONG idle;
+  ULONGLONG kernel;
+  ULONGLONG user;
+};
+
+/* Number of processors on this machine.  */
+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
+buf_next (int from)
+{
+  int next_idx = from + 1;
+
+  if (next_idx >= max_idx)
+    next_idx = 0;
+
+  return next_idx;
+}
+
+static int
+buf_prev (int from)
+{
+  int prev_idx = from - 1;
+
+  if (prev_idx < 0)
+    prev_idx = max_idx - 1;
+
+  return prev_idx;
+}
+
+static void
+sample_system_load (ULONGLONG *idle, ULONGLONG *kernel, ULONGLONG *user)
+{
+  SYSTEM_INFO sysinfo;
+  FILETIME ft_idle, ft_user, ft_kernel;
+
+  /* Initialize the number of processors on this machine.  */
+  if (num_of_processors <= 0)
+    {
+      get_native_system_info (&sysinfo);
+      num_of_processors = sysinfo.dwNumberOfProcessors;
+      if (num_of_processors <= 0)
+       {
+         GetSystemInfo (&sysinfo);
+         num_of_processors = sysinfo.dwNumberOfProcessors;
+       }
+      if (num_of_processors <= 0)
+       num_of_processors = 1;
+    }
+
+  /* TODO: Take into account threads that are ready to run, by
+     sampling the "\System\Processor Queue Length" performance
+     counter.  The code below accounts only for threads that are
+     actually running.  */
+
+  if (get_system_times (&ft_idle, &ft_kernel, &ft_user))
+    {
+      ULARGE_INTEGER uidle, ukernel, uuser;
+
+      memcpy (&uidle, &ft_idle, sizeof (ft_idle));
+      memcpy (&ukernel, &ft_kernel, sizeof (ft_kernel));
+      memcpy (&uuser, &ft_user, sizeof (ft_user));
+      *idle = uidle.QuadPart;
+      *kernel = ukernel.QuadPart;
+      *user = uuser.QuadPart;
+    }
+  else
+    {
+      *idle = 0;
+      *kernel = 0;
+      *user = 0;
+    }
+}
+
+/* Produce the load average for a given time interval, using the
+   samples in the samples[] array.  WHICH can be 0, 1, or 2, meaning
+   1-minute, 5-minute, or 15-minute average, respectively. */
+static double
+getavg (int which)
+{
+  double retval = -1.0;
+  double tdiff;
+  int idx;
+  double span = (which == 0 ? 1.0 : (which == 1 ? 5.0 : 15.0)) * 60;
+  time_t now = samples[last_idx].sample_time;
+
+  if (first_idx != last_idx)
+    {
+      for (idx = buf_prev (last_idx); ; idx = buf_prev (idx))
+       {
+         tdiff = difftime (now, samples[idx].sample_time);
+         if (tdiff >= span - 2*DBL_EPSILON*now)
+           {
+             long double sys =
+               samples[last_idx].kernel + samples[last_idx].user
+               - (samples[idx].kernel + samples[idx].user);
+             long double idl = samples[last_idx].idle - samples[idx].idle;
+
+             retval = (1.0 - idl / sys) * num_of_processors;
+             break;
+           }
+         if (idx == first_idx)
+           break;
+       }
+    }
+
+  return retval;
+}
+
 int
 getloadavg (double loadavg[], int nelem)
 {
-  int i;
+  int elem;
+  ULONGLONG idle, kernel, user;
+  time_t now = time (NULL);
+
+  /* Store another sample.  We ignore samples that are less than 1 sec
+     apart.  */
+  if (difftime (now, samples[last_idx].sample_time) >= 1.0 - 2*DBL_EPSILON*now)
+    {
+      sample_system_load (&idle, &kernel, &user);
+      last_idx = buf_next (last_idx);
+      samples[last_idx].sample_time = now;
+      samples[last_idx].idle = idle;
+      samples[last_idx].kernel = kernel;
+      samples[last_idx].user = user;
+      /* If the buffer has more that 15 min worth of samples, discard
+        the old ones.  */
+      if (first_idx == -1)
+       first_idx = last_idx;
+      while (first_idx != last_idx
+            && (difftime (now, samples[first_idx].sample_time)
+                >= 15.0*60 + 2*DBL_EPSILON*now))
+       first_idx = buf_next (first_idx);
+    }
 
-  /* A faithful emulation is going to have to be saved for a rainy day.  */
-  for (i = 0; i < nelem; i++)
+  for (elem = 0; elem < nelem; elem++)
     {
-      loadavg[i] = 0.0;
+      double avg = getavg (elem);
+
+      if (avg < 0)
+       break;
+      loadavg[elem] = avg;
     }
-  return i;
+
+  return elem;
 }
 
 /* Emulate getpwuid, getpwnam and others.  */
@@ -670,14 +1030,14 @@ static struct group dflt_group =
   0,
 };
 
-int
-getuid ()
+unsigned
+getuid (void)
 {
   return dflt_passwd.pw_uid;
 }
 
-int
-geteuid ()
+unsigned
+geteuid (void)
 {
   /* I could imagine arguing for checking to see whether the user is
      in the Administrators group and returning a UID of 0 for that
@@ -685,20 +1045,20 @@ geteuid ()
   return getuid ();
 }
 
-int
-getgid ()
+unsigned
+getgid (void)
 {
   return dflt_passwd.pw_gid;
 }
 
-int
-getegid ()
+unsigned
+getegid (void)
 {
   return getgid ();
 }
 
 struct passwd *
-getpwuid (int uid)
+getpwuid (unsigned uid)
 {
   if (uid == dflt_passwd.pw_uid)
     return &dflt_passwd;
@@ -720,14 +1080,14 @@ getpwnam (char *name)
   if (!pw)
     return pw;
 
-  if (stricmp (name, pw->pw_name))
+  if (xstrcasecmp (name, pw->pw_name))
     return NULL;
 
   return pw;
 }
 
 void
-init_user_info ()
+init_user_info (void)
 {
   /* Find the user's real name by opening the process token and
      looking up the name associated with the user-sid in that token.
@@ -737,24 +1097,41 @@ init_user_info ()
      primary group sid from the process token). */
 
   char         uname[UNLEN+1], gname[GNLEN+1], domain[1025];
-  DWORD        ulength = sizeof (uname), dlength = sizeof (domain), trash;
+  DWORD        ulength = sizeof (uname), dlength = sizeof (domain), needed;
   DWORD               glength = sizeof (gname);
   HANDLE       token = NULL;
   SID_NAME_USE user_type;
-  unsigned char buf[1024];
+  unsigned char *buf = NULL;
+  DWORD        blen = 0;
   TOKEN_USER   user_token;
   TOKEN_PRIMARY_GROUP group_token;
+  BOOL         result;
 
-  if (open_process_token (GetCurrentProcess (), TOKEN_QUERY, &token)
-      && get_token_information (token, TokenUser,
-                               (PVOID)buf, sizeof (buf), &trash)
-      && (memcpy (&user_token, buf, sizeof (user_token)),
-         lookup_account_sid (NULL, user_token.User.Sid, uname, &ulength,
-                             domain, &dlength, &user_type)))
+  result = open_process_token (GetCurrentProcess (), TOKEN_QUERY, &token);
+  if (result)
+    {
+      result = get_token_information (token, TokenUser, NULL, 0, &blen);
+      if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
+       {
+         buf = xmalloc (blen);
+         result = get_token_information (token, TokenUser,
+                                         (LPVOID)buf, blen, &needed);
+         if (result)
+           {
+             memcpy (&user_token, buf, sizeof (user_token));
+             result = lookup_account_sid (NULL, user_token.User.Sid,
+                                          uname, &ulength,
+                                          domain, &dlength, &user_type);
+           }
+       }
+      else
+       result = FALSE;
+    }
+  if (result)
     {
       strcpy (dflt_passwd.pw_name, uname);
       /* Determine a reasonable uid value.  */
-      if (stricmp ("administrator", uname) == 0)
+      if (xstrcasecmp ("administrator", uname) == 0)
        {
          dflt_passwd.pw_uid = 500; /* well-known Administrator uid */
          dflt_passwd.pw_gid = 513; /* well-known None gid */
@@ -766,12 +1143,22 @@ init_user_info ()
          dflt_passwd.pw_uid = get_rid (user_token.User.Sid);
 
          /* Get group id and name.  */
-         if (get_token_information (token, TokenPrimaryGroup,
-                                    (PVOID)buf, sizeof (buf), &trash))
+         result = get_token_information (token, TokenPrimaryGroup,
+                                         (LPVOID)buf, blen, &needed);
+         if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
+           {
+             buf = xrealloc (buf, blen = needed);
+             result = get_token_information (token, TokenPrimaryGroup,
+                                             (LPVOID)buf, blen, &needed);
+           }
+         if (result)
            {
              memcpy (&group_token, buf, sizeof (group_token));
              dflt_passwd.pw_gid = get_rid (group_token.PrimaryGroup);
              dlength = sizeof (domain);
+             /* If we can get at the real Primary Group name, use that.
+                Otherwise, the default group name was already set to
+                "None" in globals_of_w32.  */
              if (lookup_account_sid (NULL, group_token.PrimaryGroup,
                                      gname, &glength, NULL, &dlength,
                                      &user_type))
@@ -782,11 +1169,11 @@ init_user_info ()
        }
     }
   /* If security calls are not supported (presumably because we
-     are running under Windows 95), fallback to this. */
+     are running under Windows 9X), fallback to this: */
   else if (GetUserName (uname, &ulength))
     {
       strcpy (dflt_passwd.pw_name, uname);
-      if (stricmp ("administrator", uname) == 0)
+      if (xstrcasecmp ("administrator", uname) == 0)
        dflt_passwd.pw_uid = 0;
       else
        dflt_passwd.pw_uid = 123;
@@ -810,12 +1197,13 @@ init_user_info ()
   strcpy (dflt_passwd.pw_dir, getenv ("HOME"));
   strcpy (dflt_passwd.pw_shell, getenv ("SHELL"));
 
+  xfree (buf);
   if (token)
     CloseHandle (token);
 }
 
 int
-random ()
+random (void)
 {
   /* rand () on NT gives us 15 random bits...hack together 30 bits.  */
   return ((rand () << 15) | rand ());
@@ -833,9 +1221,7 @@ srandom (int seed)
    case path name components to lower case.  */
 
 static void
-normalize_filename (fp, path_sep)
-     register char *fp;
-     char path_sep;
+normalize_filename (register char *fp, char path_sep)
 {
   char sep;
   char *elem;
@@ -891,16 +1277,14 @@ normalize_filename (fp, path_sep)
 
 /* Destructively turn backslashes into slashes.  */
 void
-dostounix_filename (p)
-     register char *p;
+dostounix_filename (register char *p)
 {
   normalize_filename (p, '/');
 }
 
 /* Destructively turn slashes into backslashes.  */
 void
-unixtodos_filename (p)
-     register char *p;
+unixtodos_filename (register char *p)
 {
   normalize_filename (p, '\\');
 }
@@ -909,9 +1293,7 @@ unixtodos_filename (p)
    (From msdos.c...probably should figure out a way to share it,
    although this code isn't going to ever change.)  */
 int
-crlf_to_lf (n, buf)
-     register int n;
-     register unsigned char *buf;
+crlf_to_lf (register int n, register unsigned char *buf)
 {
   unsigned char *np = buf;
   unsigned char *startp = buf;
@@ -1089,6 +1471,30 @@ sigunblock (int sig)
   return 0;
 }
 
+int
+sigemptyset (sigset_t *set)
+{
+  return 0;
+}
+
+int
+sigaddset (sigset_t *set, int signo)
+{
+  return 0;
+}
+
+int
+sigfillset (sigset_t *set)
+{
+  return 0;
+}
+
+int
+sigprocmask (int how, const sigset_t *set, sigset_t *oset)
+{
+  return 0;
+}
+
 int
 setpgrp (int pid, int gid)
 {
@@ -1104,9 +1510,7 @@ alarm (int seconds)
 #define REG_ROOT "SOFTWARE\\GNU\\Emacs"
 
 LPBYTE
-w32_get_resource (key, lpdwtype)
-    char *key;
-    LPDWORD lpdwtype;
+w32_get_resource (char *key, LPDWORD lpdwtype)
 {
   LPBYTE lpvalue;
   HKEY hrootkey = NULL;
@@ -1127,7 +1531,7 @@ w32_get_resource (key, lpdwtype)
          return (lpvalue);
        }
 
-      if (lpvalue) xfree (lpvalue);
+      xfree (lpvalue);
 
       RegCloseKey (hrootkey);
     }
@@ -1144,7 +1548,7 @@ w32_get_resource (key, lpdwtype)
          return (lpvalue);
        }
 
-      if (lpvalue) xfree (lpvalue);
+      xfree (lpvalue);
 
       RegCloseKey (hrootkey);
     }
@@ -1226,7 +1630,7 @@ init_environment (char ** argv)
       {"LANG", NULL},
     };
 
-#define N_ENV_VARS sizeof(dflt_envvars)/sizeof(dflt_envvars[0])
+#define N_ENV_VARS sizeof (dflt_envvars)/sizeof (dflt_envvars[0])
 
     /* We need to copy dflt_envvars[] and work on the copy because we
        don't want the dumped Emacs to inherit the values of
@@ -1245,25 +1649,20 @@ init_environment (char ** argv)
       HRESULT profile_result;
       /* Dynamically load ShGetFolderPath, as it won't exist on versions
         of Windows 95 and NT4 that have not been updated to include
-        MSIE 5.  Also we don't link with shell32.dll by default.  */
-      HMODULE shell32_dll;
+        MSIE 5.  */
       ShGetFolderPath_fn get_folder_path;
-      shell32_dll = GetModuleHandle ("shell32.dll");
       get_folder_path = (ShGetFolderPath_fn)
-       GetProcAddress (shell32_dll, "SHGetFolderPathA");
+       GetProcAddress (GetModuleHandle ("shell32.dll"), "SHGetFolderPathA");
 
       if (get_folder_path != NULL)
        {
          profile_result = get_folder_path (NULL, CSIDL_APPDATA, NULL,
                                            0, default_home);
 
-         /* If we can't get the appdata dir, revert to old behaviour.  */
+         /* If we can't get the appdata dir, revert to old behavior.  */
          if (profile_result == S_OK)
            env_vars[0].def_value = default_home;
        }
-
-      /* Unload shell32.dll, it is not needed anymore.  */
-      FreeLibrary (shell32_dll);
     }
 
   /* Get default locale info and use it for LANG.  */
@@ -1296,7 +1695,7 @@ init_environment (char ** argv)
        abort ();
       *p = 0;
 
-      if ((p = strrchr (modname, '\\')) && stricmp (p, "\\bin") == 0)
+      if ((p = strrchr (modname, '\\')) && xstrcasecmp (p, "\\bin") == 0)
        {
          char buf[SET_ENV_BUF_SIZE];
 
@@ -1304,7 +1703,7 @@ init_environment (char ** argv)
          for (p = modname; *p; p++)
            if (*p == '\\') *p = '/';
 
-         _snprintf (buf, sizeof(buf)-1, "emacs_dir=%s", modname);
+         _snprintf (buf, sizeof (buf)-1, "emacs_dir=%s", modname);
          _putenv (strdup (buf));
        }
       /* Handle running emacs from the build directory: src/oo-spd/i386/  */
@@ -1312,7 +1711,7 @@ init_environment (char ** argv)
       /* FIXME: should use substring of get_emacs_configuration ().
         But I don't think the Windows build supports alpha, mips etc
          anymore, so have taken the easy option for now.  */
-      else if (p && stricmp (p, "\\i386") == 0)
+      else if (p && xstrcasecmp (p, "\\i386") == 0)
        {
          *p = 0;
          p = strrchr (modname, '\\');
@@ -1320,7 +1719,7 @@ init_environment (char ** argv)
            {
              *p = 0;
              p = strrchr (modname, '\\');
-             if (p && stricmp (p, "\\src") == 0)
+             if (p && xstrcasecmp (p, "\\src") == 0)
                {
                  char buf[SET_ENV_BUF_SIZE];
 
@@ -1328,7 +1727,7 @@ init_environment (char ** argv)
                  for (p = modname; *p; p++)
                    if (*p == '\\') *p = '/';
 
-                 _snprintf (buf, sizeof(buf)-1, "emacs_dir=%s", modname);
+                 _snprintf (buf, sizeof (buf)-1, "emacs_dir=%s", modname);
                  _putenv (strdup (buf));
                }
            }
@@ -1345,7 +1744,7 @@ init_environment (char ** argv)
                /* Also ignore empty environment variables.  */
                || *lpval == 0)
              {
-               if (lpval) xfree (lpval);
+               xfree (lpval);
                lpval = env_vars[i].def_value;
                dwType = REG_EXPAND_SZ;
                dont_free = 1;
@@ -1356,12 +1755,12 @@ init_environment (char ** argv)
                char buf1[SET_ENV_BUF_SIZE], buf2[SET_ENV_BUF_SIZE];
 
                if (dwType == REG_EXPAND_SZ)
-                 ExpandEnvironmentStrings ((LPSTR) lpval, buf1, sizeof(buf1));
+                 ExpandEnvironmentStrings ((LPSTR) lpval, buf1, sizeof (buf1));
                else if (dwType == REG_SZ)
                  strcpy (buf1, lpval);
                if (dwType == REG_EXPAND_SZ || dwType == REG_SZ)
                  {
-                   _snprintf (buf2, sizeof(buf2)-1, "%s=%s", env_vars[i].name,
+                   _snprintf (buf2, sizeof (buf2)-1, "%s=%s", env_vars[i].name,
                               buf1);
                    _putenv (strdup (buf2));
                  }
@@ -1652,7 +2051,7 @@ lookup_volume_info (char * root_dir)
   volume_info_data * info;
 
   for (info = volume_cache; info; info = info->next)
-    if (stricmp (info->root_dir, root_dir) == 0)
+    if (xstrcasecmp (info->root_dir, root_dir) == 0)
       break;
   return info;
 }
@@ -1704,7 +2103,7 @@ GetCachedVolumeInformation (char * root_dir)
      involve network access, and so is extremely quick).  */
 
   /* Map drive letter to UNC if remote. */
-  if ( isalpha( root_dir[0] ) && !fixed[ DRIVE_INDEX( root_dir[0] ) ] )
+  if (isalpha (root_dir[0]) && !fixed[DRIVE_INDEX (root_dir[0])])
     {
       char remote_name[ 256 ];
       char drive[3] = { root_dir[0], ':' };
@@ -1930,10 +2329,10 @@ is_exec (const char * name)
   char * p = strrchr (name, '.');
   return
     (p != NULL
-     && (stricmp (p, ".exe") == 0 ||
-        stricmp (p, ".com") == 0 ||
-        stricmp (p, ".bat") == 0 ||
-        stricmp (p, ".cmd") == 0));
+     && (xstrcasecmp (p, ".exe") == 0 ||
+        xstrcasecmp (p, ".com") == 0 ||
+        xstrcasecmp (p, ".bat") == 0 ||
+        xstrcasecmp (p, ".cmd") == 0));
 }
 
 /* Emulate the Unix directory procedures opendir, closedir,
@@ -2103,8 +2502,8 @@ open_unc_volume (const char *path)
   nr.lpComment = NULL;
   nr.lpProvider = NULL;
 
-  result = WNetOpenEnum(RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
-                       RESOURCEUSAGE_CONNECTABLE, &nr, &henum);
+  result = WNetOpenEnum (RESOURCE_GLOBALNET, RESOURCETYPE_DISK,
+                        RESOURCEUSAGE_CONNECTABLE, &nr, &henum);
 
   if (result == NO_ERROR)
     return henum;
@@ -2169,12 +2568,23 @@ logon_network_drive (const char *path)
   char share[MAX_PATH];
   int i, n_slashes;
   char drive[4];
+  UINT drvtype;
 
-  sprintf (drive, "%c:\\", path[0]);
+  if (IS_DIRECTORY_SEP (path[0]) && IS_DIRECTORY_SEP (path[1]))
+    drvtype = DRIVE_REMOTE;
+  else if (path[0] == '\0' || path[1] != ':')
+    drvtype = GetDriveType (NULL);
+  else
+    {
+      drive[0] = path[0];
+      drive[1] = ':';
+      drive[2] = '\\';
+      drive[3] = '\0';
+      drvtype = GetDriveType (drive);
+    }
 
   /* Only logon to networked drives.  */
-  if ((!IS_DIRECTORY_SEP (path[0]) || !IS_DIRECTORY_SEP (path[1]))
-      && GetDriveType (drive) != DRIVE_REMOTE)
+  if (drvtype != DRIVE_REMOTE)
     return;
 
   n_slashes = 2;
@@ -2269,7 +2679,7 @@ sys_creat (const char * path, int mode)
 }
 
 FILE *
-sys_fopen(const char * path, const char * mode)
+sys_fopen (const char * path, const char * mode)
 {
   int fd;
   int oflag;
@@ -2356,7 +2766,7 @@ sys_link (const char * old, const char * new)
 
          data.wid.dwStreamId = BACKUP_LINK;
          data.wid.dwStreamAttributes = 0;
-         data.wid.Size.LowPart = wlen * sizeof(WCHAR);
+         data.wid.Size.LowPart = wlen * sizeof (WCHAR);
          data.wid.Size.HighPart = 0;
          data.wid.dwStreamNameSize = 0;
 
@@ -2506,7 +2916,7 @@ sys_rename (const char * oldname, const char * newname)
        return -1;
     }
 
-  /* Emulate Unix behaviour - newname is deleted if it already exists
+  /* 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
@@ -2546,70 +2956,69 @@ sys_unlink (const char * path)
 }
 
 static FILETIME utc_base_ft;
-static long double utc_base;
+static ULONGLONG utc_base;  /* In 100ns units */
 static int init = 0;
 
+#define FILETIME_TO_U64(result, ft)        \
+  do {                                     \
+    ULARGE_INTEGER uiTemp;                 \
+    uiTemp.LowPart = (ft).dwLowDateTime;   \
+    uiTemp.HighPart = (ft).dwHighDateTime; \
+    result = uiTemp.QuadPart;              \
+  } while (0)
+
+static void
+initialize_utc_base (void)
+{
+  /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
+  SYSTEMTIME st;
+
+  st.wYear = 1970;
+  st.wMonth = 1;
+  st.wDay = 1;
+  st.wHour = 0;
+  st.wMinute = 0;
+  st.wSecond = 0;
+  st.wMilliseconds = 0;
+
+  SystemTimeToFileTime (&st, &utc_base_ft);
+  FILETIME_TO_U64 (utc_base, utc_base_ft);
+}
+
 static time_t
 convert_time (FILETIME ft)
 {
-  long double ret;
+  ULONGLONG tmp;
 
   if (!init)
     {
-      /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
-      SYSTEMTIME st;
-
-      st.wYear = 1970;
-      st.wMonth = 1;
-      st.wDay = 1;
-      st.wHour = 0;
-      st.wMinute = 0;
-      st.wSecond = 0;
-      st.wMilliseconds = 0;
-
-      SystemTimeToFileTime (&st, &utc_base_ft);
-      utc_base = (long double) utc_base_ft.dwHighDateTime
-       * 4096.0L * 1024.0L * 1024.0L + utc_base_ft.dwLowDateTime;
+      initialize_utc_base();
       init = 1;
     }
 
   if (CompareFileTime (&ft, &utc_base_ft) < 0)
     return 0;
 
-  ret = (long double) ft.dwHighDateTime
-    * 4096.0L * 1024.0L * 1024.0L + ft.dwLowDateTime;
-  ret -= utc_base;
-  return (time_t) (ret * 1e-7L);
+  FILETIME_TO_U64 (tmp, ft);
+  return (time_t) ((tmp - utc_base) / 10000000L);
 }
 
+
 void
 convert_from_time_t (time_t time, FILETIME * pft)
 {
-  long double tmp;
+  ULARGE_INTEGER tmp;
 
   if (!init)
     {
-      /* Determine the delta between 1-Jan-1601 and 1-Jan-1970. */
-      SYSTEMTIME st;
-
-      st.wYear = 1970;
-      st.wMonth = 1;
-      st.wDay = 1;
-      st.wHour = 0;
-      st.wMinute = 0;
-      st.wSecond = 0;
-      st.wMilliseconds = 0;
-
-      SystemTimeToFileTime (&st, &utc_base_ft);
-      utc_base = (long double) utc_base_ft.dwHighDateTime
-       * 4096 * 1024 * 1024 + utc_base_ft.dwLowDateTime;
+      initialize_utc_base ();
       init = 1;
     }
 
   /* time in 100ns units since 1-Jan-1601 */
-  tmp = (long double) time * 1e7 + utc_base;
-  pft->dwHighDateTime = (DWORD) (tmp / (4096.0 * 1024 * 1024));
-  pft->dwLowDateTime = (DWORD) (tmp - (4096.0 * 1024 * 1024) * pft->dwHighDateTime);
+  tmp.QuadPart = (ULONGLONG) time * 10000000L + utc_base;
+  pft->dwHighDateTime = tmp.HighPart;
+  pft->dwLowDateTime = tmp.LowPart;
 }
 
 #if 0
@@ -2693,12 +3102,75 @@ get_rid (PSID sid)
   return *get_sid_sub_authority (sid, n_subauthorities - 1);
 }
 
+/* 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;
+  char name[GNLEN+1];
+  unsigned char sid[FLEXIBLE_ARRAY_MEMBER];
+};
+
+static struct w32_id *w32_idlist;
+
+static int
+w32_cached_id (PSID sid, unsigned *id, char *name)
+{
+  struct w32_id *tail, *found;
+
+  for (found = NULL, tail = w32_idlist; tail; tail = tail->next)
+    {
+      if (equal_sid ((PSID)tail->sid, sid))
+       {
+         found = tail;
+         break;
+       }
+    }
+  if (found)
+    {
+      *id = found->rid;
+      strcpy (name, found->name);
+      return 1;
+    }
+  else
+    return 0;
+}
+
+static void
+w32_add_to_cache (PSID sid, unsigned id, char *name)
+{
+  DWORD sid_len;
+  struct w32_id *new_entry;
+
+  /* We don't want to leave behind stale cache from when Emacs was
+     dumped.  */
+  if (initialized)
+    {
+      sid_len = get_length_sid (sid);
+      new_entry = xmalloc (offsetof (struct w32_id, sid) + sid_len);
+      if (new_entry)
+       {
+         new_entry->rid = id;
+         strcpy (new_entry->name, name);
+         copy_sid (sid_len, (PSID)new_entry->sid, sid);
+         new_entry->next = w32_idlist;
+         w32_idlist = new_entry;
+       }
+    }
+}
+
 #define UID 1
 #define GID 2
 
 static int
 get_name_and_id (PSECURITY_DESCRIPTOR psd, const char *fname,
-                int *id, char *nm, int what)
+                unsigned *id, char *nm, int what)
 {
   PSID sid = NULL;
   char machine[MAX_COMPUTERNAME_LENGTH+1];
@@ -2707,7 +3179,7 @@ get_name_and_id (PSECURITY_DESCRIPTOR psd, const char *fname,
   char name[UNLEN+1];
   DWORD name_len = sizeof (name);
   char domain[1024];
-  DWORD domain_len = sizeof(domain);
+  DWORD domain_len = sizeof (domain);
   char *mp = NULL;
   int use_dflt = 0;
   int result;
@@ -2721,7 +3193,7 @@ get_name_and_id (PSECURITY_DESCRIPTOR psd, const char *fname,
 
   if (!result || !is_valid_sid (sid))
     use_dflt = 1;
-  else
+  else if (!w32_cached_id (sid, id, nm))
     {
       /* If FNAME is a UNC, we need to lookup account on the
         specified machine.  */
@@ -2746,6 +3218,7 @@ get_name_and_id (PSECURITY_DESCRIPTOR psd, const char *fname,
        {
          *id = get_rid (sid);
          strcpy (nm, name);
+         w32_add_to_cache (sid, *id, name);
        }
     }
   return use_dflt;
@@ -2785,6 +3258,28 @@ get_file_owner_and_group (
     }
 }
 
+/* Return non-zero if NAME is a potentially slow filesystem.  */
+int
+is_slow_fs (const char *name)
+{
+  char drive_root[4];
+  UINT devtype;
+
+  if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
+    devtype = DRIVE_REMOTE;       /* assume UNC name is remote */
+  else if (!(strlen (name) >= 2 && IS_DEVICE_SEP (name[1])))
+    devtype = GetDriveType (NULL); /* use root of current drive */
+  else
+    {
+      /* GetDriveType needs the root directory of the drive.  */
+      strncpy (drive_root, name, 2);
+      drive_root[2] = '\\';
+      drive_root[3] = '\0';
+      devtype = GetDriveType (drive_root);
+    }
+  return !(devtype == DRIVE_FIXED || devtype == DRIVE_RAMDISK);
+}
+
 /* MSVC stat function can't cope with UNC names and has other bugs, so
    replace it with our own.  This also allows us to calculate consistent
    inode values without hacks in the main Emacs code. */
@@ -2792,6 +3287,8 @@ int
 stat (const char * path, struct stat * buf)
 {
   char *name, *r;
+  char drive_root[4];
+  UINT devtype;
   WIN32_FIND_DATA wfd;
   HANDLE fh;
   unsigned __int64 fake_inode;
@@ -2877,7 +3374,7 @@ stat (const char * path, struct stat * buf)
       if (dir_find_handle != INVALID_HANDLE_VALUE
          && strnicmp (name, dir_pathname, len) == 0
          && IS_DIRECTORY_SEP (name[len])
-         && stricmp (name + len + 1, dir_static.d_name) == 0)
+         && xstrcasecmp (name + len + 1, dir_static.d_name) == 0)
        {
          /* This was the last entry returned by readdir.  */
          wfd = dir_find_data;
@@ -2897,8 +3394,7 @@ stat (const char * path, struct stat * buf)
     }
 
   if (!(NILP (Vw32_get_true_file_attributes)
-       || (EQ (Vw32_get_true_file_attributes, Qlocal) &&
-           GetDriveType (name) != DRIVE_FIXED))
+       || (EQ (Vw32_get_true_file_attributes, Qlocal) && is_slow_fs (name)))
       /* No access rights required to get info.  */
       && (fh = CreateFile (name, 0, 0, NULL, OPEN_EXISTING,
                           FILE_FLAG_BACKUP_SEMANTICS, NULL))
@@ -2961,8 +3457,7 @@ stat (const char * path, struct stat * buf)
 
       get_file_owner_and_group (NULL, name, buf);
     }
-  if (psd)
-    xfree (psd);
+  xfree (psd);
 
 #if 0
   /* Not sure if there is any point in this.  */
@@ -3103,10 +3598,10 @@ fstat (int desc, struct stat * buf)
 #if 0 /* no way of knowing the filename */
       char * p = strrchr (name, '.');
       if (p != NULL &&
-         (stricmp (p, ".exe") == 0 ||
-          stricmp (p, ".com") == 0 ||
-          stricmp (p, ".bat") == 0 ||
-          stricmp (p, ".cmd") == 0))
+         (xstrcasecmp (p, ".exe") == 0 ||
+          xstrcasecmp (p, ".com") == 0 ||
+          xstrcasecmp (p, ".bat") == 0 ||
+          xstrcasecmp (p, ".cmd") == 0))
        permission |= S_IEXEC;
 #endif
     }
@@ -3153,52 +3648,752 @@ utime (const char *name, struct utimbuf *times)
   return 0;
 }
 
-#ifdef HAVE_SOCKETS
+\f
+/* Support for browsing other processes and their attributes.  See
+   process.c for the Lisp bindings.  */
 
-/* Wrappers for  winsock functions to map between our file descriptors
-   and winsock's handles; also set h_errno for convenience.
+/* Helper wrapper functions.  */
 
-   To allow Emacs to run on systems which don't have winsock support
-   installed, we dynamically link to winsock on startup if present, and
-   otherwise provide the minimum necessary functionality
-   (eg. gethostname). */
+HANDLE WINAPI create_toolhelp32_snapshot (
+    DWORD Flags,
+    DWORD Ignored)
+{
+  static CreateToolhelp32Snapshot_Proc s_pfn_Create_Toolhelp32_Snapshot = NULL;
 
-/* function pointers for relevant socket functions */
-int (PASCAL *pfn_WSAStartup) (WORD wVersionRequired, LPWSADATA lpWSAData);
-void (PASCAL *pfn_WSASetLastError) (int iError);
-int (PASCAL *pfn_WSAGetLastError) (void);
-int (PASCAL *pfn_WSAEventSelect) (SOCKET s, HANDLE hEventObject, long lNetworkEvents);
-HANDLE (PASCAL *pfn_WSACreateEvent) (void);
-int (PASCAL *pfn_WSACloseEvent) (HANDLE hEvent);
-int (PASCAL *pfn_socket) (int af, int type, int protocol);
-int (PASCAL *pfn_bind) (SOCKET s, const struct sockaddr *addr, int namelen);
-int (PASCAL *pfn_connect) (SOCKET s, const struct sockaddr *addr, int namelen);
-int (PASCAL *pfn_ioctlsocket) (SOCKET s, long cmd, u_long *argp);
-int (PASCAL *pfn_recv) (SOCKET s, char * buf, int len, int flags);
-int (PASCAL *pfn_send) (SOCKET s, const char * buf, int len, int flags);
-int (PASCAL *pfn_closesocket) (SOCKET s);
-int (PASCAL *pfn_shutdown) (SOCKET s, int how);
-int (PASCAL *pfn_WSACleanup) (void);
+  if (g_b_init_create_toolhelp32_snapshot == 0)
+    {
+      g_b_init_create_toolhelp32_snapshot = 1;
+      s_pfn_Create_Toolhelp32_Snapshot = (CreateToolhelp32Snapshot_Proc)
+       GetProcAddress (GetModuleHandle ("kernel32.dll"),
+                       "CreateToolhelp32Snapshot");
+    }
+  if (s_pfn_Create_Toolhelp32_Snapshot == NULL)
+    {
+      return INVALID_HANDLE_VALUE;
+    }
+  return (s_pfn_Create_Toolhelp32_Snapshot (Flags, Ignored));
+}
 
-u_short (PASCAL *pfn_htons) (u_short hostshort);
-u_short (PASCAL *pfn_ntohs) (u_short netshort);
-unsigned long (PASCAL *pfn_inet_addr) (const char * cp);
-int (PASCAL *pfn_gethostname) (char * name, int namelen);
-struct hostent * (PASCAL *pfn_gethostbyname) (const char * name);
-struct servent * (PASCAL *pfn_getservbyname) (const char * name, const char * proto);
-int (PASCAL *pfn_getpeername) (SOCKET s, struct sockaddr *addr, int * namelen);
-int (PASCAL *pfn_setsockopt) (SOCKET s, int level, int optname,
-                             const char * optval, int optlen);
-int (PASCAL *pfn_listen) (SOCKET s, int backlog);
-int (PASCAL *pfn_getsockname) (SOCKET s, struct sockaddr * name,
-                              int * namelen);
-SOCKET (PASCAL *pfn_accept) (SOCKET s, struct sockaddr * addr, int * addrlen);
-int (PASCAL *pfn_recvfrom) (SOCKET s, char * buf, int len, int flags,
-                      struct sockaddr * from, int * fromlen);
-int (PASCAL *pfn_sendto) (SOCKET s, const char * buf, int len, int flags,
-                         const struct sockaddr * to, int tolen);
+BOOL WINAPI process32_first (
+    HANDLE hSnapshot,
+    LPPROCESSENTRY32 lppe)
+{
+  static Process32First_Proc s_pfn_Process32_First = NULL;
 
-/* SetHandleInformation is only needed to make sockets non-inheritable. */
+  if (g_b_init_process32_first == 0)
+    {
+      g_b_init_process32_first = 1;
+      s_pfn_Process32_First = (Process32First_Proc)
+       GetProcAddress (GetModuleHandle ("kernel32.dll"),
+                       "Process32First");
+    }
+  if (s_pfn_Process32_First == NULL)
+    {
+      return FALSE;
+    }
+  return (s_pfn_Process32_First (hSnapshot, lppe));
+}
+
+BOOL WINAPI process32_next (
+    HANDLE hSnapshot,
+    LPPROCESSENTRY32 lppe)
+{
+  static Process32Next_Proc s_pfn_Process32_Next = NULL;
+
+  if (g_b_init_process32_next == 0)
+    {
+      g_b_init_process32_next = 1;
+      s_pfn_Process32_Next = (Process32Next_Proc)
+       GetProcAddress (GetModuleHandle ("kernel32.dll"),
+                       "Process32Next");
+    }
+  if (s_pfn_Process32_Next == NULL)
+    {
+      return FALSE;
+    }
+  return (s_pfn_Process32_Next (hSnapshot, lppe));
+}
+
+BOOL WINAPI open_thread_token (
+    HANDLE ThreadHandle,
+    DWORD DesiredAccess,
+    BOOL OpenAsSelf,
+    PHANDLE TokenHandle)
+{
+  static OpenThreadToken_Proc s_pfn_Open_Thread_Token = NULL;
+  HMODULE hm_advapi32 = NULL;
+  if (is_windows_9x () == TRUE)
+    {
+      SetLastError (ERROR_NOT_SUPPORTED);
+      return FALSE;
+    }
+  if (g_b_init_open_thread_token == 0)
+    {
+      g_b_init_open_thread_token = 1;
+      hm_advapi32 = LoadLibrary ("Advapi32.dll");
+      s_pfn_Open_Thread_Token =
+        (OpenThreadToken_Proc) GetProcAddress (hm_advapi32, "OpenThreadToken");
+    }
+  if (s_pfn_Open_Thread_Token == NULL)
+    {
+      SetLastError (ERROR_NOT_SUPPORTED);
+      return FALSE;
+    }
+  return (
+      s_pfn_Open_Thread_Token (
+          ThreadHandle,
+          DesiredAccess,
+         OpenAsSelf,
+          TokenHandle)
+      );
+}
+
+BOOL WINAPI impersonate_self (
+    SECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
+{
+  static ImpersonateSelf_Proc s_pfn_Impersonate_Self = NULL;
+  HMODULE hm_advapi32 = NULL;
+  if (is_windows_9x () == TRUE)
+    {
+      return FALSE;
+    }
+  if (g_b_init_impersonate_self == 0)
+    {
+      g_b_init_impersonate_self = 1;
+      hm_advapi32 = LoadLibrary ("Advapi32.dll");
+      s_pfn_Impersonate_Self =
+        (ImpersonateSelf_Proc) GetProcAddress (hm_advapi32, "ImpersonateSelf");
+    }
+  if (s_pfn_Impersonate_Self == NULL)
+    {
+      return FALSE;
+    }
+  return s_pfn_Impersonate_Self (ImpersonationLevel);
+}
+
+BOOL WINAPI revert_to_self (void)
+{
+  static RevertToSelf_Proc s_pfn_Revert_To_Self = NULL;
+  HMODULE hm_advapi32 = NULL;
+  if (is_windows_9x () == TRUE)
+    {
+      return FALSE;
+    }
+  if (g_b_init_revert_to_self == 0)
+    {
+      g_b_init_revert_to_self = 1;
+      hm_advapi32 = LoadLibrary ("Advapi32.dll");
+      s_pfn_Revert_To_Self =
+        (RevertToSelf_Proc) GetProcAddress (hm_advapi32, "RevertToSelf");
+    }
+  if (s_pfn_Revert_To_Self == NULL)
+    {
+      return FALSE;
+    }
+  return s_pfn_Revert_To_Self ();
+}
+
+BOOL WINAPI get_process_memory_info (
+    HANDLE h_proc,
+    PPROCESS_MEMORY_COUNTERS mem_counters,
+    DWORD bufsize)
+{
+  static GetProcessMemoryInfo_Proc s_pfn_Get_Process_Memory_Info = NULL;
+  HMODULE hm_psapi = NULL;
+  if (is_windows_9x () == TRUE)
+    {
+      return FALSE;
+    }
+  if (g_b_init_get_process_memory_info == 0)
+    {
+      g_b_init_get_process_memory_info = 1;
+      hm_psapi = LoadLibrary ("Psapi.dll");
+      if (hm_psapi)
+       s_pfn_Get_Process_Memory_Info = (GetProcessMemoryInfo_Proc)
+         GetProcAddress (hm_psapi, "GetProcessMemoryInfo");
+    }
+  if (s_pfn_Get_Process_Memory_Info == NULL)
+    {
+      return FALSE;
+    }
+  return s_pfn_Get_Process_Memory_Info (h_proc, mem_counters, bufsize);
+}
+
+BOOL WINAPI get_process_working_set_size (
+    HANDLE h_proc,
+    DWORD *minrss,
+    DWORD *maxrss)
+{
+  static GetProcessWorkingSetSize_Proc
+    s_pfn_Get_Process_Working_Set_Size = NULL;
+
+  if (is_windows_9x () == TRUE)
+    {
+      return FALSE;
+    }
+  if (g_b_init_get_process_working_set_size == 0)
+    {
+      g_b_init_get_process_working_set_size = 1;
+      s_pfn_Get_Process_Working_Set_Size = (GetProcessWorkingSetSize_Proc)
+       GetProcAddress (GetModuleHandle ("kernel32.dll"),
+                       "GetProcessWorkingSetSize");
+    }
+  if (s_pfn_Get_Process_Working_Set_Size == NULL)
+    {
+      return FALSE;
+    }
+  return s_pfn_Get_Process_Working_Set_Size (h_proc, minrss, maxrss);
+}
+
+BOOL WINAPI global_memory_status (
+    MEMORYSTATUS *buf)
+{
+  static GlobalMemoryStatus_Proc s_pfn_Global_Memory_Status = NULL;
+
+  if (is_windows_9x () == TRUE)
+    {
+      return FALSE;
+    }
+  if (g_b_init_global_memory_status == 0)
+    {
+      g_b_init_global_memory_status = 1;
+      s_pfn_Global_Memory_Status = (GlobalMemoryStatus_Proc)
+       GetProcAddress (GetModuleHandle ("kernel32.dll"),
+                       "GlobalMemoryStatus");
+    }
+  if (s_pfn_Global_Memory_Status == NULL)
+    {
+      return FALSE;
+    }
+  return s_pfn_Global_Memory_Status (buf);
+}
+
+BOOL WINAPI global_memory_status_ex (
+    MEMORY_STATUS_EX *buf)
+{
+  static GlobalMemoryStatusEx_Proc s_pfn_Global_Memory_Status_Ex = NULL;
+
+  if (is_windows_9x () == TRUE)
+    {
+      return FALSE;
+    }
+  if (g_b_init_global_memory_status_ex == 0)
+    {
+      g_b_init_global_memory_status_ex = 1;
+      s_pfn_Global_Memory_Status_Ex = (GlobalMemoryStatusEx_Proc)
+       GetProcAddress (GetModuleHandle ("kernel32.dll"),
+                       "GlobalMemoryStatusEx");
+    }
+  if (s_pfn_Global_Memory_Status_Ex == NULL)
+    {
+      return FALSE;
+    }
+  return s_pfn_Global_Memory_Status_Ex (buf);
+}
+
+Lisp_Object
+list_system_processes (void)
+{
+  struct gcpro gcpro1;
+  Lisp_Object proclist = Qnil;
+  HANDLE h_snapshot;
+
+  h_snapshot = create_toolhelp32_snapshot (TH32CS_SNAPPROCESS, 0);
+
+  if (h_snapshot != INVALID_HANDLE_VALUE)
+    {
+      PROCESSENTRY32 proc_entry;
+      DWORD proc_id;
+      BOOL res;
+
+      GCPRO1 (proclist);
+
+      proc_entry.dwSize = sizeof (PROCESSENTRY32);
+      for (res = process32_first (h_snapshot, &proc_entry); res;
+          res = process32_next  (h_snapshot, &proc_entry))
+       {
+         proc_id = proc_entry.th32ProcessID;
+         proclist = Fcons (make_fixnum_or_float (proc_id), proclist);
+       }
+
+      CloseHandle (h_snapshot);
+      UNGCPRO;
+      proclist = Fnreverse (proclist);
+    }
+
+  return proclist;
+}
+
+static int
+enable_privilege (LPCTSTR priv_name, BOOL enable_p, TOKEN_PRIVILEGES *old_priv)
+{
+  TOKEN_PRIVILEGES priv;
+  DWORD priv_size = sizeof (priv);
+  DWORD opriv_size = sizeof (*old_priv);
+  HANDLE h_token = NULL;
+  HANDLE h_thread = GetCurrentThread ();
+  int ret_val = 0;
+  BOOL res;
+
+  res = open_thread_token (h_thread,
+                          TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
+                          FALSE, &h_token);
+  if (!res && GetLastError () == ERROR_NO_TOKEN)
+    {
+      if (impersonate_self (SecurityImpersonation))
+         res = open_thread_token (h_thread,
+                                  TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
+                                  FALSE, &h_token);
+    }
+  if (res)
+    {
+      priv.PrivilegeCount = 1;
+      priv.Privileges[0].Attributes = enable_p ? SE_PRIVILEGE_ENABLED : 0;
+      LookupPrivilegeValue (NULL, priv_name, &priv.Privileges[0].Luid);
+      if (AdjustTokenPrivileges (h_token, FALSE, &priv, priv_size,
+                                old_priv, &opriv_size)
+         && GetLastError () != ERROR_NOT_ALL_ASSIGNED)
+       ret_val = 1;
+    }
+  if (h_token)
+    CloseHandle (h_token);
+
+  return ret_val;
+}
+
+static int
+restore_privilege (TOKEN_PRIVILEGES *priv)
+{
+  DWORD priv_size = sizeof (*priv);
+  HANDLE h_token = NULL;
+  int ret_val = 0;
+
+  if (open_thread_token (GetCurrentThread (),
+                        TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
+                        FALSE, &h_token))
+    {
+      if (AdjustTokenPrivileges (h_token, FALSE, priv, priv_size, NULL, NULL)
+         && GetLastError () != ERROR_NOT_ALL_ASSIGNED)
+       ret_val = 1;
+    }
+  if (h_token)
+    CloseHandle (h_token);
+
+  return ret_val;
+}
+
+static Lisp_Object
+ltime (long time_sec, long time_usec)
+{
+  return list3 (make_number ((time_sec >> 16) & 0xffff),
+               make_number (time_sec & 0xffff),
+               make_number (time_usec));
+}
+
+#define U64_TO_LISP_TIME(time) ltime ((time) / 1000000L, (time) % 1000000L)
+
+static int
+process_times (HANDLE h_proc, Lisp_Object *ctime, Lisp_Object *etime,
+              Lisp_Object *stime, Lisp_Object *utime, Lisp_Object *ttime,
+              double *pcpu)
+{
+  FILETIME ft_creation, ft_exit, ft_kernel, ft_user, ft_current;
+  ULONGLONG tem1, tem2, tem3, tem;
+
+  if (!h_proc
+      || !get_process_times_fn
+      || !(*get_process_times_fn) (h_proc, &ft_creation, &ft_exit,
+                                  &ft_kernel, &ft_user))
+    return 0;
+
+  GetSystemTimeAsFileTime (&ft_current);
+
+  FILETIME_TO_U64 (tem1, ft_kernel);
+  tem1 /= 10L;
+  *stime = U64_TO_LISP_TIME (tem1);
+
+  FILETIME_TO_U64 (tem2, ft_user);
+  tem2 /= 10L;
+  *utime = U64_TO_LISP_TIME (tem2);
+
+  tem3 = tem1 + tem2;
+  *ttime = U64_TO_LISP_TIME (tem3);
+
+  FILETIME_TO_U64 (tem, ft_creation);
+  /* Process no 4 (System) returns zero creation time.  */
+  if (tem)
+    tem = (tem - utc_base) / 10L;
+  *ctime = U64_TO_LISP_TIME (tem);
+
+  if (tem)
+    {
+      FILETIME_TO_U64 (tem3, ft_current);
+      tem = (tem3 - utc_base) / 10L - tem;
+    }
+  *etime = U64_TO_LISP_TIME (tem);
+
+  if (tem)
+    {
+      *pcpu = 100.0 * (tem1 + tem2) / tem;
+      if (*pcpu > 100)
+       *pcpu = 100.0;
+    }
+  else
+    *pcpu = 0;
+
+  return 1;
+}
+
+Lisp_Object
+system_process_attributes (Lisp_Object pid)
+{
+  struct gcpro gcpro1, gcpro2, gcpro3;
+  Lisp_Object attrs = Qnil;
+  Lisp_Object cmd_str, decoded_cmd, tem;
+  HANDLE h_snapshot, h_proc;
+  DWORD proc_id;
+  int found_proc = 0;
+  char uname[UNLEN+1], gname[GNLEN+1], domain[1025];
+  DWORD ulength = sizeof (uname), dlength = sizeof (domain), needed;
+  DWORD glength = sizeof (gname);
+  HANDLE token = NULL;
+  SID_NAME_USE user_type;
+  unsigned char *buf = NULL;
+  DWORD blen = 0;
+  TOKEN_USER user_token;
+  TOKEN_PRIMARY_GROUP group_token;
+  unsigned euid;
+  unsigned egid;
+  DWORD sess;
+  PROCESS_MEMORY_COUNTERS mem;
+  PROCESS_MEMORY_COUNTERS_EX mem_ex;
+  DWORD minrss, maxrss;
+  MEMORYSTATUS memst;
+  MEMORY_STATUS_EX memstex;
+  double totphys = 0.0;
+  Lisp_Object ctime, stime, utime, etime, ttime;
+  double pcpu;
+  BOOL result = FALSE;
+
+  CHECK_NUMBER_OR_FLOAT (pid);
+  proc_id = FLOATP (pid) ? XFLOAT_DATA (pid) : XINT (pid);
+
+  h_snapshot = create_toolhelp32_snapshot (TH32CS_SNAPPROCESS, 0);
+
+  GCPRO3 (attrs, decoded_cmd, tem);
+
+  if (h_snapshot != INVALID_HANDLE_VALUE)
+    {
+      PROCESSENTRY32 pe;
+      BOOL res;
+
+      pe.dwSize = sizeof (PROCESSENTRY32);
+      for (res = process32_first (h_snapshot, &pe); res;
+          res = process32_next  (h_snapshot, &pe))
+       {
+         if (proc_id == pe.th32ProcessID)
+           {
+             if (proc_id == 0)
+               decoded_cmd = build_string ("Idle");
+             else
+               {
+                 /* Decode the command name from locale-specific
+                    encoding.  */
+                 cmd_str = make_unibyte_string (pe.szExeFile,
+                                                strlen (pe.szExeFile));
+                 decoded_cmd =
+                   code_convert_string_norecord (cmd_str,
+                                                 Vlocale_coding_system, 0);
+               }
+             attrs = Fcons (Fcons (Qcomm, decoded_cmd), attrs);
+             attrs = Fcons (Fcons (Qppid,
+                                   make_fixnum_or_float (pe.th32ParentProcessID)),
+                            attrs);
+             attrs = Fcons (Fcons (Qpri, make_number (pe.pcPriClassBase)),
+                            attrs);
+             attrs = Fcons (Fcons (Qthcount,
+                                   make_fixnum_or_float (pe.cntThreads)),
+                            attrs);
+             found_proc = 1;
+             break;
+           }
+       }
+
+      CloseHandle (h_snapshot);
+    }
+
+  if (!found_proc)
+    {
+      UNGCPRO;
+      return Qnil;
+    }
+
+  h_proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
+                       FALSE, proc_id);
+  /* If we were denied a handle to the process, try again after
+     enabling the SeDebugPrivilege in our process.  */
+  if (!h_proc)
+    {
+      TOKEN_PRIVILEGES priv_current;
+
+      if (enable_privilege (SE_DEBUG_NAME, TRUE, &priv_current))
+       {
+         h_proc = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
+                               FALSE, proc_id);
+         restore_privilege (&priv_current);
+         revert_to_self ();
+       }
+    }
+  if (h_proc)
+    {
+      result = open_process_token (h_proc, TOKEN_QUERY, &token);
+      if (result)
+       {
+         result = get_token_information (token, TokenUser, NULL, 0, &blen);
+         if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
+           {
+             buf = xmalloc (blen);
+             result = get_token_information (token, TokenUser,
+                                             (LPVOID)buf, blen, &needed);
+             if (result)
+               {
+                 memcpy (&user_token, buf, sizeof (user_token));
+                 if (!w32_cached_id (user_token.User.Sid, &euid, uname))
+                   {
+                     euid = get_rid (user_token.User.Sid);
+                     result = lookup_account_sid (NULL, user_token.User.Sid,
+                                                  uname, &ulength,
+                                                  domain, &dlength,
+                                                  &user_type);
+                     if (result)
+                       w32_add_to_cache (user_token.User.Sid, euid, uname);
+                     else
+                       {
+                         strcpy (uname, "unknown");
+                         result = TRUE;
+                       }
+                   }
+                 ulength = strlen (uname);
+               }
+           }
+       }
+      if (result)
+       {
+         /* Determine a reasonable euid and gid values.  */
+         if (xstrcasecmp ("administrator", uname) == 0)
+           {
+             euid = 500;       /* well-known Administrator uid */
+             egid = 513;       /* well-known None gid */
+           }
+         else
+           {
+             /* Get group id and name.  */
+             result = get_token_information (token, TokenPrimaryGroup,
+                                             (LPVOID)buf, blen, &needed);
+             if (!result && GetLastError () == ERROR_INSUFFICIENT_BUFFER)
+               {
+                 buf = xrealloc (buf, blen = needed);
+                 result = get_token_information (token, TokenPrimaryGroup,
+                                                 (LPVOID)buf, blen, &needed);
+               }
+             if (result)
+               {
+                 memcpy (&group_token, buf, sizeof (group_token));
+                 if (!w32_cached_id (group_token.PrimaryGroup, &egid, gname))
+                   {
+                     egid = get_rid (group_token.PrimaryGroup);
+                     dlength = sizeof (domain);
+                     result =
+                       lookup_account_sid (NULL, group_token.PrimaryGroup,
+                                           gname, &glength, NULL, &dlength,
+                                           &user_type);
+                     if (result)
+                       w32_add_to_cache (group_token.PrimaryGroup,
+                                         egid, gname);
+                     else
+                       {
+                         strcpy (gname, "None");
+                         result = TRUE;
+                       }
+                   }
+                 glength = strlen (gname);
+               }
+           }
+       }
+      xfree (buf);
+    }
+  if (!result)
+    {
+      if (!is_windows_9x ())
+       {
+         /* We couldn't open the process token, presumably because of
+            insufficient access rights.  Assume this process is run
+            by the system.  */
+         strcpy (uname, "SYSTEM");
+         strcpy (gname, "None");
+         euid = 18;    /* SYSTEM */
+         egid = 513;   /* None */
+         glength = strlen (gname);
+         ulength = strlen (uname);
+       }
+      /* If we are running under Windows 9X, where security calls are
+        not supported, we assume all processes are run by the current
+        user.  */
+      else if (GetUserName (uname, &ulength))
+       {
+         if (xstrcasecmp ("administrator", uname) == 0)
+           euid = 0;
+         else
+           euid = 123;
+         egid = euid;
+         strcpy (gname, "None");
+         glength = strlen (gname);
+         ulength = strlen (uname);
+       }
+      else
+       {
+         euid = 123;
+         egid = 123;
+         strcpy (uname, "administrator");
+         ulength = strlen (uname);
+         strcpy (gname, "None");
+         glength = strlen (gname);
+       }
+      if (token)
+       CloseHandle (token);
+    }
+
+  attrs = Fcons (Fcons (Qeuid, make_fixnum_or_float (euid)), attrs);
+  tem = make_unibyte_string (uname, ulength);
+  attrs = Fcons (Fcons (Quser,
+                        code_convert_string_norecord (tem, Vlocale_coding_system, 0)),
+                attrs);
+  attrs = Fcons (Fcons (Qegid, make_fixnum_or_float (egid)), attrs);
+  tem = make_unibyte_string (gname, glength);
+  attrs = Fcons (Fcons (Qgroup,
+                        code_convert_string_norecord (tem, Vlocale_coding_system, 0)),
+                attrs);
+
+  if (global_memory_status_ex (&memstex))
+#if __GNUC__ || (defined (_MSC_VER) && _MSC_VER >= 1300)
+    totphys = memstex.ullTotalPhys / 1024.0;
+#else
+  /* Visual Studio 6 cannot convert an unsigned __int64 type to
+     double, so we need to do this for it...  */
+    {
+      DWORD tot_hi = memstex.ullTotalPhys >> 32;
+      DWORD tot_md = (memstex.ullTotalPhys & 0x00000000ffffffff) >> 10;
+      DWORD tot_lo = memstex.ullTotalPhys % 1024;
+
+      totphys = tot_hi * 4194304.0 + tot_md + tot_lo / 1024.0;
+    }
+#endif /* __GNUC__ || _MSC_VER >= 1300 */
+  else if (global_memory_status (&memst))
+    totphys = memst.dwTotalPhys / 1024.0;
+
+  if (h_proc
+      && get_process_memory_info (h_proc, (PROCESS_MEMORY_COUNTERS *)&mem_ex,
+                                 sizeof (mem_ex)))
+    {
+      DWORD rss = mem_ex.WorkingSetSize / 1024;
+
+      attrs = Fcons (Fcons (Qmajflt,
+                           make_fixnum_or_float (mem_ex.PageFaultCount)),
+                    attrs);
+      attrs = Fcons (Fcons (Qvsize,
+                           make_fixnum_or_float (mem_ex.PrivateUsage / 1024)),
+                    attrs);
+      attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (rss)), attrs);
+      if (totphys)
+       attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
+    }
+  else if (h_proc
+          && get_process_memory_info (h_proc, &mem, sizeof (mem)))
+    {
+      DWORD rss = mem_ex.WorkingSetSize / 1024;
+
+      attrs = Fcons (Fcons (Qmajflt,
+                           make_fixnum_or_float (mem.PageFaultCount)),
+                    attrs);
+      attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (rss)), attrs);
+      if (totphys)
+       attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
+    }
+  else if (h_proc
+          && get_process_working_set_size (h_proc, &minrss, &maxrss))
+    {
+      DWORD rss = maxrss / 1024;
+
+      attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (maxrss / 1024)), attrs);
+      if (totphys)
+       attrs = Fcons (Fcons (Qpmem, make_float (100. * rss / totphys)), attrs);
+    }
+
+  if (process_times (h_proc, &ctime, &etime, &stime, &utime, &ttime, &pcpu))
+    {
+      attrs = Fcons (Fcons (Qutime, utime), attrs);
+      attrs = Fcons (Fcons (Qstime, stime), attrs);
+      attrs = Fcons (Fcons (Qtime,  ttime), attrs);
+      attrs = Fcons (Fcons (Qstart, ctime), attrs);
+      attrs = Fcons (Fcons (Qetime, etime), attrs);
+      attrs = Fcons (Fcons (Qpcpu, make_float (pcpu)), attrs);
+    }
+
+  /* FIXME: Retrieve command line by walking the PEB of the process.  */
+
+  if (h_proc)
+    CloseHandle (h_proc);
+  UNGCPRO;
+  return attrs;
+}
+
+\f
+#ifdef HAVE_SOCKETS
+
+/* Wrappers for  winsock functions to map between our file descriptors
+   and winsock's handles; also set h_errno for convenience.
+
+   To allow Emacs to run on systems which don't have winsock support
+   installed, we dynamically link to winsock on startup if present, and
+   otherwise provide the minimum necessary functionality
+   (eg. gethostname). */
+
+/* function pointers for relevant socket functions */
+int (PASCAL *pfn_WSAStartup) (WORD wVersionRequired, LPWSADATA lpWSAData);
+void (PASCAL *pfn_WSASetLastError) (int iError);
+int (PASCAL *pfn_WSAGetLastError) (void);
+int (PASCAL *pfn_WSAEventSelect) (SOCKET s, HANDLE hEventObject, long lNetworkEvents);
+HANDLE (PASCAL *pfn_WSACreateEvent) (void);
+int (PASCAL *pfn_WSACloseEvent) (HANDLE hEvent);
+int (PASCAL *pfn_socket) (int af, int type, int protocol);
+int (PASCAL *pfn_bind) (SOCKET s, const struct sockaddr *addr, int namelen);
+int (PASCAL *pfn_connect) (SOCKET s, const struct sockaddr *addr, int namelen);
+int (PASCAL *pfn_ioctlsocket) (SOCKET s, long cmd, u_long *argp);
+int (PASCAL *pfn_recv) (SOCKET s, char * buf, int len, int flags);
+int (PASCAL *pfn_send) (SOCKET s, const char * buf, int len, int flags);
+int (PASCAL *pfn_closesocket) (SOCKET s);
+int (PASCAL *pfn_shutdown) (SOCKET s, int how);
+int (PASCAL *pfn_WSACleanup) (void);
+
+u_short (PASCAL *pfn_htons) (u_short hostshort);
+u_short (PASCAL *pfn_ntohs) (u_short netshort);
+unsigned long (PASCAL *pfn_inet_addr) (const char * cp);
+int (PASCAL *pfn_gethostname) (char * name, int namelen);
+struct hostent * (PASCAL *pfn_gethostbyname) (const char * name);
+struct servent * (PASCAL *pfn_getservbyname) (const char * name, const char * proto);
+int (PASCAL *pfn_getpeername) (SOCKET s, struct sockaddr *addr, int * namelen);
+int (PASCAL *pfn_setsockopt) (SOCKET s, int level, int optname,
+                             const char * optval, int optlen);
+int (PASCAL *pfn_listen) (SOCKET s, int backlog);
+int (PASCAL *pfn_getsockname) (SOCKET s, struct sockaddr * name,
+                              int * namelen);
+SOCKET (PASCAL *pfn_accept) (SOCKET s, struct sockaddr * addr, int * addrlen);
+int (PASCAL *pfn_recvfrom) (SOCKET s, char * buf, int len, int flags,
+                      struct sockaddr * from, int * fromlen);
+int (PASCAL *pfn_sendto) (SOCKET s, const char * buf, int len, int flags,
+                         const struct sockaddr * to, int tolen);
+
+/* SetHandleInformation is only needed to make sockets non-inheritable. */
 BOOL (WINAPI *pfn_SetHandleInformation) (HANDLE object, DWORD mask, DWORD flags);
 #ifndef HANDLE_FLAG_INHERIT
 #define HANDLE_FLAG_INHERIT    1
@@ -3249,34 +4444,34 @@ init_winsock (int load_now)
       if ((pfn_##fn = (void *) GetProcAddress (winsock_lib, #fn)) == NULL) \
         goto fail;
 
-      LOAD_PROC( WSAStartup );
-      LOAD_PROC( WSASetLastError );
-      LOAD_PROC( WSAGetLastError );
-      LOAD_PROC( WSAEventSelect );
-      LOAD_PROC( WSACreateEvent );
-      LOAD_PROC( WSACloseEvent );
-      LOAD_PROC( socket );
-      LOAD_PROC( bind );
-      LOAD_PROC( connect );
-      LOAD_PROC( ioctlsocket );
-      LOAD_PROC( recv );
-      LOAD_PROC( send );
-      LOAD_PROC( closesocket );
-      LOAD_PROC( shutdown );
-      LOAD_PROC( htons );
-      LOAD_PROC( ntohs );
-      LOAD_PROC( inet_addr );
-      LOAD_PROC( gethostname );
-      LOAD_PROC( gethostbyname );
-      LOAD_PROC( getservbyname );
-      LOAD_PROC( getpeername );
-      LOAD_PROC( WSACleanup );
-      LOAD_PROC( setsockopt );
-      LOAD_PROC( listen );
-      LOAD_PROC( getsockname );
-      LOAD_PROC( accept );
-      LOAD_PROC( recvfrom );
-      LOAD_PROC( sendto );
+      LOAD_PROC (WSAStartup);
+      LOAD_PROC (WSASetLastError);
+      LOAD_PROC (WSAGetLastError);
+      LOAD_PROC (WSAEventSelect);
+      LOAD_PROC (WSACreateEvent);
+      LOAD_PROC (WSACloseEvent);
+      LOAD_PROC (socket);
+      LOAD_PROC (bind);
+      LOAD_PROC (connect);
+      LOAD_PROC (ioctlsocket);
+      LOAD_PROC (recv);
+      LOAD_PROC (send);
+      LOAD_PROC (closesocket);
+      LOAD_PROC (shutdown);
+      LOAD_PROC (htons);
+      LOAD_PROC (ntohs);
+      LOAD_PROC (inet_addr);
+      LOAD_PROC (gethostname);
+      LOAD_PROC (gethostbyname);
+      LOAD_PROC (getservbyname);
+      LOAD_PROC (getpeername);
+      LOAD_PROC (WSACleanup);
+      LOAD_PROC (setsockopt);
+      LOAD_PROC (listen);
+      LOAD_PROC (getsockname);
+      LOAD_PROC (accept);
+      LOAD_PROC (recvfrom);
+      LOAD_PROC (sendto);
 #undef LOAD_PROC
 
       /* specify version 1.1 of winsock */
@@ -3312,11 +4507,11 @@ init_winsock (int load_now)
 
 int h_errno = 0;
 
-/* function to set h_errno for compatability; map winsock error codes to
+/* function to set h_errno for compatibility; map winsock error codes to
    normal system codes where they overlap (non-overlapping definitions
    are already in <sys/socket.h> */
 static void
-set_errno ()
+set_errno (void)
 {
   if (winsock_lib == NULL)
     h_errno = EINVAL;
@@ -3338,7 +4533,7 @@ set_errno ()
 }
 
 static void
-check_errno ()
+check_errno (void)
 {
   if (h_errno == 0 && winsock_lib != NULL)
     pfn_WSASetLastError (0);
@@ -3421,7 +4616,7 @@ struct {
 };
 
 char *
-sys_strerror(int error_no)
+sys_strerror (int error_no)
 {
   int i;
   static char unknown_msg[40];
@@ -3433,7 +4628,7 @@ sys_strerror(int error_no)
     if (_wsa_errlist[i].errnum == error_no)
       return _wsa_errlist[i].msg;
 
-  sprintf(unknown_msg, "Unidentified error: %d", error_no);
+  sprintf (unknown_msg, "Unidentified error: %d", error_no);
   return unknown_msg;
 }
 
@@ -3452,7 +4647,7 @@ sys_strerror(int error_no)
 int socket_to_fd (SOCKET s);
 
 int
-sys_socket(int af, int type, int protocol)
+sys_socket (int af, int type, int protocol)
 {
   SOCKET s;
 
@@ -3655,7 +4850,7 @@ sys_gethostname (char * name, int namelen)
 }
 
 struct hostent *
-sys_gethostbyname(const char * name)
+sys_gethostbyname (const char * name)
 {
   struct hostent * host;
 
@@ -3673,7 +4868,7 @@ sys_gethostbyname(const char * name)
 }
 
 struct servent *
-sys_getservbyname(const char * name, const char * proto)
+sys_getservbyname (const char * name, const char * proto)
 {
   struct servent * serv;
 
@@ -3828,7 +5023,7 @@ sys_accept (int s, struct sockaddr * addr, int * addrlen)
 
 int
 sys_recvfrom (int s, char * buf, int len, int flags,
-         struct sockaddr * from, int * fromlen)
+             struct sockaddr * from, int * fromlen)
 {
   if (winsock_lib == NULL)
     {
@@ -4063,10 +5258,10 @@ _sys_read_ahead (int fd)
   if (cp == NULL || cp->fd != fd || cp->status != STATUS_READ_READY)
     return STATUS_READ_ERROR;
 
-  if ((fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET)) == 0
+  if ((fd_info[fd].flags & (FILE_PIPE | FILE_SERIAL | FILE_SOCKET)) == 0
       || (fd_info[fd].flags & FILE_READ) == 0)
     {
-      DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe or socket!\n", fd));
+      DebPrint (("_sys_read_ahead: internal error: fd %d is not a pipe, serial port, or socket!\n", fd));
       abort ();
     }
 
@@ -4080,7 +5275,7 @@ _sys_read_ahead (int fd)
         reporting that input is available; we need this because Windows 95
         connects DOS programs to pipes by making the pipe appear to be
         the normal console stdout - as a result most DOS programs will
-        write to stdout without buffering, ie.  one character at a
+        write to stdout without buffering, ie. one character at a
         time.  Even some W32 programs do this - "dir" in a command
         shell on NT is very slow if we don't do this. */
       if (rc > 0)
@@ -4096,6 +5291,29 @@ _sys_read_ahead (int fd)
              Sleep (0);
        }
     }
+  else if (fd_info[fd].flags & FILE_SERIAL)
+    {
+      HANDLE hnd = fd_info[fd].hnd;
+      OVERLAPPED *ovl = &fd_info[fd].cp->ovl_read;
+      COMMTIMEOUTS ct;
+
+      /* Configure timeouts for blocking read.  */
+      if (!GetCommTimeouts (hnd, &ct))
+       return STATUS_READ_ERROR;
+      ct.ReadIntervalTimeout           = 0;
+      ct.ReadTotalTimeoutMultiplier    = 0;
+      ct.ReadTotalTimeoutConstant      = 0;
+      if (!SetCommTimeouts (hnd, &ct))
+       return STATUS_READ_ERROR;
+
+      if (!ReadFile (hnd, &cp->chr, sizeof (char), (DWORD*) &rc, ovl))
+       {
+         if (GetLastError () != ERROR_IO_PENDING)
+           return STATUS_READ_ERROR;
+         if (!GetOverlappedResult (hnd, ovl, (DWORD*) &rc, TRUE))
+           return STATUS_READ_ERROR;
+       }
+    }
 #ifdef HAVE_SOCKETS
   else if (fd_info[fd].flags & FILE_SOCKET)
     {
@@ -4167,7 +5385,7 @@ sys_read (int fd, char * buffer, unsigned int count)
       return -1;
     }
 
-  if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET))
+  if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET | FILE_SERIAL))
     {
       child_process *cp = fd_info[fd].cp;
 
@@ -4238,6 +5456,52 @@ sys_read (int fd, char * buffer, unsigned int count)
              if (to_read > 0)
                nchars += _read (fd, buffer, to_read);
            }
+         else if (fd_info[fd].flags & FILE_SERIAL)
+           {
+             HANDLE hnd = fd_info[fd].hnd;
+             OVERLAPPED *ovl = &fd_info[fd].cp->ovl_read;
+             DWORD err = 0;
+             int rc = 0;
+             COMMTIMEOUTS ct;
+
+             if (count > 0)
+               {
+                 /* Configure timeouts for non-blocking read.  */
+                 if (!GetCommTimeouts (hnd, &ct))
+                   {
+                     errno = EIO;
+                     return -1;
+                   }
+                 ct.ReadIntervalTimeout         = MAXDWORD;
+                 ct.ReadTotalTimeoutMultiplier  = 0;
+                 ct.ReadTotalTimeoutConstant    = 0;
+                 if (!SetCommTimeouts (hnd, &ct))
+                   {
+                     errno = EIO;
+                     return -1;
+                   }
+
+                 if (!ResetEvent (ovl->hEvent))
+                   {
+                     errno = EIO;
+                     return -1;
+                   }
+                 if (!ReadFile (hnd, buffer, count, (DWORD*) &rc, ovl))
+                   {
+                     if (GetLastError () != ERROR_IO_PENDING)
+                       {
+                         errno = EIO;
+                         return -1;
+                       }
+                     if (!GetOverlappedResult (hnd, ovl, (DWORD*) &rc, TRUE))
+                       {
+                         errno = EIO;
+                         return -1;
+                       }
+                   }
+                 nchars += rc;
+               }
+           }
 #ifdef HAVE_SOCKETS
          else /* FILE_SOCKET */
            {
@@ -4257,8 +5521,8 @@ sys_read (int fd, char * buffer, unsigned int count)
                  int res = pfn_recv (SOCK_HANDLE (fd), buffer, count, 0);
                  if (res == SOCKET_ERROR)
                    {
-                     DebPrint(("sys_read.recv failed with error %d on socket %ld\n",
-                               pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
+                     DebPrint (("sys_read.recv failed with error %d on socket %ld\n",
+                                pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
                      set_errno ();
                      return -1;
                    }
@@ -4299,6 +5563,9 @@ sys_read (int fd, char * buffer, unsigned int count)
   return nchars;
 }
 
+/* From w32xfns.c */
+extern HANDLE interrupt_handle;
+
 /* For now, don't bother with a non-blocking mode */
 int
 sys_write (int fd, const void * buffer, unsigned int count)
@@ -4311,7 +5578,7 @@ sys_write (int fd, const void * buffer, unsigned int count)
       return -1;
     }
 
-  if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET))
+  if (fd < MAXDESC && fd_info[fd].flags & (FILE_PIPE | FILE_SOCKET | FILE_SERIAL))
     {
       if ((fd_info[fd].flags & FILE_WRITE) == 0)
        {
@@ -4352,6 +5619,42 @@ sys_write (int fd, const void * buffer, unsigned int count)
        }
     }
 
+  if (fd < MAXDESC && fd_info[fd].flags & FILE_SERIAL)
+    {
+      HANDLE hnd = (HANDLE) _get_osfhandle (fd);
+      OVERLAPPED *ovl = &fd_info[fd].cp->ovl_write;
+      HANDLE wait_hnd[2] = { interrupt_handle, ovl->hEvent };
+      DWORD active = 0;
+
+      if (!WriteFile (hnd, buffer, count, (DWORD*) &nchars, ovl))
+       {
+         if (GetLastError () != ERROR_IO_PENDING)
+           {
+             errno = EIO;
+             return -1;
+           }
+         if (detect_input_pending ())
+           active = MsgWaitForMultipleObjects (2, wait_hnd, FALSE, INFINITE,
+                                               QS_ALLINPUT);
+         else
+           active = WaitForMultipleObjects (2, wait_hnd, FALSE, INFINITE);
+         if (active == WAIT_OBJECT_0)
+           { /* User pressed C-g, cancel write, then leave.  Don't bother
+                cleaning up as we may only get stuck in buggy drivers.  */
+             PurgeComm (hnd, PURGE_TXABORT | PURGE_TXCLEAR);
+             CancelIo (hnd);
+             errno = EIO;
+             return -1;
+           }
+         if (active == WAIT_OBJECT_0 + 1
+             && !GetOverlappedResult (hnd, ovl, (DWORD*) &nchars, TRUE))
+           {
+             errno = EIO;
+             return -1;
+           }
+       }
+    }
+  else
 #ifdef HAVE_SOCKETS
   if (fd < MAXDESC && fd_info[fd].flags & FILE_SOCKET)
     {
@@ -4375,20 +5678,47 @@ sys_write (int fd, const void * buffer, unsigned int count)
 
       if (nchars == SOCKET_ERROR)
         {
-         DebPrint(("sys_write.send failed with error %d on socket %ld\n",
-                   pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
+         DebPrint (("sys_write.send failed with error %d on socket %ld\n",
+                    pfn_WSAGetLastError (), SOCK_HANDLE (fd)));
          set_errno ();
        }
     }
   else
 #endif
-    nchars = _write (fd, buffer, count);
+    {
+      /* Some networked filesystems don't like too large writes, so
+        break them into smaller chunks.  See the Comments section of
+        the MSDN documentation of WriteFile for details behind the
+        choice of the value of CHUNK below.  See also the thread
+        http://thread.gmane.org/gmane.comp.version-control.git/145294
+        in the git mailing list.  */
+      const unsigned char *p = buffer;
+      const unsigned chunk = 30 * 1024 * 1024;
+
+      nchars = 0;
+      while (count > 0)
+       {
+         unsigned this_chunk = count < chunk ? count : chunk;
+         int n = _write (fd, p, this_chunk);
+
+         nchars += n;
+         if (n < 0)
+           {
+             nchars = n;
+             break;
+           }
+         else if (n < this_chunk)
+           break;
+         count -= n;
+         p += n;
+       }
+    }
 
   return nchars;
 }
 
 static void
-check_windows_init_file ()
+check_windows_init_file (void)
 {
   extern int noninteractive, inhibit_window_system;
 
@@ -4444,7 +5774,7 @@ check_windows_init_file ()
 }
 
 void
-term_ntproc ()
+term_ntproc (void)
 {
 #ifdef HAVE_SOCKETS
   /* shutdown the socket interface if necessary */
@@ -4455,7 +5785,7 @@ term_ntproc ()
 }
 
 void
-init_ntproc ()
+init_ntproc (void)
 {
 #ifdef HAVE_SOCKETS
   /* Initialise the socket interface now if available and requested by
@@ -4563,7 +5893,8 @@ init_ntproc ()
         shutdown_handler ensures that buffers' autosave files are
        up to date when the user logs off, or the system shuts down.
 */
-BOOL WINAPI shutdown_handler(DWORD type)
+BOOL WINAPI
+shutdown_handler (DWORD type)
 {
   /* Ctrl-C and Ctrl-Break are already suppressed, so don't handle them.  */
   if (type == CTRL_CLOSE_EVENT        /* User closes console window.  */
@@ -4584,7 +5915,7 @@ BOOL WINAPI shutdown_handler(DWORD type)
        initialized is non zero (see the function main in emacs.c).
 */
 void
-globals_of_w32 ()
+globals_of_w32 (void)
 {
   HMODULE kernel32 = GetModuleHandle ("kernel32.dll");
 
@@ -4602,16 +5933,223 @@ globals_of_w32 ()
   g_b_init_get_security_descriptor_owner = 0;
   g_b_init_get_security_descriptor_group = 0;
   g_b_init_is_valid_sid = 0;
+  g_b_init_create_toolhelp32_snapshot = 0;
+  g_b_init_process32_first = 0;
+  g_b_init_process32_next = 0;
+  g_b_init_open_thread_token = 0;
+  g_b_init_impersonate_self = 0;
+  g_b_init_revert_to_self = 0;
+  g_b_init_get_process_memory_info = 0;
+  g_b_init_get_process_working_set_size = 0;
+  g_b_init_global_memory_status = 0;
+  g_b_init_global_memory_status_ex = 0;
+  g_b_init_equal_sid = 0;
+  g_b_init_copy_sid = 0;
+  g_b_init_get_length_sid = 0;
+  g_b_init_get_native_system_info = 0;
+  g_b_init_get_system_times = 0;
+  num_of_processors = 0;
   /* The following sets a handler for shutdown notifications for
      console apps. This actually applies to Emacs in both console and
      GUI modes, since we had to fool windows into thinking emacs is a
      console application to get console mode to work.  */
-  SetConsoleCtrlHandler(shutdown_handler, TRUE);
+  SetConsoleCtrlHandler (shutdown_handler, TRUE);
 
   /* "None" is the default group name on standalone workstations.  */
   strcpy (dflt_group_name, "None");
 }
 
+/* For make-serial-process  */
+int
+serial_open (char *port)
+{
+  HANDLE hnd;
+  child_process *cp;
+  int fd = -1;
+
+  hnd = CreateFile (port, GENERIC_READ | GENERIC_WRITE, 0, 0,
+                   OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
+  if (hnd == INVALID_HANDLE_VALUE)
+    error ("Could not open %s", port);
+  fd = (int) _open_osfhandle ((int) hnd, 0);
+  if (fd == -1)
+    error ("Could not open %s", port);
+
+  cp = new_child ();
+  if (!cp)
+    error ("Could not create child process");
+  cp->fd = fd;
+  cp->status = STATUS_READ_ACKNOWLEDGED;
+  fd_info[ fd ].hnd = hnd;
+  fd_info[ fd ].flags |=
+    FILE_READ | FILE_WRITE | FILE_BINARY | FILE_SERIAL;
+  if (fd_info[ fd ].cp != NULL)
+    {
+      error ("fd_info[fd = %d] is already in use", fd);
+    }
+  fd_info[ fd ].cp = cp;
+  cp->ovl_read.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
+  if (cp->ovl_read.hEvent == NULL)
+      error ("Could not create read event");
+  cp->ovl_write.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
+  if (cp->ovl_write.hEvent == NULL)
+      error ("Could not create write event");
+
+  return fd;
+}
+
+/* For serial-process-configure  */
+void
+serial_configure (struct Lisp_Process *p,
+                 Lisp_Object contact)
+{
+  Lisp_Object childp2 = Qnil;
+  Lisp_Object tem = Qnil;
+  HANDLE hnd;
+  DCB dcb;
+  COMMTIMEOUTS ct;
+  char summary[4] = "???"; /* This usually becomes "8N1".  */
+
+  if ((fd_info[ p->outfd ].flags & FILE_SERIAL) == 0)
+    error ("Not a serial process");
+  hnd = fd_info[ p->outfd ].hnd;
+
+  childp2 = Fcopy_sequence (p->childp);
+
+  /* Initialize timeouts for blocking read and blocking write.  */
+  if (!GetCommTimeouts (hnd, &ct))
+    error ("GetCommTimeouts() failed");
+  ct.ReadIntervalTimeout        = 0;
+  ct.ReadTotalTimeoutMultiplier         = 0;
+  ct.ReadTotalTimeoutConstant   = 0;
+  ct.WriteTotalTimeoutMultiplier = 0;
+  ct.WriteTotalTimeoutConstant  = 0;
+  if (!SetCommTimeouts (hnd, &ct))
+    error ("SetCommTimeouts() failed");
+  /* Read port attributes and prepare default configuration.  */
+  memset (&dcb, 0, sizeof (dcb));
+  dcb.DCBlength = sizeof (DCB);
+  if (!GetCommState (hnd, &dcb))
+    error ("GetCommState() failed");
+  dcb.fBinary      = TRUE;
+  dcb.fNull        = FALSE;
+  dcb.fAbortOnError = FALSE;
+  /* dcb.XonLim and dcb.XoffLim are set by GetCommState() */
+  dcb.ErrorChar            = 0;
+  dcb.EofChar      = 0;
+  dcb.EvtChar       = 0;
+
+  /* Configure speed.  */
+  if (!NILP (Fplist_member (contact, QCspeed)))
+    tem = Fplist_get (contact, QCspeed);
+  else
+    tem = Fplist_get (p->childp, QCspeed);
+  CHECK_NUMBER (tem);
+  dcb.BaudRate = XINT (tem);
+  childp2 = Fplist_put (childp2, QCspeed, tem);
+
+  /* Configure bytesize.  */
+  if (!NILP (Fplist_member (contact, QCbytesize)))
+    tem = Fplist_get (contact, QCbytesize);
+  else
+    tem = Fplist_get (p->childp, QCbytesize);
+  if (NILP (tem))
+    tem = make_number (8);
+  CHECK_NUMBER (tem);
+  if (XINT (tem) != 7 && XINT (tem) != 8)
+    error (":bytesize must be nil (8), 7, or 8");
+  dcb.ByteSize = XINT (tem);
+  summary[0] = XINT (tem) + '0';
+  childp2 = Fplist_put (childp2, QCbytesize, tem);
+
+  /* Configure parity.  */
+  if (!NILP (Fplist_member (contact, QCparity)))
+    tem = Fplist_get (contact, QCparity);
+  else
+    tem = Fplist_get (p->childp, QCparity);
+  if (!NILP (tem) && !EQ (tem, Qeven) && !EQ (tem, Qodd))
+    error (":parity must be nil (no parity), `even', or `odd'");
+  dcb.fParity = FALSE;
+  dcb.Parity = NOPARITY;
+  dcb.fErrorChar = FALSE;
+  if (NILP (tem))
+    {
+      summary[1] = 'N';
+    }
+  else if (EQ (tem, Qeven))
+    {
+      summary[1] = 'E';
+      dcb.fParity = TRUE;
+      dcb.Parity = EVENPARITY;
+      dcb.fErrorChar = TRUE;
+    }
+  else if (EQ (tem, Qodd))
+    {
+      summary[1] = 'O';
+      dcb.fParity = TRUE;
+      dcb.Parity = ODDPARITY;
+      dcb.fErrorChar = TRUE;
+    }
+  childp2 = Fplist_put (childp2, QCparity, tem);
+
+  /* Configure stopbits.  */
+  if (!NILP (Fplist_member (contact, QCstopbits)))
+    tem = Fplist_get (contact, QCstopbits);
+  else
+    tem = Fplist_get (p->childp, QCstopbits);
+  if (NILP (tem))
+    tem = make_number (1);
+  CHECK_NUMBER (tem);
+  if (XINT (tem) != 1 && XINT (tem) != 2)
+    error (":stopbits must be nil (1 stopbit), 1, or 2");
+  summary[2] = XINT (tem) + '0';
+  if (XINT (tem) == 1)
+    dcb.StopBits = ONESTOPBIT;
+  else if (XINT (tem) == 2)
+    dcb.StopBits = TWOSTOPBITS;
+  childp2 = Fplist_put (childp2, QCstopbits, tem);
+
+  /* Configure flowcontrol.  */
+  if (!NILP (Fplist_member (contact, QCflowcontrol)))
+    tem = Fplist_get (contact, QCflowcontrol);
+  else
+    tem = Fplist_get (p->childp, QCflowcontrol);
+  if (!NILP (tem) && !EQ (tem, Qhw) && !EQ (tem, Qsw))
+    error (":flowcontrol must be nil (no flowcontrol), `hw', or `sw'");
+  dcb.fOutxCtsFlow     = FALSE;
+  dcb.fOutxDsrFlow     = FALSE;
+  dcb.fDtrControl      = DTR_CONTROL_DISABLE;
+  dcb.fDsrSensitivity  = FALSE;
+  dcb.fTXContinueOnXoff        = FALSE;
+  dcb.fOutX            = FALSE;
+  dcb.fInX             = FALSE;
+  dcb.fRtsControl      = RTS_CONTROL_DISABLE;
+  dcb.XonChar          = 17; /* Control-Q  */
+  dcb.XoffChar         = 19; /* Control-S  */
+  if (NILP (tem))
+    {
+      /* Already configured.  */
+    }
+  else if (EQ (tem, Qhw))
+    {
+      dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
+      dcb.fOutxCtsFlow = TRUE;
+    }
+  else if (EQ (tem, Qsw))
+    {
+      dcb.fOutX = TRUE;
+      dcb.fInX = TRUE;
+    }
+  childp2 = Fplist_put (childp2, QCflowcontrol, tem);
+
+  /* Activate configuration.  */
+  if (!SetCommState (hnd, &dcb))
+    error ("SetCommState() failed");
+
+  childp2 = Fplist_put (childp2, QCsummary, build_string (summary));
+  p->childp = childp2;
+}
+
 /* end of w32.c */
 
 /* arch-tag: 90442dd3-37be-482b-b272-ac752e3049f1