Merge from vendor branch GDB:
[dragonfly.git] / contrib / tcsh / sh.func.c
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 #ifdef RLIMIT_POSIXLOCKS
1858     { RLIMIT_POSIXLOCKS, "posixlocks",   1,      ""             },
1859 #endif /* RLIMIT_POSIXLOCKS */
1860
1861     { -1,               NULL,           0,      NULL            }
1862 };
1863
1864 static struct limits *findlim   __P((Char *));
1865 static RLIM_TYPE getval         __P((struct limits *, Char **));
1866 static void limtail             __P((Char *, char*));
1867 static void plim                __P((struct limits *, int));
1868 static int setlim               __P((struct limits *, int, RLIM_TYPE));
1869
1870 #ifdef convex
1871 static  RLIM_TYPE
1872 restrict_limit(value)
1873     double  value;
1874 {
1875     /*
1876      * is f too large to cope with? return the maximum or minimum int
1877      */
1878     if (value > (double) INT_MAX)
1879         return (RLIM_TYPE) INT_MAX;
1880     else if (value < (double) INT_MIN)
1881         return (RLIM_TYPE) INT_MIN;
1882     else
1883         return (RLIM_TYPE) value;
1884 }
1885 #else /* !convex */
1886 # define restrict_limit(x)      ((RLIM_TYPE) (x))
1887 #endif /* convex */
1888
1889
1890 static struct limits *
1891 findlim(cp)
1892     Char   *cp;
1893 {
1894     register struct limits *lp, *res;
1895
1896     res = (struct limits *) NULL;
1897     for (lp = limits; lp->limconst >= 0; lp++)
1898         if (prefix(cp, str2short(lp->limname))) {
1899             if (res)
1900                 stderror(ERR_NAME | ERR_AMBIG);
1901             res = lp;
1902         }
1903     if (res)
1904         return (res);
1905     stderror(ERR_NAME | ERR_LIMIT);
1906     /* NOTREACHED */
1907     return (0);
1908 }
1909
1910 /*ARGSUSED*/
1911 void
1912 dolimit(v, c)
1913     register Char **v;
1914     struct command *c;
1915 {
1916     register struct limits *lp;
1917     register RLIM_TYPE limit;
1918     int    hard = 0;
1919
1920     USE(c);
1921     v++;
1922     if (*v && eq(*v, STRmh)) {
1923         hard = 1;
1924         v++;
1925     }
1926     if (*v == 0) {
1927         for (lp = limits; lp->limconst >= 0; lp++)
1928             plim(lp, hard);
1929         return;
1930     }
1931     lp = findlim(v[0]);
1932     if (v[1] == 0) {
1933         plim(lp, hard);
1934         return;
1935     }
1936     limit = getval(lp, v + 1);
1937     if (setlim(lp, hard, limit) < 0)
1938         stderror(ERR_SILENT);
1939 }
1940
1941 static  RLIM_TYPE
1942 getval(lp, v)
1943     register struct limits *lp;
1944     Char  **v;
1945 {
1946     register float f;
1947 #ifndef atof    /* This can be a macro on linux */
1948     extern double  atof __P((const char *));
1949 #endif /* atof */
1950     Char   *cp = *v++;
1951
1952     f = atof(short2str(cp));
1953
1954 # ifdef convex
1955     /*
1956      * is f too large to cope with. limit f to minint, maxint  - X-6768 by
1957      * strike
1958      */
1959     if ((f < (double) INT_MIN) || (f > (double) INT_MAX)) {
1960         stderror(ERR_NAME | ERR_TOOLARGE);
1961     }
1962 # endif /* convex */
1963
1964     while (Isdigit(*cp) || *cp == '.' || *cp == 'e' || *cp == 'E')
1965         cp++;
1966     if (*cp == 0) {
1967         if (*v == 0)
1968             return restrict_limit((f * lp->limdiv) + 0.5);
1969         cp = *v;
1970     }
1971     switch (*cp) {
1972 # ifdef RLIMIT_CPU
1973     case ':':
1974         if (lp->limconst != RLIMIT_CPU)
1975             goto badscal;
1976         return f == 0.0 ? (RLIM_TYPE) 0 : restrict_limit((f * 60.0 + atof(short2str(cp + 1))));
1977     case 'h':
1978         if (lp->limconst != RLIMIT_CPU)
1979             goto badscal;
1980         limtail(cp, "hours");
1981         f *= 3600.0;
1982         break;
1983     case 'm':
1984         if (lp->limconst == RLIMIT_CPU) {
1985             limtail(cp, "minutes");
1986             f *= 60.0;
1987             break;
1988         }
1989         *cp = 'm';
1990         limtail(cp, "megabytes");
1991         f *= 1024.0 * 1024.0;
1992         break;
1993     case 's':
1994         if (lp->limconst != RLIMIT_CPU)
1995             goto badscal;
1996         limtail(cp, "seconds");
1997         break;
1998 # endif /* RLIMIT_CPU */
1999     case 'M':
2000 # ifdef RLIMIT_CPU
2001         if (lp->limconst == RLIMIT_CPU)
2002             goto badscal;
2003 # endif /* RLIMIT_CPU */
2004         *cp = 'm';
2005         limtail(cp, "megabytes");
2006         f *= 1024.0 * 1024.0;
2007         break;
2008     case 'k':
2009 # ifdef RLIMIT_CPU
2010         if (lp->limconst == RLIMIT_CPU)
2011             goto badscal;
2012 # endif /* RLIMIT_CPU */
2013         limtail(cp, "kbytes");
2014         f *= 1024.0;
2015         break;
2016     case 'b':
2017 # ifdef RLIMIT_CPU
2018         if (lp->limconst == RLIMIT_CPU)
2019             goto badscal;
2020 # endif /* RLIMIT_CPU */
2021         limtail(cp, "blocks");
2022         f *= 512.0;
2023         break;
2024     case 'u':
2025         limtail(cp, "unlimited");
2026         return ((RLIM_TYPE) RLIM_INFINITY);
2027     default:
2028 # ifdef RLIMIT_CPU
2029 badscal:
2030 # endif /* RLIMIT_CPU */
2031         stderror(ERR_NAME | ERR_SCALEF);
2032     }
2033 # ifdef convex
2034     return f == 0.0 ? (RLIM_TYPE) 0 : restrict_limit((f + 0.5));
2035 # else
2036     f += 0.5;
2037     if (f > (float) RLIM_INFINITY)
2038         return ((RLIM_TYPE) RLIM_INFINITY);
2039     else
2040         return ((RLIM_TYPE) f);
2041 # endif /* convex */
2042 }
2043
2044 static void
2045 limtail(cp, str)
2046     Char   *cp;
2047     char   *str;
2048 {
2049     char *sp;
2050
2051     sp = str;
2052     while (*cp && *cp == *str)
2053         cp++, str++;
2054     if (*cp)
2055         stderror(ERR_BADSCALE, sp);
2056 }
2057
2058
2059 /*ARGSUSED*/
2060 static void
2061 plim(lp, hard)
2062     register struct limits *lp;
2063     int hard;
2064 {
2065 # ifdef BSDLIMIT
2066     struct rlimit rlim;
2067 # endif /* BSDLIMIT */
2068     RLIM_TYPE limit;
2069     int     div = lp->limdiv;
2070
2071     xprintf("%s \t", lp->limname);
2072
2073 # ifndef BSDLIMIT
2074     limit = ulimit(lp->limconst, 0);
2075 #  ifdef aiws
2076     if (lp->limconst == RLIMIT_DATA)
2077         limit -= 0x20000000;
2078 #  endif /* aiws */
2079 # else /* BSDLIMIT */
2080     (void) getrlimit(lp->limconst, &rlim);
2081     limit = hard ? rlim.rlim_max : rlim.rlim_cur;
2082 # endif /* BSDLIMIT */
2083
2084 # if !defined(BSDLIMIT) || defined(FILESIZE512)
2085     /*
2086      * Christos: filesize comes in 512 blocks. we divide by 2 to get 1024
2087      * blocks. Note we cannot pre-multiply cause we might overflow (A/UX)
2088      */
2089     if (lp->limconst == RLIMIT_FSIZE) {
2090         if (limit >= (RLIM_INFINITY / 512))
2091             limit = RLIM_INFINITY;
2092         else
2093             div = (div == 1024 ? 2 : 1);
2094     }
2095 # endif /* !BSDLIMIT || FILESIZE512 */
2096
2097     if (limit == RLIM_INFINITY)
2098         xprintf("unlimited");
2099     else
2100 # ifdef RLIMIT_CPU
2101     if (lp->limconst == RLIMIT_CPU)
2102         psecs((long) limit);
2103     else
2104 # endif /* RLIMIT_CPU */
2105         xprintf("%ld %s", (long) (limit / div), lp->limscale);
2106     xputchar('\n');
2107 }
2108
2109 /*ARGSUSED*/
2110 void
2111 dounlimit(v, c)
2112     register Char **v;
2113     struct command *c;
2114 {
2115     register struct limits *lp;
2116     int    lerr = 0;
2117     int    hard = 0;
2118     int    force = 0;
2119
2120     USE(c);
2121     while (*++v && **v == '-') {
2122         Char   *vp = *v;
2123         while (*++vp)
2124             switch (*vp) {
2125             case 'f':
2126                 force = 1;
2127                 break;
2128             case 'h':
2129                 hard = 1;
2130                 break;
2131             default:
2132                 stderror(ERR_ULIMUS);
2133                 break;
2134             }
2135     }
2136
2137     if (*v == 0) {
2138         for (lp = limits; lp->limconst >= 0; lp++)
2139             if (setlim(lp, hard, (RLIM_TYPE) RLIM_INFINITY) < 0)
2140                 lerr++;
2141         if (!force && lerr)
2142             stderror(ERR_SILENT);
2143         return;
2144     }
2145     while (*v) {
2146         lp = findlim(*v++);
2147         if (setlim(lp, hard, (RLIM_TYPE) RLIM_INFINITY) < 0 && !force)
2148             stderror(ERR_SILENT);
2149     }
2150 }
2151
2152 static int
2153 setlim(lp, hard, limit)
2154     register struct limits *lp;
2155     int    hard;
2156     RLIM_TYPE limit;
2157 {
2158 # ifdef BSDLIMIT
2159     struct rlimit rlim;
2160
2161     (void) getrlimit(lp->limconst, &rlim);
2162
2163 #  ifdef FILESIZE512
2164     /* Even though hpux has setrlimit(), it expects fsize in 512 byte blocks */
2165     if (limit != RLIM_INFINITY && lp->limconst == RLIMIT_FSIZE)
2166         limit /= 512;
2167 #  endif /* FILESIZE512 */
2168     if (hard)
2169         rlim.rlim_max = limit;
2170     else if (limit == RLIM_INFINITY && euid != 0)
2171         rlim.rlim_cur = rlim.rlim_max;
2172     else
2173         rlim.rlim_cur = limit;
2174
2175     if (rlim.rlim_cur > rlim.rlim_max)
2176         rlim.rlim_max = rlim.rlim_cur;
2177
2178     if (setrlimit(lp->limconst, &rlim) < 0) {
2179 # else /* BSDLIMIT */
2180     if (limit != RLIM_INFINITY && lp->limconst == RLIMIT_FSIZE)
2181         limit /= 512;
2182 # ifdef aiws
2183     if (lp->limconst == RLIMIT_DATA)
2184         limit += 0x20000000;
2185 # endif /* aiws */
2186     if (ulimit(toset(lp->limconst), limit) < 0) {
2187 # endif /* BSDLIMIT */
2188         xprintf(CGETS(15, 1, "%s: %s: Can't %s%s limit (%s)\n"), bname,
2189             lp->limname, limit == RLIM_INFINITY ? CGETS(15, 2, "remove") :
2190             CGETS(15, 3, "set"), hard ? CGETS(14, 4, " hard") : "",
2191             strerror(errno));
2192         return (-1);
2193     }
2194     return (0);
2195 }
2196
2197 #endif /* !HAVENOLIMIT */
2198
2199 /*ARGSUSED*/
2200 void
2201 dosuspend(v, c)
2202     Char **v;
2203     struct command *c;
2204 {
2205 #ifdef BSDJOBS
2206     int     ctpgrp;
2207
2208     signalfun_t old;
2209 #endif /* BSDJOBS */
2210     
2211     USE(c);
2212     USE(v);
2213
2214     if (loginsh)
2215         stderror(ERR_SUSPLOG);
2216     untty();
2217
2218 #ifdef BSDJOBS
2219     old = signal(SIGTSTP, SIG_DFL);
2220     (void) kill(0, SIGTSTP);
2221     /* the shell stops here */
2222     (void) signal(SIGTSTP, old);
2223 #else /* !BSDJOBS */
2224     stderror(ERR_JOBCONTROL);
2225 #endif /* BSDJOBS */
2226
2227 #ifdef BSDJOBS
2228     if (tpgrp != -1) {
2229 retry:
2230         ctpgrp = tcgetpgrp(FSHTTY);
2231         if (ctpgrp != opgrp) {
2232             old = signal(SIGTTIN, SIG_DFL);
2233             (void) kill(0, SIGTTIN);
2234             (void) signal(SIGTTIN, old);
2235             goto retry;
2236         }
2237         (void) setpgid(0, shpgrp);
2238         (void) tcsetpgrp(FSHTTY, shpgrp);
2239     }
2240 #endif /* BSDJOBS */
2241     (void) setdisc(FSHTTY);
2242 }
2243
2244 /* This is the dreaded EVAL built-in.
2245  *   If you don't fiddle with file descriptors, and reset didfds,
2246  *   this command will either ignore redirection inside or outside
2247  *   its arguments, e.g. eval "date >x"  vs.  eval "date" >x
2248  *   The stuff here seems to work, but I did it by trial and error rather
2249  *   than really knowing what was going on.  If tpgrp is zero, we are
2250  *   probably a background eval, e.g. "eval date &", and we want to
2251  *   make sure that any processes we start stay in our pgrp.
2252  *   This is also the case for "time eval date" -- stay in same pgrp.
2253  *   Otherwise, under stty tostop, processes will stop in the wrong
2254  *   pgrp, with no way for the shell to get them going again.  -IAN!
2255  */
2256
2257 static Char **gv = NULL, **gav = NULL;
2258
2259 /*ARGSUSED*/
2260 void
2261 doeval(v, c)
2262     Char  **v;
2263     struct command *c;
2264 {
2265     Char  **oevalvec;
2266     Char   *oevalp;
2267     int     odidfds;
2268 #ifndef CLOSE_ON_EXEC
2269     int     odidcch;
2270 #endif /* CLOSE_ON_EXEC */
2271     jmp_buf_t osetexit;
2272     int     my_reenter;
2273     Char  **savegv;
2274     int     saveIN, saveOUT, saveDIAG;
2275     int     oSHIN, oSHOUT, oSHDIAG;
2276
2277     USE(c);
2278     oevalvec = evalvec;
2279     oevalp = evalp;
2280     odidfds = didfds;
2281 #ifndef CLOSE_ON_EXEC
2282     odidcch = didcch;
2283 #endif /* CLOSE_ON_EXEC */
2284     oSHIN = SHIN;
2285     oSHOUT = SHOUT;
2286     oSHDIAG = SHDIAG;
2287
2288     savegv = gv;
2289     gav = v;
2290
2291     gav++;
2292     if (*gav == 0)
2293         return;
2294     gflag = 0, tglob(gav);
2295     if (gflag) {
2296         gv = gav = globall(gav);
2297         gargv = 0;
2298         if (gav == 0)
2299             stderror(ERR_NOMATCH);
2300         gav = copyblk(gav);
2301     }
2302     else {
2303         gv = NULL;
2304         gav = copyblk(gav);
2305         trim(gav);
2306     }
2307
2308     saveIN = dcopy(SHIN, -1);
2309     saveOUT = dcopy(SHOUT, -1);
2310     saveDIAG = dcopy(SHDIAG, -1);
2311
2312     getexit(osetexit);
2313
2314     /* PWP: setjmp/longjmp bugfix for optimizing compilers */
2315 #ifdef cray
2316     my_reenter = 1;             /* assume non-zero return val */
2317     if (setexit() == 0) {
2318         my_reenter = 0;         /* Oh well, we were wrong */
2319 #else /* !cray */
2320     if ((my_reenter = setexit()) == 0) {
2321 #endif /* cray */
2322         evalvec = gav;
2323         evalp = 0;
2324         SHIN = dcopy(0, -1);
2325         SHOUT = dcopy(1, -1);
2326         SHDIAG = dcopy(2, -1);
2327 #ifndef CLOSE_ON_EXEC
2328         didcch = 0;
2329 #endif /* CLOSE_ON_EXEC */
2330         didfds = 0;
2331         process(0);
2332     }
2333
2334     evalvec = oevalvec;
2335     evalp = oevalp;
2336     doneinp = 0;
2337 #ifndef CLOSE_ON_EXEC
2338     didcch = odidcch;
2339 #endif /* CLOSE_ON_EXEC */
2340     didfds = odidfds;
2341     (void) close(SHIN);
2342     (void) close(SHOUT);
2343     (void) close(SHDIAG);
2344     SHIN = dmove(saveIN, oSHIN);
2345     SHOUT = dmove(saveOUT, oSHOUT);
2346     SHDIAG = dmove(saveDIAG, oSHDIAG);
2347
2348     if (gv)
2349         blkfree(gv);
2350
2351     gv = savegv;
2352     resexit(osetexit);
2353     if (my_reenter)
2354         stderror(ERR_SILENT);
2355 }
2356
2357 /*************************************************************************/
2358 /* print list of builtin commands */
2359
2360 /*ARGSUSED*/
2361 void
2362 dobuiltins(v, c)
2363 Char **v;
2364 struct command *c;
2365 {
2366     /* would use print_by_column() in tw.parse.c but that assumes
2367      * we have an array of Char * to pass.. (sg)
2368      */
2369     extern int Tty_raw_mode;
2370     extern int TermH;           /* from the editor routines */
2371     extern int lbuffed;         /* from sh.print.c */
2372
2373     register struct biltins *b;
2374     register int row, col, columns, rows;
2375     unsigned int w, maxwidth;
2376
2377     USE(c);
2378     USE(v);
2379     lbuffed = 0;                /* turn off line buffering */
2380
2381     /* find widest string */
2382     for (maxwidth = 0, b = bfunc; b < &bfunc[nbfunc]; ++b)
2383         maxwidth = max(maxwidth, strlen(b->bname));
2384     ++maxwidth;                                 /* for space */
2385
2386     columns = (TermH + 1) / maxwidth;   /* PWP: terminal size change */
2387     if (!columns)
2388         columns = 1;
2389     rows = (nbfunc + (columns - 1)) / columns;
2390
2391     for (b = bfunc, row = 0; row < rows; row++) {
2392         for (col = 0; col < columns; col++) {
2393             if (b < &bfunc[nbfunc]) {
2394                 w = strlen(b->bname);
2395                 xprintf("%s", b->bname);
2396                 if (col < (columns - 1))        /* Not last column? */
2397                     for (; w < maxwidth; w++)
2398                         xputchar(' ');
2399                 ++b;
2400             }
2401         }
2402         if (row < (rows - 1)) {
2403             if (Tty_raw_mode)
2404                 xputchar('\r');
2405             xputchar('\n');
2406         }
2407     }
2408 #ifdef WINNT_NATIVE
2409     nt_print_builtins(maxwidth);
2410 #else
2411     if (Tty_raw_mode)
2412         xputchar('\r');
2413     xputchar('\n');
2414 #endif /* WINNT_NATIVE */
2415
2416     lbuffed = 1;                /* turn back on line buffering */
2417     flush();
2418 }
2419
2420 void
2421 nlsinit()
2422 {
2423 #ifdef NLS_CATALOGS
2424     char catalog[ 256 ] = { 't', 'c', 's', 'h', '\0' };
2425
2426     if (adrof(STRcatalog) != NULL)
2427         xsnprintf((char *)catalog, sizeof(catalog), "tcsh.%s",
2428                   short2str(varval(STRcatalog)));
2429     catd = catopen(catalog, MCLoadBySet);
2430 #endif /* NLS_CATALOGS */
2431 #ifdef WINNT_NATIVE
2432     nls_dll_init();
2433 #endif /* WINNT_NATIVE */
2434     errinit();          /* init the errorlist in correct locale */
2435     mesginit();         /* init the messages for signals */
2436     dateinit();         /* init the messages for dates */
2437     editinit();         /* init the editor messages */
2438     terminit();         /* init the termcap messages */
2439 }