zsh-workers
 help / color / mirror / code / Atom feed
* Re: special/readonly variables in sh emulation
@ 2002-04-03 14:57 Oliver Kiddle
  0 siblings, 0 replies; 11+ messages in thread
From: Oliver Kiddle @ 2002-04-03 14:57 UTC (permalink / raw)
  To: zsh-workers

Bart wrote:
>
> } Should we allow attributes like uppercase and integer to apply across
> } an array like in ksh (this is messier for hashes as each element has
> } its own param)?
> 
> I don't know what the ksh implementation of this is like -- does it apply
> the conversion at fetch time, or at assign time?

Assign time it seems - fetch time would be better in my opinion. The
ksh feature which I was refering to and which I like is:
  $ a=(one two three)
  $ typeset -u a
  $ echo ${a[@]}
  ONE TWO THREE
And similarly for other typeset options such as -i.

And thanks for answering the various questions.

> The way I would structure this is:
> 
> The lowest-level API provides functions to set and get scalars (strings,
> ints, etc.), arrays, array elements, and associative array elements
> (including getting the keys or values).
> 
> An intermediate API provides functions implemented in terms of the above
> to set and get string ranges, array slices, and arrays of associative
> array elements.  Special parameters have the option of implementing only
> the lowest-level API and using the functions from the intermediate one,
> or of providing the intermediate ones for efficiency or other effects.

Ok, that is roughly what the patch I posted was heading towards though
I'm entirely happy with it. To support the specials overriding the
intermediate API you get a fairly big method table. Simple specials
would use the default methods. Unless anyone can think of a better
system than the method tables or come up with a better, more generic
version of the paramdef struct system for setting up specials?

> The complication arises when we add in nested substitutions, where the
> result of an inner substitution has to be treated as a parameter value
> for purposes of outer substitutions.  I suggest we actually create a
> dummy parameter in this case rather than trying to handle everything via
> manipulation of the Value structure -- but that means some pretty heavy
> rewriting of paramsubst() and getarg().

A dummy param might be good. I was sort of hoping to get rid of the
value struct and use start/end ints where necessary but another option
might be a dummy param there to.

> If we did create a dummy parameter, we could even give it a name and
> let the surrounding substitutions refer to it explicitly, e.g.:
> 
> 	... ${$(some command):+blah blah $_ blah blah} ...

That's an interesting idea.

> I haven't looked at your patch in detail yet, but these seems like things
> that could go in the optional intermediate-level API.

It would be useful if someone could look at it just a little bit. What
I'm least sure of is what is needed to support associative specials
properly.

I've not done anything on this since last week - I was away for the
Easter bank holidays.

Oliver

This e-mail and any attachment is for authorised use by the intended recipient(s) only.  It may contain proprietary material, confidential information and/or be subject to legal privilege.  It should not be copied, disclosed to, retained or used by, any other party.  If you are not an intended recipient then please promptly delete this e-mail and any attachment and all copies and inform the sender.  Thank you.


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: special/readonly variables in sh emulation
  2002-03-26 11:09           ` Oliver Kiddle
@ 2002-03-26 16:55             ` Bart Schaefer
  0 siblings, 0 replies; 11+ messages in thread
From: Bart Schaefer @ 2002-03-26 16:55 UTC (permalink / raw)
  To: Oliver Kiddle; +Cc: Zsh hackers list

On Mar 26, 11:09am, Oliver Kiddle wrote:
} 
} What is the second parameter to the unsetfn function? Do we need it?

