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