ソースを参照

added basic heredoc function
Some things are broken:
navigation in multiline inputs
history buffer for multiline inputs
some things not been noticed yet

prozessorkern 5 年 前
コミット
280e512746
4 ファイル変更124 行追加42 行削除
  1. 4 1
      api/shellmatta.h
  2. 2 3
      example/main.c
  3. 114 36
      src/shellmatta.c
  4. 4 2
      src/shellmatta_utils.c

+ 4 - 1
api/shellmatta.h

@@ -91,6 +91,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            lastNewlineIdx;     /**< index of the lest newline              */
     uint32_t            cursor;             /**< offset where the cursor is at          */
     char                *historyBuffer;     /**< buffer to store the last commands      */
     uint32_t            historyBufferSize;  /**< size of the history buffer             */
@@ -100,7 +101,9 @@ typedef struct
     bool                historyReadUp;      /**< flag to show the last history dir      */
     uint32_t            tabCounter;         /**< counts the tabulator key presses       */
     uint32_t            escapeCounter;      /**< counts the characters of an escape seq */
-    char                escapeChars[4];     /**< buffer to save the escape characters   */
+    char                escapeChars[4u];    /**< buffer to save the escape characters   */
+    char                hereDelimiter[16u]; /**< heredoc delimiter                      */
+    uint32_t            hereLength;         /**< length of the heredoc delimiter        */
     bool                echoEnabled;        /**< if true the input is printed           */
     bool                dirty;              /**< dirty flag to show changes             */
     const char          *prompt;            /**< prompt is printed after every command  */

+ 2 - 3
example/main.c

@@ -22,8 +22,7 @@ static bool exitRequest = false;
 int f;
 shellmatta_handle_t handle;
 
