zsh - ksh/tcsh-like shell (part 5 of 8)

Paul John Falstad pfalstad at phoenix.Princeton.EDU
Sat Dec 15 10:32:05 AEST 1990


---cut here---cut here---cut here---
-{
-list2 l2 = (list2) alloc(sizeof *l2);
-int iter = 0;
-
-	for (;;)
-		{
-		if (peek == BANG)
-			{
-			l2->flags |= PFLAG_NOT;
-			matchit();
-			}
-		else if (peek == TIME)
-			{
-			l2->flags |= PFLAG_TIMED;
-			matchit();
-			}
-		else if (peek == COPROC)
-			{
-			l2->flags |= PFLAG_COPROC;
-			matchit();
-			}
-		else
-			break;
-		iter = 1;
-		}
-	if (!(l2->left = parpline()))
-		{
-		free(l2);
-		if (!errflag && iter)
-			{
-			zerr("parse error: pipeline expected");
-			errflag = 1;
-			}
-		return NULL;
-		}
-	if (peek == DAMPER || peek == DBAR)
-		{
-		l2->type = (peek == DAMPER) ? ANDNEXT : ORNEXT;
-		matchit();
-		while (peek == NEWLIN)
-			matchit();
-		if (!(l2->right = parlist2()))
-			{
-			if (!errflag)
-				{
-				zerr("invalid null command");
-				errflag = 1;
-				}
-			freepline(l2->left);
-			free(l2);
-			return NULL;
-			}
-		}
-	else
-		{
-		l2->type = END;
-		l2->right = NULL;
-		}
-	return l2;
-}
-
-/* parse a pipeline */
-
-pline parpline(void)
-{
-pline p = (pline) alloc(sizeof *p);
-
-	if (!(p->left = parcmd()))
-		{
-		free(p);
-		return NULL;
-		}
-	if (peek == HERR)
-		{
-		freecmd(p->left);
-		free(p);
-		return NULL;
-		}
-	if (peek == BAR || peek == BARAMP)
-		{
-		if (peek == BARAMP)
-			{
-			struct fnode *f;
-
-			f = alloc(sizeof *f);
-			f->type = MERGEOUT;
-			f->fd1 = 2;
-			f->u.fd2 = 1;
-			addnode(p->left->redir,f);
-			}
-		matchit();
-		while (peek == NEWLIN)
-			matchit();
-		p->type = PIPE;
-		if (!(p->right = parpline()))
-			{
-			if (!errflag)
-				{
-				zerr("invalid null command");
-				errflag = 1;
-				}
-			freecmd(p->left);
-			free(p);
-			return NULL;
-			}
-		}
-	else
-		{
-		p->type = END;
-		p->right = NULL;
-		}
-	return p;
-}
-
-/* parse a command */
-
-comm parcmd(void)
-{
-comm c = (comm) alloc(sizeof *c);
-list l;
-char *str;
-int flag,iter = 0;
-
-	incmd = 0;
-	c->left = NULL;
-	c->cmd = NULL;
-	c->args = newtable();
-	c->redir = newtable();
-	c->type = SIMPLE;
-	c->vars = NULL;
-	if (peek == EOF)
-		return NULL;
-foo:
-	switch (peek)
-		{
-		case HERR:
-			return NULL;
-		case ENVSTRING:
-			if (!c->vars)
-				c->vars = newtable(); /* FIX */
-			for (str = tstr; *str != '='; str++);
-			*str++ = '\0';
-			addnode(c->vars,tstr);
-			addnode(c->vars,strdup(str));
-			matchit();
-			goto foo;
-		case FOR:
-			incmd = 1;
-			matchit();
-			if (parfor(c,1))
-				return NULL;
-			break;
-		case SELECT:
-			incmd = 1;
-			matchit();
-			if (parfor(c,0))
-				return NULL;
-			break;
-		case CASE:
-			incmd = 1;
-			matchit();
-			if (parcase(c))
-				return NULL;
-			break;
-		case IF:
-			matchit();
-			if (parif(c))
-				return NULL;
-			break;
-		case WHILE:
-			matchit();
-			if (parwhile(c,0))
-				return NULL;
-			break;
-		case UNTIL:
-			matchit();
-			if (parwhile(c,1))
-				return NULL;
-			break;
-		case REPEAT:
-			incmd = 1;
-			matchit();
-			if (parrepeat(c))
-				return NULL;
-			break;
-		case INPAR:
-			matchit();
-			c->type = SUBSH;
-			if (!(c->left = parlist(1)))
-				{
-				freecmd(c);
-				return NULL;
-				}
-			if (peek != OUTPAR)
-				{
-				freecmd(c);
-				zerr("parse error: '}' expected");
-				return NULL;
-				}
-			matchit();
-			break;
-		case INBRACE:
-			matchit();
-			c->type = CURSH;
-			if (!(c->left = parlist(1)))
-				{
-				freecmd(c);
-				return NULL;
-				}
-			if (peek != OUTBRACE)
-				{
-				freecmd(c);
-				zerr("parse error: '}' expected");
-				return NULL;
-				}
-			matchit();
-			break;
-		case FUNC:
-			matchit();
-			str = tstr;
-			if (peek != STRING && peek != ENVSTRING)
-				{
-				c->cmd = strdup("function");
-				incmd = 1;
-				if (isredir())
-					goto jump1;
-				else
-					goto jump2;
-				}
-			do	
-				matchit();
-			while (peek == NEWLIN);
-			if (peek != INBRACE)
-				{
-				freecmd(c);
-				zerr("parse error: '{' expected");
-				return NULL;
-				}
-			matchit();
-			flag = peek == OUTBRACE;
-			if (!(l = parlist(1)))
-				{
-				freecmd(c);
-				return NULL;
-				}
-			if (peek != OUTBRACE)
-				{
-				freelist(l);
-				freecmd(c);
-				zerr("parse error: '}' expected");
-				return NULL;
-				}
-			matchit();
-			settrap(str,flag);
-			addhnode(str,l,shfunchtab,freeshfunc);
-			c->cmd = strdup("");
-			c->type = SIMPLE;
-			break;
-		case EXEC:
-			c->flags |= CFLAG_EXEC;
-			matchit();
-			iter = 1;
-			goto foo;
-		case COMMAND:
-			c->flags |= CFLAG_COMMAND;
-			matchit();
-			iter = 1;
-			goto foo;
-		default:
-jump1:
-			if (isredir())
-				{
-				if (parredir(c))
-					{
-					freecmd(c);
-					return NULL;
-					}
-				goto foo;
-				}
-			if (!(peek == STRING || peek == ENVSTRING))
-				{
-				if (full(c->redir))
-					{
-					c->cmd = strdup("cat");
-					return c;
-					}
-				if (c->vars)
-					{
-					c->cmd = strdup("");
-					return c;
-					}
-				free(c->args);
-				free(c->redir);
-				free(c);
-				if (iter && !errflag)
-					{
-					errflag = 1;
-					zerr("parse error: command expected");
-					}
-				return NULL;
-				}
-jump2:
-			while (peek == STRING || peek == ENVSTRING || isredir())
-				if (isredir())
-					{
-					if (parredir(c))
-						{
-						freecmd(c);
-						return NULL;
-						}
-					}
-				else
-					{
-					if (tstr[0] == Inpar && tstr[1] == Outpar && !tstr[2])
-						{
-						free(tstr);
-						incmd = 0;
-						matchit();
-						if (full(c->args))
-							{
-							zerr("illegal function definition");
-							freecmd(c);
-							return NULL;
-							}
-						while (peek == NEWLIN)
-							matchit();
-						if (peek != INBRACE)
-							{
-							freecmd(c);
-							zerr("parse error: '{' expected");
-							return NULL;
-							}
-						matchit();
-						flag = peek == OUTBRACE;
-						if (!(l = parlist(1)))
-							{
-							freecmd(c);
-							return NULL;
-							}
-						if (peek != OUTBRACE)
-							{
-							freelist(l);
-							freecmd(c);
-							zerr("parse error: '}' expected");
-							return NULL;
-							}
-						matchit();
-						settrap(c->cmd,flag);
-						addhnode(c->cmd,l,shfunchtab,freeshfunc);
-						c->cmd = strdup("");
-						c->type = SIMPLE;
-						incmd = 0;
-						return c;
-						}
-					if (peek == ENVSTRING && (!incmd || opts[KEYWORD] == OPT_SET))
-						{
-						if (!c->vars)
-							c->vars = newtable(); /* FIX */
-						for (str = tstr; *str != '='; str++);
-						*str++ = '\0';
-						addnode(c->vars,tstr);
-						addnode(c->vars,strdup(str));
-						}
-					else if (c->cmd)
-						addnode(c->args,tstr);
-					else
-						{
-						c->cmd = tstr;
-						incmd = 1;
-						}
-					matchit();
-					}
-			break;
-		}
-	while (isredir())
-		if (parredir(c))
-			{
-			freecmd(c);
-			return NULL;
-			}
-	incmd = 0;
-	if (peek == HERR)
-		{
-		freecmd(c);
-		return NULL;
-		}
-	return c;
-}
-
-/* != 0 if peek is a redirection operator */
-
-int isredir(void)
-{
-	return (peek >= OUTANG && peek <= DOUTANGAMPBANG);
-}
-
-/* get fd associated with str */
-
-int getfdstr(char *s)
-{
-	if (s[1])
-		return -1;
-	if (isdigit(*s))
-		return *s-'0';
-	if (*s == 'p')
-		return -2;
-	return -1;
-}
-
-int parredir(comm c)
-{
-struct fnode *fn = (struct fnode *) alloc(sizeof *fn);
-int pk = peek,ic = incmd,mrg2 = 0;
-
-	fn->type = peek-OUTANG+WRITE;
-	if (peek == OUTANGAMP)
-		fn->type = MERGEOUT;
-	if (peekfd != -1)
-		fn->fd1 = peekfd;
-	else if (peek <= DOUTANGBANG || peek >= OUTANGAMP)
-		fn->fd1 = 1;
-	else
-		fn->fd1 = 0;
-	incmd = 1;
-	matchit();
-	incmd = ic;
-	if (peek != STRING)
-		{
-		zerr("parse error: filename expected");
-		return 1;
-		}
-	
-	if ((*tstr == Inang || *tstr == Outang) && tstr[1] == Inpar)
-		{
-		if (fn->type == WRITE)
-			fn->type = OUTPIPE;
-		else if (fn->type == READ)
-			fn->type = INPIPE;
-		else
-			{
-			zerr("parse error: bad process redirection");
-			return 1;
-			}
-		fn->u.name = tstr;
-		}
-	else if (fn->type == HEREDOC)
-		fn->u.fd2 = gethere(tstr);
-	else if (pk >= OUTANGAMP && getfdstr(tstr) == -1)
-		{
-		mrg2 = 1;
-		fn->u.name = tstr;
-		fn->type = pk-OUTANGAMP;
-		}
-	else if (pk > OUTANGAMPBANG)
-		{
-		zerr("parse error: filename expected");
-		return 1;
-		}
-	else if (pk == OUTANGAMPBANG)
-		{
-		struct fnode *fe = alloc(sizeof *fe);
-
-		fe->fd1 = fn->fd1;
-		fe->type = CLOSE;
-		addnode(c->redir,fe);
-		fn->u.fd2 = getfdstr(tstr);
-		if (fn->u.fd2 == -2)
-			fn->u.fd2 = spout;
-		fn->type = MERGEOUT;
-		}
-	else if (fn->type == MERGE || fn->type == MERGEOUT)
-		{
-		if (*tstr == '-')
-			fn->type = CLOSE;
-		else
-			{
-			fn->u.fd2 = getfdstr(tstr);
-			if (fn->u.fd2 == -2)
-				fn->u.fd2 = (pk == OUTANGAMP) ? spout : spin;
-			}
-		}
-	else
-		fn->u.name = tstr;
-	addnode(c->redir,fn);
-	if (mrg2)
-		{
-		struct fnode *fe = alloc(sizeof *fe);
-
-		fe->fd1 = 2;
-		fe->u.fd2 = fn->fd1;
-		fe->type = MERGEOUT;
-		addnode(c->redir,fe);
-		}
-	matchit();
-	return 0;
-}
-
End of parse.c
echo parse.pro 1>&2
sed 's/^-//' >parse.pro <<'End of parse.pro'
-list parlist(int nest);
-list parlist1(int nest);
-list2 parlist2(void);
-pline parpline(void);
-comm parcmd(void);
-int isredir(void);
-int getfdstr(char *s);
-int parredir(comm c);
End of parse.pro
echo subst.c 1>&2
sed 's/^-//' >subst.c <<'End of subst.c'
-/*
-
-	subst.c - various substitution
-
-	This file is part of zsh, the Z shell.
-
-   zsh is free software; no one can prevent you from reading the source
-   code, or giving it to someone else.
-   This file is copyrighted under the GNU General Public License, which
-   can be found in the file called COPYING.
-
-   Copyright (C) 1990 Paul Falstad
-
-   zsh is distributed in the hope that it will be useful, but
-   WITHOUT ANY WARRANTY.  No author or distributor accepts
-   responsibility to anyone for the consequences of using it or for
-   whether it serves any particular purpose or works at all, unless he
-   says so in writing.  Refer to the GNU General Public License
-   for full details.
-
-   Everyone is granted permission to copy, modify and redistribute
-   zsh, but only under the conditions described in the GNU General Public
-   License.   A copy of this license is supposed to have been given to you
-   along with zsh so you can know your rights and responsibilities.
-   It should be in a file named COPYING.
-
-   Among other things, the copyright notice and this notice must be
-   preserved on all copies.
-
-*/
-
-#include "zsh.h"
-#include "funcs.h"
-#include <pwd.h>
-#define MAXPATHLEN 1024
-
-#define magicerr() { if (magic) putc('\n',stderr); }
-
-/* do substitutions before fork */
-
-void prefork(table list)
-{
-Node node = list->first;
-
-	while (node)
-		{
-		char *str,*str3;
-		
-		str = str3 = node->dat;
-		if (!magic && str[1] == Inpar && (*str == Inang ||
-				*str == Outang || *str == Equals))
-			{
-			if (*str == Inang)
-				node->dat = getoutproc(str+2);		/* <(...) */
-			else if (*str == Equals)
-				node->dat = getoutputfile(str+2);	/* =(...) */
-			else
-				node->dat = getinproc(str+2);			/* >(...) */
-			free(str);
-			if (!node->dat)
-				{
-				zerr("parse error in process substitution");
-				errflag = 1;
-				return;
-				}
-			}
-		else while (*str)
-			{
-			if (*str == String || *str == Qstring)
-				if (str[1] != Inpar)
-					if (str[1] == '*' || str[1] == Star)
-						parminsall(list,&node,&str,&str3);	/* $* */
-					else if (str[1] == Inbrack)
-						{
-						arithsuber((void **) &str,&str3);	/* $[...] */
-						if (magic)
-							magic = 2;
-						node->dat = str3;
-						}
-					else
-						{
-						parmsuber(str,&str3);		/* $foo */
-						node->dat = str = str3;
-						if (errflag)
-							return;
-						continue;
-						}
-			str++;
-			if (errflag)
-				return;
-			}
-		node = node->next;
-		}
-}
-
-void postfork(table list,int globstat)
-{
-Node node = list->first;
-int glb = 1;
-
-	if (isset(NOGLOBOPT) || globstat != GLOB)
-		glb = 0;
-	while (node)
-		{
-		char *str,*str3;
-		
-		str = str3 = node->dat;
-		while (*str)
-			{
-			if (((*str == String || *str == Qstring) && str[1] == Inpar) ||
-					*str == Tick || *str == Qtick)
-				comminsall(list,&node,&str,&str3);	/* `...`,$(...) */
-			str++;
-			if (errflag)
-				return;
-			}
-		
-		/* now we remove the Nulargs tokens if this is not a null
-			arguments.  The lexical analyzer throws these in so that
-			zsh will not look at this:
-
-			$PA"TH"
-
-			and expand it to $PATH.  But after parameter substitution
-			these are only a nuisance, so we remove them. */
-
-		if (*(char *) node->dat)
-			remnulargs(node->dat);
-		
-		if (unset(IGNOREBRACES))
-			while (hasbraces(node->dat))
-				xpandbraces(list,&node);
-		filesub(&node->dat);
-		if (errflag)
-			return;
-		if (glb)
-			{
-			if (haswilds(node->dat))
-				glob(list,&node);
-			if (errflag)
-				return;
-			}
-		else if (globstat == MOSTGLOB && *(char *) node->dat != '-')
-			glb = 1;
-		node = node->next;
-		}
-}
-
-/* strdup, but returns "Nularg" if this is a null string */
-
-void *nstrdup(void *s)
-{
-char *t = s,u[] = {Nularg,'\0'};
-
-	if (!*t)
-		return strdup(u);
-	return strdup(t);
-}
-
-/* $* */
-
-void parminsall(table l,Node *nn,char **aptr,char **bptr)
-{
-char *str3 = *aptr,*str = *bptr;
-Node n = *nn,where = n->last;
-table pl;
-
-	if (magic)
-		magic = 2;
-	*str3 = '\0';
-	str3 += 2;
-	remnode(l,n);
-	pl = duptable(pparms,nstrdup);
-	free(getnode(pl));
-	if (pl->first)	/* if $# > 1 */
-		{
-		char *ptr;
-		Node tmp;
-
-		ptr = pl->first->dat;
-		pl->first->dat = dyncat(str,ptr);
-		free(ptr);
-		ptr = pl->last->dat;
-		*bptr = pl->last->dat = dyncat(ptr,str3);
-		*aptr = *bptr+strlen(str)+strlen(ptr)-1;
-		free(ptr);
-		tmp = where->next;
-		where->next = pl->first;
-		pl->last->next = tmp;
-		pl->first->last = where;
-		if (tmp)
-			tmp->last = pl->last;
-		else
-			l->last = pl->last;
-		*nn = pl->last;
-		}
-	else	/* just remove the $* */
-		{
-		insnode(l,where,*bptr = dyncat(str,str3));
-		*nn = where->next;
-		*aptr = *bptr+strlen(str)-1;
-		}
-}
-
-char *dynread(char stop)
-{
-int bsiz = 256,ct = 0,c;
-char *buf = zalloc(bsiz),*ptr;
- 
-	ptr = buf;
-	while ((c = hgetc()) != stop)
-		{
-		*ptr++ = c;
-		if (++ct == bsiz)
-			{
-			buf = realloc(buf,bsiz *= 2);
-			ptr = buf+ct;
-			}
-		}
-	*ptr = 0;
-	return buf;
-}
-
-int filesub(void **namptr)
-{
-char *str = *namptr,*cnam;
-
-	if (*str == Tilde && str[1] != '=')
-		{
-		if (str[1] == '+')
-			{
-			char *foo = strdup(cwd),*t = str;	/* ~+ */
-
-			str+=2;
-			modify((void **) &foo,&str);
-			*namptr = dyncat(cwd,str);
-			free(foo);
-			free(t);
-			return 1;
-			}
-		else if (str[1] == '-')			/* ~- */
-			{
-			char *foo,*t = str;
-
-			if (cnam = getparm("OLDPWD"))
-				foo = cnam;
-			else
-				foo = cwd;
-			str += 2;
-			foo = strdup(foo);
-			modify((void **) &foo,&str);
-			*namptr = dyncat(foo,str);
-			free(t);
-			free(foo);
-			return 1;
-			}
-		if (isalpha(str[1]))		/* ~foo */
-			{
-			char *ptr,*home;
- 
-			for (ptr = ++str; *ptr && !istok(*ptr) && (isalnum(*ptr) || *ptr == '-'); ptr++)
-				if (*ptr == '-')
-					*ptr = '-';
-			if (!(home = gethome(str,ptr-str)))
-				{
-				if (magic)
-					home = completehome(str,ptr-str);
-				if (!home)
-					{
-					magicerr();
-					zerr("user not found: %l",ptr-str,str);
-					errflag = 1;
-					return 0;
-					}
-				}
-			modify((void **) &home,&ptr);
-			*namptr = dyncat(home,ptr);
-			free(home);
-			free(str-1);
-			return 1;
-			}
-		else if (str[1] == '/')	/* ~/foo */
-			{
-			*namptr = dyncat(home,str+1);
-			free(str);
-			return 1;
-			}
-		else if (!str[1])		/* ~ by itself */
-			{
-			free(str);
-			*namptr = strdup(home);
-			return 1;
-			}
-		}
-	if (*str == Equals && !istok(str[1]) && (isalnum(str[1]) || str[1] == '-'))
-		{
-		char *ptr,*s,*ds;
-		int val;
-		
-		untokenize(str);
-		if (isalpha(str[1]))		/* =foo */
-			{
-			struct chnode *chn;
-			struct anode *t;
-			char sav,*pp;
- 
-			for (pp = str+1; *pp && *pp != ':'; pp++);
-			sav = *pp;
-			*pp = '\0';
-			if ((t = gethnode(str+1,alhtab)) && t->cmd)
-				if (t->cmd >= 0)
-					cnam = strdup(t->text);
-				else
-					{
-					magicerr();
-					zerr("%s: shell reserved word",str+1);
-					errflag = 1;
-					return 0;
-					}
-		 	else if (chn = gethnode(str+1,chtab))
-				if (chn->type != BUILTIN)
-					cnam = strdup(chn->u.nam);
-				else
-					{
-					magicerr();
-					zerr("%s: shell built-in command",str+1);
-					errflag = 1;
-					return 0;
-					}
-			else if (!(cnam = findcmd(str+1)))
-				{
-				magicerr();
-				zerr("%s not found",str+1);
-				errflag = 1;
-				return 0;
-				}
-			*namptr = cnam;
-			if ((*pp = sav) == ':')
-				{
-				modify(namptr,&pp);
-				s = *namptr;
-				*namptr = dyncat(*namptr,pp);
-				free(s);
-				}
-			free(str);
-			return 1;
-			}
-		if (str[1] == '-') 	/* =- */
-			{
-			val = -1;
-			ptr = str+2;
-			}
-		else
-			val = strtol(str+1,&ptr,10);	/* =# */
-		ds = dstackent(val);
-		if (!ds)
-			return 1;
-		s = strdup(ds);
-		modify((void **) &s,&ptr);
-		*namptr = dyncat(s,ptr);
-		free(s);
-		free(str);
-		return 1;
-		}
-	return 0;
-}
-
-/* get a user's directory */
-
-char *gethome(char *user,int len)
-{
-char sav,*str;
-struct passwd *pw;
- 
-	sav = user[len];
-	user[len] = '\0';
-	if (!(pw = getpwnam(user)))
-		{
-		user[len] = sav;
-		return NULL;
-		}
-	str = xsymlink(pw->pw_dir);
-	user[len] = sav;
-	return str;
-}
-
-/* complete a user and try to get his home directory */
-
-char *completehome(char *user,int len)
-{
-FILE *in;
-char buf[MAXPATHLEN],*str;
-
-	sprintf(buf,"%s/.zfriends",getparm("HOME"));
-	if (!(in = fopen(buf,"r")))
-		return NULL;
-	while (fgetline(buf,MAXPATHLEN,in))
-		if (!strncmp(user,buf,len))
-			if (str = gethome(buf,strlen(buf)))
-				{
-				fclose(in);
-				return str;
-				}
-	fclose(in);
-	return NULL;
-}
-
-/* get the value of the parameter specified by the first len
-	characters of s */
-
-char *getsparmval(char *s,int len)
-{
-char sav = s[len];
-char *val;
-char buf[50];
-int t0;
-
-	if (len == 1 && (istok(*s) || !isalnum(*s)))
-		switch(*s)
-			{
-			case Pound:
-			case '#':
-				sprintf(buf,"%d",ppcount());
-				return strdup(buf);
-			case '-':
-				for (val = buf, t0 = ' '; t0 <= 'z'; t0++)
-					if (opts[t0] == OPT_SET)
-						*val++ = t0;
-				*val = '\0';
-				return strdup(buf);
-			case '?':
-			case Quest:
-				sprintf(buf,"%d",lastval);
-				return strdup(buf);
-			case '$':
-			case String:
-				sprintf(buf,"%d",procnum);
-				return strdup(buf);
-			case '!':
-				sprintf(buf,"%d",proclast);
-				return strdup(buf);
-			default:
-				return NULL;
-			}
-	s[len] = '\0';
-	if (isdigit(*s))
-		{
-		int num;
-		Node node;
-		
-		num = atoi(s);
-		s[len] = sav;
-		for (node = pparms->first; node && num; num--,node = node->next);
-		return (node) ? strdup(node->dat) : NULL;
-		}
-	val = getparm(s);
-	s[len] = sav;
-	return (val) ? strdup(val) : NULL;
-}
-
-/* set the parameter associated with the first len characters of s
-	to v. */
-
-void setparml(char *s,int len,char *v)
-{
-char c;
- 
-	c = s[len];
-	s[len] = 0;
-	if (isdigit(*s))
-		{
-		int num;
-		Node node;
-		
-		num = atoi(s);
-		for (node = pparms->first; node && num; num--,node = node->next);
-		if (node)
-			{
-			free(node->dat);
-			node->dat = v;
-			}
-		else
-			{
-			while (num--)
-				addnode(pparms,strdup(""));
-			addnode(pparms,v);
-			}
-		}
-	else
-		setparm(strdup(s),v,0,0);
-	s[len] = c;
-}
-
-/* `...`, $(...) */
-
-void comminsall(table l,Node *nn,char **aptr,char **bptr)
-{
-char *str3 = *aptr,*str = *bptr,*str2;
-Node n = *nn,where = n->last;
-table pl;
-int s31 = (*str3 == Qtick || *str3 == Qstring);
-
-	if (magic) magic = 2;
-	if (*str3 == Tick || *str3 == Qtick)
-		{
-		*str3 = '\0';
-		for (str2 = ++str3; *str3 != Tick && *str3 != Qtick; str3++);
-		*str3++ = '\0';
-		}
-	else
-		{
-		*str3++ = '\0';
-		for (str2 = ++str3; *str3 != Outpar; str3++);
-		*str3++ = '\0';
-		}
-	remnode(l,n);
-	if (!(pl = getoutput(str2,s31)))
-		{
-		magicerr();
-		zerr("parse error in command substitution");
-		errflag = 1;
-		return;
-		}
-	if (pl->first)
-		{
-		char *ptr;
-		Node tmp;
-
-		ptr = pl->first->dat;
-		pl->first->dat = dyncat(str,ptr);
-		free(ptr);
-		ptr = pl->last->dat;
-		*bptr = pl->last->dat = dyncat(ptr,str3);
-		*aptr = *bptr+strlen(str)+strlen(ptr)-1;
-		free(ptr);
-		tmp = where->next;
-		where->next = pl->first;
-		pl->last->next = tmp;
-		pl->first->last = where;
-		if (tmp)
-			tmp->last = pl->last;
-		else
-			l->last = pl->last;
-		/* free(tmp); */
-		*nn = pl->last;
-		free(pl);
-		}
-	else
-		{
-		insnode(l,where,*bptr = dyncat(str,str3));
-		*nn = where->next;
-		*aptr = *bptr+strlen(str)-1;
-		}
-}
-
-/* do simple parameter substitution */
-
-/*
-	consider an argument like this:
-
-	abcde${fgh:-ijk}lmnop
-
-	aptr will point to the $.
-	*bptr,ostr will point to the a.
-	t will point to the f.
-	u will point to the i.
-	s will point to the l (eventually).
-*/
-
-void parmsuber(char *aptr,char **bptr)
-{
-char *s = aptr,*t,*u,*val,*ostr = *bptr;
-int brs;			/* != 0 means ${...}, otherwise $... */
-int vlen;		/* the length of the name of the parameter */
-int colf;		/* != 0 means we found a colon after the name */
-int doub = 0;	/* != 0 means we have %%, not %, or ##, not # */
-
-	/* first, remove the $ so *bptr is pointing to a null-terminated
-		string containing the stuff before the $.  Then check for braces,
-		and get the parameter name and value, if any. */
-
-	*s++ = '\0';
-	if (brs = (*s == '{' || *s == Inbrace))
-		s++;
-	t = s;
-	if (istok(*s) || !isalnum(*s))
-		{
-		val = getsparmval(t,vlen = 1);
-		if (!val)
-			{
-			*(char *) aptr = '$';
-			if (brs)
-				s[-1] = '{';
-			return;
-			}
-		s++;
-		}
-	else
-		{
-		while (!istok(*s) && (isalnum(*s) || *s == '_'))
-			s++;
-		val = getsparmval(t,vlen = s-t);
-		}
-
-	/* val can still be NULL at this point. */
-
-	if (colf = *s == ':')
-		s++;
-	
-	/* check for ${..?...} or ${..=..} or one of those.  Only works
-		if the name is in braces. */
-
-	if (brs && (*s == '-' || *s == '=' || *s == '?' || *s == '+' || *s == '#' ||
-			*s == '%' || *s == Quest || *s == Pound))
-		{
-		if (*s == s[1])
-			{
-			s++;
-			doub = 1;
-			}
-		u = ++s;
-		if (brs)
-			while (*s != '}' && *s != Outbrace)
-				s++;
-		else
-			{
-			while (*s++);
-			s--;
-			}
-		*s = '\0';
-		switch (u[-1])
-			{
-			case '-':
-				if (!val || (colf && !*val))
-					val = strdup(u);
-				break;
-			case '=':
-				if (!val || (colf && !*val))
-					setparml(t,vlen,val = strdup(u));
-				break;
-			case '?':
-			case Quest:
-				if (!val || (colf && !*val))
-					{
-					magicerr();
-					zerr("%s",(*u) ? u : "parameter not set");
-					if (!interact)
-						exit(1);
-					else
-						errflag = 1;
-					return;
-					}
-				break;
-			case '+':
-				if (!val || (colf && !*val))
-					val = strdup("");
-				else
-					val = strdup(u);
-				break;
-			case '#':
-			case Pound:
-				if (!val)
-					val = strdup("");
-				getmatch(&val,u,doub);
-				break;
-			case '%':
-				if (!val)
-					val = strdup("");
-				getmatch(&val,u,doub+2);
-				break;
-			}
-		}
-	else		/* no ${...=...} or anything, but possible modifiers. */
-		{
-		if (!val)
-			{
-			if (isset(NOUNSET))
-				{
-				zerr("parameter not set: %l",vlen,t);
-				errflag = 1;
-				return;
-				}
-			val = strdup("");
-			}
-		if (colf)
-			{
-			s--;
-			modify((void **) &val,&s);		/* do modifiers */
-			}
-		if (brs)
-			{
-			if (*s != '}' && *s != Outbrace)
-				{
-				zerr("closing brace expected");
-				errflag = 1;
-				return;
-				}
-			s++;
-			}
-		}
-	if (errflag)
-		{
-		free(ostr);
-		return;
-		}
-	*bptr = zalloc((char *) aptr-(*bptr)+strlen(val)+strlen(s)+1);
-	strcpy(*bptr,ostr);
-	strcat(*bptr,val);
-	strcat(*bptr,s);
-	free(ostr);
-	if (magic)
-		magic = 2;
-}
-
-/* arithmetic substitution */
-
-void arithsuber(void **aptr,char **bptr)
-{
-char *s = *aptr,*t,buf[16];
-long v;
-
-	*s = '\0';
-	for (; *s != Outbrack; s++);
-	*s++ = '\0';
-	v = matheval(*aptr+2);
-	sprintf(buf,"%ld",v);
-	t = zalloc(strlen(*bptr)+strlen(buf)+strlen(s)+1);
-	strcpy(t,*bptr);
-	strcat(t,buf);
-	strcat(t,s);
-	free(*bptr);
-	*bptr = t;
-}
-
-void modify(void **str,char **ptr)
-{
-char *ptr1,*ptr2,*ptr3,del,*lptr;
-int gbal;
- 
-	while (**ptr == ':')
-		{
-		lptr = *ptr;
-		(*ptr)++;
-		gbal = 0;
-here:
-		switch(*(*ptr)++)
-			{
-			case 'h':
-				while (remtpath(str) && gbal);
-				break;
-			case 'r':
-				while (remtext(str) && gbal);
-				break;
-			case 'e':
-				while (rembutext(str) && gbal);
-				break;
-			case 't':
-				while (remlpaths(str) && gbal);
-				break;
-			case 's':
-				if (last)
-					free(last);
-				if (rast)
-					free(rast);
-				ptr1 = *ptr;
-				del = *ptr1++;
-				for (ptr2 = ptr1; *ptr2 != del && *ptr2; ptr2++);
-				if (!*ptr2)
-					{
-					magicerr();
-					zerr("bad subtitution");
-					errflag = 1;
-					return;
-					}
-				*ptr2++ = '\0';
-				for (ptr3 = ptr2; *ptr3 != del && *ptr3; ptr3++);
-				if (*ptr3)
-					*ptr3++ = '\0';
-				last = strdup(ptr1);
-				rast = strdup(ptr2);
-				*ptr = ptr3;
-			case '&':
-				if (last && rast)
-					subststr(str,last,rast,gbal);
-				break;
-			case 'g':
-				gbal = 1;
-				goto here;
-			default:
-				*ptr = lptr;
-				return;
-			}
-		}
-}
-
-/* get a directory stack entry */
-
-char *dstackent(int val)
-{
-Node node;
- 
-	if ((val < 0 && !dirstack->first) || !val--)
-		return cwd;
-	if (val < 0)
-		node = dirstack->last;
-	else
-		for (node = dirstack->first; node && val; val--,node = node->next);
-	if (!node)
-		{
-		magicerr();
-		zerr("not enough dir stack entries.");
-		errflag = 1;
-		return NULL;
-		}
-	return node->dat;
-}
- 
-void execshfunc(comm comm)
-{
-table tab,oldlocals;
-Node n;
-char *s;
-
-	tab = pparms;
-	oldlocals = locallist;
-	locallist = newtable();
-	for (n = tab->first; n; n = n->next);
-	pparms = comm->args;
-	runlist(comm->left);
-	retflag = 0;
-	comm->left = NULL;
-	pparms = tab;
-	while (s = getnode(locallist))
-		{
-		void *z = remhnode(s,parmhtab);
-		if (z)
-			freepm(z);
-		}
-	free(locallist);
-	locallist = oldlocals;
-}
-
-/* make an alias hash table node */
-
-struct anode *mkanode(char *txt,int cmflag)
-{
-struct anode *ptr = (void *) alloc(sizeof(struct anode));
-
-	ptr->text  = txt;
-	ptr->cmd = cmflag;
-	ptr->inuse = 0;
-	return ptr;
-}
-
-/* perform TAB substitution */
-
-char *docompsubs(char *str,int *i)
-{
-table fake,curt = curtab;
-char *s,*t;
-int ct = 0;
-
-	for (s = str; *s; s++)
-		for (t = tokens; *t; t++)
-			if (*s == *t)
-				{
-				*s = (t-tokens)+Pound;
-				break;
-				}
-	curtab = NULL;
-	magic = 1;
-	fake = newtable();
-	addnode(fake,str);
-	prefork(fake);
-	if (!errflag)
-		postfork(fake,GLOB);
-	if (fake->first && fake->first->next)
-		ct = 1;
-	t = s = buildline(fake);
-	free(fake);
-	rl_prep_terminal();
-	if (errflag)
-		{
-		rl_on_new_line();
-		rl_redisplay();
-		errflag = 0;
-		magic = 0;
-		curtab = curt;
-		*i = 0;
-		return NULL;
-		}
-	*i = (magic == 2) + ct;
-	magic = 0;
-	curtab = curt;
-	untokenize(s);
-	return s;
-}
-
-/* perform substitution on the command name */
-
-void docmdsubs(char **str)
-{
-table fake;
-char *s = strdup(*str);
-
-	fake = newtable();
-	addnode(fake,*str);
-	prefork(fake);
-	if (!errflag) postfork(fake,GLOB);
-	if (errflag)
-		{
-		free(fake);
-		free(s);
-		return;
-		}
-	if (fake->first && fake->first->next)
-		{
-		zerr("%s: ambiguous",s);
-		errflag = 1;
-		free(fake);
-		free(s);
-		return;
-		}
-	*str = getnode(fake);
-	free(s);
-	free(fake);
-}
-
-/* perform substitution on the variables */
-
-void dovarsubs(char **str)
-{
-table fake;
-char *s;
-
-	fake = newtable();
-	addnode(fake,*str);
-	prefork(fake);
-	if (!errflag) postfork(fake,GLOB);
-	if (errflag)
-		return;
-	s = buildline(fake);
-	untokenize(s);
-	*str = s;
-	free(fake);
-}
-
End of subst.c
echo subst.pro 1>&2
sed 's/^-//' >subst.pro <<'End of subst.pro'
-void prefork(table list);
-void postfork(table list,int globstat);
-void *nstrdup(void *s);
-void parminsall(table l,Node *nn,char **aptr,char **bptr);
-char *dynread(char stop);
-int filesub(void **namptr);
-char *gethome(char *user,int len);
-char *completehome(char *user,int len);
-char *getsparmval(char *s,int len);
-void setparml(char *s,int len,char *v);
-void comminsall(table l,Node *nn,char **aptr,char **bptr);
-void parmsuber(char *aptr,char **bptr);
-void arithsuber(void **aptr,char **bptr);
-void modify(void **str,char **ptr);
-char *dstackent(int val);
-void execshfunc(comm comm);
-struct anode *mkanode(char *txt,int cmflag);
-char *docompsubs(char *str,int *i);
-void docmdsubs(char **str);
-void dovarsubs(char **str);
End of subst.pro
echo table.c 1>&2
sed 's/^-//' >table.c <<'End of table.c'
-/*
-
-	table.c - linked list and hash table management
-
-	This file is part of zsh, the Z shell.
-
-   zsh is free software; no one can prevent you from reading the source
-   code, or giving it to someone else.
-   This file is copyrighted under the GNU General Public License, which
-   can be found in the file called COPYING.
-
-   Copyright (C) 1990 Paul Falstad
-
-   zsh is distributed in the hope that it will be useful, but
-   WITHOUT ANY WARRANTY.  No author or distributor accepts
-   responsibility to anyone for the consequences of using it or for
-   whether it serves any particular purpose or works at all, unless he
-   says so in writing.  Refer to the GNU General Public License
-   for full details.
-
-   Everyone is granted permission to copy, modify and redistribute
-   zsh, but only under the conditions described in the GNU General Public
-   License.   A copy of this license is supposed to have been given to you
-   along with zsh so you can know your rights and responsibilities.
-   It should be in a file named COPYING.
-
-   Among other things, the copyright notice and this notice must be
-   preserved on all copies.
-
-*/
-
-#include "zsh.h"
-#include "funcs.h"
-
-/* get an empty linked list header */
-
-table newtable()
-{
-table list;
- 
-	list = alloc(sizeof(*list));
-	list->first = 0;
-	list->last = (Node) list;
-	return list;
-}
-
-/* get an empty hash table */
-
-htable newhtable(int size)
-{
-htable ret;
- 
-	ret = alloc(sizeof(struct xhtab));
-	ret->hsize = size;
-	ret->nodes = alloc(size*sizeof(struct hnode *));
-	return ret;
-}
- 
-/* Peter Weinberger's hash function */
-
-int hasher(char *s)
-{
-unsigned hash = 0,g;
- 
-	for (; *s; s++)
-		{
-		hash = (hash << 4) + *s;
-		if (g = hash & 0xf0000000)
-			{
-			hash ^= g;
-			hash ^= g >> 24;
-			}
-		}
-	return hash;
-}
-
-/* add a node to a hash table */
-
-void addhnode(char *nam,void *dat,htable ht,void (*freefunc)(void *))
-{
-int hval = hasher(nam) % ht->hsize;
-struct hnode *hp = ht->nodes[hval],*hn;
- 
-	for (; hp; hp = hp->hchain)
-		if (!strcmp(hp->nam,nam))
-			{
-			freefunc(hp->dat);
-			hp->dat = dat;
-			free(nam);
-			return;
-			}
-	hn = (void *) alloc(sizeof(struct hnode));
-	hn->nam = nam;
-	hn->dat = dat;
-	hn->hchain = ht->nodes[hval];
-	ht->nodes[hval] = hn;
-	if (++ht->ct == ht->hsize*4)
-		expandhtab(ht);
-}
-
-/* expand hash tables when they get too many entries */
-
-void expandhtab(htable ht)
-{
-struct hnode *hp,**arr,**ha,*hn;
-int osize = ht->hsize,nsize = osize*8;
-
-	ht->hsize = nsize;
-	arr = ht->nodes;
-	ht->nodes = alloc(nsize*sizeof(struct hnode *));
-	for (ha = arr; osize; osize--,ha++)
-		for (hn = *ha; hn; )
-			{
-			addhnode(hn->nam,hn->dat,ht,NULL);
-			hp = hn->hchain;
-			free(hn);
-			hn = hp;
-			}
-	free(arr);
-}
-
-/* get an entry in a hash table */
-
-void *gethnode(char *nam,htable ht)
-{
-int hval = hasher(nam) % ht->hsize;
-struct hnode *hn = ht->nodes[hval];
- 
-	for (; hn; hn = hn->hchain)
-		if (!strcmp(hn->nam,nam))
-			return hn->dat;
-	return NULL;
-}
- 
-void freehtab(htable ht,void (*freefunc)(void *))
-{
-int val;
-struct hnode *hn,**hptr = &ht->nodes[0],*next;
- 
-	for (val = ht->hsize; val; val--,hptr++)
-		for (hn = *hptr; hn; )
-			{
-			next = hn->hchain;
-			freefunc(hn);
-			hn = next;
-			}
-}
-
-/* remove a hash table entry and return a pointer to it */
-
-void *remhnode(char *nam,htable ht)
-{
-int hval = hasher(nam) % ht->hsize;
-struct hnode *hn = ht->nodes[hval],*hp;
-void *dat;
-
-	if (!hn)
-		return NULL;
-	if (!strcmp(hn->nam,nam))
-		{
-		ht->nodes[hval] = hn->hchain;
-		dat = hn->dat;
-		free(hn->nam);
-		free(hn);
-		ht->ct--;
-		return dat;
-		}
-	for (hp = hn, hn = hn->hchain; hn; hn = (hp = hn)->hchain)
-		if (!strcmp(hn->nam,nam))
-			{
-			hp->hchain = hn->hchain;
-			dat = hn->dat;
-			free(hn->nam);
-			free(hn);
-			ht->ct--;
-			return dat;
-			}
-	return NULL;
-}
- 
-void *zalloc(int l)
-{
-void *z;
- 
-	if (!(z = malloc(l)))
-		{
-		zerr("fatal error: out of memory: restarting");
-		execl(MYSELF,"zsh","-f",(void *) 0);
-		exit(1);
-		}
-	return z;
-}
-
-void *alloc(int l)
-{
-void *z;
- 
-	if (!(z = calloc(l,1)))
-		{
-		zerr("fatal error: out of memory: restarting");
-		execl(MYSELF,"zsh","-f",(void *) 0);
-		exit(1);
-		}
-	return z;
-}
-
-/* add a node to the end of a linked list */
-
-void addnode(table list,void *str)
-{
-	insnode(list,list->last,str);
-}
-
-/* insert a node in a linked list after 'last' */
-
-void insnode(table list,Node last,void *dat)
-{
-Node tmp;
- 
-	tmp = last->next;
-	last->next = alloc(sizeof(*tmp));
-	last->next->last = last;
-	last->next->dat = dat;
-	last->next->next = tmp;
-	if (tmp)
-		tmp->last = last->next;
-	else
-		list->last = last->next;
-}
-
-/* remove a node from a linked list */
-
-void *remnode(table list,Node nd)
-{
-void *dat;
-
-	nd->last->next = nd->next;
-	if (nd->next)
-		nd->next->last = nd->last;
-	else
-		list->last = nd->last;
-	free(nd);
-	dat = nd->dat;
-	return dat;
-}
-
-/* delete a character in a string */
-
-void chuck(char *str)
-{
-	while (str[0] = str[1])
-		str++;
-}
-
-/* get a node in a linked list */
-
-void *getnode(table list)
-{
-void *dat;
-Node node = list->first;
- 
-	if (!node)
-		return NULL;
-	dat = node->dat;
-	list->first = node->next;
-	if (node->next)
-		node->next->last = (Node) list;
-	else
-		list->last = (Node) list;
-	free(node);
-	return dat;
-}
-
-/* != 0 if the linked list has at least one entry */
-
-int full(table list)
-{
-	return list->first != NULL;
-}
- 
-void freetable(table tab,void (*freefunc)(void *))
-{
-Node node = tab->first,next;
- 
-	while (node)
-		{
-		next = node->next;
-		freefunc(node);
-		node = next;
-		}
-	free(tab);
-}
- 
-char *strdup(char *str)
-{
-char *ret = zalloc(strlen(str)+1);
- 
-	strcpy(ret,str);
-	return ret;
-}
-
-#ifndef STRSTR
-const char *strstr(const char *s,const char *t)
-{
-const char *p1,*p2;
- 
-	for (; *s; s++)
-		{
-		for (p1 = s, p2 = t; *p2; p1++,p2++)
-			if (*p1 != *p2)
-				break;
-		if (!*p2)
-			 return (char *) s;
-		}
-	return NULL;
-}
-#endif
-
End of table.c
echo table.pro 1>&2
sed 's/^-//' >table.pro <<'End of table.pro'
-table newtable();
-htable newhtable(int size);
-int hasher(char *s) /* copied from Programming in C++, p14 */;
-void addhnode(char *nam,void *dat,htable ht,void (*freefunc)(void *));
-void expandhtab(htable ht);
-void *gethnode(char *nam,htable ht);
-void freehtab(htable ht,void (*freefunc)(void *));
-void *remhnode(char *nam,htable ht);
-void *zalloc(int l);
-void *alloc(int l);
-void addnode(table list,void *str);
-void insnode(table list,Node last,void *dat);
-void *remnode(table list,Node nd);
-void chuck(char *str);
-void *getnode(table list);
-int full(table list);
-void freetable(table tab,void (*freefunc)(void *));
-char *strdup(char *str);
-/*const char *strstr(const char *s,const char *t); */
End of table.pro
echo test.c 1>&2
sed 's/^-//' >test.c <<'End of test.c'
-/*
-
-	test.c - the test builtin
-
-	This file is part of zsh, the Z shell.
-
-   zsh is free software; no one can prevent you from reading the source
-   code, or giving it to someone else.
-   This file is copyrighted under the GNU General Public License, which
-   can be found in the file called COPYING.
-
-   Copyright (C) 1990 Paul Falstad
-
-   zsh is distributed in the hope that it will be useful, but
-   WITHOUT ANY WARRANTY.  No author or distributor accepts
-   responsibility to anyone for the consequences of using it or for
-   whether it serves any particular purpose or works at all, unless he
-   says so in writing.  Refer to the GNU General Public License
-   for full details.
-
-   Everyone is granted permission to copy, modify and redistribute
-   zsh, but only under the conditions described in the GNU General Public
-   License.   A copy of this license is supposed to have been given to you
-   along with zsh so you can know your rights and responsibilities.
-   It should be in a file named COPYING.
-
-   Among other things, the copyright notice and this notice must be
-   preserved on all copies.
-
-*/
-
-#include "zsh.h"
-
-#ifndef F_OK
-#define F_OK 00
-#define R_OK 04
-#define W_OK 02
-#define X_OK 01
-#endif
-
-#include "test.pro"
-#include "table.pro"
-
-static char **arg;
-static int efg;
-
-void die(char *str)
-{
-	if (!efg)
-		zerrnam("test",str);
-	efg = 1;
-}
-
-int test(comm comm)
-{
-Node n;
-int t0;
-char **av,**ap;
-
-	for (n = comm->args->first, t0 = 0; n; n = n->next,t0++);
-	ap = av = (char **) zalloc((sizeof(char *))*(t0+1));
-	for (n = comm->args->first; n; n = n->next)
-		*ap++ = n->dat;
-	*ap = NULL;
-	t0 = testmain(av);
-	free(av);
-	return t0;
-}
-
-int testmain(char **argv)
-{
-int ret,isbrack;
-	
-	efg = 0;
-	arg = argv+1;
-	ret = testexpr();
-	if (efg)
-		return 1;
-	isbrack = !strcmp(*argv,"[");
-	if (isbrack)
-		{
-		if (*arg && !strcmp(*arg,"]") && !arg[1])
-			return !ret;
-		}
-	else
-		if (!*arg)
-			return !ret;
-	die("bad test format");
-	return 1;
-}
-
-int testexpr(void)
-{
-int ret = testexpr2(),ret2;
-
-	if (*arg && !strcmp(*arg,"-o"))
-		{
-		arg++;
-		ret2 = testexpr2();
-		if (efg)
-			return 0;
-		ret = ret || ret2;
-		}
-	return ret;
-}
-
-int testexpr2(void)
-{
-int ret = testexpr3(),ret2;
-
-	if (*arg && !strcmp(*arg,"-a"))
-		{
-		arg++;
-		ret2 = testexpr2();
-		if (efg)
-			return 0;
-		ret = ret && ret2;
-		}
-	return ret;
-}
-
-int testexpr3(void)
-{
-	if (*arg && !strcmp(*arg,"!"))
-		{
-		arg++;
-		return !testexpr3();
-		}
-	return testexpr4();
-}
-
-int testexpr4(void)
-{
-int ret,t0,t1;
-struct stat *st;
-char buf[16],*op;
-
-	if (!*arg)
-		{
-		die("expression expected");
-		return 0;
-		}
-	if (!strcmp(*arg,"("))
-		{
-		arg++;
-		ret = testexpr();
-		if (!*arg || strcmp(*arg,")"))
-			{
-			die("')' expected");
-			return 0;
-			}
-		arg++;
-		return ret;
-		}
-	if (**arg == '-' && !(*arg)[2])
-		{
-		switch((*arg++)[1])
-			{
-			case 'a': return(doaccess(F_OK));
-			case 'b': return(S_ISBLK(dostat()));
-			case 'c': return(S_ISCHR(dostat()));
-			case 'd': return(S_ISDIR(dostat()));
-			case 'f': return(S_ISREG(dostat()));
-			case 'g': return(!!(dostat() & S_ISGID));
-			case 'k': return(!!(dostat() & S_ISVTX));
-			case 'L': return(S_ISLNK(dostat()));
-			case 'p': return(S_ISFIFO(dostat()));
-			case 'r': return(doaccess(R_OK));
-			case 's': return((st = getstat()) && !!(st->st_size));
-			case 'S': return(S_ISSOCK(dostat()));
-			case 'u': return(!!(dostat() & S_ISUID));
-			case 'w': return(doaccess(W_OK));
-			case 'x': return(doaccess(X_OK));
-			case 'O': return((st = getstat()) && st->st_uid == geteuid());
-			case 'G': return((st = getstat()) && st->st_gid == getegid());
-			case 't': {
-				int t0 = 1;
-
-				if (*arg && isdigit(**arg))
-					t0 = atoi(*arg++);
-				return isatty(t0);
-				}
-			case 'z':
-				if (!*arg)
-					{
-					die("string expected");
-					return 0;
-					}
-				return !strlen(*arg++);
-			case 'n':
-				if (!*arg)
-					{
-					die("string expected");
-					return 0;
-					}
-				return !!strlen(*arg++);
-			case 'l':
-				sprintf(buf,"%d",strlen(*arg));
-				*arg = buf;
-				break;
-			}
-		}
-	if (!arg[1] || !strcmp(arg[1],"-o") || !strcmp(arg[1],"-a") ||
-			!strcmp(arg[1],"]") || !strcmp(arg[1],")"))
-		return(!!strlen(*arg++));
-	if (!arg[2])
-		{
-		die("bad expression");
-		return 0;
-		}
-	if (!strcmp(arg[1],"-nt"))
-		{
-		time_t a;
-
-		if (!(st = getstat()))
-			{
-			arg += 2;
-			return 0;
-			}
-		a = st->st_mtime;
-		arg++;
-		if (!(st = getstat()))
-			{
-			arg += 2;
-			return 0;
-			}
-		return a > st->st_mtime;
-		}
-	if (!strcmp(arg[1],"-ot"))
-		{
-		time_t a;
-
-		if (!(st = getstat()))
-			{
-			arg += 2;
-			return 0;
-			}
-		a = st->st_mtime;
-		arg++;
-		if (!(st = getstat()))
-			{
-			arg += 2;
-			return 0;
-			}
-		return a < st->st_mtime;
-		}
-	if (!strcmp(arg[1],"-ef"))
-		{
-		dev_t d;
-		ino_t i;
-
-		if (!(st = getstat()))
-			{
-			arg += 2;
-			return 0;
-			}
-		d = st->st_dev;
-		i = st->st_ino;
-		arg++;
-		if (!(st = getstat()))
-			{
-			arg += 2;
-			return 0;
-			}
-		return d == st->st_dev && i == st->st_ino;
-		}
-	if (!strcmp(arg[1],"~="))
-		{
-		arg += 3;
-		return patmatch(arg[-3],arg[-1]);
-		}
-	if (!strcmp(arg[1],"="))
-		{
-		arg += 3;
-		return !strcmp(arg[-3],arg[-1]);
-		}
-	if (!strcmp(arg[1],"!="))
-		{
-		arg += 3;
-		return !!strcmp(arg[-3],arg[-1]);
-		}
-	t0 = atoi(arg[0]);
-	op = arg[1];
-	arg += 2;
-	if (!strcmp(*arg,"-l"))
-		{
-		if (!arg[1])
-			{
-			die("string expected");
-			return 0;
-			}
-		t1 = strlen(arg[1]);
-		arg += 2;
-		}
-	else
-		t1 = atoi(*arg++);
-	if (!strcmp(op,"-eq"))
-		return t0 == t1;
-	if (!strcmp(op,"-ne"))
-		return t0 != t1;
-	if (!strcmp(op,"-lt"))
-		return t0 < t1;
-	if (!strcmp(op,"-le"))
-		return t0 <= t1;
-	if (!strcmp(op,"-gt"))
-		return t0 > t1;
-	if (!strcmp(op,"-ge"))
-		return t0 >= t1;
-	if (!efg)
-		zerrnam("test","unrecognized operator: %s",op);
-	efg = 1;
-	return 0;
-}
-
-int doaccess(int c)
-{
-	if (!*arg)
-		{
-		die("filename expected");
-		return 0;
-		}
-	return !access(*arg++,c);
-}
-
-struct stat *getstat(void)
-{
-static struct stat st;
-
-	if (!*arg)
-		{
-		die("filename expected");
-		return NULL;
-		}
-	if (!strncmp(*arg,"/dev/fd/",8))
-		{
-		if (fstat(atoi((*arg++)+8),&st))
-			return NULL;
-		}
-	else if (lstat(*arg++,&st))
-		return NULL;
-	return &st;
-}
-
-unsigned short dostat(void)
-{
-struct stat *st;
-
-	if (!(st = getstat()))
-		return 0;
-	return st->st_mode;
-}
-
End of test.c
echo test.pro 1>&2
sed 's/^-//' >test.pro <<'End of test.pro'
-void die(char *str);
-int test(comm comm);
-int testmain(char **argv);
-int testexpr(void);
-int testexpr2(void);
-int testexpr3(void);
-int testexpr4(void);
-int doaccess(int c);
-struct stat *getstat(void);
-unsigned short dostat(void);
End of test.pro
echo utils.c 1>&2
sed 's/^-//' >utils.c <<'End of utils.c'
-/*
-
-	utils.c - miscellaneous utilities
-
-	This file is part of zsh, the Z shell.
-
-   zsh is free software; no one can prevent you from reading the source
-   code, or giving it to someone else.
-   This file is copyrighted under the GNU General Public License, which
-   can be found in the file called COPYING.
-
-   Copyright (C) 1990 Paul Falstad
-
-   zsh is distributed in the hope that it will be useful, but
-   WITHOUT ANY WARRANTY.  No author or distributor accepts
-   responsibility to anyone for the consequences of using it or for
-   whether it serves any particular purpose or works at all, unless he
-   says so in writing.  Refer to the GNU General Public License
-   for full details.
-
-   Everyone is granted permission to copy, modify and redistribute
-   zsh, but only under the conditions described in the GNU General Public
-   License.   A copy of this license is supposed to have been given to you
-   along with zsh so you can know your rights and responsibilities.
-   It should be in a file named COPYING.
-
-   Among other things, the copyright notice and this notice must be
-   preserved on all copies.
-
-*/
-
-#include "zsh.h"
-#include "funcs.h"
-#include <pwd.h>
-#include <stdarg.h> /* had to change this to stdarg.h.old on one machine */
-#include <errno.h>
-#include <sys/dir.h>
-#include <fcntl.h>
-
-/* add vars to the parm hash table */
-
-void addvars(table vars)
-{
-char *s1,*s2;
-Node node;
-
-	for (node = vars->first; node; node = node->next)
-		{
-		s1 = node->dat;
-		untokenize(s1);
-		node = node->next;
-		s2 = node->dat;
-		dovarsubs(&s2);
-		if (errflag)
-			break;
-		untokenize(s2);
-		setparm(s1,s2,0,0);
-		}
-	free(vars);
-}
-
-/* set a parameter to an integer value */
-
-void setiparm(char *s,long v,int isint)
-{
-struct pmnode *pmn,*pmo;
-
-	if (!strcmp(s,"RANDOM"))
-		{
-		srand((unsigned long) v);
-		return;
-		}
-	if (!strcmp(s,"SECONDS"))
-		{
-		shtimer = v+time(NULL);
-		return;
-		}
-	if (pmo = gethnode(s,parmhtab))
-		{
-		char buf[12];
-
-		pmn = alloc(sizeof *pmn);
-		if (pmn->isint = pmo->isint | isint)
-			pmn->u.val = v;
-		else
-			{
-			sprintf(buf,"%ld",v);
-			pmn->u.str = strdup(buf);
-			}
-		addhnode(s,pmn,parmhtab,freepm);
-		}
-	else if (getenv(s) || (opts[ALLEXPORT] == OPT_SET))
-		{
-		char buf[12];
-
-		sprintf(buf,"%ld",v);
-		putenv(tricat(s,"=",buf));
-		}
-	else
-		{
-		char buf[12];
-
-		pmn = alloc(sizeof *pmn);
-		if (pmn->isint = isint)
-			pmn->u.val = v;
-		else
-			{
-			sprintf(buf,"%ld",v);
-			pmn->u.str = strdup(buf);
-			}
-		addhnode(s,pmn,parmhtab,freepm);
-		addlocal(s);
-		}
-	if (!strcmp(s,"PERIOD"))
-		{
-		period = v*60;
-		lastperiod = time(NULL)+period;
-		}
-	if (!strcmp(s,"HISTSIZE"))
-		{
-		tevs = v;
-		if (tevs <= 2)
-			tevs = 2;
-		}
-}
-
-/* set a parameter to a string value */
-
-void setparm(char *s,char *t,int ex,int isint)
-{
-struct pmnode *pmn,*pmo;
-
-	if (!strcmp(s,"RANDOM"))
-		{
-		srand((unsigned long) atol(t));
-		return;
-		}
-	if (!strcmp(s,"SECONDS"))
-		{
-		shtimer = atol(t)+time(NULL);
-		return;
-		}
-	if (ex && gethnode(s,parmhtab))
-		freepm(remhnode(s,parmhtab));
-	if (pmo = gethnode(s,parmhtab))
-		{
-		pmn = alloc(sizeof *pmn);
-		if (pmn->isint = pmo->isint | isint)
-			{
-			pmn->u.val = matheval(t);
-			free(t);
-			t = NULL;
-			}
-		else
-			pmn->u.str = t;
-		addhnode(s,pmn,parmhtab,freepm);
-		}
-	else if (ex || getenv(s) || (opts[ALLEXPORT] == OPT_SET))
-		putenv(tricat(s,"=",t));
-	else
-		{
-		pmn = alloc(sizeof *pmn);
-		if (pmn->isint = isint)
-			{
-			pmn->u.val = matheval(t);
-			free(t);
-			t = NULL;
-			}
-		else
-			pmn->u.str = t;
-		addhnode(s,pmn,parmhtab,freepm);
-#if 0
-		addlocal(s);
-#endif
-		}
-	if (!t)
-		return;
-	if (!strcmp(s,"PATH"))
-		parsepath();
-	if (!strcmp(s,"CDPATH"))
-		parsecdpath();
-	if (!strcmp(s,"IFS"))
-		{
-		free(ifs);
-		ifs = strdup(t);
-		}
-	if (!strcmp(s,"PERIOD"))
-		{
-		period = atoi(t)*60;
-		lastperiod = time(NULL)+period;
-		}
-	if (!strcmp(s,"HISTSIZE"))
-		{
-		tevs = atoi(t);
-		if (tevs <= 2)
-			tevs = 2;
-		}
-	if (!strcmp(s,"HOME"))
-		{
-		free(home);
-		home = xsymlink(t);
-		}
-	if (!strcmp(s,"MAIL") || !strcmp(s,"MAILCHECK") || !strcmp(s,"MAILPATH"))
-		lastmailcheck = 0;
-}
-
-void unsetparm(char *s)
-{
-char **pp;
-
-	if (!strcmp(s,"HOME"))
-		return;
-	if (!strcmp(s,"PERIOD"))
-		period = 0;
-	if (!strcmp(s,"HISTSIZE"))
-		tevs = 1;
-	if (gethnode(s,parmhtab))
-		{
-		freepm(remhnode(s,parmhtab));
-		return;
-		}
-	for (pp = environ; *pp; pp++)
-		if (!strncmp(*pp,s,strlen(s)) && (*pp)[strlen(s)] == '=')
-			{
-			while (pp[0] = pp[1])
-				pp++;
-			return;
-			}
-}
-
-/* get the integer value of a parameter */
-
-long getiparm(char *s)
-{
-struct pmnode *pmn;
-char *t;
-
-	if (!isalpha(*s) && !s[1])
-		{
-		t = getsparmval(s,1);
-		return (t) ? atoi(t) : 0;
-		}
-	if (s[0] == 'T' && s[1] == 'C' && !s[4])	/* TCxx */
-		return tgetnum(s+2);
-	if (!strcmp(s,"RANDOM"))
-		return rand() & 0x7fff;
-	if (!strcmp(s,"LINENO"))
-		return lineno;
-	if (!strcmp(s,"SECONDS"))
-		return time(NULL)-shtimer;
-	if (pmn = gethnode(s,parmhtab))
-		{
-		if (pmn->isint)
-			return pmn->u.val;
-		return atol(pmn->u.str);
-		}
-	return atol(getenv(s));
-}
-
-/* get the string value of a parameter */
-
-char *getparm(char *s)
-{
-struct pmnode *pmn;
-
-	if (!isalpha(*s) && !s[1])
-		return getsparmval(s,1);
-	if (s[0] == 'T' && s[1] == 'C' && !s[4])	/* TCxx */
-		{
-		static char buf[1024];
-		char *ss = buf;
-		int t0;
-
-		if (tgetstr(s+2,&ss))
-			return buf;
-		if ((t0 = tgetnum(s+2)) != -1)
-			{
-			sprintf(buf,"%d",t0);
-			return buf;
-			}
-		return NULL;
-		}
-	if (!strcmp(s,"LINENO"))
-		{
-		static char buf[8];
-
-		sprintf(buf,"%d",lineno);
-		return buf;
-		}
-	if (!strcmp(s,"RANDOM"))
-		{
-		static char buf[8];
-
-		sprintf(buf,"%d",rand() & 0x7fff);
-		return buf;
-		}
-	if (!strcmp(s,"SECONDS"))
-		{
-		static char buf[12];
-
-		sprintf(buf,"%ld",time(NULL)-shtimer);
-		return buf;
-		}
-	if (pmn = gethnode(s,parmhtab))
-		{
-		static char buf[12];
-
-		if (pmn->isint)
-			{
-			sprintf(buf,"%ld",pmn->u.val);
-			return buf;
-			}
-		return pmn->u.str;
-		}
-	return getenv(s);
-}
-
-/* parse the PATH parameter into directory names in a array of
-	strings and create the command hash table */
-
-void parsepath(void)
-{
-char *pptr = getparm("PATH"),*ptr;
-
-	if (path)
-		{
-		while(pathct)
-			free(path[--pathct]);
-		free(path);
-		}
-	for (pathct = 1, ptr = pptr; *ptr; ptr++)
-		if (*ptr == ':')
-			pathct++;
-	path = (char **) zalloc(pathct*sizeof(char *));
-	pathct = 0;
-	ptr = pptr;
-	while(pptr)
-		{
-		ptr = strchr(pptr,':');
-		if (ptr)
-			*ptr = '\0';
-		path[pathct] = strdup(pptr);
-		if (ptr)
-			{
-			*ptr = ':';
-			pptr = ptr+1;
-			}
-		else
-			pptr = NULL;
-		if (!*path[pathct])
-			{
-			free(path[pathct]);
-			path[pathct] = strdup(".");
-			}
-		pathsub(&path[pathct]);
-		if (*path[pathct] != '/' && strcmp(path[pathct],"."))
-			{
-#ifdef PATH_WARNINGS
-			zerr("PATH component not absolute pathname: %s",path[pathct]);
-#endif
-			free(path[pathct--]);
-			}
-		pathct++;
-		}
-	createchtab();
-}
-
-void parsecdpath(void)
-{
-char *pptr = getparm("CDPATH"),*ptr;
-
-	if (cdpath)
-		{
-		while(cdpathct)
-			free(cdpath[--cdpathct]);
-		free(cdpath);
-		}
-	if (pptr == NULL)
-		{
-		cdpath = (char **) zalloc(sizeof(char *));
-		cdpath[0] = strdup(".");
-		cdpathct = 1;
-		return;
-		}
-	for (cdpathct = 2, ptr = pptr; *ptr; ptr++)
-		if (*ptr == ':')
-			cdpathct++;
-	cdpath = (char **) zalloc(cdpathct*sizeof(char *));
-	cdpath[0] = strdup(".");
-	cdpathct = 1;
-	ptr = pptr;
-	while (pptr)
-		{
-		ptr = strchr(pptr,':');
-		if (ptr)
-			*ptr = '\0';
-		cdpath[cdpathct] = strdup(pptr);
-		if (ptr)
-			{
-			*ptr = ':';
-			pptr = ptr+1;
-			}
-		else
-			pptr = NULL;
-		pathsub(&cdpath[cdpathct]);
-		if (*cdpath[cdpathct] != '/')
-			{
-#ifdef PATH_WARNINGS
-			zerr("CDPATH component not absolute pathname: %s",cdpath[cdpathct]);
-#endif
-			free(cdpath[cdpathct--]);
-			}
-		cdpathct++;
-		}
-}
-
-/* source a file */
-
-int source(char *s)
-{
-int fd,cj = curjob,iact = opts[INTERACTIVE];
-FILE *obshin = bshin;
-
-	fd = SHIN;
-	opts[INTERACTIVE] = OPT_UNSET;
-	if ((SHIN = movefd(open(s,O_RDONLY))) == -1)
-		{
-		SHIN = fd;
-		curjob = cj;
-		opts[INTERACTIVE] = iact;
-		return 1;
-		}
-	bshin = fdopen(SHIN,"r");
-	loop();
-	fclose(bshin);
-	opts[INTERACTIVE] = iact;
-	bshin = obshin;
-	SHIN = fd;
-	peek = EMPTY;
-	curjob = cj;
-	errflag = 0;
-	retflag = 0;
-	return 0;
-}
-
-/* try to source a file in our home directory */
-
-void sourcehome(char *s)
-{
-char buf[MAXPATHLEN];
-
-	sprintf(buf,"%s/%s",getparm("HOME"),s);
-	(void) source(buf);
-}
-
-/* print an error */
-
-void zerrnam(char *cmd, char *fmt, ...)
-{
-va_list ap;
-char *str;
-int num;
-
-	va_start(ap,fmt);
-	fputs(cmd,stderr);
-	putc(':',stderr);
-	putc(' ',stderr);
-	while (*fmt)
-		if (*fmt == '%')
-			{
-			fmt++;
-			switch(*fmt++)
-				{
-				case 's':	/* string */
-					str = va_arg(ap,char *);
-					while (*str)
-						niceputc(*str++,stderr);
-					break;
-				case 'l':	/* string with a length */
-					num = va_arg(ap,int);
-					str = va_arg(ap,char *);
-					while (num--)
-						niceputc(*str++,stderr);
-					break;
-				case 'd':	/* number */
-					num = va_arg(ap,int);
-					fprintf(stderr,"%d",num);
-					break;
-				case '%':
-					putc('%',stderr);
-					break;
-				case 'c':	/* char */
-					num = va_arg(ap,int);
-					niceputc(num,stderr);
-					break;
-				case 'e':	/* system error */
-					num = va_arg(ap,int);
-					if (num == EINTR)
-						{
-						fputs("interrupt\n",stderr);
-						errflag = 1;
-						return;
-						}
-					fputc(tolower(sys_errlist[num][0]),stderr);
-					fputs(sys_errlist[num]+1,stderr);
-					break;
-				}
-			}
-		else
-			putc(*fmt++,stderr);
-	putc('\n',stderr);
-	va_end(ap);
-}
-
-void zerr(char *fmt,...)
-{
-va_list ap;
-char *str;
-int num;
-
-	va_start(ap,fmt);
-	fputs("zsh: ",stderr);
-	while (*fmt)
-		if (*fmt == '%')
-			{
-			fmt++;
-			switch(*fmt++)
-				{
-				case 's':
-					str = va_arg(ap,char *);
-					while (*str)
-						niceputc(*str++,stderr);
-					break;
-				case 'l':
-					num = va_arg(ap,int);
-					str = va_arg(ap,char *);
-					while (num--)
-						niceputc(*str++,stderr);
-					break;
-				case 'd':
-					num = va_arg(ap,int);
-					fprintf(stderr,"%d",num);
-					break;
-				case '%':
-					putc('%',stderr);
-					break;
-				case 'c':
-					num = va_arg(ap,int);
-					niceputc(num,stderr);
-					break;
-				case 'e':
-					num = va_arg(ap,int);
-					if (num == EINTR)
-						{
-						fputs("interrupt\n",stderr);
-						errflag = 1;
-						return;
-						}
-					fputc(tolower(sys_errlist[num][0]),stderr);
-					fputs(sys_errlist[num]+1,stderr);
-					break;
-				}
-			}
-		else
-			putc(*fmt++,stderr);
-	putc('\n',stderr);
-	va_end(ap);
-}
-
-void niceputc(int c,FILE *f)
-{
-	if (istok(c))
-		{
-		if (c >= Pound && c <= Qtick)
-			putc(tokens[c-Pound],f);
-		return;
-		}
-	c &= 0x7f;
-	if (c >= ' ' && c < '\x7f')
-		putc(c,f);
-	else if (c == '\n')
-		{
-		putc('\\',f);
-		putc('n',f);
-		}
-	else
-		{
-		putc('^',f);
-		putc(c|'A',f);
-		}
-}
-
-/* enable ^C interrupts */
-
-void intr(void)
-{
-struct sigvec vec = { handler,sigmask(SIGINT),SV_INTERRUPT };
-	
-	if (interact)
-		sigvec(SIGINT,&vec,NULL);
-	sigsetmask(0);
-}
-
-void noholdintr(void)
-{
-	intr();
-}
-
-void holdintr(void)
-{
-struct sigvec vec = { handler,sigmask(SIGINT),0 };
-
-	if (interact)
-		{
-		sigvec(SIGINT,&vec,NULL);
-		sigsetmask(0);
-		}
-}
-
-char *fgetline(char *buf,int len,FILE *in)
-{
-	if (!fgets(buf,len,in))
-		return NULL;
-	buf[len] = '\0';
-	buf[strlen(buf)-1] = '\0';
-	return buf;
-}
-
-/* get a symlink-free pathname for s relative to PWD */
-
-char *findcwd(char *s)
-{
-char *t;
-
-	if (*s == '/')
-		return xsymlink(s);
-	s = tricat((cwd[1]) ? cwd : "","/",s);
-	t = xsymlink(s);
-	free(s);
-	return t;
-}
-
-static char xbuf[MAXPATHLEN];
-
-/* expand symlinks in s, and remove other weird things */
-
-char *xsymlink(char *s)
-{
-	if (*s != '/')
-		return NULL;
-	strcpy(xbuf,"");
-	if (xsymlinks(s+1))
-		return strdup(s);
-	if (!*xbuf)
-		return strdup("/");
-	return strdup(xbuf);
-}
-
-char **slashsplit(char *s)
-{
-char *t,**r,**q;
-int t0;
-
-	if (!*s)
-		return (char **) calloc(sizeof(char **),1);
-	for (t = s, t0 = 0; *t; t++)
-		if (*t == '/')
-			t0++;
-	q  = r = (char **) zalloc(sizeof(char **)*(t0+2));
-	while (t = strchr(s,'/'))
-		{
-		*t = '\0';
-		*q++ = strdup(s);
-		*t = '/';
-		while (*t == '/')
-			t++;
-		if (!*t)
-			{
-			*q = NULL;
-			return r;
-			}
-		s = t;
-		}
-	*q++ = strdup(s);
-	*q = NULL;
-	return r;
-}
-
-int islink(char *s)
-{
-char xbuf[MAXPATHLEN];
-
-	if (readlink(s,xbuf,1) == -1 && errno == EINVAL)
-		return 0;
-	return 1;
-}
-
-int xsymlinks(char *s)
-{
-char **pp,**opp;
-char xbuf2[MAXPATHLEN],xbuf3[MAXPATHLEN];
-int t0;
-
-	opp = pp = slashsplit(s);
-	for (; *pp; pp++)
-		{
-		if (!strcmp(*pp,"."))
-			{
-			free(*pp);
-			continue;
-			}
-		if (!strcmp(*pp,".."))
-			{
-			char *p;
-
-			free(*pp);
-			if (!strcmp(xbuf,"/"))
-				continue;
-			p = xbuf+strlen(xbuf);
-			while (*--p != '/');
-			*p = '\0';
-			continue;
-			}
-		sprintf(xbuf2,"%s/%s",xbuf,*pp);
-		t0 = readlink(xbuf2,xbuf3,MAXPATHLEN);
-		if (t0 == -1)
-			{
-			if (errno != EINVAL)
-				{
-				while (*pp)
-					free(*pp++);
-				free(opp);
-				return 1;
-				}
-			strcat(xbuf,"/");
-			strcat(xbuf,*pp);
-			free(*pp);
-			}
-		else
-			{
-			xbuf3[t0] = '\0'; /* STUPID */
-			if (*xbuf3 == '/')
-				{
-				strcpy(xbuf,"");
-				if (xsymlinks(xbuf3+1))
-					return 1;
-				}
-			else
-				if (xsymlinks(xbuf3))
-					return 1;
-			free(*pp);
-			}
-		}
-	free(opp);
-	return 0;
-}
-
-void printdir(char *s)
-{
-int t0;
-
-	if (!strncmp(s,home,t0 = strlen(home)))
-		{
-		putchar('~');
-		fputs(s+t0,stdout);
-		}
-	else
-		fputs(s,stdout);
-}
-
-
-int ddifftime(time_t t1,time_t t2)
-{
-	return ((long) t2-(long) t1);
-}
-
-/* see if jobs need printing */
-
-void scanjobs(void)
-{
-int t0;
-
-	for (t0 = 1; t0 != MAXJOB; t0++)
-		if (jobtab[t0].stat & STAT_CHANGED)
-			printjob(jobtab+t0,0);
-}
-
-/* do pre-prompt stuff */
-
-void preprompt(void)
-{
-int diff;
-list list;
-char *mc = getparm("MAILCHECK"),*wc = getparm("LOGCHECK");
-struct schnode *sch,*schl;
-
-	if (unset(NOTIFY))
-		scanjobs();
-	if (errflag)
-		return;
-	if (list = gethnode("precmd",shfunchtab))
-		newrunlist(list);
-	if (errflag)
-		return;
-	if (period && (time(NULL) > lastperiod+period) &&
-			(list = gethnode("periodic",shfunchtab)))
-		{
-		newrunlist(list);
-		lastperiod = time(NULL);
-		}
-	if (errflag)
-		return;
-	if (getparm("WATCH"))
-		{
-		diff = (int) ddifftime(lastwatch,time(NULL));
-		if (diff > ((wc) ? atoi(wc)*60 : 300))
-			{
-			lastwatch = time(NULL);
-			watch();
-			}
-		}
-	if (errflag)
-		return;
-	diff = (int) ddifftime(lastmailcheck,time(NULL));
-	if (diff > ((mc) ? atoi(mc) : 60))
-		{
-		lastmailcheck = time(NULL);
-		if (getparm("MAILPATH"))
-			checkmailpath();
-		else
-			checkmail();
-		}
-	for (schl = (struct schnode *) &scheds, sch = scheds; sch;
-			sch = (schl = sch)->next)
-		{
-		if (sch->time < time(NULL))
-			{
-			execstring(sch->cmd);
-			schl->next = sch->next;
-			free(sch);
-			}
-		if (errflag)
-			return;
-		}
-}
- 
-void checkmail(void)
-{
-struct stat st;
-char *s;
-
-	if (!(s = getparm("MAIL")))
-		return;
-	if (stat(s,&st) == -1)
-		{
-		if (errno != ENOENT)
-			zerr("%e: %s",errno,getparm("MAIL"));
-		lastmailval = 0;
-		lastmailsize = 0;
-		return;
-		}
-	else
-		if (lastmailval != -1 && lastmailval < st.st_mtime &&
-				lastmailsize < st.st_size)
-			zerr("you have new mail.");
-	lastmailval = st.st_mtime;
-	lastmailsize = st.st_size;
-}
-
-void checkfirstmail(void)
-{
-struct stat st;
-char *s;
-
-	if (!(s = getparm("MAIL")))
-		return;
-	if (stat(s,&st) == -1)
-		{
-		if (errno != ENOENT)
-			zerr("%e: %s",errno,getparm("MAIL"));
-		lastmailval = 0;
-		lastmailsize = 0;
-		return;
-		}
-	lastmailval = st.st_mtime;
-	lastmailsize = st.st_size;
-	zerr("you have mail.");
-}
- 
-void checkmailpath(void)
-{
-struct stat st;
-char *s = getparm("MAILPATH"),*v,*u,c,d;
-
-	for (;;)
-		{
-		for (v = s; *v && *v != '?' && *v != ':'; v++);
-		c = *v;
-		*v = '\0';
-		if (c != '?')
-			u = NULL;
-		else
-			{
-			for (u = v+1; *u && *u != ':'; u++);
-			d = *u;
-			*u = '\0';
-			}
-		if (stat(s,&st) == -1)
-			{
-			if (errno != ENOENT)
-				zerr("%e: %s",errno,getparm("MAIL"));
-			}
-		else
-			if (lastmailval != -1 && lastmailval < st.st_mtime &&
-					lastmailsize < st.st_size)
-				if (!u)
-					fprintf(stderr,"You have new mail.\n");
-				else
-					{
-					char *z = u;
-
-					while (*z)
-						if (*z == '$' && z[1] == '_')
-							{
-							fprintf(stderr,"%s",s);
-							z += 2;
-							}
-						else
-							fputc(*z++,stderr);
-					fputc('\n',stderr);
-					}
-		lastmailval = st.st_mtime;
-		lastmailsize = st.st_size;
-		*v = c;
-		if (u)
-			*u = d;
-		if (!c || (u && !d))
-			break;
-		v = (u) ? u+1 : v+1;
-		}
-}
-
-/* create command hash table */
-
-void createchtab(void)
-{
-int t0,dot = 0;
-struct direct *de;
-DIR *dir;
-struct chnode *cc;
-
-	holdintr();
-	if (chtab)
-		freehtab(chtab,freechnode);
-	chtab = newhtable(101);
-	for (t0 = 0; t0 != pathct; t0++)
-		if (!strcmp(".",path[t0]))
-			{
-			dot = 1;
-			break;
-			}
-	for (t0 = pathct-1; t0 >= 0; t0--)
-		if (!strcmp(".",path[t0]))
-			dot = 0;
-		else
-			{
-			dir = opendir(path[t0]);
-			if (!dir)
-				{
-				zerr("%e: %s",errno,path[t0]);
-				continue;
-				}
-			readdir(dir); readdir(dir);
-			while (de = readdir(dir))
-				{
-				cc = alloc(sizeof(struct chnode));
-				cc->type = (dot) ? EXCMD_POSTDOT : EXCMD_PREDOT;
-				cc->globstat = GLOB;
-				cc->u.nam = tricat(path[t0],"/",de->d_name);
-				addhnode(strdup(de->d_name),cc,chtab,freechnode);
-				}
-			closedir(dir);
-			}
-	addintern(chtab);
-	noholdintr();
-}
-
-void freechnode(void *a)
-{
-struct chnode *c = (struct chnode *) a;
-
-	if (c->type != BUILTIN)
-		free(c->u.nam);
-	free(c);
-}
-
-void freestr(void *a)
-{
-	free(a);
-}
-
-void freeanode(void *a)
-{
-struct anode *c = (struct anode *) a;
-
-	free(c->text);
-	free(c);
-}
-
-void freeredir(void *a)
-{
-struct fnode *f = (struct fnode *) a;
-
-	if (f)
-		{
-		if (f->type == HEREDOC)
-			close(f->u.fd2);
-		else
-			free(f->u.name);
-		free(f);
-		}
-}
-
-void freeshfunc(void *a)
-{
-	freelist((list) a);
-}
-
-void freepm(void *a)
-{
-struct pmnode *pm = a;
-
-	if (!pm->isint)
-		free(pm->u.str);
-	free(pm);
-}
-
-void restoretty(void)
-{
-	settyinfo(&shttyinfo);
-}
-
-void gettyinfo(struct ttyinfo *ti)
-{
-	if (jobbing)
-		{
-#ifndef BUGGY_GCC
-#ifdef TERMIOS
-		ioctl(SHTTY,TCGETS,&ti->termios);
-#else
-		ioctl(SHTTY,TIOCGETP,&ti->sgttyb);
-		ioctl(SHTTY,TIOCGETC,&ti->tchars);
-		ioctl(SHTTY,TIOCGLTC,&ti->ltchars);
-#endif
-		ioctl(SHTTY,TIOCGWINSZ,&ti->winsize);
-#else
-#ifdef TERMIOS
-		ioctl(SHTTY,	(	0x40000000	|((sizeof( struct termios)&0xff		)<<16)|('T'<<8)| 8)  ,&ti->termios);
-#else
-		ioctl(SHTTY,(0x40000000|((sizeof(struct sgttyb)&0x1fff)<<16)|
-			('t'<<8)|8),&ti->sgttyb);
-		ioctl(SHTTY,(0x40000000|((sizeof(struct tchars)&0x1fff)<<16)|
-			('t'<<8)|18),&ti->tchars);
-		ioctl(SHTTY,(0x40000000|((sizeof(struct ltchars)&0x1fff)<<16)|
-			('t'<<8)|116),&ti->ltchars);
-#endif
-		ioctl(SHTTY,(	0x40000000	|((sizeof( struct winsize)&0xff		)<<16)|('t'<<8)| 104) 	,&ti->winsize);
-#endif
-		}
-}
-
-void settyinfo(struct ttyinfo *ti)
-{
-	if (jobbing)
-		{
-#ifndef BUGGY_GCC
-#ifdef TERMIOS
-		ioctl(SHTTY,TCSETS,&ti->termios);
-#else
-		ioctl(SHTTY,TIOCSETP,&ti->sgttyb);
-		ioctl(SHTTY,TIOCSETC,&ti->tchars);
-		ioctl(SHTTY,TIOCSLTC,&ti->ltchars);
-#endif
-		ioctl(SHTTY,TIOCSWINSZ,&ti->winsize);
-#else
-#ifdef TERMIOS
-		ioctl(SHTTY,	(	0x80000000	|((sizeof( struct termios)&0xff		)<<16)|('T'<<8)| 9)  ,&ti->termios);
-#else
-		ioctl(SHTTY,(0x80000000|((sizeof( struct sgttyb)&0x1fff)<<16)|
-			('t'<<8)|9),&ti->sgttyb);
-		ioctl(SHTTY,(0x80000000|((sizeof(struct tchars)&0x1fff)<<16)|
-			('t'<<8)|17),&ti->tchars);
-		ioctl(SHTTY,(0x80000000|((sizeof(struct ltchars)&0x1fff)<<16)|
-			('t'<<8)|117),&ti->ltchars);
-#endif
-		ioctl(SHTTY,(	0x80000000	|((sizeof( struct winsize)&0xff		)<<16)|('t'<<8)| 103) 	,&ti->winsize);
-#endif
-		}
-}
-
-int zyztem(char *s,char *t)
-{
-#ifdef WAITPID
-int pid,statusp;
-
-	if (!(pid = fork()))
-		{
-		s = tricat(s," ",t);
-		execl("/bin/sh","sh","-c",s,(char *) 0);
-		_exit(1);
-		}
-	waitpid(pid,&statusp,WUNTRACED);
-	if (WIFEXITED(SP(statusp)))
-		return WEXITSTATUS(SP(statusp));
-	return 1;
-#else
-	if (!waitfork())
-		{
-		s = tricat(s," ",t);
-		execl("/bin/sh","sh","-c",s,(char *) 0);
-		_exit(1);
-		}
-	return 0;
-#endif
-}
-
-#ifndef WAITPID
-
-/* fork a process and wait for it to complete without confusing
-	the SIGCHLD handler */
-
-int waitfork(void)
-{
-int pipes[2];
-char x;
-
-	pipe(pipes);
-	if (!fork())
-		{
-		close(pipes[0]);
-		signal(SIGCHLD,SIG_DFL);
-		if (!fork())
-			return 0;
-		wait(NULL);
-		_exit(0);
-		}
-	close(pipes[1]);
-	read(pipes[0],&x,1);
-	close(pipes[0]);
-	return 1;
-}
-
-#endif
-
-/* move a fd to a place >= 10 */
-
-int movefd(int fd)
-{
-int fe;
-
-	if (fd == -1)
-		return fd;
-	if ((fe = dup(fd)) < 10)
-		fe = movefd(fe);
-	close(fd);
-	return fe;
-}
-
-/* move fd x to y */
-
-void redup(int x,int y)
-{
-	if (x != y)
-		{
-		dup2(x,y);
-		close(x);
-		}
-}
-
-void settrap(char *s,int empty)
-{
-int t0;
-
-	if (strncmp(s,"TRAP",4))
-		return;
-	for (t0 = 0; t0 != SIGCOUNT+2; t0++)
-		if (!strcmp(s+4,sigs[t0]))
-			{
-			if (jobbing && (t0 == SIGTTOU || t0 == SIGTSTP || t0 == SIGTTIN
-					|| t0 == SIGPIPE))
-				{
-				zerr("can't trap SIG%s in interactive shells",s);
-				return;
-				}
-			if (empty)
-				{
-				sigtrapped[t0] = 2;
-				if (t0 && t0 < SIGCOUNT && t0 != SIGCHLD)
-					{
-					signal(t0,SIG_IGN);
-					sigtrapped[t0] = 2;
-					}
-				}
-			else
-				{
-				if (t0 && t0 < SIGCOUNT && t0 != SIGCHLD)
-					signal(t0,handler);
-				sigtrapped[t0] = 1;
-				}
-			return;
---cut here---cut here---cut here---



More information about the Alt.sources mailing list