svn commit: trunk/busybox/shell

vda at busybox.net vda at busybox.net
Thu May 17 14:38:17 UTC 2007


Author: vda
Date: 2007-05-17 07:38:17 -0700 (Thu, 17 May 2007)
New Revision: 18641

Log:
hush: consolidated variable expansion for assignments and "normal" one.
-435 bytes. Tested against testsuite.


Modified:
   trunk/busybox/shell/hush.c


Changeset:
Modified: trunk/busybox/shell/hush.c
===================================================================
--- trunk/busybox/shell/hush.c	2007-05-17 13:02:41 UTC (rev 18640)
+++ trunk/busybox/shell/hush.c	2007-05-17 14:38:17 UTC (rev 18641)
@@ -444,8 +444,9 @@
 int checkjobs_and_fg_shell(struct pipe* fg_pipe); /* never called */
 #endif
 /*     local variable support */
-static char **do_variable_expansion(char **argv);
-static char *insert_var_value(char *inp);
+static char **expand_variables_to_list(char **argv);
+/* used for expansion of right hand of assignments */
+static char *expand_variables_to_string(const char *str);
 static const char *get_local_var(const char *var);
 static int set_local_var(const char *s, int flg_export);
 static void unset_local_var(const char *name);
@@ -1271,7 +1272,7 @@
 		debug_printf_exec("pid %d environment modification: %s\n",
 				getpid(), argv[i]);
 // FIXME: vfork case??
-		p = insert_var_value(argv[i]);
+		p = expand_variables_to_string(argv[i]);
 		putenv(p == argv[i] ? xstrdup(p) : p);
 	}
 	argv += i;
@@ -1282,7 +1283,7 @@
 		_exit(EXIT_SUCCESS);
 	}
 
