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