682 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			682 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
| #define Extern extern
 | |
| #include <sys/types.h>
 | |
| #include <signal.h>
 | |
| #include <errno.h>
 | |
| #include <setjmp.h>
 | |
| #include "sh.h"
 | |
| 
 | |
| /* -------- io.c -------- */
 | |
| /* #include "sh.h" */
 | |
| 
 | |
| /*
 | |
|  * shell IO
 | |
|  */
 | |
| 
 | |
| static struct iobuf sharedbuf = {AFID_NOBUF};
 | |
| static struct iobuf mainbuf = {AFID_NOBUF};
 | |
| static unsigned bufid = AFID_ID;	/* buffer id counter */
 | |
| 
 | |
| struct ioarg temparg = {0, 0, 0, AFID_NOBUF, 0};
 | |
| 
 | |
| _PROTOTYPE(static void readhere, (char **name, char *s, int ec ));
 | |
| _PROTOTYPE(void pushio, (struct ioarg *argp, int (*fn)()));
 | |
| _PROTOTYPE(static int xxchar, (struct ioarg *ap ));
 | |
| _PROTOTYPE(void tempname, (char *tname ));
 | |
| 
 | |
| int
 | |
| getc(ec)
 | |
| register int ec;
 | |
| {
 | |
| 	register int c;
 | |
| 
 | |
| 	if(e.linep > elinep) {
 | |
| 		while((c=readc()) != '\n' && c)
 | |
| 			;
 | |
| 		err("input line too long");
 | |
| 		gflg++;
 | |
| 		return(c);
 | |
| 	}
 | |
| 	c = readc();
 | |
|  	if (ec != '\'' && e.iop->task != XGRAVE) {
 | |
| 		if(c == '\\') {
 | |
| 			c = readc();
 | |
| 			if (c == '\n' && ec != '\"')
 | |
| 				return(getc(ec));
 | |
| 			c |= QUOTE;
 | |
| 		}
 | |
| 	}
 | |
| 	return(c);
 | |
| }
 | |
| 
 | |
| void
 | |
| unget(c)
 | |
| int c;
 | |
| {
 | |
| 	if (e.iop >= e.iobase)
 | |
| 		e.iop->peekc = c;
 | |
| }
 | |
| 
 | |
| int
 | |
| eofc()
 | |
| 
 | |
| {
 | |
|   return e.iop < e.iobase || (e.iop->peekc == 0 && e.iop->prev == 0);
 | |
| }
 | |
| 
 | |
| int
 | |
| readc()
 | |
| {
 | |
| 	register c;
 | |
| 
 | |
| 	for (; e.iop >= e.iobase; e.iop--)
 | |
| 		if ((c = e.iop->peekc) != '\0') {
 | |
| 			e.iop->peekc = 0;
 | |
| 			return(c);
 | |
| 		}
 | |
| 		else {
 | |
| 		    if (e.iop->prev != 0) {
 | |
| 		        if ((c = (*e.iop->iofn)(e.iop->argp, e.iop)) != '\0') {
 | |
| 			        if (c == -1) {
 | |
| 				        e.iop++;
 | |
| 				        continue;
 | |
| 			        }
 | |
| 			        if (e.iop == iostack)
 | |
| 				        ioecho(c);
 | |
| 			        return(e.iop->prev = c);
 | |
| 		        }
 | |
| 		        else if (e.iop->task == XIO && e.iop->prev != '\n') {
 | |
| 			        e.iop->prev = 0;
 | |
| 				if (e.iop == iostack)
 | |
| 					ioecho('\n');
 | |
| 			        return '\n';
 | |
| 		        }
 | |
| 		    }
 | |
| 		    if (e.iop->task == XIO) {
 | |
| 			if (multiline)
 | |
| 			    return e.iop->prev = 0;
 | |
| 			if (talking && e.iop == iostack+1)
 | |
| 			    prs(prompt->value);
 | |
| 		    }
 | |
| 		}
 | |
| 	if (e.iop >= iostack)
 | |
| 		return(0);
 | |
| 	leave();
 | |
| 	/* NOTREACHED */
 | |
| }
 | |
