2 * Copyright (c) 1980, 1991, 1993
3 * The Regents of the University of California. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. 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
37 static char sccsid[] = "@(#)func.c 8.1 (Berkeley) 5/31/93";
40 #include <sys/types.h>
55 #include "pathnames.h"
57 extern char **environ;
59 static int zlast = -1;
60 static void islogin __P((void));
61 static void reexecute __P((struct command *));
62 static void preread __P((void));
63 static void doagain __P((void));
64 static void search __P((int, int, Char *));
65 static int getword __P((Char *));
66 static int keyword __P((Char *));
67 static void toend __P((void));
68 static void xecho __P((int, Char **));
69 static void Unsetenv __P((Char *));
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};
81 if (lastchr(cp) == ':') {
82 label.bname = short2str(cp);
86 if (t->t_dflg & F_AMPERSAND) {
87 t->t_dflg &= ~F_AMPERSAND;
88 backgnd.bname = short2str(cp);
91 foregnd.bname = short2str(cp);
95 * Binary search Bp1 is the beginning of the current search range. Bp2 is
98 for (bp1 = bfunc, bp2 = bfunc + nbfunc; bp1 < bp2;) {
101 bp = bp1 + ((bp2 - bp1) >> 1);
102 if ((i = *cp - *bp->bname) == 0 &&
103 (i = Strcmp(cp, str2short(bp->bname))) == 0)
115 register struct command *t;
116 register struct biltins *bp;
122 i = blklen(t->t_dcom) - 1;
124 stderror(ERR_NAME | ERR_TOOFEW);
126 stderror(ERR_NAME | ERR_TOOMANY);
127 (*bp->bfunct) (t->t_dcom, t);
137 register Char *vv = v[1];
139 if (parintr == SIG_IGN)
141 if (setintr && intty)
142 stderror(ERR_NAME | ERR_TERMINAL);
148 (void) sigblock(sigmask(SIGINT));
150 (void) signal(SIGINT, SIG_DFL);
153 else if (eq((vv = strip(vv)), STRminus)) {
154 (void) signal(SIGINT, SIG_IGN);
155 gointr = Strsave(STRminus);
158 gointr = Strsave(vv);
159 (void) signal(SIGINT, pintr);
170 stderror(ERR_NAME | ERR_TERMINAL);
172 (void) signal(SIGHUP, SIG_IGN);
197 register struct varent *vp;
205 vp = adrof1(strip(p), &aliases);
207 blkpr(cshout, vp->vec);
212 if (eq(p, STRalias) || eq(p, STRunalias)) {
214 stderror(ERR_NAME | ERR_DANGER);
216 set1(strip(p), saveblk(v), &aliases);
247 (void) signal(SIGTERM, parterm);
248 (void) execl(_PATH_LOGIN, "login", short2str(v[1]), NULL);
256 if (chkstop == 0 && setintr)
260 stderror(ERR_NOTLOGIN);
275 stderror(ERR_NAME | ERR_EMPTYIF);
276 if (eq(*vv, STRthen)) {
278 stderror(ERR_NAME | ERR_IMPRTHEN);
279 setname(vis_str(STRthen));
281 * If expression was zero, then scan to else, otherwise just fall into
285 search(T_IF, 0, NULL);
289 * Simple command attached to this if. Left shift the node in this tree,
290 * munging it so we can reexecute it.
293 lshift(kp->t_dcom, vv - kp->t_dcom);
300 * Reexecute a command, being careful not
301 * to redo i/o redirection, which is already set up.
305 register struct command *kp;
307 kp->t_dflg &= F_SAVE;
308 kp->t_dflg |= F_REPEAT;
310 * If tty is still ours to arbitrate, arbitrate it; otherwise dont even set
311 * pgrp's as the jobs would then have no way to get the tty (we can't give
312 * it to them, and our parent wouldn't know their pgrp, etc.
314 execute(kp, (tpgrp > 0 ? tpgrp : -1), NULL, NULL);
323 search(T_ELSE, 0, NULL);
334 gotolab(lp = globone(v[1], G_ERROR));
342 register struct whyle *wp;
344 * While we still can, locate any unknown ends of existing loops. This
345 * obscure code is the WORST result of the fact that we don't really parse.
348 for (wp = whyles; wp; wp = wp->w_next)
349 if (wp->w_end.type == F_SEEK && wp->w_end.f_seek == 0) {
350 search(T_BREAK, 0, NULL);
355 search(T_GOTO, 0, lab);
357 * Eliminate loops which were exited.
368 register Char *cp, *lp;
371 if (!*v || *(*v++) != '(')
372 stderror(ERR_SYNTAX);
373 cp = **v == ')' ? STRNULL : *v++;
377 stderror(ERR_SYNTAX);
378 search(T_SWITCH, 0, lp = globone(cp, G_ERROR));
391 stderror(ERR_NAME | ERR_NOTWHILE);
400 if (chkstop == 0 && (intty || intact) && evalvec == 0)
403 * Don't DEMAND parentheses here either.
407 set(STRstatus, putn(expr(&v)));
409 stderror(ERR_NAME | ERR_EXPRESSION);
422 register Char *cp, *sp;
423 register struct whyle *nwp;
428 stderror(ERR_NAME | ERR_VARBEGIN);
429 while (*cp && alnum(*cp))
432 stderror(ERR_NAME | ERR_VARALNUM);
433 if ((cp - sp) > MAXVARLEN)
434 stderror(ERR_NAME | ERR_VARTOOLONG);
436 if (v[0][0] != '(' || v[blklen(v) - 1][0] != ')')
437 stderror(ERR_NAME | ERR_NOPAREN);
442 stderror(ERR_NAME | ERR_NOMATCH);
443 nwp = (struct whyle *) xcalloc(1, sizeof *nwp);
444 nwp->w_fe = nwp->w_fe0 = v;
446 btell(&nwp->w_start);
447 nwp->w_fename = Strsave(cp);
448 nwp->w_next = whyles;
449 nwp->w_end.type = F_SEEK;
452 * Pre-read the loop so as to be more comprehensible to a terminal user.
467 register bool again = whyles != 0 && SEEKEQ(&whyles->w_start, &lineloc) &&
468 whyles->w_fename == 0;
472 * Implement prereading here also, taking care not to evaluate the
473 * expression before the loop has been read up from a terminal.
476 status = !exp0(&v, 1);
480 stderror(ERR_NAME | ERR_EXPRESSION);
482 register struct whyle *nwp =
483 (struct whyle *) xcalloc(1, sizeof(*nwp));
485 nwp->w_start = lineloc;
486 nwp->w_end.type = F_SEEK;
487 nwp->w_end.f_seek = 0;
488 nwp->w_next = whyles;
501 /* We ain't gonna loop no more, no more! */
508 whyles->w_end.type = I_SEEK;
510 (void) sigsetmask(sigblock((sigset_t) 0) & ~sigmask(SIGINT));
512 search(T_BREAK, 0, NULL); /* read the expression in */
514 (void) sigblock(sigmask(SIGINT));
515 btell(&whyles->w_end);
525 stderror(ERR_NAME | ERR_NOTWHILE);
526 btell(&whyles->w_end);
537 stderror(ERR_NAME | ERR_NOTWHILE);
544 /* Repeating a while is simple */
545 if (whyles->w_fename == 0) {
546 bseek(&whyles->w_start);
550 * The foreach variable list actually has a spurious word ")" at the end of
551 * the w_fe list. Thus we are at the of the list if one word beyond this
554 if (!whyles->w_fe[1]) {
558 set(whyles->w_fename, Strsave(*whyles->w_fe++));
559 bseek(&whyles->w_start);
568 register sigset_t omask = 0;
572 omask = sigblock(sigmask(SIGINT)) & ~sigmask(SIGINT);
576 (void) sigsetmask(omask);
582 (void) sigsetmask(omask);
591 search(T_BRKSW, 0, NULL);
598 register struct srch *sp, *sp1, *sp2;
602 * Binary search Sp1 is the beginning of the current search range. Sp2 is
605 for (sp1 = srchn, sp2 = srchn + nsrchn; sp1 < sp2;) {
606 sp = sp1 + ((sp2 - sp1) >> 1);
607 if ((i = *cp - *sp->s_name) == 0 &&
608 (i = Strcmp(cp, str2short(sp->s_name))) == 0)
623 search(type, level, goal)
628 Char wordbuf[BUFSIZ];
629 register Char *aword = wordbuf;
634 if (type == T_GOTO) {
641 if (intty && fseekp == feobp && aret == F_SEEK)
642 (void) fprintf(cshout, "? "), (void) fflush(cshout);
644 (void) getword(aword);
645 switch (srchx(aword)) {
648 if (level == 0 && type == T_IF)
653 while (getword(aword))
655 if ((type == T_IF || type == T_ELSE) &&
661 if (type == T_IF || type == T_ELSE)
677 if (type == T_SWITCH || type == T_BRKSW)
682 if (type == T_SWITCH || type == T_BRKSW)
687 if (type == T_GOTO && getword(aword) && eq(aword, goal))
692 if (type != T_GOTO && (type != T_SWITCH || level != 0))
694 if (lastchr(aword) != ':')
696 aword[Strlen(aword) - 1] = 0;
697 if ((type == T_GOTO && eq(aword, goal)) ||
698 (type == T_SWITCH && eq(aword, STRdefault)))
703 if (type != T_SWITCH || level != 0)
705 (void) getword(aword);
706 if (lastchr(aword) == ':')
707 aword[Strlen(aword) - 1] = 0;
708 cp = strip(Dfix1(aword));
709 if (Gmatch(goal, cp))
715 if (type == T_SWITCH && level == 0)
719 (void) getword(NULL);
720 } while (level >= 0);
727 register int found = 0;
735 while (c == ' ' || c == '\t')
740 while (c >= 0 && c != '\n');
752 if (c == '\\' && (c = readc(1)) == '\n')
754 if (c == '\'' || c == '"')
763 *wp = 0; /* end the string b4 test */
765 } while ((d || (!(kwd = keyword(owp)) && c != ' '
766 && c != '\t')) && c != '\n');
770 * if we have read a keyword ( "if", "switch" or "while" ) then we do not
771 * need to unreadc the look-ahead char
785 stderror(ERR_NAME | ERR_NOTFOUND, "then/endif");
788 stderror(ERR_NAME | ERR_NOTFOUND, "endif");
792 stderror(ERR_NAME | ERR_NOTFOUND, "endsw");
795 stderror(ERR_NAME | ERR_NOTFOUND, "end");
798 setname(vis_str(Sgoal));
799 stderror(ERR_NAME | ERR_NOTFOUND, "label");
806 * keyword(wp) determines if wp is one of the built-n functions if,
807 * switch or while. It seems that when an if statement looks like
808 * "if(" then getword above sucks in the '(' and so the search routine
809 * never finds what it is scanning for. Rather than rewrite doword, I hack
810 * in a test to see if the string forms a keyword. Then doword stops
811 * and returns the word "if" -strike
818 static Char STRif[] = {'i', 'f', '\0'};
819 static Char STRwhile[] = {'w', 'h', 'i', 'l', 'e', '\0'};
820 static Char STRswitch[] = {'s', 'w', 'i', 't', 'c', 'h', '\0'};
825 if ((Strcmp(wp, STRif) == 0) || (Strcmp(wp, STRwhile) == 0)
826 || (Strcmp(wp, STRswitch) == 0))
835 if (whyles->w_end.type == F_SEEK && whyles->w_end.f_seek == 0) {
836 search(T_BREAK, 0, NULL);
837 btell(&whyles->w_end);
838 whyles->w_end.f_seek--;
841 bseek(&whyles->w_end);
853 for (; whyles; whyles = nwp) {
854 register struct whyle *wp = whyles;
858 * We free loops that have different seek types.
860 if (wp->w_end.type != I_SEEK && wp->w_start.type == wp->w_end.type &&
861 wp->w_start.type == o.type) {
862 if (wp->w_end.type == F_SEEK) {
863 if (o.f_seek >= wp->w_start.f_seek &&
864 (wp->w_end.f_seek == 0 || o.f_seek < wp->w_end.f_seek))
868 if (o.a_seek >= wp->w_start.a_seek &&
869 (wp->w_end.a_seek == 0 || o.a_seek < wp->w_end.a_seek))
877 xfree((ptr_t) wp->w_fename);
898 (void) fflush(cshout);
910 (void) sigsetmask(sigblock((sigset_t) 0) & ~sigmask(SIGINT));
918 stderror(ERR_NAME | ERR_NOMATCH);
921 v = gargv = saveblk(v);
924 if (sep == ' ' && *v && eq(*v, STRmn))
926 while ((cp = *v++) != NULL) {
929 while ((c = *cp++) != '\0')
930 (void) vis_fputc(c | QUOTE, cshout);
933 (void) vis_fputc(sep | QUOTE, cshout);
935 if (sep && nonl == 0)
936 (void) fputc('\n', cshout);
938 (void) fflush(cshout);
940 (void) sigblock(sigmask(SIGINT));
942 blkfree(gargv), gargv = 0;
954 if ((vp = *v++) == 0) {
958 (void) sigsetmask(sigblock((sigset_t) 0) & ~sigmask(SIGINT));
959 for (ep = STR_environ; *ep; ep++)
960 (void) fprintf(cshout, "%s\n", vis_str(*ep));
963 if ((lp = *v++) == 0)
965 Setenv(vp, lp = globone(lp, G_APPEND));
966 if (eq(vp, STRPATH)) {
970 else if (eq(vp, STRLANG) || eq(vp, STRLC_CTYPE) ||
971 eq(vp, STRLC_ALL) || eq(vp, STRLC_COLLATE)) {
975 (void) setlocale(LC_ALL, "");
976 for (k = 0200; k <= 0377 && !Isprint(k); k++)
978 AsciiOnly = k > 0377;
994 static Char *name = NULL;
999 * Find the longest environment variable
1001 for (maxi = 0, ep = STR_environ; *ep; ep++) {
1002 for (i = 0, p = *ep; *p && *p != '='; p++, i++)
1008 name = (Char *) xmalloc((size_t) (maxi + 1) * sizeof(Char));
1011 for (maxi = 1; maxi;)
1012 for (maxi = 0, ep = STR_environ; *ep; ep++) {
1013 for (n = name, p = *ep; *p && *p != '='; *n++ = *p++)
1016 if (!Gmatch(name, *v))
1020 * Delete name, and start again cause the environment changes
1023 if (eq(name, STRLANG) || eq(name, STRLC_CTYPE) ||
1024 eq(name, STRLC_ALL) || eq(name, STRLC_COLLATE)) {
1028 (void) setlocale(LC_ALL, "");
1029 for (k = 0200; k <= 0377 && !Isprint(k); k++)
1031 AsciiOnly = k > 0377;
1033 AsciiOnly = getenv("LANG") == NULL &&
1034 getenv("LC_ALL") == NULL &&
1035 getenv("LC_CTYPE") == NULL;
1040 xfree((ptr_t) name);
1048 register Char **ep = STR_environ;
1049 register Char *cp, *dp;
1055 for (cp = name, dp = *ep; *cp && *cp == *dp; cp++, dp++)
1057 if (*cp != 0 || *dp != '=')
1059 cp = Strspl(STRequal, val);
1060 xfree((ptr_t) * ep);
1061 *ep = strip(Strspl(name, cp));
1063 blkfree((Char **) environ);
1064 environ = short2blk(STR_environ);
1067 cp = Strspl(name, STRequal);
1068 blk[0] = strip(Strspl(cp, val));
1071 STR_environ = blkspl(STR_environ, blk);
1072 blkfree((Char **) environ);
1073 environ = short2blk(STR_environ);
1081 register Char **ep = STR_environ;
1082 register Char *cp, *dp;
1086 for (cp = name, dp = *ep; *cp && *cp == *dp; cp++, dp++)
1088 if (*cp != 0 || *dp != '=')
1092 STR_environ = blkspl(STR_environ, ep + 1);
1093 environ = short2blk(STR_environ);
1107 register Char *cp = v[1];
1113 (void) fprintf(cshout, "%o\n", i);
1117 while (Isdigit(*cp) && *cp != '8' && *cp != '9')
1118 i = i * 8 + *cp++ - '0';
1119 if (*cp || i < 0 || i > 0777)
1120 stderror(ERR_NAME | ERR_MASK);
1124 typedef quad_t RLIM_TYPE;
1126 static struct limits {
1132 { RLIMIT_CPU, "cputime", 1, "seconds" },
1133 { RLIMIT_FSIZE, "filesize", 1024, "kbytes" },
1134 { RLIMIT_DATA, "datasize", 1024, "kbytes" },
1135 { RLIMIT_STACK, "stacksize", 1024, "kbytes" },
1136 { RLIMIT_CORE, "coredumpsize", 1024, "kbytes" },
1137 { RLIMIT_RSS, "memoryuse", 1024, "kbytes" },
1138 { RLIMIT_MEMLOCK, "memorylocked", 1024, "kbytes" },
1139 { RLIMIT_NPROC, "maxproc", 1, "" },
1140 { RLIMIT_NOFILE, "openfiles", 1, "" },
1141 { -1, NULL, 0, NULL }
1144 static struct limits *findlim();
1145 static RLIM_TYPE getval();
1146 static void limtail();
1148 static int setlim();
1150 static struct limits *
1154 register struct limits *lp, *res;
1156 res = (struct limits *) NULL;
1157 for (lp = limits; lp->limconst >= 0; lp++)
1158 if (prefix(cp, str2short(lp->limname))) {
1160 stderror(ERR_NAME | ERR_AMBIG);
1165 stderror(ERR_NAME | ERR_LIMIT);
1176 register struct limits *lp;
1177 register RLIM_TYPE limit;
1181 if (*v && eq(*v, STRmh)) {
1186 for (lp = limits; lp->limconst >= 0; lp++)
1195 limit = getval(lp, v + 1);
1196 if (setlim(lp, hard, limit) < 0)
1197 stderror(ERR_SILENT);
1202 register struct limits *lp;
1209 f = atof(short2str(cp));
1211 while (Isdigit(*cp) || *cp == '.' || *cp == 'e' || *cp == 'E')
1215 return ((RLIM_TYPE) ((f + 0.5) * lp->limdiv));
1220 if (lp->limconst != RLIMIT_CPU)
1222 return ((RLIM_TYPE) (f * 60.0 + atof(short2str(cp + 1))));
1224 if (lp->limconst != RLIMIT_CPU)
1226 limtail(cp, "hours");
1230 if (lp->limconst == RLIMIT_CPU) {
1231 limtail(cp, "minutes");
1236 limtail(cp, "megabytes");
1237 f *= 1024.0 * 1024.0;
1240 if (lp->limconst != RLIMIT_CPU)
1242 limtail(cp, "seconds");
1245 if (lp->limconst == RLIMIT_CPU)
1248 limtail(cp, "megabytes");
1249 f *= 1024.0 * 1024.0;
1252 if (lp->limconst == RLIMIT_CPU)
1254 limtail(cp, "kbytes");
1258 limtail(cp, "unlimited");
1259 return (RLIM_INFINITY);
1262 stderror(ERR_NAME | ERR_SCALEF);
1265 if (f > (float) RLIM_INFINITY)
1266 return RLIM_INFINITY;
1268 return ((RLIM_TYPE) f);
1276 while (*cp && *cp == *str)
1279 stderror(ERR_BADSCALE, str);
1286 register struct limits *lp;
1292 (void) fprintf(cshout, "%s \t", lp->limname);
1294 (void) getrlimit(lp->limconst, &rlim);
1295 limit = hard ? rlim.rlim_max : rlim.rlim_cur;
1297 if (limit == RLIM_INFINITY)
1298 (void) fprintf(cshout, "unlimited");
1299 else if (lp->limconst == RLIMIT_CPU)
1300 psecs((long) limit);
1302 (void) fprintf(cshout, "%ld %s", (long) (limit / lp->limdiv),
1304 (void) fputc('\n', cshout);
1313 register struct limits *lp;
1318 if (*v && eq(*v, STRmh)) {
1323 for (lp = limits; lp->limconst >= 0; lp++)
1324 if (setlim(lp, hard, (RLIM_TYPE) RLIM_INFINITY) < 0)
1327 stderror(ERR_SILENT);
1332 if (setlim(lp, hard, (RLIM_TYPE) RLIM_INFINITY) < 0)
1333 stderror(ERR_SILENT);
1338 setlim(lp, hard, limit)
1339 register struct limits *lp;
1345 (void) getrlimit(lp->limconst, &rlim);
1348 rlim.rlim_max = limit;
1349 else if (limit == RLIM_INFINITY && geteuid() != 0)
1350 rlim.rlim_cur = rlim.rlim_max;
1352 rlim.rlim_cur = limit;
1354 if (setrlimit(lp->limconst, &rlim) < 0) {
1355 (void) fprintf(csherr, "%s: %s: Can't %s%s limit\n", bname, lp->limname,
1356 limit == RLIM_INFINITY ? "remove" : "set",
1357 hard ? " hard" : "");
1374 stderror(ERR_SUSPLOG);
1377 old = signal(SIGTSTP, SIG_DFL);
1378 (void) kill(0, SIGTSTP);
1379 /* the shell stops here */
1380 (void) signal(SIGTSTP, old);
1383 ctpgrp = tcgetpgrp(FSHTTY);
1384 while (ctpgrp != opgrp) {
1385 old = signal(SIGTTIN, SIG_DFL);
1386 (void) kill(0, SIGTTIN);
1387 (void) signal(SIGTTIN, old);
1389 (void) setpgid(0, shpgrp);
1390 (void) tcsetpgrp(FSHTTY, shpgrp);
1394 /* This is the dreaded EVAL built-in.
1395 * If you don't fiddle with file descriptors, and reset didfds,
1396 * this command will either ignore redirection inside or outside
1397 * its aguments, e.g. eval "date >x" vs. eval "date" >x
1398 * The stuff here seems to work, but I did it by trial and error rather
1399 * than really knowing what was going on. If tpgrp is zero, we are
1400 * probably a background eval, e.g. "eval date &", and we want to
1401 * make sure that any processes we start stay in our pgrp.
1402 * This is also the case for "time eval date" -- stay in same pgrp.
1403 * Otherwise, under stty tostop, processes will stop in the wrong
1404 * pgrp, with no way for the shell to get them going again. -IAN!
1406 static Char **gv = NULL;
1438 gflag = 0, tglob(v);
1440 gv = v = globall(v);
1443 stderror(ERR_NOMATCH);
1452 saveIN = dcopy(SHIN, -1);
1453 saveOUT = dcopy(SHOUT, -1);
1454 saveERR = dcopy(SHERR, -1);
1458 if ((my_reenter = setexit()) == 0) {
1461 SHIN = dcopy(0, -1);
1462 SHOUT = dcopy(1, -1);
1463 SHERR = dcopy(2, -1);
1473 (void) close(SHOUT);
1474 (void) close(SHERR);
1475 SHIN = dmove(saveIN, oSHIN);
1476 SHOUT = dmove(saveOUT, oSHOUT);
1477 SHERR = dmove(saveERR, oSHERR);
1479 blkfree(gv), gv = NULL;
1483 stderror(ERR_SILENT);
1493 extern int progprintf __P((int, char **));
1496 ret = progprintf(blklen(v), c = short2blk(v));
1497 (void) fflush(cshout);
1498 (void) fflush(csherr);
1500 blkfree((Char **) c);
1502 stderror(ERR_SILENT);