Patches by Pantelis Antoniou, 16 Apr 2004:
- add support for a new version of an Intracom board and fix
  various other things on others.
- add verify support to the crc32 command (define
  CONFIG_CRC32_VERIFY to enable it)
- fix FEC driver for MPC8xx systems:
  1. fix compilation problems for boards that use dynamic
     allocation of DPRAM
  2. shut down FEC after network transfers
- HUSH parser fixes:
  1. A new test command was added. This is a simplified version of
     the one in the bourne shell.
  2. A new exit command was added which terminates the current
     executing script.
  3. Fixed handing of $? (exit code of last executed command)
diff --git a/common/hush.c b/common/hush.c
index eeb970c..47680ed 100644
--- a/common/hush.c
+++ b/common/hush.c
@@ -290,6 +290,7 @@
 unsigned int global_argc;
 #endif
 unsigned int last_return_code;
+int nesting_level;
 #ifndef __U_BOOT__
 extern char **environ; /* This is in <unistd.h>, but protected with __USE_GNU */
 #endif
@@ -416,7 +417,9 @@
 static int b_addchr(o_string *o, int ch);
 static void b_reset(o_string *o);
 static int b_addqchr(o_string *o, int ch, int quote);
+#ifndef __U_BOOT__
 static int b_adduint(o_string *o, unsigned int i);
+#endif
 /*  in_str manipulations: */
 static int static_get(struct in_str *i);
 static int static_peek(struct in_str *i);
@@ -936,6 +939,7 @@
 	return p + 1;
 }
 
+#ifndef __U_BOOT__
 static int b_adduint(o_string *o, unsigned int i)
 {
 	int r;
@@ -944,6 +948,7 @@
 	do r=b_addchr(o, *p++); while (r==0 && *p);
 	return r;
 }
+#endif
 
 static int static_get(struct in_str *i)
 {
@@ -1921,6 +1926,10 @@
 		}
 		last_return_code=rcode;
 #else
+		if (rcode < -1) {
+			last_return_code = -rcode - 2;
+			return -2;	/* exit */
+		}
 		last_return_code=(rcode == 0) ? 0 : 1;
 #endif
 #ifndef __U_BOOT__
@@ -2145,6 +2154,10 @@
 }
 #endif
 
+#ifdef __U_BOOT__
+static char *get_dollar_var(char ch);
+#endif
+
 /* This is used to get/check local shell variables */
 static char *get_local_var(const char *s)
 {
@@ -2152,6 +2165,12 @@
 
 	if (!s)
 		return NULL;
+
+#ifdef __U_BOOT__
+	if (*s == '$')
+		return get_dollar_var(s[1]);
+#endif
+
 	for (cur = top_vars; cur; cur=cur->next)
 		if(strcmp(cur->name, s)==0)
 			return cur->value;
@@ -2168,12 +2187,19 @@
 	int result=0;
 	struct variables *cur;
 
+#ifdef __U_BOOT__
+	/* might be possible! */
+	if (!isalpha(*s))
+		return -1;
+#endif
+
 	name=strdup(s);
 
 #ifdef __U_BOOT__
 	if (getenv(name) != NULL) {
 		printf ("ERROR: "
 				"There is a global environment variable with the same name.\n");
+		free(name);
 		return -1;
 	}
 #endif
@@ -2278,7 +2304,10 @@
 
 static int is_assignment(const char *s)
 {
-	if (s==NULL || !isalpha(*s)) return 0;
+	if (s == NULL)
+		return 0;
+
+	if (!isalpha(*s)) return 0;
 	++s;
 	while(isalnum(*s) || *s=='_') ++s;
 	return *s=='=';
@@ -2749,15 +2778,35 @@
  * see the bash man page under "Parameter Expansion" */
 static char *lookup_param(char *src)
 {
-	char *p=NULL;
-	if (src) {
+	char *p;
+
+	if (!src)
+		return NULL;
+
 		p = getenv(src);
 		if (!p)
 			p = get_local_var(src);
-	}
+
 	return p;
 }
 
+#ifdef __U_BOOT__
+static char *get_dollar_var(char ch)
+{
+	static char buf[40];
+
+	buf[0] = '\0';
+	switch (ch) {
+		case '?':
+			sprintf(buf, "%u", (unsigned int)last_return_code);
+			break;
+		default:
+			return NULL;
+	}
+	return buf;
+}
+#endif
+
 /* return code: 0 for OK, 1 for syntax error */
 static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *input)
 {
@@ -2799,7 +2848,15 @@
 			break;
 #endif
 		case '?':
+#ifndef __U_BOOT__
 			b_adduint(dest,last_return_code);
+#else
+			ctx->child->sp++;
+			b_addchr(dest, SPECIAL_VAR_SYMBOL);
+			b_addchr(dest, '$');
+			b_addchr(dest, '?');
+			b_addchr(dest, SPECIAL_VAR_SYMBOL);
+#endif
 			advance = 1;
 			break;
 #ifndef __U_BOOT__
@@ -2885,8 +2942,11 @@
 		if (input->__promptme == 0) return 1;
 #endif
 		next = (ch == '\n') ? 0 : b_peek(input);
-		debug_printf("parse_stream: ch=%c (%d) m=%d quote=%d\n",
-			ch,ch,m,dest->quote);
+
+		debug_printf("parse_stream: ch=%c (%d) m=%d quote=%d - %c\n",
+			ch >= ' ' ? ch : '.', ch, m,
+			dest->quote, ctx->stack == NULL ? '*' : '.');
+
 		if (m==0 || ((m==1 || m==2) && dest->quote)) {
 			b_addqchr(dest, ch, dest->quote);
 		} else {
@@ -3107,7 +3167,18 @@
 #ifndef __U_BOOT__
 			run_list(ctx.list_head);
 #else
-			if (((code = run_list(ctx.list_head)) == -1))
+			code = run_list(ctx.list_head);
+			if (code == -2) {	/* exit */
+				b_free(&temp);
+				code = 0;
+				/* XXX hackish way to not allow exit from main loop */
+				if (inp->peek == file_peek) {
+					printf("exit not allowed from main input shell.\n");
+					continue;
+				}
+				break;
+			}
+			if (code == -1)
 			    flag_repeat = 0;
 #endif
 		} else {