Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

PATCH: 3.1.5 - keys and values of associative arrays, plus bugfix



This patch implements the syntax that I discussed in my earlier reply to PWS:

zsh% foo[one]=1
zsh% foo[2]=two
zsh% foo[three]=III
zsh% echo $foo
1 III two
zsh% echo ${(k)foo}
one three 2
zsh% echo ${(kv)foo}
one 1 three III 2 two

Note that the keys/values don't appear in any particular order, because this
is after all a hash table.  Some special-casing is probably going to be
needed to make ${(okv)foo} sensible; right now it mixes the keys and values:

zsh% echo ${(okv)foo}
1 2 III one three two

There are two other changes in this patch; first, typeset -H has become -A
for ksh93 compatibility, so you now prefix all of the above foolishness with

zsh% typeset -A foo

Second, I've added "typeset -a" which prints the values of all "ordinary"
array parameters.  It could also be used to declare array parameters, but
for some reason PM_ARRAY is explicitly turned off by bin_typeset() right
before any parameters are created, and I didn't feel like finding out why.

As for the ksh93 "${!foo[@]}" syntax:  Guess what, that !foo is a history
reference, but I took a stab at making it work when emulating ksh.  I have
no idea if the behavior is anything like the real ksh93, though.

The bugfix is to supply an emptytable function in newparamtable() so that
"unset foo" doesn't crash calling through a null function pointer.  This is
probably not a sufficient fix [needs to call unsetparam_pm() repeatedly?]
but at least it doesn't dump core.

Index: Src/builtin.c
===================================================================
--- builtin.c	1998/11/11 17:13:16	1.7
+++ builtin.c	1998/11/12 07:20:21
@@ -50,7 +50,7 @@
     BUILTIN("cd", 0, bin_cd, 0, 2, BIN_CD, NULL, NULL),
     BUILTIN("chdir", 0, bin_cd, 0, 2, BIN_CD, NULL, NULL),
     BUILTIN("continue", BINF_PSPECIAL, bin_break, 0, 1, BIN_CONTINUE, NULL, NULL),
-    BUILTIN("declare", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "HLRUZfilrtux", NULL),
+    BUILTIN("declare", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "ALRUZafilrtux", NULL),
     BUILTIN("dirs", 0, bin_dirs, 0, -1, 0, "v", NULL),
     BUILTIN("disable", 0, bin_enable, 0, -1, BIN_DISABLE, "afmr", NULL),
     BUILTIN("disown", 0, bin_fg, 0, -1, BIN_DISOWN, NULL, NULL),
@@ -60,7 +60,7 @@
     BUILTIN("enable", 0, bin_enable, 0, -1, BIN_ENABLE, "afmr", NULL),
     BUILTIN("eval", BINF_PSPECIAL, bin_eval, 0, -1, BIN_EVAL, NULL, NULL),
     BUILTIN("exit", BINF_PSPECIAL, bin_break, 0, 1, BIN_EXIT, NULL, NULL),
-    BUILTIN("export", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, BIN_EXPORT, "LRUZfilrtu", "x"),
+    BUILTIN("export", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, BIN_EXPORT, "LRUZafilrtu", "x"),
     BUILTIN("false", 0, bin_false, 0, -1, 0, NULL, NULL),
     BUILTIN("fc", BINF_FCOPTS, bin_fc, 0, -1, BIN_FC, "nlreIRWAdDfEim", NULL),
     BUILTIN("fg", 0, bin_fg, 0, -1, BIN_FG, NULL, NULL),
@@ -78,7 +78,7 @@
     BUILTIN("jobs", 0, bin_fg, 0, -1, BIN_JOBS, "dlpZrs", NULL),
     BUILTIN("kill", 0, bin_kill, 0, -1, 0, NULL, NULL),
     BUILTIN("let", 0, bin_let, 1, -1, 0, NULL, NULL),
-    BUILTIN("local", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "HLRUZilrtu", NULL),
+    BUILTIN("local", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "ALRUZailrtu", NULL),
     BUILTIN("log", 0, bin_log, 0, 0, 0, NULL, NULL),
     BUILTIN("logout", 0, bin_break, 0, 1, BIN_LOGOUT, NULL, NULL),
 
@@ -93,7 +93,7 @@
     BUILTIN("pwd", 0, bin_pwd, 0, 0, 0, "rLP", NULL),
     BUILTIN("r", BINF_R, bin_fc, 0, -1, BIN_FC, "nrl", NULL),
     BUILTIN("read", 0, bin_read, 0, -1, 0, "rzu0123456789pkqecnAlE", NULL),
-    BUILTIN("readonly", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "LRUZfiltux", "r"),
+    BUILTIN("readonly", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "ALRUZafiltux", "r"),
     BUILTIN("rehash", 0, bin_hash, 0, 0, 0, "dfv", "r"),
     BUILTIN("return", BINF_PSPECIAL, bin_break, 0, 1, BIN_RETURN, NULL, NULL),
     BUILTIN("set", BINF_PSPECIAL, bin_set, 0, -1, 0, NULL, NULL),
