Implement the -X option - an apparent variant of -x which sends all trace
output to the stderr which existed when the -X option was (last) enabled. It also enables tracing by enabling -x (and when reset, +X, also resets the 'x' flag (+x)). Note that it is still -x/+x which actually enables/disables the trace output. Hence "apparent variant" - what -X actually does (aside from setting -x) is just to lock the trace output, rather than having it follow wherever stderr is later redirected.
This commit is contained in:
parent
bfa0b331f0
commit
ffc64c6374
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: eval.c,v 1.152 2017/09/29 17:53:57 kre Exp $ */
|
||||
/* $NetBSD: eval.c,v 1.153 2017/11/19 03:23:01 kre Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1993
|
||||
|
@ -37,7 +37,7 @@
|
|||
#if 0
|
||||
static char sccsid[] = "@(#)eval.c 8.9 (Berkeley) 6/8/95";
|
||||
#else
|
||||
__RCSID("$NetBSD: eval.c,v 1.152 2017/09/29 17:53:57 kre Exp $");
|
||||
__RCSID("$NetBSD: eval.c,v 1.153 2017/11/19 03:23:01 kre Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
|
@ -279,20 +279,20 @@ evaltree(union node *n, int flags)
|
|||
if (xflag && n->nredir.redirect) {
|
||||
union node *rn;
|
||||
|
||||
out2str(expandstr(ps4val(), line_number));
|
||||
out2str("using redirections:");
|
||||
outxstr(expandstr(ps4val(), line_number));
|
||||
outxstr("using redirections:");
|
||||
for (rn = n->nredir.redirect; rn; rn = rn->nfile.next)
|
||||
(void) outredir(&errout, rn, ' ');
|
||||
out2str(" do\n");
|
||||
flushout(&errout);
|
||||
(void) outredir(outx, rn, ' ');
|
||||
outxstr(" do\n");
|
||||
flushout(outx);
|
||||
}
|
||||
redirect(n->nredir.redirect, REDIR_PUSH | REDIR_KEEP);
|
||||
evaltree(n->nredir.n, flags);
|
||||
popredir();
|
||||
if (xflag && n->nredir.redirect) {
|
||||
out2str(expandstr(ps4val(), line_number));
|
||||
out2str("done\n");
|
||||
flushout(&errout);
|
||||
outxstr(expandstr(ps4val(), line_number));
|
||||
outxstr("done\n");
|
||||
flushout(outx);
|
||||
}
|
||||
break;
|
||||
case NSUBSHELL:
|
||||
|
@ -437,13 +437,13 @@ evalfor(union node *n, int flags)
|
|||
f |= EV_MORE;
|
||||
|
||||
if (xflag) {
|
||||
out2str(expandstr(ps4val(), line_number));
|
||||
out2str("for ");
|
||||
out2str(n->nfor.var);
|
||||
out2c('=');
|
||||
out2shstr(sp->text);
|
||||
out2c('\n');
|
||||
flushout(&errout);
|
||||
outxstr(expandstr(ps4val(), line_number));
|
||||
outxstr("for ");
|
||||
outxstr(n->nfor.var);
|
||||
outxc('=');
|
||||
outxshstr(sp->text);
|
||||
outxc('\n');
|
||||
flushout(outx);
|
||||
}
|
||||
|
||||
setvar(n->nfor.var, sp->text, 0);
|
||||
|
@ -523,12 +523,12 @@ evalsubshell(union node *n, int flags)
|
|||
if (xflag && n->nredir.redirect) {
|
||||
union node *rn;
|
||||
|
||||
out2str(expandstr(ps4val(), line_number));
|
||||
out2str("using redirections:");
|
||||
outxstr(expandstr(ps4val(), line_number));
|
||||
outxstr("using redirections:");
|
||||
for (rn = n->nredir.redirect; rn; rn = rn->nfile.next)
|
||||
(void) outredir(&errout, rn, ' ');
|
||||
out2str(" do subshell\n");
|
||||
flushout(&errout);
|
||||
(void) outredir(outx, rn, ' ');
|
||||
outxstr(" do subshell\n");
|
||||
flushout(outx);
|
||||
}
|
||||
INTOFF;
|
||||
jp = makejob(n, 1);
|
||||
|
@ -543,9 +543,9 @@ evalsubshell(union node *n, int flags)
|
|||
exitstatus = backgnd ? 0 : waitforjob(jp);
|
||||
INTON;
|
||||
if (!backgnd && xflag && n->nredir.redirect) {
|
||||
out2str(expandstr(ps4val(), line_number));
|
||||
out2str("done subshell\n");
|
||||
flushout(&errout);
|
||||
outxstr(expandstr(ps4val(), line_number));
|
||||
outxstr("done subshell\n");
|
||||
flushout(outx);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -797,7 +797,8 @@ evalcommand(union node *cmd, int flgs, struct backcmd *backcmd)
|
|||
|
||||
vforked = 0;
|
||||
/* First expand the arguments. */
|
||||
CTRACE(DBG_EVAL, ("evalcommand(%p, %d) called\n", cmd, flags));
|
||||
CTRACE(DBG_EVAL, ("evalcommand(%p, %d) called [%s]\n", cmd, flags,
|
||||
cmd->ncmd.args ? cmd->ncmd.args->narg.text : ""));
|
||||
setstackmark(&smark);
|
||||
back_exitstatus = 0;
|
||||
|
||||
|
@ -861,12 +862,12 @@ evalcommand(union node *cmd, int flgs, struct backcmd *backcmd)
|
|||
char sep = 0;
|
||||
union node *rn;
|
||||
|
||||
out2str(expandstr(ps4val(), line_number));
|
||||
outxstr(expandstr(ps4val(), line_number));
|
||||
for (sp = varlist.list ; sp ; sp = sp->next) {
|
||||
char *p;
|
||||
|
||||
if (sep != 0)
|
||||
outc(sep, &errout);
|
||||
outxc(sep);
|
||||
|
||||
/*
|
||||
* The "var=" part should not be quoted, regardless
|
||||
|
@ -876,25 +877,25 @@ evalcommand(union node *cmd, int flgs, struct backcmd *backcmd)
|
|||
p = strchr(sp->text, '=');
|
||||
if (p != NULL) {
|
||||
*p = '\0'; /*XXX*/
|
||||
out2shstr(sp->text);
|
||||
out2c('=');
|
||||
outxshstr(sp->text);
|
||||
outxc('=');
|
||||
*p++ = '='; /*XXX*/
|
||||
} else
|
||||
p = sp->text;
|
||||
out2shstr(p);
|
||||
outxshstr(p);
|
||||
sep = ' ';
|
||||
}
|
||||
for (sp = arglist.list ; sp ; sp = sp->next) {
|
||||
if (sep != 0)
|
||||
outc(sep, &errout);
|
||||
out2shstr(sp->text);
|
||||
outxc(sep);
|
||||
outxshstr(sp->text);
|
||||
sep = ' ';
|
||||
}
|
||||
for (rn = cmd->ncmd.redirect; rn; rn = rn->nfile.next)
|
||||
if (outredir(&errout, rn, sep))
|
||||
if (outredir(outx, rn, sep))
|
||||
sep = ' ';
|
||||
outc('\n', &errout);
|
||||
flushout(&errout);
|
||||
outxc('\n');
|
||||
flushout(outx);
|
||||
}
|
||||
|
||||
/* Now locate the command. */
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: option.list,v 1.6 2017/07/24 14:17:11 kre Exp $ */
|
||||
/* $NetBSD: option.list,v 1.7 2017/11/19 03:23:01 kre Exp $ */
|
||||
|
||||
/*
|
||||
* define the shell's settable options
|
||||
|
@ -66,6 +66,7 @@ qflag quietprofile q # disable -v/-x in startup files
|
|||
fnline1 local_lineno L on # number lines in funcs starting at 1
|
||||
promptcmds promptcmds # allow $( ) in PS1 (et al).
|
||||
pipefail pipefail # pipe exit status
|
||||
Xflag Xtrace X # sticky stderr for -x (implies -x)
|
||||
|
||||
// editline/history related options ("vi" is standard, 'V' and others are not)
|
||||
// only one of vi/emacs can be set, hence the "set" definition, value
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: options.c,v 1.50 2017/07/24 12:35:37 kre Exp $ */
|
||||
/* $NetBSD: options.c,v 1.51 2017/11/19 03:23:01 kre Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
|
@ -37,7 +37,7 @@
|
|||
#if 0
|
||||
static char sccsid[] = "@(#)options.c 8.2 (Berkeley) 5/4/95";
|
||||
#else
|
||||
__RCSID("$NetBSD: options.c,v 1.50 2017/07/24 12:35:37 kre Exp $");
|
||||
__RCSID("$NetBSD: options.c,v 1.51 2017/11/19 03:23:01 kre Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
|
@ -252,10 +252,12 @@ set_opt_val(size_t i, int val)
|
|||
if (optlist[j].opt_set == flag)
|
||||
optlist[j].val = 0;
|
||||
}
|
||||
if (i == _SH_OPT_Xflag)
|
||||
xtracefdsetup(val);
|
||||
optlist[i].val = val;
|
||||
#ifdef DEBUG
|
||||
if (&optlist[i].val == &debug)
|
||||
opentrace();
|
||||
opentrace(); /* different "trace" than the -x one... */
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -307,6 +309,8 @@ minus_o(char *name, int val)
|
|||
for (i = 0; i < NOPTS; i++)
|
||||
if (optlist[i].name && equal(name, optlist[i].name)) {
|
||||
set_opt_val(i, val);
|
||||
if (i == _SH_OPT_Xflag)
|
||||
set_opt_val(_SH_OPT_xflag, val);
|
||||
return;
|
||||
}
|
||||
error("Illegal option %co %s", "+-"[val], name);
|
||||
|
@ -321,7 +325,9 @@ setoption(int flag, int val)
|
|||
|
||||
for (i = 0; i < NOPTS; i++)
|
||||
if (optlist[i].letter == flag) {
|
||||
set_opt_val( i, val );
|
||||
set_opt_val(i, val);
|
||||
if (i == _SH_OPT_Xflag)
|
||||
set_opt_val(_SH_OPT_xflag, val);
|
||||
return;
|
||||
}
|
||||
error("Illegal option %c%c", "+-"[val], flag);
|
||||
|
|
164
bin/sh/output.c
164
bin/sh/output.c
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: output.c,v 1.38 2017/11/19 03:22:55 kre Exp $ */
|
||||
/* $NetBSD: output.c,v 1.39 2017/11/19 03:23:01 kre Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
|
@ -37,7 +37,7 @@
|
|||
#if 0
|
||||
static char sccsid[] = "@(#)output.c 8.2 (Berkeley) 5/4/95";
|
||||
#else
|
||||
__RCSID("$NetBSD: output.c,v 1.38 2017/11/19 03:22:55 kre Exp $");
|
||||
__RCSID("$NetBSD: output.c,v 1.39 2017/11/19 03:23:01 kre Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
|
@ -67,6 +67,9 @@ __RCSID("$NetBSD: output.c,v 1.38 2017/11/19 03:22:55 kre Exp $");
|
|||
#include "output.h"
|
||||
#include "memalloc.h"
|
||||
#include "error.h"
|
||||
#include "redir.h"
|
||||
#include "options.h"
|
||||
#include "show.h"
|
||||
|
||||
|
||||
#define OUTBUFSIZ BUFSIZ
|
||||
|
@ -74,12 +77,14 @@ __RCSID("$NetBSD: output.c,v 1.38 2017/11/19 03:22:55 kre Exp $");
|
|||
#define MEM_OUT -3 /* output to dynamically allocated memory */
|
||||
|
||||
|
||||
struct output output = {NULL, 0, OUTBUFSIZ, NULL, 1, 0};
|
||||
struct output errout = {NULL, 0, 100, NULL, 2, 0};
|
||||
struct output memout = {NULL, 0, 0, NULL, MEM_OUT, 0};
|
||||
/* nextc nleft bufsize buf fd flags chain */
|
||||
struct output output = {NULL, 0, OUTBUFSIZ, NULL, 1, 0, NULL };
|
||||
struct output errout = {NULL, 0, 100, NULL, 2, 0, NULL };
|
||||
struct output memout = {NULL, 0, 0, NULL, MEM_OUT, 0, NULL };
|
||||
struct output *out1 = &output;
|
||||
struct output *out2 = &errout;
|
||||
|
||||
struct output *outx = &errout;
|
||||
struct output *outxtop = NULL;
|
||||
|
||||
|
||||
#ifdef mkinit
|
||||
|
@ -128,13 +133,21 @@ out2str(const char *p)
|
|||
outstr(p, out2);
|
||||
}
|
||||
|
||||
void
|
||||
outxstr(const char *p)
|
||||
{
|
||||
outstr(p, outx);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
outstr(const char *p, struct output *file)
|
||||
{
|
||||
char c = 0;
|
||||
|
||||
while (*p)
|
||||
outc(*p++, file);
|
||||
if (file == out2)
|
||||
outc((c = *p++), file);
|
||||
if (file == out2 || (file == outx && c == '\n'))
|
||||
flushout(file);
|
||||
}
|
||||
|
||||
|
@ -145,6 +158,11 @@ out2shstr(const char *p)
|
|||
outshstr(p, out2);
|
||||
}
|
||||
|
||||
void
|
||||
outxshstr(const char *p)
|
||||
{
|
||||
outshstr(p, outx);
|
||||
}
|
||||
|
||||
/*
|
||||
* ' is in this list, not because it does not require quoting
|
||||
|
@ -245,6 +263,8 @@ emptyoutbuf(struct output *dest)
|
|||
dest->nextc = dest->buf;
|
||||
dest->nleft = dest->bufsize;
|
||||
INTON;
|
||||
VTRACE(DBG_OUTPUT, ("emptyoutbuf now %d @%p for fd %d\n",
|
||||
dest->nleft, dest->buf, dest->fd));
|
||||
} else if (dest->fd == MEM_OUT) {
|
||||
offset = dest->bufsize;
|
||||
INTOFF;
|
||||
|
@ -274,6 +294,8 @@ flushout(struct output *dest)
|
|||
|
||||
if (dest->buf == NULL || dest->nextc == dest->buf || dest->fd < 0)
|
||||
return;
|
||||
VTRACE(DBG_OUTPUT, ("flushout fd=%d %zd to write\n", dest->fd,
|
||||
(size_t)(dest->nextc - dest->buf)));
|
||||
if (xwrite(dest->fd, dest->buf, dest->nextc - dest->buf) < 0)
|
||||
dest->flags |= OUTPUT_ERR;
|
||||
dest->nextc = dest->buf;
|
||||
|
@ -606,3 +628,129 @@ xioctl(int fd, unsigned long request, char *arg)
|
|||
while ((i = ioctl(fd, request, arg)) == -1 && errno == EINTR);
|
||||
return i;
|
||||
}
|
||||
|
||||
static void
|
||||
xtrace_fd_swap(int from, int to)
|
||||
{
|
||||
struct output *o = outxtop;
|
||||
|
||||
while (o != NULL) {
|
||||
if (o->fd == from)
|
||||
o->fd = to;
|
||||
o = o->chain;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* the -X flag is to be set or reset (not necessarily changed)
|
||||
* Do what is needed to make tracing go to where it should
|
||||
*
|
||||
* Note: Xflag has not yet been altered, "on" indicates what it will become
|
||||
*/
|
||||
|
||||
void
|
||||
xtracefdsetup(int on)
|
||||
{
|
||||
if (!on) {
|
||||
flushout(outx);
|
||||
|
||||
if (Xflag != 1) /* Was already +X */
|
||||
return; /* so nothing to do */
|
||||
|
||||
outx = out2;
|
||||
CTRACE(DBG_OUTPUT, ("Tracing to stderr\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (Xflag == 1) { /* was already set */
|
||||
/*
|
||||
* This is a change of output file only
|
||||
* Just close the current one, and reuse the struct output
|
||||
*/
|
||||
if (!(outx->flags & OUTPUT_CLONE))
|
||||
sh_close(outx->fd);
|
||||
} else if (outxtop == NULL) {
|
||||
/*
|
||||
* -X is just turning on, for the forst time,
|
||||
* need a new output struct to become outx
|
||||
*/
|
||||
xtrace_clone(1);
|
||||
} else
|
||||
outx = outxtop;
|
||||
|
||||
if (outx != out2) {
|
||||
outx->flags &= ~OUTPUT_CLONE;
|
||||
outx->fd = to_upper_fd(dup(out2->fd));
|
||||
register_sh_fd(outx->fd, xtrace_fd_swap);
|
||||
}
|
||||
|
||||
CTRACE(DBG_OUTPUT, ("Tracing now to fd %d (from %d)\n",
|
||||
outx->fd, out2->fd));
|
||||
}
|
||||
|
||||
void
|
||||
xtrace_clone(int new)
|
||||
{
|
||||
struct output *o;
|
||||
|
||||
CTRACE(DBG_OUTPUT,
|
||||
("xtrace_clone(%d): %sfd=%d buf=%p nleft=%d flags=%x ",
|
||||
new, (outx == out2 ? "out2: " : ""),
|
||||
outx->fd, outx->buf, outx->nleft, outx->flags));
|
||||
|
||||
flushout(outx);
|
||||
|
||||
if (!new && outxtop == NULL && Xflag == 0) {
|
||||
/* following stderr, nothing to save */
|
||||
CTRACE(DBG_OUTPUT, ("+X\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
o = ckmalloc(sizeof(*o));
|
||||
o->fd = outx->fd;
|
||||
o->flags = OUTPUT_CLONE;
|
||||
o->bufsize = outx->bufsize;
|
||||
o->nleft = 0;
|
||||
o->buf = NULL;
|
||||
o->nextc = NULL;
|
||||
o->chain = outxtop;
|
||||
outx = o;
|
||||
outxtop = o;
|
||||
|
||||
CTRACE(DBG_OUTPUT, ("-> fd=%d flags=%x[CLONE]\n", outx->fd, o->flags));
|
||||
}
|
||||
|
||||
void
|
||||
xtrace_pop(void)
|
||||
{
|
||||
struct output *o;
|
||||
|
||||
CTRACE(DBG_OUTPUT, ("trace_pop: fd=%d buf=%p nleft=%d flags=%x ",
|
||||
outx->fd, outx->buf, outx->nleft, outx->flags));
|
||||
|
||||
flushout(outx);
|
||||
|
||||
if (outxtop == NULL) {
|
||||
/*
|
||||
* No -X has been used, so nothing much to do
|
||||
*/
|
||||
CTRACE(DBG_OUTPUT, ("+X\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
o = outxtop;
|
||||
outx = o->chain;
|
||||
if (outx == NULL)
|
||||
outx = &errout;
|
||||
outxtop = o->chain;
|
||||
if (o != &errout) {
|
||||
if (o->fd >= 0 && !(o->flags & OUTPUT_CLONE))
|
||||
sh_close(o->fd);
|
||||
if (o->buf)
|
||||
ckfree(o->buf);
|
||||
ckfree(o);
|
||||
}
|
||||
|
||||
CTRACE(DBG_OUTPUT, ("-> fd=%d buf=%p nleft=%d flags=%x\n",
|
||||
outx->fd, outx->buf, outx->nleft, outx->flags));
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: output.h,v 1.25 2017/11/19 03:22:55 kre Exp $ */
|
||||
/* $NetBSD: output.h,v 1.26 2017/11/19 03:23:01 kre Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
|
@ -45,22 +45,27 @@ struct output {
|
|||
char *buf;
|
||||
short fd;
|
||||
short flags;
|
||||
struct output *chain;
|
||||
};
|
||||
|
||||
/* flags for ->flags */
|
||||
#define OUTPUT_ERR 01 /* error occurred on output */
|
||||
#define OUTPUT_ERR 0x01 /* error occurred on output */
|
||||
#define OUTPUT_CLONE 0x02 /* this is a clone of another */
|
||||
|
||||
extern struct output output;
|
||||
extern struct output errout;
|
||||
extern struct output memout;
|
||||
extern struct output *out1;
|
||||
extern struct output *out2;
|
||||
extern struct output *outx;
|
||||
|
||||
void open_mem(char *, int, struct output *);
|
||||
void out1str(const char *);
|
||||
void out2str(const char *);
|
||||
void outxstr(const char *);
|
||||
void outstr(const char *, struct output *);
|
||||
void out2shstr(const char *);
|
||||
void outxshstr(const char *);
|
||||
void outshstr(const char *, struct output *);
|
||||
void emptyoutbuf(struct output *);
|
||||
void flushall(void);
|
||||
|
@ -75,10 +80,14 @@ void fmtstr(char *, size_t, const char *, ...) __printflike(3, 4);
|
|||
void doformat(struct output *, const char *, va_list) __printflike(2, 0);
|
||||
int xwrite(int, char *, int);
|
||||
int xioctl(int, unsigned long, char *);
|
||||
void xtracefdsetup(int);
|
||||
void xtrace_clone(int);
|
||||
void xtrace_pop(void);
|
||||
|
||||
#define outc(c, file) (--(file)->nleft < 0? (emptyoutbuf(file), *(file)->nextc++ = (c)) : (*(file)->nextc++ = (c)))
|
||||
#define out1c(c) outc(c, out1)
|
||||
#define out2c(c) outc(c, out2)
|
||||
#define outxc(c) outc(c, outx)
|
||||
|
||||
#define OUTPUT_INCL
|
||||
#endif
|
||||
|
|
40
bin/sh/sh.1
40
bin/sh/sh.1
|
@ -1,4 +1,4 @@
|
|||
.\" $NetBSD: sh.1,v 1.173 2017/11/15 08:50:07 kre Exp $
|
||||
.\" $NetBSD: sh.1,v 1.174 2017/11/19 03:23:01 kre Exp $
|
||||
.\" Copyright (c) 1991, 1993
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
.\"
|
||||
|
@ -34,7 +34,7 @@
|
|||
.Dd October 24, 2017
|
||||
.Dt SH 1
|
||||
.\" everything except c o and s (keep them ordered)
|
||||
.ds flags abCEeFfhIiLmnpquVvx
|
||||
.ds flags abCEeFfhIiLmnpquVvXx
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm sh
|
||||
|
@ -434,10 +434,36 @@ section below.)
|
|||
.It Fl v Em verbose
|
||||
The shell writes its input to standard error as it is read.
|
||||
Useful for debugging.
|
||||
.It Fl X Em Xtrace
|
||||
Cause output from the
|
||||
.Ic xtrace
|
||||
.Pq Fl x
|
||||
option to be sent to standard error as it exists when the
|
||||
.Fl X
|
||||
option is enabled (regardless of its previous state.)
|
||||
For example:
|
||||
.Bd -compact -literal
|
||||
set -X 2>/tmp/trace-file
|
||||
.Ed
|
||||
will arrange for tracing output to be sent to the file named,
|
||||
instead of wherever it was previously being sent,
|
||||
until the X option is set again, or cleared.
|
||||
.Pp
|
||||
Each change (set or clear) to
|
||||
.Fl X
|
||||
is also performed upon
|
||||
.Fl x ,
|
||||
but not the converse.
|
||||
.It Fl x Em xtrace
|
||||
Write each command to standard error (preceded by the expanded value of
|
||||
.Dq $PS4 )
|
||||
before it is executed.
|
||||
Unless
|
||||
.Fl X
|
||||
is set,
|
||||
.Dq "standard error"
|
||||
means that which existed immediately before any redirections to
|
||||
be applied to the command are performed.
|
||||
Useful for debugging.
|
||||
.It "\ \ " Em cdprint
|
||||
Make an interactive shell always print the new directory name when
|
||||
|
@ -2633,6 +2659,16 @@ Making
|
|||
local causes any shell options that are changed via the set command inside the
|
||||
function to be restored to their original values when the function
|
||||
returns.
|
||||
If
|
||||
.Fl X
|
||||
option is altered after
|
||||
.Dq \-
|
||||
has been made local, then when the function returns, the previous
|
||||
destination for
|
||||
.Ic xtrace
|
||||
output (as of the time of the
|
||||
.Ic local
|
||||
command) will also be restored.
|
||||
.Pp
|
||||
It is an error to use
|
||||
.Ic local
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: var.c,v 1.68 2017/10/28 03:59:11 kre Exp $ */
|
||||
/* $NetBSD: var.c,v 1.69 2017/11/19 03:23:01 kre Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1991, 1993
|
||||
|
@ -37,7 +37,7 @@
|
|||
#if 0
|
||||
static char sccsid[] = "@(#)var.c 8.3 (Berkeley) 5/4/95";
|
||||
#else
|
||||
__RCSID("$NetBSD: var.c,v 1.68 2017/10/28 03:59:11 kre Exp $");
|
||||
__RCSID("$NetBSD: var.c,v 1.69 2017/11/19 03:23:01 kre Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
|
@ -925,6 +925,7 @@ mklocal(const char *name, int flags)
|
|||
p = ckmalloc(sizeof_optlist);
|
||||
lvp->text = memcpy(p, optlist, sizeof_optlist);
|
||||
vp = NULL;
|
||||
xtrace_clone(0);
|
||||
} else {
|
||||
vp = find_var(name, &vpp, NULL);
|
||||
if (vp == NULL) {
|
||||
|
@ -985,6 +986,7 @@ poplocalvars(void)
|
|||
if (vp == NULL) { /* $- saved */
|
||||
memcpy(optlist, lvp->text, sizeof_optlist);
|
||||
ckfree(lvp->text);
|
||||
xtrace_pop();
|
||||
optschanged();
|
||||
} else if ((lvp->flags & (VUNSET|VSTRFIXED)) == VUNSET) {
|
||||
(void)unsetvar(vp->text, 0);
|
||||
|
|
Loading…
Reference in New Issue