xref: /original-bsd/bin/csh/func.c (revision 35d77a20)
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.19 (Berkeley) 06/08/91";
10 #endif /* not lint */
11 
12 #include <sys/types.h>
13 #include <sys/stat.h>
14 #include <signal.h>
15 #include <locale.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <unistd.h>
19 #if __STDC__
20 # include <stdarg.h>
21 #else
22 # include <varargs.h>
23 #endif
24 
25 #include "csh.h"
26 #include "extern.h"
27 #include "pathnames.h"
28 
29 extern char **environ;
30 
31 static int zlast = -1;
32 static void	islogin __P((void));
33 static void	reexecute __P((struct command *));
34 static void	preread __P((void));
35 static void	doagain __P((void));
36 static int	getword __P((Char *));
37 static int	keyword __P((Char *));
38 static void	Unsetenv __P((Char *));
39 static void	toend __P((void));
40 static void	xecho __P((int, Char **));
41 
42 struct biltins *
43 isbfunc(t)
44     struct command *t;
45 {
46     register Char *cp = t->t_dcom[0];
47     register struct biltins *bp, *bp1, *bp2;
48     static struct biltins label = {"", dozip, 0, 0};
49     static struct biltins foregnd = {"%job", dofg1, 0, 0};
50     static struct biltins backgnd = {"%job &", dobg1, 0, 0};
51 
52     if (lastchr(cp) == ':') {
53 	label.bname = short2str(cp);
54 	return (&label);
55     }
56     if (*cp == '%') {
57 	if (t->t_dflg & F_AMPERSAND) {
58 	    t->t_dflg &= ~F_AMPERSAND;
59 	    backgnd.bname = short2str(cp);
60 	    return (&backgnd);
61 	}
62 	foregnd.bname = short2str(cp);
63 	return (&foregnd);
64     }
65     /*
66      * Binary search Bp1 is the beginning of the current search range. Bp2 is
67      * one past the end.
68      */
69     for (bp1 = bfunc, bp2 = bfunc + nbfunc; bp1 < bp2;) {
70 	register i;
71 
72 	bp = bp1 + ((bp2 - bp1) >> 1);
73 	if ((i = *cp - *bp->bname) == 0 &&
74 	    (i = Strcmp(cp, str2short(bp->bname))) == 0)
75 	    return bp;
76 	if (i < 0)
77 	    bp2 = bp;
78 	else
79 	    bp1 = bp + 1;
80     }
81     return (0);
82 }
83 
84 void
85 func(t, bp)
86     register struct command *t;
87     register struct biltins *bp;
88 {
89     int     i;
90 
91     xechoit(t->t_dcom);
92     setname(bp->bname);
93     i = blklen(t->t_dcom) - 1;
94     if (i < bp->minargs)
95 	stderror(ERR_NAME | ERR_TOOFEW);
96     if (i > bp->maxargs)
97 	stderror(ERR_NAME | ERR_TOOMANY);
98     (*bp->bfunct) (t->t_dcom, t);
99 }
100 
101 void
102 doonintr(v)
103     Char  **v;
104 {
105     register Char *cp;
106     register Char *vv = v[1];
107 
108     if (parintr == SIG_IGN)
109 	return;
110     if (setintr && intty)
111 	stderror(ERR_NAME | ERR_TERMINAL);
112     cp = gointr;
113     gointr = 0;
114     xfree((ptr_t) cp);
115     if (vv == 0) {
116 	if (setintr)
117 	    (void) sigblock(sigmask(SIGINT));
118 	else
119 	    (void) signal(SIGINT, SIG_DFL);
120 	gointr = 0;
121     }
122     else if (eq((vv = strip(vv)), STRminus)) {
123 	(void) signal(SIGINT, SIG_IGN);
124 	gointr = Strsave(STRminus);
125     }
126     else {
127 	gointr = Strsave(vv);
128 	(void) signal(SIGINT, pintr);
129     }
130 }
131 
132 void
133 donohup()
134 {
135     if (intty)
136 	stderror(ERR_NAME | ERR_TERMINAL);
137     if (setintr == 0) {
138 	(void) signal(SIGHUP, SIG_IGN);
139     }
140 }
141 
142 void
143 dozip()
144 {
145     ;
146 }
147 
148 void
149 prvars()
150 {
151     plist(&shvhed);
152 }
153 
154 void
155 doalias(v)
156     register Char **v;
157 {
158     register struct varent *vp;
159     register Char *p;
160 
161     v++;
162     p = *v++;
163     if (p == 0)
164 	plist(&aliases);
165     else if (*v == 0) {
166 	vp = adrof1(strip(p), &aliases);
167 	if (vp)
168 	    blkpr(vp->vec), xprintf("\n");
169     }
170     else {
171 	if (eq(p, STRalias) || eq(p, STRunalias)) {
172 	    setname(short2str(p));
173 	    stderror(ERR_NAME | ERR_DANGER);
174 	}
175 	set1(strip(p), saveblk(v), &aliases);
176     }
177 }
178 
179 void
180 unalias(v)
181     Char  **v;
182 {
183     unset1(v, &aliases);
184 }
185 
186 void
187 dologout()
188 {
189     islogin();
190     goodbye();
191 }
192 
193 void
194 dologin(v)
195     Char  **v;
196 {
197     islogin();
198     rechist();
199     (void) signal(SIGTERM, parterm);
200     (void) execl(_PATH_LOGIN, "login", short2str(v[1]), NULL);
201     untty();
202     xexit(1);
203 }
204 
205 static void
206 islogin()
207 {
208     if (chkstop == 0 && setintr)
209 	panystop(0);
210     if (loginsh)
211 	return;
212     stderror(ERR_NOTLOGIN);
213 }
214 
215 void
216 doif(v, kp)
217     Char  **v;
218     struct command *kp;
219 {
220     register int i;
221     register Char **vv;
222 
223     v++;
224     i = exp(&v);
225     vv = v;
226     if (*vv == NULL)
227 	stderror(ERR_NAME | ERR_EMPTYIF);
228     if (eq(*vv, STRthen)) {
229 	if (*++vv)
230 	    stderror(ERR_NAME | ERR_IMPRTHEN);
231 	setname(short2str(STRthen));
232 	/*
233 	 * If expression was zero, then scan to else, otherwise just fall into
234 	 * following code.
235 	 */
236 	if (!i)
237 	    search(T_IF, 0, NULL);
238 	return;
239     }
240     /*
241      * Simple command attached to this if. Left shift the node in this tree,
242      * munging it so we can reexecute it.
243      */
244     if (i) {
245 	lshift(kp->t_dcom, vv - kp->t_dcom);
246 	reexecute(kp);
247 	donefds();
248     }
249 }
250 
251 /*
252  * Reexecute a command, being careful not
253  * to redo i/o redirection, which is already set up.
254  */
255 static void
256 reexecute(kp)
257     register struct command *kp;
258 {
259     kp->t_dflg &= F_SAVE;
260     kp->t_dflg |= F_REPEAT;
261     /*
262      * If tty is still ours to arbitrate, arbitrate it; otherwise dont even set
263      * pgrp's as the jobs would then have no way to get the tty (we can't give
264      * it to them, and our parent wouldn't know their pgrp, etc.
265      */
266     execute(kp, (tpgrp > 0 ? tpgrp : -1), NULL, NULL);
267 }
268 
269 void
270 doelse()
271 {
272     search(T_ELSE, 0, NULL);
273 }
274 
275 void
276 dogoto(v)
277     Char  **v;
278 {
279     register struct whyle *wp;
280     Char   *lp;
281 
282     /*
283      * While we still can, locate any unknown ends of existing loops. This
284      * obscure code is the WORST result of the fact that we don't really parse.
285      */
286     zlast = T_GOTO;
287     for (wp = whyles; wp; wp = wp->w_next)
288 	if (wp->w_end == 0) {
289 	    search(T_BREAK, 0, NULL);
290 	    wp->w_end = fseekp;
291 	}
292 	else
293 	    bseek(wp->w_end);
294     search(T_GOTO, 0, lp = globone(v[1], G_ERROR));
295     xfree((ptr_t) lp);
296     /*
297      * Eliminate loops which were exited.
298      */
299     wfree();
300 }
301 
302 void
303 doswitch(v)
304     register Char **v;
305 {
306     register Char *cp, *lp;
307 
308     v++;
309     if (!*v || *(*v++) != '(')
310 	stderror(ERR_SYNTAX);
311     cp = **v == ')' ? STRNULL : *v++;
312     if (*(*v++) != ')')
313 	v--;
314     if (*v)
315 	stderror(ERR_SYNTAX);
316     search(T_SWITCH, 0, lp = globone(cp, G_ERROR));
317     xfree((ptr_t) lp);
318 }
319 
320 void
321 dobreak()
322 {
323     if (whyles)
324 	toend();
325     else
326 	stderror(ERR_NAME | ERR_NOTWHILE);
327 }
328 
329 void
330 doexit(v)
331     Char  **v;
332 {
333     if (chkstop == 0 && (intty || intact) && evalvec == 0)
334 	panystop(0);
335     /*
336      * Don't DEMAND parentheses here either.
337      */
338     v++;
339     if (*v) {
340 	set(STRstatus, putn(exp(&v)));
341 	if (*v)
342 	    stderror(ERR_NAME | ERR_EXPRESSION);
343     }
344     btoeof();
345     if (intty)
346 	(void) close(SHIN);
347 }
348 
349 void
350 doforeach(v)
351     register Char **v;
352 {
353     register Char *cp, *sp;
354     register struct whyle *nwp;
355 
356     v++;
357     sp = cp = strip(*v);
358     if (!letter(*sp))
359 	stderror(ERR_NAME | ERR_VARBEGIN);
360     while (*cp && alnum(*cp))
361 	cp++;
362     if (*cp)
363 	stderror(ERR_NAME | ERR_VARALNUM);
364     if ((cp - sp) > MAXVARLEN)
365 	stderror(ERR_NAME | ERR_VARTOOLONG);
366     cp = *v++;
367     if (v[0][0] != '(' || v[blklen(v) - 1][0] != ')')
368 	stderror(ERR_NAME | ERR_NOPAREN);
369     v++;
370     gflag = 0, tglob(v);
371     v = globall(v);
372     if (v == 0)
373 	stderror(ERR_NAME | ERR_NOMATCH);
374     nwp = (struct whyle *) xcalloc(1, sizeof *nwp);
375     nwp->w_fe = nwp->w_fe0 = v;
376     gargv = 0;
377     nwp->w_start = fseekp;
378     nwp->w_fename = Strsave(cp);
379     nwp->w_next = whyles;
380     whyles = nwp;
381     /*
382      * Pre-read the loop so as to be more comprehensible to a terminal user.
383      */
384     zlast = T_FOREACH;
385     if (intty)
386 	preread();
387     doagain();
388 }
389 
390 void
391 dowhile(v)
392     Char  **v;
393 {
394     register int status;
395     register bool again = whyles != 0 && whyles->w_start == lineloc &&
396     whyles->w_fename == 0;
397 
398     v++;
399     /*
400      * Implement prereading here also, taking care not to evaluate the
401      * expression before the loop has been read up from a terminal.
402      */
403     if (intty && !again)
404 	status = !exp0(&v, 1);
405     else
406 	status = !exp(&v);
407     if (*v)
408 	stderror(ERR_NAME | ERR_EXPRESSION);
409     if (!again) {
410 	register struct whyle *nwp =
411 	(struct whyle *) xcalloc(1, sizeof(*nwp));
412 
413 	nwp->w_start = lineloc;
414 	nwp->w_end = 0;
415 	nwp->w_next = whyles;
416 	whyles = nwp;
417 	zlast = T_WHILE;
418 	if (intty) {
419 	    /*
420 	     * The tty preread
421 	     */
422 	    preread();
423 	    doagain();
424 	    return;
425 	}
426     }
427     if (status)
428 	/* We ain't gonna loop no more, no more! */
429 	toend();
430 }
431 
432 static void
433 preread()
434 {
435     whyles->w_end = -1;
436     if (setintr)
437 	(void) sigsetmask(sigblock((sigset_t) 0) & ~sigmask(SIGINT));
438 
439     search(T_BREAK, 0, NULL);		/* read the expression in */
440     if (setintr)
441 	(void) sigblock(sigmask(SIGINT));
442     whyles->w_end = fseekp;
443 }
444 
445 void
446 doend()
447 {
448     if (!whyles)
449 	stderror(ERR_NAME | ERR_NOTWHILE);
450     whyles->w_end = fseekp;
451     doagain();
452 }
453 
454 void
455 docontin()
456 {
457     if (!whyles)
458 	stderror(ERR_NAME | ERR_NOTWHILE);
459     doagain();
460 }
461 
462 static void
463 doagain()
464 {
465     /* Repeating a while is simple */
466     if (whyles->w_fename == 0) {
467 	bseek(whyles->w_start);
468 	return;
469     }
470     /*
471      * The foreach variable list actually has a spurious word ")" at the end of
472      * the w_fe list.  Thus we are at the of the list if one word beyond this
473      * is 0.
474      */
475     if (!whyles->w_fe[1]) {
476 	dobreak();
477 	return;
478     }
479     set(whyles->w_fename, Strsave(*whyles->w_fe++));
480     bseek(whyles->w_start);
481 }
482 
483 void
484 dorepeat(v, kp)
485     Char  **v;
486     struct command *kp;
487 {
488     register int i;
489     register sigset_t omask = 0;
490 
491     i = getn(v[1]);
492     if (setintr)
493 	omask = sigblock(sigmask(SIGINT)) & ~sigmask(SIGINT);
494     lshift(v, 2);
495     while (i > 0) {
496 	if (setintr)
497 	    (void) sigsetmask(omask);
498 	reexecute(kp);
499 	--i;
500     }
501     donefds();
502     if (setintr)
503 	(void) sigsetmask(omask);
504 }
505 
506 void
507 doswbrk()
508 {
509     search(T_BRKSW, 0, NULL);
510 }
511 
512 int
513 srchx(cp)
514     register Char *cp;
515 {
516     register struct srch *sp, *sp1, *sp2;
517     register i;
518 
519     /*
520      * Binary search Sp1 is the beginning of the current search range. Sp2 is
521      * one past the end.
522      */
523     for (sp1 = srchn, sp2 = srchn + nsrchn; sp1 < sp2;) {
524 	sp = sp1 + ((sp2 - sp1) >> 1);
525 	if ((i = *cp - *sp->s_name) == 0 &&
526 	    (i = Strcmp(cp, str2short(sp->s_name))) == 0)
527 	    return sp->s_value;
528 	if (i < 0)
529 	    sp2 = sp;
530 	else
531 	    sp1 = sp + 1;
532     }
533     return (-1);
534 }
535 
536 static Char Stype;
537 static Char *Sgoal;
538 
539 /*VARARGS2*/
540 void
541 search(type, level, goal)
542     int     type;
543     register int level;
544     Char   *goal;
545 {
546     Char    wordbuf[BUFSIZ];
547     register Char *aword = wordbuf;
548     register Char *cp;
549 
550     Stype = type;
551     Sgoal = goal;
552     if (type == T_GOTO)
553 	bseek((off_t) 0);
554     do {
555 	if (intty && fseekp == feobp)
556 	    xprintf("? "), flush();
557 	aword[0] = 0;
558 	(void) getword(aword);
559 	switch (srchx(aword)) {
560 
561 	case T_ELSE:
562 	    if (level == 0 && type == T_IF)
563 		return;
564 	    break;
565 
566 	case T_IF:
567 	    while (getword(aword))
568 		continue;
569 	    if ((type == T_IF || type == T_ELSE) &&
570 		eq(aword, STRthen))
571 		level++;
572 	    break;
573 
574 	case T_ENDIF:
575 	    if (type == T_IF || type == T_ELSE)
576 		level--;
577 	    break;
578 
579 	case T_FOREACH:
580 	case T_WHILE:
581 	    if (type == T_BREAK)
582 		level++;
583 	    break;
584 
585 	case T_END:
586 	    if (type == T_BREAK)
587 		level--;
588 	    break;
589 
590 	case T_SWITCH:
591 	    if (type == T_SWITCH || type == T_BRKSW)
592 		level++;
593 	    break;
594 
595 	case T_ENDSW:
596 	    if (type == T_SWITCH || type == T_BRKSW)
597 		level--;
598 	    break;
599 
600 	case T_LABEL:
601 	    if (type == T_GOTO && getword(aword) && eq(aword, goal))
602 		level = -1;
603 	    break;
604 
605 	default:
606 	    if (type != T_GOTO && (type != T_SWITCH || level != 0))
607 		break;
608 	    if (lastchr(aword) != ':')
609 		break;
610 	    aword[Strlen(aword) - 1] = 0;
611 	    if (type == T_GOTO && eq(aword, goal) ||
612 		type == T_SWITCH && eq(aword, STRdefault))
613 		level = -1;
614 	    break;
615 
616 	case T_CASE:
617 	    if (type != T_SWITCH || level != 0)
618 		break;
619 	    (void) getword(aword);
620 	    if (lastchr(aword) == ':')
621 		aword[Strlen(aword) - 1] = 0;
622 	    cp = strip(Dfix1(aword));
623 	    if (Gmatch(goal, cp))
624 		level = -1;
625 	    xfree((ptr_t) cp);
626 	    break;
627 
628 	case T_DEFAULT:
629 	    if (type == T_SWITCH && level == 0)
630 		level = -1;
631 	    break;
632 	}
633 	(void) getword(NULL);
634     } while (level >= 0);
635 }
636 
637 static int
638 getword(wp)
639     register Char *wp;
640 {
641     register int found = 0;
642     register int c, d;
643     int     kwd = 0;
644     Char   *owp = wp;
645 
646     c = readc(1);
647     d = 0;
648     do {
649 	while (c == ' ' || c == '\t')
650 	    c = readc(1);
651 	if (c == '#')
652 	    do
653 		c = readc(1);
654 	    while (c >= 0 && c != '\n');
655 	if (c < 0)
656 	    goto past;
657 	if (c == '\n') {
658 	    if (wp)
659 		break;
660 	    return (0);
661 	}
662 	unreadc(c);
663 	found = 1;
664 	do {
665 	    c = readc(1);
666 	    if (c == '\\' && (c = readc(1)) == '\n')
667 		c = ' ';
668 	    if (c == '\'' || c == '"')
669 		if (d == 0)
670 		    d = c;
671 		else if (d == c)
672 		    d = 0;
673 	    if (c < 0)
674 		goto past;
675 	    if (wp) {
676 		*wp++ = c;
677 		*wp = 0;	/* end the string b4 test */
678 	    }
679 	} while ((d || !(kwd = keyword(owp)) && c != ' '
680 		  && c != '\t') && c != '\n');
681     } while (wp == 0);
682 
683     /*
684      * if we have read a keyword ( "if", "switch" or "while" ) then we do not
685      * need to unreadc the look-ahead char
686      */
687     if (!kwd) {
688 	unreadc(c);
689 	if (found)
690 	    *--wp = 0;
691     }
692 
693     return (found);
694 
695 past:
696     switch (Stype) {
697 
698     case T_IF:
699 	stderror(ERR_NAME | ERR_NOTFOUND, "then/endif");
700 
701     case T_ELSE:
702 	stderror(ERR_NAME | ERR_NOTFOUND, "endif");
703 
704     case T_BRKSW:
705     case T_SWITCH:
706 	stderror(ERR_NAME | ERR_NOTFOUND, "endsw");
707 
708     case T_BREAK:
709 	stderror(ERR_NAME | ERR_NOTFOUND, "end");
710 
711     case T_GOTO:
712 	setname(short2str(Sgoal));
713 	stderror(ERR_NAME | ERR_NOTFOUND, "label");
714     }
715     /* NOTREACHED */
716     return (0);
717 }
718 
719 /*
720  * keyword(wp) determines if wp is one of the built-n functions if,
721  * switch or while. It seems that when an if statement looks like
722  * "if(" then getword above sucks in the '(' and so the search routine
723  * never finds what it is scanning for. Rather than rewrite doword, I hack
724  * in a test to see if the string forms a keyword. Then doword stops
725  * and returns the word "if" -strike
726  */
727 
728 static int
729 keyword(wp)
730     Char   *wp;
731 {
732     static Char STRif[] = {'i', 'f', '\0'};
733     static Char STRwhile[] = {'w', 'h', 'i', 'l', 'e', '\0'};
734     static Char STRswitch[] = {'s', 'w', 'i', 't', 'c', 'h', '\0'};
735 
736     if (!wp)
737 	return (0);
738 
739     if ((Strcmp(wp, STRif) == 0) || (Strcmp(wp, STRwhile) == 0)
740 	|| (Strcmp(wp, STRswitch) == 0))
741 	return (1);
742 
743     return (0);
744 }
745 
746 static void
747 toend()
748 {
749     if (whyles->w_end == 0) {
750 	search(T_BREAK, 0, NULL);
751 	whyles->w_end = fseekp - 1;
752     }
753     else
754 	bseek(whyles->w_end);
755     wfree();
756 }
757 
758 void
759 wfree()
760 {
761     long    o = fseekp;
762 
763     while (whyles) {
764 	register struct whyle *wp = whyles;
765 	register struct whyle *nwp = wp->w_next;
766 
767 	if (o >= wp->w_start && (wp->w_end == 0 || o < wp->w_end))
768 	    break;
769 	if (wp->w_fe0)
770 	    blkfree(wp->w_fe0);
771 	if (wp->w_fename)
772 	    xfree((ptr_t) wp->w_fename);
773 	xfree((ptr_t) wp);
774 	whyles = nwp;
775     }
776 }
777 
778 void
779 doecho(v)
780     Char  **v;
781 {
782     xecho(' ', v);
783 }
784 
785 void
786 doglob(v)
787     Char  **v;
788 {
789     xecho(0, v);
790     flush();
791 }
792 
793 static void
794 xecho(sep, v)
795     int    sep;
796     register Char **v;
797 {
798     register Char *cp;
799     int     nonl = 0;
800 
801     if (setintr)
802 	(void) sigsetmask(sigblock((sigset_t) 0) & ~sigmask(SIGINT));
803     v++;
804     if (*v == 0)
805 	return;
806     gflag = 0, tglob(v);
807     if (gflag) {
808 	v = globall(v);
809 	if (v == 0)
810 	    stderror(ERR_NAME | ERR_NOMATCH);
811     }
812     else {
813 	v = gargv = saveblk(v);
814 	trim(v);
815     }
816     if (sep == ' ' && *v && eq(*v, STRmn))
817 	nonl++, v++;
818     while (cp = *v++) {
819 	register int c;
820 
821 	while (c = *cp++)
822 	    xputchar(c | QUOTE);
823 
824 	if (*v)
825 	    xputchar(sep | QUOTE);
826     }
827     if (sep && nonl == 0)
828 	xputchar('\n');
829     else
830 	flush();
831     if (setintr)
832 	(void) sigblock(sigmask(SIGINT));
833     if (gargv)
834 	blkfree(gargv), gargv = 0;
835 }
836 
837 /* from "Karl Berry." <karl%mote.umb.edu@relay.cs.net> -- for NeXT things
838    (and anything else with a modern compiler) */
839 
840 void
841 dosetenv(v)
842     register Char **v;
843 {
844     Char   *vp, *lp;
845 
846     v++;
847     if ((vp = *v++) == 0) {
848 	register Char **ep;
849 
850 	if (setintr)
851 	    (void) sigsetmask(sigblock((sigset_t) 0) & ~sigmask(SIGINT));
852 	for (ep = STR_environ; *ep; ep++)
853 	    xprintf("%s\n", short2str(*ep));
854 	return;
855     }
856     if ((lp = *v++) == 0)
857 	lp = STRNULL;
858     Setenv(vp, lp = globone(lp, G_ERROR));
859     if (eq(vp, STRPATH)) {
860 	importpath(lp);
861 	dohash();
862     }
863     else if (eq(vp, STRLANG) || eq(vp, STRLC_CTYPE)) {
864 #ifdef NLS
865 	int     k;
866 
867 	(void) setlocale(LC_ALL, "");
868 	for (k = 0200; k <= 0377 && !Isprint(k); k++);
869 	AsciiOnly = k > 0377;
870 #else
871 	AsciiOnly = 0;
872 #endif				/* NLS */
873     }
874     xfree((ptr_t) lp);
875 }
876 
877 void
878 dounsetenv(v)
879     register Char **v;
880 {
881     Char  **ep, *p, *n;
882     int     i, maxi;
883     static Char *name = NULL;
884 
885     if (name)
886 	xfree((ptr_t) name);
887     /*
888      * Find the longest environment variable
889      */
890     for (maxi = 0, ep = STR_environ; *ep; ep++) {
891 	for (i = 0, p = *ep; *p && *p != '='; p++, i++);
892 	if (i > maxi)
893 	    maxi = i;
894     }
895 
896     name = (Char *) xmalloc((size_t) (maxi + 1) * sizeof(Char));
897 
898     v++;
899     maxi = 1;
900     while (maxi)
901 	for (maxi = 0, ep = STR_environ; *ep; ep++) {
902 	    for (n = name, p = *ep; *p && *p != '='; *n++ = *p++);
903 	    *n = '\0';
904 	    if (!Gmatch(name, *v))
905 		continue;
906 	    maxi = 1;
907 	    if (eq(name, STRLANG) || eq(name, STRLC_CTYPE)) {
908 #ifdef NLS
909 		int     k;
910 
911 		(void) setlocale(LC_ALL, "");
912 		for (k = 0200; k <= 0377 && !Isprint(k); k++);
913 		AsciiOnly = k > 0377;
914 #else
915 		AsciiOnly = getenv("LANG") == NULL &&
916 		    getenv("LC_CTYPE") == NULL;
917 #endif				/* NLS */
918 	    }
919 	    /*
920 	     * Delete name, and start again cause the environment changes
921 	     */
922 	    Unsetenv(name);
923 	    break;
924 	}
925     xfree((ptr_t) name), name = NULL;
926 }
927 
928 void
929 Setenv(name, val)
930     Char   *name, *val;
931 {
932     register Char **ep = STR_environ;
933     register Char *cp, *dp;
934     Char   *blk[2];
935     Char  **oep = ep;
936 
937 
938     for (; *ep; ep++) {
939 	for (cp = name, dp = *ep; *cp && *cp == *dp; cp++, dp++)
940 	    continue;
941 	if (*cp != 0 || *dp != '=')
942 	    continue;
943 	cp = Strspl(STRequal, val);
944 	xfree((ptr_t) * ep);
945 	*ep = strip(Strspl(name, cp));
946 	xfree((ptr_t) cp);
947 	blkfree((Char **) environ);
948 	environ = short2blk(STR_environ);
949 	return;
950     }
951     cp = Strspl(name, STRequal);
952     blk[0] = strip(Strspl(cp, val));
953     xfree((ptr_t) cp);
954     blk[1] = 0;
955     STR_environ = blkspl(STR_environ, blk);
956     blkfree((Char **) environ);
957     environ = short2blk(STR_environ);
958     xfree((ptr_t) oep);
959 }
960 
961 static void
962 Unsetenv(name)
963     Char   *name;
964 {
965     register Char **ep = STR_environ;
966     register Char *cp, *dp;
967     Char  **oep = ep;
968 
969     for (; *ep; ep++) {
970 	for (cp = name, dp = *ep; *cp && *cp == *dp; cp++, dp++)
971 	    continue;
972 	if (*cp != 0 || *dp != '=')
973 	    continue;
974 	cp = *ep;
975 	*ep = 0;
976 	STR_environ = blkspl(STR_environ, ep + 1);
977 	environ = short2blk(STR_environ);
978 	*ep = cp;
979 	xfree((ptr_t) cp);
980 	xfree((ptr_t) oep);
981 	return;
982     }
983 }
984 
985 void
986 doumask(v)
987     register Char **v;
988 {
989     register Char *cp = v[1];
990     register int i;
991 
992     if (cp == 0) {
993 	i = umask(0);
994 	(void) umask(i);
995 	xprintf("%o\n", i);
996 	return;
997     }
998     i = 0;
999     while (Isdigit(*cp) && *cp != '8' && *cp != '9')
1000 	i = i * 8 + *cp++ - '0';
1001     if (*cp || i < 0 || i > 0777)
1002 	stderror(ERR_NAME | ERR_MASK);
1003     (void) umask(i);
1004 }
1005 
1006 typedef int RLIM_TYPE;
1007 
1008 static struct limits {
1009     int     limconst;
1010     char   *limname;
1011     int     limdiv;
1012     char   *limscale;
1013 }       limits[] = {
1014     RLIMIT_CPU, 	"cputime",	1,	"seconds",
1015     RLIMIT_FSIZE,	"filesize",	1024,	"kbytes",
1016     RLIMIT_DATA,	"datasize",	1024,	"kbytes",
1017     RLIMIT_STACK,	"stacksize",	1024,	"kbytes",
1018     RLIMIT_CORE,	"coredumpsize", 1024,	"kbytes",
1019     RLIMIT_RSS,		"memoryuse", 	1024,	"kbytes",
1020     RLIMIT_MEMLOCK,	"memorylocked",	1024,	"kbytes",
1021     RLIMIT_NPROC,	"maxproc",	1,	"",
1022     RLIMIT_OFILE,	"openfiles",	1,	"",
1023     -1, 		NULL, 		0,	NULL
1024 };
1025 
1026 static struct limits *findlim();
1027 static RLIM_TYPE getval();
1028 static void limtail();
1029 static void plim();
1030 static int setlim();
1031 
1032 static struct limits *
1033 findlim(cp)
1034     Char   *cp;
1035 {
1036     register struct limits *lp, *res;
1037 
1038     res = (struct limits *) NULL;
1039     for (lp = limits; lp->limconst >= 0; lp++)
1040 	if (prefix(cp, str2short(lp->limname))) {
1041 	    if (res)
1042 		stderror(ERR_NAME | ERR_AMBIG);
1043 	    res = lp;
1044 	}
1045     if (res)
1046 	return (res);
1047     stderror(ERR_NAME | ERR_LIMIT);
1048     /* NOTREACHED */
1049     return (0);
1050 }
1051 
1052 void
1053 dolimit(v)
1054     register Char **v;
1055 {
1056     register struct limits *lp;
1057     register RLIM_TYPE limit;
1058     char    hard = 0;
1059 
1060     v++;
1061     if (*v && eq(*v, STRmh)) {
1062 	hard = 1;
1063 	v++;
1064     }
1065     if (*v == 0) {
1066 	for (lp = limits; lp->limconst >= 0; lp++)
1067 	    plim(lp, hard);
1068 	return;
1069     }
1070     lp = findlim(v[0]);
1071     if (v[1] == 0) {
1072 	plim(lp, hard);
1073 	return;
1074     }
1075     limit = getval(lp, v + 1);
1076     if (setlim(lp, hard, limit) < 0)
1077 	stderror(ERR_SILENT);
1078 }
1079 
1080 static  RLIM_TYPE
1081 getval(lp, v)
1082     register struct limits *lp;
1083     Char  **v;
1084 {
1085     register float f;
1086     double  atof();
1087     Char   *cp = *v++;
1088 
1089     f = atof(short2str(cp));
1090 
1091     while (Isdigit(*cp) || *cp == '.' || *cp == 'e' || *cp == 'E')
1092 	cp++;
1093     if (*cp == 0) {
1094 	if (*v == 0)
1095 	    return ((RLIM_TYPE) ((f + 0.5) * lp->limdiv));
1096 	cp = *v;
1097     }
1098     switch (*cp) {
1099     case ':':
1100 	if (lp->limconst != RLIMIT_CPU)
1101 	    goto badscal;
1102 	return ((RLIM_TYPE) (f * 60.0 + atof(short2str(cp + 1))));
1103     case 'h':
1104 	if (lp->limconst != RLIMIT_CPU)
1105 	    goto badscal;
1106 	limtail(cp, "hours");
1107 	f *= 3600.0;
1108 	break;
1109     case 'm':
1110 	if (lp->limconst == RLIMIT_CPU) {
1111 	    limtail(cp, "minutes");
1112 	    f *= 60.0;
1113 	    break;
1114 	}
1115 	*cp = 'm';
1116 	limtail(cp, "megabytes");
1117 	f *= 1024.0 * 1024.0;
1118 	break;
1119     case 's':
1120 	if (lp->limconst != RLIMIT_CPU)
1121 	    goto badscal;
1122 	limtail(cp, "seconds");
1123 	break;
1124     case 'M':
1125 	if (lp->limconst == RLIMIT_CPU)
1126 	    goto badscal;
1127 	*cp = 'm';
1128 	limtail(cp, "megabytes");
1129 	f *= 1024.0 * 1024.0;
1130 	break;
1131     case 'k':
1132 	if (lp->limconst == RLIMIT_CPU)
1133 	    goto badscal;
1134 	limtail(cp, "kbytes");
1135 	f *= 1024.0;
1136 	break;
1137     case 'u':
1138 	limtail(cp, "unlimited");
1139 	return (RLIM_INFINITY);
1140     default:
1141 badscal:
1142 	stderror(ERR_NAME | ERR_SCALEF);
1143     }
1144     return ((RLIM_TYPE) (f + 0.5));
1145 }
1146 
1147 static void
1148 limtail(cp, str)
1149     Char   *cp;
1150     char   *str;
1151 {
1152     while (*cp && *cp == *str)
1153 	cp++, str++;
1154     if (*cp)
1155 	stderror(ERR_BADSCALE, str);
1156 }
1157 
1158 
1159 /*ARGSUSED*/
1160 static void
1161 plim(lp, hard)
1162     register struct limits *lp;
1163     Char    hard;
1164 {
1165     struct rlimit rlim;
1166     RLIM_TYPE limit;
1167 
1168     xprintf("%s \t", lp->limname);
1169 
1170     (void) getrlimit(lp->limconst, &rlim);
1171     limit = hard ? rlim.rlim_max : rlim.rlim_cur;
1172 
1173     if (limit == RLIM_INFINITY)
1174 	xprintf("unlimited");
1175     else if (lp->limconst == RLIMIT_CPU)
1176 	psecs((long) limit);
1177     else
1178 	xprintf("%ld %s", (long) (limit / lp->limdiv), lp->limscale);
1179     xprintf("\n");
1180 }
1181 
1182 void
1183 dounlimit(v)
1184     register Char **v;
1185 {
1186     register struct limits *lp;
1187     int     lerr = 0;
1188     Char    hard = 0;
1189 
1190     v++;
1191     if (*v && eq(*v, STRmh)) {
1192 	hard = 1;
1193 	v++;
1194     }
1195     if (*v == 0) {
1196 	for (lp = limits; lp->limconst >= 0; lp++)
1197 	    if (setlim(lp, hard, (RLIM_TYPE) RLIM_INFINITY) < 0)
1198 		lerr++;
1199 	if (lerr)
1200 	    stderror(ERR_SILENT);
1201 	return;
1202     }
1203     while (*v) {
1204 	lp = findlim(*v++);
1205 	if (setlim(lp, hard, (RLIM_TYPE) RLIM_INFINITY) < 0)
1206 	    stderror(ERR_SILENT);
1207     }
1208 }
1209 
1210 static int
1211 setlim(lp, hard, limit)
1212     register struct limits *lp;
1213     Char    hard;
1214     RLIM_TYPE limit;
1215 {
1216     struct rlimit rlim;
1217 
1218     (void) getrlimit(lp->limconst, &rlim);
1219 
1220     if (hard)
1221 	rlim.rlim_max = limit;
1222     else if (limit == RLIM_INFINITY && geteuid() != 0)
1223 	rlim.rlim_cur = rlim.rlim_max;
1224     else
1225 	rlim.rlim_cur = limit;
1226 
1227     if (setrlimit(lp->limconst, &rlim) < 0) {
1228 	xprintf("%s: %s: Can't %s%s limit\n", bname, lp->limname,
1229 		limit == RLIM_INFINITY ? "remove" : "set",
1230 		hard ? " hard" : "");
1231 	return (-1);
1232     }
1233     return (0);
1234 }
1235 
1236 void
1237 dosuspend()
1238 {
1239     int     ctpgrp;
1240 
1241     void    (*old) ();
1242 
1243     if (loginsh)
1244 	stderror(ERR_SUSPLOG);
1245     untty();
1246 
1247     old = signal(SIGTSTP, SIG_DFL);
1248     (void) kill(0, SIGTSTP);
1249     /* the shell stops here */
1250     (void) signal(SIGTSTP, old);
1251 
1252     if (tpgrp != -1) {
1253 retry:
1254 	ctpgrp = tcgetpgrp(FSHTTY);
1255 	if (ctpgrp != opgrp) {
1256 	    old = signal(SIGTTIN, SIG_DFL);
1257 	    (void) kill(0, SIGTTIN);
1258 	    (void) signal(SIGTTIN, old);
1259 	    goto retry;
1260 	}
1261 	(void) setpgid(0, shpgrp);
1262 	(void) tcsetpgrp(FSHTTY, shpgrp);
1263     }
1264 }
1265 
1266 /* This is the dreaded EVAL built-in.
1267  *   If you don't fiddle with file descriptors, and reset didfds,
1268  *   this command will either ignore redirection inside or outside
1269  *   its aguments, e.g. eval "date >x"  vs.  eval "date" >x
1270  *   The stuff here seems to work, but I did it by trial and error rather
1271  *   than really knowing what was going on.  If tpgrp is zero, we are
1272  *   probably a background eval, e.g. "eval date &", and we want to
1273  *   make sure that any processes we start stay in our pgrp.
1274  *   This is also the case for "time eval date" -- stay in same pgrp.
1275  *   Otherwise, under stty tostop, processes will stop in the wrong
1276  *   pgrp, with no way for the shell to get them going again.  -IAN!
1277  */
1278 void
1279 doeval(v)
1280     Char  **v;
1281 {
1282     Char  **oevalvec;
1283     Char   *oevalp;
1284     int     odidfds;
1285     jmp_buf osetexit;
1286     int     my_reenter;
1287     Char  **gv;
1288     int     saveIN;
1289     int     saveOUT;
1290     int     saveDIAG;
1291     int     oSHIN;
1292     int     oSHOUT;
1293     int     oSHDIAG;
1294 
1295     oevalvec = evalvec;
1296     oevalp = evalp;
1297     odidfds = didfds;
1298     oSHIN = SHIN;
1299     oSHOUT = SHOUT;
1300     oSHDIAG = SHDIAG;
1301 
1302     v++;
1303     if (*v == 0)
1304 	return;
1305     gflag = 0, tglob(v);
1306     if (gflag) {
1307 	gv = v = globall(v);
1308 	gargv = 0;
1309 	if (v == 0)
1310 	    stderror(ERR_NOMATCH);
1311 	v = copyblk(v);
1312     }
1313     else {
1314 	gv = NULL;
1315 	v = copyblk(v);
1316 	trim(v);
1317     }
1318 
1319     saveIN = dcopy(SHIN, -1);
1320     saveOUT = dcopy(SHOUT, -1);
1321     saveDIAG = dcopy(SHDIAG, -1);
1322 
1323     getexit(osetexit);
1324 
1325     if ((my_reenter = setexit()) == 0) {
1326 	evalvec = v;
1327 	evalp = 0;
1328 	SHIN = dcopy(0, -1);
1329 	SHOUT = dcopy(1, -1);
1330 	SHDIAG = dcopy(2, -1);
1331 	didfds = 0;
1332 	process(0);
1333     }
1334 
1335     evalvec = oevalvec;
1336     evalp = oevalp;
1337     doneinp = 0;
1338     didfds = odidfds;
1339     (void) close(SHIN);
1340     (void) close(SHOUT);
1341     (void) close(SHDIAG);
1342     SHIN = dmove(saveIN, oSHIN);
1343     SHOUT = dmove(saveOUT, oSHOUT);
1344     SHDIAG = dmove(saveDIAG, oSHDIAG);
1345 
1346     if (gv)
1347 	blkfree(gv);
1348     resexit(osetexit);
1349     if (my_reenter)
1350 	stderror(ERR_SILENT);
1351 }
1352