[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[microblaze-uclinux] [PATCH] Enhanced busybox msh command line editing



Hi all,

These patches add some extra features to busybox/msh:
- bigger history
- ctrl shortcuts (right, left, del, end to move between
  words, delete them and go to last line of history)
- history search (up/down select commands which match the
  beggining of the current command line)
- try to load and save history file if HISTFILE env
  contains a valid file path.

I would not say all these features works perfectly, however,
working with the command line is much more convenient with
them.

Regards,

Antoine




diff -ur -x .svn -x '*.o.cmd' -x '*.o' nX_linux_r4/petalinux-dist/user/busybox/shell/cmdedit.c nX_linux/petalinux-dist/user/busybox/shell/cmdedit.c
--- nX_linux_r4/petalinux-dist/user/busybox/shell/cmdedit.c	2009-08-07 15:55:20.000000000 +0200
+++ nX_linux/petalinux-dist/user/busybox/shell/cmdedit.c	2009-08-07 15:55:54.000000000 +0200
@@ -87,7 +87,7 @@

 /* Maximum length of the linked list for the command line history */
 #ifndef CONFIG_FEATURE_COMMAND_HISTORY
-#define MAX_HISTORY   15
+#define MAX_HISTORY   511
 #else
 #define MAX_HISTORY   CONFIG_FEATURE_COMMAND_HISTORY
 #endif
@@ -473,6 +485,35 @@
 		cmdedit_set_out_char(command_ps[cursor + 1]);
 }

