From 4b07af6730d2811363f158f5175138116038f7b9 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Thu, 5 Jul 2007 18:02:13 +0200 Subject: svn_rev_643 structure cleanup --- lib/readline.c | 302 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 302 insertions(+) create mode 100644 lib/readline.c (limited to 'lib/readline.c') diff --git a/lib/readline.c b/lib/readline.c new file mode 100644 index 0000000000..ab0a46a8c3 --- /dev/null +++ b/lib/readline.c @@ -0,0 +1,302 @@ +#include +#include +#include +#include + +extern char console_buffer[CONFIG_CBSIZE]; /* console I/O buffer */ + +/* + * cmdline-editing related codes from vivi. + * Author: Janghoon Lyu + */ + +#define putnstr(str,n) do { \ + printf ("%.*s", n, str); \ + } while (0) + +#define MAX_CMDBUF_SIZE 256 + +#define CTL_BACKSPACE ('\b') +#define DEL ((char)255) +#define DEL7 ((char)127) +#define CREAD_HIST_CHAR ('!') + +#define getcmd_putch(ch) putc(ch) +#define getcmd_getch() getc() +#define getcmd_cbeep() getcmd_putch('\a') + +#define HIST_MAX 20 +#define HIST_SIZE MAX_CMDBUF_SIZE + +static int hist_max = 0; +static int hist_add_idx = 0; +static int hist_cur = -1; +unsigned hist_num = 0; + +char* hist_list[HIST_MAX]; +char hist_lines[HIST_MAX][HIST_SIZE]; + +#define add_idx_minus_one() ((hist_add_idx == 0) ? hist_max : hist_add_idx-1) + +static int hist_init(void) +{ + int i; + + hist_max = 0; + hist_add_idx = 0; + hist_cur = -1; + hist_num = 0; + + for (i = 0; i < HIST_MAX; i++) { + hist_list[i] = hist_lines[i]; + hist_list[i][0] = '\0'; + } + return 0; +} + +postcore_initcall(hist_init); + +static void cread_add_to_hist(char *line) +{ + strcpy(hist_list[hist_add_idx], line); + + if (++hist_add_idx >= HIST_MAX) + hist_add_idx = 0; + + if (hist_add_idx > hist_max) + hist_max = hist_add_idx; + + hist_num++; +} + +static char* hist_prev(void) +{ + char *ret; + int old_cur; + + if (hist_cur < 0) + return NULL; + + old_cur = hist_cur; + if (--hist_cur < 0) + hist_cur = hist_max; + + if (hist_cur == hist_add_idx) { + hist_cur = old_cur; + ret = NULL; + } else + ret = hist_list[hist_cur]; + + return (ret); +} + +static char* hist_next(void) +{ + char *ret; + + if (hist_cur < 0) + return NULL; + + if (hist_cur == hist_add_idx) + return NULL; + + if (++hist_cur > hist_max) + hist_cur = 0; + + if (hist_cur == hist_add_idx) { + ret = ""; + } else + ret = hist_list[hist_cur]; + + return (ret); +} + +#define BEGINNING_OF_LINE() { \ + while (num) { \ + getcmd_putch(CTL_BACKSPACE); \ + num--; \ + } \ +} + +#define ERASE_TO_EOL() { \ + if (num < eol_num) { \ + int tmp; \ + for (tmp = num; tmp < eol_num; tmp++) \ + getcmd_putch(' '); \ + while (tmp-- > num) \ + getcmd_putch(CTL_BACKSPACE); \ + eol_num = num; \ + } \ +} + +#define REFRESH_TO_EOL() { \ + if (num < eol_num) { \ + wlen = eol_num - num; \ + putnstr(buf + num, wlen); \ + num = eol_num; \ + } \ +} + +static void cread_add_char(char ichar, int insert, unsigned long *num, + unsigned long *eol_num, char *buf, unsigned long len) +{ + unsigned long wlen; + + /* room ??? */ + if (insert || *num == *eol_num) { + if (*eol_num > len - 1) { + getcmd_cbeep(); + return; + } + (*eol_num)++; + } + + if (insert) { + wlen = *eol_num - *num; + if (wlen > 1) { + memmove(&buf[*num+1], &buf[*num], wlen-1); + } + + buf[*num] = ichar; + putnstr(buf + *num, wlen); + (*num)++; + while (--wlen) { + getcmd_putch(CTL_BACKSPACE); + } + } else { + /* echo the character */ + wlen = 1; + buf[*num] = ichar; + putnstr(buf + *num, wlen); + (*num)++; + } +} + +int readline(const char *prompt, char *buf, int len) +{ + unsigned long num = 0; + unsigned long eol_num = 0; + unsigned long rlen; + unsigned long wlen; + char ichar; + int insert = 1; + int rc = 0; + + puts (prompt); + + while (1) { + rlen = 1; + ichar = read_key(); + + if ((ichar == '\n') || (ichar == '\r')) { + putc('\n'); + break; + } + + switch (ichar) { + case KEY_HOME: + BEGINNING_OF_LINE(); + break; + case CTL_CH('c'): /* ^C - break */ + *buf = 0; /* discard input */ + return -1; + case KEY_RIGHT: + if (num < eol_num) { + getcmd_putch(buf[num]); + num++; + } + break; + case KEY_LEFT: + if (num) { + getcmd_putch(CTL_BACKSPACE); + num--; + } + break; + case CTL_CH('d'): + if (num < eol_num) { + wlen = eol_num - num - 1; + if (wlen) { + memmove(&buf[num], &buf[num+1], wlen); + putnstr(buf + num, wlen); + } + + getcmd_putch(' '); + do { + getcmd_putch(CTL_BACKSPACE); + } while (wlen--); + eol_num--; + } + break; + case KEY_ERASE_TO_EOL: + ERASE_TO_EOL(); + break; + case KEY_REFRESH_TO_EOL: + case KEY_END: + REFRESH_TO_EOL(); + break; + case KEY_INSERT: + insert = !insert; + break; + case KEY_ERASE_LINE: + BEGINNING_OF_LINE(); + ERASE_TO_EOL(); + break; + case DEL: + case KEY_DEL7: + case 8: + if (num) { + wlen = eol_num - num; + 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--); + eol_num--; + } + break; + case KEY_UP: + case KEY_DOWN: + { + char * hline; + + if (ichar == KEY_UP) + hline = hist_prev(); + else + hline = hist_next(); + + if (!hline) { + getcmd_cbeep(); + continue; + } + + /* nuke the current line */ + /* first, go home */ + BEGINNING_OF_LINE(); + + /* erase to end of line */ + ERASE_TO_EOL(); + + /* copy new line into place and display */ + strcpy(buf, hline); + eol_num = strlen(buf); + REFRESH_TO_EOL(); + continue; + } + default: + cread_add_char(ichar, insert, &num, &eol_num, buf, len); + break; + } + } + len = eol_num; + buf[eol_num] = '\0'; /* lose the newline */ + + if (buf[0] && buf[0] != CREAD_HIST_CHAR) + cread_add_to_hist(buf); + hist_cur = hist_add_idx; + + return rc < 0 ? rc : len; +} + -- cgit v1.2.3