commit bash-20151230 snapshot

This commit is contained in:
Chet Ramey
2016-01-04 09:18:44 -05:00
parent 25340ead08
commit 6f82653c5e
28 changed files with 1010 additions and 778 deletions
+106
View File
@@ -10176,3 +10176,109 @@ lib/readline/isearch.c
- _rl_isearch_dispatch: after removing the only character from the
search string with DEL, leaving the search string empty, don't match
the previous line if we didn't have a match before
12/22
-----
bashhist.c
- enable_history_list,remember_on_history: initialize to 0 instead of 1
shell.c
- init_interactive,init_interactive_script: set enable_history_list and
remember_on_history to 1 (defaults)
12/23
-----
variables.c
- initialize_shell_variables: don't inherit PS4 from the environment
if the shell is running with euid == 0; just reset it to `+'. This
is a known potential vulnerability, since PS4 expansion performs
command substitution in the root shell's context before displaying
it. Discussion started by up201407890@alunos.dcc.fc.up.pt
bashhist.c
- bash_history_reinit: initialize remember_on_history to the value of
enable_history_list (set -o history). Fixes bug reported by
Stephane Chazelas <stephane.chazelas@gmail.com> with command-line
option `-o history' not having any effect
12/28
-----
lib/readline/{history.h,histfile.c}
- history_file_version: new int variable, reserved for future use
- history_multiline_entries: new int variable, can be set by the
calling application to enable reading multi-line history entries
from the history file (currently undocumented)
lib/readline/history.c
- _hs_append_history_line: new function, append a line passed as an
argument to a specified history entry, used to create multi-line
history entries
lib/readline/histfile.c
- read_history_range: implement a heuristic that temporarily sets the
history comment character if the first line read from the history
file looks like it has is a timestamp (#[:digit:]) so we can read
timestamps from the history file properly. Originally reported
back in March 2015 by Christoph Anton Mitterer <calestyo@gmail.com>
- read_history_range: make sure history_multiline_entries is non-zero
if the history file looks like it has timestamps
- read_history_range: if we think we have a history file with timestamps
and we read more than one non-timestamp consecutive history lines,
assume they are part of a single multi-line history entry and paste
them together using _hs_append_history_line. Feature most recently
requested by james harvey <jamespharvey20@gmail.com>, also suggested
by Christoph Anton Mitterer <calestyo@gmail.com>
examples/loadables/setpgid.c
- setpgid: new loadable builtin, originally contributed by Jason
Vas Dias <jason.vas.dias@gmail.com>
12/29
-----
bashhist.c
- bash_history_inhibit_expansion: fix cases where a history expansion
should be skipped because it's in a command or process substitution
but there is another history expansion preceding the substitution
on the command line. Don't let the previous history expansion fool
the function into saying the command substitution history expansion
should be performed
builtins/evalstring.c
- parse_prologue: always unwind-protect history_expansion_inhibited,
since history expansion can be enabled in non-interactive shells,
and calling eval once in a non-interactive shell inhibits history
expansion forever even if `set -o histexpand' was run before the
eval
builtins/common.h
- SEVAL_NOHISTEXP: new flag for parse_and_execute/parse_string; means
to not perform history expansion (decouple from SEVAL_NOHIST, which
now means to not remember commands on history); changed all callers
that had SEVAL_NOHIST to have SEVAL_NOHIST|SEVAL_NOHISTEXP
builtins/evalstring.c
- parse_prologue: instead of calling bash_history_disable, set
remember_on_history to 0 if SEVAL_NOHIST and history_expansion_inhibited
to 1 if SEVAL_NOHISTEXP
12/30
-----
subst.c
- skip_to_histexp: new function, a stripped-down version of skip_to_delim.
Used to skip to the next unquoted instance of the history expansion
character, handles peculiar quoting and command/process substitution
requirements. Better fix for bug reported by
Zigmund.Ozean@zig-home.localdomain back in January, prompted by report
from Keith Thompson <keithsthompson@gmail.com>
bashhist.c
- bash_history_inhibit_expansion: use skip_to_histexp instead of
skip_to_delim
subst.c
- parameter_brace_expand_rhs: if the rhs of an expansion is "$@" and
IFS is null, we need to separate the (quoted) positional parameters
in the returned word with a space, and mark the word as needing to
be split on spaces (W_SPLITSPACE). Fix for issues reported back in
October 2014 as the result of an austin-group discussion, and just
re-reported by Martijn Dekker <martijn@inlv.org>
+4
View File
@@ -664,6 +664,7 @@ examples/loadables/necho.c f
examples/loadables/hello.c f
examples/loadables/print.c f
examples/loadables/realpath.c f
examples/loadables/setpgid.c f
examples/loadables/sleep.c f
examples/loadables/strftime.c f
examples/loadables/truefalse.c f
@@ -921,6 +922,7 @@ tests/dollar-at-star3.sub f
tests/dollar-at-star4.sub f
tests/dollar-at-star5.sub f
tests/dollar-at-star6.sub f
tests/dollar-at-star7.sub f
tests/dollar-at1.sub f
tests/dollar-at2.sub f
tests/dollar-at3.sub f
@@ -1020,6 +1022,8 @@ tests/herestr1.sub f
tests/histexp.tests f
tests/histexp1.sub f
tests/histexp2.sub f
tests/histexp3.sub f
tests/histexp4.sub f
tests/histexp.right f
tests/history.tests f
tests/history.right f
+19 -7
View File
@@ -83,8 +83,8 @@ static struct ignorevar histignore =
/* Non-zero means to remember lines typed to the shell on the history
list. This is different than the user-controlled behaviour; this
becomes zero when we read lines from a file, for example. */
int remember_on_history = 1;
int enable_history_list = 1; /* value for `set -o history' */
int remember_on_history = 0;
int enable_history_list = 0; /* value for `set -o history' */
/* The number of lines that Bash has added to this history session. The
difference between the number of the top element in the history list
@@ -99,6 +99,8 @@ int history_lines_in_file;
/* Non-zero means do no history expansion on this line, regardless
of what history_expansion says. */
int history_expansion_inhibited;
/* If non-zero, double quotes can quote the history expansion character. */
int double_quotes_inhibit_history_expansion = 0;
#endif
/* With the old default, every line was saved in the history individually.
@@ -229,8 +231,18 @@ bash_history_inhibit_expansion (string, i)
/* Make sure the history expansion should not be skipped by quoting or
command/process substitution. */
else if ((t = skip_to_delim (string, 0, hx, SD_NOJMP|SD_HISTEXP)) > 0 && t > i)
return (1);
else if ((t = skip_to_histexp (string, 0, hx, SD_NOJMP|SD_HISTEXP)) > 0)
{
/* Skip instances of history expansion appearing on the line before
this one. */
while (t < i)
{
t = skip_to_histexp (string, t+1, hx, SD_NOJMP|SD_HISTEXP);
if (t <= 0)
return 0;
}
return (t > i);
}
else
return (0);
}
@@ -252,9 +264,9 @@ bash_history_reinit (interact)
{
#if defined (BANG_HISTORY)
history_expansion = interact != 0;
history_expansion_inhibited = 1;
history_expansion_inhibited = 1; /* XXX */
#endif
remember_on_history = enable_history_list = interact != 0;
remember_on_history = enable_history_list;
history_inhibit_expansion_function = bash_history_inhibit_expansion;
}
@@ -270,7 +282,7 @@ bash_history_disable ()
void
bash_history_enable ()
{
remember_on_history = 1;
remember_on_history = enable_history_list = 1;
#if defined (BANG_HISTORY)
history_expansion_inhibited = 0;
#endif
+1
View File
@@ -50,6 +50,7 @@ do { \
#define SEVAL_NOLONGJMP 0x040
#define SEVAL_FUNCDEF 0x080 /* only allow function definitions */
#define SEVAL_ONECMD 0x100 /* only allow a single command */
#define SEVAL_NOHISTEXP 0x200 /* inhibit history expansion */
/* Flags for describe_command, shared between type.def and command.def */
#define CDESC_ALL 0x001 /* type -a */
+6 -2
View File
@@ -168,8 +168,7 @@ parse_prologue (string, flags, tag)
else
unwind_protect_int (remember_on_history); /* can be used in scripts */
# if defined (BANG_HISTORY)
if (interactive_shell)
unwind_protect_int (history_expansion_inhibited);
unwind_protect_int (history_expansion_inhibited);
# endif /* BANG_HISTORY */
#endif /* HISTORY */
@@ -199,6 +198,10 @@ parse_prologue (string, flags, tag)
#if defined (HISTORY)
if (flags & SEVAL_NOHIST)
bash_history_disable ();
# if defined (BANG_HISTORY)
if (flags & SEVAL_NOHISTEXP)
history_expansion_inhibited = 1;
# endif /* BANG_HISTORY */
#endif /* HISTORY */
}
@@ -211,6 +214,7 @@ parse_prologue (string, flags, tag)
(flags & SEVAL_NOHIST) -> call bash_history_disable ()
(flags & SEVAL_NOFREE) -> don't free STRING when finished
(flags & SEVAL_RESETLINE) -> reset line_number to 1
(flags & SEVAL_NOHISTEXP) -> history_expansion_inhibited -> 1
*/
int
+6 -2
View File
@@ -102,7 +102,7 @@ INC = -I. -I.. -I$(topdir) -I$(topdir)/lib -I$(topdir)/builtins -I${srcdir} \
ALLPROG = print truefalse sleep finfo logname basename dirname \
tty pathchk tee head mkdir rmdir printenv id whoami \
uname sync push ln unlink realpath strftime mypid
uname sync push ln unlink realpath strftime mypid setpgid
OTHERPROG = necho hello cat pushd
all: $(SHOBJ_STATUS)
@@ -202,6 +202,10 @@ strftime: strftime.o
mypid: mypid.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ mypid.o $(SHOBJ_LIBS)
setpgid: setpgid.o
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ setpgid.o $(SHOBJ_LIBS)
# pushd is a special case. We use the same source that the builtin version
# uses, with special compilation options.
#
@@ -278,4 +282,4 @@ push.o: push.c
mkdir.o: mkdir.c
realpath.o: realpath.c
strftime.o: strftime.c
mypid.o: mypid.c
setpgid.o: setpgid.c
-1
View File
@@ -94,4 +94,3 @@ struct builtin hello_struct = {
"hello", /* usage synopsis; becomes short_doc */
0 /* reserved for internal use */
};
+121
View File
@@ -0,0 +1,121 @@
/* setpgid.c: bash loadable wrapper for setpgid system call
An example of how to wrap a system call with a loadable builtin.
Originally contributed by Jason Vas Dias <jason.vas.dias@gmail.com>
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/>.
*/
#include <config.h>
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#include <errno.h>
#include <string.h>
#include "bashtypes.h"
#include "posixtime.h"
#include <stdio.h>
#include "builtins.h"
#include "shell.h"
#include "common.h"
#include "bashgetopt.h"
#if !defined (_POSIX_VERSION)
# define setpgid(pid, pgrp) setpgrp (pid, pgrp)
#endif
int
setpgid_builtin (list)
WORD_LIST *list;
{
register WORD_LIST *wl;
intmax_t pid_arg, pgid_arg;
pid_t pid, pgid;
char *pidstr, *pgidstr;
wl = list;
pid = pgid = 0;
if (wl == 0 || wl->next == 0)
{
builtin_usage ();
return (EX_USAGE);
}
pidstr = wl->word ? wl->word->word : 0;
pgidstr = wl->next->word ? wl->next->word->word : 0;
if (pidstr == 0 || pgidstr == 0)
{
builtin_usage ();
return (EX_USAGE);
}
if (legal_number (pidstr, &pid_arg) == 0)
{
builtin_error ("%s: pid argument must be numeric", pidstr);
return (EXECUTION_FAILURE);
}
if (pid_arg < 0)
{
builtin_error("%s: negative pid values not allowed", pidstr);
return (EXECUTION_FAILURE);
}
pid = pid_arg;
if (legal_number (pgidstr, &pgid_arg) == 0)
{
builtin_error ("%s: pgrp argument must be numeric", pgidstr);
return (EXECUTION_FAILURE);
}
if (pgid_arg < 0)
{
builtin_error ("%s: negative pgrp values not allowed", pgidstr);
return (EXECUTION_FAILURE);
}
pgid = pgid_arg;
errno = 0;
if (setpgid(pid, pgid) < 0)
{
builtin_error("setpgid failed: %s", strerror (errno));
return (EXECUTION_FAILURE);
}
return (EXECUTION_SUCCESS);
}
const char *setpgid_doc[] = {
"invoke the setpgid(2) system call",
"",
"Arguments:",
" pid : numeric process identifer, >= 0",
" pgrpid: numeric process group identifier, >=0",
"See the setpgid(2) manual page.",
(const char *)NULL
};
struct builtin setpgid_struct = {
"setpgid",
setpgid_builtin,
BUILTIN_ENABLED,
(char **)setpgid_doc,
"setpgid pid pgrpid",
0
};
+1 -1
View File
@@ -1,6 +1,6 @@
/* display.c -- readline redisplay facility. */
/* Copyright (C) 1987-2013 Free Software Foundation, Inc.
/* Copyright (C) 1987-2015 Free Software Foundation, Inc.
This file is part of the GNU Readline Library (Readline), a library
for reading lines of text with interactive input and history editing.
+1 -1
View File
@@ -1,6 +1,6 @@
/* histexpand.c -- history expansion. */
/* Copyright (C) 1989-2012 Free Software Foundation, Inc.
/* Copyright (C) 1989-2015 Free Software Foundation, Inc.
This file contains the GNU History Library (History), a set of
routines for managing the text of previously typed lines.
+30 -2
View File
@@ -107,9 +107,19 @@ extern int errno;
# define PATH_MAX 1024 /* default */
#endif
extern void _hs_append_history_line PARAMS((int, const char *));
/* history file version; currently unused */
int history_file_version = 1;
/* If non-zero, we write timestamps to the history file in history_do_write() */
int history_write_timestamps = 0;
/* If non-zero, we assume that a history file that starts with a timestamp
uses timestamp-delimited entries and can include multi-line history
entries. Used by read_history_range */
int history_multiline_entries = 0;
/* Immediately after a call to read_history() or read_history_range(), this
will return the number of lines just read from the history file in that
call. */
@@ -259,7 +269,7 @@ read_history_range (filename, from, to)
{
register char *line_start, *line_end, *p;
char *input, *buffer, *bufend, *last_ts;
int file, current_line, chars_read;
int file, current_line, chars_read, has_timestamps, reset_comment_char;
struct stat finfo;
size_t file_size;
#if defined (EFBIG)
@@ -336,6 +346,19 @@ read_history_range (filename, from, to)
bufend = buffer + chars_read;
current_line = 0;
/* Heuristic: the history comment character rarely changes, so assume we
have timestamps if the buffer starts with `#[:digit:]' and temporarily
set history_comment_char so timestamp parsing works right */
reset_comment_char = 0;
if (history_comment_char == '\0' && buffer[0] == '#' && isdigit ((unsigned char)buffer[1]))
{
history_comment_char = '#';
reset_comment_char = 1;
}
has_timestamps = HIST_TIMESTAMP_START (buffer);
history_multiline_entries += has_timestamps && history_write_timestamps;
/* Skip lines until we are at FROM. */
for (line_start = line_end = buffer; line_end < bufend && current_line < from; line_end++)
if (*line_end == '\n')
@@ -362,7 +385,10 @@ read_history_range (filename, from, to)
{
if (HIST_TIMESTAMP_START(line_start) == 0)
{
add_history (line_start);
if (last_ts == NULL && history_multiline_entries)
_hs_append_history_line (history_length - 1, line_start);
else
add_history (line_start);
if (last_ts)
{
add_history_time (last_ts);
@@ -385,6 +411,8 @@ read_history_range (filename, from, to)
}
history_lines_read_from_file = current_line;
if (reset_comment_char)
history_comment_char = '\0';
FREE (input);
#ifndef HISTORY_USE_MMAP
+25 -1
View File
@@ -1,6 +1,6 @@
/* history.c -- standalone history library */
/* Copyright (C) 1989-2011 Free Software Foundation, Inc.
/* Copyright (C) 1989-2015 Free Software Foundation, Inc.
This file contains the GNU History Library (History), a set of
routines for managing the text of previously typed lines.
@@ -407,6 +407,30 @@ replace_history_entry (which, line, data)
return (old_value);
}
/* Append LINE to the history line at offset WHICH, adding a newline to the
end of the current line first. This can be used to construct multi-line
history entries while reading lines from the history file. */
void
_hs_append_history_line (which, line)
int which;
const char *line;
{
HIST_ENTRY *hent;
size_t newlen, curlen;
char *newline;
hent = the_history[which];
curlen = strlen (hent->line);
newlen = curlen + strlen (line) + 2;
newline = realloc (hent->line, newlen);
if (newline)
{
hent->line = newline;
hent->line[curlen++] = '\n';
strcpy (hent->line + curlen, line);
}
}
/* Replace the DATA in the specified history entries, replacing OLD with
NEW. WHICH says which one(s) to replace: WHICH == -1 means to replace
all of the history entries where entry->data == OLD; WHICH == -2 means
+5 -1
View File
@@ -1,6 +1,6 @@
/* history.h -- the names of functions that you can call in history. */
/* Copyright (C) 1989-2009 Free Software Foundation, Inc.
/* Copyright (C) 1989-2015 Free Software Foundation, Inc.
This file contains the GNU History Library (History), a set of
routines for managing the text of previously typed lines.
@@ -263,6 +263,10 @@ extern int history_quotes_inhibit_expansion;
extern int history_write_timestamps;
/* These two are undocumented; the second is reserved for future use */
extern int history_multiline_entries;
extern int history_file_version;
/* Backwards compatibility */
extern int max_input_history;
+1 -1
View File
@@ -6,7 +6,7 @@
/* */
/* **************************************************************** */
/* Copyright (C) 1987-2012 Free Software Foundation, Inc.
/* Copyright (C) 1987-2015 Free Software Foundation, Inc.
This file is part of the GNU Readline Library (Readline), a library
for reading lines of text with interactive input and history editing.
+1 -1
View File
@@ -1,6 +1,6 @@
/* util.c -- readline utility functions */
/* Copyright (C) 1987-2012 Free Software Foundation, Inc.
/* Copyright (C) 1987-2015 Free Software Foundation, Inc.
This file is part of the GNU Readline Library (Readline), a library
for reading lines of text with interactive input and history editing.
+2
View File
@@ -2369,6 +2369,8 @@ shell_getc (remove_quoted_newline)
if (current_delimiter (dstack) == '\'')
history_expansion_inhibited = 1;
# endif
/* Calling with a third argument of 1 allows remember_on_history to
determine whether or not the line is saved to the history list */
expansions = pre_process_line (shell_input_line, 1, 1);
# if defined (BANG_HISTORY)
history_expansion_inhibited = old_hist;
+369 -733
View File
File diff suppressed because it is too large Load Diff
+7 -1
View File
@@ -1695,6 +1695,9 @@ init_interactive ()
{
expand_aliases = interactive_shell = startup_state = 1;
interactive = 1;
#if defined (HISTORY)
remember_on_history = enable_history_list = 1; /* XXX */
#endif
}
static void
@@ -1718,6 +1721,9 @@ init_interactive_script ()
{
init_noninteractive ();
expand_aliases = interactive_shell = startup_state = 1;
#if defined (HISTORY)
remember_on_history = enable_history_list = 1; /* XXX */
#endif
}
void
@@ -1860,7 +1866,7 @@ shell_reinitialize ()
/* XXX - should we set jobs_m_flag to 0 here? */
#if defined (HISTORY)
bash_history_reinit (0);
bash_history_reinit (enable_history_list = 0);
#endif /* HISTORY */
#if defined (RESTRICTED_SHELL)
+142 -22
View File
@@ -1763,7 +1763,7 @@ skip_to_delim (string, start, delims, flags)
int flags;
{
int i, pass_next, backq, dquote, si, c, oldjmp;
int invert, skipquote, skipcmd, noprocsub, completeflag, histexp;
int invert, skipquote, skipcmd, noprocsub, completeflag;
int arithexp, skipcol;
size_t slen;
char *temp, open[3];
@@ -1776,7 +1776,6 @@ skip_to_delim (string, start, delims, flags)
invert = (flags & SD_INVERT);
skipcmd = (flags & SD_NOSKIPCMD) == 0;
noprocsub = (flags & SD_NOPROCSUB);
histexp = (flags & SD_HISTEXP);
completeflag = (flags & SD_COMPLETE) ? SX_COMPLETE : 0;
arithexp = (flags & SD_ARITHEXP);
@@ -1835,11 +1834,6 @@ skip_to_delim (string, start, delims, flags)
/* the usual case is to use skip_xxx_quoted, but we don't skip over double
quoted strings when looking for the history expansion character as a
delimiter. */
else if (histexp && dquote && c == '\'')
{
i++;
continue;
}
/* special case for programmable completion which takes place before
parser converts backslash-escaped single quotes between $'...' to
`regular' single-quoted strings. */
@@ -1847,14 +1841,6 @@ skip_to_delim (string, start, delims, flags)
i = skip_single_quoted (string, slen, ++i, SX_COMPLETE);
else if (c == '\'')
i = skip_single_quoted (string, slen, ++i, 0);
/* The posixly_correct test makes posix-mode shells allow double quotes
to quote the history expansion character */
else if (histexp && posixly_correct == 0 && c == '"')
{
dquote = 1 - dquote;
i++;
continue;
}
else if (c == '"')
i = skip_double_quoted (string, slen, ++i, completeflag);
else if (c == LPAREN && arithexp)
@@ -1947,6 +1933,128 @@ skip_to_delim (string, start, delims, flags)
CQ_RETURN(i);
}
#if defined (BANG_HISTORY)
/* Skip to the history expansion character (delims[0]), paying attention to
quoted strings and command and process substitution. This is a stripped-
down version of skip_to_delims. The essential difference is that this
resets the quoting state when starting a command substitution */
int
skip_to_histexp (string, start, delims, flags)
char *string;
int start;
char *delims;
int flags;
{
int i, pass_next, backq, dquote, si, c, oldjmp;
int histexp_comsub, histexp_backq, old_dquote;
size_t slen;
char *temp, open[3];
DECLARE_MBSTATE;
slen = strlen (string + start) + start;
oldjmp = no_longjmp_on_fatal_error;
if (flags & SD_NOJMP)
no_longjmp_on_fatal_error = 1;
histexp_comsub = histexp_backq = old_dquote = 0;
i = start;
pass_next = backq = dquote = 0;
while (c = string[i])
{
if (pass_next)
{
pass_next = 0;
if (c == 0)
CQ_RETURN(i);
ADVANCE_CHAR (string, slen, i);
continue;
}
else if (c == '\\')
{
pass_next = 1;
i++;
continue;
}
else if (backq && c == '`')
{
backq = 0;
histexp_backq--;
dquote = old_dquote;
i++;
continue;
}
else if (c == '`')
{
backq = 1;
histexp_backq++;
old_dquote = dquote; /* simple - one level for now */
dquote = 0;
i++;
continue;
}
/* When in double quotes, act as if the double quote is a member of
history_no_expand_chars, like the history library does */
else if (dquote && c == delims[0] && string[i+1] == '"')
{
i++;
continue;
}
else if (c == delims[0])
break;
/* the usual case is to use skip_xxx_quoted, but we don't skip over double
quoted strings when looking for the history expansion character as a
delimiter. */
else if (dquote && c == '\'')
{
i++;
continue;
}
else if (c == '\'')
i = skip_single_quoted (string, slen, ++i, 0);
/* The posixly_correct test makes posix-mode shells allow double quotes
to quote the history expansion character */
else if (posixly_correct == 0 && c == '"')
{
dquote = 1 - dquote;
i++;
continue;
}
else if (c == '"')
i = skip_double_quoted (string, slen, ++i, 0);
#if defined (PROCESS_SUBSTITUTION)
else if ((c == '$' || c == '<' || c == '>') && string[i+1] == LPAREN && string[i+2] != LPAREN)
#else
else if (c == '$' && string[i+1] == LPAREN && string[i+2] != LPAREN)
#endif
{
if (string[i+2] == '\0')
CQ_RETURN(i+2);
i += 2;
histexp_comsub++;
old_dquote = dquote;
dquote = 0;
}
else if (histexp_comsub && c == RPAREN)
{
histexp_comsub--;
dquote = old_dquote;
i++;
continue;
}
else if (backq) /* placeholder */
{
ADVANCE_CHAR (string, slen, i);
continue;
}
else
ADVANCE_CHAR (string, slen, i);
}
CQ_RETURN(i);
}
#endif /* BANG_HISTORY */
#if defined (READLINE)
/* Return 1 if the portion of STRING ending at EINDEX is quoted (there is
an unclosed quoted string), or if the character at EINDEX is quoted
@@ -6488,18 +6596,28 @@ parameter_brace_expand_rhs (name, value, c, quoted, qdollaratp, hasdollarat)
free (temp);
if (l)
{
/* If l->next is not null, we know that TEMP contained "$@", since that
is the only expansion that creates more than one word. */
if (qdollaratp && ((hasdol && quoted) || l->next))
*qdollaratp = 1;
/* The expansion of TEMP returned something. We need to treat things
slightly differently if HASDOL is non-zero. If we have "$@", the
individual words have already been quoted. We need to turn them
into a string with the words separated by the first character of
$IFS without any additional quoting, so string_list_dollar_at won't
do the right thing. We use string_list_dollar_star instead. */
temp = (hasdol || l->next) ? string_list_dollar_star (l) : string_list (l);
do the right thing. If IFS is null, we want "$@" to split into
separate arguments, not be concatenated, so we use string_list_internal
and mark the word to be split on spaces later. We use
string_list_dollar_star for "$@" otherwise. */
if (l->next && ifs_is_null)
{
temp = string_list_internal (l, " ");
w->flags |= W_SPLITSPACE;
}
else
temp = (hasdol || l->next) ? string_list_dollar_star (l) : string_list (l);
/* If l->next is not null, we know that TEMP contained "$@", since that
is the only expansion that creates more than one word. */
if (qdollaratp && ((hasdol && quoted) || l->next))
*qdollaratp = 1;
/* If we have a quoted null result (QUOTED_NULL(temp)) and the word is
a quoted null (l->next == 0 && QUOTED_NULL(l->word->word)), the
flags indicate it (l->word->flags & W_HASQUOTEDNULL), and the
@@ -9477,7 +9595,9 @@ finished_with_string:
with the first character of $IFS, so we split on $IFS. If
SPLIT_ON_SPACES is set, we expanded $* (unquoted) with IFS either
unset or null, and we want to make sure that we split on spaces
regardless of what else has happened to IFS since the expansion. */
regardless of what else has happened to IFS since the expansion,
or we expanded "$@" with IFS null and we need to split the positional
parameters into separate words. */
if (split_on_spaces)
list = list_string (istring, " ", 1); /* XXX quoted == 1? */
/* If we have $@ (has_dollar_at != 0) and we are in a context where we
+5 -1
View File
@@ -1,6 +1,6 @@
/* subst.h -- Names of externally visible functions in subst.c. */
/* Copyright (C) 1993-2010 Free Software Foundation, Inc.
/* Copyright (C) 1993-2015 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -297,6 +297,10 @@ extern char *cond_expand_word __P((WORD_DESC *, int));
extern int skip_to_delim __P((char *, int, char *, int));
#if defined (BANG_HISTORY)
extern int skip_to_histexp __P((char *, int, char *, int));
#endif
#if defined (READLINE)
extern int char_is_quoted __P((char *, int));
extern int unclosed_pair __P((char *, int, char *));
+1
View File
@@ -218,6 +218,7 @@ ${THIS_SH} ./dollar-at-star3.sub
${THIS_SH} ./dollar-at-star4.sub
${THIS_SH} ./dollar-at-star5.sub
${THIS_SH} ./dollar-at-star6.sub
${THIS_SH} ./dollar-at-star7.sub
# tests for special expansion of "$*" and "${array[*]}" when used with other
# expansions -- bugs through bash-2.05b
+25
View File
@@ -0,0 +1,25 @@
IFS='' # testing with only empty IFS
set -- this is a test
printf '|%s|\n' ${1+"$@"}
echo
printf '|%s|\n' "${1+$@}"
echo
printf '|%s|\n' "$@"
echo
printf '|%s|\n' ${1-"$@"}
printf '|%s|\n' "${1-$@}"
echo
: ${foo:="$@"}
printf '|%s|\n' "$foo"
unset foo
: "${foo:=$@}"
printf '|%s|\n' "$foo"
unset foo
printf '|%s|\n' ${foo-"$@"}
printf '|%s|\n' "${foo-$@}"
+28
View File
@@ -266,6 +266,34 @@ argv[3] = <'c'>
argv[1] = <'a'>
argv[2] = <'b'>
argv[3] = <'c'>
|this|
|is|
|a|
|test|
|this|
|is|
|a|
|test|
|this|
|is|
|a|
|test|
|this|
|this|
|this is a test|
|this is a test|
|this|
|is|
|a|
|test|
|this|
|is|
|a|
|test|
xa|xb|xc
xa|xb|xc
a|b|c
+39
View File
@@ -150,3 +150,42 @@ echo "#!/bin/bash" set -o posix
#!/bin/bash set -o posix
!!
!!
a
echo $(echo echo a)
echo a
a
echo echo a $(echo echo a)
echo a echo a
b
!! $(echo !!)
c
echo "echo c" "$(echo echo c)"
echo c echo c
d
echo "echo d" $(echo "echo d")
echo d echo d
e
!! !!
f
!!
f
!!
g
echo "echo g"
echo g
g
eval echo "echo g"
echo g
a
cat < <(echo echo a)
echo a
b
echo echo b `echo echo b`
echo b echo b
c
!
d
!
e
! !
./histexp4.sub: line 20: !': event not found
+2
View File
@@ -130,3 +130,5 @@ echo !shopt*
${THIS_SH} ./histexp1.sub
${THIS_SH} ./histexp2.sub
${THIS_SH} ./histexp3.sub
${THIS_SH} ./histexp4.sub
+35
View File
@@ -0,0 +1,35 @@
HISTFILE=${TMPDIR}/bashhist-$$
set -o history
set -o histexpand
echo a
echo $(echo !!)
echo a
echo !! $(echo !!)
echo b
echo '!!' '$(echo !!)'
echo c
echo "!!" "$(echo !!)"
echo d
echo "!!" $(echo "!!")
echo e
echo '!!' $(echo '!!')
echo f
echo '!!'
echo f
eval echo '!!'
echo g
echo "!!"
echo g
eval echo "!!"
set +o history
rm -f $HISTFILE # just in case
+23
View File
@@ -0,0 +1,23 @@
HISTFILE=$TMPDIR/bashhist-$$
set -o history
set -o histexpand
echo a
cat < <(echo !!)
echo b
echo !! `echo !!`
echo c
echo "$(echo "!" )"
echo d
echo "$(echo '!' )"
echo e
echo '!' "!"
echo "'!'"
set +o history
rm -f $HISTFILE
+5 -1
View File
@@ -503,7 +503,11 @@ initialize_shell_variables (env, privmode)
#endif
set_if_not ("PS2", secondary_prompt);
}
set_if_not ("PS4", "+ ");
if (current_user.euid == 0)
bind_variable ("PS4", "+", 0);
else
set_if_not ("PS4", "+ ");
/* Don't allow IFS to be imported from the environment. */
temp_var = bind_variable ("IFS", " \t\n", 0);