31 #include "jim-eventloop.h"
34 #define __THIS__FILE__ "command.c"
42 const char *cmd_prefix,
const char *
name);
45 const char *cmd_name,
const char *help_text,
const char *usage_text);
61 return cmd->isproc ?
NULL :
cmd->u.native.privData;
64 static void tcl_output(
void *privData,
const char *file,
unsigned line,
65 const char *
function,
const char *
string)
68 Jim_AppendString(
state->interp,
state->output,
string, strlen(
string));
75 Jim_Obj *jim_output = Jim_NewStringObj(
interp,
"", 0);
79 Jim_IncrRefCount(jim_output);
84 Jim_DecrRefCount(
interp, jim_output);
89 state->output = jim_output;
124 Jim_DecrRefCount(
state->interp,
state->output);
131 int *return_retval = Jim_GetAssocData(
interp,
"retval");
133 *return_retval = retval;
135 return (retval ==
ERROR_OK) ? JIM_OK : retval;
148 for (
unsigned i = 0; i < argc; i++) {
150 const char *w = Jim_GetString(argv[i], &len);
161 for (
unsigned i = 0; i < nwords; i++)
167 unsigned argc, Jim_Obj *
const *argv,
unsigned *nwords)
169 char **words = malloc(argc *
sizeof(
char *));
174 for (i = 0; i < argc; i++) {
176 const char *w = Jim_GetString(argv[i], &len);
177 words[i] = strdup(w);
214 Jim_Obj *jim_name = Jim_NewStringObj(interp,
name, -1);
215 Jim_IncrRefCount(jim_name);
216 Jim_Cmd *
cmd = Jim_GetCommand(interp, jim_name, JIM_NONE);
217 Jim_DecrRefCount(interp, jim_name);
237 LOG_ERROR(
"BUG: command '%s' does not have the "
238 "'.usage' field filled out",
274 if (!context || !cr->
name)
280 full_name = strdup(cr->
name);
289 LOG_DEBUG(
"command '%s' is already registered", full_name);
301 LOG_DEBUG(
"registering '%s'...", full_name);
302 int retval = Jim_CreateCommand(context->
interp, full_name,
304 if (retval != JIM_OK) {
318 struct target *override_target)
322 for (i = 0; cmds[i].
name || cmds[i].
chain; i++) {
356 for (
unsigned j = 0; j < i; j++)
363 int unregister_commands_match(struct
command_context *cmd_ctx, const
char *format, ...)
365 Jim_Interp *interp = cmd_ctx->interp;
368 va_start(ap, format);
374 char *query_cmd =
alloc_printf(
"info commands {%s}", query);
379 int retval = Jim_EvalSource(interp,
__THIS__FILE__, __LINE__, query_cmd);
381 if (retval != JIM_OK)
384 Jim_Obj *list = Jim_GetResult(interp);
385 Jim_IncrRefCount(list);
387 int len = Jim_ListLength(interp, list);
388 for (
int i = 0; i < len; i++) {
389 Jim_Obj *elem = Jim_ListGetIndex(interp, list, i);
390 Jim_IncrRefCount(elem);
392 const char *
name = Jim_GetString(elem,
NULL);
396 Jim_DecrRefCount(interp, elem);
401 #if JIM_VERSION >= 80
402 Jim_DeleteCommand(interp, elem);
404 Jim_DeleteCommand(interp,
name);
409 Jim_DecrRefCount(interp, elem);
412 Jim_DecrRefCount(interp, list);
417 const char *cmd_prefix)
422 if (!cmd_prefix || !*cmd_prefix)
423 return unregister_commands_match(context,
"*");
425 int retval = unregister_commands_match(context,
"%s *", cmd_prefix);
429 return unregister_commands_match(context,
"%s", cmd_prefix);
433 const char *cmd_prefix,
const char *
name)
435 if (!context || !
name)
438 if (!cmd_prefix || !*cmd_prefix)
439 return unregister_commands_match(context,
"%s",
name);
441 return unregister_commands_match(context,
"%s %s", cmd_prefix,
name);
455 va_start(ap, format);
464 Jim_AppendString(
cmd->ctx->interp,
cmd->output,
string, -1);
478 va_start(ap, format);
482 strcat(
string,
"\n");
489 Jim_AppendString(
cmd->ctx->interp,
cmd->output,
string, -1);
514 when =
"if Cthulhu is summoned by";
517 LOG_ERROR(
"The '%s' command must be used %s 'init'.",
518 full_name ? full_name : c->
name, when);
523 struct command *c,
const char **words,
unsigned num_words)
529 .argc = num_words - 1,
533 cmd.output = Jim_NewEmptyStringObj(context->
interp);
534 Jim_IncrRefCount(
cmd.output);
544 LOG_DEBUG(
"Command '%s' failed with error code %d",
547 Jim_SetResult(context->
interp,
cmd.output);
549 Jim_DecrRefCount(context->
interp,
cmd.output);
571 Jim_Interp *interp = context->
interp;
573 Jim_DeleteAssocData(
interp,
"context");
574 retcode = Jim_SetAssocData(
interp,
"context",
NULL, context);
575 if (retcode == JIM_OK) {
577 Jim_DeleteAssocData(
interp,
"retval");
578 retcode = Jim_SetAssocData(
interp,
"retval",
NULL, &retval);
579 if (retcode == JIM_OK) {
580 retcode = Jim_Eval_Named(
interp, line, 0, 0);
582 Jim_DeleteAssocData(
interp,
"retval");
584 Jim_DeleteAssocData(
interp,
"context");
585 int inner_retcode = Jim_SetAssocData(
interp,
"context",
NULL, old_context);
586 if (retcode == JIM_OK)
587 retcode = inner_retcode;
590 if (retcode == JIM_OK) {
594 result = Jim_GetString(Jim_GetResult(
interp), &reslen);
600 }
else if (retcode == JIM_EXIT) {
606 Jim_MakeErrorMessage(
interp);
625 va_start(ap, format);
646 *copy_context = *context;
664 const char *file = Jim_GetString(argv[1],
NULL);
668 Jim_Obj *result = Jim_NewStringObj(
interp, full_path, strlen(full_path));
671 Jim_SetResult(
interp, result);
707 const char *str = Jim_GetString(argv[1],
NULL);
725 bool show_help,
const char *cmd_match);
727 static COMMAND_HELPER(command_help_show_list,
bool show_help,
const char *cmd_match)
736 #define HELP_LINE_WIDTH(_n) (int)(76 - (2 * _n))
740 for (
unsigned i = 0; i < n; i++)
745 const char *cp = str, *last = str;
747 const char *next = last;
752 }
while (*next !=
' ' && *next !=
'\t' && *next !=
'\0');
757 LOG_USER(
"%.*s", (
int)(cp - last), last);
764 bool show_help,
const char *cmd_match)
767 for (
const char *s = strchr(c->
cmd_name,
' '); s; s = strchr(s + 1,
' '))
772 bool is_match = strstr(c->
cmd_name, cmd_match) ||
774 (c->
help && strstr(c->
help, cmd_match));
786 if (is_match && show_help) {
795 int retval = Jim_Eval(
CMD_CTX->interp, request);
798 if (retval != JIM_ERR) {
799 const char *result = Jim_GetString(Jim_GetResult(
CMD_CTX->interp),
NULL);
800 if (!strcmp(result,
"any"))
802 else if (!strcmp(result,
"config"))
804 else if (!strcmp(result,
"exec"))
810 const char *stage_msg =
"";
814 stage_msg =
" (configuration command)";
817 stage_msg =
" (command valid any time)";
820 stage_msg =
" (?mode error?)";
839 bool full = strcmp(
CMD_NAME,
"help") == 0;
844 cmd_match = strdup(
"");
849 for (
unsigned int i = 1; i <
CMD_ARGC && cmd_match; ++i) {
850 char *prev = cmd_match;
857 LOG_ERROR(
"unable to build search string");
873 all = strdup(Jim_GetString(argv[0],
NULL));
879 for (i = 1; i < argc; ++i) {
893 struct command *c,
int argc, Jim_Obj *
const *argv)
904 int retval =
run_command(cmd_ctx, c, (
const char **)words, nwords);
914 Jim_Obj *js = Jim_NewStringObj(interp, s, -1);
915 Jim_IncrRefCount(js);
917 Jim_Cmd *
cmd = Jim_GetCommand(interp, js, JIM_NONE);
919 int retval = Jim_EvalObjPrefix(interp, js, argc - 2, argv + 2);
920 Jim_DecrRefCount(interp, js);
923 Jim_DecrRefCount(interp, js);
930 Jim_EvalObjPrefix(interp, Jim_NewStringObj(interp,
"usage", -1), 1, argv);
950 if (strcmp(c->
name,
"expr"))
967 int retval =
exec_command(interp, cmd_ctx, c, argc, argv);
984 Jim_Obj *s = Jim_NewStringObj(
interp, full_name, -1);
986 Jim_Cmd *
cmd = Jim_GetCommand(
interp, s, JIM_NONE);
987 Jim_DecrRefCount(
interp, s);
990 Jim_SetResultString(
interp,
"unknown", -1);
1005 const char *mode_str;
1011 mode_str =
"config";
1017 mode_str =
"unknown";
1020 Jim_SetResultString(interp, mode_str, -1);
1057 const char *
cmd_name,
const char *help_text,
const char *usage_text)
1070 entry = calloc(1,
sizeof(*entry));
1087 char *text = strdup(help_text);
1097 char *text = strdup(usage_text);
1103 entry->
usage = text;
1131 if (strcmp(
CMD_ARGV[1],
"busy") == 0)
1135 }
else if (CMD_ARGC < 1 || CMD_ARGC > 2)
1161 .usage =
"[command_name ...]",
1162 .help =
"Returns the command modes allowed by a command: "
1163 "'any', 'config', or 'exec'. If no command is "
1164 "specified, returns the current command mode. "
1165 "Returns 'unknown' if an unknown command is given. "
1166 "Command can be multiple tokens.",
1176 .help =
"find full path to file",
1183 .help =
"Capture progress output and return as tcl return value. If the "
1184 "progress output was empty, return tcl return value.",
1189 .handler = handle_echo,
1191 .help =
"Logs a message at \"user\" priority. "
1192 "Option \"-n\" suppresses trailing newline",
1193 .usage =
"[-n] string",
1196 .name =
"add_help_text",
1197 .handler = handle_help_add_command,
1199 .help =
"Add new command help text; "
1200 "Command can be multiple tokens.",
1201 .usage =
"command_name helptext_string",
1204 .name =
"add_usage_text",
1205 .handler = handle_help_add_command,
1207 .help =
"Add new command usage text; "
1208 "command can be multiple tokens.",
1209 .usage =
"command_name usage_string",
1213 .handler = handle_sleep_command,
1215 .help =
"Sleep for specified number of milliseconds. "
1216 "\"busy\" will busy wait instead (avoid this).",
1217 .usage =
"milliseconds ['busy']",
1221 .handler = handle_help_command,
1223 .help =
"Show full command help; "
1224 "command can be multiple tokens.",
1225 .usage =
"[command_name]",
1229 .handler = handle_help_command,
1231 .help =
"Show basic command usage; "
1232 "command can be multiple tokens.",
1233 .usage =
"[command_name]",
1238 .help =
"core command group (introspection)",
1258 interp = Jim_CreateInterp();
1260 Jim_RegisterCoreCommands(
interp);
1261 Jim_InitStaticExtensions(
interp);
1268 Jim_SetAssocData(
interp,
"context",
NULL, context);
1269 if (Jim_Eval_Named(
interp, startup_tcl,
"embedded:startup.tcl", 1) == JIM_ERR) {
1270 LOG_ERROR(
"Failed to run startup.tcl (embedded into OpenOCD)");
1271 Jim_MakeErrorMessage(
interp);
1275 Jim_DeleteAssocData(
interp,
"context");
1285 Jim_FreeInterp(context->
interp);
1301 static int recursion;
1306 Jim_ProcessEvents(cmd_ctx->
interp, JIM_ALL_EVENTS | JIM_DONT_WAIT);
1310 #define DEFINE_PARSE_NUM_TYPE(name, type, func, min, max) \
1311 int parse ## name(const char *str, type * ul) \
1314 LOG_ERROR("Invalid command argument"); \
1315 return ERROR_COMMAND_ARGUMENT_INVALID; \
1319 *ul = func(str, &end, 0); \
1321 LOG_ERROR("Invalid command argument"); \
1322 return ERROR_COMMAND_ARGUMENT_INVALID; \
1324 if ((max == *ul) && (errno == ERANGE)) { \
1325 LOG_ERROR("Argument overflow"); \
1326 return ERROR_COMMAND_ARGUMENT_OVERFLOW; \
1328 if (min && (min == *ul) && (errno == ERANGE)) { \
1329 LOG_ERROR("Argument underflow"); \
1330 return ERROR_COMMAND_ARGUMENT_UNDERFLOW; \
1339 #define DEFINE_PARSE_WRAPPER(name, type, min, max, functype, funcname) \
1340 int parse ## name(const char *str, type * ul) \
1343 int retval = parse ## funcname(str, &n); \
1344 if (retval != ERROR_OK) \
1347 return ERROR_COMMAND_ARGUMENT_OVERFLOW; \
1349 return ERROR_COMMAND_ARGUMENT_UNDERFLOW; \
1354 #define DEFINE_PARSE_ULONGLONG(name, type, min, max) \
1355 DEFINE_PARSE_WRAPPER(name, type, min, max, unsigned long long, _ullong)
1364 #define DEFINE_PARSE_LONGLONG(name, type, min, max) \
1365 DEFINE_PARSE_WRAPPER(name, type, min, max, long long, _llong)
1373 const
char *on, const
char *off)
1375 if (strcasecmp(in, on) == 0)
1377 else if (strcasecmp(in, off) == 0)
static struct log_capture_state * command_log_capture_start(Jim_Interp *interp)
struct command_context * current_command_context(Jim_Interp *interp)
static void command_free(struct Jim_Interp *interp, void *priv)
int command_parse_bool_arg(const char *in, bool *out)
static void script_debug(Jim_Interp *interp, unsigned int argc, Jim_Obj *const *argv)
int help_del_all_commands(struct command_context *cmd_ctx)
Unregisters the help for all commands.
static bool command_can_run(struct command_context *cmd_ctx, struct command *c, const char *full_name)
static int jim_find(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
bool jimcmd_is_oocd_command(Jim_Cmd *cmd)
Return true if the command cmd is registered by OpenOCD.
void command_print_sameline(struct command_invocation *cmd, const char *format,...)
static int command_parse_bool(const char *in, bool *out, const char *on, const char *off)
static struct command * register_command(struct command_context *context, const char *cmd_prefix, const struct command_registration *cr)
struct command_context * global_cmd_ctx
static int help_add_command(struct command_context *cmd_ctx, const char *cmd_name, const char *help_text, const char *usage_text)
static int jim_command_mode(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
static struct command * command_new(struct command_context *cmd_ctx, const char *full_name, const struct command_registration *cr)
static COMMAND_HELPER(command_help_show, struct help_entry *c, bool show_help, const char *cmd_match)
static int jim_command_dispatch(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
void command_done(struct command_context *cmd_ctx)
Frees the resources associated with a command context.
void * jimcmd_privdata(Jim_Cmd *cmd)
Return the pointer to the command's private data specified during the registration of command cmd .
static void command_help_show_indent(unsigned n)
static bool jimcmd_is_proc(Jim_Cmd *cmd)
#define HELP_LINE_WIDTH(_n)
void command_print(struct command_invocation *cmd, const char *format,...)
static void command_help_show_wrap(const char *str, unsigned n, unsigned n2)
static int unregister_command(struct command_context *context, const char *cmd_prefix, const char *name)
COMMAND_HANDLER(handle_echo)
static void command_log_capture_finish(struct log_capture_state *state)
void process_jim_events(struct command_context *cmd_ctx)
static const struct command_registration command_subcommand_handlers[]
struct command_context * copy_command_context(struct command_context *context)
Creates a copy of an existing command context.
void command_exit(struct command_context *context)
Shutdown a command context.
static struct command * command_find_from_name(Jim_Interp *interp, const char *name)
Find a openocd command from fullname.
static char ** script_command_args_alloc(unsigned argc, Jim_Obj *const *argv, unsigned *nwords)
static int run_command(struct command_context *context, struct command *c, const char **words, unsigned num_words)
static __attribute__((format(PRINTF_ATTRIBUTE_FORMAT, 2, 3)))
void command_output_text(struct command_context *context, const char *data)
#define DEFINE_PARSE_LONGLONG(name, type, min, max)
static void script_command_args_free(char **words, unsigned nwords)
static int help_del_command(struct command_context *cmd_ctx, const char *cmd_name)
struct command_context * command_init(const char *startup_tcl, Jim_Interp *interp)
Creates a new command context using the startup TCL provided and the existing Jim interpreter,...
int command_context_mode(struct command_context *cmd_ctx, enum command_mode mode)
static char * alloc_concatenate_strings(int argc, Jim_Obj *const *argv)
static int exec_command(Jim_Interp *interp, struct command_context *cmd_ctx, struct command *c, int argc, Jim_Obj *const *argv)
static void tcl_output(void *privData, const char *file, unsigned line, const char *function, const char *string)
int command_run_linef(struct command_context *context, const char *format,...)
int __register_commands(struct command_context *cmd_ctx, const char *cmd_prefix, const struct command_registration *cmds, void *data, struct target *override_target)
static int jim_capture(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
void command_set_output_handler(struct command_context *context, command_output_handler_t output_handler, void *priv)
static const struct command_registration command_builtin_handlers[]
int unregister_all_commands(struct command_context *context, const char *cmd_prefix)
Unregisters all commands from the specified context.
#define DEFINE_PARSE_ULONGLONG(name, type, min, max)
int command_run_line(struct command_context *context, char *line)
static int command_retval_set(Jim_Interp *interp, int retval)
#define DEFINE_PARSE_NUM_TYPE(name, type, func, min, max)
#define CALL_COMMAND_HANDLER(name, extra ...)
Use this to macro to call a command helper (or a nested handler).
#define CMD_NAME
Use this macro to access the name of the command being handled, rather than accessing the variable di...
#define CMD_ARGV
Use this macro to access the arguments for the command being handled, rather than accessing the varia...
int parse_ulong(const char *str, unsigned long *ul)
#define PRINTF_ATTRIBUTE_FORMAT
#define ERROR_COMMAND_SYNTAX_ERROR
#define ERROR_COMMAND_CLOSE_CONNECTION
#define CMD_ARGC
Use this macro to access the number of arguments for the command being handled, rather than accessing...
int(* command_output_handler_t)(struct command_context *context, const char *line)
The type signature for command context's output handler.
#define CMD_CTX
Use this macro to access the context of the command being handled, rather than accessing the variable...
static struct command * jim_to_command(Jim_Interp *interp)
#define COMMAND_REGISTRATION_DONE
Use this as the last entry in an array of command_registration records.
static int register_commands(struct command_context *cmd_ctx, const char *cmd_prefix, const struct command_registration *cmds)
Register one or more commands in the specified context, as children of parent (or top-level commends,...
command_mode
OpenOCD command mode is COMMAND_CONFIG at start, then switches to COMMAND_EXEC during the execution o...
char * find_file(const char *file)
static struct esp_usb_jtag * priv
void jtag_poll_unmask(bool saved)
Restore saved mask for polling.
bool jtag_poll_mask(void)
Mask (disable) polling and return the current mask status that should be feed to jtag_poll_unmask() t...
The JTAG interface can be implemented with a software or hardware fifo.
static void list_add(struct list_head *new, struct list_head *head)
list_add - add a new entry
#define list_for_each_entry(pos, head, member)
list_for_each_entry - iterate over list of given type
static void list_del(struct list_head *entry)
list_del - deletes entry from list.
#define list_for_each_entry_safe(pos, n, head, member)
list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
#define list_for_each_entry_reverse(pos, head, member)
list_for_each_entry_reverse - iterate backwards over list of given type.
static void INIT_LIST_HEAD(struct list_head *list)
INIT_LIST_HEAD - Initialize a list_head structure.
int log_remove_callback(log_callback_fn fn, void *priv)
int log_add_callback(log_callback_fn fn, void *priv)
char * alloc_vprintf(const char *fmt, va_list ap)
void busy_sleep(uint64_t ms)
char * alloc_printf(const char *format,...)
#define LOG_USER(expr ...)
#define LOG_USER_N(expr ...)
#define LOG_ERROR(expr ...)
#define LOG_INFO(expr ...)
#define LOG_DEBUG(expr ...)
static uint32_t lh(unsigned int rd, unsigned int base, uint16_t offset) __attribute__((unused))
struct list_head * help_list
void * output_handler_priv
struct target * current_target_override
command_output_handler_t output_handler
When run_command is called, a new instance will be created on the stack, filled with the proper value...
command_handler_t handler
Jim_CmdProc * jim_handler
const struct command_registration * chain
If non-NULL, the commands in chain will be registered in the same context and scope of this registrat...
const char * usage
a string listing the options and arguments, required or optional
Jim_CmdProc * jim_handler
command_handler_t handler
struct target * jim_override_target
int target_call_timer_callbacks_now()
Invoke this to ensure that e.g.