android-console: Make 'help' output match the classic emulator

Implement the 'help' command ourselves rather than using the
monitor's usual version, so we can make the output text match the
format of the classic emulator. This might not be necessary but
perhaps external tools are parsing the output to see what commands
are supported.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
diff --git a/android-commands.h b/android-commands.h
index 34a4fb3..1bfd15d 100644
--- a/android-commands.h
+++ b/android-commands.h
@@ -28,10 +28,10 @@
 static mon_cmd_t android_cmds[] = {
     {
         .name = "help|h|?",
-        .args_type = "name:S?",
+        .args_type = "helptext:S?",
         .params = "",
         .help = "print a list of commands",
-        .mhandler.cmd = do_help_cmd,
+        .mhandler.cmd = android_console_help,
     },
     {
         .name = "kill",
diff --git a/android-console.c b/android-console.c
index 1ff3341..c2e41da 100644
--- a/android-console.c
+++ b/android-console.c
@@ -240,18 +240,53 @@
 }
 #endif
 
+static const char *redir_list_help =
+    "list current port redirections. "
+    "use 'redir add' and 'redir del' to add and remove them\n"
+    "OK\n";
+
+static const char *redir_add_help =
+    "add a new port redirection, arguments must be:\n"
+    "\n"
+    "  redir add <protocol>:<host-port>:<guest-port>\n"
+    "\n"
+    "where:   <protocol>     is either 'tcp' or 'udp'\n"
+    "         <host-port>    a number indicating which "
+    "port on the host to open\n"
+    "         <guest-port>   a number indicating which "
+    "port to route to on the device\n"
+    "\n"
+    "as an example, 'redir  tcp:5000:6000' will allow any packets sent to\n"
+    "the host's TCP port 5000 to be routed to TCP port 6000 of the "
+    "emulated device\n"
+    "OK\n";
+
+static const char *redir_del_help =
+    "remove a port redirecion that was created with 'redir add', "
+    "arguments must be:\n\n"
+    "  redir  del <protocol>:<host-port>\n\n"
+    "see the 'help redir add' for the meaning of <protocol> and <host-port>\n"
+    "OK\n";
+
 void android_console_redir(Monitor *mon, const QDict *qdict)
 {
-    const char *arg = qdict_get_try_str(qdict, "arg");
+    /* This only gets called for bad subcommands and help requests */
+    const char *helptext = qdict_get_try_str(qdict, "helptext");
 
-    if (!arg) {
-        goto fail;
+    monitor_printf(mon, "help text %s\n", helptext ? helptext : "(null)");
+
+    if (helptext) {
+        if (strstr(helptext, "add")) {
+            monitor_printf(mon, "%s", redir_add_help);
+            return;
+        } else if (strstr(helptext, "del")) {
+            monitor_printf(mon, "%s", redir_del_help);
+            return;
+        } else if (strstr(helptext, "list")) {
+            monitor_printf(mon, "%s", redir_list_help);
+            return;
+        }
     }
-
-    monitor_printf(mon, "redir: arg %s\n", arg);
-    return;
-
-fail:
     monitor_printf(mon, "allows you to add, list and remove and/or "
                    "PORT redirection from the host to the device\n"
                    "as an example, 'redir  tcp:5000:6000' will route "
@@ -262,6 +297,6 @@
                    "    list             list current redirections\n"
                    "    add              add new redirection\n"
                    "    del              remove existing redirection\n"
-                   "\n"
-                   "KO: missing sub-command\n");
+                   "\n%s\n",
+                   helptext ? "OK" : "KO: missing sub-command");
 }
diff --git a/monitor.c b/monitor.c
index 50ad7d1..f071878 100644
--- a/monitor.c
+++ b/monitor.c
@@ -940,6 +940,77 @@
     help_cmd(mon, qdict_get_try_str(qdict, "name"));
 }
 
+static void android_console_help(Monitor *mon, const QDict *qdict)
+{
+    const char *name = qdict_get_try_str(qdict, "helptext");
+    const mon_cmd_t *cmd;
+    const mon_cmd_t *cmds = mon->cmd_table;
+    char *args[MAX_ARGS];
+    int nb_args = 0;
+    int thisarg = 0;
+    const mon_cmd_t *parent_cmd = NULL;
+
+    if (!name) {
+        /* No arguments, just print command list */
+        monitor_printf(mon, "Android console command help:\n\n");
+        for (cmd = cmds; cmd->name; cmd++) {
+            monitor_printf(mon, "    %-15s  %s\n", cmd->name, cmd->help);
+        }
+        monitor_printf(mon,
+                       "\ntry 'help <command>' for command-specific help\n");
+        return;
+    }
+
+    /* With an argument, look for it */
+    if (!parse_cmdline(name, &nb_args, args) < 0 || nb_args == 0) {
+        monitor_printf(mon, "KO: couldn't parse help text\n");
+        return;
+    }
+
+    for (;;) {
+        for (cmd = cmds; cmd->name; cmd++) {
+            if (compare_cmd(args[thisarg], cmd->name)) {
+                break;
+            }
+        }
+        if (!cmd->name) {
+            /* command/subcommand not found */
+            monitor_printf(mon, "try one of these instead:\n\n");
+            for (cmd = cmds; cmd->name; cmd++) {
+                int i;
+                monitor_printf(mon, "    ");
+                for (i = 0; i < thisarg; i++) {
+                    monitor_printf(mon, "%s ", args[i]);
+                }
+                monitor_printf(mon, "%s\n", cmd->name);
+            }
+            monitor_printf(mon, "\nKO: unknown command\n");
+            return;
+        }
+
+        thisarg++;
+
+        if (thisarg >= nb_args || !cmd->sub_table) {
+            /* For subtables, the command handler for the entry in the 1st
+             * level of commands deals with help (including "help subcommand"
+             * where there is no following second level command in the help
+             * string). For top level commands, we just print the short text.
+             */
+            if (parent_cmd) {
+                parent_cmd->mhandler.cmd(mon, qdict);
+            } else if (cmd->sub_table) {
+                cmd->mhandler.cmd(mon, qdict);
+            } else {
+                monitor_printf(mon, "%s\nOK\n", cmd->help);
+            }
+            return;
+        }
+
+        parent_cmd = cmd;
+        cmds = cmd->sub_table;
+    }
+}
+
 static void do_trace_event_set_state(Monitor *mon, const QDict *qdict)
 {
     const char *tp_name = qdict_get_str(qdict, "name");