(wait_reading_process_input):
[bpt/emacs.git] / src / process.c
index 567c9c9..6dcb2f9 100644 (file)
@@ -1,5 +1,5 @@
 /* Asynchronous subprocess control for GNU Emacs.
-   Copyright (C) 1985, 1986, 1987, 1988, 1992, 1993 Free Software Foundation, Inc.
+   Copyright (C) 1985, 1986, 1987, 1988, 1993 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -20,7 +20,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 
 #include <signal.h>
 
-#include "config.h"
+#include <config.h>
 
 /* This file is split into two parts by the following preprocessor
    conditional.  The 'then' clause contains all of the support for
@@ -46,6 +46,20 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include <arpa/inet.h>
 #endif /* HAVE_SOCKETS */
 
+/* TERM is a poor-man's SLIP, used on Linux.  */
+#ifdef TERM
+#include <client.h>
+#endif
+
+/* DGUX inet_addr returns a 'struct in_addr'. */
+#ifdef DGUX
+#define IN_ADDR struct in_addr
+#define NUMERIC_ADDR_ERROR (numeric_addr.s_addr == -1)
+#else
+#define IN_ADDR unsigned long
+#define NUMERIC_ADDR_ERROR (numeric_addr == -1)
+#endif
+
 #if defined(BSD) || defined(STRIDE)
 #include <sys/ioctl.h>
 #if !defined (O_NDELAY) && defined (HAVE_PTYS) && !defined(USG5)
@@ -73,6 +87,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "commands.h"
 #include "frame.h"
 
+Lisp_Object Qprocessp;
 Lisp_Object Qrun, Qstop, Qsignal, Qopen, Qclosed;
 /* Qexit is declared and initialized in eval.c.  */
 
@@ -104,72 +119,7 @@ static Lisp_Object stream_process;
 
 #include "syssignal.h"
 
-/* Define the structure that the wait system call stores.
-   On many systems, there is a structure defined for this.
-   But on vanilla-ish USG systems there is not.  */
-
-#ifndef VMS
-#ifndef WAITTYPE
-#if !defined (BSD) && !defined (UNIPLUS) && !defined (STRIDE) && !(defined (HPUX) && !defined (NOMULTIPLEJOBS)) && !defined (HAVE_WAIT_HEADER)
-#define WAITTYPE int
-#define WIFSTOPPED(w) ((w&0377) == 0177)
-#define WIFSIGNALED(w) ((w&0377) != 0177 && (w&~0377) == 0)
-#define WIFEXITED(w) ((w&0377) == 0)
-#define WRETCODE(w) (w >> 8)
-#define WSTOPSIG(w) (w >> 8)
-#define WTERMSIG(w) (w & 0377)
-#ifndef WCOREDUMP
-#define WCOREDUMP(w) ((w&0200) != 0)
-#endif
-#else 
-#ifdef BSD4_1
-#include <wait.h>
-#else
-#include <sys/wait.h>
-#endif /* not BSD 4.1 */
-
-#define WAITTYPE union wait
-#define WRETCODE(w) w.w_retcode
-#define WCOREDUMP(w) w.w_coredump
-
-#ifdef HPUX
-/* HPUX version 7 has broken definitions of these.  */
-#undef WTERMSIG
-#undef WSTOPSIG
-#undef WIFSTOPPED
-#undef WIFSIGNALED
-#undef WIFEXITED
-#endif
-
-#ifndef WTERMSIG
-#define WTERMSIG(w) w.w_termsig
-#endif
-#ifndef WSTOPSIG
-#define WSTOPSIG(w) w.w_stopsig
-#endif
-#ifndef WIFSTOPPED
-#define WIFSTOPPED(w) (WTERMSIG (w) == 0177)
-#endif
-#ifndef WIFSIGNALED
-#define WIFSIGNALED(w) (WTERMSIG (w) != 0177 && (WSTOPSIG (w)) == 0)
-#endif
-#ifndef WIFEXITED
-#define WIFEXITED(w) (WTERMSIG (w) == 0)
-#endif
-#endif /* BSD or UNIPLUS or STRIDE */
-#endif /* no WAITTYPE */
-#else /* VMS */
-
-/* For the CMU PTY driver + */
-#define DCL_PROMPT "$ "
-/* This is a hack.  I have no idea what needs to go here, but this */
-/* will get it to compile.  We can fix it later.  rbr */
-#define WAITTYPE int
-#include <ssdef.h>
-#include <iodef.h>
-#include <clidef.h>
-#include "vmsproc.h"
-#endif /* VMS */
+#include "syswait.h"
 
 extern errno;
 extern sys_nerr;
