From 47e0e319329a1ecf9da4fa1afd2b9f2738fada67 Mon Sep 17 00:00:00 2001 From: Daiki Ueno Date: Mon, 23 Mar 2015 12:40:29 +0900 Subject: [PATCH] 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'. --- doc/lispref/ChangeLog | 4 + doc/lispref/processes.texi | 55 ++++++++++++ etc/ChangeLog | 4 + etc/NEWS | 5 ++ lisp/ChangeLog | 5 ++ lisp/subr.el | 24 +++++ src/ChangeLog | 8 ++ src/process.c | 175 ++++++++++++++++++++++++++++--------- 8 files changed, 237 insertions(+), 43 deletions(-) diff --git a/doc/lispref/ChangeLog b/doc/lispref/ChangeLog index 3644d40fabf..ff1f8148e81 100644 --- a/doc/lispref/ChangeLog +++ b/doc/lispref/ChangeLog @@ -1,3 +1,7 @@ +2015-03-23 Daiki Ueno + + * processes.texi (Asynchronous Processes): Mention `make-process'. + 2015-03-18 Eli Zaretskii * minibuf.texi (Basic Completion): Fix a typo. (Bug#20108) diff --git a/doc/lispref/processes.texi b/doc/lispref/processes.texi index 177cd684f5c..3e9cc50de52 100644 --- a/doc/lispref/processes.texi +++ b/doc/lispref/processes.texi @@ -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 diff --git a/etc/ChangeLog b/etc/ChangeLog index c94e12296ed..e146f786f6f 100644 --- a/etc/ChangeLog +++ b/etc/ChangeLog @@ -1,3 +1,7 @@ +2015-03-23 Daiki Ueno + + * NEWS: Mention `make-process'. + 2015-03-21 Titus von der Malsburg * NEWS: Mention `default-font-width', `window-font-height', diff --git a/etc/NEWS b/etc/NEWS index 7cdb24b402e..3b848dc6539 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -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. diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 596b6e2ccb5..8f1534a3284 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,3 +1,8 @@ +2015-03-23 Daiki Ueno + + * subr.el (start-process): New function, ported from the C + implementation. + 2015-03-23 Daniel Colascione Automatically adjust process window sizes. diff --git a/lisp/subr.el b/lisp/subr.el index deadca6efa0..163a1c419d4 100644 --- a/lisp/subr.el +++ b/lisp/subr.el @@ -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." diff --git a/src/ChangeLog b/src/ChangeLog index 79feb611f3d..6c7955a2fc0 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,11 @@ +2015-03-23 Daiki Ueno + + * 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 * fontset.c (fontset_pattern_regexp): Replace + 1 with + 3 for diff --git a/src/process.c b/src/process.c index 1d935ba8a3e..5abe7489d0d 100644 --- a/src/process.c +++ b/src/process.c @@ -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); -- 2.39.5