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

PATCH: 3.1.5-pws-4: typeset fix



"Bart Schaefer" wrote:
> Haven't looked into it any farther yet, but run zsh -f and then (where the
> name "variable" can be any parameter that is not already set):
> 
> zsh% typeset -i variable
> zsh% typeset -m +i variable
> zsh% echo $variable
> 
> and kablooey.

Right, that's it.  I know how attached everyone is to the old typeset
code, but I've finally decided to rewrite it so that it's *gasp*
almost readable.  So far, I haven't done much else to it, though there
are probably other rationalisations which could now be added.

Known changes include:

- typeset -m behaviour is now identical to the behaviour without the
m, with the exception that restricted variables are silently ignored
if necessary (this is what happened before).  There was an additional
bug hidden here, in that the sequences of commands above, changing
`variable' from integer to non-integer, could alter the parameter
table, so it now makes a list of parameters while scanning the table,
and runs through it later.

- I removed the restriction on creating array variables (with -a).
You get an error message if you try to set the array as well.  I
can't see any problem apart from that.

- I also de-dangled some else's.

*** Doc/Zsh/builtins.yo.typeset	Thu Dec 17 17:10:13 1998
--- Doc/Zsh/builtins.yo	Thu Jan 14 16:19:39 1999
***************
*** 947,955 ****
  first assignment.
  )
  item(tt(-a))(
! The names refer to array parameters.  For historical reasons, scalar
! parameters are created even when this flag is specified, but the
! output is restricted to arrays (including associative arrays).
  )
  item(tt(-f))(
  The names refer to functions rather than parameters.  No assignments
--- 947,956 ----
  first assignment.
  )
  item(tt(-a))(
! The names refer to array parameters.  An array parameter may be
! created this way, but it may not be assigned to in the tt(typeset)
! statement.  When displaying, both normal and associative arrays are
! shown.
  )
  item(tt(-f))(
  The names refer to functions rather than parameters.  No assignments
*** Src/builtin.c.typeset	Thu Dec 17 12:17:04 1998
--- Src/builtin.c	Thu Jan 14 15:55:34 1999
***************
*** 1224,1236 ****
  		if (!editor)
  		    editor = DEFAULT_FCEDIT;
  
! 		if (fcedit(editor, fil))
  		    if (stuff(fil))
  			zwarnnam("fc", "%e: %s", s, errno);
  		    else {
  			loop(0,1);
  			retval = lastval;
  		    }
  	    }
  	}
  	unlink(fil);
--- 1224,1237 ----
  		if (!editor)
  		    editor = DEFAULT_FCEDIT;
  
! 		if (fcedit(editor, fil)) {
  		    if (stuff(fil))
  			zwarnnam("fc", "%e: %s", s, errno);
  		    else {
  			loop(0,1);
  			retval = lastval;
  		    }
+ 		}
  	    }
  	}
  	unlink(fil);
***************
*** 1464,1469 ****
--- 1465,1581 ----
      return &asg;
  }
  
+ /* function to set a single parameter */
+ 
+ /**/
+ int
+ typeset_single(char *cname, char *pname, Param pm, int func,
+ 	       int on, int off, int roff, char *value)
+ {
+     int usepm, tc;
+ 
+     /* use the existing pm? */
+     usepm = pm && !(pm->flags & PM_UNSET);
+ 
+     /* Always use an existing pm if special at current locallevel */
+     if (pm && (pm->flags & PM_SPECIAL) && pm->level == locallevel)
+ 	usepm = 1;
+ 
+     /*
+      * Don't use a non-special existing param if
+      *   - the local level has changed, and
+      *   - the function is not `export'.
+      */
+     if (usepm && !(pm->flags & PM_SPECIAL) &&
+ 	locallevel != pm->level && func != BIN_EXPORT)
+ 	usepm = 0;
+ 
+     /* attempting a type conversion? */
+     if ((tc = usepm && (((off & pm->flags) | (on & ~pm->flags)) &
+ 			(PM_INTEGER|PM_HASHED|PM_ARRAY))))
+ 	usepm = 0;
+     if (tc && (pm->flags & PM_SPECIAL)) {
+ 	zerrnam(cname, "%s: can't change type of a special parameter",
+ 		pname, 0);
+ 	return 1;
+     }
+ 
+     if (usepm) {
+ 	if (!on && !roff && !value) {
+ 	    paramtab->printnode((HashNode)pm, 0);
+ 	    return 0;
+ 	}
+ 	if ((pm->flags & PM_RESTRICTED && isset(RESTRICTED))) {
+ 	    zerrnam(cname, "%s: restricted", pname, 0);
+ 	    return 1;
+ 	}
+ 	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;
+ 	/* This auxlen/pm->ct stuff is a nasty hack. */
+ 	if ((on & (PM_LEFT | PM_RIGHT_B | PM_RIGHT_Z | PM_INTEGER)) &&
+ 	    auxlen)
+ 	    pm->ct = auxlen;
+ 	if (!(pm->flags & (PM_ARRAY|PM_HASHED))) {
+ 	    if (pm->flags & PM_EXPORTED) {
+ 		if (!(pm->flags & PM_UNSET) && !pm->env && !value)
+ 		    pm->env = addenv(pname, getsparam(pname));
+ 	    } else if (pm->env) {
+ 		delenv(pm->env);
+ 		zsfree(pm->env);
+ 		pm->env = NULL;
+ 	    }
+ 	    if (value)
+ 		setsparam(pname, ztrdup(value));
+ 	} else if (value) {
+ 	    zwarnnam(cname, "can't assign new value for array %s", pname, 0);
+ 	    return 1;
+ 	}
+ 	return 0;
+     }
+ 
+     /*
+      * We're here either because we're creating a new parameter,
+      * or we're adding a parameter at a different local level,
+      * or we're converting the type of a parameter.  In the
+      * last case only, we need to delete the old parameter.
+      */
+     if (tc) {
+ 	if (pm->flags & PM_READONLY) {
+ 	    on |= ~off & PM_READONLY;
+ 	    pm->flags &= ~PM_READONLY;
+ 	}
+ 	/*
+ 	 * Try to carry over a value, but not when changing from,
+ 	 * to, or between non-scalar types.
+ 	 */
+ 	if (!value && !((pm->flags|on) & (PM_ARRAY|PM_HASHED)))
+ 	    value = dupstring(getsparam(pname));
+ 	/* pname may point to pm->nam which is about to disappear */
+ 	pname = dupstring(pname);
+ 	unsetparam_pm(pm, 0, 1);
+     }
+     /*
+      * Create a new node for a parameter with the flags in `on' minus the
+      * readonly flag
+      */
+     pm = createparam(ztrdup(pname), on & ~PM_READONLY);
+     DPUTS(!pm, "BUG: parameter not created");
+     pm->ct = auxlen;
+     if (func != BIN_EXPORT)
+ 	pm->level = locallevel;
+     if (value && !(pm->flags & (PM_ARRAY|PM_HASHED)))
+ 	setsparam(pname, ztrdup(value));
+     pm->flags |= (on & PM_READONLY);
+     if (value && (pm->flags & (PM_ARRAY|PM_HASHED))) {
+ 	zerrnam(cname, "%s: can't assign initial value for array", pname, 0);
+ 	return 1;
+     }
+ 
+     return 0;
+ }
+ 
  /* declare, export, integer, local, readonly, typeset */
  
  /**/
