Zsh Mailing List Archive
Messages sorted by:
Reverse Date,
Date,
Thread,
Author
[PATCH] Fix output of 'typeset +m var'
- X-seq: zsh-workers 55217
- From: Philippe Altherr <philippe.altherr@xxxxxxxxx>
- To: Zsh hackers list <zsh-workers@xxxxxxx>
- Subject: [PATCH] Fix output of 'typeset +m var'
- Date: Tue, 13 Oct 2026 19:25:04 +0200
- Arc-authentication-results: i=1; mx.google.com; arc=none
- Arc-message-signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20260327; h=to:subject:message-id:date:from:mime-version:dkim-signature; bh=8m/vDPEnmfRoQdHHg8jjXtDqQ7WGeA7htpyGMdrhHf0=; fh=BgAYDYpL6Ne/A5nWEMVJiHiBtrz8Imz3uf26RDwgQX4=; b=HXKt+2aCHBB5XFXKoG/x4MZKbtK7ka31DKmdnrIURrESekLvQzPdWe202qqpT/P5t6 XF4vH4l+EIllp8m2QqnsK+cEcjuCsPqZ/3yGeo/hsPJPBy7hD1YIVovRGp9G/rQ26rHd 96AEgx1S5TfbGmfFEL2ibYqUqLlRcskNi3o4BE67PM4Bz/UR9a9LlFFYNlXWX8XqjiHg 8tAngIKfMgAjiq98qBHvmg6BoANlLU2uHIPWx0reqGNfkY6Wk8L9tnTKsT/99XU9mH/d 9t7WX4ZNFAMJ5OGNiZZb2lzFO4zRuuCLwK/0UE6ddsvX/FFwRD2QYp0m55D3g/QLNyfr OdJQ==; darn=zsh.org
- Arc-seal: i=1; a=rsa-sha256; t=1791912317; cv=none; d=google.com; s=arc-20260327; b=MuDOKQz3ACCxtjXqCpv6xRgl654c5Qyt0o9KqnQRQYiqi61kLvZegpVq22Y/XOVFuw 39HIZTlCndQK3Gus6OvVSLIFs3o7b5acYGhsrdslvGz8z5i1ttVR4i38RzCpTW+HAesu a/04/Y8415Ehk8LS8ElJWFvhdKuXNr9wlIxztBJc8rNdQqQ/o1W0hQNzNSB2SIk7KakO yS8uyAMo+KbolUy7SHXhS9ZSi1EZ/2kZ444uQ8/e389djDsCh+4O74aQnKu6KAdLeEre Wxp50/XNwJNo/tjwsjhmg25NQDMk1qWwj+of6S4XWOTFnh+4f7uAfU7KfE+Sjoed7ah7 GWWg==
- Archived-at: <https://zsh.org/workers/55217>
- List-id: <zsh-workers.zsh.org>
'typeset +m var' prints a description of 'var' that is similar to (but not the same as) the one returned by '${(t)var}'. The current implementation has two issues, which the patch below fixes:
1) For all types of variables, except named references, 'typeset +m var' first prints the type of the variable.
2) For a number of exported variables, like 'export var', 'typeset +m var' fails to include 'exported' in the description of the variable (probably because of bogus reuse of logic for printing '-x', which must avoid printing '-x' when it's implied by the keyword 'export').
-
Fix output of 'typeset +m var' (depends on
workers/55216 - Share code for $parameters[var] and ${(t)var})
Philippe
diff --git a/Src/params.c b/Src/params.c
index 5e334075a..c4837f3a7 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -6241,7 +6241,6 @@ freeparamnode(HashNode hn)
enum paramtypes_flags {
PMTF_USE_BASE = (1<<0),
PMTF_USE_WIDTH = (1<<1),
- PMTF_TEST_LEVEL = (1<<2)
};
struct paramtypes {
@@ -6258,7 +6257,8 @@ static const struct paramtypes pmtypes[] = {
{ PM_FFLOAT, "float", 'F', 0},
{ PM_ARRAY, "array", 'a', 0},
{ PM_HASHED, "association", 'A', 0},
- { 0, "local", 0, PMTF_TEST_LEVEL},
+ { PM_NAMEREF, "nameref", 'n', 0},
+ { PM_LOCAL, "local", 0, 0},
{ PM_HIDE, "hide", 'h', 0 },
{ PM_LEFT, "left justified", 'L', PMTF_USE_WIDTH},
{ PM_RIGHT_B, "right justified", 'R', PMTF_USE_WIDTH},
@@ -6270,7 +6270,6 @@ static const struct paramtypes pmtypes[] = {
{ PM_EXPORTED, "exported", 'x', 0},
{ PM_UNIQUE, "unique", 'U', 0},
{ PM_TIED, "tied", 'T', 0},
- { PM_NAMEREF, "nameref", 'n', 0}
};
#define PMTYPES_SIZE ((int)(sizeof(pmtypes)/sizeof(struct paramtypes)))
@@ -6442,59 +6441,54 @@ printparamnode(HashNode hn, int printflags)
/* Print the attributes of the parameter */
if (printflags & (PRINT_TYPE|PRINT_TYPESET)) {
- int doneminus = 0, i;
- const struct paramtypes *pmptr;
-
- for (pmptr = pmtypes, i = 0; i < PMTYPES_SIZE; i++, pmptr++) {
- int doprint = 0;
+ int pflags = p->node.flags, doneminus = 0, n = PMTYPES_SIZE;
+ if (p->level)
+ pflags |= PM_LOCAL;
+ for (const struct paramtypes *pmptr = pmtypes; n; n--, pmptr++) {
if (altname && altname == pmptr->typeflag)
continue;
+ if (!(pflags & pmptr->binflag))
+ continue;
+ if (pmptr->binflag == PM_EXPORTED &&
+ (printflags & PRINT_TYPESET) &&
+ !(pflags & (PM_LOCAL|PM_ARRAY|PM_HASHED)))
+ continue;
- if (pmptr->flags & PMTF_TEST_LEVEL) {
- if (p->level) {
- /*
- if ((p->node.flags & PM_SPECIAL) &&
- (p->node.flags & PM_LOCAL) &&
- !(p->node.flags & PM_HIDE)) {
- if (doneminus)
- putchar(' ');
- printf("+h ");
- doneminus = 0;
- }
- */
- doprint = 1;
- }
- } else if ((pmptr->binflag != PM_EXPORTED || p->level ||
- (p->node.flags & (PM_LOCAL|PM_ARRAY|PM_HASHED))) &&
- (p->node.flags & pmptr->binflag))
- doprint = 1;
-
- if (doprint) {
- if (printflags & PRINT_TYPESET) {
- if (pmptr->typeflag) {
- if (!doneminus) {
- putchar('-');
- doneminus = 1;
- }
- putchar(pmptr->typeflag);
+ /*
+ if (pmptr->binflag == PM_LOCAL &&
+ (pflags & PM_SPECIAL) &&
+ !(pflags & PM_HIDE)) {
+ if (doneminus)
+ putchar(' ');
+ printf("+h ");
+ doneminus = 0;
+ }
+ */
+
+ if (printflags & PRINT_TYPESET) {
+ if (pmptr->typeflag) {
+ if (!doneminus) {
+ putchar('-');
+ doneminus = 1;
}
- } else
- printf("%s ", pmptr->string);
- if ((pmptr->flags & PMTF_USE_BASE) && p->base) {
- printf("%d ", p->base);
- doneminus = 0;
- }
- if ((pmptr->flags & PMTF_USE_WIDTH) && p->width) {
- printf("%u ", p->width);
- doneminus = 0;
- }
+ putchar(pmptr->typeflag);
+ }
+ } else
+ printf("%s ", pmptr->string);
+ if ((pmptr->flags & PMTF_USE_BASE) && p->base) {
+ printf("%d ", p->base);
+ doneminus = 0;
+ }
+ if ((pmptr->flags & PMTF_USE_WIDTH) && p->width) {
+ printf("%u ", p->width);
+ doneminus = 0;
}
}
if (doneminus)
putchar(' ');
- if (p->node.flags & PM_TIED) {
+ if (pflags & PM_TIED) {
/*
* For scalars tied to arrays,s
* * typeset +m outputs
@@ -6518,7 +6512,7 @@ printparamnode(HashNode hn, int printflags)
/*
* Swap param and tied peer for typeset -p output
*/
- if (!(printflags & PRINT_TYPESET) || (p->node.flags & PM_ARRAY))
+ if (!(printflags & PRINT_TYPESET) || (pflags & PM_ARRAY))
peer = tmp;
else {
peer = p;
diff --git a/Test/B02typeset.ztst b/Test/B02typeset.ztst
index 6bc53c68a..768fa9991 100644
--- a/Test/B02typeset.ztst
+++ b/Test/B02typeset.ztst
@@ -39,67 +39,6 @@
scalar=scalar
array=(a r r a y)
- scope00() {
- typeset scalar
- scalar=local
- typeset -a array
- array=(l o c a l)
- print $scalar $array
- typeset -p scalar array
- typeset -m scalar array
- typeset +m scalar array
- }
- scope01() {
- local scalar
- scalar=local
- local -a array
- array=(l o c a l)
- print $scalar $array
- typeset -p scalar array
- typeset -m scalar array
- typeset +m scalar array
- }
- scope02() {
- declare scalar
- scalar=local
- declare -a array
- array=(l o c a l)
- print $scalar $array
- typeset -p scalar array
- typeset -m scalar array
- typeset +m scalar array
- }
- scope10() {
- export outer=outer
- /bin/sh -fc 'echo $outer'
- typeset -p outer
- typeset -m outer
- typeset +m outer
- }
- scope11() {
- typeset -x outer=outer
- /bin/sh -fc 'echo $outer'
- }
- scope12() {
- local -x outer=inner
- /bin/sh -fc 'echo $outer'
- }
- scope13() {
- local -xT OUTER outer
- outer=(i n n e r)
- /bin/sh -fc 'echo $OUTER'
- typeset -p OUTER outer
- typeset -m OUTER outer
- typeset +m OUTER outer
- }
-
- # Bug? `typeset -h' complains that ! # $ * - ? @ are not identifiers.
- stress00() {
- typeset -h +g -m [[:alpha:]_]*
- unset -m [[:alpha:]_]*
- typeset +m [[:alpha:]_]*
- }
-
%test
typeset -p scalar array
@@ -113,9 +52,26 @@
>scalar
>array array
- scope00
+ check() {
+ print "# Testing: $@"
+ $@ scalar
+ scalar=local
+ $@ -a array
+ array=(l o c a l)
+ print $scalar $array
+ typeset -p scalar array
+ typeset -m scalar array
+ typeset +m scalar array
+ }
+ check typeset
+ print $scalar $array
+ check local
print $scalar $array
-0:Simple local declarations
+ check declare
+ print $scalar $array
+ unfunction check
+0:Equivalence of typeset, local, and declare for simple local declarations
+># Testing: typeset
>local l o c a l
>typeset scalar=local
>typeset -a array=( l o c a l )
@@ -124,10 +80,7 @@
>local scalar
>array local array
>scalar a r r a y
-
- scope01
- print $scalar $array
-0:Equivalence of local and typeset in functions
+># Testing: local
>local l o c a l
>typeset scalar=local
>typeset -a array=( l o c a l )
@@ -136,10 +89,7 @@
>local scalar
>array local array
>scalar a r r a y
-
- scope02
- print $scalar $array
-0:Basic equivalence of declare and typeset
+># Testing: declare
>local l o c a l
>typeset scalar=local
>typeset -a array=( l o c a l )
@@ -153,26 +103,53 @@
0:declare previously lacked -m/+m options
>scalar
- scope10
- print $outer
-0:Global export
->outer
->export outer=outer
->outer=outer
->outer
->outer
-
- scope11
- print $outer
-0:Equivalence of export and typeset -x
->outer
->outer
-
- scope12
- print $outer
-0:Local export
->inner
->outer
+ check() {
+ print "# Testing: $@"
+ $@ VAR; VAR=exported
+ $@ -a var; var=(e x p o r t e d)
+ /bin/sh -fc 'echo $VAR $var'
+ typeset -p VAR var
+ typeset -m VAR var
+ typeset +m VAR var
+ }
+ check export
+ print $VAR $var
+ unset VAR var
+ check typeset -x
+ print $VAR $var
+ unset VAR var
+ check local -x
+ print $VAR $var
+ unset VAR var
+ unfunction check
+0:Comparison of export, typeset -x and local -x for exports
+># Testing: export
+>exported
+>export VAR=exported
+>typeset -g -ax var=( e x p o r t e d )
+>VAR=exported
+>var=( e x p o r t e d )
+>exported VAR
+>array exported var
+>exported e x p o r t e d
+># Testing: typeset -x
+>exported
+>export VAR=exported
+>typeset -g -ax var=( e x p o r t e d )
+>VAR=exported
+>var=( e x p o r t e d )
+>exported VAR
+>array exported var
+>exported e x p o r t e d
+># Testing: local -x
+>exported
+>local -x VAR=exported
+>local -ax var=( e x p o r t e d )
+>VAR=exported
+>var=( e x p o r t e d )
+>local exported VAR
+>array local exported var
+>
addflags() {
setopt localoptions typeset_to_unset
@@ -349,7 +326,14 @@ F:BUG:The inner "typeset -p VAR" should contain the value of the outer "var"
?(eval):typeset:2: use unset to remove tied variables
OUTER=outer
- scope13
+ () {
+ local -xT OUTER outer
+ outer=(i n n e r)
+ /bin/sh -fc 'echo $OUTER'
+ typeset -p OUTER outer
+ typeset -m OUTER outer
+ typeset +m OUTER outer
+ }
print $OUTER
0:Export of tied parameters
>i:n:n:e:r
@@ -543,9 +527,14 @@ F:BUG:The inner "typeset -p VAR" should contain the value of the outer "var"
>'000004.000'
>'-00004.000'
- stress00
+ # Bug? `typeset -h' complains that ! # $ * - ? @ are not identifiers.
+ () {
+ typeset -h +g -m [[:alpha:]_]*
+ unset -m [[:alpha:]_]*
+ typeset +m [[:alpha:]_]*
+ }
print $scalar $array
-0q:Stress test: all parameters are local and unset, using -m
+0:Stress test: all parameters are local and unset, using -m
>scalar a r y
local parentenv=preserved
@@ -1037,9 +1026,9 @@ F:BUG:The inner "typeset -p VAR" should contain the value of the outer "var"
>zsh_eval_context=( toplevel shfunc shfunc shfunc eval )
>ZSH_EVAL_CONTEXT=toplevel:shfunc:shfunc:shfunc:eval
>array tied PATH path
->tied path PATH
+>exported tied path PATH
>array tied MANPATH manpath
->tied manpath MANPATH
+>exported tied manpath MANPATH
>array readonly tied ZSH_EVAL_CONTEXT zsh_eval_context
>readonly tied zsh_eval_context ZSH_EVAL_CONTEXT
>path: array-tied-special
@@ -1295,7 +1284,7 @@ F:This is a bug, the non -h variable should not hide the autoload variable
>typeset -h EUID=''
>typeset -ih HOME=0
>typeset -ah HOME=( )
->typeset -hn HOME=''
+>typeset -nh HOME=''
>typeset -g -i10 EUID=$EUID
>export HOME=$HOME
@@ -1324,8 +1313,8 @@ F:This is a bug, the non -h variable should not hide the autoload variable
>check:5: read-only variable: int
>typeset -i int=15
>Testing "local -n ref=v<N>"
->typeset -rn ref=v1
->typeset -rn ref=v1
+>typeset -nr ref=v1
+>typeset -nr ref=v1
F:"typeset -r ref=v2" succeeds because it dereferences "ref" and assigns "v1" with "v2"
>check:local:4: ref: read-only reference
>check:local:5: ref: read-only reference
diff --git a/Test/D04parameter.ztst b/Test/D04parameter.ztst
index 886b32fe3..5abb390d9 100644
--- a/Test/D04parameter.ztst
+++ b/Test/D04parameter.ztst
@@ -903,7 +903,7 @@
unset str arr
0:${(t)...} and typeset +m ...
>scalar-left-upper-export
->left justified 3 uppercase str
+>left justified 3 uppercase exported str
>array-lower-unique
>array lowercase unique arr
>association-local-readonly-tag
@@ -914,19 +914,19 @@
>float local right justified 5 flt
>association-local-readonly-tag
>nameref-local-hide-association-local-readonly-tag
->local hide nameref ref
+>nameref local hide ref
>scalar-local-lower-tied-unique
>local lowercase unique tied var VAR
>array-local-lower-tied-unique
>array local lowercase unique tied VAR var
>scalar-export-special
->HOME
+>exported HOME
>integer-export-special
->integer 10 SHLVL
+>integer 10 exported SHLVL
>undefined
>undefined auto
>nameref-local-undefined
->local nameref refauto
+>nameref local refauto
# it's not quite clear that these are actually right unless you know
# the algorithm: search along the string for the point at which the
diff --git a/Test/K01nameref.ztst b/Test/K01nameref.ztst
index e490aab0f..6ed2f7f24 100644
--- a/Test/K01nameref.ztst
+++ b/Test/K01nameref.ztst
@@ -1124,15 +1124,15 @@ F:Checking for a bug in zmodload that affects later tests
typeset +rn ref=RW
typeset -p ref
0:add and remove readonly attribute with references
->typeset -rn ref=RO
+>typeset -nr ref=RO
>(eval):typeset:4: ref: read-only reference
>status: 1 expected: 1
>typeset -n ref=RO
>typeset -r ref=RO
->typeset -rn ref=RO
+>typeset -nr ref=RO
>status: 0 expected: 0
>typeset -n ref=RW
->typeset -rn ref=RX
+>typeset -nr ref=RX
>typeset ref=RW
() {
@@ -1440,23 +1440,23 @@ F:previously this could create an infinite recursion and crash
>foo
>typeset -n x=!
>0
->typeset -un x=!
+>typeset -nu x=!
>0
>typeset -n x='?'
>0
->typeset -un x='?'
+>typeset -nu x='?'
>0
>typeset -n x='$'
>$$
->typeset -un x='$'
+>typeset -nu x='$'
>$$
>typeset -n x=-
>569X
->typeset -un x=-
+>typeset -nu x=-
>569X
>typeset -n x=_
>x
->typeset -un x=_
+>typeset -nu x=_
>x
?edgeupper: invalid variable name: argv
?edgeupper: invalid variable name: ARGC
diff --git a/Test/V10private.ztst b/Test/V10private.ztst
index d2e87b403..c99982d1a 100644
--- a/Test/V10private.ztst
+++ b/Test/V10private.ztst
@@ -317,10 +317,10 @@ F:future revision will create a global with this assignment
>A: ref1=OUT ref2=LCL ref3= ref4= out=OUT lcl=LCL undef=
>B: ref1=Out ref2=Lcl ref3=Glb ref4=Out out=Out lcl=Lcl undef=Glb
>C: ref1= ref2= ref3= ref4= out=Out lcl=Lcl undef=Glb
->typeset -hn ref1=out
->typeset -hn ref2=lcl
->typeset -hn ref3=undef
->typeset -hn ref4=out
+>typeset -nh ref1=out
+>typeset -nh ref2=lcl
+>typeset -nh ref3=undef
+>typeset -nh ref4=out
>typeset -g undef=Glb
>D: out=Out undef=Glb
@@ -341,7 +341,7 @@ F:future revision will create a global with this assignment
1:assignment to private nameref in wrong scope, part 1
>(anon):1: ref: can't modify read-only parameter
>typeset -a ary
->typeset -hn ref=ary
+>typeset -nh ref=ary
>(eval):typeset:14: no such variable: ary
() {
@@ -362,7 +362,7 @@ F:future revision will create a global with this assignment
>typeset -g -a ary
>typeset ref=XX
>typeset -a ary
->typeset -hn ref=ary
+>typeset -nh ref=ary
>(eval):typeset:14: no such variable: ary
() {
@@ -381,7 +381,7 @@ F:future revision will create a global with this assignment
F:See K01nameref.ztst up-reference part 5
F:Here ptr1 finds private ptr2 by scope mismatch
>typeset -n ptr1=ptr2
->typeset -hn ptr2
+>typeset -nh ptr2
>(anon):1: read-only variable: ptr2
() {
@@ -400,7 +400,7 @@ F:Here ptr1 finds private ptr2 by scope mismatch
F:See K01nameref.ztst up-reference part 5
F:Here ptr1 finds private ptr2 by scope mismatch
>typeset -n ptr1=ptr2
->typeset -hn ptr2=''
+>typeset -nh ptr2=''
>(anon):1: ptr1: can't modify read-only parameter
() {
@@ -419,7 +419,7 @@ F:Here ptr1 finds private ptr2 by scope mismatch
F:See K01nameref.ztst up-reference part 5
F:Here ptr1 finds private ptr2 by scope mismatch
>typeset -n ptr1=ptr2
->typeset -hn ptr2=val
+>typeset -nh ptr2=val
>(anon):1: ptr1: can't modify read-only parameter
() {
@@ -438,7 +438,7 @@ F:Here ptr1 finds private ptr2 by scope mismatch
F:See K01nameref.ztst up-reference part 5
F:Here ptr1 finds private ptr2 by scope mismatch
>typeset -n ptr1=ptr2
->typeset -hn ptr2=foo
+>typeset -nh ptr2=foo
>(anon):1: ptr1: can't modify read-only parameter
typeset ptr2
@@ -459,13 +459,13 @@ F:Here ptr1 finds private ptr2 by scope mismatch
F:See K01typeset.ztst up-reference part 5
F:Here ptr1 points to global ptr2 so assignment succeeds
>typeset -n ptr1=ptr2
->typeset -hn ptr2
+>typeset -nh ptr2
>ptr1=ptr2
>ptr2=val
>print:ptr1=val
>print:ptr2=val
>typeset -n ptr1=ptr2
->typeset -hn ptr2
+>typeset -nh ptr2
>typeset ptr2=val
() {
@@ -478,7 +478,7 @@ F:Here ptr1 points to global ptr2 so assignment succeeds
unset val
0:up-reference for private namerefs, end is set and in scope but private
>typeset -n ptr1=ptr2
->typeset -hn ptr2=val
+>typeset -nh ptr2=val
>typeset -g val=foo
() {
@@ -492,7 +492,7 @@ F:Here ptr1 points to global ptr2 so assignment succeeds
unset val
0:up-reference for private namerefs, end is unset and in scope but private
>typeset -n ptr1=ptr2
->typeset -hn ptr2=val
+>typeset -nh ptr2=val
>typeset -g val=foo
() {
@@ -507,7 +507,7 @@ F:Here ptr1 points to global ptr2 so assignment succeeds
}
0:regression test for invalid reference detection
>typeset -n ptr1=ptr2
->typeset -hn ptr2
+>typeset -nh ptr2
() {
private x=1
Messages sorted by:
Reverse Date,
Date,
Thread,
Author