diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2019-11-06 20:57:52 -0800 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2019-11-06 20:57:52 -0800 |
commit | 22265dd7d089f9137c75042c9ede58c5e0a6d3e1 (patch) | |
tree | b80f73f7b0d8fc5b3eef87d476c24a94870536e5 | |
parent | 04ac2824f9fa74583548b0cd58097d550a09b22a (diff) | |
download | txr-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.c | 81 | ||||
-rw-r--r-- | stream.h | 3 | ||||
-rw-r--r-- | txr.1 | 119 |
3 files changed, 196 insertions, 7 deletions
@@ -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 { @@ -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 } @@ -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 |