(C6-3930): Add M-17478.
[chise/xemacs-chise.git-] / src / process.c
index c3b493a..5812151 100644 (file)
@@ -58,7 +58,7 @@ Boston, MA 02111-1307, USA.  */
 #include "systty.h"
 #include "syswait.h"
 
-Lisp_Object Qprocessp;
+Lisp_Object Qprocessp, Qprocess_live_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 */
@@ -107,26 +107,27 @@ struct hash_table *usid_to_process;
 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 obj)
+{
+  Lisp_Process *proc = XPROCESS (obj);
+  MAYBE_PROCMETH (mark_process_data, (proc));
+  mark_object (proc->name);
+  mark_object (proc->command);
+  mark_object (proc->filter);
+  mark_object (proc->sentinel);
+  mark_object (proc->buffer);
+  mark_object (proc->mark);
+  mark_object (proc->pid);
+  mark_object (proc->pipe_instream);
+  mark_object (proc->pipe_outstream);
 #ifdef FILE_CODING
-  markobj (proc->coding_instream);
-  markobj (proc->coding_outstream);
+  mark_object (proc->coding_instream);
+  mark_object (proc->coding_outstream);
 #endif
   return proc->status_symbol;
 }
@@ -134,7 +135,7 @@ mark_process (Lisp_Object obj, void (*markobj) (Lisp_Object))
 static void
 print_process (Lisp_Object obj, Lisp_Object printcharfun, int escapeflag)
 {
-  struct Lisp_Process *proc = XPROCESS (obj);
+  Lisp_Process *proc = XPROCESS (obj);
 
   if (print_readably)
     error ("printing unreadable object #<process %s>",
@@ -147,10 +148,10 @@ print_process (Lisp_Object obj, Lisp_Object printcharfun, int escapeflag)
   else
     {
       int netp = network_connection_p (obj);
-      write_c_string (((netp) ? GETTEXT ("#<network connection ") :
+      write_c_string ((netp ? GETTEXT ("#<network connection ") :
                       GETTEXT ("#<process ")), printcharfun);
       print_internal (proc->name, printcharfun, 1);
-      write_c_string (((netp) ? " " : " pid "), printcharfun);
+      write_c_string ((netp ? " " : " pid "), printcharfun);
       print_internal (proc->pid, printcharfun, 1);
       write_c_string (" state:", printcharfun);
       print_internal (proc->status_symbol, printcharfun, 1);
@@ -160,7 +161,7 @@ print_process (Lisp_Object obj, Lisp_Object printcharfun, int escapeflag)
 }
 
 #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
@@ -168,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)
     {
@@ -186,7 +187,7 @@ finalize_process (void *header, int for_disksave)
 
 DEFINE_LRECORD_IMPLEMENTATION ("process", process,
                                mark_process, print_process, finalize_process,
-                               0, 0, 0, struct Lisp_Process);
+                               0, 0, 0, Lisp_Process);
 \f
 /************************************************************************/
 /*                       basic process accessors                        */
@@ -196,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));
@@ -206,14 +206,14 @@ 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);
@@ -224,19 +224,19 @@ get_process_from_usid (USID usid)
 }
 
 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));
 }
@@ -245,7 +245,7 @@ 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
 
@@ -257,6 +257,14 @@ Return t if OBJECT is a process.
   return PROCESSP (obj) ? Qt : Qnil;
 }
 
