about summary refs log tree commit diff
diff options
context:
space:
mode:
authorBart Schaefer <schaefer@zsh.org>2024-02-20 20:16:03 -0800
committerBart Schaefer <schaefer@zsh.org>2024-02-20 20:16:03 -0800
commit6b21e5c0e201876f6659b563b56da9a993ae6c03 (patch)
treea8495275a78da67503895da1a30df15ee676152f
parenta6ea12286709273e7896916dc8a107cd52f01d26 (diff)
downloadzsh-6b21e5c0e201876f6659b563b56da9a993ae6c03.tar.gz
zsh-6b21e5c0e201876f6659b563b56da9a993ae6c03.tar.xz
zsh-6b21e5c0e201876f6659b563b56da9a993ae6c03.zip
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.
-rw-r--r--ChangeLog9
-rw-r--r--Doc/Zsh/builtins.yo8
-rw-r--r--Doc/Zsh/mod_private.yo7
-rw-r--r--Src/Modules/param_private.c2
-rw-r--r--Src/params.c24
-rw-r--r--Test/B02typeset.ztst14
-rw-r--r--Test/K01nameref.ztst4
-rw-r--r--Test/V10private.ztst13
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  <schaefer@zsh.org>
+
+	* 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  <p.w.stephenson@ntlworld.com>
 
 	* 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 `<S>' 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
 
  () {