It's telling the unset function whether the parameter is being unset at
the end of a local parameter scope (value 0), or either globally or by
explicit `unset' command (1).  I don't know if anything actually uses it,
and there's at least one place where it may not be getting propagated
correctly.

} Should I be looking to remove the overloading of ct in the param
} struct?

It wouldn't hurt.

} How essential was the arr cache in the value struct? I don't think
} it should be in the value struct but either a local in getarg() or
} internal to the hash variable implementation.

It's used in several places via getvaluearr(), so at this point it is
relied on by ordinary arrays as well; it's merely not as expensive to
recompute an ordinary array (unless maybe it's a special of some kind).

If your patch is going to do away with getvaluearr(), Value.arr can go
as well.

} Also, what is isarr in the value struct used for? I have a suspicion
} that it is being overloaded a lot?

At its basest level, it tells the parameter substitution code whether the
parameter whose value was fetched may be treated as an array.  It has in
fact been overloaded to pass flags to the associative array scanning code
to tell whether keys or values should be returned and whether to return
all matching items or just the first one found.

} Should we allow attributes like uppercase and integer to apply across
} an array like in ksh (this is messier for hashes as each element has
} its own param)?

I don't know what the ksh implementation of this is like -- does it apply
the conversion at fetch time, or at assign time?

Zsh has the added complication of being able to fetch the keys of an
assoc -- those attributes should not apply in that case.

} What worries me more is that it is making it messier to implement
} all the noddy specials because they then have to worry about things
} like assigning to a string subrange.
} 
} We basically have two interfaces to the parameter system to worry
} about: the places where we can add hooks for specials (currently the
} gets, sets and unsetfn functions) and the interface which the rest of
} zsh can use the manipulate parameters.

Right, and I think these should remain separate.  The problem so far has
been that other code would use whichever level was the fastest or simplest,
rather than respecting what should have been API boundaries.

The way I would structure this is:

The lowest-level API provides functions to set and get scalars (strings,
ints, etc.), arrays, array elements, and associative array elements
(including getting the keys or values).

An intermediate API provides functions implemented in terms of the above
to set and get string ranges, array slices, and arrays of associative
array elements.  Special parameters have the option of implementing only
the lowest-level API and using the functions from the intermediate one,
or of providing the intermediate ones for efficiency or other effects.

The highest level API, used by the rest of zsh, provides all this and
everything else (such as mapping some attributes across array values at
fetch time, if that's appropriate), implemented by calling the two lower
level APIs.

The complication arises when we add in nested substitutions, where the
result of an inner substitution has to be treated as a parameter value
for purposes of outer substitutions.  I suggest we actually create a
dummy parameter in this case rather than trying to handle everything via
manipulation of the Value structure -- but that means some pretty heavy
rewriting of paramsubst() and getarg().

If we did create a dummy parameter, we could even give it a name and
let the surrounding substitutions refer to it explicitly, e.g.:

	... ${$(some command):+blah blah $_ blah blah} ...

could be the same as

	tmp=$(some command)
	... ${tmp:+blah blah $tmp blah blah} ...

} A comment in parameter.c says "the zsh core doesn't support creation of
} special hashes, yet". What functions would we need to provide to better
} support special hashes here?

I think we can defer this until we have the rest of the mess straightened
out.

} Do we ever want to have control over the conversion of a parameter's
} type for the purposes of a special? [...]
} 
} What about other functionality in typeset_single - might that need to
} be overridden for the purposes of a special, e.g. changing the output
} format of a float?

I haven't looked at your patch in detail yet, but these seems like things
that could go in the optional intermediate-level API.

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

Zsh: http://www.zsh.org | PHPerl Project: http://phperl.sourceforge.net   


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: special/readonly variables in sh emulation
  2002-03-20 13:53         ` Peter Stephenson
  2002-03-20 17:41           ` Oliver Kiddle
@ 2002-03-26 11:09           ` Oliver Kiddle
  2002-03-26 16:55             ` Bart Schaefer
  1 sibling, 1 reply; 11+ messages in thread
From: Oliver Kiddle @ 2002-03-26 11:09 UTC (permalink / raw)
  To: Peter Stephenson; +Cc: Zsh hackers list

I've been looking at the whole parameter code thing.

What is the second parameter to the unsetfn function? Do we need it?
Should I be looking to remove the overloading of ct in the param
struct? How essential was the arr cache in the value struct? I don't
think it should be in the value struct but either a local in getarg()
or internal to the hash variable implementation. Also, what is isarr in
the value struct used for? I have a suspicion that it is being
overloaded a lot? Should we allow attributes like uppercase and integer
to apply across an array like in ksh (this is messier for hashes as
each element has its own param)?

On Wed, Mar 20, 2002 at 01:53:00PM +0000, Peter Stephenson wrote:
> Oliver Kiddle wrote:
> > Does that approach sound reasonable?
> 
> It sounds perfectly reasonable, the difficulty is probably how you make
> all the current stuff with getsparam etc. fit in with a table stored in
> the parameter.

What worries me more is that it is making it messier to implement
all the noddy specials because they then have to worry about things
like assigning to a string subrange.

We basically have two interfaces to the parameter system to worry
about: the places where we can add hooks for specials (currently the
gets, sets and unsetfn functions) and the interface which the rest of
zsh can use the manipulate parameters. The difficulty I am having at
the moment is knowing how much funcionality to draw into the functions
which the specials can override. What do we ideally need to do things
like mapfile efficiently beyond get, set and unset?

A comment in parameter.c says "the zsh core doesn't support creation of
special hashes, yet". What functions would we need to provide to better
support special hashes here? If we allow special hashes to effectively
not be a hash table of struct params we could lose some of the
advantages of hashes having been implemented with each element a struct
param. It'd cause problems for namerefs to hash elements. So I'm
unsure. 

Do we ever want to have control over the conversion of a parameter's
type for the purposes of a special? The patch below shows an initial
start where some of the thinking came from 15158. The intention was
that the set functions in the paramfns struct would convert the type of
the parameter and that the get functions would check the type of the
parameter and convert the output. For this to work, the get and set
functions will need to be passed start and end values (or value
structs) to handle ranges. Is this adding anything useful for the
purposes of writing specials or just making them messier? I'm not sure
whether or not to restore the unions for the get and set functions.

What about other functionality in typeset_single - might that need to
be overridden for the purposes of a special, e.g. changing the output
format of a float?

Oliver

Scroll down to zsh.h to see the significant part of this patch. Also
note intgetfn().

Index: Src/builtin.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/builtin.c,v
retrieving revision 1.73
diff -u -r1.73 builtin.c
--- Src/builtin.c	24 Mar 2002 07:56:42 -0000	1.73
+++ Src/builtin.c	26 Mar 2002 10:21:44 -0000
@@ -1699,14 +1699,14 @@
 	    Param apm;
 	    char **x;
 	    if (PM_TYPE(pm->flags) == PM_ARRAY) {
-		x = (*pm->gets.afn)(pm);
+		x = (*pm->m->aget)(pm);
 		uniqarray(x);
 		if (pm->ename && x)
 		    arrfixenv(pm->ename, x);
 	    } else if (PM_TYPE(pm->flags) == PM_SCALAR && pm->ename &&
 		       (apm =
 			(Param) paramtab->getnode(paramtab, pm->ename))) {
-		x = (*apm->gets.afn)(apm);
+		x = (*apm->m->aget)(apm);
 		uniqarray(x);
 		if (x)
 		    arrfixenv(pm->nam, x);
@@ -1871,8 +1871,7 @@
 	 * to make sure we only ever use the colonarr functions
 	 * when u.data is correctly set.
 	 */
-	pm->sets.cfn = colonarrsetfn;
-	pm->gets.cfn = colonarrgetfn;
+	pm->m = &colonarrparamfns;
 	pm->u.data = &altpm->u.arr;
     }
 
@@ -1896,20 +1895,20 @@
 	 */
 	switch (PM_TYPE(pm->flags)) {
 	case PM_SCALAR:
-	    pm->sets.cfn(pm, ztrdup(""));
+	    pm->m->cset(pm, ztrdup(""));
 	    break;
 	case PM_INTEGER:
-	    pm->sets.ifn(pm, 0);
+	    pm->m->iset(pm, 0);
 	    break;
 	case PM_EFLOAT:
 	case PM_FFLOAT:
-	    pm->sets.ffn(pm, 0.0);
+	    pm->m->fset(pm, 0.0);
 	    break;
 	case PM_ARRAY:
-	    pm->sets.afn(pm, mkarray(NULL));
+	    pm->m->aset(pm, mkarray(NULL));
 	    break;
 	case PM_HASHED:
-	    pm->sets.hfn(pm, newparamtable(17, pm->nam));
+	    pm->m->hset(pm, newparamtable(17, pm->nam));
 	    break;
 	}
     }
@@ -2408,7 +2407,7 @@
 	} else if (ss) {
 	    if (PM_TYPE(pm->flags) == PM_HASHED) {
 		HashTable tht = paramtab;
-		if ((paramtab = pm->gets.hfn(pm))) {
+		if ((paramtab = pm->m->hget(pm))) {
 		    *--sse = 0;
 		    unsetparam(ss+1);
 		    *sse = ']';
Index: Src/exec.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/exec.c,v
retrieving revision 1.40
diff -u -r1.40 exec.c
--- Src/exec.c	17 Dec 2001 17:17:38 -0000	1.40
+++ Src/exec.c	26 Mar 2002 10:21:44 -0000
@@ -2460,20 +2460,20 @@
 		tpm->flags = pm->flags;
 		switch (PM_TYPE(pm->flags)) {
 		case PM_SCALAR:
-		    tpm->sets.cfn(tpm, pm->u.str);
+		    tpm->m->cset(tpm, pm->u.str);
 		    break;
 		case PM_INTEGER:
-		    tpm->sets.ifn(tpm, pm->u.val);
+		    tpm->m->iset(tpm, pm->u.val);
 		    break;
 		case PM_EFLOAT:
 		case PM_FFLOAT:
-		    tpm->sets.ffn(tpm, pm->u.dval);
+		    tpm->m->fset(tpm, pm->u.dval);
 		    break;
 		case PM_ARRAY:
-		    tpm->sets.afn(tpm, pm->u.arr);
+		    tpm->m->aset(tpm, pm->u.arr);
 		    break;
 		case PM_HASHED:
-		    tpm->sets.hfn(tpm, pm->u.hash);
+		    tpm->m->hset(tpm, pm->u.hash);
 		    break;
 		}
 	    } else
Index: Src/module.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/module.c,v
retrieving revision 1.9
diff -u -r1.9 module.c
--- Src/module.c	18 May 2001 15:23:09 -0000	1.9
+++ Src/module.c	26 Mar 2002 10:21:44 -0000
@@ -1887,9 +1887,7 @@
 
     pm->level = 0;
     pm->u.data = d->var;
-    pm->sets.ifn = (void (*)(Param, zlong)) d->set;
-    pm->gets.ifn = (zlong (*)(Param)) d->get;
-    pm->unsetfn = (void (*)(Param, int)) d->unset;
+    pm->m = d->m;
 
     return 0;
 }
Index: Src/params.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/params.c,v
retrieving revision 1.63
diff -u -r1.63 params.c
--- Src/params.c	24 Mar 2002 23:52:49 -0000	1.63
+++ Src/params.c	26 Mar 2002 10:21:45 -0000
@@ -107,6 +107,108 @@
 /**/
 mod_export int termflags;
  
+/* Method tables for parameters */
+
+/**/
+struct paramfns colonarrparamfns = {
+    colonarrsetfn, nullintsetfn, nullfloatsetfn, nullarrsetfn, nullhashsetfn,
+    colonarrgetfn, intgetfn, floatgetfn, arrgetfn, hashgetfn,
+    stdunsetfn
+};
+
+/**/
+mod_export struct paramfns roparamfns = {
+    nullstrsetfn, nullintsetfn, nullfloatsetfn, nullarrsetfn, nullhashsetfn,
+    strgetfn, intgetfn, floatgetfn, arrgetfn, hashgetfn,
+    stdunsetfn
+};
+
+struct paramfns stdparamfns = {
+    strsetfn, intsetfn, floatsetfn, arrsetfn, hashsetfn,
+    strgetfn, intgetfn, floatgetfn, arrgetfn, hashgetfn,
+    stdunsetfn
+};
+
+static struct paramfns intvarparamfns = {
+    nullstrsetfn, intvarsetfn, nullfloatsetfn, nullarrsetfn, nullhashsetfn,
+    strgetfn, intvargetfn, floatgetfn, arrgetfn, hashgetfn,
+    stdunsetfn
+};
+
+static struct paramfns rointvarparamfns = {
+    nullstrsetfn, nullintsetfn, nullfloatsetfn, nullarrsetfn, nullhashsetfn,
+    strgetfn, intvargetfn, floatgetfn, arrgetfn, hashgetfn,
+    stdunsetfn
+};
+
+static struct paramfns strvarparamfns = {
+    strvarsetfn, nullintsetfn, nullfloatsetfn, nullarrsetfn, nullhashsetfn,
+    strvargetfn, intgetfn, floatgetfn, arrgetfn, hashgetfn,
+    stdunsetfn
+};
+
+static struct paramfns arrvarparamfns = {
+    nullstrsetfn, nullintsetfn, nullfloatsetfn, arrvarsetfn, nullhashsetfn,
+    strgetfn, intgetfn, floatgetfn, arrvargetfn, hashgetfn,
+    stdunsetfn
+};
+
+/**/
+mod_export struct paramfns hashvarparamfns = {
+    nullstrsetfn, nullintsetfn, nullfloatsetfn, nullarrsetfn, hashsetfn,
+    strgetfn, intgetfn, floatgetfn, arrgetfn, hashgetfn,
+    stdunsetfn
+};
+
+static struct paramfns zlevarparamfns = {
+    nullstrsetfn, zlevarsetfn, nullfloatsetfn, nullarrsetfn, nullhashsetfn,
+    strgetfn, intvargetfn, floatgetfn, arrgetfn, hashgetfn,
+    stdunsetfn
+};
+
+
+static struct paramfns pipestatparamfns = {
+    nullstrsetfn, nullintsetfn, nullfloatsetfn, pipestatsetfn, nullhashsetfn,
+    strgetfn, intgetfn, floatgetfn, pipestatgetfn, hashgetfn,
+    stdunsetfn
+};
+
+#define PFDEF1(A,B,C) static struct paramfns A = { \
+    nullstrsetfn, B, nullfloatsetfn, nullarrsetfn, nullhashsetfn, \
+    strgetfn, C, floatgetfn, arrgetfn, hashgetfn, \
+    stdunsetfn \
+};
+PFDEF1(poundparamfns, nullintsetfn, poundgetfn)
+PFDEF1(errnoparamfns, nullintsetfn, errnogetfn)
+PFDEF1(gidparamfns, gidsetfn, gidgetfn)
+PFDEF1(egidparamfns, egidsetfn, egidgetfn)
+PFDEF1(histsizeparamfns, histsizesetfn, histsizegetfn)
+PFDEF1(randomparamfns, randomsetfn, randomgetfn)
+PFDEF1(savehistparamfns, savehistsizesetfn, savehistsizegetfn)
+PFDEF1(secondsparamfns, secondssetfn, secondsgetfn)
+PFDEF1(uidparamfns, uidsetfn, uidgetfn)
+PFDEF1(euidparamfns, euidsetfn, euidgetfn)
+PFDEF1(ttyidleparamfns, nullintsetfn, ttyidlegetfn)
+
+#define PFDEF2(A,B,C) static struct paramfns A = { \
+    B, intsetfn, nullfloatsetfn, nullarrsetfn, nullhashsetfn, \
+    C, intgetfn, floatgetfn, arrgetfn, hashgetfn, \
+    stdunsetfn \
+};
+PFDEF2(usernameparamfns, usernamesetfn, usernamegetfn)
+PFDEF2(dashparamfns, nullstrsetfn, dashgetfn)
+PFDEF2(histcharsparamfns, histcharssetfn, histcharsgetfn)
+PFDEF2(homeparamfns, homesetfn, homegetfn)
+PFDEF2(termparamfns, termsetfn, termgetfn)
+PFDEF2(wordcharsparamfns, wordcharssetfn, wordcharsgetfn)
+PFDEF2(ifsparamfns, ifssetfn, ifsgetfn)
+PFDEF2(underscoreparamfns, nullstrsetfn, underscoregetfn)
+#ifdef USE_LOCALE
+PFDEF2(langparamfns, langsetfn, strgetfn)
+PFDEF2(lc_allparamfns, lc_allsetfn, strgetfn)
+PFDEF2(lcparamfns, lcsetfn, strgetfn)
+#endif
+
 /* Nodes for special parameters for parameter hash table */
 
 #ifdef HAVE_UNION_INIT
@@ -118,10 +220,8 @@
     struct hashnode *next;
     char *nam;			/* hash data                             */
     int flags;			/* PM_* flags (defined in zsh.h)         */
+    struct paramfns *m;     	/* method table */
     void *value;
-    void (*func1) _((void));	/* set func                              */
-    char *(*func2) _((void));	/* get func                              */
-    void (*unsetfn) _((Param, int));	/* unset func                    */
     int ct;			/* output base or field width            */
     char *env;			/* location in environment, if exported  */
     char *ename;		/* name of corresponding environment var */
@@ -133,33 +233,33 @@
 static initparam special_params[] ={
 #define SFN(X) BR(((void (*)_((Param, char *)))(X)))
 #define GFN(X) BR(((char *(*)_((Param)))(X)))
-#define IPDEF1(A,B,C,D) {NULL,A,PM_INTEGER|PM_SPECIAL|D,BR(NULL),SFN(C),GFN(B),stdunsetfn,10,NULL,NULL,NULL,0}
-IPDEF1("#", poundgetfn, nullintsetfn, PM_READONLY),
-IPDEF1("ERRNO", errnogetfn, nullintsetfn, PM_READONLY),
-IPDEF1("GID", gidgetfn, gidsetfn, PM_DONTIMPORT | PM_RESTRICTED),
-IPDEF1("EGID", egidgetfn, egidsetfn, PM_DONTIMPORT | PM_RESTRICTED),
-IPDEF1("HISTSIZE", histsizegetfn, histsizesetfn, PM_RESTRICTED),
-IPDEF1("RANDOM", randomgetfn, randomsetfn, 0),
-IPDEF1("SAVEHIST", savehistsizegetfn, savehistsizesetfn, PM_RESTRICTED),
-IPDEF1("SECONDS", secondsgetfn, secondssetfn, 0),
-IPDEF1("UID", uidgetfn, uidsetfn, PM_DONTIMPORT | PM_RESTRICTED),
-IPDEF1("EUID", euidgetfn, euidsetfn, PM_DONTIMPORT | PM_RESTRICTED),
-IPDEF1("TTYIDLE", ttyidlegetfn, nullintsetfn, PM_READONLY),
-
-#define IPDEF2(A,B,C,D) {NULL,A,PM_SCALAR|PM_SPECIAL|D,BR(NULL),SFN(C),GFN(B),stdunsetfn,0,NULL,NULL,NULL,0}
-IPDEF2("USERNAME", usernamegetfn, usernamesetfn, PM_DONTIMPORT|PM_RESTRICTED),
-IPDEF2("-", dashgetfn, nullstrsetfn, PM_READONLY),
-IPDEF2("histchars", histcharsgetfn, histcharssetfn, PM_DONTIMPORT),
-IPDEF2("HOME", homegetfn, homesetfn, 0),
-IPDEF2("TERM", termgetfn, termsetfn, 0),
-IPDEF2("WORDCHARS", wordcharsgetfn, wordcharssetfn, 0),
-IPDEF2("IFS", ifsgetfn, ifssetfn, PM_DONTIMPORT),
-IPDEF2("_", underscoregetfn, nullstrsetfn, PM_READONLY),
+#define IPDEF1(A,D,E) {NULL,A,PM_INTEGER|PM_SPECIAL|D,&E,BR(NULL),10,NULL,NULL,NULL,0}
+IPDEF1("#", PM_READONLY, poundparamfns),
+IPDEF1("ERRNO", PM_READONLY, errnoparamfns),
+IPDEF1("GID", PM_DONTIMPORT | PM_RESTRICTED, gidparamfns),
+IPDEF1("EGID", PM_DONTIMPORT | PM_RESTRICTED, egidparamfns),
+IPDEF1("HISTSIZE", PM_RESTRICTED, histsizeparamfns),
+IPDEF1("RANDOM", 0, randomparamfns),
+IPDEF1("SAVEHIST", PM_RESTRICTED, savehistparamfns),
+IPDEF1("SECONDS", 0, secondsparamfns),
+IPDEF1("UID", PM_DONTIMPORT | PM_RESTRICTED, uidparamfns),
+IPDEF1("EUID", PM_DONTIMPORT | PM_RESTRICTED, euidparamfns),
+IPDEF1("TTYIDLE", PM_READONLY, ttyidleparamfns),
+
+#define IPDEF2(A,D,E) {NULL,A,PM_SCALAR|PM_SPECIAL|D,&E,BR(NULL),0,NULL,NULL,NULL,0}
+IPDEF2("USERNAME", PM_DONTIMPORT|PM_RESTRICTED, usernameparamfns),
+IPDEF2("-", PM_READONLY, dashparamfns),
+IPDEF2("histchars", PM_DONTIMPORT, histcharsparamfns),
+IPDEF2("HOME", 0, homeparamfns),
+IPDEF2("TERM", 0, termparamfns),
+IPDEF2("WORDCHARS", 0, wordcharsparamfns),
+IPDEF2("IFS", PM_DONTIMPORT, ifsparamfns),
+IPDEF2("_", PM_READONLY, underscoreparamfns),
 
 #ifdef USE_LOCALE
-# define LCIPDEF(name) IPDEF2(name, strgetfn, lcsetfn, PM_UNSET)
-IPDEF2("LANG", strgetfn, langsetfn, PM_UNSET),
-IPDEF2("LC_ALL", strgetfn, lc_allsetfn, PM_UNSET),
+# define LCIPDEF(name) IPDEF2(name, PM_UNSET, lcparamfns)
+IPDEF2("LANG", PM_UNSET, langparamfns),
+IPDEF2("LC_ALL", PM_UNSET, lc_allparamfns),
 # ifdef LC_COLLATE
 LCIPDEF("LC_COLLATE"),
 # endif
@@ -177,20 +277,20 @@
 # endif
 #endif /* USE_LOCALE */
 
-#define IPDEF4(A,B) {NULL,A,PM_INTEGER|PM_READONLY|PM_SPECIAL,BR((void *)B),SFN(nullintsetfn),GFN(intvargetfn),stdunsetfn,10,NULL,NULL,NULL,0}
+#define IPDEF4(A,B) {NULL,A,PM_INTEGER|PM_READONLY|PM_SPECIAL,&rointvarparamfns,BR((void *)B),10,NULL,NULL,NULL,0}
 IPDEF4("!", &lastpid),
 IPDEF4("$", &mypid),
 IPDEF4("?", &lastval),
 IPDEF4("LINENO", &lineno),
 IPDEF4("PPID", &ppid),
 
-#define IPDEF5(A,B,F) {NULL,A,PM_INTEGER|PM_SPECIAL,BR((void *)B),SFN(F),GFN(intvargetfn),stdunsetfn,10,NULL,NULL,NULL,0}
-IPDEF5("COLUMNS", &columns, zlevarsetfn),
-IPDEF5("LINES", &lines, zlevarsetfn),
-IPDEF5("OPTIND", &zoptind, intvarsetfn),
-IPDEF5("SHLVL", &shlvl, intvarsetfn),
+#define IPDEF5(A,B,C) {NULL,A,PM_INTEGER|PM_SPECIAL,&C,BR((void *)B),10,NULL,NULL,NULL,0}
+IPDEF5("COLUMNS", &columns, zlevarparamfns),
+IPDEF5("LINES", &lines, zlevarparamfns),
+IPDEF5("OPTIND", &zoptind, intvarparamfns),
+IPDEF5("SHLVL", &shlvl, intvarparamfns),
 
-#define IPDEF7(A,B) {NULL,A,PM_SCALAR|PM_SPECIAL,BR((void *)B),SFN(strvarsetfn),GFN(strvargetfn),stdunsetfn,0,NULL,NULL,NULL,0}
+#define IPDEF7(A,B) {NULL,A,PM_SCALAR|PM_SPECIAL,&strvarparamfns,BR((void *)B),0,NULL,NULL,NULL,0}
 IPDEF7("OPTARG", &zoptarg),
 IPDEF7("NULLCMD", &nullcmd),
 IPDEF7("POSTEDIT", &postedit),
@@ -206,7 +306,7 @@
 IPDEF7("SPROMPT", &sprompt),
 IPDEF7("0", &argzero),
 
-#define IPDEF8(A,B,C,D) {NULL,A,D|PM_SCALAR|PM_SPECIAL,BR((void *)B),SFN(colonarrsetfn),GFN(colonarrgetfn),stdunsetfn,0,NULL,C,NULL,0}
+#define IPDEF8(A,B,C,D) {NULL,A,D|PM_SCALAR|PM_SPECIAL,&colonarrparamfns,BR((void *)B),0,NULL,C,NULL,0}
 IPDEF8("CDPATH", &cdpath, "cdpath", 0),
 IPDEF8("FIGNORE", &fignore, "fignore", 0),
 IPDEF8("FPATH", &fpath, "fpath", 0),
@@ -218,17 +318,17 @@
 /* MODULE_PATH is not imported for security reasons */
 IPDEF8("MODULE_PATH", &module_path, "module_path", PM_DONTIMPORT|PM_RESTRICTED),
 
-#define IPDEF9F(A,B,C,D) {NULL,A,D|PM_ARRAY|PM_SPECIAL|PM_DONTIMPORT,BR((void *)B),SFN(arrvarsetfn),GFN(arrvargetfn),stdunsetfn,0,NULL,C,NULL,0}
+#define IPDEF9F(A,B,C,D) {NULL,A,D|PM_ARRAY|PM_SPECIAL|PM_DONTIMPORT,&arrvarparamfns,BR((void *)B),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),
 {NULL, NULL},
-#define IPDEF10(A,B,C) {NULL,A,PM_ARRAY|PM_SPECIAL,BR(NULL),SFN(C),GFN(B),stdunsetfn,10,NULL,NULL,NULL,0}
+#define IPDEF10(A,B) {NULL,A,PM_ARRAY|PM_SPECIAL,&B,BR(NULL),10,NULL,NULL,NULL,0}
 
-/* The following parameters are not avaible in sh/ksh compatibility *
+/* The following parameters are not available in sh/ksh compatibility *
  * mode. All of these have sh compatible equivalents.                */
-IPDEF1("ARGC", poundgetfn, nullintsetfn, PM_READONLY),
-IPDEF2("HISTCHARS", histcharsgetfn, histcharssetfn, PM_DONTIMPORT),
+IPDEF1("ARGC", PM_READONLY, poundparamfns),
+IPDEF2("HISTCHARS", PM_DONTIMPORT, histcharsparamfns),
 IPDEF4("status", &lastval),
 IPDEF7("prompt", &prompt),
 IPDEF7("PROMPT", &prompt),
@@ -248,7 +348,7 @@
 IPDEF9F("module_path", &module_path, "MODULE_PATH", PM_RESTRICTED),
 IPDEF9F("path", &path, "PATH", PM_RESTRICTED),
 
-IPDEF10("pipestatus", pipestatgetfn, pipestatsetfn),
+IPDEF10("pipestatus", pipestatparamfns),
 
 {NULL, NULL}
 };
@@ -448,9 +548,9 @@
     if (v->arr)
 	return v->arr;
     else if (PM_TYPE(v->pm->flags) == PM_ARRAY)
-	return v->arr = v->pm->gets.afn(v->pm);
+	return v->arr = v->pm->m->aget(v->pm);
     else if (PM_TYPE(v->pm->flags) == PM_HASHED) {
-	v->arr = paramvalarr(v->pm->gets.hfn(v->pm), v->isarr);
+	v->arr = paramvalarr(v->pm->m->hget(v->pm), v->isarr);
 	/* Can't take numeric slices of associative arrays */
 	v->start = 0;
 	v->end = numparamvals + 1;
@@ -626,33 +726,7 @@
 static void
 assigngetset(Param pm)
 {
-    switch (PM_TYPE(pm->flags)) {
-    case PM_SCALAR:
-	pm->sets.cfn = strsetfn;
-	pm->gets.cfn = strgetfn;
-	break;
-    case PM_INTEGER:
-	pm->sets.ifn = intsetfn;
-	pm->gets.ifn = intgetfn;
-	break;
-    case PM_EFLOAT:
-    case PM_FFLOAT:
-	pm->sets.ffn = floatsetfn;
-	pm->gets.ffn = floatgetfn;
-	break;
-    case PM_ARRAY:
-	pm->sets.afn = arrsetfn;
-	pm->gets.afn = arrgetfn;
-	break;
-    case PM_HASHED:
-	pm->sets.hfn = hashsetfn;
-	pm->gets.hfn = hashgetfn;
-	break;
-    default:
-	DPUTS(1, "BUG: tried to create param node without valid flag");
-	break;
-    }
-    pm->unsetfn = stdunsetfn;
+  pm->m = &stdparamfns;
 }
 
 /* Create a parameter, so that it can be assigned to.  Returns NULL if the *
@@ -737,7 +811,7 @@
      * Note that tpm, into which we're copying, may not be in permanent
      * storage.  However, the values themselves are later used directly
      * to set the parameter, so must be permanently allocated (in accordance
-     * with sets.?fn() usage).
+     * with m->?set() usage).
      */
     tpm->flags = pm->flags;
     tpm->ct = pm->ct;
@@ -745,20 +819,20 @@
 	tpm->flags &= ~PM_SPECIAL;
     switch (PM_TYPE(pm->flags)) {
     case PM_SCALAR:
-	tpm->u.str = ztrdup(pm->gets.cfn(pm));
+	tpm->u.str = ztrdup(pm->m->cget(pm));
 	break;
     case PM_INTEGER:
-	tpm->u.val = pm->gets.ifn(pm);
+	tpm->u.val = pm->m->iget(pm);
 	break;
     case PM_EFLOAT:
     case PM_FFLOAT:
-	tpm->u.dval = pm->gets.ffn(pm);
+	tpm->u.dval = pm->m->fget(pm);
 	break;
     case PM_ARRAY:
-	tpm->u.arr = zarrdup(pm->gets.afn(pm));
+	tpm->u.arr = zarrdup(pm->m->aget(pm));
 	break;
     case PM_HASHED:
-	tpm->u.hash = copyparamtable(pm->gets.hfn(pm), pm->nam);
+	tpm->u.hash = copyparamtable(pm->m->hget(pm), pm->nam);
 	break;
     }
     /*
@@ -984,10 +1058,10 @@
 	remnulargs(s);	/* This is probably always a no-op, but ... */
     if (!rev) {
 	if (ishash) {
-	    HashTable ht = v->pm->gets.hfn(v->pm);
+	    HashTable ht = v->pm->m->hget(v->pm);
 	    if (!ht) {
 		ht = newparamtable(17, v->pm->nam);
-		v->pm->sets.hfn(v->pm, ht);
+		v->pm->m->hset(v->pm, ht);
 	    }
 	    untokenize(s);
 	    if (!(v->pm = (Param) ht->getnode(ht, s))) {
@@ -1445,15 +1519,15 @@
 	}
 	return s;
     case PM_INTEGER:
-	convbase(buf, v->pm->gets.ifn(v->pm), v->pm->ct);
+	convbase(buf, v->pm->m->iget(v->pm), v->pm->ct);
 	s = dupstring(buf);
 	break;
     case PM_EFLOAT:
     case PM_FFLOAT:
-	s = convfloat(v->pm->gets.ffn(v->pm), v->pm->ct, v->pm->flags, NULL);
+	s = convfloat(v->pm->m->fget(v->pm), v->pm->ct, v->pm->flags, NULL);
 	break;
     case PM_SCALAR:
-	s = v->pm->gets.cfn(v->pm);
+	s = v->pm->m->cget(v->pm);
 	break;
     default:
 	s = NULL;
@@ -1524,9 +1598,9 @@
     if (v->inv)
 	return v->start;
     if (PM_TYPE(v->pm->flags) == PM_INTEGER)
-	return v->pm->gets.ifn(v->pm);
+	return v->pm->m->iget(v->pm);
     if (v->pm->flags & (PM_EFLOAT|PM_FFLOAT))
-	return (zlong)v->pm->gets.ffn(v->pm);
+	return (zlong)v->pm->m->fget(v->pm);
     return mathevali(getstrvalue(v));
 }
 
@@ -1542,10 +1616,10 @@
     } else if (v->inv) {
 	mn.u.l = v->start;
     } else if (PM_TYPE(v->pm->flags) == PM_INTEGER) {
-	mn.u.l = v->pm->gets.ifn(v->pm);
+	mn.u.l = v->pm->m->iget(v->pm);
     } else if (v->pm->flags & (PM_EFLOAT|PM_FFLOAT)) {
 	mn.type = MN_FLOAT;
-	mn.u.d = v->pm->gets.ffn(v->pm);
+	mn.u.d = v->pm->m->fget(v->pm);
     } else
 	return matheval(getstrvalue(v));
     return mn;
@@ -1570,12 +1644,12 @@
 #endif
 	    return;
     } else if (PM_TYPE(pm->flags) == PM_INTEGER)
-	convbase(val = buf, pm->gets.ifn(pm), pm->ct);
+	convbase(val = buf, pm->m->iget(pm), pm->ct);
     else if (pm->flags & (PM_EFLOAT|PM_FFLOAT))
-	val = convfloat(pm->gets.ffn(pm), pm->ct,
+	val = convfloat(pm->m->iget(pm), pm->ct,
 			pm->flags, NULL);
     else
-	val = pm->gets.cfn(pm);
+	val = pm->m->cget(pm);
 
     pm->flags |= PM_EXPORTED;
     pm->env = addenv(pm->nam, val, pm->flags);
@@ -1603,14 +1677,14 @@
     switch (PM_TYPE(v->pm->flags)) {
     case PM_SCALAR:
 	if (v->start == 0 && v->end == -1) {
-	    (v->pm->sets.cfn) (v->pm, val);
+	    (v->pm->m->cset) (v->pm, val);
 	    if (v->pm->flags & (PM_LEFT | PM_RIGHT_B | PM_RIGHT_Z) && !v->pm->ct)
 		v->pm->ct = strlen(val);
 	} else {
 	    char *z, *x;
 	    int zlen;
 
-	    z = dupstring((v->pm->gets.cfn) (v->pm));
+	    z = dupstring((v->pm->m->cget) (v->pm));
 	    zlen = strlen(z);
 	    if (v->inv && unset(KSHARRAYS))
 		v->start--, v->end--;
@@ -1629,13 +1703,13 @@
 	    strncpy(x, z, v->start);
 	    strcpy(x + v->start, val);
 	    strcat(x + v->start, z + v->end);
-	    (v->pm->sets.cfn) (v->pm, x);
+	    (v->pm->m->cset) (v->pm, x);
 	    zsfree(val);
 	}
 	break;
     case PM_INTEGER:
 	if (val) {
-	    (v->pm->sets.ifn) (v->pm, mathevali(val));
+	    (v->pm->m->iset) (v->pm, mathevali(val));
 	    zsfree(val);
 	}
 	if (!v->pm->ct && lastbase != -1)
@@ -1645,7 +1719,7 @@
     case PM_FFLOAT:
 	if (val) {
 	    mnumber mn = matheval(val);
-	    (v->pm->sets.ffn) (v->pm, (mn.type & MN_FLOAT) ? mn.u.d :
+	    (v->pm->m->fset) (v->pm, (mn.type & MN_FLOAT) ? mn.u.d :
 			       (double)mn.u.l);
 	    zsfree(val);
 	}
@@ -1693,13 +1767,13 @@
 	setstrvalue(v, ztrdup(p));
 	break;
     case PM_INTEGER:
-	(v->pm->sets.ifn) (v->pm, (val.type & MN_INTEGER) ? val.u.l :
+	(v->pm->m->iset) (v->pm, (val.type & MN_INTEGER) ? val.u.l :
 			   (zlong) val.u.d);
 	setstrvalue(v, NULL);
 	break;
     case PM_EFLOAT:
     case PM_FFLOAT:
-	(v->pm->sets.ffn) (v->pm, (val.type & MN_INTEGER) ?
+	(v->pm->m->fset) (v->pm, (val.type & MN_INTEGER) ?
 			   (double)val.u.l : val.u.d);
 	setstrvalue(v, NULL);
 	break;
@@ -1730,7 +1804,7 @@
 	if (PM_TYPE(v->pm->flags) == PM_HASHED)
 	    arrhashsetfn(v->pm, val, 0);
 	else
-	    (v->pm->sets.afn) (v->pm, val);
+	    (v->pm->m->aset) (v->pm, val);
     } else if (v->start == -1 && v->end == 0 &&
     	    PM_TYPE(v->pm->flags) == PM_HASHED) {
     	arrhashsetfn(v->pm, val, 1);
@@ -1751,7 +1825,7 @@
 	}
 	if (v->end < v->start)
 	    v->end = v->start;
-	q = old = v->pm->gets.afn(v->pm);
+	q = old = v->pm->m->aget(v->pm);
 	n = arrlen(old);
 	if (v->start < 0) {
 	    v->start += n;
@@ -1779,7 +1853,7 @@
 		*p++ = ztrdup(*q++);
 	*p = NULL;
 
-	(v->pm->sets.afn) (v->pm, new);
+	(v->pm->m->aset) (v->pm, new);
 	freearray(val);
     }
 }
@@ -1841,7 +1915,7 @@
 
     if (!idigit(*s) && (v = getvalue(&vbuf, &s, 0)) &&
 	PM_TYPE(v->pm->flags) == PM_ARRAY)
-	return v->pm->gets.afn(v->pm);
+	return v->pm->m->aget(v->pm);
     return NULL;
 }
 
@@ -1856,7 +1930,7 @@
 
     if (!idigit(*s) && (v = getvalue(&vbuf, &s, 0)) &&
 	PM_TYPE(v->pm->flags) == PM_HASHED)
-	return paramvalarr(v->pm->gets.hfn(v->pm), SCANPM_WANTVALS);
+	return paramvalarr(v->pm->m->hget(v->pm), SCANPM_WANTVALS);
     return NULL;
 }
 
@@ -1871,7 +1945,7 @@
 
     if (!idigit(*s) && (v = getvalue(&vbuf, &s, 0)) &&
 	PM_TYPE(v->pm->flags) == PM_HASHED)
-	return paramvalarr(v->pm->gets.hfn(v->pm), SCANPM_WANTKEYS);
+	return paramvalarr(v->pm->m->hget(v->pm), SCANPM_WANTKEYS);
     return NULL;
 }
 
@@ -1945,7 +2019,7 @@
 		return v->pm; /* avoid later setstrvalue() call */
 	    case PM_ARRAY:
 	    	if (unset(KSHARRAYS)) {
-		    v->start = arrlen(v->pm->gets.afn(v->pm));
+		    v->start = arrlen(v->pm->m->aget(v->pm));
 		    v->end = v->start + 1;
 		} else {
 		    /* ksh appends scalar to first element */
@@ -1960,7 +2034,7 @@
     		if (v->end > 0)
 		    v->start = v->end;
 		else
-		    v->start = v->end = strlen(v->pm->gets.cfn(v->pm)) +
+		    v->start = v->end = strlen(v->pm->m->cget(v->pm)) +
 			v->end + 1;
 	    	break;
 	    case PM_INTEGER:
@@ -2057,7 +2131,7 @@
     if (augment) {
     	if (v->start == 0 && v->end == -1) {
 	    if (PM_TYPE(v->pm->flags) & PM_ARRAY) {
-	    	v->start = arrlen(v->pm->gets.afn(v->pm));
+	    	v->start = arrlen(v->pm->m->aget(v->pm));
 	    	v->end = v->start + 1;
 	    } else if (PM_TYPE(v->pm->flags) & PM_HASHED)
 	    	v->start = -1, v->end = 0;
@@ -2065,7 +2139,7 @@
 	    if (v->end > 0)
 		v->start = v->end--;
 	    else if (PM_TYPE(v->pm->flags) & PM_ARRAY) {
-		v->end = arrlen(v->pm->gets.afn(v->pm)) + v->end;
+		v->end = arrlen(v->pm->m->aget(v->pm)) + v->end;
 		v->start = v->end + 1;
 	    }
 	}
@@ -2225,7 +2299,7 @@
 	zerr("%s: restricted", pm->nam, 0);
 	return;
     }
-    pm->unsetfn(pm, exp);
+    pm->m->unsetfn(pm, exp);
     if ((pm->flags & PM_EXPORTED) && pm->env) {
 	delenv(pm->env);
 	pm->env = NULL;
@@ -2263,7 +2337,7 @@
 	if ((PM_TYPE(oldpm->flags) == PM_SCALAR) &&
 	    !(pm->flags & PM_HASHELEM) &&
 	    (oldpm->flags & PM_NAMEDDIR) &&
-	    oldpm->sets.cfn == strsetfn)
+	    oldpm->m->cset == strsetfn)
 	    adduserdir(oldpm->nam, oldpm->u.str, 0, 0);
 	if (oldpm->flags & PM_EXPORTED) {
 	    /*
@@ -2287,9 +2361,9 @@
 stdunsetfn(Param pm, int exp)
 {
     switch (PM_TYPE(pm->flags)) {
-	case PM_SCALAR: pm->sets.cfn(pm, NULL); break;
-	case PM_ARRAY:  pm->sets.afn(pm, NULL); break;
-	case PM_HASHED: pm->sets.hfn(pm, NULL); break;
+	case PM_SCALAR: pm->m->cset(pm, NULL); break;
+	case PM_ARRAY:  pm->m->aset(pm, NULL); break;
+	case PM_HASHED: pm->m->hset(pm, NULL); break;
 	default:
 	    if (!(pm->flags & PM_SPECIAL))
 	    	pm->u.str = NULL;
@@ -2304,13 +2378,19 @@
 mod_export zlong
 intgetfn(Param pm)
 {
-    return pm->u.val;
+    if (!pm)
+    	return 0;
+    if (PM_TYPE(pm->flags) == PM_INTEGER)
+        return pm->u.val;
+    if (pm->flags & (PM_EFLOAT|PM_FFLOAT))
+        return (zlong)pm->m->fget(pm);
+    return mathevali(pm->m->cget(pm));	
 }
 
 /* Function to set value of an integer parameter */
 
 /**/
-static void
+mod_export void
 intsetfn(Param pm, zlong x)
 {
     pm->u.val = x;
@@ -2319,7 +2399,7 @@
 /* Function to get value of a floating point parameter */
 
 /**/
-static double
+mod_export double
 floatgetfn(Param pm)
 {
     return pm->u.dval;
@@ -2413,7 +2493,7 @@
 {
     /* Best not to shortcut this by using the existing hash table,   *
      * since that could cause trouble for special hashes.  This way, *
-     * it's up to pm->sets.hfn() what to do.                         */
+     * it's up to pm->m->hset() what to do.                         */
     int alen = arrlen(val);
     HashTable opmtab = paramtab, ht = 0;
     char **aptr = val;
@@ -2427,7 +2507,7 @@
 	return;
     }
     if (alen)
-    	if (!(augment && (ht = paramtab = pm->gets.hfn(pm))))
+    	if (!(augment && (ht = paramtab = pm->m->hget(pm))))
 	    ht = paramtab = newparamtable(17, pm->nam);
     while (*aptr) {
 	/* The parameter name is ztrdup'd... */
@@ -2443,14 +2523,13 @@
 	setstrvalue(v, *aptr++);
     }
     paramtab = opmtab;
-    pm->sets.hfn(pm, ht);
+    pm->m->hset(pm, ht);
     free(val);		/* not freearray() */
 }
 
 /*
  * These functions are used as the set function for special parameters that
- * cannot be set by the user.  The set is incomplete as the only such
- * parameters are scalar and integer.
+ * cannot be set by the user.
  */
 
 /**/
@@ -2465,6 +2544,20 @@
 nullintsetfn(Param pm, zlong x)
 {}
 
+/**/
+void
+nullfloatsetfn(Param pm, double x)
+{}
+
+/**/
+void
+nullarrsetfn(Param pm, char **x)
+{}
+
+/**/
+void
+nullhashsetfn(Param pm, HashTable x)
+{}
 
 /* Function to get value of generic special integer *
  * parameter.  data is pointer to global variable   *
@@ -2717,10 +2810,10 @@
 
 /**/
 void
-uidsetfn(Param pm, uid_t x)
+uidsetfn(Param pm, zlong x)
 {
 #ifdef HAVE_SETUID
-    setuid(x);
+    setuid((uid_t)x);
 #endif
 }
 
@@ -2737,10 +2830,10 @@
 
 /**/
 void
-euidsetfn(Param pm, uid_t x)
+euidsetfn(Param pm, zlong x)
 {
 #ifdef HAVE_SETEUID
-    seteuid(x);
+    seteuid((uid_t)x);
 #endif
 }
 
@@ -2757,10 +2850,10 @@
 
 /**/
 void
-gidsetfn(Param pm, gid_t x)
+gidsetfn(Param pm, zlong x)
 {
 #ifdef HAVE_SETUID
-    setgid(x);
+    setgid((gid_t)x);
 #endif
 }
 
@@ -2777,10 +2870,10 @@
 
 /**/
 void
-egidsetfn(Param pm, gid_t x)
+egidsetfn(Param pm, zlong x)
 {
 #ifdef HAVE_SETEUID
-    setegid(x);
+    setegid((gid_t)x);
 #endif
 }
 
@@ -3437,20 +3530,20 @@
 	    if (!(tpm->flags & PM_NORESTORE))
 		switch (PM_TYPE(pm->flags)) {
 		case PM_SCALAR:
-		    pm->sets.cfn(pm, tpm->u.str);
+		    pm->m->cset(pm, tpm->u.str);
 		    break;
 		case PM_INTEGER:
-		    pm->sets.ifn(pm, tpm->u.val);
+		    pm->m->iset(pm, tpm->u.val);
 		    break;
 		case PM_EFLOAT:
 		case PM_FFLOAT:
-		    pm->sets.ffn(pm, tpm->u.dval);
+		    pm->m->fset(pm, tpm->u.dval);
 		    break;
 		case PM_ARRAY:
-		    pm->sets.afn(pm, tpm->u.arr);
+		    pm->m->aset(pm, tpm->u.arr);
 		    break;
 		case PM_HASHED:
-		    pm->sets.hfn(pm, tpm->u.hash);
+		    pm->m->hset(pm, tpm->u.hash);
 		    break;
 		}
 	    zfree(tpm, sizeof(*tpm));
@@ -3476,7 +3569,7 @@
     /* Since the second flag to unsetfn isn't used, I don't *
      * know what its value should be.                       */
     if (delunset)
-	pm->unsetfn(pm, 1);
+	pm->m->unsetfn(pm, 1);
     zsfree(pm->nam);
     /* If this variable was tied by the user, ename was ztrdup'd */
     if (pm->flags & PM_TIED)
@@ -3551,27 +3644,27 @@
     switch (PM_TYPE(p->flags)) {
     case PM_SCALAR:
 	/* string: simple output */
-	if (p->gets.cfn && (t = p->gets.cfn(p)))
+	if (p->m->cget && (t = p->m->cget(p)))
 	    quotedzputs(t, stdout);
 	break;
     case PM_INTEGER:
 	/* integer */
 #ifdef ZSH_64_BIT_TYPE
-	fputs(output64(p->gets.ifn(p)), stdout);
+	fputs(output64(p->m->iget(p)), stdout);
 #else
-	printf("%ld", p->gets.ifn(p));
+	printf("%ld", p->m->iget(p));
 #endif
 	break;
     case PM_EFLOAT:
     case PM_FFLOAT:
 	/* float */
-	convfloat(p->gets.ffn(p), p->ct, p->flags, stdout);
+	convfloat(p->m->fget(p), p->ct, p->flags, stdout);
 	break;
     case PM_ARRAY:
 	/* array */
 	if (!(printflags & PRINT_KV_PAIR))
 	    putchar('(');
-	u = p->gets.afn(p);
+	u = p->m->aget(p);
 	if(*u) {
 	    quotedzputs(*u++, stdout);
 	    while (*u) {
@@ -3587,7 +3680,7 @@
 	if (!(printflags & PRINT_KV_PAIR))
 	    putchar('(');
 	{
-            HashTable ht = p->gets.hfn(p);
+            HashTable ht = p->m->hget(p);
             if (ht)
 		scanhashtable(ht, 0, 0, PM_UNSET,
 			      ht->printnode, PRINT_KV_PAIR);
Index: Src/subst.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/subst.c,v
retrieving revision 1.30
diff -u -r1.30 subst.c
--- Src/subst.c	22 Feb 2002 17:28:06 -0000	1.30
+++ Src/subst.c	26 Mar 2002 10:21:45 -0000
@@ -1261,7 +1261,7 @@
 		aval = getarrvalue(v);
 	} else {
 	    if (v->pm->flags & PM_ARRAY) {
-		int tmplen = arrlen(v->pm->gets.afn(v->pm));
+		int tmplen = arrlen(v->pm->m->aget(v->pm));
 
 		if (v->start < 0)
 		    v->start += tmplen + v->inv;
@@ -1539,7 +1539,7 @@
 		    if (arrasg > 1) {
 			Param pm = sethparam(idbeg, a);
 			if (pm)
-			    aval = paramvalarr(pm->gets.hfn(pm), hkeys|hvals);
+			    aval = paramvalarr(pm->m->hget(pm), hkeys|hvals);
 		    } else
 			setaparam(idbeg, a);
 		} else {
Index: Src/zsh.h
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/zsh.h,v
retrieving revision 1.36
diff -u -r1.36 zsh.h
--- Src/zsh.h	17 Dec 2001 17:17:38 -0000	1.36
+++ Src/zsh.h	26 Mar 2002 10:21:45 -0000
@@ -294,6 +294,7 @@
 typedef struct alias     *Alias;
 typedef struct param     *Param;
 typedef struct paramdef  *Paramdef;
+typedef struct paramfns  *ParamFns;
 typedef struct cmdnam    *Cmdnam;
 typedef struct shfunc    *Shfunc;
 typedef struct funcstack *Funcstack;
@@ -1051,6 +1052,7 @@
     HashNode next;		/* next in hash chain */
     char *nam;			/* hash data          */
     int flags;			/* PM_* flags         */
+    ParamFns m;     	    	/* method table       */
 
     /* the value of this parameter */
     union {
@@ -1063,27 +1065,6 @@
         HashTable hash;		/* value if declared assoc   (PM_HASHED)  */
     } u;
 
-    /* pointer to function to set value of this parameter */
-    union {
-	void (*cfn) _((Param, char *));
-	void (*ifn) _((Param, zlong));
-	void (*ffn) _((Param, double));
-	void (*afn) _((Param, char **));
-        void (*hfn) _((Param, HashTable));
-    } sets;
-
-    /* pointer to function to get value of this parameter */
-    union {
-	char *(*cfn) _((Param));
-	zlong (*ifn) _((Param));
-	double (*ffn) _((Param));
-	char **(*afn) _((Param));
-        HashTable (*hfn) _((Param));
-    } gets;
-
-    /* pointer to function to unset this parameter */
-    void (*unsetfn) _((Param, int));
-
     int ct;			/* output base or field width            */
     char *env;			/* location in environment, if exported  */
     char *ename;		/* name of corresponding environment var */
@@ -1091,6 +1072,27 @@
     int level;			/* if (old != NULL), level of localness  */
 };
 
+
+/* method table for parameters */
+struct paramfns {
+    /* pointer to functions to set value of this parameter */
+    void (*cset) _((Param, char *));
+    void (*iset) _((Param, zlong));
+    void (*fset) _((Param, double));
+    void (*aset) _((Param, char **));
+    void (*hset) _((Param, HashTable));
+
+    /* pointer to function to get value of this parameter */
+    char *(*cget) _((Param));
+    zlong (*iget) _((Param));
+    double (*fget) _((Param));
+    char **(*aget) _((Param));
+    HashTable (*hget) _((Param));
+    
+    /* pointer to function to unset this parameter */
+    void (*unsetfn) _((Param, int));
+};
+
 /* flags for parameters */
 
 /* parameter types */
@@ -1184,9 +1186,7 @@
     char *name;
     int flags;
     void *var;
-    void *set;
-    void *get;
-    void *unset;
+    ParamFns m;
 };
 
 #define PARAMDEF(name, flags, var, set, get, unset) \

This e-mail and any attachment is for authorised use by the intended recipient(s) only.  It may contain proprietary material, confidential information and/or be subject to legal privilege.  It should not be copied, disclosed to, retained or used by, any other party.  If you are not an intended recipient then please promptly delete this e-mail and any attachment and all copies and inform the sender.  Thank you.


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: special/readonly variables in sh emulation
  2002-03-20 13:53         ` Peter Stephenson