@@ -107,7 +107,7 @@
     BUILTIN("trap", BINF_PSPECIAL, bin_trap, 0, -1, 0, NULL, NULL),
     BUILTIN("true", 0, bin_true, 0, -1, 0, NULL, NULL),
     BUILTIN("type", 0, bin_whence, 0, -1, 0, "ampfsw", "v"),
-    BUILTIN("typeset", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "HLRUZfilrtuxm", NULL),
+    BUILTIN("typeset", BINF_TYPEOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL, bin_typeset, 0, -1, 0, "ALRUZafilrtuxm", NULL),
     BUILTIN("umask", 0, bin_umask, 0, 1, 0, "S", NULL),
     BUILTIN("unalias", 0, bin_unhash, 1, -1, 0, "m", "a"),
     BUILTIN("unfunction", 0, bin_unhash, 1, -1, 0, "m", "f"),
@@ -1469,8 +1469,8 @@
     Param pm;
     Asgment asg;
     Comp com;
-    char *optstr = "iLRZlurtxU----H";
-    int on = 0, off = 0, roff, bit = PM_INTEGER;
+    char *optstr = "aiLRZlurtxU----A";
+    int on = 0, off = 0, roff, bit = PM_ARRAY;
     int initon, initoff, of, i;
     int returnval = 0, printflags = 0;
 
Index: Src/params.c
===================================================================
--- params.c	1998/11/12 04:26:03	1.7
+++ params.c	1998/11/12 08:05:23
@@ -255,7 +255,7 @@
     HashTable ht = newhashtable(size, name, NULL);
 
     ht->hash        = hasher;
-    ht->emptytable  = NULL;
+    ht->emptytable  = emptyhashtable;
     ht->filltable   = NULL;
     ht->addnode     = addhashnode;
     ht->getnode     = gethashnode2;
@@ -362,9 +362,18 @@
 	return v->arr;
     else if (PM_TYPE(v->pm->flags) == PM_ARRAY)
 	return v->arr = v->pm->gets.afn(v->pm);
-    else if (PM_TYPE(v->pm->flags) == PM_HASHED)
-	return v->arr = paramvalarr(v->pm->gets.hfn(v->pm), 0);
-    else
+    else if (PM_TYPE(v->pm->flags) == PM_HASHED) {
+	unsigned flags = 0;
+	if (v->a)
+	    flags |= SCANPM_WANTKEYS;
+	if (v->b > v->a)
+	    flags |= SCANPM_WANTVALS;
+	v->arr = paramvalarr(v->pm->gets.hfn(v->pm), flags);
+	/* Can't take numeric slices of associative arrays */
+	v->a = 0;
+	v->b = -1;
+	return v->arr;
+    } else
 	return NULL;
 }
 
Index: Src/subst.c
===================================================================
--- subst.c	1998/06/01 17:08:45	1.1.1.1
+++ subst.c	1998/11/12 07:54:31
@@ -716,6 +716,8 @@
     int eval = 0;
     int nojoin = 0;
     char inbrace = 0;		/* != 0 means ${...}, otherwise $... */
+    char hkeys = 0;		/* 1 means get keys from associative array */
+    char hvals = 1;		/* > hkeys get values of associative array */
 
     *s++ = '\0';
     if (!ialnum(*s) && *s != '#' && *s != Pound && *s != '-' &&
@@ -732,7 +734,10 @@
     if (*s == Inbrace) {
 	inbrace = 1;
 	s++;
-	if (*s == '(' || *s == Inpar) {
+	if (*s == '!' && s[1] != Outbrace && emulation == EMULATE_KSH) {
+	    hkeys = 1;
+	    s++;
+	} else if (*s == '(' || *s == Inpar) {
 	    char *t, sav;
 	    int tt = 0;
 	    long num;
@@ -886,6 +891,13 @@
 		    escapes = 1;
 		    break;
 
+		case 'k':
+		    hkeys = 1;
+		    break;
+		case 'v':
+		    hvals = 2;
+		    break;
+
 		default:
 		  flagerr:
 		    zerr("error in flags", NULL, 0);
@@ -986,9 +998,16 @@
 	    if (getindex(&s, v) || s == os)
 		break;
 	}
-	if ((isarr = v->isarr))
+	if ((isarr = v->isarr)) {
+	    /* No way to reach here with v->inv != 0, so getvaluearr() *
+	     * will definitely be called by getarrvalue().  Slicing of *
+	     * associations isn't done, so use v->a and v->b for flags */
+	    if (PM_TYPE(v->pm->flags) == PM_HASHED) {
+		v->a = hkeys;
+		v->b = hvals;
+	    }
 	    aval = getarrvalue(v);
-	else {
+	} else {
 	    if (v->pm->flags & PM_ARRAY) {
 		int tmplen = arrlen(v->pm->gets.afn(v->pm));
 

-- 
Bart Schaefer                                 Brass Lantern Enterprises
http://www.well.com/user/barts              http://www.brasslantern.com



Messages sorted by: Reverse Date, Date, Thread, Author