From: Chet Ramey Date: Mon, 31 Jan 2022 14:53:03 +0000 (-0500) Subject: more changes for here-docs and $'...'; command optimization updates X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=b325b0e96bd05c76bbfc4d60d0707fc93d58f03f;p=thirdparty%2Fbash.git more changes for here-docs and $'...'; command optimization updates --- diff --git a/CWRU/CWRU.chlog b/CWRU/CWRU.chlog index 5982d30ca..446c3df4d 100644 --- a/CWRU/CWRU.chlog +++ b/CWRU/CWRU.chlog @@ -3009,10 +3009,48 @@ subst.c read this new ${...} string - extract_heredoc_dolbrace_string: new function, variant of extract_dollar_brace_string, to process the WORD in ${PARAM OP WORD} - while processing here-document data. It's complicated by the + while expanding lines of here-document data. It's complicated by the requirement to add to the result string as we go along, since we need to change the contents of the input string with ansi expansion or locale translation. - string_extract_single_quoted: take a new third argument: ALLOWESC. This allows backslash to escape an embedded single quote, needed by extract_heredoc_dolbrace_string to process $'...'; changed callers + + 1/25 + ---- +parse.y + - parse_matched_pair: ansi-expand $'...' in WORD for ${PARAM OP WORD} + and single-quote the result if dolbrace_state == DOLBRACE_QUOTE + (posix pattern removal operators) even if extended_quote == 0 + +subst.c + - extract_heredoc_dolbrace_string: add logic to align with parse.y: + parse_matched_pair and its $'...' expansion, including handling + extended_quote + + 1/27 + ---- +builtins/evalstring.c + - should_optimize_fork: broke conditions for optimizing away the fork + for a simple command out of optimize_fork into new function, call + from should_suppress_fork and optimize_subshell_command. Call from + optimize_fork if (subshell_environment & SUBSHELL_PAREN), relying + on fact that CMD_TRY_OPTIMIZING is only set in a couple of specific + conditions + - optimize_fork: call should_suppress_fork only if startup_state == 2; + it does the extra checks for that specific case + - optimize_fork: call should_optimize_fork if we're in a (list) + subshell (subshell_environment & SUBSHELL_PAREN) + - optimize_subshell_command: set CMD_TRY_OPTIMIZING on the right side + of a `&&', `||', or `;' list as long as it's a simple command so + we can check with optimize_fork() when it's time to execute it + +execute_cmd.c + - execute_in_subshell: call optimize_subshell_command for (list) + subshells to either set CMD_NO_FORK for simple commands or set + CMD_TRY_OPTIMIZING for likely candidates for later optimization + +builtins/common.h,builtins/evalstring.c + - optimize_fork: renamed to optimize_connection_fork; changed callers + diff --git a/MANIFEST b/MANIFEST index 75ad59822..a4cd9ead6 100644 --- a/MANIFEST +++ b/MANIFEST @@ -454,6 +454,7 @@ lib/sh/strtoul.c f lib/sh/strtoull.c f lib/sh/strtoumax.c f lib/sh/strtrans.c f +lib/sh/strvis.c f lib/sh/timers.c f lib/sh/times.c f lib/sh/timeval.c f diff --git a/Makefile.in b/Makefile.in index 818a51b75..ef26d7083 100644 --- a/Makefile.in +++ b/Makefile.in @@ -239,7 +239,7 @@ SHLIB_SOURCE = ${SH_LIBSRC}/clktck.c ${SH_LIBSRC}/getcwd.c \ ${SH_LIBSRC}/wcswidth.c ${SH_LIBSRC}/wcsnwidth.c \ ${SH_LIBSRC}/shmbchar.c ${SH_LIBSRC}/utf8.c \ ${SH_LIBSRC}/random.c ${SH_LIBSRC}/gettimeofday.c \ - ${SH_LIBSRC}/timers.c + ${SH_LIBSRC}/timers.c ${SH_LIBSRC}/strvis.c SHLIB_LIB = -lsh SHLIB_LIBNAME = libsh.a diff --git a/builtins/common.h b/builtins/common.h index 38326b99e..1cec62fc2 100644 --- a/builtins/common.h +++ b/builtins/common.h @@ -1,6 +1,6 @@ /* common.h -- extern declarations for functions defined in common.c. */ -/* Copyright (C) 1993-2021 Free Software Foundation, Inc. +/* Copyright (C) 1993-2022 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. @@ -217,7 +217,7 @@ extern int parse_string PARAMS((char *, const char *, int, COMMAND **, char **)) extern int should_suppress_fork PARAMS((COMMAND *)); extern int can_optimize_connection PARAMS((COMMAND *)); extern int can_optimize_cat_file PARAMS((COMMAND *)); -extern void optimize_fork PARAMS((COMMAND *)); +extern void optimize_connection_fork PARAMS((COMMAND *)); extern void optimize_subshell_command PARAMS((COMMAND *)); extern void optimize_shell_function PARAMS((COMMAND *)); diff --git a/builtins/evalstring.c b/builtins/evalstring.c index 3801a7a07..5088151a6 100644 --- a/builtins/evalstring.c +++ b/builtins/evalstring.c @@ -1,6 +1,6 @@ /* evalstring.c - evaluate a string as one or more shell commands. */ -/* Copyright (C) 1996-2021 Free Software Foundation, Inc. +/* Copyright (C) 1996-2022 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. @@ -84,6 +84,24 @@ restore_lastcom (x) the_printed_command_except_trap = x; } +int +should_optimize_fork (command, subshell) + COMMAND *command; + int subshell; +{ + return (running_trap == 0 && + command->type == cm_simple && + signal_is_trapped (EXIT_TRAP) == 0 && + signal_is_trapped (ERROR_TRAP) == 0 && + any_signals_trapped () < 0 && + (subshell || (command->redirects == 0 && command->value.Simple->redirects == 0)) && + ((command->flags & CMD_TIME_PIPELINE) == 0) && + ((command->flags & CMD_INVERT_RETURN) == 0)); +} + +/* This has extra tests to account for STARTUP_STATE == 2, which is for + -c command but has been extended to command and process substitution + (basically any time you call parse_and_execute in a subshell). */ int should_suppress_fork (command) COMMAND *command; @@ -94,14 +112,7 @@ should_suppress_fork (command) return (startup_state == 2 && parse_and_execute_level == 1 && *bash_input.location.string == '\0' && parser_expanding_alias () == 0 && - running_trap == 0 && - command->type == cm_simple && - signal_is_trapped (EXIT_TRAP) == 0 && - signal_is_trapped (ERROR_TRAP) == 0 && - any_signals_trapped () < 0 && - (subshell || (command->redirects == 0 && command->value.Simple->redirects == 0)) && - ((command->flags & CMD_TIME_PIPELINE) == 0) && - ((command->flags & CMD_INVERT_RETURN) == 0)); + should_optimize_fork (command, subshell)); } int @@ -115,13 +126,14 @@ can_optimize_connection (command) } void -optimize_fork (command) +optimize_connection_fork (command) COMMAND *command; { if (command->type == cm_connection && (command->value.Connection->connector == AND_AND || command->value.Connection->connector == OR_OR || command->value.Connection->connector == ';') && (command->value.Connection->second->flags & CMD_TRY_OPTIMIZING) && - should_suppress_fork (command->value.Connection->second)) + ((startup_state == 2 && should_suppress_fork (command->value.Connection->second)) || + ((subshell_environment & SUBSHELL_PAREN) && should_optimize_fork (command->value.Connection->second, 0)))) { command->value.Connection->second->flags |= CMD_NO_FORK; command->value.Connection->second->value.Simple->flags |= CMD_NO_FORK; @@ -132,21 +144,19 @@ void optimize_subshell_command (command) COMMAND *command; { - if (running_trap == 0 && - command->type == cm_simple && - signal_is_trapped (EXIT_TRAP) == 0 && - signal_is_trapped (ERROR_TRAP) == 0 && - any_signals_trapped () < 0 && - command->redirects == 0 && command->value.Simple->redirects == 0 && - ((command->flags & CMD_TIME_PIPELINE) == 0) && - ((command->flags & CMD_INVERT_RETURN) == 0)) + if (should_optimize_fork (command, 0)) { command->flags |= CMD_NO_FORK; command->value.Simple->flags |= CMD_NO_FORK; } else if (command->type == cm_connection && - (command->value.Connection->connector == AND_AND || command->value.Connection->connector == OR_OR)) - optimize_subshell_command (command->value.Connection->second); + (command->value.Connection->connector == AND_AND || command->value.Connection->connector == OR_OR || command->value.Connection->connector == ';') && + command->value.Connection->second->type == cm_simple && + parser_expanding_alias () == 0) + { + command->value.Connection->second->flags |= CMD_TRY_OPTIMIZING; + command->value.Connection->second->value.Simple->flags |= CMD_TRY_OPTIMIZING; + } } void diff --git a/execute_cmd.c b/execute_cmd.c index f86f396ad..48706435f 100644 --- a/execute_cmd.c +++ b/execute_cmd.c @@ -1,6 +1,6 @@ /* execute_cmd.c -- Execute a COMMAND structure. */ -/* Copyright (C) 1987-2021 Free Software Foundation, Inc. +/* Copyright (C) 1987-2022 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. @@ -1650,12 +1650,12 @@ execute_in_subshell (command, asynchronous, pipe_in, pipe_out, fds_to_close) default_buffered_input = -1; #endif -#if 0 - /* We can't optimize if one of the commands executed by the subshell sets - an exit trap. */ + /* We can't optimize away forks if one of the commands executed by the + subshell sets an exit trap, so we set CMD_NO_FORK for simple commands + and set CMD_TRY_OPTIMIZING for simple commands on the right side of an + and-or or `;' list to test for optimizing forks when they are executed. */ if (user_subshell && command->type == cm_subshell) optimize_subshell_command (command->value.Subshell->command); -#endif /* Do redirections, then dispose of them before recursive call. */ if (command->redirects) @@ -2753,7 +2753,7 @@ execute_connection (command, asynchronous, pipe_in, pipe_out, fds_to_close) #endif QUIT; - optimize_fork (command); /* XXX */ + optimize_connection_fork (command); /* XXX */ exec_result = execute_command_internal (command->value.Connection->second, asynchronous, pipe_in, pipe_out, fds_to_close); @@ -2826,7 +2826,7 @@ execute_connection (command, asynchronous, pipe_in, pipe_out, fds_to_close) ((command->value.Connection->connector == OR_OR) && (exec_result != EXECUTION_SUCCESS))) { - optimize_fork (command); + optimize_connection_fork (command); second = command->value.Connection->second; if (ignore_return && second) diff --git a/externs.h b/externs.h index e8289064b..325703bbb 100644 --- a/externs.h +++ b/externs.h @@ -471,6 +471,10 @@ extern char *ansic_quote PARAMS((char *, int, int *)); extern int ansic_shouldquote PARAMS((const char *)); extern char *ansiexpand PARAMS((char *, int, int, int *)); +/* declarations for functions defined in lib/sh/strvis.c */ +extern int charvis PARAMS((const char *, size_t *, char *, size_t *)); +extern char *sh_strvis PARAMS((const char *)); + /* declarations for functions defined in lib/sh/timeval.c. No prototypes so we don't have to count on having a definition of struct timeval in scope when this file is included. */ diff --git a/include/chartypes.h b/include/chartypes.h index 0fe5fc1a2..d5be4a3ce 100644 --- a/include/chartypes.h +++ b/include/chartypes.h @@ -103,7 +103,7 @@ #endif #ifndef UNCTRL /* control char to letter -- ASCII */ -# define UNCTRL(x) (TOUPPER(x) ^ 0x40) +# define UNCTRL(x) (TOUPPER(x ^ 0x40)) #endif #endif /* _SH_CHARTYPES_H */ diff --git a/lib/readline/doc/rltech.texi b/lib/readline/doc/rltech.texi index 8c4814ecf..a1eac5ebc 100644 --- a/lib/readline/doc/rltech.texi +++ b/lib/readline/doc/rltech.texi @@ -1184,10 +1184,13 @@ Returns 0 if the timeout is set successfully. @deftypefun int rl_timeout_remaining (unsigned int *secs, unsigned int *usecs) Return the number of seconds and microseconds remaining in the current -timeout duration in @code{*secs} and @code{*usecs}, respectively. -Returns -1 on error or when there is no timeout set, 0 when the timeout has -expired (leaving @code{*secs} and @code{*usecs} unchanged), and 1 if the -timeout has not expired. If @code{secs} and @code{usecs} are @code{NULL}, +timeout duration in @var{*secs} and @var{*usecs}, respectively. +Both @var{*secs} and @var{*usecs} must be non-NULL to return any values. +The return value is -1 on error or when there is no timeout set, +0 when the timeout has expired (leaving @var{*secs} and @var{*usecs} +unchanged), +and 1 if the timeout has not expired. +If either of @var{secs} and @var{usecs} is @code{NULL}, the return value indicates whether the timeout has expired. @end deftypefun diff --git a/lib/readline/history.h b/lib/readline/history.h index fc98eeeaa..ad2ce70a1 100644 --- a/lib/readline/history.h +++ b/lib/readline/history.h @@ -44,7 +44,7 @@ typedef char *histdata_t; /* Let's not step on anyone else's define for now, since we don't use this yet. */ #ifndef HS_HISTORY_VERSION -# define HS_HISTORY_VERSION 0x0801 /* History 8.1 */ +# define HS_HISTORY_VERSION 0x0802 /* History 8.2 */ #endif /* The structure used to store a history entry. */ diff --git a/lib/readline/readline.h b/lib/readline/readline.h index 5f17dfd7b..7cf1fcf58 100644 --- a/lib/readline/readline.h +++ b/lib/readline/readline.h @@ -39,9 +39,9 @@ extern "C" { #endif /* Hex-encoded Readline version number. */ -#define RL_READLINE_VERSION 0x0801 /* Readline 8.1 */ +#define RL_READLINE_VERSION 0x0802 /* Readline 8.2 */ #define RL_VERSION_MAJOR 8 -#define RL_VERSION_MINOR 1 +#define RL_VERSION_MINOR 2 /* Readline data structures. */ diff --git a/lib/sh/Makefile.in b/lib/sh/Makefile.in index cbaf94d23..8c42c73d0 100644 --- a/lib/sh/Makefile.in +++ b/lib/sh/Makefile.in @@ -2,7 +2,7 @@ # Makefile for the Bash library # # -# Copyright (C) 1998-2020 Free Software Foundation, Inc. +# Copyright (C) 1998-2022 Free Software Foundation, Inc. # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -94,7 +94,7 @@ CSOURCES = clktck.c clock.c getcwd.c getenv.c oslib.c setlinebuf.c \ wcsdup.c fpurge.c zgetline.c mbscmp.c uconvert.c ufuncs.c \ casemod.c dprintf.c input_avail.c mbscasecmp.c fnxform.c \ strchrnul.c unicode.c wcswidth.c wcsnwidth.c shmbchar.c strdup.c \ - utf8.c random.c gettimeofday.c timers.c + strvis.c utf8.c random.c gettimeofday.c timers.c # The header files for this library. HSOURCES = @@ -108,7 +108,7 @@ OBJECTS = clktck.o clock.o getenv.o oslib.o setlinebuf.o strnlen.o \ strtrans.o snprintf.o mailstat.o fmtulong.o \ fmtullong.o fmtumax.o zcatfd.o zmapfd.o winsize.o wcsdup.o \ fpurge.o zgetline.o mbscmp.o uconvert.o ufuncs.o casemod.o \ - input_avail.o mbscasecmp.o fnxform.o unicode.o shmbchar.o \ + input_avail.o mbscasecmp.o fnxform.o unicode.o shmbchar.o strvis.o \ utf8.o random.o gettimeofday.o timers.o wcsnwidth.o ${LIBOBJS} SUPPORT = Makefile @@ -198,6 +198,7 @@ strtoul.o: strtoul.c strtoull.o: strtoull.c strtoumax.o: strtoumax.c strtrans.o: strtrans.c +strvis.o: strvis.c timers.o: timers.c times.o: times.c timeval.o: timeval.c @@ -279,6 +280,7 @@ strtoul.o: ${BUILD_DIR}/config.h strtoull.o: ${BUILD_DIR}/config.h strtoumax.o: ${BUILD_DIR}/config.h strtrans.o: ${BUILD_DIR}/config.h +strvis.o: ${BUILD_DIR}/config.h timers.o: ${BUILD_DIR}/config.h times.o: ${BUILD_DIR}/config.h timeval.o: ${BUILD_DIR}/config.h @@ -512,6 +514,11 @@ strtrans.o: ${BUILD_DIR}/pathnames.h ${topdir}/externs.h strtrans.o: ${BASHINCDIR}/shmbutil.h ${BASHINCDIR}/shmbchar.h #strtrans.o: ${BUILD_DIR}/version.h +strvis.o: ${topdir}/bashansi.h +strvis.o: ${BASHINCDIR}/ansi_stdlib.h ${BASHINCDIR}/chartypes.h +strvis.o: ${BASHINCDIR}/shmbutil.h ${BASHINCDIR}/shmbchar.h +strvis.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h + times.o: ${BASHINCDIR}/systimes.h times.o: ${BASHINCDIR}/posixtime.h diff --git a/lib/sh/strdup.c b/lib/sh/strdup.c index 90fa3532c..3d35f7c0a 100644 --- a/lib/sh/strdup.c +++ b/lib/sh/strdup.c @@ -17,7 +17,6 @@ You should have received a copy of the GNU General Public License along with Bash. If not, see . */ - #include diff --git a/lib/sh/strvis.c b/lib/sh/strvis.c new file mode 100644 index 000000000..2ad8b70f9 --- /dev/null +++ b/lib/sh/strvis.c @@ -0,0 +1,145 @@ +/* strvis.c - make unsafe graphical characters in a string visible. */ + +/* Copyright (C) 2022 Free Software Foundation, Inc. + + This file is part of GNU Bash, the Bourne Again SHell. + + Bash is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Bash is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Bash. If not, see . +*/ + +/* This is a stripped-down version suitable for the shell's use. */ +#include + +#include + +#include "bashansi.h" +#include + +#include "chartypes.h" +#include "bashintl.h" +#include "shmbutil.h" + +#define SAFECHAR(c) ((c) == ' ' || (c) == '\t') + +#ifndef RUBOUT +#define RUBOUT 0x7f +#endif + +#ifndef CTRL_CHAR +#define CTRL_CHAR(c) ((c) < 0x20) +#endif + +#ifndef META_CHAR +#define META_CHAR(c) ((c) > 0x7f && (c) <= UCHAR_MAX) +#endif + +#ifndef UNCTRL +#define UNCTRL(c) (TOUPPER ((c) | 0x40)) +#endif + +#ifndef UNMETA +#define UNMETA(c) ((c) & 0x7f) +#endif + +static int +charvis (s, sindp, ret, rindp) + const char *s; + size_t *sindp; + char *ret; + size_t *rindp; +{ + unsigned char c; + size_t si, ri; + const char *send; + DECLARE_MBSTATE; + + si = *sindp; + ri = *rindp; + c = s[*sindp]; + + send = (locale_mb_cur_max > 1) ? s + strlen (s) : 0; + + if (SAFECHAR (c)) + { + ret[ri++] = c; + si++; + } + else if (c == RUBOUT) + { + ret[ri++] = '^'; + ret[ri++] = '?'; + si++; + } + else if (CTRL_CHAR (c)) + { + ret[ri++] = '^'; + ret[ri++] = UNCTRL (c); + si++; + } + else if (locale_mb_cur_max > 1) + COPY_CHAR_I (ret, ri, s, send, si); + else if (META_CHAR (c)) + { + ret[ri++] = 'M'; + ret[ri++] = '-'; + ret[ri++] = UNMETA (c); + si++; + } + else + ret[ri++] = s[si++]; + + *sindp = si; + *rindp = ri; + + return si; +} + +/* Return a new string with `unsafe' non-graphical characters in S rendered + in a visible way. */ +char * +sh_strvis (string) + const char *string; +{ + size_t slen, sind; + char *ret; + size_t retind, retsize; + unsigned char c; + DECLARE_MBSTATE; + + if (string == 0) + return 0; + if (*string == '\0') + { + if ((ret = (char *)malloc (1)) == 0) + return 0; + ret[0] = '\0'; + return ret; + } + + slen = strlen (string); + retsize = 3 * slen + 1; + + ret = (char *)malloc (retsize); + if (ret == 0) + return 0; + + retind = 0; + sind = 0; + + while (string[sind]) + sind = charvis (string, &sind, ret, &retind); + + ret[retind] = '\0'; + return ret; +} diff --git a/parse.y b/parse.y index 095203235..b97d2c88a 100644 --- a/parse.y +++ b/parse.y @@ -3805,7 +3805,7 @@ parse_matched_pair (qc, open, close, lenp, flags) pop_delimiter (dstack); CHECK_NESTRET_ERROR (); - if MBTEST((tflags & LEX_WASDOL) && ch == '\'' && (extended_quote || (rflags & P_DQUOTE) == 0)) + if MBTEST((tflags & LEX_WASDOL) && ch == '\'' && (extended_quote || (rflags & P_DQUOTE) == 0 || dolbrace_state == DOLBRACE_QUOTE || dolbrace_state == DOLBRACE_QUOTE2)) { /* Translate $'...' here. */ /* PST_NOEXPAND */ @@ -3817,12 +3817,22 @@ parse_matched_pair (qc, open, close, lenp, flags) make sure we single-quote the results of the ansi expansion because quote removal should remove them later */ /* FLAG POSIX INTERP 221 */ - if ((shell_compatibility_level > 42) && (rflags & P_DQUOTE) && (dolbrace_state == DOLBRACE_QUOTE2) && (flags & P_DOLBRACE)) + if ((shell_compatibility_level > 42) && (rflags & P_DQUOTE) && (dolbrace_state == DOLBRACE_QUOTE2 || dolbrace_state == DOLBRACE_QUOTE) && (flags & P_DOLBRACE)) { nestret = sh_single_quote (ttrans); free (ttrans); nestlen = strlen (nestret); } +#if 0 /* TAG:bash-5.3 */ + /* This single-quotes PARAM in ${PARAM OP WORD} when PARAM + contains a $'...' even when extended_quote is set. */ + else if ((rflags & P_DQUOTE) && (dolbrace_state == DOLBRACE_PARAM) && (flags & P_DOLBRACE)) + { + nestret = sh_single_quote (ttrans); + free (ttrans); + nestlen = strlen (nestret); + } +#endif else if ((rflags & P_DQUOTE) == 0) { nestret = sh_single_quote (ttrans); diff --git a/subst.c b/subst.c index 94b2c17f5..33f5a2245 100644 --- a/subst.c +++ b/subst.c @@ -195,6 +195,7 @@ int patsub_replacement = 1; extern struct fd_bitmap *current_fds_to_close; extern int wordexp_only; extern int singlequote_translations; +extern int extended_quote; #if defined (JOB_CONTROL) && defined (PROCESS_SUBSTITUTION) extern PROCESS *last_procsub_child; @@ -1523,7 +1524,9 @@ extract_delimited_string (string, sindex, opener, alt_opener, closer, flags) path doesn't. It's separate because we don't want to mess with the fast common path. We already know we're going to allocate and return a new string and quoted == Q_HERE_DOCUMENT. We might be able to cut it down - some more, but extracting strings and adding them as we go adds complexity. */ + some more, but extracting strings and adding them as we go adds complexity. + This needs to match the logic in parse.y:parse_matched_pair so we get + consistent behavior between here-documents and double-quoted strings. */ static char * extract_heredoc_dolbrace_string (string, sindex, quoted, flags) char *string; @@ -1574,6 +1577,15 @@ extract_heredoc_dolbrace_string (string, sindex, quoted, flags) char *ttrans; int ttranslen; + if ((posixly_correct || extended_quote == 0) && dolbrace_state != DOLBRACE_QUOTE && dolbrace_state != DOLBRACE_QUOTE2) + { + RESIZE_MALLOCED_BUFFER (result, result_index, 3, result_size, 64); + result[result_index++] = '$'; + result[result_index++] = '\''; + i += 2; + continue; + } + si = i + 2; t = string_extract_single_quoted (string, &si, 1); /* XXX */ CHECK_STRING_OVERRUN (i, si, slen, c); @@ -1583,9 +1595,18 @@ extract_heredoc_dolbrace_string (string, sindex, quoted, flags) free (t); /* needed to correctly quote any embedded single quotes. */ - t = sh_single_quote (ttrans); - tlen = strlen (t); - free (ttrans); + if (dolbrace_state == DOLBRACE_QUOTE || dolbrace_state == DOLBRACE_QUOTE2) + { + t = sh_single_quote (ttrans); + tlen = strlen (t); + free (ttrans); + } + else if (extended_quote) /* dolbrace_state == DOLBRACE_PARAM */ + { + /* This matches what parse.y:parse_matched_pair() does */ + t = ttrans; + tlen = strlen (t); + } RESIZE_MALLOCED_BUFFER (result, result_index, tlen + 1, result_size, 64); strncpy (result + result_index, t, tlen); @@ -1629,7 +1650,7 @@ extract_heredoc_dolbrace_string (string, sindex, quoted, flags) result[result_index++] = c; result[result_index++] = string[i+1]; i += 2; - if (dolbrace_state == DOLBRACE_QUOTE || dolbrace_state == DOLBRACE_WORD) + if (dolbrace_state == DOLBRACE_QUOTE || dolbrace_state == DOLBRACE_QUOTE2 || dolbrace_state == DOLBRACE_WORD) dolbrace_state = DOLBRACE_PARAM; continue; } diff --git a/tests/exec.right b/tests/exec.right index 8664e97f2..ef02fbb41 100644 --- a/tests/exec.right +++ b/tests/exec.right @@ -142,3 +142,31 @@ w x y z +===== +WORKS +done +WORKS +a +b +c +d +a +b +c +d +e +A +B +c +d +c +d +e +x +y +z +WORKS +w +x +y +z diff --git a/tests/exec14.sub b/tests/exec14.sub index 3402fb95f..eddd33fa0 100644 --- a/tests/exec14.sub +++ b/tests/exec14.sub @@ -45,3 +45,20 @@ $THIS_SH -c '$binecho c && $binecho d && echo e' $THIS_SH -c 'trap "echo WORKS" EXIT ; $binecho x ; $binecho y ; $binecho z' ${THIS_SH} -c 'echo w ; { echo x ; $binecho y; }; $binecho z' + +echo ===== + +( trap "echo WORKS && rm $TMPDIR/x$$" EXIT && touch $TMPDIR/x$$ ) +( trap "echo WORKS && rm $TMPDIR/x$$" EXIT && touch $TMPDIR/x$$ ; $binecho done ) + +( echo a && { $binecho b && $binecho c ; } && echo d ) +( echo a && { $binecho b && $binecho c ; } && echo d ; $binecho e ) + +( echo A && $binecho B ) +( $binecho c && echo d ) + +( $binecho c && $binecho d && echo e ) + +( trap "echo WORKS" EXIT ; $binecho x ; $binecho y ; $binecho z ) + +( echo w ; { echo x ; $binecho y; }; $binecho z ) diff --git a/tests/posixexp.right b/tests/posixexp.right index 0955995c1..7204b960a 100644 --- a/tests/posixexp.right +++ b/tests/posixexp.right @@ -275,10 +275,31 @@ argv[2] = [ abc def ghi jkl / abc def ghi jkl ] [ abc def ghi jkl ] [ abc def ghi jkl / abc def ghi jkl / abc def ghi jkl ] -5: OK +1: OK +2: $'not' +3: OK +4: OK +5: tOK OK OK -5: $'not\ttoo\nbad' +$'not' +OK +tOK +6: $'not\ttoo\nbad' +OKa ' b +OKa ' b +7: OK +8: OKa ' b +9: OKa " b +10: OKa " b +tOK +tOK +tOK +tOK +./posixexp7.sub: line 69: ${'x1'%'t'}: bad substitution +./posixexp7.sub: line 70: ${'x1'%'t'}: bad substitution +./posixexp7.sub: line 73: ${'x1'%'t'}: bad substitution +./posixexp7.sub: line 74: ${'x1'%'t'}: bad substitution "A" A argv[1] = <"A"> diff --git a/tests/posixexp7.sub b/tests/posixexp7.sub index 2e230cf85..4e3fa007c 100644 --- a/tests/posixexp7.sub +++ b/tests/posixexp7.sub @@ -1,13 +1,76 @@ +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# # test the effect of quotes on the WORD in the posix pattern removal operators -# a here document does not behave the same as double quotes +# x=notOK +x1=not + cat <