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