|
|
@ -8,14 +8,6 @@ |
|
|
|
#include "cmd.h" |
|
|
|
#include "config.h" |
|
|
|
|
|
|
|
struct cmd_handler { |
|
|
|
char buffer[TARGET_CMD_BUFSIZE + 2]; |
|
|
|
int recved; |
|
|
|
void *priv; |
|
|
|
void (*putstring)(struct cmd_handler *, const char *s, int len); |
|
|
|
int (*getchar)(struct cmd_handler *); |
|
|
|
}; |
|
|
|
|
|
|
|
enum KEY_ACTION { |
|
|
|
KEY_NULL = 0, /* NULL */ |
|
|
|
CTRL_A = 1, /* Ctrl+a */ |
|
|
@ -38,68 +30,80 @@ enum KEY_ACTION { |
|
|
|
BACKSPACE = 127 /* Backspace */ |
|
|
|
}; |
|
|
|
|
|
|
|
struct terminal { |
|
|
|
char buf[TARGET_CMD_BUFSIZE]; /* edited line buffer */ |
|
|
|
int buflen; /* edited line buffer size */ |
|
|
|
int len; /* current edited line length */ |
|
|
|
const char *prompt; /* prompt to display */ |
|
|
|
uint16_t plen; /* prompt length */ |
|
|
|
uint16_t pos; /* current cursor poistion */ |
|
|
|
uint16_t oldpos; /* previouse refresh cursor position */ |
|
|
|
uint16_t cols; /* number of columns in terminal */ |
|
|
|
int16_t hindex; /* the history index we are currently editing */ |
|
|
|
}; |
|
|
|
|
|
|
|
static struct terminal G; |
|
|
|
static char *history[TARGET_CMD_HISTORY]; |
|
|
|
static int history_len = 0; |
|
|
|
|
|
|
|
#if defined(__CC_ARM) |
|
|
|
extern struct cmd_tbl_s Image$$CMDLINE$$Base, Image$$CMDLINE$$Limit; |
|
|
|
#else |
|
|
|
extern struct cmd_tbl_s __cmdline_cmd_start, __cmdline_cmd_end; |
|
|
|
#endif |
|
|
|
|
|
|
|
static struct cmd_handler _G; |
|
|
|
|
|
|
|
#define G_BUF (_G.buffer) |
|
|
|
#define G_N (_G.recved) |
|
|
|
#define G_GETCH() _G.getchar(&_G) |
|
|
|
|
|
|
|
#ifdef __CC_ARM /* for keil */ |
|
|
|
static void do_puts(struct cmd_handler *hc, const char *s, int len) |
|
|
|
static int tputs(const char *s, int len) |
|
|
|
{ |
|
|
|
if (len < 0) { |
|
|
|
len = strlen(s); |
|
|
|
} |
|
|
|
fwrite(s, len, 1, stdout); |
|
|
|
fflush(stdout); |
|
|
|
} |
|
|
|
static int do_getch(struct cmd_handler *hc) |
|
|
|
{ |
|
|
|
return fgetc(stdin); |
|
|
|
} |
|
|
|
#else |
|
|
|
static void do_puts(struct cmd_handler *hc, const char *s, int len) |
|
|
|
|
|
|
|
static int tgets(char *buf, int len, int blocking /* in millis */) |
|
|
|
{ |
|
|
|
char *buf_save = buf; |
|
|
|
int n; |
|
|
|
|
|
|
|
if (len < 0) { |
|
|
|
len = strlen(s); |
|
|
|
if (blocking <= 0) { |
|
|
|
return fread(buf, 1, n, stdin); |
|
|
|
} |
|
|
|
|
|
|
|
while (len > 0) { |
|
|
|
n = write(STDOUT_FILENO, s, len); |
|
|
|
n = fread(buf, 1, n, stdin); |
|
|
|
if (n > 0) { |
|
|
|
buf += n; |
|
|
|
len -= n; |
|
|
|
s += n; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return (buf - buf_save); |
|
|
|
} |
|
|
|
#else |
|
|
|
static int tputs(const char *s, int len) |
|
|
|
{ |
|
|
|
write(STDOUT_FILENO, s, len); |
|
|
|
return (len); |
|
|
|
} |
|
|
|
|
|
|
|
static int do_getch(struct cmd_handler *hc) |
|
|
|
static int tgets(char *buf, int len, int blocking /* in millis */) |
|
|
|
{ |
|
|
|
char c = 0; |
|
|
|
char *buf_save = buf; |
|
|
|
int n; |
|
|
|
|
|
|
|
if (read(STDIN_FILENO, &c, 1) == 1) { |
|
|
|
return (c); |
|
|
|
if (blocking <= 0) { |
|
|
|
return read(STDIN_FILENO, buf, len); |
|
|
|
} |
|
|
|
return -1; |
|
|
|
} |
|
|
|
#endif |
|
|
|
|
|
|
|
static void do_writen(const char *s, int len) |
|
|
|
{ |
|
|
|
_G.putstring(&_G, s, len); |
|
|
|
} |
|
|
|
while (len > 0) { |
|
|
|
n = read(STDIN_FILENO, buf, len); |
|
|
|
if (n > 0) { |
|
|
|
buf += n; |
|
|
|
len -= n; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
static void do_printf(const char *s) |
|
|
|
{ |
|
|
|
do_writen(s, -1); |
|
|
|
return (buf - buf_save); |
|
|
|
} |
|
|
|
#endif |
|
|
|
|
|
|
|
static int do_help(cmd_tbl_t s, int argc, char *argv[]) |
|
|
|
{ |
|
|
@ -108,34 +112,20 @@ static int do_help(cmd_tbl_t s, int argc, char *argv[]) |
|
|
|
#else |
|
|
|
cmd_tbl_t it = &__cmdline_cmd_start; |
|
|
|
#endif |
|
|
|
do_printf("support commands:\r\n\r\n"); |
|
|
|
printf("support commands:\r\n"); |
|
|
|
#if defined(__CC_ARM) |
|
|
|
while (it < &Image$$CMDLINE$$Limit) { |
|
|
|
#else |
|
|
|
while (it < &__cmdline_cmd_end) { |
|
|
|
while (it < &__cmdline_cmd_end) { |
|
|
|
#endif |
|
|
|
do_printf(it->name); |
|
|
|
do_printf("\t"); |
|
|
|
do_printf(it->help); |
|
|
|
do_printf("\r\n"); |
|
|
|
++it; |
|
|
|
} |
|
|
|
return 0; |
|
|
|
printf("%s\t%s\r\n", it->name, it->help); |
|
|
|
++it; |
|
|
|
} |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
CON_CMD(help, "commands help", NULL, do_help) |
|
|
|
|
|
|
|
int cmd_init() |
|
|
|
{ |
|
|
|
G_N = 0 ; |
|
|
|
_G.putstring = do_puts; |
|
|
|
_G.getchar = do_getch; |
|
|
|
setvbuf(stdout, NULL, _IONBF, 0); |
|
|
|
setvbuf(stderr, NULL, _IONBF, 0); |
|
|
|
|
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
static int parse_line(char *cmd, int len, char *argv[], int _maxargs) |
|
|
|
{ |
|
|
|
int argc; |
|
|
@ -183,16 +173,16 @@ static int parse_line(char *cmd, int len, char *argv[], int _maxargs) |
|
|
|
|
|
|
|
int cmd_process(char *line) |
|
|
|
{ |
|
|
|
int i, argc, namelen; |
|
|
|
int size = strlen(line); |
|
|
|
char *argv[TARGET_CMD_MAXARGS + 1]; |
|
|
|
|
|
|
|
#if defined(__CC_ARM) |
|
|
|
cmd_tbl_t it = &Image$$CMDLINE$$Base; |
|
|
|
#else |
|
|
|
cmd_tbl_t it = &__cmdline_cmd_start; |
|
|
|
#endif |
|
|
|
|
|
|
|
int i, argc, namelen; |
|
|
|
int size = strlen(line); |
|
|
|
char *argv[TARGET_CMD_MAXARGS + 1]; |
|
|
|
|
|
|
|
/* split line */ |
|
|
|
for (i = 0; i < TARGET_CMD_MAXARGS + 1; ++i) { |
|
|
|
argv[i] = NULL; |
|
|
@ -226,59 +216,433 @@ recovery: |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
void cmd_loop() |
|
|
|
/*
|
|
|
|
* Use the ESC [6n escape sequence to query the horizontal cursor position |
|
|
|
* and return it. On error -1 is returned, on success the position of the |
|
|
|
* cursor. |
|
|
|
*/ |
|
|
|
static int get_cursor_position() |
|
|
|
{ |
|
|
|
int c; |
|
|
|
char buf[32]; |
|
|
|
int cols, rows; |
|
|
|
unsigned int i = 0; |
|
|
|
|
|
|
|
/* Report cursor location */ |
|
|
|
if (tputs("\x1b[6n", 4) != 4) return -1; |
|
|
|
|
|
|
|
/* Read the response: ESC [ rows ; cols R */ |
|
|
|
while (i < sizeof(buf)-1) { |
|
|
|
if (tgets(buf + i, 1, 1000) != 1) break; |
|
|
|
if (buf[i] == 'R') break; |
|
|
|
i++; |
|
|
|
} |
|
|
|
buf[i] = '\0'; |
|
|
|
|
|
|
|
do { |
|
|
|
c = G_GETCH(); |
|
|
|
if (c <= 0) |
|
|
|
break; |
|
|
|
if (G_N >= TARGET_CMD_BUFSIZE) { |
|
|
|
do_printf("too long\r\n"); |
|
|
|
G_N = 0; |
|
|
|
do_writen("\r\n> ", 4); |
|
|
|
} |
|
|
|
/* Parse it. */ |
|
|
|
if (buf[0] != ESC || buf[1] != '[') return -1; |
|
|
|
if (sscanf(buf+2,"%d;%d",&rows,&cols) != 2) return -1; |
|
|
|
return cols; |
|
|
|
} |
|
|
|
|
|
|
|
switch (c) { |
|
|
|
case CTRL_C: |
|
|
|
G_N = 0; |
|
|
|
do_writen("\r\n> ", 4); |
|
|
|
return; |
|
|
|
case BACKSPACE: |
|
|
|
case CTRL_H: |
|
|
|
if (G_N > 0) { |
|
|
|
do_writen("\b \b", 3); |
|
|
|
G_N--; |
|
|
|
G_BUF[G_N] = '\0'; |
|
|
|
} |
|
|
|
return; |
|
|
|
case CTRL_L: |
|
|
|
do_writen("\x1b[H\x1b[2J",7); |
|
|
|
do_writen("> ", 2); |
|
|
|
if (G_N > 0) |
|
|
|
do_writen(G_BUF, G_N); |
|
|
|
return; |
|
|
|
|
|
|
|
/*
|
|
|
|
* Single line low level line refresh. |
|
|
|
* |
|
|
|
* Rewrite the currently edited line accordingly to the buffer content, |
|
|
|
* cursor position, and number of columns of the terminal. |
|
|
|
*/ |
|
|
|
static void refresh_line() |
|
|
|
{ |
|
|
|
char seq[64]; |
|
|
|
size_t plen = G.plen; |
|
|
|
char *buf = G.buf; |
|
|
|
size_t len = G.len; |
|
|
|
size_t pos = G.pos; |
|
|
|
|
|
|
|
while((plen + pos) >= G.cols) { |
|
|
|
buf++; |
|
|
|
len--; |
|
|
|
pos--; |
|
|
|
} |
|
|
|
|
|
|
|
while (plen+len > G.cols) { |
|
|
|
len--; |
|
|
|
} |
|
|
|
|
|
|
|
/* Cursor to left edge */ |
|
|
|
tputs("\r", 1); |
|
|
|
tputs(G.prompt, G.plen); |
|
|
|
tputs(buf, len); |
|
|
|
|
|
|
|
/* Erase to right */ |
|
|
|
tputs("\x1b[0K", 4); |
|
|
|
|
|
|
|
/* Move cursor to original position. */ |
|
|
|
snprintf(seq,64,"\r\x1b[%dC", (int)(pos+plen)); |
|
|
|
tputs(seq, strlen(seq)); |
|
|
|
} |
|
|
|
|
|
|
|
/*
|
|
|
|
* Try to get the number of columns in the current terminal, or assume 80 |
|
|
|
* if it fails. |
|
|
|
*/ |
|
|
|
static int get_columns() |
|
|
|
{ |
|
|
|
char seq[32]; |
|
|
|
int start, cols; |
|
|
|
|
|
|
|
/* Get the initial position so we can restore it later. */ |
|
|
|
start = get_cursor_position(); |
|
|
|
if (start == -1) goto failed; |
|
|
|
|
|
|
|
/* Go to right margin and get position. */ |
|
|
|
if (tputs("\x1b[999C", 6) != 6) goto failed; |
|
|
|
cols = get_cursor_position(); |
|
|
|
if (cols == -1) goto failed; |
|
|
|
|
|
|
|
/* Restore position. */ |
|
|
|
if (cols > start) { |
|
|
|
snprintf(seq,32,"\x1b[%dD",cols-start); |
|
|
|
if (tputs(seq, strlen(seq)) == -1) { |
|
|
|
/* Can't recover... */ |
|
|
|
} |
|
|
|
} |
|
|
|
return cols; |
|
|
|
failed: |
|
|
|
return 80; |
|
|
|
} |
|
|
|
|
|
|
|
/*
|
|
|
|
* Delete the character at the right of the cursor without altering the cursor |
|
|
|
* position. Basically this is what happens with the "Delete" keyboard key. |
|
|
|
*/ |
|
|
|
static void edit_delete() |
|
|
|
{ |
|
|
|
if (G.len > 0 && G.pos < G.len) { |
|
|
|
memmove(G.buf + G.pos, G.buf + G.pos + 1, G.len - G.pos - 1); |
|
|
|
G.len--; |
|
|
|
G.buf[G.len] = '\0'; |
|
|
|
refresh_line(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/* Backspace implementation. */ |
|
|
|
static void edit_backspace() |
|
|
|
{ |
|
|
|
if (G.pos > 0 && G.len > 0) { |
|
|
|
memmove(G.buf + G.pos - 1, G.buf + G.pos, G.len - G.pos); |
|
|
|
G.pos--; |
|
|
|
G.len--; |
|
|
|
G.buf[G.len] = '\0'; |
|
|
|
refresh_line(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/* end of line */ |
|
|
|
if (c == '\r' || c == '\n') { |
|
|
|
do_writen("\r\n", 2); |
|
|
|
if (G_N > 0) { |
|
|
|
G_BUF[G_N] = '\0'; |
|
|
|
cmd_process(G_BUF); |
|
|
|
do_writen("\r\n", 2); |
|
|
|
G_N = 0; |
|
|
|
/*
|
|
|
|
* Delete the previosu word, maintaining the cursor at the start of the |
|
|
|
* current word. |
|
|
|
*/ |
|
|
|
static void edit_delete_prev() |
|
|
|
{ |
|
|
|
size_t old_pos = G.pos; |
|
|
|
size_t diff; |
|
|
|
|
|
|
|
while (G.pos > 0 && G.buf[G.pos - 1] == ' ') |
|
|
|
G.pos--; |
|
|
|
while (G.pos > 0 && G.buf[G.pos - 1] != ' ') |
|
|
|
G.pos--; |
|
|
|
diff = old_pos - G.pos; |
|
|
|
memmove(G.buf + G.pos, G.buf + old_pos, G.len - old_pos + 1); |
|
|
|
G.len -= diff; |
|
|
|
refresh_line(); |
|
|
|
} |
|
|
|
|
|
|
|
/*
|
|
|
|
* Insert the character 'c' at cursor current position. |
|
|
|
* |
|
|
|
* On error writing to the terminal -1 is returned, otherwise 0. |
|
|
|
*/ |
|
|
|
static void edit_insert(char c) |
|
|
|
{ |
|
|
|
if (G.len < G.buflen) { |
|
|
|
if (G.len == G.pos) { |
|
|
|
G.buf[G.pos] = c; |
|
|
|
G.pos++; |
|
|
|
G.len++; |
|
|
|
G.buf[G.len] = '\0'; |
|
|
|
if (G.plen + G.len < G.cols) { |
|
|
|
/* Avoid a full update of the line in the
|
|
|
|
* trivial case. */ |
|
|
|
tputs(&c, 1); |
|
|
|
} |
|
|
|
do_writen("> ", 2); |
|
|
|
continue; |
|
|
|
} else { |
|
|
|
memmove(G.buf + G.pos + 1, G.buf + G.pos, G.len - G.pos); |
|
|
|
G.buf[G.pos] = c; |
|
|
|
G.len++; |
|
|
|
G.pos++; |
|
|
|
G.buf[G.len] = '\0'; |
|
|
|
refresh_line(); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
static void move_right() |
|
|
|
{ |
|
|
|
if (G.pos != G.len) { |
|
|
|
++G.pos; |
|
|
|
refresh_line(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (isprint(c)) { |
|
|
|
G_BUF[G_N] = c; |
|
|
|
G_N++; |
|
|
|
do_writen((char *)&c, 1); |
|
|
|
static void move_left() |
|
|
|
{ |
|
|
|
if (G.pos > 0) { |
|
|
|
G.pos--; |
|
|
|
refresh_line(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
static void move_home() |
|
|
|
{ |
|
|
|
if (G.pos != 0) { |
|
|
|
G.pos = 0; |
|
|
|
refresh_line(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
static void move_end() |
|
|
|
{ |
|
|
|
if (G.pos != G.len) { |
|
|
|
G.pos = G.len; |
|
|
|
refresh_line(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
static int history_add(const char *line) |
|
|
|
{ |
|
|
|
char *copy; |
|
|
|
|
|
|
|
if (history_len && !strcmp(history[history_len - 1], line)) |
|
|
|
return 0; |
|
|
|
copy = strdup(line); |
|
|
|
if (!copy) |
|
|
|
return 0; |
|
|
|
if (history_len == TARGET_CMD_HISTORY) { |
|
|
|
free(history[0]); |
|
|
|
memmove(history, history + 1, sizeof (char *) * (history_len - 1)); |
|
|
|
--history_len; |
|
|
|
} |
|
|
|
history[history_len++] = copy; |
|
|
|
return 1; |
|
|
|
} |
|
|
|
|
|
|
|
/*
|
|
|
|
* Substitute the currently edited line with the next or previous history |
|
|
|
* entry as specified by 'dir' |
|
|
|
*/ |
|
|
|
static void edit_history(int dir) |
|
|
|
{ |
|
|
|
if (history_len > 0) { |
|
|
|
G.hindex += dir; |
|
|
|
if (G.hindex < 0) { |
|
|
|
G.hindex = history_len - 1; |
|
|
|
} else if (G.hindex >= history_len) { |
|
|
|
G.hindex = 0; |
|
|
|
} |
|
|
|
} while (1) ; |
|
|
|
strncpy(G.buf, history[G.hindex], G.buflen); |
|
|
|
G.buf[G.buflen - 1] = '\0'; |
|
|
|
G.len = G.pos = strlen(G.buf); |
|
|
|
refresh_line(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
static void history_prev() |
|
|
|
{ |
|
|
|
edit_history(-1); |
|
|
|
} |
|
|
|
|
|
|
|
static void history_next() |
|
|
|
{ |
|
|
|
edit_history(1); |
|
|
|
} |
|
|
|
|
|
|
|
static void reset_linestate() |
|
|
|
{ |
|
|
|
G.cols = get_columns(); |
|
|
|
G.oldpos = 0; |
|
|
|
G.pos = 0; |
|
|
|
G.len = 0; |
|
|
|
G.hindex = history_len; |
|
|
|
|
|
|
|
tputs(G.prompt, G.plen); |
|
|
|
} |
|
|
|
|
|
|
|
static int do_clear(cmd_tbl_t s, int argc, char *argv[]) |
|
|
|
{ |
|
|
|
tputs("\x1b[H\x1b[2J",7); |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
CON_CMD(clear, "clear the screen", NULL, do_clear); |
|
|
|
|
|
|
|
int cmd_init(const char *prompt) |
|
|
|
{ |
|
|
|
#if defined(__CC_ARM) |
|
|
|
setvbuf(stdin, NULL, _IONBF, 0); |
|
|
|
setvbuf(stdout, NULL, _IONBF, 0); |
|
|
|
setvbuf(stderr, NULL, _IONBF, 0); |
|
|
|
#endif |
|
|
|
|
|
|
|
G.buflen = TARGET_CMD_BUFSIZE; |
|
|
|
G.prompt = prompt; |
|
|
|
G.plen = strlen(G.prompt); |
|
|
|
|
|
|
|
G.buf[0] = '\0'; |
|
|
|
G.buflen--; /* make sure there is always space hold `NUL' */ |
|
|
|
|
|
|
|
reset_linestate(); |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
void cmd_loop() |
|
|
|
{ |
|
|
|
char c; |
|
|
|
int nread; |
|
|
|
char seq[3]; |
|
|
|
|
|
|
|
nread = tgets(&c, 1, -1); |
|
|
|
if (nread <= 0) |
|
|
|
return; |
|
|
|
|
|
|
|
/* if c == TAB, do completion? */ |
|
|
|
|
|
|
|
switch (c) { |
|
|
|
case ENTER: |
|
|
|
case '\n': |
|
|
|
tputs("\r\n", 2); |
|
|
|
if (G.len > 0) { |
|
|
|
G.buf[G.len] = '\0'; |
|
|
|
history_add(G.buf); |
|
|
|
cmd_process(G.buf); |
|
|
|
} |
|
|
|
reset_linestate(); |
|
|
|
break; |
|
|
|
case CTRL_C: /* ctrl-c */ |
|
|
|
reset_linestate(); |
|
|
|
break; |
|
|
|
case BACKSPACE: /* backspace */ |
|
|
|
case CTRL_H: |
|
|
|
edit_backspace(); |
|
|
|
break; |
|
|
|
case CTRL_D: /* ctrl-d, remove the right of cursor. */ |
|
|
|
if (G.len > 0) { |
|
|
|
edit_delete(); |
|
|
|
} else { |
|
|
|
reset_linestate(); |
|
|
|
} |
|
|
|
break; |
|
|
|
case CTRL_T: /* ctrl-t, swaps current char with previous */ |
|
|
|
if (G.pos > 0 && G.pos < G.len) { |
|
|
|
int aux = G.buf[G.pos - 1]; |
|
|
|
G.buf[G.pos-1] = G.buf[G.pos]; |
|
|
|
G.buf[G.pos] = aux; |
|
|
|
if (G.pos != G.len - 1) G.pos++; |
|
|
|
refresh_line(); |
|
|
|
} |
|
|
|
break; |
|
|
|
case CTRL_B: /* ctrl -b */ |
|
|
|
move_left(); |
|
|
|
break; |
|
|
|
case CTRL_F: /* ctrl-f */ |
|
|
|
move_right(); |
|
|
|
break; |
|
|
|
case CTRL_L: |
|
|
|
tputs("\x1b[H\x1b[2J",7); |
|
|
|
refresh_line(); |
|
|
|
break; |
|
|
|
case CTRL_U: /* ctrl-u, delete the whole line */ |
|
|
|
G.buf[0] = '\0'; |
|
|
|
G.pos = G.len = 0; |
|
|
|
refresh_line(); |
|
|
|
break; |
|
|
|
case CTRL_K: /* ctrl-k, delete from current to end of line */ |
|
|
|
G.buf[G.pos] = '\0'; |
|
|
|
G.len = G.pos; |
|
|
|
refresh_line(); |
|
|
|
break; |
|
|
|
case CTRL_A: /* ctrl-a, goto start of the line */ |
|
|
|
move_home(); |
|
|
|
break; |
|
|
|
case CTRL_E: /* ctrl-e, goto end of the line */ |
|
|
|
move_end(); |
|
|
|
break; |
|
|
|
case CTRL_W: |
|
|
|
edit_delete_prev(); |
|
|
|
break; |
|
|
|
case CTRL_P: |
|
|
|
history_prev(); |
|
|
|
break; |
|
|
|
case CTRL_N: |
|
|
|
history_next(); |
|
|
|
break; |
|
|
|
case ESC: /* escape sequence */ |
|
|
|
/* Read the next two bytes representing the escape sequence.
|
|
|
|
* Use two calls to handle slow terminals returning the two |
|
|
|
* chars at different times. */ |
|
|
|
if (tgets(seq, 1, 1000) == -1) break; |
|
|
|
if (tgets(seq + 1 ,1, 1000) == -1) break; |
|
|
|
|
|
|
|
/* ESC [ sequences. */ |
|
|
|
if (seq[0] == '[') { |
|
|
|
if (seq[1] >= '0' && seq[1] <= '9') { |
|
|
|
/* Extended escape, read additional byte. */ |
|
|
|
if (tgets(seq + 2, 1, 1000) == -1) break; |
|
|
|
if (seq[2] == '~') { |
|
|
|
switch(seq[1]) { |
|
|
|
case '3': /* Delete key. */ |
|
|
|
edit_delete(); |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
} else { |
|
|
|
switch(seq[1]) { |
|
|
|
case 'A': /* Up */ |
|
|
|
history_prev(); |
|
|
|
break; |
|
|
|
case 'B': /* Down */ |
|
|
|
history_next(); |
|
|
|
break; |
|
|
|
case 'C': /* Right */ |
|
|
|
move_right(); |
|
|
|
break; |
|
|
|
case 'D': /* Left */ |
|
|
|
move_left(); |
|
|
|
break; |
|
|
|
case 'H': /* Home */ |
|
|
|
move_home(); |
|
|
|
break; |
|
|
|
case 'F': /* End*/ |
|
|
|
move_end(); |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/* ESC O sequences. */ |
|
|
|
else if (seq[0] == 'O') { |
|
|
|
switch(seq[1]) { |
|
|
|
case 'H': /* Home */ |
|
|
|
move_home(); |
|
|
|
break; |
|
|
|
case 'F': /* End*/ |
|
|
|
move_end(); |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
break; |
|
|
|
default: |
|
|
|
edit_insert(c); |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|