[PATCH] readline: reimplement history functions

Sascha Hauer s.hauer at pengutronix.de
Tue Jul 29 04:51:07 PDT 2014


This reimplements the history functions in readline.

- Use regular lists instead of homegrown list implementation
- Allocate history strings dynamically instead of copying strings
  to fixed buffers without checking the size
- saves us an initcall
- slightly smaller
- no longer add duplicates to the history
- when moving past the last history entry print an empty line

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 lib/readline.c | 122 +++++++++++++++++++++++++--------------------------------
 1 file changed, 54 insertions(+), 68 deletions(-)

diff --git a/lib/readline.c b/lib/readline.c
index 240a131..b70bca8 100644
--- a/lib/readline.c
+++ b/lib/readline.c
@@ -14,8 +14,6 @@
 		printf ("%.*s", n, str);	\
 	} while (0)
 
-#define MAX_CMDBUF_SIZE		256
-
 #define CTL_BACKSPACE		('\b')
 #define DEL			255
 #define DEL7			127
@@ -25,90 +23,82 @@
 #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;
-static unsigned hist_num = 0;
+struct history {
+	char *line;
+	struct list_head list;
+};
 
-static char* hist_list[HIST_MAX];
-static char hist_lines[HIST_MAX][HIST_SIZE];
+static LIST_HEAD(history_list);
 
-#define add_idx_minus_one() ((hist_add_idx == 0) ? hist_max : hist_add_idx-1)
+static struct list_head *history_current;
+static int history_num_entries;
 
-static int hist_init(void)
+static void cread_add_to_hist(char *line)
 {
-	int i;
+	struct history *history;
+	char *newline;
 
-	hist_max = 0;
-	hist_add_idx = 0;
-	hist_cur = -1;
-	hist_num = 0;
+	if (!list_empty(&history_list)) {
+		history = list_last_entry(&history_list, struct history, list);
 
-	for (i = 0; i < HIST_MAX; i++) {
-		hist_list[i] = hist_lines[i];
-		hist_list[i][0] = '\0';
+		if (!strcmp(line, history->line))
+			return;
 	}
-	return 0;
-}
-
-postcore_initcall(hist_init);
 
-static void cread_add_to_hist(char *line)
-{
-	strcpy(hist_list[hist_add_idx], line);
+	newline = strdup(line);
+	if (!newline)
+		return;
 
-	if (++hist_add_idx >= HIST_MAX)
-		hist_add_idx = 0;
+	if (history_num_entries < 32) {
+		history = xzalloc(sizeof(*history));
+		history_num_entries++;
+	} else {
+		history = list_first_entry(&history_list, struct history, list);
+		free(history->line);
+		list_del(&history->list);
+	}
 
-	if (hist_add_idx > hist_max)
-		hist_max = hist_add_idx;
+	history->line = newline;
 
-	hist_num++;
+	list_add_tail(&history->list, &history_list);
 }
 
-static char* hist_prev(void)
+static const char *hist_prev(void)
 {
-	char *ret;
-	int old_cur;
+	struct history *history;
 
-	if (hist_cur < 0)
-		return NULL;
+	if (history_current->prev == &history_list) {
+		history = list_entry(history_current, struct history, list);
+		getcmd_cbeep();
+		return history->line;
+	}
 
-	old_cur = hist_cur;
-	if (--hist_cur < 0)
-		hist_cur = hist_max;
+	history = list_entry(history_current->prev, struct history, list);
 
-	if (hist_cur == hist_add_idx) {
-		hist_cur = old_cur;
-		ret = NULL;
-	} else
-		ret = hist_list[hist_cur];
+	history_current = &history->list;
 
-	return (ret);
+	return history->line;
 }
 
-static char* hist_next(void)
+static const char *hist_next(void)
 {
-	char *ret;
+	struct history *history;
 
-	if (hist_cur < 0)
-		return NULL;
+	if (history_current->next == &history_list) {
+		history_current = &history_list;
+		return "";
+	}
 
-	if (hist_cur == hist_add_idx)
-		return NULL;
+	if (history_current == &history_list) {
+		getcmd_cbeep();
+		return "";
+	}
 
-	if (++hist_cur > hist_max)
-		hist_cur = 0;
+	history = list_entry(history_current->next, struct history, list);
 
-	if (hist_cur == hist_add_idx) {
-		ret = "";
-	} else
-		ret = hist_list[hist_cur];
+	history_current = &history->list;
 
-	return (ret);
+	return history->line;
 }
 
 #define BEGINNING_OF_LINE() {			\
@@ -198,6 +188,8 @@ int readline(const char *prompt, char *buf, int len)
 
 	complete_reset();
 #endif
+	history_current = &history_list;
+
 	puts (prompt);
 
 	while (1) {
@@ -302,18 +294,13 @@ int readline(const char *prompt, char *buf, int len)
 		case BB_KEY_UP:
 		case BB_KEY_DOWN:
 		{
-			char * hline;
+			const char *hline;
 
 			if (ichar == BB_KEY_UP)
 				hline = hist_prev();
 			else
 				hline = hist_next();
 
-			if (!hline) {
-				getcmd_cbeep();
-				continue;
-			}
-
 			/* nuke the current line */
 			/* first, go home */
 			BEGINNING_OF_LINE();
@@ -346,9 +333,8 @@ int readline(const char *prompt, char *buf, int len)
 	len = eol_num;
 	buf[eol_num] = '\0';	/* lose the newline */
 
-	if (buf[0] && buf[0] != CREAD_HIST_CHAR)
+	if (buf[0])
 		cread_add_to_hist(buf);
-	hist_cur = hist_add_idx;
 
 	return len;
 }
-- 
2.0.1




More information about the barebox mailing list