xref: /csrg-svn/bin/csh/func.c (revision 47823)
1*47823Sbostic /*-
2*47823Sbostic  * Copyright (c) 1980, 1991 The Regents of the University of California.
3*47823Sbostic  * All rights reserved.
4*47823Sbostic  *
5*47823Sbostic  * %sccs.include.redist.c%
621933Sdist  */
721933Sdist 
817519Sedward #ifndef lint
9*47823Sbostic static char sccsid[] = "@(#)func.c	5.14 (Berkeley) 04/04/91";
1047413Sbostic #endif /* not lint */
111294Sbill 
121294Sbill #include "sh.h"
131294Sbill #include <sys/ioctl.h>
1437025Sbostic #include "pathnames.h"
151294Sbill 
161294Sbill /*
171294Sbill  * C shell
181294Sbill  */
191294Sbill 
201294Sbill struct biltins *
211294Sbill isbfunc(t)
2217519Sedward 	struct command *t;
231294Sbill {
241294Sbill 	register char *cp = t->t_dcom[0];
2517519Sedward 	register struct biltins *bp, *bp1, *bp2;
261294Sbill 	int dolabel(), dofg1(), dobg1();
271294Sbill 	static struct biltins label = { "", dolabel, 0, 0 };
281294Sbill 	static struct biltins foregnd = { "%job", dofg1, 0, 0 };
291294Sbill 	static struct biltins backgnd = { "%job &", dobg1, 0, 0 };
301294Sbill 
311294Sbill 	if (lastchr(cp) == ':') {
321294Sbill 		label.bname = cp;
331294Sbill 		return (&label);
341294Sbill 	}
351294Sbill 	if (*cp == '%') {
3647724Sbostic 		if (t->t_dflg & F_AMPERSAND) {
3747724Sbostic 			t->t_dflg &= ~F_AMPERSAND;
381294Sbill 			backgnd.bname = cp;
391294Sbill 			return (&backgnd);
4017519Sedward 		}
411294Sbill 		foregnd.bname = cp;
421294Sbill 		return (&foregnd);
431294Sbill 	}
4417519Sedward 	/*
4517519Sedward 	 * Binary search
4617519Sedward 	 * Bp1 is the beginning of the current search range.
4717519Sedward 	 * Bp2 is one past the end.
4817519Sedward 	 */
4917519Sedward 	for (bp1 = bfunc, bp2 = bfunc + nbfunc; bp1 < bp2;) {
5017519Sedward 		register i;
5117519Sedward 
5217519Sedward 		bp = bp1 + (bp2 - bp1 >> 1);
5317519Sedward 		if ((i = *cp - *bp->bname) == 0 &&
5417519Sedward 		    (i = strcmp(cp, bp->bname)) == 0)
5517519Sedward 			return bp;
5617519Sedward 		if (i < 0)
5717519Sedward 			bp2 = bp;
5817519Sedward 		else
5917519Sedward 			bp1 = bp + 1;
601294Sbill 	}
611294Sbill 	return (0);
621294Sbill }
631294Sbill 
641294Sbill func(t, bp)
651294Sbill 	register struct command *t;
661294Sbill 	register struct biltins *bp;
671294Sbill {
681294Sbill 	int i;
691294Sbill 
701294Sbill 	xechoit(t->t_dcom);
711294Sbill 	setname(bp->bname);
721294Sbill 	i = blklen(t->t_dcom) - 1;
731294Sbill 	if (i < bp->minargs)
741294Sbill 		bferr("Too few arguments");
751294Sbill 	if (i > bp->maxargs)
761294Sbill 		bferr("Too many arguments");
771294Sbill 	(*bp->bfunct)(t->t_dcom, t);
781294Sbill }
791294Sbill 
801294Sbill dolabel()
811294Sbill {
821294Sbill 
831294Sbill }
841294Sbill 
851294Sbill doonintr(v)
861294Sbill 	char **v;
871294Sbill {
881294Sbill 	register char *cp;
891294Sbill 	register char *vv = v[1];
901294Sbill 
911294Sbill 	if (parintr == SIG_IGN)
921294Sbill 		return;
931294Sbill 	if (setintr && intty)
941294Sbill 		bferr("Can't from terminal");
951294Sbill 	cp = gointr, gointr = 0, xfree(cp);
961294Sbill 	if (vv == 0) {
971294Sbill 		if (setintr)
9817519Sedward 			(void) sigblock(sigmask(SIGINT));
991294Sbill 		else
10017519Sedward 			(void) signal(SIGINT, SIG_DFL);
1011294Sbill 		gointr = 0;
1021294Sbill 	} else if (eq((vv = strip(vv)), "-")) {
10317519Sedward 		(void) signal(SIGINT, SIG_IGN);
1041294Sbill 		gointr = "-";
1051294Sbill 	} else {
1061294Sbill 		gointr = savestr(vv);
10717519Sedward 		(void) signal(SIGINT, pintr);
1081294Sbill 	}
1091294Sbill }
1101294Sbill 
1111294Sbill donohup()
1121294Sbill {
1131294Sbill 
1141294Sbill 	if (intty)
1151294Sbill 		bferr("Can't from terminal");
1161294Sbill 	if (setintr == 0) {
11717519Sedward 		(void) signal(SIGHUP, SIG_IGN);
1181294Sbill #ifdef CC
1191294Sbill 		submit(getpid());
1201294Sbill #endif
1211294Sbill 	}
1221294Sbill }
1231294Sbill 
1241294Sbill dozip()
1251294Sbill {
1261294Sbill 
1271294Sbill 	;
1281294Sbill }
1291294Sbill 
1301294Sbill prvars()
1311294Sbill {
1321294Sbill 
1331294Sbill 	plist(&shvhed);
1341294Sbill }
1351294Sbill 
1361294Sbill doalias(v)
1371294Sbill 	register char **v;
1381294Sbill {
1391294Sbill 	register struct varent *vp;
1401294Sbill 	register char *p;
1411294Sbill 
1421294Sbill 	v++;
1431294Sbill 	p = *v++;
1441294Sbill 	if (p == 0)
1451294Sbill 		plist(&aliases);
1461294Sbill 	else if (*v == 0) {
1471294Sbill 		vp = adrof1(strip(p), &aliases);
1481294Sbill 		if (vp)
1491294Sbill 			blkpr(vp->vec), printf("\n");
1501294Sbill 	} else {
1511294Sbill 		if (eq(p, "alias") || eq(p, "unalias")) {
1521294Sbill 			setname(p);
1531294Sbill 			bferr("Too dangerous to alias that");
1541294Sbill 		}
1551294Sbill 		set1(strip(p), saveblk(v), &aliases);
1561294Sbill 	}
1571294Sbill }
1581294Sbill 
1591294Sbill unalias(v)
1601294Sbill 	char **v;
1611294Sbill {
1621294Sbill 
1631294Sbill 	unset1(v, &aliases);
1641294Sbill }
1651294Sbill 
1661294Sbill dologout()
1671294Sbill {
1681294Sbill 
1691294Sbill 	islogin();
1701294Sbill 	goodbye();
1711294Sbill }
1721294Sbill 
1731294Sbill dologin(v)
1741294Sbill 	char **v;
1751294Sbill {
1761294Sbill 
1771294Sbill 	islogin();
1784189Smckusic 	rechist();
17917519Sedward 	(void) signal(SIGTERM, parterm);
18037025Sbostic 	execl(_PATH_LOGIN, "login", v[1], 0);
1811294Sbill 	untty();
1821294Sbill 	exit(1);
1831294Sbill }
1841294Sbill 
1851294Sbill islogin()
1861294Sbill {
1871294Sbill 
1881294Sbill 	if (chkstop == 0 && setintr)
1891294Sbill 		panystop(0);
1901294Sbill 	if (loginsh)
1911294Sbill 		return;
1921294Sbill 	error("Not login shell");
1931294Sbill }
1941294Sbill 
1951294Sbill doif(v, kp)
1961294Sbill 	char **v;
1971294Sbill 	struct command *kp;
1981294Sbill {
1991294Sbill 	register int i;
2001294Sbill 	register char **vv;
2011294Sbill 
2021294Sbill 	v++;
2031294Sbill 	i = exp(&v);
2041294Sbill 	vv = v;
2051294Sbill 	if (*vv == NOSTR)
2061294Sbill 		bferr("Empty if");
2071294Sbill 	if (eq(*vv, "then")) {
2081294Sbill 		if (*++vv)
2091294Sbill 			bferr("Improper then");
2101294Sbill 		setname("then");
2111294Sbill 		/*
2121294Sbill 		 * If expression was zero, then scan to else,
2131294Sbill 		 * otherwise just fall into following code.
2141294Sbill 		 */
2151294Sbill 		if (!i)
21647724Sbostic 			search(T_IF, 0);
2171294Sbill 		return;
2181294Sbill 	}
2191294Sbill 	/*
2201294Sbill 	 * Simple command attached to this if.
2211294Sbill 	 * Left shift the node in this tree, munging it
2221294Sbill 	 * so we can reexecute it.
2231294Sbill 	 */
2241294Sbill 	if (i) {
2251294Sbill 		lshift(kp->t_dcom, vv - kp->t_dcom);
2261294Sbill 		reexecute(kp);
2271294Sbill 		donefds();
2281294Sbill 	}
2291294Sbill }
2301294Sbill 
2311294Sbill /*
2321294Sbill  * Reexecute a command, being careful not
2331294Sbill  * to redo i/o redirection, which is already set up.
2341294Sbill  */
2351294Sbill reexecute(kp)
2361294Sbill 	register struct command *kp;
2371294Sbill {
2381294Sbill 
23947724Sbostic 	kp->t_dflg &= F_SAVE;
24047724Sbostic 	kp->t_dflg |= F_REPEAT;
2411294Sbill 	/*
2421294Sbill 	 * If tty is still ours to arbitrate, arbitrate it;
2431294Sbill 	 * otherwise dont even set pgrp's as the jobs would
2441294Sbill 	 * then have no way to get the tty (we can't give it
2451294Sbill 	 * to them, and our parent wouldn't know their pgrp, etc.
2461294Sbill 	 */
2471294Sbill 	execute(kp, tpgrp > 0 ? tpgrp : -1);
2481294Sbill }
2491294Sbill 
2501294Sbill doelse()
2511294Sbill {
2521294Sbill 
25347724Sbostic 	search(T_ELSE, 0);
2541294Sbill }
2551294Sbill 
2561294Sbill dogoto(v)
2571294Sbill 	char **v;
2581294Sbill {
2591294Sbill 	register struct whyle *wp;
2601294Sbill 	char *lp;
2611294Sbill 
2621294Sbill 	/*
2631294Sbill 	 * While we still can, locate any unknown ends of existing loops.
2641294Sbill 	 * This obscure code is the WORST result of the fact that we
2651294Sbill 	 * don't really parse.
2661294Sbill 	 */
2671294Sbill 	for (wp = whyles; wp; wp = wp->w_next)
2681294Sbill 		if (wp->w_end == 0) {
26947724Sbostic 			search(T_BREAK, 0);
2701294Sbill 			wp->w_end = btell();
2711294Sbill 		} else
2721294Sbill 			bseek(wp->w_end);
27347724Sbostic 	search(T_GOTO, 0, lp = globone(v[1]));
2741294Sbill 	xfree(lp);
2751294Sbill 	/*
2761294Sbill 	 * Eliminate loops which were exited.
2771294Sbill 	 */
2781294Sbill 	wfree();
2791294Sbill }
2801294Sbill 
2811294Sbill doswitch(v)
2821294Sbill 	register char **v;
2831294Sbill {
2841294Sbill 	register char *cp, *lp;
2851294Sbill 
2861294Sbill 	v++;
2871294Sbill 	if (!*v || *(*v++) != '(')
2881294Sbill 		goto syntax;
2891294Sbill 	cp = **v == ')' ? "" : *v++;
2901294Sbill 	if (*(*v++) != ')')
2911294Sbill 		v--;
2921294Sbill 	if (*v)
2931294Sbill syntax:
2941294Sbill 		error("Syntax error");
29547724Sbostic 	search(T_SWITCH, 0, lp = globone(cp));
2961294Sbill 	xfree(lp);
2971294Sbill }
2981294Sbill 
2991294Sbill dobreak()
3001294Sbill {
3011294Sbill 
3021294Sbill 	if (whyles)
3031294Sbill 		toend();
3041294Sbill 	else
3051294Sbill 		bferr("Not in while/foreach");
3061294Sbill }
3071294Sbill 
3081294Sbill doexit(v)
3091294Sbill 	char **v;
3101294Sbill {
3111294Sbill 
3121294Sbill 	if (chkstop == 0)
3131294Sbill 		panystop(0);
3141294Sbill 	/*
3151294Sbill 	 * Don't DEMAND parentheses here either.
3161294Sbill 	 */
3171294Sbill 	v++;
3181294Sbill 	if (*v) {
3191294Sbill 		set("status", putn(exp(&v)));
3201294Sbill 		if (*v)
3211294Sbill 			bferr("Expression syntax");
3221294Sbill 	}
3231294Sbill 	btoeof();
3241294Sbill 	if (intty)
32517519Sedward 		(void) close(SHIN);
3261294Sbill }
3271294Sbill 
3281294Sbill doforeach(v)
3291294Sbill 	register char **v;
3301294Sbill {
3311294Sbill 	register char *cp;
3321294Sbill 	register struct whyle *nwp;
3331294Sbill 
3341294Sbill 	v++;
3351294Sbill 	cp = strip(*v);
3361294Sbill 	while (*cp && letter(*cp))
3371294Sbill 		cp++;
3381294Sbill 	if (*cp || strlen(*v) >= 20)
3391294Sbill 		bferr("Invalid variable");
3401294Sbill 	cp = *v++;
3411294Sbill 	if (v[0][0] != '(' || v[blklen(v) - 1][0] != ')')
3421294Sbill 		bferr("Words not ()'ed");
3431294Sbill 	v++;
34417519Sedward 	gflag = 0, tglob(v);
34547412Sbostic 	v = globall(v);
3461294Sbill 	if (v == 0)
3471294Sbill 		bferr("No match");
3481294Sbill 	nwp = (struct whyle *) calloc(1, sizeof *nwp);
3491294Sbill 	nwp->w_fe = nwp->w_fe0 = v; gargv = 0;
3501294Sbill 	nwp->w_start = btell();
3511294Sbill 	nwp->w_fename = savestr(cp);
3521294Sbill 	nwp->w_next = whyles;
3531294Sbill 	whyles = nwp;
3541294Sbill 	/*
3551294Sbill 	 * Pre-read the loop so as to be more
3561294Sbill 	 * comprehensible to a terminal user.
3571294Sbill 	 */
3581294Sbill 	if (intty)
3591294Sbill 		preread();
3601294Sbill 	doagain();
3611294Sbill }
3621294Sbill 
3631294Sbill dowhile(v)
3641294Sbill 	char **v;
3651294Sbill {
3661294Sbill 	register int status;
3671294Sbill 	register bool again = whyles != 0 && whyles->w_start == lineloc &&
3681294Sbill 	    whyles->w_fename == 0;
3691294Sbill 
3701294Sbill 	v++;
3711294Sbill 	/*
3721294Sbill 	 * Implement prereading here also, taking care not to
3731294Sbill 	 * evaluate the expression before the loop has been read up
3741294Sbill 	 * from a terminal.
3751294Sbill 	 */
3761294Sbill 	if (intty && !again)
3771294Sbill 		status = !exp0(&v, 1);
3781294Sbill 	else
3791294Sbill 		status = !exp(&v);
3801294Sbill 	if (*v)
3811294Sbill 		bferr("Expression syntax");
3821294Sbill 	if (!again) {
3831294Sbill 		register struct whyle *nwp = (struct whyle *) calloc(1, sizeof (*nwp));
3841294Sbill 
3851294Sbill 		nwp->w_start = lineloc;
3861294Sbill 		nwp->w_end = 0;
3871294Sbill 		nwp->w_next = whyles;
3881294Sbill 		whyles = nwp;
3891294Sbill 		if (intty) {
3901294Sbill 			/*
3911294Sbill 			 * The tty preread
3921294Sbill 			 */
3931294Sbill 			preread();
3941294Sbill 			doagain();
3951294Sbill 			return;
3961294Sbill 		}
3971294Sbill 	}
3981294Sbill 	if (status)
3991294Sbill 		/* We ain't gonna loop no more, no more! */
4001294Sbill 		toend();
4011294Sbill }
4021294Sbill 
4031294Sbill preread()
4041294Sbill {
4051294Sbill 
4061294Sbill 	whyles->w_end = -1;
4071294Sbill 	if (setintr)
40831685Sbostic 		(void) sigsetmask(sigblock(0L) & ~sigmask(SIGINT));
40947724Sbostic 	search(T_BREAK, 0);
4101294Sbill 	if (setintr)
41117519Sedward 		(void) sigblock(sigmask(SIGINT));
4121294Sbill 	whyles->w_end = btell();
4131294Sbill }
4141294Sbill 
4151294Sbill doend()
4161294Sbill {
4171294Sbill 
4181294Sbill 	if (!whyles)
4191294Sbill 		bferr("Not in while/foreach");
4201294Sbill 	whyles->w_end = btell();
4211294Sbill 	doagain();
4221294Sbill }
4231294Sbill 
4241294Sbill docontin()
4251294Sbill {
4261294Sbill 
4271294Sbill 	if (!whyles)
4281294Sbill 		bferr("Not in while/foreach");
4291294Sbill 	doagain();
4301294Sbill }
4311294Sbill 
4321294Sbill doagain()
4331294Sbill {
4341294Sbill 
4351294Sbill 	/* Repeating a while is simple */
4361294Sbill 	if (whyles->w_fename == 0) {
4371294Sbill 		bseek(whyles->w_start);
4381294Sbill 		return;
4391294Sbill 	}
4401294Sbill 	/*
4411294Sbill 	 * The foreach variable list actually has a spurious word
4421294Sbill 	 * ")" at the end of the w_fe list.  Thus we are at the
4431294Sbill 	 * of the list if one word beyond this is 0.
4441294Sbill 	 */
4451294Sbill 	if (!whyles->w_fe[1]) {
4461294Sbill 		dobreak();
4471294Sbill 		return;
4481294Sbill 	}
4491294Sbill 	set(whyles->w_fename, savestr(*whyles->w_fe++));
4501294Sbill 	bseek(whyles->w_start);
4511294Sbill }
4521294Sbill 
4531294Sbill dorepeat(v, kp)
4541294Sbill 	char **v;
4551294Sbill 	struct command *kp;
4561294Sbill {
45731685Sbostic 	register int i;
45831685Sbostic 	register long	omask;
4591294Sbill 
4601294Sbill 	i = getn(v[1]);
4611294Sbill 	if (setintr)
46217138Sralph 		omask = sigblock(sigmask(SIGINT)) & ~sigmask(SIGINT);
4631294Sbill 	lshift(v, 2);
4641294Sbill 	while (i > 0) {
4651294Sbill 		if (setintr)
46617519Sedward 			(void) sigsetmask(omask);
4671294Sbill 		reexecute(kp);
4681294Sbill 		--i;
4691294Sbill 	}
4701294Sbill 	donefds();
4711294Sbill 	if (setintr)
47217519Sedward 		(void) sigsetmask(omask);
4731294Sbill }
4741294Sbill 
4751294Sbill doswbrk()
4761294Sbill {
4771294Sbill 
47847724Sbostic 	search(T_BRKSW, 0);
4791294Sbill }
4801294Sbill 
4811294Sbill srchx(cp)
4821294Sbill 	register char *cp;
4831294Sbill {
48417519Sedward 	register struct srch *sp, *sp1, *sp2;
48517519Sedward 	register i;
4861294Sbill 
48717519Sedward 	/*
48817519Sedward 	 * Binary search
48917519Sedward 	 * Sp1 is the beginning of the current search range.
49017519Sedward 	 * Sp2 is one past the end.
49117519Sedward 	 */
49217519Sedward 	for (sp1 = srchn, sp2 = srchn + nsrchn; sp1 < sp2;) {
49317519Sedward 		sp = sp1 + (sp2 - sp1 >> 1);
49417519Sedward 		if ((i = *cp - *sp->s_name) == 0 &&
49517519Sedward 		    (i = strcmp(cp, sp->s_name)) == 0)
49617519Sedward 			return sp->s_value;
49717519Sedward 		if (i < 0)
49817519Sedward 			sp2 = sp;
49917519Sedward 		else
50017519Sedward 			sp1 = sp + 1;
50117519Sedward 	}
5021294Sbill 	return (-1);
5031294Sbill }
5041294Sbill 
5051294Sbill char	Stype;
5061294Sbill char	*Sgoal;
5071294Sbill 
5081294Sbill /*VARARGS2*/
5091294Sbill search(type, level, goal)
5101294Sbill 	int type;
5111294Sbill 	register int level;
5121294Sbill 	char *goal;
5131294Sbill {
5141294Sbill 	char wordbuf[BUFSIZ];
5151294Sbill 	register char *aword = wordbuf;
5161294Sbill 	register char *cp;
5171294Sbill 
5181294Sbill 	Stype = type; Sgoal = goal;
51947724Sbostic 	if (type == T_GOTO)
52017519Sedward 		bseek((off_t)0);
5211294Sbill 	do {
5221294Sbill 		if (intty && fseekp == feobp)
5231294Sbill 			printf("? "), flush();
52417519Sedward 		aword[0] = 0;
52517519Sedward 		(void) getword(aword);
5261294Sbill 		switch (srchx(aword)) {
5271294Sbill 
52847724Sbostic 		case T_ELSE:
52947724Sbostic 			if (level == 0 && type == T_IF)
5301294Sbill 				return;
5311294Sbill 			break;
5321294Sbill 
53347724Sbostic 		case T_IF:
5341294Sbill 			while (getword(aword))
5351294Sbill 				continue;
53647724Sbostic 			if ((type == T_IF || type == T_ELSE) &&
53747724Sbostic 			    eq(aword, "then"))
5381294Sbill 				level++;
5391294Sbill 			break;
5401294Sbill 
54147724Sbostic 		case T_ENDIF:
54247724Sbostic 			if (type == T_IF || type == T_ELSE)
5431294Sbill 				level--;
5441294Sbill 			break;
5451294Sbill 
54647724Sbostic 		case T_FOREACH:
54747724Sbostic 		case T_WHILE:
54847724Sbostic 			if (type == T_BREAK)
5491294Sbill 				level++;
5501294Sbill 			break;
5511294Sbill 
55247724Sbostic 		case T_END:
55347724Sbostic 			if (type == T_BREAK)
5541294Sbill 				level--;
5551294Sbill 			break;
5561294Sbill 
55747724Sbostic 		case T_SWITCH:
55847724Sbostic 			if (type == T_SWITCH || type == T_BRKSW)
5591294Sbill 				level++;
5601294Sbill 			break;
5611294Sbill 
56247724Sbostic 		case T_ENDSW:
56347724Sbostic 			if (type == T_SWITCH || type == T_BRKSW)
5641294Sbill 				level--;
5651294Sbill 			break;
5661294Sbill 
56747724Sbostic 		case T_LABEL:
56847724Sbostic 			if (type == T_GOTO && getword(aword) && eq(aword, goal))
5691294Sbill 				level = -1;
5701294Sbill 			break;
5711294Sbill 
5721294Sbill 		default:
57347724Sbostic 			if (type != T_GOTO && (type != T_SWITCH || level != 0))
5741294Sbill 				break;
5751294Sbill 			if (lastchr(aword) != ':')
5761294Sbill 				break;
5771294Sbill 			aword[strlen(aword) - 1] = 0;
57847724Sbostic 			if (type == T_GOTO && eq(aword, goal) ||
57947724Sbostic 			    type == T_SWITCH && eq(aword, "default"))
5801294Sbill 				level = -1;
5811294Sbill 			break;
5821294Sbill 
58347724Sbostic 		case T_CASE:
58447724Sbostic 			if (type != T_SWITCH || level != 0)
5851294Sbill 				break;
58617519Sedward 			(void) getword(aword);
5871294Sbill 			if (lastchr(aword) == ':')
5881294Sbill 				aword[strlen(aword) - 1] = 0;
5891294Sbill 			cp = strip(Dfix1(aword));
5901294Sbill 			if (Gmatch(goal, cp))
5911294Sbill 				level = -1;
5921294Sbill 			xfree(cp);
5931294Sbill 			break;
5941294Sbill 
59547724Sbostic 		case T_DEFAULT:
59647724Sbostic 			if (type == T_SWITCH && level == 0)
5971294Sbill 				level = -1;
5981294Sbill 			break;
5991294Sbill 		}
60017519Sedward 		(void) getword(NOSTR);
6011294Sbill 	} while (level >= 0);
6021294Sbill }
6031294Sbill 
6041294Sbill getword(wp)
6051294Sbill 	register char *wp;
6061294Sbill {
6071294Sbill 	register int found = 0;
6081294Sbill 	register int c, d;
6091294Sbill 
6101294Sbill 	c = readc(1);
6111294Sbill 	d = 0;
6121294Sbill 	do {
6131294Sbill 		while (c == ' ' || c == '\t')
6141294Sbill 			c = readc(1);
6153798Sroot 		if (c == '#')
6163798Sroot 			do
6173798Sroot 				c = readc(1);
6183798Sroot 			while (c >= 0 && c != '\n');
6191294Sbill 		if (c < 0)
6201294Sbill 			goto past;
6211294Sbill 		if (c == '\n') {
6221294Sbill 			if (wp)
6231294Sbill 				break;
6241294Sbill 			return (0);
6251294Sbill 		}
6261294Sbill 		unreadc(c);
6271294Sbill 		found = 1;
6281294Sbill 		do {
6291294Sbill 			c = readc(1);
6301294Sbill 			if (c == '\\' && (c = readc(1)) == '\n')
6311294Sbill 				c = ' ';
63217519Sedward 			if (c == '\'' || c == '"')
6331294Sbill 				if (d == 0)
6341294Sbill 					d = c;
6351294Sbill 				else if (d == c)
6361294Sbill 					d = 0;
6371294Sbill 			if (c < 0)
6381294Sbill 				goto past;
6391294Sbill 			if (wp)
6401294Sbill 				*wp++ = c;
6411294Sbill 		} while ((d || c != ' ' && c != '\t') && c != '\n');
6421294Sbill 	} while (wp == 0);
6431294Sbill 	unreadc(c);
6441294Sbill 	if (found)
6451294Sbill 		*--wp = 0;
6461294Sbill 	return (found);
6471294Sbill 
6481294Sbill past:
6491294Sbill 	switch (Stype) {
6501294Sbill 
65147724Sbostic 	case T_IF:
6521294Sbill 		bferr("then/endif not found");
6531294Sbill 
65447724Sbostic 	case T_ELSE:
6551294Sbill 		bferr("endif not found");
6561294Sbill 
65747724Sbostic 	case T_BRKSW:
65847724Sbostic 	case T_SWITCH:
6591294Sbill 		bferr("endsw not found");
6601294Sbill 
66147724Sbostic 	case T_BREAK:
6621294Sbill 		bferr("end not found");
6631294Sbill 
66447724Sbostic 	case T_GOTO:
6651294Sbill 		setname(Sgoal);
6661294Sbill 		bferr("label not found");
6671294Sbill 	}
6681294Sbill 	/*NOTREACHED*/
6691294Sbill }
6701294Sbill 
6711294Sbill toend()
6721294Sbill {
6731294Sbill 
6741294Sbill 	if (whyles->w_end == 0) {
67547724Sbostic 		search(T_BREAK, 0);
6761294Sbill 		whyles->w_end = btell() - 1;
6771294Sbill 	} else
6781294Sbill 		bseek(whyles->w_end);
6791294Sbill 	wfree();
6801294Sbill }
6811294Sbill 
6821294Sbill wfree()
6831294Sbill {
6841294Sbill 	long o = btell();
6851294Sbill 
6861294Sbill 	while (whyles) {
6871294Sbill 		register struct whyle *wp = whyles;
6881294Sbill 		register struct whyle *nwp = wp->w_next;
6891294Sbill 
6901294Sbill 		if (o >= wp->w_start && (wp->w_end == 0 || o < wp->w_end))
6911294Sbill 			break;
6921294Sbill 		if (wp->w_fe0)
6931294Sbill 			blkfree(wp->w_fe0);
6941294Sbill 		if (wp->w_fename)
6951294Sbill 			xfree(wp->w_fename);
6961294Sbill 		xfree((char *)wp);
6971294Sbill 		whyles = nwp;
6981294Sbill 	}
6991294Sbill }
7001294Sbill 
7011294Sbill doecho(v)
7021294Sbill 	char **v;
7031294Sbill {
7041294Sbill 
7051294Sbill 	echo(' ', v);
7061294Sbill }
7071294Sbill 
7081294Sbill doglob(v)
7091294Sbill 	char **v;
7101294Sbill {
7111294Sbill 
7121294Sbill 	echo(0, v);
7131294Sbill 	flush();
7141294Sbill }
7151294Sbill 
7161294Sbill echo(sep, v)
7171294Sbill 	char sep;
7181294Sbill 	register char **v;
7191294Sbill {
7201294Sbill 	register char *cp;
7211294Sbill 	int nonl = 0;
7221294Sbill 
7231294Sbill 	if (setintr)
72431685Sbostic 		(void) sigsetmask(sigblock(0L) & ~sigmask(SIGINT));
7251294Sbill 	v++;
7261294Sbill 	if (*v == 0)
7271294Sbill 		return;
72817519Sedward 	gflag = 0, tglob(v);
7291294Sbill 	if (gflag) {
73047412Sbostic 		v = globall(v);
7311294Sbill 		if (v == 0)
7321294Sbill 			bferr("No match");
7331294Sbill 	} else
73417519Sedward 		trim(v);
73518422Smckusick 	if (sep == ' ' && *v && !strcmp(*v, "-n"))
7361294Sbill 		nonl++, v++;
7371294Sbill 	while (cp = *v++) {
7381294Sbill 		register int c;
7391294Sbill 
7401294Sbill 		while (c = *cp++)
74134340Sbostic 			cshputchar(c | QUOTE);
7421294Sbill 		if (*v)
74334340Sbostic 			cshputchar(sep | QUOTE);
7441294Sbill 	}
7451294Sbill 	if (sep && nonl == 0)
74634340Sbostic 		cshputchar('\n');
7471294Sbill 	else
7481294Sbill 		flush();
7491294Sbill 	if (setintr)
75017519Sedward 		(void) sigblock(sigmask(SIGINT));
7511294Sbill 	if (gargv)
7521294Sbill 		blkfree(gargv), gargv = 0;
7531294Sbill }
7541294Sbill 
7551294Sbill char	**environ;
7561294Sbill 
7571294Sbill dosetenv(v)
7581294Sbill 	register char **v;
7591294Sbill {
76021753Sedward 	char *vp, *lp;
7611294Sbill 
76221753Sedward 	v++;
76321753Sedward 	if ((vp = *v++) == 0) {
76421753Sedward 		register char **ep;
76521753Sedward 
76621753Sedward 		if (setintr)
76731685Sbostic 			(void) sigsetmask(sigblock(0L) & ~ sigmask(SIGINT));
76821753Sedward 		for (ep = environ; *ep; ep++)
76921753Sedward 			printf("%s\n", *ep);
77021753Sedward 		return;
77121753Sedward 	}
77221753Sedward 	if ((lp = *v++) == 0)
77321753Sedward 		lp = "";
77421753Sedward 	setenv(vp, lp = globone(lp));
77521753Sedward 	if (eq(vp, "PATH")) {
7761294Sbill 		importpath(lp);
7771294Sbill 		dohash();
7781294Sbill 	}
7791294Sbill 	xfree(lp);
7801294Sbill }
7811294Sbill 
7821294Sbill dounsetenv(v)
7831294Sbill 	register char **v;
7841294Sbill {
7851294Sbill 
7861294Sbill 	v++;
7871294Sbill 	do
7881294Sbill 		unsetenv(*v++);
7891294Sbill 	while (*v);
7901294Sbill }
7911294Sbill 
79217519Sedward setenv(name, val)
79317519Sedward 	char *name, *val;
7941294Sbill {
7951294Sbill 	register char **ep = environ;
7961294Sbill 	register char *cp, *dp;
7971294Sbill 	char *blk[2], **oep = ep;
7981294Sbill 
7991294Sbill 	for (; *ep; ep++) {
8001294Sbill 		for (cp = name, dp = *ep; *cp && *cp == *dp; cp++, dp++)
8011294Sbill 			continue;
8021294Sbill 		if (*cp != 0 || *dp != '=')
8031294Sbill 			continue;
80417519Sedward 		cp = strspl("=", val);
8051294Sbill 		xfree(*ep);
8061294Sbill 		*ep = strspl(name, cp);
8071294Sbill 		xfree(cp);
80817519Sedward 		trim(ep);
8091294Sbill 		return;
8101294Sbill 	}
8111294Sbill 	blk[0] = strspl(name, "="); blk[1] = 0;
8121294Sbill 	environ = blkspl(environ, blk);
8131294Sbill 	xfree((char *)oep);
81417519Sedward 	setenv(name, val);
8151294Sbill }
8161294Sbill 
8171294Sbill unsetenv(name)
8181294Sbill 	char *name;
8191294Sbill {
8201294Sbill 	register char **ep = environ;
8211294Sbill 	register char *cp, *dp;
8221294Sbill 	char **oep = ep;
8231294Sbill 
8241294Sbill 	for (; *ep; ep++) {
8251294Sbill 		for (cp = name, dp = *ep; *cp && *cp == *dp; cp++, dp++)
8261294Sbill 			continue;
8271294Sbill 		if (*cp != 0 || *dp != '=')
8281294Sbill 			continue;
8291294Sbill 		cp = *ep;
8301294Sbill 		*ep = 0;
8311294Sbill 		environ = blkspl(environ, ep+1);
8321294Sbill 		*ep = cp;
8331294Sbill 		xfree(cp);
8341294Sbill 		xfree((char *)oep);
8351294Sbill 		return;
8361294Sbill 	}
8371294Sbill }
8381294Sbill 
8391294Sbill doumask(v)
8401294Sbill 	register char **v;
8411294Sbill {
8421294Sbill 	register char *cp = v[1];
8431294Sbill 	register int i;
8441294Sbill 
8451294Sbill 	if (cp == 0) {
8461294Sbill 		i = umask(0);
84717519Sedward 		(void) umask(i);
8481294Sbill 		printf("%o\n", i);
8491294Sbill 		return;
8501294Sbill 	}
8511294Sbill 	i = 0;
8521294Sbill 	while (digit(*cp) && *cp != '8' && *cp != '9')
8531294Sbill 		i = i * 8 + *cp++ - '0';
8541294Sbill 	if (*cp || i < 0 || i > 0777)
8551294Sbill 		bferr("Improper mask");
85617519Sedward 	(void) umask(i);
8571294Sbill }
8581294Sbill 
8591294Sbill 
8601294Sbill struct limits {
8611294Sbill 	int	limconst;
8621294Sbill 	char	*limname;
8631294Sbill 	int	limdiv;
8641294Sbill 	char	*limscale;
8651294Sbill } limits[] = {
86610032Ssam 	RLIMIT_CPU,	"cputime",	1,	"seconds",
86710032Ssam 	RLIMIT_FSIZE,	"filesize",	1024,	"kbytes",
86810032Ssam 	RLIMIT_DATA,	"datasize",	1024,	"kbytes",
86910032Ssam 	RLIMIT_STACK,	"stacksize",	1024,	"kbytes",
87010032Ssam 	RLIMIT_CORE,	"coredumpsize",	1024,	"kbytes",
87110032Ssam 	RLIMIT_RSS,	"memoryuse",	1024,	"kbytes",
8721294Sbill 	-1,		0,
8731294Sbill };
8741294Sbill 
8751294Sbill struct limits *
8761294Sbill findlim(cp)
8771294Sbill 	char *cp;
8781294Sbill {
8791294Sbill 	register struct limits *lp, *res;
8801294Sbill 
8811294Sbill 	res = 0;
8821294Sbill 	for (lp = limits; lp->limconst >= 0; lp++)
8831294Sbill 		if (prefix(cp, lp->limname)) {
8841294Sbill 			if (res)
8851294Sbill 				bferr("Ambiguous");
8861294Sbill 			res = lp;
8871294Sbill 		}
8881294Sbill 	if (res)
8891294Sbill 		return (res);
8901294Sbill 	bferr("No such limit");
89117519Sedward 	/*NOTREACHED*/
8921294Sbill }
8931294Sbill 
8941294Sbill dolimit(v)
8951294Sbill 	register char **v;
8961294Sbill {
8971294Sbill 	register struct limits *lp;
8981294Sbill 	register int limit;
89918539Sedward 	char hard = 0;
9001294Sbill 
9011294Sbill 	v++;
90228050Slepreau 	if (*v && eq(*v, "-h")) {
90318539Sedward 		hard = 1;
90418539Sedward 		v++;
90518539Sedward 	}
9061294Sbill 	if (*v == 0) {
90718539Sedward 		for (lp = limits; lp->limconst >= 0; lp++)
90818539Sedward 			plim(lp, hard);
9091294Sbill 		return;
9101294Sbill 	}
9111294Sbill 	lp = findlim(v[0]);
9121294Sbill 	if (v[1] == 0) {
91318539Sedward 		plim(lp,  hard);
9141294Sbill 		return;
9151294Sbill 	}
9161294Sbill 	limit = getval(lp, v+1);
91718539Sedward 	if (setlim(lp, hard, limit) < 0)
91818422Smckusick 		error(NOSTR);
9191294Sbill }
9201294Sbill 
9211294Sbill getval(lp, v)
9221294Sbill 	register struct limits *lp;
9231294Sbill 	char **v;
9241294Sbill {
9251294Sbill 	register float f;
9261294Sbill 	double atof();
9271294Sbill 	char *cp = *v++;
9281294Sbill 
9291294Sbill 	f = atof(cp);
9301294Sbill 	while (digit(*cp) || *cp == '.' || *cp == 'e' || *cp == 'E')
9311294Sbill 		cp++;
9321294Sbill 	if (*cp == 0) {
9331294Sbill 		if (*v == 0)
9341294Sbill 			return ((int)(f+0.5) * lp->limdiv);
9351294Sbill 		cp = *v;
9361294Sbill 	}
9371294Sbill 	switch (*cp) {
9381294Sbill 
9391294Sbill 	case ':':
94010032Ssam 		if (lp->limconst != RLIMIT_CPU)
9411294Sbill 			goto badscal;
9421294Sbill 		return ((int)(f * 60.0 + atof(cp+1)));
9431294Sbill 
9441294Sbill 	case 'h':
94510032Ssam 		if (lp->limconst != RLIMIT_CPU)
9461294Sbill 			goto badscal;
9471294Sbill 		limtail(cp, "hours");
9481294Sbill 		f *= 3600.;
9491294Sbill 		break;
9501294Sbill 
9511294Sbill 	case 'm':
95210032Ssam 		if (lp->limconst == RLIMIT_CPU) {
9531294Sbill 			limtail(cp, "minutes");
9541294Sbill 			f *= 60.;
9551294Sbill 			break;
9561294Sbill 		}
9571294Sbill 	case 'M':
95810032Ssam 		if (lp->limconst == RLIMIT_CPU)
9591294Sbill 			goto badscal;
9601294Sbill 		*cp = 'm';
9611294Sbill 		limtail(cp, "megabytes");
9621294Sbill 		f *= 1024.*1024.;
9631294Sbill 		break;
9641294Sbill 
9651294Sbill 	case 's':
96610032Ssam 		if (lp->limconst != RLIMIT_CPU)
9671294Sbill 			goto badscal;
9681294Sbill 		limtail(cp, "seconds");
9691294Sbill 		break;
9701294Sbill 
9711294Sbill 	case 'k':
97210032Ssam 		if (lp->limconst == RLIMIT_CPU)
9731294Sbill 			goto badscal;
9741294Sbill 		limtail(cp, "kbytes");
9751294Sbill 		f *= 1024;
9761294Sbill 		break;
9771294Sbill 
9781294Sbill 	case 'u':
9791294Sbill 		limtail(cp, "unlimited");
98010032Ssam 		return (RLIM_INFINITY);
9811294Sbill 
9821294Sbill 	default:
9831294Sbill badscal:
9841294Sbill 		bferr("Improper or unknown scale factor");
9851294Sbill 	}
9861294Sbill 	return ((int)(f+0.5));
9871294Sbill }
9881294Sbill 
9891294Sbill limtail(cp, str0)
9901294Sbill 	char *cp, *str0;
9911294Sbill {
9921294Sbill 	register char *str = str0;
9931294Sbill 
9941294Sbill 	while (*cp && *cp == *str)
9951294Sbill 		cp++, str++;
9961294Sbill 	if (*cp)
9971294Sbill 		error("Bad scaling; did you mean ``%s''?", str0);
9981294Sbill }
9991294Sbill 
100018539Sedward plim(lp, hard)
10011294Sbill 	register struct limits *lp;
100218539Sedward 	char hard;
10031294Sbill {
100410032Ssam 	struct rlimit rlim;
100518539Sedward 	int limit;
10061294Sbill 
10071294Sbill 	printf("%s \t", lp->limname);
100817519Sedward 	(void) getrlimit(lp->limconst, &rlim);
100918539Sedward 	limit = hard ? rlim.rlim_max : rlim.rlim_cur;
101018539Sedward 	if (limit == RLIM_INFINITY)
10111294Sbill 		printf("unlimited");
101210032Ssam 	else if (lp->limconst == RLIMIT_CPU)
101318539Sedward 		psecs((long)limit);
10141294Sbill 	else
101518539Sedward 		printf("%d %s", limit / lp->limdiv, lp->limscale);
10161294Sbill 	printf("\n");
10171294Sbill }
10181294Sbill 
10191294Sbill dounlimit(v)
10201294Sbill 	register char **v;
10211294Sbill {
10221294Sbill 	register struct limits *lp;
102318422Smckusick 	int err = 0;
102418539Sedward 	char hard = 0;
10251294Sbill 
10261294Sbill 	v++;
102728050Slepreau 	if (*v && eq(*v, "-h")) {
102818539Sedward 		hard = 1;
102918539Sedward 		v++;
103018539Sedward 	}
10311294Sbill 	if (*v == 0) {
103218539Sedward 		for (lp = limits; lp->limconst >= 0; lp++)
103318539Sedward 			if (setlim(lp, hard, (int)RLIM_INFINITY) < 0)
103418422Smckusick 				err++;
103518422Smckusick 		if (err)
103618422Smckusick 			error(NOSTR);
10371294Sbill 		return;
10381294Sbill 	}
10391294Sbill 	while (*v) {
10401294Sbill 		lp = findlim(*v++);
104118539Sedward 		if (setlim(lp, hard, (int)RLIM_INFINITY) < 0)
104218422Smckusick 			error(NOSTR);
10431294Sbill 	}
10441294Sbill }
10451294Sbill 
104618539Sedward setlim(lp, hard, limit)
10471294Sbill 	register struct limits *lp;
104818539Sedward 	char hard;
10491294Sbill {
105010032Ssam 	struct rlimit rlim;
10511294Sbill 
105217519Sedward 	(void) getrlimit(lp->limconst, &rlim);
105318539Sedward 	if (hard)
105418539Sedward 		rlim.rlim_max = limit;
105518539Sedward   	else if (limit == RLIM_INFINITY && geteuid() != 0)
105616661Smckusick  		rlim.rlim_cur = rlim.rlim_max;
105716661Smckusick  	else
105817519Sedward  		rlim.rlim_cur = limit;
105918422Smckusick 	if (setrlimit(lp->limconst, &rlim) < 0) {
106018539Sedward 		printf("%s: %s: Can't %s%s limit\n", bname, lp->limname,
106118539Sedward 		    limit == RLIM_INFINITY ? "remove" : "set",
106218539Sedward 		    hard ? " hard" : "");
106318422Smckusick 		return (-1);
106418422Smckusick 	}
106518422Smckusick 	return (0);
10661294Sbill }
10671294Sbill 
10681294Sbill dosuspend()
10691294Sbill {
107039205Sbostic 	sig_t old;
107117138Sralph 	int ldisc, ctpgrp;
10721294Sbill 
10731294Sbill 	if (loginsh)
10741294Sbill 		error("Can't suspend a login shell (yet)");
10751294Sbill 	untty();
107617138Sralph 	old = signal(SIGTSTP, SIG_DFL);
107717519Sedward 	(void) kill(0, SIGTSTP);
10781294Sbill 	/* the shell stops here */
107917519Sedward 	(void) signal(SIGTSTP, old);
10801294Sbill 	if (tpgrp != -1) {
10811294Sbill retry:
108217519Sedward 		(void) ioctl(FSHTTY, TIOCGPGRP, (char *)&ctpgrp);
10831294Sbill 		if (ctpgrp != opgrp) {
108417138Sralph 			old = signal(SIGTTIN, SIG_DFL);
108517519Sedward 			(void) kill(0, SIGTTIN);
108617519Sedward 			(void) signal(SIGTTIN, old);
10871294Sbill 			goto retry;
10881294Sbill 		}
108939545Smarc 		(void) setpgrp(0, shpgrp);
109017519Sedward 		(void) ioctl(FSHTTY, TIOCSPGRP, (char *)&shpgrp);
10911294Sbill 	}
10921294Sbill }
10931294Sbill 
10941294Sbill doeval(v)
10951294Sbill 	char **v;
10961294Sbill {
10971294Sbill 	char **oevalvec = evalvec;
10981294Sbill 	char *oevalp = evalp;
10991294Sbill 	jmp_buf osetexit;
11001294Sbill 	int reenter;
11011294Sbill 	char **gv = 0;
11021294Sbill 
11031294Sbill 	v++;
11041294Sbill 	if (*v == 0)
11051294Sbill 		return;
110617519Sedward 	gflag = 0, tglob(v);
11071294Sbill 	if (gflag) {
110847412Sbostic 		gv = v = globall(v);
11091294Sbill 		gargv = 0;
11101294Sbill 		if (v == 0)
11111294Sbill 			error("No match");
11121294Sbill 		v = copyblk(v);
11131294Sbill 	} else
111417519Sedward 		trim(v);
11151294Sbill 	getexit(osetexit);
11161294Sbill 	reenter = 0;
111747724Sbostic 	(void)setjmp(reslab);
11181294Sbill 	reenter++;
11191294Sbill 	if (reenter == 1) {
11201294Sbill 		evalvec = v;
11211294Sbill 		evalp = 0;
11221294Sbill 		process(0);
11231294Sbill 	}
11241294Sbill 	evalvec = oevalvec;
11251294Sbill 	evalp = oevalp;
11261294Sbill 	doneinp = 0;
11271294Sbill 	if (gv)
11281294Sbill 		blkfree(gv);
11291294Sbill 	resexit(osetexit);
11301294Sbill 	if (reenter >= 2)
11311294Sbill 		error(NOSTR);
11321294Sbill }
1133