summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2024-06-26 20:21:34 -0700
committerKaz Kylheku <kaz@kylheku.com>2024-06-26 20:21:34 -0700
commite1f183b388bb9c6e8d13b0154f82a08ed30522b0 (patch)
treeb9cf064e57c1d2c64a98fb4bad7ef1250ce27d2d
parent8e8258ed0fab433fd6fb8d5e8480eabae9a807ca (diff)
downloadtxr-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.c24
-rw-r--r--stream.h7
-rw-r--r--txr.138
3 files changed, 61 insertions, 8 deletions
diff --git a/stream.c b/stream.c
index 953dc76a..7114a123 100644
--- a/stream.c
+++ b/stream.c
@@ -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]);
}
diff --git a/stream.h b/stream.h
index d4300154..9b3adf1f 100644
--- a/stream.h
+++ b/stream.h
@@ -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)))
diff --git a/txr.1 b/txr.1
index ec0a09b9..f20e0963 100644
--- a/txr.1
+++ b/txr.1
@@ -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 .