[comp.sources.misc] v18i088: zsh2.00 - The Z shell, Part05/15

pfalstad@phoenix.princeton.edu (Paul Falstad) (04/24/91)

Submitted-by: Paul Falstad <pfalstad@phoenix.princeton.edu>
Posting-number: Volume 18, Issue 88
Archive-name: zsh2.00/part05

#!/bin/sh
# this is zsh2.00.00.shar.05 (part 5 of zsh2.00.00)
# do not concatenate these parts, unpack them in order with /bin/sh
# file zsh2.00/src/cond.c continued
#
if test ! -r _shar_seq_.tmp; then
	echo 'Please unpack part 1 first!'
	exit 1
fi
(read Scheck
 if test "$Scheck" != 5; then
	echo Please unpack part "$Scheck" next!
	exit 1
 else
	exit 0
 fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
	echo 'x - still skipping zsh2.00/src/cond.c'
else
echo 'x - continuing file zsh2.00/src/cond.c'
sed 's/^X//' << 'SHAR_EOF' >> 'zsh2.00/src/cond.c' &&
X
X	cond.c - evaluate conditional expressions
X
X	This file is part of zsh, the Z shell.
X
X	zsh is free software; no one can prevent you from reading the source
X   code, or giving it to someone else.
X
X   This file is copyrighted under the GNU General Public License, which
X   can be found in the file called COPYING.
X
X   Copyright (C) 1990, 1991 Paul Falstad
X
X   zsh is distributed in the hope that it will be useful, but
X   WITHOUT ANY WARRANTY.  No author or distributor accepts
X   responsibility to anyone for the consequences of using it or for
X   whether it serves any particular purpose or works at all, unless he
X   says so in writing.  Refer to the GNU General Public License
X   for full details.
X
X   Everyone is granted permission to copy, modify and redistribute
X   zsh, but only under the conditions described in the GNU General Public
X   License.   A copy of this license is supposed to have been given to you
X   along with zsh so you can know your rights and responsibilities.
X   It should be in a file named COPYING.
X
X   Among other things, the copyright notice and this notice must be
X   preserved on all copies.
X
X*/
X
X#include "zsh.h"
X#include "funcs.h"
X
X#ifndef F_OK
X#define F_OK 00
X#define R_OK 04
X#define W_OK 02
X#define X_OK 01
X#endif
X
Xint evalcond(c) /**/
XCond c;
X{
Xstruct stat *st;
X
X	switch (c->type)
X		{
X		case COND_NOT: return !evalcond(c->left);
X		case COND_AND: return evalcond(c->left) && evalcond(c->right);
X		case COND_OR: return evalcond(c->left) || evalcond(c->right);
X		}
X	singsub((char **) &c->left);
X	if (c->right)
X		singsub((char **) &c->right);
X	switch (c->type)
X		{
X		case COND_STREQ: return matchpat(c->left,c->right);
X		case COND_STRNEQ: return !matchpat(c->left,c->right);
X		case COND_STRLT: return strcmp(c->left,c->right) < 0;
X		case COND_STRGTR: return strcmp(c->left,c->right) > 0;
X		case 'a': return(doaccess(c->left,F_OK));
X		case 'b': return(S_ISBLK(dostat(c->left)));
X		case 'c': return(S_ISCHR(dostat(c->left)));
X		case 'd': return(S_ISDIR(dostat(c->left)));
X		case 'f': return(S_ISREG(dostat(c->left)));
X		case 'g': return(!!(dostat(c->left) & S_ISGID));
X		case 'k': return(!!(dostat(c->left) & S_ISVTX));
X		case 'n': return(!strlen(c->left));
X		case 'o': return(optison(c->left));
X		case 'p': return(S_ISFIFO(dostat(c->left)));
X		case 'r': return(doaccess(c->left,R_OK));
X		case 's': return((st = getstat(c->left)) && !!(st->st_size));
X		case 'S': return(S_ISSOCK(dostat(c->left)));
X		case 'u': return(!!(dostat(c->left) & S_ISUID));
X		case 'w': return(doaccess(c->left,W_OK));
X		case 'x': return(doaccess(c->left,X_OK));
X		case 'z': return(!!strlen(c->left));
X		case 'L': return(S_ISLNK(dostat(c->left)));
X		case 'O': return((st = getstat(c->left)) && st->st_uid == geteuid());
X		case 'G': return((st = getstat(c->left)) && st->st_gid == getegid());
X		case 't': return isatty(matheval(c->left));
X		case COND_EQ: return matheval(c->left) == matheval(c->right);
X		case COND_NE: return matheval(c->left) != matheval(c->right);
X		case COND_LT: return matheval(c->left) < matheval(c->right);
X		case COND_GT: return matheval(c->left) > matheval(c->right);
X		case COND_LE: return matheval(c->left) <= matheval(c->right);
X		case COND_GE: return matheval(c->left) >= matheval(c->right);
X		case COND_NT: case COND_OT:
X			{
X			time_t a;
X			if (!(st = getstat(c->left)))
X				return 0;
X			a = st->st_mtime;
X			if (!(st = getstat(c->right)))
X				return 0;
X			return (c->type == COND_NT) ? a > st->st_mtime : a < st->st_mtime;
X			}
X		case COND_EF:
X			{
X			dev_t d;
X			ino_t i;
X
X			if (!(st = getstat(c->left)))
X				return 0;
X			d = st->st_dev;
X			i = st->st_ino;
X			if (!(st = getstat(c->right)))
X				return 0;
X			return d == st->st_dev && i == st->st_ino;
X			}
X		default: zerr("bad cond structure",NULL,0);
X		}
X	return 0;
X}
X
Xint doaccess(s,c) /**/
Xchar *s;int c;
X{
X	return !access(s,c);
X}
X
Xstruct stat *getstat(s) /**/
Xchar *s;
X{
Xstatic struct stat st;
X
X	if (!strncmp(s,"/dev/fd/",8))
X		{
X		if (fstat(atoi(s+8),&st))
X			return NULL;
X		}
X	else if (lstat(s,&st))
X		return NULL;
X	return &st;
X}
X
Xunsigned short dostat(s) /**/
Xchar *s;
X{
Xstruct stat *st;
X
X	if (!(st = getstat(s)))
X		return 0;
X	return st->st_mode;
X}
X
Xint optison(s) /**/
Xchar *s;
X{
Xint i;
X
X	if (strlen(s) == 1)
X		return opts[*s];
X	if ((i = optlookup(s)) != -1)
X		return opts[i];
X	zerr("no such option: %s",s,0);
X	return 0;
X}
X
SHAR_EOF
echo 'File zsh2.00/src/cond.c is complete' &&
chmod 0644 zsh2.00/src/cond.c ||
echo 'restore of zsh2.00/src/cond.c failed'
Wc_c="`wc -c < 'zsh2.00/src/cond.c'`"
test 4322 -eq "$Wc_c" ||
	echo 'zsh2.00/src/cond.c: original size 4322, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= zsh2.00/src/cond.pro ==============
if test -f 'zsh2.00/src/cond.pro' -a X"$1" != X"-c"; then
	echo 'x - skipping zsh2.00/src/cond.pro (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting zsh2.00/src/cond.pro (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'zsh2.00/src/cond.pro' &&
Xint evalcond DCLPROTO((Cond c));
Xint doaccess DCLPROTO((char *s,int c));
Xstruct stat *getstat DCLPROTO((char *s));
Xunsigned short dostat DCLPROTO((char *s));
Xint optison DCLPROTO((char *s));
SHAR_EOF
chmod 0644 zsh2.00/src/cond.pro ||
echo 'restore of zsh2.00/src/cond.pro failed'
Wc_c="`wc -c < 'zsh2.00/src/cond.pro'`"
test 191 -eq "$Wc_c" ||
	echo 'zsh2.00/src/cond.pro: original size 191, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= zsh2.00/src/exec.c ==============
if test -f 'zsh2.00/src/exec.c' -a X"$1" != X"-c"; then
	echo 'x - skipping zsh2.00/src/exec.c (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting zsh2.00/src/exec.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'zsh2.00/src/exec.c' &&
X/*
X
X	exec.c - command execution
X
X	This file is part of zsh, the Z shell.
X
X	zsh is free software; no one can prevent you from reading the source
X   code, or giving it to someone else.
X
X   This file is copyrighted under the GNU General Public License, which
X   can be found in the file called COPYING.
X
X   Copyright (C) 1990, 1991 Paul Falstad
X
X   zsh is distributed in the hope that it will be useful, but
X   WITHOUT ANY WARRANTY.  No author or distributor accepts
X   responsibility to anyone for the consequences of using it or for
X   whether it serves any particular purpose or works at all, unless he
X   says so in writing.  Refer to the GNU General Public License
X   for full details.
X
X   Everyone is granted permission to copy, modify and redistribute
X   zsh, but only under the conditions described in the GNU General Public
X   License.   A copy of this license is supposed to have been given to you
X   along with zsh so you can know your rights and responsibilities.
X   It should be in a file named COPYING.
X
X   Among other things, the copyright notice and this notice must be
X   preserved on all copies.
X
X*/
X
X#include "zsh.h"
X#include "funcs.h"
X#include <sys/errno.h>
X#include <sys/dir.h>
X
X#define execerr() { if (forked) exit(1); \
X	closemnodes(mfds); errflag = 1; return; }
X
X/* parse list in a string */
X
XList parselstring(s) /**/
Xchar *s;
X{
XList l;
X
X	hungets(s);
X	strinbeg();
X	pushheap();
X	if (!(l = parlist()))
X		{
X		strinend();
X		hflush();
X		popheap();
X		return NULL;
X		}
X	strinend();
X	return l;
X}
X
X/* execute a string */
X
Xvoid execstring(s) /**/
Xchar *s;
X{
XList l;
X
X	if (l = parselstring(s))
X		{
X		execlist(l);
X		popheap();
X		}
X}
X
X/* duplicate a list and run it */
X
Xvoid newrunlist(l) /**/
XList l;
X{
X	List a = dupstruct(l); runlist(a);
X}
X
X/* fork and set limits */
X
Xint phork() /**/
X{
Xint pid = fork(),t0;
X
X	if (pid == -1)
X		{
X		zerr("fork failed: %e",NULL,errno);
X		return -1;
X		}
X	if (!pid)
X		for (t0 = 0; t0 != RLIM_NLIMITS; t0++)
X			setrlimit(t0,limits+t0);
X	return pid;
X}
X
X/* execute a current shell command */
X
Xint execcursh(cmd) /**/
XCmd cmd;
X{
X	runlist(cmd->u.list);
X	cmd->u.list = NULL;
X	return lastval;
X}
X
X/* execve after handling $_ and #! */
X
Xvoid zexecve(pth,argv,ee,b1,b2) /**/
Xchar *pth;char **argv;int *ee;char *b1;char *b2;
X{
Xint eno;
Xchar buf[MAXPATHLEN*2];
Xchar **eep;
X
X	for (eep = environ; *eep; eep++)
X		if (**eep == '_' && (*eep)[1] == '=')
X			break;
X	buf[0] = '_';
X	buf[1] = '=';
X	if (*pth == '/')
X		strcpy(buf+2,pth);
X	else
X		sprintf(buf+2,"%s/%s",cwd,pth);
X	if (!*eep)
X		eep[1] = NULL;
X	*eep = buf;
X	execve(pth,argv,environ);
X	if ((eno = errno) == ENOEXEC)
X		{
X		char buf[33],*ptr,*ptr2,*argv0;
X		int fd,ct,t0;
X
X		if ((fd = open(pth,O_RDONLY)) >= 0)
X			{
X			argv0 = *argv;
X			*argv = pth;
X			ct = read(fd,buf,32);
X			close(fd);
X			if (ct > 0)
X				{
X				if (buf[0] == '#')
X					if (buf[1] == '!')
X						{
X						for (t0 = 0; t0 != ct; t0++)
X							if (buf[t0] == '\n')
X								buf[t0] = '\0';
X						buf[32] = '\0';
X						for (ptr = buf+2; *ptr && *ptr == ' '; ptr++);
X						for (ptr2 = ptr; *ptr && *ptr != ' '; ptr++);
X						if (*ptr)
X							{
X							*ptr = '\0';
X							argv[-2] = ptr2;
X							argv[-1] = ptr+1;
X							execve(ptr2,argv-2,environ);
X							}
X						else
X							{
X							argv[-1] = ptr2;
X							execve(ptr2,argv-1,environ);
X							}
X						}
X					else
X						{
X						argv[-1] = MYSELF;
X						execve(MYSELF,argv-1,environ);
X						}
X				else
X					{
X					for (t0 = 0; t0 != ct; t0++)
X						if (!buf[t0])
X							break;
X					if (t0 == ct)
X						{
X						argv[-1] = "/bin/sh";
X						execve("/bin/sh",argv-1,environ);
X						}
X					}
X				}
X			else
X				eno = errno;
X			*argv = argv0;
X			}
X		else
X			eno = errno;
X		}
X	if (ee && eno != ENOENT)
X		{
X		*ee = eno;
X		strcpy(b1,b2);
X		}
X}
X
X#define MAXCMDLEN (MAXPATHLEN*4)
X
X/* execute an external command */
X
Xvoid execute(args,dash) /**/
XLklist args;int dash;
X{
Xchar **argv,*arg0;
Xchar *z,*s,buf[MAXCMDLEN],buf2[MAXCMDLEN];
XCmdnam cn;
Xint tl,ee = 0;
X
X	cn = gethnode(peekfirst(args),cmdnamtab);
X	if (s = zgetenv("STTY"))
X		zyztem("stty",s);
X	arg0 = peekfirst(args);
X	if (z = zgetenv("ARGV0"))
X		{
X		setdata(firstnode(args),ztrdup(z));
X		delenv(z-6);
X		}
X	else if (dash)
X		{
X		sprintf(buf2,"-%s",arg0);
X		setdata(firstnode(args),ztrdup(buf2));
X		}
X	argv = makecline(args);
X	fixsigs();
X	if (cn && (cn->type != BUILTIN && cn->type != SHFUNC))
X		{
X		if (cn->type == EXCMD_POSTDOT)
X			zexecve(arg0,argv,&ee,buf2,buf);
X		zexecve(cn->u.nam,argv,&ee,buf2,buf);
X		}
X	for (s = arg0; *s; s++)
X		if (*s == '/')
X			{
X			zexecve(arg0,argv,NULL,NULL,NULL);
X			if (arg0 == s || unset(PATHDIRS))
X				{
X				zerr("%e: %s",arg0,errno);
X				_exit(1);
X				}
X			break;
X			}
X	for (; *path; path++)
X		if ((*path)[0] == '.' && !(*path)[1])
X			zexecve(arg0,argv,&ee,buf2,buf);
X		else
X			{
X			tl = strlen(*path);
X			strcpy(buf,*path);
X			buf[tl] = '/';
X			if (strlen(arg0)+strlen(buf)+1 >= MAXCMDLEN)
X				{
X				zerr("command too long: %s",arg0,0);
X				_exit(1);
X				}
X			strcpy(buf+tl+1,arg0);
X			zexecve(buf,argv,&ee,buf2,buf);
X			}
X	if (ee)
X		{
X		zerr("%e: %s",arg0,ee);
X		_exit(1);
X		}
X	zerr("command not found: %s",arg0,0);
X	_exit(1);
X}
X
X#define try(X) { if (!access(X,X_OK)) return ztrdup(X); }
X
X/* get the pathname of a command */
X
Xchar *findcmd(arg0) /**/
Xchar *arg0;
X{
Xchar *s,buf[MAXPATHLEN];
Xint tl;
Xstruct cmdnam *cn = gethnode(arg0,cmdnamtab);
Xchar **pp = path;
X
X	if (cn && (cn->type == EXCMD_POSTDOT || cn->type == EXCMD_PREDOT))
X		{
X		if (cn->type == EXCMD_POSTDOT)
X			{
X			strcpy(buf,"./");
X			strcat(buf,arg0);
X			try(buf);
X			}
X		try(cn->u.nam);
X		}
X	for (s = arg0; *s; s++)
X		if (*s == '/')
X			{
X			try(arg0);
X			if (s == arg0 || unset(PATHDIRS))
X				goto failed;
X			break;
X			}
X	for (; *pp; pp++)
X		if (**pp == '.')
X			{
X			strcpy(buf,"./");
X			strcat(buf,arg0);
X			try(buf);
X			}
X		else
X			{
X			tl = strlen(*pp);
X			strcpy(buf,*pp);
X			buf[tl] = '/';
X			strcpy(buf+tl+1,arg0);
X			try(buf);
X			}
Xfailed:
X	return NULL;
X}
X
Xvoid execlist(list) /**/
XList list;
X{
X	if (breaks)
X		return;
X	simplifyright(list);
X	switch(list->type)
X		{
X		case SYNC:
X		case ASYNC:
X			execlist2(list->left,list->type,!list->right);
X			if (sigtrapped[SIGDEBUG])
X				dotrap(SIGDEBUG);
X			if (sigtrapped[SIGERR] && lastval)
X				dotrap(SIGERR);
X			if (list->right && !retflag)
X				execlist(list->right);
X			break;
X		}
X}
X
Xvoid execlist2(list,type,last1) /**/
XSublist list;int type;int last1;
X{
X	switch(list->type)
X		{
X		case END:
X			execpline(list,type,last1);
X			break;
X		case ORNEXT:
X			if (!execpline(list,SYNC,0))
X				execlist2(list->right,type,last1);
X			break;
X		case ANDNEXT:
X			if (execpline(list,SYNC,0))
X				execlist2(list->right,type,last1);
X			break;
X		}
X}
X
Xint execpline(l,how,last1) /**/
XSublist l;int how;int last1;
X{
Xint ipipe[2],opipe[2];
X
X	ipipe[0] = ipipe[1] = opipe[0] = opipe[1] = 0;
X	sigblock(sigmask(SIGCHLD));
X	if ((thisjob = getfreejob()) == -1)
X		return 1;
X	initjob();
X	if (how == TIMED)
X		{
X		jobtab[thisjob].stat |= STAT_TIMED;
X		how = SYNC;
X		}
X	if (l->flags & PFLAG_COPROC)
X		{
X		how = ASYNC;
X		mpipe(ipipe);
X		mpipe(opipe);
X		if (coprocin)
X			{
X			close(coprocin);
X			close(coprocout);
X			}
X		coprocin = ipipe[0];
X		coprocout = opipe[1];
X		}
X	execpline2(l->left,how,opipe[0],ipipe[1],last1);
X	if (how == ASYNC)
X		{
X		spawnjob();
X		sigsetmask(0);
X		return 1;
X		}
X	else
X		{
X		waitjobs();
X		sigsetmask(0);
X		if (l->flags & PFLAG_NOT)
X			lastval = !lastval;
X		return !lastval;
X		}
X}
X
Xvoid execpline2(pline,how,input,output,last1) /**/
XPline pline;int how;int input;int output;int last1;
X{
Xint pid;
Xint pipes[2];
X
X	if (breaks)
X		return;
X	if (!pline)
X		return;
X	if (pline->type == END)
X		{
X		execcmd(pline->left,input,output,how==ASYNC,last1);
X		pline->left = NULL;
X		}
X	else
X		{
X		mpipe(pipes);
X
X		/* if we are doing "foo | bar" where foo is a current
X			shell command, do foo in the current shell and do
X			the rest of the pipeline in a subshell. */
X
X		if (pline->left->type >= CURSH && how == SYNC)
X			{
X			if (!(pid = fork()))
X				{
X				close(pipes[1]);
X				entersubsh(1);
X				exiting = 1;
X				execpline2(pline->right,ASYNC,pipes[0],output,1);
X				_exit(lastval);
X				}
X			else if (pid == -1)
X				zerr("fork failed: %e",NULL,errno);
X			else
X				{
X				char *s,*text;
X
X				close(pipes[0]);
X				text = s = gettext((void *) pline->right,0);
X				addproc(pid,text)->lastfg = 1;
X				pline->right = NULL;
X				}
X			}
X
X		/* otherwise just do the pipeline normally. */
X
X		execcmd(pline->left,input,pipes[1],how==ASYNC,0);
X		pline->left = NULL;
X		close(pipes[1]);
X		if (pline->right)
X			{
X			execpline2(pline->right,how,pipes[0],output,last1);
X			close(pipes[0]);
X			}
X		}
X}
X
X/* make the argv array */
X
Xchar **makecline(list) /**/
Xstruct lklist *list;
X{
Xint ct = 0;
XLknode node;
Xchar **argv,**ptr;
X
X	if (isset(XTRACE))
X		{
X		fprintf(stderr,"%s",(prompt4) ? prompt4 : "");
X		for (node = firstnode(list); node; incnode(node),ct++);
X		ptr = argv = 2+(char **) ncalloc((ct+4)*sizeof(char *));
X		for (node = firstnode(list); node; incnode(node))
X			if (*(char *) getdata(node))
X				{
X				*ptr++ = getdata(node);
X				untokenize(getdata(node));
X				fputs(getdata(node),stderr);
X				if (nextnode(node))
X					fputc(' ',stderr);
X				}
X		*ptr = NULL;
X		fputc('\n',stderr);
X		fflush(stderr);
X		return(argv);
X		}
X	else
X		{
X		for (node = firstnode(list); node; incnode(node),ct++);
X		ptr = argv = 2+(char **) ncalloc((ct+4)*sizeof(char *));
X		for (node = firstnode(list); node; incnode(node))
X			if (*(char *) getdata(node))
X				{
X				*ptr++ = getdata(node);
X				untokenize(getdata(node));
X				}
X		*ptr = NULL;
X		return(argv);
X		}
X}
X
X/* untokenize the command line and remove null arguments */
X
Xvoid fixcline(l) /**/
XLklist l;
X{
XLknode node,next;
X
X	for (node = firstnode(l); node; node = next)
X		{
X		next = nextnode(node);
X		if (*(char *) getdata(node))
X			untokenize(getdata(node));
X		else
X			uremnode(l,node);
X		}
X}
X
Xvoid untokenize(s) /**/
Xchar *s;
X{
X	for (; *s; s++)
X		if (itok(*s))
X			if (*s == Nularg)
X				chuck(s--);
X			else
X				*s = ztokens[*s-Pound];
X}
X
X/* nonzero if we shouldn't clobber a file */
X
Xint dontclob(f) /**/
Xstruct redir *f;
X{
Xstruct stat buf;
X
X	if (unset(NOCLOBBER) || f->type & 1)
X		return 0;
X	if (stat(f->name,&buf) == -1)
X		return 1;
X	return S_ISREG(buf.st_mode);
X}
X
X/* close an multio (success) */
X
Xvoid closemn(mfds,fd) /**/
Xstruct multio **mfds;int fd;
X{
X	if (mfds[fd])
X		{
X		if (mfds[fd]->ct > 1)
X			if (mfds[fd]->rflag == 0)
X				catproc(mfds[fd]);
X			else
X				teeproc(mfds[fd]);
X		mfds[fd] = NULL;
X		}
X}
X
X/* close all the mnodes (failure) */
X
Xvoid closemnodes(mfds) /**/
Xstruct multio **mfds;
X{
Xint t0,t1;
X
X	for (t0 = 0; t0 != 10; t0++)
X		if (mfds[t0])
X			{
X			for (t1 = 0; t1 != mfds[t0]->ct; t1++)
X				close(mfds[t0]->fds[t1]);
X			mfds[t0] = NULL;
X			}
X}
X
X/* add a fd to an multio */
X/* an multio is a list of fds associated with a certain fd.
X	thus if you do "foo >bar >ble", the multio for fd 1 will have
X	two fds, the result of open("bar",...), and the result of
X	open("ble",....). */
X
Xvoid addfd(forked,save,mfds,fd1,fd2,rflag) /**/
Xint forked;int *save;struct multio **mfds;int fd1;int fd2;int rflag;
X{
Xint pipes[2];
X
X	if (!mfds[fd1])	/* starting a new multio */
X		{
X		mfds[fd1] = alloc(sizeof(struct multio));
X		if (!forked && fd1 != fd2 && fd1 < 10)
X			save[fd1] = movefd(fd1);
X		redup(fd2,fd1);
X		mfds[fd1]->ct = 1;
X		mfds[fd1]->fds[0] = fd1;
X		mfds[fd1]->rflag = rflag;
X		}
X	else
X		{
X		if (mfds[fd1]->rflag != rflag)
X			{
X			zerr("file mode mismatch on fd %d",NULL,fd1);
X			return;
X			}
X		if (mfds[fd1]->ct == 1)		/* split the stream */
X			{
X			mfds[fd1]->fds[0] = movefd(fd1);
X			mfds[fd1]->fds[1] = movefd(fd2);
X			mpipe(pipes);
X			mfds[fd1]->pipe = pipes[1-rflag];
X			redup(pipes[rflag],fd1);
X			mfds[fd1]->ct = 2;
X			}
X		else		/* add another fd to an already split stream */
X			mfds[fd1]->fds[mfds[fd1]->ct++] = movefd(fd2);
X		}
X}
X
Xvoid addvars(l,export) /**/
XLklist l;int export;
X{
Xstruct varasg *v;
XLklist vl;
X
X	while (full(l))
X		{
X		char **arr,**ptr;
X
X		v = ugetnode(l);
X		singsub(&v->name);
X		if (errflag)
X			return;
X		untokenize(v->name);
X		if (v->type == PMFLAG_s)
X			{
X			vl = newlist();
X			addnode(vl,v->str);
X			}
X		else
X			vl = v->arr;
X		prefork(vl);
X		if (errflag)
X			return;
X		postfork(vl,1);
X		if (errflag)
X			return;
X		if (v->type == PMFLAG_s)
X			{
X			Param pm;
X			char *val;
X
X			if (!full(vl))
X				pm = setsparam(v->name,val = ztrdup(""));
X			else
X				{
X				untokenize(peekfirst(vl));
X				pm = setsparam(v->name,val = ztrdup(ugetnode(vl)));
X				}
X			if (export && !(pm->flags & PMFLAG_x))
X				addenv(v->name,val);
X			continue;
X			}
X		ptr = arr = (char **) zalloc(sizeof(char **)*(countnodes(v->arr)+1));
X		while (full(v->arr))
X			{
X			*ptr = ztrdup(ugetnode(v->arr));
X			untokenize(*ptr++);
X			}
X		*ptr = NULL;
X		setaparam(v->name,arr);
X		}
X}
X
Xvoid execcmd(cmd,input,output,bkg,last1) /**/
XCmd cmd;int input;int output;int bkg;int last1;
X{
Xint type;
Xlong pid = 0;
XLklist args = cmd->args;
Xint save[10],t0;
Xstruct redir *fn;
Xstruct multio *mfds[10];
Xint fil,forked = 0,iscursh = 0,nullexec = 0;
XCmdnam chn = NULL;
Xchar *text;
X
X	for (t0 = 0; t0 != 10; t0++)
X		{
X		save[t0] = 0;
X		mfds[t0] = NULL;
X		}
X	if ((type = cmd->type) == SIMPLE && !full(args))
X		if (full(cmd->redir))
X			if (cmd->flags & CFLAG_EXEC)
X				nullexec = 1;
X			else
X				addnode(args,strdup("cat"));
X		else
X			{
X			addvars(cmd->vars,0);
X			return;
X			}
X	if (full(args) && *(char *) peekfirst(args) == '%')
X		{
X		insnode(args,(Lknode) args,strdup((bkg) ? "bg" : "fg"));
X		bkg = 0;
X		}
X	if (isset(AUTORESUME) && !full(cmd->redir) && full(args) &&
X			type == SIMPLE && !nextnode(firstnode(args)) &&
X			findjobnam(peekfirst(args)) != -1)
X		pushnode(args,strdup("fg"));
X	if (unset(RMSTARSILENT) && interact && isset(SHINSTDIN) &&
X				type == SIMPLE && full(args) && nextnode(firstnode(args)) &&
X				!strcmp(peekfirst(args),"rm"))
X			{
X			char *s = getdata(nextnode(firstnode(args)));
X
X			if (s[0] == Star && !s[1])
X				checkrmall();
X			}
X	if (jobbing)	/* get the text associated with this command */
X		{
X		char *s;
X		s = text = gettext((void *) cmd,0);
X		}
X	else
X		text = NULL;
X	prefork(args);	/* do prefork substitutions */
X	if (errflag)
X		{
X		lastval = 1;
X		return;
X		}
X	if (full(args) && !(cmd->flags & CFLAG_COMMAND))
X		chn = gethnode(peekfirst(args),cmdnamtab);
X	if (!pathsuppress && !chn && isset(AUTOCD) && full(args) &&
X			!full(cmd->redir) &&
X			!nextnode(firstnode(args)) && cancd(peekfirst(args)))
X		{
X		pushnode(args,strdup("cd"));
X		chn = gethnode("cd",cmdnamtab);
X		}
X
X	/* this is nonzero if cmd is a current shell procedure */
X
X	iscursh = (type >= CURSH) || (type == SIMPLE && chn &&
X		(chn->type == BUILTIN || chn->type == SHFUNC));
X
X	/* if this command is backgrounded or (this is an external
X		command and we are not exec'ing it) or this is a builtin
X		with output piped somewhere, then fork.  If this is the
X		last stage in a subshell pipeline, don't fork, but make
X		the rest of the function think we forked. */
X
X	if (bkg || !(iscursh || (cmd->flags & CFLAG_EXEC)) ||
X			(chn && (chn->type == BUILTIN || chn->type == SHFUNC) && output))
X		{
X		pid = (last1 && execok()) ? 0 : phork();
X		if (pid == -1)
X			return;
X		if (pid)
X			{
X			if (pid == -1)
X				zerr("%e",NULL,errno);
X			else
X				( void ) addproc(pid,text);
X			return;
X			}
X		entersubsh(bkg);
X		forked = 1;
X		}
X	if (bkg && isset(BGNICE))	/* stupid */
X		nice(5);
X	if (input)		/* add pipeline input/output to mnodes */
X		addfd(forked,save,mfds,0,input,0);
X	if (output)
X		addfd(forked,save,mfds,1,output,1);
X	spawnpipes(cmd->redir);		/* do process substitutions */
X	while (full(cmd->redir))
X		if ((fn = ugetnode(cmd->redir))->type == INPIPE)
X			{
X			if (fn->fd2 == -1)
X				execerr();
X			addfd(forked,save,mfds,fn->fd1,fn->fd2,0);
X			}
X		else if (fn->type == OUTPIPE)
X			{
X			if (fn->fd2 == -1)
X				execerr();
X			addfd(forked,save,mfds,fn->fd1,fn->fd2,1);
X			}
X		else
X			{
X			if (!(fn->type == HERESTR || fn->type == CLOSE || fn->type ==
X					MERGE || fn->type == MERGEOUT))
X				if (xpandredir(fn,cmd->redir))
X					continue;
X			if (fn->type == HERESTR)
X				{
X				fil = getherestr(fn);
X				if (fil == -1)
X					{
X					if (errno != EINTR)
X						zerr("%e",NULL,errno);
X					execerr();
X					}
X				addfd(forked,save,mfds,fn->fd1,fil,0);
X				}
X			else if (fn->type == READ)
X				{
X				fil = open(fn->name,O_RDONLY);
X				if (fil == -1)
X					{
X					if (errno != EINTR)
X						zerr("%e: %s",fn->name,errno);
X					execerr();
X					}
X				addfd(forked,save,mfds,fn->fd1,fil,0);
X				}
X			else if (fn->type == CLOSE)
X				{
X				if (!forked && fn->fd1 < 3)
X					{
X					zerr("can't close fd %d without forking",NULL,fn->fd1);
X					execerr();
X					}
X				closemn(mfds,fn->fd1);
X				close(fn->fd1);
X				}
X			else if (fn->type == MERGE || fn->type == MERGEOUT)
X				{
X				fil = dup(fn->fd2);
X				if (mfds[fn->fd1])
X					redup(fil,fn->fd1);
X				else
X					addfd(forked,save,mfds,fn->fd1,fil,fn->type == MERGEOUT);
X				}
X			else
X				{
X				if (fn->type >= APP)
X					fil = open(fn->name,isset(NOCLOBBER) ?
X						O_WRONLY|O_APPEND : O_WRONLY|O_APPEND|O_CREAT,0666);
X				else
X					fil = open(fn->name,dontclob(fn) ? 
X						O_WRONLY|O_CREAT|O_EXCL : O_WRONLY|O_CREAT|O_TRUNC,0666);
X				if (fil == -1)
X					{
X					if (errno != EINTR)
X						zerr("%e: %s",fn->name,errno);
X					execerr();
X					}
X				addfd(forked,save,mfds,fn->fd1,fil,1);
X				}
X			}
X	postfork(args,!(cmd->flags & CFLAG_NOGLOB));
X		/* perform postfork substitutions */
X	if (errflag)
X		{
X		lastval = 1;
X		goto err;
X		}
X	
X	/* we are done with redirection.  close the mnodes, spawning
X		tee/cat processes as necessary. */
X	for (t0 = 0; t0 != 10; t0++)
X		closemn(mfds,t0);
X
X	if (nullexec)
X		return;
X	if (unset(NOEXEC))
X		if (type >= CTIME)
X			{
X			static int (*func[]) DCLPROTO((Cmd)) = {
X				exectime,execcursh,execfuncdef,execfor,execwhile,
X				execrepeat,execif,execcase,execselect,execcond };
X	
X			fixcline(args);
X			lastval = (func[type-CTIME])(cmd);
X			}
X		else if (iscursh)		/* builtin or shell function */
X			{
X			if (cmd->vars)
X				addvars(cmd->vars,0);
X			fixcline(args);
X			if (chn && chn->type == SHFUNC)
X				execshfunc(cmd,chn);
X			else
X				{
X				lastval = execbin(args,chn);
X				if (isset(PRINTEXITVALUE) && lastval)
X					zerr("exit %d",NULL,lastval);
X				fflush(stdout);
X				if (ferror(stdout))
X					{
X					zerr("write error: %e",NULL,errno);
X					clearerr(stdout);
X					}
X				}
X			}
X		else
X			{
X			if (cmd->vars)
X				addvars(cmd->vars,1);
X			if (type == SIMPLE)
X				{
X				closem();
X				execute(args,cmd->flags & CFLAG_DASH);
X				}
X			else	/* ( ... ) */
X				execlist(cmd->u.list);
X			}
Xerr:
X	if (forked)
X		_exit(lastval);
X	fixfds(save);
X}
X
X/* restore fds after redirecting a builtin */
X
Xvoid fixfds(save) /**/
Xint *save;
X{
Xint t0;
X
X	for (t0 = 0; t0 != 10; t0++)
X		if (save[t0])
X			redup(save[t0],t0);
X}
X
Xvoid entersubsh(bkg) /**/
Xint bkg;
X{
X	if (!jobbing)
X		{
X		if (bkg && isatty(0))
X			{
X			close(0);
X			if (open("/dev/null",O_RDWR))
X				{
X				zerr("can't open /dev/null: %e",NULL,errno);
X				_exit(1);
X				}
X			}
X		}
X	else if (!jobtab[thisjob].gleader)
X		{
X		setpgrp(0L,jobtab[thisjob].gleader = getpid());
X		if (!bkg)
X			attachtty(jobtab[thisjob].gleader);
X		}
X	else
X		setpgrp(0L,jobtab[thisjob].gleader);
X	subsh = 1;
X	if (SHTTY != -1)
X		{
X		close(SHTTY);
X		SHTTY = -1;
X		}
X	if (jobbing)
X		{
X		signal(SIGTTOU,SIG_DFL);
X		signal(SIGTTIN,SIG_DFL);
X		signal(SIGTSTP,SIG_DFL);
X		signal(SIGPIPE,SIG_DFL);
X		}
X	if (interact)
X		{
X		signal(SIGTERM,SIG_DFL);
X		if (sigtrapped[SIGINT])
X			signal(SIGINT,SIG_IGN);
X		}
X	if (!sigtrapped[SIGQUIT])
X		signal(SIGQUIT,SIG_DFL);
X	opts[MONITOR] = OPT_UNSET;
X	clearjobtab();
X}
X
X/* close all internal shell fds */
X
Xvoid closem() /**/
X{
Xint t0;
X
X	for (t0 = 10; t0 != NOFILE; t0++)
X		close(t0);
X}
X
X/* convert here document into a here string */
X
Xchar *gethere(str) /**/
Xchar *str;
X{
Xchar pbuf[256];
Xint qt = 0,siz = 0,l,strip = 0;
Xchar *s,*t,*bptr;
X
X	for (s = str; *s; s++)
X		if (*s == Nularg)
X			qt = 1;
X	untokenize(str);
X	if (*str == '-')
X		{
X		str++;
X		strip = 1;
X		while (*str == '\t')
X			str++;
X		}
X	t = ztrdup("");
X	for(;;)
X		{
X		char *u,*v;
X
X		if (!fgets(pbuf,256,bshin))
X			break;
X		bptr = pbuf;
X		if (strip)
X			while (*bptr == '\t')
X				bptr++;
X		for (u = bptr, v = str; *u != '\n' && *v; u++,v++)
X			if (*u != *v)
X				break;
X		if (!(*u == '\n' && !*v))
X			{
X			l = strlen(bptr);
X			if (!qt && l > 1 && bptr[l-1] == '\n' && bptr[l-2] == '\\')
X				bptr[l -= 2] = '\0';
X			t = realloc(t,siz+l+1);
X			strncpy(t+siz,bptr,l);
X			siz += l;
X			}
X		else
X			break;
X		}
X	t[siz] = '\0';
X	if (siz && t[siz-1] == '\n')
X		t[siz-1] = '\0';
X	if (!qt)
X		for (s = t; *s; s++)
X			if (*s == '$')
X				*s = Qstring;
X			else if (*s == '`')
X				*s = Qtick;
X			else if (*s == '\\')
X				{
X				s++;
X				if (!*s)
X					break;
X				}
X	s = strdup(t);
X	free(t);
X	return s;
X}
X
X/* open here string fd */
X
Xint getherestr(fn) /**/
Xstruct redir *fn;
X{
XLklist fake;
Xchar *s = gettemp(),*t;
Xint fd;
X
X	fake = newlist();
X	addnode(fake,fn->name);
X	prefork(fake);
X	if (!errflag)
X		postfork(fake,1);
X	if (errflag)
X		return -1;
X	if ((fd = open(s,O_CREAT|O_WRONLY,0600)) == -1)
X		return -1;
X	while (t = ugetnode(fake))
X		{
X		untokenize(t);
X		write(fd,t,strlen(t));
X		if (full(fake))
X			write(fd," ",1);
X		}
X	write(fd,"\n",1);
X	close(fd);
X	fd = open(s,O_RDONLY);
X	unlink(s);
X	return fd;
X}
X
Xvoid catproc(mn) /**/
Xstruct multio *mn;
X{
Xint len,t0;
Xchar *buf;
X
X	if (phork())
X		{
X		for (t0 = 0; t0 != mn->ct; t0++)
X			close(mn->fds[t0]);
X		close(mn->pipe);
X		return;
X		}
X	closeallelse(mn);
X	buf = zalloc(4096);
X	for (t0 = 0; t0 != mn->ct; t0++)
X		while (len = read(mn->fds[t0],buf,4096))
X			write(mn->pipe,buf,len);
X	_exit(0);
X}
X 
Xvoid teeproc(mn) /**/
Xstruct multio *mn;
X{
Xint len,t0;
Xchar *buf;
X
X	if (phork())
X		{
X		for (t0 = 0; t0 != mn->ct; t0++)
X			close(mn->fds[t0]);
X		close(mn->pipe);
X		return;
X		}
X	buf = zalloc(4096);
X	closeallelse(mn);
X	while ((len = read(mn->pipe,buf,4096)) > 0)
X		for (t0 = 0; t0 != mn->ct; t0++)
X			write(mn->fds[t0],buf,len);
X	_exit(0);
X}
X
Xvoid closeallelse(mn) /**/
Xstruct multio *mn;
X{
Xint t0,t1;
X
X	for (t0 = 0; t0 != NOFILE; t0++)
X		if (mn->pipe != t0)
X			{
X			for (t1 = 0; t1 != mn->ct; t1++)
X				if (mn->fds[t1] == t0)
X					break;
X			if (t1 == mn->ct)
X				close(t0);
X			}
X}
X
Xlong int zstrtol(s,t,base) /**/
Xchar *s;char **t;int base;
X{
Xint ret = 0;
X
X	for (; *s >= '0' && *s < ('0'+base); s++)
X		ret = ret*base+*s-'0';
X	if (t)
X		*t = (char *) s;
X	return ret;
X}
X
X/* $(...) */
X
XLklist getoutput(cmd,qt) /**/
Xchar *cmd;int qt;
X{
XList list;
Xint pipes[2];
X
X	if (*cmd == '<')
X		{
X		int stream;
X		char *fi;
X
X		fi = strdup(cmd+1);
X		if (*fi == '~')
X			*fi = Tilde;
X		else if (*fi == '=')
X			*fi = Equals;
X		singsub(&fi);
X		if (errflag)
X			return NULL;
X		stream = open(fi,O_RDONLY);
X		if (stream == -1)
X			{
X			zerr("%e: %s",cmd+1,errno);
X			return NULL;
X			}
X		return readoutput(stream,qt);
X		}
X	if (!(list = parselstring(cmd)))
X		return NULL;
X	mpipe(pipes);
X	if (phork())
X		{
X		popheap();
X		close(pipes[1]);
X		return readoutput(pipes[0],qt);
X		}
X	subsh = 1;
X	close(pipes[0]);
X	redup(pipes[1],1);
X	entersubsh(0);
X	signal(SIGTSTP,SIG_IGN);
X	exiting = 1;
X	execlist(list);
X	close(1);
X	exit(0);  return NULL;
X}
X
X/* read output of command substitution */
X
XLklist readoutput(in,qt) /**/
Xint in;int qt;
X{
XLklist ret;
Xchar *buf,*ptr;
Xint bsiz,c,cnt = 0;
XFILE *fin;
X
X	fin = fdopen(in,"r");
X	ret = newlist();
X	ptr = buf = zalloc(bsiz = 256);
X	while ((c = fgetc(fin)) != EOF)
X		if (!qt && isep(c))
X			{
X			if (cnt)
X				{
X				*ptr = '\0';
X				addnode(ret,ztrdup(buf));
X				cnt = 0;
X				ptr = buf;
X				}
X			}
X		else
X			{
X			*ptr++ = c;
X			if (++cnt == bsiz)
X				{
X				char *pp = zalloc(bsiz *= 2);
X				
X				memcpy(pp,buf,cnt);
X				free(buf);
X				ptr = (buf = pp)+cnt;
X				}
X			}
X	if (qt && ptr != buf && ptr[-1] == '\n')
X		ptr[-1] = '\0';
X	if (cnt)
X		addnode(ret,ztrdup(buf));
X	free(buf);
X	fclose(fin);
X	return ret;
X}
X
X/* =(...) */
X
Xchar *getoutputfile(cmd) /**/
Xchar *cmd;
X{
X#ifdef WAITPID
Xint pid;
X#endif
Xchar *nam = gettemp(),*str;
Xint tfil;
XList list;
X
X	if (thisjob == -1)
X		return NULL;
X	for (str = cmd; *str && *str != Outpar; str++);
X	if (!*str)
X		zerr("oops.",NULL,0);
X	*str = '\0';
X	if (!(list = parselstring(cmd)))
X		return NULL;
X	permalloc();
X	if (!jobtab[thisjob].filelist)
X		jobtab[thisjob].filelist = newlist();
X	addnode(jobtab[thisjob].filelist,ztrdup(nam));
X	heapalloc();
X#ifdef WAITPID
X	if (pid = phork())
X		{
X		popheap();
X		waitpid(pid,NULL,WUNTRACED);
X		return nam;
X		}
X#else
X	if (waitfork())
X		return nam;
X#endif
X	subsh = 1;
X	close(1);
X	entersubsh(0);
X	tfil = creat(nam,0666);
X	exiting = 1;
X	execlist(list);
X	close(1);
X	exit(0); return NULL;
X}
X
X/* get a temporary named pipe */
X
Xchar *namedpipe() /**/
X{
Xchar *tnam = gettemp();
X
X	mknod(tnam,0010666,0);
X	return tnam;
X}
X
X/* <(...) */
X
Xchar *getoutproc(cmd) /**/
Xchar *cmd;
X{
XList list;
Xint fd;
Xchar *pnam,*str;
X
X	if (thisjob == -1)
X		return NULL;
X	for (str = cmd; *str && *str != Outpar; str++);
X	if (!*str)
X		zerr("oops.",NULL,0);
X	*str = '\0';
X	pnam = namedpipe();
X	permalloc();
X	if (!jobtab[thisjob].filelist)
X		jobtab[thisjob].filelist = newlist();
X	addnode(jobtab[thisjob].filelist,ztrdup(pnam));
X	heapalloc();
X	if (!(list = parselstring(cmd)))
X		return NULL;
X	if (phork())
X		{
X		popheap();
X		return pnam;
X		}
X	entersubsh(1);
X	fd = open(pnam,O_WRONLY);
X	if (fd == -1)
X		{
X		zerr("can't open %s: %e",pnam,errno);
X		_exit(0);
X		}
X	redup(fd,1);
X	fd = open("/dev/null",O_RDONLY);
X	redup(fd,0);
X	exiting = 1;
X	execlist(list);
X	close(1);
X	_exit(0);  return NULL;
X}
X
X/* >(...) */
X
Xchar *getinproc(cmd) /**/
Xchar *cmd;
X{
XList list;
Xint pid,fd;
Xchar *pnam,*str;
X
X	if (thisjob == -1)
X		return NULL;
X	for (str = cmd; *str && *str != Outpar; str++);
X	if (!*str)
X		zerr("oops.",NULL,0);
X	*str = '\0';
X	pnam = namedpipe();
X	permalloc();
X	if (!jobtab[thisjob].filelist)
X		jobtab[thisjob].filelist = newlist();
X	addnode(jobtab[thisjob].filelist,ztrdup(pnam));
X	heapalloc();
X	if (!(list = parselstring(cmd)))
X		return NULL;
X	if (pid = phork())
X		{
X		popheap();
X		return pnam;
X		}
X	entersubsh(1);
X	fd = open(pnam,O_RDONLY);
X	redup(fd,0);
X	exiting = 1;
X	execlist(list);
X	_exit(0);  return NULL;
X}
X
X/* > >(...) (does not use named pipes) */
X
Xint getinpipe(cmd) /**/
Xchar *cmd;
X{
XList list;
Xint pipes[2];
Xchar *str = cmd;
X
X	for (str = cmd; *str && *str != Outpar; str++);
X	if (!*str)
X		zerr("oops.",NULL,0);
X	*str = '\0';
X	if (!(list = parselstring(cmd+2)))
X		return -1;
X	mpipe(pipes);
X	if (phork())
X		{
X		popheap();
X		close(pipes[1]);
X		return pipes[0];
X		}
X	close(pipes[0]);
X	entersubsh(1);
X	redup(pipes[1],1);
X	exiting = 1;
X	execlist(list);
X	_exit(0);  return 0;
X}
X
X/* < <(...) */
X
Xint getoutpipe(cmd) /**/
Xchar *cmd;
X{
XList list;
Xint pipes[2];
Xchar *str;
X
X	for (str = cmd; *str && *str != Outpar; str++);
X	if (!*str)
X		zerr("oops.",NULL,0);
X	*str = '\0';
X	if (!(list = parselstring(cmd+2)))
X		return -1;
X	strinend();
X	mpipe(pipes);
X	if (phork())
X		{
X		popheap();
X		close(pipes[0]);
X		return pipes[1];
X		}
X	close(pipes[1]);
X	entersubsh(1);
X	redup(pipes[0],0);
X	exiting = 1;
X	execlist(list);
X	_exit(0);  return 0;
X}
X
X/* run a list, saving the current job num */
X
Xvoid runlist(l) /**/
XList l;
X{
Xint cj = thisjob;
X
X	execlist(l);
X	thisjob = cj;
X}
X
Xchar *gettemp() /**/
X{
X	return mktemp(strdup("/tmp/zshXXXXXX"));
X}
X
X/* my getwd; all the other ones I tried confused the SIGCHLD handler */
X
Xchar *zgetwd() /**/
X{
Xstatic char buf0[MAXPATHLEN];
Xchar buf3[MAXPATHLEN],*buf2 = buf0+1;
Xstruct stat sbuf;
Xstruct direct *de;
XDIR *dir;
Xino_t ino = -1;
Xdev_t dev = -1;
X
X	holdintr();
X	buf2[0] = '\0';
X	buf0[0] = '/';
X	for(;;)
X		{
X		if (stat(".",&sbuf) < 0)
X			{
X			chdir(buf0);
X			noholdintr();
X			return ztrdup(".");
X			}
X		ino = sbuf.st_ino;
X		dev = sbuf.st_dev;
X		if (stat("..",&sbuf) < 0)
X			{
X			chdir(buf0);
X			noholdintr();
X			return ztrdup(".");
X			}
X		if (sbuf.st_ino == ino && sbuf.st_dev == dev)
X			{
X			chdir(buf0);
X			noholdintr();
X			return ztrdup(buf0);
X			}
X		dir = opendir("..");
X		if (!dir)
X			{
X			chdir(buf0);
X			noholdintr();
X			return ztrdup(".");
X			}
X		chdir("..");
X		readdir(dir); readdir(dir);
X		while (de = readdir(dir))
X			if (de->d_ino == ino)
X				{
X				lstat(de->d_name,&sbuf);
X				if (sbuf.st_dev == dev)
X					goto match;
X				}
X		rewinddir(dir);
X		readdir(dir); readdir(dir);
X		while (de = readdir(dir))
X			{
X			lstat(de->d_name,&sbuf);
X			if (sbuf.st_dev == dev)
X				goto match;
X			}
X		noholdintr();
X		closedir(dir);
X		return ztrdup(".");
Xmatch:
X		strcpy(buf3,de->d_name);
X		if (*buf2)
X			strcat(buf3,"/");
X		strcat(buf3,buf2);
X		strcpy(buf2,buf3);
X		closedir(dir);
X		}
X}
X
X/* open pipes with fds >= 10 */
X
Xvoid mpipe(pp) /**/
Xint *pp;
X{
X	pipe(pp);
X	pp[0] = movefd(pp[0]);
X	pp[1] = movefd(pp[1]);
X}
X
X/* do process substitution with redirection */
X
Xvoid spawnpipes(l) /**/
XLklist l;
X{
XLknode n = firstnode(l);
Xstruct redir *f;
X
X	for (; n; incnode(n))
X		{
X		f = getdata(n);
X		if (f->type == OUTPIPE)
X			{
X			char *str = f->name;
X			f->fd2 = getoutpipe(str);
X			}
X		if (f->type == INPIPE)
X			{
X			char *str = f->name;
X			f->fd2 = getinpipe(str);
X			}
X		}
X}
X
X/* perform time ... command */
X
Xint exectime(cmd) /**/
XCmd cmd;
X{
Xint jb = thisjob;
X
X	execpline(cmd->u.pline,TIMED,0);
X	thisjob = jb;
X	return lastval;
X}
X
X/* define a function */
X
Xint execfuncdef(cmd) /**/
XCmd cmd;
X{
XCmdnam cc;
Xchar *s;
X
X	permalloc();
X	while (s = ugetnode(cmd->args))
X		{
X		cc = zalloc(sizeof *cc);
X		cc->type = SHFUNC;
X		cc->flags = 0;
X		cc->u.list = dupstruct(cmd->u.list);
X		addhnode(ztrdup(s),cc,cmdnamtab,freecmdnam);
X		if (!strncmp(s,"TRAP",4))
X			{
X			int t0 = getsignum(s+4);
X
X			if (t0 != -1)
X				settrap(t0,cmd->u.list);
X			}
X		}
X	heapalloc();
X	return 0;
X}
X
X/* evaluate a [[ ... ]] */
X
Xint execcond(cmd) /**/
XCmd cmd;
X{
X	return !evalcond(cmd->u.cond);
X}
X
Xvoid execshfunc(cmd,cn) /**/
XCmd cmd;Cmdnam cn;
X{
Xchar **tab,**x,*oargv0;
Xint oxtr = opts[XTRACE],flags,xexittr;
XList l;
XLklist olist;
Xchar *s;
XList xexitfn;
X
X	if (errflag)
X		return;
X	l = cn->u.list;
X	if (!l)
X		{
X		char *nam;
X
X		if (!(l = getfpfunc(nam = peekfirst(cmd->args))))
X			{
X			zerr("function not found: %s",nam,0);
X			lastval = 1;
X			return;
X			}
X		cn->flags &= ~PMFLAG_u;
X		permalloc();
X		cn->u.list = dupstruct(l);
X		heapalloc();
X		}
X	flags = cn->flags;
X	xexittr = sigtrapped[SIGEXIT];
X	xexitfn = sigfuncs[SIGEXIT];
X	tab = pparams;
X	oargv0 = argzero;
X	if (flags & PMFLAG_t)
X		opts[XTRACE] = OPT_SET;
X	pparams = x = zcalloc(((sizeof *x)*(1+countnodes(cmd->args))));
X	argzero = ztrdup(ugetnode(cmd->args));
X	while (*x = ugetnode(cmd->args))
X		*x = ztrdup(*x), x++;
X	permalloc();
X	olist = locallist;
X	locallist = newlist();
X	heapalloc();
X	newrunlist(l);
X	while (s = getnode(locallist))
X		unsetparam(s);
X	free(locallist);
X	locallist = olist;
X	retflag = 0;
X	cmd->u.list = NULL;
X	freearray(pparams);
X	free(argzero);
X	argzero = oargv0;
X	pparams = tab;
X	if (sigtrapped[SIGEXIT])
X		dotrap(SIGEXIT);
X	if (sigfuncs[SIGEXIT])
X		freestruct(sigfuncs[SIGEXIT]);
X	sigtrapped[SIGEXIT] = xexittr;
X	sigfuncs[SIGEXIT] = xexitfn;
X	opts[XTRACE] = oxtr;
X}
X
X/* search fpath for an undefined function */
X
XList getfpfunc(s) /**/
Xchar *s;
X{
Xchar **pp = fpath,buf[MAXPATHLEN];
Xint fd;
X
X	for (; *pp; pp++)
X		{
X		sprintf(buf,"%s/%s",*pp,s);
X		if (!access(buf,X_OK) && (fd = open(buf,O_RDONLY)) != -1)
X			{
X			int len = lseek(fd,0,2);
X
X			if (len == -1)
X				close(fd);
X			else
X				{
X				char *d;
X
X				lseek(fd,0,0);
X				d = zcalloc(len+1);
X				if (read(fd,d,len) != len)
X					{
X					free(d);
X					close(fd);
X					}
X				else
X					{
X					close(fd);
X					return parselstring(d);
X					}
X				}
X			}
X		}
X	return NULL;
X}
X
X/* check to see if AUTOCD applies here */
X
Xint cancd(s)
Xchar *s;
X{
Xchar *t;
X
X	for (t = s; *t; t++)
X		if (*t == '/')
X			break;
X	if (!*t)
X		{
X		char sbuf[MAXPATHLEN],**cp;
X
X		if (cancd2(s))
X			return 1;
X		for (cp = cdpath; *cp; cp++)
X			{
X			sprintf(sbuf,"%s/%s",*cp,s);
X			if (cancd2(sbuf))
X				return 1;
X			}
X		return 0;
X		}
X	return cancd2(s);
X}
X
Xint cancd2(s)
Xchar *s;
X{
Xstruct stat buf;
X
X	return !(access(s,X_OK) || lstat(s,&buf) || !S_ISDIR(buf.st_mode));
X}
X
SHAR_EOF
chmod 0644 zsh2.00/src/exec.c ||
echo 'restore of zsh2.00/src/exec.c failed'
Wc_c="`wc -c < 'zsh2.00/src/exec.c'`"
test 31640 -eq "$Wc_c" ||
	echo 'zsh2.00/src/exec.c: original size 31640, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= zsh2.00/src/exec.pro ==============