***************
*** 1475,1481 ****
      Comp com;
      char *optstr = "aiALRZlurtxU";
      int on = 0, off = 0, roff, bit = PM_ARRAY;
!     int initon, initoff, of, i;
      int returnval = 0, printflags = 0;
  
      /* hash -f is really the builtin `functions' */
--- 1587,1593 ----
      Comp com;
      char *optstr = "aiALRZlurtxU";
      int on = 0, off = 0, roff, bit = PM_ARRAY;
!     int i;
      int returnval = 0, printflags = 0;
  
      /* hash -f is really the builtin `functions' */
***************
*** 1521,1527 ****
--- 1633,1643 ----
  
      /* With the -m option, treat arguments as glob patterns */
      if (ops['m']) {
+ 	MUSTUSEHEAP("typeset -m");
  	while ((asg = getasg(*argv++))) {
+ 	    LinkList pmlist = newlinklist();
+ 	    LinkNode pmnode;
+ 
  	    tokenize(asg->name);   /* expand argument */
  	    if (!(com = parsereg(asg->name))) {
  		untokenize(asg->name);
***************
*** 1529,1671 ****
  		returnval = 1;
  		continue;
  	    }
! 	    /* If no options or values are given, display all *
! 	     * parameters matching the glob pattern.          */
! 	    if (!(on || roff || asg->value)) {
! 		scanmatchtable(paramtab, com, 0, 0, paramtab->printnode, 0);
! 		continue;
! 	    }
! 	    /* Since either options or values are given, we search   *
! 	     * through the parameter table and change all parameters *
! 	     * matching the glob pattern to have these flags and/or  *
! 	     * value.                                                */
  	    for (i = 0; i < paramtab->hsize; i++) {
! 		for (pm = (Param) paramtab->nodes[i]; pm; pm = (Param) pm->next) {
  		    if ((pm->flags & PM_RESTRICTED) && isset(RESTRICTED))
  			continue;
! 		    if (domatch(pm->nam, com, 0)) {
! 			/* set up flags if we have any */
! 			if (on || roff) {
! 			    if (PM_TYPE(pm->flags) == PM_ARRAY && (on & PM_UNIQUE) &&
! 				!(pm->flags & PM_READONLY & ~off))
! 				uniqarray((*pm->gets.afn) (pm));
! 			    if ((on & ~pm->flags) & PM_HASHED) {
! 				char *nam = ztrdup(pm->nam);
! 				unsetparam(nam);
! 				pm = createparam(nam, on & ~PM_READONLY);
! 				DPUTS(!pm, "BUG: parameter not created");
! 			    }
! 			    pm->flags = (pm->flags | on) & ~off;
! 			    if (PM_TYPE(pm->flags) != PM_ARRAY &&
! 				PM_TYPE(pm->flags) != PM_HASHED) {
! 				if ((on & (PM_LEFT | PM_RIGHT_B | PM_RIGHT_Z | PM_INTEGER)) && auxlen)
! 				    pm->ct = auxlen;
! 				/* did we just export this? */
! 				if ((pm->flags & PM_EXPORTED) && !pm->env) {
! 				    pm->env = addenv(pm->nam, (asg->value) ? asg->value : getsparam(pm->nam));
! 				} else if (!(pm->flags & PM_EXPORTED) && pm->env) {
! 				/* did we just unexport this? */
! 				    delenv(pm->env);
! 				    zsfree(pm->env);
! 				    pm->env = NULL;
! 				}
! 			    }
! 			}
! 			/* set up a new value if given */
! 			if (asg->value) {
! 			    setsparam(pm->nam, ztrdup(asg->value));
! 			}
! 		    }
  		}
  	    }
  	}
  	return returnval;
      }
  
