(U-0002195D): Add `ideographic-structure'; add `sound@ja/on'; add
[chise/xemacs-chise.git.1] / src / process.c
index a9a9131..127fc17 100644 (file)
@@ -1,5 +1,5 @@
 /* Asynchronous subprocess control for XEmacs.
-   Copyright (C) 1985, 1986, 1987, 1988, 1992, 1993, 1994, 1995
+   Copyright (C) 1985, 1986, 1987, 1988, 1992, 1993, 1994, 1995, 2003
    Free Software Foundation, Inc.
    Copyright (C) 1995 Sun Microsystems, Inc.
    Copyright (C) 1995, 1996 Ben Wing.
@@ -58,7 +58,7 @@ Boston, MA 02111-1307, USA.  */
 #include "systty.h"
 #include "syswait.h"
 
-Lisp_Object Qprocessp;
+Lisp_Object Qprocessp, Qprocess_live_p, Qprocess_readable_p;
 
 /* Process methods */
 struct process_methods the_process_methods;
@@ -71,7 +71,7 @@ Lisp_Object Qrun, Qstop;
 /* Qrun => Qopen, Qexit => Qclosed for "network connection" processes */
 Lisp_Object Qopen, Qclosed;
 /* Protocol families */
-Lisp_Object Qtcpip;
+Lisp_Object Qtcp, Qudp;
 
 #ifdef HAVE_MULTICAST
 Lisp_Object Qmulticast; /* Will be used for occasional warnings */
@@ -106,59 +106,62 @@ struct hash_table *usid_to_process;
 /* List of process objects. */
 Lisp_Object Vprocess_list;
 
+extern Lisp_Object Vlisp_EXEC_SUFFIXES;
+Lisp_Object Vnull_device;
+
 \f
 
 static Lisp_Object
