xref: /csrg-svn/bin/csh/func.c (revision 17519)
1*17519Sedward #ifndef lint
2*17519Sedward static	char *sccsid = "@(#)func.c	4.13 (Berkeley) 12/13/84";
3*17519Sedward #endif
41294Sbill 
51294Sbill #include "sh.h"
61294Sbill #include <sys/ioctl.h>
71294Sbill 
81294Sbill /*
91294Sbill  * C shell
101294Sbill  */
111294Sbill 
121294Sbill struct biltins *
131294Sbill isbfunc(t)
14*17519Sedward 	struct command *t;
151294Sbill {
161294Sbill 	register char *cp = t->t_dcom[0];
17*17519Sedward 	register struct biltins *bp, *bp1, *bp2;
181294Sbill 	int dolabel(), dofg1(), dobg1();
191294Sbill 	static struct biltins label = { "", dolabel, 0, 0 };
201294Sbill 	static struct biltins foregnd = { "%job", dofg1, 0, 0 };
211294Sbill 	static struct biltins backgnd = { "%job &", dobg1, 0, 0 };
221294Sbill 
231294Sbill 	if (lastchr(cp) == ':') {
241294Sbill 		label.bname = cp;
251294Sbill 		return (&label);
261294Sbill 	}
271294Sbill 	if (*cp == '%') {
281294Sbill 		if (t->t_dflg & FAND) {
291294Sbill 			t->t_dflg &= ~FAND;
301294Sbill 			backgnd.bname = cp;
311294Sbill 			return (&backgnd);
32*17519Sedward 		}
331294Sbill 		foregnd.bname = cp;
341294Sbill 		return (&foregnd);
351294Sbill 	}
36*17519Sedward 	/*
37*17519Sedward 	 * Binary search
38*17519Sedward 	 * Bp1 is the beginning of the current search range.
39*17519Sedward 	 * Bp2 is one past the end.
40*17519Sedward 	 */
41*17519Sedward 	for (bp1 = bfunc, bp2 = bfunc + nbfunc; bp1 < bp2;) {
42*17519Sedward 		register i;
43*17519Sedward 
44*17519Sedward 		bp = bp1 + (bp2 - bp1 >> 1);
45*17519Sedward 		if ((i = *cp - *bp->bname) == 0 &&
46*17519Sedward 		    (i = strcmp(cp, bp->bname)) == 0)
47*17519Sedward 			return bp;
48*17519Sedward 		if (i < 0)
49*17519Sedward 			bp2 = bp;
50*17519Sedward 		else
51*17519Sedward 			bp1 = bp + 1;
521294Sbill 	}
531294Sbill 	return (0);
541294Sbill }
551294Sbill 
561294Sbill func(t, bp)
571294Sbill 	register struct command *t;
581294Sbill 	register struct biltins *bp;
591294Sbill {
601294Sbill 	int i;
611294Sbill 
621294Sbill 	xechoit(t->t_dcom);
631294Sbill 	setname(bp->bname);
641294Sbill 	i = blklen(t->t_dcom) - 1;
651294Sbill 	if (i < bp->minargs)
661294Sbill 		bferr("Too few arguments");
671294Sbill 	if (i > bp->maxargs)
681294Sbill 		bferr("Too many arguments");
691294Sbill 	(*bp->bfunct)(t->t_dcom, t);
701294Sbill }
711294Sbill 
721294Sbill dolabel()
731294Sbill {
741294Sbill 
751294Sbill }
761294Sbill 
771294Sbill doonintr(v)
781294Sbill 	char **v;
791294Sbill {
801294Sbill 	register char *cp;
811294Sbill 	register char *vv = v[1];
821294Sbill 
831294Sbill 	if (parintr == SIG_IGN)
841294Sbill 		return;
851294Sbill 	if (setintr && intty)
861294Sbill 		bferr("Can't from terminal");
871294Sbill 	cp = gointr, gointr = 0, xfree(cp);
881294Sbill 	if (vv == 0) {
891294Sbill 		if (setintr)
90*17519Sedward 			(void) sigblock(sigmask(SIGINT));
911294Sbill 		else
92*17519Sedward 			(void) signal(SIGINT, SIG_DFL);
931294Sbill 		gointr = 0;
941294Sbill 	} else if (eq((vv = strip(vv)), "-")) {
95*17519Sedward 		(void) signal(SIGINT, SIG_IGN);
961294Sbill 		gointr = "-";
971294Sbill 	} else {
981294Sbill 		gointr = savestr(vv);
99*17519Sedward 		(void) signal(SIGINT, pintr);
1001294Sbill 	}
1011294Sbill }
1021294Sbill 
1031294Sbill donohup()
1041294Sbill {
1051294Sbill 
1061294Sbill 	if (intty)
1071294Sbill 		bferr("Can't from terminal");
1081294Sbill 	if (setintr == 0) {
109*17519Sedward 		(void) signal(SIGHUP, SIG_IGN);
1101294Sbill #ifdef CC
1111294Sbill 		submit(getpid());
1121294Sbill #endif
1131294Sbill 	}
1141294Sbill }
1151294Sbill 
1161294Sbill dozip()
1171294Sbill {
1181294Sbill 
1191294Sbill 	;
1201294Sbill }
1211294Sbill 
1221294Sbill prvars()
1231294Sbill {
1241294Sbill 
1251294Sbill 	plist(&shvhed);
1261294Sbill }
1271294Sbill 
1281294Sbill doalias(v)
1291294Sbill 	register char **v;
1301294Sbill {
1311294Sbill 	register struct varent *vp;
1321294Sbill 	register char *p;
1331294Sbill 
1341294Sbill 	v++;
1351294Sbill 	p = *v++;
1361294Sbill 	if (p == 0)
1371294Sbill 		plist(&aliases);
1381294Sbill 	else if (*v == 0) {
1391294Sbill 		vp = adrof1(strip(p), &aliases);
1401294Sbill 		if (vp)
1411294Sbill 			blkpr(vp->vec), printf("\n");
1421294Sbill 	} else {
1431294Sbill 		if (eq(p, "alias") || eq(p, "unalias")) {
1441294Sbill 			setname(p);
1451294Sbill 			bferr("Too dangerous to alias that");
1461294Sbill 		}
1471294Sbill 		set1(strip(p), saveblk(v), &aliases);
1481294Sbill 	}
1491294Sbill }
1501294Sbill 
1511294Sbill unalias(v)
1521294Sbill 	char **v;
1531294Sbill {
1541294Sbill 
1551294Sbill 	unset1(v, &aliases);
1561294Sbill }
1571294Sbill 
1581294Sbill dologout()
1591294Sbill {
1601294Sbill 
1611294Sbill 	islogin();
1621294Sbill 	goodbye();
1631294Sbill }
1641294Sbill 
1651294Sbill dologin(v)
1661294Sbill 	char **v;
1671294Sbill {
1681294Sbill 
1691294Sbill 	islogin();
1704189Smckusic 	rechist();
171*17519Sedward 	(void) signal(SIGTERM, parterm);
1721294Sbill 	execl("/bin/login", "login", v[1], 0);
1731294Sbill 	untty();
1741294Sbill 	exit(1);
1751294Sbill }
1761294Sbill 
17712996Ssam #ifdef NEWGRP
1781294Sbill donewgrp(v)
1791294Sbill 	char **v;
1801294Sbill {
1811294Sbill 
1823908Sroot 	if (chkstop == 0 && setintr)
1833908Sroot 		panystop(0);
184*17519Sedward 	(void) signal(SIGTERM, parterm);
1851294Sbill 	execl("/bin/newgrp", "newgrp", v[1], 0);
1861294Sbill 	execl("/usr/bin/newgrp", "newgrp", v[1], 0);
1871294Sbill 	untty();
1881294Sbill 	exit(1);
1891294Sbill }
19012996Ssam #endif
1911294Sbill 
1921294Sbill islogin()
1931294Sbill {
1941294Sbill 
1951294Sbill 	if (chkstop == 0 && setintr)
1961294Sbill 		panystop(0);
1971294Sbill 	if (loginsh)
1981294Sbill 		return;
1991294Sbill 	error("Not login shell");
2001294Sbill }
2011294Sbill 
2021294Sbill doif(v, kp)
2031294Sbill 	char **v;
2041294Sbill 	struct command *kp;
2051294Sbill {
2061294Sbill 	register int i;
2071294Sbill 	register char **vv;
2081294Sbill 
2091294Sbill 	v++;
2101294Sbill 	i = exp(&v);
2111294Sbill 	vv = v;
2121294Sbill 	if (*vv == NOSTR)
2131294Sbill 		bferr("Empty if");
2141294Sbill 	if (eq(*vv, "then")) {
2151294Sbill 		if (*++vv)
2161294Sbill 			bferr("Improper then");
2171294Sbill 		setname("then");
2181294Sbill 		/*
2191294Sbill 		 * If expression was zero, then scan to else,
2201294Sbill 		 * otherwise just fall into following code.
2211294Sbill 		 */
2221294Sbill 		if (!i)
2231294Sbill 			search(ZIF, 0);
2241294Sbill 		return;
2251294Sbill 	}
2261294Sbill 	/*
2271294Sbill 	 * Simple command attached to this if.
2281294Sbill 	 * Left shift the node in this tree, munging it
2291294Sbill 	 * so we can reexecute it.
2301294Sbill 	 */
2311294Sbill 	if (i) {
2321294Sbill 		lshift(kp->t_dcom, vv - kp->t_dcom);
2331294Sbill 		reexecute(kp);
2341294Sbill 		donefds();
2351294Sbill 	}
2361294Sbill }
2371294Sbill 
2381294Sbill /*
2391294Sbill  * Reexecute a command, being careful not
2401294Sbill  * to redo i/o redirection, which is already set up.
2411294Sbill  */
2421294Sbill reexecute(kp)
2431294Sbill 	register struct command *kp;
2441294Sbill {
2451294Sbill 
2461294Sbill 	kp->t_dflg &= FSAVE;
2471294Sbill 	kp->t_dflg |= FREDO;
2481294Sbill 	/*
2491294Sbill 	 * If tty is still ours to arbitrate, arbitrate it;
2501294Sbill 	 * otherwise dont even set pgrp's as the jobs would
2511294Sbill 	 * then have no way to get the tty (we can't give it
2521294Sbill 	 * to them, and our parent wouldn't know their pgrp, etc.
2531294Sbill 	 */
2541294Sbill 	execute(kp, tpgrp > 0 ? tpgrp : -1);
2551294Sbill }
2561294Sbill 
2571294Sbill doelse()
2581294Sbill {
2591294Sbill 
2601294Sbill 	search(ZELSE, 0);
2611294Sbill }
2621294Sbill 
2631294Sbill dogoto(v)
2641294Sbill 	char **v;
2651294Sbill {
2661294Sbill 	register struct whyle *wp;
2671294Sbill 	char *lp;
2681294Sbill 
2691294Sbill 	/*
2701294Sbill 	 * While we still can, locate any unknown ends of existing loops.
2711294Sbill 	 * This obscure code is the WORST result of the fact that we
2721294Sbill 	 * don't really parse.
2731294Sbill 	 */
2741294Sbill 	for (wp = whyles; wp; wp = wp->w_next)
2751294Sbill 		if (wp->w_end == 0) {
2761294Sbill 			search(ZBREAK, 0);
2771294Sbill 			wp->w_end = btell();
2781294Sbill 		} else
2791294Sbill 			bseek(wp->w_end);
2801294Sbill 	search(ZGOTO, 0, lp = globone(v[1]));
2811294Sbill 	xfree(lp);
2821294Sbill 	/*
2831294Sbill 	 * Eliminate loops which were exited.
2841294Sbill 	 */
2851294Sbill 	wfree();
2861294Sbill }
2871294Sbill 
2881294Sbill doswitch(v)
2891294Sbill 	register char **v;
2901294Sbill {
2911294Sbill 	register char *cp, *lp;
2921294Sbill 
2931294Sbill 	v++;
2941294Sbill 	if (!*v || *(*v++) != '(')
2951294Sbill 		goto syntax;
2961294Sbill 	cp = **v == ')' ? "" : *v++;
2971294Sbill 	if (*(*v++) != ')')
2981294Sbill 		v--;
2991294Sbill 	if (*v)
3001294Sbill syntax:
3011294Sbill 		error("Syntax error");
3021294Sbill 	search(ZSWITCH, 0, lp = globone(cp));
3031294Sbill 	xfree(lp);
3041294Sbill }
3051294Sbill 
3061294Sbill dobreak()
3071294Sbill {
3081294Sbill 
3091294Sbill 	if (whyles)
3101294Sbill 		toend();
3111294Sbill 	else
3121294Sbill 		bferr("Not in while/foreach");
3131294Sbill }
3141294Sbill 
3151294Sbill doexit(v)
3161294Sbill 	char **v;
3171294Sbill {
3181294Sbill 
3191294Sbill 	if (chkstop == 0)
3201294Sbill 		panystop(0);
3211294Sbill 	/*
3221294Sbill 	 * Don't DEMAND parentheses here either.
3231294Sbill 	 */
3241294Sbill 	v++;
3251294Sbill 	if (*v) {
3261294Sbill 		set("status", putn(exp(&v)));
3271294Sbill 		if (*v)
3281294Sbill 			bferr("Expression syntax");
3291294Sbill 	}
3301294Sbill 	btoeof();
3311294Sbill 	if (intty)
332*17519Sedward 		(void) close(SHIN);
3331294Sbill }
3341294Sbill 
3351294Sbill doforeach(v)
3361294Sbill 	register char **v;
3371294Sbill {
3381294Sbill 	register char *cp;
3391294Sbill 	register struct whyle *nwp;
3401294Sbill 
3411294Sbill 	v++;
3421294Sbill 	cp = strip(*v);
3431294Sbill 	while (*cp && letter(*cp))
3441294Sbill 		cp++;
3451294Sbill 	if (*cp || strlen(*v) >= 20)
3461294Sbill 		bferr("Invalid variable");
3471294Sbill 	cp = *v++;
3481294Sbill 	if (v[0][0] != '(' || v[blklen(v) - 1][0] != ')')
3491294Sbill 		bferr("Words not ()'ed");
3501294Sbill 	v++;
351*17519Sedward 	gflag = 0, tglob(v);
3521294Sbill 	v = glob(v);
3531294Sbill 	if (v == 0)
3541294Sbill 		bferr("No match");
3551294Sbill 	nwp = (struct whyle *) calloc(1, sizeof *nwp);
3561294Sbill 	nwp->w_fe = nwp->w_fe0 = v; gargv = 0;
3571294Sbill 	nwp->w_start = btell();
3581294Sbill 	nwp->w_fename = savestr(cp);
3591294Sbill 	nwp->w_next = whyles;
3601294Sbill 	whyles = nwp;
3611294Sbill 	/*
3621294Sbill 	 * Pre-read the loop so as to be more
3631294Sbill 	 * comprehensible to a terminal user.
3641294Sbill 	 */
3651294Sbill 	if (intty)
3661294Sbill 		preread();
3671294Sbill 	doagain();
3681294Sbill }
3691294Sbill 
3701294Sbill dowhile(v)
3711294Sbill 	char **v;
3721294Sbill {
3731294Sbill 	register int status;
3741294Sbill 	register bool again = whyles != 0 && whyles->w_start == lineloc &&
3751294Sbill 	    whyles->w_fename == 0;
3761294Sbill 
3771294Sbill 	v++;
3781294Sbill 	/*
3791294Sbill 	 * Implement prereading here also, taking care not to
3801294Sbill 	 * evaluate the expression before the loop has been read up
3811294Sbill 	 * from a terminal.
3821294Sbill 	 */
3831294Sbill 	if (intty && !again)
3841294Sbill 		status = !exp0(&v, 1);
3851294Sbill 	else
3861294Sbill 		status = !exp(&v);
3871294Sbill 	if (*v)
3881294Sbill 		bferr("Expression syntax");
3891294Sbill 	if (!again) {
3901294Sbill 		register struct whyle *nwp = (struct whyle *) calloc(1, sizeof (*nwp));
3911294Sbill 
3921294Sbill 		nwp->w_start = lineloc;
3931294Sbill 		nwp->w_end = 0;
3941294Sbill 		nwp->w_next = whyles;
3951294Sbill 		whyles = nwp;
3961294Sbill 		if (intty) {
3971294Sbill 			/*
3981294Sbill 			 * The tty preread
3991294Sbill 			 */
4001294Sbill 			preread();
4011294Sbill 			doagain();
4021294Sbill 			return;
4031294Sbill 		}
4041294Sbill 	}
4051294Sbill 	if (status)
4061294Sbill 		/* We ain't gonna loop no more, no more! */
4071294Sbill 		toend();
4081294Sbill }
4091294Sbill 
4101294Sbill preread()
4111294Sbill {
4121294Sbill 
4131294Sbill 	whyles->w_end = -1;
4141294Sbill 	if (setintr)
415*17519Sedward 		(void) sigsetmask(sigblock(0) & ~sigmask(SIGINT));
4161294Sbill 	search(ZBREAK, 0);
4171294Sbill 	if (setintr)
418*17519Sedward 		(void) sigblock(sigmask(SIGINT));
4191294Sbill 	whyles->w_end = btell();
4201294Sbill }
4211294Sbill 
4221294Sbill doend()
4231294Sbill {
4241294Sbill 
4251294Sbill 	if (!whyles)
4261294Sbill 		bferr("Not in while/foreach");
4271294Sbill 	whyles->w_end = btell();
4281294Sbill 	doagain();
4291294Sbill }
4301294Sbill 
4311294Sbill docontin()
4321294Sbill {
4331294Sbill 
4341294Sbill 	if (!whyles)
4351294Sbill 		bferr("Not in while/foreach");
4361294Sbill 	doagain();
4371294Sbill }
4381294Sbill 
4391294Sbill doagain()
4401294Sbill {
4411294Sbill 
4421294Sbill 	/* Repeating a while is simple */
4431294Sbill 	if (whyles->w_fename == 0) {
4441294Sbill 		bseek(whyles->w_start);
4451294Sbill 		return;
4461294Sbill 	}
4471294Sbill 	/*
4481294Sbill 	 * The foreach variable list actually has a spurious word
4491294Sbill 	 * ")" at the end of the w_fe list.  Thus we are at the
4501294Sbill 	 * of the list if one word beyond this is 0.
4511294Sbill 	 */
4521294Sbill 	if (!whyles->w_fe[1]) {
4531294Sbill 		dobreak();
4541294Sbill 		return;
4551294Sbill 	}
4561294Sbill 	set(whyles->w_fename, savestr(*whyles->w_fe++));
4571294Sbill 	bseek(whyles->w_start);
4581294Sbill }
4591294Sbill 
4601294Sbill dorepeat(v, kp)
4611294Sbill 	char **v;
4621294Sbill 	struct command *kp;
4631294Sbill {
46417138Sralph 	register int i, omask;
4651294Sbill 
4661294Sbill 	i = getn(v[1]);
4671294Sbill 	if (setintr)
46817138Sralph 		omask = sigblock(sigmask(SIGINT)) & ~sigmask(SIGINT);
4691294Sbill 	lshift(v, 2);
4701294Sbill 	while (i > 0) {
4711294Sbill 		if (setintr)
472*17519Sedward 			(void) sigsetmask(omask);
4731294Sbill 		reexecute(kp);
4741294Sbill 		--i;
4751294Sbill 	}
4761294Sbill 	donefds();
4771294Sbill 	if (setintr)
478*17519Sedward 		(void) sigsetmask(omask);
4791294Sbill }
4801294Sbill 
4811294Sbill doswbrk()
4821294Sbill {
4831294Sbill 
4841294Sbill 	search(ZBRKSW, 0);
4851294Sbill }
4861294Sbill 
4871294Sbill srchx(cp)
4881294Sbill 	register char *cp;
4891294Sbill {
490*17519Sedward 	register struct srch *sp, *sp1, *sp2;
491*17519Sedward 	register i;
4921294Sbill 
493*17519Sedward 	/*
494*17519Sedward 	 * Binary search
495*17519Sedward 	 * Sp1 is the beginning of the current search range.
496*17519Sedward 	 * Sp2 is one past the end.
497*17519Sedward 	 */
498*17519Sedward 	for (sp1 = srchn, sp2 = srchn + nsrchn; sp1 < sp2;) {
499*17519Sedward 		sp = sp1 + (sp2 - sp1 >> 1);
500*17519Sedward 		if ((i = *cp - *sp->s_name) == 0 &&
501*17519Sedward 		    (i = strcmp(cp, sp->s_name)) == 0)
502*17519Sedward 			return sp->s_value;
503*17519Sedward 		if (i < 0)
504*17519Sedward 			sp2 = sp;
505*17519Sedward 		else
506*17519Sedward 			sp1 = sp + 1;
507*17519Sedward 	}
5081294Sbill 	return (-1);
5091294Sbill }
5101294Sbill 
5111294Sbill char	Stype;
5121294Sbill char	*Sgoal;
5131294Sbill 
5141294Sbill /*VARARGS2*/
5151294Sbill search(type, level, goal)
5161294Sbill 	int type;
5171294Sbill 	register int level;
5181294Sbill 	char *goal;
5191294Sbill {
5201294Sbill 	char wordbuf[BUFSIZ];
5211294Sbill 	register char *aword = wordbuf;
5221294Sbill 	register char *cp;
5231294Sbill 
5241294Sbill 	Stype = type; Sgoal = goal;
5251294Sbill 	if (type == ZGOTO)
526*17519Sedward 		bseek((off_t)0);
5271294Sbill 	do {
5281294Sbill 		if (intty && fseekp == feobp)
5291294Sbill 			printf("? "), flush();
530*17519Sedward 		aword[0] = 0;
531*17519Sedward 		(void) getword(aword);
5321294Sbill 		switch (srchx(aword)) {
5331294Sbill 
5341294Sbill 		case ZELSE:
5351294Sbill 			if (level == 0 && type == ZIF)
5361294Sbill 				return;
5371294Sbill 			break;
5381294Sbill 
5391294Sbill 		case ZIF:
5401294Sbill 			while (getword(aword))
5411294Sbill 				continue;
5421294Sbill 			if ((type == ZIF || type == ZELSE) && eq(aword, "then"))
5431294Sbill 				level++;
5441294Sbill 			break;
5451294Sbill 
5461294Sbill 		case ZENDIF:
5471294Sbill 			if (type == ZIF || type == ZELSE)
5481294Sbill 				level--;
5491294Sbill 			break;
5501294Sbill 
5511294Sbill 		case ZFOREACH:
5521294Sbill 		case ZWHILE:
5531294Sbill 			if (type == ZBREAK)
5541294Sbill 				level++;
5551294Sbill 			break;
5561294Sbill 
5571294Sbill 		case ZEND:
5581294Sbill 			if (type == ZBREAK)
5591294Sbill 				level--;
5601294Sbill 			break;
5611294Sbill 
5621294Sbill 		case ZSWITCH:
5631294Sbill 			if (type == ZSWITCH || type == ZBRKSW)
5641294Sbill 				level++;
5651294Sbill 			break;
5661294Sbill 
5671294Sbill 		case ZENDSW:
5681294Sbill 			if (type == ZSWITCH || type == ZBRKSW)
5691294Sbill 				level--;
5701294Sbill 			break;
5711294Sbill 
5721294Sbill 		case ZLABEL:
5731294Sbill 			if (type == ZGOTO && getword(aword) && eq(aword, goal))
5741294Sbill 				level = -1;
5751294Sbill 			break;
5761294Sbill 
5771294Sbill 		default:
5781294Sbill 			if (type != ZGOTO && (type != ZSWITCH || level != 0))
5791294Sbill 				break;
5801294Sbill 			if (lastchr(aword) != ':')
5811294Sbill 				break;
5821294Sbill 			aword[strlen(aword) - 1] = 0;
5831294Sbill 			if (type == ZGOTO && eq(aword, goal) || type == ZSWITCH && eq(aword, "default"))
5841294Sbill 				level = -1;
5851294Sbill 			break;
5861294Sbill 
5871294Sbill 		case ZCASE:
5881294Sbill 			if (type != ZSWITCH || level != 0)
5891294Sbill 				break;
590*17519Sedward 			(void) getword(aword);
5911294Sbill 			if (lastchr(aword) == ':')
5921294Sbill 				aword[strlen(aword) - 1] = 0;
5931294Sbill 			cp = strip(Dfix1(aword));
5941294Sbill 			if (Gmatch(goal, cp))
5951294Sbill 				level = -1;
5961294Sbill 			xfree(cp);
5971294Sbill 			break;
5981294Sbill 
5991294Sbill 		case ZDEFAULT:
6001294Sbill 			if (type == ZSWITCH && level == 0)
6011294Sbill 				level = -1;
6021294Sbill 			break;
6031294Sbill 		}
604*17519Sedward 		(void) getword(NOSTR);
6051294Sbill 	} while (level >= 0);
6061294Sbill }
6071294Sbill 
6081294Sbill getword(wp)
6091294Sbill 	register char *wp;
6101294Sbill {
6111294Sbill 	register int found = 0;
6121294Sbill 	register int c, d;
6131294Sbill 
6141294Sbill 	c = readc(1);
6151294Sbill 	d = 0;
6161294Sbill 	do {
6171294Sbill 		while (c == ' ' || c == '\t')
6181294Sbill 			c = readc(1);
6193798Sroot 		if (c == '#')
6203798Sroot 			do
6213798Sroot 				c = readc(1);
6223798Sroot 			while (c >= 0 && c != '\n');
6231294Sbill 		if (c < 0)
6241294Sbill 			goto past;
6251294Sbill 		if (c == '\n') {
6261294Sbill 			if (wp)
6271294Sbill 				break;
6281294Sbill 			return (0);
6291294Sbill 		}
6301294Sbill 		unreadc(c);
6311294Sbill 		found = 1;
6321294Sbill 		do {
6331294Sbill 			c = readc(1);
6341294Sbill 			if (c == '\\' && (c = readc(1)) == '\n')
6351294Sbill 				c = ' ';
636*17519Sedward 			if (c == '\'' || c == '"')
6371294Sbill 				if (d == 0)
6381294Sbill 					d = c;
6391294Sbill 				else if (d == c)
6401294Sbill 					d = 0;
6411294Sbill 			if (c < 0)
6421294Sbill 				goto past;
6431294Sbill 			if (wp)
6441294Sbill 				*wp++ = c;
6451294Sbill 		} while ((d || c != ' ' && c != '\t') && c != '\n');
6461294Sbill 	} while (wp == 0);
6471294Sbill 	unreadc(c);
6481294Sbill 	if (found)
6491294Sbill 		*--wp = 0;
6501294Sbill 	return (found);
6511294Sbill 
6521294Sbill past:
6531294Sbill 	switch (Stype) {
6541294Sbill 
6551294Sbill 	case ZIF:
6561294Sbill 		bferr("then/endif not found");
6571294Sbill 
6581294Sbill 	case ZELSE:
6591294Sbill 		bferr("endif not found");
6601294Sbill 
6611294Sbill 	case ZBRKSW:
6621294Sbill 	case ZSWITCH:
6631294Sbill 		bferr("endsw not found");
6641294Sbill 
6651294Sbill 	case ZBREAK:
6661294Sbill 		bferr("end not found");
6671294Sbill 
6681294Sbill 	case ZGOTO:
6691294Sbill 		setname(Sgoal);
6701294Sbill 		bferr("label not found");
6711294Sbill 	}
6721294Sbill 	/*NOTREACHED*/
6731294Sbill }
6741294Sbill 
6751294Sbill toend()
6761294Sbill {
6771294Sbill 
6781294Sbill 	if (whyles->w_end == 0) {
6791294Sbill 		search(ZBREAK, 0);
6801294Sbill 		whyles->w_end = btell() - 1;
6811294Sbill 	} else
6821294Sbill 		bseek(whyles->w_end);
6831294Sbill 	wfree();
6841294Sbill }
6851294Sbill 
6861294Sbill wfree()
6871294Sbill {
6881294Sbill 	long o = btell();
6891294Sbill 
6901294Sbill 	while (whyles) {
6911294Sbill 		register struct whyle *wp = whyles;
6921294Sbill 		register struct whyle *nwp = wp->w_next;
6931294Sbill 
6941294Sbill 		if (o >= wp->w_start && (wp->w_end == 0 || o < wp->w_end))
6951294Sbill 			break;
6961294Sbill 		if (wp->w_fe0)
6971294Sbill 			blkfree(wp->w_fe0);
6981294Sbill 		if (wp->w_fename)
6991294Sbill 			xfree(wp->w_fename);
7001294Sbill 		xfree((char *)wp);
7011294Sbill 		whyles = nwp;
7021294Sbill 	}
7031294Sbill }
7041294Sbill 
7051294Sbill doecho(v)
7061294Sbill 	char **v;
7071294Sbill {
7081294Sbill 
7091294Sbill 	echo(' ', v);
7101294Sbill }
7111294Sbill 
7121294Sbill doglob(v)
7131294Sbill 	char **v;
7141294Sbill {
7151294Sbill 
7161294Sbill 	echo(0, v);
7171294Sbill 	flush();
7181294Sbill }
7191294Sbill 
7201294Sbill echo(sep, v)
7211294Sbill 	char sep;
7221294Sbill 	register char **v;
7231294Sbill {
7241294Sbill 	register char *cp;
7251294Sbill 	int nonl = 0;
7261294Sbill 
7271294Sbill 	if (setintr)
728*17519Sedward 		(void) sigsetmask(sigblock(0) & ~sigmask(SIGINT));
7291294Sbill 	v++;
7301294Sbill 	if (*v == 0)
7311294Sbill 		return;
732*17519Sedward 	gflag = 0, tglob(v);
7331294Sbill 	if (gflag) {
7341294Sbill 		v = glob(v);
7351294Sbill 		if (v == 0)
7361294Sbill 			bferr("No match");
7371294Sbill 	} else
738*17519Sedward 		trim(v);
7391294Sbill 	if (sep == ' ' && !strcmp(*v, "-n"))
7401294Sbill 		nonl++, v++;
7411294Sbill 	while (cp = *v++) {
7421294Sbill 		register int c;
7431294Sbill 
7441294Sbill 		while (c = *cp++)
7451294Sbill 			putchar(c | QUOTE);
7461294Sbill 		if (*v)
7471294Sbill 			putchar(sep | QUOTE);
7481294Sbill 	}
7491294Sbill 	if (sep && nonl == 0)
7501294Sbill 		putchar('\n');
7511294Sbill 	else
7521294Sbill 		flush();
7531294Sbill 	if (setintr)
754*17519Sedward 		(void) sigblock(sigmask(SIGINT));
7551294Sbill 	if (gargv)
7561294Sbill 		blkfree(gargv), gargv = 0;
7571294Sbill }
7581294Sbill 
7591294Sbill char	**environ;
7601294Sbill 
7611294Sbill dosetenv(v)
7621294Sbill 	register char **v;
7631294Sbill {
7641294Sbill 	char *lp = globone(v[2]);
7651294Sbill 
7661294Sbill 	setenv(v[1], lp);
7671294Sbill 	if (eq(v[1], "PATH")) {
7681294Sbill 		importpath(lp);
7691294Sbill 		dohash();
7701294Sbill 	}
7711294Sbill 	xfree(lp);
7721294Sbill }
7731294Sbill 
7741294Sbill dounsetenv(v)
7751294Sbill 	register char **v;
7761294Sbill {
7771294Sbill 
7781294Sbill 	v++;
7791294Sbill 	do
7801294Sbill 		unsetenv(*v++);
7811294Sbill 	while (*v);
7821294Sbill }
7831294Sbill 
784*17519Sedward setenv(name, val)
785*17519Sedward 	char *name, *val;
7861294Sbill {
7871294Sbill 	register char **ep = environ;
7881294Sbill 	register char *cp, *dp;
7891294Sbill 	char *blk[2], **oep = ep;
7901294Sbill 
7911294Sbill 	for (; *ep; ep++) {
7921294Sbill 		for (cp = name, dp = *ep; *cp && *cp == *dp; cp++, dp++)
7931294Sbill 			continue;
7941294Sbill 		if (*cp != 0 || *dp != '=')
7951294Sbill 			continue;
796*17519Sedward 		cp = strspl("=", val);
7971294Sbill 		xfree(*ep);
7981294Sbill 		*ep = strspl(name, cp);
7991294Sbill 		xfree(cp);
800*17519Sedward 		trim(ep);
8011294Sbill 		return;
8021294Sbill 	}
8031294Sbill 	blk[0] = strspl(name, "="); blk[1] = 0;
8041294Sbill 	environ = blkspl(environ, blk);
8051294Sbill 	xfree((char *)oep);
806*17519Sedward 	setenv(name, val);
8071294Sbill }
8081294Sbill 
8091294Sbill unsetenv(name)
8101294Sbill 	char *name;
8111294Sbill {
8121294Sbill 	register char **ep = environ;
8131294Sbill 	register char *cp, *dp;
8141294Sbill 	char **oep = ep;
8151294Sbill 
8161294Sbill 	for (; *ep; ep++) {
8171294Sbill 		for (cp = name, dp = *ep; *cp && *cp == *dp; cp++, dp++)
8181294Sbill 			continue;
8191294Sbill 		if (*cp != 0 || *dp != '=')
8201294Sbill 			continue;
8211294Sbill 		cp = *ep;
8221294Sbill 		*ep = 0;
8231294Sbill 		environ = blkspl(environ, ep+1);
8241294Sbill 		*ep = cp;
8251294Sbill 		xfree(cp);
8261294Sbill 		xfree((char *)oep);
8271294Sbill 		return;
8281294Sbill 	}
8291294Sbill }
8301294Sbill 
8311294Sbill doumask(v)
8321294Sbill 	register char **v;
8331294Sbill {
8341294Sbill 	register char *cp = v[1];
8351294Sbill 	register int i;
8361294Sbill 
8371294Sbill 	if (cp == 0) {
8381294Sbill 		i = umask(0);
839*17519Sedward 		(void) umask(i);
8401294Sbill 		printf("%o\n", i);
8411294Sbill 		return;
8421294Sbill 	}
8431294Sbill 	i = 0;
8441294Sbill 	while (digit(*cp) && *cp != '8' && *cp != '9')
8451294Sbill 		i = i * 8 + *cp++ - '0';
8461294Sbill 	if (*cp || i < 0 || i > 0777)
8471294Sbill 		bferr("Improper mask");
848*17519Sedward 	(void) umask(i);
8491294Sbill }
8501294Sbill 
8511294Sbill 
8521294Sbill struct limits {
8531294Sbill 	int	limconst;
8541294Sbill 	char	*limname;
8551294Sbill 	int	limdiv;
8561294Sbill 	char	*limscale;
8571294Sbill } limits[] = {
85810032Ssam 	RLIMIT_CPU,	"cputime",	1,	"seconds",
85910032Ssam 	RLIMIT_FSIZE,	"filesize",	1024,	"kbytes",
86010032Ssam 	RLIMIT_DATA,	"datasize",	1024,	"kbytes",
86110032Ssam 	RLIMIT_STACK,	"stacksize",	1024,	"kbytes",
86210032Ssam 	RLIMIT_CORE,	"coredumpsize",	1024,	"kbytes",
86310032Ssam 	RLIMIT_RSS,	"memoryuse",	1024,	"kbytes",
8641294Sbill 	-1,		0,
8651294Sbill };
8661294Sbill 
8671294Sbill struct limits *
8681294Sbill findlim(cp)
8691294Sbill 	char *cp;
8701294Sbill {
8711294Sbill 	register struct limits *lp, *res;
8721294Sbill 
8731294Sbill 	res = 0;
8741294Sbill 	for (lp = limits; lp->limconst >= 0; lp++)
8751294Sbill 		if (prefix(cp, lp->limname)) {
8761294Sbill 			if (res)
8771294Sbill 				bferr("Ambiguous");
8781294Sbill 			res = lp;
8791294Sbill 		}
8801294Sbill 	if (res)
8811294Sbill 		return (res);
8821294Sbill 	bferr("No such limit");
883*17519Sedward 	/*NOTREACHED*/
8841294Sbill }
8851294Sbill 
8861294Sbill dolimit(v)
8871294Sbill 	register char **v;
8881294Sbill {
8891294Sbill 	register struct limits *lp;
8901294Sbill 	register int limit;
8911294Sbill 
8921294Sbill 	v++;
8931294Sbill 	if (*v == 0) {
8941294Sbill 		for (lp = limits+1; lp->limconst >= 0; lp++)
8951294Sbill 			plim(lp);
8961294Sbill 		return;
8971294Sbill 	}
8981294Sbill 	lp = findlim(v[0]);
8991294Sbill 	if (v[1] == 0) {
9001294Sbill 		plim(lp);
9011294Sbill 		return;
9021294Sbill 	}
9031294Sbill 	limit = getval(lp, v+1);
9041294Sbill 	setlim(lp, limit);
9051294Sbill }
9061294Sbill 
9071294Sbill getval(lp, v)
9081294Sbill 	register struct limits *lp;
9091294Sbill 	char **v;
9101294Sbill {
9111294Sbill 	register float f;
9121294Sbill 	double atof();
9131294Sbill 	char *cp = *v++;
9141294Sbill 
9151294Sbill 	f = atof(cp);
9161294Sbill 	while (digit(*cp) || *cp == '.' || *cp == 'e' || *cp == 'E')
9171294Sbill 		cp++;
9181294Sbill 	if (*cp == 0) {
9191294Sbill 		if (*v == 0)
9201294Sbill 			return ((int)(f+0.5) * lp->limdiv);
9211294Sbill 		cp = *v;
9221294Sbill 	}
9231294Sbill 	switch (*cp) {
9241294Sbill 
9251294Sbill 	case ':':
92610032Ssam 		if (lp->limconst != RLIMIT_CPU)
9271294Sbill 			goto badscal;
9281294Sbill 		return ((int)(f * 60.0 + atof(cp+1)));
9291294Sbill 
9301294Sbill 	case 'h':
93110032Ssam 		if (lp->limconst != RLIMIT_CPU)
9321294Sbill 			goto badscal;
9331294Sbill 		limtail(cp, "hours");
9341294Sbill 		f *= 3600.;
9351294Sbill 		break;
9361294Sbill 
9371294Sbill 	case 'm':
93810032Ssam 		if (lp->limconst == RLIMIT_CPU) {
9391294Sbill 			limtail(cp, "minutes");
9401294Sbill 			f *= 60.;
9411294Sbill 			break;
9421294Sbill 		}
9431294Sbill 	case 'M':
94410032Ssam 		if (lp->limconst == RLIMIT_CPU)
9451294Sbill 			goto badscal;
9461294Sbill 		*cp = 'm';
9471294Sbill 		limtail(cp, "megabytes");
9481294Sbill 		f *= 1024.*1024.;
9491294Sbill 		break;
9501294Sbill 
9511294Sbill 	case 's':
95210032Ssam 		if (lp->limconst != RLIMIT_CPU)
9531294Sbill 			goto badscal;
9541294Sbill 		limtail(cp, "seconds");
9551294Sbill 		break;
9561294Sbill 
9571294Sbill 	case 'k':
95810032Ssam 		if (lp->limconst == RLIMIT_CPU)
9591294Sbill 			goto badscal;
9601294Sbill 		limtail(cp, "kbytes");
9611294Sbill 		f *= 1024;
9621294Sbill 		break;
9631294Sbill 
9641294Sbill 	case 'u':
9651294Sbill 		limtail(cp, "unlimited");
96610032Ssam 		return (RLIM_INFINITY);
9671294Sbill 
9681294Sbill 	default:
9691294Sbill badscal:
9701294Sbill 		bferr("Improper or unknown scale factor");
9711294Sbill 	}
9721294Sbill 	return ((int)(f+0.5));
9731294Sbill }
9741294Sbill 
9751294Sbill limtail(cp, str0)
9761294Sbill 	char *cp, *str0;
9771294Sbill {
9781294Sbill 	register char *str = str0;
9791294Sbill 
9801294Sbill 	while (*cp && *cp == *str)
9811294Sbill 		cp++, str++;
9821294Sbill 	if (*cp)
9831294Sbill 		error("Bad scaling; did you mean ``%s''?", str0);
9841294Sbill }
9851294Sbill 
9861294Sbill plim(lp)
9871294Sbill 	register struct limits *lp;
9881294Sbill {
98910032Ssam 	struct rlimit rlim;
9901294Sbill 
9911294Sbill 	printf("%s \t", lp->limname);
992*17519Sedward 	(void) getrlimit(lp->limconst, &rlim);
99310032Ssam 	if (rlim.rlim_cur == RLIM_INFINITY)
9941294Sbill 		printf("unlimited");
99510032Ssam 	else if (lp->limconst == RLIMIT_CPU)
99610032Ssam 		psecs((long)rlim.rlim_cur);
9971294Sbill 	else
99810032Ssam 		printf("%d %s", rlim.rlim_cur / lp->limdiv, lp->limscale);
9991294Sbill 	printf("\n");
10001294Sbill }
10011294Sbill 
10021294Sbill dounlimit(v)
10031294Sbill 	register char **v;
10041294Sbill {
10051294Sbill 	register struct limits *lp;
10061294Sbill 
10071294Sbill 	v++;
10081294Sbill 	if (*v == 0) {
10091294Sbill 		for (lp = limits+1; lp->limconst >= 0; lp++)
1010*17519Sedward 			setlim(lp, (int)RLIM_INFINITY);
10111294Sbill 		return;
10121294Sbill 	}
10131294Sbill 	while (*v) {
10141294Sbill 		lp = findlim(*v++);
1015*17519Sedward 		setlim(lp, (int)RLIM_INFINITY);
10161294Sbill 	}
10171294Sbill }
10181294Sbill 
10191294Sbill setlim(lp, limit)
10201294Sbill 	register struct limits *lp;
10211294Sbill {
102210032Ssam 	struct rlimit rlim;
10231294Sbill 
1024*17519Sedward 	(void) getrlimit(lp->limconst, &rlim);
102516661Smckusick   	if(limit == RLIM_INFINITY && geteuid() != 0)
102616661Smckusick  		rlim.rlim_cur = rlim.rlim_max;
102716661Smckusick  	else
1028*17519Sedward  		rlim.rlim_cur = limit;
102910032Ssam 	if (setrlimit(lp->limconst, &rlim) < 0)
10301294Sbill 		Perror(bname);
10311294Sbill }
10321294Sbill 
10331294Sbill dosuspend()
10341294Sbill {
103517138Sralph 	int ldisc, ctpgrp;
103617138Sralph 	int (*old)();
10371294Sbill 
10381294Sbill 	if (loginsh)
10391294Sbill 		error("Can't suspend a login shell (yet)");
10401294Sbill 	untty();
104117138Sralph 	old = signal(SIGTSTP, SIG_DFL);
1042*17519Sedward 	(void) kill(0, SIGTSTP);
10431294Sbill 	/* the shell stops here */
1044*17519Sedward 	(void) signal(SIGTSTP, old);
10451294Sbill 	if (tpgrp != -1) {
10461294Sbill retry:
1047*17519Sedward 		(void) ioctl(FSHTTY, TIOCGPGRP, (char *)&ctpgrp);
10481294Sbill 		if (ctpgrp != opgrp) {
104917138Sralph 			old = signal(SIGTTIN, SIG_DFL);
1050*17519Sedward 			(void) kill(0, SIGTTIN);
1051*17519Sedward 			(void) signal(SIGTTIN, old);
10521294Sbill 			goto retry;
10531294Sbill 		}
1054*17519Sedward 		(void) ioctl(FSHTTY, TIOCSPGRP, (char *)&shpgrp);
1055*17519Sedward 		(void) setpgrp(0, shpgrp);
10561294Sbill 	}
1057*17519Sedward 	(void) ioctl(FSHTTY, TIOCGETD, (char *)&oldisc);
10581294Sbill 	if (oldisc != NTTYDISC) {
10591294Sbill 		printf("Switching to new tty driver...\n");
10601294Sbill 		ldisc = NTTYDISC;
1061*17519Sedward 		(void) ioctl(FSHTTY, TIOCSETD, (char *)&ldisc);
10621294Sbill 	}
10631294Sbill }
10641294Sbill 
10651294Sbill doeval(v)
10661294Sbill 	char **v;
10671294Sbill {
10681294Sbill 	char **oevalvec = evalvec;
10691294Sbill 	char *oevalp = evalp;
10701294Sbill 	jmp_buf osetexit;
10711294Sbill 	int reenter;
10721294Sbill 	char **gv = 0;
10731294Sbill 
10741294Sbill 	v++;
10751294Sbill 	if (*v == 0)
10761294Sbill 		return;
1077*17519Sedward 	gflag = 0, tglob(v);
10781294Sbill 	if (gflag) {
10791294Sbill 		gv = v = glob(v);
10801294Sbill 		gargv = 0;
10811294Sbill 		if (v == 0)
10821294Sbill 			error("No match");
10831294Sbill 		v = copyblk(v);
10841294Sbill 	} else
1085*17519Sedward 		trim(v);
10861294Sbill 	getexit(osetexit);
10871294Sbill 	reenter = 0;
10881294Sbill 	setexit();
10891294Sbill 	reenter++;
10901294Sbill 	if (reenter == 1) {
10911294Sbill 		evalvec = v;
10921294Sbill 		evalp = 0;
10931294Sbill 		process(0);
10941294Sbill 	}
10951294Sbill 	evalvec = oevalvec;
10961294Sbill 	evalp = oevalp;
10971294Sbill 	doneinp = 0;
10981294Sbill 	if (gv)
10991294Sbill 		blkfree(gv);
11001294Sbill 	resexit(osetexit);
11011294Sbill 	if (reenter >= 2)
11021294Sbill 		error(NOSTR);
11031294Sbill }
1104