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