| 
 | |
| void
 | |
| ioecho(c)
 | |
| char c;
 | |
| {
 | |
| 	if (flag['v'])
 | |
| 		write(2, &c, sizeof c);
 | |
| }
 | |
| 
 | |
| void
 | |
| pushio(argp, fn)
 | |
| struct ioarg *argp;
 | |
| int (*fn)();
 | |
| {
 | |
| 	if (++e.iop >= &iostack[NPUSH]) {
 | |
| 		e.iop--;
 | |
| 		err("Shell input nested too deeply");
 | |
| 		gflg++;
 | |
| 		return;
 | |
| 	}
 | |
| 	e.iop->iofn = fn;
 | |
| 
 | |
| 	if (argp->afid != AFID_NOBUF)
 | |
| 	  e.iop->argp = argp;
 | |
| 	else {
 | |
| 	  e.iop->argp  = ioargstack + (e.iop - iostack);
 | |
| 	  *e.iop->argp = *argp;
 | |
| 	  e.iop->argp->afbuf = e.iop == &iostack[0] ? &mainbuf : &sharedbuf;
 | |
| 	  if (isatty(e.iop->argp->afile) == 0 &&
 | |
| 	      (e.iop == &iostack[0] ||
 | |
| 	       lseek(e.iop->argp->afile, 0L, 1) != -1)) {
 | |
| 	    if (++bufid == AFID_NOBUF)
 | |
| 	      bufid = AFID_ID;
 | |
| 	    e.iop->argp->afid  = bufid;
 | |
| 	  }
 | |
| 	}
 | |
| 
 | |
| 	e.iop->prev  = ~'\n';
 | |
| 	e.iop->peekc = 0;
 | |
| 	e.iop->xchar = 0;
 | |
| 	e.iop->nlcount = 0;
 | |
| 	if (fn == filechar || fn == linechar)
 | |
| 		e.iop->task = XIO;
 | |
| 	else if (fn == gravechar || fn == qgravechar)
 | |
| 		e.iop->task = XGRAVE;
 | |
| 	else
 | |
| 		e.iop->task = XOTHER;
 | |
| }
 | |
| 
 | |
| struct io *
 | |
| setbase(ip)
 | |
| struct io *ip;
 | |
