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