X-Git-Url: http://cloudbase.mooo.com/gitweb/z180-stamp.git/blobdiff_plain/db6a28d817d6430b5774aedab7e1b8715e358d46..f1e16f884308e8ef720a4ecbcdcc97af97dce4bd:/avr/cli_readline.c diff --git a/avr/cli_readline.c b/avr/cli_readline.c index e34f0c8..0ed8f67 100644 --- a/avr/cli_readline.c +++ b/avr/cli_readline.c @@ -15,7 +15,6 @@ #include "common.h" #include #include -#include #include #include @@ -23,8 +22,23 @@ #include "con-utils.h" #include "print-utils.h" #include "command.h" +#include "debug.h" +#define DEBUG_READLINE 0 /* set to 1 to debug */ + +#define debug_readline(fmt, args...) \ + debug_cond(DEBUG_READLINE, fmt, ##args) + + + +char console_buffer[CONFIG_SYS_CBSIZE + 1]; /* console I/O buffer */ + +#define CTL_CH(c) ((c) - 'a' + 1) +#define CTL_BACKSPACE ('\b') +#define DEL ((char)255) +#define DEL7 ((char)127) + /************************************************************************************************/ /* TODO: @@ -67,23 +81,26 @@ struct fkey_tbl_s { static const FLASH struct fkey_tbl_s fkey_table[] = { FKEY_TBL_ITEM(B, KEY_DOWN), // Down arrow key -FKEY_TBL_ITEM(A, KEY_UP), // Up arrow key +FKEY_TBL_ITEM(A, KEY_UP), // Up arrow key FKEY_TBL_ITEM(D, KEY_LEFT), // Left arrow key -FKEY_TBL_ITEM(C, KEY_RIGHT), // Right arrow key +FKEY_TBL_ITEM(C, KEY_RIGHT), // Right arrow key FKEY_TBL_ITEM(1~, KEY_HOME), // Home key -FKEY_TBL_ITEM(3~, KEY_DC), // Delete character key -FKEY_TBL_ITEM(2~, KEY_IC), // Ins char/toggle ins mode key -FKEY_TBL_ITEM(6~, KEY_NPAGE), // Next-page key -FKEY_TBL_ITEM(5~, KEY_PPAGE), // Previous-page key +FKEY_TBL_ITEM(3~, KEY_DC), // Delete character key +FKEY_TBL_ITEM(2~, KEY_IC), // Ins char/toggle ins mode key +FKEY_TBL_ITEM(6~, KEY_NPAGE), // Next-page key +FKEY_TBL_ITEM(5~, KEY_PPAGE), // Previous-page key FKEY_TBL_ITEM(4~, KEY_END), // End key FKEY_TBL_ITEM(Z, KEY_BTAB), // Back tab key +/* */ +FKEY_TBL_ITEM(H, KEY_HOME), // Home key +FKEY_TBL_ITEM(F, KEY_END), // End key /* VT400: */ FKEY_TBL_ITEM(11~, KEY_F(1)), // Function key F1 FKEY_TBL_ITEM(12~, KEY_F(2)), // Function key F2 FKEY_TBL_ITEM(13~, KEY_F(3)), // Function key F3 FKEY_TBL_ITEM(14~, KEY_F(4)), // Function key F4 FKEY_TBL_ITEM(15~, KEY_F(5)), // Function key F5 -/* Linux consoe */ +/* Linux console */ FKEY_TBL_ITEM([A, KEY_F(1)), // Function key F1 FKEY_TBL_ITEM([B, KEY_F(2)), // Function key F2 FKEY_TBL_ITEM([C, KEY_F(3)), // Function key F3 @@ -94,9 +111,9 @@ FKEY_TBL_ITEM(17~, KEY_F(6)), // Function key F6 FKEY_TBL_ITEM(18~, KEY_F(7)), // Function key F7 FKEY_TBL_ITEM(19~, KEY_F(8)), // Function key F8 FKEY_TBL_ITEM(20~, KEY_F(9)), // Function key F9 -FKEY_TBL_ITEM(21~, KEY_F(10)), // Function key F10 -FKEY_TBL_ITEM(23~, KEY_F(11)), // Function key F11 -FKEY_TBL_ITEM(24~, KEY_F(12)), // Function key F12 +FKEY_TBL_ITEM(21~, KEY_F(10)), // Function key F10 +FKEY_TBL_ITEM(23~, KEY_F(11)), // Function key F11 +FKEY_TBL_ITEM(24~, KEY_F(12)), // Function key F12 { NULL } /* Mark end of table */ }; @@ -105,7 +122,8 @@ FKEY_TBL_ITEM(24~, KEY_F(12)), // Function key F12 typedef enum { STATE_GROUND, STATE_ESCAPE, - STATE_CSI_ENTRY + STATE_CSI_ENTRY, + STATE_SS3 } vtparse_state_t; #define CHB_SIZE 15 @@ -116,7 +134,7 @@ int vt_parse (void) static vtparse_state_t state = STATE_GROUND; char buf[CHB_SIZE+1]; uint8_t param[2]; - uint8_t i_buf; + uint8_t i_buf = 0; uint8_t i_param; int ch; @@ -145,6 +163,17 @@ int vt_parse (void) i_param = 0; continue; } + if (ch == 'O') { + state = STATE_SS3; + continue; + } + state = STATE_GROUND; + break; + case STATE_SS3: + if (ch == 'F') + ch = KEY_END; + if (ch == 'H') + ch = KEY_HOME; state = STATE_GROUND; break; case STATE_CSI_ENTRY: @@ -188,197 +217,236 @@ int vt_parse (void) /************************************************************************************************/ - -char console_buffer[CONFIG_SYS_CBSIZE + 1]; /* console I/O buffer */ - /* * cmdline-editing related codes from vivi. * Author: Janghoon Lyu */ -static void putnstr(char *str, int n) -{ - /* printf_P(PSTR("%.*s"), (int)n, str) */ - while (n-- && *str) - putchar(*str++); -} - - -#define CTL_CH(c) ((c) - 'a' + 1) -#define CTL_BACKSPACE ('\b') -#define DEL ((char)255) -#define DEL7 ((char)127) -#define getcmd_putch(ch) putchar(ch) -#define getcmd_getch() vt_parse() -#define getcmd_cbeep() getcmd_putch('\a') +char histbuf[CONFIG_SYS_HISTSIZE+1]; +#define HISTBUFE (histbuf+CONFIG_SYS_HISTSIZE) +static char *hist_head; +static char *hist_cur; -struct hist_node_s { - struct hist_node_s *next; - char line[]; -}; -typedef struct hist_node_s hist_node; +static void hist_reset(void) +{ + if (hist_head == NULL) + hist_head = HISTBUFE; + hist_cur = hist_head; +} +static char *hist_entry_next(char *p) +{ + if (*p) + while (*p++); -static hist_node *hist_head; -static hist_node *hist_cur; + return p; +} -static hist_node *hist_search_node(char *line) +static char *hist_entry_prev(char *p) { - hist_node *p = hist_head; + if (p == hist_head) + return NULL; + + --p; + while (p != hist_head && *(p-1) != 0) + --p; - while (p && strcmp(p->line, line)) - p = p->next; return p; } -#if 0 -static hist_node *hist_insert(char *line) +static char *hist_search_entry(char *line) { - hist_node *p = (hist_node *) malloc(sizeof (hist_node) + strlen(line) + 1); + char *p = hist_head; - if (p) { - strcpy(p->line, line); - p->next = hist_head; - hist_head = p; - } - return p; + while (*p && strcmp(p, line)) + p = hist_entry_next(p); + return *p ? p : NULL; } -#endif -static hist_node *hist_new(char *line) +static char *hist_delete(size_t amount) { - hist_node *p = (hist_node *) malloc(sizeof (hist_node) + strlen(line) + 1); + char *p; + + p = HISTBUFE - amount; + if (p < hist_head) + p = hist_head; - if (p) { - strcpy(p->line, line); - p->next = NULL; + while (p > hist_head && *(p-1)) + --p; + + if (p == hist_head) + hist_head = HISTBUFE; + else { + size_t shift = HISTBUFE - p; + size_t len = p - hist_head; + hist_head = memmove(hist_head + shift, hist_head, len); } - return p; + return hist_head; } -static hist_node *hist_delete(void) +static char *hist_delete_entry(char *entry) { - hist_node *p = NULL; - hist_node *q = hist_head; + size_t shift = strlen(entry) + 1; + size_t len = entry - hist_head; - if (q) { - while(q->next) { - p = q; - q = q->next; - } - free(q); - if (p) - p->next = NULL; - } - return p; + hist_head = memmove(hist_head + shift, hist_head, len); + + return hist_head; } -static hist_node *hist_unlink(hist_node *pos) + +static char *hist_add_entry(char *line) { - hist_node *p = NULL; - hist_node *q = hist_head; + char *p = hist_head; - while(q && q != pos) { - p = q; - q = q->next; - } - if (q) { - if (p) - p->next = q->next; - else - hist_head = q->next; - q->next = NULL; - } - return q; + if (p == NULL) + p = HISTBUFE; + + char *q = p - strlen(line) - 1; + if (q < histbuf) + q = histbuf; + + strlcpy(q, line, p - q); + + hist_head = q; + + return hist_head; } -static uint_fast8_t hist_count(void) +static uint_fast8_t hist_get_count(void) { - hist_node *p = hist_head; + char *p = hist_head; uint_fast8_t n = 0; - while (p) { + while (*p) { ++n; - p = p->next; + while (*p++); } return n; } -static hist_node *cread_add_to_hist(char *line) +static int hist_get_size(void) { - hist_node * p; + return HISTBUFE - hist_head; +} - p = hist_search_node(line); - if (p) - hist_unlink(p); - else - p = hist_new(line); +static char *cread_add_to_hist(char *line) +{ + char *p; - if (p) { - p->next = hist_head; - hist_head = p; + p = hist_search_entry(line); + if (p) + hist_delete_entry(p); + else { + size_t free = hist_head - histbuf; + if (free < strlen(line) + 1) + hist_delete(strlen(line) + 1 - free); } + hist_add_entry(line); - if (hist_count() > CONFIG_SYS_HIST_MAX) - hist_delete(); return p; } static char *hist_prev(void) { - hist_node *p = hist_cur; + char *p = hist_cur; - if (p == NULL) + if (*p == '\0') return NULL; + hist_cur = hist_entry_next(p); - hist_cur = hist_cur->next; - - return p->line; + return p; } static char *hist_next(void) { - hist_node *p = NULL; - hist_node *q = hist_head; + char *p = hist_cur; + + if(p == hist_head) + return NULL; + + p = hist_entry_prev(p); + hist_cur = p; + + return p == hist_head ? "" : hist_entry_prev(p); +} + +static char *hist_search_backward(char* buf, uint8_t num) +{ + char *p = hist_cur; - if(q == hist_cur) + if (*p == '\0') return NULL; - while(q->next != hist_cur) { - p = q; - q = q->next; + while (*p && strncmp(p, buf, num)) + p = hist_entry_next(p); + + if(!strncmp(p, buf, num)) { + hist_cur = hist_entry_next(p); + return p; + } + + return NULL; +} + +static char *hist_search_forward (char* buf, uint8_t num) +{ + char *p = hist_cur; + + if(p != hist_head && (p = hist_entry_prev(p)) != NULL) { + do { + p = hist_entry_prev(p); + } while (p && strncmp(p, buf, num) != 0); + + //if(!strncmp(p, buf, num)) { + if(p) { + hist_cur = hist_entry_next(p); + return p; + } } - hist_cur = q; - return p ? p->line : ""; + return NULL; +} + +static void putnstr(char *str, int n) +{ + /* printf_P(PSTR("%.*s"), (int)n, str) */ + while (n-- && *str) + putchar(*str++); } +static void getcmd_putch(int ch) { putchar(ch);} +static int getcmd_getch(void) { return vt_parse();} +static void getcmd_cbeep(void) { getcmd_putch('\a');} -#define BEGINNING_OF_LINE() { \ - while (num) { \ - getcmd_putch(CTL_BACKSPACE); \ - num--; \ - } \ +static void beginning_of_line(uint8_t *num) +{ + while (*num) { + getcmd_putch(CTL_BACKSPACE); + (*num)--; + } } -#define ERASE_TO_EOL() { \ - if (num < eol_num) { \ - /* printf_P(PSTR("%*S"), (int)(eol_num - num), PSTR("")); */ \ - print_blanks(eol_num - num); \ - do { \ - getcmd_putch(CTL_BACKSPACE); \ - } while (--eol_num > num); \ - } \ +static void erase_to_eol(uint_fast8_t *num, uint_fast8_t *eol_num) +{ + if (*num < *eol_num) { + /* printf_P(PSTR("%*S"), (int)(*eol_num - *num), PSTR("")); */ + print_blanks(*eol_num - *num); + do { + getcmd_putch(CTL_BACKSPACE); + } while (--(*eol_num) > *num); + } } -#define REFRESH_TO_EOL() { \ - if (num < eol_num) { \ - wlen = eol_num - num; \ - putnstr(buf + num, wlen); \ - num = eol_num; \ - } \ +static void refresh_to_eol(char *buf, uint_fast8_t *num, uint_fast8_t *eol_num) +{ + if (*num < *eol_num) { + uint_fast8_t wlen = *eol_num - *num; + putnstr(buf + *num, wlen); + *num = *eol_num; + } } static void cread_add_char(char ichar, bool insert, uint_fast8_t *num, @@ -407,40 +475,37 @@ static void cread_add_char(char ichar, bool insert, uint_fast8_t *num, getcmd_putch(CTL_BACKSPACE); } else { /* echo the character */ - wlen = 1; buf[*num] = ichar; - putnstr(buf + *num, wlen); + putnstr(buf + *num, 1); (*num)++; } } -static void cread_add_str(char *str, int strsize, bool insert, - uint_fast8_t *num, uint_fast8_t *eol_num, - char *buf, uint_fast8_t len) +static void cread_add_str(char *str, bool insert, uint_fast8_t *num, + uint_fast8_t *eol_num, char *buf, uint_fast8_t len) { - while (strsize--) { - cread_add_char(*str, insert, num, eol_num, buf, len); - str++; - } + char c; + + while ((c = *str++) != '\0') + cread_add_char(c, insert, num, eol_num, buf, len); } static int cread_line(const FLASH char *const prompt, char *buf, - uint_fast8_t *len, bool enable_history) + uint_fast8_t len, bool enable_history) { uint_fast8_t num = 0; uint_fast8_t eol_num = 0; - uint_fast8_t wlen; - int ichar; bool insert = 1; - int init_len = strlen(buf); (void) prompt; - if (init_len) - cread_add_str(buf, init_len, 1, &num, &eol_num, buf, *len); + if (buf[0]) + cread_add_str(buf, 1, &num, &eol_num, buf, len); + + hist_reset(); while (1) { - ichar = getcmd_getch(); + int ichar = getcmd_getch(); if ((ichar == '\n') || (ichar == '\r')) { putchar('\n'); @@ -452,9 +517,10 @@ static int cread_line(const FLASH char *const prompt, char *buf, case KEY_HOME: case CTL_CH('a'): - BEGINNING_OF_LINE(); + beginning_of_line(&num); break; case CTL_CH('c'): /* ^C - break */ + putchar('\n'); *buf = '\0'; /* discard input */ return -1; case KEY_RIGHT: @@ -474,7 +540,7 @@ static int cread_line(const FLASH char *const prompt, char *buf, case KEY_DC: case CTL_CH('d'): /* delete-char */ if (num < eol_num) { - wlen = eol_num - num - 1; + uint_fast8_t wlen = eol_num - num - 1; if (wlen) { memmove(&buf[num], &buf[num+1], wlen); putnstr(buf + num, wlen); @@ -488,11 +554,11 @@ static int cread_line(const FLASH char *const prompt, char *buf, } break; case CTL_CH('k'): /* kill-line */ - ERASE_TO_EOL(); + erase_to_eol(&num, &eol_num); break; case KEY_END: case CTL_CH('e'): - REFRESH_TO_EOL(); + refresh_to_eol(buf, &num, &eol_num); break; case KEY_IC: case CTL_CH('o'): @@ -500,22 +566,21 @@ static int cread_line(const FLASH char *const prompt, char *buf, break; case CTL_CH('x'): case CTL_CH('u'): /* kill-whole-line */ - BEGINNING_OF_LINE(); - ERASE_TO_EOL(); + beginning_of_line(&num); + erase_to_eol(&num, &eol_num); break; case DEL: case DEL7: case 8: /* backward-delete-char */ if (num) { - wlen = eol_num - num; - num--; + uint_fast8_t wlen = eol_num - --num; + buf[eol_num] = ' '; memmove(&buf[num], &buf[num+1], wlen); getcmd_putch(CTL_BACKSPACE); putnstr(buf + num, wlen); - getcmd_putch(' '); do { getcmd_putch(CTL_BACKSPACE); - } while (wlen--); + } while (--wlen); eol_num--; } break; @@ -532,17 +597,38 @@ static int cread_line(const FLASH char *const prompt, char *buf, hline = hist_next(); if (hline) { - /* nuke the current line */ /* first, go home */ - BEGINNING_OF_LINE(); - + beginning_of_line(&num); + /* overwrite current line */ + cread_add_str(hline, 0, &num, &eol_num, buf, len); /* erase to end of line */ - ERASE_TO_EOL(); + erase_to_eol(&num, &eol_num); + + } else { + getcmd_cbeep(); + } + } else { + getcmd_cbeep(); + } + break; + case KEY_PPAGE: /* history-search-backward */ + case KEY_NPAGE: /* history-search-forward */ + if (enable_history) { + char *hline; + if (ichar == KEY_PPAGE) + hline = hist_search_backward(buf, num); + else + hline = hist_search_forward(buf, num); - /* copy new line into place and display */ - strcpy(buf, hline); - eol_num = strlen(buf); - REFRESH_TO_EOL(); + if (hline) { + uint_fast8_t num2 = num; + /* overwrite current line from cursor position */ + cread_add_str(hline+num, 0, &num2, &eol_num, buf, len); + /* erase to end of line */ + erase_to_eol(&num2, &eol_num); + /* cursor back */ + while (num2-- > num) + getcmd_putch(CTL_BACKSPACE); } else { getcmd_cbeep(); } @@ -573,37 +659,33 @@ static int cread_line(const FLASH char *const prompt, char *buf, #endif default: if (isprint(ichar)) - cread_add_char(ichar, insert, &num, &eol_num, buf, - *len); + cread_add_char(ichar, insert, &num, &eol_num, buf, len); break; } } - *len = eol_num; + while (eol_num && buf[eol_num-1] == ' ') + --eol_num; /* remove trailing blanks */ buf[eol_num] = '\0'; /* lose the newline */ - if (enable_history) { - if (buf[0]) - hist_cur = cread_add_to_hist(buf); + uint_fast8_t i = 0; + while (buf[i] == ' ') + ++i; /* remove leading blanks */ + if (i) { + eol_num -= i; + memmove(buf, buf+i, eol_num+1); } - return 0; + + debug_readline("### hist_head: %p, hist_cur: %p\n", hist_head, hist_cur); + if (enable_history && buf[0]) { + cread_add_to_hist(buf); + debug_readline("### hist_head: %p, hist_cur: %p, hist_size: %3d, hist_count: %2d\n", + hist_head, hist_cur, hist_get_size(), hist_get_count()); + } + return eol_num; } /****************************************************************************/ -static int cli_readline_into_buffer(const FLASH char *const prompt, - char *buffer, bool enable_history) -{ - char *p = buffer; - uint_fast8_t len = CONFIG_SYS_CBSIZE; - int rc; - - if (prompt) - my_puts_P(prompt); - - rc = cread_line(prompt, p, &len, enable_history); - return rc < 0 ? rc : (int) len; -} - int cli_readline(const FLASH char *const prompt, bool enable_history) { /* @@ -612,5 +694,8 @@ int cli_readline(const FLASH char *const prompt, bool enable_history) */ console_buffer[0] = '\0'; - return cli_readline_into_buffer(prompt, console_buffer, enable_history); + if (prompt) + my_puts_P(prompt); + + return cread_line(prompt, console_buffer, CONFIG_SYS_CBSIZE, enable_history); }