diff options
author | Denys Vlasenko <dvlasenk@redhat.com> | 2010-09-03 14:09:24 +0200 |
---|---|---|
committer | Denys Vlasenko <dvlasenk@redhat.com> | 2010-09-03 14:09:24 +0200 |
commit | 76939e7b72937a5a2d00be3f62a6d2fa2757bdc9 (patch) | |
tree | 7e649ad10f9d3de3b084f6bdf47c77d19b27a354 /libbb | |
parent | ba0e103a662f640060041c5b56c2afdce09408b3 (diff) | |
download | busybox-w32-76939e7b72937a5a2d00be3f62a6d2fa2757bdc9.tar.gz busybox-w32-76939e7b72937a5a2d00be3f62a6d2fa2757bdc9.tar.bz2 busybox-w32-76939e7b72937a5a2d00be3f62a6d2fa2757bdc9.zip |
lineedit: allocate matchBuf only temporarily: saves MAX_LINELEN bytes
function old new delta
input_tab 1027 1041 +14
build_match_prefix 590 562 -28
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/1 up/down: 14/-28) Total: -14 bytes
Signed-off-by: Denys Vlasenko <dvlasenk@redhat.com>
Diffstat (limited to 'libbb')
-rw-r--r-- | libbb/lineedit.c | 93 |
1 files changed, 48 insertions, 45 deletions
diff --git a/libbb/lineedit.c b/libbb/lineedit.c index ff5d28408..a917c5f92 100644 --- a/libbb/lineedit.c +++ b/libbb/lineedit.c | |||
@@ -150,11 +150,6 @@ struct lineedit_statics { | |||
150 | #if ENABLE_FEATURE_EDITING_ASK_TERMINAL | 150 | #if ENABLE_FEATURE_EDITING_ASK_TERMINAL |
151 | smallint sent_ESC_br6n; | 151 | smallint sent_ESC_br6n; |
152 | #endif | 152 | #endif |
153 | |||
154 | /* Formerly these were big buffers on stack: */ | ||
155 | #if ENABLE_FEATURE_TAB_COMPLETION | ||
156 | char input_tab__matchBuf[MAX_LINELEN]; | ||
157 | #endif | ||
158 | }; | 153 | }; |
159 | 154 | ||
160 | /* See lineedit_ptr_hack.c */ | 155 | /* See lineedit_ptr_hack.c */ |
@@ -810,17 +805,17 @@ static NOINLINE unsigned complete_cmd_dir_file(const char *command, int type) | |||
810 | } | 805 | } |
811 | 806 | ||
812 | /* build_match_prefix: | 807 | /* build_match_prefix: |
813 | * On entry, matchBuf contains everything up to cursor at the moment <tab> | 808 | * On entry, match_buf contains everything up to cursor at the moment <tab> |
814 | * was pressed. This function looks at it, figures out what part of it | 809 | * was pressed. This function looks at it, figures out what part of it |
815 | * constitutes the command/file/directory prefix to use for completion, | 810 | * constitutes the command/file/directory prefix to use for completion, |
816 | * and rewrites matchBuf to contain only that part. | 811 | * and rewrites match_buf to contain only that part. |
817 | */ | 812 | */ |
813 | #define dbg_bmp 0 | ||
818 | /* Helpers: */ | 814 | /* Helpers: */ |
819 | /* QUOT is used on elements of int_buf[], which are bytes, | 815 | /* QUOT is used on elements of int_buf[], which are bytes, |
820 | * not Unicode chars. Therefore it works correctly even in Unicode mode. | 816 | * not Unicode chars. Therefore it works correctly even in Unicode mode. |
821 | */ | 817 | */ |
822 | #define QUOT (UCHAR_MAX+1) | 818 | #define QUOT (UCHAR_MAX+1) |
823 | #define dbg_bmp 0 | ||
824 | static void remove_chunk(int16_t *int_buf, int beg, int end) | 819 | static void remove_chunk(int16_t *int_buf, int beg, int end) |
825 | { | 820 | { |
826 | /* beg must be <= end */ | 821 | /* beg must be <= end */ |
@@ -837,25 +832,29 @@ static void remove_chunk(int16_t *int_buf, int beg, int end) | |||
837 | bb_putchar('\n'); | 832 | bb_putchar('\n'); |
838 | } | 833 | } |
839 | } | 834 | } |
840 | static NOINLINE int build_match_prefix(char *matchBuf) | 835 | /* Caller ensures that match_buf points to a malloced buffer |
836 | * big enough to hold strlen(match_buf)*2 + 2 | ||
837 | */ | ||
838 | static NOINLINE int build_match_prefix(char *match_buf) | ||
841 | { | 839 | { |
842 | int i, j; | 840 | int i, j; |
843 | int command_mode; | 841 | int command_mode; |
844 | int16_t *int_buf; | 842 | int16_t *int_buf = (int16_t*)match_buf; |
845 | 843 | ||
846 | if (dbg_bmp) printf("\n%s\n", matchBuf); | 844 | if (dbg_bmp) printf("\n%s\n", match_buf); |
847 | 845 | ||
848 | int_buf = xmalloc(sizeof(int_buf[0]) * (strlen(matchBuf) + 1)); | 846 | /* Copy in reverse order, since they overlap */ |
849 | i = 0; | 847 | i = strlen(match_buf); |
850 | while ((int_buf[i] = (unsigned char)matchBuf[i]) != '\0') | 848 | do { |
851 | i++; | 849 | int_buf[i] = (unsigned char)match_buf[i]; |
850 | i--; | ||
851 | } while (i >= 0); | ||
852 | 852 | ||
853 | /* Mark every \c as "quoted c" */ | 853 | /* Mark every \c as "quoted c" */ |
854 | for (i = j = 0; matchBuf[i]; i++, j++) { | 854 | for (i = 0; int_buf[i]; i++) { |
855 | if (matchBuf[i] == '\\') { | 855 | if (int_buf[i] == '\\') { |
856 | remove_chunk(int_buf, j, j + 1); | 856 | remove_chunk(int_buf, i, i + 1); |
857 | int_buf[j] |= QUOT; | 857 | int_buf[i] |= QUOT; |
858 | i++; | ||
859 | } | 858 | } |
860 | } | 859 | } |
861 | /* Quote-mark "chars" and 'chars', drop delimiters */ | 860 | /* Quote-mark "chars" and 'chars', drop delimiters */ |
@@ -964,13 +963,12 @@ static NOINLINE int build_match_prefix(char *matchBuf) | |||
964 | } | 963 | } |
965 | } | 964 | } |
966 | 965 | ||
967 | /* Store only match prefix */ | 966 | /* Convert back to string of _chars_ */ |
968 | i = 0; | 967 | i = 0; |
969 | while ((matchBuf[i] = int_buf[i]) != '\0') | 968 | while ((match_buf[i] = int_buf[i]) != '\0') |
970 | i++; | 969 | i++; |
971 | free(int_buf); | ||
972 | 970 | ||
973 | if (dbg_bmp) printf("final matchBuf:'%s'\n", matchBuf); | 971 | if (dbg_bmp) printf("final match_buf:'%s'\n", match_buf); |
974 | 972 | ||
975 | return command_mode; | 973 | return command_mode; |
976 | } | 974 | } |
@@ -1037,9 +1035,8 @@ static char *add_quote_for_spec_chars(char *found) | |||
1037 | static NOINLINE void input_tab(smallint *lastWasTab) | 1035 | static NOINLINE void input_tab(smallint *lastWasTab) |
1038 | { | 1036 | { |
1039 | char *chosen_match; | 1037 | char *chosen_match; |
1038 | char *match_buf; | ||
1040 | size_t len_found; | 1039 | size_t len_found; |
1041 | /* char matchBuf[MAX_LINELEN]; */ | ||
1042 | #define matchBuf (S.input_tab__matchBuf) | ||
1043 | /* Length of string used for matching */ | 1040 | /* Length of string used for matching */ |
1044 | unsigned match_pfx_len = match_pfx_len; | 1041 | unsigned match_pfx_len = match_pfx_len; |
1045 | int find_type; | 1042 | int find_type; |
@@ -1065,21 +1062,26 @@ static NOINLINE void input_tab(smallint *lastWasTab) | |||
1065 | } | 1062 | } |
1066 | 1063 | ||
1067 | *lastWasTab = 1; | 1064 | *lastWasTab = 1; |
1065 | chosen_match = NULL; | ||
1068 | 1066 | ||
1069 | /* Make a local copy of the string -- | 1067 | /* Make a local copy of the string up to the position of the cursor. |
1070 | * up to the position of the cursor */ | 1068 | * build_match_prefix will expand it into int16_t's, need to allocate |
1069 | * twice as much as the string_len+1. | ||
1070 | * (we then also (ab)use this extra space later - see (**)) | ||
1071 | */ | ||
1072 | match_buf = xmalloc(MAX_LINELEN * sizeof(int16_t)); | ||
1071 | #if !ENABLE_UNICODE_SUPPORT | 1073 | #if !ENABLE_UNICODE_SUPPORT |
1072 | save_string(matchBuf, cursor + 1); | 1074 | save_string(match_buf, cursor + 1); /* +1 for NUL */ |
1073 | #else | 1075 | #else |
1074 | { | 1076 | { |
1075 | CHAR_T wc = command_ps[cursor]; | 1077 | CHAR_T wc = command_ps[cursor]; |
1076 | command_ps[cursor] = BB_NUL; | 1078 | command_ps[cursor] = BB_NUL; |
1077 | save_string(matchBuf, MAX_LINELEN); | 1079 | save_string(match_buf, MAX_LINELEN); |
1078 | command_ps[cursor] = wc; | 1080 | command_ps[cursor] = wc; |
1079 | cursor_mb = strlen(matchBuf); | 1081 | cursor_mb = strlen(match_buf); |
1080 | } | 1082 | } |
1081 | #endif | 1083 | #endif |
1082 | find_type = build_match_prefix(matchBuf); | 1084 | find_type = build_match_prefix(match_buf); |
1083 | 1085 | ||
1084 | /* Free up any memory already allocated */ | 1086 | /* Free up any memory already allocated */ |
1085 | free_tab_completion_data(); | 1087 | free_tab_completion_data(); |
@@ -1088,12 +1090,12 @@ static NOINLINE void input_tab(smallint *lastWasTab) | |||
1088 | /* If the word starts with `~' and there is no slash in the word, | 1090 | /* If the word starts with `~' and there is no slash in the word, |
1089 | * then try completing this word as a username. */ | 1091 | * then try completing this word as a username. */ |
1090 | if (state->flags & USERNAME_COMPLETION) | 1092 | if (state->flags & USERNAME_COMPLETION) |
1091 | if (matchBuf[0] == '~' && strchr(matchBuf, '/') == NULL) | 1093 | if (match_buf[0] == '~' && strchr(match_buf, '/') == NULL) |
1092 | match_pfx_len = complete_username(matchBuf); | 1094 | match_pfx_len = complete_username(match_buf); |
1093 | #endif | 1095 | #endif |
1094 | /* Try to match a command in $PATH, or a directory, or a file */ | 1096 | /* Try to match a command in $PATH, or a directory, or a file */ |
1095 | if (!matches) | 1097 | if (!matches) |
1096 | match_pfx_len = complete_cmd_dir_file(matchBuf, find_type); | 1098 | match_pfx_len = complete_cmd_dir_file(match_buf, find_type); |
1097 | /* Remove duplicates */ | 1099 | /* Remove duplicates */ |
1098 | if (matches) { | 1100 | if (matches) { |
1099 | unsigned i; | 1101 | unsigned i; |
@@ -1117,7 +1119,7 @@ static NOINLINE void input_tab(smallint *lastWasTab) | |||
1117 | char *cp; | 1119 | char *cp; |
1118 | beep(); | 1120 | beep(); |
1119 | if (!matches) | 1121 | if (!matches) |
1120 | return; /* no matches at all */ | 1122 | goto ret; /* no matches at all */ |
1121 | /* Find common prefix */ | 1123 | /* Find common prefix */ |
1122 | chosen_match = xstrdup(matches[0]); | 1124 | chosen_match = xstrdup(matches[0]); |
1123 | for (cp = chosen_match; *cp; cp++) { | 1125 | for (cp = chosen_match; *cp; cp++) { |
@@ -1130,8 +1132,7 @@ static NOINLINE void input_tab(smallint *lastWasTab) | |||
1130 | } | 1132 | } |
1131 | stop: | 1133 | stop: |
1132 | if (cp == chosen_match) { /* have unique prefix? */ | 1134 | if (cp == chosen_match) { /* have unique prefix? */ |
1133 | free(chosen_match); /* no */ | 1135 | goto ret; /* no */ |
1134 | return; | ||
1135 | } | 1136 | } |
1136 | *cp = '\0'; | 1137 | *cp = '\0'; |
1137 | cp = add_quote_for_spec_chars(chosen_match); | 1138 | cp = add_quote_for_spec_chars(chosen_match); |
@@ -1158,9 +1159,9 @@ static NOINLINE void input_tab(smallint *lastWasTab) | |||
1158 | if ((int)(len_found - match_pfx_len + command_len) < S.maxsize) { | 1159 | if ((int)(len_found - match_pfx_len + command_len) < S.maxsize) { |
1159 | int pos; | 1160 | int pos; |
1160 | /* save tail */ | 1161 | /* save tail */ |
1161 | strcpy(matchBuf, &command_ps[cursor]); | 1162 | strcpy(match_buf, &command_ps[cursor]); |
1162 | /* add match and tail */ | 1163 | /* add match and tail */ |
1163 | sprintf(&command_ps[cursor], "%s%s", chosen_match + match_pfx_len, matchBuf); | 1164 | sprintf(&command_ps[cursor], "%s%s", chosen_match + match_pfx_len, match_buf); |
1164 | command_len = strlen(command_ps); | 1165 | command_len = strlen(command_ps); |
1165 | /* new pos */ | 1166 | /* new pos */ |
1166 | pos = cursor + len_found - match_pfx_len; | 1167 | pos = cursor + len_found - match_pfx_len; |
@@ -1169,19 +1170,20 @@ static NOINLINE void input_tab(smallint *lastWasTab) | |||
1169 | } | 1170 | } |
1170 | #else | 1171 | #else |
1171 | { | 1172 | { |
1172 | char command[MAX_LINELEN]; | 1173 | /* Use 2nd half of match_buf as scratch space - see (**) */ |
1173 | int len = save_string(command, sizeof(command)); | 1174 | char *command = match_buf + MAX_LINELEN; |
1175 | int len = save_string(command, MAX_LINELEN); | ||
1174 | /* Have space to place the match? */ | 1176 | /* Have space to place the match? */ |
1175 | /* cursor_mb + (len_found - match_pfx_len) + (len - cursor_mb) */ | 1177 | /* cursor_mb + (len_found - match_pfx_len) + (len - cursor_mb) */ |
1176 | if ((int)(len_found - match_pfx_len + len) < MAX_LINELEN) { | 1178 | if ((int)(len_found - match_pfx_len + len) < MAX_LINELEN) { |
1177 | int pos; | 1179 | int pos; |
1178 | /* save tail */ | 1180 | /* save tail */ |
1179 | strcpy(matchBuf, &command[cursor_mb]); | 1181 | strcpy(match_buf, &command[cursor_mb]); |
1180 | /* where do we want to have cursor after all? */ | 1182 | /* where do we want to have cursor after all? */ |
1181 | strcpy(&command[cursor_mb], chosen_match + match_pfx_len); | 1183 | strcpy(&command[cursor_mb], chosen_match + match_pfx_len); |
1182 | len = load_string(command, S.maxsize); | 1184 | len = load_string(command, S.maxsize); |
1183 | /* add match and tail */ | 1185 | /* add match and tail */ |
1184 | sprintf(&command[cursor_mb], "%s%s", chosen_match + match_pfx_len, matchBuf); | 1186 | sprintf(&command[cursor_mb], "%s%s", chosen_match + match_pfx_len, match_buf); |
1185 | command_len = load_string(command, S.maxsize); | 1187 | command_len = load_string(command, S.maxsize); |
1186 | /* write out the matched command */ | 1188 | /* write out the matched command */ |
1187 | /* paranoia: load_string can return 0 on conv error, | 1189 | /* paranoia: load_string can return 0 on conv error, |
@@ -1191,8 +1193,9 @@ static NOINLINE void input_tab(smallint *lastWasTab) | |||
1191 | } | 1193 | } |
1192 | } | 1194 | } |
1193 | #endif | 1195 | #endif |
1196 | ret: | ||
1194 | free(chosen_match); | 1197 | free(chosen_match); |
1195 | #undef matchBuf | 1198 | free(match_buf); |
1196 | } | 1199 | } |
1197 | 1200 | ||
1198 | #endif /* FEATURE_TAB_COMPLETION */ | 1201 | #endif /* FEATURE_TAB_COMPLETION */ |