source: trunk/third/tcsh/sh.func.c @ 13093

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