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