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