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