From 057a9fbdb4d9ad01b000743fcea9918b80823afc Mon Sep 17 00:00:00 2001 From: Chet Ramey Date: Mon, 6 Aug 2018 08:58:26 -0400 Subject: [PATCH] commit bash-20180803 snapshot --- CWRU/CWRU.chlog | 44 ++++++++ MANIFEST | 3 +- array.c | 86 ++++------------ assoc.c | 55 +++------- subst.c | 65 +++++++----- tests/array.right | 68 ++++++++++++ tests/array6.sub | 73 +++++++++++++ tests/nameref.right | 6 ++ tests/nameref20.sub | 13 +++ tests/nquote1.right | 10 ++ tests/nquote1.tests | 9 ++ tests/run-varenv | 2 +- tests/varenv.right | 17 +++ tests/varenv.tests | 244 ++++++++++++++++++++++++++++++++++++++++++++ tests/varenv14.sub | 33 ++++++ variables.c | 48 +++++++-- 16 files changed, 635 insertions(+), 141 deletions(-) create mode 100644 tests/varenv.tests create mode 100644 tests/varenv14.sub diff --git a/CWRU/CWRU.chlog b/CWRU/CWRU.chlog index eb7c8d6f..2e3aa5fb 100644 --- a/CWRU/CWRU.chlog +++ b/CWRU/CWRU.chlog @@ -4109,3 +4109,47 @@ subst.c subst.c - get_var_and_type: if VALUE is NULL, check before calling dequote_string. Report and fix from Grisha Levit + + 7/30 + ---- +variables.c + - make_local_{array,assoc}_variable: make sure we're not trying to + inherit a value from an incompatible array type. Fixes issue raised + by Grisha Levit + - nameref_transform_name: if we're trying to resolve a nameref that + will be used to create a local variable, make sure the nameref is + at the same variable scope. Report from Grisha Levit + + + 8/2 + --- +array.c + - array_subrange: change to use string_list_pos_params after creating a + WORD_LIST from the array slice, like assoc_subrange does + +subst.c + - parameter_brace_substring: since assoc_subrange and array_subrange + both call string_list_pos_params now, treat the results the same as + the VT_POSPARAMS case (pos_params also calls string_list_pos_params). + Fixes behavior difference between ${a[@]:sub} and ${@:sub} reported + by Ilkka Virta + + 8/3 + --- +array.c + - array_patsub: rewrite to work in terms of a WORD_LIST * and call + string_list_pos_params on the result to be consistent with the + expansions of ${@/pat/rep} and ${*/pat/rep} + +assoc.c + - assoc_patsub: rewrite to work in terms of a WORD_LIST * and call + string_list_pos_params on the result to be consistent with the + expansions of ${@/pat/rep} and ${*/pat/rep} + +subst.c + - parameter_brace_patsub: change how return value of {array,assoc}_patsub + is treated to make it identical to pos_params_pat_subst, since they + all call string_list_pos_params now + - expand_string_for_pat: make sure we preserve the value of + expand_no_split_dollar_star instead of just unconditionally setting + it back to 0 in case it was 1 before this function was called diff --git a/MANIFEST b/MANIFEST index 2fe3081e..6b5ee772 100644 --- a/MANIFEST +++ b/MANIFEST @@ -1359,7 +1359,7 @@ tests/unicode1.sub f tests/unicode2.sub f tests/unicode3.sub f tests/varenv.right f -tests/varenv.sh f +tests/varenv.tests f tests/varenv1.sub f tests/varenv2.sub f tests/varenv3.sub f @@ -1373,6 +1373,7 @@ tests/varenv10.sub f tests/varenv11.sub f tests/varenv12.sub f tests/varenv13.sub f +tests/varenv14.sub f tests/version f tests/version.mini f tests/vredir.tests f diff --git a/array.c b/array.c index 5f7d72f1..56d586b4 100644 --- a/array.c +++ b/array.c @@ -406,8 +406,8 @@ int starsub, quoted; ARRAY *a2; ARRAY_ELEMENT *h, *p; arrayind_t i; - char *ifs, *sifs, *t; - int slen; + char *t; + WORD_LIST *wl; p = a ? array_head (a) : 0; if (p == 0 || array_empty (a) || start > array_max_index(a)) @@ -432,32 +432,12 @@ int starsub, quoted; a2 = array_slice(a, h, p); - if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) - array_quote(a2); - else - array_quote_escapes(a2); - - if (starsub && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))) { - /* ${array[*]} */ - array_remove_quoted_nulls (a2); - sifs = ifs_firstchar ((int *)NULL); - t = array_to_string (a2, sifs, 0); - free (sifs); - } else if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) { - /* ${array[@]} */ - sifs = ifs_firstchar (&slen); - ifs = getifs (); - if (ifs == 0 || *ifs == 0) { - if (slen < 2) - sifs = xrealloc(sifs, 2); - sifs[0] = ' '; - sifs[1] = '\0'; - } - t = array_to_string (a2, sifs, 0); - free (sifs); - } else - t = array_to_string (a2, " ", 0); + wl = array_to_word_list(a2); array_dispose(a2); + if (wl == 0) + return (char *)NULL; + t = string_list_pos_params(starsub ? '*' : '@', wl, quoted); + dispose_words(wl); return t; } @@ -468,50 +448,28 @@ ARRAY *a; char *pat, *rep; int mflags; { - ARRAY *a2; - ARRAY_ELEMENT *e; - char *t, *sifs, *ifs; - int slen; + char *t; + int pchar, qflags; + WORD_LIST *wl, *save; if (a == 0 || array_head(a) == 0 || array_empty(a)) return ((char *)NULL); - a2 = array_copy(a); - for (e = element_forw(a2->head); e != a2->head; e = element_forw(e)) { - t = pat_subst(element_value(e), pat, rep, mflags); - FREE(element_value(e)); - e->value = t; + wl = array_to_word_list(a); + if (wl == 0) + return (char *)NULL; + + for (save = wl; wl; wl = wl->next) { + t = pat_subst (wl->word->word, pat, rep, mflags); + FREE (wl->word->word); + wl->word->word = t; } - if (mflags & MATCH_QUOTED) - array_quote(a2); - else - array_quote_escapes(a2); + pchar = (mflags & MATCH_STARSUB) == MATCH_STARSUB ? '*' : '@'; + qflags = (mflags & MATCH_QUOTED) == MATCH_QUOTED ? Q_DOUBLE_QUOTES : 0; - if (mflags & MATCH_STARSUB) { - array_remove_quoted_nulls (a2); - if ((mflags & MATCH_QUOTED) == 0 && ifs_is_null) - sifs = spacesep; - else - sifs = ifs_firstchar((int *)NULL); - t = array_to_string (a2, sifs, 0); - if (sifs != spacesep) - free(sifs); - } else if (mflags & MATCH_QUOTED) { - /* ${array[@]} */ - sifs = ifs_firstchar (&slen); - ifs = getifs (); - if (ifs == 0 || *ifs == 0) { - if (slen < 2) - sifs = xrealloc (sifs, 2); - sifs[0] = ' '; - sifs[1] = '\0'; - } - t = array_to_string (a2, sifs, 0); - free(sifs); - } else - t = array_to_string (a2, " ", 0); - array_dispose (a2); + t = string_list_pos_params (pchar, save, qflags); + dispose_words(save); return t; } diff --git a/assoc.c b/assoc.c index 84a387c2..202d4a67 100644 --- a/assoc.c +++ b/assoc.c @@ -305,54 +305,29 @@ assoc_patsub (h, pat, rep, mflags) char *pat, *rep; int mflags; { - BUCKET_CONTENTS *tlist; - int i, slen; - HASH_TABLE *h2; - char *t, *sifs, *ifs; + char *t; + int pchar, qflags; + WORD_LIST *wl, *save; if (h == 0 || assoc_empty (h)) return ((char *)NULL); - h2 = assoc_copy (h); - for (i = 0; i < h2->nbuckets; i++) - for (tlist = hash_items (i, h2); tlist; tlist = tlist->next) - { - t = pat_subst ((char *)tlist->data, pat, rep, mflags); - FREE (tlist->data); - tlist->data = t; - } + wl = assoc_to_word_list (h); + if (wl == 0) + return (char *)NULL; - if (mflags & MATCH_QUOTED) - assoc_quote (h2); - else - assoc_quote_escapes (h2); - - if (mflags & MATCH_STARSUB) + for (save = wl; wl; wl = wl->next) { - assoc_remove_quoted_nulls (h2); - sifs = ifs_firstchar ((int *)NULL); - t = assoc_to_string (h2, sifs, 0); - free (sifs); + t = pat_subst (wl->word->word, pat, rep, mflags); + FREE (wl->word->word); + wl->word->word = t; } - else if (mflags & MATCH_QUOTED) - { - /* ${array[@]} */ - sifs = ifs_firstchar (&slen); - ifs = getifs (); - if (ifs == 0 || *ifs == 0) - { - if (slen < 2) - sifs = xrealloc (sifs, 2); - sifs[0] = ' '; - sifs[1] = '\0'; - } - t = assoc_to_string (h2, sifs, 0); - free(sifs); - } - else - t = assoc_to_string (h2, " ", 0); - assoc_dispose (h2); + pchar = (mflags & MATCH_STARSUB) == MATCH_STARSUB ? '*' : '@'; + qflags = (mflags & MATCH_QUOTED) == MATCH_QUOTED ? Q_DOUBLE_QUOTES : 0; + + t = string_list_pos_params (pchar, save, qflags); + dispose_words (save); return t; } diff --git a/subst.c b/subst.c index 59ba900d..c9c94571 100644 --- a/subst.c +++ b/subst.c @@ -3903,15 +3903,17 @@ expand_string_for_pat (string, quoted, dollar_at_p, expanded_p) { WORD_DESC td; WORD_LIST *tresult; + int oexp; if (string == 0 || *string == '\0') return (WORD_LIST *)NULL; + oexp = expand_no_split_dollar_star; expand_no_split_dollar_star = 1; td.flags = W_NOSPLIT2; /* no splitting, remove "" and '' */ td.word = string; tresult = call_expand_word_internal (&td, quoted, 1, dollar_at_p, expanded_p); - expand_no_split_dollar_star = 0; + expand_no_split_dollar_star = oexp; return (tresult); } @@ -7706,7 +7708,7 @@ parameter_brace_substring (varname, value, ind, substr, quoted, pflags, flags) int quoted, pflags, flags; { intmax_t e1, e2; - int vtype, r, starsub, qflags; + int vtype, r, starsub; char *temp, *val, *tt, *oname; SHELL_VAR *v; @@ -7755,9 +7757,23 @@ parameter_brace_substring (varname, value, ind, substr, quoted, pflags, flags) FREE (tt); break; case VT_POSPARMS: - qflags = quoted; - tt = pos_params (varname, e1, e2, qflags); - /* string_list_dollar_at will quote the list if ifs_is_null != 0 */ + case VT_ARRAYVAR: + if (vtype == VT_POSPARMS) + tt = pos_params (varname, e1, e2, quoted); +#if defined (ARRAY_VARS) + /* assoc_subrange and array_subrange both call string_list_pos_params, + so we can treat this case just like VT_POSPARAMS. */ + else if (assoc_p (v)) + /* we convert to list and take first e2 elements starting at e1th + element -- officially undefined for now */ + tt = assoc_subrange (assoc_cell (v), e1, e2, starsub, quoted); + else + /* We want E2 to be the number of elements desired (arrays can be + sparse, so verify_substring_values just returns the numbers + specified and we rely on array_subrange to understand how to + deal with them). */ + tt = array_subrange (array_cell (v), e1, e2, starsub, quoted); +#endif /* We want to leave this alone in every case where pos_params/ string_list_pos_params quotes the list members */ if (tt && quoted == 0 && ifs_is_null) @@ -7772,21 +7788,7 @@ parameter_brace_substring (varname, value, ind, substr, quoted, pflags, flags) else temp = tt; break; -#if defined (ARRAY_VARS) - case VT_ARRAYVAR: - if (assoc_p (v)) - /* we convert to list and take first e2 elements starting at e1th - element -- officially undefined for now */ - temp = assoc_subrange (assoc_cell (v), e1, e2, starsub, quoted); - else - /* We want E2 to be the number of elements desired (arrays can be sparse, - so verify_substring_values just returns the numbers specified and we - rely on array_subrange to understand how to deal with them). */ - temp = array_subrange (array_cell (v), e1, e2, starsub, quoted); - /* array_subrange now calls array_quote_escapes as appropriate, so the - caller no longer needs to. */ - break; -#endif + default: temp = (char *)NULL; } @@ -7978,7 +7980,7 @@ pos_params_pat_subst (string, pat, rep, mflags) qflags = (mflags & MATCH_QUOTED) == MATCH_QUOTED ? Q_DOUBLE_QUOTES : 0; /* If we are expanding in a context where word splitting will not be - performed, treat as quoted. This changes how $* will be expanded. */ + performed, treat as quoted. This changes how $* will be expanded. */ if (pchar == '*' && (mflags & MATCH_ASSIGNRHS) && expand_no_split_dollar_star && ifs_is_null) qflags |= Q_DOUBLE_QUOTES; /* Posix interp 888 */ @@ -8145,11 +8147,22 @@ parameter_brace_patsub (varname, value, ind, patsub, quoted, pflags, flags) if ((mflags & MATCH_STARSUB) && (mflags & MATCH_ASSIGNRHS) && ifs_is_null) mflags |= MATCH_QUOTED; /* Posix interp 888 */ - temp = assoc_p (v) ? assoc_patsub (assoc_cell (v), p, rep, mflags) - : array_patsub (array_cell (v), p, rep, mflags); - /* Don't call quote_escapes anymore; array_patsub calls - array_quote_escapes as appropriate before adding the - space separators; ditto for assoc_patsub. */ + /* these eventually call string_list_pos_params */ + if (assoc_p (v)) + temp = assoc_patsub (assoc_cell (v), p, rep, mflags); + else + temp = array_patsub (array_cell (v), p, rep, mflags); + + if (temp && quoted == 0 && ifs_is_null) + { + /* Posix interp 888 */ + } + else if (temp && (mflags & MATCH_QUOTED) == 0) + { + tt = quote_escapes (temp); + free (temp); + temp = tt; + } break; #endif } diff --git a/tests/array.right b/tests/array.right index aab4153d..00e3a9dd 100644 --- a/tests/array.right +++ b/tests/array.right @@ -270,6 +270,74 @@ argv[1] = argv[2] = argv[1] = argv[2] = +argv[1] = +argv[2] = +argv[1] = +argv[2] = +argv[1] = +argv[2] = +argv[1] = +argv[2] = +argv[1] = +argv[2] = +argv[3] = +argv[4] = +argv[1] = +argv[2] = +argv[3] = +argv[4] = +argv[1] = +argv[2] = +argv[1] = +argv[2] = +argv[3] = +argv[4] = +argv[1] = +argv[2] = +argv[1] = +argv[2] = +argv[1] = +argv[2] = +argv[1] = +argv[2] = +argv[1] = +argv[2] = +argv[1] = +argv[2] = +argv[1] = +argv[1] = +argv[1] = +argv[2] = +argv[1] = +argv[2] = +argv[1] = +argv[2] = +argv[1] = +argv[2] = +argv[1] = +argv[1] = +argv[2] = +argv[1] = +argv[2] = +argv[1] = +argv[2] = +argv[1] = +argv[2] = +argv[1] = +argv[2] = +argv[1] = +argv[2] = +argv[1] = +argv[1] = +argv[1] = +argv[2] = +argv[1] = +argv[2] = +argv[1] = +argv[2] = +argv[1] = +argv[2] = +argv[1] = nord!olz rdholz diff --git a/tests/array6.sub b/tests/array6.sub index 0017f4cd..2dc40fcb 100644 --- a/tests/array6.sub +++ b/tests/array6.sub @@ -113,3 +113,76 @@ recho $@ IFS="$oIFS" unset a a2 array foo + +# these should produce the same results +a=(aa bb) +set -- aa bb + +IFS=+ + +recho ${a[@]} +recho ${a[@]:0} + +recho $@ +recho ${@:1} + +A=${a[*]} B=${a[*]:0} +recho $* ${*:1} +recho ${a[*]} ${a[*]:0} +recho "$A" "$B" +recho $A $B + +unset A B + +recho ${@/a/x} +recho ${a[@]/a/x} +recho "${@/a/x}" +recho "${a[@]/a/x}" + +recho ${*/a/x} +recho ${a[*]/a/x} +recho "${*/a/x}" +recho "${a[*]/a/x}" + +A=${*/a/x} +B=${a[*]/a/x} + +recho "$A" "$B" + +unset A B +declare -A A +A[0]=aa +A[1]=bb + +recho ${A[@]/a/x} +recho "${A[@]/a/x}" +recho ${A[*]/a/x} +recho "${A[*]/a/x}" + +unset A +IFS= + +recho ${@/a/x} +recho ${a[@]/a/x} +recho "${@/a/x}" +recho "${a[@]/a/x}" + +recho ${*/a/x} +recho ${a[*]/a/x} +recho "${*/a/x}" +recho "${a[*]/a/x}" + +A=${*/a/x} +B=${a[*]/a/x} + +recho "$A" "$B" + +unset A B +declare -A A +A[0]=aa +A[1]=bb + +recho ${A[@]/a/x} +recho "${A[@]/a/x}" +recho ${A[*]/a/x} +recho "${A[*]/a/x}" diff --git a/tests/nameref.right b/tests/nameref.right index 233a31cf..b52a3e90 100644 --- a/tests/nameref.right +++ b/tests/nameref.right @@ -463,3 +463,9 @@ outside: ./nameref20.sub: line 45: declare: var: not found declare -n ref="var" declare -a var=([0]="Y") +declare -- ref="Y" +declare -- var="X" +ref=Y +declare -- ref="Y" +./nameref20.sub: line 61: declare: var: not found +ref=Y diff --git a/tests/nameref20.sub b/tests/nameref20.sub index 7416233d..211975e2 100644 --- a/tests/nameref20.sub +++ b/tests/nameref20.sub @@ -54,3 +54,16 @@ f() declare -p ref var } f + +unset -f f + +declare -n ref=var +f() { local ref=Y; declare -p ref var; local; } + +var=X +f + +unset -v var +f + +unset -n ref diff --git a/tests/nquote1.right b/tests/nquote1.right index 26e16b91..45389ef3 100644 --- a/tests/nquote1.right +++ b/tests/nquote1.right @@ -119,3 +119,13 @@ argv[3] = argv[1] = <@2> argv[2] = argv[3] = +argv[1] = +argv[2] = +argv[1] = +argv[2] = +argv[1] = +argv[2] = +argv[3] = +argv[1] = +argv[2] = +argv[3] = diff --git a/tests/nquote1.tests b/tests/nquote1.tests index 0970e77c..f47ab54e 100644 --- a/tests/nquote1.tests +++ b/tests/nquote1.tests @@ -95,3 +95,12 @@ recho d2 "${1:2:2}" recho @1 ${@:1:2} recho @2 "${@:1:2}" + +declare -A assoc +assoc=( [0]=$e [1]=$e ) + +recho aa1 ${assoc:0:4} +recho aa2 "${assoc:0:4}" + +recho aa3 ${assoc[@]:0:2} +recho aa4 "${assoc[@]:0:2}" diff --git a/tests/run-varenv b/tests/run-varenv index 5987a7f3..f147d70b 100644 --- a/tests/run-varenv +++ b/tests/run-varenv @@ -1,2 +1,2 @@ -${THIS_SH} ./varenv.sh 2>&1 | grep -v '^expect' > ${BASH_TSTOUT} +${THIS_SH} ./varenv.tests 2>&1 | grep -v '^expect' > ${BASH_TSTOUT} diff ${BASH_TSTOUT} varenv.right && rm -f ${BASH_TSTOUT} diff --git a/tests/varenv.right b/tests/varenv.right index 8d72266d..c2f00848 100644 --- a/tests/varenv.right +++ b/tests/varenv.right @@ -160,6 +160,23 @@ declare -A var=([0]="X" ) help ./varenv13.sub: line 21: `var[0]': not a valid identifier 1 +./varenv14.sub: line 6: warning: var: cannot inherit value from incompatible type +declare -a var=([0]="X") +./varenv14.sub: line 9: warning: var: cannot inherit value from incompatible type +declare -a var=([0]="Y") +./varenv14.sub: line 10: warning: var: cannot inherit value from incompatible type +declare -a var=([0]="Y") +./varenv14.sub: line 11: warning: var: cannot inherit value from incompatible type +declare -a var=() +./varenv14.sub: line 12: warning: var: cannot inherit value from incompatible type +declare -a var=() +./varenv14.sub: line 18: f: var: cannot convert indexed to associative array +declare -a a=([0]="X") +declare -a s=([0]="X") +declare -a a=([0]="X" [1]="Y") +declare -a s=([0]="X" [1]="Y") +declare -a a=([0]="XY") +declare -a s=([0]="XY") a=z a=b a=z diff --git a/tests/varenv.tests b/tests/varenv.tests new file mode 100644 index 00000000..52d23fdd --- /dev/null +++ b/tests/varenv.tests @@ -0,0 +1,244 @@ +# +# varenv.sh +# +# Test the behavior of the shell with respect to variable and environment +# assignments +# +expect() +{ + echo expect "$@" +} + +a=1 +b=2 +c=3 +d=4 +e=5 +f=6 g=7 h=8 + +a=3 b=4 $CHMOD $MODE $FN + +# This should echo "3 4" according to Posix.2 +expect "3 4" +echo $a $b + +set -k + +# Assignment statements made when no words are left affect the shell's +# environment +a=5 b=6 $CHMOD c=7 $MODE d=8 $FN e=9 + +expect "5 6 7 8 9" +echo $a $b $c $d $e + +$CHMOD f=7 $MODE g=8 $FN h=9 +expect "7 8 9" +echo $f $g $h + +set +k + +# The temporary environment does not affect variable expansion, only the +# environment given to the command + +export HOME=/usr/chet +expect $HOME +echo $HOME + +expect $HOME +HOME=/a/b/c /bin/echo $HOME + +expect $HOME +echo $HOME + +# This should echo /a/b/c +expect /a/b/c +HOME=/a/b/c printenv HOME + +set -k + +# This should echo $HOME 9, NOT /a/b/c 9 + +expect "$HOME" +HOME=/a/b/c /bin/echo $HOME c=9 +expect "$HOME 7" +echo $HOME $c + +# I claim the next two echo calls should give identical output. +# ksh agrees, the System V.3 sh does not + +expect "/a/b/c 9 /a/b/c" +HOME=/a/b/c $ECHO a=$HOME c=9 +echo $HOME $c $a + +expect "/a/b/c 9 /a/b/c" +HOME=/a/b/c a=$HOME c=9 +echo $HOME $c $a +set +k + +# How do assignment statements affect subsequent assignments on the same +# line? +expect "/a/b/c /a/b/c" +HOME=/a/b/c a=$HOME +echo $HOME $a + +# The system V.3 sh does this wrong; the last echo should output "1 1", +# but the system V.3 sh has it output "2 2". Posix.2 says the assignment +# statements are processed left-to-right. bash and ksh output the right +# thing +c=1 +d=2 +expect "1 2" +echo $c $d +d=$c c=$d +expect "1 1" +echo $c $d + +# just for completeness +unset d c +expect unset +echo ${d-unset} + +# no output +export a +a=bcde +export a +/bin/true 2>/dev/null + +func() +{ + local YYZ + + YYZ="song by rush" + echo $YYZ + echo $A +} + +YYZ="toronto airport" +A="AVAR" +echo $YYZ +echo $A +A=BVAR func +echo $YYZ +echo $A + +export A +# Make sure expansion doesn't use assignment statements preceding a builtin +A=ZVAR echo $A + +XPATH=/bin:/usr/bin:/usr/local/bin:. +func2() +{ + local z=yy + local -a avar=( ${XPATH//: } ) + echo ${avar[@]} + local +} + +avar=42 +echo $avar +func2 +echo $avar + +# try to set an attribute for an unset variable; make sure it persists +# when the variable is assigned a value +declare -i ivar + +ivar=10 + +declare -p ivar +unset ivar + +# export an unset variable, make sure it is not suddenly set, but make +# sure the export attribute persists when the variable is assigned a +# value +export ivar +echo ${ivar-unset} + +ivar=42 +declare -p ivar + +# make sure set [-+]o ignoreeof and $IGNOREEOF are reflected +unset IGNOREEOF +set +o ignoreeof +set -o ignoreeof +if [ "$IGNOREEOF" -ne 10 ]; then + echo "./varenv.sh: set -o ignoreeof is not reflected in IGNOREEOF" >&2 +fi +unset IGNOREEOF +set +o ignoreeof + +# older versions of bash used to not reset RANDOM in subshells correctly +[[ $RANDOM -eq $(echo $RANDOM) ]] && echo "RANDOM: problem with subshells" + +# make sure that shopt -o is reflected in $SHELLOPTS +# first, get rid of things that might be set automatically via shell +# variables +set +o posix +set +o ignoreeof +set +o monitor +echo $- +echo ${SHELLOPTS} +shopt -so physical +echo $- +echo ${SHELLOPTS} + +# and make sure it is readonly +readonly -p | grep SHELLOPTS + +# This was an error in bash versions prior to bash-2.04. The `set -a' +# should cause the assignment statement that's an argument to typeset +# to create an exported variable +unset FOOFOO +FOOFOO=bar +set -a +typeset FOOFOO=abcde + +printenv FOOFOO + +# test out export behavior of variable assignments preceding builtins and +# functions +$THIS_SH ./varenv1.sub + +# more tests; bugs in bash up to version 2.05a +$THIS_SH ./varenv2.sub + +# more tests; bugs in bash IFS scoping up through version 4.2 +$THIS_SH ./varenv3.sub + +# scoping problems with declare -g through bash-4.2 +${THIS_SH} ./varenv4.sub + +# more scoping and declaration problems with -g and arrays through bash-4.2 +${THIS_SH} ./varenv5.sub + +# variable scoping in the presence of nameref +${THIS_SH} ./varenv6.sub + +# variable declaration problems with arrays and readonly local variables +${THIS_SH} ./varenv7.sub + +# variable visibility problems with process substitution subshells in +# redirections +${THIS_SH} ./varenv8.sub + +# make sure that builtins like readonly and export modify local array variables +# if executed in shell functions, like they modify local scalar variables +${THIS_SH} ./varenv9.sub + +# more tests of unset and local variables with dynamic scoping +${THIS_SH} ./varenv10.sub + +# tests of compound assignments in function scope +${THIS_SH} ./varenv11.sub + +# temporary environment variable propagation and scoping in posix mode +${THIS_SH} ./varenv12.sub + +# temporary environment and invalid shell indentifier names +${THIS_SH} ./varenv13.sub + +# localvar_inherit +${THIS_SH} ./varenv14.sub + +# make sure variable scoping is done right +tt() { typeset a=b;echo a=$a; };a=z;echo a=$a;tt;echo a=$a diff --git a/tests/varenv14.sub b/tests/varenv14.sub new file mode 100644 index 00000000..52b20d81 --- /dev/null +++ b/tests/varenv14.sub @@ -0,0 +1,33 @@ +# testing framework for local variable inheritence + +shopt -s localvar_inherit +declare -A var + +f() { declare var+=([0]=X); declare -p var; } +f + +f() { declare var=([Y]=Y); declare -p var; }; f +f() { declare var+=([Y]=Y); declare -p var; }; f +f() { declare var+=(); declare -p var; }; f +f() { declare var=(); declare -p var; }; f + +unset -f f +unset -v var + +declare -a var=( [0]=12 ) +f() { declare -A var+=([0]=X); declare -p var; } +f + +unset -f f +unset a s + +a=(X) s=X + +f() { local -a a s; declare -p a s; } +f + +f() { local a+=(Y) s+=(Y); declare -p a s; } +f + +f() { local -a a+=Y s+=Y; declare -p a s; } +f diff --git a/variables.c b/variables.c index cf6822d9..8336d073 100644 --- a/variables.c +++ b/variables.c @@ -2282,7 +2282,13 @@ nameref_transform_name (name, flags) v = 0; if (flags & ASS_MKLOCAL) - v = find_variable_last_nameref (name, 1); + { + v = find_variable_last_nameref (name, 1); + /* If we're making local variables, only follow namerefs that point to + non-existant variables at the same variable context. */ + if (v && v->context != variable_context) + v = 0; + } else if (flags & ASS_MKGLOBAL) v = (flags & ASS_CHKLOCAL) ? find_variable_last_nameref (name, 1) : find_global_variable_last_nameref (name, 1); @@ -2781,11 +2787,23 @@ make_local_array_variable (name, assoc_ok) /* Validate any value we inherited from a variable instance at a previous scope and disard anything that's invalid. */ + if (localvar_inherit && assoc_p (var)) + { + internal_warning ("%s: cannot inherit value from incompatible type", name); + VUNSETATTR (var, att_assoc); + dispose_variable_value (var); + array = array_create (); + var_setarray (var, array); + } + else if (localvar_inherit) + var = convert_var_to_array (var); /* XXX */ + else + { + dispose_variable_value (var); + array = array_create (); + var_setarray (var, array); + } - array = array_create (); - - dispose_variable_value (var); - var_setarray (var, array); VSETATTR (var, att_array); return var; } @@ -2822,11 +2840,23 @@ make_local_assoc_variable (name, array_ok) /* Validate any value we inherited from a variable instance at a previous scope and disard anything that's invalid. */ + if (localvar_inherit && array_p (var)) + { + internal_warning ("%s: cannot inherit value from incompatible type", name); + VUNSETATTR (var, att_array); + dispose_variable_value (var); + hash = assoc_create (0); + var_setassoc (var, hash); + } + else if (localvar_inherit) + var = convert_var_to_assoc (var); /* XXX */ + else + { + dispose_variable_value (var); + hash = assoc_create (0); + var_setassoc (var, hash); + } - dispose_variable_value (var); - hash = assoc_create (0); - - var_setassoc (var, hash); VSETATTR (var, att_assoc); return var; }