svn commit: trunk/busybox/shell: hush_test/hush-misc

vda at busybox.net vda at busybox.net
Sun Jul 6 10:01:13 UTC 2008


Author: vda
Date: 2008-07-06 03:01:13 -0700 (Sun, 06 Jul 2008)
New Revision: 22664

Log:
hush: support "for if in do done then; do echo $if; done" case

function                                             old     new   delta
done_pipe                                             83      95     +12
parse_stream                                        1758    1764      +6
done_word                                            674     647     -27
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 2/1 up/down: 18/-27)             Total: -9 bytes



Added:
   trunk/busybox/shell/hush_test/hush-misc/for_with_keywords.right
   trunk/busybox/shell/hush_test/hush-misc/for_with_keywords.tests

Modified:
   trunk/busybox/shell/hush.c


Changeset:
Modified: trunk/busybox/shell/hush.c
===================================================================
--- trunk/busybox/shell/hush.c	2008-07-06 07:34:41 UTC (rev 22663)
+++ trunk/busybox/shell/hush.c	2008-07-06 10:01:13 UTC (rev 22664)
@@ -1344,7 +1344,7 @@
 		if (redir->dup == -1) {
 			char *p;
 			mode = redir_table[redir->rd_type].mode;
-//TODO: check redir to names like '\\'
+//TODO: check redir for names like '\\'
 			p = expand_string_to_string(redir->rd_filename);
 			openfd = open_or_warn(p, mode);
 			free(p);
@@ -2854,17 +2854,7 @@
 			continue;
 		debug_printf("found reserved word %s, res %d\n", r->literal, r->res);
 		if (r->flag == 0) { /* '!' */
-#if ENABLE_HUSH_LOOPS
-			if (ctx->ctx_res_w == RES_IN) {
-				/* 'for a in ! a b c; ...' - ! isn't a keyword here */
-				break;
-			}
-#endif
-			if (ctx->ctx_inverted /* bash doesn't accept '! ! true' */
-#if ENABLE_HUSH_LOOPS
-			 || ctx->ctx_res_w == RES_FOR /* example: 'for ! a' */
-#endif
-			) {
+			if (ctx->ctx_inverted) { /* bash doesn't accept '! ! true' */
 				syntax(NULL);
 				IF_HAS_KEYWORDS(ctx->ctx_res_w = RES_SNTX;)
 			}
@@ -2885,7 +2875,7 @@
 			*new = *ctx;   /* physical copy */
 			initialize_context(ctx);
 			ctx->stack = new;
-		} else if (ctx->ctx_res_w == RES_NONE || !(ctx->old_flag & (1 << r->res))) {
+		} else if (/*ctx->ctx_res_w == RES_NONE ||*/ !(ctx->old_flag & (1 << r->res))) {
 			syntax(NULL);
 			ctx->ctx_res_w = RES_SNTX;
 			return 1;
@@ -2940,7 +2930,10 @@
 			return 1;
 		}
 #if HAS_KEYWORDS
-		if (!child->argv) { /* if it's the first word... */
+		if (!child->argv /* if it's the first word... */
+		 && ctx->ctx_res_w != RES_FOR /* ...not after FOR or IN */
+		 && ctx->ctx_res_w != RES_IN
+		) {
 			debug_printf_parse(": checking '%s' for reserved-ness\n", word->data);
 			if (reserved_word(word, ctx)) {
 				o_reset(word);
@@ -2953,9 +2946,9 @@
 		if (word->nonnull /* word had "xx" or 'xx' at least as part of it. */
 		 /* optimization: and if it's ("" or '') or ($v... or `cmd`...): */
 		 && (word->data[0] == '\0' || word->data[0] == SPECIAL_VAR_SYMBOL)
-		 /* (otherwise it's "abc".... and is already safe) */
+		 /* (otherwise it's known to be not empty and is already safe) */
 		) {
-			/* but exclude "$@" - it expands to no word despite "" */
+			/* exclude "$@" - it can expand to no word despite "" */
 			char *p = word->data;
 			while (p[0] == SPECIAL_VAR_SYMBOL
 			    && (p[1] & 0x7f) == '@'
@@ -2964,7 +2957,9 @@
 				p += 3;
 			}
 			if (p == word->data || p[0] != '\0') {
-				/* Insert "empty variable" reference, this makes
+				/* saw no "$@", or not only "$@" but some
+				 * real text is there too */
+				/* insert "empty variable" reference, this makes
 				 * e.g. "", $empty"" etc to not disappear */
 				o_addchr(word, SPECIAL_VAR_SYMBOL);
 				o_addchr(word, SPECIAL_VAR_SYMBOL);
@@ -2979,8 +2974,13 @@
 
 #if ENABLE_HUSH_LOOPS
 	/* Force FOR to have just one word (variable name) */
-	if (ctx->ctx_res_w == RES_FOR)
+	/* NB: basically, this makes hush see "for v in ..." syntax as if
+	 * as it is "for v; in ...". FOR and IN become two pipe structs
+	 * in parse tree. */
+	if (ctx->ctx_res_w == RES_FOR) {
+//TODO: check that child->argv[0] is a valid variable name!
 		done_pipe(ctx, PIPE_SEQ);
+	}
 #endif
 	debug_printf_parse("done_word return 0\n");
 	return 0;
@@ -3030,19 +3030,28 @@
 	debug_printf_parse("done_pipe entered, followup %d\n", type);
 	not_null = done_command(ctx);  /* implicit closure of previous command */
 	ctx->pipe->followup = type;
-	IF_HAS_KEYWORDS(ctx->pipe->res_word = ctx->ctx_res_w;)
 	IF_HAS_KEYWORDS(ctx->pipe->pi_inverted = ctx->ctx_inverted;)
 	IF_HAS_KEYWORDS(ctx->ctx_inverted = 0;)
+	IF_HAS_KEYWORDS(ctx->pipe->res_word = ctx->ctx_res_w;)
 	/* Without this check, even just <enter> on command line generates
 	 * tree of three NOPs (!). Which is harmless but annoying.
 	 * IOW: it is safe to do it unconditionally.
-	 * RES_IN case is for "for a in; do ..." (empty IN set)
-	 * to work. */
-	if (not_null USE_HUSH_LOOPS(|| ctx->pipe->res_word == RES_IN)) {
+	 * RES_NONE case is for "for a in; do ..." (empty IN set)
+	 * to work, possibly other cases too. */
+	if (not_null IF_HAS_KEYWORDS(|| ctx->ctx_res_w != RES_NONE)) {
 		struct pipe *new_p = new_pipe();
 		ctx->pipe->next = new_p;
 		ctx->pipe = new_p;
 		ctx->child = NULL; /* needed! */
+		/* RES_IF, RES_WHILE etc are "sticky" -
+		 * they remain set for commands inside if/while.
+		 * This is used to control execution.
+		 * RES_FOR and RES_IN are NOT sticky (needed to support
+		 * cases where variable or value happens to match a keyword):
+		 */
+		if (ctx->ctx_res_w == RES_FOR
+		 || ctx->ctx_res_w == RES_IN)
+			ctx->ctx_res_w = RES_NONE;
 		/* Create the memory for child, roughly:
 		 * ctx->pipe->progs = new struct child_prog;
 		 * ctx->pipe->progs[0].family = ctx->pipe;
@@ -3444,7 +3453,7 @@
 	return 0;
 }
 
-/* Scan input, call done_word() whenever full IFS delemited word was seen.
+/* Scan input, call done_word() whenever full IFS delimited word was seen.
  * call done_pipe if '\n' was seen (and end_trigger != NULL)
  * Return if (non-quoted) char in end_trigger was seen; or on parse error. */
 /* Return code is 0 if end_trigger char is met,
@@ -3517,7 +3526,9 @@
 //err chk?
 					done_pipe(ctx, PIPE_SEQ);
 				}
-				if (!HAS_KEYWORDS IF_HAS_KEYWORDS(|| ctx->ctx_res_w == RES_NONE)) {
+				if (!HAS_KEYWORDS
+				 IF_HAS_KEYWORDS(|| (ctx->ctx_res_w == RES_NONE && ctx->old_flag == 0))
+				) {
 					debug_printf_parse("parse_stream return 0: end_trigger char found\n");
 					return 0;
 				}

Added: trunk/busybox/shell/hush_test/hush-misc/for_with_keywords.right
===================================================================
--- trunk/busybox/shell/hush_test/hush-misc/for_with_keywords.right	                        (rev 0)
+++ trunk/busybox/shell/hush_test/hush-misc/for_with_keywords.right	2008-07-06 10:01:13 UTC (rev 22664)
@@ -0,0 +1,4 @@
+do
+done
+then
+OK: 0

Added: trunk/busybox/shell/hush_test/hush-misc/for_with_keywords.tests
===================================================================
--- trunk/busybox/shell/hush_test/hush-misc/for_with_keywords.tests	                        (rev 0)
+++ trunk/busybox/shell/hush_test/hush-misc/for_with_keywords.tests	2008-07-06 10:01:13 UTC (rev 22664)
@@ -0,0 +1,2 @@
+for if in do done then; do echo $if; done
+echo OK: $?


Property changes on: trunk/busybox/shell/hush_test/hush-misc/for_with_keywords.tests
___________________________________________________________________
Name: svn:executable
   + *




More information about the busybox-cvs mailing list