X-Git-Url: https://review.openocd.org/gitweb?p=openocd.git;a=blobdiff_plain;f=src%2Fhelper%2Fcommand.h;h=733ba42dd1ef5ae113aaa1cc7c17d52407ca658f;hp=762356355c39074298838295f194ccb2f527e3d4;hb=HEAD;hpb=08d4411b59dd8bd0e7d8009003b71d23acbf6eee diff --git a/src/helper/command.h b/src/helper/command.h index 762356355c..dc45070420 100644 --- a/src/helper/command.h +++ b/src/helper/command.h @@ -1,30 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * ***************************************************************************/ -#ifndef COMMAND_H -#define COMMAND_H +#ifndef OPENOCD_HELPER_COMMAND_H +#define OPENOCD_HELPER_COMMAND_H + +#include +#include -#include +#include +#include +#include /* To achieve C99 printf compatibility in MinGW, gnu_printf should be * used for __attribute__((format( ... ))), with GCC v4.4 or later @@ -35,10 +27,20 @@ #define PRINTF_ATTRIBUTE_FORMAT printf #endif +/** + * OpenOCD command mode is COMMAND_CONFIG at start, then switches to COMMAND_EXEC + * during the execution of command 'init'. + * The field 'mode' in struct command_registration specifies in which command mode + * the command can be executed: + * - during COMMAND_CONFIG only, + * - during COMMAND_EXEC only, + * - in both modes (COMMAND_ANY). + */ enum command_mode { COMMAND_EXEC, COMMAND_CONFIG, COMMAND_ANY, + COMMAND_UNKNOWN = -1, /* error condition */ }; struct command_context; @@ -50,10 +52,18 @@ typedef int (*command_output_handler_t)(struct command_context *context, struct command_context { Jim_Interp *interp; enum command_mode mode; - struct command *commands; - int current_target; + struct target *current_target; + /* The target set by 'targets xx' command or the latest created */ + struct target *current_target_override; + /* If set overrides current_target + * It happens during processing of + * 1) a target prefixed command + * 2) an event handler + * Pay attention to reentrancy when setting override. + */ command_output_handler_t output_handler; void *output_handler_priv; + struct list_head *help_list; }; struct command; @@ -69,8 +79,21 @@ struct command_invocation { const char *name; unsigned argc; const char **argv; + Jim_Obj * const *jimtcl_argv; + Jim_Obj *output; }; +/** + * Return true if the command @c cmd is registered by OpenOCD. + */ +bool jimcmd_is_oocd_command(Jim_Cmd *cmd); + +/** + * Return the pointer to the command's private data specified during the + * registration of command @a cmd . + */ +void *jimcmd_privdata(Jim_Cmd *cmd); + /** * Command handlers may be defined with more parameters than the base * set provided by command.c. This macro uses C99 magic to allow @@ -111,6 +134,11 @@ struct command_invocation { */ #define COMMAND_HELPER(name, extra ...) __COMMAND_HANDLER(name, extra) +/** + * Use this macro to access the command being handled, + * rather than accessing the variable directly. It may be moved. + */ +#define CMD (cmd) /** * Use this macro to access the context of the command being handled, * rather than accessing the variable directly. It may be moved. @@ -126,6 +154,11 @@ struct command_invocation { * rather than accessing the variable directly. It may be moved. */ #define CMD_ARGV (cmd->argv) +/** + * Use this macro to access the jimtcl arguments for the command being + * handled, rather than accessing the variable directly. It may be moved. + */ +#define CMD_JIMTCL_ARGV (cmd->jimtcl_argv) /** * Use this macro to access the name of the command being handled, * rather than accessing the variable directly. It may be moved. @@ -152,7 +185,7 @@ struct command_invocation { * * This is *especially* important for commands such as writing * to flash or verifying memory. The reason is that those commands - * can be used by programs to determine if the operation succeded + * can be used by programs to determine if the operation succeeded * or not. If the operation failed, then a program can try * an alternative approach. * @@ -162,33 +195,30 @@ struct command_invocation { typedef __COMMAND_HANDLER((*command_handler_t)); struct command { - const char *name; - const char *help; - const char *usage; - struct command *parent; - struct command *children; + char *name; command_handler_t handler; - Jim_CmdProc jim_handler; + Jim_CmdProc *jim_handler; void *jim_handler_data; + /* Command handlers can use it for any handler specific data */ + struct target *jim_override_target; + /* Used only for target of target-prefixed cmd */ enum command_mode mode; - struct command *next; }; -/** - * @param c The command to be named. - * @param delim The character to place between command names. - * @returns A malloc'd string containing the full command name, - * which may include one or more ancestor components. Multiple names - * are separated by single spaces. The caller must free() the string - * when done with it. +/* + * Return the struct command pointer kept in private data + * Used to enforce check on data type */ -char *command_name(struct command *c, char delim); +static inline struct command *jim_to_command(Jim_Interp *interp) +{ + return Jim_CmdPrivData(interp); +} /* * Commands should be registered by filling in one or more of these - * structures and passing them to register_command(). + * structures and passing them to [un]register_commands(). * - * A conventioal format should be used for help strings, to provide both + * A conventional format should be used for help strings, to provide both * usage and basic information: * @code * "@ ... - some explanation text" @@ -204,8 +234,7 @@ char *command_name(struct command *c, char delim); struct command_registration { const char *name; command_handler_t handler; - Jim_CmdProc jim_handler; - void *jim_handler_data; + Jim_CmdProc *jim_handler; enum command_mode mode; const char *help; /** a string listing the options and arguments, required or optional */ @@ -223,23 +252,9 @@ struct command_registration { /** Use this as the last entry in an array of command_registration records. */ #define COMMAND_REGISTRATION_DONE { .name = NULL, .chain = NULL } -/** - * Register a command @c handler that can be called from scripts during - * the execution @c mode specified. - * - * If @c parent is non-NULL, the new command will be registered as a - * sub-command under it; otherwise, it will be available as a top-level - * command. - * - * @param cmd_ctx The command_context in which to register the command. - * @param parent Register this command as a child of this, or NULL to - * register a top-level command. - * @param rec A command_registration record that contains the desired - * command parameters. - * @returns The new command, if successful; otherwise, NULL. - */ -struct command *register_command(struct command_context *cmd_ctx, - struct command *parent, const struct command_registration *rec); +int __register_commands(struct command_context *cmd_ctx, const char *cmd_prefix, + const struct command_registration *cmds, void *data, + struct target *override_target); /** * Register one or more commands in the specified context, as children @@ -249,49 +264,77 @@ struct command *register_command(struct command_context *cmd_ctx, * Otherwise, the chained commands are added as children of the command. * * @param cmd_ctx The command_context in which to register the command. - * @param parent Register this command as a child of this, or NULL to + * @param cmd_prefix Register this command as a child of this, or NULL to * register a top-level command. * @param cmds Pointer to an array of command_registration records that * contains the desired command parameters. The last record must have * NULL for all fields. * @returns ERROR_OK on success; ERROR_FAIL if any registration fails. */ -int register_commands(struct command_context *cmd_ctx, struct command *parent, - const struct command_registration *cmds); +static inline int register_commands(struct command_context *cmd_ctx, const char *cmd_prefix, + const struct command_registration *cmds) +{ + return __register_commands(cmd_ctx, cmd_prefix, cmds, NULL, NULL); +} +/** + * Register one or more commands, as register_commands(), plus specify + * that command should override the current target + * + * @param cmd_ctx The command_context in which to register the command. + * @param cmd_prefix Register this command as a child of this, or NULL to + * register a top-level command. + * @param cmds Pointer to an array of command_registration records that + * contains the desired command parameters. The last record must have + * NULL for all fields. + * @param target The target that has to override current target. + * @returns ERROR_OK on success; ERROR_FAIL if any registration fails. + */ +static inline int register_commands_override_target(struct command_context *cmd_ctx, + const char *cmd_prefix, const struct command_registration *cmds, + struct target *target) +{ + return __register_commands(cmd_ctx, cmd_prefix, cmds, NULL, target); +} /** - * Unregisters command @c name from the given context, @c cmd_ctx. - * @param cmd_ctx The context of the registered command. - * @param parent The parent of the given command, or NULL. - * @param name The name of the command to unregister. - * @returns ERROR_OK on success, or an error code. + * Register one or more commands, as register_commands(), plus specify + * a pointer to command private data that would be accessible through + * the macro CMD_DATA. The private data will not be freed when command + * is unregistered. + * + * @param cmd_ctx The command_context in which to register the command. + * @param cmd_prefix Register this command as a child of this, or NULL to + * register a top-level command. + * @param cmds Pointer to an array of command_registration records that + * contains the desired command parameters. The last record must have + * NULL for all fields. + * @param data The command private data. + * @returns ERROR_OK on success; ERROR_FAIL if any registration fails. */ -int unregister_command(struct command_context *cmd_ctx, - struct command *parent, const char *name); +static inline int register_commands_with_data(struct command_context *cmd_ctx, + const char *cmd_prefix, const struct command_registration *cmds, + void *data) +{ + return __register_commands(cmd_ctx, cmd_prefix, cmds, data, NULL); +} + /** - * Unregisters all commands from the specfied context. + * Unregisters all commands from the specified context. * @param cmd_ctx The context that will be cleared of registered commands. - * @param parent If given, only clear commands from under this one command. + * @param cmd_prefix If given, only clear commands from under this one command. * @returns ERROR_OK on success, or an error code. */ int unregister_all_commands(struct command_context *cmd_ctx, - struct command *parent); - -struct command *command_find_in_context(struct command_context *cmd_ctx, - const char *name); -struct command *command_find_in_parent(struct command *parent, - const char *name); + const char *cmd_prefix); /** - * Update the private command data field for a command and all descendents. - * This is used when creating a new heirarchy of commands that depends - * on obtaining a dynamically created context. The value will be available - * in command handlers by using the CMD_DATA macro. - * @param c The command (group) whose data pointer(s) will be updated. - * @param p The new data pointer to use for the command or its descendents. + * Unregisters the help for all commands. Used at exit to remove the help + * added through the commands 'add_help_text' and 'add_usage_text'. + * @param cmd_ctx The context that will be cleared of registered helps. + * @returns ERROR_OK on success, or an error code. */ -void command_set_handler_data(struct command *c, void *p); +int help_del_all_commands(struct command_context *cmd_ctx); void command_set_output_handler(struct command_context *context, command_output_handler_t output_handler, void *priv); @@ -309,6 +352,14 @@ struct command_context *current_command_context(Jim_Interp *interp); * creates a command interpreter. */ struct command_context *command_init(const char *startup_tcl, Jim_Interp *interp); +/** + * Shutdown a command context. + * + * Free the command context and the associated Jim interpreter. + * + * @param context The command_context that will be destroyed. + */ +void command_exit(struct command_context *context); /** * Creates a copy of an existing command context. This does not create * a deep copy of the command list, so modifications in one context will @@ -325,10 +376,21 @@ struct command_context *copy_command_context(struct command_context *cmd_ctx); */ void command_done(struct command_context *context); -void command_print(struct command_context *context, const char *format, ...) +/* + * command_print() and command_print_sameline() are used to produce the TCL + * output of OpenOCD commands. command_print() automatically adds a '\n' at + * the end or the format string. Use command_print_sameline() to avoid the + * trailing '\n', e.g. to concatenate the command output in the same line. + * The very last '\n' of the command is stripped away (see run_command()). + * For commands that strictly require a '\n' as last output character, add + * it explicitly with either an empty command_print() or with a '\n' in the + * last command_print() and add a comment to document it. + */ +void command_print(struct command_invocation *cmd, const char *format, ...) __attribute__ ((format (PRINTF_ATTRIBUTE_FORMAT, 2, 3))); -void command_print_sameline(struct command_context *context, const char *format, ...) +void command_print_sameline(struct command_invocation *cmd, const char *format, ...) __attribute__ ((format (PRINTF_ATTRIBUTE_FORMAT, 2, 3))); + int command_run_line(struct command_context *context, char *line); int command_run_linef(struct command_context *context, const char *format, ...) __attribute__ ((format (PRINTF_ATTRIBUTE_FORMAT, 2, 3))); @@ -353,15 +415,19 @@ int parse_llong(const char *str, long long *ul); int parse ## name(const char *str, type * ul) DECLARE_PARSE_WRAPPER(_uint, unsigned); +DECLARE_PARSE_WRAPPER(_u64, uint64_t); DECLARE_PARSE_WRAPPER(_u32, uint32_t); DECLARE_PARSE_WRAPPER(_u16, uint16_t); DECLARE_PARSE_WRAPPER(_u8, uint8_t); DECLARE_PARSE_WRAPPER(_int, int); +DECLARE_PARSE_WRAPPER(_s64, int64_t); DECLARE_PARSE_WRAPPER(_s32, int32_t); DECLARE_PARSE_WRAPPER(_s16, int16_t); DECLARE_PARSE_WRAPPER(_s8, int8_t); +DECLARE_PARSE_WRAPPER(_target_addr, target_addr_t); + /** * @brief parses the string @a in into @a out as a @a type, or prints * a command error and passes the error code to the caller. If an error @@ -370,19 +436,64 @@ DECLARE_PARSE_WRAPPER(_s8, int8_t); * * This function may cause the calling function to return immediately, * so it should be used carefully to avoid leaking resources. In most - * situations, parsing should be completed in full before proceding + * situations, parsing should be completed in full before proceeding * to allocate resources, and this strategy will most prevents leaks. */ #define COMMAND_PARSE_NUMBER(type, in, out) \ do { \ int retval_macro_tmp = parse_ ## type(in, &(out)); \ - if (ERROR_OK != retval_macro_tmp) { \ - command_print(CMD_CTX, stringify(out) \ + if (retval_macro_tmp != ERROR_OK) { \ + command_print(CMD, stringify(out) \ " option value ('%s') is not valid", in); \ return retval_macro_tmp; \ } \ } while (0) +#define COMMAND_PARSE_ADDRESS(in, out) \ + COMMAND_PARSE_NUMBER(target_addr, in, out) + +/** + * @brief parses the command argument at position @a argn into @a out + * as a @a type, or prints a command error referring to @a name_str + * and passes the error code to the caller. @a argn will be incremented + * if no error occurred. Otherwise the calling function will return + * the error code produced by the parsing function. + * + * This function may cause the calling function to return immediately, + * so it should be used carefully to avoid leaking resources. In most + * situations, parsing should be completed in full before proceeding + * to allocate resources, and this strategy will most prevents leaks. + */ +#define COMMAND_PARSE_ADDITIONAL_NUMBER(type, argn, out, name_str) \ + do { \ + if (argn+1 >= CMD_ARGC || CMD_ARGV[argn+1][0] == '-') { \ + command_print(CMD, "no " name_str " given"); \ + return ERROR_FAIL; \ + } \ + ++argn; \ + COMMAND_PARSE_NUMBER(type, CMD_ARGV[argn], out); \ + } while (0) + +/** + * @brief parses the command argument at position @a argn into @a out + * as a @a type if the argument @a argn does not start with '-'. + * and passes the error code to the caller. @a argn will be incremented + * if no error occurred. Otherwise the calling function will return + * the error code produced by the parsing function. + * + * This function may cause the calling function to return immediately, + * so it should be used carefully to avoid leaking resources. In most + * situations, parsing should be completed in full before proceeding + * to allocate resources, and this strategy will most prevents leaks. + */ +#define COMMAND_PARSE_OPTIONAL_NUMBER(type, argn, out) \ + do { \ + if (argn+1 < CMD_ARGC && CMD_ARGV[argn+1][0] != '-') { \ + ++argn; \ + COMMAND_PARSE_NUMBER(type, CMD_ARGV[argn], out); \ + } \ + } while (0) + /** * Parse the string @c as a binary parameter, storing the boolean value * in @c out. The strings @c on and @c off are used to match different @@ -393,10 +504,10 @@ DECLARE_PARSE_WRAPPER(_s8, int8_t); do { \ bool value; \ int retval_macro_tmp = command_parse_bool_arg(in, &value); \ - if (ERROR_OK != retval_macro_tmp) { \ - command_print(CMD_CTX, stringify(out) \ + if (retval_macro_tmp != ERROR_OK) { \ + command_print(CMD, stringify(out) \ " option value ('%s') is not valid", in); \ - command_print(CMD_CTX, " choices are '%s' or '%s'", \ + command_print(CMD, " choices are '%s' or '%s'", \ on, off); \ return retval_macro_tmp; \ } \ @@ -413,7 +524,4 @@ COMMAND_HELPER(handle_command_parse_bool, bool *out, const char *label); #define COMMAND_PARSE_ENABLE(in, out) \ COMMAND_PARSE_BOOL(in, out, "enable", "disable") -void script_debug(Jim_Interp *interp, const char *cmd, - unsigned argc, Jim_Obj * const *argv); - -#endif /* COMMAND_H */ +#endif /* OPENOCD_HELPER_COMMAND_H */