svn commit: [25953] trunk/busybox/shell

vda at busybox.net vda at busybox.net
Sat Apr 4 22:47:51 UTC 2009


Author: vda
Date: 2009-04-04 22:47:50 +0000 (Sat, 04 Apr 2009)
New Revision: 25953

Log:
hush: preparatory patch for NOMMU-safe { list } handling.

function                                             old     new   delta
o_addblock                                             -      58     +58
o_addstr_with_NUL                                      -      27     +27
builtin_exit                                          47      49      +2
run_list                                            2020    2018      -2
o_addstrauto                                          27       -     -27
parse_stream                                        1508    1461     -47
o_addstr                                              58       -     -58
------------------------------------------------------------------------------
(add/remove: 2/2 grow/shrink: 1/2 up/down: 87/-134)           Total: -47 bytes



Modified:
   trunk/busybox/shell/hush.c


Changeset:
Modified: trunk/busybox/shell/hush.c
===================================================================
--- trunk/busybox/shell/hush.c	2009-04-04 20:34:22 UTC (rev 25952)
+++ trunk/busybox/shell/hush.c	2009-04-04 22:47:50 UTC (rev 25953)
@@ -73,11 +73,19 @@
 #if ENABLE_HUSH_CASE
 #include <fnmatch.h>
 #endif
-
 #include "math.h"
 
-#define HUSH_VER_STR "0.92"
+#ifdef WANT_TO_TEST_NOMMU
+# undef BB_MMU
+# undef USE_FOR_NOMMU
+# undef USE_FOR_MMU
+# define BB_MMU 0
+# define USE_FOR_NOMMU(...) __VA_ARGS__
+# define USE_FOR_MMU(...)
+#endif
 
+#define HUSH_VER_STR "0.93"
+
 #if defined SINGLE_APPLET_MAIN
 /* STANDALONE does not make sense, and won't compile */
 #undef CONFIG_FEATURE_SH_STANDALONE
@@ -298,6 +306,45 @@
 	RES_SNTX
 } reserved_style;
 
+typedef struct o_string {
+	char *data;
+	int length; /* position where data is appended */
+	int maxlen;
+	/* Protect newly added chars against globbing
+	 * (by prepending \ to *, ?, [, \) */
+	smallint o_escape;
+	smallint o_glob;
+	smallint nonnull;
+	smallint has_empty_slot;
+	smallint o_assignment; /* 0:maybe, 1:yes, 2:no */
+} o_string;
+enum {
+	MAYBE_ASSIGNMENT = 0,
+	DEFINITELY_ASSIGNMENT = 1,
+	NOT_ASSIGNMENT = 2,
+	WORD_IS_KEYWORD = 3, /* not assigment, but next word may be: "if v=xyz cmd;" */
+};
+/* Used for initialization: o_string foo = NULL_O_STRING; */
+#define NULL_O_STRING { NULL }
+
+/* I can almost use ordinary FILE*.  Is open_memstream() universally
+ * available?  Where is it documented? */
+typedef struct in_str {
+	const char *p;
+	/* eof_flag=1: last char in ->p is really an EOF */
+	char eof_flag; /* meaningless if ->p == NULL */
+	char peek_buf[2];
+#if ENABLE_HUSH_INTERACTIVE
+	smallint promptme;
+	smallint promptmode; /* 0: PS1, 1: PS2 */
+#endif
+	FILE *file;
+	int (*get) (struct in_str *);
+	int (*peek) (struct in_str *);
+} in_str;
+#define i_getch(input) ((input)->get(input))
+#define i_peek(input) ((input)->peek(input))
+
 struct redir_struct {
 	struct redir_struct *next;
 	char *rd_filename;          /* filename */
@@ -311,8 +358,11 @@
 	int assignment_cnt;         /* how many argv[i] are assignments? */
 	smallint is_stopped;        /* is the command currently running? */
 	smallint grp_type;          /* GRP_xxx */
-	struct pipe *group;         /* if non-NULL, this "prog" is {} group,
-	                             * subshell, or a compound statement */
+	struct pipe *group;         /* if non-NULL, this "command" is { list },
+	                             * ( list ), or a compound statement */
+#if !BB_MMU
+	char *group_as_string;
+#endif
 	char **argv;                /* command name and arguments */
 	struct redir_struct *redirects; /* I/O redirections */
 };
@@ -354,6 +404,9 @@
 	struct command *command;
 	/* last redirect in command->redirects list */
 	struct redir_struct *pending_redirect;
