mirror of
https://https.git.savannah.gnu.org/git/bash.git
synced 2026-06-28 16:09:51 +02:00
commit bash-20151230 snapshot
This commit is contained in:
+106
@@ -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>
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -94,4 +94,3 @@ struct builtin hello_struct = {
|
||||
"hello", /* usage synopsis; becomes short_doc */
|
||||
0 /* reserved for internal use */
|
||||
};
|
||||
|
||||
|
||||
@@ -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,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,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
@@ -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
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 *));
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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-$@}"
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -130,3 +130,5 @@ echo !shopt*
|
||||
|
||||
${THIS_SH} ./histexp1.sub
|
||||
${THIS_SH} ./histexp2.sub
|
||||
${THIS_SH} ./histexp3.sub
|
||||
${THIS_SH} ./histexp4.sub
|
||||
|
||||
@@ -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
|
||||
@@ -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
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user