Compare commits

..

3 Commits

9 changed files with 431 additions and 46 deletions

21
.vscode/launch.json vendored
View File

@ -4,6 +4,27 @@
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "debug example",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/output/example/example",
"args": ["/dev/pts/3"],
"stopAtEntry": false,
"cwd": "${workspaceFolder}",
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
],
"preLaunchTask": "make example",
"miDebuggerPath": "/usr/bin/gdb"
},
{
"name": "debug unittest",
"type": "cppdbg",

View File

@ -126,12 +126,19 @@ shellmatta_retCode_t shellmatta_doInit( shellmatta_instance_t *inst,
const shellmatta_cmd_t *cmdList,
shellmatta_write_t writeFct);
shellmatta_retCode_t shellmatta_resetShell( shellmatta_handle_t handle,
bool printPrompt);
shellmatta_retCode_t shellmatta_addCmd( shellmatta_handle_t handle,
shellmatta_cmd_t *cmd);
shellmatta_retCode_t shellmatta_removeCmd( shellmatta_handle_t handle,
shellmatta_cmd_t *cmd);
shellmatta_retCode_t shellmatta_configure( shellmatta_handle_t handle,
shellmatta_mode_t mode,
bool echoEnabled);
shellmatta_retCode_t shellmatta_processData(shellmatta_handle_t handle,
char *data,
uint32_t size);

View File

@ -52,6 +52,8 @@ static shellmatta_retCode_t doSome(shellmatta_handle_t handle, const char *argum
shellmatta_write(handle, "blubb\r\n", 7u);
shellmatta_configure(handle, SHELLMATTA_MODE_INSERT, false);
(void)arguments;
(void)length;
@ -91,11 +93,32 @@ static shellmatta_retCode_t empty(shellmatta_handle_t handle, const char *argume
(void)length;
shellmatta_printf(handle, "empty function called\r\n");
shellmatta_configure(handle, SHELLMATTA_MODE_OVERWRITE, true);
return SHELLMATTA_OK;
}
shellmatta_cmd_t emptyCommand = {"empty", NULL, NULL, NULL, empty, NULL};
static shellmatta_retCode_t reset(shellmatta_handle_t handle, const char *arguments, uint32_t length)
{
(void)arguments;
(void)length;
if(0 == strncmp(arguments, "prompt", length))
{
shellmatta_resetShell(handle, true);
}
else
{
shellmatta_resetShell(handle, false);
}
shellmatta_configure(handle, SHELLMATTA_MODE_INSERT, true);
return SHELLMATTA_OK;
}
shellmatta_cmd_t resetCommand = {"reset", NULL, "resets the shellmatta instance", "reset [prompt]", reset, NULL};
shellmatta_retCode_t writeFct(const char* data, uint32_t length)
{
@ -140,6 +163,7 @@ int main(int argc, char **argv)
shellmatta_addCmd(handle, &quitCommand);
shellmatta_addCmd(handle, &removeCommand);
shellmatta_addCmd(handle, &emptyCommand);
shellmatta_addCmd(handle, &resetCommand);
while(exitRequest == false)
{

View File

@ -111,6 +111,53 @@ shellmatta_retCode_t shellmatta_doInit(
return SHELLMATTA_OK;
}
/**
* @brief resets the whole shellmatta instance
* @param[in] handle shellmatta instance handle
* @param[in] printPrompt print a new command prompt
*
* This function can be used e.g. when working with connection based interfaces (e.g. sockets) to clear
* the shell from old content when a new connection is opened.
* It resets all internal states - the buffers are left as they are - they will be overwritten.
* The history buffer is deleted as well.
*/
shellmatta_retCode_t shellmatta_resetShell( shellmatta_handle_t handle, bool printPrompt)
{
shellmatta_instance_t *inst = (shellmatta_instance_t *)handle;
shellmatta_retCode_t ret = SHELLMATTA_OK;
/*! -# check if the instance is plausible */
if( (NULL != handle)
&& (SHELLMATTA_MAGIC == inst->magic))
{
inst->inputCount = 0u;
inst->lastNewlineIdx = 0u;
inst->cursor = 0u;
inst->historyStart = 0u;
inst->historyEnd = 0u;
inst->historyRead = 0u;
inst->historyReadUp = true;
inst->dirty = false;
inst->tabCounter = 0u;
inst->escapeCounter = 0u;
inst->hereStartIdx = 0u;
inst->hereDelimiterIdx = 0u;
inst->hereLength = 0u;
if(true == printPrompt)
{
/** -# print a prompt if requested */
utils_terminateInput(inst);
}
}
else
{
ret = SHELLMATTA_USE_FAULT;
}
return ret;
}
/**
* @brief adds a command to the command list alphabetically ordered
* @param[in] handle shellmatta instance handle
@ -153,7 +200,8 @@ shellmatta_retCode_t shellmatta_addCmd(shellmatta_handle_t handle, shellmatta_cm
while ((false == cmdPlaced) && (SHELLMATTA_OK == ret))
{
cmdDiff = strcmp(tempCmd->cmd, cmd->cmd);
if(NULL != cmd->cmdAlias)
if( (NULL != cmd->cmdAlias)
&& (NULL != tempCmd->cmdAlias))
{
aliasDiff = strcmp(tempCmd->cmdAlias, cmd->cmdAlias);
}
@ -259,6 +307,35 @@ shellmatta_retCode_t shellmatta_removeCmd(shellmatta_handle_t handle, shellmatta
return ret;
}
/**
* @brief changes configuration of a shellmatta instance
* @param[in] handle shellmatta instance handle
* @param[in] mode insert mode of the shellmatta type #shellmatta_mode_t
* @param[in] echoEnabled true: echo received chars to the output
* @return errorcode #SHELLMATTA_OK
* #SHELLMATTA_USE_FAULT (param err)
*/
shellmatta_retCode_t shellmatta_configure(shellmatta_handle_t handle, shellmatta_mode_t mode, bool echoEnabled)
{
shellmatta_instance_t *inst = (shellmatta_instance_t*)handle;
shellmatta_retCode_t ret = SHELLMATTA_OK;
/** -# check parameters for plausibility */
if( (NULL != inst)
&& (SHELLMATTA_MAGIC == inst->magic)
&& ((mode == SHELLMATTA_MODE_INSERT) || (mode == SHELLMATTA_MODE_OVERWRITE)))
{
inst->mode = mode;
inst->echoEnabled = echoEnabled;
}
else
{
ret = SHELLMATTA_USE_FAULT;
}
return ret;
}
/**
* @brief processes the passed amount of data
* @param[in] handle shellmatta instance handle
@ -275,8 +352,8 @@ shellmatta_retCode_t shellmatta_processData(shellmatta_handle_t handle,
uint8_t cmdExecuted = 0u;
uint32_t cmdLen;
char *tempString;
char *argumentString = NULL;
uint32_t argumentLength = 0u;
char *argumentString;
uint32_t argumentLength;
uint32_t byteCounter;
uint32_t idx;
@ -290,6 +367,10 @@ shellmatta_retCode_t shellmatta_processData(shellmatta_handle_t handle,
/** -# process byte wise */
for (byteCounter = 0u; byteCounter < size; byteCounter++)
{
/*! -# set default values for the command argument - can be overwritten by heredoc */
argumentString = inst->buffer;
argumentLength = inst->inputCount;
/** -# handle escape sequences */
if(inst->escapeCounter != 0u)
{
@ -315,7 +396,8 @@ shellmatta_retCode_t shellmatta_processData(shellmatta_handle_t handle,
* }
* \enddot */
/** -# check for heredoc */
/** -# check for heredoc - add string delimiter to stop strstr from searching too far */
inst->buffer[inst->inputCount] = '\0';
tempString = strstr(inst->buffer, "<<");
if(NULL != tempString)
{
@ -349,9 +431,6 @@ shellmatta_retCode_t shellmatta_processData(shellmatta_handle_t handle,
}
else
{
argumentString = inst->buffer;
argumentLength = inst->inputCount;
/** -# store the current command and reset the history buffer */
inst->dirty = true;
history_storeCmd(inst);
@ -396,8 +475,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 */
inst->lastNewlineIdx = inst->inputCount;
utils_insertChars(inst, data, 1);
utils_insertChars(inst, data, 1u);
}
}
@ -420,26 +500,18 @@ shellmatta_retCode_t shellmatta_processData(shellmatta_handle_t handle,
/** -# search for a matching command */
while (NULL != cmd)
{
/** -# compare command string and length */
if ((0 == strncmp( argumentString,
/** -# compare command and alias string and length */
if ( ((0 == strncmp( argumentString,
cmd->cmd,
cmdLen))
&& (cmdLen == strlen(cmd->cmd)))
{
inst->write("\r\n", 2u);
cmdExecuted = 1u;
cmd->cmdFct(inst, argumentString, argumentLength);
cmd = NULL;
}
/** -# compare command alias if any and length */
else if((NULL != cmd->cmdAlias)
|| ((NULL != cmd->cmdAlias)
&& ((0 == strncmp( argumentString,
cmd->cmdAlias,
cmdLen))
&& (cmdLen == strlen(cmd->cmdAlias))))
&& (cmdLen == strlen(cmd->cmdAlias)))))
{
inst->write("\r\n", 2u);
utils_writeEcho(inst, "\r\n", 2u);
cmdExecuted = 1u;
cmd->cmdFct(inst, argumentString, argumentLength);

View File

@ -25,7 +25,7 @@
#include <stdint.h>
/**
* @brief processes the excape character stream of the instance and chacks
* @brief processes the excape character stream of the instance and checks
* if an arrow key was pressed
* @param[in] inst pointer to a shellmatta instance
* @return #SHELLMATTA_OK if an arrow key was pressed
@ -47,7 +47,6 @@ shellmatta_retCode_t escape_processArrowKeys(shellmatta_instance_t *inst)
history_navigate(inst, -1);
}
inst->historyReadUp = true;
utils_clearInput(inst);
history_restoreCmd(inst);
history_navigate(inst, -1);
@ -63,7 +62,6 @@ shellmatta_retCode_t escape_processArrowKeys(shellmatta_instance_t *inst)
}
inst->historyReadUp = false;
history_navigate(inst, 1);
utils_clearInput(inst);
history_restoreCmd(inst);
}
break;

View File

@ -201,8 +201,16 @@ void history_restoreCmd(shellmatta_instance_t *inst)
{
char byte;
bool ret = true;
bool anythingToRestore = false;
ret = getHistoryByte(inst, &byte);
/*! -# delete the input if there is data in the history buffer */
if(true == ret)
{
utils_clearInput(inst);
anythingToRestore = true;
}
while((ret == true) && (byte != 0u))
{
inst->buffer[inst->inputCount] = byte;
@ -211,9 +219,12 @@ void history_restoreCmd(shellmatta_instance_t *inst)
ret = getHistoryByte(inst, &byte);
}
if(true == anythingToRestore)
{
utils_writeEcho(inst, inst->buffer, inst->inputCount);
history_navigate(inst, 1);
inst->dirty = false;
}
history_navigate(inst, 1);
}
/**

View File

@ -162,6 +162,7 @@ void utils_forwardCursor(shellmatta_instance_t *inst, uint32_t length)
* @param[in] inst pointer to shellmatta instance
* @param[in] data pointer to the data to be inserted
* @param[in] length length of the data to be inserted
* @todo this function shall check buffer overflows
*/
void utils_insertChars( shellmatta_instance_t *inst,
char *data,
@ -192,16 +193,20 @@ void utils_insertChars( shellmatta_instance_t *inst,
&(inst->buffer[inst->cursor + length]),
inst->inputCount - inst->cursor);
utils_restoreCursorPos(inst);
inst->cursor += length;
inst->inputCount += length;
}
/** -# just overwrite/append the chars */
/** -# overwrite - if the cursor reaches the end of the input it is pushed further */
else
{
memcpy(&(inst->buffer[inst->cursor]), data, length);
utils_writeEcho(inst, data, length);
}
inst->inputCount += length;
inst->cursor += length;
if(inst->cursor > inst->inputCount)
{
inst->inputCount = inst->cursor;
}
}
}
}

View File

@ -77,6 +77,7 @@ TEST_CASE( "shellmatta help function" ) {
char historyBuffer[1024];
char *dummyData = (char*)"?\r\n"
"doSomething do Function does something use me, please\r\n"
"empty \r\n"
"help ? Print this help text help\r\n"
"\r\nshellmatta->";
@ -89,6 +90,7 @@ TEST_CASE( "shellmatta help function" ) {
"shellmatta->",
NULL,
writeFct);
shellmatta_addCmd(handle, &emptyCmd);
shellmatta_addCmd(handle, &doSomethingCmd);
write_callCnt = 0u;
@ -97,11 +99,9 @@ TEST_CASE( "shellmatta help function" ) {
shellmatta_processData(handle, (char*)"?\r", 2);
CHECK( write_length == 123u);
CHECK( write_length == strlen(dummyData));
CHECK( strcmp(dummyData, write_data) == 0);
shellmatta_addCmd(handle, &emptyCmd);
write_callCnt = 0u;
memset(write_data, 0, sizeof(write_data));
write_length = 0u;
@ -228,9 +228,256 @@ TEST_CASE( "shellmatta remove function" ) {
"help ? Print this help text help\r\n"
"\r\nshellmatta->";
printf("sdfsd sdf sdf sdf sdf sd fds\n%s", write_data);
CHECK( write_length == 72u);
REQUIRE( strcmp(dummyData, write_data) == 0);
}
TEST_CASE( "shellmatta reset no prompt" ) {
shellmatta_instance_t inst;
shellmatta_handle_t handle;
char buffer[1024];
char historyBuffer[1024];
char *dummyData = (char*)"dkfg hdlsfkgh ldksfjhg lkdjfsh glkd?\r\n"
"doSomething do Function does something use me, please\r\n"
"help ? Print this help text help\r\n"
"\r\nshellmatta->";
shellmatta_doInit( &inst,
&handle,
buffer,
sizeof(buffer),
historyBuffer,
sizeof(historyBuffer),
"shellmatta->",
NULL,
writeFct);
shellmatta_addCmd(handle, &doSomethingCmd);
write_callCnt = 0u;
memset(write_data, 0, sizeof(write_data));
write_length = 0u;
shellmatta_processData(handle, (char*)"dkfg hdlsfkgh ldksfjhg lkdjfsh glkd", 35);
shellmatta_resetShell(handle, false);
shellmatta_processData(handle, (char*)"?\r", 2);
CHECK( write_length == strlen(dummyData));
REQUIRE( strcmp(dummyData, write_data) == 0);
}
TEST_CASE( "shellmatta reset with prompt" ) {
shellmatta_instance_t inst;
shellmatta_handle_t handle;
char buffer[1024];
char historyBuffer[1024];
char *dummyData = (char*)"dkfg hdlsfkgh ldksfjhg lkdjfsh glkd"
"\r\nshellmatta->?\r\n"
"doSomething do Function does something use me, please\r\n"
"help ? Print this help text help\r\n"
"\r\nshellmatta->";
shellmatta_doInit( &inst,
&handle,
buffer,
sizeof(buffer),
historyBuffer,
sizeof(historyBuffer),
"shellmatta->",
NULL,
writeFct);
shellmatta_addCmd(handle, &doSomethingCmd);
write_callCnt = 0u;
memset(write_data, 0, sizeof(write_data));
write_length = 0u;
shellmatta_processData(handle, (char*)"dkfg hdlsfkgh ldksfjhg lkdjfsh glkd", 35);
shellmatta_resetShell(handle, true);
shellmatta_processData(handle, (char*)"?\r", 2);
CHECK( write_length == strlen(dummyData));
REQUIRE( strcmp(dummyData, write_data) == 0);
}
TEST_CASE( "shellmatta reset no prompt history buffer" ) {
shellmatta_instance_t inst;
shellmatta_handle_t handle;
char buffer[1024];
char historyBuffer[1024];
char *dummyData = (char*)"?\r\n"
"doSomething do Function does something use me, please\r\n"
"help ? Print this help text help\r\n"
"\r\nshellmatta->";
shellmatta_doInit( &inst,
&handle,
buffer,
sizeof(buffer),
historyBuffer,
sizeof(historyBuffer),
"shellmatta->",
NULL,
writeFct);
shellmatta_addCmd(handle, &doSomethingCmd);
shellmatta_processData(handle, (char*)"dkfg hdlsfkgh ldksfjhg lkdjfsh gl\r\n", 35u);
shellmatta_processData(handle, (char*)"dkfg hdlsfkgh ldksfjhg lkdjfsh gl\r\n", 35u);
shellmatta_processData(handle, (char*)"dkfg hdlsfkgh ldksfjhg lkdjfsh gl\r\n", 35u);
write_callCnt = 0u;
memset(write_data, 0, sizeof(write_data));
write_length = 0u;
shellmatta_resetShell(handle, false);
/* process arrow key up - if reset worked this should deliver nothing */
shellmatta_processData(handle, (char*)"\033[A", 3u);
shellmatta_processData(handle, (char*)"?\r", 2);
CHECK( write_length == strlen(dummyData));
REQUIRE( strcmp(dummyData, write_data) == 0);
}
TEST_CASE( "shellmatta reset no prompt heredoc" ) {
shellmatta_instance_t inst;
shellmatta_handle_t handle;
char buffer[1024];
char historyBuffer[1024];
char *dummyData = (char*)"?\r\n"
"doSomething do Function does something use me, please\r\n"
"help ? Print this help text help\r\n"
"\r\nshellmatta->";
shellmatta_doInit( &inst,
&handle,
buffer,
sizeof(buffer),
historyBuffer,
sizeof(historyBuffer),
"shellmatta->",
NULL,
writeFct);
shellmatta_addCmd(handle, &doSomethingCmd);
shellmatta_processData(handle, (char*)"dummy cmd << EOF\r\n", 18u);
shellmatta_processData(handle, (char*)"dkfg hdlsfkgh ldksfjhg lkdjfsh gl\r\n", 35u);
shellmatta_processData(handle, (char*)"dkfg hdlsfkgh ldksfjhg lkdjfsh gl\r\n", 35u);
write_callCnt = 0u;
memset(write_data, 0, sizeof(write_data));
write_length = 0u;
/* end the heredoc session by resetting the shell */
shellmatta_resetShell(handle, false);
/* now the new command should be processed */
shellmatta_processData(handle, (char*)"?\r", 2);
CHECK( write_length == strlen(dummyData));
REQUIRE( strcmp(dummyData, write_data) == 0);
}
TEST_CASE( "shellmatta configure disable echo" ) {
shellmatta_instance_t inst;
shellmatta_handle_t handle;
shellmatta_retCode_t ret;
char buffer[1024];
char historyBuffer[1024];
char *dummyData = (char*)"help this is some dummy Text\r\n"
"doSomething do Function does something use me, please\r\n"
"help ? Print this help text help\r\n"
"\r\nshellmatta->";
char *dummyData2 = (char*)"doSomething do Function does something use me, please\r\n"
"help ? Print this help text help\r\n"
"\r\nshellmatta->";
shellmatta_doInit( &inst,
&handle,
buffer,
sizeof(buffer),
historyBuffer,
sizeof(historyBuffer),
"shellmatta->",
NULL,
writeFct);
shellmatta_addCmd(handle, &doSomethingCmd);
write_callCnt = 0u;
memset(write_data, 0, sizeof(write_data));
write_length = 0u;
/* check with echo enabled */
shellmatta_processData(handle, (char*)"help this is some dummy Text\r\n", 30u);
CHECK( write_length == strlen(dummyData));
CHECK( strcmp(dummyData, write_data) == 0);
write_callCnt = 0u;
memset(write_data, 0, sizeof(write_data));
write_length = 0u;
/* turn off echo now */
ret = shellmatta_configure(handle, SHELLMATTA_MODE_INSERT, false);
CHECK( ret == SHELLMATTA_OK );
/* check with echo disabled */
shellmatta_processData(handle, (char*)"help this is some dummy Text\r\n", 30u);
CHECK( write_length == strlen(dummyData2));
REQUIRE( strcmp(dummyData2, write_data) == 0);
}
TEST_CASE( "shellmatta configure mode" ) {
shellmatta_instance_t inst;
shellmatta_handle_t handle;
shellmatta_retCode_t ret;
char buffer[1024];
char historyBuffer[1024];
char *dummyData = (char*)"\r\nCommand: meow this is some dum123456my Text not found\r\nshellmatta->";
char *dummyData2 = (char*)"\r\nCommand: meow this is some dum123456t not found\r\nshellmatta->";
shellmatta_doInit( &inst,
&handle,
buffer,
sizeof(buffer),
historyBuffer,
sizeof(historyBuffer),
"shellmatta->",
NULL,
writeFct);
shellmatta_addCmd(handle, &doSomethingCmd);
ret = shellmatta_configure(handle, SHELLMATTA_MODE_INSERT, false);
write_callCnt = 0u;
memset(write_data, 0, sizeof(write_data));
write_length = 0u;
/* check with insert mode */
shellmatta_processData(handle, (char*)"meow this is some dummy Text\x1b[D\x1b[D\x1b[D\x1b[D\x1b[D\x1b[D\x1b[D123456\r\n", 57u);
CHECK( write_length == strlen(dummyData));
CHECK( strcmp(dummyData, write_data) == 0);
write_callCnt = 0u;
memset(write_data, 0, sizeof(write_data));
write_length = 0u;
/* check with overwrite mode */
ret = shellmatta_configure(handle, SHELLMATTA_MODE_OVERWRITE, false);
CHECK( ret == SHELLMATTA_OK );
/* check with echo disabled */
shellmatta_processData(handle, (char*)"meow this is some dummy Text\x1b[D\x1b[D\x1b[D\x1b[D\x1b[D\x1b[D\x1b[D123456\r\n", 57u);
CHECK( write_length == strlen(dummyData2));
REQUIRE( strcmp(dummyData2, write_data) == 0);
}

View File

@ -61,7 +61,7 @@ TEST_CASE( "shellmatta_insertChars overwrite" ) {
utils_insertChars(&inst, (char*)"blksdflsd kfjlk", 4u);
CHECK( inst.cursor == 12);
CHECK( inst.inputCount == 14);
CHECK( inst.inputCount == 12);
CHECK( write_callCnt == 1u );
CHECK( strncmp("blks", write_data, 5u) == 0);
REQUIRE( strncmp("abcdefghblks\0\0\0\0\0\0\0\0\0", buffer, sizeof(buffer)) == 0);