+DEFUN ("process-live-p", Fprocess_live_p, 1, 1, 0, /*
+Return t if OBJECT is a process that is alive.
+*/
+       (obj))
+{
+  return PROCESSP (obj) && PROCESS_LIVE_P (XPROCESS (obj)) ? Qt : Qnil;
+}
+
 DEFUN ("process-list", Fprocess_list, 0, 0, 0, /*
 Return a list of all processes.
 */
@@ -272,7 +280,7 @@ Return the process named NAME, or nil if there is none.
 {
   Lisp_Object tail;
 
-  if (GC_PROCESSP (name))
+  if (PROCESSP (name))
     return name;
 
   if (!gc_in_progress)
@@ -280,7 +288,7 @@ Return the process named NAME, or nil if there is none.
        of a signal or crash. */
     CHECK_STRING (name);
 
-  for (tail = Vprocess_list; GC_CONSP (tail); tail = XCDR (tail))
+  for (tail = Vprocess_list; CONSP (tail); tail = XCDR (tail))
     {
       Lisp_Object proc = XCAR (tail);
       QUIT;
@@ -298,18 +306,18 @@ BUFFER may be a buffer or the name of one.
 {
   Lisp_Object buf, tail, proc;
 
-  if (GC_NILP (name)) return Qnil;
+  if (NILP (name)) return Qnil;
   buf = Fget_buffer (name);
-  if (GC_NILP (buf)) return Qnil;
+  if (NILP (buf)) return Qnil;
 
-  for (tail = Vprocess_list; GC_CONSP (tail); tail = XCDR (tail))
+  for (tail = Vprocess_list; 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))
+      if (PROCESSP (proc) && EQ (XPROCESS (proc)->buffer, buf))
        return proc;
     }
   return Qnil;
@@ -331,28 +339,28 @@ get_process (Lisp_Object name)
 
   /* This may be called during a GC from process_send_signal() from
      kill_buffer_processes() if emacs decides to abort(). */
-  if (GC_PROCESSP (name))
+  if (PROCESSP (name))
     return name;
 
-  if (GC_STRINGP (name))
+  if (STRINGP (name))
     {
       obj = Fget_process (name);
-      if (GC_NILP (obj))
+      if (NILP (obj))
         obj = Fget_buffer (name);
-      if (GC_NILP (obj))
+      if (NILP (obj))
         error ("Process %s does not exist", XSTRING_DATA (name));
     }
-  else if (GC_NILP (name))
+  else if (NILP (name))
     obj = Fcurrent_buffer ();
   else
     obj = name;
 
   /* Now obj should be either a buffer object or a process object.
    */
-  if (GC_BUFFERP (obj))
+  if (BUFFERP (obj))
     {
       proc = Fget_buffer_process (obj);
-      if (GC_NILP (proc))
+      if (NILP (proc))
        error ("Buffer %s has no process", XSTRING_DATA (XBUFFER(obj)->name));
     }
   else
@@ -416,8 +424,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;
@@ -464,7 +471,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,
@@ -477,7 +484,7 @@ init_process_io_handles (struct Lisp_Process *p, void* in, void* out, int flags)
     {
       Lisp_Object proc = Qnil;
       XSETPROCESS (proc, p);
-      puthash ((CONST void*)usid, LISP_TO_VOID (proc), usid_to_process);
+      puthash ((const void*)usid, LISP_TO_VOID (proc), usid_to_process);
     }
 
   MAYBE_PROCMETH (init_process_io_handles, (p, in, out, flags));
@@ -499,7 +506,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
@@ -510,7 +517,7 @@ 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_LIVE_P (p))
     event_stream_select_process (p);
 }
 
@@ -601,10 +608,24 @@ 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;
     }
 
+  if (!NILP (Ffile_directory_p (program)))
+    invalid_operation ("Specified program for new process is a directory",
+                      program);
+
   proc = make_process_internal (name);
 
   XPROCESS (proc)->buffer = buffer;
@@ -657,9 +678,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 subprocess-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.
@@ -671,10 +693,18 @@ BUFFER is the buffer (or buffer-name) to associate with the process.
 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.
+Fifth argument PROTOCOL is a network protocol.  Currently '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 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 */
@@ -682,17 +712,17 @@ Fifth argument FAMILY is a protocol family. When omitted, 'tcp/ip
   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))
@@ -716,7 +746,7 @@ Fifth argument FAMILY is a protocol family. When omitted, 'tcp/ip
 
 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 subprocess-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.
@@ -805,7 +835,7 @@ read_process_output (Lisp_Object proc)
   Bytecount nbytes, nchars;
   Bufbyte chars[1024];
   Lisp_Object outstream;
-  struct Lisp_Process *p = XPROCESS (proc);
+  Lisp_Process *p = XPROCESS (proc);
 
   /* If there is a lot of output from the subprocess, the loop in
      execute_internal_event() might call read_process_output() more
@@ -815,7 +845,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_LIVE_P (p))
     return -1; /* already closed */
 
   if (!NILP (p->filter) && (p->filter_does_read))