@@ -177,7 +127,9 @@ extern char *sys_errlist[];
 
 #ifndef VMS
 #ifndef BSD4_1
+#ifndef LINUX
 extern char *sys_siglist[];
+#endif
 #else
 char *sys_siglist[] =
   {
@@ -213,7 +165,7 @@ char *sys_siglist[] =
 
 /* t means use pty, nil means use a pipe,
    maybe other values to come.  */
-Lisp_Object Vprocess_connection_type;
+static Lisp_Object Vprocess_connection_type;
 
 #ifdef SKTPAIR
 #ifndef HAVE_SOCKETS
@@ -222,16 +174,20 @@ Lisp_Object Vprocess_connection_type;
 #endif /* SKTPAIR */
 
 /* Number of events of change of status of a process.  */
-int process_tick;
+static int process_tick;
 
 /* Number of events for which the user or sentinel has been notified.  */
-int update_tick;
+static int update_tick;
 
 #ifdef FD_SET
 /* We could get this from param.h, but better not to depend on finding that.
    And better not to risk that it might define other symbols used in this
    file.  */
+#ifdef FD_SETSIZE
+#define MAXDESC FD_SETSIZE
+#else
 #define MAXDESC 64
+#endif
 #define SELECT_TYPE fd_set
 #else /* no FD_SET */
 #define MAXDESC 32
@@ -246,19 +202,19 @@ int update_tick;
 
 /* Mask of bits indicating the descriptors that we wait for input on */
 
-SELECT_TYPE input_wait_mask;
+static SELECT_TYPE input_wait_mask;
+
+/* Descriptor to use for keyboard input.  */
+static int keyboard_descriptor;
 
-int delete_exited_processes;
+/* 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 */
-Lisp_Object chan_process[MAXDESC];
+static Lisp_Object chan_process[MAXDESC];
 
 /* Alist of elements (NAME . PROCESS) */
-Lisp_Object Vprocess_alist;
-
-Lisp_Object Qprocessp;
-
-Lisp_Object get_process ();
+static Lisp_Object Vprocess_alist;
 
 /* Buffered-ahead input char from process, indexed by channel.
    -1 means empty (no char is buffered).
@@ -266,7 +222,9 @@ Lisp_Object get_process ();
    output from the process is to read at least one char.
    Always -1 on systems that support FIONREAD.  */
 
-int proc_buffered_char[MAXDESC];
+static int proc_buffered_char[MAXDESC];
+
+static Lisp_Object get_process ();
 \f
 /* Compute the Lisp form of the process status, p->status, from
    the numeric status that was returned by `wait'.  */
@@ -283,7 +241,7 @@ update_status (p)
   p->raw_status_high = Qnil;
 }
 
-/*  Convert a process status work in Unix format to 
+/*  Convert a process status word in Unix format to 
     the list that we use internally.  */
 
 Lisp_Object
