504 lines
16 KiB
C
504 lines
16 KiB
C
#ifndef GS_UTIL_GOSH_COMMAND_H
|
|
#define GS_UTIL_GOSH_COMMAND_H
|
|
/* Copyright (c) 2013-2017 GomSpace A/S. All rights reserved. */
|
|
/**
|
|
@file
|
|
|
|
Command framework.
|
|
|
|
Provides a simple way of organizing commands in a hierarchy. A command is a text string mapping to a function - supporting arguments.
|
|
*/
|
|
|
|
#include <gs/util/stdio.h>
|
|
#include <gs/util/pgm.h>
|
|
#include <gs/util/check.h>
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
/**
|
|
Max langth of a command (including NUL termination).
|
|
*/
|
|
#define GS_COMMAND_MAX_LEN_COMMAND 20
|
|
|
|
/**
|
|
Flag for hiding command in help and tab-complete.
|
|
*/
|
|
#define GS_COMMAND_FLAG_HIDDEN 0x02
|
|
|
|
/**
|
|
'root' command attribute.
|
|
|
|
On embedded (none Linux) systems, it is prefered to store as much as possible in \a program memory, in order to save RAM.
|
|
This is accomplished by tagging all \a root commands with this attribute, which instructs the linker to put all commands in a named
|
|
section. This section is then through the linker-script, placed in \a program memory.
|
|
The command framework can read commands directly from this section, and therefore doesn't need an RAM to maintain the list.
|
|
|
|
The gs_command_register() must still be called for all \a root commands, which ensures that the linker doesn't throw away the
|
|
command objects, due to missing code reference.
|
|
|
|
On a Linux system, the commands are not group in a section. Instead gs_command_register() dynamicly builds a list with the commands.
|
|
|
|
@see gs_command_register()
|
|
*/
|
|
#if (__linux__ == 0)
|
|
#define GS_COMMAND_ROOT __attribute__ ((section(".commands")))
|
|
#else
|
|
#define GS_COMMAND_ROOT
|
|
#endif
|
|
|
|
/**
|
|
Sub command attribute,
|
|
|
|
Only necesasry on AVR8, due to its memory model.
|
|
*/
|
|
#define GS_COMMAND_SUB GS_PGM_OBJECT
|
|
|
|
/**
|
|
Macro for initializing command chains.
|
|
*/
|
|
#define GS_COMMAND_INIT_CHAIN(__list) {.list = __list, .count = GS_ARRAY_SIZE(__list)}
|
|
|
|
/**
|
|
Macro for registering commands.
|
|
|
|
@see gs_command_register()
|
|
*/
|
|
#define GS_COMMAND_REGISTER(__cmd) gs_command_register(__cmd, GS_ARRAY_SIZE(__cmd))
|
|
|
|
/**
|
|
Command reference.
|
|
@note Use gs_command_t instead of 'struct command'.
|
|
*/
|
|
typedef struct command gs_command_t;
|
|
|
|
/**
|
|
Commands context reference
|
|
@note Use gs_command_context_t instead of struct command_context
|
|
*/
|
|
typedef struct command_context gs_command_context_t;
|
|
|
|
/**
|
|
Command output interface
|
|
*/
|
|
typedef struct command_io_functions {
|
|
/**
|
|
Function interface for setting result
|
|
@param output_ctx pointer to output context for the given impl.
|
|
@param group Group name specifies the group that a given key/value pair belongs to.
|
|
@param key key name
|
|
@param value string value of the result
|
|
@return_gs_error_t
|
|
*/
|
|
gs_error_t (*set_result)(gs_command_context_t *ctx, const char *group, const char *key, const char *value);
|
|
/**
|
|
Function interface for flushing results. Used by the command handler to ensure output/results
|
|
are flushed to stdout/File or any other receiver of the output.
|
|
@param output_ctx pointer to output context for the given impl.
|
|
@return_gs_error_t
|
|
*/
|
|
gs_error_t (*flush)(gs_command_context_t *ctx);
|
|
/**
|
|
Function interface for waiting for key/input
|
|
@param output_ctx pointer to output context for the given impl.
|
|
@param ch pointer to character returned by function
|
|
@param timeout_ms maximum time to wait of the character.
|
|
@return_gs_error_t
|
|
*/
|
|
gs_error_t (*wait_for_key)(gs_command_context_t *ctx, int *ch, int timeout_ms);
|
|
} gs_command_io_functions_t;
|
|
|
|
|
|
|
|
/**
|
|
Command context for executing a command.
|
|
*/
|
|
struct command_context {
|
|
/**
|
|
Input (raw) command line, including arguments.
|
|
*/
|
|
const char * command_line;
|
|
|
|
/**
|
|
Command being executed.
|
|
*/
|
|
const gs_command_t * command;
|
|
|
|
/**
|
|
Number of arguments (standard argc style).
|
|
*/
|
|
int argc;
|
|
|
|
/**
|
|
Argument array (standard argv style).
|
|
*/
|
|
char **argv;
|
|
|
|
/**
|
|
FILE handle for capturing stdout from command.
|
|
*/
|
|
FILE* out;
|
|
|
|
/**
|
|
getopt variable.
|
|
*/
|
|
int optind;
|
|
|
|
/**
|
|
getopt variable.
|
|
*/
|
|
int optopt;
|
|
|
|
/**
|
|
getopt variable.
|
|
*/
|
|
char *optarg;
|
|
|
|
/**
|
|
getopt variable.
|
|
*/
|
|
int optsp;
|
|
|
|
/**
|
|
Function interface for I/O operations
|
|
*/
|
|
const gs_command_io_functions_t *io_functions;
|
|
|
|
/**
|
|
Pointer for storing the context used by the I/O functions
|
|
*/
|
|
void * io_ctx;
|
|
};
|
|
|
|
/**
|
|
Command logging call-back
|
|
|
|
logs information on the command called.
|
|
@param[in] cmd_line command line string
|
|
@param[in] ret return code from command execution framework
|
|
@param[in] cmd_ret return code from the executed command
|
|
@param[in] start time_stamp when command execution started.
|
|
@param[in] end time_stamp when command execution completed.
|
|
@param[in] ctx context pointer for the logger.
|
|
@return_gs_error_t
|
|
*/
|
|
typedef gs_error_t (*gs_command_log_t)(const char *cmd_line, gs_error_t ret, gs_error_t cmd_ret, gs_timestamp_t start, gs_timestamp_t end, void * ctx);
|
|
|
|
/**
|
|
Command handler.
|
|
*/
|
|
typedef int (*gs_command_handler_t)(gs_command_context_t * ctx);
|
|
|
|
/**
|
|
Completer call-back (tab complete).
|
|
|
|
@param[in] ctx command context.
|
|
@param[in] arg_to_complete argument to complete
|
|
@return #GS_OK Found at least 1 match.
|
|
The \a completer is expected to have completed more of the command line.
|
|
If the framework detects multiple matches, the framework will proceed as if #GS_ERROR_AMBIGUOUS was returned.
|
|
The framework doesn't expect anything to be printed to \a out, but will update/refresh the console line.
|
|
@return #GS_ERROR_AMBIGUOUS Ambiguous - multiple matches or force the framework to show help.
|
|
The \a completer may have extended/completed more of the command line.
|
|
The framework expects the \a completer to have printed to \a out, and will show help/usage for the command on a new line.
|
|
@return #GS_ERROR_NOT_FOUND (or others) No matches found or no more arguments to complete.
|
|
The framewrok doesn't expect anything to be printed to \a out, and will not update the console.
|
|
*/
|
|
typedef gs_error_t (*gs_command_completer_t)(gs_command_context_t * ctx, int arg_to_complete);
|
|
|
|
/**
|
|
Add token - helper to 'tab complete' argument(s).
|
|
|
|
@param[in] ctx command context.
|
|
@param[in] token possible completion - the API will find the common part.
|
|
@param[in] exact \a true if \a token is an exact match - all other added tokens will be ignored.
|
|
@return number of tokens added.
|
|
*/
|
|
unsigned int gs_command_completer_add_token(gs_command_context_t * ctx, const char * token, bool exact);
|
|
|
|
/**
|
|
Chain element for chaning sub-commands.
|
|
*/
|
|
typedef struct {
|
|
/**
|
|
Command list.
|
|
*/
|
|
const gs_command_t * list;
|
|
/**
|
|
Number of commands in the \a list.
|
|
*/
|
|
unsigned int count;
|
|
} gs_command_chain_t;
|
|
|
|
/**
|
|
Signals no command arguments in command definition, see mandatory arguments.
|
|
*/
|
|
#define GS_COMMAND_NO_ARGS 255
|
|
|
|
/**
|
|
Command definition.
|
|
*/
|
|
struct command {
|
|
#if (__AVR__)
|
|
char name[GS_COMMAND_MAX_LEN_COMMAND];
|
|
char help[50];
|
|
char usage[50];
|
|
#else
|
|
/**
|
|
Name.
|
|
*/
|
|
const char * const name;
|
|
/**
|
|
Help text.
|
|
*/
|
|
const char * const help;
|
|
/**
|
|
Usage text.
|
|
*/
|
|
const char * const usage;
|
|
#endif
|
|
/**
|
|
Command handler - the "actual command function".
|
|
*/
|
|
gs_command_handler_t handler;
|
|
#if (__AVR__ == 0)
|
|
/**
|
|
Completer function - helps completing an argument.
|
|
*/
|
|
gs_command_completer_t completer;
|
|
#endif
|
|
/**
|
|
Sub-command (if any).
|
|
*/
|
|
gs_command_chain_t chain;
|
|
/**
|
|
Mode/flags.
|
|
See #GS_COMMAND_FLAG_HIDDEN.
|
|
*/
|
|
unsigned int mode;
|
|
/**
|
|
Number of mandatory (minimum) arguments.
|
|
|
|
@note Due to backwards compatibility, 0 (zero) cannot be used to signal no arguments - use #GS_COMMAND_NO_ARGS instead, if command doesn't take any arguments (mandatory or optional).
|
|
*/
|
|
uint8_t mandatory_args;
|
|
/**
|
|
Number of optional arguments.
|
|
*/
|
|
uint8_t optional_args;
|
|
/**
|
|
Filler for future use.
|
|
*/
|
|
uint8_t filler[2];
|
|
};
|
|
|
|
/**
|
|
Returns the arguments as a string, where arguments are separated by spaces.
|
|
@param ctx command context.
|
|
@return Pointer to concatenated arguments
|
|
*/
|
|
const char * gs_command_args(gs_command_context_t *ctx);
|
|
|
|
/**
|
|
Execute command.
|
|
@deprecated Replaced by gs_command_execute & gs_command_execute_stdio
|
|
|
|
Looks up a command and executes it. If the command is executed (this function returns GS_OK), the command's return
|
|
result is stored in \a command_result.
|
|
|
|
@param[in] command Command to execute, including arguments separated by spaces.
|
|
@param[out] command_result Result returned by \a command (if executed). Use \a NULL to ignore result.
|
|
@return #GS_ERROR_NOT_FOUND if command wasn't found.
|
|
@return #GS_ERROR_ARG if number of argumenets exceeds \a mandatory + \a optional count.
|
|
@return_gs_error_t
|
|
*/
|
|
gs_error_t gs_command_run(const char * command, gs_error_t * command_result);
|
|
|
|
/**
|
|
Execute command.
|
|
|
|
Looks up a command and executes it. If the command is executed (this function returns GS_OK), the command's return
|
|
result is stored in \a command_result.
|
|
|
|
@param[in] command Command to execute, including arguments separated by spaces.
|
|
@param[out] command_result Result returned by \a command (if executed). Use \a NULL to ignore result.
|
|
@param[in] out output (FILE) stream
|
|
@param[in] iof Pointer to function interface of IO operations
|
|
@param[in] iof_ctx Pointer to context used by the IO function interface
|
|
@return #GS_ERROR_NOT_FOUND if command wasn't found.
|
|
@return #GS_ERROR_ARG if number of argumenets exceeds \a mandatory + \a optional count.
|
|
@return_gs_error_t
|
|
*/
|
|
gs_error_t gs_command_execute(const char * command, gs_error_t * command_result, FILE *out, const gs_command_io_functions_t * iof, void * iof_ctx);
|
|
|
|
/**
|
|
Execute command.
|
|
|
|
Looks up a command and executes it. If the command is executed (this function returns GS_OK), the command's return
|
|
result is stored in \a command_result. The results are printed on stdout and input captured on stdin.
|
|
|
|
@param[in] command Command to execute, including arguments separated by spaces.
|
|
@param[out] command_result Result from command. Use \a NULL to ignore result.
|
|
@return #GS_OK if command was executed - result returned in \a command_result. Otherwise an error indicating why the command wasn't executed.
|
|
*/
|
|
gs_error_t gs_command_execute_stdio(const char * command, gs_error_t * command_result);
|
|
|
|
/**
|
|
Set output
|
|
|
|
Sets output from command, using the io function struct in ctx.
|
|
|
|
@param[in] ctx the command context
|
|
@param[in] group a string specifying the group of the result. Leave blank if not used.
|
|
@param[in] key a string specifying the key/name of the result variable.
|
|
@param[in] value a string representation of the result value.
|
|
@return_gs_error_t
|
|
*/
|
|
gs_error_t gs_command_set_output(gs_command_context_t *ctx, const char* group, const char* key, const char* value);
|
|
|
|
/**
|
|
Set output
|
|
|
|
Sets output from command using printf formatting, using the io function struct in ctx.
|
|
|
|
@param[in] ctx the command context
|
|
@param[in] group a string specifying the group of the result. Leave blank if not used.
|
|
@param[in] key a string specifying the key/name of the result variable.
|
|
@param[in] format printf syntax for formatting data
|
|
@return_gs_error_t
|
|
*/
|
|
gs_error_t gs_command_set_output_printf(gs_command_context_t *ctx, const char* group, const char* key, const char * format, ...);
|
|
|
|
/**
|
|
Flush output/Results
|
|
|
|
Instruct the command output stream & results to be flushed from it's buffers.
|
|
|
|
@param[in] ctx the command context
|
|
@return_gs_error_t
|
|
*/
|
|
gs_error_t gs_command_flush_output(gs_command_context_t *ctx);
|
|
|
|
/**
|
|
Wait for any key input
|
|
|
|
Instruct the command input stream to wait for any key.
|
|
|
|
@param[in] ctx the command context
|
|
@param[in] timeout_ms timeout, < 0: block forever, 0: poll, > 0: wait number of milliseconds.
|
|
@return true if command should proceed (either because of key press present or if no input stream available)
|
|
*/
|
|
bool gs_command_wait_any_key(gs_command_context_t *ctx, int timeout_ms);
|
|
|
|
/**
|
|
Wait for key input
|
|
|
|
Instruct the io stream to wait for a key, and return the pressed key in ch.
|
|
|
|
@param[in] ctx the command context
|
|
@param[out] ch the character that was read on the input stream
|
|
@param[in] timeout_ms timeout, < 0: block forever, 0: poll, > 0: wait number of milliseconds.
|
|
@return #GS_OK if key was read
|
|
@return #GS_ERROR_HANDLE if no input stream is present
|
|
@return #GS_ERROR_TIMEOUT on timeout.
|
|
*/
|
|
gs_error_t gs_command_wait_key(gs_command_context_t *ctx, int* ch, int timeout_ms);
|
|
|
|
/**
|
|
Register commands.
|
|
|
|
gs_command_init() must be called prior to registering any commands.
|
|
|
|
See #GS_COMMAND_ROOT for details.
|
|
|
|
@param[in] cmds Pointer to command array
|
|
@param[in] cmd_count Number of commands in command array
|
|
@return_gs_error_t
|
|
*/
|
|
gs_error_t gs_command_register(const gs_command_t * cmds, size_t cmd_count);
|
|
|
|
/**
|
|
Initialize command system and register default commands.
|
|
|
|
Registers following commands: gs_log_register_commands() and gs_command_register_default_commands().
|
|
|
|
@param[in] min_stack_size Minimum stack size required for executing commands. The stack size will be used by other sub-systems such as gs_console, g-script. Stack size may be ignored on some platforms, e.g. Linux.
|
|
@return_gs_error_t
|
|
@see gs_command_init_no_commands()
|
|
*/
|
|
gs_error_t gs_command_init(size_t min_stack_size);
|
|
|
|
/**
|
|
Initialize command system (without any default commands).
|
|
|
|
@param[in] min_stack_size Minimum stack size required for executing commands. The stack size will be used by other sub-systems such as gs_console, g-script. Stack size may be ignored on some platforms, e.g. Linux.
|
|
@return_gs_error_t
|
|
@see gs_command_init()
|
|
*/
|
|
gs_error_t gs_command_init_no_commands(size_t min_stack_size);
|
|
|
|
|
|
/**
|
|
Register a call-back used for logging of command execution.
|
|
|
|
@param[in] log_cb the logging call back.
|
|
@param[in] log_ctx pointer to context data. Set to NULL if not used.
|
|
@return_gs_error_t
|
|
*/
|
|
gs_error_t gs_command_register_logger(gs_command_log_t log_cb, void *log_ctx);
|
|
|
|
/**
|
|
Default implementation of the command logger, that can be used if no other
|
|
custom command logger is provided by the system.
|
|
|
|
@param[in] cmd_line command line string
|
|
@param[in] ret return code provided by the command execution function.
|
|
@param[in] cmd_ret return code provided by the executed command.
|
|
@param[in] t_start time stamp when command execution started.
|
|
@param[in] t_end time stamp when command execution completed.
|
|
@param[in] log_ctx context for the command logger.
|
|
@return_gs_error_t
|
|
*/
|
|
gs_error_t gs_command_logger_default(const char* cmd_line, gs_error_t ret, gs_error_t cmd_ret, gs_timestamp_t t_start, gs_timestamp_t t_end, void * log_ctx);
|
|
|
|
/**
|
|
Return minimum stack size.
|
|
@return minimm stack size required for executing commands. The minimum stack size is set by call to gs_command_init().
|
|
*/
|
|
size_t gs_command_get_stack_size(void);
|
|
|
|
/**
|
|
Register set of default commands.
|
|
@return_gs_error_t
|
|
*/
|
|
gs_error_t gs_command_register_default_commands(void);
|
|
|
|
/**
|
|
Split line into argc/argv.
|
|
|
|
@param[in] line line to split - the line will be chop up into argv.
|
|
@param[out] argc argc count.
|
|
@param[out] argv argv array.
|
|
@param[in] max_argc max argv elements.
|
|
@return \a true if successfull, else \a false.
|
|
*/
|
|
bool gs_command_build_argv(char *line, int *argc, char **argv, int max_argc);
|
|
|
|
/**
|
|
Parse options.
|
|
|
|
Adapted from AT&T public domain source from:
|
|
http://www.informatica.co.cr/unix-source-code/research/1985/1103.html
|
|
|
|
@param[in] ctx command context.
|
|
@param[in] opts options
|
|
@return option character
|
|
*/
|
|
int gs_command_getopt(gs_command_context_t *ctx, const char *opts);
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
#endif
|