@@ -950,7 +980,7 @@ read_process_output (Lisp_Object proc)
 
 void
 send_process (Lisp_Object proc,
-              Lisp_Object relocatable, CONST Bufbyte *nonrelocatable,
+              Lisp_Object relocatable, const Bufbyte *nonrelocatable,
               int start, int len)
 {
   /* This function can GC */
@@ -965,7 +995,7 @@ send_process (Lisp_Object proc,
   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
@@ -1024,7 +1054,7 @@ void
 set_process_filter (Lisp_Object proc, Lisp_Object filter, int filter_does_read)
 {
   CHECK_PROCESS (proc);
-  if (PROCESS_LIVE_P (proc)) {
+  if (PROCESS_LIVE_P (XPROCESS (proc))) {
     if (EQ (filter, Qt))
       event_stream_unselect_process (XPROCESS (proc));
     else
@@ -1059,24 +1089,25 @@ See `set-process-filter' for more info on filter functions.
   return XPROCESS (proc)->filter;
 }
 
-DEFUN ("process-send-region", Fprocess_send_region, 3, 3, 0, /*
-Send current contents of region as input to PROCESS.
+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 name or an actual process.
-Called from program, takes three arguments, PROCESS, START and END.
+BUFFER specifies the buffer to look in; if nil, the current buffer is used.
 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.
 */
-       (process, start, end))
+       (process, start, end, buffer))
 {
   /* This function can GC */
   Lisp_Object proc = get_process (process);
   Bufpos st, en;
+  struct buffer *buf = decode_buffer (buffer, 0);
 
-  get_buffer_range_char (current_buffer, start, end, &st, &en, 0);
+  XSETBUFFER (buffer, buf);
+  get_buffer_range_char (buf, start, end, &st, &en, 0);
 
-  send_process (proc, Fcurrent_buffer (), 0,
-                st, en - st);
+  send_process (proc, buffer, 0, st, en - st);
   return Qnil;
 }
 
@@ -1113,6 +1144,7 @@ Return PROCESS's input coding system.
        (process))
 {
   process = get_process (process);
+  CHECK_LIVE_PROCESS (process);
   return decoding_stream_coding_system (XLSTREAM (XPROCESS (process)->coding_instream) );
 }
 
@@ -1122,6 +1154,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));
 }
 
@@ -1131,6 +1164,7 @@ Return a pair of coding-system for decoding and encoding of PROCESS.
        (process))
 {
   process = get_process (process);
+  CHECK_LIVE_PROCESS (process);
   return Fcons (decoding_stream_coding_system
                (XLSTREAM (XPROCESS (process)->coding_instream)),
                encoding_stream_coding_system
@@ -1145,6 +1179,8 @@ Set PROCESS's input coding system to CODESYS.
 {
   codesys = Fget_coding_system (codesys);
   process = get_process (process);
+  CHECK_LIVE_PROCESS (process);
+
   set_decoding_stream_coding_system
     (XLSTREAM (XPROCESS (process)->coding_instream), codesys);
   return Qnil;
@@ -1158,6 +1194,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;
@@ -1166,6 +1204,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))
 {
@@ -1187,7 +1227,7 @@ 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;
@@ -1198,7 +1238,7 @@ exec_sentinel (Lisp_Object proc, Lisp_Object reason)
 {
   /* This function can GC */
   int speccount = specpdl_depth ();
-  struct Lisp_Process *p = XPROCESS (proc);
+  Lisp_Process *p = XPROCESS (proc);
   Lisp_Object sentinel = p->sentinel;
 
   if (NILP (sentinel))
@@ -1243,13 +1283,13 @@ See `set-process-sentinel' for more info on sentinels.
 }
 
 \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
@@ -1268,7 +1308,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;
@@ -1352,7 +1392,7 @@ status_notify (void)
   for (tail = Vprocess_list; CONSP (tail); tail = XCDR (tail))
     {
       Lisp_Object proc = XCAR (tail);
-      struct Lisp_Process *p = XPROCESS (proc);
+      Lisp_Process *p = XPROCESS (proc);
       /* p->tick is also volatile.  Same thing as above applies. */
       int this_process_tick;
 
@@ -1498,135 +1538,23 @@ If PROCESS has not yet exited or died, return 0.
 
 \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))
+static int
+decode_signal (Lisp_Object signal_)
 {
-  /* 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))
-{
-  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 */
@@ -1760,14 +1688,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 */
+  Lisp_Object proc = get_process (process);
+
+  if (network_connection_p (proc))
+    error ("Network connection %s is not a subprocess",
+          XSTRING_DATA (XPROCESS(proc)->name));
+  CHECK_LIVE_PROCESS (proc);
+
+  MAYBE_PROCMETH (kill_child_process, (proc, 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, /*
@@ -1811,7 +1870,7 @@ text to PROCESS after you call this function.
 void
 deactivate_process (Lisp_Object proc)
 {
-  struct Lisp_Process *p = XPROCESS (proc);
+  Lisp_Process *p = XPROCESS (proc);
   USID usid;
 
   /* It's possible that we got as far in the process-creation
@@ -1838,7 +1897,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;
@@ -1864,7 +1923,7 @@ PROCESS may be a process or the name of one, or a buffer name.
        (proc))
 {
   /* This function can GC */
-  struct Lisp_Process *p;
+  Lisp_Process *p;
   proc = get_process (proc);
   p = XPROCESS (proc);
   if (network_connection_p (proc))
@@ -1875,7 +1934,7 @@ 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);
       /* Do this now, since remove_process will make sigchld_handler do nothing.  */
@@ -1898,16 +1957,16 @@ kill_buffer_processes (Lisp_Object buffer)
 {
   Lisp_Object tail;
 
-  for (tail = Vprocess_list; GC_CONSP (tail);
+  for (tail = Vprocess_list; CONSP (tail);
        tail = XCDR (tail))
     {
       Lisp_Object proc = XCAR (tail);
-      if (GC_PROCESSP (proc)
-         && (GC_NILP (buffer) || GC_EQ (XPROCESS (proc)->buffer, buffer)))
+      if (PROCESSP (proc)
+         && (NILP (buffer) || EQ (XPROCESS (proc)->buffer, buffer)))
        {
          if (network_connection_p (proc))
            Fdelete_process (proc);
-         else if (!NILP (XPROCESS (proc)->pipe_instream))
+         else if (PROCESS_LIVE_P (XPROCESS (proc)))
            process_send_signal (proc, SIGHUP, 0, 1);
        }
     }
@@ -1969,19 +2028,24 @@ 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");
   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);
   DEFSUBR (Fget_process);
   DEFSUBR (Fget_buffer_process);
   DEFSUBR (Fdelete_process);
@@ -2011,6 +2075,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);
@@ -2048,6 +2113,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.