-mark_process (Lisp_Object obj, void (*markobj) (Lisp_Object))
-{
-  struct Lisp_Process *proc = XPROCESS (obj);
-  MAYBE_PROCMETH (mark_process_data, (proc, markobj));
-  markobj (proc->name);
-  markobj (proc->command);
-  markobj (proc->filter);
-  markobj (proc->sentinel);
-  markobj (proc->buffer);
-  markobj (proc->mark);
-  markobj (proc->pid);
-  markobj (proc->pipe_instream);
-  markobj (proc->pipe_outstream);
+mark_process (Lisp_Object object)
+{
+  Lisp_Process *process = XPROCESS (object);
+  MAYBE_PROCMETH (mark_process_data, (process));
+  mark_object (process->name);
+  mark_object (process->command);
+  mark_object (process->filter);
+  mark_object (process->sentinel);
+  mark_object (process->buffer);
+  mark_object (process->mark);
+  mark_object (process->pid);
+  mark_object (process->pipe_instream);
+  mark_object (process->pipe_outstream);
 #ifdef FILE_CODING
-  markobj (proc->coding_instream);
-  markobj (proc->coding_outstream);
+  mark_object (process->coding_instream);
+  mark_object (process->coding_outstream);
 #endif
-  return proc->status_symbol;
+  return process->status_symbol;
 }
 
 static void
-print_process (Lisp_Object obj, Lisp_Object printcharfun, int escapeflag)
+print_process (Lisp_Object object, Lisp_Object printcharfun, int escapeflag)
 {
-  struct Lisp_Process *proc = XPROCESS (obj);
+  Lisp_Process *process = XPROCESS (object);
 
   if (print_readably)
     error ("printing unreadable object #<process %s>",
-           XSTRING_DATA (proc->name));
+           XSTRING_DATA (process->name));
 
   if (!escapeflag)
     {
-      print_internal (proc->name, printcharfun, 0);
+      print_internal (process->name, printcharfun, 0);
     }
   else
     {
-      int netp = network_connection_p (obj);
-      write_c_string (((netp) ? GETTEXT ("#<network connection ") :
+      int netp = network_connection_p (object);
+      write_c_string ((netp ? GETTEXT ("#<network connection ") :
                       GETTEXT ("#<process ")), printcharfun);
-      print_internal (proc->name, printcharfun, 1);
-      write_c_string (((netp) ? " " : " pid "), printcharfun);
-      print_internal (proc->pid, printcharfun, 1);
+      print_internal (process->name, printcharfun, 1);
+      write_c_string ((netp ? " " : " pid "), printcharfun);
+      print_internal (process->pid, printcharfun, 1);
       write_c_string (" state:", printcharfun);
-      print_internal (proc->status_symbol, printcharfun, 1);
-      MAYBE_PROCMETH (print_process_data, (proc, printcharfun));
+      print_internal (process->status_symbol, printcharfun, 1);
+      MAYBE_PROCMETH (print_process_data, (process, printcharfun));
       write_c_string (">", printcharfun);
     }
 }
 
 #ifdef HAVE_WINDOW_SYSTEM
-extern void debug_process_finalization (struct Lisp_Process *p);
+extern void debug_process_finalization (Lisp_Process *p);
 #endif /* HAVE_WINDOW_SYSTEM */
 
 static void
@@ -166,7 +169,7 @@ finalize_process (void *header, int for_disksave)
 {
   /* #### this probably needs to be tied into the tty event loop */
   /* #### when there is one */
-  struct Lisp_Process *p = (struct Lisp_Process *) header;
+  Lisp_Process *p = (Lisp_Process *) header;
 #ifdef HAVE_WINDOW_SYSTEM
   if (!for_disksave)
     {
@@ -184,7 +187,7 @@ finalize_process (void *header, int for_disksave)
 
 DEFINE_LRECORD_IMPLEMENTATION ("process", process,
                                mark_process, print_process, finalize_process,
-                               0, 0, struct Lisp_Process);
+                               0, 0, 0, Lisp_Process);
 \f
 /************************************************************************/
 /*                       basic process accessors                        */
@@ -194,8 +197,7 @@ DEFINE_LRECORD_IMPLEMENTATION ("process", process,
    directly to the child process, rather than en/decoding FILE_CODING
    streams */
 void
-get_process_streams (struct Lisp_Process *p,
-                    Lisp_Object *instr, Lisp_Object *outstr)
+get_process_streams (Lisp_Process *p, Lisp_Object *instr, Lisp_Object *outstr)
 {
   assert (p);
   assert (NILP (p->pipe_instream) || LSTREAMP(p->pipe_instream));
@@ -204,37 +206,37 @@ get_process_streams (struct Lisp_Process *p,
   *outstr = p->pipe_outstream;
 }
 
-struct Lisp_Process *
+Lisp_Process *
 get_process_from_usid (USID usid)
 {
-  CONST void *vval;
+  const void *vval;
 
   assert (usid != USID_ERROR && usid != USID_DONTHASH);
 
-  if (gethash ((CONST void*)usid, usid_to_process, &vval))
+  if (gethash ((const void*)usid, usid_to_process, &vval))
     {
-      Lisp_Object proc;
-      CVOID_TO_LISP (proc, vval);
-      return XPROCESS (proc);
+      Lisp_Object process;
+      CVOID_TO_LISP (process, vval);
+      return XPROCESS (process);
     }
   else
     return 0;
 }
 
 int
-get_process_selected_p (struct Lisp_Process *p)
+get_process_selected_p (Lisp_Process *p)
 {
   return p->selected;
 }
 
 void
-set_process_selected_p (struct Lisp_Process *p, int selected_p)
+set_process_selected_p (Lisp_Process *p, int selected_p)
 {
   p->selected = !!selected_p;
 }
 
 int
-connected_via_filedesc_p (struct Lisp_Process *p)
+connected_via_filedesc_p (Lisp_Process *p)
 {
   return MAYBE_INT_PROCMETH (tooltalk_connection_p, (p));
 }
@@ -243,18 +245,50 @@ connected_via_filedesc_p (struct Lisp_Process *p)
 int
 network_connection_p (Lisp_Object process)
 {
-  return GC_CONSP (XPROCESS (process)->pid);
+  return CONSP (XPROCESS (process)->pid);
 }
 #endif
 
 DEFUN ("processp", Fprocessp, 1, 1, 0, /*
 Return t if OBJECT is a process.
 */
-       (obj))
+       (object))
+{
+  return PROCESSP (object) ? Qt : Qnil;
+}
+
+DEFUN ("process-live-p", Fprocess_live_p, 1, 1, 0, /*
+Return t if OBJECT is a process that is alive.
+*/
+       (object))
 {
-  return PROCESSP (obj) ? Qt : Qnil;
+  return PROCESSP (object) && PROCESS_LIVE_P (XPROCESS (object))
+    ? Qt : Qnil;
 }
 
+#if 0
+/* This is a reasonable definition for this new primitive.  Kyle sez:
+
+   "The patch looks OK to me except for the creation and exporting of the
+   Fprocess_readable_p function.  I don't think a new Lisp function
+   should be created until we know something actually needs it.  If
+   we later want to give process-readable-p different semantics it
+   may be hard to do it and stay compatible with what we hastily
+   create today."
+
+   He's right, not yet.  Let's discuss the semantics on XEmacs Design
+   before enabling this.
+*/
+DEFUN ("process-readable-p", Fprocess_readable_p, 1, 1, 0, /*
+Return t if OBJECT is a process from which input may be available.
+*/
+       (object))
+{
+  return PROCESSP (object) && PROCESS_READABLE_P (XPROCESS (object))
+    ? Qt : Qnil;
+}
+#endif
+
 DEFUN ("process-list", Fprocess_list, 0, 0, 0, /*
 Return a list of all processes.
 */
@@ -264,27 +298,24 @@ Return a list of all processes.
 }
 
 DEFUN ("get-process", Fget_process, 1, 1, 0, /*
-Return the process named NAME, or nil if there is none.
+Return the process named PROCESS-NAME (a string), or nil if there is none.
+PROCESS-NAME may also be a process; if so, the value is that process.
 */
-       (name))
+       (process_name))
 {
-  Lisp_Object tail;
-
-  if (GC_PROCESSP (name))
-    return name;
+  if (PROCESSP (process_name))
+    return process_name;
 
   if (!gc_in_progress)
     /* this only gets called during GC when emacs is going away as a result
        of a signal or crash. */
-    CHECK_STRING (name);
+    CHECK_STRING (process_name);
 
-  for (tail = Vprocess_list; GC_CONSP (tail); tail = XCDR (tail))
-    {
-      Lisp_Object proc = XCAR (tail);
-      QUIT;
-      if (internal_equal (name, XPROCESS (proc)->name, 0))
-        return XCAR (tail);
-    }
+  {
+    LIST_LOOP_2 (process, Vprocess_list)
+      if (internal_equal (process_name, XPROCESS (process)->name, 0))
+        return process;
+  }
   return Qnil;
 }
 
@@ -292,24 +323,17 @@ DEFUN ("get-buffer-process", Fget_buffer_process, 1, 1, 0, /*
 Return the (or, a) process associated with BUFFER.
 BUFFER may be a buffer or the name of one.
 */
-       (name))
+       (buffer))
 {
-  Lisp_Object buf, tail, proc;
+  if (NILP (buffer)) return Qnil;
+  buffer = Fget_buffer (buffer);
+  if (NILP (buffer)) return Qnil;
 
-  if (GC_NILP (name)) return Qnil;
-  buf = Fget_buffer (name);
-  if (GC_NILP (buf)) return Qnil;
-
-  for (tail = Vprocess_list; GC_CONSP (tail); tail = XCDR (tail))
-    {
-      /* jwz: do not quit here - it isn't necessary, as there is no way for
-        Vprocess_list to get circular or overwhelmingly long, and this
-        function is called from layout_mode_element under redisplay. */
-      /* QUIT; */
-      proc = XCAR (tail);
-      if (GC_PROCESSP (proc) && EQ (XPROCESS (proc)->buffer, buf))
-       return proc;
-    }
+  {
+    LIST_LOOP_2 (process, Vprocess_list)
+      if (EQ (XPROCESS (process)->buffer, buffer))
+        return process;
+  }
   return Qnil;
 }
 
@@ -321,46 +345,50 @@ BUFFER may be a buffer or the name of one.
 static Lisp_Object
 get_process (Lisp_Object name)
 {
-  Lisp_Object proc, obj;
+  Lisp_Object buffer;
 
 #ifdef I18N3
   /* #### Look more closely into translating process names. */
 #endif
 
   /* This may be called during a GC from process_send_signal() from
-     kill_buffer_processes() if emacs decides to abort(). */
-  if (GC_PROCESSP (name))
+     kill_buffer_processes() if emacs decides to ABORT(). */
+  if (PROCESSP (name))
     return name;
-
-  if (GC_STRINGP (name))
+  else if (STRINGP (name))
     {
-      obj = Fget_process (name);
-      if (GC_NILP (obj))
-        obj = Fget_buffer (name);
-      if (GC_NILP (obj))
-        error ("Process %s does not exist", XSTRING_DATA (name));
-    }
-  else if (GC_NILP (name))
-    obj = Fcurrent_buffer ();
-  else
-    obj = name;
+      Lisp_Object object = Fget_process (name);
+      if (PROCESSP (object))
+       return object;
+
+      buffer = Fget_buffer (name);
+      if (BUFFERP (buffer))
+       goto have_buffer_object;
 
-  /* Now obj should be either a buffer object or a process object.
-   */
-  if (GC_BUFFERP (obj))
+      error ("Process %s does not exist", XSTRING_DATA (name));
+    }
+  else if (NILP (name))
     {
-      proc = Fget_buffer_process (obj);
-      if (GC_NILP (proc))
-       error ("Buffer %s has no process", XSTRING_DATA (XBUFFER(obj)->name));
+      buffer = Fcurrent_buffer ();
+      goto have_buffer_object;
     }
-  else
+  else if (BUFFERP (name))
     {
-      /* #### This was commented out. Although, simple
-        (kill-process 7 "qqq") resulted in a fatal error. - kkm */
-      CHECK_PROCESS (obj);
-      proc = obj;
+      Lisp_Object process;
+      buffer = name;
+
+    have_buffer_object:
+      process = Fget_buffer_process (buffer);
+      if (PROCESSP (process))
+       return process;
+
+      error ("Buffer %s has no process",
+            XSTRING_DATA (XBUFFER (buffer)->name));
     }
-  return proc;
+  else
+    return get_process (Fsignal (Qwrong_type_argument,
+                                (list2 (build_string ("process or buffer or nil"),
+                                name))));
 }
 
 DEFUN ("process-id", Fprocess_id, 1, 1, 0, /*
@@ -369,13 +397,13 @@ This is the pid of the Unix process which PROCESS uses or talks to.
 For a network connection, this value is a cons of
  (foreign-network-port . foreign-host-name).
 */
-       (proc))
+       (process))
 {
   Lisp_Object pid;
-  CHECK_PROCESS (proc);
+  CHECK_PROCESS (process);
 
-  pid = XPROCESS (proc)->pid;
-  if (network_connection_p (proc))
+  pid = XPROCESS (process)->pid;
+  if (network_connection_p (process))
     /* return Qnil; */
     return Fcons (Fcar (pid), Fcdr (pid));
   else
@@ -387,10 +415,10 @@ Return the name of PROCESS, as a string.
 This is the name of the program invoked in PROCESS,
 possibly modified to make it unique among process names.
 */
-       (proc))
+       (process))
 {
-  CHECK_PROCESS (proc);
-  return XPROCESS (proc)->name;
+  CHECK_PROCESS (process);
+  return XPROCESS (process)->name;
 }
 
 DEFUN ("process-command", Fprocess_command, 1, 1, 0, /*
@@ -398,10 +426,10 @@ Return the command that was executed to start PROCESS.
 This is a list of strings, the first string being the program executed
 and the rest of the strings being the arguments given to it.
 */
-       (proc))
+       (process))
 {
-  CHECK_PROCESS (proc);
-  return XPROCESS (proc)->command;
+  CHECK_PROCESS (process);
+  return XPROCESS (process)->command;
 }
 
 \f
@@ -414,8 +442,7 @@ make_process_internal (Lisp_Object name)
 {
   Lisp_Object val, name1;
   int i;
-  struct Lisp_Process *p =
-    alloc_lcrecord_type (struct Lisp_Process, lrecord_process);
+  Lisp_Process *p = alloc_lcrecord_type (Lisp_Process, &lrecord_process);
 
   /* If name is already in use, modify it until it is unused.  */
   name1 = name;
@@ -462,7 +489,7 @@ make_process_internal (Lisp_Object name)
 }
 
 void
