(VALBITS, GCTYPEBITS): Deleted; default is better.
[bpt/emacs.git] / src / process.c
index 301a44d..526f46f 100644 (file)
@@ -38,6 +38,14 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include <sys/types.h>         /* some typedefs are used in sys/file.h */
 #include <sys/file.h>
 #include <sys/stat.h>
 #include <sys/types.h>         /* some typedefs are used in sys/file.h */
 #include <sys/file.h>
 #include <sys/stat.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef WINDOWSNT
+#include <stdlib.h>
+#include <fcntl.h>
+#endif /* not WINDOWSNT */
 
 #ifdef HAVE_SOCKETS    /* TCP connection support, if kernel can do it */
 #include <sys/socket.h>
 
 #ifdef HAVE_SOCKETS    /* TCP connection support, if kernel can do it */
 #include <sys/socket.h>
@@ -51,8 +59,8 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include <client.h>
 #endif
 
 #include <client.h>
 #endif
 
-/* DGUX inet_addr returns a 'struct in_addr'. */
-#ifdef DGUX
+/* On some systems, e.g. DGUX, inet_addr returns a 'struct in_addr'. */
+#ifdef HAVE_BROKEN_INET_ADDR
 #define IN_ADDR struct in_addr
 #define NUMERIC_ADDR_ERROR (numeric_addr.s_addr == -1)
 #else
 #define IN_ADDR struct in_addr
 #define NUMERIC_ADDR_ERROR (numeric_addr.s_addr == -1)
 #else
@@ -93,6 +101,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 
 Lisp_Object Qprocessp;
 Lisp_Object Qrun, Qstop, Qsignal, Qopen, Qclosed;
 
 Lisp_Object Qprocessp;
 Lisp_Object Qrun, Qstop, Qsignal, Qopen, Qclosed;
+Lisp_Object Qlast_nonmenu_event;
 /* Qexit is declared and initialized in eval.c.  */
 
 /* a process object is a network connection when its childp field is neither
 /* Qexit is declared and initialized in eval.c.  */
 
 /* a process object is a network connection when its childp field is neither
@@ -102,7 +111,7 @@ Lisp_Object Qrun, Qstop, Qsignal, Qopen, Qclosed;
 #ifdef HAVE_SOCKETS
 static Lisp_Object stream_process;
 
 #ifdef HAVE_SOCKETS
 static Lisp_Object stream_process;
 
-#define NETCONN_P(p) (XGCTYPE (XPROCESS (p)->childp) == Lisp_String)
+#define NETCONN_P(p) (GC_STRINGP (XPROCESS (p)->childp))
 #else
 #define NETCONN_P(p) 0
 #endif /* HAVE_SOCKETS */
 #else
 #define NETCONN_P(p) 0
 #endif /* HAVE_SOCKETS */
@@ -131,8 +140,14 @@ extern char *strerror ();
 extern char *sys_errlist[];
 #endif
 
 extern char *sys_errlist[];
 #endif
 
+#ifndef HAVE_H_ERRNO
+extern int h_errno;
+#endif
+
+#ifndef SYS_SIGLIST_DECLARED
 #ifndef VMS
 #ifndef BSD4_1
 #ifndef VMS
 #ifndef BSD4_1
+#ifndef WINDOWSNT
 #ifndef LINUX
 extern char *sys_siglist[];
 #endif /* not LINUX */
 #ifndef LINUX
 extern char *sys_siglist[];
 #endif /* not LINUX */
@@ -166,8 +181,10 @@ char *sys_siglist[] =
     "exceeded CPU time limit",
     "exceeded file size limit"
     };
     "exceeded CPU time limit",
     "exceeded file size limit"
     };
+#endif /* not WINDOWSNT */
 #endif
 #endif /* VMS */
 #endif
 #endif /* VMS */
+#endif /* ! SYS_SIGLIST_DECLARED */
 
 /* t means use pty, nil means use a pipe,
    maybe other values to come.  */
 
 /* t means use pty, nil means use a pipe,
    maybe other values to come.  */
@@ -206,21 +223,34 @@ static int update_tick;
 #define FD_ZERO(p) (*(p) = 0)
 #endif /* no FD_SET */
 
 #define FD_ZERO(p) (*(p) = 0)
 #endif /* no FD_SET */
 
-/* Mask of bits indicating the descriptors that we wait for input on */
+/* If we support X Windows, turn on the code to poll periodically
+   to detect C-g.  It isn't actually used when doing interrupt input.  */
+#ifdef HAVE_X_WINDOWS
+#define POLL_FOR_INPUT
+#endif
+
+/* Mask of bits indicating the descriptors that we wait for input on.  */
 
 static SELECT_TYPE input_wait_mask;
 
 
 static SELECT_TYPE input_wait_mask;
 
-/* Descriptor to use for keyboard input.  */
-static int keyboard_descriptor;
+/* Mask that excludes keyboard input descriptor (s).  */
+
+static SELECT_TYPE non_keyboard_wait_mask;
+
+/* The largest descriptor currently in use for a process object.  */
+static int max_process_desc;
+
+/* The largest descriptor currently in use for keyboard input.  */
+static int max_keyboard_desc;
 
 /* Nonzero means delete a process right away if it exits.  */
 static int delete_exited_processes;
 
 /* Indexed by descriptor, gives the process (if any) for that descriptor */
 
 /* Nonzero means delete a process right away if it exits.  */
 static int delete_exited_processes;
 
 /* Indexed by descriptor, gives the process (if any) for that descriptor */
-static Lisp_Object chan_process[MAXDESC];
+Lisp_Object chan_process[MAXDESC];
 
 /* Alist of elements (NAME . PROCESS) */
 
 /* Alist of elements (NAME . PROCESS) */
-static Lisp_Object Vprocess_alist;
+Lisp_Object Vprocess_alist;
 
 /* Buffered-ahead input char from process, indexed by channel.
    -1 means empty (no char is buffered).
 
 /* Buffered-ahead input char from process, indexed by channel.
    -1 means empty (no char is buffered).
@@ -228,9 +258,20 @@ static Lisp_Object Vprocess_alist;
    output from the process is to read at least one char.
    Always -1 on systems that support FIONREAD.  */
 
    output from the process is to read at least one char.
    Always -1 on systems that support FIONREAD.  */
 
-static int proc_buffered_char[MAXDESC];
+/* Don't make static; need to access externally.  */
+int proc_buffered_char[MAXDESC];
 
 static Lisp_Object get_process ();
 
 static Lisp_Object get_process ();
+
+/* Maximum number of bytes to send to a pty without an eof.  */
+static int pty_max_bytes;
+
+/* Open an available pty, returning a file descriptor.
+   Return -1 on failure.
+   The file name of the terminal corresponding to the pty
+   is left in the variable pty_name.  */
+
+static char pty_name[24];
 \f
 /* Compute the Lisp form of the process status, p->status, from
    the numeric status that was returned by `wait'.  */
 \f
 /* Compute the Lisp form of the process status, p->status, from
    the numeric status that was returned by `wait'.  */
