about summary refs log tree commit diff
path: root/Src/params.c
diff options
context:
space:
mode:
Diffstat (limited to 'Src/params.c')
-rw-r--r--Src/params.c153
1 files changed, 121 insertions, 32 deletions
diff --git a/Src/params.c b/Src/params.c
index d92dd228a..75eff1ebb 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -27,6 +27,8 @@
  *
  */
 
+#include <assert.h>
+
 #include "zsh.mdh"
 #include "params.pro"
 
@@ -264,6 +266,7 @@ typedef struct iparam {
     void *gsu;			/* get/set/unset methods */
     int base;			/* output base                           */
     int width;			/* output field width                    */
+    int length;                 /* length of array                       */
     char *env;			/* location in environment, if exported  */
     char *ename;		/* name of corresponding environment var */
     Param old;			/* old struct for use with local         */
@@ -274,7 +277,7 @@ typedef struct iparam {
 static initparam special_params[] ={
 #define GSU(X) BR((GsuScalar)(void *)(&(X)))
 #define NULL_GSU BR((GsuScalar)(void *)NULL)
-#define IPDEF1(A,B,C) {{NULL,A,PM_INTEGER|PM_SPECIAL|C},BR(NULL),GSU(B),10,0,NULL,NULL,NULL,0}
+#define IPDEF1(A,B,C) {{NULL,A,PM_INTEGER|PM_SPECIAL|C},BR(NULL),GSU(B),10,0,0,NULL,NULL,NULL,0}
 IPDEF1("#", pound_gsu, PM_READONLY),
 IPDEF1("ERRNO", errno_gsu, PM_UNSET),
 IPDEF1("GID", gid_gsu, PM_DONTIMPORT | PM_RESTRICTED),
@@ -287,7 +290,7 @@ IPDEF1("UID", uid_gsu, PM_DONTIMPORT | PM_RESTRICTED),
 IPDEF1("EUID", euid_gsu, PM_DONTIMPORT | PM_RESTRICTED),
 IPDEF1("TTYIDLE", ttyidle_gsu, PM_READONLY),
 
-#define IPDEF2(A,B,C) {{NULL,A,PM_SCALAR|PM_SPECIAL|C},BR(NULL),GSU(B),0,0,NULL,NULL,NULL,0}
+#define IPDEF2(A,B,C) {{NULL,A,PM_SCALAR|PM_SPECIAL|C},BR(NULL),GSU(B),0,0,0,NULL,NULL,NULL,0}
 IPDEF2("USERNAME", username_gsu, PM_DONTIMPORT|PM_RESTRICTED),
 IPDEF2("-", dash_gsu, PM_READONLY),
 IPDEF2("histchars", histchars_gsu, PM_DONTIMPORT),
@@ -322,7 +325,7 @@ LCIPDEF("LC_TIME"),
 # endif
 #endif /* USE_LOCALE */
 
-#define IPDEF4(A,B) {{NULL,A,PM_INTEGER|PM_READONLY|PM_SPECIAL},BR((void *)B),GSU(varint_readonly_gsu),10,0,NULL,NULL,NULL,0}
+#define IPDEF4(A,B) {{NULL,A,PM_INTEGER|PM_READONLY|PM_SPECIAL},BR((void *)B),GSU(varint_readonly_gsu),10,0,0,NULL,NULL,NULL,0}
 IPDEF4("!", &lastpid),
 IPDEF4("$", &mypid),
 IPDEF4("?", &lastval),
@@ -331,22 +334,22 @@ IPDEF4("LINENO", &lineno),
 IPDEF4("PPID", &ppid),
 IPDEF4("ZSH_SUBSHELL", &zsh_subshell),
 
-#define IPDEF5(A,B,F) {{NULL,A,PM_INTEGER|PM_SPECIAL},BR((void *)B),GSU(F),10,0,NULL,NULL,NULL,0}
-#define IPDEF5U(A,B,F) {{NULL,A,PM_INTEGER|PM_SPECIAL|PM_UNSET},BR((void *)B),GSU(F),10,0,NULL,NULL,NULL,0}
+#define IPDEF5(A,B,F) {{NULL,A,PM_INTEGER|PM_SPECIAL},BR((void *)B),GSU(F),10,0,0,NULL,NULL,NULL,0}
+#define IPDEF5U(A,B,F) {{NULL,A,PM_INTEGER|PM_SPECIAL|PM_UNSET},BR((void *)B),GSU(F),10,0,0,NULL,NULL,NULL,0}
 IPDEF5("COLUMNS", &zterm_columns, zlevar_gsu),
 IPDEF5("LINES", &zterm_lines, zlevar_gsu),
 IPDEF5U("ZLE_RPROMPT_INDENT", &rprompt_indent, rprompt_indent_gsu),
 IPDEF5("SHLVL", &shlvl, varinteger_gsu),
 
 /* Don't import internal integer status variables. */
-#define IPDEF6(A,B,F) {{NULL,A,PM_INTEGER|PM_SPECIAL|PM_DONTIMPORT},BR((void *)B),GSU(F),10,0,NULL,NULL,NULL,0}
+#define IPDEF6(A,B,F) {{NULL,A,PM_INTEGER|PM_SPECIAL|PM_DONTIMPORT},BR((void *)B),GSU(F),10,0,0,NULL,NULL,NULL,0}
 IPDEF6("OPTIND", &zoptind, varinteger_gsu),
 IPDEF6("TRY_BLOCK_ERROR", &try_errflag, varinteger_gsu),
 IPDEF6("TRY_BLOCK_INTERRUPT", &try_interrupt, varinteger_gsu),
 
-#define IPDEF7(A,B) {{NULL,A,PM_SCALAR|PM_SPECIAL},BR((void *)B),GSU(varscalar_gsu),0,0,NULL,NULL,NULL,0}
-#define IPDEF7R(A,B) {{NULL,A,PM_SCALAR|PM_SPECIAL|PM_DONTIMPORT_SUID},BR((void *)B),GSU(varscalar_gsu),0,0,NULL,NULL,NULL,0}
-#define IPDEF7U(A,B) {{NULL,A,PM_SCALAR|PM_SPECIAL|PM_UNSET},BR((void *)B),GSU(varscalar_gsu),0,0,NULL,NULL,NULL,0}
+#define IPDEF7(A,B) {{NULL,A,PM_SCALAR|PM_SPECIAL},BR((void *)B),GSU(varscalar_gsu),0,0,0,NULL,NULL,NULL,0}
+#define IPDEF7R(A,B) {{NULL,A,PM_SCALAR|PM_SPECIAL|PM_DONTIMPORT_SUID},BR((void *)B),GSU(varscalar_gsu),0,0,0,NULL,NULL,NULL,0}
+#define IPDEF7U(A,B) {{NULL,A,PM_SCALAR|PM_SPECIAL|PM_UNSET},BR((void *)B),GSU(varscalar_gsu),0,0,0,NULL,NULL,NULL,0}
 IPDEF7("OPTARG", &zoptarg),
 IPDEF7("NULLCMD", &nullcmd),
 IPDEF7U("POSTEDIT", &postedit),
@@ -361,7 +364,7 @@ IPDEF7("PS3", &prompt3),
 IPDEF7R("PS4", &prompt4),
 IPDEF7("SPROMPT", &sprompt),
 
-#define IPDEF9F(A,B,C,D) {{NULL,A,D|PM_ARRAY|PM_SPECIAL|PM_DONTIMPORT},BR((void *)B),GSU(vararray_gsu),0,0,NULL,C,NULL,0}
+#define IPDEF9F(A,B,C,D) {{NULL,A,D|PM_ARRAY|PM_SPECIAL|PM_DONTIMPORT},BR((void *)B),GSU(vararray_gsu),0,0,0,NULL,C,NULL,0}
 #define IPDEF9(A,B,C) IPDEF9F(A,B,C,0)
 IPDEF9F("*", &pparams, NULL, PM_ARRAY|PM_SPECIAL|PM_DONTIMPORT|PM_READONLY),
 IPDEF9F("@", &pparams, NULL, PM_ARRAY|PM_SPECIAL|PM_DONTIMPORT|PM_READONLY),
@@ -370,9 +373,9 @@ IPDEF9F("@", &pparams, NULL, PM_ARRAY|PM_SPECIAL|PM_DONTIMPORT|PM_READONLY),
  * This empty row indicates the end of parameters available in
  * all emulations.
  */
-{{NULL,NULL,0},BR(NULL),NULL_GSU,0,0,NULL,NULL,NULL,0},
+{{NULL,NULL,0},BR(NULL),NULL_GSU,0,0,0,NULL,NULL,NULL,0},
 
-#define IPDEF8(A,B,C,D) {{NULL,A,D|PM_SCALAR|PM_SPECIAL},BR((void *)B),GSU(colonarr_gsu),0,0,NULL,C,NULL,0}
+#define IPDEF8(A,B,C,D) {{NULL,A,D|PM_SCALAR|PM_SPECIAL},BR((void *)B),GSU(colonarr_gsu),0,0,0,NULL,C,NULL,0}
 IPDEF8("CDPATH", &cdpath, "cdpath", 0),
 IPDEF8("FIGNORE", &fignore, "fignore", 0),
 IPDEF8("FPATH", &fpath, "fpath", 0),
@@ -385,7 +388,7 @@ IPDEF8("ZSH_EVAL_CONTEXT", &zsh_eval_context, "zsh_eval_context", PM_READONLY),
 /* MODULE_PATH is not imported for security reasons */
 IPDEF8("MODULE_PATH", &module_path, "module_path", PM_DONTIMPORT|PM_RESTRICTED),
 
-#define IPDEF10(A,B) {{NULL,A,PM_ARRAY|PM_SPECIAL},BR(NULL),GSU(B),10,0,NULL,NULL,NULL,0}
+#define IPDEF10(A,B) {{NULL,A,PM_ARRAY|PM_SPECIAL},BR(NULL),GSU(B),10,0,0,NULL,NULL,NULL,0}
 
 /*
  * The following parameters are not available in sh/ksh compatibility *
@@ -420,7 +423,7 @@ IPDEF9F("path", &path, "PATH", PM_RESTRICTED),
 
 IPDEF10("pipestatus", pipestatus_gsu),
 
-{{NULL,NULL,0},BR(NULL),NULL_GSU,0,0,NULL,NULL,NULL,0},
+{{NULL,NULL,0},BR(NULL),NULL_GSU,0,0,0,NULL,NULL,NULL,0},
 };
 
 /*
@@ -440,7 +443,7 @@ IPDEF8("ZSH_EVAL_CONTEXT", &zsh_eval_context, NULL, PM_READONLY),
 /* MODULE_PATH is not imported for security reasons */
 IPDEF8("MODULE_PATH", &module_path, NULL, PM_DONTIMPORT|PM_RESTRICTED),
 
-{{NULL,NULL,0},BR(NULL),NULL_GSU,0,0,NULL,NULL,NULL,0},
+{{NULL,NULL,0},BR(NULL),NULL_GSU,0,0,0,NULL,NULL,NULL,0},
 };
 
 /*
@@ -744,6 +747,20 @@ static int dontimport(int flags)
     return 0;
 }
 
+/**/
+int
+arrcachelen(Param pm)
+{
+    int len;
+
+    len = pm->length;
+    if (len == 0 && pm->u.arr) {
+       len = arrlen(pm->u.arr);
+       pm->length = len;
+    }
+    return len;
+}
+
 /* Set up parameter hash table.  This will add predefined  *
  * parameter entries as well as setting up parameter table *
  * entries for environment variables we inherit.           */
@@ -991,7 +1008,7 @@ createparam(char *name, int flags)
 	    }
 
 	    pm = oldpm;
-	    pm->base = pm->width = 0;
+	    pm->base = pm->width = pm->length = 0;
 	    oldpm = pm->old;
 	} else {
 	    pm = (Param) zshcalloc(sizeof *pm);
@@ -1104,6 +1121,7 @@ copyparam(Param tpm, Param pm, int fakecopy)
      */
     tpm->node.flags = pm->node.flags;
     tpm->base = pm->base;
+    tpm->length = pm->length;
     tpm->width = pm->width;
     tpm->level = pm->level;
     if (!fakecopy)
@@ -1552,7 +1570,12 @@ getarg(char **str, int *inv, Value v, int a2, zlong *w,
 		ta = getarrvalue(v);
 	    if (!ta || !*ta)
 		return !down;
-	    len = arrlen(ta);
+	    if (v->pm->node.flags & PM_CACHELEN) {
+		len = arrcachelen(v->pm);
+		if (v->pm->node.flags & PM_CHECKLEN)
+		    assert(len == arrlen(ta));
+	    } else
+		len = arrlen(ta);
 	    if (beg < 0)
 		beg += len;
 	    if (down) {
@@ -1575,7 +1598,12 @@ getarg(char **str, int *inv, Value v, int a2, zlong *w,
 	    }
 	} else if (word) {
 	    ta = sepsplit(d = s = getstrvalue(v), sep, 1, 1);
-	    len = arrlen(ta);
+	    if (v->pm->node.flags & PM_CACHELEN) {
+		len = arrcachelen(v->pm);
+		if (v->pm->node.flags & PM_CHECKLEN)
+		    assert(len == arrlen(ta));
+	    } else
+		len = arrlen(ta);
 	    if (beg < 0)
 		beg += len;
 	    if (down) {
@@ -2140,10 +2168,20 @@ getstrvalue(Value v)
 	if (v->isarr)
 	    s = sepjoin(ss, NULL, 1);
 	else {
-	    if (v->start < 0)
-		v->start += arrlen(ss);
-	    s = (arrlen_le(ss, v->start) || v->start < 0) ?
-		(char *) hcalloc(1) : ss[v->start];
+	    if (v->pm->node.flags & PM_CACHELEN) {
+		len = arrcachelen(v->pm);
+		if (v->pm->node.flags & PM_CHECKLEN)
+		    assert(v->pm->length == arrlen(ss));
+		if (v->start < 0)
+		    v->start += len;
+		s = (v->start >= len || v->start < 0) ?
+		    (char *) hcalloc(1) : ss[v->start];
+	    } else {
+		if (v->start < 0)
+		    v->start += arrlen(ss);
+		s = (arrlen_le(ss, v->start) || v->start < 0) ?
+		    (char *) hcalloc(1) : ss[v->start];
+	    }
 	}
 	return s;
     case PM_INTEGER:
@@ -2341,10 +2379,20 @@ getarrvalue(Value v)
     s = getvaluearr(v);
     if (v->start == 0 && v->end == -1)
 	return s;
-    if (v->start < 0)
-	v->start += arrlen(s);
-    if (v->end < 0)
-	v->end += arrlen(s) + 1;
+    if (v->pm->node.flags & PM_CACHELEN) {
+	int len = arrcachelen(v->pm);
+	if (v->pm->node.flags & PM_CHECKLEN)
+	    assert(v->pm->length == arrlen(s));
+	if (v->start < 0)
+	    v->start += len;
+	if (v->end < 0)
+	    v->end += len + 1;
+    } else {
+	if (v->start < 0)
+	    v->start += arrlen(s);
+	if (v->end < 0)
+	    v->end += arrlen(s) + 1;
+    }
 
     /* Null if 1) array too short, 2) index still negative */
     if (v->end <= v->start) {
@@ -2353,7 +2401,8 @@ getarrvalue(Value v)
     else if (v->start < 0) {
 	s = arrdup_max(nular, 1);
     }
-    else if (arrlen_le(s, v->start)) {
+    else if ((v->pm->node.flags & PM_CACHELEN) ?
+	     v->start > v->pm->length : arrlen_le(s, v->start)) {
 	/* Handle $ary[i,i] consistently for any $i > $#ary
 	 * and $ary[i,j] consistently for any $j > $i > $#ary
 	 */
@@ -2714,10 +2763,15 @@ setarrvalue(Value v, char **val)
 	char **const old = v->pm->gsu.a->getfn(v->pm);
 	char **new;
 	char **p, **q, **r; /* index variables */
-	const int pre_assignment_length = arrlen(old);
+	int pre_assignment_length = arrcachelen(v->pm);
 	int post_assignment_length;
 	int i;
 
+	if (v->pm->node.flags & PM_CACHELEN) {
+	    if (v->pm->node.flags & PM_CHECKLEN)
+		assert(v->pm->length == arrlen(old));
+	} else
+	    pre_assignment_length = arrlen(old);
 	q = old;
 
 	if ((v->flags & VALFLAG_INV) && unset(KSHARRAYS)) {
@@ -2810,6 +2864,7 @@ setarrvalue(Value v, char **val)
 
                 v->pm->gsu.a->setfn(v->pm, new);
             }
+	    v->pm->length = post_assignment_length;
 
 	    DPUTS2(p - new != post_assignment_length, "setarrvalue: wrong allocation: %d 1= %lu",
 		   post_assignment_length, (unsigned long)(p - new));
@@ -2880,14 +2935,25 @@ getsparam_u(char *s)
 
 /**/
 mod_export char **
-getaparam(char *s)
+getaparam(char *s, int *len)
 {
     struct value vbuf;
     Value v;
 
     if (!idigit(*s) && (v = getvalue(&vbuf, &s, 0)) &&
 	PM_TYPE(v->pm->node.flags) == PM_ARRAY)
+    {
+	if (len) {
+	    if (v->pm->node.flags & PM_CACHELEN) {
+		*len = arrcachelen(v->pm);
+		if (v->pm->node.flags & PM_CHECKLEN)
+		    assert (*len == arrlen(v->pm->gsu.a->getfn(v->pm)));
+	    } else
+		*len = arrlen(v->pm->gsu.a->getfn(v->pm));
+	}
+	//fprintf(stderr, "%i %i\n", v->pm->length, arrlen(v->pm->gsu.a->getfn(v->pm)));
 	return v->pm->gsu.a->getfn(v->pm);
+    }
     return NULL;
 }
 
@@ -3061,7 +3127,10 @@ assignsparam(char *s, char *val, int flags)
 		return v->pm; /* avoid later setstrvalue() call */
 	    case PM_ARRAY:
 	    	if (unset(KSHARRAYS)) {
-		    v->start = arrlen(v->pm->gsu.a->getfn(v->pm));
+		    if (v->pm->node.flags & PM_CACHELEN)
+			v->start = arrcachelen(v->pm);
+		    else
+			v->start = arrlen(v->pm->gsu.a->getfn(v->pm));
 		    v->end = v->start + 1;
 		} else {
 		    /* ksh appends scalar to first element */
@@ -3164,6 +3233,8 @@ assignaparam(char *s, char **val, int flags)
 		char **new;
 		int lv = arrlen(val);
 
+		v->pm->length = lv + 1;
+
 		new = (char **) zalloc(sizeof(char *) * (lv + 2));
 		*new = ztrdup(getstrvalue(v));
 		memcpy(new+1, val, sizeof(char *) * (lv + 1));
@@ -3188,7 +3259,16 @@ assignaparam(char *s, char **val, int flags)
     if (flags & ASSPM_AUGMENT) {
     	if (v->start == 0 && v->end == -1) {
 	    if (PM_TYPE(v->pm->node.flags) & PM_ARRAY) {
-	    	v->start = arrlen(v->pm->gsu.a->getfn(v->pm));
+		if (v->pm->node.flags & PM_CACHELEN) {
+		    v->start = 
+			//arrlen(v->pm->gsu.a->getfn(v->pm));
+			arrcachelen(v->pm);
+		    if (v->pm->node.flags & PM_CHECKLEN)
+			assert(v->pm->length == arrlen(v->pm->gsu.a->getfn(v->pm)));
+		} else {
+		    v->start = 
+			arrlen(v->pm->gsu.a->getfn(v->pm));
+		}
 	    	v->end = v->start + 1;
 	    } else if (PM_TYPE(v->pm->node.flags) & PM_HASHED)
 	    	v->start = -1, v->end = 0;
@@ -3196,7 +3276,16 @@ assignaparam(char *s, char **val, int flags)
 	    if (v->end > 0)
 		v->start = v->end--;
 	    else if (PM_TYPE(v->pm->node.flags) & PM_ARRAY) {
-		v->end = arrlen(v->pm->gsu.a->getfn(v->pm)) + v->end;
+		if (v->pm->node.flags & PM_CACHELEN) {
+		    v->end 
+			//= arrlen(v->pm->gsu.a->getfn(v->pm)) + v->end;
+			+= arrcachelen(v->pm);
+		    if (v->pm->node.flags & PM_CHECKLEN)
+			assert(v->pm->length == arrlen(v->pm->gsu.a->getfn(v->pm)));
+		} else {
+		    v->end 
+			= arrlen(v->pm->gsu.a->getfn(v->pm)) + v->end;
+		}
 		v->start = v->end + 1;
 	    }
 	}