1#define Extern extern
2#include <sys/types.h>
3#include <signal.h>
4#define _NSIG NSIG
5#include <errno.h>
6#include <setjmp.h>
7#include "sh.h"
8
9/* -------- io.c -------- */
10/* #include "sh.h" */
11
12/*
13 * shell IO
14 */
15
16static struct iobuf sharedbuf = {AFID_NOBUF};
17static struct iobuf mainbuf = {AFID_NOBUF};
18static unsigned bufid = AFID_ID;	/* buffer id counter */
19
20struct ioarg temparg = {0, 0, 0, AFID_NOBUF, 0};
21
22_PROTOTYPE(static void readhere, (char **name, char *s, int ec ));
23_PROTOTYPE(void pushio, (struct ioarg *argp, int (*fn)()));
24_PROTOTYPE(static int xxchar, (struct ioarg *ap ));
25_PROTOTYPE(void tempname, (char *tname ));
26
27int
28getc(ec)
29register int ec;
30{
31	register int c;
32
33	if(e.linep > elinep) {
34		while((c=readc()) != '\n' && c)
35			;
36		err("input line too long");
37		gflg++;
38		return(c);
39	}
40	c = readc();
41 	if (ec != '\'' && e.iop->task != XGRAVE) {
42		if(c == '\\') {
43			c = readc();
44			if (c == '\n' && ec != '\"')
45				return(getc(ec));
46			c |= QUOTE;
47		}
48	}
49	return(c);
50}
51
52void
53unget(c)
54int c;
55{
56	if (e.iop >= e.iobase)
57		e.iop->peekc = c;
58}
59
60int
61eofc()
62
63{
64  return e.iop < e.iobase || (e.iop->peekc == 0 && e.iop->prev == 0);
65}
66
67int
68readc()
69{
70	register c;
71
72	for (; e.iop >= e.iobase; e.iop--)
73		if ((c = e.iop->peekc) != '\0') {
74			e.iop->peekc = 0;
75			return(c);
76		}
77		else {
78		    if (e.iop->prev != 0) {
79		        if ((c = (*e.iop->iofn)(e.iop->argp, e.iop)) != '\0') {
80			        if (c == -1) {
81				        e.iop++;
82				        continue;
83			        }
84			        if (e.iop == iostack)
85				        ioecho(c);
86			        return(e.iop->prev = c);
87		        }
88		        else if (e.iop->task == XIO && e.iop->prev != '\n') {
89			        e.iop->prev = 0;
90				if (e.iop == iostack)
91					ioecho('\n');
92			        return '\n';
93		        }
94		    }
95		    if (e.iop->task == XIO) {
96			if (multiline)
97			    return e.iop->prev = 0;
98			if (talking && e.iop == iostack+1)
99			    prs(prompt->value);
100		    }
101		}
102	if (e.iop >= iostack)
103		return(0);
104	leave();
105	/* NOTREACHED */
106}
107
108void
109ioecho(c)
110char c;
111{
112	if (flag['v'])
113		write(2, &c, sizeof c);
114}
115
116void
117pushio(argp, fn)
118struct ioarg *argp;
119int (*fn)();
120{
121	if (++e.iop >= &iostack[NPUSH]) {
122		e.iop--;
123		err("Shell input nested too deeply");
124		gflg++;
125		return;
126	}
127	e.iop->iofn = fn;
128
129	if (argp->afid != AFID_NOBUF)
130	  e.iop->argp = argp;
131	else {
132	  e.iop->argp  = ioargstack + (e.iop - iostack);
133	  *e.iop->argp = *argp;
134	  e.iop->argp->afbuf = e.iop == &iostack[0] ? &mainbuf : &sharedbuf;
135	  if (isatty(e.iop->argp->afile) == 0 &&
136	      (e.iop == &iostack[0] ||
137	       lseek(e.iop->argp->afile, 0L, 1) != -1)) {
138	    if (++bufid == AFID_NOBUF)
139	      bufid = AFID_ID;
140	    e.iop->argp->afid  = bufid;
141	  }
142	}
143
144	e.iop->prev  = ~'\n';
145	e.iop->peekc = 0;
146	e.iop->xchar = 0;
147	e.iop->nlcount = 0;
148	if (fn == filechar || fn == linechar)
149		e.iop->task = XIO;
150	else if (fn == gravechar || fn == qgravechar)
151		e.iop->task = XGRAVE;
152	else
153		e.iop->task = XOTHER;
154}
155
156struct io *
157setbase(ip)
158struct io *ip;
159{
160	register struct io *xp;
161
162	xp = e.iobase;
163	e.iobase = ip;
164	return(xp);
165}
166
167/*
168 * Input generating functions
169 */
170
171/*
172 * Produce the characters of a string, then a newline, then EOF.
173 */
174int
175nlchar(ap)
176register struct ioarg *ap;
177{
178	register int c;
179
180	if (ap->aword == NULL)
181		return(0);
182	if ((c = *ap->aword++) == 0) {
183		ap->aword = NULL;
184		return('\n');
185	}
186	return(c);
187}
188
189/*
190 * Given a list of words, produce the characters
191 * in them, with a space after each word.
192 */
193int
194wdchar(ap)
195register struct ioarg *ap;
196{
197	register char c;
198	register char **wl;
199
200	if ((wl = ap->awordlist) == NULL)
201		return(0);
202	if (*wl != NULL) {
203		if ((c = *(*wl)++) != 0)
204			return(c & 0177);
205		ap->awordlist++;
206		return(' ');
207	}
208	ap->awordlist = NULL;
209	return('\n');
210}
211
212/*
213 * Return the characters of a list of words,
214 * producing a space between them.
215 */
216int
217dolchar(ap)
218register struct ioarg *ap;
219{
220	register char *wp;
221
222	if ((wp = *ap->awordlist++) != NULL) {
223		PUSHIO(aword, wp, *ap->awordlist == NULL? strchar: xxchar);
224		return(-1);
225	}
226	return(0);
227}
228
229static int
230xxchar(ap)
231register struct ioarg *ap;
232{
233	register int c;
234
235	if (ap->aword == NULL)
236		return(0);
237	if ((c = *ap->aword++) == '\0') {
238		ap->aword = NULL;
239		return(' ');
240	}
241	return(c);
242}
243
244/*
245 * Produce the characters from a single word (string).
246 */
247int
248strchar(ap)
249register struct ioarg *ap;
250{
251	register int c;
252
253	if (ap->aword == NULL || (c = *ap->aword++) == 0)
254		return(0);
255	return(c);
256}
257
258/*
259 * Produce quoted characters from a single word (string).
260 */
261int
262qstrchar(ap)
263register struct ioarg *ap;
264{
265	register int c;
266
267	if (ap->aword == NULL || (c = *ap->aword++) == 0)
268		return(0);
269	return(c|QUOTE);
270}
271
272/*
273 * Return the characters from a file.
274 */
275int
276filechar(ap)
277register struct ioarg *ap;
278{
279	register int i;
280	char c;
281	struct iobuf *bp = ap->afbuf;
282
283	if (ap->afid != AFID_NOBUF) {
284	  if ((i = ap->afid != bp->id) || bp->bufp == bp->ebufp) {
285	    if (i)
286	      lseek(ap->afile, ap->afpos, 0);
287	    do {
288	      i = read(ap->afile, bp->buf, sizeof(bp->buf));
289	    } while (i < 0 && errno == EINTR);
290	    if (i <= 0) {
291	      closef(ap->afile);
292	      return 0;
293	    }
294	    bp->id = ap->afid;
295	    bp->ebufp = (bp->bufp  = bp->buf) + i;
296	  }
297	  ap->afpos++;
298	  return *bp->bufp++ & 0177;
299	}
300
301	do {
302		i = read(ap->afile, &c, sizeof(c));
303	} while (i < 0 && errno == EINTR);
304	return(i == sizeof(c)? c&0177: (closef(ap->afile), 0));
305}
306
307/*
308 * Return the characters from a here temp file.
309 */
310int
311herechar(ap)
312register struct ioarg *ap;
313{
314	char c;
315
316
317	if (read(ap->afile, &c, sizeof(c)) != sizeof(c)) {
318		close(ap->afile);
319		c = 0;
320	}
321	return (c);
322
323}
324
325/*
326 * Return the characters produced by a process (`...`).
327 * Quote them if required, and remove any trailing newline characters.
328 */
329int
330gravechar(ap, iop)
331struct ioarg *ap;
332struct io *iop;
333{
334	register int c;
335
336	if ((c = qgravechar(ap, iop)&~QUOTE) == '\n')
337		c = ' ';
338	return(c);
339}
340
341int
342qgravechar(ap, iop)
343register struct ioarg *ap;
344struct io *iop;
345{
346	register int c;
347
348	if (iop->xchar) {
349		if (iop->nlcount) {
350			iop->nlcount--;
351			return('\n'|QUOTE);
352		}
353		c = iop->xchar;
354		iop->xchar = 0;
355	} else if ((c = filechar(ap)) == '\n') {
356		iop->nlcount = 1;
357		while ((c = filechar(ap)) == '\n')
358			iop->nlcount++;
359		iop->xchar = c;
360		if (c == 0)
361			return(c);
362		iop->nlcount--;
363		c = '\n';
364	}
365	return(c!=0? c|QUOTE: 0);
366}
367
368/*
369 * Return a single command (usually the first line) from a file.
370 */
371int
372linechar(ap)
373register struct ioarg *ap;
374{
375	register int c;
376
377	if ((c = filechar(ap)) == '\n') {
378		if (!multiline) {
379			closef(ap->afile);
380			ap->afile = -1;	/* illegal value */
381		}
382	}
383	return(c);
384}
385
386void
387prs(s)
388register char *s;
389{
390	if (*s)
391		write(2, s, strlen(s));
392}
393
394void
395putc(c)
396char c;
397{
398	write(2, &c, sizeof c);
399}
400
401void
402prn(u)
403unsigned u;
404{
405	prs(itoa(u, 0));
406}
407
408void
409closef(i)
410register int i;
411{
412	if (i > 2)
413		close(i);
414}
415
416void
417closeall()
418{
419	register u;
420
421	for (u=NUFILE; u<NOFILE;)
422		close(u++);
423}
424
425/*
426 * remap fd into Shell's fd space
427 */
428int
429remap(fd)
430register int fd;
431{
432	register int i;
433	int map[NOFILE];
434
435	if (fd < e.iofd) {
436		for (i=0; i<NOFILE; i++)
437			map[i] = 0;
438		do {
439			map[fd] = 1;
440			fd = dup(fd);
441		} while (fd >= 0 && fd < e.iofd);
442		for (i=0; i<NOFILE; i++)
443			if (map[i])
444				close(i);
445		if (fd < 0)
446			err("too many files open in shell");
447	}
448	return(fd);
449}
450
451int
452openpipe(pv)
453register int *pv;
454{
455	register int i;
456
457	if ((i = pipe(pv)) < 0)
458		err("can't create pipe - try again");
459	return(i);
460}
461
462void
463closepipe(pv)
464register int *pv;
465{
466	if (pv != NULL) {
467		close(*pv++);
468		close(*pv);
469	}
470}
471
472/* -------- here.c -------- */
473/* #include "sh.h" */
474
475/*
476 * here documents
477 */
478
479struct	here {
480	char	*h_tag;
481	int	h_dosub;
482	struct	ioword *h_iop;
483	struct	here	*h_next;
484};
485
486static	struct here *inhere;		/* list of hear docs while parsing */
487static	struct here *acthere;		/* list of active here documents */
488
489void
490markhere(s, iop)
491register char *s;
492struct ioword *iop;
493{
494	register struct here *h, *lh;
495
496	h = (struct here *) space(sizeof(struct here));
497	if (h == 0)
498		return;
499	h->h_tag = evalstr(s, DOSUB);
500	if (h->h_tag == 0)
501		return;
502	h->h_iop = iop;
503	iop->io_name = 0;
504	h->h_next = NULL;
505	if (inhere == 0)
506		inhere = h;
507	else
508		for (lh = inhere; lh!=NULL; lh = lh->h_next)
509			if (lh->h_next == 0) {
510				lh->h_next = h;
511				break;
512			}
513	iop->io_flag |= IOHERE|IOXHERE;
514	for (s = h->h_tag; *s; s++)
515		if (*s & QUOTE) {
516			iop->io_flag &= ~ IOXHERE;
517			*s &= ~ QUOTE;
518		}
519	h->h_dosub = iop->io_flag & IOXHERE;
520}
521
522void
523gethere()
524{
525	register struct here *h, *hp;
526
527	/* Scan here files first leaving inhere list in place */
528	for (hp = h = inhere; h != NULL; hp = h, h = h->h_next)
529	  readhere(&h->h_iop->io_name, h->h_tag, h->h_dosub? 0: '\'');
530
531	/* Make inhere list active - keep list intact for scraphere */
532	if (hp != NULL) {
533	  hp->h_next = acthere;
534	  acthere    = inhere;
535	  inhere     = NULL;
536	}
537}
538
539static void
540readhere(name, s, ec)
541char **name;
542register char *s;
543int ec;
544{
545	int tf;
546	char tname[30];
547	register c;
548	jmp_buf ev;
549	char line [LINELIM+1];
550	char *next;
551
552	tempname(tname);
553	*name = strsave(tname, areanum);
554	tf = creat(tname, 0600);
555	if (tf < 0)
556		return;
557	if (newenv(setjmp(errpt = ev)) != 0)
558		unlink(tname);
559	else {
560		pushio(e.iop->argp, e.iop->iofn);
561		e.iobase = e.iop;
562		for (;;) {
563			if (talking && e.iop <= iostack)
564				prs(cprompt->value);
565			next = line;
566			while ((c = getc(ec)) != '\n' && c) {
567				if (ec == '\'')
568					c &= ~ QUOTE;
569				if (next >= &line[LINELIM]) {
570					c = 0;
571					break;
572				}
573				*next++ = c;
574			}
575			*next = 0;
576			if (strcmp(s, line) == 0 || c == 0)
577				break;
578			*next++ = '\n';
579			write (tf, line, (int)(next-line));
580		}
581		if (c == 0) {
582			prs("here document `"); prs(s); err("' unclosed");
583		}
584		quitenv();
585	}
586	close(tf);
587}
588
589/*
590 * open here temp file.
591 * if unquoted here, expand here temp file into second temp file.
592 */
593int
594herein(hname, xdoll)
595char *hname;
596int xdoll;
597{
598	register hf, tf;
599
600	if (hname == 0)
601		return(-1);
602	hf = open(hname, 0);
603	if (hf < 0)
604		return (-1);
605	if (xdoll) {
606		char c;
607		char tname[30];
608		jmp_buf ev;
609
610		tempname(tname);
611		if ((tf = creat(tname, 0600)) < 0)
612			return (-1);
613		if (newenv(setjmp(errpt = ev)) == 0) {
614			PUSHIO(afile, hf, herechar);
615			setbase(e.iop);
616			while ((c = subgetc(0, 0)) != 0) {
617				c &= ~ QUOTE;
618				write(tf, &c, sizeof c);
619			}
620			quitenv();
621		} else
622			unlink(tname);
623		close(tf);
624		tf = open(tname, 0);
625		unlink(tname);
626		return (tf);
627	} else
628		return (hf);
629}
630
631void
632scraphere()
633{
634	register struct here *h;
635
636	for (h = inhere; h != NULL; h = h->h_next) {
637		if (h->h_iop && h->h_iop->io_name)
638		  unlink(h->h_iop->io_name);
639	}
640	inhere = NULL;
641}
642
643/* unlink here temp files before a freearea(area) */
644void
645freehere(area)
646int area;
647{
648	register struct here *h, *hl;
649
650	hl = NULL;
651	for (h = acthere; h != NULL; h = h->h_next)
652		if (getarea((char *) h) >= area) {
653			if (h->h_iop->io_name != NULL)
654				unlink(h->h_iop->io_name);
655			if (hl == NULL)
656				acthere = h->h_next;
657			else
658				hl->h_next = h->h_next;
659		} else
660			hl = h;
661}
662
663void
664tempname(tname)
665char *tname;
666{
667	static int inc;
668	register char *cp, *lp;
669
670	for (cp = tname, lp = "/tmp/shtm"; (*cp = *lp++) != '\0'; cp++)
671		;
672	lp = putn(getpid()*1000 + inc++);
673	for (; (*cp = *lp++) != '\0'; cp++)
674		;
675}
676