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

local parameters



-----BEGIN PGP SIGNED MESSAGE-----

This patch fixes handling of local parameters to match ksh.  This is
based on experimentation with pdksh.  The new semantics are that unset
will always delete the parameter node, revealing the parameter in the
outer scope if there is one.  Also, a local parameter can have the same
name as (and therefore hide) a special parameter.

To match ksh, "export" and "typeset -x" are no longer completely
equivalent.  The difference is that "typeset -x" always creates a local
parameter, just like the other uses of "typeset", whereas "export" acts on
an existing parameter if possible, and will otherwise create a parameter
in the global scope.  (Actually, zsh used to forbid exporting local
variables at all, although the code in params.c handles it just fine.)

Special parameters still behave differently from ksh.  In ksh, special
parameter values seem to be obtained each time they are required by
looking up the name, with the effect that special parameters such as
PATH can be given a temporary local value.  If it turns out that POSIX
requires this behaviour, a lot of zsh code will have to change.

In zsh, special parameters are still special: in an exception to the
normal behaviour, they are not deleted when unset.  Consequently, local
special parameters (currently only the ZLE ones) will irreversibly
hide any parameter of the same name in an outer scope.  Furthermore,
to avoid certain problems that have become apparent, changing of the
type of special parameters is forbidden.

This patch really ought to go into 3.0.  I think one or two hunks depend
on changes made in the ZLE parameters patch (3014), but it should be
perfectly safe to just update those bits of code to the state this
patch would leave them in without using anything else from that patch.
The call of unsetparam_pm() that appears in context in this patch should
*not* be changed unless all the relevant parts of 3014 are applied.

 -zefram

 *** Doc/Zsh/builtins.yo	1997/03/29 23:37:14	1.15
 --- Doc/Zsh/builtins.yo	1997/03/29 23:47:42
 ***************
 *** 396,402 ****
   item(tt(export) [ var(name)[tt(=)var(value)] ... ])(
   The specified var(name)s are marked for automatic export
   to the environment of subsequently executed commands.
 ! tt(export) is equivalent to tt(typeset -x).
   )
   findex(false)
   cindex(doing nothing, unsuccessfully)
 --- 396,405 ----
   item(tt(export) [ var(name)[tt(=)var(value)] ... ])(
   The specified var(name)s are marked for automatic export
   to the environment of subsequently executed commands.
 ! Equivalent to tt(typeset -x), except that no parameter will be created
 ! to hide an existing one in an outer scope.
 ! If a parameter specified does not
 ! already exist, it is created in the global scope.
   )
   findex(false)
   cindex(doing nothing, unsuccessfully)
 *** Doc/Zsh/guide.yo	1997/03/29 23:37:15	1.9
 --- Doc/Zsh/guide.yo	1997/03/29 23:37:32
 ***************
 *** 83,88 ****
 --- 83,89 ----
   
   Parameters
   
 + menu(Local Parameters)
   menu(Array Parameters)
   menu(Positional Parameters)
   menu(Parameters Set By The Shell)
 *** Doc/Zsh/params.yo	1997/03/29 23:37:15	1.7
 --- Doc/Zsh/params.yo	1997/03/29 23:38:09
 ***************
 *** 20,31 ****
   If the integer attribute, tt(-i), is set for var(name),
   the var(value) is subject to arithmetic evaluation.
   startmenu()
   menu(Array Parameters)
   menu(Positional Parameters)
   menu(Parameters Set By The Shell)
   menu(Parameters Used By The Shell)
   endmenu()
 ! texinode(Array Parameters)(Positional Parameters)()(Parameters)
   sect(Array Parameters)
   The value of an array parameter may be assigned by writing:
   
 --- 20,50 ----
   If the integer attribute, tt(-i), is set for var(name),
   the var(value) is subject to arithmetic evaluation.
   startmenu()
 + menu(Local Parameters)
   menu(Array Parameters)
   menu(Positional Parameters)
   menu(Parameters Set By The Shell)
   menu(Parameters Used By The Shell)
   endmenu()
 ! texinode(Local Parameters)(Array Parameters)()(Parameters)
 ! sect(Local Parameters)
 ! Shell function executions delimit scopes for shell parameters.
 ! (Parameters are dynamically scoped.)  The tt(typeset) builtin, and its
 ! alternative forms tt(declare), tt(integer), tt(local) and tt(readonly)
 ! (but not tt(export)), can be used to declare a parameter as being local
 ! to the innermost scope.
 ! 
 ! When a parameter is read or assigned to, the
 ! innermost existing parameter of that name is used.  (That is, the
 ! local parameter hides any less-local parameter.)  However, assigning
 ! to a non-existent parameter, or declaring a new parameter with tt(export),
 ! causes it to be created in the em(outer)most scope.
 ! 
 ! Local parameters disappear when their scope ends.
 ! tt(unset) can be used to delete a parameter while it is still in scope; this
 ! will reveal the next outer parameter of the same name.  However, em(special)
 ! parameters are still special when unset.
 ! texinode(Array Parameters)(Positional Parameters)(Local Parameters)(Parameters)
   sect(Array Parameters)
   The value of an array parameter may be assigned by writing:
   
 *** Src/builtin.c	1997/03/29 23:37:23	1.73
 --- Src/builtin.c	1997/03/29 23:53:05
 ***************
 *** 1299,1306 ****
       roff = off;
   
       /* Sanity checks on the options.  Remove conficting options. */
 -     if ((on | off) & PM_EXPORTED)
 - 	func = BIN_EXPORT;
       if (on & PM_INTEGER)
   	off |= PM_RIGHT_B | PM_LEFT | PM_RIGHT_Z | PM_UPPER | PM_ARRAY;
       if (on & PM_LEFT)
 --- 1299,1304 ----
 ***************
 *** 1400,1421 ****
   	    returnval = 1;
   	    continue;
   	}
 - 	if ((pm = (Param) paramtab->getnode(paramtab, asg->name))) {
 - 	    if (pm->flags & PM_SPECIAL) {
 - 		func = 0;
 - 		on = (PM_TYPE(pm->flags) == PM_INTEGER) ?
 - 		    (on &= ~(PM_LEFT | PM_RIGHT_B | PM_RIGHT_Z | PM_UPPER)) :
 - 		    (on & ~PM_INTEGER);
 - 		off &= ~PM_INTEGER;
 - 	    }
 - 	    if (pm->level) {
 - 		if ((on & PM_EXPORTED) && !(on &= ~PM_EXPORTED) && !off)
 - 		    return 1;
 - 	    }
 - 	}
   	bit = 0;    /* flag for switching int<->not-int */
 ! 	if (pm && !(pm->flags & PM_UNSET) && ((((locallevel == pm->level) || func == BIN_EXPORT)
 ! 		&& !(bit = ((off & pm->flags) | (on & ~pm->flags)) & PM_INTEGER)) || (pm->flags & PM_SPECIAL))) {
   	    /* if no flags or values are given, just print this parameter */
   	    if (!on && !roff && !asg->value) {
   		paramtab->printnode((HashNode) pm, 0);
 --- 1398,1409 ----
   	    returnval = 1;
   	    continue;
   	}
   	bit = 0;    /* flag for switching int<->not-int */
 ! 	if ((pm = (Param)paramtab->getnode(paramtab, asg->name)) &&
 ! 	    (((pm->flags & PM_SPECIAL) && pm->level == locallevel) ||
 ! 	     (!(pm->flags & PM_UNSET) &&
 ! 	      ((locallevel == pm->level) || func == BIN_EXPORT) &&
 ! 	      !(bit = ((off & pm->flags) | (on & ~pm->flags)) & PM_INTEGER)))) {
   	    /* if no flags or values are given, just print this parameter */
   	    if (!on && !roff && !asg->value) {
   		paramtab->printnode((HashNode) pm, 0);
 ***************
 *** 1423,1435 ****
   	    }
   	    if ((pm->flags & PM_RESTRICTED) && isset(RESTRICTED)) {
   		zerrnam(name, "%s: restricted", pm->nam, 0);
   		continue;
   	    }
   	    if (PM_TYPE(pm->flags) == PM_ARRAY && (on & PM_UNIQUE) &&
   		!(pm->flags & PM_READONLY & ~off))
   		uniqarray((*pm->gets.afn) (pm));
   	    pm->flags = (pm->flags | on) & ~off;
 ! 	    if ((on & (PM_LEFT | PM_RIGHT_B | PM_RIGHT_Z | PM_INTEGER)) && auxlen)
   		pm->ct = auxlen;
   	    if (PM_TYPE(pm->flags) != PM_ARRAY) {
   		if (pm->flags & PM_EXPORTED) {
 --- 1411,1432 ----
   	    }
   	    if ((pm->flags & PM_RESTRICTED) && isset(RESTRICTED)) {
   		zerrnam(name, "%s: restricted", pm->nam, 0);
 + 		returnval = 1;
 + 		continue;
 + 	    }
 + 	    if((pm->flags & PM_SPECIAL) &&
 + 	       PM_TYPE(on) && PM_TYPE(on) != PM_TYPE(pm->flags)) {
 + 		zerrnam(name, "%s: cannot change type of a special parameter",
 + 		    pm->nam, 0);
 + 		returnval = 1;
   		continue;
   	    }
   	    if (PM_TYPE(pm->flags) == PM_ARRAY && (on & PM_UNIQUE) &&
   		!(pm->flags & PM_READONLY & ~off))
   		uniqarray((*pm->gets.afn) (pm));
   	    pm->flags = (pm->flags | on) & ~off;
 ! 	    if ((on & (PM_LEFT | PM_RIGHT_B | PM_RIGHT_Z | PM_INTEGER)) &&
 ! 		auxlen)
   		pm->ct = auxlen;
   	    if (PM_TYPE(pm->flags) != PM_ARRAY) {
   		if (pm->flags & PM_EXPORTED) {
 *** Src/params.c	1997/03/29 23:37:25	1.41
 --- Src/params.c	1997/03/29 23:37:32
 ***************
 *** 159,180 ****
       noerrs = 0;
   }
   
 ! /* Create a new parameter node */
   
   /**/
   Param
   createparam(char *name, int flags)
   {
 !     Param pm, oldpm, altpm;
 !     int spec;
   
       if (name != nulstring) {
   	oldpm = (Param) paramtab->getnode(paramtab, name);
 - 	spec = oldpm && (oldpm->flags & PM_SPECIAL);
   
 ! 	if ((oldpm && oldpm->level == locallevel) || spec) {
 ! 	    if (oldpm && !(oldpm->flags & PM_UNSET))
   		return NULL;
   	    if ((oldpm->flags & PM_RESTRICTED) && isset(RESTRICTED)) {
   		zerr("%s: restricted", name, 0);
   		return NULL;
 --- 159,186 ----
       noerrs = 0;
   }
   
 ! /* Create a parameter, so that it can be assigned to.  Returns NULL if the *
 !  * parameter already exists or can't be created, otherwise returns the     *
 !  * parameter node.  If a parameter of the same name exists in an outer     *
 !  * scope, it is hidden by a newly created parameter.  An already existing  *
 !  * parameter node at the current level may be `created' and returned       *
 !  * provided it is unset and not special.  If the parameter can't be        *
 !  * created because it already exists, the PM_UNSET flag is cleared.        */
   
   /**/
   Param
   createparam(char *name, int flags)
   {
 !     Param pm, oldpm;
   
       if (name != nulstring) {
   	oldpm = (Param) paramtab->getnode(paramtab, name);
   
 ! 	if (oldpm && oldpm->level == locallevel) {
 ! 	    if (!(oldpm->flags & PM_UNSET) || (oldpm->flags & PM_SPECIAL)) {
 ! 		oldpm->flags &= ~PM_UNSET;
   		return NULL;
 + 	    }
   	    if ((oldpm->flags & PM_RESTRICTED) && isset(RESTRICTED)) {
   		zerr("%s: restricted", name, 0);
   		return NULL;
 ***************
 *** 183,198 ****
   	    pm = oldpm;
   	    pm->ct = 0;
   	    oldpm = pm->old;
 - 	    pm->flags = (flags & (PM_EXPORTED | PM_LEFT | PM_RIGHT_B |
 - 				  PM_RIGHT_Z | PM_LOWER | PM_UPPER |
 - 				  PM_READONLY | PM_TAGGED | PM_UNIQUE)) |
 - 		(pm->flags & (PM_SCALAR | PM_INTEGER | PM_ARRAY | PM_SPECIAL));
 - 	    if (pm->ename &&
 - 		(altpm = (Param) paramtab->getnode(paramtab, pm->ename))) {
 - 		altpm->flags &= ~(PM_UNSET | PM_UNIQUE | PM_UPPER | PM_LEFT |
 - 				  PM_RIGHT_B | PM_RIGHT_Z | PM_LOWER |
 - 				  PM_READONLY | PM_TAGGED | PM_EXPORTED);
 - 	    }
   	} else {
   	    pm = (Param) zcalloc(sizeof *pm);
   	    if ((pm->old = oldpm)) {
 --- 189,194 ----
 ***************
 *** 203,216 ****
   	}
   
   	if (isset(ALLEXPORT) && !oldpm)
 ! 	    pm->flags |= PM_EXPORTED;
 !     } else {
   	pm = (Param) alloc(sizeof *pm);
 ! 	spec = 0;
 !     }
   
 !     if (!spec) {
 ! 	pm->flags = flags;
   	switch (PM_TYPE(flags)) {
   	case PM_SCALAR:
   	    pm->sets.cfn = strsetfn;
 --- 199,210 ----
   	}
   
   	if (isset(ALLEXPORT) && !oldpm)
 ! 	    flags |= PM_EXPORTED;
 !     } else
   	pm = (Param) alloc(sizeof *pm);
 !     pm->flags = flags;
   
 !     if(!(pm->flags & PM_SPECIAL)) {
   	switch (PM_TYPE(flags)) {
   	case PM_SCALAR:
   	    pm->sets.cfn = strsetfn;
 ***************
 *** 1139,1146 ****
   	unsetparam_pm(altpm, 1, exp);
       }
   
 !     if (locallevel >= pm->level &&
 ! 	((locallevel && locallevel == pm->level) || (pm->flags & PM_SPECIAL)))
   	return;
   
       paramtab->removenode(paramtab, pm->nam); /* remove parameter node from table */
 --- 1133,1139 ----
   	unsetparam_pm(altpm, 1, exp);
       }
   
 !     if (locallevel >= pm->level && (pm->flags & PM_SPECIAL))
   	return;
   
       paramtab->removenode(paramtab, pm->nam); /* remove parameter node from table */

-----BEGIN PGP SIGNATURE-----
Version: 2.6.3ia
Charset: ascii

iQCVAwUBMz2tH3D/+HJTpU/hAQHTlQP/ZoylfTupCCuzTKjpMh0v7xWAi4tFaOEW
Mvex38gTfXCLDhfFdrxNiqHDkSSw8W/w6ZgMpuYTVHHsxoTauPHyELpoEEUojl1v
NIcvXAc1Dxtn8FJDp6FQhl1/HoHvwnX+CB5CevAhaXMyrl5OqTJoOvARM6SELvue
5mUpifCebOE=
=KU1g
-----END PGP SIGNATURE-----



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