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