xref: /csrg-svn/bin/csh/func.c (revision 68576)
147823Sbostic /*-
260765Sbostic  * Copyright (c) 1980, 1991, 1993
360765Sbostic  *	The Regents of the University of California.  All rights reserved.
447823Sbostic  *
547823Sbostic  * %sccs.include.redist.c%
621933Sdist  */
721933Sdist 
817519Sedward #ifndef lint
9*68576Schristos static char sccsid[] = "@(#)func.c	8.2 (Berkeley) 03/22/95";
1047413Sbostic #endif /* not lint */
111294Sbill 
1250028Sbostic #include <sys/types.h>
1350028Sbostic #include <sys/stat.h>
1450028Sbostic #include <signal.h>
1550028Sbostic #include <locale.h>
1650028Sbostic #include <stdlib.h>
1750028Sbostic #include <string.h>
1850028Sbostic #include <unistd.h>
1950033Schristos #if __STDC__
2050033Schristos # include <stdarg.h>
2150033Schristos #else
2250033Schristos # include <varargs.h>
2350033Schristos #endif
2450033Schristos 
2550023Sbostic #include "csh.h"
2650023Sbostic #include "extern.h"
2750028Sbostic #include "pathnames.h"
281294Sbill 
2949992Sbostic extern char **environ;
301294Sbill 
3149992Sbostic static int zlast = -1;
3250024Schristos static void	islogin __P((void));
3350024Schristos static void	reexecute __P((struct command *));
3450024Schristos static void	preread __P((void));
3550024Schristos static void	doagain __P((void));
3651420Schristos static void	search __P((int, int, Char *));
3750024Schristos static int	getword __P((Char *));
3850024Schristos static int	keyword __P((Char *));
3950024Schristos static void	toend __P((void));
4050024Schristos static void	xecho __P((int, Char **));
4151420Schristos static void	Unsetenv __P((Char *));
4249992Sbostic 
431294Sbill struct biltins *
isbfunc(t)441294Sbill isbfunc(t)
4549992Sbostic     struct command *t;
461294Sbill {
4749992Sbostic     register Char *cp = t->t_dcom[0];
4849992Sbostic     register struct biltins *bp, *bp1, *bp2;
4949992Sbostic     static struct biltins label = {"", dozip, 0, 0};
5049992Sbostic     static struct biltins foregnd = {"%job", dofg1, 0, 0};
5149992Sbostic     static struct biltins backgnd = {"%job &", dobg1, 0, 0};
521294Sbill 
5349992Sbostic     if (lastchr(cp) == ':') {
5449992Sbostic 	label.bname = short2str(cp);
5549992Sbostic 	return (&label);
5649992Sbostic     }
5749992Sbostic     if (*cp == '%') {
5849992Sbostic 	if (t->t_dflg & F_AMPERSAND) {
5949992Sbostic 	    t->t_dflg &= ~F_AMPERSAND;
6049992Sbostic 	    backgnd.bname = short2str(cp);
6149992Sbostic 	    return (&backgnd);
621294Sbill 	}
6349992Sbostic 	foregnd.bname = short2str(cp);
6449992Sbostic 	return (&foregnd);
6549992Sbostic     }
6649992Sbostic     /*
6749992Sbostic      * Binary search Bp1 is the beginning of the current search range. Bp2 is
6849992Sbostic      * one past the end.
6949992Sbostic      */
7049992Sbostic     for (bp1 = bfunc, bp2 = bfunc + nbfunc; bp1 < bp2;) {
7149992Sbostic 	register i;
7217519Sedward 
7349992Sbostic 	bp = bp1 + ((bp2 - bp1) >> 1);
7449992Sbostic 	if ((i = *cp - *bp->bname) == 0 &&
7549992Sbostic 	    (i = Strcmp(cp, str2short(bp->bname))) == 0)
7649992Sbostic 	    return bp;
7749992Sbostic 	if (i < 0)
7849992Sbostic 	    bp2 = bp;
7949992Sbostic 	else
8049992Sbostic 	    bp1 = bp + 1;
8149992Sbostic     }
8249992Sbostic     return (0);
831294Sbill }
841294Sbill 
8549992Sbostic void
func(t,bp)861294Sbill func(t, bp)
8749992Sbostic     register struct command *t;
8849992Sbostic     register struct biltins *bp;
891294Sbill {
9049992Sbostic     int     i;
911294Sbill 
9249992Sbostic     xechoit(t->t_dcom);
9349992Sbostic     setname(bp->bname);
9449992Sbostic     i = blklen(t->t_dcom) - 1;
9549992Sbostic     if (i < bp->minargs)
9649992Sbostic 	stderror(ERR_NAME | ERR_TOOFEW);
9749992Sbostic     if (i > bp->maxargs)
9849992Sbostic 	stderror(ERR_NAME | ERR_TOOMANY);
9949992Sbostic     (*bp->bfunct) (t->t_dcom, t);
1001294Sbill }
1011294Sbill 
10249992Sbostic void
10350439Schristos /*ARGSUSED*/
doonintr(v,t)10450439Schristos doonintr(v, t)
10550439Schristos     Char **v;
10650439Schristos     struct command *t;
1071294Sbill {
10849992Sbostic     register Char *cp;
10949992Sbostic     register Char *vv = v[1];
110*68576Schristos     sigset_t sigset;
1111294Sbill 
11249992Sbostic     if (parintr == SIG_IGN)
11349992Sbostic 	return;
11449992Sbostic     if (setintr && intty)
11549992Sbostic 	stderror(ERR_NAME | ERR_TERMINAL);
11649992Sbostic     cp = gointr;
11749992Sbostic     gointr = 0;
11849992Sbostic     xfree((ptr_t) cp);
11949992Sbostic     if (vv == 0) {
120*68576Schristos 	if (setintr) {
121*68576Schristos 	    sigemptyset(&sigset);
122*68576Schristos 	    sigaddset(&sigset, SIGINT);
123*68576Schristos 	    sigprocmask(SIG_BLOCK, &sigset, NULL);
124*68576Schristos 	} else
12549992Sbostic 	    (void) signal(SIGINT, SIG_DFL);
12649992Sbostic 	gointr = 0;
12749992Sbostic     }
12849992Sbostic     else if (eq((vv = strip(vv)), STRminus)) {
12949992Sbostic 	(void) signal(SIGINT, SIG_IGN);
13049992Sbostic 	gointr = Strsave(STRminus);
13149992Sbostic     }
13249992Sbostic     else {
13349992Sbostic 	gointr = Strsave(vv);
13449992Sbostic 	(void) signal(SIGINT, pintr);
13549992Sbostic     }
1361294Sbill }
1371294Sbill 
13849992Sbostic void
13950439Schristos /*ARGSUSED*/
donohup(v,t)14050439Schristos donohup(v, t)
14150439Schristos     Char **v;
14250439Schristos     struct command *t;
1431294Sbill {
14449992Sbostic     if (intty)
14549992Sbostic 	stderror(ERR_NAME | ERR_TERMINAL);
14649992Sbostic     if (setintr == 0) {
14749992Sbostic 	(void) signal(SIGHUP, SIG_IGN);
14849992Sbostic     }
1491294Sbill }
1501294Sbill 
15149992Sbostic void
15250439Schristos /*ARGSUSED*/
dozip(v,t)15350439Schristos dozip(v, t)
15450439Schristos     Char **v;
15550439Schristos     struct command *t;
1561294Sbill {
15749992Sbostic     ;
1581294Sbill }
1591294Sbill 
16049992Sbostic void
prvars()1611294Sbill prvars()
1621294Sbill {
16349992Sbostic     plist(&shvhed);
1641294Sbill }
1651294Sbill 
16649992Sbostic void
16750439Schristos /*ARGSUSED*/
doalias(v,t)16850439Schristos doalias(v, t)
16950439Schristos     Char **v;
17050439Schristos     struct command *t;
1711294Sbill {
17249992Sbostic     register struct varent *vp;
17349992Sbostic     register Char *p;
1741294Sbill 
17549992Sbostic     v++;
17649992Sbostic     p = *v++;
17749992Sbostic     if (p == 0)
17849992Sbostic 	plist(&aliases);
17949992Sbostic     else if (*v == 0) {
18049992Sbostic 	vp = adrof1(strip(p), &aliases);
18150439Schristos 	if (vp) {
18250439Schristos 	    blkpr(cshout, vp->vec);
18350439Schristos 	    fputc('\n', cshout);
18450439Schristos 	}
18549992Sbostic     }
18649992Sbostic     else {
18749992Sbostic 	if (eq(p, STRalias) || eq(p, STRunalias)) {
18851589Schristos 	    setname(vis_str(p));
18949992Sbostic 	    stderror(ERR_NAME | ERR_DANGER);
1901294Sbill 	}
19149992Sbostic 	set1(strip(p), saveblk(v), &aliases);
19249992Sbostic     }
1931294Sbill }
1941294Sbill 
19549992Sbostic void
19650439Schristos /*ARGSUSED*/
unalias(v,t)19750439Schristos unalias(v, t)
19850439Schristos     Char **v;
19950439Schristos     struct command *t;
2001294Sbill {
20149992Sbostic     unset1(v, &aliases);
2021294Sbill }
2031294Sbill 
20449992Sbostic void
20550439Schristos /*ARGSUSED*/
dologout(v,t)20650439Schristos dologout(v, t)
20750439Schristos     Char **v;
20850439Schristos     struct command *t;
2091294Sbill {
21049992Sbostic     islogin();
21149992Sbostic     goodbye();
2121294Sbill }
2131294Sbill 
21449992Sbostic void
21550439Schristos /*ARGSUSED*/
dologin(v,t)21650439Schristos dologin(v, t)
21750439Schristos     Char **v;
21850439Schristos     struct command *t;
2191294Sbill {
22049992Sbostic     islogin();
22149992Sbostic     rechist();
22249992Sbostic     (void) signal(SIGTERM, parterm);
22350024Schristos     (void) execl(_PATH_LOGIN, "login", short2str(v[1]), NULL);
22449992Sbostic     untty();
22549992Sbostic     xexit(1);
2261294Sbill }
2271294Sbill 
22849992Sbostic static void
islogin()2291294Sbill islogin()
2301294Sbill {
23149992Sbostic     if (chkstop == 0 && setintr)
23249992Sbostic 	panystop(0);
23349992Sbostic     if (loginsh)
23449992Sbostic 	return;
23549992Sbostic     stderror(ERR_NOTLOGIN);
2361294Sbill }
2371294Sbill 
23849992Sbostic void
doif(v,kp)2391294Sbill doif(v, kp)
24049992Sbostic     Char  **v;
24149992Sbostic     struct command *kp;
2421294Sbill {
24349992Sbostic     register int i;
24449992Sbostic     register Char **vv;
2451294Sbill 
24649992Sbostic     v++;
24751009Schristos     i = expr(&v);
24849992Sbostic     vv = v;
24949992Sbostic     if (*vv == NULL)
25049992Sbostic 	stderror(ERR_NAME | ERR_EMPTYIF);
25149992Sbostic     if (eq(*vv, STRthen)) {
25249992Sbostic 	if (*++vv)
25349992Sbostic 	    stderror(ERR_NAME | ERR_IMPRTHEN);
25451589Schristos 	setname(vis_str(STRthen));
2551294Sbill 	/*
25649992Sbostic 	 * If expression was zero, then scan to else, otherwise just fall into
25749992Sbostic 	 * following code.
2581294Sbill 	 */
25949992Sbostic 	if (!i)
26050024Schristos 	    search(T_IF, 0, NULL);
26149992Sbostic 	return;
26249992Sbostic     }
26349992Sbostic     /*
26449992Sbostic      * Simple command attached to this if. Left shift the node in this tree,
26549992Sbostic      * munging it so we can reexecute it.
26649992Sbostic      */
26749992Sbostic     if (i) {
26849992Sbostic 	lshift(kp->t_dcom, vv - kp->t_dcom);
26949992Sbostic 	reexecute(kp);
27049992Sbostic 	donefds();
27149992Sbostic     }
2721294Sbill }
2731294Sbill 
2741294Sbill /*
2751294Sbill  * Reexecute a command, being careful not
2761294Sbill  * to redo i/o redirection, which is already set up.
2771294Sbill  */
27849992Sbostic static void
reexecute(kp)2791294Sbill reexecute(kp)
28049992Sbostic     register struct command *kp;
2811294Sbill {
28249992Sbostic     kp->t_dflg &= F_SAVE;
28349992Sbostic     kp->t_dflg |= F_REPEAT;
28449992Sbostic     /*
28549992Sbostic      * If tty is still ours to arbitrate, arbitrate it; otherwise dont even set
28649992Sbostic      * pgrp's as the jobs would then have no way to get the tty (we can't give
28749992Sbostic      * it to them, and our parent wouldn't know their pgrp, etc.
28849992Sbostic      */
28950023Sbostic     execute(kp, (tpgrp > 0 ? tpgrp : -1), NULL, NULL);
2901294Sbill }
2911294Sbill 
29249992Sbostic void
29350439Schristos /*ARGSUSED*/
doelse(v,t)29450439Schristos doelse(v, t)
29550439Schristos     Char **v;
29650439Schristos     struct command *t;
2971294Sbill {
29850024Schristos     search(T_ELSE, 0, NULL);
2991294Sbill }
3001294Sbill 
30149992Sbostic void
30250439Schristos /*ARGSUSED*/
dogoto(v,t)30350439Schristos dogoto(v, t)
30450439Schristos     Char **v;
30550439Schristos     struct command *t;
3061294Sbill {
30749992Sbostic     Char   *lp;
3081294Sbill 
30951420Schristos     gotolab(lp = globone(v[1], G_ERROR));
31051420Schristos     xfree((ptr_t) lp);
31151420Schristos }
31251420Schristos 
31351420Schristos void
gotolab(lab)31451420Schristos gotolab(lab)
31551420Schristos     Char *lab;
31651420Schristos {
31751420Schristos     register struct whyle *wp;
31849992Sbostic     /*
31949992Sbostic      * While we still can, locate any unknown ends of existing loops. This
32049992Sbostic      * obscure code is the WORST result of the fact that we don't really parse.
32149992Sbostic      */
32249992Sbostic     zlast = T_GOTO;
32349992Sbostic     for (wp = whyles; wp; wp = wp->w_next)
32451378Schristos 	if (wp->w_end.type == F_SEEK && wp->w_end.f_seek == 0) {
32550024Schristos 	    search(T_BREAK, 0, NULL);
32650944Schristos 	    btell(&wp->w_end);
32749992Sbostic 	}
32849992Sbostic 	else
32950944Schristos 	    bseek(&wp->w_end);
33051420Schristos     search(T_GOTO, 0, lab);
33149992Sbostic     /*
33249992Sbostic      * Eliminate loops which were exited.
33349992Sbostic      */
33449992Sbostic     wfree();
3351294Sbill }
3361294Sbill 
33749992Sbostic void
33850439Schristos /*ARGSUSED*/
doswitch(v,t)33950439Schristos doswitch(v, t)
34050439Schristos     Char **v;
34150439Schristos     struct command *t;
3421294Sbill {
34349992Sbostic     register Char *cp, *lp;
3441294Sbill 
34549992Sbostic     v++;
34649992Sbostic     if (!*v || *(*v++) != '(')
34749992Sbostic 	stderror(ERR_SYNTAX);
34849992Sbostic     cp = **v == ')' ? STRNULL : *v++;
34949992Sbostic     if (*(*v++) != ')')
35049992Sbostic 	v--;
35149992Sbostic     if (*v)
35249992Sbostic 	stderror(ERR_SYNTAX);
35349992Sbostic     search(T_SWITCH, 0, lp = globone(cp, G_ERROR));
35449992Sbostic     xfree((ptr_t) lp);
3551294Sbill }
3561294Sbill 
35749992Sbostic void
35850439Schristos /*ARGSUSED*/
dobreak(v,t)35950439Schristos dobreak(v, t)
36050439Schristos     Char **v;
36150439Schristos     struct command *t;
3621294Sbill {
36349992Sbostic     if (whyles)
36449992Sbostic 	toend();
36549992Sbostic     else
36649992Sbostic 	stderror(ERR_NAME | ERR_NOTWHILE);
3671294Sbill }
3681294Sbill 
36949992Sbostic void
37050439Schristos /*ARGSUSED*/
doexit(v,t)37150439Schristos doexit(v, t)
37250439Schristos     Char **v;
37350439Schristos     struct command *t;
3741294Sbill {
37549992Sbostic     if (chkstop == 0 && (intty || intact) && evalvec == 0)
37649992Sbostic 	panystop(0);
37749992Sbostic     /*
37849992Sbostic      * Don't DEMAND parentheses here either.
37949992Sbostic      */
38049992Sbostic     v++;
38149992Sbostic     if (*v) {
38251009Schristos 	set(STRstatus, putn(expr(&v)));
38349992Sbostic 	if (*v)
38449992Sbostic 	    stderror(ERR_NAME | ERR_EXPRESSION);
38549992Sbostic     }
38649992Sbostic     btoeof();
38749992Sbostic     if (intty)
38849992Sbostic 	(void) close(SHIN);
3891294Sbill }
3901294Sbill 
39149992Sbostic void
39250439Schristos /*ARGSUSED*/
doforeach(v,t)39350439Schristos doforeach(v, t)
39450439Schristos     Char **v;
39550439Schristos     struct command *t;
3961294Sbill {
39749992Sbostic     register Char *cp, *sp;
39849992Sbostic     register struct whyle *nwp;
3991294Sbill 
40049992Sbostic     v++;
40149992Sbostic     sp = cp = strip(*v);
40249992Sbostic     if (!letter(*sp))
40349992Sbostic 	stderror(ERR_NAME | ERR_VARBEGIN);
40449992Sbostic     while (*cp && alnum(*cp))
40549992Sbostic 	cp++;
40649992Sbostic     if (*cp)
40749992Sbostic 	stderror(ERR_NAME | ERR_VARALNUM);
40849992Sbostic     if ((cp - sp) > MAXVARLEN)
40949992Sbostic 	stderror(ERR_NAME | ERR_VARTOOLONG);
41049992Sbostic     cp = *v++;
41149992Sbostic     if (v[0][0] != '(' || v[blklen(v) - 1][0] != ')')
41249992Sbostic 	stderror(ERR_NAME | ERR_NOPAREN);
41349992Sbostic     v++;
41449992Sbostic     gflag = 0, tglob(v);
41549992Sbostic     v = globall(v);
41649992Sbostic     if (v == 0)
41749992Sbostic 	stderror(ERR_NAME | ERR_NOMATCH);
41849992Sbostic     nwp = (struct whyle *) xcalloc(1, sizeof *nwp);
41949992Sbostic     nwp->w_fe = nwp->w_fe0 = v;
42049992Sbostic     gargv = 0;
42150944Schristos     btell(&nwp->w_start);
42249992Sbostic     nwp->w_fename = Strsave(cp);
42349992Sbostic     nwp->w_next = whyles;
42451378Schristos     nwp->w_end.type = F_SEEK;
42549992Sbostic     whyles = nwp;
42649992Sbostic     /*
42749992Sbostic      * Pre-read the loop so as to be more comprehensible to a terminal user.
42849992Sbostic      */
42949992Sbostic     zlast = T_FOREACH;
43049992Sbostic     if (intty)
43149992Sbostic 	preread();
43249992Sbostic     doagain();
4331294Sbill }
4341294Sbill 
43549992Sbostic void
43650439Schristos /*ARGSUSED*/
dowhile(v,t)43750439Schristos dowhile(v, t)
43850439Schristos     Char **v;
43950439Schristos     struct command *t;
4401294Sbill {
44149992Sbostic     register int status;
44250944Schristos     register bool again = whyles != 0 && SEEKEQ(&whyles->w_start, &lineloc) &&
44349992Sbostic     whyles->w_fename == 0;
4441294Sbill 
44549992Sbostic     v++;
44649992Sbostic     /*
44749992Sbostic      * Implement prereading here also, taking care not to evaluate the
44849992Sbostic      * expression before the loop has been read up from a terminal.
44949992Sbostic      */
45049992Sbostic     if (intty && !again)
45149992Sbostic 	status = !exp0(&v, 1);
45249992Sbostic     else
45351009Schristos 	status = !expr(&v);
45449992Sbostic     if (*v)
45549992Sbostic 	stderror(ERR_NAME | ERR_EXPRESSION);
45649992Sbostic     if (!again) {
45749992Sbostic 	register struct whyle *nwp =
45849992Sbostic 	(struct whyle *) xcalloc(1, sizeof(*nwp));
4591294Sbill 
46049992Sbostic 	nwp->w_start = lineloc;
46151378Schristos 	nwp->w_end.type = F_SEEK;
46251378Schristos 	nwp->w_end.f_seek = 0;
46349992Sbostic 	nwp->w_next = whyles;
46449992Sbostic 	whyles = nwp;
46549992Sbostic 	zlast = T_WHILE;
46649992Sbostic 	if (intty) {
46749992Sbostic 	    /*
46849992Sbostic 	     * The tty preread
46949992Sbostic 	     */
47049992Sbostic 	    preread();
47149992Sbostic 	    doagain();
47249992Sbostic 	    return;
4731294Sbill 	}
47449992Sbostic     }
47549992Sbostic     if (status)
47649992Sbostic 	/* We ain't gonna loop no more, no more! */
47749992Sbostic 	toend();
4781294Sbill }
4791294Sbill 
48049992Sbostic static void
preread()4811294Sbill preread()
4821294Sbill {
483*68576Schristos     sigset_t sigset;
484*68576Schristos 
48550944Schristos     whyles->w_end.type = I_SEEK;
486*68576Schristos     if (setintr) {
487*68576Schristos 	sigemptyset(&sigset);
488*68576Schristos 	sigaddset(&sigset, SIGINT);
489*68576Schristos 	sigprocmask(SIG_UNBLOCK, &sigset, NULL);
490*68576Schristos     }
4911294Sbill 
49250024Schristos     search(T_BREAK, 0, NULL);		/* read the expression in */
49349992Sbostic     if (setintr)
494*68576Schristos 	sigprocmask(SIG_BLOCK, &sigset, NULL);
49550944Schristos     btell(&whyles->w_end);
4961294Sbill }
4971294Sbill 
49849992Sbostic void
49950439Schristos /*ARGSUSED*/
doend(v,t)50050439Schristos doend(v, t)
50150439Schristos     Char **v;
50250439Schristos     struct command *t;
5031294Sbill {
50449992Sbostic     if (!whyles)
50549992Sbostic 	stderror(ERR_NAME | ERR_NOTWHILE);
50650944Schristos     btell(&whyles->w_end);
50749992Sbostic     doagain();
5081294Sbill }
5091294Sbill 
51049992Sbostic void
51150439Schristos /*ARGSUSED*/
docontin(v,t)51250439Schristos docontin(v, t)
51350439Schristos     Char **v;
51450439Schristos     struct command *t;
5151294Sbill {
51649992Sbostic     if (!whyles)
51749992Sbostic 	stderror(ERR_NAME | ERR_NOTWHILE);
51849992Sbostic     doagain();
5191294Sbill }
5201294Sbill 
52149992Sbostic static void
doagain()5221294Sbill doagain()
5231294Sbill {
52449992Sbostic     /* Repeating a while is simple */
52549992Sbostic     if (whyles->w_fename == 0) {
52650944Schristos 	bseek(&whyles->w_start);
52749992Sbostic 	return;
52849992Sbostic     }
52949992Sbostic     /*
53049992Sbostic      * The foreach variable list actually has a spurious word ")" at the end of
53149992Sbostic      * the w_fe list.  Thus we are at the of the list if one word beyond this
53249992Sbostic      * is 0.
53349992Sbostic      */
53449992Sbostic     if (!whyles->w_fe[1]) {
53550439Schristos 	dobreak(NULL, NULL);
53649992Sbostic 	return;
53749992Sbostic     }
53849992Sbostic     set(whyles->w_fename, Strsave(*whyles->w_fe++));
53950944Schristos     bseek(&whyles->w_start);
5401294Sbill }
5411294Sbill 
54249992Sbostic void
dorepeat(v,kp)5431294Sbill dorepeat(v, kp)
54449992Sbostic     Char  **v;
54549992Sbostic     struct command *kp;
5461294Sbill {
54749992Sbostic     register int i;
548*68576Schristos     sigset_t sigset;
5491294Sbill 
55049992Sbostic     i = getn(v[1]);
551*68576Schristos     if (setintr) {
552*68576Schristos 	sigemptyset(&sigset);
553*68576Schristos 	sigaddset(&sigset, SIGINT);
554*68576Schristos 	sigprocmask(SIG_BLOCK, &sigset, NULL);
555*68576Schristos     }
55649992Sbostic     lshift(v, 2);
55749992Sbostic     while (i > 0) {
5581294Sbill 	if (setintr)
559*68576Schristos 	    sigprocmask(SIG_UNBLOCK, &sigset, NULL);
56049992Sbostic 	reexecute(kp);
56149992Sbostic 	--i;
56249992Sbostic     }
56349992Sbostic     donefds();
56449992Sbostic     if (setintr)
565*68576Schristos 	sigprocmask(SIG_UNBLOCK, &sigset, NULL);
5661294Sbill }
5671294Sbill 
56849992Sbostic void
56950439Schristos /*ARGSUSED*/
doswbrk(v,t)57050439Schristos doswbrk(v, t)
57150439Schristos     Char **v;
57250439Schristos     struct command *t;
5731294Sbill {
57450024Schristos     search(T_BRKSW, 0, NULL);
5751294Sbill }
5761294Sbill 
57749992Sbostic int
srchx(cp)5781294Sbill srchx(cp)
57949992Sbostic     register Char *cp;
5801294Sbill {
58149992Sbostic     register struct srch *sp, *sp1, *sp2;
58249992Sbostic     register i;
5831294Sbill 
58449992Sbostic     /*
58549992Sbostic      * Binary search Sp1 is the beginning of the current search range. Sp2 is
58649992Sbostic      * one past the end.
58749992Sbostic      */
58849992Sbostic     for (sp1 = srchn, sp2 = srchn + nsrchn; sp1 < sp2;) {
58949992Sbostic 	sp = sp1 + ((sp2 - sp1) >> 1);
59049992Sbostic 	if ((i = *cp - *sp->s_name) == 0 &&
59149992Sbostic 	    (i = Strcmp(cp, str2short(sp->s_name))) == 0)
59249992Sbostic 	    return sp->s_value;
59349992Sbostic 	if (i < 0)
59449992Sbostic 	    sp2 = sp;
59549992Sbostic 	else
59649992Sbostic 	    sp1 = sp + 1;
59749992Sbostic     }
59849992Sbostic     return (-1);
5991294Sbill }
6001294Sbill 
60149992Sbostic static Char Stype;
60249992Sbostic static Char *Sgoal;
6031294Sbill 
6041294Sbill /*VARARGS2*/
60551666Sbostic static void
search(type,level,goal)6061294Sbill search(type, level, goal)
60749992Sbostic     int     type;
60849992Sbostic     register int level;
60949992Sbostic     Char   *goal;
6101294Sbill {
61149992Sbostic     Char    wordbuf[BUFSIZ];
61249992Sbostic     register Char *aword = wordbuf;
61349992Sbostic     register Char *cp;
6141294Sbill 
61549992Sbostic     Stype = type;
61649992Sbostic     Sgoal = goal;
61750944Schristos     if (type == T_GOTO) {
61850944Schristos 	struct Ain a;
61950944Schristos 	a.type = F_SEEK;
62050944Schristos 	a.f_seek = 0;
62150944Schristos 	bseek(&a);
62250944Schristos     }
62349992Sbostic     do {
62450944Schristos 	if (intty && fseekp == feobp && aret == F_SEEK)
62550439Schristos 	    (void) fprintf(cshout, "? "), (void) fflush(cshout);
62649992Sbostic 	aword[0] = 0;
62749992Sbostic 	(void) getword(aword);
62849992Sbostic 	switch (srchx(aword)) {
6291294Sbill 
63049992Sbostic 	case T_ELSE:
63149992Sbostic 	    if (level == 0 && type == T_IF)
63249992Sbostic 		return;
63349992Sbostic 	    break;
6341294Sbill 
63549992Sbostic 	case T_IF:
63649992Sbostic 	    while (getword(aword))
63749992Sbostic 		continue;
63849992Sbostic 	    if ((type == T_IF || type == T_ELSE) &&
63949992Sbostic 		eq(aword, STRthen))
64049992Sbostic 		level++;
64149992Sbostic 	    break;
6421294Sbill 
64349992Sbostic 	case T_ENDIF:
64449992Sbostic 	    if (type == T_IF || type == T_ELSE)
64549992Sbostic 		level--;
64649992Sbostic 	    break;
6471294Sbill 
64849992Sbostic 	case T_FOREACH:
64949992Sbostic 	case T_WHILE:
65049992Sbostic 	    if (type == T_BREAK)
65149992Sbostic 		level++;
65249992Sbostic 	    break;
6531294Sbill 
65449992Sbostic 	case T_END:
65549992Sbostic 	    if (type == T_BREAK)
65649992Sbostic 		level--;
65749992Sbostic 	    break;
6581294Sbill 
65949992Sbostic 	case T_SWITCH:
66049992Sbostic 	    if (type == T_SWITCH || type == T_BRKSW)
66149992Sbostic 		level++;
66249992Sbostic 	    break;
6631294Sbill 
66449992Sbostic 	case T_ENDSW:
66549992Sbostic 	    if (type == T_SWITCH || type == T_BRKSW)
66649992Sbostic 		level--;
66749992Sbostic 	    break;
6681294Sbill 
66949992Sbostic 	case T_LABEL:
67049992Sbostic 	    if (type == T_GOTO && getword(aword) && eq(aword, goal))
67149992Sbostic 		level = -1;
67249992Sbostic 	    break;
6731294Sbill 
67449992Sbostic 	default:
67549992Sbostic 	    if (type != T_GOTO && (type != T_SWITCH || level != 0))
67649992Sbostic 		break;
67749992Sbostic 	    if (lastchr(aword) != ':')
67849992Sbostic 		break;
67949992Sbostic 	    aword[Strlen(aword) - 1] = 0;
68060237Schristos 	    if ((type == T_GOTO && eq(aword, goal)) ||
68160237Schristos 		(type == T_SWITCH && eq(aword, STRdefault)))
68249992Sbostic 		level = -1;
68349992Sbostic 	    break;
6841294Sbill 
68549992Sbostic 	case T_CASE:
68649992Sbostic 	    if (type != T_SWITCH || level != 0)
68749992Sbostic 		break;
68849992Sbostic 	    (void) getword(aword);
68949992Sbostic 	    if (lastchr(aword) == ':')
69049992Sbostic 		aword[Strlen(aword) - 1] = 0;
69149992Sbostic 	    cp = strip(Dfix1(aword));
69249992Sbostic 	    if (Gmatch(goal, cp))
69349992Sbostic 		level = -1;
69449992Sbostic 	    xfree((ptr_t) cp);
69549992Sbostic 	    break;
6961294Sbill 
69749992Sbostic 	case T_DEFAULT:
69849992Sbostic 	    if (type == T_SWITCH && level == 0)
69949992Sbostic 		level = -1;
70049992Sbostic 	    break;
70149992Sbostic 	}
70249992Sbostic 	(void) getword(NULL);
70349992Sbostic     } while (level >= 0);
7041294Sbill }
7051294Sbill 
70649992Sbostic static int
getword(wp)7071294Sbill getword(wp)
70849992Sbostic     register Char *wp;
7091294Sbill {
71049992Sbostic     register int found = 0;
71149992Sbostic     register int c, d;
71249992Sbostic     int     kwd = 0;
71349992Sbostic     Char   *owp = wp;
7141294Sbill 
71549992Sbostic     c = readc(1);
71649992Sbostic     d = 0;
71749992Sbostic     do {
71849992Sbostic 	while (c == ' ' || c == '\t')
71949992Sbostic 	    c = readc(1);
72049992Sbostic 	if (c == '#')
72149992Sbostic 	    do
72249992Sbostic 		c = readc(1);
72349992Sbostic 	    while (c >= 0 && c != '\n');
72449992Sbostic 	if (c < 0)
72549992Sbostic 	    goto past;
72649992Sbostic 	if (c == '\n') {
72749992Sbostic 	    if (wp)
72849992Sbostic 		break;
72949992Sbostic 	    return (0);
73049992Sbostic 	}
73149992Sbostic 	unreadc(c);
73249992Sbostic 	found = 1;
7331294Sbill 	do {
73449992Sbostic 	    c = readc(1);
73549992Sbostic 	    if (c == '\\' && (c = readc(1)) == '\n')
73649992Sbostic 		c = ' ';
73749992Sbostic 	    if (c == '\'' || c == '"')
73849992Sbostic 		if (d == 0)
73949992Sbostic 		    d = c;
74049992Sbostic 		else if (d == c)
74149992Sbostic 		    d = 0;
74249992Sbostic 	    if (c < 0)
74349992Sbostic 		goto past;
74449992Sbostic 	    if (wp) {
74549992Sbostic 		*wp++ = c;
74649992Sbostic 		*wp = 0;	/* end the string b4 test */
74749992Sbostic 	    }
74860237Schristos 	} while ((d || (!(kwd = keyword(owp)) && c != ' '
74960237Schristos 		  && c != '\t')) && c != '\n');
75049992Sbostic     } while (wp == 0);
75149992Sbostic 
75249992Sbostic     /*
75349992Sbostic      * if we have read a keyword ( "if", "switch" or "while" ) then we do not
75449992Sbostic      * need to unreadc the look-ahead char
75549992Sbostic      */
75649992Sbostic     if (!kwd) {
7571294Sbill 	unreadc(c);
7581294Sbill 	if (found)
75949992Sbostic 	    *--wp = 0;
76049992Sbostic     }
7611294Sbill 
76249992Sbostic     return (found);
76349992Sbostic 
7641294Sbill past:
76549992Sbostic     switch (Stype) {
7661294Sbill 
76749992Sbostic     case T_IF:
76849992Sbostic 	stderror(ERR_NAME | ERR_NOTFOUND, "then/endif");
7691294Sbill 
77049992Sbostic     case T_ELSE:
77149992Sbostic 	stderror(ERR_NAME | ERR_NOTFOUND, "endif");
7721294Sbill 
77349992Sbostic     case T_BRKSW:
77449992Sbostic     case T_SWITCH:
77549992Sbostic 	stderror(ERR_NAME | ERR_NOTFOUND, "endsw");
7761294Sbill 
77749992Sbostic     case T_BREAK:
77849992Sbostic 	stderror(ERR_NAME | ERR_NOTFOUND, "end");
7791294Sbill 
78049992Sbostic     case T_GOTO:
78151589Schristos 	setname(vis_str(Sgoal));
78249992Sbostic 	stderror(ERR_NAME | ERR_NOTFOUND, "label");
78349992Sbostic     }
78449992Sbostic     /* NOTREACHED */
78549992Sbostic     return (0);
7861294Sbill }
7871294Sbill 
78849992Sbostic /*
78949992Sbostic  * keyword(wp) determines if wp is one of the built-n functions if,
79049992Sbostic  * switch or while. It seems that when an if statement looks like
79149992Sbostic  * "if(" then getword above sucks in the '(' and so the search routine
79249992Sbostic  * never finds what it is scanning for. Rather than rewrite doword, I hack
79349992Sbostic  * in a test to see if the string forms a keyword. Then doword stops
79449992Sbostic  * and returns the word "if" -strike
79549992Sbostic  */
79649992Sbostic 
79749992Sbostic static int
keyword(wp)79849992Sbostic keyword(wp)
79949992Sbostic     Char   *wp;
8001294Sbill {
80149992Sbostic     static Char STRif[] = {'i', 'f', '\0'};
80249992Sbostic     static Char STRwhile[] = {'w', 'h', 'i', 'l', 'e', '\0'};
80349992Sbostic     static Char STRswitch[] = {'s', 'w', 'i', 't', 'c', 'h', '\0'};
8041294Sbill 
80549992Sbostic     if (!wp)
80649992Sbostic 	return (0);
80749992Sbostic 
80849992Sbostic     if ((Strcmp(wp, STRif) == 0) || (Strcmp(wp, STRwhile) == 0)
80949992Sbostic 	|| (Strcmp(wp, STRswitch) == 0))
81049992Sbostic 	return (1);
81149992Sbostic 
81249992Sbostic     return (0);
8131294Sbill }
8141294Sbill 
81549992Sbostic static void
toend()81649992Sbostic toend()
81749992Sbostic {
81851378Schristos     if (whyles->w_end.type == F_SEEK && whyles->w_end.f_seek == 0) {
81949992Sbostic 	search(T_BREAK, 0, NULL);
82050944Schristos 	btell(&whyles->w_end);
82150944Schristos 	whyles->w_end.f_seek--;
82249992Sbostic     }
82349992Sbostic     else
82450944Schristos 	bseek(&whyles->w_end);
82549992Sbostic     wfree();
82649992Sbostic }
82749992Sbostic 
82849992Sbostic void
wfree()8291294Sbill wfree()
8301294Sbill {
83150944Schristos     struct Ain    o;
83250944Schristos     struct whyle *nwp;
83351527Schristos 
83450944Schristos     btell(&o);
8351294Sbill 
83650944Schristos     for (; whyles; whyles = nwp) {
83749992Sbostic 	register struct whyle *wp = whyles;
83850944Schristos 	nwp = wp->w_next;
83951527Schristos 
84051527Schristos 	/*
84151527Schristos 	 * We free loops that have different seek types.
84251527Schristos 	 */
84351527Schristos 	if (wp->w_end.type != I_SEEK && wp->w_start.type == wp->w_end.type &&
84451527Schristos 	    wp->w_start.type == o.type) {
84551527Schristos 	    if (wp->w_end.type == F_SEEK) {
84651527Schristos 		if (o.f_seek >= wp->w_start.f_seek &&
84751527Schristos 		    (wp->w_end.f_seek == 0 || o.f_seek < wp->w_end.f_seek))
84851527Schristos 		    break;
84951527Schristos 	    }
85051527Schristos 	    else {
85151527Schristos 		if (o.a_seek >= wp->w_start.a_seek &&
85251527Schristos 		    (wp->w_end.a_seek == 0 || o.a_seek < wp->w_end.a_seek))
85351527Schristos 		    break;
85451527Schristos 	    }
85551420Schristos 	}
85651527Schristos 
85749992Sbostic 	if (wp->w_fe0)
85849992Sbostic 	    blkfree(wp->w_fe0);
85949992Sbostic 	if (wp->w_fename)
86049992Sbostic 	    xfree((ptr_t) wp->w_fename);
86149992Sbostic 	xfree((ptr_t) wp);
86249992Sbostic     }
8631294Sbill }
8641294Sbill 
86549992Sbostic void
86650439Schristos /*ARGSUSED*/
doecho(v,t)86750439Schristos doecho(v, t)
86850439Schristos     Char **v;
86950439Schristos     struct command *t;
8701294Sbill {
87149992Sbostic     xecho(' ', v);
8721294Sbill }
8731294Sbill 
87449992Sbostic void
87550439Schristos /*ARGSUSED*/
doglob(v,t)87650439Schristos doglob(v, t)
87750439Schristos     Char **v;
87850439Schristos     struct command *t;
8791294Sbill {
88049992Sbostic     xecho(0, v);
88150439Schristos     (void) fflush(cshout);
8821294Sbill }
8831294Sbill 
88449992Sbostic static void
xecho(sep,v)88549992Sbostic xecho(sep, v)
88650024Schristos     int    sep;
88749992Sbostic     register Char **v;
8881294Sbill {
88949992Sbostic     register Char *cp;
89049992Sbostic     int     nonl = 0;
891*68576Schristos     sigset_t sigset;
8921294Sbill 
893*68576Schristos     if (setintr) {
894*68576Schristos 	sigemptyset(&sigset);
895*68576Schristos 	sigaddset(&sigset, SIGINT);
896*68576Schristos 	sigprocmask(SIG_UNBLOCK, &sigset, NULL);
897*68576Schristos     }
89849992Sbostic     v++;
89949992Sbostic     if (*v == 0)
90049992Sbostic 	return;
90149992Sbostic     gflag = 0, tglob(v);
90249992Sbostic     if (gflag) {
90349992Sbostic 	v = globall(v);
90449992Sbostic 	if (v == 0)
90549992Sbostic 	    stderror(ERR_NAME | ERR_NOMATCH);
90649992Sbostic     }
90749992Sbostic     else {
90849992Sbostic 	v = gargv = saveblk(v);
90949992Sbostic 	trim(v);
91049992Sbostic     }
91149992Sbostic     if (sep == ' ' && *v && eq(*v, STRmn))
91249992Sbostic 	nonl++, v++;
91360237Schristos     while ((cp = *v++) != NULL) {
91449992Sbostic 	register int c;
9151294Sbill 
91660237Schristos 	while ((c = *cp++) != '\0')
91751589Schristos 	    (void) vis_fputc(c | QUOTE, cshout);
91849992Sbostic 
91949992Sbostic 	if (*v)
92051589Schristos 	    (void) vis_fputc(sep | QUOTE, cshout);
92149992Sbostic     }
92249992Sbostic     if (sep && nonl == 0)
92350439Schristos 	(void) fputc('\n', cshout);
92449992Sbostic     else
92550439Schristos 	(void) fflush(cshout);
92649992Sbostic     if (setintr)
927*68576Schristos 	sigprocmask(SIG_BLOCK, &sigset, NULL);
92849992Sbostic     if (gargv)
92949992Sbostic 	blkfree(gargv), gargv = 0;
9301294Sbill }
9311294Sbill 
93249992Sbostic void
93350439Schristos /*ARGSUSED*/
dosetenv(v,t)93450439Schristos dosetenv(v, t)
93550439Schristos     Char **v;
93650439Schristos     struct command *t;
9371294Sbill {
93849992Sbostic     Char   *vp, *lp;
939*68576Schristos     sigset_t sigset;
9401294Sbill 
94149992Sbostic     v++;
94249992Sbostic     if ((vp = *v++) == 0) {
94349992Sbostic 	register Char **ep;
94421753Sedward 
945*68576Schristos 	if (setintr) {
946*68576Schristos 	    sigemptyset(&sigset);
947*68576Schristos 	    sigaddset(&sigset, SIGINT);
948*68576Schristos 	    sigprocmask(SIG_UNBLOCK, &sigset, NULL);
949*68576Schristos 	}
95049992Sbostic 	for (ep = STR_environ; *ep; ep++)
95151589Schristos 	    (void) fprintf(cshout, "%s\n", vis_str(*ep));
95249992Sbostic 	return;
95349992Sbostic     }
95449992Sbostic     if ((lp = *v++) == 0)
95549992Sbostic 	lp = STRNULL;
95650746Schristos     Setenv(vp, lp = globone(lp, G_APPEND));
95749992Sbostic     if (eq(vp, STRPATH)) {
95849992Sbostic 	importpath(lp);
95950439Schristos 	dohash(NULL, NULL);
96049992Sbostic     }
96149992Sbostic     else if (eq(vp, STRLANG) || eq(vp, STRLC_CTYPE)) {
96249992Sbostic #ifdef NLS
96349992Sbostic 	int     k;
96449992Sbostic 
96549992Sbostic 	(void) setlocale(LC_ALL, "");
96651437Sleres 	for (k = 0200; k <= 0377 && !Isprint(k); k++)
96751437Sleres 		continue;
96849992Sbostic 	AsciiOnly = k > 0377;
96949992Sbostic #else
97049992Sbostic 	AsciiOnly = 0;
97149992Sbostic #endif				/* NLS */
97249992Sbostic     }
97349992Sbostic     xfree((ptr_t) lp);
9741294Sbill }
9751294Sbill 
97649992Sbostic void
97750439Schristos /*ARGSUSED*/
dounsetenv(v,t)97850439Schristos dounsetenv(v, t)
97950439Schristos     Char **v;
98050439Schristos     struct command *t;
9811294Sbill {
98249992Sbostic     Char  **ep, *p, *n;
98349992Sbostic     int     i, maxi;
98449992Sbostic     static Char *name = NULL;
9851294Sbill 
98649992Sbostic     if (name)
98749992Sbostic 	xfree((ptr_t) name);
98849992Sbostic     /*
98949992Sbostic      * Find the longest environment variable
99049992Sbostic      */
99149992Sbostic     for (maxi = 0, ep = STR_environ; *ep; ep++) {
99251437Sleres 	for (i = 0, p = *ep; *p && *p != '='; p++, i++)
99351437Sleres 	    continue;
99449992Sbostic 	if (i > maxi)
99549992Sbostic 	    maxi = i;
99649992Sbostic     }
99749992Sbostic 
99849992Sbostic     name = (Char *) xmalloc((size_t) (maxi + 1) * sizeof(Char));
99949992Sbostic 
100050160Schristos     while (++v && *v)
100150160Schristos 	for (maxi = 1; maxi;)
100250160Schristos 	    for (maxi = 0, ep = STR_environ; *ep; ep++) {
100351437Sleres 		for (n = name, p = *ep; *p && *p != '='; *n++ = *p++)
100451437Sleres 		    continue;
100550160Schristos 		*n = '\0';
100650160Schristos 		if (!Gmatch(name, *v))
100750160Schristos 		    continue;
100850160Schristos 		maxi = 1;
100950160Schristos 		if (eq(name, STRLANG) || eq(name, STRLC_CTYPE)) {
101049992Sbostic #ifdef NLS
101150160Schristos 		    int     k;
101249992Sbostic 
101350160Schristos 		    (void) setlocale(LC_ALL, "");
101451437Sleres 		    for (k = 0200; k <= 0377 && !Isprint(k); k++)
101551437Sleres 			continue;
101650160Schristos 		    AsciiOnly = k > 0377;
101749992Sbostic #else
101850160Schristos 		    AsciiOnly = getenv("LANG") == NULL &&
101950160Schristos 			getenv("LC_CTYPE") == NULL;
102049992Sbostic #endif				/* NLS */
102150160Schristos 		}
102250160Schristos 		/*
102350160Schristos 		 * Delete name, and start again cause the environment changes
102450160Schristos 		 */
102550160Schristos 		Unsetenv(name);
102650160Schristos 		break;
102749992Sbostic 	    }
102850976Schristos     xfree((ptr_t) name);
102950976Schristos     name = NULL;
10301294Sbill }
10311294Sbill 
103249992Sbostic void
Setenv(name,val)103349992Sbostic Setenv(name, val)
103449992Sbostic     Char   *name, *val;
10351294Sbill {
103649992Sbostic     register Char **ep = STR_environ;
103749992Sbostic     register Char *cp, *dp;
103849992Sbostic     Char   *blk[2];
103949992Sbostic     Char  **oep = ep;
10401294Sbill 
104149992Sbostic 
104249992Sbostic     for (; *ep; ep++) {
104349992Sbostic 	for (cp = name, dp = *ep; *cp && *cp == *dp; cp++, dp++)
104449992Sbostic 	    continue;
104549992Sbostic 	if (*cp != 0 || *dp != '=')
104649992Sbostic 	    continue;
104749992Sbostic 	cp = Strspl(STRequal, val);
104849992Sbostic 	xfree((ptr_t) * ep);
104949992Sbostic 	*ep = strip(Strspl(name, cp));
105049992Sbostic 	xfree((ptr_t) cp);
105149992Sbostic 	blkfree((Char **) environ);
105249992Sbostic 	environ = short2blk(STR_environ);
105349992Sbostic 	return;
105449992Sbostic     }
105549992Sbostic     cp = Strspl(name, STRequal);
105649992Sbostic     blk[0] = strip(Strspl(cp, val));
105749992Sbostic     xfree((ptr_t) cp);
105849992Sbostic     blk[1] = 0;
105949992Sbostic     STR_environ = blkspl(STR_environ, blk);
106049992Sbostic     blkfree((Char **) environ);
106149992Sbostic     environ = short2blk(STR_environ);
106249992Sbostic     xfree((ptr_t) oep);
10631294Sbill }
10641294Sbill 
106549992Sbostic static void
Unsetenv(name)106649992Sbostic Unsetenv(name)
106749992Sbostic     Char   *name;
10681294Sbill {
106949992Sbostic     register Char **ep = STR_environ;
107049992Sbostic     register Char *cp, *dp;
107149992Sbostic     Char  **oep = ep;
10721294Sbill 
107349992Sbostic     for (; *ep; ep++) {
107449992Sbostic 	for (cp = name, dp = *ep; *cp && *cp == *dp; cp++, dp++)
107549992Sbostic 	    continue;
107649992Sbostic 	if (*cp != 0 || *dp != '=')
107749992Sbostic 	    continue;
107849992Sbostic 	cp = *ep;
107949992Sbostic 	*ep = 0;
108049992Sbostic 	STR_environ = blkspl(STR_environ, ep + 1);
108149992Sbostic 	environ = short2blk(STR_environ);
108249992Sbostic 	*ep = cp;
108349992Sbostic 	xfree((ptr_t) cp);
108449992Sbostic 	xfree((ptr_t) oep);
108549992Sbostic 	return;
108649992Sbostic     }
10871294Sbill }
10881294Sbill 
108949992Sbostic void
109050439Schristos /*ARGSUSED*/
doumask(v,t)109150439Schristos doumask(v, t)
109250439Schristos     Char **v;
109350439Schristos     struct command *t;
10941294Sbill {
109549992Sbostic     register Char *cp = v[1];
109649992Sbostic     register int i;
10971294Sbill 
109849992Sbostic     if (cp == 0) {
109949992Sbostic 	i = umask(0);
110017519Sedward 	(void) umask(i);
110150439Schristos 	(void) fprintf(cshout, "%o\n", i);
110249992Sbostic 	return;
110349992Sbostic     }
110449992Sbostic     i = 0;
110549992Sbostic     while (Isdigit(*cp) && *cp != '8' && *cp != '9')
110649992Sbostic 	i = i * 8 + *cp++ - '0';
110749992Sbostic     if (*cp || i < 0 || i > 0777)
110849992Sbostic 	stderror(ERR_NAME | ERR_MASK);
110949992Sbostic     (void) umask(i);
11101294Sbill }
11111294Sbill 
111253727Smckusick typedef quad_t RLIM_TYPE;
11131294Sbill 
111449992Sbostic static struct limits {
111549992Sbostic     int     limconst;
111649992Sbostic     char   *limname;
111749992Sbostic     int     limdiv;
111849992Sbostic     char   *limscale;
111949992Sbostic }       limits[] = {
112060237Schristos     { RLIMIT_CPU,	"cputime",	1,	"seconds" },
112160237Schristos     { RLIMIT_FSIZE,	"filesize",	1024,	"kbytes" },
112260237Schristos     { RLIMIT_DATA,	"datasize",	1024,	"kbytes" },
112360237Schristos     { RLIMIT_STACK,	"stacksize",	1024,	"kbytes" },
112460237Schristos     { RLIMIT_CORE,	"coredumpsize", 1024,	"kbytes" },
112560237Schristos     { RLIMIT_RSS,	"memoryuse",	1024,	"kbytes" },
112660237Schristos     { RLIMIT_MEMLOCK,	"memorylocked",	1024,	"kbytes" },
112760237Schristos     { RLIMIT_NPROC,	"maxproc",	1,	"" },
112860237Schristos     { RLIMIT_NOFILE,	"openfiles",	1,	"" },
112960237Schristos     { -1,		NULL,		0,	NULL }
11301294Sbill };
11311294Sbill 
113249992Sbostic static struct limits *findlim();
113349992Sbostic static RLIM_TYPE getval();
113449992Sbostic static void limtail();
113549992Sbostic static void plim();
113649992Sbostic static int setlim();
113749992Sbostic 
113849992Sbostic static struct limits *
findlim(cp)11391294Sbill findlim(cp)
114049992Sbostic     Char   *cp;
11411294Sbill {
114249992Sbostic     register struct limits *lp, *res;
11431294Sbill 
114449992Sbostic     res = (struct limits *) NULL;
114549992Sbostic     for (lp = limits; lp->limconst >= 0; lp++)
114649992Sbostic 	if (prefix(cp, str2short(lp->limname))) {
114749992Sbostic 	    if (res)
114849992Sbostic 		stderror(ERR_NAME | ERR_AMBIG);
114949992Sbostic 	    res = lp;
115049992Sbostic 	}
115149992Sbostic     if (res)
115249992Sbostic 	return (res);
115349992Sbostic     stderror(ERR_NAME | ERR_LIMIT);
115449992Sbostic     /* NOTREACHED */
115549992Sbostic     return (0);
11561294Sbill }
11571294Sbill 
115849992Sbostic void
115950439Schristos /*ARGSUSED*/
dolimit(v,t)116050439Schristos dolimit(v, t)
116150439Schristos     Char **v;
116250439Schristos     struct command *t;
11631294Sbill {
116449992Sbostic     register struct limits *lp;
116549992Sbostic     register RLIM_TYPE limit;
116649992Sbostic     char    hard = 0;
11671294Sbill 
116849992Sbostic     v++;
116949992Sbostic     if (*v && eq(*v, STRmh)) {
117049992Sbostic 	hard = 1;
11711294Sbill 	v++;
117249992Sbostic     }
117349992Sbostic     if (*v == 0) {
117449992Sbostic 	for (lp = limits; lp->limconst >= 0; lp++)
117549992Sbostic 	    plim(lp, hard);
117649992Sbostic 	return;
117749992Sbostic     }
117849992Sbostic     lp = findlim(v[0]);
117949992Sbostic     if (v[1] == 0) {
118049992Sbostic 	plim(lp, hard);
118149992Sbostic 	return;
118249992Sbostic     }
118349992Sbostic     limit = getval(lp, v + 1);
118449992Sbostic     if (setlim(lp, hard, limit) < 0)
118549992Sbostic 	stderror(ERR_SILENT);
11861294Sbill }
11871294Sbill 
118849992Sbostic static  RLIM_TYPE
getval(lp,v)11891294Sbill getval(lp, v)
119049992Sbostic     register struct limits *lp;
119149992Sbostic     Char  **v;
11921294Sbill {
119349992Sbostic     register float f;
119449992Sbostic     double  atof();
119549992Sbostic     Char   *cp = *v++;
11961294Sbill 
119749992Sbostic     f = atof(short2str(cp));
119849992Sbostic 
119949992Sbostic     while (Isdigit(*cp) || *cp == '.' || *cp == 'e' || *cp == 'E')
120049992Sbostic 	cp++;
120149992Sbostic     if (*cp == 0) {
120249992Sbostic 	if (*v == 0)
120349992Sbostic 	    return ((RLIM_TYPE) ((f + 0.5) * lp->limdiv));
120449992Sbostic 	cp = *v;
120549992Sbostic     }
120649992Sbostic     switch (*cp) {
120749992Sbostic     case ':':
120849992Sbostic 	if (lp->limconst != RLIMIT_CPU)
120949992Sbostic 	    goto badscal;
121049992Sbostic 	return ((RLIM_TYPE) (f * 60.0 + atof(short2str(cp + 1))));
121149992Sbostic     case 'h':
121249992Sbostic 	if (lp->limconst != RLIMIT_CPU)
121349992Sbostic 	    goto badscal;
121449992Sbostic 	limtail(cp, "hours");
121549992Sbostic 	f *= 3600.0;
121649992Sbostic 	break;
121749992Sbostic     case 'm':
121849992Sbostic 	if (lp->limconst == RLIMIT_CPU) {
121949992Sbostic 	    limtail(cp, "minutes");
122049992Sbostic 	    f *= 60.0;
122149992Sbostic 	    break;
12221294Sbill 	}
122349992Sbostic 	*cp = 'm';
122449992Sbostic 	limtail(cp, "megabytes");
122549992Sbostic 	f *= 1024.0 * 1024.0;
122649992Sbostic 	break;
122749992Sbostic     case 's':
122849992Sbostic 	if (lp->limconst != RLIMIT_CPU)
122949992Sbostic 	    goto badscal;
123049992Sbostic 	limtail(cp, "seconds");
123149992Sbostic 	break;
123249992Sbostic     case 'M':
123349992Sbostic 	if (lp->limconst == RLIMIT_CPU)
123449992Sbostic 	    goto badscal;
123549992Sbostic 	*cp = 'm';
123649992Sbostic 	limtail(cp, "megabytes");
123749992Sbostic 	f *= 1024.0 * 1024.0;
123849992Sbostic 	break;
123949992Sbostic     case 'k':
124049992Sbostic 	if (lp->limconst == RLIMIT_CPU)
124149992Sbostic 	    goto badscal;
124249992Sbostic 	limtail(cp, "kbytes");
124349992Sbostic 	f *= 1024.0;
124449992Sbostic 	break;
124549992Sbostic     case 'u':
124649992Sbostic 	limtail(cp, "unlimited");
124749992Sbostic 	return (RLIM_INFINITY);
124849992Sbostic     default:
12491294Sbill badscal:
125049992Sbostic 	stderror(ERR_NAME | ERR_SCALEF);
125149992Sbostic     }
125252369Schristos     f += 0.5;
125354994Schristos     if (f > (float) RLIM_INFINITY)
125454994Schristos 	return RLIM_INFINITY;
125552369Schristos     else
125652369Schristos 	return ((RLIM_TYPE) f);
12571294Sbill }
12581294Sbill 
125949992Sbostic static void
limtail(cp,str)126049992Sbostic limtail(cp, str)
126149992Sbostic     Char   *cp;
126249992Sbostic     char   *str;
12631294Sbill {
126449992Sbostic     while (*cp && *cp == *str)
126549992Sbostic 	cp++, str++;
126649992Sbostic     if (*cp)
126749992Sbostic 	stderror(ERR_BADSCALE, str);
12681294Sbill }
12691294Sbill 
127049992Sbostic 
127149992Sbostic /*ARGSUSED*/
127249992Sbostic static void
plim(lp,hard)127318539Sedward plim(lp, hard)
127449992Sbostic     register struct limits *lp;
127549992Sbostic     Char    hard;
12761294Sbill {
127749992Sbostic     struct rlimit rlim;
127849992Sbostic     RLIM_TYPE limit;
12791294Sbill 
128050439Schristos     (void) fprintf(cshout, "%s \t", lp->limname);
128149992Sbostic 
128249992Sbostic     (void) getrlimit(lp->limconst, &rlim);
128349992Sbostic     limit = hard ? rlim.rlim_max : rlim.rlim_cur;
128449992Sbostic 
128549992Sbostic     if (limit == RLIM_INFINITY)
128650439Schristos 	(void) fprintf(cshout, "unlimited");
128749992Sbostic     else if (lp->limconst == RLIMIT_CPU)
128849992Sbostic 	psecs((long) limit);
128949992Sbostic     else
129051437Sleres 	(void) fprintf(cshout, "%ld %s", (long) (limit / lp->limdiv),
129150439Schristos 		       lp->limscale);
129250439Schristos     (void) fputc('\n', cshout);
12931294Sbill }
12941294Sbill 
129549992Sbostic void
129650439Schristos /*ARGSUSED*/
dounlimit(v,t)129750439Schristos dounlimit(v, t)
129850439Schristos     Char **v;
129950439Schristos     struct command *t;
13001294Sbill {
130149992Sbostic     register struct limits *lp;
130249992Sbostic     int     lerr = 0;
130349992Sbostic     Char    hard = 0;
13041294Sbill 
130549992Sbostic     v++;
130649992Sbostic     if (*v && eq(*v, STRmh)) {
130749992Sbostic 	hard = 1;
13081294Sbill 	v++;
130949992Sbostic     }
131049992Sbostic     if (*v == 0) {
131149992Sbostic 	for (lp = limits; lp->limconst >= 0; lp++)
131249992Sbostic 	    if (setlim(lp, hard, (RLIM_TYPE) RLIM_INFINITY) < 0)
131349992Sbostic 		lerr++;
131449992Sbostic 	if (lerr)
131549992Sbostic 	    stderror(ERR_SILENT);
131649992Sbostic 	return;
131749992Sbostic     }
131849992Sbostic     while (*v) {
131949992Sbostic 	lp = findlim(*v++);
132049992Sbostic 	if (setlim(lp, hard, (RLIM_TYPE) RLIM_INFINITY) < 0)
132149992Sbostic 	    stderror(ERR_SILENT);
132249992Sbostic     }
13231294Sbill }
13241294Sbill 
132549992Sbostic static int
setlim(lp,hard,limit)132618539Sedward setlim(lp, hard, limit)
132749992Sbostic     register struct limits *lp;
132849992Sbostic     Char    hard;
132949992Sbostic     RLIM_TYPE limit;
13301294Sbill {
133149992Sbostic     struct rlimit rlim;
13321294Sbill 
133349992Sbostic     (void) getrlimit(lp->limconst, &rlim);
133449992Sbostic 
133549992Sbostic     if (hard)
133649992Sbostic 	rlim.rlim_max = limit;
133749992Sbostic     else if (limit == RLIM_INFINITY && geteuid() != 0)
133849992Sbostic 	rlim.rlim_cur = rlim.rlim_max;
133949992Sbostic     else
134049992Sbostic 	rlim.rlim_cur = limit;
134149992Sbostic 
134249992Sbostic     if (setrlimit(lp->limconst, &rlim) < 0) {
134350439Schristos 	(void) fprintf(csherr, "%s: %s: Can't %s%s limit\n", bname, lp->limname,
134450439Schristos 		       limit == RLIM_INFINITY ? "remove" : "set",
134550439Schristos 		       hard ? " hard" : "");
134649992Sbostic 	return (-1);
134749992Sbostic     }
134849992Sbostic     return (0);
13491294Sbill }
13501294Sbill 
135149992Sbostic void
135250439Schristos /*ARGSUSED*/
dosuspend(v,t)135350439Schristos dosuspend(v, t)
135450439Schristos     Char **v;
135550439Schristos     struct command *t;
13561294Sbill {
135749992Sbostic     int     ctpgrp;
13581294Sbill 
135949992Sbostic     void    (*old) ();
136049992Sbostic 
136149992Sbostic     if (loginsh)
136249992Sbostic 	stderror(ERR_SUSPLOG);
136349992Sbostic     untty();
136449992Sbostic 
136549992Sbostic     old = signal(SIGTSTP, SIG_DFL);
136649992Sbostic     (void) kill(0, SIGTSTP);
136749992Sbostic     /* the shell stops here */
136849992Sbostic     (void) signal(SIGTSTP, old);
136949992Sbostic 
137049992Sbostic     if (tpgrp != -1) {
137149992Sbostic 	ctpgrp = tcgetpgrp(FSHTTY);
137250439Schristos 	while  (ctpgrp != opgrp) {
137349992Sbostic 	    old = signal(SIGTTIN, SIG_DFL);
137449992Sbostic 	    (void) kill(0, SIGTTIN);
137549992Sbostic 	    (void) signal(SIGTTIN, old);
13761294Sbill 	}
137749992Sbostic 	(void) setpgid(0, shpgrp);
137849992Sbostic 	(void) tcsetpgrp(FSHTTY, shpgrp);
137949992Sbostic     }
13801294Sbill }
13811294Sbill 
138249992Sbostic /* This is the dreaded EVAL built-in.
138349992Sbostic  *   If you don't fiddle with file descriptors, and reset didfds,
138449992Sbostic  *   this command will either ignore redirection inside or outside
138549992Sbostic  *   its aguments, e.g. eval "date >x"  vs.  eval "date" >x
138649992Sbostic  *   The stuff here seems to work, but I did it by trial and error rather
138749992Sbostic  *   than really knowing what was going on.  If tpgrp is zero, we are
138849992Sbostic  *   probably a background eval, e.g. "eval date &", and we want to
138949992Sbostic  *   make sure that any processes we start stay in our pgrp.
139049992Sbostic  *   This is also the case for "time eval date" -- stay in same pgrp.
139149992Sbostic  *   Otherwise, under stty tostop, processes will stop in the wrong
139249992Sbostic  *   pgrp, with no way for the shell to get them going again.  -IAN!
139349992Sbostic  */
139450439Schristos static Char **gv = NULL;
139549992Sbostic void
139650439Schristos /*ARGSUSED*/
doeval(v,t)139750439Schristos doeval(v, t)
139850439Schristos     Char **v;
139950439Schristos     struct command *t;
14001294Sbill {
140149992Sbostic     Char  **oevalvec;
140249992Sbostic     Char   *oevalp;
140349992Sbostic     int     odidfds;
140449992Sbostic     jmp_buf osetexit;
140549992Sbostic     int     my_reenter;
140650439Schristos     Char  **savegv = gv;
140749992Sbostic     int     saveIN;
140849992Sbostic     int     saveOUT;
140950439Schristos     int     saveERR;
141049992Sbostic     int     oSHIN;
141149992Sbostic     int     oSHOUT;
141250439Schristos     int     oSHERR;
14131294Sbill 
141460237Schristos     UNREGISTER(v);
141560237Schristos 
141649992Sbostic     oevalvec = evalvec;
141749992Sbostic     oevalp = evalp;
141849992Sbostic     odidfds = didfds;
141949992Sbostic     oSHIN = SHIN;
142049992Sbostic     oSHOUT = SHOUT;
142150439Schristos     oSHERR = SHERR;
142249992Sbostic 
142349992Sbostic     v++;
142449992Sbostic     if (*v == 0)
142549992Sbostic 	return;
142649992Sbostic     gflag = 0, tglob(v);
142749992Sbostic     if (gflag) {
142849992Sbostic 	gv = v = globall(v);
142949992Sbostic 	gargv = 0;
143049992Sbostic 	if (v == 0)
143149992Sbostic 	    stderror(ERR_NOMATCH);
143249992Sbostic 	v = copyblk(v);
143349992Sbostic     }
143449992Sbostic     else {
143550024Schristos 	gv = NULL;
143649992Sbostic 	v = copyblk(v);
143749992Sbostic 	trim(v);
143849992Sbostic     }
143949992Sbostic 
144049992Sbostic     saveIN = dcopy(SHIN, -1);
144149992Sbostic     saveOUT = dcopy(SHOUT, -1);
144250439Schristos     saveERR = dcopy(SHERR, -1);
144349992Sbostic 
144449992Sbostic     getexit(osetexit);
144549992Sbostic 
144649992Sbostic     if ((my_reenter = setexit()) == 0) {
144749992Sbostic 	evalvec = v;
144849992Sbostic 	evalp = 0;
144949992Sbostic 	SHIN = dcopy(0, -1);
145049992Sbostic 	SHOUT = dcopy(1, -1);
145150439Schristos 	SHERR = dcopy(2, -1);
145249992Sbostic 	didfds = 0;
145349992Sbostic 	process(0);
145449992Sbostic     }
145549992Sbostic 
145649992Sbostic     evalvec = oevalvec;
145749992Sbostic     evalp = oevalp;
145849992Sbostic     doneinp = 0;
145949992Sbostic     didfds = odidfds;
146049992Sbostic     (void) close(SHIN);
146149992Sbostic     (void) close(SHOUT);
146250439Schristos     (void) close(SHERR);
146349992Sbostic     SHIN = dmove(saveIN, oSHIN);
146449992Sbostic     SHOUT = dmove(saveOUT, oSHOUT);
146550439Schristos     SHERR = dmove(saveERR, oSHERR);
146649992Sbostic     if (gv)
146750439Schristos 	blkfree(gv), gv = NULL;
146849992Sbostic     resexit(osetexit);
146950439Schristos     gv = savegv;
147049992Sbostic     if (my_reenter)
147149992Sbostic 	stderror(ERR_SILENT);
14721294Sbill }
147350639Schristos 
147450639Schristos void
147550639Schristos /*ARGSUSED*/
doprintf(v,t)147650639Schristos doprintf(v, t)
147750639Schristos     Char **v;
147850639Schristos     struct command *t;
147950639Schristos {
148050639Schristos     char **c;
148150639Schristos     extern int progprintf __P((int, char **));
148250639Schristos     int ret;
148351437Sleres 
148450639Schristos     ret = progprintf(blklen(v), c = short2blk(v));
148553566Schristos     (void) fflush(cshout);
148653566Schristos     (void) fflush(csherr);
148750639Schristos 
148850639Schristos     blkfree((Char **) c);
148950639Schristos     if (ret)
149050639Schristos 	stderror(ERR_SILENT);
149150639Schristos }
1492