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