xref: /csrg-svn/bin/csh/func.c (revision 50639)
147823Sbostic /*-
247823Sbostic  * Copyright (c) 1980, 1991 The Regents of the University of California.
347823Sbostic  * All rights reserved.
447823Sbostic  *
547823Sbostic  * %sccs.include.redist.c%
621933Sdist  */
721933Sdist 
817519Sedward #ifndef lint
9*50639Schristos static char sccsid[] = "@(#)func.c	5.22 (Berkeley) 07/28/91";
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));
3650024Schristos static int	getword __P((Char *));
3750024Schristos static int	keyword __P((Char *));
3850024Schristos static void	Unsetenv __P((Char *));
3950024Schristos static void	toend __P((void));
4050024Schristos static void	xecho __P((int, Char **));
4149992Sbostic 
421294Sbill struct biltins *
431294Sbill isbfunc(t)
4449992Sbostic     struct command *t;
451294Sbill {
4649992Sbostic     register Char *cp = t->t_dcom[0];
4749992Sbostic     register struct biltins *bp, *bp1, *bp2;
4849992Sbostic     static struct biltins label = {"", dozip, 0, 0};
4949992Sbostic     static struct biltins foregnd = {"%job", dofg1, 0, 0};
5049992Sbostic     static struct biltins backgnd = {"%job &", dobg1, 0, 0};
511294Sbill 
5249992Sbostic     if (lastchr(cp) == ':') {
5349992Sbostic 	label.bname = short2str(cp);
5449992Sbostic 	return (&label);
5549992Sbostic     }
5649992Sbostic     if (*cp == '%') {
5749992Sbostic 	if (t->t_dflg & F_AMPERSAND) {
5849992Sbostic 	    t->t_dflg &= ~F_AMPERSAND;
5949992Sbostic 	    backgnd.bname = short2str(cp);
6049992Sbostic 	    return (&backgnd);
611294Sbill 	}
6249992Sbostic 	foregnd.bname = short2str(cp);
6349992Sbostic 	return (&foregnd);
6449992Sbostic     }
6549992Sbostic     /*
6649992Sbostic      * Binary search Bp1 is the beginning of the current search range. Bp2 is
6749992Sbostic      * one past the end.
6849992Sbostic      */
6949992Sbostic     for (bp1 = bfunc, bp2 = bfunc + nbfunc; bp1 < bp2;) {
7049992Sbostic 	register i;
7117519Sedward 
7249992Sbostic 	bp = bp1 + ((bp2 - bp1) >> 1);
7349992Sbostic 	if ((i = *cp - *bp->bname) == 0 &&
7449992Sbostic 	    (i = Strcmp(cp, str2short(bp->bname))) == 0)
7549992Sbostic 	    return bp;
7649992Sbostic 	if (i < 0)
7749992Sbostic 	    bp2 = bp;
7849992Sbostic 	else
7949992Sbostic 	    bp1 = bp + 1;
8049992Sbostic     }
8149992Sbostic     return (0);
821294Sbill }
831294Sbill 
8449992Sbostic void
851294Sbill func(t, bp)
8649992Sbostic     register struct command *t;
8749992Sbostic     register struct biltins *bp;
881294Sbill {
8949992Sbostic     int     i;
901294Sbill 
9149992Sbostic     xechoit(t->t_dcom);
9249992Sbostic     setname(bp->bname);
9349992Sbostic     i = blklen(t->t_dcom) - 1;
9449992Sbostic     if (i < bp->minargs)
9549992Sbostic 	stderror(ERR_NAME | ERR_TOOFEW);
9649992Sbostic     if (i > bp->maxargs)
9749992Sbostic 	stderror(ERR_NAME | ERR_TOOMANY);
9849992Sbostic     (*bp->bfunct) (t->t_dcom, t);
991294Sbill }
1001294Sbill 
10149992Sbostic void
10250439Schristos /*ARGSUSED*/
10350439Schristos doonintr(v, t)
10450439Schristos     Char **v;
10550439Schristos     struct command *t;
1061294Sbill {
10749992Sbostic     register Char *cp;
10849992Sbostic     register Char *vv = v[1];
1091294Sbill 
11049992Sbostic     if (parintr == SIG_IGN)
11149992Sbostic 	return;
11249992Sbostic     if (setintr && intty)
11349992Sbostic 	stderror(ERR_NAME | ERR_TERMINAL);
11449992Sbostic     cp = gointr;
11549992Sbostic     gointr = 0;
11649992Sbostic     xfree((ptr_t) cp);
11749992Sbostic     if (vv == 0) {
11849992Sbostic 	if (setintr)
11949992Sbostic 	    (void) sigblock(sigmask(SIGINT));
12049992Sbostic 	else
12149992Sbostic 	    (void) signal(SIGINT, SIG_DFL);
12249992Sbostic 	gointr = 0;
12349992Sbostic     }
12449992Sbostic     else if (eq((vv = strip(vv)), STRminus)) {
12549992Sbostic 	(void) signal(SIGINT, SIG_IGN);
12649992Sbostic 	gointr = Strsave(STRminus);
12749992Sbostic     }
12849992Sbostic     else {
12949992Sbostic 	gointr = Strsave(vv);
13049992Sbostic 	(void) signal(SIGINT, pintr);
13149992Sbostic     }
1321294Sbill }
1331294Sbill 
13449992Sbostic void
13550439Schristos /*ARGSUSED*/
13650439Schristos donohup(v, t)
13750439Schristos     Char **v;
13850439Schristos     struct command *t;
1391294Sbill {
14049992Sbostic     if (intty)
14149992Sbostic 	stderror(ERR_NAME | ERR_TERMINAL);
14249992Sbostic     if (setintr == 0) {
14349992Sbostic 	(void) signal(SIGHUP, SIG_IGN);
14449992Sbostic     }
1451294Sbill }
1461294Sbill 
14749992Sbostic void
14850439Schristos /*ARGSUSED*/
14950439Schristos dozip(v, t)
15050439Schristos     Char **v;
15150439Schristos     struct command *t;
1521294Sbill {
15349992Sbostic     ;
1541294Sbill }
1551294Sbill 
15649992Sbostic void
1571294Sbill prvars()
1581294Sbill {
15949992Sbostic     plist(&shvhed);
1601294Sbill }
1611294Sbill 
16249992Sbostic void
16350439Schristos /*ARGSUSED*/
16450439Schristos doalias(v, t)
16550439Schristos     Char **v;
16650439Schristos     struct command *t;
1671294Sbill {
16849992Sbostic     register struct varent *vp;
16949992Sbostic     register Char *p;
1701294Sbill 
17149992Sbostic     v++;
17249992Sbostic     p = *v++;
17349992Sbostic     if (p == 0)
17449992Sbostic 	plist(&aliases);
17549992Sbostic     else if (*v == 0) {
17649992Sbostic 	vp = adrof1(strip(p), &aliases);
17750439Schristos 	if (vp) {
17850439Schristos 	    blkpr(cshout, vp->vec);
17950439Schristos 	    fputc('\n', cshout);
18050439Schristos 	}
18149992Sbostic     }
18249992Sbostic     else {
18349992Sbostic 	if (eq(p, STRalias) || eq(p, STRunalias)) {
18449992Sbostic 	    setname(short2str(p));
18549992Sbostic 	    stderror(ERR_NAME | ERR_DANGER);
1861294Sbill 	}
18749992Sbostic 	set1(strip(p), saveblk(v), &aliases);
18849992Sbostic     }
1891294Sbill }
1901294Sbill 
19149992Sbostic void
19250439Schristos /*ARGSUSED*/
19350439Schristos unalias(v, t)
19450439Schristos     Char **v;
19550439Schristos     struct command *t;
1961294Sbill {
19749992Sbostic     unset1(v, &aliases);
1981294Sbill }
1991294Sbill 
20049992Sbostic void
20150439Schristos /*ARGSUSED*/
20250439Schristos dologout(v, t)
20350439Schristos     Char **v;
20450439Schristos     struct command *t;
2051294Sbill {
20649992Sbostic     islogin();
20749992Sbostic     goodbye();
2081294Sbill }
2091294Sbill 
21049992Sbostic void
21150439Schristos /*ARGSUSED*/
21250439Schristos dologin(v, t)
21350439Schristos     Char **v;
21450439Schristos     struct command *t;
2151294Sbill {
21649992Sbostic     islogin();
21749992Sbostic     rechist();
21849992Sbostic     (void) signal(SIGTERM, parterm);
21950024Schristos     (void) execl(_PATH_LOGIN, "login", short2str(v[1]), NULL);
22049992Sbostic     untty();
22149992Sbostic     xexit(1);
2221294Sbill }
2231294Sbill 
22449992Sbostic static void
2251294Sbill islogin()
2261294Sbill {
22749992Sbostic     if (chkstop == 0 && setintr)
22849992Sbostic 	panystop(0);
22949992Sbostic     if (loginsh)
23049992Sbostic 	return;
23149992Sbostic     stderror(ERR_NOTLOGIN);
2321294Sbill }
2331294Sbill 
23449992Sbostic void
2351294Sbill doif(v, kp)
23649992Sbostic     Char  **v;
23749992Sbostic     struct command *kp;
2381294Sbill {
23949992Sbostic     register int i;
24049992Sbostic     register Char **vv;
2411294Sbill 
24249992Sbostic     v++;
24349992Sbostic     i = exp(&v);
24449992Sbostic     vv = v;
24549992Sbostic     if (*vv == NULL)
24649992Sbostic 	stderror(ERR_NAME | ERR_EMPTYIF);
24749992Sbostic     if (eq(*vv, STRthen)) {
24849992Sbostic 	if (*++vv)
24949992Sbostic 	    stderror(ERR_NAME | ERR_IMPRTHEN);
25049992Sbostic 	setname(short2str(STRthen));
2511294Sbill 	/*
25249992Sbostic 	 * If expression was zero, then scan to else, otherwise just fall into
25349992Sbostic 	 * following code.
2541294Sbill 	 */
25549992Sbostic 	if (!i)
25650024Schristos 	    search(T_IF, 0, NULL);
25749992Sbostic 	return;
25849992Sbostic     }
25949992Sbostic     /*
26049992Sbostic      * Simple command attached to this if. Left shift the node in this tree,
26149992Sbostic      * munging it so we can reexecute it.
26249992Sbostic      */
26349992Sbostic     if (i) {
26449992Sbostic 	lshift(kp->t_dcom, vv - kp->t_dcom);
26549992Sbostic 	reexecute(kp);
26649992Sbostic 	donefds();
26749992Sbostic     }
2681294Sbill }
2691294Sbill 
2701294Sbill /*
2711294Sbill  * Reexecute a command, being careful not
2721294Sbill  * to redo i/o redirection, which is already set up.
2731294Sbill  */
27449992Sbostic static void
2751294Sbill reexecute(kp)
27649992Sbostic     register struct command *kp;
2771294Sbill {
27849992Sbostic     kp->t_dflg &= F_SAVE;
27949992Sbostic     kp->t_dflg |= F_REPEAT;
28049992Sbostic     /*
28149992Sbostic      * If tty is still ours to arbitrate, arbitrate it; otherwise dont even set
28249992Sbostic      * pgrp's as the jobs would then have no way to get the tty (we can't give
28349992Sbostic      * it to them, and our parent wouldn't know their pgrp, etc.
28449992Sbostic      */
28550023Sbostic     execute(kp, (tpgrp > 0 ? tpgrp : -1), NULL, NULL);
2861294Sbill }
2871294Sbill 
28849992Sbostic void
28950439Schristos /*ARGSUSED*/
29050439Schristos doelse(v, t)
29150439Schristos     Char **v;
29250439Schristos     struct command *t;
2931294Sbill {
29450024Schristos     search(T_ELSE, 0, NULL);
2951294Sbill }
2961294Sbill 
29749992Sbostic void
29850439Schristos /*ARGSUSED*/
29950439Schristos dogoto(v, t)
30050439Schristos     Char **v;
30150439Schristos     struct command *t;
3021294Sbill {
30349992Sbostic     register struct whyle *wp;
30449992Sbostic     Char   *lp;
3051294Sbill 
30649992Sbostic     /*
30749992Sbostic      * While we still can, locate any unknown ends of existing loops. This
30849992Sbostic      * obscure code is the WORST result of the fact that we don't really parse.
30949992Sbostic      */
31049992Sbostic     zlast = T_GOTO;
31149992Sbostic     for (wp = whyles; wp; wp = wp->w_next)
31249992Sbostic 	if (wp->w_end == 0) {
31350024Schristos 	    search(T_BREAK, 0, NULL);
31450023Sbostic 	    wp->w_end = fseekp;
31549992Sbostic 	}
31649992Sbostic 	else
31749992Sbostic 	    bseek(wp->w_end);
31849992Sbostic     search(T_GOTO, 0, lp = globone(v[1], G_ERROR));
31949992Sbostic     xfree((ptr_t) lp);
32049992Sbostic     /*
32149992Sbostic      * Eliminate loops which were exited.
32249992Sbostic      */
32349992Sbostic     wfree();
3241294Sbill }
3251294Sbill 
32649992Sbostic void
32750439Schristos /*ARGSUSED*/
32850439Schristos doswitch(v, t)
32950439Schristos     Char **v;
33050439Schristos     struct command *t;
3311294Sbill {
33249992Sbostic     register Char *cp, *lp;
3331294Sbill 
33449992Sbostic     v++;
33549992Sbostic     if (!*v || *(*v++) != '(')
33649992Sbostic 	stderror(ERR_SYNTAX);
33749992Sbostic     cp = **v == ')' ? STRNULL : *v++;
33849992Sbostic     if (*(*v++) != ')')
33949992Sbostic 	v--;
34049992Sbostic     if (*v)
34149992Sbostic 	stderror(ERR_SYNTAX);
34249992Sbostic     search(T_SWITCH, 0, lp = globone(cp, G_ERROR));
34349992Sbostic     xfree((ptr_t) lp);
3441294Sbill }
3451294Sbill 
34649992Sbostic void
34750439Schristos /*ARGSUSED*/
34850439Schristos dobreak(v, t)
34950439Schristos     Char **v;
35050439Schristos     struct command *t;
3511294Sbill {
35249992Sbostic     if (whyles)
35349992Sbostic 	toend();
35449992Sbostic     else
35549992Sbostic 	stderror(ERR_NAME | ERR_NOTWHILE);
3561294Sbill }
3571294Sbill 
35849992Sbostic void
35950439Schristos /*ARGSUSED*/
36050439Schristos doexit(v, t)
36150439Schristos     Char **v;
36250439Schristos     struct command *t;
3631294Sbill {
36449992Sbostic     if (chkstop == 0 && (intty || intact) && evalvec == 0)
36549992Sbostic 	panystop(0);
36649992Sbostic     /*
36749992Sbostic      * Don't DEMAND parentheses here either.
36849992Sbostic      */
36949992Sbostic     v++;
37049992Sbostic     if (*v) {
37149992Sbostic 	set(STRstatus, putn(exp(&v)));
37249992Sbostic 	if (*v)
37349992Sbostic 	    stderror(ERR_NAME | ERR_EXPRESSION);
37449992Sbostic     }
37549992Sbostic     btoeof();
37649992Sbostic     if (intty)
37749992Sbostic 	(void) close(SHIN);
3781294Sbill }
3791294Sbill 
38049992Sbostic void
38150439Schristos /*ARGSUSED*/
38250439Schristos doforeach(v, t)
38350439Schristos     Char **v;
38450439Schristos     struct command *t;
3851294Sbill {
38649992Sbostic     register Char *cp, *sp;
38749992Sbostic     register struct whyle *nwp;
3881294Sbill 
38949992Sbostic     v++;
39049992Sbostic     sp = cp = strip(*v);
39149992Sbostic     if (!letter(*sp))
39249992Sbostic 	stderror(ERR_NAME | ERR_VARBEGIN);
39349992Sbostic     while (*cp && alnum(*cp))
39449992Sbostic 	cp++;
39549992Sbostic     if (*cp)
39649992Sbostic 	stderror(ERR_NAME | ERR_VARALNUM);
39749992Sbostic     if ((cp - sp) > MAXVARLEN)
39849992Sbostic 	stderror(ERR_NAME | ERR_VARTOOLONG);
39949992Sbostic     cp = *v++;
40049992Sbostic     if (v[0][0] != '(' || v[blklen(v) - 1][0] != ')')
40149992Sbostic 	stderror(ERR_NAME | ERR_NOPAREN);
40249992Sbostic     v++;
40349992Sbostic     gflag = 0, tglob(v);
40449992Sbostic     v = globall(v);
40549992Sbostic     if (v == 0)
40649992Sbostic 	stderror(ERR_NAME | ERR_NOMATCH);
40749992Sbostic     nwp = (struct whyle *) xcalloc(1, sizeof *nwp);
40849992Sbostic     nwp->w_fe = nwp->w_fe0 = v;
40949992Sbostic     gargv = 0;
41050023Sbostic     nwp->w_start = fseekp;
41149992Sbostic     nwp->w_fename = Strsave(cp);
41249992Sbostic     nwp->w_next = whyles;
41349992Sbostic     whyles = nwp;
41449992Sbostic     /*
41549992Sbostic      * Pre-read the loop so as to be more comprehensible to a terminal user.
41649992Sbostic      */
41749992Sbostic     zlast = T_FOREACH;
41849992Sbostic     if (intty)
41949992Sbostic 	preread();
42049992Sbostic     doagain();
4211294Sbill }
4221294Sbill 
42349992Sbostic void
42450439Schristos /*ARGSUSED*/
42550439Schristos dowhile(v, t)
42650439Schristos     Char **v;
42750439Schristos     struct command *t;
4281294Sbill {
42949992Sbostic     register int status;
43049992Sbostic     register bool again = whyles != 0 && whyles->w_start == lineloc &&
43149992Sbostic     whyles->w_fename == 0;
4321294Sbill 
43349992Sbostic     v++;
43449992Sbostic     /*
43549992Sbostic      * Implement prereading here also, taking care not to evaluate the
43649992Sbostic      * expression before the loop has been read up from a terminal.
43749992Sbostic      */
43849992Sbostic     if (intty && !again)
43949992Sbostic 	status = !exp0(&v, 1);
44049992Sbostic     else
44149992Sbostic 	status = !exp(&v);
44249992Sbostic     if (*v)
44349992Sbostic 	stderror(ERR_NAME | ERR_EXPRESSION);
44449992Sbostic     if (!again) {
44549992Sbostic 	register struct whyle *nwp =
44649992Sbostic 	(struct whyle *) xcalloc(1, sizeof(*nwp));
4471294Sbill 
44849992Sbostic 	nwp->w_start = lineloc;
44949992Sbostic 	nwp->w_end = 0;
45049992Sbostic 	nwp->w_next = whyles;
45149992Sbostic 	whyles = nwp;
45249992Sbostic 	zlast = T_WHILE;
45349992Sbostic 	if (intty) {
45449992Sbostic 	    /*
45549992Sbostic 	     * The tty preread
45649992Sbostic 	     */
45749992Sbostic 	    preread();
45849992Sbostic 	    doagain();
45949992Sbostic 	    return;
4601294Sbill 	}
46149992Sbostic     }
46249992Sbostic     if (status)
46349992Sbostic 	/* We ain't gonna loop no more, no more! */
46449992Sbostic 	toend();
4651294Sbill }
4661294Sbill 
46749992Sbostic static void
4681294Sbill preread()
4691294Sbill {
47049992Sbostic     whyles->w_end = -1;
47149992Sbostic     if (setintr)
47250028Sbostic 	(void) sigsetmask(sigblock((sigset_t) 0) & ~sigmask(SIGINT));
4731294Sbill 
47450024Schristos     search(T_BREAK, 0, NULL);		/* read the expression in */
47549992Sbostic     if (setintr)
47649992Sbostic 	(void) sigblock(sigmask(SIGINT));
47750023Sbostic     whyles->w_end = fseekp;
4781294Sbill }
4791294Sbill 
48049992Sbostic void
48150439Schristos /*ARGSUSED*/
48250439Schristos doend(v, t)
48350439Schristos     Char **v;
48450439Schristos     struct command *t;
4851294Sbill {
48649992Sbostic     if (!whyles)
48749992Sbostic 	stderror(ERR_NAME | ERR_NOTWHILE);
48850023Sbostic     whyles->w_end = fseekp;
48949992Sbostic     doagain();
4901294Sbill }
4911294Sbill 
49249992Sbostic void
49350439Schristos /*ARGSUSED*/
49450439Schristos docontin(v, t)
49550439Schristos     Char **v;
49650439Schristos     struct command *t;
4971294Sbill {
49849992Sbostic     if (!whyles)
49949992Sbostic 	stderror(ERR_NAME | ERR_NOTWHILE);
50049992Sbostic     doagain();
5011294Sbill }
5021294Sbill 
50349992Sbostic static void
5041294Sbill doagain()
5051294Sbill {
50649992Sbostic     /* Repeating a while is simple */
50749992Sbostic     if (whyles->w_fename == 0) {
5081294Sbill 	bseek(whyles->w_start);
50949992Sbostic 	return;
51049992Sbostic     }
51149992Sbostic     /*
51249992Sbostic      * The foreach variable list actually has a spurious word ")" at the end of
51349992Sbostic      * the w_fe list.  Thus we are at the of the list if one word beyond this
51449992Sbostic      * is 0.
51549992Sbostic      */
51649992Sbostic     if (!whyles->w_fe[1]) {
51750439Schristos 	dobreak(NULL, NULL);
51849992Sbostic 	return;
51949992Sbostic     }
52049992Sbostic     set(whyles->w_fename, Strsave(*whyles->w_fe++));
52149992Sbostic     bseek(whyles->w_start);
5221294Sbill }
5231294Sbill 
52449992Sbostic void
5251294Sbill dorepeat(v, kp)
52649992Sbostic     Char  **v;
52749992Sbostic     struct command *kp;
5281294Sbill {
52949992Sbostic     register int i;
53050028Sbostic     register sigset_t omask = 0;
5311294Sbill 
53249992Sbostic     i = getn(v[1]);
53349992Sbostic     if (setintr)
53449992Sbostic 	omask = sigblock(sigmask(SIGINT)) & ~sigmask(SIGINT);
53549992Sbostic     lshift(v, 2);
53649992Sbostic     while (i > 0) {
5371294Sbill 	if (setintr)
53849992Sbostic 	    (void) sigsetmask(omask);
53949992Sbostic 	reexecute(kp);
54049992Sbostic 	--i;
54149992Sbostic     }
54249992Sbostic     donefds();
54349992Sbostic     if (setintr)
54449992Sbostic 	(void) sigsetmask(omask);
5451294Sbill }
5461294Sbill 
54749992Sbostic void
54850439Schristos /*ARGSUSED*/
54950439Schristos doswbrk(v, t)
55050439Schristos     Char **v;
55150439Schristos     struct command *t;
5521294Sbill {
55350024Schristos     search(T_BRKSW, 0, NULL);
5541294Sbill }
5551294Sbill 
55649992Sbostic int
5571294Sbill srchx(cp)
55849992Sbostic     register Char *cp;
5591294Sbill {
56049992Sbostic     register struct srch *sp, *sp1, *sp2;
56149992Sbostic     register i;
5621294Sbill 
56349992Sbostic     /*
56449992Sbostic      * Binary search Sp1 is the beginning of the current search range. Sp2 is
56549992Sbostic      * one past the end.
56649992Sbostic      */
56749992Sbostic     for (sp1 = srchn, sp2 = srchn + nsrchn; sp1 < sp2;) {
56849992Sbostic 	sp = sp1 + ((sp2 - sp1) >> 1);
56949992Sbostic 	if ((i = *cp - *sp->s_name) == 0 &&
57049992Sbostic 	    (i = Strcmp(cp, str2short(sp->s_name))) == 0)
57149992Sbostic 	    return sp->s_value;
57249992Sbostic 	if (i < 0)
57349992Sbostic 	    sp2 = sp;
57449992Sbostic 	else
57549992Sbostic 	    sp1 = sp + 1;
57649992Sbostic     }
57749992Sbostic     return (-1);
5781294Sbill }
5791294Sbill 
58049992Sbostic static Char Stype;
58149992Sbostic static Char *Sgoal;
5821294Sbill 
5831294Sbill /*VARARGS2*/
58449992Sbostic void
5851294Sbill search(type, level, goal)
58649992Sbostic     int     type;
58749992Sbostic     register int level;
58849992Sbostic     Char   *goal;
5891294Sbill {
59049992Sbostic     Char    wordbuf[BUFSIZ];
59149992Sbostic     register Char *aword = wordbuf;
59249992Sbostic     register Char *cp;
5931294Sbill 
59449992Sbostic     Stype = type;
59549992Sbostic     Sgoal = goal;
59649992Sbostic     if (type == T_GOTO)
59749992Sbostic 	bseek((off_t) 0);
59849992Sbostic     do {
59949992Sbostic 	if (intty && fseekp == feobp)
60050439Schristos 	    (void) fprintf(cshout, "? "), (void) fflush(cshout);
60149992Sbostic 	aword[0] = 0;
60249992Sbostic 	(void) getword(aword);
60349992Sbostic 	switch (srchx(aword)) {
6041294Sbill 
60549992Sbostic 	case T_ELSE:
60649992Sbostic 	    if (level == 0 && type == T_IF)
60749992Sbostic 		return;
60849992Sbostic 	    break;
6091294Sbill 
61049992Sbostic 	case T_IF:
61149992Sbostic 	    while (getword(aword))
61249992Sbostic 		continue;
61349992Sbostic 	    if ((type == T_IF || type == T_ELSE) &&
61449992Sbostic 		eq(aword, STRthen))
61549992Sbostic 		level++;
61649992Sbostic 	    break;
6171294Sbill 
61849992Sbostic 	case T_ENDIF:
61949992Sbostic 	    if (type == T_IF || type == T_ELSE)
62049992Sbostic 		level--;
62149992Sbostic 	    break;
6221294Sbill 
62349992Sbostic 	case T_FOREACH:
62449992Sbostic 	case T_WHILE:
62549992Sbostic 	    if (type == T_BREAK)
62649992Sbostic 		level++;
62749992Sbostic 	    break;
6281294Sbill 
62949992Sbostic 	case T_END:
63049992Sbostic 	    if (type == T_BREAK)
63149992Sbostic 		level--;
63249992Sbostic 	    break;
6331294Sbill 
63449992Sbostic 	case T_SWITCH:
63549992Sbostic 	    if (type == T_SWITCH || type == T_BRKSW)
63649992Sbostic 		level++;
63749992Sbostic 	    break;
6381294Sbill 
63949992Sbostic 	case T_ENDSW:
64049992Sbostic 	    if (type == T_SWITCH || type == T_BRKSW)
64149992Sbostic 		level--;
64249992Sbostic 	    break;
6431294Sbill 
64449992Sbostic 	case T_LABEL:
64549992Sbostic 	    if (type == T_GOTO && getword(aword) && eq(aword, goal))
64649992Sbostic 		level = -1;
64749992Sbostic 	    break;
6481294Sbill 
64949992Sbostic 	default:
65049992Sbostic 	    if (type != T_GOTO && (type != T_SWITCH || level != 0))
65149992Sbostic 		break;
65249992Sbostic 	    if (lastchr(aword) != ':')
65349992Sbostic 		break;
65449992Sbostic 	    aword[Strlen(aword) - 1] = 0;
65549992Sbostic 	    if (type == T_GOTO && eq(aword, goal) ||
65649992Sbostic 		type == T_SWITCH && eq(aword, STRdefault))
65749992Sbostic 		level = -1;
65849992Sbostic 	    break;
6591294Sbill 
66049992Sbostic 	case T_CASE:
66149992Sbostic 	    if (type != T_SWITCH || level != 0)
66249992Sbostic 		break;
66349992Sbostic 	    (void) getword(aword);
66449992Sbostic 	    if (lastchr(aword) == ':')
66549992Sbostic 		aword[Strlen(aword) - 1] = 0;
66649992Sbostic 	    cp = strip(Dfix1(aword));
66749992Sbostic 	    if (Gmatch(goal, cp))
66849992Sbostic 		level = -1;
66949992Sbostic 	    xfree((ptr_t) cp);
67049992Sbostic 	    break;
6711294Sbill 
67249992Sbostic 	case T_DEFAULT:
67349992Sbostic 	    if (type == T_SWITCH && level == 0)
67449992Sbostic 		level = -1;
67549992Sbostic 	    break;
67649992Sbostic 	}
67749992Sbostic 	(void) getword(NULL);
67849992Sbostic     } while (level >= 0);
6791294Sbill }
6801294Sbill 
68149992Sbostic static int
6821294Sbill getword(wp)
68349992Sbostic     register Char *wp;
6841294Sbill {
68549992Sbostic     register int found = 0;
68649992Sbostic     register int c, d;
68749992Sbostic     int     kwd = 0;
68849992Sbostic     Char   *owp = wp;
6891294Sbill 
69049992Sbostic     c = readc(1);
69149992Sbostic     d = 0;
69249992Sbostic     do {
69349992Sbostic 	while (c == ' ' || c == '\t')
69449992Sbostic 	    c = readc(1);
69549992Sbostic 	if (c == '#')
69649992Sbostic 	    do
69749992Sbostic 		c = readc(1);
69849992Sbostic 	    while (c >= 0 && c != '\n');
69949992Sbostic 	if (c < 0)
70049992Sbostic 	    goto past;
70149992Sbostic 	if (c == '\n') {
70249992Sbostic 	    if (wp)
70349992Sbostic 		break;
70449992Sbostic 	    return (0);
70549992Sbostic 	}
70649992Sbostic 	unreadc(c);
70749992Sbostic 	found = 1;
7081294Sbill 	do {
70949992Sbostic 	    c = readc(1);
71049992Sbostic 	    if (c == '\\' && (c = readc(1)) == '\n')
71149992Sbostic 		c = ' ';
71249992Sbostic 	    if (c == '\'' || c == '"')
71349992Sbostic 		if (d == 0)
71449992Sbostic 		    d = c;
71549992Sbostic 		else if (d == c)
71649992Sbostic 		    d = 0;
71749992Sbostic 	    if (c < 0)
71849992Sbostic 		goto past;
71949992Sbostic 	    if (wp) {
72049992Sbostic 		*wp++ = c;
72149992Sbostic 		*wp = 0;	/* end the string b4 test */
72249992Sbostic 	    }
72349992Sbostic 	} while ((d || !(kwd = keyword(owp)) && c != ' '
72449992Sbostic 		  && c != '\t') && c != '\n');
72549992Sbostic     } while (wp == 0);
72649992Sbostic 
72749992Sbostic     /*
72849992Sbostic      * if we have read a keyword ( "if", "switch" or "while" ) then we do not
72949992Sbostic      * need to unreadc the look-ahead char
73049992Sbostic      */
73149992Sbostic     if (!kwd) {
7321294Sbill 	unreadc(c);
7331294Sbill 	if (found)
73449992Sbostic 	    *--wp = 0;
73549992Sbostic     }
7361294Sbill 
73749992Sbostic     return (found);
73849992Sbostic 
7391294Sbill past:
74049992Sbostic     switch (Stype) {
7411294Sbill 
74249992Sbostic     case T_IF:
74349992Sbostic 	stderror(ERR_NAME | ERR_NOTFOUND, "then/endif");
7441294Sbill 
74549992Sbostic     case T_ELSE:
74649992Sbostic 	stderror(ERR_NAME | ERR_NOTFOUND, "endif");
7471294Sbill 
74849992Sbostic     case T_BRKSW:
74949992Sbostic     case T_SWITCH:
75049992Sbostic 	stderror(ERR_NAME | ERR_NOTFOUND, "endsw");
7511294Sbill 
75249992Sbostic     case T_BREAK:
75349992Sbostic 	stderror(ERR_NAME | ERR_NOTFOUND, "end");
7541294Sbill 
75549992Sbostic     case T_GOTO:
75649992Sbostic 	setname(short2str(Sgoal));
75749992Sbostic 	stderror(ERR_NAME | ERR_NOTFOUND, "label");
75849992Sbostic     }
75949992Sbostic     /* NOTREACHED */
76049992Sbostic     return (0);
7611294Sbill }
7621294Sbill 
76349992Sbostic /*
76449992Sbostic  * keyword(wp) determines if wp is one of the built-n functions if,
76549992Sbostic  * switch or while. It seems that when an if statement looks like
76649992Sbostic  * "if(" then getword above sucks in the '(' and so the search routine
76749992Sbostic  * never finds what it is scanning for. Rather than rewrite doword, I hack
76849992Sbostic  * in a test to see if the string forms a keyword. Then doword stops
76949992Sbostic  * and returns the word "if" -strike
77049992Sbostic  */
77149992Sbostic 
77249992Sbostic static int
77349992Sbostic keyword(wp)
77449992Sbostic     Char   *wp;
7751294Sbill {
77649992Sbostic     static Char STRif[] = {'i', 'f', '\0'};
77749992Sbostic     static Char STRwhile[] = {'w', 'h', 'i', 'l', 'e', '\0'};
77849992Sbostic     static Char STRswitch[] = {'s', 'w', 'i', 't', 'c', 'h', '\0'};
7791294Sbill 
78049992Sbostic     if (!wp)
78149992Sbostic 	return (0);
78249992Sbostic 
78349992Sbostic     if ((Strcmp(wp, STRif) == 0) || (Strcmp(wp, STRwhile) == 0)
78449992Sbostic 	|| (Strcmp(wp, STRswitch) == 0))
78549992Sbostic 	return (1);
78649992Sbostic 
78749992Sbostic     return (0);
7881294Sbill }
7891294Sbill 
79049992Sbostic static void
79149992Sbostic toend()
79249992Sbostic {
79349992Sbostic     if (whyles->w_end == 0) {
79449992Sbostic 	search(T_BREAK, 0, NULL);
79550023Sbostic 	whyles->w_end = fseekp - 1;
79649992Sbostic     }
79749992Sbostic     else
79849992Sbostic 	bseek(whyles->w_end);
79949992Sbostic     wfree();
80049992Sbostic }
80149992Sbostic 
80249992Sbostic void
8031294Sbill wfree()
8041294Sbill {
80550023Sbostic     long    o = fseekp;
8061294Sbill 
80749992Sbostic     while (whyles) {
80849992Sbostic 	register struct whyle *wp = whyles;
80949992Sbostic 	register struct whyle *nwp = wp->w_next;
8101294Sbill 
81149992Sbostic 	if (o >= wp->w_start && (wp->w_end == 0 || o < wp->w_end))
81249992Sbostic 	    break;
81349992Sbostic 	if (wp->w_fe0)
81449992Sbostic 	    blkfree(wp->w_fe0);
81549992Sbostic 	if (wp->w_fename)
81649992Sbostic 	    xfree((ptr_t) wp->w_fename);
81749992Sbostic 	xfree((ptr_t) wp);
81849992Sbostic 	whyles = nwp;
81949992Sbostic     }
8201294Sbill }
8211294Sbill 
82249992Sbostic void
82350439Schristos /*ARGSUSED*/
82450439Schristos doecho(v, t)
82550439Schristos     Char **v;
82650439Schristos     struct command *t;
8271294Sbill {
82849992Sbostic     xecho(' ', v);
8291294Sbill }
8301294Sbill 
83149992Sbostic void
83250439Schristos /*ARGSUSED*/
83350439Schristos doglob(v, t)
83450439Schristos     Char **v;
83550439Schristos     struct command *t;
8361294Sbill {
83749992Sbostic     xecho(0, v);
83850439Schristos     (void) fflush(cshout);
8391294Sbill }
8401294Sbill 
84149992Sbostic static void
84249992Sbostic xecho(sep, v)
84350024Schristos     int    sep;
84449992Sbostic     register Char **v;
8451294Sbill {
84649992Sbostic     register Char *cp;
84749992Sbostic     int     nonl = 0;
8481294Sbill 
84949992Sbostic     if (setintr)
85050028Sbostic 	(void) sigsetmask(sigblock((sigset_t) 0) & ~sigmask(SIGINT));
85149992Sbostic     v++;
85249992Sbostic     if (*v == 0)
85349992Sbostic 	return;
85449992Sbostic     gflag = 0, tglob(v);
85549992Sbostic     if (gflag) {
85649992Sbostic 	v = globall(v);
85749992Sbostic 	if (v == 0)
85849992Sbostic 	    stderror(ERR_NAME | ERR_NOMATCH);
85949992Sbostic     }
86049992Sbostic     else {
86149992Sbostic 	v = gargv = saveblk(v);
86249992Sbostic 	trim(v);
86349992Sbostic     }
86449992Sbostic     if (sep == ' ' && *v && eq(*v, STRmn))
86549992Sbostic 	nonl++, v++;
86649992Sbostic     while (cp = *v++) {
86749992Sbostic 	register int c;
8681294Sbill 
86949992Sbostic 	while (c = *cp++)
87050439Schristos 	    (void) fputc(c | QUOTE, cshout);
87149992Sbostic 
87249992Sbostic 	if (*v)
87350439Schristos 	    (void) fputc(sep | QUOTE, cshout);
87449992Sbostic     }
87549992Sbostic     if (sep && nonl == 0)
87650439Schristos 	(void) fputc('\n', cshout);
87749992Sbostic     else
87850439Schristos 	(void) fflush(cshout);
87949992Sbostic     if (setintr)
88049992Sbostic 	(void) sigblock(sigmask(SIGINT));
88149992Sbostic     if (gargv)
88249992Sbostic 	blkfree(gargv), gargv = 0;
8831294Sbill }
8841294Sbill 
88549992Sbostic void
88650439Schristos /*ARGSUSED*/
88750439Schristos dosetenv(v, t)
88850439Schristos     Char **v;
88950439Schristos     struct command *t;
8901294Sbill {
89149992Sbostic     Char   *vp, *lp;
8921294Sbill 
89349992Sbostic     v++;
89449992Sbostic     if ((vp = *v++) == 0) {
89549992Sbostic 	register Char **ep;
89621753Sedward 
89749992Sbostic 	if (setintr)
89850028Sbostic 	    (void) sigsetmask(sigblock((sigset_t) 0) & ~sigmask(SIGINT));
89949992Sbostic 	for (ep = STR_environ; *ep; ep++)
90050439Schristos 	    (void) fprintf(cshout, "%s\n", short2str(*ep));
90149992Sbostic 	return;
90249992Sbostic     }
90349992Sbostic     if ((lp = *v++) == 0)
90449992Sbostic 	lp = STRNULL;
90549992Sbostic     Setenv(vp, lp = globone(lp, G_ERROR));
90649992Sbostic     if (eq(vp, STRPATH)) {
90749992Sbostic 	importpath(lp);
90850439Schristos 	dohash(NULL, NULL);
90949992Sbostic     }
91049992Sbostic     else if (eq(vp, STRLANG) || eq(vp, STRLC_CTYPE)) {
91149992Sbostic #ifdef NLS
91249992Sbostic 	int     k;
91349992Sbostic 
91449992Sbostic 	(void) setlocale(LC_ALL, "");
91549992Sbostic 	for (k = 0200; k <= 0377 && !Isprint(k); k++);
91649992Sbostic 	AsciiOnly = k > 0377;
91749992Sbostic #else
91849992Sbostic 	AsciiOnly = 0;
91949992Sbostic #endif				/* NLS */
92049992Sbostic     }
92149992Sbostic     xfree((ptr_t) lp);
9221294Sbill }
9231294Sbill 
92449992Sbostic void
92550439Schristos /*ARGSUSED*/
92650439Schristos dounsetenv(v, t)
92750439Schristos     Char **v;
92850439Schristos     struct command *t;
9291294Sbill {
93049992Sbostic     Char  **ep, *p, *n;
93149992Sbostic     int     i, maxi;
93249992Sbostic     static Char *name = NULL;
9331294Sbill 
93449992Sbostic     if (name)
93549992Sbostic 	xfree((ptr_t) name);
93649992Sbostic     /*
93749992Sbostic      * Find the longest environment variable
93849992Sbostic      */
93949992Sbostic     for (maxi = 0, ep = STR_environ; *ep; ep++) {
94049992Sbostic 	for (i = 0, p = *ep; *p && *p != '='; p++, i++);
94149992Sbostic 	if (i > maxi)
94249992Sbostic 	    maxi = i;
94349992Sbostic     }
94449992Sbostic 
94549992Sbostic     name = (Char *) xmalloc((size_t) (maxi + 1) * sizeof(Char));
94649992Sbostic 
94750160Schristos     while (++v && *v)
94850160Schristos 	for (maxi = 1; maxi;)
94950160Schristos 	    for (maxi = 0, ep = STR_environ; *ep; ep++) {
95050160Schristos 		for (n = name, p = *ep; *p && *p != '='; *n++ = *p++);
95150160Schristos 		*n = '\0';
95250160Schristos 		if (!Gmatch(name, *v))
95350160Schristos 		    continue;
95450160Schristos 		maxi = 1;
95550160Schristos 		if (eq(name, STRLANG) || eq(name, STRLC_CTYPE)) {
95649992Sbostic #ifdef NLS
95750160Schristos 		    int     k;
95849992Sbostic 
95950160Schristos 		    (void) setlocale(LC_ALL, "");
96050160Schristos 		    for (k = 0200; k <= 0377 && !Isprint(k); k++);
96150160Schristos 		    AsciiOnly = k > 0377;
96249992Sbostic #else
96350160Schristos 		    AsciiOnly = getenv("LANG") == NULL &&
96450160Schristos 			getenv("LC_CTYPE") == NULL;
96549992Sbostic #endif				/* NLS */
96650160Schristos 		}
96750160Schristos 		/*
96850160Schristos 		 * Delete name, and start again cause the environment changes
96950160Schristos 		 */
97050160Schristos 		Unsetenv(name);
97150160Schristos 		break;
97249992Sbostic 	    }
97349992Sbostic     xfree((ptr_t) name), name = NULL;
9741294Sbill }
9751294Sbill 
97649992Sbostic void
97749992Sbostic Setenv(name, val)
97849992Sbostic     Char   *name, *val;
9791294Sbill {
98049992Sbostic     register Char **ep = STR_environ;
98149992Sbostic     register Char *cp, *dp;
98249992Sbostic     Char   *blk[2];
98349992Sbostic     Char  **oep = ep;
9841294Sbill 
98549992Sbostic 
98649992Sbostic     for (; *ep; ep++) {
98749992Sbostic 	for (cp = name, dp = *ep; *cp && *cp == *dp; cp++, dp++)
98849992Sbostic 	    continue;
98949992Sbostic 	if (*cp != 0 || *dp != '=')
99049992Sbostic 	    continue;
99149992Sbostic 	cp = Strspl(STRequal, val);
99249992Sbostic 	xfree((ptr_t) * ep);
99349992Sbostic 	*ep = strip(Strspl(name, cp));
99449992Sbostic 	xfree((ptr_t) cp);
99549992Sbostic 	blkfree((Char **) environ);
99649992Sbostic 	environ = short2blk(STR_environ);
99749992Sbostic 	return;
99849992Sbostic     }
99949992Sbostic     cp = Strspl(name, STRequal);
100049992Sbostic     blk[0] = strip(Strspl(cp, val));
100149992Sbostic     xfree((ptr_t) cp);
100249992Sbostic     blk[1] = 0;
100349992Sbostic     STR_environ = blkspl(STR_environ, blk);
100449992Sbostic     blkfree((Char **) environ);
100549992Sbostic     environ = short2blk(STR_environ);
100649992Sbostic     xfree((ptr_t) oep);
10071294Sbill }
10081294Sbill 
100949992Sbostic static void
101049992Sbostic Unsetenv(name)
101149992Sbostic     Char   *name;
10121294Sbill {
101349992Sbostic     register Char **ep = STR_environ;
101449992Sbostic     register Char *cp, *dp;
101549992Sbostic     Char  **oep = ep;
10161294Sbill 
101749992Sbostic     for (; *ep; ep++) {
101849992Sbostic 	for (cp = name, dp = *ep; *cp && *cp == *dp; cp++, dp++)
101949992Sbostic 	    continue;
102049992Sbostic 	if (*cp != 0 || *dp != '=')
102149992Sbostic 	    continue;
102249992Sbostic 	cp = *ep;
102349992Sbostic 	*ep = 0;
102449992Sbostic 	STR_environ = blkspl(STR_environ, ep + 1);
102549992Sbostic 	environ = short2blk(STR_environ);
102649992Sbostic 	*ep = cp;
102749992Sbostic 	xfree((ptr_t) cp);
102849992Sbostic 	xfree((ptr_t) oep);
102949992Sbostic 	return;
103049992Sbostic     }
10311294Sbill }
10321294Sbill 
103349992Sbostic void
103450439Schristos /*ARGSUSED*/
103550439Schristos doumask(v, t)
103650439Schristos     Char **v;
103750439Schristos     struct command *t;
10381294Sbill {
103949992Sbostic     register Char *cp = v[1];
104049992Sbostic     register int i;
10411294Sbill 
104249992Sbostic     if (cp == 0) {
104349992Sbostic 	i = umask(0);
104417519Sedward 	(void) umask(i);
104550439Schristos 	(void) fprintf(cshout, "%o\n", i);
104649992Sbostic 	return;
104749992Sbostic     }
104849992Sbostic     i = 0;
104949992Sbostic     while (Isdigit(*cp) && *cp != '8' && *cp != '9')
105049992Sbostic 	i = i * 8 + *cp++ - '0';
105149992Sbostic     if (*cp || i < 0 || i > 0777)
105249992Sbostic 	stderror(ERR_NAME | ERR_MASK);
105349992Sbostic     (void) umask(i);
10541294Sbill }
10551294Sbill 
105649992Sbostic typedef int RLIM_TYPE;
10571294Sbill 
105849992Sbostic static struct limits {
105949992Sbostic     int     limconst;
106049992Sbostic     char   *limname;
106149992Sbostic     int     limdiv;
106249992Sbostic     char   *limscale;
106349992Sbostic }       limits[] = {
106449992Sbostic     RLIMIT_CPU, 	"cputime",	1,	"seconds",
106549992Sbostic     RLIMIT_FSIZE,	"filesize",	1024,	"kbytes",
106649992Sbostic     RLIMIT_DATA,	"datasize",	1024,	"kbytes",
106749992Sbostic     RLIMIT_STACK,	"stacksize",	1024,	"kbytes",
106849992Sbostic     RLIMIT_CORE,	"coredumpsize", 1024,	"kbytes",
106949992Sbostic     RLIMIT_RSS,		"memoryuse", 	1024,	"kbytes",
107050024Schristos     RLIMIT_MEMLOCK,	"memorylocked",	1024,	"kbytes",
107150024Schristos     RLIMIT_NPROC,	"maxproc",	1,	"",
107250024Schristos     RLIMIT_OFILE,	"openfiles",	1,	"",
107350024Schristos     -1, 		NULL, 		0,	NULL
10741294Sbill };
10751294Sbill 
107649992Sbostic static struct limits *findlim();
107749992Sbostic static RLIM_TYPE getval();
107849992Sbostic static void limtail();
107949992Sbostic static void plim();
108049992Sbostic static int setlim();
108149992Sbostic 
108249992Sbostic static struct limits *
10831294Sbill findlim(cp)
108449992Sbostic     Char   *cp;
10851294Sbill {
108649992Sbostic     register struct limits *lp, *res;
10871294Sbill 
108849992Sbostic     res = (struct limits *) NULL;
108949992Sbostic     for (lp = limits; lp->limconst >= 0; lp++)
109049992Sbostic 	if (prefix(cp, str2short(lp->limname))) {
109149992Sbostic 	    if (res)
109249992Sbostic 		stderror(ERR_NAME | ERR_AMBIG);
109349992Sbostic 	    res = lp;
109449992Sbostic 	}
109549992Sbostic     if (res)
109649992Sbostic 	return (res);
109749992Sbostic     stderror(ERR_NAME | ERR_LIMIT);
109849992Sbostic     /* NOTREACHED */
109949992Sbostic     return (0);
11001294Sbill }
11011294Sbill 
110249992Sbostic void
110350439Schristos /*ARGSUSED*/
110450439Schristos dolimit(v, t)
110550439Schristos     Char **v;
110650439Schristos     struct command *t;
11071294Sbill {
110849992Sbostic     register struct limits *lp;
110949992Sbostic     register RLIM_TYPE limit;
111049992Sbostic     char    hard = 0;
11111294Sbill 
111249992Sbostic     v++;
111349992Sbostic     if (*v && eq(*v, STRmh)) {
111449992Sbostic 	hard = 1;
11151294Sbill 	v++;
111649992Sbostic     }
111749992Sbostic     if (*v == 0) {
111849992Sbostic 	for (lp = limits; lp->limconst >= 0; lp++)
111949992Sbostic 	    plim(lp, hard);
112049992Sbostic 	return;
112149992Sbostic     }
112249992Sbostic     lp = findlim(v[0]);
112349992Sbostic     if (v[1] == 0) {
112449992Sbostic 	plim(lp, hard);
112549992Sbostic 	return;
112649992Sbostic     }
112749992Sbostic     limit = getval(lp, v + 1);
112849992Sbostic     if (setlim(lp, hard, limit) < 0)
112949992Sbostic 	stderror(ERR_SILENT);
11301294Sbill }
11311294Sbill 
113249992Sbostic static  RLIM_TYPE
11331294Sbill getval(lp, v)
113449992Sbostic     register struct limits *lp;
113549992Sbostic     Char  **v;
11361294Sbill {
113749992Sbostic     register float f;
113849992Sbostic     double  atof();
113949992Sbostic     Char   *cp = *v++;
11401294Sbill 
114149992Sbostic     f = atof(short2str(cp));
114249992Sbostic 
114349992Sbostic     while (Isdigit(*cp) || *cp == '.' || *cp == 'e' || *cp == 'E')
114449992Sbostic 	cp++;
114549992Sbostic     if (*cp == 0) {
114649992Sbostic 	if (*v == 0)
114749992Sbostic 	    return ((RLIM_TYPE) ((f + 0.5) * lp->limdiv));
114849992Sbostic 	cp = *v;
114949992Sbostic     }
115049992Sbostic     switch (*cp) {
115149992Sbostic     case ':':
115249992Sbostic 	if (lp->limconst != RLIMIT_CPU)
115349992Sbostic 	    goto badscal;
115449992Sbostic 	return ((RLIM_TYPE) (f * 60.0 + atof(short2str(cp + 1))));
115549992Sbostic     case 'h':
115649992Sbostic 	if (lp->limconst != RLIMIT_CPU)
115749992Sbostic 	    goto badscal;
115849992Sbostic 	limtail(cp, "hours");
115949992Sbostic 	f *= 3600.0;
116049992Sbostic 	break;
116149992Sbostic     case 'm':
116249992Sbostic 	if (lp->limconst == RLIMIT_CPU) {
116349992Sbostic 	    limtail(cp, "minutes");
116449992Sbostic 	    f *= 60.0;
116549992Sbostic 	    break;
11661294Sbill 	}
116749992Sbostic 	*cp = 'm';
116849992Sbostic 	limtail(cp, "megabytes");
116949992Sbostic 	f *= 1024.0 * 1024.0;
117049992Sbostic 	break;
117149992Sbostic     case 's':
117249992Sbostic 	if (lp->limconst != RLIMIT_CPU)
117349992Sbostic 	    goto badscal;
117449992Sbostic 	limtail(cp, "seconds");
117549992Sbostic 	break;
117649992Sbostic     case 'M':
117749992Sbostic 	if (lp->limconst == RLIMIT_CPU)
117849992Sbostic 	    goto badscal;
117949992Sbostic 	*cp = 'm';
118049992Sbostic 	limtail(cp, "megabytes");
118149992Sbostic 	f *= 1024.0 * 1024.0;
118249992Sbostic 	break;
118349992Sbostic     case 'k':
118449992Sbostic 	if (lp->limconst == RLIMIT_CPU)
118549992Sbostic 	    goto badscal;
118649992Sbostic 	limtail(cp, "kbytes");
118749992Sbostic 	f *= 1024.0;
118849992Sbostic 	break;
118949992Sbostic     case 'u':
119049992Sbostic 	limtail(cp, "unlimited");
119149992Sbostic 	return (RLIM_INFINITY);
119249992Sbostic     default:
11931294Sbill badscal:
119449992Sbostic 	stderror(ERR_NAME | ERR_SCALEF);
119549992Sbostic     }
119649992Sbostic     return ((RLIM_TYPE) (f + 0.5));
11971294Sbill }
11981294Sbill 
119949992Sbostic static void
120049992Sbostic limtail(cp, str)
120149992Sbostic     Char   *cp;
120249992Sbostic     char   *str;
12031294Sbill {
120449992Sbostic     while (*cp && *cp == *str)
120549992Sbostic 	cp++, str++;
120649992Sbostic     if (*cp)
120749992Sbostic 	stderror(ERR_BADSCALE, str);
12081294Sbill }
12091294Sbill 
121049992Sbostic 
121149992Sbostic /*ARGSUSED*/
121249992Sbostic static void
121318539Sedward plim(lp, hard)
121449992Sbostic     register struct limits *lp;
121549992Sbostic     Char    hard;
12161294Sbill {
121749992Sbostic     struct rlimit rlim;
121849992Sbostic     RLIM_TYPE limit;
12191294Sbill 
122050439Schristos     (void) fprintf(cshout, "%s \t", lp->limname);
122149992Sbostic 
122249992Sbostic     (void) getrlimit(lp->limconst, &rlim);
122349992Sbostic     limit = hard ? rlim.rlim_max : rlim.rlim_cur;
122449992Sbostic 
122549992Sbostic     if (limit == RLIM_INFINITY)
122650439Schristos 	(void) fprintf(cshout, "unlimited");
122749992Sbostic     else if (lp->limconst == RLIMIT_CPU)
122849992Sbostic 	psecs((long) limit);
122949992Sbostic     else
123050439Schristos 	(void) fprintf(cshout, "%ld %s", (long) (limit / lp->limdiv),
123150439Schristos 		       lp->limscale);
123250439Schristos     (void) fputc('\n', cshout);
12331294Sbill }
12341294Sbill 
123549992Sbostic void
123650439Schristos /*ARGSUSED*/
123750439Schristos dounlimit(v, t)
123850439Schristos     Char **v;
123950439Schristos     struct command *t;
12401294Sbill {
124149992Sbostic     register struct limits *lp;
124249992Sbostic     int     lerr = 0;
124349992Sbostic     Char    hard = 0;
12441294Sbill 
124549992Sbostic     v++;
124649992Sbostic     if (*v && eq(*v, STRmh)) {
124749992Sbostic 	hard = 1;
12481294Sbill 	v++;
124949992Sbostic     }
125049992Sbostic     if (*v == 0) {
125149992Sbostic 	for (lp = limits; lp->limconst >= 0; lp++)
125249992Sbostic 	    if (setlim(lp, hard, (RLIM_TYPE) RLIM_INFINITY) < 0)
125349992Sbostic 		lerr++;
125449992Sbostic 	if (lerr)
125549992Sbostic 	    stderror(ERR_SILENT);
125649992Sbostic 	return;
125749992Sbostic     }
125849992Sbostic     while (*v) {
125949992Sbostic 	lp = findlim(*v++);
126049992Sbostic 	if (setlim(lp, hard, (RLIM_TYPE) RLIM_INFINITY) < 0)
126149992Sbostic 	    stderror(ERR_SILENT);
126249992Sbostic     }
12631294Sbill }
12641294Sbill 
126549992Sbostic static int
126618539Sedward setlim(lp, hard, limit)
126749992Sbostic     register struct limits *lp;
126849992Sbostic     Char    hard;
126949992Sbostic     RLIM_TYPE limit;
12701294Sbill {
127149992Sbostic     struct rlimit rlim;
12721294Sbill 
127349992Sbostic     (void) getrlimit(lp->limconst, &rlim);
127449992Sbostic 
127549992Sbostic     if (hard)
127649992Sbostic 	rlim.rlim_max = limit;
127749992Sbostic     else if (limit == RLIM_INFINITY && geteuid() != 0)
127849992Sbostic 	rlim.rlim_cur = rlim.rlim_max;
127949992Sbostic     else
128049992Sbostic 	rlim.rlim_cur = limit;
128149992Sbostic 
128249992Sbostic     if (setrlimit(lp->limconst, &rlim) < 0) {
128350439Schristos 	(void) fprintf(csherr, "%s: %s: Can't %s%s limit\n", bname, lp->limname,
128450439Schristos 		       limit == RLIM_INFINITY ? "remove" : "set",
128550439Schristos 		       hard ? " hard" : "");
128649992Sbostic 	return (-1);
128749992Sbostic     }
128849992Sbostic     return (0);
12891294Sbill }
12901294Sbill 
129149992Sbostic void
129250439Schristos /*ARGSUSED*/
129350439Schristos dosuspend(v, t)
129450439Schristos     Char **v;
129550439Schristos     struct command *t;
12961294Sbill {
129749992Sbostic     int     ctpgrp;
12981294Sbill 
129949992Sbostic     void    (*old) ();
130049992Sbostic 
130149992Sbostic     if (loginsh)
130249992Sbostic 	stderror(ERR_SUSPLOG);
130349992Sbostic     untty();
130449992Sbostic 
130549992Sbostic     old = signal(SIGTSTP, SIG_DFL);
130649992Sbostic     (void) kill(0, SIGTSTP);
130749992Sbostic     /* the shell stops here */
130849992Sbostic     (void) signal(SIGTSTP, old);
130949992Sbostic 
131049992Sbostic     if (tpgrp != -1) {
131149992Sbostic 	ctpgrp = tcgetpgrp(FSHTTY);
131250439Schristos 	while  (ctpgrp != opgrp) {
131349992Sbostic 	    old = signal(SIGTTIN, SIG_DFL);
131449992Sbostic 	    (void) kill(0, SIGTTIN);
131549992Sbostic 	    (void) signal(SIGTTIN, old);
13161294Sbill 	}
131749992Sbostic 	(void) setpgid(0, shpgrp);
131849992Sbostic 	(void) tcsetpgrp(FSHTTY, shpgrp);
131949992Sbostic     }
13201294Sbill }
13211294Sbill 
132249992Sbostic /* This is the dreaded EVAL built-in.
132349992Sbostic  *   If you don't fiddle with file descriptors, and reset didfds,
132449992Sbostic  *   this command will either ignore redirection inside or outside
132549992Sbostic  *   its aguments, e.g. eval "date >x"  vs.  eval "date" >x
132649992Sbostic  *   The stuff here seems to work, but I did it by trial and error rather
132749992Sbostic  *   than really knowing what was going on.  If tpgrp is zero, we are
132849992Sbostic  *   probably a background eval, e.g. "eval date &", and we want to
132949992Sbostic  *   make sure that any processes we start stay in our pgrp.
133049992Sbostic  *   This is also the case for "time eval date" -- stay in same pgrp.
133149992Sbostic  *   Otherwise, under stty tostop, processes will stop in the wrong
133249992Sbostic  *   pgrp, with no way for the shell to get them going again.  -IAN!
133349992Sbostic  */
133450439Schristos static Char **gv = NULL;
133549992Sbostic void
133650439Schristos /*ARGSUSED*/
133750439Schristos doeval(v, t)
133850439Schristos     Char **v;
133950439Schristos     struct command *t;
13401294Sbill {
134149992Sbostic     Char  **oevalvec;
134249992Sbostic     Char   *oevalp;
134349992Sbostic     int     odidfds;
134449992Sbostic     jmp_buf osetexit;
134549992Sbostic     int     my_reenter;
134650439Schristos     Char  **savegv = gv;
134749992Sbostic     int     saveIN;
134849992Sbostic     int     saveOUT;
134950439Schristos     int     saveERR;
135049992Sbostic     int     oSHIN;
135149992Sbostic     int     oSHOUT;
135250439Schristos     int     oSHERR;
13531294Sbill 
135449992Sbostic     oevalvec = evalvec;
135549992Sbostic     oevalp = evalp;
135649992Sbostic     odidfds = didfds;
135749992Sbostic     oSHIN = SHIN;
135849992Sbostic     oSHOUT = SHOUT;
135950439Schristos     oSHERR = SHERR;
136049992Sbostic 
136149992Sbostic     v++;
136249992Sbostic     if (*v == 0)
136349992Sbostic 	return;
136449992Sbostic     gflag = 0, tglob(v);
136549992Sbostic     if (gflag) {
136649992Sbostic 	gv = v = globall(v);
136749992Sbostic 	gargv = 0;
136849992Sbostic 	if (v == 0)
136949992Sbostic 	    stderror(ERR_NOMATCH);
137049992Sbostic 	v = copyblk(v);
137149992Sbostic     }
137249992Sbostic     else {
137350024Schristos 	gv = NULL;
137449992Sbostic 	v = copyblk(v);
137549992Sbostic 	trim(v);
137649992Sbostic     }
137749992Sbostic 
137849992Sbostic     saveIN = dcopy(SHIN, -1);
137949992Sbostic     saveOUT = dcopy(SHOUT, -1);
138050439Schristos     saveERR = dcopy(SHERR, -1);
138149992Sbostic 
138249992Sbostic     getexit(osetexit);
138349992Sbostic 
138449992Sbostic     if ((my_reenter = setexit()) == 0) {
138549992Sbostic 	evalvec = v;
138649992Sbostic 	evalp = 0;
138749992Sbostic 	SHIN = dcopy(0, -1);
138849992Sbostic 	SHOUT = dcopy(1, -1);
138950439Schristos 	SHERR = dcopy(2, -1);
139049992Sbostic 	didfds = 0;
139149992Sbostic 	process(0);
139249992Sbostic     }
139349992Sbostic 
139449992Sbostic     evalvec = oevalvec;
139549992Sbostic     evalp = oevalp;
139649992Sbostic     doneinp = 0;
139749992Sbostic     didfds = odidfds;
139849992Sbostic     (void) close(SHIN);
139949992Sbostic     (void) close(SHOUT);
140050439Schristos     (void) close(SHERR);
140149992Sbostic     SHIN = dmove(saveIN, oSHIN);
140249992Sbostic     SHOUT = dmove(saveOUT, oSHOUT);
140350439Schristos     SHERR = dmove(saveERR, oSHERR);
140449992Sbostic     if (gv)
140550439Schristos 	blkfree(gv), gv = NULL;
140649992Sbostic     resexit(osetexit);
140750439Schristos     gv = savegv;
140849992Sbostic     if (my_reenter)
140949992Sbostic 	stderror(ERR_SILENT);
14101294Sbill }
1411*50639Schristos 
1412*50639Schristos void
1413*50639Schristos /*ARGSUSED*/
1414*50639Schristos doprintf(v, t)
1415*50639Schristos     Char **v;
1416*50639Schristos     struct command *t;
1417*50639Schristos {
1418*50639Schristos     char **c;
1419*50639Schristos     extern int progprintf __P((int, char **));
1420*50639Schristos     int ret;
1421*50639Schristos 
1422*50639Schristos     ret = progprintf(blklen(v), c = short2blk(v));
1423*50639Schristos 
1424*50639Schristos     blkfree((Char **) c);
1425*50639Schristos     if (ret)
1426*50639Schristos 	stderror(ERR_SILENT);
1427*50639Schristos }
1428*50639Schristos 
1429