[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Proposed new feature for bash: unbuffered pipes, part 3: bash.diff
From: |
Dale R. Worley |
Subject: |
Proposed new feature for bash: unbuffered pipes, part 3: bash.diff |
Date: |
Tue, 21 Apr 2020 20:39:51 -0400 |
diff --git a/command.h b/command.h
index 3249516..ef611a4 100644
--- a/command.h
+++ b/command.h
@@ -186,6 +186,7 @@ typedef struct element {
#define CMD_COPROC_SUBSHELL 0x1000
#define CMD_LASTPIPE 0x2000
#define CMD_STDPATH 0x4000 /* use standard path for command lookup
*/
+#define CMD_STDOUT_UNBUFFERED 0x8000 /* Do not buffer stdout. */
/* What a command looks like. */
typedef struct command {
diff --git a/execute_cmd.c b/execute_cmd.c
index 8b3c83a..61d3647 100644
--- a/execute_cmd.c
+++ b/execute_cmd.c
@@ -567,6 +567,11 @@ execute_command_internal (command, asynchronous, pipe_in,
pipe_out,
volatile char *ofifo_list;
#endif
+#ifdef DRW
+ fprintf(stderr, "execute_command_internal %p %X\n", command, (command ?
command->flags : 0));
+ fprintf(stderr, "%s\n", make_command_string(command));
+#endif
+
if (breaking || continuing)
return (last_command_exit_value);
if (command == 0 || read_but_dont_execute)
@@ -836,6 +841,8 @@ execute_command_internal (command, asynchronous, pipe_in,
pipe_out,
command->value.Simple->flags |= CMD_IGNORE_RETURN;
if (command->flags & CMD_STDIN_REDIR)
command->value.Simple->flags |= CMD_STDIN_REDIR;
+ if (command->flags & CMD_STDOUT_UNBUFFERED)
+ command->value.Simple->flags |= CMD_STDOUT_UNBUFFERED;
line_number_for_err_trap = line_number = command->value.Simple->line;
exec_result =
@@ -2466,6 +2473,11 @@ execute_pipeline (command, asynchronous, pipe_in,
pipe_out, fds_to_close)
struct fd_bitmap *fd_bitmap;
pid_t lastpid;
+#ifdef DRW
+ fprintf(stderr, "execute_pipeline %p %X\n", command, command->flags);
+ fprintf(stderr, "%s\n", make_command_string(command));
+#endif
+
#if defined (JOB_CONTROL)
sigset_t set, oset;
BLOCK_CHILD (set, oset);
@@ -2477,7 +2489,9 @@ execute_pipeline (command, asynchronous, pipe_in,
pipe_out, fds_to_close)
cmd = command;
while (cmd && cmd->type == cm_connection &&
- cmd->value.Connection && cmd->value.Connection->connector == '|')
+ cmd->value.Connection &&
+ (cmd->value.Connection->connector == '|' ||
+ cmd->value.Connection->connector == GREATER_BAR_GREATER))
{
/* Make a pipeline between the two commands. */
if (pipe (fildes) < 0)
@@ -2551,6 +2565,10 @@ execute_pipeline (command, asynchronous, pipe_in,
pipe_out, fds_to_close)
dispose_fd_bitmap (fd_bitmap);
discard_unwind_frame ("pipe-file-descriptors");
+ if (cmd->flags & CMD_STDOUT_UNBUFFERED)
+ /* If cmd should not buffer stdout, then cmd...->second should
+ not buffer stdout. */
+ cmd->value.Connection->second->flags |= CMD_STDOUT_UNBUFFERED;
cmd = cmd->value.Connection->second;
}
@@ -2644,6 +2662,11 @@ execute_connection (command, asynchronous, pipe_in,
pipe_out, fds_to_close)
int ignore_return, exec_result, was_error_trap, invert;
volatile int save_line_number;
+#ifdef DRW
+ fprintf(stderr, "execute_connection %p %X\n", command, (command ?
command->flags : 0));
+ fprintf(stderr, "%s\n", make_command_string(command));
+#endif
+
ignore_return = (command->flags & CMD_IGNORE_RETURN) != 0;
switch (command->value.Connection->connector)
@@ -4158,6 +4181,16 @@ execute_simple_command (simple_command, pipe_in,
pipe_out, async, fds_to_close)
SHELL_VAR *func;
volatile int old_builtin, old_command_builtin;
+#ifdef DRW
+ fprintf(stderr, "execute_simple_command %p %X\n", simple_command,
(simple_command ? simple_command->flags : 0));
+ {
+ WORD_LIST *w;
+ for (w = simple_command->words; w; w = w->next)
+ fprintf(stderr, "%s ", w->word->word);
+ fprintf(stderr, "\n");
+ }
+#endif
+
result = EXECUTION_SUCCESS;
special_builtin_failed = builtin_is_special = 0;
command_line = (char *)0;
@@ -5425,6 +5458,25 @@ execute_disk_command (words, redirects, command_line,
pipe_in, pipe_out,
exit (EXECUTION_FAILURE);
}
+#ifdef DRW
+ fprintf(stderr, "execute_disk_command %X '%s'\n", cmdflags,
command_line);
+#endif /* DRW */
+ if (cmdflags & CMD_STDOUT_UNBUFFERED)
+ {
+ /* Set the environment to request unbuffered stdout from the new
+ program. */
+ struct stat buf;
+ char value[40];
+ fstat(1, &buf);
+ sprintf(value, "STDOUT_UNBUFFERED=%lu:%lu", (unsigned long)
buf.st_dev,
+ (unsigned long) buf.st_ino);
+ maybe_make_export_env ();
+ export_env = add_or_supercede_exported_var (value, 1);
+#ifdef DRW
+ fprintf(stderr, "execute_disk_command set '%s'\n", value);
+#endif /* DRW */
+ }
+
if (async)
interactive = old_interactive;
diff --git a/make_cmd.c b/make_cmd.c
index ecbbfd6..cd8e4c6 100644
--- a/make_cmd.c
+++ b/make_cmd.c
@@ -39,6 +39,7 @@
#include "parser.h"
#include "flags.h"
#include "input.h"
+#include "y.tab.h"
#if defined (JOB_CONTROL)
#include "jobs.h"
@@ -189,11 +190,19 @@ command_connect (com1, com2, connector)
{
CONNECTION *temp;
+ if (connector == GREATER_BAR_GREATER || connector == GREATER_BAR_GREATER_AND)
+ com1->flags |= CMD_STDOUT_UNBUFFERED;
+
temp = (CONNECTION *)xmalloc (sizeof (CONNECTION));
temp->connector = connector;
temp->first = com1;
temp->second = com2;
- return (make_command (cm_connection, (SIMPLE_COM *)temp));
+ COMMAND *c = make_command (cm_connection, (SIMPLE_COM *)temp);
+#ifdef DRW
+ fprintf(stderr, "command_connect com1 = %p %X, com2 = %p %X, c = %p %X,
connector = %d\n", com1, (com1 ? com1->flags : 0), com2, (com2 ? com2->flags :
0), c, (c ? c->flags : 0), connector);
+ fprintf(stderr, "%s\n", make_command_string(c));
+#endif
+ return (c);
}
static COMMAND *
diff --git a/parse.y b/parse.y
index 3ff87bc..49c2162 100644
--- a/parse.y
+++ b/parse.y
@@ -214,6 +214,8 @@ static size_t shell_input_line_propsize = 0;
# define set_line_mbstate()
#endif
+static void redirect_stderr_to_stdout __P((COMMAND *));
+
extern int yyerror __P((const char *));
#ifdef DEBUG
@@ -352,6 +354,7 @@ static FILE *yyerrstream;
%token GREATER_AND SEMI_SEMI SEMI_AND SEMI_SEMI_AND
%token LESS_LESS_MINUS AND_GREATER AND_GREATER_GREATER LESS_GREATER
%token GREATER_BAR BAR_AND
+%token GREATER_BAR_GREATER GREATER_BAR_GREATER_AND
/* The types that the various syntactical units return. */
@@ -375,7 +378,7 @@ static FILE *yyerrstream;
%left '&' ';' '\n' yacc_EOF
%left AND_AND OR_OR
-%right '|' BAR_AND
+%right '|' BAR_AND GREATER_BAR_GREATER GREATER_BAR_GREATER_AND
%%
inputunit: simple_list simple_list_terminator
@@ -1283,29 +1286,18 @@ pipeline_command: pipeline
pipeline: pipeline '|' newline_list pipeline
{ $$ = command_connect ($1, $4, '|'); }
+ | pipeline GREATER_BAR_GREATER newline_list pipeline
+ { $$ = command_connect ($1, $4, GREATER_BAR_GREATER); }
| pipeline BAR_AND newline_list pipeline
{
- /* Make cmd1 |& cmd2 equivalent to cmd1 2>&1 | cmd2 */
- COMMAND *tc;
- REDIRECTEE rd, sd;
- REDIRECT *r;
-
- tc = $1->type == cm_simple ? (COMMAND
*)$1->value.Simple : $1;
- sd.dest = 2;
- rd.dest = 1;
- r = make_redirection (sd, r_duplicating_output, rd,
0);
- if (tc->redirects)
- {
- register REDIRECT *t;
- for (t = tc->redirects; t->next; t = t->next)
- ;
- t->next = r;
- }
- else
- tc->redirects = r;
-
+ redirect_stderr_to_stdout($1);
$$ = command_connect ($1, $4, '|');
}
+ | pipeline GREATER_BAR_GREATER_AND newline_list pipeline
+ {
+ redirect_stderr_to_stdout($1);
+ $$ = command_connect ($1, $4, GREATER_BAR_GREATER);
+ }
| command
{ $$ = $1; }
;
@@ -1319,6 +1311,31 @@ timespec: TIME
;
%%
+/* Make cmd1 |& cmd2 equivalent to cmd1 2>&1 | cmd2
+ Similarly, cmd1 >|>& cmd2 is equivalent to cmd1 2>&1 >|> cmd2 */
+static void
+redirect_stderr_to_stdout (pipeline)
+ COMMAND *pipeline;
+{
+ COMMAND *tc;
+ REDIRECTEE rd, sd;
+ REDIRECT *r;
+
+ tc = pipeline->type == cm_simple ? (COMMAND *)pipeline->value.Simple :
pipeline;
+ sd.dest = 2;
+ rd.dest = 1;
+ r = make_redirection (sd, r_duplicating_output, rd, 0);
+ if (tc->redirects)
+ {
+ register REDIRECT *t;
+ for (t = tc->redirects; t->next; t = t->next)
+ ;
+ t->next = r;
+ }
+ else
+ tc->redirects = r;
+}
+
/* Initial size to allocate for tokens, and the
amount to grow them by. */
#define TOKEN_DEFAULT_INITIAL_SIZE 496
@@ -2195,6 +2212,8 @@ STRING_INT_ALIST other_token_alist[] = {
{ "&>>", AND_GREATER_GREATER },
{ "<>", LESS_GREATER },
{ ">|", GREATER_BAR },
+ { ">|>", GREATER_BAR_GREATER },
+ { ">|>&", GREATER_BAR_GREATER_AND },
{ "|&", BAR_AND },
{ "EOF", yacc_EOF },
/* Tokens whose value is the character itself */
@@ -3375,7 +3394,19 @@ itrace("shell_getc: bash_input.location.string = `%s'",
bash_input.location.stri
else if MBTEST(character == '<' && peek_char == '>')
return (LESS_GREATER);
else if MBTEST(character == '>' && peek_char == '|')
- return (GREATER_BAR);
+ {
+ peek_char = shell_getc (1);
+ if MBTEST(peek_char == '>')
+ {
+ peek_char = shell_getc (1);
+ if MBTEST(peek_char == '&')
+ return (GREATER_BAR_GREATER_AND);
+ shell_ungetc (peek_char);
+ return (GREATER_BAR_GREATER);
+ }
+ shell_ungetc (peek_char);
+ return (GREATER_BAR);
+ }
else if MBTEST(character == '&' && peek_char == '>')
{
peek_char = shell_getc (1);
@@ -5395,6 +5426,8 @@ reserved_word_acceptable (toksym)
case ESAC:
case FI:
case IF:
+ case GREATER_BAR_GREATER_AND:
+ case GREATER_BAR_GREATER:
case OR_OR:
case SEMI_SEMI:
case SEMI_AND:
diff --git a/print_cmd.c b/print_cmd.c
index 9aa6557..1da3844 100644
--- a/print_cmd.c
+++ b/print_cmd.c
@@ -277,6 +277,12 @@ make_command_string_internal (command)
skip_this_indent++;
break;
+ case GREATER_BAR_GREATER:
+ print_deferred_heredocs (" >|> ");
+ if (command->value.Connection->second)
+ skip_this_indent++;
+ break;
+
case ';':
if (deferred_heredocs == 0)
{
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- Proposed new feature for bash: unbuffered pipes, part 3: bash.diff,
Dale R. Worley <=