Description: Implement tab completion and history
 By using the linenoise library.
Author: Marco d'Itri <md@linux.it>
--- a/Makefile
+++ b/Makefile
@@ -53,6 +53,7 @@ MANDIR = /usr/share/man
 
 
 OBJS = sash.o cmds.o cmd_dd.o cmd_ed.o cmd_grep.o cmd_ls.o cmd_tar.o \
+       linenoise.o encodings/utf8.o \
 	cmd_gzip.o cmd_find.o cmd_file.o cmd_chattr.o cmd_ar.o utils.o
 
 
--- a/sash.c
+++ b/sash.c
@@ -14,6 +14,11 @@
 
 #include "sash.h"
 
+#define HAVE_LINENOISE
+#ifdef HAVE_LINENOISE
+# include "linenoise.h"
+# include "encodings/utf8.h"
+#endif
 
 static const char * const	version = "3.8";
 
@@ -407,6 +412,10 @@ static	char *	prompt;
  */
 static	void	catchInt(int);
 static	void	catchQuit(int);
+#ifdef HAVE_LINENOISE
+static	void	linenoiseCompletion(const char *, linenoiseCompletions *);
+static	int	readInteractive(void);
+#endif
 static	int	readFile(const char * name);
 static	int	command(const char * cmd);
 static	BOOL	tryBuiltIn(const char * cmd);
@@ -615,6 +624,67 @@ main(int argc, const char ** argv)
 
 }
 
+#ifdef HAVE_LINENOISE
+static void
+linenoiseCompletion(const char * buf, linenoiseCompletions * lc)
+{
+	const CommandEntry *	entry;
+	const Alias *		alias;
+	int			count;
+
+	/*
+	 * Search the command table looking for the command name.
+	 */
+	for (entry = commandEntryTable; entry->name != NULL; entry++)
+		if (strncmp(entry->name, buf, strlen(buf)) == 0)
+			linenoiseAddCompletion(lc, entry->name);
+
+	/*
+	 * Search the alias table looking for the alias name.
+	 */
+	count = aliasCount;
+	for (alias = aliasTable; count-- > 0; alias++)
+		if (strncmp(alias->name, buf, strlen(buf)) == 0)
+			linenoiseAddCompletion(lc, alias->name);
+}
+
+/*
+ * Read commands interactively.
+ */
+static int
+readInteractive(void)
+{
+	char *	ln_prompt = "> ";
+	int	r = 0;
+
+	linenoiseSetEncodingFunctions(
+	    linenoiseUtf8PrevCharLen,
+	    linenoiseUtf8NextCharLen,
+	    linenoiseUtf8ReadCode);
+	linenoiseSetCompletionCallback(linenoiseCompletion);
+
+	if (prompt)
+		ln_prompt = prompt;
+
+	while (TRUE)
+	{
+		char *line;
+
+		line = linenoise(ln_prompt);
+		if (!line)
+			break;
+
+		if (line[0] == '\0')
+			continue;
+
+		linenoiseHistoryAdd(line);
+		r = command(line);
+	}
+
+	return r;
+}
+#endif
+
 
 /*
  * Read commands from the specified file.
@@ -654,6 +724,11 @@ readFile(const char * name)
 
 	ttyFlag = isatty(fileno(fp));
 
+#ifdef HAVE_LINENOISE
+	if (!name && ttyFlag)	/* is interactive */
+	    return readInteractive();
+#endif
+
 	while (TRUE)
 	{
 		if (ttyFlag)
