xref: /netbsd-src/bin/csh/func.c (revision 509d26c5fb01645d5dfb1d910cec099cd0f8d510)
1*509d26c5Snia /* $NetBSD: func.c,v 1.45 2024/04/24 15:49:03 nia Exp $ */
249f0ad86Scgd 
361f28255Scgd /*-
4cee2bad8Smycroft  * Copyright (c) 1980, 1991, 1993
5cee2bad8Smycroft  *	The Regents of the University of California.  All rights reserved.
661f28255Scgd  *
761f28255Scgd  * Redistribution and use in source and binary forms, with or without
861f28255Scgd  * modification, are permitted provided that the following conditions
961f28255Scgd  * are met:
1061f28255Scgd  * 1. Redistributions of source code must retain the above copyright
1161f28255Scgd  *    notice, this list of conditions and the following disclaimer.
1261f28255Scgd  * 2. Redistributions in binary form must reproduce the above copyright
1361f28255Scgd  *    notice, this list of conditions and the following disclaimer in the
1461f28255Scgd  *    documentation and/or other materials provided with the distribution.
15b5b29542Sagc  * 3. Neither the name of the University nor the names of its contributors
1661f28255Scgd  *    may be used to endorse or promote products derived from this software
1761f28255Scgd  *    without specific prior written permission.
1861f28255Scgd  *
1961f28255Scgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2061f28255Scgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2161f28255Scgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2261f28255Scgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2361f28255Scgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2461f28255Scgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2561f28255Scgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2661f28255Scgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2761f28255Scgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2861f28255Scgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2961f28255Scgd  * SUCH DAMAGE.
3061f28255Scgd  */
3161f28255Scgd 
328ea378c6Schristos #include <sys/cdefs.h>
3361f28255Scgd #ifndef lint
3449f0ad86Scgd #if 0
3549f0ad86Scgd static char sccsid[] = "@(#)func.c	8.1 (Berkeley) 5/31/93";
3649f0ad86Scgd #else
37*509d26c5Snia __RCSID("$NetBSD: func.c,v 1.45 2024/04/24 15:49:03 nia Exp $");
3849f0ad86Scgd #endif
3961f28255Scgd #endif /* not lint */
4061f28255Scgd 
4161f28255Scgd #include <sys/stat.h>
42b771e65bSwiz #include <sys/types.h>
43b771e65bSwiz 
4461f28255Scgd #include <locale.h>
4537e39248Schristos #include <inttypes.h>
46b771e65bSwiz #include <signal.h>
4718158540Swiz #include <stdarg.h>
4861f28255Scgd #include <stdlib.h>
4961f28255Scgd #include <string.h>
5061f28255Scgd #include <unistd.h>
518b19d01fSragge #include <errno.h>
52b771e65bSwiz 
5361f28255Scgd #include "csh.h"
5461f28255Scgd #include "extern.h"
5561f28255Scgd #include "pathnames.h"
5661f28255Scgd 
5761f28255Scgd extern char **environ;
58b771e65bSwiz extern int progprintf(int, char **);
5961f28255Scgd 
60b771e65bSwiz static void islogin(void);
61b771e65bSwiz static void reexecute(struct command *);
62b771e65bSwiz static void preread(void);
63b771e65bSwiz static void doagain(void);
64b771e65bSwiz static void search(int, int, Char *);
65b771e65bSwiz static int getword(Char *);
66b771e65bSwiz static int keyword(Char *);
67b771e65bSwiz static void toend(void);
68b771e65bSwiz static void xecho(int, Char **);
69b771e65bSwiz static void Unsetenv(Char *);
709a77f167Schristos static void wpfree(struct whyle *);
7161f28255Scgd 
7261f28255Scgd struct biltins *
isbfunc(struct command * t)73b771e65bSwiz isbfunc(struct command *t)
7461f28255Scgd {
7561f28255Scgd     static struct biltins label = {"", dozip, 0, 0};
7661f28255Scgd     static struct biltins foregnd = {"%job", dofg1, 0, 0};
7761f28255Scgd     static struct biltins backgnd = {"%job &", dobg1, 0, 0};
78b771e65bSwiz     struct biltins *bp, *bp1, *bp2;
79b771e65bSwiz     Char *cp;
80b771e65bSwiz 
81b771e65bSwiz     cp = t->t_dcom[0];
8261f28255Scgd 
8361f28255Scgd     if (lastchr(cp) == ':') {
8461f28255Scgd 	label.bname = short2str(cp);
8561f28255Scgd 	return (&label);
8661f28255Scgd     }
8761f28255Scgd     if (*cp == '%') {
8861f28255Scgd 	if (t->t_dflg & F_AMPERSAND) {
8961f28255Scgd 	    t->t_dflg &= ~F_AMPERSAND;
9061f28255Scgd 	    backgnd.bname = short2str(cp);
9161f28255Scgd 	    return (&backgnd);
9261f28255Scgd 	}
9361f28255Scgd 	foregnd.bname = short2str(cp);
9461f28255Scgd 	return (&foregnd);
9561f28255Scgd     }
9661f28255Scgd     /*
9761f28255Scgd      * Binary search Bp1 is the beginning of the current search range. Bp2 is
9861f28255Scgd      * one past the end.
9961f28255Scgd      */
10061f28255Scgd     for (bp1 = bfunc, bp2 = bfunc + nbfunc; bp1 < bp2;) {
10176adbe2bStls 	int i;
10261f28255Scgd 
10361f28255Scgd 	bp = bp1 + ((bp2 - bp1) >> 1);
10461f28255Scgd 	if ((i = *cp - *bp->bname) == 0 &&
10561f28255Scgd 	    (i = Strcmp(cp, str2short(bp->bname))) == 0)
10661f28255Scgd 	    return bp;
10761f28255Scgd 	if (i < 0)
10861f28255Scgd 	    bp2 = bp;
10961f28255Scgd 	else
11061f28255Scgd 	    bp1 = bp + 1;
11161f28255Scgd     }
11261f28255Scgd     return (0);
11361f28255Scgd }
11461f28255Scgd 
11561f28255Scgd void
func(struct command * t,struct biltins * bp)116b771e65bSwiz func(struct command *t, struct biltins *bp)
11761f28255Scgd {
11861f28255Scgd     int i;
11961f28255Scgd 
12061f28255Scgd     xechoit(t->t_dcom);
12161f28255Scgd     setname(bp->bname);
12261f28255Scgd     i = blklen(t->t_dcom) - 1;
123ee9e50eaSmycroft     if (i < bp->minargs)
12461f28255Scgd 	stderror(ERR_NAME | ERR_TOOFEW);
125ee9e50eaSmycroft     if (i > bp->maxargs)
12661f28255Scgd 	stderror(ERR_NAME | ERR_TOOMANY);
12761f28255Scgd     (*bp->bfunct) (t->t_dcom, t);
12861f28255Scgd }
12961f28255Scgd 
13061f28255Scgd void
131cee2bad8Smycroft /*ARGSUSED*/
doonintr(Char ** v,struct command * t)132b771e65bSwiz doonintr(Char **v, struct command *t)
13361f28255Scgd {
134b771e65bSwiz     Char *cp, *vv;
135b3df6303Skleink     sigset_t nsigset;
13661f28255Scgd 
137b771e65bSwiz     vv = v[1];
13861f28255Scgd     if (parintr == SIG_IGN)
13961f28255Scgd 	return;
140ee9e50eaSmycroft     if (setintr && intty)
14161f28255Scgd 	stderror(ERR_NAME | ERR_TERMINAL);
14261f28255Scgd     cp = gointr;
14361f28255Scgd     gointr = 0;
1441767ce60Schristos     free(cp);
14561f28255Scgd     if (vv == 0) {
1467b38403cSmycroft 	if (setintr) {
147b3df6303Skleink 	    sigemptyset(&nsigset);
148b3df6303Skleink 	    (void)sigaddset(&nsigset, SIGINT);
149b3df6303Skleink 	    (void)sigprocmask(SIG_BLOCK, &nsigset, NULL);
1507b38403cSmycroft 	} else
15161f28255Scgd 	    (void)signal(SIGINT, SIG_DFL);
15261f28255Scgd 	gointr = 0;
15361f28255Scgd     }
15461f28255Scgd     else if (eq((vv = strip(vv)), STRminus)) {
15561f28255Scgd 	(void)signal(SIGINT, SIG_IGN);
15661f28255Scgd 	gointr = Strsave(STRminus);
15761f28255Scgd     }
15861f28255Scgd     else {
15961f28255Scgd 	gointr = Strsave(vv);
16061f28255Scgd 	(void)signal(SIGINT, pintr);
16161f28255Scgd     }
16261f28255Scgd }
16361f28255Scgd 
16461f28255Scgd void
165cee2bad8Smycroft /*ARGSUSED*/
donohup(Char ** v,struct command * t)166b771e65bSwiz donohup(Char **v, struct command *t)
16761f28255Scgd {
168ee9e50eaSmycroft     if (intty)
16961f28255Scgd 	stderror(ERR_NAME | ERR_TERMINAL);
17061f28255Scgd     if (setintr == 0) {
17161f28255Scgd 	(void) signal(SIGHUP, SIG_IGN);
17261f28255Scgd     }
17361f28255Scgd }
17461f28255Scgd 
17561f28255Scgd void
176cee2bad8Smycroft /*ARGSUSED*/
dozip(Char ** v,struct command * t)177b771e65bSwiz dozip(Char **v, struct command *t)
17861f28255Scgd {
17961f28255Scgd     ;
18061f28255Scgd }
18161f28255Scgd 
18261f28255Scgd void
prvars(void)183b771e65bSwiz prvars(void)
18461f28255Scgd {
18561f28255Scgd     plist(&shvhed);
18661f28255Scgd }
18761f28255Scgd 
18861f28255Scgd void
189cee2bad8Smycroft /*ARGSUSED*/
doalias(Char ** v,struct command * t)190b771e65bSwiz doalias(Char **v, struct command *t)
19161f28255Scgd {
19276adbe2bStls     struct varent *vp;
19376adbe2bStls     Char *p;
19461f28255Scgd 
19561f28255Scgd     v++;
19661f28255Scgd     p = *v++;
19761f28255Scgd     if (p == 0)
19861f28255Scgd 	plist(&aliases);
19961f28255Scgd     else if (*v == 0) {
20061f28255Scgd 	vp = adrof1(strip(p), &aliases);
201cee2bad8Smycroft 	if (vp) {
202cee2bad8Smycroft 	    blkpr(cshout, vp->vec);
2035924694dSmycroft 	    (void) fputc('\n', cshout);
204cee2bad8Smycroft 	}
20561f28255Scgd     }
20661f28255Scgd     else {
20761f28255Scgd 	if (eq(p, STRalias) || eq(p, STRunalias)) {
208cee2bad8Smycroft 	    setname(vis_str(p));
20961f28255Scgd 	    stderror(ERR_NAME | ERR_DANGER);
21061f28255Scgd 	}
21161f28255Scgd 	set1(strip(p), saveblk(v), &aliases);
21261f28255Scgd     }
21361f28255Scgd }
21461f28255Scgd 
21561f28255Scgd void
216cee2bad8Smycroft /*ARGSUSED*/
unalias(Char ** v,struct command * t)217b771e65bSwiz unalias(Char **v, struct command *t)
21861f28255Scgd {
21961f28255Scgd     unset1(v, &aliases);
22061f28255Scgd }
22161f28255Scgd 
22261f28255Scgd void
223cee2bad8Smycroft /*ARGSUSED*/
dologout(Char ** v,struct command * t)224b771e65bSwiz dologout(Char **v, struct command *t)
22561f28255Scgd {
22661f28255Scgd     islogin();
22761f28255Scgd     goodbye();
22861f28255Scgd }
22961f28255Scgd 
23061f28255Scgd void
231cee2bad8Smycroft /*ARGSUSED*/
dologin(Char ** v,struct command * t)232b771e65bSwiz dologin(Char **v, struct command *t)
23361f28255Scgd {
23461f28255Scgd     islogin();
23561f28255Scgd     rechist();
23661f28255Scgd     (void)signal(SIGTERM, parterm);
23761f28255Scgd     (void)execl(_PATH_LOGIN, "login", short2str(v[1]), NULL);
23861f28255Scgd     untty();
23961f28255Scgd     xexit(1);
240cdbd74daSmycroft     /* NOTREACHED */
24161f28255Scgd }
24261f28255Scgd 
24361f28255Scgd static void
islogin(void)244b771e65bSwiz islogin(void)
24561f28255Scgd {
24661f28255Scgd     if (chkstop == 0 && setintr)
24761f28255Scgd 	panystop(0);
24861f28255Scgd     if (loginsh)
24961f28255Scgd 	return;
25061f28255Scgd     stderror(ERR_NOTLOGIN);
251cdbd74daSmycroft     /* NOTREACHED */
25261f28255Scgd }
25361f28255Scgd 
25461f28255Scgd void
doif(Char ** v,struct command * kp)255b771e65bSwiz doif(Char **v, struct command *kp)
25661f28255Scgd {
25776adbe2bStls     Char **vv;
258b771e65bSwiz     int i;
25961f28255Scgd 
26061f28255Scgd     v++;
261cee2bad8Smycroft     i = expr(&v);
26261f28255Scgd     vv = v;
263ee9e50eaSmycroft     if (*vv == NULL)
26461f28255Scgd 	stderror(ERR_NAME | ERR_EMPTYIF);
26561f28255Scgd     if (eq(*vv, STRthen)) {
266ee9e50eaSmycroft 	if (*++vv)
26761f28255Scgd 	    stderror(ERR_NAME | ERR_IMPRTHEN);
268cee2bad8Smycroft 	setname(vis_str(STRthen));
26961f28255Scgd 	/*
27061f28255Scgd 	 * If expression was zero, then scan to else, otherwise just fall into
27161f28255Scgd 	 * following code.
27261f28255Scgd 	 */
27361f28255Scgd 	if (!i)
27461f28255Scgd 	    search(T_IF, 0, NULL);
27561f28255Scgd 	return;
27661f28255Scgd     }
27761f28255Scgd     /*
27861f28255Scgd      * Simple command attached to this if. Left shift the node in this tree,
27961f28255Scgd      * munging it so we can reexecute it.
28061f28255Scgd      */
28161f28255Scgd     if (i) {
28237e39248Schristos 	lshift(kp->t_dcom, (size_t)(vv - kp->t_dcom));
28361f28255Scgd 	reexecute(kp);
28461f28255Scgd 	donefds();
28561f28255Scgd     }
28661f28255Scgd }
28761f28255Scgd 
28861f28255Scgd /*
28961f28255Scgd  * Reexecute a command, being careful not
29061f28255Scgd  * to redo i/o redirection, which is already set up.
29161f28255Scgd  */
29261f28255Scgd static void
reexecute(struct command * kp)293b771e65bSwiz reexecute(struct command *kp)
29461f28255Scgd {
29561f28255Scgd     kp->t_dflg &= F_SAVE;
29661f28255Scgd     kp->t_dflg |= F_REPEAT;
29761f28255Scgd     /*
29861f28255Scgd      * If tty is still ours to arbitrate, arbitrate it; otherwise dont even set
29961f28255Scgd      * pgrp's as the jobs would then have no way to get the tty (we can't give
30061f28255Scgd      * it to them, and our parent wouldn't know their pgrp, etc.
30161f28255Scgd      */
30261f28255Scgd     execute(kp, (tpgrp > 0 ? tpgrp : -1), NULL, NULL);
30361f28255Scgd }
30461f28255Scgd 
30561f28255Scgd void
306cee2bad8Smycroft /*ARGSUSED*/
doelse(Char ** v,struct command * t)307b771e65bSwiz doelse(Char **v, struct command *t)
30861f28255Scgd {
30961f28255Scgd     search(T_ELSE, 0, NULL);
31061f28255Scgd }
31161f28255Scgd 
31261f28255Scgd void
313cee2bad8Smycroft /*ARGSUSED*/
dogoto(Char ** v,struct command * t)314b771e65bSwiz dogoto(Char **v, struct command *t)
31561f28255Scgd {
31661f28255Scgd     Char *lp;
31761f28255Scgd 
318cee2bad8Smycroft     gotolab(lp = globone(v[1], G_ERROR));
3191767ce60Schristos     free(lp);
320cee2bad8Smycroft }
321cee2bad8Smycroft 
322cee2bad8Smycroft void
gotolab(Char * lab)323b771e65bSwiz gotolab(Char *lab)
324cee2bad8Smycroft {
32576adbe2bStls     struct whyle *wp;
32661f28255Scgd     /*
32761f28255Scgd      * While we still can, locate any unknown ends of existing loops. This
32861f28255Scgd      * obscure code is the WORST result of the fact that we don't really parse.
32961f28255Scgd      */
33061f28255Scgd     for (wp = whyles; wp; wp = wp->w_next)
331cee2bad8Smycroft 	if (wp->w_end.type == F_SEEK && wp->w_end.f_seek == 0) {
33261f28255Scgd 	    search(T_BREAK, 0, NULL);
333cee2bad8Smycroft 	    btell(&wp->w_end);
33461f28255Scgd 	}
33561f28255Scgd 	else
336cee2bad8Smycroft 	    bseek(&wp->w_end);
337cee2bad8Smycroft     search(T_GOTO, 0, lab);
33861f28255Scgd     /*
33961f28255Scgd      * Eliminate loops which were exited.
34061f28255Scgd      */
34161f28255Scgd     wfree();
34261f28255Scgd }
34361f28255Scgd 
34461f28255Scgd void
345cee2bad8Smycroft /*ARGSUSED*/
doswitch(Char ** v,struct command * t)346b771e65bSwiz doswitch(Char **v, struct command *t)
34761f28255Scgd {
34876adbe2bStls     Char *cp, *lp;
34961f28255Scgd 
35061f28255Scgd     v++;
351ee9e50eaSmycroft     if (!*v || *(*v++) != '(')
35261f28255Scgd 	stderror(ERR_SYNTAX);
35361f28255Scgd     cp = **v == ')' ? STRNULL : *v++;
35461f28255Scgd     if (*(*v++) != ')')
35561f28255Scgd 	v--;
356ee9e50eaSmycroft     if (*v)
35761f28255Scgd 	stderror(ERR_SYNTAX);
35861f28255Scgd     search(T_SWITCH, 0, lp = globone(cp, G_ERROR));
3591767ce60Schristos     free(lp);
36061f28255Scgd }
36161f28255Scgd 
36261f28255Scgd void
363cee2bad8Smycroft /*ARGSUSED*/
dobreak(Char ** v,struct command * t)364b771e65bSwiz dobreak(Char **v, struct command *t)
36561f28255Scgd {
36661f28255Scgd     if (whyles)
36761f28255Scgd 	toend();
368ee9e50eaSmycroft     else
36961f28255Scgd 	stderror(ERR_NAME | ERR_NOTWHILE);
37061f28255Scgd }
37161f28255Scgd 
37261f28255Scgd void
373cee2bad8Smycroft /*ARGSUSED*/
doexit(Char ** v,struct command * t)374b771e65bSwiz doexit(Char **v, struct command *t)
37561f28255Scgd {
37661f28255Scgd     if (chkstop == 0 && (intty || intact) && evalvec == 0)
37761f28255Scgd 	panystop(0);
37861f28255Scgd     /*
37961f28255Scgd      * Don't DEMAND parentheses here either.
38061f28255Scgd      */
38161f28255Scgd     v++;
38261f28255Scgd     if (*v) {
383cee2bad8Smycroft 	set(STRstatus, putn(expr(&v)));
384ee9e50eaSmycroft 	if (*v)
38561f28255Scgd 	    stderror(ERR_NAME | ERR_EXPRESSION);
38661f28255Scgd     }
38761f28255Scgd     btoeof();
38861f28255Scgd     if (intty)
38961f28255Scgd 	(void) close(SHIN);
39061f28255Scgd }
39161f28255Scgd 
39261f28255Scgd void
393cee2bad8Smycroft /*ARGSUSED*/
doforeach(Char ** v,struct command * t)394b771e65bSwiz doforeach(Char **v, struct command *t)
39561f28255Scgd {
39676adbe2bStls     struct whyle *nwp;
397b771e65bSwiz     Char *cp, *sp;
39861f28255Scgd 
39961f28255Scgd     v++;
40061f28255Scgd     sp = cp = strip(*v);
401ee9e50eaSmycroft     if (!letter(*sp))
40261f28255Scgd 	stderror(ERR_NAME | ERR_VARBEGIN);
40361f28255Scgd     while (*cp && alnum(*cp))
40461f28255Scgd 	cp++;
405ee9e50eaSmycroft     if (*cp)
40661f28255Scgd 	stderror(ERR_NAME | ERR_VARALNUM);
407ee9e50eaSmycroft     if ((cp - sp) > MAXVARLEN)
40861f28255Scgd 	stderror(ERR_NAME | ERR_VARTOOLONG);
40961f28255Scgd     cp = *v++;
410ee9e50eaSmycroft     if (v[0][0] != '(' || v[blklen(v) - 1][0] != ')')
41161f28255Scgd 	stderror(ERR_NAME | ERR_NOPAREN);
41261f28255Scgd     v++;
41361f28255Scgd     gflag = 0, tglob(v);
41461f28255Scgd     v = globall(v);
415ee9e50eaSmycroft     if (v == 0)
41661f28255Scgd 	stderror(ERR_NAME | ERR_NOMATCH);
41785bd10cbSdholland     nwp = xcalloc(1, sizeof *nwp);
41861f28255Scgd     nwp->w_fe = nwp->w_fe0 = v;
41961f28255Scgd     gargv = 0;
420cee2bad8Smycroft     btell(&nwp->w_start);
42161f28255Scgd     nwp->w_fename = Strsave(cp);
42261f28255Scgd     nwp->w_next = whyles;
423cee2bad8Smycroft     nwp->w_end.type = F_SEEK;
42461f28255Scgd     whyles = nwp;
42561f28255Scgd     /*
42661f28255Scgd      * Pre-read the loop so as to be more comprehensible to a terminal user.
42761f28255Scgd      */
42861f28255Scgd     if (intty)
42961f28255Scgd 	preread();
43061f28255Scgd     doagain();
43161f28255Scgd }
43261f28255Scgd 
43361f28255Scgd void
434cee2bad8Smycroft /*ARGSUSED*/
dowhile(Char ** v,struct command * t)435b771e65bSwiz dowhile(Char **v, struct command *t)
43661f28255Scgd {
43776adbe2bStls     int status;
438b79c2ef2Schristos     int again;
43961f28255Scgd 
440b771e65bSwiz     again = whyles != 0 && SEEKEQ(&whyles->w_start, &lineloc) &&
441b771e65bSwiz         whyles->w_fename == 0;
44261f28255Scgd     v++;
44361f28255Scgd     /*
44461f28255Scgd      * Implement prereading here also, taking care not to evaluate the
44561f28255Scgd      * expression before the loop has been read up from a terminal.
44661f28255Scgd      */
44761f28255Scgd     if (intty && !again)
44861f28255Scgd 	status = !exp0(&v, 1);
44961f28255Scgd     else
450cee2bad8Smycroft 	status = !expr(&v);
451ee9e50eaSmycroft     if (*v)
45261f28255Scgd 	stderror(ERR_NAME | ERR_EXPRESSION);
45361f28255Scgd     if (!again) {
45476adbe2bStls 	struct whyle *nwp =
45585bd10cbSdholland 		xcalloc(1, sizeof(*nwp));
45661f28255Scgd 
45761f28255Scgd 	nwp->w_start = lineloc;
458cee2bad8Smycroft 	nwp->w_end.type = F_SEEK;
459cee2bad8Smycroft 	nwp->w_end.f_seek = 0;
46061f28255Scgd 	nwp->w_next = whyles;
46161f28255Scgd 	whyles = nwp;
46261f28255Scgd 	if (intty) {
46361f28255Scgd 	    /*
46461f28255Scgd 	     * The tty preread
46561f28255Scgd 	     */
46661f28255Scgd 	    preread();
46761f28255Scgd 	    doagain();
46861f28255Scgd 	    return;
46961f28255Scgd 	}
47061f28255Scgd     }
47161f28255Scgd     if (status)
47261f28255Scgd 	/* We ain't gonna loop no more, no more! */
47361f28255Scgd 	toend();
47461f28255Scgd }
47561f28255Scgd 
47661f28255Scgd static void
preread(void)477b771e65bSwiz preread(void)
47861f28255Scgd {
479b3df6303Skleink     sigset_t nsigset;
4807b38403cSmycroft 
481cee2bad8Smycroft     whyles->w_end.type = I_SEEK;
4827b38403cSmycroft     if (setintr) {
483b3df6303Skleink 	sigemptyset(&nsigset);
484b3df6303Skleink 	(void) sigaddset(&nsigset, SIGINT);
485b3df6303Skleink 	(void) sigprocmask(SIG_UNBLOCK, &nsigset, NULL);
4867b38403cSmycroft     }
48761f28255Scgd 
48861f28255Scgd     search(T_BREAK, 0, NULL);		/* read the expression in */
48961f28255Scgd     if (setintr)
490b3df6303Skleink 	(void)sigprocmask(SIG_BLOCK, &nsigset, NULL);
491cee2bad8Smycroft     btell(&whyles->w_end);
49261f28255Scgd }
49361f28255Scgd 
49461f28255Scgd void
495cee2bad8Smycroft /*ARGSUSED*/
doend(Char ** v,struct command * t)496b771e65bSwiz doend(Char **v, struct command *t)
49761f28255Scgd {
498ee9e50eaSmycroft     if (!whyles)
49961f28255Scgd 	stderror(ERR_NAME | ERR_NOTWHILE);
500cee2bad8Smycroft     btell(&whyles->w_end);
50161f28255Scgd     doagain();
50261f28255Scgd }
50361f28255Scgd 
50461f28255Scgd void
505cee2bad8Smycroft /*ARGSUSED*/
docontin(Char ** v,struct command * t)506b771e65bSwiz docontin(Char **v, struct command *t)
50761f28255Scgd {
508ee9e50eaSmycroft     if (!whyles)
50961f28255Scgd 	stderror(ERR_NAME | ERR_NOTWHILE);
51061f28255Scgd     doagain();
51161f28255Scgd }
51261f28255Scgd 
51361f28255Scgd static void
doagain(void)514b771e65bSwiz doagain(void)
51561f28255Scgd {
51661f28255Scgd     /* Repeating a while is simple */
51761f28255Scgd     if (whyles->w_fename == 0) {
518cee2bad8Smycroft 	bseek(&whyles->w_start);
51961f28255Scgd 	return;
52061f28255Scgd     }
52161f28255Scgd     /*
52261f28255Scgd      * The foreach variable list actually has a spurious word ")" at the end of
52361f28255Scgd      * the w_fe list.  Thus we are at the of the list if one word beyond this
52461f28255Scgd      * is 0.
52561f28255Scgd      */
52661f28255Scgd     if (!whyles->w_fe[1]) {
527cee2bad8Smycroft 	dobreak(NULL, NULL);
52861f28255Scgd 	return;
52961f28255Scgd     }
53061f28255Scgd     set(whyles->w_fename, Strsave(*whyles->w_fe++));
531cee2bad8Smycroft     bseek(&whyles->w_start);
53261f28255Scgd }
53361f28255Scgd 
53461f28255Scgd void
dorepeat(Char ** v,struct command * kp)535b771e65bSwiz dorepeat(Char **v, struct command *kp)
53661f28255Scgd {
53776adbe2bStls     int i;
538b3df6303Skleink     sigset_t nsigset;
53961f28255Scgd 
54061f28255Scgd     i = getn(v[1]);
5417b38403cSmycroft     if (setintr) {
542b3df6303Skleink 	sigemptyset(&nsigset);
543b3df6303Skleink 	(void)sigaddset(&nsigset, SIGINT);
544b3df6303Skleink 	(void)sigprocmask(SIG_BLOCK, &nsigset, NULL);
5457b38403cSmycroft     }
54661f28255Scgd     lshift(v, 2);
54761f28255Scgd     while (i > 0) {
54861f28255Scgd 	if (setintr)
549b3df6303Skleink 	    (void)sigprocmask(SIG_UNBLOCK, &nsigset, NULL);
55061f28255Scgd 	reexecute(kp);
55161f28255Scgd 	--i;
55261f28255Scgd     }
55361f28255Scgd     donefds();
55461f28255Scgd     if (setintr)
555b3df6303Skleink 	(void) sigprocmask(SIG_UNBLOCK, &nsigset, NULL);
55661f28255Scgd }
55761f28255Scgd 
55861f28255Scgd void
559cee2bad8Smycroft /*ARGSUSED*/
doswbrk(Char ** v,struct command * t)560b771e65bSwiz doswbrk(Char **v, struct command *t)
56161f28255Scgd {
56261f28255Scgd     search(T_BRKSW, 0, NULL);
56361f28255Scgd }
56461f28255Scgd 
56561f28255Scgd int
srchx(Char * cp)566b771e65bSwiz srchx(Char *cp)
56761f28255Scgd {
56876adbe2bStls     struct srch *sp, *sp1, *sp2;
56976adbe2bStls     int i;
57061f28255Scgd 
57161f28255Scgd     /*
57261f28255Scgd      * Binary search Sp1 is the beginning of the current search range. Sp2 is
57361f28255Scgd      * one past the end.
57461f28255Scgd      */
57561f28255Scgd     for (sp1 = srchn, sp2 = srchn + nsrchn; sp1 < sp2;) {
57661f28255Scgd 	sp = sp1 + ((sp2 - sp1) >> 1);
57761f28255Scgd 	if ((i = *cp - *sp->s_name) == 0 &&
57861f28255Scgd 	    (i = Strcmp(cp, str2short(sp->s_name))) == 0)
57961f28255Scgd 	    return sp->s_value;
58061f28255Scgd 	if (i < 0)
58161f28255Scgd 	    sp2 = sp;
58261f28255Scgd 	else
58361f28255Scgd 	    sp1 = sp + 1;
58461f28255Scgd     }
58561f28255Scgd     return (-1);
58661f28255Scgd }
58761f28255Scgd 
58861f28255Scgd static Char Stype;
58961f28255Scgd static Char *Sgoal;
59061f28255Scgd 
59161f28255Scgd /*VARARGS2*/
592cee2bad8Smycroft static void
search(int type,int level,Char * goal)593b771e65bSwiz search(int type, int level, Char *goal)
59461f28255Scgd {
5950bf6fd0cSchristos     Char wordbuf[BUFSIZE];
596b771e65bSwiz     Char *aword, *cp;
5979a77f167Schristos     struct whyle *wp;
598626d1a41Schristos     int wlevel = 0;
59961f28255Scgd 
600b771e65bSwiz     aword = wordbuf;
60137e39248Schristos     Stype = (Char)type;
60261f28255Scgd     Sgoal = goal;
603cee2bad8Smycroft     if (type == T_GOTO) {
604cee2bad8Smycroft 	struct Ain a;
605cee2bad8Smycroft 	a.type = F_SEEK;
606cee2bad8Smycroft 	a.f_seek = 0;
607cee2bad8Smycroft 	bseek(&a);
608cee2bad8Smycroft     }
60961f28255Scgd     do {
610cee2bad8Smycroft 	if (intty && fseekp == feobp && aret == F_SEEK)
611cee2bad8Smycroft 	    (void)fprintf(cshout, "? "), (void)fflush(cshout);
61261f28255Scgd 	aword[0] = 0;
61361f28255Scgd 	(void)getword(aword);
61461f28255Scgd 	switch (srchx(aword)) {
61561f28255Scgd 	case T_CASE:
61661f28255Scgd 	    if (type != T_SWITCH || level != 0)
61761f28255Scgd 		break;
61861f28255Scgd 	    (void) getword(aword);
61961f28255Scgd 	    if (lastchr(aword) == ':')
62061f28255Scgd 		aword[Strlen(aword) - 1] = 0;
62161f28255Scgd 	    cp = strip(Dfix1(aword));
62261f28255Scgd 	    if (Gmatch(goal, cp))
62361f28255Scgd 		level = -1;
6241767ce60Schristos 	    free(cp);
62561f28255Scgd 	    break;
62661f28255Scgd 	case T_DEFAULT:
62761f28255Scgd 	    if (type == T_SWITCH && level == 0)
62861f28255Scgd 		level = -1;
62961f28255Scgd 	    break;
630b771e65bSwiz 	case T_ELSE:
631b771e65bSwiz 	    if (level == 0 && type == T_IF)
632b771e65bSwiz 		return;
633b771e65bSwiz 	    break;
634b771e65bSwiz 	case T_END:
6359a77f167Schristos 	    if (type == T_BRKSW) {
636626d1a41Schristos 		if (wlevel == 0) {
6379a77f167Schristos 		    wp = whyles;
6389a77f167Schristos 		    if (wp) {
6399a77f167Schristos 			whyles = wp->w_next;
6409a77f167Schristos 			wpfree(wp);
6419a77f167Schristos 		    }
6429a77f167Schristos 		}
643626d1a41Schristos 	    }
644b771e65bSwiz 	    if (type == T_BREAK)
645b771e65bSwiz 		level--;
646626d1a41Schristos 	    wlevel--;
647b771e65bSwiz 	    break;
648b771e65bSwiz 	case T_ENDIF:
649b771e65bSwiz 	    if (type == T_IF || type == T_ELSE)
650b771e65bSwiz 		level--;
651b771e65bSwiz 	    break;
652b771e65bSwiz 	case T_ENDSW:
653b771e65bSwiz 	    if (type == T_SWITCH || type == T_BRKSW)
654b771e65bSwiz 		level--;
655b771e65bSwiz 	    break;
656b771e65bSwiz 	case T_IF:
657b771e65bSwiz 	    while (getword(aword))
658b771e65bSwiz 		continue;
659b771e65bSwiz 	    if ((type == T_IF || type == T_ELSE) &&
660b771e65bSwiz 		eq(aword, STRthen))
661b771e65bSwiz 		level++;
662b771e65bSwiz 	    break;
663b771e65bSwiz 	case T_LABEL:
664b771e65bSwiz 	    if (type == T_GOTO && getword(aword) && eq(aword, goal))
665b771e65bSwiz 		level = -1;
666b771e65bSwiz 	    break;
667b771e65bSwiz 	case T_SWITCH:
668b771e65bSwiz 	    if (type == T_SWITCH || type == T_BRKSW)
669b771e65bSwiz 		level++;
670b771e65bSwiz 	    break;
671b771e65bSwiz 	case T_FOREACH:
672b771e65bSwiz 	case T_WHILE:
673626d1a41Schristos 	    wlevel++;
674b771e65bSwiz 	    if (type == T_BREAK)
675b771e65bSwiz 		level++;
676b771e65bSwiz 	    break;
677b771e65bSwiz 	default:
678b771e65bSwiz 	    if (type != T_GOTO && (type != T_SWITCH || level != 0))
679b771e65bSwiz 		break;
680b771e65bSwiz 	    if (lastchr(aword) != ':')
681b771e65bSwiz 		break;
682b771e65bSwiz 	    aword[Strlen(aword) - 1] = 0;
683b771e65bSwiz 	    if ((type == T_GOTO && eq(aword, goal)) ||
684b771e65bSwiz 		(type == T_SWITCH && eq(aword, STRdefault)))
685b771e65bSwiz 		level = -1;
686b771e65bSwiz 	    break;
68761f28255Scgd 	}
68861f28255Scgd 	(void) getword(NULL);
68961f28255Scgd     } while (level >= 0);
69061f28255Scgd }
69161f28255Scgd 
6929a77f167Schristos static void
wpfree(struct whyle * wp)6939a77f167Schristos wpfree(struct whyle *wp)
6949a77f167Schristos {
6959a77f167Schristos     if (wp->w_fe0)
6969a77f167Schristos 	blkfree(wp->w_fe0);
6979a77f167Schristos     if (wp->w_fename)
6981767ce60Schristos 	free(wp->w_fename);
6991767ce60Schristos     free(wp);
7009a77f167Schristos }
7019a77f167Schristos 
70261f28255Scgd static int
getword(Char * wp)703b771e65bSwiz getword(Char *wp)
70461f28255Scgd {
705b771e65bSwiz     int c, d, found, kwd;
706b771e65bSwiz     Char *owp;
70761f28255Scgd 
70861f28255Scgd     c = readc(1);
70961f28255Scgd     d = 0;
710b771e65bSwiz     found = 0;
711b771e65bSwiz     kwd = 0;
712b771e65bSwiz     owp = wp;
71361f28255Scgd     do {
71461f28255Scgd 	while (c == ' ' || c == '\t')
71561f28255Scgd 	    c = readc(1);
71661f28255Scgd 	if (c == '#')
71761f28255Scgd 	    do
71861f28255Scgd 		c = readc(1);
71961f28255Scgd 	    while (c >= 0 && c != '\n');
72061f28255Scgd 	if (c < 0)
72161f28255Scgd 	    goto past;
72261f28255Scgd 	if (c == '\n') {
72361f28255Scgd 	    if (wp)
72461f28255Scgd 		break;
72561f28255Scgd 	    return (0);
72661f28255Scgd 	}
72761f28255Scgd 	unreadc(c);
72861f28255Scgd 	found = 1;
72961f28255Scgd 	do {
73061f28255Scgd 	    c = readc(1);
73161f28255Scgd 	    if (c == '\\' && (c = readc(1)) == '\n')
73261f28255Scgd 		c = ' ';
733341bd18bSthorpej 	    if (c == '\'' || c == '"') {
73461f28255Scgd 		if (d == 0)
73561f28255Scgd 		    d = c;
73661f28255Scgd 		else if (d == c)
73761f28255Scgd 		    d = 0;
738341bd18bSthorpej 	    }
73961f28255Scgd 	    if (c < 0)
74061f28255Scgd 		goto past;
74161f28255Scgd 	    if (wp) {
74237e39248Schristos 		*wp++ = (Char)c;
74361f28255Scgd 		*wp = 0;	/* end the string b4 test */
74461f28255Scgd 	    }
745cee2bad8Smycroft 	} while ((d || (!(kwd = keyword(owp)) && c != ' '
746cee2bad8Smycroft 		  && c != '\t')) && c != '\n');
74761f28255Scgd     } while (wp == 0);
74861f28255Scgd 
74961f28255Scgd     /*
75061f28255Scgd      * if we have read a keyword ( "if", "switch" or "while" ) then we do not
75161f28255Scgd      * need to unreadc the look-ahead char
75261f28255Scgd      */
75361f28255Scgd     if (!kwd) {
75461f28255Scgd 	unreadc(c);
75561f28255Scgd 	if (found)
75661f28255Scgd 	    *--wp = 0;
75761f28255Scgd     }
75861f28255Scgd 
75961f28255Scgd     return (found);
76061f28255Scgd 
76161f28255Scgd past:
76261f28255Scgd     switch (Stype) {
76361f28255Scgd     case T_BREAK:
76461f28255Scgd 	stderror(ERR_NAME | ERR_NOTFOUND, "end");
765cdbd74daSmycroft 	/* NOTREACHED */
766b771e65bSwiz     case T_ELSE:
767b771e65bSwiz 	stderror(ERR_NAME | ERR_NOTFOUND, "endif");
768b771e65bSwiz 	/* NOTREACHED */
76961f28255Scgd     case T_GOTO:
770cee2bad8Smycroft 	setname(vis_str(Sgoal));
77161f28255Scgd 	stderror(ERR_NAME | ERR_NOTFOUND, "label");
77261f28255Scgd 	/* NOTREACHED */
773b771e65bSwiz     case T_IF:
774b771e65bSwiz 	stderror(ERR_NAME | ERR_NOTFOUND, "then/endif");
775b771e65bSwiz 	/* NOTREACHED */
776b771e65bSwiz     case T_BRKSW:
777b771e65bSwiz     case T_SWITCH:
778b771e65bSwiz 	stderror(ERR_NAME | ERR_NOTFOUND, "endsw");
779b771e65bSwiz 	/* NOTREACHED */
780cdbd74daSmycroft     }
78161f28255Scgd     return (0);
78261f28255Scgd }
78361f28255Scgd 
78461f28255Scgd /*
78561f28255Scgd  * keyword(wp) determines if wp is one of the built-n functions if,
78661f28255Scgd  * switch or while. It seems that when an if statement looks like
78761f28255Scgd  * "if(" then getword above sucks in the '(' and so the search routine
78861f28255Scgd  * never finds what it is scanning for. Rather than rewrite doword, I hack
78961f28255Scgd  * in a test to see if the string forms a keyword. Then doword stops
79061f28255Scgd  * and returns the word "if" -strike
79161f28255Scgd  */
79261f28255Scgd 
79361f28255Scgd static int
keyword(Char * wp)794b771e65bSwiz keyword(Char *wp)
79561f28255Scgd {
79661f28255Scgd     static Char STRswitch[] = {'s', 'w', 'i', 't', 'c', 'h', '\0'};
797b771e65bSwiz     static Char STRwhile[] = {'w', 'h', 'i', 'l', 'e', '\0'};
798b771e65bSwiz     static Char STRif[] = {'i', 'f', '\0'};
79961f28255Scgd 
80061f28255Scgd     if (!wp)
80161f28255Scgd 	return (0);
80261f28255Scgd 
80361f28255Scgd     if ((Strcmp(wp, STRif) == 0) || (Strcmp(wp, STRwhile) == 0)
80461f28255Scgd 	|| (Strcmp(wp, STRswitch) == 0))
80561f28255Scgd 	return (1);
80661f28255Scgd 
80761f28255Scgd     return (0);
80861f28255Scgd }
80961f28255Scgd 
81061f28255Scgd static void
toend(void)811b771e65bSwiz toend(void)
81261f28255Scgd {
813cee2bad8Smycroft     if (whyles->w_end.type == F_SEEK && whyles->w_end.f_seek == 0) {
81461f28255Scgd 	search(T_BREAK, 0, NULL);
815cee2bad8Smycroft 	btell(&whyles->w_end);
816cee2bad8Smycroft 	whyles->w_end.f_seek--;
81761f28255Scgd     }
81861f28255Scgd     else
819cee2bad8Smycroft 	bseek(&whyles->w_end);
82061f28255Scgd     wfree();
82161f28255Scgd }
82261f28255Scgd 
82361f28255Scgd void
wfree(void)824b771e65bSwiz wfree(void)
82561f28255Scgd {
826cee2bad8Smycroft     struct Ain o;
827cee2bad8Smycroft     struct whyle *nwp;
82861f28255Scgd 
829cee2bad8Smycroft     btell(&o);
830cee2bad8Smycroft 
831cee2bad8Smycroft     for (; whyles; whyles = nwp) {
83276adbe2bStls 	struct whyle *wp = whyles;
833cee2bad8Smycroft 	nwp = wp->w_next;
83461f28255Scgd 
835cee2bad8Smycroft 	/*
836cee2bad8Smycroft 	 * We free loops that have different seek types.
837cee2bad8Smycroft 	 */
838cee2bad8Smycroft 	if (wp->w_end.type != I_SEEK && wp->w_start.type == wp->w_end.type &&
839cee2bad8Smycroft 	    wp->w_start.type == o.type) {
840cee2bad8Smycroft 	    if (wp->w_end.type == F_SEEK) {
841cee2bad8Smycroft 		if (o.f_seek >= wp->w_start.f_seek &&
842cee2bad8Smycroft 		    (wp->w_end.f_seek == 0 || o.f_seek < wp->w_end.f_seek))
84361f28255Scgd 		    break;
844cee2bad8Smycroft 	    }
845cee2bad8Smycroft 	    else {
846cee2bad8Smycroft 		if (o.a_seek >= wp->w_start.a_seek &&
847cee2bad8Smycroft 		    (wp->w_end.a_seek == 0 || o.a_seek < wp->w_end.a_seek))
848cee2bad8Smycroft 		    break;
849cee2bad8Smycroft 	    }
850cee2bad8Smycroft 	}
851cee2bad8Smycroft 
8529a77f167Schristos 	wpfree(wp);
85361f28255Scgd     }
85461f28255Scgd }
85561f28255Scgd 
85661f28255Scgd void
857cee2bad8Smycroft /*ARGSUSED*/
doecho(Char ** v,struct command * t)858b771e65bSwiz doecho(Char **v, struct command *t)
85961f28255Scgd {
86061f28255Scgd     xecho(' ', v);
86161f28255Scgd }
86261f28255Scgd 
86361f28255Scgd void
864cee2bad8Smycroft /*ARGSUSED*/
doglob(Char ** v,struct command * t)865b771e65bSwiz doglob(Char **v, struct command *t)
86661f28255Scgd {
86761f28255Scgd     xecho(0, v);
868cee2bad8Smycroft     (void)fflush(cshout);
86961f28255Scgd }
87061f28255Scgd 
87161f28255Scgd static void
xecho(int sep,Char ** v)872b771e65bSwiz xecho(int sep, Char **v)
87361f28255Scgd {
87476adbe2bStls     Char *cp;
875b3df6303Skleink     sigset_t nsigset;
876b771e65bSwiz     int nonl;
87761f28255Scgd 
878b771e65bSwiz     nonl = 0;
8797b38403cSmycroft     if (setintr) {
880b3df6303Skleink 	sigemptyset(&nsigset);
881b3df6303Skleink 	(void)sigaddset(&nsigset, SIGINT);
882b3df6303Skleink 	(void)sigprocmask(SIG_UNBLOCK, &nsigset, NULL);
8837b38403cSmycroft     }
88461f28255Scgd     v++;
88561f28255Scgd     if (*v == 0)
8865aaa5482Schristos 	goto done;
88761f28255Scgd     gflag = 0, tglob(v);
88861f28255Scgd     if (gflag) {
88961f28255Scgd 	v = globall(v);
890ee9e50eaSmycroft 	if (v == 0)
89161f28255Scgd 	    stderror(ERR_NAME | ERR_NOMATCH);
89261f28255Scgd     }
89361f28255Scgd     else {
89461f28255Scgd 	v = gargv = saveblk(v);
89561f28255Scgd 	trim(v);
89661f28255Scgd     }
89761f28255Scgd     if (sep == ' ' && *v && eq(*v, STRmn))
89861f28255Scgd 	nonl++, v++;
899cee2bad8Smycroft     while ((cp = *v++) != NULL) {
90076adbe2bStls 	int c;
90161f28255Scgd 
902cee2bad8Smycroft 	while ((c = *cp++) != '\0')
903cee2bad8Smycroft 	    (void)vis_fputc(c | QUOTE, cshout);
90461f28255Scgd 
90561f28255Scgd 	if (*v)
906cee2bad8Smycroft 	    (void)vis_fputc(sep | QUOTE, cshout);
90761f28255Scgd     }
9085aaa5482Schristos done:
90961f28255Scgd     if (sep && nonl == 0)
910cee2bad8Smycroft 	(void)fputc('\n', cshout);
91161f28255Scgd     else
912cee2bad8Smycroft 	(void)fflush(cshout);
91361f28255Scgd     if (setintr)
914b3df6303Skleink 	(void)sigprocmask(SIG_BLOCK, &nsigset, NULL);
91561f28255Scgd     if (gargv)
91661f28255Scgd 	blkfree(gargv), gargv = 0;
91761f28255Scgd }
91861f28255Scgd 
91961f28255Scgd void
920cee2bad8Smycroft /*ARGSUSED*/
dosetenv(Char ** v,struct command * t)921b771e65bSwiz dosetenv(Char **v, struct command *t)
92261f28255Scgd {
923b771e65bSwiz     Char *lp, *vp;
924b3df6303Skleink     sigset_t nsigset;
92561f28255Scgd 
92661f28255Scgd     v++;
92761f28255Scgd     if ((vp = *v++) == 0) {
92876adbe2bStls 	Char **ep;
92961f28255Scgd 
9307b38403cSmycroft 	if (setintr) {
931b3df6303Skleink 	    sigemptyset(&nsigset);
932b3df6303Skleink 	    (void)sigaddset(&nsigset, SIGINT);
933b3df6303Skleink 	    (void)sigprocmask(SIG_UNBLOCK, &nsigset, NULL);
9347b38403cSmycroft 	}
93561f28255Scgd 	for (ep = STR_environ; *ep; ep++)
936cee2bad8Smycroft 	    (void)fprintf(cshout, "%s\n", vis_str(*ep));
93761f28255Scgd 	return;
93861f28255Scgd     }
93961f28255Scgd     if ((lp = *v++) == 0)
94061f28255Scgd 	lp = STRNULL;
941cee2bad8Smycroft     Setenv(vp, lp = globone(lp, G_APPEND));
94261f28255Scgd     if (eq(vp, STRPATH)) {
94361f28255Scgd 	importpath(lp);
944cee2bad8Smycroft 	dohash(NULL, NULL);
94561f28255Scgd     }
94661f28255Scgd     else if (eq(vp, STRLANG) || eq(vp, STRLC_CTYPE)) {
94761f28255Scgd #ifdef NLS
94861f28255Scgd 	int k;
94961f28255Scgd 
95061f28255Scgd 	(void)setlocale(LC_ALL, "");
951cee2bad8Smycroft 	for (k = 0200; k <= 0377 && !Isprint(k); k++)
952cee2bad8Smycroft 		continue;
95361f28255Scgd 	AsciiOnly = k > 0377;
95461f28255Scgd #else
95561f28255Scgd 	AsciiOnly = 0;
95661f28255Scgd #endif				/* NLS */
95761f28255Scgd     }
9581767ce60Schristos     free(lp);
95961f28255Scgd }
96061f28255Scgd 
96161f28255Scgd void
962cee2bad8Smycroft /*ARGSUSED*/
dounsetenv(Char ** v,struct command * t)963b771e65bSwiz dounsetenv(Char **v, struct command *t)
96461f28255Scgd {
965b771e65bSwiz     static Char *name = NULL;
96661f28255Scgd     Char **ep, *p, *n;
96761f28255Scgd     int i, maxi;
96861f28255Scgd 
96961f28255Scgd     if (name)
9701767ce60Schristos 	free(name);
97161f28255Scgd     /*
97261f28255Scgd      * Find the longest environment variable
97361f28255Scgd      */
97461f28255Scgd     for (maxi = 0, ep = STR_environ; *ep; ep++) {
975cee2bad8Smycroft 	for (i = 0, p = *ep; *p && *p != '='; p++, i++)
976cee2bad8Smycroft 	    continue;
97761f28255Scgd 	if (i > maxi)
97861f28255Scgd 	    maxi = i;
97961f28255Scgd     }
98061f28255Scgd 
981*509d26c5Snia     name = xreallocarray(NULL, (size_t)(maxi + 1), sizeof(Char));
98261f28255Scgd 
98361f28255Scgd     while (++v && *v)
98461f28255Scgd 	for (maxi = 1; maxi;)
98561f28255Scgd 	    for (maxi = 0, ep = STR_environ; *ep; ep++) {
986cee2bad8Smycroft 		for (n = name, p = *ep; *p && *p != '='; *n++ = *p++)
987cee2bad8Smycroft 		    continue;
98861f28255Scgd 		*n = '\0';
98961f28255Scgd 		if (!Gmatch(name, *v))
99061f28255Scgd 		    continue;
99161f28255Scgd 		maxi = 1;
99261f28255Scgd 		if (eq(name, STRLANG) || eq(name, STRLC_CTYPE)) {
99361f28255Scgd #ifdef NLS
99461f28255Scgd 		    int     k;
99561f28255Scgd 
99661f28255Scgd 		    (void) setlocale(LC_ALL, "");
997cee2bad8Smycroft 		    for (k = 0200; k <= 0377 && !Isprint(k); k++)
998cee2bad8Smycroft 			continue;
99961f28255Scgd 		    AsciiOnly = k > 0377;
100061f28255Scgd #else
100161f28255Scgd 		    AsciiOnly = getenv("LANG") == NULL &&
100261f28255Scgd 			getenv("LC_CTYPE") == NULL;
100361f28255Scgd #endif				/* NLS */
100461f28255Scgd 		}
100561f28255Scgd 		/*
100661f28255Scgd 		 * Delete name, and start again cause the environment changes
100761f28255Scgd 		 */
100861f28255Scgd 		Unsetenv(name);
100961f28255Scgd 		break;
101061f28255Scgd 	    }
10111767ce60Schristos     free(name);
1012cee2bad8Smycroft     name = NULL;
101361f28255Scgd }
101461f28255Scgd 
101561f28255Scgd void
Setenv(Char * name,Char * val)1016b771e65bSwiz Setenv(Char *name, Char *val)
101761f28255Scgd {
1018b771e65bSwiz     Char *blk[2], *cp, *dp, **ep, **oep;
101961f28255Scgd 
1020b771e65bSwiz     ep = STR_environ;
1021b771e65bSwiz     oep = ep;
102261f28255Scgd 
102361f28255Scgd     for (; *ep; ep++) {
102461f28255Scgd 	for (cp = name, dp = *ep; *cp && *cp == *dp; cp++, dp++)
102561f28255Scgd 	    continue;
102661f28255Scgd 	if (*cp != 0 || *dp != '=')
102761f28255Scgd 	    continue;
102861f28255Scgd 	cp = Strspl(STRequal, val);
10291767ce60Schristos 	free(* ep);
103061f28255Scgd 	*ep = strip(Strspl(name, cp));
10311767ce60Schristos 	free(cp);
103261f28255Scgd 	blkfree((Char **)environ);
103361f28255Scgd 	environ = short2blk(STR_environ);
103461f28255Scgd 	return;
103561f28255Scgd     }
103661f28255Scgd     cp = Strspl(name, STRequal);
103761f28255Scgd     blk[0] = strip(Strspl(cp, val));
10381767ce60Schristos     free(cp);
103961f28255Scgd     blk[1] = 0;
104061f28255Scgd     STR_environ = blkspl(STR_environ, blk);
104161f28255Scgd     blkfree((Char **)environ);
104261f28255Scgd     environ = short2blk(STR_environ);
10431767ce60Schristos     free(oep);
104461f28255Scgd }
104561f28255Scgd 
104661f28255Scgd static void
Unsetenv(Char * name)1047b771e65bSwiz Unsetenv(Char *name)
104861f28255Scgd {
1049b771e65bSwiz     Char *cp, *dp, **ep, **oep;
1050b771e65bSwiz 
1051b771e65bSwiz     ep = STR_environ;
1052b771e65bSwiz     oep = ep;
105361f28255Scgd 
105461f28255Scgd     for (; *ep; ep++) {
105561f28255Scgd 	for (cp = name, dp = *ep; *cp && *cp == *dp; cp++, dp++)
105661f28255Scgd 	    continue;
105761f28255Scgd 	if (*cp != 0 || *dp != '=')
105861f28255Scgd 	    continue;
105961f28255Scgd 	cp = *ep;
106061f28255Scgd 	*ep = 0;
106161f28255Scgd 	STR_environ = blkspl(STR_environ, ep + 1);
106261f28255Scgd 	environ = short2blk(STR_environ);
106361f28255Scgd 	*ep = cp;
10641767ce60Schristos 	free(cp);
10651767ce60Schristos 	free(oep);
106661f28255Scgd 	return;
106761f28255Scgd     }
106861f28255Scgd }
106961f28255Scgd 
107061f28255Scgd void
1071cee2bad8Smycroft /*ARGSUSED*/
doumask(Char ** v,struct command * t)1072b771e65bSwiz doumask(Char **v, struct command *t)
107361f28255Scgd {
1074b771e65bSwiz     Char *cp;
107537e39248Schristos     mode_t i;
107661f28255Scgd 
1077b771e65bSwiz     cp = v[1];
107861f28255Scgd     if (cp == 0) {
107961f28255Scgd 	i = umask(0);
108061f28255Scgd 	(void)umask(i);
1081cee2bad8Smycroft 	(void)fprintf(cshout, "%o\n", i);
108261f28255Scgd 	return;
108361f28255Scgd     }
108461f28255Scgd     i = 0;
108561f28255Scgd     while (Isdigit(*cp) && *cp != '8' && *cp != '9')
108637e39248Schristos 	i = i * 8 + (mode_t)(*cp++ - '0');
108737e39248Schristos     if (*cp || i > 0777)
108861f28255Scgd 	stderror(ERR_NAME | ERR_MASK);
108961f28255Scgd     (void)umask(i);
109061f28255Scgd }
109161f28255Scgd 
10921da7ff99Swiz typedef rlim_t RLIM_TYPE;
109361f28255Scgd 
1094cdbd74daSmycroft static const struct limits {
109561f28255Scgd     int     limconst;
1096cdbd74daSmycroft     const   char *limname;
109761f28255Scgd     int     limdiv;
1098cdbd74daSmycroft     const   char *limscale;
109961f28255Scgd }       limits[] = {
1100cee2bad8Smycroft     { RLIMIT_CPU,	"cputime",	1,	"seconds" },
1101cee2bad8Smycroft     { RLIMIT_FSIZE,	"filesize",	1024,	"kbytes" },
1102cee2bad8Smycroft     { RLIMIT_DATA,	"datasize",	1024,	"kbytes" },
1103cee2bad8Smycroft     { RLIMIT_STACK,	"stacksize",	1024,	"kbytes" },
1104cee2bad8Smycroft     { RLIMIT_CORE,	"coredumpsize", 1024,	"kbytes" },
1105cee2bad8Smycroft     { RLIMIT_RSS,	"memoryuse",	1024,	"kbytes" },
1106cee2bad8Smycroft     { RLIMIT_MEMLOCK,	"memorylocked",	1024,	"kbytes" },
1107cee2bad8Smycroft     { RLIMIT_NPROC,	"maxproc",	1,	"" },
11088af1ed16Schristos     { RLIMIT_NTHR,	"maxthread",	1,	"" },
1109cee2bad8Smycroft     { RLIMIT_NOFILE,	"openfiles",	1,	"" },
11106acf809eSchristos     { RLIMIT_SBSIZE,	"sbsize",	1,	"bytes" },
1111fcc02354Smrg     { RLIMIT_AS,	"vmemoryuse",	1024,	"kbytes" },
1112cee2bad8Smycroft     { -1,		NULL,		0,	NULL }
111361f28255Scgd };
111461f28255Scgd 
1115b771e65bSwiz static const struct limits *findlim(Char *);
1116b771e65bSwiz static RLIM_TYPE getval(const struct limits *, Char **);
11176310b596Schristos static void limtail(Char *, const char *);
1118b771e65bSwiz static void plim(const struct limits *, Char);
1119b771e65bSwiz static int setlim(const struct limits *, Char, RLIM_TYPE);
112061f28255Scgd 
1121cdbd74daSmycroft static const struct limits *
findlim(Char * cp)1122b771e65bSwiz findlim(Char *cp)
112361f28255Scgd {
1124cdbd74daSmycroft     const struct limits *lp, *res;
112561f28255Scgd 
11269f61b804Splunky     res = NULL;
112761f28255Scgd     for (lp = limits; lp->limconst >= 0; lp++)
112861f28255Scgd 	if (prefix(cp, str2short(lp->limname))) {
1129ee9e50eaSmycroft 	    if (res)
113061f28255Scgd 		stderror(ERR_NAME | ERR_AMBIG);
113161f28255Scgd 	    res = lp;
113261f28255Scgd 	}
113361f28255Scgd     if (res)
113461f28255Scgd 	return (res);
113561f28255Scgd     stderror(ERR_NAME | ERR_LIMIT);
113661f28255Scgd     /* NOTREACHED */
113761f28255Scgd }
113861f28255Scgd 
113961f28255Scgd void
1140cee2bad8Smycroft /*ARGSUSED*/
dolimit(Char ** v,struct command * t)1141b771e65bSwiz dolimit(Char **v, struct command *t)
114261f28255Scgd {
1143cdbd74daSmycroft     const struct limits *lp;
114476adbe2bStls     RLIM_TYPE limit;
1145b771e65bSwiz     char hard;
114661f28255Scgd 
1147b771e65bSwiz     hard = 0;
114861f28255Scgd     v++;
114961f28255Scgd     if (*v && eq(*v, STRmh)) {
115061f28255Scgd 	hard = 1;
115161f28255Scgd 	v++;
115261f28255Scgd     }
115361f28255Scgd     if (*v == 0) {
115461f28255Scgd 	for (lp = limits; lp->limconst >= 0; lp++)
115561f28255Scgd 	    plim(lp, hard);
115661f28255Scgd 	return;
115761f28255Scgd     }
115861f28255Scgd     lp = findlim(v[0]);
115961f28255Scgd     if (v[1] == 0) {
116061f28255Scgd 	plim(lp, hard);
116161f28255Scgd 	return;
116261f28255Scgd     }
116361f28255Scgd     limit = getval(lp, v + 1);
1164ee9e50eaSmycroft     if (setlim(lp, hard, limit) < 0)
116561f28255Scgd 	stderror(ERR_SILENT);
116661f28255Scgd }
116761f28255Scgd 
116861f28255Scgd static  RLIM_TYPE
getval(const struct limits * lp,Char ** v)1169b771e65bSwiz getval(const struct limits *lp, Char **v)
117061f28255Scgd {
1171b771e65bSwiz     Char *cp;
117237e39248Schristos     double d;
117361f28255Scgd 
1174b771e65bSwiz     cp = *v++;
117537e39248Schristos     d = atof(short2str(cp));
117661f28255Scgd 
117761f28255Scgd     while (Isdigit(*cp) || *cp == '.' || *cp == 'e' || *cp == 'E')
117861f28255Scgd 	cp++;
117961f28255Scgd     if (*cp == 0) {
118061f28255Scgd 	if (*v == 0)
118137e39248Schristos 	    return ((RLIM_TYPE)((d + 0.5) * lp->limdiv));
118261f28255Scgd 	cp = *v;
118361f28255Scgd     }
118461f28255Scgd     switch (*cp) {
118561f28255Scgd     case ':':
118661f28255Scgd 	if (lp->limconst != RLIMIT_CPU)
118761f28255Scgd 	    goto badscal;
118837e39248Schristos 	return ((RLIM_TYPE)(d * 60.0 + atof(short2str(cp + 1))));
1189b771e65bSwiz     case 'M':
1190b771e65bSwiz 	if (lp->limconst == RLIMIT_CPU)
1191b771e65bSwiz 	    goto badscal;
1192b771e65bSwiz 	*cp = 'm';
1193b771e65bSwiz 	limtail(cp, "megabytes");
119437e39248Schristos 	d *= 1024.0 * 1024.0;
1195b771e65bSwiz 	break;
119661f28255Scgd     case 'h':
119761f28255Scgd 	if (lp->limconst != RLIMIT_CPU)
119861f28255Scgd 	    goto badscal;
119961f28255Scgd 	limtail(cp, "hours");
120037e39248Schristos 	d *= 3600.0;
120161f28255Scgd 	break;
1202b771e65bSwiz     case 'k':
1203b771e65bSwiz 	if (lp->limconst == RLIMIT_CPU)
1204b771e65bSwiz 	    goto badscal;
1205b771e65bSwiz 	limtail(cp, "kbytes");
120637e39248Schristos 	d *= 1024.0;
1207b771e65bSwiz 	break;
120861f28255Scgd     case 'm':
120961f28255Scgd 	if (lp->limconst == RLIMIT_CPU) {
121061f28255Scgd 	    limtail(cp, "minutes");
121137e39248Schristos 	    d *= 60.0;
121261f28255Scgd 	    break;
121361f28255Scgd 	}
121461f28255Scgd 	*cp = 'm';
121561f28255Scgd 	limtail(cp, "megabytes");
121637e39248Schristos 	d *= 1024.0 * 1024.0;
121761f28255Scgd 	break;
121861f28255Scgd     case 's':
121961f28255Scgd 	if (lp->limconst != RLIMIT_CPU)
122061f28255Scgd 	    goto badscal;
122161f28255Scgd 	limtail(cp, "seconds");
122261f28255Scgd 	break;
122361f28255Scgd     case 'u':
122461f28255Scgd 	limtail(cp, "unlimited");
122561f28255Scgd 	return (RLIM_INFINITY);
122661f28255Scgd     default:
122761f28255Scgd     badscal:
122861f28255Scgd 	stderror(ERR_NAME | ERR_SCALEF);
1229cdbd74daSmycroft 	/* NOTREACHED */
123061f28255Scgd     }
123137e39248Schristos     d += 0.5;
123237e39248Schristos     if (d > (double) RLIM_INFINITY)
1233cee2bad8Smycroft 	return RLIM_INFINITY;
1234cee2bad8Smycroft     else
123537e39248Schristos 	return ((RLIM_TYPE)d);
123661f28255Scgd }
123761f28255Scgd 
123861f28255Scgd static void
limtail(Char * cp,const char * str)12396310b596Schristos limtail(Char *cp, const char *str)
124061f28255Scgd {
124161f28255Scgd     while (*cp && *cp == *str)
124261f28255Scgd 	cp++, str++;
1243ee9e50eaSmycroft     if (*cp)
124461f28255Scgd 	stderror(ERR_BADSCALE, str);
124561f28255Scgd }
124661f28255Scgd 
124761f28255Scgd 
124861f28255Scgd /*ARGSUSED*/
124961f28255Scgd static void
plim(const struct limits * lp,Char hard)1250b771e65bSwiz plim(const struct limits *lp, Char hard)
125161f28255Scgd {
125261f28255Scgd     struct rlimit rlim;
125361f28255Scgd     RLIM_TYPE limit;
125461f28255Scgd 
12556acf809eSchristos     (void)fprintf(cshout, "%-13.13s", lp->limname);
125661f28255Scgd 
125761f28255Scgd     (void)getrlimit(lp->limconst, &rlim);
125861f28255Scgd     limit = hard ? rlim.rlim_max : rlim.rlim_cur;
125961f28255Scgd 
126061f28255Scgd     if (limit == RLIM_INFINITY)
1261cee2bad8Smycroft 	(void)fprintf(cshout, "unlimited");
126261f28255Scgd     else if (lp->limconst == RLIMIT_CPU)
126361f28255Scgd 	psecs((long) limit);
126461f28255Scgd     else
126537e39248Schristos 	(void)fprintf(cshout, "%jd %s",
126637e39248Schristos 	    (intmax_t) (limit / (RLIM_TYPE)lp->limdiv), lp->limscale);
1267cee2bad8Smycroft     (void)fputc('\n', cshout);
126861f28255Scgd }
126961f28255Scgd 
127061f28255Scgd void
1271cee2bad8Smycroft /*ARGSUSED*/
dounlimit(Char ** v,struct command * t)1272b771e65bSwiz dounlimit(Char **v, struct command *t)
127361f28255Scgd {
1274cdbd74daSmycroft     const struct limits *lp;
1275b771e65bSwiz     int lerr;
1276b771e65bSwiz     Char hard;
127761f28255Scgd 
1278b771e65bSwiz     lerr = 0;
1279b771e65bSwiz     hard = 0;
128061f28255Scgd     v++;
128161f28255Scgd     if (*v && eq(*v, STRmh)) {
128261f28255Scgd 	hard = 1;
128361f28255Scgd 	v++;
128461f28255Scgd     }
128561f28255Scgd     if (*v == 0) {
128661f28255Scgd 	for (lp = limits; lp->limconst >= 0; lp++)
128761f28255Scgd 	    if (setlim(lp, hard, (RLIM_TYPE)RLIM_INFINITY) < 0)
128861f28255Scgd 		lerr++;
1289ee9e50eaSmycroft 	if (lerr)
129061f28255Scgd 	    stderror(ERR_SILENT);
129161f28255Scgd 	return;
129261f28255Scgd     }
129361f28255Scgd     while (*v) {
129461f28255Scgd 	lp = findlim(*v++);
1295ee9e50eaSmycroft 	if (setlim(lp, hard, (RLIM_TYPE)RLIM_INFINITY) < 0)
129661f28255Scgd 	    stderror(ERR_SILENT);
129761f28255Scgd     }
129861f28255Scgd }
129961f28255Scgd 
130061f28255Scgd static int
setlim(const struct limits * lp,Char hard,RLIM_TYPE limit)1301b771e65bSwiz setlim(const struct limits *lp, Char hard, RLIM_TYPE limit)
130261f28255Scgd {
130361f28255Scgd     struct rlimit rlim;
130461f28255Scgd 
130561f28255Scgd     (void)getrlimit(lp->limconst, &rlim);
130661f28255Scgd 
130761f28255Scgd     if (hard)
130861f28255Scgd 	rlim.rlim_max = limit;
130961f28255Scgd     else if (limit == RLIM_INFINITY && geteuid() != 0)
131061f28255Scgd 	rlim.rlim_cur = rlim.rlim_max;
131161f28255Scgd     else
131261f28255Scgd 	rlim.rlim_cur = limit;
131361f28255Scgd 
13148c43d5edSchristos     if (rlim.rlim_max < rlim.rlim_cur)
13158c43d5edSchristos 	rlim.rlim_max = rlim.rlim_cur;
13168c43d5edSchristos 
131761f28255Scgd     if (setrlimit(lp->limconst, &rlim) < 0) {
13188c43d5edSchristos 	(void)fprintf(csherr, "%s: %s: Can't %s%s limit (%s)\n", bname,
13198c43d5edSchristos 	    lp->limname, limit == RLIM_INFINITY ? "remove" : "set",
13208c43d5edSchristos 	    hard ? " hard" : "", strerror(errno));
132161f28255Scgd 	return (-1);
132261f28255Scgd     }
132361f28255Scgd     return (0);
132461f28255Scgd }
132561f28255Scgd 
132661f28255Scgd void
1327cee2bad8Smycroft /*ARGSUSED*/
dosuspend(Char ** v,struct command * t)1328b771e65bSwiz dosuspend(Char **v, struct command *t)
132961f28255Scgd {
133061f28255Scgd     int     ctpgrp;
1331b771e65bSwiz     void    (*old)(int);
133261f28255Scgd 
1333ee9e50eaSmycroft     if (loginsh)
133461f28255Scgd 	stderror(ERR_SUSPLOG);
133561f28255Scgd     untty();
133661f28255Scgd 
133761f28255Scgd     old = signal(SIGTSTP, SIG_DFL);
133861f28255Scgd     (void)kill(0, SIGTSTP);
133961f28255Scgd     /* the shell stops here */
134061f28255Scgd     (void)signal(SIGTSTP, old);
134161f28255Scgd 
134261f28255Scgd     if (tpgrp != -1) {
1343a8a54fa6Schristos retry:
134461f28255Scgd 	ctpgrp = tcgetpgrp(FSHTTY);
1345a8a54fa6Schristos 	if  (ctpgrp != opgrp) {
134661f28255Scgd 	    old = signal(SIGTTIN, SIG_DFL);
134761f28255Scgd 	    (void)kill(0, SIGTTIN);
134861f28255Scgd 	    (void)signal(SIGTTIN, old);
1349a8a54fa6Schristos 	    goto retry;
135061f28255Scgd 	}
135161f28255Scgd 	(void)setpgid(0, shpgrp);
135261f28255Scgd 	(void)tcsetpgrp(FSHTTY, shpgrp);
135361f28255Scgd     }
135461f28255Scgd }
135561f28255Scgd 
135661f28255Scgd /* This is the dreaded EVAL built-in.
135761f28255Scgd  *   If you don't fiddle with file descriptors, and reset didfds,
135861f28255Scgd  *   this command will either ignore redirection inside or outside
13598ce1f4ffSmsaitoh  *   its arguments, e.g. eval "date >x"  vs.  eval "date" >x
136061f28255Scgd  *   The stuff here seems to work, but I did it by trial and error rather
136161f28255Scgd  *   than really knowing what was going on.  If tpgrp is zero, we are
136261f28255Scgd  *   probably a background eval, e.g. "eval date &", and we want to
136361f28255Scgd  *   make sure that any processes we start stay in our pgrp.
136461f28255Scgd  *   This is also the case for "time eval date" -- stay in same pgrp.
136561f28255Scgd  *   Otherwise, under stty tostop, processes will stop in the wrong
136661f28255Scgd  *   pgrp, with no way for the shell to get them going again.  -IAN!
136761f28255Scgd  */
1368cee2bad8Smycroft static Char **gv = NULL;
1369b771e65bSwiz 
137061f28255Scgd void
1371cee2bad8Smycroft /*ARGSUSED*/
doeval(Char ** v,struct command * t)1372b771e65bSwiz doeval(Char **v, struct command *t)
137361f28255Scgd {
137461f28255Scgd     jmp_buf osetexit;
1375b771e65bSwiz     Char *oevalp, **oevalvec, **savegv;
1376b771e65bSwiz     int my_reenter, odidfds, oSHERR, oSHIN, oSHOUT, saveERR, saveIN, saveOUT;
1377cee2bad8Smycroft 
1378b771e65bSwiz     savegv = gv;
1379cee2bad8Smycroft     UNREGISTER(v);
138061f28255Scgd 
138161f28255Scgd     oevalvec = evalvec;
138261f28255Scgd     oevalp = evalp;
138361f28255Scgd     odidfds = didfds;
138461f28255Scgd     oSHIN = SHIN;
138561f28255Scgd     oSHOUT = SHOUT;
1386cee2bad8Smycroft     oSHERR = SHERR;
138761f28255Scgd 
138861f28255Scgd     v++;
138961f28255Scgd     if (*v == 0)
139061f28255Scgd 	return;
139161f28255Scgd     gflag = 0, tglob(v);
139261f28255Scgd     if (gflag) {
139361f28255Scgd 	gv = v = globall(v);
139461f28255Scgd 	gargv = 0;
1395ee9e50eaSmycroft 	if (v == 0)
139661f28255Scgd 	    stderror(ERR_NOMATCH);
139761f28255Scgd 	v = copyblk(v);
139861f28255Scgd     }
139961f28255Scgd     else {
140061f28255Scgd 	gv = NULL;
140161f28255Scgd 	v = copyblk(v);
140261f28255Scgd 	trim(v);
140361f28255Scgd     }
140461f28255Scgd 
140561f28255Scgd     saveIN = dcopy(SHIN, -1);
140661f28255Scgd     saveOUT = dcopy(SHOUT, -1);
1407cee2bad8Smycroft     saveERR = dcopy(SHERR, -1);
140861f28255Scgd 
140961f28255Scgd     getexit(osetexit);
141061f28255Scgd 
141161f28255Scgd     if ((my_reenter = setexit()) == 0) {
141261f28255Scgd 	evalvec = v;
141361f28255Scgd 	evalp = 0;
141461f28255Scgd 	SHIN = dcopy(0, -1);
141561f28255Scgd 	SHOUT = dcopy(1, -1);
1416cee2bad8Smycroft 	SHERR = dcopy(2, -1);
141761f28255Scgd 	didfds = 0;
141861f28255Scgd 	process(0);
141961f28255Scgd     }
142061f28255Scgd 
142161f28255Scgd     evalvec = oevalvec;
142261f28255Scgd     evalp = oevalp;
142361f28255Scgd     doneinp = 0;
142461f28255Scgd     didfds = odidfds;
14254d7c6251Schristos     if (SHIN != -1)
142661f28255Scgd 	(void)close(SHIN);
14274d7c6251Schristos     if (SHOUT != -1)
142861f28255Scgd 	(void)close(SHOUT);
14294d7c6251Schristos     if (SHERR != -1)
1430cee2bad8Smycroft 	(void)close(SHERR);
143161f28255Scgd     SHIN = dmove(saveIN, oSHIN);
143261f28255Scgd     SHOUT = dmove(saveOUT, oSHOUT);
1433cee2bad8Smycroft     SHERR = dmove(saveERR, oSHERR);
143461f28255Scgd     if (gv)
1435cee2bad8Smycroft 	blkfree(gv), gv = NULL;
143661f28255Scgd     resexit(osetexit);
1437cee2bad8Smycroft     gv = savegv;
1438ee9e50eaSmycroft     if (my_reenter)
143961f28255Scgd 	stderror(ERR_SILENT);
144061f28255Scgd }
1441cee2bad8Smycroft 
1442cee2bad8Smycroft void
1443cee2bad8Smycroft /*ARGSUSED*/
doprintf(Char ** v,struct command * t)1444b771e65bSwiz doprintf(Char **v, struct command *t)
1445cee2bad8Smycroft {
1446cee2bad8Smycroft     char **c;
1447cee2bad8Smycroft     int ret;
1448cee2bad8Smycroft 
1449cee2bad8Smycroft     ret = progprintf(blklen(v), c = short2blk(v));
1450cee2bad8Smycroft     (void)fflush(cshout);
1451cee2bad8Smycroft     (void)fflush(csherr);
1452cee2bad8Smycroft 
1453cee2bad8Smycroft     blkfree((Char **)c);
1454ee9e50eaSmycroft     if (ret)
1455cee2bad8Smycroft 	stderror(ERR_SILENT);
1456cee2bad8Smycroft }
1457