diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2024-06-26 20:21:34 -0700 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2024-06-26 20:21:34 -0700 |
commit | e1f183b388bb9c6e8d13b0154f82a08ed30522b0 (patch) | |
tree | b9cf064e57c1d2c64a98fb4bad7ef1250ce27d2d | |
parent | 8e8258ed0fab433fd6fb8d5e8480eabae9a807ca (diff) | |
download | txr-e1f183b388bb9c6e8d13b0154f82a08ed30522b0.tar.gz txr-e1f183b388bb9c6e8d13b0154f82a08ed30522b0.tar.bz2 txr-e1f183b388bb9c6e8d13b0154f82a08ed30522b0.zip |
open-process: new ?fdno option for selecting stream fd.
If, for instance ?2 is specified in the mode string argument
of open-process and related functions, this means that the
file descriptor 2 of the process will be used as the data
source (or sink) for the stream that is returned by the
function. With this feature we can easily read the standard
error of a process while leaving its standard output
unredirected.
* stream.c (do_parse_mode): Parse the ? mode option.
(open_subprocess): Check for the presence of the alternative
file descriptor in the stdio_mode structure, and and use it
isntead of STDIN_FILENO or STDOUT_FILENO.
* stream.h (struct stdio_mode): New member, streamfd.
(stdio_mode_init_blank, stdio_mode_init_r,
stdio_mode_init_rpb, stdio_mode_init_blank, stdio_mode_init_r,
stdio_mode_init_rpb): Update initializer macros to cover the
new member, setting it to the default value -1 (not
specified).
* txr.1: Documented.
-rw-r--r-- | stream.c | 24 | ||||
-rw-r--r-- | stream.h | 7 | ||||
-rw-r--r-- | txr.1 | 38 |
3 files changed, 61 insertions, 8 deletions
@@ -1584,6 +1584,20 @@ static struct stdio_mode do_parse_mode(val mode_str, struct stdio_mode m_dfl, nredir++; break; } + case '?': + { + wchar_t *past; + long val = wcstol(ms + 1, &past, 10); + + if (past == ms + 1 || val < 0 || val >= INT_MAX) { + m.malformed = 1; + return m; + } + + m.streamfd = val; + ms = past - 1; + break; + } case 'z': m.gzip = 1; if (isdigit(convert(unsigned char, ms[1]))) { @@ -4526,6 +4540,8 @@ static val open_subprocess(val name, val mode_str, val args, val fun) struct save_fds sfds; val ret = nil; int fds_flags = (input ? FDS_IN : FDS_OUT) | FDS_ERR; + int streamfd_in = m.streamfd != -1 ? m.streamfd : STDIN_FILENO; + int streamfd_out = m.streamfd != -1 ? m.streamfd : STDOUT_FILENO; args = default_null_arg(args); fun = default_null_arg(fun); @@ -4579,13 +4595,13 @@ static val open_subprocess(val name, val mode_str, val args, val fun) fds_clobber(&sfds, fds_flags); if (input) { - dup2(fd[1], STDOUT_FILENO); - if (fd[1] != STDOUT_FILENO) /* You never know */ + dup2(fd[1], streamfd_out); + if (fd[1] != streamfd_out) /* You never know */ close(fd[1]); close(fd[0]); } else { - dup2(fd[0], STDIN_FILENO); - if (fd[0] != STDIN_FILENO) /* You never know */ + dup2(fd[0], streamfd_in); + if (fd[0] != streamfd_in) /* You never know */ close(fd[0]); close(fd[1]); } @@ -121,11 +121,12 @@ struct stdio_mode { unsigned tmpfile : 1; int buforder : 5; int redir[STDIO_MODE_NREDIRS][2]; + int streamfd; }; -#define stdio_mode_init_blank { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, { { 0 } } } -#define stdio_mode_init_r { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, { { 0 } } } -#define stdio_mode_init_rpb { 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, { { 0 } } } +#define stdio_mode_init_blank { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, { { 0 } }, -1 } +#define stdio_mode_init_r { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, { { 0 } }, -1 } +#define stdio_mode_init_rpb { 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, { { 0 } }, -1 } #define std_input (deref(lookup_var_l(nil, stdin_s))) #define std_output (deref(lookup_var_l(nil, stdout_s))) @@ -62988,7 +62988,7 @@ Note that it permits no whitespace characters: .mets < mode := { < selector [ + ] | + } .mets < selector := { r | w | a | m | T } .mets < options := { b | x | l | u | i | n | < digit | -.mets \ \ \ \ \ \ \ \ \ \ \ \ \ \ <> z[ digit ] | < redirection } +.mets \ \ \ \ \ \ \ \ \ \ \ \ \ \ <> z[ digit ] | < redirection | >> ? fdno } .mets < digit := { 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 } .onom @@ -63160,6 +63160,17 @@ in mode strings that are passed to the function; the syntax performs I/O redirections in the child process created by that function, and is described in that function's documentation. +.meIP >> ? fdno +Like +.metn redirection , +this option refers to syntax which only has an effect in +mode strings that are passed to the +.code open-process +function. The syntax selects an alternative file descriptor +to connect to the returned stream. This is described in the +documentation for +.code open-process +function. .RE .IP The @@ -66219,6 +66230,31 @@ to standard output, standard input is connected to the null device, and descriptor 27 is redirected to descriptor 31. The +.meta mode-string +argument of +.code open-process +also supports a special +.mono +.meti >> ? fdno +.onom +syntax. This syntax specifies an alternative file descriptor in +the process to which the returned stream should be connected. +By default, when the process is opened for writing, its standard +output descriptpr 1 is used, and when it is opened for reading, +its standard input descriptor 0 is used. This option overrides the +choice of descriptor. The +.meta fdno +portion of the syntax must be a sequence of decimal digits, immediately +following the +.code ? +character. For example, the mode string +.str ?2 +specifies that the process is to be open for input, such that +the input stream captures the standard error output of +that process. In this situation, the standard output will not be +captured; it remains unredirected. + +The .code open-subprocess function is a variant of .codn open-process . |