Преглед изворни кода

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

prozessorkern пре 4 година
родитељ
комит
d7962a54dc
5 измењених фајлова са 218 додато и 30 уклоњено
  1. 4 1
      api/shellmatta.h
  2. 2 1
      makefile
  3. 81 28
      src/shellmatta.c
  4. 1 0
      src/shellmatta_utils.c
  5. 130 0
      test/integrationtest/test_integration_busy.cpp

+ 4 - 1
api/shellmatta.h

@@ -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                 */

+ 2 - 1
makefile

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

+ 81 - 28
src/shellmatta.c

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

+ 1 - 0
src/shellmatta_utils.c

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

+ 130 - 0
test/integrationtest/test_integration_busy.cpp

@@ -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);
+}