xref: /openbsd-src/bin/csh/func.c (revision fc253c1da959f2b9b44fae7dcf06027f7ad7c0de)
1 /*    $OpenBSD: func.c,v 1.34 2017/07/26 19:15:09 anton Exp $       */
2 /*    $NetBSD: func.c,v 1.11 1996/02/09 02:28:29 christos Exp $       */
3 
4 /*-
5  * Copyright (c) 1980, 1991, 1993
6  *	The Regents of the University of California.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. Neither the name of the University nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32 
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <signal.h>
36 #include <locale.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <unistd.h>
40 #include <stdarg.h>
41 
42 #include "csh.h"
43 #include "extern.h"
44 #include "pathnames.h"
45 
46 extern char **environ;
47 
48 static int zlast = -1;
49 static void	islogin(void);
50 static void	reexecute(struct command *);
51 static void	preread(void);
52 static void	doagain(void);
53 static void	search(int, int, Char *);
54 static int	getword(Char *);
55 static int	keyword(Char *);
56 static void	toend(void);
57 static void	xecho(int, Char **);
58 static void	Unsetenv(Char *);
59 
60 struct biltins *
61 isbfunc(struct command *t)
62 {
63     Char *cp = t->t_dcom[0];
64     struct biltins *bp, *bp1, *bp2;
65     static struct biltins label = {"", dozip, 0, 0};
66     static struct biltins foregnd = {"%job", dofg1, 0, 0};
67     static struct biltins backgnd = {"%job &", dobg1, 0, 0};
68 
69     if (lastchr(cp) == ':') {
70 	label.bname = short2str(cp);
71 	return (&label);
72     }
73     if (*cp == '%') {
74 	if (t->t_dflg & F_AMPERSAND) {
75 	    t->t_dflg &= ~F_AMPERSAND;
76 	    backgnd.bname = short2str(cp);
77 	    return (&backgnd);
78 	}
79 	foregnd.bname = short2str(cp);
80 	return (&foregnd);
81     }
82     /*
83      * Binary search Bp1 is the beginning of the current search range. Bp2 is
84      * one past the end.
85      */
86     for (bp1 = bfunc, bp2 = bfunc + nbfunc; bp1 < bp2;) {
87 	int i;
88 
89 	bp = bp1 + ((bp2 - bp1) >> 1);
90 	if ((i = *cp - *bp->bname) == 0 &&
91 	    (i = Strcmp(cp, str2short(bp->bname))) == 0)
92 	    return bp;
93 	if (i < 0)
94 	    bp2 = bp;
95 	else
96 	    bp1 = bp + 1;
97     }
98     return (0);
99 }
100 
101 void
102 func(struct command *t, struct biltins *bp)
103 {
104     int     i;
105 
106     xechoit(t->t_dcom);
107     setname(bp->bname);
108     i = blklen(t->t_dcom) - 1;
109     if (i < bp->minargs)
110 	stderror(ERR_NAME | ERR_TOOFEW);
111     if (i > bp->maxargs)
112 	stderror(ERR_NAME | ERR_TOOMANY);
113     (*bp->bfunct) (t->t_dcom, t);
114 }
115 
116 void
117 /*ARGSUSED*/
118 doonintr(Char **v, struct command *t)
119 {
120     Char *cp;
121     Char *vv = v[1];
122     sigset_t sigset;
123 
124     if (parintr == SIG_IGN)
125 	return;
126     if (setintr && intty)
127 	stderror(ERR_NAME | ERR_TERMINAL);
128     cp = gointr;
129     gointr = 0;
130     free(cp);
131     if (vv == 0) {
132 	if (setintr) {
133 	    sigemptyset(&sigset);
134 	    sigaddset(&sigset, SIGINT);
135 	    sigprocmask(SIG_BLOCK, &sigset, NULL);
136 	} else
137 	    (void) signal(SIGINT, SIG_DFL);
138 	gointr = 0;
139     }
140     else if (eq((vv = strip(vv)), STRminus)) {
141 	(void) signal(SIGINT, SIG_IGN);
142 	gointr = Strsave(STRminus);
143     }
144     else {
145 	gointr = Strsave(vv);
146 	(void) signal(SIGINT, pintr);
147     }
148 }
149 
150 void
151 /*ARGSUSED*/
152 donohup(Char **v, struct command *t)
153 {
154     if (intty)
155 	stderror(ERR_NAME | ERR_TERMINAL);
156     if (setintr == 0) {
157 	(void) signal(SIGHUP, SIG_IGN);
158     }
159 }
160 
161 void
162 /*ARGSUSED*/
163 dozip(Char **v, struct command *t)
164 {
165     ;
166 }
167 
168 void
169 prvars(void)
170 {
171     plist(&shvhed);
172 }
173 
174 void
175 /*ARGSUSED*/
176 doalias(Char **v, struct command *t)
177 {
178     struct varent *vp;
179     Char *p;
180 
181     v++;
182     p = *v++;
183     if (p == 0)
184 	plist(&aliases);
185     else if (*v == 0) {
186 	vp = adrof1(strip(p), &aliases);
187 	if (vp) {
188 	    blkpr(cshout, vp->vec);
189 	    fputc('\n', cshout);
190 	}
191     }
192     else {
193 	if (eq(p, STRalias) || eq(p, STRunalias)) {
194 	    setname(vis_str(p));
195 	    stderror(ERR_NAME | ERR_DANGER);
196 	}
197 	set1(strip(p), saveblk(v), &aliases);
198     }
199 }
200 
201 void
202 /*ARGSUSED*/
203 unalias(Char **v, struct command *t)
204 {
205     unset1(v, &aliases);
206 }
207 
208 void
209 /*ARGSUSED*/
210 dologout(Char **v, struct command *t)
211 {
212     islogin();
213     goodbye();
214 }
215 
216 void
217 /*ARGSUSED*/
218 dologin(Char **v, struct command *t)
219 {
220     islogin();
221     rechist();
222     (void) signal(SIGTERM, parterm);
223     (void) execl(_PATH_LOGIN, "login", short2str(v[1]), (char *)NULL);
224     untty();
225     xexit(1);
226 }
227 
228 static void
229 islogin(void)
230 {
231     if (chkstop == 0 && setintr)
232 	panystop(0);
233     if (loginsh)
234 	return;
235     stderror(ERR_NOTLOGIN);
236 }
237 
238 void
239 doif(Char **v, struct command *kp)
240 {
241     int i;
242     Char **vv;
243 
244     v++;
245     i = expr(&v);
246     vv = v;
247     if (*vv == NULL)
248 	stderror(ERR_NAME | ERR_EMPTYIF);
249     if (eq(*vv, STRthen)) {
250 	if (*++vv)
251 	    stderror(ERR_NAME | ERR_IMPRTHEN);
252 	setname(vis_str(STRthen));
253 	/*
254 	 * If expression was zero, then scan to else, otherwise just fall into
255 	 * following code.
256 	 */
257 	if (!i)
258 	    search(T_IF, 0, NULL);
259 	return;
260     }
261     /*
262      * Simple command attached to this if. Left shift the node in this tree,
263      * munging it so we can reexecute it.
264      */
265     if (i) {
266 	lshift(kp->t_dcom, vv - kp->t_dcom);
267 	reexecute(kp);
268 	donefds();
269     }
270 }
271 
272 /*
273  * Reexecute a command, being careful not
274  * to redo i/o redirection, which is already set up.
275  */
276 static void
277 reexecute(struct command *kp)
278 {
279     kp->t_dflg &= F_SAVE;
280     kp->t_dflg |= F_REPEAT;
281     /*
282      * If tty is still ours to arbitrate, arbitrate it; otherwise dont even set
283      * pgrp's as the jobs would then have no way to get the tty (we can't give
284      * it to them, and our parent wouldn't know their pgrp, etc.
285      */
286     execute(kp, (tpgrp > 0 ? tpgrp : -1), NULL, NULL);
287 }
288 
289 void
290 /*ARGSUSED*/
291 doelse(Char **v, struct command *t)
292 {
293     search(T_ELSE, 0, NULL);
294 }
295 
296 void
297 /*ARGSUSED*/
298 dogoto(Char **v, struct command *t)
299 {
300     Char   *lp;
301 
302     gotolab(lp = globone(v[1], G_ERROR));
303     free(lp);
304 }
305 
306 void
307 gotolab(Char *lab)
308 {
309     struct whyle *wp;
310     /*
311      * While we still can, locate any unknown ends of existing loops. This
312      * obscure code is the WORST result of the fact that we don't really parse.
313      */
314     zlast = T_GOTO;
315     for (wp = whyles; wp; wp = wp->w_next)
316 	if (wp->w_end.type == F_SEEK && wp->w_end.f_seek == 0) {
317 	    search(T_BREAK, 0, NULL);
318 	    btell(&wp->w_end);
319 	}
320 	else
321 	    bseek(&wp->w_end);
322     search(T_GOTO, 0, lab);
323     /*
324      * Eliminate loops which were exited.
325      */
326     wfree();
327 }
328 
329 void
330 /*ARGSUSED*/
331 doswitch(Char **v, struct command *t)
332 {
333     Char *cp, *lp;
334 
335     v++;
336     if (!*v || *(*v++) != '(')
337 	stderror(ERR_SYNTAX);
338     cp = **v == ')' ? STRNULL : *v++;
339     if (*(*v++) != ')')
340 	v--;
341     if (*v)
342 	stderror(ERR_SYNTAX);
343     search(T_SWITCH, 0, lp = globone(cp, G_ERROR));
344     free(lp);
345 }
346 
347 void
348 /*ARGSUSED*/
349 dobreak(Char **v, struct command *t)
350 {
351     if (whyles)
352 	toend();
353     else
354 	stderror(ERR_NAME | ERR_NOTWHILE);
355 }
356 
357 void
358 /*ARGSUSED*/
359 doexit(Char **v, struct command *t)
360 {
361     if (chkstop == 0 && (intty || intact) && evalvec == 0)
362 	panystop(0);
363     /*
364      * Don't DEMAND parentheses here either.
365      */
366     v++;
367     if (*v) {
368 	set(STRstatus, putn(expr(&v)));
369 	if (*v)
370 	    stderror(ERR_NAME | ERR_EXPRESSION);
371     }
372     btoeof();
373     if (intty)
374 	(void) close(SHIN);
375 }
376 
377 void
378 /*ARGSUSED*/
379 doforeach(Char **v, struct command *t)
380 {
381     Char *cp, *sp;
382     struct whyle *nwp;
383 
384     v++;
385     sp = cp = strip(*v);
386     if (!letter(*sp))
387 	stderror(ERR_NAME | ERR_VARBEGIN);
388     while (*cp && alnum(*cp))
389 	cp++;
390     if (*cp)
391 	stderror(ERR_NAME | ERR_VARALNUM);
392     if ((cp - sp) > MAXVARLEN)
393 	stderror(ERR_NAME | ERR_VARTOOLONG);
394     cp = *v++;
395     if (v[0][0] != '(' || v[blklen(v) - 1][0] != ')')
396 	stderror(ERR_NAME | ERR_NOPAREN);
397     v++;
398     gflag = 0, tglob(v);
399     v = globall(v);
400     if (v == 0)
401 	stderror(ERR_NAME | ERR_NOMATCH);
402     nwp = xcalloc(1, sizeof *nwp);
403     nwp->w_fe = nwp->w_fe0 = v;
404     gargv = 0;
405     btell(&nwp->w_start);
406     nwp->w_fename = Strsave(cp);
407     nwp->w_next = whyles;
408     nwp->w_end.type = F_SEEK;
409     whyles = nwp;
410     /*
411      * Pre-read the loop so as to be more comprehensible to a terminal user.
412      */
413     zlast = T_FOREACH;
414     if (intty)
415 	preread();
416     doagain();
417 }
418 
419 void
420 /*ARGSUSED*/
421 dowhile(Char **v, struct command *t)
422 {
423     int status;
424     bool again = whyles != 0 && SEEKEQ(&whyles->w_start, &lineloc) &&
425     whyles->w_fename == 0;
426 
427     v++;
428     /*
429      * Implement prereading here also, taking care not to evaluate the
430      * expression before the loop has been read up from a terminal.
431      */
432     if (intty && !again)
433 	status = !exp0(&v, 1);
434     else
435 	status = !expr(&v);
436     if (*v)
437 	stderror(ERR_NAME | ERR_EXPRESSION);
438     if (!again) {
439 	struct whyle *nwp = xcalloc(1, sizeof(*nwp));
440 
441 	nwp->w_start = lineloc;
442 	nwp->w_end.type = F_SEEK;
443 	nwp->w_end.f_seek = 0;
444 	nwp->w_next = whyles;
445 	whyles = nwp;
446 	zlast = T_WHILE;
447 	if (intty) {
448 	    /*
449 	     * The tty preread
450 	     */
451 	    preread();
452 	    doagain();
453 	    return;
454 	}
455     }
456     if (status)
457 	/* We ain't gonna loop no more, no more! */
458 	toend();
459 }
460 
461 static void
462 preread(void)
463 {
464     sigset_t sigset;
465 
466     whyles->w_end.type = I_SEEK;
467     if (setintr) {
468 	sigemptyset(&sigset);
469 	sigaddset(&sigset, SIGINT);
470 	sigprocmask(SIG_UNBLOCK, &sigset, NULL);
471     }
472 
473     search(T_BREAK, 0, NULL);		/* read the expression in */
474     if (setintr)
475 	sigprocmask(SIG_BLOCK, &sigset, NULL);
476     btell(&whyles->w_end);
477 }
478 
479 void
480 /*ARGSUSED*/
481 doend(Char **v, struct command *t)
482 {
483     if (!whyles)
484 	stderror(ERR_NAME | ERR_NOTWHILE);
485     btell(&whyles->w_end);
486     doagain();
487 }
488 
489 void
490 /*ARGSUSED*/
491 docontin(Char **v, struct command *t)
492 {
493     if (!whyles)
494 	stderror(ERR_NAME | ERR_NOTWHILE);
495     doagain();
496 }
497 
498 static void
499 doagain(void)
500 {
501     /* Repeating a while is simple */
502     if (whyles->w_fename == 0) {
503 	bseek(&whyles->w_start);
504 	return;
505     }
506     /*
507      * The foreach variable list actually has a spurious word ")" at the end of
508      * the w_fe list.  Thus we are at the of the list if one word beyond this
509      * is 0.
510      */
511     if (!whyles->w_fe[1]) {
512 	dobreak(NULL, NULL);
513 	return;
514     }
515     set(whyles->w_fename, Strsave(*whyles->w_fe++));
516     bseek(&whyles->w_start);
517 }
518 
519 void
520 dorepeat(Char **v, struct command *kp)
521 {
522     int i;
523     sigset_t sigset;
524 
525     i = getn(v[1]);
526     if (setintr) {
527 	sigemptyset(&sigset);
528 	sigaddset(&sigset, SIGINT);
529 	sigprocmask(SIG_BLOCK, &sigset, NULL);
530     }
531     lshift(v, 2);
532     while (i > 0) {
533 	if (setintr)
534 	    sigprocmask(SIG_UNBLOCK, &sigset, NULL);
535 	reexecute(kp);
536 	--i;
537     }
538     donefds();
539     if (setintr)
540 	sigprocmask(SIG_UNBLOCK, &sigset, NULL);
541 }
542 
543 void
544 /*ARGSUSED*/
545 doswbrk(Char **v, struct command *t)
546 {
547     search(T_BRKSW, 0, NULL);
548 }
549 
550 int
551 srchx(Char *cp)
552 {
553     struct srch *sp, *sp1, *sp2;
554     int i;
555 
556     /*
557      * Binary search Sp1 is the beginning of the current search range. Sp2 is
558      * one past the end.
559      */
560     for (sp1 = srchn, sp2 = srchn + nsrchn; sp1 < sp2;) {
561 	sp = sp1 + ((sp2 - sp1) >> 1);
562 	if ((i = *cp - *sp->s_name) == 0 &&
563 	    (i = Strcmp(cp, str2short(sp->s_name))) == 0)
564 	    return sp->s_value;
565 	if (i < 0)
566 	    sp2 = sp;
567 	else
568 	    sp1 = sp + 1;
569     }
570     return (-1);
571 }
572 
573 static Char Stype;
574 static Char *Sgoal;
575 
576 static void
577 search(int type, int level, Char *goal)
578 {
579     Char    wordbuf[BUFSIZ];
580     Char *aword = wordbuf;
581     Char *cp;
582 
583     Stype = type;
584     Sgoal = goal;
585     if (type == T_GOTO) {
586 	struct Ain a;
587 	a.type = F_SEEK;
588 	a.f_seek = 0;
589 	bseek(&a);
590     }
591     do {
592 	if (intty && !filec && fseekp == feobp && aret == F_SEEK)
593 	    (void) fprintf(cshout, "? "), (void) fflush(cshout);
594 	aword[0] = 0;
595 	(void) getword(aword);
596 	switch (srchx(aword)) {
597 
598 	case T_ELSE:
599 	    if (level == 0 && type == T_IF)
600 		return;
601 	    break;
602 
603 	case T_IF:
604 	    while (getword(aword))
605 		continue;
606 	    if ((type == T_IF || type == T_ELSE) &&
607 		eq(aword, STRthen))
608 		level++;
609 	    break;
610 
611 	case T_ENDIF:
612 	    if (type == T_IF || type == T_ELSE)
613 		level--;
614 	    break;
615 
616 	case T_FOREACH:
617 	case T_WHILE:
618 	    if (type == T_BREAK)
619 		level++;
620 	    break;
621 
622 	case T_END:
623 	    if (type == T_BREAK)
624 		level--;
625 	    break;
626 
627 	case T_SWITCH:
628 	    if (type == T_SWITCH || type == T_BRKSW)
629 		level++;
630 	    break;
631 
632 	case T_ENDSW:
633 	    if (type == T_SWITCH || type == T_BRKSW)
634 		level--;
635 	    break;
636 
637 	case T_LABEL:
638 	    if (type == T_GOTO && getword(aword) && eq(aword, goal))
639 		level = -1;
640 	    break;
641 
642 	default:
643 	    if (type != T_GOTO && (type != T_SWITCH || level != 0))
644 		break;
645 	    if (lastchr(aword) != ':')
646 		break;
647 	    aword[Strlen(aword) - 1] = 0;
648 	    if ((type == T_GOTO && eq(aword, goal)) ||
649 		(type == T_SWITCH && eq(aword, STRdefault)))
650 		level = -1;
651 	    break;
652 
653 	case T_CASE:
654 	    if (type != T_SWITCH || level != 0)
655 		break;
656 	    (void) getword(aword);
657 	    if (lastchr(aword) == ':')
658 		aword[Strlen(aword) - 1] = 0;
659 	    cp = strip(Dfix1(aword));
660 	    if (Gmatch(goal, cp))
661 		level = -1;
662 	    free(cp);
663 	    break;
664 
665 	case T_DEFAULT:
666 	    if (type == T_SWITCH && level == 0)
667 		level = -1;
668 	    break;
669 	}
670 	(void) getword(NULL);
671     } while (level >= 0);
672 }
673 
674 static int
675 getword(Char *wp)
676 {
677     int found = 0;
678     int c, d;
679     int     kwd = 0;
680     Char   *owp = wp;
681 
682     c = readc(1);
683     d = 0;
684     do {
685 	while (c == ' ' || c == '\t')
686 	    c = readc(1);
687 	if (c == '#')
688 	    do
689 		c = readc(1);
690 	    while (c >= 0 && c != '\n');
691 	if (c < 0)
692 	    goto past;
693 	if (c == '\n') {
694 	    if (wp)
695 		break;
696 	    return (0);
697 	}
698 	unreadc(c);
699 	found = 1;
700 	do {
701 	    c = readc(1);
702 	    if (c == '\\' && (c = readc(1)) == '\n')
703 		c = ' ';
704 	    if (c == '\'' || c == '"') {
705 		if (d == 0)
706 		    d = c;
707 		else if (d == c)
708 		    d = 0;
709 	    }
710 	    if (c < 0)
711 		goto past;
712 	    if (wp) {
713 		*wp++ = c;
714 		*wp = 0;	/* end the string b4 test */
715 	    }
716 	} while ((d || (!(kwd = keyword(owp)) && c != ' '
717 		  && c != '\t')) && c != '\n');
718     } while (wp == 0);
719 
720     /*
721      * if we have read a keyword ( "if", "switch" or "while" ) then we do not
722      * need to unreadc the look-ahead char
723      */
724     if (!kwd) {
725 	unreadc(c);
726 	if (found)
727 	    *--wp = 0;
728     }
729 
730     return (found);
731 
732 past:
733     switch (Stype) {
734 
735     case T_IF:
736 	stderror(ERR_NAME | ERR_NOTFOUND, "then/endif");
737 
738     case T_ELSE:
739 	stderror(ERR_NAME | ERR_NOTFOUND, "endif");
740 
741     case T_BRKSW:
742     case T_SWITCH:
743 	stderror(ERR_NAME | ERR_NOTFOUND, "endsw");
744 
745     case T_BREAK:
746 	stderror(ERR_NAME | ERR_NOTFOUND, "end");
747 
748     case T_GOTO:
749 	setname(vis_str(Sgoal));
750 	stderror(ERR_NAME | ERR_NOTFOUND, "label");
751     }
752     /* NOTREACHED */
753     return (0);
754 }
755 
756 /*
757  * keyword(wp) determines if wp is one of the built-n functions if,
758  * switch or while. It seems that when an if statement looks like
759  * "if(" then getword above sucks in the '(' and so the search routine
760  * never finds what it is scanning for. Rather than rewrite doword, I hack
761  * in a test to see if the string forms a keyword. Then doword stops
762  * and returns the word "if" -strike
763  */
764 
765 static int
766 keyword(Char *wp)
767 {
768     static Char STRif[] = {'i', 'f', '\0'};
769     static Char STRwhile[] = {'w', 'h', 'i', 'l', 'e', '\0'};
770     static Char STRswitch[] = {'s', 'w', 'i', 't', 'c', 'h', '\0'};
771 
772     if (!wp)
773 	return (0);
774 
775     if ((Strcmp(wp, STRif) == 0) || (Strcmp(wp, STRwhile) == 0)
776 	|| (Strcmp(wp, STRswitch) == 0))
777 	return (1);
778 
779     return (0);
780 }
781 
782 static void
783 toend(void)
784 {
785     if (whyles->w_end.type == F_SEEK && whyles->w_end.f_seek == 0) {
786 	search(T_BREAK, 0, NULL);
787 	btell(&whyles->w_end);
788 	whyles->w_end.f_seek--;
789     }
790     else
791 	bseek(&whyles->w_end);
792     wfree();
793 }
794 
795 void
796 wfree(void)
797 {
798     struct Ain    o;
799     struct whyle *nwp;
800 
801     btell(&o);
802 
803     for (; whyles; whyles = nwp) {
804 	struct whyle *wp = whyles;
805 	nwp = wp->w_next;
806 
807 	/*
808 	 * We free loops that have different seek types.
809 	 */
810 	if (wp->w_end.type != I_SEEK && wp->w_start.type == wp->w_end.type &&
811 	    wp->w_start.type == o.type) {
812 	    if (wp->w_end.type == F_SEEK) {
813 		if (o.f_seek >= wp->w_start.f_seek &&
814 		    (wp->w_end.f_seek == 0 || o.f_seek < wp->w_end.f_seek))
815 		    break;
816 	    }
817 	    else {
818 		if (o.a_seek >= wp->w_start.a_seek &&
819 		    (wp->w_end.a_seek == 0 || o.a_seek < wp->w_end.a_seek))
820 		    break;
821 	    }
822 	}
823 
824 	if (wp->w_fe0)
825 	    blkfree(wp->w_fe0);
826 	if (wp->w_fename)
827 	    free(wp->w_fename);
828 	free(wp);
829     }
830 }
831 
832 void
833 /*ARGSUSED*/
834 doecho(Char **v, struct command *t)
835 {
836     xecho(' ', v);
837 }
838 
839 void
840 /*ARGSUSED*/
841 doglob(Char **v, struct command *t)
842 {
843     xecho(0, v);
844     (void) fflush(cshout);
845 }
846 
847 static void
848 xecho(int sep, Char **v)
849 {
850     Char *cp;
851     int     nonl = 0;
852     sigset_t sigset;
853 
854     if (setintr) {
855 	sigemptyset(&sigset);
856 	sigaddset(&sigset, SIGINT);
857 	sigprocmask(SIG_UNBLOCK, &sigset, NULL);
858     }
859     v++;
860     if (*v == 0)
861 	return;
862     gflag = 0, tglob(v);
863     if (gflag) {
864 	v = globall(v);
865 	if (v == 0)
866 	    stderror(ERR_NAME | ERR_NOMATCH);
867     }
868     else {
869 	v = gargv = saveblk(v);
870 	trim(v);
871     }
872     if (sep == ' ' && *v && eq(*v, STRmn))
873 	nonl++, v++;
874     while ((cp = *v++) != NULL) {
875 	int c;
876 
877 	while ((c = *cp++) != '\0')
878 	    (void) vis_fputc(c | QUOTE, cshout);
879 
880 	if (*v)
881 	    (void) vis_fputc(sep | QUOTE, cshout);
882     }
883     if (sep && nonl == 0)
884 	(void) fputc('\n', cshout);
885     else
886 	(void) fflush(cshout);
887     if (setintr)
888 	sigprocmask(SIG_BLOCK, &sigset, NULL);
889     if (gargv)
890 	blkfree(gargv), gargv = 0;
891 }
892 
893 void
894 /*ARGSUSED*/
895 dosetenv(Char **v, struct command *t)
896 {
897     Char   *vp, *lp;
898     sigset_t sigset;
899 
900     v++;
901     if ((vp = *v++) == 0) {
902 	Char **ep;
903 
904 	if (setintr) {
905 	    sigemptyset(&sigset);
906 	    sigaddset(&sigset, SIGINT);
907 	    sigprocmask(SIG_UNBLOCK, &sigset, NULL);
908 	}
909 	for (ep = STR_environ; *ep; ep++)
910 	    (void) fprintf(cshout, "%s\n", vis_str(*ep));
911 	return;
912     }
913     if ((lp = *v++) == 0)
914 	lp = STRNULL;
915     Setenv(vp, lp = globone(lp, G_APPEND));
916     if (eq(vp, STRPATH)) {
917 	importpath(lp);
918 	dohash(NULL, NULL);
919     }
920     free(lp);
921 }
922 
923 void
924 /*ARGSUSED*/
925 dounsetenv(Char **v, struct command *t)
926 {
927     Char  **ep, *p, *n;
928     int     i, maxi;
929     static Char *name = NULL;
930 
931     if (name)
932 	free(name);
933     /*
934      * Find the longest environment variable
935      */
936     for (maxi = 0, ep = STR_environ; *ep; ep++) {
937 	for (i = 0, p = *ep; *p && *p != '='; p++, i++)
938 	    continue;
939 	if (i > maxi)
940 	    maxi = i;
941     }
942 
943     name = xreallocarray(NULL, maxi + 1, sizeof(Char));
944 
945     while (++v && *v)
946 	for (maxi = 1; maxi;)
947 	    for (maxi = 0, ep = STR_environ; *ep; ep++) {
948 		for (n = name, p = *ep; *p && *p != '='; *n++ = *p++)
949 		    continue;
950 		*n = '\0';
951 		if (!Gmatch(name, *v))
952 		    continue;
953 		maxi = 1;
954 		/*
955 		 * Delete name, and start again cause the environment changes
956 		 */
957 		Unsetenv(name);
958 		break;
959 	    }
960     free(name);
961     name = NULL;
962 }
963 
964 void
965 Setenv(Char *name, Char *val)
966 {
967     Char **ep = STR_environ;
968     Char *cp, *dp;
969     Char   *blk[2];
970     Char  **oep = ep;
971 
972     for (; *ep; ep++) {
973 	for (cp = name, dp = *ep; *cp && *cp == *dp; cp++, dp++)
974 	    continue;
975 	if (*cp != 0 || *dp != '=')
976 	    continue;
977 	cp = Strspl(STRequal, val);
978 	free(* ep);
979 	*ep = strip(Strspl(name, cp));
980 	free(cp);
981 	blkfree((Char **) environ);
982 	environ = short2blk(STR_environ);
983 	return;
984     }
985     cp = Strspl(name, STRequal);
986     blk[0] = strip(Strspl(cp, val));
987     free(cp);
988     blk[1] = 0;
989     STR_environ = blkspl(STR_environ, blk);
990     blkfree((Char **) environ);
991     environ = short2blk(STR_environ);
992     free(oep);
993 }
994 
995 static void
996 Unsetenv(Char *name)
997 {
998     Char **ep = STR_environ;
999     Char *cp, *dp;
1000     Char  **oep = ep;
1001 
1002     for (; *ep; ep++) {
1003 	for (cp = name, dp = *ep; *cp && *cp == *dp; cp++, dp++)
1004 	    continue;
1005 	if (*cp != 0 || *dp != '=')
1006 	    continue;
1007 	cp = *ep;
1008 	*ep = 0;
1009 	STR_environ = blkspl(STR_environ, ep + 1);
1010 	environ = short2blk(STR_environ);
1011 	*ep = cp;
1012 	free(cp);
1013 	free(oep);
1014 	return;
1015     }
1016 }
1017 
1018 void
1019 /*ARGSUSED*/
1020 doumask(Char **v, struct command *t)
1021 {
1022     Char *cp = v[1];
1023     int i;
1024 
1025     if (cp == 0) {
1026 	i = umask(0);
1027 	(void) umask(i);
1028 	(void) fprintf(cshout, "%o\n", i);
1029 	return;
1030     }
1031     i = 0;
1032     while (Isdigit(*cp) && *cp != '8' && *cp != '9')
1033 	i = i * 8 + *cp++ - '0';
1034     if (*cp || i < 0 || i > 0777)
1035 	stderror(ERR_NAME | ERR_MASK);
1036     (void) umask(i);
1037 }
1038 
1039 static struct limits {
1040     int     limconst;
1041     char   *limname;
1042     int     limdiv;
1043     char   *limscale;
1044 }       limits[] = {
1045     { RLIMIT_CPU,	"cputime",	1,	"seconds" },
1046     { RLIMIT_FSIZE,	"filesize",	1024,	"kbytes" },
1047     { RLIMIT_DATA,	"datasize",	1024,	"kbytes" },
1048     { RLIMIT_STACK,	"stacksize",	1024,	"kbytes" },
1049     { RLIMIT_CORE,	"coredumpsize", 1024,	"kbytes" },
1050     { RLIMIT_RSS,	"memoryuse",	1024,	"kbytes" },
1051 #ifdef RLIMIT_VMEM
1052     { RLIMIT_VMEM,	"vmemoryuse",	1024,	"kbytes" },
1053 #endif
1054     { RLIMIT_MEMLOCK,	"memorylocked",	1024,	"kbytes" },
1055     { RLIMIT_NPROC,	"maxproc",	1,	"" },
1056     { RLIMIT_NOFILE,	"openfiles",	1,	"" },
1057     { -1,		NULL,		0,	NULL }
1058 };
1059 
1060 static struct limits *findlim(Char *);
1061 static rlim_t getval(struct limits *, Char **);
1062 static void limtail(Char *, char *);
1063 static void plim(struct limits *, Char);
1064 static int setlim(struct limits *, Char, rlim_t);
1065 
1066 static struct limits *
1067 findlim(Char *cp)
1068 {
1069     struct limits *lp, *res;
1070 
1071     res = NULL;
1072     for (lp = limits; lp->limconst >= 0; lp++)
1073 	if (prefix(cp, str2short(lp->limname))) {
1074 	    if (res)
1075 		stderror(ERR_NAME | ERR_AMBIG);
1076 	    res = lp;
1077 	}
1078     if (res)
1079 	return (res);
1080     stderror(ERR_NAME | ERR_LIMIT);
1081     /* NOTREACHED */
1082     return (0);
1083 }
1084 
1085 void
1086 /*ARGSUSED*/
1087 dolimit(Char **v, struct command *t)
1088 {
1089     struct limits *lp;
1090     rlim_t limit;
1091     char    hard = 0;
1092 
1093     v++;
1094     if (*v && eq(*v, STRmh)) {
1095 	hard = 1;
1096 	v++;
1097     }
1098     if (*v == 0) {
1099 	for (lp = limits; lp->limconst >= 0; lp++)
1100 	    plim(lp, hard);
1101 	return;
1102     }
1103     lp = findlim(v[0]);
1104     if (v[1] == 0) {
1105 	plim(lp, hard);
1106 	return;
1107     }
1108     limit = getval(lp, v + 1);
1109     if (setlim(lp, hard, limit) < 0)
1110 	stderror(ERR_SILENT);
1111 }
1112 
1113 static  rlim_t
1114 getval(struct limits *lp, Char **v)
1115 {
1116     float f;
1117     Char   *cp = *v++;
1118 
1119     f = atof(short2str(cp));
1120 
1121     while (Isdigit(*cp) || *cp == '.' || *cp == 'e' || *cp == 'E')
1122 	cp++;
1123     if (*cp == 0) {
1124 	if (*v == 0)
1125 	    return ((rlim_t) ((f + 0.5) * lp->limdiv));
1126 	cp = *v;
1127     }
1128     switch (*cp) {
1129     case ':':
1130 	if (lp->limconst != RLIMIT_CPU)
1131 	    goto badscal;
1132 	return ((rlim_t) (f * 60.0 + atof(short2str(cp + 1))));
1133     case 'h':
1134 	if (lp->limconst != RLIMIT_CPU)
1135 	    goto badscal;
1136 	limtail(cp, "hours");
1137 	f *= 3600.0;
1138 	break;
1139     case 'm':
1140 	if (lp->limconst == RLIMIT_CPU) {
1141 	    limtail(cp, "minutes");
1142 	    f *= 60.0;
1143 	    break;
1144 	}
1145 	*cp = 'm';
1146 	limtail(cp, "megabytes");
1147 	f *= 1024.0 * 1024.0;
1148 	break;
1149     case 's':
1150 	if (lp->limconst != RLIMIT_CPU)
1151 	    goto badscal;
1152 	limtail(cp, "seconds");
1153 	break;
1154     case 'M':
1155 	if (lp->limconst == RLIMIT_CPU)
1156 	    goto badscal;
1157 	*cp = 'm';
1158 	limtail(cp, "megabytes");
1159 	f *= 1024.0 * 1024.0;
1160 	break;
1161     case 'k':
1162 	if (lp->limconst == RLIMIT_CPU)
1163 	    goto badscal;
1164 	limtail(cp, "kbytes");
1165 	f *= 1024.0;
1166 	break;
1167     case 'u':
1168 	limtail(cp, "unlimited");
1169 	return (RLIM_INFINITY);
1170     default:
1171 badscal:
1172 	stderror(ERR_NAME | ERR_SCALEF);
1173     }
1174     f += 0.5;
1175     if (f > (float) RLIM_INFINITY)
1176 	return RLIM_INFINITY;
1177     else
1178 	return ((rlim_t) f);
1179 }
1180 
1181 static void
1182 limtail(Char *cp, char *str)
1183 {
1184     char *origstr = str;
1185 
1186     while (*cp && *cp == *str)
1187 	cp++, str++;
1188     if (*cp)
1189 	stderror(ERR_BADSCALE, origstr);
1190 }
1191 
1192 /*ARGSUSED*/
1193 static void
1194 plim(struct limits *lp, Char hard)
1195 {
1196     struct rlimit rlim;
1197     rlim_t limit;
1198 
1199     (void) fprintf(cshout, "%s \t", lp->limname);
1200 
1201     (void) getrlimit(lp->limconst, &rlim);
1202     limit = hard ? rlim.rlim_max : rlim.rlim_cur;
1203 
1204     if (limit == RLIM_INFINITY)
1205 	(void) fprintf(cshout, "unlimited");
1206     else if (lp->limconst == RLIMIT_CPU)
1207 	psecs((long) limit);
1208     else
1209 	(void) fprintf(cshout, "%llu %s",
1210 	    (unsigned long long) (limit / lp->limdiv), lp->limscale);
1211     (void) fputc('\n', cshout);
1212 }
1213 
1214 void
1215 /*ARGSUSED*/
1216 dounlimit(Char **v, struct command *t)
1217 {
1218     struct limits *lp;
1219     int     lerr = 0;
1220     Char    hard = 0;
1221 
1222     v++;
1223     if (*v && eq(*v, STRmh)) {
1224 	hard = 1;
1225 	v++;
1226     }
1227     if (*v == 0) {
1228 	for (lp = limits; lp->limconst >= 0; lp++)
1229 	    if (setlim(lp, hard, RLIM_INFINITY) < 0)
1230 		lerr++;
1231 	if (lerr)
1232 	    stderror(ERR_SILENT);
1233 	return;
1234     }
1235     while (*v) {
1236 	lp = findlim(*v++);
1237 	if (setlim(lp, hard, RLIM_INFINITY) < 0)
1238 	    stderror(ERR_SILENT);
1239     }
1240 }
1241 
1242 static int
1243 setlim(struct limits *lp, Char hard, rlim_t limit)
1244 {
1245     struct rlimit rlim;
1246 
1247     (void) getrlimit(lp->limconst, &rlim);
1248 
1249     if (hard)
1250 	rlim.rlim_max = limit;
1251     else if (limit == RLIM_INFINITY && geteuid() != 0)
1252 	rlim.rlim_cur = rlim.rlim_max;
1253     else
1254 	rlim.rlim_cur = limit;
1255 
1256     if (setrlimit(lp->limconst, &rlim) < 0) {
1257 	(void) fprintf(csherr, "%s: %s: Can't %s%s limit\n", bname, lp->limname,
1258 		       limit == RLIM_INFINITY ? "remove" : "set",
1259 		       hard ? " hard" : "");
1260 	return (-1);
1261     }
1262     return (0);
1263 }
1264 
1265 void
1266 /*ARGSUSED*/
1267 dosuspend(Char **v, struct command *t)
1268 {
1269     int     ctpgrp;
1270 
1271     void    (*old) (int);
1272 
1273     if (loginsh)
1274 	stderror(ERR_SUSPLOG);
1275     untty();
1276 
1277     old = signal(SIGTSTP, SIG_DFL);
1278     (void) kill(0, SIGTSTP);
1279     /* the shell stops here */
1280     (void) signal(SIGTSTP, old);
1281 
1282     if (tpgrp != -1) {
1283 retry:
1284 	ctpgrp = tcgetpgrp(FSHTTY);
1285       if  (ctpgrp != opgrp) {
1286 	    old = signal(SIGTTIN, SIG_DFL);
1287 	    (void) kill(0, SIGTTIN);
1288 	    (void) signal(SIGTTIN, old);
1289 	  goto retry;
1290 	}
1291 	(void) setpgid(0, shpgrp);
1292 	(void) tcsetpgrp(FSHTTY, shpgrp);
1293     }
1294 }
1295 
1296 /* This is the dreaded EVAL built-in.
1297  *   If you don't fiddle with file descriptors, and reset didfds,
1298  *   this command will either ignore redirection inside or outside
1299  *   its arguments, e.g. eval "date >x"  vs.  eval "date" >x
1300  *   The stuff here seems to work, but I did it by trial and error rather
1301  *   than really knowing what was going on.  If tpgrp is zero, we are
1302  *   probably a background eval, e.g. "eval date &", and we want to
1303  *   make sure that any processes we start stay in our pgrp.
1304  *   This is also the case for "time eval date" -- stay in same pgrp.
1305  *   Otherwise, under stty tostop, processes will stop in the wrong
1306  *   pgrp, with no way for the shell to get them going again.  -IAN!
1307  */
1308 
1309 static Char **gv = NULL;
1310 
1311 void
1312 /*ARGSUSED*/
1313 doeval(Char **v, struct command *t)
1314 {
1315     Char  **oevalvec;
1316     Char   *oevalp;
1317     int     odidfds;
1318     jmp_buf osetexit;
1319     int     my_reenter;
1320     Char  **savegv = gv;
1321     int     saveIN;
1322     int     saveOUT;
1323     int     saveERR;
1324     int     oSHIN;
1325     int     oSHOUT;
1326     int     oSHERR;
1327 
1328     UNREGISTER(v);
1329 
1330     oevalvec = evalvec;
1331     oevalp = evalp;
1332     odidfds = didfds;
1333     oSHIN = SHIN;
1334     oSHOUT = SHOUT;
1335     oSHERR = SHERR;
1336 
1337     v++;
1338     if (*v == 0)
1339 	return;
1340     gflag = 0, tglob(v);
1341     if (gflag) {
1342 	gv = v = globall(v);
1343 	gargv = 0;
1344 	if (v == 0)
1345 	    stderror(ERR_NOMATCH);
1346 	v = copyblk(v);
1347     }
1348     else {
1349 	gv = NULL;
1350 	v = copyblk(v);
1351 	trim(v);
1352     }
1353 
1354     saveIN = dcopy(SHIN, -1);
1355     saveOUT = dcopy(SHOUT, -1);
1356     saveERR = dcopy(SHERR, -1);
1357 
1358     getexit(osetexit);
1359 
1360     if ((my_reenter = setexit()) == 0) {
1361 	evalvec = v;
1362 	evalp = 0;
1363 	SHIN = dcopy(0, -1);
1364 	SHOUT = dcopy(1, -1);
1365 	SHERR = dcopy(2, -1);
1366 	didfds = 0;
1367 	process(0);
1368     }
1369 
1370     evalvec = oevalvec;
1371     evalp = oevalp;
1372     doneinp = 0;
1373     didfds = odidfds;
1374     (void) close(SHIN);
1375     (void) close(SHOUT);
1376     (void) close(SHERR);
1377     SHIN = dmove(saveIN, oSHIN);
1378     SHOUT = dmove(saveOUT, oSHOUT);
1379     SHERR = dmove(saveERR, oSHERR);
1380     if (gv)
1381 	blkfree(gv), gv = NULL;
1382     resexit(osetexit);
1383     gv = savegv;
1384     if (my_reenter)
1385 	stderror(ERR_SILENT);
1386 }
1387