xref: /csrg-svn/bin/csh/func.c (revision 51589)
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*51589Schristos static char sccsid[] = "@(#)func.c	5.32 (Berkeley) 11/06/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));
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 *
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
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*/
10450439Schristos doonintr(v, t)
10550439Schristos     Char **v;
10650439Schristos     struct command *t;
1071294Sbill {
10849992Sbostic     register Char *cp;
10949992Sbostic     register Char *vv = v[1];
1101294Sbill 
11149992Sbostic     if (parintr == SIG_IGN)
11249992Sbostic 	return;
11349992Sbostic     if (setintr && intty)
11449992Sbostic 	stderror(ERR_NAME | ERR_TERMINAL);
11549992Sbostic     cp = gointr;
11649992Sbostic     gointr = 0;
11749992Sbostic     xfree((ptr_t) cp);
11849992Sbostic     if (vv == 0) {
11949992Sbostic 	if (setintr)
12049992Sbostic 	    (void) sigblock(sigmask(SIGINT));
12149992Sbostic 	else
12249992Sbostic 	    (void) signal(SIGINT, SIG_DFL);
12349992Sbostic 	gointr = 0;
12449992Sbostic     }
12549992Sbostic     else if (eq((vv = strip(vv)), STRminus)) {
12649992Sbostic 	(void) signal(SIGINT, SIG_IGN);
12749992Sbostic 	gointr = Strsave(STRminus);
12849992Sbostic     }
12949992Sbostic     else {
13049992Sbostic 	gointr = Strsave(vv);
13149992Sbostic 	(void) signal(SIGINT, pintr);
13249992Sbostic     }
1331294Sbill }
1341294Sbill 
13549992Sbostic void
13650439Schristos /*ARGSUSED*/
13750439Schristos donohup(v, t)
13850439Schristos     Char **v;
13950439Schristos     struct command *t;
1401294Sbill {
14149992Sbostic     if (intty)
14249992Sbostic 	stderror(ERR_NAME | ERR_TERMINAL);
14349992Sbostic     if (setintr == 0) {
14449992Sbostic 	(void) signal(SIGHUP, SIG_IGN);
14549992Sbostic     }
1461294Sbill }
1471294Sbill 
14849992Sbostic void
14950439Schristos /*ARGSUSED*/
15050439Schristos dozip(v, t)
15150439Schristos     Char **v;
15250439Schristos     struct command *t;
1531294Sbill {
15449992Sbostic     ;
1551294Sbill }
1561294Sbill 
15749992Sbostic void
1581294Sbill prvars()
1591294Sbill {
16049992Sbostic     plist(&shvhed);
1611294Sbill }
1621294Sbill 
16349992Sbostic void
16450439Schristos /*ARGSUSED*/
16550439Schristos doalias(v, t)
16650439Schristos     Char **v;
16750439Schristos     struct command *t;
1681294Sbill {
16949992Sbostic     register struct varent *vp;
17049992Sbostic     register Char *p;
1711294Sbill 
17249992Sbostic     v++;
17349992Sbostic     p = *v++;
17449992Sbostic     if (p == 0)
17549992Sbostic 	plist(&aliases);
17649992Sbostic     else if (*v == 0) {
17749992Sbostic 	vp = adrof1(strip(p), &aliases);
17850439Schristos 	if (vp) {
17950439Schristos 	    blkpr(cshout, vp->vec);
18050439Schristos 	    fputc('\n', cshout);
18150439Schristos 	}
18249992Sbostic     }
18349992Sbostic     else {
18449992Sbostic 	if (eq(p, STRalias) || eq(p, STRunalias)) {
185*51589Schristos 	    setname(vis_str(p));
18649992Sbostic 	    stderror(ERR_NAME | ERR_DANGER);
1871294Sbill 	}
18849992Sbostic 	set1(strip(p), saveblk(v), &aliases);
18949992Sbostic     }
1901294Sbill }
1911294Sbill 
19249992Sbostic void
19350439Schristos /*ARGSUSED*/
19450439Schristos unalias(v, t)
19550439Schristos     Char **v;
19650439Schristos     struct command *t;
1971294Sbill {
19849992Sbostic     unset1(v, &aliases);
1991294Sbill }
2001294Sbill 
20149992Sbostic void
20250439Schristos /*ARGSUSED*/
20350439Schristos dologout(v, t)
20450439Schristos     Char **v;
20550439Schristos     struct command *t;
2061294Sbill {
20749992Sbostic     islogin();
20849992Sbostic     goodbye();
2091294Sbill }
2101294Sbill 
21149992Sbostic void
21250439Schristos /*ARGSUSED*/
21350439Schristos dologin(v, t)
21450439Schristos     Char **v;
21550439Schristos     struct command *t;
2161294Sbill {
21749992Sbostic     islogin();
21849992Sbostic     rechist();
21949992Sbostic     (void) signal(SIGTERM, parterm);
22050024Schristos     (void) execl(_PATH_LOGIN, "login", short2str(v[1]), NULL);
22149992Sbostic     untty();
22249992Sbostic     xexit(1);
2231294Sbill }
2241294Sbill 
22549992Sbostic static void
2261294Sbill islogin()
2271294Sbill {
22849992Sbostic     if (chkstop == 0 && setintr)
22949992Sbostic 	panystop(0);
23049992Sbostic     if (loginsh)
23149992Sbostic 	return;
23249992Sbostic     stderror(ERR_NOTLOGIN);
2331294Sbill }
2341294Sbill 
23549992Sbostic void
2361294Sbill doif(v, kp)
23749992Sbostic     Char  **v;
23849992Sbostic     struct command *kp;
2391294Sbill {
24049992Sbostic     register int i;
24149992Sbostic     register Char **vv;
2421294Sbill 
24349992Sbostic     v++;
24451009Schristos     i = expr(&v);
24549992Sbostic     vv = v;
24649992Sbostic     if (*vv == NULL)
24749992Sbostic 	stderror(ERR_NAME | ERR_EMPTYIF);
24849992Sbostic     if (eq(*vv, STRthen)) {
24949992Sbostic 	if (*++vv)
25049992Sbostic 	    stderror(ERR_NAME | ERR_IMPRTHEN);
251*51589Schristos 	setname(vis_str(STRthen));
2521294Sbill 	/*
25349992Sbostic 	 * If expression was zero, then scan to else, otherwise just fall into
25449992Sbostic 	 * following code.
2551294Sbill 	 */
25649992Sbostic 	if (!i)
25750024Schristos 	    search(T_IF, 0, NULL);
25849992Sbostic 	return;
25949992Sbostic     }
26049992Sbostic     /*
26149992Sbostic      * Simple command attached to this if. Left shift the node in this tree,
26249992Sbostic      * munging it so we can reexecute it.
26349992Sbostic      */
26449992Sbostic     if (i) {
26549992Sbostic 	lshift(kp->t_dcom, vv - kp->t_dcom);
26649992Sbostic 	reexecute(kp);
26749992Sbostic 	donefds();
26849992Sbostic     }
2691294Sbill }
2701294Sbill 
2711294Sbill /*
2721294Sbill  * Reexecute a command, being careful not
2731294Sbill  * to redo i/o redirection, which is already set up.
2741294Sbill  */
27549992Sbostic static void
2761294Sbill reexecute(kp)
27749992Sbostic     register struct command *kp;
2781294Sbill {
27949992Sbostic     kp->t_dflg &= F_SAVE;
28049992Sbostic     kp->t_dflg |= F_REPEAT;
28149992Sbostic     /*
28249992Sbostic      * If tty is still ours to arbitrate, arbitrate it; otherwise dont even set
28349992Sbostic      * pgrp's as the jobs would then have no way to get the tty (we can't give
28449992Sbostic      * it to them, and our parent wouldn't know their pgrp, etc.
28549992Sbostic      */
28650023Sbostic     execute(kp, (tpgrp > 0 ? tpgrp : -1), NULL, NULL);
2871294Sbill }
2881294Sbill 
28949992Sbostic void
29050439Schristos /*ARGSUSED*/
29150439Schristos doelse(v, t)
29250439Schristos     Char **v;
29350439Schristos     struct command *t;
2941294Sbill {
29550024Schristos     search(T_ELSE, 0, NULL);
2961294Sbill }
2971294Sbill 
29849992Sbostic void
29950439Schristos /*ARGSUSED*/
30050439Schristos dogoto(v, t)
30150439Schristos     Char **v;
30250439Schristos     struct command *t;
3031294Sbill {
30449992Sbostic     Char   *lp;
3051294Sbill 
30651420Schristos     gotolab(lp = globone(v[1], G_ERROR));
30751420Schristos     xfree((ptr_t) lp);
30851420Schristos }
30951420Schristos 
31051420Schristos void
31151420Schristos gotolab(lab)
31251420Schristos     Char *lab;
31351420Schristos {
31451420Schristos     register struct whyle *wp;
31549992Sbostic     /*
31649992Sbostic      * While we still can, locate any unknown ends of existing loops. This
31749992Sbostic      * obscure code is the WORST result of the fact that we don't really parse.
31849992Sbostic      */
31949992Sbostic     zlast = T_GOTO;
32049992Sbostic     for (wp = whyles; wp; wp = wp->w_next)
32151378Schristos 	if (wp->w_end.type == F_SEEK && wp->w_end.f_seek == 0) {
32250024Schristos 	    search(T_BREAK, 0, NULL);
32350944Schristos 	    btell(&wp->w_end);
32449992Sbostic 	}
32549992Sbostic 	else
32650944Schristos 	    bseek(&wp->w_end);
32751420Schristos     search(T_GOTO, 0, lab);
32849992Sbostic     /*
32949992Sbostic      * Eliminate loops which were exited.
33049992Sbostic      */
33149992Sbostic     wfree();
3321294Sbill }
3331294Sbill 
33449992Sbostic void
33550439Schristos /*ARGSUSED*/
33650439Schristos doswitch(v, t)
33750439Schristos     Char **v;
33850439Schristos     struct command *t;
3391294Sbill {
34049992Sbostic     register Char *cp, *lp;
3411294Sbill 
34249992Sbostic     v++;
34349992Sbostic     if (!*v || *(*v++) != '(')
34449992Sbostic 	stderror(ERR_SYNTAX);
34549992Sbostic     cp = **v == ')' ? STRNULL : *v++;
34649992Sbostic     if (*(*v++) != ')')
34749992Sbostic 	v--;
34849992Sbostic     if (*v)
34949992Sbostic 	stderror(ERR_SYNTAX);
35049992Sbostic     search(T_SWITCH, 0, lp = globone(cp, G_ERROR));
35149992Sbostic     xfree((ptr_t) lp);
3521294Sbill }
3531294Sbill 
35449992Sbostic void
35550439Schristos /*ARGSUSED*/
35650439Schristos dobreak(v, t)
35750439Schristos     Char **v;
35850439Schristos     struct command *t;
3591294Sbill {
36049992Sbostic     if (whyles)
36149992Sbostic 	toend();
36249992Sbostic     else
36349992Sbostic 	stderror(ERR_NAME | ERR_NOTWHILE);
3641294Sbill }
3651294Sbill 
36649992Sbostic void
36750439Schristos /*ARGSUSED*/
36850439Schristos doexit(v, t)
36950439Schristos     Char **v;
37050439Schristos     struct command *t;
3711294Sbill {
37249992Sbostic     if (chkstop == 0 && (intty || intact) && evalvec == 0)
37349992Sbostic 	panystop(0);
37449992Sbostic     /*
37549992Sbostic      * Don't DEMAND parentheses here either.
37649992Sbostic      */
37749992Sbostic     v++;
37849992Sbostic     if (*v) {
37951009Schristos 	set(STRstatus, putn(expr(&v)));
38049992Sbostic 	if (*v)
38149992Sbostic 	    stderror(ERR_NAME | ERR_EXPRESSION);
38249992Sbostic     }
38349992Sbostic     btoeof();
38449992Sbostic     if (intty)
38549992Sbostic 	(void) close(SHIN);
3861294Sbill }
3871294Sbill 
38849992Sbostic void
38950439Schristos /*ARGSUSED*/
39050439Schristos doforeach(v, t)
39150439Schristos     Char **v;
39250439Schristos     struct command *t;
3931294Sbill {
39449992Sbostic     register Char *cp, *sp;
39549992Sbostic     register struct whyle *nwp;
3961294Sbill 
39749992Sbostic     v++;
39849992Sbostic     sp = cp = strip(*v);
39949992Sbostic     if (!letter(*sp))
40049992Sbostic 	stderror(ERR_NAME | ERR_VARBEGIN);
40149992Sbostic     while (*cp && alnum(*cp))
40249992Sbostic 	cp++;
40349992Sbostic     if (*cp)
40449992Sbostic 	stderror(ERR_NAME | ERR_VARALNUM);
40549992Sbostic     if ((cp - sp) > MAXVARLEN)
40649992Sbostic 	stderror(ERR_NAME | ERR_VARTOOLONG);
40749992Sbostic     cp = *v++;
40849992Sbostic     if (v[0][0] != '(' || v[blklen(v) - 1][0] != ')')
40949992Sbostic 	stderror(ERR_NAME | ERR_NOPAREN);
41049992Sbostic     v++;
41149992Sbostic     gflag = 0, tglob(v);
41249992Sbostic     v = globall(v);
41349992Sbostic     if (v == 0)
41449992Sbostic 	stderror(ERR_NAME | ERR_NOMATCH);
41549992Sbostic     nwp = (struct whyle *) xcalloc(1, sizeof *nwp);
41649992Sbostic     nwp->w_fe = nwp->w_fe0 = v;
41749992Sbostic     gargv = 0;
41850944Schristos     btell(&nwp->w_start);
41949992Sbostic     nwp->w_fename = Strsave(cp);
42049992Sbostic     nwp->w_next = whyles;
42151378Schristos     nwp->w_end.type = F_SEEK;
42249992Sbostic     whyles = nwp;
42349992Sbostic     /*
42449992Sbostic      * Pre-read the loop so as to be more comprehensible to a terminal user.
42549992Sbostic      */
42649992Sbostic     zlast = T_FOREACH;
42749992Sbostic     if (intty)
42849992Sbostic 	preread();
42949992Sbostic     doagain();
4301294Sbill }
4311294Sbill 
43249992Sbostic void
43350439Schristos /*ARGSUSED*/
43450439Schristos dowhile(v, t)
43550439Schristos     Char **v;
43650439Schristos     struct command *t;
4371294Sbill {
43849992Sbostic     register int status;
43950944Schristos     register bool again = whyles != 0 && SEEKEQ(&whyles->w_start, &lineloc) &&
44049992Sbostic     whyles->w_fename == 0;
4411294Sbill 
44249992Sbostic     v++;
44349992Sbostic     /*
44449992Sbostic      * Implement prereading here also, taking care not to evaluate the
44549992Sbostic      * expression before the loop has been read up from a terminal.
44649992Sbostic      */
44749992Sbostic     if (intty && !again)
44849992Sbostic 	status = !exp0(&v, 1);
44949992Sbostic     else
45051009Schristos 	status = !expr(&v);
45149992Sbostic     if (*v)
45249992Sbostic 	stderror(ERR_NAME | ERR_EXPRESSION);
45349992Sbostic     if (!again) {
45449992Sbostic 	register struct whyle *nwp =
45549992Sbostic 	(struct whyle *) xcalloc(1, sizeof(*nwp));
4561294Sbill 
45749992Sbostic 	nwp->w_start = lineloc;
45851378Schristos 	nwp->w_end.type = F_SEEK;
45951378Schristos 	nwp->w_end.f_seek = 0;
46049992Sbostic 	nwp->w_next = whyles;
46149992Sbostic 	whyles = nwp;
46249992Sbostic 	zlast = T_WHILE;
46349992Sbostic 	if (intty) {
46449992Sbostic 	    /*
46549992Sbostic 	     * The tty preread
46649992Sbostic 	     */
46749992Sbostic 	    preread();
46849992Sbostic 	    doagain();
46949992Sbostic 	    return;
4701294Sbill 	}
47149992Sbostic     }
47249992Sbostic     if (status)
47349992Sbostic 	/* We ain't gonna loop no more, no more! */
47449992Sbostic 	toend();
4751294Sbill }
4761294Sbill 
47749992Sbostic static void
4781294Sbill preread()
4791294Sbill {
48050944Schristos     whyles->w_end.type = I_SEEK;
48149992Sbostic     if (setintr)
48250028Sbostic 	(void) sigsetmask(sigblock((sigset_t) 0) & ~sigmask(SIGINT));
4831294Sbill 
48450024Schristos     search(T_BREAK, 0, NULL);		/* read the expression in */
48549992Sbostic     if (setintr)
48649992Sbostic 	(void) sigblock(sigmask(SIGINT));
48750944Schristos     btell(&whyles->w_end);
4881294Sbill }
4891294Sbill 
49049992Sbostic void
49150439Schristos /*ARGSUSED*/
49250439Schristos doend(v, t)
49350439Schristos     Char **v;
49450439Schristos     struct command *t;
4951294Sbill {
49649992Sbostic     if (!whyles)
49749992Sbostic 	stderror(ERR_NAME | ERR_NOTWHILE);
49850944Schristos     btell(&whyles->w_end);
49949992Sbostic     doagain();
5001294Sbill }
5011294Sbill 
50249992Sbostic void
50350439Schristos /*ARGSUSED*/
50450439Schristos docontin(v, t)
50550439Schristos     Char **v;
50650439Schristos     struct command *t;
5071294Sbill {
50849992Sbostic     if (!whyles)
50949992Sbostic 	stderror(ERR_NAME | ERR_NOTWHILE);
51049992Sbostic     doagain();
5111294Sbill }
5121294Sbill 
51349992Sbostic static void
5141294Sbill doagain()
5151294Sbill {
51649992Sbostic     /* Repeating a while is simple */
51749992Sbostic     if (whyles->w_fename == 0) {
51850944Schristos 	bseek(&whyles->w_start);
51949992Sbostic 	return;
52049992Sbostic     }
52149992Sbostic     /*
52249992Sbostic      * The foreach variable list actually has a spurious word ")" at the end of
52349992Sbostic      * the w_fe list.  Thus we are at the of the list if one word beyond this
52449992Sbostic      * is 0.
52549992Sbostic      */
52649992Sbostic     if (!whyles->w_fe[1]) {
52750439Schristos 	dobreak(NULL, NULL);
52849992Sbostic 	return;
52949992Sbostic     }
53049992Sbostic     set(whyles->w_fename, Strsave(*whyles->w_fe++));
53150944Schristos     bseek(&whyles->w_start);
5321294Sbill }
5331294Sbill 
53449992Sbostic void
5351294Sbill dorepeat(v, kp)
53649992Sbostic     Char  **v;
53749992Sbostic     struct command *kp;
5381294Sbill {
53949992Sbostic     register int i;
54050028Sbostic     register sigset_t omask = 0;
5411294Sbill 
54249992Sbostic     i = getn(v[1]);
54349992Sbostic     if (setintr)
54449992Sbostic 	omask = sigblock(sigmask(SIGINT)) & ~sigmask(SIGINT);
54549992Sbostic     lshift(v, 2);
54649992Sbostic     while (i > 0) {
5471294Sbill 	if (setintr)
54849992Sbostic 	    (void) sigsetmask(omask);
54949992Sbostic 	reexecute(kp);
55049992Sbostic 	--i;
55149992Sbostic     }
55249992Sbostic     donefds();
55349992Sbostic     if (setintr)
55449992Sbostic 	(void) sigsetmask(omask);
5551294Sbill }
5561294Sbill 
55749992Sbostic void
55850439Schristos /*ARGSUSED*/
55950439Schristos doswbrk(v, t)
56050439Schristos     Char **v;
56150439Schristos     struct command *t;
5621294Sbill {
56350024Schristos     search(T_BRKSW, 0, NULL);
5641294Sbill }
5651294Sbill 
56649992Sbostic int
5671294Sbill srchx(cp)
56849992Sbostic     register Char *cp;
5691294Sbill {
57049992Sbostic     register struct srch *sp, *sp1, *sp2;
57149992Sbostic     register i;
5721294Sbill 
57349992Sbostic     /*
57449992Sbostic      * Binary search Sp1 is the beginning of the current search range. Sp2 is
57549992Sbostic      * one past the end.
57649992Sbostic      */
57749992Sbostic     for (sp1 = srchn, sp2 = srchn + nsrchn; sp1 < sp2;) {
57849992Sbostic 	sp = sp1 + ((sp2 - sp1) >> 1);
57949992Sbostic 	if ((i = *cp - *sp->s_name) == 0 &&
58049992Sbostic 	    (i = Strcmp(cp, str2short(sp->s_name))) == 0)
58149992Sbostic 	    return sp->s_value;
58249992Sbostic 	if (i < 0)
58349992Sbostic 	    sp2 = sp;
58449992Sbostic 	else
58549992Sbostic 	    sp1 = sp + 1;
58649992Sbostic     }
58749992Sbostic     return (-1);
5881294Sbill }
5891294Sbill 
59049992Sbostic static Char Stype;
59149992Sbostic static Char *Sgoal;
5921294Sbill 
5931294Sbill /*VARARGS2*/
59449992Sbostic void
5951294Sbill search(type, level, goal)
59649992Sbostic     int     type;
59749992Sbostic     register int level;
59849992Sbostic     Char   *goal;
5991294Sbill {
60049992Sbostic     Char    wordbuf[BUFSIZ];
60149992Sbostic     register Char *aword = wordbuf;
60249992Sbostic     register Char *cp;
6031294Sbill 
60449992Sbostic     Stype = type;
60549992Sbostic     Sgoal = goal;
60650944Schristos     if (type == T_GOTO) {
60750944Schristos 	struct Ain a;
60850944Schristos 	a.type = F_SEEK;
60950944Schristos 	a.f_seek = 0;
61050944Schristos 	bseek(&a);
61150944Schristos     }
61249992Sbostic     do {
61350944Schristos 	if (intty && fseekp == feobp && aret == F_SEEK)
61450439Schristos 	    (void) fprintf(cshout, "? "), (void) fflush(cshout);
61549992Sbostic 	aword[0] = 0;
61649992Sbostic 	(void) getword(aword);
61749992Sbostic 	switch (srchx(aword)) {
6181294Sbill 
61949992Sbostic 	case T_ELSE:
62049992Sbostic 	    if (level == 0 && type == T_IF)
62149992Sbostic 		return;
62249992Sbostic 	    break;
6231294Sbill 
62449992Sbostic 	case T_IF:
62549992Sbostic 	    while (getword(aword))
62649992Sbostic 		continue;
62749992Sbostic 	    if ((type == T_IF || type == T_ELSE) &&
62849992Sbostic 		eq(aword, STRthen))
62949992Sbostic 		level++;
63049992Sbostic 	    break;
6311294Sbill 
63249992Sbostic 	case T_ENDIF:
63349992Sbostic 	    if (type == T_IF || type == T_ELSE)
63449992Sbostic 		level--;
63549992Sbostic 	    break;
6361294Sbill 
63749992Sbostic 	case T_FOREACH:
63849992Sbostic 	case T_WHILE:
63949992Sbostic 	    if (type == T_BREAK)
64049992Sbostic 		level++;
64149992Sbostic 	    break;
6421294Sbill 
64349992Sbostic 	case T_END:
64449992Sbostic 	    if (type == T_BREAK)
64549992Sbostic 		level--;
64649992Sbostic 	    break;
6471294Sbill 
64849992Sbostic 	case T_SWITCH:
64949992Sbostic 	    if (type == T_SWITCH || type == T_BRKSW)
65049992Sbostic 		level++;
65149992Sbostic 	    break;
6521294Sbill 
65349992Sbostic 	case T_ENDSW:
65449992Sbostic 	    if (type == T_SWITCH || type == T_BRKSW)
65549992Sbostic 		level--;
65649992Sbostic 	    break;
6571294Sbill 
65849992Sbostic 	case T_LABEL:
65949992Sbostic 	    if (type == T_GOTO && getword(aword) && eq(aword, goal))
66049992Sbostic 		level = -1;
66149992Sbostic 	    break;
6621294Sbill 
66349992Sbostic 	default:
66449992Sbostic 	    if (type != T_GOTO && (type != T_SWITCH || level != 0))
66549992Sbostic 		break;
66649992Sbostic 	    if (lastchr(aword) != ':')
66749992Sbostic 		break;
66849992Sbostic 	    aword[Strlen(aword) - 1] = 0;
66949992Sbostic 	    if (type == T_GOTO && eq(aword, goal) ||
67049992Sbostic 		type == T_SWITCH && eq(aword, STRdefault))
67149992Sbostic 		level = -1;
67249992Sbostic 	    break;
6731294Sbill 
67449992Sbostic 	case T_CASE:
67549992Sbostic 	    if (type != T_SWITCH || level != 0)
67649992Sbostic 		break;
67749992Sbostic 	    (void) getword(aword);
67849992Sbostic 	    if (lastchr(aword) == ':')
67949992Sbostic 		aword[Strlen(aword) - 1] = 0;
68049992Sbostic 	    cp = strip(Dfix1(aword));
68149992Sbostic 	    if (Gmatch(goal, cp))
68249992Sbostic 		level = -1;
68349992Sbostic 	    xfree((ptr_t) cp);
68449992Sbostic 	    break;
6851294Sbill 
68649992Sbostic 	case T_DEFAULT:
68749992Sbostic 	    if (type == T_SWITCH && level == 0)
68849992Sbostic 		level = -1;
68949992Sbostic 	    break;
69049992Sbostic 	}
69149992Sbostic 	(void) getword(NULL);
69249992Sbostic     } while (level >= 0);
6931294Sbill }
6941294Sbill 
69549992Sbostic static int
6961294Sbill getword(wp)
69749992Sbostic     register Char *wp;
6981294Sbill {
69949992Sbostic     register int found = 0;
70049992Sbostic     register int c, d;
70149992Sbostic     int     kwd = 0;
70249992Sbostic     Char   *owp = wp;
7031294Sbill 
70449992Sbostic     c = readc(1);
70549992Sbostic     d = 0;
70649992Sbostic     do {
70749992Sbostic 	while (c == ' ' || c == '\t')
70849992Sbostic 	    c = readc(1);
70949992Sbostic 	if (c == '#')
71049992Sbostic 	    do
71149992Sbostic 		c = readc(1);
71249992Sbostic 	    while (c >= 0 && c != '\n');
71349992Sbostic 	if (c < 0)
71449992Sbostic 	    goto past;
71549992Sbostic 	if (c == '\n') {
71649992Sbostic 	    if (wp)
71749992Sbostic 		break;
71849992Sbostic 	    return (0);
71949992Sbostic 	}
72049992Sbostic 	unreadc(c);
72149992Sbostic 	found = 1;
7221294Sbill 	do {
72349992Sbostic 	    c = readc(1);
72449992Sbostic 	    if (c == '\\' && (c = readc(1)) == '\n')
72549992Sbostic 		c = ' ';
72649992Sbostic 	    if (c == '\'' || c == '"')
72749992Sbostic 		if (d == 0)
72849992Sbostic 		    d = c;
72949992Sbostic 		else if (d == c)
73049992Sbostic 		    d = 0;
73149992Sbostic 	    if (c < 0)
73249992Sbostic 		goto past;
73349992Sbostic 	    if (wp) {
73449992Sbostic 		*wp++ = c;
73549992Sbostic 		*wp = 0;	/* end the string b4 test */
73649992Sbostic 	    }
73749992Sbostic 	} while ((d || !(kwd = keyword(owp)) && c != ' '
73849992Sbostic 		  && c != '\t') && c != '\n');
73949992Sbostic     } while (wp == 0);
74049992Sbostic 
74149992Sbostic     /*
74249992Sbostic      * if we have read a keyword ( "if", "switch" or "while" ) then we do not
74349992Sbostic      * need to unreadc the look-ahead char
74449992Sbostic      */
74549992Sbostic     if (!kwd) {
7461294Sbill 	unreadc(c);
7471294Sbill 	if (found)
74849992Sbostic 	    *--wp = 0;
74949992Sbostic     }
7501294Sbill 
75149992Sbostic     return (found);
75249992Sbostic 
7531294Sbill past:
75449992Sbostic     switch (Stype) {
7551294Sbill 
75649992Sbostic     case T_IF:
75749992Sbostic 	stderror(ERR_NAME | ERR_NOTFOUND, "then/endif");
7581294Sbill 
75949992Sbostic     case T_ELSE:
76049992Sbostic 	stderror(ERR_NAME | ERR_NOTFOUND, "endif");
7611294Sbill 
76249992Sbostic     case T_BRKSW:
76349992Sbostic     case T_SWITCH:
76449992Sbostic 	stderror(ERR_NAME | ERR_NOTFOUND, "endsw");
7651294Sbill 
76649992Sbostic     case T_BREAK:
76749992Sbostic 	stderror(ERR_NAME | ERR_NOTFOUND, "end");
7681294Sbill 
76949992Sbostic     case T_GOTO:
770*51589Schristos 	setname(vis_str(Sgoal));
77149992Sbostic 	stderror(ERR_NAME | ERR_NOTFOUND, "label");
77249992Sbostic     }
77349992Sbostic     /* NOTREACHED */
77449992Sbostic     return (0);
7751294Sbill }
7761294Sbill 
77749992Sbostic /*
77849992Sbostic  * keyword(wp) determines if wp is one of the built-n functions if,
77949992Sbostic  * switch or while. It seems that when an if statement looks like
78049992Sbostic  * "if(" then getword above sucks in the '(' and so the search routine
78149992Sbostic  * never finds what it is scanning for. Rather than rewrite doword, I hack
78249992Sbostic  * in a test to see if the string forms a keyword. Then doword stops
78349992Sbostic  * and returns the word "if" -strike
78449992Sbostic  */
78549992Sbostic 
78649992Sbostic static int
78749992Sbostic keyword(wp)
78849992Sbostic     Char   *wp;
7891294Sbill {
79049992Sbostic     static Char STRif[] = {'i', 'f', '\0'};
79149992Sbostic     static Char STRwhile[] = {'w', 'h', 'i', 'l', 'e', '\0'};
79249992Sbostic     static Char STRswitch[] = {'s', 'w', 'i', 't', 'c', 'h', '\0'};
7931294Sbill 
79449992Sbostic     if (!wp)
79549992Sbostic 	return (0);
79649992Sbostic 
79749992Sbostic     if ((Strcmp(wp, STRif) == 0) || (Strcmp(wp, STRwhile) == 0)
79849992Sbostic 	|| (Strcmp(wp, STRswitch) == 0))
79949992Sbostic 	return (1);
80049992Sbostic 
80149992Sbostic     return (0);
8021294Sbill }
8031294Sbill 
80449992Sbostic static void
80549992Sbostic toend()
80649992Sbostic {
80751378Schristos     if (whyles->w_end.type == F_SEEK && whyles->w_end.f_seek == 0) {
80849992Sbostic 	search(T_BREAK, 0, NULL);
80950944Schristos 	btell(&whyles->w_end);
81050944Schristos 	whyles->w_end.f_seek--;
81149992Sbostic     }
81249992Sbostic     else
81350944Schristos 	bseek(&whyles->w_end);
81449992Sbostic     wfree();
81549992Sbostic }
81649992Sbostic 
81749992Sbostic void
8181294Sbill wfree()
8191294Sbill {
82050944Schristos     struct Ain    o;
82150944Schristos     struct whyle *nwp;
82251527Schristos 
82350944Schristos     btell(&o);
8241294Sbill 
82550944Schristos     for (; whyles; whyles = nwp) {
82649992Sbostic 	register struct whyle *wp = whyles;
82750944Schristos 	nwp = wp->w_next;
82851527Schristos 
82951527Schristos 	/*
83051527Schristos 	 * We free loops that have different seek types.
83151527Schristos 	 */
83251527Schristos 	if (wp->w_end.type != I_SEEK && wp->w_start.type == wp->w_end.type &&
83351527Schristos 	    wp->w_start.type == o.type) {
83451527Schristos 	    if (wp->w_end.type == F_SEEK) {
83551527Schristos 		if (o.f_seek >= wp->w_start.f_seek &&
83651527Schristos 		    (wp->w_end.f_seek == 0 || o.f_seek < wp->w_end.f_seek))
83751527Schristos 		    break;
83851527Schristos 	    }
83951527Schristos 	    else {
84051527Schristos 		if (o.a_seek >= wp->w_start.a_seek &&
84151527Schristos 		    (wp->w_end.a_seek == 0 || o.a_seek < wp->w_end.a_seek))
84251527Schristos 		    break;
84351527Schristos 	    }
84451420Schristos 	}
84551527Schristos 
84649992Sbostic 	if (wp->w_fe0)
84749992Sbostic 	    blkfree(wp->w_fe0);
84849992Sbostic 	if (wp->w_fename)
84949992Sbostic 	    xfree((ptr_t) wp->w_fename);
85049992Sbostic 	xfree((ptr_t) wp);
85149992Sbostic     }
8521294Sbill }
8531294Sbill 
85449992Sbostic void
85550439Schristos /*ARGSUSED*/
85650439Schristos doecho(v, t)
85750439Schristos     Char **v;
85850439Schristos     struct command *t;
8591294Sbill {
86049992Sbostic     xecho(' ', v);
8611294Sbill }
8621294Sbill 
86349992Sbostic void
86450439Schristos /*ARGSUSED*/
86550439Schristos doglob(v, t)
86650439Schristos     Char **v;
86750439Schristos     struct command *t;
8681294Sbill {
86949992Sbostic     xecho(0, v);
87050439Schristos     (void) fflush(cshout);
8711294Sbill }
8721294Sbill 
87349992Sbostic static void
87449992Sbostic xecho(sep, v)
87550024Schristos     int    sep;
87649992Sbostic     register Char **v;
8771294Sbill {
87849992Sbostic     register Char *cp;
87949992Sbostic     int     nonl = 0;
8801294Sbill 
88149992Sbostic     if (setintr)
88250028Sbostic 	(void) sigsetmask(sigblock((sigset_t) 0) & ~sigmask(SIGINT));
88349992Sbostic     v++;
88449992Sbostic     if (*v == 0)
88549992Sbostic 	return;
88649992Sbostic     gflag = 0, tglob(v);
88749992Sbostic     if (gflag) {
88849992Sbostic 	v = globall(v);
88949992Sbostic 	if (v == 0)
89049992Sbostic 	    stderror(ERR_NAME | ERR_NOMATCH);
89149992Sbostic     }
89249992Sbostic     else {
89349992Sbostic 	v = gargv = saveblk(v);
89449992Sbostic 	trim(v);
89549992Sbostic     }
89649992Sbostic     if (sep == ' ' && *v && eq(*v, STRmn))
89749992Sbostic 	nonl++, v++;
89849992Sbostic     while (cp = *v++) {
89949992Sbostic 	register int c;
9001294Sbill 
90149992Sbostic 	while (c = *cp++)
902*51589Schristos 	    (void) vis_fputc(c | QUOTE, cshout);
90349992Sbostic 
90449992Sbostic 	if (*v)
905*51589Schristos 	    (void) vis_fputc(sep | QUOTE, cshout);
90649992Sbostic     }
90749992Sbostic     if (sep && nonl == 0)
90850439Schristos 	(void) fputc('\n', cshout);
90949992Sbostic     else
91050439Schristos 	(void) fflush(cshout);
91149992Sbostic     if (setintr)
91249992Sbostic 	(void) sigblock(sigmask(SIGINT));
91349992Sbostic     if (gargv)
91449992Sbostic 	blkfree(gargv), gargv = 0;
9151294Sbill }
9161294Sbill 
91749992Sbostic void
91850439Schristos /*ARGSUSED*/
91950439Schristos dosetenv(v, t)
92050439Schristos     Char **v;
92150439Schristos     struct command *t;
9221294Sbill {
92349992Sbostic     Char   *vp, *lp;
9241294Sbill 
92549992Sbostic     v++;
92649992Sbostic     if ((vp = *v++) == 0) {
92749992Sbostic 	register Char **ep;
92821753Sedward 
92949992Sbostic 	if (setintr)
93050028Sbostic 	    (void) sigsetmask(sigblock((sigset_t) 0) & ~sigmask(SIGINT));
93149992Sbostic 	for (ep = STR_environ; *ep; ep++)
932*51589Schristos 	    (void) fprintf(cshout, "%s\n", vis_str(*ep));
93349992Sbostic 	return;
93449992Sbostic     }
93549992Sbostic     if ((lp = *v++) == 0)
93649992Sbostic 	lp = STRNULL;
93750746Schristos     Setenv(vp, lp = globone(lp, G_APPEND));
93849992Sbostic     if (eq(vp, STRPATH)) {
93949992Sbostic 	importpath(lp);
94050439Schristos 	dohash(NULL, NULL);
94149992Sbostic     }
94249992Sbostic     else if (eq(vp, STRLANG) || eq(vp, STRLC_CTYPE)) {
94349992Sbostic #ifdef NLS
94449992Sbostic 	int     k;
94549992Sbostic 
94649992Sbostic 	(void) setlocale(LC_ALL, "");
94751437Sleres 	for (k = 0200; k <= 0377 && !Isprint(k); k++)
94851437Sleres 		continue;
94949992Sbostic 	AsciiOnly = k > 0377;
95049992Sbostic #else
95149992Sbostic 	AsciiOnly = 0;
95249992Sbostic #endif				/* NLS */
95349992Sbostic     }
95449992Sbostic     xfree((ptr_t) lp);
9551294Sbill }
9561294Sbill 
95749992Sbostic void
95850439Schristos /*ARGSUSED*/
95950439Schristos dounsetenv(v, t)
96050439Schristos     Char **v;
96150439Schristos     struct command *t;
9621294Sbill {
96349992Sbostic     Char  **ep, *p, *n;
96449992Sbostic     int     i, maxi;
96549992Sbostic     static Char *name = NULL;
9661294Sbill 
96749992Sbostic     if (name)
96849992Sbostic 	xfree((ptr_t) name);
96949992Sbostic     /*
97049992Sbostic      * Find the longest environment variable
97149992Sbostic      */
97249992Sbostic     for (maxi = 0, ep = STR_environ; *ep; ep++) {
97351437Sleres 	for (i = 0, p = *ep; *p && *p != '='; p++, i++)
97451437Sleres 	    continue;
97549992Sbostic 	if (i > maxi)
97649992Sbostic 	    maxi = i;
97749992Sbostic     }
97849992Sbostic 
97949992Sbostic     name = (Char *) xmalloc((size_t) (maxi + 1) * sizeof(Char));
98049992Sbostic 
98150160Schristos     while (++v && *v)
98250160Schristos 	for (maxi = 1; maxi;)
98350160Schristos 	    for (maxi = 0, ep = STR_environ; *ep; ep++) {
98451437Sleres 		for (n = name, p = *ep; *p && *p != '='; *n++ = *p++)
98551437Sleres 		    continue;
98650160Schristos 		*n = '\0';
98750160Schristos 		if (!Gmatch(name, *v))
98850160Schristos 		    continue;
98950160Schristos 		maxi = 1;
99050160Schristos 		if (eq(name, STRLANG) || eq(name, STRLC_CTYPE)) {
99149992Sbostic #ifdef NLS
99250160Schristos 		    int     k;
99349992Sbostic 
99450160Schristos 		    (void) setlocale(LC_ALL, "");
99551437Sleres 		    for (k = 0200; k <= 0377 && !Isprint(k); k++)
99651437Sleres 			continue;
99750160Schristos 		    AsciiOnly = k > 0377;
99849992Sbostic #else
99950160Schristos 		    AsciiOnly = getenv("LANG") == NULL &&
100050160Schristos 			getenv("LC_CTYPE") == NULL;
100149992Sbostic #endif				/* NLS */
100250160Schristos 		}
100350160Schristos 		/*
100450160Schristos 		 * Delete name, and start again cause the environment changes
100550160Schristos 		 */
100650160Schristos 		Unsetenv(name);
100750160Schristos 		break;
100849992Sbostic 	    }
100950976Schristos     xfree((ptr_t) name);
101050976Schristos     name = NULL;
10111294Sbill }
10121294Sbill 
101349992Sbostic void
101449992Sbostic Setenv(name, val)
101549992Sbostic     Char   *name, *val;
10161294Sbill {
101749992Sbostic     register Char **ep = STR_environ;
101849992Sbostic     register Char *cp, *dp;
101949992Sbostic     Char   *blk[2];
102049992Sbostic     Char  **oep = ep;
10211294Sbill 
102249992Sbostic 
102349992Sbostic     for (; *ep; ep++) {
102449992Sbostic 	for (cp = name, dp = *ep; *cp && *cp == *dp; cp++, dp++)
102549992Sbostic 	    continue;
102649992Sbostic 	if (*cp != 0 || *dp != '=')
102749992Sbostic 	    continue;
102849992Sbostic 	cp = Strspl(STRequal, val);
102949992Sbostic 	xfree((ptr_t) * ep);
103049992Sbostic 	*ep = strip(Strspl(name, cp));
103149992Sbostic 	xfree((ptr_t) cp);
103249992Sbostic 	blkfree((Char **) environ);
103349992Sbostic 	environ = short2blk(STR_environ);
103449992Sbostic 	return;
103549992Sbostic     }
103649992Sbostic     cp = Strspl(name, STRequal);
103749992Sbostic     blk[0] = strip(Strspl(cp, val));
103849992Sbostic     xfree((ptr_t) cp);
103949992Sbostic     blk[1] = 0;
104049992Sbostic     STR_environ = blkspl(STR_environ, blk);
104149992Sbostic     blkfree((Char **) environ);
104249992Sbostic     environ = short2blk(STR_environ);
104349992Sbostic     xfree((ptr_t) oep);
10441294Sbill }
10451294Sbill 
104649992Sbostic static void
104749992Sbostic Unsetenv(name)
104849992Sbostic     Char   *name;
10491294Sbill {
105049992Sbostic     register Char **ep = STR_environ;
105149992Sbostic     register Char *cp, *dp;
105249992Sbostic     Char  **oep = ep;
10531294Sbill 
105449992Sbostic     for (; *ep; ep++) {
105549992Sbostic 	for (cp = name, dp = *ep; *cp && *cp == *dp; cp++, dp++)
105649992Sbostic 	    continue;
105749992Sbostic 	if (*cp != 0 || *dp != '=')
105849992Sbostic 	    continue;
105949992Sbostic 	cp = *ep;
106049992Sbostic 	*ep = 0;
106149992Sbostic 	STR_environ = blkspl(STR_environ, ep + 1);
106249992Sbostic 	environ = short2blk(STR_environ);
106349992Sbostic 	*ep = cp;
106449992Sbostic 	xfree((ptr_t) cp);
106549992Sbostic 	xfree((ptr_t) oep);
106649992Sbostic 	return;
106749992Sbostic     }
10681294Sbill }
10691294Sbill 
107049992Sbostic void
107150439Schristos /*ARGSUSED*/
107250439Schristos doumask(v, t)
107350439Schristos     Char **v;
107450439Schristos     struct command *t;
10751294Sbill {
107649992Sbostic     register Char *cp = v[1];
107749992Sbostic     register int i;
10781294Sbill 
107949992Sbostic     if (cp == 0) {
108049992Sbostic 	i = umask(0);
108117519Sedward 	(void) umask(i);
108250439Schristos 	(void) fprintf(cshout, "%o\n", i);
108349992Sbostic 	return;
108449992Sbostic     }
108549992Sbostic     i = 0;
108649992Sbostic     while (Isdigit(*cp) && *cp != '8' && *cp != '9')
108749992Sbostic 	i = i * 8 + *cp++ - '0';
108849992Sbostic     if (*cp || i < 0 || i > 0777)
108949992Sbostic 	stderror(ERR_NAME | ERR_MASK);
109049992Sbostic     (void) umask(i);
10911294Sbill }
10921294Sbill 
109349992Sbostic typedef int RLIM_TYPE;
10941294Sbill 
109549992Sbostic static struct limits {
109649992Sbostic     int     limconst;
109749992Sbostic     char   *limname;
109849992Sbostic     int     limdiv;
109949992Sbostic     char   *limscale;
110049992Sbostic }       limits[] = {
110151437Sleres     RLIMIT_CPU,		"cputime",	1,	"seconds",
110249992Sbostic     RLIMIT_FSIZE,	"filesize",	1024,	"kbytes",
110349992Sbostic     RLIMIT_DATA,	"datasize",	1024,	"kbytes",
110449992Sbostic     RLIMIT_STACK,	"stacksize",	1024,	"kbytes",
110549992Sbostic     RLIMIT_CORE,	"coredumpsize", 1024,	"kbytes",
110651437Sleres     RLIMIT_RSS,		"memoryuse",	1024,	"kbytes",
110750024Schristos     RLIMIT_MEMLOCK,	"memorylocked",	1024,	"kbytes",
110850024Schristos     RLIMIT_NPROC,	"maxproc",	1,	"",
110950024Schristos     RLIMIT_OFILE,	"openfiles",	1,	"",
111051437Sleres     -1,			NULL,		0,	NULL
11111294Sbill };
11121294Sbill 
111349992Sbostic static struct limits *findlim();
111449992Sbostic static RLIM_TYPE getval();
111549992Sbostic static void limtail();
111649992Sbostic static void plim();
111749992Sbostic static int setlim();
111849992Sbostic 
111949992Sbostic static struct limits *
11201294Sbill findlim(cp)
112149992Sbostic     Char   *cp;
11221294Sbill {
112349992Sbostic     register struct limits *lp, *res;
11241294Sbill 
112549992Sbostic     res = (struct limits *) NULL;
112649992Sbostic     for (lp = limits; lp->limconst >= 0; lp++)
112749992Sbostic 	if (prefix(cp, str2short(lp->limname))) {
112849992Sbostic 	    if (res)
112949992Sbostic 		stderror(ERR_NAME | ERR_AMBIG);
113049992Sbostic 	    res = lp;
113149992Sbostic 	}
113249992Sbostic     if (res)
113349992Sbostic 	return (res);
113449992Sbostic     stderror(ERR_NAME | ERR_LIMIT);
113549992Sbostic     /* NOTREACHED */
113649992Sbostic     return (0);
11371294Sbill }
11381294Sbill 
113949992Sbostic void
114050439Schristos /*ARGSUSED*/
114150439Schristos dolimit(v, t)
114250439Schristos     Char **v;
114350439Schristos     struct command *t;
11441294Sbill {
114549992Sbostic     register struct limits *lp;
114649992Sbostic     register RLIM_TYPE limit;
114749992Sbostic     char    hard = 0;
11481294Sbill 
114949992Sbostic     v++;
115049992Sbostic     if (*v && eq(*v, STRmh)) {
115149992Sbostic 	hard = 1;
11521294Sbill 	v++;
115349992Sbostic     }
115449992Sbostic     if (*v == 0) {
115549992Sbostic 	for (lp = limits; lp->limconst >= 0; lp++)
115649992Sbostic 	    plim(lp, hard);
115749992Sbostic 	return;
115849992Sbostic     }
115949992Sbostic     lp = findlim(v[0]);
116049992Sbostic     if (v[1] == 0) {
116149992Sbostic 	plim(lp, hard);
116249992Sbostic 	return;
116349992Sbostic     }
116449992Sbostic     limit = getval(lp, v + 1);
116549992Sbostic     if (setlim(lp, hard, limit) < 0)
116649992Sbostic 	stderror(ERR_SILENT);
11671294Sbill }
11681294Sbill 
116949992Sbostic static  RLIM_TYPE
11701294Sbill getval(lp, v)
117149992Sbostic     register struct limits *lp;
117249992Sbostic     Char  **v;
11731294Sbill {
117449992Sbostic     register float f;
117549992Sbostic     double  atof();
117649992Sbostic     Char   *cp = *v++;
11771294Sbill 
117849992Sbostic     f = atof(short2str(cp));
117949992Sbostic 
118049992Sbostic     while (Isdigit(*cp) || *cp == '.' || *cp == 'e' || *cp == 'E')
118149992Sbostic 	cp++;
118249992Sbostic     if (*cp == 0) {
118349992Sbostic 	if (*v == 0)
118449992Sbostic 	    return ((RLIM_TYPE) ((f + 0.5) * lp->limdiv));
118549992Sbostic 	cp = *v;
118649992Sbostic     }
118749992Sbostic     switch (*cp) {
118849992Sbostic     case ':':
118949992Sbostic 	if (lp->limconst != RLIMIT_CPU)
119049992Sbostic 	    goto badscal;
119149992Sbostic 	return ((RLIM_TYPE) (f * 60.0 + atof(short2str(cp + 1))));
119249992Sbostic     case 'h':
119349992Sbostic 	if (lp->limconst != RLIMIT_CPU)
119449992Sbostic 	    goto badscal;
119549992Sbostic 	limtail(cp, "hours");
119649992Sbostic 	f *= 3600.0;
119749992Sbostic 	break;
119849992Sbostic     case 'm':
119949992Sbostic 	if (lp->limconst == RLIMIT_CPU) {
120049992Sbostic 	    limtail(cp, "minutes");
120149992Sbostic 	    f *= 60.0;
120249992Sbostic 	    break;
12031294Sbill 	}
120449992Sbostic 	*cp = 'm';
120549992Sbostic 	limtail(cp, "megabytes");
120649992Sbostic 	f *= 1024.0 * 1024.0;
120749992Sbostic 	break;
120849992Sbostic     case 's':
120949992Sbostic 	if (lp->limconst != RLIMIT_CPU)
121049992Sbostic 	    goto badscal;
121149992Sbostic 	limtail(cp, "seconds");
121249992Sbostic 	break;
121349992Sbostic     case 'M':
121449992Sbostic 	if (lp->limconst == RLIMIT_CPU)
121549992Sbostic 	    goto badscal;
121649992Sbostic 	*cp = 'm';
121749992Sbostic 	limtail(cp, "megabytes");
121849992Sbostic 	f *= 1024.0 * 1024.0;
121949992Sbostic 	break;
122049992Sbostic     case 'k':
122149992Sbostic 	if (lp->limconst == RLIMIT_CPU)
122249992Sbostic 	    goto badscal;
122349992Sbostic 	limtail(cp, "kbytes");
122449992Sbostic 	f *= 1024.0;
122549992Sbostic 	break;
122649992Sbostic     case 'u':
122749992Sbostic 	limtail(cp, "unlimited");
122849992Sbostic 	return (RLIM_INFINITY);
122949992Sbostic     default:
12301294Sbill badscal:
123149992Sbostic 	stderror(ERR_NAME | ERR_SCALEF);
123249992Sbostic     }
123350944Schristos     if ((f + 0.5) >= (float) 0x7fffffff || (f + 0.5) < (float) 0x80000000)
123450944Schristos 	stderror(ERR_NAME | ERR_SCALEF);
123549992Sbostic     return ((RLIM_TYPE) (f + 0.5));
12361294Sbill }
12371294Sbill 
123849992Sbostic static void
123949992Sbostic limtail(cp, str)
124049992Sbostic     Char   *cp;
124149992Sbostic     char   *str;
12421294Sbill {
124349992Sbostic     while (*cp && *cp == *str)
124449992Sbostic 	cp++, str++;
124549992Sbostic     if (*cp)
124649992Sbostic 	stderror(ERR_BADSCALE, str);
12471294Sbill }
12481294Sbill 
124949992Sbostic 
125049992Sbostic /*ARGSUSED*/
125149992Sbostic static void
125218539Sedward plim(lp, hard)
125349992Sbostic     register struct limits *lp;
125449992Sbostic     Char    hard;
12551294Sbill {
125649992Sbostic     struct rlimit rlim;
125749992Sbostic     RLIM_TYPE limit;
12581294Sbill 
125950439Schristos     (void) fprintf(cshout, "%s \t", lp->limname);
126049992Sbostic 
126149992Sbostic     (void) getrlimit(lp->limconst, &rlim);
126249992Sbostic     limit = hard ? rlim.rlim_max : rlim.rlim_cur;
126349992Sbostic 
126449992Sbostic     if (limit == RLIM_INFINITY)
126550439Schristos 	(void) fprintf(cshout, "unlimited");
126649992Sbostic     else if (lp->limconst == RLIMIT_CPU)
126749992Sbostic 	psecs((long) limit);
126849992Sbostic     else
126951437Sleres 	(void) fprintf(cshout, "%ld %s", (long) (limit / lp->limdiv),
127050439Schristos 		       lp->limscale);
127150439Schristos     (void) fputc('\n', cshout);
12721294Sbill }
12731294Sbill 
127449992Sbostic void
127550439Schristos /*ARGSUSED*/
127650439Schristos dounlimit(v, t)
127750439Schristos     Char **v;
127850439Schristos     struct command *t;
12791294Sbill {
128049992Sbostic     register struct limits *lp;
128149992Sbostic     int     lerr = 0;
128249992Sbostic     Char    hard = 0;
12831294Sbill 
128449992Sbostic     v++;
128549992Sbostic     if (*v && eq(*v, STRmh)) {
128649992Sbostic 	hard = 1;
12871294Sbill 	v++;
128849992Sbostic     }
128949992Sbostic     if (*v == 0) {
129049992Sbostic 	for (lp = limits; lp->limconst >= 0; lp++)
129149992Sbostic 	    if (setlim(lp, hard, (RLIM_TYPE) RLIM_INFINITY) < 0)
129249992Sbostic 		lerr++;
129349992Sbostic 	if (lerr)
129449992Sbostic 	    stderror(ERR_SILENT);
129549992Sbostic 	return;
129649992Sbostic     }
129749992Sbostic     while (*v) {
129849992Sbostic 	lp = findlim(*v++);
129949992Sbostic 	if (setlim(lp, hard, (RLIM_TYPE) RLIM_INFINITY) < 0)
130049992Sbostic 	    stderror(ERR_SILENT);
130149992Sbostic     }
13021294Sbill }
13031294Sbill 
130449992Sbostic static int
130518539Sedward setlim(lp, hard, limit)
130649992Sbostic     register struct limits *lp;
130749992Sbostic     Char    hard;
130849992Sbostic     RLIM_TYPE limit;
13091294Sbill {
131049992Sbostic     struct rlimit rlim;
13111294Sbill 
131249992Sbostic     (void) getrlimit(lp->limconst, &rlim);
131349992Sbostic 
131449992Sbostic     if (hard)
131549992Sbostic 	rlim.rlim_max = limit;
131649992Sbostic     else if (limit == RLIM_INFINITY && geteuid() != 0)
131749992Sbostic 	rlim.rlim_cur = rlim.rlim_max;
131849992Sbostic     else
131949992Sbostic 	rlim.rlim_cur = limit;
132049992Sbostic 
132149992Sbostic     if (setrlimit(lp->limconst, &rlim) < 0) {
132250439Schristos 	(void) fprintf(csherr, "%s: %s: Can't %s%s limit\n", bname, lp->limname,
132350439Schristos 		       limit == RLIM_INFINITY ? "remove" : "set",
132450439Schristos 		       hard ? " hard" : "");
132549992Sbostic 	return (-1);
132649992Sbostic     }
132749992Sbostic     return (0);
13281294Sbill }
13291294Sbill 
133049992Sbostic void
133150439Schristos /*ARGSUSED*/
133250439Schristos dosuspend(v, t)
133350439Schristos     Char **v;
133450439Schristos     struct command *t;
13351294Sbill {
133649992Sbostic     int     ctpgrp;
13371294Sbill 
133849992Sbostic     void    (*old) ();
133949992Sbostic 
134049992Sbostic     if (loginsh)
134149992Sbostic 	stderror(ERR_SUSPLOG);
134249992Sbostic     untty();
134349992Sbostic 
134449992Sbostic     old = signal(SIGTSTP, SIG_DFL);
134549992Sbostic     (void) kill(0, SIGTSTP);
134649992Sbostic     /* the shell stops here */
134749992Sbostic     (void) signal(SIGTSTP, old);
134849992Sbostic 
134949992Sbostic     if (tpgrp != -1) {
135049992Sbostic 	ctpgrp = tcgetpgrp(FSHTTY);
135150439Schristos 	while  (ctpgrp != opgrp) {
135249992Sbostic 	    old = signal(SIGTTIN, SIG_DFL);
135349992Sbostic 	    (void) kill(0, SIGTTIN);
135449992Sbostic 	    (void) signal(SIGTTIN, old);
13551294Sbill 	}
135649992Sbostic 	(void) setpgid(0, shpgrp);
135749992Sbostic 	(void) tcsetpgrp(FSHTTY, shpgrp);
135849992Sbostic     }
13591294Sbill }
13601294Sbill 
136149992Sbostic /* This is the dreaded EVAL built-in.
136249992Sbostic  *   If you don't fiddle with file descriptors, and reset didfds,
136349992Sbostic  *   this command will either ignore redirection inside or outside
136449992Sbostic  *   its aguments, e.g. eval "date >x"  vs.  eval "date" >x
136549992Sbostic  *   The stuff here seems to work, but I did it by trial and error rather
136649992Sbostic  *   than really knowing what was going on.  If tpgrp is zero, we are
136749992Sbostic  *   probably a background eval, e.g. "eval date &", and we want to
136849992Sbostic  *   make sure that any processes we start stay in our pgrp.
136949992Sbostic  *   This is also the case for "time eval date" -- stay in same pgrp.
137049992Sbostic  *   Otherwise, under stty tostop, processes will stop in the wrong
137149992Sbostic  *   pgrp, with no way for the shell to get them going again.  -IAN!
137249992Sbostic  */
137350439Schristos static Char **gv = NULL;
137449992Sbostic void
137550439Schristos /*ARGSUSED*/
137650439Schristos doeval(v, t)
137750439Schristos     Char **v;
137850439Schristos     struct command *t;
13791294Sbill {
138049992Sbostic     Char  **oevalvec;
138149992Sbostic     Char   *oevalp;
138249992Sbostic     int     odidfds;
138349992Sbostic     jmp_buf osetexit;
138449992Sbostic     int     my_reenter;
138550439Schristos     Char  **savegv = gv;
138649992Sbostic     int     saveIN;
138749992Sbostic     int     saveOUT;
138850439Schristos     int     saveERR;
138949992Sbostic     int     oSHIN;
139049992Sbostic     int     oSHOUT;
139150439Schristos     int     oSHERR;
13921294Sbill 
139349992Sbostic     oevalvec = evalvec;
139449992Sbostic     oevalp = evalp;
139549992Sbostic     odidfds = didfds;
139649992Sbostic     oSHIN = SHIN;
139749992Sbostic     oSHOUT = SHOUT;
139850439Schristos     oSHERR = SHERR;
139949992Sbostic 
140049992Sbostic     v++;
140149992Sbostic     if (*v == 0)
140249992Sbostic 	return;
140349992Sbostic     gflag = 0, tglob(v);
140449992Sbostic     if (gflag) {
140549992Sbostic 	gv = v = globall(v);
140649992Sbostic 	gargv = 0;
140749992Sbostic 	if (v == 0)
140849992Sbostic 	    stderror(ERR_NOMATCH);
140949992Sbostic 	v = copyblk(v);
141049992Sbostic     }
141149992Sbostic     else {
141250024Schristos 	gv = NULL;
141349992Sbostic 	v = copyblk(v);
141449992Sbostic 	trim(v);
141549992Sbostic     }
141649992Sbostic 
141749992Sbostic     saveIN = dcopy(SHIN, -1);
141849992Sbostic     saveOUT = dcopy(SHOUT, -1);
141950439Schristos     saveERR = dcopy(SHERR, -1);
142049992Sbostic 
142149992Sbostic     getexit(osetexit);
142249992Sbostic 
142349992Sbostic     if ((my_reenter = setexit()) == 0) {
142449992Sbostic 	evalvec = v;
142549992Sbostic 	evalp = 0;
142649992Sbostic 	SHIN = dcopy(0, -1);
142749992Sbostic 	SHOUT = dcopy(1, -1);
142850439Schristos 	SHERR = dcopy(2, -1);
142949992Sbostic 	didfds = 0;
143049992Sbostic 	process(0);
143149992Sbostic     }
143249992Sbostic 
143349992Sbostic     evalvec = oevalvec;
143449992Sbostic     evalp = oevalp;
143549992Sbostic     doneinp = 0;
143649992Sbostic     didfds = odidfds;
143749992Sbostic     (void) close(SHIN);
143849992Sbostic     (void) close(SHOUT);
143950439Schristos     (void) close(SHERR);
144049992Sbostic     SHIN = dmove(saveIN, oSHIN);
144149992Sbostic     SHOUT = dmove(saveOUT, oSHOUT);
144250439Schristos     SHERR = dmove(saveERR, oSHERR);
144349992Sbostic     if (gv)
144450439Schristos 	blkfree(gv), gv = NULL;
144549992Sbostic     resexit(osetexit);
144650439Schristos     gv = savegv;
144749992Sbostic     if (my_reenter)
144849992Sbostic 	stderror(ERR_SILENT);
14491294Sbill }
145050639Schristos 
145150639Schristos void
145250639Schristos /*ARGSUSED*/
145350639Schristos doprintf(v, t)
145450639Schristos     Char **v;
145550639Schristos     struct command *t;
145650639Schristos {
145750639Schristos     char **c;
145850639Schristos     extern int progprintf __P((int, char **));
145950639Schristos     int ret;
146051437Sleres 
146150639Schristos     ret = progprintf(blklen(v), c = short2blk(v));
146250639Schristos 
146350639Schristos     blkfree((Char **) c);
146450639Schristos     if (ret)
146550639Schristos 	stderror(ERR_SILENT);
146650639Schristos }
1467