[BusyBox] enhanced cmdedit
Stefani Seibold
stefani at seibold.net
Tue Jan 20 16:59:10 UTC 2004
Hi folks,
below a patch against busybox-1.00-pre5.
- First it fix a small bug in the tab command completion.
Currently the tab command completion use only the pathes in the
enviroment variable path and not the acutal defined path variable in the shell.
This is a bad behavior because it make it necessary to invoke a new shell for tab
completion with the new defined path.
- Second it enables incremental search in the command history
You can use now CTRL-R for reverse incremental search and CTRL-S for
forward incremental search in the command history like in the bash shell. The
behavior is mostly like the bash shell.
This is a very especial usefull feature for embedded developer when testing and
working on the target.
- Third it enables to jump to the bottom or top of the history
The page up and page down key jumps now to the top or bottom
of the hisotry.
This is still also very usefull for embedded developers.
Please apply the patch to the current development tree if you like.
Have fun,
Stefani
----------------------------------------------------------------------------------------
diff -ru busybox-1.00-pre5.orig/shell/ash.c busybox-1.00-pre5/shell/ash.c
--- busybox-1.00-pre5.orig/shell/ash.c 2003-11-25 21:45:38.000000000 +0100
+++ busybox-1.00-pre5/shell/ash.c 2004-01-12 11:58:27.000000000 +0100
@@ -6041,6 +6041,9 @@
if (!iflag || parsefile->fd)
nr = safe_read(parsefile->fd, buf, BUFSIZ - 1);
else {
+#ifdef CONFIG_FEATURE_COMMAND_TAB_COMPLETION
+ cmdedit_comp_path = lookupvar("PATH");
+#endif
nr = cmdedit_read_input((char *) cmdedit_prompt, buf);
if(nr == 0) {
/* Ctrl+C presend */
diff -ru busybox-1.00-pre5.orig/shell/cmdedit.c busybox-1.00-pre5/shell/cmdedit.c
--- busybox-1.00-pre5.orig/shell/cmdedit.c 2003-09-15 10:33:40.000000000 +0200
+++ busybox-1.00-pre5/shell/cmdedit.c 2004-01-20 14:48:26.000000000 +0100
@@ -96,6 +96,8 @@
#define MAX_HISTORY CONFIG_FEATURE_COMMAND_HISTORY
#endif
+char *cmdedit_comp_path;
+
#if MAX_HISTORY < 1
#warning cmdedit: You set MAX_HISTORY < 1. The history algorithm switched off.
#else
@@ -110,6 +112,11 @@
#define setTermSettings(fd,argp) tcsetattr(fd,TCSANOW,argp)
#define getTermSettings(fd,argp) tcgetattr(fd, argp);
+enum {
+ ESC = 27,
+ DEL = 127,
+};
+
/* Current termio and the previous termio before starting sh */
static struct termios initial_settings, new_settings;
@@ -261,6 +268,7 @@
static inline void beep(void)
{
putchar('\007');
+ fflush(stdout);
}
/* Move back one charactor */
@@ -308,7 +316,6 @@
{
cmdedit_prompt = prmt_ptr;
cmdedit_prmt_len = strlen(prmt_ptr);
- put_prompt();
}
#else
static void parse_prompt(const char *prmt_ptr)
@@ -428,7 +435,6 @@
free(pwd_buf);
cmdedit_prompt = prmt_mem_ptr;
cmdedit_prmt_len = prmt_len - sub_len;
- put_prompt();
}
#endif
@@ -616,16 +622,16 @@
{
int npth;
char *tmp;
- char *pth;
/* if not setenv PATH variable, to search cur dir "." */
- if (flags != FIND_EXE_ONLY || (pth = getenv("PATH")) == 0 ||
+ if (flags != FIND_EXE_ONLY ||
/* PATH=<empty> or PATH=:<empty> */
- *pth == 0 || (*pth == ':' && *(pth + 1) == 0)) {
+ *cmdedit_comp_path == 0 ||
+ (*cmdedit_comp_path == ':' && *(cmdedit_comp_path + 1) == 0)) {
return 1;
}
- tmp = pth;
+ tmp = cmdedit_comp_path;
npth = 0;
for (;;) {
@@ -640,19 +646,19 @@
*p = xmalloc(npth * sizeof(char *));
- tmp = pth;
+ tmp = cmdedit_comp_path;
(*p)[0] = bb_xstrdup(tmp);
npth = 1; /* count words is + 1 count ':' */
for (;;) {
tmp = strchr(tmp, ':');
if (tmp) {
- (*p)[0][(tmp - pth)] = 0; /* ':' -> '\0' */
+ (*p)[0][(tmp - cmdedit_comp_path)] = 0; /* ':' -> '\0' */
if (*++tmp == 0)
break; /* :<empty> */
} else
break;
- (*p)[npth++] = &(*p)[0][(tmp - pth)]; /* p[next]=p[0][&'\0'+1] */
+ (*p)[npth++] = &(*p)[0][(tmp - cmdedit_comp_path)]; /* p[next]=p[0][&'\0'+1] */
}
return npth;
@@ -1122,26 +1128,211 @@
#endif /* CONFIG_FEATURE_COMMAND_TAB_COMPLETION */
#if MAX_HISTORY >= 1
-static void get_previous_history(void)
+static void store_history(void)
{
if(command_ps[0] != 0 || history[cur_history] == 0) {
free(history[cur_history]);
history[cur_history] = bb_xstrdup(command_ps);
}
+}
+
+static void get_previous_history(void)
+{
+ store_history();
cur_history--;
}
static int get_next_history(void)
{
- int ch = cur_history;
+ if (cur_history < n_history) {
+ store_history(); /* save the current history line */
+ return ++cur_history;
+ }
+ beep();
+ return 0;
+}
+
+static int find_str(char *s1,char *s2,int s1_len,int c)
+{
+ int s2_len;
+ int i;
- if (ch < n_history) {
- get_previous_history(); /* save the current history line */
- return (cur_history = ch+1);
- } else {
+ s2_len=strlen(s2);
+
+ for(i=0;i+s1_len<=s2_len;i++) {
+
+ if ((strncmp(s1,s2+i,s1_len)==0)&&((c<0)||(s2[i+s1_len]==c)))
+ return i;
+ }
+ return -1;
+}
+
+static int find_history(int idx, int last,int searchLen,int c,int dir)
+{
+ int ret;
+
+ do {
+ ret=find_str(command_ps+cursor,history[idx],searchLen,c);
+ if (ret>=0) {
+ cursor=ret;
+
+ if (idx==cur_history)
+ return 0;
+
+ if (strcmp(history[cur_history],history[idx])) {
+ cur_history=idx;
+ len=strlen(strcpy(command_ps,history[cur_history]));
+ return 1;
+ }
+ }
+ idx+=dir;
+ } while(idx!=last);
+
+ return -1;
+}
+
+static void histPrompt(char *promptBuf,char *promptStr,int searchLen)
+{
+ int sav_cursor;
+
+ cmdedit_prmt_len = strlen(promptStr);
+ cmdedit_prompt = promptBuf;
+
+ memcpy(promptBuf,promptStr,cmdedit_prmt_len);
+
+ promptBuf+=cmdedit_prmt_len;
+
+ memcpy(promptBuf,command_ps+cursor,searchLen);
+
+ promptBuf+=searchLen;
+
+ *promptBuf++='\'';
+ *promptBuf++=':';
+ *promptBuf++=' ';
+
+ *promptBuf=0;
+
+ cmdedit_prmt_len+=searchLen + 3;
+
+ sav_cursor=cursor;
+
+ redraw(cmdedit_y, len - cursor);
+
+ cursor=sav_cursor;
+
+ fflush(stdout); /* buffered out to fast */
+}
+
+static int searchHistory(char *histPromptStr,int first,int last,int dir)
+{
+ unsigned char c = 0;
+ int searchLen;
+ int ret;
+ char *histPromptBuf;
+
+ if (n_history==0) {
beep();
+
return 0;
}
+
+ histPromptBuf = xmalloc(BUFSIZ+strlen(histPromptStr)+3);
+
+#if !defined(CONFIG_ASH)
+ lastWasTab = FALSE;
+#endif
+ searchLen=-1;
+
+ histPrompt(histPromptBuf,histPromptStr,0);
+
+ while(safe_read(0, &c, 1) >= 1) {
+
+ switch(c){
+ case 3:
+ /* Control-c -- stop gathering input */
+ *command_ps = 0;
+ len = 0;
+ free(histPromptBuf);
+ return 2;
+ case '\n':
+ case '\r':
+ /* Enter */
+ free(histPromptBuf);
+ return 1;
+ case ESC:
+ free(histPromptBuf);
+ return 0;
+ case '\b':
+ case DEL:
+ /* Control-h and DEL */
+ if (searchLen<=0) {
+ beep();
+
+ break;
+ }
+ searchLen--;
+
+ histPrompt(histPromptBuf,histPromptStr,searchLen);
+
+ break;
+ case 18:
+ if (searchLen<=0) {
+ beep();
+
+ break;
+ }
+ ret=find_str(command_ps+cursor,history[cur_history]+cursor+1,searchLen,-1);
+ if (ret>=0) {
+ cursor+=ret+1;
+ histPrompt(histPromptBuf,histPromptStr,searchLen);
+
+ break;
+ }
+ if ((cur_history==0)||(find_history(cur_history+dir,last,searchLen,-1,dir))<0) {
+ beep();
+
+ break;
+ }
+ histPrompt(histPromptBuf,histPromptStr,searchLen);
+
+ break;
+ default:
+ if (!Isprint(c)) /* Skip non-printable characters */
+ break;
+
+ if (searchLen<0) {
+ cur_history=n_history;
+
+ store_history();
+
+ if (find_history(first,0,0,c,dir)<0) {
+ beep();
+
+ break;
+ }
+ searchLen=1;
+ }
+ else {
+ if (find_history(cur_history,0,searchLen,c,dir)<0) {
+ beep();
+
+ break;
+ }
+ searchLen++;
+ }
+ histPrompt(histPromptBuf,histPromptStr,searchLen);
+
+ break;
+ }
+ }
+ free(histPromptBuf);
+#if !defined(CONFIG_ASH)
+ printf("exit");
+ goto_new_line();
+ /* cmdedit_reset_term() called in atexit */
+ exit(EXIT_SUCCESS);
+#endif
+ return -1;
}
#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
@@ -1197,12 +1388,6 @@
#endif
-enum {
- ESC = 27,
- DEL = 127,
-};
-
-
/*
* This function is used to grab a character buffer
* from the input file descriptor and allows you to
@@ -1257,6 +1442,7 @@
cmdedit_init();
/* Print out the command prompt */
parse_prompt(prompt);
+ put_prompt();
while (1) {
@@ -1283,7 +1469,6 @@
break;
case 3:
/* Control-c -- stop gathering input */
- goto_new_line();
command[0] = 0;
len = 0;
#if !defined(CONFIG_ASH)
@@ -1355,6 +1540,24 @@
beep();
}
break;
+ case 18:
+ /* Control-R -- Search reverse history buffer */
+ break_out=searchHistory("(reverse-i-search)`",n_history-1,0,-1);
+ parse_prompt(prompt);
+ redraw(cmdedit_y, len - cursor);
+ if (break_out==1)
+ goto_new_line();
+ fflush(stdout);
+ break;
+ case 19:
+ /* Control-S -- Search history buffer */
+ break_out=searchHistory("(i-search)`",0,n_history-1, 1);
+ parse_prompt(prompt);
+ redraw(cmdedit_y, len - cursor);
+ if (break_out==1)
+ goto_new_line();
+ fflush(stdout);
+ break;
#endif
case 21:
/* Control-U -- Clear line before cursor */
@@ -1423,6 +1626,26 @@
/* End (Ctrl-E) */
input_end();
break;
+ case '5':
+ /* first history entry */
+ if (n_history==0) {
+ beep();
+
+ break;
+ }
+ store_history();
+ cur_history=0;
+ goto rewrite_line;
+ case '6':
+ /* last history entry */
+ if (n_history==0) {
+ beep();
+
+ break;
+ }
+ store_history();
+ cur_history=n_history-1;
+ goto rewrite_line;
default:
if (!(c >= '1' && c <= '9'))
c = 0;
@@ -1490,19 +1713,22 @@
free(history[MAX_HISTORY]);
history[MAX_HISTORY] = 0;
if (len) { /* no put empty line */
- int i = n_history;
- /* After max history, remove the oldest command */
- if (i >= MAX_HISTORY) {
- free(history[0]);
- for(i = 0; i < (MAX_HISTORY-1); i++)
- history[i] = history[i+1];
- }
- history[i++] = bb_xstrdup(command);
- cur_history = i;
- n_history = i;
+ /* don't waist history with consecutive repeating identical commands */
+ if ((n_history==0)||(strcmp(history[n_history-1],command)!=0)){
+ int i = n_history;
+ /* After max history, remove the oldest command */
+ if (i >= MAX_HISTORY) {
+ free(history[0]);
+ for(i = 0; i < (MAX_HISTORY-1); i++)
+ history[i] = history[i+1];
+ }
+ history[i++] = bb_xstrdup(command);
+ cur_history = i;
+ n_history = i;
#if defined(CONFIG_FEATURE_SH_FANCY_PROMPT)
- num_ok_lines++;
+ num_ok_lines++;
#endif
+ }
}
#else /* MAX_HISTORY < 1 */
#if defined(CONFIG_FEATURE_SH_FANCY_PROMPT)
diff -ru busybox-1.00-pre5.orig/shell/cmdedit.h busybox-1.00-pre5/shell/cmdedit.h
--- busybox-1.00-pre5.orig/shell/cmdedit.h 2002-12-09 12:10:40.000000000 +0100
+++ busybox-1.00-pre5/shell/cmdedit.h 2004-01-12 11:59:03.000000000 +0100
@@ -1,5 +1,7 @@
#ifndef CMDEDIT_H
#define CMDEDIT_H
+
+extern char *cmdedit_comp_path;
int cmdedit_read_input(char* promptStr, char* command);
diff -ru busybox-1.00-pre5.orig/shell/hush.c busybox-1.00-pre5/shell/hush.c
--- busybox-1.00-pre5.orig/shell/hush.c 2003-07-14 23:21:05.000000000 +0200
+++ busybox-1.00-pre5/shell/hush.c 2004-01-12 11:56:26.000000000 +0100
@@ -908,6 +908,9 @@
** atexit() handlers and other unwanted stuff to our
** child processes (rob at sysgo.de)
*/
+#ifdef CONFIG_FEATURE_COMMAND_TAB_COMPLETION
+ cmdedit_comp_path = getenv("PATH");
+#endif
cmdedit_read_input(prompt_str, the_command);
#else
fputs(prompt_str, stdout);
diff -ru busybox-1.00-pre5.orig/shell/lash.c busybox-1.00-pre5/shell/lash.c
--- busybox-1.00-pre5.orig/shell/lash.c 2003-07-14 23:21:05.000000000 +0200
+++ busybox-1.00-pre5/shell/lash.c 2004-01-12 11:55:25.000000000 +0100
@@ -710,6 +710,9 @@
** atexit() handlers and other unwanted stuff to our
** child processes (rob at sysgo.de)
*/
+#ifdef CONFIG_FEATURE_COMMAND_TAB_COMPLETION
+ cmdedit_comp_path = getenv("PATH");
+#endif
cmdedit_read_input(prompt_str, command);
return 0;
#else
diff -ru busybox-1.00-pre5.orig/shell/msh.c busybox-1.00-pre5/shell/msh.c
--- busybox-1.00-pre5.orig/shell/msh.c 2003-09-02 04:36:18.000000000 +0200
+++ busybox-1.00-pre5/shell/msh.c 2004-01-12 11:53:43.000000000 +0100
@@ -4550,6 +4550,9 @@
static int position = 0, size = 0;
while (size == 0 || position >= size) {
+#ifdef CONFIG_FEATURE_COMMAND_TAB_COMPLETION
+ cmdedit_comp_path = lookup("PATH");
+#endif
cmdedit_read_input(current_prompt, mycommand);
size = strlen(mycommand);
position = 0;
More information about the busybox
mailing list