1 /* $Header: /src/pub/tcsh/sh.func.c,v 3.126 2005/03/20 06:35:48 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.126 2005/03/20 06:35:48 christos Exp $")
42 #endif /* WINNT_NATIVE */
47 static iconv_t catgets_iconv; /* Or (iconv_t)-1 */
54 extern int just_signaled;
55 extern char **environ;
57 extern int MapsAreInited;
58 extern int NLSMapsAreInited;
59 extern int GotTermCaps;
61 static int zlast = -1;
63 static void islogin __P((void));
64 static void preread __P((void));
65 static void doagain __P((void));
66 static const char *isrchx __P((int));
67 static void search __P((int, int, Char *));
68 static int getword __P((Char *));
69 static void toend __P((void));
70 static void xecho __P((int, Char **));
71 static int islocale_var __P((Char *));
72 static void wpfree __P((struct whyle *));
78 Char *cp = t->t_dcom[0];
79 struct biltins *bp, *bp1, *bp2;
80 static struct biltins label = {"", dozip, 0, 0};
81 static struct biltins foregnd = {"%job", dofg1, 0, 0};
82 static struct biltins backgnd = {"%job &", dobg1, 0, 0};
85 * We never match a builtin that has quoted the first
86 * character; this has been the traditional way to escape
92 if (*cp != ':' && lastchr(cp) == ':') {
93 label.bname = short2str(cp);
97 if (t->t_dflg & F_AMPERSAND) {
98 t->t_dflg &= ~F_AMPERSAND;
99 backgnd.bname = short2str(cp);
102 foregnd.bname = short2str(cp);
107 * This is a perhaps kludgy way to determine if the warp builtin is to be
108 * acknowledged or not. If checkwarp() fails, then we are to assume that
109 * the warp command is invalid, and carry on as we would handle any other
110 * non-builtin command. -- JDK 2/4/88
112 if (eq(STRwarp, cp) && !checkwarp()) {
113 return (0); /* this builtin disabled */
117 * Binary search Bp1 is the beginning of the current search range. Bp2 is
120 for (bp1 = bfunc, bp2 = bfunc + nbfunc; bp1 < bp2;) {
123 bp = bp1 + ((bp2 - bp1) >> 1);
124 if ((i = ((char) *cp) - *bp->bname) == 0 &&
125 (i = StrQcmp(cp, str2short(bp->bname))) == 0)
133 return nt_check_additional_builtins(cp);
134 #endif /*WINNT_NATIVE*/
147 i = blklen(t->t_dcom) - 1;
149 stderror(ERR_NAME | ERR_TOOFEW);
151 stderror(ERR_NAME | ERR_TOOMANY);
152 (*bp->bfunct) (t->t_dcom, t);
165 if (parintr == SIG_IGN)
167 if (setintr && intty)
168 stderror(ERR_NAME | ERR_TERMINAL);
175 (void) sigblock(sigmask(SIGINT));
176 (void) signal(SIGINT, pintr);
179 (void) signal(SIGINT, SIG_DFL);
182 (void) sighold(SIGINT);
183 (void) sigset(SIGINT, pintr);
186 (void) sigset(SIGINT, SIG_DFL);
190 else if (eq((vv = strip(vv)), STRminus)) {
192 (void) signal(SIGINT, SIG_IGN);
194 (void) sigset(SIGINT, SIG_IGN);
196 gointr = Strsave(STRminus);
199 gointr = Strsave(vv);
201 (void) signal(SIGINT, pintr);
203 (void) sigset(SIGINT, pintr);
217 stderror(ERR_NAME | ERR_TERMINAL);
219 (void) signal(SIGHUP, SIG_IGN);
235 stderror(ERR_NAME | ERR_TERMINAL);
237 (void) signal(SIGHUP, SIG_DFL);
257 Char **fileptr, *ftest, *res;
260 if (*(ftest = *++v) != '-')
261 stderror(ERR_NAME | ERR_FILEINQ);
269 stderror(ERR_NAME | ERR_NOMATCH);
272 v = gargv = saveblk(v);
275 while (*(fileptr = v++) != '\0') {
276 xprintf("%S", res = filetest(ftest, &fileptr, 0));
292 plist(&shvhed, VAR_ALL);
308 plist(&aliases, VAR_ALL);
310 vp = adrof1(strip(p), &aliases);
312 blkpr(vp->vec), xputchar('\n');
315 if (eq(p, STRalias) || eq(p, STRunalias)) {
316 setname(short2str(p));
317 stderror(ERR_NAME | ERR_DANGER);
319 set1(strip(p), saveblk(v), &aliases, VAR_READWRITE);
356 #else /* !WINNT_NATIVE */
357 char **p = short2blk(v);
360 rechist(NULL, adrof(STRsavehist) != NULL);
361 (void) signal(SIGTERM, parterm);
362 (void) execv(_PATH_BIN_LOGIN, p);
363 (void) execv(_PATH_USRBIN_LOGIN, p);
364 blkfree((Char **) p);
367 #endif /* !WINNT_NATIVE */
379 if (chkstop == 0 && setintr)
381 (void) signal(SIGTERM, parterm);
384 * From Beto Appleton (beto@aixwiz.austin.ibm.com)
385 * Newgrp can take 2 arguments...
387 (void) execv(_PATH_BIN_NEWGRP, p);
388 (void) execv(_PATH_USRBIN_NEWGRP, p);
389 blkfree((Char **) p);
398 if (chkstop == 0 && setintr)
402 stderror(ERR_NOTLOGIN);
417 stderror(ERR_NAME | ERR_EMPTYIF);
418 if (eq(*vv, STRthen)) {
420 stderror(ERR_NAME | ERR_IMPRTHEN);
421 setname(short2str(STRthen));
423 * If expression was zero, then scan to else , otherwise just fall into
427 search(TC_IF, 0, NULL);
431 * Simple command attached to this if. Left shift the node in this tree,
432 * munging it so we can reexecute it.
435 lshift(kp->t_dcom, vv - kp->t_dcom);
442 * Reexecute a command, being careful not
443 * to redo i/o redirection, which is already set up.
449 kp->t_dflg &= F_SAVE;
450 kp->t_dflg |= F_REPEAT;
452 * If tty is still ours to arbitrate, arbitrate it; otherwise dont even set
453 * pgrp's as the jobs would then have no way to get the tty (we can't give
454 * it to them, and our parent wouldn't know their pgrp, etc.
456 execute(kp, (tpgrp > 0 ? tpgrp : -1), NULL, NULL, TRUE);
467 search(TC_ELSE, 0, NULL);
479 gotolab(lp = globone(v[1], G_ERROR));
489 * While we still can, locate any unknown ends of existing loops. This
490 * obscure code is the WORST result of the fact that we don't really parse.
493 for (wp = whyles; wp; wp = wp->w_next)
494 if (wp->w_end.type == TCSH_F_SEEK && wp->w_end.f_seek == 0) {
495 search(TC_BREAK, 0, NULL);
501 search(TC_GOTO, 0, lab);
503 * Eliminate loops which were exited.
518 if (!*v || *(*v++) != '(')
519 stderror(ERR_SYNTAX);
520 cp = **v == ')' ? STRNULL : *v++;
524 stderror(ERR_SYNTAX);
525 search(TC_SWITCH, 0, lp = globone(cp, G_ERROR));
540 stderror(ERR_NAME | ERR_NOTWHILE);
551 if (chkstop == 0 && (intty || intact) && evalvec == 0)
554 * Don't DEMAND parentheses here either.
558 set(STRstatus, putn(expr(&v)), VAR_READWRITE);
560 stderror(ERR_NAME | ERR_EXPRESSION);
566 /* Always close, why only on ttys? */
583 stderror(ERR_NAME | ERR_VARBEGIN);
584 while (*cp && alnum(*cp))
587 stderror(ERR_NAME | ERR_VARALNUM);
588 if ((cp - sp) > MAXVARLEN)
589 stderror(ERR_NAME | ERR_VARTOOLONG);
591 if (v[0][0] != '(' || v[blklen(v) - 1][0] != ')')
592 stderror(ERR_NAME | ERR_NOPAREN);
598 stderror(ERR_NAME | ERR_NOMATCH);
601 v = gargv = saveblk(v);
604 nwp = (struct whyle *) xcalloc(1, sizeof *nwp);
605 nwp->w_fe = nwp->w_fe0 = v;
607 btell(&nwp->w_start);
608 nwp->w_fename = Strsave(cp);
609 nwp->w_next = whyles;
610 nwp->w_end.type = TCSH_F_SEEK;
613 * Pre-read the loop so as to be more comprehensible to a terminal user.
628 int again = whyles != 0 &&
629 SEEKEQ(&whyles->w_start, &lineloc) &&
630 whyles->w_fename == 0;
635 * Implement prereading here also, taking care not to evaluate the
636 * expression before the loop has been read up from a terminal.
639 status = !exp0(&v, 1);
643 stderror(ERR_NAME | ERR_EXPRESSION);
646 (struct whyle *) xcalloc(1, sizeof(*nwp));
648 nwp->w_start = lineloc;
649 nwp->w_end.type = TCSH_F_SEEK;
650 nwp->w_end.f_seek = 0;
651 nwp->w_next = whyles;
664 /* We ain't gonna loop no more, no more! */
671 whyles->w_end.type = TCSH_I_SEEK;
674 (void) sigsetmask(sigblock((sigmask_t) 0) & ~sigmask(SIGINT));
676 (void) sigrelse (SIGINT);
678 search(TC_BREAK, 0, NULL); /* read the expression in */
681 (void) sigblock(sigmask(SIGINT));
683 (void) sighold(SIGINT);
685 btell(&whyles->w_end);
697 stderror(ERR_NAME | ERR_NOTWHILE);
698 btell(&whyles->w_end);
711 stderror(ERR_NAME | ERR_NOTWHILE);
718 /* Repeating a while is simple */
719 if (whyles->w_fename == 0) {
720 bseek(&whyles->w_start);
724 * The foreach variable list actually has a spurious word ")" at the end of
725 * the w_fe list. Thus we are at the of the list if one word beyond this
728 if (!whyles->w_fe[1]) {
732 set(whyles->w_fename, quote(Strsave(*whyles->w_fe++)), VAR_READWRITE);
733 bseek(&whyles->w_start);
750 } while (v[0] != NULL && Strcmp(v[0], STRrepeat) == 0);
754 omask = sigblock(sigmask(SIGINT)) & ~sigmask(SIGINT);
756 (void) sighold(SIGINT);
761 (void) sigsetmask(omask);
763 (void) sigrelse (SIGINT);
771 (void) sigsetmask(omask);
773 (void) sigrelse (SIGINT);
785 search(TC_BRKSW, 0, NULL);
792 struct srch *sp, *sp1, *sp2;
796 * Ignore keywords inside heredocs
802 * Binary search Sp1 is the beginning of the current search range. Sp2 is
805 for (sp1 = srchn, sp2 = srchn + nsrchn; sp1 < sp2;) {
806 sp = sp1 + ((sp2 - sp1) >> 1);
807 if ((i = *cp - *sp->s_name) == 0 &&
808 (i = Strcmp(cp, str2short(sp->s_name))) == 0)
822 struct srch *sp, *sp2;
824 for (sp = srchn, sp2 = srchn + nsrchn; sp < sp2; sp++)
825 if (sp->s_value == n)
835 search(type, level, goal)
840 Char wordbuf[BUFSIZE];
841 Char *aword = wordbuf;
848 if (type == TC_GOTO) {
850 a.type = TCSH_F_SEEK;
855 if (intty && fseekp == feobp && aret == TCSH_F_SEEK)
856 printprompt(1, isrchx(type == TC_BREAK ? zlast : type));
857 /* xprintf("? "), flush(); */
859 (void) getword(aword);
860 switch (srchx(aword)) {
863 if (level == 0 && type == TC_IF)
868 while (getword(aword))
870 if ((type == TC_IF || type == TC_ELSE) &&
876 if (type == TC_IF || type == TC_ELSE)
883 if (type == TC_BREAK)
888 if (type == TC_BRKSW) {
897 if (type == TC_BREAK)
903 if (type == TC_SWITCH || type == TC_BRKSW)
908 if (type == TC_SWITCH || type == TC_BRKSW)
913 if (type == TC_GOTO && getword(aword) && eq(aword, goal))
918 if (type != TC_GOTO && (type != TC_SWITCH || level != 0))
920 if (lastchr(aword) != ':')
922 aword[Strlen(aword) - 1] = 0;
923 if ((type == TC_GOTO && eq(aword, goal)) ||
924 (type == TC_SWITCH && eq(aword, STRdefault)))
929 if (type != TC_SWITCH || level != 0)
931 (void) getword(aword);
932 if (lastchr(aword) == ':')
933 aword[Strlen(aword) - 1] = 0;
934 cp = strip(Dfix1(aword));
935 if (Gmatch(goal, cp))
941 if (type == TC_SWITCH && level == 0)
945 (void) getword(NULL);
946 } while (level >= 0);
953 int found = 0, first;
959 while (c == ' ' || c == '\t')
964 while (c != CHAR_ERR && c != '\n');
977 if (c == '\\' && (c = readc(1)) == '\n')
979 if (c == '\'' || c == '"') {
991 if (!first && !d && c == '(') {
1001 } while ((d || (c != ' ' && c != '\t')) && c != '\n');
1014 stderror(ERR_NAME | ERR_NOTFOUND, "then/endif");
1018 stderror(ERR_NAME | ERR_NOTFOUND, "endif");
1023 stderror(ERR_NAME | ERR_NOTFOUND, "endsw");
1027 stderror(ERR_NAME | ERR_NOTFOUND, "end");
1031 setname(short2str(Sgoal));
1032 stderror(ERR_NAME | ERR_NOTFOUND, "label");
1045 if (whyles->w_end.type == TCSH_F_SEEK && whyles->w_end.f_seek == 0) {
1046 search(TC_BREAK, 0, NULL);
1047 btell(&whyles->w_end);
1048 whyles->w_end.f_seek--;
1051 bseek(&whyles->w_end);
1063 xfree((ptr_t) wp->w_fename);
1073 nwp = NULL; /* sun lint is dumb! */
1077 static char foo[] = "IAFE";
1083 xprintf("o->type %c o->a_seek %d o->f_seek %d\n",
1084 foo[o.type + 1], o.a_seek, o.f_seek);
1087 for (; whyles; whyles = nwp) {
1088 struct whyle *wp = whyles;
1092 xprintf("start->type %c start->a_seek %d start->f_seek %d\n",
1093 foo[wp->w_start.type+1],
1094 wp->w_start.a_seek, wp->w_start.f_seek);
1095 xprintf("end->type %c end->a_seek %d end->f_seek %d\n",
1096 foo[wp->w_end.type + 1], wp->w_end.a_seek, wp->w_end.f_seek);
1100 * XXX: We free loops that have different seek types.
1102 if (wp->w_end.type != TCSH_I_SEEK && wp->w_start.type == wp->w_end.type &&
1103 wp->w_start.type == o.type) {
1104 if (wp->w_end.type == TCSH_F_SEEK) {
1105 if (o.f_seek >= wp->w_start.f_seek &&
1106 (wp->w_end.f_seek == 0 || o.f_seek < wp->w_end.f_seek))
1110 if (o.a_seek >= wp->w_start.a_seek &&
1111 (wp->w_end.a_seek == 0 || o.a_seek < wp->w_end.a_seek))
1149 int echo_style = ECHO_STYLE;
1150 #else /* !ECHO_STYLE */
1152 int echo_style = SYSV_ECHO;
1153 # else /* SYSVREL == 0 */
1154 int echo_style = BSD_ECHO;
1155 # endif /* SYSVREL */
1156 #endif /* ECHO_STYLE */
1159 if ((vp = adrof(STRecho_style)) != NULL && vp->vec != NULL &&
1160 vp->vec[0] != NULL) {
1161 if (Strcmp(vp->vec[0], STRbsd) == 0)
1162 echo_style = BSD_ECHO;
1163 else if (Strcmp(vp->vec[0], STRsysv) == 0)
1164 echo_style = SYSV_ECHO;
1165 else if (Strcmp(vp->vec[0], STRboth) == 0)
1166 echo_style = BOTH_ECHO;
1167 else if (Strcmp(vp->vec[0], STRnone) == 0)
1168 echo_style = NONE_ECHO;
1173 (void) sigsetmask(sigblock((sigmask_t) 0) & ~sigmask(SIGINT));
1174 #else /* !BSDSIGS */
1175 (void) sigrelse (SIGINT);
1176 #endif /* BSDSIGS */
1180 gflag = 0, tglob(v);
1184 stderror(ERR_NAME | ERR_NOMATCH);
1187 v = gargv = saveblk(v);
1191 if ((echo_style & BSD_ECHO) != 0 && sep == ' ' && *v && eq(*v, STRmn))
1194 while ((cp = *v++) != 0) {
1197 while ((c = *cp++) != 0) {
1198 if ((echo_style & SYSV_ECHO) != 0 && c == '\\') {
1199 switch (c = *cp++) {
1210 #if 0 /* Windows does not understand \e */
1236 if (*cp >= '0' && *cp < '8')
1237 c = c * 8 + *cp++ - '0';
1238 if (*cp >= '0' && *cp < '8')
1239 c = c * 8 + *cp++ - '0';
1240 if (*cp >= '0' && *cp < '8')
1241 c = c * 8 + *cp++ - '0';
1248 xputchar('\\' | QUOTE);
1252 xputwchar(c | QUOTE);
1256 xputchar(sep | QUOTE);
1259 if (sep && nonl == 0)
1265 (void) sigblock(sigmask(SIGINT));
1266 #else /* !BSDSIGS */
1267 (void) sighold(SIGINT);
1268 #endif /* BSDSIGS */
1270 blkfree(gargv), gargv = 0;
1273 /* check whether an environment variable should invoke 'set_locale()' */
1278 static Char *locale_vars[] = {
1279 STRLANG, STRLC_ALL, STRLC_CTYPE, STRLC_NUMERIC,
1280 STRLC_TIME, STRLC_COLLATE, STRLC_MESSAGES, STRLC_MONETARY, 0
1284 for (v = locale_vars; *v; ++v)
1301 (void) sigsetmask(sigblock((sigmask_t) 0) & ~sigmask(SIGINT));
1302 #else /* !BSDSIGS */
1303 (void) sigrelse (SIGINT);
1304 #endif /* BSDSIGS */
1311 for (ep = STR_environ; *ep; ep++)
1312 xprintf("%S\n", *ep);
1315 else if ((e = tgetenv(*v)) != NULL) {
1321 set(STRstatus, Strsave(STR1), VAR_READWRITE);
1324 /* from "Karl Berry." <karl%mote.umb.edu@relay.cs.net> -- for NeXT things
1325 (and anything else with a modern compiler) */
1345 for (; *lp != '\0' ; lp++) {
1347 stderror(ERR_NAME | ERR_SYNTAX);
1349 if ((lp = *v++) == 0)
1352 tsetenv(vp, lp = globone(lp, G_APPEND));
1353 if (eq(vp, STRKPATH)) {
1361 if (eq(vp, STRSYSTYPE)) {
1368 /* dspkanji/dspmbyte autosetting */
1369 /* PATCH IDEA FROM Issei.Suzuki VERY THANKS */
1370 #if defined(DSPMBYTE)
1371 if(eq(vp, STRLANG) && !adrof(CHECK_MBYTEVAR)) {
1372 autoset_dspmbyte(lp);
1376 if (islocale_var(vp)) {
1380 # ifdef SETLOCALEBUG
1382 # endif /* SETLOCALEBUG */
1383 (void) setlocale(LC_ALL, "");
1385 (void) setlocale(LC_COLLATE, "");
1388 (void) setlocale(LC_CTYPE, ""); /* for iscntrl */
1389 # endif /* LC_CTYPE */
1390 # ifdef NLS_CATALOGS
1392 (void) setlocale(LC_MESSAGES, "");
1393 # endif /* LC_MESSAGES */
1396 # endif /* NLS_CATALOGS */
1397 # ifdef SETLOCALEBUG
1399 # endif /* SETLOCALEBUG */
1402 # endif /* STRCOLLBUG */
1403 tw_cmd_free(); /* since the collation sequence has changed */
1404 for (k = 0200; k <= 0377 && !Isprint(k); k++)
1406 AsciiOnly = MB_CUR_MAX == 1 && k > 0377;
1410 NLSMapsAreInited = 0;
1412 if (MapsAreInited && !NLSMapsAreInited)
1419 if (eq(vp, STRNLSPATH)) {
1425 if (eq(vp, STRNOREBIND)) {
1428 NLSMapsAreInited = 0;
1434 if (eq(vp, STRtcshlang)) {
1439 #endif /* WINNT_NATIVE */
1440 if (eq(vp, STRKTERM)) {
1442 set(STRterm, quote(lp), VAR_READWRITE); /* lp memory used here */
1444 if (noediting && strcmp(t, "unknown") != 0 && strcmp(t,"dumb") != 0) {
1447 set(STRedit, Strsave(STRNULL), VAR_READWRITE);
1454 if (eq(vp, STRKHOME)) {
1456 * convert to canonical pathname (possibly resolving symlinks)
1458 lp = dcanon(lp, lp);
1459 set(STRhome, quote(lp), VAR_READWRITE); /* cp memory used here */
1461 /* fix directory stack for new tilde home */
1466 if (eq(vp, STRKSHLVL)) {
1467 /* lp memory used here */
1468 set(STRshlvl, quote(lp), VAR_READWRITE);
1472 if (eq(vp, STRKUSER)) {
1473 set(STRuser, quote(lp), VAR_READWRITE); /* lp memory used here */
1477 if (eq(vp, STRKGROUP)) {
1478 set(STRgroup, quote(lp), VAR_READWRITE); /* lp memory used here */
1483 if (eq(vp, STRLS_COLORS)) {
1487 #endif /* COLOR_LS_F */
1491 * Load/Update $LINES $COLUMNS
1493 if ((eq(lp, STRNULL) && (eq(vp, STRLINES) || eq(vp, STRCOLUMNS))) ||
1494 eq(vp, STRTERMCAP)) {
1496 check_window_size(1);
1501 * Change the size to the one directed by $LINES and $COLUMNS
1503 if (eq(vp, STRLINES) || eq(vp, STRCOLUMNS)) {
1511 #endif /* SIG_WINDOW */
1523 static Char *name = NULL;
1527 xfree((ptr_t) name);
1529 * Find the longest environment variable
1531 for (maxi = 0, ep = STR_environ; *ep; ep++) {
1532 for (i = 0, p = *ep; *p && *p != '='; p++, i++)
1538 name = (Char *) xmalloc((size_t) ((maxi + 1) * sizeof(Char)));
1541 for (maxi = 1; maxi;)
1542 for (maxi = 0, ep = STR_environ; *ep; ep++) {
1543 for (n = name, p = *ep; *p && *p != '='; *n++ = *p++)
1546 if (!Gmatch(name, *v))
1550 /* Unset the name. This wasn't being done until
1551 * later but most of the stuff following won't
1552 * work (particularly the setlocale() and getenv()
1553 * stuff) as intended until the name is actually
1558 if (eq(name, STRNOREBIND)) {
1561 NLSMapsAreInited = 0;
1565 else if (eq(name, STRSYSTYPE))
1568 else if (islocale_var(name)) {
1572 # ifdef SETLOCALEBUG
1574 # endif /* SETLOCALEBUG */
1575 (void) setlocale(LC_ALL, "");
1577 (void) setlocale(LC_COLLATE, "");
1580 (void) setlocale(LC_CTYPE, ""); /* for iscntrl */
1581 # endif /* LC_CTYPE */
1582 # ifdef NLS_CATALOGS
1584 (void) setlocale(LC_MESSAGES, "");
1585 # endif /* LC_MESSAGES */
1588 # endif /* NLS_CATALOGS */
1589 # ifdef SETLOCALEBUG
1591 # endif /* SETLOCALEBUG */
1594 # endif /* STRCOLLBUG */
1595 tw_cmd_free();/* since the collation sequence has changed */
1596 for (k = 0200; k <= 0377 && !Isprint(k); k++)
1598 AsciiOnly = MB_CUR_MAX == 1 && k > 0377;
1600 AsciiOnly = getenv("LANG") == NULL &&
1601 getenv("LC_CTYPE") == NULL;
1603 NLSMapsAreInited = 0;
1605 if (MapsAreInited && !NLSMapsAreInited)
1610 else if (eq(name,(STRtcshlang))) {
1614 #endif /* WINNT_NATIVE */
1616 else if (eq(name, STRLS_COLORS))
1618 #endif /* COLOR_LS_F */
1620 else if (eq(name, STRNLSPATH)) {
1626 * start again cause the environment changes
1630 xfree((ptr_t) name); name = NULL;
1635 const Char *name, *val;
1637 #ifdef SETENV_IN_LIB
1639 * XXX: This does not work right, since tcsh cannot track changes to
1640 * the environment this way. (the builtin setenv without arguments does
1641 * not print the right stuff neither does unsetenv). This was for Mach,
1642 * it is not needed anymore.
1645 char nameBuf[BUFSIZE];
1646 char *cname = short2str(name);
1650 (void) strcpy(nameBuf, cname);
1651 setenv(nameBuf, short2str(val), 1);
1652 #else /* !SETENV_IN_LIB */
1653 Char **ep = STR_environ;
1660 nt_set_env(name,val);
1661 #endif /* WINNT_NATIVE */
1664 for (ccp = name, dp = *ep; *ccp && Tolower(*ccp & TRIM) == Tolower(*dp);
1667 for (ccp = name, dp = *ep; *ccp && (*ccp & TRIM) == *dp; ccp++, dp++)
1668 #endif /* WINNT_NATIVE */
1670 if (*ccp != 0 || *dp != '=')
1672 cp = Strspl(STRequal, val);
1673 xfree((ptr_t) * ep);
1674 *ep = strip(Strspl(name, cp));
1676 blkfree((Char **) environ);
1677 environ = short2blk(STR_environ);
1680 cp = Strspl(name, STRequal);
1681 blk[0] = strip(Strspl(cp, val));
1684 STR_environ = blkspl(STR_environ, blk);
1685 blkfree((Char **) environ);
1686 environ = short2blk(STR_environ);
1688 #endif /* SETENV_IN_LIB */
1695 Char **ep = STR_environ;
1700 nt_set_env(name,NULL);
1701 #endif /*WINNT_NATIVE */
1703 for (cp = name, dp = *ep; *cp && *cp == *dp; cp++, dp++)
1705 if (*cp != 0 || *dp != '=')
1709 STR_environ = blkspl(STR_environ, ep + 1);
1710 blkfree((Char **) environ);
1711 environ = short2blk(STR_environ);
1736 while (Isdigit(*cp) && *cp != '8' && *cp != '9')
1737 i = i * 8 + *cp++ - '0';
1738 if (*cp || i < 0 || i > 0777)
1739 stderror(ERR_NAME | ERR_MASK);
1745 typedef long RLIM_TYPE;
1746 # ifdef _OSD_POSIX /* BS2000 */
1747 # include <ulimit.h>
1749 # ifndef RLIM_INFINITY
1750 # if !defined(_MINIX) && !defined(__clipper__) && !defined(_CRAY)
1751 extern RLIM_TYPE ulimit();
1752 # endif /* ! _MINIX && !__clipper__ */
1753 # define RLIM_INFINITY 0x003fffff
1754 # define RLIMIT_FSIZE 1
1755 # endif /* RLIM_INFINITY */
1757 # define toset(a) (((a) == 3) ? 1004 : (a) + 1)
1758 # define RLIMIT_DATA 3
1759 # define RLIMIT_STACK 1005
1761 # define toset(a) ((a) + 1)
1763 # else /* BSDLIMIT */
1764 # if (defined(BSD4_4) || defined(__linux__) || defined(__GNU__) || defined(__GLIBC__) || (HPUXVERSION >= 1100)) && !defined(__386BSD__)
1765 typedef rlim_t RLIM_TYPE;
1767 # if defined(SOLARIS2) || (defined(sgi) && SYSVREL > 3)
1768 typedef rlim_t RLIM_TYPE;
1771 typedef long long RLIM_TYPE;
1773 typedef unsigned long RLIM_TYPE;
1775 # endif /* SOLARIS2 || (sgi && SYSVREL > 3) */
1776 # endif /* BSD4_4 && !__386BSD__ */
1777 # endif /* BSDLIMIT */
1779 # if (HPUXVERSION > 700) && (HPUXVERSION < 1100) && defined(BSDLIMIT)
1780 /* Yes hpux8.0 has limits but <sys/resource.h> does not make them public */
1781 /* Yes, we could have defined _KERNEL, and -I/etc/conf/h, but is that better? */
1783 # define RLIMIT_CPU 0
1784 # define RLIMIT_FSIZE 1
1785 # define RLIMIT_DATA 2
1786 # define RLIMIT_STACK 3
1787 # define RLIMIT_CORE 4
1788 # define RLIMIT_RSS 5
1789 # define RLIMIT_NOFILE 6
1790 # endif /* RLIMIT_CPU */
1791 # ifndef RLIM_INFINITY
1792 # define RLIM_INFINITY 0x7fffffff
1793 # endif /* RLIM_INFINITY */
1795 * old versions of HP/UX counted limits in 512 bytes
1798 # define FILESIZE512
1799 # endif /* SIGRTMIN */
1800 # endif /* (HPUXVERSION > 700) && (HPUXVERSION < 1100) && BSDLIMIT */
1802 # if SYSVREL > 3 && defined(BSDLIMIT) && !defined(_SX)
1803 /* In order to use rusage, we included "/usr/ucbinclude/sys/resource.h" in */
1804 /* sh.h. However, some SVR4 limits are defined in <sys/resource.h>. Rather */
1805 /* than include both and get warnings, we define the extra SVR4 limits here. */
1806 /* XXX: I don't understand if RLIMIT_AS is defined, why don't we define */
1807 /* RLIMIT_VMEM based on it? */
1808 # ifndef RLIMIT_VMEM
1809 # define RLIMIT_VMEM 6
1812 # define RLIMIT_AS RLIMIT_VMEM
1814 # endif /* SYSVREL > 3 && BSDLIMIT */
1816 # if (defined(__linux__) || defined(__GNU__) || defined(__GLIBC__)) && defined(RLIMIT_AS) && !defined(RLIMIT_VMEM)
1817 # define RLIMIT_VMEM RLIMIT_AS
1820 struct limits limits[] =
1823 { RLIMIT_CPU, "cputime", 1, "seconds" },
1824 # endif /* RLIMIT_CPU */
1826 # ifdef RLIMIT_FSIZE
1828 { RLIMIT_FSIZE, "filesize", 1024, "kbytes" },
1830 { RLIMIT_FSIZE, "filesize", 512, "blocks" },
1832 # endif /* RLIMIT_FSIZE */
1835 { RLIMIT_DATA, "datasize", 1024, "kbytes" },
1836 # endif /* RLIMIT_DATA */
1838 # ifdef RLIMIT_STACK
1840 { RLIMIT_STACK, "stacksize", 1024, "kbytes" },
1842 { RLIMIT_STACK, "stacksize", 1024 * 1024, "kbytes"},
1844 # endif /* RLIMIT_STACK */
1847 { RLIMIT_CORE, "coredumpsize", 1024, "kbytes" },
1848 # endif /* RLIMIT_CORE */
1851 { RLIMIT_RSS, "memoryuse", 1024, "kbytes" },
1852 # endif /* RLIMIT_RSS */
1855 { RLIMIT_UMEM, "memoryuse", 1024, "kbytes" },
1856 # endif /* RLIMIT_UMEM */
1859 { RLIMIT_VMEM, "vmemoryuse", 1024, "kbytes" },
1860 # endif /* RLIMIT_VMEM */
1862 # if defined(RLIMIT_HEAP) /* found on BS2000/OSD systems */
1863 { RLIMIT_HEAP, "heapsize", 1024, "kbytes" },
1864 # endif /* RLIMIT_HEAP */
1866 # ifdef RLIMIT_NOFILE
1867 { RLIMIT_NOFILE, "descriptors", 1, "" },
1868 # endif /* RLIMIT_NOFILE */
1870 # ifdef RLIMIT_CONCUR
1871 { RLIMIT_CONCUR, "concurrency", 1, "thread(s)" },
1872 # endif /* RLIMIT_CONCUR */
1874 # ifdef RLIMIT_MEMLOCK
1875 { RLIMIT_MEMLOCK, "memorylocked", 1024, "kbytes" },
1876 # endif /* RLIMIT_MEMLOCK */
1878 # ifdef RLIMIT_NPROC
1879 { RLIMIT_NPROC, "maxproc", 1, "" },
1880 # endif /* RLIMIT_NPROC */
1882 # if defined(RLIMIT_OFILE) && !defined(RLIMIT_NOFILE)
1883 { RLIMIT_OFILE, "openfiles", 1, "" },
1884 # endif /* RLIMIT_OFILE && !defined(RLIMIT_NOFILE) */
1886 # ifdef RLIMIT_SBSIZE
1887 { RLIMIT_SBSIZE, "sbsize", 1, "" },
1888 # endif /* RLIMIT_SBSIZE */
1890 { -1, NULL, 0, NULL }
1893 static struct limits *findlim __P((Char *));
1894 static RLIM_TYPE getval __P((struct limits *, Char **));
1895 static void limtail __P((Char *, const char *));
1896 static void plim __P((struct limits *, int));
1897 static int setlim __P((struct limits *, int, RLIM_TYPE));
1901 restrict_limit(value)
1905 * is f too large to cope with? return the maximum or minimum int
1907 if (value > (double) INT_MAX)
1908 return (RLIM_TYPE) INT_MAX;
1909 else if (value < (double) INT_MIN)
1910 return (RLIM_TYPE) INT_MIN;
1912 return (RLIM_TYPE) value;
1915 # define restrict_limit(x) ((RLIM_TYPE) (x))
1919 static struct limits *
1923 struct limits *lp, *res;
1925 res = (struct limits *) NULL;
1926 for (lp = limits; lp->limconst >= 0; lp++)
1927 if (prefix(cp, str2short(lp->limname))) {
1929 stderror(ERR_NAME | ERR_AMBIG);
1934 stderror(ERR_NAME | ERR_LIMIT);
1951 if (*v && eq(*v, STRmh)) {
1956 for (lp = limits; lp->limconst >= 0; lp++)
1965 limit = getval(lp, v + 1);
1966 if (setlim(lp, hard, limit) < 0)
1967 stderror(ERR_SILENT);
1978 f = atof(short2str(cp));
1982 * is f too large to cope with. limit f to minint, maxint - X-6768 by
1985 if ((f < (double) INT_MIN) || (f > (double) INT_MAX)) {
1986 stderror(ERR_NAME | ERR_TOOLARGE);
1988 # endif /* convex */
1990 while (Isdigit(*cp) || *cp == '.' || *cp == 'e' || *cp == 'E')
1994 return restrict_limit((f * lp->limdiv) + 0.5);
2000 if (lp->limconst != RLIMIT_CPU)
2002 return f == 0.0 ? (RLIM_TYPE) 0 : restrict_limit((f * 60.0 + atof(short2str(cp + 1))));
2004 if (lp->limconst != RLIMIT_CPU)
2006 limtail(cp, "hours");
2010 if (lp->limconst == RLIMIT_CPU) {
2011 limtail(cp, "minutes");
2016 limtail(cp, "megabytes");
2017 f *= 1024.0 * 1024.0;
2020 if (lp->limconst != RLIMIT_CPU)
2022 limtail(cp, "seconds");
2024 # endif /* RLIMIT_CPU */
2027 if (lp->limconst == RLIMIT_CPU)
2029 # endif /* RLIMIT_CPU */
2031 limtail(cp, "megabytes");
2032 f *= 1024.0 * 1024.0;
2036 if (lp->limconst == RLIMIT_CPU)
2038 # endif /* RLIMIT_CPU */
2039 limtail(cp, "kbytes");
2044 if (lp->limconst == RLIMIT_CPU)
2046 # endif /* RLIMIT_CPU */
2047 limtail(cp, "blocks");
2051 limtail(cp, "unlimited");
2052 return ((RLIM_TYPE) RLIM_INFINITY);
2056 # endif /* RLIMIT_CPU */
2057 stderror(ERR_NAME | ERR_SCALEF);
2060 return f == 0.0 ? (RLIM_TYPE) 0 : restrict_limit((f + 0.5));
2063 if (f > (float) RLIM_INFINITY)
2064 return ((RLIM_TYPE) RLIM_INFINITY);
2066 return ((RLIM_TYPE) f);
2067 # endif /* convex */
2078 while (*cp && *cp == (Char)*str)
2081 stderror(ERR_BADSCALE, sp);
2093 # endif /* BSDLIMIT */
2095 int xdiv = lp->limdiv;
2097 xprintf("%-13.13s", lp->limname);
2100 limit = ulimit(lp->limconst, 0);
2102 if (lp->limconst == RLIMIT_DATA)
2103 limit -= 0x20000000;
2105 # else /* BSDLIMIT */
2106 (void) getrlimit(lp->limconst, &rlim);
2107 limit = hard ? rlim.rlim_max : rlim.rlim_cur;
2108 # endif /* BSDLIMIT */
2110 # if !defined(BSDLIMIT) || defined(FILESIZE512)
2112 * Christos: filesize comes in 512 blocks. we divide by 2 to get 1024
2113 * blocks. Note we cannot pre-multiply cause we might overflow (A/UX)
2115 if (lp->limconst == RLIMIT_FSIZE) {
2116 if (limit >= (RLIM_INFINITY / 512))
2117 limit = RLIM_INFINITY;
2119 xdiv = (xdiv == 1024 ? 2 : 1);
2121 # endif /* !BSDLIMIT || FILESIZE512 */
2123 if (limit == RLIM_INFINITY)
2124 xprintf("unlimited");
2126 # if defined(RLIMIT_CPU) && defined(_OSD_POSIX)
2127 if (lp->limconst == RLIMIT_CPU &&
2128 (unsigned long)limit >= 0x7ffffffdUL)
2129 xprintf("unlimited");
2133 if (lp->limconst == RLIMIT_CPU)
2134 psecs((long) limit);
2136 # endif /* RLIMIT_CPU */
2137 xprintf("%ld %s", (long) (limit / xdiv), lp->limscale);
2153 while (*++v && **v == '-') {
2164 stderror(ERR_ULIMUS);
2170 for (lp = limits; lp->limconst >= 0; lp++)
2171 if (setlim(lp, hard, (RLIM_TYPE) RLIM_INFINITY) < 0)
2174 stderror(ERR_SILENT);
2179 if (setlim(lp, hard, (RLIM_TYPE) RLIM_INFINITY) < 0 && !force)
2180 stderror(ERR_SILENT);
2185 setlim(lp, hard, limit)
2193 (void) getrlimit(lp->limconst, &rlim);
2196 /* Even though hpux has setrlimit(), it expects fsize in 512 byte blocks */
2197 if (limit != RLIM_INFINITY && lp->limconst == RLIMIT_FSIZE)
2199 # endif /* FILESIZE512 */
2201 rlim.rlim_max = limit;
2202 else if (limit == RLIM_INFINITY && euid != 0)
2203 rlim.rlim_cur = rlim.rlim_max;
2205 rlim.rlim_cur = limit;
2207 if (rlim.rlim_cur > rlim.rlim_max)
2208 rlim.rlim_max = rlim.rlim_cur;
2210 if (setrlimit(lp->limconst, &rlim) < 0) {
2211 # else /* BSDLIMIT */
2212 if (limit != RLIM_INFINITY && lp->limconst == RLIMIT_FSIZE)
2215 if (lp->limconst == RLIMIT_DATA)
2216 limit += 0x20000000;
2218 if (ulimit(toset(lp->limconst), limit) < 0) {
2219 # endif /* BSDLIMIT */
2224 op = strsave(limit == RLIM_INFINITY ? CGETS(15, 2, "remove") :
2225 CGETS(15, 3, "set"));
2226 type = strsave(hard ? CGETS(15, 4, " hard") : "");
2227 xprintf(CGETS(15, 1, "%s: %s: Can't %s%s limit (%s)\n"), bname,
2228 lp->limname, op, type, strerror(err));
2236 #endif /* !HAVENOLIMIT */
2248 #endif /* BSDJOBS */
2254 stderror(ERR_SUSPLOG);
2258 old = signal(SIGTSTP, SIG_DFL);
2259 (void) kill(0, SIGTSTP);
2260 /* the shell stops here */
2261 (void) signal(SIGTSTP, old);
2262 #else /* !BSDJOBS */
2263 stderror(ERR_JOBCONTROL);
2264 #endif /* BSDJOBS */
2269 ctpgrp = tcgetpgrp(FSHTTY);
2271 stderror(ERR_SYSTEM, "tcgetpgrp", strerror(errno));
2272 if (ctpgrp != opgrp) {
2273 old = signal(SIGTTIN, SIG_DFL);
2274 (void) kill(0, SIGTTIN);
2275 (void) signal(SIGTTIN, old);
2278 (void) setpgid(0, shpgrp);
2279 (void) tcsetpgrp(FSHTTY, shpgrp);
2281 #endif /* BSDJOBS */
2282 (void) setdisc(FSHTTY);
2285 /* This is the dreaded EVAL built-in.
2286 * If you don't fiddle with file descriptors, and reset didfds,
2287 * this command will either ignore redirection inside or outside
2288 * its arguments, e.g. eval "date >x" vs. eval "date" >x
2289 * The stuff here seems to work, but I did it by trial and error rather
2290 * than really knowing what was going on. If tpgrp is zero, we are
2291 * probably a background eval, e.g. "eval date &", and we want to
2292 * make sure that any processes we start stay in our pgrp.
2293 * This is also the case for "time eval date" -- stay in same pgrp.
2294 * Otherwise, under stty tostop, processes will stop in the wrong
2295 * pgrp, with no way for the shell to get them going again. -IAN!
2298 static Char **gv = NULL, **gav = NULL;
2309 #ifndef CLOSE_ON_EXEC
2311 #endif /* CLOSE_ON_EXEC */
2315 int saveIN, saveOUT, saveDIAG;
2316 int oSHIN, oSHOUT, oSHDIAG;
2322 #ifndef CLOSE_ON_EXEC
2324 #endif /* CLOSE_ON_EXEC */
2335 gflag = 0, tglob(gav);
2337 gv = gav = globall(gav);
2340 stderror(ERR_NOMATCH);
2349 (void)close_on_exec(saveIN = dcopy(SHIN, -1), 1);
2350 (void)close_on_exec(saveOUT = dcopy(SHOUT, -1), 1);
2351 (void)close_on_exec(saveDIAG = dcopy(SHDIAG, -1), 1);
2355 /* PWP: setjmp/longjmp bugfix for optimizing compilers */
2357 my_reenter = 1; /* assume non-zero return val */
2358 if (setexit() == 0) {
2359 my_reenter = 0; /* Oh well, we were wrong */
2361 if ((my_reenter = setexit()) == 0) {
2365 (void)close_on_exec(SHIN = dcopy(0, -1), 1);
2366 (void)close_on_exec(SHOUT = dcopy(1, -1), 1);
2367 (void)close_on_exec(SHDIAG = dcopy(2, -1), 1);
2368 #ifndef CLOSE_ON_EXEC
2370 #endif /* CLOSE_ON_EXEC */
2378 #ifndef CLOSE_ON_EXEC
2380 #endif /* CLOSE_ON_EXEC */
2383 (void) close(SHOUT);
2384 (void) close(SHDIAG);
2385 (void)close_on_exec (SHIN = dmove(saveIN, oSHIN), 1);
2386 (void)close_on_exec (SHOUT = dmove(saveOUT, oSHOUT), 1);
2387 (void)close_on_exec (SHDIAG = dmove(saveDIAG, oSHDIAG), 1);
2395 stderror(ERR_SILENT);
2398 /*************************************************************************/
2399 /* print list of builtin commands */
2407 /* would use print_by_column() in tw.parse.c but that assumes
2408 * we have an array of Char * to pass.. (sg)
2411 int row, col, columns, rows;
2412 unsigned int w, maxwidth;
2416 lbuffed = 0; /* turn off line buffering */
2418 /* find widest string */
2419 for (maxwidth = 0, b = bfunc; b < &bfunc[nbfunc]; ++b)
2420 maxwidth = max(maxwidth, strlen(b->bname));
2421 ++maxwidth; /* for space */
2423 columns = (TermH + 1) / maxwidth; /* PWP: terminal size change */
2426 rows = (nbfunc + (columns - 1)) / columns;
2428 for (b = bfunc, row = 0; row < rows; row++) {
2429 for (col = 0; col < columns; col++) {
2430 if (b < &bfunc[nbfunc]) {
2431 w = strlen(b->bname);
2432 xprintf("%s", b->bname);
2433 if (col < (columns - 1)) /* Not last column? */
2434 for (; w < maxwidth; w++)
2439 if (row < (rows - 1)) {
2446 nt_print_builtins(maxwidth);
2451 #endif /* WINNT_NATIVE */
2453 lbuffed = 1; /* turn back on line buffering */
2460 iconv_catgets(ctd, set_id, msg_id, s)
2465 static char *buf = NULL;
2466 static size_t buf_size = 0;
2468 char *orig, *dest, *p;
2474 size_t src_size, dest_size;
2476 orig = catgets(ctd, set_id, msg_id, s);
2477 if (catgets_iconv == (iconv_t)-1 || orig == s)
2480 src_size = strlen(src) + 1;
2481 if (buf == NULL && (buf = xmalloc(buf_size = src_size + 32)) == NULL)
2484 while (src_size != 0) {
2485 dest_size = buf + buf_size - dest;
2486 if (iconv(catgets_iconv, &src, &src_size, &dest, &dest_size)
2490 if ((p = xrealloc(buf, buf_size * 2)) == NULL)
2493 dest = p + (dest - buf);
2497 case EILSEQ: case EINVAL: default:
2511 char catalog[ 256 ] = { 't', 'c', 's', 'h', '\0' };
2513 if (adrof(STRcatalog) != NULL)
2514 xsnprintf((char *)catalog, sizeof(catalog), "tcsh.%s",
2515 short2str(varval(STRcatalog)));
2516 catd = catopen(catalog, MCLoadBySet);
2518 /* catgets (), not CGETS, the charset name should be in ASCII anyway. */
2519 catgets_iconv = iconv_open (nl_langinfo (CODESET),
2520 catgets(catd, 255, 1, "ASCII"));
2521 #endif /* HAVE_ICONV */
2522 #endif /* NLS_CATALOGS */
2525 #endif /* WINNT_NATIVE */
2526 errinit(); /* init the errorlist in correct locale */
2527 mesginit(); /* init the messages for signals */
2528 dateinit(); /* init the messages for dates */
2529 editinit(); /* init the editor messages */
2530 terminit(); /* init the termcap messages */
2538 if (catgets_iconv != (iconv_t)-1) {
2539 iconv_close(catgets_iconv);
2540 catgets_iconv = (iconv_t)-1;
2542 #endif /* HAVE_ICONV */
2544 #endif /* NLS_CATALOGS */