@@ -357,7 +315,7 @@ status_message (status)
     {
       if (code == 0)
        return build_string ("finished\n");
-      string = Fint_to_string (make_number (code));
+      string = Fnumber_to_string (make_number (code));
       string2 = build_string (coredump ? " (core dumped)\n" : "\n");
       return concat2 (build_string ("exited abnormally with code "),
                      concat2 (string, string2));
@@ -442,7 +400,7 @@ allocate_pty ()
            if (access (pty_name, 6) != 0)
              {
                close (fd);
-#ifndef IRIS
+#if !defined(IRIS) && !defined(__sgi)
                continue;
 #else
                return -1;
@@ -477,8 +435,8 @@ make_process (name)
   XSETTYPE (val, Lisp_Process);
 
   p = XPROCESS (val);
-  XFASTINT (p->infd) = 0;
-  XFASTINT (p->outfd) = 0;
+  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;
@@ -560,7 +518,7 @@ BUFFER may be a buffer or the name of one.")
    Buffers denote the first process in the buffer, and nil denotes the
    current buffer.  */
 
-Lisp_Object
+static Lisp_Object
 get_process (name)
      register Lisp_Object name;
 {
@@ -599,7 +557,7 @@ nil, indicating the current buffer's process.")
       XPROCESS (proc)->status = Fcons (Qexit, Fcons (make_number (0), Qnil));
       XSETINT (XPROCESS (proc)->tick, ++process_tick);
     }
-  else if (XFASTINT (XPROCESS (proc)->infd))
+  else if (XINT (XPROCESS (proc)->infd >= 0))
     {
       Fkill_process (proc, Qnil);
       /* Do this now, since remove_process will make sigchld_handler do nothing.  */
@@ -623,14 +581,12 @@ closed -- for a network stream connection that is closed.\n\
 nil -- if arg is a process name and no such process exists.\n\
 PROCESS may be a process, a buffer, the name of a process or buffer, or\n\
 nil, indicating the current buffer's process.")
-/* command -- for a command channel opened to Emacs by another process.\n\
-   external -- for an i/o channel opened to Emacs by another process.\n\  */
   (proc)
      register Lisp_Object proc;
 {
   register struct Lisp_Process *p;
   register Lisp_Object status;
-  proc = get_process (proc);
+  proc = Fget_process (proc);
   if (NILP (proc))
     return proc;
   p = XPROCESS (proc);
@@ -736,6 +692,7 @@ DEFUN ("process-mark", Fprocess_mark, Sprocess_mark,
 DEFUN ("set-process-filter", Fset_process_filter, Sset_process_filter,
   2, 2, 0,
   "Give PROCESS the filter function FILTER; nil means no filter.\n\
+t means stop accepting output from the process.\n\
 When a process has a filter, each time it does output\n\
 the entire string of output is passed to the filter.\n\
 The filter gets two arguments: the process and the string of output.\n\
@@ -744,6 +701,10 @@ If the process has a filter, its buffer is not used for output.")
      register Lisp_Object proc, filter;
 {
   CHECK_PROCESS (proc, 0);
+  if (EQ (filter, Qt))
+    FD_CLR (XINT (XPROCESS (proc)->infd), &input_wait_mask);
+  else if (EQ (XPROCESS (proc)->filter, Qt))
+    FD_SET (XINT (XPROCESS (proc)->infd), &input_wait_mask);
   XPROCESS (proc)->filter = filter;
   return filter;
 }
@@ -799,6 +760,19 @@ Value is t if a query was formerly required.")
 
   return Fnull (tem);
 }
+
+#if 0 /* Turned off because we don't currently record this info
+        in the process.  Perhaps add it.  */
+DEFUN ("process-connection", Fprocess_connection, Sprocess_connection, 1, 1, 0,
+ "Return the connection type of `PROCESS'.\n\
+The value is `nil' for a pipe,\n\
+`t' or `pty' for a pty, or `stream' for a socket connection.")
+  (process)
+     Lisp_Object process;
+{
+  return XPROCESS (process)->type;
+}
+#endif
 \f
 Lisp_Object
 list_processes_1 ()
@@ -1032,7 +1006,7 @@ Remaining arguments are strings to give program as arguments.")
   if (new_argv[0][0] != '/')
     {
       tem = Qnil;
-      openp (Vexec_path, program, "", &tem, 1);
+      openp (Vexec_path, program, EXEC_SUFFIXES, &tem, 1);
       if (NILP (tem))
        report_file_error ("Searching for program", Fcons (program, Qnil));
       new_argv[0] = XSTRING (tem)->data;
@@ -1070,7 +1044,7 @@ start_process_unwind (proc)
     abort ();
 
   /* Was PROC started successfully?  */
-  if (XPROCESS (proc)->pid <= 0)
+  if (XINT (XPROCESS (proc)->pid) <= 0)
     remove_process (proc);
 
   return Qnil;
@@ -1192,8 +1166,8 @@ 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;
-  XFASTINT (XPROCESS (process)->infd) = inchannel;
-  XFASTINT (XPROCESS (process)->outfd) = outchannel;
+  XSET (XPROCESS (process)->infd, Lisp_Int, inchannel);
+  XSET (XPROCESS (process)->outfd, Lisp_Int, outchannel);
   /* Record the tty descriptor used in the subprocess.  */
   if (forkin < 0)
     XPROCESS (process)->subtty = Qnil;
@@ -1251,11 +1225,13 @@ create_process (process, new_argv, current_dir)
        setsid ();
 #ifdef TIOCSCTTY
        /* Make the pty's terminal the controlling terminal.  */
-       if (pty_flag && (ioctl (xforkin, TIOCSCTTY, 0) < 0))
-         abort ();
+       if (pty_flag)
+         /* We ignore the return value
+            because faith@cs.unc.edu says that is necessary on Linux.  */
+         ioctl (xforkin, TIOCSCTTY, 0);
 #endif
 #else /* not HAVE_SETSID */
-#ifdef USG
+#if defined (USG) && !defined (IRIX)
        /* It's very important to call setpgrp() here and no time
           afterwards.  Otherwise, we lose our controlling tty which
           is set when we open the pty. */
@@ -1413,7 +1389,7 @@ Fourth arg SERVICE is name of the service desired, or an integer\n\
   struct servent *svc_info;
   struct hostent *host_info_ptr, host_info;
   char *(addr_list[2]);
-  unsigned long numeric_addr;
+  IN_ADDR numeric_addr;
   int s, outch, inch;
   char errstring[80];
   int port;
@@ -1434,20 +1410,26 @@ Fourth arg SERVICE is name of the service desired, or an integer\n\
       port = svc_info->s_port;
     }
 
+#ifndef TERM
   host_info_ptr = gethostbyname (XSTRING (host)->data);
   if (host_info_ptr == 0)
     /* Attempt to interpret host as numeric inet address */
     {
-      numeric_addr = inet_addr (XSTRING (host)->data);
-      if (numeric_addr == -1)
+      numeric_addr = inet_addr ((char *) XSTRING (host)->data);
+      if (NUMERIC_ADDR_ERROR)
        error ("Unknown host \"%s\"", XSTRING (host)->data);
 
       host_info_ptr = &host_info;
       host_info.h_name = 0;
       host_info.h_aliases = 0;
       host_info.h_addrtype = AF_INET;
-      host_info.h_addr_list  =  &(addr_list[0]);
-      addr_list[0] = (char*)(&numeric_addr);
+#ifdef h_addr
+      /* Older machines have only one address slot called h_addr.
+        Newer machines have h_addr_list, but #define h_addr to
+        be its first element.  */
+      host_info.h_addr_list = &(addr_list[0]);
+#endif
+      host_info.h_addr = (char*)(&numeric_addr);
       addr_list[1] = 0;
       host_info.h_length = strlen (addr_list[0]);
     }
@@ -1463,7 +1445,7 @@ Fourth arg SERVICE is name of the service desired, or an integer\n\
     report_file_error ("error creating socket", Fcons (name, Qnil));
 
  loop:
-  if (connect (s, &address, sizeof address) == -1)
+  if (connect (s, (struct sockaddr *) &address, sizeof address) == -1)
     {
       int xerrno = errno;
       if (errno == EINTR)
@@ -1473,6 +1455,13 @@ Fourth arg SERVICE is name of the service desired, or an integer\n\
       report_file_error ("connection failed",
                         Fcons (host, Fcons (name, Qnil)));
     }
+#else /* TERM */
+  s = connect_server (0);
+  if (s < 0)
+    report_file_error ("error creating socket", Fcons (name, Qnil));
+  send_command (s, C_PORT, 0, "%s:%d", XSTRING (host)->data, ntohs (port));
+  send_command (s, C_DUMB, 1, 0);
+#endif /* TERM */
 
   inch = s;
   outch = dup (s);
@@ -1500,8 +1489,8 @@ 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;
-  XFASTINT (XPROCESS (proc)->infd) = s;
-  XFASTINT (XPROCESS (proc)->outfd) = outch;
+  XSET (XPROCESS (proc)->infd, Lisp_Int, s);
+  XSET (XPROCESS (proc)->outfd, Lisp_Int, outch);
   XPROCESS (proc)->status = Qrun;
   FD_SET (inch, &input_wait_mask);
 
@@ -1516,10 +1505,10 @@ deactivate_process (proc)
   register int inchannel, outchannel;
   register struct Lisp_Process *p = XPROCESS (proc);
 
-  inchannel = XFASTINT (p->infd);
-  outchannel = XFASTINT (p->outfd);
+  inchannel = XINT (p->infd);
+  outchannel = XINT (p->outfd);
 
-  if (inchannel)
+  if (inchannel >= 0)
     {
       /* Beware SIGCHLD hereabouts. */
       flush_pending_output (inchannel);
@@ -1527,18 +1516,18 @@ deactivate_process (proc)
       {
        VMS_PROC_STUFF *get_vms_process_pointer (), *vs;
        sys$dassgn (outchannel);
-       vs = get_vms_process_pointer (p->pid)
+       vs = get_vms_process_pointer (p->pid);
        if (vs)
          give_back_vms_process_stuff (vs);
       }
 #else
       close (inchannel);
-      if (outchannel && outchannel != inchannel)
+      if (outchannel >= 0 && outchannel != inchannel)
        close (outchannel);
 #endif
 
-      XFASTINT (p->infd) = 0;
-      XFASTINT (p->outfd) = 0;
+      XSET (p->infd, Lisp_Int, -1);
+      XSET (p->outfd, Lisp_Int, -1);
       chan_process[inchannel] = Qnil;
       FD_CLR (inchannel, &input_wait_mask);
     }
@@ -1557,11 +1546,11 @@ close_process_descs ()
       process = chan_process[i];
       if (!NILP (process))
        {
-         int in = XFASTINT (XPROCESS (process)->infd);
-         int out = XFASTINT (XPROCESS (process)->outfd);
-         if (in)
+         int in = XINT (XPROCESS (process)->infd);
+         int out = XINT (XPROCESS (process)->outfd);
+         if (in >= 0)
            close (in);
-         if (out && in != out)
+         if (out >= 0 && in != out)
            close (out);
        }
     }
@@ -1643,28 +1632,34 @@ static int waiting_for_user_input_p;
 /* Read and dispose of subprocess output while waiting for timeout to
    elapse and/or keyboard input to be available.
 
-   time_limit is:
+   TIME_LIMIT is:
      timeout in seconds, or
      zero for no limit, or
      -1 means gobble data immediately available but don't wait for any.
 
-   read_kbd is a lisp value:
+   MICROSECS is:
+     an additional duration to wait, measured in microseconds.
+     If this is nonzero and time_limit is 0, then the timeout
+     consists of MICROSECS only.
+
+   READ_KBD is a lisp value:
      0 to ignore keyboard input, 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, or
+     a cons cell, meaning wait 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
        that process.
 
-   do_display != 0 means redisplay should be done to show subprocess
+   DO_DISPLAY != 0 means redisplay should be done to show subprocess
    output that arrives.
 
-   If read_kbd is a pointer to a struct Lisp_Process, then the
+   If READ_KBD is a pointer to a struct Lisp_Process, then the
      function returns true iff we received input from that process
      before the timeout elapsed.
-   Otherwise, return true iff we recieved input from any process.  */
+   Otherwise, return true iff we received input from any process.  */
 
 wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
      int time_limit, microsecs;
@@ -1677,7 +1672,7 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
   Lisp_Object proc;
   EMACS_TIME timeout, end_time, garbage;
   SELECT_TYPE Atemp;
-  int wait_channel = 0;
+  int wait_channel = -1;
   struct Lisp_Process *wait_proc = 0;
   int got_some_input = 0;
   Lisp_Object *wait_for_cell = 0;
@@ -1689,7 +1684,7 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
   if (XTYPE (read_kbd) == Lisp_Process)
     {
       wait_proc = XPROCESS (read_kbd);
-      wait_channel = XFASTINT (wait_proc->infd);
+      wait_channel = XINT (wait_proc->infd);
       XFASTINT (read_kbd) = 0;
     }
 
@@ -1719,6 +1714,10 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
       if (XINT (read_kbd) >= 0)
        QUIT;
 
+      /* Exit now if the cell we're waiting for became non-nil.  */
+      if (wait_for_cell && ! NILP (*wait_for_cell))
+       break;
+
       /* Compute time from now till when time limit is up */
       /* Exit if already run out */
       if (time_limit == -1)
@@ -1759,7 +1758,12 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
          Atemp = input_wait_mask;
          EMACS_SET_SECS_USECS (timeout, 0, 0);
          if (select (MAXDESC, &Atemp, 0, 0, &timeout) <= 0)
-           status_notify ();
+           {
+             /* It's okay for us to do this and then continue with
+                the loop, since timeout has already been zeroed out. */
+             clear_waiting_for_input ();
+             status_notify ();
+           }
        }
 
       /* Don't wait for output from a non-running process.  */
@@ -1767,13 +1771,19 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
        update_status (wait_proc);
       if (wait_proc != 0
          && ! EQ (wait_proc->status, Qrun))
-       break;
+       {
+         clear_waiting_for_input ();
+         break;
+       }
 
       /* 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 (0, &Available);
+       FD_CLR (keyboard_descriptor, &Available);
 
       /* If frame size has changed or the window is newly mapped,
         redisplay now, before we start to wait.  There is a race
@@ -1784,7 +1794,10 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
        redisplay_preserve_echo_area ();
 
       if (XINT (read_kbd) && detect_input_pending ())
-       nfds = 0;
+       {
+         nfds = 0;
+         FD_ZERO (&Available);
+       }
       else
        nfds = select (MAXDESC, &Available, 0, 0, &timeout);
 
@@ -1835,9 +1848,16 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
          else
            error("select error: %s", sys_errlist[xerrno]);
        }
-#ifdef sun
-      else if (nfds > 0 && FD_ISSET (0, &Available) && interrupt_input)
-       /* System sometimes fails to deliver SIGIO.  */
+#if defined(sun) && !defined(USG5_4)
+      else if (nfds > 0 && FD_ISSET (keyboard_descriptor, &Available)
+              && interrupt_input)
+       /* System sometimes fails to deliver SIGIO.
+
+          David J. Mackenzie says that Emacs doesn't compile under
+          Solaris if this code is enabled, thus the USG5_4 in the CPP
+          conditional.  "I haven't noticed any ill effects so far.
+          If you find a Solaris expert somewhere, they might know
+          better." */
        kill (getpid (), SIGIO);
 #endif
 
@@ -1845,8 +1865,15 @@ 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 (XINT (read_kbd) && detect_input_pending ())
-       break;
+      /* We used to do his if wait_for_cell,
+        but that caused infinite recursion in selection request events.  */
+      if ((XINT (read_kbd))
+         && detect_input_pending ())
+       {
+         swallow_events ();
+         if (detect_input_pending ())
+           break;
+       }
 
       /* Exit now if the cell we're waiting for became non-nil.  */
       if (wait_for_cell && ! NILP (*wait_for_cell))
@@ -1858,7 +1885,8 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
         In that case, there really is no input and no SIGIO,
         but select says there is input.  */
 
-      if (XINT (read_kbd) && interrupt_input && (FD_ISSET (fileno (stdin), &Available)))
+      if (XINT (read_kbd) && interrupt_input
+         && (FD_ISSET (keyboard_descriptor, &Available)))
        kill (0, SIGIO);
 #endif
 
@@ -1867,11 +1895,14 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
 
       /* If checking input just got us a size-change event from X,
         obey it now if we should.  */
-      if (XINT (read_kbd))
+      if (XINT (read_kbd) || wait_for_cell)
        do_pending_window_change ();
 
-      /* Check for data from a process or a command channel */
-      for (channel = FIRST_PROC_DESC; channel < MAXDESC; channel++)
+      /* 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++)
        {
          if (FD_ISSET (channel, &Available))
            {
@@ -1882,7 +1913,7 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
                 waiting.  */
              if (wait_channel == channel)
                {
-                 wait_channel = 0;
+                 wait_channel = -1;
                  time_limit = -1;
                  got_some_input = 1;
                }
@@ -2038,9 +2069,16 @@ read_process_output (proc, channel)
         hitting ^G when a filter happens to be running won't screw
         it up.  */
       int count = specpdl_ptr - specpdl;
+      Lisp_Object odeactivate;
+
+      odeactivate = Vdeactivate_mark;
+
       specbind (Qinhibit_quit, Qt);
       call2 (outstream, proc, make_string (chars, nchars));
 
+      /* Handling the process output should not deactivate the mark.  */
+      Vdeactivate_mark = odeactivate;
+
 #ifdef VMS
       start_vms_process_read (vs);
 #endif
@@ -2053,6 +2091,9 @@ read_process_output (proc, channel)
     {
       Lisp_Object old_read_only;
       Lisp_Object old_begv, old_zv;
+      Lisp_Object odeactivate;
+
+      odeactivate = Vdeactivate_mark;
 
       Fset_buffer (p->buffer);
       opoint = point;
@@ -2097,6 +2138,9 @@ read_process_output (proc, channel)
       if (XFASTINT (old_begv) != BEGV || XFASTINT (old_zv) != ZV)
        Fnarrow_to_region (old_begv, old_zv);
 
+      /* Handling the process output should not deactivate the mark.  */
+      Vdeactivate_mark = odeactivate;
+
       current_buffer->read_only = old_read_only;
       SET_PT (opoint);
       set_buffer_internal (old);
@@ -2167,7 +2211,7 @@ send_process (proc, buf, len)
        if (this > 500)
          this = 500;
        old_sigpipe = (SIGTYPE (*) ()) signal (SIGPIPE, send_process_trap);
-       rv = write (XFASTINT (XPROCESS (proc)->outfd), buf, this);
+       rv = write (XINT (XPROCESS (proc)->outfd), buf, this);
        signal (SIGPIPE, old_sigpipe);
        if (rv < 0)
          {
@@ -2293,7 +2337,7 @@ process_send_signal (process, signo, current_group, nomsg)
   if (!EQ (p->childp, Qt))
     error ("Process %s is not a subprocess",
           XSTRING (p->name)->data);
-  if (!XFASTINT (p->infd))
+  if (XINT (p->infd) < 0)
     error ("Process %s is not active",
           XSTRING (p->name)->data);
 
@@ -2315,17 +2359,17 @@ process_send_signal (process, signo, current_group, nomsg)
       switch (signo)
        {
        case SIGINT:
-         tcgetattr (XFASTINT (p->infd), &t);
+         tcgetattr (XINT (p->infd), &t);
          send_process (proc, &t.c_cc[VINTR], 1);
          return;
 
        case SIGQUIT:
-         tcgetattr (XFASTINT (p->infd), &t);
+         tcgetattr (XINT (p->infd), &t);
          send_process (proc, &t.c_cc[VQUIT], 1);
          return;
 
        case SIGTSTP:
-         tcgetattr (XFASTINT (p->infd), &t);
+         tcgetattr (XINT (p->infd), &t);
 #ifdef VSWTCH
          send_process (proc, &t.c_cc[VSWTCH], 1);
 #else
@@ -2346,16 +2390,16 @@ process_send_signal (process, signo, current_group, nomsg)
       switch (signo)
        {
        case SIGINT:
-         ioctl (XFASTINT (p->infd), TIOCGETC, &c);
+         ioctl (XINT (p->infd), TIOCGETC, &c);
          send_process (proc, &c.t_intrc, 1);
          return;
        case SIGQUIT:
-         ioctl (XFASTINT (p->infd), TIOCGETC, &c);
+         ioctl (XINT (p->infd), TIOCGETC, &c);
          send_process (proc, &c.t_quitc, 1);
          return;
 #ifdef SIGTSTP
        case SIGTSTP:
-         ioctl (XFASTINT (p->infd), TIOCGLTC, &lc);
+         ioctl (XINT (p->infd), TIOCGLTC, &lc);
          send_process (proc, &lc.t_suspc, 1);
          return;
 #endif /* ! defined (SIGTSTP) */
@@ -2370,16 +2414,16 @@ process_send_signal (process, signo, current_group, nomsg)
       switch (signo)
        {
        case SIGINT:
-         ioctl (XFASTINT (p->infd), TCGETA, &t);
+         ioctl (XINT (p->infd), TCGETA, &t);
          send_process (proc, &t.c_cc[VINTR], 1);
          return;
        case SIGQUIT:
-         ioctl (XFASTINT (p->infd), TCGETA, &t);
+         ioctl (XINT (p->infd), TCGETA, &t);
          send_process (proc, &t.c_cc[VQUIT], 1);
          return;
 #ifdef SIGTSTP
        case SIGTSTP:
-         ioctl (XFASTINT (p->infd), TCGETA, &t);
+         ioctl (XINT (p->infd), TCGETA, &t);
          send_process (proc, &t.c_cc[VSWTCH], 1);
          return;
 #endif /* ! defined (SIGTSTP) */
@@ -2407,7 +2451,7 @@ process_send_signal (process, signo, current_group, nomsg)
        if (!NILP (p->subtty))
          err = ioctl (XFASTINT (p->subtty), TIOCGPGRP, &gid);
        else
-         err = ioctl (XFASTINT (p->infd), TIOCGPGRP, &gid);
+         err = ioctl (XINT (p->infd), TIOCGPGRP, &gid);
 
 #ifdef pfa
        if (err == -1)
@@ -2454,7 +2498,7 @@ process_send_signal (process, signo, current_group, nomsg)
       sys$forcex (&(XFASTINT (p->pid)), 0, 1);
       whoosh:
 #endif
-      flush_pending_output (XFASTINT (p->infd));
+      flush_pending_output (XINT (p->infd));
       break;
     }
 
@@ -2470,7 +2514,7 @@ process_send_signal (process, signo, current_group, nomsg)
   /* gid may be a pid, or minus a pgrp's number */
 #ifdef TIOCSIGSEND
   if (!NILP (current_group))
-    ioctl (XFASTINT (p->infd), TIOCSIGSEND, signo);
+    ioctl (XINT (p->infd), TIOCSIGSEND, signo);
   else
     {
       gid = - XFASTINT (p->pid);
@@ -2580,7 +2624,7 @@ nil, indicating the current buffer's process.")
 #ifdef DID_REMOTE
   {
     char buf[1];
-    write (XFASTINT (XPROCESS (proc)->outfd), buf, 0);
+    write (XINT (XPROCESS (proc)->outfd), buf, 0);
   }
 #else /* did not do TOICREMOTE */
 #ifdef VMS
@@ -2590,8 +2634,8 @@ nil, indicating the current buffer's process.")
     send_process (proc, "\004", 1);
   else
     {
-      close (XPROCESS (proc)->outfd);
-      XFASTINT (XPROCESS (proc)->outfd) = open ("/dev/null", O_WRONLY);
+      close (XINT (XPROCESS (proc)->outfd));
+      XSET (XPROCESS (proc)->outfd, Lisp_Int, open (NULL_DEVICE, O_WRONLY));
     }
 #endif /* VMS */
 #endif /* did not do TOICREMOTE */
@@ -2615,7 +2659,7 @@ kill_buffer_processes (buffer)
        {
          if (NETCONN_P (proc))
            deactivate_process (proc);
-         else if (XFASTINT (XPROCESS (proc)->infd))
+         else if (XINT (XPROCESS (proc)->infd) >= 0)
            process_send_signal (proc, SIGHUP, Qnil, 1);
        }
     }
@@ -2730,8 +2774,8 @@ sigchld_handler (signo)
          
          /* If process has terminated, stop waiting for its output.  */
          if (WIFSIGNALED (w) || WIFEXITED (w))
-           if (XFASTINT (p->infd))
-             FD_CLR (XFASTINT (p->infd), &input_wait_mask);
+           if (XINT (p->infd) >= 0)
+             FD_CLR (XINT (p->infd), &input_wait_mask);
 
          /* Tell wait_reading_process_input that it needs to wake up and
             look around.  */
@@ -2750,7 +2794,7 @@ sigchld_handler (signo)
            synch_process_retcode = WRETCODE (w);
          else if (WIFSIGNALED (w))
 #ifndef VMS
-           synch_process_death = sys_siglist[WTERMSIG (w)];
+           synch_process_death = (char *) sys_siglist[WTERMSIG (w)];
 #else
            synch_process_death = sys_errlist[WTERMSIG (w)];
 #endif
@@ -2837,8 +2881,9 @@ status_notify ()
          XSETINT (p->update_tick, XINT (p->tick));
 
          /* If process is still active, read any output that remains.  */
-         if (XFASTINT (p->infd))
-           while (read_process_output (proc, XFASTINT (p->infd)) > 0);
+         if (XINT (p->infd) >= 0)
+           while (! EQ (p->filter, Qt)
+                  && read_process_output (proc, XINT (p->infd)) > 0);
 
          buffer = p->buffer;
 
@@ -2924,7 +2969,10 @@ init_process ()
 #endif
 
   FD_ZERO (&input_wait_mask);
-  FD_SET (0, &input_wait_mask);
+
+  keyboard_descriptor = 0;
+  FD_SET (keyboard_descriptor, &input_wait_mask);
+
   Vprocess_alist = Qnil;
   for (i = 0; i < MAXDESC; i++)
     {
@@ -2932,16 +2980,18 @@ init_process ()
       proc_buffered_char[i] = -1;
     }
 }
-#if 0
-DEFUN ("process-connection", Fprocess_connection, Sprocess_connection, 0, 1, 0,
- "Return the connection type of `PROCESS'.  This can be nil (pipe),\n\
-t or pty (pty) or stream (socket connection).")
-  (process)
-     Lisp_Object process;
+
+/* From now on, assume keyboard input comes from descriptor DESC.  */
+
+void
+change_keyboard_wait_descriptor (desc)
+     int desc;
 {
-  return XPROCESS (process)->type;
+  FD_CLR (keyboard_descriptor, &input_wait_mask);
+  keyboard_descriptor = desc;
+  FD_SET (keyboard_descriptor, &input_wait_mask);
 }
-#endif
+
 syms_of_process ()
 {
 #ifdef HAVE_SOCKETS
@@ -3052,7 +3102,7 @@ extern int frame_garbaged;
    do_display != 0 means redisplay should be done to show subprocess
    output that arrives.  This version of the function ignores it.
 
-   Return true iff we recieved input from any process.  */
+   Return true iff we received input from any process.  */
 
 int
 wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
@@ -3140,8 +3190,10 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
        /* System sometimes fails to deliver SIGIO.  */
        kill (getpid (), SIGIO);
 #endif
+#ifdef SIGIO
       if (XINT (read_kbd) && interrupt_input && (waitchannels & 1))
        kill (0, SIGIO);
+#endif
 
       /* If we have timed out (nfds == 0) or found some input (nfds > 0),
         we should exit.  */
@@ -3156,9 +3208,9 @@ wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
 
 
 DEFUN ("get-buffer-process", Fget_buffer_process, Sget_buffer_process, 1, 1, 0,
-  "Return the (or, a) process associated with BUFFER.\n\
-This copy of Emacs has not been built to support subprocesses, so this\n\
-function always returns nil.")
+  /* Don't confused make-docfile by having two doc strings for this function.
+     make-docfile does not pay attention to #if, for good reason!  */
+  0)
   (name)
      register Lisp_Object name;
 {