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