diff options
author | Denys Vlasenko <dvlasenk@redhat.com> | 2010-09-03 12:56:36 +0200 |
---|---|---|
committer | Denys Vlasenko <dvlasenk@redhat.com> | 2010-09-03 12:56:36 +0200 |
commit | 3c460b005c3c422fe73dc464902e0626fc57938a (patch) | |
tree | 79d5d815280dac6d2f3e1c4cf534842c4ef4486e /libbb | |
parent | 2679e3c8cccbf3ae4cac8e735e5430ebbe714b00 (diff) | |
download | busybox-w32-3c460b005c3c422fe73dc464902e0626fc57938a.tar.gz busybox-w32-3c460b005c3c422fe73dc464902e0626fc57938a.tar.bz2 busybox-w32-3c460b005c3c422fe73dc464902e0626fc57938a.zip |
lineedit: return prefix len from tab completion helpers
This kills horrific logic which deletes and re-adds prefix (!)
function old new delta
complete_cmd_dir_file 705 731 +26
complete_username 121 124 +3
input_tab 1041 1016 -25
build_match_prefix 838 804 -34
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 2/2 up/down: 29/-59) Total: -30 bytes
Signed-off-by: Denys Vlasenko <dvlasenk@redhat.com>
Diffstat (limited to 'libbb')
-rw-r--r-- | libbb/lineedit.c | 86 |
1 files changed, 50 insertions, 36 deletions
diff --git a/libbb/lineedit.c b/libbb/lineedit.c index dd9d85b28..e40917f62 100644 --- a/libbb/lineedit.c +++ b/libbb/lineedit.c | |||
@@ -638,14 +638,16 @@ static char *username_path_completion(char *ud) | |||
638 | return tilde_name; | 638 | return tilde_name; |
639 | } | 639 | } |
640 | 640 | ||
641 | /* ~use<tab> - find all users with this prefix */ | 641 | /* ~use<tab> - find all users with this prefix. |
642 | static NOINLINE void complete_username(const char *ud) | 642 | * Return the length of the prefix used for matching. |
643 | */ | ||
644 | static NOINLINE unsigned complete_username(const char *ud) | ||
643 | { | 645 | { |
644 | /* Using _r function to avoid pulling in static buffers */ | 646 | /* Using _r function to avoid pulling in static buffers */ |
645 | char line_buff[256]; | 647 | char line_buff[256]; |
646 | struct passwd pwd; | 648 | struct passwd pwd; |
647 | struct passwd *result; | 649 | struct passwd *result; |
648 | int userlen; | 650 | unsigned userlen; |
649 | 651 | ||
650 | ud++; /* skip ~ */ | 652 | ud++; /* skip ~ */ |
651 | userlen = strlen(ud); | 653 | userlen = strlen(ud); |
@@ -658,6 +660,8 @@ static NOINLINE void complete_username(const char *ud) | |||
658 | } | 660 | } |
659 | } | 661 | } |
660 | endpwent(); | 662 | endpwent(); |
663 | |||
664 | return 1 + userlen; | ||
661 | } | 665 | } |
662 | #endif /* FEATURE_USERNAME_COMPLETION */ | 666 | #endif /* FEATURE_USERNAME_COMPLETION */ |
663 | 667 | ||
@@ -710,14 +714,17 @@ static int path_parse(char ***p) | |||
710 | return npth; | 714 | return npth; |
711 | } | 715 | } |
712 | 716 | ||
713 | static NOINLINE void complete_cmd_dir_file(char *command, int type) | 717 | /* Complete command, directory or file name. |
718 | * Return the length of the prefix used for matching. | ||
719 | */ | ||
720 | static NOINLINE unsigned complete_cmd_dir_file(const char *command, int type) | ||
714 | { | 721 | { |
715 | char *path1[1]; | 722 | char *path1[1]; |
716 | char **paths = path1; | 723 | char **paths = path1; |
717 | int npaths; | 724 | int npaths; |
718 | int i; | 725 | int i; |
719 | unsigned pf_len; | 726 | unsigned pf_len; |
720 | char *pfind; | 727 | const char *pfind; |
721 | char *dirbuf = NULL; | 728 | char *dirbuf = NULL; |
722 | 729 | ||
723 | npaths = 1; | 730 | npaths = 1; |
@@ -797,8 +804,12 @@ static NOINLINE void complete_cmd_dir_file(char *command, int type) | |||
797 | if (paths != path1) { | 804 | if (paths != path1) { |
798 | free(paths[0]); /* allocated memory is only in first member */ | 805 | free(paths[0]); /* allocated memory is only in first member */ |
799 | free(paths); | 806 | free(paths); |
807 | } else if (dirbuf) { | ||
808 | pf_len += strlen(dirbuf); | ||
809 | free(dirbuf); | ||
800 | } | 810 | } |
801 | free(dirbuf); | 811 | |
812 | return pf_len; | ||
802 | } | 813 | } |
803 | 814 | ||
804 | /* build_match_prefix: | 815 | /* build_match_prefix: |
@@ -829,7 +840,7 @@ static void collapse_pos(int beg, int end) | |||
829 | bb_putchar('\n'); | 840 | bb_putchar('\n'); |
830 | } | 841 | } |
831 | } | 842 | } |
832 | static NOINLINE int build_match_prefix(char *matchBuf, int *len_with_quotes) | 843 | static NOINLINE int build_match_prefix(char *matchBuf) |
833 | { | 844 | { |
834 | int i, j; | 845 | int i, j; |
835 | int command_mode; | 846 | int command_mode; |
@@ -992,9 +1003,6 @@ static NOINLINE int build_match_prefix(char *matchBuf, int *len_with_quotes) | |||
992 | pos = pos_buf[i] + 1; | 1003 | pos = pos_buf[i] + 1; |
993 | } | 1004 | } |
994 | matchBuf[j] = '\0'; | 1005 | matchBuf[j] = '\0'; |
995 | /* old length matchBuf with quotes symbols */ | ||
996 | *len_with_quotes = pos ? pos - pos_buf[0] : 0; | ||
997 | if (dbg_bmp) printf("len_with_quotes:%d\n", *len_with_quotes); | ||
998 | } | 1006 | } |
999 | 1007 | ||
1000 | return command_mode; | 1008 | return command_mode; |
@@ -1067,12 +1075,13 @@ static NOINLINE void input_tab(smallint *lastWasTab) | |||
1067 | return; | 1075 | return; |
1068 | 1076 | ||
1069 | if (!*lastWasTab) { | 1077 | if (!*lastWasTab) { |
1070 | char *tmp, *tmp1; | 1078 | char *tmp; |
1071 | size_t len_found; | 1079 | size_t len_found; |
1072 | /* char matchBuf[MAX_LINELEN]; */ | 1080 | /* char matchBuf[MAX_LINELEN]; */ |
1073 | #define matchBuf (S.input_tab__matchBuf) | 1081 | #define matchBuf (S.input_tab__matchBuf) |
1082 | /* Length of string used for matching */ | ||
1083 | unsigned match_pfx_len = match_pfx_len; | ||
1074 | int find_type; | 1084 | int find_type; |
1075 | int recalc_pos; | ||
1076 | #if ENABLE_UNICODE_SUPPORT | 1085 | #if ENABLE_UNICODE_SUPPORT |
1077 | /* cursor pos in command converted to multibyte form */ | 1086 | /* cursor pos in command converted to multibyte form */ |
1078 | int cursor_mb; | 1087 | int cursor_mb; |
@@ -1095,7 +1104,7 @@ static NOINLINE void input_tab(smallint *lastWasTab) | |||
1095 | #endif | 1104 | #endif |
1096 | tmp = matchBuf; | 1105 | tmp = matchBuf; |
1097 | 1106 | ||
1098 | find_type = build_match_prefix(matchBuf, &recalc_pos); | 1107 | find_type = build_match_prefix(matchBuf); |
1099 | 1108 | ||
1100 | /* Free up any memory already allocated */ | 1109 | /* Free up any memory already allocated */ |
1101 | free_tab_completion_data(); | 1110 | free_tab_completion_data(); |
@@ -1105,11 +1114,11 @@ static NOINLINE void input_tab(smallint *lastWasTab) | |||
1105 | * then try completing this word as a username. */ | 1114 | * then try completing this word as a username. */ |
1106 | if (state->flags & USERNAME_COMPLETION) | 1115 | if (state->flags & USERNAME_COMPLETION) |
1107 | if (matchBuf[0] == '~' && strchr(matchBuf, '/') == NULL) | 1116 | if (matchBuf[0] == '~' && strchr(matchBuf, '/') == NULL) |
1108 | complete_username(matchBuf); | 1117 | match_pfx_len = complete_username(matchBuf); |
1109 | #endif | 1118 | #endif |
1110 | /* Try to match a command in $PATH, or a directory, or a file */ | 1119 | /* Try to match a command in $PATH, or a directory, or a file */ |
1111 | if (!matches) | 1120 | if (!matches) |
1112 | complete_cmd_dir_file(matchBuf, find_type); | 1121 | match_pfx_len = complete_cmd_dir_file(matchBuf, find_type); |
1113 | /* Remove duplicates */ | 1122 | /* Remove duplicates */ |
1114 | if (matches) { | 1123 | if (matches) { |
1115 | unsigned i; | 1124 | unsigned i; |
@@ -1130,23 +1139,26 @@ static NOINLINE void input_tab(smallint *lastWasTab) | |||
1130 | } | 1139 | } |
1131 | /* Did we find exactly one match? */ | 1140 | /* Did we find exactly one match? */ |
1132 | if (num_matches != 1) { /* no */ | 1141 | if (num_matches != 1) { /* no */ |
1142 | char *tmp1; | ||
1133 | beep(); | 1143 | beep(); |
1134 | if (!matches) | 1144 | if (!matches) |
1135 | return; /* no matches at all */ | 1145 | return; /* no matches at all */ |
1136 | /* Find common prefix */ | 1146 | /* Find common prefix */ |
1137 | tmp1 = xstrdup(matches[0]); | 1147 | tmp1 = xstrdup(matches[0]); |
1138 | for (tmp = tmp1; *tmp; tmp++) { | 1148 | for (tmp = tmp1; *tmp; tmp++) { |
1139 | for (len_found = 1; len_found < num_matches; len_found++) { | 1149 | unsigned n; |
1140 | if (matches[len_found][tmp - tmp1] != *tmp) { | 1150 | for (n = 1; n < num_matches; n++) { |
1141 | *tmp = '\0'; | 1151 | if (matches[n][tmp - tmp1] != *tmp) { |
1142 | break; | 1152 | goto stop; |
1143 | } | 1153 | } |
1144 | } | 1154 | } |
1145 | } | 1155 | } |
1146 | if (*tmp1 == '\0') { /* have unique prefix? */ | 1156 | stop: |
1157 | if (tmp1 == tmp) { /* have unique prefix? */ | ||
1147 | free(tmp1); /* no */ | 1158 | free(tmp1); /* no */ |
1148 | return; | 1159 | return; |
1149 | } | 1160 | } |
1161 | *tmp = '\0'; | ||
1150 | tmp = add_quote_for_spec_chars(tmp1); | 1162 | tmp = add_quote_for_spec_chars(tmp1); |
1151 | free(tmp1); | 1163 | free(tmp1); |
1152 | len_found = strlen(tmp); | 1164 | len_found = strlen(tmp); |
@@ -1163,41 +1175,43 @@ static NOINLINE void input_tab(smallint *lastWasTab) | |||
1163 | } | 1175 | } |
1164 | 1176 | ||
1165 | #if !ENABLE_UNICODE_SUPPORT | 1177 | #if !ENABLE_UNICODE_SUPPORT |
1166 | /* have space to place the match? */ | 1178 | /* Have space to place the match? */ |
1167 | /* The result consists of three parts with these lengths: */ | 1179 | /* The result consists of three parts with these lengths: */ |
1168 | /* (cursor - recalc_pos) + len_found + (command_len - cursor) */ | 1180 | /* cursor + (len_found - match_pfx_len) + (command_len - cursor) */ |
1169 | /* it simplifies into: */ | 1181 | /* it simplifies into: */ |
1170 | if ((int)(len_found + command_len - recalc_pos) < S.maxsize) { | 1182 | if ((int)(len_found - match_pfx_len + command_len) < S.maxsize) { |
1183 | int pos; | ||
1171 | /* save tail */ | 1184 | /* save tail */ |
1172 | strcpy(matchBuf, command_ps + cursor); | 1185 | strcpy(matchBuf, &command_ps[cursor]); |
1173 | /* add match and tail */ | 1186 | /* add match and tail */ |
1174 | sprintf(&command_ps[cursor - recalc_pos], "%s%s", tmp, matchBuf); | 1187 | sprintf(&command_ps[cursor], "%s%s", tmp + match_pfx_len, matchBuf); |
1175 | command_len = strlen(command_ps); | 1188 | command_len = strlen(command_ps); |
1176 | /* new pos */ | 1189 | /* new pos */ |
1177 | recalc_pos = cursor - recalc_pos + len_found; | 1190 | pos = cursor + len_found - match_pfx_len; |
1178 | /* write out the matched command */ | 1191 | /* write out the matched command */ |
1179 | redraw(cmdedit_y, command_len - recalc_pos); | 1192 | redraw(cmdedit_y, command_len - pos); |
1180 | } | 1193 | } |
1181 | #else | 1194 | #else |
1182 | { | 1195 | { |
1183 | char command[MAX_LINELEN]; | 1196 | char command[MAX_LINELEN]; |
1184 | int len = save_string(command, sizeof(command)); | 1197 | int len = save_string(command, sizeof(command)); |
1185 | /* have space to place the match? */ | 1198 | /* Have space to place the match? */ |
1186 | /* (cursor_mb - recalc_pos) + len_found + (len - cursor_mb) */ | 1199 | /* cursor_mb + (len_found - match_pfx_len) + (len - cursor_mb) */ |
1187 | if ((int)(len_found + len - recalc_pos) < MAX_LINELEN) { | 1200 | if ((int)(len_found - match_pfx_len + len) < MAX_LINELEN) { |
1201 | int pos; | ||
1188 | /* save tail */ | 1202 | /* save tail */ |
1189 | strcpy(matchBuf, command + cursor_mb); | 1203 | strcpy(matchBuf, &command[cursor_mb]); |
1190 | /* where do we want to have cursor after all? */ | 1204 | /* where do we want to have cursor after all? */ |
1191 | strcpy(&command[cursor_mb - recalc_pos], tmp); | 1205 | strcpy(&command[cursor_mb], tmp + match_pfx_len); |
1192 | len = load_string(command, S.maxsize); | 1206 | len = load_string(command, S.maxsize); |
1193 | /* add match and tail */ | 1207 | /* add match and tail */ |
1194 | sprintf(&command[cursor_mb - recalc_pos], "%s%s", tmp, matchBuf); | 1208 | sprintf(&command[cursor_mb], "%s%s", tmp + match_pfx_len, matchBuf); |
1195 | command_len = load_string(command, S.maxsize); | 1209 | command_len = load_string(command, S.maxsize); |
1196 | /* write out the matched command */ | 1210 | /* write out the matched command */ |
1197 | /* paranoia: load_string can return 0 on conv error, | 1211 | /* paranoia: load_string can return 0 on conv error, |
1198 | * prevent passing len = (0 - 12) to redraw */ | 1212 | * prevent passing pos = (0 - 12) to redraw */ |
1199 | len = command_len - len; | 1213 | pos = command_len - len; |
1200 | redraw(cmdedit_y, len >= 0 ? len : 0); | 1214 | redraw(cmdedit_y, pos >= 0 ? pos : 0); |
1201 | } | 1215 | } |
1202 | } | 1216 | } |
1203 | #endif | 1217 | #endif |