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