added busy mode and test

a command can now return SHELLMATTA_BUSY
This will be passed back to the caller of processData
afterwards the instance has to be called with the same parameters
The shellmatta will then just call the busy command until it finishes
as soon as the command returns != SHELLMATTA_BUSY the instance will continue processing the rest of the input data
This commit is contained in:
prozessorkern 2020-03-28 11:26:50 +01:00
parent 3b99ad2a56
commit d7962a54dc
5 changed files with 218 additions and 30 deletions

View File

@ -39,7 +39,8 @@ typedef enum
SHELLMATTA_ERROR , /**< error occured */
SHELLMATTA_CONTINUE , /**< the function is not over */
SHELLMATTA_USE_FAULT , /**< parameter error - wrong usage */
SHELLMATTA_DUPLICATE /**< duplicate command */
SHELLMATTA_DUPLICATE , /**< duplicate command */
SHELLMATTA_BUSY /**< command is busy keep calling */
} shellmatta_retCode_t;
/**
@ -121,6 +122,7 @@ typedef struct
char *buffer; /**< input buffer */
uint32_t bufferSize; /**< size of the input buffer */
uint32_t inputCount; /**< offset of the current write operation */
uint32_t byteCounter; /**< counter used to loop over input data */
uint32_t lastNewlineIdx; /**< index of the lest newline */
uint32_t cursor; /**< offset where the cursor is at */
uint32_t stdinIdx; /**< start index of stdin in buffer */
@ -146,6 +148,7 @@ typedef struct
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 */
shellmatta_cmd_t *busyCmd; /**< command to be polled (busy mode) */
bool cmdListIsConst; /**< true if the #cmdList was passed during
initialization */
shellmatta_opt_t optionParser; /**< option parser sructure */

View File

@ -41,7 +41,8 @@ UNITTEST_SOURCES := test/unittest/test_main.cpp
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_optLong.cpp \
test/integrationtest/test_integration_busy.cpp
UNITTEST_CPPOBJ := $(patsubst %.cpp,$(OBJ_DIR)%.o,$(UNITTEST_SOURCES))

View File

