failed approach
This commit is contained in:
503
gomspace/libutil/include/gs/util/gosh/command.h
Normal file
503
gomspace/libutil/include/gs/util/gosh/command.h
Normal file
@ -0,0 +1,503 @@
|
||||
#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
|
Reference in New Issue
Block a user