From bf7f366cb6f4b1d539d9a6c6169af7dd1235fc9c Mon Sep 17 00:00:00 2001 From: prozessorkern Date: Fri, 21 Jun 2019 04:47:35 +0200 Subject: [PATCH] implemented most text based functions: - byte wise processing and call of the command function - history buffer - auto complete - edit functions (backspace, del, arrow keys, pos1, end) --- api/shellmatta.h | 66 +++- src/shellmatta.c | 771 ++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 774 insertions(+), 63 deletions(-) diff --git a/api/shellmatta.h b/api/shellmatta.h index 03a3b6c..92fc88d 100644 --- a/api/shellmatta.h +++ b/api/shellmatta.h @@ -37,6 +37,7 @@ #define _SHELLMATTA_H_ #include +#include /** * @brief definition of shellmatta return codes @@ -46,25 +47,40 @@ typedef enum SHELLMATTA_OK = 0u, /**< everything is OK */ SHELLMATTA_ERROR , /**< error occured */ SHELLMATTA_CONTINUE , /**< the function is not over */ - SHELLMATTA_USE_FAULT /**< parameter error - wrong usage */ + SHELLMATTA_USE_FAULT , /**< parameter error - wrong usage */ + SHELLMATTA_DUPLICATE /**< duplicate command */ } shellmatta_retCode_t; +/** + * @brief definition of shellmatta insert mode + */ +typedef enum +{ + SHELLMATTA_MODE_INSERT = 0u, /**< insert mode */ + SHELLMATTA_MODE_OVERWRITE , /**< overwrite mode */ +} shellmatta_mode_t; + /** * @brief shellmatta command function definition */ typedef shellmatta_retCode_t (*shellmatta_cmdFct_t)(int argc, char *argv[]); +/** + * @brief shellmatta write function definition + */ +typedef shellmatta_retCode_t (*shellmatta_write_t)(const char* data, uint32_t length); + /** * @brief structure of one shellmatta command */ typedef struct shellmatta_cmd { - char *cmd; /**< command name */ - char *cmdAlias; /**< command alias */ - char *helpText; /**< help text to print in "help" command */ - char *usageText; /**< usage text to print on parameter error */ - shellmatta_cmdFct_t cmdFct; /**< pointer to the cmd callack function */ - struct shellmatta_cmd *next; /**< pointer to next command or NULL */ + char *cmd; /**< command name */ + char *cmdAlias; /**< command alias */ + char *helpText; /**< help text to print in "help" command */ + char *usageText; /**< usage text to print on parameter error */ + shellmatta_cmdFct_t cmdFct; /**< pointer to the cmd callack function */ + struct shellmatta_cmd *next; /**< pointer to next command or NULL */ } shellmatta_cmd_t; /** @@ -72,17 +88,35 @@ typedef struct shellmatta_cmd */ typedef struct { - uint8_t *buffer; /**< input buffer */ - uint32_t bufferSize; /**< size of the input buffer */ - uint32_t bufferWritePointer; /**< offset of the current write operation */ - uint32_t bufferReadPointer; /**< offset of the current read operation */ - uint8_t *historyBuffer; /**< buffer to store the last commands */ - uint32_t historyBufferSize; /**< size of the history buffer */ - shellmatta_cmd_t *cmdList; /**< pointer to the first command */ + uint8_t *buffer; /**< input buffer */ + uint32_t bufferSize; /**< size of the input buffer */ + uint32_t inputCount; /**< offset of the current write operation */ + uint32_t cursor; /**< offset where the cursor is at */ + uint8_t *historyBuffer; /**< buffer to store the last commands */ + uint32_t historyBufferSize; /**< size of the history buffer */ + uint32_t historyStart; /**< index of the oldest stored command */ + uint32_t historyEnd; /**< index of the newest stored command */ + uint32_t historyRead; /**< index of the current search */ + 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 */ + uint8_t escapeChars[4]; /**< buffer to save the escape characters */ + bool echoEnabled; /**< if true the input is printed */ + bool dirty; /**< dirty flag to show changes */ + const char *prompt; /**< prompt is printed after every command */ + shellmatta_mode_t mode; /**< mode of the shell */ + shellmatta_write_t write; /**< pointer to write function */ + shellmatta_cmd_t *cmdList; /**< pointer to the first command */ } shellmatta_instance_t; -void shellmatta_doInit(shellmatta_instance_t *inst, uint8_t *buffer, uint32_t bufferSize, uint8_t *historyBuffer, uint32_t historyBufferSize); -void shellmatta_addCmd(shellmatta_instance_t *inst, shellmatta_cmd_t *cmd); +shellmatta_retCode_t shellmatta_doInit( shellmatta_instance_t *inst, + uint8_t *buffer, + uint32_t bufferSize, + uint8_t *historyBuffer, + uint32_t historyBufferSize, + const char *prompt, + shellmatta_write_t writeFct); +shellmatta_retCode_t shellmatta_addCmd(shellmatta_instance_t *inst, shellmatta_cmd_t *cmd); void shellmatta_doTask(shellmatta_instance_t *inst, uint32_t time); void shellmatta_processData(shellmatta_instance_t *inst, char *data, uint32_t size); void shellmatta_printf(shellmatta_instance_t *inst, const char *fmt, ...); diff --git a/src/shellmatta.c b/src/shellmatta.c index 5444715..48ca8eb 100644 --- a/src/shellmatta.c +++ b/src/shellmatta.c @@ -37,6 +37,560 @@ #include #include #include +#include + +#define SHELLMATTA_MIN(a,b) (((a) > (b)) ? (b) : (a)) +#define SHELLMATTA_MAX(a,b) (((a) > (b)) ? (b) : (a)) + +static void writeEcho( shellmatta_instance_t *inst, + const uint8_t *data, + uint32_t length) +{ + if(true == inst->echoEnabled) + { + inst->write(data, length); + } +} + +static void appendHistoryByte(shellmatta_instance_t *inst, uint8_t byte) +{ + inst->historyEnd ++; + + if(inst->historyEnd >= inst->historyBufferSize) + { + inst->historyEnd = 0u; + } + + inst->historyBuffer[inst->historyEnd] = byte; + + if(inst->historyEnd == inst->historyStart) + { + /* move the start pointer to the next termination (0) */ + do + { + inst->historyStart ++; + + if(inst->historyStart >= inst->historyBufferSize) + { + inst->historyStart = 0u; + } + + }while(0u != inst->historyBuffer[inst->historyStart]); + } +} + +static bool getHistoryByte(shellmatta_instance_t *inst, uint8_t *byte) +{ + bool ret = false; + + if(inst->historyRead != inst->historyStart) + { + *byte = inst->historyBuffer[inst->historyRead]; + + if(0u == inst->historyRead) + { + inst->historyRead = inst->historyBufferSize; + } + + inst->historyRead --; + + ret = true; + } + + return ret; +} + +static void storeHistoryCmd(shellmatta_instance_t *inst) +{ + if( (inst->historyBufferSize > inst->inputCount) + && (0u != inst->inputCount) + && (true == inst->dirty)) + { + appendHistoryByte(inst, 0u); + + for(uint32_t i = inst->inputCount; i > 0u; i --) + { + appendHistoryByte(inst, inst->buffer[i - 1u]); + } + } + inst->dirty = false; +} + +static bool navigateHistoryCmd(shellmatta_instance_t *inst, int32_t cnt) +{ + bool ret = true; + uint32_t tempReadIdx = 0u; + + while((cnt > 0) && (true == ret)) + { + if(inst->historyRead != inst->historyEnd) + { + inst->historyRead ++; + } + while(inst->historyRead != inst->historyEnd) + { + inst->historyRead ++; + if(inst->historyRead >= inst->historyBufferSize) + { + inst->historyRead = 0u; + } + + if( (inst->historyRead != inst->historyEnd) + && (0u == inst->historyBuffer[inst->historyRead])) + { + if(0u == inst->historyRead) + { + inst->historyRead = inst->historyBufferSize; + } + inst->historyRead --; + cnt -= 1; + break; + } + } + + if(inst->historyRead == inst->historyEnd) + { + ret = false; + } + } + + while((cnt < 0) && (true == ret)) + { + tempReadIdx = inst->historyRead; + while(inst->historyRead != inst->historyStart) + { + if(0u == inst->historyRead) + { + inst->historyRead = inst->historyBufferSize; + } + inst->historyRead --; + + if( (inst->historyRead != inst->historyStart) + && (0u == inst->historyBuffer[inst->historyRead])) + { + if(0u == inst->historyRead) + { + inst->historyRead = inst->historyBufferSize; + } + inst->historyRead --; + cnt += 1; + break; + } + } + if(inst->historyRead == inst->historyStart) + { + inst->historyRead = tempReadIdx; + inst->historyReadUp = false; + ret = false; + } + } + + return ret; +} + +static void restoreHistoryCmd(shellmatta_instance_t *inst) +{ + uint8_t byte; + bool ret = true; + + ret = getHistoryByte(inst, &byte); + while((ret == true) && (byte != 0u)) + { + inst->buffer[inst->inputCount] = byte; + inst->inputCount ++; + inst->cursor ++; + ret = getHistoryByte(inst, &byte); + } + + writeEcho(inst, inst->buffer, inst->inputCount); + navigateHistoryCmd(inst, 1); + inst->dirty = false; +} + +static void resetHistoryBuffer(shellmatta_instance_t *inst) +{ + inst->historyRead = inst->historyEnd; + inst->historyReadUp = true; +} + +static void saveCursorPos(shellmatta_instance_t *inst) +{ + writeEcho(inst, "\e[s", 3u); +} + +static void restoreCursorPos(shellmatta_instance_t *inst) +{ + writeEcho(inst, "\e[u", 3u); +} + +static void eraseLine(shellmatta_instance_t *inst) +{ + writeEcho(inst, "\e[K", 3u); +} + +static void rewindCursor(shellmatta_instance_t *inst, uint32_t length) +{ + uint8_t terminalCmd[16]; + size_t size; + + length = SHELLMATTA_MIN (length, inst->cursor); + if(length > 0u) + { + size = snprintf(terminalCmd, sizeof(terminalCmd), "\e[%uD", length); + writeEcho(inst, terminalCmd, size); + inst->cursor -= length; + } +} + +static void forwardCursor(shellmatta_instance_t *inst, uint32_t length) +{ + uint8_t terminalCmd[16]; + size_t size; + + length = SHELLMATTA_MAX (length, + (inst->inputCount - inst->cursor)); + if (length > 0u) + { + size = snprintf(terminalCmd, sizeof(terminalCmd), "\e[%uC", length); + writeEcho(inst, terminalCmd, size); + inst->cursor -= length; + } +} + +static void insertChars(shellmatta_instance_t *inst, + uint8_t *data, + uint32_t length) +{ + /* check if we have to move chars in the buffer */ + if( (inst->cursor != inst->inputCount) + && (SHELLMATTA_MODE_INSERT == inst->mode)) + { + /* move the existing chars */ + for ( uint32_t i = inst->inputCount; + i > inst->cursor; + i --) + { + inst->buffer[i + length - 1] = inst->buffer[i - 1]; + } + + /* store and print the new chars */ + memcpy(&(inst->buffer[inst->cursor]), data, length); + writeEcho(inst, data, length); + + /* print the other chars and restore the cursor to this position */ + eraseLine(inst); + saveCursorPos(inst); + writeEcho( inst, + &(inst->buffer[inst->cursor + length]), + inst->inputCount - inst->cursor); + restoreCursorPos(inst); + } + /* just overwrite/append the chars */ + else + { + memcpy(&(inst->buffer[inst->cursor]), data, length); + writeEcho(inst, data, length); + } + + inst->inputCount += length; + inst->cursor += length; +} + +static void removeChars(shellmatta_instance_t *inst, + uint32_t length, + bool backspace) +{ + length = SHELLMATTA_MIN (length, inst->cursor); + if(0u != length) + { + if(true == backspace) + { + rewindCursor(inst, length); + } + /* delete the char at the cursor position */ + for ( uint32_t i = inst->cursor; + i < (inst->inputCount - length); + i++) + { + inst->buffer[i] = inst->buffer[i + length]; + } + eraseLine(inst); + saveCursorPos(inst); + writeEcho( inst, + &(inst->buffer[inst->cursor]), + (inst->inputCount - inst->cursor - length)); + restoreCursorPos(inst); + + inst->inputCount -= length; + } +} + +static void clearInput(shellmatta_instance_t *inst) +{ + rewindCursor(inst, inst->cursor); + eraseLine(inst); + inst->inputCount = 0u; + inst->dirty = false; +} + +static shellmatta_retCode_t processArrowKeys(shellmatta_instance_t *inst) +{ + shellmatta_retCode_t ret = SHELLMATTA_USE_FAULT; + + if ('[' == inst->escapeChars[0]) + { + ret = SHELLMATTA_OK; + + switch (inst->escapeChars[1]) + { + case 'A': /* arrow up */ + storeHistoryCmd(inst); + if(false == inst->historyReadUp) + { + navigateHistoryCmd(inst, -1); + } + inst->historyReadUp = true; + clearInput(inst); + restoreHistoryCmd(inst); + navigateHistoryCmd(inst, -1); + + break; + case 'B': /* arrow down */ + + if((inst->historyRead != inst->historyEnd)) + { + storeHistoryCmd(inst); + if(true == inst->historyReadUp) + { + navigateHistoryCmd(inst, 1); + } + inst->historyReadUp = false; + navigateHistoryCmd(inst, 1); + clearInput(inst); + restoreHistoryCmd(inst); + } + break; + case 'C': /* arrow right */ + forwardCursor(inst, 1u); + break; + case 'D': /* arrow left */ + rewindCursor(inst, 1u); + break; + default: + /** ignore unknown escape */ + ret = SHELLMATTA_USE_FAULT; + break; + } + } + return ret; +} + +void handleEscapeSequence(shellmatta_instance_t *inst, uint8_t *data) +{ + switch (inst->escapeCounter) + { + case 1u: + inst->escapeChars[inst->escapeCounter - 1] = *data; + inst->escapeCounter ++; + break; + case 2u: + inst->escapeChars[inst->escapeCounter - 1] = *data; + if(SHELLMATTA_OK == processArrowKeys(inst)) + { + inst->escapeCounter = 0u; + } + else if ( (0x4fu == inst->escapeChars[0]) + && (0x46u == inst->escapeChars[1])) + { + forwardCursor(inst, inst->inputCount - inst->cursor); + inst->escapeCounter = 0u; + } + else if(0u == (0x40u & *data)) + { + inst->escapeCounter ++; + } + else + { + inst->escapeCounter = 0u; + } + break; + case 3u: + inst->escapeChars[inst->escapeCounter - 1] = *data; + if( (0x5bu == inst->escapeChars[0]) + && (0x33u == inst->escapeChars[1]) + && (0x7eu == inst->escapeChars[2])) + { + removeChars(inst, 1u, false); + inst->escapeCounter = 0u; + } + /* pos1 */ + else if ( (0x5bu == inst->escapeChars[0]) + && (0x31u == inst->escapeChars[1]) + && (0x7eu == inst->escapeChars[2])) + { + rewindCursor(inst, inst->cursor); + inst->escapeCounter = 0u; + } + else if(0u == (0x40u & *data)) + { + inst->escapeCounter ++; + } + else + { + inst->escapeCounter = 0u; + } + break; + default: + inst->escapeCounter = 0u; + break; + } +} + +static void terminateInput(shellmatta_instance_t *inst) +{ + inst->inputCount = 0u; + inst->cursor = 0u; + shellmatta_printf(inst, "\n\r%s", inst->prompt); +} + +static void doAutocomplete(shellmatta_instance_t *inst) +{ + shellmatta_cmd_t *cmd = inst->cmdList; + uint8_t *tempCmd = NULL; + uint32_t minLen = 0u; + uint32_t sizeDiff = 0u; + bool exactMatch = true; + uint32_t printedLen = 0u; + + inst->tabCounter++; + + /* on douple tab show all matching commands */ + if (1u < inst->tabCounter) + { + inst->tabCounter = 0u; + + while (NULL != cmd) + { + /* check if command matches the input */ + if( (strlen(cmd->cmd) > inst->cursor) + && (0u == memcmp(cmd->cmd, inst->buffer, inst->cursor))) + { + /* add newline on first find */ + if(0u == printedLen) + { + saveCursorPos(inst); + inst->write("\n\r", 2u); + } + inst->write(cmd->cmd, strlen(cmd->cmd)); + printedLen += strlen(cmd->cmd); + inst->write(" ", 4u); + printedLen += 4u; + } + /* check if command matches the input */ + if( (strlen(cmd->cmdAlias) > inst->cursor) + && (0u == memcmp(cmd->cmdAlias, inst->buffer, inst->cursor))) + { + /* add newline on first find */ + if(0u == printedLen) + { + saveCursorPos(inst); + inst->write("\n\r", 2u); + } + inst->write(cmd->cmdAlias, strlen(cmd->cmdAlias)); + printedLen += strlen(cmd->cmdAlias); + inst->write(" ", 4u); + printedLen += 4u; + } + cmd = cmd->next; + } + /* print input again if a commands was found */ + if(printedLen > 0u) + { + writeEcho(inst, "\n\r", 2u); + writeEcho(inst, inst->prompt, strlen(inst->prompt)); + writeEcho(inst, inst->buffer, inst->inputCount); + restoreCursorPos(inst); + } + } + /* on single tab autocomplete as far as possible */ + else if(0u != inst->cursor) + { + /* loop through all registered commands */ + while (NULL != cmd) + { + /* check if command matches the input */ + if( (strlen(cmd->cmd) > inst->cursor) + && (0u == memcmp(cmd->cmd, inst->buffer, inst->cursor))) + { + /* store first match */ + if(NULL == tempCmd) + { + tempCmd = cmd->cmd; + minLen = strlen(cmd->cmd); + } + /* find common part of the matches */ + else + { + exactMatch = false; + minLen = SHELLMATTA_MIN(strlen(cmd->cmd), minLen); + for(uint32_t i = 0u; i < minLen; i++) + { + if(cmd->cmd[i] != tempCmd[i]) + { + minLen = i; + } + } + } + } + + /* check if command Alias matches the input */ + if( (strlen(cmd->cmdAlias) > inst->cursor) + && (0u == memcmp(cmd->cmdAlias, inst->buffer, inst->cursor))) + { + /* store first match */ + if(NULL == tempCmd) + { + tempCmd = cmd->cmdAlias; + minLen = strlen(cmd->cmdAlias); + } + /* find common part of the matches */ + else + { + exactMatch = false; + minLen = SHELLMATTA_MIN(strlen(cmd->cmdAlias), minLen); + for(uint32_t i = 0u; i < minLen; i++) + { + if(cmd->cmdAlias[i] != tempCmd[i]) + { + minLen = i; + } + } + } + } + cmd = cmd->next; + } + + /* autocomplete found command */ + if(NULL != tempCmd) + { + /* calculate the size of the command to be inserted */ + sizeDiff = minLen - inst->cursor; + + /* copy the found part into the buffer and display it */ + insertChars(inst, &(tempCmd[inst->cursor]), sizeDiff); + + /* on exact match there is no need to double Tab to display all */ + if(true == exactMatch) + { + inst->tabCounter = 0u; + } + } + } + else + { + /* nothing to do here */ + } +} /** * @brief initialize the shellmatta terminal and provide all callbacks @@ -47,43 +601,97 @@ * NULL in case of no history buffer * @param[in] historyBufferSize size of the history buffer * 0 in case of no history buffer + * @param[in] prompt pointer to prompt string - is printed + * after each command + * @param[in] writeFct function pointer to output function */ -void shellmatta_doInit( - shellmatta_instance_t *inst, - uint8_t *buffer, - uint32_t bufferSize, - uint8_t *historyBuffer, - uint32_t historyBufferSize) +shellmatta_retCode_t shellmatta_doInit( + shellmatta_instance_t *inst, + uint8_t *buffer, + uint32_t bufferSize, + uint8_t *historyBuffer, + uint32_t historyBufferSize, + const char *prompt, + shellmatta_write_t writeFct) { /** - copy all provided buffers into the shellmatta instance */ - inst->buffer = buffer; - inst->bufferSize = bufferSize; - inst->bufferReadPointer = 0u; - inst->bufferWritePointer = 0u; - inst->cmdList = NULL; - inst->historyBuffer = historyBuffer; - inst->historyBufferSize = historyBufferSize; + inst->buffer = buffer; + inst->bufferSize = bufferSize; + inst->inputCount = 0u; + inst->cursor = 0u; + inst->cmdList = NULL; + inst->historyBuffer = historyBuffer; + inst->historyBufferSize = historyBufferSize; + inst->historyStart = 0u; + inst->historyEnd = 0u; + inst->historyRead = 0u; + inst->historyReadUp = true; + inst->write = writeFct; + inst->prompt = prompt; + inst->echoEnabled = true; + inst->dirty = false; + inst->tabCounter = 0u; + inst->escapeCounter = 0u; + inst->mode = SHELLMATTA_MODE_INSERT; + + terminateInput(inst); + + return SHELLMATTA_OK; } - -void shellmatta_addCmd(shellmatta_instance_t *inst, shellmatta_cmd_t *cmd) +/** + * @brief adds a command to the command list alphabetically ordered + * @param[in] inst pointer to a shellmatta instance + * @param[in] cmd pointer to the command to add type #shellmatta_cmd_t + */ +shellmatta_retCode_t shellmatta_addCmd(shellmatta_instance_t *inst, shellmatta_cmd_t *cmd) { - shellmatta_cmd_t *tempCmd = inst->cmdList; + shellmatta_cmd_t *tempCmd = inst->cmdList; + shellmatta_cmd_t **prevCmd = &inst->cmdList; + bool cmdPlaced = false; + shellmatta_retCode_t ret = SHELLMATTA_OK; + int cmdDiff = 0; + int aliasDiff = 0; + /* register first command as list entry */ if (NULL == tempCmd) { inst->cmdList = cmd; cmd->next = NULL; } + /* append the new command sorted */ else { - while (tempCmd->next != NULL) + while ((false == cmdPlaced) && (SHELLMATTA_OK == ret)) { + cmdDiff = strcmp(tempCmd->cmd, cmd->cmd); + aliasDiff = strcmp(tempCmd->cmdAlias, cmd->cmdAlias); + /* check for a duplicate command */ + if((0u == cmdDiff) || (0u == aliasDiff)) + { + ret = SHELLMATTA_DUPLICATE; + } + else if(0 < cmdDiff) + { + cmd->next = tempCmd; + *prevCmd = cmd; + cmdPlaced = true; + } + else if(NULL == tempCmd->next) + { + tempCmd->next = cmd; + cmd->next = NULL; + cmdPlaced = true; + } + else + { + /* nothing to do */ + } + prevCmd = &tempCmd; tempCmd = tempCmd->next; } - tempCmd->next = cmd; - cmd->next = NULL; } + return ret; } @@ -92,51 +700,120 @@ void shellmatta_doTask(shellmatta_instance_t *inst, uint32_t time) } -void shellmatta_processData(shellmatta_instance_t *inst, char *data, - uint32_t size) +/** + * @brief processes the passed amount of data + * @param[in] inst pointer to a shellmatta instance + * @param[in] data pointer to input data to process + * @param[in] size length of input data to process + */ +void shellmatta_processData(shellmatta_instance_t *inst, + char *data, + uint32_t size) { - printf("%c", *data); - - if (0x0A == *data) + /* process byte wise */ + for (uint32_t i = 0u; i < size; i++) { - shellmatta_cmd_t *cmd = inst->cmdList; - uint8_t cmdExecuted = 0u; - inst->buffer[inst->bufferWritePointer] = 0u; - - while (NULL != cmd) + /* handle escape sequences */ + if(inst->escapeCounter != 0u) { - if (0 == strcmp(inst->buffer, cmd->cmd)) + handleEscapeSequence(inst, data); + } + /* handle return as start of processing the command */ + else if ('\r' == *data) + { + shellmatta_cmd_t *cmd = inst->cmdList; + uint8_t cmdExecuted = 0u; + inst->buffer[inst->inputCount] = 0u; + + /* store the current command and reset the history buffer */ + inst->dirty = true; + storeHistoryCmd(inst); + resetHistoryBuffer(inst); + + while (NULL != cmd) { - cmdExecuted = 1u; - char *blubb[10]; - blubb[0] = inst->buffer; - cmd->cmdFct(1, blubb); - cmd = NULL; + if ( (0 == strcmp(inst->buffer, cmd->cmd)) + || (0 == strcmp(inst->buffer, cmd->cmdAlias))) + { + inst->write("\n\r", 2u); + + cmdExecuted = 1u; + char *blubb[10]; + blubb[0] = inst->buffer; + cmd->cmdFct(1, blubb); + cmd = NULL; + } + else + { + cmd = cmd->next; + } } - else + + if ((cmdExecuted == 0u) && (inst->inputCount > 0)) { - cmd = cmd->next; + inst->buffer[inst->inputCount] = '\0'; + shellmatta_printf( inst, + "\n\rCommand: %s not found", + inst->buffer); } + terminateInput(inst); + } + /* tabulator key - auto complete */ + else if('\t' == *data) + { + inst->dirty = true; + doAutocomplete(inst); + } + /* cancel - terminate current input and print prompt again */ + else if(3 == *data) + { + inst->dirty = false; + resetHistoryBuffer(inst); + terminateInput(inst); + } + /* backspace */ + else if('\b' == *data) + { + inst->dirty = true; + removeChars(inst, 1u, true); + } + /* check for delete key */ + else if(0x7eu == *data) + { + inst->dirty = true; + removeChars(inst, 1u, false); + } + /* start of escape sequence */ + else if('\e' == *data) + { + inst->escapeCounter = 1u; + } + else + { + inst->dirty = true; + insertChars(inst, data, 1); } - if (cmdExecuted == 0u) + /* reset tab counter on not a tab */ + if ('\t' != *data) { - printf("failed to find command"); + inst->tabCounter = 0u; } - inst->bufferWritePointer = 0u; - } - else - { - inst->buffer[inst->bufferWritePointer] = *data; - inst->bufferWritePointer++; + data ++; } } void shellmatta_printf(shellmatta_instance_t *inst, const char *fmt, ...) { - /*TODO dummy implementation, shall be replaced by a generic output mechanism */ - printf(fmt); + char outputBuffer[1024u]; + va_list arg; + + va_start(arg, fmt); + int length = vsnprintf(outputBuffer, 1024, fmt, arg); + va_end(arg); + + inst->write(outputBuffer, length); } void shellmatta_getArg(uint32_t cnt, uint8_t *arg)