8b6a46
diff -up mksh/exec.c.fixtrace mksh/exec.c
8b6a46
--- mksh/exec.c.fixtrace	2013-04-26 23:23:09.000000000 +0200
8b6a46
+++ mksh/exec.c	2017-10-10 12:11:30.472249513 +0200
8b6a46
@@ -138,11 +138,6 @@ execute(struct op * volatile t,
8b6a46
 			/* Allow option parsing (bizarre, but POSIX) */
8b6a46
 			timex_hook(t, &up);
8b6a46
 		ap = (const char **)up;
8b6a46
-		if (Flag(FXTRACE)) {
8b6a46
-			shf_puts(substitute(str_val(global("PS4")), 0),
8b6a46
-			    shl_out);
8b6a46
-			Flag(FXTRACE) = 2;
8b6a46
-		}
8b6a46
 		if (ap[0])
8b6a46
 			tp = findcom(ap[0], FC_BI|FC_FUNC);
8b6a46
 	}
8b6a46
@@ -637,6 +632,8 @@ comexec(struct op *t, struct tbl * volat
8b6a46
 	l_assign = e->loc;
8b6a46
 	if (Flag(FEXPORT))
8b6a46
 		type_flags |= EXPORT;
8b6a46
+	if (Flag(FXTRACE))
8b6a46
+		change_xtrace(2, false);
8b6a46
 	for (i = 0; t->vars[i]; i++) {
8b6a46
 		/* do NOT lookup in the new var/fn block just created */
8b6a46
 		e->loc = l_expand;
8b6a46
@@ -650,9 +647,9 @@ comexec(struct op *t, struct tbl * volat
8b6a46
 				++ccp;
8b6a46
 			if (*ccp == '=')
8b6a46
 				++ccp;
8b6a46
-			shf_write(cp, ccp - cp, shl_out);
8b6a46
-			print_value_quoted(shl_out, ccp);
8b6a46
-			shf_putc(' ', shl_out);
8b6a46
+			shf_write(cp, ccp - cp, shl_xtrace);
8b6a46
+			print_value_quoted(shl_xtrace, ccp);
8b6a46
+			shf_putc(' ', shl_xtrace);
8b6a46
 		}
8b6a46
 		/* but assign in there as usual */
8b6a46
 		typeset(cp, type_flags, 0, 0, 0);
8b6a46
@@ -661,17 +658,16 @@ comexec(struct op *t, struct tbl * volat
8b6a46
 	}
8b6a46
 
8b6a46
 	if (Flag(FXTRACE)) {
8b6a46
+		change_xtrace(2, false);
8b6a46
 		if (ap[rv = 0]) {
8b6a46
  xtrace_ap_loop:
8b6a46
-			print_value_quoted(shl_out, ap[rv]);
8b6a46
+			print_value_quoted(shl_xtrace, ap[rv]);
8b6a46
 			if (ap[++rv]) {
8b6a46
-				shf_putc(' ', shl_out);
8b6a46
+				shf_putc(' ', shl_xtrace);
8b6a46
 				goto xtrace_ap_loop;
8b6a46
 			}
8b6a46
 		}
8b6a46
-		shf_putc('\n', shl_out);
8b6a46
-		Flag(FXTRACE) = 1;
8b6a46
-		shf_flush(shl_out);
8b6a46
+		change_xtrace(1, false);
8b6a46
 	}
8b6a46
 
8b6a46
 	if ((cp = *ap) == NULL) {
8b6a46
@@ -754,9 +750,9 @@ comexec(struct op *t, struct tbl * volat
8b6a46
 			getopts_reset(1);
8b6a46
 		}
8b6a46
 
8b6a46
-		old_xflag = Flag(FXTRACE);
8b6a46
-		Flag(FXTRACE) |= tp->flag & TRACE ? 1 : 0;
8b6a46
-
8b6a46
+		old_xflag = Flag(FXTRACE) ? 1 : 0;
8b6a46
+		change_xtrace((Flag(FXTRACEREC) ? old_xflag : 0) |
8b6a46
+		    ((tp->flag & TRACE) ? 1 : 0), false);
8b6a46
 		old_inuse = tp->flag & FINUSE;
8b6a46
 		tp->flag |= FINUSE;
8b6a46
 
8b6a46
@@ -765,9 +761,11 @@ comexec(struct op *t, struct tbl * volat
8b6a46
 			execute(tp->val.t, flags & XERROK, NULL);
8b6a46
 			i = LRETURN;
8b6a46
 		}
8b6a46
+
8b6a46
 		kshname = old_kshname;
8b6a46
-		Flag(FXTRACE) = old_xflag;
8b6a46
+		change_xtrace(old_xflag, false);
8b6a46
 		tp->flag = (tp->flag & ~FINUSE) | old_inuse;
8b6a46
+
8b6a46
 		/*
8b6a46
 		 * Were we deleted while executing? If so, free the
8b6a46
 		 * execution tree. TODO: Unfortunately, the table entry
8b6a46
@@ -1308,8 +1306,11 @@ iosetup(struct ioword *iop, struct tbl *
8b6a46
 	iotmp.name = (iotype == IOHERE) ? NULL : cp;
8b6a46
 	iotmp.flag |= IONAMEXP;
8b6a46
 
8b6a46
-	if (Flag(FXTRACE) == 2)
8b6a46
-		fptreef(shl_out, 0, "%R", &iotmp);
8b6a46
+	if (Flag(FXTRACE)) {
8b6a46
+		change_xtrace(2, false);
8b6a46
+		fptreef(shl_xtrace, 0, "%R", &iotmp);
8b6a46
+		change_xtrace(1, false);
8b6a46
+	}
8b6a46
 
8b6a46
 	switch (iotype) {
8b6a46
 	case IOREAD:
8b6a46
diff -up mksh/main.c.fixtrace mksh/main.c
8b6a46
--- mksh/main.c.fixtrace	2013-05-02 22:22:08.000000000 +0200
8b6a46
+++ mksh/main.c	2013-07-21 20:47:44.000000000 +0200
8b6a46
@@ -332,6 +343,11 @@ main_init(int argc, const char *argv[],
8b6a46
 	 */
8b6a46
 	Flag(FBRACEEXPAND) = 1;
8b6a46
 
8b6a46
+	/*
8b6a46
+	 * Turn on "set -x" inheritance by default.
8b6a46
+	 */
8b6a46
+	Flag(FXTRACEREC) = 1;
8b6a46
+
8b6a46
 #ifndef MKSH_NO_CMDLINE_EDITING
8b6a46
 	/*
8b6a46
 	 * Set edit mode to emacs by default, may be overridden
8b6a46
@@ -1373,7 +1393,7 @@ initio(void)
8b6a46
 	/* force buffer allocation */
8b6a46
 	shf_fdopen(1, SHF_WR, shl_stdout);
8b6a46
 	shf_fdopen(2, SHF_WR, shl_out);
8b6a46
-	shf_fdopen(2, SHF_WR, shl_spare);
8b6a46
+	shf_fdopen(2, SHF_WR, shl_xtrace);
8b6a46
 #ifdef DF
8b6a46
 	if ((lfp = getenv("SDMKSH_PATH")) == NULL) {
8b6a46
 		if ((lfp = getenv("HOME")) == NULL || *lfp != '/')
8b6a46
diff -up mksh/misc.c.fixtrace mksh/misc.c
8b6a46
--- mksh/misc.c.fixtrace	2013-05-02 22:22:09.000000000 +0200
8b6a46
+++ mksh/misc.c	2017-10-10 12:11:30.472249513 +0200
8b6a46
@@ -229,8 +229,12 @@ void
8b6a46
 change_flag(enum sh_flag f, int what, bool newset)
8b6a46
 {
8b6a46
 	unsigned char oldval;
8b6a46
-	unsigned char newval;
8b6a46
+	unsigned char newval = (newset ? 1 : 0);
8b6a46
 
8b6a46
+	if (f == FXTRACE) {
8b6a46
+		change_xtrace(newval, true);
8b6a46
+		return;
8b6a46
+	}
8b6a46
 	oldval = Flag(f);
8b6a46
 	Flag(f) = newval = (newset ? 1 : 0);
8b6a46
 #ifndef MKSH_UNEMPLOYED
8b6a46
@@ -286,6 +290,37 @@ change_flag(enum sh_flag f, int what, bo
8b6a46
 	}
8b6a46
 }
8b6a46
 
8b6a46
+void
8b6a46
+change_xtrace(unsigned char newval, bool dosnapshot)
8b6a46
+{
8b6a46
+	if (!dosnapshot && newval == Flag(FXTRACE))
8b6a46
+		return;
8b6a46
+
8b6a46
+	if (Flag(FXTRACE) == 2) {
8b6a46
+		shf_putc('\n', shl_xtrace);
8b6a46
+		Flag(FXTRACE) = 1;
8b6a46
+		shf_flush(shl_xtrace);
8b6a46
+	}
8b6a46
+
8b6a46
+	if (!dosnapshot && Flag(FXTRACE) == 1)
8b6a46
+		switch (newval) {
8b6a46
+		case 1:
8b6a46
+			return;
8b6a46
+		case 2:
8b6a46
+			goto changed_xtrace;
8b6a46
+		}
8b6a46
+
8b6a46
+	shf_flush(shl_xtrace);
8b6a46
+	if (shl_xtrace->fd != 2)
8b6a46
+		close(shl_xtrace->fd);
8b6a46
+	if (!newval || (shl_xtrace->fd = savefd(2)) == -1)
8b6a46
+		shl_xtrace->fd = 2;
8b6a46
+
8b6a46
+ changed_xtrace:
8b6a46
+	if ((Flag(FXTRACE) = newval) == 2)
8b6a46
+		shf_puts(substitute(str_val(global("PS4")), 0), shl_xtrace);
8b6a46
+}
8b6a46
+
8b6a46
 /*
8b6a46
  * Parse command line and set command arguments. Returns the index of
8b6a46
  * non-option arguments, -1 if there is an error.
8b6a46
@@ -444,8 +479,10 @@ parse_args(const char **argv,
8b6a46
 	    (argv[go.optind][0] == '-' || argv[go.optind][0] == '+') &&
8b6a46
 	    argv[go.optind][1] == '\0') {
8b6a46
 		/* lone - clears -v and -x flags */
8b6a46
-		if (argv[go.optind][0] == '-')
8b6a46
-			Flag(FVERBOSE) = Flag(FXTRACE) = 0;
8b6a46
+		if (argv[go.optind][0] == '-') {
8b6a46
+			Flag(FVERBOSE) = 0;
8b6a46
+			change_xtrace(0, false);
8b6a46
+		}
8b6a46
 		/* set skips lone - or + option */
8b6a46
 		go.optind++;
8b6a46
 	}
8b6a46
diff -up mksh/sh_flags.h.fixtrace mksh/sh_flags.h
8b6a46
--- mksh/sh_flags.h.fixtrace	2013-05-02 22:28:40.000000000 +0200
8b6a46
+++ mksh/sh_flags.h	2017-10-10 12:11:30.472249513 +0200
8b6a46
@@ -45,6 +45,9 @@ FN("gmacs", FGMACS, 0, OF_ANY)
8b6a46
 /* ./.	reading EOF does not exit */
8b6a46
 FN("ignoreeof", FIGNOREEOF, 0, OF_ANY)
8b6a46
 
8b6a46
+/* ./.	inherit -x flag */
8b6a46
+FN("inherit-xtrace", FXTRACEREC, 0, OF_ANY)
8b6a46
+
8b6a46
 /* -i	interactive shell */
8b6a46
 FN("interactive", FTALKING, 'i', OF_CMDLINE)
8b6a46
 
8b6a46
diff -up mksh/sh.h.fixtrace mksh/sh.h
8b6a46
--- mksh/sh.h.fixtrace	2013-05-03 00:00:17.000000000 +0200
8b6a46
+++ mksh/sh.h	2017-10-10 12:11:30.472249513 +0200
8b6a46
@@ -837,7 +837,7 @@ struct temp {
8b6a46
  * stdio and our IO routines
8b6a46
  */
8b6a46
 
8b6a46
-#define shl_spare	(&shf_iob[0])	/* for c_read()/c_print() */
8b6a46
+#define shl_xtrace	(&shf_iob[0])	/* for set -x */
8b6a46
 #define shl_stdout	(&shf_iob[1])
8b6a46
 #define shl_out		(&shf_iob[2])
8b6a46
 #ifdef DF
8b6a46
@@ -1905,6 +1905,7 @@ void initctypes(void);
8b6a46
 size_t option(const char *);
8b6a46
 char *getoptions(void);
8b6a46
 void change_flag(enum sh_flag, int, bool);
8b6a46
+void change_xtrace(unsigned char, bool);
8b6a46
 int parse_args(const char **, int, bool *);
8b6a46
 int getn(const char *, int *);
8b6a46
 int gmatchx(const char *, const char *, bool);