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