@@ -278,7 +319,7 @@ decode_status (l, symbol, code, coredump)
 {
   Lisp_Object tem;
 
 {
   Lisp_Object tem;
 
-  if (XTYPE (l) == Lisp_Symbol)
+  if (SYMBOLP (l))
     {
       *symbol = l;
       *code = 0;
     {
       *symbol = l;
       *code = 0;
@@ -308,11 +349,19 @@ status_message (status)
 
   if (EQ (symbol, Qsignal) || EQ (symbol, Qstop))
     {
 
   if (EQ (symbol, Qsignal) || EQ (symbol, Qstop))
     {
+      char *signame = 0;
+      if (code < NSIG)
+       {
 #ifndef VMS
 #ifndef VMS
-      string = build_string (code < NSIG ? sys_siglist[code] : "unknown");
+         /* Cast to suppress warning if the table has const char *.  */
+         signame = (char *) sys_siglist[code];
 #else
 #else
-      string = build_string (code < NSIG ? sys_errlist[code] : "unknown");
+         signame = sys_errlist[code];
 #endif
 #endif
+       }
+      if (signame == 0)
+       signame = "unknown";
+      string = build_string (signame);
       string2 = build_string (coredump ? " (core dumped)\n" : "\n");
       XSTRING (string)->data[0] = DOWNCASE (XSTRING (string)->data[0]);
       return concat2 (string, string2);
       string2 = build_string (coredump ? " (core dumped)\n" : "\n");
       XSTRING (string)->data[0] = DOWNCASE (XSTRING (string)->data[0]);
       return concat2 (string, string2);
@@ -332,13 +381,6 @@ status_message (status)
 \f
 #ifdef HAVE_PTYS
 
 \f
 #ifdef HAVE_PTYS
 
-/* Open an available pty, returning a file descriptor.
-   Return -1 on failure.
-   The file name of the terminal corresponding to the pty
-   is left in the variable pty_name.  */
-
-char pty_name[24];
-
 int
 allocate_pty ()
 {
 int
 allocate_pty ()
 {
@@ -425,27 +467,23 @@ Lisp_Object
 make_process (name)
      Lisp_Object name;
 {
 make_process (name)
      Lisp_Object name;
 {
+  struct Lisp_Vector *vec;
   register Lisp_Object val, tem, name1;
   register struct Lisp_Process *p;
   char suffix[10];
   register int i;
 
   register Lisp_Object val, tem, name1;
   register struct Lisp_Process *p;
   char suffix[10];
   register int i;
 
-  /* size of process structure includes the vector header,
-     so deduct for that.  But struct Lisp_Vector includes the first
-     element, thus deducts too much, so add it back.  */
-  val = Fmake_vector (make_number ((sizeof (struct Lisp_Process)
-                                   - sizeof (struct Lisp_Vector)
-                                   + sizeof (Lisp_Object))
-                                  / sizeof (Lisp_Object)),
-                     Qnil);
-  XSETTYPE (val, Lisp_Process);
-
-  p = XPROCESS (val);
-  XSET (p->infd, Lisp_Int, -1);
-  XSET (p->outfd, Lisp_Int, -1);
-  XFASTINT (p->pid) = 0;
-  XFASTINT (p->tick) = 0;
-  XFASTINT (p->update_tick) = 0;
+  vec = allocate_vectorlike ((EMACS_INT) VECSIZE (struct Lisp_Process));
+  for (i = 0; i < VECSIZE (struct Lisp_Process); i++)
+    vec->contents[i] = Qnil;
+  vec->size = VECSIZE (struct Lisp_Process);
+  p = (struct Lisp_Process *)vec;
+
+  XSETINT (p->infd, -1);
+  XSETINT (p->outfd, -1);
+  XSETFASTINT (p->pid, 0);
+  XSETFASTINT (p->tick, 0);
+  XSETFASTINT (p->update_tick, 0);
   p->raw_status_low = Qnil;
   p->raw_status_high = Qnil;
   p->status = Qrun;
   p->raw_status_low = Qnil;
   p->raw_status_high = Qnil;
   p->status = Qrun;
@@ -463,6 +501,7 @@ make_process (name)
     }
   name = name1;
   p->name = name;
     }
   name = name1;
   p->name = name;
+  XSETPROCESS (val, p);
   Vprocess_alist = Fcons (Fcons (name, val), Vprocess_alist);
   return val;
 }
   Vprocess_alist = Fcons (Fcons (name, val), Vprocess_alist);
   return val;
 }
@@ -484,7 +523,7 @@ DEFUN ("processp", Fprocessp, Sprocessp, 1, 1, 0,
   (obj)
      Lisp_Object obj;
 {
   (obj)
      Lisp_Object obj;
 {
-  return XTYPE (obj) == Lisp_Process ? Qt : Qnil;
+  return PROCESSP (obj) ? Qt : Qnil;
 }
 
 DEFUN ("get-process", Fget_process, Sget_process, 1, 1, 0,
 }
 
 DEFUN ("get-process", Fget_process, Sget_process, 1, 1, 0,
@@ -492,7 +531,7 @@ DEFUN ("get-process", Fget_process, Sget_process, 1, 1, 0,
   (name)
      register Lisp_Object name;
 {
   (name)
      register Lisp_Object name;
 {
-  if (XTYPE (name) == Lisp_Process)
+  if (PROCESSP (name))
     return name;
   CHECK_STRING (name, 0);
   return Fcdr (Fassoc (name, Vprocess_alist));
     return name;
   CHECK_STRING (name, 0);
   return Fcdr (Fassoc (name, Vprocess_alist));
@@ -513,7 +552,7 @@ BUFFER may be a buffer or the name of one.")
   for (tail = Vprocess_alist; !NILP (tail); tail = Fcdr (tail))
     {
       proc = Fcdr (Fcar (tail));
   for (tail = Vprocess_alist; !NILP (tail); tail = Fcdr (tail))
     {
       proc = Fcdr (Fcar (tail));
-      if (XTYPE (proc) == Lisp_Process && EQ (XPROCESS (proc)->buffer, buf))
+      if (PROCESSP (proc) && EQ (XPROCESS (proc)->buffer, buf))
        return proc;
     }
   return Qnil;
        return proc;
     }
   return Qnil;
@@ -528,24 +567,34 @@ static Lisp_Object
 get_process (name)
      register Lisp_Object name;
 {
 get_process (name)
      register Lisp_Object name;
 {
-  register Lisp_Object proc;
-  if (NILP (name))
-    proc = Fget_buffer_process (Fcurrent_buffer ());
+  register Lisp_Object proc, obj;
+  if (STRINGP (name))
+    {
+      obj = Fget_process (name);
+      if (NILP (obj))
+       obj = Fget_buffer (name);
+      if (NILP (obj))
+       error ("Process %s does not exist", XSTRING (name)->data);
+    }
+  else if (NILP (name))
+    obj = Fcurrent_buffer ();
   else
   else
+    obj = name;
+
+  /* Now obj should be either a buffer object or a process object.
+   */
+  if (BUFFERP (obj))
     {
     {
-      proc = Fget_process (name);
+      proc = Fget_buffer_process (obj);
       if (NILP (proc))
       if (NILP (proc))
-       proc = Fget_buffer_process (Fget_buffer (name));
+       error ("Buffer %s has no process", XSTRING (XBUFFER (obj)->name)->data);
     }
     }
-
-  if (!NILP (proc))
-    return proc;
-
-  if (NILP (name))
-    error ("Current buffer has no process");
   else
   else
-    error ("Process %s does not exist", XSTRING (name)->data);
-  /* NOTREACHED */
+    {
+      CHECK_PROCESS (obj, 0);
+      proc = obj;
+    }
+  return proc;
 }
 
 DEFUN ("delete-process", Fdelete_process, Sdelete_process, 1, 1, 0,
 }
 
 DEFUN ("delete-process", Fdelete_process, Sdelete_process, 1, 1, 0,
@@ -592,14 +641,20 @@ nil, indicating the current buffer's process.")
 {
   register struct Lisp_Process *p;
   register Lisp_Object status;
 {
   register struct Lisp_Process *p;
   register Lisp_Object status;
-  proc = get_process (proc);
+
+  if (STRINGP (proc))
+    proc = Fget_process (proc);
+  else
+    proc = get_process (proc);
+
   if (NILP (proc))
     return proc;
   if (NILP (proc))
     return proc;
+
   p = XPROCESS (proc);
   if (!NILP (p->raw_status_low))
     update_status (p);
   status = p->status;
   p = XPROCESS (proc);
   if (!NILP (p->raw_status_low))
     update_status (p);
   status = p->status;
-  if (XTYPE (status) == Lisp_Cons)
+  if (CONSP (status))
     status = XCONS (status)->car;
   if (NETCONN_P (proc))
     {
     status = XCONS (status)->car;
   if (NETCONN_P (proc))
     {
@@ -621,7 +676,7 @@ If PROCESS has not yet exited or died, return 0.")
   CHECK_PROCESS (proc, 0);
   if (!NILP (XPROCESS (proc)->raw_status_low))
     update_status (XPROCESS (proc));
   CHECK_PROCESS (proc, 0);
   if (!NILP (XPROCESS (proc)->raw_status_low))
     update_status (XPROCESS (proc));
-  if (XTYPE (XPROCESS (proc)->status) == Lisp_Cons)
+  if (CONSP (XPROCESS (proc)->status))
     return XCONS (XCONS (XPROCESS (proc)->status)->cdr)->car;
   return make_number (0);
 }
     return XCONS (XCONS (XPROCESS (proc)->status)->cdr)->car;
   return make_number (0);
 }
@@ -660,6 +715,17 @@ For a non-child channel, this is nil.")
   return XPROCESS (proc)->command;
 }
 
   return XPROCESS (proc)->command;
 }
 
+DEFUN ("process-tty-name", Fprocess_tty_name, Sprocess_tty_name, 1, 1, 0,
+  "Return the name of the terminal PROCESS uses, or nil if none.\n\
+This is the terminal that the process itself reads and writes on,\n\
+not the name of the pty that Emacs uses to talk with that terminal.")
+  (proc)
+     register Lisp_Object proc;
+{
+  CHECK_PROCESS (proc, 0);
+  return XPROCESS (proc)->tty_name;
+}
+
 DEFUN ("set-process-buffer", Fset_process_buffer, Sset_process_buffer,
   2, 2, 0,
   "Set buffer associated with PROCESS to BUFFER (a buffer, or nil).")
 DEFUN ("set-process-buffer", Fset_process_buffer, Sset_process_buffer,
   2, 2, 0,
   "Set buffer associated with PROCESS to BUFFER (a buffer, or nil).")
@@ -708,9 +774,15 @@ If the process has a filter, its buffer is not used for output.")
 {
   CHECK_PROCESS (proc, 0);
   if (EQ (filter, Qt))
 {
   CHECK_PROCESS (proc, 0);
   if (EQ (filter, Qt))
-    FD_CLR (XINT (XPROCESS (proc)->infd), &input_wait_mask);
+    {
+      FD_CLR (XINT (XPROCESS (proc)->infd), &input_wait_mask);
+      FD_CLR (XINT (XPROCESS (proc)->infd), &non_keyboard_wait_mask);
+    }
   else if (EQ (XPROCESS (proc)->filter, Qt))
   else if (EQ (XPROCESS (proc)->filter, Qt))
-    FD_SET (XINT (XPROCESS (proc)->infd), &input_wait_mask);
+    {
+      FD_SET (XINT (XPROCESS (proc)->infd), &input_wait_mask);
+      FD_SET (XINT (XPROCESS (proc)->infd), &non_keyboard_wait_mask);
+    }
   XPROCESS (proc)->filter = filter;
   return filter;
 }
   XPROCESS (proc)->filter = filter;
   return filter;
 }
@@ -750,10 +822,26 @@ See `set-process-sentinel' for more info on sentinels.")
   return XPROCESS (proc)->sentinel;
 }
 
   return XPROCESS (proc)->sentinel;
 }
 
+DEFUN ("set-process-window-size", Fset_process_window_size,
+  Sset_process_window_size, 3, 3, 0,
+  "Tell PROCESS that it has logical window size HEIGHT and WIDTH.")
+  (proc, height, width)
+     register Lisp_Object proc, height, width;
+{
+  CHECK_PROCESS (proc, 0);
+  CHECK_NATNUM (height, 0);
+  CHECK_NATNUM (width, 0);
+  if (set_window_size (XINT (XPROCESS (proc)->infd),
+                      XINT (height), XINT(width)) <= 0)
+    return Qnil;
+  else
+    return Qt;
+}
+
 DEFUN ("process-kill-without-query", Fprocess_kill_without_query,
   Sprocess_kill_without_query, 1, 2, 0,
   "Say no query needed if PROCESS is running when Emacs is exited.\n\
 DEFUN ("process-kill-without-query", Fprocess_kill_without_query,
   Sprocess_kill_without_query, 1, 2, 0,
   "Say no query needed if PROCESS is running when Emacs is exited.\n\
-Optional second argument if non-nill says to require a query.\n\
+Optional second argument if non-nil says to require a query.\n\
 Value is t if a query was formerly required.")
   (proc, value)
      register Lisp_Object proc, value;
 Value is t if a query was formerly required.")
   (proc, value)
      register Lisp_Object proc, value;
@@ -790,7 +878,7 @@ list_processes_1 ()
   register int state;
   char tembuf[80];
 
   register int state;
   char tembuf[80];
 
-  XFASTINT (minspace) = 1;
+  XSETFASTINT (minspace, 1);
 
   set_buffer_internal (XBUFFER (Vstandard_output));
   Fbuffer_disable_undo (Vstandard_output);
 
   set_buffer_internal (XBUFFER (Vstandard_output));
   Fbuffer_disable_undo (Vstandard_output);
@@ -798,8 +886,8 @@ list_processes_1 ()
   current_buffer->truncate_lines = Qt;
 
   write_string ("\
   current_buffer->truncate_lines = Qt;
 
   write_string ("\
-Proc         Status   Buffer         Command\n\
-----         ------   ------         -------\n", -1);
+Proc         Status   Buffer         Tty         Command\n\
+----         ------   ------         ---         -------\n", -1);
 
   for (tail = Vprocess_alist; !NILP (tail); tail = Fcdr (tail))
     {
 
   for (tail = Vprocess_alist; !NILP (tail); tail = Fcdr (tail))
     {
@@ -816,7 +904,7 @@ Proc         Status   Buffer         Command\n\
       if (!NILP (p->raw_status_low))
        update_status (p);
       symbol = p->status;
       if (!NILP (p->raw_status_low))
        update_status (p);
       symbol = p->status;
-      if (XTYPE (p->status) == Lisp_Cons)
+      if (CONSP (p->status))
        symbol = XCONS (p->status)->car;
 
       
        symbol = XCONS (p->status)->car;
 
       
@@ -867,6 +955,13 @@ Proc         Status   Buffer         Command\n\
 
       Findent_to (make_number (37), minspace);
 
 
       Findent_to (make_number (37), minspace);
 
+      if (STRINGP (p->tty_name))
+       Finsert (1, &p->tty_name);
+      else
+       insert_string ("(none)");
+
+      Findent_to (make_number (49), minspace);
+
       if (NETCONN_P (proc))
         {
          sprintf (tembuf, "(network stream connection to %s)\n",
       if (NETCONN_P (proc))
         {
          sprintf (tembuf, "(network stream connection to %s)\n",
@@ -999,24 +1094,31 @@ Remaining arguments are strings to give program as arguments.")
 #else /* not VMS */
   new_argv = (unsigned char **) alloca ((nargs - 1) * sizeof (char *));
 
 #else /* not VMS */
   new_argv = (unsigned char **) alloca ((nargs - 1) * sizeof (char *));
 
-  for (i = 3; i < nargs; i++)
-    {
-      tem = args[i];
-      CHECK_STRING (tem, i);
-      new_argv[i - 2] = XSTRING (tem)->data;
-    }
-  new_argv[i - 2] = 0;
-  new_argv[0] = XSTRING (program)->data;
-
   /* If program file name is not absolute, search our path for it */
   /* If program file name is not absolute, search our path for it */
-  if (new_argv[0][0] != '/')
+  if (!IS_DIRECTORY_SEP (XSTRING (program)->data[0])
+      && !(XSTRING (program)->size > 1
+          && IS_DEVICE_SEP (XSTRING (program)->data[1])))
     {
     {
+      struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
+
       tem = Qnil;
       tem = Qnil;
+      GCPRO4 (name, program, buffer, current_dir);
       openp (Vexec_path, program, EXEC_SUFFIXES, &tem, 1);
       openp (Vexec_path, program, EXEC_SUFFIXES, &tem, 1);
+      UNGCPRO;
       if (NILP (tem))
        report_file_error ("Searching for program", Fcons (program, Qnil));
       new_argv[0] = XSTRING (tem)->data;
     }
       if (NILP (tem))
        report_file_error ("Searching for program", Fcons (program, Qnil));
       new_argv[0] = XSTRING (tem)->data;
     }
+  else
+    new_argv[0] = XSTRING (program)->data;
+
+  for (i = 3; i < nargs; i++)
+    {
+      tem = args[i];
+      CHECK_STRING (tem, i);
+      new_argv[i - 2] = XSTRING (tem)->data;
+    }
+  new_argv[i - 2] = 0;
 #endif /* not VMS */
 
   proc = make_process (name);
 #endif /* not VMS */
 
   proc = make_process (name);
@@ -1046,7 +1148,7 @@ static Lisp_Object
 start_process_unwind (proc)
      Lisp_Object proc;
 {
 start_process_unwind (proc)
      Lisp_Object proc;
 {
-  if (XTYPE (proc) != Lisp_Process)
+  if (!PROCESSP (proc))
     abort ();
 
   /* Was PROC started successfully?  */
     abort ();
 
   /* Was PROC started successfully?  */
@@ -1104,7 +1206,7 @@ create_process (process, new_argv, current_dir)
   inchannel = outchannel = -1;
 
 #ifdef HAVE_PTYS
   inchannel = outchannel = -1;
 
 #ifdef HAVE_PTYS
-  if (EQ (Vprocess_connection_type, Qt))
+  if (!NILP (Vprocess_connection_type))
     outchannel = inchannel = allocate_pty ();
 
   if (inchannel >= 0)
     outchannel = inchannel = allocate_pty ();
 
   if (inchannel >= 0)
@@ -1137,12 +1239,22 @@ create_process (process, new_argv, current_dir)
     }
 #else /* not SKTPAIR */
     {
     }
 #else /* not SKTPAIR */
     {
+#ifdef WINDOWSNT
+      pipe_with_inherited_out (sv);
+      inchannel = sv[0];
+      forkout = sv[1];
+
+      pipe_with_inherited_in (sv);
+      forkin = sv[0];
+      outchannel = sv[1];
+#else /* not WINDOWSNT */
       pipe (sv);
       inchannel = sv[0];
       forkout = sv[1];
       pipe (sv);
       outchannel = sv[1];
       forkin = sv[0];
       pipe (sv);
       inchannel = sv[0];
       forkout = sv[1];
       pipe (sv);
       outchannel = sv[1];
       forkin = sv[0];
+#endif /* not WINDOWSNT */
     }
 #endif /* not SKTPAIR */
 
     }
 #endif /* not SKTPAIR */
 
@@ -1172,13 +1284,13 @@ create_process (process, new_argv, current_dir)
   /* Record this as an active process, with its channels.
      As a result, child_setup will close Emacs's side of the pipes.  */
   chan_process[inchannel] = process;
   /* Record this as an active process, with its channels.
      As a result, child_setup will close Emacs's side of the pipes.  */
   chan_process[inchannel] = process;
-  XSET (XPROCESS (process)->infd, Lisp_Int, inchannel);
-  XSET (XPROCESS (process)->outfd, Lisp_Int, outchannel);
+  XSETINT (XPROCESS (process)->infd, inchannel);
+  XSETINT (XPROCESS (process)->outfd, outchannel);
   /* Record the tty descriptor used in the subprocess.  */
   if (forkin < 0)
     XPROCESS (process)->subtty = Qnil;
   else
   /* Record the tty descriptor used in the subprocess.  */
   if (forkin < 0)
     XPROCESS (process)->subtty = Qnil;
   else
-    XFASTINT (XPROCESS (process)->subtty) = forkin;
+    XSETFASTINT (XPROCESS (process)->subtty, forkin);
   XPROCESS (process)->pty_flag = (pty_flag ? Qt : Qnil);
   XPROCESS (process)->status = Qrun;
 
   XPROCESS (process)->pty_flag = (pty_flag ? Qt : Qnil);
   XPROCESS (process)->status = Qrun;
 
@@ -1199,6 +1311,11 @@ create_process (process, new_argv, current_dir)
 #endif /* not BSD4_1 */
 #endif /* SIGCHLD */
 
 #endif /* not BSD4_1 */
 #endif /* SIGCHLD */
 
+  FD_SET (inchannel, &input_wait_mask);
+  FD_SET (inchannel, &non_keyboard_wait_mask);
+  if (inchannel > max_process_desc)
+    max_process_desc = inchannel;
+
   /* Until we store the proper pid, enable sigchld_handler
      to recognize an unknown pid as standing for this process.
      It is very important not to let this `marker' value stay
   /* Until we store the proper pid, enable sigchld_handler
      to recognize an unknown pid as standing for this process.
      It is very important not to let this `marker' value stay
@@ -1212,8 +1329,10 @@ create_process (process, new_argv, current_dir)
        Protect it from permanent change.  */
     char **save_environ = environ;
 
        Protect it from permanent change.  */
     char **save_environ = environ;
 
+#ifndef WINDOWSNT
     pid = vfork ();
     if (pid == 0)
     pid = vfork ();
     if (pid == 0)
+#endif /* not WINDOWSNT */
       {
        int xforkin = forkin;
        int xforkout = forkout;
       {
        int xforkin = forkin;
        int xforkout = forkout;
@@ -1228,14 +1347,18 @@ create_process (process, new_argv, current_dir)
 #ifdef HAVE_PTYS
        /* First, disconnect its current controlling terminal.  */
 #ifdef HAVE_SETSID
 #ifdef HAVE_PTYS
        /* First, disconnect its current controlling terminal.  */
 #ifdef HAVE_SETSID
+       /* We tried doing setsid only if pty_flag, but it caused
+          process_set_signal to fail on SGI when using a pipe.  */
        setsid ();
        setsid ();
-#ifdef TIOCSCTTY
        /* Make the pty's terminal the controlling terminal.  */
        if (pty_flag)
        /* Make the pty's terminal the controlling terminal.  */
        if (pty_flag)
-         /* We ignore the return value
-            because faith@cs.unc.edu says that is necessary on Linux.  */
-         ioctl (xforkin, TIOCSCTTY, 0);
+         {
+#ifdef TIOCSCTTY
+           /* We ignore the return value
+              because faith@cs.unc.edu says that is necessary on Linux.  */
+           ioctl (xforkin, TIOCSCTTY, 0);
 #endif
 #endif
+         }
 #else /* not HAVE_SETSID */
 #ifdef USG
        /* It's very important to call setpgrp here and no time
 #else /* not HAVE_SETSID */
 #ifdef USG
        /* It's very important to call setpgrp here and no time
@@ -1244,15 +1367,25 @@ create_process (process, new_argv, current_dir)
        setpgrp ();
 #endif /* USG */
 #endif /* not HAVE_SETSID */
        setpgrp ();
 #endif /* USG */
 #endif /* not HAVE_SETSID */
-#ifdef NTTYDISC
-       if (pty_flag)
+#if defined (HAVE_TERMIOS) && defined (LDISC1)
+       if (pty_flag && xforkin >= 0)
+         {
+           struct termios t;
+           tcgetattr (xforkin, &t);
+           t.c_lflag = LDISC1;
+           if (tcsetattr (xforkin, TCSANOW, &t) < 0)
+             write (1, "create_process/tcsetattr LDISC1 failed\n", 39);
+         }
+#else
+#if defined (NTTYDISC) && defined (TIOCSETD)
+       if (pty_flag && xforkin >= 0)
          {
            /* Use new line discipline.  */
            int ldisc = NTTYDISC;
          {
            /* Use new line discipline.  */
            int ldisc = NTTYDISC;
-           if (ioctl (xforkin, TIOCSETD, &ldisc) < 0)
-             write (1, "create_process/TIOCSETD failed\n", 31);
+           ioctl (xforkin, TIOCSETD, &ldisc);
          }
 #endif
          }
 #endif
+#endif
 #ifdef TIOCNOTTY 
        /* In 4.3BSD, the TIOCSPGRP bug has been fixed, and now you
           can do TIOCSPGRP only to the process's controlling tty.  */
 #ifdef TIOCNOTTY 
        /* In 4.3BSD, the TIOCSPGRP bug has been fixed, and now you
           can do TIOCSPGRP only to the process's controlling tty.  */
@@ -1267,7 +1400,11 @@ create_process (process, new_argv, current_dir)
            /* In order to get a controlling terminal on some versions
               of BSD, it is necessary to put the process in pgrp 0
               before it opens the terminal.  */
            /* In order to get a controlling terminal on some versions
               of BSD, it is necessary to put the process in pgrp 0
               before it opens the terminal.  */
+#ifdef OSF1
+           setpgid (0, 0);
+#else
            setpgrp (0, 0);
            setpgrp (0, 0);
+#endif
 #endif
          }
 #endif /* TIOCNOTTY */
 #endif
          }
 #endif /* TIOCNOTTY */
@@ -1298,7 +1435,10 @@ create_process (process, new_argv, current_dir)
          }
 #endif /* not UNIPLUS and not RTU */
 #ifdef SETUP_SLAVE_PTY
          }
 #endif /* not UNIPLUS and not RTU */
 #ifdef SETUP_SLAVE_PTY
-       SETUP_SLAVE_PTY;
+       if (pty_flag)
+         {
+           SETUP_SLAVE_PTY;
+         }
 #endif /* SETUP_SLAVE_PTY */
 #ifdef AIX
        /* On AIX, we've disabled SIGHUP above once we start a child on a pty.
 #endif /* SETUP_SLAVE_PTY */
 #ifdef AIX
        /* On AIX, we've disabled SIGHUP above once we start a child on a pty.
@@ -1322,19 +1462,36 @@ create_process (process, new_argv, current_dir)
 #endif /* not BSD4_1 */
 #endif /* SIGCHLD */
 
 #endif /* not BSD4_1 */
 #endif /* SIGCHLD */
 
-       child_setup_tty (xforkout);
+       signal (SIGINT, SIG_DFL);
+       signal (SIGQUIT, SIG_DFL);
+
+       if (pty_flag)
+         child_setup_tty (xforkout);
+#ifdef WINDOWSNT
+       pid = child_setup (xforkin, xforkout, xforkout,
+                          new_argv, 1, current_dir);
+#else  /* not WINDOWSNT */     
        child_setup (xforkin, xforkout, xforkout,
                     new_argv, 1, current_dir);
        child_setup (xforkin, xforkout, xforkout,
                     new_argv, 1, current_dir);
+#endif /* not WINDOWSNT */
       }
     environ = save_environ;
   }
 
   if (pid < 0)
       }
     environ = save_environ;
   }
 
   if (pid < 0)
-    report_file_error ("Doing vfork", Qnil);
+    {
+      if (forkin >= 0)
+       close (forkin);
+      if (forkin != forkout && forkout >= 0)
+       close (forkout);
+      report_file_error ("Doing vfork", Qnil);
+    }
   
   
-  XFASTINT (XPROCESS (process)->pid) = pid;
+  XSETFASTINT (XPROCESS (process)->pid, pid);
 
 
-  FD_SET (inchannel, &input_wait_mask);
+#ifdef WINDOWSNT
+  register_child (pid, inchannel);
+#endif /* WINDOWSNT */
 
   /* If the subfork execv fails, and it exits,
      this close hangs.  I don't know why.
 
   /* If the subfork execv fails, and it exits,
      this close hangs.  I don't know why.
@@ -1350,6 +1507,8 @@ create_process (process, new_argv, current_dir)
   if (forkin != forkout && forkout >= 0)
     close (forkout);
 
   if (forkin != forkout && forkout >= 0)
     close (forkout);
 
+  XPROCESS (process)->tty_name = build_string (pty_name);
+
 #ifdef SIGCHLD
 #ifdef BSD4_1
   sigrelse (SIGCHLD);
 #ifdef SIGCHLD
 #ifdef BSD4_1
   sigrelse (SIGCHLD);
@@ -1408,11 +1567,13 @@ Fourth arg SERVICE is name of the service desired, or an integer\n\
   int port;
   struct hostent host_info_fixed;
   struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
   int port;
   struct hostent host_info_fixed;
   struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
+  int retry = 0;
+  int count = specpdl_ptr - specpdl;
 
   GCPRO4 (name, buffer, host, service);
   CHECK_STRING (name, 0);
   CHECK_STRING (host, 0);
 
   GCPRO4 (name, buffer, host, service);
   CHECK_STRING (name, 0);
   CHECK_STRING (host, 0);
-  if (XTYPE(service) == Lisp_Int)
+  if (INTEGERP (service))
     port = htons ((unsigned short) XINT (service));
   else
     {
     port = htons ((unsigned short) XINT (service));
   else
     {
@@ -1424,7 +1585,18 @@ Fourth arg SERVICE is name of the service desired, or an integer\n\
     }
 
 #ifndef TERM
     }
 
 #ifndef TERM
-  host_info_ptr = gethostbyname (XSTRING (host)->data);
+  while (1)
+    {
+#ifdef TRY_AGAIN
+      h_errno = 0;
+#endif
+      host_info_ptr = gethostbyname (XSTRING (host)->data);
+#ifdef TRY_AGAIN
+      if (! (host_info_ptr == 0 && h_errno == TRY_AGAIN))
+#endif
+       break;
+      Fsleep_for (make_number (1), Qnil);
+    }
   if (host_info_ptr == 0)
     /* Attempt to interpret host as numeric inet address */
     {
   if (host_info_ptr == 0)
     /* Attempt to interpret host as numeric inet address */
     {
@@ -1466,12 +1638,27 @@ Fourth arg SERVICE is name of the service desired, or an integer\n\
   if (interrupt_input)
     unrequest_sigio ();
 
   if (interrupt_input)
     unrequest_sigio ();
 
+  /* Slow down polling to every ten seconds.
+     Some kernels have a bug which causes retrying connect to fail
+     after a connect.  */
+#ifdef POLL_FOR_INPUT
+  bind_polling_period (10);
+#endif
+
  loop:
  loop:
-  if (connect (s, (struct sockaddr *) &address, sizeof address) == -1)
+  if (connect (s, (struct sockaddr *) &address, sizeof address) == -1
+      && errno != EISCONN)
     {
       int xerrno = errno;
     {
       int xerrno = errno;
+
       if (errno == EINTR)
        goto loop;
       if (errno == EINTR)
        goto loop;
+      if (errno == EADDRINUSE && retry < 20)
+       {
+         retry++;
+         goto loop;
+       }
+
       close (s);
 
       if (interrupt_input)
       close (s);
 
       if (interrupt_input)
@@ -1482,6 +1669,10 @@ Fourth arg SERVICE is name of the service desired, or an integer\n\
                         Fcons (host, Fcons (name, Qnil)));
     }
 
                         Fcons (host, Fcons (name, Qnil)));
     }
 
+#ifdef POLL_FOR_INPUT
+  unbind_to (count, Qnil);
+#endif
+
   if (interrupt_input)
     request_sigio ();
 
   if (interrupt_input)
     request_sigio ();
 
@@ -1519,10 +1710,13 @@ Fourth arg SERVICE is name of the service desired, or an integer\n\
   XPROCESS (proc)->filter = Qnil;
   XPROCESS (proc)->command = Qnil;
   XPROCESS (proc)->pid = Qnil;
   XPROCESS (proc)->filter = Qnil;
   XPROCESS (proc)->command = Qnil;
   XPROCESS (proc)->pid = Qnil;
-  XSET (XPROCESS (proc)->infd, Lisp_Int, s);
-  XSET (XPROCESS (proc)->outfd, Lisp_Int, outch);
+  XSETINT (XPROCESS (proc)->infd, s);
+  XSETINT (XPROCESS (proc)->outfd, outch);
   XPROCESS (proc)->status = Qrun;
   FD_SET (inch, &input_wait_mask);
   XPROCESS (proc)->status = Qrun;
   FD_SET (inch, &input_wait_mask);
+  FD_SET (inch, &non_keyboard_wait_mask);
+  if (inch > max_process_desc)
+    max_process_desc = inch;
 
   UNGCPRO;
   return proc;
 
   UNGCPRO;
   return proc;
@@ -1556,10 +1750,21 @@ deactivate_process (proc)
        close (outchannel);
 #endif
 
        close (outchannel);
 #endif
 
-      XSET (p->infd, Lisp_Int, -1);
-      XSET (p->outfd, Lisp_Int, -1);
+      XSETINT (p->infd, -1);
+      XSETINT (p->outfd, -1);
       chan_process[inchannel] = Qnil;
       FD_CLR (inchannel, &input_wait_mask);
       chan_process[inchannel] = Qnil;
       FD_CLR (inchannel, &input_wait_mask);
+      FD_CLR (inchannel, &non_keyboard_wait_mask);
+      if (inchannel == max_process_desc)
+       {
+         int i;
+         /* We just closed the highest-numbered process input descriptor,
+            so recompute the highest-numbered one now.  */
+         max_process_desc = 0;
+         for (i = 0; i < MAXDESC; i++)
+           if (!NILP (chan_process[i]))
+             max_process_desc = i;
+       }
     }
 }
 
     }
 }
 
@@ -1569,6 +1774,7 @@ deactivate_process (proc)
 
 close_process_descs ()
 {
 
 close_process_descs ()
 {
+#ifndef WINDOWSNT
   int i;
   for (i = 0; i < MAXDESC; i++)
     {
   int i;
   for (i = 0; i < MAXDESC; i++)
     {
@@ -1584,6 +1790,7 @@ close_process_descs ()
            close (out);
        }
     }
            close (out);
        }
     }
+#endif
 }
 \f
 DEFUN ("accept-process-output", Faccept_process_output, Saccept_process_output,
 }
 \f
 DEFUN ("accept-process-output", Faccept_process_output, Saccept_process_output,
@@ -1606,8 +1813,8 @@ Return non-nil iff we received any output before the timeout expired.")
     {
       CHECK_NUMBER (timeout_msecs, 2);
       useconds = XINT (timeout_msecs);
     {
       CHECK_NUMBER (timeout_msecs, 2);
       useconds = XINT (timeout_msecs);
-      if (XTYPE (timeout) != Lisp_Int)
-       XSET (timeout, Lisp_Int, 0);
+      if (!INTEGERP (timeout))
+       XSETINT (timeout, 0);
 
       {
        int carry = useconds / 1000000;
 
       {
        int carry = useconds / 1000000;
@@ -1644,7 +1851,7 @@ Return non-nil iff we received any output before the timeout expired.")
     }
 
   if (NILP (proc))
     }
 
   if (NILP (proc))
-    XFASTINT (proc) = 0;
+    XSETFASTINT (proc, 0);
 
   return
     (wait_reading_process_input (seconds, useconds, proc, 0)
 
   return
     (wait_reading_process_input (seconds, useconds, proc, 0)
@@ -1656,7 +1863,10 @@ Return non-nil iff we received any output before the timeout expired.")
    function Fwaiting_for_user_input_p below) whether emacs was waiting
    for user-input when that process-filter was called.
    waiting_for_input cannot be used as that is by definition 0 when
    function Fwaiting_for_user_input_p below) whether emacs was waiting
    for user-input when that process-filter was called.
    waiting_for_input cannot be used as that is by definition 0 when
-   lisp code is being evalled */
+   lisp code is being evalled.
+   This is also used in record_asynch_buffer_change.
+   For that purpose, this must be 0
+   when not inside wait_reading_process_input.  */
 static int waiting_for_user_input_p;
 
 /* Read and dispose of subprocess output while waiting for timeout to
 static int waiting_for_user_input_p;
 
 /* Read and dispose of subprocess output while waiting for timeout to
@@ -1677,7 +1887,7 @@ static int waiting_for_user_input_p;
      1 to return when input is available, or
      -1 meaning caller will actually read the input, so don't throw to
        the quit handler, or
      1 to return when input is available, or
      -1 meaning caller will actually read the input, so don't throw to
        the quit handler, or
-     a cons cell, meaning wait wait until its car is non-nil
+     a cons cell, meaning wait until its car is non-nil
        (and gobble terminal input into the buffer if any arrives), or
      a process object, meaning wait until something arrives from that
        process.  The return value is true iff we read some input from
        (and gobble terminal input into the buffer if any arrives), or
      a process object, meaning wait until something arrives from that
        process.  The return value is true iff we read some input from
@@ -1711,18 +1921,18 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
 
   /* If read_kbd is a process to watch, set wait_proc and wait_channel
      accordingly.  */
 
   /* If read_kbd is a process to watch, set wait_proc and wait_channel
      accordingly.  */
-  if (XTYPE (read_kbd) == Lisp_Process)
+  if (PROCESSP (read_kbd))
     {
       wait_proc = XPROCESS (read_kbd);
       wait_channel = XINT (wait_proc->infd);
     {
       wait_proc = XPROCESS (read_kbd);
       wait_channel = XINT (wait_proc->infd);
-      XFASTINT (read_kbd) = 0;
+      XSETFASTINT (read_kbd, 0);
     }
 
   /* If waiting for non-nil in a cell, record where.  */
     }
 
   /* If waiting for non-nil in a cell, record where.  */
-  if (XTYPE (read_kbd) == Lisp_Cons)
+  if (CONSP (read_kbd))
     {
       wait_for_cell = &XCONS (read_kbd)->car;
     {
       wait_for_cell = &XCONS (read_kbd)->car;
-      XFASTINT (read_kbd) = 0;
+      XSETFASTINT (read_kbd, 0);
     }
 
   waiting_for_user_input_p = XINT (read_kbd);
     }
 
   waiting_for_user_input_p = XINT (read_kbd);
@@ -1738,7 +1948,8 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
 
   /* It would not be safe to call this below,
      where we call redisplay_preserve_echo_area.  */
 
   /* It would not be safe to call this below,
      where we call redisplay_preserve_echo_area.  */
-  prepare_menu_bars ();
+  if (do_display && frame_garbaged)
+    prepare_menu_bars ();
 
   while (1)
     {
 
   while (1)
     {
@@ -1812,19 +2023,17 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
 
       /* Wait till there is something to do */
 
 
       /* Wait till there is something to do */
 
-      Available = input_wait_mask;
-      /* We used to have  && wait_for_cell == 0
-        but that led to lossage handling selection_request events:
-        within one, we would start to handle another.  */
-      if (! XINT (read_kbd))
-       FD_CLR (keyboard_descriptor, &Available);
+      if (! XINT (read_kbd) && wait_for_cell == 0)
+       Available = non_keyboard_wait_mask;
+      else
+       Available = input_wait_mask;
 
       /* If frame size has changed or the window is newly mapped,
         redisplay now, before we start to wait.  There is a race
         condition here; if a SIGIO arrives between now and the select
         and indicates that a frame is trashed, the select may block
         displaying a trashed screen.  */
 
       /* If frame size has changed or the window is newly mapped,
         redisplay now, before we start to wait.  There is a race
         condition here; if a SIGIO arrives between now and the select
         and indicates that a frame is trashed, the select may block
         displaying a trashed screen.  */
-      if (frame_garbaged)
+      if (frame_garbaged && do_display)
        redisplay_preserve_echo_area ();
 
       if (XINT (read_kbd) && detect_input_pending ())
        redisplay_preserve_echo_area ();
 
       if (XINT (read_kbd) && detect_input_pending ())
@@ -1883,7 +2092,7 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
            error("select error: %s", strerror (xerrno));
        }
 #if defined(sun) && !defined(USG5_4)
            error("select error: %s", strerror (xerrno));
        }
 #if defined(sun) && !defined(USG5_4)
-      else if (nfds > 0 && FD_ISSET (keyboard_descriptor, &Available)
+      else if (nfds > 0 && keyboard_bit_set (&Available)
               && interrupt_input)
        /* System sometimes fails to deliver SIGIO.
 
               && interrupt_input)
        /* System sometimes fails to deliver SIGIO.
 
@@ -1899,9 +2108,9 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
       /* If there is any, return immediately
         to give it higher priority than subprocesses */
 
       /* If there is any, return immediately
         to give it higher priority than subprocesses */
 
-      /* We used to do his if wait_for_cell,
+      /* We used to do this if wait_for_cell,
         but that caused infinite recursion in selection request events.  */
         but that caused infinite recursion in selection request events.  */
-      if ((XINT (read_kbd))
+      if ((XINT (read_kbd) || wait_for_cell)
          && detect_input_pending ())
        {
          swallow_events ();
          && detect_input_pending ())
        {
          swallow_events ();
@@ -1920,7 +2129,7 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
         but select says there is input.  */
 
       if (XINT (read_kbd) && interrupt_input
         but select says there is input.  */
 
       if (XINT (read_kbd) && interrupt_input
-         && (FD_ISSET (keyboard_descriptor, &Available)))
+         && (keyboard_bit_set (&Available)))
        kill (0, SIGIO);
 #endif
 
        kill (0, SIGIO);
 #endif
 
@@ -1935,10 +2144,10 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
       /* Check for data from a process.  */
       /* Really FIRST_PROC_DESC should be 0 on Unix,
         but this is safer in the short run.  */
       /* Check for data from a process.  */
       /* Really FIRST_PROC_DESC should be 0 on Unix,
         but this is safer in the short run.  */
-      for (channel = keyboard_descriptor == 0 ? FIRST_PROC_DESC : 0;
-          channel < MAXDESC; channel++)
+      for (channel = 0; channel <= max_process_desc; channel++)
        {
        {
-         if (FD_ISSET (channel, &Available))
+         if (FD_ISSET (channel, &Available)
+             && FD_ISSET (channel, &non_keyboard_wait_mask))
            {
              int nread;
 
            {
              int nread;
 
@@ -2022,6 +2231,8 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
        }                       /* end for each file descriptor */
     }                          /* end while exit conditions not met */
 
        }                       /* end for each file descriptor */
     }                          /* end while exit conditions not met */
 
+  waiting_for_user_input_p = 0;
+
   /* If calling from keyboard input, do not quit
      since we want to return C-g as an input character.
      Otherwise, do pending quit if requested.  */
   /* If calling from keyboard input, do not quit
      since we want to return C-g as an input character.
      Otherwise, do pending quit if requested.  */
@@ -2035,6 +2246,25 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
   return got_some_input;
 }
 \f
   return got_some_input;
 }
 \f
+/* Given a list (FUNCTION ARGS...), apply FUNCTION to the ARGS.  */
+
+static Lisp_Object
+read_process_output_call (fun_and_args)
+     Lisp_Object fun_and_args;
+{
+  return apply1 (XCONS (fun_and_args)->car, XCONS (fun_and_args)->cdr);
+}
+
+static Lisp_Object
+read_process_output_error_handler (error)
+     Lisp_Object error;
+{
+  cmd_error_internal (error, "error in process filter: ");
+  Vinhibit_quit = Qt;
+  update_echo_area ();
+  Fsleep_for (make_number (2));
+}
+
 /* Read pending output from the process channel,
    starting with our buffered-ahead character if we have one.
    Yield number of characters read.
 /* Read pending output from the process channel,
    starting with our buffered-ahead character if we have one.
    Yield number of characters read.
@@ -2081,12 +2311,20 @@ read_process_output (proc, channel)
 #else /* not VMS */
 
   if (proc_buffered_char[channel] < 0)
 #else /* not VMS */
 
   if (proc_buffered_char[channel] < 0)
+#ifdef WINDOWSNT
+    nchars = read_child_output (channel, chars, sizeof (chars));
+#else
     nchars = read (channel, chars, sizeof chars);
     nchars = read (channel, chars, sizeof chars);
+#endif
   else
     {
       chars[0] = proc_buffered_char[channel];
       proc_buffered_char[channel] = -1;
   else
     {
       chars[0] = proc_buffered_char[channel];
       proc_buffered_char[channel] = -1;
+#ifdef WINDOWSNT
+      nchars = read_child_output (channel, chars + 1, sizeof (chars) - 1);
+#else
       nchars = read (channel, chars + 1, sizeof chars - 1);
       nchars = read (channel, chars + 1, sizeof chars - 1);
+#endif
       if (nchars < 0)
        nchars = 1;
       else
       if (nchars < 0)
        nchars = 1;
       else
@@ -2104,19 +2342,39 @@ read_process_output (proc, channel)
         it up.  */
       int count = specpdl_ptr - specpdl;
       Lisp_Object odeactivate;
         it up.  */
       int count = specpdl_ptr - specpdl;
       Lisp_Object odeactivate;
+      Lisp_Object obuffer;
 
       odeactivate = Vdeactivate_mark;
 
       odeactivate = Vdeactivate_mark;
+      obuffer = Fcurrent_buffer ();
 
       specbind (Qinhibit_quit, Qt);
 
       specbind (Qinhibit_quit, Qt);
-      call2 (outstream, proc, make_string (chars, nchars));
+      specbind (Qlast_nonmenu_event, Qt);
+
+      running_asynch_code = 1;
+      internal_condition_case_1 (read_process_output_call,
+                                Fcons (outstream,
+                                       Fcons (proc,
+                                              Fcons (make_string (chars,
+                                                                  nchars),
+                                                     Qnil))),
+                                !NILP (Vdebug_on_error) ? Qnil : Qerror,
+                                read_process_output_error_handler);
+      running_asynch_code = 0;
+      restore_match_data ();
 
       /* Handling the process output should not deactivate the mark.  */
       Vdeactivate_mark = odeactivate;
 
 
       /* Handling the process output should not deactivate the mark.  */
       Vdeactivate_mark = odeactivate;
 
+      if (! EQ (Fcurrent_buffer (), obuffer))
+       record_asynch_buffer_change ();
+
+      if (waiting_for_user_input_p)
+       prepare_menu_bars ();
+
 #ifdef VMS
       start_vms_process_read (vs);
 #endif
 #ifdef VMS
       start_vms_process_read (vs);
 #endif
-      unbind_to (count);
+      unbind_to (count, Qnil);
       return nchars;
     }
 
       return nchars;
     }
 
@@ -2132,8 +2390,8 @@ read_process_output (proc, channel)
       Fset_buffer (p->buffer);
       opoint = point;
       old_read_only = current_buffer->read_only;
       Fset_buffer (p->buffer);
       opoint = point;
       old_read_only = current_buffer->read_only;
-      XFASTINT (old_begv) = BEGV;
-      XFASTINT (old_zv) = ZV;
+      XSETFASTINT (old_begv, BEGV);
+      XSETFASTINT (old_zv, ZV);
 
       current_buffer->read_only = Qnil;
 
 
       current_buffer->read_only = Qnil;
 
@@ -2157,9 +2415,9 @@ read_process_output (proc, channel)
 
       /* Insert after old_begv, but before old_zv.  */
       if (point < XFASTINT (old_begv))
 
       /* Insert after old_begv, but before old_zv.  */
       if (point < XFASTINT (old_begv))
-       XFASTINT (old_begv) += nchars;
+       XSETFASTINT (old_begv, XFASTINT (old_begv) + nchars);
       if (point <= XFASTINT (old_zv))
       if (point <= XFASTINT (old_zv))
-       XFASTINT (old_zv) += nchars;
+       XSETFASTINT (old_zv, XFASTINT (old_zv) + nchars);
 
       /* Insert before markers in case we are inserting where
         the buffer's mark is, and the user's next command is Meta-y.  */
 
       /* Insert before markers in case we are inserting where
         the buffer's mark is, and the user's next command is Meta-y.  */
@@ -2187,11 +2445,11 @@ read_process_output (proc, channel)
 
 DEFUN ("waiting-for-user-input-p", Fwaiting_for_user_input_p, Swaiting_for_user_input_p,
        0, 0, 0,
 
 DEFUN ("waiting-for-user-input-p", Fwaiting_for_user_input_p, Swaiting_for_user_input_p,
        0, 0, 0,
-  "Returns non-NIL if emacs is waiting for input from the user.\n\
+  "Returns non-nil if emacs is waiting for input from the user.\n\
 This is intended for use by asynchronous process output filters and sentinels.")
        ()
 {
 This is intended for use by asynchronous process output filters and sentinels.")
        ()
 {
-  return ((waiting_for_user_input_p) ? Qt : Qnil);
+  return (waiting_for_user_input_p ? Qt : Qnil);
 }
 \f
 /* Sending data to subprocess */
 }
 \f
 /* Sending data to subprocess */
@@ -2208,16 +2466,20 @@ send_process_trap ()
   longjmp (send_process_frame, 1);
 }
 
   longjmp (send_process_frame, 1);
 }
 
-send_process (proc, buf, len)
+/* Send some data to process PROC.
+   BUF is the beginning of the data; LEN is the number of characters.
+   OBJECT is the Lisp object that the data comes from.  */
+
+send_process (proc, buf, len, object)
      Lisp_Object proc;
      char *buf;
      int len;
      Lisp_Object proc;
      char *buf;
      int len;
+     Lisp_Object object;
 {
   /* Don't use register vars; longjmp can lose them.  */
   int rv;
   unsigned char *procname = XSTRING (XPROCESS (proc)->name)->data;
 
 {
   /* Don't use register vars; longjmp can lose them.  */
   int rv;
   unsigned char *procname = XSTRING (XPROCESS (proc)->name)->data;
 
-
 #ifdef VMS
   struct Lisp_Process *p = XPROCESS (proc);
   VMS_PROC_STUFF *vs, *get_vms_process_pointer();
 #ifdef VMS
   struct Lisp_Process *p = XPROCESS (proc);
   VMS_PROC_STUFF *vs, *get_vms_process_pointer();
@@ -2235,51 +2497,111 @@ send_process (proc, buf, len)
   else if (write_to_vms_process (vs, buf, len))
     ;
 #else
   else if (write_to_vms_process (vs, buf, len))
     ;
 #else
+
+  if (pty_max_bytes == 0)
+    {
+#if defined (HAVE_FPATHCONF) && defined (_PC_MAX_CANON)
+      pty_max_bytes = fpathconf (XFASTINT (XPROCESS (proc)->outfd),
+                                _PC_MAX_CANON);
+      if (pty_max_bytes < 0)
+       pty_max_bytes = 250;
+#else
+      pty_max_bytes = 250;
+#endif
+      /* Deduct one, to leave space for the eof.  */
+      pty_max_bytes--;
+    }
+
   if (!setjmp (send_process_frame))
     while (len > 0)
       {
        int this = len;
        SIGTYPE (*old_sigpipe)();
   if (!setjmp (send_process_frame))
     while (len > 0)
       {
        int this = len;
        SIGTYPE (*old_sigpipe)();
+       int flush_pty = 0;
 
 
-       /* Don't send more than 500 bytes at a time.  */
-       if (this > 500)
-         this = 500;
-       old_sigpipe = (SIGTYPE (*) ()) signal (SIGPIPE, send_process_trap);
-       rv = write (XINT (XPROCESS (proc)->outfd), buf, this);
-       signal (SIGPIPE, old_sigpipe);
-       if (rv < 0)
+       /* Decide how much data we can send in one batch.
+          Long lines need to be split into multiple batches.  */
+       if (!NILP (XPROCESS (proc)->pty_flag))
          {
          {
-           if (0
-#ifdef EWOULDBLOCK
-               || errno == EWOULDBLOCK
-#endif
-#ifdef EAGAIN
-               || errno == EAGAIN
-#endif
-               )
+           /* Starting this at zero is always correct when not the first iteration
+              because the previous iteration ended by sending C-d.
+              It may not be correct for the first iteration
+              if a partial line was sent in a separate send_process call.
+              If that proves worth handling, we need to save linepos
+              in the process object.  */
+           int linepos = 0;
+           char *ptr = buf;
+           char *end = buf + len;
+
+           /* Scan through this text for a line that is too long.  */
+           while (ptr != end && linepos < pty_max_bytes)
              {
              {
-               /* It would be nice to accept process output here,
-                  but that is difficult.  For example, it could
-                  garbage what we are sending if that is from a buffer.  */
-               immediate_quit = 1;
-               QUIT;
-               sleep (1);
-               immediate_quit = 0;
-               continue;
+               if (*ptr == '\n')
+                 linepos = 0;
+               else
+                 linepos++;
+               ptr++;
              }
              }
-           report_file_error ("writing to process", Fcons (proc, Qnil));
+           /* If we found one, break the line there
+              and put in a C-d to force the buffer through.  */
+           this = ptr - buf;
          }
          }
-       buf += rv;
-       len -= rv;
-       /* Allow input from processes between bursts of sending.
-          Otherwise things may get stopped up.  */
-       if (len > 0)
+
+       /* Send this batch, using one or more write calls.  */
+       while (this > 0)
          {
          {
-           Lisp_Object zero;
+           old_sigpipe = (SIGTYPE (*) ()) signal (SIGPIPE, send_process_trap);
+           rv = write (XINT (XPROCESS (proc)->outfd), buf, this);
+           signal (SIGPIPE, old_sigpipe);
 
 
-           XFASTINT (zero) = 0;
-           wait_reading_process_input (-1, 0, zero, 0);
+           if (rv < 0)
+             {
+               if (0
+#ifdef EWOULDBLOCK
+                   || errno == EWOULDBLOCK
+#endif
+#ifdef EAGAIN
+                   || errno == EAGAIN
+#endif
+                   )
+                 /* Buffer is full.  Wait, accepting input; 
+                    that may allow the program
+                    to finish doing output and read more.  */
+                 {
+                   Lisp_Object zero;
+                   int offset;
+
+                   /* Running filters might relocate buffers or strings.
+                      Arrange to relocate BUF.  */
+                   if (BUFFERP (object))
+                     offset = BUF_PTR_CHAR_POS (XBUFFER (object),
+                                                (unsigned char *) buf);
+                   else if (STRINGP (object))
+                     offset = buf - (char *) XSTRING (object)->data;
+
+                   XSETFASTINT (zero, 0);
+                   wait_reading_process_input (1, 0, zero, 0);
+
+                   if (BUFFERP (object))
+                     buf = (char *) BUF_CHAR_ADDRESS (XBUFFER (object), offset);
+                   else if (STRINGP (object))
+                     buf = offset + (char *) XSTRING (object)->data;
+
+                   rv = 0;
+                 }
+               else
+                 /* This is a real error.  */
+                 report_file_error ("writing to process", Fcons (proc, Qnil));
+             }
+           buf += rv;
+           len -= rv;
+           this -= rv;
          }
          }
+
+       /* If we sent just part of the string, put in an EOF
+          to force it through, before we send the rest.  */
+       if (len > 0)
+         Fprocess_send_eof (proc);
       }
 #endif
   else
       }
 #endif
   else
@@ -2319,7 +2641,8 @@ Output from processes can arrive in between bunches.")
     move_gap (start);
 
   start1 = XINT (start);
     move_gap (start);
 
   start1 = XINT (start);
-  send_process (proc, &FETCH_CHAR (start1), XINT (end) - XINT (start));
+  send_process (proc, &FETCH_CHAR (start1), XINT (end) - XINT (start),
+               Fcurrent_buffer ());
 
   return Qnil;
 }
 
   return Qnil;
 }
@@ -2338,7 +2661,7 @@ Output from processes can arrive in between bunches.")
   Lisp_Object proc;
   CHECK_STRING (string, 1);
   proc = get_process (process);
   Lisp_Object proc;
   CHECK_STRING (string, 1);
   proc = get_process (process);
-  send_process (proc, XSTRING (string)->data, XSTRING (string)->size);
+  send_process (proc, XSTRING (string)->data, XSTRING (string)->size, string);
   return Qnil;
 }
 \f
   return Qnil;
 }
 \f
@@ -2350,7 +2673,7 @@ Output from processes can arrive in between bunches.")
    right away.
 
    If we can, we try to signal PROCESS by sending control characters
    right away.
 
    If we can, we try to signal PROCESS by sending control characters
-   down the pipe.  This allows us to signal inferiors who have changed
+   down the pty.  This allows us to signal inferiors who have changed
    their uid, for which killpg would return an EPERM error.  */
 
 static void
    their uid, for which killpg would return an EPERM error.  */
 
 static void
@@ -2394,20 +2717,20 @@ process_send_signal (process, signo, current_group, nomsg)
        {
        case SIGINT:
          tcgetattr (XINT (p->infd), &t);
        {
        case SIGINT:
          tcgetattr (XINT (p->infd), &t);
-         send_process (proc, &t.c_cc[VINTR], 1);
+         send_process (proc, &t.c_cc[VINTR], 1, Qnil);
          return;
 
        case SIGQUIT:
          tcgetattr (XINT (p->infd), &t);
          return;
 
        case SIGQUIT:
          tcgetattr (XINT (p->infd), &t);
-         send_process (proc, &t.c_cc[VQUIT], 1);
+         send_process (proc, &t.c_cc[VQUIT], 1, Qnil);
          return;
 
        case SIGTSTP:
          tcgetattr (XINT (p->infd), &t);
          return;
 
        case SIGTSTP:
          tcgetattr (XINT (p->infd), &t);
-#if defined (VSWTCH) && !defined (IRIX5)
-         send_process (proc, &t.c_cc[VSWTCH], 1);
+#if defined (VSWTCH) && !defined (PREFER_VSUSP)
+         send_process (proc, &t.c_cc[VSWTCH], 1, Qnil);
 #else
 #else
-         send_process (proc, &t.c_cc[VSUSP], 1);
+         send_process (proc, &t.c_cc[VSUSP], 1, Qnil);
 #endif
          return;
        }
 #endif
          return;
        }
@@ -2425,16 +2748,16 @@ process_send_signal (process, signo, current_group, nomsg)
        {
        case SIGINT:
          ioctl (XINT (p->infd), TIOCGETC, &c);
        {
        case SIGINT:
          ioctl (XINT (p->infd), TIOCGETC, &c);
-         send_process (proc, &c.t_intrc, 1);
+         send_process (proc, &c.t_intrc, 1, Qnil);
          return;
        case SIGQUIT:
          ioctl (XINT (p->infd), TIOCGETC, &c);
          return;
        case SIGQUIT:
          ioctl (XINT (p->infd), TIOCGETC, &c);
-         send_process (proc, &c.t_quitc, 1);
+         send_process (proc, &c.t_quitc, 1, Qnil);
          return;
 #ifdef SIGTSTP
        case SIGTSTP:
          ioctl (XINT (p->infd), TIOCGLTC, &lc);
          return;
 #ifdef SIGTSTP
        case SIGTSTP:
          ioctl (XINT (p->infd), TIOCGLTC, &lc);
-         send_process (proc, &lc.t_suspc, 1);
+         send_process (proc, &lc.t_suspc, 1, Qnil);
          return;
 #endif /* ! defined (SIGTSTP) */
        }
          return;
 #endif /* ! defined (SIGTSTP) */
        }
@@ -2449,16 +2772,16 @@ process_send_signal (process, signo, current_group, nomsg)
        {
        case SIGINT:
          ioctl (XINT (p->infd), TCGETA, &t);
        {
        case SIGINT:
          ioctl (XINT (p->infd), TCGETA, &t);
-         send_process (proc, &t.c_cc[VINTR], 1);
+         send_process (proc, &t.c_cc[VINTR], 1, Qnil);
          return;
        case SIGQUIT:
          ioctl (XINT (p->infd), TCGETA, &t);
          return;
        case SIGQUIT:
          ioctl (XINT (p->infd), TCGETA, &t);
-         send_process (proc, &t.c_cc[VQUIT], 1);
+         send_process (proc, &t.c_cc[VQUIT], 1, Qnil);
          return;
 #ifdef SIGTSTP
        case SIGTSTP:
          ioctl (XINT (p->infd), TCGETA, &t);
          return;
 #ifdef SIGTSTP
        case SIGTSTP:
          ioctl (XINT (p->infd), TCGETA, &t);
-         send_process (proc, &t.c_cc[VSWTCH], 1);
+         send_process (proc, &t.c_cc[VSWTCH], 1, Qnil);
          return;
 #endif /* ! defined (SIGTSTP) */
        }
          return;
 #endif /* ! defined (SIGTSTP) */
        }
@@ -2519,12 +2842,12 @@ process_send_signal (process, signo, current_group, nomsg)
 #endif /* ! defined (SIGCONT) */
     case SIGINT:
 #ifdef VMS
 #endif /* ! defined (SIGCONT) */
     case SIGINT:
 #ifdef VMS
-      send_process (proc, "\003", 1);  /* ^C */
+      send_process (proc, "\003", 1, Qnil);    /* ^C */
       goto whoosh;
 #endif
     case SIGQUIT:
 #ifdef VMS
       goto whoosh;
 #endif
     case SIGQUIT:
 #ifdef VMS
-      send_process (proc, "\031", 1);  /* ^Y */
+      send_process (proc, "\031", 1, Qnil);    /* ^Y */
       goto whoosh;
 #endif
     case SIGKILL:
       goto whoosh;
 #endif
     case SIGKILL:
@@ -2562,7 +2885,7 @@ process_send_signal (process, signo, current_group, nomsg)
 DEFUN ("interrupt-process", Finterrupt_process, Sinterrupt_process, 0, 2, 0,
   "Interrupt process PROCESS.  May be process or name of one.\n\
 PROCESS may be a process, a buffer, or the name of a process or buffer.\n\
 DEFUN ("interrupt-process", Finterrupt_process, Sinterrupt_process, 0, 2, 0,
   "Interrupt process PROCESS.  May be process or name of one.\n\
 PROCESS may be a process, a buffer, or the name of a process or buffer.\n\
-Nil or no arg means current buffer's process.\n\
+nil or no arg means current buffer's process.\n\
 Second arg CURRENT-GROUP non-nil means send signal to\n\
 the current process-group of the process's controlling terminal\n\
 rather than to the process's own process group.\n\
 Second arg CURRENT-GROUP non-nil means send signal to\n\
 the current process-group of the process's controlling terminal\n\
 rather than to the process's own process group.\n\
@@ -2632,14 +2955,22 @@ Both PID and CODE are integers.")
 {
   CHECK_NUMBER (pid, 0);
   CHECK_NUMBER (sig, 1);
 {
   CHECK_NUMBER (pid, 0);
   CHECK_NUMBER (sig, 1);
+#ifdef WINDOWSNT
+  /* Only works for kill-type signals */
+  return make_number (win32_kill_process (XINT (pid), XINT (sig)));
+#else
   return make_number (kill (XINT (pid), XINT (sig)));
   return make_number (kill (XINT (pid), XINT (sig)));
+#endif
 }
 
 DEFUN ("process-send-eof", Fprocess_send_eof, Sprocess_send_eof, 0, 1, 0,
   "Make PROCESS see end-of-file in its input.\n\
 Eof comes after any text already sent to it.\n\
 PROCESS may be a process, a buffer, the name of a process or buffer, or\n\
 }
 
 DEFUN ("process-send-eof", Fprocess_send_eof, Sprocess_send_eof, 0, 1, 0,
   "Make PROCESS see end-of-file in its input.\n\
 Eof comes after any text already sent to it.\n\
 PROCESS may be a process, a buffer, the name of a process or buffer, or\n\
-nil, indicating the current buffer's process.")
+nil, indicating the current buffer's process.\n\
+If PROCESS is a network connection, or is a process communicating\n\
+through a pipe (as opposed to a pty), then you cannot send any more\n\
+text to PROCESS after you call this function.")
   (process)
      Lisp_Object process;
 {
   (process)
      Lisp_Object process;
 {
@@ -2653,26 +2984,17 @@ nil, indicating the current buffer's process.")
   if (! EQ (XPROCESS (proc)->status, Qrun))
     error ("Process %s not running", XSTRING (XPROCESS (proc)->name)->data);
 
   if (! EQ (XPROCESS (proc)->status, Qrun))
     error ("Process %s not running", XSTRING (XPROCESS (proc)->name)->data);
 
-  /* Sending a zero-length record is supposed to mean eof
-     when TIOCREMOTE is turned on.  */
-#ifdef DID_REMOTE
-  {
-    char buf[1];
-    write (XINT (XPROCESS (proc)->outfd), buf, 0);
-  }
-#else /* did not do TOICREMOTE */
 #ifdef VMS
 #ifdef VMS
-  send_process (proc, "\032", 1);      /* ^z */
+  send_process (proc, "\032", 1, Qnil);        /* ^z */
 #else
   if (!NILP (XPROCESS (proc)->pty_flag))
 #else
   if (!NILP (XPROCESS (proc)->pty_flag))
-    send_process (proc, "\004", 1);
+    send_process (proc, "\004", 1, Qnil);
   else
     {
       close (XINT (XPROCESS (proc)->outfd));
   else
     {
       close (XINT (XPROCESS (proc)->outfd));
-      XSET (XPROCESS (proc)->outfd, Lisp_Int, open (NULL_DEVICE, O_WRONLY));
+      XSETINT (XPROCESS (proc)->outfd, open (NULL_DEVICE, O_WRONLY));
     }
 #endif /* VMS */
     }
 #endif /* VMS */
-#endif /* did not do TOICREMOTE */
   return process;
 }
 
   return process;
 }
 
@@ -2684,15 +3006,14 @@ kill_buffer_processes (buffer)
 {
   Lisp_Object tail, proc;
 
 {
   Lisp_Object tail, proc;
 
-  for (tail = Vprocess_alist; XGCTYPE (tail) == Lisp_Cons;
-       tail = XCONS (tail)->cdr)
+  for (tail = Vprocess_alist; GC_CONSP (tail); tail = XCONS (tail)->cdr)
     {
       proc = XCONS (XCONS (tail)->car)->cdr;
     {
       proc = XCONS (XCONS (tail)->car)->cdr;
-      if (XGCTYPE (proc) == Lisp_Process
+      if (GC_PROCESSP (proc)
          && (NILP (buffer) || EQ (XPROCESS (proc)->buffer, buffer)))
        {
          if (NETCONN_P (proc))
          && (NILP (buffer) || EQ (XPROCESS (proc)->buffer, buffer)))
        {
          if (NETCONN_P (proc))
-           deactivate_process (proc);
+           Fdelete_process (proc);
          else if (XINT (XPROCESS (proc)->infd) >= 0)
            process_send_signal (proc, SIGHUP, Qnil, 1);
        }
          else if (XINT (XPROCESS (proc)->infd) >= 0)
            process_send_signal (proc, SIGHUP, Qnil, 1);
        }
@@ -2791,7 +3112,7 @@ sigchld_handler (signo)
          {
            proc = XCONS (XCONS (tail)->car)->cdr;
            p = XPROCESS (proc);
          {
            proc = XCONS (XCONS (tail)->car)->cdr;
            p = XPROCESS (proc);
-           if (XTYPE (p->pid) == Lisp_Int && XINT (p->pid) == -1)
+           if (INTEGERP (p->pid) && XINT (p->pid) == -1)
              break;
            p = 0;
          }
              break;
            p = 0;
          }
@@ -2800,16 +3121,24 @@ sigchld_handler (signo)
       if (p != 0)
        {
          union { int i; WAITTYPE wt; } u;
       if (p != 0)
        {
          union { int i; WAITTYPE wt; } u;
+         int clear_desc_flag = 0;
          
          XSETINT (p->tick, ++process_tick);
          u.wt = w;
          
          XSETINT (p->tick, ++process_tick);
          u.wt = w;
-         XFASTINT (p->raw_status_low) = u.i & 0xffff;
-         XFASTINT (p->raw_status_high) = u.i >> 16;
+         XSETFASTINT (p->raw_status_low, u.i & 0xffff);
+         XSETFASTINT (p->raw_status_high, u.i >> 16);
          
          /* If process has terminated, stop waiting for its output.  */
          
          /* If process has terminated, stop waiting for its output.  */
-         if (WIFSIGNALED (w) || WIFEXITED (w))
-           if (XINT (p->infd) >= 0)
+         if ((WIFSIGNALED (w) || WIFEXITED (w))
+             && XINT (p->infd) >= 0)
+           clear_desc_flag = 1;
+
+         /* We use clear_desc_flag to avoid a compiler bug in Microsoft C.  */
+         if (clear_desc_flag)
+           {
              FD_CLR (XINT (p->infd), &input_wait_mask);
              FD_CLR (XINT (p->infd), &input_wait_mask);
+             FD_CLR (XINT (p->infd), &non_keyboard_wait_mask);
+           }
 
          /* Tell wait_reading_process_input that it needs to wake up and
             look around.  */
 
          /* Tell wait_reading_process_input that it needs to wake up and
             look around.  */
@@ -2827,11 +3156,24 @@ sigchld_handler (signo)
          if (WIFEXITED (w))
            synch_process_retcode = WRETCODE (w);
          else if (WIFSIGNALED (w))
          if (WIFEXITED (w))
            synch_process_retcode = WRETCODE (w);
          else if (WIFSIGNALED (w))
+           {
+             int code = WTERMSIG (w);
+             char *signame = 0;
+
+             if (code < NSIG)
+               {
 #ifndef VMS
 #ifndef VMS
-           synch_process_death = (char *) sys_siglist[WTERMSIG (w)];
+                 /* Suppress warning if the table has const char *.  */
+                 signame = (char *) sys_siglist[code];
 #else
 #else
-           synch_process_death = sys_errlist[WTERMSIG (w)];
+                 signame = sys_errlist[code];
 #endif
 #endif
+               }
+             if (signame == 0)
+               signame = "unknown";
+
+             synch_process_death = signame;
+           }
 
          /* Tell wait_reading_process_input that it needs to wake up and
             look around.  */
 
          /* Tell wait_reading_process_input that it needs to wake up and
             look around.  */
@@ -2844,7 +3186,7 @@ sigchld_handler (signo)
         get another signal.
         Otherwise (on systems that have WNOHANG), loop around
         to use up all the processes that have something to tell us.  */
         get another signal.
         Otherwise (on systems that have WNOHANG), loop around
         to use up all the processes that have something to tell us.  */
-#if defined (USG) && ! (defined (HPUX) && defined (WNOHANG))
+#if defined (USG) && ! (defined (HPUX) && defined (WNOHANG)) || defined (WINDOWSNT)
 #ifdef USG
       signal (signo, sigchld_handler);
 #endif
 #ifdef USG
       signal (signo, sigchld_handler);
 #endif
@@ -2863,14 +3205,26 @@ exec_sentinel_unwind (data)
   return Qnil;
 }
 
   return Qnil;
 }
 
+static Lisp_Object
+exec_sentinel_error_handler (error)
+     Lisp_Object error;
+{
+  cmd_error_internal (error, "error in process sentinel: ");
+  Vinhibit_quit = Qt;
+  update_echo_area ();
+  Fsleep_for (make_number (2));
+}
+
 static void
 exec_sentinel (proc, reason)
      Lisp_Object proc, reason;
 {
 static void
 exec_sentinel (proc, reason)
      Lisp_Object proc, reason;
 {
-  Lisp_Object sentinel;
+  Lisp_Object sentinel, obuffer, odeactivate;
   register struct Lisp_Process *p = XPROCESS (proc);
   int count = specpdl_ptr - specpdl;
 
   register struct Lisp_Process *p = XPROCESS (proc);
   int count = specpdl_ptr - specpdl;
 
+  odeactivate = Vdeactivate_mark;
+  obuffer = Fcurrent_buffer ();
   sentinel = p->sentinel;
   if (NILP (sentinel))
     return;
   sentinel = p->sentinel;
   if (NILP (sentinel))
     return;
@@ -2881,8 +3235,24 @@ exec_sentinel (proc, reason)
   record_unwind_protect (exec_sentinel_unwind, Fcons (proc, sentinel));
   /* Inhibit quit so that random quits don't screw up a running filter.  */
   specbind (Qinhibit_quit, Qt);
   record_unwind_protect (exec_sentinel_unwind, Fcons (proc, sentinel));
   /* Inhibit quit so that random quits don't screw up a running filter.  */
   specbind (Qinhibit_quit, Qt);
-  call2 (sentinel, proc, reason);
-  unbind_to (count);
+  specbind (Qlast_nonmenu_event, Qt);
+
+  running_asynch_code = 1;
+  internal_condition_case_1 (read_process_output_call,
+                            Fcons (sentinel,
+                                   Fcons (proc, Fcons (reason, Qnil))),
+                            !NILP (Vdebug_on_error) ? Qnil : Qerror,
+                            exec_sentinel_error_handler);
+  running_asynch_code = 0;
+  restore_match_data ();
+
+  Vdeactivate_mark = odeactivate;
+  if (! EQ (Fcurrent_buffer (), obuffer))
+    record_asynch_buffer_change ();
+
+  if (waiting_for_user_input_p)
+    prepare_menu_bars ();
+  unbind_to (count, Qnil);
 }
 
 /* Report all recent events of a change in process status
 }
 
 /* Report all recent events of a change in process status
@@ -2892,10 +3262,11 @@ exec_sentinel (proc, reason)
 status_notify ()
 {
   register Lisp_Object proc, buffer;
 status_notify ()
 {
   register Lisp_Object proc, buffer;
-  Lisp_Object tail = Qnil;
-  Lisp_Object msg = Qnil;
+  Lisp_Object tail, msg;
   struct gcpro gcpro1, gcpro2;
 
   struct gcpro gcpro1, gcpro2;
 
+  tail = Qnil;
+  msg = Qnil;
   /* We need to gcpro tail; if read_process_output calls a filter
      which deletes a process and removes the cons to which tail points
      from Vprocess_alist, and then causes a GC, tail is an unprotected
   /* We need to gcpro tail; if read_process_output calls a filter
      which deletes a process and removes the cons to which tail points
      from Vprocess_alist, and then causes a GC, tail is an unprotected
@@ -2928,7 +3299,7 @@ status_notify ()
 
          /* If process is terminated, deactivate it or delete it.  */
          symbol = p->status;
 
          /* If process is terminated, deactivate it or delete it.  */
          symbol = p->status;
-         if (XTYPE (p->status) == Lisp_Cons)
+         if (CONSP (p->status))
            symbol = XCONS (p->status)->car;
 
          if (EQ (symbol, Qsignal) || EQ (symbol, Qexit)
            symbol = XCONS (p->status)->car;
 
          if (EQ (symbol, Qsignal) || EQ (symbol, Qexit)
@@ -2947,11 +3318,12 @@ status_notify ()
             when a process becomes runnable.  */
          else if (!EQ (symbol, Qrun) && !NILP (buffer))
            {
             when a process becomes runnable.  */
          else if (!EQ (symbol, Qrun) && !NILP (buffer))
            {
-             Lisp_Object ro = XBUFFER (buffer)->read_only;
-             Lisp_Object tem;
+             Lisp_Object ro, tem;
              struct buffer *old = current_buffer;
              int opoint;
 
              struct buffer *old = current_buffer;
              int opoint;
 
+             ro = XBUFFER (buffer)->read_only;
+
              /* Avoid error if buffer is deleted
                 (probably that's why the process is dead, too) */
              if (NILP (XBUFFER (buffer)->name))
              /* Avoid error if buffer is deleted
                 (probably that's why the process is dead, too) */
              if (NILP (XBUFFER (buffer)->name))
@@ -2991,6 +3363,60 @@ status_notify ()
   UNGCPRO;
 }
 \f
   UNGCPRO;
 }
 \f
+/* The first time this is called, assume keyboard input comes from DESC
+   instead of from where we used to expect it.
+   Subsequent calls mean assume input keyboard can come from DESC
+   in addition to other places.  */
+
+static int add_keyboard_wait_descriptor_called_flag;
+
+void
+add_keyboard_wait_descriptor (desc)
+     int desc;
+{
+  if (! add_keyboard_wait_descriptor_called_flag)
+    FD_CLR (0, &input_wait_mask);
+  add_keyboard_wait_descriptor_called_flag = 1;
+  FD_SET (desc, &input_wait_mask);
+  if (desc > max_keyboard_desc)
+    max_keyboard_desc = desc;
+}
+
+/* From now on, do not expect DESC to give keyboard input.  */
+
+void
+delete_keyboard_wait_descriptor (desc)
+     int desc;
+{
+  int fd;
+  int lim = max_keyboard_desc;
+
+  FD_CLR (desc, &input_wait_mask);
+
+  if (desc == max_keyboard_desc)
+    for (fd = 0; fd < lim; fd++)
+      if (FD_ISSET (fd, &input_wait_mask)
+         && !FD_ISSET (fd, &non_keyboard_wait_mask))
+       max_keyboard_desc = fd;
+}
+
+/* Return nonzero if *MASK has a bit set
+   that corresponds to one of the keyboard input descriptors.  */
+
+int
+keyboard_bit_set (mask)
+     SELECT_TYPE *mask;
+{
+  int fd;
+
+  for (fd = 0; fd < max_keyboard_desc; fd++)
+    if (FD_ISSET (fd, mask) && FD_ISSET (fd, &input_wait_mask)
+       && !FD_ISSET (fd, &non_keyboard_wait_mask))
+      return 1;
+
+  return 0;
+}
+\f
 init_process ()
 {
   register int i;
 init_process ()
 {
   register int i;
@@ -3003,9 +3429,10 @@ init_process ()
 #endif
 
   FD_ZERO (&input_wait_mask);
 #endif
 
   FD_ZERO (&input_wait_mask);
+  FD_ZERO (&non_keyboard_wait_mask);
+  max_process_desc = 0;
 
 
-  keyboard_descriptor = 0;
-  FD_SET (keyboard_descriptor, &input_wait_mask);
+  FD_SET (0, &input_wait_mask);
 
   Vprocess_alist = Qnil;
   for (i = 0; i < MAXDESC; i++)
 
   Vprocess_alist = Qnil;
   for (i = 0; i < MAXDESC; i++)
@@ -3015,17 +3442,6 @@ init_process ()
     }
 }
 
     }
 }
 
-/* From now on, assume keyboard input comes from descriptor DESC.  */
-
-void
-change_keyboard_wait_descriptor (desc)
-     int desc;
-{
-  FD_CLR (keyboard_descriptor, &input_wait_mask);
-  keyboard_descriptor = desc;
-  FD_SET (keyboard_descriptor, &input_wait_mask);
-}
-
 syms_of_process ()
 {
 #ifdef HAVE_SOCKETS
 syms_of_process ()
 {
 #ifdef HAVE_SOCKETS
@@ -3051,6 +3467,9 @@ syms_of_process ()
   Qclosed = intern ("closed");
   staticpro (&Qclosed);
 
   Qclosed = intern ("closed");
   staticpro (&Qclosed);
 
+  Qlast_nonmenu_event = intern ("last-nonmenu-event");
+  staticpro (&Qlast_nonmenu_event);
+
   staticpro (&Vprocess_alist);
 
   DEFVAR_BOOL ("delete-exited-processes", &delete_exited_processes,
   staticpro (&Vprocess_alist);
 
   DEFVAR_BOOL ("delete-exited-processes", &delete_exited_processes,
@@ -3061,9 +3480,10 @@ nil means don't delete them until `list-processes' is run.");
 
   DEFVAR_LISP ("process-connection-type", &Vprocess_connection_type,
     "Control type of device used to communicate with subprocesses.\n\
 
   DEFVAR_LISP ("process-connection-type", &Vprocess_connection_type,
     "Control type of device used to communicate with subprocesses.\n\
-Values are nil to use a pipe, and t or 'pty for a pty.  Note that if\n\
-pty's are not available, this variable will be ignored. The value takes\n\
-effect when `start-process' is called.");
+Values are nil to use a pipe, or t or `pty' to use a pty.\n\
+The value has no effect if the system has no ptys or if all ptys are busy:\n\
+then a pipe is used in any case.\n\
+The value takes effect when `start-process' is called.");
   Vprocess_connection_type = Qt;
 
   defsubr (&Sprocessp);
   Vprocess_connection_type = Qt;
 
   defsubr (&Sprocessp);
@@ -3074,6 +3494,7 @@ effect when `start-process' is called.");
   defsubr (&Sprocess_exit_status);
   defsubr (&Sprocess_id);
   defsubr (&Sprocess_name);
   defsubr (&Sprocess_exit_status);
   defsubr (&Sprocess_id);
   defsubr (&Sprocess_name);
+  defsubr (&Sprocess_tty_name);
   defsubr (&Sprocess_command);
   defsubr (&Sset_process_buffer);
   defsubr (&Sprocess_buffer);
   defsubr (&Sprocess_command);
   defsubr (&Sset_process_buffer);
   defsubr (&Sprocess_buffer);
@@ -3081,6 +3502,7 @@ effect when `start-process' is called.");
   defsubr (&Sset_process_filter);
   defsubr (&Sprocess_filter);
   defsubr (&Sset_process_sentinel);
   defsubr (&Sset_process_filter);
   defsubr (&Sprocess_filter);
   defsubr (&Sset_process_sentinel);
+  defsubr (&Sset_process_window_size);
   defsubr (&Sprocess_sentinel);
   defsubr (&Sprocess_kill_without_query);
   defsubr (&Slist_processes);
   defsubr (&Sprocess_sentinel);
   defsubr (&Sprocess_kill_without_query);
   defsubr (&Slist_processes);
@@ -3134,7 +3556,7 @@ extern int frame_garbaged;
      `subprocesses' isn't defined.
 
    do_display != 0 means redisplay should be done to show subprocess
      `subprocesses' isn't defined.
 
    do_display != 0 means redisplay should be done to show subprocess
-   output that arrives.  This version of the function ignores it.
+   output that arrives.
 
    Return true iff we received input from any process.  */
 
 
    Return true iff we received input from any process.  */
 
@@ -3201,7 +3623,7 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
 
       /* If a frame has been newly mapped and needs updating,
         reprocess its display stuff.  */
 
       /* If a frame has been newly mapped and needs updating,
         reprocess its display stuff.  */
-      if (frame_garbaged)
+      if (frame_garbaged && do_display)
        redisplay_preserve_echo_area ();
 
       if (XINT (read_kbd) && detect_input_pending ())
        redisplay_preserve_echo_area ();
 
       if (XINT (read_kbd) && detect_input_pending ())
@@ -3245,7 +3667,7 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
 
 
 DEFUN ("get-buffer-process", Fget_buffer_process, Sget_buffer_process, 1, 1, 0,
 
 
 DEFUN ("get-buffer-process", Fget_buffer_process, Sget_buffer_process, 1, 1, 0,
-  /* Don't confused make-docfile by having two doc strings for this function.
+  /* Don't confuse make-docfile by having two doc strings for this function.
      make-docfile does not pay attention to #if, for good reason!  */
   0)
   (name)
      make-docfile does not pay attention to #if, for good reason!  */
   0)
   (name)