[PATCH] ash: perform autocompletion on builtin commands

Matteo Croce matteo at openwrt.org
Fri Oct 24 14:54:21 UTC 2014


Refactor read_line_input to accept a list of strings which are
added byt the autocompletion suggestions.
Let ash pass the builtin command list to read_line_input to enable
completion of builtin commands as echo, printf, history, exec, etc.
---
 editors/ed.c       |  6 +++---
 include/libbb.h    |  2 +-
 libbb/lineedit.c   | 17 ++++++++++++-----
 shell/ash.c        |  8 +++++++-
 shell/hush.c       |  2 +-
 util-linux/fdisk.c |  2 +-
 6 files changed, 25 insertions(+), 12 deletions(-)

diff --git a/editors/ed.c b/editors/ed.c
index 3087fb0..812580f 100644
--- a/editors/ed.c
+++ b/editors/ed.c
@@ -144,7 +144,7 @@ static void doCommands(void)
 		 * 0  on ctrl-C,
 		 * >0 length of input string, including terminating '\n'
 		 */
-		len = read_line_input(NULL, ": ", buf, sizeof(buf), /*timeout*/ -1);
+		len = read_line_input(NULL, ": ", buf, sizeof(buf), /*timeout*/ -1, NULL);
 		if (len <= 0)
 			return;
 		endbuf = &buf[len - 1];
@@ -242,7 +242,7 @@ static void doCommands(void)
 			}
 			if (!dirty)
 				return;
-			len = read_line_input(NULL, "Really quit? ", buf, 16, /*timeout*/ -1);
+			len = read_line_input(NULL, "Really quit? ", buf, 16, /*timeout*/ -1, NULL);
 			/* read error/EOF - no way to continue */
 			if (len < 0)
 				return;
@@ -556,7 +556,7 @@ static void addLines(int num)
 		 * 0  on ctrl-C,
 		 * >0 length of input string, including terminating '\n'
 		 */
