Add STREAM argument to 'process-tty-name'

* src/process.c (process-tty-name): Add STREAM argument.

* lisp/eshell/esh-io.el (eshell-close-target): Only call
'process-send-eof' once if the process's stdin is a pipe.

* test/src/process-tests.el (make-process/test-connection-type): Check
behavior of 'process-tty-name'.

* doc/lispref/processes.texi (Process Information): Document the new
argument.

* etc/NEWS: Announce this change.
This commit is contained in:
Jim Porter 2022-07-19 21:36:54 -07:00
parent d7b89ea407
commit 4e59830bc0
5 changed files with 58 additions and 23 deletions

View file

@ -1243,15 +1243,24 @@ that are already closed, the value is either 0 or 256, depending on
whether the connection was closed normally or abnormally.
@end defun
@defun process-tty-name process
@defun process-tty-name process &optional stream
This function returns the terminal name that @var{process} is using for
its communication with Emacs---or @code{nil} if it is using pipes
instead of a pty (see @code{process-connection-type} in
@ref{Asynchronous Processes}). If @var{process} represents a program
running on a remote host, the terminal name used by that program on
the remote host is provided as process property @code{remote-tty}. If
@var{process} represents a network, serial, or pipe connection, the
value is @code{nil}.
@ref{Asynchronous Processes}). By default, this function returns the
terminal name if any of @var{process}'s standard streams use a
terminal. If @var{stream} is one of @code{stdin}, @code{stdout}, or
@code{stderr}, this function returns the terminal name (or @code{nil},
as above) that @var{process} uses for that stream specifically. You
can use this to determine whether a particular stream uses a pipe or a
pty.
If @var{process} represents a program running on a remote host, this
function returns the @emph{local} terminal name that communicates with
@var{process}; you can get the terminal name used by that program on
the remote host with the process property @code{remote-tty}. If
@var{process} represents a network, serial, or pipe connection, this
function always returns @code{nil}.
@end defun
@defun process-coding-system process

View file

@ -3333,7 +3333,10 @@ invocation. Such shells are POSIX conformant by default.
** 'make-process' can set connection type independently for input and output.
When calling 'make-process', communication via pty can be enabled
selectively for just input or output by passing a cons cell for
':connection-type', e.g. '(pipe . pty)'.
':connection-type', e.g. '(pipe . pty)'. When examining a process
later, you can determine whether a particular stream for a process
uses a pty by passing one of 'stdin', 'stdout', or 'stderr' as the
second argument to 'process-tty-name'.
+++
** 'signal-process' now consults the list 'signal-process-functions'.

View file

@ -276,18 +276,21 @@ STATUS should be non-nil on successful termination of the output."
;; If we're redirecting to a process (via a pipe, or process
;; redirection), send it EOF so that it knows we're finished.
((eshell-processp target)
;; According to POSIX.1-2017, section 11.1.9, sending EOF causes
;; all bytes waiting to be read to be sent to the process
;; immediately. Thus, if there are any bytes waiting, we need to
;; send EOF twice: once to flush the buffer, and a second time to
;; cause the next read() to return a size of 0, indicating
;; end-of-file to the reading process. However, some platforms
;; (e.g. Solaris) actually require sending a *third* EOF. Since
;; sending extra EOFs while the process is running shouldn't break
;; anything, we'll just send the maximum we'd ever need. See
;; bug#56025 for further details.
(let ((i 0))
(while (and (<= (cl-incf i) 3)
;; According to POSIX.1-2017, section 11.1.9, when communicating
;; via terminal, sending EOF causes all bytes waiting to be read
;; to be sent to the process immediately. Thus, if there are any
;; bytes waiting, we need to send EOF twice: once to flush the
;; buffer, and a second time to cause the next read() to return a
;; size of 0, indicating end-of-file to the reading process.
;; However, some platforms (e.g. Solaris) actually require sending
;; a *third* EOF. Since sending extra EOFs while the process is
;; running are a no-op, we'll just send the maximum we'd ever
;; need. See bug#56025 for further details.
(let ((i 0)
;; Only call `process-send-eof' once if communicating via a
;; pipe (in truth, this just closes the pipe).
(max-attempts (if (process-tty-name target 'stdin) 3 1)))
(while (and (<= (cl-incf i) max-attempts)
(eq (process-status target) 'run))
(process-send-eof target))))

View file

@ -1243,14 +1243,31 @@ or t (process is stopped). */)
return XPROCESS (process)->command;
}
DEFUN ("process-tty-name", Fprocess_tty_name, Sprocess_tty_name, 1, 1, 0,
DEFUN ("process-tty-name", Fprocess_tty_name, Sprocess_tty_name, 1, 2, 0,
doc: /* Return the name of the terminal PROCESS uses, or nil if none.
This is the terminal that the process itself reads and writes on,
not the name of the pty that Emacs uses to talk with that terminal. */)
(register Lisp_Object process)
not the name of the pty that Emacs uses to talk with that terminal.
If STREAM is nil, return the terminal name if any of PROCESS's
standard streams use a terminal for communication. If STREAM is one
of `stdin', `stdout', or `stderr', return the name of the terminal
PROCESS uses for that stream specifically, or nil if that stream
communicates via a pipe. */)
(register Lisp_Object process, Lisp_Object stream)
{
CHECK_PROCESS (process);
return XPROCESS (process)->tty_name;
register struct Lisp_Process *p = XPROCESS (process);
if (NILP (stream))
return p->tty_name;
else if (EQ (stream, Qstdin))
return p->pty_in ? p->tty_name : Qnil;
else if (EQ (stream, Qstdout))
return p->pty_out ? p->tty_name : Qnil;
else if (EQ (stream, Qstderr))
return p->pty_out && NILP (p->stderrproc) ? p->tty_name : Qnil;
else
signal_error ("Unknown stream", stream);
}
static void

View file

@ -294,6 +294,9 @@ should be a TTY, respectively."
"if [ -t 2 ]; then echo stderr; fi"))
:buffer stdout-buffer
args)))
(should (eq (and (process-tty-name proc 'stdin) t) (nth 0 ttys)))
(should (eq (and (process-tty-name proc 'stdout) t) (nth 1 ttys)))
(should (eq (and (process-tty-name proc 'stderr) t) (nth 2 ttys)))
(process-test-wait-for-sentinel proc 0)
(should (equal (with-current-buffer stdout-buffer (buffer-string))
expected-output))))