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