From a30f513fc4cd507e74de6f0d0006b289a017a0d0 Mon Sep 17 00:00:00 2001 From: Chet Ramey Date: Thu, 13 May 2021 14:49:18 -0400 Subject: [PATCH] more changes to handle @ and * as associative array keys --- CWRU/CWRU.chlog | 65 +++++++++++++++++++++ MANIFEST | 1 + arrayfunc.c | 7 ++- arrayfunc.h | 8 ++- builtins/bashgetopt.c | 15 ++++- builtins/bashgetopt.h | 1 + builtins/common.c | 5 ++ builtins/printf.def | 11 ++-- builtins/set.def | 23 +++++--- doc/bash.1 | 6 +- doc/bashref.texi | 7 ++- doc/version.texi | 4 +- examples/loadables/cat.c | 5 ++ examples/loadables/cut.c | 4 ++ examples/loadables/head.c | 3 + examples/loadables/rm.c | 6 +- examples/loadables/tee.c | 7 ++- examples/loadables/tty.c | 3 +- expr.c | 1 + po/zh_TW.gmo | Bin 152061 -> 152761 bytes po/zh_TW.po | 17 ++---- subst.c | 13 +++-- test.c | 14 +++-- tests/array.right | 2 +- tests/assoc.right | 6 +- tests/builtins.right | 6 ++ tests/builtins5.sub | 11 +++- tests/cond.right | 2 + tests/cond.tests | 7 +++ tests/quotearray.right | 39 ++++++++++++- tests/quotearray.tests | 3 + tests/quotearray1.sub | 9 +++ tests/quotearray2.sub | 11 ++++ tests/quotearray3.sub | 25 +++++++- tests/quotearray4.sub | 116 ++++++++++++++++++++++++++++++++++++++ 35 files changed, 404 insertions(+), 59 deletions(-) create mode 100644 tests/quotearray4.sub 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 75d5bc104669660fe3e9a809123a74531457ea52..c9e58a044fb1e7b2e0e080b95d8ea291d00b808b 100644 GIT binary patch delta 12319 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 delta 12221 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, 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