From 5e84f1b02275df27bebfa1fc8c12de63c60a6a54 Mon Sep 17 00:00:00 2001 From: prozessorkern Date: Sun, 22 Mar 2020 21:27:18 +0100 Subject: [PATCH] added continuous mode support fix #3 If a command returns SHELLMATTA_CONTINUE all received data is passed to this command until it returns != SHELLMATTA_CONTINUE or a cancel is received The data is passed stdin like and can be read byte by byte vie shellmatta_read The stdin buffer is overwritten witch each new char --- api/shellmatta.h | 1 + example/main.c | 25 ++++++++++++++ src/shellmatta.c | 72 ++++++++++++++++++++++++++++++---------- src/shellmatta_history.c | 2 +- src/shellmatta_opt.c | 52 ++++++++++++++--------------- src/shellmatta_utils.c | 1 + src/shellmatta_utils.h | 14 ++++---- 7 files changed, 115 insertions(+), 52 deletions(-) diff --git a/api/shellmatta.h b/api/shellmatta.h index 8af38ac..281413f 100644 --- a/api/shellmatta.h +++ b/api/shellmatta.h @@ -144,6 +144,7 @@ typedef struct shellmatta_write_t write; /**< pointer to write function */ shellmatta_cmd_t helpCmd; /**< help command structure */ shellmatta_cmd_t *cmdList; /**< pointer to the first command */ + shellmatta_cmd_t *continuousCmd; /**< command to be called continuously */ bool cmdListIsConst; /**< true if the #cmdList was passed during initialization */ shellmatta_opt_t optionParser; /**< option parser sructure */ diff --git a/example/main.c b/example/main.c index d1523f9..19224c7 100644 --- a/example/main.c +++ b/example/main.c @@ -119,6 +119,30 @@ static shellmatta_retCode_t reset(shellmatta_handle_t handle, const char *argume } shellmatta_cmd_t resetCommand = {"reset", NULL, "resets the shellmatta instance", "reset [prompt]", reset, NULL}; +static shellmatta_retCode_t continuous(shellmatta_handle_t handle, const char *arguments, uint32_t length) +{ + (void)arguments; + (void)length; + + shellmatta_retCode_t ret = SHELLMATTA_CONTINUE; + uint32_t stdinLength; + char *stdinData; + + shellmatta_read(handle, &stdinData, &stdinLength); + if(NULL != stdinData) + { + if('x' == stdinData[0u]) + { + ret = SHELLMATTA_OK; + } + + stdinData[0u] ++; + shellmatta_write(handle, stdinData, stdinLength); + } + return ret; +} +shellmatta_cmd_t continuousCommand = {"continuous", "cont", "prints continously all input bytes", "continuous", continuous, NULL}; + shellmatta_retCode_t writeFct(const char* data, uint32_t length) { @@ -164,6 +188,7 @@ int main(int argc, char **argv) shellmatta_addCmd(handle, &removeCommand); shellmatta_addCmd(handle, &emptyCommand); shellmatta_addCmd(handle, &resetCommand); + shellmatta_addCmd(handle, &continuousCommand); while(exitRequest == false) { diff --git a/src/shellmatta.c b/src/shellmatta.c index be004c0..2caa763 100644 --- a/src/shellmatta.c +++ b/src/shellmatta.c @@ -96,9 +96,10 @@ shellmatta_retCode_t shellmatta_doInit( inst->hereLength = 0u; inst->mode = SHELLMATTA_MODE_INSERT; inst->cmdList = &(inst->helpCmd); + inst->continuousCmd = NULL; inst->cmdListIsConst = false; - /*! -# copy the help command structure to this instance */ + /** -# copy the help command structure to this instance */ memcpy(&(inst->helpCmd), &helpCmd, sizeof(shellmatta_cmd_t)); if(NULL != cmdList) @@ -132,11 +133,12 @@ shellmatta_retCode_t shellmatta_resetShell( shellmatta_handle_t handle, bool pri shellmatta_instance_t *inst = (shellmatta_instance_t *)handle; shellmatta_retCode_t ret = SHELLMATTA_OK; - /*! -# check if the instance is plausible */ + /** -# check if the instance is plausible */ if( (NULL != handle) && (SHELLMATTA_MAGIC == inst->magic)) { inst->inputCount = 0u; + inst->continuousCmd = NULL; inst->lastNewlineIdx = 0u; inst->cursor = 0u; inst->stdinIdx = 0u; @@ -276,25 +278,25 @@ shellmatta_retCode_t shellmatta_removeCmd(shellmatta_handle_t handle, shellmatta tempCmd = inst->cmdList; prevCmd = NULL; - /*! -# loop through command list */ + /** -# loop through command list */ while(NULL != tempCmd) { - /*! -# compare command strings to find the command to delete */ + /** -# compare command strings to find the command to delete */ if (0 == strcmp( tempCmd->cmd, cmd->cmd) && (strlen(tempCmd->cmd) == strlen(cmd->cmd))) { - /*! -# first command removed */ + /** -# first command removed */ if(NULL == prevCmd) { inst->cmdList = tempCmd->next; } - /*! -# last command removed */ + /** -# last command removed */ else if(NULL == tempCmd->next) { prevCmd->next = NULL; } - /*! -# command removed from the middle of the list */ + /** -# command removed from the middle of the list */ else { prevCmd->next = tempCmd->next; @@ -363,6 +365,7 @@ shellmatta_retCode_t shellmatta_processData(shellmatta_handle_t handle, uint32_t byteCounter; shellmatta_retCode_t ret = SHELLMATTA_OK; + shellmatta_retCode_t cmdRet; shellmatta_instance_t *inst = (shellmatta_instance_t*)handle; /** -# check parameters for plausibility */ @@ -372,8 +375,22 @@ shellmatta_retCode_t shellmatta_processData(shellmatta_handle_t handle, /** -# process byte wise */ for (byteCounter = 0u; byteCounter < size; byteCounter++) { + /** -# in continuous mode - pass data directly to the command */ + if(NULL != inst->continuousCmd) + { + /** -# copy data and call command function */ + inst->buffer[inst->stdinIdx] = data[byteCounter]; + inst->stdinLength = 1u; + cmdRet = inst->continuousCmd->cmdFct(inst, inst->buffer, inst->inputCount); + + /** -# check if continuous mode is canceled */ + if(('\x03' == data[byteCounter]) || (SHELLMATTA_CONTINUE != cmdRet)) + { + utils_terminateInput(inst); + } + } /** -# handle escape sequences */ - if(inst->escapeCounter != 0u) + else if(inst->escapeCounter != 0u) { escape_handleSequence(inst, *data); } @@ -460,8 +477,8 @@ shellmatta_retCode_t shellmatta_processData(shellmatta_handle_t handle, history_storeCmd(inst); history_reset(inst); - /*! -# process heredoc as stdin like input */ - /*! -# find start of heredoc data */ + /** -# process heredoc as stdin like input */ + /** -# find start of heredoc data */ inst->stdinIdx = inst->hereDelimiterIdx + inst->hereLength; while( ('\n' == inst->buffer[inst->stdinIdx]) || ('\r' == inst->buffer[inst->stdinIdx])) @@ -481,7 +498,7 @@ shellmatta_retCode_t shellmatta_processData(shellmatta_handle_t handle, } else { - /*! -# the party goes on - print the \r and add a \n to satisfy most terminals */ + /** -# the party goes on - print the \r and add a \n to satisfy most terminals */ inst->lastNewlineIdx = inst->inputCount; utils_insertChars(inst, data, 1u); } @@ -519,7 +536,15 @@ shellmatta_retCode_t shellmatta_processData(shellmatta_handle_t handle, utils_writeEcho(inst, "\r\n", 2u); shellmatta_opt_init(inst, cmdLen + 1u); cmdExecuted = 1u; - cmd->cmdFct(inst, inst->buffer, inst->inputCount); + cmdRet = cmd->cmdFct(inst, inst->buffer, inst->inputCount); + if(SHELLMATTA_CONTINUE == cmdRet) + { + inst->continuousCmd = cmd; + + /** -# initialize stdin buffer */ + inst->stdinIdx = inst->inputCount + 1u; + inst->stdinLength = 0u; + } cmd = NULL; } else @@ -534,9 +559,13 @@ shellmatta_retCode_t shellmatta_processData(shellmatta_handle_t handle, inst->write(inst->buffer, inst->inputCount); inst->write(" not found", 10u); } - utils_terminateInput(inst); - } + /** -# terminate this session if no continuous mode is requested */ + if(NULL == inst->continuousCmd) + { + utils_terminateInput(inst); + } + } } /** -# check for tabulator key - auto complete */ else if('\t' == *data) @@ -546,7 +575,7 @@ shellmatta_retCode_t shellmatta_processData(shellmatta_handle_t handle, } /** -# check for cancel - * terminate current input and print prompt again */ - else if(3 == *data) + else if('\x03' == *data) { inst->dirty = false; history_reset(inst); @@ -614,7 +643,7 @@ shellmatta_retCode_t shellmatta_write( shellmatta_handle_t handle, /** * @brief reads the stdin like buffer * @param[in] handle shellmatta instance handle - * @param[out] data pointer to pointer to store ref to the buffer + * @param[out] data stdin data or NULL * @param[out] length size of the stdin data * @return */ @@ -631,8 +660,15 @@ shellmatta_retCode_t shellmatta_read( shellmatta_handle_t handle, && (NULL != data) && (NULL != length)) { - /** -# return a pointer to the data */ - *data = &(inst->buffer[inst->stdinIdx]); + /** -# return a pointer to the data or NULL */ + if(0u == inst->stdinLength) + { + *data = NULL; + } + else + { + *data = &(inst->buffer[inst->stdinIdx]); + } *length = inst->stdinLength; } diff --git a/src/shellmatta_history.c b/src/shellmatta_history.c index 2066226..1731dc2 100644 --- a/src/shellmatta_history.c +++ b/src/shellmatta_history.c @@ -205,7 +205,7 @@ void history_restoreCmd(shellmatta_instance_t *inst) ret = getHistoryByte(inst, &byte); - /*! -# delete the input if there is data in the history buffer */ + /** -# delete the input if there is data in the history buffer */ if(true == ret) { utils_clearInput(inst); diff --git a/src/shellmatta_opt.c b/src/shellmatta_opt.c index ed08f15..ad86ddd 100644 --- a/src/shellmatta_opt.c +++ b/src/shellmatta_opt.c @@ -36,7 +36,7 @@ static shellmatta_retCode_t findNextHunk(shellmatta_instance_t *inst) uint32_t exeptionOffset = 0u; char quotation = '\0'; /* holds the current quotation mark if any */ - /*! -# find beginning of next hunk */ + /** -# find beginning of next hunk */ while( (newOffset < inst->inputCount) && ((' ' == inst->buffer[newOffset]) || ('\0' == inst->buffer[newOffset]))) @@ -46,21 +46,21 @@ static shellmatta_retCode_t findNextHunk(shellmatta_instance_t *inst) inst->optionParser.offset = newOffset; - /*! -# determine length */ + /** -# determine length */ while((newOffset < inst->inputCount) && (((' ' != inst->buffer[newOffset]) && ('\0' != inst->buffer[newOffset])) || '\0' != quotation)) { - /*! -# check for new quotation */ + /** -# check for new quotation */ if((('\'' == inst->buffer[newOffset]) || ('"' == inst->buffer[newOffset])) && (quotation == '\0')) { quotation = inst->buffer[newOffset]; exeptionOffset ++; } - /*! -# check if quotation has ended */ + /** -# check if quotation has ended */ else if(quotation == inst->buffer[newOffset]) { exeptionOffset ++; - /*! -# check if quotation is excaped */ + /** -# check if quotation is excaped */ if('\\' != inst->buffer[newOffset - 1u]) { quotation = '\0'; @@ -72,7 +72,7 @@ static shellmatta_retCode_t findNextHunk(shellmatta_instance_t *inst) } else { - /*! -# shift back chars */ + /** -# shift back chars */ if(0u != exeptionOffset) { inst->buffer[newOffset - exeptionOffset] = inst->buffer[newOffset]; @@ -84,7 +84,7 @@ static shellmatta_retCode_t findNextHunk(shellmatta_instance_t *inst) inst->optionParser.nextOffset = newOffset; inst->optionParser.len = newOffset - inst->optionParser.offset - exeptionOffset; - /*! -# add terminating 0 */ + /** -# add terminating 0 */ inst->buffer[inst->optionParser.offset + inst->optionParser.len] = '\0'; if((inst->optionParser.offset < inst->inputCount) && (0u != inst->optionParser.len) && ('\0' == quotation)) @@ -104,7 +104,7 @@ static char peekNextHunk(shellmatta_instance_t *inst) { uint32_t newOffset = inst->optionParser.nextOffset; - /*! -# find beginning of next hunk */ + /** -# find beginning of next hunk */ while( (newOffset < inst->inputCount) && ((' ' == inst->buffer[newOffset]) || ('\0' == inst->buffer[newOffset]))) @@ -132,22 +132,22 @@ static shellmatta_retCode_t parseShortOpt( shellmatta_instance_t *inst, char *buffer = &inst->buffer[inst->optionParser.offset]; uint32_t i; - /*! -# check for correct syntax */ + /** -# check for correct syntax */ if((2u == inst->optionParser.len) && ('-' == buffer[0u]) && ('-' != buffer[1u]) && ('\0' != buffer[1u])) { *option = '\0'; - /*! -# search for option character in option string */ + /** -# search for option character in option string */ for(i = 0u; ('\0' != optionString[i]) && ('\0' == *option); i ++) { if(buffer[1u] == optionString[i]) { ret = SHELLMATTA_OK; - /*! -# return found option character */ + /** -# return found option character */ *option = buffer[1u]; - /*! -# check if an argument is required or optional */ + /** -# check if an argument is required or optional */ if(':' == optionString[i + 1u]) { *argtype = SHELLMATTA_OPT_ARG_REQUIRED; @@ -163,7 +163,7 @@ static shellmatta_retCode_t parseShortOpt( shellmatta_instance_t *inst, } } } - /*! -# skip "--" */ + /** -# skip "--" */ else if((2u == inst->optionParser.len) && ('-' == buffer[0u]) && ('-' == buffer[1u])) { ret = SHELLMATTA_CONTINUE; @@ -194,39 +194,39 @@ static shellmatta_retCode_t parseLongOpt( shellmatta_instance_t *inst, char *buffer = &inst->buffer[inst->optionParser.offset]; uint32_t i; - /*! -# check for correct syntax for short options */ + /** -# check for correct syntax for short options */ if((2u == inst->optionParser.len) && ('-' == buffer[0u]) && ('-' != buffer[1u]) && ('\0' != buffer[1u])) { - /*! -# search for option character in option list */ + /** -# search for option character in option list */ for(i = 0u; ('\0' != longOptions[i].paramShort) && ('\0' == *option); i ++) { if(buffer[1u] == longOptions[i].paramShort) { ret = SHELLMATTA_OK; - /*! -# return found option character */ + /** -# return found option character */ *option = longOptions[i].paramShort; *argtype = longOptions[i].argtype; } } } - /*! -# check for correct syntax for long options */ + /** -# check for correct syntax for long options */ else if((3u <= inst->optionParser.len) && ('-' == buffer[0u]) && ('-' == buffer[1u])) { - /*! -# search for long option in option list */ + /** -# search for long option in option list */ for(i = 0u; ('\0' != longOptions[i].paramShort) && ('\0' == *option); i ++) { if(0 == strcmp(&buffer[2u], longOptions[i].paramLong)) { ret = SHELLMATTA_OK; - /*! -# return found option character */ + /** -# return found option character */ *option = longOptions[i].paramShort; *argtype = longOptions[i].argtype; } } } - /*! -# ignore "--" */ + /** -# ignore "--" */ else if((2u == inst->optionParser.len) && ('-' == buffer[0u]) && ('-' == buffer[1u])) { *option = '\0'; @@ -279,13 +279,13 @@ static shellmatta_retCode_t shellmatta_opt_int( shellmatta_handle_t handle, *argLen = 0u; } - /*! -# do this until we find a not skipable argument */ + /** -# do this until we find a not skipable argument */ do { ret = findNextHunk(inst); if(SHELLMATTA_OK == ret) { - /*! -# call the matching parse function */ + /** -# call the matching parse function */ if(NULL != optionString) { ret = parseShortOpt(inst, optionString, option, &argtype); @@ -299,7 +299,7 @@ static shellmatta_retCode_t shellmatta_opt_int( shellmatta_handle_t handle, ret = SHELLMATTA_USE_FAULT; } - /*! -# when no option is found return this as raw argument */ + /** -# when no option is found return this as raw argument */ if(SHELLMATTA_ERROR == ret) { if(NULL != argument) @@ -314,7 +314,7 @@ static shellmatta_retCode_t shellmatta_opt_int( shellmatta_handle_t handle, } else if(SHELLMATTA_USE_FAULT == ret) { - /*! -# nothing to do - just return errorcode */ + /** -# nothing to do - just return errorcode */ } else { @@ -333,7 +333,7 @@ static shellmatta_retCode_t shellmatta_opt_int( shellmatta_handle_t handle, } break; case SHELLMATTA_OPT_ARG_OPTIONAL: - /*! -# treat anything not starting with '-' as argument */ + /** -# treat anything not starting with '-' as argument */ if('-' != peekNextHunk(inst)) { ret = findNextHunk(inst); @@ -412,7 +412,7 @@ shellmatta_retCode_t shellmatta_opt_long( shellmatta_handle_t handle, */ shellmatta_retCode_t shellmatta_opt_init(shellmatta_instance_t *inst, uint32_t argStart) { - /*! -# initialize all relevant option parser variables */ + /** -# initialize all relevant option parser variables */ inst->optionParser.nextOffset = argStart; return SHELLMATTA_OK; diff --git a/src/shellmatta_utils.c b/src/shellmatta_utils.c index 7124272..78416db 100644 --- a/src/shellmatta_utils.c +++ b/src/shellmatta_utils.c @@ -366,6 +366,7 @@ void utils_terminateInput(shellmatta_instance_t *inst) inst->cursor = 0u; inst->stdinIdx = 0u; inst->stdinLength = 0u; + inst->continuousCmd = NULL; inst->write("\r\n", 2u); inst->write(inst->prompt, strlen(inst->prompt)); } diff --git a/src/shellmatta_utils.h b/src/shellmatta_utils.h index fa368c6..ffa2351 100644 --- a/src/shellmatta_utils.h +++ b/src/shellmatta_utils.h @@ -40,12 +40,12 @@ extern const shellmatta_cmd_t helpCmd; #define SHELLMATTA_MAGIC 0x5101E110u -/*! \brief overwritable output buffer size */ +/** \brief overwritable output buffer size */ #ifndef SHELLMATTA_OUTPUT_BUFFER_SIZE #define SHELLMATTA_OUTPUT_BUFFER_SIZE 128u #endif -/*! @defgroup Shellmatta Help command overwrites +/** @defgroup Shellmatta Help command overwrites * @{ * overwritable help command parameters - the help command is built in and cannot be removed, but you can change * the command, alias and help texts by defining them in your build process @@ -57,18 +57,18 @@ extern const shellmatta_cmd_t helpCmd; * e.g. use _-DSHELLMATTA_HELP_ALIAS=\"?\"_ as compile option to change the alias to ? */ #ifndef SHELLMATTA_HELP_COMMAND -#define SHELLMATTA_HELP_COMMAND (char*)"help" /*!< help command */ +#define SHELLMATTA_HELP_COMMAND (char*)"help" /**< help command */ #endif #ifndef SHELLMATTA_HELP_ALIAS -#define SHELLMATTA_HELP_ALIAS (char*)"h" /*!< help command alias */ +#define SHELLMATTA_HELP_ALIAS (char*)"h" /**< help command alias */ #endif #ifndef SHELLMATTA_HELP_HELP_TEXT -#define SHELLMATTA_HELP_HELP_TEXT (char*)"Print this help text" /*!< help command help text */ +#define SHELLMATTA_HELP_HELP_TEXT (char*)"Print this help text" /**< help command help text */ #endif #ifndef SHELLMATTA_HELP_USAGE_TEXT -#define SHELLMATTA_HELP_USAGE_TEXT (char*)"help" /*!< help command usage text */ +#define SHELLMATTA_HELP_USAGE_TEXT (char*)"help" /**< help command usage text */ #endif -/*! +/** * @} */