encapsulate and re-use log capture, retval setup
[fw/openocd] / src / helper / command.c
index 1263a93142272a5348fe1ced3faacb617dbb41ce..8b29ab4ac4b41a48ce1953adffb1ec2715d7bbf0 100644 (file)
@@ -56,6 +56,34 @@ static void tcl_output(void *privData, const char *file, unsigned line,
        Jim_AppendString(interp, tclOutput, string, strlen(string));
 }
 
+static Jim_Obj *command_log_capture_start(Jim_Interp *interp)
+{
+       /* capture log output and return it. A garbage collect can
+        * happen, so we need a reference count to this object */
+       Jim_Obj *tclOutput = Jim_NewStringObj(interp, "", 0);
+       if (NULL == tclOutput)
+               return NULL;
+       Jim_IncrRefCount(tclOutput);
+       log_add_callback(tcl_output, tclOutput);
+       return tclOutput;
+}
+
+static void command_log_capture_finish(Jim_Interp *interp, Jim_Obj *tclOutput)
+{
+       log_remove_callback(tcl_output, tclOutput);
+       Jim_SetResult(interp, tclOutput);
+       Jim_DecrRefCount(interp, tclOutput);
+}
+
+static int command_retval_set(Jim_Interp *interp, int retval)
+{
+       int *return_retval = Jim_GetAssocData(interp, "retval");
+       if (return_retval != NULL)
+               *return_retval = retval;
+
+       return (retval == ERROR_OK) ? JIM_OK : JIM_ERR;
+}
+
 extern struct command_context *global_cmd_ctx;
 
 void script_debug(Jim_Interp *interp, const char *name,
@@ -125,20 +153,10 @@ static struct command_context *current_command_context(void)
 static int script_command(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
        /* the private data is stashed in the interp structure */
-       struct command *c;
-       int retval;
 
-       /* DANGER!!!! be careful what we invoke here, since interp->cmdPrivData might
-        * get overwritten by running other Jim commands! Treat it as an
-        * emphemeral global variable that is used in lieu of an argument
-        * to the fn and fish it out manually.
-        */
-       c = interp->cmdPrivData;
-       if (c == NULL)
-       {
-               LOG_ERROR("BUG: interp->cmdPrivData == NULL");
-               return JIM_ERR;
-       }
+       struct command *c = interp->cmdPrivData;
+       assert(c);
+
        target_call_timer_callbacks_now();
        LOG_USER_N("%s", ""); /* Keep GDB connection alive*/
 
@@ -149,31 +167,14 @@ static int script_command(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
        if (NULL == words)
                return JIM_ERR;
 
-       /* capture log output and return it */
-       Jim_Obj *tclOutput = Jim_NewStringObj(interp, "", 0);
-       /* a garbage collect can happen, so we need a reference count to this object */
-       Jim_IncrRefCount(tclOutput);
-
-       log_add_callback(tcl_output, tclOutput);
+       Jim_Obj *tclOutput = command_log_capture_start(interp);
 
        struct command_context *cmd_ctx = current_command_context();
-       retval = run_command(cmd_ctx, c, (const char **)words, nwords);
-
-       log_remove_callback(tcl_output, tclOutput);
-
-       /* We dump output into this local variable */
-       Jim_SetResult(interp, tclOutput);
-       Jim_DecrRefCount(interp, tclOutput);
+       int retval = run_command(cmd_ctx, c, (const char **)words, nwords);
 
+       command_log_capture_finish(interp, tclOutput);
        script_command_args_free(words, nwords);
-
-       int *return_retval = Jim_GetAssocData(interp, "retval");
-       if (return_retval != NULL)
-       {
-               *return_retval = retval;
-       }
-
-       return (retval == ERROR_OK)?JIM_OK:JIM_ERR;
+       return command_retval_set(interp, retval);
 }
 
 /* nice short description of source file */
@@ -766,23 +767,13 @@ static int jim_capture(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
        if (argc != 2)
                return JIM_ERR;
-       int retcode;
-       const char *str = Jim_GetString(argv[1], NULL);
-
-       /* capture log output and return it */
-       Jim_Obj *tclOutput = Jim_NewStringObj(interp, "", 0);
-       /* a garbage collect can happen, so we need a reference count to this object */
-       Jim_IncrRefCount(tclOutput);
 
-       log_add_callback(tcl_output, tclOutput);
+       Jim_Obj *tclOutput = command_log_capture_start(interp);
 
-       retcode = Jim_Eval_Named(interp, str, __THIS__FILE__, __LINE__);
-
-       log_remove_callback(tcl_output, tclOutput);
+       const char *str = Jim_GetString(argv[1], NULL);
+       int retcode = Jim_Eval_Named(interp, str, __THIS__FILE__, __LINE__);
 
-       /* We dump output into this local variable */
-       Jim_SetResult(interp, tclOutput);
-       Jim_DecrRefCount(interp, tclOutput);
+       command_log_capture_finish(interp, tclOutput);
 
        return retcode;
 }
@@ -811,20 +802,48 @@ static COMMAND_HELPER(command_help_show_list, struct command *head, unsigned n,
                CALL_COMMAND_HANDLER(command_help_show, c, n, show_help);
        return ERROR_OK;
 }
+
+#define HELP_LINE_WIDTH(_n) (int)(76 - (2 * _n))
+
+static void command_help_show_indent(unsigned n)
+{
+       for (unsigned i = 0; i < n; i++)
+               LOG_USER_N("  ");
+}
+static void command_help_show_wrap(const char *str, unsigned n, unsigned n2)
+{
+       const char *cp = str, *last = str;
+       while (*cp)
+       {
+               const char *next = last;
+               do {
+                       cp = next;
+                       do {
+                               next++;
+                       } while (*next != ' ' && *next != '\t' && *next != '\0');
+               } while ((next - last < HELP_LINE_WIDTH(n)) && *next != '\0');
+               if (next - last < HELP_LINE_WIDTH(n))
+                       cp = next;
+               command_help_show_indent(n);
+               LOG_USER_N("%.*s", (int)(cp - last), last);
+               LOG_USER_N("\n");
+               last = cp + 1;
+               n = n2;
+       }
+}
 static COMMAND_HELPER(command_help_show, struct command *c, unsigned n,
                bool show_help)
 {
-       const char *usage = c->usage ? : "";
-       const char *help = "";
-       const char *sep = "";
-       if (show_help && c->help)
-       {
-               help = c->help ? : "";
-               sep = c->usage ? " | " : "";
+       command_help_show_indent(n);
+       LOG_USER_N("%s", command_name(c, ' '));
+       if (c->usage) {
+               LOG_USER_N(" ");
+               command_help_show_wrap(c->usage, 0, n + 5);
        }
-       command_run_linef(CMD_CTX, "cmd_help {%s} {%s%s%s} %d",
-                       command_name(c, ' '), usage, sep, help, n);
-
+       else
+               LOG_USER_N("\n");
+       if (show_help && c->help)
+               command_help_show_wrap(c->help, n + 3, n + 3);
        if (++n >= 2)
                return ERROR_OK;
 
@@ -833,30 +852,18 @@ static COMMAND_HELPER(command_help_show, struct command *c, unsigned n,
 }
 COMMAND_HANDLER(handle_help_command)
 {
-       struct command *c = CMD_CTX->commands;
+       bool full = strcmp(CMD_NAME, "help") == 0;
 
-       if (0 == CMD_ARGC)
-               return CALL_COMMAND_HANDLER(command_help_show_list, c, 0, true);
-
-       int retval = CALL_COMMAND_HANDLER(command_help_find, c, &c);
-       if (ERROR_OK != retval)
-               return retval;
-
-       return CALL_COMMAND_HANDLER(command_help_show, c, 0, true);
-}
-
-COMMAND_HANDLER(handle_usage_command)
-{
        struct command *c = CMD_CTX->commands;
 
        if (0 == CMD_ARGC)
-               return CALL_COMMAND_HANDLER(command_help_show_list, c, 0, false);
+               return CALL_COMMAND_HANDLER(command_help_show_list, c, 0, full);
 
        int retval = CALL_COMMAND_HANDLER(command_help_find, c, &c);
        if (ERROR_OK != retval)
                return retval;
 
-       return CALL_COMMAND_HANDLER(command_help_show, c, 0, false);
+       return CALL_COMMAND_HANDLER(command_help_show, c, 0, full);
 }
 
 static int command_unknown_find(unsigned argc, Jim_Obj *const *argv,
@@ -920,14 +927,17 @@ static int command_unknown(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
        if (NULL == words)
                return JIM_ERR;
 
+       Jim_Obj *tclOutput = command_log_capture_start(interp);
+
        int retval = run_command(cmd_ctx, c, words, nwords);
 
+       command_log_capture_finish(interp, tclOutput);
        script_command_args_free(words, nwords);
 
        if (!found && ERROR_OK == retval)
                retval = ERROR_FAIL;
 
-       return retval;
+       return command_retval_set(interp, retval);
 }
 
 int help_add_command(struct command_context *cmd_ctx, struct command *parent,
@@ -1078,15 +1088,15 @@ static const struct command_registration command_builtin_handlers[] = {
                .name = "help",
                .handler = &handle_help_command,
                .mode = COMMAND_ANY,
-               .help = "show built-in command help",
-               .usage = "[<command_name> ...]",
+               .help = "show full command help",
+               .usage = "[<command> ...]",
        },
        {
                .name = "usage",
-               .handler = &handle_usage_command,
+               .handler = &handle_help_command,
                .mode = COMMAND_ANY,
-               .help = "show command usage",
-               .usage = "[<command_name> ...]",
+               .help = "show basic command usage",
+               .usage = "[<command> ...]",
        },
        COMMAND_REGISTRATION_DONE
 };