-init_process_io_handles (struct Lisp_Process *p, void* in, void* out, int flags)
+init_process_io_handles (Lisp_Process *p, void* in, void* out, int flags)
 {
   USID usid = event_stream_create_stream_pair (in, out,
                                               &p->pipe_instream, &p->pipe_outstream,
@@ -473,9 +500,9 @@ init_process_io_handles (struct Lisp_Process *p, void* in, void* out, int flags)
 
   if (usid != USID_DONTHASH)
     {
-      Lisp_Object proc = Qnil;
-      XSETPROCESS (proc, p);
-      puthash ((CONST void*)usid, LISP_TO_VOID (proc), usid_to_process);
+      Lisp_Object process = Qnil;
+      XSETPROCESS (process, p);
+      puthash ((const void*)usid, LISP_TO_VOID (process), usid_to_process);
     }
 
   MAYBE_PROCMETH (init_process_io_handles, (p, in, out, flags));
@@ -497,7 +524,7 @@ static void
 create_process (Lisp_Object process, Lisp_Object *argv, int nargv,
                Lisp_Object program, Lisp_Object cur_dir)
 {
-  struct Lisp_Process *p = XPROCESS (process);
+  Lisp_Process *p = XPROCESS (process);
   int pid;
 
   /* *_create_process may change status_symbol, if the process
@@ -508,21 +535,21 @@ create_process (Lisp_Object process, Lisp_Object *argv, int nargv,
   pid = PROCMETH (create_process, (p, argv, nargv, program, cur_dir));
 
   p->pid = make_int (pid);
-  if (!NILP(p->pipe_instream))
+  if (PROCESS_READABLE_P (p))
     event_stream_select_process (p);
 }
 
 /* This function is the unwind_protect form for Fstart_process_internal.  If
-   PROC doesn't have its pid set, then we know someone has signalled
+   PROCESS doesn't have its pid set, then we know someone has signalled
    an error and the process wasn't started successfully, so we should
    remove it from the process list.  */
-static void remove_process (Lisp_Object proc);
+static void remove_process (Lisp_Object process);
 static Lisp_Object
-start_process_unwind (Lisp_Object proc)
+start_process_unwind (Lisp_Object process)
 {
-  /* Was PROC started successfully?  */
-  if (EQ (XPROCESS (proc)->pid, Qnil))
-    remove_process (proc);
+  /* Was PROCESS started successfully?  */
+  if (EQ (XPROCESS (process)->pid, Qnil))
+    remove_process (process);
   return Qnil;
 }
 
@@ -537,15 +564,16 @@ BUFFER is the buffer or (buffer-name) to associate with the process.
  with any buffer
 Third arg is program file name.  It is searched for as in the shell.
 Remaining arguments are strings to give program as arguments.
-INCODE and OUTCODE specify the coding-system objects used in input/output
- from/to the process.
+If bound, `coding-system-for-read' and `coding-system-for-write' specify
+ the coding-system objects used in input from and output to the process.
 */
        (int nargs, Lisp_Object *args))
 {
   /* This function can call lisp */
   /* !!#### This function has not been Mule-ized */
-  Lisp_Object buffer, name, program, proc, current_dir;
+  Lisp_Object buffer, name, program, process, current_dir;
   Lisp_Object tem;
+  int i;
   int speccount = specpdl_depth ();
   struct gcpro gcpro1, gcpro2, gcpro3;
 
@@ -562,6 +590,8 @@ INCODE and OUTCODE specify the coding-system objects used in input/output
 
   CHECK_STRING (name);
   CHECK_STRING (program);
+  for (i = 3; i < nargs; ++i)
+    CHECK_STRING (args[i]);
 
   /* Make sure that the child will be able to chdir to the current
      buffer's current directory, or its unhandled equivalent.  We
@@ -591,8 +621,7 @@ INCODE and OUTCODE specify the coding-system objects used in input/output
 
       tem = Qnil;
       NGCPRO1 (tem);
-      locate_file (Vexec_path, program, EXEC_SUFFIXES, &tem,
-                  X_OK);
+      locate_file (Vexec_path, program, Vlisp_EXEC_SUFFIXES, &tem, X_OK);
       if (NILP (tem))
        report_file_error ("Searching for program", list1 (program));
       program = Fexpand_file_name (tem, Qnil);
@@ -600,31 +629,45 @@ INCODE and OUTCODE specify the coding-system objects used in input/output
     }
   else
     {
-      if (!NILP (Ffile_directory_p (program)))
-       error ("Specified program for new process is a directory");
+      /* we still need to canonicalize it and ensure it has the proper
+        ending, e.g. .exe */
+      struct gcpro ngcpro1;
+
+      tem = Qnil;
+      NGCPRO1 (tem);
+      locate_file (list1 (build_string ("")), program, Vlisp_EXEC_SUFFIXES,
+                  &tem, X_OK);
+      if (NILP (tem))
+       report_file_error ("Searching for program", list1 (program));
+      program = tem;
+      NUNGCPRO;
     }
 
-  proc = make_process_internal (name);
+  if (!NILP (Ffile_directory_p (program)))
+    invalid_operation ("Specified program for new process is a directory",
+                      program);
 
-  XPROCESS (proc)->buffer = buffer;
-  XPROCESS (proc)->command = Flist (nargs - 2,
+  process = make_process_internal (name);
+
+  XPROCESS (process)->buffer = buffer;
+  XPROCESS (process)->command = Flist (nargs - 2,
                                    args + 2);
 
   /* Make the process marker point into the process buffer (if any).  */
   if (!NILP (buffer))
-    Fset_marker (XPROCESS (proc)->mark,
+    Fset_marker (XPROCESS (process)->mark,
                 make_int (BUF_ZV (XBUFFER (buffer))), buffer);
 
   /* If an error occurs and we can't start the process, we want to
      remove it from the process list.  This means that each error
      check in create_process doesn't need to call remove_process
      itself; it's all taken care of here.  */
-  record_unwind_protect (start_process_unwind, proc);
+  record_unwind_protect (start_process_unwind, process);
 
-  create_process (proc, args + 3, nargs - 3, program, current_dir);
+  create_process (process, args + 3, nargs - 3, program, current_dir);
 
   UNGCPRO;
-  return unbind_to (speccount, proc);
+  return unbind_to (speccount, process);
 }
 
 \f
@@ -656,9 +699,10 @@ INCODE and OUTCODE specify the coding-system objects used in input/output
    connection has no PID; you cannot signal it.  All you can do is
    deactivate and close it via delete-process */
 
-DEFUN ("open-network-stream-internal", Fopen_network_stream_internal, 4, 5, 0, /*
+DEFUN ("open-network-stream-internal", Fopen_network_stream_internal, 4, 5,
+       0, /*
 Open a TCP connection for a service to a host.
-Returns a subprocess-object to represent the connection.
+Return a process object to represent the connection.
 Input and output work as for subprocesses; `delete-process' closes it.
 
 NAME is name for process.  It is modified if necessary to make it unique.
@@ -667,55 +711,64 @@ BUFFER is the buffer (or buffer-name) to associate with the process.
  an output stream or filter function to handle the output.
  BUFFER may also be nil, meaning that this process is not associated
  with any buffer.
-Third arg is name of the host to connect to, or its IP address.
-Fourth arg SERVICE is name of the service desired, or an integer
- specifying a port number to connect to.
-Fifth argument FAMILY is a protocol family. When omitted, 'tcp/ip
-\(Internet protocol family TCP/IP) is assumed.
+Third arg HOST (a string) is  the name of the host to connect to,
+ or its IP address.
+Fourth arg SERVICE is the name of the service desired (a string),
+ or an integer specifying a port number to connect to.
+Optional fifth arg PROTOCOL is a network protocol.  Currently only 'tcp
+ (Transmission Control Protocol) and 'udp (User Datagram Protocol) are
+ supported.  When omitted, 'tcp is assumed.
+
+Output via `process-send-string' and input via buffer or filter (see
+`set-process-filter') are stream-oriented.  That means UDP datagrams are
+not guaranteed to be sent and received in discrete packets. (But small
+datagrams around 500 bytes that are not truncated by `process-send-string'
+are usually fine.)  Note further that the UDP protocol does not guard
+against lost packets.
 */
-       (name, buffer, host, service, family))
+       (name, buffer, host, service, protocol))
 {
   /* !!#### This function has not been Mule-ized */
   /* This function can GC */
-  Lisp_Object proc = Qnil;
+  Lisp_Object process = Qnil;
   struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5, ngcpro1;
   void *inch, *outch;
 
-  GCPRO5 (name, buffer, host, service, family);
+  GCPRO5 (name, buffer, host, service, protocol);
   CHECK_STRING (name);
 
-  if (NILP(family))
-    family = Qtcpip;
+  if (NILP(protocol))
+    protocol = Qtcp;
   else
-    CHECK_SYMBOL (family);
+    CHECK_SYMBOL (protocol);
 
   /* Since this code is inside HAVE_SOCKETS, existence of
      open_network_stream is mandatory */
-  PROCMETH (open_network_stream, (name, host, service, family,
+  PROCMETH (open_network_stream, (name, host, service, protocol,
                                  &inch, &outch));
 
   if (!NILP (buffer))
     buffer = Fget_buffer_create (buffer);
-  proc = make_process_internal (name);
-  NGCPRO1 (proc);
+  process = make_process_internal (name);
+  NGCPRO1 (process);
 
-  XPROCESS (proc)->pid = Fcons (service, host);
-  XPROCESS (proc)->buffer = buffer;
-  init_process_io_handles (XPROCESS (proc), (void*)inch, (void*)outch,
+  XPROCESS (process)->pid = Fcons (service, host);
+  XPROCESS (process)->buffer = buffer;
+  init_process_io_handles (XPROCESS (process), (void*)inch, (void*)outch,
                           STREAM_NETWORK_CONNECTION);
 
-  event_stream_select_process (XPROCESS (proc));
+  event_stream_select_process (XPROCESS (process));
 
-  UNGCPRO;
   NUNGCPRO;
-  return proc;
+  UNGCPRO;
+  return process;
 }
 
 #ifdef HAVE_MULTICAST
 
 DEFUN ("open-multicast-group-internal", Fopen_multicast_group_internal, 5, 5, 0, /*
 Open a multicast connection on the specified dest/port/ttl.
-Returns a subprocess-object to represent the connection.
+Return a process object to represent the connection.
 Input and output work as for subprocesses; `delete-process' closes it.
 
 NAME is name for process.  It is modified if necessary to make it unique.
@@ -733,7 +786,7 @@ Third, fourth and fifth args are the multicast destination group, port and ttl.
 {
   /* !!#### This function has not been Mule-ized */
   /* This function can GC */
-  Lisp_Object proc = Qnil;
+  Lisp_Object process = Qnil;
   struct gcpro gcpro1;
   void *inch, *outch;
 
@@ -747,18 +800,18 @@ Third, fourth and fifth args are the multicast destination group, port and ttl.
   if (!NILP (buffer))
     buffer = Fget_buffer_create (buffer);
 
-  proc = make_process_internal (name);
-  GCPRO1 (proc);
+  process = make_process_internal (name);
+  GCPRO1 (process);
 
-  XPROCESS (proc)->pid = Fcons (port, dest);
-  XPROCESS (proc)->buffer = buffer;
-  init_process_io_handles (XPROCESS (proc), (void*)inch, (void*)outch,
+  XPROCESS (process)->pid = Fcons (port, dest);
+  XPROCESS (process)->buffer = buffer;
+  init_process_io_handles (XPROCESS (process), (void*)inch, (void*)outch,
                           STREAM_NETWORK_CONNECTION);
 
-  event_stream_select_process (XPROCESS (proc));
+  event_stream_select_process (XPROCESS (process));
 
   UNGCPRO;
-  return proc;
+  return process;
 }
 #endif /* HAVE_MULTICAST */
 
@@ -774,13 +827,14 @@ canonicalize_host_name (Lisp_Object host)
 DEFUN ("set-process-window-size", Fset_process_window_size, 3, 3, 0, /*
 Tell PROCESS that it has logical window size HEIGHT and WIDTH.
 */
-       (proc, height, width))
+       (process, height, width))
 {
-  CHECK_PROCESS (proc);
+  CHECK_PROCESS (process);
   CHECK_NATNUM (height);
   CHECK_NATNUM (width);
   return
-    MAYBE_INT_PROCMETH (set_window_size, (XPROCESS (proc), XINT (height), XINT (width))) <= 0
+    MAYBE_INT_PROCMETH (set_window_size,
+                       (XPROCESS (process), XINT (height), XINT (width))) <= 0
     ? Qnil : Qt;
 }
 
@@ -798,13 +852,13 @@ Tell PROCESS that it has logical window size HEIGHT and WIDTH.
    you must call it repeatedly until it returns zero.  */
 
 Charcount
-read_process_output (Lisp_Object proc)
+read_process_output (Lisp_Object process)
 {
   /* This function can GC */
   Bytecount nbytes, nchars;
   Bufbyte chars[1024];
   Lisp_Object outstream;
-  struct Lisp_Process *p = XPROCESS (proc);
+  Lisp_Process *p = XPROCESS (process);
 
   /* If there is a lot of output from the subprocess, the loop in
      execute_internal_event() might call read_process_output() more
@@ -814,7 +868,7 @@ read_process_output (Lisp_Object proc)
      Really, the loop in execute_internal_event() should check itself
      for a process-filter change, like in status_notify(); but the
      struct Lisp_Process is not exported outside of this file. */
-  if (NILP(p->pipe_instream))
+  if (!PROCESS_READABLE_P (p))
     return -1; /* already closed */
 
   if (!NILP (p->filter) && (p->filter_does_read))
@@ -825,7 +879,7 @@ read_process_output (Lisp_Object proc)
         Vdeactivate_mark and current_buffer->keymap */
       running_asynch_code = 1;
       filter_result = call2_trapping_errors ("Error in process filter",
-                                            p->filter, proc, Qnil);
+                                            p->filter, process, Qnil);
       running_asynch_code = 0;
       restore_match_data ();
       CHECK_INT (filter_result);
@@ -843,7 +897,7 @@ read_process_output (Lisp_Object proc)
         call2_trapping_errors() does that for us. */
       running_asynch_code = 1;
       call2_trapping_errors ("Error in process filter",
-                            outstream, proc, make_string (chars, nbytes));
+                            outstream, process, make_string (chars, nbytes));
       running_asynch_code = 0;
       restore_match_data ();
       return nchars;
@@ -860,7 +914,7 @@ read_process_output (Lisp_Object proc)
       struct gcpro gcpro1, gcpro2;
       struct buffer *buf = XBUFFER (p->buffer);
 
-      GCPRO2 (proc, old_read_only);
+      GCPRO2 (process, old_read_only);
 
       old_point = BUF_PT (buf);
       old_begv = BUF_BEGV (buf);
@@ -939,7 +993,7 @@ read_process_output (Lisp_Object proc)
 \f
 /* Sending data to subprocess */
 
-/* send some data to process PROC.  If NONRELOCATABLE is non-NULL, it
+/* send some data to process PROCESS.  If NONRELOCATABLE is non-NULL, it
    specifies the address of the data.  Otherwise, the data comes from the
    object RELOCATABLE (either a string or a buffer).  START and LEN
    specify the offset and length of the data to send.
@@ -948,29 +1002,29 @@ read_process_output (Lisp_Object proc)
    and in Bytecounts otherwise. */
 
 void
-send_process (Lisp_Object proc,
-              Lisp_Object relocatable, CONST Bufbyte *nonrelocatable,
+send_process (Lisp_Object process,
+              Lisp_Object relocatable, const Bufbyte *nonrelocatable,
               int start, int len)
 {
   /* This function can GC */
   struct gcpro gcpro1, gcpro2;
   Lisp_Object lstream = Qnil;
 
-  GCPRO2 (proc, lstream);
+  GCPRO2 (process, lstream);
 
-  if (NILP (DATA_OUTSTREAM (XPROCESS (proc))))
-    signal_simple_error ("Process not open for writing", proc);
+  if (NILP (DATA_OUTSTREAM (XPROCESS (process))))
+    signal_simple_error ("Process not open for writing", process);
 
   if (nonrelocatable)
     lstream =
       make_fixed_buffer_input_stream (nonrelocatable + start, len);
-  else if (GC_BUFFERP (relocatable))
+  else if (BUFFERP (relocatable))
     lstream = make_lisp_buffer_input_stream (XBUFFER (relocatable),
                                             start, start + len, 0);
   else
     lstream = make_lisp_string_input_stream (relocatable, start, len);
 
-  PROCMETH (send_process, (proc, XLSTREAM (lstream)));
+  PROCMETH (send_process, (process, XLSTREAM (lstream)));
 
   UNGCPRO;
   Lstream_delete (XLSTREAM (lstream));
@@ -981,21 +1035,21 @@ Return the name of the terminal PROCESS uses, or nil if none.
 This is the terminal that the process itself reads and writes on,
 not the name of the pty that Emacs uses to talk with that terminal.
 */
-       (proc))
+       (process))
 {
-  CHECK_PROCESS (proc);
-  return MAYBE_LISP_PROCMETH (get_tty_name, (XPROCESS (proc)));
+  CHECK_PROCESS (process);
+  return MAYBE_LISP_PROCMETH (get_tty_name, (XPROCESS (process)));
 }
 
 DEFUN ("set-process-buffer", Fset_process_buffer, 2, 2, 0, /*
 Set buffer associated with PROCESS to BUFFER (a buffer, or nil).
 */
-       (proc, buffer))
+       (process, buffer))
 {
-  CHECK_PROCESS (proc);
+  CHECK_PROCESS (process);
   if (!NILP (buffer))
     CHECK_BUFFER (buffer);
-  XPROCESS (proc)->buffer = buffer;
+  XPROCESS (process)->buffer = buffer;
   return buffer;
 }
 
@@ -1004,34 +1058,34 @@ Return the buffer PROCESS is associated with.
 Output from PROCESS is inserted in this buffer
 unless PROCESS has a filter.
 */
-       (proc))
+       (process))
 {
-  CHECK_PROCESS (proc);
-  return XPROCESS (proc)->buffer;
+  CHECK_PROCESS (process);
+  return XPROCESS (process)->buffer;
 }
 
 DEFUN ("process-mark", Fprocess_mark, 1, 1, 0, /*
 Return the marker for the end of the last output from PROCESS.
 */
-       (proc))
+       (process))
 {
-  CHECK_PROCESS (proc);
-  return XPROCESS (proc)->mark;
+  CHECK_PROCESS (process);
+  return XPROCESS (process)->mark;
 }
 
 void