@ 2002-03-20 17:41           ` Oliver Kiddle
  2002-03-26 11:09           ` Oliver Kiddle
  1 sibling, 0 replies; 11+ messages in thread
From: Oliver Kiddle @ 2002-03-20 17:41 UTC (permalink / raw)
  To: Peter Stephenson; +Cc: Zsh hackers list

On Wed, Mar 20, 2002 at 01:53:00PM +0000, Peter Stephenson wrote:
> 
> It sounds perfectly reasonable, the difficulty is probably how you make
> all the current stuff with getsparam etc. fit in with a table stored in
> the parameter.

Yes. I was going to try to leave things like getsparam initially so
that I don't break the current stuff.

> This got truncated somehow, I meant the zsh/mapfile module, where
> $mapfile actually reads in a complete file of arbitrary length, and
> `mapfile[...]=' or `vared mapfile[...]' writes a value to it.  The way
> the assignment code works, you have to retrieve the value first (in the
> case of vared, even if you just finished reading and modifying the

Ah, I understand now.

I suppose the problem is that there is a lot of code which reads the
value of a param by going straight to the u union (just grep for
pm->u.str in the source to see). It would be better if all getting
and setting values went through functions in param.c. Calling
something like fetchvalue would return a pointer to a Param but not
actually retrieve the value of the parameter. This could be defered
until actually reading the value. So there will need to be functions
which do things like return association keys or assign to an array
range in the method table. We could even make the param struct an
opaque type - passing Params out as void pointers so that only code
in params.c can dig about inside it. I'm not sure it is worth the
bother though.

Would it be a good idea to allow arrays to be arrays of any type
such as integers. Ksh arrays can be arrays of floats, scalars
or integers but not arrays of arrays or namespaces.

Oliver

This e-mail and any attachment is for authorised use by the intended recipient(s) only.  It may contain proprietary material, confidential information and/or be subject to legal privilege.  It should not be copied, disclosed to, retained or used by, any other party.  If you are not an intended recipient then please promptly delete this e-mail and any attachment and all copies and inform the sender.  Thank you.


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: special/readonly variables in sh emulation
  2002-03-20 12:55       ` Oliver Kiddle
@ 2002-03-20 13:53         ` Peter Stephenson
  2002-03-20 17:41           ` Oliver Kiddle
  2002-03-26 11:09           ` Oliver Kiddle
  0 siblings, 2 replies; 11+ messages in thread
From: Peter Stephenson @ 2002-03-20 13:53 UTC (permalink / raw)
  To: Zsh hackers list

Oliver Kiddle wrote:
> Does that approach sound reasonable?

It sounds perfectly reasonable, the difficulty is probably how you make
all the current stuff with getsparam etc. fit in with a table stored in
the parameter.

> > One other point:  I became aware when writing the map that calls to the
> > system are inefficient.  Even if you're assigning a parameter, there are
> 
> the map?
> and what do you mean by "the system" - the current parameter system?

This got truncated somehow, I meant the zsh/mapfile module, where
$mapfile actually reads in a complete file of arbitrary length, and
`mapfile[...]=' or `vared mapfile[...]' writes a value to it.  The way
the assignment code works, you have to retrieve the value first (in the
case of vared, even if you just finished reading and modifying the
value).  This shouldn't be necessary and it's particularly inefficient
in this case.  This is where intelligent caching could help, at least in
the case where you actually had to read in the file; if you mapped it,
you would have to maintain extra system state information in order to
unmap it and it's probably not worth it.

-- 
Peter Stephenson <pws@csr.com>                  Software Engineer
CSR Ltd., Science Park, Milton Road,
Cambridge, CB4 0WH, UK                          Tel: +44 (0)1223 392070


**********************************************************************
The information transmitted is intended only for the person or
entity to which it is addressed and may contain confidential 
and/or privileged material. 
Any review, retransmission, dissemination or other use of, or
taking of any action in reliance upon, this information by 
persons or entities other than the intended recipient is 
prohibited.  
If you received this in error, please contact the sender and 
delete the material from any computer.
**********************************************************************


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: special/readonly variables in sh emulation
  2002-03-19  1:43     ` Bart Schaefer
@ 2002-03-20 12:55       ` Oliver Kiddle
  2002-03-20 13:53         ` Peter Stephenson
  0 siblings, 1 reply; 11+ messages in thread
From: Oliver Kiddle @ 2002-03-20 12:55 UTC (permalink / raw)
  To: zsh-workers

Bart wrote:
> 
> My suggestion would be simply to disable module autoloading entirely when
> in sh emulation mode (and maybe ksh too).  A sh/ksh script can't possibly
> be expecting a dynamically loaded module, and "compinit" et al. can load
> anything they explicitly need.

That seems like a good plan to me. Perhaps excepting any module
autoloads explicitly defined by the user with zmodload.

> A slightly less drastic approach might be to disable autoloading only for
> non-interactive sh emulation.

I'm not sure that would gain anything and it can make it confusing or
hard to debug when interactive and non-interactive behaviour vary.

> On Mon, 18 Mar 2002, Peter Stephenson wrote:
> 
> > Another is to shift this sort of parameter into a namespace, as we've
> > been planning for a long time.  I think Sven had a way of doing this
> > simply by allowing dots in parameter names --- it wasn't a fully

Has anyone got a message number for that. I don't remember it.

> I've fooled around with this a bit.  The problem is that you have to allow
> the dots only inside ${...}, because lots of things break if $file.ext is
> interpreted as ${file.ext} rather than ${file}.ext.  This is a little
> tricky to acheive, because there'd need to be different typtab[] flags for
> lexing inside braces v. outside.

You would also have to cope with what things like .a..b mean. This
again shows why I think it is not a good idea to just allow dots in
identifiers. It should think of the references as
<identifier>.<identifier> and not as just <identifier>. This is
important with things like namerefs where it has to resolve each
identifier separately.

> On Mon, 18 Mar 2002, Oliver Kiddle wrote:
> > Compound variables could be implemented better by being like
> > associative arrays - the parent is a hash table of the elements the

> In fact, I deliberately used full parameter hash tables for the
> associative array implementation precisely so they could be extended in
> the future to support elements of any type.  What's needed is a sensible
> reference and assignment syntax.

You were very wise then. I can't think of any better assignment or
reference syntax than ksh's. Implementing the nested assignments could
be defered until later.

> > Also, am I right that we *need* a=() to assign an empty array?
> 
> No; `set -A a' will do it.

Hm, not as nice though.

Peter wrote:

> 
> Oliver Kiddle wrote:
> > So to start this off, if we start by getting together a list of:
> > 1. what we think is wrong with the current implementation
> > 2. what it has got right and should be preserved,
> > 3. what new features we might want to support
> > 4. any ideas for the implementation, in particular on the data
> > structure and the interface.
> > 5. anything else
> 
> What's wrong is that it's all very messy; there is a dense hierarchy of

Okay, we're agreed on the problem then. Following paragraphs also
made sense.

> Unfortunately there are dozens of different things you can do with
> parameters:

The whole complexity of parameters makes me think that we need to
evolve it into something better instead of ditching and rewriting.
How complete is the test suite for parameters?

My implementation idea is to take the param struct, get rid of sets,
gets and unsetfn from it and add a new pointer to a method table.

The method table would contain a list of function pointers. These
functions would be the "uniformly defined entry points". It should be
possible to implement a special by overriding the default versions of
these functions.

Initially, I would replace the gets, sets and unsetfn with functions
which pass particular types such as arrays, integers etc. Calling the
array set for an integer would change the parameter's type. The get
functions would not change the parameter but would do a conversion to
return the requested type - much as you described with your contexts
suggestion.

I could then add more functions to the method table bit by bit to move
more functionality in.

Does that approach sound reasonable?

>   - handle quoting, e.g. what a scalar does with an array slice may
>     depend on whether it is in quotes

I can't think of an example of this but this and areas like the value
struct is where I have fewer ideas on implementation.

> Very likely any consistent system would mean revisiting the rules on
> parameter susbstitution, unfortunately.  I suspect however hard we try
> to keep it the same there will be occasions where it doesn't fit.

Parameter substitution is one of the parts which worry me because I
don't understand it at all well.

>From here on, I got very lost:

> One other point:  I became aware when writing the map that calls to the
> system are inefficient.  Even if you're assigning a parameter, there are

the map?
and what do you mean by "the system" - the current parameter system?

Oliver

-- 

This e-mail and any attachment is for authorised use by the intended recipient(s) only.  It may contain proprietary material, confidential information and/or be subject to legal privilege.  It should not be copied, disclosed to, retained or used by, any other party.  If you are not an intended recipient then please promptly delete this e-mail and any attachment and all copies and inform the sender.  Thank you.


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: special/readonly variables in sh emulation
  2002-03-18 15:41   ` Oliver Kiddle
  2002-03-19  1:43     ` Bart Schaefer
@ 2002-03-19 11:27     ` Peter Stephenson
  1 sibling, 0 replies; 11+ messages in thread
From: Peter Stephenson @ 2002-03-19 11:27 UTC (permalink / raw)
  To: Zsh hackers list

Oliver Kiddle wrote:
> So to start this off, if we start by getting together a list of:
> 1. what we think is wrong with the current implementation
> 2. what it has got right and should be preserved,
> 3. what new features we might want to support
> 4. any ideas for the implementation, in particular on the data
> structure and the interface.
> 5. anything else

What's wrong is that it's all very messy; there is a dense hierarchy of
functions in params.c, plus code to handle typeset in builtin.c which
interacts in a non-trivial way with the core code, plus extra code to
handle function scoping, plus quite a lot of duplication of parameter
functionality elsewhere when we need to do something special with
functions, in particular in the special parameter modules.

What we need is a small number of uniformly defined entry points to the
parameter system which hide the workings of the structure.  That way we
can implement particular special parameters any way we like, and can
easily trap all entry points for special handling of discipline
functions.

Ideally --- I don't know if this is feasible --- the parameter type as
well as the representation should be irrelevant to code outside the
parameter system.  It should be possible to change an existing
parameter's type by an assignment, or create a new one at a new scoping
level, by supplying flags to indicate that is allowed or wanted, but the
actual decision about whether to do that should be inside the parameter
system.  This puts the horrible logic in typeset_single() where it
should be.

Unfortunately there are dozens of different things you can do with
parameters:
  When assigning
   - create a new parameter
     - overriding an existing one
       - maybe taking account of whether or not it's special
     - hiding an existing one in a higher function scope
     - converting an old one
       - maybe inheriting some of its properties (for example,
         keeping the value but changing the floating point output format)
  - pass down an input which may be scalar, array, numeric
    (it depends on the type of parameter what it will do with each)
  - handle array slices
  - handle operations on array slices as given by subscript flags
  - handle quoting, e.g. what a scalar does with an array slice may
    depend on whether it is in quotes
  When retrieving
   ... same sort of thing ...

Much of this is currently done by ad hoc code in places like
typeset_single() and paramsubst() which looks at the parameter type and
alters the value accodingly before passing it down for assignment.  It
may be we can't get around all this, and as the type is likely to remain
exposed maybe we can continue to handle it but still keep a neater
interface to the core parameter code.

Maybe we can help things along by introducing contexts.  The arguments
of an array assignment or substitution with explicit word-splitting
would retrieve a parameter in an array context, although the parameter
could be a scalar, or an integer.  (We would need extra flags for types
of associative array substitution, subscripts --- also required in
scalar contexts --- etc.)  This would always return an array, but that
might be a single word.  Similarly, a numeric context would always
return an mnumber, and the parameter code itself would be responsible
for converting the parameter to an mnumber.

This is already roughly what happens, but the interface isn't by any
stretch of the imagination simple or uniform --- sometimes we call the
parameters `gets.?fn' directly, sometimes we use get?param(), sometimes
we have calls to getvalue() to generate intermediate values for
tinkering with.  As far as the `value' struct goes, I would suggest
either we get rid of it, or we use it only inside the parameter system,
or we always use it as part of the parameter interface --- anyway, the
current hybrid is rather a mess.

Also, I don't know what to do about word-splitting.  It might be neater
to make that internal to the parameter system, passing information down
into it.  However, this may be unnecessary.

Very likely any consistent system would mean revisiting the rules on
parameter susbstitution, unfortunately.  I suspect however hard we try
to keep it the same there will be occasions where it doesn't fit.

One other point:  I became aware when writing the map that calls to the
system are inefficient.  Even if you're assigning a parameter, there are
cases when you currently read the value.  So maybe too naive a system of
encapsulation (assuming there's always a real parameter value sitting
there which you can access at any point) isn't the best way of doing
it.  Or maybe (I haven't looked in any detail) it's good enough to be
more careful about separating the retrieval of information about the
parameter from retrieval of its value.

Here's one other idea: suppose we extend the heap system so that anyone
using a heap can test whether the memory is still valid.  Then we can
have a transparent way of caching information for a short time inside
the parameter code --- next time it looks for a value, it can tell if
the cache is valid, and if it is, we are still in the same operation
(because otherwise the heap would have been popped) and it can use
whatever it cached.  I'm not sure how efficiently we can implement the
validity test, however: the first thing that comes to mind is having
heaps `marked' with a single integer which is always incremented and
which eventually simply wraps.  But that's not good enough, since a heap
is still valid when another one is pushed, so it would probably have to
be a linked list of heap ids.  Maybe this idea doesn't gain very much,
but the hope is that you can do repeated operations on parameters in a
simple fashion and rely on them being efficiently implemented
underneath.

I expect you're now as confused as I am.

-- 
Peter Stephenson <pws@csr.com>                  Software Engineer
CSR Ltd., Science Park, Milton Road,
Cambridge, CB4 0WH, UK                          Tel: +44 (0)1223 392070


**********************************************************************
The information transmitted is intended only for the person or
entity to which it is addressed and may contain confidential 
and/or privileged material. 
Any review, retransmission, dissemination or other use of, or
taking of any action in reliance upon, this information by 
persons or entities other than the intended recipient is 
prohibited.  
If you received this in error, please contact the sender and 
delete the material from any computer.
**********************************************************************


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: special/readonly variables in sh emulation
  2002-03-18 15:41   ` Oliver Kiddle
@ 2002-03-19  1:43     ` Bart Schaefer
  2002-03-20 12:55       ` Oliver Kiddle
  2002-03-19 11:27     ` Peter Stephenson
  1 sibling, 1 reply; 11+ messages in thread
From: Bart Schaefer @ 2002-03-19  1:43 UTC (permalink / raw)
  To: zsh-workers

On Mon, 18 Mar 2002, Oliver Kiddle wrote:

> We perhaps ought to rethink the status of any special variables
> in sh emulation mode. Especially those which are autoloaded out of
> places like zsh/parameter. Any ideas on how to solve this?

My suggestion would be simply to disable module autoloading entirely when
in sh emulation mode (and maybe ksh too).  A sh/ksh script can't possibly
be expecting a dynamically loaded module, and "compinit" et al. can load
anything they explicitly need.

A slightly less drastic approach might be to disable autoloading only for
non-interactive sh emulation.

On Mon, 18 Mar 2002, Peter Stephenson wrote:

> Another is to shift this sort of parameter into a namespace, as we've
> been planning for a long time.  I think Sven had a way of doing this
> simply by allowing dots in parameter names --- it wasn't a fully
> featured namespace implementation, but it might be close enough to allow
> us to go over to that if anybody had the time to write it.

I've fooled around with this a bit.  The problem is that you have to allow
the dots only inside ${...}, because lots of things break if $file.ext is
interpreted as ${file.ext} rather than ${file}.ext.  This is a little
tricky to acheive, because there'd need to be different typtab[] flags for
lexing inside braces v. outside.

On Mon, 18 Mar 2002, Oliver Kiddle wrote:

> Compound variables could be implemented better by being like
> associative arrays - the parent is a hash table of the elements the
> only difference being the elements can be any type, and the syntax is
> different. This alone wouldn't be hard to add onto the existing
> parameter code.

In fact, I deliberately used full parameter hash tables for the
associative array implementation precisely so they could be extended in
the future to support elements of any type.  What's needed is a sensible
reference and assignment syntax.

> Also, am I right that we *need* a=() to assign an empty array?

No; `set -A a' will do it.


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: special/readonly variables in sh emulation
  2002-03-18 14:07 ` Peter Stephenson
@ 2002-03-18 15:41   ` Oliver Kiddle
  2002-03-19  1:43     ` Bart Schaefer
  2002-03-19 11:27     ` Peter Stephenson
  0 siblings, 2 replies; 11+ messages in thread
From: Oliver Kiddle @ 2002-03-18 15:41 UTC (permalink / raw)
  To: zsh-workers

Peter wrote:

> I guess the problem is `load=yes' in zleparameter.mdd --- if it wasn't
> always loaded there would be no problem.  Is it just enough to set that
> to `no' and make zle load it when it needs to run a widget?  (If you're
> using zle or completion widgets, all bets about compatibility are off.)

> One way would be to track dependency information better.  zsh/parameter
> is loaded by default because zle needs it.  zle itself is not used in a
> non-interactive shell.  So unless the user has directly registered an
> interest in zsh/parameter we shouldn't load it until we need zle.

>From what I understand, zsh/parameter isn't loaded but we have the
equivalent of zmodload -ap for all it's parameters done somewhere. I'm
not sure that it is particularly connected to zle. We could limit this
autoloading to interactive shells or skip it in sh emulation. As a
short term solution and for 4.0, something like this is probably the
best way to go and I think we should do it regardless of any longer
term ideas like namespaces.

Another thing to consider is that because the parameters in
zsh/parameter are readonly, we could get the parameter autoloading to
allow the parameter to be assigned to without loading the module and
then be used - this would solve both the cases I mentioned. Only
reading from the parameter without first assigning would do the
autoload.

> Another is to shift this sort of parameter into a namespace, as we've
> been planning for a long time.  I think Sven had a way of doing this
> simply by allowing dots in parameter names --- it wasn't a fully
> featured namespace implementation, but it might be close enough to allow

The compound (hierarchical) parameters feature of ksh93 is exactly this
- a hack to allow dots in a parameter name. I think this is a mistake
because you lose the connection between parameters sharing a common
parent. This means that you can't do things like unset a whole
hierarchy by unsetting the parent. Some of these problems led on to the
unfinished namespace idea in ksh93.

Compound variables could be implemented better by being like
associative arrays - the parent is a hash table of the elements the
only difference being the elements can be any type, and the syntax is
different. This alone wouldn't be hard to add onto the existing
parameter code.

It still needs further thought on my part but I think it would be
possible to merge the concepts of namespaces and hierarchical variables
by using lexical constructs to decide when to do things like
copy-on-read for parent variables.

> featured namespace implementation, but it might be close enough to allow
> us to go over to that if anybody had the time to write it.

Depends on what you mean by having time - in each day I don't have much
free but if I start working on the parameter stuff, I'll get there
eventually.

So to start this off, if we start by getting together a list of:
1. what we think is wrong with the current implementation
2. what it has got right and should be preserved,
3. what new features we might want to support
4. any ideas for the implementation, in particular on the data
structure and the interface.
5. anything else
I'd prefer to get it right but if the consensus is in favour of
something quicker and dirtier then fine.

Also, am I right that we *need* a=() to assign an empty array? In ksh,
this is how you define something as a compound variable parent which
I'd prefer to have done with typeset.

Oliver

This e-mail and any attachment is for authorised use by the intended recipient(s) only.  It may contain proprietary material, confidential information and/or be subject to legal privilege.  It should not be copied, disclosed to, retained or used by, any other party.  If you are not an intended recipient then please promptly delete this e-mail and any attachment and all copies and inform the sender.  Thank you.


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: special/readonly variables in sh emulation
  2002-03-18 12:56 Oliver Kiddle
@ 2002-03-18 14:07 ` Peter Stephenson
  2002-03-18 15:41   ` Oliver Kiddle
  0 siblings, 1 reply; 11+ messages in thread
From: Peter Stephenson @ 2002-03-18 14:07 UTC (permalink / raw)
  To: Zsh hackers list

Oliver Kiddle wrote:
> We perhaps ought to rethink the status of any special variables
> in sh emulation mode. Especially those which are autoloaded out of
> places like zsh/parameter. Any ideas on how to solve this?

Yes, this looks like a big compatibility problem if it's happening in sh
mode.

I guess the problem is `load=yes' in zleparameter.mdd --- if it wasn't
always loaded there would be no problem.  Is it just enough to set that
to `no' and make zle load it when it needs to run a widget?  (If you're
using zle or completion widgets, all bets about compatibility are off.)
If so, we can forget the more sophisticated solutions below which I
wrote before that occurred to me.

One way would be to track dependency information better.  zsh/parameter
is loaded by default because zle needs it.  zle itself is not used in a
non-interactive shell.  So unless the user has directly registered an
interest in zsh/parameter we shouldn't load it until we need zle.

Another is to shift this sort of parameter into a namespace, as we've
been planning for a long time.  I think Sven had a way of doing this
simply by allowing dots in parameter names --- it wasn't a fully
featured namespace implementation, but it might be close enough to allow
us to go over to that if anybody had the time to write it.

Another is to restrict visibility of zsh/parameter to zle somehow unless
the user has asked for it explicitly.

-- 
Peter Stephenson <pws@csr.com>                  Software Engineer
CSR Ltd., Science Park, Milton Road,
Cambridge, CB4 0WH, UK                          Tel: +44 (0)1223 392070


**********************************************************************
The information transmitted is intended only for the person or
entity to which it is addressed and may contain confidential 
and/or privileged material. 
Any review, retransmission, dissemination or other use of, or
taking of any action in reliance upon, this information by 
persons or entities other than the intended recipient is 
prohibited.  
If you received this in error, please contact the sender and 
delete the material from any computer.
**********************************************************************


^ permalink raw reply	[flat|nested] 11+ messages in thread

* special/readonly variables in sh emulation
@ 2002-03-18 12:56 Oliver Kiddle
  2002-03-18 14:07 ` Peter Stephenson
  0 siblings, 1 reply; 11+ messages in thread
From: Oliver Kiddle @ 2002-03-18 12:56 UTC (permalink / raw)
  To: zsh-workers

I've recently set /bin/sh to be zsh on my Debian Linux box to see what
if any problems occur.

The only problem with the init scripts was this:
/etc/rcS.d/S45mountnfs.sh:29: options: attempt to set slice of associative array

The offending line is:
   while read device mountpt fstype options

Everything else was fine including several configure scripts until I
tried to configure, of all things, zsh:

./configure:10594: functions: attempt to set slice of associative array

We perhaps ought to rethink the status of any special variables
in sh emulation mode. Especially those which are autoloaded out of
places like zsh/parameter. Any ideas on how to solve this?

Oliver
-- 

This e-mail and any attachment is for authorised use by the intended recipient(s) only.  It may contain proprietary material, confidential information and/or be subject to legal privilege.  It should not be copied, disclosed to, retained or used by, any other party.  If you are not an intended recipient then please promptly delete this e-mail and any attachment and all copies and inform the sender.  Thank you.


^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2002-04-03 14:57 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2002-04-03 14:57 special/readonly variables in sh emulation Oliver Kiddle
  -- strict thread matches above, loose matches on Subject: below --
2002-03-18 12:56 Oliver Kiddle
2002-03-18 14:07 ` Peter Stephenson
2002-03-18 15:41   ` Oliver Kiddle
2002-03-19  1:43     ` Bart Schaefer
2002-03-20 12:55       ` Oliver Kiddle
2002-03-20 13:53         ` Peter Stephenson
2002-03-20 17:41           ` Oliver Kiddle
2002-03-26 11:09           ` Oliver Kiddle
2002-03-26 16:55             ` Bart Schaefer
2002-03-19 11:27     ` Peter Stephenson

Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/zsh/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).