+#if !BB_MMU
+	o_string as_string;
+#endif
 #if HAS_KEYWORDS
 	smallint ctx_res_w;
 	smallint ctx_inverted; /* "! cmd | cmd" */
@@ -389,46 +442,7 @@
 	smallint flg_read_only;
 };
 
-typedef struct o_string {
-	char *data;
-	int length; /* position where data is appended */
-	int maxlen;
-	/* Protect newly added chars against globbing
-	 * (by prepending \ to *, ?, [, \) */
-	smallint o_escape;
-	smallint o_glob;
-	smallint nonnull;
-	smallint has_empty_slot;
-	smallint o_assignment; /* 0:maybe, 1:yes, 2:no */
-} o_string;
 enum {
-	MAYBE_ASSIGNMENT = 0,
-	DEFINITELY_ASSIGNMENT = 1,
-	NOT_ASSIGNMENT = 2,
-	WORD_IS_KEYWORD = 3, /* not assigment, but next word may be: "if v=xyz cmd;" */
-};
-/* Used for initialization: o_string foo = NULL_O_STRING; */
-#define NULL_O_STRING { NULL }
-
-/* I can almost use ordinary FILE*.  Is open_memstream() universally
- * available?  Where is it documented? */
-typedef struct in_str {
-	const char *p;
-	/* eof_flag=1: last char in ->p is really an EOF */
-	char eof_flag; /* meaningless if ->p == NULL */
-	char peek_buf[2];
-#if ENABLE_HUSH_INTERACTIVE
-	smallint promptme;
-	smallint promptmode; /* 0: PS1, 1: PS2 */
-#endif
-	FILE *file;
-	int (*get) (struct in_str *);
-	int (*peek) (struct in_str *);
-} in_str;
-#define i_getch(input) ((input)->get(input))
-#define i_peek(input) ((input)->peek(input))
-
-enum {
 	BC_BREAK = 1,
 	BC_CONTINUE = 2,
 };
@@ -1359,6 +1373,11 @@
 	memset(o, 0, sizeof(*o));
 }
 