-set_process_filter (Lisp_Object proc, Lisp_Object filter, int filter_does_read)
+set_process_filter (Lisp_Object process, Lisp_Object filter, int filter_does_read)
 {
-  CHECK_PROCESS (proc);
-  if (PROCESS_LIVE_P (proc)) {
+  CHECK_PROCESS (process);
+  if (PROCESS_READABLE_P (XPROCESS (process))) {
     if (EQ (filter, Qt))
-      event_stream_unselect_process (XPROCESS (proc));
+      event_stream_unselect_process (XPROCESS (process));
     else
-      event_stream_select_process (XPROCESS (proc));
+      event_stream_select_process (XPROCESS (process));
   }
 
-  XPROCESS (proc)->filter = filter;
-  XPROCESS (proc)->filter_does_read = filter_does_read;
+  XPROCESS (process)->filter = filter;
+  XPROCESS (process)->filter_does_read = filter_does_read;
 }
 
 DEFUN ("set-process-filter", Fset_process_filter, 2, 2, 0, /*
@@ -1042,9 +1096,9 @@ the entire string of output is passed to the filter.
 The filter gets two arguments: the process and the string of output.
 If the process has a filter, its buffer is not used for output.
 */
-       (proc, filter))
+       (process, filter))
 {
-  set_process_filter (proc, filter, 0);
+  set_process_filter (process, filter, 0);
   return filter;
 }
 