-     /* Save the values of on, off, and func */
-     initon = on;
-     initoff = off;
-     of = func;
- 
      /* Take arguments literally.  Don't glob */
      while ((asg = getasg(*argv++))) {
- 	/* restore the original values of on, off, and func */
- 	on = initon;
- 	off = initoff;
- 	func = of;
- 	on &= ~PM_ARRAY;
- 
  	/* check if argument is a valid identifier */
  	if (!isident(asg->name)) {
  	    zerr("not an identifier: %s", asg->name, 0);
  	    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|PM_HASHED)))))) {
! 	    /* if no flags or values are given, just print this parameter */
! 	    if (!on && !roff && !asg->value) {
! 		paramtab->printnode((HashNode) pm, 0);
! 		continue;
! 	    }
! 	    if ((pm->flags & PM_RESTRICTED) && isset(RESTRICTED)) {
! 		zerrnam(name, "%s: restricted", pm->nam, 0);
! 		returnval = 1;
! 		continue;
! 	    }
! 	    if((pm->flags & PM_SPECIAL) &&
! 	       PM_TYPE((pm->flags | on) & ~off) != 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 &&
! 		PM_TYPE(pm->flags) != PM_HASHED) {
! 		if (pm->flags & PM_EXPORTED) {
! 		    if (!(pm->flags & PM_UNSET) && !pm->env && !asg->value)
! 			pm->env = addenv(asg->name, getsparam(asg->name));
! 		} else if (pm->env) {
! 		    delenv(pm->env);
! 		    zsfree(pm->env);
! 		    pm->env = NULL;
! 		}
! 		if (asg->value)
! 		    setsparam(asg->name, ztrdup(asg->value));
! 	    }
! 	} else {
! 	    if (bit) {
! 		if (pm->flags & PM_READONLY) {
! 		    on |= ~off & PM_READONLY;
! 		    pm->flags &= ~PM_READONLY;
! 		}
! 		if (!asg->value)
! 		    asg->value = dupstring(getsparam(asg->name));
! 		unsetparam(asg->name);
! 	    }
! 	    /* create a new node for a parameter with the *
! 	     * flags in `on' minus the readonly flag      */
! 	    pm = createparam(ztrdup(asg->name), on & ~PM_READONLY);
! 	    DPUTS(!pm, "BUG: parameter not created");
! 	    pm->ct = auxlen;
! 	    if (func != BIN_EXPORT)
! 		pm->level = locallevel;
! 	    if (asg->value)
! 		setsparam(asg->name, ztrdup(asg->value));
! 	    pm->flags |= (on & PM_READONLY);
! 	}
      }
      return returnval;
  }
