From 36886b5bac75cda19506ba357136200ccf2fe2d4 Mon Sep 17 00:00:00 2001 From: Bart Schaefer Date: Sat, 28 Nov 2020 09:23:10 -0800 Subject: Add PM_DECLARED and PM_DECLAREDNULL parameter flags. This addresses the issue that "typeset foo" creates $foo set to an empty string, which differs from typeset handling in bash and ksh. It does this by concealing the internal value rather than alter the way internal values are defaulted. This imposes the following changes: A typeset variable with no assignment triggers NO_UNSET warnings when the name is used in parameter expansion or math. The typeset -AEFHLRTZailux options are applied upon the first assignment to the variable. Explicit unset before the first assignment discards all of those properties. If any option is applied to an existing name, historic behavior is unchanged. Consequent to the foregoing, the (t) parameter expansion flag prints nothing until after the first assignment, and the (i) and (I) subscript flags also print nothing. The bash behavior of "unset foo; typeset -p foo" is NOT used. This is called out as an emulation distinction, not a change. The test cases have not been updated, so several now fail. The test harness has been updated to declare default values. --- Src/zsh.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'Src/zsh.h') diff --git a/Src/zsh.h b/Src/zsh.h index a26b2d05b..b9b21f218 100644 --- a/Src/zsh.h +++ b/Src/zsh.h @@ -1931,6 +1931,8 @@ struct tieddata { #define PM_DONTIMPORT (1<<22) /* do not import this variable */ #define PM_RESTRICTED (1<<23) /* cannot be changed in restricted mode */ #define PM_UNSET (1<<24) /* has null value */ +#define PM_DECLARED (1<<17) /* */ +#define PM_DECLAREDNULL (PM_DECLARED|PM_UNSET) #define PM_REMOVABLE (1<<25) /* special can be removed from paramtab */ #define PM_AUTOLOAD (1<<26) /* autoloaded from module */ #define PM_NORESTORE (1<<27) /* do not restore value of local special */ -- cgit 1.4.1 From a8f2a5d0c868e2a2263bbfaf98713f43477ba896 Mon Sep 17 00:00:00 2001 From: Bart Schaefer Date: Sat, 28 Nov 2020 11:25:23 -0800 Subject: Choose a better bit-value for PM_DECLARED --- Src/zsh.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Src/zsh.h') diff --git a/Src/zsh.h b/Src/zsh.h index b9b21f218..787afaafa 100644 --- a/Src/zsh.h +++ b/Src/zsh.h @@ -1929,9 +1929,9 @@ struct tieddata { made read-only by the user */ #define PM_READONLY_SPECIAL (PM_SPECIAL|PM_READONLY|PM_RO_BY_DESIGN) #define PM_DONTIMPORT (1<<22) /* do not import this variable */ +#define PM_DECLARED (1<<22) /* explicitly named with typeset */ #define PM_RESTRICTED (1<<23) /* cannot be changed in restricted mode */ #define PM_UNSET (1<<24) /* has null value */ -#define PM_DECLARED (1<<17) /* */ #define PM_DECLAREDNULL (PM_DECLARED|PM_UNSET) #define PM_REMOVABLE (1<<25) /* special can be removed from paramtab */ #define PM_AUTOLOAD (1<<26) /* autoloaded from module */ -- cgit 1.4.1 From fd89e7cefa4d3806f3f469d5ad4b496d130305a6 Mon Sep 17 00:00:00 2001 From: Bart Schaefer Date: Sat, 27 Mar 2021 14:04:05 -0700 Subject: Change DECLAREDNULL to DEFAULTED --- Src/builtin.c | 6 +++--- Src/params.c | 16 ++++++++-------- Src/zsh.h | 2 +- 3 files changed, 12 insertions(+), 12 deletions(-) (limited to 'Src/zsh.h') diff --git a/Src/builtin.c b/Src/builtin.c index b0d4eb7f7..f0c490119 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -2492,7 +2492,7 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func), } } if (isset(POSIXBUILTINS)) - pm->node.flags |= PM_DECLAREDNULL; + pm->node.flags |= PM_DEFAULTED; } else { if (idigit(*pname)) zerrnam(cname, "not an identifier: %s", pname); @@ -2892,7 +2892,7 @@ bin_typeset(char *name, char **argv, LinkList assigns, Options ops, int func) * Don't attempt to set it yet, it's too early * to be exported properly. * - * This may create the array with PM_DECLAREDNULL. + * This may create the array with PM_DEFAULTED. */ asg2.name = asg->name; asg2.flags = 0; @@ -2936,7 +2936,7 @@ bin_typeset(char *name, char **argv, LinkList assigns, Options ops, int func) assignaparam(asg->name, zlinklist2array(asg->value.array, 1), flags); } else if (asg0.value.scalar || oldval) { /* We have to undo what we did wrong with asg2 */ - apm->node.flags &= ~PM_DECLAREDNULL; + apm->node.flags &= ~PM_DEFAULTED; if (oldval) assignsparam(asg0.name, oldval, 0); } diff --git a/Src/params.c b/Src/params.c index c09a3eccf..33bbc54f6 100644 --- a/Src/params.c +++ b/Src/params.c @@ -3056,7 +3056,7 @@ assignsparam(char *s, char *val, int flags) * Don't warn about anything. */ flags &= ~ASSPM_WARN; - v->pm->node.flags &= ~PM_DECLAREDNULL; + v->pm->node.flags &= ~PM_DEFAULTED; } *ss = '['; v = NULL; @@ -3082,7 +3082,7 @@ assignsparam(char *s, char *val, int flags) } if (flags & ASSPM_WARN) check_warn_pm(v->pm, "scalar", created, 1); - v->pm->node.flags &= ~PM_DECLAREDNULL; + v->pm->node.flags &= ~PM_DEFAULTED; if (flags & ASSPM_AUGMENT) { if (v->start == 0 && v->end == -1) { switch (PM_TYPE(v->pm->node.flags)) { @@ -3235,7 +3235,7 @@ assignaparam(char *s, char **val, int flags) if (flags & ASSPM_WARN) check_warn_pm(v->pm, "array", created, may_warn_about_nested_vars); - v->pm->node.flags &= ~PM_DECLAREDNULL; + v->pm->node.flags &= ~PM_DEFAULTED; /* * At this point, we may have array entries consisting of @@ -3448,7 +3448,7 @@ sethparam(char *s, char **val) return NULL; } check_warn_pm(v->pm, "associative array", checkcreate, 1); - v->pm->node.flags &= ~PM_DECLAREDNULL; + v->pm->node.flags &= ~PM_DEFAULTED; setarrvalue(v, val); unqueue_signals(); return v->pm; @@ -3520,7 +3520,7 @@ assignnparam(char *s, mnumber val, int flags) if (flags & ASSPM_WARN) check_warn_pm(v->pm, "numeric", 0, 1); } - v->pm->node.flags &= ~PM_DECLAREDNULL; + v->pm->node.flags &= ~PM_DEFAULTED; setnumvalue(v, val); unqueue_signals(); return v->pm; @@ -4128,7 +4128,7 @@ tiedarrsetfn(Param pm, char *x) else if (pm->ename) { Param altpm = (Param) paramtab->getnode(paramtab, pm->ename); if (altpm) - altpm->node.flags &= ~PM_DECLAREDNULL; + altpm->node.flags &= ~PM_DEFAULTED; } if (x) { char sepbuf[3]; @@ -5049,7 +5049,7 @@ arrfixenv(char *s, char **t) if (isset(ALLEXPORT)) pm->node.flags |= PM_EXPORTED; - pm->node.flags &= ~PM_DECLAREDNULL; + pm->node.flags &= ~PM_DEFAULTED; /* * Do not "fix" parameters that were not exported @@ -5856,7 +5856,7 @@ printparamnode(HashNode hn, int printflags) if (p->node.flags & PM_UNSET) { if ((printflags & (PRINT_POSIX_READONLY|PRINT_POSIX_EXPORT) && p->node.flags & (PM_READONLY|PM_EXPORTED)) || - (p->node.flags & PM_DECLAREDNULL) == PM_DECLAREDNULL) { + (p->node.flags & PM_DEFAULTED) == PM_DEFAULTED) { /* * Special POSIX rules: show the parameter as readonly/exported * even though it's unset, but with no value. diff --git a/Src/zsh.h b/Src/zsh.h index 787afaafa..27be1f788 100644 --- a/Src/zsh.h +++ b/Src/zsh.h @@ -1932,7 +1932,7 @@ struct tieddata { #define PM_DECLARED (1<<22) /* explicitly named with typeset */ #define PM_RESTRICTED (1<<23) /* cannot be changed in restricted mode */ #define PM_UNSET (1<<24) /* has null value */ -#define PM_DECLAREDNULL (PM_DECLARED|PM_UNSET) +#define PM_DEFAULTED (PM_DECLARED|PM_UNSET) #define PM_REMOVABLE (1<<25) /* special can be removed from paramtab */ #define PM_AUTOLOAD (1<<26) /* autoloaded from module */ #define PM_NORESTORE (1<<27) /* do not restore value of local special */ -- cgit 1.4.1 From e67ccd7f1efae7696dc17f6e3e720cd994e90155 Mon Sep 17 00:00:00 2001 From: Bart Schaefer Date: Sat, 10 Apr 2021 14:10:21 -0700 Subject: Add TYPESET_DOES_NOT_SET option (cf. 48469) --- Src/builtin.c | 2 +- Src/options.c | 1 + Src/zsh.h | 1 + Test/E03posix.ztst | 2 +- 4 files changed, 4 insertions(+), 2 deletions(-) (limited to 'Src/zsh.h') diff --git a/Src/builtin.c b/Src/builtin.c index f0c490119..edd4cad44 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -2491,7 +2491,7 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func), return NULL; } } - if (isset(POSIXBUILTINS)) + if (isset(TYPESETDOESNOTSET)) pm->node.flags |= PM_DEFAULTED; } else { if (idigit(*pname)) diff --git a/Src/options.c b/Src/options.c index fba021e7d..766ffdfdb 100644 --- a/Src/options.c +++ b/Src/options.c @@ -257,6 +257,7 @@ static struct optname optns[] = { {{NULL, "sunkeyboardhack", 0}, SUNKEYBOARDHACK}, {{NULL, "transientrprompt", 0}, TRANSIENTRPROMPT}, {{NULL, "trapsasync", 0}, TRAPSASYNC}, +{{NULL, "typesetdoesnotset", OPT_EMULATE|OPT_BOURNE}, TYPESETDOESNOTSET}, {{NULL, "typesetsilent", OPT_EMULATE|OPT_BOURNE}, TYPESETSILENT}, {{NULL, "unset", OPT_EMULATE|OPT_BSHELL}, UNSET}, {{NULL, "verbose", 0}, VERBOSE}, diff --git a/Src/zsh.h b/Src/zsh.h index 27be1f788..12efb784f 100644 --- a/Src/zsh.h +++ b/Src/zsh.h @@ -2536,6 +2536,7 @@ enum { SUNKEYBOARDHACK, TRANSIENTRPROMPT, TRAPSASYNC, + TYPESETDOESNOTSET, TYPESETSILENT, UNSET, VERBOSE, diff --git a/Test/E03posix.ztst b/Test/E03posix.ztst index c59ca4f6e..a2769f3aa 100644 --- a/Test/E03posix.ztst +++ b/Test/E03posix.ztst @@ -4,7 +4,7 @@ # %prep - setopt POSIX_BUILTINS + setopt POSIX_BUILTINS TYPESET_DOES_NOT_SET %test -- cgit 1.4.1 From b3613e4895f7b059558c4ef211189b516dbf903d Mon Sep 17 00:00:00 2001 From: Bart Schaefer Date: Mon, 12 Apr 2021 13:59:06 -0700 Subject: Change TYPESET_DOES_NOT_SET to TYPESET_TO_UNSET to avoid double-negative --- Doc/Zsh/builtins.yo | 6 +++++- Doc/Zsh/options.yo | 10 ++++++++++ Src/builtin.c | 2 +- Src/options.c | 2 +- Src/zsh.h | 2 +- Test/D06subscript.ztst | 5 +++++ Test/E03posix.ztst | 45 ++++++++++++++++++++++++++++++++++++++++++++- 7 files changed, 67 insertions(+), 5 deletions(-) (limited to 'Src/zsh.h') diff --git a/Doc/Zsh/builtins.yo b/Doc/Zsh/builtins.yo index a7afe42cf..61dc6986f 100644 --- a/Doc/Zsh/builtins.yo +++ b/Doc/Zsh/builtins.yo @@ -1872,7 +1872,11 @@ ifnzman(noderef(Local Parameters))\ retain their special attributes when made local. For each var(name)tt(=)var(value) assignment, the parameter -var(name) is set to var(value). +var(name) is set to var(value). If the assignment is omitted and var(name) +does em(not) refer to an existing parameter, a new parameter is intialized +to empty string, zero, or empty array (as appropriate), em(unless) the +shell option tt(TYPESET_TO_UNSET) is set. When that option is set, +the parameter attributes are recorded but the parameter remains unset. If the shell option tt(TYPESET_SILENT) is not set, for each remaining var(name) that refers to a parameter that is already set, the name and diff --git a/Doc/Zsh/options.yo b/Doc/Zsh/options.yo index b3bf11f5c..6a1f82b07 100644 --- a/Doc/Zsh/options.yo +++ b/Doc/Zsh/options.yo @@ -1926,6 +1926,16 @@ If the option is set, they will only be shown when parameters are selected with the `tt(-m)' option. The option `tt(-p)' is available whether or not the option is set. ) +pindex(TYPESET_TO_UNSET) +pindex(NO_TYPESET_TO_UNSET) +pindex(TYPESETTOUNSET) +pindex(NOTYPESETTOUNSET) +item(tt(TYPESET_TO_UNSET) )( +When declaring a new parameter with any of the `tt(typeset)' family of +related commands, the parameter remains unset unless and until a +value is explicity assigned to it, either in the `tt(typeset)' command +itself or as a later assignment statement. +) pindex(VERBOSE) pindex(NO_VERBOSE) pindex(NOVERBOSE) diff --git a/Src/builtin.c b/Src/builtin.c index edd4cad44..6d119f7a5 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -2491,7 +2491,7 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func), return NULL; } } - if (isset(TYPESETDOESNOTSET)) + if (isset(TYPESETTOUNSET)) pm->node.flags |= PM_DEFAULTED; } else { if (idigit(*pname)) diff --git a/Src/options.c b/Src/options.c index 766ffdfdb..23935ae18 100644 --- a/Src/options.c +++ b/Src/options.c @@ -257,8 +257,8 @@ static struct optname optns[] = { {{NULL, "sunkeyboardhack", 0}, SUNKEYBOARDHACK}, {{NULL, "transientrprompt", 0}, TRANSIENTRPROMPT}, {{NULL, "trapsasync", 0}, TRAPSASYNC}, -{{NULL, "typesetdoesnotset", OPT_EMULATE|OPT_BOURNE}, TYPESETDOESNOTSET}, {{NULL, "typesetsilent", OPT_EMULATE|OPT_BOURNE}, TYPESETSILENT}, +{{NULL, "typesettounset", OPT_EMULATE|OPT_BOURNE}, TYPESETTOUNSET}, {{NULL, "unset", OPT_EMULATE|OPT_BSHELL}, UNSET}, {{NULL, "verbose", 0}, VERBOSE}, {{NULL, "vi", 0}, VIMODE}, diff --git a/Src/zsh.h b/Src/zsh.h index 12efb784f..490407ad0 100644 --- a/Src/zsh.h +++ b/Src/zsh.h @@ -2536,8 +2536,8 @@ enum { SUNKEYBOARDHACK, TRANSIENTRPROMPT, TRAPSASYNC, - TYPESETDOESNOTSET, TYPESETSILENT, + TYPESETTOUNSET, UNSET, VERBOSE, VIMODE, diff --git a/Test/D06subscript.ztst b/Test/D06subscript.ztst index c1a8d79cf..4225c543c 100644 --- a/Test/D06subscript.ztst +++ b/Test/D06subscript.ztst @@ -289,3 +289,8 @@ F:Regression test for workers/42297 >14 24 >b b >b?rbaz foob?r + + i=1,3 + [[ ${a[$i]} = ${a[i]} ]] +0f:Math evaluation of commas in array subscripts +F:In math, (($i)) should be the same as ((i)). diff --git a/Test/E03posix.ztst b/Test/E03posix.ztst index a2769f3aa..fb394986d 100644 --- a/Test/E03posix.ztst +++ b/Test/E03posix.ztst @@ -4,7 +4,7 @@ # %prep - setopt POSIX_BUILTINS TYPESET_DOES_NOT_SET + setopt POSIX_BUILTINS TYPESET_TO_UNSET %test @@ -117,3 +117,46 @@ } 0:readonly with typeset -p >typeset -g -r var + +# Tests expected to fail + + echo - +0f:A single "-" for echo does not end the arguments +F:POSIX requires a solitary "-" to be a plain argument +>- + + ARGV0=sh $ZTST_testdir/../Src/zsh -c 'foreach() { true; }' +-f:"foreach" is not a reserved word + + ARGV0=sh $ZTST_testdir/../Src/zsh -c 'end() { true; } +-f:"end" is not a reserved word + + a='a:b:' ARGV0=sh $ZTST_testdir/../Src/zsh -c 'IFS=:; printf "<%s>\n" $a' +0f:IFS is a separator, not a delimiter +> +> + + a=$'\ra\r\rb' ARGV0=sh $ZTST_testdir/../Src/zsh -c 'IFS=:; printf "<%s>\n" $a' +0f:All whitespace characters are "IFS whitespace" +F:isspace('\r') is true so \r should behave like space, \t, \n +F:This may also need to apply to multibyte whitespace +> +> + + ARGV0=sh $ZTST_testdir/../Src/zsh -c 'IFS=2; printf "<%s>\n" $((11*11))' +0f:IFS applies to math results (numbers treated as strings) +><1> +><1> + + ARGV0=sh $ZTST_testdir/../Src/zsh -c 'inf=42; echo $((inf))' +0f:The math constant Inf is case-sensitive, with capital I +>42 + + ARGV0=sh $ZTST_testdir/../Src/zsh -c 'EUID=10; echo "$EUID"' +-f:EUID is not a special variable +>10 + + ARGV0=sh $ZTST_testdir/../Src/zsh -c "printf '<%10s>\n' St$'\M-C\M-)'phane" +0f:Width of %s is computed in bytes not characters +F:This is considered a bugfix in zsh +>< Stéphane> -- cgit 1.4.1