aboutsummaryrefslogtreecommitdiff
path: root/libbb
diff options
context:
space:
mode:
authorDenys Vlasenko <dvlasenk@redhat.com>2010-09-03 12:51:36 +0200
committerDenys Vlasenko <dvlasenk@redhat.com>2010-09-03 12:51:36 +0200
commit57ea9b488b096e17418a808d20f263daea468974 (patch)
tree863e814d727aeb12c4bbbfdd1a8feca6336ea510 /libbb
parent7063e86d0d6e0be7f8eed4f7b435a7be3f26ecdd (diff)
downloadbusybox-w32-57ea9b488b096e17418a808d20f263daea468974.tar.gz
busybox-w32-57ea9b488b096e17418a808d20f263daea468974.tar.bz2
busybox-w32-57ea9b488b096e17418a808d20f263daea468974.zip
preparatory cleanup patch for tab completion fixes
renames and deinlines a few functions function old new delta input_tab - 1041 +1041 complete_cmd_dir_file - 699 +699 complete_username - 121 +121 username_completion 121 - -121 read_line_input 5002 3313 -1689 ------------------------------------------------------------------------------ (add/remove: 3/1 grow/shrink: 0/1 up/down: 1861/-1810) Total: 51 bytes Signed-off-by: Denys Vlasenko <dvlasenk@redhat.com>
Diffstat (limited to 'libbb')
-rw-r--r--libbb/lineedit.c126
1 files changed, 65 insertions, 61 deletions
diff --git a/libbb/lineedit.c b/libbb/lineedit.c
index 35f1d0031..7bb709f9d 100644
--- a/libbb/lineedit.c
+++ b/libbb/lineedit.c
@@ -1,6 +1,6 @@
1/* vi: set sw=4 ts=4: */ 1/* vi: set sw=4 ts=4: */
2/* 2/*
3 * Termios command line History and Editing. 3 * Command line editing.
4 * 4 *
5 * Copyright (c) 1986-2003 may safely be consumed by a BSD or GPL license. 5 * Copyright (c) 1986-2003 may safely be consumed by a BSD or GPL license.
6 * Written by: Vladimir Oleynik <dzo@simtreas.ru> 6 * Written by: Vladimir Oleynik <dzo@simtreas.ru>
@@ -194,7 +194,7 @@ static void deinit_S(void)
194{ 194{
195#if ENABLE_FEATURE_EDITING_FANCY_PROMPT 195#if ENABLE_FEATURE_EDITING_FANCY_PROMPT
196 /* This one is allocated only if FANCY_PROMPT is on 196 /* This one is allocated only if FANCY_PROMPT is on
197 * (otherwise it points to verbatim prompt (NOT malloced) */ 197 * (otherwise it points to verbatim prompt (NOT malloced)) */
198 free((char*)cmdedit_prompt); 198 free((char*)cmdedit_prompt);
199#endif 199#endif
200#if ENABLE_USERNAME_OR_HOMEDIR 200#if ENABLE_USERNAME_OR_HOMEDIR
@@ -213,7 +213,7 @@ static size_t load_string(const char *src, int maxsize)
213 ssize_t len = mbstowcs(command_ps, src, maxsize - 1); 213 ssize_t len = mbstowcs(command_ps, src, maxsize - 1);
214 if (len < 0) 214 if (len < 0)
215 len = 0; 215 len = 0;
216 command_ps[len] = 0; 216 command_ps[len] = BB_NUL;
217 return len; 217 return len;
218} 218}
219static unsigned save_string(char *dst, unsigned maxsize) 219static unsigned save_string(char *dst, unsigned maxsize)
@@ -234,17 +234,17 @@ static unsigned save_string(char *dst, unsigned maxsize)
234 int n = srcpos; 234 int n = srcpos;
235 235
236 /* Convert up to 1st invalid byte (or up to end) */ 236 /* Convert up to 1st invalid byte (or up to end) */
237 while ((wc = command_ps[srcpos]) != 0 237 while ((wc = command_ps[srcpos]) != BB_NUL
238 && !unicode_is_raw_byte(wc) 238 && !unicode_is_raw_byte(wc)
239 ) { 239 ) {
240 srcpos++; 240 srcpos++;
241 } 241 }
242 command_ps[srcpos] = 0; 242 command_ps[srcpos] = BB_NUL;
243 n = wcstombs(dst + dstpos, command_ps + n, maxsize - dstpos); 243 n = wcstombs(dst + dstpos, command_ps + n, maxsize - dstpos);
244 if (n < 0) /* should not happen */ 244 if (n < 0) /* should not happen */
245 break; 245 break;
246 dstpos += n; 246 dstpos += n;
247 if (wc == 0) /* usually is */ 247 if (wc == BB_NUL) /* usually is */
248 break; 248 break;
249 249
250 /* We do have invalid byte here! */ 250 /* We do have invalid byte here! */
@@ -639,7 +639,7 @@ static char *username_path_completion(char *ud)
639} 639}
640 640
641/* ~use<tab> - find all users with this prefix */ 641/* ~use<tab> - find all users with this prefix */
642static NOINLINE void username_completion(const char *ud) 642static NOINLINE void complete_username(const char *ud)
643{ 643{
644 /* Using _r function to avoid pulling in static buffers */ 644 /* Using _r function to avoid pulling in static buffers */
645 char line_buff[256]; 645 char line_buff[256];
@@ -659,7 +659,7 @@ static NOINLINE void username_completion(const char *ud)
659 } 659 }
660 endpwent(); 660 endpwent();
661} 661}
662#endif /* FEATURE_COMMAND_USERNAME_COMPLETION */ 662#endif /* FEATURE_USERNAME_COMPLETION */
663 663
664enum { 664enum {
665 FIND_EXE_ONLY = 0, 665 FIND_EXE_ONLY = 0,
@@ -710,7 +710,7 @@ static int path_parse(char ***p)
710 return npth; 710 return npth;
711} 711}
712 712
713static void exe_n_cwd_tab_completion(char *command, int type) 713static NOINLINE void complete_cmd_dir_file(char *command, int type)
714{ 714{
715 char *path1[1]; 715 char *path1[1];
716 char **paths = path1; 716 char **paths = path1;
@@ -799,24 +799,25 @@ static void exe_n_cwd_tab_completion(char *command, int type)
799 free(dirbuf); 799 free(dirbuf);
800} 800}
801 801
802/* build_match_prefix:
803 * On entry, matchBuf contains everything up to cursor at the moment <tab>
804 * was pressed. This function looks at it, figures out what part of it
805 * constitutes the command/file/directory prefix to use for completion,
806 * and rewrites matchBuf to contain only that part.
807 */
808/* Helpers: */
802/* QUOT is used on elements of int_buf[], which are bytes, 809/* QUOT is used on elements of int_buf[], which are bytes,
803 * not Unicode chars. Therefore it works correctly even in Unicode mode. 810 * not Unicode chars. Therefore it works correctly even in Unicode mode.
804 */ 811 */
805#define QUOT (UCHAR_MAX+1) 812#define QUOT (UCHAR_MAX+1)
806
807#define int_buf (S.find_match__int_buf) 813#define int_buf (S.find_match__int_buf)
808#define pos_buf (S.find_match__pos_buf) 814#define pos_buf (S.find_match__pos_buf)
809/* is must be <= in */ 815static void collapse_pos(int beg, int end)
810static void collapse_pos(int is, int in)
811{ 816{
812 memmove(int_buf+is, int_buf+in, (MAX_LINELEN+1-in) * sizeof(int_buf[0])); 817 /* beg must be <= end */
813 memmove(pos_buf+is, pos_buf+in, (MAX_LINELEN+1-in) * sizeof(pos_buf[0])); 818 memmove(int_buf+beg, int_buf+end, (MAX_LINELEN+1-end) * sizeof(int_buf[0]));
819 memmove(pos_buf+beg, pos_buf+end, (MAX_LINELEN+1-end) * sizeof(pos_buf[0]));
814} 820}
815/* On entry, matchBuf contains everything up to cursor at the moment <tab>
816 * was pressed. This function looks at it, figures out what part of it
817 * constitutes the command/file/directory prefix to use for completion,
818 * and rewrites matchBuf to contain only that part.
819 */
820static NOINLINE int build_match_prefix(char *matchBuf, int *len_with_quotes) 821static NOINLINE int build_match_prefix(char *matchBuf, int *len_with_quotes)
821{ 822{
822 int i, j; 823 int i, j;
@@ -826,17 +827,16 @@ static NOINLINE int build_match_prefix(char *matchBuf, int *len_with_quotes)
826/* int16_t int_buf[MAX_LINELEN + 1]; */ 827/* int16_t int_buf[MAX_LINELEN + 1]; */
827/* int16_t pos_buf[MAX_LINELEN + 1]; */ 828/* int16_t pos_buf[MAX_LINELEN + 1]; */
828 829
829 /* set to integer dimension characters and own positions */
830 for (i = 0;; i++) { 830 for (i = 0;; i++) {
831 int_buf[i] = (unsigned char)matchBuf[i]; 831 int_buf[i] = (unsigned char)matchBuf[i];
832 if (int_buf[i] == 0) { 832 if (int_buf[i] == 0) {
833 pos_buf[i] = -1; /* end-fo-line indicator */ 833 pos_buf[i] = -1; /* end-of-line indicator */
834 break; 834 break;
835 } 835 }
836 pos_buf[i] = i; 836 pos_buf[i] = i;
837 } 837 }
838 838
839 /* mask \+symbol and convert '\t' to ' ' */ 839 /* Mark every \c as "quoted c" */
840 for (i = j = 0; matchBuf[i]; i++, j++) { 840 for (i = j = 0; matchBuf[i]; i++, j++) {
841 if (matchBuf[i] == '\\') { 841 if (matchBuf[i] == '\\') {
842 collapse_pos(j, j + 1); 842 collapse_pos(j, j + 1);
@@ -844,7 +844,7 @@ static NOINLINE int build_match_prefix(char *matchBuf, int *len_with_quotes)
844 i++; 844 i++;
845 } 845 }
846 } 846 }
847 /* mask "symbols" or 'symbols' */ 847 /* Quote-mark "chars" and 'chars' */
848 c2 = 0; 848 c2 = 0;
849 for (i = 0; int_buf[i]; i++) { 849 for (i = 0; int_buf[i]; i++) {
850 c = int_buf[i]; 850 c = int_buf[i];
@@ -861,8 +861,10 @@ static NOINLINE int build_match_prefix(char *matchBuf, int *len_with_quotes)
861 int_buf[i] |= QUOT; 861 int_buf[i] |= QUOT;
862 } 862 }
863 863
864 /* skip commands with arguments if line has commands delimiters */ 864 /* Remove everything up to command delimiters:
865 /* ';' ';;' '&' '|' '&&' '||' but '>&' '<&' '>|' */ 865 * ';' ';;' '&' '|' '&&' '||',
866 * but careful with '>&' '<&' '>|'
867 */
866 for (i = 0; int_buf[i]; i++) { 868 for (i = 0; int_buf[i]; i++) {
867 int n; 869 int n;
868 c = int_buf[i]; 870 c = int_buf[i];
@@ -879,28 +881,29 @@ static NOINLINE int build_match_prefix(char *matchBuf, int *len_with_quotes)
879 } 881 }
880 if (n) { 882 if (n) {
881 collapse_pos(0, i + n); 883 collapse_pos(0, i + n);
882 i = -1; /* hack incremet */ 884 i = -1; /* hack increment */
883 } 885 }
884 } 886 }
885 /* collapse `command...` */ 887 /* Remove all `cmd` */
886 for (i = 0; int_buf[i]; i++) { 888 for (i = 0; int_buf[i]; i++) {
887 if (int_buf[i] == '`') { 889 if (int_buf[i] == '`') {
888 for (j = i + 1; int_buf[j]; j++) 890 for (j = i + 1; int_buf[j]; j++) {
889 if (int_buf[j] == '`') { 891 if (int_buf[j] == '`') {
890 collapse_pos(i, j + 1); 892 collapse_pos(i, j + 1);
891 j = 0; 893 j = 0;
892 break; 894 break;
893 } 895 }
896 }
894 if (j) { 897 if (j) {
895 /* not found closing ` - command mode, collapse all previous */ 898 /* No closing ` - command mode, remove all up to ` */
896 collapse_pos(0, i + 1); 899 collapse_pos(0, i + 1);
897 break; 900 break;
898 } else 901 }
899 i--; /* hack incremet */ 902 i--; /* hack increment */
900 } 903 }
901 } 904 }
902 905
903 /* collapse (command...(command...)...) or {command...{command...}...} */ 906 /* Remove (command...(command...)...) and {command...{command...}...} */
904 c = 0; /* "recursive" level */ 907 c = 0; /* "recursive" level */
905 c2 = 0; 908 c2 = 0;
906 for (i = 0; int_buf[i]; i++) { 909 for (i = 0; int_buf[i]; i++) {
@@ -910,7 +913,7 @@ static NOINLINE int build_match_prefix(char *matchBuf, int *len_with_quotes)
910 else 913 else
911 c2++; 914 c2++;
912 collapse_pos(0, i + 1); 915 collapse_pos(0, i + 1);
913 i = -1; /* hack incremet */ 916 i = -1; /* hack increment */
914 } 917 }
915 } 918 }
916 for (i = 0; pos_buf[i] >= 0 && (c > 0 || c2 > 0); i++) { 919 for (i = 0; pos_buf[i] >= 0 && (c > 0 || c2 > 0); i++) {
@@ -920,22 +923,23 @@ static NOINLINE int build_match_prefix(char *matchBuf, int *len_with_quotes)
920 else 923 else
921 c2--; 924 c2--;
922 collapse_pos(0, i + 1); 925 collapse_pos(0, i + 1);
923 i = -1; /* hack incremet */ 926 i = -1; /* hack increment */
924 } 927 }
925 } 928 }
926 929
927 /* skip first not quote space */ 930 /* Remove leading unquoted spaces */
928 for (i = 0; int_buf[i]; i++) 931 for (i = 0; int_buf[i]; i++)
929 if (int_buf[i] != ' ') 932 if (int_buf[i] != ' ')
930 break; 933 break;
931 if (i) 934 if (i)
932 collapse_pos(0, i); 935 collapse_pos(0, i);
933 936
934 /* set find mode for completion */ 937 /* Determine completion mode */
935 command_mode = FIND_EXE_ONLY; 938 command_mode = FIND_EXE_ONLY;
936 for (i = 0; int_buf[i]; i++) { 939 for (i = 0; int_buf[i]; i++) {
937 if (int_buf[i] == ' ' || int_buf[i] == '<' || int_buf[i] == '>') { 940 if (int_buf[i] == ' ' || int_buf[i] == '<' || int_buf[i] == '>') {
938 if (int_buf[i] == ' ' && command_mode == FIND_EXE_ONLY 941 if (int_buf[i] == ' '
942 && command_mode == FIND_EXE_ONLY
939 && matchBuf[pos_buf[0]] == 'c' 943 && matchBuf[pos_buf[0]] == 'c'
940 && matchBuf[pos_buf[1]] == 'd' 944 && matchBuf[pos_buf[1]] == 'd'
941 ) { 945 ) {
@@ -946,9 +950,10 @@ static NOINLINE int build_match_prefix(char *matchBuf, int *len_with_quotes)
946 } 950 }
947 } 951 }
948 } 952 }
953
954 /* Remove everything except last word */
949 for (i = 0; int_buf[i]; i++) /* quasi-strlen(int_buf) */ 955 for (i = 0; int_buf[i]; i++) /* quasi-strlen(int_buf) */
950 continue; 956 continue;
951 /* find last word */
952 for (--i; i >= 0; i--) { 957 for (--i; i >= 0; i--) {
953 c = int_buf[i]; 958 c = int_buf[i];
954 if (c == ' ' || c == '<' || c == '>' || c == '|' || c == '&') { 959 if (c == ' ' || c == '<' || c == '>' || c == '|' || c == '&') {
@@ -956,7 +961,7 @@ static NOINLINE int build_match_prefix(char *matchBuf, int *len_with_quotes)
956 break; 961 break;
957 } 962 }
958 } 963 }
959 /* skip first not quoted '\'' or '"' */ 964 /* Skip all leading unquoted ' or " */
960 for (i = 0; int_buf[i] == '\'' || int_buf[i] == '"'; i++) 965 for (i = 0; int_buf[i] == '\'' || int_buf[i] == '"'; i++)
961 continue; 966 continue;
962 /* collapse quote or unquote // or /~ */ 967 /* collapse quote or unquote // or /~ */
@@ -982,8 +987,8 @@ static NOINLINE int build_match_prefix(char *matchBuf, int *len_with_quotes)
982#undef pos_buf 987#undef pos_buf
983 988
984/* 989/*
985 * display by column (original idea from ls applet, 990 * Display by column (original idea from ls applet,
986 * very optimized by me :) 991 * very optimized by me [Vladimir] :)
987 */ 992 */
988static void showfiles(void) 993static void showfiles(void)
989{ 994{
@@ -1040,7 +1045,7 @@ static char *add_quote_for_spec_chars(char *found)
1040} 1045}
1041 1046
1042/* Do TAB completion */ 1047/* Do TAB completion */
1043static void input_tab(smallint *lastWasTab) 1048static NOINLINE void input_tab(smallint *lastWasTab)
1044{ 1049{
1045 if (!(state->flags & TAB_COMPLETION)) 1050 if (!(state->flags & TAB_COMPLETION))
1046 return; 1051 return;
@@ -1057,7 +1062,7 @@ static void input_tab(smallint *lastWasTab)
1057 int cursor_mb; 1062 int cursor_mb;
1058#endif 1063#endif
1059 1064
1060 *lastWasTab = TRUE; /* flop trigger */ 1065 *lastWasTab = 1;
1061 1066
1062 /* Make a local copy of the string -- 1067 /* Make a local copy of the string --
1063 * up to the position of the cursor */ 1068 * up to the position of the cursor */
@@ -1066,7 +1071,7 @@ static void input_tab(smallint *lastWasTab)
1066#else 1071#else
1067 { 1072 {
1068 CHAR_T wc = command_ps[cursor]; 1073 CHAR_T wc = command_ps[cursor];
1069 command_ps[cursor] = 0; 1074 command_ps[cursor] = BB_NUL;
1070 save_string(matchBuf, MAX_LINELEN); 1075 save_string(matchBuf, MAX_LINELEN);
1071 command_ps[cursor] = wc; 1076 command_ps[cursor] = wc;
1072 cursor_mb = strlen(matchBuf); 1077 cursor_mb = strlen(matchBuf);
@@ -1084,26 +1089,25 @@ static void input_tab(smallint *lastWasTab)
1084 * then try completing this word as a username. */ 1089 * then try completing this word as a username. */
1085 if (state->flags & USERNAME_COMPLETION) 1090 if (state->flags & USERNAME_COMPLETION)
1086 if (matchBuf[0] == '~' && strchr(matchBuf, '/') == NULL) 1091 if (matchBuf[0] == '~' && strchr(matchBuf, '/') == NULL)
1087 username_completion(matchBuf); 1092 complete_username(matchBuf);
1088#endif 1093#endif
1089 /* Try to match any executable in our path and everything 1094 /* Try to match a command in $PATH, or a directory, or a file */
1090 * in the current working directory */
1091 if (!matches) 1095 if (!matches)
1092 exe_n_cwd_tab_completion(matchBuf, find_type); 1096 complete_cmd_dir_file(matchBuf, find_type);
1093 /* Sort, then remove any duplicates found */ 1097 /* Remove duplicates */
1094 if (matches) { 1098 if (matches) {
1095 unsigned i; 1099 unsigned i;
1096 unsigned n = 0; 1100 unsigned n = 0;
1097 qsort_string_vector(matches, num_matches); 1101 qsort_string_vector(matches, num_matches);
1098 for (i = 0; i < num_matches - 1; ++i) { 1102 for (i = 0; i < num_matches - 1; ++i) {
1099 if (matches[i] && matches[i+1]) { /* paranoia */ 1103 //if (matches[i] && matches[i+1]) { /* paranoia */
1100 if (strcmp(matches[i], matches[i+1]) == 0) { 1104 if (strcmp(matches[i], matches[i+1]) == 0) {
1101 free(matches[i]); 1105 free(matches[i]);
1102 matches[i] = NULL; /* paranoia */ 1106 //matches[i] = NULL; /* paranoia */
1103 } else { 1107 } else {
1104 matches[n++] = matches[i]; 1108 matches[n++] = matches[i];
1105 } 1109 }
1106 } 1110 //}
1107 } 1111 }
1108 matches[n++] = matches[i]; 1112 matches[n++] = matches[i];
1109 num_matches = n; 1113 num_matches = n;
@@ -1113,7 +1117,7 @@ static void input_tab(smallint *lastWasTab)
1113 beep(); 1117 beep();
1114 if (!matches) 1118 if (!matches)
1115 return; /* no matches at all */ 1119 return; /* no matches at all */
1116 /* find minimal match */ 1120 /* Find common prefix */
1117 tmp1 = xstrdup(matches[0]); 1121 tmp1 = xstrdup(matches[0]);
1118 for (tmp = tmp1; *tmp; tmp++) { 1122 for (tmp = tmp1; *tmp; tmp++) {
1119 for (len_found = 1; len_found < num_matches; len_found++) { 1123 for (len_found = 1; len_found < num_matches; len_found++) {
@@ -1123,7 +1127,7 @@ static void input_tab(smallint *lastWasTab)
1123 } 1127 }
1124 } 1128 }
1125 } 1129 }
1126 if (*tmp1 == '\0') { /* have unique pfx? */ 1130 if (*tmp1 == '\0') { /* have unique prefix? */
1127 free(tmp1); /* no */ 1131 free(tmp1); /* no */
1128 return; 1132 return;
1129 } 1133 }
@@ -1131,10 +1135,10 @@ static void input_tab(smallint *lastWasTab)
1131 free(tmp1); 1135 free(tmp1);
1132 len_found = strlen(tmp); 1136 len_found = strlen(tmp);
1133 } else { /* exactly one match */ 1137 } else { /* exactly one match */
1134 tmp = add_quote_for_spec_chars(matches[0]); 1138 /* Next <tab> is not a double-tab */
1135 /* for next completion current found */ 1139 *lastWasTab = 0;
1136 *lastWasTab = FALSE;
1137 1140
1141 tmp = add_quote_for_spec_chars(matches[0]);
1138 len_found = strlen(tmp); 1142 len_found = strlen(tmp);
1139 if (tmp[len_found-1] != '/') { 1143 if (tmp[len_found-1] != '/') {
1140 tmp[len_found] = ' '; 1144 tmp[len_found] = ' ';
@@ -1199,7 +1203,7 @@ static void input_tab(smallint *lastWasTab)
1199 } 1203 }
1200} 1204}
1201 1205
1202#endif /* FEATURE_COMMAND_TAB_COMPLETION */ 1206#endif /* FEATURE_TAB_COMPLETION */
1203 1207
1204 1208
1205line_input_t* FAST_FUNC new_line_input_t(int flags) 1209line_input_t* FAST_FUNC new_line_input_t(int flags)
@@ -1899,7 +1903,7 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li
1899{ 1903{
1900 int len; 1904 int len;
1901#if ENABLE_FEATURE_TAB_COMPLETION 1905#if ENABLE_FEATURE_TAB_COMPLETION
1902 smallint lastWasTab = FALSE; 1906 smallint lastWasTab = 0;
1903#endif 1907#endif
1904 smallint break_out = 0; 1908 smallint break_out = 0;
1905#if ENABLE_FEATURE_EDITING_VI 1909#if ENABLE_FEATURE_EDITING_VI
@@ -2375,7 +2379,7 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li
2375 2379
2376#if ENABLE_FEATURE_TAB_COMPLETION 2380#if ENABLE_FEATURE_TAB_COMPLETION
2377 if (ic_raw != '\t') 2381 if (ic_raw != '\t')
2378 lastWasTab = FALSE; 2382 lastWasTab = 0;
2379#endif 2383#endif
2380 } /* while (1) */ 2384 } /* while (1) */
2381 2385
@@ -2469,7 +2473,7 @@ int main(int argc, char **argv)
2469 l = read_line_input(prompt, buff); 2473 l = read_line_input(prompt, buff);
2470 if (l <= 0 || buff[l-1] != '\n') 2474 if (l <= 0 || buff[l-1] != '\n')
2471 break; 2475 break;
2472 buff[l-1] = 0; 2476 buff[l-1] = '\0';
2473 printf("*** read_line_input() returned line =%s=\n", buff); 2477 printf("*** read_line_input() returned line =%s=\n", buff);
2474 } 2478 }
2475 printf("*** read_line_input() detect ^D\n"); 2479 printf("*** read_line_input() detect ^D\n");