From 8e1c71529c2bf38a04d4a117e625e59044a0785a Mon Sep 17 00:00:00 2001 From: Denis Vlasenko Date: Mon, 22 Jan 2007 07:21:38 +0000 Subject: Convert cmdedit into more generic line input facility (make history and completion optional at runtime). Use it for fdisk, as an example. Some unrelated fixes in fdisk are also here. --- shell/Kbuild | 10 +- shell/ash.c | 106 ++++++++++--------- shell/cmdedit.c | 316 ++++++++++++++++++++++++++++---------------------------- shell/cmdedit.h | 21 +--- shell/hush.c | 13 ++- shell/lash.c | 14 ++- shell/msh.c | 26 +++-- 7 files changed, 251 insertions(+), 255 deletions(-) (limited to 'shell') diff --git a/shell/Kbuild b/shell/Kbuild index eb0199e..9c60698 100644 --- a/shell/Kbuild +++ b/shell/Kbuild @@ -5,8 +5,8 @@ # Licensed under the GPL v2, see the file LICENSE in this tarball. lib-y:= -lib-$(CONFIG_ASH) += ash.o -lib-$(CONFIG_HUSH) += hush.o -lib-$(CONFIG_LASH) += lash.o -lib-$(CONFIG_MSH) += msh.o -lib-$(CONFIG_FEATURE_COMMAND_EDITING) += cmdedit.o +lib-y += cmdedit.o +lib-$(CONFIG_ASH) += ash.o +lib-$(CONFIG_HUSH) += hush.o +lib-$(CONFIG_LASH) += lash.o +lib-$(CONFIG_MSH) += msh.o diff --git a/shell/ash.c b/shell/ash.c index 2db3302..8afdf3d 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -92,7 +92,6 @@ #include #endif -#include "cmdedit.h" #ifdef __GLIBC__ /* glibc sucks */ @@ -1238,7 +1237,7 @@ static int fgcmd(int, char **); static int getoptscmd(int, char **); #endif static int hashcmd(int, char **); -#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET +#if !ENABLE_FEATURE_SH_EXTRA_QUIET static int helpcmd(int argc, char **argv); #endif #if JOBS @@ -1347,7 +1346,7 @@ static const struct builtincmd builtincmd[] = { { BUILTIN_REGULAR "getopts", getoptscmd }, #endif { BUILTIN_NOSPEC "hash", hashcmd }, -#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET +#if !ENABLE_FEATURE_SH_EXTRA_QUIET { BUILTIN_NOSPEC "help", helpcmd }, #endif #if JOBS @@ -1529,7 +1528,7 @@ static struct var varinit[] = { {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_ALL\0", change_lc_all }, {0, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_CTYPE\0", change_lc_ctype }, #endif -#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY +#if ENABLE_FEATURE_COMMAND_SAVEHISTORY {0, VSTRFIXED | VTEXTFIXED | VUNSET, "HISTFILE\0", NULL }, #endif }; @@ -1934,10 +1933,6 @@ struct shparam { #define debug optlist[15] #endif -#ifndef CONFIG_FEATURE_COMMAND_EDITING_VI -#define setvimode(on) viflag = 0 /* forcibly keep the option off */ -#endif - /* options.c */ @@ -3718,7 +3713,7 @@ shellexec(char **argv, const char *path, int idx) clearredir(1); envp = environment(); if (strchr(argv[0], '/') || is_safe_applet(argv[0]) -#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL +#if ENABLE_FEATURE_SH_STANDALONE_SHELL || find_applet_by_name(argv[0]) #endif ) { @@ -3775,7 +3770,7 @@ tryexec(char *cmd, char **argv, char **envp) applet_name = cmd; exit(a->main(argc, argv)); } -#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL +#if ENABLE_FEATURE_SH_STANDALONE_SHELL if (find_applet_by_name(cmd) != NULL) { /* re-exec ourselves with the new arguments */ execve(CONFIG_BUSYBOX_EXEC_PATH,argv,envp); @@ -3949,7 +3944,7 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) return; } -#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL +#if ENABLE_FEATURE_SH_STANDALONE_SHELL if (find_applet_by_name(name)) { entry->cmdtype = CMDNORMAL; entry->u.index = -1; @@ -6045,21 +6040,18 @@ static char * pfgets(char *line, int len) } - -#ifdef CONFIG_FEATURE_COMMAND_EDITING -#ifdef CONFIG_ASH_EXPAND_PRMT -static char *cmdedit_prompt; -#else +#if ENABLE_FEATURE_COMMAND_EDITING +static line_input_t *line_input_state; +//static SKIP_ASH_EXPAND_PRMT(const) char *cmdedit_prompt; static const char *cmdedit_prompt; -#endif static void putprompt(const char *s) { -#ifdef CONFIG_ASH_EXPAND_PRMT - free(cmdedit_prompt); - cmdedit_prompt = xstrdup(s); -#else + if (ENABLE_ASH_EXPAND_PRMT) { + free((char*)cmdedit_prompt); + cmdedit_prompt = xstrdup(s); + return; + } cmdedit_prompt = s; -#endif } #else static void putprompt(const char *s) @@ -6068,6 +6060,16 @@ static void putprompt(const char *s) } #endif +#if ENABLE_FEATURE_COMMAND_EDITING_VI +#define setvimode(on) do { \ + if (on) line_input_state->flags |= VI_MODE; \ + else line_input_state->flags &= ~VI_MODE; \ +} while (0) +#else +#define setvimode(on) viflag = 0 /* forcibly keep the option off */ +#endif + + static int preadfd(void) { int nr; @@ -6075,25 +6077,25 @@ static int preadfd(void) parsenextc = buf; retry: -#ifdef CONFIG_FEATURE_COMMAND_EDITING +#if ENABLE_FEATURE_COMMAND_EDITING if (!iflag || parsefile->fd) nr = safe_read(parsefile->fd, buf, BUFSIZ - 1); else { -#ifdef CONFIG_FEATURE_COMMAND_TAB_COMPLETION - cmdedit_path_lookup = pathval(); +#if ENABLE_FEATURE_COMMAND_TAB_COMPLETION + line_input_state->path_lookup = pathval(); #endif - nr = cmdedit_read_input((char *) cmdedit_prompt, buf); - if(nr == 0) { - /* Ctrl+C presend */ - if(trap[SIGINT]) { + nr = read_line_input(cmdedit_prompt, buf, BUFSIZ, line_input_state); + if (nr == 0) { + /* Ctrl+C pressed */ + if (trap[SIGINT]) { buf[0] = '\n'; - buf[1] = 0; + buf[1] = '\0'; raise(SIGINT); return 1; } goto retry; } - if(nr < 0 && errno == 0) { + if (nr < 0 && errno == 0) { /* Ctrl+D presend */ nr = 0; } @@ -7913,6 +7915,10 @@ ash_main(int argc, char **argv) #if PROFILE monitor(4, etext, profile_buf, sizeof profile_buf, 50); #endif + +#if ENABLE_FEATURE_COMMAND_EDITING + line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP); +#endif state = 0; if (setjmp(jmploc.loc)) { int e; @@ -7954,11 +7960,11 @@ ash_main(int argc, char **argv) init(); setstackmark(&smark); procargs(argc, argv); -#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY - if ( iflag ) { +#if ENABLE_FEATURE_COMMAND_SAVEHISTORY + if (iflag) { const char *hp = lookupvar("HISTFILE"); - if(hp == NULL ) { + if (hp == NULL) { hp = lookupvar("HOME"); if(hp != NULL) { char *defhp = concat_path_file(hp, ".ash_history"); @@ -7995,15 +8001,15 @@ state3: evalstring(minusc, 0); if (sflag || minusc == NULL) { -#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY - if ( iflag ) { - const char *hp = lookupvar("HISTFILE"); +#if ENABLE_FEATURE_COMMAND_SAVEHISTORY + if ( iflag ) { + const char *hp = lookupvar("HISTFILE"); - if(hp != NULL ) - load_history ( hp ); - } + if (hp != NULL) + line_input_state->hist_file = hp; + } #endif -state4: /* XXX ??? - why isn't this before the "if" statement */ + state4: /* XXX ??? - why isn't this before the "if" statement */ cmdloop(1); } #if PROFILE @@ -11880,7 +11886,7 @@ setinteractive(int on) setsignal(SIGINT); setsignal(SIGQUIT); setsignal(SIGTERM); -#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET +#if !ENABLE_FEATURE_SH_EXTRA_QUIET if(is_interactive > 1) { /* Looks like they want an interactive shell */ static int do_banner; @@ -11897,7 +11903,7 @@ setinteractive(int on) } -#ifndef CONFIG_FEATURE_SH_EXTRA_QUIET +#if !ENABLE_FEATURE_SH_EXTRA_QUIET /*** List the available builtins ***/ static int helpcmd(int argc, char **argv) @@ -11913,7 +11919,7 @@ static int helpcmd(int argc, char **argv) col = 0; } } -#ifdef CONFIG_FEATURE_SH_STANDALONE_SHELL +#if ENABLE_FEATURE_SH_STANDALONE_SHELL for (i = 0; i < NUM_APPLETS; i++) { col += out1fmt("%c%s", ((col == 0) ? '\t' : ' '), applets[i].name); if (col > 60) { @@ -11945,7 +11951,7 @@ exitshell(void) /* dash bug: it just does _exit(exitstatus) here * but we have to do setjobctl(0) first! * (bug is still not fixed in dash-0.5.3 - if you run dash - * under Midnight Commander, on exit MC is backgrounded) */ + * under Midnight Commander, on exit from dash MC is backgrounded) */ status = exitstatus; goto out; } @@ -11955,14 +11961,6 @@ exitshell(void) evalstring(p, 0); } flushall(); -#ifdef CONFIG_FEATURE_COMMAND_SAVEHISTORY - if (iflag && rootshell) { - const char *hp = lookupvar("HISTFILE"); - - if (hp != NULL) - save_history(hp); - } -#endif out: setjobctl(0); _exit(status); @@ -13491,7 +13489,7 @@ static const char op_tokens[] = { #define endexpression &op_tokens[sizeof(op_tokens)-7] -static arith_t arith (const char *expr, int *perrcode) +static arith_t arith(const char *expr, int *perrcode) { char arithval; /* Current character under analysis */ operator lasttok, op; diff --git a/shell/cmdedit.c b/shell/cmdedit.c index a1432af..554a4eb 100644 --- a/shell/cmdedit.c +++ b/shell/cmdedit.c @@ -30,7 +30,6 @@ #include #include "busybox.h" -#include "cmdedit.h" /* FIXME: obsolete CONFIG item? */ @@ -51,7 +50,6 @@ /* Entire file (except TESTing part) sits inside this #if */ #if ENABLE_FEATURE_COMMAND_EDITING - #if ENABLE_LOCALE_SUPPORT #define Isprint(c) isprint(c) #else @@ -61,29 +59,21 @@ #define ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR \ (ENABLE_FEATURE_COMMAND_USERNAME_COMPLETION || ENABLE_FEATURE_SH_FANCY_PROMPT) -/* Maximum length of command line history */ -#if !ENABLE_FEATURE_COMMAND_HISTORY -#define MAX_HISTORY 15 -#else -#define MAX_HISTORY (CONFIG_FEATURE_COMMAND_HISTORY + 0) -#endif +static line_input_t *state; -/* Current termios and the previous termios before starting sh */ static struct termios initial_settings, new_settings; -static -volatile unsigned cmdedit_termw = 80; /* actual terminal width */ - +static volatile unsigned cmdedit_termw = 80; /* actual terminal width */ static int cmdedit_x; /* real x terminal position */ static int cmdedit_y; /* pseudoreal y terminal position */ static int cmdedit_prmt_len; /* length of prompt (without colors etc) */ -static int cursor; -static int len; +static unsigned cursor; +static unsigned command_len; static char *command_ps; -static SKIP_FEATURE_SH_FANCY_PROMPT(const) char *cmdedit_prompt; +static const char *cmdedit_prompt; #if ENABLE_FEATURE_SH_FANCY_PROMPT static char *hostname_buf; @@ -142,7 +132,7 @@ static void cmdedit_set_out_char(int next_char) /* Move to end of line (by printing all chars till the end) */ static void input_end(void) { - while (cursor < len) + while (cursor < command_len) cmdedit_set_out_char(' '); } @@ -200,7 +190,7 @@ static void input_backward(unsigned num) static void put_prompt(void) { out1str(cmdedit_prompt); - cmdedit_x = cmdedit_prmt_len; /* count real x terminal position */ + cmdedit_x = cmdedit_prmt_len; cursor = 0; // Huh? what if cmdedit_prmt_len >= width? cmdedit_y = 0; /* new quasireal y */ @@ -231,7 +221,7 @@ static void input_delete(int save) { int j = cursor; - if (j == len) + if (j == command_len) return; #if ENABLE_FEATURE_COMMAND_EDITING_VI @@ -249,7 +239,7 @@ static void input_delete(int save) #endif strcpy(command_ps + j, command_ps + j + 1); - len--; + command_len--; input_end(); /* rewrite new line */ cmdedit_set_out_char(' '); /* erase char */ input_backward(cursor - j); /* back to old pos cursor */ @@ -285,7 +275,7 @@ static void input_backspace(void) /* Move forward one character */ static void input_forward(void) { - if (cursor < len) + if (cursor < command_len) cmdedit_set_out_char(command_ps[cursor + 1]); } @@ -372,54 +362,50 @@ enum { FIND_FILE_ONLY = 2, }; -#if ENABLE_ASH -const char *cmdedit_path_lookup; -#endif static int path_parse(char ***p, int flags) { int npth; const char *tmp; -#if ENABLE_ASH - const char *pth = cmdedit_path_lookup; -#else - const char *pth = getenv("PATH") -#endif + const char *pth; + char **res; /* if not setenv PATH variable, to search cur dir "." */ if (flags != FIND_EXE_ONLY) return 1; + + if (state->flags & WITH_PATH_LOOKUP) + pth = state->path_lookup; + else + pth = getenv("PATH"); /* PATH= or PATH=: */ if (!pth || !pth[0] || LONE_CHAR(pth, ':')) return 1; tmp = pth; - npth = 0; - + npth = 1; /* path component count */ while (1) { - npth++; /* count words is + 1 count ':' */ tmp = strchr(tmp, ':'); if (!tmp) break; if (*++tmp == '\0') break; /* : */ + npth++; } - *p = xmalloc(npth * sizeof(char *)); - + res = xmalloc(npth * sizeof(char*)); + res[0] = xstrdup(pth); tmp = pth; - (*p)[0] = xstrdup(tmp); - npth = 1; /* count words is + 1 count ':' */ - + npth = 1; while (1) { tmp = strchr(tmp, ':'); if (!tmp) break; - (*p)[0][(tmp - pth)] = 0; /* ':' -> '\0' */ - if (*++tmp == 0) - break; /* : */ - (*p)[npth++] = &(*p)[0][(tmp - pth)]; /* p[next]=p[0][&'\0'+1] */ + *tmp++ = '\0'; /* ':' -> '\0' */ + if (*tmp == '\0') + break; /* : */ + res[npth++] = tmp; } - + *p = res; return npth; } @@ -742,6 +728,9 @@ static int match_compare(const void *a, const void *b) /* Do TAB completion */ static void input_tab(int *lastWasTab) { + if (!(state->flags & TAB_COMPLETION)) + return; + if (!*lastWasTab) { char *tmp, *tmp1; int len_found; @@ -764,13 +753,13 @@ static void input_tab(int *lastWasTab) #if ENABLE_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. */ - - if (matchBuf[0] == '~' && strchr(matchBuf, '/') == 0) - username_tab_completion(matchBuf, NULL); - if (!matches) + if (state->flags & USERNAME_COMPLETION) + if (matchBuf[0] == '~' && strchr(matchBuf, '/') == 0) + username_tab_completion(matchBuf, NULL); #endif /* Try to match any executable in our path and everything * in the current working directory */ + if (!matches) exe_n_cwd_tab_completion(matchBuf, find_type); /* Sort, then remove any duplicates found */ if (matches) { @@ -855,51 +844,48 @@ static void input_tab(int *lastWasTab) } } +#else +#define input_tab(a) ((void)0) #endif /* FEATURE_COMMAND_TAB_COMPLETION */ #if MAX_HISTORY > 0 -static char *history[MAX_HISTORY+1]; /* history + current */ -/* saved history lines */ -static int n_history; -/* current pointer to history line */ -static int cur_history; - +/* state->flags is already checked to be nonzero */ static void get_previous_history(void) { - if (command_ps[0] != '\0' || history[cur_history] == NULL) { - free(history[cur_history]); - history[cur_history] = xstrdup(command_ps); + if (command_ps[0] != '\0' || state->history[state->cur_history] == NULL) { + free(state->history[state->cur_history]); + state->history[state->cur_history] = xstrdup(command_ps); } - cur_history--; + state->cur_history--; } static int get_next_history(void) { - int ch = cur_history; - - if (ch < n_history) { - get_previous_history(); /* save the current history line */ - cur_history = ch + 1; - return cur_history; - } else { - beep(); - return 0; + if (state->flags & DO_HISTORY) { + int ch = state->cur_history; + if (ch < state->cnt_history) { + get_previous_history(); /* save the current history line */ + state->cur_history = ch + 1; + return state->cur_history; + } } + beep(); + return 0; } #if ENABLE_FEATURE_COMMAND_SAVEHISTORY +/* state->flags is already checked to be nonzero */ void load_history(const char *fromfile) { FILE *fp; int hi; /* cleanup old */ - - for (hi = n_history; hi > 0;) { + for (hi = state->cnt_history; hi > 0;) { hi--; - free(history[hi]); + free(state->history[hi]); } fp = fopen(fromfile, "r"); @@ -917,29 +903,62 @@ void load_history(const char *fromfile) free(hl); continue; } - history[hi++] = hl; + state->history[hi++] = hl; } fclose(fp); } - cur_history = n_history = hi; + state->cur_history = state->cnt_history = hi; } +/* state->flags is already checked to be nonzero */ void save_history(const char *tofile) { - FILE *fp = fopen(tofile, "w"); + FILE *fp; + fp = fopen(tofile, "w"); if (fp) { int i; - for (i = 0; i < n_history; i++) { - fprintf(fp, "%s\n", history[i]); + for (i = 0; i < state->cnt_history; i++) { + fprintf(fp, "%s\n", state->history[i]); } fclose(fp); } } +#else +#define load_history(a) ((void)0) +#define save_history(a) ((void)0) #endif /* FEATURE_COMMAND_SAVEHISTORY */ -#endif /* MAX_HISTORY > 0 */ +static void remember_in_history(const char *str) +{ + int i; + + if (!(state->flags & DO_HISTORY)) + return; + + i = state->cnt_history; + free(state->history[MAX_HISTORY]); + state->history[MAX_HISTORY] = NULL; + /* After max history, remove the oldest command */ + if (i >= MAX_HISTORY) { + free(state->history[0]); + for (i = 0; i < MAX_HISTORY-1; i++) + state->history[i] = state->history[i+1]; + } +// Maybe "if (!i || strcmp(history[i-1], command) != 0) ..." +// (i.e. do not save dups?) + state->history[i++] = xstrdup(str); + state->cur_history = i; + state->cnt_history = i; + if (state->flags & SAVE_HISTORY) + save_history(state->hist_file); + USE_FEATURE_SH_FANCY_PROMPT(num_ok_lines++;) +} + +#else /* MAX_HISTORY == 0 */ +#define remember_in_history(a) ((void)0) +#endif /* MAX_HISTORY */ /* @@ -960,13 +979,6 @@ void save_history(const char *tofile) */ #if ENABLE_FEATURE_COMMAND_EDITING_VI -static int vi_mode; - -void setvimode(int viflag) -{ - vi_mode = viflag; -} - static void vi_Word_motion(char *command, int eat) { @@ -1058,13 +1070,11 @@ vi_back_motion(char *command) input_backward(1); } } -#else -enum { vi_mode = 0 }; #endif /* - * cmdedit_read_input and its helpers + * read_line_input and its helpers */ #if !ENABLE_FEATURE_SH_FANCY_PROMPT @@ -1190,7 +1200,7 @@ static void parse_prompt(const char *prmt_ptr) cmdedit_prmt_len += cur_prmt_len; prmt_mem_ptr = strcat(xrealloc(prmt_mem_ptr, prmt_len+1), pbuf); } - if (pwd_buf!=(char *)bb_msg_unknown) + if (pwd_buf != (char *)bb_msg_unknown) free(pwd_buf); cmdedit_prompt = prmt_mem_ptr; put_prompt(); @@ -1217,7 +1227,7 @@ static void cmdedit_setwidth(unsigned w, int redraw_flg) /* new y for current cursor */ int new_y = (cursor + cmdedit_prmt_len) / w; /* redraw */ - redraw((new_y >= cmdedit_y ? new_y : cmdedit_y), len - cursor); + redraw((new_y >= cmdedit_y ? new_y : cmdedit_y), command_len - cursor); fflush(stdout); } } @@ -1275,9 +1285,10 @@ static void cmdedit_init(void) #undef CTRL #define CTRL(a) ((a) & ~0x40) - -int cmdedit_read_input(char *prompt, char command[BUFSIZ]) +int read_line_input(const char* prompt, char* command, int maxsize, line_input_t *st) { + static const int null_flags; + int lastWasTab = FALSE; unsigned int ic; unsigned char c; @@ -1286,18 +1297,28 @@ int cmdedit_read_input(char *prompt, char command[BUFSIZ]) smallint vi_cmdmode = 0; smalluint prevc; #endif + +// FIXME: audit & improve this + if (maxsize > BUFSIZ) + maxsize = BUFSIZ; + + /* With null flags, no other fields are ever used */ + state = st ? st : (line_input_t*) &null_flags; + if (state->flags & SAVE_HISTORY) + load_history(state->hist_file); + /* prepare before init handlers */ cmdedit_y = 0; /* quasireal y, not true if line > xt*yt */ - len = 0; + command_len = 0; command_ps = command; command[0] = '\0'; getTermSettings(0, (void *) &initial_settings); - memcpy(&new_settings, &initial_settings, sizeof(struct termios)); + memcpy(&new_settings, &initial_settings, sizeof(new_settings)); new_settings.c_lflag &= ~ICANON; /* unbuffered input */ /* Turn off echoing and CTRL-C, so we can trap it */ new_settings.c_lflag &= ~(ECHO | ECHONL | ISIG); - /* Hmm, in linux c_cc[] not parsed if set ~ICANON */ + /* Hmm, in linux c_cc[] is not parsed if ICANON is off */ new_settings.c_cc[VMIN] = 1; new_settings.c_cc[VTIME] = 0; /* Turn off CTRL-C, so we can trap it */ @@ -1354,34 +1375,18 @@ int cmdedit_read_input(char *prompt, char command[BUFSIZ]) vi_case(CTRL('C')|vbit:) /* Control-c -- stop gathering input */ goto_new_line(); -#if !ENABLE_ASH - command[0] = '\0'; - len = 0; - lastWasTab = FALSE; - put_prompt(); -#else - len = 0; - break_out = -1; /* to control traps */ -#endif + command_len = 0; + break_out = -1; /* "do not append '\n'" */ break; case CTRL('D'): /* Control-d -- Delete one character, or exit * if the len=0 and no chars to delete */ - if (len == 0) { + if (command_len == 0) { errno = 0; prepare_to_die: -// So, our API depends on whether we have ash compiled in or not? Crap... -#if !ENABLE_ASH - printf("exit"); - goto_new_line(); - /* cmdedit_reset_term() called in atexit */ -// FIXME. this is definitely not good - exit(EXIT_SUCCESS); -#else /* to control stopped jobs */ - break_out = len = -1; + break_out = command_len = -1; break; -#endif } input_delete(0); break; @@ -1407,23 +1412,21 @@ int cmdedit_read_input(char *prompt, char command[BUFSIZ]) break; case '\t': -#if ENABLE_FEATURE_COMMAND_TAB_COMPLETION input_tab(&lastWasTab); -#endif break; #if ENABLE_FEATURE_EDITING_FANCY_KEYS case CTRL('K'): /* Control-k -- clear to end of line */ command[cursor] = 0; - len = cursor; + command_len = cursor; printf("\033[J"); break; case CTRL('L'): vi_case(CTRL('L')|vbit:) /* Control-l -- clear screen */ printf("\033[H"); - redraw(0, len - cursor); + redraw(0, command_len - cursor); break; #endif @@ -1439,12 +1442,11 @@ int cmdedit_read_input(char *prompt, char command[BUFSIZ]) vi_case(CTRL('P')|vbit:) vi_case('k'|vbit:) /* Control-p -- Get previous command from history */ - if (cur_history > 0) { + if ((state->flags & DO_HISTORY) && state->cur_history > 0) { get_previous_history(); goto rewrite_line; - } else { - beep(); } + beep(); break; #endif @@ -1454,7 +1456,8 @@ int cmdedit_read_input(char *prompt, char command[BUFSIZ]) /* Control-U -- Clear line before cursor */ if (cursor) { strcpy(command, command + cursor); - redraw(cmdedit_y, len -= cursor); + command_len -= cursor; + redraw(cmdedit_y, command_len); } break; #endif @@ -1571,7 +1574,7 @@ int cmdedit_read_input(char *prompt, char command[BUFSIZ]) break; case '$': /* "d$", "c$" */ clear_to_eol: - while (cursor < len) + while (cursor < command_len) input_delete(1); break; } @@ -1599,7 +1602,7 @@ int cmdedit_read_input(char *prompt, char command[BUFSIZ]) case '\x1b': /* ESC */ #if ENABLE_FEATURE_COMMAND_EDITING_VI - if (vi_mode) { + if (state->flags & VI_MODE) { /* ESC: insert mode --> command mode */ vi_cmdmode = 1; input_backward(1); @@ -1634,7 +1637,7 @@ int cmdedit_read_input(char *prompt, char command[BUFSIZ]) #if MAX_HISTORY > 0 case 'A': /* Up Arrow -- Get previous command from history */ - if (cur_history > 0) { + if ((state->flags & DO_HISTORY) && state->cur_history > 0) { get_previous_history(); goto rewrite_line; } @@ -1647,9 +1650,9 @@ int cmdedit_read_input(char *prompt, char command[BUFSIZ]) rewrite_line: /* Rewrite the line with the selected history item */ /* change command */ - len = strlen(strcpy(command, history[cur_history])); + command_len = strlen(strcpy(command, state->history[state->cur_history])); /* redraw and go to eol (bol, in vi */ - redraw(cmdedit_y, vi_mode ? 9999 : 0); + redraw(cmdedit_y, (state->flags & VI_MODE) ? 9999 : 0); break; #endif case 'C': @@ -1700,18 +1703,18 @@ int cmdedit_read_input(char *prompt, char command[BUFSIZ]) if (!Isprint(c)) /* Skip non-printable characters */ break; - if (len >= (BUFSIZ - 2)) /* Need to leave space for enter */ + if (command_len >= (maxsize - 2)) /* Need to leave space for enter */ break; - len++; - if (cursor == (len - 1)) { /* Append if at the end of the line */ + command_len++; + if (cursor == (command_len - 1)) { /* Append if at the end of the line */ command[cursor] = c; command[cursor+1] = '\0'; cmdedit_set_out_char(' '); } else { /* Insert otherwise */ int sc = cursor; - memmove(command + sc + 1, command + sc, len - sc); + memmove(command + sc + 1, command + sc, command_len - sc); command[sc] = c; sc++; /* rewrite from cursor */ @@ -1728,35 +1731,12 @@ int cmdedit_read_input(char *prompt, char command[BUFSIZ]) lastWasTab = FALSE; } -#if MAX_HISTORY > 0 - /* Handle command history log */ - /* cleanup may be saved current command line */ - if (len > 0) { - int i = n_history; - - free(history[MAX_HISTORY]); - history[MAX_HISTORY] = NULL; - /* 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]; - } -// Maybe "if (!i || strcmp(history[i-1], command) != 0) ..." -// (i.e. do not save dups?) - history[i++] = xstrdup(command); - cur_history = i; - n_history = i; - USE_FEATURE_SH_FANCY_PROMPT(num_ok_lines++;) - } -#else /* MAX_HISTORY == 0 */ - /* dont put empty line */ - USE_FEATURE_SH_FANCY_PROMPT(if (len > 0) num_ok_lines++;) -#endif /* MAX_HISTORY */ + if (command_len > 0) + remember_in_history(command); if (break_out > 0) { - command[len++] = '\n'; - command[len] = '\0'; + command[command_len++] = '\n'; + command[command_len] = '\0'; } #if ENABLE_FEATURE_CLEAN_UP && ENABLE_FEATURE_COMMAND_TAB_COMPLETION @@ -1764,11 +1744,29 @@ int cmdedit_read_input(char *prompt, char command[BUFSIZ]) #endif #if ENABLE_FEATURE_SH_FANCY_PROMPT - free(cmdedit_prompt); + free((char*)cmdedit_prompt); #endif /* restore initial_settings and SIGWINCH handler */ cmdedit_reset_term(); - return len; + return command_len; +} + +line_input_t *new_line_input_t(int flags) +{ + line_input_t *n = xzalloc(sizeof(*n)); + n->flags = flags; + return n; +} + +#else + +#undef read_line_input +int read_line_input(const char* prompt, char* command, int maxsize) +{ + fputs(prompt, stdout); + fflush(stdout); + fgets(command, maxsize, stdin); + return strlen(command); } #endif /* FEATURE_COMMAND_EDITING */ @@ -1801,13 +1799,13 @@ int main(int argc, char **argv) #endif while (1) { int l; - l = cmdedit_read_input(prompt, buff); + l = read_line_input(prompt, buff); if (l <= 0 || buff[l-1] != '\n') break; buff[l-1] = 0; - printf("*** cmdedit_read_input() returned line =%s=\n", buff); + printf("*** read_line_input() returned line =%s=\n", buff); } - printf("*** cmdedit_read_input() detect ^D\n"); + printf("*** read_line_input() detect ^D\n"); return 0; } diff --git a/shell/cmdedit.h b/shell/cmdedit.h index 4a32cf6..7af2f75 100644 --- a/shell/cmdedit.h +++ b/shell/cmdedit.h @@ -1,20 +1 @@ -/* vi: set sw=4 ts=4: */ -#ifndef CMDEDIT_H -#define CMDEDIT_H - -int cmdedit_read_input(char* promptStr, char* command); - -#if ENABLE_ASH -extern const char *cmdedit_path_lookup; -#endif - -#if ENABLE_FEATURE_COMMAND_SAVEHISTORY -void load_history(const char *fromfile); -void save_history(const char *tofile); -#endif - -#if ENABLE_FEATURE_COMMAND_EDITING_VI -void setvimode(int viflag); -#endif - -#endif /* CMDEDIT_H */ +/* TO DELETE */ diff --git a/shell/hush.c b/shell/hush.c index 8f2dc80..2c88238 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -98,7 +98,6 @@ /* #include */ /* #define DEBUG_SHELL */ -#include "cmdedit.h" #define SPECIAL_VAR_SYMBOL 03 #define FLAG_EXIT_FROM_LOOP 1 @@ -883,20 +882,24 @@ static void setup_prompt_string(int promptmode, char **prompt_str) debug_printf("result %s\n",*prompt_str); } +#if ENABLE_FEATURE_COMMAND_EDITING +static line_input_t *line_input_state; +#endif + static void get_user_input(struct in_str *i) { char *prompt_str; static char the_command[BUFSIZ]; setup_prompt_string(i->promptmode, &prompt_str); -#ifdef CONFIG_FEATURE_COMMAND_EDITING +#if ENABLE_FEATURE_COMMAND_EDITING /* ** enable command line editing only while a command line ** is actually being read; otherwise, we'll end up bequeathing ** atexit() handlers and other unwanted stuff to our ** child processes (rob@sysgo.de) */ - cmdedit_read_input(prompt_str, the_command); + read_line_input(prompt_str, the_command, BUFSIZ, line_input_state); #else fputs(prompt_str, stdout); fflush(stdout); @@ -2647,6 +2650,10 @@ int hush_main(int argc, char **argv) FILE *input; char **e = environ; +#ifdef CONFIG_FEATURE_COMMAND_EDITING + line_input_state = new_line_input_t(FOR_SHELL); +#endif + /* XXX what should these be while sourcing /etc/profile? */ global_argc = argc; global_argv = argv; diff --git a/shell/lash.c b/shell/lash.c index b2ccaf0..a09a9a9 100644 --- a/shell/lash.c +++ b/shell/lash.c @@ -23,8 +23,6 @@ #include "busybox.h" #include -#include "cmdedit.h" - #include #define expand_t glob_t @@ -641,6 +639,10 @@ static inline void setup_prompt_string(char **prompt_str) #endif } +#if ENABLE_FEATURE_COMMAND_EDITING +static line_input_t *line_input_state; +#endif + static int get_command(FILE * source, char *command) { char *prompt_str; @@ -659,14 +661,14 @@ static int get_command(FILE * source, char *command) if (source == stdin) { setup_prompt_string(&prompt_str); -#ifdef CONFIG_FEATURE_COMMAND_EDITING +#if ENABLE_FEATURE_COMMAND_EDITING /* ** enable command line editing only while a command line ** is actually being read; otherwise, we'll end up bequeathing ** atexit() handlers and other unwanted stuff to our ** child processes (rob@sysgo.de) */ - cmdedit_read_input(prompt_str, command); + read_line_input(prompt_str, command, BUFSIZ, line_input_state); return 0; #else fputs(prompt_str, stdout); @@ -1505,6 +1507,10 @@ int lash_main(int argc_l, char **argv_l) argc = argc_l; argv = argv_l; +#if ENABLE_FEATURE_COMMAND_EDITING + line_input_state = new_line_input_t(FOR_SHELL); +#endif + /* These variables need re-initializing when recursing */ last_jobid = 0; close_me_list = NULL; diff --git a/shell/msh.c b/shell/msh.c index c88308f..8746e42 100644 --- a/shell/msh.c +++ b/shell/msh.c @@ -17,7 +17,6 @@ #include #include -#include "cmdedit.h" /*#define MSHDEBUG 1*/ @@ -777,7 +776,7 @@ void print_tree(struct op *head) #endif /* MSHDEBUG */ -#ifdef CONFIG_FEATURE_COMMAND_EDITING +#if ENABLE_FEATURE_COMMAND_EDITING static char *current_prompt; #endif @@ -787,6 +786,10 @@ static char *current_prompt; */ +#if ENABLE_FEATURE_COMMAND_EDITING +static line_input_t *line_input_state; +#endif + int msh_main(int argc, char **argv) { int f; @@ -795,6 +798,10 @@ int msh_main(int argc, char **argv) char *name, **ap; int (*iof) (struct ioarg *); +#if ENABLE_FEATURE_COMMAND_EDITING + line_input_state = new_line_input_t(FOR_SHELL); +#endif + DBGPRINTF(("MSH_MAIN: argc %d, environ %p\n", argc, environ)); initarea(); @@ -964,7 +971,7 @@ int msh_main(int argc, char **argv) for (;;) { if (interactive && e.iop <= iostack) { -#ifdef CONFIG_FEATURE_COMMAND_EDITING +#if ENABLE_FEATURE_COMMAND_EDITING current_prompt = prompt->value; #else prs(prompt->value); @@ -2371,7 +2378,7 @@ static int yylex(int cf) startl = 1; if (multiline || cf & CONTIN) { if (interactive && e.iop <= iostack) { -#ifdef CONFIG_FEATURE_COMMAND_EDITING +#if ENABLE_FEATURE_COMMAND_EDITING current_prompt = cprompt->value; #else prs(cprompt->value); @@ -2432,7 +2439,7 @@ static int collect(int c, int c1) return YYERRCODE; } if (interactive && c == '\n' && e.iop <= iostack) { -#ifdef CONFIG_FEATURE_COMMAND_EDITING +#if ENABLE_FEATURE_COMMAND_EDITING current_prompt = cprompt->value; #else prs(cprompt->value); @@ -4666,7 +4673,7 @@ static int readc(void) return e.iop->prev = 0; } if (interactive && e.iop == iostack + 1) { -#ifdef CONFIG_FEATURE_COMMAND_EDITING +#if ENABLE_FEATURE_COMMAND_EDITING current_prompt = prompt->value; #else prs(prompt->value); @@ -4898,13 +4905,13 @@ static int filechar(struct ioarg *ap) ap->afpos++; return *bp->bufp++ & 0177; } -#ifdef CONFIG_FEATURE_COMMAND_EDITING +#if ENABLE_FEATURE_COMMAND_EDITING if (interactive && isatty(ap->afile)) { static char mycommand[BUFSIZ]; static int position = 0, size = 0; while (size == 0 || position >= size) { - cmdedit_read_input(current_prompt, mycommand); + read_line_input(current_prompt, mycommand, BUFSIZ, line_input_state); size = strlen(mycommand); position = 0; } @@ -4913,7 +4920,6 @@ static int filechar(struct ioarg *ap) return c; } else #endif - { i = safe_read(ap->afile, &c, sizeof(c)); return i == sizeof(c) ? (c & 0x7f) : (closef(ap->afile), 0); @@ -5150,7 +5156,7 @@ static void readhere(char **name, char *s, int ec) e.iobase = e.iop; for (;;) { if (interactive && e.iop <= iostack) { -#ifdef CONFIG_FEATURE_COMMAND_EDITING +#if ENABLE_FEATURE_COMMAND_EDITING current_prompt = cprompt->value; #else prs(cprompt->value); -- cgit v1.1