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