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