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