mirror of
https://https.git.savannah.gnu.org/git/bash.git
synced 2026-06-27 07:43:07 +02:00
more changes for here-docs and $'...'; command optimization updates
This commit is contained in:
+39
-1
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
+2
-2
@@ -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 *));
|
||||
|
||||
|
||||
+31
-21
@@ -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
|
||||
|
||||
+7
-7
@@ -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)
|
||||
|
||||
@@ -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. */
|
||||
|
||||
+1
-1
@@ -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 */
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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. */
|
||||
|
||||
@@ -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. */
|
||||
|
||||
|
||||
+10
-3
@@ -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
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Bash. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include <config.h>
|
||||
|
||||
|
||||
+145
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* This is a stripped-down version suitable for the shell's use. */
|
||||
#include <config.h>
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include "bashansi.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 )
|
||||
|
||||
+23
-2
@@ -275,10 +275,31 @@ argv[2] = <b>
|
||||
[ 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">
|
||||
|
||||
+66
-3
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# 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 <<EOF
|
||||
5: ${x#$'not'}
|
||||
1: ${x#$'not'}
|
||||
2: $'not'
|
||||
3: ${x#"not"}
|
||||
4: ${x#'not'}
|
||||
5: ${x#${x1%'t'}}
|
||||
EOF
|
||||
|
||||
echo "${x#'not'}"
|
||||
echo "${x#$'not'}"
|
||||
|
||||
echo "$'not'"
|
||||
echo "${x#"not"}"
|
||||
echo "${x#${x1%'t'}}"
|
||||
|
||||
cat <<EOF
|
||||
5: $'not\ttoo\nbad'
|
||||
6: $'not\ttoo\nbad'
|
||||
EOF
|
||||
|
||||
x=OK$'a\t\'\tb'
|
||||
echo OK$'a\t\'\tb'
|
||||
echo "$x"
|
||||
|
||||
cat <<EOF
|
||||
7: ${x%$'a\t\'\tb'}
|
||||
8: ${x#$'a\t\'\tb'}
|
||||
EOF
|
||||
|
||||
x=OK'a " b'
|
||||
|
||||
cat <<EOF
|
||||
9: ${x#'a " b'}
|
||||
10: ${x#$'a " b'}
|
||||
EOF
|
||||
|
||||
x=notOK
|
||||
x1=not
|
||||
|
||||
# extquote makes these work
|
||||
echo "${x#${$'x1'%$'t'}}"
|
||||
cat <<EOF
|
||||
${x#${$'x1'%$'t'}}
|
||||
EOF
|
||||
echo "${x#${$'x1'%'t'}}"
|
||||
cat <<EOF
|
||||
${x#${$'x1'%'t'}}
|
||||
EOF
|
||||
|
||||
# syntax errors
|
||||
|
||||
echo "${x#${'x1'%'t'}}"
|
||||
cat <<EOF
|
||||
${x#${'x1'%'t'}}
|
||||
EOF
|
||||
echo "${x#${'x1'%$'t'}}"
|
||||
cat <<EOF
|
||||
${x#${'x1'%$'t'}}
|
||||
EOF
|
||||
|
||||
Reference in New Issue
Block a user