about summary refs log tree commit diff
diff options
context:
space:
mode:
authorBart Schaefer <schaefer@zsh.org>2023-03-06 20:01:04 -0800
committerBart Schaefer <schaefer@zsh.org>2023-03-06 20:01:04 -0800
commit8d009d35a9eeacb1bbe9399316d2649a47102014 (patch)
tree54b21c0628dd1196c32bc83b8db7f50a9308e4cd
parent0562be0af8127bb728774de47e4e8851461bd8e2 (diff)
downloadzsh-8d009d35a9eeacb1bbe9399316d2649a47102014.tar.gz
zsh-8d009d35a9eeacb1bbe9399316d2649a47102014.tar.xz
zsh-8d009d35a9eeacb1bbe9399316d2649a47102014.zip
51510: Skip namespaces in "set"/"typeset" output, add tests, fix bug
-rw-r--r--ChangeLog5
-rw-r--r--Src/builtin.c14
-rw-r--r--Src/params.c4
-rw-r--r--Src/utils.c8
-rw-r--r--Src/zsh.h1
-rw-r--r--Test/K02parameter.ztst106
6 files changed, 130 insertions, 8 deletions
diff --git a/ChangeLog b/ChangeLog
index 809466c0e..96adb9c57 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,10 @@
 2023-03-06  Bart Schaefer  <schaefer@zsh.org>
 
+	* 51510: Src/builtin.c, Src/params.c, Src/utils.c, Src/zsh.h,
+	Test/K02parameter.ztst: parameters with a leading namespace are
+	skipped in output of "set" and "typeset", add tests for ksh-like
+	parameter handling and fix a bug thus revealed
+
 	* 51509 (+ fix typo): Src/params.c, Src/subst.c, Src/zsh.h: Add
 	${(!)name} for the referred-to parameter of a named reference,
 	and extend ${!name} in ksh emulation for same
diff --git a/Src/builtin.c b/Src/builtin.c
index 11c1ab3a4..d99802f5f 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -2240,7 +2240,8 @@ typeset_single(char *cname, char *pname, Param pm, int func,
 		paramtab->printnode(&pm->node, PRINT_TYPESET);
 	    else if (!OPT_ISSET(ops,'g') &&
 		     (unset(TYPESETSILENT) || OPT_ISSET(ops,'m')))
-		paramtab->printnode(&pm->node, PRINT_INCLUDEVALUE);
+		paramtab->printnode(&pm->node,
+				    PRINT_INCLUDEVALUE|PRINT_WITH_NAMESPACE);
 	    return pm;
 	}
 	if ((pm->node.flags & PM_RESTRICTED) && isset(RESTRICTED)) {
@@ -2274,7 +2275,7 @@ typeset_single(char *cname, char *pname, Param pm, int func,
 	    }
 	}
 	if (OPT_ISSET(ops,'p')) {
-	    paramtab->printnode(&pm->node, PRINT_TYPESET);
+	    paramtab->printnode(&pm->node, PRINT_TYPESET|PRINT_WITH_NAMESPACE);
 	    return pm;
 	}
 	if (usepm == 2)		/* do not change the PM_UNSET flag */
@@ -2662,7 +2663,7 @@ bin_typeset(char *name, char **argv, LinkList assigns, Options ops, int func)
     char *optstr = TYPESET_OPTSTR;
     int on = 0, off = 0, roff, bit = PM_ARRAY;
     int i;
-    int returnval = 0, printflags = 0;
+    int returnval = 0, printflags = PRINT_WITH_NAMESPACE;
     int hasargs = *argv != NULL || (assigns && firstnode(assigns));
 
     /* POSIXBUILTINS is set for bash/ksh and both ignore -p with args */
@@ -2730,7 +2731,6 @@ bin_typeset(char *name, char **argv, LinkList assigns, Options ops, int func)
 
     queue_signals();
 
-    /* Given no arguments, list whatever the options specify. */
     if (OPT_ISSET(ops,'p')) {
 
 	if (isset(POSIXBUILTINS) && SHELL_EMULATION() != EMULATE_KSH) {
@@ -2756,8 +2756,14 @@ bin_typeset(char *name, char **argv, LinkList assigns, Options ops, int func)
 	    /* -p0 treated as -p for consistency */
 	}
     }
