/*
- * (C) Copyright 2014 Leo C. <erbl259-lmu@yahoo.de>
+ * (C) Copyright 2014-2016 Leo C. <erbl259-lmu@yahoo.de>
*
* (C) Copyright 2000
* Wolfgang Denk, DENX Software Engineering, wd@denx.de.
* SPDX-License-Identifier: GPL-2.0
*/
+#include "cli_readline.h"
#include "common.h"
#include <string.h>
#include <stdio.h>
#include "con-utils.h"
#include "print-utils.h"
#include "command.h"
-#include "cli_readline.h"
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
/* VT400: */
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 */
};
typedef enum {
STATE_GROUND,
STATE_ESCAPE,
- STATE_CSI_ENTRY
+ STATE_CSI_ENTRY,
+ STATE_SS3
} vtparse_state_t;
#define CHB_SIZE 15
i_param = 0;
continue;
}
+ if (ch == 'O') {
+ state = STATE_SS3;
+ continue;
+ }
+ state = STATE_GROUND;
+ break;
+ case STATE_SS3:
+ if (ch == 'F') /* weird */
+ ch = KEY_END;
state = STATE_GROUND;
break;
case STATE_CSI_ENTRY:
#define getcmd_getch() vt_parse()
#define getcmd_cbeep() getcmd_putch('\a')
-#define HIST_MAX 20
-static int_fast8_t hist_max;
-static int_fast8_t hist_add_idx;
-static int_fast8_t hist_cur = -1;
+struct hist_node_s {
+ struct hist_node_s *next;
+ char line[];
+};
+typedef struct hist_node_s hist_node;
+
-static char *hist_list[HIST_MAX];
+static hist_node *hist_head;
+static hist_node *hist_cur;
-static void cread_add_to_hist(char *line)
+static hist_node *hist_search_node(char *line)
{
- if (hist_max) {
- int_fast8_t last = hist_add_idx;
- if (--last < 0)
- last = hist_max;
+ hist_node *p = hist_head;
- if (!strcmp(line, hist_list[last]))
- return;
+ while (p && strcmp(p->line, line))
+ p = p->next;
+ return p;
+}
+
+#if 0
+static hist_node *hist_insert(char *line)
+{
+ hist_node *p = (hist_node *) malloc(sizeof (hist_node) + strlen(line) + 1);
+
+ if (p) {
+ strcpy(p->line, line);
+ p->next = hist_head;
+ hist_head = p;
}
+ return p;
+}
+#endif
+
+static hist_node *hist_new(char *line)
+{
+ hist_node *p = (hist_node *) malloc(sizeof (hist_node) + strlen(line) + 1);
- char *p = strdup(line);
if (p) {
- free(hist_list[hist_add_idx]);
- hist_list[hist_add_idx] = p;
+ strcpy(p->line, line);
+ p->next = NULL;
+ }
+ return p;
+}
- if (++hist_add_idx >= HIST_MAX)
- hist_add_idx = 0;
+static hist_node *hist_delete(void)
+{
+ hist_node *p = NULL;
+ hist_node *q = hist_head;
- if (hist_add_idx > hist_max)
- hist_max = hist_add_idx;
+ if (q) {
+ while(q->next) {
+ p = q;
+ q = q->next;
+ }
+ free(q);
+ if (p)
+ p->next = NULL;
}
+ return p;
}
-static char *hist_prev(void)
+static hist_node *hist_unlink(hist_node *pos)
{
- char *ret;
- int_fast8_t old_cur;
+ hist_node *p = NULL;
+ hist_node *q = hist_head;
- if (hist_cur < 0)
- return NULL;
+ 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;
+}
- old_cur = hist_cur;
- if (--hist_cur < 0)
- hist_cur = hist_max;
+static uint_fast8_t hist_count(void)
+{
+ hist_node *p = hist_head;
+ uint_fast8_t n = 0;
- if (hist_cur == hist_add_idx) {
- hist_cur = old_cur;
- ret = NULL;
- } else {
- ret = hist_list[hist_cur];
+ while (p) {
+ ++n;
+ p = p->next;
+ }
+ return n;
+}
+
+static hist_node *cread_add_to_hist(char *line)
+{
+ hist_node * p;
+
+ p = hist_search_node(line);
+ if (p)
+ hist_unlink(p);
+ else
+ p = hist_new(line);
+
+ if (p) {
+ p->next = hist_head;
+ hist_head = p;
}
- return ret;
+ if (hist_count() > CONFIG_SYS_HIST_MAX)
+ hist_delete();
+ return p;
}
-static char *hist_next(void)
+static char *hist_prev(void)
{
- char *ret;
+ hist_node *p = hist_cur;
- if (hist_cur < 0)
+ if (p == NULL)
return NULL;
- if (hist_cur == hist_add_idx)
- return NULL;
+ hist_cur = hist_cur->next;
- if (++hist_cur > hist_max)
- hist_cur = 0;
+ return p->line;
+}
- if (hist_cur == hist_add_idx)
- ret = "";
- else
- ret = hist_list[hist_cur];
+static char *hist_next(void)
+{
+ hist_node *p = NULL;
+ hist_node *q = hist_head;
+
+ if(q == hist_cur)
+ return NULL;
+
+ while(q->next != hist_cur) {
+ p = q;
+ q = q->next;
+ }
+ hist_cur = q;
- return ret;
+ return p ? p->line : "";
}
#define REFRESH_TO_EOL() { \
if (num < eol_num) { \
- wlen = eol_num - num; \
+ uint_fast8_t wlen = eol_num - num; \
putnstr(buf + num, wlen); \
num = eol_num; \
} \
}
}
-static void cread_add_str(char *str, int strsize, bool insert,
+static void cread_add_str(char *str, uint_fast8_t strsize, bool insert,
uint_fast8_t *num, uint_fast8_t *eol_num,
char *buf, uint_fast8_t len)
{
}
}
-static int cread_line(const FLASH char *const prompt, char *buf, uint_fast8_t *len)
+static int cread_line(const FLASH char *const prompt, char *buf,
+ 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;
+ uint_fast8_t init_len = strlen(buf);
if (init_len)
cread_add_str(buf, init_len, 1, &num, &eol_num, buf, *len);
while (1) {
- ichar = getcmd_getch();
+ int ichar = getcmd_getch();
if ((ichar == '\n') || (ichar == '\r')) {
putchar('\n');
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);
case DEL7:
case 8: /* backward-delete-char */
if (num) {
- wlen = eol_num - num;
+ uint_fast8_t wlen = eol_num - num;
num--;
memmove(&buf[num], &buf[num+1], wlen);
getcmd_putch(CTL_BACKSPACE);
case CTL_CH('p'): /* previous-history */
case KEY_DOWN:
case CTL_CH('n'): /* next-history */
- {
- char *hline;
-
- if (ichar == CTL_CH('p') || ichar == KEY_UP)
- hline = hist_prev();
- else
- hline = hist_next();
-
- if (!hline) {
+ if (enable_history) {
+ char *hline;
+
+ if (ichar == CTL_CH('p') || ichar == KEY_UP)
+ hline = hist_prev();
+ else
+ hline = hist_next();
+
+ if (hline) {
+ /* 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();
+ } else {
+ getcmd_cbeep();
+ }
+ } else {
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;
- }
+ break;
+#if 0
+ 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();
+ else
+ hline = hist_search_forward();
+
+ if (hline) {
+ /* 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();
+ } else {
+ getcmd_cbeep();
+ }
+ } else {
+ getcmd_cbeep();
+ }
+ break;
+#endif
#ifdef CONFIG_AUTO_COMPLETE
case '\t': {
int num2, col;
*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;
-
+ if (enable_history) {
+ if (buf[0])
+ hist_cur = cread_add_to_hist(buf);
+ }
return 0;
}
/****************************************************************************/
-static int cli_readline_into_buffer(const FLASH char *const prompt, char *buffer)
+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;
if (prompt)
my_puts_P(prompt);
- rc = cread_line(prompt, p, &len);
+ rc = cread_line(prompt, p, &len, enable_history);
return rc < 0 ? rc : (int) len;
}
-int cli_readline(const FLASH char *const prompt)
+int cli_readline(const FLASH char *const prompt, bool enable_history)
{
/*
* If console_buffer isn't 0-length the user will be prompted to modify
*/
console_buffer[0] = '\0';
- return cli_readline_into_buffer(prompt, console_buffer);
+ return cli_readline_into_buffer(prompt, console_buffer, enable_history);
}