sh.func.c revision 100616
1/* $Header: /src/pub/tcsh/sh.func.c,v 3.103 2002/07/09 12:56:55 christos Exp $ */
2/*
3 * sh.func.c: csh builtin functions
4 */
5/*-
6 * Copyright (c) 1980, 1991 The Regents of the University of California.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33#include "sh.h"
34
35RCSID("$Id: sh.func.c,v 3.103 2002/07/09 12:56:55 christos Exp $")
36
37#include "ed.h"
38#include "tw.h"
39#include "tc.h"
40#ifdef WINNT_NATIVE
41#include "nt.const.h"
42#endif /* WINNT_NATIVE */
43
44/*
45 * C shell
46 */
47extern int just_signaled;
48extern char **environ;
49
50extern bool MapsAreInited;
51extern bool NLSMapsAreInited;
52extern bool NoNLSRebind;
53extern bool GotTermCaps;
54
55static int zlast = -1;
56
57static	void	islogin		__P((void));
58static	void	preread		__P((void));
59static	void	doagain		__P((void));
60static  char   *isrchx		__P((int));
61static	void	search		__P((int, int, Char *));
62static	int	getword		__P((Char *));
63static	void	toend		__P((void));
64static	void	xecho		__P((int, Char **));
65static	bool	islocale_var	__P((Char *));
66
67struct biltins *
68isbfunc(t)
69    struct command *t;
70{
71    register Char *cp = t->t_dcom[0];
72    register struct biltins *bp, *bp1, *bp2;
73    static struct biltins label = {"", dozip, 0, 0};
74    static struct biltins foregnd = {"%job", dofg1, 0, 0};
75    static struct biltins backgnd = {"%job &", dobg1, 0, 0};
76
77    /*
78     * We never match a builtin that has quoted the first
79     * character; this has been the traditional way to escape
80     * builtin commands.
81     */
82    if (*cp & QUOTE)
83	return NULL;
84
85    if (*cp != ':' && lastchr(cp) == ':') {
86	label.bname = short2str(cp);
87	return (&label);
88    }
89    if (*cp == '%') {
90	if (t->t_dflg & F_AMPERSAND) {
91	    t->t_dflg &= ~F_AMPERSAND;
92	    backgnd.bname = short2str(cp);
93	    return (&backgnd);
94	}
95	foregnd.bname = short2str(cp);
96	return (&foregnd);
97    }
98#ifdef WARP
99    /*
100     * This is a perhaps kludgy way to determine if the warp builtin is to be
101     * acknowledged or not.  If checkwarp() fails, then we are to assume that
102     * the warp command is invalid, and carry on as we would handle any other
103     * non-builtin command.         -- JDK 2/4/88
104     */
105    if (eq(STRwarp, cp) && !checkwarp()) {
106	return (0);		/* this builtin disabled */
107    }
108#endif /* WARP */
109    /*
110     * Binary search Bp1 is the beginning of the current search range. Bp2 is
111     * one past the end.
112     */
113    for (bp1 = bfunc, bp2 = bfunc + nbfunc; bp1 < bp2;) {
114	int i;
115
116	bp = bp1 + ((bp2 - bp1) >> 1);
117	if ((i = ((char) *cp) - *bp->bname) == 0 &&
118	    (i = StrQcmp(cp, str2short(bp->bname))) == 0)
119	    return bp;
120	if (i < 0)
121	    bp2 = bp;
122	else
123	    bp1 = bp + 1;
124    }
125#ifdef WINNT_NATIVE
126    return nt_check_additional_builtins(cp);
127#endif /*WINNT_NATIVE*/
128    return (0);
129}
130
131void
132func(t, bp)
133    register struct command *t;
134    register struct biltins *bp;
135{
136    int     i;
137
138    xechoit(t->t_dcom);
139    setname(bp->bname);
140    i = blklen(t->t_dcom) - 1;
141    if (i < bp->minargs)
142	stderror(ERR_NAME | ERR_TOOFEW);
143    if (i > bp->maxargs)
144	stderror(ERR_NAME | ERR_TOOMANY);
145    (*bp->bfunct) (t->t_dcom, t);
146}
147
148/*ARGSUSED*/
149void
150doonintr(v, c)
151    Char  **v;
152    struct command *c;
153{
154    register Char *cp;
155    register Char *vv = v[1];
156
157    USE(c);
158    if (parintr == SIG_IGN)
159	return;
160    if (setintr && intty)
161	stderror(ERR_NAME | ERR_TERMINAL);
162    cp = gointr;
163    gointr = 0;
164    xfree((ptr_t) cp);
165    if (vv == 0) {
166#ifdef BSDSIGS
167	if (setintr) {
168	    (void) sigblock(sigmask(SIGINT));
169	    (void) signal(SIGINT, pintr);
170	}
171	else
172	    (void) signal(SIGINT, SIG_DFL);
173#else /* !BSDSIGS */
174	if (setintr) {
175	    (void) sighold(SIGINT);
176	    (void) sigset(SIGINT, pintr);
177	}
178	else
179	    (void) sigset(SIGINT, SIG_DFL);
180#endif /* BSDSIGS */
181	gointr = 0;
182    }
183    else if (eq((vv = strip(vv)), STRminus)) {
184#ifdef BSDSIGS
185	(void) signal(SIGINT, SIG_IGN);
186#else /* !BSDSIGS */
187	(void) sigset(SIGINT, SIG_IGN);
188#endif /* BSDSIGS */
189	gointr = Strsave(STRminus);
190    }
191    else {
192	gointr = Strsave(vv);
193#ifdef BSDSIGS
194	(void) signal(SIGINT, pintr);
195#else /* !BSDSIGS */
196	(void) sigset(SIGINT, pintr);
197#endif /* BSDSIGS */
198    }
199}
200
201/*ARGSUSED*/
202void
203donohup(v, c)
204    Char **v;
205    struct command *c;
206{
207    USE(c);
208    USE(v);
209    if (intty)
210	stderror(ERR_NAME | ERR_TERMINAL);
211    if (setintr == 0) {
212	(void) signal(SIGHUP, SIG_IGN);
213#ifdef CC
214	submit(getpid());
215#endif /* CC */
216    }
217}
218
219/*ARGSUSED*/
220void
221dohup(v, c)
222    Char **v;
223    struct command *c;
224{
225    USE(c);
226    USE(v);
227    if (intty)
228	stderror(ERR_NAME | ERR_TERMINAL);
229    if (setintr == 0)
230	(void) signal(SIGHUP, SIG_DFL);
231}
232
233
234/*ARGSUSED*/
235void
236dozip(v, c)
237    Char **v;
238    struct command *c;
239{
240    USE(c);
241    USE(v);
242}
243
244/*ARGSUSED*/
245void
246dofiletest(v, c)
247    Char **v;
248    struct command *c;
249{
250    Char **fileptr, *ftest, *res;
251
252    if (*(ftest = *++v) != '-')
253	stderror(ERR_NAME | ERR_FILEINQ);
254    ++v;
255
256    gflag = 0;
257    tglob(v);
258    if (gflag) {
259	v = globall(v);
260	if (v == 0)
261	    stderror(ERR_NAME | ERR_NOMATCH);
262    }
263    else
264	v = gargv = saveblk(v);
265    trim(v);
266
267    while (*(fileptr = v++) != '\0') {
268	xprintf("%S", res = filetest(ftest, &fileptr, 0));
269	xfree((ptr_t) res);
270	if (*v)
271	    xprintf(" ");
272    }
273    xprintf("\n");
274
275    if (gargv) {
276	blkfree(gargv);
277	gargv = 0;
278    }
279}
280
281void
282prvars()
283{
284    plist(&shvhed, VAR_ALL);
285}
286
287/*ARGSUSED*/
288void
289doalias(v, c)
290    register Char **v;
291    struct command *c;
292{
293    register struct varent *vp;
294    register Char *p;
295
296    USE(c);
297    v++;
298    p = *v++;
299    if (p == 0)
300	plist(&aliases, VAR_ALL);
301    else if (*v == 0) {
302	vp = adrof1(strip(p), &aliases);
303	if (vp && vp->vec)
304	    blkpr(vp->vec), xputchar('\n');
305    }
306    else {
307	if (eq(p, STRalias) || eq(p, STRunalias)) {
308	    setname(short2str(p));
309	    stderror(ERR_NAME | ERR_DANGER);
310	}
311	set1(strip(p), saveblk(v), &aliases, VAR_READWRITE);
312	tw_cmd_free();
313    }
314}
315
316/*ARGSUSED*/
317void
318unalias(v, c)
319    Char  **v;
320    struct command *c;
321{
322    USE(c);
323    unset1(v, &aliases);
324    tw_cmd_free();
325}
326
327/*ARGSUSED*/
328void
329dologout(v, c)
330    Char **v;
331    struct command *c;
332{
333    USE(c);
334    USE(v);
335    islogin();
336    goodbye(NULL, NULL);
337}
338
339/*ARGSUSED*/
340void
341dologin(v, c)
342    Char  **v;
343    struct command *c;
344{
345    USE(c);
346#ifdef WINNT_NATIVE
347    USE(v);
348#else /* !WINNT_NATIVE */
349    islogin();
350    rechist(NULL, adrof(STRsavehist) != NULL);
351    (void) signal(SIGTERM, parterm);
352    (void) execl(_PATH_BIN_LOGIN, "login", short2str(v[1]), NULL);
353    (void) execl(_PATH_USRBIN_LOGIN, "login", short2str(v[1]), NULL);
354    untty();
355    xexit(1);
356#endif /* !WINNT_NATIVE */
357}
358
359
360#ifdef NEWGRP
361/*ARGSUSED*/
362void
363donewgrp(v, c)
364    Char  **v;
365    struct command *c;
366{
367    char **p;
368    if (chkstop == 0 && setintr)
369	panystop(0);
370    (void) signal(SIGTERM, parterm);
371    p = short2blk(v);
372    /*
373     * From Beto Appleton (beto@aixwiz.austin.ibm.com)
374     * Newgrp can take 2 arguments...
375     */
376    (void) execv(_PATH_BIN_NEWGRP, p);
377    (void) execv(_PATH_USRBIN_NEWGRP, p);
378    blkfree((Char **) p);
379    untty();
380    xexit(1);
381}
382#endif /* NEWGRP */
383
384static void
385islogin()
386{
387    if (chkstop == 0 && setintr)
388	panystop(0);
389    if (loginsh)
390	return;
391    stderror(ERR_NOTLOGIN);
392}
393
394void
395doif(v, kp)
396    Char  **v;
397    struct command *kp;
398{
399    register int i;
400    register Char **vv;
401
402    v++;
403    i = expr(&v);
404    vv = v;
405    if (*vv == NULL)
406	stderror(ERR_NAME | ERR_EMPTYIF);
407    if (eq(*vv, STRthen)) {
408	if (*++vv)
409	    stderror(ERR_NAME | ERR_IMPRTHEN);
410	setname(short2str(STRthen));
411	/*
412	 * If expression was zero, then scan to else , otherwise just fall into
413	 * following code.
414	 */
415	if (!i)
416	    search(TC_IF, 0, NULL);
417	return;
418    }
419    /*
420     * Simple command attached to this if. Left shift the node in this tree,
421     * munging it so we can reexecute it.
422     */
423    if (i) {
424	lshift(kp->t_dcom, vv - kp->t_dcom);
425	reexecute(kp);
426	donefds();
427    }
428}
429
430/*
431 * Reexecute a command, being careful not
432 * to redo i/o redirection, which is already set up.
433 */
434void
435reexecute(kp)
436    register struct command *kp;
437{
438    kp->t_dflg &= F_SAVE;
439    kp->t_dflg |= F_REPEAT;
440    /*
441     * If tty is still ours to arbitrate, arbitrate it; otherwise dont even set
442     * pgrp's as the jobs would then have no way to get the tty (we can't give
443     * it to them, and our parent wouldn't know their pgrp, etc.
444     */
445    execute(kp, (tpgrp > 0 ? tpgrp : -1), NULL, NULL, TRUE);
446}
447
448/*ARGSUSED*/
449void
450doelse (v, c)
451    Char **v;
452    struct command *c;
453{
454    USE(c);
455    USE(v);
456    search(TC_ELSE, 0, NULL);
457}
458
459/*ARGSUSED*/
460void
461dogoto(v, c)
462    Char  **v;
463    struct command *c;
464{
465    Char   *lp;
466
467    USE(c);
468    gotolab(lp = globone(v[1], G_ERROR));
469    xfree((ptr_t) lp);
470}
471
472void
473gotolab(lab)
474    Char *lab;
475{
476    register struct whyle *wp;
477    /*
478     * While we still can, locate any unknown ends of existing loops. This
479     * obscure code is the WORST result of the fact that we don't really parse.
480     */
481    zlast = TC_GOTO;
482    for (wp = whyles; wp; wp = wp->w_next)
483	if (wp->w_end.type == TCSH_F_SEEK && wp->w_end.f_seek == 0) {
484	    search(TC_BREAK, 0, NULL);
485	    btell(&wp->w_end);
486	}
487	else {
488	    bseek(&wp->w_end);
489	}
490    search(TC_GOTO, 0, lab);
491    /*
492     * Eliminate loops which were exited.
493     */
494    wfree();
495}
496
497/*ARGSUSED*/
498void
499doswitch(v, c)
500    register Char **v;
501    struct command *c;
502{
503    register Char *cp, *lp;
504
505    USE(c);
506    v++;
507    if (!*v || *(*v++) != '(')
508	stderror(ERR_SYNTAX);
509    cp = **v == ')' ? STRNULL : *v++;
510    if (*(*v++) != ')')
511	v--;
512    if (*v)
513	stderror(ERR_SYNTAX);
514    search(TC_SWITCH, 0, lp = globone(cp, G_ERROR));
515    xfree((ptr_t) lp);
516}
517
518/*ARGSUSED*/
519void
520dobreak(v, c)
521    Char **v;
522    struct command *c;
523{
524    USE(v);
525    USE(c);
526    if (whyles)
527	toend();
528    else
529	stderror(ERR_NAME | ERR_NOTWHILE);
530}
531
532/*ARGSUSED*/
533void
534doexit(v, c)
535    Char  **v;
536    struct command *c;
537{
538    USE(c);
539
540    if (chkstop == 0 && (intty || intact) && evalvec == 0)
541	panystop(0);
542    /*
543     * Don't DEMAND parentheses here either.
544     */
545    v++;
546    if (*v) {
547	set(STRstatus, putn(expr(&v)), VAR_READWRITE);
548	if (*v)
549	    stderror(ERR_NAME | ERR_EXPRESSION);
550    }
551    btoeof();
552#if 0
553    if (intty)
554#endif
555    /* Always close, why only on ttys? */
556	(void) close(SHIN);
557}
558
559/*ARGSUSED*/
560void
561doforeach(v, c)
562    register Char **v;
563    struct command *c;
564{
565    register Char *cp, *sp;
566    register struct whyle *nwp;
567
568    USE(c);
569    v++;
570    sp = cp = strip(*v);
571    if (!letter(*sp))
572	stderror(ERR_NAME | ERR_VARBEGIN);
573    while (*cp && alnum(*cp))
574	cp++;
575    if (*cp)
576	stderror(ERR_NAME | ERR_VARALNUM);
577    if ((cp - sp) > MAXVARLEN)
578	stderror(ERR_NAME | ERR_VARTOOLONG);
579    cp = *v++;
580    if (v[0][0] != '(' || v[blklen(v) - 1][0] != ')')
581	stderror(ERR_NAME | ERR_NOPAREN);
582    v++;
583    gflag = 0, tglob(v);
584    if (gflag) {
585	v = globall(v);
586	if (v == 0)
587	    stderror(ERR_NAME | ERR_NOMATCH);
588    }
589    else {
590	v = gargv = saveblk(v);
591	trim(v);
592    }
593    nwp = (struct whyle *) xcalloc(1, sizeof *nwp);
594    nwp->w_fe = nwp->w_fe0 = v;
595    gargv = 0;
596    btell(&nwp->w_start);
597    nwp->w_fename = Strsave(cp);
598    nwp->w_next = whyles;
599    nwp->w_end.type = TCSH_F_SEEK;
600    whyles = nwp;
601    /*
602     * Pre-read the loop so as to be more comprehensible to a terminal user.
603     */
604    zlast = TC_FOREACH;
605    if (intty)
606	preread();
607    doagain();
608}
609
610/*ARGSUSED*/
611void
612dowhile(v, c)
613    Char  **v;
614    struct command *c;
615{
616    register int status;
617    register bool again = whyles != 0 &&
618			  SEEKEQ(&whyles->w_start, &lineloc) &&
619			  whyles->w_fename == 0;
620
621    USE(c);
622    v++;
623    /*
624     * Implement prereading here also, taking care not to evaluate the
625     * expression before the loop has been read up from a terminal.
626     */
627    if (intty && !again)
628	status = !exp0(&v, 1);
629    else
630	status = !expr(&v);
631    if (*v)
632	stderror(ERR_NAME | ERR_EXPRESSION);
633    if (!again) {
634	register struct whyle *nwp =
635	(struct whyle *) xcalloc(1, sizeof(*nwp));
636
637	nwp->w_start = lineloc;
638	nwp->w_end.type = TCSH_F_SEEK;
639	nwp->w_end.f_seek = 0;
640	nwp->w_next = whyles;
641	whyles = nwp;
642	zlast = TC_WHILE;
643	if (intty) {
644	    /*
645	     * The tty preread
646	     */
647	    preread();
648	    doagain();
649	    return;
650	}
651    }
652    if (status)
653	/* We ain't gonna loop no more, no more! */
654	toend();
655}
656
657static void
658preread()
659{
660    whyles->w_end.type = TCSH_I_SEEK;
661    if (setintr)
662#ifdef BSDSIGS
663	(void) sigsetmask(sigblock((sigmask_t) 0) & ~sigmask(SIGINT));
664#else /* !BSDSIGS */
665	(void) sigrelse (SIGINT);
666#endif /* BSDSIGS */
667    search(TC_BREAK, 0, NULL);		/* read the expression in */
668    if (setintr)
669#ifdef BSDSIGS
670	(void) sigblock(sigmask(SIGINT));
671#else /* !BSDSIGS */
672	(void) sighold(SIGINT);
673#endif /* BSDSIGS */
674    btell(&whyles->w_end);
675}
676
677/*ARGSUSED*/
678void
679doend(v, c)
680    Char **v;
681    struct command *c;
682{
683    USE(v);
684    USE(c);
685    if (!whyles)
686	stderror(ERR_NAME | ERR_NOTWHILE);
687    btell(&whyles->w_end);
688    doagain();
689}
690
691/*ARGSUSED*/
692void
693docontin(v, c)
694    Char **v;
695    struct command *c;
696{
697    USE(v);
698    USE(c);
699    if (!whyles)
700	stderror(ERR_NAME | ERR_NOTWHILE);
701    doagain();
702}
703
704static void
705doagain()
706{
707    /* Repeating a while is simple */
708    if (whyles->w_fename == 0) {
709	bseek(&whyles->w_start);
710	return;
711    }
712    /*
713     * The foreach variable list actually has a spurious word ")" at the end of
714     * the w_fe list.  Thus we are at the of the list if one word beyond this
715     * is 0.
716     */
717    if (!whyles->w_fe[1]) {
718	dobreak(NULL, NULL);
719	return;
720    }
721    set(whyles->w_fename, quote(Strsave(*whyles->w_fe++)), VAR_READWRITE);
722    bseek(&whyles->w_start);
723}
724
725void
726dorepeat(v, kp)
727    Char  **v;
728    struct command *kp;
729{
730    int i = 1;
731
732#ifdef BSDSIGS
733    register sigmask_t omask = 0;
734#endif /* BSDSIGS */
735
736    do {
737	i *= getn(v[1]);
738	lshift(v, 2);
739    } while (v[0] != NULL && Strcmp(v[0], STRrepeat) == 0);
740
741    if (setintr)
742#ifdef BSDSIGS
743	omask = sigblock(sigmask(SIGINT)) & ~sigmask(SIGINT);
744#else /* !BSDSIGS */
745	(void) sighold(SIGINT);
746#endif /* BSDSIGS */
747    while (i > 0) {
748	if (setintr)
749#ifdef BSDSIGS
750	    (void) sigsetmask(omask);
751#else /* !BSDSIGS */
752	    (void) sigrelse (SIGINT);
753#endif /* BSDSIGS */
754	reexecute(kp);
755	--i;
756    }
757    donefds();
758    if (setintr)
759#ifdef BSDSIGS
760	(void) sigsetmask(omask);
761#else /* !BSDSIGS */
762	(void) sigrelse (SIGINT);
763#endif /* BSDSIGS */
764}
765
766/*ARGSUSED*/
767void
768doswbrk(v, c)
769    Char **v;
770    struct command *c;
771{
772    USE(v);
773    USE(c);
774    search(TC_BRKSW, 0, NULL);
775}
776
777int
778srchx(cp)
779    Char *cp;
780{
781    struct srch *sp, *sp1, *sp2;
782    int i;
783
784    /*
785     * Ignore keywords inside heredocs
786     */
787    if (inheredoc)
788	return -1;
789
790    /*
791     * Binary search Sp1 is the beginning of the current search range. Sp2 is
792     * one past the end.
793     */
794    for (sp1 = srchn, sp2 = srchn + nsrchn; sp1 < sp2;) {
795	sp = sp1 + ((sp2 - sp1) >> 1);
796	if ((i = *cp - *sp->s_name) == 0 &&
797	    (i = Strcmp(cp, str2short(sp->s_name))) == 0)
798	    return sp->s_value;
799	if (i < 0)
800	    sp2 = sp;
801	else
802	    sp1 = sp + 1;
803    }
804    return (-1);
805}
806
807static char *
808isrchx(n)
809    register int n;
810{
811    register struct srch *sp, *sp2;
812
813    for (sp = srchn, sp2 = srchn + nsrchn; sp < sp2; sp++)
814	if (sp->s_value == n)
815	    return (sp->s_name);
816    return ("");
817}
818
819
820static Char Stype;
821static Char *Sgoal;
822
823static void
824search(type, level, goal)
825    int     type;
826    register int level;
827    Char   *goal;
828{
829    Char    wordbuf[BUFSIZE];
830    register Char *aword = wordbuf;
831    register Char *cp;
832
833    Stype = (Char) type;
834    Sgoal = goal;
835    if (type == TC_GOTO) {
836	struct Ain a;
837	a.type = TCSH_F_SEEK;
838	a.f_seek = 0;
839	bseek(&a);
840    }
841    do {
842	if (intty && fseekp == feobp && aret == TCSH_F_SEEK)
843	    printprompt(1, isrchx(type == TC_BREAK ? zlast : type));
844	/* xprintf("? "), flush(); */
845	aword[0] = 0;
846	(void) getword(aword);
847	switch (srchx(aword)) {
848
849	case TC_ELSE:
850	    if (level == 0 && type == TC_IF)
851		return;
852	    break;
853
854	case TC_IF:
855	    while (getword(aword))
856		continue;
857	    if ((type == TC_IF || type == TC_ELSE) &&
858		eq(aword, STRthen))
859		level++;
860	    break;
861
862	case TC_ENDIF:
863	    if (type == TC_IF || type == TC_ELSE)
864		level--;
865	    break;
866
867	case TC_FOREACH:
868	case TC_WHILE:
869	    if (type == TC_BREAK)
870		level++;
871	    break;
872
873	case TC_END:
874	    if (type == TC_BREAK)
875		level--;
876	    break;
877
878	case TC_SWITCH:
879	    if (type == TC_SWITCH || type == TC_BRKSW)
880		level++;
881	    break;
882
883	case TC_ENDSW:
884	    if (type == TC_SWITCH || type == TC_BRKSW)
885		level--;
886	    break;
887
888	case TC_LABEL:
889	    if (type == TC_GOTO && getword(aword) && eq(aword, goal))
890		level = -1;
891	    break;
892
893	default:
894	    if (type != TC_GOTO && (type != TC_SWITCH || level != 0))
895		break;
896	    if (lastchr(aword) != ':')
897		break;
898	    aword[Strlen(aword) - 1] = 0;
899	    if ((type == TC_GOTO && eq(aword, goal)) ||
900		(type == TC_SWITCH && eq(aword, STRdefault)))
901		level = -1;
902	    break;
903
904	case TC_CASE:
905	    if (type != TC_SWITCH || level != 0)
906		break;
907	    (void) getword(aword);
908	    if (lastchr(aword) == ':')
909		aword[Strlen(aword) - 1] = 0;
910	    cp = strip(Dfix1(aword));
911	    if (Gmatch(goal, cp))
912		level = -1;
913	    xfree((ptr_t) cp);
914	    break;
915
916	case TC_DEFAULT:
917	    if (type == TC_SWITCH && level == 0)
918		level = -1;
919	    break;
920	}
921	(void) getword(NULL);
922    } while (level >= 0);
923}
924
925static int
926getword(wp)
927    register Char *wp;
928{
929    int found = 0, first;
930    int c, d;
931
932    c = readc(1);
933    d = 0;
934    do {
935	while (c == ' ' || c == '\t')
936	    c = readc(1);
937	if (c == '#')
938	    do
939		c = readc(1);
940	    while (c >= 0 && c != '\n');
941	if (c < 0)
942	    goto past;
943	if (c == '\n') {
944	    if (wp)
945		break;
946	    return (0);
947	}
948	unreadc(c);
949	found = 1;
950	first = 1;
951	do {
952	    c = readc(1);
953	    if (c == '\\' && (c = readc(1)) == '\n')
954		c = ' ';
955	    if (c == '\'' || c == '"') {
956		if (d == 0)
957		    d = c;
958		else if (d == c)
959		    d = 0;
960	    }
961	    if (c < 0)
962		goto past;
963	    if (wp) {
964		*wp++ = (Char) c;
965		*wp = '\0';
966	    }
967	    if (!first && !d && c == '(') {
968		if (wp) {
969		    unreadc(c);
970		    *--wp = '\0';
971		    return found;
972		}
973		else
974		    break;
975	    }
976	    first = 0;
977	} while ((d || (c != ' ' && c != '\t')) && c != '\n');
978    } while (wp == 0);
979
980    unreadc(c);
981    if (found)
982	*--wp = '\0';
983
984    return (found);
985
986past:
987    switch (Stype) {
988
989    case TC_IF:
990	stderror(ERR_NAME | ERR_NOTFOUND, "then/endif");
991	break;
992
993    case TC_ELSE:
994	stderror(ERR_NAME | ERR_NOTFOUND, "endif");
995	break;
996
997    case TC_BRKSW:
998    case TC_SWITCH:
999	stderror(ERR_NAME | ERR_NOTFOUND, "endsw");
1000	break;
1001
1002    case TC_BREAK:
1003	stderror(ERR_NAME | ERR_NOTFOUND, "end");
1004	break;
1005
1006    case TC_GOTO:
1007	setname(short2str(Sgoal));
1008	stderror(ERR_NAME | ERR_NOTFOUND, "label");
1009	break;
1010
1011    default:
1012	break;
1013    }
1014    /* NOTREACHED */
1015    return (0);
1016}
1017
1018static void
1019toend()
1020{
1021    if (whyles->w_end.type == TCSH_F_SEEK && whyles->w_end.f_seek == 0) {
1022	search(TC_BREAK, 0, NULL);
1023	btell(&whyles->w_end);
1024	whyles->w_end.f_seek--;
1025    }
1026    else {
1027	bseek(&whyles->w_end);
1028    }
1029    wfree();
1030}
1031
1032void
1033wfree()
1034{
1035    struct Ain    o;
1036    struct whyle *nwp;
1037#ifdef lint
1038    nwp = NULL;	/* sun lint is dumb! */
1039#endif
1040
1041#ifdef FDEBUG
1042    static char foo[] = "IAFE";
1043#endif /* FDEBUG */
1044
1045    btell(&o);
1046
1047#ifdef FDEBUG
1048    xprintf("o->type %c o->a_seek %d o->f_seek %d\n",
1049	    foo[o.type + 1], o.a_seek, o.f_seek);
1050#endif /* FDEBUG */
1051
1052    for (; whyles; whyles = nwp) {
1053	register struct whyle *wp = whyles;
1054	nwp = wp->w_next;
1055
1056#ifdef FDEBUG
1057	xprintf("start->type %c start->a_seek %d start->f_seek %d\n",
1058		foo[wp->w_start.type+1],
1059		wp->w_start.a_seek, wp->w_start.f_seek);
1060	xprintf("end->type %c end->a_seek %d end->f_seek %d\n",
1061		foo[wp->w_end.type + 1], wp->w_end.a_seek, wp->w_end.f_seek);
1062#endif /* FDEBUG */
1063
1064	/*
1065	 * XXX: We free loops that have different seek types.
1066	 */
1067	if (wp->w_end.type != TCSH_I_SEEK && wp->w_start.type == wp->w_end.type &&
1068	    wp->w_start.type == o.type) {
1069	    if (wp->w_end.type == TCSH_F_SEEK) {
1070		if (o.f_seek >= wp->w_start.f_seek &&
1071		    (wp->w_end.f_seek == 0 || o.f_seek < wp->w_end.f_seek))
1072		    break;
1073	    }
1074	    else {
1075		if (o.a_seek >= wp->w_start.a_seek &&
1076		    (wp->w_end.a_seek == 0 || o.a_seek < wp->w_end.a_seek))
1077		    break;
1078	    }
1079	}
1080
1081	if (wp->w_fe0)
1082	    blkfree(wp->w_fe0);
1083	if (wp->w_fename)
1084	    xfree((ptr_t) wp->w_fename);
1085	xfree((ptr_t) wp);
1086    }
1087}
1088
1089/*ARGSUSED*/
1090void
1091doecho(v, c)
1092    Char  **v;
1093    struct command *c;
1094{
1095    USE(c);
1096    xecho(' ', v);
1097}
1098
1099/*ARGSUSED*/
1100void
1101doglob(v, c)
1102    Char  **v;
1103    struct command *c;
1104{
1105    USE(c);
1106    xecho(0, v);
1107    flush();
1108}
1109
1110static void
1111xecho(sep, v)
1112    int    sep;
1113    register Char **v;
1114{
1115    register Char *cp;
1116    int     nonl = 0;
1117#ifdef ECHO_STYLE
1118    int	    echo_style = ECHO_STYLE;
1119#else /* !ECHO_STYLE */
1120# if SYSVREL > 0
1121    int	    echo_style = SYSV_ECHO;
1122# else /* SYSVREL == 0 */
1123    int	    echo_style = BSD_ECHO;
1124# endif /* SYSVREL */
1125#endif /* ECHO_STYLE */
1126    struct varent *vp;
1127
1128    if ((vp = adrof(STRecho_style)) != NULL && vp->vec != NULL &&
1129	vp->vec[0] != NULL) {
1130	if (Strcmp(vp->vec[0], STRbsd) == 0)
1131	    echo_style = BSD_ECHO;
1132	else if (Strcmp(vp->vec[0], STRsysv) == 0)
1133	    echo_style = SYSV_ECHO;
1134	else if (Strcmp(vp->vec[0], STRboth) == 0)
1135	    echo_style = BOTH_ECHO;
1136	else if (Strcmp(vp->vec[0], STRnone) == 0)
1137	    echo_style = NONE_ECHO;
1138    }
1139
1140    if (setintr)
1141#ifdef BSDSIGS
1142	(void) sigsetmask(sigblock((sigmask_t) 0) & ~sigmask(SIGINT));
1143#else /* !BSDSIGS */
1144	(void) sigrelse (SIGINT);
1145#endif /* BSDSIGS */
1146    v++;
1147    if (*v == 0)
1148	goto done;
1149    gflag = 0, tglob(v);
1150    if (gflag) {
1151	v = globall(v);
1152	if (v == 0)
1153	    stderror(ERR_NAME | ERR_NOMATCH);
1154    }
1155    else {
1156	v = gargv = saveblk(v);
1157	trim(v);
1158    }
1159
1160    if ((echo_style & BSD_ECHO) != 0 && sep == ' ' && *v && eq(*v, STRmn))
1161	nonl++, v++;
1162
1163    while ((cp = *v++) != 0) {
1164	register int c;
1165
1166	while ((c = *cp++) != 0) {
1167	    if ((echo_style & SYSV_ECHO) != 0 && c == '\\') {
1168		switch (c = *cp++) {
1169		case 'a':
1170		    c = '\a';
1171		    break;
1172		case 'b':
1173		    c = '\b';
1174		    break;
1175		case 'c':
1176		    nonl = 1;
1177		    goto done;
1178		case 'e':
1179#if 0			/* Windows does not understand \e */
1180		    c = '\e';
1181#else
1182		    c = '\033';
1183#endif
1184		    break;
1185		case 'f':
1186		    c = '\f';
1187		    break;
1188		case 'n':
1189		    c = '\n';
1190		    break;
1191		case 'r':
1192		    c = '\r';
1193		    break;
1194		case 't':
1195		    c = '\t';
1196		    break;
1197		case 'v':
1198		    c = '\v';
1199		    break;
1200		case '\\':
1201		    c = '\\';
1202		    break;
1203		case '0':
1204		    c = 0;
1205		    if (*cp >= '0' && *cp < '8')
1206			c = c * 8 + *cp++ - '0';
1207		    if (*cp >= '0' && *cp < '8')
1208			c = c * 8 + *cp++ - '0';
1209		    if (*cp >= '0' && *cp < '8')
1210			c = c * 8 + *cp++ - '0';
1211		    break;
1212		case '\0':
1213		    c = '\\';
1214		    cp--;
1215		    break;
1216		default:
1217		    xputchar('\\' | QUOTE);
1218		    break;
1219		}
1220	    }
1221	    xputchar(c | QUOTE);
1222
1223	}
1224	if (*v)
1225	    xputchar(sep | QUOTE);
1226    }
1227done:
1228    if (sep && nonl == 0)
1229	xputchar('\n');
1230    else
1231	flush();
1232    if (setintr)
1233#ifdef BSDSIGS
1234	(void) sigblock(sigmask(SIGINT));
1235#else /* !BSDSIGS */
1236	(void) sighold(SIGINT);
1237#endif /* BSDSIGS */
1238    if (gargv)
1239	blkfree(gargv), gargv = 0;
1240}
1241
1242/* check whether an environment variable should invoke 'set_locale()' */
1243static bool
1244islocale_var(var)
1245    Char *var;
1246{
1247    static Char *locale_vars[] = {
1248	STRLANG,	STRLC_CTYPE,	STRLC_NUMERIC,	STRLC_TIME,
1249	STRLC_COLLATE,	STRLC_MESSAGES,	STRLC_MONETARY, 0
1250    };
1251    register Char **v;
1252
1253    for (v = locale_vars; *v; ++v)
1254	if (eq(var, *v))
1255	    return 1;
1256    return 0;
1257}
1258
1259/*ARGSUSED*/
1260void
1261doprintenv(v, c)
1262    register Char **v;
1263    struct command *c;
1264{
1265    Char   *e;
1266    extern bool output_raw;
1267    extern bool xlate_cr;
1268
1269    USE(c);
1270    if (setintr)
1271#ifdef BSDSIGS
1272	(void) sigsetmask(sigblock((sigmask_t) 0) & ~sigmask(SIGINT));
1273#else /* !BSDSIGS */
1274	(void) sigrelse (SIGINT);
1275#endif /* BSDSIGS */
1276
1277    v++;
1278    if (*v == 0) {
1279	register Char **ep;
1280
1281	xlate_cr = 1;
1282	for (ep = STR_environ; *ep; ep++)
1283	    xprintf("%S\n", *ep);
1284	xlate_cr = 0;
1285    }
1286    else if ((e = tgetenv(*v)) != NULL) {
1287	output_raw = 1;
1288	xprintf("%S\n", e);
1289	output_raw = 0;
1290    }
1291    else
1292	set(STRstatus, Strsave(STR1), VAR_READWRITE);
1293}
1294
1295/* from "Karl Berry." <karl%mote.umb.edu@relay.cs.net> -- for NeXT things
1296   (and anything else with a modern compiler) */
1297
1298/*ARGSUSED*/
1299void
1300dosetenv(v, c)
1301    register Char **v;
1302    struct command *c;
1303{
1304    Char   *vp, *lp;
1305
1306    USE(c);
1307    if (*++v == 0) {
1308	doprintenv(--v, 0);
1309	return;
1310    }
1311
1312    vp = *v++;
1313
1314    lp = vp;
1315    if (!letter(*lp))
1316        stderror(ERR_NAME | ERR_VARBEGIN);
1317
1318    for (; alnum(*lp); lp++)
1319        continue;
1320
1321    if (*lp != '\0')
1322	stderror(ERR_NAME | ERR_SYNTAX);
1323
1324    if ((lp = *v++) == 0)
1325	lp = STRNULL;
1326
1327    tsetenv(vp, lp = globone(lp, G_APPEND));
1328    if (eq(vp, STRKPATH)) {
1329	importpath(lp);
1330	dohash(NULL, NULL);
1331	xfree((ptr_t) lp);
1332	return;
1333    }
1334
1335#ifdef apollo
1336    if (eq(vp, STRSYSTYPE)) {
1337	dohash(NULL, NULL);
1338	xfree((ptr_t) lp);
1339	return;
1340    }
1341#endif /* apollo */
1342
1343    /* dspkanji/dspmbyte autosetting */
1344    /* PATCH IDEA FROM Issei.Suzuki VERY THANKS */
1345#if defined(DSPMBYTE)
1346    if(eq(vp, STRLANG) && !adrof(CHECK_MBYTEVAR)) {
1347	autoset_dspmbyte(lp);
1348    }
1349#endif
1350
1351    if (islocale_var(vp)) {
1352#ifdef NLS
1353	int     k;
1354
1355# ifdef SETLOCALEBUG
1356	dont_free = 1;
1357# endif /* SETLOCALEBUG */
1358	(void) setlocale(LC_ALL, "");
1359# ifdef LC_COLLATE
1360	(void) setlocale(LC_COLLATE, "");
1361# endif
1362# ifdef NLS_CATALOGS
1363#  ifdef LC_MESSAGES
1364	(void) setlocale(LC_MESSAGES, "");
1365#  endif /* LC_MESSAGES */
1366	(void) catclose(catd);
1367	nlsinit();
1368# endif /* NLS_CATALOGS */
1369# ifdef LC_CTYPE
1370	(void) setlocale(LC_CTYPE, ""); /* for iscntrl */
1371# endif /* LC_CTYPE */
1372# ifdef SETLOCALEBUG
1373	dont_free = 0;
1374# endif /* SETLOCALEBUG */
1375# ifdef STRCOLLBUG
1376	fix_strcoll_bug();
1377# endif /* STRCOLLBUG */
1378	tw_cmd_free();	/* since the collation sequence has changed */
1379	for (k = 0200; k <= 0377 && !Isprint(k); k++)
1380	    continue;
1381	AsciiOnly = k > 0377;
1382#else /* !NLS */
1383	AsciiOnly = 0;
1384#endif /* NLS */
1385	NLSMapsAreInited = 0;
1386	ed_Init();
1387	if (MapsAreInited && !NLSMapsAreInited)
1388	    ed_InitNLSMaps();
1389	xfree((ptr_t) lp);
1390	return;
1391    }
1392
1393#ifdef NLS_CATALOGS
1394    if (eq(vp, STRNLSPATH)) {
1395	(void) catclose(catd);
1396	nlsinit();
1397    }
1398#endif
1399
1400    if (eq(vp, STRNOREBIND)) {
1401	NoNLSRebind = 1;
1402	MapsAreInited = 0;
1403	NLSMapsAreInited = 0;
1404	ed_InitMaps();
1405	xfree((ptr_t) lp);
1406	return;
1407    }
1408#ifdef WINNT_NATIVE
1409    if (eq(vp, STRtcshlang)) {
1410	nlsinit();
1411	xfree((ptr_t) lp);
1412	return;
1413    }
1414#endif /* WINNT_NATIVE */
1415    if (eq(vp, STRKTERM)) {
1416	char *t;
1417	set(STRterm, quote(lp), VAR_READWRITE);	/* lp memory used here */
1418	t = short2str(lp);
1419	if (noediting && strcmp(t, "unknown") != 0 && strcmp(t,"dumb") != 0) {
1420	    editing = 1;
1421	    noediting = 0;
1422	    set(STRedit, Strsave(STRNULL), VAR_READWRITE);
1423	}
1424	GotTermCaps = 0;
1425	ed_Init();
1426	return;
1427    }
1428
1429    if (eq(vp, STRKHOME)) {
1430	/*
1431	 * convert to canonical pathname (possibly resolving symlinks)
1432	 */
1433	lp = dcanon(lp, lp);
1434	set(STRhome, quote(lp), VAR_READWRITE);	/* cp memory used here */
1435
1436	/* fix directory stack for new tilde home */
1437	dtilde();
1438	return;
1439    }
1440
1441    if (eq(vp, STRKSHLVL)) {
1442	/* lp memory used here */
1443	set(STRshlvl, quote(lp), VAR_READWRITE);
1444	return;
1445    }
1446
1447    if (eq(vp, STRKUSER)) {
1448	set(STRuser, quote(lp), VAR_READWRITE);	/* lp memory used here */
1449	return;
1450    }
1451
1452    if (eq(vp, STRKGROUP)) {
1453	set(STRgroup, quote(lp), VAR_READWRITE);	/* lp memory used here */
1454	return;
1455    }
1456
1457#ifdef COLOR_LS_F
1458    if (eq(vp, STRLS_COLORS)) {
1459        parseLS_COLORS(lp);
1460	return;
1461    }
1462#endif /* COLOR_LS_F */
1463
1464#ifdef SIG_WINDOW
1465    /*
1466     * Load/Update $LINES $COLUMNS
1467     */
1468    if ((eq(lp, STRNULL) && (eq(vp, STRLINES) || eq(vp, STRCOLUMNS))) ||
1469	eq(vp, STRTERMCAP)) {
1470	xfree((ptr_t) lp);
1471	check_window_size(1);
1472	return;
1473    }
1474
1475    /*
1476     * Change the size to the one directed by $LINES and $COLUMNS
1477     */
1478    if (eq(vp, STRLINES) || eq(vp, STRCOLUMNS)) {
1479#if 0
1480	GotTermCaps = 0;
1481#endif
1482	xfree((ptr_t) lp);
1483	ed_Init();
1484	return;
1485    }
1486#endif /* SIG_WINDOW */
1487    xfree((ptr_t) lp);
1488}
1489
1490/*ARGSUSED*/
1491void
1492dounsetenv(v, c)
1493    register Char **v;
1494    struct command *c;
1495{
1496    Char  **ep, *p, *n;
1497    int     i, maxi;
1498    static Char *name = NULL;
1499
1500    USE(c);
1501    if (name)
1502	xfree((ptr_t) name);
1503    /*
1504     * Find the longest environment variable
1505     */
1506    for (maxi = 0, ep = STR_environ; *ep; ep++) {
1507	for (i = 0, p = *ep; *p && *p != '='; p++, i++)
1508	    continue;
1509	if (i > maxi)
1510	    maxi = i;
1511    }
1512
1513    name = (Char *) xmalloc((size_t) ((maxi + 1) * sizeof(Char)));
1514
1515    while (++v && *v)
1516	for (maxi = 1; maxi;)
1517	    for (maxi = 0, ep = STR_environ; *ep; ep++) {
1518		for (n = name, p = *ep; *p && *p != '='; *n++ = *p++)
1519		    continue;
1520		*n = '\0';
1521		if (!Gmatch(name, *v))
1522		    continue;
1523		maxi = 1;
1524
1525		/* Unset the name. This wasn't being done until
1526		 * later but most of the stuff following won't
1527		 * work (particularly the setlocale() and getenv()
1528		 * stuff) as intended until the name is actually
1529		 * removed. (sg)
1530		 */
1531		Unsetenv(name);
1532
1533		if (eq(name, STRNOREBIND)) {
1534		    NoNLSRebind = 0;
1535		    MapsAreInited = 0;
1536		    NLSMapsAreInited = 0;
1537		    ed_InitMaps();
1538		}
1539#ifdef apollo
1540		else if (eq(name, STRSYSTYPE))
1541		    dohash(NULL, NULL);
1542#endif /* apollo */
1543		else if (islocale_var(name)) {
1544#ifdef NLS
1545		    int     k;
1546
1547# ifdef SETLOCALEBUG
1548		    dont_free = 1;
1549# endif /* SETLOCALEBUG */
1550		    (void) setlocale(LC_ALL, "");
1551# ifdef LC_COLLATE
1552		    (void) setlocale(LC_COLLATE, "");
1553# endif
1554# ifdef NLS_CATALOGS
1555#  ifdef LC_MESSAGES
1556		    (void) setlocale(LC_MESSAGES, "");
1557#  endif /* LC_MESSAGES */
1558		    (void) catclose(catd);
1559		    nlsinit();
1560# endif /* NLS_CATALOGS */
1561# ifdef LC_CTYPE
1562	(void) setlocale(LC_CTYPE, ""); /* for iscntrl */
1563# endif /* LC_CTYPE */
1564# ifdef SETLOCALEBUG
1565		    dont_free = 0;
1566# endif /* SETLOCALEBUG */
1567# ifdef STRCOLLBUG
1568		    fix_strcoll_bug();
1569# endif /* STRCOLLBUG */
1570		    tw_cmd_free();/* since the collation sequence has changed */
1571		    for (k = 0200; k <= 0377 && !Isprint(k); k++)
1572			continue;
1573		    AsciiOnly = k > 0377;
1574#else /* !NLS */
1575		    AsciiOnly = getenv("LANG") == NULL &&
1576			getenv("LC_CTYPE") == NULL;
1577#endif /* NLS */
1578		    NLSMapsAreInited = 0;
1579		    ed_Init();
1580		    if (MapsAreInited && !NLSMapsAreInited)
1581			ed_InitNLSMaps();
1582
1583		}
1584#ifdef WINNT_NATIVE
1585		else if (eq(name,(STRtcshlang))) {
1586		    nls_dll_unload();
1587		    nlsinit();
1588		}
1589#endif /* WINNT_NATIVE */
1590#ifdef COLOR_LS_F
1591		else if (eq(name, STRLS_COLORS))
1592		    parseLS_COLORS(n);
1593#endif /* COLOR_LS_F */
1594#ifdef NLS_CATALOGS
1595		else if (eq(name, STRNLSPATH)) {
1596		    (void) catclose(catd);
1597		    nlsinit();
1598		}
1599#endif
1600		/*
1601		 * start again cause the environment changes
1602		 */
1603		break;
1604	    }
1605    xfree((ptr_t) name); name = NULL;
1606}
1607
1608void
1609tsetenv(name, val)
1610    Char   *name, *val;
1611{
1612#ifdef SETENV_IN_LIB
1613/*
1614 * XXX: This does not work right, since tcsh cannot track changes to
1615 * the environment this way. (the builtin setenv without arguments does
1616 * not print the right stuff neither does unsetenv). This was for Mach,
1617 * it is not needed anymore.
1618 */
1619#undef setenv
1620    char    nameBuf[BUFSIZE];
1621    char   *cname = short2str(name);
1622
1623    if (cname == NULL)
1624	return;
1625    (void) strcpy(nameBuf, cname);
1626    setenv(nameBuf, short2str(val), 1);
1627#else /* !SETENV_IN_LIB */
1628    register Char **ep = STR_environ;
1629    register Char *cp, *dp;
1630    Char   *blk[2];
1631    Char  **oep = ep;
1632
1633#ifdef WINNT_NATIVE
1634	nt_set_env(name,val);
1635#endif /* WINNT_NATIVE */
1636    for (; *ep; ep++) {
1637#ifdef WINNT_NATIVE
1638	for (cp = name, dp = *ep; *cp && Tolower(*cp & TRIM) == Tolower(*dp);
1639				cp++, dp++)
1640#else
1641	for (cp = name, dp = *ep; *cp && (*cp & TRIM) == *dp; cp++, dp++)
1642#endif /* WINNT_NATIVE */
1643	    continue;
1644	if (*cp != 0 || *dp != '=')
1645	    continue;
1646	cp = Strspl(STRequal, val);
1647	xfree((ptr_t) * ep);
1648	*ep = strip(Strspl(name, cp));
1649	xfree((ptr_t) cp);
1650	blkfree((Char **) environ);
1651	environ = short2blk(STR_environ);
1652	return;
1653    }
1654    cp = Strspl(name, STRequal);
1655    blk[0] = strip(Strspl(cp, val));
1656    xfree((ptr_t) cp);
1657    blk[1] = 0;
1658    STR_environ = blkspl(STR_environ, blk);
1659    blkfree((Char **) environ);
1660    environ = short2blk(STR_environ);
1661    xfree((ptr_t) oep);
1662#endif /* SETENV_IN_LIB */
1663}
1664
1665void
1666Unsetenv(name)
1667    Char   *name;
1668{
1669    register Char **ep = STR_environ;
1670    register Char *cp, *dp;
1671    Char **oep = ep;
1672
1673#ifdef WINNT_NATIVE
1674	nt_set_env(name,NULL);
1675#endif /*WINNT_NATIVE */
1676    for (; *ep; ep++) {
1677	for (cp = name, dp = *ep; *cp && *cp == *dp; cp++, dp++)
1678	    continue;
1679	if (*cp != 0 || *dp != '=')
1680	    continue;
1681	cp = *ep;
1682	*ep = 0;
1683	STR_environ = blkspl(STR_environ, ep + 1);
1684	blkfree((Char **) environ);
1685	environ = short2blk(STR_environ);
1686	*ep = cp;
1687	xfree((ptr_t) cp);
1688	xfree((ptr_t) oep);
1689	return;
1690    }
1691}
1692
1693/*ARGSUSED*/
1694void
1695doumask(v, c)
1696    register Char **v;
1697    struct command *c;
1698{
1699    register Char *cp = v[1];
1700    register int i;
1701
1702    USE(c);
1703    if (cp == 0) {
1704	i = (int)umask(0);
1705	(void) umask(i);
1706	xprintf("%o\n", i);
1707	return;
1708    }
1709    i = 0;
1710    while (Isdigit(*cp) && *cp != '8' && *cp != '9')
1711	i = i * 8 + *cp++ - '0';
1712    if (*cp || i < 0 || i > 0777)
1713	stderror(ERR_NAME | ERR_MASK);
1714    (void) umask(i);
1715}
1716
1717#ifndef HAVENOLIMIT
1718# ifndef BSDLIMIT
1719   typedef long RLIM_TYPE;
1720#  ifndef RLIM_INFINITY
1721#   if !defined(_MINIX) && !defined(__clipper__) && !defined(_CRAY)
1722    extern RLIM_TYPE ulimit();
1723#   endif /* ! _MINIX && !__clipper__ */
1724#   define RLIM_INFINITY 0x003fffff
1725#   define RLIMIT_FSIZE 1
1726#  endif /* RLIM_INFINITY */
1727#  ifdef aiws
1728#   define toset(a) (((a) == 3) ? 1004 : (a) + 1)
1729#   define RLIMIT_DATA	3
1730#   define RLIMIT_STACK 1005
1731#  else /* aiws */
1732#   define toset(a) ((a) + 1)
1733#  endif /* aiws */
1734# else /* BSDLIMIT */
1735#  if (defined(BSD4_4) || defined(__linux__)) && !defined(__386BSD__)
1736    typedef rlim_t RLIM_TYPE;
1737#  else
1738#   if defined(SOLARIS2) || (defined(sgi) && SYSVREL > 3)
1739     typedef rlim_t RLIM_TYPE;
1740#   else
1741#    if defined(_SX)
1742      typedef long long RLIM_TYPE;
1743#    else /* !_SX */
1744      typedef unsigned long RLIM_TYPE;
1745#    endif /* _SX */
1746#   endif /* SOLARIS2 || (sgi && SYSVREL > 3) */
1747#  endif /* BSD4_4 && !__386BSD__  */
1748# endif /* BSDLIMIT */
1749
1750# if (HPUXVERSION > 700) && defined(BSDLIMIT)
1751/* Yes hpux8.0 has limits but <sys/resource.h> does not make them public */
1752/* Yes, we could have defined _KERNEL, and -I/etc/conf/h, but is that better? */
1753#  ifndef RLIMIT_CPU
1754#   define RLIMIT_CPU		0
1755#   define RLIMIT_FSIZE		1
1756#   define RLIMIT_DATA		2
1757#   define RLIMIT_STACK		3
1758#   define RLIMIT_CORE		4
1759#   define RLIMIT_RSS		5
1760#   define RLIMIT_NOFILE	6
1761#  endif /* RLIMIT_CPU */
1762#  ifndef RLIM_INFINITY
1763#   define RLIM_INFINITY	0x7fffffff
1764#  endif /* RLIM_INFINITY */
1765   /*
1766    * old versions of HP/UX counted limits in 512 bytes
1767    */
1768#  ifndef SIGRTMIN
1769#   define FILESIZE512
1770#  endif /* SIGRTMIN */
1771# endif /* (HPUXVERSION > 700) && BSDLIMIT */
1772
1773# if SYSVREL > 3 && defined(BSDLIMIT) && !defined(_SX)
1774/* In order to use rusage, we included "/usr/ucbinclude/sys/resource.h" in */
1775/* sh.h.  However, some SVR4 limits are defined in <sys/resource.h>.  Rather */
1776/* than include both and get warnings, we define the extra SVR4 limits here. */
1777/* XXX: I don't understand if RLIMIT_AS is defined, why don't we define */
1778/* RLIMIT_VMEM based on it? */
1779#  ifndef RLIMIT_VMEM
1780#   define RLIMIT_VMEM	6
1781#  endif
1782#  ifndef RLIMIT_AS
1783#   define RLIMIT_AS	RLIMIT_VMEM
1784#  endif
1785# endif /* SYSVREL > 3 && BSDLIMIT */
1786
1787# if defined(__linux__) && defined(RLIMIT_AS) && !defined(RLIMIT_VMEM)
1788#  define RLIMIT_VMEM	RLIMIT_AS
1789# endif
1790
1791struct limits limits[] =
1792{
1793# ifdef RLIMIT_CPU
1794    { RLIMIT_CPU, 	"cputime",	1,	"seconds"	},
1795# endif /* RLIMIT_CPU */
1796
1797# ifdef RLIMIT_FSIZE
1798#  ifndef aiws
1799    { RLIMIT_FSIZE, 	"filesize",	1024,	"kbytes"	},
1800#  else
1801    { RLIMIT_FSIZE, 	"filesize",	512,	"blocks"	},
1802#  endif /* aiws */
1803# endif /* RLIMIT_FSIZE */
1804
1805# ifdef RLIMIT_DATA
1806    { RLIMIT_DATA, 	"datasize",	1024,	"kbytes"	},
1807# endif /* RLIMIT_DATA */
1808
1809# ifdef RLIMIT_STACK
1810#  ifndef aiws
1811    { RLIMIT_STACK, 	"stacksize",	1024,	"kbytes"	},
1812#  else
1813    { RLIMIT_STACK, 	"stacksize",	1024 * 1024,	"kbytes"},
1814#  endif /* aiws */
1815# endif /* RLIMIT_STACK */
1816
1817# ifdef RLIMIT_CORE
1818    { RLIMIT_CORE, 	"coredumpsize",	1024,	"kbytes"	},
1819# endif /* RLIMIT_CORE */
1820
1821# ifdef RLIMIT_RSS
1822    { RLIMIT_RSS, 	"memoryuse",	1024,	"kbytes"	},
1823# endif /* RLIMIT_RSS */
1824
1825# ifdef RLIMIT_UMEM
1826    { RLIMIT_UMEM, 	"memoryuse",	1024,	"kbytes"	},
1827# endif /* RLIMIT_UMEM */
1828
1829# ifdef RLIMIT_VMEM
1830    { RLIMIT_VMEM, 	"vmemoryuse",	1024,	"kbytes"	},
1831# endif /* RLIMIT_VMEM */
1832
1833# ifdef RLIMIT_NOFILE
1834    { RLIMIT_NOFILE, 	"descriptors", 1,	""		},
1835# endif /* RLIMIT_NOFILE */
1836
1837# ifdef RLIMIT_CONCUR
1838    { RLIMIT_CONCUR, 	"concurrency", 1,	"thread(s)"	},
1839# endif /* RLIMIT_CONCUR */
1840
1841# ifdef RLIMIT_MEMLOCK
1842    { RLIMIT_MEMLOCK,	"memorylocked",	1024,	"kbytes"	},
1843# endif /* RLIMIT_MEMLOCK */
1844
1845# ifdef RLIMIT_NPROC
1846    { RLIMIT_NPROC,	"maxproc",	1,	""		},
1847# endif /* RLIMIT_NPROC */
1848
1849# if defined(RLIMIT_OFILE) && !defined(RLIMIT_NOFILE)
1850    { RLIMIT_OFILE,	"openfiles",	1,	""		},
1851# endif /* RLIMIT_OFILE && !defined(RLIMIT_NOFILE) */
1852
1853# ifdef RLIMIT_SBSIZE
1854    { RLIMIT_SBSIZE,	"sbsize",	1,	""		},
1855# endif /* RLIMIT_SBSIZE */
1856
1857    { -1, 		NULL, 		0, 	NULL		}
1858};
1859
1860static struct limits *findlim	__P((Char *));
1861static RLIM_TYPE getval		__P((struct limits *, Char **));
1862static void limtail		__P((Char *, char*));
1863static void plim		__P((struct limits *, int));
1864static int setlim		__P((struct limits *, int, RLIM_TYPE));
1865
1866#ifdef convex
1867static  RLIM_TYPE
1868restrict_limit(value)
1869    double  value;
1870{
1871    /*
1872     * is f too large to cope with? return the maximum or minimum int
1873     */
1874    if (value > (double) INT_MAX)
1875	return (RLIM_TYPE) INT_MAX;
1876    else if (value < (double) INT_MIN)
1877	return (RLIM_TYPE) INT_MIN;
1878    else
1879	return (RLIM_TYPE) value;
1880}
1881#else /* !convex */
1882# define restrict_limit(x)	((RLIM_TYPE) (x))
1883#endif /* convex */
1884
1885
1886static struct limits *
1887findlim(cp)
1888    Char   *cp;
1889{
1890    register struct limits *lp, *res;
1891
1892    res = (struct limits *) NULL;
1893    for (lp = limits; lp->limconst >= 0; lp++)
1894	if (prefix(cp, str2short(lp->limname))) {
1895	    if (res)
1896		stderror(ERR_NAME | ERR_AMBIG);
1897	    res = lp;
1898	}
1899    if (res)
1900	return (res);
1901    stderror(ERR_NAME | ERR_LIMIT);
1902    /* NOTREACHED */
1903    return (0);
1904}
1905
1906/*ARGSUSED*/
1907void
1908dolimit(v, c)
1909    register Char **v;
1910    struct command *c;
1911{
1912    register struct limits *lp;
1913    register RLIM_TYPE limit;
1914    int    hard = 0;
1915
1916    USE(c);
1917    v++;
1918    if (*v && eq(*v, STRmh)) {
1919	hard = 1;
1920	v++;
1921    }
1922    if (*v == 0) {
1923	for (lp = limits; lp->limconst >= 0; lp++)
1924	    plim(lp, hard);
1925	return;
1926    }
1927    lp = findlim(v[0]);
1928    if (v[1] == 0) {
1929	plim(lp, hard);
1930	return;
1931    }
1932    limit = getval(lp, v + 1);
1933    if (setlim(lp, hard, limit) < 0)
1934	stderror(ERR_SILENT);
1935}
1936
1937static  RLIM_TYPE
1938getval(lp, v)
1939    register struct limits *lp;
1940    Char  **v;
1941{
1942    register float f;
1943#ifndef atof	/* This can be a macro on linux */
1944    extern double  atof __P((const char *));
1945#endif /* atof */
1946    Char   *cp = *v++;
1947
1948    f = atof(short2str(cp));
1949
1950# ifdef convex
1951    /*
1952     * is f too large to cope with. limit f to minint, maxint  - X-6768 by
1953     * strike
1954     */
1955    if ((f < (double) INT_MIN) || (f > (double) INT_MAX)) {
1956	stderror(ERR_NAME | ERR_TOOLARGE);
1957    }
1958# endif /* convex */
1959
1960    while (Isdigit(*cp) || *cp == '.' || *cp == 'e' || *cp == 'E')
1961	cp++;
1962    if (*cp == 0) {
1963	if (*v == 0)
1964	    return restrict_limit((f * lp->limdiv) + 0.5);
1965	cp = *v;
1966    }
1967    switch (*cp) {
1968# ifdef RLIMIT_CPU
1969    case ':':
1970	if (lp->limconst != RLIMIT_CPU)
1971	    goto badscal;
1972	return f == 0.0 ? (RLIM_TYPE) 0 : restrict_limit((f * 60.0 + atof(short2str(cp + 1))));
1973    case 'h':
1974	if (lp->limconst != RLIMIT_CPU)
1975	    goto badscal;
1976	limtail(cp, "hours");
1977	f *= 3600.0;
1978	break;
1979    case 'm':
1980	if (lp->limconst == RLIMIT_CPU) {
1981	    limtail(cp, "minutes");
1982	    f *= 60.0;
1983	    break;
1984	}
1985	*cp = 'm';
1986	limtail(cp, "megabytes");
1987	f *= 1024.0 * 1024.0;
1988	break;
1989    case 's':
1990	if (lp->limconst != RLIMIT_CPU)
1991	    goto badscal;
1992	limtail(cp, "seconds");
1993	break;
1994# endif /* RLIMIT_CPU */
1995    case 'M':
1996# ifdef RLIMIT_CPU
1997	if (lp->limconst == RLIMIT_CPU)
1998	    goto badscal;
1999# endif /* RLIMIT_CPU */
2000	*cp = 'm';
2001	limtail(cp, "megabytes");
2002	f *= 1024.0 * 1024.0;
2003	break;
2004    case 'k':
2005# ifdef RLIMIT_CPU
2006	if (lp->limconst == RLIMIT_CPU)
2007	    goto badscal;
2008# endif /* RLIMIT_CPU */
2009	limtail(cp, "kbytes");
2010	f *= 1024.0;
2011	break;
2012    case 'b':
2013# ifdef RLIMIT_CPU
2014	if (lp->limconst == RLIMIT_CPU)
2015	    goto badscal;
2016# endif /* RLIMIT_CPU */
2017	limtail(cp, "blocks");
2018	f *= 512.0;
2019	break;
2020    case 'u':
2021	limtail(cp, "unlimited");
2022	return ((RLIM_TYPE) RLIM_INFINITY);
2023    default:
2024# ifdef RLIMIT_CPU
2025badscal:
2026# endif /* RLIMIT_CPU */
2027	stderror(ERR_NAME | ERR_SCALEF);
2028    }
2029# ifdef convex
2030    return f == 0.0 ? (RLIM_TYPE) 0 : restrict_limit((f + 0.5));
2031# else
2032    f += 0.5;
2033    if (f > (float) RLIM_INFINITY)
2034	return ((RLIM_TYPE) RLIM_INFINITY);
2035    else
2036	return ((RLIM_TYPE) f);
2037# endif /* convex */
2038}
2039
2040static void
2041limtail(cp, str)
2042    Char   *cp;
2043    char   *str;
2044{
2045    char *sp;
2046
2047    sp = str;
2048    while (*cp && *cp == *str)
2049	cp++, str++;
2050    if (*cp)
2051	stderror(ERR_BADSCALE, sp);
2052}
2053
2054
2055/*ARGSUSED*/
2056static void
2057plim(lp, hard)
2058    register struct limits *lp;
2059    int hard;
2060{
2061# ifdef BSDLIMIT
2062    struct rlimit rlim;
2063# endif /* BSDLIMIT */
2064    RLIM_TYPE limit;
2065    int     div = lp->limdiv;
2066
2067    xprintf("%s \t", lp->limname);
2068
2069# ifndef BSDLIMIT
2070    limit = ulimit(lp->limconst, 0);
2071#  ifdef aiws
2072    if (lp->limconst == RLIMIT_DATA)
2073	limit -= 0x20000000;
2074#  endif /* aiws */
2075# else /* BSDLIMIT */
2076    (void) getrlimit(lp->limconst, &rlim);
2077    limit = hard ? rlim.rlim_max : rlim.rlim_cur;
2078# endif /* BSDLIMIT */
2079
2080# if !defined(BSDLIMIT) || defined(FILESIZE512)
2081    /*
2082     * Christos: filesize comes in 512 blocks. we divide by 2 to get 1024
2083     * blocks. Note we cannot pre-multiply cause we might overflow (A/UX)
2084     */
2085    if (lp->limconst == RLIMIT_FSIZE) {
2086	if (limit >= (RLIM_INFINITY / 512))
2087	    limit = RLIM_INFINITY;
2088	else
2089	    div = (div == 1024 ? 2 : 1);
2090    }
2091# endif /* !BSDLIMIT || FILESIZE512 */
2092
2093    if (limit == RLIM_INFINITY)
2094	xprintf("unlimited");
2095    else
2096# ifdef RLIMIT_CPU
2097    if (lp->limconst == RLIMIT_CPU)
2098	psecs((long) limit);
2099    else
2100# endif /* RLIMIT_CPU */
2101	xprintf("%ld %s", (long) (limit / div), lp->limscale);
2102    xputchar('\n');
2103}
2104
2105/*ARGSUSED*/
2106void
2107dounlimit(v, c)
2108    register Char **v;
2109    struct command *c;
2110{
2111    register struct limits *lp;
2112    int    lerr = 0;
2113    int    hard = 0;
2114    int	   force = 0;
2115
2116    USE(c);
2117    while (*++v && **v == '-') {
2118	Char   *vp = *v;
2119	while (*++vp)
2120	    switch (*vp) {
2121	    case 'f':
2122		force = 1;
2123		break;
2124	    case 'h':
2125		hard = 1;
2126		break;
2127	    default:
2128		stderror(ERR_ULIMUS);
2129		break;
2130	    }
2131    }
2132
2133    if (*v == 0) {
2134	for (lp = limits; lp->limconst >= 0; lp++)
2135	    if (setlim(lp, hard, (RLIM_TYPE) RLIM_INFINITY) < 0)
2136		lerr++;
2137	if (!force && lerr)
2138	    stderror(ERR_SILENT);
2139	return;
2140    }
2141    while (*v) {
2142	lp = findlim(*v++);
2143	if (setlim(lp, hard, (RLIM_TYPE) RLIM_INFINITY) < 0 && !force)
2144	    stderror(ERR_SILENT);
2145    }
2146}
2147
2148static int
2149setlim(lp, hard, limit)
2150    register struct limits *lp;
2151    int    hard;
2152    RLIM_TYPE limit;
2153{
2154# ifdef BSDLIMIT
2155    struct rlimit rlim;
2156
2157    (void) getrlimit(lp->limconst, &rlim);
2158
2159#  ifdef FILESIZE512
2160    /* Even though hpux has setrlimit(), it expects fsize in 512 byte blocks */
2161    if (limit != RLIM_INFINITY && lp->limconst == RLIMIT_FSIZE)
2162	limit /= 512;
2163#  endif /* FILESIZE512 */
2164    if (hard)
2165	rlim.rlim_max = limit;
2166    else if (limit == RLIM_INFINITY && euid != 0)
2167	rlim.rlim_cur = rlim.rlim_max;
2168    else
2169	rlim.rlim_cur = limit;
2170
2171    if (rlim.rlim_cur > rlim.rlim_max)
2172	rlim.rlim_max = rlim.rlim_cur;
2173
2174    if (setrlimit(lp->limconst, &rlim) < 0) {
2175# else /* BSDLIMIT */
2176    if (limit != RLIM_INFINITY && lp->limconst == RLIMIT_FSIZE)
2177	limit /= 512;
2178# ifdef aiws
2179    if (lp->limconst == RLIMIT_DATA)
2180	limit += 0x20000000;
2181# endif /* aiws */
2182    if (ulimit(toset(lp->limconst), limit) < 0) {
2183# endif /* BSDLIMIT */
2184	xprintf(CGETS(15, 1, "%s: %s: Can't %s%s limit (%s)\n"), bname,
2185	    lp->limname, limit == RLIM_INFINITY ? CGETS(15, 2, "remove") :
2186	    CGETS(15, 3, "set"), hard ? CGETS(14, 4, " hard") : "",
2187	    strerror(errno));
2188	return (-1);
2189    }
2190    return (0);
2191}
2192
2193#endif /* !HAVENOLIMIT */
2194
2195/*ARGSUSED*/
2196void
2197dosuspend(v, c)
2198    Char **v;
2199    struct command *c;
2200{
2201#ifdef BSDJOBS
2202    int     ctpgrp;
2203
2204    signalfun_t old;
2205#endif /* BSDJOBS */
2206
2207    USE(c);
2208    USE(v);
2209
2210    if (loginsh)
2211	stderror(ERR_SUSPLOG);
2212    untty();
2213
2214#ifdef BSDJOBS
2215    old = signal(SIGTSTP, SIG_DFL);
2216    (void) kill(0, SIGTSTP);
2217    /* the shell stops here */
2218    (void) signal(SIGTSTP, old);
2219#else /* !BSDJOBS */
2220    stderror(ERR_JOBCONTROL);
2221#endif /* BSDJOBS */
2222
2223#ifdef BSDJOBS
2224    if (tpgrp != -1) {
2225retry:
2226	ctpgrp = tcgetpgrp(FSHTTY);
2227	if (ctpgrp != opgrp) {
2228	    old = signal(SIGTTIN, SIG_DFL);
2229	    (void) kill(0, SIGTTIN);
2230	    (void) signal(SIGTTIN, old);
2231	    goto retry;
2232	}
2233	(void) setpgid(0, shpgrp);
2234	(void) tcsetpgrp(FSHTTY, shpgrp);
2235    }
2236#endif /* BSDJOBS */
2237    (void) setdisc(FSHTTY);
2238}
2239
2240/* This is the dreaded EVAL built-in.
2241 *   If you don't fiddle with file descriptors, and reset didfds,
2242 *   this command will either ignore redirection inside or outside
2243 *   its arguments, e.g. eval "date >x"  vs.  eval "date" >x
2244 *   The stuff here seems to work, but I did it by trial and error rather
2245 *   than really knowing what was going on.  If tpgrp is zero, we are
2246 *   probably a background eval, e.g. "eval date &", and we want to
2247 *   make sure that any processes we start stay in our pgrp.
2248 *   This is also the case for "time eval date" -- stay in same pgrp.
2249 *   Otherwise, under stty tostop, processes will stop in the wrong
2250 *   pgrp, with no way for the shell to get them going again.  -IAN!
2251 */
2252
2253static Char **gv = NULL, **gav = NULL;
2254
2255/*ARGSUSED*/
2256void
2257doeval(v, c)
2258    Char  **v;
2259    struct command *c;
2260{
2261    Char  **oevalvec;
2262    Char   *oevalp;
2263    int     odidfds;
2264#ifndef CLOSE_ON_EXEC
2265    int     odidcch;
2266#endif /* CLOSE_ON_EXEC */
2267    jmp_buf_t osetexit;
2268    int     my_reenter;
2269    Char  **savegv;
2270    int     saveIN, saveOUT, saveDIAG;
2271    int     oSHIN, oSHOUT, oSHDIAG;
2272
2273    USE(c);
2274    oevalvec = evalvec;
2275    oevalp = evalp;
2276    odidfds = didfds;
2277#ifndef CLOSE_ON_EXEC
2278    odidcch = didcch;
2279#endif /* CLOSE_ON_EXEC */
2280    oSHIN = SHIN;
2281    oSHOUT = SHOUT;
2282    oSHDIAG = SHDIAG;
2283
2284    savegv = gv;
2285    gav = v;
2286
2287    gav++;
2288    if (*gav == 0)
2289	return;
2290    gflag = 0, tglob(gav);
2291    if (gflag) {
2292	gv = gav = globall(gav);
2293	gargv = 0;
2294	if (gav == 0)
2295	    stderror(ERR_NOMATCH);
2296	gav = copyblk(gav);
2297    }
2298    else {
2299	gv = NULL;
2300	gav = copyblk(gav);
2301	trim(gav);
2302    }
2303
2304    saveIN = dcopy(SHIN, -1);
2305    saveOUT = dcopy(SHOUT, -1);
2306    saveDIAG = dcopy(SHDIAG, -1);
2307
2308    getexit(osetexit);
2309
2310    /* PWP: setjmp/longjmp bugfix for optimizing compilers */
2311#ifdef cray
2312    my_reenter = 1;             /* assume non-zero return val */
2313    if (setexit() == 0) {
2314	my_reenter = 0;         /* Oh well, we were wrong */
2315#else /* !cray */
2316    if ((my_reenter = setexit()) == 0) {
2317#endif /* cray */
2318	evalvec = gav;
2319	evalp = 0;
2320	SHIN = dcopy(0, -1);
2321	SHOUT = dcopy(1, -1);
2322	SHDIAG = dcopy(2, -1);
2323#ifndef CLOSE_ON_EXEC
2324	didcch = 0;
2325#endif /* CLOSE_ON_EXEC */
2326	didfds = 0;
2327	process(0);
2328    }
2329
2330    evalvec = oevalvec;
2331    evalp = oevalp;
2332    doneinp = 0;
2333#ifndef CLOSE_ON_EXEC
2334    didcch = odidcch;
2335#endif /* CLOSE_ON_EXEC */
2336    didfds = odidfds;
2337    (void) close(SHIN);
2338    (void) close(SHOUT);
2339    (void) close(SHDIAG);
2340    SHIN = dmove(saveIN, oSHIN);
2341    SHOUT = dmove(saveOUT, oSHOUT);
2342    SHDIAG = dmove(saveDIAG, oSHDIAG);
2343
2344    if (gv)
2345	blkfree(gv);
2346
2347    gv = savegv;
2348    resexit(osetexit);
2349    if (my_reenter)
2350	stderror(ERR_SILENT);
2351}
2352
2353/*************************************************************************/
2354/* print list of builtin commands */
2355
2356/*ARGSUSED*/
2357void
2358dobuiltins(v, c)
2359Char **v;
2360struct command *c;
2361{
2362    /* would use print_by_column() in tw.parse.c but that assumes
2363     * we have an array of Char * to pass.. (sg)
2364     */
2365    extern int Tty_raw_mode;
2366    extern int TermH;		/* from the editor routines */
2367    extern int lbuffed;		/* from sh.print.c */
2368
2369    register struct biltins *b;
2370    register int row, col, columns, rows;
2371    unsigned int w, maxwidth;
2372
2373    USE(c);
2374    USE(v);
2375    lbuffed = 0;		/* turn off line buffering */
2376
2377    /* find widest string */
2378    for (maxwidth = 0, b = bfunc; b < &bfunc[nbfunc]; ++b)
2379	maxwidth = max(maxwidth, strlen(b->bname));
2380    ++maxwidth;					/* for space */
2381
2382    columns = (TermH + 1) / maxwidth;	/* PWP: terminal size change */
2383    if (!columns)
2384	columns = 1;
2385    rows = (nbfunc + (columns - 1)) / columns;
2386
2387    for (b = bfunc, row = 0; row < rows; row++) {
2388	for (col = 0; col < columns; col++) {
2389	    if (b < &bfunc[nbfunc]) {
2390		w = strlen(b->bname);
2391		xprintf("%s", b->bname);
2392		if (col < (columns - 1))	/* Not last column? */
2393		    for (; w < maxwidth; w++)
2394			xputchar(' ');
2395		++b;
2396	    }
2397	}
2398	if (row < (rows - 1)) {
2399	    if (Tty_raw_mode)
2400		xputchar('\r');
2401	    xputchar('\n');
2402	}
2403    }
2404#ifdef WINNT_NATIVE
2405    nt_print_builtins(maxwidth);
2406#else
2407    if (Tty_raw_mode)
2408	xputchar('\r');
2409    xputchar('\n');
2410#endif /* WINNT_NATIVE */
2411
2412    lbuffed = 1;		/* turn back on line buffering */
2413    flush();
2414}
2415
2416void
2417nlsinit()
2418{
2419#ifdef NLS_CATALOGS
2420    char catalog[ 256 ] = { 't', 'c', 's', 'h', '\0' };
2421
2422    if (adrof(STRcatalog) != NULL)
2423        xsnprintf((char *)catalog, sizeof(catalog), "tcsh.%s",
2424		  short2str(varval(STRcatalog)));
2425    catd = catopen(catalog, MCLoadBySet);
2426#endif /* NLS_CATALOGS */
2427#ifdef WINNT_NATIVE
2428    nls_dll_init();
2429#endif /* WINNT_NATIVE */
2430    errinit();		/* init the errorlist in correct locale */
2431    mesginit();		/* init the messages for signals */
2432    dateinit();		/* init the messages for dates */
2433    editinit();		/* init the editor messages */
2434    terminit();		/* init the termcap messages */
2435}
2436