Procházet zdrojové kódy

close #14 - added a resetShell api function + fixed some problems

prozessorkern před 4 roky
rodič
revize
bf1d91eca7

+ 21 - 0
.vscode/launch.json

@@ -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",

+ 3 - 0
api/shellmatta.h

@@ -126,6 +126,9 @@ 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);
 

+ 19 - 0
example/main.c

@@ -96,6 +96,24 @@ static shellmatta_retCode_t empty(shellmatta_handle_t handle, const char *argume
 }
 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);
+    }
+
+    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 +158,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)
     {

+ 59 - 8
src/shellmatta.c

@@ -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);
                 }
@@ -275,8 +323,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 +338,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 +367,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 +402,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 +446,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);
                     }
                 }
 

+ 0 - 2
src/shellmatta_escape.c

@@ -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;

+ 13 - 2
src/shellmatta_history.c

@@ -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);
     }
 
-    utils_writeEcho(inst, inst->buffer, inst->inputCount);
+    if(true == anythingToRestore)
+    {
+        utils_writeEcho(inst, inst->buffer, inst->inputCount);
+        inst->dirty = false;
+    }
     history_navigate(inst, 1);
-    inst->dirty = false;
 }
 
 /**

+ 154 - 6
test/integrationtest/test_integration.cpp

@@ -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,157 @@ 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);
+
+    printf("%s", write_data);
+
+    CHECK( write_length == strlen(dummyData));
+    REQUIRE( strcmp(dummyData, write_data) == 0);
+}