only push the delimiter back if we read that character ourselves
(i > 1).
Report from Greg Wooledge <greg@wooledge.org>
+
+ 4/23
+ ----
+parse.y
+ - pop_delimiter: only decrement delimiter_depth if it's > 0, since
+ reset_parser() may have set it to 0 after the matching call to
+ push_delimiter
+ Report from Grisha Levit <grishalevit@gmail.com> based on a report
+ from Александр Ушаков <aushakov@astralinux.ru>
+
+ 4/25
+ ----
+parse.y
+ - read_a_line: if the shell is interactive, and not reading from a
+ string, check whether a previous call to shell_getc has set
+ EOF_Reached and return EOF in this case, after resetting the
+ current token to '\n'. This makes EOFs that are not the first
+ character on the line `sticky' instead of just token delimiters.
+ From https://savannah.gnu.org/bugs/?67045
+ - history_delimiting_chars: if it looks like we just finished a
+ subshell, and the line we're adding begins with an operator that
+ can't follow a semicolon, return a newline
+ From https://savannah.gnu.org/patch/?10517
+
+ 4/28
+ ----
+parse.y
+ - parse_arith_command: if the character after the first right paren
+ isn't a right paren, making the construct a nested subshell, push
+ that character back and return the subshell command as the current
+ token string, which we push onto the pushed string list. Reading
+ one character more can cause synchronization problems with backslash
+ newline, among other things.
+ From https://savannah.gnu.org/patch/?10517
+
QUIT;
/* If we're reading the here-document from an alias, use shell_getc */
- c = heredoc_string ? shell_getc (0) : yy_getc ();
+ if (interactive && EOF_Reached && heredoc_string == 0)
+ {
+ c = EOF;
+ EOF_Reached = 0;
+ if (current_token == yacc_EOF)
+ current_token = '\n'; /* reset state */
+ }
+ else
+ c = heredoc_string ? shell_getc (0) : yy_getc ();
/* Ignore null bytes in input. */
if (c == 0)
} \
while (0)
-#define pop_delimiter(ds) ds.delimiter_depth--
+/* The parsing or expansion code may have called reset_parser() between the
+ time push_delimiter was called and this call to pop_delimiter, which resets
+ delimiter_depth to 0, so we check. */
+#define pop_delimiter(ds) do { if (ds.delimiter_depth > 0) ds.delimiter_depth--; } while (0)
/* Return the next shell input character. This always reads characters
from shell_input_line; when that line is exhausted, it is time to
}
else /* nested subshell */
{
+ shell_ungetc (c);
+
tokstr[0] = '(';
strncpy (tokstr + 1, ttok, ttoklen - 1);
tokstr[ttoklen] = ')';
- tokstr[ttoklen+1] = c;
- tokstr[ttoklen+2] = '\0';
+ tokstr[ttoklen+1] = '\0';
}
*ep = tokstr;
0
};
+static const int no_semi_predecessors[] = {
+'&', '|', ';', 0
+};
+
/* If we are not within a delimited expression, try to be smart
about which separators can be semi-colons and which must be
newlines. Returns the string that should be added into the
history_delimiting_chars (const char *line)
{
static int last_was_heredoc = 0; /* was the last entry the start of a here document? */
+ const char *lp;
register int i;
if ((parser_state & PST_HEREDOC) == 0)
if (parser_state & PST_COMPASSIGN)
return (" ");
+ for (lp = line; *lp && shellblank(*lp); lp++)
+ ;
+
/* First, handle some special cases. */
/*(*/
/* If we just read `()', assume it's a function definition, and don't
else if (parser_state & PST_CASESTMT) /* case statement pattern */
return " ";
else
- return "; "; /* (...) subshell */
+ {
+ /* (...) subshell. Make sure this line doesn't start with an
+ operator that cannot be preceded by a semicolon. If it can't
+ (basically the command terminators), return a newline. */
+ for (i = 0; no_semi_predecessors[i]; i++)
+ if (*lp == no_semi_predecessors[i])
+ return "\n";
+ return "; ";
+ }
}
else if (token_before_that == WORD && two_tokens_ago == FUNCTION)
return " "; /* function def using `function name' without `()' */
printf '%b\200' winter 'spring\0375' summer automn |
while IFS= read -rd $'\200' season; do LC_ALL=C printf "<%q>\n" "$season"; done
-: ${TMPDIR:=/tmp}
-INFILE=$TMPDIR/read-in-$$
-printf '%b\243' winter 'spring\0375' '\0277summer' '\0277' automn > $INFILE
-
-LANG=zh_HK.big5hkscs
-while IFS= read -rd $'\243' season; do
- LC_ALL=C printf "<%q>\n" "$season"
-done < $INFILE
+# this test is encoding-dependent, and varies from system to system
+#: ${TMPDIR:=/tmp}
+#INFILE=$TMPDIR/read-in-$$
+#printf '%b\243' winter 'spring\0375' '\0277summer' '\0277' automn > $INFILE
+#
+#LANG=zh_HK.big5hkscs
+#while IFS= read -rd $'\243' season; do
+# LC_ALL=C printf "<%q>\n" "$season"
+#done < $INFILE
+#
+#rm -f $INFILE
-rm -f $INFILE
exit 0