-	argv = do_variable_expansion(argv);
+	argv = expand_variables_to_list(argv);
 
 	/*
 	 * Check if the command matches any of the builtins.
@@ -1667,7 +1668,7 @@
 					export_me = 1;
 				}
 				free(name);
-				p = insert_var_value(argv[i]);
+				p = expand_variables_to_string(argv[i]);
 				set_local_var(p, export_me);
 				if (p != argv[i])
 					free(p);
@@ -1675,7 +1676,7 @@
 			return EXIT_SUCCESS;   /* don't worry about errors in set_local_var() yet */
 		}
 		for (i = 0; is_assignment(argv[i]); i++) {
-			p = insert_var_value(argv[i]);
+			p = expand_variables_to_string(argv[i]);
 			if (p != argv[i]) {
 				//sp: child->sp--;
 				putenv(p);
@@ -1698,7 +1699,7 @@
 				setup_redirects(child, squirrel);
 				debug_printf_exec(": builtin '%s' '%s'...\n", x->cmd, argv[i+1]);
 				//sp: if (child->sp) /* btw we can do it unconditionally... */
-				argv_expanded = do_variable_expansion(argv + i);
+				argv_expanded = expand_variables_to_list(argv + i);
 				rcode = x->function(argv_expanded);
 				free(argv_expanded);
 				restore_redirects(squirrel);
@@ -1714,7 +1715,7 @@
 				save_nofork_data(&nofork_save);
 				argv_expanded = argv + i;
 				//sp: if (child->sp)
-				argv_expanded = do_variable_expansion(argv + i);
+				argv_expanded = expand_variables_to_list(argv + i);
 				debug_printf_exec(": run_nofork_applet '%s' '%s'...\n", argv_expanded[0], argv_expanded[1]);
 				rcode = run_nofork_applet_prime(&nofork_save, a, argv_expanded);
 				free(argv_expanded);
@@ -1991,7 +1992,7 @@
 				if (!pi->next->progs->argv)
 					continue;
 				/* create list of variable values */
-				for_list = do_variable_expansion(pi->next->progs->argv);
+				for_list = expand_variables_to_list(pi->next->progs->argv);
 				for_lcur = for_list;
 				for_varname = pi->progs->argv[0];
 				pi->progs->argv[0] = NULL;
@@ -2251,8 +2252,7 @@
 	return gr;
 }
 
-
-/* do_variable_expansion() takes a list of strings, expands
+/* expand_variables_to_list() takes a list of strings, expands
  * all variable references within and returns a pointer to
  * a list of expanded strings, possibly with larger number
  * of strings. (Think VAR="a b"; echo $VAR).
@@ -2371,8 +2371,11 @@
  * 'echo -$*-'. If you play here, you must run testsuite afterwards! */
 /* NB: another bug is that we cannot detect empty strings yet:
  * "" or $empty"" expands to zero words, has to expand to empty word */
-static int expand_vars_to_list(char **list, int n, char **posp, char *arg)
+static int expand_vars_to_list(char **list, int n, char **posp, char *arg, char or_mask)
 {
+	/* or_mask is either 0 (normal case) or 0x80
+	 * (expansion of right-hand side of assignment == 1-element expand) */
+
 	char first_ch, ored_ch;
 	int i;
 	const char *val;
@@ -2392,7 +2395,7 @@
 		arg = ++p;
 		p = strchr(p, SPECIAL_VAR_SYMBOL);
 
-		first_ch = arg[0];
+		first_ch = arg[0] | or_mask; /* forced to "quoted" if or_mask = 0x80 */
 		ored_ch |= first_ch;
 		val = NULL;
 		switch (first_ch & 0x7f) {
@@ -2427,7 +2430,10 @@
 						list[n++] = pos;
 					}
 				}
-			} else if (first_ch == ('@'|0x80)) { /* quoted $@ */
+			} else
+			/* If or_mask is nonzero, we handle assignment 'a=....$@.....'
+			 * and in this case should theat it like '$*' */
+			if (first_ch == ('@'|0x80) && !or_mask) { /* quoted $@ */
 				while (1) {
 					strcpy(pos, global_argv[i]);
 					pos += strlen(global_argv[i]);
@@ -2490,7 +2496,7 @@
 	return n;
 }
 
-static char **do_variable_expansion(char **argv)
+static char **expand_variables(char **argv, char or_mask)
 {
 	int n;
 	int count = 1;
@@ -2515,9 +2521,9 @@
 	n = 0;
 	v = argv;
 	while (*v)
-		n = expand_vars_to_list(list, n, &pos, *v++);
+		n = expand_vars_to_list(list, n, &pos, *v++, or_mask);
 
-	if(n) debug_printf_expand("finalized list[%d]=%p '%s' "
+	if (n) debug_printf_expand("finalized list[%d]=%p '%s' "
 		"strlen=%d next=%p pos=%p\n", n-1, list[n-1], list[n-1],
 		strlen(list[n-1]), list[n-1] + strlen(list[n-1]) + 1, pos);
 	list[n] = NULL;
@@ -2538,80 +2544,26 @@
 	return list;
 }
 
+static char **expand_variables_to_list(char **argv)
+{
+	return expand_variables(argv, 0);
+}
 
-static char *insert_var_value(char *inp)
+static char *expand_variables_to_string(const char *str)
 {
-	int res_str_len = 0;
-	int len;
-	int done = 0;
-	int i;
-	const char *p1;
-	char *p, *p2;
-	char *res_str = NULL;
+	char *argv[2], **list;
 
-	while ((p = strchr(inp, SPECIAL_VAR_SYMBOL))) {
-		if (p != inp) {
-			len = p - inp;
-			res_str = xrealloc(res_str, (res_str_len + len));
-			strncpy((res_str + res_str_len), inp, len);
-			res_str_len += len;
-		}
-		inp = ++p;
-		p = strchr(inp, SPECIAL_VAR_SYMBOL);
-		*p = '\0';
-
-		switch (inp[0]) {
-		case '$':
-			/* FIXME: (echo $$) should still print pid of main shell */
-			p1 = utoa(getpid());
-			break;
-		case '!':
-			p1 = last_bg_pid ? utoa(last_bg_pid) : (char*)"";
-			break;
-		case '?':
-			p1 = utoa(last_return_code);
-			break;
-		case '#':
-			p1 = utoa(global_argc ? global_argc-1 : 0);
-			break;
-		case '*':
-		case '@': /* FIXME: we treat $@ as $* for now */
-			len = 1;
-			for (i = 1; i < global_argc; i++)
-				len += strlen(global_argv[i]) + 1;
-			p1 = p2 = alloca(--len);
-			for (i = 1; i < global_argc; i++) {
-				strcpy(p2, global_argv[i]);
-				p2 += strlen(global_argv[i]);
-				*p2++ = ifs[0];
-			}
-			*--p2 = '\0';
-			break;
-		default:
-			p1 = lookup_param(inp);
-		}
-
-		if (p1) {
-			len = res_str_len + strlen(p1);
-			res_str = xrealloc(res_str, 1 + len);
-			strcpy(res_str + res_str_len, p1);
-			res_str_len = len;
-		}
-		*p = SPECIAL_VAR_SYMBOL;
-		inp = ++p;
-		done = 1;
-	}
-	if (done) {
-		res_str = xrealloc(res_str, (1 + res_str_len + strlen(inp)));
-		strcpy((res_str + res_str_len), inp);
-		while ((p = strchr(res_str, '\n'))) {
-			*p = ' ';
-		}
-	}
-	return (res_str == NULL) ? inp : res_str;
+	argv[0] = (char*)str;
+	argv[1] = NULL;
+	list = expand_variables(argv, 0x80); /* 0x80: make one-element expansion */
+	/* To be removed / made conditional later. */
+	if (!list[0] || list[1])
+		bb_error_msg_and_die("BUG in varexp");
+	/* actually, just move string 2*sizeof(char*) bytes back */
+	strcpy((char*)list, list[0]);
+	return (char*)list;
 }
 
-
 /* This is used to get/check local shell variables */
 static const char *get_local_var(const char *s)
 {
@@ -3195,7 +3147,7 @@
 	int len = 0;
 
 	for (n = 0; inp[n]; n++) {
-		p = insert_var_value(inp[n]);
+		p = expand_variables_to_string(inp[n]);
 		val_len = strlen(p);
 		str = xrealloc(str, len + val_len + 3); /* +3: space, '\n', <nul>*/
 		str[len++] = ' ';




More information about the busybox-cvs mailing list