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