-void
-set_blocking (int fd, int should_block)
+void set_blocking (int fd, int should_block)
 {
         struct termios tty;
         memset (&tty, 0, sizeof tty);
@@ -80,7 +79,7 @@ int main(void)
     static char historyBuffer[4096];
     static shellmatta_instance_t instance;
 
-    f = open("/dev/pts/3", O_RDWR | O_SYNC);
+    f = open("/dev/pts/1", O_RDWR | O_SYNC);
 
     if (f < 0)
     {

+ 114 - 36
src/shellmatta.c

@@ -74,6 +74,7 @@ shellmatta_retCode_t shellmatta_doInit(
         inst->buffer                = buffer;
         inst->bufferSize            = bufferSize;
         inst->inputCount            = 0u;
+        inst->lastNewlineIdx        = 0u;
         inst->cursor                = 0u;
         inst->historyBuffer         = historyBuffer;
         inst->historyBufferSize     = historyBufferSize;
@@ -87,6 +88,7 @@ shellmatta_retCode_t shellmatta_doInit(
         inst->dirty                 = false;
         inst->tabCounter            = 0u;
         inst->escapeCounter         = 0u;
+        inst->hereLength            = 0u;
         inst->mode                  = SHELLMATTA_MODE_INSERT;
         inst->cmdList               = &helpCmd;
         inst->cmdListIsConst        = false;
@@ -194,6 +196,7 @@ shellmatta_retCode_t shellmatta_processData(shellmatta_handle_t     handle,
     shellmatta_cmd_t        *cmd;
     uint8_t                 cmdExecuted = 0u;
     uint32_t                cmdLen;
+    char                    *tempString;
     shellmatta_retCode_t    ret = SHELLMATTA_OK;
     shellmatta_instance_t   *inst = (shellmatta_instance_t*)handle;
 
@@ -218,56 +221,131 @@ shellmatta_retCode_t shellmatta_processData(shellmatta_handle_t     handle,
             /** -# handle return as start of processing the command */
             else if ('\r' == *data)
             {
-                cmd                             = inst->cmdList;
-                inst->buffer[inst->inputCount]  = 0u;
+                if(0u == inst->hereLength)
+                {
+                    /**
+                      *  \dot
+                      *  digraph heredocParser {
+                      *      start -> wait [ label="<< in first line - store delimiter" ];
+                      *      wait -> wait [ label="delimiter not detected" ];
+                      *      wait -> end [ label="delimiter found - remove all heredoc stuff and send the input to the command" ];
+                      *  }
+                      *  \enddot */
 
-                /** -# store the current command and reset the history buffer */
-                inst->dirty = true;
-                history_storeCmd(inst);
-                history_reset(inst);
+                    /** -# check for heredoc */
+                    tempString = strstr(inst->buffer, "<<");
+                    if(NULL != tempString)
+                    {
+                        /*' -# check if length of heredoc delimiter is valid */
+                        if(inst->inputCount > ((uint32_t)(tempString - inst->buffer) + 2u))
+                        {
+                            inst->hereLength = inst->inputCount - ((uint32_t)(tempString - inst->buffer) + 2u);
 
-                /** -# determine the cmd len (chars until first space or \0 is found */
-                cmdLen = 0u;
-                while(      (cmdLen <   inst->inputCount)
-                        &&  (' '    !=  inst->buffer[cmdLen])
-                        &&  ('\0'   !=  inst->buffer[cmdLen]))
-                {
-                    cmdLen ++;
-                }
+                            if(sizeof(inst->hereDelimiter) < inst->hereLength)
+                            {
+                                inst->write("\r\nHeredoc delimiter too long\r\n", 30u);
+                                inst->inputCount = 0u;
+                                inst->hereLength    = 0u;
+                            }
+                            else
+                            {
+                                /** -# store delimiter and remove it from the input buffer */
+                                strncpy(inst->hereDelimiter, &(tempString[2u]), inst->hereLength);
 
-                /** -# search for a matching command */
-                while (NULL != cmd)
+                                inst->inputCount    -= (inst->hereLength + 2u);
+                                inst->cursor        = inst->inputCount;
+                                inst->dirty = true;
+                                utils_insertChars(inst, data, 1);
+                                inst->lastNewlineIdx = inst->inputCount;
+                            }
+                        }
+                        else
+                        {
+                            inst->hereLength    = 0u;
+                        }
+                    }
+                }
+                else
                 {
-                    /** -# compare command string and length */
-                    if (    ((0 == strncmp( inst->buffer,
-                                            cmd->cmd,
-                                            cmdLen))
-                            && (cmdLen == strlen(cmd->cmd)))
-                        ||  ((0 == strncmp( inst->buffer,
-                                            cmd->cmdAlias,
-                                            cmdLen))
-                            && (cmdLen == strlen(cmd->cmdAlias))))
+                    tempString  = &inst->buffer[inst->lastNewlineIdx];
+                    cmdLen      = inst->inputCount - inst->lastNewlineIdx;
+
+                    /** -# skip newline characters before comparison */
+                    while(('\n' == *tempString) || ('\r' == *tempString))
                     {
-                        inst->write("\r\n", 2u);
+                        tempString ++;
+                        cmdLen --;
+                    }
 
-                        cmdExecuted = 1u;
-                        cmd->cmdFct(inst, inst->buffer, inst->inputCount);
-                        cmd = NULL;
+                    if(     (inst->hereLength == cmdLen)
+                        &&  (0  == strncmp( inst->hereDelimiter,
+                                            tempString,
+                                            inst->hereLength)))
+                    {
+                        inst->inputCount = inst->lastNewlineIdx;
+                        inst->hereLength = 0u;
                     }
                     else
                     {
-                        cmd = cmd->next;
+                        inst->lastNewlineIdx = inst->inputCount;
+                        utils_insertChars(inst, data, 1);
                     }
                 }
 
-                if ((cmdExecuted == 0u) && (inst->inputCount > 0))
+                if(0u == inst->hereLength)
                 {
-                    inst->buffer[inst->inputCount] = '\0';
-                    inst->write("\r\nCommand: ", 11u);
-                    inst->write(inst->buffer, inst->inputCount);
-                    inst->write(" not found", 10u);
+                    cmd                             = inst->cmdList;
+                    inst->buffer[inst->inputCount]  = 0u;
+
+                    /** -# store the current command and reset the history buffer */
+                    inst->dirty = true;
+                    history_storeCmd(inst);
+                    history_reset(inst);
+
+                    /** -# determine the cmd len (chars until first space or \0 is found */
+                    cmdLen = 0u;
+                    while(      (cmdLen <   inst->inputCount)
+                            &&  (' '    !=  inst->buffer[cmdLen])
+                            &&  ('\0'   !=  inst->buffer[cmdLen]))
+                    {
+                        cmdLen ++;
+                    }
+
+                    /** -# search for a matching command */
+                    while (NULL != cmd)
+                    {
+                        /** -# compare command string and length */
+                        if (    ((0 == strncmp( inst->buffer,
+                                                cmd->cmd,
+                                                cmdLen))
+                                && (cmdLen == strlen(cmd->cmd)))
+                            ||  ((0 == strncmp( inst->buffer,
+                                                cmd->cmdAlias,
+                                                cmdLen))
+                                && (cmdLen == strlen(cmd->cmdAlias))))
+                        {
+                            inst->write("\r\n", 2u);
+
+                            cmdExecuted = 1u;
+                            cmd->cmdFct(inst, inst->buffer, inst->inputCount);
+                            cmd = NULL;
+                        }
+                        else
+                        {
+                            cmd = cmd->next;
+                        }
+                    }
+
+                    if ((cmdExecuted == 0u) && (inst->inputCount > 0))
+                    {
+                        inst->buffer[inst->inputCount] = '\0';
+                        inst->write("\r\nCommand: ", 11u);
+                        inst->write(inst->buffer, inst->inputCount);
+                        inst->write(" not found", 10u);
+                    }
+                    utils_terminateInput(inst);
                 }
-                utils_terminateInput(inst);
+
             }
             /** -# check for tabulator key - auto complete */
             else if('\t' == *data)

+ 4 - 2
src/shellmatta_utils.c

@@ -335,8 +335,10 @@ shellmatta_cmd_t helpCmd = {"help", "h", "Print this help text", "help", helpCmd
  */
 void utils_terminateInput(shellmatta_instance_t *inst)
 {
-    inst->inputCount    = 0u;
-    inst->cursor        = 0u;
+    inst->inputCount        = 0u;
+    inst->lastNewlineIdx    = 0u;
+    inst->hereLength        = 0u;
+    inst->cursor            = 0u;
     inst->write("\r\n", 2u);
     inst->write(inst->prompt, strlen(inst->prompt));
 }