#include "CLI.h" #include #include #include #include // #include #define HISTORY #include "../FIFOBuff/FIFOBuffChar.h" #ifdef HISTORY #include "../History/history.h" #endif CLI_charOutFn CLI_charOut; CMDList_t* CMDList; FIFOBuffChar_t* FIFO; enum { CLI_State_Default, CLI_State_Esc, CLI_State_ANSIVT100 } CLI_State = CLI_State_Default; #ifdef HISTORY History_t* History; #endif void CLI_charOut_save(char ch) { if (CLI_charOut != NULL) { // create string of size one to be compatable with string print function char c[2] = {ch, 0}; (*CLI_charOut)(&c[0]); } } void CLI_stringOut(char* str) { for (; *str != 0; str++) { CLI_charOut_save(*str); } } // initilize and register the lineout print function bool CLI_init(CLI_charOutFn lineOut, CMDList_t* cmdList) { CLI_charOut = lineOut; CMDList = cmdList; FIFO = FIFOBuffChar_create(); #ifdef HISTORY History = History_init(); #endif if (CLI_charOut != NULL) { CLI_stringOut((char*)"> "); } return true; } bool CLI_deinit() { CLI_charOut = NULL; CMDList = NULL; FIFOBuffChar_delete(FIFO); #ifdef HISTORY History_deinit(History, true); #endif return true; } char* fifoToString(FIFOBuffChar_t* fifo) { char* out = malloc(fifo->size + 1); char* write_p = out; int i; for (i = fifo->size; i > 0; i--) { FIFOBuffChar_get(fifo, write_p); write_p++; } *write_p = 0; return out; } #ifdef HISTORY void CLI_PrintHistory() { char** historyList; int ret = History_getFullHistory(History, &historyList); int i; if (ret >= 0) { for (i=0; *(historyList + i) != NULL; i++) { printf("%03i: %s\n", i, *(historyList + i)); } } else { printf("ERROR: get history returnd: %i\n", ret); } free(historyList); } void historyPrevius() { char* line; int i; if ( (History_getCurrPos(History) == History_getSize(History)) && (FIFOBuffChar_getSize(FIFO) > 0) ) { // add current text to end of history line = fifoToString(FIFO); History_put(History, line); for (i=0; *(line + i) != '\0'; i++) { CLI_stringOut((char*)"\x1b[D \x1b[D"); } History_getPrev(History, &line); } // empty current line while (FIFOBuffChar_getSize(FIFO) > 0) { CLI_stringOut((char*)"\x1b[D \x1b[D"); FIFOBuffChar_pop(FIFO); } // get previus command int ret = History_getPrev(History, &line); // write line if ((ret >= 0) && (line != NULL)) { for (i=0; *(line + i) != '\0'; i++) { CLI_charIn(*(line + i)); } } } void historyNext() { char* line; // empty current line while (FIFOBuffChar_getSize(FIFO) > 0) { CLI_stringOut((char*)"\x1b[D \x1b[D"); FIFOBuffChar_pop(FIFO); } // get next command int ret = History_getNext(History, &line); // write line if ((ret >= 0) && (line != NULL)) { int i; for (i=0; *(line + i) != '\0'; i++) { CLI_charIn(*(line + i)); } } } #endif int tryExecute(FIFOBuffChar_t* fifo) { int ret = 0; CMD_t* cmd = NULL; char* line = fifoToString(fifo); if (*line == '\0') { // empty line ret = 1; CLI_stringOut((char*)"> "); } else { cmd = CMDList_get(CMDList, line); } if (cmd != NULL) { #ifdef HISTORY History_put(History, line); #endif int ret = (*(cmd->fn))(line); if (ret != INT_MIN) { CLI_stringOut((char*)"> "); } ret = 0; } else if (ret == 0) { if (CLI_charOut != NULL) { char err[100]; sprintf(&err[0], "command not found: %s\n> ", line); CLI_stringOut(&err[0]); } ret = -1; #ifdef HISTORY free(line); #endif } #ifndef HISTORY free(line); #endif return ret; } // to recive a single caracter bool CLI_charIn(char c) { bool ok = true; char str[100]; char C = c; if ((C >= 'a') && (C <= 'z')) { C &= (~0x20); // convert to uppercase } switch (CLI_State) { case CLI_State_Default: if ( //TODO: update list of accepted characters ((C >= 'A') && (C <= 'Z')) || ((c >= '0') && (c <= '9')) || (c == ' ') || (c == '-') || (c == '_') ) { FIFOBuffChar_put(FIFO, C); // save char in buffer CLI_charOut_save(c); } else { switch (c) { case '\n': case '\r': if (CLI_charOut != NULL) { // echo to terminal char ch[2] = {c, 0}; (*CLI_charOut)(&ch[0]); } FIFOBuffChar_t* fifo = FIFO; FIFO = FIFOBuffChar_create(); ok = (tryExecute(fifo) == 0); FIFOBuffChar_delete(fifo); break; case 8: case 127: // backspace if (FIFOBuffChar_pop(FIFO)) { // pop something of the buffer CLI_stringOut((char*)"\x1b[D \x1b[D"); // "" } break; case 27: // escape (start for arrow keys) CLI_State = CLI_State_Esc; break; default: sprintf(&str[0], "\ninvlid char: '%c' - (%i)\n", c, c); CLI_stringOut(&str[0]); break; } } break; case CLI_State_Esc: if (c == '[') { CLI_State = CLI_State_ANSIVT100; } else { CLI_State = CLI_State_Default; } break; case CLI_State_ANSIVT100: switch (c) { #ifdef HISTORY case 'A': // arrow up CLI_State = CLI_State_Default; historyPrevius(); break; case 'B': // arrow down CLI_State = CLI_State_Default; historyNext(); break; case 'C': // arrow right CLI_stringOut((char*)"(key: arrow right)"); CLI_State = CLI_State_Default; break; case 'D': // arrow left CLI_stringOut((char*)"(key: arrow left)"); CLI_State = CLI_State_Default; break; #endif default: // only to back on on alpha char. seems to be the with all '\x1d[' commands if ((C >= 'A') && (C <= 'Z')) { CLI_State = CLI_State_Default; } } break; } return ok; }