if test -f 'zsh2.00/src/exec.pro' -a X"$1" != X"-c"; then
	echo 'x - skipping zsh2.00/src/exec.pro (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting zsh2.00/src/exec.pro (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'zsh2.00/src/exec.pro' &&
XList parselstring DCLPROTO((char *s));
Xvoid execstring DCLPROTO((char *s));
Xvoid newrunlist DCLPROTO((List l));
Xint phork DCLPROTO((void));
Xint execcursh DCLPROTO((Cmd cmd));
Xvoid zexecve DCLPROTO((char *pth,char **argv,int *ee,char *b1,char *b2));
Xvoid execute DCLPROTO((Lklist args,int dash));
Xchar *findcmd DCLPROTO((char *arg0));
Xvoid execlist DCLPROTO((List list));
Xvoid execlist2 DCLPROTO((Sublist list,int type,int last1));
Xint execpline DCLPROTO((Sublist l,int how,int last1));
Xvoid execpline2 DCLPROTO((Pline pline,int how,int input,int output,int last1));
Xchar **makecline DCLPROTO((struct lklist *list));
Xvoid fixcline DCLPROTO((Lklist l));
Xvoid untokenize DCLPROTO((char *s));
Xint dontclob DCLPROTO((struct redir *f));
Xvoid closemn DCLPROTO((struct multio **mfds,int fd));
Xvoid closemnodes DCLPROTO((struct multio **mfds));
Xvoid addfd DCLPROTO((int forked,int *save,struct multio **mfds,int fd1,int fd2,int rflag));
Xvoid addvars DCLPROTO((Lklist l,int export));
Xvoid execcmd DCLPROTO((Cmd cmd,int input,int output,int bkg,int last1));
Xvoid fixfds DCLPROTO((int *save));
Xvoid entersubsh DCLPROTO((int bkg));
Xvoid closem DCLPROTO((void));
Xchar *gethere DCLPROTO((char *str));
Xint getherestr DCLPROTO((struct redir *fn));
Xvoid catproc DCLPROTO((struct multio *mn));
Xvoid teeproc DCLPROTO((struct multio *mn));
Xvoid closeallelse DCLPROTO((struct multio *mn));
Xlong int zstrtol DCLPROTO((char *s,char **t,int base));
XLklist getoutput DCLPROTO((char *cmd,int qt));
XLklist readoutput DCLPROTO((int in,int qt));
Xchar *getoutputfile DCLPROTO((char *cmd));
Xchar *namedpipe DCLPROTO((void));
Xchar *getoutproc DCLPROTO((char *cmd));
Xchar *getinproc DCLPROTO((char *cmd));
Xint getinpipe DCLPROTO((char *cmd));
Xint getoutpipe DCLPROTO((char *cmd));
Xvoid runlist DCLPROTO((List l));
Xchar *gettemp DCLPROTO((void));
Xchar *zgetwd DCLPROTO((void));
Xvoid mpipe DCLPROTO((int *pp));
Xvoid spawnpipes DCLPROTO((Lklist l));
Xint exectime DCLPROTO((Cmd cmd));
Xint execfuncdef DCLPROTO((Cmd cmd));
Xint execcond DCLPROTO((Cmd cmd));
Xvoid execshfunc DCLPROTO((Cmd cmd,Cmdnam cn));
XList getfpfunc DCLPROTO((char *s));
SHAR_EOF
chmod 0644 zsh2.00/src/exec.pro ||
echo 'restore of zsh2.00/src/exec.pro failed'
Wc_c="`wc -c < 'zsh2.00/src/exec.pro'`"
test 2101 -eq "$Wc_c" ||
	echo 'zsh2.00/src/exec.pro: original size 2101, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= zsh2.00/src/funcs.h ==============