+static ALWAYS_INLINE void o_free_unsafe(o_string *o)
+{
+	free(o->data);
+}
+
 static void o_grow_by(o_string *o, int len)
 {
 	if (o->length + len > o->maxlen) {
@@ -1376,7 +1395,7 @@
 	o->data[o->length] = '\0';
 }
 
-static void o_addstr(o_string *o, const char *str, int len)
+static void o_addblock(o_string *o, const char *str, int len)
 {
 	o_grow_by(o, len);
 	memcpy(&o->data[o->length], str, len);
@@ -1384,13 +1403,20 @@
 	o->data[o->length] = '\0';
 }
 
-static void o_addstrauto(o_string *o, const char *str)
+#if !BB_MMU
+static void o_addstr(o_string *o, const char *str)
 {
-	o_addstr(o, str, strlen(str) + 1);
+	o_addblock(o, str, strlen(str));
 }
+#endif
 
-static void o_addstr_duplicate_backslash(o_string *o, const char *str, int len)
+static void o_addstr_with_NUL(o_string *o, const char *str)
 {
+	o_addblock(o, str, strlen(str) + 1);
+}
+
+static void o_addblock_duplicate_backslash(o_string *o, const char *str, int len)
+{
 	while (len) {
 		o_addchr(o, *str);
 		if (*str++ == '\\'
@@ -1438,7 +1464,7 @@
 static void o_addQstr(o_string *o, const char *str, int len)
 {
 	if (!o->o_escape) {
-		o_addstr(o, str, len);
+		o_addblock(o, str, len);
 		return;
 	}
 	while (len) {
@@ -1447,7 +1473,7 @@
 		int ordinary_cnt = strcspn(str, "*?[\\");
 		if (ordinary_cnt > len) /* paranoia */
 			ordinary_cnt = len;
-		o_addstr(o, str, ordinary_cnt);
+		o_addblock(o, str, ordinary_cnt);
 		if (ordinary_cnt == len)
 			return;
 		str += ordinary_cnt;
@@ -1582,7 +1608,7 @@
 		char **argv = globdata.gl_pathv;
 		o->length = pattern - o->data; /* "forget" pattern */
 		while (1) {
-			o_addstrauto(o, *argv);
+			o_addstr_with_NUL(o, *argv);
 			n = o_save_ptr_helper(o, n);
 			argv++;
 			if (!*argv)
@@ -1635,7 +1661,14 @@
 static int process_command_subs(o_string *dest, const char *s);
 #endif
 static char *expand_string_to_string(const char *str);
-static int parse_stream_dquoted(o_string *dest, struct in_str *input, int dquote_end);
+#if BB_MMU
+#define parse_stream_dquoted(ctx, dest, input, dquote_end) \
+	parse_stream_dquoted(dest, input, dquote_end)
+#endif
+static int parse_stream_dquoted(struct parse_context *ctx,
+		o_string *dest,
+		struct in_str *input,
+		int dquote_end);
 
 /* expand_strvec_to_strvec() takes a list of strings, expands
  * all variable references within and returns a pointer to
@@ -1657,7 +1690,7 @@
 			if (output->o_escape || !output->o_glob)
 				o_addQstr(output, str, word_len);
 			else /* protect backslashes against globbing up :) */
-				o_addstr_duplicate_backslash(output, str, word_len);
+				o_addblock_duplicate_backslash(output, str, word_len);
 			str += word_len;
 		}
 		if (!*str)  /* EOL - do not finalize word */
@@ -1701,7 +1734,7 @@
 #if ENABLE_SH_MATH_SUPPORT
 		char arith_buf[sizeof(arith_t)*3 + 2];
 #endif
-		o_addstr(output, arg, p - arg);
+		o_addblock(output, arg, p - arg);
 		debug_print_list("expand_vars_to_list[1]", output, n);
 		arg = ++p;
 		p = strchr(p, SPECIAL_VAR_SYMBOL);
@@ -1825,7 +1858,7 @@
 				o_string dest = NULL_O_STRING;
 
 				setup_string_in_str(&input, arg);
-				parse_stream_dquoted(&dest, &input, EOF);
+				parse_stream_dquoted(NULL, &dest, &input, EOF);
 				//bb_error_msg("'%s' -> '%s'", arg, dest.data);
 				exp_str = expand_string_to_string(dest.data);
 				//bb_error_msg("'%s' -> '%s'", dest.data, exp_str);
@@ -1958,7 +1991,7 @@
 		debug_print_list("expand_vars_to_list[a]", output, n);
 		/* this part is literal, and it was already pre-quoted
 		 * if needed (much earlier), do not use o_addQstr here! */
-		o_addstrauto(output, arg);
+		o_addstr_with_NUL(output, arg);
 		debug_print_list("expand_vars_to_list[b]", output, n);
 	} else if (output->length == o_get_last_ptr(output, n) /* expansion is empty */
 	 && !(ored_ch & 0x80) /* and all vars were not quoted. */
@@ -2148,6 +2181,10 @@
 			debug_printf_clean("%s   end group\n", indenter(indent));
 			command->group = NULL;
 		}
+#if !BB_MMU
+		free(command->group_as_string);
+		command->group_as_string = NULL;
+#endif
 		for (r = command->redirects; r; r = rnext) {
 			debug_printf_clean("%s   redirect %d%s", indenter(indent), r->fd, redir_table[r->rd_type].descrip);
 			if (r->dup == -1) {
@@ -2215,9 +2252,7 @@
 		char **argv, int assignment_cnt,
 		char **argv_expanded)
 {
-	int rcode;
 	char **new_env;
-	const struct built_in_command *x;
 
 	/* Case when we are here: ... | var=val | ... */
 	if (!argv[assignment_cnt])
@@ -2251,12 +2286,17 @@
 	 * easier to waste a few CPU cycles than it is to figure out
 	 * if this is one of those cases.
 	 */
-	for (x = bltins; x != &bltins[ARRAY_SIZE(bltins)]; x++) {
-		if (strcmp(argv[0], x->cmd) == 0) {
-			debug_printf_exec("running builtin '%s'\n", argv[0]);
-			rcode = x->function(argv);
-			fflush(NULL);
-			_exit(rcode);
+	{
+		int rcode;
+		const struct built_in_command *x;
+		for (x = bltins; x != &bltins[ARRAY_SIZE(bltins)]; x++) {
+			if (strcmp(argv[0], x->cmd) == 0) {
+				debug_printf_exec("running builtin '%s'\n",
+						argv[0]);
+				rcode = x->function(argv);
+				fflush(NULL);
+				_exit(rcode);
+			}
 		}
 	}
 #endif
@@ -2320,8 +2360,8 @@
 		 * since this process is about to exit */
 		_exit(rcode);
 #else
-//TODO: re-exec "hush -c command->group_as_a_string"
-		bb_error_msg_and_die("nested lists are not supported on NOMMU");
+		bb_error_msg_and_die("NOMMU TODO: re-exec '%s'",
+				command->group_as_string);
 #endif
 	}
 
@@ -3587,6 +3627,13 @@
 		old = ctx->stack;
 		old->command->group = ctx->list_head;
 		old->command->grp_type = GRP_NORMAL;
+#if !BB_MMU
+		o_addstr(&old->as_string, ctx->as_string.data);
+		o_free_unsafe(&ctx->as_string);
+		old->command->group_as_string = xstrdup(old->as_string.data);
+		debug_printf_parse("pop, remembering as:'%s'\n",
+				old->command->group_as_string);
+#endif
 		*ctx = *old;   /* physical copy */
 		free(old);
 	}
@@ -3739,7 +3786,13 @@
 	return num;
 }
 
-static struct pipe *parse_stream(struct in_str *input, int end_trigger);
+#if BB_MMU
+#define parse_stream(pstring, input, end_trigger) \
+	parse_stream(input, end_trigger)
+#endif
+static struct pipe *parse_stream(char **pstring,
+		struct in_str *input,
+		int end_trigger);
 static void parse_and_run_string(const char *s);
 
 #if ENABLE_HUSH_TICK
@@ -3864,15 +3917,33 @@
 		endch = ')';
 		command->grp_type = GRP_SUBSHELL;
 	}
-	pipe_list = parse_stream(input, endch);
-	/* empty ()/{} or parse error? */
-	if (!pipe_list || pipe_list == ERR_PTR) {
-		syntax(NULL);
-		debug_printf_parse("parse_group return 1: "
-			"parse_stream returned %p\n", pipe_list);
-		return 1;
+	{
+#if !BB_MMU
+		char *as_string = NULL;
+#endif
+		pipe_list = parse_stream(&as_string, input, endch);
+#if !BB_MMU
+		if (as_string)
+			o_addstr(&ctx->as_string, as_string);
+#endif
+		/* empty ()/{} or parse error? */
+		if (!pipe_list || pipe_list == ERR_PTR) {
+#if !BB_MMU
+			free(as_string);
+#endif
+			syntax(NULL);
+			debug_printf_parse("parse_group return 1: "
+				"parse_stream returned %p\n", pipe_list);
+			return 1;
+		}
+		command->group = pipe_list;
+#if !BB_MMU
+		as_string[strlen(as_string) - 1] = '\0'; /* plink ')' or '}' */
+		command->group_as_string = as_string;
+		debug_printf_parse("end of group, remembering as:'%s'\n",
+				command->group_as_string);
+#endif
 	}
-	command->group = pipe_list;
 	debug_printf_parse("parse_group return 0\n");
 	return 0;
 	/* command remains "open", available for possible redirects */
@@ -4151,14 +4222,24 @@
 	return 0;
 }
 
-static int parse_stream_dquoted(o_string *dest,
-		struct in_str *input, int dquote_end)
+#if BB_MMU
+#define parse_stream_dquoted(ctx, dest, input, dquote_end) \
+	parse_stream_dquoted(dest, input, dquote_end)
+#endif
+static int parse_stream_dquoted(struct parse_context *ctx,
+		o_string *dest,
+		struct in_str *input,
+		int dquote_end)
 {
 	int ch;
 	int next;
 
  again:
 	ch = i_getch(input);
+#if !BB_MMU
+	if (ctx && ch != EOF)
+		o_addchr(&ctx->as_string, ch);
+#endif
 	if (ch == dquote_end) { /* may be only '"' or EOF */
 		dest->nonnull = 1;
 		if (dest->o_assignment == NOT_ASSIGNMENT)
@@ -4237,15 +4318,13 @@
  * reset parsing machinery and start parsing anew,
  * or return ERR_PTR.
  */
-static struct pipe *parse_stream(struct in_str *input, int end_trigger)
+static struct pipe *parse_stream(char **pstring,
+		struct in_str *input,
+		int end_trigger)
 {
 	struct parse_context ctx;
 	o_string dest = NULL_O_STRING;
-	int redir_fd;
-	int next;
 	int is_in_dquote;
-	int ch;
-	redir_type redir_style;
 
 	/* Double-quote state is handled in the state variable is_in_dquote.
 	 * A single-quote triggers a bypass of the main loop until its mate is
@@ -4268,15 +4347,18 @@
 	while (1) {
 		const char *is_ifs;
 		const char *is_special;
+		int ch;
+		int next;
+		int redir_fd;
+		redir_type redir_style;
 
 		if (is_in_dquote) {
-			if (parse_stream_dquoted(&dest, input, '"')) {
+			if (parse_stream_dquoted(&ctx, &dest, input, '"')) {
 				goto parse_error;
 			}
 			/* We reached closing '"' */
 			is_in_dquote = 0;
 		}
-		next = '\0';
 		ch = i_getch(input);
 		debug_printf_parse(": ch=%c (%d) escape=%d\n",
 						ch, ch, dest.o_escape);
@@ -4287,8 +4369,9 @@
 			}
 			o_free(&dest);
 			done_pipe(&ctx, PIPE_SEQ);
+			pi = ctx.list_head;
 			/* If we got nothing... */
-			pi = ctx.list_head;
+// TODO: test script consisting of just "&"
 			if (pi->num_cmds == 0
 			    IF_HAS_KEYWORDS( && pi->res_word == RES_NONE)
 			) {
@@ -4296,12 +4379,18 @@
 				pi = NULL;
 			}
 			debug_printf_parse("parse_stream return %p\n", pi);
+#if !BB_MMU
+			debug_printf_parse("as_string '%s'\n", ctx.as_string.data);
+			if (pstring)
+				*pstring = ctx.as_string.data;
+			else
+				o_free_unsafe(&ctx.as_string);
+#endif
 			return pi;
 		}
-		if (ch != '\n') {
-			next = i_peek(input);
-		}
-
+#if !BB_MMU
+		o_addchr(&ctx.as_string, ch);
+#endif
 		is_ifs = strchr(G.ifs, ch);
 		is_special = strchr("<>;&|(){}#'" /* special outside of "str" */
 				"\\$\"" USE_HUSH_TICK("`") /* always special */
@@ -4356,6 +4445,13 @@
 						"end_trigger char found\n",
 						ctx.list_head);
 				o_free(&dest);
+#if !BB_MMU
+				debug_printf_parse("as_string '%s'\n", ctx.as_string.data);
+				if (pstring)
+					*pstring = ctx.as_string.data;
+				else
+					o_free_unsafe(&ctx.as_string);
+#endif
 				return ctx.list_head;
 			}
 		}
@@ -4368,6 +4464,11 @@
 			dest.o_assignment = NOT_ASSIGNMENT;
 		}
 
+		next = '\0';
+		if (ch != '\n') {
+			next = i_peek(input);
+		}
+
 		switch (ch) {
 		case '#':
 			if (dest.length == 0) {
@@ -4601,6 +4702,9 @@
 			debug_print_tree(pctx->list_head, 0);
 			free_pipe_list(pctx->list_head, 0);
 			debug_printf_clean("freed list %p\n", pctx->list_head);
+#if !BB_MMU
+			o_free_unsafe(&pctx->as_string);
+#endif
 			IF_HAS_KEYWORDS(p2 = pctx->stack;)
 			if (pctx != &ctx) {
 				free(pctx);
@@ -4612,8 +4716,13 @@
 		/* If we are not in top-level parse, we return,
 		 * our caller will propagate error.
 		 */
-		if (end_trigger != ';')
+		if (end_trigger != ';') {
+#if !BB_MMU
+			if (pstring)
+				*pstring = NULL;
+#endif
 			return ERR_PTR;
+		}
 		/* Discard cached input, force prompt */
 		input->p = NULL;
 		USE_HUSH_INTERACTIVE(input->promptme = 1;)
@@ -4621,7 +4730,7 @@
 	}
 }
 
-/* Execiting from string: eval, sh -c '...'
+/* Executing from string: eval, sh -c '...'
  *          or from file: /etc/profile, . file, sh <script>, sh (intereactive)
  * end_trigger controls how often we stop parsing
  * NUL: parse all, execute, return
@@ -4632,7 +4741,7 @@
 	while (1) {
 		struct pipe *pipe_list;
 
-		pipe_list = parse_stream(inp, end_trigger);
+		pipe_list = parse_stream(NULL, inp, end_trigger);
 		if (!pipe_list) /* EOF */
 			break;
 		debug_print_tree(pipe_list, 0);



More information about the busybox-cvs mailing list