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