147823Sbostic /*-
260765Sbostic * Copyright (c) 1980, 1991, 1993
360765Sbostic * The Regents of the University of California. All rights reserved.
447823Sbostic *
547823Sbostic * %sccs.include.redist.c%
621937Sdist */
721937Sdist
817148Ssam #ifndef lint
9*69126Schristos static char sccsid[] = "@(#)lex.c 8.2 (Berkeley) 04/29/95";
1050028Sbostic #endif /* not lint */
111299Sbill
1250028Sbostic #include <sys/types.h>
1350028Sbostic #include <sys/ioctl.h>
1450028Sbostic #include <termios.h>
1550028Sbostic #include <errno.h>
1650028Sbostic #include <stdlib.h>
1750028Sbostic #include <string.h>
1850028Sbostic #include <unistd.h>
1950033Schristos #if __STDC__
2050033Schristos # include <stdarg.h>
2150033Schristos #else
2250033Schristos # include <varargs.h>
2350033Schristos #endif
2450033Schristos
2550023Sbostic #include "csh.h"
2650023Sbostic #include "extern.h"
271299Sbill
281299Sbill /*
291299Sbill * These lexical routines read input and form lists of words.
301299Sbill * There is some involved processing here, because of the complications
311299Sbill * of input buffering, and especially because of history substitution.
321299Sbill */
331299Sbill
3450024Schristos static Char *word __P((void));
3550024Schristos static int getC1 __P((int));
3650024Schristos static void getdol __P((void));
3750024Schristos static void getexcl __P((int));
3851437Sleres static struct Hist
3950024Schristos *findev __P((Char *, bool));
4050024Schristos static void setexclp __P((Char *));
4150024Schristos static int bgetc __P((void));
4250024Schristos static void bfree __P((void));
4351437Sleres static struct wordent
4450024Schristos *gethent __P((int));
4550024Schristos static int matchs __P((Char *, Char *));
4650024Schristos static int getsel __P((int *, int *, int));
4751437Sleres static struct wordent
4850024Schristos *getsub __P((struct wordent *));
4951437Sleres static Char *subword __P((Char *, int, bool *));
5051437Sleres static struct wordent
5150024Schristos *dosub __P((int, struct wordent *, bool));
521299Sbill
531299Sbill /*
5449992Sbostic * Peekc is a peek character for getC, peekread for readc.
551299Sbill * There is a subtlety here in many places... history routines
561299Sbill * will read ahead and then insert stuff into the input stream.
571299Sbill * If they push back a character then they must push it behind
581299Sbill * the text substituted by the history substitution. On the other
591299Sbill * hand in several places we need 2 peek characters. To make this
601299Sbill * all work, the history routines read with getC, and make use both
611299Sbill * of ungetC and unreadc. The key observation is that the state
621299Sbill * of getC at the call of a history reference is such that calls
631299Sbill * to getC from the history routines will always yield calls of
641299Sbill * readc, unless this peeking is involved. That is to say that during
651299Sbill * getexcl the variables lap, exclp, and exclnxt are all zero.
661299Sbill *
671299Sbill * Getdol invokes history substitution, hence the extra peek, peekd,
681299Sbill * which it can ungetD to be before history substitutions.
691299Sbill */
7049992Sbostic static Char peekc = 0, peekd = 0;
7149992Sbostic static Char peekread = 0;
721299Sbill
7349992Sbostic /* (Tail of) current word from ! subst */
7450028Sbostic static Char *exclp = NULL;
751299Sbill
7649992Sbostic /* The rest of the ! subst words */
7750028Sbostic static struct wordent *exclnxt = NULL;
7849992Sbostic
7949992Sbostic /* Count of remaining words in ! subst */
8049992Sbostic static int exclc = 0;
8149992Sbostic
8249992Sbostic /* "Globp" for alias resubstitution */
8351526Schristos Char *alvecp = NULL;
8450944Schristos int aret = F_SEEK;
8549992Sbostic
861299Sbill /*
8749992Sbostic * Labuf implements a general buffer for lookahead during lexical operations.
8849992Sbostic * Text which is to be placed in the input stream can be stuck here.
8949992Sbostic * We stick parsed ahead $ constructs during initial input,
9049992Sbostic * process id's from `$$', and modified variable values (from qualifiers
9149992Sbostic * during expansion in sh.dol.c) here.
9249992Sbostic */
9349992Sbostic static Char labuf[BUFSIZ];
9449992Sbostic
9549992Sbostic /*
961299Sbill * Lex returns to its caller not only a wordlist (as a "var" parameter)
971299Sbill * but also whether a history substitution occurred. This is used in
981299Sbill * the main (process) routine to determine whether to echo, and also
991299Sbill * when called by the alias routine to determine whether to keep the
1001299Sbill * argument list.
1011299Sbill */
10249992Sbostic static bool hadhist = 0;
1031299Sbill
10449992Sbostic /*
10549992Sbostic * Avoid alias expansion recursion via \!#
10649992Sbostic */
10749992Sbostic int hleft;
10849992Sbostic
10949992Sbostic static Char getCtmp;
11049992Sbostic
11117517Sedward #define getC(f) ((getCtmp = peekc) ? (peekc = 0, getCtmp) : getC1(f))
1121299Sbill #define ungetC(c) peekc = c
1131299Sbill #define ungetD(c) peekd = c
1141299Sbill
11549992Sbostic int
lex(hp)1161299Sbill lex(hp)
11749992Sbostic register struct wordent *hp;
1181299Sbill {
11949992Sbostic register struct wordent *wdp;
12049992Sbostic int c;
1211299Sbill
12250944Schristos btell(&lineloc);
12349992Sbostic hp->next = hp->prev = hp;
12449992Sbostic hp->word = STRNULL;
12550944Schristos hadhist = 0;
12649992Sbostic do
12749992Sbostic c = readc(0);
12849992Sbostic while (c == ' ' || c == '\t');
12949992Sbostic if (c == HISTSUB && intty)
13049992Sbostic /* ^lef^rit from tty is short !:s^lef^rit */
13149992Sbostic getexcl(c);
13249992Sbostic else
13349992Sbostic unreadc(c);
13449992Sbostic wdp = hp;
13549992Sbostic /*
13649992Sbostic * The following loop is written so that the links needed by freelex will
13749992Sbostic * be ready and rarin to go even if it is interrupted.
13849992Sbostic */
13949992Sbostic do {
14049992Sbostic register struct wordent *new;
1411299Sbill
14249992Sbostic new = (struct wordent *) xmalloc((size_t) sizeof(*wdp));
14349992Sbostic new->word = 0;
14449992Sbostic new->prev = wdp;
14549992Sbostic new->next = hp;
14649992Sbostic wdp->next = new;
14749992Sbostic wdp = new;
14849992Sbostic wdp->word = word();
14949992Sbostic } while (wdp->word[0] != '\n');
15049992Sbostic hp->prev = wdp;
15149992Sbostic return (hadhist);
1521299Sbill }
1531299Sbill
15449992Sbostic void
prlex(fp,sp0)15550439Schristos prlex(fp, sp0)
15650439Schristos FILE *fp;
15749992Sbostic struct wordent *sp0;
1581299Sbill {
15949992Sbostic register struct wordent *sp = sp0->next;
1601299Sbill
16149992Sbostic for (;;) {
16251589Schristos (void) fprintf(fp, "%s", vis_str(sp->word));
16349992Sbostic sp = sp->next;
16449992Sbostic if (sp == sp0)
16549992Sbostic break;
16649992Sbostic if (sp->word[0] != '\n')
16750439Schristos (void) fputc(' ', fp);
16849992Sbostic }
1691299Sbill }
1701299Sbill
17149992Sbostic void
copylex(hp,fp)1721299Sbill copylex(hp, fp)
17349992Sbostic register struct wordent *hp;
17449992Sbostic register struct wordent *fp;
1751299Sbill {
17649992Sbostic register struct wordent *wdp;
1771299Sbill
17849992Sbostic wdp = hp;
17949992Sbostic fp = fp->next;
18049992Sbostic do {
18149992Sbostic register struct wordent *new;
18249992Sbostic
18349992Sbostic new = (struct wordent *) xmalloc((size_t) sizeof(*wdp));
18449992Sbostic new->prev = wdp;
18549992Sbostic new->next = hp;
18649992Sbostic wdp->next = new;
18749992Sbostic wdp = new;
18849992Sbostic wdp->word = Strsave(fp->word);
1891299Sbill fp = fp->next;
19049992Sbostic } while (wdp->word[0] != '\n');
19149992Sbostic hp->prev = wdp;
1921299Sbill }
1931299Sbill
19449992Sbostic void
freelex(vp)1951299Sbill freelex(vp)
19649992Sbostic register struct wordent *vp;
1971299Sbill {
19849992Sbostic register struct wordent *fp;
1991299Sbill
20049992Sbostic while (vp->next != vp) {
20149992Sbostic fp = vp->next;
20249992Sbostic vp->next = fp->next;
20349992Sbostic xfree((ptr_t) fp->word);
20449992Sbostic xfree((ptr_t) fp);
20549992Sbostic }
20649992Sbostic vp->prev = vp;
2071299Sbill }
2081299Sbill
20949992Sbostic static Char *
word()2101299Sbill word()
2111299Sbill {
21249992Sbostic register Char c, c1;
21349992Sbostic register Char *wp;
21449992Sbostic Char wbuf[BUFSIZ];
21549992Sbostic register bool dolflg;
21649992Sbostic register int i;
2171299Sbill
21849992Sbostic wp = wbuf;
21949992Sbostic i = BUFSIZ - 4;
2201299Sbill loop:
22151437Sleres while ((c = getC(DOALL)) == ' ' || c == '\t')
22251437Sleres continue;
22349992Sbostic if (cmap(c, _META | _ESC))
22449992Sbostic switch (c) {
22549992Sbostic case '&':
22649992Sbostic case '|':
22749992Sbostic case '<':
22849992Sbostic case '>':
22949992Sbostic *wp++ = c;
23049992Sbostic c1 = getC(DOALL);
23149992Sbostic if (c1 == c)
23249992Sbostic *wp++ = c1;
23349992Sbostic else
23449992Sbostic ungetC(c1);
23549992Sbostic goto ret;
2361299Sbill
23749992Sbostic case '#':
23849992Sbostic if (intty)
23949992Sbostic break;
24049992Sbostic c = 0;
24149992Sbostic do {
24249992Sbostic c1 = c;
24349992Sbostic c = getC(0);
24449992Sbostic } while (c != '\n');
24549992Sbostic if (c1 == '\\')
24649992Sbostic goto loop;
24749992Sbostic /* fall into ... */
24817517Sedward
24949992Sbostic case ';':
25049992Sbostic case '(':
25149992Sbostic case ')':
25249992Sbostic case '\n':
25349992Sbostic *wp++ = c;
25449992Sbostic goto ret;
2551299Sbill
25649992Sbostic case '\\':
25749992Sbostic c = getC(0);
25849992Sbostic if (c == '\n') {
25949992Sbostic if (onelflg == 1)
26049992Sbostic onelflg = 2;
26149992Sbostic goto loop;
26249992Sbostic }
26349992Sbostic if (c != HIST)
26449992Sbostic *wp++ = '\\', --i;
26549992Sbostic c |= QUOTE;
26649992Sbostic }
26749992Sbostic c1 = 0;
26849992Sbostic dolflg = DOALL;
26949992Sbostic for (;;) {
27049992Sbostic if (c1) {
27149992Sbostic if (c == c1) {
27249992Sbostic c1 = 0;
27349992Sbostic dolflg = DOALL;
27449992Sbostic }
27549992Sbostic else if (c == '\\') {
27649992Sbostic c = getC(0);
27749992Sbostic if (c == HIST)
27849992Sbostic c |= QUOTE;
27949992Sbostic else {
28049992Sbostic if (c == '\n')
28149992Sbostic /*
28249992Sbostic * if (c1 == '`') c = ' '; else
28349992Sbostic */
2841299Sbill c |= QUOTE;
28549992Sbostic ungetC(c);
28649992Sbostic c = '\\';
2871299Sbill }
28849992Sbostic }
28949992Sbostic else if (c == '\n') {
29049992Sbostic seterror(ERR_UNMATCHED, c1);
29149992Sbostic ungetC(c);
29249992Sbostic break;
29349992Sbostic }
29449992Sbostic }
29560488Schristos else if (cmap(c, _META | _QF | _QB | _ESC)) {
29649992Sbostic if (c == '\\') {
29749992Sbostic c = getC(0);
29849992Sbostic if (c == '\n') {
29949992Sbostic if (onelflg == 1)
30049992Sbostic onelflg = 2;
30149992Sbostic break;
3021299Sbill }
30349992Sbostic if (c != HIST)
30449992Sbostic *wp++ = '\\', --i;
30549992Sbostic c |= QUOTE;
30649992Sbostic }
30760488Schristos else if (cmap(c, _QF | _QB)) { /* '"` */
30849992Sbostic c1 = c;
30949992Sbostic dolflg = c == '"' ? DOALL : DOEXCL;
31049992Sbostic }
31149992Sbostic else if (c != '#' || !intty) {
31249992Sbostic ungetC(c);
31349992Sbostic break;
31449992Sbostic }
3151299Sbill }
31649992Sbostic if (--i > 0) {
31749992Sbostic *wp++ = c;
31849992Sbostic c = getC(dolflg);
31949992Sbostic }
32049992Sbostic else {
32149992Sbostic seterror(ERR_WTOOLONG);
32249992Sbostic wp = &wbuf[1];
32349992Sbostic break;
32449992Sbostic }
32549992Sbostic }
3261299Sbill ret:
32749992Sbostic *wp = 0;
32849992Sbostic return (Strsave(wbuf));
3291299Sbill }
3301299Sbill
33149992Sbostic static int
getC1(flag)33217517Sedward getC1(flag)
33349992Sbostic register int flag;
3341299Sbill {
33549992Sbostic register Char c;
3361299Sbill
33749992Sbostic while (1) {
33860237Schristos if ((c = peekc) != '\0') {
33949992Sbostic peekc = 0;
34049992Sbostic return (c);
3411299Sbill }
3421299Sbill if (lap) {
34349992Sbostic if ((c = *lap++) == 0)
34449992Sbostic lap = 0;
34549992Sbostic else {
34660488Schristos if (cmap(c, _META | _QF | _QB))
34749992Sbostic c |= QUOTE;
34849992Sbostic return (c);
34949992Sbostic }
3501299Sbill }
35160237Schristos if ((c = peekd) != '\0') {
35249992Sbostic peekd = 0;
35349992Sbostic return (c);
3541299Sbill }
3551299Sbill if (exclp) {
35660237Schristos if ((c = *exclp++) != '\0')
35749992Sbostic return (c);
35849992Sbostic if (exclnxt && --exclc >= 0) {
35949992Sbostic exclnxt = exclnxt->next;
36049992Sbostic setexclp(exclnxt->word);
36149992Sbostic return (' ');
36249992Sbostic }
36349992Sbostic exclp = 0;
36449992Sbostic exclnxt = 0;
3651299Sbill }
3661299Sbill if (exclnxt) {
36749992Sbostic exclnxt = exclnxt->next;
36849992Sbostic if (--exclc < 0)
36949992Sbostic exclnxt = 0;
37049992Sbostic else
37149992Sbostic setexclp(exclnxt->word);
37249992Sbostic continue;
3731299Sbill }
3741299Sbill c = readc(0);
3751299Sbill if (c == '$' && (flag & DODOL)) {
37649992Sbostic getdol();
37749992Sbostic continue;
3781299Sbill }
3791299Sbill if (c == HIST && (flag & DOEXCL)) {
38049992Sbostic getexcl(0);
38149992Sbostic continue;
3821299Sbill }
38349992Sbostic break;
38449992Sbostic }
38549992Sbostic return (c);
3861299Sbill }
3871299Sbill
38849992Sbostic static void
getdol()3891299Sbill getdol()
3901299Sbill {
39149992Sbostic register Char *np, *ep;
39249992Sbostic Char name[4 * MAXVARLEN + 1];
39349992Sbostic register int c;
39449992Sbostic int sc;
39549992Sbostic bool special = 0, toolong;
3961299Sbill
39749992Sbostic np = name, *np++ = '$';
39849992Sbostic c = sc = getC(DOEXCL);
39949992Sbostic if (any("\t \n", c)) {
40049992Sbostic ungetD(c);
40149992Sbostic ungetC('$' | QUOTE);
40249992Sbostic return;
40349992Sbostic }
40449992Sbostic if (c == '{')
40549992Sbostic *np++ = c, c = getC(DOEXCL);
40649992Sbostic if (c == '#' || c == '?')
40749992Sbostic special++, *np++ = c, c = getC(DOEXCL);
40849992Sbostic *np++ = c;
40949992Sbostic switch (c) {
4101299Sbill
41149992Sbostic case '<':
41249992Sbostic case '$':
41351526Schristos case '!':
41449992Sbostic if (special)
41549992Sbostic seterror(ERR_SPDOLLT);
41649992Sbostic *np = 0;
41749992Sbostic addla(name);
41849992Sbostic return;
4191299Sbill
42049992Sbostic case '\n':
42149992Sbostic ungetD(c);
42249992Sbostic np--;
42349992Sbostic seterror(ERR_NEWLINE);
42449992Sbostic *np = 0;
42549992Sbostic addla(name);
42649992Sbostic return;
4271299Sbill
42849992Sbostic case '*':
42949992Sbostic if (special)
43049992Sbostic seterror(ERR_SPSTAR);
43149992Sbostic *np = 0;
43249992Sbostic addla(name);
43349992Sbostic return;
43449992Sbostic
43549992Sbostic default:
43649992Sbostic toolong = 0;
43749992Sbostic if (Isdigit(c)) {
43849992Sbostic #ifdef notdef
43949992Sbostic /* let $?0 pass for now */
44049992Sbostic if (special) {
44149992Sbostic seterror(ERR_DIGIT);
44249992Sbostic *np = 0;
44349992Sbostic addla(name);
44449992Sbostic return;
44549992Sbostic }
44649992Sbostic #endif
44749992Sbostic /* we know that np < &name[4] */
44849992Sbostic ep = &np[MAXVARLEN];
44960237Schristos while ((c = getC(DOEXCL)) != '\0'){
45049992Sbostic if (!Isdigit(c))
45149992Sbostic break;
45249992Sbostic if (np < ep)
45349992Sbostic *np++ = c;
4541299Sbill else
45549992Sbostic toolong = 1;
45649992Sbostic }
4571299Sbill }
45849992Sbostic else if (letter(c)) {
45949992Sbostic /* we know that np < &name[4] */
46049992Sbostic ep = &np[MAXVARLEN];
46149992Sbostic toolong = 0;
46260237Schristos while ((c = getC(DOEXCL)) != '\0') {
46349992Sbostic /* Bugfix for ${v123x} from Chris Torek, DAS DEC-90. */
46449992Sbostic if (!letter(c) && !Isdigit(c))
46549992Sbostic break;
46649992Sbostic if (np < ep)
46749992Sbostic *np++ = c;
46849992Sbostic else
46949992Sbostic toolong = 1;
47049992Sbostic }
4711299Sbill }
47249992Sbostic else {
47349992Sbostic *np = 0;
47449992Sbostic seterror(ERR_VARILL);
47549992Sbostic addla(name);
47649992Sbostic return;
47749992Sbostic }
47849992Sbostic if (toolong) {
47949992Sbostic seterror(ERR_VARTOOLONG);
48049992Sbostic *np = 0;
48149992Sbostic addla(name);
48249992Sbostic return;
48349992Sbostic }
48449992Sbostic break;
48549992Sbostic }
48649992Sbostic if (c == '[') {
48749992Sbostic *np++ = c;
48849992Sbostic /*
48949992Sbostic * Name up to here is a max of MAXVARLEN + 8.
49049992Sbostic */
49149992Sbostic ep = &np[2 * MAXVARLEN + 8];
49249992Sbostic do {
49349992Sbostic /*
49449992Sbostic * Michael Greim: Allow $ expansion to take place in selector
49549992Sbostic * expressions. (limits the number of characters returned)
49649992Sbostic */
49749992Sbostic c = getC(DOEXCL | DODOL);
49849992Sbostic if (c == '\n') {
4991299Sbill ungetD(c);
50049992Sbostic np--;
50149992Sbostic seterror(ERR_NLINDEX);
50249992Sbostic *np = 0;
50349992Sbostic addla(name);
50449992Sbostic return;
50549992Sbostic }
50649992Sbostic if (np < ep)
5071299Sbill *np++ = c;
50849992Sbostic } while (c != ']');
50949992Sbostic *np = '\0';
51049992Sbostic if (np >= ep) {
51149992Sbostic seterror(ERR_SELOVFL);
51249992Sbostic addla(name);
51349992Sbostic return;
5141299Sbill }
51549992Sbostic c = getC(DOEXCL);
51649992Sbostic }
51749992Sbostic /*
51849992Sbostic * Name up to here is a max of 2 * MAXVARLEN + 8.
51949992Sbostic */
52049992Sbostic if (c == ':') {
52149992Sbostic /*
52249992Sbostic * if the :g modifier is followed by a newline, then error right away!
52349992Sbostic * -strike
52449992Sbostic */
5251299Sbill
52651526Schristos int gmodflag = 0, amodflag = 0;
52749992Sbostic
52850464Schristos do {
52950464Schristos *np++ = c, c = getC(DOEXCL);
53051526Schristos if (c == 'g' || c == 'a') {
53151526Schristos if (c == 'g')
53251526Schristos gmodflag++;
53351526Schristos else
53451526Schristos amodflag++;
53551526Schristos *np++ = c; c = getC(DOEXCL);
53651526Schristos }
53751526Schristos if ((c == 'g' && !gmodflag) || (c == 'a' && !amodflag)) {
53851526Schristos if (c == 'g')
53951526Schristos gmodflag++;
54051526Schristos else
54151526Schristos amodflag++;
54251526Schristos *np++ = c; c = getC(DOEXCL);
54351526Schristos }
54450464Schristos *np++ = c;
54551526Schristos /* scan s// [eichin:19910926.0512EST] */
54651526Schristos if (c == 's') {
54751526Schristos int delimcnt = 2;
54851526Schristos int delim = getC(0);
54951526Schristos *np++ = delim;
55051526Schristos
55151526Schristos if (!delim || letter(delim)
55251526Schristos || Isdigit(delim) || any(" \t\n", delim)) {
55351526Schristos seterror(ERR_BADSUBST);
55451526Schristos break;
55551526Schristos }
55651526Schristos while ((c = getC(0)) != (-1)) {
55751526Schristos *np++ = c;
55851526Schristos if(c == delim) delimcnt--;
55951526Schristos if(!delimcnt) break;
56051526Schristos }
56151526Schristos if(delimcnt) {
56251526Schristos seterror(ERR_BADSUBST);
56351526Schristos break;
56451526Schristos }
56551526Schristos c = 's';
56651526Schristos }
56751526Schristos if (!any("htrqxes", c)) {
56851526Schristos if ((amodflag || gmodflag) && c == '\n')
56950464Schristos stderror(ERR_VARSYN); /* strike */
57050464Schristos seterror(ERR_VARMOD, c);
57150464Schristos *np = 0;
57250464Schristos addla(name);
57350464Schristos return;
57450464Schristos }
57549992Sbostic }
57650464Schristos while ((c = getC(DOEXCL)) == ':');
57750464Schristos ungetD(c);
57849992Sbostic }
57949992Sbostic else
58049992Sbostic ungetD(c);
58149992Sbostic if (sc == '{') {
58249992Sbostic c = getC(DOEXCL);
58349992Sbostic if (c != '}') {
58449992Sbostic ungetD(c);
58549992Sbostic seterror(ERR_MISSING, '}');
58649992Sbostic *np = 0;
58749992Sbostic addla(name);
58849992Sbostic return;
58949992Sbostic }
59049992Sbostic *np++ = c;
59149992Sbostic }
59249992Sbostic *np = 0;
59349992Sbostic addla(name);
59449992Sbostic return;
5951299Sbill }
5961299Sbill
59749992Sbostic void
addla(cp)5981299Sbill addla(cp)
59949992Sbostic Char *cp;
6001299Sbill {
60149992Sbostic Char buf[BUFSIZ];
6021299Sbill
60349992Sbostic if (Strlen(cp) + (lap ? Strlen(lap) : 0) >=
60449992Sbostic (sizeof(labuf) - 4) / sizeof(Char)) {
60549992Sbostic seterror(ERR_EXPOVFL);
60649992Sbostic return;
60749992Sbostic }
60849992Sbostic if (lap)
60949992Sbostic (void) Strcpy(buf, lap);
61049992Sbostic (void) Strcpy(labuf, cp);
61149992Sbostic if (lap)
61249992Sbostic (void) Strcat(labuf, buf);
61349992Sbostic lap = labuf;
6141299Sbill }
6151299Sbill
61649992Sbostic static Char lhsb[32];
61749992Sbostic static Char slhs[32];
61849992Sbostic static Char rhsb[64];
61949992Sbostic static int quesarg;
6201299Sbill
62149992Sbostic static void
getexcl(sc)6221299Sbill getexcl(sc)
62350024Schristos int sc;
6241299Sbill {
62549992Sbostic register struct wordent *hp, *ip;
62649992Sbostic int left, right, dol;
62749992Sbostic register int c;
6281299Sbill
62949992Sbostic if (sc == 0) {
63049992Sbostic sc = getC(0);
63149992Sbostic if (sc != '{') {
63249992Sbostic ungetC(sc);
63349992Sbostic sc = 0;
6341299Sbill }
63549992Sbostic }
63649992Sbostic quesarg = -1;
63749992Sbostic lastev = eventno;
63849992Sbostic hp = gethent(sc);
63949992Sbostic if (hp == 0)
64049992Sbostic return;
64149992Sbostic hadhist = 1;
64249992Sbostic dol = 0;
64349992Sbostic if (hp == alhistp)
64449992Sbostic for (ip = hp->next->next; ip != alhistt; ip = ip->next)
64549992Sbostic dol++;
64649992Sbostic else
64749992Sbostic for (ip = hp->next->next; ip != hp->prev; ip = ip->next)
64849992Sbostic dol++;
64949992Sbostic left = 0, right = dol;
65049992Sbostic if (sc == HISTSUB) {
65149992Sbostic ungetC('s'), unreadc(HISTSUB), c = ':';
65249992Sbostic goto subst;
65349992Sbostic }
65449992Sbostic c = getC(0);
65549992Sbostic if (!any(":^$*-%", c))
65649992Sbostic goto subst;
65749992Sbostic left = right = -1;
65849992Sbostic if (c == ':') {
65949992Sbostic c = getC(0);
66049992Sbostic unreadc(c);
66149992Sbostic if (letter(c) || c == '&') {
66249992Sbostic c = ':';
66349992Sbostic left = 0, right = dol;
66449992Sbostic goto subst;
6651299Sbill }
66649992Sbostic }
66749992Sbostic else
66849992Sbostic ungetC(c);
66949992Sbostic if (!getsel(&left, &right, dol))
67049992Sbostic return;
67149992Sbostic c = getC(0);
67249992Sbostic if (c == '*')
67349992Sbostic ungetC(c), c = '-';
67449992Sbostic if (c == '-') {
6751299Sbill if (!getsel(&left, &right, dol))
67649992Sbostic return;
6771299Sbill c = getC(0);
67849992Sbostic }
6791299Sbill subst:
68049992Sbostic exclc = right - left + 1;
68149992Sbostic while (--left >= 0)
68249992Sbostic hp = hp->next;
68349992Sbostic if (sc == HISTSUB || c == ':') {
68449992Sbostic do {
68549992Sbostic hp = getsub(hp);
68649992Sbostic c = getC(0);
68749992Sbostic } while (c == ':');
68849992Sbostic }
68949992Sbostic unreadc(c);
69049992Sbostic if (sc == '{') {
69149992Sbostic c = getC(0);
69249992Sbostic if (c != '}')
69349992Sbostic seterror(ERR_BADBANG);
69449992Sbostic }
69549992Sbostic exclnxt = hp;
6961299Sbill }
6971299Sbill
69849992Sbostic static struct wordent *
getsub(en)6991299Sbill getsub(en)
70049992Sbostic struct wordent *en;
7011299Sbill {
70249992Sbostic register Char *cp;
70349992Sbostic int delim;
70449992Sbostic register int c;
70549992Sbostic int sc;
70651526Schristos bool global;
70749992Sbostic Char orhsb[sizeof(rhsb) / sizeof(Char)];
7081299Sbill
70950464Schristos do {
71050464Schristos exclnxt = 0;
71151526Schristos global = 0;
71250464Schristos sc = c = getC(0);
71351526Schristos if (c == 'g' || c == 'a') {
71451526Schristos global |= (c == 'g') ? 1 : 2;
71551526Schristos sc = c = getC(0);
71651526Schristos }
71751526Schristos if (((c =='g') && !(global & 1)) || ((c == 'a') && !(global & 2))) {
71851526Schristos global |= (c == 'g') ? 1 : 2;
71951526Schristos sc = c = getC(0);
72051526Schristos }
7211299Sbill
72250464Schristos switch (c) {
72350464Schristos case 'p':
72450464Schristos justpr++;
72550464Schristos return (en);
7261299Sbill
72750464Schristos case 'x':
72850464Schristos case 'q':
72951526Schristos global |= 1;
7301299Sbill
73150464Schristos /* fall into ... */
7321299Sbill
73350464Schristos case 'h':
73450464Schristos case 'r':
73550464Schristos case 't':
73650464Schristos case 'e':
73750464Schristos break;
7381299Sbill
73950464Schristos case '&':
74050464Schristos if (slhs[0] == 0) {
74150464Schristos seterror(ERR_NOSUBST);
74250464Schristos return (en);
74350464Schristos }
74450464Schristos (void) Strcpy(lhsb, slhs);
74550464Schristos break;
7461299Sbill
74749992Sbostic #ifdef notdef
74850464Schristos case '~':
74950464Schristos if (lhsb[0] == 0)
75050464Schristos goto badlhs;
75150464Schristos break;
75249992Sbostic #endif
75349992Sbostic
75450464Schristos case 's':
75550464Schristos delim = getC(0);
75650464Schristos if (letter(delim) || Isdigit(delim) || any(" \t\n", delim)) {
75750464Schristos unreadc(delim);
75849992Sbostic lhsb[0] = 0;
75949992Sbostic seterror(ERR_BADSUBST);
76049992Sbostic return (en);
76149992Sbostic }
76250464Schristos cp = lhsb;
76350464Schristos for (;;) {
76449992Sbostic c = getC(0);
76550464Schristos if (c == '\n') {
76650464Schristos unreadc(c);
76750464Schristos break;
76850464Schristos }
76950464Schristos if (c == delim)
77050464Schristos break;
77150464Schristos if (cp > &lhsb[sizeof(lhsb) / sizeof(Char) - 2]) {
77250464Schristos lhsb[0] = 0;
77350464Schristos seterror(ERR_BADSUBST);
77450464Schristos return (en);
77550464Schristos }
77650464Schristos if (c == '\\') {
77750464Schristos c = getC(0);
77850464Schristos if (c != delim && c != '\\')
77950464Schristos *cp++ = '\\';
78050464Schristos }
78150464Schristos *cp++ = c;
78249992Sbostic }
78350464Schristos if (cp != lhsb)
78450464Schristos *cp++ = 0;
78550464Schristos else if (lhsb[0] == 0) {
78650464Schristos seterror(ERR_LHS);
78750464Schristos return (en);
78849992Sbostic }
78950464Schristos cp = rhsb;
79050464Schristos (void) Strcpy(orhsb, cp);
79150464Schristos for (;;) {
79250464Schristos c = getC(0);
79350464Schristos if (c == '\n') {
79450464Schristos unreadc(c);
79550464Schristos break;
79650464Schristos }
79750464Schristos if (c == delim)
79850464Schristos break;
79949992Sbostic #ifdef notdef
80050464Schristos if (c == '~') {
80151437Sleres if (&cp[Strlen(orhsb)] > &rhsb[sizeof(rhsb) /
80250464Schristos sizeof(Char) - 2])
80350464Schristos goto toorhs;
80450464Schristos (void) Strcpy(cp, orhsb);
80550464Schristos cp = Strend(cp);
80650464Schristos continue;
80750464Schristos }
80849992Sbostic #endif
80950464Schristos if (cp > &rhsb[sizeof(rhsb) / sizeof(Char) - 2]) {
81050464Schristos seterror(ERR_RHSLONG);
81150464Schristos return (en);
81250464Schristos }
81350464Schristos if (c == '\\') {
81450464Schristos c = getC(0);
81550464Schristos if (c != delim /* && c != '~' */ )
81650464Schristos *cp++ = '\\';
81750464Schristos }
81850464Schristos *cp++ = c;
81949992Sbostic }
82050464Schristos *cp++ = 0;
82150464Schristos break;
82250464Schristos
82350464Schristos default:
82450464Schristos if (c == '\n')
82550464Schristos unreadc(c);
82650464Schristos seterror(ERR_BADBANGMOD, c);
82750464Schristos return (en);
82849992Sbostic }
82950464Schristos (void) Strcpy(slhs, lhsb);
83050464Schristos if (exclc)
83150464Schristos en = dosub(sc, en, global);
83249992Sbostic }
83350464Schristos while ((c = getC(0)) == ':');
83450464Schristos unreadc(c);
83549992Sbostic return (en);
8361299Sbill }
8371299Sbill
83849992Sbostic static struct wordent *
dosub(sc,en,global)8391299Sbill dosub(sc, en, global)
84049992Sbostic int sc;
84149992Sbostic struct wordent *en;
84249992Sbostic bool global;
8431299Sbill {
84449992Sbostic struct wordent lexi;
84551526Schristos bool didsub = 0, didone = 0;
84649992Sbostic struct wordent *hp = &lexi;
84749992Sbostic register struct wordent *wdp;
84849992Sbostic register int i = exclc;
8491299Sbill
85049992Sbostic wdp = hp;
85149992Sbostic while (--i >= 0) {
85251526Schristos register struct wordent *new =
85351526Schristos (struct wordent *) xcalloc(1, sizeof *wdp);
8541299Sbill
85549992Sbostic new->word = 0;
85649992Sbostic new->prev = wdp;
85749992Sbostic new->next = hp;
85849992Sbostic wdp->next = new;
85949992Sbostic wdp = new;
86049992Sbostic en = en->next;
86151526Schristos if (en->word) {
86251526Schristos Char *tword, *otword;
86351526Schristos
86451526Schristos if ((global & 1) || didsub == 0) {
86551526Schristos tword = subword(en->word, sc, &didone);
86651526Schristos if (didone)
86751526Schristos didsub = 1;
86851526Schristos if (global & 2) {
86951526Schristos while (didone && tword != STRNULL) {
87051526Schristos otword = tword;
87151526Schristos tword = subword(otword, sc, &didone);
87251526Schristos if (Strcmp(tword, otword) == 0) {
87351526Schristos xfree((ptr_t) otword);
87451526Schristos break;
87551526Schristos }
87651526Schristos else
87751526Schristos xfree((ptr_t) otword);
87851526Schristos }
87951526Schristos }
88051526Schristos }
88151526Schristos else
88251526Schristos tword = Strsave(en->word);
88351526Schristos wdp->word = tword;
88451526Schristos }
88549992Sbostic }
88649992Sbostic if (didsub == 0)
88749992Sbostic seterror(ERR_MODFAIL);
88849992Sbostic hp->prev = wdp;
88949992Sbostic return (&enthist(-1000, &lexi, 0)->Hlex);
8901299Sbill }
8911299Sbill
89249992Sbostic static Char *
subword(cp,type,adid)8931299Sbill subword(cp, type, adid)
89449992Sbostic Char *cp;
89549992Sbostic int type;
89649992Sbostic bool *adid;
8971299Sbill {
89849992Sbostic Char wbuf[BUFSIZ];
89949992Sbostic register Char *wp, *mp, *np;
90049992Sbostic register int i;
9011299Sbill
90251526Schristos *adid = 0;
90349992Sbostic switch (type) {
9041299Sbill
90549992Sbostic case 'r':
90649992Sbostic case 'e':
90749992Sbostic case 'h':
90849992Sbostic case 't':
90949992Sbostic case 'q':
91049992Sbostic case 'x':
91149992Sbostic wp = domod(cp, type);
91249992Sbostic if (wp == 0)
91349992Sbostic return (Strsave(cp));
91449992Sbostic *adid = 1;
91549992Sbostic return (wp);
9161299Sbill
91749992Sbostic default:
91849992Sbostic wp = wbuf;
91949992Sbostic i = BUFSIZ - 4;
92049992Sbostic for (mp = cp; *mp; mp++)
92149992Sbostic if (matchs(mp, lhsb)) {
92249992Sbostic for (np = cp; np < mp;)
92349992Sbostic *wp++ = *np++, --i;
92449992Sbostic for (np = rhsb; *np; np++)
92549992Sbostic switch (*np) {
9261299Sbill
92749992Sbostic case '\\':
92849992Sbostic if (np[1] == '&')
92949992Sbostic np++;
93049992Sbostic /* fall into ... */
9311299Sbill
93249992Sbostic default:
93349992Sbostic if (--i < 0) {
93449992Sbostic seterror(ERR_SUBOVFL);
93549992Sbostic return (STRNULL);
93649992Sbostic }
93749992Sbostic *wp++ = *np;
93849992Sbostic continue;
9391299Sbill
94049992Sbostic case '&':
94149992Sbostic i -= Strlen(lhsb);
94249992Sbostic if (i < 0) {
94349992Sbostic seterror(ERR_SUBOVFL);
94449992Sbostic return (STRNULL);
9451299Sbill }
94649992Sbostic *wp = 0;
94749992Sbostic (void) Strcat(wp, lhsb);
94849992Sbostic wp = Strend(wp);
94949992Sbostic continue;
95049992Sbostic }
95149992Sbostic mp += Strlen(lhsb);
95249992Sbostic i -= Strlen(mp);
95349992Sbostic if (i < 0) {
95449992Sbostic seterror(ERR_SUBOVFL);
95549992Sbostic return (STRNULL);
95649992Sbostic }
95749992Sbostic *wp = 0;
95849992Sbostic (void) Strcat(wp, mp);
95949992Sbostic *adid = 1;
96049992Sbostic return (Strsave(wbuf));
96149992Sbostic }
96249992Sbostic return (Strsave(cp));
96349992Sbostic }
9641299Sbill }
9651299Sbill
96649992Sbostic Char *
domod(cp,type)9671299Sbill domod(cp, type)
96849992Sbostic Char *cp;
96949992Sbostic int type;
9701299Sbill {
97149992Sbostic register Char *wp, *xp;
97249992Sbostic register int c;
9731299Sbill
97449992Sbostic switch (type) {
9751299Sbill
97649992Sbostic case 'x':
97749992Sbostic case 'q':
97849992Sbostic wp = Strsave(cp);
97960237Schristos for (xp = wp; (c = *xp) != '\0'; xp++)
98049992Sbostic if ((c != ' ' && c != '\t') || type == 'q')
98149992Sbostic *xp |= QUOTE;
98249992Sbostic return (wp);
9831299Sbill
98449992Sbostic case 'h':
98549992Sbostic case 't':
98649992Sbostic if (!any(short2str(cp), '/'))
98749992Sbostic return (type == 't' ? Strsave(cp) : 0);
98849992Sbostic wp = Strend(cp);
98949992Sbostic while (*--wp != '/')
99049992Sbostic continue;
99149992Sbostic if (type == 'h')
99249992Sbostic xp = Strsave(cp), xp[wp - cp] = 0;
99349992Sbostic else
99449992Sbostic xp = Strsave(wp + 1);
99549992Sbostic return (xp);
99649992Sbostic
99749992Sbostic case 'e':
99849992Sbostic case 'r':
99949992Sbostic wp = Strend(cp);
100049992Sbostic for (wp--; wp >= cp && *wp != '/'; wp--)
100149992Sbostic if (*wp == '.') {
100249992Sbostic if (type == 'e')
100349992Sbostic xp = Strsave(wp + 1);
10041299Sbill else
100549992Sbostic xp = Strsave(cp), xp[wp - cp] = 0;
10061299Sbill return (xp);
100749992Sbostic }
100849992Sbostic return (Strsave(type == 'e' ? STRNULL : cp));
100951526Schristos default:
101051526Schristos break;
101149992Sbostic }
101249992Sbostic return (0);
10131299Sbill }
10141299Sbill
101549992Sbostic static int
matchs(str,pat)10161299Sbill matchs(str, pat)
101749992Sbostic register Char *str, *pat;
10181299Sbill {
101949992Sbostic while (*str && *pat && *str == *pat)
102049992Sbostic str++, pat++;
102149992Sbostic return (*pat == 0);
10221299Sbill }
10231299Sbill
102449992Sbostic static int
getsel(al,ar,dol)10251299Sbill getsel(al, ar, dol)
102649992Sbostic register int *al, *ar;
102749992Sbostic int dol;
10281299Sbill {
102949992Sbostic register int c = getC(0);
103049992Sbostic register int i;
103149992Sbostic bool first = *al < 0;
10321299Sbill
103349992Sbostic switch (c) {
10341299Sbill
103549992Sbostic case '%':
103649992Sbostic if (quesarg == -1) {
103749992Sbostic seterror(ERR_BADBANGARG);
103849992Sbostic return (0);
103949992Sbostic }
104049992Sbostic if (*al < 0)
104149992Sbostic *al = quesarg;
104249992Sbostic *ar = quesarg;
104349992Sbostic break;
10441299Sbill
104549992Sbostic case '-':
104649992Sbostic if (*al < 0) {
104749992Sbostic *al = 0;
104849992Sbostic *ar = dol - 1;
104949992Sbostic unreadc(c);
105049992Sbostic }
105149992Sbostic return (1);
10521299Sbill
105349992Sbostic case '^':
105449992Sbostic if (*al < 0)
105549992Sbostic *al = 1;
105649992Sbostic *ar = 1;
105749992Sbostic break;
10581299Sbill
105949992Sbostic case '$':
106049992Sbostic if (*al < 0)
106149992Sbostic *al = dol;
106249992Sbostic *ar = dol;
106349992Sbostic break;
10641299Sbill
106549992Sbostic case '*':
106649992Sbostic if (*al < 0)
106749992Sbostic *al = 1;
106849992Sbostic *ar = dol;
106949992Sbostic if (*ar < *al) {
107049992Sbostic *ar = 0;
107149992Sbostic *al = 1;
107249992Sbostic return (1);
107349992Sbostic }
107449992Sbostic break;
10751299Sbill
107649992Sbostic default:
107749992Sbostic if (Isdigit(c)) {
107849992Sbostic i = 0;
107949992Sbostic while (Isdigit(c)) {
108049992Sbostic i = i * 10 + c - '0';
10811299Sbill c = getC(0);
108249992Sbostic }
108349992Sbostic if (i < 0)
108449992Sbostic i = dol + 1;
108549992Sbostic if (*al < 0)
108649992Sbostic *al = i;
108749992Sbostic *ar = i;
10881299Sbill }
108949992Sbostic else if (*al < 0)
109049992Sbostic *al = 0, *ar = dol;
109149992Sbostic else
109249992Sbostic *ar = dol - 1;
109349992Sbostic unreadc(c);
109449992Sbostic break;
109549992Sbostic }
109649992Sbostic if (first) {
109749992Sbostic c = getC(0);
109849992Sbostic unreadc(c);
109949992Sbostic if (any("-$*", c))
110049992Sbostic return (1);
110149992Sbostic }
110249992Sbostic if (*al > *ar || *ar > dol) {
110349992Sbostic seterror(ERR_BADBANGARG);
110449992Sbostic return (0);
110549992Sbostic }
110649992Sbostic return (1);
11071299Sbill
11081299Sbill }
11091299Sbill
111049992Sbostic static struct wordent *
gethent(sc)11111299Sbill gethent(sc)
111249992Sbostic int sc;
11131299Sbill {
111449992Sbostic register struct Hist *hp;
111549992Sbostic register Char *np;
111649992Sbostic register int c;
111749992Sbostic int event;
111849992Sbostic bool back = 0;
11191299Sbill
112049992Sbostic c = sc == HISTSUB ? HIST : getC(0);
112149992Sbostic if (c == HIST) {
112249992Sbostic if (alhistp)
112349992Sbostic return (alhistp);
112449992Sbostic event = eventno;
112549992Sbostic }
112649992Sbostic else
11271299Sbill switch (c) {
11281299Sbill
11291299Sbill case ':':
11301299Sbill case '^':
11311299Sbill case '$':
11321299Sbill case '*':
11331299Sbill case '%':
113449992Sbostic ungetC(c);
113549992Sbostic if (lastev == eventno && alhistp)
113649992Sbostic return (alhistp);
113749992Sbostic event = lastev;
113849992Sbostic break;
11391299Sbill
114049992Sbostic case '#': /* !# is command being typed in (mrh) */
114149992Sbostic if (--hleft == 0) {
114249992Sbostic seterror(ERR_HISTLOOP);
114349992Sbostic return (0);
114449992Sbostic }
114549992Sbostic else
114649992Sbostic return (¶ml);
114749992Sbostic /* NOTREACHED */
114849992Sbostic
11491299Sbill case '-':
115049992Sbostic back = 1;
115149992Sbostic c = getC(0);
115249992Sbostic /* FALLSTHROUGH */
11531299Sbill
11541299Sbill default:
115549992Sbostic if (any("(=~", c)) {
11561299Sbill unreadc(c);
115749992Sbostic ungetC(HIST);
115849992Sbostic return (0);
115949992Sbostic }
116049992Sbostic np = lhsb;
116149992Sbostic event = 0;
116260488Schristos while (!cmap(c, _ESC | _META | _QF | _QB) && !any("${}:", c)) {
116349992Sbostic if (event != -1 && Isdigit(c))
116449992Sbostic event = event * 10 + c - '0';
116549992Sbostic else
116649992Sbostic event = -1;
116749992Sbostic if (np < &lhsb[sizeof(lhsb) / sizeof(Char) - 2])
116849992Sbostic *np++ = c;
116949992Sbostic c = getC(0);
117049992Sbostic }
117149992Sbostic unreadc(c);
117249992Sbostic if (np == lhsb) {
117349992Sbostic ungetC(HIST);
117449992Sbostic return (0);
117549992Sbostic }
117649992Sbostic *np++ = 0;
117749992Sbostic if (event != -1) {
117849992Sbostic /*
117949992Sbostic * History had only digits
118049992Sbostic */
118149992Sbostic if (back)
118249992Sbostic event = eventno + (alhistp == 0) - (event ? event : 0);
118349992Sbostic break;
118449992Sbostic }
118549992Sbostic hp = findev(lhsb, 0);
118649992Sbostic if (hp)
118749992Sbostic lastev = hp->Hnum;
118849992Sbostic return (&hp->Hlex);
11891299Sbill
11901299Sbill case '?':
119149992Sbostic np = lhsb;
119249992Sbostic for (;;) {
119349992Sbostic c = getC(0);
119449992Sbostic if (c == '\n') {
119549992Sbostic unreadc(c);
119649992Sbostic break;
11971299Sbill }
119849992Sbostic if (c == '?')
119949992Sbostic break;
120049992Sbostic if (np < &lhsb[sizeof(lhsb) / sizeof(Char) - 2])
120149992Sbostic *np++ = c;
120249992Sbostic }
120349992Sbostic if (np == lhsb) {
120449992Sbostic if (lhsb[0] == 0) {
120549992Sbostic seterror(ERR_NOSEARCH);
120649992Sbostic return (0);
12071299Sbill }
120849992Sbostic }
120949992Sbostic else
121049992Sbostic *np++ = 0;
121149992Sbostic hp = findev(lhsb, 1);
121249992Sbostic if (hp)
121349992Sbostic lastev = hp->Hnum;
121449992Sbostic return (&hp->Hlex);
12151299Sbill }
121649992Sbostic
121749992Sbostic for (hp = Histlist.Hnext; hp; hp = hp->Hnext)
121849992Sbostic if (hp->Hnum == event) {
121949992Sbostic hp->Href = eventno;
122049992Sbostic lastev = hp->Hnum;
122149992Sbostic return (&hp->Hlex);
122249992Sbostic }
122349992Sbostic np = putn(event);
122451589Schristos seterror(ERR_NOEVENT, vis_str(np));
122549992Sbostic return (0);
12261299Sbill }
12271299Sbill
122849992Sbostic static struct Hist *
findev(cp,anyarg)12291299Sbill findev(cp, anyarg)
123049992Sbostic Char *cp;
123149992Sbostic bool anyarg;
12321299Sbill {
123349992Sbostic register struct Hist *hp;
12341299Sbill
123549992Sbostic for (hp = Histlist.Hnext; hp; hp = hp->Hnext) {
123649992Sbostic Char *dp;
123749992Sbostic register Char *p, *q;
123849992Sbostic register struct wordent *lp = hp->Hlex.next;
123949992Sbostic int argno = 0;
124017517Sedward
124149992Sbostic /*
124249992Sbostic * The entries added by alias substitution don't have a newline but do
124349992Sbostic * have a negative event number. Savehist() trims off these entries,
124449992Sbostic * but it happens before alias expansion, too early to delete those
124549992Sbostic * from the previous command.
124649992Sbostic */
124749992Sbostic if (hp->Hnum < 0)
124849992Sbostic continue;
124949992Sbostic if (lp->word[0] == '\n')
125049992Sbostic continue;
125149992Sbostic if (!anyarg) {
125249992Sbostic p = cp;
125349992Sbostic q = lp->word;
125449992Sbostic do
125549992Sbostic if (!*p)
125649992Sbostic return (hp);
125749992Sbostic while (*p++ == *q++);
125849992Sbostic continue;
125917517Sedward }
126049992Sbostic do {
126149992Sbostic for (dp = lp->word; *dp; dp++) {
126249992Sbostic p = cp;
126349992Sbostic q = dp;
126449992Sbostic do
126549992Sbostic if (!*p) {
126649992Sbostic quesarg = argno;
126749992Sbostic return (hp);
126849992Sbostic }
126949992Sbostic while (*p++ == *q++);
127049992Sbostic }
127149992Sbostic lp = lp->next;
127249992Sbostic argno++;
127349992Sbostic } while (lp->word[0] != '\n');
127449992Sbostic }
127551589Schristos seterror(ERR_NOEVENT, vis_str(cp));
127649992Sbostic return (0);
12771299Sbill }
12781299Sbill
12791299Sbill
128049992Sbostic static void
setexclp(cp)12811299Sbill setexclp(cp)
128249992Sbostic register Char *cp;
12831299Sbill {
128449992Sbostic if (cp && cp[0] == '\n')
128549992Sbostic return;
128649992Sbostic exclp = cp;
12871299Sbill }
12881299Sbill
128949992Sbostic void
unreadc(c)12901299Sbill unreadc(c)
129150023Sbostic int c;
12921299Sbill {
129349992Sbostic peekread = c;
12941299Sbill }
12951299Sbill
129649992Sbostic int
readc(wanteof)12971299Sbill readc(wanteof)
129849992Sbostic bool wanteof;
12991299Sbill {
130049992Sbostic register int c;
130149992Sbostic static sincereal;
13021299Sbill
130350944Schristos aret = F_SEEK;
130460237Schristos if ((c = peekread) != '\0') {
130549992Sbostic peekread = 0;
130649992Sbostic return (c);
130749992Sbostic }
13081299Sbill top:
130950944Schristos aret = F_SEEK;
131049992Sbostic if (alvecp) {
131150944Schristos aret = A_SEEK;
131260237Schristos if ((c = *alvecp++) != '\0')
131349992Sbostic return (c);
131450895Schristos if (alvec && *alvec) {
131550944Schristos alvecp = *alvec++;
131650944Schristos return (' ');
13171299Sbill }
131850944Schristos else {
131950944Schristos aret = F_SEEK;
132050944Schristos alvecp = NULL;
132150944Schristos return('\n');
132250944Schristos }
132349992Sbostic }
132449992Sbostic if (alvec) {
132560237Schristos if ((alvecp = *alvec) != '\0') {
132649992Sbostic alvec++;
132749992Sbostic goto top;
13281299Sbill }
132949992Sbostic /* Infinite source! */
133049992Sbostic return ('\n');
133149992Sbostic }
133249992Sbostic if (evalp) {
133350944Schristos aret = E_SEEK;
133460237Schristos if ((c = *evalp++) != '\0')
133549992Sbostic return (c);
133650944Schristos if (evalvec && *evalvec) {
133749992Sbostic evalp = *evalvec++;
133849992Sbostic return (' ');
13391299Sbill }
134050944Schristos aret = F_SEEK;
134149992Sbostic evalp = 0;
134249992Sbostic }
134349992Sbostic if (evalvec) {
134449992Sbostic if (evalvec == (Char **) 1) {
134549992Sbostic doneinp = 1;
134649992Sbostic reset();
134749992Sbostic }
134860237Schristos if ((evalp = *evalvec) != '\0') {
134949992Sbostic evalvec++;
135049992Sbostic goto top;
135149992Sbostic }
135249992Sbostic evalvec = (Char **) 1;
135349992Sbostic return ('\n');
135449992Sbostic }
135549992Sbostic do {
135649992Sbostic if (arginp == (Char *) 1 || onelflg == 1) {
135749992Sbostic if (wanteof)
135849992Sbostic return (-1);
135949992Sbostic exitstat();
136049992Sbostic }
136149992Sbostic if (arginp) {
136249992Sbostic if ((c = *arginp++) == 0) {
136349992Sbostic arginp = (Char *) 1;
13641299Sbill return ('\n');
136549992Sbostic }
136649992Sbostic return (c);
13671299Sbill }
13681299Sbill reread:
136949992Sbostic c = bgetc();
137049992Sbostic if (c < 0) {
137149992Sbostic struct termios tty;
137249992Sbostic if (wanteof)
137349992Sbostic return (-1);
137449992Sbostic /* was isatty but raw with ignoreeof yields problems */
137549992Sbostic if (tcgetattr(SHIN, &tty) == 0 && (tty.c_lflag & ICANON))
137649992Sbostic {
137749992Sbostic /* was 'short' for FILEC */
137849992Sbostic int ctpgrp;
13791299Sbill
138049992Sbostic if (++sincereal > 25)
138149992Sbostic goto oops;
138249992Sbostic if (tpgrp != -1 &&
138349992Sbostic (ctpgrp = tcgetpgrp(FSHTTY)) != -1 &&
138449992Sbostic tpgrp != ctpgrp) {
138549992Sbostic (void) tcsetpgrp(FSHTTY, tpgrp);
138649992Sbostic (void) killpg((pid_t) ctpgrp, SIGHUP);
138751437Sleres (void) fprintf(csherr, "Reset tty pgrp from %d to %d\n",
138850439Schristos ctpgrp, tpgrp);
138949992Sbostic goto reread;
13901299Sbill }
139149992Sbostic if (adrof(STRignoreeof)) {
139249992Sbostic if (loginsh)
139350439Schristos (void) fprintf(csherr,"\nUse \"logout\" to logout.\n");
139449992Sbostic else
139550439Schristos (void) fprintf(csherr,"\nUse \"exit\" to leave csh.\n");
139649992Sbostic reset();
139749992Sbostic }
139849992Sbostic if (chkstop == 0)
139949992Sbostic panystop(1);
140049992Sbostic }
140149992Sbostic oops:
140249992Sbostic doneinp = 1;
140349992Sbostic reset();
140449992Sbostic }
140549992Sbostic sincereal = 0;
140649992Sbostic if (c == '\n' && onelflg)
140749992Sbostic onelflg--;
140849992Sbostic } while (c == 0);
140949992Sbostic return (c);
14101299Sbill }
14111299Sbill
141249992Sbostic static int
bgetc()14131299Sbill bgetc()
14141299Sbill {
141549992Sbostic register int buf, off, c;
141649992Sbostic
141715376Slayer #ifdef FILEC
141849992Sbostic register int numleft = 0, roomleft;
141949992Sbostic Char ttyline[BUFSIZ];
142017148Ssam #endif
142149992Sbostic char tbuf[BUFSIZ + 1];
14221299Sbill
142349992Sbostic if (cantell) {
142449992Sbostic if (fseekp < fbobp || fseekp > feobp) {
142549992Sbostic fbobp = feobp = fseekp;
142649992Sbostic (void) lseek(SHIN, fseekp, L_SET);
14271299Sbill }
142849992Sbostic if (fseekp == feobp) {
142949992Sbostic int i;
143049992Sbostic
143149992Sbostic fbobp = feobp;
143249992Sbostic do
143349992Sbostic c = read(SHIN, tbuf, BUFSIZ);
143449992Sbostic while (c < 0 && errno == EINTR);
143549992Sbostic if (c <= 0)
143649992Sbostic return (-1);
143749992Sbostic for (i = 0; i < c; i++)
143849992Sbostic fbuf[0][i] = (unsigned char) tbuf[i];
143949992Sbostic feobp += c;
144049992Sbostic }
144149992Sbostic c = fbuf[0][fseekp - fbobp];
144249992Sbostic fseekp++;
144349992Sbostic return (c);
144449992Sbostic }
144549992Sbostic
14461299Sbill again:
144749992Sbostic buf = (int) fseekp / BUFSIZ;
144849992Sbostic if (buf >= fblocks) {
144949992Sbostic register Char **nfbuf =
145049992Sbostic (Char **) xcalloc((size_t) (fblocks + 2),
145149992Sbostic sizeof(Char **));
14521299Sbill
145349992Sbostic if (fbuf) {
145449992Sbostic (void) blkcpy(nfbuf, fbuf);
145549992Sbostic xfree((ptr_t) fbuf);
145649992Sbostic }
145749992Sbostic fbuf = nfbuf;
145849992Sbostic fbuf[fblocks] = (Char *) xcalloc(BUFSIZ, sizeof(Char));
145949992Sbostic fblocks++;
146049992Sbostic if (!intty)
146149992Sbostic goto again;
146249992Sbostic }
146349992Sbostic if (fseekp >= feobp) {
146449992Sbostic buf = (int) feobp / BUFSIZ;
146549992Sbostic off = (int) feobp % BUFSIZ;
146649992Sbostic roomleft = BUFSIZ - off;
146749992Sbostic
146849992Sbostic #ifdef FILEC
146949992Sbostic roomleft = BUFSIZ - off;
147049992Sbostic for (;;) {
147149992Sbostic if (filec && intty) {
147249992Sbostic c = numleft ? numleft : tenex(ttyline, BUFSIZ);
147349992Sbostic if (c > roomleft) {
147449992Sbostic /* start with fresh buffer */
147549992Sbostic feobp = fseekp = fblocks * BUFSIZ;
147649992Sbostic numleft = c;
147749992Sbostic goto again;
14781299Sbill }
147949992Sbostic if (c > 0)
1480*69126Schristos memmove(fbuf[buf] + off, ttyline, c * sizeof(Char));
148149992Sbostic numleft = 0;
148249992Sbostic }
148349992Sbostic else {
148417148Ssam #endif
148549992Sbostic c = read(SHIN, tbuf, roomleft);
148649992Sbostic if (c > 0) {
148749992Sbostic int i;
148849992Sbostic Char *ptr = fbuf[buf] + off;
148917884Sedward
149049992Sbostic for (i = 0; i < c; i++)
149149992Sbostic ptr[i] = (unsigned char) tbuf[i];
149217884Sedward }
149349992Sbostic #ifdef FILEC
149449992Sbostic }
149549992Sbostic #endif
149649992Sbostic if (c >= 0)
149749992Sbostic break;
149849992Sbostic if (errno == EWOULDBLOCK) {
149949992Sbostic int off = 0;
150049992Sbostic
150149992Sbostic (void) ioctl(SHIN, FIONBIO, (ioctl_t) & off);
150249992Sbostic }
150349992Sbostic else if (errno != EINTR)
150449992Sbostic break;
150549992Sbostic }
150649992Sbostic if (c <= 0)
150749992Sbostic return (-1);
150849992Sbostic feobp += c;
150915376Slayer #ifndef FILEC
151049992Sbostic goto again;
151117148Ssam #else
151249992Sbostic if (filec && !intty)
151349992Sbostic goto again;
151417148Ssam #endif
151549992Sbostic }
151649992Sbostic c = fbuf[buf][(int) fseekp % BUFSIZ];
151749992Sbostic fseekp++;
151849992Sbostic return (c);
15191299Sbill }
15201299Sbill
152149992Sbostic static void
bfree()15221299Sbill bfree()
15231299Sbill {
152449992Sbostic register int sb, i;
15251299Sbill
152649992Sbostic if (cantell)
152749992Sbostic return;
152849992Sbostic if (whyles)
152949992Sbostic return;
153049992Sbostic sb = (int) (fseekp - 1) / BUFSIZ;
153149992Sbostic if (sb > 0) {
153249992Sbostic for (i = 0; i < sb; i++)
153349992Sbostic xfree((ptr_t) fbuf[i]);
153449992Sbostic (void) blkcpy(fbuf, &fbuf[sb]);
153549992Sbostic fseekp -= BUFSIZ * sb;
153649992Sbostic feobp -= BUFSIZ * sb;
153749992Sbostic fblocks -= sb;
153849992Sbostic }
15391299Sbill }
15401299Sbill
154149992Sbostic void
bseek(l)15421299Sbill bseek(l)
154350944Schristos struct Ain *l;
154450944Schristos {
154550944Schristos switch (aret = l->type) {
154650944Schristos case E_SEEK:
154750944Schristos evalvec = l->a_seek;
154858876Schristos evalp = l->c_seek;
154950944Schristos return;
155050944Schristos case A_SEEK:
155150944Schristos alvec = l->a_seek;
155258876Schristos alvecp = l->c_seek;
155350944Schristos return;
155451437Sleres case F_SEEK:
155550944Schristos fseekp = l->f_seek;
155650944Schristos return;
155750944Schristos default:
155850944Schristos (void) fprintf(csherr, "Bad seek type %d\n", aret);
155950944Schristos abort();
156050944Schristos }
156150944Schristos }
156249992Sbostic
156350944Schristos void
btell(l)156450944Schristos btell(l)
156550944Schristos struct Ain *l;
15661299Sbill {
156750944Schristos switch (l->type = aret) {
156850944Schristos case E_SEEK:
156950944Schristos l->a_seek = evalvec;
157058876Schristos l->c_seek = evalp;
157150944Schristos return;
157250944Schristos case A_SEEK:
157350944Schristos l->a_seek = alvec;
157458876Schristos l->c_seek = alvecp;
157550944Schristos return;
157650944Schristos case F_SEEK:
157750944Schristos l->f_seek = fseekp;
157850944Schristos l->a_seek = NULL;
157950944Schristos return;
158050944Schristos default:
158150944Schristos (void) fprintf(csherr, "Bad seek type %d\n", aret);
158250944Schristos abort();
158349992Sbostic }
15841299Sbill }
15851299Sbill
158649992Sbostic void
btoeof()15871299Sbill btoeof()
15881299Sbill {
158949992Sbostic (void) lseek(SHIN, (off_t) 0, L_XTND);
159050948Schristos aret = F_SEEK;
159149992Sbostic fseekp = feobp;
159250948Schristos alvec = NULL;
159350948Schristos alvecp = NULL;
159450948Schristos evalvec = NULL;
159550948Schristos evalp = NULL;
159649992Sbostic wfree();
159749992Sbostic bfree();
15981299Sbill }
15991299Sbill
160049992Sbostic void
settell()16011299Sbill settell()
16021299Sbill {
160349992Sbostic cantell = 0;
160449992Sbostic if (arginp || onelflg || intty)
160549992Sbostic return;
160649992Sbostic if (lseek(SHIN, (off_t) 0, L_INCR) < 0 || errno == ESPIPE)
160749992Sbostic return;
160849992Sbostic fbuf = (Char **) xcalloc(2, sizeof(Char **));
160949992Sbostic fblocks = 1;
161049992Sbostic fbuf[0] = (Char *) xcalloc(BUFSIZ, sizeof(Char));
161149992Sbostic fseekp = fbobp = feobp = lseek(SHIN, (off_t) 0, L_INCR);
161249992Sbostic cantell = 1;
161349992Sbostic }
1614