if test -f 'zsh2.00/src/funcs.h' -a X"$1" != X"-c"; then
	echo 'x - skipping zsh2.00/src/funcs.h (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting zsh2.00/src/funcs.h (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'zsh2.00/src/funcs.h' &&
X#include "glob.pro"
X#include "hist.pro"
X#include "table.pro"
X#include "subst.pro"
X#include "params.pro"
X#include "builtin.pro"
X#include "loop.pro"
X#include "jobs.pro"
X#include "exec.pro"
X#include "init.pro"
X#include "lex.pro"
X#include "parse.pro"
X#include "utils.pro"
X#include "cond.pro"
X#include "mem.pro"
X#include "text.pro"
X#include "watch.pro"
X
X#include "zle_emacs.pro"
X#include "zle_utils.pro"
X#include "zle_main.pro"
X#include "zle_refresh.pro"
X#include "zle_tricky.pro"
X#include "zle_vi.pro"
X
Xchar *mktemp DCLPROTO((char *));
Xchar *malloc DCLPROTO((int));
Xchar *realloc DCLPROTO((char *,int));
Xchar *calloc DCLPROTO((int,int));
Xchar *ttyname DCLPROTO((int));
Xchar *tgetstr();
SHAR_EOF
chmod 0644 zsh2.00/src/funcs.h ||
echo 'restore of zsh2.00/src/funcs.h failed'
Wc_c="`wc -c < 'zsh2.00/src/funcs.h'`"
test 682 -eq "$Wc_c" ||
	echo 'zsh2.00/src/funcs.h: original size 682, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= zsh2.00/src/glob.c ==============
