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