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