sh.func.c revision 145479
1215976Sjmallett/* $Header: /src/pub/tcsh/sh.func.c,v 3.126 2005/03/20 06:35:48 christos Exp $ */
2215976Sjmallett/*
3215976Sjmallett * sh.func.c: csh builtin functions
4215976Sjmallett */
5215976Sjmallett/*-
6215976Sjmallett * Copyright (c) 1980, 1991 The Regents of the University of California.
7215976Sjmallett * All rights reserved.
8215976Sjmallett *
9215976Sjmallett * Redistribution and use in source and binary forms, with or without
10215976Sjmallett * modification, are permitted provided that the following conditions
11215976Sjmallett * are met:
12215976Sjmallett * 1. Redistributions of source code must retain the above copyright
13215976Sjmallett *    notice, this list of conditions and the following disclaimer.
14215976Sjmallett * 2. Redistributions in binary form must reproduce the above copyright
15215976Sjmallett *    notice, this list of conditions and the following disclaimer in the
16215976Sjmallett *    documentation and/or other materials provided with the distribution.
17215976Sjmallett * 3. Neither the name of the University nor the names of its contributors
18215976Sjmallett *    may be used to endorse or promote products derived from this software
19215976Sjmallett *    without specific prior written permission.
20215976Sjmallett *
21215976Sjmallett * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22215976Sjmallett * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23215976Sjmallett * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24215976Sjmallett * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25215976Sjmallett * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26215976Sjmallett * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27215976Sjmallett * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28215976Sjmallett * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29215976Sjmallett * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30215976Sjmallett * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31215976Sjmallett * SUCH DAMAGE.
32215976Sjmallett */
33215976Sjmallett#include "sh.h"
34215976Sjmallett
35215976SjmallettRCSID("$Id: sh.func.c,v 3.126 2005/03/20 06:35:48 christos Exp $")
36215976Sjmallett
37215976Sjmallett#include "ed.h"
38215976Sjmallett#include "tw.h"
39215976Sjmallett#include "tc.h"
40215976Sjmallett#ifdef WINNT_NATIVE
41215976Sjmallett#include "nt.const.h"
42215976Sjmallett#endif /* WINNT_NATIVE */
43215976Sjmallett
44215976Sjmallett#ifdef NLS_CATALOGS
45215976Sjmallett#ifdef HAVE_ICONV
46215976Sjmallett#include <langinfo.h>
47215976Sjmallettstatic iconv_t catgets_iconv; /* Or (iconv_t)-1 */
48215976Sjmallett#endif
49215976Sjmallett#endif
50215976Sjmallett
51215976Sjmallett/*
52215976Sjmallett * C shell
53215976Sjmallett */
54215976Sjmallettextern int just_signaled;
55215976Sjmallettextern char **environ;
56215976Sjmallett
57215976Sjmallettextern int MapsAreInited;
58215976Sjmallettextern int NLSMapsAreInited;
59215976Sjmallettextern int GotTermCaps;
60215976Sjmallett
61215976Sjmallettstatic int zlast = -1;
62215976Sjmallett
63215976Sjmallettstatic	void	islogin		__P((void));
64215976Sjmallettstatic	void	preread		__P((void));
65215976Sjmallettstatic	void	doagain		__P((void));
66215976Sjmallettstatic  const char *isrchx	__P((int));
67215976Sjmallettstatic	void	search		__P((int, int, Char *));
68215976Sjmallettstatic	int	getword		__P((Char *));
69215976Sjmallettstatic	void	toend		__P((void));
70215976Sjmallettstatic	void	xecho		__P((int, Char **));
71215976Sjmallettstatic	int	islocale_var	__P((Char *));
72215976Sjmallettstatic	void	wpfree		__P((struct whyle *));
73215976Sjmallett
74215976Sjmallettstruct biltins *
75215976Sjmallettisbfunc(t)
76215976Sjmallett    struct command *t;
77215976Sjmallett{
78215976Sjmallett    Char *cp = t->t_dcom[0];
79215976Sjmallett    struct biltins *bp, *bp1, *bp2;
80215976Sjmallett    static struct biltins label = {"", dozip, 0, 0};
81215976Sjmallett    static struct biltins foregnd = {"%job", dofg1, 0, 0};
82215976Sjmallett    static struct biltins backgnd = {"%job &", dobg1, 0, 0};
83215976Sjmallett
84215976Sjmallett    /*
85215976Sjmallett     * We never match a builtin that has quoted the first
86215976Sjmallett     * character; this has been the traditional way to escape
87215976Sjmallett     * builtin commands.
88215976Sjmallett     */
89215976Sjmallett    if (*cp & QUOTE)
90215976Sjmallett	return NULL;
91215976Sjmallett
92215976Sjmallett    if (*cp != ':' && lastchr(cp) == ':') {
93215976Sjmallett	label.bname = short2str(cp);
94215976Sjmallett	return (&label);
95215976Sjmallett    }
96215976Sjmallett    if (*cp == '%') {
97215976Sjmallett	if (t->t_dflg & F_AMPERSAND) {
98215976Sjmallett	    t->t_dflg &= ~F_AMPERSAND;
99215976Sjmallett	    backgnd.bname = short2str(cp);
100215976Sjmallett	    return (&backgnd);
101215976Sjmallett	}
102215976Sjmallett	foregnd.bname = short2str(cp);
103215976Sjmallett	return (&foregnd);
104215976Sjmallett    }
105215976Sjmallett#ifdef WARP
106215976Sjmallett    /*
107215976Sjmallett     * This is a perhaps kludgy way to determine if the warp builtin is to be
108215976Sjmallett     * acknowledged or not.  If checkwarp() fails, then we are to assume that
109215976Sjmallett     * the warp command is invalid, and carry on as we would handle any other
110215976Sjmallett     * non-builtin command.         -- JDK 2/4/88
111215976Sjmallett     */
112215976Sjmallett    if (eq(STRwarp, cp) && !checkwarp()) {
113215976Sjmallett	return (0);		/* this builtin disabled */
114215976Sjmallett    }
115215976Sjmallett#endif /* WARP */
116215976Sjmallett    /*
117215976Sjmallett     * Binary search Bp1 is the beginning of the current search range. Bp2 is
118215976Sjmallett     * one past the end.
119215976Sjmallett     */
120215976Sjmallett    for (bp1 = bfunc, bp2 = bfunc + nbfunc; bp1 < bp2;) {
121215976Sjmallett	int i;
122215976Sjmallett
123215976Sjmallett	bp = bp1 + ((bp2 - bp1) >> 1);
124215976Sjmallett	if ((i = ((char) *cp) - *bp->bname) == 0 &&
125215976Sjmallett	    (i = StrQcmp(cp, str2short(bp->bname))) == 0)
126215976Sjmallett	    return bp;
127215976Sjmallett	if (i < 0)
128215976Sjmallett	    bp2 = bp;
129215976Sjmallett	else
130215976Sjmallett	    bp1 = bp + 1;
131215976Sjmallett    }
132215976Sjmallett#ifdef WINNT_NATIVE
133215976Sjmallett    return nt_check_additional_builtins(cp);
134215976Sjmallett#endif /*WINNT_NATIVE*/
135215976Sjmallett    return (0);
136215976Sjmallett}
137215976Sjmallett
138215976Sjmallettvoid
139215976Sjmallettfunc(t, bp)
140215976Sjmallett    struct command *t;
141215976Sjmallett    struct biltins *bp;
142215976Sjmallett{
143215976Sjmallett    int     i;
144215976Sjmallett
145215976Sjmallett    xechoit(t->t_dcom);
146215976Sjmallett    setname(bp->bname);
147215976Sjmallett    i = blklen(t->t_dcom) - 1;
148215976Sjmallett    if (i < bp->minargs)
149215976Sjmallett	stderror(ERR_NAME | ERR_TOOFEW);
150215976Sjmallett    if (i > bp->maxargs)
151215976Sjmallett	stderror(ERR_NAME | ERR_TOOMANY);
152215976Sjmallett    (*bp->bfunct) (t->t_dcom, t);
153215976Sjmallett}
154215976Sjmallett
155215976Sjmallett/*ARGSUSED*/
156215976Sjmallettvoid
157215976Sjmallettdoonintr(v, c)
158215976Sjmallett    Char  **v;
159215976Sjmallett    struct command *c;
160215976Sjmallett{
161215976Sjmallett    Char *cp;
162215976Sjmallett    Char *vv = v[1];
163215976Sjmallett
164215976Sjmallett    USE(c);
165215976Sjmallett    if (parintr == SIG_IGN)
166215976Sjmallett	return;
167215976Sjmallett    if (setintr && intty)
168215976Sjmallett	stderror(ERR_NAME | ERR_TERMINAL);
169215976Sjmallett    cp = gointr;
170215976Sjmallett    gointr = 0;
171215976Sjmallett    xfree((ptr_t) cp);
172215976Sjmallett    if (vv == 0) {
173215976Sjmallett#ifdef BSDSIGS
174215976Sjmallett	if (setintr) {
175215976Sjmallett	    (void) sigblock(sigmask(SIGINT));
176215976Sjmallett	    (void) signal(SIGINT, pintr);
177215976Sjmallett	}
178215976Sjmallett	else
179215976Sjmallett	    (void) signal(SIGINT, SIG_DFL);
180215976Sjmallett#else /* !BSDSIGS */
181215976Sjmallett	if (setintr) {
182215976Sjmallett	    (void) sighold(SIGINT);
183215976Sjmallett	    (void) sigset(SIGINT, pintr);
184215976Sjmallett	}
185215976Sjmallett	else
186215976Sjmallett	    (void) sigset(SIGINT, SIG_DFL);
187215976Sjmallett#endif /* BSDSIGS */
188215976Sjmallett	gointr = 0;
189215976Sjmallett    }
190215976Sjmallett    else if (eq((vv = strip(vv)), STRminus)) {
191215976Sjmallett#ifdef BSDSIGS
192215976Sjmallett	(void) signal(SIGINT, SIG_IGN);
193215976Sjmallett#else /* !BSDSIGS */
194215976Sjmallett	(void) sigset(SIGINT, SIG_IGN);
195215976Sjmallett#endif /* BSDSIGS */
196215976Sjmallett	gointr = Strsave(STRminus);
197215976Sjmallett    }
198215976Sjmallett    else {
199215976Sjmallett	gointr = Strsave(vv);
200215976Sjmallett#ifdef BSDSIGS
201215976Sjmallett	(void) signal(SIGINT, pintr);
202215976Sjmallett#else /* !BSDSIGS */
203215976Sjmallett	(void) sigset(SIGINT, pintr);
204215976Sjmallett#endif /* BSDSIGS */
205215976Sjmallett    }
206215976Sjmallett}
207215976Sjmallett
208215976Sjmallett/*ARGSUSED*/
209215976Sjmallettvoid
210215976Sjmallettdonohup(v, c)
211215976Sjmallett    Char **v;
212215976Sjmallett    struct command *c;
213215976Sjmallett{
214215976Sjmallett    USE(c);
215215976Sjmallett    USE(v);
216215976Sjmallett    if (intty)
217215976Sjmallett	stderror(ERR_NAME | ERR_TERMINAL);
218215976Sjmallett    if (setintr == 0) {
219215976Sjmallett	(void) signal(SIGHUP, SIG_IGN);
220215976Sjmallett#ifdef CC
221215976Sjmallett	submit(getpid());
222215976Sjmallett#endif /* CC */
223215976Sjmallett    }
224215976Sjmallett}
225215976Sjmallett
226215976Sjmallett/*ARGSUSED*/
227215976Sjmallettvoid
228215976Sjmallettdohup(v, c)
229215976Sjmallett    Char **v;
230215976Sjmallett    struct command *c;
231215976Sjmallett{
232215976Sjmallett    USE(c);
233215976Sjmallett    USE(v);
234215976Sjmallett    if (intty)
235215976Sjmallett	stderror(ERR_NAME | ERR_TERMINAL);
236215976Sjmallett    if (setintr == 0)
237215976Sjmallett	(void) signal(SIGHUP, SIG_DFL);
238215976Sjmallett}
239215976Sjmallett
240215976Sjmallett
241215976Sjmallett/*ARGSUSED*/
242215976Sjmallettvoid
243215976Sjmallettdozip(v, c)
244215976Sjmallett    Char **v;
245215976Sjmallett    struct command *c;
246215976Sjmallett{
247215976Sjmallett    USE(c);
248215976Sjmallett    USE(v);
249215976Sjmallett}
250215976Sjmallett
251215976Sjmallett/*ARGSUSED*/
252215976Sjmallettvoid
253215976Sjmallettdofiletest(v, c)
254215976Sjmallett    Char **v;
255215976Sjmallett    struct command *c;
256215976Sjmallett{
257215976Sjmallett    Char **fileptr, *ftest, *res;
258215976Sjmallett
259215976Sjmallett    USE(c);
260215976Sjmallett    if (*(ftest = *++v) != '-')
261215976Sjmallett	stderror(ERR_NAME | ERR_FILEINQ);
262215976Sjmallett    ++v;
263215976Sjmallett
264215976Sjmallett    gflag = 0;
265215976Sjmallett    tglob(v);
266215976Sjmallett    if (gflag) {
267215976Sjmallett	v = globall(v);
268215976Sjmallett	if (v == 0)
269215976Sjmallett	    stderror(ERR_NAME | ERR_NOMATCH);
270215976Sjmallett    }
271215976Sjmallett    else
272215976Sjmallett	v = gargv = saveblk(v);
273215976Sjmallett    trim(v);
274215976Sjmallett
275215976Sjmallett    while (*(fileptr = v++) != '\0') {
276215976Sjmallett	xprintf("%S", res = filetest(ftest, &fileptr, 0));
277215976Sjmallett	xfree((ptr_t) res);
278215976Sjmallett	if (*v)
279215976Sjmallett	    xprintf(" ");
280215976Sjmallett    }
281215976Sjmallett    xprintf("\n");
282215976Sjmallett
283215976Sjmallett    if (gargv) {
284215976Sjmallett	blkfree(gargv);
285215976Sjmallett	gargv = 0;
286215976Sjmallett    }
287215976Sjmallett}
288215976Sjmallett
289215976Sjmallettvoid
290215976Sjmallettprvars()
291215976Sjmallett{
292215976Sjmallett    plist(&shvhed, VAR_ALL);
293215976Sjmallett}
294215976Sjmallett
295215976Sjmallett/*ARGSUSED*/
296215976Sjmallettvoid
297215976Sjmallettdoalias(v, c)
298215976Sjmallett    Char **v;
299215976Sjmallett    struct command *c;
300215976Sjmallett{
301215976Sjmallett    struct varent *vp;
302215976Sjmallett    Char *p;
303215976Sjmallett
304215976Sjmallett    USE(c);
305215976Sjmallett    v++;
306215976Sjmallett    p = *v++;
307215976Sjmallett    if (p == 0)
308215976Sjmallett	plist(&aliases, VAR_ALL);
309215976Sjmallett    else if (*v == 0) {
310215976Sjmallett	vp = adrof1(strip(p), &aliases);
311215976Sjmallett	if (vp && vp->vec)
312215976Sjmallett	    blkpr(vp->vec), xputchar('\n');
313215976Sjmallett    }
314215976Sjmallett    else {
315215976Sjmallett	if (eq(p, STRalias) || eq(p, STRunalias)) {
316215976Sjmallett	    setname(short2str(p));
317215976Sjmallett	    stderror(ERR_NAME | ERR_DANGER);
318215976Sjmallett	}
319215976Sjmallett	set1(strip(p), saveblk(v), &aliases, VAR_READWRITE);
320215976Sjmallett	tw_cmd_free();
321215976Sjmallett    }
322215976Sjmallett}
323215976Sjmallett
324215976Sjmallett/*ARGSUSED*/
325215976Sjmallettvoid
326215976Sjmallettunalias(v, c)
327215976Sjmallett    Char  **v;
328215976Sjmallett    struct command *c;
329215976Sjmallett{
330215976Sjmallett    USE(c);
331215976Sjmallett    unset1(v, &aliases);
332215976Sjmallett    tw_cmd_free();
333215976Sjmallett}
334215976Sjmallett
335215976Sjmallett/*ARGSUSED*/
336215976Sjmallettvoid
337215976Sjmallettdologout(v, c)
338215976Sjmallett    Char **v;
339215976Sjmallett    struct command *c;
340215976Sjmallett{
341215976Sjmallett    USE(c);
342215976Sjmallett    USE(v);
343215976Sjmallett    islogin();
344215976Sjmallett    goodbye(NULL, NULL);
345215976Sjmallett}
346215976Sjmallett
347215976Sjmallett/*ARGSUSED*/
348215976Sjmallettvoid
349215976Sjmallettdologin(v, c)
350215976Sjmallett    Char  **v;
351215976Sjmallett    struct command *c;
352215976Sjmallett{
353215976Sjmallett#ifdef WINNT_NATIVE
354215976Sjmallett    USE(c);
355215976Sjmallett    USE(v);
356215976Sjmallett#else /* !WINNT_NATIVE */
357215976Sjmallett    char **p = short2blk(v);
358215976Sjmallett    USE(c);
359215976Sjmallett    islogin();
360215976Sjmallett    rechist(NULL, adrof(STRsavehist) != NULL);
361215976Sjmallett    (void) signal(SIGTERM, parterm);
362215976Sjmallett    (void) execv(_PATH_BIN_LOGIN, p);
363215976Sjmallett    (void) execv(_PATH_USRBIN_LOGIN, p);
364215976Sjmallett    blkfree((Char **) p);
365215976Sjmallett    untty();
366215976Sjmallett    xexit(1);
367215976Sjmallett#endif /* !WINNT_NATIVE */
368215976Sjmallett}
369215976Sjmallett
370215976Sjmallett
371215976Sjmallett#ifdef NEWGRP
372215976Sjmallett/*ARGSUSED*/
373215976Sjmallettvoid
374215976Sjmallettdonewgrp(v, c)
375215976Sjmallett    Char  **v;
376215976Sjmallett    struct command *c;
377215976Sjmallett{
378215976Sjmallett    char **p;
379215976Sjmallett    if (chkstop == 0 && setintr)
380215976Sjmallett	panystop(0);
381215976Sjmallett    (void) signal(SIGTERM, parterm);
382215976Sjmallett    p = short2blk(v);
383215976Sjmallett    /*
384215976Sjmallett     * From Beto Appleton (beto@aixwiz.austin.ibm.com)
385215976Sjmallett     * Newgrp can take 2 arguments...
386215976Sjmallett     */
387215976Sjmallett    (void) execv(_PATH_BIN_NEWGRP, p);
388215976Sjmallett    (void) execv(_PATH_USRBIN_NEWGRP, p);
389215976Sjmallett    blkfree((Char **) p);
390215976Sjmallett    untty();
391215976Sjmallett    xexit(1);
392215976Sjmallett}
393215976Sjmallett#endif /* NEWGRP */
394215976Sjmallett
395215976Sjmallettstatic void
396215976Sjmallettislogin()
397215976Sjmallett{
398215976Sjmallett    if (chkstop == 0 && setintr)
399215976Sjmallett	panystop(0);
400215976Sjmallett    if (loginsh)
401215976Sjmallett	return;
402215976Sjmallett    stderror(ERR_NOTLOGIN);
403215976Sjmallett}
404215976Sjmallett
405215976Sjmallettvoid
406215976Sjmallettdoif(v, kp)
407215976Sjmallett    Char  **v;
408215976Sjmallett    struct command *kp;
409215976Sjmallett{
410215976Sjmallett    int i;
411215976Sjmallett    Char **vv;
412215976Sjmallett
413215976Sjmallett    v++;
414215976Sjmallett    i = expr(&v);
415215976Sjmallett    vv = v;
416215976Sjmallett    if (*vv == NULL)
417215976Sjmallett	stderror(ERR_NAME | ERR_EMPTYIF);
418215976Sjmallett    if (eq(*vv, STRthen)) {
419215976Sjmallett	if (*++vv)
420215976Sjmallett	    stderror(ERR_NAME | ERR_IMPRTHEN);
421215976Sjmallett	setname(short2str(STRthen));
422215976Sjmallett	/*
423215976Sjmallett	 * If expression was zero, then scan to else , otherwise just fall into
424215976Sjmallett	 * following code.
425215976Sjmallett	 */
426215976Sjmallett	if (!i)
427215976Sjmallett	    search(TC_IF, 0, NULL);
428215976Sjmallett	return;
429215976Sjmallett    }
430215976Sjmallett    /*
431215976Sjmallett     * Simple command attached to this if. Left shift the node in this tree,
432215976Sjmallett     * munging it so we can reexecute it.
433215976Sjmallett     */
434215976Sjmallett    if (i) {
435215976Sjmallett	lshift(kp->t_dcom, vv - kp->t_dcom);
436215976Sjmallett	reexecute(kp);
437215976Sjmallett	donefds();
438215976Sjmallett    }
439215976Sjmallett}
440215976Sjmallett
441215976Sjmallett/*
442215976Sjmallett * Reexecute a command, being careful not
443215976Sjmallett * to redo i/o redirection, which is already set up.
444215976Sjmallett */
445215976Sjmallettvoid
446215976Sjmallettreexecute(kp)
447215976Sjmallett    struct command *kp;
448215976Sjmallett{
449215976Sjmallett    kp->t_dflg &= F_SAVE;
450215976Sjmallett    kp->t_dflg |= F_REPEAT;
451215976Sjmallett    /*
452215976Sjmallett     * If tty is still ours to arbitrate, arbitrate it; otherwise dont even set
453215976Sjmallett     * pgrp's as the jobs would then have no way to get the tty (we can't give
454215976Sjmallett     * it to them, and our parent wouldn't know their pgrp, etc.
455215976Sjmallett     */
456215976Sjmallett    execute(kp, (tpgrp > 0 ? tpgrp : -1), NULL, NULL, TRUE);
457215976Sjmallett}
458215976Sjmallett
459215976Sjmallett/*ARGSUSED*/
460215976Sjmallettvoid
461215976Sjmallettdoelse (v, c)
462215976Sjmallett    Char **v;
463215976Sjmallett    struct command *c;
464215976Sjmallett{
465215976Sjmallett    USE(c);
466215976Sjmallett    USE(v);
467215976Sjmallett    search(TC_ELSE, 0, NULL);
468215976Sjmallett}
469215976Sjmallett
470215976Sjmallett/*ARGSUSED*/
471215976Sjmallettvoid
472215976Sjmallettdogoto(v, c)
473215976Sjmallett    Char  **v;
474215976Sjmallett    struct command *c;
475215976Sjmallett{
476215976Sjmallett    Char   *lp;
477215976Sjmallett
478215976Sjmallett    USE(c);
479215976Sjmallett    gotolab(lp = globone(v[1], G_ERROR));
480215976Sjmallett    xfree((ptr_t) lp);
481215976Sjmallett}
482215976Sjmallett
483215976Sjmallettvoid
484215976Sjmallettgotolab(lab)
485215976Sjmallett    Char *lab;
486215976Sjmallett{
487215976Sjmallett    struct whyle *wp;
488215976Sjmallett    /*
489215976Sjmallett     * While we still can, locate any unknown ends of existing loops. This
490215976Sjmallett     * obscure code is the WORST result of the fact that we don't really parse.
491215976Sjmallett     */
492215976Sjmallett    zlast = TC_GOTO;
493215976Sjmallett    for (wp = whyles; wp; wp = wp->w_next)
494215976Sjmallett	if (wp->w_end.type == TCSH_F_SEEK && wp->w_end.f_seek == 0) {
495215976Sjmallett	    search(TC_BREAK, 0, NULL);
496215976Sjmallett	    btell(&wp->w_end);
497215976Sjmallett	}
498215976Sjmallett	else {
499215976Sjmallett	    bseek(&wp->w_end);
500215976Sjmallett	}
501215976Sjmallett    search(TC_GOTO, 0, lab);
502215976Sjmallett    /*
503215976Sjmallett     * Eliminate loops which were exited.
504215976Sjmallett     */
505215976Sjmallett    wfree();
506215976Sjmallett}
507215976Sjmallett
508215976Sjmallett/*ARGSUSED*/
509215976Sjmallettvoid
510215976Sjmallettdoswitch(v, c)
511215976Sjmallett    Char **v;
512215976Sjmallett    struct command *c;
513215976Sjmallett{
514215976Sjmallett    Char *cp, *lp;
515215976Sjmallett
516215976Sjmallett    USE(c);
517215976Sjmallett    v++;
518215976Sjmallett    if (!*v || *(*v++) != '(')
519215976Sjmallett	stderror(ERR_SYNTAX);
520215976Sjmallett    cp = **v == ')' ? STRNULL : *v++;
521215976Sjmallett    if (*(*v++) != ')')
522215976Sjmallett	v--;
523215976Sjmallett    if (*v)
524215976Sjmallett	stderror(ERR_SYNTAX);
525215976Sjmallett    search(TC_SWITCH, 0, lp = globone(cp, G_ERROR));
526215976Sjmallett    xfree((ptr_t) lp);
527215976Sjmallett}
528215976Sjmallett
529215976Sjmallett/*ARGSUSED*/
530215976Sjmallettvoid
531215976Sjmallettdobreak(v, c)
532215976Sjmallett    Char **v;
533215976Sjmallett    struct command *c;
534215976Sjmallett{
535215976Sjmallett    USE(v);
536215976Sjmallett    USE(c);
537215976Sjmallett    if (whyles)
538215976Sjmallett	toend();
539215976Sjmallett    else
540215976Sjmallett	stderror(ERR_NAME | ERR_NOTWHILE);
541215976Sjmallett}
542215976Sjmallett
543215976Sjmallett/*ARGSUSED*/
544215976Sjmallettvoid
545215976Sjmallettdoexit(v, c)
546215976Sjmallett    Char  **v;
547215976Sjmallett    struct command *c;
548215976Sjmallett{
549215976Sjmallett    USE(c);
550215976Sjmallett
551215976Sjmallett    if (chkstop == 0 && (intty || intact) && evalvec == 0)
552215976Sjmallett	panystop(0);
553215976Sjmallett    /*
554215976Sjmallett     * Don't DEMAND parentheses here either.
555215976Sjmallett     */
556215976Sjmallett    v++;
557215976Sjmallett    if (*v) {
558215976Sjmallett	set(STRstatus, putn(expr(&v)), VAR_READWRITE);
559215976Sjmallett	if (*v)
560215976Sjmallett	    stderror(ERR_NAME | ERR_EXPRESSION);
561215976Sjmallett    }
562215976Sjmallett    btoeof();
563215976Sjmallett#if 0
564215976Sjmallett    if (intty)
565215976Sjmallett#endif
566215976Sjmallett    /* Always close, why only on ttys? */
567215976Sjmallett	(void) close(SHIN);
568215976Sjmallett}
569215976Sjmallett
570215976Sjmallett/*ARGSUSED*/
571215976Sjmallettvoid
572215976Sjmallettdoforeach(v, c)
573215976Sjmallett    Char **v;
574215976Sjmallett    struct command *c;
575215976Sjmallett{
576215976Sjmallett    Char *cp, *sp;
577215976Sjmallett    struct whyle *nwp;
578215976Sjmallett
579215976Sjmallett    USE(c);
580215976Sjmallett    v++;
581215976Sjmallett    sp = cp = strip(*v);
582215976Sjmallett    if (!letter(*sp))
583215976Sjmallett	stderror(ERR_NAME | ERR_VARBEGIN);
584215976Sjmallett    while (*cp && alnum(*cp))
585215976Sjmallett	cp++;
586215976Sjmallett    if (*cp)
587215976Sjmallett	stderror(ERR_NAME | ERR_VARALNUM);
588215976Sjmallett    if ((cp - sp) > MAXVARLEN)
589215976Sjmallett	stderror(ERR_NAME | ERR_VARTOOLONG);
590215976Sjmallett    cp = *v++;
591215976Sjmallett    if (v[0][0] != '(' || v[blklen(v) - 1][0] != ')')
592215976Sjmallett	stderror(ERR_NAME | ERR_NOPAREN);
593215976Sjmallett    v++;
594215976Sjmallett    gflag = 0, tglob(v);
595215976Sjmallett    if (gflag) {
596215976Sjmallett	v = globall(v);
597215976Sjmallett	if (v == 0)
598215976Sjmallett	    stderror(ERR_NAME | ERR_NOMATCH);
599215976Sjmallett    }
600215976Sjmallett    else {
601215976Sjmallett	v = gargv = saveblk(v);
602215976Sjmallett	trim(v);
603215976Sjmallett    }
604215976Sjmallett    nwp = (struct whyle *) xcalloc(1, sizeof *nwp);
605215976Sjmallett    nwp->w_fe = nwp->w_fe0 = v;
606215976Sjmallett    gargv = 0;
607215976Sjmallett    btell(&nwp->w_start);
608215976Sjmallett    nwp->w_fename = Strsave(cp);
609215976Sjmallett    nwp->w_next = whyles;
610215976Sjmallett    nwp->w_end.type = TCSH_F_SEEK;
611215976Sjmallett    whyles = nwp;
612215976Sjmallett    /*
613215976Sjmallett     * Pre-read the loop so as to be more comprehensible to a terminal user.
614215976Sjmallett     */
615215976Sjmallett    zlast = TC_FOREACH;
616215976Sjmallett    if (intty)
617215976Sjmallett	preread();
618215976Sjmallett    doagain();
619215976Sjmallett}
620215976Sjmallett
621215976Sjmallett/*ARGSUSED*/
622215976Sjmallettvoid
623215976Sjmallettdowhile(v, c)
624215976Sjmallett    Char  **v;
625215976Sjmallett    struct command *c;
626215976Sjmallett{
627215976Sjmallett    int status;
628215976Sjmallett    int again = whyles != 0 &&
629215976Sjmallett			  SEEKEQ(&whyles->w_start, &lineloc) &&
630215976Sjmallett			  whyles->w_fename == 0;
631215976Sjmallett
632215976Sjmallett    USE(c);
633215976Sjmallett    v++;
634215976Sjmallett    /*
635215976Sjmallett     * Implement prereading here also, taking care not to evaluate the
636215976Sjmallett     * expression before the loop has been read up from a terminal.
637215976Sjmallett     */
638215976Sjmallett    if (intty && !again)
639215976Sjmallett	status = !exp0(&v, 1);
640215976Sjmallett    else
641215976Sjmallett	status = !expr(&v);
642215976Sjmallett    if (*v)
643215976Sjmallett	stderror(ERR_NAME | ERR_EXPRESSION);
644215976Sjmallett    if (!again) {
645215976Sjmallett	struct whyle *nwp =
646215976Sjmallett	(struct whyle *) xcalloc(1, sizeof(*nwp));
647215976Sjmallett
648215976Sjmallett	nwp->w_start = lineloc;
649215976Sjmallett	nwp->w_end.type = TCSH_F_SEEK;
650215976Sjmallett	nwp->w_end.f_seek = 0;
651215976Sjmallett	nwp->w_next = whyles;
652215976Sjmallett	whyles = nwp;
653215976Sjmallett	zlast = TC_WHILE;
654215976Sjmallett	if (intty) {
655215976Sjmallett	    /*
656215976Sjmallett	     * The tty preread
657215976Sjmallett	     */
658215976Sjmallett	    preread();
659215976Sjmallett	    doagain();
660215976Sjmallett	    return;
661215976Sjmallett	}
662215976Sjmallett    }
663215976Sjmallett    if (status)
664215976Sjmallett	/* We ain't gonna loop no more, no more! */
665215976Sjmallett	toend();
666215976Sjmallett}
667215976Sjmallett
668215976Sjmallettstatic void
669215976Sjmallettpreread()
670215976Sjmallett{
671215976Sjmallett    whyles->w_end.type = TCSH_I_SEEK;
672215976Sjmallett    if (setintr)
673215976Sjmallett#ifdef BSDSIGS
674215976Sjmallett	(void) sigsetmask(sigblock((sigmask_t) 0) & ~sigmask(SIGINT));
675215976Sjmallett#else /* !BSDSIGS */
676215976Sjmallett	(void) sigrelse (SIGINT);
677215976Sjmallett#endif /* BSDSIGS */
678215976Sjmallett    search(TC_BREAK, 0, NULL);		/* read the expression in */
679215976Sjmallett    if (setintr)
680215976Sjmallett#ifdef BSDSIGS
681215976Sjmallett	(void) sigblock(sigmask(SIGINT));
682215976Sjmallett#else /* !BSDSIGS */
683215976Sjmallett	(void) sighold(SIGINT);
684215976Sjmallett#endif /* BSDSIGS */
685215976Sjmallett    btell(&whyles->w_end);
686215976Sjmallett}
687215976Sjmallett
688215976Sjmallett/*ARGSUSED*/
689215976Sjmallettvoid
690215976Sjmallettdoend(v, c)
691215976Sjmallett    Char **v;
692215976Sjmallett    struct command *c;
693215976Sjmallett{
694215976Sjmallett    USE(v);
695215976Sjmallett    USE(c);
696215976Sjmallett    if (!whyles)
697215976Sjmallett	stderror(ERR_NAME | ERR_NOTWHILE);
698215976Sjmallett    btell(&whyles->w_end);
699215976Sjmallett    doagain();
700215976Sjmallett}
701215976Sjmallett
702215976Sjmallett/*ARGSUSED*/
703215976Sjmallettvoid
704215976Sjmallettdocontin(v, c)
705215976Sjmallett    Char **v;
706215976Sjmallett    struct command *c;
707215976Sjmallett{
708215976Sjmallett    USE(v);
709215976Sjmallett    USE(c);
710215976Sjmallett    if (!whyles)
711215976Sjmallett	stderror(ERR_NAME | ERR_NOTWHILE);
712215976Sjmallett    doagain();
713215976Sjmallett}
714215976Sjmallett
715215976Sjmallettstatic void
716215976Sjmallettdoagain()
717215976Sjmallett{
718215976Sjmallett    /* Repeating a while is simple */
719215976Sjmallett    if (whyles->w_fename == 0) {
720215976Sjmallett	bseek(&whyles->w_start);
721215976Sjmallett	return;
722215976Sjmallett    }
723215976Sjmallett    /*
724215976Sjmallett     * The foreach variable list actually has a spurious word ")" at the end of
725215976Sjmallett     * the w_fe list.  Thus we are at the of the list if one word beyond this
726215976Sjmallett     * is 0.
727215976Sjmallett     */
728215976Sjmallett    if (!whyles->w_fe[1]) {
729215976Sjmallett	dobreak(NULL, NULL);
730215976Sjmallett	return;
731215976Sjmallett    }
732215976Sjmallett    set(whyles->w_fename, quote(Strsave(*whyles->w_fe++)), VAR_READWRITE);
733215976Sjmallett    bseek(&whyles->w_start);
734215976Sjmallett}
735215976Sjmallett
736215976Sjmallettvoid
737215976Sjmallettdorepeat(v, kp)
738215976Sjmallett    Char  **v;
739215976Sjmallett    struct command *kp;
740215976Sjmallett{
741215976Sjmallett    int i = 1;
742215976Sjmallett
743215976Sjmallett#ifdef BSDSIGS
744215976Sjmallett    sigmask_t omask = 0;
745215976Sjmallett#endif /* BSDSIGS */
746215976Sjmallett
747215976Sjmallett    do {
748215976Sjmallett	i *= getn(v[1]);
749215976Sjmallett	lshift(v, 2);
750215976Sjmallett    } while (v[0] != NULL && Strcmp(v[0], STRrepeat) == 0);
751215976Sjmallett
752215976Sjmallett    if (setintr)
753215976Sjmallett#ifdef BSDSIGS
754215976Sjmallett	omask = sigblock(sigmask(SIGINT)) & ~sigmask(SIGINT);
755215976Sjmallett#else /* !BSDSIGS */
756215976Sjmallett	(void) sighold(SIGINT);
757215976Sjmallett#endif /* BSDSIGS */
758215976Sjmallett    while (i > 0) {
759215976Sjmallett	if (setintr)
760215976Sjmallett#ifdef BSDSIGS
761215976Sjmallett	    (void) sigsetmask(omask);
762215976Sjmallett#else /* !BSDSIGS */
763215976Sjmallett	    (void) sigrelse (SIGINT);
764215976Sjmallett#endif /* BSDSIGS */
765215976Sjmallett	reexecute(kp);
766215976Sjmallett	--i;
767215976Sjmallett    }
768215976Sjmallett    donefds();
769215976Sjmallett    if (setintr)
770215976Sjmallett#ifdef BSDSIGS
771215976Sjmallett	(void) sigsetmask(omask);
772215976Sjmallett#else /* !BSDSIGS */
773215976Sjmallett	(void) sigrelse (SIGINT);
774215976Sjmallett#endif /* BSDSIGS */
775215976Sjmallett}
776215976Sjmallett
777215976Sjmallett/*ARGSUSED*/
778215976Sjmallettvoid
779215976Sjmallettdoswbrk(v, c)
780215976Sjmallett    Char **v;
781215976Sjmallett    struct command *c;
782215976Sjmallett{
783215976Sjmallett    USE(v);
784215976Sjmallett    USE(c);
785215976Sjmallett    search(TC_BRKSW, 0, NULL);
786215976Sjmallett}
787215976Sjmallett
788215976Sjmallettint
789215976Sjmallettsrchx(cp)
790215976Sjmallett    Char *cp;
791215976Sjmallett{
792215976Sjmallett    struct srch *sp, *sp1, *sp2;
793215976Sjmallett    int i;
794215976Sjmallett
795215976Sjmallett    /*
796215976Sjmallett     * Ignore keywords inside heredocs
797215976Sjmallett     */
798215976Sjmallett    if (inheredoc)
799215976Sjmallett	return -1;
800215976Sjmallett
801215976Sjmallett    /*
802215976Sjmallett     * Binary search Sp1 is the beginning of the current search range. Sp2 is
803215976Sjmallett     * one past the end.
804215976Sjmallett     */
805215976Sjmallett    for (sp1 = srchn, sp2 = srchn + nsrchn; sp1 < sp2;) {
806215976Sjmallett	sp = sp1 + ((sp2 - sp1) >> 1);
807215976Sjmallett	if ((i = *cp - *sp->s_name) == 0 &&
808215976Sjmallett	    (i = Strcmp(cp, str2short(sp->s_name))) == 0)
809215976Sjmallett	    return sp->s_value;
810215976Sjmallett	if (i < 0)
811215976Sjmallett	    sp2 = sp;
812215976Sjmallett	else
813215976Sjmallett	    sp1 = sp + 1;
814215976Sjmallett    }
815215976Sjmallett    return (-1);
816215976Sjmallett}
817215976Sjmallett
818215976Sjmallettstatic const char *
819215976Sjmallettisrchx(n)
820215976Sjmallett    int n;
821215976Sjmallett{
822215976Sjmallett    struct srch *sp, *sp2;
823215976Sjmallett
824215976Sjmallett    for (sp = srchn, sp2 = srchn + nsrchn; sp < sp2; sp++)
825215976Sjmallett	if (sp->s_value == n)
826215976Sjmallett	    return (sp->s_name);
827215976Sjmallett    return ("");
828215976Sjmallett}
829215976Sjmallett
830215976Sjmallett
831215976Sjmallettstatic Char Stype;
832215976Sjmallettstatic Char *Sgoal;
833215976Sjmallett
834215976Sjmallettstatic void
835215976Sjmallettsearch(type, level, goal)
836215976Sjmallett    int     type;
837215976Sjmallett    int level;
838215976Sjmallett    Char   *goal;
839215976Sjmallett{
840215976Sjmallett    Char    wordbuf[BUFSIZE];
841215976Sjmallett    Char *aword = wordbuf;
842215976Sjmallett    Char *cp;
843215976Sjmallett    struct whyle *wp;
844215976Sjmallett    int wlevel = 0;
845215976Sjmallett
846215976Sjmallett    Stype = (Char) type;
847215976Sjmallett    Sgoal = goal;
848215976Sjmallett    if (type == TC_GOTO) {
849215976Sjmallett	struct Ain a;
850215976Sjmallett	a.type = TCSH_F_SEEK;
851215976Sjmallett	a.f_seek = 0;
852215976Sjmallett	bseek(&a);
853215976Sjmallett    }
854215976Sjmallett    do {
855215976Sjmallett	if (intty && fseekp == feobp && aret == TCSH_F_SEEK)
856215976Sjmallett	    printprompt(1, isrchx(type == TC_BREAK ? zlast : type));
857215976Sjmallett	/* xprintf("? "), flush(); */
858215976Sjmallett	aword[0] = 0;
859215976Sjmallett	(void) getword(aword);
860215976Sjmallett	switch (srchx(aword)) {
861215976Sjmallett
862215976Sjmallett	case TC_ELSE:
863215976Sjmallett	    if (level == 0 && type == TC_IF)
864215976Sjmallett		return;
865215976Sjmallett	    break;
866215976Sjmallett
867215976Sjmallett	case TC_IF:
868215976Sjmallett	    while (getword(aword))
869215976Sjmallett		continue;
870215976Sjmallett	    if ((type == TC_IF || type == TC_ELSE) &&
871215976Sjmallett		eq(aword, STRthen))
872215976Sjmallett		level++;
873215976Sjmallett	    break;
874215976Sjmallett
875215976Sjmallett	case TC_ENDIF:
876215976Sjmallett	    if (type == TC_IF || type == TC_ELSE)
877215976Sjmallett		level--;
878215976Sjmallett	    break;
879215976Sjmallett
880215976Sjmallett	case TC_FOREACH:
881215976Sjmallett	case TC_WHILE:
882215976Sjmallett	    wlevel++;
883215976Sjmallett	    if (type == TC_BREAK)
884215976Sjmallett		level++;
885215976Sjmallett	    break;
886215976Sjmallett
887215976Sjmallett	case TC_END:
888215976Sjmallett	    if (type == TC_BRKSW) {
889215976Sjmallett		if (wlevel == 0) {
890215976Sjmallett		    wp = whyles;
891215976Sjmallett		    if (wp) {
892215976Sjmallett			    whyles = wp->w_next;
893215976Sjmallett			    wpfree(wp);
894215976Sjmallett		    }
895215976Sjmallett		}
896215976Sjmallett	    }
897215976Sjmallett	    if (type == TC_BREAK)
898215976Sjmallett		level--;
899215976Sjmallett	    wlevel--;
900215976Sjmallett	    break;
901215976Sjmallett
902215976Sjmallett	case TC_SWITCH:
903215976Sjmallett	    if (type == TC_SWITCH || type == TC_BRKSW)
904215976Sjmallett		level++;
905215976Sjmallett	    break;
906215976Sjmallett
907215976Sjmallett	case TC_ENDSW:
908215976Sjmallett	    if (type == TC_SWITCH || type == TC_BRKSW)
909215976Sjmallett		level--;
910215976Sjmallett	    break;
911215976Sjmallett
912215976Sjmallett	case TC_LABEL:
913215976Sjmallett	    if (type == TC_GOTO && getword(aword) && eq(aword, goal))
914215976Sjmallett		level = -1;
915215976Sjmallett	    break;
916215976Sjmallett
917215976Sjmallett	default:
918215976Sjmallett	    if (type != TC_GOTO && (type != TC_SWITCH || level != 0))
919215976Sjmallett		break;
920215976Sjmallett	    if (lastchr(aword) != ':')
921215976Sjmallett		break;
922215976Sjmallett	    aword[Strlen(aword) - 1] = 0;
923215976Sjmallett	    if ((type == TC_GOTO && eq(aword, goal)) ||
924215976Sjmallett		(type == TC_SWITCH && eq(aword, STRdefault)))
925215976Sjmallett		level = -1;
926215976Sjmallett	    break;
927215976Sjmallett
928215976Sjmallett	case TC_CASE:
929215976Sjmallett	    if (type != TC_SWITCH || level != 0)
930215976Sjmallett		break;
931215976Sjmallett	    (void) getword(aword);
932215976Sjmallett	    if (lastchr(aword) == ':')
933215976Sjmallett		aword[Strlen(aword) - 1] = 0;
934215976Sjmallett	    cp = strip(Dfix1(aword));
935215976Sjmallett	    if (Gmatch(goal, cp))
936215976Sjmallett		level = -1;
937215976Sjmallett	    xfree((ptr_t) cp);
938215976Sjmallett	    break;
939215976Sjmallett
940215976Sjmallett	case TC_DEFAULT:
941215976Sjmallett	    if (type == TC_SWITCH && level == 0)
942215976Sjmallett		level = -1;
943215976Sjmallett	    break;
944215976Sjmallett	}
945215976Sjmallett	(void) getword(NULL);
946215976Sjmallett    } while (level >= 0);
947215976Sjmallett}
948215976Sjmallett
949215976Sjmallettstatic int
950215976Sjmallettgetword(wp)
951215976Sjmallett    Char *wp;
952215976Sjmallett{
953215976Sjmallett    int found = 0, first;
954215976Sjmallett    eChar c, d;
955215976Sjmallett
956215976Sjmallett    c = readc(1);
957215976Sjmallett    d = 0;
958215976Sjmallett    do {
959215976Sjmallett	while (c == ' ' || c == '\t')
960215976Sjmallett	    c = readc(1);
961215976Sjmallett	if (c == '#')
962215976Sjmallett	    do
963215976Sjmallett		c = readc(1);
964215976Sjmallett	    while (c != CHAR_ERR && c != '\n');
965215976Sjmallett	if (c == CHAR_ERR)
966215976Sjmallett	    goto past;
967215976Sjmallett	if (c == '\n') {
968215976Sjmallett	    if (wp)
969215976Sjmallett		break;
970215976Sjmallett	    return (0);
971215976Sjmallett	}
972215976Sjmallett	unreadc(c);
973215976Sjmallett	found = 1;
974215976Sjmallett	first = 1;
975215976Sjmallett	do {
976215976Sjmallett	    c = readc(1);
977215976Sjmallett	    if (c == '\\' && (c = readc(1)) == '\n')
978215976Sjmallett		c = ' ';
979215976Sjmallett	    if (c == '\'' || c == '"') {
980215976Sjmallett		if (d == 0)
981215976Sjmallett		    d = c;
982215976Sjmallett		else if (d == c)
983215976Sjmallett		    d = 0;
984215976Sjmallett	    }
985215976Sjmallett	    if (c == CHAR_ERR)
986215976Sjmallett		goto past;
987215976Sjmallett	    if (wp) {
988215976Sjmallett		*wp++ = (Char) c;
989215976Sjmallett		*wp = '\0';
990215976Sjmallett	    }
991215976Sjmallett	    if (!first && !d && c == '(') {
992215976Sjmallett		if (wp) {
993215976Sjmallett		    unreadc(c);
994215976Sjmallett		    *--wp = '\0';
995215976Sjmallett		    return found;
996215976Sjmallett		}
997215976Sjmallett		else
998215976Sjmallett		    break;
999215976Sjmallett	    }
1000215976Sjmallett	    first = 0;
1001215976Sjmallett	} while ((d || (c != ' ' && c != '\t')) && c != '\n');
1002215976Sjmallett    } while (wp == 0);
1003215976Sjmallett
1004215976Sjmallett    unreadc(c);
1005215976Sjmallett    if (found)
1006215976Sjmallett	*--wp = '\0';
1007215976Sjmallett
1008215976Sjmallett    return (found);
1009215976Sjmallett
1010215976Sjmallettpast:
1011215976Sjmallett    switch (Stype) {
1012215976Sjmallett
1013215976Sjmallett    case TC_IF:
1014215976Sjmallett	stderror(ERR_NAME | ERR_NOTFOUND, "then/endif");
1015215976Sjmallett	break;
1016215976Sjmallett
1017215976Sjmallett    case TC_ELSE:
1018215976Sjmallett	stderror(ERR_NAME | ERR_NOTFOUND, "endif");
1019215976Sjmallett	break;
1020215976Sjmallett
1021215976Sjmallett    case TC_BRKSW:
1022215976Sjmallett    case TC_SWITCH:
1023215976Sjmallett	stderror(ERR_NAME | ERR_NOTFOUND, "endsw");
1024215976Sjmallett	break;
1025215976Sjmallett
1026215976Sjmallett    case TC_BREAK:
1027215976Sjmallett	stderror(ERR_NAME | ERR_NOTFOUND, "end");
1028215976Sjmallett	break;
1029215976Sjmallett
1030215976Sjmallett    case TC_GOTO:
1031215976Sjmallett	setname(short2str(Sgoal));
1032215976Sjmallett	stderror(ERR_NAME | ERR_NOTFOUND, "label");
1033215976Sjmallett	break;
1034215976Sjmallett
1035215976Sjmallett    default:
1036215976Sjmallett	break;
1037215976Sjmallett    }
1038215976Sjmallett    /* NOTREACHED */
1039215976Sjmallett    return (0);
1040215976Sjmallett}
1041215976Sjmallett
1042215976Sjmallettstatic void
1043215976Sjmalletttoend()
1044215976Sjmallett{
1045215976Sjmallett    if (whyles->w_end.type == TCSH_F_SEEK && whyles->w_end.f_seek == 0) {
1046215976Sjmallett	search(TC_BREAK, 0, NULL);
1047215976Sjmallett	btell(&whyles->w_end);
1048215976Sjmallett	whyles->w_end.f_seek--;
1049215976Sjmallett    }
1050215976Sjmallett    else {
1051215976Sjmallett	bseek(&whyles->w_end);
1052215976Sjmallett    }
1053215976Sjmallett    wfree();
1054215976Sjmallett}
1055215976Sjmallett
1056215976Sjmallettstatic void
1057215976Sjmallettwpfree(wp)
1058215976Sjmallett    struct whyle *wp;
1059215976Sjmallett{
1060215976Sjmallett	if (wp->w_fe0)
1061215976Sjmallett	    blkfree(wp->w_fe0);
1062215976Sjmallett	if (wp->w_fename)
1063215976Sjmallett	    xfree((ptr_t) wp->w_fename);
1064215976Sjmallett	xfree((ptr_t) wp);
1065215976Sjmallett}
1066215976Sjmallett
1067215976Sjmallettvoid
1068215976Sjmallettwfree()
1069215976Sjmallett{
1070215976Sjmallett    struct Ain    o;
1071215976Sjmallett    struct whyle *nwp;
1072215976Sjmallett#ifdef lint
1073215976Sjmallett    nwp = NULL;	/* sun lint is dumb! */
1074215976Sjmallett#endif
1075215976Sjmallett
1076215976Sjmallett#ifdef FDEBUG
1077215976Sjmallett    static char foo[] = "IAFE";
1078215976Sjmallett#endif /* FDEBUG */
1079215976Sjmallett
1080215976Sjmallett    btell(&o);
1081215976Sjmallett
1082215976Sjmallett#ifdef FDEBUG
1083215976Sjmallett    xprintf("o->type %c o->a_seek %d o->f_seek %d\n",
1084215976Sjmallett	    foo[o.type + 1], o.a_seek, o.f_seek);
1085215976Sjmallett#endif /* FDEBUG */
1086215976Sjmallett
1087215976Sjmallett    for (; whyles; whyles = nwp) {
1088215976Sjmallett	struct whyle *wp = whyles;
1089215976Sjmallett	nwp = wp->w_next;
1090215976Sjmallett
1091215976Sjmallett#ifdef FDEBUG
1092215976Sjmallett	xprintf("start->type %c start->a_seek %d start->f_seek %d\n",
1093215976Sjmallett		foo[wp->w_start.type+1],
1094215976Sjmallett		wp->w_start.a_seek, wp->w_start.f_seek);
1095215976Sjmallett	xprintf("end->type %c end->a_seek %d end->f_seek %d\n",
1096215976Sjmallett		foo[wp->w_end.type + 1], wp->w_end.a_seek, wp->w_end.f_seek);
1097215976Sjmallett#endif /* FDEBUG */
1098215976Sjmallett
1099215976Sjmallett	/*
1100215976Sjmallett	 * XXX: We free loops that have different seek types.
1101215976Sjmallett	 */
1102215976Sjmallett	if (wp->w_end.type != TCSH_I_SEEK && wp->w_start.type == wp->w_end.type &&
1103215976Sjmallett	    wp->w_start.type == o.type) {
1104215976Sjmallett	    if (wp->w_end.type == TCSH_F_SEEK) {
1105215976Sjmallett		if (o.f_seek >= wp->w_start.f_seek &&
1106215976Sjmallett		    (wp->w_end.f_seek == 0 || o.f_seek < wp->w_end.f_seek))
1107215976Sjmallett		    break;
1108215976Sjmallett	    }
1109215976Sjmallett	    else {
1110215976Sjmallett		if (o.a_seek >= wp->w_start.a_seek &&
1111215976Sjmallett		    (wp->w_end.a_seek == 0 || o.a_seek < wp->w_end.a_seek))
1112215976Sjmallett		    break;
1113215976Sjmallett	    }
1114215976Sjmallett	}
1115215976Sjmallett
1116215976Sjmallett	wpfree(wp);
1117215976Sjmallett    }
1118215976Sjmallett}
1119215976Sjmallett
1120215976Sjmallett/*ARGSUSED*/
1121215976Sjmallettvoid
1122215976Sjmallettdoecho(v, c)
1123215976Sjmallett    Char  **v;
1124215976Sjmallett    struct command *c;
1125215976Sjmallett{
1126215976Sjmallett    USE(c);
1127215976Sjmallett    xecho(' ', v);
1128215976Sjmallett}
1129215976Sjmallett
1130215976Sjmallett/*ARGSUSED*/
1131215976Sjmallettvoid
1132215976Sjmallettdoglob(v, c)
1133215976Sjmallett    Char  **v;
1134215976Sjmallett    struct command *c;
1135215976Sjmallett{
1136215976Sjmallett    USE(c);
1137215976Sjmallett    xecho(0, v);
1138215976Sjmallett    flush();
1139215976Sjmallett}
1140215976Sjmallett
1141215976Sjmallettstatic void
1142215976Sjmallettxecho(sep, v)
1143215976Sjmallett    int    sep;
1144215976Sjmallett    Char **v;
1145215976Sjmallett{
1146215976Sjmallett    Char *cp;
1147215976Sjmallett    int     nonl = 0;
1148215976Sjmallett#ifdef ECHO_STYLE
1149215976Sjmallett    int	    echo_style = ECHO_STYLE;
1150215976Sjmallett#else /* !ECHO_STYLE */
1151215976Sjmallett# if SYSVREL > 0
1152215976Sjmallett    int	    echo_style = SYSV_ECHO;
1153215976Sjmallett# else /* SYSVREL == 0 */
1154215976Sjmallett    int	    echo_style = BSD_ECHO;
1155215976Sjmallett# endif /* SYSVREL */
1156215976Sjmallett#endif /* ECHO_STYLE */
1157215976Sjmallett    struct varent *vp;
1158215976Sjmallett
1159215976Sjmallett    if ((vp = adrof(STRecho_style)) != NULL && vp->vec != NULL &&
1160215976Sjmallett	vp->vec[0] != NULL) {
1161215976Sjmallett	if (Strcmp(vp->vec[0], STRbsd) == 0)
1162215976Sjmallett	    echo_style = BSD_ECHO;
1163215976Sjmallett	else if (Strcmp(vp->vec[0], STRsysv) == 0)
1164215976Sjmallett	    echo_style = SYSV_ECHO;
1165215976Sjmallett	else if (Strcmp(vp->vec[0], STRboth) == 0)
1166215976Sjmallett	    echo_style = BOTH_ECHO;
1167215976Sjmallett	else if (Strcmp(vp->vec[0], STRnone) == 0)
1168215976Sjmallett	    echo_style = NONE_ECHO;
1169215976Sjmallett    }
1170215976Sjmallett
1171215976Sjmallett    if (setintr)
1172215976Sjmallett#ifdef BSDSIGS
1173	(void) sigsetmask(sigblock((sigmask_t) 0) & ~sigmask(SIGINT));
1174#else /* !BSDSIGS */
1175	(void) sigrelse (SIGINT);
1176#endif /* BSDSIGS */
1177    v++;
1178    if (*v == 0)
1179	goto done;
1180    gflag = 0, tglob(v);
1181    if (gflag) {
1182	v = globall(v);
1183	if (v == 0)
1184	    stderror(ERR_NAME | ERR_NOMATCH);
1185    }
1186    else {
1187	v = gargv = saveblk(v);
1188	trim(v);
1189    }
1190
1191    if ((echo_style & BSD_ECHO) != 0 && sep == ' ' && *v && eq(*v, STRmn))
1192	nonl++, v++;
1193
1194    while ((cp = *v++) != 0) {
1195	Char c;
1196
1197	while ((c = *cp++) != 0) {
1198	    if ((echo_style & SYSV_ECHO) != 0 && c == '\\') {
1199		switch (c = *cp++) {
1200		case 'a':
1201		    c = '\a';
1202		    break;
1203		case 'b':
1204		    c = '\b';
1205		    break;
1206		case 'c':
1207		    nonl = 1;
1208		    goto done;
1209		case 'e':
1210#if 0			/* Windows does not understand \e */
1211		    c = '\e';
1212#else
1213		    c = '\033';
1214#endif
1215		    break;
1216		case 'f':
1217		    c = '\f';
1218		    break;
1219		case 'n':
1220		    c = '\n';
1221		    break;
1222		case 'r':
1223		    c = '\r';
1224		    break;
1225		case 't':
1226		    c = '\t';
1227		    break;
1228		case 'v':
1229		    c = '\v';
1230		    break;
1231		case '\\':
1232		    c = '\\';
1233		    break;
1234		case '0':
1235		    c = 0;
1236		    if (*cp >= '0' && *cp < '8')
1237			c = c * 8 + *cp++ - '0';
1238		    if (*cp >= '0' && *cp < '8')
1239			c = c * 8 + *cp++ - '0';
1240		    if (*cp >= '0' && *cp < '8')
1241			c = c * 8 + *cp++ - '0';
1242		    break;
1243		case '\0':
1244		    c = '\\';
1245		    cp--;
1246		    break;
1247		default:
1248		    xputchar('\\' | QUOTE);
1249		    break;
1250		}
1251	    }
1252	    xputwchar(c | QUOTE);
1253
1254	}
1255	if (*v)
1256	    xputchar(sep | QUOTE);
1257    }
1258done:
1259    if (sep && nonl == 0)
1260	xputchar('\n');
1261    else
1262	flush();
1263    if (setintr)
1264#ifdef BSDSIGS
1265	(void) sigblock(sigmask(SIGINT));
1266#else /* !BSDSIGS */
1267	(void) sighold(SIGINT);
1268#endif /* BSDSIGS */
1269    if (gargv)
1270	blkfree(gargv), gargv = 0;
1271}
1272
1273/* check whether an environment variable should invoke 'set_locale()' */
1274static int
1275islocale_var(var)
1276    Char *var;
1277{
1278    static Char *locale_vars[] = {
1279	STRLANG,	STRLC_ALL, 	STRLC_CTYPE,	STRLC_NUMERIC,
1280	STRLC_TIME,	STRLC_COLLATE,	STRLC_MESSAGES,	STRLC_MONETARY, 0
1281    };
1282    Char **v;
1283
1284    for (v = locale_vars; *v; ++v)
1285	if (eq(var, *v))
1286	    return 1;
1287    return 0;
1288}
1289
1290/*ARGSUSED*/
1291void
1292doprintenv(v, c)
1293    Char **v;
1294    struct command *c;
1295{
1296    Char   *e;
1297
1298    USE(c);
1299    if (setintr)
1300#ifdef BSDSIGS
1301	(void) sigsetmask(sigblock((sigmask_t) 0) & ~sigmask(SIGINT));
1302#else /* !BSDSIGS */
1303	(void) sigrelse (SIGINT);
1304#endif /* BSDSIGS */
1305
1306    v++;
1307    if (*v == 0) {
1308	Char **ep;
1309
1310	xlate_cr = 1;
1311	for (ep = STR_environ; *ep; ep++)
1312	    xprintf("%S\n", *ep);
1313	xlate_cr = 0;
1314    }
1315    else if ((e = tgetenv(*v)) != NULL) {
1316	output_raw = 1;
1317	xprintf("%S\n", e);
1318	output_raw = 0;
1319    }
1320    else
1321	set(STRstatus, Strsave(STR1), VAR_READWRITE);
1322}
1323
1324/* from "Karl Berry." <karl%mote.umb.edu@relay.cs.net> -- for NeXT things
1325   (and anything else with a modern compiler) */
1326
1327/*ARGSUSED*/
1328void
1329dosetenv(v, c)
1330    Char **v;
1331    struct command *c;
1332{
1333    Char   *vp, *lp;
1334
1335    USE(c);
1336    if (*++v == 0) {
1337	doprintenv(--v, 0);
1338	return;
1339    }
1340
1341    vp = *v++;
1342
1343    lp = vp;
1344
1345    for (; *lp != '\0' ; lp++) {
1346	if (*lp == '=')
1347	    stderror(ERR_NAME | ERR_SYNTAX);
1348    }
1349    if ((lp = *v++) == 0)
1350	lp = STRNULL;
1351
1352    tsetenv(vp, lp = globone(lp, G_APPEND));
1353    if (eq(vp, STRKPATH)) {
1354	importpath(lp);
1355	dohash(NULL, NULL);
1356	xfree((ptr_t) lp);
1357	return;
1358    }
1359
1360#ifdef apollo
1361    if (eq(vp, STRSYSTYPE)) {
1362	dohash(NULL, NULL);
1363	xfree((ptr_t) lp);
1364	return;
1365    }
1366#endif /* apollo */
1367
1368    /* dspkanji/dspmbyte autosetting */
1369    /* PATCH IDEA FROM Issei.Suzuki VERY THANKS */
1370#if defined(DSPMBYTE)
1371    if(eq(vp, STRLANG) && !adrof(CHECK_MBYTEVAR)) {
1372	autoset_dspmbyte(lp);
1373    }
1374#endif
1375
1376    if (islocale_var(vp)) {
1377#ifdef NLS
1378	int     k;
1379
1380# ifdef SETLOCALEBUG
1381	dont_free = 1;
1382# endif /* SETLOCALEBUG */
1383	(void) setlocale(LC_ALL, "");
1384# ifdef LC_COLLATE
1385	(void) setlocale(LC_COLLATE, "");
1386# endif
1387# ifdef LC_CTYPE
1388	(void) setlocale(LC_CTYPE, ""); /* for iscntrl */
1389# endif /* LC_CTYPE */
1390# ifdef NLS_CATALOGS
1391#  ifdef LC_MESSAGES
1392	(void) setlocale(LC_MESSAGES, "");
1393#  endif /* LC_MESSAGES */
1394	nlsclose();
1395	nlsinit();
1396# endif /* NLS_CATALOGS */
1397# ifdef SETLOCALEBUG
1398	dont_free = 0;
1399# endif /* SETLOCALEBUG */
1400# ifdef STRCOLLBUG
1401	fix_strcoll_bug();
1402# endif /* STRCOLLBUG */
1403	tw_cmd_free();	/* since the collation sequence has changed */
1404	for (k = 0200; k <= 0377 && !Isprint(k); k++)
1405	    continue;
1406	AsciiOnly = MB_CUR_MAX == 1 && k > 0377;
1407#else /* !NLS */
1408	AsciiOnly = 0;
1409#endif /* NLS */
1410	NLSMapsAreInited = 0;
1411	ed_Init();
1412	if (MapsAreInited && !NLSMapsAreInited)
1413	    ed_InitNLSMaps();
1414	xfree((ptr_t) lp);
1415	return;
1416    }
1417
1418#ifdef NLS_CATALOGS
1419    if (eq(vp, STRNLSPATH)) {
1420	nlsclose();
1421	nlsinit();
1422    }
1423#endif
1424
1425    if (eq(vp, STRNOREBIND)) {
1426	NoNLSRebind = 1;
1427	MapsAreInited = 0;
1428	NLSMapsAreInited = 0;
1429	ed_InitMaps();
1430	xfree((ptr_t) lp);
1431	return;
1432    }
1433#ifdef WINNT_NATIVE
1434    if (eq(vp, STRtcshlang)) {
1435	nlsinit();
1436	xfree((ptr_t) lp);
1437	return;
1438    }
1439#endif /* WINNT_NATIVE */
1440    if (eq(vp, STRKTERM)) {
1441	char *t;
1442	set(STRterm, quote(lp), VAR_READWRITE);	/* lp memory used here */
1443	t = short2str(lp);
1444	if (noediting && strcmp(t, "unknown") != 0 && strcmp(t,"dumb") != 0) {
1445	    editing = 1;
1446	    noediting = 0;
1447	    set(STRedit, Strsave(STRNULL), VAR_READWRITE);
1448	}
1449	GotTermCaps = 0;
1450	ed_Init();
1451	return;
1452    }
1453
1454    if (eq(vp, STRKHOME)) {
1455	/*
1456	 * convert to canonical pathname (possibly resolving symlinks)
1457	 */
1458	lp = dcanon(lp, lp);
1459	set(STRhome, quote(lp), VAR_READWRITE);	/* cp memory used here */
1460
1461	/* fix directory stack for new tilde home */
1462	dtilde();
1463	return;
1464    }
1465
1466    if (eq(vp, STRKSHLVL)) {
1467	/* lp memory used here */
1468	set(STRshlvl, quote(lp), VAR_READWRITE);
1469	return;
1470    }
1471
1472    if (eq(vp, STRKUSER)) {
1473	set(STRuser, quote(lp), VAR_READWRITE);	/* lp memory used here */
1474	return;
1475    }
1476
1477    if (eq(vp, STRKGROUP)) {
1478	set(STRgroup, quote(lp), VAR_READWRITE);	/* lp memory used here */
1479	return;
1480    }
1481
1482#ifdef COLOR_LS_F
1483    if (eq(vp, STRLS_COLORS)) {
1484        parseLS_COLORS(lp);
1485	return;
1486    }
1487#endif /* COLOR_LS_F */
1488
1489#ifdef SIG_WINDOW
1490    /*
1491     * Load/Update $LINES $COLUMNS
1492     */
1493    if ((eq(lp, STRNULL) && (eq(vp, STRLINES) || eq(vp, STRCOLUMNS))) ||
1494	eq(vp, STRTERMCAP)) {
1495	xfree((ptr_t) lp);
1496	check_window_size(1);
1497	return;
1498    }
1499
1500    /*
1501     * Change the size to the one directed by $LINES and $COLUMNS
1502     */
1503    if (eq(vp, STRLINES) || eq(vp, STRCOLUMNS)) {
1504#if 0
1505	GotTermCaps = 0;
1506#endif
1507	xfree((ptr_t) lp);
1508	ed_Init();
1509	return;
1510    }
1511#endif /* SIG_WINDOW */
1512    xfree((ptr_t) lp);
1513}
1514
1515/*ARGSUSED*/
1516void
1517dounsetenv(v, c)
1518    Char **v;
1519    struct command *c;
1520{
1521    Char  **ep, *p, *n;
1522    int     i, maxi;
1523    static Char *name = NULL;
1524
1525    USE(c);
1526    if (name)
1527	xfree((ptr_t) name);
1528    /*
1529     * Find the longest environment variable
1530     */
1531    for (maxi = 0, ep = STR_environ; *ep; ep++) {
1532	for (i = 0, p = *ep; *p && *p != '='; p++, i++)
1533	    continue;
1534	if (i > maxi)
1535	    maxi = i;
1536    }
1537
1538    name = (Char *) xmalloc((size_t) ((maxi + 1) * sizeof(Char)));
1539
1540    while (++v && *v)
1541	for (maxi = 1; maxi;)
1542	    for (maxi = 0, ep = STR_environ; *ep; ep++) {
1543		for (n = name, p = *ep; *p && *p != '='; *n++ = *p++)
1544		    continue;
1545		*n = '\0';
1546		if (!Gmatch(name, *v))
1547		    continue;
1548		maxi = 1;
1549
1550		/* Unset the name. This wasn't being done until
1551		 * later but most of the stuff following won't
1552		 * work (particularly the setlocale() and getenv()
1553		 * stuff) as intended until the name is actually
1554		 * removed. (sg)
1555		 */
1556		Unsetenv(name);
1557
1558		if (eq(name, STRNOREBIND)) {
1559		    NoNLSRebind = 0;
1560		    MapsAreInited = 0;
1561		    NLSMapsAreInited = 0;
1562		    ed_InitMaps();
1563		}
1564#ifdef apollo
1565		else if (eq(name, STRSYSTYPE))
1566		    dohash(NULL, NULL);
1567#endif /* apollo */
1568		else if (islocale_var(name)) {
1569#ifdef NLS
1570		    int     k;
1571
1572# ifdef SETLOCALEBUG
1573		    dont_free = 1;
1574# endif /* SETLOCALEBUG */
1575		    (void) setlocale(LC_ALL, "");
1576# ifdef LC_COLLATE
1577		    (void) setlocale(LC_COLLATE, "");
1578# endif
1579# ifdef LC_CTYPE
1580	(void) setlocale(LC_CTYPE, ""); /* for iscntrl */
1581# endif /* LC_CTYPE */
1582# ifdef NLS_CATALOGS
1583#  ifdef LC_MESSAGES
1584		    (void) setlocale(LC_MESSAGES, "");
1585#  endif /* LC_MESSAGES */
1586		    nlsclose();
1587		    nlsinit();
1588# endif /* NLS_CATALOGS */
1589# ifdef SETLOCALEBUG
1590		    dont_free = 0;
1591# endif /* SETLOCALEBUG */
1592# ifdef STRCOLLBUG
1593		    fix_strcoll_bug();
1594# endif /* STRCOLLBUG */
1595		    tw_cmd_free();/* since the collation sequence has changed */
1596		    for (k = 0200; k <= 0377 && !Isprint(k); k++)
1597			continue;
1598		    AsciiOnly = MB_CUR_MAX == 1 && k > 0377;
1599#else /* !NLS */
1600		    AsciiOnly = getenv("LANG") == NULL &&
1601			getenv("LC_CTYPE") == NULL;
1602#endif /* NLS */
1603		    NLSMapsAreInited = 0;
1604		    ed_Init();
1605		    if (MapsAreInited && !NLSMapsAreInited)
1606			ed_InitNLSMaps();
1607
1608		}
1609#ifdef WINNT_NATIVE
1610		else if (eq(name,(STRtcshlang))) {
1611		    nls_dll_unload();
1612		    nlsinit();
1613		}
1614#endif /* WINNT_NATIVE */
1615#ifdef COLOR_LS_F
1616		else if (eq(name, STRLS_COLORS))
1617		    parseLS_COLORS(n);
1618#endif /* COLOR_LS_F */
1619#ifdef NLS_CATALOGS
1620		else if (eq(name, STRNLSPATH)) {
1621		    nlsclose();
1622		    nlsinit();
1623		}
1624#endif
1625		/*
1626		 * start again cause the environment changes
1627		 */
1628		break;
1629	    }
1630    xfree((ptr_t) name); name = NULL;
1631}
1632
1633void
1634tsetenv(name, val)
1635    const Char *name, *val;
1636{
1637#ifdef SETENV_IN_LIB
1638/*
1639 * XXX: This does not work right, since tcsh cannot track changes to
1640 * the environment this way. (the builtin setenv without arguments does
1641 * not print the right stuff neither does unsetenv). This was for Mach,
1642 * it is not needed anymore.
1643 */
1644#undef setenv
1645    char    nameBuf[BUFSIZE];
1646    char   *cname = short2str(name);
1647
1648    if (cname == NULL)
1649	return;
1650    (void) strcpy(nameBuf, cname);
1651    setenv(nameBuf, short2str(val), 1);
1652#else /* !SETENV_IN_LIB */
1653    Char **ep = STR_environ;
1654    const Char *ccp;
1655    Char *cp, *dp;
1656    Char   *blk[2];
1657    Char  **oep = ep;
1658
1659#ifdef WINNT_NATIVE
1660	nt_set_env(name,val);
1661#endif /* WINNT_NATIVE */
1662    for (; *ep; ep++) {
1663#ifdef WINNT_NATIVE
1664	for (ccp = name, dp = *ep; *ccp && Tolower(*ccp & TRIM) == Tolower(*dp);
1665				ccp++, dp++)
1666#else
1667	for (ccp = name, dp = *ep; *ccp && (*ccp & TRIM) == *dp; ccp++, dp++)
1668#endif /* WINNT_NATIVE */
1669	    continue;
1670	if (*ccp != 0 || *dp != '=')
1671	    continue;
1672	cp = Strspl(STRequal, val);
1673	xfree((ptr_t) * ep);
1674	*ep = strip(Strspl(name, cp));
1675	xfree((ptr_t) cp);
1676	blkfree((Char **) environ);
1677	environ = short2blk(STR_environ);
1678	return;
1679    }
1680    cp = Strspl(name, STRequal);
1681    blk[0] = strip(Strspl(cp, val));
1682    xfree((ptr_t) cp);
1683    blk[1] = 0;
1684    STR_environ = blkspl(STR_environ, blk);
1685    blkfree((Char **) environ);
1686    environ = short2blk(STR_environ);
1687    xfree((ptr_t) oep);
1688#endif /* SETENV_IN_LIB */
1689}
1690
1691void
1692Unsetenv(name)
1693    Char   *name;
1694{
1695    Char **ep = STR_environ;
1696    Char *cp, *dp;
1697    Char **oep = ep;
1698
1699#ifdef WINNT_NATIVE
1700	nt_set_env(name,NULL);
1701#endif /*WINNT_NATIVE */
1702    for (; *ep; ep++) {
1703	for (cp = name, dp = *ep; *cp && *cp == *dp; cp++, dp++)
1704	    continue;
1705	if (*cp != 0 || *dp != '=')
1706	    continue;
1707	cp = *ep;
1708	*ep = 0;
1709	STR_environ = blkspl(STR_environ, ep + 1);
1710	blkfree((Char **) environ);
1711	environ = short2blk(STR_environ);
1712	*ep = cp;
1713	xfree((ptr_t) cp);
1714	xfree((ptr_t) oep);
1715	return;
1716    }
1717}
1718
1719/*ARGSUSED*/
1720void
1721doumask(v, c)
1722    Char **v;
1723    struct command *c;
1724{
1725    Char *cp = v[1];
1726    int i;
1727
1728    USE(c);
1729    if (cp == 0) {
1730	i = (int)umask(0);
1731	(void) umask(i);
1732	xprintf("%o\n", i);
1733	return;
1734    }
1735    i = 0;
1736    while (Isdigit(*cp) && *cp != '8' && *cp != '9')
1737	i = i * 8 + *cp++ - '0';
1738    if (*cp || i < 0 || i > 0777)
1739	stderror(ERR_NAME | ERR_MASK);
1740    (void) umask(i);
1741}
1742
1743#ifndef HAVENOLIMIT
1744# ifndef BSDLIMIT
1745   typedef long RLIM_TYPE;
1746#  ifdef _OSD_POSIX /* BS2000 */
1747#   include <ulimit.h>
1748#  endif
1749#  ifndef RLIM_INFINITY
1750#   if !defined(_MINIX) && !defined(__clipper__) && !defined(_CRAY)
1751    extern RLIM_TYPE ulimit();
1752#   endif /* ! _MINIX && !__clipper__ */
1753#   define RLIM_INFINITY 0x003fffff
1754#   define RLIMIT_FSIZE 1
1755#  endif /* RLIM_INFINITY */
1756#  ifdef aiws
1757#   define toset(a) (((a) == 3) ? 1004 : (a) + 1)
1758#   define RLIMIT_DATA	3
1759#   define RLIMIT_STACK 1005
1760#  else /* aiws */
1761#   define toset(a) ((a) + 1)
1762#  endif /* aiws */
1763# else /* BSDLIMIT */
1764#  if (defined(BSD4_4) || defined(__linux__) || defined(__GNU__) || defined(__GLIBC__) || (HPUXVERSION >= 1100)) && !defined(__386BSD__)
1765    typedef rlim_t RLIM_TYPE;
1766#  else
1767#   if defined(SOLARIS2) || (defined(sgi) && SYSVREL > 3)
1768     typedef rlim_t RLIM_TYPE;
1769#   else
1770#    if defined(_SX)
1771      typedef long long RLIM_TYPE;
1772#    else /* !_SX */
1773      typedef unsigned long RLIM_TYPE;
1774#    endif /* _SX */
1775#   endif /* SOLARIS2 || (sgi && SYSVREL > 3) */
1776#  endif /* BSD4_4 && !__386BSD__  */
1777# endif /* BSDLIMIT */
1778
1779# if (HPUXVERSION > 700) && (HPUXVERSION < 1100) && defined(BSDLIMIT)
1780/* Yes hpux8.0 has limits but <sys/resource.h> does not make them public */
1781/* Yes, we could have defined _KERNEL, and -I/etc/conf/h, but is that better? */
1782#  ifndef RLIMIT_CPU
1783#   define RLIMIT_CPU		0
1784#   define RLIMIT_FSIZE		1
1785#   define RLIMIT_DATA		2
1786#   define RLIMIT_STACK		3
1787#   define RLIMIT_CORE		4
1788#   define RLIMIT_RSS		5
1789#   define RLIMIT_NOFILE	6
1790#  endif /* RLIMIT_CPU */
1791#  ifndef RLIM_INFINITY
1792#   define RLIM_INFINITY	0x7fffffff
1793#  endif /* RLIM_INFINITY */
1794   /*
1795    * old versions of HP/UX counted limits in 512 bytes
1796    */
1797#  ifndef SIGRTMIN
1798#   define FILESIZE512
1799#  endif /* SIGRTMIN */
1800# endif /* (HPUXVERSION > 700) && (HPUXVERSION < 1100) && BSDLIMIT */
1801
1802# if SYSVREL > 3 && defined(BSDLIMIT) && !defined(_SX)
1803/* In order to use rusage, we included "/usr/ucbinclude/sys/resource.h" in */
1804/* sh.h.  However, some SVR4 limits are defined in <sys/resource.h>.  Rather */
1805/* than include both and get warnings, we define the extra SVR4 limits here. */
1806/* XXX: I don't understand if RLIMIT_AS is defined, why don't we define */
1807/* RLIMIT_VMEM based on it? */
1808#  ifndef RLIMIT_VMEM
1809#   define RLIMIT_VMEM	6
1810#  endif
1811#  ifndef RLIMIT_AS
1812#   define RLIMIT_AS	RLIMIT_VMEM
1813#  endif
1814# endif /* SYSVREL > 3 && BSDLIMIT */
1815
1816# if (defined(__linux__) || defined(__GNU__) || defined(__GLIBC__)) && defined(RLIMIT_AS) && !defined(RLIMIT_VMEM)
1817#  define RLIMIT_VMEM	RLIMIT_AS
1818# endif
1819
1820struct limits limits[] =
1821{
1822# ifdef RLIMIT_CPU
1823    { RLIMIT_CPU, 	"cputime",	1,	"seconds"	},
1824# endif /* RLIMIT_CPU */
1825
1826# ifdef RLIMIT_FSIZE
1827#  ifndef aiws
1828    { RLIMIT_FSIZE, 	"filesize",	1024,	"kbytes"	},
1829#  else
1830    { RLIMIT_FSIZE, 	"filesize",	512,	"blocks"	},
1831#  endif /* aiws */
1832# endif /* RLIMIT_FSIZE */
1833
1834# ifdef RLIMIT_DATA
1835    { RLIMIT_DATA, 	"datasize",	1024,	"kbytes"	},
1836# endif /* RLIMIT_DATA */
1837
1838# ifdef RLIMIT_STACK
1839#  ifndef aiws
1840    { RLIMIT_STACK, 	"stacksize",	1024,	"kbytes"	},
1841#  else
1842    { RLIMIT_STACK, 	"stacksize",	1024 * 1024,	"kbytes"},
1843#  endif /* aiws */
1844# endif /* RLIMIT_STACK */
1845
1846# ifdef RLIMIT_CORE
1847    { RLIMIT_CORE, 	"coredumpsize",	1024,	"kbytes"	},
1848# endif /* RLIMIT_CORE */
1849
1850# ifdef RLIMIT_RSS
1851    { RLIMIT_RSS, 	"memoryuse",	1024,	"kbytes"	},
1852# endif /* RLIMIT_RSS */
1853
1854# ifdef RLIMIT_UMEM
1855    { RLIMIT_UMEM, 	"memoryuse",	1024,	"kbytes"	},
1856# endif /* RLIMIT_UMEM */
1857
1858# ifdef RLIMIT_VMEM
1859    { RLIMIT_VMEM, 	"vmemoryuse",	1024,	"kbytes"	},
1860# endif /* RLIMIT_VMEM */
1861
1862# if defined(RLIMIT_HEAP) /* found on BS2000/OSD systems */
1863    { RLIMIT_HEAP,	"heapsize",	1024,	"kbytes"	},
1864# endif /* RLIMIT_HEAP */
1865
1866# ifdef RLIMIT_NOFILE
1867    { RLIMIT_NOFILE, 	"descriptors", 1,	""		},
1868# endif /* RLIMIT_NOFILE */
1869
1870# ifdef RLIMIT_CONCUR
1871    { RLIMIT_CONCUR, 	"concurrency", 1,	"thread(s)"	},
1872# endif /* RLIMIT_CONCUR */
1873
1874# ifdef RLIMIT_MEMLOCK
1875    { RLIMIT_MEMLOCK,	"memorylocked",	1024,	"kbytes"	},
1876# endif /* RLIMIT_MEMLOCK */
1877
1878# ifdef RLIMIT_NPROC
1879    { RLIMIT_NPROC,	"maxproc",	1,	""		},
1880# endif /* RLIMIT_NPROC */
1881
1882# if defined(RLIMIT_OFILE) && !defined(RLIMIT_NOFILE)
1883    { RLIMIT_OFILE,	"openfiles",	1,	""		},
1884# endif /* RLIMIT_OFILE && !defined(RLIMIT_NOFILE) */
1885
1886# ifdef RLIMIT_SBSIZE
1887    { RLIMIT_SBSIZE,	"sbsize",	1,	""		},
1888# endif /* RLIMIT_SBSIZE */
1889
1890    { -1, 		NULL, 		0, 	NULL		}
1891};
1892
1893static struct limits *findlim	__P((Char *));
1894static RLIM_TYPE getval		__P((struct limits *, Char **));
1895static void limtail		__P((Char *, const char *));
1896static void plim		__P((struct limits *, int));
1897static int setlim		__P((struct limits *, int, RLIM_TYPE));
1898
1899#ifdef convex
1900static  RLIM_TYPE
1901restrict_limit(value)
1902    double  value;
1903{
1904    /*
1905     * is f too large to cope with? return the maximum or minimum int
1906     */
1907    if (value > (double) INT_MAX)
1908	return (RLIM_TYPE) INT_MAX;
1909    else if (value < (double) INT_MIN)
1910	return (RLIM_TYPE) INT_MIN;
1911    else
1912	return (RLIM_TYPE) value;
1913}
1914#else /* !convex */
1915# define restrict_limit(x)	((RLIM_TYPE) (x))
1916#endif /* convex */
1917
1918
1919static struct limits *
1920findlim(cp)
1921    Char   *cp;
1922{
1923    struct limits *lp, *res;
1924
1925    res = (struct limits *) NULL;
1926    for (lp = limits; lp->limconst >= 0; lp++)
1927	if (prefix(cp, str2short(lp->limname))) {
1928	    if (res)
1929		stderror(ERR_NAME | ERR_AMBIG);
1930	    res = lp;
1931	}
1932    if (res)
1933	return (res);
1934    stderror(ERR_NAME | ERR_LIMIT);
1935    /* NOTREACHED */
1936    return (0);
1937}
1938
1939/*ARGSUSED*/
1940void
1941dolimit(v, c)
1942    Char **v;
1943    struct command *c;
1944{
1945    struct limits *lp;
1946    RLIM_TYPE limit;
1947    int    hard = 0;
1948
1949    USE(c);
1950    v++;
1951    if (*v && eq(*v, STRmh)) {
1952	hard = 1;
1953	v++;
1954    }
1955    if (*v == 0) {
1956	for (lp = limits; lp->limconst >= 0; lp++)
1957	    plim(lp, hard);
1958	return;
1959    }
1960    lp = findlim(v[0]);
1961    if (v[1] == 0) {
1962	plim(lp, hard);
1963	return;
1964    }
1965    limit = getval(lp, v + 1);
1966    if (setlim(lp, hard, limit) < 0)
1967	stderror(ERR_SILENT);
1968}
1969
1970static  RLIM_TYPE
1971getval(lp, v)
1972    struct limits *lp;
1973    Char  **v;
1974{
1975    float f;
1976    Char   *cp = *v++;
1977
1978    f = atof(short2str(cp));
1979
1980# ifdef convex
1981    /*
1982     * is f too large to cope with. limit f to minint, maxint  - X-6768 by
1983     * strike
1984     */
1985    if ((f < (double) INT_MIN) || (f > (double) INT_MAX)) {
1986	stderror(ERR_NAME | ERR_TOOLARGE);
1987    }
1988# endif /* convex */
1989
1990    while (Isdigit(*cp) || *cp == '.' || *cp == 'e' || *cp == 'E')
1991	cp++;
1992    if (*cp == 0) {
1993	if (*v == 0)
1994	    return restrict_limit((f * lp->limdiv) + 0.5);
1995	cp = *v;
1996    }
1997    switch (*cp) {
1998# ifdef RLIMIT_CPU
1999    case ':':
2000	if (lp->limconst != RLIMIT_CPU)
2001	    goto badscal;
2002	return f == 0.0 ? (RLIM_TYPE) 0 : restrict_limit((f * 60.0 + atof(short2str(cp + 1))));
2003    case 'h':
2004	if (lp->limconst != RLIMIT_CPU)
2005	    goto badscal;
2006	limtail(cp, "hours");
2007	f *= 3600.0;
2008	break;
2009    case 'm':
2010	if (lp->limconst == RLIMIT_CPU) {
2011	    limtail(cp, "minutes");
2012	    f *= 60.0;
2013	    break;
2014	}
2015	*cp = 'm';
2016	limtail(cp, "megabytes");
2017	f *= 1024.0 * 1024.0;
2018	break;
2019    case 's':
2020	if (lp->limconst != RLIMIT_CPU)
2021	    goto badscal;
2022	limtail(cp, "seconds");
2023	break;
2024# endif /* RLIMIT_CPU */
2025    case 'M':
2026# ifdef RLIMIT_CPU
2027	if (lp->limconst == RLIMIT_CPU)
2028	    goto badscal;
2029# endif /* RLIMIT_CPU */
2030	*cp = 'm';
2031	limtail(cp, "megabytes");
2032	f *= 1024.0 * 1024.0;
2033	break;
2034    case 'k':
2035# ifdef RLIMIT_CPU
2036	if (lp->limconst == RLIMIT_CPU)
2037	    goto badscal;
2038# endif /* RLIMIT_CPU */
2039	limtail(cp, "kbytes");
2040	f *= 1024.0;
2041	break;
2042    case 'b':
2043# ifdef RLIMIT_CPU
2044	if (lp->limconst == RLIMIT_CPU)
2045	    goto badscal;
2046# endif /* RLIMIT_CPU */
2047	limtail(cp, "blocks");
2048	f *= 512.0;
2049	break;
2050    case 'u':
2051	limtail(cp, "unlimited");
2052	return ((RLIM_TYPE) RLIM_INFINITY);
2053    default:
2054# ifdef RLIMIT_CPU
2055badscal:
2056# endif /* RLIMIT_CPU */
2057	stderror(ERR_NAME | ERR_SCALEF);
2058    }
2059# ifdef convex
2060    return f == 0.0 ? (RLIM_TYPE) 0 : restrict_limit((f + 0.5));
2061# else
2062    f += 0.5;
2063    if (f > (float) RLIM_INFINITY)
2064	return ((RLIM_TYPE) RLIM_INFINITY);
2065    else
2066	return ((RLIM_TYPE) f);
2067# endif /* convex */
2068}
2069
2070static void
2071limtail(cp, str)
2072    Char   *cp;
2073    const char   *str;
2074{
2075    const char *sp;
2076
2077    sp = str;
2078    while (*cp && *cp == (Char)*str)
2079	cp++, str++;
2080    if (*cp)
2081	stderror(ERR_BADSCALE, sp);
2082}
2083
2084
2085/*ARGSUSED*/
2086static void
2087plim(lp, hard)
2088    struct limits *lp;
2089    int hard;
2090{
2091# ifdef BSDLIMIT
2092    struct rlimit rlim;
2093# endif /* BSDLIMIT */
2094    RLIM_TYPE limit;
2095    int     xdiv = lp->limdiv;
2096
2097    xprintf("%-13.13s", lp->limname);
2098
2099# ifndef BSDLIMIT
2100    limit = ulimit(lp->limconst, 0);
2101#  ifdef aiws
2102    if (lp->limconst == RLIMIT_DATA)
2103	limit -= 0x20000000;
2104#  endif /* aiws */
2105# else /* BSDLIMIT */
2106    (void) getrlimit(lp->limconst, &rlim);
2107    limit = hard ? rlim.rlim_max : rlim.rlim_cur;
2108# endif /* BSDLIMIT */
2109
2110# if !defined(BSDLIMIT) || defined(FILESIZE512)
2111    /*
2112     * Christos: filesize comes in 512 blocks. we divide by 2 to get 1024
2113     * blocks. Note we cannot pre-multiply cause we might overflow (A/UX)
2114     */
2115    if (lp->limconst == RLIMIT_FSIZE) {
2116	if (limit >= (RLIM_INFINITY / 512))
2117	    limit = RLIM_INFINITY;
2118	else
2119	    xdiv = (xdiv == 1024 ? 2 : 1);
2120    }
2121# endif /* !BSDLIMIT || FILESIZE512 */
2122
2123    if (limit == RLIM_INFINITY)
2124	xprintf("unlimited");
2125    else
2126# if defined(RLIMIT_CPU) && defined(_OSD_POSIX)
2127    if (lp->limconst == RLIMIT_CPU &&
2128        (unsigned long)limit >= 0x7ffffffdUL)
2129	xprintf("unlimited");
2130    else
2131# endif
2132# ifdef RLIMIT_CPU
2133    if (lp->limconst == RLIMIT_CPU)
2134	psecs((long) limit);
2135    else
2136# endif /* RLIMIT_CPU */
2137	xprintf("%ld %s", (long) (limit / xdiv), lp->limscale);
2138    xputchar('\n');
2139}
2140
2141/*ARGSUSED*/
2142void
2143dounlimit(v, c)
2144    Char **v;
2145    struct command *c;
2146{
2147    struct limits *lp;
2148    int    lerr = 0;
2149    int    hard = 0;
2150    int	   force = 0;
2151
2152    USE(c);
2153    while (*++v && **v == '-') {
2154	Char   *vp = *v;
2155	while (*++vp)
2156	    switch (*vp) {
2157	    case 'f':
2158		force = 1;
2159		break;
2160	    case 'h':
2161		hard = 1;
2162		break;
2163	    default:
2164		stderror(ERR_ULIMUS);
2165		break;
2166	    }
2167    }
2168
2169    if (*v == 0) {
2170	for (lp = limits; lp->limconst >= 0; lp++)
2171	    if (setlim(lp, hard, (RLIM_TYPE) RLIM_INFINITY) < 0)
2172		lerr++;
2173	if (!force && lerr)
2174	    stderror(ERR_SILENT);
2175	return;
2176    }
2177    while (*v) {
2178	lp = findlim(*v++);
2179	if (setlim(lp, hard, (RLIM_TYPE) RLIM_INFINITY) < 0 && !force)
2180	    stderror(ERR_SILENT);
2181    }
2182}
2183
2184static int
2185setlim(lp, hard, limit)
2186    struct limits *lp;
2187    int    hard;
2188    RLIM_TYPE limit;
2189{
2190# ifdef BSDLIMIT
2191    struct rlimit rlim;
2192
2193    (void) getrlimit(lp->limconst, &rlim);
2194
2195#  ifdef FILESIZE512
2196    /* Even though hpux has setrlimit(), it expects fsize in 512 byte blocks */
2197    if (limit != RLIM_INFINITY && lp->limconst == RLIMIT_FSIZE)
2198	limit /= 512;
2199#  endif /* FILESIZE512 */
2200    if (hard)
2201	rlim.rlim_max = limit;
2202    else if (limit == RLIM_INFINITY && euid != 0)
2203	rlim.rlim_cur = rlim.rlim_max;
2204    else
2205	rlim.rlim_cur = limit;
2206
2207    if (rlim.rlim_cur > rlim.rlim_max)
2208	rlim.rlim_max = rlim.rlim_cur;
2209
2210    if (setrlimit(lp->limconst, &rlim) < 0) {
2211# else /* BSDLIMIT */
2212    if (limit != RLIM_INFINITY && lp->limconst == RLIMIT_FSIZE)
2213	limit /= 512;
2214# ifdef aiws
2215    if (lp->limconst == RLIMIT_DATA)
2216	limit += 0x20000000;
2217# endif /* aiws */
2218    if (ulimit(toset(lp->limconst), limit) < 0) {
2219# endif /* BSDLIMIT */
2220        int err;
2221        char *op, *type;
2222
2223	err = errno;
2224	op = strsave(limit == RLIM_INFINITY ? CGETS(15, 2, "remove") :
2225		     	CGETS(15, 3, "set"));
2226	type = strsave(hard ? CGETS(15, 4, " hard") : "");
2227	xprintf(CGETS(15, 1, "%s: %s: Can't %s%s limit (%s)\n"), bname,
2228	    lp->limname, op, type, strerror(err));
2229	xfree(type);
2230	xfree(op);
2231	return (-1);
2232    }
2233    return (0);
2234}
2235
2236#endif /* !HAVENOLIMIT */
2237
2238/*ARGSUSED*/
2239void
2240dosuspend(v, c)
2241    Char **v;
2242    struct command *c;
2243{
2244#ifdef BSDJOBS
2245    int     ctpgrp;
2246
2247    signalfun_t old;
2248#endif /* BSDJOBS */
2249
2250    USE(c);
2251    USE(v);
2252
2253    if (loginsh)
2254	stderror(ERR_SUSPLOG);
2255    untty();
2256
2257#ifdef BSDJOBS
2258    old = signal(SIGTSTP, SIG_DFL);
2259    (void) kill(0, SIGTSTP);
2260    /* the shell stops here */
2261    (void) signal(SIGTSTP, old);
2262#else /* !BSDJOBS */
2263    stderror(ERR_JOBCONTROL);
2264#endif /* BSDJOBS */
2265
2266#ifdef BSDJOBS
2267    if (tpgrp != -1) {
2268retry:
2269	ctpgrp = tcgetpgrp(FSHTTY);
2270	if (ctpgrp == -1)
2271	    stderror(ERR_SYSTEM, "tcgetpgrp", strerror(errno));
2272	if (ctpgrp != opgrp) {
2273	    old = signal(SIGTTIN, SIG_DFL);
2274	    (void) kill(0, SIGTTIN);
2275	    (void) signal(SIGTTIN, old);
2276	    goto retry;
2277	}
2278	(void) setpgid(0, shpgrp);
2279	(void) tcsetpgrp(FSHTTY, shpgrp);
2280    }
2281#endif /* BSDJOBS */
2282    (void) setdisc(FSHTTY);
2283}
2284
2285/* This is the dreaded EVAL built-in.
2286 *   If you don't fiddle with file descriptors, and reset didfds,
2287 *   this command will either ignore redirection inside or outside
2288 *   its arguments, e.g. eval "date >x"  vs.  eval "date" >x
2289 *   The stuff here seems to work, but I did it by trial and error rather
2290 *   than really knowing what was going on.  If tpgrp is zero, we are
2291 *   probably a background eval, e.g. "eval date &", and we want to
2292 *   make sure that any processes we start stay in our pgrp.
2293 *   This is also the case for "time eval date" -- stay in same pgrp.
2294 *   Otherwise, under stty tostop, processes will stop in the wrong
2295 *   pgrp, with no way for the shell to get them going again.  -IAN!
2296 */
2297
2298static Char **gv = NULL, **gav = NULL;
2299
2300/*ARGSUSED*/
2301void
2302doeval(v, c)
2303    Char  **v;
2304    struct command *c;
2305{
2306    Char  **oevalvec;
2307    Char   *oevalp;
2308    int     odidfds;
2309#ifndef CLOSE_ON_EXEC
2310    int     odidcch;
2311#endif /* CLOSE_ON_EXEC */
2312    jmp_buf_t osetexit;
2313    int     my_reenter;
2314    Char  **savegv;
2315    int     saveIN, saveOUT, saveDIAG;
2316    int     oSHIN, oSHOUT, oSHDIAG;
2317
2318    USE(c);
2319    oevalvec = evalvec;
2320    oevalp = evalp;
2321    odidfds = didfds;
2322#ifndef CLOSE_ON_EXEC
2323    odidcch = didcch;
2324#endif /* CLOSE_ON_EXEC */
2325    oSHIN = SHIN;
2326    oSHOUT = SHOUT;
2327    oSHDIAG = SHDIAG;
2328
2329    savegv = gv;
2330    gav = v;
2331
2332    gav++;
2333    if (*gav == 0)
2334	return;
2335    gflag = 0, tglob(gav);
2336    if (gflag) {
2337	gv = gav = globall(gav);
2338	gargv = 0;
2339	if (gav == 0)
2340	    stderror(ERR_NOMATCH);
2341	gav = copyblk(gav);
2342    }
2343    else {
2344	gv = NULL;
2345	gav = copyblk(gav);
2346	trim(gav);
2347    }
2348
2349    (void)close_on_exec(saveIN = dcopy(SHIN, -1), 1);
2350    (void)close_on_exec(saveOUT = dcopy(SHOUT, -1), 1);
2351    (void)close_on_exec(saveDIAG = dcopy(SHDIAG, -1), 1);
2352
2353    getexit(osetexit);
2354
2355    /* PWP: setjmp/longjmp bugfix for optimizing compilers */
2356#ifdef cray
2357    my_reenter = 1;             /* assume non-zero return val */
2358    if (setexit() == 0) {
2359	my_reenter = 0;         /* Oh well, we were wrong */
2360#else /* !cray */
2361    if ((my_reenter = setexit()) == 0) {
2362#endif /* cray */
2363	evalvec = gav;
2364	evalp = 0;
2365	(void)close_on_exec(SHIN = dcopy(0, -1), 1);
2366	(void)close_on_exec(SHOUT = dcopy(1, -1), 1);
2367	(void)close_on_exec(SHDIAG = dcopy(2, -1), 1);
2368#ifndef CLOSE_ON_EXEC
2369	didcch = 0;
2370#endif /* CLOSE_ON_EXEC */
2371	didfds = 0;
2372	process(0);
2373    }
2374
2375    evalvec = oevalvec;
2376    evalp = oevalp;
2377    doneinp = 0;
2378#ifndef CLOSE_ON_EXEC
2379    didcch = odidcch;
2380#endif /* CLOSE_ON_EXEC */
2381    didfds = odidfds;
2382    (void) close(SHIN);
2383    (void) close(SHOUT);
2384    (void) close(SHDIAG);
2385    (void)close_on_exec (SHIN = dmove(saveIN, oSHIN), 1);
2386    (void)close_on_exec (SHOUT = dmove(saveOUT, oSHOUT), 1);
2387    (void)close_on_exec (SHDIAG = dmove(saveDIAG, oSHDIAG), 1);
2388
2389    if (gv)
2390	blkfree(gv);
2391
2392    gv = savegv;
2393    resexit(osetexit);
2394    if (my_reenter)
2395	stderror(ERR_SILENT);
2396}
2397
2398/*************************************************************************/
2399/* print list of builtin commands */
2400
2401/*ARGSUSED*/
2402void
2403dobuiltins(v, c)
2404Char **v;
2405struct command *c;
2406{
2407    /* would use print_by_column() in tw.parse.c but that assumes
2408     * we have an array of Char * to pass.. (sg)
2409     */
2410    struct biltins *b;
2411    int row, col, columns, rows;
2412    unsigned int w, maxwidth;
2413
2414    USE(c);
2415    USE(v);
2416    lbuffed = 0;		/* turn off line buffering */
2417
2418    /* find widest string */
2419    for (maxwidth = 0, b = bfunc; b < &bfunc[nbfunc]; ++b)
2420	maxwidth = max(maxwidth, strlen(b->bname));
2421    ++maxwidth;					/* for space */
2422
2423    columns = (TermH + 1) / maxwidth;	/* PWP: terminal size change */
2424    if (!columns)
2425	columns = 1;
2426    rows = (nbfunc + (columns - 1)) / columns;
2427
2428    for (b = bfunc, row = 0; row < rows; row++) {
2429	for (col = 0; col < columns; col++) {
2430	    if (b < &bfunc[nbfunc]) {
2431		w = strlen(b->bname);
2432		xprintf("%s", b->bname);
2433		if (col < (columns - 1))	/* Not last column? */
2434		    for (; w < maxwidth; w++)
2435			xputchar(' ');
2436		++b;
2437	    }
2438	}
2439	if (row < (rows - 1)) {
2440	    if (Tty_raw_mode)
2441		xputchar('\r');
2442	    xputchar('\n');
2443	}
2444    }
2445#ifdef WINNT_NATIVE
2446    nt_print_builtins(maxwidth);
2447#else
2448    if (Tty_raw_mode)
2449	xputchar('\r');
2450    xputchar('\n');
2451#endif /* WINNT_NATIVE */
2452
2453    lbuffed = 1;		/* turn back on line buffering */
2454    flush();
2455}
2456
2457#ifdef NLS_CATALOGS
2458#ifdef HAVE_ICONV
2459char *
2460iconv_catgets(ctd, set_id, msg_id, s)
2461nl_catd ctd;
2462int set_id, msg_id;
2463const char *s;
2464{
2465    static char *buf = NULL;
2466    static size_t buf_size = 0;
2467
2468    char *orig, *dest, *p;
2469#ifdef __NetBSD__
2470    const char *src;
2471#else
2472    char *src;
2473#endif
2474    size_t src_size, dest_size;
2475
2476    orig = catgets(ctd, set_id, msg_id, s);
2477    if (catgets_iconv == (iconv_t)-1 || orig == s)
2478        return orig;
2479    src = orig;
2480    src_size = strlen(src) + 1;
2481    if (buf == NULL && (buf = xmalloc(buf_size = src_size + 32)) == NULL)
2482	return orig;
2483    dest = buf;
2484    while (src_size != 0) {
2485        dest_size = buf + buf_size - dest;
2486	if (iconv(catgets_iconv, &src, &src_size, &dest, &dest_size)
2487	    == (size_t)-1) {
2488	    switch (errno) {
2489	    case E2BIG:
2490		if ((p = xrealloc(buf, buf_size * 2)) == NULL)
2491		    return orig;
2492		buf_size *= 2;
2493		dest = p + (dest - buf);
2494		buf = p;
2495		break;
2496
2497	    case EILSEQ: case EINVAL: default:
2498		return orig;
2499	    }
2500	}
2501    }
2502    return buf;
2503}
2504#endif
2505#endif
2506
2507void
2508nlsinit()
2509{
2510#ifdef NLS_CATALOGS
2511    char catalog[ 256 ] = { 't', 'c', 's', 'h', '\0' };
2512
2513    if (adrof(STRcatalog) != NULL)
2514        xsnprintf((char *)catalog, sizeof(catalog), "tcsh.%s",
2515		  short2str(varval(STRcatalog)));
2516    catd = catopen(catalog, MCLoadBySet);
2517#ifdef HAVE_ICONV
2518    /* catgets (), not CGETS, the charset name should be in ASCII anyway. */
2519    catgets_iconv = iconv_open (nl_langinfo (CODESET),
2520				catgets(catd, 255, 1, "ASCII"));
2521#endif /* HAVE_ICONV */
2522#endif /* NLS_CATALOGS */
2523#ifdef WINNT_NATIVE
2524    nls_dll_init();
2525#endif /* WINNT_NATIVE */
2526    errinit();		/* init the errorlist in correct locale */
2527    mesginit();		/* init the messages for signals */
2528    dateinit();		/* init the messages for dates */
2529    editinit();		/* init the editor messages */
2530    terminit();		/* init the termcap messages */
2531}
2532
2533void
2534nlsclose()
2535{
2536#ifdef NLS_CATALOGS
2537#ifdef HAVE_ICONV
2538    if (catgets_iconv != (iconv_t)-1) {
2539	iconv_close(catgets_iconv);
2540	catgets_iconv = (iconv_t)-1;
2541    }
2542#endif /* HAVE_ICONV */
2543    catclose(catd);
2544#endif /* NLS_CATALOGS */
2545}
2546