1 /* $Header: /src/pub/tcsh/sh.func.c,v 3.103 2002/07/09 12:56:55 christos Exp $ */
3 * sh.func.c: csh builtin functions
6 * Copyright (c) 1980, 1991 The Regents of the University of California.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
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.
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
35 RCSID("$Id: sh.func.c,v 3.103 2002/07/09 12:56:55 christos Exp $")
42 #endif /* WINNT_NATIVE */
47 extern int just_signaled
;
48 extern char **environ
;
50 extern bool MapsAreInited
;
51 extern bool NLSMapsAreInited
;
52 extern bool NoNLSRebind
;
53 extern bool GotTermCaps
;
55 static int zlast
= -1;
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
*));
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};
78 * We never match a builtin that has quoted the first
79 * character; this has been the traditional way to escape
85 if (*cp
!= ':' && lastchr(cp
) == ':') {
86 label
.bname
= short2str(cp
);
90 if (t
->t_dflg
& F_AMPERSAND
) {
91 t
->t_dflg
&= ~F_AMPERSAND
;
92 backgnd
.bname
= short2str(cp
);
95 foregnd
.bname
= short2str(cp
);
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
105 if (eq(STRwarp
, cp
) && !checkwarp()) {
106 return (0); /* this builtin disabled */
110 * Binary search Bp1 is the beginning of the current search range. Bp2 is
113 for (bp1
= bfunc
, bp2
= bfunc
+ nbfunc
; bp1
< bp2
;) {
116 bp
= bp1
+ ((bp2
- bp1
) >> 1);
117 if ((i
= ((char) *cp
) - *bp
->bname
) == 0 &&
118 (i
= StrQcmp(cp
, str2short(bp
->bname
))) == 0)
126 return nt_check_additional_builtins(cp
);
127 #endif /*WINNT_NATIVE*/
133 register struct command
*t
;
134 register struct biltins
*bp
;
140 i
= blklen(t
->t_dcom
) - 1;
142 stderror(ERR_NAME
| ERR_TOOFEW
);
144 stderror(ERR_NAME
| ERR_TOOMANY
);
145 (*bp
->bfunct
) (t
->t_dcom
, t
);
155 register Char
*vv
= v
[1];
158 if (parintr
== SIG_IGN
)
160 if (setintr
&& intty
)
161 stderror(ERR_NAME
| ERR_TERMINAL
);
168 (void) sigblock(sigmask(SIGINT
));
169 (void) signal(SIGINT
, pintr
);
172 (void) signal(SIGINT
, SIG_DFL
);
175 (void) sighold(SIGINT
);
176 (void) sigset(SIGINT
, pintr
);
179 (void) sigset(SIGINT
, SIG_DFL
);
183 else if (eq((vv
= strip(vv
)), STRminus
)) {
185 (void) signal(SIGINT
, SIG_IGN
);
187 (void) sigset(SIGINT
, SIG_IGN
);
189 gointr
= Strsave(STRminus
);
192 gointr
= Strsave(vv
);
194 (void) signal(SIGINT
, pintr
);
196 (void) sigset(SIGINT
, pintr
);
210 stderror(ERR_NAME
| ERR_TERMINAL
);
212 (void) signal(SIGHUP
, SIG_IGN
);
228 stderror(ERR_NAME
| ERR_TERMINAL
);
230 (void) signal(SIGHUP
, SIG_DFL
);
250 Char
**fileptr
, *ftest
, *res
;
252 if (*(ftest
= *++v
) != '-')
253 stderror(ERR_NAME
| ERR_FILEINQ
);
261 stderror(ERR_NAME
| ERR_NOMATCH
);
264 v
= gargv
= saveblk(v
);
267 while (*(fileptr
= v
++) != '\0') {
268 xprintf("%S", res
= filetest(ftest
, &fileptr
, 0));
284 plist(&shvhed
, VAR_ALL
);
293 register struct varent
*vp
;
300 plist(&aliases
, VAR_ALL
);
302 vp
= adrof1(strip(p
), &aliases
);
304 blkpr(vp
->vec
), xputchar('\n');
307 if (eq(p
, STRalias
) || eq(p
, STRunalias
)) {
308 setname(short2str(p
));
309 stderror(ERR_NAME
| ERR_DANGER
);
311 set1(strip(p
), saveblk(v
), &aliases
, VAR_READWRITE
);
348 #else /* !WINNT_NATIVE */
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
);
356 #endif /* !WINNT_NATIVE */
368 if (chkstop
== 0 && setintr
)
370 (void) signal(SIGTERM
, parterm
);
373 * From Beto Appleton (beto@aixwiz.austin.ibm.com)
374 * Newgrp can take 2 arguments...
376 (void) execv(_PATH_BIN_NEWGRP
, p
);
377 (void) execv(_PATH_USRBIN_NEWGRP
, p
);
378 blkfree((Char
**) p
);
387 if (chkstop
== 0 && setintr
)
391 stderror(ERR_NOTLOGIN
);
406 stderror(ERR_NAME
| ERR_EMPTYIF
);
407 if (eq(*vv
, STRthen
)) {
409 stderror(ERR_NAME
| ERR_IMPRTHEN
);
410 setname(short2str(STRthen
));
412 * If expression was zero, then scan to else , otherwise just fall into
416 search(TC_IF
, 0, NULL
);
420 * Simple command attached to this if. Left shift the node in this tree,
421 * munging it so we can reexecute it.
424 lshift(kp
->t_dcom
, vv
- kp
->t_dcom
);
431 * Reexecute a command, being careful not
432 * to redo i/o redirection, which is already set up.
436 register struct command
*kp
;
438 kp
->t_dflg
&= F_SAVE
;
439 kp
->t_dflg
|= F_REPEAT
;
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.
445 execute(kp
, (tpgrp
> 0 ? tpgrp
: -1), NULL
, NULL
, TRUE
);
456 search(TC_ELSE
, 0, NULL
);
468 gotolab(lp
= globone(v
[1], G_ERROR
));
476 register struct whyle
*wp
;
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.
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
);
490 search(TC_GOTO
, 0, lab
);
492 * Eliminate loops which were exited.
503 register Char
*cp
, *lp
;
507 if (!*v
|| *(*v
++) != '(')
508 stderror(ERR_SYNTAX
);
509 cp
= **v
== ')' ? STRNULL
: *v
++;
513 stderror(ERR_SYNTAX
);
514 search(TC_SWITCH
, 0, lp
= globone(cp
, G_ERROR
));
529 stderror(ERR_NAME
| ERR_NOTWHILE
);
540 if (chkstop
== 0 && (intty
|| intact
) && evalvec
== 0)
543 * Don't DEMAND parentheses here either.
547 set(STRstatus
, putn(expr(&v
)), VAR_READWRITE
);
549 stderror(ERR_NAME
| ERR_EXPRESSION
);
555 /* Always close, why only on ttys? */
565 register Char
*cp
, *sp
;
566 register struct whyle
*nwp
;
572 stderror(ERR_NAME
| ERR_VARBEGIN
);
573 while (*cp
&& alnum(*cp
))
576 stderror(ERR_NAME
| ERR_VARALNUM
);
577 if ((cp
- sp
) > MAXVARLEN
)
578 stderror(ERR_NAME
| ERR_VARTOOLONG
);
580 if (v
[0][0] != '(' || v
[blklen(v
) - 1][0] != ')')
581 stderror(ERR_NAME
| ERR_NOPAREN
);
587 stderror(ERR_NAME
| ERR_NOMATCH
);
590 v
= gargv
= saveblk(v
);
593 nwp
= (struct whyle
*) xcalloc(1, sizeof *nwp
);
594 nwp
->w_fe
= nwp
->w_fe0
= v
;
596 btell(&nwp
->w_start
);
597 nwp
->w_fename
= Strsave(cp
);
598 nwp
->w_next
= whyles
;
599 nwp
->w_end
.type
= TCSH_F_SEEK
;
602 * Pre-read the loop so as to be more comprehensible to a terminal user.
617 register bool again
= whyles
!= 0 &&
618 SEEKEQ(&whyles
->w_start
, &lineloc
) &&
619 whyles
->w_fename
== 0;
624 * Implement prereading here also, taking care not to evaluate the
625 * expression before the loop has been read up from a terminal.
628 status
= !exp0(&v
, 1);
632 stderror(ERR_NAME
| ERR_EXPRESSION
);
634 register struct whyle
*nwp
=
635 (struct whyle
*) xcalloc(1, sizeof(*nwp
));
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
;
653 /* We ain't gonna loop no more, no more! */
660 whyles
->w_end
.type
= TCSH_I_SEEK
;
663 (void) sigsetmask(sigblock((sigmask_t
) 0) & ~sigmask(SIGINT
));
665 (void) sigrelse (SIGINT
);
667 search(TC_BREAK
, 0, NULL
); /* read the expression in */
670 (void) sigblock(sigmask(SIGINT
));
672 (void) sighold(SIGINT
);
674 btell(&whyles
->w_end
);
686 stderror(ERR_NAME
| ERR_NOTWHILE
);
687 btell(&whyles
->w_end
);
700 stderror(ERR_NAME
| ERR_NOTWHILE
);
707 /* Repeating a while is simple */
708 if (whyles
->w_fename
== 0) {
709 bseek(&whyles
->w_start
);
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
717 if (!whyles
->w_fe
[1]) {
721 set(whyles
->w_fename
, quote(Strsave(*whyles
->w_fe
++)), VAR_READWRITE
);
722 bseek(&whyles
->w_start
);
733 register sigmask_t omask
= 0;
739 } while (v
[0] != NULL
&& Strcmp(v
[0], STRrepeat
) == 0);
743 omask
= sigblock(sigmask(SIGINT
)) & ~sigmask(SIGINT
);
745 (void) sighold(SIGINT
);
750 (void) sigsetmask(omask
);
752 (void) sigrelse (SIGINT
);
760 (void) sigsetmask(omask
);
762 (void) sigrelse (SIGINT
);
774 search(TC_BRKSW
, 0, NULL
);
781 struct srch
*sp
, *sp1
, *sp2
;
785 * Ignore keywords inside heredocs
791 * Binary search Sp1 is the beginning of the current search range. Sp2 is
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)
811 register struct srch
*sp
, *sp2
;
813 for (sp
= srchn
, sp2
= srchn
+ nsrchn
; sp
< sp2
; sp
++)
814 if (sp
->s_value
== n
)
824 search(type
, level
, goal
)
829 Char wordbuf
[BUFSIZE
];
830 register Char
*aword
= wordbuf
;
835 if (type
== TC_GOTO
) {
837 a
.type
= TCSH_F_SEEK
;
842 if (intty
&& fseekp
== feobp
&& aret
== TCSH_F_SEEK
)
843 printprompt(1, isrchx(type
== TC_BREAK
? zlast
: type
));
844 /* xprintf("? "), flush(); */
846 (void) getword(aword
);
847 switch (srchx(aword
)) {
850 if (level
== 0 && type
== TC_IF
)
855 while (getword(aword
))
857 if ((type
== TC_IF
|| type
== TC_ELSE
) &&
863 if (type
== TC_IF
|| type
== TC_ELSE
)
869 if (type
== TC_BREAK
)
874 if (type
== TC_BREAK
)
879 if (type
== TC_SWITCH
|| type
== TC_BRKSW
)
884 if (type
== TC_SWITCH
|| type
== TC_BRKSW
)
889 if (type
== TC_GOTO
&& getword(aword
) && eq(aword
, goal
))
894 if (type
!= TC_GOTO
&& (type
!= TC_SWITCH
|| level
!= 0))
896 if (lastchr(aword
) != ':')
898 aword
[Strlen(aword
) - 1] = 0;
899 if ((type
== TC_GOTO
&& eq(aword
, goal
)) ||
900 (type
== TC_SWITCH
&& eq(aword
, STRdefault
)))
905 if (type
!= TC_SWITCH
|| level
!= 0)
907 (void) getword(aword
);
908 if (lastchr(aword
) == ':')
909 aword
[Strlen(aword
) - 1] = 0;
910 cp
= strip(Dfix1(aword
));
911 if (Gmatch(goal
, cp
))
917 if (type
== TC_SWITCH
&& level
== 0)
921 (void) getword(NULL
);
922 } while (level
>= 0);
929 int found
= 0, first
;
935 while (c
== ' ' || c
== '\t')
940 while (c
>= 0 && c
!= '\n');
953 if (c
== '\\' && (c
= readc(1)) == '\n')
955 if (c
== '\'' || c
== '"') {
967 if (!first
&& !d
&& c
== '(') {
977 } while ((d
|| (c
!= ' ' && c
!= '\t')) && c
!= '\n');
990 stderror(ERR_NAME
| ERR_NOTFOUND
, "then/endif");
994 stderror(ERR_NAME
| ERR_NOTFOUND
, "endif");
999 stderror(ERR_NAME
| ERR_NOTFOUND
, "endsw");
1003 stderror(ERR_NAME
| ERR_NOTFOUND
, "end");
1007 setname(short2str(Sgoal
));
1008 stderror(ERR_NAME
| ERR_NOTFOUND
, "label");
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
--;
1027 bseek(&whyles
->w_end
);
1038 nwp
= NULL
; /* sun lint is dumb! */
1042 static char foo
[] = "IAFE";
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
);
1052 for (; whyles
; whyles
= nwp
) {
1053 register struct whyle
*wp
= whyles
;
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
);
1065 * XXX: We free loops that have different seek types.
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
))
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
))
1084 xfree((ptr_t
) wp
->w_fename
);
1118 int echo_style
= ECHO_STYLE
;
1119 #else /* !ECHO_STYLE */
1121 int echo_style
= SYSV_ECHO
;
1122 # else /* SYSVREL == 0 */
1123 int echo_style
= BSD_ECHO
;
1124 # endif /* SYSVREL */
1125 #endif /* ECHO_STYLE */
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
;
1142 (void) sigsetmask(sigblock((sigmask_t
) 0) & ~sigmask(SIGINT
));
1143 #else /* !BSDSIGS */
1144 (void) sigrelse (SIGINT
);
1145 #endif /* BSDSIGS */
1149 gflag
= 0, tglob(v
);
1153 stderror(ERR_NAME
| ERR_NOMATCH
);
1156 v
= gargv
= saveblk(v
);
1160 if ((echo_style
& BSD_ECHO
) != 0 && sep
== ' ' && *v
&& eq(*v
, STRmn
))
1163 while ((cp
= *v
++) != 0) {
1166 while ((c
= *cp
++) != 0) {
1167 if ((echo_style
& SYSV_ECHO
) != 0 && c
== '\\') {
1168 switch (c
= *cp
++) {
1179 #if 0 /* Windows does not understand \e */
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';
1217 xputchar('\\' | QUOTE
);
1221 xputchar(c
| QUOTE
);
1225 xputchar(sep
| QUOTE
);
1228 if (sep
&& nonl
== 0)
1234 (void) sigblock(sigmask(SIGINT
));
1235 #else /* !BSDSIGS */
1236 (void) sighold(SIGINT
);
1237 #endif /* BSDSIGS */
1239 blkfree(gargv
), gargv
= 0;
1242 /* check whether an environment variable should invoke 'set_locale()' */
1247 static Char
*locale_vars
[] = {
1248 STRLANG
, STRLC_CTYPE
, STRLC_NUMERIC
, STRLC_TIME
,
1249 STRLC_COLLATE
, STRLC_MESSAGES
, STRLC_MONETARY
, 0
1253 for (v
= locale_vars
; *v
; ++v
)
1266 extern bool output_raw
;
1267 extern bool xlate_cr
;
1272 (void) sigsetmask(sigblock((sigmask_t
) 0) & ~sigmask(SIGINT
));
1273 #else /* !BSDSIGS */
1274 (void) sigrelse (SIGINT
);
1275 #endif /* BSDSIGS */
1282 for (ep
= STR_environ
; *ep
; ep
++)
1283 xprintf("%S\n", *ep
);
1286 else if ((e
= tgetenv(*v
)) != NULL
) {
1292 set(STRstatus
, Strsave(STR1
), VAR_READWRITE
);
1295 /* from "Karl Berry." <karl%mote.umb.edu@relay.cs.net> -- for NeXT things
1296 (and anything else with a modern compiler) */
1316 stderror(ERR_NAME
| ERR_VARBEGIN
);
1318 for (; alnum(*lp
); lp
++)
1322 stderror(ERR_NAME
| ERR_SYNTAX
);
1324 if ((lp
= *v
++) == 0)
1327 tsetenv(vp
, lp
= globone(lp
, G_APPEND
));
1328 if (eq(vp
, STRKPATH
)) {
1336 if (eq(vp
, STRSYSTYPE
)) {
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
);
1351 if (islocale_var(vp
)) {
1355 # ifdef SETLOCALEBUG
1357 # endif /* SETLOCALEBUG */
1358 (void) setlocale(LC_ALL
, "");
1360 (void) setlocale(LC_COLLATE
, "");
1362 # ifdef NLS_CATALOGS
1364 (void) setlocale(LC_MESSAGES
, "");
1365 # endif /* LC_MESSAGES */
1366 (void) catclose(catd
);
1368 # endif /* NLS_CATALOGS */
1370 (void) setlocale(LC_CTYPE
, ""); /* for iscntrl */
1371 # endif /* LC_CTYPE */
1372 # ifdef SETLOCALEBUG
1374 # endif /* SETLOCALEBUG */
1377 # endif /* STRCOLLBUG */
1378 tw_cmd_free(); /* since the collation sequence has changed */
1379 for (k
= 0200; k
<= 0377 && !Isprint(k
); k
++)
1381 AsciiOnly
= k
> 0377;
1385 NLSMapsAreInited
= 0;
1387 if (MapsAreInited
&& !NLSMapsAreInited
)
1394 if (eq(vp
, STRNLSPATH
)) {
1395 (void) catclose(catd
);
1400 if (eq(vp
, STRNOREBIND
)) {
1403 NLSMapsAreInited
= 0;
1409 if (eq(vp
, STRtcshlang
)) {
1414 #endif /* WINNT_NATIVE */
1415 if (eq(vp
, STRKTERM
)) {
1417 set(STRterm
, quote(lp
), VAR_READWRITE
); /* lp memory used here */
1419 if (noediting
&& strcmp(t
, "unknown") != 0 && strcmp(t
,"dumb") != 0) {
1422 set(STRedit
, Strsave(STRNULL
), VAR_READWRITE
);
1429 if (eq(vp
, STRKHOME
)) {
1431 * convert to canonical pathname (possibly resolving symlinks)
1433 lp
= dcanon(lp
, lp
);
1434 set(STRhome
, quote(lp
), VAR_READWRITE
); /* cp memory used here */
1436 /* fix directory stack for new tilde home */
1441 if (eq(vp
, STRKSHLVL
)) {
1442 /* lp memory used here */
1443 set(STRshlvl
, quote(lp
), VAR_READWRITE
);
1447 if (eq(vp
, STRKUSER
)) {
1448 set(STRuser
, quote(lp
), VAR_READWRITE
); /* lp memory used here */
1452 if (eq(vp
, STRKGROUP
)) {
1453 set(STRgroup
, quote(lp
), VAR_READWRITE
); /* lp memory used here */
1458 if (eq(vp
, STRLS_COLORS
)) {
1462 #endif /* COLOR_LS_F */
1466 * Load/Update $LINES $COLUMNS
1468 if ((eq(lp
, STRNULL
) && (eq(vp
, STRLINES
) || eq(vp
, STRCOLUMNS
))) ||
1469 eq(vp
, STRTERMCAP
)) {
1471 check_window_size(1);
1476 * Change the size to the one directed by $LINES and $COLUMNS
1478 if (eq(vp
, STRLINES
) || eq(vp
, STRCOLUMNS
)) {
1486 #endif /* SIG_WINDOW */
1498 static Char
*name
= NULL
;
1502 xfree((ptr_t
) name
);
1504 * Find the longest environment variable
1506 for (maxi
= 0, ep
= STR_environ
; *ep
; ep
++) {
1507 for (i
= 0, p
= *ep
; *p
&& *p
!= '='; p
++, i
++)
1513 name
= (Char
*) xmalloc((size_t) ((maxi
+ 1) * sizeof(Char
)));
1516 for (maxi
= 1; maxi
;)
1517 for (maxi
= 0, ep
= STR_environ
; *ep
; ep
++) {
1518 for (n
= name
, p
= *ep
; *p
&& *p
!= '='; *n
++ = *p
++)
1521 if (!Gmatch(name
, *v
))
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
1533 if (eq(name
, STRNOREBIND
)) {
1536 NLSMapsAreInited
= 0;
1540 else if (eq(name
, STRSYSTYPE
))
1543 else if (islocale_var(name
)) {
1547 # ifdef SETLOCALEBUG
1549 # endif /* SETLOCALEBUG */
1550 (void) setlocale(LC_ALL
, "");
1552 (void) setlocale(LC_COLLATE
, "");
1554 # ifdef NLS_CATALOGS
1556 (void) setlocale(LC_MESSAGES
, "");
1557 # endif /* LC_MESSAGES */
1558 (void) catclose(catd
);
1560 # endif /* NLS_CATALOGS */
1562 (void) setlocale(LC_CTYPE
, ""); /* for iscntrl */
1563 # endif /* LC_CTYPE */
1564 # ifdef SETLOCALEBUG
1566 # endif /* SETLOCALEBUG */
1569 # endif /* STRCOLLBUG */
1570 tw_cmd_free();/* since the collation sequence has changed */
1571 for (k
= 0200; k
<= 0377 && !Isprint(k
); k
++)
1573 AsciiOnly
= k
> 0377;
1575 AsciiOnly
= getenv("LANG") == NULL
&&
1576 getenv("LC_CTYPE") == NULL
;
1578 NLSMapsAreInited
= 0;
1580 if (MapsAreInited
&& !NLSMapsAreInited
)
1585 else if (eq(name
,(STRtcshlang
))) {
1589 #endif /* WINNT_NATIVE */
1591 else if (eq(name
, STRLS_COLORS
))
1593 #endif /* COLOR_LS_F */
1595 else if (eq(name
, STRNLSPATH
)) {
1596 (void) catclose(catd
);
1601 * start again cause the environment changes
1605 xfree((ptr_t
) name
); name
= NULL
;
1612 #ifdef SETENV_IN_LIB
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.
1620 char nameBuf
[BUFSIZE
];
1621 char *cname
= short2str(name
);
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
;
1634 nt_set_env(name
,val
);
1635 #endif /* WINNT_NATIVE */
1638 for (cp
= name
, dp
= *ep
; *cp
&& Tolower(*cp
& TRIM
) == Tolower(*dp
);
1641 for (cp
= name
, dp
= *ep
; *cp
&& (*cp
& TRIM
) == *dp
; cp
++, dp
++)
1642 #endif /* WINNT_NATIVE */
1644 if (*cp
!= 0 || *dp
!= '=')
1646 cp
= Strspl(STRequal
, val
);
1647 xfree((ptr_t
) * ep
);
1648 *ep
= strip(Strspl(name
, cp
));
1650 blkfree((Char
**) environ
);
1651 environ
= short2blk(STR_environ
);
1654 cp
= Strspl(name
, STRequal
);
1655 blk
[0] = strip(Strspl(cp
, val
));
1658 STR_environ
= blkspl(STR_environ
, blk
);
1659 blkfree((Char
**) environ
);
1660 environ
= short2blk(STR_environ
);
1662 #endif /* SETENV_IN_LIB */
1669 register Char
**ep
= STR_environ
;
1670 register Char
*cp
, *dp
;
1674 nt_set_env(name
,NULL
);
1675 #endif /*WINNT_NATIVE */
1677 for (cp
= name
, dp
= *ep
; *cp
&& *cp
== *dp
; cp
++, dp
++)
1679 if (*cp
!= 0 || *dp
!= '=')
1683 STR_environ
= blkspl(STR_environ
, ep
+ 1);
1684 blkfree((Char
**) environ
);
1685 environ
= short2blk(STR_environ
);
1699 register Char
*cp
= v
[1];
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
);
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 */
1728 # define toset(a) (((a) == 3) ? 1004 : (a) + 1)
1729 # define RLIMIT_DATA 3
1730 # define RLIMIT_STACK 1005
1732 # define toset(a) ((a) + 1)
1734 # else /* BSDLIMIT */
1735 # if (defined(BSD4_4) || defined(__linux__)) && !defined(__386BSD__)
1736 typedef rlim_t RLIM_TYPE
;
1738 # if defined(SOLARIS2) || (defined(sgi) && SYSVREL > 3)
1739 typedef rlim_t RLIM_TYPE
;
1742 typedef long long RLIM_TYPE
;
1744 typedef unsigned long RLIM_TYPE
;
1746 # endif /* SOLARIS2 || (sgi && SYSVREL > 3) */
1747 # endif /* BSD4_4 && !__386BSD__ */
1748 # endif /* BSDLIMIT */
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? */
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 */
1766 * old versions of HP/UX counted limits in 512 bytes
1769 # define FILESIZE512
1770 # endif /* SIGRTMIN */
1771 # endif /* (HPUXVERSION > 700) && BSDLIMIT */
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
1783 # define RLIMIT_AS RLIMIT_VMEM
1785 # endif /* SYSVREL > 3 && BSDLIMIT */
1787 # if defined(__linux__) && defined(RLIMIT_AS) && !defined(RLIMIT_VMEM)
1788 # define RLIMIT_VMEM RLIMIT_AS
1791 struct limits limits
[] =
1794 { RLIMIT_CPU
, "cputime", 1, "seconds" },
1795 # endif /* RLIMIT_CPU */
1797 # ifdef RLIMIT_FSIZE
1799 { RLIMIT_FSIZE
, "filesize", 1024, "kbytes" },
1801 { RLIMIT_FSIZE
, "filesize", 512, "blocks" },
1803 # endif /* RLIMIT_FSIZE */
1806 { RLIMIT_DATA
, "datasize", 1024, "kbytes" },
1807 # endif /* RLIMIT_DATA */
1809 # ifdef RLIMIT_STACK
1811 { RLIMIT_STACK
, "stacksize", 1024, "kbytes" },
1813 { RLIMIT_STACK
, "stacksize", 1024 * 1024, "kbytes"},
1815 # endif /* RLIMIT_STACK */
1818 { RLIMIT_CORE
, "coredumpsize", 1024, "kbytes" },
1819 # endif /* RLIMIT_CORE */
1822 { RLIMIT_RSS
, "memoryuse", 1024, "kbytes" },
1823 # endif /* RLIMIT_RSS */
1826 { RLIMIT_UMEM
, "memoryuse", 1024, "kbytes" },
1827 # endif /* RLIMIT_UMEM */
1830 { RLIMIT_VMEM
, "vmemoryuse", 1024, "kbytes" },
1831 # endif /* RLIMIT_VMEM */
1833 # ifdef RLIMIT_NOFILE
1834 { RLIMIT_NOFILE
, "descriptors", 1, "" },
1835 # endif /* RLIMIT_NOFILE */
1837 # ifdef RLIMIT_CONCUR
1838 { RLIMIT_CONCUR
, "concurrency", 1, "thread(s)" },
1839 # endif /* RLIMIT_CONCUR */
1841 # ifdef RLIMIT_MEMLOCK
1842 { RLIMIT_MEMLOCK
, "memorylocked", 1024, "kbytes" },
1843 # endif /* RLIMIT_MEMLOCK */
1845 # ifdef RLIMIT_NPROC
1846 { RLIMIT_NPROC
, "maxproc", 1, "" },
1847 # endif /* RLIMIT_NPROC */
1849 # if defined(RLIMIT_OFILE) && !defined(RLIMIT_NOFILE)
1850 { RLIMIT_OFILE
, "openfiles", 1, "" },
1851 # endif /* RLIMIT_OFILE && !defined(RLIMIT_NOFILE) */
1853 # ifdef RLIMIT_SBSIZE
1854 { RLIMIT_SBSIZE
, "sbsize", 1, "" },
1855 # endif /* RLIMIT_SBSIZE */
1857 #ifdef RLIMIT_POSIXLOCKS
1858 { RLIMIT_POSIXLOCKS
, "posixlocks", 1, "" },
1859 #endif /* RLIMIT_POSIXLOCKS */
1861 { -1, NULL
, 0, NULL
}
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
));
1872 restrict_limit(value
)
1876 * is f too large to cope with? return the maximum or minimum int
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
;
1883 return (RLIM_TYPE
) value
;
1886 # define restrict_limit(x) ((RLIM_TYPE) (x))
1890 static struct limits
*
1894 register struct limits
*lp
, *res
;
1896 res
= (struct limits
*) NULL
;
1897 for (lp
= limits
; lp
->limconst
>= 0; lp
++)
1898 if (prefix(cp
, str2short(lp
->limname
))) {
1900 stderror(ERR_NAME
| ERR_AMBIG
);
1905 stderror(ERR_NAME
| ERR_LIMIT
);
1916 register struct limits
*lp
;
1917 register RLIM_TYPE limit
;
1922 if (*v
&& eq(*v
, STRmh
)) {
1927 for (lp
= limits
; lp
->limconst
>= 0; lp
++)
1936 limit
= getval(lp
, v
+ 1);
1937 if (setlim(lp
, hard
, limit
) < 0)
1938 stderror(ERR_SILENT
);
1943 register struct limits
*lp
;
1947 #ifndef atof /* This can be a macro on linux */
1948 extern double atof
__P((const char *));
1952 f
= atof(short2str(cp
));
1956 * is f too large to cope with. limit f to minint, maxint - X-6768 by
1959 if ((f
< (double) INT_MIN
) || (f
> (double) INT_MAX
)) {
1960 stderror(ERR_NAME
| ERR_TOOLARGE
);
1962 # endif /* convex */
1964 while (Isdigit(*cp
) || *cp
== '.' || *cp
== 'e' || *cp
== 'E')
1968 return restrict_limit((f
* lp
->limdiv
) + 0.5);
1974 if (lp
->limconst
!= RLIMIT_CPU
)
1976 return f
== 0.0 ? (RLIM_TYPE
) 0 : restrict_limit((f
* 60.0 + atof(short2str(cp
+ 1))));
1978 if (lp
->limconst
!= RLIMIT_CPU
)
1980 limtail(cp
, "hours");
1984 if (lp
->limconst
== RLIMIT_CPU
) {
1985 limtail(cp
, "minutes");
1990 limtail(cp
, "megabytes");
1991 f
*= 1024.0 * 1024.0;
1994 if (lp
->limconst
!= RLIMIT_CPU
)
1996 limtail(cp
, "seconds");
1998 # endif /* RLIMIT_CPU */
2001 if (lp
->limconst
== RLIMIT_CPU
)
2003 # endif /* RLIMIT_CPU */
2005 limtail(cp
, "megabytes");
2006 f
*= 1024.0 * 1024.0;
2010 if (lp
->limconst
== RLIMIT_CPU
)
2012 # endif /* RLIMIT_CPU */
2013 limtail(cp
, "kbytes");
2018 if (lp
->limconst
== RLIMIT_CPU
)
2020 # endif /* RLIMIT_CPU */
2021 limtail(cp
, "blocks");
2025 limtail(cp
, "unlimited");
2026 return ((RLIM_TYPE
) RLIM_INFINITY
);
2030 # endif /* RLIMIT_CPU */
2031 stderror(ERR_NAME
| ERR_SCALEF
);
2034 return f
== 0.0 ? (RLIM_TYPE
) 0 : restrict_limit((f
+ 0.5));
2037 if (f
> (float) RLIM_INFINITY
)
2038 return ((RLIM_TYPE
) RLIM_INFINITY
);
2040 return ((RLIM_TYPE
) f
);
2041 # endif /* convex */
2052 while (*cp
&& *cp
== *str
)
2055 stderror(ERR_BADSCALE
, sp
);
2062 register struct limits
*lp
;
2067 # endif /* BSDLIMIT */
2069 int div
= lp
->limdiv
;
2071 xprintf("%s \t", lp
->limname
);
2074 limit
= ulimit(lp
->limconst
, 0);
2076 if (lp
->limconst
== RLIMIT_DATA
)
2077 limit
-= 0x20000000;
2079 # else /* BSDLIMIT */
2080 (void) getrlimit(lp
->limconst
, &rlim
);
2081 limit
= hard
? rlim
.rlim_max
: rlim
.rlim_cur
;
2082 # endif /* BSDLIMIT */
2084 # if !defined(BSDLIMIT) || defined(FILESIZE512)
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)
2089 if (lp
->limconst
== RLIMIT_FSIZE
) {
2090 if (limit
>= (RLIM_INFINITY
/ 512))
2091 limit
= RLIM_INFINITY
;
2093 div
= (div
== 1024 ? 2 : 1);
2095 # endif /* !BSDLIMIT || FILESIZE512 */
2097 if (limit
== RLIM_INFINITY
)
2098 xprintf("unlimited");
2101 if (lp
->limconst
== RLIMIT_CPU
)
2102 psecs((long) limit
);
2104 # endif /* RLIMIT_CPU */
2105 xprintf("%ld %s", (long) (limit
/ div
), lp
->limscale
);
2115 register struct limits
*lp
;
2121 while (*++v
&& **v
== '-') {
2132 stderror(ERR_ULIMUS
);
2138 for (lp
= limits
; lp
->limconst
>= 0; lp
++)
2139 if (setlim(lp
, hard
, (RLIM_TYPE
) RLIM_INFINITY
) < 0)
2142 stderror(ERR_SILENT
);
2147 if (setlim(lp
, hard
, (RLIM_TYPE
) RLIM_INFINITY
) < 0 && !force
)
2148 stderror(ERR_SILENT
);
2153 setlim(lp
, hard
, limit
)
2154 register struct limits
*lp
;
2161 (void) getrlimit(lp
->limconst
, &rlim
);
2164 /* Even though hpux has setrlimit(), it expects fsize in 512 byte blocks */
2165 if (limit
!= RLIM_INFINITY
&& lp
->limconst
== RLIMIT_FSIZE
)
2167 # endif /* FILESIZE512 */
2169 rlim
.rlim_max
= limit
;
2170 else if (limit
== RLIM_INFINITY
&& euid
!= 0)
2171 rlim
.rlim_cur
= rlim
.rlim_max
;
2173 rlim
.rlim_cur
= limit
;
2175 if (rlim
.rlim_cur
> rlim
.rlim_max
)
2176 rlim
.rlim_max
= rlim
.rlim_cur
;
2178 if (setrlimit(lp
->limconst
, &rlim
) < 0) {
2179 # else /* BSDLIMIT */
2180 if (limit
!= RLIM_INFINITY
&& lp
->limconst
== RLIMIT_FSIZE
)
2183 if (lp
->limconst
== RLIMIT_DATA
)
2184 limit
+= 0x20000000;
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") : "",
2197 #endif /* !HAVENOLIMIT */
2209 #endif /* BSDJOBS */
2215 stderror(ERR_SUSPLOG
);
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 */
2230 ctpgrp
= tcgetpgrp(FSHTTY
);
2231 if (ctpgrp
!= opgrp
) {
2232 old
= signal(SIGTTIN
, SIG_DFL
);
2233 (void) kill(0, SIGTTIN
);
2234 (void) signal(SIGTTIN
, old
);
2237 (void) setpgid(0, shpgrp
);
2238 (void) tcsetpgrp(FSHTTY
, shpgrp
);
2240 #endif /* BSDJOBS */
2241 (void) setdisc(FSHTTY
);
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!
2257 static Char
**gv
= NULL
, **gav
= NULL
;
2268 #ifndef CLOSE_ON_EXEC
2270 #endif /* CLOSE_ON_EXEC */
2274 int saveIN
, saveOUT
, saveDIAG
;
2275 int oSHIN
, oSHOUT
, oSHDIAG
;
2281 #ifndef CLOSE_ON_EXEC
2283 #endif /* CLOSE_ON_EXEC */
2294 gflag
= 0, tglob(gav
);
2296 gv
= gav
= globall(gav
);
2299 stderror(ERR_NOMATCH
);
2308 saveIN
= dcopy(SHIN
, -1);
2309 saveOUT
= dcopy(SHOUT
, -1);
2310 saveDIAG
= dcopy(SHDIAG
, -1);
2314 /* PWP: setjmp/longjmp bugfix for optimizing compilers */
2316 my_reenter
= 1; /* assume non-zero return val */
2317 if (setexit() == 0) {
2318 my_reenter
= 0; /* Oh well, we were wrong */
2320 if ((my_reenter
= setexit()) == 0) {
2324 SHIN
= dcopy(0, -1);
2325 SHOUT
= dcopy(1, -1);
2326 SHDIAG
= dcopy(2, -1);
2327 #ifndef CLOSE_ON_EXEC
2329 #endif /* CLOSE_ON_EXEC */
2337 #ifndef CLOSE_ON_EXEC
2339 #endif /* CLOSE_ON_EXEC */
2342 (void) close(SHOUT
);
2343 (void) close(SHDIAG
);
2344 SHIN
= dmove(saveIN
, oSHIN
);
2345 SHOUT
= dmove(saveOUT
, oSHOUT
);
2346 SHDIAG
= dmove(saveDIAG
, oSHDIAG
);
2354 stderror(ERR_SILENT
);
2357 /*************************************************************************/
2358 /* print list of builtin commands */
2366 /* would use print_by_column() in tw.parse.c but that assumes
2367 * we have an array of Char * to pass.. (sg)
2369 extern int Tty_raw_mode
;
2370 extern int TermH
; /* from the editor routines */
2371 extern int lbuffed
; /* from sh.print.c */
2373 register struct biltins
*b
;
2374 register int row
, col
, columns
, rows
;
2375 unsigned int w
, maxwidth
;
2379 lbuffed
= 0; /* turn off line buffering */
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 */
2386 columns
= (TermH
+ 1) / maxwidth
; /* PWP: terminal size change */
2389 rows
= (nbfunc
+ (columns
- 1)) / columns
;
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
++)
2402 if (row
< (rows
- 1)) {
2409 nt_print_builtins(maxwidth
);
2414 #endif /* WINNT_NATIVE */
2416 lbuffed
= 1; /* turn back on line buffering */
2424 char catalog
[ 256 ] = { 't', 'c', 's', 'h', '\0' };
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 */
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 */