add script_command_run helper
[openocd.git] / src / helper / command.c
index 3cb36ea27590850c4f18131f10d265604b6af7d4..62fb48791c771dee0cacddbb2bcc3391c2228e1b 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,
@@ -122,58 +150,39 @@ static struct command_context *current_command_context(void)
        return cmd_ctx;
 }
 
-static int script_command(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+static int script_command_run(Jim_Interp *interp,
+               int argc, Jim_Obj *const *argv, struct command *c, bool capture)
 {
-       /* 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;
-       }
        target_call_timer_callbacks_now();
        LOG_USER_N("%s", ""); /* Keep GDB connection alive*/
 
-       script_debug(interp, c->name, argc, argv);
-
        unsigned nwords;
        const char **words = script_command_args_alloc(argc, argv, &nwords);
        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 = NULL;
+       if (capture)
+               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);
+       int retval = run_command(cmd_ctx, c, (const char **)words, nwords);
 
-       /* We dump output into this local variable */
-       Jim_SetResult(interp, tclOutput);
-       Jim_DecrRefCount(interp, tclOutput);
+       if (capture)
+               command_log_capture_finish(interp, tclOutput);
 
        script_command_args_free(words, nwords);
+       return command_retval_set(interp, retval);
+}
 
-       int *return_retval = Jim_GetAssocData(interp, "retval");
-       if (return_retval != NULL)
-       {
-               *return_retval = retval;
-       }
+static int script_command(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+       /* the private data is stashed in the interp structure */
 
-       return (retval == ERROR_OK)?JIM_OK:JIM_ERR;
+       struct command *c = interp->cmdPrivData;
+       assert(c);
+       script_debug(interp, c->name, argc, argv);
+       return script_command_run(interp, argc, argv, c, true);
 }
 
 /* nice short description of source file */
@@ -766,23 +775,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);
-
-       retcode = Jim_Eval_Named(interp, str, __THIS__FILE__, __LINE__);
+       Jim_Obj *tclOutput = command_log_capture_start(interp);
 
-       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 +810,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 +860,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,
@@ -915,19 +930,7 @@ static int command_unknown(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
                return (*c->jim_handler)(interp, count, start);
        }
 
-       unsigned nwords;
-       const char **words = script_command_args_alloc(count, start, &nwords);
-       if (NULL == words)
-               return JIM_ERR;
-
-       int retval = run_command(cmd_ctx, c, words, nwords);
-
-       script_command_args_free(words, nwords);
-
-       if (!found && ERROR_OK == retval)
-               retval = ERROR_FAIL;
-
-       return retval;
+       return script_command_run(interp, count, start, c, found);
 }
 
 int help_add_command(struct command_context *cmd_ctx, struct command *parent,
@@ -951,8 +954,9 @@ int help_add_command(struct command_context *cmd_ctx, struct command *parent,
                        return ERROR_FAIL;
                }
                LOG_DEBUG("added '%s' help text", cmd_name);
+               return ERROR_OK;
        }
-       else
+       if (help_text)
        {
                bool replaced = false;
                if (nc->help)
@@ -961,12 +965,25 @@ int help_add_command(struct command_context *cmd_ctx, struct command *parent,
                        replaced = true;
                }
                nc->help = strdup(help_text);
-
                if (replaced)
                        LOG_INFO("replaced existing '%s' help", cmd_name);
                else
                        LOG_DEBUG("added '%s' help text", cmd_name);
        }
+       if (usage)
+       {
+               bool replaced = false;
+               if (nc->usage)
+               {
+                       free((void *)nc->usage);
+                       replaced = true;
+               }
+               nc->usage = strdup(usage);
+               if (replaced)
+                       LOG_INFO("replaced existing '%s' usage", cmd_name);
+               else
+                       LOG_DEBUG("added '%s' usage text", cmd_name);
+       }
        return ERROR_OK;
 }
 
@@ -979,7 +996,14 @@ COMMAND_HANDLER(handle_help_add_command)
        }
 
        // save help text and remove it from argument list
-       const char *help_text = CMD_ARGV[--CMD_ARGC];
+       const char *str = CMD_ARGV[--CMD_ARGC];
+       const char *help = !strcmp(CMD_NAME, "add_help_text") ? str : NULL;
+       const char *usage = !strcmp(CMD_NAME, "add_usage_text") ? str : NULL;
+       if (!help && !usage)
+       {
+               LOG_ERROR("command name '%s' is unknown", CMD_NAME);
+               return ERROR_INVALID_ARGUMENTS;
+       }
        // likewise for the leaf command name
        const char *cmd_name = CMD_ARGV[--CMD_ARGC];
 
@@ -991,7 +1015,7 @@ COMMAND_HANDLER(handle_help_add_command)
                if (ERROR_OK != retval)
                        return retval;
        }
-       return help_add_command(CMD_CTX, c, cmd_name, help_text, NULL);
+       return help_add_command(CMD_CTX, c, cmd_name, help, usage);
 }
 
 /* sleep command sleeps for <n> miliseconds
@@ -1038,6 +1062,13 @@ static const struct command_registration command_builtin_handlers[] = {
                .help = "add new command help text",
                .usage = "<command> [...] <help_text>]",
        },
+       {
+               .name = "add_usage_text",
+               .handler = &handle_help_add_command,
+               .mode = COMMAND_ANY,
+               .help = "add new command usage text",
+               .usage = "<command> [...] <usage_text>]",
+       },
        {
                .name = "sleep",
                .handler = &handle_sleep_command,
@@ -1050,15 +1081,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
 };

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)