xref: /original-bsd/bin/csh/lex.c (revision 55330032)
1 static	char *sccsid = "@(#)lex.c 4.1 10/09/80";
2 
3 #include "sh.h"
4 
5 /*
6  * C shell
7  */
8 
9 /*
10  * These lexical routines read input and form lists of words.
11  * There is some involved processing here, because of the complications
12  * of input buffering, and especially because of history substitution.
13  */
14 
15 char	*word();
16 
17 /*
18  * Peekc is a peek characer for getC, peekread for readc.
19  * There is a subtlety here in many places... history routines
20  * will read ahead and then insert stuff into the input stream.
21  * If they push back a character then they must push it behind
22  * the text substituted by the history substitution.  On the other
23  * hand in several places we need 2 peek characters.  To make this
24  * all work, the history routines read with getC, and make use both
25  * of ungetC and unreadc.  The key observation is that the state
26  * of getC at the call of a history reference is such that calls
27  * to getC from the history routines will always yield calls of
28  * readc, unless this peeking is involved.  That is to say that during
29  * getexcl the variables lap, exclp, and exclnxt are all zero.
30  *
31  * Getdol invokes history substitution, hence the extra peek, peekd,
32  * which it can ungetD to be before history substitutions.
33  */
34 char	peekc, peekd;
35 char	peekread;
36 
37 char	*exclp;			/* (Tail of) current word from ! subst */
38 struct	wordent *exclnxt;	/* The rest of the ! subst words */
39 int	exclc;			/* Count of remainig words in ! subst */
40 char	*alvecp;		/* "Globp" for alias resubstitution */
41 
42 /*
43  * Lex returns to its caller not only a wordlist (as a "var" parameter)
44  * but also whether a history substitution occurred.  This is used in
45  * the main (process) routine to determine whether to echo, and also
46  * when called by the alias routine to determine whether to keep the
47  * argument list.
48  */
49 bool	hadhist;
50 
51 #define	ungetC(c)	peekc = c
52 #define	ungetD(c)	peekd = c
53 
54 lex(hp)
55 	register struct wordent *hp;
56 {
57 	register struct wordent *wdp;
58 	int c;
59 
60 	lineloc = btell();
61 	hp->next = hp->prev = hp;
62 	hp->word = "";
63 	alvecp = 0, hadhist = 0;
64 	do
65 		c = readc(0);
66 	while (c == ' ' || c == '\t');
67 	if (c == HISTSUB && intty)
68 		/* ^lef^rit	from tty is short !:s^lef^rit */
69 		getexcl(c);
70 	else
71 		unreadc(c);
72 	wdp = hp;
73 	/*
74 	 * The following loop is written so that the links needed
75 	 * by freelex will be ready and rarin to go even if it is
76 	 * interrupted.
77 	 */
78 	do {
79 		register struct wordent *new = (struct wordent *) calloc(1, sizeof *wdp);
80 
81 		new->prev = wdp;
82 		new->next = hp;
83 		wdp->next = new;
84 		wdp = new;
85 		wdp->word = word();
86 	} while (wdp->word[0] != '\n');
87 	hp->prev = wdp;
88 	return (hadhist);
89 }
90 
91 prlex(sp0)
92 	struct wordent *sp0;
93 {
94 	register struct wordent *sp = sp0->next;
95 
96 	for (;;) {
97 		printf("%s", sp->word);
98 		sp = sp->next;
99 		if (sp == sp0)
100 			break;
101 		printf(" ");
102 	}
103 }
104 
105 copylex(hp, fp)
106 	register struct wordent *hp;
107 	struct wordent *fp;
108 {
109 	register struct wordent *wdp;
110 
111 	wdp = hp;
112 	fp = fp->next;
113 	do {
114 		register struct wordent *new = (struct wordent *) calloc(1, sizeof *wdp);
115 
116 		new->prev = wdp;
117 		new->next = hp;
118 		wdp->next = new;
119 		wdp = new;
120 		wdp->word = savestr(fp->word);
121 		fp = fp->next;
122 	} while (wdp->word[0] != '\n');
123 	hp->prev = wdp;
124 }
125 
126 freelex(vp)
127 	register struct wordent *vp;
128 {
129 	register struct wordent *fp;
130 
131 	while (vp->next != vp) {
132 		fp = vp->next;
133 		vp->next = fp->next;
134 		xfree(fp->word);
135 		xfree((char *)fp);
136 	}
137 	vp->prev = vp;
138 }
139 
140 char	*WORDMETA =	"# '`\"\t;&<>()|\n";
141 
142 char *
143 word()
144 {
145 	register char c, c1;
146 	register char *wp;
147 	char wbuf[BUFSIZ];
148 	register bool dolflg;
149 	register int i;
150 
151 	wp = wbuf;
152 	i = BUFSIZ - 4;
153 loop:
154 	c = getC(DOALL);
155 	switch (c) {
156 
157 	case ' ':
158 	case '\t':
159 		goto loop;
160 
161 	case '`':
162 	case '\'':
163 	case '"':
164 		*wp++ = c, --i, c1 = c;
165 		dolflg = c == '"' ? DOALL : DOEXCL;
166 		for (;;) {
167 			c = getC(dolflg);
168 			if (c == c1)
169 				break;
170 			if (c == '\n') {
171 				seterrc("Unmatched ", c1);
172 				ungetC(c);
173 				goto ret;
174 			}
175 			if (c == '\\') {
176 				c = getC(0);
177 				if (c == HIST)
178 					c |= QUOTE;
179 				else {
180 					if (c == '\n' && c1 != '`')
181 						c |= QUOTE;
182 					ungetC(c), c = '\\';
183 				}
184 			}
185 			if (--i <= 0)
186 				goto toochars;
187 			*wp++ = c;
188 		}
189 		*wp++ = c, --i;
190 		goto pack;
191 
192 	case '&':
193 	case '|':
194 	case '<':
195 	case '>':
196 		*wp++ = c;
197 		c1 = getC(DOALL);
198 		if (c1 == c)
199 			*wp++ = c1;
200 		else
201 			ungetC(c1);
202 		goto ret;
203 
204 	case '#':
205 		if (intty)
206 			break;
207 		if (wp != wbuf) {
208 			ungetC(c);
209 			goto ret;
210 		}
211 		c = 0;
212 		do {
213 			c1 = c;
214 			c = getC(0);
215 		} while (c != '\n');
216 		if (c1 == '\\')
217 			goto loop;
218 		/* fall into ... */
219 
220 	case ';':
221 	case '(':
222 	case ')':
223 	case '\n':
224 		*wp++ = c;
225 		goto ret;
226 
227 casebksl:
228 	case '\\':
229 		c = getC(0);
230 		if (c == '\n') {
231 			if (onelflg == 1)
232 				onelflg = 2;
233 			goto loop;
234 		}
235 		if (c != HIST)
236 			*wp++ = '\\', --i;
237 		c |= QUOTE;
238 		break;
239 	}
240 	ungetC(c);
241 pack:
242 	for (;;) {
243 		c = getC(DOALL);
244 		if (c == '\\') {
245 			c = getC(0);
246 			if (c == '\n') {
247 				if (onelflg == 1)
248 					onelflg = 2;
249 				goto ret;
250 			}
251 			if (c != HIST)
252 				*wp++ = '\\', --i;
253 			c |= QUOTE;
254 		}
255 		if (any(c, WORDMETA + intty)) {
256 			ungetC(c);
257 			if (any(c, "\"'`"))
258 				goto loop;
259 			goto ret;
260 		}
261 		if (--i <= 0)
262 			goto toochars;
263 		*wp++ = c;
264 	}
265 toochars:
266 	seterr("Word too long");
267 	wp = &wbuf[1];
268 ret:
269 	*wp = 0;
270 	return (savestr(wbuf));
271 }
272 
273 getC(flag)
274 	register int flag;
275 {
276 	register char c;
277 
278 top:
279 	if (c = peekc) {
280 		peekc = 0;
281 		return (c);
282 	}
283 	if (lap) {
284 		c = *lap++;
285 		if (c == 0) {
286 			lap = 0;
287 			goto top;
288 		}
289 		if (any(c, WORDMETA + intty))
290 			c |= QUOTE;
291 		return (c);
292 	}
293 	if (c = peekd) {
294 		peekd = 0;
295 		return (c);
296 	}
297 	if (exclp) {
298 		if (c = *exclp++)
299 			return (c);
300 		if (exclnxt && --exclc >= 0) {
301 			exclnxt = exclnxt->next;
302 			setexclp(exclnxt->word);
303 			return (' ');
304 		}
305 		exclp = 0;
306 		exclnxt = 0;
307 	}
308 	if (exclnxt) {
309 		exclnxt = exclnxt->next;
310 		if (--exclc < 0)
311 			exclnxt = 0;
312 		else
313 			setexclp(exclnxt->word);
314 		goto top;
315 	}
316 	c = readc(0);
317 	if (c == '$' && (flag & DODOL)) {
318 		getdol();
319 		goto top;
320 	}
321 	if (c == HIST && (flag & DOEXCL)) {
322 		getexcl(0);
323 		goto top;
324 	}
325 	return (c);
326 }
327 
328 getdol()
329 {
330 	register char *np;
331 	char name[40];
332 	register int c;
333 	int sc;
334 	bool special = 0;
335 
336 	np = name, *np++ = '$';
337 	c = sc = getC(DOEXCL);
338 	if (any(c, "\t \n")) {
339 		ungetD(c);
340 		ungetC('$' | QUOTE);
341 		return;
342 	}
343 	if (c == '{')
344 		*np++ = c, c = getC(DOEXCL);
345 	if (c == '#' || c == '?')
346 		special++, *np++ = c, c = getC(DOEXCL);
347 	*np++ = c;
348 	switch (c) {
349 
350 	case '<':
351 	case '$':
352 		if (special)
353 			goto vsyn;
354 		goto ret;
355 
356 	case '\n':
357 		ungetD(c);
358 		np--;
359 		goto vsyn;
360 
361 	case '*':
362 		if (special)
363 			goto vsyn;
364 		goto ret;
365 
366 	default:
367 		if (digit(c)) {
368 /*
369  * let $?0 pass for now
370 			if (special)
371 				goto vsyn;
372 */
373 			while (digit(c = getC(DOEXCL))) {
374 				if (np < &name[sizeof name / 2])
375 					*np++ = c;
376 			}
377 		} else if (letter(c))
378 			while (letter(c = getC(DOEXCL))) {
379 				if (np < &name[sizeof name / 2])
380 					*np++ = c;
381 			}
382 		else
383 			goto vsyn;
384 	}
385 	if (c == '[') {
386 		*np++ = c;
387 		do {
388 			c = getC(DOEXCL);
389 			if (c == '\n') {
390 				ungetD(c);
391 				np--;
392 				goto vsyn;
393 			}
394 			if (np >= &name[sizeof name - 8])
395 				goto vsyn;
396 			*np++ = c;
397 		} while (c != ']');
398 		c = getC(DOEXCL);
399 	}
400 	if (c == ':') {
401 		*np++ = c, c = getC(DOEXCL);
402 		if (c == 'g')
403 			*np++ = c, c = getC(DOEXCL);
404 		*np++ = c;
405 		if (!any(c, "htrqxe"))
406 			goto vsyn;
407 	} else
408 		ungetD(c);
409 	if (sc == '{') {
410 		c = getC(DOEXCL);
411 		if (c != '}') {
412 			ungetC(c);
413 			goto vsyn;
414 		}
415 		*np++ = c;
416 	}
417 ret:
418 	*np = 0;
419 	addla(name);
420 	return;
421 
422 vsyn:
423 	seterr("Variable syntax");
424 	goto ret;
425 }
426 
427 addla(cp)
428 	char *cp;
429 {
430 	char buf[BUFSIZ];
431 
432 	if (lap != 0 && strlen(cp) + strlen(lap) >= sizeof (labuf) - 4) {
433 		seterr("Expansion buf ovflo");
434 		return;
435 	}
436 	if (lap)
437 		strcpy(buf, lap);
438 	strcpy(labuf, cp);
439 	if (lap)
440 		strcat(labuf, buf);
441 	lap = labuf;
442 }
443 
444 char	lhsb[32];
445 char	slhs[32];
446 char	rhsb[64];
447 int	quesarg;
448 
449 getexcl(sc)
450 	char sc;
451 {
452 	register struct wordent *hp, *ip;
453 	int left, right, dol;
454 	register int c;
455 
456 	if (sc == 0) {
457 		sc = getC(0);
458 		if (sc != '{') {
459 			ungetC(sc);
460 			sc = 0;
461 		}
462 	}
463 	quesarg = -1;
464 	lastev = eventno;
465 	hp = gethent(sc);
466 	if (hp == 0)
467 		return;
468 	hadhist = 1;
469 	dol = 0;
470 	if (hp == alhistp)
471 		for (ip = hp->next->next; ip != alhistt; ip = ip->next)
472 			dol++;
473 	else
474 		for (ip = hp->next->next; ip != hp->prev; ip = ip->next)
475 			dol++;
476 	left = 0, right = dol;
477 	if (sc == HISTSUB) {
478 		ungetC('s'), unreadc(HISTSUB), c = ':';
479 		goto subst;
480 	}
481 	c = getC(0);
482 	if (!any(c, ":^$*-%"))
483 		goto subst;
484 	left = right = -1;
485 	if (c == ':') {
486 		c = getC(0);
487 		unreadc(c);
488 		if (letter(c) || c == '&') {
489 			c = ':';
490 			left = 0, right = dol;
491 			goto subst;
492 		}
493 	} else
494 		ungetC(c);
495 	if (!getsel(&left, &right, dol))
496 		return;
497 	c = getC(0);
498 	if (c == '*')
499 		ungetC(c), c = '-';
500 	if (c == '-') {
501 		if (!getsel(&left, &right, dol))
502 			return;
503 		c = getC(0);
504 	}
505 subst:
506 	exclc = right - left + 1;
507 	while (--left >= 0)
508 		hp = hp->next;
509 	if (sc == HISTSUB || c == ':') {
510 		do {
511 			hp = getsub(hp);
512 			c = getC(0);
513 		} while (c == ':');
514 	}
515 	unreadc(c);
516 	if (sc == '{') {
517 		c = getC(0);
518 		if (c != '}')
519 			seterr("Bad ! form");
520 	}
521 	exclnxt = hp;
522 }
523 
524 struct wordent *
525 getsub(en)
526 	struct wordent *en;
527 {
528 	register char *cp;
529 	int delim;
530 	register int c;
531 	int sc;
532 	bool global = 0;
533 	char orhsb[sizeof rhsb];
534 
535 	exclnxt = 0;
536 	sc = c = getC(0);
537 	if (c == 'g')
538 		global++, c = getC(0);
539 	switch (c) {
540 
541 	case 'p':
542 		justpr++;
543 		goto ret;
544 
545 	case 'x':
546 	case 'q':
547 		global++;
548 		/* fall into ... */
549 
550 	case 'h':
551 	case 'r':
552 	case 't':
553 	case 'e':
554 		break;
555 
556 	case '&':
557 		if (slhs[0] == 0) {
558 			seterr("No prev sub");
559 			goto ret;
560 		}
561 		strcpy(lhsb, slhs);
562 		break;
563 
564 /*
565 	case '~':
566 		if (lhsb[0] == 0)
567 			goto badlhs;
568 		break;
569 */
570 
571 	case 's':
572 		delim = getC(0);
573 		if (letter(delim) || digit(delim) || any(delim, " \t\n")) {
574 			unreadc(delim);
575 bads:
576 			lhsb[0] = 0;
577 			seterr("Bad substitute");
578 			goto ret;
579 		}
580 		cp = lhsb;
581 		for (;;) {
582 			c = getC(0);
583 			if (c == '\n') {
584 				unreadc(c);
585 				goto bads;
586 			}
587 			if (c == delim)
588 				break;
589 			if (cp > &lhsb[sizeof lhsb - 2])
590 				goto bads;
591 			if (c == '\\') {
592 				c = getC(0);
593 				if (c != delim && c != '\\')
594 					*cp++ = '\\';
595 			}
596 			*cp++ = c;
597 		}
598 		if (cp != lhsb)
599 			*cp++ = 0;
600 		else if (lhsb[0] == 0) {
601 /*badlhs:*/
602 			seterr("No prev lhs");
603 			goto ret;
604 		}
605 		cp = rhsb;
606 		strcpy(orhsb, cp);
607 		for (;;) {
608 			c = getC(0);
609 			if (c == '\n') {
610 				unreadc(c);
611 				break;
612 			}
613 			if (c == delim)
614 				break;
615 /*
616 			if (c == '~') {
617 				if (&cp[strlen(orhsb)] > &rhsb[sizeof rhsb - 2])
618 					goto toorhs;
619 				strcpy(cp, orhsb);
620 				cp = strend(cp);
621 				continue;
622 			}
623 */
624 			if (cp > &rhsb[sizeof rhsb - 2]) {
625 /*toorhs:*/
626 				seterr("Rhs too long");
627 				goto ret;
628 			}
629 			if (c == '\\') {
630 				c = getC(0);
631 				if (c != delim /* && c != '~' */)
632 					*cp++ = '\\';
633 			}
634 			*cp++ = c;
635 		}
636 		*cp++ = 0;
637 		break;
638 
639 	default:
640 		if (c == '\n')
641 			unreadc(c);
642 		seterrc("Bad ! modifier: ", c);
643 		goto ret;
644 	}
645 	strcpy(slhs, lhsb);
646 	if (exclc)
647 		en = dosub(sc, en, global);
648 ret:
649 	return (en);
650 }
651 
652 struct wordent *
653 dosub(sc, en, global)
654 	int sc;
655 	struct wordent *en;
656 	bool global;
657 {
658 	struct wordent lex;
659 	bool didsub = 0;
660 	struct wordent *hp = &lex;
661 	register struct wordent *wdp;
662 	register int i = exclc;
663 
664 	wdp = hp;
665 	while (--i >= 0) {
666 		register struct wordent *new = (struct wordent *) calloc(1, sizeof *wdp);
667 
668 		new->prev = wdp;
669 		new->next = hp;
670 		wdp->next = new;
671 		wdp = new;
672 		en = en->next;
673 		wdp->word = global || didsub == 0 ?
674 		    subword(en->word, sc, &didsub) : savestr(en->word);
675 	}
676 	if (didsub == 0)
677 		seterr("Modifier failed");
678 	hp->prev = wdp;
679 	return (&enthist(-1000, &lex, 0)->Hlex);
680 }
681 
682 char *
683 subword(cp, type, adid)
684 	char *cp;
685 	int type;
686 	bool *adid;
687 {
688 	char wbuf[BUFSIZ];
689 	register char *wp, *mp, *np;
690 	register int i;
691 
692 	switch (type) {
693 
694 	case 'r':
695 	case 'h':
696 	case 't':
697 	case 'q':
698 	case 'x':
699 		wp = domod(cp, type);
700 		if (wp == 0)
701 			return (savestr(cp));
702 		*adid = 1;
703 		return (wp);
704 
705 	default:
706 		wp = wbuf;
707 		i = BUFSIZ - 4;
708 		for (mp = cp; *mp; mp++)
709 			if (matchs(mp, lhsb)) {
710 				for (np = cp; np < mp;)
711 					*wp++ = *np++, --i;
712 				for (np = rhsb; *np; np++) switch (*np) {
713 
714 				case '\\':
715 					if (np[1] == '&')
716 						np++;
717 					/* fall into ... */
718 
719 				default:
720 					if (--i < 0)
721 						goto ovflo;
722 					*wp++ = *np;
723 					continue;
724 
725 				case '&':
726 					i -= strlen(lhsb);
727 					if (i < 0)
728 						goto ovflo;
729 					*wp = 0;
730 					strcat(wp, lhsb);
731 					wp = strend(wp);
732 					continue;
733 				}
734 				mp += strlen(lhsb);
735 				i -= strlen(mp);
736 				if (i < 0) {
737 ovflo:
738 					seterr("Subst buf ovflo");
739 					return ("");
740 				}
741 				*wp = 0;
742 				strcat(wp, mp);
743 				*adid = 1;
744 				return (savestr(wbuf));
745 			}
746 		return (savestr(cp));
747 	}
748 }
749 
750 char *
751 domod(cp, type)
752 	char *cp;
753 	int type;
754 {
755 	register char *wp, *xp;
756 	register int c;
757 
758 	switch (type) {
759 
760 	case 'x':
761 	case 'q':
762 		wp = savestr(cp);
763 		for (xp = wp; c = *xp; xp++)
764 			if ((c != ' ' && c != '\t') || type == 'q')
765 				*xp |= QUOTE;
766 		return (wp);
767 
768 	case 'h':
769 	case 't':
770 		if (!any('/', cp))	/* what if :h :t are both the same? */
771 			return (0);
772 		wp = strend(cp);
773 		while (*--wp != '/')
774 			continue;
775 		if (type == 'h')
776 take:
777 			xp = savestr(cp), xp[wp - cp] = 0;
778 		else
779 			xp = savestr(wp + 1);
780 		return (xp);
781 
782 	case 'e':
783 	case 'r':
784 		wp = strend(cp);
785 		for (wp--; wp >= cp && *wp != '/'; wp--)
786 			if (*wp == '.') {
787 				if (type == 'e')
788 					xp = savestr(wp + 1);
789 				else
790 					xp = savestr(cp), xp[wp - cp] = 0;
791 				return (xp);
792 			}
793 		return (savestr(type == 'e' ? "" : cp));
794 	}
795 	return (0);
796 }
797 
798 matchs(str, pat)
799 	register char *str, *pat;
800 {
801 
802 	while (*str && *pat && *str == *pat)
803 		str++, pat++;
804 	return (*pat == 0);
805 }
806 
807 getsel(al, ar, dol)
808 	register int *al, *ar;
809 	int dol;
810 {
811 	register int c = getC(0);
812 	register int i;
813 	bool first = *al < 0;
814 
815 	switch (c) {
816 
817 	case '%':
818 		if (quesarg == -1)
819 			goto bad;
820 		if (*al < 0)
821 			*al = quesarg;
822 		*ar = quesarg;
823 		break;
824 
825 	case '-':
826 		if (*al < 0) {
827 			*al = 0;
828 			*ar = dol - 1;
829 			unreadc(c);
830 		}
831 		return (1);
832 
833 	case '^':
834 		if (*al < 0)
835 			*al = 1;
836 		*ar = 1;
837 		break;
838 
839 	case '$':
840 		if (*al < 0)
841 			*al = dol;
842 		*ar = dol;
843 		break;
844 
845 	case '*':
846 		if (*al < 0)
847 			*al = 1;
848 		*ar = dol;
849 		if (*ar < *al) {
850 			*ar = 0;
851 			*al = 1;
852 			return (1);
853 		}
854 		break;
855 
856 	default:
857 		if (digit(c)) {
858 			i = 0;
859 			while (digit(c)) {
860 				i = i * 10 + c - '0';
861 				c = getC(0);
862 			}
863 			if (i < 0)
864 				i = dol + 1;
865 			if (*al < 0)
866 				*al = i;
867 			*ar = i;
868 		} else
869 			if (*al < 0)
870 				*al = 0, *ar = dol;
871 			else
872 				*ar = dol - 1;
873 		unreadc(c);
874 		break;
875 	}
876 	if (first) {
877 		c = getC(0);
878 		unreadc(c);
879 		if (any(c, "-$*"))
880 			return (1);
881 	}
882 	if (*al > *ar || *ar > dol) {
883 bad:
884 		seterr("Bad ! arg selector");
885 		return (0);
886 	}
887 	return (1);
888 
889 }
890 
891 struct wordent *
892 gethent(sc)
893 	int sc;
894 {
895 	register struct Hist *hp;
896 	register char *np;
897 	register int c;
898 	int event;
899 	bool back = 0;
900 
901 	c = sc == HISTSUB ? HIST : getC(0);
902 	if (c == HIST) {
903 		if (alhistp)
904 			return (alhistp);
905 		event = eventno;
906 		goto skip;
907 	}
908 	switch (c) {
909 
910 	case ':':
911 	case '^':
912 	case '$':
913 	case '*':
914 	case '%':
915 		ungetC(c);
916 		if (lastev == eventno && alhistp)
917 			return (alhistp);
918 		event = lastev;
919 		break;
920 
921 	case '-':
922 		back = 1;
923 		c = getC(0);
924 		goto number;
925 
926 	case '#':			/* !# is command being typed in (mrh) */
927 		return(&paraml);
928 
929 	default:
930 		if (any(c, "(=~")) {
931 			unreadc(c);
932 			ungetC(HIST);
933 			return (0);
934 		}
935 		if (digit(c))
936 			goto number;
937 		np = lhsb;
938 		while (!any(c, ": \t\\\n}")) {
939 			if (np < &lhsb[sizeof lhsb - 2])
940 				*np++ = c;
941 			c = getC(0);
942 		}
943 		unreadc(c);
944 		if (np == lhsb) {
945 			ungetC(HIST);
946 			return (0);
947 		}
948 		*np++ = 0;
949 		hp = findev(lhsb, 0);
950 		if (hp)
951 			lastev = hp->Hnum;
952 		return (&hp->Hlex);
953 
954 	case '?':
955 		np = lhsb;
956 		for (;;) {
957 			c = getC(0);
958 			if (c == '\n') {
959 				unreadc(c);
960 				break;
961 			}
962 			if (c == '?')
963 				break;
964 			if (np < &lhsb[sizeof lhsb - 2])
965 				*np++ = c;
966 		}
967 		if (np == lhsb) {
968 			if (lhsb[0] == 0) {
969 				seterr("No prev search");
970 				return (0);
971 			}
972 		} else
973 			*np++ = 0;
974 		hp = findev(lhsb, 1);
975 		if (hp)
976 			lastev = hp->Hnum;
977 		return (&hp->Hlex);
978 
979 	number:
980 		event = 0;
981 		while (digit(c)) {
982 			event = event * 10 + c - '0';
983 			c = getC(0);
984 		}
985 		if (back)
986 			event = eventno + (alhistp == 0) - (event ? event : 0);
987 		unreadc(c);
988 		break;
989 	}
990 skip:
991 	for (hp = Histlist.Hnext; hp; hp = hp->Hnext)
992 		if (hp->Hnum == event) {
993 			hp->Href = eventno;
994 			lastev = hp->Hnum;
995 			return (&hp->Hlex);
996 		}
997 	np = putn(event);
998 	noev(np);
999 	return (0);
1000 }
1001 
1002 struct Hist *
1003 findev(cp, anyarg)
1004 	char *cp;
1005 	bool anyarg;
1006 {
1007 	register struct Hist *hp;
1008 
1009 	for (hp = Histlist.Hnext; hp; hp = hp->Hnext)
1010 		if (matchev(hp, cp, anyarg))
1011 			return (hp);
1012 	noev(cp);
1013 	return (0);
1014 }
1015 
1016 noev(cp)
1017 	char *cp;
1018 {
1019 
1020 	seterr2(cp, ": Event not found");
1021 }
1022 
1023 matchev(hp, cp, anyarg)
1024 	register struct Hist *hp;
1025 	char *cp;
1026 	bool anyarg;
1027 {
1028 	register char *dp;
1029 	struct wordent *lp = &hp->Hlex;
1030 	int argno = 0;
1031 
1032 	for (;;) {
1033 		lp = lp->next;
1034 		if (lp->word[0] == '\n')
1035 			return (0);
1036 		for (dp = lp->word; *dp; dp++) {
1037 			if (matchs(dp, cp)) {
1038 				if (anyarg)
1039 					quesarg = argno;
1040 				return (1);
1041 			}
1042 			if (!anyarg)
1043 				return (0);
1044 		}
1045 		argno++;
1046 	}
1047 }
1048 
1049 setexclp(cp)
1050 	register char *cp;
1051 {
1052 
1053 	if (cp[0] == '\n')
1054 		return;
1055 	exclp = cp;
1056 }
1057 
1058 unreadc(c)
1059 	char c;
1060 {
1061 
1062 	peekread = c;
1063 }
1064 
1065 readc(wanteof)
1066 	bool wanteof;
1067 {
1068 	register int c;
1069 	static sincereal;
1070 
1071 	if (c = peekread) {
1072 		peekread = 0;
1073 		return (c);
1074 	}
1075 top:
1076 	if (alvecp) {
1077 		if (c = *alvecp++)
1078 			return (c);
1079 		if (*alvec) {
1080 			alvecp = *alvec++;
1081 			return (' ');
1082 		}
1083 	}
1084 	if (alvec) {
1085 		if (alvecp = *alvec) {
1086 			alvec++;
1087 			goto top;
1088 		}
1089 		/* Infinite source! */
1090 		return ('\n');
1091 	}
1092 	if (evalp) {
1093 		if (c = *evalp++)
1094 			return (c);
1095 		if (*evalvec) {
1096 			evalp = *evalvec++;
1097 			return (' ');
1098 		}
1099 		evalp = 0;
1100 	}
1101 	if (evalvec) {
1102 		if (evalvec == (char **)1) {
1103 			doneinp = 1;
1104 			reset();
1105 		}
1106 		if (evalp = *evalvec) {
1107 			evalvec++;
1108 			goto top;
1109 		}
1110 		evalvec = (char **)1;
1111 		return ('\n');
1112 	}
1113 	do {
1114 		if (arginp == (char *) 1 || onelflg == 1) {
1115 			if (wanteof)
1116 				return (-1);
1117 			exitstat();
1118 		}
1119 		if (arginp) {
1120 			if ((c = *arginp++) == 0) {
1121 				arginp = (char *) 1;
1122 				return ('\n');
1123 			}
1124 			return (c);
1125 		}
1126 reread:
1127 		c = bgetc();
1128 		if (c < 0) {
1129 #include <sgtty.h>
1130 			struct sgttyb tty;
1131 
1132 			if (wanteof)
1133 				return (-1);
1134 			/* was isatty but raw with ignoreeof yields problems */
1135 			if (ioctl(SHIN, TIOCGETP, &tty)==0 && (tty.sg_flags & RAW) == 0) {
1136 				short ctpgrp;
1137 
1138 				if (++sincereal > 25)
1139 					goto oops;
1140 				if (tpgrp != -1 &&
1141 				    ioctl(FSHTTY, TIOCGPGRP, &ctpgrp) == 0 &&
1142 				    tpgrp != ctpgrp) {
1143 					ioctl(FSHTTY, TIOCSPGRP, &tpgrp);
1144 					killpg(ctpgrp, SIGHUP);
1145 printf("Reset tty pgrp from %d to %d\n", ctpgrp, tpgrp);
1146 					goto reread;
1147 				}
1148 				if (adrof("ignoreeof")) {
1149 					if (loginsh)
1150 						printf("\nUse \"logout\" to logout.\n");
1151 					else
1152 						printf("\nUse \"exit\" to leave csh.\n");
1153 					reset();
1154 				}
1155 				if (chkstop == 0)
1156 					panystop(1);
1157 			}
1158 oops:
1159 			doneinp = 1;
1160 			reset();
1161 		}
1162 		sincereal = 0;
1163 		if (c == '\n' && onelflg)
1164 			onelflg--;
1165 	} while (c == 0);
1166 	return (c);
1167 }
1168 
1169 bgetc()
1170 {
1171 	register int buf, off, c;
1172 
1173 #ifdef TELL
1174 	if (cantell) {
1175 		if (fseekp < fbobp || fseekp > feobp) {
1176 			fbobp = feobp = fseekp;
1177 			lseek(SHIN, fseekp, 0);
1178 		}
1179 		if (fseekp == feobp) {
1180 			fbobp = feobp;
1181 			do
1182 				c = read(SHIN, fbuf[0], BUFSIZ);
1183 			while (c < 0 && errno == EINTR);
1184 			if (c <= 0)
1185 				return (-1);
1186 			feobp += c;
1187 		}
1188 		c = fbuf[0][fseekp - fbobp];
1189 		fseekp++;
1190 		return (c);
1191 	}
1192 #endif
1193 again:
1194 	buf = (int) fseekp / BUFSIZ;
1195 	if (buf >= fblocks) {
1196 		register char **nfbuf = (char **) calloc(fblocks+2, sizeof (char **));
1197 
1198 		if (fbuf) {
1199 			blkcpy(nfbuf, fbuf);
1200 			xfree((char *)fbuf);
1201 		}
1202 		fbuf = nfbuf;
1203 		fbuf[fblocks] = calloc(BUFSIZ, sizeof (char));
1204 		fblocks++;
1205 		goto again;
1206 	}
1207 	if (fseekp >= feobp) {
1208 		buf = (int) feobp / BUFSIZ;
1209 		off = (int) feobp % BUFSIZ;
1210 		do
1211 			c = read(SHIN, fbuf[buf] + off, BUFSIZ - off);
1212 		while (c < 0 && errno == EINTR);
1213 		if (c <= 0)
1214 			return (-1);
1215 		feobp += c;
1216 		goto again;
1217 	}
1218 	c = fbuf[buf][(int) fseekp % BUFSIZ];
1219 	fseekp++;
1220 	return (c);
1221 }
1222 
1223 bfree()
1224 {
1225 	register int sb, i;
1226 
1227 #ifdef TELL
1228 	if (cantell)
1229 		return;
1230 #endif
1231 	if (whyles)
1232 		return;
1233 	sb = (int) (fseekp - 1) / BUFSIZ;
1234 	if (sb > 0) {
1235 		for (i = 0; i < sb; i++)
1236 			xfree(fbuf[i]);
1237 		blkcpy(fbuf, &fbuf[sb]);
1238 		fseekp -= BUFSIZ * sb;
1239 		feobp -= BUFSIZ * sb;
1240 		fblocks -= sb;
1241 	}
1242 }
1243 
1244 bseek(l)
1245 	long l;
1246 {
1247 	register struct whyle *wp;
1248 
1249 	fseekp = l;
1250 #ifdef TELL
1251 	if (!cantell) {
1252 #endif
1253 		if (!whyles)
1254 			return;
1255 		for (wp = whyles; wp->w_next; wp = wp->w_next)
1256 			continue;
1257 		if (wp->w_start > l)
1258 			l = wp->w_start;
1259 #ifdef TELL
1260 	}
1261 #endif
1262 }
1263 
1264 /* any similarity to bell telephone is purely accidental */
1265 long
1266 btell()
1267 {
1268 
1269 	return (fseekp);
1270 }
1271 
1272 btoeof()
1273 {
1274 
1275 	lseek(SHIN, 0l, 2);
1276 	fseekp = feobp;
1277 	wfree();
1278 	bfree();
1279 }
1280 
1281 #ifdef TELL
1282 settell()
1283 {
1284 
1285 	cantell = 0;
1286 	if (arginp || onelflg || intty)
1287 		return;
1288 	if (lseek(SHIN, 0l, 1) < 0 || errno == ESPIPE)
1289 		return;
1290 	fbuf = (char **) calloc(2, sizeof (char **));
1291 	fblocks = 1;
1292 	fbuf[0] = calloc(BUFSIZ, sizeof (char));
1293 	fseekp = fbobp = feobp = tell(SHIN);
1294 	cantell = 1;
1295 }
1296 #endif
1297