if test -f 'zsh2.00/src/glob.c' -a X"$1" != X"-c"; then
	echo 'x - skipping zsh2.00/src/glob.c (File already exists)'
	rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting zsh2.00/src/glob.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'zsh2.00/src/glob.c' &&
X/*
X
X	glob.c - filename generation
X
X	This file is part of zsh, the Z shell.
X
X	zsh is free software; no one can prevent you from reading the source
X   code, or giving it to someone else.
X
X   This file is copyrighted under the GNU General Public License, which
X   can be found in the file called COPYING.
X
X   Copyright (C) 1990, 1991 Paul Falstad
X
X   zsh is distributed in the hope that it will be useful, but
X   WITHOUT ANY WARRANTY.  No author or distributor accepts
X   responsibility to anyone for the consequences of using it or for
X   whether it serves any particular purpose or works at all, unless he
X   says so in writing.  Refer to the GNU General Public License
X   for full details.
X
X   Everyone is granted permission to copy, modify and redistribute
X   zsh, but only under the conditions described in the GNU General Public
X   License.   A copy of this license is supposed to have been given to you
X   along with zsh so you can know your rights and responsibilities.
X   It should be in a file named COPYING.
X
X   Among other things, the copyright notice and this notice must be
X   preserved on all copies.
X
X*/
X
X#include "zsh.h"
X#include "funcs.h"
X#ifndef INT_MAX
X#include <limits.h>
X#endif
X#include <sys/dir.h>
X#include <sys/errno.h>
X
X#define exists(X) (access(X,0) == 0)
X
Xstatic int mode;				/* != 0 if we are parsing glob patterns */
Xstatic int pathpos;			/* position in pathbuf */
Xstatic int matchsz;			/* size of matchbuf */
Xstatic int matchct;			/* number of matches found */
Xstatic char pathbuf[MAXPATHLEN];	/* pathname buffer */
Xstatic char **matchbuf;		/* array of matches */
Xstatic char **matchptr;		/* &matchbuf[matchct] */
X
X/* max # of qualifiers */
X
X#define QUALCT 16
X
Xstatic int (*qualfuncs[QUALCT])DCLPROTO((struct stat *,long));
Xstatic long qualdata[QUALCT];
Xstatic int qualsense[QUALCT];
Xstatic int qualct;
X
X/* pathname component in filename patterns */
X
Xstruct complist {
X	Complist next;
X	Comp comp;
X	int closure;	/* 1 if this is a (foo/)# */
X	};
Xstruct comp {
X	Comp left,right,next;
X	char *str;
X	int closure,last;
X	};
X
Xvoid glob(list,np) /**/
XLklist list;Lknode *np;
X{
XLknode node = prevnode(*np);
XLknode next = nextnode(*np);
Xint sl;			/* length of the pattern */
Xchar *ostr;		/* the pattern before the parser chops it up */
XComplist q;		/* pattern after parsing */
Xchar *str = getdata(*np);	/* the pattern */
X
X	sl = strlen(str);
X	ostr = strdup(str);
X	uremnode(list,*np);
X	qualct = 0;
X	if (str[sl-1] == Outpar)	/* check for qualifiers */
X		{
X		char *s;
X		int sense = 0;
X		long data;
X		int (*func) DCLPROTO((struct stat *,long));
X
X		for (s = str+sl-2; s != str; s--)
X			if (*s == Bar || *s == Outpar || *s == Inpar)
X				break;
X		if (*s == Inpar)
X			{
X			*s++ = '\0';
X			func = NULL;
X			while (*s != Outpar)
X				{
X				func = NULL;
X				if (idigit(*s))
X					{
X					func = qualflags;
X					data = 0;
X					while (idigit(*s))
X						data = data*010+(*s-'0');
X					}
X				else switch (*s++)
X					{
X					case Hat: sense = 1-sense; break;
X					case '@': func = qualmode; data = S_IFLNK; break;
X					case '=': func = qualmode; data = S_IFSOCK; break;
X					case 'p': func = qualmode; data = S_IFIFO; break;
X					case '/': func = qualmode; data = S_IFDIR; break;
X					case '.': func = qualmode; data = S_IFREG; break;
X					case '%': func = qualisdev; break;
X					case Star:  func = qualflags; data = 0100; break;
X					case 'R': func = qualflags; data = 0004; break;
X					case 'W': func = qualflags; data = 0002; break;
X					case 'X': func = qualflags; data = 0001; break;
X					case 'r': func = qualflags; data = 0400; break;
X					case 'w': func = qualflags; data = 0200; break;
X					case 'x': func = qualflags; data = 0100; break;
X					case 's': func = qualflags; data = 04000; break;
X					case 'S': func = qualflags; data = 02000; break;
X					case 'd': func = qualdev; data = qgetnum(&s); break;
X					case 'l': func = qualnlink; data = qgetnum(&s); break;
X					case 'U': func = qualuid; data = geteuid(); break;
X					case 'G': func = qualgid; data = getegid(); break;
X					case 'u': func = qualuid; data = qgetnum(&s); break;
X					case 'g': func = qualgid; data = qgetnum(&s); break;
X					default: zerr("unknown file attribute",NULL,0); return;
X					}
X				if (func)
X					{
X					if (qualct == 15)
X						{
X						zerr("too many qualifiers",NULL,0);
X						return;
X						}
X					qualfuncs[qualct] = func;
X					qualsense[qualct] = sense;
X					qualdata[qualct] = data;
X					qualct++;
X					}
X				if (errflag)
X					return;
X				}
X			}
X		}
X	else if (str[sl-1] == '/')		/* foo/ == foo(/) */
X		{
X		str[sl-1] = '\0';
X		qualfuncs[0] = qualmode;
X		qualdata[0] = S_IFDIR;
X		qualsense[0] = 0;
X		qualct = 1;
X		}
X	if (*str == '/')	/* pattern has absolute path */
X		{
X		str++;
X		pathbuf[0] = '/';
X		pathbuf[pathpos = 1] = '\0';
X		}
X	else		/* pattern is relative to cwd */
X		pathbuf[pathpos = 0] = '\0';
X	q = parsepat(str);
X	if (!q || errflag)	/* if parsing failed */
X		{
X		if (isset(NOBADPATTERN))
X			{
X			insnode(list,node,ostr);
X			return;
X			}
X		errflag = 0;
X		zerr("bad pattern: %s",ostr,0);
X		return;
X		}
X	matchptr = matchbuf = (char **) zalloc((matchsz = 16)*sizeof(char *));
X	matchct = 0;
X	scanner(q);		/* do the globbing */
X	if (!matchct && unset(NULLGLOB))
X		if (unset(NONOMATCH))
X			{
X			zerr("no matches found: %s",ostr,0);
X			free(matchbuf);
X			return;
X			}
X		else
X			{
X			*matchptr++ = strdup(ostr);
X			matchct = 1;
X			}
X	qsort(&matchbuf[0],matchct,sizeof(char *),notstrcmp);
X	matchptr = matchbuf;
X	while (matchct--)			/* insert matches in the arg list */
X		insnode(list,node,*matchptr++);
X	free(matchbuf);
X	*np = (next) ? prevnode(next) : lastnode(list);
X}
X
X/* get number after qualifier */
X
Xlong qgetnum(s) /**/
Xchar **s;
X{
Xlong v = 0;
X
X	if (!idigit(**s))
X		{
X		zerr("number expected",NULL,0);
X		return 0;
X		}
X	while (idigit(**s))
X		v = v*10+*(*s)++-'0';
X	return v;
X}
X
Xint notstrcmp(a,b) /**/
Xchar **a;char **b;
X{
Xchar *c = *b,*d = *a;
SHAR_EOF
true || echo 'restore of zsh2.00/src/glob.c failed'
fi
echo 'End of zsh2.00.00 part 5'
echo 'File zsh2.00/src/glob.c is continued in part 6'
echo 6 > _shar_seq_.tmp
exit 0
--
              Paul Falstad  pfalstad@phoenix.princeton.edu
         And on the roads, too, vicious gangs of KEEP LEFT signs!
     If Princeton knew my opinions, they'd have expelled me long ago.

exit 0 # Just in case...
-- 
Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
Sterling Software, IMD           UUCP:     uunet!sparky!kent
Phone:    (402) 291-8300         FAX:      (402) 291-4362
Please send comp.sources.misc-related mail to kent@uunet.uu.net.