[git commit] hush: make "set -x" output closer to bash

Denys Vlasenko vda.linux at googlemail.com
Fri Jul 27 15:43:39 UTC 2018


commit: https://git.busybox.net/busybox/commit/?id=4b70c926bcbfaf6df6e21c98ea096b0db8629095
branch: https://git.busybox.net/busybox/commit/?id=refs/heads/master

function                                             old     new   delta
print_optionally_squoted                               -     145    +145
run_pipe                                            1902    1919     +17
dump_cmd_in_x_mode                                   142     110     -32
------------------------------------------------------------------------------
(add/remove: 1/0 grow/shrink: 1/1 up/down: 162/-32)           Total: 130 bytes

Signed-off-by: Denys Vlasenko <vda.linux at googlemail.com>
---
 shell/hush.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++--------------
 1 file changed, 60 insertions(+), 18 deletions(-)

diff --git a/shell/hush.c b/shell/hush.c
index e9212cefc..ac8467fb4 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -8030,28 +8030,67 @@ static void execvp_or_die(char **argv)
 }
 
 #if ENABLE_HUSH_MODE_X
+static void print_optionally_squoted(FILE *fp, const char *str)
+{
+	unsigned len;
+	const char *cp;
+
+	cp = str;
+	if (str[0] != '{' && str[0] != '(') for (;;) {
+		if (!*cp) {
+			/* string has no special chars */
+			fputs(str, fp);
+			return;
+		}
+		if (*cp == '\\') break;
+		if (*cp == '\'') break;
+		if (*cp == '"') break;
+		if (*cp == '$') break;
+		if (*cp == '!') break;
+		if (*cp == '*') break;
+		if (*cp == '[') break;
+		if (*cp == ']') break;
+#if ENABLE_HUSH_TICK
+		if (*cp == '`') break;
+#endif
+		if (isspace(*cp)) break;
+		cp++;
+	}
+
+	cp = str;
+	for (;;) {
+		/* print '....' up to EOL or first squote */
+		len = (int)(strchrnul(cp, '\'') - cp);
+		if (len != 0) {
+			fprintf(fp, "'%.*s'", len, cp);
+			cp += len;
+		}
+		if (*cp == '\0')
+			break;
+		/* string contains squote(s), print them as \' */
+		fprintf(fp, "\\'");
+		cp++;
+	}
+}
 static void dump_cmd_in_x_mode(char **argv)
 {
 	if (G_x_mode && argv) {
-		/* We want to output the line in one write op */
-		char *buf, *p;
-		unsigned len;
 		unsigned n;
 
-		len = G.x_mode_depth + 3; /* "+[+++...][ cmd...]\n\0" */
-		n = 0;
-		while (argv[n])
-			len += strlen(argv[n++]) + 1;
-		p = buf = xmalloc(len);
+		/* "+[+++...][ cmd...]\n\0" */
 		n = G.x_mode_depth;
-		do *p++ = '+'; while ((int)(--n) >= 0);
+		do bb_putchar_stderr('+'); while ((int)(--n) >= 0);
 		n = 0;
-		while (argv[n])
-			p += sprintf(p, " %s", argv[n++]);
-		*p++ = '\n';
-		*p = '\0';
-		fputs(buf, stderr);
-		free(buf);
+		while (argv[n]) {
+			if (argv[n][0] == '\0')
+				fputs(" ''", stderr);
+			else {
+				bb_putchar_stderr(' ');
+				print_optionally_squoted(stderr, argv[n]);
+			}
+			n++;
+		}
+		bb_putchar_stderr('\n');
 	}
 }
 #else
@@ -8845,13 +8884,18 @@ static NOINLINE int run_pipe(struct pipe *pi)
 				);
 #if ENABLE_HUSH_MODE_X
 				if (G_x_mode) {
+					char *eq;
 					if (i == 0) {
 						unsigned n = G.x_mode_depth;
 						do
 							bb_putchar_stderr('+');
 						while ((int)(--n) >= 0);
 					}
-					fprintf(stderr, " %s", p);
+					eq = strchrnul(p, '=');
+					fprintf(stderr, " %.*s=", (int)(eq - p), p);
+					if (*eq)
+						print_optionally_squoted(stderr, eq + 1);
+					bb_putchar_stderr('\n');
 				}
 #endif
 				debug_printf_env("set shell var:'%s'->'%s'\n", *argv, p);
@@ -8861,8 +8905,6 @@ static NOINLINE int run_pipe(struct pipe *pi)
 				}
 				i++;
 			}
-			if (G_x_mode)
-				bb_putchar_stderr('\n');
 			/* Redirect error sets $? to 1. Otherwise,
 			 * if evaluating assignment value set $?, retain it.
 			 * Else, clear $?:


More information about the busybox-cvs mailing list