From 06db13a410aad0af6fdfce901e214e20a80652de Mon Sep 17 00:00:00 2001 From: Chet Ramey Date: Tue, 20 Dec 2016 14:15:35 -0500 Subject: [PATCH] commit bash-20161216 snapshot --- CWRU/CWRU.chlog | 70 ++++++++++++++++++++++++++++ MANIFEST | 1 + arrayfunc.c | 10 ++-- bashline.c | 2 +- builtins/declare.def | 9 +++- builtins/history.def | 29 +++++++++--- builtins/printf.def | 6 +-- builtins/read.def | 10 ++-- builtins/set.def | 2 +- doc/bash.1 | 8 +++- doc/version.texi | 4 +- expr.c | 14 ++++-- general.c | 7 +-- lib/readline/doc/hsuser.texi | 8 +++- lib/readline/history.c | 13 ++++++ pcomplete.c | 8 ++-- subst.c | 2 +- subst.h | 1 + tests/assoc.right | 20 ++++++++ tests/assoc.tests | 3 ++ tests/assoc9.sub | 89 ++++++++++++++++++++++++++++++++++++ variables.c | 13 +++--- variables.h | 2 +- 23 files changed, 284 insertions(+), 47 deletions(-) create mode 100644 tests/assoc9.sub diff --git a/CWRU/CWRU.chlog b/CWRU/CWRU.chlog index bf119c4c..155f237a 100644 --- a/CWRU/CWRU.chlog +++ b/CWRU/CWRU.chlog @@ -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 + +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 diff --git a/MANIFEST b/MANIFEST index d033b3fa..668d433b 100644 --- a/MANIFEST +++ b/MANIFEST @@ -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 diff --git a/arrayfunc.c b/arrayfunc.c index c31afc50..9a1a1401 100644 --- a/arrayfunc.c +++ b/arrayfunc.c @@ -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) { diff --git a/bashline.c b/bashline.c index f6cd75b7..e5d9f5e3 100644 --- a/bashline.c +++ b/bashline.c @@ -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; diff --git a/builtins/declare.def b/builtins/declare.def index 276f538e..c0fa3b56 100644 --- a/builtins/declare.def +++ b/builtins/declare.def @@ -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 */ { diff --git a/builtins/history.def b/builtins/history.def index 48b59aeb..8428bc36 100644 --- a/builtins/history.def +++ b/builtins/history.def @@ -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. */ diff --git a/builtins/printf.def b/builtins/printf.def index e6b82c02..5f20e068 100644 --- a/builtins/printf.def +++ b/builtins/printf.def @@ -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 */ diff --git a/builtins/read.def b/builtins/read.def index 8d1fd452..eebdf593 100644 --- a/builtins/read.def +++ b/builtins/read.def @@ -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 */ diff --git a/builtins/set.def b/builtins/set.def index a6a70aa2..9a45f388 100644 --- a/builtins/set.def +++ b/builtins/set.def @@ -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'; diff --git a/doc/bash.1 b/doc/bash.1 index 7c3496d7..6c1adfae 100644 --- a/doc/bash.1 +++ b/doc/bash.1 @@ -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. diff --git a/doc/version.texi b/doc/version.texi index fc58e42e..e47c17e4 100644 --- a/doc/version.texi +++ b/doc/version.texi @@ -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 diff --git a/expr.c b/expr.c index 8fc9b359..48a92fc2 100644 --- a/expr.c +++ b/expr.c @@ -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); diff --git a/general.c b/general.c index a711360a..9e4dc7d9 100644 --- a/general.c +++ b/general.c @@ -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] == '=') diff --git a/lib/readline/doc/hsuser.texi b/lib/readline/doc/hsuser.texi index 04e192eb..7999eb56 100644 --- a/lib/readline/doc/hsuser.texi +++ b/lib/readline/doc/hsuser.texi @@ -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. diff --git a/lib/readline/history.c b/lib/readline/history.c index 4362837e..915e7ae4 100644 --- a/lib/readline/history.c +++ b/lib/readline/history.c @@ -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--; diff --git a/pcomplete.c b/pcomplete.c index 7c629890..3d734d97 100644 --- a/pcomplete.c +++ b/pcomplete.c @@ -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 diff --git a/subst.c b/subst.c index 9ddbcc19..16f19e34 100644 --- a/subst.c +++ b/subst.c @@ -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); diff --git a/subst.h b/subst.h index 577cf571..c588ccb3 100644 --- a/subst.h +++ b/subst.h @@ -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 */ diff --git a/tests/assoc.right b/tests/assoc.right index 0a6951d4..6de4af26 100644 --- a/tests/assoc.right +++ b/tests/assoc.right @@ -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" ) diff --git a/tests/assoc.tests b/tests/assoc.tests index 863405b6..f5bbdba3 100644 --- a/tests/assoc.tests +++ b/tests/assoc.tests @@ -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 diff --git a/tests/assoc9.sub b/tests/assoc9.sub new file mode 100644 index 00000000..30161aad --- /dev/null +++ b/tests/assoc9.sub @@ -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 diff --git a/variables.c b/variables.c index 027b0ce8..fe42d62d 100644 --- a/variables.c +++ b/variables.c @@ -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 diff --git a/variables.h b/variables.h index 25c9ae07..7b398f33 100644 --- a/variables.h +++ b/variables.h @@ -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));