+
+    /* Given no arguments, list whatever the options specify. */
     if (!hasargs) {
 	int exclude = 0;
+
+	if (!OPT_ISSET(ops,'m'))
+	    printflags &= ~PRINT_WITH_NAMESPACE;
+	
 	if (!OPT_ISSET(ops,'p')) {
 	    if (!(on|roff))
 		printflags |= PRINT_TYPE;
diff --git a/Src/params.c b/Src/params.c
index 85eaee609..021d341e8 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -5966,6 +5966,10 @@ printparamnode(HashNode hn, int printflags)
     Param p = (Param) hn;
     Param peer = NULL;
 
+    if (!(p->node.flags & PM_HASHELEM) &&
+	!(printflags & PRINT_WITH_NAMESPACE) && *(p->node.nam) == '.')
+	return;
+    
     if (p->node.flags & PM_UNSET) {
 	if ((printflags & (PRINT_POSIX_READONLY|PRINT_POSIX_EXPORT) &&
 	     p->node.flags & (PM_READONLY|PM_EXPORTED)) ||
diff --git a/Src/utils.c b/Src/utils.c
index 8ce9a175d..14ff0ed47 100644
--- a/Src/utils.c
+++ b/Src/utils.c
@@ -4319,13 +4319,13 @@ itype_end(const char *ptr, int itype, int once)
 {
     if (itype == INAMESPC) {
 	itype = IIDENT;
-	if (once == 0 && (!isset(POSIXIDENTIFIERS) || EMULATION(EMULATE_KSH))) {
+	if (!isset(POSIXIDENTIFIERS) || EMULATION(EMULATE_KSH)) {
 	    /* Special case for names containing ".", ksh93 namespaces */
 	    char *t = itype_end(ptr + (*ptr == '.'), itype, 0);
-	    if (t > ptr+1) {
+	    if (t > ptr + (*ptr == '.')) {
 		if (*t == '.')
-		    return itype_end(t+1, itype, 0);
-		else
+		    ptr = t + 1;	/* Fall through */
+		else if (!once)
 		    return t;
 	    }
 	}
diff --git a/Src/zsh.h b/Src/zsh.h
index f3a777045..a0243e98e 100644
--- a/Src/zsh.h
+++ b/Src/zsh.h
@@ -2184,6 +2184,7 @@ typedef groupset *Groupset;
 #define PRINT_LINE	        (1<<6)
 #define PRINT_POSIX_EXPORT	(1<<7)
 #define PRINT_POSIX_READONLY	(1<<8)
+#define PRINT_WITH_NAMESPACE	(1<<9)
 
 /* flags for printing for the whence builtin */
 #define PRINT_WHENCE_CSH	(1<<7)
diff --git a/Test/K02parameter.ztst b/Test/K02parameter.ztst
new file mode 100644
index 000000000..8a1be1e36
--- /dev/null
+++ b/Test/K02parameter.ztst
@@ -0,0 +1,106 @@
+# Test parameter expansion with namespace syntax
+# (heavily borrowed from D04parameter.ztst)
+
+%prep
+
+%test
+
+  .k02.foo='the first parameter'
+  .k02.bar='the second parameter'
+  print -l $.k02.foo ${.k02.bar}
+0:Basic scalars with namespace
+F:Braces are required
+>$.k02.foo
+>the second parameter
+
+  typeset .k02.bar='the second parameter'
+  print -l ${.k02.bar}
+0:Scalar but with typeset
+>the second parameter
+
+  .k02.array1=(the first array)
+  .k02.array2=(the second array)
+  print -l $.k02.array1 ${.k02.array2}
+0:Basic arrays with namespace
+>$.k02.array1
+>the
+>second
+>array
+
+  typeset -a .k02.array2=(the second array)
+  print -l ${.k02.array2}
+0:Array but with typeset
+>the
+>second
+>array
+
+  setopt ksharrays
+  print -l ${.k02.array2}
+  unsetopt ksharrays
+0:Basic ksharray with namespace
+>the
+
+  setopt shwordsplit
+  print -l ${.k02.foo} ${==.k02.bar}
+  unsetopt shwordsplit
+0:Basic shwordsplit with namespace
+>the
+>first
+>parameter
+>the second parameter
+
+  print ${+.k02.foo} ${+.k02.notappearinginthistest}
+0:$+... and namespace
+>1 0
+
+  .k02.x=()
+  print ${+.k02.x} ${+.k02.x[1]} ${+.k02.x[(r)foo]} ${+.k02.x[(r)bar]}
+  .k02.x=(foo)
+  print ${+.k02.x} ${+.k02.x[1]} ${+.k02.x[(r)foo]} ${+.k02.x[(r)bar]}
+0:$+... with arrays and namespace
+>1 0 0 0
+>1 1 1 0
+
+  # See D04 for complete explanation.
+  # For K02 we're just testing that flag syntax works.
+  .k02.foo='<five> {six} (seven) >eight< }nine{ |forty-two| $many$ )ten( more'
+  .k02.array=(${(z).k02.foo})
+  print -l ${(Q).k02.array}
+0:${(z)...} and ${(Q)...} for some hard to parse cases
+><
+>five
+>>
+>{six}
+>(
+>seven
+>)
+>>
+>eight
+><
+>}nine{
+>|
+>forty-two
+>|
+>$many$
+>)
+>ten( more
+
+  .k02.array=(characters in an array)
+  print ${(c)#.k02.array}
+0:${(c)#...}
+>22
+
+  () {
+    typeset -n .k02.ref=.k02.array
+    emulate -L ksh
+    print -l ${!.k02.ref} ${(!).k02.ref} ${.k02.ref}
+  }
+0:namerefs with namespaces
+>.k02.array
+>.k02.array
+>characters
+
+  k.2=test
+  print ${k.2}
+0:Parse without leading dot (future proofing)
+>test