#include "busybox.h"
-#ifdef BB_LOCALE_SUPPORT
+#ifdef CONFIG_LOCALE_SUPPORT
#define Isprint(c) isprint((c))
#else
#define Isprint(c) ( (c) >= ' ' && (c) != ((unsigned char)'\233') )
#else
-#define BB_FEATURE_COMMAND_EDITING
-#define BB_FEATURE_COMMAND_TAB_COMPLETION
-#define BB_FEATURE_COMMAND_USERNAME_COMPLETION
-#define BB_FEATURE_NONPRINTABLE_INVERSE_PUT
-#define BB_FEATURE_CLEAN_UP
+#define CONFIG_FEATURE_COMMAND_EDITING
+#define CONFIG_FEATURE_COMMAND_TAB_COMPLETION
+#define CONFIG_FEATURE_COMMAND_USERNAME_COMPLETION
+#define CONFIG_FEATURE_NONPRINTABLE_INVERSE_PUT
+#define CONFIG_FEATURE_CLEAN_UP
#define D(x) x
#endif /* TEST */
-#ifdef BB_FEATURE_COMMAND_TAB_COMPLETION
+#ifdef CONFIG_FEATURE_COMMAND_TAB_COMPLETION
#include <dirent.h>
#include <sys/stat.h>
#endif
-#ifdef BB_FEATURE_COMMAND_EDITING
+#ifdef CONFIG_FEATURE_COMMAND_EDITING
-#ifndef BB_FEATURE_COMMAND_TAB_COMPLETION
-#undef BB_FEATURE_COMMAND_USERNAME_COMPLETION
+#ifndef CONFIG_FEATURE_COMMAND_TAB_COMPLETION
+#undef CONFIG_FEATURE_COMMAND_USERNAME_COMPLETION
#endif
-#if defined(BB_FEATURE_COMMAND_USERNAME_COMPLETION) || defined(BB_FEATURE_SH_FANCY_PROMPT)
-#define BB_FEATURE_GETUSERNAME_AND_HOMEDIR
+#if defined(CONFIG_FEATURE_COMMAND_USERNAME_COMPLETION) || defined(CONFIG_FEATURE_SH_FANCY_PROMPT)
+#define CONFIG_FEATURE_GETUSERNAME_AND_HOMEDIR
#endif
-#ifdef BB_FEATURE_GETUSERNAME_AND_HOMEDIR
+#ifdef CONFIG_FEATURE_GETUSERNAME_AND_HOMEDIR
# ifndef TEST
-# include "pwd_grp/pwd.h"
+# include "pwd_.h"
# else
# include <pwd.h>
# endif /* TEST */
#endif /* advanced FEATURES */
-
-struct history {
- char *s;
- struct history *p;
- struct history *n;
-};
-
/* Maximum length of the linked list for the command line history */
-static const int MAX_HISTORY = 15;
-
-/* First element in command line list */
-static struct history *his_front = NULL;
-
-/* Last element in command line list */
-static struct history *his_end = NULL;
-
+#define MAX_HISTORY 15
+#if MAX_HISTORY < 1
+#warning cmdedit: You set MAX_HISTORY < 1. The history algorithm switched off.
+#else
+static char *history[MAX_HISTORY+1]; /* history + current */
+/* saved history lines */
+static int n_history;
+/* current pointer to history line */
+static int cur_history;
+#endif
#include <termios.h>
#define setTermSettings(fd,argp) tcsetattr(fd,TCSANOW,argp)
static
volatile int cmdedit_termw = 80; /* actual terminal width */
-static int history_counter = 0; /* Number of commands in history list */
static
volatile int handlers_sets = 0; /* Set next bites: */
static int len; /* --- "" - - "" - -"- --""-- --""--- */
static char *command_ps; /* --- "" - - "" - -"- --""-- --""--- */
static
-#ifndef BB_FEATURE_SH_FANCY_PROMPT
+#ifndef CONFIG_FEATURE_SH_FANCY_PROMPT
const
#endif
char *cmdedit_prompt; /* --- "" - - "" - -"- --""-- --""--- */
-#ifdef BB_FEATURE_GETUSERNAME_AND_HOMEDIR
+#ifdef CONFIG_FEATURE_GETUSERNAME_AND_HOMEDIR
static char *user_buf = "";
static char *home_pwd_buf = "";
static int my_euid;
#endif
-#ifdef BB_FEATURE_SH_FANCY_PROMPT
-static char *hostname_buf = "";
+#ifdef CONFIG_FEATURE_SH_FANCY_PROMPT
+static char *hostname_buf;
static int num_ok_lines = 1;
#endif
-#ifdef BB_FEATURE_COMMAND_TAB_COMPLETION
+#ifdef CONFIG_FEATURE_COMMAND_TAB_COMPLETION
-#ifndef BB_FEATURE_GETUSERNAME_AND_HOMEDIR
+#ifndef CONFIG_FEATURE_GETUSERNAME_AND_HOMEDIR
static int my_euid;
#endif
static int my_uid;
static int my_gid;
-#endif /* BB_FEATURE_COMMAND_TAB_COMPLETION */
+#endif /* CONFIG_FEATURE_COMMAND_TAB_COMPLETION */
+/* It seems that libc5 doesn't know what a sighandler_t is... */
+#if (__GLIBC__ <= 2) && (__GLIBC_MINOR__ < 1)
+typedef void (*sighandler_t) (int);
+#endif
static void cmdedit_setwidth(int w, int redraw_flg);
handlers_sets &= ~SET_WCHG_HANDLERS;
}
fflush(stdout);
-#ifdef BB_FEATURE_CLEAN_UP
- if (his_front) {
- struct history *n;
-
- while (his_front != his_end) {
- n = his_front->n;
- free(his_front->s);
- free(his_front);
- his_front = n;
- }
- }
-#endif
}
if (c == 0)
c = ' '; /* destroy end char? */
-#ifdef BB_FEATURE_NONPRINTABLE_INVERSE_PUT
+#ifdef CONFIG_FEATURE_NONPRINTABLE_INVERSE_PUT
if (!Isprint(c)) { /* Inverse put non-printable characters */
if (c >= 128)
c -= 128;
static inline void out1str(const char *s)
{
- fputs(s, stdout);
+ if ( s )
+ fputs(s, stdout);
}
static inline void beep(void)
{
cmdedit_y = 0; /* new quasireal y */
}
-#ifndef BB_FEATURE_SH_FANCY_PROMPT
+#ifndef CONFIG_FEATURE_SH_FANCY_PROMPT
static void parse_prompt(const char *prmt_ptr)
{
cmdedit_prompt = prmt_ptr;
break;
c = *prmt_ptr++;
switch (c) {
-#ifdef BB_FEATURE_GETUSERNAME_AND_HOMEDIR
+#ifdef CONFIG_FEATURE_GETUSERNAME_AND_HOMEDIR
case 'u':
pbuf = user_buf;
break;
#endif
case 'h':
pbuf = hostname_buf;
- if (*pbuf == 0) {
+ if (pbuf == 0) {
pbuf = xcalloc(256, 1);
if (gethostname(pbuf, 255) < 0) {
strcpy(pbuf, "?");
case '$':
c = my_euid == 0 ? '#' : '$';
break;
-#ifdef BB_FEATURE_GETUSERNAME_AND_HOMEDIR
+#ifdef CONFIG_FEATURE_GETUSERNAME_AND_HOMEDIR
case 'w':
pbuf = pwd_buf;
l = strlen(home_pwd_buf);
}
if ((handlers_sets & SET_ATEXIT) == 0) {
-#ifdef BB_FEATURE_GETUSERNAME_AND_HOMEDIR
+#ifdef CONFIG_FEATURE_GETUSERNAME_AND_HOMEDIR
struct passwd *entry;
my_euid = geteuid();
}
#endif
-#ifdef BB_FEATURE_COMMAND_TAB_COMPLETION
+#ifdef CONFIG_FEATURE_COMMAND_TAB_COMPLETION
-#ifndef BB_FEATURE_GETUSERNAME_AND_HOMEDIR
+#ifndef CONFIG_FEATURE_GETUSERNAME_AND_HOMEDIR
my_euid = geteuid();
#endif
my_uid = getuid();
my_gid = getgid();
-#endif /* BB_FEATURE_COMMAND_TAB_COMPLETION */
+#endif /* CONFIG_FEATURE_COMMAND_TAB_COMPLETION */
handlers_sets |= SET_ATEXIT;
atexit(cmdedit_reset_term); /* be sure to do this only once */
}
}
-#ifdef BB_FEATURE_COMMAND_TAB_COMPLETION
+#ifdef CONFIG_FEATURE_COMMAND_TAB_COMPLETION
static int is_execute(const struct stat *st)
{
return FALSE;
}
-#ifdef BB_FEATURE_COMMAND_USERNAME_COMPLETION
+#ifdef CONFIG_FEATURE_COMMAND_USERNAME_COMPLETION
static char **username_tab_completion(char *ud, int *num_matches)
{
/* Null usernames should result in all users as possible completions. */
if ( /*!userlen || */ !strncmp(ud, entry->pw_name, userlen)) {
- temp = xmalloc(3 + strlen(entry->pw_name));
- sprintf(temp, "~%s/", entry->pw_name);
+ bb_asprintf(&temp, "~%s/", entry->pw_name);
matches = xrealloc(matches, (nm + 1) * sizeof(char *));
matches[nm++] = temp;
return (matches);
}
}
-#endif /* BB_FEATURE_COMMAND_USERNAME_COMPLETION */
+#endif /* CONFIG_FEATURE_COMMAND_USERNAME_COMPLETION */
enum {
FIND_EXE_ONLY = 0,
strcpy(dirbuf, command);
/* set dir only */
dirbuf[(pfind - command) + 1] = 0;
-#ifdef BB_FEATURE_COMMAND_USERNAME_COMPLETION
+#ifdef CONFIG_FEATURE_COMMAND_USERNAME_COMPLETION
if (dirbuf[0] == '~') /* ~/... or ~user/... */
username_tab_completion(dirbuf, 0);
#endif
goto cont;
str_found = add_quote_for_spec_chars(found);
if (type == FIND_FILE_ONLY ||
- (type == FIND_EXE_ONLY && is_execute(&st) == TRUE))
+ (type == FIND_EXE_ONLY && is_execute(&st)))
strcat(str_found, " ");
}
/* Add it to the list */
#define QUOT (UCHAR_MAX+1)
#define collapse_pos(is, in) { \
- memcpy(int_buf+is, int_buf+in, (BUFSIZ+1-is-in)*sizeof(int)); \
- memcpy(pos_buf+is, pos_buf+in, (BUFSIZ+1-is-in)*sizeof(int)); }
+ memcpy(int_buf+(is), int_buf+(in), (BUFSIZ+1-(is)-(in))*sizeof(int)); \
+ memcpy(pos_buf+(is), pos_buf+(in), (BUFSIZ+1-(is)-(in))*sizeof(int)); }
static int find_match(char *matchBuf, int *len_with_quotes)
{
collapse_pos(j, j + 1);
int_buf[j] |= QUOT;
i++;
-#ifdef BB_FEATURE_NONPRINTABLE_INVERSE_PUT
+#ifdef CONFIG_FEATURE_NONPRINTABLE_INVERSE_PUT
if (matchBuf[i] == '\t') /* algorithm equivalent */
int_buf[j] = ' ' | QUOT;
#endif
}
-#ifdef BB_FEATURE_NONPRINTABLE_INVERSE_PUT
+#ifdef CONFIG_FEATURE_NONPRINTABLE_INVERSE_PUT
else if (matchBuf[i] == '\t')
int_buf[j] = ' ';
#endif
}
return;
}
- if (*lastWasTab == FALSE) {
+ if (! *lastWasTab) {
char *tmp;
int len_found;
/* Free up any memory already allocated */
input_tab(0);
-#ifdef BB_FEATURE_COMMAND_USERNAME_COMPLETION
+#ifdef CONFIG_FEATURE_COMMAND_USERNAME_COMPLETION
/* If the word starts with `~' and there is no slash in the word,
* then try completing this word as a username. */
}
}
}
-#endif /* BB_FEATURE_COMMAND_TAB_COMPLETION */
+#endif /* CONFIG_FEATURE_COMMAND_TAB_COMPLETION */
-static void get_previous_history(struct history **hp, struct history *p)
+#if MAX_HISTORY >= 1
+static void get_previous_history(void)
{
- if ((*hp)->s)
- free((*hp)->s);
- (*hp)->s = xstrdup(command_ps);
- *hp = p;
+ if(command_ps[0] != 0 || history[cur_history] == 0) {
+ free(history[cur_history]);
+ history[cur_history] = xstrdup(command_ps);
+ }
+ cur_history--;
}
-static inline void get_next_history(struct history **hp)
+static int get_next_history(void)
{
- get_previous_history(hp, (*hp)->n);
+ int ch = cur_history;
+
+ if (ch < n_history) {
+ get_previous_history(); /* save the current history line */
+ return (cur_history = ch+1);
+ } else {
+ beep();
+ return 0;
+ }
}
+#endif
enum {
ESC = 27,
int break_out = 0;
int lastWasTab = FALSE;
unsigned char c = 0;
- struct history *hp = his_end;
/* prepare before init handlers */
cmdedit_y = 0; /* quasireal y, not true work if line > xt*yt */
* if the len=0 and no chars to delete */
if (len == 0) {
prepare_to_die:
-#if !defined(BB_ASH)
+#if !defined(CONFIG_ASH)
printf("exit");
goto_new_line();
/* cmdedit_reset_term() called in atexit */
input_backspace();
break;
case '\t':
-#ifdef BB_FEATURE_COMMAND_TAB_COMPLETION
+#ifdef CONFIG_FEATURE_COMMAND_TAB_COMPLETION
input_tab(&lastWasTab);
#endif
break;
+ case 11:
+ /* Control-k -- clear to end of line */
+ *(command + cursor) = 0;
+ len = cursor;
+ printf("\033[J");
+ break;
+ case 12:
+ /* Control-l -- clear screen */
+ printf("\033[H");
+ redraw(0, len-cursor);
+ break;
+#if MAX_HISTORY >= 1
case 14:
/* Control-n -- Get next command in history */
- if (hp && hp->n && hp->n->s) {
- get_next_history(&hp);
+ if (get_next_history())
goto rewrite_line;
- } else {
- beep();
- }
break;
case 16:
/* Control-p -- Get previous command from history */
- if (hp && hp->p) {
- get_previous_history(&hp, hp->p);
+ if (cur_history > 0) {
+ get_previous_history();
goto rewrite_line;
} else {
beep();
}
break;
+#endif
case 21:
/* Control-U -- Clear line before cursor */
if (cursor) {
redraw(cmdedit_y, len -= cursor);
}
break;
-
case ESC:{
/* escape sequence follows */
if (safe_read(0, &c, 1) < 1)
goto prepare_to_die;
}
switch (c) {
-#ifdef BB_FEATURE_COMMAND_TAB_COMPLETION
+#ifdef CONFIG_FEATURE_COMMAND_TAB_COMPLETION
case '\t': /* Alt-Tab */
input_tab(&lastWasTab);
break;
#endif
+#if MAX_HISTORY >= 1
case 'A':
/* Up Arrow -- Get previous command from history */
- if (hp && hp->p) {
- get_previous_history(&hp, hp->p);
+ if (cur_history > 0) {
+ get_previous_history();
goto rewrite_line;
} else {
beep();
break;
case 'B':
/* Down Arrow -- Get next command in history */
- if (hp && hp->n && hp->n->s) {
- get_next_history(&hp);
- goto rewrite_line;
- } else {
- beep();
- }
+ if (!get_next_history())
break;
-
/* Rewrite the line with the selected history item */
- rewrite_line:
+rewrite_line:
/* change command */
- len = strlen(strcpy(command, hp->s));
+ len = strlen(strcpy(command, history[cur_history]));
/* redraw and go to end line */
redraw(cmdedit_y, 0);
break;
+#endif
case 'C':
/* Right Arrow -- Move forward one character */
input_forward();
}
default: /* If it's regular input, do the normal thing */
-#ifdef BB_FEATURE_NONPRINTABLE_INVERSE_PUT
+#ifdef CONFIG_FEATURE_NONPRINTABLE_INVERSE_PUT
/* Control-V -- Add non-printable symbol */
if (c == 22) {
if (safe_read(0, &c, 1) < 1)
setTermSettings(0, (void *) &initial_settings);
handlers_sets &= ~SET_RESET_TERM;
+#if MAX_HISTORY >= 1
/* Handle command history log */
+ /* cleanup may be saved current command line */
+ free(history[MAX_HISTORY]);
+ history[MAX_HISTORY] = 0;
if (len) { /* no put empty line */
-
- struct history *h = his_end;
- char *ss;
-
- ss = xstrdup(command); /* duplicate */
-
- if (h == 0) {
- /* No previous history -- this memory is never freed */
- h = his_front = xmalloc(sizeof(struct history));
- h->n = xmalloc(sizeof(struct history));
-
- h->p = NULL;
- h->s = ss;
- h->n->p = h;
- h->n->n = NULL;
- h->n->s = NULL;
- his_end = h->n;
- history_counter++;
- } else {
- /* Add a new history command -- this memory is never freed */
- h->n = xmalloc(sizeof(struct history));
-
- h->n->p = h;
- h->n->n = NULL;
- h->n->s = NULL;
- h->s = ss;
- his_end = h->n;
-
+ int i = n_history;
/* After max history, remove the oldest command */
- if (history_counter >= MAX_HISTORY) {
-
- struct history *p = his_front->n;
-
- p->p = NULL;
- free(his_front->s);
- free(his_front);
- his_front = p;
- } else {
- history_counter++;
- }
+ if (i >= MAX_HISTORY) {
+ free(history[0]);
+ for(i = 0; i < (MAX_HISTORY-1); i++)
+ history[i] = history[i+1];
}
-#if defined(BB_FEATURE_SH_FANCY_PROMPT)
+ history[i++] = xstrdup(command);
+ cur_history = i;
+ n_history = i;
+#if defined(CONFIG_FEATURE_SH_FANCY_PROMPT)
num_ok_lines++;
#endif
}
+#else /* MAX_HISTORY < 1 */
+#if defined(CONFIG_FEATURE_SH_FANCY_PROMPT)
+ if (len) { /* no put empty line */
+ num_ok_lines++;
+ }
+#endif
+#endif /* MAX_HISTORY >= 1 */
if(break_out>0) {
command[len++] = '\n'; /* set '\n' */
command[len] = 0;
}
-#if defined(BB_FEATURE_CLEAN_UP) && defined(BB_FEATURE_COMMAND_TAB_COMPLETION)
+#if defined(CONFIG_FEATURE_CLEAN_UP) && defined(CONFIG_FEATURE_COMMAND_TAB_COMPLETION)
input_tab(0); /* strong free */
#endif
-#if defined(BB_FEATURE_SH_FANCY_PROMPT)
+#if defined(CONFIG_FEATURE_SH_FANCY_PROMPT)
free(cmdedit_prompt);
#endif
cmdedit_reset_term();
-#endif /* BB_FEATURE_COMMAND_EDITING */
+#endif /* CONFIG_FEATURE_COMMAND_EDITING */
#ifdef TEST
const char *applet_name = "debug stuff usage";
const char *memory_exhausted = "Memory exhausted";
-#ifdef BB_FEATURE_NONPRINTABLE_INVERSE_PUT
+#ifdef CONFIG_FEATURE_NONPRINTABLE_INVERSE_PUT
#include <locale.h>
#endif
{
char buff[BUFSIZ];
char *prompt =
-#if defined(BB_FEATURE_SH_FANCY_PROMPT)
+#if defined(CONFIG_FEATURE_SH_FANCY_PROMPT)
"\\[\\033[32;1m\\]\\u@\\[\\x1b[33;1m\\]\\h:\
\\[\\033[34;1m\\]\\w\\[\\033[35;1m\\] \
\\!\\[\\e[36;1m\\]\\$ \\[\\E[0m\\]";
"% ";
#endif
-#ifdef BB_FEATURE_NONPRINTABLE_INVERSE_PUT
+#ifdef CONFIG_FEATURE_NONPRINTABLE_INVERSE_PUT
setlocale(LC_ALL, "");
#endif
while(1) {