aboutsummaryrefslogtreecommitdiff
path: root/libbb/lineedit.c
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2021-01-14 13:28:49 +0000
committerRon Yorston <rmy@pobox.com>2021-01-14 13:28:49 +0000
commit89963b524d211e1aec12b72b3725be05ee95c8cf (patch)
tree48590aef62b7ee7686b7898256f29def8d9c50b9 /libbb/lineedit.c
parent9aa5a829070392c2ac6494d0c4e674c0c2bc7dab (diff)
parent2b7c1aa92c68524559a2067609d09309d5c09adc (diff)
downloadbusybox-w32-89963b524d211e1aec12b72b3725be05ee95c8cf.tar.gz
busybox-w32-89963b524d211e1aec12b72b3725be05ee95c8cf.tar.bz2
busybox-w32-89963b524d211e1aec12b72b3725be05ee95c8cf.zip
Merge branch 'busybox' into merge
Diffstat (limited to 'libbb/lineedit.c')
-rw-r--r--libbb/lineedit.c129
1 files changed, 81 insertions, 48 deletions
diff --git a/libbb/lineedit.c b/libbb/lineedit.c
index b35da1874..f3cbc512c 100644
--- a/libbb/lineedit.c
+++ b/libbb/lineedit.c
@@ -57,12 +57,23 @@
57#if ENABLE_FEATURE_EDITING 57#if ENABLE_FEATURE_EDITING
58 58
59 59
60#if !ENABLE_SHELL_ASH && !ENABLE_SHELL_HUSH
61/* so far only shells use these features */
62# undef ENABLE_FEATURE_EDITING_FANCY_PROMPT
63# undef ENABLE_FEATURE_TAB_COMPLETION
64# undef ENABLE_FEATURE_USERNAME_COMPLETION
65# define ENABLE_FEATURE_EDITING_FANCY_PROMPT 0
66# define ENABLE_FEATURE_TAB_COMPLETION 0
67# define ENABLE_FEATURE_USERNAME_COMPLETION 0
68#endif
69
70
60#define ENABLE_USERNAME_OR_HOMEDIR \ 71#define ENABLE_USERNAME_OR_HOMEDIR \
61 (ENABLE_FEATURE_USERNAME_COMPLETION || ENABLE_FEATURE_EDITING_FANCY_PROMPT) 72 (ENABLE_FEATURE_USERNAME_COMPLETION || ENABLE_FEATURE_EDITING_FANCY_PROMPT)
62#define IF_USERNAME_OR_HOMEDIR(...)
63#if ENABLE_USERNAME_OR_HOMEDIR 73#if ENABLE_USERNAME_OR_HOMEDIR
64# undef IF_USERNAME_OR_HOMEDIR
65# define IF_USERNAME_OR_HOMEDIR(...) __VA_ARGS__ 74# define IF_USERNAME_OR_HOMEDIR(...) __VA_ARGS__
75#else
76# define IF_USERNAME_OR_HOMEDIR(...) /*nothing*/
66#endif 77#endif
67 78
68 79
@@ -205,9 +216,6 @@ extern struct lineedit_statics *const lineedit_ptr_to_statics;
205#define INIT_S() do { \ 216#define INIT_S() do { \
206 (*(struct lineedit_statics**)not_const_pp(&lineedit_ptr_to_statics)) = xzalloc(sizeof(S)); \ 217 (*(struct lineedit_statics**)not_const_pp(&lineedit_ptr_to_statics)) = xzalloc(sizeof(S)); \
207 barrier(); \ 218 barrier(); \
208 cmdedit_termw = 80; \
209 IF_USERNAME_OR_HOMEDIR(home_pwd_buf = (char*)null_str;) \
210 IF_FEATURE_EDITING_VI(delptr = delbuf;) \
211} while (0) 219} while (0)
212 220
213static void deinit_S(void) 221static void deinit_S(void)
@@ -796,16 +804,18 @@ enum {
796 FIND_FILE_ONLY = 2, 804 FIND_FILE_ONLY = 2,
797}; 805};
798 806
799static int path_parse(char ***p) 807static unsigned path_parse(char ***p)
800{ 808{
801 int npth; 809 unsigned npth;
802 const char *pth; 810 const char *pth;
803 char *tmp; 811 char *tmp;
804 char **res; 812 char **res;
805 813
814# if EDITING_HAS_path_lookup
806 if (state->flags & WITH_PATH_LOOKUP) 815 if (state->flags & WITH_PATH_LOOKUP)
807 pth = state->path_lookup; 816 pth = state->path_lookup;
808 else 817 else
818# endif
809 pth = getenv("PATH"); 819 pth = getenv("PATH");
810 820
811 /* PATH="" or PATH=":"? */ 821 /* PATH="" or PATH=":"? */
@@ -824,7 +834,7 @@ static int path_parse(char ***p)
824 npth++; 834 npth++;
825 } 835 }
826 836
827 *p = res = xmalloc(npth * sizeof(res[0])); 837 *p = res = xzalloc((npth + 1) * sizeof(res[0]));
828 res[0] = tmp = xstrdup(pth); 838 res[0] = tmp = xstrdup(pth);
829 npth = 1; 839 npth = 1;
830 while (1) { 840 while (1) {
@@ -836,6 +846,8 @@ static int path_parse(char ***p)
836 break; /* :<empty> */ 846 break; /* :<empty> */
837 res[npth++] = tmp; 847 res[npth++] = tmp;
838 } 848 }
849 /* special case: "match subdirectories of the current directory" */
850 /*res[npth++] = NULL; - filled by xzalloc() */
839 return npth; 851 return npth;
840} 852}
841 853
@@ -846,49 +858,49 @@ static NOINLINE unsigned complete_cmd_dir_file(const char *command, int type)
846{ 858{
847 char *path1[1]; 859 char *path1[1];
848 char **paths = path1; 860 char **paths = path1;
849 int npaths; 861 unsigned npaths;
850 int i; 862 unsigned i;
851 unsigned pf_len; 863 unsigned baselen;
852 const char *pfind; 864 const char *basecmd;
853 char *dirbuf = NULL; 865 char *dirbuf = NULL;
854 866
855 npaths = 1; 867 npaths = 1;
856 path1[0] = (char*)"."; 868 path1[0] = (char*)".";
857 869
858 pfind = strrchr(command, '/'); 870 basecmd = strrchr(command, '/');
859#if ENABLE_PLATFORM_MINGW32 871#if ENABLE_PLATFORM_MINGW32
860 if (!pfind && has_dos_drive_prefix(command) && command[2] != '\0') { 872 if (!basecmd && has_dos_drive_prefix(command) && command[2] != '\0') {
861 char buffer[PATH_MAX]; 873 char buffer[PATH_MAX];
862 874
863 /* path is of form c:path with no '/' */ 875 /* path is of form c:path with no '/' */
864 if (get_drive_cwd(command, buffer, PATH_MAX)) { 876 if (get_drive_cwd(command, buffer, PATH_MAX)) {
865 pfind = command + 2; 877 basecmd = command + 2;
866 path1[0] = dirbuf = xstrdup(buffer); 878 path1[0] = dirbuf = xstrdup(buffer);
867 } 879 }
868 } else 880 } else
869#endif 881#endif
870 if (!pfind) { 882 if (!basecmd) {
871 if (type == FIND_EXE_ONLY) 883 if (type == FIND_EXE_ONLY)
872 npaths = path_parse(&paths); 884 npaths = path_parse(&paths);
873 pfind = command; 885 basecmd = command;
874 } else { 886 } else {
875 /* point to 'l' in "..../last_component" */ 887 /* point to 'l' in "..../last_component" */
876 pfind++; 888 basecmd++;
877 /* dirbuf = ".../.../.../" */ 889 /* dirbuf = ".../.../.../" */
878 dirbuf = xstrndup(command, pfind - command); 890 dirbuf = xstrndup(command, basecmd - command);
879# if ENABLE_FEATURE_USERNAME_COMPLETION 891# if ENABLE_FEATURE_USERNAME_COMPLETION
880 if (dirbuf[0] == '~') /* ~/... or ~user/... */ 892 if (dirbuf[0] == '~') /* ~/... or ~user/... */
881 dirbuf = username_path_completion(dirbuf); 893 dirbuf = username_path_completion(dirbuf);
882# endif 894# endif
883 path1[0] = dirbuf; 895 path1[0] = dirbuf;
884 } 896 }
885 pf_len = strlen(pfind); 897 baselen = strlen(basecmd);
886 898
887 if (type == FIND_EXE_ONLY && !dirbuf) { 899 if (type == FIND_EXE_ONLY && !dirbuf) {
888# if ENABLE_FEATURE_SH_STANDALONE && NUM_APPLETS != 1 900# if ENABLE_FEATURE_SH_STANDALONE && NUM_APPLETS != 1
889 const char *p = applet_names; 901 const char *p = applet_names;
890 while (*p) { 902 while (*p) {
891 if (strncmp(pfind, p, pf_len) == 0) 903 if (strncmp(basecmd, p, baselen) == 0)
892 add_match(xstrdup(p)); 904 add_match(xstrdup(p));
893 while (*p++ != '\0') 905 while (*p++ != '\0')
894 continue; 906 continue;
@@ -901,7 +913,7 @@ static NOINLINE unsigned complete_cmd_dir_file(const char *command, int type)
901 const char *b = state->get_exe_name(i++); 913 const char *b = state->get_exe_name(i++);
902 if (!b) 914 if (!b)
903 break; 915 break;
904 if (strncmp(pfind, b, pf_len) == 0) 916 if (strncmp(basecmd, b, baselen) == 0)
905 add_match(xstrdup(b)); 917 add_match(xstrdup(b));
906 } 918 }
907 } 919 }
@@ -913,9 +925,20 @@ static NOINLINE unsigned complete_cmd_dir_file(const char *command, int type)
913 struct dirent *next; 925 struct dirent *next;
914 struct stat st; 926 struct stat st;
915 char *found; 927 char *found;
928#if ENABLE_PLATFORM_MINGW32
929 char *lpath;
930#endif
931
932 if (paths[i] == NULL) { /* path_parse()'s last component? */
933 /* in PATH completion, current dir's subdir names
934 * can be completions (but only subdirs, not files).
935 */
936 type = FIND_DIR_ONLY;
937 paths[i] = (char *)".";
938 }
916 939
917#if ENABLE_PLATFORM_MINGW32 940#if ENABLE_PLATFORM_MINGW32
918 char *lpath = auto_string(alloc_system_drive(paths[i])); 941 lpath = auto_string(alloc_system_drive(paths[i]));
919 dir = opendir(lpath); 942 dir = opendir(lpath);
920#else 943#else
921 dir = opendir(paths[i]); 944 dir = opendir(paths[i]);
@@ -928,10 +951,10 @@ static NOINLINE unsigned complete_cmd_dir_file(const char *command, int type)
928 const char *name_found = next->d_name; 951 const char *name_found = next->d_name;
929 952
930 /* .../<tab>: bash 3.2.0 shows dotfiles, but not . and .. */ 953 /* .../<tab>: bash 3.2.0 shows dotfiles, but not . and .. */
931 if (!pfind[0] && DOT_OR_DOTDOT(name_found)) 954 if (!basecmd[0] && DOT_OR_DOTDOT(name_found))
932 continue; 955 continue;
933 /* match? */ 956 /* match? */
934 if (!is_prefixed_with(name_found, pfind)) 957 if (strncmp(basecmd, name_found, baselen) != 0)
935 continue; /* no */ 958 continue; /* no */
936 959
937#if ENABLE_PLATFORM_MINGW32 960#if ENABLE_PLATFORM_MINGW32
@@ -957,6 +980,9 @@ static NOINLINE unsigned complete_cmd_dir_file(const char *command, int type)
957 strcpy(found, name_found); 980 strcpy(found, name_found);
958 981
959 if (S_ISDIR(st.st_mode)) { 982 if (S_ISDIR(st.st_mode)) {
983 /* skip directories if searching PATH */
984 if (type == FIND_EXE_ONLY && !dirbuf)
985 goto cont;
960 /* name is a directory, add slash */ 986 /* name is a directory, add slash */
961 found[len] = '/'; 987 found[len] = '/';
962 found[len + 1] = '\0'; 988 found[len + 1] = '\0';
@@ -980,7 +1006,7 @@ static NOINLINE unsigned complete_cmd_dir_file(const char *command, int type)
980 } 1006 }
981 free(dirbuf); 1007 free(dirbuf);
982 1008
983 return pf_len; 1009 return baselen;
984} 1010}
985 1011
986/* build_match_prefix: 1012/* build_match_prefix:
@@ -1492,15 +1518,19 @@ void FAST_FUNC show_history(const line_input_t *st)
1492 printf("%4d %s\n", i, st->history[i]); 1518 printf("%4d %s\n", i, st->history[i]);
1493} 1519}
1494 1520
1521# if ENABLE_FEATURE_EDITING_SAVEHISTORY
1495void FAST_FUNC free_line_input_t(line_input_t *n) 1522void FAST_FUNC free_line_input_t(line_input_t *n)
1496{ 1523{
1497# if ENABLE_FEATURE_EDITING_SAVEHISTORY 1524 if (n) {
1498 int i = n->cnt_history; 1525 int i = n->cnt_history;
1499 while (i > 0) 1526 while (i > 0)
1500 free(n->history[--i]); 1527 free(n->history[--i]);
1501#endif 1528 free(n);
1502 free(n); 1529 }
1503} 1530}
1531# else
1532/* #defined to free() in libbb.h */
1533# endif
1504 1534
1505# if ENABLE_FEATURE_EDITING_SAVEHISTORY 1535# if ENABLE_FEATURE_EDITING_SAVEHISTORY
1506/* We try to ensure that concurrent additions to the history 1536/* We try to ensure that concurrent additions to the history
@@ -1581,7 +1611,7 @@ void save_history(line_input_t *st)
1581{ 1611{
1582 FILE *fp; 1612 FILE *fp;
1583 1613
1584 if (!st->hist_file) 1614 if (!st || !st->hist_file)
1585 return; 1615 return;
1586 if (st->cnt_history <= st->cnt_history_in_file) 1616 if (st->cnt_history <= st->cnt_history_in_file)
1587 return; 1617 return;
@@ -1971,9 +2001,7 @@ static void parse_and_put_prompt(const char *prmt_ptr)
1971{ 2001{
1972 int prmt_size = 0; 2002 int prmt_size = 0;
1973 char *prmt_mem_ptr = xzalloc(1); 2003 char *prmt_mem_ptr = xzalloc(1);
1974# if ENABLE_USERNAME_OR_HOMEDIR
1975 char *cwd_buf = NULL; 2004 char *cwd_buf = NULL;
1976# endif
1977 char flg_not_length = '['; 2005 char flg_not_length = '[';
1978 char cbuf[2]; 2006 char cbuf[2];
1979 2007
@@ -2040,11 +2068,9 @@ static void parse_and_put_prompt(const char *prmt_ptr)
2040 c = *prmt_ptr++; 2068 c = *prmt_ptr++;
2041 2069
2042 switch (c) { 2070 switch (c) {
2043# if ENABLE_USERNAME_OR_HOMEDIR
2044 case 'u': 2071 case 'u':
2045 pbuf = user_buf ? user_buf : (char*)""; 2072 pbuf = user_buf ? user_buf : (char*)"";
2046 break; 2073 break;
2047# endif
2048 case 'H': 2074 case 'H':
2049 case 'h': 2075 case 'h':
2050 pbuf = free_me = safe_gethostname(); 2076 pbuf = free_me = safe_gethostname();
@@ -2062,7 +2088,6 @@ static void parse_and_put_prompt(const char *prmt_ptr)
2062 strftime_HHMMSS(timebuf, sizeof(timebuf), NULL)[-3] = '\0'; 2088 strftime_HHMMSS(timebuf, sizeof(timebuf), NULL)[-3] = '\0';
2063 pbuf = timebuf; 2089 pbuf = timebuf;
2064 break; 2090 break;
2065# if ENABLE_USERNAME_OR_HOMEDIR
2066 case 'w': /* current dir */ 2091 case 'w': /* current dir */
2067 case 'W': /* basename of cur dir */ 2092 case 'W': /* basename of cur dir */
2068 if (!cwd_buf) { 2093 if (!cwd_buf) {
@@ -2089,7 +2114,6 @@ static void parse_and_put_prompt(const char *prmt_ptr)
2089 if (cp) 2114 if (cp)
2090 pbuf = (char*)cp + 1; 2115 pbuf = (char*)cp + 1;
2091 break; 2116 break;
2092# endif
2093// bb_process_escape_sequence does this now: 2117// bb_process_escape_sequence does this now:
2094// case 'e': case 'E': /* \e \E = \033 */ 2118// case 'e': case 'E': /* \e \E = \033 */
2095// c = '\033'; 2119// c = '\033';
@@ -2130,10 +2154,17 @@ static void parse_and_put_prompt(const char *prmt_ptr)
2130 if (c == '\n') 2154 if (c == '\n')
2131 cmdedit_prmt_len = 0; 2155 cmdedit_prmt_len = 0;
2132 else if (flg_not_length != ']') { 2156 else if (flg_not_length != ']') {
2133#if 0 /*ENABLE_UNICODE_SUPPORT*/ 2157#if ENABLE_UNICODE_SUPPORT
2134/* Won't work, pbuf is one BYTE string here instead of an one Unicode char string. */ 2158 if (n == 1) {
2135/* FIXME */ 2159 /* Only count single-byte characters and the first of multi-byte characters */
2136 cmdedit_prmt_len += unicode_strwidth(pbuf); 2160 if ((unsigned char)*pbuf < 0x80 /* single byte character */
2161 || (unsigned char)*pbuf >= 0xc0 /* first of multi-byte characters */
2162 ) {
2163 cmdedit_prmt_len += n;
2164 }
2165 } else {
2166 cmdedit_prmt_len += unicode_strwidth(pbuf);
2167 }
2137#else 2168#else
2138 cmdedit_prmt_len += n; 2169 cmdedit_prmt_len += n;
2139#endif 2170#endif
@@ -2143,10 +2174,8 @@ static void parse_and_put_prompt(const char *prmt_ptr)
2143 free(free_me); 2174 free(free_me);
2144 } /* while */ 2175 } /* while */
2145 2176
2146# if ENABLE_USERNAME_OR_HOMEDIR
2147 if (cwd_buf != (char *)bb_msg_unknown) 2177 if (cwd_buf != (char *)bb_msg_unknown)
2148 free(cwd_buf); 2178 free(cwd_buf);
2149# endif
2150 /* see comment (above this function) about multiline prompt redrawing */ 2179 /* see comment (above this function) about multiline prompt redrawing */
2151 cmdedit_prompt = prompt_last_line = prmt_mem_ptr; 2180 cmdedit_prompt = prompt_last_line = prmt_mem_ptr;
2152 prmt_ptr = strrchr(cmdedit_prompt, '\n'); 2181 prmt_ptr = strrchr(cmdedit_prompt, '\n');
@@ -2154,7 +2183,7 @@ static void parse_and_put_prompt(const char *prmt_ptr)
2154 prompt_last_line = prmt_ptr + 1; 2183 prompt_last_line = prmt_ptr + 1;
2155 put_prompt(); 2184 put_prompt();
2156} 2185}
2157#endif 2186#endif /* FEATURE_EDITING_FANCY_PROMPT */
2158 2187
2159#if ENABLE_FEATURE_EDITING_WINCH 2188#if ENABLE_FEATURE_EDITING_WINCH
2160static void cmdedit_setwidth(void) 2189static void cmdedit_setwidth(void)
@@ -2467,6 +2496,11 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman
2467 char read_key_buffer[KEYCODE_BUFFER_SIZE]; 2496 char read_key_buffer[KEYCODE_BUFFER_SIZE];
2468 2497
2469 INIT_S(); 2498 INIT_S();
2499 //command_len = 0; - done by INIT_S()
2500 //cmdedit_y = 0; /* quasireal y, not true if line > xt*yt */
2501 cmdedit_termw = 80;
2502 IF_USERNAME_OR_HOMEDIR(home_pwd_buf = (char*)null_str;)
2503 IF_FEATURE_EDITING_VI(delptr = delbuf;)
2470 2504
2471#if !ENABLE_PLATFORM_MINGW32 2505#if !ENABLE_PLATFORM_MINGW32
2472 n = get_termios_and_make_raw(STDIN_FILENO, &new_settings, &initial_settings, 0 2506 n = get_termios_and_make_raw(STDIN_FILENO, &new_settings, &initial_settings, 0
@@ -2521,8 +2555,6 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman
2521#endif 2555#endif
2522 2556
2523 /* prepare before init handlers */ 2557 /* prepare before init handlers */
2524 cmdedit_y = 0; /* quasireal y, not true if line > xt*yt */
2525 command_len = 0;
2526#if ENABLE_UNICODE_SUPPORT 2558#if ENABLE_UNICODE_SUPPORT
2527 command_ps = xzalloc(maxsize * sizeof(command_ps[0])); 2559 command_ps = xzalloc(maxsize * sizeof(command_ps[0]));
2528#else 2560#else
@@ -3005,6 +3037,7 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman
3005 * before it comes in. UGLY! 3037 * before it comes in. UGLY!
3006 */ 3038 */
3007 usleep(20*1000); 3039 usleep(20*1000);
3040// MAYBE? tcflush(STDIN_FILENO, TCIFLUSH); /* flushes data received but not read */
3008 } 3041 }
3009#endif 3042#endif
3010 3043