@@ -1052,55 +1106,57 @@ DEFUN ("process-filter", Fprocess_filter, 1, 1, 0, /*
 Return the filter function of PROCESS; nil if none.
 See `set-process-filter' for more info on filter functions.
 */
-       (proc))
+       (process))
 {
-  CHECK_PROCESS (proc);
-  return XPROCESS (proc)->filter;
+  CHECK_PROCESS (process);
+  return XPROCESS (process)->filter;
 }
 
-DEFUN ("process-send-region", Fprocess_send_region, 3, 3, 0, /*
-Send current contents of region as input to PROCESS.
-PROCESS may be a process name or an actual process.
-Called from program, takes three arguments, PROCESS, START and END.
-If the region is more than 500 or so characters long,
-it is sent in several bunches.  This may happen even for shorter regions.
-Output from processes can arrive in between bunches.
+DEFUN ("process-send-region", Fprocess_send_region, 3, 4, 0, /*
+Send current contents of the region between START and END as input to PROCESS.
+PROCESS may be a process or the name of a process, or a buffer or the
+name of a buffer, in which case the buffer's process is used.  If it
+is nil, the current buffer's process is used.
+BUFFER specifies the buffer to look in; if nil, the current buffer is used.
+If STRING is more than 100 or so characters long, it may be sent in
+several chunks.  This may happen even for shorter strings.  Output
+from processes can arrive in between chunks.
 */
-       (process, start, end))
+       (process, start, end, buffer))
 {
   /* This function can GC */
-  Lisp_Object proc = get_process (process);
-  Bufpos st, en;
+  Bufpos bstart, bend;
+  struct buffer *buf = decode_buffer (buffer, 0);
 
-  get_buffer_range_char (current_buffer, start, end, &st, &en, 0);
+  XSETBUFFER (buffer, buf);
+  process = get_process (process);
+  get_buffer_range_char (buf, start, end, &bstart, &bend, 0);
 
-  send_process (proc, Fcurrent_buffer (), 0,
-                st, en - st);
+  send_process (process, buffer, 0, bstart, bend - bstart);
   return Qnil;
 }
 
 DEFUN ("process-send-string", Fprocess_send_string, 2, 4, 0, /*
 Send PROCESS the contents of STRING as input.
-PROCESS may be a process name or an actual process.
-Optional arguments FROM and TO specify part of STRING, see `substring'.
-If STRING is more than 500 or so characters long,
-it is sent in several bunches.  This may happen even for shorter strings.
-Output from processes can arrive in between bunches.
+PROCESS may be a process or the name of a process, or a buffer or the
+name of a buffer, in which case the buffer's process is used.  If it
+is nil, the current buffer's process is used.
+Optional arguments START and END specify part of STRING; see `substring'.
+If STRING is more than 100 or so characters long, it may be sent in
+several chunks.  This may happen even for shorter strings.  Output
+from processes can arrive in between chunks.
 */
-       (process, string, from, to))
+       (process, string, start, end))
 {
   /* This function can GC */
-  Lisp_Object proc;
-  Bytecount len;
-  Bytecount bfr, bto;
+  Bytecount bstart, bend;
 
-  proc = get_process (process);
+  process = get_process (process);
   CHECK_STRING (string);
-  get_string_range_byte (string, from, to, &bfr, &bto,
+  get_string_range_byte (string, start, end, &bstart, &bend,
                         GB_HISTORICAL_STRING_BEHAVIOR);
-  len = bto - bfr;
 
-  send_process (proc, string, 0, bfr, len);
+  send_process (process, string, 0, bstart, bend - bstart);
   return Qnil;
 }
 
@@ -1112,6 +1168,7 @@ Return PROCESS's input coding system.
        (process))
 {
   process = get_process (process);
+  CHECK_READABLE_PROCESS (process);
   return decoding_stream_coding_system (XLSTREAM (XPROCESS (process)->coding_instream) );
 }
 
@@ -1121,6 +1178,7 @@ Return PROCESS's output coding system.
        (process))
 {
   process = get_process (process);
+  CHECK_LIVE_PROCESS (process);
   return encoding_stream_coding_system (XLSTREAM (XPROCESS (process)->coding_outstream));
 }
 
