From 7e46765153ea2d372fbd146cb49d7df2562e9e8c Mon Sep 17 00:00:00 2001 From: Jakub Rzeszutko Date: Fri, 15 Jan 2021 14:04:21 +0100 Subject: [PATCH] shell: add getopt library support This functionality is is enabled by setting CONFIG_SHELL_GETOPT. It is not active by default. User can call following functions inside command handlers: - shell_getopt - getopt function based on freebsd implementation - shell_getopt_status_get - returns getopt status Beware when getopt functionality is enabled shell will not parse command handler to look for "-h" or "--help" options and print help message automatically. Signed-off-by: Jakub Rzeszutko --- include/shell/shell.h | 46 +++++++++++++++++++++++++++++++++++- include/shell/shell_getopt.h | 27 +++++++++++++++++++++ subsys/shell/CMakeLists.txt | 5 ++++ subsys/shell/Kconfig | 6 +++++ subsys/shell/shell.c | 4 ++++ subsys/shell/shell_getopt.c | 37 +++++++++++++++++++++++++++++ 6 files changed, 124 insertions(+), 1 deletion(-) create mode 100644 include/shell/shell_getopt.h create mode 100644 subsys/shell/shell_getopt.c diff --git a/include/shell/shell.h b/include/shell/shell.h index fc5f07851b9..7ef1e8686a8 100644 --- a/include/shell/shell.h +++ b/include/shell/shell.h @@ -16,6 +16,10 @@ #include #include +#if defined CONFIG_SHELL_GETOPT +#include +#endif + #ifdef __cplusplus extern "C" { #endif @@ -67,6 +71,7 @@ extern "C" { * @{ */ +struct getopt_state; struct shell_static_entry; /** @@ -649,6 +654,11 @@ struct shell_ctx { /*!< VT100 color and cursor position, terminal width.*/ struct shell_vt100_ctx vt100_ctx; +#if defined CONFIG_SHELL_GETOPT + /*!< getopt context for a shell backend. */ + struct getopt_state getopt_state; +#endif + uint16_t cmd_buff_len; /*!< Command length.*/ uint16_t cmd_buff_pos; /*!< Command buffer cursor position.*/ @@ -958,6 +968,40 @@ void shell_help(const struct shell *shell); /* @brief Command's help has been printed */ #define SHELL_CMD_HELP_PRINTED (1) +#if defined CONFIG_SHELL_GETOPT +/** + * @brief Parses the command-line arguments. + * + * It is based on FreeBSD implementation. + * + * @param[in] shell Pointer to the shell instance. + * @param[in] argc Arguments count. + * @param[in] argv Arguments. + * @param[in] ostr String containing the legitimate option characters. + * + * @return If an option was successfully found, function returns + * the option character. + * @return If options have been detected that is not in @p ostr + * function will return '?'. + * If function encounters an option with a missing + * argument, then the return value depends on the first + * character in optstring: if it is ':', then ':' is + * returned; otherwise '?' is returned. + * @return -1 If all options have been parsed. + */ +int shell_getopt(const struct shell *shell, int argc, char *const argv[], + const char *ostr); + +/** + * @brief Returns shell_getopt state. + * + * @param[in] shell Pointer to the shell instance. + * + * @return Pointer to struct getopt_state. + */ +struct getopt_state *shell_getopt_state_get(const struct shell *shell); +#endif /* CONFIG_SHELL_GETOPT */ + /** @brief Execute command. * * Pass command line to shell to execute. @@ -973,7 +1017,7 @@ void shell_help(const struct shell *shell); * @option{CONFIG_SHELL_BACKEND_DUMMY} option is enabled. * @param[in] cmd Command to be executed. * - * @returns Result of the execution + * @return Result of the execution */ int shell_execute_cmd(const struct shell *shell, const char *cmd); diff --git a/include/shell/shell_getopt.h b/include/shell/shell_getopt.h new file mode 100644 index 00000000000..789aa11c18b --- /dev/null +++ b/include/shell/shell_getopt.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2021 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef SHELL_GETOPT_H__ +#define SHELL_GETOPT_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +/* Initializing shell getopt module. + * + * @param[in] shell Pointer to the shell instance. + */ +void z_shell_getopt_init(struct getopt_state *state); + +#ifdef __cplusplus +} +#endif + +#endif /* SHELL_GETOPT_H__ */ diff --git a/subsys/shell/CMakeLists.txt b/subsys/shell/CMakeLists.txt index f911ee3bd26..442ab2b7c59 100644 --- a/subsys/shell/CMakeLists.txt +++ b/subsys/shell/CMakeLists.txt @@ -35,6 +35,11 @@ zephyr_sources_ifdef( shell_help.c ) +zephyr_sources_ifdef( + CONFIG_SHELL_GETOPT + shell_getopt.c + ) + zephyr_sources_ifdef( CONFIG_SHELL_CMDS shell_cmds.c diff --git a/subsys/shell/Kconfig b/subsys/shell/Kconfig index 094224347c9..5d30fa691ee 100644 --- a/subsys/shell/Kconfig +++ b/subsys/shell/Kconfig @@ -109,6 +109,12 @@ config SHELL_VT100_COLORS help If enabled VT100 colors are used in shell (e.g. print errors in red). +config SHELL_GETOPT + bool "Enable getopt support" + select GETOPT + help + Enables getopt support in the shell. + config SHELL_METAKEYS bool "Enable metakeys" default y if !SHELL_MINIMAL diff --git a/subsys/shell/shell.c b/subsys/shell/shell.c index 5d6eb684595..7655c132ab7 100644 --- a/subsys/shell/shell.c +++ b/subsys/shell/shell.c @@ -533,6 +533,10 @@ static int exec_cmd(const struct shell *shell, size_t argc, const char **argv, } if (!ret_val) { +#if CONFIG_SHELL_GETOPT + z_shell_getopt_init(&shell->ctx->getopt_state); +#endif + z_flag_cmd_ctx_set(shell, true); /* Unlock thread mutex in case command would like to borrow * shell context to other thread to avoid mutex deadlock. diff --git a/subsys/shell/shell_getopt.c b/subsys/shell/shell_getopt.c new file mode 100644 index 00000000000..9b1dea14463 --- /dev/null +++ b/subsys/shell/shell_getopt.c @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2021 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +void z_shell_getopt_init(struct getopt_state *state) +{ + getopt_init(state); +} + +int shell_getopt(const struct shell *shell, int argc, char *const argv[], + const char *ostr) +{ + if (!IS_ENABLED(CONFIG_SHELL_GETOPT)) { + return 0; + } + + __ASSERT_NO_MSG(shell); + + return getopt(&shell->ctx->getopt_state, argc, argv, ostr); +} + +struct getopt_state *shell_getopt_state_get(const struct shell *shell) +{ + if (!IS_ENABLED(CONFIG_SHELL_GETOPT)) { + return NULL; + } + + __ASSERT_NO_MSG(shell); + + return &shell->ctx->getopt_state; +}