From 6b21e5c0e201876f6659b563b56da9a993ae6c03 Mon Sep 17 00:00:00 2001 From: Bart Schaefer Date: Tue, 20 Feb 2024 20:16:03 -0800 Subject: 52559: revise "typeset -p" with respect to local readonly special parameters Update doc and tests to describe handling of global readonly specials and to account for side-effects on zsh/param/private. --- ChangeLog | 9 +++++++++ Doc/Zsh/builtins.yo | 8 ++++++++ Doc/Zsh/mod_private.yo | 7 ++++--- Src/Modules/param_private.c | 2 +- Src/params.c | 24 ++++++++++++++++++++++-- Test/B02typeset.ztst | 14 ++++++++++++++ Test/K01nameref.ztst | 4 ++-- Test/V10private.ztst | 13 +++++++++---- 8 files changed, 69 insertions(+), 12 deletions(-) diff --git a/ChangeLog b/ChangeLog index e3762340a..090644e8b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2024-02-20 Bart Schaefer + + * 52559: Doc/Zsh/builtins.yo, Doc/Zsh/mod_private.yo, + Src/Modules/param_private.c, Src/params.c, Test/B02typeset.ztst, + Test/K01nameref.ztst, Test/V10private.ztst: revise "typeset -p" + with respect to local readonly special parameters; update doc + and tests to describe handling of global readonly specials and + to account for side-effects on zsh/param/private. + 2024-02-19 Peter Stephenson * 52549: Doc/Zsh/builtins.yo: document that return already works diff --git a/Doc/Zsh/builtins.yo b/Doc/Zsh/builtins.yo index 7a8654f27..784089594 100644 --- a/Doc/Zsh/builtins.yo +++ b/Doc/Zsh/builtins.yo @@ -2136,6 +2136,14 @@ tt(-p) may be followed by an optional integer argument. Currently only the value tt(1) is supported. In this case arrays and associative arrays are printed with newlines between indented elements for readability. + +The names and values of readonly special parameters +(most of the parameters marked `' in +ifzman(zmanref(zshparam))ifnzman(noderef(Parameters Set By The Shell)), +except those documented as settable) +are not printed with `tt(-)tt(p)' because to execute those typeset commands +would cause errors. However, these parameters are printed when they +have been made local to the scope where `tt(typeset -p)' is run. ) item(tt(-T) [ var(scalar)[tt(=)var(value)] var(array)[tt(=LPAR())var(value) ...tt(RPAR())] [ var(sep) ] ])( This flag has a different meaning when used with tt(-f); see below. diff --git a/Doc/Zsh/mod_private.yo b/Doc/Zsh/mod_private.yo index 08ac4cafe..24c099f38 100644 --- a/Doc/Zsh/mod_private.yo +++ b/Doc/Zsh/mod_private.yo @@ -16,9 +16,10 @@ The tt(private) builtin accepts all the same options and arguments as tt(local) (ifzman(zmanref(zshbuiltins))ifnzman(noderef(Shell Builtin Commands))) except for the `tt(-)tt(T)' option. Tied parameters may not be made private. -The `tt(-)tt(p)' option is presently a no-op because the state of -private parameters cannot reliably be reloaded. This also applies -to printing private parameters with `tt(typeset -p)'. +The `tt(-)tt(p)' option is presently disabled because the state of +private parameters cannot reliably be reloaded. When `tt(typeset -)tt(p)' +outputs a private parameter, it is treated as a local with the +`tt(-)tt(h)' (hide) option enabled. If used at the top level (outside a function scope), tt(private) creates a normal parameter in the same manner as tt(declare) or tt(typeset). A diff --git a/Src/Modules/param_private.c b/Src/Modules/param_private.c index 5003d4627..044617190 100644 --- a/Src/Modules/param_private.c +++ b/Src/Modules/param_private.c @@ -646,7 +646,7 @@ printprivatenode(HashNode hn, int printflags) static struct builtin bintab[] = { /* Copied from BUILTIN("local"), "P" added */ - BUILTIN("private", BINF_PLUSOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL | BINF_ASSIGN, (HandlerFunc)bin_private, 0, -1, 0, "AE:%F:%HL:%PR:%TUZ:%ahi:%lnmprtux", "P") + BUILTIN("private", BINF_PLUSOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL | BINF_ASSIGN, (HandlerFunc)bin_private, 0, -1, 0, "AE:%F:%HL:%PR:%TUZ:%ahi:%lnmrtux", "P") }; static struct features module_features = { diff --git a/Src/params.c b/Src/params.c index fce3af940..b329d2079 100644 --- a/Src/params.c +++ b/Src/params.c @@ -5896,6 +5896,7 @@ static const struct paramtypes pmtypes[] = { { PM_ARRAY, "array", 'a', 0}, { PM_HASHED, "association", 'A', 0}, { 0, "local", 0, PMTF_TEST_LEVEL}, + { PM_HIDE, "hide", 'h', 0 }, { PM_LEFT, "left justified", 'L', PMTF_USE_WIDTH}, { PM_RIGHT_B, "right justified", 'R', PMTF_USE_WIDTH}, { PM_RIGHT_Z, "zero filled", 'Z', PMTF_USE_WIDTH}, @@ -6025,13 +6026,21 @@ printparamnode(HashNode hn, int printflags) printflags |= PRINT_NAMEONLY; if (printflags & (PRINT_TYPESET|PRINT_POSIX_READONLY|PRINT_POSIX_EXPORT)) { - if (p->node.flags & (PM_RO_BY_DESIGN|PM_AUTOLOAD)) { + if (p->node.flags & PM_AUTOLOAD) { /* * It's not possible to restore the state of * these, so don't output. */ return; } + if (p->node.flags & PM_RO_BY_DESIGN) { + /* + * Compromise: cannot be restored out of context, + * but show anyway if printed in scope of declaration + */ + if (p->level != locallevel || p->level == 0) + return; + } /* * The zsh variants of export -p/readonly -p also report other * flags to indicate other attributes or scope. The POSIX variants @@ -6064,8 +6073,19 @@ printparamnode(HashNode hn, int printflags) for (pmptr = pmtypes, i = 0; i < PMTYPES_SIZE; i++, pmptr++) { int doprint = 0; if (pmptr->flags & PMTF_TEST_LEVEL) { - if (p->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)) diff --git a/Test/B02typeset.ztst b/Test/B02typeset.ztst index 8b3988151..d90f17d13 100644 --- a/Test/B02typeset.ztst +++ b/Test/B02typeset.ztst @@ -959,6 +959,20 @@ > [three]='' >) + () { + local -h status + typeset -p status + } +0:parameter hiding preserved by "typeset -p" +>typeset -h status='' + + () { + local status + typeset -p status + } +0:read-only special params are output when localized +>typeset -i10 -r status=0 + (export PATH MANPATH path=(/bin) MANPATH=/ diff --git a/Test/K01nameref.ztst b/Test/K01nameref.ztst index ebb70dd92..ff48e2289 100644 --- a/Test/K01nameref.ztst +++ b/Test/K01nameref.ztst @@ -464,7 +464,7 @@ F:unexpected side-effects of previous tests } 0:up-reference part 3, hidden global >outside ->typeset var +>typeset -h var () { typeset notdef @@ -541,7 +541,7 @@ F:Same test, should part 5 output look like this? fi 0:up-reference part 3, autoloading with hidden special >nameref-local-nameref-local ->typeset parameters +>typeset -h parameters if [[ $options[typesettounset] != on ]]; then ZTST_skip='Ignoring zmodload bug that resets TYPESET_TO_UNSET' diff --git a/Test/V10private.ztst b/Test/V10private.ztst index 9eeda0f47..4140d4e96 100644 --- a/Test/V10private.ztst +++ b/Test/V10private.ztst @@ -28,7 +28,7 @@ print $scalar_test 0:basic scope hiding >toplevel ->local scalar_test +>local hide scalar_test >0 >toplevel @@ -54,7 +54,7 @@ print $+unset_test 0:variable defined only in scope >0 ->local unset_test +>local hide unset_test >setme >0 @@ -70,7 +70,7 @@ } print $array_test 0:nested scope with different type, correctly restored ->local array_test +>local hide array_test >in function >top level @@ -113,7 +113,7 @@ typeset -a hash_test=(top level) typeset -p hash_test inner () { - private -p hash_test + typeset -p hash_test print ${(t)hash_test} ${(kv)hash_test} } outer () { @@ -328,6 +328,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 *?*read-only variable: ptr2 () { @@ -348,10 +349,12 @@ F:See K01nameref.ztst up-reference part 5 F:Here ptr1 finds private ptr2 by scope mismatch F:Assignment silently fails, is that correct? >typeset -n ptr1=ptr2 +>typeset -hn ptr2='' >ptr1=ptr2 >ptr1= >ptr2= >typeset -n ptr1=ptr2 +>typeset -hn ptr2='' *?*no such variable: ptr2 typeset ptr2 @@ -372,11 +375,13 @@ F:Assignment silently fails, is that correct? 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 >ptr1=ptr2 >ptr2=val >ptr1=val >ptr2=val >typeset -n ptr1=ptr2 +>typeset -hn ptr2 >typeset ptr2=val () { -- cgit 1.4.1