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