1 /* $NetBSD: lex.c,v 1.31 2013/08/06 05:42:43 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.31 2013/08/06 05:42:43 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 int peekc = 0, peekd = 0;
93 static int 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 int 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
lex(struct wordent * hp)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 = xmalloc(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
prlex(FILE * fp,struct wordent * sp0)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
sprlex(char ** s,struct wordent * sp0)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
copylex(struct wordent * hp,struct wordent * fp)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 = xmalloc(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
freelex(struct wordent * vp)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 *
word(void)257 word(void)
258 {
259 Char wbuf[BUFSIZE], *wp;
260 int i, c, c1;
261 int dolflg;
262
263 wp = wbuf;
264 i = BUFSIZE - 4;
265 loop:
266 while ((c = getC(DOALL)) == ' ' || c == '\t')
267 continue;
268 if (cmap(c, _META | _ESC))
269 switch (c) {
270 case '&':
271 case '|':
272 case '<':
273 case '>':
274 *wp++ = (Char)c;
275 c1 = getC(DOALL);
276 if (c1 == c)
277 *wp++ = (Char)c1;
278 else
279 ungetC(c1);
280 goto ret;
281
282 case '#':
283 if (intty)
284 break;
285 c = 0;
286 do {
287 c1 = c;
288 c = getC(0);
289 } while (c != '\n');
290 if (c1 == '\\')
291 goto loop;
292 /* FALLTHROUGH */
293
294 case ';':
295 case '(':
296 case ')':
297 case '\n':
298 *wp++ = (Char)c;
299 goto ret;
300
301 case '\\':
302 c = getC(0);
303 if (c == '\n') {
304 if (onelflg == 1)
305 onelflg = 2;
306 goto loop;
307 }
308 if (c != HIST)
309 *wp++ = '\\', --i;
310 c |= QUOTE;
311 break;
312 }
313 c1 = 0;
314 dolflg = DOALL;
315 for (;;) {
316 if (c1) {
317 if (c == c1) {
318 c1 = 0;
319 dolflg = DOALL;
320 }
321 else if (c == '\\') {
322 c = getC(0);
323 if (c == HIST)
324 c |= QUOTE;
325 else {
326 if (c == '\n')
327 /*
328 * if (c1 == '`') c = ' '; else
329 */
330 c |= QUOTE;
331 ungetC(c);
332 c = '\\';
333 }
334 }
335 else if (c == '\n') {
336 seterror(ERR_UNMATCHED, c1);
337 ungetC(c);
338 break;
339 }
340 }
341 else if (cmap(c, _META | _QF | _QB | _ESC)) {
342 if (c == '\\') {
343 c = getC(0);
344 if (c == '\n') {
345 if (onelflg == 1)
346 onelflg = 2;
347 break;
348 }
349 if (c != HIST)
350 *wp++ = '\\', --i;
351 c |= QUOTE;
352 }
353 else if (cmap(c, _QF | _QB)) { /* '"` */
354 c1 = c;
355 dolflg = c == '"' ? DOALL : DOEXCL;
356 }
357 else if (c != '#' || !intty) {
358 ungetC(c);
359 break;
360 }
361 }
362 if (--i > 0) {
363 *wp++ = (Char)c;
364 c = getC(dolflg);
365 }
366 else {
367 seterror(ERR_WTOOLONG);
368 wp = &wbuf[1];
369 break;
370 }
371 }
372 ret:
373 *wp = 0;
374 return (Strsave(wbuf));
375 }
376
377 static int
getC1(int flag)378 getC1(int flag)
379 {
380 int c;
381
382 for (;;) {
383 if ((c = peekc) != '\0') {
384 peekc = 0;
385 return (c);
386 }
387 if (lap) {
388 if ((c = *lap++) == 0)
389 lap = 0;
390 else {
391 if (cmap(c, _META | _QF | _QB))
392 c |= QUOTE;
393 return (c);
394 }
395 }
396 if ((c = peekd) != '\0') {
397 peekd = 0;
398 return (c);
399 }
400 if (exclp) {
401 if ((c = *exclp++) != '\0')
402 return (c);
403 if (exclnxt && --exclc >= 0) {
404 exclnxt = exclnxt->next;
405 setexclp(exclnxt->word);
406 return (' ');
407 }
408 exclp = 0;
409 exclnxt = 0;
410 }
411 if (exclnxt) {
412 exclnxt = exclnxt->next;
413 if (--exclc < 0)
414 exclnxt = 0;
415 else
416 setexclp(exclnxt->word);
417 continue;
418 }
419 c = readc(0);
420 if (c == '$' && (flag & DODOL)) {
421 getdol();
422 continue;
423 }
424 if (c == HIST && (flag & DOEXCL)) {
425 getexcl(0);
426 continue;
427 }
428 break;
429 }
430 return (c);
431 }
432
433 static void
getdol(void)434 getdol(void)
435 {
436 Char name[4*MAXVARLEN+1], *ep, *np;
437 int c, sc;
438 int special, toolong;
439
440 special = 0;
441 np = name, *np++ = '$';
442 c = sc = getC(DOEXCL);
443 if (any("\t \n", c)) {
444 ungetD(c);
445 ungetC('$' | QUOTE);
446 return;
447 }
448 if (c == '{')
449 *np++ = (Char)c, c = getC(DOEXCL);
450 if (c == '#' || c == '?')
451 special++, *np++ = (Char)c, c = getC(DOEXCL);
452 *np++ = (Char)c;
453 switch (c) {
454 case '<':
455 case '$':
456 case '!':
457 if (special)
458 seterror(ERR_SPDOLLT);
459 *np = 0;
460 addla(name);
461 return;
462 case '\n':
463 ungetD(c);
464 np--;
465 seterror(ERR_NEWLINE);
466 *np = 0;
467 addla(name);
468 return;
469 case '*':
470 if (special)
471 seterror(ERR_SPSTAR);
472 *np = 0;
473 addla(name);
474 return;
475 default:
476 toolong = 0;
477 if (Isdigit(c)) {
478 #ifdef notdef
479 /* let $?0 pass for now */
480 if (special) {
481 seterror(ERR_DIGIT);
482 *np = 0;
483 addla(name);
484 return;
485 }
486 #endif
487 /* we know that np < &name[4] */
488 ep = &np[MAXVARLEN];
489 while ((c = getC(DOEXCL)) != '\0'){
490 if (!Isdigit(c))
491 break;
492 if (np < ep)
493 *np++ = (Char)c;
494 else
495 toolong = 1;
496 }
497 }
498 else if (letter(c)) {
499 /* we know that np < &name[4] */
500 ep = &np[MAXVARLEN];
501 toolong = 0;
502 while ((c = getC(DOEXCL)) != '\0') {
503 /* Bugfix for ${v123x} from Chris Torek, DAS DEC-90. */
504 if (!letter(c) && !Isdigit(c))
505 break;
506 if (np < ep)
507 *np++ = (Char)c;
508 else
509 toolong = 1;
510 }
511 }
512 else {
513 *np = 0;
514 seterror(ERR_VARILL);
515 addla(name);
516 return;
517 }
518 if (toolong) {
519 seterror(ERR_VARTOOLONG);
520 *np = 0;
521 addla(name);
522 return;
523 }
524 break;
525 }
526 if (c == '[') {
527 *np++ = (Char)c;
528 /*
529 * Name up to here is a max of MAXVARLEN + 8.
530 */
531 ep = &np[2 * MAXVARLEN + 8];
532 do {
533 /*
534 * Michael Greim: Allow $ expansion to take place in selector
535 * expressions. (limits the number of characters returned)
536 */
537 c = getC(DOEXCL | DODOL);
538 if (c == '\n') {
539 ungetD(c);
540 np--;
541 seterror(ERR_NLINDEX);
542 *np = 0;
543 addla(name);
544 return;
545 }
546 if (np < ep)
547 *np++ = (Char)c;
548 } while (c != ']');
549 *np = '\0';
550 if (np >= ep) {
551 seterror(ERR_SELOVFL);
552 addla(name);
553 return;
554 }
555 c = getC(DOEXCL);
556 }
557 /*
558 * Name up to here is a max of 2 * MAXVARLEN + 8.
559 */
560 if (c == ':') {
561 /*
562 * if the :g modifier is followed by a newline, then error right away!
563 * -strike
564 */
565 int amodflag, gmodflag;
566
567 amodflag = 0;
568 gmodflag = 0;
569 do {
570 *np++ = (Char)c, c = getC(DOEXCL);
571 if (c == 'g' || c == 'a') {
572 if (c == 'g')
573 gmodflag++;
574 else
575 amodflag++;
576 *np++ = (Char)c; c = getC(DOEXCL);
577 }
578 if ((c == 'g' && !gmodflag) || (c == 'a' && !amodflag)) {
579 if (c == 'g')
580 gmodflag++;
581 else
582 amodflag++;
583 *np++ = (Char)c, c = getC(DOEXCL);
584 }
585 *np++ = (Char)c;
586 /* scan s// [eichin:19910926.0512EST] */
587 if (c == 's') {
588 int delimcnt = 2;
589 int delim = getC(0);
590 *np++ = (Char)delim;
591
592 if (!delim || letter(delim)
593 || Isdigit(delim) || any(" \t\n", delim)) {
594 seterror(ERR_BADSUBST);
595 break;
596 }
597 while ((c = getC(0)) != -1) {
598 *np++ = (Char)c;
599 if(c == delim) delimcnt--;
600 if(!delimcnt) break;
601 }
602 if(delimcnt) {
603 seterror(ERR_BADSUBST);
604 break;
605 }
606 c = 's';
607 }
608 if (!any("htrqxes", c)) {
609 if ((amodflag || gmodflag) && c == '\n')
610 stderror(ERR_VARSYN); /* strike */
611 seterror(ERR_VARMOD, c);
612 *np = 0;
613 addla(name);
614 return;
615 }
616 }
617 while ((c = getC(DOEXCL)) == ':');
618 ungetD(c);
619 }
620 else
621 ungetD(c);
622 if (sc == '{') {
623 c = getC(DOEXCL);
624 if (c != '}') {
625 ungetD(c);
626 seterror(ERR_MISSING, '}');
627 *np = 0;
628 addla(name);
629 return;
630 }
631 *np++ = (Char)c;
632 }
633 *np = 0;
634 addla(name);
635 return;
636 }
637
638 void
addla(Char * cp)639 addla(Char *cp)
640 {
641 Char buf[BUFSIZE];
642
643 if (Strlen(cp) + (lap ? Strlen(lap) : 0) >=
644 (sizeof(labuf) - 4) / sizeof(Char)) {
645 seterror(ERR_EXPOVFL);
646 return;
647 }
648 if (lap)
649 (void)Strcpy(buf, lap);
650 (void)Strcpy(labuf, cp);
651 if (lap)
652 (void)Strcat(labuf, buf);
653 lap = labuf;
654 }
655
656 static Char lhsb[32];
657 static Char slhs[32];
658 static Char rhsb[64];
659 static int quesarg;
660
661 static void
getexcl(int sc)662 getexcl(int sc)
663 {
664 struct wordent *hp, *ip;
665 int c, dol, left, right;
666
667 if (sc == 0) {
668 sc = getC(0);
669 if (sc != '{') {
670 ungetC(sc);
671 sc = 0;
672 }
673 }
674 quesarg = -1;
675 lastev = eventno;
676 hp = gethent(sc);
677 if (hp == 0)
678 return;
679 hadhist = 1;
680 dol = 0;
681 if (hp == alhistp)
682 for (ip = hp->next->next; ip != alhistt; ip = ip->next)
683 dol++;
684 else
685 for (ip = hp->next->next; ip != hp->prev; ip = ip->next)
686 dol++;
687 left = 0, right = dol;
688 if (sc == HISTSUB) {
689 ungetC('s'), unreadc(HISTSUB), c = ':';
690 goto subst;
691 }
692 c = getC(0);
693 if (!any(":^$*-%", c))
694 goto subst;
695 left = right = -1;
696 if (c == ':') {
697 c = getC(0);
698 unreadc(c);
699 if (letter(c) || c == '&') {
700 c = ':';
701 left = 0, right = dol;
702 goto subst;
703 }
704 }
705 else
706 ungetC(c);
707 if (!getsel(&left, &right, dol))
708 return;
709 c = getC(0);
710 if (c == '*')
711 ungetC(c), c = '-';
712 if (c == '-') {
713 if (!getsel(&left, &right, dol))
714 return;
715 c = getC(0);
716 }
717 subst:
718 exclc = right - left + 1;
719 while (--left >= 0)
720 hp = hp->next;
721 if (sc == HISTSUB || c == ':') {
722 do {
723 hp = getsub(hp);
724 c = getC(0);
725 } while (c == ':');
726 }
727 unreadc(c);
728 if (sc == '{') {
729 c = getC(0);
730 if (c != '}')
731 seterror(ERR_BADBANG);
732 }
733 exclnxt = hp;
734 }
735
736 static struct wordent *
getsub(struct wordent * en)737 getsub(struct wordent *en)
738 {
739 Char orhsb[sizeof(rhsb) / sizeof(Char)];
740 Char *cp;
741 int c, delim, sc;
742 int global;
743
744 do {
745 exclnxt = 0;
746 global = 0;
747 sc = c = getC(0);
748 if (c == 'g' || c == 'a') {
749 global |= (c == 'g') ? 1 : 2;
750 sc = c = getC(0);
751 }
752 if (((c =='g') && !(global & 1)) || ((c == 'a') && !(global & 2))) {
753 global |= (c == 'g') ? 1 : 2;
754 sc = c = getC(0);
755 }
756
757 switch (c) {
758 case 'p':
759 justpr++;
760 return (en);
761 case 'x':
762 case 'q':
763 global |= 1;
764 /* FALLTHROUGH */
765 case 'h':
766 case 'r':
767 case 't':
768 case 'e':
769 break;
770 case '&':
771 if (slhs[0] == 0) {
772 seterror(ERR_NOSUBST);
773 return (en);
774 }
775 (void) Strcpy(lhsb, slhs);
776 break;
777 #ifdef notdef
778 case '~':
779 if (lhsb[0] == 0)
780 goto badlhs;
781 break;
782 #endif
783 case 's':
784 delim = getC(0);
785 if (letter(delim) || Isdigit(delim) || any(" \t\n", delim)) {
786 unreadc(delim);
787 lhsb[0] = 0;
788 seterror(ERR_BADSUBST);
789 return (en);
790 }
791 cp = lhsb;
792 for (;;) {
793 c = getC(0);
794 if (c == '\n') {
795 unreadc(c);
796 break;
797 }
798 if (c == delim)
799 break;
800 if (cp > &lhsb[sizeof(lhsb) / sizeof(Char) - 2]) {
801 lhsb[0] = 0;
802 seterror(ERR_BADSUBST);
803 return (en);
804 }
805 if (c == '\\') {
806 c = getC(0);
807 if (c != delim && c != '\\')
808 *cp++ = '\\';
809 }
810 *cp++ = (Char)c;
811 }
812 if (cp != lhsb)
813 *cp++ = 0;
814 else if (lhsb[0] == 0) {
815 seterror(ERR_LHS);
816 return (en);
817 }
818 cp = rhsb;
819 (void)Strcpy(orhsb, cp);
820 for (;;) {
821 c = getC(0);
822 if (c == '\n') {
823 unreadc(c);
824 break;
825 }
826 if (c == delim)
827 break;
828 #ifdef notdef
829 if (c == '~') {
830 if (&cp[Strlen(orhsb)] > &rhsb[sizeof(rhsb) /
831 sizeof(Char) - 2])
832 goto toorhs;
833 (void)Strcpy(cp, orhsb);
834 cp = Strend(cp);
835 continue;
836 }
837 #endif
838 if (cp > &rhsb[sizeof(rhsb) / sizeof(Char) - 2]) {
839 seterror(ERR_RHSLONG);
840 return (en);
841 }
842 if (c == '\\') {
843 c = getC(0);
844 if (c != delim /* && c != '~' */ )
845 *cp++ = '\\';
846 }
847 *cp++ = (Char)c;
848 }
849 *cp++ = 0;
850 break;
851 default:
852 if (c == '\n')
853 unreadc(c);
854 seterror(ERR_BADBANGMOD, c);
855 return (en);
856 }
857 (void)Strcpy(slhs, lhsb);
858 if (exclc)
859 en = dosub(sc, en, global);
860 }
861 while ((c = getC(0)) == ':');
862 unreadc(c);
863 return (en);
864 }
865
866 static struct wordent *
dosub(int sc,struct wordent * en,int global)867 dosub(int sc, struct wordent *en, int global)
868 {
869 struct wordent lexi, *hp, *wdp;
870 int i;
871 int didone, didsub;
872
873 didone = 0;
874 didsub = 0;
875 i = exclc;
876 hp = &lexi;
877
878 wdp = hp;
879 while (--i >= 0) {
880 struct wordent *new = (struct wordent *)xcalloc(1, sizeof *wdp);
881
882 new->word = 0;
883 new->prev = wdp;
884 new->next = hp;
885 wdp->next = new;
886 wdp = new;
887 en = en->next;
888 if (en->word) {
889 Char *tword, *otword;
890
891 if ((global & 1) || didsub == 0) {
892 tword = subword(en->word, sc, &didone);
893 if (didone)
894 didsub = 1;
895 if (global & 2) {
896 while (didone && tword != STRNULL) {
897 otword = tword;
898 tword = subword(otword, sc, &didone);
899 if (Strcmp(tword, otword) == 0) {
900 xfree((ptr_t) otword);
901 break;
902 }
903 else
904 xfree((ptr_t)otword);
905 }
906 }
907 }
908 else
909 tword = Strsave(en->word);
910 wdp->word = tword;
911 }
912 }
913 if (didsub == 0)
914 seterror(ERR_MODFAIL);
915 hp->prev = wdp;
916 return (&enthist(-1000, &lexi, 0)->Hlex);
917 }
918
919 static Char *
subword(Char * cp,int type,int * adid)920 subword(Char *cp, int type, int *adid)
921 {
922 Char wbuf[BUFSIZE];
923 Char *mp, *np, *wp;
924 ssize_t i;
925
926 *adid = 0;
927 switch (type) {
928 case 'r':
929 case 'e':
930 case 'h':
931 case 't':
932 case 'q':
933 case 'x':
934 wp = domod(cp, type);
935 if (wp == 0)
936 return (Strsave(cp));
937 *adid = 1;
938 return (wp);
939 default:
940 wp = wbuf;
941 i = BUFSIZE - 4;
942 for (mp = cp; *mp; mp++)
943 if (matchs(mp, lhsb)) {
944 for (np = cp; np < mp;)
945 *wp++ = *np++, --i;
946 for (np = rhsb; *np; np++)
947 switch (*np) {
948 case '\\':
949 if (np[1] == '&')
950 np++;
951 /* FALLTHROUGH */
952 default:
953 if (--i < 0) {
954 seterror(ERR_SUBOVFL);
955 return (STRNULL);
956 }
957 *wp++ = *np;
958 continue;
959 case '&':
960 i -= (ssize_t)Strlen(lhsb);
961 if (i < 0) {
962 seterror(ERR_SUBOVFL);
963 return (STRNULL);
964 }
965 *wp = 0;
966 (void) Strcat(wp, lhsb);
967 wp = Strend(wp);
968 continue;
969 }
970 mp += Strlen(lhsb);
971 i -= (ssize_t)Strlen(mp);
972 if (i < 0) {
973 seterror(ERR_SUBOVFL);
974 return (STRNULL);
975 }
976 *wp = 0;
977 (void) Strcat(wp, mp);
978 *adid = 1;
979 return (Strsave(wbuf));
980 }
981 return (Strsave(cp));
982 }
983 }
984
985 Char *
domod(Char * cp,int type)986 domod(Char *cp, int type)
987 {
988 Char *wp, *xp;
989 int c;
990
991 switch (type) {
992 case 'x':
993 case 'q':
994 wp = Strsave(cp);
995 for (xp = wp; (c = *xp) != '\0'; xp++)
996 if ((c != ' ' && c != '\t') || type == 'q')
997 *xp |= QUOTE;
998 return (wp);
999 case 'h':
1000 case 't':
1001 if (!any(short2str(cp), '/'))
1002 return (type == 't' ? Strsave(cp) : 0);
1003 wp = Strend(cp);
1004 while (*--wp != '/')
1005 continue;
1006 if (type == 'h')
1007 xp = Strsave(cp), xp[wp - cp] = 0;
1008 else
1009 xp = Strsave(wp + 1);
1010 return (xp);
1011 case 'e':
1012 case 'r':
1013 wp = Strend(cp);
1014 for (wp--; wp >= cp && *wp != '/'; wp--)
1015 if (*wp == '.') {
1016 if (type == 'e')
1017 xp = Strsave(wp + 1);
1018 else
1019 xp = Strsave(cp), xp[wp - cp] = 0;
1020 return (xp);
1021 }
1022 return (Strsave(type == 'e' ? STRNULL : cp));
1023 default:
1024 break;
1025 }
1026 return (0);
1027 }
1028
1029 static int
matchs(Char * str,Char * pat)1030 matchs(Char *str, Char *pat)
1031 {
1032 while (*str && *pat && *str == *pat)
1033 str++, pat++;
1034 return (*pat == 0);
1035 }
1036
1037 static int
getsel(int * al,int * ar,int dol)1038 getsel(int *al, int *ar, int dol)
1039 {
1040 int c, i;
1041 int first;
1042
1043 c = getC(0);
1044 first = *al < 0;
1045
1046 switch (c) {
1047 case '%':
1048 if (quesarg == -1) {
1049 seterror(ERR_BADBANGARG);
1050 return (0);
1051 }
1052 if (*al < 0)
1053 *al = quesarg;
1054 *ar = quesarg;
1055 break;
1056 case '-':
1057 if (*al < 0) {
1058 *al = 0;
1059 *ar = dol - 1;
1060 unreadc(c);
1061 }
1062 return (1);
1063 case '^':
1064 if (*al < 0)
1065 *al = 1;
1066 *ar = 1;
1067 break;
1068 case '$':
1069 if (*al < 0)
1070 *al = dol;
1071 *ar = dol;
1072 break;
1073 case '*':
1074 if (*al < 0)
1075 *al = 1;
1076 *ar = dol;
1077 if (*ar < *al) {
1078 *ar = 0;
1079 *al = 1;
1080 return (1);
1081 }
1082 break;
1083 default:
1084 if (Isdigit(c)) {
1085 i = 0;
1086 while (Isdigit(c)) {
1087 i = i * 10 + c - '0';
1088 c = getC(0);
1089 }
1090 if (i < 0)
1091 i = dol + 1;
1092 if (*al < 0)
1093 *al = i;
1094 *ar = i;
1095 }
1096 else if (*al < 0)
1097 *al = 0, *ar = dol;
1098 else
1099 *ar = dol - 1;
1100 unreadc(c);
1101 break;
1102 }
1103 if (first) {
1104 c = getC(0);
1105 unreadc(c);
1106 if (any("-$*", c))
1107 return (1);
1108 }
1109 if (*al > *ar || *ar > dol) {
1110 seterror(ERR_BADBANGARG);
1111 return (0);
1112 }
1113 return (1);
1114
1115 }
1116
1117 static struct wordent *
gethent(int sc)1118 gethent(int sc)
1119 {
1120 struct Hist *hp;
1121 Char *np;
1122 char *str;
1123 int c, event;
1124 int back;
1125
1126 back = 0;
1127 c = sc == HISTSUB ? HIST : getC(0);
1128 if (c == HIST) {
1129 if (alhistp)
1130 return (alhistp);
1131 event = eventno;
1132 }
1133 else
1134 switch (c) {
1135 case ':':
1136 case '^':
1137 case '$':
1138 case '*':
1139 case '%':
1140 ungetC(c);
1141 if (lastev == eventno && alhistp)
1142 return (alhistp);
1143 event = lastev;
1144 break;
1145 case '#': /* !# is command being typed in (mrh) */
1146 if (--hleft == 0) {
1147 seterror(ERR_HISTLOOP);
1148 return (0);
1149 }
1150 else
1151 return (¶ml);
1152 /* NOTREACHED */
1153 case '-':
1154 back = 1;
1155 c = getC(0);
1156 /* FALLTHROUGH */
1157 default:
1158 if (any("(=~", c)) {
1159 unreadc(c);
1160 ungetC(HIST);
1161 return (0);
1162 }
1163 np = lhsb;
1164 event = 0;
1165 while (!cmap(c, _ESC | _META | _QF | _QB) && !any("${}:", c)) {
1166 if (event != -1 && Isdigit(c))
1167 event = event * 10 + c - '0';
1168 else
1169 event = -1;
1170 if (np < &lhsb[sizeof(lhsb) / sizeof(Char) - 2])
1171 *np++ = (Char)c;
1172 c = getC(0);
1173 }
1174 unreadc(c);
1175 if (np == lhsb) {
1176 ungetC(HIST);
1177 return (0);
1178 }
1179 *np++ = 0;
1180 if (event != -1) {
1181 /*
1182 * History had only digits
1183 */
1184 if (back)
1185 event = eventno + (alhistp == 0) - (event ? event : 0);
1186 break;
1187 }
1188 hp = findev(lhsb, 0);
1189 if (hp)
1190 lastev = hp->Hnum;
1191 return (&hp->Hlex);
1192 case '?':
1193 np = lhsb;
1194 for (;;) {
1195 c = getC(0);
1196 if (c == '\n') {
1197 unreadc(c);
1198 break;
1199 }
1200 if (c == '?')
1201 break;
1202 if (np < &lhsb[sizeof(lhsb) / sizeof(Char) - 2])
1203 *np++ = (Char)c;
1204 }
1205 if (np == lhsb) {
1206 if (lhsb[0] == 0) {
1207 seterror(ERR_NOSEARCH);
1208 return (0);
1209 }
1210 }
1211 else
1212 *np++ = 0;
1213 hp = findev(lhsb, 1);
1214 if (hp)
1215 lastev = hp->Hnum;
1216 return (&hp->Hlex);
1217 }
1218
1219 for (hp = Histlist.Hnext; hp; hp = hp->Hnext)
1220 if (hp->Hnum == event) {
1221 hp->Href = eventno;
1222 lastev = hp->Hnum;
1223 return (&hp->Hlex);
1224 }
1225 np = putn(event);
1226 str = vis_str(np);
1227 xfree((ptr_t) np);
1228 seterror(ERR_NOEVENT, str);
1229 return (0);
1230 }
1231
1232 static struct Hist *
findev(Char * cp,int anyarg)1233 findev(Char *cp, int anyarg)
1234 {
1235 struct Hist *hp;
1236
1237 for (hp = Histlist.Hnext; hp; hp = hp->Hnext) {
1238 Char *dp, *p, *q;
1239 struct wordent *lp;
1240 int argno;
1241
1242 lp = hp->Hlex.next;
1243 argno = 0;
1244
1245 /*
1246 * The entries added by alias substitution don't have a newline but do
1247 * have a negative event number. Savehist() trims off these entries,
1248 * but it happens before alias expansion, too early to delete those
1249 * from the previous command.
1250 */
1251 if (hp->Hnum < 0)
1252 continue;
1253 if (lp->word[0] == '\n')
1254 continue;
1255 if (!anyarg) {
1256 p = cp;
1257 q = lp->word;
1258 do
1259 if (!*p)
1260 return (hp);
1261 while (*p++ == *q++);
1262 continue;
1263 }
1264 do {
1265 for (dp = lp->word; *dp; dp++) {
1266 p = cp;
1267 q = dp;
1268 do
1269 if (!*p) {
1270 quesarg = argno;
1271 return (hp);
1272 }
1273 while (*p++ == *q++);
1274 }
1275 lp = lp->next;
1276 argno++;
1277 } while (lp->word[0] != '\n');
1278 }
1279 seterror(ERR_NOEVENT, vis_str(cp));
1280 return (0);
1281 }
1282
1283
1284 static void
setexclp(Char * cp)1285 setexclp(Char *cp)
1286 {
1287 if (cp && cp[0] == '\n')
1288 return;
1289 exclp = cp;
1290 }
1291
1292 void
unreadc(int c)1293 unreadc(int c)
1294 {
1295 peekread = c;
1296 }
1297
1298 int
readc(int wanteof)1299 readc(int wanteof)
1300 {
1301 static int sincereal;
1302 int c;
1303
1304 aret = F_SEEK;
1305 if ((c = peekread) != '\0') {
1306 peekread = 0;
1307 return (c);
1308 }
1309 top:
1310 aret = F_SEEK;
1311 if (alvecp) {
1312 aret = A_SEEK;
1313 if ((c = *alvecp++) != '\0')
1314 return (c);
1315 if (alvec && *alvec) {
1316 alvecp = *alvec++;
1317 return (' ');
1318 }
1319 else {
1320 aret = F_SEEK;
1321 alvecp = NULL;
1322 return('\n');
1323 }
1324 }
1325 if (alvec) {
1326 if ((alvecp = *alvec) != '\0') {
1327 alvec++;
1328 goto top;
1329 }
1330 /* Infinite source! */
1331 return ('\n');
1332 }
1333 if (evalp) {
1334 aret = E_SEEK;
1335 if ((c = *evalp++) != '\0')
1336 return (c);
1337 if (evalvec && *evalvec) {
1338 evalp = *evalvec++;
1339 return (' ');
1340 }
1341 aret = F_SEEK;
1342 evalp = 0;
1343 }
1344 if (evalvec) {
1345 if (evalvec == (Char **) 1) {
1346 doneinp = 1;
1347 reset();
1348 }
1349 if ((evalp = *evalvec) != '\0') {
1350 evalvec++;
1351 goto top;
1352 }
1353 evalvec = (Char **) 1;
1354 return ('\n');
1355 }
1356 do {
1357 if (arginp == (Char *) 1 || onelflg == 1) {
1358 if (wanteof)
1359 return (-1);
1360 exitstat();
1361 }
1362 if (arginp) {
1363 if ((c = *arginp++) == 0) {
1364 arginp = (Char *) 1;
1365 return ('\n');
1366 }
1367 return (c);
1368 }
1369 reread:
1370 c = bgetc();
1371 if (c < 0) {
1372 struct termios tty;
1373 if (wanteof)
1374 return (-1);
1375 /* was isatty but raw with ignoreeof yields problems */
1376 if (tcgetattr(SHIN, &tty) == 0 && (tty.c_lflag & ICANON))
1377 {
1378 /* was 'short' for FILEC */
1379 pid_t ctpgrp;
1380
1381 if (++sincereal > 25)
1382 goto oops;
1383 if (tpgrp != -1 &&
1384 (ctpgrp = tcgetpgrp(FSHTTY)) != -1 &&
1385 tpgrp != ctpgrp) {
1386 (void)tcsetpgrp(FSHTTY, tpgrp);
1387 (void)kill(-ctpgrp, SIGHUP);
1388 (void)fprintf(csherr, "Reset tty pgrp from %ld to %ld\n",
1389 (long)ctpgrp, (long)tpgrp);
1390 goto reread;
1391 }
1392 if (adrof(STRignoreeof)) {
1393 if (loginsh)
1394 (void)fprintf(csherr,"\nUse \"logout\" to logout.\n");
1395 else
1396 (void)fprintf(csherr,"\nUse \"exit\" to leave csh.\n");
1397 reset();
1398 }
1399 if (chkstop == 0)
1400 panystop(1);
1401 }
1402 oops:
1403 doneinp = 1;
1404 reset();
1405 }
1406 sincereal = 0;
1407 if (c == '\n' && onelflg)
1408 onelflg--;
1409 } while (c == 0);
1410 return (c);
1411 }
1412
1413 static int
bgetc(void)1414 bgetc(void)
1415 {
1416 #ifdef FILEC
1417 char tbuf[BUFSIZE + 1];
1418 Char ttyline[BUFSIZE];
1419 int buf, off;
1420 ssize_t c, numleft, 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 (int)(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 int d;
1479 if ((p = el_gets(el, &d)) != NULL) {
1480 size_t i;
1481 /* XXX: Truncation */
1482 numleft = d > BUFSIZE ? BUFSIZE : d;
1483 for (i = 0; *p && i < BUFSIZE; i++, p++)
1484 ttyline[i] = *p;
1485 ttyline[i - (i == BUFSIZE)] = '\0';
1486 }
1487 }
1488 #endif
1489 c = numleft ? numleft : tenex(ttyline, BUFSIZE);
1490 if (c > roomleft) {
1491 /* start with fresh buffer */
1492 feobp = fseekp = fblocks * BUFSIZE;
1493 numleft = c;
1494 goto again;
1495 }
1496 if (c > 0)
1497 (void)memcpy(fbuf[buf] + off, ttyline,
1498 (size_t)c * sizeof(**fbuf));
1499 numleft = 0;
1500 }
1501 else {
1502 #endif
1503 c = read(SHIN, tbuf, (size_t)roomleft);
1504 if (c > 0) {
1505 int i;
1506 Char *ptr = fbuf[buf] + off;
1507
1508 for (i = 0; i < c; i++)
1509 ptr[i] = (unsigned char) tbuf[i];
1510 }
1511 #ifdef FILEC
1512 }
1513 #endif
1514 if (c >= 0)
1515 break;
1516 if (errno == EWOULDBLOCK) {
1517 int iooff = 0;
1518
1519 (void)ioctl(SHIN, FIONBIO, (ioctl_t) & iooff);
1520 }
1521 else if (errno != EINTR)
1522 break;
1523 #ifdef FILEC
1524 }
1525 #endif
1526 if (c <= 0)
1527 return (-1);
1528 feobp += c;
1529 #ifndef FILEC
1530 goto again;
1531 #else
1532 if (filec && !intty)
1533 goto again;
1534 #endif
1535 }
1536 c = fbuf[buf][(int)fseekp % BUFSIZE];
1537 fseekp++;
1538 return (int)(c);
1539 }
1540
1541 static void
bfree(void)1542 bfree(void)
1543 {
1544 int i, sb;
1545
1546 if (cantell)
1547 return;
1548 if (whyles)
1549 return;
1550 sb = (int)(fseekp - 1) / BUFSIZE;
1551 if (sb > 0) {
1552 for (i = 0; i < sb; i++)
1553 xfree((ptr_t) fbuf[i]);
1554 (void)blkcpy(fbuf, &fbuf[sb]);
1555 fseekp -= BUFSIZE * sb;
1556 feobp -= BUFSIZE * sb;
1557 fblocks -= sb;
1558 }
1559 }
1560
1561 void
bseek(struct Ain * l)1562 bseek(struct Ain *l)
1563 {
1564 switch (aret = l->type) {
1565 case A_SEEK:
1566 alvec = l->a_seek;
1567 alvecp = l->c_seek;
1568 return;
1569 case E_SEEK:
1570 evalvec = l->a_seek;
1571 evalp = l->c_seek;
1572 return;
1573 case F_SEEK:
1574 fseekp = l->f_seek;
1575 return;
1576 default:
1577 (void)fprintf(csherr, "Bad seek type %d\n", aret);
1578 abort();
1579 }
1580 }
1581
1582 void
btell(struct Ain * l)1583 btell(struct Ain *l)
1584 {
1585 switch (l->type = aret) {
1586 case A_SEEK:
1587 l->a_seek = alvec;
1588 l->c_seek = alvecp;
1589 return;
1590 case E_SEEK:
1591 l->a_seek = evalvec;
1592 l->c_seek = evalp;
1593 return;
1594 case F_SEEK:
1595 l->f_seek = fseekp;
1596 l->a_seek = NULL;
1597 return;
1598 default:
1599 (void)fprintf(csherr, "Bad seek type %d\n", aret);
1600 abort();
1601 }
1602 }
1603
1604 void
btoeof(void)1605 btoeof(void)
1606 {
1607 (void)lseek(SHIN, (off_t) 0, SEEK_END);
1608 aret = F_SEEK;
1609 fseekp = feobp;
1610 alvec = NULL;
1611 alvecp = NULL;
1612 evalvec = NULL;
1613 evalp = NULL;
1614 wfree();
1615 bfree();
1616 }
1617
1618 void
settell(void)1619 settell(void)
1620 {
1621 cantell = 0;
1622 if (arginp || onelflg || intty)
1623 return;
1624 if (lseek(SHIN, (off_t) 0, SEEK_CUR) < 0 || errno == ESPIPE)
1625 return;
1626 fbuf = (Char **)xcalloc(2, sizeof(Char **));
1627 fblocks = 1;
1628 fbuf[0] = (Char *)xcalloc(BUFSIZE, sizeof(Char));
1629 fseekp = fbobp = feobp = lseek(SHIN, (off_t) 0, SEEK_CUR);
1630 cantell = 1;
1631 }
1632