xref: /csrg-svn/bin/csh/func.c (revision 1294)
1*1294Sbill static	char *sccsid = "@(#)func.c 4.1 10/09/80";
2*1294Sbill 
3*1294Sbill #include "sh.h"
4*1294Sbill #include <sys/ioctl.h>
5*1294Sbill 
6*1294Sbill /*
7*1294Sbill  * C shell
8*1294Sbill  */
9*1294Sbill 
10*1294Sbill struct biltins *
11*1294Sbill isbfunc(t)
12*1294Sbill 	register struct command *t;
13*1294Sbill {
14*1294Sbill 	register char *cp = t->t_dcom[0];
15*1294Sbill 	register char *dp;
16*1294Sbill 	register struct biltins *bp;
17*1294Sbill 	int dolabel(), dofg1(), dobg1();
18*1294Sbill 	static struct biltins label = { "", dolabel, 0, 0 };
19*1294Sbill 	static struct biltins foregnd = { "%job", dofg1, 0, 0 };
20*1294Sbill 	static struct biltins backgnd = { "%job &", dobg1, 0, 0 };
21*1294Sbill 
22*1294Sbill 	if (lastchr(cp) == ':') {
23*1294Sbill 		label.bname = cp;
24*1294Sbill 		return (&label);
25*1294Sbill 	}
26*1294Sbill 	if (*cp == '%') {
27*1294Sbill 		if (t->t_dflg & FAND) {
28*1294Sbill 			t->t_dflg &= ~FAND;
29*1294Sbill 			backgnd.bname = cp;
30*1294Sbill 			return (&backgnd);
31*1294Sbill 		}
32*1294Sbill 		foregnd.bname = cp;
33*1294Sbill 		return (&foregnd);
34*1294Sbill 	}
35*1294Sbill 	for (bp = bfunc; dp = bp->bname; bp++) {
36*1294Sbill 		if (dp[0] == cp[0] && eq(dp, cp))
37*1294Sbill 			return (bp);
38*1294Sbill 		if (dp[0] > cp[0])
39*1294Sbill 			break;
40*1294Sbill 	}
41*1294Sbill 	return (0);
42*1294Sbill }
43*1294Sbill 
44*1294Sbill func(t, bp)
45*1294Sbill 	register struct command *t;
46*1294Sbill 	register struct biltins *bp;
47*1294Sbill {
48*1294Sbill 	int i;
49*1294Sbill 
50*1294Sbill 	xechoit(t->t_dcom);
51*1294Sbill 	setname(bp->bname);
52*1294Sbill 	i = blklen(t->t_dcom) - 1;
53*1294Sbill 	if (i < bp->minargs)
54*1294Sbill 		bferr("Too few arguments");
55*1294Sbill 	if (i > bp->maxargs)
56*1294Sbill 		bferr("Too many arguments");
57*1294Sbill 	(*bp->bfunct)(t->t_dcom, t);
58*1294Sbill }
59*1294Sbill 
60*1294Sbill dolabel()
61*1294Sbill {
62*1294Sbill 
63*1294Sbill }
64*1294Sbill 
65*1294Sbill doonintr(v)
66*1294Sbill 	char **v;
67*1294Sbill {
68*1294Sbill 	register char *cp;
69*1294Sbill 	register char *vv = v[1];
70*1294Sbill 
71*1294Sbill 	if (parintr == SIG_IGN)
72*1294Sbill 		return;
73*1294Sbill 	if (setintr && intty)
74*1294Sbill 		bferr("Can't from terminal");
75*1294Sbill 	cp = gointr, gointr = 0, xfree(cp);
76*1294Sbill 	if (vv == 0) {
77*1294Sbill 		if (setintr)
78*1294Sbill 			sighold(SIGINT);
79*1294Sbill 		else
80*1294Sbill 			sigset(SIGINT, SIG_DFL);
81*1294Sbill 		gointr = 0;
82*1294Sbill 	} else if (eq((vv = strip(vv)), "-")) {
83*1294Sbill 		sigset(SIGINT, SIG_IGN);
84*1294Sbill 		gointr = "-";
85*1294Sbill 	} else {
86*1294Sbill 		gointr = savestr(vv);
87*1294Sbill 		sigset(SIGINT, pintr);
88*1294Sbill 	}
89*1294Sbill }
90*1294Sbill 
91*1294Sbill donohup()
92*1294Sbill {
93*1294Sbill 
94*1294Sbill 	if (intty)
95*1294Sbill 		bferr("Can't from terminal");
96*1294Sbill 	if (setintr == 0) {
97*1294Sbill 		signal(SIGHUP, SIG_IGN);
98*1294Sbill #ifdef CC
99*1294Sbill 		submit(getpid());
100*1294Sbill #endif
101*1294Sbill 	}
102*1294Sbill }
103*1294Sbill 
104*1294Sbill dozip()
105*1294Sbill {
106*1294Sbill 
107*1294Sbill 	;
108*1294Sbill }
109*1294Sbill 
110*1294Sbill prvars()
111*1294Sbill {
112*1294Sbill 
113*1294Sbill 	plist(&shvhed);
114*1294Sbill }
115*1294Sbill 
116*1294Sbill doalias(v)
117*1294Sbill 	register char **v;
118*1294Sbill {
119*1294Sbill 	register struct varent *vp;
120*1294Sbill 	register char *p;
121*1294Sbill 
122*1294Sbill 	v++;
123*1294Sbill 	p = *v++;
124*1294Sbill 	if (p == 0)
125*1294Sbill 		plist(&aliases);
126*1294Sbill 	else if (*v == 0) {
127*1294Sbill 		vp = adrof1(strip(p), &aliases);
128*1294Sbill 		if (vp)
129*1294Sbill 			blkpr(vp->vec), printf("\n");
130*1294Sbill 	} else {
131*1294Sbill 		if (eq(p, "alias") || eq(p, "unalias")) {
132*1294Sbill 			setname(p);
133*1294Sbill 			bferr("Too dangerous to alias that");
134*1294Sbill 		}
135*1294Sbill 		set1(strip(p), saveblk(v), &aliases);
136*1294Sbill 	}
137*1294Sbill }
138*1294Sbill 
139*1294Sbill unalias(v)
140*1294Sbill 	char **v;
141*1294Sbill {
142*1294Sbill 
143*1294Sbill 	unset1(v, &aliases);
144*1294Sbill }
145*1294Sbill 
146*1294Sbill dologout()
147*1294Sbill {
148*1294Sbill 
149*1294Sbill 	islogin();
150*1294Sbill 	goodbye();
151*1294Sbill }
152*1294Sbill 
153*1294Sbill dologin(v)
154*1294Sbill 	char **v;
155*1294Sbill {
156*1294Sbill 
157*1294Sbill 	islogin();
158*1294Sbill 	signal(SIGTERM, parterm);
159*1294Sbill 	execl("/bin/login", "login", v[1], 0);
160*1294Sbill 	untty();
161*1294Sbill 	exit(1);
162*1294Sbill }
163*1294Sbill 
164*1294Sbill donewgrp(v)
165*1294Sbill 	char **v;
166*1294Sbill {
167*1294Sbill 
168*1294Sbill 	signal(SIGTERM, parterm);
169*1294Sbill 	execl("/bin/newgrp", "newgrp", v[1], 0);
170*1294Sbill 	execl("/usr/bin/newgrp", "newgrp", v[1], 0);
171*1294Sbill 	untty();
172*1294Sbill 	exit(1);
173*1294Sbill }
174*1294Sbill 
175*1294Sbill islogin()
176*1294Sbill {
177*1294Sbill 
178*1294Sbill 	if (chkstop == 0 && setintr)
179*1294Sbill 		panystop(0);
180*1294Sbill 	if (loginsh)
181*1294Sbill 		return;
182*1294Sbill 	error("Not login shell");
183*1294Sbill }
184*1294Sbill 
185*1294Sbill doif(v, kp)
186*1294Sbill 	char **v;
187*1294Sbill 	struct command *kp;
188*1294Sbill {
189*1294Sbill 	register int i;
190*1294Sbill 	register char **vv;
191*1294Sbill 
192*1294Sbill 	v++;
193*1294Sbill 	i = exp(&v);
194*1294Sbill 	vv = v;
195*1294Sbill 	if (*vv == NOSTR)
196*1294Sbill 		bferr("Empty if");
197*1294Sbill 	if (eq(*vv, "then")) {
198*1294Sbill 		if (*++vv)
199*1294Sbill 			bferr("Improper then");
200*1294Sbill 		setname("then");
201*1294Sbill 		/*
202*1294Sbill 		 * If expression was zero, then scan to else,
203*1294Sbill 		 * otherwise just fall into following code.
204*1294Sbill 		 */
205*1294Sbill 		if (!i)
206*1294Sbill 			search(ZIF, 0);
207*1294Sbill 		return;
208*1294Sbill 	}
209*1294Sbill 	/*
210*1294Sbill 	 * Simple command attached to this if.
211*1294Sbill 	 * Left shift the node in this tree, munging it
212*1294Sbill 	 * so we can reexecute it.
213*1294Sbill 	 */
214*1294Sbill 	if (i) {
215*1294Sbill 		lshift(kp->t_dcom, vv - kp->t_dcom);
216*1294Sbill 		reexecute(kp);
217*1294Sbill 		donefds();
218*1294Sbill 	}
219*1294Sbill }
220*1294Sbill 
221*1294Sbill /*
222*1294Sbill  * Reexecute a command, being careful not
223*1294Sbill  * to redo i/o redirection, which is already set up.
224*1294Sbill  */
225*1294Sbill reexecute(kp)
226*1294Sbill 	register struct command *kp;
227*1294Sbill {
228*1294Sbill 
229*1294Sbill 	kp->t_dflg &= FSAVE;
230*1294Sbill 	kp->t_dflg |= FREDO;
231*1294Sbill 	/*
232*1294Sbill 	 * If tty is still ours to arbitrate, arbitrate it;
233*1294Sbill 	 * otherwise dont even set pgrp's as the jobs would
234*1294Sbill 	 * then have no way to get the tty (we can't give it
235*1294Sbill 	 * to them, and our parent wouldn't know their pgrp, etc.
236*1294Sbill 	 */
237*1294Sbill 	execute(kp, tpgrp > 0 ? tpgrp : -1);
238*1294Sbill }
239*1294Sbill 
240*1294Sbill doelse()
241*1294Sbill {
242*1294Sbill 
243*1294Sbill 	search(ZELSE, 0);
244*1294Sbill }
245*1294Sbill 
246*1294Sbill dogoto(v)
247*1294Sbill 	char **v;
248*1294Sbill {
249*1294Sbill 	register struct whyle *wp;
250*1294Sbill 	char *lp;
251*1294Sbill 
252*1294Sbill 	/*
253*1294Sbill 	 * While we still can, locate any unknown ends of existing loops.
254*1294Sbill 	 * This obscure code is the WORST result of the fact that we
255*1294Sbill 	 * don't really parse.
256*1294Sbill 	 */
257*1294Sbill 	for (wp = whyles; wp; wp = wp->w_next)
258*1294Sbill 		if (wp->w_end == 0) {
259*1294Sbill 			search(ZBREAK, 0);
260*1294Sbill 			wp->w_end = btell();
261*1294Sbill 		} else
262*1294Sbill 			bseek(wp->w_end);
263*1294Sbill 	search(ZGOTO, 0, lp = globone(v[1]));
264*1294Sbill 	xfree(lp);
265*1294Sbill 	/*
266*1294Sbill 	 * Eliminate loops which were exited.
267*1294Sbill 	 */
268*1294Sbill 	wfree();
269*1294Sbill }
270*1294Sbill 
271*1294Sbill doswitch(v)
272*1294Sbill 	register char **v;
273*1294Sbill {
274*1294Sbill 	register char *cp, *lp;
275*1294Sbill 
276*1294Sbill 	v++;
277*1294Sbill 	if (!*v || *(*v++) != '(')
278*1294Sbill 		goto syntax;
279*1294Sbill 	cp = **v == ')' ? "" : *v++;
280*1294Sbill 	if (*(*v++) != ')')
281*1294Sbill 		v--;
282*1294Sbill 	if (*v)
283*1294Sbill syntax:
284*1294Sbill 		error("Syntax error");
285*1294Sbill 	search(ZSWITCH, 0, lp = globone(cp));
286*1294Sbill 	xfree(lp);
287*1294Sbill }
288*1294Sbill 
289*1294Sbill dobreak()
290*1294Sbill {
291*1294Sbill 
292*1294Sbill 	if (whyles)
293*1294Sbill 		toend();
294*1294Sbill 	else
295*1294Sbill 		bferr("Not in while/foreach");
296*1294Sbill }
297*1294Sbill 
298*1294Sbill doexit(v)
299*1294Sbill 	char **v;
300*1294Sbill {
301*1294Sbill 
302*1294Sbill 	if (chkstop == 0)
303*1294Sbill 		panystop(0);
304*1294Sbill 	/*
305*1294Sbill 	 * Don't DEMAND parentheses here either.
306*1294Sbill 	 */
307*1294Sbill 	v++;
308*1294Sbill 	if (*v) {
309*1294Sbill 		set("status", putn(exp(&v)));
310*1294Sbill 		if (*v)
311*1294Sbill 			bferr("Expression syntax");
312*1294Sbill 	}
313*1294Sbill 	btoeof();
314*1294Sbill 	if (intty)
315*1294Sbill 		close(SHIN);
316*1294Sbill }
317*1294Sbill 
318*1294Sbill doforeach(v)
319*1294Sbill 	register char **v;
320*1294Sbill {
321*1294Sbill 	register char *cp;
322*1294Sbill 	register struct whyle *nwp;
323*1294Sbill 
324*1294Sbill 	v++;
325*1294Sbill 	cp = strip(*v);
326*1294Sbill 	while (*cp && letter(*cp))
327*1294Sbill 		cp++;
328*1294Sbill 	if (*cp || strlen(*v) >= 20)
329*1294Sbill 		bferr("Invalid variable");
330*1294Sbill 	cp = *v++;
331*1294Sbill 	if (v[0][0] != '(' || v[blklen(v) - 1][0] != ')')
332*1294Sbill 		bferr("Words not ()'ed");
333*1294Sbill 	v++;
334*1294Sbill 	gflag = 0, rscan(v, tglob);
335*1294Sbill 	v = glob(v);
336*1294Sbill 	if (v == 0)
337*1294Sbill 		bferr("No match");
338*1294Sbill 	nwp = (struct whyle *) calloc(1, sizeof *nwp);
339*1294Sbill 	nwp->w_fe = nwp->w_fe0 = v; gargv = 0;
340*1294Sbill 	nwp->w_start = btell();
341*1294Sbill 	nwp->w_fename = savestr(cp);
342*1294Sbill 	nwp->w_next = whyles;
343*1294Sbill 	whyles = nwp;
344*1294Sbill 	/*
345*1294Sbill 	 * Pre-read the loop so as to be more
346*1294Sbill 	 * comprehensible to a terminal user.
347*1294Sbill 	 */
348*1294Sbill 	if (intty)
349*1294Sbill 		preread();
350*1294Sbill 	doagain();
351*1294Sbill }
352*1294Sbill 
353*1294Sbill dowhile(v)
354*1294Sbill 	char **v;
355*1294Sbill {
356*1294Sbill 	register int status;
357*1294Sbill 	register bool again = whyles != 0 && whyles->w_start == lineloc &&
358*1294Sbill 	    whyles->w_fename == 0;
359*1294Sbill 
360*1294Sbill 	v++;
361*1294Sbill 	/*
362*1294Sbill 	 * Implement prereading here also, taking care not to
363*1294Sbill 	 * evaluate the expression before the loop has been read up
364*1294Sbill 	 * from a terminal.
365*1294Sbill 	 */
366*1294Sbill 	if (intty && !again)
367*1294Sbill 		status = !exp0(&v, 1);
368*1294Sbill 	else
369*1294Sbill 		status = !exp(&v);
370*1294Sbill 	if (*v)
371*1294Sbill 		bferr("Expression syntax");
372*1294Sbill 	if (!again) {
373*1294Sbill 		register struct whyle *nwp = (struct whyle *) calloc(1, sizeof (*nwp));
374*1294Sbill 
375*1294Sbill 		nwp->w_start = lineloc;
376*1294Sbill 		nwp->w_end = 0;
377*1294Sbill 		nwp->w_next = whyles;
378*1294Sbill 		whyles = nwp;
379*1294Sbill 		if (intty) {
380*1294Sbill 			/*
381*1294Sbill 			 * The tty preread
382*1294Sbill 			 */
383*1294Sbill 			preread();
384*1294Sbill 			doagain();
385*1294Sbill 			return;
386*1294Sbill 		}
387*1294Sbill 	}
388*1294Sbill 	if (status)
389*1294Sbill 		/* We ain't gonna loop no more, no more! */
390*1294Sbill 		toend();
391*1294Sbill }
392*1294Sbill 
393*1294Sbill preread()
394*1294Sbill {
395*1294Sbill 
396*1294Sbill 	whyles->w_end = -1;
397*1294Sbill 	if (setintr)
398*1294Sbill 		sigrelse(SIGINT);
399*1294Sbill 	search(ZBREAK, 0);
400*1294Sbill 	if (setintr)
401*1294Sbill 		sighold(SIGINT);
402*1294Sbill 	whyles->w_end = btell();
403*1294Sbill }
404*1294Sbill 
405*1294Sbill doend()
406*1294Sbill {
407*1294Sbill 
408*1294Sbill 	if (!whyles)
409*1294Sbill 		bferr("Not in while/foreach");
410*1294Sbill 	whyles->w_end = btell();
411*1294Sbill 	doagain();
412*1294Sbill }
413*1294Sbill 
414*1294Sbill docontin()
415*1294Sbill {
416*1294Sbill 
417*1294Sbill 	if (!whyles)
418*1294Sbill 		bferr("Not in while/foreach");
419*1294Sbill 	doagain();
420*1294Sbill }
421*1294Sbill 
422*1294Sbill doagain()
423*1294Sbill {
424*1294Sbill 
425*1294Sbill 	/* Repeating a while is simple */
426*1294Sbill 	if (whyles->w_fename == 0) {
427*1294Sbill 		bseek(whyles->w_start);
428*1294Sbill 		return;
429*1294Sbill 	}
430*1294Sbill 	/*
431*1294Sbill 	 * The foreach variable list actually has a spurious word
432*1294Sbill 	 * ")" at the end of the w_fe list.  Thus we are at the
433*1294Sbill 	 * of the list if one word beyond this is 0.
434*1294Sbill 	 */
435*1294Sbill 	if (!whyles->w_fe[1]) {
436*1294Sbill 		dobreak();
437*1294Sbill 		return;
438*1294Sbill 	}
439*1294Sbill 	set(whyles->w_fename, savestr(*whyles->w_fe++));
440*1294Sbill 	bseek(whyles->w_start);
441*1294Sbill }
442*1294Sbill 
443*1294Sbill dorepeat(v, kp)
444*1294Sbill 	char **v;
445*1294Sbill 	struct command *kp;
446*1294Sbill {
447*1294Sbill 	register int i;
448*1294Sbill 
449*1294Sbill 	i = getn(v[1]);
450*1294Sbill 	if (setintr)
451*1294Sbill 		sighold(SIGINT);
452*1294Sbill 	lshift(v, 2);
453*1294Sbill 	while (i > 0) {
454*1294Sbill 		if (setintr)
455*1294Sbill 			sigrelse(SIGINT);
456*1294Sbill 		reexecute(kp);
457*1294Sbill 		--i;
458*1294Sbill 	}
459*1294Sbill 	donefds();
460*1294Sbill 	if (setintr)
461*1294Sbill 		sigrelse(SIGINT);
462*1294Sbill }
463*1294Sbill 
464*1294Sbill doswbrk()
465*1294Sbill {
466*1294Sbill 
467*1294Sbill 	search(ZBRKSW, 0);
468*1294Sbill }
469*1294Sbill 
470*1294Sbill srchx(cp)
471*1294Sbill 	register char *cp;
472*1294Sbill {
473*1294Sbill 	register struct srch *sp;
474*1294Sbill 
475*1294Sbill 	for (sp = srchn; sp->s_name; sp++)
476*1294Sbill 		if (eq(cp, sp->s_name))
477*1294Sbill 			return (sp->s_value);
478*1294Sbill 	return (-1);
479*1294Sbill }
480*1294Sbill 
481*1294Sbill char	Stype;
482*1294Sbill char	*Sgoal;
483*1294Sbill 
484*1294Sbill /*VARARGS2*/
485*1294Sbill search(type, level, goal)
486*1294Sbill 	int type;
487*1294Sbill 	register int level;
488*1294Sbill 	char *goal;
489*1294Sbill {
490*1294Sbill 	char wordbuf[BUFSIZ];
491*1294Sbill 	register char *aword = wordbuf;
492*1294Sbill 	register char *cp;
493*1294Sbill 
494*1294Sbill 	Stype = type; Sgoal = goal;
495*1294Sbill 	if (type == ZGOTO)
496*1294Sbill 		bseek(0l);
497*1294Sbill 	do {
498*1294Sbill 		if (intty && fseekp == feobp)
499*1294Sbill 			printf("? "), flush();
500*1294Sbill 		aword[0] = 0, getword(aword);
501*1294Sbill 		switch (srchx(aword)) {
502*1294Sbill 
503*1294Sbill 		case ZELSE:
504*1294Sbill 			if (level == 0 && type == ZIF)
505*1294Sbill 				return;
506*1294Sbill 			break;
507*1294Sbill 
508*1294Sbill 		case ZIF:
509*1294Sbill 			while (getword(aword))
510*1294Sbill 				continue;
511*1294Sbill 			if ((type == ZIF || type == ZELSE) && eq(aword, "then"))
512*1294Sbill 				level++;
513*1294Sbill 			break;
514*1294Sbill 
515*1294Sbill 		case ZENDIF:
516*1294Sbill 			if (type == ZIF || type == ZELSE)
517*1294Sbill 				level--;
518*1294Sbill 			break;
519*1294Sbill 
520*1294Sbill 		case ZFOREACH:
521*1294Sbill 		case ZWHILE:
522*1294Sbill 			if (type == ZBREAK)
523*1294Sbill 				level++;
524*1294Sbill 			break;
525*1294Sbill 
526*1294Sbill 		case ZEND:
527*1294Sbill 			if (type == ZBREAK)
528*1294Sbill 				level--;
529*1294Sbill 			break;
530*1294Sbill 
531*1294Sbill 		case ZSWITCH:
532*1294Sbill 			if (type == ZSWITCH || type == ZBRKSW)
533*1294Sbill 				level++;
534*1294Sbill 			break;
535*1294Sbill 
536*1294Sbill 		case ZENDSW:
537*1294Sbill 			if (type == ZSWITCH || type == ZBRKSW)
538*1294Sbill 				level--;
539*1294Sbill 			break;
540*1294Sbill 
541*1294Sbill 		case ZLABEL:
542*1294Sbill 			if (type == ZGOTO && getword(aword) && eq(aword, goal))
543*1294Sbill 				level = -1;
544*1294Sbill 			break;
545*1294Sbill 
546*1294Sbill 		default:
547*1294Sbill 			if (type != ZGOTO && (type != ZSWITCH || level != 0))
548*1294Sbill 				break;
549*1294Sbill 			if (lastchr(aword) != ':')
550*1294Sbill 				break;
551*1294Sbill 			aword[strlen(aword) - 1] = 0;
552*1294Sbill 			if (type == ZGOTO && eq(aword, goal) || type == ZSWITCH && eq(aword, "default"))
553*1294Sbill 				level = -1;
554*1294Sbill 			break;
555*1294Sbill 
556*1294Sbill 		case ZCASE:
557*1294Sbill 			if (type != ZSWITCH || level != 0)
558*1294Sbill 				break;
559*1294Sbill 			getword(aword);
560*1294Sbill 			if (lastchr(aword) == ':')
561*1294Sbill 				aword[strlen(aword) - 1] = 0;
562*1294Sbill 			cp = strip(Dfix1(aword));
563*1294Sbill 			if (Gmatch(goal, cp))
564*1294Sbill 				level = -1;
565*1294Sbill 			xfree(cp);
566*1294Sbill 			break;
567*1294Sbill 
568*1294Sbill 		case ZDEFAULT:
569*1294Sbill 			if (type == ZSWITCH && level == 0)
570*1294Sbill 				level = -1;
571*1294Sbill 			break;
572*1294Sbill 		}
573*1294Sbill 		getword(NOSTR);
574*1294Sbill 	} while (level >= 0);
575*1294Sbill }
576*1294Sbill 
577*1294Sbill getword(wp)
578*1294Sbill 	register char *wp;
579*1294Sbill {
580*1294Sbill 	register int found = 0;
581*1294Sbill 	register int c, d;
582*1294Sbill 
583*1294Sbill 	c = readc(1);
584*1294Sbill 	d = 0;
585*1294Sbill 	do {
586*1294Sbill 		while (c == ' ' || c == '\t')
587*1294Sbill 			c = readc(1);
588*1294Sbill 		if (c < 0)
589*1294Sbill 			goto past;
590*1294Sbill 		if (c == '\n') {
591*1294Sbill 			if (wp)
592*1294Sbill 				break;
593*1294Sbill 			return (0);
594*1294Sbill 		}
595*1294Sbill 		unreadc(c);
596*1294Sbill 		found = 1;
597*1294Sbill 		do {
598*1294Sbill 			c = readc(1);
599*1294Sbill 			if (c == '\\' && (c = readc(1)) == '\n')
600*1294Sbill 				c = ' ';
601*1294Sbill 			if (any(c, "'\""))
602*1294Sbill 				if (d == 0)
603*1294Sbill 					d = c;
604*1294Sbill 				else if (d == c)
605*1294Sbill 					d = 0;
606*1294Sbill 			if (c < 0)
607*1294Sbill 				goto past;
608*1294Sbill 			if (wp)
609*1294Sbill 				*wp++ = c;
610*1294Sbill 		} while ((d || c != ' ' && c != '\t') && c != '\n');
611*1294Sbill 	} while (wp == 0);
612*1294Sbill 	unreadc(c);
613*1294Sbill 	if (found)
614*1294Sbill 		*--wp = 0;
615*1294Sbill 	return (found);
616*1294Sbill 
617*1294Sbill past:
618*1294Sbill 	switch (Stype) {
619*1294Sbill 
620*1294Sbill 	case ZIF:
621*1294Sbill 		bferr("then/endif not found");
622*1294Sbill 
623*1294Sbill 	case ZELSE:
624*1294Sbill 		bferr("endif not found");
625*1294Sbill 
626*1294Sbill 	case ZBRKSW:
627*1294Sbill 	case ZSWITCH:
628*1294Sbill 		bferr("endsw not found");
629*1294Sbill 
630*1294Sbill 	case ZBREAK:
631*1294Sbill 		bferr("end not found");
632*1294Sbill 
633*1294Sbill 	case ZGOTO:
634*1294Sbill 		setname(Sgoal);
635*1294Sbill 		bferr("label not found");
636*1294Sbill 	}
637*1294Sbill 	/*NOTREACHED*/
638*1294Sbill }
639*1294Sbill 
640*1294Sbill toend()
641*1294Sbill {
642*1294Sbill 
643*1294Sbill 	if (whyles->w_end == 0) {
644*1294Sbill 		search(ZBREAK, 0);
645*1294Sbill 		whyles->w_end = btell() - 1;
646*1294Sbill 	} else
647*1294Sbill 		bseek(whyles->w_end);
648*1294Sbill 	wfree();
649*1294Sbill }
650*1294Sbill 
651*1294Sbill wfree()
652*1294Sbill {
653*1294Sbill 	long o = btell();
654*1294Sbill 
655*1294Sbill 	while (whyles) {
656*1294Sbill 		register struct whyle *wp = whyles;
657*1294Sbill 		register struct whyle *nwp = wp->w_next;
658*1294Sbill 
659*1294Sbill 		if (o >= wp->w_start && (wp->w_end == 0 || o < wp->w_end))
660*1294Sbill 			break;
661*1294Sbill 		if (wp->w_fe0)
662*1294Sbill 			blkfree(wp->w_fe0);
663*1294Sbill 		if (wp->w_fename)
664*1294Sbill 			xfree(wp->w_fename);
665*1294Sbill 		xfree((char *)wp);
666*1294Sbill 		whyles = nwp;
667*1294Sbill 	}
668*1294Sbill }
669*1294Sbill 
670*1294Sbill doecho(v)
671*1294Sbill 	char **v;
672*1294Sbill {
673*1294Sbill 
674*1294Sbill 	echo(' ', v);
675*1294Sbill }
676*1294Sbill 
677*1294Sbill doglob(v)
678*1294Sbill 	char **v;
679*1294Sbill {
680*1294Sbill 
681*1294Sbill 	echo(0, v);
682*1294Sbill 	flush();
683*1294Sbill }
684*1294Sbill 
685*1294Sbill echo(sep, v)
686*1294Sbill 	char sep;
687*1294Sbill 	register char **v;
688*1294Sbill {
689*1294Sbill 	register char *cp;
690*1294Sbill 	int nonl = 0;
691*1294Sbill 
692*1294Sbill 	if (setintr)
693*1294Sbill 		sigrelse(SIGINT);
694*1294Sbill 	v++;
695*1294Sbill 	if (*v == 0)
696*1294Sbill 		return;
697*1294Sbill 	gflag = 0; rscan(v, tglob);
698*1294Sbill 	if (gflag) {
699*1294Sbill 		v = glob(v);
700*1294Sbill 		if (v == 0)
701*1294Sbill 			bferr("No match");
702*1294Sbill 	} else
703*1294Sbill 		scan(v, trim);
704*1294Sbill 	if (sep == ' ' && !strcmp(*v, "-n"))
705*1294Sbill 		nonl++, v++;
706*1294Sbill 	while (cp = *v++) {
707*1294Sbill 		register int c;
708*1294Sbill 
709*1294Sbill 		while (c = *cp++)
710*1294Sbill 			putchar(c | QUOTE);
711*1294Sbill 		if (*v)
712*1294Sbill 			putchar(sep | QUOTE);
713*1294Sbill 	}
714*1294Sbill 	if (sep && nonl == 0)
715*1294Sbill 		putchar('\n');
716*1294Sbill 	else
717*1294Sbill 		flush();
718*1294Sbill 	if (setintr)
719*1294Sbill 		sighold(SIGINT);
720*1294Sbill 	if (gargv)
721*1294Sbill 		blkfree(gargv), gargv = 0;
722*1294Sbill }
723*1294Sbill 
724*1294Sbill char	**environ;
725*1294Sbill 
726*1294Sbill dosetenv(v)
727*1294Sbill 	register char **v;
728*1294Sbill {
729*1294Sbill 	char *lp = globone(v[2]);
730*1294Sbill 
731*1294Sbill 	setenv(v[1], lp);
732*1294Sbill 	if (eq(v[1], "PATH")) {
733*1294Sbill 		importpath(lp);
734*1294Sbill 		dohash();
735*1294Sbill 	}
736*1294Sbill 	xfree(lp);
737*1294Sbill }
738*1294Sbill 
739*1294Sbill dounsetenv(v)
740*1294Sbill 	register char **v;
741*1294Sbill {
742*1294Sbill 
743*1294Sbill 	v++;
744*1294Sbill 	do
745*1294Sbill 		unsetenv(*v++);
746*1294Sbill 	while (*v);
747*1294Sbill }
748*1294Sbill 
749*1294Sbill setenv(name, value)
750*1294Sbill 	char *name, *value;
751*1294Sbill {
752*1294Sbill 	register char **ep = environ;
753*1294Sbill 	register char *cp, *dp;
754*1294Sbill 	char *blk[2], **oep = ep;
755*1294Sbill 
756*1294Sbill 	for (; *ep; ep++) {
757*1294Sbill 		for (cp = name, dp = *ep; *cp && *cp == *dp; cp++, dp++)
758*1294Sbill 			continue;
759*1294Sbill 		if (*cp != 0 || *dp != '=')
760*1294Sbill 			continue;
761*1294Sbill 		cp = strspl("=", value);
762*1294Sbill 		xfree(*ep);
763*1294Sbill 		*ep = strspl(name, cp);
764*1294Sbill 		xfree(cp);
765*1294Sbill 		scan(ep, trim);
766*1294Sbill 		return;
767*1294Sbill 	}
768*1294Sbill 	blk[0] = strspl(name, "="); blk[1] = 0;
769*1294Sbill 	environ = blkspl(environ, blk);
770*1294Sbill 	xfree((char *)oep);
771*1294Sbill 	setenv(name, value);
772*1294Sbill }
773*1294Sbill 
774*1294Sbill unsetenv(name)
775*1294Sbill 	char *name;
776*1294Sbill {
777*1294Sbill 	register char **ep = environ;
778*1294Sbill 	register char *cp, *dp;
779*1294Sbill 	char **oep = ep;
780*1294Sbill 
781*1294Sbill 	for (; *ep; ep++) {
782*1294Sbill 		for (cp = name, dp = *ep; *cp && *cp == *dp; cp++, dp++)
783*1294Sbill 			continue;
784*1294Sbill 		if (*cp != 0 || *dp != '=')
785*1294Sbill 			continue;
786*1294Sbill 		cp = *ep;
787*1294Sbill 		*ep = 0;
788*1294Sbill 		environ = blkspl(environ, ep+1);
789*1294Sbill 		*ep = cp;
790*1294Sbill 		xfree(cp);
791*1294Sbill 		xfree((char *)oep);
792*1294Sbill 		return;
793*1294Sbill 	}
794*1294Sbill }
795*1294Sbill 
796*1294Sbill doumask(v)
797*1294Sbill 	register char **v;
798*1294Sbill {
799*1294Sbill 	register char *cp = v[1];
800*1294Sbill 	register int i;
801*1294Sbill 
802*1294Sbill 	if (cp == 0) {
803*1294Sbill 		i = umask(0);
804*1294Sbill 		umask(i);
805*1294Sbill 		printf("%o\n", i);
806*1294Sbill 		return;
807*1294Sbill 	}
808*1294Sbill 	i = 0;
809*1294Sbill 	while (digit(*cp) && *cp != '8' && *cp != '9')
810*1294Sbill 		i = i * 8 + *cp++ - '0';
811*1294Sbill 	if (*cp || i < 0 || i > 0777)
812*1294Sbill 		bferr("Improper mask");
813*1294Sbill 	umask(i);
814*1294Sbill }
815*1294Sbill 
816*1294Sbill #include <sys/limit.h>
817*1294Sbill 
818*1294Sbill struct limits {
819*1294Sbill 	int	limconst;
820*1294Sbill 	char	*limname;
821*1294Sbill 	int	limdiv;
822*1294Sbill 	char	*limscale;
823*1294Sbill } limits[] = {
824*1294Sbill 	LIM_NORAISE,	"noraise",	1,	"",
825*1294Sbill 	LIM_CPU,	"cputime",	1,	"seconds",
826*1294Sbill 	LIM_FSIZE,	"filesize",	1024,	"kbytes",
827*1294Sbill 	LIM_DATA,	"datasize",	1024,	"kbytes",
828*1294Sbill 	LIM_STACK,	"stacksize",	1024,	"kbytes",
829*1294Sbill 	LIM_CORE,	"coredumpsize",	1024,	"kbytes",
830*1294Sbill 	-1,		0,
831*1294Sbill };
832*1294Sbill 
833*1294Sbill struct limits *
834*1294Sbill findlim(cp)
835*1294Sbill 	char *cp;
836*1294Sbill {
837*1294Sbill 	register struct limits *lp, *res;
838*1294Sbill 
839*1294Sbill 	res = 0;
840*1294Sbill 	for (lp = limits; lp->limconst >= 0; lp++)
841*1294Sbill 		if (prefix(cp, lp->limname)) {
842*1294Sbill 			if (res)
843*1294Sbill 				bferr("Ambiguous");
844*1294Sbill 			res = lp;
845*1294Sbill 		}
846*1294Sbill 	if (res)
847*1294Sbill 		return (res);
848*1294Sbill 	bferr("No such limit");
849*1294Sbill }
850*1294Sbill 
851*1294Sbill dolimit(v)
852*1294Sbill 	register char **v;
853*1294Sbill {
854*1294Sbill 	register struct limits *lp;
855*1294Sbill 	register int limit;
856*1294Sbill 
857*1294Sbill 	v++;
858*1294Sbill 	if (*v == 0) {
859*1294Sbill 		for (lp = limits+1; lp->limconst >= 0; lp++)
860*1294Sbill 			plim(lp);
861*1294Sbill 		if (vlimit(LIM_NORAISE, -1) && getuid())
862*1294Sbill 			printf("Limits cannot be raised\n");
863*1294Sbill 		return;
864*1294Sbill 	}
865*1294Sbill 	lp = findlim(v[0]);
866*1294Sbill 	if (v[1] == 0) {
867*1294Sbill 		plim(lp);
868*1294Sbill 		return;
869*1294Sbill 	}
870*1294Sbill 	limit = getval(lp, v+1);
871*1294Sbill 	setlim(lp, limit);
872*1294Sbill }
873*1294Sbill 
874*1294Sbill getval(lp, v)
875*1294Sbill 	register struct limits *lp;
876*1294Sbill 	char **v;
877*1294Sbill {
878*1294Sbill 	register float f;
879*1294Sbill 	double atof();
880*1294Sbill 	char *cp = *v++;
881*1294Sbill 
882*1294Sbill 	f = atof(cp);
883*1294Sbill 	while (digit(*cp) || *cp == '.' || *cp == 'e' || *cp == 'E')
884*1294Sbill 		cp++;
885*1294Sbill 	if (*cp == 0) {
886*1294Sbill 		if (*v == 0)
887*1294Sbill 			return ((int)(f+0.5) * lp->limdiv);
888*1294Sbill 		cp = *v;
889*1294Sbill 	}
890*1294Sbill 	if (lp->limconst == LIM_NORAISE)
891*1294Sbill 		goto badscal;
892*1294Sbill 	switch (*cp) {
893*1294Sbill 
894*1294Sbill 	case ':':
895*1294Sbill 		if (lp->limconst != LIM_CPU)
896*1294Sbill 			goto badscal;
897*1294Sbill 		return ((int)(f * 60.0 + atof(cp+1)));
898*1294Sbill 
899*1294Sbill 	case 'h':
900*1294Sbill 		if (lp->limconst != LIM_CPU)
901*1294Sbill 			goto badscal;
902*1294Sbill 		limtail(cp, "hours");
903*1294Sbill 		f *= 3600.;
904*1294Sbill 		break;
905*1294Sbill 
906*1294Sbill 	case 'm':
907*1294Sbill 		if (lp->limconst == LIM_CPU) {
908*1294Sbill 			limtail(cp, "minutes");
909*1294Sbill 			f *= 60.;
910*1294Sbill 			break;
911*1294Sbill 		}
912*1294Sbill 	case 'M':
913*1294Sbill 		if (lp->limconst == LIM_CPU)
914*1294Sbill 			goto badscal;
915*1294Sbill 		*cp = 'm';
916*1294Sbill 		limtail(cp, "megabytes");
917*1294Sbill 		f *= 1024.*1024.;
918*1294Sbill 		break;
919*1294Sbill 
920*1294Sbill 	case 's':
921*1294Sbill 		if (lp->limconst != LIM_CPU)
922*1294Sbill 			goto badscal;
923*1294Sbill 		limtail(cp, "seconds");
924*1294Sbill 		break;
925*1294Sbill 
926*1294Sbill 	case 'k':
927*1294Sbill 		if (lp->limconst == LIM_CPU)
928*1294Sbill 			goto badscal;
929*1294Sbill 		limtail(cp, "kbytes");
930*1294Sbill 		f *= 1024;
931*1294Sbill 		break;
932*1294Sbill 
933*1294Sbill 	case 'u':
934*1294Sbill 		limtail(cp, "unlimited");
935*1294Sbill 		return (INFINITY);
936*1294Sbill 
937*1294Sbill 	default:
938*1294Sbill badscal:
939*1294Sbill 		bferr("Improper or unknown scale factor");
940*1294Sbill 	}
941*1294Sbill 	return ((int)(f+0.5));
942*1294Sbill }
943*1294Sbill 
944*1294Sbill limtail(cp, str0)
945*1294Sbill 	char *cp, *str0;
946*1294Sbill {
947*1294Sbill 	register char *str = str0;
948*1294Sbill 
949*1294Sbill 	while (*cp && *cp == *str)
950*1294Sbill 		cp++, str++;
951*1294Sbill 	if (*cp)
952*1294Sbill 		error("Bad scaling; did you mean ``%s''?", str0);
953*1294Sbill }
954*1294Sbill 
955*1294Sbill plim(lp)
956*1294Sbill 	register struct limits *lp;
957*1294Sbill {
958*1294Sbill 	register int lim;
959*1294Sbill 
960*1294Sbill 	printf("%s \t", lp->limname);
961*1294Sbill 	lim = vlimit(lp->limconst, -1);
962*1294Sbill 	if (lim == INFINITY)
963*1294Sbill 		printf("unlimited");
964*1294Sbill 	else if (lp->limconst == LIM_CPU)
965*1294Sbill 		psecs((long)lim);
966*1294Sbill 	else
967*1294Sbill 		printf("%d %s", lim / lp->limdiv, lp->limscale);
968*1294Sbill 	printf("\n");
969*1294Sbill }
970*1294Sbill 
971*1294Sbill dounlimit(v)
972*1294Sbill 	register char **v;
973*1294Sbill {
974*1294Sbill 	register struct limits *lp;
975*1294Sbill 
976*1294Sbill 	v++;
977*1294Sbill 	if (*v == 0) {
978*1294Sbill 		for (lp = limits+1; lp->limconst >= 0; lp++)
979*1294Sbill 			setlim(lp, INFINITY);
980*1294Sbill 		return;
981*1294Sbill 	}
982*1294Sbill 	while (*v) {
983*1294Sbill 		lp = findlim(*v++);
984*1294Sbill 		setlim(lp, INFINITY);
985*1294Sbill 	}
986*1294Sbill }
987*1294Sbill 
988*1294Sbill setlim(lp, limit)
989*1294Sbill 	register struct limits *lp;
990*1294Sbill {
991*1294Sbill 
992*1294Sbill 	if (vlimit(lp->limconst, limit) < 0)
993*1294Sbill 		Perror(bname);
994*1294Sbill }
995*1294Sbill 
996*1294Sbill dosuspend()
997*1294Sbill {
998*1294Sbill 	int old, ldisc;
999*1294Sbill 	short ctpgrp;
1000*1294Sbill 
1001*1294Sbill 	if (loginsh)
1002*1294Sbill 		error("Can't suspend a login shell (yet)");
1003*1294Sbill 	untty();
1004*1294Sbill 	old = sigsys(SIGTSTP, SIG_DFL);
1005*1294Sbill 	kill(0, SIGTSTP);
1006*1294Sbill 	/* the shell stops here */
1007*1294Sbill 	sigsys(SIGTSTP, old);
1008*1294Sbill 	if (tpgrp != -1) {
1009*1294Sbill retry:
1010*1294Sbill 		ioctl(FSHTTY, TIOCGPGRP, &ctpgrp);
1011*1294Sbill 		if (ctpgrp != opgrp) {
1012*1294Sbill 			old = sigsys(SIGTTIN, SIG_DFL);
1013*1294Sbill 			kill(0, SIGTTIN);
1014*1294Sbill 			sigsys(SIGTTIN, old);
1015*1294Sbill 			goto retry;
1016*1294Sbill 		}
1017*1294Sbill 		ioctl(FSHTTY, TIOCSPGRP, &shpgrp);
1018*1294Sbill 		setpgrp(0, shpgrp);
1019*1294Sbill 	}
1020*1294Sbill 	ioctl(FSHTTY, TIOCGETD, &oldisc);
1021*1294Sbill 	if (oldisc != NTTYDISC) {
1022*1294Sbill 		printf("Switching to new tty driver...\n");
1023*1294Sbill 		ldisc = NTTYDISC;
1024*1294Sbill 		ioctl(FSHTTY, TIOCSETD, &ldisc);
1025*1294Sbill 	}
1026*1294Sbill }
1027*1294Sbill 
1028*1294Sbill doeval(v)
1029*1294Sbill 	char **v;
1030*1294Sbill {
1031*1294Sbill 	char **oevalvec = evalvec;
1032*1294Sbill 	char *oevalp = evalp;
1033*1294Sbill 	jmp_buf osetexit;
1034*1294Sbill 	int reenter;
1035*1294Sbill 	char **gv = 0;
1036*1294Sbill 
1037*1294Sbill 	v++;
1038*1294Sbill 	if (*v == 0)
1039*1294Sbill 		return;
1040*1294Sbill 	gflag = 0; rscan(v, tglob);
1041*1294Sbill 	if (gflag) {
1042*1294Sbill 		gv = v = glob(v);
1043*1294Sbill 		gargv = 0;
1044*1294Sbill 		if (v == 0)
1045*1294Sbill 			error("No match");
1046*1294Sbill 		v = copyblk(v);
1047*1294Sbill 	} else
1048*1294Sbill 		scan(v, trim);
1049*1294Sbill 	getexit(osetexit);
1050*1294Sbill 	reenter = 0;
1051*1294Sbill 	setexit();
1052*1294Sbill 	reenter++;
1053*1294Sbill 	if (reenter == 1) {
1054*1294Sbill 		evalvec = v;
1055*1294Sbill 		evalp = 0;
1056*1294Sbill 		process(0);
1057*1294Sbill 	}
1058*1294Sbill 	evalvec = oevalvec;
1059*1294Sbill 	evalp = oevalp;
1060*1294Sbill 	doneinp = 0;
1061*1294Sbill 	if (gv)
1062*1294Sbill 		blkfree(gv);
1063*1294Sbill 	resexit(osetexit);
1064*1294Sbill 	if (reenter >= 2)
1065*1294Sbill 		error(NOSTR);
1066*1294Sbill }
1067