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