Commit 47e0e319 authored by Daiki Ueno's avatar Daiki Ueno
Browse files

Generalize start-process with keyword args

* src/process.c (Fmake_process): New function.
(create_process, create_pty): Check p->pty_flag instead of
Vprocess_connection_type.
(syms_of_process): Register QCcommand, QCconnection_type, Qpty,
Qpipe, and Smake_process.  Unregister Sstart_process.

* lisp/subr.el (start-process): New function, ported from the C
implementation.

* doc/lispref/processes.texi (Asynchronous Processes): Mention
`make-process'.

* etc/NEWS: Mention `make-process'.
parent 165bea78
2015-03-23 Daiki Ueno <ueno@gnu.org>
* processes.texi (Asynchronous Processes): Mention `make-process'.
2015-03-18 Eli Zaretskii <eliz@gnu.org>
* minibuf.texi (Basic Completion): Fix a typo. (Bug#20108)
......
......@@ -692,6 +692,61 @@ use the function @code{process-tty-name} (@pxref{Process
Information}).
@end defvar
@defun make-process &rest args
This function is like @code{start-process}, but takes keyword arguments.
The arguments @var{args} are a list of keyword/argument pairs.
Omitting a keyword is always equivalent to specifying it with value
@code{nil}. Here are the meaningful keywords:
@table @asis
@item :name @var{name}
Use the string @var{name} as the process name. It is modified if
necessary to make it unique.
@item :buffer @var{buffer}
Use @var{buffer} as the process buffer.
@item :command @var{command}
Use @var{command} as the command line of the process. @var{command}
is a list starting with the program's executable file name, followed
by strings to give to program as arguments.
@item :coding @var{coding}
If @var{coding} is a symbol, it specifies the coding system to be
used for both reading and writing of data from and to the
connection. If @var{coding} is a cons cell
@w{@code{(@var{decoding} . @var{encoding})}}, then @var{decoding}
will be used for reading and @var{encoding} for writing.
If @var{coding} is @code{nil}, the default rules for finding the
coding system will apply. @xref{Default Coding Systems}.
@item :connection-type @var{TYPE}
Initialize the type of device used to communicate with the subprocess.
Possible values are @code{pty} to use a pty, @code{pipe} to use a
pipe, or @code{nil} to use the default derived from the value of
the @code{process-connection-type} variable.
@item :noquery @var{query-flag}
Initialize the process query flag to @var{query-flag}.
@xref{Query Before Exit}.
@item :stop @var{stopped}
If @var{stopped} is non-@code{nil}, start the process in the
``stopped'' state.
@item :filter @var{filter}
Initialize the process filter to @var{filter}.
@item :sentinel @var{sentinel}
Initialize the process sentinel to @var{sentinel}.
@end table
The original argument list, modified with the actual connection
information, is available via the @code{process-contact} function.
@end defun
@node Deleting Processes
@section Deleting Processes
@cindex deleting processes
......
2015-03-23 Daiki Ueno <ueno@gnu.org>
* NEWS: Mention `make-process'.
2015-03-21 Titus von der Malsburg <malsburg@posteo.de>
* NEWS: Mention `default-font-width', `window-font-height',
......
......@@ -651,6 +651,11 @@ word syntax, use `\sw' instead.
* Lisp Changes in Emacs 25.1
** New function `make-process' provides an alternative interface to
`start-process'. It allows programs to set process parameters such as
process filter, sentinel, etc., through keyword arguments (similar to
`make-network-process').
** `read-buffer' takes a new `predicate' argument.
** Emacs Lisp now supports generators.
......
2015-03-23 Daiki Ueno <ueno@gnu.org>
* subr.el (start-process): New function, ported from the C
implementation.
2015-03-23 Daniel Colascione <dancol@dancol.org>
 