@@ -1130,6 +1188,7 @@ Return a pair of coding-system for decoding and encoding of PROCESS.
        (process))
 {
   process = get_process (process);
+  CHECK_READABLE_PROCESS (process);
   return Fcons (decoding_stream_coding_system
                (XLSTREAM (XPROCESS (process)->coding_instream)),
                encoding_stream_coding_system
@@ -1144,6 +1203,8 @@ Set PROCESS's input coding system to CODESYS.
 {
   codesys = Fget_coding_system (codesys);
   process = get_process (process);
+  CHECK_READABLE_PROCESS (process);
+
   set_decoding_stream_coding_system
     (XLSTREAM (XPROCESS (process)->coding_instream), codesys);
   return Qnil;
@@ -1157,6 +1218,8 @@ Set PROCESS's output coding system to CODESYS.
 {
   codesys = Fget_coding_system (codesys);
   process = get_process (process);
+  CHECK_LIVE_PROCESS (process);
+
   set_encoding_stream_coding_system
     (XLSTREAM (XPROCESS (process)->coding_outstream), codesys);
   return Qnil;
@@ -1165,6 +1228,8 @@ Set PROCESS's output coding system to CODESYS.
 DEFUN ("set-process-coding-system", Fset_process_coding_system,
        1, 3, 0, /*
 Set coding-systems of PROCESS to DECODING and ENCODING.
+DECODING will be used to decode subprocess output and ENCODING to
+encode subprocess input.
 */
        (process, decoding, encoding))
 {
@@ -1186,18 +1251,18 @@ Set coding-systems of PROCESS to DECODING and ENCODING.
 static Lisp_Object
 exec_sentinel_unwind (Lisp_Object datum)
 {
-  struct Lisp_Cons *d = XCONS (datum);
+  Lisp_Cons *d = XCONS (datum);
   XPROCESS (d->car)->sentinel = d->cdr;
   free_cons (d);
   return Qnil;
 }
 
 static void
-exec_sentinel (Lisp_Object proc, Lisp_Object reason)
+exec_sentinel (Lisp_Object process, Lisp_Object reason)
 {
   /* This function can GC */
   int speccount = specpdl_depth ();
-  struct Lisp_Process *p = XPROCESS (proc);
+  Lisp_Process *p = XPROCESS (process);
   Lisp_Object sentinel = p->sentinel;
 
   if (NILP (sentinel))
@@ -1209,11 +1274,11 @@ exec_sentinel (Lisp_Object proc, Lisp_Object reason)
   /* Zilch the sentinel while it's running, to avoid recursive invocations;
      assure that it gets restored no matter how the sentinel exits.  */
   p->sentinel = Qnil;
-  record_unwind_protect (exec_sentinel_unwind, noseeum_cons (proc, sentinel));
+  record_unwind_protect (exec_sentinel_unwind, noseeum_cons (process, sentinel));
   /* We used to bind inhibit-quit to t here, but call2_trapping_errors()
      does that for us. */
   running_asynch_code = 1;
-  call2_trapping_errors ("Error in process sentinel", sentinel, proc, reason);
+  call2_trapping_errors ("Error in process sentinel", sentinel, process, reason);
   running_asynch_code = 0;
   restore_match_data ();
   unbind_to (speccount, Qnil);
@@ -1224,10 +1289,10 @@ Give PROCESS the sentinel SENTINEL; nil for none.
 The sentinel is called as a function when the process changes state.
 It gets two arguments: the process, and a string describing the change.
 */
-       (proc, sentinel))
+       (process, sentinel))
 {
-  CHECK_PROCESS (proc);
-  XPROCESS (proc)->sentinel = sentinel;
+  CHECK_PROCESS (process);
+  XPROCESS (process)->sentinel = sentinel;
   return sentinel;
 }
 
@@ -1235,20 +1300,20 @@ DEFUN ("process-sentinel", Fprocess_sentinel, 1, 1, 0, /*
 Return the sentinel of PROCESS; nil if none.
 See `set-process-sentinel' for more info on sentinels.
 */
-       (proc))
+       (process))
 {
-  CHECK_PROCESS (proc);
-  return XPROCESS (proc)->sentinel;
+  CHECK_PROCESS (process);
+  return XPROCESS (process)->sentinel;
 }
 
 \f
-CONST char *
+const char *
 signal_name (int signum)
 {
   if (signum >= 0 && signum < NSIG)
-    return (CONST char *) sys_siglist[signum];
+    return (const char *) sys_siglist[signum];
 
-  return (CONST char *) GETTEXT ("unknown signal");
+  return (const char *) GETTEXT ("unknown signal");
 }
 
 void
@@ -1267,7 +1332,7 @@ update_process_status (Lisp_Object p,
 /* Return a string describing a process status list.  */
 
 static Lisp_Object
-status_message (struct Lisp_Process *p)
+status_message (Lisp_Process *p)
 {
   Lisp_Object symbol = p->status_symbol;
   int code = p->exit_code;
@@ -1326,7 +1391,7 @@ status_notify (void)
   Lisp_Object msg = Qnil;
   struct gcpro gcpro1, gcpro2, gcpro3;
   /* process_tick is volatile, so we have to remember it now.
-     Otherwise, we get a race condition is SIGCHLD happens during
+     Otherwise, we get a race condition if SIGCHLD happens during
      this function.
 
      (Actually, this is not the case anymore.  The code to
@@ -1350,8 +1415,8 @@ status_notify (void)
 
   for (tail = Vprocess_list; CONSP (tail); tail = XCDR (tail))
     {
-      Lisp_Object proc = XCAR (tail);
-      struct Lisp_Process *p = XPROCESS (proc);
+      Lisp_Object process = XCAR (tail);
+      Lisp_Process *p = XPROCESS (process);
       /* p->tick is also volatile.  Same thing as above applies. */
       int this_process_tick;
 
@@ -1368,7 +1433,7 @@ status_notify (void)
 
          /* If process is still active, read any output that remains.  */
           while (!EQ (p->filter, Qt)
-                && read_process_output (proc) > 0)
+                && read_process_output (process) > 0)
             ;
 
          /* Get the text to use for the message.  */
@@ -1381,14 +1446,14 @@ status_notify (void)
               || EQ (symbol, Qexit))
            {
              if (delete_exited_processes)
-               remove_process (proc);
+               remove_process (process);
              else
-               deactivate_process (proc);
+               deactivate_process (process);
            }
 
          /* Now output the message suitably.  */
          if (!NILP (p->sentinel))
-           exec_sentinel (proc, msg);
+           exec_sentinel (process, msg);
          /* Don't bother with a message in the buffer
             when a process becomes runnable.  */
          else if (!EQ (symbol, Qrun) && !NILP (p->buffer))
@@ -1462,20 +1527,20 @@ nil    -- if arg is a process name and no such process exists.
 PROCESS may be a process, a buffer, the name of a process or buffer, or
 nil, indicating the current buffer's process.
 */
-       (proc))
+       (process))
 {
   Lisp_Object status_symbol;
 
-  if (STRINGP (proc))
-    proc = Fget_process (proc);
+  if (STRINGP (process))
+    process = Fget_process (process);
   else
-    proc = get_process (proc);
+    process = get_process (process);
 
-  if (NILP (proc))
+  if (NILP (process))
     return Qnil;
 
-  status_symbol = XPROCESS (proc)->status_symbol;
-  if (network_connection_p (proc))
+  status_symbol = XPROCESS (process)->status_symbol;
+  if (network_connection_p (process))
     {
       if (EQ (status_symbol, Qrun))
        status_symbol = Qopen;
@@ -1489,143 +1554,31 @@ DEFUN ("process-exit-status", Fprocess_exit_status, 1, 1, 0, /*
 Return the exit status of PROCESS or the signal number that killed it.
 If PROCESS has not yet exited or died, return 0.
 */
-       (proc))
+       (process))
 {
-  CHECK_PROCESS (proc);
-  return make_int (XPROCESS (proc)->exit_code);
+  CHECK_PROCESS (process);
+  return make_int (XPROCESS (process)->exit_code);
 }
 
 \f
 
-/* send a signal number SIGNO to PROCESS.
-   CURRENT_GROUP means send to the process group that currently owns
-   the terminal being used to communicate with PROCESS.
-   This is used for various commands in shell mode.
-   If NOMSG is zero, insert signal-announcements into process's buffers
-   right away.
-
-   If we can, we try to signal PROCESS by sending control characters
-   down the pty.  This allows us to signal inferiors who have changed
-   their uid, for which killpg would return an EPERM error.  */
-
-static void
-process_send_signal (Lisp_Object process, int signo,
-                     int current_group, int nomsg)
-{
-  /* This function can GC */
-  Lisp_Object proc = get_process (process);
-
-  if (network_connection_p (proc))
-    error ("Network connection %s is not a subprocess",
-          XSTRING_DATA (XPROCESS(proc)->name));
-  if (!PROCESS_LIVE_P (proc))
-    error ("Process %s is not active",
-          XSTRING_DATA (XPROCESS(proc)->name));
-
-  MAYBE_PROCMETH (kill_child_process, (proc, signo, current_group, nomsg));
-}
-
-DEFUN ("interrupt-process", Finterrupt_process, 0, 2, 0, /*
-Interrupt process PROCESS.  May be process or name of one.
-Nil or no arg means current buffer's process.
-Second arg CURRENT-GROUP non-nil means send signal to
-the current process-group of the process's controlling terminal
-rather than to the process's own process group.
-If the process is a shell, this means interrupt current subjob
-rather than the shell.
-*/
-       (process, current_group))
-{
-  /* This function can GC */
-  process_send_signal (process, SIGINT, !NILP (current_group), 0);
-  return process;
-}
-
-DEFUN ("kill-process", Fkill_process, 0, 2, 0, /*
-Kill process PROCESS.  May be process or name of one.
-See function `interrupt-process' for more details on usage.
-*/
-       (process, current_group))
-{
-  /* This function can GC */
-#ifdef SIGKILL
-  process_send_signal (process, SIGKILL, !NILP (current_group), 0);
-#else
-  error ("kill-process: Not supported on this system");
-#endif
-  return process;
-}
-
-DEFUN ("quit-process", Fquit_process, 0, 2, 0, /*
-Send QUIT signal to process PROCESS.  May be process or name of one.
-See function `interrupt-process' for more details on usage.
-*/
-       (process, current_group))
-{
-  /* This function can GC */
-#ifdef SIGQUIT
-  process_send_signal (process, SIGQUIT, !NILP (current_group), 0);
-#else
-  error ("quit-process: Not supported on this system");
-#endif
-  return process;
-}
-
-DEFUN ("stop-process", Fstop_process, 0, 2, 0, /*
-Stop process PROCESS.  May be process or name of one.
-See function `interrupt-process' for more details on usage.
-*/
-       (process, current_group))
-{
-  /* This function can GC */
-#ifdef SIGTSTP
-  process_send_signal (process, SIGTSTP, !NILP (current_group), 0);
-#else
-  error ("stop-process: Not supported on this system");
-#endif
-  return process;
-}
-
-DEFUN ("continue-process", Fcontinue_process, 0, 2, 0, /*
-Continue process PROCESS.  May be process or name of one.
-See function `interrupt-process' for more details on usage.
-*/
-       (process, current_group))
-{
-  /* This function can GC */
-#ifdef SIGCONT
-  process_send_signal (process, SIGCONT, !NILP (current_group), 0);
-#else
-  error ("continue-process: Not supported on this system");
-#endif
-  return process;
-}
-
-DEFUN ("signal-process", Fsignal_process, 2, 2,
-       "nProcess number: \nnSignal code: ", /*
-Send the process with process id PID the signal with code SIGCODE.
-PID must be an integer.  The process need not be a child of this Emacs.
-SIGCODE may be an integer, or a symbol whose name is a signal name.
-*/
-       (pid, sigcode))
+static int
+decode_signal (Lisp_Object signal_)
 {
-  CHECK_INT (pid);
-
-  if (INTP (sigcode))
-    ;
+  if (INTP (signal_))
+    return XINT (signal_);
   else
     {
       Bufbyte *name;
 
-      CHECK_SYMBOL (sigcode);
-      name = string_data (XSYMBOL (sigcode)->name);
+      CHECK_SYMBOL (signal_);
+      name = string_data (XSYMBOL (signal_)->name);
 
-#define handle_signal(signal)                          \
-  else if (!strcmp ((CONST char *) name, #signal))     \
-    XSETINT (sigcode, signal)
+#define handle_signal(sym) do {                                \
+       if (!strcmp ((const char *) name, #sym))        \
+         return sym;                                   \
+      } while (0)
 
-      if (0)
-       ;
       handle_signal (SIGINT);  /* ANSI */
       handle_signal (SIGILL);  /* ANSI */
       handle_signal (SIGABRT); /* ANSI */
@@ -1759,14 +1712,145 @@ SIGCODE may be an integer, or a symbol whose name is a signal name.
 #ifdef SIGPWR
       handle_signal (SIGPWR);
 #endif
-      else
-       error ("Undefined signal name %s", name);
-    }
 
 #undef handle_signal
 
+      error ("Undefined signal name %s", name);
+      return 0; /* Unreached */
+    }
+}
+
+/* Send signal number SIGNO to PROCESS.
+   CURRENT-GROUP non-nil means send signal to the current
+   foreground process group of the process's controlling terminal rather
+   than to the process's own process group.
+   This is used for various commands in shell mode.
+   If NOMSG is zero, insert signal-announcements into process's buffers
+   right away.
+
+   If we can, we try to signal PROCESS by sending control characters
+   down the pty.  This allows us to signal inferiors who have changed
+   their uid, for which kill() would return an EPERM error, or to
+   processes running on another computer through a remote login.  */
+
+static void
+process_send_signal (Lisp_Object process, int signo,
+                     int current_group, int nomsg)
+{
+  /* This function can GC */
+  process = get_process (process);
+
+  if (network_connection_p (process))
+    error ("Network connection %s is not a subprocess",
+          XSTRING_DATA (XPROCESS(process)->name));
+  CHECK_LIVE_PROCESS (process);
+
+  MAYBE_PROCMETH (kill_child_process, (process, signo, current_group, nomsg));
+}
+
+DEFUN ("process-send-signal", Fprocess_send_signal, 1, 3, 0, /*
+Send signal SIGNAL to process PROCESS.
+SIGNAL may be an integer, or a symbol naming a signal, like `SIGSEGV'.
+PROCESS may be a process, a buffer, the name of a process or buffer, or
+nil, indicating the current buffer's process.
+Third arg CURRENT-GROUP non-nil means send signal to the current
+foreground process group of the process's controlling terminal rather
+than to the process's own process group.
+If the process is a shell that supports job control, this means
+send the signal to the current subjob rather than the shell.
+*/
+       (signal_, process, current_group))
+{
+  /* This function can GC */
+  process_send_signal (process, decode_signal (signal_),
+                      !NILP (current_group), 0);
+  return process;
+}
+
+DEFUN ("interrupt-process", Finterrupt_process, 0, 2, 0, /*
+Interrupt process PROCESS.
+See function `process-send-signal' for more details on usage.
+*/
+       (process, current_group))
+{
+  /* This function can GC */
+  process_send_signal (process, SIGINT, !NILP (current_group), 0);
+  return process;
+}
+
+DEFUN ("kill-process", Fkill_process, 0, 2, 0, /*
+Kill process PROCESS.
+See function `process-send-signal' for more details on usage.
+*/
+       (process, current_group))
+{
+  /* This function can GC */
+#ifdef SIGKILL
+  process_send_signal (process, SIGKILL, !NILP (current_group), 0);
+#else
+  error ("kill-process: Not supported on this system");
+#endif
+  return process;
+}
+
+DEFUN ("quit-process", Fquit_process, 0, 2, 0, /*
+Send QUIT signal to process PROCESS.
+See function `process-send-signal' for more details on usage.
+*/
+       (process, current_group))
+{
+  /* This function can GC */
+#ifdef SIGQUIT
+  process_send_signal (process, SIGQUIT, !NILP (current_group), 0);
+#else
+  error ("quit-process: Not supported on this system");
+#endif
+  return process;
+}
+
+DEFUN ("stop-process", Fstop_process, 0, 2, 0, /*
+Stop process PROCESS.
+See function `process-send-signal' for more details on usage.
+*/
+       (process, current_group))
+{
+  /* This function can GC */
+#ifdef SIGTSTP
+  process_send_signal (process, SIGTSTP, !NILP (current_group), 0);
+#else
+  error ("stop-process: Not supported on this system");
+#endif
+  return process;
+}
+
+DEFUN ("continue-process", Fcontinue_process, 0, 2, 0, /*
+Continue process PROCESS.
+See function `process-send-signal' for more details on usage.
+*/
+       (process, current_group))
+{
+  /* This function can GC */
+#ifdef SIGCONT
+  process_send_signal (process, SIGCONT, !NILP (current_group), 0);
+#else
+  error ("continue-process: Not supported on this system");
+#endif
+  return process;
+}
+
+DEFUN ("signal-process", Fsignal_process, 2, 2,
+       "nProcess number: \nnSignal code: ", /*
+Send the process with process id PID the signal with code SIGNAL.
+PID must be an integer.  The process need not be a child of this Emacs.
+SIGNAL may be an integer, or a symbol naming a signal, like `SIGSEGV'.
+*/
+       (pid, signal_))
+{
+  CHECK_INT (pid);
+
   return make_int (PROCMETH_OR_GIVEN (kill_process_by_pid,
-                                     (XINT (pid), XINT (sigcode)), -1));
+                                     (XINT (pid), decode_signal (signal_)),
+                                     -1));
 }
 
 DEFUN ("process-send-eof", Fprocess_send_eof, 0, 1, 0, /*
@@ -1780,21 +1864,21 @@ text to PROCESS after you call this function.
        (process))
 {
   /* This function can GC */
-  Lisp_Object proc = get_process (process);
+  process = get_process (process);
 
   /* Make sure the process is really alive.  */
-  if (! EQ (XPROCESS (proc)->status_symbol, Qrun))
-    error ("Process %s not running", XSTRING_DATA (XPROCESS (proc)->name));
+  if (! EQ (XPROCESS (process)->status_symbol, Qrun))
+    error ("Process %s not running", XSTRING_DATA (XPROCESS (process)->name));
 
-  if (!MAYBE_INT_PROCMETH (process_send_eof, (proc)))
+  if (!MAYBE_INT_PROCMETH (process_send_eof, (process)))
     {
-      if (!NILP (DATA_OUTSTREAM (XPROCESS (proc))))
+      if (!NILP (DATA_OUTSTREAM (XPROCESS (process))))
        {
-         Lstream_close (XLSTREAM (DATA_OUTSTREAM (XPROCESS (proc))));
-         event_stream_delete_stream_pair (Qnil, XPROCESS (proc)->pipe_outstream);
-         XPROCESS (proc)->pipe_outstream = Qnil;
+         Lstream_close (XLSTREAM (DATA_OUTSTREAM (XPROCESS (process))));
+         event_stream_delete_stream_pair (Qnil, XPROCESS (process)->pipe_outstream);
+         XPROCESS (process)->pipe_outstream = Qnil;
 #ifdef FILE_CODING
-         XPROCESS (proc)->coding_outstream = Qnil;
+         XPROCESS (process)->coding_outstream = Qnil;
 #endif
        }
     }
@@ -1808,9 +1892,9 @@ text to PROCESS after you call this function.
 /************************************************************************/
 
 void
-deactivate_process (Lisp_Object proc)
+deactivate_process (Lisp_Object process)
 {
-  struct Lisp_Process *p = XPROCESS (proc);
+  Lisp_Process *p = XPROCESS (process);
   USID usid;
 
   /* It's possible that we got as far in the process-creation
@@ -1837,7 +1921,7 @@ deactivate_process (Lisp_Object proc)
                                            p->pipe_outstream);
 
   if (usid != USID_DONTHASH)
-    remhash ((CONST void*)usid, usid_to_process);
+    remhash ((const void*)usid, usid_to_process);
 
   p->pipe_instream = Qnil;
   p->pipe_outstream = Qnil;
@@ -1848,25 +1932,25 @@ deactivate_process (Lisp_Object proc)
 }
 
 static void
-remove_process (Lisp_Object proc)
+remove_process (Lisp_Object process)
 {
-  Vprocess_list = delq_no_quit (proc, Vprocess_list);
-  Fset_marker (XPROCESS (proc)->mark, Qnil, Qnil);
+  Vprocess_list = delq_no_quit (process, Vprocess_list);
+  Fset_marker (XPROCESS (process)->mark, Qnil, Qnil);
 
-  deactivate_process (proc);
+  deactivate_process (process);
 }
 
 DEFUN ("delete-process", Fdelete_process, 1, 1, 0, /*
 Delete PROCESS: kill it and forget about it immediately.
 PROCESS may be a process or the name of one, or a buffer name.
 */
-       (proc))
+       (process))
 {
   /* This function can GC */
-  struct Lisp_Process *p;
-  proc = get_process (proc);
-  p = XPROCESS (proc);
-  if (network_connection_p (proc))
+  Lisp_Process *p;
+  process = get_process (process);
+  p = XPROCESS (process);
+  if (network_connection_p (process))
     {
       p->status_symbol = Qexit;
       p->exit_code = 0;
@@ -1874,9 +1958,9 @@ PROCESS may be a process or the name of one, or a buffer name.
       p->tick++;
       process_tick++;
     }
-  else if (!NILP(p->pipe_instream))
+  else if (PROCESS_LIVE_P (p))
     {
-      Fkill_process (proc, Qnil);
+      Fkill_process (process, Qnil);
       /* Do this now, since remove_process will make sigchld_handler do nothing.  */
       p->status_symbol = Qsignal;
       p->exit_code = SIGKILL;
@@ -1885,7 +1969,7 @@ PROCESS may be a process or the name of one, or a buffer name.
       process_tick++;
       status_notify ();
     }
-  remove_process (proc);
+  remove_process (process);
   return Qnil;
 }
 
@@ -1895,21 +1979,14 @@ PROCESS may be a process or the name of one, or a buffer name.
 void
 kill_buffer_processes (Lisp_Object buffer)
 {
-  Lisp_Object tail;
-
-  for (tail = Vprocess_list; GC_CONSP (tail);
-       tail = XCDR (tail))
-    {
-      Lisp_Object proc = XCAR (tail);
-      if (GC_PROCESSP (proc)
-         && (GC_NILP (buffer) || GC_EQ (XPROCESS (proc)->buffer, buffer)))
-       {
-         if (network_connection_p (proc))
-           Fdelete_process (proc);
-         else if (!NILP (XPROCESS (proc)->pipe_instream))
-           process_send_signal (proc, SIGHUP, 0, 1);
-       }
-    }
+  LIST_LOOP_2 (process, Vprocess_list)
+    if ((NILP (buffer) || EQ (XPROCESS (process)->buffer, buffer)))
+      {
+       if (network_connection_p (process))
+         Fdelete_process (process);
+       else if (PROCESS_LIVE_P (XPROCESS (process)))
+         process_send_signal (process, SIGHUP, 0, 1);
+      }
 }
 
 DEFUN ("process-kill-without-query", Fprocess_kill_without_query, 1, 2, 0, /*
@@ -1917,24 +1994,24 @@ Say no query needed if PROCESS is running when Emacs is exited.
 Optional second argument if non-nil says to require a query.
 Value is t if a query was formerly required.
 */
-       (proc, require_query_p))
+       (process, require_query_p))
 {
   int tem;
 
-  CHECK_PROCESS (proc);
-  tem = XPROCESS (proc)->kill_without_query;
-  XPROCESS (proc)->kill_without_query = NILP (require_query_p);
+  CHECK_PROCESS (process);
+  tem = XPROCESS (process)->kill_without_query;
+  XPROCESS (process)->kill_without_query = NILP (require_query_p);
 
   return tem ? Qnil : Qt;
 }
 
 DEFUN ("process-kill-without-query-p", Fprocess_kill_without_query_p, 1, 1, 0, /*
-Whether PROC will be killed without query if running when emacs is exited.
+Return t if PROCESS will be killed without query when emacs is exited.
 */
-       (proc))
+       (process))
 {
-  CHECK_PROCESS (proc);
-  return XPROCESS (proc)->kill_without_query ? Qt : Qnil;
+  CHECK_PROCESS (process);
+  return XPROCESS (process)->kill_without_query ? Qt : Qnil;
 }
 
 \f
@@ -1968,19 +2045,32 @@ t or pty (pty) or stream (socket connection).
 void
 syms_of_process (void)
 {
+  INIT_LRECORD_IMPLEMENTATION (process);
+
   defsymbol (&Qprocessp, "processp");
+  defsymbol (&Qprocess_live_p, "process-live-p");
+#if 0
+  /* see comment at Fprocess_readable_p */
+  defsymbol (&Qprocess_readable_p, "process-readable-p");
+#endif
   defsymbol (&Qrun, "run");
   defsymbol (&Qstop, "stop");
   defsymbol (&Qopen, "open");
   defsymbol (&Qclosed, "closed");
 
-  defsymbol (&Qtcpip, "tcp/ip");
+  defsymbol (&Qtcp, "tcp");
+  defsymbol (&Qudp, "udp");
 
 #ifdef HAVE_MULTICAST
   defsymbol(&Qmulticast, "multicast"); /* Used for occasional warnings */
 #endif
 
   DEFSUBR (Fprocessp);
+  DEFSUBR (Fprocess_live_p);
+#if 0
+  /* see comment at Fprocess_readable_p */
+  DEFSUBR (Fprocess_readable_p);
+#endif
   DEFSUBR (Fget_process);
   DEFSUBR (Fget_buffer_process);
   DEFSUBR (Fdelete_process);
@@ -2010,6 +2100,7 @@ syms_of_process (void)
 #endif /* HAVE_SOCKETS */
   DEFSUBR (Fprocess_send_region);
   DEFSUBR (Fprocess_send_string);
+  DEFSUBR (Fprocess_send_signal);
   DEFSUBR (Finterrupt_process);
   DEFSUBR (Fkill_process);
   DEFSUBR (Fquit_process);
@@ -2047,6 +2138,22 @@ nil means don't delete them until `list-processes' is run.
 
   delete_exited_processes = 1;
 
+  DEFVAR_CONST_LISP ("null-device", &Vnull_device /*
+Name of the null device, which differs from system to system.
+The null device is a filename that acts as a sink for arbitrary amounts of
+data, which is discarded, or as a source for a zero-length file.
+It is available on all the systems that we currently support, but with
+different names (typically either `/dev/null' or `nul').
+
+Note that there is also a /dev/zero on most modern Unix versions (including
+Cygwin), which acts like /dev/null when used as a sink, but as a source
+it sends a non-ending stream of zero bytes.  It's used most often along
+with memory-mapping.  We don't provide a Lisp variable for this because
+the operations needing this are lower level than what ELisp programs
+typically do, and in any case no equivalent exists under native MS Windows.
+*/ );
+  Vnull_device = build_string (NULL_DEVICE);
+
   DEFVAR_LISP ("process-connection-type", &Vprocess_connection_type /*
 Control type of device used to communicate with subprocesses.
 Values are nil to use a pipe, or t or `pty' to use a pty.