diff --git a/api/shellmatta.h b/api/shellmatta.h index 11c0e52..5a2fa42 100644 --- a/api/shellmatta.h +++ b/api/shellmatta.h @@ -77,6 +77,7 @@ typedef struct */ typedef struct { + uint32_t argStart; /**< start of the arguments of the command */ uint32_t offset; /**< current offset of the option parser */ uint32_t nextOffset; /**< offset of the next hunk */ uint32_t len; /**< length of the current hunk */ diff --git a/makefile b/makefile index b3f2998..8a66d79 100644 --- a/makefile +++ b/makefile @@ -42,6 +42,7 @@ INTEGRATIONTEST_SOURCES := test/integrationtest/test_main.cpp test/integrationtest/test_integration.cpp \ test/integrationtest/test_integration_opt.cpp \ test/integrationtest/test_integration_optLong.cpp \ + test/integrationtest/test_integration_continue.cpp \ test/integrationtest/test_integration_busy.cpp UNITTEST_CPPOBJ := $(patsubst %.cpp,$(OBJ_DIR)%.o,$(UNITTEST_SOURCES)) diff --git a/src/shellmatta.c b/src/shellmatta.c index 7ad8ea6..c20a220 100644 --- a/src/shellmatta.c +++ b/src/shellmatta.c @@ -101,6 +101,7 @@ shellmatta_retCode_t shellmatta_doInit( inst->continuousCmd = NULL; inst->busyCmd = NULL; inst->cmdListIsConst = false; + shellmatta_opt_init(inst, 0u); /** -# copy the help command structure to this instance */ memcpy(&(inst->helpCmd), &helpCmd, sizeof(shellmatta_cmd_t)); @@ -158,6 +159,7 @@ shellmatta_retCode_t shellmatta_resetShell( shellmatta_handle_t handle, bool pri inst->hereStartIdx = 0u; inst->hereDelimiterIdx = 0u; inst->hereLength = 0u; + shellmatta_opt_init(inst, 0u); if(true == printPrompt) { @@ -385,20 +387,44 @@ shellmatta_retCode_t shellmatta_processData(shellmatta_handle_t handle, if(NULL != inst->busyCmd) { /** -# just call the function until it is not busy anymore */ - cmdRet = inst->busyCmd->cmdFct(handle, inst->buffer, inst->inputCount); + (void)shellmatta_opt_reInit(inst); + ret = inst->busyCmd->cmdFct(handle, inst->buffer, inst->inputCount); - if(SHELLMATTA_BUSY != cmdRet) + if(SHELLMATTA_BUSY == ret) { - utils_terminateInput(inst); + /** -# do nothing - still busy */ } - else if(SHELLMATTA_CONTINUE == cmdRet) + else if(SHELLMATTA_CONTINUE == ret) { inst->continuousCmd = inst->busyCmd; inst->busyCmd = NULL; } else { - ret = cmdRet; + utils_terminateInput(inst); + } + } + /** -# call continuous function even if there is no data */ + else if((0u == size) && (NULL != inst->continuousCmd)) + { + /** -# just call the function without any new data */ + inst->stdinLength = 0u; + inst->buffer[inst->stdinIdx] = '\0'; + (void)shellmatta_opt_reInit(inst); + ret = inst->continuousCmd->cmdFct(handle, inst->buffer, inst->inputCount); + + if(SHELLMATTA_CONTINUE == ret) + { + /** -# do nothing just continue */ + } + else if(SHELLMATTA_BUSY == ret) + { + inst->busyCmd = inst->continuousCmd; + inst->continuousCmd = NULL; + } + else + { + utils_terminateInput(inst); } } @@ -409,21 +435,25 @@ shellmatta_retCode_t shellmatta_processData(shellmatta_handle_t handle, if(NULL != inst->continuousCmd) { /** -# copy data and call command function */ - inst->buffer[inst->stdinIdx] = data[inst->byteCounter]; - inst->stdinLength = 1u; - cmdRet = inst->continuousCmd->cmdFct(handle, inst->buffer, inst->inputCount); + inst->buffer[inst->stdinIdx] = data[inst->byteCounter]; + inst->buffer[inst->stdinIdx + 1u] = '\0'; + inst->stdinLength = 1u; + (void)shellmatta_opt_reInit(inst); + ret = inst->continuousCmd->cmdFct(handle, inst->buffer, inst->inputCount); /** -# check if continuous mode is canceled or interrupted by busy mode */ - if(SHELLMATTA_BUSY == cmdRet) + if(SHELLMATTA_BUSY == ret) { inst->busyCmd = inst->continuousCmd; inst->continuousCmd = NULL; } else if(('\x03' == data[inst->byteCounter])) { + /** -# cancel continue session */ utils_terminateInput(inst); + ret = SHELLMATTA_OK; } - else if(SHELLMATTA_CONTINUE == cmdRet) + else if(SHELLMATTA_CONTINUE == ret) { /** -# do nothing - continue */ } @@ -589,6 +619,7 @@ shellmatta_retCode_t shellmatta_processData(shellmatta_handle_t handle, inst->stdinIdx = inst->inputCount + 1u; inst->stdinLength = 0u; inst->continuousCmd = cmd; + ret = cmdRet; break; case SHELLMATTA_BUSY: @@ -668,7 +699,7 @@ shellmatta_retCode_t shellmatta_processData(shellmatta_handle_t handle, } } - /*! -# initialize the byte buffer if processing of the input is finished */ + /** -# initialize the byte buffer if processing of the input is finished */ if(ret != SHELLMATTA_BUSY) { inst->byteCounter = 0u; diff --git a/src/shellmatta_opt.c b/src/shellmatta_opt.c index 19a7a90..37caee0 100644 --- a/src/shellmatta_opt.c +++ b/src/shellmatta_opt.c @@ -410,12 +410,21 @@ shellmatta_retCode_t shellmatta_opt_long( shellmatta_handle_t handle, * @param[in, out] inst pointer to a shellmatta instance * @param[in] argStart start offset of the arguments (after command name/alias) */ -shellmatta_retCode_t shellmatta_opt_init(shellmatta_instance_t *inst, uint32_t argStart) +void shellmatta_opt_init(shellmatta_instance_t *inst, uint32_t argStart) { /** -# initialize all relevant option parser variables */ - inst->optionParser.nextOffset = argStart; + inst->optionParser.argStart = argStart; + inst->optionParser.nextOffset = argStart; +} - return SHELLMATTA_OK; +/** + * @brief re-initializes the option parser instance using the data from the last init + * @param[in, out] inst pointer to a shellmatta instance + */ +void shellmatta_opt_reInit(shellmatta_instance_t *inst) +{ + /** -# initialize all relevant option parser variables */ + inst->optionParser.nextOffset = inst->optionParser.argStart; } /** diff --git a/src/shellmatta_opt.h b/src/shellmatta_opt.h index 852f05b..2f6a14d 100644 --- a/src/shellmatta_opt.h +++ b/src/shellmatta_opt.h @@ -34,9 +34,11 @@ shellmatta_retCode_t shellmatta_opt_long( shellmatta_handle_t handle, char **argument, uint32_t *argLen); -shellmatta_retCode_t shellmatta_opt_init( shellmatta_instance_t *inst, +void shellmatta_opt_init( shellmatta_instance_t *inst, uint32_t argStart); +void shellmatta_opt_reInit( shellmatta_instance_t *inst); + #endif /** @} */ diff --git a/test/integrationtest/test_integration_busy.cpp b/test/integrationtest/test_integration_busy.cpp index 8637d76..92c7952 100644 --- a/test/integrationtest/test_integration_busy.cpp +++ b/test/integrationtest/test_integration_busy.cpp @@ -23,6 +23,7 @@ static char write_data[1024]; static uint32_t write_length; static uint32_t busyCallCnt; static uint32_t notBusyCallCnt; +static bool suspendBusy; static shellmatta_retCode_t writeFct(const char* data, uint32_t length) { @@ -67,6 +68,11 @@ static shellmatta_retCode_t busyCmdFct(shellmatta_handle_t handle, const char *a ret = SHELLMATTA_OK; } + if(true == suspendBusy) + { + ret = SHELLMATTA_CONTINUE; + } + return ret; } shellmatta_cmd_t busyCmd = {(char*)"busy", (char*)"b", NULL, NULL, busyCmdFct, NULL}; @@ -111,6 +117,7 @@ TEST_CASE( "shellmatta busy 1" ) { write_callCnt = 0u; memset(write_data, 0, sizeof(write_data)); write_length = 0u; + suspendBusy = false; shellmatta_addCmd(handle, &busyCmd); shellmatta_addCmd(handle, ¬BusyCmd); @@ -128,3 +135,49 @@ TEST_CASE( "shellmatta busy 1" ) { CHECK( write_length == strlen(dummyData)); REQUIRE( strcmp(dummyData, write_data) == 0); } + +TEST_CASE( "shellmatta busy suspend with continuous mode" ) { + + shellmatta_retCode_t ret; + shellmatta_instance_t inst; + shellmatta_handle_t handle; + char buffer[1024]; + char historyBuffer[1024]; + char *dummyData = (char*) "busy and some arguments\r\n"; + + shellmatta_doInit( &inst, + &handle, + buffer, + sizeof(buffer), + historyBuffer, + sizeof(historyBuffer), + "shellmatta->", + NULL, + writeFct); + + busyCallCnt = 0u; + notBusyCallCnt = 0u; + write_callCnt = 0u; + memset(write_data, 0, sizeof(write_data)); + write_length = 0u; + suspendBusy = false; + + shellmatta_addCmd(handle, &busyCmd); + shellmatta_addCmd(handle, ¬BusyCmd); + + do + { + ret = shellmatta_processData(handle, (char*)"busy and some arguments\r123", 27u); + + suspendBusy = true; + + } while (SHELLMATTA_BUSY == ret); + + ret = shellmatta_processData(handle, (char*)"", 0u); + + CHECK( SHELLMATTA_CONTINUE == ret); + CHECK( 6u == busyCallCnt); + CHECK( 0u == notBusyCallCnt ); + CHECK( write_length == strlen(dummyData)); + REQUIRE( strcmp(dummyData, write_data) == 0); +} diff --git a/test/integrationtest/test_integration_continue.cpp b/test/integrationtest/test_integration_continue.cpp new file mode 100644 index 0000000..43b77c6 --- /dev/null +++ b/test/integrationtest/test_integration_continue.cpp @@ -0,0 +1,284 @@ +/* + * Copyright (c) 2019 Stefan Strobel + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +/** + * @file test_integration_busy.cpp + * @brief integration test implementation for the cmd busy function + * @author Stefan Strobel + */ + +#include "test/framework/catch.hpp" +extern "C" { +#include "shellmatta.h" +} +#include + +static uint32_t write_callCnt = 0u; +static char write_data[1024]; +static uint32_t write_length; +static uint32_t contCallCnt; +static uint32_t busyCallCnt; + +static shellmatta_retCode_t writeFct(const char* data, uint32_t length) +{ + write_callCnt ++; + while((length > 0) && (write_length < sizeof(write_data))) + { + write_data[write_length] = *data; + data ++; + length --; + write_length ++; + } + + return SHELLMATTA_OK; +} + +static shellmatta_retCode_t continueCmdFct(shellmatta_handle_t handle, const char *arguments, uint32_t length) +{ + (void) handle; + (void) arguments; + (void) length; + shellmatta_retCode_t ret = SHELLMATTA_CONTINUE; + char *stdinData; + uint32_t stdinLength = 0u; + + shellmatta_read(handle, &stdinData, &stdinLength); + if(NULL == stdinData) + { + stdinData = (char *)""; + } + + shellmatta_printf(handle, "arguments: %s length: %u\r\n", stdinData, stdinLength); + + /** change to busy mode when k is pressed */ + if('k' == stdinData[0]) + { + ret = SHELLMATTA_BUSY; + busyCallCnt ++; + } + + if(busyCallCnt > 1u) + { + ret = SHELLMATTA_CONTINUE; + } + + if(contCallCnt >= 9u) + { + ret = SHELLMATTA_OK; + } + + /* -# the arguments shall stay the same on every call - data is transferred per stdin */ + CHECK(length == 28u); + CHECK(strcmp(arguments, "continue some arguments meow") == 0); + + contCallCnt ++; + + return ret; +} +shellmatta_cmd_t continueCmd = {(char*)"continue", (char*)"c", NULL, NULL, continueCmdFct, NULL}; + + +TEST_CASE( "shellmatta continue 1" ) { + + shellmatta_retCode_t ret; + shellmatta_instance_t inst; + shellmatta_handle_t handle; + char buffer[1024]; + char historyBuffer[1024]; + char *dummyData = (char*) "continue some arguments meow\r\n" + "arguments: length: 0\r\n" + "arguments: length: 0\r\n" + "arguments: a length: 1\r\n" + "arguments: b length: 1\r\n" + "arguments: c length: 1\r\n" + "arguments: 8 length: 1\r\n" + "arguments: 7 length: 1\r\n" + "arguments: 6 length: 1\r\n" + "arguments: 5 length: 1\r\n" + "arguments: length: 0\r\n" + "\r\n" + "shellmatta->\r\n" + "shellmatta->"; + + shellmatta_doInit( &inst, + &handle, + buffer, + sizeof(buffer), + historyBuffer, + sizeof(historyBuffer), + "shellmatta->", + NULL, + writeFct); + + contCallCnt = 0u; + busyCallCnt = 0u; + write_callCnt = 0u; + memset(write_data, 0, sizeof(write_data)); + write_length = 0u; + + shellmatta_addCmd(handle, &continueCmd); + + ret = shellmatta_processData(handle, (char*)"continue some arguments meow\r", 29); + CHECK(SHELLMATTA_CONTINUE == ret); + + /** -# call without any argument */ + ret = shellmatta_processData(handle, NULL, 0); + CHECK(SHELLMATTA_CONTINUE == ret); + + /** -# pass some argument */ + ret = shellmatta_processData(handle, (char*)"abc", 3); + CHECK(SHELLMATTA_CONTINUE == ret); + + ret = shellmatta_processData(handle, (char*)"8765", 4); + CHECK(SHELLMATTA_CONTINUE == ret); + + /** -# call without any argument */ + ret = shellmatta_processData(handle, NULL, 0); + CHECK(SHELLMATTA_OK == ret); + + /** -# continue session should be over */ + ret = shellmatta_processData(handle, (char*)"\r", 1); + CHECK(SHELLMATTA_OK == ret); + + CHECK( 0u == busyCallCnt); + CHECK( 10u == contCallCnt); + CHECK( write_length == strlen(dummyData)); + REQUIRE( strcmp(dummyData, write_data) == 0); +} + +TEST_CASE( "shellmatta continue cancel" ) { + + shellmatta_retCode_t ret; + shellmatta_instance_t inst; + shellmatta_handle_t handle; + char buffer[1024]; + char historyBuffer[1024]; + char *dummyData = (char*) "continue some arguments meow\r\n" + "arguments: length: 0\r\n" + "arguments: length: 0\r\n" + "arguments: a length: 1\r\n" + "arguments: b length: 1\r\n" + "arguments: \x03 length: 1\r\n" + "\r\n" + "shellmatta->\r\n" + "shellmatta->"; + + shellmatta_doInit( &inst, + &handle, + buffer, + sizeof(buffer), + historyBuffer, + sizeof(historyBuffer), + "shellmatta->", + NULL, + writeFct); + + contCallCnt = 0u; + busyCallCnt = 0u; + write_callCnt = 0u; + memset(write_data, 0, sizeof(write_data)); + write_length = 0u; + + shellmatta_addCmd(handle, &continueCmd); + + ret = shellmatta_processData(handle, (char*)"continue some arguments meow\r", 29); + CHECK(SHELLMATTA_CONTINUE == ret); + + /** -# call without any argument */ + ret = shellmatta_processData(handle, NULL, 0); + CHECK(SHELLMATTA_CONTINUE == ret); + + /** -# pass some argument */ + ret = shellmatta_processData(handle, (char*)"ab", 2); + CHECK(SHELLMATTA_CONTINUE == ret); + + ret = shellmatta_processData(handle, (char*)"\x03", 1); + CHECK(SHELLMATTA_OK == ret); + + /** -# continue session should be over */ + ret = shellmatta_processData(handle, (char*)"\r", 1); + CHECK(SHELLMATTA_OK == ret); + + CHECK( 0u == busyCallCnt); + CHECK( 5u == contCallCnt); + CHECK( write_length == strlen(dummyData)); + REQUIRE( strcmp(dummyData, write_data) == 0); +} + +TEST_CASE( "shellmatta continue suspend with busy mode" ) { + + shellmatta_retCode_t ret; + shellmatta_instance_t inst; + shellmatta_handle_t handle; + char buffer[1024]; + char historyBuffer[1024]; + char *dummyData = (char*) "continue some arguments meow\r\n" + "arguments: length: 0\r\n" + "arguments: length: 0\r\n" + "arguments: a length: 1\r\n" + "arguments: b length: 1\r\n" + "arguments: k length: 1\r\n" + "arguments: k length: 1\r\n" + "arguments: length: 0\r\n" + "arguments: a length: 1\r\n" + "arguments: b length: 1\r\n" + "arguments: c length: 1\r\n" + "\r\n" + "shellmatta->\r\n" + "shellmatta->"; + + shellmatta_doInit( &inst, + &handle, + buffer, + sizeof(buffer), + historyBuffer, + sizeof(historyBuffer), + "shellmatta->", + NULL, + writeFct); + + contCallCnt = 0u; + busyCallCnt = 0u; + write_callCnt = 0u; + memset(write_data, 0, sizeof(write_data)); + write_length = 0u; + + shellmatta_addCmd(handle, &continueCmd); + + ret = shellmatta_processData(handle, (char*)"continue some arguments meow\r", 29); + CHECK(SHELLMATTA_CONTINUE == ret); + + /** -# call without any argument */ + ret = shellmatta_processData(handle, NULL, 0); + CHECK(SHELLMATTA_CONTINUE == ret); + + /** -# pass some argument */ + ret = shellmatta_processData(handle, (char*)"ab", 2); + CHECK(SHELLMATTA_CONTINUE == ret); + + ret = shellmatta_processData(handle, (char*)"k", 1); + CHECK(SHELLMATTA_BUSY == ret); + + ret = shellmatta_processData(handle, (char*)"k", 1); + CHECK(SHELLMATTA_CONTINUE == ret); + + ret = shellmatta_processData(handle, (char*)"", 0); + CHECK(SHELLMATTA_CONTINUE == ret); + + ret = shellmatta_processData(handle, (char*)"abc", 3); + CHECK(SHELLMATTA_OK == ret); + + /** -# continue session should be over */ + ret = shellmatta_processData(handle, (char*)"\r", 1); + CHECK(SHELLMATTA_OK == ret); + + CHECK( 10u == contCallCnt); + CHECK( 2u == busyCallCnt); + CHECK( write_length == strlen(dummyData)); + REQUIRE( strcmp(dummyData, write_data) == 0); +}