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