Automatically adjust process window sizes.
......
......@@ -1901,6 +1901,30 @@ and the file name is displayed in the echo area."
;;;; Process stuff.
(defun start-process (name buffer program &rest program-args)
"Start a program in a subprocess. Return the process object for it.
NAME is name for process. It is modified if necessary to make it unique.
BUFFER is the buffer (or buffer name) to associate with the process.
Process output (both standard output and standard error streams) goes
at end of BUFFER, unless you specify an output stream or filter
function to handle the output. BUFFER may also be nil, meaning that
this process is not associated with any buffer.
PROGRAM is the program file name. It is searched for in `exec-path'
\(which see). If nil, just associate a pty with the buffer. Remaining
arguments are strings to give program as arguments.
If you want to separate standard output from standard error, invoke
the command through a shell and redirect one of them using the shell
syntax."
(unless (fboundp 'make-process)
(error "Emacs was compiled without subprocess support"))
(apply #'make-process
(append (list :name name :buffer buffer)
(if program
(list :command (cons program program-args))))))
(defun process-lines (program &rest args)
"Execute PROGRAM with ARGS, returning its output as a list of lines.
Signal an error if the program returns with a non-zero exit status."
......
2015-03-23 Daiki Ueno <ueno@gnu.org>
* process.c (Fmake_process): New function.
(create_process, create_pty): Check p->pty_flag instead of
Vprocess_connection_type.
(syms_of_process): Register QCcommand, QCconnection_type, Qpty,
Qpipe, and Smake_process. Unregister Sstart_process.
2015-03-22 Jan Djärv <jan.h.d@swipnet.se>
 
* fontset.c (fontset_pattern_regexp): Replace + 1 with + 3 for
......
......@@ -1355,34 +1355,63 @@ DEFUN ("process-list", Fprocess_list, Sprocess_list, 0, 0, 0,
static void start_process_unwind (Lisp_Object proc);
DEFUN ("start-process", Fstart_process, Sstart_process, 3, MANY, 0,
DEFUN ("make-process", Fmake_process, Smake_process, 0, MANY, 0,
doc: /* Start a program in a subprocess. Return the process object for it.
NAME is name for process. It is modified if necessary to make it unique.
BUFFER is the buffer (or buffer name) to associate with the process.
Process output (both standard output and standard error streams) goes
at end of BUFFER, unless you specify an output stream or filter
function to handle the output. BUFFER may also be nil, meaning that
this process is not associated with any buffer.
This is similar to `start-process', but arguments are specified as
keyword/argument pairs. The following arguments are defined:
PROGRAM is the program file name. It is searched for in `exec-path'
(which see). If nil, just associate a pty with the buffer. Remaining
arguments are strings to give program as arguments.
:name NAME -- NAME is name for process. It is modified if necessary
to make it unique.
:buffer BUFFER -- BUFFER is the buffer (or buffer-name) to associate
with the process. Process output goes at end of that buffer, unless
you specify an output stream or filter function to handle the output.
BUFFER may be also nil, meaning that this process is not associated
with any buffer.
If you want to separate standard output from standard error, invoke
the command through a shell and redirect one of them using the shell
syntax.
:command COMMAND -- COMMAND is a list starting with the program file
name, followed by strings to give to the program as arguments.
:coding CODING -- If CODING is a symbol, it specifies the coding
system used for both reading and writing for this process. If CODING
is a cons (DECODING . ENCODING), DECODING is used for reading, and
ENCODING is used for writing.
:noquery BOOL -- When exiting Emacs, query the user if BOOL is nil and
the process is running. If BOOL is not given, query before exiting.
usage: (start-process NAME BUFFER PROGRAM &rest PROGRAM-ARGS) */)
:stop BOOL -- Start process in the `stopped' state if BOOL non-nil.
In the stopped state, a process does not accept incoming data, but you
can send outgoing data. The stopped state is cleared by
`continue-process' and set by `stop-process'.
:connection-type TYPE -- TYPE is control type of device used to
communicate with subprocesses. Values are `pipe' to use a pipe, `pty'
to use a pty, or nil to use the default specified through
`process-connection-type'.
:filter FILTER -- Install FILTER as the process filter.
:sentinel SENTINEL -- Install SENTINEL as the process sentinel.
usage: (make-process &rest ARGS) */)
(ptrdiff_t nargs, Lisp_Object *args)
{
Lisp_Object buffer, name, program, proc, current_dir, tem;
unsigned char **new_argv;
Lisp_Object buffer, name, command, program, proc, contact, current_dir, tem;
ptrdiff_t i;
ptrdiff_t count = SPECPDL_INDEX ();
struct gcpro gcpro1;
USE_SAFE_ALLOCA;
buffer = args[1];
if (nargs == 0)
return Qnil;
/* Save arguments for process-contact and clone-process. */
contact = Flist (nargs, args);
GCPRO1 (contact);
buffer = Fplist_get (contact, QCbuffer);
if (!NILP (buffer))
buffer = Fget_buffer_create (buffer);
......@@ -1402,10 +1431,14 @@ usage: (start-process NAME BUFFER PROGRAM &rest PROGRAM-ARGS) */)
UNGCPRO;
}
name = args[0];
name = Fplist_get (contact, QCname);
CHECK_STRING (name);
program = args[2];
command = Fplist_get (contact, QCcommand);
if (CONSP (command))
program = XCAR (command);
else
program = Qnil;
if (!NILP (program))
CHECK_STRING (program);
......@@ -1423,7 +1456,22 @@ usage: (start-process NAME BUFFER PROGRAM &rest PROGRAM-ARGS) */)
pset_buffer (XPROCESS (proc), buffer);
pset_sentinel (XPROCESS (proc), Qinternal_default_process_sentinel);
pset_filter (XPROCESS (proc), Qinternal_default_process_filter);
pset_command (XPROCESS (proc), Flist (nargs - 2, args + 2));
pset_command (XPROCESS (proc), Fcopy_sequence (command));
if (tem = Fplist_get (contact, QCnoquery), !NILP (tem))
XPROCESS (proc)->kill_without_query = 1;
if (tem = Fplist_get (contact, QCstop), !NILP (tem))
pset_command (XPROCESS (proc), Qt);
tem = Fplist_get (contact, QCconnection_type);
if (EQ (tem, Qpty))
XPROCESS (proc)->pty_flag = true;
else if (EQ (tem, Qpipe))
XPROCESS (proc)->pty_flag = false;
else if (NILP (tem))
XPROCESS (proc)->pty_flag = !NILP (Vprocess_connection_type);
else
report_file_error ("Unknown connection type", tem);
#ifdef HAVE_GNUTLS
/* AKA GNUTLS_INITSTAGE(proc). */
......@@ -1453,15 +1501,29 @@ usage: (start-process NAME BUFFER PROGRAM &rest PROGRAM-ARGS) */)
Lisp_Object val, *args2;
struct gcpro gcpro1, gcpro2;
val = Vcoding_system_for_read;
tem = Fplist_get (contact, QCcoding);
if (!NILP (tem))
{
val = tem;
if (CONSP (val))
val = XCAR (val);
}
else
val = Vcoding_system_for_read;
if (NILP (val))
{
SAFE_ALLOCA_LISP (args2, nargs + 1);
args2[0] = Qstart_process;
for (i = 0; i < nargs; i++) args2[i + 1] = args[i];
ptrdiff_t nargs2 = 3 + XINT (Flength (command));
Lisp_Object tem2;
SAFE_ALLOCA_LISP (args2, nargs2);
i = 0;
args2[i++] = Qstart_process;
args2[i++] = name;
args2[i++] = buffer;
for (tem2 = command; CONSP (tem2); tem2 = XCDR (tem2))
args2[i++] = XCAR (tem2);
GCPRO2 (proc, current_dir);
if (!NILP (program))
coding_systems = Ffind_operation_coding_system (nargs + 1, args2);
coding_systems = Ffind_operation_coding_system (nargs2, args2);
UNGCPRO;
if (CONSP (coding_systems))
val = XCAR (coding_systems);
......@@ -1470,17 +1532,30 @@ usage: (start-process NAME BUFFER PROGRAM &rest PROGRAM-ARGS) */)
}
pset_decode_coding_system (XPROCESS (proc), val);
val = Vcoding_system_for_write;
if (!NILP (tem))
{
val = tem;
if (CONSP (val))
val = XCDR (val);
}
else
val = Vcoding_system_for_write;
if (NILP (val))
{
if (EQ (coding_systems, Qt))
{
SAFE_ALLOCA_LISP (args2, nargs + 1);
args2[0] = Qstart_process;
for (i = 0; i < nargs; i++) args2[i + 1] = args[i];
ptrdiff_t nargs2 = 3 + XINT (Flength (command));
Lisp_Object tem2;
SAFE_ALLOCA_LISP (args2, nargs2);
i = 0;
args2[i++] = Qstart_process;
args2[i++] = name;
args2[i++] = buffer;
for (tem2 = command; CONSP (tem2); tem2 = XCDR (tem2))
args2[i++] = XCAR (tem2);
GCPRO2 (proc, current_dir);
if (!NILP (program))
coding_systems = Ffind_operation_coding_system (nargs + 1, args2);
coding_systems = Ffind_operation_coding_system (nargs2, args2);
UNGCPRO;
}
if (CONSP (coding_systems))
......@@ -1506,16 +1581,20 @@ usage: (start-process NAME BUFFER PROGRAM &rest PROGRAM-ARGS) */)
if (!NILP (program))
{
Lisp_Object program_args = XCDR (command);
unsigned char **new_argv;
ptrdiff_t new_argc;
/* If program file name is not absolute, search our path for it.
Put the name we will really use in TEM. */
if (!IS_DIRECTORY_SEP (SREF (program, 0))
&& !(SCHARS (program) > 1
&& IS_DEVICE_SEP (SREF (program, 1))))
{
struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
struct gcpro gcpro1, gcpro2;
tem = Qnil;
GCPRO4 (name, program, buffer, current_dir);
GCPRO2 (buffer, current_dir);
openp (Vexec_path, program, Vexec_suffixes, &tem,
make_number (X_OK), false);
UNGCPRO;
......@@ -1534,7 +1613,7 @@ usage: (start-process NAME BUFFER PROGRAM &rest PROGRAM-ARGS) */)
tem = remove_slash_colon (tem);
{
Lisp_Object arg_encoding = Qnil;
Lisp_Object arg_encoding = Qnil, tem2;
struct gcpro gcpro1;
GCPRO1 (tem);
......@@ -1547,9 +1626,9 @@ usage: (start-process NAME BUFFER PROGRAM &rest PROGRAM-ARGS) */)
systems for encoding arguments and for encoding data sent to the
process. */
for (i = 3; i < nargs; i++)
for (tem2 = program_args; CONSP (tem2); tem2 = XCDR (tem2))
{
tem = Fcons (args[i], tem);
tem = Fcons (XCAR (tem2), tem);
CHECK_STRING (XCAR (tem));
if (STRING_MULTIBYTE (XCAR (tem)))
{
......@@ -1567,10 +1646,11 @@ usage: (start-process NAME BUFFER PROGRAM &rest PROGRAM-ARGS) */)
/* Now that everything is encoded we can collect the strings into
NEW_ARGV. */
SAFE_NALLOCA (new_argv, 1, nargs - 1);
new_argv[nargs - 2] = 0;
new_argc = XINT (Flength (tem));
SAFE_NALLOCA (new_argv, 1, new_argc + 1);
new_argv[new_argc] = 0;
for (i = nargs - 2; i-- != 0; )
for (i = new_argc - 1; i >= 0; i--)
{
new_argv[i] = SDATA (XCAR (tem));
tem = XCDR (tem);
......@@ -1581,6 +1661,7 @@ usage: (start-process NAME BUFFER PROGRAM &rest PROGRAM-ARGS) */)
else
create_pty (proc);
UNGCPRO;
SAFE_FREE ();
return unbind_to (count, proc);
}
......@@ -1648,7 +1729,7 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir)
inchannel = outchannel = -1;
if (!NILP (Vprocess_connection_type))
if (p->pty_flag)
outchannel = inchannel = allocate_pty (pty_name);
if (inchannel >= 0)
......@@ -1701,8 +1782,12 @@ create_process (Lisp_Object process, char **new_argv, Lisp_Object current_dir)
p->pty_flag = pty_flag;
pset_status (p, Qrun);
FD_SET (inchannel, &input_wait_mask);
FD_SET (inchannel, &non_keyboard_wait_mask);
if (!EQ (p->command, Qt))
{
FD_SET (inchannel, &input_wait_mask);
FD_SET (inchannel, &non_keyboard_wait_mask);
}
if (inchannel > max_process_desc)
max_process_desc = inchannel;
......@@ -1894,7 +1979,7 @@ create_pty (Lisp_Object process)
{
struct Lisp_Process *p = XPROCESS (process);
char pty_name[PTY_NAME_SIZE];
int pty_fd = NILP (Vprocess_connection_type) ? -1 : allocate_pty (pty_name);
int pty_fd = !p->pty_flag ? -1 : allocate_pty (pty_name);
if (pty_fd >= 0)
{
......@@ -7269,6 +7354,10 @@ syms_of_process (void)
DEFSYM (QCstop, ":stop");
DEFSYM (QCoptions, ":options");
DEFSYM (QCplist, ":plist");
DEFSYM (QCcommand, ":command");
DEFSYM (QCconnection_type, ":connection-type");
DEFSYM (Qpty, "pty");
DEFSYM (Qpipe, "pipe");
DEFSYM (Qlast_nonmenu_event, "last-nonmenu-event");
......@@ -7371,7 +7460,7 @@ The variable takes effect when `start-process' is called. */);
defsubr (&Sprocess_plist);
defsubr (&Sset_process_plist);
defsubr (&Sprocess_list);
defsubr (&Sstart_process);
defsubr (&Smake_process);
defsubr (&Sserial_process_configure);
defsubr (&Smake_serial_process);
defsubr (&Sset_network_process_option);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment