hush: finish and enable optional case...esac support. Code size cost:

function                                             old     new   delta
run_list                                            1891    2075    +184
parse_stream                                        1764    1847     +83
expand_strvec_to_string                                -      83     +83
done_word                                            647     715     +68
static.reserved_list                                 144     168     +24
static.reserved_match                                  -      12     +12
done_pipe                                             95     105     +10
builtin_exit                                          48      46      -2
builtin_eval                                         127      54     -73
------------------------------------------------------------------------------
(add/remove: 2/0 grow/shrink: 5/2 up/down: 464/-75)           Total: 389 bytes

diff --git a/shell/hush.c b/shell/hush.c
index cf6a18f..5a565b3 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -67,14 +67,12 @@
  * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
  */
 
-
-#include <glob.h>      /* glob, of course */
-/* #include <dmalloc.h> */
-
 #include "busybox.h" /* for APPLET_IS_NOFORK/NOEXEC */
-
-// TEMP
-#define ENABLE_HUSH_CASE 0
+#include <glob.h>
+/* #include <dmalloc.h> */
+#if ENABLE_HUSH_CASE
+#include <fnmatch.h>
+#endif
 
 
 #if !BB_MMU && ENABLE_HUSH_TICK
@@ -2064,6 +2062,10 @@
 	rpipe = NULL;
 #endif
 
+	/* Past this point, all code paths should jump to ret: label
+	 * in order to return, no direct "return" statements.
+	 * This helps to ensure that no memory is leaked */
+
 #if ENABLE_HUSH_JOB
 	/* Example of nested list: "while true; do { sleep 1 | exit 2; } done".
 	 * We are saving state before entering outermost list ("while...done")
@@ -2170,6 +2172,7 @@
 			if (!*for_lcur) {
 				/* for loop is over, clean up */
 				free(for_list);
+				for_list = NULL;
 				for_lcur = NULL;
 				flag_rep = 0;
 				pi->progs->argv[0] = for_varname;
@@ -2195,14 +2198,21 @@
 #endif
 #if ENABLE_HUSH_CASE
 		if (rword == RES_CASE) {
-			case_word = pi->progs->argv[0];
+			case_word = expand_strvec_to_string(pi->progs->argv);
+			//bb_error_msg("case: arg:'%s' case_word:'%s'", pi->progs->argv[0], case_word);
 			continue;
 		}
 		if (rword == RES_MATCH) {
 			if (case_word) {
-				next_if_code = strcmp(case_word, pi->progs->argv[0]);
-				if (next_if_code == 0)
+				char *pattern = expand_strvec_to_string(pi->progs->argv);
+				/* TODO: which FNM_xxx flags to use? */
+				next_if_code = fnmatch(pattern, case_word, /*flags:*/ 0);
+				//bb_error_msg("fnmatch('%s','%s'):%d", pattern, case_word, next_if_code);
+				free(pattern);
+				if (next_if_code == 0) {
+					free(case_word);
 					case_word = NULL;
+				}
 				continue;
 			}
 			break;
@@ -2276,6 +2286,12 @@
 	}
 #endif
 	debug_printf_exec("run_list lvl %d return %d\n", run_list_level + 1, rcode);
+#if ENABLE_HUSH_LOOPS
+	free(for_list);
+#endif
+#if ENABLE_HUSH_CASE
+	free(case_word);
+#endif
 	return rcode;
 }