-		len = read_line_input(NULL, "", buf, sizeof(buf), /*timeout*/ -1);
+		len = read_line_input(NULL, "", buf, sizeof(buf), /*timeout*/ -1, NULL);
 		if (len <= 0) {
 			/* Previously, ctrl-C was exiting to shell.
 			 * Now we exit to ed prompt. Is in important? */
diff --git a/include/libbb.h b/include/libbb.h
index d57f00e..c384f11 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -1505,7 +1505,7 @@ line_input_t *new_line_input_t(int flags) FAST_FUNC;
  * 0  on ctrl-C (the line entered is still returned in 'command'),
  * >0 length of input string, including terminating '\n'
  */
-int read_line_input(line_input_t *st, const char *prompt, char *command, int maxsize, int timeout) FAST_FUNC;
+int read_line_input(line_input_t *st, const char *prompt, char *command, int maxsize, int timeout, char *completions[]) FAST_FUNC;
 void show_history(const line_input_t *st) FAST_FUNC;
 # if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
 void save_history(line_input_t *st);
diff --git a/libbb/lineedit.c b/libbb/lineedit.c
index 8564307..270445a 100644
--- a/libbb/lineedit.c
+++ b/libbb/lineedit.c
@@ -746,7 +746,7 @@ static int path_parse(char ***p)
 /* Complete command, directory or file name.
  * Return the length of the prefix used for matching.
  */
-static NOINLINE unsigned complete_cmd_dir_file(const char *command, int type)
+static NOINLINE unsigned complete_cmd_dir_file(const char *command, int type, char **completions)
 {
 	char *path1[1];
 	char **paths = path1;
@@ -828,6 +828,13 @@ static NOINLINE unsigned complete_cmd_dir_file(const char *command, int type)
 		closedir(dir);
 	} /* for every path */
 
+	if (completions && type == FIND_EXE_ONLY) {
+		int len = strlen(command);
+		for(i = 0; completions[i]; i++)
+			if(!strncmp(command, completions[i], len))
+				add_match(xstrdup(completions[i]));
+	}
+
 	if (paths != path1) {
 		free(paths[0]); /* allocated memory is only in first member */
 		free(paths);
@@ -1070,7 +1077,7 @@ static char *quote_special_chars(char *found)
 }
 
 /* Do TAB completion */
-static NOINLINE void input_tab(smallint *lastWasTab)
+static NOINLINE void input_tab(smallint *lastWasTab, char **completions)
 {
 	char *chosen_match;
 	char *match_buf;
@@ -1134,7 +1141,7 @@ static NOINLINE void input_tab(smallint *lastWasTab)
 	/* If complete_username() did not match,
 	 * try to match a command in $PATH, or a directory, or a file */
 	if (!matches)
-		match_pfx_len = complete_cmd_dir_file(match_buf, find_type);
+		match_pfx_len = complete_cmd_dir_file(match_buf, find_type, completions);
 
 	/* Account for backslashes which will be inserted
 	 * by quote_special_chars() later */
@@ -2239,7 +2246,7 @@ static int32_t reverse_i_search(void)
  * 0  on ctrl-C (the line entered is still returned in 'command'),
  * >0 length of input string, including terminating '\n'
  */
-int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *command, int maxsize, int timeout)
+int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *command, int maxsize, int timeout, char **completions)
 {
 	int len;
 #if ENABLE_FEATURE_TAB_COMPLETION
@@ -2412,7 +2419,7 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman
 			break;
 #if ENABLE_FEATURE_TAB_COMPLETION
 		case '\t':
-			input_tab(&lastWasTab);
+			input_tab(&lastWasTab, completions);
 			break;
 #endif
 		case CTRL('K'):
diff --git a/shell/ash.c b/shell/ash.c
index 705fe9f..e3d2354 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -9674,7 +9674,9 @@ preadfd(void)
 	if (!iflag || g_parsefile->pf_fd != STDIN_FILENO)
 		nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1, /*loop_on_EINTR:*/ 1);
 	else {
+		int i;
 		int timeout = -1;
+		char *builtins[(ARRAY_SIZE(builtintab) + 1) * sizeof(char *)];
 # if ENABLE_ASH_IDLE_TIMEOUT
 		if (iflag) {
 			const char *tmout_var = lookupvar("TMOUT");
@@ -9687,9 +9689,13 @@ preadfd(void)
 # endif
 # if ENABLE_FEATURE_TAB_COMPLETION
 		line_input_state->path_lookup = pathval();
+		for (i = 0; i < ARRAY_SIZE(builtintab); i++)
+				builtins[i] = builtintab[i].name + 1;
+		builtins[i] = 0;
 # endif
 		reinit_unicode_for_ash();
-		nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ, timeout);
+		nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ, timeout, builtins);
+
 		if (nr == 0) {
 			/* Ctrl+C pressed */
 			if (trap[SIGINT]) {
diff --git a/shell/hush.c b/shell/hush.c
index 92d7901..603ae17 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -2066,7 +2066,7 @@ static void get_user_input(struct in_str *i)
 		G.flag_SIGINT = 0;
 		/* buglet: SIGINT will not make new prompt to appear _at once_,
 		 * only after <Enter>. (^C will work) */
-		r = read_line_input(G.line_input_state, prompt_str, G.user_input_buf, CONFIG_FEATURE_EDITING_MAX_LEN-1, /*timeout*/ -1);
+		r = read_line_input(G.line_input_state, prompt_str, G.user_input_buf, CONFIG_FEATURE_EDITING_MAX_LEN-1, /*timeout*/ -1, NULL);
 		/* catch *SIGINT* etc (^C is handled by read_line_input) */
 		check_and_run_traps();
 	} while (r == 0 || G.flag_SIGINT); /* repeat if ^C or SIGINT */
diff --git a/util-linux/fdisk.c b/util-linux/fdisk.c
index 39eb27b..bdf98ea 100644
--- a/util-linux/fdisk.c
+++ b/util-linux/fdisk.c
@@ -569,7 +569,7 @@ read_line(const char *prompt)
 {
 	int sz;
 
-	sz = read_line_input(NULL, prompt, line_buffer, sizeof(line_buffer), /*timeout*/ -1);
+	sz = read_line_input(NULL, prompt, line_buffer, sizeof(line_buffer), /*timeout*/ -1, NULL);
 	if (sz <= 0)
 		exit(EXIT_SUCCESS); /* Ctrl-D or Ctrl-C */
 
-- 
1.9.1



More information about the busybox mailing list