diff --git a/CWRU/CWRU.chlog b/CWRU/CWRU.chlog index 5982d30c..446c3df4 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 75ad5982..a4cd9ead 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 818a51b7..ef26d708 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 38326b99..1cec62fc 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 3801a7a0..5088151a 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 f86f396a..48706435 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 e8289064..325703bb 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 0fe5fc1a..d5be4a3c 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 8c4814ec..a1eac5eb 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 fc98eeea..ad2ce70a 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 5f17dfd7..7cf1fcf5 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 cbaf94d2..8c42c73d 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 90fa3532..3d35f7c0 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 00000000..2ad8b70f --- /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 09520323..b97d2c88 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 94b2c17f..33f5a224 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 8664e97f..ef02fbb4 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 3402fb95..eddd33fa 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 0955995c..7204b960 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 2e230cf8..4e3fa007 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 <