diff --git a/CWRU/CWRU.chlog b/CWRU/CWRU.chlog index ff2c589b..571cc9f3 100644 --- a/CWRU/CWRU.chlog +++ b/CWRU/CWRU.chlog @@ -10247,3 +10247,68 @@ builtins/shopt.def builtins/common.h - expand_once_flag: extern declaration + + 5/10 + ---- +doc/{bash.1,bashref.texi} + - note that case patterns undergo quote removal. Reported by + AlvinSeville7cf + + 5/11 + ---- + +builtins/bashgetopt.c + - list_optflags: flags associated with the word corresponding to + list_optarg, assuming list_optarg is a separate argument + +builtins/bashgetopt.h + - list_optflags: extern declaration + +builtins/set.def + - unset_builtin: set VFLAGS each time through the loop, since we take + whether or not the word has W_ARRAYREF set into account + - unset_builtin: don't pass VA_ALLOWALL to unbind_array_element for + now + +test.c + - unary_test: in the -v case, use assoc_expand_once in the first call + to valid_array_reference () + +builtins/printf.def + - printf_builtin: only set VA_ONEWORD if the option argument to -v has + W_ARRAYREF set (look at list_optflags) + + 5/12 + ---- + +subst.c + - expand_array_subscript: don't quote @ or * in the expanded subscript + at all, even when they are the only character in the subscript. See + how this works out -- it might uncover places where we need to allow + `*' and `@' as subscripts where they are not allowed now + +expr.c + - expr_bind_variable: pass ASS_ALLOWALLSUB to bind_int_variable so we + can allow (( A[@]=value )) when A is an existing associative array + +arrayfunc.h + - AV_ATSTARKEYS: new flag value, means to accept a[@] and a[*] but + treat them as keys/expressions and not special values + +arrayfunc.c + - array_value_internal: check AV_ATSTARKEYS and don't treat them as + ALL_ELEMENT_SUB values; they fall through to use as keys/indices + +test.c + - unary_test: if -v is passed an array reference, add AV_ATSTARKEYS to + the flags passed to array_value so we treat @ and * as keys for an + existing associative array + + 5/13 + ---- + +subst.c + - expand_cond_word: if SPECIAL == 3 (arithmetic expression), dequote the + resulting WORD_LIST * as if special == 0, because we don't want to + quote the list for pattern matching. Report from + Adjudicator Darren diff --git a/MANIFEST b/MANIFEST index 2f22d30b..f8b63bbe 100644 --- a/MANIFEST +++ b/MANIFEST @@ -1313,6 +1313,7 @@ tests/quotearray.tests f tests/quotearray1.sub f tests/quotearray2.sub f tests/quotearray3.sub f +tests/quotearray4.sub f tests/read.tests f tests/read.right f tests/read1.sub f diff --git a/arrayfunc.c b/arrayfunc.c index c37788d6..5a826ce1 100644 --- a/arrayfunc.c +++ b/arrayfunc.c @@ -1370,7 +1370,7 @@ array_value_internal (s, quoted, flags, rtype, indp) int quoted, flags, *rtype; arrayind_t *indp; { - int len; + int len, isassoc; arrayind_t ind; char *akey; char *retval, *t, *temp; @@ -1389,9 +1389,12 @@ array_value_internal (s, quoted, flags, rtype, indp) if (len == 0) return ((char *)NULL); /* error message already printed */ + isassoc = var && assoc_p (var); /* [ */ akey = 0; - if (ALL_ELEMENT_SUB (t[0]) && t[1] == ']') + /* Backwards compatibility: we only change the behavior of A[@] and A[*] + for associative arrays, and the caller has to request it. */ + if ((isassoc == 0 || (flags & AV_ATSTARKEYS) == 0) && ALL_ELEMENT_SUB (t[0]) && t[1] == ']') { if (rtype) *rtype = (t[0] == '*') ? 1 : 2; diff --git a/arrayfunc.h b/arrayfunc.h index 981fdcad..31d91cc8 100644 --- a/arrayfunc.h +++ b/arrayfunc.h @@ -33,12 +33,14 @@ extern int assoc_expand_once; extern int array_expand_once; /* Flags for array_value_internal and callers array_value/get_array_value */ -#define AV_ALLOWALL 0x001 +#define AV_ALLOWALL 0x001 /* treat a[@] like $@ and a[*] like $* */ #define AV_QUOTED 0x002 #define AV_USEIND 0x004 #define AV_USEVAL 0x008 /* XXX - should move this */ #define AV_ASSIGNRHS 0x010 /* no splitting, special case ${a[@]} */ #define AV_NOEXPAND 0x020 /* don't run assoc subscripts through word expansion */ +#define AV_ONEWORD 0x040 /* not used yet */ +#define AV_ATSTARKEYS 0x080 /* accept a[@] and a[*] but use them as keys, not special values */ /* Flags for valid_array_reference. Value 1 is reserved for skipsubscript(). Also used by unbind_array_element, which is currently the only function @@ -94,7 +96,11 @@ extern SHELL_VAR *array_variable_part PARAMS((const char *, int, char **, int *) #define AV_ALLOWALL 0 #define AV_QUOTED 0 #define AV_USEIND 0 +#define AV_USEVAL 0 #define AV_ASSIGNRHS 0 +#define AV_NOEXPAND 0 +#define AV_ONEWORD 0 +#define AV_ATSTARKEYS 0 #define VA_NOEXPAND 0 #define VA_ONEWORD 0 diff --git a/builtins/bashgetopt.c b/builtins/bashgetopt.c index 405ced43..43f18806 100644 --- a/builtins/bashgetopt.c +++ b/builtins/bashgetopt.c @@ -39,6 +39,7 @@ static int sp; char *list_optarg; +int list_optflags; int list_optopt; int list_opttype; @@ -62,6 +63,7 @@ char *opts; if (list == 0) { list_optarg = (char *)NULL; + list_optflags = 0; loptend = (WORD_LIST *)NULL; /* No non-option arguments */ return -1; } @@ -102,6 +104,7 @@ char *opts; sp = 1; } list_optarg = NULL; + list_optflags = 0; if (lcurrent) loptend = lcurrent->next; return('?'); @@ -113,6 +116,7 @@ char *opts; /* We allow -l2 as equivalent to -l 2 */ if (lcurrent->word->word[sp+1]) { list_optarg = lcurrent->word->word + sp + 1; + list_optflags = 0; lcurrent = lcurrent->next; /* If the specifier is `;', don't set optarg if the next argument looks like another option. */ @@ -123,15 +127,18 @@ char *opts; #endif lcurrent = lcurrent->next; list_optarg = lcurrent->word->word; + list_optflags = lcurrent->word->flags; lcurrent = lcurrent->next; } else if (*cp == ';') { list_optarg = (char *)NULL; + list_optflags = 0; lcurrent = lcurrent->next; } else { /* lcurrent->next == NULL */ errstr[1] = c; sh_needarg (errstr); sp = 1; list_optarg = (char *)NULL; + list_optflags = 0; return('?'); } sp = 1; @@ -140,19 +147,24 @@ char *opts; if (lcurrent->word->word[sp+1]) { if (DIGIT(lcurrent->word->word[sp+1])) { list_optarg = lcurrent->word->word + sp + 1; + list_optflags = 0; lcurrent = lcurrent->next; - } else + } else { list_optarg = (char *)NULL; + list_optflags = 0; + } } else { if (lcurrent->next && legal_number(lcurrent->next->word->word, (intmax_t *)0)) { lcurrent = lcurrent->next; list_optarg = lcurrent->word->word; + list_optflags = lcurrent->word->flags; lcurrent = lcurrent->next; } else { errstr[1] = c; sh_neednumarg (errstr); sp = 1; list_optarg = (char *)NULL; + list_optflags = 0; return ('?'); } } @@ -164,6 +176,7 @@ char *opts; lcurrent = lcurrent->next; } list_optarg = (char *)NULL; + list_optflags = 0; } return(c); diff --git a/builtins/bashgetopt.h b/builtins/bashgetopt.h index dcdaa48a..875bc612 100644 --- a/builtins/bashgetopt.h +++ b/builtins/bashgetopt.h @@ -29,6 +29,7 @@ #define GETOPT_HELP -99 extern char *list_optarg; +extern int list_optflags; extern int list_optopt; extern int list_opttype; diff --git a/builtins/common.c b/builtins/common.c index ae62964a..dc7b8d9c 100644 --- a/builtins/common.c +++ b/builtins/common.c @@ -980,6 +980,11 @@ builtin_bind_variable (name, value, flags) SHELL_VAR *v; #if defined (ARRAY_VARS) + /* Callers are responsible for calling this with array references that have + already undergone valid_array_reference checks. + Affected builtins: read, printf + To make this really work, needs additional downstream support, starting + with assign_array_element and array_variable_name. */ if (valid_array_reference (name, assoc_expand_once ? (VA_NOEXPAND|VA_ONEWORD) : 0) == 0) v = bind_variable (name, value, flags); else diff --git a/builtins/printf.def b/builtins/printf.def index 9343b367..a10fb979 100644 --- a/builtins/printf.def +++ b/builtins/printf.def @@ -1,7 +1,7 @@ This file is printf.def, from which is created printf.c. It implements the builtin "printf" in Bash. -Copyright (C) 1997-2020 Free Software Foundation, Inc. +Copyright (C) 1997-2021 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. @@ -267,11 +267,14 @@ printf_builtin (list) case 'v': vname = list_optarg; #if defined (ARRAY_VARS) - arrayflags = assoc_expand_once ? (VA_NOEXPAND|VA_ONEWORD) : 0; - if (legal_identifier (vname) || valid_array_reference (vname, arrayflags)) + arrayflags = assoc_expand_once ? VA_NOEXPAND : 0; + if (assoc_expand_once && (list_optflags & W_ARRAYREF)) + arrayflags |= VA_ONEWORD; /* XXX - VA_NOEXPAND? */ + retval = legal_identifier (vname) || valid_array_reference (vname, arrayflags); #else - if (legal_identifier (vname)) + retval = legal_identifier (vname); #endif + if (retval) { vflag = 1; if (vbsize == 0) diff --git a/builtins/set.def b/builtins/set.def index 21ee84ea..8b68b98d 100644 --- a/builtins/set.def +++ b/builtins/set.def @@ -835,7 +835,7 @@ unset_builtin (list) WORD_LIST *list; { int unset_function, unset_variable, unset_array, opt, nameref, any_failed; - int global_unset_func, global_unset_var, vflags, valid_id; + int global_unset_func, global_unset_var, vflags, base_vflags, valid_id; char *name, *tname; unset_function = unset_variable = unset_array = nameref = any_failed = 0; @@ -872,9 +872,7 @@ unset_builtin (list) else if (unset_function && nameref) nameref = 0; -#if defined (ARRAY_VARS) - vflags = assoc_expand_once ? (VA_NOEXPAND|VA_ONEWORD) : 0; -#endif + base_vflags = assoc_expand_once ? VA_NOEXPAND : 0; while (list) { @@ -889,6 +887,16 @@ unset_builtin (list) unset_function = global_unset_func; unset_variable = global_unset_var; +#if defined (ARRAY_VARS) + vflags = base_vflags; + /* Don't require assoc_expand_once if we have an argument that's already + passed through valid_array_reference and been expanded once. That + doesn't protect it from normal expansions like word splitting, so + proper quoting is still required. */ + if (list->word->flags & W_ARRAYREF) + vflags |= VA_ONEWORD|VA_NOEXPAND; +#endif + #if defined (ARRAY_VARS) unset_array = 0; /* XXX valid array reference second arg was 0 */ @@ -959,15 +967,12 @@ unset_builtin (list) #if defined (ARRAY_VARS) if (var && unset_array) { - int tvflags; - - tvflags = vflags; #if 0 /* TAG:bash-5.2 */ if (shell_compatibility_level <= 51) - tvflags |= VA_ALLOWALL; + vflags |= VA_ALLOWALL; #endif /* Let unbind_array_element decide what to do with non-array vars */ - tem = unbind_array_element (var, t, tvflags); /* XXX new third arg */ + tem = unbind_array_element (var, t, vflags); /* XXX new third arg */ if (tem == -2 && array_p (var) == 0 && assoc_p (var) == 0) { builtin_error (_("%s: not an array variable"), var->name); diff --git a/doc/bash.1 b/doc/bash.1 index 41254999..82dfa1e6 100644 --- a/doc/bash.1 +++ b/doc/bash.1 @@ -5,12 +5,12 @@ .\" Case Western Reserve University .\" chet.ramey@case.edu .\" -.\" Last Change: Wed May 5 16:28:46 EDT 2021 +.\" Last Change: Mon May 10 10:12:31 EDT 2021 .\" .\" bash_builtins, strip all but Built-Ins section .if \n(zZ=1 .ig zZ .if \n(zY=1 .ig zY -.TH BASH 1 "2021 May 5" "GNU Bash 5.1" +.TH BASH 1 "2021 May 10" "GNU Bash 5.1" .\" .\" There's some problem with having a `@' .\" in a tagged paragraph with the BSD man macros. @@ -894,7 +894,7 @@ expansion, parameter and variable expansion, arithmetic expansion, command substitution, process substitution and quote removal. Each \fIpattern\fP examined is expanded using tilde expansion, parameter and variable expansion, arithmetic expansion, -command substitution, and process substitution. +command substitution, process substitution, and quote removal. If the .B nocasematch shell option is enabled, the match is performed without regard to the case diff --git a/doc/bashref.texi b/doc/bashref.texi index 77b9cb36..9cc8b1ae 100644 --- a/doc/bashref.texi +++ b/doc/bashref.texi @@ -1039,9 +1039,10 @@ Each clause must be terminated with @samp{;;}, @samp{;&}, or @samp{;;&}. The @var{word} undergoes tilde expansion, parameter expansion, command substitution, arithmetic expansion, and quote removal (@pxref{Shell Parameter Expansion}) -before matching is -attempted. Each @var{pattern} undergoes tilde expansion, parameter -expansion, command substitution, and arithmetic expansion. +before matching is attempted. +Each @var{pattern} undergoes tilde expansion, parameter expansion, +command substitution, arithmetic expansion, process substitution, and +quote removal. There may be an arbitrary number of @code{case} clauses, each terminated by a @samp{;;}, @samp{;&}, or @samp{;;&}. diff --git a/doc/version.texi b/doc/version.texi index f51259df..13969e8a 100644 --- a/doc/version.texi +++ b/doc/version.texi @@ -2,10 +2,10 @@ Copyright (C) 1988-2021 Free Software Foundation, Inc. @end ignore -@set LASTCHANGE Wed May 5 16:29:06 EDT 2021 +@set LASTCHANGE Mon May 10 10:12:46 EDT 2021 @set EDITION 5.1 @set VERSION 5.1 -@set UPDATED 5 May 2021 +@set UPDATED 10 May 2021 @set UPDATED-MONTH May 2021 diff --git a/examples/loadables/cat.c b/examples/loadables/cat.c index 36ffc7e2..0b082d33 100644 --- a/examples/loadables/cat.c +++ b/examples/loadables/cat.c @@ -54,6 +54,7 @@ char *fn; write(2, "\n", 1); return 1; } + QUIT; w = write(1, buf, n); if (w != n) { e = errno; @@ -63,6 +64,7 @@ char *fn; write(2, "\n", 1); return 1; } + QUIT; } return 0; } @@ -79,6 +81,7 @@ char **argv; return (fcopy(0, "standard input")); for (i = r = 1; i < argc; i++) { + QUIT; if (argv[i][0] == '-' && argv[i][1] == '\0') fd = 0; else { @@ -97,6 +100,7 @@ char **argv; if (fd != 0) close(fd); } + QUIT; return (r); } @@ -108,6 +112,7 @@ WORD_LIST *list; int c, r; v = make_builtin_argv(list, &c); + QUIT; r = cat_main(c, v); free(v); diff --git a/examples/loadables/cut.c b/examples/loadables/cut.c index ad9a8335..ed4972d2 100644 --- a/examples/loadables/cut.c +++ b/examples/loadables/cut.c @@ -415,10 +415,14 @@ cutfile (v, list, ops) #endif while ((n = zgetline (fd, &line, &llen, '\n', unbuffered_read)) != -1) + { + QUIT; cutline (v, line, ops); /* can modify line */ + } if (fd > 0) close (fd); + QUIT; if (l) l = l->next; } diff --git a/examples/loadables/head.c b/examples/loadables/head.c index 1edca6c5..f9f022a6 100644 --- a/examples/loadables/head.c +++ b/examples/loadables/head.c @@ -79,11 +79,13 @@ file_head (fp, cnt) { while ((ch = getc (fp)) != EOF) { + QUIT; if (putchar (ch) == EOF) { builtin_error ("write error: %s", strerror (errno)); return EXECUTION_FAILURE; } + QUIT; if (ch == '\n') break; } @@ -141,6 +143,7 @@ head_builtin (list) printf ("%s==> %s <==\n", opt ? "" : "\n", l->word->word); opt = 0; } + QUIT; rval = file_head (fp, nline); fclose (fp); } diff --git a/examples/loadables/rm.c b/examples/loadables/rm.c index 0af5493c..d8d1522b 100644 --- a/examples/loadables/rm.c +++ b/examples/loadables/rm.c @@ -59,7 +59,8 @@ _remove_directory(const char *dirname) char *fname; int fnsize; #endif - + + QUIT; if (*dp->d_name == '.' && (dp->d_name[1] == 0 || (dp->d_name[1] == '.' && dp->d_name[2] == 0))) continue; @@ -76,6 +77,7 @@ _remove_directory(const char *dirname) #ifndef __GNUC__ free (fname); #endif + QUIT; } closedir(dir); @@ -98,6 +100,7 @@ rm_file(const char *fname) if (unlink (fname) == 0) return 0; + QUIT; /* If FNAME is a directory glibc returns EISDIR but correct POSIX value would be EPERM. If we get that error and FNAME is a directory and -r was supplied, recursively remove the directory and its contents */ @@ -155,6 +158,7 @@ rm_builtin (list) for (l = list; l; l = l->next) { + QUIT; if (rm_file(l->word->word) && force == 0) rval = EXECUTION_FAILURE; } diff --git a/examples/loadables/tee.c b/examples/loadables/tee.c index 283f23f1..0365aa9a 100644 --- a/examples/loadables/tee.c +++ b/examples/loadables/tee.c @@ -3,7 +3,7 @@ /* See Makefile for compilation details. */ /* - Copyright (C) 1999-2009 Free Software Foundation, Inc. + Copyright (C) 1999-2021 Free Software Foundation, Inc. This file is part of GNU Bash. Bash is free software: you can redistribute it and/or modify @@ -121,6 +121,7 @@ tee_builtin (list) fl = fl->next; fl->next = (FLIST *)NULL; } + QUIT; } while ((nr = read(0, buf, TEE_BUFSIZE)) > 0) @@ -137,6 +138,7 @@ tee_builtin (list) break; } bp += nw; + QUIT; } while (n -= nw); } @@ -156,7 +158,8 @@ tee_builtin (list) tee_flist = tee_flist->next; free (fl); } - + + QUIT; return (rval); } diff --git a/examples/loadables/tty.c b/examples/loadables/tty.c index febf518b..381df257 100644 --- a/examples/loadables/tty.c +++ b/examples/loadables/tty.c @@ -3,7 +3,7 @@ /* See Makefile for compilation details. */ /* - Copyright (C) 1999-2009 Free Software Foundation, Inc. + Copyright (C) 1999-2021 Free Software Foundation, Inc. This file is part of GNU Bash. Bash is free software: you can redistribute it and/or modify @@ -55,6 +55,7 @@ tty_builtin (list) list = loptend; t = ttyname (0); + QUIT; if (sflag == 0) puts (t ? t : "not a tty"); return (t ? EXECUTION_SUCCESS : EXECUTION_FAILURE); diff --git a/expr.c b/expr.c index bbff95e9..56c72fd6 100644 --- a/expr.c +++ b/expr.c @@ -330,6 +330,7 @@ expr_bind_variable (lhs, rhs) #if defined (ARRAY_VARS) aflags = (assoc_expand_once && already_expanded) ? ASS_NOEXPAND : 0; + aflags |= ASS_ALLOWALLSUB; /* allow assoc[@]=value */ #else aflags = 0; #endif diff --git a/po/zh_TW.gmo b/po/zh_TW.gmo index 75d5bc10..c9e58a04 100644 Binary files a/po/zh_TW.gmo and b/po/zh_TW.gmo differ diff --git a/po/zh_TW.po b/po/zh_TW.po index 665d53e0..01d18837 100644 --- a/po/zh_TW.po +++ b/po/zh_TW.po @@ -5,13 +5,13 @@ # Zi-You Dai , 2008. # Mingye Wang (Arthur2e5) , 2015. # Wei-Lun Chao , 2015. -# Yi-Jyun Pan , 2018, 2019, 2020. +# Yi-Jyun Pan , 2018, 2019, 2020, 2021. msgid "" msgstr "" "Project-Id-Version: bash 5.1\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2020-11-28 12:51-0500\n" -"PO-Revision-Date: 2020-12-08 06:39+0800\n" +"PO-Revision-Date: 2021-05-09 20:48+0800\n" "Last-Translator: Yi-Jyun Pan \n" "Language-Team: Chinese (traditional) \n" "Language: zh_TW\n" @@ -20,7 +20,7 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Bugs: Report translation errors to the Language-Team address.\n" "Plural-Forms: nplurals=1; plural=0;\n" -"X-Generator: Poedit 2.4.2\n" +"X-Generator: Poedit 2.4.3\n" #: arrayfunc.c:66 msgid "bad array subscript" @@ -144,7 +144,6 @@ msgid "only meaningful in a `for', `while', or `until' loop" msgstr "僅在「for」,「while」, 或者「until」迴圈中有意義" #: builtins/caller.def:136 -#, fuzzy msgid "" "Returns the context of the current subroutine call.\n" " \n" @@ -158,15 +157,11 @@ msgstr "" "回傳目前子呼叫的語境。\n" " \n" " 不帶有 EXPR 時,回傳「$line $filename」。帶有 EXPR 時,回傳\n" -" 「$line $subroutine $filename」;這個額外的資訊可以被用於提供\n" -" 堆疊追蹤。\n" +" 「$line $subroutine $filename」;提供堆疊追蹤時可以用到這個\n" +" 延伸資訊。\n" " \n" " EXPR 的值顯示了到目前呼叫框格需要回去多少個呼叫框格;頂部框格\n" -" 是第 0 框格。\n" -" \n" -" 結束狀態:\n" -" 除非 shell 不在執行一個 shell 函數或者 EXPR 無效,否則回傳結\n" -" 果為 0。" +" 是第 0 框格。" #: builtins/cd.def:327 msgid "HOME not set" diff --git a/subst.c b/subst.c index d0a157a2..579de3f6 100644 --- a/subst.c +++ b/subst.c @@ -3696,6 +3696,13 @@ cond_expand_word (w, special) dequote_list (l); r = string_list (l); } + else if (special == 3) /* arithmetic expression, Q_ARITH */ + { + if (l->word) + word_list_remove_quoted_nulls (l); /* for now */ + dequote_list (l); + r = string_list (l); + } else { /* Need to figure out whether or not we should call dequote_escapes @@ -10192,6 +10199,7 @@ expand_array_subscript (string, sindex, quoted, flags) abstab[LBRACK] = abstab[RBRACK] = 1; abstab['$'] = abstab['`'] = abstab['~'] = 1; abstab['\\'] = abstab['\''] = 1; + /* We don't quote `@' or `*' in the subscript at all. */ } /* string[si] == LBRACK */ @@ -10215,11 +10223,6 @@ itrace("expand_array_subscript: bad subscript string: `%s'", string+si); exp = substring (string, si+1, ni); t = expand_subscript_string (exp, quoted & ~(Q_ARITH|Q_DOUBLE_QUOTES)); free (exp); - /* Only quote `@' and `*' if they are the only character in the subscript */ - if (ALL_ELEMENT_SUB (t[0]) && t[1] == '\0') - abstab['*'] = abstab['@'] = 1; - else - abstab['*'] = abstab['@'] = 0; exp = sh_backslash_quote (t, abstab, 0); free (t); diff --git a/test.c b/test.c index ac80e6b6..fdd46c4f 100644 --- a/test.c +++ b/test.c @@ -632,16 +632,22 @@ unary_test (op, arg, flags) case 'v': #if defined (ARRAY_VARS) - if (valid_array_reference (arg, 0)) + if (valid_array_reference (arg, assoc_expand_once ? VA_NOEXPAND : 0)) { char *t; - int rtype, ret, flags; + int rtype, ret, aflags; /* Let's assume that this has already been expanded once. */ /* XXX - TAG:bash-5.2 fix with corresponding fix to execute_cmd.c: execute_cond_node() that passes TEST_ARRAYEXP in FLAGS */ - flags = assoc_expand_once ? AV_NOEXPAND : 0; - t = array_value (arg, 0, flags, &rtype, (arrayind_t *)0); + + aflags = assoc_expand_once ? AV_NOEXPAND : 0; +#if 0 + /* TAG:bash-5.2 */ + if (shell_compatibility_level > 51) +#endif + aflags |= AV_ATSTARKEYS; + t = array_value (arg, 0, aflags, &rtype, (arrayind_t *)0); ret = t ? TRUE : FALSE; if (rtype > 0) /* subscript is * or @ */ free (t); diff --git a/tests/array.right b/tests/array.right index 964b2c81..c2c9a718 100644 --- a/tests/array.right +++ b/tests/array.right @@ -747,7 +747,7 @@ declare -A A=([$'\t']="2" ["*"]="2" [" "]="2" ["]"]="2" ["@"]="2" ) declare -A A=([$'\t']="2" ["*"]="2" [" "]="2" ["]"]="2" ["@"]="2" ) ./array27.sub: line 52: A[]]: bad array subscript declare -A A=([$'\t']="X" ["*"]="X" [" "]="X" ["@"]="X" ) -./array27.sub: line 60: A[]]: bad array subscript +./array27.sub: line 60: printf: `A[]]': not a valid identifier declare -A A=([$'\t']="X" ["*"]="X" [" "]="X" ["@"]="X" ) ./array27.sub: line 68: declare: `A[]]=X': not a valid identifier declare -A A=(["*"]="X" ["@"]="X" ) diff --git a/tests/assoc.right b/tests/assoc.right index 58d84550..b8325685 100644 --- a/tests/assoc.right +++ b/tests/assoc.right @@ -199,11 +199,7 @@ declare -A hash=([key]="value1 value2" ) declare -A b=([")"]="" ["\""]="" ["]"]="" ["\\"]="" ["\`"]="" ) declare -A b=(["]"]="" ["\`"]="" ) declare -A dict=(["'"]="3" ["\""]="1" ["\\"]="4" ["\`"]="2" ) -./assoc9.sub: line 36: unset: `dict[']': not a valid identifier -./assoc9.sub: line 36: unset: `dict["]': not a valid identifier -./assoc9.sub: line 36: unset: `dict[\]': not a valid identifier -./assoc9.sub: line 36: unset: `dict[`]': not a valid identifier -declare -A dict=(["'"]="3" ["\""]="1" ["\\"]="4" ["\`"]="2" ) +declare -A dict=() declare -A dict=(["'"]="3" ["\""]="1" ["\\"]="4" ["\`"]="2" ) declare -A dict=() 4 diff --git a/tests/builtins.right b/tests/builtins.right index ae2cf3ef..4f51d436 100644 --- a/tests/builtins.right +++ b/tests/builtins.right @@ -179,10 +179,16 @@ unset2 1 1 1 +0 +0 +assoc A unset +array a assoc A array a assoc B unset array b unset +assoc B unset +array b unset scalar 1 scalar 2 scalar 3 unset diff --git a/tests/builtins5.sub b/tests/builtins5.sub index d36e03a5..4fcf793d 100644 --- a/tests/builtins5.sub +++ b/tests/builtins5.sub @@ -36,15 +36,25 @@ echo ${#a[@]} typeset -A B typeset -a b +echo ${#B[@]} +echo ${#b[@]} + scalar1=foo scalar2= +# this now checks for A[@] treating @ as a valid key - post-bash-5.1 if [ -v A[@] ]; then echo assoc A; else echo assoc A unset; fi if [ -v a[@] ]; then echo array a; else echo array a unset; fi +if [ ${#A[@]} -gt 0 ]; then echo assoc A; else echo assoc A unset; fi +if [ ${#a[@]} -gt 0 ]; then echo array a; else echo array a unset; fi + if [ -v B[@] ]; then echo assoc B; else echo assoc B unset; fi if [ -v b[@] ]; then echo array b; else echo array b unset; fi +if [ ${#B[@]} -gt 0 ]; then echo assoc B; else echo assoc B unset; fi +if [ ${#b[@]} -gt 0 ]; then echo array b; else echo array b unset; fi + if [ -v scalar1[@] ]; then echo scalar 1; else echo scalar 1 unset; fi if [ -v scalar2[@] ]; then echo scalar 2; else echo scalar 2 unset; fi if [ -v scalar3[@] ]; then echo scalar 3; else echo scalar 3 unset; fi @@ -71,4 +81,3 @@ echo scalar: ${#scalar3} echo scalar: ${#scalar3[@]} - diff --git a/tests/cond.right b/tests/cond.right index 59a4a886..67199e8c 100644 --- a/tests/cond.right +++ b/tests/cond.right @@ -27,6 +27,8 @@ returns: 0 returns: 1 returns: 0 returns: 0 +returns: 0 +returns: 0 returns: 1 returns: 0 returns: 0 diff --git a/tests/cond.tests b/tests/cond.tests index 17e0b50f..234d4b59 100644 --- a/tests/cond.tests +++ b/tests/cond.tests @@ -122,6 +122,13 @@ A=7 [[ $IVAR -eq A ]] echo returns: $? +[[ "$IVAR" -eq "7" ]] +echo returns: $? + +A=7 +[[ "$IVAR" -eq "A" ]] +echo returns: $? + unset IVAR A # more pattern matching tests diff --git a/tests/quotearray.right b/tests/quotearray.right index ed1914cb..c106f7a7 100644 --- a/tests/quotearray.right +++ b/tests/quotearray.right @@ -44,7 +44,7 @@ declare -A assoc=(["\` echo >&2 foo\`"]="128" [0]="0" ["]"]="12" ["x],b[\$(echo foo 0 0 -./quotearray1.sub: line 67: 0\],b\[1: syntax error: invalid arithmetic operator (error token is "\],b\[1") +./quotearray1.sub: line 68: 0\],b\[1: syntax error: invalid arithmetic operator (error token is "\],b\[1") declare -a array 0 0 @@ -56,6 +56,9 @@ declare -A aa=(["\$( echo 2>& date)"]="foo" ) foo 0 1 +1 +./quotearray1.sub: line 111: test: aa[$(echo: binary operator expected +2 declare -A a=([1]="1" [0]="0" [" "]="11" ) 7 7 @@ -71,6 +74,8 @@ declare -A A=(["*"]="X" ["@"]="X" ) declare -A A=(["*"]="X" ["@"]="X" ) ./quotearray2.sub: line 89: let: assoc[x],b[$(echo: bad array subscript (error token is "b[$(echo") declare -A assoc +declare -A assoc=(["\$(echo foo)"]="1" ) +0 declare -A assoc=(["\$var"]="value" ) declare -A assoc=(["\$var"]="value" ) declare -A assoc=(["\$var"]="value" ) @@ -80,5 +85,37 @@ declare -A a=(["\$(echo foo)"]="1" ) declare -A a=() declare -A a=(["\$(echo foo)"]="1" ) declare -A assoc=(["!"]="bang" ) +1 +1 +declare -A assoc=(["!"]="bang" ["@"]="at" ) +declare -A assoc=(["!"]="bang" ) +declare -a array=([0]="1" [1]="2" [2]="3") +./quotearray3.sub: line 93: declare: array: not found +./quotearray3.sub: line 97: declare: array: not found +declare -A assoc=(["*"]="star" ["!"]="bang" ["@"]="at" ) +declare -A assoc=(["*"]="star" ["!"]="bang" ) +declare -A assoc=(["!"]="bang" ) +./quotearray4.sub: line 41: declare: assoc: not found +declare -A assoc=(["*"]="star" ["!"]="bang" ["@"]="at" ) +declare -A assoc=(["*"]="star" ["!"]="bang" ) +declare -A assoc=(["!"]="bang" ) +declare -A assoc=(["*"]="star" ["!"]="bang" ) +declare -A assoc=(["!"]="bang" ) +star bang at +star bang at +0 +0 0 1 +1 +declare -A assoc=(["*"]="star" ["!"]="bang" ["@"]=" key" ) +=== +1 +1 +declare -a array=([0]="1" [1]="2" [2]="3") +1 2 3 +1 2 3 +0 +0 +./quotearray4.sub: line 115: array[@]: bad array subscript +declare -a array=([0]="1" [1]="2" [2]="3") diff --git a/tests/quotearray.tests b/tests/quotearray.tests index 9d49353b..83e50ad8 100644 --- a/tests/quotearray.tests +++ b/tests/quotearray.tests @@ -155,3 +155,6 @@ echo $? ${THIS_SH} ./quotearray1.sub ${THIS_SH} ./quotearray2.sub ${THIS_SH} ./quotearray3.sub + +# behavior of builtins with array subscripts @ and * +${THIS_SH} ./quotearray4.sub diff --git a/tests/quotearray1.sub b/tests/quotearray1.sub index 67607eb8..cda30770 100644 --- a/tests/quotearray1.sub +++ b/tests/quotearray1.sub @@ -23,6 +23,7 @@ key2='` echo >&2 foo`' key3='~' key4='7<(4+2)' key5='$( echo 2>& date)' +key6='$(echo foo)' [[ -n assoc[$key] ]] declare -p assoc @@ -102,4 +103,12 @@ echo $? [[ -v aa[$key] ]] echo $? +aa[$key6]=42 +# this still performs expansion +test -v aa["$key6"] +echo $? +# should be an error +test -v aa[$key6] +echo $? + unset aa key diff --git a/tests/quotearray2.sub b/tests/quotearray2.sub index b3dd5e13..d7ae8176 100644 --- a/tests/quotearray2.sub +++ b/tests/quotearray2.sub @@ -90,3 +90,14 @@ let assoc[$key]++ declare -p assoc unset assoc + +typeset -A assoc +at=@ + +key='$(echo foo)' + +assoc[$key]=1 +declare -p assoc + +shopt -s assoc_expand_once +test -v assoc["$key"] ; echo $? diff --git a/tests/quotearray3.sub b/tests/quotearray3.sub index 228e8669..43487630 100644 --- a/tests/quotearray3.sub +++ b/tests/quotearray3.sub @@ -66,11 +66,32 @@ assoc[!]=bang unset -v assoc[$key] typeset -p assoc -# this doesn't work yet +# this should check for assoc[@] and return 1 test -v assoc[$key] echo $? +# this should too [[ -v assoc[$key] ]] echo $? -unset assoc +unset assoc array + +declare -A assoc +declare -a array + +assoc=([@]=at [!]=bang) +declare -p assoc + +unset assoc[@] +declare -p assoc + +array=(1 2 3) +declare -p array + +# right now, this still unsets the entire array +unset array[@] +declare -p array + +BASH_COMPAT=51 +unset array[@] +declare -p array diff --git a/tests/quotearray4.sub b/tests/quotearray4.sub new file mode 100644 index 00000000..964aac75 --- /dev/null +++ b/tests/quotearray4.sub @@ -0,0 +1,116 @@ +# This program 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. +# +# This program 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 this program. If not, see . +# + +# tests for builtins handling associative array keys `*' and `@', with some +# indexed array tests as well (backwards compatible) + +# derived from test cases posted to bug-bash by myoga.murase@gmail.com + +declare -A assoc +declare -a array + +assoc[@]=at +assoc[*]=star +assoc[!]=bang + +key=@ + +iref='array[@]' +aref='assoc[@]' + +declare -p assoc + +unset assoc[@] +declare -p assoc + +unset assoc[*] +declare -p assoc + +unset assoc +declare -p assoc + +declare -A assoc +assoc[@]=at +assoc[*]=star +assoc[!]=bang + +declare -p assoc + +unset assoc["$key"] +declare -p assoc + +unset assoc["*"] +declare -p assoc + +assoc[@]=at assoc[*]=star + +unset assoc['@'] +declare -p assoc + +unset assoc['*'] + +declare -p assoc + +assoc[@]=at assoc[*]=star +echo ${!aref} + +declare -n nref=$aref +echo ${nref} +unset -n nref + +# for associative arrays, test -v treats @ and * as keys + +test -v 'assoc[@]' +echo $? +test -v assoc[$key] +echo $? +[[ -v assoc[$key] ]] +echo $? + +unset -v 'assoc[@]' + +test -v 'assoc[@]' +echo $? +[[ -v assoc[@] ]] +echo $? + +assoc[@]=at + +printf -v assoc[@] "%10s" key +declare -p assoc + +echo === +array=() +test -v array[@] +echo $? +[[ -v array[@] ]] +echo $? + +array=(1 2 3) +declare -p array + +echo ${!iref} +declare -n nref=$iref + +echo $nref +unset -n nref + +# but for indexed arrays, test -v treats @ and * as standing for the entire array +test -v 'array[@]' +echo $? +[[ -v array[@] ]] +echo $? + +printf -v array[@] "%-10s" key +declare -p array