X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=shell%2Fcmdedit.c;h=b6e743eb4118f33532758d84d687043c7c01f2e6;hb=062c74f71035091fcef0b20ff4e8cb77d18124cc;hp=ffe7afab2a86a2f362ef5e3e92d14d6cea6a9ae9;hpb=61173a537149484dfaaeb8f94a2c86ef01d30613;p=oweals%2Fbusybox.git diff --git a/shell/cmdedit.c b/shell/cmdedit.c index ffe7afab2..b6e743eb4 100644 --- a/shell/cmdedit.c +++ b/shell/cmdedit.c @@ -3,7 +3,7 @@ * Termios command line History and Editting. * * Copyright (c) 1986-2001 may safely be consumed by a BSD or GPL license. - * Written by: Vladimir Oleynik + * Written by: Vladimir Oleynik * * Used ideas: * Adam Rogoyski @@ -31,8 +31,6 @@ */ -//#define TEST - #include #include #include @@ -43,129 +41,84 @@ #include #include -#ifndef TEST - #include "busybox.h" +#ifdef CONFIG_LOCALE_SUPPORT +#define Isprint(c) isprint((c)) +#else +#define Isprint(c) ( (c) >= ' ' && (c) != ((unsigned char)'\233') ) +#endif + +#ifndef TEST + #define D(x) #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 -#ifndef TRUE -#define TRUE 1 -#endif -#ifndef FALSE -#define FALSE 0 -#endif - #endif /* TEST */ -#ifdef BB_FEATURE_COMMAND_TAB_COMPLETION +#ifdef CONFIG_FEATURE_COMMAND_TAB_COMPLETION #include #include #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_SIMPLE_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 -#ifndef TEST -#include "pwd_grp/pwd.h" -#else -#include -#endif /* TEST */ +#ifdef CONFIG_FEATURE_GETUSERNAME_AND_HOMEDIR +# ifndef TEST +# include "pwd_.h" +# else +# include +# endif /* TEST */ #endif /* advanced FEATURES */ -#ifdef TEST -void *xrealloc(void *old, size_t size) -{ - return realloc(old, size); -} - -void *xmalloc(size_t size) -{ - return malloc(size); -} -char *xstrdup(const char *s) -{ - return strdup(s); -} - -void *xcalloc(size_t size, size_t se) -{ - return calloc(size, se); -} - -#define error_msg(s, d) fprintf(stderr, s, d) -#endif - - -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; - - -/* ED: sparc termios is broken: revert back to old termio handling. */ - -#if #cpu(sparc) -# include -# define termios termio -# define setTermSettings(fd,argp) ioctl(fd,TCSETAF,argp) -# define getTermSettings(fd,argp) ioctl(fd,TCGETA,argp) +#define MAX_HISTORY 15 +#if MAX_HISTORY < 1 +#warning cmdedit: You set MAX_HISTORY < 1. The history algorithm switched off. #else -# include -# define setTermSettings(fd,argp) tcsetattr(fd,TCSANOW,argp) -# define getTermSettings(fd,argp) tcgetattr(fd, argp); +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 +#define setTermSettings(fd,argp) tcsetattr(fd,TCSANOW,argp) +#define getTermSettings(fd,argp) tcgetattr(fd, argp); + /* Current termio and the previous termio before starting sh */ static struct termios initial_settings, new_settings; -#ifndef _POSIX_VDISABLE -#define _POSIX_VDISABLE '\0' -#endif - - 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: */ enum { SET_ATEXIT = 1, /* when atexit() has been called and get euid,uid,gid to fast compare */ - SET_TERM_HANDLERS = 2, /* set many terminates signal handlers */ - SET_WCHG_HANDLERS = 4, /* winchg signal handler */ - SET_RESET_TERM = 8, /* if the terminal needs to be reset upon exit */ + SET_WCHG_HANDLERS = 2, /* winchg signal handler */ + SET_RESET_TERM = 4, /* if the terminal needs to be reset upon exit */ }; @@ -177,45 +130,45 @@ static int cursor; /* required global for signal handler */ static int len; /* --- "" - - "" - -"- --""-- --""--- */ static char *command_ps; /* --- "" - - "" - -"- --""-- --""--- */ static -#ifdef BB_FEATURE_SH_SIMPLE_PROMPT +#ifndef CONFIG_FEATURE_SH_FANCY_PROMPT const #endif char *cmdedit_prompt; /* --- "" - - "" - -"- --""-- --""--- */ -/* Link into lash to reset context to 0 on ^C and such */ -extern unsigned int shell_context; - - -#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 -#ifndef BB_FEATURE_SH_SIMPLE_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); static void win_changed(int nsig) { struct winsize win = { 0, 0, 0, 0 }; - static __sighandler_t previous_SIGWINCH_handler; /* for reset */ + static sighandler_t previous_SIGWINCH_handler; /* for reset */ /* emulate || signal call */ if (nsig == -SIGWINCH || nsig == SIGWINCH) { @@ -238,7 +191,7 @@ static void win_changed(int nsig) static void cmdedit_reset_term(void) { if ((handlers_sets & SET_RESET_TERM) != 0) { - /* sparc and other have broken termios support: use old termio handling. */ +/* sparc and other have broken termios support: use old termio handling. */ setTermSettings(fileno(stdin), (void *) &initial_settings); handlers_sets &= ~SET_RESET_TERM; } @@ -248,18 +201,6 @@ static void cmdedit_reset_term(void) 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 } @@ -270,9 +211,9 @@ static void cmdedit_set_out_char(int next_char) int c = (int)((unsigned char) command_ps[cursor]); if (c == 0) - c = ' '; /* destroy end char? */ -#ifdef BB_FEATURE_NONPRINTABLE_INVERSE_PUT - if (!isprint(c)) { /* Inverse put non-printable characters */ + c = ' '; /* destroy end char? */ +#ifdef CONFIG_FEATURE_NONPRINTABLE_INVERSE_PUT + if (!Isprint(c)) { /* Inverse put non-printable characters */ if (c >= 128) c -= 128; if (c < ' ') @@ -315,7 +256,8 @@ static void goto_new_line(void) static inline void out1str(const char *s) { - fputs(s, stdout); + if ( s ) + fputs(s, stdout); } static inline void beep(void) { @@ -328,7 +270,7 @@ static void input_backward(int num) { if (num > cursor) num = cursor; - cursor -= num; /* new cursor (in command, not terminal) */ + cursor -= num; /* new cursor (in command, not terminal) */ if (cmdedit_x >= num) { /* no to up line */ cmdedit_x -= num; @@ -359,9 +301,10 @@ static void put_prompt(void) out1str(cmdedit_prompt); cmdedit_x = cmdedit_prmt_len; /* count real x terminal position */ cursor = 0; + cmdedit_y = 0; /* new quasireal y */ } -#ifdef BB_FEATURE_SH_SIMPLE_PROMPT +#ifndef CONFIG_FEATURE_SH_FANCY_PROMPT static void parse_prompt(const char *prmt_ptr) { cmdedit_prompt = prmt_ptr; @@ -369,134 +312,121 @@ static void parse_prompt(const char *prmt_ptr) put_prompt(); } #else -static void add_to_prompt(char **prmt_mem_ptr, int *alm, - int *prmt_len, const char *addb) -{ - *prmt_len += strlen(addb); - if (*alm < (*prmt_len) + 1) { - *alm = (*prmt_len) + 1; - *prmt_mem_ptr = xrealloc(*prmt_mem_ptr, *alm); - } - strcat(*prmt_mem_ptr, addb); -} - static void parse_prompt(const char *prmt_ptr) { - int alm = strlen(prmt_ptr) + 1; /* supposedly require memory */ int prmt_len = 0; int sub_len = 0; - int flg_not_length = '['; - char *prmt_mem_ptr = xstrdup(prmt_ptr); - char pwd_buf[PATH_MAX + 1]; - char buf[16]; - int c; - - pwd_buf[0] = 0; - *prmt_mem_ptr = 0; + char flg_not_length = '['; + char *prmt_mem_ptr = xcalloc(1, 1); + char *pwd_buf = xgetcwd(0); + char buf2[PATH_MAX + 1]; + char buf[2]; + char c; + char *pbuf; + + if (!pwd_buf) { + pwd_buf=(char *)unknown; + } while (*prmt_ptr) { + pbuf = buf; + pbuf[1] = 0; c = *prmt_ptr++; if (c == '\\') { - c = *prmt_ptr; - if (c == 0) + const char *cp = prmt_ptr; + int l; + + c = process_escape_sequence(&prmt_ptr); + if(prmt_ptr==cp) { + if (*cp == 0) + break; + c = *prmt_ptr++; + switch (c) { +#ifdef CONFIG_FEATURE_GETUSERNAME_AND_HOMEDIR + case 'u': + pbuf = user_buf; break; - prmt_ptr++; - switch (c) { -#ifdef BB_FEATURE_GETUSERNAME_AND_HOMEDIR - case 'u': - add_to_prompt(&prmt_mem_ptr, &alm, &prmt_len, user_buf); - continue; #endif - case 'h': - if (hostname_buf[0] == 0) { - hostname_buf = xcalloc(256, 1); - if (gethostname(hostname_buf, 255) < 0) { - strcpy(hostname_buf, "?"); + case 'h': + pbuf = hostname_buf; + if (pbuf == 0) { + pbuf = xcalloc(256, 1); + if (gethostname(pbuf, 255) < 0) { + strcpy(pbuf, "?"); } else { - char *s = strchr(hostname_buf, '.'); + char *s = strchr(pbuf, '.'); if (s) *s = 0; } + hostname_buf = pbuf; } - add_to_prompt(&prmt_mem_ptr, &alm, &prmt_len, - hostname_buf); - continue; - case '$': + break; + case '$': c = my_euid == 0 ? '#' : '$'; break; -#ifdef BB_FEATURE_GETUSERNAME_AND_HOMEDIR - case 'w': - if (pwd_buf[0] == 0) { - int l; - - getcwd(pwd_buf, PATH_MAX); - l = strlen(home_pwd_buf); - if (home_pwd_buf[0] != 0 && - strncmp(home_pwd_buf, pwd_buf, l) == 0) { - strcpy(pwd_buf + 1, pwd_buf + l); - pwd_buf[0] = '~'; +#ifdef CONFIG_FEATURE_GETUSERNAME_AND_HOMEDIR + case 'w': + pbuf = pwd_buf; + l = strlen(home_pwd_buf); + if (home_pwd_buf[0] != 0 && + strncmp(home_pwd_buf, pbuf, l) == 0 && + (pbuf[l]=='/' || pbuf[l]=='\0') && + strlen(pwd_buf+l) UCHAR_MAX || (eho - buf) < l) { + int h; + buf2[l++] = *prmt_ptr; + buf2[l] = 0; + h = strtol(buf2, &pbuf, 16); + if (h > UCHAR_MAX || (pbuf - buf2) < l) { l--; break; } prmt_ptr++; } - buf[l] = 0; - ho = strtol(buf, 0, c == 'x' ? 16 : 8); - c = ho == 0 ? '?' : (char) ho; + buf2[l] = 0; + c = (char)strtol(buf2, 0, 16); + if(c==0) + c = '?'; + pbuf = buf; break; - } - case '[': - case ']': + case '[': case ']': if (c == flg_not_length) { flg_not_length = flg_not_length == '[' ? ']' : '['; continue; } break; - } + } + } } - buf[0] = c; - buf[1] = 0; - add_to_prompt(&prmt_mem_ptr, &alm, &prmt_len, buf); + if(pbuf == buf) + *pbuf = c; + prmt_len += strlen(pbuf); + prmt_mem_ptr = strcat(xrealloc(prmt_mem_ptr, prmt_len+1), pbuf); if (flg_not_length == ']') sub_len++; } + if(pwd_buf!=(char *)unknown) + free(pwd_buf); cmdedit_prompt = prmt_mem_ptr; cmdedit_prmt_len = prmt_len - sub_len; put_prompt(); @@ -509,7 +439,6 @@ static void redraw(int y, int back_cursor) { if (y > 0) /* up to start y */ printf("\033[%dA", y); - cmdedit_y = 0; /* new quasireal y */ putchar('\r'); put_prompt(); input_end(); /* rewrite */ @@ -550,14 +479,6 @@ static void input_forward(void) } -static void clean_up_and_die(int sig) -{ - goto_new_line(); - if (sig != SIGINT) - exit(EXIT_SUCCESS); /* cmdedit_reset_term() called in atexit */ - cmdedit_reset_term(); -} - static void cmdedit_setwidth(int w, int redraw_flg) { cmdedit_termw = cmdedit_prmt_len + 2; @@ -578,7 +499,7 @@ static void cmdedit_setwidth(int w, int redraw_flg) } } -extern void cmdedit_init(void) +static void cmdedit_init(void) { cmdedit_prmt_len = 0; if ((handlers_sets & SET_WCHG_HANDLERS) == 0) { @@ -588,7 +509,7 @@ extern void cmdedit_init(void) } if ((handlers_sets & SET_ATEXIT) == 0) { -#ifdef BB_FEATURE_GETUSERNAME_AND_HOMEDIR +#ifdef CONFIG_FEATURE_GETUSERNAME_AND_HOMEDIR struct passwd *entry; my_euid = geteuid(); @@ -599,29 +520,20 @@ extern void cmdedit_init(void) } #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 */ } - - if ((handlers_sets & SET_TERM_HANDLERS) == 0) { - signal(SIGKILL, clean_up_and_die); - signal(SIGINT, clean_up_and_die); - signal(SIGQUIT, clean_up_and_die); - signal(SIGTERM, clean_up_and_die); - handlers_sets |= SET_TERM_HANDLERS; - } - } -#ifdef BB_FEATURE_COMMAND_TAB_COMPLETION +#ifdef CONFIG_FEATURE_COMMAND_TAB_COMPLETION static int is_execute(const struct stat *st) { @@ -632,7 +544,7 @@ 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) { @@ -681,8 +593,7 @@ 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; @@ -694,7 +605,7 @@ static char **username_tab_completion(char *ud, int *num_matches) return (matches); } } -#endif /* BB_FEATURE_COMMAND_USERNAME_COMPLETION */ +#endif /* CONFIG_FEATURE_COMMAND_USERNAME_COMPLETION */ enum { FIND_EXE_ONLY = 0, @@ -776,7 +687,7 @@ static char **exe_n_cwd_tab_completion(char *command, int *num_matches, char **paths = path1; int npaths; int i; - char found[BUFSIZ + 4 + PATH_MAX]; + char *found; char *pfind = strrchr(command, '/'); path1[0] = "."; @@ -791,7 +702,7 @@ static char **exe_n_cwd_tab_completion(char *command, int *num_matches, 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 @@ -809,7 +720,6 @@ static char **exe_n_cwd_tab_completion(char *command, int *num_matches, continue; while ((next = readdir(dir)) != NULL) { - const char *str_merge = "%s/%s"; char *str_found = next->d_name; /* matched ? */ @@ -822,34 +732,34 @@ static char **exe_n_cwd_tab_completion(char *command, int *num_matches, else continue; } - if (paths[i][strlen(paths[i]) - 1] == '/') - str_merge = "%s%s"; - sprintf(found, str_merge, paths[i], str_found); + found = concat_path_file(paths[i], str_found); /* hmm, remover in progress? */ - if (stat(found, &st) < 0) - continue; + if (stat(found, &st) < 0) + goto cont; /* find with dirs ? */ if (paths[i] != dirbuf) strcpy(found, next->d_name); /* only name */ if (S_ISDIR(st.st_mode)) { /* name is directory */ - /* algorithmic only "/" ? */ - if (*str_found) - strcat(found, "/"); + str_found = found; + found = concat_path_file(found, ""); + free(str_found); str_found = add_quote_for_spec_chars(found); } else { /* not put found file if search only dirs for cd */ - if (type == FIND_DIR_ONLY) - continue; + if (type == FIND_DIR_ONLY) + 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 */ matches = xrealloc(matches, (nm + 1) * sizeof(char *)); matches[nm++] = str_found; +cont: + free(found); } closedir(dir); } @@ -871,8 +781,8 @@ static int match_compare(const void *a, const void *b) #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) { @@ -898,12 +808,12 @@ 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 @@ -1022,17 +932,14 @@ static int find_match(char *matchBuf, int *len_with_quotes) || (int_buf[i + 1] & ~QUOT) == '~')) { i++; } - if (i) { - collapse_pos(0, i); - } /* set only match and destroy quotes */ j = 0; - for (i = 0; pos_buf[i] >= 0; i++) { - matchBuf[i] = matchBuf[pos_buf[i]]; + for (c = 0; pos_buf[i] >= 0; i++) { + matchBuf[c++] = matchBuf[pos_buf[i]]; j = pos_buf[i] + 1; } - matchBuf[i] = 0; + matchBuf[c] = 0; /* old lenght matchBuf with quotes symbols */ *len_with_quotes = j ? j - pos_buf[0] : 0; @@ -1055,7 +962,7 @@ static void input_tab(int *lastWasTab) } return; } - if (*lastWasTab == FALSE) { + if (! *lastWasTab) { char *tmp; int len_found; @@ -1075,7 +982,7 @@ static void input_tab(int *lastWasTab) /* 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. */ @@ -1086,9 +993,30 @@ static void input_tab(int *lastWasTab) * in the current working directory that matches. */ if (!matches) matches = - exe_n_cwd_tab_completion(matchBuf, &num_matches, - find_type); - + exe_n_cwd_tab_completion(matchBuf, + &num_matches, find_type); + /* Remove duplicate found */ + if(matches) { + int i, j; + /* bubble */ + for(i=0; i<(num_matches-1); i++) + for(j=i+1; j 1) { char *tmp1; @@ -1136,8 +1064,7 @@ static void input_tab(int *lastWasTab) /* new len */ len = strlen(command_ps); /* write out the matched command */ - input_end(); - input_backward(cursor - recalc_pos); + redraw(cmdedit_y, len - recalc_pos); } if (tmp != matches[0]) free(tmp); @@ -1174,20 +1101,31 @@ static void input_tab(int *lastWasTab) } } } -#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, @@ -1212,38 +1150,37 @@ enum { * */ -extern void cmdedit_read_input(char *prompt, char command[BUFSIZ]) -{ - int inputFd = fileno(stdin); +int cmdedit_read_input(char *prompt, char command[BUFSIZ]) +{ 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 */ len = 0; command_ps = command; - if (new_settings.c_cc[VMIN] == 0) { /* first call */ - - getTermSettings(inputFd, (void *) &initial_settings); - memcpy(&new_settings, &initial_settings, sizeof(struct termios)); - - new_settings.c_cc[VMIN] = 1; - new_settings.c_cc[VTIME] = 0; - /* Turn off CTRL-C, so we can trap it */ - new_settings.c_cc[VINTR] = _POSIX_VDISABLE; - new_settings.c_lflag &= ~ICANON; /* unbuffered input */ - /* Turn off echoing */ - new_settings.c_lflag &= ~(ECHO | ECHOCTL | ECHONL); - } - + getTermSettings(0, (void *) &initial_settings); + memcpy(&new_settings, &initial_settings, sizeof(struct termios)); + 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); +#ifndef linux + /* Hmm, in linux c_cc[] not parsed if set ~ICANON */ + new_settings.c_cc[VMIN] = 1; + new_settings.c_cc[VTIME] = 0; + /* Turn off CTRL-C, so we can trap it */ +# ifndef _POSIX_VDISABLE +# define _POSIX_VDISABLE '\0' +# endif + new_settings.c_cc[VINTR] = _POSIX_VDISABLE; +#endif command[0] = 0; - setTermSettings(inputFd, (void *) &new_settings); + setTermSettings(0, (void *) &new_settings); handlers_sets |= SET_RESET_TERM; /* Now initialize things */ @@ -1255,8 +1192,9 @@ extern void cmdedit_read_input(char *prompt, char command[BUFSIZ]) fflush(stdout); /* buffered out to fast */ - if (read(inputFd, &c, 1) < 1) - return; + if (safe_read(0, &c, 1) < 1) + /* if we can't read input then exit */ + goto prepare_to_die; switch (c) { case '\n': @@ -1275,21 +1213,26 @@ extern void cmdedit_read_input(char *prompt, char command[BUFSIZ]) break; case 3: /* Control-c -- stop gathering input */ - - /* Link into lash to reset context to 0 on ^C and such */ - shell_context = 0; - - /* Go to the next line */ goto_new_line(); command[0] = 0; - - return; + len = 0; + lastWasTab = FALSE; + put_prompt(); + break; case 4: /* Control-d -- Delete one character, or exit * if the len=0 and no chars to delete */ if (len == 0) { +prepare_to_die: +#if !defined(CONFIG_ASH) printf("exit"); - clean_up_and_die(0); + goto_new_line(); + /* cmdedit_reset_term() called in atexit */ + exit(EXIT_SUCCESS); +#else + break_out = -1; /* for control stoped jobs */ + break; +#endif } else { input_delete(); } @@ -1308,28 +1251,37 @@ extern void cmdedit_read_input(char *prompt, char command[BUFSIZ]) 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) { @@ -1337,27 +1289,27 @@ extern void cmdedit_read_input(char *prompt, char command[BUFSIZ]) redraw(cmdedit_y, len -= cursor); } break; - case ESC:{ /* escape sequence follows */ - if (read(inputFd, &c, 1) < 1) - return; + if (safe_read(0, &c, 1) < 1) + goto prepare_to_die; /* different vt100 emulations */ if (c == '[' || c == 'O') { - if (read(inputFd, &c, 1) < 1) - return; + 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(); @@ -1365,21 +1317,16 @@ extern void cmdedit_read_input(char *prompt, char command[BUFSIZ]) 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(); @@ -1409,25 +1356,25 @@ extern void cmdedit_read_input(char *prompt, char command[BUFSIZ]) } if (c >= '1' && c <= '9') do - if (read(inputFd, &c, 1) < 1) - return; + if (safe_read(0, &c, 1) < 1) + goto prepare_to_die; while (c != '~'); break; } 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 (read(inputFd, &c, 1) < 1) - return; + if (safe_read(0, &c, 1) < 1) + goto prepare_to_die; if (c == 0) { beep(); break; } } else #endif - if (!isprint(c)) /* Skip non-printable characters */ + if (!Isprint(c)) /* Skip non-printable characters */ break; if (len >= (BUFSIZ - 2)) /* Need to leave space for enter */ @@ -1460,98 +1407,69 @@ extern void cmdedit_read_input(char *prompt, char command[BUFSIZ]) lastWasTab = FALSE; } - setTermSettings(inputFd, (void *) &initial_settings); + 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_SIMPLE_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_SIMPLE_PROMPT) +#if defined(CONFIG_FEATURE_SH_FANCY_PROMPT) free(cmdedit_prompt); #endif - return; + cmdedit_reset_term(); + return len; } -/* Undo the effects of cmdedit_init(). */ -extern void cmdedit_terminate(void) -{ - cmdedit_reset_term(); - if ((handlers_sets & SET_TERM_HANDLERS) != 0) { - signal(SIGKILL, SIG_DFL); - signal(SIGINT, SIG_DFL); - signal(SIGQUIT, SIG_DFL); - signal(SIGTERM, SIG_DFL); - signal(SIGWINCH, SIG_DFL); - handlers_sets &= ~SET_TERM_HANDLERS; - } -} -#endif /* BB_FEATURE_COMMAND_EDITING */ +#endif /* CONFIG_FEATURE_COMMAND_EDITING */ #ifdef TEST -#ifdef BB_FEATURE_NONPRINTABLE_INVERSE_PUT +const char *applet_name = "debug stuff usage"; +const char *memory_exhausted = "Memory exhausted"; + +#ifdef CONFIG_FEATURE_NONPRINTABLE_INVERSE_PUT #include #endif -unsigned int shell_context; - int main(int argc, char **argv) { char buff[BUFSIZ]; char *prompt = -#if !defined(BB_FEATURE_SH_SIMPLE_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\\]"; @@ -1559,18 +1477,19 @@ int main(int argc, char **argv) "% "; #endif -#ifdef BB_FEATURE_NONPRINTABLE_INVERSE_PUT +#ifdef CONFIG_FEATURE_NONPRINTABLE_INVERSE_PUT setlocale(LC_ALL, ""); #endif - shell_context = 1; - do { + while(1) { int l; cmdedit_read_input(prompt, buff); l = strlen(buff); + if(l==0) + break; if(l > 0 && buff[l-1] == '\n') buff[l-1] = 0; printf("*** cmdedit_read_input() returned line =%s=\n", buff); - } while (shell_context); + } printf("*** cmdedit_read_input() detect ^C\n"); return 0; }