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