xref: /original-bsd/bin/csh/lex.c (revision 65d10654)
1 /*-
2  * Copyright (c) 1980, 1991, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #ifndef lint
9 static char sccsid[] = "@(#)lex.c	8.2 (Berkeley) 04/29/95";
10 #endif /* not lint */
11 
12 #include <sys/types.h>
13 #include <sys/ioctl.h>
14 #include <termios.h>
15 #include <errno.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <unistd.h>
19 #if __STDC__
20 # include <stdarg.h>
21 #else
22 # include <varargs.h>
23 #endif
24 
25 #include "csh.h"
26 #include "extern.h"
27 
28 /*
29  * These lexical routines read input and form lists of words.
30  * There is some involved processing here, because of the complications
31  * of input buffering, and especially because of history substitution.
32  */
33 
34 static Char	*word __P((void));
35 static int	 getC1 __P((int));
36 static void	 getdol __P((void));
37 static void	 getexcl __P((int));
38 static struct Hist
39 		*findev __P((Char *, bool));
40 static void	 setexclp __P((Char *));
41 static int	 bgetc __P((void));
42 static void	 bfree __P((void));
43 static struct wordent
44 		*gethent __P((int));
45 static int	 matchs __P((Char *, Char *));
46 static int	 getsel __P((int *, int *, int));
47 static struct wordent
48 		*getsub __P((struct wordent *));
49 static Char	*subword __P((Char *, int, bool *));
50 static struct wordent
51 		*dosub __P((int, struct wordent *, bool));
52 
53 /*
54  * Peekc is a peek character for getC, peekread for readc.
55  * There is a subtlety here in many places... history routines
56  * will read ahead and then insert stuff into the input stream.
57  * If they push back a character then they must push it behind
58  * the text substituted by the history substitution.  On the other
59  * hand in several places we need 2 peek characters.  To make this
60  * all work, the history routines read with getC, and make use both
61  * of ungetC and unreadc.  The key observation is that the state
62  * of getC at the call of a history reference is such that calls
63  * to getC from the history routines will always yield calls of
64  * readc, unless this peeking is involved.  That is to say that during
65  * getexcl the variables lap, exclp, and exclnxt are all zero.
66  *
67  * Getdol invokes history substitution, hence the extra peek, peekd,
68  * which it can ungetD to be before history substitutions.
69  */
70 static Char peekc = 0, peekd = 0;
71 static Char peekread = 0;
72 
73 /* (Tail of) current word from ! subst */
74 static Char *exclp = NULL;
75 
76 /* The rest of the ! subst words */
77 static struct wordent *exclnxt = NULL;
78 
79 /* Count of remaining words in ! subst */
80 static int exclc = 0;
81 
82 /* "Globp" for alias resubstitution */
83 Char *alvecp = NULL;
84 int aret = F_SEEK;
85 
86 /*
87  * Labuf implements a general buffer for lookahead during lexical operations.
88  * Text which is to be placed in the input stream can be stuck here.
89  * We stick parsed ahead $ constructs during initial input,
90  * process id's from `$$', and modified variable values (from qualifiers
91  * during expansion in sh.dol.c) here.
92  */
93 static Char labuf[BUFSIZ];
94 
95 /*
96  * Lex returns to its caller not only a wordlist (as a "var" parameter)
97  * but also whether a history substitution occurred.  This is used in
98  * the main (process) routine to determine whether to echo, and also
99  * when called by the alias routine to determine whether to keep the
100  * argument list.
101  */
102 static bool hadhist = 0;
103 
104 /*
105  * Avoid alias expansion recursion via \!#
106  */
107 int     hleft;
108 
109 static Char getCtmp;
110 
111 #define getC(f)		((getCtmp = peekc) ? (peekc = 0, getCtmp) : getC1(f))
112 #define	ungetC(c)	peekc = c
113 #define	ungetD(c)	peekd = c
114 
115 int
116 lex(hp)
117     register struct wordent *hp;
118 {
119     register struct wordent *wdp;
120     int     c;
121 
122     btell(&lineloc);
123     hp->next = hp->prev = hp;
124     hp->word = STRNULL;
125     hadhist = 0;
126     do
127 	c = readc(0);
128     while (c == ' ' || c == '\t');
129     if (c == HISTSUB && intty)
130 	/* ^lef^rit	from tty is short !:s^lef^rit */
131 	getexcl(c);
132     else
133 	unreadc(c);
134     wdp = hp;
135     /*
136      * The following loop is written so that the links needed by freelex will
137      * be ready and rarin to go even if it is interrupted.
138      */
139     do {
140 	register struct wordent *new;
141 
142 	new = (struct wordent *) xmalloc((size_t) sizeof(*wdp));
143 	new->word = 0;
144 	new->prev = wdp;
145 	new->next = hp;
146 	wdp->next = new;
147 	wdp = new;
148 	wdp->word = word();
149     } while (wdp->word[0] != '\n');
150     hp->prev = wdp;
151     return (hadhist);
152 }
153 
154 void
155 prlex(fp, sp0)
156     FILE *fp;
157     struct wordent *sp0;
158 {
159     register struct wordent *sp = sp0->next;
160 
161     for (;;) {
162 	(void) fprintf(fp, "%s", vis_str(sp->word));
163 	sp = sp->next;
164 	if (sp == sp0)
165 	    break;
166 	if (sp->word[0] != '\n')
167 	    (void) fputc(' ', fp);
168     }
169 }
170 
171 void
172 copylex(hp, fp)
173     register struct wordent *hp;
174     register struct wordent *fp;
175 {
176     register struct wordent *wdp;
177 
178     wdp = hp;
179     fp = fp->next;
180     do {
181 	register struct wordent *new;
182 
183 	new = (struct wordent *) xmalloc((size_t) sizeof(*wdp));
184 	new->prev = wdp;
185 	new->next = hp;
186 	wdp->next = new;
187 	wdp = new;
188 	wdp->word = Strsave(fp->word);
189 	fp = fp->next;
190     } while (wdp->word[0] != '\n');
191     hp->prev = wdp;
192 }
193 
194 void
195 freelex(vp)
196     register struct wordent *vp;
197 {
198     register struct wordent *fp;
199 
200     while (vp->next != vp) {
201 	fp = vp->next;
202 	vp->next = fp->next;
203 	xfree((ptr_t) fp->word);
204 	xfree((ptr_t) fp);
205     }
206     vp->prev = vp;
207 }
208 
209 static Char *
210 word()
211 {
212     register Char c, c1;
213     register Char *wp;
214     Char    wbuf[BUFSIZ];
215     register bool dolflg;
216     register int i;
217 
218     wp = wbuf;
219     i = BUFSIZ - 4;
220 loop:
221     while ((c = getC(DOALL)) == ' ' || c == '\t')
222 	continue;
223     if (cmap(c, _META | _ESC))
224 	switch (c) {
225 	case '&':
226 	case '|':
227 	case '<':
228 	case '>':
229 	    *wp++ = c;
230 	    c1 = getC(DOALL);
231 	    if (c1 == c)
232 		*wp++ = c1;
233 	    else
234 		ungetC(c1);
235 	    goto ret;
236 
237 	case '#':
238 	    if (intty)
239 		break;
240 	    c = 0;
241 	    do {
242 		c1 = c;
243 		c = getC(0);
244 	    } while (c != '\n');
245 	    if (c1 == '\\')
246 		goto loop;
247 	    /* fall into ... */
248 
249 	case ';':
250 	case '(':
251 	case ')':
252 	case '\n':
253 	    *wp++ = c;
254 	    goto ret;
255 
256 	case '\\':
257 	    c = getC(0);
258 	    if (c == '\n') {
259 		if (onelflg == 1)
260 		    onelflg = 2;
261 		goto loop;
262 	    }
263 	    if (c != HIST)
264 		*wp++ = '\\', --i;
265 	    c |= QUOTE;
266 	}
267     c1 = 0;
268     dolflg = DOALL;
269     for (;;) {
270 	if (c1) {
271 	    if (c == c1) {
272 		c1 = 0;
273 		dolflg = DOALL;
274 	    }
275 	    else if (c == '\\') {
276 		c = getC(0);
277 		if (c == HIST)
278 		    c |= QUOTE;
279 		else {
280 		    if (c == '\n')
281 			/*
282 			 * if (c1 == '`') c = ' '; else
283 			 */
284 			c |= QUOTE;
285 		    ungetC(c);
286 		    c = '\\';
287 		}
288 	    }
289 	    else if (c == '\n') {
290 		seterror(ERR_UNMATCHED, c1);
291 		ungetC(c);
292 		break;
293 	    }
294 	}
295 	else if (cmap(c, _META | _QF | _QB | _ESC)) {
296 	    if (c == '\\') {
297 		c = getC(0);
298 		if (c == '\n') {
299 		    if (onelflg == 1)
300 			onelflg = 2;
301 		    break;
302 		}
303 		if (c != HIST)
304 		    *wp++ = '\\', --i;
305 		c |= QUOTE;
306 	    }
307 	    else if (cmap(c, _QF | _QB)) {	/* '"` */
308 		c1 = c;
309 		dolflg = c == '"' ? DOALL : DOEXCL;
310 	    }
311 	    else if (c != '#' || !intty) {
312 		ungetC(c);
313 		break;
314 	    }
315 	}
316 	if (--i > 0) {
317 	    *wp++ = c;
318 	    c = getC(dolflg);
319 	}
320 	else {
321 	    seterror(ERR_WTOOLONG);
322 	    wp = &wbuf[1];
323 	    break;
324 	}
325     }
326 ret:
327     *wp = 0;
328     return (Strsave(wbuf));
329 }
330 
331 static int
332 getC1(flag)
333     register int flag;
334 {
335     register Char c;
336 
337     while (1) {
338 	if ((c = peekc) != '\0') {
339 	    peekc = 0;
340 	    return (c);
341 	}
342 	if (lap) {
343 	    if ((c = *lap++) == 0)
344 		lap = 0;
345 	    else {
346 		if (cmap(c, _META | _QF | _QB))
347 		    c |= QUOTE;
348 		return (c);
349 	    }
350 	}
351 	if ((c = peekd) != '\0') {
352 	    peekd = 0;
353 	    return (c);
354 	}
355 	if (exclp) {
356 	    if ((c = *exclp++) != '\0')
357 		return (c);
358 	    if (exclnxt && --exclc >= 0) {
359 		exclnxt = exclnxt->next;
360 		setexclp(exclnxt->word);
361 		return (' ');
362 	    }
363 	    exclp = 0;
364 	    exclnxt = 0;
365 	}
366 	if (exclnxt) {
367 	    exclnxt = exclnxt->next;
368 	    if (--exclc < 0)
369 		exclnxt = 0;
370 	    else
371 		setexclp(exclnxt->word);
372 	    continue;
373 	}
374 	c = readc(0);
375 	if (c == '$' && (flag & DODOL)) {
376 	    getdol();
377 	    continue;
378 	}
379 	if (c == HIST && (flag & DOEXCL)) {
380 	    getexcl(0);
381 	    continue;
382 	}
383 	break;
384     }
385     return (c);
386 }
387 
388 static void
389 getdol()
390 {
391     register Char *np, *ep;
392     Char    name[4 * MAXVARLEN + 1];
393     register int c;
394     int     sc;
395     bool    special = 0, toolong;
396 
397     np = name, *np++ = '$';
398     c = sc = getC(DOEXCL);
399     if (any("\t \n", c)) {
400 	ungetD(c);
401 	ungetC('$' | QUOTE);
402 	return;
403     }
404     if (c == '{')
405 	*np++ = c, c = getC(DOEXCL);
406     if (c == '#' || c == '?')
407 	special++, *np++ = c, c = getC(DOEXCL);
408     *np++ = c;
409     switch (c) {
410 
411     case '<':
412     case '$':
413     case '!':
414 	if (special)
415 	    seterror(ERR_SPDOLLT);
416 	*np = 0;
417 	addla(name);
418 	return;
419 
420     case '\n':
421 	ungetD(c);
422 	np--;
423 	seterror(ERR_NEWLINE);
424 	*np = 0;
425 	addla(name);
426 	return;
427 
428     case '*':
429 	if (special)
430 	    seterror(ERR_SPSTAR);
431 	*np = 0;
432 	addla(name);
433 	return;
434 
435     default:
436 	toolong = 0;
437 	if (Isdigit(c)) {
438 #ifdef notdef
439 	    /* let $?0 pass for now */
440 	    if (special) {
441 		seterror(ERR_DIGIT);
442 		*np = 0;
443 		addla(name);
444 		return;
445 	    }
446 #endif
447 	    /* we know that np < &name[4] */
448 	    ep = &np[MAXVARLEN];
449 	    while ((c = getC(DOEXCL)) != '\0'){
450 		if (!Isdigit(c))
451 		    break;
452 		if (np < ep)
453 		    *np++ = c;
454 		else
455 		    toolong = 1;
456 	    }
457 	}
458 	else if (letter(c)) {
459 	    /* we know that np < &name[4] */
460 	    ep = &np[MAXVARLEN];
461 	    toolong = 0;
462 	    while ((c = getC(DOEXCL)) != '\0') {
463 		/* Bugfix for ${v123x} from Chris Torek, DAS DEC-90. */
464 		if (!letter(c) && !Isdigit(c))
465 		    break;
466 		if (np < ep)
467 		    *np++ = c;
468 		else
469 		    toolong = 1;
470 	    }
471 	}
472 	else {
473 	    *np = 0;
474 	    seterror(ERR_VARILL);
475 	    addla(name);
476 	    return;
477 	}
478 	if (toolong) {
479 	    seterror(ERR_VARTOOLONG);
480 	    *np = 0;
481 	    addla(name);
482 	    return;
483 	}
484 	break;
485     }
486     if (c == '[') {
487 	*np++ = c;
488 	/*
489 	 * Name up to here is a max of MAXVARLEN + 8.
490 	 */
491 	ep = &np[2 * MAXVARLEN + 8];
492 	do {
493 	    /*
494 	     * Michael Greim: Allow $ expansion to take place in selector
495 	     * expressions. (limits the number of characters returned)
496 	     */
497 	    c = getC(DOEXCL | DODOL);
498 	    if (c == '\n') {
499 		ungetD(c);
500 		np--;
501 		seterror(ERR_NLINDEX);
502 		*np = 0;
503 		addla(name);
504 		return;
505 	    }
506 	    if (np < ep)
507 		*np++ = c;
508 	} while (c != ']');
509 	*np = '\0';
510 	if (np >= ep) {
511 	    seterror(ERR_SELOVFL);
512 	    addla(name);
513 	    return;
514 	}
515 	c = getC(DOEXCL);
516     }
517     /*
518      * Name up to here is a max of 2 * MAXVARLEN + 8.
519      */
520     if (c == ':') {
521 	/*
522 	 * if the :g modifier is followed by a newline, then error right away!
523 	 * -strike
524 	 */
525 
526 	int     gmodflag = 0, amodflag = 0;
527 
528 	do {
529 	    *np++ = c, c = getC(DOEXCL);
530 	    if (c == 'g' || c == 'a') {
531 		if (c == 'g')
532 		    gmodflag++;
533 		else
534 		    amodflag++;
535 		*np++ = c; c = getC(DOEXCL);
536 	    }
537 	    if ((c == 'g' && !gmodflag) || (c == 'a' && !amodflag)) {
538 		if (c == 'g')
539 		    gmodflag++;
540 		else
541 		    amodflag++;
542 		*np++ = c; c = getC(DOEXCL);
543 	    }
544 	    *np++ = c;
545 	    /* scan s// [eichin:19910926.0512EST] */
546 	    if (c == 's') {
547 		int delimcnt = 2;
548 		int delim = getC(0);
549 		*np++ = delim;
550 
551 		if (!delim || letter(delim)
552 		    || Isdigit(delim) || any(" \t\n", delim)) {
553 		    seterror(ERR_BADSUBST);
554 		    break;
555 		}
556 		while ((c = getC(0)) != (-1)) {
557 		    *np++ = c;
558 		    if(c == delim) delimcnt--;
559 		    if(!delimcnt) break;
560 		}
561 		if(delimcnt) {
562 		    seterror(ERR_BADSUBST);
563 		    break;
564 		}
565 		c = 's';
566 	    }
567 	    if (!any("htrqxes", c)) {
568 		if ((amodflag || gmodflag) && c == '\n')
569 		    stderror(ERR_VARSYN);	/* strike */
570 		seterror(ERR_VARMOD, c);
571 		*np = 0;
572 		addla(name);
573 		return;
574 	    }
575 	}
576 	while ((c = getC(DOEXCL)) == ':');
577 	ungetD(c);
578     }
579     else
580 	ungetD(c);
581     if (sc == '{') {
582 	c = getC(DOEXCL);
583 	if (c != '}') {
584 	    ungetD(c);
585 	    seterror(ERR_MISSING, '}');
586 	    *np = 0;
587 	    addla(name);
588 	    return;
589 	}
590 	*np++ = c;
591     }
592     *np = 0;
593     addla(name);
594     return;
595 }
596 
597 void
598 addla(cp)
599     Char   *cp;
600 {
601     Char    buf[BUFSIZ];
602 
603     if (Strlen(cp) + (lap ? Strlen(lap) : 0) >=
604 	(sizeof(labuf) - 4) / sizeof(Char)) {
605 	seterror(ERR_EXPOVFL);
606 	return;
607     }
608     if (lap)
609 	(void) Strcpy(buf, lap);
610     (void) Strcpy(labuf, cp);
611     if (lap)
612 	(void) Strcat(labuf, buf);
613     lap = labuf;
614 }
615 
616 static Char lhsb[32];
617 static Char slhs[32];
618 static Char rhsb[64];
619 static int quesarg;
620 
621 static void
622 getexcl(sc)
623     int    sc;
624 {
625     register struct wordent *hp, *ip;
626     int     left, right, dol;
627     register int c;
628 
629     if (sc == 0) {
630 	sc = getC(0);
631 	if (sc != '{') {
632 	    ungetC(sc);
633 	    sc = 0;
634 	}
635     }
636     quesarg = -1;
637     lastev = eventno;
638     hp = gethent(sc);
639     if (hp == 0)
640 	return;
641     hadhist = 1;
642     dol = 0;
643     if (hp == alhistp)
644 	for (ip = hp->next->next; ip != alhistt; ip = ip->next)
645 	    dol++;
646     else
647 	for (ip = hp->next->next; ip != hp->prev; ip = ip->next)
648 	    dol++;
649     left = 0, right = dol;
650     if (sc == HISTSUB) {
651 	ungetC('s'), unreadc(HISTSUB), c = ':';
652 	goto subst;
653     }
654     c = getC(0);
655     if (!any(":^$*-%", c))
656 	goto subst;
657     left = right = -1;
658     if (c == ':') {
659 	c = getC(0);
660 	unreadc(c);
661 	if (letter(c) || c == '&') {
662 	    c = ':';
663 	    left = 0, right = dol;
664 	    goto subst;
665 	}
666     }
667     else
668 	ungetC(c);
669     if (!getsel(&left, &right, dol))
670 	return;
671     c = getC(0);
672     if (c == '*')
673 	ungetC(c), c = '-';
674     if (c == '-') {
675 	if (!getsel(&left, &right, dol))
676 	    return;
677 	c = getC(0);
678     }
679 subst:
680     exclc = right - left + 1;
681     while (--left >= 0)
682 	hp = hp->next;
683     if (sc == HISTSUB || c == ':') {
684 	do {
685 	    hp = getsub(hp);
686 	    c = getC(0);
687 	} while (c == ':');
688     }
689     unreadc(c);
690     if (sc == '{') {
691 	c = getC(0);
692 	if (c != '}')
693 	    seterror(ERR_BADBANG);
694     }
695     exclnxt = hp;
696 }
697 
698 static struct wordent *
699 getsub(en)
700     struct wordent *en;
701 {
702     register Char *cp;
703     int     delim;
704     register int c;
705     int     sc;
706     bool global;
707     Char    orhsb[sizeof(rhsb) / sizeof(Char)];
708 
709     do {
710 	exclnxt = 0;
711 	global = 0;
712 	sc = c = getC(0);
713 	if (c == 'g' || c == 'a') {
714 	    global |= (c == 'g') ? 1 : 2;
715 	    sc = c = getC(0);
716 	}
717 	if (((c =='g') && !(global & 1)) || ((c == 'a') && !(global & 2))) {
718 	    global |= (c == 'g') ? 1 : 2;
719 	    sc = c = getC(0);
720 	}
721 
722 	switch (c) {
723 	case 'p':
724 	    justpr++;
725 	    return (en);
726 
727 	case 'x':
728 	case 'q':
729 	    global |= 1;
730 
731 	    /* fall into ... */
732 
733 	case 'h':
734 	case 'r':
735 	case 't':
736 	case 'e':
737 	    break;
738 
739 	case '&':
740 	    if (slhs[0] == 0) {
741 		seterror(ERR_NOSUBST);
742 		return (en);
743 	    }
744 	    (void) Strcpy(lhsb, slhs);
745 	    break;
746 
747 #ifdef notdef
748 	case '~':
749 	    if (lhsb[0] == 0)
750 		goto badlhs;
751 	    break;
752 #endif
753 
754 	case 's':
755 	    delim = getC(0);
756 	    if (letter(delim) || Isdigit(delim) || any(" \t\n", delim)) {
757 		unreadc(delim);
758 		lhsb[0] = 0;
759 		seterror(ERR_BADSUBST);
760 		return (en);
761 	    }
762 	    cp = lhsb;
763 	    for (;;) {
764 		c = getC(0);
765 		if (c == '\n') {
766 		    unreadc(c);
767 		    break;
768 		}
769 		if (c == delim)
770 		    break;
771 		if (cp > &lhsb[sizeof(lhsb) / sizeof(Char) - 2]) {
772 		    lhsb[0] = 0;
773 		    seterror(ERR_BADSUBST);
774 		    return (en);
775 		}
776 		if (c == '\\') {
777 		    c = getC(0);
778 		    if (c != delim && c != '\\')
779 			*cp++ = '\\';
780 		}
781 		*cp++ = c;
782 	    }
783 	    if (cp != lhsb)
784 		*cp++ = 0;
785 	    else if (lhsb[0] == 0) {
786 		seterror(ERR_LHS);
787 		return (en);
788 	    }
789 	    cp = rhsb;
790 	    (void) Strcpy(orhsb, cp);
791 	    for (;;) {
792 		c = getC(0);
793 		if (c == '\n') {
794 		    unreadc(c);
795 		    break;
796 		}
797 		if (c == delim)
798 		    break;
799 #ifdef notdef
800 		if (c == '~') {
801 		    if (&cp[Strlen(orhsb)] > &rhsb[sizeof(rhsb) /
802 						   sizeof(Char) - 2])
803 			goto toorhs;
804 		    (void) Strcpy(cp, orhsb);
805 		    cp = Strend(cp);
806 		    continue;
807 		}
808 #endif
809 		if (cp > &rhsb[sizeof(rhsb) / sizeof(Char) - 2]) {
810 		    seterror(ERR_RHSLONG);
811 		    return (en);
812 		}
813 		if (c == '\\') {
814 		    c = getC(0);
815 		    if (c != delim /* && c != '~' */ )
816 			*cp++ = '\\';
817 		}
818 		*cp++ = c;
819 	    }
820 	    *cp++ = 0;
821 	    break;
822 
823 	default:
824 	    if (c == '\n')
825 		unreadc(c);
826 	    seterror(ERR_BADBANGMOD, c);
827 	    return (en);
828 	}
829 	(void) Strcpy(slhs, lhsb);
830 	if (exclc)
831 	    en = dosub(sc, en, global);
832     }
833     while ((c = getC(0)) == ':');
834     unreadc(c);
835     return (en);
836 }
837 
838 static struct wordent *
839 dosub(sc, en, global)
840     int     sc;
841     struct wordent *en;
842     bool global;
843 {
844     struct wordent lexi;
845     bool    didsub = 0, didone = 0;
846     struct wordent *hp = &lexi;
847     register struct wordent *wdp;
848     register int i = exclc;
849 
850     wdp = hp;
851     while (--i >= 0) {
852 	register struct wordent *new =
853 		(struct wordent *) xcalloc(1, sizeof *wdp);
854 
855 	new->word = 0;
856 	new->prev = wdp;
857 	new->next = hp;
858 	wdp->next = new;
859 	wdp = new;
860 	en = en->next;
861 	if (en->word) {
862 	    Char *tword, *otword;
863 
864 	    if ((global & 1) || didsub == 0) {
865 		tword = subword(en->word, sc, &didone);
866 		if (didone)
867 		    didsub = 1;
868 		if (global & 2) {
869 		    while (didone && tword != STRNULL) {
870 			otword = tword;
871 			tword = subword(otword, sc, &didone);
872 			if (Strcmp(tword, otword) == 0) {
873 			    xfree((ptr_t) otword);
874 			    break;
875 			}
876 			else
877 			    xfree((ptr_t) otword);
878 		    }
879 		}
880 	    }
881 	    else
882 		tword = Strsave(en->word);
883 	    wdp->word = tword;
884 	}
885     }
886     if (didsub == 0)
887 	seterror(ERR_MODFAIL);
888     hp->prev = wdp;
889     return (&enthist(-1000, &lexi, 0)->Hlex);
890 }
891 
892 static Char *
893 subword(cp, type, adid)
894     Char   *cp;
895     int     type;
896     bool   *adid;
897 {
898     Char    wbuf[BUFSIZ];
899     register Char *wp, *mp, *np;
900     register int i;
901 
902     *adid = 0;
903     switch (type) {
904 
905     case 'r':
906     case 'e':
907     case 'h':
908     case 't':
909     case 'q':
910     case 'x':
911 	wp = domod(cp, type);
912 	if (wp == 0)
913 	    return (Strsave(cp));
914 	*adid = 1;
915 	return (wp);
916 
917     default:
918 	wp = wbuf;
919 	i = BUFSIZ - 4;
920 	for (mp = cp; *mp; mp++)
921 	    if (matchs(mp, lhsb)) {
922 		for (np = cp; np < mp;)
923 		    *wp++ = *np++, --i;
924 		for (np = rhsb; *np; np++)
925 		    switch (*np) {
926 
927 		    case '\\':
928 			if (np[1] == '&')
929 			    np++;
930 			/* fall into ... */
931 
932 		    default:
933 			if (--i < 0) {
934 			    seterror(ERR_SUBOVFL);
935 			    return (STRNULL);
936 			}
937 			*wp++ = *np;
938 			continue;
939 
940 		    case '&':
941 			i -= Strlen(lhsb);
942 			if (i < 0) {
943 			    seterror(ERR_SUBOVFL);
944 			    return (STRNULL);
945 			}
946 			*wp = 0;
947 			(void) Strcat(wp, lhsb);
948 			wp = Strend(wp);
949 			continue;
950 		    }
951 		mp += Strlen(lhsb);
952 		i -= Strlen(mp);
953 		if (i < 0) {
954 		    seterror(ERR_SUBOVFL);
955 		    return (STRNULL);
956 		}
957 		*wp = 0;
958 		(void) Strcat(wp, mp);
959 		*adid = 1;
960 		return (Strsave(wbuf));
961 	    }
962 	return (Strsave(cp));
963     }
964 }
965 
966 Char   *
967 domod(cp, type)
968     Char   *cp;
969     int     type;
970 {
971     register Char *wp, *xp;
972     register int c;
973 
974     switch (type) {
975 
976     case 'x':
977     case 'q':
978 	wp = Strsave(cp);
979 	for (xp = wp; (c = *xp) != '\0'; xp++)
980 	    if ((c != ' ' && c != '\t') || type == 'q')
981 		*xp |= QUOTE;
982 	return (wp);
983 
984     case 'h':
985     case 't':
986 	if (!any(short2str(cp), '/'))
987 	    return (type == 't' ? Strsave(cp) : 0);
988 	wp = Strend(cp);
989 	while (*--wp != '/')
990 	    continue;
991 	if (type == 'h')
992 	    xp = Strsave(cp), xp[wp - cp] = 0;
993 	else
994 	    xp = Strsave(wp + 1);
995 	return (xp);
996 
997     case 'e':
998     case 'r':
999 	wp = Strend(cp);
1000 	for (wp--; wp >= cp && *wp != '/'; wp--)
1001 	    if (*wp == '.') {
1002 		if (type == 'e')
1003 		    xp = Strsave(wp + 1);
1004 		else
1005 		    xp = Strsave(cp), xp[wp - cp] = 0;
1006 		return (xp);
1007 	    }
1008 	return (Strsave(type == 'e' ? STRNULL : cp));
1009     default:
1010 	break;
1011     }
1012     return (0);
1013 }
1014 
1015 static int
1016 matchs(str, pat)
1017     register Char *str, *pat;
1018 {
1019     while (*str && *pat && *str == *pat)
1020 	str++, pat++;
1021     return (*pat == 0);
1022 }
1023 
1024 static int
1025 getsel(al, ar, dol)
1026     register int *al, *ar;
1027     int     dol;
1028 {
1029     register int c = getC(0);
1030     register int i;
1031     bool    first = *al < 0;
1032 
1033     switch (c) {
1034 
1035     case '%':
1036 	if (quesarg == -1) {
1037 	    seterror(ERR_BADBANGARG);
1038 	    return (0);
1039 	}
1040 	if (*al < 0)
1041 	    *al = quesarg;
1042 	*ar = quesarg;
1043 	break;
1044 
1045     case '-':
1046 	if (*al < 0) {
1047 	    *al = 0;
1048 	    *ar = dol - 1;
1049 	    unreadc(c);
1050 	}
1051 	return (1);
1052 
1053     case '^':
1054 	if (*al < 0)
1055 	    *al = 1;
1056 	*ar = 1;
1057 	break;
1058 
1059     case '$':
1060 	if (*al < 0)
1061 	    *al = dol;
1062 	*ar = dol;
1063 	break;
1064 
1065     case '*':
1066 	if (*al < 0)
1067 	    *al = 1;
1068 	*ar = dol;
1069 	if (*ar < *al) {
1070 	    *ar = 0;
1071 	    *al = 1;
1072 	    return (1);
1073 	}
1074 	break;
1075 
1076     default:
1077 	if (Isdigit(c)) {
1078 	    i = 0;
1079 	    while (Isdigit(c)) {
1080 		i = i * 10 + c - '0';
1081 		c = getC(0);
1082 	    }
1083 	    if (i < 0)
1084 		i = dol + 1;
1085 	    if (*al < 0)
1086 		*al = i;
1087 	    *ar = i;
1088 	}
1089 	else if (*al < 0)
1090 	    *al = 0, *ar = dol;
1091 	else
1092 	    *ar = dol - 1;
1093 	unreadc(c);
1094 	break;
1095     }
1096     if (first) {
1097 	c = getC(0);
1098 	unreadc(c);
1099 	if (any("-$*", c))
1100 	    return (1);
1101     }
1102     if (*al > *ar || *ar > dol) {
1103 	seterror(ERR_BADBANGARG);
1104 	return (0);
1105     }
1106     return (1);
1107 
1108 }
1109 
1110 static struct wordent *
1111 gethent(sc)
1112     int     sc;
1113 {
1114     register struct Hist *hp;
1115     register Char *np;
1116     register int c;
1117     int     event;
1118     bool    back = 0;
1119 
1120     c = sc == HISTSUB ? HIST : getC(0);
1121     if (c == HIST) {
1122 	if (alhistp)
1123 	    return (alhistp);
1124 	event = eventno;
1125     }
1126     else
1127 	switch (c) {
1128 
1129 	case ':':
1130 	case '^':
1131 	case '$':
1132 	case '*':
1133 	case '%':
1134 	    ungetC(c);
1135 	    if (lastev == eventno && alhistp)
1136 		return (alhistp);
1137 	    event = lastev;
1138 	    break;
1139 
1140 	case '#':		/* !# is command being typed in (mrh) */
1141 	    if (--hleft == 0) {
1142 		seterror(ERR_HISTLOOP);
1143 		return (0);
1144 	    }
1145 	    else
1146 		return (&paraml);
1147 	    /* NOTREACHED */
1148 
1149 	case '-':
1150 	    back = 1;
1151 	    c = getC(0);
1152 	    /* FALLSTHROUGH */
1153 
1154 	default:
1155 	    if (any("(=~", c)) {
1156 		unreadc(c);
1157 		ungetC(HIST);
1158 		return (0);
1159 	    }
1160 	    np = lhsb;
1161 	    event = 0;
1162 	    while (!cmap(c, _ESC | _META | _QF | _QB) && !any("${}:", c)) {
1163 		if (event != -1 && Isdigit(c))
1164 		    event = event * 10 + c - '0';
1165 		else
1166 		    event = -1;
1167 		if (np < &lhsb[sizeof(lhsb) / sizeof(Char) - 2])
1168 		    *np++ = c;
1169 		c = getC(0);
1170 	    }
1171 	    unreadc(c);
1172 	    if (np == lhsb) {
1173 		ungetC(HIST);
1174 		return (0);
1175 	    }
1176 	    *np++ = 0;
1177 	    if (event != -1) {
1178 		/*
1179 		 * History had only digits
1180 		 */
1181 		if (back)
1182 		    event = eventno + (alhistp == 0) - (event ? event : 0);
1183 		break;
1184 	    }
1185 	    hp = findev(lhsb, 0);
1186 	    if (hp)
1187 		lastev = hp->Hnum;
1188 	    return (&hp->Hlex);
1189 
1190 	case '?':
1191 	    np = lhsb;
1192 	    for (;;) {
1193 		c = getC(0);
1194 		if (c == '\n') {
1195 		    unreadc(c);
1196 		    break;
1197 		}
1198 		if (c == '?')
1199 		    break;
1200 		if (np < &lhsb[sizeof(lhsb) / sizeof(Char) - 2])
1201 		    *np++ = c;
1202 	    }
1203 	    if (np == lhsb) {
1204 		if (lhsb[0] == 0) {
1205 		    seterror(ERR_NOSEARCH);
1206 		    return (0);
1207 		}
1208 	    }
1209 	    else
1210 		*np++ = 0;
1211 	    hp = findev(lhsb, 1);
1212 	    if (hp)
1213 		lastev = hp->Hnum;
1214 	    return (&hp->Hlex);
1215 	}
1216 
1217     for (hp = Histlist.Hnext; hp; hp = hp->Hnext)
1218 	if (hp->Hnum == event) {
1219 	    hp->Href = eventno;
1220 	    lastev = hp->Hnum;
1221 	    return (&hp->Hlex);
1222 	}
1223     np = putn(event);
1224     seterror(ERR_NOEVENT, vis_str(np));
1225     return (0);
1226 }
1227 
1228 static struct Hist *
1229 findev(cp, anyarg)
1230     Char   *cp;
1231     bool    anyarg;
1232 {
1233     register struct Hist *hp;
1234 
1235     for (hp = Histlist.Hnext; hp; hp = hp->Hnext) {
1236 	Char   *dp;
1237 	register Char *p, *q;
1238 	register struct wordent *lp = hp->Hlex.next;
1239 	int     argno = 0;
1240 
1241 	/*
1242 	 * The entries added by alias substitution don't have a newline but do
1243 	 * have a negative event number. Savehist() trims off these entries,
1244 	 * but it happens before alias expansion, too early to delete those
1245 	 * from the previous command.
1246 	 */
1247 	if (hp->Hnum < 0)
1248 	    continue;
1249 	if (lp->word[0] == '\n')
1250 	    continue;
1251 	if (!anyarg) {
1252 	    p = cp;
1253 	    q = lp->word;
1254 	    do
1255 		if (!*p)
1256 		    return (hp);
1257 	    while (*p++ == *q++);
1258 	    continue;
1259 	}
1260 	do {
1261 	    for (dp = lp->word; *dp; dp++) {
1262 		p = cp;
1263 		q = dp;
1264 		do
1265 		    if (!*p) {
1266 			quesarg = argno;
1267 			return (hp);
1268 		    }
1269 		while (*p++ == *q++);
1270 	    }
1271 	    lp = lp->next;
1272 	    argno++;
1273 	} while (lp->word[0] != '\n');
1274     }
1275     seterror(ERR_NOEVENT, vis_str(cp));
1276     return (0);
1277 }
1278 
1279 
1280 static void
1281 setexclp(cp)
1282     register Char *cp;
1283 {
1284     if (cp && cp[0] == '\n')
1285 	return;
1286     exclp = cp;
1287 }
1288 
1289 void
1290 unreadc(c)
1291     int    c;
1292 {
1293     peekread = c;
1294 }
1295 
1296 int
1297 readc(wanteof)
1298     bool    wanteof;
1299 {
1300     register int c;
1301     static  sincereal;
1302 
1303     aret = F_SEEK;
1304     if ((c = peekread) != '\0') {
1305 	peekread = 0;
1306 	return (c);
1307     }
1308 top:
1309     aret = F_SEEK;
1310     if (alvecp) {
1311 	aret = A_SEEK;
1312 	if ((c = *alvecp++) != '\0')
1313 	    return (c);
1314 	if (alvec && *alvec) {
1315 		alvecp = *alvec++;
1316 		return (' ');
1317 	}
1318 	else {
1319 	    aret = F_SEEK;
1320 	    alvecp = NULL;
1321 	    return('\n');
1322 	}
1323     }
1324     if (alvec) {
1325 	if ((alvecp = *alvec) != '\0') {
1326 	    alvec++;
1327 	    goto top;
1328 	}
1329 	/* Infinite source! */
1330 	return ('\n');
1331     }
1332     if (evalp) {
1333 	aret = E_SEEK;
1334 	if ((c = *evalp++) != '\0')
1335 	    return (c);
1336 	if (evalvec && *evalvec) {
1337 	    evalp = *evalvec++;
1338 	    return (' ');
1339 	}
1340 	aret = F_SEEK;
1341 	evalp = 0;
1342     }
1343     if (evalvec) {
1344 	if (evalvec == (Char **) 1) {
1345 	    doneinp = 1;
1346 	    reset();
1347 	}
1348 	if ((evalp = *evalvec) != '\0') {
1349 	    evalvec++;
1350 	    goto top;
1351 	}
1352 	evalvec = (Char **) 1;
1353 	return ('\n');
1354     }
1355     do {
1356 	if (arginp == (Char *) 1 || onelflg == 1) {
1357 	    if (wanteof)
1358 		return (-1);
1359 	    exitstat();
1360 	}
1361 	if (arginp) {
1362 	    if ((c = *arginp++) == 0) {
1363 		arginp = (Char *) 1;
1364 		return ('\n');
1365 	    }
1366 	    return (c);
1367 	}
1368 reread:
1369 	c = bgetc();
1370 	if (c < 0) {
1371 	    struct termios tty;
1372 	    if (wanteof)
1373 		return (-1);
1374 	    /* was isatty but raw with ignoreeof yields problems */
1375 	    if (tcgetattr(SHIN, &tty) == 0 && (tty.c_lflag & ICANON))
1376 	    {
1377 		/* was 'short' for FILEC */
1378 		int     ctpgrp;
1379 
1380 		if (++sincereal > 25)
1381 		    goto oops;
1382 		if (tpgrp != -1 &&
1383 		    (ctpgrp = tcgetpgrp(FSHTTY)) != -1 &&
1384 		    tpgrp != ctpgrp) {
1385 		    (void) tcsetpgrp(FSHTTY, tpgrp);
1386 		    (void) killpg((pid_t) ctpgrp, SIGHUP);
1387 		    (void) fprintf(csherr, "Reset tty pgrp from %d to %d\n",
1388 				   ctpgrp, tpgrp);
1389 		    goto reread;
1390 		}
1391 		if (adrof(STRignoreeof)) {
1392 		    if (loginsh)
1393 			(void) fprintf(csherr,"\nUse \"logout\" to logout.\n");
1394 		    else
1395 			(void) fprintf(csherr,"\nUse \"exit\" to leave csh.\n");
1396 		    reset();
1397 		}
1398 		if (chkstop == 0)
1399 		    panystop(1);
1400 	    }
1401     oops:
1402 	    doneinp = 1;
1403 	    reset();
1404 	}
1405 	sincereal = 0;
1406 	if (c == '\n' && onelflg)
1407 	    onelflg--;
1408     } while (c == 0);
1409     return (c);
1410 }
1411 
1412 static int
1413 bgetc()
1414 {
1415     register int buf, off, c;
1416 
1417 #ifdef FILEC
1418     register int numleft = 0, roomleft;
1419     Char    ttyline[BUFSIZ];
1420 #endif
1421     char    tbuf[BUFSIZ + 1];
1422 
1423     if (cantell) {
1424 	if (fseekp < fbobp || fseekp > feobp) {
1425 	    fbobp = feobp = fseekp;
1426 	    (void) lseek(SHIN, fseekp, L_SET);
1427 	}
1428 	if (fseekp == feobp) {
1429 	    int     i;
1430 
1431 	    fbobp = feobp;
1432 	    do
1433 		c = read(SHIN, tbuf, BUFSIZ);
1434 	    while (c < 0 && errno == EINTR);
1435 	    if (c <= 0)
1436 		return (-1);
1437 	    for (i = 0; i < c; i++)
1438 		fbuf[0][i] = (unsigned char) tbuf[i];
1439 	    feobp += c;
1440 	}
1441 	c = fbuf[0][fseekp - fbobp];
1442 	fseekp++;
1443 	return (c);
1444     }
1445 
1446 again:
1447     buf = (int) fseekp / BUFSIZ;
1448     if (buf >= fblocks) {
1449 	register Char **nfbuf =
1450 	(Char **) xcalloc((size_t) (fblocks + 2),
1451 			  sizeof(Char **));
1452 
1453 	if (fbuf) {
1454 	    (void) blkcpy(nfbuf, fbuf);
1455 	    xfree((ptr_t) fbuf);
1456 	}
1457 	fbuf = nfbuf;
1458 	fbuf[fblocks] = (Char *) xcalloc(BUFSIZ, sizeof(Char));
1459 	fblocks++;
1460 	if (!intty)
1461 	    goto again;
1462     }
1463     if (fseekp >= feobp) {
1464 	buf = (int) feobp / BUFSIZ;
1465 	off = (int) feobp % BUFSIZ;
1466 	roomleft = BUFSIZ - off;
1467 
1468 #ifdef FILEC
1469 	roomleft = BUFSIZ - off;
1470 	for (;;) {
1471 	    if (filec && intty) {
1472 		c = numleft ? numleft : tenex(ttyline, BUFSIZ);
1473 		if (c > roomleft) {
1474 		    /* start with fresh buffer */
1475 		    feobp = fseekp = fblocks * BUFSIZ;
1476 		    numleft = c;
1477 		    goto again;
1478 		}
1479 		if (c > 0)
1480 		    memmove(fbuf[buf] + off, ttyline, c * sizeof(Char));
1481 		numleft = 0;
1482 	    }
1483 	    else {
1484 #endif
1485 		c = read(SHIN, tbuf, roomleft);
1486 		if (c > 0) {
1487 		    int     i;
1488 		    Char   *ptr = fbuf[buf] + off;
1489 
1490 		    for (i = 0; i < c; i++)
1491 			ptr[i] = (unsigned char) tbuf[i];
1492 		}
1493 #ifdef FILEC
1494 	    }
1495 #endif
1496 	    if (c >= 0)
1497 		break;
1498 	    if (errno == EWOULDBLOCK) {
1499 		int     off = 0;
1500 
1501 		(void) ioctl(SHIN, FIONBIO, (ioctl_t) & off);
1502 	    }
1503 	    else if (errno != EINTR)
1504 		break;
1505 	}
1506 	if (c <= 0)
1507 	    return (-1);
1508 	feobp += c;
1509 #ifndef FILEC
1510 	goto again;
1511 #else
1512 	if (filec && !intty)
1513 	    goto again;
1514 #endif
1515     }
1516     c = fbuf[buf][(int) fseekp % BUFSIZ];
1517     fseekp++;
1518     return (c);
1519 }
1520 
1521 static void
1522 bfree()
1523 {
1524     register int sb, i;
1525 
1526     if (cantell)
1527 	return;
1528     if (whyles)
1529 	return;
1530     sb = (int) (fseekp - 1) / BUFSIZ;
1531     if (sb > 0) {
1532 	for (i = 0; i < sb; i++)
1533 	    xfree((ptr_t) fbuf[i]);
1534 	(void) blkcpy(fbuf, &fbuf[sb]);
1535 	fseekp -= BUFSIZ * sb;
1536 	feobp -= BUFSIZ * sb;
1537 	fblocks -= sb;
1538     }
1539 }
1540 
1541 void
1542 bseek(l)
1543     struct Ain   *l;
1544 {
1545     switch (aret = l->type) {
1546     case E_SEEK:
1547 	evalvec = l->a_seek;
1548 	evalp = l->c_seek;
1549 	return;
1550     case A_SEEK:
1551 	alvec = l->a_seek;
1552 	alvecp = l->c_seek;
1553 	return;
1554     case F_SEEK:
1555 	fseekp = l->f_seek;
1556 	return;
1557     default:
1558 	(void) fprintf(csherr, "Bad seek type %d\n", aret);
1559 	abort();
1560     }
1561 }
1562 
1563 void
1564 btell(l)
1565     struct Ain *l;
1566 {
1567     switch (l->type = aret) {
1568     case E_SEEK:
1569 	l->a_seek = evalvec;
1570 	l->c_seek = evalp;
1571 	return;
1572     case A_SEEK:
1573 	l->a_seek = alvec;
1574 	l->c_seek = alvecp;
1575 	return;
1576     case F_SEEK:
1577 	l->f_seek = fseekp;
1578 	l->a_seek = NULL;
1579 	return;
1580     default:
1581 	(void) fprintf(csherr, "Bad seek type %d\n", aret);
1582 	abort();
1583     }
1584 }
1585 
1586 void
1587 btoeof()
1588 {
1589     (void) lseek(SHIN, (off_t) 0, L_XTND);
1590     aret = F_SEEK;
1591     fseekp = feobp;
1592     alvec = NULL;
1593     alvecp = NULL;
1594     evalvec = NULL;
1595     evalp = NULL;
1596     wfree();
1597     bfree();
1598 }
1599 
1600 void
1601 settell()
1602 {
1603     cantell = 0;
1604     if (arginp || onelflg || intty)
1605 	return;
1606     if (lseek(SHIN, (off_t) 0, L_INCR) < 0 || errno == ESPIPE)
1607 	return;
1608     fbuf = (Char **) xcalloc(2, sizeof(Char **));
1609     fblocks = 1;
1610     fbuf[0] = (Char *) xcalloc(BUFSIZ, sizeof(Char));
1611     fseekp = fbobp = feobp = lseek(SHIN, (off_t) 0, L_INCR);
1612     cantell = 1;
1613 }
1614