2022-02-25 04:13:05 +00:00
|
|
|
#include "lmem.h"
|
|
|
|
#include "scmd.h"
|
|
|
|
#include "sterm.h"
|
|
|
|
|
|
|
|
#define KEY_ESCAPE 0x001b
|
|
|
|
#define KEY_ENTER 0x000a
|
|
|
|
#define KEY_BACKSPACE 0x007f
|
|
|
|
#define KEY_UP 0x0105
|
|
|
|
#define KEY_DOWN 0x0106
|
|
|
|
#define KEY_LEFT 0x0107
|
|
|
|
#define KEY_RIGHT 0x0108
|
|
|
|
|
|
|
|
#define cursorForward(x) printf("\033[%dC", (x))
|
|
|
|
#define cursorBackward(x) printf("\033[%dD", (x))
|
|
|
|
#define clearLine() printf("\033[2K")
|
|
|
|
|
|
|
|
struct termios orig_termios;
|
|
|
|
char *cmd, *prompt = "$> ";
|
|
|
|
int cmdCount = 0, cmdCap = 4, cmdCursor = 0;
|
|
|
|
|
|
|
|
void shellT_conioTerm(void) {
|
|
|
|
struct termios new_termios;
|
|
|
|
|
|
|
|
/* take two copies - one for now, one for later */
|
|
|
|
tcgetattr(0, &orig_termios);
|
|
|
|
memcpy(&new_termios, &orig_termios, sizeof(new_termios));
|
|
|
|
|
|
|
|
/* register cleanup handler, and set the new terminal mode */
|
|
|
|
atexit(shellT_resetTerm);
|
|
|
|
new_termios.c_lflag &= ~(ICANON | ECHO);
|
|
|
|
tcsetattr(STDIN_FILENO, TCSANOW, &new_termios);
|
|
|
|
}
|
|
|
|
|
|
|
|
void shellT_resetTerm(void) {
|
|
|
|
tcsetattr(STDIN_FILENO, TCSANOW, &orig_termios);
|
|
|
|
}
|
|
|
|
|
|
|
|
void shellT_printf(const char *format, ...) {
|
|
|
|
va_list args;
|
|
|
|
|
|
|
|
va_start(args, format);
|
2022-03-03 16:28:43 +00:00
|
|
|
vprintf(format, args);
|
2022-02-25 04:13:05 +00:00
|
|
|
va_end(args);
|
2022-03-03 16:28:43 +00:00
|
|
|
|
2022-02-25 04:13:05 +00:00
|
|
|
fflush(stdout);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* waits for input for timeout. returns true if input is ready to be read, false if no events */
|
|
|
|
bool shellT_waitForInput(int timeout) {
|
|
|
|
struct timeval tv;
|
|
|
|
fd_set fds;
|
|
|
|
|
|
|
|
/* setup stdin file descriptor */
|
|
|
|
FD_ZERO(&fds);
|
|
|
|
FD_SET(STDIN_FILENO, &fds);
|
|
|
|
|
|
|
|
/* wait for read events on STDIN_FILENO for timeout period */
|
|
|
|
tv.tv_sec = timeout / 1000;
|
|
|
|
tv.tv_usec = (timeout % 1000) * 1000;
|
|
|
|
return select(1, &fds, NULL, NULL, &tv) > 0;
|
|
|
|
}
|
|
|
|
|
2022-03-02 16:38:16 +00:00
|
|
|
int shellT_readRawInput(uint8_t *buf, size_t max) {
|
|
|
|
return read(STDIN_FILENO, buf, max);
|
|
|
|
}
|
|
|
|
|
|
|
|
void shellT_writeRawOutput(uint8_t *buf, size_t sz) {
|
|
|
|
write(STDOUT_FILENO, buf, sz);
|
|
|
|
fflush(stdout);
|
|
|
|
}
|
|
|
|
|
2022-03-07 21:16:46 +00:00
|
|
|
void shellT_getTermSize(int *col, int *row) {
|
|
|
|
struct winsize ws;
|
|
|
|
ioctl(STDIN_FILENO, TIOCGWINSZ, &ws);
|
|
|
|
|
|
|
|
*col = ws.ws_col;
|
|
|
|
*row = ws.ws_row;
|
|
|
|
}
|
|
|
|
|
2022-02-25 04:13:05 +00:00
|
|
|
char shellT_getch(void) {
|
|
|
|
int r;
|
|
|
|
char in;
|
|
|
|
|
2022-03-02 16:38:16 +00:00
|
|
|
if ((r = shellT_readRawInput(&in, 1)) > 0) {
|
2022-02-25 04:13:05 +00:00
|
|
|
return in;
|
|
|
|
} else {
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int shellT_kbesc(void) {
|
|
|
|
int c;
|
|
|
|
|
|
|
|
/* if no event waiting, it's KEY_ESCAPE */
|
|
|
|
if (!shellT_waitForInput(0))
|
|
|
|
return KEY_ESCAPE;
|
|
|
|
|
|
|
|
if ((c = shellT_getch()) == '[') {
|
|
|
|
switch (shellT_getch()) {
|
|
|
|
case 'A': c = KEY_UP; break;
|
|
|
|
case 'B': c = KEY_DOWN; break;
|
|
|
|
case 'C': c = KEY_RIGHT; break;
|
|
|
|
case 'D': c = KEY_LEFT; break;
|
|
|
|
default: c = 0; break;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
c = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* unrecognized key? consume until there's no event */
|
|
|
|
if (c == 0) {
|
|
|
|
while (shellT_waitForInput(0)) shellT_getch();
|
|
|
|
}
|
|
|
|
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
|
|
|
|
int shellT_kbget(void) {
|
|
|
|
char c = shellT_getch();
|
|
|
|
return (c == KEY_ESCAPE) ? shellT_kbesc() : c;
|
|
|
|
}
|
|
|
|
|
|
|
|
void shellT_printPrompt(void) {
|
|
|
|
clearLine();
|
|
|
|
shellT_printf("\r%s%.*s", prompt, cmdCount, (cmd ? cmd : ""));
|
|
|
|
if (cmdCount > cmdCursor)
|
|
|
|
cursorBackward(cmdCount-cmdCursor);
|
|
|
|
fflush(stdout);
|
|
|
|
}
|
|
|
|
|
|
|
|
void shellT_setPrompt(char *_prompt) {
|
|
|
|
prompt = _prompt;
|
|
|
|
}
|
|
|
|
|
|
|
|
void shellT_addChar(tShell_client *client, int c) {
|
|
|
|
int i;
|
|
|
|
|
|
|
|
switch (c) {
|
|
|
|
case KEY_BACKSPACE:
|
|
|
|
if (cmdCursor > 0) {
|
|
|
|
laikaM_rmvarray(cmd, cmdCount, (cmdCursor-1), 1);
|
|
|
|
cmdCursor--;
|
|
|
|
shellT_printPrompt();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case KEY_LEFT:
|
|
|
|
if (cmdCursor > 0) {
|
|
|
|
cursorBackward(1);
|
|
|
|
--cmdCursor;
|
|
|
|
fflush(stdout);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case KEY_RIGHT:
|
|
|
|
if (cmdCursor < cmdCount) {
|
|
|
|
cursorForward(1);
|
|
|
|
cmdCursor++;
|
|
|
|
fflush(stdout);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case KEY_ENTER:
|
|
|
|
if (cmdCount > 0) {
|
|
|
|
cmd[cmdCount] = '\0';
|
|
|
|
cmdCount = 0;
|
|
|
|
cmdCursor = 0;
|
|
|
|
shellS_runCmd(client, cmd);
|
|
|
|
shellT_printPrompt();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case KEY_UP: case KEY_DOWN: break; /* ignore these */
|
|
|
|
default:
|
|
|
|
laikaM_growarray(char, cmd, 1, cmdCount, cmdCap);
|
|
|
|
laikaM_insertarray(cmd, cmdCount, cmdCursor, 1);
|
|
|
|
cmd[cmdCursor++] = c;
|
|
|
|
shellT_printPrompt();
|
|
|
|
}
|
|
|
|
}
|