[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/