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