| {
 | |
| 	register struct io *xp;
 | |
| 
 | |
| 	xp = e.iobase;
 | |
| 	e.iobase = ip;
 | |
| 	return(xp);
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Input generating functions
 | |
|  */
 | |
| 
 | |
| /*
 | |
|  * Produce the characters of a string, then a newline, then EOF.
 | |
|  */
 | |
| int
 | |
| nlchar(ap)
 | |
| register struct ioarg *ap;
 | |
| {
 | |
| 	register int c;
 | |
| 
 | |
| 	if (ap->aword == NULL)
 | |
| 		return(0);
 | |
| 	if ((c = *ap->aword++) == 0) {
 | |
| 		ap->aword = NULL;
 | |
| 		return('\n');
 | |
| 	}
 | |
| 	return(c);
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Given a list of words, produce the characters
 | |
|  * in them, with a space after each word.
 | |
|  */
 | |
| int
 | |
| wdchar(ap)
 | |
| register struct ioarg *ap;
 | |
| {
 | |
| 	register char c;
 | |
| 	register char **wl;
 | |
| 
 | |
| 	if ((wl = ap->awordlist) == NULL)
 | |
| 		return(0);
 | |
| 	if (*wl != NULL) {
 | |
| 		if ((c = *(*wl)++) != 0)
 | |
| 			return(c & 0177);
 | |
| 		ap->awordlist++;
 | |
| 		return(' ');
 | |
| 	}
 | |
| 	ap->awordlist = NULL;
 | |
| 	return('\n');
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Return the characters of a list of words,
 | |
|  * producing a space between them.
 | |
|  */
 | |
| int
 | |
| dolchar(ap)
 | |
| register struct ioarg *ap;
 | |
| {
 | |
| 	register char *wp;
 | |
| 
 | |
| 	if ((wp = *ap->awordlist++) != NULL) {
 | |
| 		PUSHIO(aword, wp, *ap->awordlist == NULL? strchar: xxchar);
 | |
| 		return(-1);
 | |
| 	}
 | |
| 	return(0);
 | |
| }
 | |
| 
 | |
| static int
 | |
| xxchar(ap)
 | |
| register struct ioarg *ap;
 | |
| {
 | |
| 	register int c;
 | |
| 
 | |
| 	if (ap->aword == NULL)
 | |
| 		return(0);
 | |
| 	if ((c = *ap->aword++) == '\0') {
 | |
| 		ap->aword = NULL;
 | |
| 		return(' ');
 | |
| 	}
 | |
| 	return(c);
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Produce the characters from a single word (string).
 | |
|  */
 | |
| int
 | |
| strchar(ap)
 | |
| register struct ioarg *ap;
 | |
| {
 | |
| 	register int c;
 | |
| 
 | |
| 	if (ap->aword == NULL || (c = *ap->aword++) == 0)
 | |
| 		return(0);
 | |
| 	return(c);
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Produce quoted characters from a single word (string).
 | |
|  */
 | |
| int
 | |
| qstrchar(ap)
 | |
| register struct ioarg *ap;
 | |
| {
 | |
| 	register int c;
 | |
| 
 | |
| 	if (ap->aword == NULL || (c = *ap->aword++) == 0)
 | |
| 		return(0);
 | |
| 	return(c|QUOTE);
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Return the characters from a file.
 | |
|  */
 | |
| int
 | |
| filechar(ap)
 | |
| register struct ioarg *ap;
 | |
| {
 | |
| 	register int i;
 | |
| 	char c;
 | |
| 	struct iobuf *bp = ap->afbuf;
 | |
| 
 | |
| 	if (ap->afid != AFID_NOBUF) {
 | |
| 	  if ((i = ap->afid != bp->id) || bp->bufp == bp->ebufp) {
 | |
| 	    if (i)
 | |
| 	      lseek(ap->afile, ap->afpos, 0);
 | |
| 	    do {
 | |
| 	      i = read(ap->afile, bp->buf, sizeof(bp->buf));
 | |
| 	    } while (i < 0 && errno == EINTR);
 | |
| 	    if (i <= 0) {
 | |
| 	      closef(ap->afile);
 | |
| 	      return 0;
 | |
| 	    }
 | |
| 	    bp->id = ap->afid;
 | |
| 	    bp->ebufp = (bp->bufp  = bp->buf) + i;
 | |
| 	  }
 | |
| 	  ap->afpos++;
 | |
| 	  return *bp->bufp++ & 0177;
 | |
| 	}
 | |
| 
 | |
| 	do {
 | |
| 		i = read(ap->afile, &c, sizeof(c));
 | |
| 	} while (i < 0 && errno == EINTR);
 | |
| 	return(i == sizeof(c)? c&0177: (closef(ap->afile), 0));
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Return the characters from a here temp file.
 | |
|  */
 | |
| int
 | |
| herechar(ap)
 | |
| register struct ioarg *ap;
 | |
| {
 | |
| 	char c;
 | |
| 
 | |
| 
 | |
| 	if (read(ap->afile, &c, sizeof(c)) != sizeof(c)) {
 | |
| 		close(ap->afile);
 | |
| 		c = 0;
 | |
| 	}
 | |
| 	return (c);
 | |
| 
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Return the characters produced by a process (`...`).
 | |
|  * Quote them if required, and remove any trailing newline characters.
 | |
|  */
 | |
| int
 | |
| gravechar(ap, iop)
 | |
| struct ioarg *ap;
 | |
| struct io *iop;
 | |
| {
 | |
| 	register int c;
 | |
| 
 | |
| 	if ((c = qgravechar(ap, iop)&~QUOTE) == '\n')
 | |
| 		c = ' ';
 | |
| 	return(c);
 | |
| }
 | |
| 
 | |
| int
 | |
| qgravechar(ap, iop)
 | |
| register struct ioarg *ap;
 | |
| struct io *iop;
 | |
| {
 | |
| 	register int c;
 | |
| 
 | |
| 	if (iop->xchar) {
 | |
| 		if (iop->nlcount) {
 | |
| 			iop->nlcount--;
 | |
| 			return('\n'|QUOTE);
 | |
| 		}
 | |
| 		c = iop->xchar;
 | |
| 		iop->xchar = 0;
 | |
| 	} else if ((c = filechar(ap)) == '\n') {
 | |
| 		iop->nlcount = 1;
 | |
| 		while ((c = filechar(ap)) == '\n')
 | |
| 			iop->nlcount++;
 | |
| 		iop->xchar = c;
 | |
| 		if (c == 0)
 | |
| 			return(c);
 | |
| 		iop->nlcount--;
 | |
| 		c = '\n';
 | |
| 	}
 | |
| 	return(c!=0? c|QUOTE: 0);
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Return a single command (usually the first line) from a file.
 | |
|  */
 | |
| int
 | |
| linechar(ap)
 | |
| register struct ioarg *ap;
 | |
| {
 | |
| 	register int c;
 | |
| 
 | |
| 	if ((c = filechar(ap)) == '\n') {
 | |
| 		if (!multiline) {
 | |
| 			closef(ap->afile);
 | |
| 			ap->afile = -1;	/* illegal value */
 | |
| 		}
 | |
| 	}
 | |
| 	return(c);
 | |
| }
 | |
| 
 | |
| void
 | |
| prs(s)
 | |
| register char *s;
 | |
| {
 | |
| 	if (*s)
 | |
| 		write(2, s, strlen(s));
 | |
| }
 | |
| 
 | |
| void
 | |
| putc(c)
 | |
| char c;
 | |
| {
 | |
| 	write(2, &c, sizeof c);
 | |
| }
 | |
| 
 | |
| void
 | |
| prn(u)
 | |
| unsigned u;
 | |
| {
 | |
| 	prs(itoa(u, 0));
 | |
| }
 | |
| 
 | |
| void
 | |
| closef(i)
 | |
| register int i;
 | |
| {
 | |
| 	if (i > 2)
 | |
| 		close(i);
 | |
| }
 | |
| 
 | |
| void
 | |
| closeall()
 | |
| {
 | |
| 	register u;
 | |
| 
 | |
| 	for (u=NUFILE; u<NOFILE;)
 | |
| 		close(u++);
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * remap fd into Shell's fd space
 | |
|  */
 | |
| int
 | |
| remap(fd)
 | |
| register int fd;
 | |
| {
 | |
| 	register int i;
 | |
| 	int map[NOFILE];
 | |
| 
 | |
| 	if (fd < e.iofd) {
 | |
| 		for (i=0; i<NOFILE; i++)
 | |
| 			map[i] = 0;
 | |
| 		do {
 | |
| 			map[fd] = 1;
 | |
| 			fd = dup(fd);
 | |
| 		} while (fd >= 0 && fd < e.iofd);
 | |
| 		for (i=0; i<NOFILE; i++)
 | |
| 			if (map[i])
 | |
| 				close(i);
 | |
| 		if (fd < 0)
 | |
| 			err("too many files open in shell");
 | |
| 	}
 | |
| 	return(fd);
 | |
| }
 | |
| 
 | |
| int
 | |
| openpipe(pv)
 | |
| register int *pv;
 | |
| {
 | |
| 	register int i;
 | |
| 
 | |
| 	if ((i = pipe(pv)) < 0)
 | |
| 		err("can't create pipe - try again");
 | |
| 	return(i);
 | |
| }
 | |
| 
 | |
| void
 | |
| closepipe(pv)
 | |
| register int *pv;
 | |
| {
 | |
| 	if (pv != NULL) {
 | |
| 		close(*pv++);
 | |
| 		close(*pv);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| /* -------- here.c -------- */
 | |
| /* #include "sh.h" */
 | |
| 
 | |
| /*
 | |
|  * here documents
 | |
|  */
 | |
| 
 | |
| struct	here {
 | |
| 	char	*h_tag;
 | |
| 	int	h_dosub;
 | |
| 	struct	ioword *h_iop;
 | |
| 	struct	here	*h_next;
 | |
| };
 | |
| 
 | |
| static	struct here *inhere;		/* list of hear docs while parsing */
 | |
| static	struct here *acthere;		/* list of active here documents */
 | |
| 
 | |
| void
 | |
| inithere()
 | |
| {
 | |
| 	inhere=acthere=(struct here*)0;
 | |
| }
 | |
| 
 | |
| void
 | |
| markhere(s, iop)
 | |
| register char *s;
 | |
| struct ioword *iop;
 | |
| {
 | |
| 	register struct here *h, *lh;
 | |
| 
 | |
| 	h = (struct here *) space(sizeof(struct here));
 | |
| 	if (h == 0)
 | |
| 		return;
 | |
| 	h->h_tag = evalstr(s, DOSUB);
 | |
| 	if (h->h_tag == 0)
 | |
| 		return;
 | |
| 	h->h_iop = iop;
 | |
| 	iop->io_name = 0;
 | |
| 	h->h_next = NULL;
 | |
| 	if (inhere == 0)
 | |
| 		inhere = h;
 | |
| 	else
 | |
| 		for (lh = inhere; lh!=NULL; lh = lh->h_next)
 | |
| 			if (lh->h_next == 0) {
 | |
| 				lh->h_next = h;
 | |
| 				break;
 | |
| 			}
 | |
| 	iop->io_flag |= IOHERE|IOXHERE;
 | |
| 	for (s = h->h_tag; *s; s++)
 | |
| 		if (*s & QUOTE) {
 | |
| 			iop->io_flag &= ~ IOXHERE;
 | |
| 			*s &= ~ QUOTE;
 | |
| 		}
 | |
| 	h->h_dosub = iop->io_flag & IOXHERE;
 | |
| }
 | |
| 
 | |
| void
 | |
| gethere()
 | |
| {
 | |
| 	register struct here *h, *hp;
 | |
| 
 | |
| 	/* Scan here files first leaving inhere list in place */
 | |
| 	for (hp = h = inhere; h != NULL; hp = h, h = h->h_next)
 | |
| 	  readhere(&h->h_iop->io_name, h->h_tag, h->h_dosub? 0: '\'');
 | |
| 
 | |
| 	/* Make inhere list active - keep list intact for scraphere */
 | |
| 	if (hp != NULL) {
 | |
| 	  hp->h_next = acthere;
 | |
| 	  acthere    = inhere;
 | |
| 	  inhere     = NULL;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static void
 | |
| readhere(name, s, ec)
 | |
| char **name;
 | |
| register char *s;
 | |
| int ec;
 | |
| {
 | |
| 	int tf;
 | |
| 	char tname[30];
 | |
| 	register c;
 | |
| 	jmp_buf ev;
 | |
| 	char line [LINELIM+1];
 | |
| 	char *next;
 | |
| 
 | |
| 	tempname(tname);
 | |
| 	*name = strsave(tname, areanum);
 | |
| 	tf = creat(tname, 0600);
 | |
| 	if (tf < 0)
 | |
| 		return;
 | |
| 	if (newenv(setjmp(errpt = ev)) != 0)
 | |
| 		unlink(tname);
 | |
| 	else {
 | |
| 		pushio(e.iop->argp, e.iop->iofn);
 | |
| 		e.iobase = e.iop;
 | |
| 		for (;;) {
 | |
| 			if (talking && e.iop <= iostack)
 | |
| 				prs(cprompt->value);
 | |
| 			next = line;
 | |
| 			while ((c = readc()) != '\n' && c) {
 | |
| 				if (next >= &line[LINELIM]) {
 | |
| 					c = 0;
 | |
| 					break;
 | |
| 				}
 | |
| 				*next++ = c;
 | |
| 			}
 | |
| 			*next = 0;
 | |
| 			if (strcmp(s, line) == 0 || c == 0)
 | |
| 				break;
 | |
| 			*next++ = '\n';
 | |
| 			write (tf, line, (int)(next-line));
 | |
| 		}
 | |
| 		if (c == 0) {
 | |
| 			prs("here document `"); prs(s); err("' unclosed");
 | |
| 		}
 | |
| 		quitenv();
 | |
| 	}
 | |
| 	close(tf);
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * open here temp file.
 | |
|  * if unquoted here, expand here temp file into second temp file.
 | |
|  */
 | |
| int
 | |
| herein(hname, xdoll)
 | |
| char *hname;
 | |
| int xdoll;
 | |
| {
 | |
| 	register hf, tf;
 | |
| 
 | |
| 	if (hname == 0)
 | |
| 		return(-1);
 | |
| 	hf = open(hname, 0);
 | |
| 	if (hf < 0)
 | |
| 		return (-1);
 | |
| 	if (xdoll) {
 | |
| 		char c;
 | |
| 		char tname[30];
 | |
| 		jmp_buf ev;
 | |
| 
 | |
| 		tempname(tname);
 | |
| 		if ((tf = creat(tname, 0600)) < 0)
 | |
| 			return (-1);
 | |
| 		if (newenv(setjmp(errpt = ev)) == 0) {
 | |
| 			PUSHIO(afile, hf, herechar);
 | |
| 			setbase(e.iop);
 | |
| 			while ((c = subgetc(0, 0)) != 0) {
 | |
| 				char c1 = c&~QUOTE;
 | |
| 
 | |
| 				if (c"E && !any(c1,"`$\\"))
 | |
| 					write(tf,"\\",1);
 | |
| 				write(tf, &c1, 1);
 | |
| 			}
 | |
| 			quitenv();
 | |
| 		} else
 | |
| 			unlink(tname);
 | |
| 		close(tf);
 | |
| 		tf = open(tname, 0);
 | |
| 		unlink(tname);
 | |
| 		return (tf);
 | |
| 	} else
 | |
| 		return (hf);
 | |
| }
 | |
| 
 | |
| void
 | |
| scraphere()
 | |
| {
 | |
| 	register struct here *h;
 | |
| 
 | |
| 	for (h = inhere; h != NULL; h = h->h_next) {
 | |
| 		if (h->h_iop && h->h_iop->io_name)
 | |
| 		  unlink(h->h_iop->io_name);
 | |
| 	}
 | |
| 	inhere = NULL;
 | |
| }
 | |
| 
 | |
| /* unlink here temp files before a freearea(area) */
 | |
| void
 | |
| freehere(area)
 | |
| int area;
 | |
| {
 | |
| 	register struct here *h, *hl;
 | |
| 
 | |
| 	hl = NULL;
 | |
| 	for (h = acthere; h != NULL; h = h->h_next)
 | |
| 		if (getarea((char *) h) >= area) {
 | |
| 			if (h->h_iop->io_name != NULL)
 | |
| 				unlink(h->h_iop->io_name);
 | |
| 			if (hl == NULL)
 | |
| 				acthere = h->h_next;
 | |
| 			else
 | |
| 				hl->h_next = h->h_next;
 | |
| 		} else
 | |
| 			hl = h;
 | |
| }
 | |
| 
 | |
| void
 | |
| tempname(tname)
 | |
| char *tname;
 | |
| {
 | |
| 	static int inc;
 | |
| 	register char *cp, *lp;
 | |
| 
 | |
| 	for (cp = tname, lp = "/tmp/shtm"; (*cp = *lp++) != '\0'; cp++)
 | |
| 		;
 | |
| 	lp = putn(getpid()*1000 + inc++);
 | |
| 	for (; (*cp = *lp++) != '\0'; cp++)
 | |
| 		;
 | |
| }
 | 