--- 1645,1689 ----
  		returnval = 1;
  		continue;
  	    }
! 	    /*
! 	     * Search through the parameter table and change all parameters
! 	     * matching the glob pattern to have these flags and/or value.
! 	     * Bad news:  if the parameter gets altered, e.g. by
! 	     * a type conversion, then paramtab can be shifted around,
! 	     * so we need to store the parameters to alter on a separate
! 	     * list for later use.	     
! 	     */
  	    for (i = 0; i < paramtab->hsize; i++) {
! 		for (pm = (Param) paramtab->nodes[i]; pm;
! 		     pm = (Param) pm->next) {
  		    if ((pm->flags & PM_RESTRICTED) && isset(RESTRICTED))
  			continue;
! 		    if (domatch(pm->nam, com, 0))
! 			addlinknode(pmlist, pm);
  		}
  	    }
+ 	    for (pmnode = firstnode(pmlist); pmnode; incnode(pmnode)) {
+ 		pm = (Param) getdata(pmnode);
+ 		if (typeset_single(name, pm->nam, pm, func, on, off, roff,
+ 				   asg->value))
+ 		    returnval = 1;
+ 	    }
  	}
  	return returnval;
      }
  
      /* Take arguments literally.  Don't glob */
      while ((asg = getasg(*argv++))) {
  	/* check if argument is a valid identifier */
  	if (!isident(asg->name)) {
  	    zerr("not an identifier: %s", asg->name, 0);
  	    returnval = 1;
  	    continue;
  	}
! 	if (typeset_single(name, asg->name,
! 			   (Param)paramtab->getnode(paramtab, asg->name),
! 			   func, on, off, roff, asg->value))
! 	    returnval = 1;
      }
      return returnval;
  }
***************
*** 2778,2785 ****
  		LASTALLOC_RETURN;
  	    }
  	}
! 	if (in_exit++ && from_signal)
  	    LASTALLOC_RETURN;
  	if (isset(MONITOR))
  	    /* send SIGHUP to any jobs left running  */
  	    killrunjobs(from_signal);
--- 2796,2804 ----
  		LASTALLOC_RETURN;
  	    }
  	}
! 	if (in_exit++ && from_signal) {
  	    LASTALLOC_RETURN;
+ 	}
  	if (isset(MONITOR))
  	    /* send SIGHUP to any jobs left running  */
  	    killrunjobs(from_signal);
***************
*** 3181,3193 ****
  	    }
  	    if (c == EOF || (c == '\n' && !zbuf))
  		break;
! 	    if (!bslash && isep(c) && bptr == buf)
  		if (iwsep(c))
  		    continue;
  		else if (!first) {
  		    first = 1;
  		    continue;
  		}
  	    bslash = c == '\\' && !bslash && !ops['r'];
  	    if (bslash)
  		continue;
--- 3200,3213 ----
  	    }
  	    if (c == EOF || (c == '\n' && !zbuf))
  		break;
! 	    if (!bslash && isep(c) && bptr == buf) {
  		if (iwsep(c))
  		    continue;
  		else if (!first) {
  		    first = 1;
  		    continue;
  		}
+ 	    }
  	    bslash = c == '\\' && !bslash && !ops['r'];
  	    if (bslash)
  		continue;
***************
*** 3240,3246 ****
      char cc, retry = 0;
  
      /* use zbuf if possible */
!     if (zbuf)
  	/* If zbuf points to anything, it points to the next character in the
  	buffer.  This may be a null byte to indicate EOF.  If reading from the
  	buffer, move on the buffer pointer. */
--- 3260,3266 ----
      char cc, retry = 0;
  
      /* use zbuf if possible */
!     if (zbuf) {
  	/* If zbuf points to anything, it points to the next character in the
  	buffer.  This may be a null byte to indicate EOF.  If reading from the
  	buffer, move on the buffer pointer. */
***************
*** 3248,3253 ****
--- 3268,3274 ----
  	    return zbuf++, STOUC(*zbuf++ ^ 32);
  	else
  	    return (*zbuf) ? STOUC(*zbuf++) : EOF;
+     }
      for (;;) {
  	/* read a character from readfd */
  	switch (read(readfd, &cc, 1)) {

-- 
Peter Stephenson <pws@xxxxxxxxxxxxxxxxx>       Tel: +39 050 844536
WWW:  http://www.ifh.de/~pws/
Dipartimento di Fisica, Via Buonarroti 2, 56127 Pisa, Italy



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