aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/process.c3
-rw-r--r--src/process.c-dl4976
2 files changed, 4978 insertions, 1 deletions
diff --git a/src/process.c b/src/process.c
index 71e244fc7f..9fe2c5af94 100644
--- a/src/process.c
+++ b/src/process.c
@@ -1023,7 +1023,6 @@ static Lisp_Object start_process_unwind ();
DEFUN ("start-process", Fstart_process, Sstart_process, 3, MANY, 0,
"Start a program in a subprocess. Return the process object for it.\n\
-Args are NAME BUFFER PROGRAM &rest PROGRAM-ARGS\n\
NAME is name for process. It is modified if necessary to make it unique.\n\
BUFFER is the buffer or (buffer-name) to associate with the process.\n\
Process output goes at end of that buffer, unless you specify\n\
@@ -2835,6 +2834,7 @@ read_process_output_error_handler (error)
Vinhibit_quit = Qt;
update_echo_area ();
Fsleep_for (make_number (2), Qnil);
+ return Qt;
}
/* Read pending output from the process channel,
@@ -4263,6 +4263,7 @@ exec_sentinel_error_handler (error)
Vinhibit_quit = Qt;
update_echo_area ();
Fsleep_for (make_number (2), Qnil);
+ return Qt;
}
static void
diff --git a/src/process.c-dl b/src/process.c-dl
new file mode 100644
index 0000000000..58d2518016
--- /dev/null
+++ b/src/process.c-dl
@@ -0,0 +1,4976 @@
+/* Asynchronous subprocess control for GNU Emacs.
+ Copyright (C) 1985, 86, 87, 88, 93, 94, 95, 96, 98, 1999
+ Free Software Foundation, Inc.
+
+This file is part of GNU Emacs.
+
+GNU Emacs is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Emacs is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Emacs; see the file COPYING. If not, write to
+the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+
+#define _GNU_SOURCE /* to get strsignal declared with glibc 2 */
+#include <config.h>
+#include <signal.h>
+
+/* This file is split into two parts by the following preprocessor
+ conditional. The 'then' clause contains all of the support for
+ asynchronous subprocesses. The 'else' clause contains stub
+ versions of some of the asynchronous subprocess routines that are
+ often called elsewhere in Emacs, so we don't have to #ifdef the
+ sections that call them. */
+
+
+#ifdef subprocesses
+
+#include <stdio.h>
+#include <errno.h>
+#include <setjmp.h>
+#include <sys/types.h> /* some typedefs are used in sys/file.h */
+#include <sys/file.h>
+#include <sys/stat.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef WINDOWSNT
+#include <stdlib.h>
+#include <fcntl.h>
+#endif /* not WINDOWSNT */
+
+#ifdef HAVE_SOCKETS /* TCP connection support, if kernel can do it */
+#include <sys/socket.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#ifdef NEED_NET_ERRNO_H
+#include <net/errno.h>
+#endif /* NEED_NET_ERRNO_H */
+#endif /* HAVE_SOCKETS */
+
+/* TERM is a poor-man's SLIP, used on GNU/Linux. */
+#ifdef TERM
+#include <client.h>
+#endif
+
+/* On some systems, e.g. DGUX, inet_addr returns a 'struct in_addr'. */
+#ifdef HAVE_BROKEN_INET_ADDR
+#define IN_ADDR struct in_addr
+#define NUMERIC_ADDR_ERROR (numeric_addr.s_addr == -1)
+#else
+#define IN_ADDR unsigned long
+#define NUMERIC_ADDR_ERROR (numeric_addr == -1)
+#endif
+
+#if defined(BSD_SYSTEM) || defined(STRIDE)
+#include <sys/ioctl.h>
+#if !defined (O_NDELAY) && defined (HAVE_PTYS) && !defined(USG5)
+#include <fcntl.h>
+#endif /* HAVE_PTYS and no O_NDELAY */
+#endif /* BSD_SYSTEM || STRIDE */
+
+#ifdef BROKEN_O_NONBLOCK
+#undef O_NONBLOCK
+#endif /* BROKEN_O_NONBLOCK */
+
+#ifdef NEED_BSDTTY
+#include <bsdtty.h>
+#endif
+
+#ifdef IRIS
+#include <sys/sysmacros.h> /* for "minor" */
+#endif /* not IRIS */
+
+#include "systime.h"
+#include "systty.h"
+
+#include "lisp.h"
+#include "window.h"
+#include "buffer.h"
+#include "charset.h"
+#include "coding.h"
+#include "process.h"
+#include "termhooks.h"
+#include "termopts.h"
+#include "commands.h"
+#include "frame.h"
+#include "blockinput.h"
+#include "keyboard.h"
+#include "dispextern.h"
+#include "composite.h"
+#include "atimer.h"
+
+#define max(a, b) ((a) > (b) ? (a) : (b))
+
+Lisp_Object Qprocessp;
+Lisp_Object Qrun, Qstop, Qsignal, Qopen, Qclosed;
+Lisp_Object Qlast_nonmenu_event;
+/* Qexit is declared and initialized in eval.c. */
+
+/* a process object is a network connection when its childp field is neither
+ Qt nor Qnil but is instead a cons cell (HOSTNAME PORTNUM). */
+
+#ifdef HAVE_SOCKETS
+#define NETCONN_P(p) (GC_CONSP (XPROCESS (p)->childp))
+#else
+#define NETCONN_P(p) 0
+#endif /* HAVE_SOCKETS */
+
+/* Define first descriptor number available for subprocesses. */
+#ifdef VMS
+#define FIRST_PROC_DESC 1
+#else /* Not VMS */
+#define FIRST_PROC_DESC 3
+#endif
+
+/* Define SIGCHLD as an alias for SIGCLD. There are many conditionals
+ testing SIGCHLD. */
+
+#if !defined (SIGCHLD) && defined (SIGCLD)
+#define SIGCHLD SIGCLD
+#endif /* SIGCLD */
+
+#include "syssignal.h"
+
+#include "syswait.h"
+
+extern void set_waiting_for_input P_ ((EMACS_TIME *));
+
+extern int errno;
+#ifdef VMS
+extern char *sys_errlist[];
+#endif
+
+#ifndef HAVE_H_ERRNO
+extern int h_errno;
+#endif
+
+/* t means use pty, nil means use a pipe,
+ maybe other values to come. */
+static Lisp_Object Vprocess_connection_type;
+
+#ifdef SKTPAIR
+#ifndef HAVE_SOCKETS
+#include <sys/socket.h>
+#endif
+#endif /* SKTPAIR */
+
+/* These next two vars are non-static since sysdep.c uses them in the
+ emulation of `select'. */
+/* Number of events of change of status of a process. */
+int process_tick;
+/* Number of events for which the user or sentinel has been notified. */
+int update_tick;
+
+#include "sysselect.h"
+
+extern int keyboard_bit_set P_ ((SELECT_TYPE *));
+
+/* If we support a window system, turn on the code to poll periodically
+ to detect C-g. It isn't actually used when doing interrupt input. */
+#ifdef HAVE_WINDOW_SYSTEM
+#define POLL_FOR_INPUT
+#endif
+
+/* Mask of bits indicating the descriptors that we wait for input on. */
+
+static SELECT_TYPE input_wait_mask;
+
+/* Mask that excludes keyboard input descriptor (s). */
+
+static SELECT_TYPE non_keyboard_wait_mask;
+
+/* Mask that excludes process input descriptor (s). */
+
+static SELECT_TYPE non_process_wait_mask;
+
+/* The largest descriptor currently in use for a process object. */
+static int max_process_desc;
+
+/* The largest descriptor currently in use for keyboard input. */
+static int max_keyboard_desc;
+
+/* Nonzero means delete a process right away if it exits. */
+static int delete_exited_processes;
+
+/* Indexed by descriptor, gives the process (if any) for that descriptor */
+Lisp_Object chan_process[MAXDESC];
+
+/* Alist of elements (NAME . PROCESS) */
+Lisp_Object Vprocess_alist;
+
+/* Buffered-ahead input char from process, indexed by channel.
+ -1 means empty (no char is buffered).
+ Used on sys V where the only way to tell if there is any
+ output from the process is to read at least one char.
+ Always -1 on systems that support FIONREAD. */
+
+/* Don't make static; need to access externally. */
+int proc_buffered_char[MAXDESC];
+
+/* Table of `struct coding-system' for each process. */
+static struct coding_system *proc_decode_coding_system[MAXDESC];
+static struct coding_system *proc_encode_coding_system[MAXDESC];
+
+static Lisp_Object get_process ();
+
+extern EMACS_TIME timer_check ();
+extern int timers_run;
+
+/* Maximum number of bytes to send to a pty without an eof. */
+static int pty_max_bytes;
+
+extern Lisp_Object Vfile_name_coding_system, Vdefault_file_name_coding_system;
+
+#ifdef HAVE_PTYS
+/* The file name of the pty opened by allocate_pty. */
+
+static char pty_name[24];
+#endif
+
+/* Compute the Lisp form of the process status, p->status, from
+ the numeric status that was returned by `wait'. */
+
+Lisp_Object status_convert ();
+
+void
+update_status (p)
+ struct Lisp_Process *p;
+{
+ union { int i; WAITTYPE wt; } u;
+ u.i = XFASTINT (p->raw_status_low) + (XFASTINT (p->raw_status_high) << 16);
+ p->status = status_convert (u.wt);
+ p->raw_status_low = Qnil;
+ p->raw_status_high = Qnil;
+}
+
+/* Convert a process status word in Unix format to
+ the list that we use internally. */
+
+Lisp_Object
+status_convert (w)
+ WAITTYPE w;
+{
+ if (WIFSTOPPED (w))
+ return Fcons (Qstop, Fcons (make_number (WSTOPSIG (w)), Qnil));
+ else if (WIFEXITED (w))
+ return Fcons (Qexit, Fcons (make_number (WRETCODE (w)),
+ WCOREDUMP (w) ? Qt : Qnil));
+ else if (WIFSIGNALED (w))
+ return Fcons (Qsignal, Fcons (make_number (WTERMSIG (w)),
+ WCOREDUMP (w) ? Qt : Qnil));
+ else
+ return Qrun;
+}
+
+/* Given a status-list, extract the three pieces of information
+ and store them individually through the three pointers. */
+
+void
+decode_status (l, symbol, code, coredump)
+ Lisp_Object l;
+ Lisp_Object *symbol;
+ int *code;
+ int *coredump;
+{
+ Lisp_Object tem;
+
+ if (SYMBOLP (l))
+ {
+ *symbol = l;
+ *code = 0;
+ *coredump = 0;
+ }
+ else
+ {
+ *symbol = XCAR (l);
+ tem = XCDR (l);
+ *code = XFASTINT (XCAR (tem));
+ tem = XCDR (tem);
+ *coredump = !NILP (tem);
+ }
+}
+
+/* Return a string describing a process status list. */
+
+Lisp_Object
+status_message (status)
+ Lisp_Object status;
+{
+ Lisp_Object symbol;
+ int code, coredump;
+ Lisp_Object string, string2;
+
+ decode_status (status, &symbol, &code, &coredump);
+
+ if (EQ (symbol, Qsignal) || EQ (symbol, Qstop))
+ {
+ char *signame;
+ synchronize_system_messages_locale ();
+ signame = strsignal (code);
+ if (signame == 0)
+ signame = "unknown";
+ string = build_string (signame);
+ string2 = build_string (coredump ? " (core dumped)\n" : "\n");
+ XSTRING (string)->data[0] = DOWNCASE (XSTRING (string)->data[0]);
+ return concat2 (string, string2);
+ }
+ else if (EQ (symbol, Qexit))
+ {
+ if (code == 0)
+ return build_string ("finished\n");
+ string = Fnumber_to_string (make_number (code));
+ string2 = build_string (coredump ? " (core dumped)\n" : "\n");
+ return concat2 (build_string ("exited abnormally with code "),
+ concat2 (string, string2));
+ }
+ else
+ return Fcopy_sequence (Fsymbol_name (symbol));
+}
+
+#ifdef HAVE_PTYS
+
+/* Open an available pty, returning a file descriptor.
+ Return -1 on failure.
+ The file name of the terminal corresponding to the pty
+ is left in the variable pty_name. */
+
+int
+allocate_pty ()
+{
+ struct stat stb;
+ register int c, i;
+ int fd;
+
+ /* Some systems name their pseudoterminals so that there are gaps in
+ the usual sequence - for example, on HP9000/S700 systems, there
+ are no pseudoterminals with names ending in 'f'. So we wait for
+ three failures in a row before deciding that we've reached the
+ end of the ptys. */
+ int failed_count = 0;
+
+#ifdef PTY_ITERATION
+ PTY_ITERATION
+#else
+ for (c = FIRST_PTY_LETTER; c <= 'z'; c++)
+ for (i = 0; i < 16; i++)
+#endif
+ {
+#ifdef PTY_NAME_SPRINTF
+ PTY_NAME_SPRINTF
+#else
+ sprintf (pty_name, "/dev/pty%c%x", c, i);
+#endif /* no PTY_NAME_SPRINTF */
+
+#ifdef PTY_OPEN
+ PTY_OPEN;
+#else /* no PTY_OPEN */
+#ifdef IRIS
+ /* Unusual IRIS code */
+ *ptyv = emacs_open ("/dev/ptc", O_RDWR | O_NDELAY, 0);
+ if (fd < 0)
+ return -1;
+ if (fstat (fd, &stb) < 0)
+ return -1;
+#else /* not IRIS */
+ if (stat (pty_name, &stb) < 0)
+ {
+ failed_count++;
+ if (failed_count >= 3)
+ return -1;
+ }
+ else
+ failed_count = 0;
+#ifdef O_NONBLOCK
+ fd = emacs_open (pty_name, O_RDWR | O_NONBLOCK, 0);
+#else
+ fd = emacs_open (pty_name, O_RDWR | O_NDELAY, 0);
+#endif
+#endif /* not IRIS */
+#endif /* no PTY_OPEN */
+
+ if (fd >= 0)
+ {
+ /* check to make certain that both sides are available
+ this avoids a nasty yet stupid bug in rlogins */
+#ifdef PTY_TTY_NAME_SPRINTF
+ PTY_TTY_NAME_SPRINTF
+#else
+ sprintf (pty_name, "/dev/tty%c%x", c, i);
+#endif /* no PTY_TTY_NAME_SPRINTF */
+#ifndef UNIPLUS
+ if (access (pty_name, 6) != 0)
+ {
+ emacs_close (fd);
+#if !defined(IRIS) && !defined(__sgi)
+ continue;
+#else
+ return -1;
+#endif /* IRIS */
+ }
+#endif /* not UNIPLUS */
+ setup_pty (fd);
+ return fd;
+ }
+ }
+ return -1;
+}
+#endif /* HAVE_PTYS */
+
+Lisp_Object
+make_process (name)
+ Lisp_Object name;
+{
+ struct Lisp_Vector *vec;
+ register Lisp_Object val, tem, name1;
+ register struct Lisp_Process *p;
+ char suffix[10];
+ register int i;
+
+ vec = allocate_vectorlike ((EMACS_INT) VECSIZE (struct Lisp_Process));
+ for (i = 0; i < VECSIZE (struct Lisp_Process); i++)
+ vec->contents[i] = Qnil;
+ vec->size = VECSIZE (struct Lisp_Process);
+ p = (struct Lisp_Process *)vec;
+
+ XSETINT (p->infd, -1);
+ XSETINT (p->outfd, -1);
+ XSETFASTINT (p->pid, 0);
+ XSETFASTINT (p->tick, 0);
+ XSETFASTINT (p->update_tick, 0);
+ p->raw_status_low = Qnil;
+ p->raw_status_high = Qnil;
+ p->status = Qrun;
+ p->mark = Fmake_marker ();
+
+ /* If name is already in use, modify it until it is unused. */
+
+ name1 = name;
+ for (i = 1; ; i++)
+ {
+ tem = Fget_process (name1);
+ if (NILP (tem)) break;
+ sprintf (suffix, "<%d>", i);
+ name1 = concat2 (name, build_string (suffix));
+ }
+ name = name1;
+ p->name = name;
+ XSETPROCESS (val, p);
+ Vprocess_alist = Fcons (Fcons (name, val), Vprocess_alist);
+ return val;
+}
+
+void
+remove_process (proc)
+ register Lisp_Object proc;
+{
+ register Lisp_Object pair;
+
+ pair = Frassq (proc, Vprocess_alist);
+ Vprocess_alist = Fdelq (pair, Vprocess_alist);
+
+ deactivate_process (proc);
+}
+
+DEFUN ("processp", Fprocessp, Sprocessp, 1, 1, 0,
+ "Return t if OBJECT is a process.")
+ (object)
+ Lisp_Object object;
+{
+ return PROCESSP (object) ? Qt : Qnil;
+}
+
+DEFUN ("get-process", Fget_process, Sget_process, 1, 1, 0,
+ "Return the process named NAME, or nil if there is none.")
+ (name)
+ register Lisp_Object name;
+{
+ if (PROCESSP (name))
+ return name;
+ CHECK_STRING (name, 0);
+ return Fcdr (Fassoc (name, Vprocess_alist));
+}
+
+DEFUN ("get-buffer-process", Fget_buffer_process, Sget_buffer_process, 1, 1, 0,
+ "Return the (or a) process associated with BUFFER.\n\
+BUFFER may be a buffer or the name of one.")
+ (buffer)
+ register Lisp_Object buffer;
+{
+ register Lisp_Object buf, tail, proc;
+
+ if (NILP (buffer)) return Qnil;
+ buf = Fget_buffer (buffer);
+ if (NILP (buf)) return Qnil;
+
+ for (tail = Vprocess_alist; !NILP (tail); tail = Fcdr (tail))
+ {
+ proc = Fcdr (Fcar (tail));
+ if (PROCESSP (proc) && EQ (XPROCESS (proc)->buffer, buf))
+ return proc;
+ }
+ return Qnil;
+}
+
+/* This is how commands for the user decode process arguments. It
+ accepts a process, a process name, a buffer, a buffer name, or nil.
+ Buffers denote the first process in the buffer, and nil denotes the
+ current buffer. */
+
+static Lisp_Object
+get_process (name)
+ register Lisp_Object name;
+{
+ register Lisp_Object proc, obj;
+ if (STRINGP (name))
+ {
+ obj = Fget_process (name);
+ if (NILP (obj))
+ obj = Fget_buffer (name);
+ if (NILP (obj))
+ error ("Process %s does not exist", XSTRING (name)->data);
+ }
+ else if (NILP (name))
+ obj = Fcurrent_buffer ();
+ else
+ obj = name;
+
+ /* Now obj should be either a buffer object or a process object.
+ */
+ if (BUFFERP (obj))
+ {
+ proc = Fget_buffer_process (obj);
+ if (NILP (proc))
+ error ("Buffer %s has no process", XSTRING (XBUFFER (obj)->name)->data);
+ }
+ else
+ {
+ CHECK_PROCESS (obj, 0);
+ proc = obj;
+ }
+ return proc;
+}
+
+DEFUN ("delete-process", Fdelete_process, Sdelete_process, 1, 1, 0,
+ "Delete PROCESS: kill it and forget about it immediately.\n\
+PROCESS may be a process, a buffer, the name of a process or buffer, or\n\
+nil, indicating the current buffer's process.")
+ (process)
+ register Lisp_Object process;
+{
+ process = get_process (process);
+ XPROCESS (process)->raw_status_low = Qnil;
+ XPROCESS (process)->raw_status_high = Qnil;
+ if (NETCONN_P (process))
+ {
+ XPROCESS (process)->status = Fcons (Qexit, Fcons (make_number (0), Qnil));
+ XSETINT (XPROCESS (process)->tick, ++process_tick);
+ }
+ else if (XINT (XPROCESS (process)->infd) >= 0)
+ {
+ Fkill_process (process, Qnil);
+ /* Do this now, since remove_process will make sigchld_handler do nothing. */
+ XPROCESS (process)->status
+ = Fcons (Qsignal, Fcons (make_number (SIGKILL), Qnil));
+ XSETINT (XPROCESS (process)->tick, ++process_tick);
+ status_notify ();
+ }
+ remove_process (process);
+ return Qnil;
+}
+
+DEFUN ("process-status", Fprocess_status, Sprocess_status, 1, 1, 0,
+ "Return the status of PROCESS.\n\
+The returned value is one of the following symbols:\n\
+run -- for a process that is running.\n\
+stop -- for a process stopped but continuable.\n\
+exit -- for a process that has exited.\n\
+signal -- for a process that has got a fatal signal.\n\
+open -- for a network stream connection that is open.\n\
+closed -- for a network stream connection that is closed.\n\
+nil -- if arg is a process name and no such process exists.\n\
+PROCESS may be a process, a buffer, the name of a process, or\n\
+nil, indicating the current buffer's process.")
+ (process)
+ register Lisp_Object process;
+{
+ register struct Lisp_Process *p;
+ register Lisp_Object status;
+
+ if (STRINGP (process))
+ process = Fget_process (process);
+ else
+ process = get_process (process);
+
+ if (NILP (process))
+ return process;
+
+ p = XPROCESS (process);
+ if (!NILP (p->raw_status_low))
+ update_status (p);
+ status = p->status;
+ if (CONSP (status))
+ status = XCAR (status);
+ if (NETCONN_P (process))
+ {
+ if (EQ (status, Qrun))
+ status = Qopen;
+ else if (EQ (status, Qexit))
+ status = Qclosed;
+ }
+ return status;
+}
+
+DEFUN ("process-exit-status", Fprocess_exit_status, Sprocess_exit_status,
+ 1, 1, 0,
+ "Return the exit status of PROCESS or the signal number that killed it.\n\
+If PROCESS has not yet exited or died, return 0.")
+ (process)
+ register Lisp_Object process;
+{
+ CHECK_PROCESS (process, 0);
+ if (!NILP (XPROCESS (process)->raw_status_low))
+ update_status (XPROCESS (process));
+ if (CONSP (XPROCESS (process)->status))
+ return XCAR (XCDR (XPROCESS (process)->status));
+ return make_number (0);
+}
+
+DEFUN ("process-id", Fprocess_id, Sprocess_id, 1, 1, 0,
+ "Return the process id of PROCESS.\n\
+This is the pid of the Unix process which PROCESS uses or talks to.\n\
+For a network connection, this value is nil.")
+ (process)
+ register Lisp_Object process;
+{
+ CHECK_PROCESS (process, 0);
+ return XPROCESS (process)->pid;
+}
+
+DEFUN ("process-name", Fprocess_name, Sprocess_name, 1, 1, 0,
+ "Return the name of PROCESS, as a string.\n\
+This is the name of the program invoked in PROCESS,\n\
+possibly modified to make it unique among process names.")
+ (process)
+ register Lisp_Object process;
+{
+ CHECK_PROCESS (process, 0);
+ return XPROCESS (process)->name;
+}
+
+DEFUN ("process-command", Fprocess_command, Sprocess_command, 1, 1, 0,
+ "Return the command that was executed to start PROCESS.\n\
+This is a list of strings, the first string being the program executed\n\
+and the rest of the strings being the arguments given to it.\n\
+For a non-child channel, this is nil.")
+ (process)
+ register Lisp_Object process;
+{
+ CHECK_PROCESS (process, 0);
+ return XPROCESS (process)->command;
+}
+
+DEFUN ("process-tty-name", Fprocess_tty_name, Sprocess_tty_name, 1, 1, 0,
+ "Return the name of the terminal PROCESS uses, or nil if none.\n\
+This is the terminal that the process itself reads and writes on,\n\
+not the name of the pty that Emacs uses to talk with that terminal.")
+ (process)
+ register Lisp_Object process;
+{
+ CHECK_PROCESS (process, 0);
+ return XPROCESS (process)->tty_name;
+}
+
+DEFUN ("set-process-buffer", Fset_process_buffer, Sset_process_buffer,
+ 2, 2, 0,
+ "Set buffer associated with PROCESS to BUFFER (a buffer, or nil).")
+ (process, buffer)
+ register Lisp_Object process, buffer;
+{
+ CHECK_PROCESS (process, 0);
+ if (!NILP (buffer))
+ CHECK_BUFFER (buffer, 1);
+ XPROCESS (process)->buffer = buffer;
+ return buffer;
+}
+
+DEFUN ("process-buffer", Fprocess_buffer, Sprocess_buffer,
+ 1, 1, 0,
+ "Return the buffer PROCESS is associated with.\n\
+Output from PROCESS is inserted in this buffer unless PROCESS has a filter.")
+ (process)
+ register Lisp_Object process;
+{
+ CHECK_PROCESS (process, 0);
+ return XPROCESS (process)->buffer;
+}
+
+DEFUN ("process-mark", Fprocess_mark, Sprocess_mark,
+ 1, 1, 0,
+ "Return the marker for the end of the last output from PROCESS.")
+ (process)
+ register Lisp_Object process;
+{
+ CHECK_PROCESS (process, 0);
+ return XPROCESS (process)->mark;
+}
+
+DEFUN ("set-process-filter", Fset_process_filter, Sset_process_filter,
+ 2, 2, 0,
+ "Give PROCESS the filter function FILTER; nil means no filter.\n\
+t means stop accepting output from the process.\n\
+When a process has a filter, each time it does output\n\
+the entire string of output is passed to the filter.\n\
+The filter gets two arguments: the process and the string of output.\n\
+If the process has a filter, its buffer is not used for output.")
+ (process, filter)
+ register Lisp_Object process, filter;
+{
+ CHECK_PROCESS (process, 0);
+ if (EQ (filter, Qt))
+ {
+ FD_CLR (XINT (XPROCESS (process)->infd), &input_wait_mask);
+ FD_CLR (XINT (XPROCESS (process)->infd), &non_keyboard_wait_mask);
+ }
+ else if (EQ (XPROCESS (process)->filter, Qt))
+ {
+ FD_SET (XINT (XPROCESS (process)->infd), &input_wait_mask);
+ FD_SET (XINT (XPROCESS (process)->infd), &non_keyboard_wait_mask);
+ }
+ XPROCESS (process)->filter = filter;
+ return filter;
+}
+
+DEFUN ("process-filter", Fprocess_filter, Sprocess_filter,
+ 1, 1, 0,
+ "Returns the filter function of PROCESS; nil if none.\n\
+See `set-process-filter' for more info on filter functions.")
+ (process)
+ register Lisp_Object process;
+{
+ CHECK_PROCESS (process, 0);
+ return XPROCESS (process)->filter;
+}
+
+DEFUN ("set-process-sentinel", Fset_process_sentinel, Sset_process_sentinel,
+ 2, 2, 0,
+ "Give PROCESS the sentinel SENTINEL; nil for none.\n\
+The sentinel is called as a function when the process changes state.\n\
+It gets two arguments: the process, and a string describing the change.")
+ (process, sentinel)
+ register Lisp_Object process, sentinel;
+{
+ CHECK_PROCESS (process, 0);
+ XPROCESS (process)->sentinel = sentinel;
+ return sentinel;
+}
+
+DEFUN ("process-sentinel", Fprocess_sentinel, Sprocess_sentinel,
+ 1, 1, 0,
+ "Return the sentinel of PROCESS; nil if none.\n\
+See `set-process-sentinel' for more info on sentinels.")
+ (process)
+ register Lisp_Object process;
+{
+ CHECK_PROCESS (process, 0);
+ return XPROCESS (process)->sentinel;
+}
+
+DEFUN ("set-process-window-size", Fset_process_window_size,
+ Sset_process_window_size, 3, 3, 0,
+ "Tell PROCESS that it has logical window size HEIGHT and WIDTH.")
+ (process, height, width)
+ register Lisp_Object process, height, width;
+{
+ CHECK_PROCESS (process, 0);
+ CHECK_NATNUM (height, 0);
+ CHECK_NATNUM (width, 0);
+ if (set_window_size (XINT (XPROCESS (process)->infd),
+ XINT (height), XINT (width)) <= 0)
+ return Qnil;
+ else
+ return Qt;
+}
+
+DEFUN ("set-process-inherit-coding-system-flag",
+ Fset_process_inherit_coding_system_flag,
+ Sset_process_inherit_coding_system_flag, 2, 2, 0,
+ "Determine whether buffer of PROCESS will inherit coding-system.\n\
+If the second argument FLAG is non-nil, then the variable\n\
+`buffer-file-coding-system' of the buffer associated with PROCESS\n\
+will be bound to the value of the coding system used to decode\n\
+the process output.\n\
+\n\
+This is useful when the coding system specified for the process buffer\n\
+leaves either the character code conversion or the end-of-line conversion\n\
+unspecified, or if the coding system used to decode the process output\n\
+is more appropriate for saving the process buffer.\n\
+\n\
+Binding the variable `inherit-process-coding-system' to non-nil before\n\
+starting the process is an alternative way of setting the inherit flag\n\
+for the process which will run.")
+ (process, flag)
+ register Lisp_Object process, flag;
+{
+ CHECK_PROCESS (process, 0);
+ XPROCESS (process)->inherit_coding_system_flag = flag;
+ return flag;
+}
+
+DEFUN ("process-inherit-coding-system-flag",
+ Fprocess_inherit_coding_system_flag, Sprocess_inherit_coding_system_flag,
+ 1, 1, 0,
+ "Return the value of inherit-coding-system flag for PROCESS.\n\
+If this flag is t, `buffer-file-coding-system' of the buffer\n\
+associated with PROCESS will inherit the coding system used to decode\n\
+the process output.")
+ (process)
+ register Lisp_Object process;
+{
+ CHECK_PROCESS (process, 0);
+ return XPROCESS (process)->inherit_coding_system_flag;
+}
+
+DEFUN ("process-kill-without-query", Fprocess_kill_without_query,
+ Sprocess_kill_without_query, 1, 2, 0,
+ "Say no query needed if PROCESS is running when Emacs is exited.\n\
+Optional second argument if non-nil says to require a query.\n\
+Value is t if a query was formerly required.")
+ (process, value)
+ register Lisp_Object process, value;
+{
+ Lisp_Object tem;
+
+ CHECK_PROCESS (process, 0);
+ tem = XPROCESS (process)->kill_without_query;
+ XPROCESS (process)->kill_without_query = Fnull (value);
+
+ return Fnull (tem);
+}
+
+DEFUN ("process-contact", Fprocess_contact, Sprocess_contact,
+ 1, 1, 0,
+ "Return the contact info of PROCESS; t for a real child.\n\
+For a net connection, the value is a cons cell of the form (HOST SERVICE).")
+ (process)
+ register Lisp_Object process;
+{
+ CHECK_PROCESS (process, 0);
+ return XPROCESS (process)->childp;
+}
+
+#if 0 /* Turned off because we don't currently record this info
+ in the process. Perhaps add it. */
+DEFUN ("process-connection", Fprocess_connection, Sprocess_connection, 1, 1, 0,
+ "Return the connection type of PROCESS.\n\
+The value is nil for a pipe, t or `pty' for a pty, or `stream' for\n\
+a socket connection.")
+ (process)
+ Lisp_Object process;
+{
+ return XPROCESS (process)->type;
+}
+#endif
+
+Lisp_Object
+list_processes_1 ()
+{
+ register Lisp_Object tail, tem;
+ Lisp_Object proc, minspace, tem1;
+ register struct Lisp_Process *p;
+ char tembuf[80];
+
+ XSETFASTINT (minspace, 1);
+
+ set_buffer_internal (XBUFFER (Vstandard_output));
+ Fbuffer_disable_undo (Vstandard_output);
+
+ current_buffer->truncate_lines = Qt;
+
+ write_string ("\
+Proc Status Buffer Tty Command\n\
+---- ------ ------ --- -------\n", -1);
+
+ for (tail = Vprocess_alist; !NILP (tail); tail = Fcdr (tail))
+ {
+ Lisp_Object symbol;
+
+ proc = Fcdr (Fcar (tail));
+ p = XPROCESS (proc);
+ if (NILP (p->childp))
+ continue;
+
+ Finsert (1, &p->name);
+ Findent_to (make_number (13), minspace);
+
+ if (!NILP (p->raw_status_low))
+ update_status (p);
+ symbol = p->status;
+ if (CONSP (p->status))
+ symbol = XCAR (p->status);
+
+
+ if (EQ (symbol, Qsignal))
+ {
+ Lisp_Object tem;
+ tem = Fcar (Fcdr (p->status));
+#ifdef VMS
+ if (XINT (tem) < NSIG)
+ write_string (sys_errlist [XINT (tem)], -1);
+ else
+#endif
+ Fprinc (symbol, Qnil);
+ }
+ else if (NETCONN_P (proc))
+ {
+ if (EQ (symbol, Qrun))
+ write_string ("open", -1);
+ else if (EQ (symbol, Qexit))
+ write_string ("closed", -1);
+ else
+ Fprinc (symbol, Qnil);
+ }
+ else
+ Fprinc (symbol, Qnil);
+
+ if (EQ (symbol, Qexit))
+ {
+ Lisp_Object tem;
+ tem = Fcar (Fcdr (p->status));
+ if (XFASTINT (tem))
+ {
+ sprintf (tembuf, " %d", (int) XFASTINT (tem));
+ write_string (tembuf, -1);
+ }
+ }
+
+ if (EQ (symbol, Qsignal) || EQ (symbol, Qexit))
+ remove_process (proc);
+
+ Findent_to (make_number (22), minspace);
+ if (NILP (p->buffer))
+ insert_string ("(none)");
+ else if (NILP (XBUFFER (p->buffer)->name))
+ insert_string ("(Killed)");
+ else
+ Finsert (1, &XBUFFER (p->buffer)->name);
+
+ Findent_to (make_number (37), minspace);
+
+ if (STRINGP (p->tty_name))
+ Finsert (1, &p->tty_name);
+ else
+ insert_string ("(none)");
+
+ Findent_to (make_number (49), minspace);
+
+ if (NETCONN_P (proc))
+ {
+ sprintf (tembuf, "(network stream connection to %s)\n",
+ XSTRING (XCAR (p->childp))->data);
+ insert_string (tembuf);
+ }
+ else
+ {
+ tem = p->command;
+ while (1)
+ {
+ tem1 = Fcar (tem);
+ Finsert (1, &tem1);
+ tem = Fcdr (tem);
+ if (NILP (tem))
+ break;
+ insert_string (" ");
+ }
+ insert_string ("\n");
+ }
+ }
+ return Qnil;
+}
+
+DEFUN ("list-processes", Flist_processes, Slist_processes, 0, 0, "",
+ "Display a list of all processes.\n\
+Any process listed as exited or signaled is actually eliminated\n\
+after the listing is made.")
+ ()
+{
+ internal_with_output_to_temp_buffer ("*Process List*",
+ list_processes_1, Qnil);
+ return Qnil;
+}
+
+DEFUN ("process-list", Fprocess_list, Sprocess_list, 0, 0, 0,
+ "Return a list of all processes.")
+ ()
+{
+ return Fmapcar (Qcdr, Vprocess_alist);
+}
+
+/* Starting asynchronous inferior processes. */
+
+static Lisp_Object start_process_unwind ();
+
+DEFUN ("start-process", Fstart_process, Sstart_process, 3, MANY, 0,
+ "Start a program in a subprocess. Return the process object for it.\n\
+NAME is name for process. It is modified if necessary to make it unique.\n\
+BUFFER is the buffer or (buffer-name) to associate with the process.\n\
+ Process output goes at end of that buffer, unless you specify\n\
+ an output stream or filter function to handle the output.\n\
+ BUFFER may be also nil, meaning that this process is not associated\n\
+ with any buffer.\n\
+Third arg is program file name. It is searched for in PATH.\n\
+Remaining arguments are strings to give program as arguments.")
+ (nargs, args)
+ int nargs;
+ register Lisp_Object *args;
+{
+ Lisp_Object buffer, name, program, proc, current_dir, tem;
+#ifdef VMS
+ register unsigned char *new_argv;
+ int len;
+#else
+ register unsigned char **new_argv;
+#endif
+ register int i;
+ int count = specpdl_ptr - specpdl;
+
+ buffer = args[1];
+ if (!NILP (buffer))
+ buffer = Fget_buffer_create (buffer);
+
+ /* Make sure that the child will be able to chdir to the current
+ buffer's current directory, or its unhandled equivalent. We
+ can't just have the child check for an error when it does the
+ chdir, since it's in a vfork.
+
+ We have to GCPRO around this because Fexpand_file_name and
+ Funhandled_file_name_directory might call a file name handling
+ function. The argument list is protected by the caller, so all
+ we really have to worry about is buffer. */
+ {
+ struct gcpro gcpro1, gcpro2;
+
+ current_dir = current_buffer->directory;
+
+ GCPRO2 (buffer, current_dir);
+
+ current_dir
+ = expand_and_dir_to_file (Funhandled_file_name_directory (current_dir),
+ Qnil);
+ if (NILP (Ffile_accessible_directory_p (current_dir)))
+ report_file_error ("Setting current directory",
+ Fcons (current_buffer->directory, Qnil));
+
+ UNGCPRO;
+ }
+
+ name = args[0];
+ CHECK_STRING (name, 0);
+
+ program = args[2];
+
+ CHECK_STRING (program, 2);
+
+#ifdef VMS
+ /* Make a one member argv with all args concatenated
+ together separated by a blank. */
+ len = STRING_BYTES (XSTRING (program)) + 2;
+ for (i = 3; i < nargs; i++)
+ {
+ tem = args[i];
+ CHECK_STRING (tem, i);
+ len += STRING_BYTES (XSTRING (tem)) + 1; /* count the blank */
+ }
+ new_argv = (unsigned char *) alloca (len);
+ strcpy (new_argv, XSTRING (program)->data);
+ for (i = 3; i < nargs; i++)
+ {
+ tem = args[i];
+ CHECK_STRING (tem, i);
+ strcat (new_argv, " ");
+ strcat (new_argv, XSTRING (tem)->data);
+ }
+ /* Need to add code here to check for program existence on VMS */
+
+#else /* not VMS */
+ new_argv = (unsigned char **) alloca ((nargs - 1) * sizeof (char *));
+
+ /* If program file name is not absolute, search our path for it */
+ if (!IS_DIRECTORY_SEP (XSTRING (program)->data[0])
+ && !(XSTRING (program)->size > 1
+ && IS_DEVICE_SEP (XSTRING (program)->data[1])))
+ {
+ struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
+
+ tem = Qnil;
+ GCPRO4 (name, program, buffer, current_dir);
+ openp (Vexec_path, program, EXEC_SUFFIXES, &tem, 1);
+ UNGCPRO;
+ if (NILP (tem))
+ report_file_error ("Searching for program", Fcons (program, Qnil));
+ tem = Fexpand_file_name (tem, Qnil);
+ new_argv[0] = XSTRING (tem)->data;
+ }
+ else
+ {
+ if (!NILP (Ffile_directory_p (program)))
+ error ("Specified program for new process is a directory");
+
+ new_argv[0] = XSTRING (program)->data;
+ }
+
+ for (i = 3; i < nargs; i++)
+ {
+ tem = args[i];
+ CHECK_STRING (tem, i);
+ new_argv[i - 2] = XSTRING (tem)->data;
+ }
+ new_argv[i - 2] = 0;
+#endif /* not VMS */
+
+ proc = make_process (name);
+ /* 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);
+
+ XPROCESS (proc)->childp = Qt;
+ XPROCESS (proc)->command_channel_p = Qnil;
+ XPROCESS (proc)->buffer = buffer;
+ XPROCESS (proc)->sentinel = Qnil;
+ XPROCESS (proc)->filter = Qnil;
+ XPROCESS (proc)->command = Flist (nargs - 2, args + 2);
+
+ /* Make the process marker point into the process buffer (if any). */
+ if (!NILP (buffer))
+ set_marker_both (XPROCESS (proc)->mark, buffer,
+ BUF_ZV (XBUFFER (buffer)),
+ BUF_ZV_BYTE (XBUFFER (buffer)));
+
+ {
+ /* Decide coding systems for communicating with the process. Here
+ we don't setup the structure coding_system nor pay attention to
+ unibyte mode. They are done in create_process. */
+
+ /* Qt denotes we have not yet called Ffind_operation_coding_system. */
+ Lisp_Object coding_systems = Qt;
+ Lisp_Object val, *args2;
+ struct gcpro gcpro1;
+
+ val = Vcoding_system_for_read;
+ if (NILP (val))
+ {
+ args2 = (Lisp_Object *) alloca ((nargs + 1) * sizeof *args2);
+ args2[0] = Qstart_process;
+ for (i = 0; i < nargs; i++) args2[i + 1] = args[i];
+ GCPRO1 (proc);
+ coding_systems = Ffind_operation_coding_system (nargs + 1, args2);
+ UNGCPRO;
+ if (CONSP (coding_systems))
+ val = XCAR (coding_systems);
+ else if (CONSP (Vdefault_process_coding_system))
+ val = XCAR (Vdefault_process_coding_system);
+ }
+ XPROCESS (proc)->decode_coding_system = val;
+
+ val = Vcoding_system_for_write;
+ if (NILP (val))
+ {
+ if (EQ (coding_systems, Qt))
+ {
+ args2 = (Lisp_Object *) alloca ((nargs + 1) * sizeof args2);
+ args2[0] = Qstart_process;
+ for (i = 0; i < nargs; i++) args2[i + 1] = args[i];
+ GCPRO1 (proc);
+ coding_systems = Ffind_operation_coding_system (nargs + 1, args2);
+ UNGCPRO;
+ }
+ if (CONSP (coding_systems))
+ val = XCDR (coding_systems);
+ else if (CONSP (Vdefault_process_coding_system))
+ val = XCDR (Vdefault_process_coding_system);
+ }
+ XPROCESS (proc)->encode_coding_system = val;
+ }
+
+ XPROCESS (proc)->decoding_buf = make_uninit_string (0);
+ XPROCESS (proc)->decoding_carryover = make_number (0);
+ XPROCESS (proc)->encoding_buf = make_uninit_string (0);
+ XPROCESS (proc)->encoding_carryover = make_number (0);
+
+ XPROCESS (proc)->inherit_coding_system_flag
+ = (NILP (buffer) || !inherit_process_coding_system
+ ? Qnil : Qt);
+
+ create_process (proc, (char **) new_argv, current_dir);
+
+ return unbind_to (count, proc);
+}
+
+/* This function is the unwind_protect form for Fstart_process. If
+ PROC doesn't have its pid set, then we know someone has signaled
+ an error and the process wasn't started successfully, so we should
+ remove it from the process list. */
+static Lisp_Object
+start_process_unwind (proc)
+ Lisp_Object proc;
+{
+ if (!PROCESSP (proc))
+ abort ();
+
+ /* Was PROC started successfully? */
+ if (XINT (XPROCESS (proc)->pid) <= 0)
+ remove_process (proc);
+
+ return Qnil;
+}
+
+void
+create_process_1 (timer)
+ struct atimer *timer;
+{
+ /* Nothing to do. */
+}
+
+
+#if 0 /* This doesn't work; see the note before sigchld_handler. */
+#ifdef USG
+#ifdef SIGCHLD
+/* Mimic blocking of signals on system V, which doesn't really have it. */
+
+/* Nonzero means we got a SIGCHLD when it was supposed to be blocked. */
+int sigchld_deferred;
+
+SIGTYPE
+create_process_sigchld ()
+{
+ signal (SIGCHLD, create_process_sigchld);
+
+ sigchld_deferred = 1;
+}
+#endif
+#endif
+#endif
+
+#ifndef VMS /* VMS version of this function is in vmsproc.c. */
+void
+create_process (process, new_argv, current_dir)
+ Lisp_Object process;
+ char **new_argv;
+ Lisp_Object current_dir;
+{
+ int pid, inchannel, outchannel;
+ int sv[2];
+#ifdef POSIX_SIGNALS
+ sigset_t procmask;
+ sigset_t blocked;
+ struct sigaction sigint_action;
+ struct sigaction sigquit_action;
+#ifdef AIX
+ struct sigaction sighup_action;
+#endif
+#else /* !POSIX_SIGNALS */
+#if 0
+#ifdef SIGCHLD
+ SIGTYPE (*sigchld)();
+#endif
+#endif /* 0 */
+#endif /* !POSIX_SIGNALS */
+ /* Use volatile to protect variables from being clobbered by longjmp. */
+ volatile int forkin, forkout;
+ volatile int pty_flag = 0;
+ extern char **environ;
+ Lisp_Object buffer = XPROCESS (process)->buffer;
+
+ inchannel = outchannel = -1;
+
+#ifdef HAVE_PTYS
+ if (!NILP (Vprocess_connection_type))
+ outchannel = inchannel = allocate_pty ();
+
+ if (inchannel >= 0)
+ {
+#ifndef USG
+ /* On USG systems it does not work to open the pty's tty here
+ and then close and reopen it in the child. */
+#ifdef O_NOCTTY
+ /* Don't let this terminal become our controlling terminal
+ (in case we don't have one). */
+ forkout = forkin = emacs_open (pty_name, O_RDWR | O_NOCTTY, 0);
+#else
+ forkout = forkin = emacs_open (pty_name, O_RDWR, 0);
+#endif
+ if (forkin < 0)
+ report_file_error ("Opening pty", Qnil);
+#else
+ forkin = forkout = -1;
+#endif /* not USG */
+ pty_flag = 1;
+ }
+ else
+#endif /* HAVE_PTYS */
+#ifdef SKTPAIR
+ {
+ if (socketpair (AF_UNIX, SOCK_STREAM, 0, sv) < 0)
+ report_file_error ("Opening socketpair", Qnil);
+ outchannel = inchannel = sv[0];
+ forkout = forkin = sv[1];
+ }
+#else /* not SKTPAIR */
+ {
+ int tem;
+ tem = pipe (sv);
+ if (tem < 0)
+ report_file_error ("Creating pipe", Qnil);
+ inchannel = sv[0];
+ forkout = sv[1];
+ tem = pipe (sv);
+ if (tem < 0)
+ {
+ emacs_close (inchannel);
+ emacs_close (forkout);
+ report_file_error ("Creating pipe", Qnil);
+ }
+ outchannel = sv[1];
+ forkin = sv[0];
+ }
+#endif /* not SKTPAIR */
+
+#if 0
+ /* Replaced by close_process_descs */
+ set_exclusive_use (inchannel);
+ set_exclusive_use (outchannel);
+#endif
+
+/* Stride people say it's a mystery why this is needed
+ as well as the O_NDELAY, but that it fails without this. */
+#if defined (STRIDE) || (defined (pfa) && defined (HAVE_PTYS))
+ {
+ int one = 1;
+ ioctl (inchannel, FIONBIO, &one);
+ }
+#endif
+
+#ifdef O_NONBLOCK
+ fcntl (inchannel, F_SETFL, O_NONBLOCK);
+ fcntl (outchannel, F_SETFL, O_NONBLOCK);
+#else
+#ifdef O_NDELAY
+ fcntl (inchannel, F_SETFL, O_NDELAY);
+ fcntl (outchannel, F_SETFL, O_NDELAY);
+#endif
+#endif
+
+ /* Record this as an active process, with its channels.
+ As a result, child_setup will close Emacs's side of the pipes. */
+ chan_process[inchannel] = process;
+ XSETINT (XPROCESS (process)->infd, inchannel);
+ XSETINT (XPROCESS (process)->outfd, outchannel);
+ /* Record the tty descriptor used in the subprocess. */
+ if (forkin < 0)
+ XPROCESS (process)->subtty = Qnil;
+ else
+ XSETFASTINT (XPROCESS (process)->subtty, forkin);
+ XPROCESS (process)->pty_flag = (pty_flag ? Qt : Qnil);
+ XPROCESS (process)->status = Qrun;
+ if (!proc_decode_coding_system[inchannel])
+ proc_decode_coding_system[inchannel]
+ = (struct coding_system *) xmalloc (sizeof (struct coding_system));
+ setup_coding_system (XPROCESS (process)->decode_coding_system,
+ proc_decode_coding_system[inchannel]);
+ if (!proc_encode_coding_system[outchannel])
+ proc_encode_coding_system[outchannel]
+ = (struct coding_system *) xmalloc (sizeof (struct coding_system));
+ setup_coding_system (XPROCESS (process)->encode_coding_system,
+ proc_encode_coding_system[outchannel]);
+
+ if ((!NILP (buffer) && NILP (XBUFFER (buffer)->enable_multibyte_characters))
+ || (NILP (buffer) && NILP (buffer_defaults.enable_multibyte_characters)))
+ {
+ /* In unibyte mode, character code conversion should not take
+ place but EOL conversion should. So, setup raw-text or one
+ of the subsidiary according to the information just setup. */
+ if (!NILP (XPROCESS (process)->decode_coding_system))
+ setup_raw_text_coding_system (proc_decode_coding_system[inchannel]);
+ if (!NILP (XPROCESS (process)->encode_coding_system))
+ setup_raw_text_coding_system (proc_encode_coding_system[outchannel]);
+ }
+
+ if (CODING_REQUIRE_ENCODING (proc_encode_coding_system[outchannel]))
+ {
+ /* Here we encode arguments by the coding system used for
+ sending data to the process. We don't support using
+ different coding systems for encoding arguments and for
+ encoding data sent to the process. */
+ struct gcpro gcpro1;
+ int i = 1;
+ struct coding_system *coding = proc_encode_coding_system[outchannel];
+
+ coding->mode |= CODING_MODE_LAST_BLOCK;
+ GCPRO1 (process);
+ while (new_argv[i] != 0)
+ {
+ int len = strlen (new_argv[i]);
+ int size = encoding_buffer_size (coding, len);
+ unsigned char *buf = (unsigned char *) alloca (size);
+
+ encode_coding (coding, (unsigned char *)new_argv[i], buf, len, size);
+ buf[coding->produced] = 0;
+ /* We don't have to free new_argv[i] because it points to a
+ Lisp string given as an argument to `start-process'. */
+ new_argv[i++] = (char *) buf;
+ }
+ UNGCPRO;
+ coding->mode &= ~CODING_MODE_LAST_BLOCK;
+ }
+
+ /* Delay interrupts until we have a chance to store
+ the new fork's pid in its process structure */
+#ifdef POSIX_SIGNALS
+ sigemptyset (&blocked);
+#ifdef SIGCHLD
+ sigaddset (&blocked, SIGCHLD);
+#endif
+#ifdef HAVE_VFORK
+ /* On many hosts (e.g. Solaris 2.4), if a vforked child calls `signal',
+ this sets the parent's signal handlers as well as the child's.
+ So delay all interrupts whose handlers the child might munge,
+ and record the current handlers so they can be restored later. */
+ sigaddset (&blocked, SIGINT ); sigaction (SIGINT , 0, &sigint_action );
+ sigaddset (&blocked, SIGQUIT); sigaction (SIGQUIT, 0, &sigquit_action);
+#ifdef AIX
+ sigaddset (&blocked, SIGHUP ); sigaction (SIGHUP , 0, &sighup_action );
+#endif
+#endif /* HAVE_VFORK */
+ sigprocmask (SIG_BLOCK, &blocked, &procmask);
+#else /* !POSIX_SIGNALS */
+#ifdef SIGCHLD
+#ifdef BSD4_1
+ sighold (SIGCHLD);
+#else /* not BSD4_1 */
+#if defined (BSD_SYSTEM) || defined (UNIPLUS) || defined (HPUX)
+ sigsetmask (sigmask (SIGCHLD));
+#else /* ordinary USG */
+#if 0
+ sigchld_deferred = 0;
+ sigchld = signal (SIGCHLD, create_process_sigchld);
+#endif
+#endif /* ordinary USG */
+#endif /* not BSD4_1 */
+#endif /* SIGCHLD */
+#endif /* !POSIX_SIGNALS */
+
+ FD_SET (inchannel, &input_wait_mask);
+ FD_SET (inchannel, &non_keyboard_wait_mask);
+ if (inchannel > max_process_desc)
+ max_process_desc = inchannel;
+
+ /* Until we store the proper pid, enable sigchld_handler
+ to recognize an unknown pid as standing for this process.
+ It is very important not to let this `marker' value stay
+ in the table after this function has returned; if it does
+ it might cause call-process to hang and subsequent asynchronous
+ processes to get their return values scrambled. */
+ XSETINT (XPROCESS (process)->pid, -1);
+
+ BLOCK_INPUT;
+
+ {
+ /* child_setup must clobber environ on systems with true vfork.
+ Protect it from permanent change. */
+ char **save_environ = environ;
+
+ current_dir = ENCODE_FILE (current_dir);
+
+#ifndef WINDOWSNT
+ pid = vfork ();
+ if (pid == 0)
+#endif /* not WINDOWSNT */
+ {
+ int xforkin = forkin;
+ int xforkout = forkout;
+
+#if 0 /* This was probably a mistake--it duplicates code later on,
+ but fails to handle all the cases. */
+ /* Make sure SIGCHLD is not blocked in the child. */
+ sigsetmask (SIGEMPTYMASK);
+#endif
+
+ /* Make the pty be the controlling terminal of the process. */
+#ifdef HAVE_PTYS
+ /* First, disconnect its current controlling terminal. */
+#ifdef HAVE_SETSID
+ /* We tried doing setsid only if pty_flag, but it caused
+ process_set_signal to fail on SGI when using a pipe. */
+ setsid ();
+ /* Make the pty's terminal the controlling terminal. */
+ if (pty_flag)
+ {
+#ifdef TIOCSCTTY
+ /* We ignore the return value
+ because [email protected] says that is necessary on Linux. */
+ ioctl (xforkin, TIOCSCTTY, 0);
+#endif
+ }
+#else /* not HAVE_SETSID */
+#ifdef USG
+ /* It's very important to call setpgrp here and no time
+ afterwards. Otherwise, we lose our controlling tty which
+ is set when we open the pty. */
+ setpgrp ();
+#endif /* USG */
+#endif /* not HAVE_SETSID */
+#if defined (HAVE_TERMIOS) && defined (LDISC1)
+ if (pty_flag && xforkin >= 0)
+ {
+ struct termios t;
+ tcgetattr (xforkin, &t);
+ t.c_lflag = LDISC1;
+ if (tcsetattr (xforkin, TCSANOW, &t) < 0)
+ emacs_write (1, "create_process/tcsetattr LDISC1 failed\n", 39);
+ }
+#else
+#if defined (NTTYDISC) && defined (TIOCSETD)
+ if (pty_flag && xforkin >= 0)
+ {
+ /* Use new line discipline. */
+ int ldisc = NTTYDISC;
+ ioctl (xforkin, TIOCSETD, &ldisc);
+ }
+#endif
+#endif
+#ifdef TIOCNOTTY
+ /* In 4.3BSD, the TIOCSPGRP bug has been fixed, and now you
+ can do TIOCSPGRP only to the process's controlling tty. */
+ if (pty_flag)
+ {
+ /* I wonder: would just ioctl (0, TIOCNOTTY, 0) work here?
+ I can't test it since I don't have 4.3. */
+ int j = emacs_open ("/dev/tty", O_RDWR, 0);
+ ioctl (j, TIOCNOTTY, 0);
+ emacs_close (j);
+#ifndef USG
+ /* In order to get a controlling terminal on some versions
+ of BSD, it is necessary to put the process in pgrp 0
+ before it opens the terminal. */
+#ifdef HAVE_SETPGID
+ setpgid (0, 0);
+#else
+ setpgrp (0, 0);
+#endif
+#endif
+ }
+#endif /* TIOCNOTTY */
+
+#if !defined (RTU) && !defined (UNIPLUS) && !defined (DONT_REOPEN_PTY)
+/*** There is a suggestion that this ought to be a
+ conditional on TIOCSPGRP,
+ or !(defined (HAVE_SETSID) && defined (TIOCSCTTY)).
+ Trying the latter gave the wrong results on Debian GNU/Linux 1.1;
+ that system does seem to need this code, even though
+ both HAVE_SETSID and TIOCSCTTY are defined. */
+ /* Now close the pty (if we had it open) and reopen it.
+ This makes the pty the controlling terminal of the subprocess. */
+ if (pty_flag)
+ {
+#ifdef SET_CHILD_PTY_PGRP
+ int pgrp = getpid ();
+#endif
+
+ /* I wonder if emacs_close (emacs_open (pty_name, ...))
+ would work? */
+ if (xforkin >= 0)
+ emacs_close (xforkin);
+ xforkout = xforkin = emacs_open (pty_name, O_RDWR, 0);
+
+ if (xforkin < 0)
+ {
+ emacs_write (1, "Couldn't open the pty terminal ", 31);
+ emacs_write (1, pty_name, strlen (pty_name));
+ emacs_write (1, "\n", 1);
+ _exit (1);
+ }
+
+#ifdef SET_CHILD_PTY_PGRP
+ ioctl (xforkin, TIOCSPGRP, &pgrp);
+ ioctl (xforkout, TIOCSPGRP, &pgrp);
+#endif
+ }
+#endif /* not UNIPLUS and not RTU and not DONT_REOPEN_PTY */
+
+#ifdef SETUP_SLAVE_PTY
+ if (pty_flag)
+ {
+ SETUP_SLAVE_PTY;
+ }
+#endif /* SETUP_SLAVE_PTY */
+#ifdef AIX
+ /* On AIX, we've disabled SIGHUP above once we start a child on a pty.
+ Now reenable it in the child, so it will die when we want it to. */
+ if (pty_flag)
+ signal (SIGHUP, SIG_DFL);
+#endif
+#endif /* HAVE_PTYS */
+
+ signal (SIGINT, SIG_DFL);
+ signal (SIGQUIT, SIG_DFL);
+
+ /* Stop blocking signals in the child. */
+#ifdef POSIX_SIGNALS
+ sigprocmask (SIG_SETMASK, &procmask, 0);
+#else /* !POSIX_SIGNALS */
+#ifdef SIGCHLD
+#ifdef BSD4_1
+ sigrelse (SIGCHLD);
+#else /* not BSD4_1 */
+#if defined (BSD_SYSTEM) || defined (UNIPLUS) || defined (HPUX)
+ sigsetmask (SIGEMPTYMASK);
+#else /* ordinary USG */
+#if 0
+ signal (SIGCHLD, sigchld);
+#endif
+#endif /* ordinary USG */
+#endif /* not BSD4_1 */
+#endif /* SIGCHLD */
+#endif /* !POSIX_SIGNALS */
+
+ if (pty_flag)
+ child_setup_tty (xforkout);
+#ifdef WINDOWSNT
+ pid = child_setup (xforkin, xforkout, xforkout,
+ new_argv, 1, current_dir);
+#else /* not WINDOWSNT */
+ child_setup (xforkin, xforkout, xforkout,
+ new_argv, 1, current_dir);
+#endif /* not WINDOWSNT */
+ }
+ environ = save_environ;
+ }
+
+ UNBLOCK_INPUT;
+
+ /* This runs in the Emacs process. */
+ if (pid < 0)
+ {
+ if (forkin >= 0)
+ emacs_close (forkin);
+ if (forkin != forkout && forkout >= 0)
+ emacs_close (forkout);
+ }
+ else
+ {
+ /* vfork succeeded. */
+ XSETFASTINT (XPROCESS (process)->pid, pid);
+
+#ifdef WINDOWSNT
+ register_child (pid, inchannel);
+#endif /* WINDOWSNT */
+
+ /* If the subfork execv fails, and it exits,
+ this close hangs. I don't know why.
+ So have an interrupt jar it loose. */
+ {
+ struct atimer *timer;
+ EMACS_TIME offset;
+
+ stop_polling ();
+ EMACS_SET_SECS_USECS (offset, 1, 0);
+ timer = start_atimer (ATIMER_RELATIVE, offset, create_process_1, 0);
+
+ XPROCESS (process)->subtty = Qnil;
+ if (forkin >= 0)
+ emacs_close (forkin);
+
+ cancel_atimer (timer);
+ start_polling ();
+ }
+
+ if (forkin != forkout && forkout >= 0)
+ emacs_close (forkout);
+
+#ifdef HAVE_PTYS
+ if (pty_flag)
+ XPROCESS (process)->tty_name = build_string (pty_name);
+ else
+#endif
+ XPROCESS (process)->tty_name = Qnil;
+ }
+
+ /* Restore the signal state whether vfork succeeded or not.
+ (We will signal an error, below, if it failed.) */
+#ifdef POSIX_SIGNALS
+#ifdef HAVE_VFORK
+ /* Restore the parent's signal handlers. */
+ sigaction (SIGINT, &sigint_action, 0);
+ sigaction (SIGQUIT, &sigquit_action, 0);
+#ifdef AIX
+ sigaction (SIGHUP, &sighup_action, 0);
+#endif
+#endif /* HAVE_VFORK */
+ /* Stop blocking signals in the parent. */
+ sigprocmask (SIG_SETMASK, &procmask, 0);
+#else /* !POSIX_SIGNALS */
+#ifdef SIGCHLD
+#ifdef BSD4_1
+ sigrelse (SIGCHLD);
+#else /* not BSD4_1 */
+#if defined (BSD_SYSTEM) || defined (UNIPLUS) || defined (HPUX)
+ sigsetmask (SIGEMPTYMASK);
+#else /* ordinary USG */
+#if 0
+ signal (SIGCHLD, sigchld);
+ /* Now really handle any of these signals
+ that came in during this function. */
+ if (sigchld_deferred)
+ kill (getpid (), SIGCHLD);
+#endif
+#endif /* ordinary USG */
+#endif /* not BSD4_1 */
+#endif /* SIGCHLD */
+#endif /* !POSIX_SIGNALS */
+
+ /* Now generate the error if vfork failed. */
+ if (pid < 0)
+ report_file_error ("Doing vfork", Qnil);
+}
+#endif /* not VMS */
+
+#ifdef HAVE_SOCKETS
+
+/* open a TCP network connection to a given HOST/SERVICE. Treated
+ exactly like a normal process when reading and writing. Only
+ differences are in status display and process deletion. A network
+ connection has no PID; you cannot signal it. All you can do is
+ deactivate and close it via delete-process */
+
+DEFUN ("open-network-stream", Fopen_network_stream, Sopen_network_stream,
+ 4, 4, 0,
+ "Open a TCP connection for a service to a host.\n\
+Returns a subprocess-object to represent the connection.\n\
+Input and output work as for subprocesses; `delete-process' closes it.\n\
+Args are NAME BUFFER HOST SERVICE.\n\
+NAME is name for process. It is modified if necessary to make it unique.\n\
+BUFFER is the buffer (or buffer-name) to associate with the process.\n\
+ Process output goes at end of that buffer, unless you specify\n\
+ an output stream or filter function to handle the output.\n\
+ BUFFER may be also nil, meaning that this process is not associated\n\
+ with any buffer\n\
+Third arg is name of the host to connect to, or its IP address.\n\
+Fourth arg SERVICE is name of the service desired, or an integer\n\
+ specifying a port number to connect to.")
+ (name, buffer, host, service)
+ Lisp_Object name, buffer, host, service;
+{
+ Lisp_Object proc;
+#ifndef HAVE_GETADDRINFO
+ struct sockaddr_in address;
+ struct servent *svc_info;
+ struct hostent *host_info_ptr, host_info;
+ char *(addr_list[2]);
+ IN_ADDR numeric_addr;
+ int port;
+#else /* HAVE_GETADDRINFO */
+ struct addrinfo hints, *res, *lres;
+ int ret = 0;
+ int xerrno = 0;
+ char *portstring, portbuf[128];
+#endif /* HAVE_GETADDRINFO */
+ int s = -1, outch, inch;
+ struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
+ int retry = 0;
+ int count = specpdl_ptr - specpdl;
+ int count1;
+
+#ifdef WINDOWSNT
+ /* Ensure socket support is loaded if available. */
+ init_winsock (TRUE);
+#endif
+
+ GCPRO4 (name, buffer, host, service);
+ CHECK_STRING (name, 0);
+ CHECK_STRING (host, 0);
+
+#ifdef HAVE_GETADDRINFO
+ /*
+ * SERVICE can either be a string or int.
+ * Convert to a C string for later use by getaddrinfo.
+ */
+ if (INTEGERP (service))
+ {
+ sprintf (portbuf, "%d", XINT (service));
+ portstring = portbuf;
+ }
+ else
+ {
+ CHECK_STRING (service, 0);
+ portstring = XSTRING (service)->data;
+ }
+#else /* ! HAVE_GETADDRINFO */
+ if (INTEGERP (service))
+ port = htons ((unsigned short) XINT (service));
+ else
+ {
+ CHECK_STRING (service, 0);
+ svc_info = getservbyname (XSTRING (service)->data, "tcp");
+ if (svc_info == 0)
+ error ("Unknown service \"%s\"", XSTRING (service)->data);
+ port = svc_info->s_port;
+ }
+#endif /* ! HAVE_GETADDRINFO */
+
+
+ /* Slow down polling to every ten seconds.
+ Some kernels have a bug which causes retrying connect to fail
+ after a connect. Polling can interfere with gethostbyname too. */
+#ifdef POLL_FOR_INPUT
+ bind_polling_period (10);
+#endif
+
+#ifndef TERM
+#ifdef HAVE_GETADDRINFO
+ {
+ immediate_quit = 1;
+ QUIT;
+ memset (&hints, 0, sizeof (hints));
+ hints.ai_flags = 0;
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = 0;
+ ret = getaddrinfo (XSTRING (host)->data, portstring, &hints, &res);
+ if (ret)
+ {
+ error ("%s/%s %s", XSTRING (host)->data, portstring,
+ strerror (ret));
+ }
+ immediate_quit = 0;
+ }
+
+ s = -1;
+ count1 = specpdl_ptr - specpdl;
+ record_unwind_protect (close_file_unwind, make_number (s));
+
+ for (lres = res; lres; lres = lres->ai_next)
+ {
+ s = socket (lres->ai_family, lres->ai_socktype, lres->ai_protocol);
+ if (s < 0)
+ continue;
+
+ /* Kernel bugs (on Ultrix at least) cause lossage (not just EINTR)
+ when connect is interrupted. So let's not let it get interrupted.
+ Note we do not turn off polling, because polling is only used
+ when not interrupt_input, and thus not normally used on the systems
+ which have this bug. On systems which use polling, there's no way
+ to quit if polling is turned off. */
+ if (interrupt_input)
+ unrequest_sigio ();
+
+ immediate_quit = 1;
+ QUIT;
+
+ ret = connect (s, lres->ai_addr, lres->ai_addrlen);
+ if (ret == 0)
+ break;
+ emacs_close (s);
+ s = -1;
+ }
+
+ freeaddrinfo (res);
+ if (s < 0)
+ {
+ if (interrupt_input)
+ request_sigio ();
+
+ errno = xerrno;
+ report_file_error ("connection failed",
+ Fcons (host, Fcons (name, Qnil)));
+ }
+#else /* ! HAVE_GETADDRINFO */
+
+ while (1)
+ {
+#if 0
+#ifdef TRY_AGAIN
+ h_errno = 0;
+#endif
+#endif
+ immediate_quit = 1;
+ QUIT;
+ host_info_ptr = gethostbyname (XSTRING (host)->data);
+ immediate_quit = 0;
+#if 0
+#ifdef TRY_AGAIN
+ if (! (host_info_ptr == 0 && h_errno == TRY_AGAIN))
+#endif
+#endif
+ break;
+ Fsleep_for (make_number (1), Qnil);
+ }
+ if (host_info_ptr == 0)
+ /* Attempt to interpret host as numeric inet address */
+ {
+ numeric_addr = inet_addr ((char *) XSTRING (host)->data);
+ if (NUMERIC_ADDR_ERROR)
+ error ("Unknown host \"%s\"", XSTRING (host)->data);
+
+ host_info_ptr = &host_info;
+ host_info.h_name = 0;
+ host_info.h_aliases = 0;
+ host_info.h_addrtype = AF_INET;
+#ifdef h_addr
+ /* Older machines have only one address slot called h_addr.
+ Newer machines have h_addr_list, but #define h_addr to
+ be its first element. */
+ host_info.h_addr_list = &(addr_list[0]);
+#endif
+ host_info.h_addr = (char*)(&numeric_addr);
+ addr_list[1] = 0;
+ /* numeric_addr isn't null-terminated; it has fixed length. */
+ host_info.h_length = sizeof (numeric_addr);
+ }
+
+ bzero (&address, sizeof address);
+ bcopy (host_info_ptr->h_addr, (char *) &address.sin_addr,
+ host_info_ptr->h_length);
+ address.sin_family = host_info_ptr->h_addrtype;
+ address.sin_port = port;
+
+ s = socket (host_info_ptr->h_addrtype, SOCK_STREAM, 0);
+ if (s < 0)
+ report_file_error ("error creating socket", Fcons (name, Qnil));
+
+ count1 = specpdl_ptr - specpdl;
+ record_unwind_protect (close_file_unwind, make_number (s));
+
+ /* Kernel bugs (on Ultrix at least) cause lossage (not just EINTR)
+ when connect is interrupted. So let's not let it get interrupted.
+ Note we do not turn off polling, because polling is only used
+ when not interrupt_input, and thus not normally used on the systems
+ which have this bug. On systems which use polling, there's no way
+ to quit if polling is turned off. */
+ if (interrupt_input)
+ unrequest_sigio ();
+
+ loop:
+
+ immediate_quit = 1;
+ QUIT;
+
+ if (connect (s, (struct sockaddr *) &address, sizeof address) == -1
+ && errno != EISCONN)
+ {
+ int xerrno = errno;
+
+ immediate_quit = 0;
+
+ if (errno == EINTR)
+ goto loop;
+ if (errno == EADDRINUSE && retry < 20)
+ {
+ /* A delay here is needed on some FreeBSD systems,
+ and it is harmless, since this retrying takes time anyway
+ and should be infrequent. */
+ Fsleep_for (make_number (1), Qnil);
+ retry++;
+ goto loop;
+ }
+
+ /* Discard the unwind protect. */
+ specpdl_ptr = specpdl + count1;
+
+ emacs_close (s);
+
+ if (interrupt_input)
+ request_sigio ();
+
+ errno = xerrno;
+ report_file_error ("connection failed",
+ Fcons (host, Fcons (name, Qnil)));
+ }
+#endif /* ! HAVE_GETADDRINFO */
+
+ immediate_quit = 0;
+
+ /* Discard the unwind protect. */
+ specpdl_ptr = specpdl + count1;
+
+#ifdef POLL_FOR_INPUT
+ unbind_to (count, Qnil);
+#endif
+
+ if (interrupt_input)
+ request_sigio ();
+
+#else /* TERM */
+ s = connect_server (0);
+ if (s < 0)
+ report_file_error ("error creating socket", Fcons (name, Qnil));
+ send_command (s, C_PORT, 0, "%s:%d", XSTRING (host)->data, ntohs (port));
+ send_command (s, C_DUMB, 1, 0);
+#endif /* TERM */
+
+ inch = s;
+ outch = s;
+
+ if (!NILP (buffer))
+ buffer = Fget_buffer_create (buffer);
+ proc = make_process (name);
+
+ chan_process[inch] = proc;
+
+#ifdef O_NONBLOCK
+ fcntl (inch, F_SETFL, O_NONBLOCK);
+#else
+#ifdef O_NDELAY
+ fcntl (inch, F_SETFL, O_NDELAY);
+#endif
+#endif
+
+ XPROCESS (proc)->childp = Fcons (host, Fcons (service, Qnil));
+ XPROCESS (proc)->command_channel_p = Qnil;
+ XPROCESS (proc)->buffer = buffer;
+ XPROCESS (proc)->sentinel = Qnil;
+ XPROCESS (proc)->filter = Qnil;
+ XPROCESS (proc)->command = Qnil;
+ XPROCESS (proc)->pid = Qnil;
+ XSETINT (XPROCESS (proc)->infd, inch);
+ XSETINT (XPROCESS (proc)->outfd, outch);
+ XPROCESS (proc)->status = Qrun;
+ FD_SET (inch, &input_wait_mask);
+ FD_SET (inch, &non_keyboard_wait_mask);
+ if (inch > max_process_desc)
+ max_process_desc = inch;
+
+ {
+ /* Setup coding systems for communicating with the network stream. */
+ struct gcpro gcpro1;
+ /* Qt denotes we have not yet called Ffind_operation_coding_system. */
+ Lisp_Object coding_systems = Qt;
+ Lisp_Object args[5], val;
+
+ if (!NILP (Vcoding_system_for_read))
+ val = Vcoding_system_for_read;
+ else if ((!NILP (buffer) && NILP (XBUFFER (buffer)->enable_multibyte_characters))
+ || (NILP (buffer) && NILP (buffer_defaults.enable_multibyte_characters)))
+ /* We dare not decode end-of-line format by setting VAL to
+ Qraw_text, because the existing Emacs Lisp libraries
+ assume that they receive bare code including a sequene of
+ CR LF. */
+ val = Qnil;
+ else
+ {
+ args[0] = Qopen_network_stream, args[1] = name,
+ args[2] = buffer, args[3] = host, args[4] = service;
+ GCPRO1 (proc);
+ coding_systems = Ffind_operation_coding_system (5, args);
+ UNGCPRO;
+ if (CONSP (coding_systems))
+ val = XCAR (coding_systems);
+ else if (CONSP (Vdefault_process_coding_system))
+ val = XCAR (Vdefault_process_coding_system);
+ else
+ val = Qnil;
+ }
+ XPROCESS (proc)->decode_coding_system = val;
+
+ if (!NILP (Vcoding_system_for_write))
+ val = Vcoding_system_for_write;
+ else if (NILP (current_buffer->enable_multibyte_characters))
+ val = Qnil;
+ else
+ {
+ if (EQ (coding_systems, Qt))
+ {
+ args[0] = Qopen_network_stream, args[1] = name,
+ args[2] = buffer, args[3] = host, args[4] = service;
+ GCPRO1 (proc);
+ coding_systems = Ffind_operation_coding_system (5, args);
+ UNGCPRO;
+ }
+ if (CONSP (coding_systems))
+ val = XCDR (coding_systems);
+ else if (CONSP (Vdefault_process_coding_system))
+ val = XCDR (Vdefault_process_coding_system);
+ else
+ val = Qnil;
+ }
+ XPROCESS (proc)->encode_coding_system = val;
+ }
+
+ if (!proc_decode_coding_system[inch])
+ proc_decode_coding_system[inch]
+ = (struct coding_system *) xmalloc (sizeof (struct coding_system));
+ setup_coding_system (XPROCESS (proc)->decode_coding_system,
+ proc_decode_coding_system[inch]);
+ if (!proc_encode_coding_system[outch])
+ proc_encode_coding_system[outch]
+ = (struct coding_system *) xmalloc (sizeof (struct coding_system));
+ setup_coding_system (XPROCESS (proc)->encode_coding_system,
+ proc_encode_coding_system[outch]);
+
+ XPROCESS (proc)->decoding_buf = make_uninit_string (0);
+ XPROCESS (proc)->decoding_carryover = make_number (0);
+ XPROCESS (proc)->encoding_buf = make_uninit_string (0);
+ XPROCESS (proc)->encoding_carryover = make_number (0);
+
+ XPROCESS (proc)->inherit_coding_system_flag
+ = (NILP (buffer) || !inherit_process_coding_system
+ ? Qnil : Qt);
+
+ UNGCPRO;
+ return proc;
+}
+#endif /* HAVE_SOCKETS */
+
+void
+deactivate_process (proc)
+ Lisp_Object proc;
+{
+ register int inchannel, outchannel;
+ register struct Lisp_Process *p = XPROCESS (proc);
+
+ inchannel = XINT (p->infd);
+ outchannel = XINT (p->outfd);
+
+ if (inchannel >= 0)
+ {
+ /* Beware SIGCHLD hereabouts. */
+ flush_pending_output (inchannel);
+#ifdef VMS
+ {
+ VMS_PROC_STUFF *get_vms_process_pointer (), *vs;
+ sys$dassgn (outchannel);
+ vs = get_vms_process_pointer (p->pid);
+ if (vs)
+ give_back_vms_process_stuff (vs);
+ }
+#else
+ emacs_close (inchannel);
+ if (outchannel >= 0 && outchannel != inchannel)
+ emacs_close (outchannel);
+#endif
+
+ XSETINT (p->infd, -1);
+ XSETINT (p->outfd, -1);
+ chan_process[inchannel] = Qnil;
+ FD_CLR (inchannel, &input_wait_mask);
+ FD_CLR (inchannel, &non_keyboard_wait_mask);
+ if (inchannel == max_process_desc)
+ {
+ int i;
+ /* We just closed the highest-numbered process input descriptor,
+ so recompute the highest-numbered one now. */
+ max_process_desc = 0;
+ for (i = 0; i < MAXDESC; i++)
+ if (!NILP (chan_process[i]))
+ max_process_desc = i;
+ }
+ }
+}
+
+/* Close all descriptors currently in use for communication
+ with subprocess. This is used in a newly-forked subprocess
+ to get rid of irrelevant descriptors. */
+
+void
+close_process_descs ()
+{
+#ifndef WINDOWSNT
+ int i;
+ for (i = 0; i < MAXDESC; i++)
+ {
+ Lisp_Object process;
+ process = chan_process[i];
+ if (!NILP (process))
+ {
+ int in = XINT (XPROCESS (process)->infd);
+ int out = XINT (XPROCESS (process)->outfd);
+ if (in >= 0)
+ emacs_close (in);
+ if (out >= 0 && in != out)
+ emacs_close (out);
+ }
+ }
+#endif
+}
+
+DEFUN ("accept-process-output", Faccept_process_output, Saccept_process_output,
+ 0, 3, 0,
+ "Allow any pending output from subprocesses to be read by Emacs.\n\
+It is read into the process' buffers or given to their filter functions.\n\
+Non-nil arg PROCESS means do not return until some output has been received\n\
+from PROCESS.\n\
+Non-nil second arg TIMEOUT and third arg TIMEOUT-MSECS are number of\n\
+seconds and microseconds to wait; return after that much time whether\n\
+or not there is input.\n\
+Return non-nil iff we received any output before the timeout expired.")
+ (process, timeout, timeout_msecs)
+ register Lisp_Object process, timeout, timeout_msecs;
+{
+ int seconds;
+ int useconds;
+
+ if (! NILP (process))
+ CHECK_PROCESS (process, 0);
+
+ if (! NILP (timeout_msecs))
+ {
+ CHECK_NUMBER (timeout_msecs, 2);
+ useconds = XINT (timeout_msecs);
+ if (!INTEGERP (timeout))
+ XSETINT (timeout, 0);
+
+ {
+ int carry = useconds / 1000000;
+
+ XSETINT (timeout, XINT (timeout) + carry);
+ useconds -= carry * 1000000;
+
+ /* I think this clause is necessary because C doesn't
+ guarantee a particular rounding direction for negative
+ integers. */
+ if (useconds < 0)
+ {
+ XSETINT (timeout, XINT (timeout) - 1);
+ useconds += 1000000;
+ }
+ }
+ }
+ else
+ useconds = 0;
+
+ if (! NILP (timeout))
+ {
+ CHECK_NUMBER (timeout, 1);
+ seconds = XINT (timeout);
+ if (seconds < 0 || (seconds == 0 && useconds == 0))
+ seconds = -1;
+ }
+ else
+ {
+ if (NILP (process))
+ seconds = -1;
+ else
+ seconds = 0;
+ }
+
+ if (NILP (process))
+ XSETFASTINT (process, 0);
+
+ return
+ (wait_reading_process_input (seconds, useconds, process, 0)
+ ? Qt : Qnil);
+}
+
+/* This variable is different from waiting_for_input in keyboard.c.
+ It is used to communicate to a lisp process-filter/sentinel (via the
+ function Fwaiting_for_user_input_p below) whether emacs was waiting
+ for user-input when that process-filter was called.
+ waiting_for_input cannot be used as that is by definition 0 when
+ lisp code is being evalled.
+ This is also used in record_asynch_buffer_change.
+ For that purpose, this must be 0
+ when not inside wait_reading_process_input. */
+static int waiting_for_user_input_p;
+
+/* This is here so breakpoints can be put on it. */
+static void
+wait_reading_process_input_1 ()
+{
+}
+
+/* Read and dispose of subprocess output while waiting for timeout to
+ elapse and/or keyboard input to be available.
+
+ TIME_LIMIT is:
+ timeout in seconds, or
+ zero for no limit, or
+ -1 means gobble data immediately available but don't wait for any.
+
+ MICROSECS is:
+ an additional duration to wait, measured in microseconds.
+ If this is nonzero and time_limit is 0, then the timeout
+ consists of MICROSECS only.
+
+ READ_KBD is a lisp value:
+ 0 to ignore keyboard input, or
+ 1 to return when input is available, or
+ -1 meaning caller will actually read the input, so don't throw to
+ the quit handler, or
+ a cons cell, meaning wait until its car is non-nil
+ (and gobble terminal input into the buffer if any arrives), or
+ a process object, meaning wait until something arrives from that
+ process. The return value is true iff we read some input from
+ that process.
+
+ DO_DISPLAY != 0 means redisplay should be done to show subprocess
+ output that arrives.
+
+ If READ_KBD is a pointer to a struct Lisp_Process, then the
+ function returns true iff we received input from that process
+ before the timeout elapsed.
+ Otherwise, return true iff we received input from any process. */
+
+int
+wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
+ int time_limit, microsecs;
+ Lisp_Object read_kbd;
+ int do_display;
+{
+ register int channel, nfds;
+ static SELECT_TYPE Available;
+ int xerrno;
+ Lisp_Object proc;
+ EMACS_TIME timeout, end_time;
+ SELECT_TYPE Atemp;
+ int wait_channel = -1;
+ struct Lisp_Process *wait_proc = 0;
+ int got_some_input = 0;
+ Lisp_Object *wait_for_cell = 0;
+
+ FD_ZERO (&Available);
+
+ /* If read_kbd is a process to watch, set wait_proc and wait_channel
+ accordingly. */
+ if (PROCESSP (read_kbd))
+ {
+ wait_proc = XPROCESS (read_kbd);
+ wait_channel = XINT (wait_proc->infd);
+ XSETFASTINT (read_kbd, 0);
+ }
+
+ /* If waiting for non-nil in a cell, record where. */
+ if (CONSP (read_kbd))
+ {
+ wait_for_cell = &XCAR (read_kbd);
+ XSETFASTINT (read_kbd, 0);
+ }
+
+ waiting_for_user_input_p = XINT (read_kbd);
+
+ /* Since we may need to wait several times,
+ compute the absolute time to return at. */
+ if (time_limit || microsecs)
+ {
+ EMACS_GET_TIME (end_time);
+ EMACS_SET_SECS_USECS (timeout, time_limit, microsecs);
+ EMACS_ADD_TIME (end_time, end_time, timeout);
+ }
+#ifdef hpux
+ /* AlainF 5-Jul-1996
+ HP-UX 10.10 seem to have problems with signals coming in
+ Causes "poll: interrupted system call" messages when Emacs is run
+ in an X window
+ Turn off periodic alarms (in case they are in use) */
+ turn_on_atimers (0);
+#endif
+
+ while (1)
+ {
+ int timeout_reduced_for_timers = 0;
+
+#ifdef HAVE_X_WINDOWS
+ if (display_busy_cursor_p)
+ Fx_hide_busy_cursor (Qnil);
+#endif
+
+ /* If calling from keyboard input, do not quit
+ since we want to return C-g as an input character.
+ Otherwise, do pending quit if requested. */
+ if (XINT (read_kbd) >= 0)
+ QUIT;
+
+ /* Exit now if the cell we're waiting for became non-nil. */
+ if (wait_for_cell && ! NILP (*wait_for_cell))
+ break;
+
+ /* Compute time from now till when time limit is up */
+ /* Exit if already run out */
+ if (time_limit == -1)
+ {
+ /* -1 specified for timeout means
+ gobble output available now
+ but don't wait at all. */
+
+ EMACS_SET_SECS_USECS (timeout, 0, 0);
+ }
+ else if (time_limit || microsecs)
+ {
+ EMACS_GET_TIME (timeout);
+ EMACS_SUB_TIME (timeout, end_time, timeout);
+ if (EMACS_TIME_NEG_P (timeout))
+ break;
+ }
+ else
+ {
+ EMACS_SET_SECS_USECS (timeout, 100000, 0);
+ }
+
+ /* Normally we run timers here.
+ But not if wait_for_cell; in those cases,
+ the wait is supposed to be short,
+ and those callers cannot handle running arbitrary Lisp code here. */
+ if (! wait_for_cell)
+ {
+ EMACS_TIME timer_delay;
+ int old_timers_run;
+
+ retry:
+ old_timers_run = timers_run;
+ timer_delay = timer_check (1);
+ if (timers_run != old_timers_run && do_display)
+ {
+ redisplay_preserve_echo_area ();
+ /* We must retry, since a timer may have requeued itself
+ and that could alter the time_delay. */
+ goto retry;
+ }
+
+ /* If there is unread keyboard input, also return. */
+ if (XINT (read_kbd) != 0
+ && requeued_events_pending_p ())
+ break;
+
+ if (! EMACS_TIME_NEG_P (timer_delay) && time_limit != -1)
+ {
+ EMACS_TIME difference;
+ EMACS_SUB_TIME (difference, timer_delay, timeout);
+ if (EMACS_TIME_NEG_P (difference))
+ {
+ timeout = timer_delay;
+ timeout_reduced_for_timers = 1;
+ }
+ }
+ /* If time_limit is -1, we are not going to wait at all. */
+ else if (time_limit != -1)
+ {
+ /* This is so a breakpoint can be put here. */
+ wait_reading_process_input_1 ();
+ }
+ }
+
+ /* Cause C-g and alarm signals to take immediate action,
+ and cause input available signals to zero out timeout.
+
+ It is important that we do this before checking for process
+ activity. If we get a SIGCHLD after the explicit checks for
+ process activity, timeout is the only way we will know. */
+ if (XINT (read_kbd) < 0)
+ set_waiting_for_input (&timeout);
+
+ /* If status of something has changed, and no input is
+ available, notify the user of the change right away. After
+ this explicit check, we'll let the SIGCHLD handler zap
+ timeout to get our attention. */
+ if (update_tick != process_tick && do_display)
+ {
+ Atemp = input_wait_mask;
+ EMACS_SET_SECS_USECS (timeout, 0, 0);
+ if ((select (max (max_process_desc, max_keyboard_desc) + 1,
+ &Atemp, (SELECT_TYPE *)0, (SELECT_TYPE *)0,
+ &timeout)
+ <= 0))
+ {
+ /* It's okay for us to do this and then continue with
+ the loop, since timeout has already been zeroed out. */
+ clear_waiting_for_input ();
+ status_notify ();
+ }
+ }
+
+ /* Don't wait for output from a non-running process. */
+ if (wait_proc != 0 && !NILP (wait_proc->raw_status_low))
+ update_status (wait_proc);
+ if (wait_proc != 0
+ && ! EQ (wait_proc->status, Qrun))
+ {
+ int nread, total_nread = 0;
+
+ clear_waiting_for_input ();
+ XSETPROCESS (proc, wait_proc);
+
+ /* Read data from the process, until we exhaust it. */
+ while (XINT (wait_proc->infd) >= 0)
+ {
+ nread = read_process_output (proc, XINT (wait_proc->infd));
+
+ if (nread == 0)
+ break;
+
+ if (0 < nread)
+ total_nread += nread;
+#ifdef EIO
+ else if (nread == -1 && EIO == errno)
+ break;
+#endif
+#ifdef EAGAIN
+ else if (nread == -1 && EAGAIN == errno)
+ break;
+#endif
+#ifdef EWOULDBLOCK
+ else if (nread == -1 && EWOULDBLOCK == errno)
+ break;
+#endif
+ }
+ if (total_nread > 0 && do_display)
+ redisplay_preserve_echo_area ();
+
+ break;
+ }
+
+ /* Wait till there is something to do */
+
+ if (wait_for_cell)
+ Available = non_process_wait_mask;
+ else if (! XINT (read_kbd))
+ Available = non_keyboard_wait_mask;
+ else
+ Available = input_wait_mask;
+
+ /* If frame size has changed or the window is newly mapped,
+ redisplay now, before we start to wait. There is a race
+ condition here; if a SIGIO arrives between now and the select
+ and indicates that a frame is trashed, the select may block
+ displaying a trashed screen. */
+ if (frame_garbaged && do_display)
+ {
+ clear_waiting_for_input ();
+ redisplay_preserve_echo_area ();
+ if (XINT (read_kbd) < 0)
+ set_waiting_for_input (&timeout);
+ }
+
+ if (XINT (read_kbd) && detect_input_pending ())
+ {
+ nfds = 0;
+ FD_ZERO (&Available);
+ }
+ else
+ nfds = select (max (max_process_desc, max_keyboard_desc) + 1,
+ &Available, (SELECT_TYPE *)0, (SELECT_TYPE *)0,
+ &timeout);
+
+ xerrno = errno;
+
+ /* Make C-g and alarm signals set flags again */
+ clear_waiting_for_input ();
+
+ /* If we woke up due to SIGWINCH, actually change size now. */
+ do_pending_window_change (0);
+
+ if (time_limit && nfds == 0 && ! timeout_reduced_for_timers)
+ /* We wanted the full specified time, so return now. */
+ break;
+ if (nfds < 0)
+ {
+ if (xerrno == EINTR)
+ FD_ZERO (&Available);
+#ifdef ultrix
+ /* Ultrix select seems to return ENOMEM when it is
+ interrupted. Treat it just like EINTR. Bleah. Note
+ that we want to test for the "ultrix" CPP symbol, not
+ "__ultrix__"; the latter is only defined under GCC, but
+ not by DEC's bundled CC. -JimB */
+ else if (xerrno == ENOMEM)
+ FD_ZERO (&Available);
+#endif
+#ifdef ALLIANT
+ /* This happens for no known reason on ALLIANT.
+ I am guessing that this is the right response. -- RMS. */
+ else if (xerrno == EFAULT)
+ FD_ZERO (&Available);
+#endif
+ else if (xerrno == EBADF)
+ {
+#ifdef AIX
+ /* AIX doesn't handle PTY closure the same way BSD does. On AIX,
+ the child's closure of the pts gives the parent a SIGHUP, and
+ the ptc file descriptor is automatically closed,
+ yielding EBADF here or at select() call above.
+ So, SIGHUP is ignored (see def of PTY_TTY_NAME_SPRINTF
+ in m/ibmrt-aix.h), and here we just ignore the select error.
+ Cleanup occurs c/o status_notify after SIGCLD. */
+ FD_ZERO (&Available); /* Cannot depend on values returned */
+#else
+ abort ();
+#endif
+ }
+ else
+ error ("select error: %s", emacs_strerror (xerrno));
+ }
+#if defined(sun) && !defined(USG5_4)
+ else if (nfds > 0 && keyboard_bit_set (&Available)
+ && interrupt_input)
+ /* System sometimes fails to deliver SIGIO.
+
+ David J. Mackenzie says that Emacs doesn't compile under
+ Solaris if this code is enabled, thus the USG5_4 in the CPP
+ conditional. "I haven't noticed any ill effects so far.
+ If you find a Solaris expert somewhere, they might know
+ better." */
+ kill (getpid (), SIGIO);
+#endif
+
+#if 0 /* When polling is used, interrupt_input is 0,
+ so get_input_pending should read the input.
+ So this should not be needed. */
+ /* If we are using polling for input,
+ and we see input available, make it get read now.
+ Otherwise it might not actually get read for a second.
+ And on hpux, since we turn off polling in wait_reading_process_input,
+ it might never get read at all if we don't spend much time
+ outside of wait_reading_process_input. */
+ if (XINT (read_kbd) && interrupt_input
+ && keyboard_bit_set (&Available)
+ && input_polling_used ())
+ kill (getpid (), SIGALRM);
+#endif
+
+ /* Check for keyboard input */
+ /* If there is any, return immediately
+ to give it higher priority than subprocesses */
+
+ if (XINT (read_kbd) != 0
+ && detect_input_pending_run_timers (do_display))
+ {
+ swallow_events (do_display);
+ if (detect_input_pending_run_timers (do_display))
+ break;
+ }
+
+ /* If there is unread keyboard input, also return. */
+ if (XINT (read_kbd) != 0
+ && requeued_events_pending_p ())
+ break;
+
+ /* If we are not checking for keyboard input now,
+ do process events (but don't run any timers).
+ This is so that X events will be processed.
+ Otherwise they may have to wait until polling takes place.
+ That would causes delays in pasting selections, for example.
+
+ (We used to do this only if wait_for_cell.) */
+ if (XINT (read_kbd) == 0 && detect_input_pending ())
+ {
+ swallow_events (do_display);
+#if 0 /* Exiting when read_kbd doesn't request that seems wrong, though. */
+ if (detect_input_pending ())
+ break;
+#endif
+ }
+
+ /* Exit now if the cell we're waiting for became non-nil. */
+ if (wait_for_cell && ! NILP (*wait_for_cell))
+ break;
+
+#ifdef SIGIO
+ /* If we think we have keyboard input waiting, but didn't get SIGIO,
+ go read it. This can happen with X on BSD after logging out.
+ In that case, there really is no input and no SIGIO,
+ but select says there is input. */
+
+ if (XINT (read_kbd) && interrupt_input
+ && keyboard_bit_set (&Available))
+ kill (getpid (), SIGIO);
+#endif
+
+ if (! wait_proc)
+ got_some_input |= nfds > 0;
+
+ /* If checking input just got us a size-change event from X,
+ obey it now if we should. */
+ if (XINT (read_kbd) || wait_for_cell)
+ do_pending_window_change (0);
+
+ /* Check for data from a process. */
+ /* Really FIRST_PROC_DESC should be 0 on Unix,
+ but this is safer in the short run. */
+ for (channel = 0; channel <= max_process_desc; channel++)
+ {
+ if (FD_ISSET (channel, &Available)
+ && FD_ISSET (channel, &non_keyboard_wait_mask))
+ {
+ int nread;
+
+ /* If waiting for this channel, arrange to return as
+ soon as no more input to be processed. No more
+ waiting. */
+ if (wait_channel == channel)
+ {
+ wait_channel = -1;
+ time_limit = -1;
+ got_some_input = 1;
+ }
+ proc = chan_process[channel];
+ if (NILP (proc))
+ continue;
+
+ /* Read data from the process, starting with our
+ buffered-ahead character if we have one. */
+
+ nread = read_process_output (proc, channel);
+ if (nread > 0)
+ {
+ /* Since read_process_output can run a filter,
+ which can call accept-process-output,
+ don't try to read from any other processes
+ before doing the select again. */
+ FD_ZERO (&Available);
+
+ if (do_display)
+ redisplay_preserve_echo_area ();
+ }
+#ifdef EWOULDBLOCK
+ else if (nread == -1 && errno == EWOULDBLOCK)
+ ;
+#endif
+ /* ISC 4.1 defines both EWOULDBLOCK and O_NONBLOCK,
+ and Emacs uses O_NONBLOCK, so what we get is EAGAIN. */
+#ifdef O_NONBLOCK
+ else if (nread == -1 && errno == EAGAIN)
+ ;
+#else
+#ifdef O_NDELAY
+ else if (nread == -1 && errno == EAGAIN)
+ ;
+ /* Note that we cannot distinguish between no input
+ available now and a closed pipe.
+ With luck, a closed pipe will be accompanied by
+ subprocess termination and SIGCHLD. */
+ else if (nread == 0 && !NETCONN_P (proc))
+ ;
+#endif /* O_NDELAY */
+#endif /* O_NONBLOCK */
+#ifdef HAVE_PTYS
+ /* On some OSs with ptys, when the process on one end of
+ a pty exits, the other end gets an error reading with
+ errno = EIO instead of getting an EOF (0 bytes read).
+ Therefore, if we get an error reading and errno =
+ EIO, just continue, because the child process has
+ exited and should clean itself up soon (e.g. when we
+ get a SIGCHLD).
+
+ However, it has been known to happen that the SIGCHLD
+ got lost. So raise the signl again just in case.
+ It can't hurt. */
+ else if (nread == -1 && errno == EIO)
+ kill (getpid (), SIGCHLD);
+#endif /* HAVE_PTYS */
+ /* If we can detect process termination, don't consider the process
+ gone just because its pipe is closed. */
+#ifdef SIGCHLD
+ else if (nread == 0 && !NETCONN_P (proc))
+ ;
+#endif
+ else
+ {
+ /* Preserve status of processes already terminated. */
+ XSETINT (XPROCESS (proc)->tick, ++process_tick);
+ deactivate_process (proc);
+ if (!NILP (XPROCESS (proc)->raw_status_low))
+ update_status (XPROCESS (proc));
+ if (EQ (XPROCESS (proc)->status, Qrun))
+ XPROCESS (proc)->status
+ = Fcons (Qexit, Fcons (make_number (256), Qnil));
+ }
+ }
+ } /* end for each file descriptor */
+ } /* end while exit conditions not met */
+
+ waiting_for_user_input_p = 0;
+
+ /* If calling from keyboard input, do not quit
+ since we want to return C-g as an input character.
+ Otherwise, do pending quit if requested. */
+ if (XINT (read_kbd) >= 0)
+ {
+ /* Prevent input_pending from remaining set if we quit. */
+ clear_input_pending ();
+ QUIT;
+ }
+#ifdef hpux
+ /* AlainF 5-Jul-1996
+ HP-UX 10.10 seems to have problems with signals coming in
+ Causes "poll: interrupted system call" messages when Emacs is run
+ in an X window
+ Turn periodic alarms back on */
+ start_polling ();
+#endif
+
+#ifdef HAVE_X_WINDOWS
+ if (display_busy_cursor_p)
+ if (!inhibit_busy_cursor)
+ Fx_show_busy_cursor ();
+#endif
+
+ return got_some_input;
+}
+
+/* Given a list (FUNCTION ARGS...), apply FUNCTION to the ARGS. */
+
+static Lisp_Object
+read_process_output_call (fun_and_args)
+ Lisp_Object fun_and_args;
+{
+ return apply1 (XCAR (fun_and_args), XCDR (fun_and_args));
+}
+
+static Lisp_Object
+read_process_output_error_handler (error)
+ Lisp_Object error;
+{
+ cmd_error_internal (error, "error in process filter: ");
+ Vinhibit_quit = Qt;
+ update_echo_area ();
+ Fsleep_for (make_number (2), Qnil);
+}
+
+/* Read pending output from the process channel,
+ starting with our buffered-ahead character if we have one.
+ Yield number of decoded characters read.
+
+ This function reads at most 1024 characters.
+ If you want to read all available subprocess output,
+ you must call it repeatedly until it returns zero.
+
+ The characters read are decoded according to PROC's coding-system
+ for decoding. */
+
+int
+read_process_output (proc, channel)
+ Lisp_Object proc;
+ register int channel;
+{
+ register int nchars, nbytes;
+ char *chars;
+#ifdef VMS
+ int chars_allocated = 0; /* If 1, `chars' should be freed later. */
+#else
+ char buf[1024];
+#endif
+ register Lisp_Object outstream;
+ register struct buffer *old = current_buffer;
+ register struct Lisp_Process *p = XPROCESS (proc);
+ register int opoint;
+ struct coding_system *coding = proc_decode_coding_system[channel];
+ int chars_in_decoding_buf = 0; /* If 1, `chars' points
+ XSTRING (p->decoding_buf)->data. */
+ int carryover = XINT (p->decoding_carryover);
+
+#ifdef VMS
+ VMS_PROC_STUFF *vs, *get_vms_process_pointer();
+
+ vs = get_vms_process_pointer (p->pid);
+ if (vs)
+ {
+ if (!vs->iosb[0])
+ return (0); /* Really weird if it does this */
+ if (!(vs->iosb[0] & 1))
+ return -1; /* I/O error */
+ }
+ else
+ error ("Could not get VMS process pointer");
+ chars = vs->inputBuffer;
+ nbytes = clean_vms_buffer (chars, vs->iosb[1]);
+ if (nbytes <= 0)
+ {
+ start_vms_process_read (vs); /* Crank up the next read on the process */
+ return 1; /* Nothing worth printing, say we got 1 */
+ }
+ if (carryover > 0)
+ {
+ /* The data carried over in the previous decoding (which are at
+ the tail of decoding buffer) should be prepended to the new
+ data read to decode all together. */
+ char *buf = (char *) xmalloc (nbytes + carryover);
+
+ bcopy (XSTRING (p->decoding_buf)->data
+ + STRING_BYTES (XSTRING (p->decoding_buf)) - carryover,
+ buf, carryover);
+ bcopy (chars, buf + carryover, nbytes);
+ chars = buf;
+ chars_allocated = 1;
+ }
+#else /* not VMS */
+
+ if (carryover)
+ /* See the comment above. */
+ bcopy (XSTRING (p->decoding_buf)->data
+ + STRING_BYTES (XSTRING (p->decoding_buf)) - carryover,
+ buf, carryover);
+
+ if (proc_buffered_char[channel] < 0)
+ nbytes = emacs_read (channel, buf + carryover, (sizeof buf) - carryover);
+ else
+ {
+ buf[carryover] = proc_buffered_char[channel];
+ proc_buffered_char[channel] = -1;
+ nbytes = emacs_read (channel, buf + carryover + 1,
+ (sizeof buf) - carryover - 1);
+ if (nbytes < 0)
+ nbytes = 1;
+ else
+ nbytes = nbytes + 1;
+ }
+ chars = buf;
+#endif /* not VMS */
+
+ XSETINT (p->decoding_carryover, 0);
+
+ /* At this point, NBYTES holds number of characters just received
+ (including the one in proc_buffered_char[channel]). */
+ if (nbytes <= 0)
+ {
+ if (nbytes < 0 || coding->mode & CODING_MODE_LAST_BLOCK)
+ return nbytes;
+ coding->mode |= CODING_MODE_LAST_BLOCK;
+ }
+
+ /* Now set NBYTES how many bytes we must decode. */
+ nbytes += carryover;
+ nchars = nbytes;
+
+ if (CODING_MAY_REQUIRE_DECODING (coding))
+ {
+ int require = decoding_buffer_size (coding, nbytes);
+ int result;
+
+ if (STRING_BYTES (XSTRING (p->decoding_buf)) < require)
+ p->decoding_buf = make_uninit_string (require);
+ result = decode_coding (coding, chars, XSTRING (p->decoding_buf)->data,
+ nbytes, STRING_BYTES (XSTRING (p->decoding_buf)));
+ carryover = nbytes - coding->consumed;
+ if (carryover > 0)
+ {
+ /* Copy the carryover bytes to the end of p->decoding_buf, to
+ be processed on the next read. Since decoding_buffer_size
+ asks for an extra amount of space beyond the maximum
+ expected for the output, there should always be sufficient
+ space for the carryover (which is by definition a sequence
+ of bytes that was not long enough to be decoded, and thus
+ has a bounded length). */
+ if (STRING_BYTES (XSTRING (p->decoding_buf))
+ < coding->produced + carryover)
+ abort ();
+ bcopy (chars + coding->consumed,
+ XSTRING (p->decoding_buf)->data
+ + STRING_BYTES (XSTRING (p->decoding_buf)) - carryover,
+ carryover);
+ XSETINT (p->decoding_carryover, carryover);
+ }
+
+ /* A new coding system might be found by `decode_coding'. */
+ if (!EQ (p->decode_coding_system, coding->symbol))
+ {
+ p->decode_coding_system = coding->symbol;
+
+ /* Don't call setup_coding_system for
+ proc_decode_coding_system[channel] here. It is done in
+ detect_coding called via decode_coding above. */
+
+ /* If a coding system for encoding is not yet decided, we set
+ it as the same as coding-system for decoding.
+
+ But, before doing that we must check if
+ proc_encode_coding_system[p->outfd] surely points to a
+ valid memory because p->outfd will be changed once EOF is
+ sent to the process. */
+ if (NILP (p->encode_coding_system)
+ && proc_encode_coding_system[XINT (p->outfd)])
+ {
+ p->encode_coding_system = coding->symbol;
+ setup_coding_system (coding->symbol,
+ proc_encode_coding_system[XINT (p->outfd)]);
+ }
+ }
+
+#ifdef VMS
+ /* Now we don't need the contents of `chars'. */
+ if (chars_allocated)
+ free (chars);
+#endif
+ if (coding->produced == 0)
+ return 0;
+ chars = (char *) XSTRING (p->decoding_buf)->data;
+ nbytes = coding->produced;
+ nchars = (coding->fake_multibyte
+ ? multibyte_chars_in_text (chars, nbytes)
+ : coding->produced_char);
+ chars_in_decoding_buf = 1;
+ }
+ else
+ {
+#ifdef VMS
+ if (chars_allocated)
+ {
+ /* Although we don't have to decode the received data, we
+ must move it to an area which we don't have to free. */
+ if (! STRINGP (p->decoding_buf)
+ || STRING_BYTES (XSTRING (p->decoding_buf)) < nbytes)
+ p->decoding_buf = make_uninit_string (nbytes);
+ bcopy (chars, XSTRING (p->decoding_buf)->data, nbytes);
+ free (chars);
+ chars = XSTRING (p->decoding_buf)->data;
+ chars_in_decoding_buf = 1;
+ }
+#endif
+ nchars = multibyte_chars_in_text (chars, nbytes);
+ }
+
+ Vlast_coding_system_used = coding->symbol;
+
+ /* If the caller required, let the process associated buffer
+ inherit the coding-system used to decode the process output. */
+ if (! NILP (p->inherit_coding_system_flag)
+ && !NILP (p->buffer) && !NILP (XBUFFER (p->buffer)->name))
+ {
+ struct buffer *prev_buf = current_buffer;
+
+ Fset_buffer (p->buffer);
+ call1 (intern ("after-insert-file-set-buffer-file-coding-system"),
+ make_number (nbytes));
+ set_buffer_internal (prev_buf);
+ }
+
+ /* Read and dispose of the process output. */
+ outstream = p->filter;
+ if (!NILP (outstream))
+ {
+ /* We inhibit quit here instead of just catching it so that
+ hitting ^G when a filter happens to be running won't screw
+ it up. */
+ int count = specpdl_ptr - specpdl;
+ Lisp_Object odeactivate;
+ Lisp_Object obuffer, okeymap;
+ Lisp_Object text;
+ int outer_running_asynch_code = running_asynch_code;
+ int waiting = waiting_for_user_input_p;
+
+ /* No need to gcpro these, because all we do with them later
+ is test them for EQness, and none of them should be a string. */
+ odeactivate = Vdeactivate_mark;
+ XSETBUFFER (obuffer, current_buffer);
+ okeymap = current_buffer->keymap;
+
+ specbind (Qinhibit_quit, Qt);
+ specbind (Qlast_nonmenu_event, Qt);
+
+ /* In case we get recursively called,
+ and we already saved the match data nonrecursively,
+ save the same match data in safely recursive fashion. */
+ if (outer_running_asynch_code)
+ {
+ Lisp_Object tem;
+ /* Don't clobber the CURRENT match data, either! */
+ tem = Fmatch_data (Qnil, Qnil);
+ restore_match_data ();
+ record_unwind_protect (Fset_match_data, Fmatch_data (Qnil, Qnil));
+ Fset_match_data (tem);
+ }
+
+ /* For speed, if a search happens within this code,
+ save the match data in a special nonrecursive fashion. */
+ running_asynch_code = 1;
+
+ /* The multibyteness of a string given to the filter is decided
+ by which coding system we used for decoding. */
+ if (coding->type == coding_type_no_conversion
+ || coding->type == coding_type_raw_text)
+ text = make_unibyte_string (chars, nbytes);
+ else
+ text = make_multibyte_string (chars, nchars, nbytes);
+
+ internal_condition_case_1 (read_process_output_call,
+ Fcons (outstream,
+ Fcons (proc, Fcons (text, Qnil))),
+ !NILP (Vdebug_on_error) ? Qnil : Qerror,
+ read_process_output_error_handler);
+
+ /* If we saved the match data nonrecursively, restore it now. */
+ restore_match_data ();
+ running_asynch_code = outer_running_asynch_code;
+
+ /* Handling the process output should not deactivate the mark. */
+ Vdeactivate_mark = odeactivate;
+
+ /* Restore waiting_for_user_input_p as it was
+ when we were called, in case the filter clobbered it. */
+ waiting_for_user_input_p = waiting;
+
+#if 0 /* Call record_asynch_buffer_change unconditionally,
+ because we might have changed minor modes or other things
+ that affect key bindings. */
+ if (! EQ (Fcurrent_buffer (), obuffer)
+ || ! EQ (current_buffer->keymap, okeymap))
+#endif
+ /* But do it only if the caller is actually going to read events.
+ Otherwise there's no need to make him wake up, and it could
+ cause trouble (for example it would make Fsit_for return). */
+ if (waiting_for_user_input_p == -1)
+ record_asynch_buffer_change ();
+
+#ifdef VMS
+ start_vms_process_read (vs);
+#endif
+ unbind_to (count, Qnil);
+ return nchars;
+ }
+
+ /* If no filter, write into buffer if it isn't dead. */
+ if (!NILP (p->buffer) && !NILP (XBUFFER (p->buffer)->name))
+ {
+ Lisp_Object old_read_only;
+ int old_begv, old_zv;
+ int old_begv_byte, old_zv_byte;
+ Lisp_Object odeactivate;
+ int before, before_byte;
+ int opoint_byte;
+
+ odeactivate = Vdeactivate_mark;
+
+ Fset_buffer (p->buffer);
+ opoint = PT;
+ opoint_byte = PT_BYTE;
+ old_read_only = current_buffer->read_only;
+ old_begv = BEGV;
+ old_zv = ZV;
+ old_begv_byte = BEGV_BYTE;
+ old_zv_byte = ZV_BYTE;
+
+ current_buffer->read_only = Qnil;
+
+ /* Insert new output into buffer
+ at the current end-of-output marker,
+ thus preserving logical ordering of input and output. */
+ if (XMARKER (p->mark)->buffer)
+ SET_PT_BOTH (clip_to_bounds (BEGV, marker_position (p->mark), ZV),
+ clip_to_bounds (BEGV_BYTE, marker_byte_position (p->mark),
+ ZV_BYTE));
+ else
+ SET_PT_BOTH (ZV, ZV_BYTE);
+ before = PT;
+ before_byte = PT_BYTE;
+
+ /* If the output marker is outside of the visible region, save
+ the restriction and widen. */
+ if (! (BEGV <= PT && PT <= ZV))
+ Fwiden ();
+
+ if (NILP (current_buffer->enable_multibyte_characters))
+ nchars = nbytes;
+
+ /* Insert before markers in case we are inserting where
+ the buffer's mark is, and the user's next command is Meta-y. */
+ if (chars_in_decoding_buf)
+ {
+ /* Since multibyteness of p->docoding_buf is corrupted, we
+ can't use insert_from_string_before_markers. */
+ char *temp_buf;
+
+ temp_buf = (char *) alloca (nbytes);
+ bcopy (XSTRING (p->decoding_buf)->data, temp_buf, nbytes);
+ insert_before_markers (temp_buf, nbytes);
+ }
+ else
+ {
+ insert_1_both (chars, nchars, nbytes, 0, 1, 1);
+ signal_after_change (before, 0, PT - before);
+ update_compositions (before, PT, CHECK_BORDER);
+ }
+ set_marker_both (p->mark, p->buffer, PT, PT_BYTE);
+
+ update_mode_lines++;
+
+ /* Make sure opoint and the old restrictions
+ float ahead of any new text just as point would. */
+ if (opoint >= before)
+ {
+ opoint += PT - before;
+ opoint_byte += PT_BYTE - before_byte;
+ }
+ if (old_begv > before)
+ {
+ old_begv += PT - before;
+ old_begv_byte += PT_BYTE - before_byte;
+ }
+ if (old_zv >= before)
+ {
+ old_zv += PT - before;
+ old_zv_byte += PT_BYTE - before_byte;
+ }
+
+ /* If the restriction isn't what it should be, set it. */
+ if (old_begv != BEGV || old_zv != ZV)
+ Fnarrow_to_region (make_number (old_begv), make_number (old_zv));
+
+ /* Handling the process output should not deactivate the mark. */
+ Vdeactivate_mark = odeactivate;
+
+ current_buffer->read_only = old_read_only;
+ SET_PT_BOTH (opoint, opoint_byte);
+ set_buffer_internal (old);
+ }
+#ifdef VMS
+ start_vms_process_read (vs);
+#endif
+ return nbytes;
+}
+
+DEFUN ("waiting-for-user-input-p", Fwaiting_for_user_input_p, Swaiting_for_user_input_p,
+ 0, 0, 0,
+ "Returns non-nil if emacs is waiting for input from the user.\n\
+This is intended for use by asynchronous process output filters and sentinels.")
+ ()
+{
+ return (waiting_for_user_input_p ? Qt : Qnil);
+}
+
+/* Sending data to subprocess */
+
+jmp_buf send_process_frame;
+
+SIGTYPE
+send_process_trap ()
+{
+#ifdef BSD4_1
+ sigrelse (SIGPIPE);
+ sigrelse (SIGALRM);
+#endif /* BSD4_1 */
+ longjmp (send_process_frame, 1);
+}
+
+/* Send some data to process PROC.
+ BUF is the beginning of the data; LEN is the number of characters.
+ OBJECT is the Lisp object that the data comes from.
+
+ The data is encoded by PROC's coding-system for encoding before it
+ is sent. But if the data ends at the middle of multi-byte
+ representation, that incomplete sequence of bytes are sent without
+ being encoded. Should we store them in a buffer to prepend them to
+ the data send later? */
+
+void
+send_process (proc, buf, len, object)
+ volatile Lisp_Object proc;
+ unsigned char *buf;
+ int len;
+ Lisp_Object object;
+{
+ /* Use volatile to protect variables from being clobbered by longjmp. */
+ int rv;
+ volatile unsigned char *procname = XSTRING (XPROCESS (proc)->name)->data;
+ struct coding_system *coding;
+ struct gcpro gcpro1;
+ int carryover = XINT (XPROCESS (proc)->encoding_carryover);
+
+ GCPRO1 (object);
+
+#ifdef VMS
+ struct Lisp_Process *p = XPROCESS (proc);
+ VMS_PROC_STUFF *vs, *get_vms_process_pointer();
+#endif /* VMS */
+
+ if (! NILP (XPROCESS (proc)->raw_status_low))
+ update_status (XPROCESS (proc));
+ if (! EQ (XPROCESS (proc)->status, Qrun))
+ error ("Process %s not running", procname);
+ if (XINT (XPROCESS (proc)->outfd) < 0)
+ error ("Output file descriptor of %s is closed", procname);
+
+ coding = proc_encode_coding_system[XINT (XPROCESS (proc)->outfd)];
+ Vlast_coding_system_used = coding->symbol;
+
+ if (CODING_REQUIRE_ENCODING (coding))
+ {
+ int require = encoding_buffer_size (coding, len);
+ int offset;
+ unsigned char *temp_buf = NULL;
+
+ /* Remember the offset of data because a string or a buffer may
+ be relocated. Setting OFFSET to -1 means we don't have to
+ care about relocation. */
+ offset = (BUFFERP (object)
+ ? BUF_PTR_BYTE_POS (XBUFFER (object), buf)
+ : (STRINGP (object)
+ ? buf - XSTRING (object)->data
+ : -1));
+
+ if (carryover > 0)
+ {
+ temp_buf = (unsigned char *) xmalloc (len + carryover);
+
+ if (offset >= 0)
+ {
+ if (BUFFERP (object))
+ buf = BUF_BYTE_ADDRESS (XBUFFER (object), offset);
+ else if (STRINGP (object))
+ buf = offset + XSTRING (object)->data;
+ /* Now we don't have to care about relocation. */
+ offset = -1;
+ }
+ bcopy ((XSTRING (XPROCESS (proc)->encoding_buf)->data
+ + STRING_BYTES (XSTRING (XPROCESS (proc)->encoding_buf))
+ - carryover),
+ temp_buf,
+ carryover);
+ bcopy (buf, temp_buf + carryover, len);
+ buf = temp_buf;
+ }
+
+ if (STRING_BYTES (XSTRING (XPROCESS (proc)->encoding_buf)) < require)
+ {
+ XPROCESS (proc)->encoding_buf = make_uninit_string (require);
+
+ if (offset >= 0)
+ {
+ if (BUFFERP (object))
+ buf = BUF_BYTE_ADDRESS (XBUFFER (object), offset);
+ else if (STRINGP (object))
+ buf = offset + XSTRING (object)->data;
+ }
+ }
+ object = XPROCESS (proc)->encoding_buf;
+ encode_coding (coding, buf, XSTRING (object)->data,
+ len, STRING_BYTES (XSTRING (object)));
+ len = coding->produced;
+ buf = XSTRING (object)->data;
+ if (temp_buf)
+ xfree (temp_buf);
+ }
+
+#ifdef VMS
+ vs = get_vms_process_pointer (p->pid);
+ if (vs == 0)
+ error ("Could not find this process: %x", p->pid);
+ else if (write_to_vms_process (vs, buf, len))
+ ;
+#else
+
+ if (pty_max_bytes == 0)
+ {
+#if defined (HAVE_FPATHCONF) && defined (_PC_MAX_CANON)
+ pty_max_bytes = fpathconf (XFASTINT (XPROCESS (proc)->outfd),
+ _PC_MAX_CANON);
+ if (pty_max_bytes < 0)
+ pty_max_bytes = 250;
+#else
+ pty_max_bytes = 250;
+#endif
+ /* Deduct one, to leave space for the eof. */
+ pty_max_bytes--;
+ }
+
+ if (!setjmp (send_process_frame))
+ while (len > 0)
+ {
+ int this = len;
+ SIGTYPE (*old_sigpipe)();
+
+ /* Decide how much data we can send in one batch.
+ Long lines need to be split into multiple batches. */
+ if (!NILP (XPROCESS (proc)->pty_flag))
+ {
+ /* Starting this at zero is always correct when not the first iteration
+ because the previous iteration ended by sending C-d.
+ It may not be correct for the first iteration
+ if a partial line was sent in a separate send_process call.
+ If that proves worth handling, we need to save linepos
+ in the process object. */
+ int linepos = 0;
+ unsigned char *ptr = buf;
+ unsigned char *end = buf + len;
+
+ /* Scan through this text for a line that is too long. */
+ while (ptr != end && linepos < pty_max_bytes)
+ {
+ if (*ptr == '\n')
+ linepos = 0;
+ else
+ linepos++;
+ ptr++;
+ }
+ /* If we found one, break the line there
+ and put in a C-d to force the buffer through. */
+ this = ptr - buf;
+ }
+
+ /* Send this batch, using one or more write calls. */
+ while (this > 0)
+ {
+ old_sigpipe = (SIGTYPE (*) ()) signal (SIGPIPE, send_process_trap);
+ rv = emacs_write (XINT (XPROCESS (proc)->outfd), buf, this);
+ signal (SIGPIPE, old_sigpipe);
+
+ if (rv < 0)
+ {
+ if (0
+#ifdef EWOULDBLOCK
+ || errno == EWOULDBLOCK
+#endif
+#ifdef EAGAIN
+ || errno == EAGAIN
+#endif
+ )
+ /* Buffer is full. Wait, accepting input;
+ that may allow the program
+ to finish doing output and read more. */
+ {
+ Lisp_Object zero;
+ int offset;
+
+ /* Running filters might relocate buffers or strings.
+ Arrange to relocate BUF. */
+ if (BUFFERP (object))
+ offset = BUF_PTR_BYTE_POS (XBUFFER (object), buf);
+ else if (STRINGP (object))
+ offset = buf - XSTRING (object)->data;
+
+ XSETFASTINT (zero, 0);
+#ifdef EMACS_HAS_USECS
+ wait_reading_process_input (0, 20000, zero, 0);
+#else
+ wait_reading_process_input (1, 0, zero, 0);
+#endif
+
+ if (BUFFERP (object))
+ buf = BUF_BYTE_ADDRESS (XBUFFER (object), offset);
+ else if (STRINGP (object))
+ buf = offset + XSTRING (object)->data;
+
+ rv = 0;
+ }
+ else
+ /* This is a real error. */
+ report_file_error ("writing to process", Fcons (proc, Qnil));
+ }
+ buf += rv;
+ len -= rv;
+ this -= rv;
+ }
+
+ /* If we sent just part of the string, put in an EOF
+ to force it through, before we send the rest. */
+ if (len > 0)
+ Fprocess_send_eof (proc);
+ }
+#endif
+ else
+ {
+ XPROCESS (proc)->raw_status_low = Qnil;
+ XPROCESS (proc)->raw_status_high = Qnil;
+ XPROCESS (proc)->status = Fcons (Qexit, Fcons (make_number (256), Qnil));
+ XSETINT (XPROCESS (proc)->tick, ++process_tick);
+ deactivate_process (proc);
+#ifdef VMS
+ error ("Error writing to process %s; closed it", procname);
+#else
+ error ("SIGPIPE raised on process %s; closed it", procname);
+#endif
+ }
+
+ UNGCPRO;
+}
+
+DEFUN ("process-send-region", Fprocess_send_region, Sprocess_send_region,
+ 3, 3, 0,
+ "Send current contents of region as input to PROCESS.\n\
+PROCESS may be a process, a buffer, the name of a process or buffer, or\n\
+nil, indicating the current buffer's process.\n\
+Called from program, takes three arguments, PROCESS, START and END.\n\
+If the region is more than 500 characters long,\n\
+it is sent in several bunches. This may happen even for shorter regions.\n\
+Output from processes can arrive in between bunches.")
+ (process, start, end)
+ Lisp_Object process, start, end;
+{
+ Lisp_Object proc;
+ int start1, end1;
+
+ proc = get_process (process);
+ validate_region (&start, &end);
+
+ if (XINT (start) < GPT && XINT (end) > GPT)
+ move_gap (XINT (start));
+
+ start1 = CHAR_TO_BYTE (XINT (start));
+ end1 = CHAR_TO_BYTE (XINT (end));
+ send_process (proc, BYTE_POS_ADDR (start1), end1 - start1,
+ Fcurrent_buffer ());
+
+ return Qnil;
+}
+
+DEFUN ("process-send-string", Fprocess_send_string, Sprocess_send_string,
+ 2, 2, 0,
+ "Send PROCESS the contents of STRING as input.\n\
+PROCESS may be a process, a buffer, the name of a process or buffer, or\n\
+nil, indicating the current buffer's process.\n\
+If STRING is more than 500 characters long,\n\
+it is sent in several bunches. This may happen even for shorter strings.\n\
+Output from processes can arrive in between bunches.")
+ (process, string)
+ Lisp_Object process, string;
+{
+ Lisp_Object proc;
+ CHECK_STRING (string, 1);
+ proc = get_process (process);
+ send_process (proc, XSTRING (string)->data,
+ STRING_BYTES (XSTRING (string)), string);
+ return Qnil;
+}
+
+DEFUN ("process-running-child-p", Fprocess_running_child_p,
+ Sprocess_running_child_p, 0, 1, 0,
+ "Return t if PROCESS has given the terminal to a child.\n\
+If the operating system does not make it possible to find out,\n\
+return t unconditionally.")
+ (process)
+ Lisp_Object process;
+{
+ /* Initialize in case ioctl doesn't exist or gives an error,
+ in a way that will cause returning t. */
+ int gid = 0;
+ Lisp_Object proc;
+ struct Lisp_Process *p;
+
+ proc = get_process (process);
+ p = XPROCESS (proc);
+
+ if (!EQ (p->childp, Qt))
+ error ("Process %s is not a subprocess",
+ XSTRING (p->name)->data);
+ if (XINT (p->infd) < 0)
+ error ("Process %s is not active",
+ XSTRING (p->name)->data);
+
+#ifdef TIOCGPGRP
+ if (!NILP (p->subtty))
+ ioctl (XFASTINT (p->subtty), TIOCGPGRP, &gid);
+ else
+ ioctl (XINT (p->infd), TIOCGPGRP, &gid);
+#endif /* defined (TIOCGPGRP ) */
+
+ if (gid == XFASTINT (p->pid))
+ return Qnil;
+ return Qt;
+}
+
+/* send a signal number SIGNO to PROCESS.
+ If CURRENT_GROUP is t, that 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 CURRENT_GROUP is lambda, that means send to the process group
+ that currently owns the terminal, but only if it is NOT the shell itself.
+
+ 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 (process, signo, current_group, nomsg)
+ Lisp_Object process;
+ int signo;
+ Lisp_Object current_group;
+ int nomsg;
+{
+ Lisp_Object proc;
+ register struct Lisp_Process *p;
+ int gid;
+ int no_pgrp = 0;
+
+ proc = get_process (process);
+ p = XPROCESS (proc);
+
+ if (!EQ (p->childp, Qt))
+ error ("Process %s is not a subprocess",
+ XSTRING (p->name)->data);
+ if (XINT (p->infd) < 0)
+ error ("Process %s is not active",
+ XSTRING (p->name)->data);
+
+ if (NILP (p->pty_flag))
+ current_group = Qnil;
+
+ /* If we are using pgrps, get a pgrp number and make it negative. */
+ if (!NILP (current_group))
+ {
+#ifdef SIGNALS_VIA_CHARACTERS
+ /* If possible, send signals to the entire pgrp
+ by sending an input character to it. */
+
+ /* TERMIOS is the latest and bestest, and seems most likely to
+ work. If the system has it, use it. */
+#ifdef HAVE_TERMIOS
+ struct termios t;
+
+ switch (signo)
+ {
+ case SIGINT:
+ tcgetattr (XINT (p->infd), &t);
+ send_process (proc, &t.c_cc[VINTR], 1, Qnil);
+ return;
+
+ case SIGQUIT:
+ tcgetattr (XINT (p->infd), &t);
+ send_process (proc, &t.c_cc[VQUIT], 1, Qnil);
+ return;
+
+ case SIGTSTP:
+ tcgetattr (XINT (p->infd), &t);
+#if defined (VSWTCH) && !defined (PREFER_VSUSP)
+ send_process (proc, &t.c_cc[VSWTCH], 1, Qnil);
+#else
+ send_process (proc, &t.c_cc[VSUSP], 1, Qnil);
+#endif
+ return;
+ }
+
+#else /* ! HAVE_TERMIOS */
+
+ /* On Berkeley descendants, the following IOCTL's retrieve the
+ current control characters. */
+#if defined (TIOCGLTC) && defined (TIOCGETC)
+
+ struct tchars c;
+ struct ltchars lc;
+
+ switch (signo)
+ {
+ case SIGINT:
+ ioctl (XINT (p->infd), TIOCGETC, &c);
+ send_process (proc, &c.t_intrc, 1, Qnil);
+ return;
+ case SIGQUIT:
+ ioctl (XINT (p->infd), TIOCGETC, &c);
+ send_process (proc, &c.t_quitc, 1, Qnil);
+ return;
+#ifdef SIGTSTP
+ case SIGTSTP:
+ ioctl (XINT (p->infd), TIOCGLTC, &lc);
+ send_process (proc, &lc.t_suspc, 1, Qnil);
+ return;
+#endif /* ! defined (SIGTSTP) */
+ }
+
+#else /* ! defined (TIOCGLTC) && defined (TIOCGETC) */
+
+ /* On SYSV descendants, the TCGETA ioctl retrieves the current control
+ characters. */
+#ifdef TCGETA
+ struct termio t;
+ switch (signo)
+ {
+ case SIGINT:
+ ioctl (XINT (p->infd), TCGETA, &t);
+ send_process (proc, &t.c_cc[VINTR], 1, Qnil);
+ return;
+ case SIGQUIT:
+ ioctl (XINT (p->infd), TCGETA, &t);
+ send_process (proc, &t.c_cc[VQUIT], 1, Qnil);
+ return;
+#ifdef SIGTSTP
+ case SIGTSTP:
+ ioctl (XINT (p->infd), TCGETA, &t);
+ send_process (proc, &t.c_cc[VSWTCH], 1, Qnil);
+ return;
+#endif /* ! defined (SIGTSTP) */
+ }
+#else /* ! defined (TCGETA) */
+ Your configuration files are messed up.
+ /* If your system configuration files define SIGNALS_VIA_CHARACTERS,
+ you'd better be using one of the alternatives above! */
+#endif /* ! defined (TCGETA) */
+#endif /* ! defined (TIOCGLTC) && defined (TIOCGETC) */
+#endif /* ! defined HAVE_TERMIOS */
+#endif /* ! defined (SIGNALS_VIA_CHARACTERS) */
+
+#ifdef TIOCGPGRP
+ /* Get the pgrp using the tty itself, if we have that.
+ Otherwise, use the pty to get the pgrp.
+ On pfa systems, [email protected] writes:
+ "TIOCGPGRP symbol defined in sys/ioctl.h at E50.
+ But, TIOCGPGRP does not work on E50 ;-P works fine on E60"
+ His patch indicates that if TIOCGPGRP returns an error, then
+ we should just assume that p->pid is also the process group id. */
+ {
+ int err;
+
+ if (!NILP (p->subtty))
+ err = ioctl (XFASTINT (p->subtty), TIOCGPGRP, &gid);
+ else
+ err = ioctl (XINT (p->infd), TIOCGPGRP, &gid);
+
+#ifdef pfa
+ if (err == -1)
+ gid = - XFASTINT (p->pid);
+#endif /* ! defined (pfa) */
+ }
+ if (gid == -1)
+ no_pgrp = 1;
+ else
+ gid = - gid;
+#else /* ! defined (TIOCGPGRP ) */
+ /* Can't select pgrps on this system, so we know that
+ the child itself heads the pgrp. */
+ gid = - XFASTINT (p->pid);
+#endif /* ! defined (TIOCGPGRP ) */
+
+ /* If current_group is lambda, and the shell owns the terminal,
+ don't send any signal. */
+ if (EQ (current_group, Qlambda) && gid == - XFASTINT (p->pid))
+ return;
+ }
+ else
+ gid = - XFASTINT (p->pid);
+
+ switch (signo)
+ {
+#ifdef SIGCONT
+ case SIGCONT:
+ p->raw_status_low = Qnil;
+ p->raw_status_high = Qnil;
+ p->status = Qrun;
+ XSETINT (p->tick, ++process_tick);
+ if (!nomsg)
+ status_notify ();
+ break;
+#endif /* ! defined (SIGCONT) */
+ case SIGINT:
+#ifdef VMS
+ send_process (proc, "\003", 1, Qnil); /* ^C */
+ goto whoosh;
+#endif
+ case SIGQUIT:
+#ifdef VMS
+ send_process (proc, "\031", 1, Qnil); /* ^Y */
+ goto whoosh;
+#endif
+ case SIGKILL:
+#ifdef VMS
+ sys$forcex (&(XFASTINT (p->pid)), 0, 1);
+ whoosh:
+#endif
+ flush_pending_output (XINT (p->infd));
+ break;
+ }
+
+ /* If we don't have process groups, send the signal to the immediate
+ subprocess. That isn't really right, but it's better than any
+ obvious alternative. */
+ if (no_pgrp)
+ {
+ kill (XFASTINT (p->pid), signo);
+ return;
+ }
+
+ /* gid may be a pid, or minus a pgrp's number */
+#ifdef TIOCSIGSEND
+ if (!NILP (current_group))
+ ioctl (XINT (p->infd), TIOCSIGSEND, signo);
+ else
+ {
+ gid = - XFASTINT (p->pid);
+ kill (gid, signo);
+ }
+#else /* ! defined (TIOCSIGSEND) */
+ EMACS_KILLPG (-gid, signo);
+#endif /* ! defined (TIOCSIGSEND) */
+}
+
+DEFUN ("interrupt-process", Finterrupt_process, Sinterrupt_process, 0, 2, 0,
+ "Interrupt process PROCESS.\n\
+PROCESS may be a process, a buffer, or the name of a process or buffer.\n\
+nil or no arg means current buffer's process.\n\
+Second arg CURRENT-GROUP non-nil means send signal to\n\
+the current process-group of the process's controlling terminal\n\
+rather than to the process's own process group.\n\
+If the process is a shell, this means interrupt current subjob\n\
+rather than the shell.\n\
+\n\
+If CURRENT-GROUP is `lambda', and if the shell owns the terminal,\n\
+don't send the signal.")
+ (process, current_group)
+ Lisp_Object process, current_group;
+{
+ process_send_signal (process, SIGINT, current_group, 0);
+ return process;
+}
+
+DEFUN ("kill-process", Fkill_process, Skill_process, 0, 2, 0,
+ "Kill process PROCESS. May be process or name of one.\n\
+See function `interrupt-process' for more details on usage.")
+ (process, current_group)
+ Lisp_Object process, current_group;
+{
+ process_send_signal (process, SIGKILL, current_group, 0);
+ return process;
+}
+
+DEFUN ("quit-process", Fquit_process, Squit_process, 0, 2, 0,
+ "Send QUIT signal to process PROCESS. May be process or name of one.\n\
+See function `interrupt-process' for more details on usage.")
+ (process, current_group)
+ Lisp_Object process, current_group;
+{
+ process_send_signal (process, SIGQUIT, current_group, 0);
+ return process;
+}
+
+DEFUN ("stop-process", Fstop_process, Sstop_process, 0, 2, 0,
+ "Stop process PROCESS. May be process or name of one.\n\
+See function `interrupt-process' for more details on usage.")
+ (process, current_group)
+ Lisp_Object process, current_group;
+{
+#ifndef SIGTSTP
+ error ("no SIGTSTP support");
+#else
+ process_send_signal (process, SIGTSTP, current_group, 0);
+#endif
+ return process;
+}
+
+DEFUN ("continue-process", Fcontinue_process, Scontinue_process, 0, 2, 0,
+ "Continue process PROCESS. May be process or name of one.\n\
+See function `interrupt-process' for more details on usage.")
+ (process, current_group)
+ Lisp_Object process, current_group;
+{
+#ifdef SIGCONT
+ process_send_signal (process, SIGCONT, current_group, 0);
+#else
+ error ("no SIGCONT support");
+#endif
+ return process;
+}
+
+DEFUN ("signal-process", Fsignal_process, Ssignal_process,
+ 2, 2, "nProcess number: \nnSignal code: ",
+ "Send the process with process id PID the signal with code SIGCODE.\n\
+PID must be an integer. The process need not be a child of this Emacs.\n\
+SIGCODE may be an integer, or a symbol whose name is a signal name.")
+ (pid, sigcode)
+ Lisp_Object pid, sigcode;
+{
+ CHECK_NUMBER (pid, 0);
+
+#define handle_signal(NAME, VALUE) \
+ else if (!strcmp (name, NAME)) \
+ XSETINT (sigcode, VALUE)
+
+ if (INTEGERP (sigcode))
+ ;
+ else
+ {
+ unsigned char *name;
+
+ CHECK_SYMBOL (sigcode, 1);
+ name = XSYMBOL (sigcode)->name->data;
+
+ if (0)
+ ;
+#ifdef SIGHUP
+ handle_signal ("SIGHUP", SIGHUP);
+#endif
+#ifdef SIGINT
+ handle_signal ("SIGINT", SIGINT);
+#endif
+#ifdef SIGQUIT
+ handle_signal ("SIGQUIT", SIGQUIT);
+#endif
+#ifdef SIGILL
+ handle_signal ("SIGILL", SIGILL);
+#endif
+#ifdef SIGABRT
+ handle_signal ("SIGABRT", SIGABRT);
+#endif
+#ifdef SIGEMT
+ handle_signal ("SIGEMT", SIGEMT);
+#endif
+#ifdef SIGKILL
+ handle_signal ("SIGKILL", SIGKILL);
+#endif
+#ifdef SIGFPE
+ handle_signal ("SIGFPE", SIGFPE);
+#endif
+#ifdef SIGBUS
+ handle_signal ("SIGBUS", SIGBUS);
+#endif
+#ifdef SIGSEGV
+ handle_signal ("SIGSEGV", SIGSEGV);
+#endif
+#ifdef SIGSYS
+ handle_signal ("SIGSYS", SIGSYS);
+#endif
+#ifdef SIGPIPE
+ handle_signal ("SIGPIPE", SIGPIPE);
+#endif
+#ifdef SIGALRM
+ handle_signal ("SIGALRM", SIGALRM);
+#endif
+#ifdef SIGTERM
+ handle_signal ("SIGTERM", SIGTERM);
+#endif
+#ifdef SIGURG
+ handle_signal ("SIGURG", SIGURG);
+#endif
+#ifdef SIGSTOP
+ handle_signal ("SIGSTOP", SIGSTOP);
+#endif
+#ifdef SIGTSTP
+ handle_signal ("SIGTSTP", SIGTSTP);
+#endif
+#ifdef SIGCONT
+ handle_signal ("SIGCONT", SIGCONT);
+#endif
+#ifdef SIGCHLD
+ handle_signal ("SIGCHLD", SIGCHLD);
+#endif
+#ifdef SIGTTIN
+ handle_signal ("SIGTTIN", SIGTTIN);
+#endif
+#ifdef SIGTTOU
+ handle_signal ("SIGTTOU", SIGTTOU);
+#endif
+#ifdef SIGIO
+ handle_signal ("SIGIO", SIGIO);
+#endif
+#ifdef SIGXCPU
+ handle_signal ("SIGXCPU", SIGXCPU);
+#endif
+#ifdef SIGXFSZ
+ handle_signal ("SIGXFSZ", SIGXFSZ);
+#endif
+#ifdef SIGVTALRM
+ handle_signal ("SIGVTALRM", SIGVTALRM);
+#endif
+#ifdef SIGPROF
+ handle_signal ("SIGPROF", SIGPROF);
+#endif
+#ifdef SIGWINCH
+ handle_signal ("SIGWINCH", SIGWINCH);
+#endif
+#ifdef SIGINFO
+ handle_signal ("SIGINFO", SIGINFO);
+#endif
+#ifdef SIGUSR1
+ handle_signal ("SIGUSR1", SIGUSR1);
+#endif
+#ifdef SIGUSR2
+ handle_signal ("SIGUSR2", SIGUSR2);
+#endif
+ else
+ error ("Undefined signal name %s", name);
+ }
+
+#undef handle_signal
+
+ return make_number (kill (XINT (pid), XINT (sigcode)));
+}
+
+DEFUN ("process-send-eof", Fprocess_send_eof, Sprocess_send_eof, 0, 1, 0,
+ "Make PROCESS see end-of-file in its input.\n\
+EOF comes after any text already sent to it.\n\
+PROCESS may be a process, a buffer, the name of a process or buffer, or\n\
+nil, indicating the current buffer's process.\n\
+If PROCESS is a network connection, or is a process communicating\n\
+through a pipe (as opposed to a pty), then you cannot send any more\n\
+text to PROCESS after you call this function.")
+ (process)
+ Lisp_Object process;
+{
+ Lisp_Object proc;
+ struct coding_system *coding;
+
+ proc = get_process (process);
+ coding = proc_encode_coding_system[XINT (XPROCESS (proc)->outfd)];
+
+ /* Make sure the process is really alive. */
+ if (! NILP (XPROCESS (proc)->raw_status_low))
+ update_status (XPROCESS (proc));
+ if (! EQ (XPROCESS (proc)->status, Qrun))
+ error ("Process %s not running", XSTRING (XPROCESS (proc)->name)->data);
+
+ if (CODING_REQUIRE_FLUSHING (coding))
+ {
+ coding->mode |= CODING_MODE_LAST_BLOCK;
+ send_process (proc, "", 0, Qnil);
+ }
+
+#ifdef VMS
+ send_process (proc, "\032", 1, Qnil); /* ^z */
+#else
+ if (!NILP (XPROCESS (proc)->pty_flag))
+ send_process (proc, "\004", 1, Qnil);
+ else
+ {
+ int old_outfd, new_outfd;
+
+#ifdef HAVE_SHUTDOWN
+ /* If this is a network connection, or socketpair is used
+ for communication with the subprocess, call shutdown to cause EOF.
+ (In some old system, shutdown to socketpair doesn't work.
+ Then we just can't win.) */
+ if (NILP (XPROCESS (proc)->pid)
+ || XINT (XPROCESS (proc)->outfd) == XINT (XPROCESS (proc)->infd))
+ shutdown (XINT (XPROCESS (proc)->outfd), 1);
+ /* In case of socketpair, outfd == infd, so don't close it. */
+ if (XINT (XPROCESS (proc)->outfd) != XINT (XPROCESS (proc)->infd))
+ emacs_close (XINT (XPROCESS (proc)->outfd));
+#else /* not HAVE_SHUTDOWN */
+ emacs_close (XINT (XPROCESS (proc)->outfd));
+#endif /* not HAVE_SHUTDOWN */
+ new_outfd = emacs_open (NULL_DEVICE, O_WRONLY, 0);
+ old_outfd = XINT (XPROCESS (proc)->outfd);
+
+ if (!proc_encode_coding_system[new_outfd])
+ proc_encode_coding_system[new_outfd]
+ = (struct coding_system *) xmalloc (sizeof (struct coding_system));
+ bcopy (proc_encode_coding_system[old_outfd],
+ proc_encode_coding_system[new_outfd],
+ sizeof (struct coding_system));
+ bzero (proc_encode_coding_system[old_outfd],
+ sizeof (struct coding_system));
+
+ XSETINT (XPROCESS (proc)->outfd, new_outfd);
+ }
+#endif /* VMS */
+ return process;
+}
+
+/* Kill all processes associated with `buffer'.
+ If `buffer' is nil, kill all processes */
+
+void
+kill_buffer_processes (buffer)
+ Lisp_Object buffer;
+{
+ Lisp_Object tail, proc;
+
+ for (tail = Vprocess_alist; GC_CONSP (tail); tail = XCDR (tail))
+ {
+ proc = XCDR (XCAR (tail));
+ if (GC_PROCESSP (proc)
+ && (NILP (buffer) || EQ (XPROCESS (proc)->buffer, buffer)))
+ {
+ if (NETCONN_P (proc))
+ Fdelete_process (proc);
+ else if (XINT (XPROCESS (proc)->infd) >= 0)
+ process_send_signal (proc, SIGHUP, Qnil, 1);
+ }
+ }
+}
+
+/* On receipt of a signal that a child status has changed,
+ loop asking about children with changed statuses until
+ the system says there are no more.
+ All we do is change the status;
+ we do not run sentinels or print notifications.
+ That is saved for the next time keyboard input is done,
+ in order to avoid timing errors. */
+
+/** WARNING: this can be called during garbage collection.
+ Therefore, it must not be fooled by the presence of mark bits in
+ Lisp objects. */
+
+/** USG WARNING: Although it is not obvious from the documentation
+ in signal(2), on a USG system the SIGCLD handler MUST NOT call
+ signal() before executing at least one wait(), otherwise the handler
+ will be called again, resulting in an infinite loop. The relevant
+ portion of the documentation reads "SIGCLD signals will be queued
+ and the signal-catching function will be continually reentered until
+ the queue is empty". Invoking signal() causes the kernel to reexamine
+ the SIGCLD queue. Fred Fish, UniSoft Systems Inc. */
+
+SIGTYPE
+sigchld_handler (signo)
+ int signo;
+{
+ int old_errno = errno;
+ Lisp_Object proc;
+ register struct Lisp_Process *p;
+ extern EMACS_TIME *input_available_clear_time;
+
+#ifdef BSD4_1
+ extern int sigheld;
+ sigheld |= sigbit (SIGCHLD);
+#endif
+
+ while (1)
+ {
+ register int pid;
+ WAITTYPE w;
+ Lisp_Object tail;
+
+#ifdef WNOHANG
+#ifndef WUNTRACED
+#define WUNTRACED 0
+#endif /* no WUNTRACED */
+ /* Keep trying to get a status until we get a definitive result. */
+ do
+ {
+ errno = 0;
+ pid = wait3 (&w, WNOHANG | WUNTRACED, 0);
+ }
+ while (pid <= 0 && errno == EINTR);
+
+ if (pid <= 0)
+ {
+ /* A real failure. We have done all our job, so return. */
+
+ /* USG systems forget handlers when they are used;
+ must reestablish each time */
+#if defined (USG) && !defined (POSIX_SIGNALS)
+ signal (signo, sigchld_handler); /* WARNING - must come after wait3() */
+#endif
+#ifdef BSD4_1
+ sigheld &= ~sigbit (SIGCHLD);
+ sigrelse (SIGCHLD);
+#endif
+ errno = old_errno;
+ return;
+ }
+#else
+ pid = wait (&w);
+#endif /* no WNOHANG */
+
+ /* Find the process that signaled us, and record its status. */
+
+ p = 0;
+ for (tail = Vprocess_alist; CONSP (tail); tail = XCDR (tail))
+ {
+ proc = XCDR (XCAR (tail));
+ p = XPROCESS (proc);
+ if (EQ (p->childp, Qt) && XFASTINT (p->pid) == pid)
+ break;
+ p = 0;
+ }
+
+ /* Look for an asynchronous process whose pid hasn't been filled
+ in yet. */
+ if (p == 0)
+ for (tail = Vprocess_alist; CONSP (tail); tail = XCDR (tail))
+ {
+ proc = XCDR (XCAR (tail));
+ p = XPROCESS (proc);
+ if (INTEGERP (p->pid) && XINT (p->pid) == -1)
+ break;
+ p = 0;
+ }
+
+ /* Change the status of the process that was found. */
+ if (p != 0)
+ {
+ union { int i; WAITTYPE wt; } u;
+ int clear_desc_flag = 0;
+
+ XSETINT (p->tick, ++process_tick);
+ u.wt = w;
+ XSETINT (p->raw_status_low, u.i & 0xffff);
+ XSETINT (p->raw_status_high, u.i >> 16);
+
+ /* If process has terminated, stop waiting for its output. */
+ if ((WIFSIGNALED (w) || WIFEXITED (w))
+ && XINT (p->infd) >= 0)
+ clear_desc_flag = 1;
+
+ /* We use clear_desc_flag to avoid a compiler bug in Microsoft C. */
+ if (clear_desc_flag)
+ {
+ FD_CLR (XINT (p->infd), &input_wait_mask);
+ FD_CLR (XINT (p->infd), &non_keyboard_wait_mask);
+ }
+
+ /* Tell wait_reading_process_input that it needs to wake up and
+ look around. */
+ if (input_available_clear_time)
+ EMACS_SET_SECS_USECS (*input_available_clear_time, 0, 0);
+ }
+
+ /* There was no asynchronous process found for that id. Check
+ if we have a synchronous process. */
+ else
+ {
+ synch_process_alive = 0;
+
+ /* Report the status of the synchronous process. */
+ if (WIFEXITED (w))
+ synch_process_retcode = WRETCODE (w);
+ else if (WIFSIGNALED (w))
+ {
+ int code = WTERMSIG (w);
+ char *signame;
+
+ synchronize_system_messages_locale ();
+ signame = strsignal (code);
+
+ if (signame == 0)
+ signame = "unknown";
+
+ synch_process_death = signame;
+ }
+
+ /* Tell wait_reading_process_input that it needs to wake up and
+ look around. */
+ if (input_available_clear_time)
+ EMACS_SET_SECS_USECS (*input_available_clear_time, 0, 0);
+ }
+
+ /* On some systems, we must return right away.
+ If any more processes want to signal us, we will
+ get another signal.
+ Otherwise (on systems that have WNOHANG), loop around
+ to use up all the processes that have something to tell us. */
+#if defined (USG) && ! (defined (HPUX) && defined (WNOHANG)) || defined (WINDOWSNT)
+#if defined (USG) && ! defined (POSIX_SIGNALS)
+ signal (signo, sigchld_handler);
+#endif
+ errno = old_errno;
+ return;
+#endif /* USG, but not HPUX with WNOHANG */
+ }
+}
+
+
+static Lisp_Object
+exec_sentinel_unwind (data)
+ Lisp_Object data;
+{
+ XPROCESS (XCAR (data))->sentinel = XCDR (data);
+ return Qnil;
+}
+
+static Lisp_Object
+exec_sentinel_error_handler (error)
+ Lisp_Object error;
+{
+ cmd_error_internal (error, "error in process sentinel: ");
+ Vinhibit_quit = Qt;
+ update_echo_area ();
+ Fsleep_for (make_number (2), Qnil);
+}
+
+static void
+exec_sentinel (proc, reason)
+ Lisp_Object proc, reason;
+{
+ Lisp_Object sentinel, obuffer, odeactivate, okeymap;
+ register struct Lisp_Process *p = XPROCESS (proc);
+ int count = specpdl_ptr - specpdl;
+ int outer_running_asynch_code = running_asynch_code;
+ int waiting = waiting_for_user_input_p;
+
+ /* No need to gcpro these, because all we do with them later
+ is test them for EQness, and none of them should be a string. */
+ odeactivate = Vdeactivate_mark;
+ XSETBUFFER (obuffer, current_buffer);
+ okeymap = current_buffer->keymap;
+
+ sentinel = p->sentinel;
+ if (NILP (sentinel))
+ return;
+
+ /* 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, Fcons (proc, sentinel));
+ /* Inhibit quit so that random quits don't screw up a running filter. */
+ specbind (Qinhibit_quit, Qt);
+ specbind (Qlast_nonmenu_event, Qt);
+
+ /* In case we get recursively called,
+ and we already saved the match data nonrecursively,
+ save the same match data in safely recursive fashion. */
+ if (outer_running_asynch_code)
+ {
+ Lisp_Object tem;
+ tem = Fmatch_data (Qnil, Qnil);
+ restore_match_data ();
+ record_unwind_protect (Fset_match_data, Fmatch_data (Qnil, Qnil));
+ Fset_match_data (tem);
+ }
+
+ /* For speed, if a search happens within this code,
+ save the match data in a special nonrecursive fashion. */
+ running_asynch_code = 1;
+
+ internal_condition_case_1 (read_process_output_call,
+ Fcons (sentinel,
+ Fcons (proc, Fcons (reason, Qnil))),
+ !NILP (Vdebug_on_error) ? Qnil : Qerror,
+ exec_sentinel_error_handler);
+
+ /* If we saved the match data nonrecursively, restore it now. */
+ restore_match_data ();
+ running_asynch_code = outer_running_asynch_code;
+
+ Vdeactivate_mark = odeactivate;
+
+ /* Restore waiting_for_user_input_p as it was
+ when we were called, in case the filter clobbered it. */
+ waiting_for_user_input_p = waiting;
+
+#if 0
+ if (! EQ (Fcurrent_buffer (), obuffer)
+ || ! EQ (current_buffer->keymap, okeymap))
+#endif
+ /* But do it only if the caller is actually going to read events.
+ Otherwise there's no need to make him wake up, and it could
+ cause trouble (for example it would make Fsit_for return). */
+ if (waiting_for_user_input_p == -1)
+ record_asynch_buffer_change ();
+
+ unbind_to (count, Qnil);
+}
+
+/* Report all recent events of a change in process status
+ (either run the sentinel or output a message).
+ This is done while Emacs is waiting for keyboard input. */
+
+void
+status_notify ()
+{
+ register Lisp_Object proc, buffer;
+ Lisp_Object tail, msg;
+ struct gcpro gcpro1, gcpro2;
+
+ tail = Qnil;
+ msg = Qnil;
+ /* We need to gcpro tail; if read_process_output calls a filter
+ which deletes a process and removes the cons to which tail points
+ from Vprocess_alist, and then causes a GC, tail is an unprotected
+ reference. */
+ GCPRO2 (tail, msg);
+
+ /* Set this now, so that if new processes are created by sentinels
+ that we run, we get called again to handle their status changes. */
+ update_tick = process_tick;
+
+ for (tail = Vprocess_alist; !NILP (tail); tail = Fcdr (tail))
+ {
+ Lisp_Object symbol;
+ register struct Lisp_Process *p;
+
+ proc = Fcdr (Fcar (tail));
+ p = XPROCESS (proc);
+
+ if (XINT (p->tick) != XINT (p->update_tick))
+ {
+ XSETINT (p->update_tick, XINT (p->tick));
+
+ /* If process is still active, read any output that remains. */
+ while (! EQ (p->filter, Qt)
+ && XINT (p->infd) >= 0
+ && read_process_output (proc, XINT (p->infd)) > 0);
+
+ buffer = p->buffer;
+
+ /* Get the text to use for the message. */
+ if (!NILP (p->raw_status_low))
+ update_status (p);
+ msg = status_message (p->status);
+
+ /* If process is terminated, deactivate it or delete it. */
+ symbol = p->status;
+ if (CONSP (p->status))
+ symbol = XCAR (p->status);
+
+ if (EQ (symbol, Qsignal) || EQ (symbol, Qexit)
+ || EQ (symbol, Qclosed))
+ {
+ if (delete_exited_processes)
+ remove_process (proc);
+ else
+ deactivate_process (proc);
+ }
+
+ /* The actions above may have further incremented p->tick.
+ So set p->update_tick again
+ so that an error in the sentinel will not cause
+ this code to be run again. */
+ XSETINT (p->update_tick, XINT (p->tick));
+ /* Now output the message suitably. */
+ if (!NILP (p->sentinel))
+ exec_sentinel (proc, msg);
+ /* Don't bother with a message in the buffer
+ when a process becomes runnable. */
+ else if (!EQ (symbol, Qrun) && !NILP (buffer))
+ {
+ Lisp_Object ro, tem;
+ struct buffer *old = current_buffer;
+ int opoint, opoint_byte;
+ int before, before_byte;
+
+ ro = XBUFFER (buffer)->read_only;
+
+ /* Avoid error if buffer is deleted
+ (probably that's why the process is dead, too) */
+ if (NILP (XBUFFER (buffer)->name))
+ continue;
+ Fset_buffer (buffer);
+
+ opoint = PT;
+ opoint_byte = PT_BYTE;
+ /* Insert new output into buffer
+ at the current end-of-output marker,
+ thus preserving logical ordering of input and output. */
+ if (XMARKER (p->mark)->buffer)
+ Fgoto_char (p->mark);
+ else
+ SET_PT_BOTH (ZV, ZV_BYTE);
+
+ before = PT;
+ before_byte = PT_BYTE;
+
+ tem = current_buffer->read_only;
+ current_buffer->read_only = Qnil;
+ insert_string ("\nProcess ");
+ Finsert (1, &p->name);
+ insert_string (" ");
+ Finsert (1, &msg);
+ current_buffer->read_only = tem;
+ set_marker_both (p->mark, p->buffer, PT, PT_BYTE);
+
+ if (opoint >= before)
+ SET_PT_BOTH (opoint + (PT - before),
+ opoint_byte + (PT_BYTE - before_byte));
+ else
+ SET_PT_BOTH (opoint, opoint_byte);
+
+ set_buffer_internal (old);
+ }
+ }
+ } /* end for */
+
+ update_mode_lines++; /* in case buffers use %s in mode-line-format */
+ redisplay_preserve_echo_area ();
+
+ UNGCPRO;
+}
+
+
+DEFUN ("set-process-coding-system", Fset_process_coding_system,
+ Sset_process_coding_system, 1, 3, 0,
+ "Set coding systems of PROCESS to DECODING and ENCODING.\n\
+DECODING will be used to decode subprocess output and ENCODING to\n\
+encode subprocess input.")
+ (proc, decoding, encoding)
+ register Lisp_Object proc, decoding, encoding;
+{
+ register struct Lisp_Process *p;
+
+ CHECK_PROCESS (proc, 0);
+ p = XPROCESS (proc);
+ if (XINT (p->infd) < 0)
+ error ("Input file descriptor of %s closed", XSTRING (p->name)->data);
+ if (XINT (p->outfd) < 0)
+ error ("Output file descriptor of %s closed", XSTRING (p->name)->data);
+
+ p->decode_coding_system = Fcheck_coding_system (decoding);
+ p->encode_coding_system = Fcheck_coding_system (encoding);
+ setup_coding_system (decoding,
+ proc_decode_coding_system[XINT (p->infd)]);
+ setup_coding_system (encoding,
+ proc_encode_coding_system[XINT (p->outfd)]);
+
+ return Qnil;
+}
+
+DEFUN ("process-coding-system",
+ Fprocess_coding_system, Sprocess_coding_system, 1, 1, 0,
+ "Return a cons of coding systems for decoding and encoding of PROCESS.")
+ (proc)
+ register Lisp_Object proc;
+{
+ CHECK_PROCESS (proc, 0);
+ return Fcons (XPROCESS (proc)->decode_coding_system,
+ XPROCESS (proc)->encode_coding_system);
+}
+
+/* The first time this is called, assume keyboard input comes from DESC
+ instead of from where we used to expect it.
+ Subsequent calls mean assume input keyboard can come from DESC
+ in addition to other places. */
+
+static int add_keyboard_wait_descriptor_called_flag;
+
+void
+add_keyboard_wait_descriptor (desc)
+ int desc;
+{
+ if (! add_keyboard_wait_descriptor_called_flag)
+ FD_CLR (0, &input_wait_mask);
+ add_keyboard_wait_descriptor_called_flag = 1;
+ FD_SET (desc, &input_wait_mask);
+ FD_SET (desc, &non_process_wait_mask);
+ if (desc > max_keyboard_desc)
+ max_keyboard_desc = desc;
+}
+
+/* From now on, do not expect DESC to give keyboard input. */
+
+void
+delete_keyboard_wait_descriptor (desc)
+ int desc;
+{
+ int fd;
+ int lim = max_keyboard_desc;
+
+ FD_CLR (desc, &input_wait_mask);
+ FD_CLR (desc, &non_process_wait_mask);
+
+ if (desc == max_keyboard_desc)
+ for (fd = 0; fd < lim; fd++)
+ if (FD_ISSET (fd, &input_wait_mask)
+ && !FD_ISSET (fd, &non_keyboard_wait_mask))
+ max_keyboard_desc = fd;
+}
+
+/* Return nonzero if *MASK has a bit set
+ that corresponds to one of the keyboard input descriptors. */
+
+int
+keyboard_bit_set (mask)
+ SELECT_TYPE *mask;
+{
+ int fd;
+
+ for (fd = 0; fd <= max_keyboard_desc; fd++)
+ if (FD_ISSET (fd, mask) && FD_ISSET (fd, &input_wait_mask)
+ && !FD_ISSET (fd, &non_keyboard_wait_mask))
+ return 1;
+
+ return 0;
+}
+
+void
+init_process ()
+{
+ register int i;
+
+#ifdef SIGCHLD
+#ifndef CANNOT_DUMP
+ if (! noninteractive || initialized)
+#endif
+ signal (SIGCHLD, sigchld_handler);
+#endif
+
+ FD_ZERO (&input_wait_mask);
+ FD_ZERO (&non_keyboard_wait_mask);
+ FD_ZERO (&non_process_wait_mask);
+ max_process_desc = 0;
+
+ FD_SET (0, &input_wait_mask);
+
+ Vprocess_alist = Qnil;
+ for (i = 0; i < MAXDESC; i++)
+ {
+ chan_process[i] = Qnil;
+ proc_buffered_char[i] = -1;
+ }
+ bzero (proc_decode_coding_system, sizeof proc_decode_coding_system);
+ bzero (proc_encode_coding_system, sizeof proc_encode_coding_system);
+
+ Vdefault_process_coding_system
+ = (NILP (buffer_defaults.enable_multibyte_characters)
+ ? Fcons (Qraw_text, Qnil)
+ : Fcons (Qemacs_mule, Qnil));
+}
+
+void
+syms_of_process ()
+{
+ Qprocessp = intern ("processp");
+ staticpro (&Qprocessp);
+ Qrun = intern ("run");
+ staticpro (&Qrun);
+ Qstop = intern ("stop");
+ staticpro (&Qstop);
+ Qsignal = intern ("signal");
+ staticpro (&Qsignal);
+
+ /* Qexit is already staticpro'd by syms_of_eval; don't staticpro it
+ here again.
+
+ Qexit = intern ("exit");
+ staticpro (&Qexit); */
+
+ Qopen = intern ("open");
+ staticpro (&Qopen);
+ Qclosed = intern ("closed");
+ staticpro (&Qclosed);
+
+ Qlast_nonmenu_event = intern ("last-nonmenu-event");
+ staticpro (&Qlast_nonmenu_event);
+
+ staticpro (&Vprocess_alist);
+
+ DEFVAR_BOOL ("delete-exited-processes", &delete_exited_processes,
+ "*Non-nil means delete processes immediately when they exit.\n\
+nil means don't delete them until `list-processes' is run.");
+
+ delete_exited_processes = 1;
+
+ DEFVAR_LISP ("process-connection-type", &Vprocess_connection_type,
+ "Control type of device used to communicate with subprocesses.\n\
+Values are nil to use a pipe, or t or `pty' to use a pty.\n\
+The value has no effect if the system has no ptys or if all ptys are busy:\n\
+then a pipe is used in any case.\n\
+The value takes effect when `start-process' is called.");
+ Vprocess_connection_type = Qt;
+
+ defsubr (&Sprocessp);
+ defsubr (&Sget_process);
+ defsubr (&Sget_buffer_process);
+ defsubr (&Sdelete_process);
+ defsubr (&Sprocess_status);
+ defsubr (&Sprocess_exit_status);
+ defsubr (&Sprocess_id);
+ defsubr (&Sprocess_name);
+ defsubr (&Sprocess_tty_name);
+ defsubr (&Sprocess_command);
+ defsubr (&Sset_process_buffer);
+ defsubr (&Sprocess_buffer);
+ defsubr (&Sprocess_mark);
+ defsubr (&Sset_process_filter);
+ defsubr (&Sprocess_filter);
+ defsubr (&Sset_process_sentinel);
+ defsubr (&Sprocess_sentinel);
+ defsubr (&Sset_process_window_size);
+ defsubr (&Sset_process_inherit_coding_system_flag);
+ defsubr (&Sprocess_inherit_coding_system_flag);
+ defsubr (&Sprocess_kill_without_query);
+ defsubr (&Sprocess_contact);
+ defsubr (&Slist_processes);
+ defsubr (&Sprocess_list);
+ defsubr (&Sstart_process);
+#ifdef HAVE_SOCKETS
+ defsubr (&Sopen_network_stream);
+#endif /* HAVE_SOCKETS */
+ defsubr (&Saccept_process_output);
+ defsubr (&Sprocess_send_region);
+ defsubr (&Sprocess_send_string);
+ defsubr (&Sinterrupt_process);
+ defsubr (&Skill_process);
+ defsubr (&Squit_process);
+ defsubr (&Sstop_process);
+ defsubr (&Scontinue_process);
+ defsubr (&Sprocess_running_child_p);
+ defsubr (&Sprocess_send_eof);
+ defsubr (&Ssignal_process);
+ defsubr (&Swaiting_for_user_input_p);
+/* defsubr (&Sprocess_connection); */
+ defsubr (&Sset_process_coding_system);
+ defsubr (&Sprocess_coding_system);
+}
+
+
+#else /* not subprocesses */
+
+#include <sys/types.h>
+#include <errno.h>
+
+#include "lisp.h"
+#include "systime.h"
+#include "charset.h"
+#include "coding.h"
+#include "termopts.h"
+#include "sysselect.h"
+
+extern int frame_garbaged;
+
+extern EMACS_TIME timer_check ();
+extern int timers_run;
+
+/* As described above, except assuming that there are no subprocesses:
+
+ Wait for timeout to elapse and/or keyboard input to be available.
+
+ time_limit is:
+ timeout in seconds, or
+ zero for no limit, or
+ -1 means gobble data immediately available but don't wait for any.
+
+ read_kbd is a Lisp_Object:
+ 0 to ignore keyboard input, or
+ 1 to return when input is available, or
+ -1 means caller will actually read the input, so don't throw to
+ the quit handler.
+ a cons cell, meaning wait until its car is non-nil
+ (and gobble terminal input into the buffer if any arrives), or
+ We know that read_kbd will never be a Lisp_Process, since
+ `subprocesses' isn't defined.
+
+ do_display != 0 means redisplay should be done to show subprocess
+ output that arrives.
+
+ Return true iff we received input from any process. */
+
+int
+wait_reading_process_input (time_limit, microsecs, read_kbd, do_display)
+ int time_limit, microsecs;
+ Lisp_Object read_kbd;
+ int do_display;
+{
+ register int nfds;
+ EMACS_TIME end_time, timeout;
+ SELECT_TYPE waitchannels;
+ int xerrno;
+ Lisp_Object *wait_for_cell = 0;
+
+ /* If waiting for non-nil in a cell, record where. */
+ if (CONSP (read_kbd))
+ {
+ wait_for_cell = &XCAR (read_kbd);
+ XSETFASTINT (read_kbd, 0);
+ }
+
+ /* What does time_limit really mean? */
+ if (time_limit || microsecs)
+ {
+ EMACS_GET_TIME (end_time);
+ EMACS_SET_SECS_USECS (timeout, time_limit, microsecs);
+ EMACS_ADD_TIME (end_time, end_time, timeout);
+ }
+
+ /* Turn off periodic alarms (in case they are in use)
+ because the select emulator uses alarms. */
+ turn_on_atimers (0);
+
+ while (1)
+ {
+ int timeout_reduced_for_timers = 0;
+
+ /* If calling from keyboard input, do not quit
+ since we want to return C-g as an input character.
+ Otherwise, do pending quit if requested. */
+ if (XINT (read_kbd) >= 0)
+ QUIT;
+
+ /* Exit now if the cell we're waiting for became non-nil. */
+ if (wait_for_cell && ! NILP (*wait_for_cell))
+ break;
+
+ /* Compute time from now till when time limit is up */
+ /* Exit if already run out */
+ if (time_limit == -1)
+ {
+ /* -1 specified for timeout means
+ gobble output available now
+ but don't wait at all. */
+
+ EMACS_SET_SECS_USECS (timeout, 0, 0);
+ }
+ else if (time_limit || microsecs)
+ {
+ EMACS_GET_TIME (timeout);
+ EMACS_SUB_TIME (timeout, end_time, timeout);
+ if (EMACS_TIME_NEG_P (timeout))
+ break;
+ }
+ else
+ {
+ EMACS_SET_SECS_USECS (timeout, 100000, 0);
+ }
+
+ /* If our caller will not immediately handle keyboard events,
+ run timer events directly.
+ (Callers that will immediately read keyboard events
+ call timer_delay on their own.) */
+ if (! wait_for_cell)
+ {
+ EMACS_TIME timer_delay;
+ int old_timers_run;
+
+ retry:
+ old_timers_run = timers_run;
+ timer_delay = timer_check (1);
+ if (timers_run != old_timers_run && do_display)
+ {
+ redisplay_preserve_echo_area ();
+ /* We must retry, since a timer may have requeued itself
+ and that could alter the time delay. */
+ goto retry;
+ }
+
+ /* If there is unread keyboard input, also return. */
+ if (XINT (read_kbd) != 0
+ && requeued_events_pending_p ())
+ break;
+
+ if (! EMACS_TIME_NEG_P (timer_delay) && time_limit != -1)
+ {
+ EMACS_TIME difference;
+ EMACS_SUB_TIME (difference, timer_delay, timeout);
+ if (EMACS_TIME_NEG_P (difference))
+ {
+ timeout = timer_delay;
+ timeout_reduced_for_timers = 1;
+ }
+ }
+ }
+
+ /* Cause C-g and alarm signals to take immediate action,
+ and cause input available signals to zero out timeout. */
+ if (XINT (read_kbd) < 0)
+ set_waiting_for_input (&timeout);
+
+ /* Wait till there is something to do. */
+
+ if (! XINT (read_kbd) && wait_for_cell == 0)
+ FD_ZERO (&waitchannels);
+ else
+ FD_SET (0, &waitchannels);
+
+ /* If a frame has been newly mapped and needs updating,
+ reprocess its display stuff. */
+ if (frame_garbaged && do_display)
+ {
+ clear_waiting_for_input ();
+ redisplay_preserve_echo_area ();
+ if (XINT (read_kbd) < 0)
+ set_waiting_for_input (&timeout);
+ }
+
+ if (XINT (read_kbd) && detect_input_pending ())
+ {
+ nfds = 0;
+ FD_ZERO (&waitchannels);
+ }
+ else
+ nfds = select (1, &waitchannels, (SELECT_TYPE *)0, (SELECT_TYPE *)0,
+ &timeout);
+
+ xerrno = errno;
+
+ /* Make C-g and alarm signals set flags again */
+ clear_waiting_for_input ();
+
+ /* If we woke up due to SIGWINCH, actually change size now. */
+ do_pending_window_change (0);
+
+ if (time_limit && nfds == 0 && ! timeout_reduced_for_timers)
+ /* We waited the full specified time, so return now. */
+ break;
+
+ if (nfds == -1)
+ {
+ /* If the system call was interrupted, then go around the
+ loop again. */
+ if (xerrno == EINTR)
+ FD_ZERO (&waitchannels);
+ else
+ error ("select error: %s", emacs_strerror (xerrno));
+ }
+#ifdef sun
+ else if (nfds > 0 && (waitchannels & 1) && interrupt_input)
+ /* System sometimes fails to deliver SIGIO. */
+ kill (getpid (), SIGIO);
+#endif
+#ifdef SIGIO
+ if (XINT (read_kbd) && interrupt_input && (waitchannels & 1))
+ kill (getpid (), SIGIO);
+#endif
+
+ /* Check for keyboard input */
+
+ if ((XINT (read_kbd) != 0)
+ && detect_input_pending_run_timers (do_display))
+ {
+ swallow_events (do_display);
+ if (detect_input_pending_run_timers (do_display))
+ break;
+ }
+
+ /* If there is unread keyboard input, also return. */
+ if (XINT (read_kbd) != 0
+ && requeued_events_pending_p ())
+ break;
+
+ /* If wait_for_cell. check for keyboard input
+ but don't run any timers.
+ ??? (It seems wrong to me to check for keyboard
+ input at all when wait_for_cell, but the code
+ has been this way since July 1994.
+ Try changing this after version 19.31.) */
+ if (wait_for_cell
+ && detect_input_pending ())
+ {
+ swallow_events (do_display);
+ if (detect_input_pending ())
+ break;
+ }
+
+ /* Exit now if the cell we're waiting for became non-nil. */
+ if (wait_for_cell && ! NILP (*wait_for_cell))
+ break;
+ }
+
+ start_polling ();
+
+ return 0;
+}
+
+
+DEFUN ("get-buffer-process", Fget_buffer_process, Sget_buffer_process, 1, 1, 0,
+ /* Don't confuse make-docfile by having two doc strings for this function.
+ make-docfile does not pay attention to #if, for good reason! */
+ 0)
+ (name)
+ register Lisp_Object name;
+{
+ return Qnil;
+}
+
+DEFUN ("process-inherit-coding-system-flag",
+ Fprocess_inherit_coding_system_flag, Sprocess_inherit_coding_system_flag,
+ 1, 1, 0,
+ /* Don't confuse make-docfile by having two doc strings for this function.
+ make-docfile does not pay attention to #if, for good reason! */
+ 0)
+ (process)
+ register Lisp_Object process;
+{
+ /* Ignore the argument and return the value of
+ inherit-process-coding-system. */
+ return inherit_process_coding_system ? Qt : Qnil;
+}
+
+/* Kill all processes associated with `buffer'.
+ If `buffer' is nil, kill all processes.
+ Since we have no subprocesses, this does nothing. */
+
+void
+kill_buffer_processes (buffer)
+ Lisp_Object buffer;
+{
+}
+
+void
+init_process ()
+{
+}
+
+void
+syms_of_process ()
+{
+ defsubr (&Sget_buffer_process);
+ defsubr (&Sprocess_inherit_coding_system_flag);
+}
+
+
+#endif /* not subprocesses */