summaryrefslogtreecommitdiffstats
path: root/lib/readline.c
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2007-07-05 18:02:13 +0200
committerSascha Hauer <sha@octopus.labnet.pengutronix.de>2007-07-05 18:02:13 +0200
commit4b07af6730d2811363f158f5175138116038f7b9 (patch)
tree206044270884f80204a2da69e02ca3b6f5803185 /lib/readline.c
parentd08c60e9d77dc0f83946cd702d383451865e66dd (diff)
downloadbarebox-4b07af6730d2811363f158f5175138116038f7b9.tar.gz
barebox-4b07af6730d2811363f158f5175138116038f7b9.tar.xz
svn_rev_643
structure cleanup
Diffstat (limited to 'lib/readline.c')
-rw-r--r--lib/readline.c302
1 files changed, 302 insertions, 0 deletions
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 <common.h>
+#include <readkey.h>
+#include <init.h>
+#include <xfuncs.h>
+
+extern char console_buffer[CONFIG_CBSIZE]; /* console I/O buffer */
+
+/*
+ * cmdline-editing related codes from vivi.
+ * Author: Janghoon Lyu <nandy@mizi.com>
+ */
+
+#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;
+}
+