summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2019-11-06 20:57:52 -0800
committerKaz Kylheku <kaz@kylheku.com>2019-11-06 20:57:52 -0800
commit22265dd7d089f9137c75042c9ede58c5e0a6d3e1 (patch)
treeb80f73f7b0d8fc5b3eef87d476c24a94870536e5
parent04ac2824f9fa74583548b0cd58097d550a09b22a (diff)
downloadtxr-22265dd7d089f9137c75042c9ede58c5e0a6d3e1.tar.gz
txr-22265dd7d089f9137c75042c9ede58c5e0a6d3e1.tar.bz2
txr-22265dd7d089f9137c75042c9ede58c5e0a6d3e1.zip
open-process: I/O redirection feature.
In the mode-string of open-process, I/O redirections can now be specified that are carried out in the child process. * stream.c (do_parse_mode): Parse the redirection syntax indicated by >, which has a short and long form. The redirections are entered into a small table in the mode structure. (open_process): In the child process, perform the redirection specified in the mode structure's redirection table. * stream.h (STDIO_MODE_NREDIRS): New preprprocessor symbol. (struct stdio_mode): New array member, redir. * txr.1: Documented.
-rw-r--r--stream.c81
-rw-r--r--stream.h3
-rw-r--r--txr.1119
3 files changed, 196 insertions, 7 deletions
diff --git a/stream.c b/stream.c
index 0993ef97..18c154b3 100644
--- a/stream.c
+++ b/stream.c
@@ -1332,6 +1332,7 @@ static struct stdio_mode do_parse_mode(val mode_str, struct stdio_mode m_dfl)
{
struct stdio_mode m = stdio_mode_init_blank;
const wchar_t *ms = c_str(default_arg(mode_str, lit("")));
+ int nredir = 0;
switch (*ms) {
case 'r':
@@ -1392,12 +1393,64 @@ static struct stdio_mode do_parse_mode(val mode_str, struct stdio_mode m_dfl)
}
m.buforder = *ms - '0';
break;
+ case '>':
+ if (nredir >= STDIO_MODE_NREDIRS) {
+ m.malformed = 1;
+ return m;
+ }
+
+ if (ms[1] != '(') {
+ if (!isdigit((unsigned char) ms[1]) || !ms[2]) {
+ m.malformed = 1;
+ return m;
+ }
+
+ m.redir[nredir][0] = ms[1] - '0';
+ if (isdigit((unsigned char) ms[2])) {
+ m.redir[nredir][1] = ms[2] - '0';
+ } else switch (ms[2]) {
+ case 'n': case 'x':
+ m.redir[nredir][1] = ms[2];
+ break;
+ default:
+ m.malformed = 1;
+ return m;
+ }
+
+ ms += 2;
+ nredir++;
+ break;
+ }
+
+ {
+ char code[2];
+ char rpar[2];
+ unsigned to, from;
+
+ if (swscanf(ms, L">(%u %[nx]%[)]", &to, code, rpar) == 3) {
+ m.redir[nredir][0] = to;
+ m.redir[nredir][1] = code[0];
+ } else if (swscanf(ms, L">(%u %u%[)]", &to, &from, rpar) == 3) {
+ m.redir[nredir][0] = to;
+ m.redir[nredir][1] = from;
+ } else {
+ m.malformed = 1;
+ return m;
+ }
+
+ ms = wcschr(ms, ')');
+ nredir++;
+ break;
+ }
default:
m.malformed = 1;
return m;
}
}
+ if (nredir < STDIO_MODE_NREDIRS)
+ m.redir[nredir][0] = -1;
+
return m;
}
@@ -4107,6 +4160,34 @@ val open_process(val name, val mode_str, val args)
close(fd[1]);
}
+ for (i = 0; i < STDIO_MODE_NREDIRS; i++) {
+ int to = m.redir[i][0];
+ int from = m.redir[i][1];
+
+ if (to < 0)
+ break;
+
+ switch (from) {
+ case 'n':
+#if HAVE_FCNTL
+ {
+ int n = open("/dev/null", O_RDWR);
+ if (n > 0) {
+ dup2(n, to);
+ close(n);
+ }
+ }
+#endif
+ break;
+ case 'x':
+ close(to);
+ break;
+ default:
+ dup2(from, to);
+ break;
+ }
+ }
+
execvp(argv[0], argv);
_exit(errno);
} else {
diff --git a/stream.h b/stream.h
index 9bae897c..5d137d47 100644
--- a/stream.h
+++ b/stream.h
@@ -99,6 +99,8 @@ struct strm_ops {
get_error, get_error_str, clear_error, get_fd, 0, 0, 0, 0 \
}
+#define STDIO_MODE_NREDIRS 4
+
struct stdio_mode {
unsigned malformed : 1;
unsigned read : 1;
@@ -110,6 +112,7 @@ struct stdio_mode {
unsigned unbuf : 1;
unsigned linebuf : 1;
int buforder : 5;
+ int redir[STDIO_MODE_NREDIRS][2];
};
#define stdio_mode_init_blank { 0, 0, 0, 0, 0, 0, 0, 0, 0, -1 }
diff --git a/txr.1 b/txr.1
index a22b2423..f49c8d95 100644
--- a/txr.1
+++ b/txr.1
@@ -48507,7 +48507,7 @@ grammar. Note that it permits no whitespace characters:
.mets < mode-string := [ < mode ] [ < options ]
.mets < mode := { < selector [ + ] | + }
.mets < selector := { r | w | a }
-.mets < options := { b | l | u | < digit }
+.mets < options := { b | l | u | < digit | < redirection }
.mets < digit := { 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 }
.onom
@@ -48599,6 +48599,13 @@ specifying 524288 bytes. If no such digit is specified, then the
stream uses a default buffer size. It is erroneous for the
size order digit to be present together with the option
.codn u .
+.meIP redirection
+This option refers to a special syntax that only has an effect
+in mode strings that are passed to the
+.code open-process
+function; the syntax performs I/O redirections in the child process
+created by that function, and is described in that function's
+documentation.
.RE
.coNP Function @ open-tail
@@ -50522,6 +50529,16 @@ the value
if it is missing. See the
.code open-file
function for a discussion of modes.
+The
+.code open-command
+function is implemented using POSIX
+.codn popen .
+Those elements of
+.meta mode-string
+which are applicable to
+.code popen
+are passed to it, and hence their semantics follows from
+their processing in that function.
The
.code open-command
@@ -50548,12 +50565,6 @@ as its exit status. This value can be retrieved via
.codn close-stream .
The
-.meta mode-string
-argument follows the convention used by the POSIX
-.code popen
-function.
-
-The
.meta argument-list
argument is a list of strings which specifies additional
optional arguments to be passed passed to the program. The
@@ -50649,6 +50660,100 @@ situation also.
If a coprocess terminates abnormally or unsuccessfully, an exception is raised.
+On platforms which have the
+.code fork
+function, the
+.meta mode-string
+argument of
+.code open-process
+supports a special
+.meta redirection
+syntax. This syntax specifies I/O redirections which are done in the
+context of the child process, before the specified program is executed.
+Instances of the syntax are considered options; if
+.meta mode-string
+specifies a mode such as
+.code r
+that mode must precede the redirections. Redirections may be mixed with
+other options.
+
+Up to four redirections may be specified using one
+of two forms: a short form or the long form. If more than four
+redirections are specified, the
+.meta mode-string
+is considered ill-formed.
+
+The short form of the syntax consists of three characters: the prefix
+character
+.codn > ,
+a single decimal digit indicating the file descriptor to be redirected,
+and then a third character which is either another digit, or else one of the
+two characters
+.code n
+or
+.codn x .
+If the third character is a digit, it indicates the target file descriptor
+of the redirection. For instance
+.code >21
+indicates that file descriptor 2 is to be redirected to 1 (so that material
+written to standard error goes to the same destination as that written
+to standard output).
+If the third character is
+.codn n ,
+it means that the file descriptor will be redirected to the file
+.codn /dev/null .
+For instance,
+.code >2n
+indicates that descriptor 2 (standard error) will be redirected to
+the null device. If the third character is
+.codn x ,
+it indicates that the file descriptor shall be closed. For instance
+.code >0x
+means to close descriptor 0 (standard input).
+
+The long form of the syntax allows file descriptors that require more
+than one decimal digit. It consists of the same prefix character
+.code >
+which is immediately followed by an open parenthesis
+.codn ( .
+The parenthesis is immediately followed by one or more digits which
+give the to-be-redirected file descriptor. This is followed by
+one or more whitespace characters, and then either another multi-digit decimal file descriptor
+or one of the two letters
+.code n
+or
+.codn x .
+This second element must be immediately followed by the closing
+parenthesis
+.codn ) .
+Thus
+.code >21
+and
+.code >2n
+may be written in the long form, respectively, as
+.code ">(2 1)"
+and
+.codn ">(2 n)" ,
+while
+.code ">(32 47)"
+has no short form equivalent.
+Multiple redirections may be specified, in any mixture of the long and
+short form. For instance
+.code "r>21>0n>(27 31)"
+specifies a process pipe that is open for reading, capturing the
+output of the process. In that process, standard error is redirected
+to standard output, standard input is connected to the null device,
+and descriptor 27 is redirected to descriptor 31.
+
+Note: on platforms which don't have a
+.code fork
+function, the implementation of
+.code open-process
+is simulated via
+.code open-command
+and therefore does not support the redirection syntax; it is parsed
+and ignored.
+
.SS* I/O-Related Convenience Functions
The functions in this group create a stream, perform an I/O operation