@ -75,6 +75,7 @@ shellmatta_retCode_t shellmatta_doInit(
inst->buffer = buffer;
inst->bufferSize = bufferSize;
inst->inputCount = 0u;
inst->byteCounter = 0u;
inst->lastNewlineIdx = 0u;
inst->cursor = 0u;
inst->stdinIdx = 0u;
@ -98,6 +99,7 @@ shellmatta_retCode_t shellmatta_doInit(
inst->mode = SHELLMATTA_MODE_INSERT;
inst->cmdList = &(inst->helpCmd);
inst->continuousCmd = NULL;
inst->busyCmd = NULL;
inst->cmdListIsConst = false;
/** -# copy the help command structure to this instance */
@ -139,7 +141,9 @@ shellmatta_retCode_t shellmatta_resetShell( shellmatta_handle_t handle, bool pri
&& (SHELLMATTA_MAGIC == inst->magic))
{
inst->inputCount = 0u;
inst->byteCounter = 0u;
inst->continuousCmd = NULL;
inst->busyCmd = NULL;
inst->lastNewlineIdx = 0u;
inst->cursor = 0u;
inst->stdinIdx = 0u;
@ -368,7 +372,6 @@ shellmatta_retCode_t shellmatta_processData(shellmatta_handle_t handle,
uint8_t cmdExecuted = 0u;
uint32_t cmdLen;
char *tempString;
uint32_t byteCounter;
shellmatta_retCode_t ret = SHELLMATTA_OK;
shellmatta_retCode_t cmdRet;
@ -378,19 +381,53 @@ shellmatta_retCode_t shellmatta_processData(shellmatta_handle_t handle,
if( (NULL != inst)
&& (SHELLMATTA_MAGIC == inst->magic))
{
/** -# in busy mode - keep calling this command */
if(NULL != inst->busyCmd)
{
/** -# just call the function until it is not busy anymore */
cmdRet = inst->busyCmd->cmdFct(handle, inst->buffer, inst->inputCount);
if(SHELLMATTA_BUSY != cmdRet)
{
utils_terminateInput(inst);
}
else if(SHELLMATTA_CONTINUE == cmdRet)
{
inst->continuousCmd = inst->busyCmd;
inst->busyCmd = NULL;
}
else
{
ret = cmdRet;
}
}
/** -# process byte wise */
for (byteCounter = 0u; byteCounter < size; byteCounter++)
for (; (inst->byteCounter < size) && (NULL == inst->busyCmd); inst->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->buffer[inst->stdinIdx] = data[inst->byteCounter];
inst->stdinLength = 1u;
cmdRet = inst->continuousCmd->cmdFct(inst, inst->buffer, inst->inputCount);
cmdRet = inst->continuousCmd->cmdFct(handle, inst->buffer, inst->inputCount);
/** -# check if continuous mode is canceled */
if(('\x03' == data[byteCounter]) || (SHELLMATTA_CONTINUE != cmdRet))
/** -# check if continuous mode is canceled or interrupted by busy mode */
if(SHELLMATTA_BUSY == cmdRet)
{
inst->busyCmd = inst->busyCmd;
inst->continuousCmd = NULL;
}
else if(('\x03' == data[inst->byteCounter]))
{
utils_terminateInput(inst);
}
else if(SHELLMATTA_CONTINUE == cmdRet)
{
/** -# do nothing - continue */
}
else
{
utils_terminateInput(inst);
}
@ -398,10 +435,10 @@ shellmatta_retCode_t shellmatta_processData(shellmatta_handle_t handle,
/** -# handle escape sequences */
else if(inst->escapeCounter != 0u)
{
escape_handleSequence(inst, *data);
escape_handleSequence(inst, data[inst->byteCounter]);
}
/** -# handle delimiter as start of processing the command */
else if (inst->delimiter == *data)
else if (inst->delimiter == data[inst->byteCounter])
{
if(0u == inst->hereLength)
{
@ -434,7 +471,7 @@ shellmatta_retCode_t shellmatta_processData(shellmatta_handle_t handle,
inst->hereLength = inst->inputCount - inst->hereDelimiterIdx;
inst->dirty = true;
utils_insertChars(inst, data, 1);
utils_insertChars(inst, &data[inst->byteCounter], 1u);
inst->lastNewlineIdx = inst->inputCount;
}
else
@ -505,9 +542,9 @@ 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 - just print the delimiter and store the position */
inst->lastNewlineIdx = inst->inputCount;
utils_insertChars(inst, data, 1u);
utils_insertChars(inst, &data[inst->byteCounter], 1u);
}
}
@ -543,14 +580,25 @@ shellmatta_retCode_t shellmatta_processData(shellmatta_handle_t handle,
utils_writeEcho(inst, "\r\n", 2u);
shellmatta_opt_init(inst, cmdLen + 1u);
cmdExecuted = 1u;
cmdRet = cmd->cmdFct(inst, inst->buffer, inst->inputCount);
if(SHELLMATTA_CONTINUE == cmdRet)
{
inst->continuousCmd = cmd;
cmdRet = cmd->cmdFct(handle, inst->buffer, inst->inputCount);
/** -# initialize stdin buffer */
inst->stdinIdx = inst->inputCount + 1u;
inst->stdinLength = 0u;
switch(cmdRet)
{
case SHELLMATTA_CONTINUE:
/** -# initialize stdin buffer and continuous cmd */
inst->stdinIdx = inst->inputCount + 1u;
inst->stdinLength = 0u;
inst->continuousCmd = cmd;
break;
case SHELLMATTA_BUSY:
inst->busyCmd = cmd;
ret = cmdRet;
break;
default:
/* nothing to do - everything ok */
break;
}
cmd = NULL;
}
@ -568,7 +616,8 @@ shellmatta_retCode_t shellmatta_processData(shellmatta_handle_t handle,
}
/** -# terminate this session if no continuous mode is requested */
if(NULL == inst->continuousCmd)
if( (NULL == inst->continuousCmd)
&& (NULL == inst->busyCmd))
{
utils_terminateInput(inst);
}
@ -576,49 +625,53 @@ shellmatta_retCode_t shellmatta_processData(shellmatta_handle_t handle,
}
/** -# ignore newline as first character (to be compatible to
* terminals sending newline after return */
else if((0u == inst->inputCount) && ('\n' == *data))
else if((0u == inst->inputCount) && ('\n' == data[inst->byteCounter]))
{
/* do nothing */
}
/** -# check for tabulator key - auto complete */
else if('\t' == *data)
else if('\t' == data[inst->byteCounter])
{
inst->dirty = true;
autocomplete_run(inst);
}
/** -# check for cancel -
* terminate current input and print prompt again */
else if('\x03' == *data)
else if('\x03' == data[inst->byteCounter])
{
inst->dirty = false;
history_reset(inst);
utils_terminateInput(inst);
}
/** -# check for backspace */
else if( ('\b' == *data)
|| ('\x7f' == *data))
else if( ('\b' == data[inst->byteCounter])
|| ('\x7f' == data[inst->byteCounter]))
{
inst->dirty = true;
utils_removeChars(inst, 1u, true);
}
/** -# check for start of escape sequence */
else if('\x1b' == *data)
else if('\x1b' == data[inst->byteCounter])
{
inst->escapeCounter = 1u;
}
else
{
inst->dirty = true;
utils_insertChars(inst, data, 1);
utils_insertChars(inst, &data[inst->byteCounter], 1u);
}
/** -# reset tab counter on not a tab */
if ('\t' != *data)
if ('\t' != data[inst->byteCounter])
{
inst->tabCounter = 0u;
}
}
data ++;
/*! -# initialize the byte buffer if processing of the input is finished */
if(ret != SHELLMATTA_BUSY)
{
inst->byteCounter = 0u;
}
}
else

View File

@ -367,6 +367,7 @@ void utils_terminateInput(shellmatta_instance_t *inst)
inst->stdinIdx = 0u;
inst->stdinLength = 0u;
inst->continuousCmd = NULL;
inst->busyCmd = NULL;
inst->write("\r\n", 2u);
inst->write(inst->prompt, strlen(inst->prompt));
}

View File

@ -0,0 +1,130 @@
/*
* Copyright (c) 2019 Stefan Strobel <stefan.strobel@shimatta.net>
*
* 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 <stefan.strobel@shimatta.net>
*/
#include "test/framework/catch.hpp"
extern "C" {
#include "shellmatta.h"
}
#include <string.h>
static uint32_t write_callCnt = 0u;
static char write_data[1024];
static uint32_t write_length;
static uint32_t busyCallCnt;
static uint32_t notBusyCallCnt;
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 busyCmdFct(shellmatta_handle_t handle, const char *arguments, uint32_t length)
{
(void) handle;
(void) arguments;
(void) length;
shellmatta_retCode_t ret = SHELLMATTA_BUSY;
static const char *callArgs = NULL;
static uint32_t callLength = 0u;;
if(busyCallCnt < 10u)
{
if(NULL == callArgs)
{
callArgs = arguments;
callLength = length;
}
else
{
CHECK(callArgs == arguments);
CHECK(callLength == length);
}
busyCallCnt ++;
}
else
{
ret = SHELLMATTA_OK;
}
return ret;
}
shellmatta_cmd_t busyCmd = {(char*)"busy", (char*)"b", NULL, NULL, busyCmdFct, NULL};
static shellmatta_retCode_t notBusyCmdFct(shellmatta_handle_t handle, const char *arguments, uint32_t length)
{
(void) handle;
(void) arguments;
(void) length;
notBusyCallCnt ++;
return SHELLMATTA_OK;
}
shellmatta_cmd_t notBusyCmd = {(char*)"notBusy", (char*)"n", NULL, NULL, notBusyCmdFct, NULL};
TEST_CASE( "shellmatta busy 1" ) {
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"
"\r\nshellmatta->notBusy and some arguments\r\n"
"\r\nshellmatta->";
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;
shellmatta_addCmd(handle, &busyCmd);
shellmatta_addCmd(handle, &notBusyCmd);
do
{
ret = shellmatta_processData(handle, (char*)"busy and some arguments\r"
"notBusy and some arguments\r", 51);
} while (SHELLMATTA_BUSY == ret);
CHECK( 10u == busyCallCnt);
CHECK( 1u == notBusyCallCnt );
CHECK( write_length == strlen(dummyData));
REQUIRE( strcmp(dummyData, write_data) == 0);
}