changes to text representation of parsed command substitution; small changes to tests

This commit is contained in:
Chet Ramey
2022-07-06 10:05:59 -04:00
parent 42768befc0
commit 67e47f224c
13 changed files with 863 additions and 1080 deletions
+4 -1
View File
@@ -321,7 +321,10 @@ b. There is a new internal timer framework used for read builtin timeouts.
c. Rewrote the command substitution parsing code to call the parser recursively
and rebuild the command string from the parsed command. This allows better
syntax checking and catches errors much earlier.
syntax checking and catches errors much earlier. Along with this, if
command substitution parsing completes with here-documents remaining to be
read, the shell prints a warning message and reads the here-document bodies
from the current input stream.
d. The `ulimit' builtin now treats an operand remaining after all of the options
and arguments are parsed as an argument to the last command specified by
+4 -1
View File
@@ -321,7 +321,10 @@ b. There is a new internal timer framework used for read builtin timeouts.
c. Rewrote the command substitution parsing code to call the parser recursively
and rebuild the command string from the parsed command. This allows better
syntax checking and catches errors much earlier.
syntax checking and catches errors much earlier. Along with this, if
command substitution parsing completes with here-documents remaining to be
read, the shell prints a warning message and reads the here-document bodies
from the current input stream.
d. The `ulimit' builtin now treats an operand remaining after all of the options
and arguments are parsed as an argument to the last command specified by
+18
View File
@@ -3731,3 +3731,21 @@ subst.c
indicating that we're doing this for completion, probably to
determine whether or not to append something to the word. Fixes bug
reported by Emanuele Torre <torreemanuele6@gmail.com>.
7/5
---
execute_cmd.c
- execute_connection: treat a connector of '\n' the same as ';'
print_cmd.c
- print_comsub: new function, sets flag noting we are printing a
command substitution and calls make_command_string
- make_command_string_internal: add '\n' to the ';' case; print command
list with newline connector appropriately
parse.y
- parse_comsub: call print_comsub instead of make_command_string
- list1 production (part of compound_list): if a list is separated by
newlines, and the parser is parsing a command substitution, make
the connection command with a '\n' connector. Makes the text
output of parse_comsub closer to the original source text. From a
report from Martijn Dekker <martijn@inlv.org>
+4 -1
View File
@@ -10,7 +10,10 @@ b. There is a new internal timer framework used for read builtin timeouts.
c. Rewrote the command substitution parsing code to call the parser recursively
and rebuild the command string from the parsed command. This allows better
syntax checking and catches errors much earlier.
syntax checking and catches errors much earlier. Along with this, if
command substitution parsing completes with here-documents remaining to be
read, the shell prints a warning message and reads the here-document bodies
from the current input stream.
d. The `ulimit' builtin now treats an operand remaining after all of the options
and arguments are parsed as an argument to the last command specified by
+4 -1
View File
@@ -10,7 +10,10 @@ b. There is a new internal timer framework used for read builtin timeouts.
c. Rewrote the command substitution parsing code to call the parser recursively
and rebuild the command string from the parsed command. This allows better
syntax checking and catches errors much earlier.
syntax checking and catches errors much earlier. Along with this, if
command substitution parsing completes with here-documents remaining to be
read, the shell prints a warning message and reads the here-document bodies
from the current input stream.
d. The `ulimit' builtin now treats an operand remaining after all of the options
and arguments are parsed as an argument to the last command specified by
+1
View File
@@ -2738,6 +2738,7 @@ execute_connection (command, asynchronous, pipe_in, pipe_out, fds_to_close)
/* Just call execute command on both sides. */
case ';':
case '\n': /* special case, happens in command substitutions */
if (ignore_return)
{
if (command->value.Connection->first)
+1
View File
@@ -36,6 +36,7 @@ extern intmax_t evalexp PARAMS((char *, int, int *));
#define FUNC_EXTERNAL 0x02
extern char *make_command_string PARAMS((COMMAND *));
extern char *print_comsub PARAMS((COMMAND *));
extern char *named_function_string PARAMS((char *, COMMAND *, int));
extern void print_command PARAMS((COMMAND *));
+12 -7
View File
@@ -1154,7 +1154,12 @@ list1: list1 AND_AND newline_list list1
| list1 ';' newline_list list1
{ $$ = command_connect ($1, $4, ';'); }
| list1 '\n' newline_list list1
{ $$ = command_connect ($1, $4, ';'); }
{
if (parser_state & PST_CMDSUBST)
$$ = command_connect ($1, $4, '\n');
else
$$ = command_connect ($1, $4, ';');
}
| pipeline_command
{ $$ = $1; }
;
@@ -1188,7 +1193,7 @@ simple_list: simple_list1
gather_here_documents ();
if ((parser_state & PST_CMDSUBST) && current_token == shell_eof_token)
{
itrace("LEGACY: parser: command substitution simple_list1 -> simple_list");
INTERNAL_DEBUG (("LEGACY: parser: command substitution simple_list1 -> simple_list"));
global_command = $1;
eof_encountered = 0;
if (bash_input.type == st_string)
@@ -1206,7 +1211,7 @@ itrace("LEGACY: parser: command substitution simple_list1 -> simple_list");
gather_here_documents ();
if ((parser_state & PST_CMDSUBST) && current_token == shell_eof_token)
{
itrace("LEGACY: parser: command substitution simple_list1 '&' -> simple_list");
INTERNAL_DEBUG (("LEGACY: parser: command substitution simple_list1 '&' -> simple_list"));
global_command = $1;
eof_encountered = 0;
if (bash_input.type == st_string)
@@ -1221,7 +1226,7 @@ itrace("LEGACY: parser: command substitution simple_list1 '&' -> simple_list");
gather_here_documents ();
if ((parser_state & PST_CMDSUBST) && current_token == shell_eof_token)
{
itrace("LEGACY: parser: command substitution simple_list1 ';' -> simple_list");
INTERNAL_DEBUG (("LEGACY: parser: command substitution simple_list1 ';' -> simple_list"));
global_command = $1;
eof_encountered = 0;
if (bash_input.type == st_string)
@@ -4095,8 +4100,8 @@ parse_comsub (qc, open, close, lenp, flags)
if (need_here_doc > 0)
{
internal_debug("command substitution: %d unterminated here-document%s", need_here_doc, (need_here_doc == 1) ? "" : "s");
gather_here_documents ();
internal_warning ("command substitution: %d unterminated here-document%s", need_here_doc, (need_here_doc == 1) ? "" : "s");
gather_here_documents (); /* XXX check compatibility level? */
}
parsed_command = global_command;
@@ -4126,7 +4131,7 @@ INTERNAL_DEBUG(("current_token (%d) != shell_eof_token (%c)", current_token, she
restore_parser_state (&ps);
tcmd = make_command_string (parsed_command); /* returns static memory */
tcmd = print_comsub (parsed_command); /* returns static memory */
retlen = strlen (tcmd);
if (tcmd[0] == '(') /* ) need a space to prevent arithmetic expansion */
retlen++;
BIN
View File
Binary file not shown.
+752 -1042
View File
File diff suppressed because it is too large Load Diff
+46 -18
View File
@@ -129,6 +129,7 @@ static int inside_function_def;
static int skip_this_indent;
static int was_heredoc;
static int printing_connection;
static int printing_comsub;
static REDIRECT *deferred_heredocs;
/* The depth of the group commands that we are currently printing. This
@@ -162,6 +163,21 @@ make_command_string (command)
return (the_printed_command);
}
/* Print a command substitution after parsing it in parse_comsub to turn it
back into an external representation without turning newlines into `;'.
Placeholder for other changes, if any are necessary. */
char *
print_comsub (command)
COMMAND *command;
{
char *ret;
printing_comsub++;
ret = make_command_string (command);
printing_comsub--;
return ret;
}
/* The internal function. This is the real workhorse. */
static void
make_command_string_internal (command)
@@ -278,25 +294,35 @@ make_command_string_internal (command)
break;
case ';':
if (deferred_heredocs == 0)
{
if (was_heredoc == 0)
cprintf (";");
else
was_heredoc = 0;
}
else
print_deferred_heredocs (inside_function_def ? "" : ";");
case '\n': /* special case this */
{
char c = command->value.Connection->connector;
if (inside_function_def)
cprintf ("\n");
else
{
cprintf (" ");
if (command->value.Connection->second)
skip_this_indent++;
}
break;
s[0] = printing_comsub ? c : ';';
s[1] = '\0';
if (deferred_heredocs == 0)
{
if (was_heredoc == 0)
cprintf (s); /* inside_function_def? */
else
was_heredoc = 0;
}
else
/* print_deferred_heredocs special-cases `;' */
print_deferred_heredocs (inside_function_def ? "" : ";");
if (inside_function_def)
cprintf ("\n");
else
{
if (c == ';')
cprintf (" ");
if (command->value.Connection->second)
skip_this_indent++;
}
break;
}
default:
cprintf (_("print_command: bad connector `%d'"),
@@ -1293,6 +1319,7 @@ reset_locals ()
indentation = 0;
printing_connection = 0;
deferred_heredocs = 0;
printing_comsub = 0;
}
static void
@@ -1364,6 +1391,7 @@ named_function_string (name, command, flags)
old_amount = indentation_amount;
command_string_index = was_heredoc = 0;
deferred_heredocs = 0;
printing_comsub = 0;
if (name && *name)
{
+15 -8
View File
@@ -53,16 +53,23 @@ unset before after
# date +%s should be portable enough now
# then try gawk, perl, python in that order
now1=$(date +%s 2>/dev/null) D=date
[ -z "$now1" ] && now1=$(gawk 'BEGIN { print systime(); }' 2>/dev/null) D=gawk
[ -z "$now1" ] && now1=$(perl -e 'print time' 2>/dev/null) D=perl
[ -z "$now1" ] && now1=$(python -c 'import time; ts = int(time.time()); print(ts)' 2>/dev/null) D=python
[ -z "$now1" ] &&
{
now1=$(gawk 'BEGIN { print systime(); }' 2>/dev/null) D=gawk
[ -z "$now1" ] && now1=$(perl -e 'print time' 2>/dev/null) D=perl
[ -z "$now1" ] && now1=$(python -c 'import time; ts = int(time.time()); print(ts)' 2>/dev/null) D=python
}
now2=$EPOCHSECONDS
case $now1 in
$now2) echo EPOCHSECONDS ok ;;
'') echo "cannot get current time using date/gawk/perl/python" >&2 ;;
*) echo "current time via $D and EPOCHSECONDS possible mismatch|$now1|$now2" >&2 ;;
esac
# use a window of +-1 second
offset=1
if [[ -z $now1 ]]; then
echo "cannot get current time using date/gawk/perl/python" >&2
elif (( $now1 - $offset <= $now2 && $now2 <= $now1 + $offset )); then
echo EPOCHSECONDS ok
else
echo "current time via $D and EPOCHSECONDS possible mismatch|$now1|$now2|offset=$offset" >&2
fi
unset now1 now2 D
LC_ALL=C # force decimal point to `.'
+2 -1
View File
@@ -120,11 +120,12 @@ argv[3] = <ve>
5: ${x#$pat}
6: ${y#$'not'}
7: ${y#'not'}
./heredoc7.sub: line 17: warning: command substitution: 1 unterminated here-document
foo bar
./heredoc7.sub: line 21: after: command not found
./heredoc7.sub: line 29: warning: here-document at line 29 delimited by end-of-file (wanted `EOF')
./heredoc7.sub: line 29: foobar: command not found
./heredoc7.sub: line 29: EOF: command not found
./heredoc7.sub: line 30: EOF: command not found
grep: *.c: No such file or directory
comsub here-string
./heredoc.tests: line 156: warning: here-document at line 154 delimited by end-of-file (wanted `EOF')