332 lines
5.6 KiB
C
332 lines
5.6 KiB
C
#include "CLI.h"
|
|
|
|
#include <stddef.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <limits.h>
|
|
|
|
// #include <config.h>
|
|
#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"); // "<left arrow><space><left arrow>"
|
|
}
|
|
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;
|
|
}
|