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