+static void input_word_delete(void)
+{
+	if (cursor < len && isspace(command_ps[cursor]))
+		input_forward();
+	while (cursor < len && !isspace(command_ps[cursor]))
+		input_delete();
+	while (cursor < len && isspace(command_ps[cursor]))
+		input_delete();
+}
+
+
+static void input_word_backward(void)
+{
+	int j = cursor;
+	while (0 < j && isspace(command_ps[j-1])) j--;
+	while (0 < j && !isspace(command_ps[j-1])) j--;
+
+	input_backward(cursor - j);
+}
+
+static void input_word_forward(void)
+{
+	int j = cursor;
+	while (j < len && !isspace(command_ps[j])) j++;
+	while (j < len && isspace(command_ps[j])) j++;
+
+	redraw(cmdedit_y, len -j);
+}
+

 static void cmdedit_setwidth(int w, int redraw_flg)
 {
@@ -1124,26 +1165,45 @@
 #endif  /* CONFIG_FEATURE_COMMAND_TAB_COMPLETION */

 #if MAX_HISTORY >= 1
-static void get_previous_history(void)
+static int get_previous_history(void)
 {
-	if(command_ps[0] != 0 || history[cur_history] == 0) {
-		free(history[cur_history]);
-		history[cur_history] = bb_xstrdup(command_ps);
+	int len_last;
+
+	/* Save command line only if it is the last history line */
+	if (cur_history == n_history) {
+		free(history[n_history]);
+		history[n_history] = bb_xstrdup(command_ps);
+	}
+
+	/* Count chars on the last history line */
+	len_last = strlen(history[n_history]);
+
+	/* Search previous line with matching beginning - works for len=0 */
+	while (cur_history) {
+		cur_history--;
+		if (!strncmp(history[n_history], history[cur_history], len_last))
+			return 1;
 	}
-	cur_history--;
+
+	beep();
+	return 0;
 }

 static int get_next_history(void)
 {
-	int ch = cur_history;
+	/* Count chars on the last history line */
+	int len_last = strlen(history[n_history]);

-	if (ch < n_history) {
-		get_previous_history(); /* save the current history line */
-		return (cur_history = ch+1);
-	} else {
-		beep();
-		return 0;
+	/* Search previous line with matching beginning - works for len=0 */
+	while (cur_history < n_history) {
+		cur_history++;
+		if (!strncmp(history[n_history], history[cur_history], len_last)) {
+			return 1;
+		}
 	}
+
+	beep();
+	return 0;
 }

 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
@@ -1152,15 +1212,14 @@
 	FILE *fp;
 	int hi;

-	/* cleanup old */
-
-	for(hi = n_history; hi > 0; ) {
-		hi--;
-		free ( history [hi] );
-	}
-
 	if (( fp = fopen ( fromfile, "r" ))) {

+		/* cleanup old */
+		for (hi = n_history; hi > 0; ) {
+			hi--;
+			free ( history [hi] );
+		}
+
 		for ( hi = 0; hi < MAX_HISTORY; ) {
 			char * hl = bb_get_chomped_line_from_file(fp);
 			int l;
@@ -1177,8 +1236,8 @@
 			history [hi++] = hl;
 		}
 		fclose ( fp );
+		cur_history = n_history = hi;
 	}
-	cur_history = n_history = hi;
 }

 extern void save_history ( const char *tofile )
@@ -1282,6 +1341,12 @@
 			break;
 		case 3:
 			/* Control-c -- stop gathering input */
+#if MAX_HISTORY >= 1
+			/* set the last entry as the current and erase it */
+			cur_history = n_history;
+			if (history[n_history])
+				history[n_history][0] = 0;
+#endif
 			goto_new_line();
 #ifndef CONFIG_ASH
 			command[0] = 0;
@@ -1350,12 +1415,8 @@
 			break;
 		case 16:
 			/* Control-p -- Get previous command from history */
-			if (cur_history > 0) {
-				get_previous_history();
+			if (get_previous_history())
 				goto rewrite_line;
-			} else {
-				beep();
-			}
 			break;
 #endif
 		case 21:
@@ -1372,24 +1433,45 @@
 			while (cursor > 0 &&!isspace(command[cursor-1]))
 				input_backspace();
 			break;
-		case ESC:{
+		case ESC:{
+			unsigned char seq[6], *seq_ptr = seq;
+			int seq_len = safe_read(0, seq, 6);
+
 			/* escape sequence follows */
-			if (safe_read(0, &c, 1) < 1)
+			if (seq_len < 1)
 				goto prepare_to_die;
+
 			/* different vt100 emulations */
-			if (c == '[' || c == 'O') {
-				if (safe_read(0, &c, 1) < 1)
-					goto prepare_to_die;
+			if (seq[0] == '[' || seq[0] == 'O') {
+				seq_ptr++;
+				seq_len--;
 			}
-			if (c >= '1' && c <= '9') {
-				unsigned char dummy;
-
-				if (safe_read(0, &dummy, 1) < 1)
-					goto prepare_to_die;
-				if(dummy != '~')
+			if (seq_len == 4) {
+				if (!strncmp(seq_ptr, "1;5C", 4)) { /* Ctrl + right */
+					input_word_forward();
+				} else if (!strncmp(seq_ptr, "1;5D", 4)) { /* Ctrl + left */
+					input_word_backward();
+				} else if (!strncmp(seq_ptr, "1;5F", 4)) { /* Ctrl + end */
+					cur_history = n_history;
+					goto rewrite_line;
+				} else if (!strncmp(seq_ptr, "3;5~", 4)) { /* Ctrl + del */
+					input_word_delete();
+				} else {
+					printf("<%x %x %x %x>",
+						seq_ptr[0], seq_ptr[1], seq_ptr[2], seq_ptr[3]);
+					c = 0;
+				}
+				break;
+			} else if (seq_len == 3) {
+				printf("<%x %x %x>", seq_ptr[0], seq_ptr[1], seq_ptr[2]);
+				c = 0;
+			} else if (seq_len == 2) {
+				if (seq_ptr[0] < '1' || '9' < seq_ptr[0] || seq_ptr[1] != '~') {
+					printf("<%x %x>", seq_ptr[0], seq_ptr[1]);
 					c = 0;
+				}
 			}
-			switch (c) {
+			switch (seq_ptr[0]) {
 #ifdef CONFIG_FEATURE_COMMAND_TAB_COMPLETION
 			case '\t':                      /* Alt-Tab */

@@ -1399,17 +1481,13 @@
 #if MAX_HISTORY >= 1
 			case 'A':
 				/* Up Arrow -- Get previous command from history */
-				if (cur_history > 0) {
-					get_previous_history();
-					goto rewrite_line;
-				} else {
-					beep();
-				}
+				if (get_previous_history())
+					goto rewrite_line;
 				break;
 			case 'B':
 				/* Down Arrow -- Get next command in history */
 				if (!get_next_history())
-				break;
+					break;
 				/* Rewrite the line with the selected history item */
 rewrite_line:
 				/* change command */
diff -ur -x .svn -x '*.o.cmd' -x '*.o' nX_linux_r4/petalinux-dist/user/busybox/shell/cmdedit.h nX_linux/petalinux-dist/user/busybox/shell/cmdedit.h
--- nX_linux_r4/petalinux-dist/user/busybox/shell/cmdedit.h	2009-08-07 15:55:20.000000000 +0200
+++ nX_linux/petalinux-dist/user/busybox/shell/cmdedit.h	2009-08-07 15:55:54.000000000 +0200
@@ -8,6 +8,7 @@
 #endif

 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
+#define HISTVAR		"HISTFILE"
 void    load_history ( const char *fromfile );
 void    save_history ( const char *tofile );
 #endif
diff -ur -x .svn -x '*.o.cmd' -x '*.o' nX_linux_r4/petalinux-dist/user/busybox/shell/Config.in nX_linux/petalinux-dist/user/busybox/shell/Config.in
--- nX_linux_r4/petalinux-dist/user/busybox/shell/Config.in	2009-08-07 15:55:20.000000000 +0200
+++ nX_linux/petalinux-dist/user/busybox/shell/Config.in	2009-08-07 15:55:54.000000000 +0200
@@ -206,7 +206,7 @@
 config CONFIG_FEATURE_COMMAND_SAVEHISTORY
 	bool "history saving"
 	default n
-	depends on CONFIG_ASH && CONFIG_FEATURE_COMMAND_EDITING
+	depends on (CONFIG_MSH || CONFIG_ASH) && CONFIG_FEATURE_COMMAND_EDITING
 	help
 	  Enable history saving in ash shell.

diff -ur -x .svn -x '*.o.cmd' -x '*.o' nX_linux_r4/petalinux-dist/user/busybox/shell/msh.c nX_linux/petalinux-dist/user/busybox/shell/msh.c
--- nX_linux_r4/petalinux-dist/user/busybox/shell/msh.c	2009-08-07 15:55:20.000000000 +0200
+++ nX_linux/petalinux-dist/user/busybox/shell/msh.c	2009-08-07 15:55:54.000000000 +0200
@@ -45,8 +45,8 @@
 #include <sys/types.h>
 #include <sys/wait.h>

-#include "cmdedit.h"
 #include "busybox.h"
+#include "cmdedit.h"


 /* Conditional use of "register" keyword */
@@ -812,6 +812,22 @@
 static char *current_prompt;
 #endif

+#define PROMPT_SUFFIX_LEN    2
+#define PROMPT_LEN           256
+
+char current_prompt_buf[PROMPT_LEN];
+
+static void current_prompt_cwd(void)
+{
+	char *ret = getcwd(current_prompt_buf, PROMPT_LEN - PROMPT_SUFFIX_LEN);
+
+	if (ret)
+		current_prompt = strcat(current_prompt_buf, prompt->value);
+	else
+		current_prompt = prompt->value;
+}
+
+
 /* -------- sh.c -------- */
 /*
  * shell
@@ -963,20 +979,24 @@
 #endif
 		}
 	}
-
+
 	signal(SIGQUIT, qflag);
 	if (name && name[0] == '-') {
 		interactive++;
+	}
+
+	if (interactive) {
 		if ((f = open(".profile", 0)) >= 0)
 			next(remap(f));
 		if ((f = open("/etc/profile", 0)) >= 0)
 			next(remap(f));
-	}
-	if (interactive)
+
 		signal(SIGTERM, sig);

+	}
 	if (signal(SIGINT, SIG_IGN) != SIG_IGN)
 		signal(SIGINT, onintr);
+
 	dolv = argv;
 	dolc = argc;
 	dolv[0] = name;
@@ -989,14 +1009,27 @@
 			}
 		}
 	}
+
 	setval(lookup("#"), putn((--dolc < 0) ? (dolc = 0) : dolc));

 	DBGPRINTF(("MSH_MAIN: begin FOR loop, interactive %d, e.iop 0x%x, iostack 0x%x\n", interactive, e.iop, iostack));

+	while (iostack < e.iop )
+		onecommand();
+
+#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
+	if (interactive)
+	{
+		struct var *hp = lookup(HISTVAR);
+		//printf ("Loading hist into %s\n", hp->value);
+        if (hp->value != null) load_history(hp->value);
+	}
+#endif
+
 	for (;;) {
 		if (interactive && e.iop <= iostack) {
 #ifdef CONFIG_FEATURE_COMMAND_EDITING
-			current_prompt = prompt->value;
+			current_prompt_cwd();
 #else
 			prs(prompt->value);
 #endif
@@ -1150,6 +1183,15 @@
 static void leave()
 {
 	DBGPRINTF(("LEAVE: leave called!\n"));
+
+#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
+	if (interactive)
+	{
+		struct var *hp = lookup(HISTVAR);
+		//printf ("Saving hist into %s\n", hp->value);
+	    if (hp->value != null) save_history(hp->value);
+	}
+#endif

 	if (execflg)
 		fail();
@@ -4831,7 +4873,7 @@
 				}
 				if (interactive && e.iop == iostack + 1) {
 #ifdef CONFIG_FEATURE_COMMAND_EDITING
-					current_prompt = prompt->value;
+					current_prompt_cwd();
 #else
 					prs(prompt->value);
 #endif

___________________________
microblaze-uclinux mailing list
microblaze-uclinux@xxxxxxxxxxxxxx
Project Home Page : http://www.itee.uq.edu.au/~jwilliams/mblaze-uclinux
Mailing List Archive : http://www.itee.uq.edu.au/~listarch/microblaze-uclinux/