[BusyBox] enhanced busybox cmdedit 2nd try

seibold seibold at seibold.net
Wed Feb 4 14:37:17 UTC 2004


Hi there,

below attached is the newest enhanced cmdedit against the current cvs tree. I realized all suggestions about the last version.
  
With this patch you can use now CTRL-R and CTRL-S for incremental search in the command history like in the bash shell. This is a very especial usefull feature for embedded developer when testing and working on the target.

The feature is now configureable and can be switched on and off at compile time.

Hope the patch will be applied.

Thnx,
Stefani Seibold

-------------- next part --------------
--- busybox/shell/cmdedit.c.orig	Thu Jan 22 13:42:23 2004
+++ busybox/shell/cmdedit.c	Wed Feb  4 14:29:27 2004
@@ -10,6 +10,7 @@
  *      Dave Cinege      <dcinege at psychosis.com>
  *      Jakub Jelinek (c) 1995
  *      Erik Andersen    <andersen at codepoet.org> (Majorly adjusted for busybox)
+ *      Stefani Seibold  <stefani at seibold.net> (incremental search)
  *
  * This code is 'as is' with no warranty.
  *
@@ -106,6 +107,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;
 
@@ -257,6 +263,7 @@
 static inline void beep(void)
 {
 	putchar('\007');
+	fflush(stdout);
 }
 
 /* Move back one charactor */
@@ -304,7 +311,6 @@
 {
 	cmdedit_prompt = prmt_ptr;
 	cmdedit_prmt_len = strlen(prmt_ptr);
-	put_prompt();
 }
 #else
 static void parse_prompt(const char *prmt_ptr)
@@ -424,7 +430,6 @@
 		free(pwd_buf);
 	cmdedit_prompt = prmt_mem_ptr;
 	cmdedit_prmt_len = prmt_len - sub_len;
-	put_prompt();
 }
 #endif
 
@@ -1124,27 +1129,196 @@
 #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;
+}
 
-	if (ch < n_history) {
-		get_previous_history(); /* save the current history line */
-		return (cur_history = ch+1);
-	} else {
+#ifdef CONFIG_FEATURE_COMMAND_FANCYHISTORY
+static int find_str(char *s1,char *s2,int s1_len,int c)
+{
+	int	s2_len;
+	int i;
+
+	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 *promptStr,int searchLen)
+{
+	int	sav_cursor;
+	char *promptBuf;
+
+	cmdedit_prmt_len = strlen(promptStr);
+	cmdedit_prompt = xmalloc(BUFSIZ+strlen(promptStr)+3);
+
+	promptBuf=(char *)cmdedit_prompt;
+	memcpy(promptBuf,promptStr,cmdedit_prmt_len);
+	promptBuf+=cmdedit_prmt_len;
+	memcpy(promptBuf,command_ps+cursor,searchLen);
+	promptBuf+=searchLen;
+	strcpy(promptBuf,"\': ");
+	cmdedit_prmt_len+=searchLen + 3;
+
+	sav_cursor=cursor;
+	redraw(cmdedit_y, len - cursor);
+	cursor=sav_cursor;
+	fflush(stdout);
+
+	free((char *)cmdedit_prompt);
+}
+
+static int searchHistory(char *histPromptStr,int first,int last,int dir)
+{
+	unsigned char c = 0;
+	int	searchLen;
+	int	ret;
+
+	if (n_history==0) {
 		beep();
+
 		return 0;
 	}
+
+#if !defined(CONFIG_ASH)
+	lastWasTab = FALSE;
+#endif
+	searchLen=-1;
+
+	histPrompt(histPromptStr,0);
+
+	while(safe_read(0, &c, 1) >= 1) {
+
+		switch(c){
+		case 3:
+			/* Control-c -- stop gathering input */
+			*command_ps = 0;
+			len = 0;
+			return 2;
+		case '\n':
+		case '\r':
+			/* Enter */
+			return 1;
+		case ESC:
+			return 0;
+		case '\b':
+		case DEL:
+			/* Control-h and DEL */
+			if (searchLen<=0) {
+				beep();
+				
+				continue;
+			}
+			searchLen--;
+
+			find_history(first,last,searchLen,-1,dir);
+
+			break;
+		case 18:
+			if (searchLen<=0) {
+				beep();
+					
+				continue;
+			}
+			ret=find_str(command_ps+cursor,history[cur_history]+cursor+1,searchLen,-1);
+			if (ret>=0) {
+				cursor+=ret+1;
+
+				continue;
+			}
+			if ((cur_history==0)||(find_history(cur_history+dir,last,searchLen,-1,dir))<0) {
+				beep();
+				
+				continue;
+			}
+
+			break;
+		default:
+			if (!Isprint(c))        /* Skip non-printable characters */
+				continue;
+
+			if (searchLen<0) {
+				cur_history=n_history;
+
+				store_history();
+
+				if (find_history(first,last,0,c,dir)<0) {
+					beep();
+
+					continue;
+				}
+				searchLen=1;
+			}
+			else {
+				if (find_history(cur_history,last,searchLen,c,dir)<0) {
+					beep();
+
+					continue;
+				}
+				searchLen++;
+			}
+			break;
+		}
+		histPrompt(histPromptStr,searchLen);
+	}
+#if !defined(CONFIG_ASH)
+	printf("exit");
+	goto_new_line();
+	/* cmdedit_reset_term() called in atexit */
+	exit(EXIT_SUCCESS);
+#endif
+	return -1;
 }
+#endif
 
 #ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY
 extern void load_history ( const char *fromfile )
@@ -1198,12 +1372,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
@@ -1256,6 +1424,7 @@
 	cmdedit_init();
 	/* Print out the command prompt */
 	parse_prompt(prompt);
+	put_prompt();
 
 	while (1) {
 
@@ -1282,7 +1451,6 @@
 			break;
 		case 3:
 			/* Control-c -- stop gathering input */
-			goto_new_line();
 			command[0] = 0;
 			len = 0;
 			lastWasTab = FALSE;
@@ -1350,6 +1518,26 @@
 				beep();
 			}
 			break;
+#ifdef CONFIG_FEATURE_COMMAND_FANCYHISTORY
+		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
 #endif
 		case 21:
 			/* Control-U -- Clear line before cursor */
@@ -1433,6 +1621,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:
 				c = 0;
 				beep();
@@ -1494,19 +1702,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)
--- busybox/shell/Config.in.orig	Sat Jan  3 13:07:32 2004
+++ busybox/shell/Config.in	Wed Feb  4 13:59:18 2004
@@ -203,4 +203,11 @@
 	  Setting this option allows for prompts to use things like \w and
 	  \$ and also using escape codes.
 
+config CONFIG_FEATURE_COMMAND_FANCYHISTORY
+	bool "Fancy command history functions"
+	default n
+	depends on CONFIG_FEATURE_COMMAND_EDITING
+	help
+	  Enable incremental search in history (CTRL-S & CTRL-R)
+
 endmenu



More information about the busybox mailing list