X-Git-Url: https://review.openocd.org/gitweb?p=openocd.git;a=blobdiff_plain;f=src%2Fhelper%2Fcommand.h;h=3d1cdec8608730184e2ad4de6a1487070e608310;hp=b57ca75d85a3df6ea80cf22d855e2f747b4c19a5;hb=33a17fd35995a7f679f92600055a8f55ae380022;hpb=69076057dde9f4336b54fb4da677da8fe5da66bd diff --git a/src/helper/command.h b/src/helper/command.h index b57ca75d85..3d1cdec860 100644 --- a/src/helper/command.h +++ b/src/helper/command.h @@ -23,18 +23,17 @@ #ifndef COMMAND_H #define COMMAND_H -#include "types.h" +#include /* Integrate the JIM TCL interpretor into the command processing. */ #if BUILD_ECOSBOARD #include #include -/* Jim is provied by eCos */ -#include -#else -#include "jim.h" #endif +#include +#include + /* To achieve C99 printf compatibility in MinGW, gnu_printf should be * used for __attribute__((format( ... ))), with GCC v4.4 or later */ @@ -59,27 +58,16 @@ 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; - /* Execute a command. - * - * If the command fails, it *MUST* return a value != ERROR_OK - * (many commands break this rule, patches welcome!) - * - * 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 - * or not. If the operation failed, then a program can try - * an alternative approach. - * - * Returning ERROR_COMMAND_SYNTAX_ERROR will have the effect of - * printing out the syntax of the command. - */ command_output_handler_t output_handler; void *output_handler_priv; }; +struct command; + /** * When run_command is called, a new instance will be created on the * stack, filled with the proper values, and passed by reference to the @@ -87,6 +75,7 @@ struct command_context */ struct command_invocation { struct command_context *ctx; + struct command *current; const char *name; unsigned argc; const char **argv; @@ -151,18 +140,47 @@ struct command_invocation { * rather than accessing the variable directly. It may be moved. */ #define CMD_NAME cmd->name +/** + * Use this macro to access the current command being handled, + * rather than accessing the variable directly. It may be moved. + */ +#define CMD_CURRENT cmd->current +/** + * Use this macro to access the invoked command handler's data pointer, + * rather than accessing the variable directly. It may be moved. + */ +#define CMD_DATA CMD_CURRENT->jim_handler_data -/// The type signature for commands' handler functions. +/** + * The type signature for command handling functions. They are + * usually registered as part of command_registration, providing + * a high-level means for executing a command. + * + * If the command fails, it *MUST* return a value != ERROR_OK + * (many commands break this rule, patches welcome!) + * + * 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 + * or not. If the operation failed, then a program can try + * an alternative approach. + * + * Returning ERROR_COMMAND_SYNTAX_ERROR will have the effect of + * printing out the syntax of the command. + */ typedef __COMMAND_HANDLER((*command_handler_t)); struct command { - char *name; + const char *name; const char *help; + const char *usage; struct command *parent; struct command *children; command_handler_t handler; + Jim_CmdProc jim_handler; + void *jim_handler_data; enum command_mode mode; struct command *next; }; @@ -197,10 +215,25 @@ 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; enum command_mode mode; const char *help; + /// a string listing the options and arguments, required or optional + const char *usage; + + /** + * If non-NULL, the commands in @c chain will be registered in + * the same context and scope of this registration record. + * This allows modules to inherit lists commands from other + * modules. + */ + const struct command_registration *chain; }; +/// 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. @@ -219,16 +252,24 @@ struct command_registration { struct command* register_command(struct command_context *cmd_ctx, struct command *parent, const struct command_registration *rec); -#define COMMAND_REGISTER(_cmd_ctx, _parent, _name, _handler, _mode, _help) \ - ({ \ - struct command_registration cr = { \ - .name = _name, \ - .handler = _handler, \ - .mode = _mode, \ - .help = _help, \ - }; \ - register_command(_cmd_ctx, _parent, &cr); \ - }) +/** + * Register one or more commands in the specified context, as children + * of @c parent (or top-level commends, if NULL). In a registration's + * record contains a non-NULL @c chain member and name is NULL, the + * commands on the chain will be registered in the same context. + * 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 + * 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); + /** * Unregisters command @c name from the given context, @c cmd_ctx. @@ -248,18 +289,52 @@ int unregister_command(struct command_context *cmd_ctx, 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); + +/** + * 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. + */ +void command_set_handler_data(struct command *c, void *p); + void command_set_output_handler(struct command_context* context, command_output_handler_t output_handler, void *priv); -struct command_context* copy_command_context(struct command_context* context); int command_context_mode(struct command_context *context, enum command_mode mode); +/* Return the current command context associated with the Jim interpreter or + * alternatively the global default command interpreter + */ +struct command_context *current_command_context(Jim_Interp *interp); +/** + * Creates a new command context using the startup TCL provided and + * the existing Jim interpreter, if any. If interp == NULL, then command_init + * creates a command interpreter. + */ +struct command_context* command_init(const char *startup_tcl, Jim_Interp *interp); /** - * Creates a new command context using the startup TCL provided. + * 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 + * affect all shared contexts. The caller must track reference counting + * and ensure the commands are freed before destroying the last instance. + * @param cmd_ctx The command_context that will be copied. + * @returns A new command_context with the same state as the original. */ -struct command_context* command_init(const char *startup_tcl); -int command_done(struct command_context *context); +struct command_context* copy_command_context(struct command_context* cmd_ctx); +/** + * Frees the resources associated with a command context. The commands + * are not removed, so unregister_all_commands() must be called first. + * @param context The command_context that will be destroyed. + */ +void command_done(struct command_context *context); void command_print(struct command_context *context, const char *format, ...) __attribute__ ((format (PRINTF_ATTRIBUTE_FORMAT, 2, 3))); @@ -270,7 +345,7 @@ int command_run_linef(struct command_context *context, const char *format, ...) __attribute__ ((format (PRINTF_ATTRIBUTE_FORMAT, 2, 3))); void command_output_text(struct command_context *context, const char *data); -void process_jim_events(void); +void process_jim_events(struct command_context *cmd_ctx); #define ERROR_COMMAND_CLOSE_CONNECTION (-600) #define ERROR_COMMAND_SYNTAX_ERROR (-601) @@ -279,11 +354,6 @@ void process_jim_events(void); #define ERROR_COMMAND_ARGUMENT_OVERFLOW (-604) #define ERROR_COMMAND_ARGUMENT_UNDERFLOW (-605) -extern Jim_Interp *interp; - -void register_jim(struct command_context *context, const char *name, - Jim_CmdProc cmd, const char *help); - int parse_ulong(const char *str, unsigned long *ul); int parse_ullong(const char *str, unsigned long long *ul); @@ -316,11 +386,11 @@ DECLARE_PARSE_WRAPPER(_s8, int8_t); */ #define COMMAND_PARSE_NUMBER(type, in, out) \ do { \ - int retval = parse_##type(in, &(out)); \ - if (ERROR_OK != retval) { \ + int retval_macro_tmp = parse_##type(in, &(out)); \ + if (ERROR_OK != retval_macro_tmp) { \ command_print(CMD_CTX, stringify(out) \ " option value ('%s') is not valid", in); \ - return retval; \ + return retval_macro_tmp; \ } \ } while (0) @@ -333,13 +403,13 @@ DECLARE_PARSE_WRAPPER(_s8, int8_t); #define COMMAND_PARSE_BOOL(in, out, on, off) \ do { \ bool value; \ - int retval = command_parse_bool_arg(in, &value); \ - if (ERROR_OK != retval) { \ + int retval_macro_tmp = command_parse_bool_arg(in, &value); \ + if (ERROR_OK != retval_macro_tmp) { \ command_print(CMD_CTX, stringify(out) \ " option value ('%s') is not valid", in); \ command_print(CMD_CTX, " choices are '%s' or '%s'", \ on, off); \ - return retval; \ + return retval_macro_tmp; \ } \ out = value; \ } while (0)