From 280e51274631e7c53629f331a8d0a5f7cf26ccd0 Mon Sep 17 00:00:00 2001 From: prozessorkern Date: Mon, 29 Jul 2019 01:30:16 +0200 Subject: [PATCH] added basic heredoc function Some things are broken: navigation in multiline inputs history buffer for multiline inputs some things not been noticed yet --- api/shellmatta.h | 5 +- example/main.c | 5 +- src/shellmatta.c | 154 +++++++++++++++++++++++++++++++---------- src/shellmatta_utils.c | 6 +- 4 files changed, 126 insertions(+), 44 deletions(-) diff --git a/api/shellmatta.h b/api/shellmatta.h index 67f4d37..1e9b804 100644 --- a/api/shellmatta.h +++ b/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 */ diff --git a/example/main.c b/example/main.c index d8ef635..8366255 100644 --- a/example/main.c +++ b/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) { diff --git a/src/shellmatta.c b/src/shellmatta.c index c9bdd68..b072856 100644 --- a/src/shellmatta.c +++ b/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; - - /** -# 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])) + if(0u == inst->hereLength) { - cmdLen ++; - } + /** + * \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 */ - /** -# 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)))) + /** -# check for heredoc */ + tempString = strstr(inst->buffer, "<<"); + if(NULL != tempString) { - inst->write("\r\n", 2u); + /*' -# 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); - cmdExecuted = 1u; - cmd->cmdFct(inst, inst->buffer, inst->inputCount); - cmd = NULL; + 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); + + 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 + { + tempString = &inst->buffer[inst->lastNewlineIdx]; + cmdLen = inst->inputCount - inst->lastNewlineIdx; + + /** -# skip newline characters before comparison */ + while(('\n' == *tempString) || ('\r' == *tempString)) + { + tempString ++; + cmdLen --; + } + + 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) diff --git a/src/shellmatta_utils.c b/src/shellmatta_utils.c index 2b67f1d..9993e0f 100644 --- a/src/shellmatta_utils.c +++ b/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)); }