#include "CLI.h" #include #include #include #include void CLI_charOut_save(CLI_t* cli, char ch) { if (cli->CLI_charOut != NULL) { // create string of size one to be compatable with string print function char c[2] = {ch, 0}; (*(cli->CLI_charOut))(&c[0]); } } void CLI_stringOut(CLI_t* cli, char* str) { for (; *str != 0; str++) { CLI_charOut_save(cli, *str); } } // initilize and register the lineout print function CLI_t CLI_init(CLI_charOutFn lineOut, CMDList_t* cmdList) { CLI_t cli; cli.CLI_charOut = lineOut; cli.CMDList = cmdList; cli.CLI_State = CLI_State_Default; cli.FIFO = FIFOBuffChar_create(); #ifdef HISTORY cli.History = History_init(); #endif if (cli.CLI_charOut != NULL) { CLI_stringOut(&cli, (char*)"> "); } return cli; } bool CLI_deinit(CLI_t* cli) { cli->CLI_charOut = NULL; cli->CMDList = NULL; FIFOBuffChar_delete(cli->FIFO); #ifdef HISTORY History_deinit(cli->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(CLI_t* cli) { char** historyList; int ret = History_getFullHistory(cli->History, &historyList); int i; char str[150]; if (ret >= 0) { for (i=0; *(historyList + i) != NULL; i++) { snprintf(&str[0], 150, "%03i: %s\n", i, *(historyList + i)); CLI_stringOut(cli, &str[0]); } } else { snprintf(&str[0], 150, "ERROR: get history returnd: %i\n", ret); CLI_stringOut(cli, &str[0]); } free(historyList); } void historyPrevius(CLI_t* cli) { char* line; int i; if ( (History_getCurrPos(cli->History) == History_getSize(cli->History)) && (FIFOBuffChar_getSize(cli->FIFO) > 0) ) { // add current text to end of history line = fifoToString(cli->FIFO); History_put(cli->History, line); for (i=0; *(line + i) != '\0'; i++) { CLI_stringOut(cli, (char*)"\x1b[D \x1b[D"); } History_getPrev(cli->History, &line); } // empty current line while (FIFOBuffChar_getSize(cli->FIFO) > 0) { CLI_stringOut(cli, (char*)"\x1b[D \x1b[D"); FIFOBuffChar_pop(cli->FIFO); } // get previus command int ret = History_getPrev(cli->History, &line); // write line if ((ret >= 0) && (line != NULL)) { int i; for (i=0; *(line + i) != '\0'; i++) { CLI_charIn(cli, *(line + i)); } } } void historyNext(CLI_t* cli) { char* line; // empty current line while (FIFOBuffChar_getSize(cli->FIFO) > 0) { CLI_stringOut(cli, (char*)"\x1b[D \x1b[D"); FIFOBuffChar_pop(cli->FIFO); } // get next command int ret = History_getNext(cli->History, &line); // write line if ((ret >= 0) && (line != NULL)) { int i; for (i=0; *(line + i) != '\0'; i++) { CLI_charIn(cli, *(line + i)); } } } #endif int tryExecute(CLI_t* cli, FIFOBuffChar_t* fifo) { int ret = 0; CMD_t* cmd = NULL; char* line = fifoToString(fifo); if (*line == '\0') { // empty line ret = 1; CLI_stringOut(cli, (char*)"> "); } else { cmd = CMDList_get(cli->CMDList, line); } if (cmd != NULL) { #ifdef HISTORY History_put(cli->History, line); #endif int ret = (*(cmd->fn))(line, cli); if (ret != INT_MIN) { CLI_stringOut(cli, (char*)"> "); } ret = 0; } else if (ret == 0) { char err[100]; sprintf(&err[0], "command not found: %s\n> ", line); CLI_stringOut(cli, &err[0]); ret = -1; #ifdef HISTORY free(line); #endif } #ifndef HISTORY free(line); #endif return ret; } // to recive a single caracter bool CLI_charIn(CLI_t* cli, char c) { bool ok = true; char str[100]; char C = c; if ((C >= 'a') && (C <= 'z')) { C &= (~0x20); // convert to uppercase } switch (cli->CLI_State) { case CLI_State_Default: if ((C >= ' ') && (C <= '~')) // see ascii table { FIFOBuffChar_put(cli->FIFO, C); // save char in buffer CLI_charOut_save(cli, c); } else { switch (c) { case '\n': case '\r': // echo to terminal CLI_charOut_save(cli, c); // copy buffer and create new buffer FIFOBuffChar_t* fifo = cli->FIFO; cli->FIFO = FIFOBuffChar_create(); // execute command if valid ok = (tryExecute(cli, fifo) == 0); // delete old buffer FIFOBuffChar_delete(fifo); break; case 8: case 127: // delete (backspace) if (FIFOBuffChar_pop(cli->FIFO)) { // pop something of the buffer CLI_stringOut(cli, (char*)"\x1b[D \x1b[D"); // "" } break; case 27: // escape (start for arrow keys) cli->CLI_State = CLI_State_Esc; break; default: sprintf(&str[0], "\ninvlid char: '%c' - (%i)\n", c, c); CLI_stringOut(cli, &str[0]); break; } } break; case CLI_State_Esc: if (c == '[') { cli->CLI_State = CLI_State_ANSIVT100; } else { cli->CLI_State = CLI_State_Default; } break; case CLI_State_ANSIVT100: switch (c) { #ifdef HISTORY case 'A': // arrow up cli->CLI_State = CLI_State_Default; historyPrevius(cli); break; case 'B': // arrow down cli->CLI_State = CLI_State_Default; historyNext(cli); break; case 'C': // arrow right CLI_stringOut(cli, (char*)"(key: arrow right)"); cli->CLI_State = CLI_State_Default; break; case 'D': // arrow left CLI_stringOut(cli, (char*)"(key: arrow left)"); cli->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->CLI_State = CLI_State_Default; } } break; } return ok; }