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