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