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