sh.func.c revision 131962
1131962Smp/* $Header: /src/pub/tcsh/sh.func.c,v 3.111 2004/05/13 15:23:39 christos Exp $ */
259243Sobrien/*
359243Sobrien * sh.func.c: csh builtin functions
459243Sobrien */
559243Sobrien/*-
659243Sobrien * Copyright (c) 1980, 1991 The Regents of the University of California.
759243Sobrien * All rights reserved.
859243Sobrien *
959243Sobrien * Redistribution and use in source and binary forms, with or without
1059243Sobrien * modification, are permitted provided that the following conditions
1159243Sobrien * are met:
1259243Sobrien * 1. Redistributions of source code must retain the above copyright
1359243Sobrien *    notice, this list of conditions and the following disclaimer.
1459243Sobrien * 2. Redistributions in binary form must reproduce the above copyright
1559243Sobrien *    notice, this list of conditions and the following disclaimer in the
1659243Sobrien *    documentation and/or other materials provided with the distribution.
17100616Smp * 3. Neither the name of the University nor the names of its contributors
1859243Sobrien *    may be used to endorse or promote products derived from this software
1959243Sobrien *    without specific prior written permission.
2059243Sobrien *
2159243Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2259243Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2359243Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2459243Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2559243Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2659243Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2759243Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2859243Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2959243Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3059243Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3159243Sobrien * SUCH DAMAGE.
3259243Sobrien */
3359243Sobrien#include "sh.h"
3459243Sobrien
35131962SmpRCSID("$Id: sh.func.c,v 3.111 2004/05/13 15:23:39 christos Exp $")
3659243Sobrien
3759243Sobrien#include "ed.h"
3859243Sobrien#include "tw.h"
3959243Sobrien#include "tc.h"
4069408Sache#ifdef WINNT_NATIVE
4159243Sobrien#include "nt.const.h"
4269408Sache#endif /* WINNT_NATIVE */
4359243Sobrien
4459243Sobrien/*
4559243Sobrien * C shell
4659243Sobrien */
4759243Sobrienextern int just_signaled;
4859243Sobrienextern char **environ;
4959243Sobrien
5059243Sobrienextern bool MapsAreInited;
5159243Sobrienextern bool NLSMapsAreInited;
5259243Sobrienextern bool NoNLSRebind;
5359243Sobrienextern bool GotTermCaps;
5459243Sobrien
5559243Sobrienstatic int zlast = -1;
5659243Sobrien
5759243Sobrienstatic	void	islogin		__P((void));
5859243Sobrienstatic	void	preread		__P((void));
5959243Sobrienstatic	void	doagain		__P((void));
6059243Sobrienstatic  char   *isrchx		__P((int));
6159243Sobrienstatic	void	search		__P((int, int, Char *));
6259243Sobrienstatic	int	getword		__P((Char *));
6359243Sobrienstatic	void	toend		__P((void));
6459243Sobrienstatic	void	xecho		__P((int, Char **));
6559243Sobrienstatic	bool	islocale_var	__P((Char *));
66131962Smpstatic	void	wpfree		__P((struct whyle *));
6759243Sobrien
6859243Sobrienstruct biltins *
6959243Sobrienisbfunc(t)
7059243Sobrien    struct command *t;
7159243Sobrien{
7259243Sobrien    register Char *cp = t->t_dcom[0];
7359243Sobrien    register struct biltins *bp, *bp1, *bp2;
7459243Sobrien    static struct biltins label = {"", dozip, 0, 0};
7559243Sobrien    static struct biltins foregnd = {"%job", dofg1, 0, 0};
7659243Sobrien    static struct biltins backgnd = {"%job &", dobg1, 0, 0};
7759243Sobrien
7859243Sobrien    /*
7959243Sobrien     * We never match a builtin that has quoted the first
8059243Sobrien     * character; this has been the traditional way to escape
8159243Sobrien     * builtin commands.
8259243Sobrien     */
8359243Sobrien    if (*cp & QUOTE)
8459243Sobrien	return NULL;
8559243Sobrien
8659243Sobrien    if (*cp != ':' && lastchr(cp) == ':') {
8759243Sobrien	label.bname = short2str(cp);
8859243Sobrien	return (&label);
8959243Sobrien    }
9059243Sobrien    if (*cp == '%') {
9159243Sobrien	if (t->t_dflg & F_AMPERSAND) {
9259243Sobrien	    t->t_dflg &= ~F_AMPERSAND;
9359243Sobrien	    backgnd.bname = short2str(cp);
9459243Sobrien	    return (&backgnd);
9559243Sobrien	}
9659243Sobrien	foregnd.bname = short2str(cp);
9759243Sobrien	return (&foregnd);
9859243Sobrien    }
9959243Sobrien#ifdef WARP
10059243Sobrien    /*
10159243Sobrien     * This is a perhaps kludgy way to determine if the warp builtin is to be
10259243Sobrien     * acknowledged or not.  If checkwarp() fails, then we are to assume that
10359243Sobrien     * the warp command is invalid, and carry on as we would handle any other
10459243Sobrien     * non-builtin command.         -- JDK 2/4/88
10559243Sobrien     */
10659243Sobrien    if (eq(STRwarp, cp) && !checkwarp()) {
10759243Sobrien	return (0);		/* this builtin disabled */
10859243Sobrien    }
10959243Sobrien#endif /* WARP */
11059243Sobrien    /*
11159243Sobrien     * Binary search Bp1 is the beginning of the current search range. Bp2 is
11259243Sobrien     * one past the end.
11359243Sobrien     */
11459243Sobrien    for (bp1 = bfunc, bp2 = bfunc + nbfunc; bp1 < bp2;) {
11559243Sobrien	int i;
11659243Sobrien
11759243Sobrien	bp = bp1 + ((bp2 - bp1) >> 1);
11859243Sobrien	if ((i = ((char) *cp) - *bp->bname) == 0 &&
11959243Sobrien	    (i = StrQcmp(cp, str2short(bp->bname))) == 0)
12059243Sobrien	    return bp;
12159243Sobrien	if (i < 0)
12259243Sobrien	    bp2 = bp;
12359243Sobrien	else
12459243Sobrien	    bp1 = bp + 1;
12559243Sobrien    }
12669408Sache#ifdef WINNT_NATIVE
12759243Sobrien    return nt_check_additional_builtins(cp);
12869408Sache#endif /*WINNT_NATIVE*/
12959243Sobrien    return (0);
13059243Sobrien}
13159243Sobrien
13259243Sobrienvoid
13359243Sobrienfunc(t, bp)
13459243Sobrien    register struct command *t;
13559243Sobrien    register struct biltins *bp;
13659243Sobrien{
13759243Sobrien    int     i;
13859243Sobrien
13959243Sobrien    xechoit(t->t_dcom);
14059243Sobrien    setname(bp->bname);
14159243Sobrien    i = blklen(t->t_dcom) - 1;
14259243Sobrien    if (i < bp->minargs)
14359243Sobrien	stderror(ERR_NAME | ERR_TOOFEW);
14459243Sobrien    if (i > bp->maxargs)
14559243Sobrien	stderror(ERR_NAME | ERR_TOOMANY);
14659243Sobrien    (*bp->bfunct) (t->t_dcom, t);
14759243Sobrien}
14859243Sobrien
14959243Sobrien/*ARGSUSED*/
15059243Sobrienvoid
15159243Sobriendoonintr(v, c)
15259243Sobrien    Char  **v;
15359243Sobrien    struct command *c;
15459243Sobrien{
15559243Sobrien    register Char *cp;
15659243Sobrien    register Char *vv = v[1];
15759243Sobrien
15859243Sobrien    USE(c);
15959243Sobrien    if (parintr == SIG_IGN)
16059243Sobrien	return;
16159243Sobrien    if (setintr && intty)
16259243Sobrien	stderror(ERR_NAME | ERR_TERMINAL);
16359243Sobrien    cp = gointr;
16459243Sobrien    gointr = 0;
16559243Sobrien    xfree((ptr_t) cp);
16659243Sobrien    if (vv == 0) {
16759243Sobrien#ifdef BSDSIGS
16859243Sobrien	if (setintr) {
16959243Sobrien	    (void) sigblock(sigmask(SIGINT));
17059243Sobrien	    (void) signal(SIGINT, pintr);
17159243Sobrien	}
17259243Sobrien	else
17359243Sobrien	    (void) signal(SIGINT, SIG_DFL);
17459243Sobrien#else /* !BSDSIGS */
17559243Sobrien	if (setintr) {
17659243Sobrien	    (void) sighold(SIGINT);
17759243Sobrien	    (void) sigset(SIGINT, pintr);
17859243Sobrien	}
17959243Sobrien	else
18059243Sobrien	    (void) sigset(SIGINT, SIG_DFL);
18159243Sobrien#endif /* BSDSIGS */
18259243Sobrien	gointr = 0;
18359243Sobrien    }
18459243Sobrien    else if (eq((vv = strip(vv)), STRminus)) {
18559243Sobrien#ifdef BSDSIGS
18659243Sobrien	(void) signal(SIGINT, SIG_IGN);
18759243Sobrien#else /* !BSDSIGS */
18859243Sobrien	(void) sigset(SIGINT, SIG_IGN);
18959243Sobrien#endif /* BSDSIGS */
19059243Sobrien	gointr = Strsave(STRminus);
19159243Sobrien    }
19259243Sobrien    else {
19359243Sobrien	gointr = Strsave(vv);
19459243Sobrien#ifdef BSDSIGS
19559243Sobrien	(void) signal(SIGINT, pintr);
19659243Sobrien#else /* !BSDSIGS */
19759243Sobrien	(void) sigset(SIGINT, pintr);
19859243Sobrien#endif /* BSDSIGS */
19959243Sobrien    }
20059243Sobrien}
20159243Sobrien
20259243Sobrien/*ARGSUSED*/
20359243Sobrienvoid
20459243Sobriendonohup(v, c)
20559243Sobrien    Char **v;
20659243Sobrien    struct command *c;
20759243Sobrien{
20859243Sobrien    USE(c);
20959243Sobrien    USE(v);
21059243Sobrien    if (intty)
21159243Sobrien	stderror(ERR_NAME | ERR_TERMINAL);
21259243Sobrien    if (setintr == 0) {
21359243Sobrien	(void) signal(SIGHUP, SIG_IGN);
21459243Sobrien#ifdef CC
21559243Sobrien	submit(getpid());
21659243Sobrien#endif /* CC */
21759243Sobrien    }
21859243Sobrien}
21959243Sobrien
22059243Sobrien/*ARGSUSED*/
22159243Sobrienvoid
22259243Sobriendohup(v, c)
22359243Sobrien    Char **v;
22459243Sobrien    struct command *c;
22559243Sobrien{
22659243Sobrien    USE(c);
22759243Sobrien    USE(v);
22859243Sobrien    if (intty)
22959243Sobrien	stderror(ERR_NAME | ERR_TERMINAL);
23059243Sobrien    if (setintr == 0)
23159243Sobrien	(void) signal(SIGHUP, SIG_DFL);
23259243Sobrien}
23359243Sobrien
23459243Sobrien
23559243Sobrien/*ARGSUSED*/
23659243Sobrienvoid
23759243Sobriendozip(v, c)
23859243Sobrien    Char **v;
23959243Sobrien    struct command *c;
24059243Sobrien{
24159243Sobrien    USE(c);
24259243Sobrien    USE(v);
24359243Sobrien}
24459243Sobrien
24559243Sobrien/*ARGSUSED*/
24659243Sobrienvoid
24759243Sobriendofiletest(v, c)
24859243Sobrien    Char **v;
24959243Sobrien    struct command *c;
25059243Sobrien{
25159243Sobrien    Char **fileptr, *ftest, *res;
25259243Sobrien
25359243Sobrien    if (*(ftest = *++v) != '-')
25459243Sobrien	stderror(ERR_NAME | ERR_FILEINQ);
25559243Sobrien    ++v;
25659243Sobrien
25759243Sobrien    gflag = 0;
25859243Sobrien    tglob(v);
25959243Sobrien    if (gflag) {
26059243Sobrien	v = globall(v);
26159243Sobrien	if (v == 0)
26259243Sobrien	    stderror(ERR_NAME | ERR_NOMATCH);
26359243Sobrien    }
26459243Sobrien    else
26559243Sobrien	v = gargv = saveblk(v);
26659243Sobrien    trim(v);
26759243Sobrien
26859243Sobrien    while (*(fileptr = v++) != '\0') {
26959243Sobrien	xprintf("%S", res = filetest(ftest, &fileptr, 0));
27059243Sobrien	xfree((ptr_t) res);
27159243Sobrien	if (*v)
27259243Sobrien	    xprintf(" ");
27359243Sobrien    }
27459243Sobrien    xprintf("\n");
27559243Sobrien
27659243Sobrien    if (gargv) {
27759243Sobrien	blkfree(gargv);
27859243Sobrien	gargv = 0;
27959243Sobrien    }
28059243Sobrien}
28159243Sobrien
28259243Sobrienvoid
28359243Sobrienprvars()
28459243Sobrien{
28559243Sobrien    plist(&shvhed, VAR_ALL);
28659243Sobrien}
28759243Sobrien
28859243Sobrien/*ARGSUSED*/
28959243Sobrienvoid
29059243Sobriendoalias(v, c)
29159243Sobrien    register Char **v;
29259243Sobrien    struct command *c;
29359243Sobrien{
29459243Sobrien    register struct varent *vp;
29559243Sobrien    register Char *p;
29659243Sobrien
29759243Sobrien    USE(c);
29859243Sobrien    v++;
29959243Sobrien    p = *v++;
30059243Sobrien    if (p == 0)
30159243Sobrien	plist(&aliases, VAR_ALL);
30259243Sobrien    else if (*v == 0) {
30359243Sobrien	vp = adrof1(strip(p), &aliases);
304100616Smp	if (vp && vp->vec)
30559243Sobrien	    blkpr(vp->vec), xputchar('\n');
30659243Sobrien    }
30759243Sobrien    else {
30859243Sobrien	if (eq(p, STRalias) || eq(p, STRunalias)) {
30959243Sobrien	    setname(short2str(p));
31059243Sobrien	    stderror(ERR_NAME | ERR_DANGER);
31159243Sobrien	}
31259243Sobrien	set1(strip(p), saveblk(v), &aliases, VAR_READWRITE);
31359243Sobrien	tw_cmd_free();
31459243Sobrien    }
31559243Sobrien}
31659243Sobrien
31759243Sobrien/*ARGSUSED*/
31859243Sobrienvoid
31959243Sobrienunalias(v, c)
32059243Sobrien    Char  **v;
32159243Sobrien    struct command *c;
32259243Sobrien{
32359243Sobrien    USE(c);
32459243Sobrien    unset1(v, &aliases);
32559243Sobrien    tw_cmd_free();
32659243Sobrien}
32759243Sobrien
32859243Sobrien/*ARGSUSED*/
32959243Sobrienvoid
33059243Sobriendologout(v, c)
33159243Sobrien    Char **v;
33259243Sobrien    struct command *c;
33359243Sobrien{
33459243Sobrien    USE(c);
33559243Sobrien    USE(v);
33659243Sobrien    islogin();
33759243Sobrien    goodbye(NULL, NULL);
33859243Sobrien}
33959243Sobrien
34059243Sobrien/*ARGSUSED*/
34159243Sobrienvoid
34259243Sobriendologin(v, c)
34359243Sobrien    Char  **v;
34459243Sobrien    struct command *c;
34559243Sobrien{
346131962Smp#ifdef WINNT_NATIVE
34759243Sobrien    USE(c);
34859243Sobrien    USE(v);
34969408Sache#else /* !WINNT_NATIVE */
350131962Smp    char **p = short2blk(v);
351131962Smp    USE(c);
35259243Sobrien    islogin();
35359243Sobrien    rechist(NULL, adrof(STRsavehist) != NULL);
35459243Sobrien    (void) signal(SIGTERM, parterm);
355131962Smp    (void) execv(_PATH_BIN_LOGIN, p);
356131962Smp    (void) execv(_PATH_USRBIN_LOGIN, p);
357131962Smp    blkfree((Char **) p);
35859243Sobrien    untty();
35959243Sobrien    xexit(1);
36069408Sache#endif /* !WINNT_NATIVE */
36159243Sobrien}
36259243Sobrien
36359243Sobrien
36459243Sobrien#ifdef NEWGRP
36559243Sobrien/*ARGSUSED*/
36659243Sobrienvoid
36759243Sobriendonewgrp(v, c)
36859243Sobrien    Char  **v;
36959243Sobrien    struct command *c;
37059243Sobrien{
37159243Sobrien    char **p;
37259243Sobrien    if (chkstop == 0 && setintr)
37359243Sobrien	panystop(0);
37459243Sobrien    (void) signal(SIGTERM, parterm);
37559243Sobrien    p = short2blk(v);
37659243Sobrien    /*
37759243Sobrien     * From Beto Appleton (beto@aixwiz.austin.ibm.com)
37859243Sobrien     * Newgrp can take 2 arguments...
37959243Sobrien     */
38059243Sobrien    (void) execv(_PATH_BIN_NEWGRP, p);
38159243Sobrien    (void) execv(_PATH_USRBIN_NEWGRP, p);
38259243Sobrien    blkfree((Char **) p);
38359243Sobrien    untty();
38459243Sobrien    xexit(1);
38559243Sobrien}
38659243Sobrien#endif /* NEWGRP */
38759243Sobrien
38859243Sobrienstatic void
38959243Sobrienislogin()
39059243Sobrien{
39159243Sobrien    if (chkstop == 0 && setintr)
39259243Sobrien	panystop(0);
39359243Sobrien    if (loginsh)
39459243Sobrien	return;
39559243Sobrien    stderror(ERR_NOTLOGIN);
39659243Sobrien}
39759243Sobrien
39859243Sobrienvoid
39959243Sobriendoif(v, kp)
40059243Sobrien    Char  **v;
40159243Sobrien    struct command *kp;
40259243Sobrien{
40359243Sobrien    register int i;
40459243Sobrien    register Char **vv;
40559243Sobrien
40659243Sobrien    v++;
40759243Sobrien    i = expr(&v);
40859243Sobrien    vv = v;
40959243Sobrien    if (*vv == NULL)
41059243Sobrien	stderror(ERR_NAME | ERR_EMPTYIF);
41159243Sobrien    if (eq(*vv, STRthen)) {
41259243Sobrien	if (*++vv)
41359243Sobrien	    stderror(ERR_NAME | ERR_IMPRTHEN);
41459243Sobrien	setname(short2str(STRthen));
41559243Sobrien	/*
41659243Sobrien	 * If expression was zero, then scan to else , otherwise just fall into
41759243Sobrien	 * following code.
41859243Sobrien	 */
41959243Sobrien	if (!i)
42059243Sobrien	    search(TC_IF, 0, NULL);
42159243Sobrien	return;
42259243Sobrien    }
42359243Sobrien    /*
42459243Sobrien     * Simple command attached to this if. Left shift the node in this tree,
42559243Sobrien     * munging it so we can reexecute it.
42659243Sobrien     */
42759243Sobrien    if (i) {
42859243Sobrien	lshift(kp->t_dcom, vv - kp->t_dcom);
42959243Sobrien	reexecute(kp);
43059243Sobrien	donefds();
43159243Sobrien    }
43259243Sobrien}
43359243Sobrien
43459243Sobrien/*
43559243Sobrien * Reexecute a command, being careful not
43659243Sobrien * to redo i/o redirection, which is already set up.
43759243Sobrien */
43859243Sobrienvoid
43959243Sobrienreexecute(kp)
44059243Sobrien    register struct command *kp;
44159243Sobrien{
44259243Sobrien    kp->t_dflg &= F_SAVE;
44359243Sobrien    kp->t_dflg |= F_REPEAT;
44459243Sobrien    /*
44559243Sobrien     * If tty is still ours to arbitrate, arbitrate it; otherwise dont even set
44659243Sobrien     * pgrp's as the jobs would then have no way to get the tty (we can't give
44759243Sobrien     * it to them, and our parent wouldn't know their pgrp, etc.
44859243Sobrien     */
449100616Smp    execute(kp, (tpgrp > 0 ? tpgrp : -1), NULL, NULL, TRUE);
45059243Sobrien}
45159243Sobrien
45259243Sobrien/*ARGSUSED*/
45359243Sobrienvoid
45459243Sobriendoelse (v, c)
45559243Sobrien    Char **v;
45659243Sobrien    struct command *c;
45759243Sobrien{
45859243Sobrien    USE(c);
45959243Sobrien    USE(v);
46059243Sobrien    search(TC_ELSE, 0, NULL);
46159243Sobrien}
46259243Sobrien
46359243Sobrien/*ARGSUSED*/
46459243Sobrienvoid
46559243Sobriendogoto(v, c)
46659243Sobrien    Char  **v;
46759243Sobrien    struct command *c;
46859243Sobrien{
46959243Sobrien    Char   *lp;
47059243Sobrien
47159243Sobrien    USE(c);
47259243Sobrien    gotolab(lp = globone(v[1], G_ERROR));
47359243Sobrien    xfree((ptr_t) lp);
47459243Sobrien}
47559243Sobrien
47659243Sobrienvoid
47759243Sobriengotolab(lab)
47859243Sobrien    Char *lab;
47959243Sobrien{
48059243Sobrien    register struct whyle *wp;
48159243Sobrien    /*
48259243Sobrien     * While we still can, locate any unknown ends of existing loops. This
48359243Sobrien     * obscure code is the WORST result of the fact that we don't really parse.
48459243Sobrien     */
48559243Sobrien    zlast = TC_GOTO;
48659243Sobrien    for (wp = whyles; wp; wp = wp->w_next)
48769408Sache	if (wp->w_end.type == TCSH_F_SEEK && wp->w_end.f_seek == 0) {
48859243Sobrien	    search(TC_BREAK, 0, NULL);
48959243Sobrien	    btell(&wp->w_end);
49059243Sobrien	}
49159243Sobrien	else {
49259243Sobrien	    bseek(&wp->w_end);
49359243Sobrien	}
49459243Sobrien    search(TC_GOTO, 0, lab);
49559243Sobrien    /*
49659243Sobrien     * Eliminate loops which were exited.
49759243Sobrien     */
49859243Sobrien    wfree();
49959243Sobrien}
50059243Sobrien
50159243Sobrien/*ARGSUSED*/
50259243Sobrienvoid
50359243Sobriendoswitch(v, c)
50459243Sobrien    register Char **v;
50559243Sobrien    struct command *c;
50659243Sobrien{
50759243Sobrien    register Char *cp, *lp;
50859243Sobrien
50959243Sobrien    USE(c);
51059243Sobrien    v++;
51159243Sobrien    if (!*v || *(*v++) != '(')
51259243Sobrien	stderror(ERR_SYNTAX);
51359243Sobrien    cp = **v == ')' ? STRNULL : *v++;
51459243Sobrien    if (*(*v++) != ')')
51559243Sobrien	v--;
51659243Sobrien    if (*v)
51759243Sobrien	stderror(ERR_SYNTAX);
51859243Sobrien    search(TC_SWITCH, 0, lp = globone(cp, G_ERROR));
51959243Sobrien    xfree((ptr_t) lp);
52059243Sobrien}
52159243Sobrien
52259243Sobrien/*ARGSUSED*/
52359243Sobrienvoid
52459243Sobriendobreak(v, c)
52559243Sobrien    Char **v;
52659243Sobrien    struct command *c;
52759243Sobrien{
52859243Sobrien    USE(v);
52959243Sobrien    USE(c);
53059243Sobrien    if (whyles)
53159243Sobrien	toend();
53259243Sobrien    else
53359243Sobrien	stderror(ERR_NAME | ERR_NOTWHILE);
53459243Sobrien}
53559243Sobrien
53659243Sobrien/*ARGSUSED*/
53759243Sobrienvoid
53859243Sobriendoexit(v, c)
53959243Sobrien    Char  **v;
54059243Sobrien    struct command *c;
54159243Sobrien{
54259243Sobrien    USE(c);
54359243Sobrien
54459243Sobrien    if (chkstop == 0 && (intty || intact) && evalvec == 0)
54559243Sobrien	panystop(0);
54659243Sobrien    /*
54759243Sobrien     * Don't DEMAND parentheses here either.
54859243Sobrien     */
54959243Sobrien    v++;
55059243Sobrien    if (*v) {
55159243Sobrien	set(STRstatus, putn(expr(&v)), VAR_READWRITE);
55259243Sobrien	if (*v)
55359243Sobrien	    stderror(ERR_NAME | ERR_EXPRESSION);
55459243Sobrien    }
55559243Sobrien    btoeof();
55659243Sobrien#if 0
55759243Sobrien    if (intty)
55859243Sobrien#endif
55959243Sobrien    /* Always close, why only on ttys? */
56059243Sobrien	(void) close(SHIN);
56159243Sobrien}
56259243Sobrien
56359243Sobrien/*ARGSUSED*/
56459243Sobrienvoid
56559243Sobriendoforeach(v, c)
56659243Sobrien    register Char **v;
56759243Sobrien    struct command *c;
56859243Sobrien{
56959243Sobrien    register Char *cp, *sp;
57059243Sobrien    register struct whyle *nwp;
57159243Sobrien
57259243Sobrien    USE(c);
57359243Sobrien    v++;
57459243Sobrien    sp = cp = strip(*v);
57559243Sobrien    if (!letter(*sp))
57659243Sobrien	stderror(ERR_NAME | ERR_VARBEGIN);
57759243Sobrien    while (*cp && alnum(*cp))
57859243Sobrien	cp++;
57959243Sobrien    if (*cp)
58059243Sobrien	stderror(ERR_NAME | ERR_VARALNUM);
58159243Sobrien    if ((cp - sp) > MAXVARLEN)
58259243Sobrien	stderror(ERR_NAME | ERR_VARTOOLONG);
58359243Sobrien    cp = *v++;
58459243Sobrien    if (v[0][0] != '(' || v[blklen(v) - 1][0] != ')')
58559243Sobrien	stderror(ERR_NAME | ERR_NOPAREN);
58659243Sobrien    v++;
58759243Sobrien    gflag = 0, tglob(v);
58859243Sobrien    if (gflag) {
58959243Sobrien	v = globall(v);
59059243Sobrien	if (v == 0)
59159243Sobrien	    stderror(ERR_NAME | ERR_NOMATCH);
59259243Sobrien    }
59359243Sobrien    else {
59459243Sobrien	v = gargv = saveblk(v);
59559243Sobrien	trim(v);
59659243Sobrien    }
59759243Sobrien    nwp = (struct whyle *) xcalloc(1, sizeof *nwp);
59859243Sobrien    nwp->w_fe = nwp->w_fe0 = v;
59959243Sobrien    gargv = 0;
60059243Sobrien    btell(&nwp->w_start);
60159243Sobrien    nwp->w_fename = Strsave(cp);
60259243Sobrien    nwp->w_next = whyles;
60369408Sache    nwp->w_end.type = TCSH_F_SEEK;
60459243Sobrien    whyles = nwp;
60559243Sobrien    /*
60659243Sobrien     * Pre-read the loop so as to be more comprehensible to a terminal user.
60759243Sobrien     */
60859243Sobrien    zlast = TC_FOREACH;
60959243Sobrien    if (intty)
61059243Sobrien	preread();
61159243Sobrien    doagain();
61259243Sobrien}
61359243Sobrien
61459243Sobrien/*ARGSUSED*/
61559243Sobrienvoid
61659243Sobriendowhile(v, c)
61759243Sobrien    Char  **v;
61859243Sobrien    struct command *c;
61959243Sobrien{
62059243Sobrien    register int status;
62159243Sobrien    register bool again = whyles != 0 &&
62259243Sobrien			  SEEKEQ(&whyles->w_start, &lineloc) &&
62359243Sobrien			  whyles->w_fename == 0;
62459243Sobrien
62559243Sobrien    USE(c);
62659243Sobrien    v++;
62759243Sobrien    /*
62859243Sobrien     * Implement prereading here also, taking care not to evaluate the
62959243Sobrien     * expression before the loop has been read up from a terminal.
63059243Sobrien     */
63159243Sobrien    if (intty && !again)
63259243Sobrien	status = !exp0(&v, 1);
63359243Sobrien    else
63459243Sobrien	status = !expr(&v);
63559243Sobrien    if (*v)
63659243Sobrien	stderror(ERR_NAME | ERR_EXPRESSION);
63759243Sobrien    if (!again) {
63859243Sobrien	register struct whyle *nwp =
63959243Sobrien	(struct whyle *) xcalloc(1, sizeof(*nwp));
64059243Sobrien
64159243Sobrien	nwp->w_start = lineloc;
64269408Sache	nwp->w_end.type = TCSH_F_SEEK;
64359243Sobrien	nwp->w_end.f_seek = 0;
64459243Sobrien	nwp->w_next = whyles;
64559243Sobrien	whyles = nwp;
64659243Sobrien	zlast = TC_WHILE;
64759243Sobrien	if (intty) {
64859243Sobrien	    /*
64959243Sobrien	     * The tty preread
65059243Sobrien	     */
65159243Sobrien	    preread();
65259243Sobrien	    doagain();
65359243Sobrien	    return;
65459243Sobrien	}
65559243Sobrien    }
65659243Sobrien    if (status)
65759243Sobrien	/* We ain't gonna loop no more, no more! */
65859243Sobrien	toend();
65959243Sobrien}
66059243Sobrien
66159243Sobrienstatic void
66259243Sobrienpreread()
66359243Sobrien{
66469408Sache    whyles->w_end.type = TCSH_I_SEEK;
66559243Sobrien    if (setintr)
66659243Sobrien#ifdef BSDSIGS
66759243Sobrien	(void) sigsetmask(sigblock((sigmask_t) 0) & ~sigmask(SIGINT));
66859243Sobrien#else /* !BSDSIGS */
66959243Sobrien	(void) sigrelse (SIGINT);
67059243Sobrien#endif /* BSDSIGS */
67159243Sobrien    search(TC_BREAK, 0, NULL);		/* read the expression in */
67259243Sobrien    if (setintr)
67359243Sobrien#ifdef BSDSIGS
67459243Sobrien	(void) sigblock(sigmask(SIGINT));
67559243Sobrien#else /* !BSDSIGS */
67659243Sobrien	(void) sighold(SIGINT);
67759243Sobrien#endif /* BSDSIGS */
67859243Sobrien    btell(&whyles->w_end);
67959243Sobrien}
68059243Sobrien
68159243Sobrien/*ARGSUSED*/
68259243Sobrienvoid
68359243Sobriendoend(v, c)
68459243Sobrien    Char **v;
68559243Sobrien    struct command *c;
68659243Sobrien{
68759243Sobrien    USE(v);
68859243Sobrien    USE(c);
68959243Sobrien    if (!whyles)
69059243Sobrien	stderror(ERR_NAME | ERR_NOTWHILE);
69159243Sobrien    btell(&whyles->w_end);
69259243Sobrien    doagain();
69359243Sobrien}
69459243Sobrien
69559243Sobrien/*ARGSUSED*/
69659243Sobrienvoid
69759243Sobriendocontin(v, c)
69859243Sobrien    Char **v;
69959243Sobrien    struct command *c;
70059243Sobrien{
70159243Sobrien    USE(v);
70259243Sobrien    USE(c);
70359243Sobrien    if (!whyles)
70459243Sobrien	stderror(ERR_NAME | ERR_NOTWHILE);
70559243Sobrien    doagain();
70659243Sobrien}
70759243Sobrien
70859243Sobrienstatic void
70959243Sobriendoagain()
71059243Sobrien{
71159243Sobrien    /* Repeating a while is simple */
71259243Sobrien    if (whyles->w_fename == 0) {
71359243Sobrien	bseek(&whyles->w_start);
71459243Sobrien	return;
71559243Sobrien    }
71659243Sobrien    /*
71759243Sobrien     * The foreach variable list actually has a spurious word ")" at the end of
71859243Sobrien     * the w_fe list.  Thus we are at the of the list if one word beyond this
71959243Sobrien     * is 0.
72059243Sobrien     */
72159243Sobrien    if (!whyles->w_fe[1]) {
72259243Sobrien	dobreak(NULL, NULL);
72359243Sobrien	return;
72459243Sobrien    }
72559243Sobrien    set(whyles->w_fename, quote(Strsave(*whyles->w_fe++)), VAR_READWRITE);
72659243Sobrien    bseek(&whyles->w_start);
72759243Sobrien}
72859243Sobrien
72959243Sobrienvoid
73059243Sobriendorepeat(v, kp)
73159243Sobrien    Char  **v;
73259243Sobrien    struct command *kp;
73359243Sobrien{
734100616Smp    int i = 1;
73559243Sobrien
73659243Sobrien#ifdef BSDSIGS
73759243Sobrien    register sigmask_t omask = 0;
73859243Sobrien#endif /* BSDSIGS */
73959243Sobrien
740100616Smp    do {
741100616Smp	i *= getn(v[1]);
742100616Smp	lshift(v, 2);
743100616Smp    } while (v[0] != NULL && Strcmp(v[0], STRrepeat) == 0);
744100616Smp
74559243Sobrien    if (setintr)
74659243Sobrien#ifdef BSDSIGS
74759243Sobrien	omask = sigblock(sigmask(SIGINT)) & ~sigmask(SIGINT);
74859243Sobrien#else /* !BSDSIGS */
74959243Sobrien	(void) sighold(SIGINT);
75059243Sobrien#endif /* BSDSIGS */
75159243Sobrien    while (i > 0) {
75259243Sobrien	if (setintr)
75359243Sobrien#ifdef BSDSIGS
75459243Sobrien	    (void) sigsetmask(omask);
75559243Sobrien#else /* !BSDSIGS */
75659243Sobrien	    (void) sigrelse (SIGINT);
75759243Sobrien#endif /* BSDSIGS */
75859243Sobrien	reexecute(kp);
75959243Sobrien	--i;
76059243Sobrien    }
76159243Sobrien    donefds();
76259243Sobrien    if (setintr)
76359243Sobrien#ifdef BSDSIGS
76459243Sobrien	(void) sigsetmask(omask);
76559243Sobrien#else /* !BSDSIGS */
76659243Sobrien	(void) sigrelse (SIGINT);
76759243Sobrien#endif /* BSDSIGS */
76859243Sobrien}
76959243Sobrien
77059243Sobrien/*ARGSUSED*/
77159243Sobrienvoid
77259243Sobriendoswbrk(v, c)
77359243Sobrien    Char **v;
77459243Sobrien    struct command *c;
77559243Sobrien{
77659243Sobrien    USE(v);
77759243Sobrien    USE(c);
77859243Sobrien    search(TC_BRKSW, 0, NULL);
77959243Sobrien}
78059243Sobrien
78159243Sobrienint
78259243Sobriensrchx(cp)
78359243Sobrien    Char *cp;
78459243Sobrien{
78559243Sobrien    struct srch *sp, *sp1, *sp2;
78659243Sobrien    int i;
78759243Sobrien
78859243Sobrien    /*
78959243Sobrien     * Ignore keywords inside heredocs
79059243Sobrien     */
79159243Sobrien    if (inheredoc)
79259243Sobrien	return -1;
79359243Sobrien
79459243Sobrien    /*
79559243Sobrien     * Binary search Sp1 is the beginning of the current search range. Sp2 is
79659243Sobrien     * one past the end.
79759243Sobrien     */
79859243Sobrien    for (sp1 = srchn, sp2 = srchn + nsrchn; sp1 < sp2;) {
79959243Sobrien	sp = sp1 + ((sp2 - sp1) >> 1);
80059243Sobrien	if ((i = *cp - *sp->s_name) == 0 &&
80159243Sobrien	    (i = Strcmp(cp, str2short(sp->s_name))) == 0)
80259243Sobrien	    return sp->s_value;
80359243Sobrien	if (i < 0)
80459243Sobrien	    sp2 = sp;
80559243Sobrien	else
80659243Sobrien	    sp1 = sp + 1;
80759243Sobrien    }
80859243Sobrien    return (-1);
80959243Sobrien}
81059243Sobrien
81159243Sobrienstatic char *
81259243Sobrienisrchx(n)
81359243Sobrien    register int n;
81459243Sobrien{
81559243Sobrien    register struct srch *sp, *sp2;
81659243Sobrien
81759243Sobrien    for (sp = srchn, sp2 = srchn + nsrchn; sp < sp2; sp++)
81859243Sobrien	if (sp->s_value == n)
81959243Sobrien	    return (sp->s_name);
82059243Sobrien    return ("");
82159243Sobrien}
82259243Sobrien
82359243Sobrien
82459243Sobrienstatic Char Stype;
82559243Sobrienstatic Char *Sgoal;
82659243Sobrien
82759243Sobrienstatic void
82859243Sobriensearch(type, level, goal)
82959243Sobrien    int     type;
83059243Sobrien    register int level;
83159243Sobrien    Char   *goal;
83259243Sobrien{
83359243Sobrien    Char    wordbuf[BUFSIZE];
83459243Sobrien    register Char *aword = wordbuf;
83559243Sobrien    register Char *cp;
836131962Smp    struct whyle *wp;
837131962Smp    int wlevel = 0;
83859243Sobrien
83959243Sobrien    Stype = (Char) type;
84059243Sobrien    Sgoal = goal;
84159243Sobrien    if (type == TC_GOTO) {
84259243Sobrien	struct Ain a;
84369408Sache	a.type = TCSH_F_SEEK;
84459243Sobrien	a.f_seek = 0;
84559243Sobrien	bseek(&a);
84659243Sobrien    }
84759243Sobrien    do {
84869408Sache	if (intty && fseekp == feobp && aret == TCSH_F_SEEK)
84959243Sobrien	    printprompt(1, isrchx(type == TC_BREAK ? zlast : type));
85059243Sobrien	/* xprintf("? "), flush(); */
85159243Sobrien	aword[0] = 0;
85259243Sobrien	(void) getword(aword);
85359243Sobrien	switch (srchx(aword)) {
85459243Sobrien
85559243Sobrien	case TC_ELSE:
85659243Sobrien	    if (level == 0 && type == TC_IF)
85759243Sobrien		return;
85859243Sobrien	    break;
85959243Sobrien
86059243Sobrien	case TC_IF:
86159243Sobrien	    while (getword(aword))
86259243Sobrien		continue;
86359243Sobrien	    if ((type == TC_IF || type == TC_ELSE) &&
86459243Sobrien		eq(aword, STRthen))
86559243Sobrien		level++;
86659243Sobrien	    break;
86759243Sobrien
86859243Sobrien	case TC_ENDIF:
86959243Sobrien	    if (type == TC_IF || type == TC_ELSE)
87059243Sobrien		level--;
87159243Sobrien	    break;
87259243Sobrien
87359243Sobrien	case TC_FOREACH:
87459243Sobrien	case TC_WHILE:
875131962Smp	    wlevel++;
87659243Sobrien	    if (type == TC_BREAK)
87759243Sobrien		level++;
87859243Sobrien	    break;
87959243Sobrien
88059243Sobrien	case TC_END:
881131962Smp	    if (type == TC_BRKSW) {
882131962Smp		if (wlevel == 0) {
883131962Smp		    wp = whyles;
884131962Smp		    if (wp) {
885131962Smp			    whyles = wp->w_next;
886131962Smp			    wpfree(wp);
887131962Smp		    }
888131962Smp		}
889131962Smp	    }
89059243Sobrien	    if (type == TC_BREAK)
89159243Sobrien		level--;
892131962Smp	    wlevel--;
89359243Sobrien	    break;
89459243Sobrien
89559243Sobrien	case TC_SWITCH:
89659243Sobrien	    if (type == TC_SWITCH || type == TC_BRKSW)
89759243Sobrien		level++;
89859243Sobrien	    break;
89959243Sobrien
90059243Sobrien	case TC_ENDSW:
90159243Sobrien	    if (type == TC_SWITCH || type == TC_BRKSW)
90259243Sobrien		level--;
90359243Sobrien	    break;
90459243Sobrien
90559243Sobrien	case TC_LABEL:
90659243Sobrien	    if (type == TC_GOTO && getword(aword) && eq(aword, goal))
90759243Sobrien		level = -1;
90859243Sobrien	    break;
90959243Sobrien
91059243Sobrien	default:
91159243Sobrien	    if (type != TC_GOTO && (type != TC_SWITCH || level != 0))
91259243Sobrien		break;
91359243Sobrien	    if (lastchr(aword) != ':')
91459243Sobrien		break;
91559243Sobrien	    aword[Strlen(aword) - 1] = 0;
91659243Sobrien	    if ((type == TC_GOTO && eq(aword, goal)) ||
91759243Sobrien		(type == TC_SWITCH && eq(aword, STRdefault)))
91859243Sobrien		level = -1;
91959243Sobrien	    break;
92059243Sobrien
92159243Sobrien	case TC_CASE:
92259243Sobrien	    if (type != TC_SWITCH || level != 0)
92359243Sobrien		break;
92459243Sobrien	    (void) getword(aword);
92559243Sobrien	    if (lastchr(aword) == ':')
92659243Sobrien		aword[Strlen(aword) - 1] = 0;
92759243Sobrien	    cp = strip(Dfix1(aword));
92859243Sobrien	    if (Gmatch(goal, cp))
92959243Sobrien		level = -1;
93059243Sobrien	    xfree((ptr_t) cp);
93159243Sobrien	    break;
93259243Sobrien
93359243Sobrien	case TC_DEFAULT:
93459243Sobrien	    if (type == TC_SWITCH && level == 0)
93559243Sobrien		level = -1;
93659243Sobrien	    break;
93759243Sobrien	}
93859243Sobrien	(void) getword(NULL);
93959243Sobrien    } while (level >= 0);
94059243Sobrien}
94159243Sobrien
94259243Sobrienstatic int
94359243Sobriengetword(wp)
94459243Sobrien    register Char *wp;
94559243Sobrien{
94659243Sobrien    int found = 0, first;
94759243Sobrien    int c, d;
94859243Sobrien
94959243Sobrien    c = readc(1);
95059243Sobrien    d = 0;
95159243Sobrien    do {
95259243Sobrien	while (c == ' ' || c == '\t')
95359243Sobrien	    c = readc(1);
95459243Sobrien	if (c == '#')
95559243Sobrien	    do
95659243Sobrien		c = readc(1);
95759243Sobrien	    while (c >= 0 && c != '\n');
95859243Sobrien	if (c < 0)
95959243Sobrien	    goto past;
96059243Sobrien	if (c == '\n') {
96159243Sobrien	    if (wp)
96259243Sobrien		break;
96359243Sobrien	    return (0);
96459243Sobrien	}
96559243Sobrien	unreadc(c);
96659243Sobrien	found = 1;
96759243Sobrien	first = 1;
96859243Sobrien	do {
96959243Sobrien	    c = readc(1);
97059243Sobrien	    if (c == '\\' && (c = readc(1)) == '\n')
97159243Sobrien		c = ' ';
97259243Sobrien	    if (c == '\'' || c == '"') {
97359243Sobrien		if (d == 0)
97459243Sobrien		    d = c;
97559243Sobrien		else if (d == c)
97659243Sobrien		    d = 0;
97759243Sobrien	    }
97859243Sobrien	    if (c < 0)
97959243Sobrien		goto past;
98059243Sobrien	    if (wp) {
98159243Sobrien		*wp++ = (Char) c;
98259243Sobrien		*wp = '\0';
98359243Sobrien	    }
98459243Sobrien	    if (!first && !d && c == '(') {
98559243Sobrien		if (wp) {
98659243Sobrien		    unreadc(c);
98759243Sobrien		    *--wp = '\0';
98859243Sobrien		    return found;
98959243Sobrien		}
99059243Sobrien		else
99159243Sobrien		    break;
99259243Sobrien	    }
99359243Sobrien	    first = 0;
99459243Sobrien	} while ((d || (c != ' ' && c != '\t')) && c != '\n');
99559243Sobrien    } while (wp == 0);
99659243Sobrien
99759243Sobrien    unreadc(c);
99859243Sobrien    if (found)
99959243Sobrien	*--wp = '\0';
100059243Sobrien
100159243Sobrien    return (found);
100259243Sobrien
100359243Sobrienpast:
100459243Sobrien    switch (Stype) {
100559243Sobrien
100659243Sobrien    case TC_IF:
100759243Sobrien	stderror(ERR_NAME | ERR_NOTFOUND, "then/endif");
100859243Sobrien	break;
100959243Sobrien
101059243Sobrien    case TC_ELSE:
101159243Sobrien	stderror(ERR_NAME | ERR_NOTFOUND, "endif");
101259243Sobrien	break;
101359243Sobrien
101459243Sobrien    case TC_BRKSW:
101559243Sobrien    case TC_SWITCH:
101659243Sobrien	stderror(ERR_NAME | ERR_NOTFOUND, "endsw");
101759243Sobrien	break;
101859243Sobrien
101959243Sobrien    case TC_BREAK:
102059243Sobrien	stderror(ERR_NAME | ERR_NOTFOUND, "end");
102159243Sobrien	break;
102259243Sobrien
102359243Sobrien    case TC_GOTO:
102459243Sobrien	setname(short2str(Sgoal));
102559243Sobrien	stderror(ERR_NAME | ERR_NOTFOUND, "label");
102659243Sobrien	break;
102759243Sobrien
102859243Sobrien    default:
102959243Sobrien	break;
103059243Sobrien    }
103159243Sobrien    /* NOTREACHED */
103259243Sobrien    return (0);
103359243Sobrien}
103459243Sobrien
103559243Sobrienstatic void
103659243Sobrientoend()
103759243Sobrien{
103869408Sache    if (whyles->w_end.type == TCSH_F_SEEK && whyles->w_end.f_seek == 0) {
103959243Sobrien	search(TC_BREAK, 0, NULL);
104059243Sobrien	btell(&whyles->w_end);
104159243Sobrien	whyles->w_end.f_seek--;
104259243Sobrien    }
104359243Sobrien    else {
104459243Sobrien	bseek(&whyles->w_end);
104559243Sobrien    }
104659243Sobrien    wfree();
104759243Sobrien}
104859243Sobrien
1049131962Smpstatic void
1050131962Smpwpfree(wp)
1051131962Smp    struct whyle *wp;
1052131962Smp{
1053131962Smp	if (wp->w_fe0)
1054131962Smp	    blkfree(wp->w_fe0);
1055131962Smp	if (wp->w_fename)
1056131962Smp	    xfree((ptr_t) wp->w_fename);
1057131962Smp	xfree((ptr_t) wp);
1058131962Smp}
1059131962Smp
106059243Sobrienvoid
106159243Sobrienwfree()
106259243Sobrien{
106359243Sobrien    struct Ain    o;
106459243Sobrien    struct whyle *nwp;
106559243Sobrien#ifdef lint
106659243Sobrien    nwp = NULL;	/* sun lint is dumb! */
106759243Sobrien#endif
106859243Sobrien
106959243Sobrien#ifdef FDEBUG
107059243Sobrien    static char foo[] = "IAFE";
107159243Sobrien#endif /* FDEBUG */
107259243Sobrien
107359243Sobrien    btell(&o);
107459243Sobrien
107559243Sobrien#ifdef FDEBUG
107659243Sobrien    xprintf("o->type %c o->a_seek %d o->f_seek %d\n",
107759243Sobrien	    foo[o.type + 1], o.a_seek, o.f_seek);
107859243Sobrien#endif /* FDEBUG */
107959243Sobrien
108059243Sobrien    for (; whyles; whyles = nwp) {
108159243Sobrien	register struct whyle *wp = whyles;
108259243Sobrien	nwp = wp->w_next;
108359243Sobrien
108459243Sobrien#ifdef FDEBUG
108559243Sobrien	xprintf("start->type %c start->a_seek %d start->f_seek %d\n",
108659243Sobrien		foo[wp->w_start.type+1],
108759243Sobrien		wp->w_start.a_seek, wp->w_start.f_seek);
108859243Sobrien	xprintf("end->type %c end->a_seek %d end->f_seek %d\n",
108959243Sobrien		foo[wp->w_end.type + 1], wp->w_end.a_seek, wp->w_end.f_seek);
109059243Sobrien#endif /* FDEBUG */
109159243Sobrien
109259243Sobrien	/*
109359243Sobrien	 * XXX: We free loops that have different seek types.
109459243Sobrien	 */
109569408Sache	if (wp->w_end.type != TCSH_I_SEEK && wp->w_start.type == wp->w_end.type &&
109659243Sobrien	    wp->w_start.type == o.type) {
109769408Sache	    if (wp->w_end.type == TCSH_F_SEEK) {
109859243Sobrien		if (o.f_seek >= wp->w_start.f_seek &&
109959243Sobrien		    (wp->w_end.f_seek == 0 || o.f_seek < wp->w_end.f_seek))
110059243Sobrien		    break;
110159243Sobrien	    }
110259243Sobrien	    else {
110359243Sobrien		if (o.a_seek >= wp->w_start.a_seek &&
110459243Sobrien		    (wp->w_end.a_seek == 0 || o.a_seek < wp->w_end.a_seek))
110559243Sobrien		    break;
110659243Sobrien	    }
110759243Sobrien	}
110859243Sobrien
1109131962Smp	wpfree(wp);
111059243Sobrien    }
111159243Sobrien}
111259243Sobrien
111359243Sobrien/*ARGSUSED*/
111459243Sobrienvoid
111559243Sobriendoecho(v, c)
111659243Sobrien    Char  **v;
111759243Sobrien    struct command *c;
111859243Sobrien{
111959243Sobrien    USE(c);
112059243Sobrien    xecho(' ', v);
112159243Sobrien}
112259243Sobrien
112359243Sobrien/*ARGSUSED*/
112459243Sobrienvoid
112559243Sobriendoglob(v, c)
112659243Sobrien    Char  **v;
112759243Sobrien    struct command *c;
112859243Sobrien{
112959243Sobrien    USE(c);
113059243Sobrien    xecho(0, v);
113159243Sobrien    flush();
113259243Sobrien}
113359243Sobrien
113459243Sobrienstatic void
113559243Sobrienxecho(sep, v)
113659243Sobrien    int    sep;
113759243Sobrien    register Char **v;
113859243Sobrien{
113959243Sobrien    register Char *cp;
114059243Sobrien    int     nonl = 0;
114159243Sobrien#ifdef ECHO_STYLE
114259243Sobrien    int	    echo_style = ECHO_STYLE;
114359243Sobrien#else /* !ECHO_STYLE */
114459243Sobrien# if SYSVREL > 0
114559243Sobrien    int	    echo_style = SYSV_ECHO;
114659243Sobrien# else /* SYSVREL == 0 */
114759243Sobrien    int	    echo_style = BSD_ECHO;
114859243Sobrien# endif /* SYSVREL */
114959243Sobrien#endif /* ECHO_STYLE */
115059243Sobrien    struct varent *vp;
115159243Sobrien
115259243Sobrien    if ((vp = adrof(STRecho_style)) != NULL && vp->vec != NULL &&
115359243Sobrien	vp->vec[0] != NULL) {
115459243Sobrien	if (Strcmp(vp->vec[0], STRbsd) == 0)
115559243Sobrien	    echo_style = BSD_ECHO;
115659243Sobrien	else if (Strcmp(vp->vec[0], STRsysv) == 0)
115759243Sobrien	    echo_style = SYSV_ECHO;
115859243Sobrien	else if (Strcmp(vp->vec[0], STRboth) == 0)
115959243Sobrien	    echo_style = BOTH_ECHO;
116059243Sobrien	else if (Strcmp(vp->vec[0], STRnone) == 0)
116159243Sobrien	    echo_style = NONE_ECHO;
116259243Sobrien    }
116359243Sobrien
116459243Sobrien    if (setintr)
116559243Sobrien#ifdef BSDSIGS
116659243Sobrien	(void) sigsetmask(sigblock((sigmask_t) 0) & ~sigmask(SIGINT));
116759243Sobrien#else /* !BSDSIGS */
116859243Sobrien	(void) sigrelse (SIGINT);
116959243Sobrien#endif /* BSDSIGS */
117059243Sobrien    v++;
117159243Sobrien    if (*v == 0)
117283098Smp	goto done;
117359243Sobrien    gflag = 0, tglob(v);
117459243Sobrien    if (gflag) {
117559243Sobrien	v = globall(v);
117659243Sobrien	if (v == 0)
117759243Sobrien	    stderror(ERR_NAME | ERR_NOMATCH);
117859243Sobrien    }
117959243Sobrien    else {
118059243Sobrien	v = gargv = saveblk(v);
118159243Sobrien	trim(v);
118259243Sobrien    }
118359243Sobrien
118459243Sobrien    if ((echo_style & BSD_ECHO) != 0 && sep == ' ' && *v && eq(*v, STRmn))
118559243Sobrien	nonl++, v++;
118659243Sobrien
118759243Sobrien    while ((cp = *v++) != 0) {
118859243Sobrien	register int c;
118959243Sobrien
119059243Sobrien	while ((c = *cp++) != 0) {
119159243Sobrien	    if ((echo_style & SYSV_ECHO) != 0 && c == '\\') {
119259243Sobrien		switch (c = *cp++) {
119359243Sobrien		case 'a':
119459243Sobrien		    c = '\a';
119559243Sobrien		    break;
119659243Sobrien		case 'b':
119759243Sobrien		    c = '\b';
119859243Sobrien		    break;
119959243Sobrien		case 'c':
120059243Sobrien		    nonl = 1;
120159243Sobrien		    goto done;
120259243Sobrien		case 'e':
120359243Sobrien#if 0			/* Windows does not understand \e */
120459243Sobrien		    c = '\e';
120559243Sobrien#else
120659243Sobrien		    c = '\033';
120759243Sobrien#endif
120859243Sobrien		    break;
120959243Sobrien		case 'f':
121059243Sobrien		    c = '\f';
121159243Sobrien		    break;
121259243Sobrien		case 'n':
121359243Sobrien		    c = '\n';
121459243Sobrien		    break;
121559243Sobrien		case 'r':
121659243Sobrien		    c = '\r';
121759243Sobrien		    break;
121859243Sobrien		case 't':
121959243Sobrien		    c = '\t';
122059243Sobrien		    break;
122159243Sobrien		case 'v':
122259243Sobrien		    c = '\v';
122359243Sobrien		    break;
122459243Sobrien		case '\\':
122559243Sobrien		    c = '\\';
122659243Sobrien		    break;
122759243Sobrien		case '0':
122859243Sobrien		    c = 0;
122959243Sobrien		    if (*cp >= '0' && *cp < '8')
123059243Sobrien			c = c * 8 + *cp++ - '0';
123159243Sobrien		    if (*cp >= '0' && *cp < '8')
123259243Sobrien			c = c * 8 + *cp++ - '0';
123359243Sobrien		    if (*cp >= '0' && *cp < '8')
123459243Sobrien			c = c * 8 + *cp++ - '0';
123559243Sobrien		    break;
123659243Sobrien		case '\0':
123759243Sobrien		    c = '\\';
123859243Sobrien		    cp--;
123959243Sobrien		    break;
124059243Sobrien		default:
124159243Sobrien		    xputchar('\\' | QUOTE);
124259243Sobrien		    break;
124359243Sobrien		}
124459243Sobrien	    }
124559243Sobrien	    xputchar(c | QUOTE);
124659243Sobrien
124759243Sobrien	}
124859243Sobrien	if (*v)
124959243Sobrien	    xputchar(sep | QUOTE);
125059243Sobrien    }
125159243Sobriendone:
125259243Sobrien    if (sep && nonl == 0)
125359243Sobrien	xputchar('\n');
125459243Sobrien    else
125559243Sobrien	flush();
125659243Sobrien    if (setintr)
125759243Sobrien#ifdef BSDSIGS
125859243Sobrien	(void) sigblock(sigmask(SIGINT));
125959243Sobrien#else /* !BSDSIGS */
126059243Sobrien	(void) sighold(SIGINT);
126159243Sobrien#endif /* BSDSIGS */
126259243Sobrien    if (gargv)
126359243Sobrien	blkfree(gargv), gargv = 0;
126459243Sobrien}
126559243Sobrien
126659243Sobrien/* check whether an environment variable should invoke 'set_locale()' */
126759243Sobrienstatic bool
126859243Sobrienislocale_var(var)
126959243Sobrien    Char *var;
127059243Sobrien{
127159243Sobrien    static Char *locale_vars[] = {
1272131962Smp	STRLANG,	STRLC_ALL, 	STRLC_CTYPE,	STRLC_NUMERIC,
1273131962Smp	STRLC_TIME,	STRLC_COLLATE,	STRLC_MESSAGES,	STRLC_MONETARY, 0
127459243Sobrien    };
127559243Sobrien    register Char **v;
127659243Sobrien
127759243Sobrien    for (v = locale_vars; *v; ++v)
127859243Sobrien	if (eq(var, *v))
127959243Sobrien	    return 1;
128059243Sobrien    return 0;
128159243Sobrien}
128259243Sobrien
128359243Sobrien/*ARGSUSED*/
128459243Sobrienvoid
128559243Sobriendoprintenv(v, c)
128659243Sobrien    register Char **v;
128759243Sobrien    struct command *c;
128859243Sobrien{
128959243Sobrien    Char   *e;
129059243Sobrien    extern bool output_raw;
129159243Sobrien    extern bool xlate_cr;
129259243Sobrien
129359243Sobrien    USE(c);
129459243Sobrien    if (setintr)
129559243Sobrien#ifdef BSDSIGS
129659243Sobrien	(void) sigsetmask(sigblock((sigmask_t) 0) & ~sigmask(SIGINT));
129759243Sobrien#else /* !BSDSIGS */
129859243Sobrien	(void) sigrelse (SIGINT);
129959243Sobrien#endif /* BSDSIGS */
130059243Sobrien
130159243Sobrien    v++;
130259243Sobrien    if (*v == 0) {
130359243Sobrien	register Char **ep;
130459243Sobrien
130559243Sobrien	xlate_cr = 1;
130659243Sobrien	for (ep = STR_environ; *ep; ep++)
130759243Sobrien	    xprintf("%S\n", *ep);
130859243Sobrien	xlate_cr = 0;
130959243Sobrien    }
131059243Sobrien    else if ((e = tgetenv(*v)) != NULL) {
131159243Sobrien	output_raw = 1;
131259243Sobrien	xprintf("%S\n", e);
131359243Sobrien	output_raw = 0;
131459243Sobrien    }
131559243Sobrien    else
131659243Sobrien	set(STRstatus, Strsave(STR1), VAR_READWRITE);
131759243Sobrien}
131859243Sobrien
131959243Sobrien/* from "Karl Berry." <karl%mote.umb.edu@relay.cs.net> -- for NeXT things
132059243Sobrien   (and anything else with a modern compiler) */
132159243Sobrien
132259243Sobrien/*ARGSUSED*/
132359243Sobrienvoid
132459243Sobriendosetenv(v, c)
132559243Sobrien    register Char **v;
132659243Sobrien    struct command *c;
132759243Sobrien{
132859243Sobrien    Char   *vp, *lp;
132959243Sobrien
133059243Sobrien    USE(c);
133159243Sobrien    if (*++v == 0) {
133259243Sobrien	doprintenv(--v, 0);
133359243Sobrien	return;
133459243Sobrien    }
133559243Sobrien
133659243Sobrien    vp = *v++;
133759243Sobrien
1338100616Smp    lp = vp;
1339100616Smp
1340131962Smp    for (; *lp != '\0' ; lp++) {
1341131962Smp	if (*lp == '=')
1342131962Smp	    stderror(ERR_NAME | ERR_SYNTAX);
1343131962Smp    }
134459243Sobrien    if ((lp = *v++) == 0)
134559243Sobrien	lp = STRNULL;
134659243Sobrien
134759243Sobrien    tsetenv(vp, lp = globone(lp, G_APPEND));
134859243Sobrien    if (eq(vp, STRKPATH)) {
134959243Sobrien	importpath(lp);
135059243Sobrien	dohash(NULL, NULL);
135159243Sobrien	xfree((ptr_t) lp);
135259243Sobrien	return;
135359243Sobrien    }
135459243Sobrien
135559243Sobrien#ifdef apollo
135659243Sobrien    if (eq(vp, STRSYSTYPE)) {
135759243Sobrien	dohash(NULL, NULL);
135859243Sobrien	xfree((ptr_t) lp);
135959243Sobrien	return;
136059243Sobrien    }
136159243Sobrien#endif /* apollo */
136259243Sobrien
136359243Sobrien    /* dspkanji/dspmbyte autosetting */
136459243Sobrien    /* PATCH IDEA FROM Issei.Suzuki VERY THANKS */
136559243Sobrien#if defined(DSPMBYTE)
136659243Sobrien    if(eq(vp, STRLANG) && !adrof(CHECK_MBYTEVAR)) {
136759243Sobrien	autoset_dspmbyte(lp);
136859243Sobrien    }
136959243Sobrien#endif
137059243Sobrien
137159243Sobrien    if (islocale_var(vp)) {
137259243Sobrien#ifdef NLS
137359243Sobrien	int     k;
137459243Sobrien
137559243Sobrien# ifdef SETLOCALEBUG
137659243Sobrien	dont_free = 1;
137759243Sobrien# endif /* SETLOCALEBUG */
137859243Sobrien	(void) setlocale(LC_ALL, "");
137959243Sobrien# ifdef LC_COLLATE
138059243Sobrien	(void) setlocale(LC_COLLATE, "");
138159243Sobrien# endif
138259243Sobrien# ifdef NLS_CATALOGS
138359243Sobrien#  ifdef LC_MESSAGES
138459243Sobrien	(void) setlocale(LC_MESSAGES, "");
138559243Sobrien#  endif /* LC_MESSAGES */
138659243Sobrien	(void) catclose(catd);
138759243Sobrien	nlsinit();
138859243Sobrien# endif /* NLS_CATALOGS */
138959243Sobrien# ifdef LC_CTYPE
139059243Sobrien	(void) setlocale(LC_CTYPE, ""); /* for iscntrl */
139159243Sobrien# endif /* LC_CTYPE */
139259243Sobrien# ifdef SETLOCALEBUG
139359243Sobrien	dont_free = 0;
139459243Sobrien# endif /* SETLOCALEBUG */
139559243Sobrien# ifdef STRCOLLBUG
139659243Sobrien	fix_strcoll_bug();
139759243Sobrien# endif /* STRCOLLBUG */
139859243Sobrien	tw_cmd_free();	/* since the collation sequence has changed */
139959243Sobrien	for (k = 0200; k <= 0377 && !Isprint(k); k++)
140059243Sobrien	    continue;
140159243Sobrien	AsciiOnly = k > 0377;
140259243Sobrien#else /* !NLS */
140359243Sobrien	AsciiOnly = 0;
140459243Sobrien#endif /* NLS */
140559243Sobrien	NLSMapsAreInited = 0;
140659243Sobrien	ed_Init();
140759243Sobrien	if (MapsAreInited && !NLSMapsAreInited)
140859243Sobrien	    ed_InitNLSMaps();
140959243Sobrien	xfree((ptr_t) lp);
141059243Sobrien	return;
141159243Sobrien    }
141259243Sobrien
1413100616Smp#ifdef NLS_CATALOGS
1414100616Smp    if (eq(vp, STRNLSPATH)) {
1415100616Smp	(void) catclose(catd);
1416100616Smp	nlsinit();
1417100616Smp    }
1418100616Smp#endif
1419100616Smp
142059243Sobrien    if (eq(vp, STRNOREBIND)) {
142159243Sobrien	NoNLSRebind = 1;
142259243Sobrien	MapsAreInited = 0;
142359243Sobrien	NLSMapsAreInited = 0;
142459243Sobrien	ed_InitMaps();
142559243Sobrien	xfree((ptr_t) lp);
142659243Sobrien	return;
142759243Sobrien    }
142869408Sache#ifdef WINNT_NATIVE
142959243Sobrien    if (eq(vp, STRtcshlang)) {
143059243Sobrien	nlsinit();
143159243Sobrien	xfree((ptr_t) lp);
143259243Sobrien	return;
143359243Sobrien    }
143469408Sache#endif /* WINNT_NATIVE */
143559243Sobrien    if (eq(vp, STRKTERM)) {
143659243Sobrien	char *t;
143759243Sobrien	set(STRterm, quote(lp), VAR_READWRITE);	/* lp memory used here */
143859243Sobrien	t = short2str(lp);
143959243Sobrien	if (noediting && strcmp(t, "unknown") != 0 && strcmp(t,"dumb") != 0) {
144059243Sobrien	    editing = 1;
144159243Sobrien	    noediting = 0;
144259243Sobrien	    set(STRedit, Strsave(STRNULL), VAR_READWRITE);
144359243Sobrien	}
144459243Sobrien	GotTermCaps = 0;
144559243Sobrien	ed_Init();
144659243Sobrien	return;
144759243Sobrien    }
144859243Sobrien
144959243Sobrien    if (eq(vp, STRKHOME)) {
145059243Sobrien	/*
145159243Sobrien	 * convert to canonical pathname (possibly resolving symlinks)
145259243Sobrien	 */
145359243Sobrien	lp = dcanon(lp, lp);
145459243Sobrien	set(STRhome, quote(lp), VAR_READWRITE);	/* cp memory used here */
145559243Sobrien
145659243Sobrien	/* fix directory stack for new tilde home */
145759243Sobrien	dtilde();
145859243Sobrien	return;
145959243Sobrien    }
146059243Sobrien
146159243Sobrien    if (eq(vp, STRKSHLVL)) {
146259243Sobrien	/* lp memory used here */
146359243Sobrien	set(STRshlvl, quote(lp), VAR_READWRITE);
146459243Sobrien	return;
146559243Sobrien    }
146659243Sobrien
146759243Sobrien    if (eq(vp, STRKUSER)) {
146859243Sobrien	set(STRuser, quote(lp), VAR_READWRITE);	/* lp memory used here */
146959243Sobrien	return;
147059243Sobrien    }
147159243Sobrien
147259243Sobrien    if (eq(vp, STRKGROUP)) {
147359243Sobrien	set(STRgroup, quote(lp), VAR_READWRITE);	/* lp memory used here */
147459243Sobrien	return;
147559243Sobrien    }
147659243Sobrien
147759243Sobrien#ifdef COLOR_LS_F
147859243Sobrien    if (eq(vp, STRLS_COLORS)) {
147959243Sobrien        parseLS_COLORS(lp);
148059243Sobrien	return;
148159243Sobrien    }
148259243Sobrien#endif /* COLOR_LS_F */
148359243Sobrien
148459243Sobrien#ifdef SIG_WINDOW
148559243Sobrien    /*
148659243Sobrien     * Load/Update $LINES $COLUMNS
148759243Sobrien     */
148859243Sobrien    if ((eq(lp, STRNULL) && (eq(vp, STRLINES) || eq(vp, STRCOLUMNS))) ||
148959243Sobrien	eq(vp, STRTERMCAP)) {
149059243Sobrien	xfree((ptr_t) lp);
149159243Sobrien	check_window_size(1);
149259243Sobrien	return;
149359243Sobrien    }
149459243Sobrien
149559243Sobrien    /*
149659243Sobrien     * Change the size to the one directed by $LINES and $COLUMNS
149759243Sobrien     */
149859243Sobrien    if (eq(vp, STRLINES) || eq(vp, STRCOLUMNS)) {
149959243Sobrien#if 0
150059243Sobrien	GotTermCaps = 0;
150159243Sobrien#endif
150259243Sobrien	xfree((ptr_t) lp);
150359243Sobrien	ed_Init();
150459243Sobrien	return;
150559243Sobrien    }
150659243Sobrien#endif /* SIG_WINDOW */
150759243Sobrien    xfree((ptr_t) lp);
150859243Sobrien}
150959243Sobrien
151059243Sobrien/*ARGSUSED*/
151159243Sobrienvoid
151259243Sobriendounsetenv(v, c)
151359243Sobrien    register Char **v;
151459243Sobrien    struct command *c;
151559243Sobrien{
151659243Sobrien    Char  **ep, *p, *n;
151759243Sobrien    int     i, maxi;
151859243Sobrien    static Char *name = NULL;
151959243Sobrien
152059243Sobrien    USE(c);
152159243Sobrien    if (name)
152259243Sobrien	xfree((ptr_t) name);
152359243Sobrien    /*
152459243Sobrien     * Find the longest environment variable
152559243Sobrien     */
152659243Sobrien    for (maxi = 0, ep = STR_environ; *ep; ep++) {
152759243Sobrien	for (i = 0, p = *ep; *p && *p != '='; p++, i++)
152859243Sobrien	    continue;
152959243Sobrien	if (i > maxi)
153059243Sobrien	    maxi = i;
153159243Sobrien    }
153259243Sobrien
153359243Sobrien    name = (Char *) xmalloc((size_t) ((maxi + 1) * sizeof(Char)));
153459243Sobrien
153559243Sobrien    while (++v && *v)
153659243Sobrien	for (maxi = 1; maxi;)
153759243Sobrien	    for (maxi = 0, ep = STR_environ; *ep; ep++) {
153859243Sobrien		for (n = name, p = *ep; *p && *p != '='; *n++ = *p++)
153959243Sobrien		    continue;
154059243Sobrien		*n = '\0';
154159243Sobrien		if (!Gmatch(name, *v))
154259243Sobrien		    continue;
154359243Sobrien		maxi = 1;
154459243Sobrien
154559243Sobrien		/* Unset the name. This wasn't being done until
154659243Sobrien		 * later but most of the stuff following won't
154759243Sobrien		 * work (particularly the setlocale() and getenv()
154859243Sobrien		 * stuff) as intended until the name is actually
154959243Sobrien		 * removed. (sg)
155059243Sobrien		 */
155159243Sobrien		Unsetenv(name);
155259243Sobrien
155359243Sobrien		if (eq(name, STRNOREBIND)) {
155459243Sobrien		    NoNLSRebind = 0;
155559243Sobrien		    MapsAreInited = 0;
155659243Sobrien		    NLSMapsAreInited = 0;
155759243Sobrien		    ed_InitMaps();
155859243Sobrien		}
155959243Sobrien#ifdef apollo
156059243Sobrien		else if (eq(name, STRSYSTYPE))
156159243Sobrien		    dohash(NULL, NULL);
156259243Sobrien#endif /* apollo */
156359243Sobrien		else if (islocale_var(name)) {
156459243Sobrien#ifdef NLS
156559243Sobrien		    int     k;
156659243Sobrien
156759243Sobrien# ifdef SETLOCALEBUG
156859243Sobrien		    dont_free = 1;
156959243Sobrien# endif /* SETLOCALEBUG */
157059243Sobrien		    (void) setlocale(LC_ALL, "");
157159243Sobrien# ifdef LC_COLLATE
157259243Sobrien		    (void) setlocale(LC_COLLATE, "");
157359243Sobrien# endif
157459243Sobrien# ifdef NLS_CATALOGS
157559243Sobrien#  ifdef LC_MESSAGES
157659243Sobrien		    (void) setlocale(LC_MESSAGES, "");
157759243Sobrien#  endif /* LC_MESSAGES */
157859243Sobrien		    (void) catclose(catd);
157959243Sobrien		    nlsinit();
158059243Sobrien# endif /* NLS_CATALOGS */
158159243Sobrien# ifdef LC_CTYPE
158259243Sobrien	(void) setlocale(LC_CTYPE, ""); /* for iscntrl */
158359243Sobrien# endif /* LC_CTYPE */
158459243Sobrien# ifdef SETLOCALEBUG
158559243Sobrien		    dont_free = 0;
158659243Sobrien# endif /* SETLOCALEBUG */
158759243Sobrien# ifdef STRCOLLBUG
158859243Sobrien		    fix_strcoll_bug();
158959243Sobrien# endif /* STRCOLLBUG */
159059243Sobrien		    tw_cmd_free();/* since the collation sequence has changed */
159159243Sobrien		    for (k = 0200; k <= 0377 && !Isprint(k); k++)
159259243Sobrien			continue;
159359243Sobrien		    AsciiOnly = k > 0377;
159459243Sobrien#else /* !NLS */
159559243Sobrien		    AsciiOnly = getenv("LANG") == NULL &&
159659243Sobrien			getenv("LC_CTYPE") == NULL;
159759243Sobrien#endif /* NLS */
159859243Sobrien		    NLSMapsAreInited = 0;
159959243Sobrien		    ed_Init();
160059243Sobrien		    if (MapsAreInited && !NLSMapsAreInited)
160159243Sobrien			ed_InitNLSMaps();
160259243Sobrien
160359243Sobrien		}
160469408Sache#ifdef WINNT_NATIVE
160559243Sobrien		else if (eq(name,(STRtcshlang))) {
160659243Sobrien		    nls_dll_unload();
160759243Sobrien		    nlsinit();
160859243Sobrien		}
160969408Sache#endif /* WINNT_NATIVE */
161059243Sobrien#ifdef COLOR_LS_F
161159243Sobrien		else if (eq(name, STRLS_COLORS))
161259243Sobrien		    parseLS_COLORS(n);
161359243Sobrien#endif /* COLOR_LS_F */
1614100616Smp#ifdef NLS_CATALOGS
1615100616Smp		else if (eq(name, STRNLSPATH)) {
1616100616Smp		    (void) catclose(catd);
1617100616Smp		    nlsinit();
1618100616Smp		}
1619100616Smp#endif
162059243Sobrien		/*
162159243Sobrien		 * start again cause the environment changes
162259243Sobrien		 */
162359243Sobrien		break;
162459243Sobrien	    }
162559243Sobrien    xfree((ptr_t) name); name = NULL;
162659243Sobrien}
162759243Sobrien
162859243Sobrienvoid
162959243Sobrientsetenv(name, val)
163059243Sobrien    Char   *name, *val;
163159243Sobrien{
163259243Sobrien#ifdef SETENV_IN_LIB
163359243Sobrien/*
163459243Sobrien * XXX: This does not work right, since tcsh cannot track changes to
163559243Sobrien * the environment this way. (the builtin setenv without arguments does
163659243Sobrien * not print the right stuff neither does unsetenv). This was for Mach,
163759243Sobrien * it is not needed anymore.
163859243Sobrien */
163959243Sobrien#undef setenv
164059243Sobrien    char    nameBuf[BUFSIZE];
164159243Sobrien    char   *cname = short2str(name);
164259243Sobrien
164359243Sobrien    if (cname == NULL)
164459243Sobrien	return;
164559243Sobrien    (void) strcpy(nameBuf, cname);
164659243Sobrien    setenv(nameBuf, short2str(val), 1);
164759243Sobrien#else /* !SETENV_IN_LIB */
164859243Sobrien    register Char **ep = STR_environ;
164959243Sobrien    register Char *cp, *dp;
165059243Sobrien    Char   *blk[2];
165159243Sobrien    Char  **oep = ep;
165259243Sobrien
165369408Sache#ifdef WINNT_NATIVE
165459243Sobrien	nt_set_env(name,val);
165569408Sache#endif /* WINNT_NATIVE */
165659243Sobrien    for (; *ep; ep++) {
165769408Sache#ifdef WINNT_NATIVE
165859243Sobrien	for (cp = name, dp = *ep; *cp && Tolower(*cp & TRIM) == Tolower(*dp);
165959243Sobrien				cp++, dp++)
166059243Sobrien#else
166159243Sobrien	for (cp = name, dp = *ep; *cp && (*cp & TRIM) == *dp; cp++, dp++)
166269408Sache#endif /* WINNT_NATIVE */
166359243Sobrien	    continue;
166459243Sobrien	if (*cp != 0 || *dp != '=')
166559243Sobrien	    continue;
166659243Sobrien	cp = Strspl(STRequal, val);
166759243Sobrien	xfree((ptr_t) * ep);
166859243Sobrien	*ep = strip(Strspl(name, cp));
166959243Sobrien	xfree((ptr_t) cp);
167059243Sobrien	blkfree((Char **) environ);
167159243Sobrien	environ = short2blk(STR_environ);
167259243Sobrien	return;
167359243Sobrien    }
167459243Sobrien    cp = Strspl(name, STRequal);
167559243Sobrien    blk[0] = strip(Strspl(cp, val));
167659243Sobrien    xfree((ptr_t) cp);
167759243Sobrien    blk[1] = 0;
167859243Sobrien    STR_environ = blkspl(STR_environ, blk);
167959243Sobrien    blkfree((Char **) environ);
168059243Sobrien    environ = short2blk(STR_environ);
168159243Sobrien    xfree((ptr_t) oep);
168259243Sobrien#endif /* SETENV_IN_LIB */
168359243Sobrien}
168459243Sobrien
168559243Sobrienvoid
168659243SobrienUnsetenv(name)
168759243Sobrien    Char   *name;
168859243Sobrien{
168959243Sobrien    register Char **ep = STR_environ;
169059243Sobrien    register Char *cp, *dp;
169159243Sobrien    Char **oep = ep;
169259243Sobrien
169369408Sache#ifdef WINNT_NATIVE
169459243Sobrien	nt_set_env(name,NULL);
169569408Sache#endif /*WINNT_NATIVE */
169659243Sobrien    for (; *ep; ep++) {
169759243Sobrien	for (cp = name, dp = *ep; *cp && *cp == *dp; cp++, dp++)
169859243Sobrien	    continue;
169959243Sobrien	if (*cp != 0 || *dp != '=')
170059243Sobrien	    continue;
170159243Sobrien	cp = *ep;
170259243Sobrien	*ep = 0;
170359243Sobrien	STR_environ = blkspl(STR_environ, ep + 1);
170459243Sobrien	blkfree((Char **) environ);
170559243Sobrien	environ = short2blk(STR_environ);
170659243Sobrien	*ep = cp;
170759243Sobrien	xfree((ptr_t) cp);
170859243Sobrien	xfree((ptr_t) oep);
170959243Sobrien	return;
171059243Sobrien    }
171159243Sobrien}
171259243Sobrien
171359243Sobrien/*ARGSUSED*/
171459243Sobrienvoid
171559243Sobriendoumask(v, c)
171659243Sobrien    register Char **v;
171759243Sobrien    struct command *c;
171859243Sobrien{
171959243Sobrien    register Char *cp = v[1];
172059243Sobrien    register int i;
172159243Sobrien
172259243Sobrien    USE(c);
172359243Sobrien    if (cp == 0) {
172459415Sobrien	i = (int)umask(0);
172559243Sobrien	(void) umask(i);
172659243Sobrien	xprintf("%o\n", i);
172759243Sobrien	return;
172859243Sobrien    }
172959243Sobrien    i = 0;
173059243Sobrien    while (Isdigit(*cp) && *cp != '8' && *cp != '9')
173159243Sobrien	i = i * 8 + *cp++ - '0';
173259243Sobrien    if (*cp || i < 0 || i > 0777)
173359243Sobrien	stderror(ERR_NAME | ERR_MASK);
173459243Sobrien    (void) umask(i);
173559243Sobrien}
173659243Sobrien
173759243Sobrien#ifndef HAVENOLIMIT
173859243Sobrien# ifndef BSDLIMIT
173959243Sobrien   typedef long RLIM_TYPE;
174059243Sobrien#  ifndef RLIM_INFINITY
174159243Sobrien#   if !defined(_MINIX) && !defined(__clipper__) && !defined(_CRAY)
174259243Sobrien    extern RLIM_TYPE ulimit();
174359243Sobrien#   endif /* ! _MINIX && !__clipper__ */
174459243Sobrien#   define RLIM_INFINITY 0x003fffff
174559243Sobrien#   define RLIMIT_FSIZE 1
174659243Sobrien#  endif /* RLIM_INFINITY */
174759243Sobrien#  ifdef aiws
174859243Sobrien#   define toset(a) (((a) == 3) ? 1004 : (a) + 1)
174959243Sobrien#   define RLIMIT_DATA	3
175059243Sobrien#   define RLIMIT_STACK 1005
175159243Sobrien#  else /* aiws */
175259243Sobrien#   define toset(a) ((a) + 1)
175359243Sobrien#  endif /* aiws */
175459243Sobrien# else /* BSDLIMIT */
1755131962Smp#  if (defined(BSD4_4) || defined(__linux__) || (HPUXVERSION >= 1100)) && !defined(__386BSD__)
1756100616Smp    typedef rlim_t RLIM_TYPE;
175759243Sobrien#  else
175859243Sobrien#   if defined(SOLARIS2) || (defined(sgi) && SYSVREL > 3)
175959243Sobrien     typedef rlim_t RLIM_TYPE;
176059243Sobrien#   else
176159243Sobrien#    if defined(_SX)
176259243Sobrien      typedef long long RLIM_TYPE;
1763100616Smp#    else /* !_SX */
176459243Sobrien      typedef unsigned long RLIM_TYPE;
176559243Sobrien#    endif /* _SX */
176659243Sobrien#   endif /* SOLARIS2 || (sgi && SYSVREL > 3) */
176759243Sobrien#  endif /* BSD4_4 && !__386BSD__  */
176859243Sobrien# endif /* BSDLIMIT */
176959243Sobrien
1770131962Smp# if (HPUXVERSION > 700) && (HPUXVERSION < 1100) && defined(BSDLIMIT)
177159243Sobrien/* Yes hpux8.0 has limits but <sys/resource.h> does not make them public */
177259243Sobrien/* Yes, we could have defined _KERNEL, and -I/etc/conf/h, but is that better? */
177359243Sobrien#  ifndef RLIMIT_CPU
177459243Sobrien#   define RLIMIT_CPU		0
177559243Sobrien#   define RLIMIT_FSIZE		1
177659243Sobrien#   define RLIMIT_DATA		2
177759243Sobrien#   define RLIMIT_STACK		3
177859243Sobrien#   define RLIMIT_CORE		4
177959243Sobrien#   define RLIMIT_RSS		5
178059243Sobrien#   define RLIMIT_NOFILE	6
178159243Sobrien#  endif /* RLIMIT_CPU */
178259243Sobrien#  ifndef RLIM_INFINITY
178359243Sobrien#   define RLIM_INFINITY	0x7fffffff
178459243Sobrien#  endif /* RLIM_INFINITY */
178559243Sobrien   /*
178659243Sobrien    * old versions of HP/UX counted limits in 512 bytes
178759243Sobrien    */
178859243Sobrien#  ifndef SIGRTMIN
178959243Sobrien#   define FILESIZE512
179059243Sobrien#  endif /* SIGRTMIN */
1791131962Smp# endif /* (HPUXVERSION > 700) && (HPUXVERSION < 1100) && BSDLIMIT */
179259243Sobrien
179359243Sobrien# if SYSVREL > 3 && defined(BSDLIMIT) && !defined(_SX)
179459243Sobrien/* In order to use rusage, we included "/usr/ucbinclude/sys/resource.h" in */
179559243Sobrien/* sh.h.  However, some SVR4 limits are defined in <sys/resource.h>.  Rather */
179659243Sobrien/* than include both and get warnings, we define the extra SVR4 limits here. */
179783098Smp/* XXX: I don't understand if RLIMIT_AS is defined, why don't we define */
179883098Smp/* RLIMIT_VMEM based on it? */
179959243Sobrien#  ifndef RLIMIT_VMEM
180059243Sobrien#   define RLIMIT_VMEM	6
180159243Sobrien#  endif
180259243Sobrien#  ifndef RLIMIT_AS
180359243Sobrien#   define RLIMIT_AS	RLIMIT_VMEM
180459243Sobrien#  endif
180559243Sobrien# endif /* SYSVREL > 3 && BSDLIMIT */
180659243Sobrien
180783098Smp# if defined(__linux__) && defined(RLIMIT_AS) && !defined(RLIMIT_VMEM)
180883098Smp#  define RLIMIT_VMEM	RLIMIT_AS
180983098Smp# endif
181083098Smp
181159243Sobrienstruct limits limits[] =
181259243Sobrien{
181359243Sobrien# ifdef RLIMIT_CPU
181459243Sobrien    { RLIMIT_CPU, 	"cputime",	1,	"seconds"	},
181559243Sobrien# endif /* RLIMIT_CPU */
181659243Sobrien
181759243Sobrien# ifdef RLIMIT_FSIZE
181859243Sobrien#  ifndef aiws
181959243Sobrien    { RLIMIT_FSIZE, 	"filesize",	1024,	"kbytes"	},
182059243Sobrien#  else
182159243Sobrien    { RLIMIT_FSIZE, 	"filesize",	512,	"blocks"	},
182259243Sobrien#  endif /* aiws */
182359243Sobrien# endif /* RLIMIT_FSIZE */
182459243Sobrien
182559243Sobrien# ifdef RLIMIT_DATA
182659243Sobrien    { RLIMIT_DATA, 	"datasize",	1024,	"kbytes"	},
182759243Sobrien# endif /* RLIMIT_DATA */
182859243Sobrien
182959243Sobrien# ifdef RLIMIT_STACK
183059243Sobrien#  ifndef aiws
183159243Sobrien    { RLIMIT_STACK, 	"stacksize",	1024,	"kbytes"	},
183259243Sobrien#  else
183359243Sobrien    { RLIMIT_STACK, 	"stacksize",	1024 * 1024,	"kbytes"},
183459243Sobrien#  endif /* aiws */
183559243Sobrien# endif /* RLIMIT_STACK */
183659243Sobrien
183759243Sobrien# ifdef RLIMIT_CORE
183859243Sobrien    { RLIMIT_CORE, 	"coredumpsize",	1024,	"kbytes"	},
183959243Sobrien# endif /* RLIMIT_CORE */
184059243Sobrien
184159243Sobrien# ifdef RLIMIT_RSS
184259243Sobrien    { RLIMIT_RSS, 	"memoryuse",	1024,	"kbytes"	},
184359243Sobrien# endif /* RLIMIT_RSS */
184459243Sobrien
184559243Sobrien# ifdef RLIMIT_UMEM
184659243Sobrien    { RLIMIT_UMEM, 	"memoryuse",	1024,	"kbytes"	},
184759243Sobrien# endif /* RLIMIT_UMEM */
184859243Sobrien
184959243Sobrien# ifdef RLIMIT_VMEM
185059243Sobrien    { RLIMIT_VMEM, 	"vmemoryuse",	1024,	"kbytes"	},
185159243Sobrien# endif /* RLIMIT_VMEM */
185259243Sobrien
185359243Sobrien# ifdef RLIMIT_NOFILE
185459243Sobrien    { RLIMIT_NOFILE, 	"descriptors", 1,	""		},
185559243Sobrien# endif /* RLIMIT_NOFILE */
185659243Sobrien
185759243Sobrien# ifdef RLIMIT_CONCUR
185859243Sobrien    { RLIMIT_CONCUR, 	"concurrency", 1,	"thread(s)"	},
185959243Sobrien# endif /* RLIMIT_CONCUR */
186059243Sobrien
186159243Sobrien# ifdef RLIMIT_MEMLOCK
186259243Sobrien    { RLIMIT_MEMLOCK,	"memorylocked",	1024,	"kbytes"	},
186359243Sobrien# endif /* RLIMIT_MEMLOCK */
186459243Sobrien
186559243Sobrien# ifdef RLIMIT_NPROC
186659243Sobrien    { RLIMIT_NPROC,	"maxproc",	1,	""		},
186759243Sobrien# endif /* RLIMIT_NPROC */
186859243Sobrien
1869100616Smp# if defined(RLIMIT_OFILE) && !defined(RLIMIT_NOFILE)
187059243Sobrien    { RLIMIT_OFILE,	"openfiles",	1,	""		},
1871100616Smp# endif /* RLIMIT_OFILE && !defined(RLIMIT_NOFILE) */
187259243Sobrien
1873100616Smp# ifdef RLIMIT_SBSIZE
1874100616Smp    { RLIMIT_SBSIZE,	"sbsize",	1,	""		},
1875100616Smp# endif /* RLIMIT_SBSIZE */
1876100616Smp
187759243Sobrien    { -1, 		NULL, 		0, 	NULL		}
187859243Sobrien};
187959243Sobrien
188059243Sobrienstatic struct limits *findlim	__P((Char *));
188159243Sobrienstatic RLIM_TYPE getval		__P((struct limits *, Char **));
188259243Sobrienstatic void limtail		__P((Char *, char*));
188359243Sobrienstatic void plim		__P((struct limits *, int));
188459243Sobrienstatic int setlim		__P((struct limits *, int, RLIM_TYPE));
188559243Sobrien
188659243Sobrien#ifdef convex
188759243Sobrienstatic  RLIM_TYPE
188859243Sobrienrestrict_limit(value)
188959243Sobrien    double  value;
189059243Sobrien{
189159243Sobrien    /*
189259243Sobrien     * is f too large to cope with? return the maximum or minimum int
189359243Sobrien     */
189459243Sobrien    if (value > (double) INT_MAX)
189559243Sobrien	return (RLIM_TYPE) INT_MAX;
189659243Sobrien    else if (value < (double) INT_MIN)
189759243Sobrien	return (RLIM_TYPE) INT_MIN;
189859243Sobrien    else
189959243Sobrien	return (RLIM_TYPE) value;
190059243Sobrien}
190159243Sobrien#else /* !convex */
190259243Sobrien# define restrict_limit(x)	((RLIM_TYPE) (x))
190359243Sobrien#endif /* convex */
190459243Sobrien
190559243Sobrien
190659243Sobrienstatic struct limits *
190759243Sobrienfindlim(cp)
190859243Sobrien    Char   *cp;
190959243Sobrien{
191059243Sobrien    register struct limits *lp, *res;
191159243Sobrien
191259243Sobrien    res = (struct limits *) NULL;
191359243Sobrien    for (lp = limits; lp->limconst >= 0; lp++)
191459243Sobrien	if (prefix(cp, str2short(lp->limname))) {
191559243Sobrien	    if (res)
191659243Sobrien		stderror(ERR_NAME | ERR_AMBIG);
191759243Sobrien	    res = lp;
191859243Sobrien	}
191959243Sobrien    if (res)
192059243Sobrien	return (res);
192159243Sobrien    stderror(ERR_NAME | ERR_LIMIT);
192259243Sobrien    /* NOTREACHED */
192359243Sobrien    return (0);
192459243Sobrien}
192559243Sobrien
192659243Sobrien/*ARGSUSED*/
192759243Sobrienvoid
192859243Sobriendolimit(v, c)
192959243Sobrien    register Char **v;
193059243Sobrien    struct command *c;
193159243Sobrien{
193259243Sobrien    register struct limits *lp;
193359243Sobrien    register RLIM_TYPE limit;
193459243Sobrien    int    hard = 0;
193559243Sobrien
193659243Sobrien    USE(c);
193759243Sobrien    v++;
193859243Sobrien    if (*v && eq(*v, STRmh)) {
193959243Sobrien	hard = 1;
194059243Sobrien	v++;
194159243Sobrien    }
194259243Sobrien    if (*v == 0) {
194359243Sobrien	for (lp = limits; lp->limconst >= 0; lp++)
194459243Sobrien	    plim(lp, hard);
194559243Sobrien	return;
194659243Sobrien    }
194759243Sobrien    lp = findlim(v[0]);
194859243Sobrien    if (v[1] == 0) {
194959243Sobrien	plim(lp, hard);
195059243Sobrien	return;
195159243Sobrien    }
195259243Sobrien    limit = getval(lp, v + 1);
195359243Sobrien    if (setlim(lp, hard, limit) < 0)
195459243Sobrien	stderror(ERR_SILENT);
195559243Sobrien}
195659243Sobrien
195759243Sobrienstatic  RLIM_TYPE
195859243Sobriengetval(lp, v)
195959243Sobrien    register struct limits *lp;
196059243Sobrien    Char  **v;
196159243Sobrien{
196259243Sobrien    register float f;
196359243Sobrien#ifndef atof	/* This can be a macro on linux */
196459243Sobrien    extern double  atof __P((const char *));
196559243Sobrien#endif /* atof */
196659243Sobrien    Char   *cp = *v++;
196759243Sobrien
196859243Sobrien    f = atof(short2str(cp));
196959243Sobrien
197059243Sobrien# ifdef convex
197159243Sobrien    /*
197259243Sobrien     * is f too large to cope with. limit f to minint, maxint  - X-6768 by
197359243Sobrien     * strike
197459243Sobrien     */
197559243Sobrien    if ((f < (double) INT_MIN) || (f > (double) INT_MAX)) {
197659243Sobrien	stderror(ERR_NAME | ERR_TOOLARGE);
197759243Sobrien    }
197859243Sobrien# endif /* convex */
197959243Sobrien
198059243Sobrien    while (Isdigit(*cp) || *cp == '.' || *cp == 'e' || *cp == 'E')
198159243Sobrien	cp++;
198259243Sobrien    if (*cp == 0) {
198359243Sobrien	if (*v == 0)
198469408Sache	    return restrict_limit((f * lp->limdiv) + 0.5);
198559243Sobrien	cp = *v;
198659243Sobrien    }
198759243Sobrien    switch (*cp) {
198859243Sobrien# ifdef RLIMIT_CPU
198959243Sobrien    case ':':
199059243Sobrien	if (lp->limconst != RLIMIT_CPU)
199159243Sobrien	    goto badscal;
199259243Sobrien	return f == 0.0 ? (RLIM_TYPE) 0 : restrict_limit((f * 60.0 + atof(short2str(cp + 1))));
199359243Sobrien    case 'h':
199459243Sobrien	if (lp->limconst != RLIMIT_CPU)
199559243Sobrien	    goto badscal;
199659243Sobrien	limtail(cp, "hours");
199759243Sobrien	f *= 3600.0;
199859243Sobrien	break;
199959243Sobrien    case 'm':
200059243Sobrien	if (lp->limconst == RLIMIT_CPU) {
200159243Sobrien	    limtail(cp, "minutes");
200259243Sobrien	    f *= 60.0;
200359243Sobrien	    break;
200459243Sobrien	}
200559243Sobrien	*cp = 'm';
200659243Sobrien	limtail(cp, "megabytes");
200759243Sobrien	f *= 1024.0 * 1024.0;
200859243Sobrien	break;
200959243Sobrien    case 's':
201059243Sobrien	if (lp->limconst != RLIMIT_CPU)
201159243Sobrien	    goto badscal;
201259243Sobrien	limtail(cp, "seconds");
201359243Sobrien	break;
201459243Sobrien# endif /* RLIMIT_CPU */
201559243Sobrien    case 'M':
201659243Sobrien# ifdef RLIMIT_CPU
201759243Sobrien	if (lp->limconst == RLIMIT_CPU)
201859243Sobrien	    goto badscal;
201959243Sobrien# endif /* RLIMIT_CPU */
202059243Sobrien	*cp = 'm';
202159243Sobrien	limtail(cp, "megabytes");
202259243Sobrien	f *= 1024.0 * 1024.0;
202359243Sobrien	break;
202459243Sobrien    case 'k':
202559243Sobrien# ifdef RLIMIT_CPU
202659243Sobrien	if (lp->limconst == RLIMIT_CPU)
202759243Sobrien	    goto badscal;
202859243Sobrien# endif /* RLIMIT_CPU */
202959243Sobrien	limtail(cp, "kbytes");
203059243Sobrien	f *= 1024.0;
203159243Sobrien	break;
203259243Sobrien    case 'b':
203359243Sobrien# ifdef RLIMIT_CPU
203459243Sobrien	if (lp->limconst == RLIMIT_CPU)
203559243Sobrien	    goto badscal;
203659243Sobrien# endif /* RLIMIT_CPU */
203759243Sobrien	limtail(cp, "blocks");
203859243Sobrien	f *= 512.0;
203959243Sobrien	break;
204059243Sobrien    case 'u':
204159243Sobrien	limtail(cp, "unlimited");
204259243Sobrien	return ((RLIM_TYPE) RLIM_INFINITY);
204359243Sobrien    default:
204459243Sobrien# ifdef RLIMIT_CPU
204559243Sobrienbadscal:
204659243Sobrien# endif /* RLIMIT_CPU */
204759243Sobrien	stderror(ERR_NAME | ERR_SCALEF);
204859243Sobrien    }
204959243Sobrien# ifdef convex
205059243Sobrien    return f == 0.0 ? (RLIM_TYPE) 0 : restrict_limit((f + 0.5));
205159243Sobrien# else
205259243Sobrien    f += 0.5;
205359243Sobrien    if (f > (float) RLIM_INFINITY)
205459243Sobrien	return ((RLIM_TYPE) RLIM_INFINITY);
205559243Sobrien    else
205659243Sobrien	return ((RLIM_TYPE) f);
205759243Sobrien# endif /* convex */
205859243Sobrien}
205959243Sobrien
206059243Sobrienstatic void
206159243Sobrienlimtail(cp, str)
206259243Sobrien    Char   *cp;
206359243Sobrien    char   *str;
206459243Sobrien{
206561515Sobrien    char *sp;
206661515Sobrien
206761515Sobrien    sp = str;
206859243Sobrien    while (*cp && *cp == *str)
206959243Sobrien	cp++, str++;
207059243Sobrien    if (*cp)
207161515Sobrien	stderror(ERR_BADSCALE, sp);
207259243Sobrien}
207359243Sobrien
207459243Sobrien
207559243Sobrien/*ARGSUSED*/
207659243Sobrienstatic void
207759243Sobrienplim(lp, hard)
207859243Sobrien    register struct limits *lp;
207959243Sobrien    int hard;
208059243Sobrien{
208159243Sobrien# ifdef BSDLIMIT
208259243Sobrien    struct rlimit rlim;
208359243Sobrien# endif /* BSDLIMIT */
208459243Sobrien    RLIM_TYPE limit;
208559243Sobrien    int     div = lp->limdiv;
208659243Sobrien
2087131962Smp    xprintf("%-13.13s", lp->limname);
208859243Sobrien
208959243Sobrien# ifndef BSDLIMIT
209059243Sobrien    limit = ulimit(lp->limconst, 0);
209159243Sobrien#  ifdef aiws
209259243Sobrien    if (lp->limconst == RLIMIT_DATA)
209359243Sobrien	limit -= 0x20000000;
209459243Sobrien#  endif /* aiws */
209559243Sobrien# else /* BSDLIMIT */
209659243Sobrien    (void) getrlimit(lp->limconst, &rlim);
209759243Sobrien    limit = hard ? rlim.rlim_max : rlim.rlim_cur;
209859243Sobrien# endif /* BSDLIMIT */
209959243Sobrien
210059243Sobrien# if !defined(BSDLIMIT) || defined(FILESIZE512)
210159243Sobrien    /*
210259243Sobrien     * Christos: filesize comes in 512 blocks. we divide by 2 to get 1024
210359243Sobrien     * blocks. Note we cannot pre-multiply cause we might overflow (A/UX)
210459243Sobrien     */
210559243Sobrien    if (lp->limconst == RLIMIT_FSIZE) {
210659243Sobrien	if (limit >= (RLIM_INFINITY / 512))
210759243Sobrien	    limit = RLIM_INFINITY;
210859243Sobrien	else
210959243Sobrien	    div = (div == 1024 ? 2 : 1);
211059243Sobrien    }
211159243Sobrien# endif /* !BSDLIMIT || FILESIZE512 */
211259243Sobrien
211359243Sobrien    if (limit == RLIM_INFINITY)
211459243Sobrien	xprintf("unlimited");
211559243Sobrien    else
211659243Sobrien# ifdef RLIMIT_CPU
211759243Sobrien    if (lp->limconst == RLIMIT_CPU)
211859243Sobrien	psecs((long) limit);
211959243Sobrien    else
212059243Sobrien# endif /* RLIMIT_CPU */
212159243Sobrien	xprintf("%ld %s", (long) (limit / div), lp->limscale);
212259243Sobrien    xputchar('\n');
212359243Sobrien}
212459243Sobrien
212559243Sobrien/*ARGSUSED*/
212659243Sobrienvoid
212759243Sobriendounlimit(v, c)
212859243Sobrien    register Char **v;
212959243Sobrien    struct command *c;
213059243Sobrien{
213159243Sobrien    register struct limits *lp;
213259243Sobrien    int    lerr = 0;
213359243Sobrien    int    hard = 0;
213459243Sobrien    int	   force = 0;
213559243Sobrien
213659243Sobrien    USE(c);
213759243Sobrien    while (*++v && **v == '-') {
213859243Sobrien	Char   *vp = *v;
213959243Sobrien	while (*++vp)
214059243Sobrien	    switch (*vp) {
214159243Sobrien	    case 'f':
214259243Sobrien		force = 1;
214359243Sobrien		break;
214459243Sobrien	    case 'h':
214559243Sobrien		hard = 1;
214659243Sobrien		break;
214759243Sobrien	    default:
214859243Sobrien		stderror(ERR_ULIMUS);
214959243Sobrien		break;
215059243Sobrien	    }
215159243Sobrien    }
215259243Sobrien
215359243Sobrien    if (*v == 0) {
215459243Sobrien	for (lp = limits; lp->limconst >= 0; lp++)
215559243Sobrien	    if (setlim(lp, hard, (RLIM_TYPE) RLIM_INFINITY) < 0)
215659243Sobrien		lerr++;
215759243Sobrien	if (!force && lerr)
215859243Sobrien	    stderror(ERR_SILENT);
215959243Sobrien	return;
216059243Sobrien    }
216159243Sobrien    while (*v) {
216259243Sobrien	lp = findlim(*v++);
216359243Sobrien	if (setlim(lp, hard, (RLIM_TYPE) RLIM_INFINITY) < 0 && !force)
216459243Sobrien	    stderror(ERR_SILENT);
216559243Sobrien    }
216659243Sobrien}
216759243Sobrien
216859243Sobrienstatic int
216959243Sobriensetlim(lp, hard, limit)
217059243Sobrien    register struct limits *lp;
217159243Sobrien    int    hard;
217259243Sobrien    RLIM_TYPE limit;
217359243Sobrien{
217459243Sobrien# ifdef BSDLIMIT
217559243Sobrien    struct rlimit rlim;
217659243Sobrien
217759243Sobrien    (void) getrlimit(lp->limconst, &rlim);
217859243Sobrien
217959243Sobrien#  ifdef FILESIZE512
218059243Sobrien    /* Even though hpux has setrlimit(), it expects fsize in 512 byte blocks */
218159243Sobrien    if (limit != RLIM_INFINITY && lp->limconst == RLIMIT_FSIZE)
218259243Sobrien	limit /= 512;
218359243Sobrien#  endif /* FILESIZE512 */
218459243Sobrien    if (hard)
218559243Sobrien	rlim.rlim_max = limit;
218659243Sobrien    else if (limit == RLIM_INFINITY && euid != 0)
218759243Sobrien	rlim.rlim_cur = rlim.rlim_max;
218859243Sobrien    else
218959243Sobrien	rlim.rlim_cur = limit;
219059243Sobrien
2191100616Smp    if (rlim.rlim_cur > rlim.rlim_max)
2192100616Smp	rlim.rlim_max = rlim.rlim_cur;
2193100616Smp
219459243Sobrien    if (setrlimit(lp->limconst, &rlim) < 0) {
219559243Sobrien# else /* BSDLIMIT */
219659243Sobrien    if (limit != RLIM_INFINITY && lp->limconst == RLIMIT_FSIZE)
219759243Sobrien	limit /= 512;
219859243Sobrien# ifdef aiws
219959243Sobrien    if (lp->limconst == RLIMIT_DATA)
220059243Sobrien	limit += 0x20000000;
220159243Sobrien# endif /* aiws */
220259243Sobrien    if (ulimit(toset(lp->limconst), limit) < 0) {
220359243Sobrien# endif /* BSDLIMIT */
2204100616Smp	xprintf(CGETS(15, 1, "%s: %s: Can't %s%s limit (%s)\n"), bname,
2205100616Smp	    lp->limname, limit == RLIM_INFINITY ? CGETS(15, 2, "remove") :
2206100616Smp	    CGETS(15, 3, "set"), hard ? CGETS(14, 4, " hard") : "",
2207100616Smp	    strerror(errno));
220859243Sobrien	return (-1);
220959243Sobrien    }
221059243Sobrien    return (0);
221159243Sobrien}
221259243Sobrien
221359243Sobrien#endif /* !HAVENOLIMIT */
221459243Sobrien
221559243Sobrien/*ARGSUSED*/
221659243Sobrienvoid
221759243Sobriendosuspend(v, c)
221859243Sobrien    Char **v;
221959243Sobrien    struct command *c;
222059243Sobrien{
222159243Sobrien#ifdef BSDJOBS
222259243Sobrien    int     ctpgrp;
222359243Sobrien
222459243Sobrien    signalfun_t old;
222559243Sobrien#endif /* BSDJOBS */
222659243Sobrien
222759243Sobrien    USE(c);
222859243Sobrien    USE(v);
222959243Sobrien
223059243Sobrien    if (loginsh)
223159243Sobrien	stderror(ERR_SUSPLOG);
223259243Sobrien    untty();
223359243Sobrien
223459243Sobrien#ifdef BSDJOBS
223559243Sobrien    old = signal(SIGTSTP, SIG_DFL);
223659243Sobrien    (void) kill(0, SIGTSTP);
223759243Sobrien    /* the shell stops here */
223859243Sobrien    (void) signal(SIGTSTP, old);
223959243Sobrien#else /* !BSDJOBS */
224059243Sobrien    stderror(ERR_JOBCONTROL);
224159243Sobrien#endif /* BSDJOBS */
224259243Sobrien
224359243Sobrien#ifdef BSDJOBS
224459243Sobrien    if (tpgrp != -1) {
224559243Sobrienretry:
224659243Sobrien	ctpgrp = tcgetpgrp(FSHTTY);
2247131962Smp	if (ctpgrp == -1)
2248131962Smp	    stderror(ERR_SYSTEM, "tcgetpgrp", strerror(errno));
224959243Sobrien	if (ctpgrp != opgrp) {
225059243Sobrien	    old = signal(SIGTTIN, SIG_DFL);
225159243Sobrien	    (void) kill(0, SIGTTIN);
225259243Sobrien	    (void) signal(SIGTTIN, old);
225359243Sobrien	    goto retry;
225459243Sobrien	}
225559243Sobrien	(void) setpgid(0, shpgrp);
225659243Sobrien	(void) tcsetpgrp(FSHTTY, shpgrp);
225759243Sobrien    }
225859243Sobrien#endif /* BSDJOBS */
225959243Sobrien    (void) setdisc(FSHTTY);
226059243Sobrien}
226159243Sobrien
226259243Sobrien/* This is the dreaded EVAL built-in.
226359243Sobrien *   If you don't fiddle with file descriptors, and reset didfds,
226459243Sobrien *   this command will either ignore redirection inside or outside
226559243Sobrien *   its arguments, e.g. eval "date >x"  vs.  eval "date" >x
226659243Sobrien *   The stuff here seems to work, but I did it by trial and error rather
226759243Sobrien *   than really knowing what was going on.  If tpgrp is zero, we are
226859243Sobrien *   probably a background eval, e.g. "eval date &", and we want to
226959243Sobrien *   make sure that any processes we start stay in our pgrp.
227059243Sobrien *   This is also the case for "time eval date" -- stay in same pgrp.
227159243Sobrien *   Otherwise, under stty tostop, processes will stop in the wrong
227259243Sobrien *   pgrp, with no way for the shell to get them going again.  -IAN!
227359243Sobrien */
227459243Sobrien
227559243Sobrienstatic Char **gv = NULL, **gav = NULL;
227659243Sobrien
227759243Sobrien/*ARGSUSED*/
227859243Sobrienvoid
227959243Sobriendoeval(v, c)
228059243Sobrien    Char  **v;
228159243Sobrien    struct command *c;
228259243Sobrien{
228359243Sobrien    Char  **oevalvec;
228459243Sobrien    Char   *oevalp;
228559243Sobrien    int     odidfds;
228659243Sobrien#ifndef CLOSE_ON_EXEC
228759243Sobrien    int     odidcch;
228859243Sobrien#endif /* CLOSE_ON_EXEC */
228959243Sobrien    jmp_buf_t osetexit;
229059243Sobrien    int     my_reenter;
229159243Sobrien    Char  **savegv;
229259243Sobrien    int     saveIN, saveOUT, saveDIAG;
229359243Sobrien    int     oSHIN, oSHOUT, oSHDIAG;
229459243Sobrien
229559243Sobrien    USE(c);
229659243Sobrien    oevalvec = evalvec;
229759243Sobrien    oevalp = evalp;
229859243Sobrien    odidfds = didfds;
229959243Sobrien#ifndef CLOSE_ON_EXEC
230059243Sobrien    odidcch = didcch;
230159243Sobrien#endif /* CLOSE_ON_EXEC */
230259243Sobrien    oSHIN = SHIN;
230359243Sobrien    oSHOUT = SHOUT;
230459243Sobrien    oSHDIAG = SHDIAG;
230559243Sobrien
230659243Sobrien    savegv = gv;
230759243Sobrien    gav = v;
230859243Sobrien
230959243Sobrien    gav++;
231059243Sobrien    if (*gav == 0)
231159243Sobrien	return;
231259243Sobrien    gflag = 0, tglob(gav);
231359243Sobrien    if (gflag) {
231459243Sobrien	gv = gav = globall(gav);
231559243Sobrien	gargv = 0;
231659243Sobrien	if (gav == 0)
231759243Sobrien	    stderror(ERR_NOMATCH);
231859243Sobrien	gav = copyblk(gav);
231959243Sobrien    }
232059243Sobrien    else {
232159243Sobrien	gv = NULL;
232259243Sobrien	gav = copyblk(gav);
232359243Sobrien	trim(gav);
232459243Sobrien    }
232559243Sobrien
232659243Sobrien    saveIN = dcopy(SHIN, -1);
232759243Sobrien    saveOUT = dcopy(SHOUT, -1);
232859243Sobrien    saveDIAG = dcopy(SHDIAG, -1);
232959243Sobrien
233059243Sobrien    getexit(osetexit);
233159243Sobrien
233259243Sobrien    /* PWP: setjmp/longjmp bugfix for optimizing compilers */
233359243Sobrien#ifdef cray
233459243Sobrien    my_reenter = 1;             /* assume non-zero return val */
233559243Sobrien    if (setexit() == 0) {
233659243Sobrien	my_reenter = 0;         /* Oh well, we were wrong */
233759243Sobrien#else /* !cray */
233859243Sobrien    if ((my_reenter = setexit()) == 0) {
233959243Sobrien#endif /* cray */
234059243Sobrien	evalvec = gav;
234159243Sobrien	evalp = 0;
234259243Sobrien	SHIN = dcopy(0, -1);
234359243Sobrien	SHOUT = dcopy(1, -1);
234459243Sobrien	SHDIAG = dcopy(2, -1);
234559243Sobrien#ifndef CLOSE_ON_EXEC
234659243Sobrien	didcch = 0;
234759243Sobrien#endif /* CLOSE_ON_EXEC */
234859243Sobrien	didfds = 0;
234959243Sobrien	process(0);
235059243Sobrien    }
235159243Sobrien
235259243Sobrien    evalvec = oevalvec;
235359243Sobrien    evalp = oevalp;
235459243Sobrien    doneinp = 0;
235559243Sobrien#ifndef CLOSE_ON_EXEC
235659243Sobrien    didcch = odidcch;
235759243Sobrien#endif /* CLOSE_ON_EXEC */
235859243Sobrien    didfds = odidfds;
235959243Sobrien    (void) close(SHIN);
236059243Sobrien    (void) close(SHOUT);
236159243Sobrien    (void) close(SHDIAG);
236259243Sobrien    SHIN = dmove(saveIN, oSHIN);
236359243Sobrien    SHOUT = dmove(saveOUT, oSHOUT);
236459243Sobrien    SHDIAG = dmove(saveDIAG, oSHDIAG);
236559243Sobrien
236659243Sobrien    if (gv)
236759243Sobrien	blkfree(gv);
236859243Sobrien
236959243Sobrien    gv = savegv;
237059243Sobrien    resexit(osetexit);
237159243Sobrien    if (my_reenter)
237259243Sobrien	stderror(ERR_SILENT);
237359243Sobrien}
237459243Sobrien
237559243Sobrien/*************************************************************************/
237659243Sobrien/* print list of builtin commands */
237759243Sobrien
237859243Sobrien/*ARGSUSED*/
237959243Sobrienvoid
238059243Sobriendobuiltins(v, c)
238159243SobrienChar **v;
238259243Sobrienstruct command *c;
238359243Sobrien{
238459243Sobrien    /* would use print_by_column() in tw.parse.c but that assumes
238559243Sobrien     * we have an array of Char * to pass.. (sg)
238659243Sobrien     */
238759243Sobrien    extern int Tty_raw_mode;
238859243Sobrien    extern int TermH;		/* from the editor routines */
238959243Sobrien    extern int lbuffed;		/* from sh.print.c */
239059243Sobrien
239159243Sobrien    register struct biltins *b;
239259243Sobrien    register int row, col, columns, rows;
239359243Sobrien    unsigned int w, maxwidth;
239459243Sobrien
239559243Sobrien    USE(c);
239659243Sobrien    USE(v);
239759243Sobrien    lbuffed = 0;		/* turn off line buffering */
239859243Sobrien
239959243Sobrien    /* find widest string */
240059243Sobrien    for (maxwidth = 0, b = bfunc; b < &bfunc[nbfunc]; ++b)
240159243Sobrien	maxwidth = max(maxwidth, strlen(b->bname));
240259243Sobrien    ++maxwidth;					/* for space */
240359243Sobrien
240459243Sobrien    columns = (TermH + 1) / maxwidth;	/* PWP: terminal size change */
240559243Sobrien    if (!columns)
240659243Sobrien	columns = 1;
240759243Sobrien    rows = (nbfunc + (columns - 1)) / columns;
240859243Sobrien
240959243Sobrien    for (b = bfunc, row = 0; row < rows; row++) {
241059243Sobrien	for (col = 0; col < columns; col++) {
241159243Sobrien	    if (b < &bfunc[nbfunc]) {
241259243Sobrien		w = strlen(b->bname);
241359243Sobrien		xprintf("%s", b->bname);
241459243Sobrien		if (col < (columns - 1))	/* Not last column? */
241559243Sobrien		    for (; w < maxwidth; w++)
241659243Sobrien			xputchar(' ');
241759243Sobrien		++b;
241859243Sobrien	    }
241959243Sobrien	}
242059243Sobrien	if (row < (rows - 1)) {
242159243Sobrien	    if (Tty_raw_mode)
242259243Sobrien		xputchar('\r');
242359243Sobrien	    xputchar('\n');
242459243Sobrien	}
242559243Sobrien    }
242669408Sache#ifdef WINNT_NATIVE
242759243Sobrien    nt_print_builtins(maxwidth);
242859243Sobrien#else
242959243Sobrien    if (Tty_raw_mode)
243059243Sobrien	xputchar('\r');
243159243Sobrien    xputchar('\n');
243269408Sache#endif /* WINNT_NATIVE */
243359243Sobrien
243459243Sobrien    lbuffed = 1;		/* turn back on line buffering */
243559243Sobrien    flush();
243659243Sobrien}
243759243Sobrien
243859243Sobrienvoid
243959243Sobriennlsinit()
244059243Sobrien{
244159243Sobrien#ifdef NLS_CATALOGS
244269408Sache    char catalog[ 256 ] = { 't', 'c', 's', 'h', '\0' };
244369408Sache
244469408Sache    if (adrof(STRcatalog) != NULL)
244569408Sache        xsnprintf((char *)catalog, sizeof(catalog), "tcsh.%s",
244669408Sache		  short2str(varval(STRcatalog)));
244769408Sache    catd = catopen(catalog, MCLoadBySet);
244869408Sache#endif /* NLS_CATALOGS */
244969408Sache#ifdef WINNT_NATIVE
245059243Sobrien    nls_dll_init();
245169408Sache#endif /* WINNT_NATIVE */
245259243Sobrien    errinit();		/* init the errorlist in correct locale */
245359243Sobrien    mesginit();		/* init the messages for signals */
245459243Sobrien    dateinit();		/* init the messages for dates */
245559243Sobrien    editinit();		/* init the editor messages */
245659243Sobrien    terminit();		/* init the termcap messages */
245759243Sobrien}
2458