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