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