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

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


---cut here---cut here---cut here---
-				close(pipes[1]);
-				entersubsh(1);
-				exiting = 1;
-				execpline2(pline->right,ASYNC,pipes[0],output,1);
-				_exit(lastval);
-				}
-			else if (pid == -1)
-				{
-				zerr("fork failed: %e",errno);
-				errflag = 1;
-				}
-			else
-				{
-				char *s,*text;
-
-				close(pipes[0]);
-				text = s = getptext(pline->right);
-				for (;*s;s++)
-				if (*s == '\n')
-					*s = ';';
-				untokenize(text);
-				addproc(pid,text)->lastfg = 1;
-				freepline(pline->right);
-				pline->right = NULL;
-				}
-			}
-
-		/* otherwise just do the pipeline normally. */
-
-		execcomm(pline->left,input,pipes[1],how==ASYNC,0);
-		pline->left = NULL;
-		close(pipes[1]);
-		if (pline->right)
-			{
-			execpline2(pline->right,how,pipes[0],output,last1);
-			close(pipes[0]);
-			}
-		}
-}
-
-/* make the argv array */
-
-char **makecline(char *nam,struct xlist *list)
-{
-int ct = 0;
-Node node;
-char **argv,**ptr;
-
-	if (isset(XTRACE))
-		{
-		for (node = list->first; node; node = node->next,ct++);
-		ptr = argv = (char **) zalloc((ct+2)*sizeof(char *));
-		*ptr++ = nam;
-		fprintf(stderr,"+ %s",nam);
-		if (list->first)
-			fputc(' ',stderr);
-		for (node = list->first; node; node = node->next)
-			if (*(char *) node->dat)
-				{
-				*ptr++ = node->dat;
-				untokenize(node->dat);
-				fputs(node->dat,stderr);
-				if (node->next)
-					fputc(' ',stderr);
-				}
-		*ptr = NULL;
-		fputc('\n',stderr);
-		return(argv);
-		}
-	else
-		{
-		for (node = list->first; node; node = node->next,ct++);
-		ptr = argv = (char **) zalloc((ct+2)*sizeof(char *));
-		*ptr++ = nam;
-		for (node = list->first; node; node = node->next)
-			if (*(char *) node->dat)
-				{
-				*ptr++ = node->dat;
-				untokenize(node->dat);
-				}
-		*ptr = NULL;
-		return(argv);
-		}
-}
-
-/* untokenize the command line and remove null arguments */
-
-void fixcline(table l)
-{
-Node node,next;
-
-	for (node = l->first; node; node = next)
-		{
-		next = node->next;
-		if (*(char *) node->dat)
-			untokenize(node->dat);
-		else
-			remnode(l,node);
-		}
-}
-
-void untokenize(char *s)
-{
-	for (; *s; s++)
-		if (istok(*s))
-			if (*s == HQUOT || *s == Nularg)
-				chuck(s--);
-			else
-				*s = tokens[*s-Pound];
-}
-
-/* add vars to the environment */
-
-void addenv(table list)
-{
-char *s,*t;
-
-	while (s = getnode(list))
-		{
-		dovarsubs(&s);
-		if (errflag)
-			break;
-		untokenize(s);
-		t = getnode(list);
-		dovarsubs(&t);
-		if (errflag)
-			break;
-		untokenize(t);
-		setparm(s,t,1,0);
-		}
-}
-
-/* nonzero if we shouldn't clobber a file */
-
-int dontclob(struct fnode *f)
-{
-struct stat buf;
-
-	if (isset(CLOBBER) || f->type & 1)
-		return 0;
-	if (stat(f->u.name,&buf) == -1)
-		return 1;
-	return S_ISREG(buf.st_mode);
-}
-
-/* close an mnode (success) */
-
-void closemn(struct mnode *mfds[10],int fd)
-{
-	if (mfds[fd])
-		{
-		if (mfds[fd]->ct > 1)
-			if (mfds[fd]->rflag == 0)
-				catproc(mfds[fd]);
-			else
-				teeproc(mfds[fd]);
-		free(mfds[fd]);
-		mfds[fd] = NULL;
-		}
-}
-
-/* close all the mnodes (failure) */
-
-void closemnodes(struct mnode *mfds[10])
-{
-int t0,t1;
-
-	for (t0 = 0; t0 != 10; t0++)
-		if (mfds[t0])
-			{
-			for (t1 = 0; t1 != mfds[t0]->ct; t1++)
-				close(mfds[t0]->fds[t1]);
-			free(mfds[t0]);
-			mfds[t0] = NULL;
-			}
-}
-
-/* add a fd to an mnode */
-/* an mnode is a list of fds associated with a certain fd.
-	thus if you do "foo >bar >ble", the mnode for fd 1 will have
-	two fds, the result of open("bar",...), and the result of
-	open("ble",....). */
-
-void addfd(int forked,int save[10],struct mnode *mfds[10],int fd1,int fd2,int rflag)
-{
-int pipes[2];
-
-	if (!mfds[fd1])	/* starting a new mnode */
-		{
-		mfds[fd1] = alloc(sizeof(struct mnode));
-		if (!forked && fd1 != fd2 && fd1 < 10)
-			save[fd1] = movefd(fd1);
-		redup(fd2,fd1);
-		mfds[fd1]->ct = 1;
-		mfds[fd1]->fds[0] = fd1;
-		mfds[fd1]->rflag = rflag;
-		}
-	else
-		{
-		if (mfds[fd1]->rflag != rflag)
-			{
-			zerr("file mode mismatch on fd %d",fd1);
-			errflag = 1;
-			return;
-			}
-		if (mfds[fd1]->ct == 1)		/* split the stream */
-			{
-			mfds[fd1]->fds[0] = movefd(fd1);
-			mfds[fd1]->fds[1] = movefd(fd2);
-			mpipe(pipes);
-			mfds[fd1]->pipe = pipes[1-rflag];
-			redup(pipes[rflag],fd1);
-			mfds[fd1]->ct = 2;
-			}
-		else		/* add another fd to an already split stream */
-			mfds[fd1]->fds[mfds[fd1]->ct++] = movefd(fd2);
-		}
-}
-
-void execcomm(comm comm,int input,int output,int bkg,int last1)
-{
-int type;
-long pid = 0;
-table args = comm->args;
-int save[10] = {0,0,0,0,0,0,0,0,0,0},gstat;
-struct fnode *fn;
-struct mnode *mfds[10] = {0,0,0,0,0,0,0,0,0,0};
-int fil,forked = 0,iscursh = 0,t0;
-struct chnode *chn = NULL;
-char *text;
-list l;
-
-	if ((type = comm->type) == SIMPLE && !*comm->cmd)
-		{
-		if (comm->vars)
-			addvars(comm->vars);
-		return;
-		}
-	if (comm->cmd)
-		{
-		if (*comm->cmd == '%')
-			{
-			if (full(args))
-				{
-				zerrnam(comm->cmd,"too many arguments");
-				return;
-				}
-			addnode(args,comm->cmd);
-			comm->cmd = strdup((bkg) ? "bg" : "fg");
-			bkg = 0;
-			}
-		docmdsubs(&comm->cmd);
-		if (errflag)
-			{
-			freecmd(comm);
-			lastval = 1;
-			return;
-			}
-		untokenize(comm->cmd);
-		}
-	if (jobbing)	/* get the text associated with this command */
-		{
-		char *s;
-		s = text = gettext(comm);
-		for (;*s;s++)
-			if (*s == '\n')
-				*s = ';';
-		untokenize(text);
-		}
-	else
-		text = NULL;
-	prefork(comm->args);	/* do prefork substitutions */
-	if (comm->cmd && !(comm->flags & CFLAG_COMMAND))
-		{
-		if (isset(CORRECT) && jobbing)
-			spckcmd(&comm->cmd);
-		if ((l = gethnode(comm->cmd,shfunchtab)) &&
-				!(comm->flags & CFLAG_COMMAND))
-			{
-			insnode(comm->args,(Node) comm->args,comm->cmd);
-			comm->cmd = NULL;
-			comm->left = duplist(l);
-			type = comm->type = SHFUNC;
-			}
-		else
-			chn = gethnode(comm->cmd,chtab);
-		}
-	if (unset(RMSTARSILENT) && jobbing && chn && chn->type != BUILTIN &&
-			!strcmp(comm->cmd,"rm") && full(comm->args) &&
-			((char *) comm->args->first->dat)[0] == Star &&
-			((char *) comm->args->first->dat)[1] == '\0')
-		checkrmall();
-	if (errflag)
-		{
-		freecmd(comm);
-		lastval = 1;
-		return;
-		}
-	
-	/* this is nonzero if comm is a current shell procedure */
-
-	iscursh = (type >= CURSH) || (type == SIMPLE && chn &&
-		chn->type == BUILTIN);
-
-	gstat = (chn) ? chn->globstat : GLOB;
-
-	/* if this command is backgrounded or (this is an external
-		command and we are not exec'ing it) or this is a builtin
-		with output piped somewhere, then fork.  If this is the
-		last stage in a subshell pipeline, don't fork, but make
-		the rest of the function think we forked. */
-
-	if (bkg || !(iscursh || (comm->flags & CFLAG_EXEC)) ||
-			(chn && chn->type == BUILTIN && output))
-		{
-		pid = (last1 && execok()) ? 0 : phork();
-		if (pid == -1)
-			return;
-		if (pid)
-			{
-			if (pid == -1)
-				zerr("%e",errno);
-			else
-				(void) addproc(pid,text);
-			return;
-			}
-		entersubsh(bkg);
-		forked = 1;
-		}
-	if (bkg && isset(BGNICE))	/* stupid */
-		nice(5);
-	if (input)		/* add pipeline input/output to mnodes */
-		addfd(forked,save,mfds,0,input,0);
-	if (output)
-		addfd(forked,save,mfds,1,output,1);
-	spawnpipes(comm->redir);		/* do process substitutions */
-	while (full(comm->redir))
-		if ((fn = getnode(comm->redir))->type == INPIPE)
-			{
-			if (fn->u.fd2 == -1)
-				execerr();
-			addfd(forked,save,mfds,fn->fd1,fn->u.fd2,0);
-			free(fn);
-			}
-		else if (fn->type == OUTPIPE)
-			{
-			if (fn->u.fd2 == -1)
-				execerr();
-			addfd(forked,save,mfds,fn->fd1,fn->u.fd2,1);
-			free(fn);
-			}
-		else
-			{
-			if (!(fn->type == HEREDOC || fn->type == CLOSE || fn->type ==
-					MERGE || fn->type == MERGEOUT))
-				if (xpandredir(fn,comm->redir))
-					continue;
-			if (fn->type == READ || fn->type == HEREDOC)
-				{
-				fil = (fn->type == READ) ? open(fn->u.name,O_RDONLY) : fn->u.fd2;
-				if (fil == -1)
-					{
-					if (errno != EINTR)
-						zerr("%e: %s",errno,fn->u.name);
-					execerr();
-					}
-				addfd(forked,save,mfds,fn->fd1,fil,0);
-				if (fn->type == READ)
-					free(fn->u.name);
-				}
-			else if (fn->type == CLOSE)
-				{
-				if (!forked && fn->fd1 < 3)
-					{
-					zerr("can't close fd %d without forking",fn->fd1);
-					execerr();
-					}
-				closemn(mfds,fn->fd1);
-				close(fn->fd1);
-				}
-			else if (fn->type == MERGE || fn->type == MERGEOUT)
-				{
-				fil = dup(fn->u.fd2);
-				if (mfds[fn->fd1])
-					redup(fil,fn->fd1);
-				else
-					addfd(forked,save,mfds,fn->fd1,fil,fn->type == MERGEOUT);
-				}
-			else
-				{
-				if (fn->type >= APP)
-					fil = open(fn->u.name,dontclob(fn) ?
-						O_WRONLY|O_APPEND : O_WRONLY|O_APPEND|O_CREAT,0666);
-				else
-					fil = open(fn->u.name,dontclob(fn) ? 
-						O_WRONLY|O_CREAT|O_EXCL : O_WRONLY|O_CREAT|O_TRUNC,0666);
-				if (fil == -1)
-					{
-					if (errno != EINTR)
-						zerr("%e: %s",errno,fn->u.name);
-					execerr();
-					}
-				addfd(forked,save,mfds,fn->fd1,fil,1);
-				free(fn->u.name);
-				}
-			free(fn);
-			}
-	postfork(comm->args,gstat);	/* perform postfork substitutions */
-	if (errflag)
-		{
-		lastval = 1;
-		goto err;
-		}
-	
-	/* we are done with redirection.  close the mnodes, spawning
-		tee/cat processes as necessary. */
-	for (t0 = 0; t0 != 10; t0++)
-		closemn(mfds,t0);
-
-	if (unset(NOEXEC))
-		if (type >= CURSH)	/* current shell proc */
-			{
-			void (*func[])(struct cnode *) = {execcursh,execshfunc,
-				execfor,execwhile,execrepeat,execif,execcase,execselect};
-	
-			fixcline(comm->args);
-			(func[type-CURSH])(comm);
-			fflush(stdout);
-			if (ferror(stdout))
-				{
-				zerr("write error: %e",errno);
-				clearerr(stdout);
-				}
-			}
-		else if (iscursh)		/* builtin */
-			{
-			int (*func)() = chn->u.func;
-
-			if (comm->vars)
-				{
-				addvars(comm->vars);
-				comm->vars = NULL;
-				}
-			fixcline(comm->args);
-			if (func == test)		/* let test know if it is test or [ */
-				insnode(comm->args,(Node) comm->args,strdup(comm->cmd));
-			lastval = func(comm);
-			if (isset(PRINTEXITVALUE) && lastval)
-				zerr("exit %d",lastval);
-			}
-		else
-			{
-			if (comm->vars)
-				addenv(comm->vars);
-			if (type == SIMPLE)
-				{
-				closem();
-				execute(comm->cmd,args);
-				}
-			else	/* ( ... ) */
-				execlist(comm->left);
-			}
-err:
-	if (forked)
-		_exit(lastval);
-	fixfds(save);
-	freecmd(comm);
-}
-
-/* restore fds after redirecting a builtin */
-
-void fixfds(int save[10])
-{
-int t0;
-
-	for (t0 = 0; t0 != 10; t0++)
-		if (save[t0])
-			redup(save[t0],t0);
-}
-
-void entersubsh(int bkg)
-{
-	if (!jobbing)
-		{
-		if (bkg && isatty(0))
-			{
-			close(0);
-			if (open("/dev/null",O_RDWR))
-				{
-				zerr("can't open /dev/null: %e",errno);
-				_exit(1);
-				}
-			}
-		}
-	else if (!jobtab[curjob].gleader)
-		{
-		setpgrp(0L,jobtab[curjob].gleader = getpid());
-		if (!bkg)
-			attachtty(jobtab[curjob].gleader);
-		}
-	else
-		setpgrp(0L,jobtab[curjob].gleader);
-	subsh = 1;
-	if (SHTTY != -1)
-		{
-		close(SHTTY);
-		SHTTY = -1;
-		}
-	if (jobbing)
-		{
-		signal(SIGTTOU,SIG_DFL);
-		signal(SIGTTIN,SIG_DFL);
-		signal(SIGTSTP,SIG_DFL);
-		signal(SIGPIPE,SIG_DFL);
-		}
-	if (interact)
-		{
-		signal(SIGTERM,SIG_DFL);
-		if (sigtrapped[SIGINT])
-			signal(SIGINT,SIG_IGN);
-		}
-	if (!sigtrapped[SIGQUIT])
-		signal(SIGQUIT,SIG_DFL);
-	opts[MONITOR] = OPT_UNSET;
-	clearjobtab();
-}
-
-/* close all shell files */
-
-void closem(void)
-{
-int t0;
-
-	for (t0 = 10; t0 != NOFILE; t0++)
-		close(t0);
-}
-
-/* get here document */
-
-int gethere(char *str)
-{
-char pbuf[256],*nam = gettemp();
-int tfil = creat(nam,0666);
-FILE *in = fdopen(SHIN,"r");
-
-	FOREVER
-		{
-		fgetline(pbuf,256,in);
-		if (strcmp(str,pbuf))
-			{
-			pbuf[strlen(pbuf)] = '\n';
-			write(tfil,pbuf,strlen(pbuf));
-			}
-		else
-			break;
-		}
-	close(tfil);
-	tfil = open(nam,O_RDONLY);
-	unlink(nam);
-	free(nam);
-	return(tfil);
-}
-
-void catproc(struct mnode *mn)
-{
-int len,t0;
-char *buf;
-
-	if (phork())
-		{
-		for (t0 = 0; t0 != mn->ct; t0++)
-			close(mn->fds[t0]);
-		close(mn->pipe);
-		return;
-		}
-	closeallelse(mn);
-	buf = zalloc(4096);
-	for (t0 = 0; t0 != mn->ct; t0++)
-		while (len = read(mn->fds[t0],buf,4096))
-			write(mn->pipe,buf,len);
-	_exit(0);
-}
- 
-void teeproc(struct mnode *mn)
-{
-int len,t0;
-char *buf;
-
-	if (phork())
-		{
-		for (t0 = 0; t0 != mn->ct; t0++)
-			close(mn->fds[t0]);
-		close(mn->pipe);
-		return;
-		}
-	buf = zalloc(4096);
-	closeallelse(mn);
-	while ((len = read(mn->pipe,buf,4096)) > 0)
-		for (t0 = 0; t0 != mn->ct; t0++)
-			write(mn->fds[t0],buf,len);
-	_exit(0);
-}
-
-void closeallelse(struct mnode *mn)
-{
-int t0,t1;
-
-	for (t0 = 0; t0 != NOFILE; t0++)
-		if (mn->pipe != t0)
-			{
-			for (t1 = 0; t1 != mn->ct; t1++)
-				if (mn->fds[t1] == t0)
-					break;
-			if (t1 == mn->ct)
-				close(t0);
-			}
-}
-
-/* strtol() doesn't work right on my system */
-
-long int zstrtol(const char *s,char **t,int base)
-{
-int ret = 0;
- 
-	for (; *s >= '0' && *s < ('0'+base); s++)
-		ret = ret*base+*s-'0';
-	if (t)
-		*t = (char *) s;
-	return ret;
-}
-
-/* $(...) */
-
-table getoutput(char *cmd,int qt)
-{
-list list;
-int pipes[2];
-
-	if (*cmd == '<')
-		{
-		int stream;
-		char *fi;
-
-		fi = strdup(cmd+1);
-		if (*fi == '~')
-			*fi = Tilde;
-		else if (*fi == '=')
-			*fi = Equals;
-		filesub((void **) &fi);
-		if (errflag)
-			return NULL;
-		stream = open(fi,O_RDONLY);
-		if (stream == -1)
-			{
-			magicerr();
-			zerr("%e: %s",errno,cmd+1);
-			return NULL;
-			}
-		return readoutput(stream,qt);
-		}
-	hungets(strdup(cmd));
-	strinbeg();
-	if (!(list = parlist(1)))
-		{
-		strinend();
-		hflush();
-		return NULL;
-		}
-	if (peek != EOF && peek != EMPTY)
-		{
-		strinend();
-		hflush();
-		return NULL;
-		}
-	strinend();
-	mpipe(pipes);
-	if (phork())
-		{
-		close(pipes[1]);
-		return readoutput(pipes[0],qt);
-		}
-	subsh = 1;
-	close(pipes[0]);
-	redup(pipes[1],1);
-	entersubsh(0);
-	signal(SIGTSTP,SIG_IGN);
-	exiting = 1;
-	execlist(list);
-	close(1);
-	exit(0);  return NULL;
-}
-
-/* read output of command substitution */
-
-table readoutput(int in,int qt)
-{
-table ret;
-char *buf,*ptr;
-int bsiz,c,cnt = 0;
-FILE *fin;
-
-	fin = fdopen(in,"r");
-	ret = newtable();
-	ptr = buf = zalloc(bsiz = 256);
-	while ((c = fgetc(fin)) != EOF)
-		if (!qt && znspace(c))
-			{
-			if (cnt)
-				{
-				*ptr = '\0';
-				addnode(ret,strdup(buf));
-				cnt = 0;
-				ptr = buf;
-				}
-			}
-		else
-			{
-			*ptr++ = c;
-			if (++cnt == bsiz)
-				{
-				char *pp = zalloc(bsiz *= 2);
-				
-				memcpy(pp,buf,cnt);
-				free(buf);
-				ptr = (buf = pp)+cnt;
-				}
-			}
-	if (qt && ptr != buf && ptr[-1] == '\n')
-		ptr[-1] = '\0';
-	if (cnt)
-		addnode(ret,strdup(buf));
-	free(buf);
-	fclose(fin);
-	return ret;
-}
-
-/* =(...) */
-
-char *getoutputfile(char *cmd)
-{
-#ifdef WAITPID
-int pid;
-#endif
-char *nam = gettemp(),*str;
-int tfil;
-list list;
-
-	for (str = cmd; *str && *str != Outpar; str++);
-	if (!*str)
-		zerr("oops.");
-	*str = '\0';
-	hungets(strdup(cmd));
-	strinbeg();
-	if (!(list = parlist(1)))
-		{
-		hflush();
-		strinend();
-		return NULL;
-		}
-	if (peek != EOF && peek != EMPTY)
-		{
-		strinend();
-		hflush();
-		return NULL;
-		}
-	strinend();
-	if (!jobtab[curjob].filelist)
-		jobtab[curjob].filelist = newtable();
-	addnode(jobtab[curjob].filelist,strdup(nam));
-#ifdef WAITPID
-	if (pid = phork())
-		{
-		waitpid(pid,NULL,WUNTRACED);
-		return nam;
-		}
-#else
-	if (waitfork())
-		return nam;
-#endif
-	subsh = 1;
-	close(1);
-	entersubsh(0);
-	tfil = creat(nam,0666);
-	exiting = 1;
-	execlist(list);
-	close(1);
-	exit(0); return NULL;
-}
-
-/* get a temporary named pipe */
-
-char *namedpipe(void)
-{
-char *tnam = gettemp();
-
-	mknod(tnam,0010666,0);
-	return tnam;
-}
-
-/* <(...) */
-
-char *getoutproc(char *cmd)
-{
-list list;
-int fd;
-char *pnam,*str;
-
-	for (str = cmd; *str && *str != Outpar; str++);
-	if (!*str)
-		zerr("oops.");
-	*str = '\0';
-	hungets(strdup(cmd));
-	strinbeg();
-	if (!(list = parlist(1)))
-		{
-		strinend();
-		hflush();
-		return NULL;
-		}
-	if (peek != EOF && peek != EMPTY)
-		{
-		strinend();
-		hflush();
-		return NULL;
-		}
-	strinend();
-	pnam = namedpipe();
-	if (!jobtab[curjob].filelist)
-		jobtab[curjob].filelist = newtable();
-	addnode(jobtab[curjob].filelist,strdup(pnam));
-	if (phork())
-		return pnam;
-	entersubsh(1);
-	fd = open(pnam,O_WRONLY);
-	if (fd == -1)
-		{
-		zerr("can't open %s: %e",pnam,errno);
-		_exit(0);
-		}
-	redup(fd,1);
-	fd = open("/dev/null",O_RDONLY);
-	redup(fd,0);
-	exiting = 1;
-	execlist(list);
-	close(1);
-	_exit(0);  return NULL;
-}
-
-/* >(...) */
-
-char *getinproc(char *cmd)
-{
-list list;
-int pid,fd;
-char *pnam,*str;
-
-	for (str = cmd; *str && *str != Outpar; str++);
-	if (!*str)
-		zerr("oops.");
-	*str = '\0';
-	hungets(strdup(cmd));
-	strinbeg();
-	if (!(list = parlist(1)))
-		{
-		strinend();
-		hflush();
-		return NULL;
-		}
-	if (peek != EOF && peek != EMPTY)
-		{
-		strinend();
-		hflush();
-		return NULL;
-		}
-	strinend();
-	pnam = namedpipe();
-	if (!jobtab[curjob].filelist)
-		jobtab[curjob].filelist = newtable();
-	addnode(jobtab[curjob].filelist,strdup(pnam));
-	if (pid = phork())
-		return pnam;
-	entersubsh(1);
-	fd = open(pnam,O_RDONLY);
-	redup(fd,0);
-	exiting = 1;
-	execlist(list);
-	_exit(0);  return NULL;
-}
-
-/* > >(...) (does not use named pipes) */
-
-int getinpipe(char *cmd)
-{
-list list;
-int pipes[2];
-char *str = cmd;
-
-	for (str = cmd; *str && *str != Outpar; str++);
-	if (!*str)
-		zerr("oops.");
-	*str = '\0';
-	hungets(strdup(cmd+2));
-	strinbeg();
-	if (!(list = parlist(1)))
-		{
-		strinend();
-		hflush();
-		return -1;
-		}
-	if (peek != EOF && peek != EMPTY)
-		{
-		strinend();
-		hflush();
-		return NULL;
-		}
-	strinend();
-	mpipe(pipes);
-	if (phork())
-		{
-		close(pipes[1]);
-		return pipes[0];
-		}
-	close(pipes[0]);
-	entersubsh(1);
-	redup(pipes[1],1);
-	exiting = 1;
-	execlist(list);
-	_exit(0);  return 0;
-}
-
-/* < <(...) */
-
-int getoutpipe(char *cmd)
-{
-list list;
-int pipes[2];
-char *str;
-
-	for (str = cmd; *str && *str != Outpar; str++);
-	if (!*str)
-		zerr("oops.");
-	*str = '\0';
-	hungets(strdup(cmd+2));
-	strinbeg();
-	if (!(list = parlist(1)))
-		{
-		strinend();
-		hflush();
-		return -1;
-		}
-	if (peek != EOF && peek != EMPTY)
-		{
-		strinend();
-		hflush();
-		return NULL;
-		}
-	strinend();
-	mpipe(pipes);
-	if (phork())
-		{
-		close(pipes[0]);
-		return pipes[1];
-		}
-	close(pipes[1]);
-	entersubsh(1);
-	redup(pipes[0],0);
-	exiting = 1;
-	execlist(list);
-	_exit(0);  return 0;
-}
-
-/* run a list, saving the current job num */
-
-void runlist(list l)
-{
-int cj = curjob;
-
-	execlist(l);
-	curjob = cj;
-}
-
-char *gettemp(void)
-{
-	return mktemp(strdup("/tmp/zshXXXXXX"));
-}
-
-/* my getwd; all the other ones I tried confused the SIGCHLD handler */
-
-char *zgetwd(void)
-{
-static char buf0[MAXPATHLEN];
-char buf3[MAXPATHLEN],*buf2 = buf0+1;
-struct stat sbuf;
-struct direct *de;
-DIR *dir;
-ino_t ino = -1;
-dev_t dev = -1;
-
-	holdintr();
-	buf2[0] = '\0';
-	buf0[0] = '/';
-	for(;;)
-		{
-		if (stat(".",&sbuf) < 0)
-			{
-			chdir(buf0);
-			noholdintr();
-			return strdup(".");
-			}
-		ino = sbuf.st_ino;
-		dev = sbuf.st_dev;
-		if (stat("..",&sbuf) < 0)
-			{
-			chdir(buf0);
-			noholdintr();
-			return strdup(".");
-			}
-		if (sbuf.st_ino == ino && sbuf.st_dev == dev)
-			{
-			chdir(buf0);
-			noholdintr();
-			return strdup(buf0);
-			}
-		dir = opendir("..");
-		if (!dir)
-			{
-			chdir(buf0);
-			noholdintr();
-			return strdup(".");
-			}
-		chdir("..");
-		readdir(dir); readdir(dir);
-		while (de = readdir(dir))
-			if (de->d_fileno == ino)
-				{
-				lstat(de->d_name,&sbuf);
-				if (sbuf.st_dev == dev)
-					goto match;
-				}
-		rewinddir(dir);
-		readdir(dir); readdir(dir);
-		while (de = readdir(dir))
-			{
-			lstat(de->d_name,&sbuf);
-			if (sbuf.st_dev == dev)
-				goto match;
-			}
-		noholdintr();
-		closedir(dir);
-		return strdup(".");
-match:
-		strcpy(buf3,de->d_name);
-		if (*buf2)
-			strcat(buf3,"/");
-		strcat(buf3,buf2);
-		strcpy(buf2,buf3);
-		closedir(dir);
-		}
-}
-
-/* open pipes with fds >= 10 */
-
-void mpipe(int pp[2])
-{
-	pipe(pp);
-	pp[0] = movefd(pp[0]);
-	pp[1] = movefd(pp[1]);
-}
-
-/* do process substitution with redirection */
-
-void spawnpipes(table l)
-{
-Node n = l->first;
-struct fnode *f;
-
-	for (; n; n = n->next)
-		{
-		f = n->dat;
-		if (f->type == OUTPIPE)
-			{
-			char *str = f->u.name;
-			f->u.fd2 = getoutpipe(str);
-			free(str);
-			}
-		if (f->type == INPIPE)
-			{
-			char *str = f->u.name;
-			f->u.fd2 = getinpipe(str);
-			free(str);
-			}
-		}
-}
-
End of exec.c
echo exec.pro 1>&2
sed 's/^-//' >exec.pro <<'End of exec.pro'
-void execstring(char *s);
-void newrunlist(list l);
-int phork(void);
-void execcursh(comm comm);
-void execute(char *arg0,table args);
-char *findcmd(char *arg0);
-void execlist(list list);
-void execlist1(list list);
-void execlist2(list2 list,int type,int last1);
-int execpline(list2 l,int how,int last1);
-void execpline2(pline pline,int how,int input,int output,int last1);
-char **makecline(char *nam,struct xlist *list);
-void fixcline(table l);
-void untokenize(char *s);
-void addenv(table list);
-int dontclob(struct fnode *f);
-void closemn(struct mnode *mfds[10],int fd);
-void closemnodes(struct mnode *mfds[10]);
-void addfd(int forked,int save[10],struct mnode *mfds[10],int fd1,int fd2,int rflag);
-void execcomm(comm comm,int input,int output,int bkg,int last1);
-void fixfds(int save[10]);
-void entersubsh(int bkg);
-void closem(void);
-int gethere(char *str);
-void catproc(struct mnode *mn);
-void teeproc(struct mnode *mn);
-void closeallelse(struct mnode *mn);
-long int zstrtol(const char *s,char **t,int base);
-table getoutput(char *cmd,int qt);
-table readoutput(int in,int qt);
-char *getoutputfile(char *cmd);
-char *namedpipe(void);
-char *getoutproc(char *cmd);
-char *getinproc(char *cmd);
-int getinpipe(char *cmd);
-int getoutpipe(char *cmd);
-void runlist(list l);
-char *gettemp(void);
-char *zgetwd(void);
-void mpipe(int pp[2]);
-void spawnpipes(table l);
End of exec.pro
echo funcs.h 1>&2
sed 's/^-//' >funcs.h <<'End of funcs.h'
-/*
-
-	funcs.h - includes for all prototype files
-
-	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 "glob.pro"
-#include "hist.pro"
-#include "table.pro"
-#include "subst.pro"
-#include "builtin.pro"
-#include "loop.pro"
-#include "jobs.pro"
-#include "exec.pro"
-#include "init.pro"
-#include "lex.pro"
-#include "parse.pro"
-#include "utils.pro"
-#include "test.pro"
-char *readline(char *);
-char *mktemp(char *);
End of funcs.h
echo glob.c 1>&2
sed 's/^-//' >glob.c <<'End of glob.c'
-/*
-
-	glob.c - filename generation and brace expansion
-
-	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"
-#ifndef INT_MAX
-#include <limits.h>
-#endif
-#include <sys/dir.h>
-#include <sys/errno.h>
-
-#define exists(X) (access(X,0) == 0)
-#define magicerr() { if (magic) putc('\n',stderr); errflag = 1; }
-
-static int gtype;	/* file type for (X) */
-static int mode;	/* != 0 if we are parsing glob patterns */
-static int sense; /* (X) or (^X) */
-static int pathpos;	/* position in pathbuf */
-static int matchsz;	/* size of matchbuf */
-static int matchct;	/* number of matches found */
-static char pathbuf[MAXPATHLEN];	/* pathname buffer */
-static char **matchbuf;		/* array of matches */
-static char **matchptr;		/* &matchbuf[matchct] */
-
-/* pathname component in filename patterns */
-
-/* qath is a struct xpath * */
-
-struct xpath {
-	qath next;
-	comp comp;
-	int closure;	/* 1 if this is a (foo/)# */
-	};
-struct xcomp {
-	comp nx1,nx2;
-	char *str;
-	};
-
-void glob(table list,Node *np)
-{
-Node node = (*np)->last;	/* the node before this one */
-Node next = (*np)->next;	/* the node after this one */
-int sl;		/* length of the pattern */
-char *ostr;	/* the pattern before the parser chops it up */
-char *wd;	/* the cwd */
-qath q;		/* pattern after parsing */
-char *str = (*np)->dat;	/* the pattern */
-
-	sl = strlen(str);
-	ostr = strdup(str);
-	remnode(list,*np);
-	gtype = 0;
-	if (str[sl-1] == Outpar)	/* check for (X) or (^X) */
-		{
-		if (sl > 4 && str[sl-4] == Inpar && str[sl-3] == Hat)
-			sense = 1;
-		else if (sl > 3 && str[sl-3] == Inpar)
-			sense = 0;
-		else
-			sense = 2;
-		if (sense != 2)
-			{
-			str[sl-3-sense] = '\0';
-			switch (str[sl-2])
-				{
-				case '@': gtype = S_IFLNK; break;
-				case '=': gtype = S_IFSOCK; break;
-				case Inang: gtype = S_IFIFO; break;
-				case '/': gtype = S_IFDIR; break;
-				case '.': gtype = S_IFREG; break;
-				case Star:  gtype = 0100; break;
-				case '%': gtype = S_IFCHR; break;
-				case 'R': gtype = 0004; break;
-				case 'W': gtype = 0002; break;
-				case 'X': gtype = 0001; break;
-				case 'r': gtype = 0400; break;
-				case 'w': gtype = 0200; break;
-				case 'x': gtype = 0100; break;
-				default:
-					magicerr();
-					zerr("unknown file attribute");
-					return;
-				};
-			}
-		}
-	else if (str[sl-1] == '/')		/* foo/ == foo(/) */
-		{
-		gtype = S_IFDIR;
-		sense = 0;
-		}
-	if (*str == '/')	/* pattern has absolute path */
-		{
-		wd = zgetwd();
-		str++;
-		chdir("/");
-		pathbuf[0] = '/';
-		pathbuf[pathpos = 1] = '\0';
-		}
-	else		/* pattern is relative to cwd */
-		{
-		wd = NULL;
-		pathbuf[pathpos = 0] = '\0';
-		}
-	q = parsepat(str);
-	if (!q || errflag)	/* if parsing failed */
-		{
-		if (isset(NOBADPATTERN))
-			{
-			insnode(list,node,ostr);
-			return;
-			}
-		magicerr();
-		zerr("bad pattern: %s",ostr);
-		free(ostr);
-		return;
-		}
-	matchptr = matchbuf = (char **) zalloc((matchsz = 16)*sizeof(char *));
-	matchct = 0;
-	scanner(q);		/* do the globbing */
-	freepath(q);
-	if (wd)		/* reset cwd */
-		{
-		chdir(wd);
-		free(wd);
-		}
-	if (!matchct && unset(NULLGLOB))
-		if (unset(NONOMATCH))
-			{
-			if (!errflag)
-				{
-				magicerr();
-				zerr("no matches found: %s",ostr);
-				}
-			free(matchbuf);
-			free(ostr);
-			errflag = 1;
-			return;
-			}
-		else
-			{
-			*matchptr++ = strdup(ostr);
-			matchct = 1;
-			}
-	qsort(&matchbuf[0],matchct,sizeof(char *),notstrcmp);
-	matchptr = matchbuf;
-	while (matchct--)			/* insert matches in the arg list */
-		insnode(list,node,*matchptr++);
-	free(matchbuf);
-	free(ostr);
-	if (magic)
-		magic = 2;	/* tell readline we did something */
-	*np = (next) ? next->last : list->last;
-}
-
-int notstrcmp(char **a,char **b)
-{
-char *c = *b,*d = *a;
-
-	for (; *c == *d && *c; c++,d++);
-	return ((int) (unsigned char) *c-(int) (unsigned char) *d);
-}
-
-/* add a match to the list */
-
-void insert(char *s)
-{
-struct stat buf;
-
-	if (isset(MARKDIRS) && !lstat(s,&buf) && S_ISDIR(buf.st_mode)) /* grrr */
-		{
-		char *t;
-		int ll = strlen(s);
-
-		t = zalloc(ll+2);
-		strcpy(t,s);
-		t[ll] = '/';
-		t[ll+1] = '\0';
-		free(s);
-		s = t;
-		}
-	*matchptr++ = s;
-	if (++matchct == matchsz)
-		{
-		matchbuf = (char **) realloc(matchbuf,sizeof(char **)*(matchsz *= 2));
-		matchptr = matchbuf+matchct;
-		}
-}
-
-/* check to see if str is eligible for filename generation */
-
-int haswilds(char *str)	
-{
-	if (!str[1] && (*str == Inbrack || *str == Outbrack))
-		return 0;
-	if (str[0] == '%')
-		return 0;
-	for (; *str; str++)
-		if (!strncmp(str,"..../",5))
-			return 1;
-		else if (*str == Pound || *str == Hat || *str == Star ||
-				*str == Bar || *str == Inbrack || *str == Inang ||
-				*str == Quest)
-			return 1;
-	return 0;
-}
-
-/* check to see if str is eligible for brace expansion */
-
-int hasbraces(char *str)
-{
-int mb,bc,cmct1,cmct2;
-char *lbr = NULL;
-
-	if (str[0] == Inbrace && str[1] == Outbrace)
-		return 0;
-	for (mb = bc = cmct1 = cmct2 = 0; *str; str++)
-		{
-		if (*str == Inbrace)
-			{
-			if (!bc)
-				lbr = str;
-			bc++;
-			if (str[4] == Outbrace && str[2] == '-') /* {a-z} */
-				{
-				cmct1++;
-				if (bc == 1)
-					cmct2++;
-				}
-			}
-		else if (*str == Outbrace)
-			{
-			bc--;
-			if (!bc && !cmct2)
-				{
-				*lbr = '{';
-				*str = '}';
-				}
-			cmct2 = 0;
-			}
-		else if (*str == Comma && bc)
-			{
-			cmct1++;
-			if (bc == 1)
-				cmct2++;
-			}
-		if (bc > mb)
-			mb = bc;
-		if (bc < 0)
-			return 0;
-		}
-	return (mb && bc == 0 && cmct1);
-}
-
-/* expand stuff like >>*.c */
-
-int xpandredir(struct fnode *fn,table tab)
-{
-table fake;
-char *nam;
-struct fnode *ff;
-int ret = 0;
-
-	fake = newtable();
-	addnode(fake,fn->u.name);
-	prefork(fake);
-	if (!errflag)
-		postfork(fake,GLOB);
-	if (errflag)
-		{
-		freetable(fake,freestr);
-		return 0;
-		}
-	if (fake->first && !fake->first->next)
-		{
-		fn->u.name = fake->first->dat;
-		untokenize(fn->u.name);
-		}
-	else
-		while (nam = getnode(fake))
-			{
-			ff = alloc(sizeof(struct fnode));
-			ff->u.name = nam;
-			ff->type = fn->type;
-			addnode(tab,ff);
-			ret = 1;
-			}
-	free(fake);
-	return ret;
-}
-
-/* concatenate s1 and s2 in dynamically allocated buffer */
-
-char *dyncat(char *s1,char *s2)
-{
-char *ptr;
- 
-	ptr = zalloc(strlen(s1)+strlen(s2)+1);
-	strcpy(ptr,s1);
-	strcat(ptr,s2);
-	return ptr;
-}
-
-/* concatenate s1, s2, and s3 in dynamically allocated buffer */
-
-char *tricat(char *s1,char *s2,char *s3)
-{
-char *ptr;
-
-	ptr = zalloc(strlen(s1)+strlen(s2)+strlen(s3)+1);
-	strcpy(ptr,s1);
-	strcat(ptr,s2);
-	strcat(ptr,s3);
-	return ptr;
-}
-
-/* brace expansion */
-
-void xpandbraces(table list,Node *np)
-{
-Node node = (*np),last = node->last;
-char *str = node->dat,*str3 = str,*str2;
-int prev;
-
-	if (magic)
-		magic = 2;
-	for (; *str != Inbrace; str++);
- 	if (str[2] == '-' && str[4] == Outbrace)	 /* {a-z} */
-		{
-		char c1,c2;
-
-		remnode(list,node);
-		chuck(str);
-		c1 = *str;
-		chuck(str);
-		chuck(str);
-		c2 = *str;
-		chuck(str);
-		if (istok(c1))
-			c1 = tokens[c1-Pound];
-		if (istok(c2))
-			c2 = tokens[c2-Pound];
-		if (c1 < c2)
-			for (; c2 >= c1; c2--)	/* {a-z} */
-				{
-				*str = c2;
-				insnode(list,last,strdup(str3));
-				}
-		else
-			for (; c2 <= c1; c2++)	/* {z-a} */
-				{
-				*str = c2;
-				insnode(list,last,strdup(str3));
-				}
-		free(str3);
-		*np = last->next;
-		return;
-		}
-	prev = str-str3;
-	str2 = getparen(str++);
-	if (!str2)
-		{
-		errflag = 1;
-		zerr("how did you get this error?");
-		return;
-		}
-	remnode(list,node);
-	node = last;
-	FOREVER
-		{
-		char *zz,*str4;
-		int cnt;
-		
-		for (str4 = str, cnt = 0; cnt || *str != Comma && *str !=
-				Outbrace; str++)
-			if (*str == Inbrace)
-				cnt++;
-			else if (*str == Outbrace)
-				cnt--;
-			else if (!*str)
-				exit(10);
-		zz = zalloc(prev+(str-str4)+strlen(str2)+1);
-		strncpy(zz,str3,prev);
-		zz[prev] = '\0';
-		strncat(zz,str4,str-str4);
-		strcat(zz,str2);
-		insnode(list,node,zz);
-		node = node->next;
-		if (*str != Outbrace)
-			str++;
-		else
-			break;
-		}
-	free(str3);
-	*np = last->next;
-}
-
-/* get closing paren, given pointer to opening paren */
-
-char *getparen(char *str)
-{
-int cnt = 1;
-char typein = *str++,typeout = typein+1;
-
-	for (; *str && cnt; str++)
-		if (*str == typein)
-			cnt++;
-		else if (*str == typeout)
-			cnt--;
-	if (!str && cnt)
-		return NULL;
-	return str;
-}
-
-/* check to see if a matches b (b is not a filename pattern) */
-
-int matchpat(char *a,char *b)
-{
-comp c;
-int val;
-
-	c = parsereg(b);
-	if (!c)
-		{
-		zerr("bad pattern: %s");
-		errflag = 1;
-		return NULL;
-		}
-	val = doesmatch(a,c,0);
-	freecomp(c);
-	return val;
-}
-
-/* do the ${foo%%bar}, ${foo#bar} stuff */
-/* please do not laugh at this code. */
-
-void getmatch(char **sp,char *pat,int dd)
-{
-comp c;
-char *t,*lng = NULL,cc,*s = *sp;
-
-	c = parsereg(pat);
-	if (!c)
-		{
-		magicerr();
-		zerr("bad pattern: %s",pat);
-		return;
-		}
-	if (!(dd & 2))
-		{
-		for (t = s; t==s || t[-1]; t++)
-			{
-			cc = *t;
-			*t = '\0';
-			if (doesmatch(s,c,0))
-				{
-				if (!(dd & 1))
-					{
-					*t = cc;
-					t = strdup(t);
-					free(s);
-					freecomp(c);
-					*sp = t;
-					return;
-					}
-				lng = t;
-				}
-			*t = cc;
-			}
-		if (lng)
-			{
-			t = strdup(lng);
-			free(s);
-			freecomp(c);
-			*sp = t;
-			return;
-			}
-		}
-	else
-		{
-		for (t = s+strlen(s); t >= s; t--)
-			{
-			if (doesmatch(t,c,0))
-				{
-				if (!(dd & 1))
-					{
-					*t = '\0';
-					freecomp(c);
-					return;
-					}
-				lng = t;
-				}
-			}
-		if (lng)
-			{
-			*lng = '\0';
-			freecomp(c);
-			return;
-			}
-		}
-	freecomp(c);
-}
-
-/* add a component to pathbuf */
-
-void addpath(char *s)
-{
-	while (pathbuf[pathpos++] = *s++);
-	pathbuf[pathpos-1] = '/';
-	pathbuf[pathpos] = '\0';
-}
-
-/* do the globbing */
-
-void scanner(qath q)
-{
-comp c;
-
-	if (q->closure)			/* (foo/)# */
-		if (q->closure == 2)		/* (foo/)## */
-			q->closure = 1;
-		else
-			scanner(q->next);
-	if (c = q->comp)
-		{
-		if (!(c->nx1 || c->nx2) && !haswilds(c->str))
-			if (q->next)
-				{
-				char *wd = NULL;
-				
-				if (errflag)
-					return;
-				if (islink(c->str) || !strcmp(c->str,".."))
-					wd = zgetwd();
-				if (!chdir(c->str))
-					{
-					int oppos = pathpos;
-					
-					addpath(c->str);
-					scanner((q->closure) ? q : q->next);
-					if (wd)
-						chdir(wd);
-					else if (strcmp(c->str,"."))
-						chdir("..");
-					pathbuf[pathpos = oppos] = '\0';
-					}
-				else
-					{
-					magicerr();
-					zerr("%e: %s",errno,c->str);
-					if (wd)
-						chdir(wd);
-					else if (strcmp(c->str,"."))
-						chdir("..");
-					return;
-					}
-				}
-			else
-				{
-				if (exists(c->str))
-					insert(dyncat(pathbuf,c->str));
-				}
-		else
-			{
-			char *fn;
-			int type,type3,dirs = !!q->next;
-			struct direct *de;
-			DIR *lock = opendir(".");
-			static struct stat buf;
-			 
-			if (lock == NULL)
-				{
-				magicerr();
-				if (errno != EINTR)
-					zerr("%e: %s",errno,pathbuf);
-				return;
-				}
-			readdir(lock); readdir(lock); 	/* skip . and .. */
-			while (de = readdir(lock))
-				{
-				if (errflag)
-					break;
-				fn = &de->d_name[0];
-				if (dirs)
-					{
-					if (lstat(fn,&buf) == -1)
-						{
-						magicerr();
-						zerr("%e: %s",errno,fn);
-						}
-					type3 = buf.st_mode & S_IFMT;
-					if (type3 != S_IFDIR)
-						continue;
-					}
-				else
-					if (gtype)	/* do the (X) (^X) stuff */
-						{
-						if (lstat(fn,&buf) == -1)
-							{
-							if (errno != ENOENT)
-								{
-								magicerr();
-								zerr("%e: %s",errno,fn);
-								}
-							continue;
-							}
-						type3 = (type = buf.st_mode) & S_IFMT;
-						if (gtype & 0777)
-							{
-							if ((!(type & gtype) ^ sense) || type3 == S_IFLNK)
-								continue;
-							}
-						else if (gtype == S_IFCHR)
-							{
-							if ((type3 != S_IFCHR && type3 != S_IFBLK) ^ sense)
-								continue;
-							}
-						else if ((gtype != type3) ^ sense)
-							continue;
-						}
-				if (doesmatch(fn,c,unset(GLOBDOTS)))
-					if (dirs)
-						{
-						if (!chdir(fn))
-							{
-							int oppos = pathpos;
-					
-							addpath(fn);
-							scanner((q->closure) ? q : q->next); /* scan next level */
-							chdir("..");
-							pathbuf[pathpos = oppos] = '\0';
-							}
-						}
-					else
-						insert(dyncat(pathbuf,fn));
-				}
-			closedir(lock);
-			}
-		}
-	else
-		{
-		zerr("no idea how you got this error message.");
-		errflag = 1;
-		}
-}
-
-/* do the [..(foo)..] business */
-
-int minimatch(char **pat,char **str)
-{
-char *pt = *pat+1,*s = *str;
-	
-	for (; *pt != Outpar; s++,pt++)
-		if ((*pt != Quest || !*s) && *pt != *s)
-			{
-			*pat = getparen(*pat)-1;
-			return 0;
-			}
-	*str = s-1;
-	return 1;
-}
-
-/* see if str matches c; first means worry about matching . explicitly */
-
-int doesmatch(char *str,comp c,int first)
-{
-char *pat = c->str;
-
-	FOREVER
-		{
-		if (!*pat)
-			{
-			if (errflag)
-				return 0;
-			if (!(*str || c->nx1 || c->nx2))
-				return 1;
-			return (c->nx1 && doesmatch(str,c->nx1,first)) ||
-				(c->nx2 && doesmatch(str,c->nx2,first));
-			}
-		if (first && *str == '.' && *pat != '.')
-			return 0;
-		if (*pat == Star)	/* final * is not expanded to ?#; returns success */
-			return 1;
-		first = 0;
-		if (*pat == Quest && *str)
-			{
-			str++;
-			pat++;
-			continue;
-			}
-		if (*pat == Hat)
-			return 1-doesmatch(str,c->nx1,first);
-		if (*pat == Inbrack)
-			if (pat[1] == Hat)
-				{
-				for (pat += 2; *pat != Outbrack && *pat; pat++)
-					if (*pat == '-' && pat[-1] != Hat && pat[1] != Outbrack)
-						{
-						if (pat[-1] <= *str && pat[1] >= *str)
-							break;
-						}
-					else if (*str == *pat)
-						break;
-				if (!*pat)
-					{
-					zerr("something is very wrong.");
-					return 0;
-					}
-				if (*pat != Outbrack)
-					break;
-				pat++;
-				str++;
-				continue;
-				}
-			else
-				{
-				for (pat++; *pat != Outbrack && *pat; pat++)
-					if (*pat == Inpar)
-						{
-						if (minimatch(&pat,&str))
-							break;
-						}
-					else if (*pat == '-' && pat[-1] != Inbrack && pat[1] != Outbrack)
-						{
-						if (pat[-1] <= *str && pat[1] >= *str)
-							break;
-						}
-					else if (*str == *pat)
-						break;
-				if (!pat || !*pat)
-					{
-					zerr("oh dear.  that CAN'T be right.");
-					return 0;
-					}
-				if (*pat == Outbrack)
-					break;
-				for (str++; *pat != Outbrack; pat++);
-				pat++;
-				continue;
-				}
-		if (*pat == Inang)
-			{
-			int t1,t2,t3;
-			char *ptr;
-
-			if (*++pat == Outang)	/* handle <> case */
-				{
-				(void) zstrtol(str,&ptr,10);
-				if (ptr == str)
-					break;
-				str = ptr;
-				pat++;
-				}
-			else
-				{
-				t1 = zstrtol(str,&ptr,10);
-				if (ptr == str)
-					break;
-				str = ptr;
-				t2 = zstrtol(pat,&ptr,10);
-				if (*ptr != '-')
-					exit(31);
-				t3 = zstrtol(ptr+1,&pat,10);
-				if (!t3)
-					t3 = INT_MAX;
-				if (*pat++ != Outang)
-					exit(21);
-				if (t1 < t2 || t1 > t3)
-					break;
-				}
-			continue;
-			}
-		if (*str == *pat)
-			{
-			str++;
-			pat++;
-			continue;
-			}
-		break;
-		}
-	return 0;
-}
-
-static char *pptr;
-
-qath parsepat(char *str)
-{
-	mode = 0;
-	pptr = str;
-	return parseqath();
-}
-
-comp parsereg(char *str)
-{
-	mode = 1;
-	pptr = str;
-	return parsecompsw();
-}
-
-qath parseqath(void)
-{
-comp c1;
-qath p1;
-
-	if (pptr[0] == '.' && pptr[1] == '.' && pptr[2] == '.' && pptr[3] ==
-			'.' && pptr[4] == '/')
-		{
-		pptr[0] = Inpar;
-		pptr[1] = Star;
-		pptr[2] = '/';
-		pptr[3] = Outpar;
-		pptr[4] = Pound;	/* "..../" -> "( * /)#" */
-		}
-	if (*pptr == Inpar)
-		{
-		char *str;
-		int pars = 1;
-
-		for (str = pptr+1; *str && pars; str++)
-			if (*str == Inpar)
-				pars++;
-			else if (*str == Outpar)
-				pars--;
-		if (str[0] != Pound || str[-1] != Outpar || str[-2] != '/')
-			goto kludge;
-		pptr++;
-		if (!(c1 = parsecompsw()))
-			return NULL;
-		if (pptr[0] == '/' && pptr[1] == Outpar && pptr[2] == Pound)
-			{
-			int pdflag = 0;
-
-			pptr += 3;
-			if (*pptr == Pound)
-				{
-				pdflag = 1;
-				pptr++;
-				}
-			p1 = (qath) alloc(sizeof(struct xpath));
-			p1->comp = c1;
-			p1->closure = 1+pdflag;
-			p1->next = parseqath();
-			return (p1->comp) ? p1 : NULL;
-			}
-		}
-	else
-		{
-kludge:
-		if (!(c1 = parsecompsw()))
-			return NULL;
-		if (*pptr == '/' || !*pptr)
-			{
-			int ef = *pptr == '/';
-
-			p1 = (qath) alloc(sizeof(struct xpath));
-			p1->comp = c1;
-			p1->closure = 0;
-			p1->next = (*pptr == '/') ? (pptr++,parseqath()) : NULL;
-			return (ef && !p1->next) ? NULL : p1;
-			}
-		}
-	magicerr();
-	errflag = 1;
-	return NULL;
-}
-
-comp parsecomp(void)
-{
-comp c = (comp) alloc(sizeof(struct xcomp)),c1,c2;
-char *s = c->str = alloc(MAXPATHLEN*2),*ls = NULL;
-
-	c->nx2 = NULL;
-	while (*pptr && (mode || *pptr != '/') && *pptr != Bar &&
-			*pptr != Outpar)
-		{
-		if (*pptr == Hat)
-			{
-			*s++ = Hat;
-			*s++ = '\0';
-			pptr++;
-			if (!(c->nx1 = parsecomp()))
-				{
-				free(c->str);
-				free(c);
-				return NULL;
-				}
-			return c;
-			}
-		if (*pptr == Star && pptr[1] && (mode || pptr[1] != '/'))
-			{
-			*s++ = '\0';
-			pptr++;
-			c->nx1 = c1 = (comp) alloc(sizeof(struct xcomp));
-			*((c1->nx1 = c1)->str = strdup("?")) = Quest;
-			c->nx2 = c1->nx2 = parsecomp();
-			return (c->nx2) ? c : NULL;
-			}
-		if (*pptr == Inpar)
-			{
-			*s++ = '\0';
-			pptr++;
-			c->nx1 = c1 = parsecompsw();
-			if (*pptr != Outpar)
-				{
-				errflag = 1;
-				free(c);
-				free(c->str);
-				return NULL;
-				}
-			pptr++;
-			if (*pptr == Pound)
-				{
-				int dpnd = 0;
-
-				pptr++;
-				if (*pptr == Pound)
-					{
-					pptr++;
-					dpnd = 1;
-					}
-				c2 = parsecomp();
-				if (dpnd)
-					c->nx2 = NULL;
-				else
-					c->nx2 = c2;
-				if (!c2)
-					{
-					free(c);
-					free(c->str);
-					return NULL;
-					}
-				adjustcomp(c1,c2,c1);
-				return c;
-				}
-			c2 = parsecomp();
-			if (!c2)
-				{
-				free(c);
-				free(c->str);
-				return NULL;
-				}
-			adjustcomp(c1,c2,NULL);
-			return c;
-			}
-		if (*pptr == Pound)
-			{
-			int dpnd = 0;
-
-			*s = '\0';
-			pptr++;
-			if (*pptr == Pound)
-				{
-				pptr++;
-				dpnd = 1;
-				}
-			if (!ls)
-				return NULL;
-			c->nx1 = c1 = (comp) alloc(sizeof(struct xcomp));
-			(c1->nx2 = c1)->str = strdup(ls);
-			c->nx2 = c1->nx1 = parsecomp();
-			if (!c->nx2)
-				{
-				free(c);
-				free(c->str);
-				return NULL;
-				}
-			if (dpnd)
-				c->nx2 = NULL;
-			*ls++ = '\0';
-			return c;
-			}
-		ls = s;
-		if (*pptr == Inang)
-			{
-			int dshct;
-
-			dshct = (pptr[1] == Outang);
-			*s++ = *pptr++;
-			while (*pptr && (*s++ = *pptr++) != Outang)
-				if (s[-1] == '-')
-					dshct++;
-				else if (!isdigit(s[-1]))
-					break;
-			if (s[-1] != Outang || dshct != 1)
-				{
-				free(c);
-				free(c->str);
-				return NULL;
-				}
-			}
-		else if (*pptr == Inbrack)
-			{
-			while (*pptr && (*s++ = *pptr++) != Outbrack);
-			if (s[-1] != Outbrack)
-				{
-				free(c);
-				free(c->str);
-				return NULL;
-				}
-			}
-		else if (istok(*pptr) && *pptr != Star && *pptr != Quest)
-			*s++ = tokens[*pptr++-Pound];
-		else
-			*s++ = *pptr++;
-		}
-	*s++ = '\0';
-	c->nx1 = NULL;
-	return c;
-}
-
-comp parsecompsw(void)
-{
-comp c1,c2,c3;
-
-	c1 = parsecomp();
-	if (!c1)
-		return NULL;
-	if (*pptr == Bar)
-		{
-		c2 = (comp) alloc(sizeof(struct xcomp));
-		pptr++;
-		c3 = parsecompsw();
-		if (!c3)
-			return NULL;
-		c2->str = strdup("");
-		c2->nx1 = c1;
-		c2->nx2 = c3;
-		return c2;
-		}
-	return c1;
-}
-
-#define MARKER ((void *) 1L)
-
-void adjustcomp(comp c1,comp c2,comp c3)
-{
-comp z;
-
-	if (c1->nx1 == c2 && c1->nx2 == c3)
-		return;
-	if (c1->nx1)
-		{
-		if ((z = c1->nx1) == MARKER)
-			return;
-		c1->nx1 = MARKER;
-		adjustcomp(z,c2,c3);
-		c1->nx1 = z;
-		}
-	if (c1->nx2)
-		adjustcomp(c1->nx2,c2,c3);
-	if (!(c1->nx1 || c1->nx2))
-		{
-		c1->nx1 = c2;
-		c1->nx2 = c3;
-		}
-}
-
-void freepath(qath p)
-{
-	if (p)
-		{
-		freepath(p->next);
-		freecomp(p->comp);
-		free(p);
-		}
-}
-
-void freecomp(comp c)
-{
-	if (c && c->str)
-		{
-		free(c->str);
-		c->str = NULL;
-		freecomp(c->nx1);
-		freecomp(c->nx2);
-		free(c);
-		}
-}
-
-/* tokenize and see if ss matches tt */
-
-int patmatch(char *ss,char *tt)
-{
-char *s = ss,*t;
-
-	for (; *s; s++)
-		if (*s == '\\')
-			chuck(s);
-		else
-			for (t = tokens; *t; t++)
-				if (*t == *s)
-					{
-					*s = (t-tokens)+Pound;
-					break;
-					}
-	return matchpat(ss,tt);
-}
-
-/* remove unnecessary Nulargs */
-
-void remnulargs(char *s)
-{
-int nl = *s;
-char *t = s;
-
-	while (*s)
-		if (*s == Nularg)
-			chuck(s);
-		else
-			s++;
-	if (!*t && nl)
-		{
-		t[0] = Nularg;
-		t[1] = '\0';
-		}
-}
-
End of glob.c
echo glob.pro 1>&2
sed 's/^-//' >glob.pro <<'End of glob.pro'
-void glob(table list,Node *np);
-int notstrcmp(char **a,char **b);
-void insert(char *s);
-int haswilds(char *str);
-int hasbraces(char *str);
-int xpandredir(struct fnode *fn,table tab);
-char *dyncat(char *s1,char *s2);
-char *tricat(char *s1,char *s2,char *s3);
-void xpandbraces(table list,Node *np);
-char *getparen(char *str);
-int matchpat(char *a,char *b);
-void getmatch(char **sp,char *pat,int dd);
-void addpath(char *s);
-void scanner(qath q);
-int minimatch(char **pat,char **str);
-int doesmatch(char *str,comp c,int first);
-qath parsepat(char *str);
-comp parsereg(char *str);
-qath parseqath(void);
-comp parsecomp(void);
-comp parsecompsw(void);
-void adjustcomp(comp c1,comp c2,comp c3);
-void freepath(qath p);
-void freecomp(comp c);
-int patmatch(char *ss,char *tt);
-void remnulargs(char *s);
End of glob.pro
echo hist.c 1>&2
sed 's/^-//' >hist.c <<'End of hist.c'
-/*
-
-	hist.c - ! history	
-
-	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"
-
-int lastc;
-
-/* add a character to the current history word */
-
-void hwaddc(int c)
-{
-	if (hlastw)
-		{
-		if (c == EOF || c == HERR)
-			return;
-		*hlastp++ = c;
-		if (hlastp-hlastw == hlastsz)
-			{
-			hlastw = realloc(hlastw,hlastsz *= 2);
-			hlastp = hlastw+(hlastsz/2);
-			}
-		}
-}
-
-#define habort() { errflag = 1; return HERR; }
-
-/* get a character after performing history substitution */
-
-int hgetc(void)
-{
-int c,ev,farg,larg,argc,marg = -1,cflag = 0,bflag = 0;
-char buf[256],*ptr;
-table slist,elist;
-
-tailrec:
-	c = hgetch();
-	if (stophist)
-		{
-		hwaddc(c);
-		return c;
-		}
-	if (firstch && c == '^' && !(ungots && !magic))
-		{
-		firstch = 0;
-		hungets(strdup(":s^"));
-		c = '!';
-		goto hatskip;
-		}
-	if (c != ' ')
-		firstch = 0;
-	if (c == '\\')
-		{
-		int g = hgetch();
-		
-		if (g != '!')
-			hungetch(g);
-		else
-			{
-			hwaddc('!');
-			return '!';
-			}
-		}
-	if (c != '!' || (ungots && !magic))
-		{
-		hwaddc(c);
-		return c;
-		}
-hatskip:
-	if ((c = hgetch()) == '{')
-		{
-			bflag = cflag = 1;
-			c = hgetch();
-			}
-		if (c == '\"')
-			{
-			stophist = 1;
-			goto tailrec;
-			}
-		if (!cflag && znspace(c) || c == '=' || c == '(')
-			{
-			hungetch(c);
-			hwaddc('!');
-			return '!';
-			}
-		cflag = 0;
-		ptr = buf;
-
-		/* get event number */
-
-		if (c == '?')
-			{
-			FOREVER
-				{
-				c = hgetch();
-				if (c == '?' || c == '\n')
-					break;
-				else
-					*ptr++ = c;
-				}
-			if (c != '\n')
-				c = hgetch();
-			*ptr = NULL;
-			ev = hconsearch(last = strdup(buf),&marg);
-			if (ev == -1)
-				{
-				herrflush();
-				zerr("no such event: %s",buf);
-				habort();
-				}
-			}
-		else
-			{
-			int t0;
-	 
-			FOREVER
-				{
-				if (znspace(c) || c == ':' || c == '^' || c == '$' || c == '*'
-						|| c == '%' || c == '}')
-					break;
-				if (ptr != buf && c == '-')
-					break;
-				*ptr++ = c;
-				if (c == '#' || c == '!')
-					{
-					c = hgetch();
-					break;
-					}
-				c = hgetch();
-				}
-			*ptr = 0;
-			if (!*buf)
-				ev = dev;
-			else if (t0 = atoi(buf))
-				ev = (t0 < 0) ? cev+t0 : t0;
-			else if (*buf == '!')
-				ev = cev-1;
-			else if (*buf == '#')
-				ev = cev;
-			else if ((ev = hcomsearch(buf)) == -1)
-				{
-				zerr("event not found: %s",buf);
-				while (c != '\n')
-					c = hgetch();
-				habort();
-				}
-			}
-
-		/* get the event */
-
-		if (!(elist = getevent(dev = ev)))
-			habort();
-
-		/* extract the relevant arguments */
-
-		argc = getargc(elist)-1;
-		if (c == ':')
-			{
-			cflag = 1;
-			c = hgetch();
-			}
-		if (c == '*')
-			{
-			farg = 1;
-			larg = argc;
-			cflag = 0;
-			}
-		else
-			{
-			hungetch(c);
-			larg = farg = getargspec(argc,marg);
-			if (larg == -2)
-				habort();
-			if (farg != -1)
-				cflag = 0;
-			c = hgetch();
-			if (c == '*')
-				{
-				cflag = 0;
-				larg = argc;
-				}
-			else if (c == '-')
-				{
-				cflag = 0;
-				larg = getargspec(argc,marg);
-				if (larg == -2)
-					habort();
-				if (larg == -1)
-					larg = argc-1;
-				}
-			else
-				hungetch(c);
-			}
-		if (farg == -1)
-			farg = 0;
-		if (larg == -1)
-			larg = argc;
-		if (!(slist = getargs(elist,farg,larg)))
-			habort();
-
-		/* do the modifiers */
-
-		FOREVER
-			{
-			c = (cflag) ? ':' : hgetch();
-			cflag = 0;
-			if (c == ':')
-				{
-				int gbal = 0;
-			
-				if ((c = hgetch()) == 'g')
-					{
-					gbal = 1;
-					c = hgetch();
-					}
-				switch(c)
-					{
-					case 'p':
-						hflag = 2;
-						break;
-					case 'h':
-						if (!apply1(gbal,remtpath,slist))
-							{
-							herrflush();
-							zerr("modifier failed: h");
-							habort();
-							}
-						break;
-					case 'e':
-						if (!apply1(gbal,rembutext,slist))
-							{
-							herrflush();
-							zerr("modifier failed: e");
-							habort();
-							}
-						break;
-					case 'r':
-						if (!apply1(gbal,remtext,slist))
-							{
-							herrflush();
-							zerr("modifier failed: r");
-							habort();
-							}
-						break;
-					case 't':
-						if (!apply1(gbal,remlpaths,slist))
-							{
-							herrflush();
-							zerr("modifier failed: t");
-							habort();
-							}
-						break;
-					case 's':
-						{
-						int del;
-						char *ptr1,*ptr2;
-					
-						del = hgetch();
-						ptr1 = hdynread(del);
-						if (!ptr1)
-							habort();
-						ptr2 = hdynread2(del);
-						if (strlen(ptr1))
-							{
-							if (last)
-								free(last);
-							last = ptr1;
-							}
-						if (rast)
-							free(rast);
-						rast = ptr2;
-						}
-					case '&':
-						if (last && rast)
-							{
-							if (subst(gbal,slist,last,rast))
-								habort();
-							}
-						else
-							{
-							herrflush();
-							zerr("no previous substitution with &");
-							habort();
-							}
-						break;
-					case 'q':
-						apply1(0,quote,slist);
-						break;
-					case 'x':
-						apply1(0,quotebreak,slist);
-						break;
-					default:
-						herrflush();
-						zerr("illegal modifier: %c",c);
-					habort();
-					break;
-				}
-			}
-		else
-			{
-			if (c != '}' || !bflag)
-				hungetch(c);
-			if (c != '}' && bflag)
-				{
-				zerr("'}' expected");
-				habort();
-				}
-			break;
-			}
-		}
-	
-	/* stuff the resulting string in the input queue and start over */
-
-	hungets(makehlist(slist,1));
-	hflag |= 1;
-	goto tailrec;
-}
-
-/* begin reading a string */
-
-void strinbeg(void)
-{
-	strin = 1;
-}
-
-/* done reading a string */
-
-void strinend(void)
-{
-	strin = 0;
-	firstch = 1;
-	hflag = 0;
-	free(ungots);
-	ungotptr = ungots = NULL;
-	peek = EMPTY;
-}
-
-static char *line = NULL,*oline = NULL;
-
-/* stuff a whole FILE into the input queue */
-
-int stuff(char *fn)
-{
-FILE *in;
-char *buf;
-int len;
-
-	if (!(in = fopen(fn,"r")))
-		{
-		zerr("can't open %s",fn);
-		return 1;
-		}
-	fseek(in,0,2);
-	len = ftell(in);
-	fseek(in,0,0);
-	buf = alloc(len+1);
-	if (!(fread(buf,len,1,in)))
-		{
-		zerr("read error on %s",fn);
-		fclose(fn);
-		free(buf);
-		return 1;
-		}
-	fclose(in);
-	if (!line)
-		line = oline = buf;
-	else
-		{
-		line = dyncat(line,buf);
-		free(oline);
-		oline = line;
-		}
-	return 0;
-}
-
-/* get a char without history */
-
-int hgetch(void)
-{
-char *pmpt = NULL,*s;
-
-	if (ungots)
-		{
-		if (*ungotptr)
-			{
-			if (*ungotptr == ALPOP)	/* done expanding an alias,
-												pop the alias stack */
-				{
-				if (!alix)
-					{
-					ungotptr++;
-					return lastc = HERR;
-					}
-				alstack[--alix]->inuse = 0;
-				s = alstack[alix]->text;
-				if (*s && s[strlen(s)-1] == ' ')
-					alstat = ALSTAT_MORE;
-				else
-					alstat = ALSTAT_JUNK;
-				ungotptr++;
-				return lastc = hgetch();
-				}
-			return lastc = *ungotptr++;
-			}
-		if (strin)
-			return lastc = EOF;
-		ungotptr = 0;
-		free(ungots);
-		ungots = NULL;
-		}
-kludge:
-	if (errflag)
-		{
-		if (oline)
-			free(oline);
-		oline = line = NULL;
-		return lastc = HERR;
-		}
-	if (line && *line)
-		return lastc = (*line++);
-	if (line)
-		free(oline);
-	if (interact)
-		if (!firstln)
-			pmpt = putprompt("PROMPT2");
-		else
-			pmpt = putprompt("PROMPT");
-	if (interact && SHTTY == -1)
-		write(2,pmpt,strlen(pmpt));
-	oline = line = (interact && SHTTY != -1) ? readline(pmpt) : 
-		fgets(zalloc(256),256,bshin);
-	if (isset(VERBOSE) && line)
-		fputs(line,stderr);
-	if (!line)
-		return lastc = EOF;
-	if (line[strlen(line)-1] == '\n')
-		lineno++;
-	firstch = 1;
-	firstln = 0;
-	goto kludge;
-}
-
-/* unget a character */
-
-void hungetch(int c)
-{
-static char ubuf2[] = {'x',0};
-
-	if (c == EOF)
-		return;
-	ubuf2[0] = c;
-	hungets(strdup(ubuf2));
-}
-
-/* unget a character and remove it from the history word */
-
-void hungetc(int c)
-{
-	if (hlastw)
-		{
-		if (hlastw == hlastp)
-			zerr("hungetc attempted at buffer start");
-		else
-			hlastp--;
-		}
-	hungetch(c);
-}
-
-void hflush(void)
-{
-	if (ungots)
-		free(ungots);
-	ungots = ungotptr = NULL;
-}
-
-/* unget a string into the input queue */
-
-void hungets(char *str)
-{
-	if (ungots && !*ungotptr)
-		{
-		free(ungots);
-		ungots = NULL;
-		}
-	if (ungots)
-		{
-		char *ptr;
-		
-		ptr = dyncat(str,ungotptr);
-		free(ungots);
-		free(str);
-		ungotptr = ungots = ptr;
-		}
-	else
-		ungots = ungotptr = str;
-}
-
-/* initialize the history mechanism */
-
-void hbegin(void)
-{
-	firstln = firstch = 1;
-	histremmed = errflag = hflag = 0;
-	stophist = isset(NOBANGHIST);
-	if (interact)
-		{
-		inittty();
-		dev = cev++;
-		while (cev-tfev >= tevs)
-			{
-			freetable(getnode(histlist),freestr);
-			tfev++;
-			}
-		addnode(histlist,curtab = newtable());
-		}
-}
-
-void inittty(void)
-{
-	attachtty(shpgrp);
-	settyinfo(&shttyinfo);
-}
-
-/* say we're done using the history mechanism */
-
-int hend(void)
-{
-char *ptr;
-int flag;
-
-	if (!interact)
-		return 1;
-	if (!curtab)
-		return 0;
-	flag = hflag;
-	hflag = 0;
-	if (curtab->first && (*(char *) curtab->last->dat == '\n'))
-		free(remnode(curtab,curtab->last));
-	if (!curtab->first)
-		{
-		freetable(remnode(histlist,histlist->last),freestr);
-		cev--;
-		flag = 0;
-		}
-	if (flag)
-		{
-		fprintf(stderr,"%s\n",ptr = makehlist(curtab,0));
-		free(ptr);
-		}
-	curtab = NULL;
-	return !(flag & 2 || errflag);
-}
-
-/* remove the current line from the history list */
-
-void remhist(void)
-{
-	if (!interact)
-		return;
-	if (!histremmed)
-		{
-		histremmed = 1;
-		freetable(remnode(histlist,histlist->last),freestr);
-		cev--;
-		}
-}
-
-/* begin a word */
-
-void hwbegin(void)
-{
-	if (hlastw)
-		free(hlastw);
-	hlastw = hlastp = zalloc(hlastsz = 32);
-}
-
-/* add a word to the history list */
-
-char *hwadd(void)
-{
-char *ret = hlastw;
-
-	if (hlastw)
-		*hlastp = '\0';
-	if (hlastw && lastc != EOF && !errflag)
-		if (curtab && !alix/* && alstat != ALSTAT_JUNK*/)
-			{
-			addnode(curtab,hlastw);
-			hlastw = NULL;
-			}
-	if (alstat == ALSTAT_JUNK)
-		alstat = 0;
-	return ret;
-}
-
-/* get an argument specification */
-
-int getargspec(int argc,int marg)
-{
-int c,ret = -1;
- 
-	if ((c = hgetch()) == '0')
-		return 0;
-	if (isdigit(c))
-		{
-		ret = 0;
-		while (isdigit(c))
-			{
-			ret = ret*10+c-'0';
-			c = hgetch();
-			}
-		hungetch(c);
-		}
-	else if (c == '^')
-		ret = 1;
-	else if (c == '$')
-		ret = argc;
-	else if (c == '%')
-		{
-		if (marg == -1)
-			{
-			herrflush();
-			zerr("%% with no previous word matched");
-			return -2;
-			}
-		ret = marg;
-		}
-	else
-		hungetch(c);
-	return ret;
-}
-
-/* do ?foo? search */
-
-int hconsearch(char *str,int *marg)
-{
-int t0,t1;
-Node node,node2;
- 
-	if (cev-tfev < 1)
-		return -1;
-	for (t0 = cev-1,node = histlist->last->last;
-			t0 >= tfev; t0--,node = node->last)
-		for (t1 = 0,node2 = ((table) node->dat)->first; node2; t1++,node2 =
-				node2->next)
-			if (strstr(node2->dat,str))
-				{
-				*marg = t1;
-				return t0;
-				}
-	return -1;
-}
-
-/* do !foo search */
-
-int hcomsearch(char *str)
-{
-int t0;
-Node node,node2;
- 
-	if (cev-tfev < 1)
-		return -1;
-	for (t0 = cev-1,node = histlist->last->last; t0 >= tfev;
-			t0--,node = node->last)
-		if ((node2 = ((table) node->dat)->first)->dat &&
-				strstr(node2->dat,str))
-			return t0;
-	return -1;
-}
-
-/* apply func to a list */
-
-int apply1(int gflag,int (*func)(void **),table list)
-{
-Node node;
-int flag = 0;
- 
-	for (node = list->first; node; node = node->next)
-		if ((flag |= func(&node->dat)) && !gflag)
-			return 1;
-	return flag;
-}
-
-/* various utilities for : modifiers */
-
-int remtpath(void **junkptr)
-{
-char *str = *junkptr,*cut;
- 
-	if (cut = strrchr(str,'/'))
-		{
-		*cut = NULL;
-		return 1;
-		}
-	return 0;
-}
- 
-int remtext(void **junkptr)
-{
-char *str = *junkptr,*cut;
- 
-	if ((cut = strrchr(str,'.')) && cut != str)
-		{
-		*cut = NULL;
-		return 1;
-		}
-	return 0;
-}
- 
-int rembutext(void **junkptr)
-{
-char *str = *junkptr,*cut;
- 
-	if ((cut = strrchr(str,'.')) && cut != str)
-		{
-		*junkptr = strdup(cut+1);  /* .xx or xx? */
-		free(str);
-		return 1;
-		}
-	return 0;
-}
- 
-int remlpaths(void **junkptr)
-{
-char *str = *junkptr,*cut;
- 
-	if (cut = strrchr(str,'/'))
-		{
-		*cut = NULL;
-		*junkptr = strdup(cut+1);
-		free(str);
-		return 1;
-		}
-	return 0;
-}
- 
-int subst(int gbal,table slist,char *ptr1,char *ptr2)
-{
-Node node;
-int iflag = 0;
- 
-	for (node = slist->first; node; )
-		if (subststr(&node->dat,ptr1,ptr2,gbal))
-			{
-			iflag = 1;
-			if (!gbal)
-				return 0;
-			}
-		else
-			node = node->next;
-	if (!iflag)
-		{
-		herrflush();
-		zerr("string not found: %s",ptr1);
-		return 1;
-		}
-	return 0;
-}
- 
-int subststr(void **strptr,char *in,char *out,int gbal)
-{
-char *str = *strptr,*cut,*sptr,*ss;
-int ret = 0;
-
-maze:
-	if (cut = (char *) strstr(str,in))
-		{
-		char *incop;
-		
-		incop = strdup(in);
-		*cut = '\0';
-		cut += strlen(in);
-		ss = *strptr;
-		*strptr = tricat(*strptr,sptr = convamps(out,incop),cut);
-		free(ss);
-		free(sptr);
-		free(incop);
-		if (gbal)
-			{
-			str = (char *) *strptr+(cut-str)+strlen(in);
-			ret = 1;
-			goto maze;
-			}
-		return 1;
-		}
-	return ret;
-}
- 
-char *convamps(char *out,char *in)
-{
-char *ptr,*ret,*pp;
-int slen,inlen = strlen(in);
- 
-	for (ptr = out, slen = 0; *ptr; ptr++,slen++)
-		if (*ptr == '\\')
-			ptr++;
-		else if (*ptr == '&')
-			slen += inlen-1;
-	ret = pp = zalloc(slen+1);
-	for (ptr = out; *ptr; ptr++)
-		if (*ptr == '\\')
-			*pp++ = *++ptr;
-		else if (*ptr == '&')
-			{
-			strcpy(pp,in);
-			pp += inlen;
-			}
-		else
-			*pp++ = *ptr;
-	*pp = '\0';
-	return ret;
-}
-
-/* make a string out of a history list */
-
-char *makehlist(table tab,int freeit)
-{
-int ccnt;
-Node node;
-char *ret,*ptr;
-char sep = *ifs;
-
-	for (ccnt = 0, node = (freeit == 2) ? tab->first->next : tab->first;
-			node; node = node->next)
-		ccnt += strlen(node->dat)+1;
-	if (!ccnt)
-		return strdup("");
-	ptr = ret = zalloc(ccnt);
-	for (node = (freeit == 2) ? tab->first->next : tab->first;
-			node; node = node->next)
-		{
-		strcpy(ptr,node->dat);
-		ptr += strlen(node->dat);
-		if (freeit == 1)
-			free(node->dat);
-		*ptr++ = sep;
-		}
-	*--ptr = '\0';
-	return ret;
-}
-
-table quietgetevent(int ev)
-{
-Node node;
- 
-	ev -= tfev;
-	for (node = histlist->first; ev && node; node = node->next, ev--);
-	if (ev)
-		return NULL;
-	return node->dat;
-}
-
-table getevent(int ev)
-{
-Node node;
-int oev = ev;
- 
-	ev -= tfev;
-	for (node = histlist->first; ev && node; node = node->next, ev--);
-	if (ev || !node)
-		{
-		herrflush();
-		zerr("no such event: %d",oev);
-		return NULL;
-		}
-	return node->dat;
-}
- 
-int getargc(table tab)
-{
-int argc;
-Node node;
- 
-	for (argc = 0, node = tab->first; node; node = node->next, argc++);
-	return argc;
-}
- 
-table getargs(table elist,int arg1,int arg2)
-{
-table ret = newtable();
-Node node;
-int oarg1 = arg1,oarg2 = arg2;
- 
-	for (node = elist->first; arg1 && node; node = node->next, arg1--,arg2--);
-	if (!node)
-		{
-		herrflush();
-		zerr("no such word in event: %d",oarg1);
-		return NULL;
-		}
-	for (arg2++; arg2 && node; node = node->next, arg2--)
-		addnode(ret,strdup(node->dat));
-	if (arg2 && !node)
-		{
-		herrflush();
-		zerr("no such word in event: %d",oarg2);
-		return NULL;
-		}
-	return ret;
-}
-
-int quote(void **tr)
-{
-char *ptr,*rptr,**str = (char **) tr;
-int len = 1;
- 
-	for (ptr = *str; *ptr; ptr++,len++)
-		if (*ptr == '\'')
-			len += 3;
-	ptr = *str;
-	*str = rptr = alloc(len);
-	for (ptr = *str; *ptr; )
-		if (*ptr == '\'')
-			{
-			*rptr++ = '\'';
-			*rptr++ = '\\';
-			*rptr++ = '\'';
-			*rptr++ = '\'';
-			ptr++;
-			}
-		else
-			*rptr++ = *ptr++;
-	return 0;
-}
- 
-int quotebreak(void **tr)
-{
-char *ptr,*rptr,**str = (char **) tr;
-int len = 1;
- 
-	for (ptr = *str; *ptr; ptr++,len++)
-		if (*ptr == '\'')
-			len += 3;
-		else if (znspace(*ptr))
-			len += 2;
-	ptr = *str;
-	*str = rptr = alloc(len);
-	for (ptr = *str; *ptr; )
-		if (*ptr == '\'')
-			{
-			*rptr++ = '\'';
-			*rptr++ = '\\';
-			*rptr++ = '\'';
-			*rptr++ = '\'';
-			ptr++;
-			}
-		else if (znspace(*ptr))
-			{
-			*rptr++ = '\'';
-			*rptr++ = *ptr++;
-			*rptr++ = '\'';
-			}
-		else
-			*rptr++ = *ptr++;
-	return 0;
-}
-
-void stradd(char **p,char *d)
-{
-char *s = *p;
-
-	while (*s++ = *d++);
-	*p = s-1;
-}
-
-/* get a prompt string */
-
-char *putprompt(char *fm)
-{
-char *ss,*ttyname(int);
-static char buf[256];
-char *bp = buf;
-int t0;
-struct tm *tm = NULL;
-time_t timet;
-
-	clearerr(stdin);
-	fm = getparm(fm);
-	for(;*fm;fm++)
-		{
-		if (bp-buf >= 220)
-			break;
-		if (*fm == '%')
-			switch (*++fm)
-				{
-				case '~':
-					if (!strncmp(cwd,home,t0 = strlen(home)))
-						{
-						*bp++ = '~';
-						stradd(&bp,cwd+t0);
-						break;
-						}
-				case 'd':
-				case '/':
-					stradd(&bp,cwd);
-					break;
-				case 'c':
-				case '.':
-					for (ss = cwd+strlen(cwd); ss > cwd; ss--)
-						if (*ss == '/')
-							{
-							ss++;
-							break;
-							}
-					stradd(&bp,ss);
-					break;
-				case 'h':
-				case '!':
-					sprintf(bp,"%d",cev);
-					bp += strlen(bp);
-					break;
---cut here---cut here---cut here---



More information about the Alt.sources mailing list