1d6fabe6eSbostic /*-
2548b48c4Sbostic * Copyright (c) 1980, 1991, 1993
3548b48c4Sbostic * The Regents of the University of California. All rights reserved.
4d6fabe6eSbostic *
5d6fabe6eSbostic * %sccs.include.redist.c%
6dcd540e4Sdist */
7dcd540e4Sdist
85c5636eeSedward #ifndef lint
9*5fad6ed4Schristos static char sccsid[] = "@(#)func.c 8.2 (Berkeley) 03/22/95";
10ccdc25dfSbostic #endif /* not lint */
117079687aSbill
129374f148Sbostic #include <sys/types.h>
139374f148Sbostic #include <sys/stat.h>
149374f148Sbostic #include <signal.h>
159374f148Sbostic #include <locale.h>
169374f148Sbostic #include <stdlib.h>
179374f148Sbostic #include <string.h>
189374f148Sbostic #include <unistd.h>
19c1ce954aSchristos #if __STDC__
20c1ce954aSchristos # include <stdarg.h>
21c1ce954aSchristos #else
22c1ce954aSchristos # include <varargs.h>
23c1ce954aSchristos #endif
24c1ce954aSchristos
25afc71901Sbostic #include "csh.h"
26afc71901Sbostic #include "extern.h"
279374f148Sbostic #include "pathnames.h"
287079687aSbill
29f3328da7Sbostic extern char **environ;
30f3328da7Sbostic
31f3328da7Sbostic static int zlast = -1;
3223ceb1ffSchristos static void islogin __P((void));
3323ceb1ffSchristos static void reexecute __P((struct command *));
3423ceb1ffSchristos static void preread __P((void));
3523ceb1ffSchristos static void doagain __P((void));
36c5aa27adSchristos static void search __P((int, int, Char *));
3723ceb1ffSchristos static int getword __P((Char *));
3823ceb1ffSchristos static int keyword __P((Char *));
3923ceb1ffSchristos static void toend __P((void));
4023ceb1ffSchristos static void xecho __P((int, Char **));
41c5aa27adSchristos static void Unsetenv __P((Char *));
427079687aSbill
437079687aSbill struct biltins *
isbfunc(t)447079687aSbill isbfunc(t)
455c5636eeSedward struct command *t;
467079687aSbill {
47f3328da7Sbostic register Char *cp = t->t_dcom[0];
485c5636eeSedward register struct biltins *bp, *bp1, *bp2;
49f3328da7Sbostic static struct biltins label = {"", dozip, 0, 0};
507079687aSbill static struct biltins foregnd = {"%job", dofg1, 0, 0};
517079687aSbill static struct biltins backgnd = {"%job &", dobg1, 0, 0};
527079687aSbill
537079687aSbill if (lastchr(cp) == ':') {
54f3328da7Sbostic label.bname = short2str(cp);
557079687aSbill return (&label);
567079687aSbill }
577079687aSbill if (*cp == '%') {
585eb3278cSbostic if (t->t_dflg & F_AMPERSAND) {
595eb3278cSbostic t->t_dflg &= ~F_AMPERSAND;
60f3328da7Sbostic backgnd.bname = short2str(cp);
617079687aSbill return (&backgnd);
627079687aSbill }
63f3328da7Sbostic foregnd.bname = short2str(cp);
647079687aSbill return (&foregnd);
657079687aSbill }
665c5636eeSedward /*
67f3328da7Sbostic * Binary search Bp1 is the beginning of the current search range. Bp2 is
68f3328da7Sbostic * one past the end.
695c5636eeSedward */
705c5636eeSedward for (bp1 = bfunc, bp2 = bfunc + nbfunc; bp1 < bp2;) {
715c5636eeSedward register i;
725c5636eeSedward
73f3328da7Sbostic bp = bp1 + ((bp2 - bp1) >> 1);
745c5636eeSedward if ((i = *cp - *bp->bname) == 0 &&
75f3328da7Sbostic (i = Strcmp(cp, str2short(bp->bname))) == 0)
765c5636eeSedward return bp;
775c5636eeSedward if (i < 0)
785c5636eeSedward bp2 = bp;
795c5636eeSedward else
805c5636eeSedward bp1 = bp + 1;
817079687aSbill }
827079687aSbill return (0);
837079687aSbill }
847079687aSbill
85f3328da7Sbostic void
func(t,bp)867079687aSbill func(t, bp)
877079687aSbill register struct command *t;
887079687aSbill register struct biltins *bp;
897079687aSbill {
907079687aSbill int i;
917079687aSbill
927079687aSbill xechoit(t->t_dcom);
937079687aSbill setname(bp->bname);
947079687aSbill i = blklen(t->t_dcom) - 1;
957079687aSbill if (i < bp->minargs)
96f3328da7Sbostic stderror(ERR_NAME | ERR_TOOFEW);
977079687aSbill if (i > bp->maxargs)
98f3328da7Sbostic stderror(ERR_NAME | ERR_TOOMANY);
997079687aSbill (*bp->bfunct) (t->t_dcom, t);
1007079687aSbill }
1017079687aSbill
102f3328da7Sbostic void
103cce51c35Schristos /*ARGSUSED*/
doonintr(v,t)104cce51c35Schristos doonintr(v, t)
105f3328da7Sbostic Char **v;
106cce51c35Schristos struct command *t;
1077079687aSbill {
108f3328da7Sbostic register Char *cp;
109f3328da7Sbostic register Char *vv = v[1];
110*5fad6ed4Schristos sigset_t sigset;
1117079687aSbill
1127079687aSbill if (parintr == SIG_IGN)
1137079687aSbill return;
1147079687aSbill if (setintr && intty)
115f3328da7Sbostic stderror(ERR_NAME | ERR_TERMINAL);
116f3328da7Sbostic cp = gointr;
117f3328da7Sbostic gointr = 0;
118f3328da7Sbostic xfree((ptr_t) cp);
1197079687aSbill if (vv == 0) {
120*5fad6ed4Schristos if (setintr) {
121*5fad6ed4Schristos sigemptyset(&sigset);
122*5fad6ed4Schristos sigaddset(&sigset, SIGINT);
123*5fad6ed4Schristos sigprocmask(SIG_BLOCK, &sigset, NULL);
124*5fad6ed4Schristos } else
1255c5636eeSedward (void) signal(SIGINT, SIG_DFL);
1267079687aSbill gointr = 0;
127f3328da7Sbostic }
128f3328da7Sbostic else if (eq((vv = strip(vv)), STRminus)) {
1295c5636eeSedward (void) signal(SIGINT, SIG_IGN);
130f3328da7Sbostic gointr = Strsave(STRminus);
131f3328da7Sbostic }
132f3328da7Sbostic else {
133f3328da7Sbostic gointr = Strsave(vv);
1345c5636eeSedward (void) signal(SIGINT, pintr);
1357079687aSbill }
1367079687aSbill }
1377079687aSbill
138f3328da7Sbostic void
139cce51c35Schristos /*ARGSUSED*/
donohup(v,t)140cce51c35Schristos donohup(v, t)
141cce51c35Schristos Char **v;
142cce51c35Schristos struct command *t;
1437079687aSbill {
1447079687aSbill if (intty)
145f3328da7Sbostic stderror(ERR_NAME | ERR_TERMINAL);
1467079687aSbill if (setintr == 0) {
1475c5636eeSedward (void) signal(SIGHUP, SIG_IGN);
1487079687aSbill }
1497079687aSbill }
1507079687aSbill
151f3328da7Sbostic void
152cce51c35Schristos /*ARGSUSED*/
dozip(v,t)153cce51c35Schristos dozip(v, t)
154cce51c35Schristos Char **v;
155cce51c35Schristos struct command *t;
1567079687aSbill {
1577079687aSbill ;
1587079687aSbill }
1597079687aSbill
160f3328da7Sbostic void
prvars()1617079687aSbill prvars()
1627079687aSbill {
1637079687aSbill plist(&shvhed);
1647079687aSbill }
1657079687aSbill
166f3328da7Sbostic void
167cce51c35Schristos /*ARGSUSED*/
doalias(v,t)168cce51c35Schristos doalias(v, t)
169cce51c35Schristos Char **v;
170cce51c35Schristos struct command *t;
1717079687aSbill {
1727079687aSbill register struct varent *vp;
173f3328da7Sbostic register Char *p;
1747079687aSbill
1757079687aSbill v++;
1767079687aSbill p = *v++;
1777079687aSbill if (p == 0)
1787079687aSbill plist(&aliases);
1797079687aSbill else if (*v == 0) {
1807079687aSbill vp = adrof1(strip(p), &aliases);
181cce51c35Schristos if (vp) {
182cce51c35Schristos blkpr(cshout, vp->vec);
183cce51c35Schristos fputc('\n', cshout);
184cce51c35Schristos }
185f3328da7Sbostic }
186f3328da7Sbostic else {
187f3328da7Sbostic if (eq(p, STRalias) || eq(p, STRunalias)) {
1888d2f70fbSchristos setname(vis_str(p));
189f3328da7Sbostic stderror(ERR_NAME | ERR_DANGER);
1907079687aSbill }
1917079687aSbill set1(strip(p), saveblk(v), &aliases);
1927079687aSbill }
1937079687aSbill }
1947079687aSbill
195f3328da7Sbostic void
196cce51c35Schristos /*ARGSUSED*/
unalias(v,t)197cce51c35Schristos unalias(v, t)
198f3328da7Sbostic Char **v;
199cce51c35Schristos struct command *t;
2007079687aSbill {
2017079687aSbill unset1(v, &aliases);
2027079687aSbill }
2037079687aSbill
204f3328da7Sbostic void
205cce51c35Schristos /*ARGSUSED*/
dologout(v,t)206cce51c35Schristos dologout(v, t)
207cce51c35Schristos Char **v;
208cce51c35Schristos struct command *t;
2097079687aSbill {
2107079687aSbill islogin();
2117079687aSbill goodbye();
2127079687aSbill }
2137079687aSbill
214f3328da7Sbostic void
215cce51c35Schristos /*ARGSUSED*/
dologin(v,t)216cce51c35Schristos dologin(v, t)
217f3328da7Sbostic Char **v;
218cce51c35Schristos struct command *t;
2197079687aSbill {
2207079687aSbill islogin();
22151729a55Smckusic rechist();
2225c5636eeSedward (void) signal(SIGTERM, parterm);
22323ceb1ffSchristos (void) execl(_PATH_LOGIN, "login", short2str(v[1]), NULL);
2247079687aSbill untty();
225f3328da7Sbostic xexit(1);
2267079687aSbill }
2277079687aSbill
228f3328da7Sbostic static void
islogin()2297079687aSbill islogin()
2307079687aSbill {
2317079687aSbill if (chkstop == 0 && setintr)
2327079687aSbill panystop(0);
2337079687aSbill if (loginsh)
2347079687aSbill return;
235f3328da7Sbostic stderror(ERR_NOTLOGIN);
2367079687aSbill }
2377079687aSbill
238f3328da7Sbostic void
doif(v,kp)2397079687aSbill doif(v, kp)
240f3328da7Sbostic Char **v;
2417079687aSbill struct command *kp;
2427079687aSbill {
2437079687aSbill register int i;
244f3328da7Sbostic register Char **vv;
2457079687aSbill
2467079687aSbill v++;
24767a52095Schristos i = expr(&v);
2487079687aSbill vv = v;
249f3328da7Sbostic if (*vv == NULL)
250f3328da7Sbostic stderror(ERR_NAME | ERR_EMPTYIF);
251f3328da7Sbostic if (eq(*vv, STRthen)) {
2527079687aSbill if (*++vv)
253f3328da7Sbostic stderror(ERR_NAME | ERR_IMPRTHEN);
2548d2f70fbSchristos setname(vis_str(STRthen));
2557079687aSbill /*
256f3328da7Sbostic * If expression was zero, then scan to else, otherwise just fall into
257f3328da7Sbostic * following code.
2587079687aSbill */
2597079687aSbill if (!i)
26023ceb1ffSchristos search(T_IF, 0, NULL);
2617079687aSbill return;
2627079687aSbill }
2637079687aSbill /*
264f3328da7Sbostic * Simple command attached to this if. Left shift the node in this tree,
265f3328da7Sbostic * munging it so we can reexecute it.
2667079687aSbill */
2677079687aSbill if (i) {
2687079687aSbill lshift(kp->t_dcom, vv - kp->t_dcom);
2697079687aSbill reexecute(kp);
2707079687aSbill donefds();
2717079687aSbill }
2727079687aSbill }
2737079687aSbill
2747079687aSbill /*
2757079687aSbill * Reexecute a command, being careful not
2767079687aSbill * to redo i/o redirection, which is already set up.
2777079687aSbill */
278f3328da7Sbostic static void
reexecute(kp)2797079687aSbill reexecute(kp)
2807079687aSbill register struct command *kp;
2817079687aSbill {
2825eb3278cSbostic kp->t_dflg &= F_SAVE;
2835eb3278cSbostic kp->t_dflg |= F_REPEAT;
2847079687aSbill /*
285f3328da7Sbostic * If tty is still ours to arbitrate, arbitrate it; otherwise dont even set
286f3328da7Sbostic * pgrp's as the jobs would then have no way to get the tty (we can't give
287f3328da7Sbostic * it to them, and our parent wouldn't know their pgrp, etc.
2887079687aSbill */
289afc71901Sbostic execute(kp, (tpgrp > 0 ? tpgrp : -1), NULL, NULL);
2907079687aSbill }
2917079687aSbill
292f3328da7Sbostic void
293cce51c35Schristos /*ARGSUSED*/
doelse(v,t)294cce51c35Schristos doelse(v, t)
295cce51c35Schristos Char **v;
296cce51c35Schristos struct command *t;
2977079687aSbill {
29823ceb1ffSchristos search(T_ELSE, 0, NULL);
2997079687aSbill }
3007079687aSbill
301f3328da7Sbostic void
302cce51c35Schristos /*ARGSUSED*/
dogoto(v,t)303cce51c35Schristos dogoto(v, t)
304f3328da7Sbostic Char **v;
305cce51c35Schristos struct command *t;
3067079687aSbill {
307f3328da7Sbostic Char *lp;
3087079687aSbill
309c5aa27adSchristos gotolab(lp = globone(v[1], G_ERROR));
310c5aa27adSchristos xfree((ptr_t) lp);
311c5aa27adSchristos }
312c5aa27adSchristos
313c5aa27adSchristos void
gotolab(lab)314c5aa27adSchristos gotolab(lab)
315c5aa27adSchristos Char *lab;
316c5aa27adSchristos {
317c5aa27adSchristos register struct whyle *wp;
3187079687aSbill /*
319f3328da7Sbostic * While we still can, locate any unknown ends of existing loops. This
320f3328da7Sbostic * obscure code is the WORST result of the fact that we don't really parse.
3217079687aSbill */
322f3328da7Sbostic zlast = T_GOTO;
3237079687aSbill for (wp = whyles; wp; wp = wp->w_next)
324af359014Schristos if (wp->w_end.type == F_SEEK && wp->w_end.f_seek == 0) {
32523ceb1ffSchristos search(T_BREAK, 0, NULL);
326063c38e3Schristos btell(&wp->w_end);
327f3328da7Sbostic }
328f3328da7Sbostic else
329063c38e3Schristos bseek(&wp->w_end);
330c5aa27adSchristos search(T_GOTO, 0, lab);
3317079687aSbill /*
3327079687aSbill * Eliminate loops which were exited.
3337079687aSbill */
3347079687aSbill wfree();
3357079687aSbill }
3367079687aSbill
337f3328da7Sbostic void
338cce51c35Schristos /*ARGSUSED*/
doswitch(v,t)339cce51c35Schristos doswitch(v, t)
340cce51c35Schristos Char **v;
341cce51c35Schristos struct command *t;
3427079687aSbill {
343f3328da7Sbostic register Char *cp, *lp;
3447079687aSbill
3457079687aSbill v++;
3467079687aSbill if (!*v || *(*v++) != '(')
347f3328da7Sbostic stderror(ERR_SYNTAX);
348f3328da7Sbostic cp = **v == ')' ? STRNULL : *v++;
3497079687aSbill if (*(*v++) != ')')
3507079687aSbill v--;
3517079687aSbill if (*v)
352f3328da7Sbostic stderror(ERR_SYNTAX);
353f3328da7Sbostic search(T_SWITCH, 0, lp = globone(cp, G_ERROR));
354f3328da7Sbostic xfree((ptr_t) lp);
3557079687aSbill }
3567079687aSbill
357f3328da7Sbostic void
358cce51c35Schristos /*ARGSUSED*/
dobreak(v,t)359cce51c35Schristos dobreak(v, t)
360cce51c35Schristos Char **v;
361cce51c35Schristos struct command *t;
3627079687aSbill {
3637079687aSbill if (whyles)
3647079687aSbill toend();
3657079687aSbill else
366f3328da7Sbostic stderror(ERR_NAME | ERR_NOTWHILE);
3677079687aSbill }
3687079687aSbill
369f3328da7Sbostic void
370cce51c35Schristos /*ARGSUSED*/
doexit(v,t)371cce51c35Schristos doexit(v, t)
372f3328da7Sbostic Char **v;
373cce51c35Schristos struct command *t;
3747079687aSbill {
375f3328da7Sbostic if (chkstop == 0 && (intty || intact) && evalvec == 0)
3767079687aSbill panystop(0);
3777079687aSbill /*
3787079687aSbill * Don't DEMAND parentheses here either.
3797079687aSbill */
3807079687aSbill v++;
3817079687aSbill if (*v) {
38267a52095Schristos set(STRstatus, putn(expr(&v)));
3837079687aSbill if (*v)
384f3328da7Sbostic stderror(ERR_NAME | ERR_EXPRESSION);
3857079687aSbill }
3867079687aSbill btoeof();
3877079687aSbill if (intty)
3885c5636eeSedward (void) close(SHIN);
3897079687aSbill }
3907079687aSbill
391f3328da7Sbostic void
392cce51c35Schristos /*ARGSUSED*/
doforeach(v,t)393cce51c35Schristos doforeach(v, t)
394cce51c35Schristos Char **v;
395cce51c35Schristos struct command *t;
3967079687aSbill {
397f3328da7Sbostic register Char *cp, *sp;
3987079687aSbill register struct whyle *nwp;
3997079687aSbill
4007079687aSbill v++;
401f3328da7Sbostic sp = cp = strip(*v);
402f3328da7Sbostic if (!letter(*sp))
403f3328da7Sbostic stderror(ERR_NAME | ERR_VARBEGIN);
404f3328da7Sbostic while (*cp && alnum(*cp))
4057079687aSbill cp++;
406f3328da7Sbostic if (*cp)
407f3328da7Sbostic stderror(ERR_NAME | ERR_VARALNUM);
408f3328da7Sbostic if ((cp - sp) > MAXVARLEN)
409f3328da7Sbostic stderror(ERR_NAME | ERR_VARTOOLONG);
4107079687aSbill cp = *v++;
4117079687aSbill if (v[0][0] != '(' || v[blklen(v) - 1][0] != ')')
412f3328da7Sbostic stderror(ERR_NAME | ERR_NOPAREN);
4137079687aSbill v++;
4145c5636eeSedward gflag = 0, tglob(v);
415f21ede9aSbostic v = globall(v);
4167079687aSbill if (v == 0)
417f3328da7Sbostic stderror(ERR_NAME | ERR_NOMATCH);
418f3328da7Sbostic nwp = (struct whyle *) xcalloc(1, sizeof *nwp);
419f3328da7Sbostic nwp->w_fe = nwp->w_fe0 = v;
420f3328da7Sbostic gargv = 0;
421063c38e3Schristos btell(&nwp->w_start);
422f3328da7Sbostic nwp->w_fename = Strsave(cp);
4237079687aSbill nwp->w_next = whyles;
424af359014Schristos nwp->w_end.type = F_SEEK;
4257079687aSbill whyles = nwp;
4267079687aSbill /*
427f3328da7Sbostic * Pre-read the loop so as to be more comprehensible to a terminal user.
4287079687aSbill */
429f3328da7Sbostic zlast = T_FOREACH;
4307079687aSbill if (intty)
4317079687aSbill preread();
4327079687aSbill doagain();
4337079687aSbill }
4347079687aSbill
435f3328da7Sbostic void
436cce51c35Schristos /*ARGSUSED*/
dowhile(v,t)437cce51c35Schristos dowhile(v, t)
438f3328da7Sbostic Char **v;
439cce51c35Schristos struct command *t;
4407079687aSbill {
4417079687aSbill register int status;
442063c38e3Schristos register bool again = whyles != 0 && SEEKEQ(&whyles->w_start, &lineloc) &&
4437079687aSbill whyles->w_fename == 0;
4447079687aSbill
4457079687aSbill v++;
4467079687aSbill /*
447f3328da7Sbostic * Implement prereading here also, taking care not to evaluate the
448f3328da7Sbostic * expression before the loop has been read up from a terminal.
4497079687aSbill */
4507079687aSbill if (intty && !again)
4517079687aSbill status = !exp0(&v, 1);
4527079687aSbill else
45367a52095Schristos status = !expr(&v);
4547079687aSbill if (*v)
455f3328da7Sbostic stderror(ERR_NAME | ERR_EXPRESSION);
4567079687aSbill if (!again) {
457f3328da7Sbostic register struct whyle *nwp =
458f3328da7Sbostic (struct whyle *) xcalloc(1, sizeof(*nwp));
4597079687aSbill
4607079687aSbill nwp->w_start = lineloc;
461af359014Schristos nwp->w_end.type = F_SEEK;
462af359014Schristos nwp->w_end.f_seek = 0;
4637079687aSbill nwp->w_next = whyles;
4647079687aSbill whyles = nwp;
465f3328da7Sbostic zlast = T_WHILE;
4667079687aSbill if (intty) {
4677079687aSbill /*
4687079687aSbill * The tty preread
4697079687aSbill */
4707079687aSbill preread();
4717079687aSbill doagain();
4727079687aSbill return;
4737079687aSbill }
4747079687aSbill }
4757079687aSbill if (status)
4767079687aSbill /* We ain't gonna loop no more, no more! */
4777079687aSbill toend();
4787079687aSbill }
4797079687aSbill
480f3328da7Sbostic static void
preread()4817079687aSbill preread()
4827079687aSbill {
483*5fad6ed4Schristos sigset_t sigset;
484*5fad6ed4Schristos
485063c38e3Schristos whyles->w_end.type = I_SEEK;
486*5fad6ed4Schristos if (setintr) {
487*5fad6ed4Schristos sigemptyset(&sigset);
488*5fad6ed4Schristos sigaddset(&sigset, SIGINT);
489*5fad6ed4Schristos sigprocmask(SIG_UNBLOCK, &sigset, NULL);
490*5fad6ed4Schristos }
491f3328da7Sbostic
49223ceb1ffSchristos search(T_BREAK, 0, NULL); /* read the expression in */
4937079687aSbill if (setintr)
494*5fad6ed4Schristos sigprocmask(SIG_BLOCK, &sigset, NULL);
495063c38e3Schristos btell(&whyles->w_end);
4967079687aSbill }
4977079687aSbill
498f3328da7Sbostic void
499cce51c35Schristos /*ARGSUSED*/
doend(v,t)500cce51c35Schristos doend(v, t)
501cce51c35Schristos Char **v;
502cce51c35Schristos struct command *t;
5037079687aSbill {
5047079687aSbill if (!whyles)
505f3328da7Sbostic stderror(ERR_NAME | ERR_NOTWHILE);
506063c38e3Schristos btell(&whyles->w_end);
5077079687aSbill doagain();
5087079687aSbill }
5097079687aSbill
510f3328da7Sbostic void
511cce51c35Schristos /*ARGSUSED*/
docontin(v,t)512cce51c35Schristos docontin(v, t)
513cce51c35Schristos Char **v;
514cce51c35Schristos struct command *t;
5157079687aSbill {
5167079687aSbill if (!whyles)
517f3328da7Sbostic stderror(ERR_NAME | ERR_NOTWHILE);
5187079687aSbill doagain();
5197079687aSbill }
5207079687aSbill
521f3328da7Sbostic static void
doagain()5227079687aSbill doagain()
5237079687aSbill {
5247079687aSbill /* Repeating a while is simple */
5257079687aSbill if (whyles->w_fename == 0) {
526063c38e3Schristos bseek(&whyles->w_start);
5277079687aSbill return;
5287079687aSbill }
5297079687aSbill /*
530f3328da7Sbostic * The foreach variable list actually has a spurious word ")" at the end of
531f3328da7Sbostic * the w_fe list. Thus we are at the of the list if one word beyond this
532f3328da7Sbostic * is 0.
5337079687aSbill */
5347079687aSbill if (!whyles->w_fe[1]) {
535cce51c35Schristos dobreak(NULL, NULL);
5367079687aSbill return;
5377079687aSbill }
538f3328da7Sbostic set(whyles->w_fename, Strsave(*whyles->w_fe++));
539063c38e3Schristos bseek(&whyles->w_start);
5407079687aSbill }
5417079687aSbill
542f3328da7Sbostic void
dorepeat(v,kp)5437079687aSbill dorepeat(v, kp)
544f3328da7Sbostic Char **v;
5457079687aSbill struct command *kp;
5467079687aSbill {
5473bb023eaSbostic register int i;
548*5fad6ed4Schristos sigset_t sigset;
5497079687aSbill
5507079687aSbill i = getn(v[1]);
551*5fad6ed4Schristos if (setintr) {
552*5fad6ed4Schristos sigemptyset(&sigset);
553*5fad6ed4Schristos sigaddset(&sigset, SIGINT);
554*5fad6ed4Schristos sigprocmask(SIG_BLOCK, &sigset, NULL);
555*5fad6ed4Schristos }
5567079687aSbill lshift(v, 2);
5577079687aSbill while (i > 0) {
5587079687aSbill if (setintr)
559*5fad6ed4Schristos sigprocmask(SIG_UNBLOCK, &sigset, NULL);
5607079687aSbill reexecute(kp);
5617079687aSbill --i;
5627079687aSbill }
5637079687aSbill donefds();
5647079687aSbill if (setintr)
565*5fad6ed4Schristos sigprocmask(SIG_UNBLOCK, &sigset, NULL);
5667079687aSbill }
5677079687aSbill
568f3328da7Sbostic void
569cce51c35Schristos /*ARGSUSED*/
doswbrk(v,t)570cce51c35Schristos doswbrk(v, t)
571cce51c35Schristos Char **v;
572cce51c35Schristos struct command *t;
5737079687aSbill {
57423ceb1ffSchristos search(T_BRKSW, 0, NULL);
5757079687aSbill }
5767079687aSbill
577f3328da7Sbostic int
srchx(cp)5787079687aSbill srchx(cp)
579f3328da7Sbostic register Char *cp;
5807079687aSbill {
5815c5636eeSedward register struct srch *sp, *sp1, *sp2;
5825c5636eeSedward register i;
5837079687aSbill
5845c5636eeSedward /*
585f3328da7Sbostic * Binary search Sp1 is the beginning of the current search range. Sp2 is
586f3328da7Sbostic * one past the end.
5875c5636eeSedward */
5885c5636eeSedward for (sp1 = srchn, sp2 = srchn + nsrchn; sp1 < sp2;) {
589f3328da7Sbostic sp = sp1 + ((sp2 - sp1) >> 1);
5905c5636eeSedward if ((i = *cp - *sp->s_name) == 0 &&
591f3328da7Sbostic (i = Strcmp(cp, str2short(sp->s_name))) == 0)
5925c5636eeSedward return sp->s_value;
5935c5636eeSedward if (i < 0)
5945c5636eeSedward sp2 = sp;
5955c5636eeSedward else
5965c5636eeSedward sp1 = sp + 1;
5975c5636eeSedward }
5987079687aSbill return (-1);
5997079687aSbill }
6007079687aSbill
601f3328da7Sbostic static Char Stype;
602f3328da7Sbostic static Char *Sgoal;
6037079687aSbill
6047079687aSbill /*VARARGS2*/
605085e994eSbostic static void
search(type,level,goal)6067079687aSbill search(type, level, goal)
6077079687aSbill int type;
6087079687aSbill register int level;
609f3328da7Sbostic Char *goal;
6107079687aSbill {
611f3328da7Sbostic Char wordbuf[BUFSIZ];
612f3328da7Sbostic register Char *aword = wordbuf;
613f3328da7Sbostic register Char *cp;
6147079687aSbill
615f3328da7Sbostic Stype = type;
616f3328da7Sbostic Sgoal = goal;
617063c38e3Schristos if (type == T_GOTO) {
618063c38e3Schristos struct Ain a;
619063c38e3Schristos a.type = F_SEEK;
620063c38e3Schristos a.f_seek = 0;
621063c38e3Schristos bseek(&a);
622063c38e3Schristos }
6237079687aSbill do {
624063c38e3Schristos if (intty && fseekp == feobp && aret == F_SEEK)
625cce51c35Schristos (void) fprintf(cshout, "? "), (void) fflush(cshout);
6265c5636eeSedward aword[0] = 0;
6275c5636eeSedward (void) getword(aword);
6287079687aSbill switch (srchx(aword)) {
6297079687aSbill
6305eb3278cSbostic case T_ELSE:
6315eb3278cSbostic if (level == 0 && type == T_IF)
6327079687aSbill return;
6337079687aSbill break;
6347079687aSbill
6355eb3278cSbostic case T_IF:
6367079687aSbill while (getword(aword))
6377079687aSbill continue;
6385eb3278cSbostic if ((type == T_IF || type == T_ELSE) &&
639f3328da7Sbostic eq(aword, STRthen))
6407079687aSbill level++;
6417079687aSbill break;
6427079687aSbill
6435eb3278cSbostic case T_ENDIF:
6445eb3278cSbostic if (type == T_IF || type == T_ELSE)
6457079687aSbill level--;
6467079687aSbill break;
6477079687aSbill
6485eb3278cSbostic case T_FOREACH:
6495eb3278cSbostic case T_WHILE:
6505eb3278cSbostic if (type == T_BREAK)
6517079687aSbill level++;
6527079687aSbill break;
6537079687aSbill
6545eb3278cSbostic case T_END:
6555eb3278cSbostic if (type == T_BREAK)
6567079687aSbill level--;
6577079687aSbill break;
6587079687aSbill
6595eb3278cSbostic case T_SWITCH:
6605eb3278cSbostic if (type == T_SWITCH || type == T_BRKSW)
6617079687aSbill level++;
6627079687aSbill break;
6637079687aSbill
6645eb3278cSbostic case T_ENDSW:
6655eb3278cSbostic if (type == T_SWITCH || type == T_BRKSW)
6667079687aSbill level--;
6677079687aSbill break;
6687079687aSbill
6695eb3278cSbostic case T_LABEL:
6705eb3278cSbostic if (type == T_GOTO && getword(aword) && eq(aword, goal))
6717079687aSbill level = -1;
6727079687aSbill break;
6737079687aSbill
6747079687aSbill default:
6755eb3278cSbostic if (type != T_GOTO && (type != T_SWITCH || level != 0))
6767079687aSbill break;
6777079687aSbill if (lastchr(aword) != ':')
6787079687aSbill break;
679f3328da7Sbostic aword[Strlen(aword) - 1] = 0;
68050cee248Schristos if ((type == T_GOTO && eq(aword, goal)) ||
68150cee248Schristos (type == T_SWITCH && eq(aword, STRdefault)))
6827079687aSbill level = -1;
6837079687aSbill break;
6847079687aSbill
6855eb3278cSbostic case T_CASE:
6865eb3278cSbostic if (type != T_SWITCH || level != 0)
6877079687aSbill break;
6885c5636eeSedward (void) getword(aword);
6897079687aSbill if (lastchr(aword) == ':')
690f3328da7Sbostic aword[Strlen(aword) - 1] = 0;
6917079687aSbill cp = strip(Dfix1(aword));
6927079687aSbill if (Gmatch(goal, cp))
6937079687aSbill level = -1;
694f3328da7Sbostic xfree((ptr_t) cp);
6957079687aSbill break;
6967079687aSbill
6975eb3278cSbostic case T_DEFAULT:
6985eb3278cSbostic if (type == T_SWITCH && level == 0)
6997079687aSbill level = -1;
7007079687aSbill break;
7017079687aSbill }
702f3328da7Sbostic (void) getword(NULL);
7037079687aSbill } while (level >= 0);
7047079687aSbill }
7057079687aSbill
706f3328da7Sbostic static int
getword(wp)7077079687aSbill getword(wp)
708f3328da7Sbostic register Char *wp;
7097079687aSbill {
7107079687aSbill register int found = 0;
7117079687aSbill register int c, d;
712f3328da7Sbostic int kwd = 0;
713f3328da7Sbostic Char *owp = wp;
7147079687aSbill
7157079687aSbill c = readc(1);
7167079687aSbill d = 0;
7177079687aSbill do {
7187079687aSbill while (c == ' ' || c == '\t')
7197079687aSbill c = readc(1);
7203f5f1f90Sroot if (c == '#')
7213f5f1f90Sroot do
7223f5f1f90Sroot c = readc(1);
7233f5f1f90Sroot while (c >= 0 && c != '\n');
7247079687aSbill if (c < 0)
7257079687aSbill goto past;
7267079687aSbill if (c == '\n') {
7277079687aSbill if (wp)
7287079687aSbill break;
7297079687aSbill return (0);
7307079687aSbill }
7317079687aSbill unreadc(c);
7327079687aSbill found = 1;
7337079687aSbill do {
7347079687aSbill c = readc(1);
7357079687aSbill if (c == '\\' && (c = readc(1)) == '\n')
7367079687aSbill c = ' ';
7375c5636eeSedward if (c == '\'' || c == '"')
7387079687aSbill if (d == 0)
7397079687aSbill d = c;
7407079687aSbill else if (d == c)
7417079687aSbill d = 0;
7427079687aSbill if (c < 0)
7437079687aSbill goto past;
744f3328da7Sbostic if (wp) {
7457079687aSbill *wp++ = c;
746f3328da7Sbostic *wp = 0; /* end the string b4 test */
747f3328da7Sbostic }
74850cee248Schristos } while ((d || (!(kwd = keyword(owp)) && c != ' '
74950cee248Schristos && c != '\t')) && c != '\n');
7507079687aSbill } while (wp == 0);
751f3328da7Sbostic
752f3328da7Sbostic /*
753f3328da7Sbostic * if we have read a keyword ( "if", "switch" or "while" ) then we do not
754f3328da7Sbostic * need to unreadc the look-ahead char
755f3328da7Sbostic */
756f3328da7Sbostic if (!kwd) {
7577079687aSbill unreadc(c);
7587079687aSbill if (found)
7597079687aSbill *--wp = 0;
760f3328da7Sbostic }
761f3328da7Sbostic
7627079687aSbill return (found);
7637079687aSbill
7647079687aSbill past:
7657079687aSbill switch (Stype) {
7667079687aSbill
7675eb3278cSbostic case T_IF:
768f3328da7Sbostic stderror(ERR_NAME | ERR_NOTFOUND, "then/endif");
7697079687aSbill
7705eb3278cSbostic case T_ELSE:
771f3328da7Sbostic stderror(ERR_NAME | ERR_NOTFOUND, "endif");
7727079687aSbill
7735eb3278cSbostic case T_BRKSW:
7745eb3278cSbostic case T_SWITCH:
775f3328da7Sbostic stderror(ERR_NAME | ERR_NOTFOUND, "endsw");
7767079687aSbill
7775eb3278cSbostic case T_BREAK:
778f3328da7Sbostic stderror(ERR_NAME | ERR_NOTFOUND, "end");
7797079687aSbill
7805eb3278cSbostic case T_GOTO:
7818d2f70fbSchristos setname(vis_str(Sgoal));
782f3328da7Sbostic stderror(ERR_NAME | ERR_NOTFOUND, "label");
7837079687aSbill }
7847079687aSbill /* NOTREACHED */
785f3328da7Sbostic return (0);
7867079687aSbill }
7877079687aSbill
788f3328da7Sbostic /*
789f3328da7Sbostic * keyword(wp) determines if wp is one of the built-n functions if,
790f3328da7Sbostic * switch or while. It seems that when an if statement looks like
791f3328da7Sbostic * "if(" then getword above sucks in the '(' and so the search routine
792f3328da7Sbostic * never finds what it is scanning for. Rather than rewrite doword, I hack
793f3328da7Sbostic * in a test to see if the string forms a keyword. Then doword stops
794f3328da7Sbostic * and returns the word "if" -strike
795f3328da7Sbostic */
796f3328da7Sbostic
797f3328da7Sbostic static int
keyword(wp)798f3328da7Sbostic keyword(wp)
799f3328da7Sbostic Char *wp;
800f3328da7Sbostic {
801f3328da7Sbostic static Char STRif[] = {'i', 'f', '\0'};
802f3328da7Sbostic static Char STRwhile[] = {'w', 'h', 'i', 'l', 'e', '\0'};
803f3328da7Sbostic static Char STRswitch[] = {'s', 'w', 'i', 't', 'c', 'h', '\0'};
804f3328da7Sbostic
805f3328da7Sbostic if (!wp)
806f3328da7Sbostic return (0);
807f3328da7Sbostic
808f3328da7Sbostic if ((Strcmp(wp, STRif) == 0) || (Strcmp(wp, STRwhile) == 0)
809f3328da7Sbostic || (Strcmp(wp, STRswitch) == 0))
810f3328da7Sbostic return (1);
811f3328da7Sbostic
812f3328da7Sbostic return (0);
813f3328da7Sbostic }
814f3328da7Sbostic
815f3328da7Sbostic static void
toend()8167079687aSbill toend()
8177079687aSbill {
818af359014Schristos if (whyles->w_end.type == F_SEEK && whyles->w_end.f_seek == 0) {
819f3328da7Sbostic search(T_BREAK, 0, NULL);
820063c38e3Schristos btell(&whyles->w_end);
821063c38e3Schristos whyles->w_end.f_seek--;
822f3328da7Sbostic }
823f3328da7Sbostic else
824063c38e3Schristos bseek(&whyles->w_end);
8257079687aSbill wfree();
8267079687aSbill }
8277079687aSbill
828f3328da7Sbostic void
wfree()8297079687aSbill wfree()
8307079687aSbill {
831063c38e3Schristos struct Ain o;
832063c38e3Schristos struct whyle *nwp;
8337079687aSbill
834537134faSchristos btell(&o);
835063c38e3Schristos
836063c38e3Schristos for (; whyles; whyles = nwp) {
8377079687aSbill register struct whyle *wp = whyles;
838063c38e3Schristos nwp = wp->w_next;
839537134faSchristos
840537134faSchristos /*
841537134faSchristos * We free loops that have different seek types.
842537134faSchristos */
843537134faSchristos if (wp->w_end.type != I_SEEK && wp->w_start.type == wp->w_end.type &&
844537134faSchristos wp->w_start.type == o.type) {
845537134faSchristos if (wp->w_end.type == F_SEEK) {
846063c38e3Schristos if (o.f_seek >= wp->w_start.f_seek &&
847063c38e3Schristos (wp->w_end.f_seek == 0 || o.f_seek < wp->w_end.f_seek))
8487079687aSbill break;
849c5aa27adSchristos }
850537134faSchristos else {
851537134faSchristos if (o.a_seek >= wp->w_start.a_seek &&
852537134faSchristos (wp->w_end.a_seek == 0 || o.a_seek < wp->w_end.a_seek))
853537134faSchristos break;
854537134faSchristos }
855537134faSchristos }
856537134faSchristos
8577079687aSbill if (wp->w_fe0)
8587079687aSbill blkfree(wp->w_fe0);
8597079687aSbill if (wp->w_fename)
860f3328da7Sbostic xfree((ptr_t) wp->w_fename);
861f3328da7Sbostic xfree((ptr_t) wp);
8627079687aSbill }
8637079687aSbill }
8647079687aSbill
865f3328da7Sbostic void
866cce51c35Schristos /*ARGSUSED*/
doecho(v,t)867cce51c35Schristos doecho(v, t)
868f3328da7Sbostic Char **v;
869cce51c35Schristos struct command *t;
8707079687aSbill {
871f3328da7Sbostic xecho(' ', v);
8727079687aSbill }
8737079687aSbill
874f3328da7Sbostic void
875cce51c35Schristos /*ARGSUSED*/
doglob(v,t)876cce51c35Schristos doglob(v, t)
877f3328da7Sbostic Char **v;
878cce51c35Schristos struct command *t;
8797079687aSbill {
880f3328da7Sbostic xecho(0, v);
881cce51c35Schristos (void) fflush(cshout);
8827079687aSbill }
8837079687aSbill
884f3328da7Sbostic static void
xecho(sep,v)885f3328da7Sbostic xecho(sep, v)
88623ceb1ffSchristos int sep;
887f3328da7Sbostic register Char **v;
8887079687aSbill {
889f3328da7Sbostic register Char *cp;
8907079687aSbill int nonl = 0;
891*5fad6ed4Schristos sigset_t sigset;
8927079687aSbill
893*5fad6ed4Schristos if (setintr) {
894*5fad6ed4Schristos sigemptyset(&sigset);
895*5fad6ed4Schristos sigaddset(&sigset, SIGINT);
896*5fad6ed4Schristos sigprocmask(SIG_UNBLOCK, &sigset, NULL);
897*5fad6ed4Schristos }
8987079687aSbill v++;
8997079687aSbill if (*v == 0)
9007079687aSbill return;
9015c5636eeSedward gflag = 0, tglob(v);
9027079687aSbill if (gflag) {
903f21ede9aSbostic v = globall(v);
9047079687aSbill if (v == 0)
905f3328da7Sbostic stderror(ERR_NAME | ERR_NOMATCH);
906f3328da7Sbostic }
907f3328da7Sbostic else {
908f3328da7Sbostic v = gargv = saveblk(v);
9095c5636eeSedward trim(v);
910f3328da7Sbostic }
911f3328da7Sbostic if (sep == ' ' && *v && eq(*v, STRmn))
9127079687aSbill nonl++, v++;
91350cee248Schristos while ((cp = *v++) != NULL) {
9147079687aSbill register int c;
9157079687aSbill
91650cee248Schristos while ((c = *cp++) != '\0')
9178d2f70fbSchristos (void) vis_fputc(c | QUOTE, cshout);
918f3328da7Sbostic
9197079687aSbill if (*v)
9208d2f70fbSchristos (void) vis_fputc(sep | QUOTE, cshout);
9217079687aSbill }
9227079687aSbill if (sep && nonl == 0)
923cce51c35Schristos (void) fputc('\n', cshout);
9247079687aSbill else
925cce51c35Schristos (void) fflush(cshout);
9267079687aSbill if (setintr)
927*5fad6ed4Schristos sigprocmask(SIG_BLOCK, &sigset, NULL);
9287079687aSbill if (gargv)
9297079687aSbill blkfree(gargv), gargv = 0;
9307079687aSbill }
9317079687aSbill
932f3328da7Sbostic void
933cce51c35Schristos /*ARGSUSED*/
dosetenv(v,t)934cce51c35Schristos dosetenv(v, t)
935cce51c35Schristos Char **v;
936cce51c35Schristos struct command *t;
9377079687aSbill {
938f3328da7Sbostic Char *vp, *lp;
939*5fad6ed4Schristos sigset_t sigset;
9407079687aSbill
9418c565d60Sedward v++;
9428c565d60Sedward if ((vp = *v++) == 0) {
943f3328da7Sbostic register Char **ep;
9448c565d60Sedward
945*5fad6ed4Schristos if (setintr) {
946*5fad6ed4Schristos sigemptyset(&sigset);
947*5fad6ed4Schristos sigaddset(&sigset, SIGINT);
948*5fad6ed4Schristos sigprocmask(SIG_UNBLOCK, &sigset, NULL);
949*5fad6ed4Schristos }
950f3328da7Sbostic for (ep = STR_environ; *ep; ep++)
9518d2f70fbSchristos (void) fprintf(cshout, "%s\n", vis_str(*ep));
9528c565d60Sedward return;
9538c565d60Sedward }
9548c565d60Sedward if ((lp = *v++) == 0)
955f3328da7Sbostic lp = STRNULL;
9566b8cdf34Schristos Setenv(vp, lp = globone(lp, G_APPEND));
957f3328da7Sbostic if (eq(vp, STRPATH)) {
9587079687aSbill importpath(lp);
959cce51c35Schristos dohash(NULL, NULL);
9607079687aSbill }
961f3328da7Sbostic else if (eq(vp, STRLANG) || eq(vp, STRLC_CTYPE)) {
962f3328da7Sbostic #ifdef NLS
963f3328da7Sbostic int k;
964f3328da7Sbostic
965f3328da7Sbostic (void) setlocale(LC_ALL, "");
966a4c1bdd8Sleres for (k = 0200; k <= 0377 && !Isprint(k); k++)
967a4c1bdd8Sleres continue;
968f3328da7Sbostic AsciiOnly = k > 0377;
969f3328da7Sbostic #else
970f3328da7Sbostic AsciiOnly = 0;
971f3328da7Sbostic #endif /* NLS */
972f3328da7Sbostic }
973f3328da7Sbostic xfree((ptr_t) lp);
9747079687aSbill }
9757079687aSbill
976f3328da7Sbostic void
977cce51c35Schristos /*ARGSUSED*/
dounsetenv(v,t)978cce51c35Schristos dounsetenv(v, t)
979cce51c35Schristos Char **v;
980cce51c35Schristos struct command *t;
9817079687aSbill {
982f3328da7Sbostic Char **ep, *p, *n;
983f3328da7Sbostic int i, maxi;
984f3328da7Sbostic static Char *name = NULL;
985f3328da7Sbostic
986f3328da7Sbostic if (name)
987f3328da7Sbostic xfree((ptr_t) name);
988f3328da7Sbostic /*
989f3328da7Sbostic * Find the longest environment variable
990f3328da7Sbostic */
991f3328da7Sbostic for (maxi = 0, ep = STR_environ; *ep; ep++) {
992a4c1bdd8Sleres for (i = 0, p = *ep; *p && *p != '='; p++, i++)
993a4c1bdd8Sleres continue;
994f3328da7Sbostic if (i > maxi)
995f3328da7Sbostic maxi = i;
996f3328da7Sbostic }
997f3328da7Sbostic
998f3328da7Sbostic name = (Char *) xmalloc((size_t) (maxi + 1) * sizeof(Char));
9997079687aSbill
10006a3d3adeSchristos while (++v && *v)
10016a3d3adeSchristos for (maxi = 1; maxi;)
1002f3328da7Sbostic for (maxi = 0, ep = STR_environ; *ep; ep++) {
1003a4c1bdd8Sleres for (n = name, p = *ep; *p && *p != '='; *n++ = *p++)
1004a4c1bdd8Sleres continue;
1005f3328da7Sbostic *n = '\0';
1006f3328da7Sbostic if (!Gmatch(name, *v))
1007f3328da7Sbostic continue;
1008f3328da7Sbostic maxi = 1;
1009f3328da7Sbostic if (eq(name, STRLANG) || eq(name, STRLC_CTYPE)) {
1010f3328da7Sbostic #ifdef NLS
1011f3328da7Sbostic int k;
1012f3328da7Sbostic
1013f3328da7Sbostic (void) setlocale(LC_ALL, "");
1014a4c1bdd8Sleres for (k = 0200; k <= 0377 && !Isprint(k); k++)
1015a4c1bdd8Sleres continue;
1016f3328da7Sbostic AsciiOnly = k > 0377;
1017f3328da7Sbostic #else
1018f3328da7Sbostic AsciiOnly = getenv("LANG") == NULL &&
1019f3328da7Sbostic getenv("LC_CTYPE") == NULL;
1020f3328da7Sbostic #endif /* NLS */
1021f3328da7Sbostic }
1022f3328da7Sbostic /*
1023f3328da7Sbostic * Delete name, and start again cause the environment changes
1024f3328da7Sbostic */
1025f3328da7Sbostic Unsetenv(name);
1026f3328da7Sbostic break;
1027f3328da7Sbostic }
10288b08a34bSchristos xfree((ptr_t) name);
10298b08a34bSchristos name = NULL;
10307079687aSbill }
10317079687aSbill
1032f3328da7Sbostic void
Setenv(name,val)1033f3328da7Sbostic Setenv(name, val)
1034f3328da7Sbostic Char *name, *val;
10357079687aSbill {
1036f3328da7Sbostic register Char **ep = STR_environ;
1037f3328da7Sbostic register Char *cp, *dp;
1038f3328da7Sbostic Char *blk[2];
1039f3328da7Sbostic Char **oep = ep;
1040f3328da7Sbostic
10417079687aSbill
10427079687aSbill for (; *ep; ep++) {
10437079687aSbill for (cp = name, dp = *ep; *cp && *cp == *dp; cp++, dp++)
10447079687aSbill continue;
10457079687aSbill if (*cp != 0 || *dp != '=')
10467079687aSbill continue;
1047f3328da7Sbostic cp = Strspl(STRequal, val);
1048f3328da7Sbostic xfree((ptr_t) * ep);
1049f3328da7Sbostic *ep = strip(Strspl(name, cp));
1050f3328da7Sbostic xfree((ptr_t) cp);
1051f3328da7Sbostic blkfree((Char **) environ);
1052f3328da7Sbostic environ = short2blk(STR_environ);
10537079687aSbill return;
10547079687aSbill }
1055f3328da7Sbostic cp = Strspl(name, STRequal);
1056f3328da7Sbostic blk[0] = strip(Strspl(cp, val));
1057f3328da7Sbostic xfree((ptr_t) cp);
1058f3328da7Sbostic blk[1] = 0;
1059f3328da7Sbostic STR_environ = blkspl(STR_environ, blk);
1060f3328da7Sbostic blkfree((Char **) environ);
1061f3328da7Sbostic environ = short2blk(STR_environ);
1062f3328da7Sbostic xfree((ptr_t) oep);
10637079687aSbill }
10647079687aSbill
1065f3328da7Sbostic static void
Unsetenv(name)1066f3328da7Sbostic Unsetenv(name)
1067f3328da7Sbostic Char *name;
10687079687aSbill {
1069f3328da7Sbostic register Char **ep = STR_environ;
1070f3328da7Sbostic register Char *cp, *dp;
1071f3328da7Sbostic Char **oep = ep;
10727079687aSbill
10737079687aSbill for (; *ep; ep++) {
10747079687aSbill for (cp = name, dp = *ep; *cp && *cp == *dp; cp++, dp++)
10757079687aSbill continue;
10767079687aSbill if (*cp != 0 || *dp != '=')
10777079687aSbill continue;
10787079687aSbill cp = *ep;
10797079687aSbill *ep = 0;
1080f3328da7Sbostic STR_environ = blkspl(STR_environ, ep + 1);
1081f3328da7Sbostic environ = short2blk(STR_environ);
10827079687aSbill *ep = cp;
1083f3328da7Sbostic xfree((ptr_t) cp);
1084f3328da7Sbostic xfree((ptr_t) oep);
10857079687aSbill return;
10867079687aSbill }
10877079687aSbill }
10887079687aSbill
1089f3328da7Sbostic void
1090cce51c35Schristos /*ARGSUSED*/
doumask(v,t)1091cce51c35Schristos doumask(v, t)
1092cce51c35Schristos Char **v;
1093cce51c35Schristos struct command *t;
10947079687aSbill {
1095f3328da7Sbostic register Char *cp = v[1];
10967079687aSbill register int i;
10977079687aSbill
10987079687aSbill if (cp == 0) {
10997079687aSbill i = umask(0);
11005c5636eeSedward (void) umask(i);
1101cce51c35Schristos (void) fprintf(cshout, "%o\n", i);
11027079687aSbill return;
11037079687aSbill }
11047079687aSbill i = 0;
1105f3328da7Sbostic while (Isdigit(*cp) && *cp != '8' && *cp != '9')
11067079687aSbill i = i * 8 + *cp++ - '0';
11077079687aSbill if (*cp || i < 0 || i > 0777)
1108f3328da7Sbostic stderror(ERR_NAME | ERR_MASK);
11095c5636eeSedward (void) umask(i);
11107079687aSbill }
11117079687aSbill
1112f2bd196cSmckusick typedef quad_t RLIM_TYPE;
11137079687aSbill
1114f3328da7Sbostic static struct limits {
11157079687aSbill int limconst;
11167079687aSbill char *limname;
11177079687aSbill int limdiv;
11187079687aSbill char *limscale;
11197079687aSbill } limits[] = {
112050cee248Schristos { RLIMIT_CPU, "cputime", 1, "seconds" },
112150cee248Schristos { RLIMIT_FSIZE, "filesize", 1024, "kbytes" },
112250cee248Schristos { RLIMIT_DATA, "datasize", 1024, "kbytes" },
112350cee248Schristos { RLIMIT_STACK, "stacksize", 1024, "kbytes" },
112450cee248Schristos { RLIMIT_CORE, "coredumpsize", 1024, "kbytes" },
112550cee248Schristos { RLIMIT_RSS, "memoryuse", 1024, "kbytes" },
112650cee248Schristos { RLIMIT_MEMLOCK, "memorylocked", 1024, "kbytes" },
112750cee248Schristos { RLIMIT_NPROC, "maxproc", 1, "" },
112850cee248Schristos { RLIMIT_NOFILE, "openfiles", 1, "" },
112950cee248Schristos { -1, NULL, 0, NULL }
11307079687aSbill };
11317079687aSbill
1132f3328da7Sbostic static struct limits *findlim();
1133f3328da7Sbostic static RLIM_TYPE getval();
1134f3328da7Sbostic static void limtail();
1135f3328da7Sbostic static void plim();
1136f3328da7Sbostic static int setlim();
1137f3328da7Sbostic
1138f3328da7Sbostic static struct limits *
findlim(cp)11397079687aSbill findlim(cp)
1140f3328da7Sbostic Char *cp;
11417079687aSbill {
11427079687aSbill register struct limits *lp, *res;
11437079687aSbill
1144f3328da7Sbostic res = (struct limits *) NULL;
11457079687aSbill for (lp = limits; lp->limconst >= 0; lp++)
1146f3328da7Sbostic if (prefix(cp, str2short(lp->limname))) {
11477079687aSbill if (res)
1148f3328da7Sbostic stderror(ERR_NAME | ERR_AMBIG);
11497079687aSbill res = lp;
11507079687aSbill }
11517079687aSbill if (res)
11527079687aSbill return (res);
1153f3328da7Sbostic stderror(ERR_NAME | ERR_LIMIT);
11545c5636eeSedward /* NOTREACHED */
1155f3328da7Sbostic return (0);
11567079687aSbill }
11577079687aSbill
1158f3328da7Sbostic void
1159cce51c35Schristos /*ARGSUSED*/
dolimit(v,t)1160cce51c35Schristos dolimit(v, t)
1161cce51c35Schristos Char **v;
1162cce51c35Schristos struct command *t;
11637079687aSbill {
11647079687aSbill register struct limits *lp;
1165f3328da7Sbostic register RLIM_TYPE limit;
11663c8a896fSedward char hard = 0;
11677079687aSbill
11687079687aSbill v++;
1169f3328da7Sbostic if (*v && eq(*v, STRmh)) {
11703c8a896fSedward hard = 1;
11713c8a896fSedward v++;
11723c8a896fSedward }
11737079687aSbill if (*v == 0) {
11743c8a896fSedward for (lp = limits; lp->limconst >= 0; lp++)
11753c8a896fSedward plim(lp, hard);
11767079687aSbill return;
11777079687aSbill }
11787079687aSbill lp = findlim(v[0]);
11797079687aSbill if (v[1] == 0) {
11803c8a896fSedward plim(lp, hard);
11817079687aSbill return;
11827079687aSbill }
11837079687aSbill limit = getval(lp, v + 1);
11843c8a896fSedward if (setlim(lp, hard, limit) < 0)
1185f3328da7Sbostic stderror(ERR_SILENT);
11867079687aSbill }
11877079687aSbill
1188f3328da7Sbostic static RLIM_TYPE
getval(lp,v)11897079687aSbill getval(lp, v)
11907079687aSbill register struct limits *lp;
1191f3328da7Sbostic Char **v;
11927079687aSbill {
11937079687aSbill register float f;
11947079687aSbill double atof();
1195f3328da7Sbostic Char *cp = *v++;
11967079687aSbill
1197f3328da7Sbostic f = atof(short2str(cp));
1198f3328da7Sbostic
1199f3328da7Sbostic while (Isdigit(*cp) || *cp == '.' || *cp == 'e' || *cp == 'E')
12007079687aSbill cp++;
12017079687aSbill if (*cp == 0) {
12027079687aSbill if (*v == 0)
1203f3328da7Sbostic return ((RLIM_TYPE) ((f + 0.5) * lp->limdiv));
12047079687aSbill cp = *v;
12057079687aSbill }
12067079687aSbill switch (*cp) {
12077079687aSbill case ':':
1208b12aea6aSsam if (lp->limconst != RLIMIT_CPU)
12097079687aSbill goto badscal;
1210f3328da7Sbostic return ((RLIM_TYPE) (f * 60.0 + atof(short2str(cp + 1))));
12117079687aSbill case 'h':
1212b12aea6aSsam if (lp->limconst != RLIMIT_CPU)
12137079687aSbill goto badscal;
12147079687aSbill limtail(cp, "hours");
1215f3328da7Sbostic f *= 3600.0;
12167079687aSbill break;
12177079687aSbill case 'm':
1218b12aea6aSsam if (lp->limconst == RLIMIT_CPU) {
12197079687aSbill limtail(cp, "minutes");
1220f3328da7Sbostic f *= 60.0;
12217079687aSbill break;
12227079687aSbill }
12237079687aSbill *cp = 'm';
12247079687aSbill limtail(cp, "megabytes");
1225f3328da7Sbostic f *= 1024.0 * 1024.0;
12267079687aSbill break;
12277079687aSbill case 's':
1228b12aea6aSsam if (lp->limconst != RLIMIT_CPU)
12297079687aSbill goto badscal;
12307079687aSbill limtail(cp, "seconds");
12317079687aSbill break;
1232f3328da7Sbostic case 'M':
1233f3328da7Sbostic if (lp->limconst == RLIMIT_CPU)
1234f3328da7Sbostic goto badscal;
1235f3328da7Sbostic *cp = 'm';
1236f3328da7Sbostic limtail(cp, "megabytes");
1237f3328da7Sbostic f *= 1024.0 * 1024.0;
1238f3328da7Sbostic break;
12397079687aSbill case 'k':
1240b12aea6aSsam if (lp->limconst == RLIMIT_CPU)
12417079687aSbill goto badscal;
12427079687aSbill limtail(cp, "kbytes");
1243f3328da7Sbostic f *= 1024.0;
12447079687aSbill break;
12457079687aSbill case 'u':
12467079687aSbill limtail(cp, "unlimited");
1247b12aea6aSsam return (RLIM_INFINITY);
12487079687aSbill default:
12497079687aSbill badscal:
1250f3328da7Sbostic stderror(ERR_NAME | ERR_SCALEF);
12517079687aSbill }
125228434420Schristos f += 0.5;
125318b0cf93Schristos if (f > (float) RLIM_INFINITY)
125418b0cf93Schristos return RLIM_INFINITY;
125528434420Schristos else
125628434420Schristos return ((RLIM_TYPE) f);
12577079687aSbill }
12587079687aSbill
1259f3328da7Sbostic static void
limtail(cp,str)1260f3328da7Sbostic limtail(cp, str)
1261f3328da7Sbostic Char *cp;
1262f3328da7Sbostic char *str;
12637079687aSbill {
12647079687aSbill while (*cp && *cp == *str)
12657079687aSbill cp++, str++;
12667079687aSbill if (*cp)
1267f3328da7Sbostic stderror(ERR_BADSCALE, str);
12687079687aSbill }
12697079687aSbill
1270f3328da7Sbostic
1271f3328da7Sbostic /*ARGSUSED*/
1272f3328da7Sbostic static void
plim(lp,hard)12733c8a896fSedward plim(lp, hard)
12747079687aSbill register struct limits *lp;
1275f3328da7Sbostic Char hard;
12767079687aSbill {
1277b12aea6aSsam struct rlimit rlim;
1278f3328da7Sbostic RLIM_TYPE limit;
12797079687aSbill
1280cce51c35Schristos (void) fprintf(cshout, "%s \t", lp->limname);
1281f3328da7Sbostic
12825c5636eeSedward (void) getrlimit(lp->limconst, &rlim);
12833c8a896fSedward limit = hard ? rlim.rlim_max : rlim.rlim_cur;
1284f3328da7Sbostic
12853c8a896fSedward if (limit == RLIM_INFINITY)
1286cce51c35Schristos (void) fprintf(cshout, "unlimited");
1287b12aea6aSsam else if (lp->limconst == RLIMIT_CPU)
12883c8a896fSedward psecs((long) limit);
12897079687aSbill else
1290cce51c35Schristos (void) fprintf(cshout, "%ld %s", (long) (limit / lp->limdiv),
1291cce51c35Schristos lp->limscale);
1292cce51c35Schristos (void) fputc('\n', cshout);
12937079687aSbill }
12947079687aSbill
1295f3328da7Sbostic void
1296cce51c35Schristos /*ARGSUSED*/
dounlimit(v,t)1297cce51c35Schristos dounlimit(v, t)
1298cce51c35Schristos Char **v;
1299cce51c35Schristos struct command *t;
13007079687aSbill {
13017079687aSbill register struct limits *lp;
1302f3328da7Sbostic int lerr = 0;
1303f3328da7Sbostic Char hard = 0;
13047079687aSbill
13057079687aSbill v++;
1306f3328da7Sbostic if (*v && eq(*v, STRmh)) {
13073c8a896fSedward hard = 1;
13083c8a896fSedward v++;
13093c8a896fSedward }
13107079687aSbill if (*v == 0) {
13113c8a896fSedward for (lp = limits; lp->limconst >= 0; lp++)
1312f3328da7Sbostic if (setlim(lp, hard, (RLIM_TYPE) RLIM_INFINITY) < 0)
1313f3328da7Sbostic lerr++;
1314f3328da7Sbostic if (lerr)
1315f3328da7Sbostic stderror(ERR_SILENT);
13167079687aSbill return;
13177079687aSbill }
13187079687aSbill while (*v) {
13197079687aSbill lp = findlim(*v++);
1320f3328da7Sbostic if (setlim(lp, hard, (RLIM_TYPE) RLIM_INFINITY) < 0)
1321f3328da7Sbostic stderror(ERR_SILENT);
13227079687aSbill }
13237079687aSbill }
13247079687aSbill
1325f3328da7Sbostic static int
setlim(lp,hard,limit)13263c8a896fSedward setlim(lp, hard, limit)
13277079687aSbill register struct limits *lp;
1328f3328da7Sbostic Char hard;
1329f3328da7Sbostic RLIM_TYPE limit;
13307079687aSbill {
1331b12aea6aSsam struct rlimit rlim;
13327079687aSbill
13335c5636eeSedward (void) getrlimit(lp->limconst, &rlim);
1334f3328da7Sbostic
13353c8a896fSedward if (hard)
13363c8a896fSedward rlim.rlim_max = limit;
13373c8a896fSedward else if (limit == RLIM_INFINITY && geteuid() != 0)
13384a4a4a91Smckusick rlim.rlim_cur = rlim.rlim_max;
13394a4a4a91Smckusick else
1340b12aea6aSsam rlim.rlim_cur = limit;
1341f3328da7Sbostic
13426fabb4b4Smckusick if (setrlimit(lp->limconst, &rlim) < 0) {
1343cce51c35Schristos (void) fprintf(csherr, "%s: %s: Can't %s%s limit\n", bname, lp->limname,
13443c8a896fSedward limit == RLIM_INFINITY ? "remove" : "set",
13453c8a896fSedward hard ? " hard" : "");
13466fabb4b4Smckusick return (-1);
13476fabb4b4Smckusick }
13486fabb4b4Smckusick return (0);
13497079687aSbill }
13507079687aSbill
1351f3328da7Sbostic void
1352cce51c35Schristos /*ARGSUSED*/
dosuspend(v,t)1353cce51c35Schristos dosuspend(v, t)
1354cce51c35Schristos Char **v;
1355cce51c35Schristos struct command *t;
13567079687aSbill {
1357f3328da7Sbostic int ctpgrp;
1358f3328da7Sbostic
1359f3328da7Sbostic void (*old) ();
13607079687aSbill
13617079687aSbill if (loginsh)
1362f3328da7Sbostic stderror(ERR_SUSPLOG);
13637079687aSbill untty();
1364f3328da7Sbostic
1365c2336e9cSralph old = signal(SIGTSTP, SIG_DFL);
13665c5636eeSedward (void) kill(0, SIGTSTP);
13677079687aSbill /* the shell stops here */
13685c5636eeSedward (void) signal(SIGTSTP, old);
1369f3328da7Sbostic
13707079687aSbill if (tpgrp != -1) {
1371f3328da7Sbostic ctpgrp = tcgetpgrp(FSHTTY);
1372cce51c35Schristos while (ctpgrp != opgrp) {
1373c2336e9cSralph old = signal(SIGTTIN, SIG_DFL);
13745c5636eeSedward (void) kill(0, SIGTTIN);
13755c5636eeSedward (void) signal(SIGTTIN, old);
13767079687aSbill }
1377f3328da7Sbostic (void) setpgid(0, shpgrp);
1378f3328da7Sbostic (void) tcsetpgrp(FSHTTY, shpgrp);
13797079687aSbill }
13807079687aSbill }
13817079687aSbill
1382f3328da7Sbostic /* This is the dreaded EVAL built-in.
1383f3328da7Sbostic * If you don't fiddle with file descriptors, and reset didfds,
1384f3328da7Sbostic * this command will either ignore redirection inside or outside
1385f3328da7Sbostic * its aguments, e.g. eval "date >x" vs. eval "date" >x
1386f3328da7Sbostic * The stuff here seems to work, but I did it by trial and error rather
1387f3328da7Sbostic * than really knowing what was going on. If tpgrp is zero, we are
1388f3328da7Sbostic * probably a background eval, e.g. "eval date &", and we want to
1389f3328da7Sbostic * make sure that any processes we start stay in our pgrp.
1390f3328da7Sbostic * This is also the case for "time eval date" -- stay in same pgrp.
1391f3328da7Sbostic * Otherwise, under stty tostop, processes will stop in the wrong
1392f3328da7Sbostic * pgrp, with no way for the shell to get them going again. -IAN!
1393f3328da7Sbostic */
1394cce51c35Schristos static Char **gv = NULL;
1395f3328da7Sbostic void
1396cce51c35Schristos /*ARGSUSED*/
doeval(v,t)1397cce51c35Schristos doeval(v, t)
1398f3328da7Sbostic Char **v;
1399cce51c35Schristos struct command *t;
14007079687aSbill {
1401f3328da7Sbostic Char **oevalvec;
1402f3328da7Sbostic Char *oevalp;
1403f3328da7Sbostic int odidfds;
14047079687aSbill jmp_buf osetexit;
1405f3328da7Sbostic int my_reenter;
1406cce51c35Schristos Char **savegv = gv;
1407f3328da7Sbostic int saveIN;
1408f3328da7Sbostic int saveOUT;
1409cce51c35Schristos int saveERR;
1410f3328da7Sbostic int oSHIN;
1411f3328da7Sbostic int oSHOUT;
1412cce51c35Schristos int oSHERR;
1413f3328da7Sbostic
141450cee248Schristos UNREGISTER(v);
141550cee248Schristos
1416f3328da7Sbostic oevalvec = evalvec;
1417f3328da7Sbostic oevalp = evalp;
1418f3328da7Sbostic odidfds = didfds;
1419f3328da7Sbostic oSHIN = SHIN;
1420f3328da7Sbostic oSHOUT = SHOUT;
1421cce51c35Schristos oSHERR = SHERR;
14227079687aSbill
14237079687aSbill v++;
14247079687aSbill if (*v == 0)
14257079687aSbill return;
14265c5636eeSedward gflag = 0, tglob(v);
14277079687aSbill if (gflag) {
1428f21ede9aSbostic gv = v = globall(v);
14297079687aSbill gargv = 0;
14307079687aSbill if (v == 0)
1431f3328da7Sbostic stderror(ERR_NOMATCH);
14327079687aSbill v = copyblk(v);
1433f3328da7Sbostic }
1434f3328da7Sbostic else {
143523ceb1ffSchristos gv = NULL;
1436f3328da7Sbostic v = copyblk(v);
14375c5636eeSedward trim(v);
1438f3328da7Sbostic }
1439f3328da7Sbostic
1440f3328da7Sbostic saveIN = dcopy(SHIN, -1);
1441f3328da7Sbostic saveOUT = dcopy(SHOUT, -1);
1442cce51c35Schristos saveERR = dcopy(SHERR, -1);
1443f3328da7Sbostic
14447079687aSbill getexit(osetexit);
1445f3328da7Sbostic
1446f3328da7Sbostic if ((my_reenter = setexit()) == 0) {
14477079687aSbill evalvec = v;
14487079687aSbill evalp = 0;
1449f3328da7Sbostic SHIN = dcopy(0, -1);
1450f3328da7Sbostic SHOUT = dcopy(1, -1);
1451cce51c35Schristos SHERR = dcopy(2, -1);
1452f3328da7Sbostic didfds = 0;
14537079687aSbill process(0);
14547079687aSbill }
1455f3328da7Sbostic
14567079687aSbill evalvec = oevalvec;
14577079687aSbill evalp = oevalp;
14587079687aSbill doneinp = 0;
1459f3328da7Sbostic didfds = odidfds;
1460f3328da7Sbostic (void) close(SHIN);
1461f3328da7Sbostic (void) close(SHOUT);
1462cce51c35Schristos (void) close(SHERR);
1463f3328da7Sbostic SHIN = dmove(saveIN, oSHIN);
1464f3328da7Sbostic SHOUT = dmove(saveOUT, oSHOUT);
1465cce51c35Schristos SHERR = dmove(saveERR, oSHERR);
14667079687aSbill if (gv)
1467cce51c35Schristos blkfree(gv), gv = NULL;
14687079687aSbill resexit(osetexit);
1469cce51c35Schristos gv = savegv;
1470f3328da7Sbostic if (my_reenter)
1471f3328da7Sbostic stderror(ERR_SILENT);
14727079687aSbill }
1473cee4b30eSchristos
1474cee4b30eSchristos void
1475cee4b30eSchristos /*ARGSUSED*/
doprintf(v,t)1476cee4b30eSchristos doprintf(v, t)
1477cee4b30eSchristos Char **v;
1478cee4b30eSchristos struct command *t;
1479cee4b30eSchristos {
1480cee4b30eSchristos char **c;
1481cee4b30eSchristos extern int progprintf __P((int, char **));
1482cee4b30eSchristos int ret;
1483cee4b30eSchristos
1484cee4b30eSchristos ret = progprintf(blklen(v), c = short2blk(v));
14853e94c217Schristos (void) fflush(cshout);
14863e94c217Schristos (void) fflush(csherr);
1487cee4b30eSchristos
1488cee4b30eSchristos blkfree((Char **) c);
1489cee4b30eSchristos if (ret)
1490cee4b30eSchristos stderror(ERR_SILENT);
1491cee4b30eSchristos }
1492