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