commit bash-20161216 snapshot

This commit is contained in:
Chet Ramey
2016-12-20 14:15:35 -05:00
parent a57ed9e90a
commit 06db13a410
23 changed files with 284 additions and 47 deletions
+70
View File
@@ -12749,3 +12749,73 @@ arrayfunc.c
expand_assignment_string_to_string; just use the unexpanded subscript
to produce the key [THIS IS A WORK IN PROGRESS]
12/14
-----
subst.h
- ASS_NOEXPAND: assignment flag that inhibits expansion of associative
array subscripts
variables.c
- bind_int_variable: takes new flags arg; flags are taken from the
ASS_ set of assignment flags, changed callers (bashline.c, expr.c,
pcomplete.c)
- bind_int_variable: if flags includes ASS_NOEXPAND, pass 1 as flag to
valid_array_reference and array_variable_part to pass along to
skipsubscript, so we don't try to skip over quoted strings in the
subscript
- bind_int_variable: pass flags along to assign_array_element
variables.h
- bind_int_variable: updated extern declaration with new flags arg
expr.c
- expr_bind_variable: if the assoc_expand_once option is enabled, and
the flags to evalexp indicate that we have already run the expression
through word expansion, pass ASS_NOEXPAND as flag to bind_int_variable
arrayfunc.c
- assign_array_element: if flags includes ASS_NOEXPAND, pass 1 as flag
to array_variable_name to pass along to skipsubscript
- assign_array_element: if flags includes ASS_NOEXPAND, don't run an
associative array subscript through word expansion, just use as-is
subst.c
- param_expand: call evalexp with EXP_EXPANDED flag for arithmetic
substitution because the string has already been expanded with
expand_arith_string
12/15
-----
builtins/read.def
- read_builtin: use value of assoc_expand_once for valid_array_reference
as with other uses
- bind_read_variable: if assoc_expand_once is set, pass ASS_NOEXPAND
to assign_array_element
general.c
- assignment: instead of checking whether flags == 0 to allow a `[',
explicitly check for (flags&1) to disallow it. This leaves the door
open for additional flag values
builtins/printf.def
- printf_builtin: use value of assoc_expand_once for
valid_array_reference as with other uses
- bind_printf_variable: if assoc_expand_once is set, pass ASS_NOEXPAND
to assign_array_element
12/16
-----
builtins/history.def
- change history -d option to handle negative arguments; negative
arguments offset from the end of the history list (last_position + 1
so history -d -1 deletes the history -d command that just got
added). Original patch from Piotr Grzybowski <narsil.pl@gmail.com>
doc/bash.1,lib/readline/doc/hsuser.texi
- documented new behavior of negative offsets for `history -d'
12/17
-----
lib/readline/history.c
- remove_history: use memmove to move the history list around instead
of a loop that copies pointers one at a time, similar to add_history
+1
View File
@@ -864,6 +864,7 @@ tests/assoc5.sub f
tests/assoc6.sub f
tests/assoc7.sub f
tests/assoc8.sub f
tests/assoc9.sub f
tests/attr.tests f
tests/attr.right f
tests/attr1.sub f
+7 -3
View File
@@ -276,7 +276,8 @@ bind_assoc_variable (entry, name, key, value, flags)
}
/* Parse NAME, a lhs of an assignment statement of the form v[s], and
assign VALUE to that array element by calling bind_array_variable(). */
assign VALUE to that array element by calling bind_array_variable().
Flags are ASS_ assignment flags */
SHELL_VAR *
assign_array_element (name, value, flags)
char *name, *value;
@@ -286,7 +287,7 @@ assign_array_element (name, value, flags)
int sublen;
SHELL_VAR *entry, *nv;
vname = array_variable_name (name, 0, &sub, &sublen);
vname = array_variable_name (name, (flags & ASS_NOEXPAND) != 0, &sub, &sublen);
if (vname == 0)
return ((SHELL_VAR *)NULL);
@@ -321,7 +322,10 @@ assign_array_element_internal (entry, name, vname, sub, sublen, value, flags)
if (entry && assoc_p (entry))
{
sub[sublen-1] = '\0';
akey = expand_assignment_string_to_string (sub, 0); /* [ */
if ((flags & ASS_NOEXPAND) == 0)
akey = expand_assignment_string_to_string (sub, 0); /* [ */
else
akey = savestring (sub);
sub[sublen-1] = ']';
if (akey == 0 || *akey == 0)
{
+1 -1
View File
@@ -4137,7 +4137,7 @@ bash_execute_unix_command (count, key)
VSETATTR (v, att_exported);
l = v ? value_cell (v) : 0;
value = inttostr (rl_point, ibuf, sizeof (ibuf));
v = bind_int_variable ("READLINE_POINT", value);
v = bind_int_variable ("READLINE_POINT", value, 0);
if (v)
VSETATTR (v, att_exported);
array_needs_making = 1;
+7 -2
View File
@@ -295,6 +295,7 @@ declare_internal (list, local_var)
{
char *value, *name, *oldname;
int offset, aflags, wflags, created_var, namelen;
int assoc_noexpand;
#if defined (ARRAY_VARS)
int making_array_special, compound_array_assign, simple_array_assign;
int var_exists, array_exists, creating_array, array_subscript_assignment;
@@ -302,7 +303,8 @@ declare_internal (list, local_var)
name = savestring (list->word->word);
wflags = list->word->flags;
offset = assignment (name, 0);
assoc_noexpand = assoc_expand_once && (wflags & W_ASSIGNMENT);
offset = assignment (name, assoc_noexpand ? 2 : 0);
aflags = 0;
created_var = 0;
@@ -828,10 +830,13 @@ restart_new_var_name:
assign_array_var_from_string (var, value, aflags|ASS_FORCE);
else if (simple_array_assign && subscript_start)
{
int local_aflags;
/* declare [-aA] name[N]=value */
*subscript_start = '['; /* ] */
/* XXX - problem here with appending */
var = assign_array_element (name, value, aflags&ASS_APPEND); /* XXX - not aflags */
local_aflags = aflags&ASS_APPEND;
local_aflags |= assoc_noexpand ? ASS_NOEXPAND : 0;
var = assign_array_element (name, value, local_aflags); /* XXX - not aflags */
*subscript_start = '\0';
if (var == 0) /* some kind of assignment error */
{
+23 -6
View File
@@ -31,7 +31,8 @@ entry with a `*'. An argument of N lists only the last N entries.
Options:
-c clear the history list by deleting all of the entries
-d offset delete the history entry at position OFFSET.
-d offset delete the history entry at position OFFSET. Negative
offsets count back from the end of the history list
-a append history lines from this session to the history file
-n read all history lines not already read from the history file
@@ -104,7 +105,7 @@ int
history_builtin (list)
WORD_LIST *list;
{
int flags, opt, result, old_history_lines, obase;
int flags, opt, result, old_history_lines, obase, ind;
char *filename, *delete_arg;
intmax_t delete_offset;
@@ -180,14 +181,30 @@ history_builtin (list)
#endif
else if (flags & DFLAG)
{
if ((legal_number (delete_arg, &delete_offset) == 0)
|| (delete_offset < history_base)
|| (delete_offset > (history_base + history_length)))
if (legal_number (delete_arg, &delete_offset) == 0)
{
sh_erange (delete_arg, _("history position"));
return (EXECUTION_FAILURE);
}
opt = delete_offset;
/* check for negative offsets, count back from end of list */
if (delete_arg[0] == '-' && delete_offset < 0)
{
ind = history_length + delete_offset;
if (ind < history_base)
{
sh_erange (delete_arg, _("history position"));
return (EXECUTION_FAILURE);
}
opt = ind + 1; /* so history -d -1 deletes last history entry */
}
else if ((delete_offset < history_base) || (delete_offset > (history_base + history_length)))
{
sh_erange (delete_arg, _("history position"));
return (EXECUTION_FAILURE);
}
else
opt = delete_offset;
result = bash_delete_histent (opt - history_base);
/* Since remove_history changes history_length, this can happen if
we delete the last history entry. */
+3 -3
View File
@@ -258,7 +258,7 @@ printf_builtin (list)
case 'v':
vname = list_optarg;
#if defined (ARRAY_VARS)
if (legal_identifier (vname) || valid_array_reference (vname, 0))
if (legal_identifier (vname) || valid_array_reference (vname, assoc_expand_once))
#else
if (legal_identifier (vname))
#endif
@@ -1270,10 +1270,10 @@ bind_printf_variable (name, value, flags)
SHELL_VAR *v;
#if defined (ARRAY_VARS)
if (valid_array_reference (name, 0) == 0)
if (valid_array_reference (name, assoc_expand_once) == 0)
v = bind_variable (name, value, flags);
else
v = assign_array_element (name, value, flags);
v = assign_array_element (name, value, flags | (assoc_expand_once ? ASS_NOEXPAND : 0));
#else /* !ARRAY_VARS */
v = bind_variable (name, value, flags);
#endif /* !ARRAY_VARS */
+5 -5
View File
@@ -337,7 +337,7 @@ read_builtin (list)
/* Convenience: check early whether or not the first of possibly several
variable names is a valid identifier, and bail early if so. */
#if defined (ARRAY_VARS)
if (list && legal_identifier (list->word->word) == 0 && valid_array_reference (list->word->word, 0) == 0)
if (list && legal_identifier (list->word->word) == 0 && valid_array_reference (list->word->word, assoc_expand_once) == 0)
#else
if (list && legal_identifier (list->word->word) == 0)
#endif
@@ -816,7 +816,7 @@ assign_vars:
{
varname = list->word->word;
#if defined (ARRAY_VARS)
if (legal_identifier (varname) == 0 && valid_array_reference (varname, 0) == 0)
if (legal_identifier (varname) == 0 && valid_array_reference (varname, assoc_expand_once) == 0)
#else
if (legal_identifier (varname) == 0)
#endif
@@ -864,7 +864,7 @@ assign_vars:
/* Now assign the rest of the line to the last variable argument. */
#if defined (ARRAY_VARS)
if (legal_identifier (list->word->word) == 0 && valid_array_reference (list->word->word, 0) == 0)
if (legal_identifier (list->word->word) == 0 && valid_array_reference (list->word->word, assoc_expand_once) == 0)
#else
if (legal_identifier (list->word->word) == 0)
#endif
@@ -927,10 +927,10 @@ bind_read_variable (name, value)
SHELL_VAR *v;
#if defined (ARRAY_VARS)
if (valid_array_reference (name, 0) == 0)
if (valid_array_reference (name, assoc_expand_once) == 0)
v = bind_variable (name, value, 0);
else
v = assign_array_element (name, value, 0);
v = assign_array_element (name, value, assoc_expand_once ? ASS_NOEXPAND : 0);
#else /* !ARRAY_VARS */
v = bind_variable (name, value, 0);
#endif /* !ARRAY_VARS */
+1 -1
View File
@@ -859,7 +859,7 @@ unset_builtin (list)
#if defined (ARRAY_VARS)
unset_array = 0;
if (!unset_function && nameref == 0 && valid_array_reference (name, 1)) /* XXX valid array reference second arg was 0 */
if (!unset_function && nameref == 0 && valid_array_reference (name, assoc_expand_once)) /* XXX valid array reference second arg was 0 */
{
t = strchr (name, '[');
*t++ = '\0';
+6 -2
View File
@@ -5,12 +5,12 @@
.\" Case Western Reserve University
.\" chet.ramey@case.edu
.\"
.\" Last Change: Wed Nov 30 10:05:42 PST 2016
.\" Last Change: Fri Dec 16 11:45:56 EST 2016
.\"
.\" bash_builtins, strip all but Built-Ins section
.if \n(zZ=1 .ig zZ
.if \n(zY=1 .ig zY
.TH BASH 1 "2016 November 30" "GNU Bash 4.4"
.TH BASH 1 "2016 December 16" "GNU Bash 4.4"
.\"
.\" There's some problem with having a `@'
.\" in a tagged paragraph with the BSD man macros.
@@ -8468,6 +8468,10 @@ Clear the history list by deleting all the entries.
.TP
\fB\-d\fP \fIoffset\fP
Delete the history entry at position \fIoffset\fP.
If \fIoffset\fP is negative, it is interpreted as relative to one greater
than the last history position, so negative indices count back from the
end of the history, and an index of \-1 refers to the current
\fBhistory -d\fP command.
.TP
.B \-a
Append the ``new'' history lines to the history file.
+2 -2
View File
@@ -2,10 +2,10 @@
Copyright (C) 1988-2016 Free Software Foundation, Inc.
@end ignore
@set LASTCHANGE Mon Dec 12 12:26:16 EST 2016
@set LASTCHANGE Fri Dec 16 11:45:56 EST 2016
@set EDITION 4.4
@set VERSION 4.4
@set UPDATED 12 December 2016
@set UPDATED 16 December 2016
@set UPDATED-MONTH December 2016
+9 -5
View File
@@ -82,6 +82,7 @@
#include "bashintl.h"
#include "shell.h"
#include "subst.h"
#include "typemax.h" /* INTMAX_MAX, INTMAX_MIN */
/* Because of the $((...)) construct, expressions may include newlines.
@@ -317,8 +318,10 @@ expr_bind_variable (lhs, rhs)
char *lhs, *rhs;
{
SHELL_VAR *v;
int aflags;
v = bind_int_variable (lhs, rhs);
aflags = (assoc_expand_once && already_expanded) ? ASS_NOEXPAND : 0;
v = bind_int_variable (lhs, rhs, aflags);
if (v && (readonly_p (v) || noassign_p (v)))
sh_longjmp (evalbuf, 1); /* variable assignment error */
stupidly_hack_special_variables (lhs);
@@ -1150,10 +1153,11 @@ expr_streval (tok, e, lvalue)
#if defined (ARRAY_VARS)
ind = -1;
/* Second argument of 0 to get_array_value means that we don't allow
references like array[@]. In this case, get_array_value is just
like get_variable_value in that it does not return newly-allocated
memory or quote the results. */
/* If the second argument to get_array_value doesn't include AV_ALLOWALL,
we don't allow references like array[@]. In this case, get_array_value
is just like get_variable_value in that it does not return newly-allocated
memory or quote the results. AFLAG is set above and is either AV_NOEXPAND
or 0. */
value = (e == ']') ? get_array_value (tok, aflag, (int *)NULL, &ind) : get_variable_value (v);
#else
value = get_variable_value (v);
+4 -3
View File
@@ -349,7 +349,8 @@ legal_alias_name (string, flags)
}
/* Returns non-zero if STRING is an assignment statement. The returned value
is the index of the `=' sign. */
is the index of the `=' sign. If FLAGS&1 we are expecting a compound assignment
and don't want an array subscript before the `='. */
int
assignment (string, flags)
const char *string;
@@ -361,7 +362,7 @@ assignment (string, flags)
c = string[indx = 0];
#if defined (ARRAY_VARS)
if ((legal_variable_starter (c) == 0) && (flags == 0 || c != '[')) /* ] */
if ((legal_variable_starter (c) == 0) && ((flags&1) == 0 || c != '[')) /* ] */
#else
if (legal_variable_starter (c) == 0)
#endif
@@ -377,7 +378,7 @@ assignment (string, flags)
#if defined (ARRAY_VARS)
if (c == '[')
{
newi = skipsubscript (string, indx, 0);
newi = skipsubscript (string, indx, (flags & 2) ? 1 : 0);
if (string[newi++] != ']')
return (0);
if (string[newi] == '+' && string[newi+1] == '=')
+6 -2
View File
@@ -198,8 +198,12 @@ with the other options to replace the history list completely.
@item -d @var{offset}
Delete the history entry at position @var{offset}.
@var{offset} should be specified as it appears when the history is
displayed.
If @var{offset} is positive, it should be specified as it appears when
the history is displayed.
If @var{offset} is negative, it is interpreted as relative to one greater
than the last history position, so negative indices count back from the
end of the history, and an index of @samp{-1} refers to the current
@code{history -d} command.
@item -a
Append the new history lines to the history file.
+13
View File
@@ -498,14 +498,27 @@ remove_history (which)
{
HIST_ENTRY *return_value;
register int i;
#if 1
int nentries;
HIST_ENTRY **start, **end;
#endif
if (which < 0 || which >= history_length || history_length == 0 || the_history == 0)
return ((HIST_ENTRY *)NULL);
return_value = the_history[which];
#if 1
/* Copy the rest of the entries, moving down one slot. Copy includes
trailing NULL. */
nentries = history_length - which;
start = the_history + which;
end = start + 1;
memmove (start, end, nentries * sizeof (HIST_ENTRY *));
#else
for (i = which; i < history_length; i++)
the_history[i] = the_history[i + 1];
#endif
history_length--;
+4 -4
View File
@@ -993,17 +993,17 @@ bind_compfunc_variables (line, ind, lwords, cw, exported)
llen = MB_STRLEN (line);
line[ind] = c;
value = inttostr (llen, ibuf, sizeof(ibuf));
v = bind_int_variable ("COMP_POINT", value);
v = bind_int_variable ("COMP_POINT", value, 0);
if (v && exported)
VSETATTR(v, att_exported);
value = inttostr (rl_completion_type, ibuf, sizeof (ibuf));
v = bind_int_variable ("COMP_TYPE", value);
v = bind_int_variable ("COMP_TYPE", value, 0);
if (v && exported)
VSETATTR(v, att_exported);
value = inttostr (rl_completion_invoking_key, ibuf, sizeof (ibuf));
v = bind_int_variable ("COMP_KEY", value);
v = bind_int_variable ("COMP_KEY", value, 0);
if (v && exported)
VSETATTR(v, att_exported);
@@ -1014,7 +1014,7 @@ bind_compfunc_variables (line, ind, lwords, cw, exported)
#ifdef ARRAY_VARS
v = bind_comp_words (lwords);
value = inttostr (cw, ibuf, sizeof(ibuf));
bind_int_variable ("COMP_CWORD", value);
bind_int_variable ("COMP_CWORD", value, 0);
#endif
}
else
+1 -1
View File
@@ -8963,7 +8963,7 @@ arithsub:
/* No error messages. */
savecmd = this_command_name;
this_command_name = (char *)NULL;
number = evalexp (temp1, 0, &expok);
number = evalexp (temp1, EXP_EXPANDED, &expok);
this_command_name = savecmd;
free (temp);
free (temp1);
+1
View File
@@ -51,6 +51,7 @@
#define ASS_NAMEREF 0x0010 /* assigning to nameref variable */
#define ASS_FORCE 0x0020 /* force assignment even to readonly variable */
#define ASS_CHKLOCAL 0x0040 /* check local variable before assignment */
#define ASS_NOEXPAND 0x0080 /* don't expand associative array subscripts */
/* Flags for the string extraction functions. */
#define SX_NOALLOC 0x0001 /* just skip; don't return substring */
+20
View File
@@ -195,3 +195,23 @@ declare -A assoc=([0]="assoc" )
assoc
declare -A assoc=([two]="twoless" [three]="three" [one]="onemore" )
declare -Ar assoc=([two]="twoless" [three]="three" [one]="onemore" )
declare -A b=(["\""]="" [")"]="" ["\\"]="" ["]"]="" ["\`"]="" )
declare -A b=(["]"]="" ["\`"]="" )
declare -A dict=(["\""]="1" ["'"]="3" ["\\"]="4" ["\`"]="2" )
./assoc9.sub: line 23: unset: `dict["]': not a valid identifier
./assoc9.sub: line 23: unset: `dict[']': not a valid identifier
./assoc9.sub: line 23: unset: `dict[\]': not a valid identifier
./assoc9.sub: line 23: unset: `dict[`]': not a valid identifier
declare -A dict=(["\""]="1" ["'"]="3" ["\\"]="4" ["\`"]="2" )
declare -A dict=(["\""]="1" ["'"]="3" ["\\"]="4" ["\`"]="2" )
declare -A dict=()
4
4
a[$b]= 5
declare -A a=(["80's"]="Depeche Mode" )
./assoc9.sub: line 71: read: `a[80's]': not a valid identifier
declare -A a
declare -A a=(["80's"]="Depeche Mode" )
./assoc9.sub: line 83: printf: `a[80's]': not a valid identifier
declare -A a
declare -A a=(["80's"]="Depeche Mode" )
+3
View File
@@ -207,3 +207,6 @@ readonly -A assoc
declare -p assoc
${THIS_SH} ./assoc8.sub
# new shopt option to prevent multiple expansion of assoc array subscripts
${THIS_SH} ./assoc9.sub
+89
View File
@@ -0,0 +1,89 @@
typeset -A a=( [\\]= [\"]= [\)]= ) b
for x in "${!a[@]}"; do b[$x]=; done
b+=([\`]= [\]]=)
typeset -p b
for x in "${!a[@]}"; do
unset -v 'b[$x]'
done
typeset -p b
unset -v a b
loaddict()
{
dict['"']=1
dict['`']=2
dict["'"]=3
dict['\']=4
declare -p dict
}
del()
{
unset -v dict["$1"];
}
declare -A dict
loaddict
for k in "${!dict[@]}"; do del "$k"; done
declare -p dict
unset 'dict[@]'
shopt -s assoc_expand_once
declare -A dict
loaddict
for k in "${!dict[@]}"; do del "$k"; done
declare -p dict
unset a b dict
typeset -A a
b="80's"
((++a[$b]))
((++a["$b"]))
[[ $((++a[$b])) ]]
[[ $((++a["$b"])) ]]
echo ${a["$b"]}
echo ${a[$b]}
let "++a[$b]"
echo 'a[$b]=' "${a[$b]}"
unset a b
declare -A a
b="80's"
: ${a[$b]:='Depeche Mode'}
declare -p a
unset a b
shopt -u assoc_expand_once
typeset -A a
b="80's"
read a[$b] <<<"Depeche Mode"
typeset -p a
shopt -s assoc_expand_once
read a[$b] <<<"Depeche Mode"
typeset -p a
unset a
shopt -u assoc_expand_once
typeset -A a
printf -v a[$b] "%s" "Depeche Mode"
typeset -p a
shopt -s assoc_expand_once
printf -v a[$b] "%s" "Depeche Mode"
typeset -p a
+7 -6
View File
@@ -3076,18 +3076,19 @@ bind_variable_value (var, value, aflags)
variable we set here, then turn it back on after binding as necessary. */
SHELL_VAR *
bind_int_variable (lhs, rhs)
bind_int_variable (lhs, rhs, flags)
char *lhs, *rhs;
int flags;
{
register SHELL_VAR *v;
int isint, isarr, implicitarray;
isint = isarr = implicitarray = 0;
#if defined (ARRAY_VARS)
if (valid_array_reference (lhs, 0))
if (valid_array_reference (lhs, (flags & ASS_NOEXPAND) != 0))
{
isarr = 1;
v = array_variable_part (lhs, 0, (char **)0, (int *)0);
v = array_variable_part (lhs, (flags & ASS_NOEXPAND) != 0, (char **)0, (int *)0);
}
else
#endif
@@ -3105,9 +3106,9 @@ bind_int_variable (lhs, rhs)
#if defined (ARRAY_VARS)
if (isarr)
v = assign_array_element (lhs, rhs, 0);
v = assign_array_element (lhs, rhs, flags);
else if (implicitarray)
v = bind_array_variable (lhs, 0, rhs, 0);
v = bind_array_variable (lhs, 0, rhs, 0); /* XXX - check on flags */
else
#endif
v = bind_variable (lhs, rhs, 0); /* why not use bind_variable_value? */
@@ -3133,7 +3134,7 @@ bind_var_to_int (var, val)
char ibuf[INT_STRLEN_BOUND (intmax_t) + 1], *p;
p = fmtulong (val, 10, ibuf, sizeof (ibuf), 0);
return (bind_int_variable (var, p));
return (bind_int_variable (var, p, 0));
}
/* Do a function binding to a variable. You pass the name and
+1 -1
View File
@@ -296,7 +296,7 @@ extern char *sh_get_env_value __P((const char *));
extern char *make_variable_value __P((SHELL_VAR *, char *, int));
extern SHELL_VAR *bind_variable_value __P((SHELL_VAR *, char *, int));
extern SHELL_VAR *bind_int_variable __P((char *, char *));
extern SHELL_VAR *bind_int_variable __P((char *, char *, int));
extern SHELL_VAR *bind_var_to_int __P((char *, intmax_t));
extern int assign_in_env __P((WORD_DESC *, int));