diff options
author | Ron Yorston <rmy@pobox.com> | 2016-11-29 11:26:45 +0000 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2016-11-29 11:26:45 +0000 |
commit | bb8d79eadbba1942dbdb9f9cee5c47833afe269f (patch) | |
tree | b8c517e9ca895d60d7227aef7177b6291df5e2cd /libbb | |
parent | 9fa1e4990e655a85025c9d270a1606983e375e47 (diff) | |
parent | 7d877fc9312a742b06125927bb1d34bd35398c6c (diff) | |
download | busybox-w32-bb8d79eadbba1942dbdb9f9cee5c47833afe269f.tar.gz busybox-w32-bb8d79eadbba1942dbdb9f9cee5c47833afe269f.tar.bz2 busybox-w32-bb8d79eadbba1942dbdb9f9cee5c47833afe269f.zip |
Merge branch 'busybox' into merge
Diffstat (limited to 'libbb')
-rw-r--r-- | libbb/Config.src | 162 | ||||
-rw-r--r-- | libbb/appletlib.c | 26 | ||||
-rw-r--r-- | libbb/lineedit.c | 112 | ||||
-rw-r--r-- | libbb/read_key.c | 12 |
4 files changed, 259 insertions, 53 deletions
diff --git a/libbb/Config.src b/libbb/Config.src index 6ba256290..00804e31e 100644 --- a/libbb/Config.src +++ b/libbb/Config.src | |||
@@ -7,6 +7,30 @@ menu "Busybox Library Tuning" | |||
7 | 7 | ||
8 | INSERT | 8 | INSERT |
9 | 9 | ||
10 | choice | ||
11 | prompt "Buffer allocation policy" | ||
12 | default FEATURE_BUFFERS_USE_MALLOC | ||
13 | help | ||
14 | There are 3 ways BusyBox can handle buffer allocations: | ||
15 | - Use malloc. This costs code size for the call to xmalloc. | ||
16 | - Put them on stack. For some very small machines with limited stack | ||
17 | space, this can be deadly. For most folks, this works just fine. | ||
18 | - Put them in BSS. This works beautifully for computers with a real | ||
19 | MMU (and OS support), but wastes runtime RAM for uCLinux. This | ||
20 | behavior was the only one available for BusyBox versions 0.48 and | ||
21 | earlier. | ||
22 | |||
23 | config FEATURE_BUFFERS_USE_MALLOC | ||
24 | bool "Allocate with Malloc" | ||
25 | |||
26 | config FEATURE_BUFFERS_GO_ON_STACK | ||
27 | bool "Allocate on the Stack" | ||
28 | |||
29 | config FEATURE_BUFFERS_GO_IN_BSS | ||
30 | bool "Allocate in the .bss section" | ||
31 | |||
32 | endchoice | ||
33 | |||
10 | config PASSWORD_MINLEN | 34 | config PASSWORD_MINLEN |
11 | int "Minimum password length" | 35 | int "Minimum password length" |
12 | default 6 | 36 | default 6 |
@@ -153,6 +177,131 @@ config FEATURE_EDITING_ASK_TERMINAL | |||
153 | correctly, or want to save on code size (about 400 bytes), | 177 | correctly, or want to save on code size (about 400 bytes), |
154 | then do not turn this option on. | 178 | then do not turn this option on. |
155 | 179 | ||
180 | config LOCALE_SUPPORT | ||
181 | bool "Enable locale support (system needs locale for this to work)" | ||
182 | default n | ||
183 | help | ||
184 | Enable this if your system has locale support and you would like | ||
185 | busybox to support locale settings. | ||
186 | |||
187 | config UNICODE_SUPPORT | ||
188 | bool "Support Unicode" | ||
189 | default y | ||
190 | help | ||
191 | This makes various applets aware that one byte is not | ||
192 | one character on screen. | ||
193 | |||
194 | Busybox aims to eventually work correctly with Unicode displays. | ||
195 | Any older encodings are not guaranteed to work. | ||
196 | Probably by the time when busybox will be fully Unicode-clean, | ||
197 | other encodings will be mainly of historic interest. | ||
198 | |||
199 | config UNICODE_USING_LOCALE | ||
200 | bool "Use libc routines for Unicode (else uses internal ones)" | ||
201 | default n | ||
202 | depends on UNICODE_SUPPORT && LOCALE_SUPPORT | ||
203 | help | ||
204 | With this option on, Unicode support is implemented using libc | ||
205 | routines. Otherwise, internal implementation is used. | ||
206 | Internal implementation is smaller. | ||
207 | |||
208 | config FEATURE_CHECK_UNICODE_IN_ENV | ||
209 | bool "Check $LC_ALL, $LC_CTYPE and $LANG environment variables" | ||
210 | default n | ||
211 | depends on UNICODE_SUPPORT && !UNICODE_USING_LOCALE | ||
212 | help | ||
213 | With this option on, Unicode support is activated | ||
214 | only if locale-related variables have the value of the form | ||
215 | "xxxx.utf8" | ||
216 | |||
217 | Otherwise, Unicode support will be always enabled and active. | ||
218 | |||
219 | config SUBST_WCHAR | ||
220 | int "Character code to substitute unprintable characters with" | ||
221 | depends on UNICODE_SUPPORT | ||
222 | default 63 | ||
223 | help | ||
224 | Typical values are 63 for '?' (works with any output device), | ||
225 | 30 for ASCII substitute control code, | ||
226 | 65533 (0xfffd) for Unicode replacement character. | ||
227 | |||
228 | config LAST_SUPPORTED_WCHAR | ||
229 | int "Range of supported Unicode characters" | ||
230 | depends on UNICODE_SUPPORT | ||
231 | default 767 | ||
232 | help | ||
233 | Any character with Unicode value bigger than this is assumed | ||
234 | to be non-printable on output device. Many applets replace | ||
235 | such characters with substitution character. | ||
236 | |||
237 | The idea is that many valid printable Unicode chars | ||
238 | nevertheless are not displayed correctly. Think about | ||
239 | combining charachers, double-wide hieroglyphs, obscure | ||
240 | characters in dozens of ancient scripts... | ||
241 | Many terminals, terminal emulators, xterms etc will fail | ||
242 | to handle them correctly. Choose the smallest value | ||
243 | which suits your needs. | ||
244 | |||
245 | Typical values are: | ||
246 | 126 - ASCII only | ||
247 | 767 (0x2ff) - there are no combining chars in [0..767] range | ||
248 | (the range includes Latin 1, Latin Ext. A and B), | ||
249 | code is ~700 bytes smaller for this case. | ||
250 | 4351 (0x10ff) - there are no double-wide chars in [0..4351] range, | ||
251 | code is ~300 bytes smaller for this case. | ||
252 | 12799 (0x31ff) - nearly all non-ideographic characters are | ||
253 | available in [0..12799] range, including | ||
254 | East Asian scripts like katakana, hiragana, hangul, | ||
255 | bopomofo... | ||
256 | 0 - off, any valid printable Unicode character will be printed. | ||
257 | |||
258 | config UNICODE_COMBINING_WCHARS | ||
259 | bool "Allow zero-width Unicode characters on output" | ||
260 | default n | ||
261 | depends on UNICODE_SUPPORT | ||
262 | help | ||
263 | With this option off, any Unicode char with width of 0 | ||
264 | is substituted on output. | ||
265 | |||
266 | config UNICODE_WIDE_WCHARS | ||
267 | bool "Allow wide Unicode characters on output" | ||
268 | default n | ||
269 | depends on UNICODE_SUPPORT | ||
270 | help | ||
271 | With this option off, any Unicode char with width > 1 | ||
272 | is substituted on output. | ||
273 | |||
274 | config UNICODE_BIDI_SUPPORT | ||
275 | bool "Bidirectional character-aware line input" | ||
276 | default n | ||
277 | depends on UNICODE_SUPPORT && !UNICODE_USING_LOCALE | ||
278 | help | ||
279 | With this option on, right-to-left Unicode characters | ||
280 | are treated differently on input (e.g. cursor movement). | ||
281 | |||
282 | config UNICODE_NEUTRAL_TABLE | ||
283 | bool "In bidi input, support non-ASCII neutral chars too" | ||
284 | default n | ||
285 | depends on UNICODE_BIDI_SUPPORT | ||
286 | help | ||
287 | In most cases it's enough to treat only ASCII non-letters | ||
288 | (i.e. punctuation, numbers and space) as characters | ||
289 | with neutral directionality. | ||
290 | With this option on, more extensive (and bigger) table | ||
291 | of neutral chars will be used. | ||
292 | |||
293 | config UNICODE_PRESERVE_BROKEN | ||
294 | bool "Make it possible to enter sequences of chars which are not Unicode" | ||
295 | default n | ||
296 | depends on UNICODE_SUPPORT | ||
297 | help | ||
298 | With this option on, on line-editing input (such as used by shells) | ||
299 | invalid UTF-8 bytes are not substituted with the selected | ||
300 | substitution character. | ||
301 | For example, this means that entering 'l', 's', ' ', 0xff, [Enter] | ||
302 | at shell prompt will list file named 0xff (single char name | ||
303 | with char value 255), not file named '?'. | ||
304 | |||
156 | config FEATURE_NON_POSIX_CP | 305 | config FEATURE_NON_POSIX_CP |
157 | bool "Non-POSIX, but safer, copying to special nodes" | 306 | bool "Non-POSIX, but safer, copying to special nodes" |
158 | default y | 307 | default y |
@@ -177,6 +326,19 @@ config FEATURE_VERBOSE_CP_MESSAGE | |||
177 | cp: cannot stat '/vmlinuz/file': Not a directory | 326 | cp: cannot stat '/vmlinuz/file': Not a directory |
178 | This will cost you ~60 bytes. | 327 | This will cost you ~60 bytes. |
179 | 328 | ||
329 | config FEATURE_USE_SENDFILE | ||
330 | bool "Use sendfile system call" | ||
331 | default y | ||
332 | select PLATFORM_LINUX | ||
333 | help | ||
334 | When enabled, busybox will use the kernel sendfile() function | ||
335 | instead of read/write loops to copy data between file descriptors | ||
336 | (for example, cp command does this a lot). | ||
337 | If sendfile() doesn't work, copying code falls back to read/write | ||
338 | loop. sendfile() was originally implemented for faster I/O | ||
339 | from files to sockets, but since Linux 2.6.33 it was extended | ||
340 | to work for many more file types. | ||
341 | |||
180 | config FEATURE_COPYBUF_KB | 342 | config FEATURE_COPYBUF_KB |
181 | int "Copy buffer size, in kilobytes" | 343 | int "Copy buffer size, in kilobytes" |
182 | range 1 1024 | 344 | range 1 1024 |
diff --git a/libbb/appletlib.c b/libbb/appletlib.c index 4aa40454f..1fe0eb44f 100644 --- a/libbb/appletlib.c +++ b/libbb/appletlib.c | |||
@@ -821,7 +821,7 @@ static int busybox_main(char **argv) | |||
821 | col += len2; | 821 | col += len2; |
822 | a += len2 - 1; | 822 | a += len2 - 1; |
823 | } | 823 | } |
824 | full_write2_str("\n\n"); | 824 | full_write2_str("\n"); |
825 | return 0; | 825 | return 0; |
826 | } | 826 | } |
827 | 827 | ||
@@ -936,20 +936,21 @@ void FAST_FUNC run_applet_no_and_exit(int applet_no, char **argv) | |||
936 | } | 936 | } |
937 | # endif /* NUM_APPLETS > 0 */ | 937 | # endif /* NUM_APPLETS > 0 */ |
938 | 938 | ||
939 | # if ENABLE_BUSYBOX || NUM_APPLETS > 0 | ||
939 | static NORETURN void run_applet_and_exit(const char *name, char **argv) | 940 | static NORETURN void run_applet_and_exit(const char *name, char **argv) |
940 | { | 941 | { |
941 | # if ENABLE_BUSYBOX | 942 | # if ENABLE_BUSYBOX |
942 | if (is_prefixed_with(name, "busybox")) | 943 | if (is_prefixed_with(name, "busybox")) |
943 | exit(busybox_main(argv)); | 944 | exit(busybox_main(argv)); |
944 | # endif | 945 | # endif |
945 | # if NUM_APPLETS > 0 | 946 | # if NUM_APPLETS > 0 |
946 | /* find_applet_by_name() search is more expensive, so goes second */ | 947 | /* find_applet_by_name() search is more expensive, so goes second */ |
947 | { | 948 | { |
948 | int applet = find_applet_by_name(name); | 949 | int applet = find_applet_by_name(name); |
949 | if (applet >= 0) | 950 | if (applet >= 0) |
950 | run_applet_no_and_exit(applet, argv); | 951 | run_applet_no_and_exit(applet, argv); |
951 | } | 952 | } |
952 | # endif | 953 | # endif |
953 | 954 | ||
954 | /*bb_error_msg_and_die("applet not found"); - links in printf */ | 955 | /*bb_error_msg_and_die("applet not found"); - links in printf */ |
955 | full_write2_str(applet_name); | 956 | full_write2_str(applet_name); |
@@ -957,11 +958,11 @@ static NORETURN void run_applet_and_exit(const char *name, char **argv) | |||
957 | /* POSIX: "If a command is not found, the exit status shall be 127" */ | 958 | /* POSIX: "If a command is not found, the exit status shall be 127" */ |
958 | exit(127); | 959 | exit(127); |
959 | } | 960 | } |
961 | # endif | ||
960 | 962 | ||
961 | #endif /* !defined(SINGLE_APPLET_MAIN) */ | 963 | #endif /* !defined(SINGLE_APPLET_MAIN) */ |
962 | 964 | ||
963 | 965 | ||
964 | |||
965 | #if ENABLE_BUILD_LIBBUSYBOX | 966 | #if ENABLE_BUILD_LIBBUSYBOX |
966 | int lbb_main(char **argv) | 967 | int lbb_main(char **argv) |
967 | #else | 968 | #else |
@@ -1025,6 +1026,7 @@ int main(int argc UNUSED_PARAM, char **argv) | |||
1025 | #endif | 1026 | #endif |
1026 | 1027 | ||
1027 | #if defined(SINGLE_APPLET_MAIN) | 1028 | #if defined(SINGLE_APPLET_MAIN) |
1029 | |||
1028 | /* Only one applet is selected in .config */ | 1030 | /* Only one applet is selected in .config */ |
1029 | if (argv[1] && is_prefixed_with(argv[0], "busybox")) { | 1031 | if (argv[1] && is_prefixed_with(argv[0], "busybox")) { |
1030 | /* "busybox <applet> <params>" should still work as expected */ | 1032 | /* "busybox <applet> <params>" should still work as expected */ |
@@ -1033,9 +1035,16 @@ int main(int argc UNUSED_PARAM, char **argv) | |||
1033 | /* applet_names in this case is just "applet\0\0" */ | 1035 | /* applet_names in this case is just "applet\0\0" */ |
1034 | lbb_prepare(applet_names IF_FEATURE_INDIVIDUAL(, argv)); | 1036 | lbb_prepare(applet_names IF_FEATURE_INDIVIDUAL(, argv)); |
1035 | return SINGLE_APPLET_MAIN(argc, argv); | 1037 | return SINGLE_APPLET_MAIN(argc, argv); |
1038 | |||
1039 | #elif !ENABLE_BUSYBOX && NUM_APPLETS == 0 | ||
1040 | |||
1041 | full_write2_str(bb_basename(argv[0])); | ||
1042 | full_write2_str(": no applets enabled\n"); | ||
1043 | exit(127); | ||
1044 | |||
1036 | #else | 1045 | #else |
1037 | lbb_prepare("busybox" IF_FEATURE_INDIVIDUAL(, argv)); | ||
1038 | 1046 | ||
1047 | lbb_prepare("busybox" IF_FEATURE_INDIVIDUAL(, argv)); | ||
1039 | # if !ENABLE_BUSYBOX | 1048 | # if !ENABLE_BUSYBOX |
1040 | if (argv[1] && is_prefixed_with(bb_basename(argv[0]), "busybox")) | 1049 | if (argv[1] && is_prefixed_with(bb_basename(argv[0]), "busybox")) |
1041 | argv++; | 1050 | argv++; |
@@ -1067,9 +1076,8 @@ int main(int argc UNUSED_PARAM, char **argv) | |||
1067 | } | 1076 | } |
1068 | } | 1077 | } |
1069 | applet_name = bb_basename(applet_name); | 1078 | applet_name = bb_basename(applet_name); |
1070 | |||
1071 | parse_config_file(); /* ...maybe, if FEATURE_SUID_CONFIG */ | 1079 | parse_config_file(); /* ...maybe, if FEATURE_SUID_CONFIG */ |
1072 | |||
1073 | run_applet_and_exit(applet_name, argv); | 1080 | run_applet_and_exit(applet_name, argv); |
1081 | |||
1074 | #endif | 1082 | #endif |
1075 | } | 1083 | } |
diff --git a/libbb/lineedit.c b/libbb/lineedit.c index 06f708b62..5d9080131 100644 --- a/libbb/lineedit.c +++ b/libbb/lineedit.c | |||
@@ -13,7 +13,6 @@ | |||
13 | * | 13 | * |
14 | * This code is 'as is' with no warranty. | 14 | * This code is 'as is' with no warranty. |
15 | */ | 15 | */ |
16 | |||
17 | /* | 16 | /* |
18 | * Usage and known bugs: | 17 | * Usage and known bugs: |
19 | * Terminal key codes are not extensive, more needs to be added. | 18 | * Terminal key codes are not extensive, more needs to be added. |
@@ -23,9 +22,6 @@ | |||
23 | * Ctrl-E also works as End. | 22 | * Ctrl-E also works as End. |
24 | * | 23 | * |
25 | * The following readline-like commands are not implemented: | 24 | * The following readline-like commands are not implemented: |
26 | * ESC-b -- Move back one word | ||
27 | * ESC-f -- Move forward one word | ||
28 | * ESC-d -- Delete forward one word | ||
29 | * CTL-t -- Transpose two characters | 25 | * CTL-t -- Transpose two characters |
30 | * | 26 | * |
31 | * lineedit does not know that the terminal escape sequences do not | 27 | * lineedit does not know that the terminal escape sequences do not |
@@ -133,8 +129,7 @@ static const char null_str[] ALIGN1 = ""; | |||
133 | struct lineedit_statics { | 129 | struct lineedit_statics { |
134 | line_input_t *state; | 130 | line_input_t *state; |
135 | 131 | ||
136 | volatile unsigned cmdedit_termw; /* = 80; */ /* actual terminal width */ | 132 | unsigned cmdedit_termw; /* = 80; */ /* actual terminal width */ |
137 | sighandler_t previous_SIGWINCH_handler; | ||
138 | 133 | ||
139 | unsigned cmdedit_x; /* real x (col) terminal position */ | 134 | unsigned cmdedit_x; /* real x (col) terminal position */ |
140 | unsigned cmdedit_y; /* pseudoreal y (row) terminal position */ | 135 | unsigned cmdedit_y; /* pseudoreal y (row) terminal position */ |
@@ -159,15 +154,22 @@ struct lineedit_statics { | |||
159 | unsigned num_matches; | 154 | unsigned num_matches; |
160 | #endif | 155 | #endif |
161 | 156 | ||
157 | unsigned SIGWINCH_saved; | ||
158 | volatile unsigned SIGWINCH_count; | ||
159 | volatile smallint ok_to_redraw; | ||
160 | |||
162 | #if ENABLE_FEATURE_EDITING_VI | 161 | #if ENABLE_FEATURE_EDITING_VI |
163 | # define DELBUFSIZ 128 | 162 | # define DELBUFSIZ 128 |
164 | CHAR_T *delptr; | ||
165 | smallint newdelflag; /* whether delbuf should be reused yet */ | 163 | smallint newdelflag; /* whether delbuf should be reused yet */ |
164 | CHAR_T *delptr; | ||
166 | CHAR_T delbuf[DELBUFSIZ]; /* a place to store deleted characters */ | 165 | CHAR_T delbuf[DELBUFSIZ]; /* a place to store deleted characters */ |
167 | #endif | 166 | #endif |
168 | #if ENABLE_FEATURE_EDITING_ASK_TERMINAL | 167 | #if ENABLE_FEATURE_EDITING_ASK_TERMINAL |
169 | smallint sent_ESC_br6n; | 168 | smallint sent_ESC_br6n; |
170 | #endif | 169 | #endif |
170 | |||
171 | /* Largish struct, keeping it last results in smaller code */ | ||
172 | struct sigaction SIGWINCH_handler; | ||
171 | }; | 173 | }; |
172 | 174 | ||
173 | /* See lineedit_ptr_hack.c */ | 175 | /* See lineedit_ptr_hack.c */ |
@@ -176,7 +178,6 @@ extern struct lineedit_statics *const lineedit_ptr_to_statics; | |||
176 | #define S (*lineedit_ptr_to_statics) | 178 | #define S (*lineedit_ptr_to_statics) |
177 | #define state (S.state ) | 179 | #define state (S.state ) |
178 | #define cmdedit_termw (S.cmdedit_termw ) | 180 | #define cmdedit_termw (S.cmdedit_termw ) |
179 | #define previous_SIGWINCH_handler (S.previous_SIGWINCH_handler) | ||
180 | #define cmdedit_x (S.cmdedit_x ) | 181 | #define cmdedit_x (S.cmdedit_x ) |
181 | #define cmdedit_y (S.cmdedit_y ) | 182 | #define cmdedit_y (S.cmdedit_y ) |
182 | #define cmdedit_prmt_len (S.cmdedit_prmt_len) | 183 | #define cmdedit_prmt_len (S.cmdedit_prmt_len) |
@@ -474,14 +475,10 @@ static void beep(void) | |||
474 | 475 | ||
475 | static void put_prompt(void) | 476 | static void put_prompt(void) |
476 | { | 477 | { |
477 | unsigned w; | ||
478 | |||
479 | fputs(cmdedit_prompt, stdout); | 478 | fputs(cmdedit_prompt, stdout); |
480 | fflush_all(); | ||
481 | cursor = 0; | 479 | cursor = 0; |
482 | w = cmdedit_termw; /* read volatile var once */ | 480 | cmdedit_y = cmdedit_prmt_len / cmdedit_termw; /* new quasireal y */ |
483 | cmdedit_y = cmdedit_prmt_len / w; /* new quasireal y */ | 481 | cmdedit_x = cmdedit_prmt_len % cmdedit_termw; |
484 | cmdedit_x = cmdedit_prmt_len % w; | ||
485 | } | 482 | } |
486 | 483 | ||
487 | /* Move back one character */ | 484 | /* Move back one character */ |
@@ -555,13 +552,11 @@ static void input_backward(unsigned num) | |||
555 | put_cur_glyph_and_inc_cursor(); | 552 | put_cur_glyph_and_inc_cursor(); |
556 | } else { | 553 | } else { |
557 | int lines_up; | 554 | int lines_up; |
558 | unsigned width; | ||
559 | /* num = chars to go back from the beginning of current line: */ | 555 | /* num = chars to go back from the beginning of current line: */ |
560 | num -= cmdedit_x; | 556 | num -= cmdedit_x; |
561 | width = cmdedit_termw; /* read volatile var once */ | ||
562 | /* num=1...w: one line up, w+1...2w: two, etc: */ | 557 | /* num=1...w: one line up, w+1...2w: two, etc: */ |
563 | lines_up = 1 + (num - 1) / width; | 558 | lines_up = 1 + (num - 1) / cmdedit_termw; |
564 | cmdedit_x = (width * cmdedit_y - num) % width; | 559 | cmdedit_x = (cmdedit_termw * cmdedit_y - num) % cmdedit_termw; |
565 | cmdedit_y -= lines_up; | 560 | cmdedit_y -= lines_up; |
566 | /* go to 1st column; go up */ | 561 | /* go to 1st column; go up */ |
567 | printf("\r" ESC"[%uA", lines_up); | 562 | printf("\r" ESC"[%uA", lines_up); |
@@ -2052,28 +2047,29 @@ static void parse_and_put_prompt(const char *prmt_ptr) | |||
2052 | } | 2047 | } |
2053 | #endif | 2048 | #endif |
2054 | 2049 | ||
2055 | static void cmdedit_setwidth(unsigned w, int redraw_flg) | 2050 | static void cmdedit_setwidth(void) |
2056 | { | 2051 | { |
2057 | cmdedit_termw = w; | 2052 | int new_y; |
2058 | if (redraw_flg) { | 2053 | |
2059 | /* new y for current cursor */ | 2054 | cmdedit_termw = get_terminal_width(STDIN_FILENO); |
2060 | int new_y = (cursor + cmdedit_prmt_len) / w; | 2055 | /* new y for current cursor */ |
2061 | /* redraw */ | 2056 | new_y = (cursor + cmdedit_prmt_len) / cmdedit_termw; |
2062 | redraw((new_y >= cmdedit_y ? new_y : cmdedit_y), command_len - cursor); | 2057 | /* redraw */ |
2063 | fflush_all(); | 2058 | redraw((new_y >= cmdedit_y ? new_y : cmdedit_y), command_len - cursor); |
2064 | } | ||
2065 | } | 2059 | } |
2066 | 2060 | ||
2067 | static void win_changed(int nsig) | 2061 | static void win_changed(int nsig UNUSED_PARAM) |
2068 | { | 2062 | { |
2069 | int sv_errno = errno; | 2063 | if (S.ok_to_redraw) { |
2070 | unsigned width; | 2064 | /* We are in read_key(), safe to redraw immediately */ |
2071 | 2065 | int sv_errno = errno; | |
2072 | get_terminal_width_height(0, &width, NULL); | 2066 | cmdedit_setwidth(); |
2073 | //FIXME: cmdedit_setwidth() -> redraw() -> printf() -> KABOOM! (we are in signal handler!) | 2067 | fflush_all(); |
2074 | cmdedit_setwidth(width, /*redraw_flg:*/ nsig); | 2068 | errno = sv_errno; |
2075 | 2069 | } else { | |
2076 | errno = sv_errno; | 2070 | /* Signal main loop that redraw is necessary */ |
2071 | S.SIGWINCH_count++; | ||
2072 | } | ||
2077 | } | 2073 | } |
2078 | 2074 | ||
2079 | static int lineedit_read_key(char *read_key_buffer, int timeout) | 2075 | static int lineedit_read_key(char *read_key_buffer, int timeout) |
@@ -2084,6 +2080,7 @@ static int lineedit_read_key(char *read_key_buffer, int timeout) | |||
2084 | int unicode_idx = 0; | 2080 | int unicode_idx = 0; |
2085 | #endif | 2081 | #endif |
2086 | 2082 | ||
2083 | fflush_all(); | ||
2087 | while (1) { | 2084 | while (1) { |
2088 | /* Wait for input. TIMEOUT = -1 makes read_key wait even | 2085 | /* Wait for input. TIMEOUT = -1 makes read_key wait even |
2089 | * on nonblocking stdin, TIMEOUT = 50 makes sure we won't | 2086 | * on nonblocking stdin, TIMEOUT = 50 makes sure we won't |
@@ -2092,7 +2089,9 @@ static int lineedit_read_key(char *read_key_buffer, int timeout) | |||
2092 | * | 2089 | * |
2093 | * Note: read_key sets errno to 0 on success. | 2090 | * Note: read_key sets errno to 0 on success. |
2094 | */ | 2091 | */ |
2092 | S.ok_to_redraw = 1; | ||
2095 | ic = read_key(STDIN_FILENO, read_key_buffer, timeout); | 2093 | ic = read_key(STDIN_FILENO, read_key_buffer, timeout); |
2094 | S.ok_to_redraw = 0; | ||
2096 | if (errno) { | 2095 | if (errno) { |
2097 | #if ENABLE_UNICODE_SUPPORT | 2096 | #if ENABLE_UNICODE_SUPPORT |
2098 | if (errno == EAGAIN && unicode_idx != 0) | 2097 | if (errno == EAGAIN && unicode_idx != 0) |
@@ -2223,7 +2222,6 @@ static int32_t reverse_i_search(void) | |||
2223 | int h; | 2222 | int h; |
2224 | unsigned match_buf_len = strlen(match_buf); | 2223 | unsigned match_buf_len = strlen(match_buf); |
2225 | 2224 | ||
2226 | fflush_all(); | ||
2227 | //FIXME: correct timeout? | 2225 | //FIXME: correct timeout? |
2228 | ic = lineedit_read_key(read_key_buffer, -1); | 2226 | ic = lineedit_read_key(read_key_buffer, -1); |
2229 | 2227 | ||
@@ -2325,6 +2323,7 @@ static int32_t reverse_i_search(void) | |||
2325 | * Returns: | 2323 | * Returns: |
2326 | * -1 on read errors or EOF, or on bare Ctrl-D, | 2324 | * -1 on read errors or EOF, or on bare Ctrl-D, |
2327 | * 0 on ctrl-C (the line entered is still returned in 'command'), | 2325 | * 0 on ctrl-C (the line entered is still returned in 'command'), |
2326 | * (in both cases the cursor remains on the input line, '\n' is not printed) | ||
2328 | * >0 length of input string, including terminating '\n' | 2327 | * >0 length of input string, including terminating '\n' |
2329 | */ | 2328 | */ |
2330 | int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *command, int maxsize, int timeout) | 2329 | int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *command, int maxsize, int timeout) |
@@ -2359,7 +2358,7 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman | |||
2359 | * tty is still in "raw mode"). | 2358 | * tty is still in "raw mode"). |
2360 | */ | 2359 | */ |
2361 | parse_and_put_prompt(prompt); | 2360 | parse_and_put_prompt(prompt); |
2362 | /* fflush_all(); - done by parse_and_put_prompt */ | 2361 | fflush_all(); |
2363 | if (fgets(command, maxsize, stdin) == NULL) | 2362 | if (fgets(command, maxsize, stdin) == NULL) |
2364 | len = -1; /* EOF or error */ | 2363 | len = -1; /* EOF or error */ |
2365 | else | 2364 | else |
@@ -2435,9 +2434,11 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman | |||
2435 | ask_terminal(); | 2434 | ask_terminal(); |
2436 | 2435 | ||
2437 | /* Install window resize handler (NB: after *all* init is complete) */ | 2436 | /* Install window resize handler (NB: after *all* init is complete) */ |
2438 | //FIXME: save entire sigaction! | 2437 | S.SIGWINCH_handler.sa_handler = win_changed; |
2439 | previous_SIGWINCH_handler = signal(SIGWINCH, win_changed); | 2438 | S.SIGWINCH_handler.sa_flags = SA_RESTART; |
2440 | win_changed(0); /* get initial window size */ | 2439 | sigaction(SIGWINCH, &S.SIGWINCH_handler, &S.SIGWINCH_handler); |
2440 | |||
2441 | cmdedit_termw = get_terminal_width(STDIN_FILENO); | ||
2441 | 2442 | ||
2442 | read_key_buffer[0] = 0; | 2443 | read_key_buffer[0] = 0; |
2443 | while (1) { | 2444 | while (1) { |
@@ -2450,8 +2451,14 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman | |||
2450 | * in one place. | 2451 | * in one place. |
2451 | */ | 2452 | */ |
2452 | int32_t ic, ic_raw; | 2453 | int32_t ic, ic_raw; |
2454 | unsigned count; | ||
2455 | |||
2456 | count = S.SIGWINCH_count; | ||
2457 | if (S.SIGWINCH_saved != count) { | ||
2458 | S.SIGWINCH_saved = count; | ||
2459 | cmdedit_setwidth(); | ||
2460 | } | ||
2453 | 2461 | ||
2454 | fflush_all(); | ||
2455 | ic = ic_raw = lineedit_read_key(read_key_buffer, timeout); | 2462 | ic = ic_raw = lineedit_read_key(read_key_buffer, timeout); |
2456 | #if ENABLE_PLATFORM_MINGW32 | 2463 | #if ENABLE_PLATFORM_MINGW32 |
2457 | /* scroll to cursor position on any keypress */ | 2464 | /* scroll to cursor position on any keypress */ |
@@ -2565,6 +2572,24 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman | |||
2565 | while (cursor > 0 && !BB_isspace(command_ps[cursor-1])) | 2572 | while (cursor > 0 && !BB_isspace(command_ps[cursor-1])) |
2566 | input_backspace(); | 2573 | input_backspace(); |
2567 | break; | 2574 | break; |
2575 | case KEYCODE_ALT_D: { | ||
2576 | /* Delete word forward */ | ||
2577 | int nc, sc = cursor; | ||
2578 | ctrl_right(); | ||
2579 | nc = cursor - sc; | ||
2580 | input_backward(nc); | ||
2581 | while (--nc >= 0) | ||
2582 | input_delete(1); | ||
2583 | break; | ||
2584 | } | ||
2585 | case KEYCODE_ALT_BACKSPACE: { | ||
2586 | /* Delete word backward */ | ||
2587 | int sc = cursor; | ||
2588 | ctrl_left(); | ||
2589 | while (sc-- > cursor) | ||
2590 | input_delete(1); | ||
2591 | break; | ||
2592 | } | ||
2568 | #if ENABLE_FEATURE_REVERSE_SEARCH | 2593 | #if ENABLE_FEATURE_REVERSE_SEARCH |
2569 | case CTRL('R'): | 2594 | case CTRL('R'): |
2570 | ic = ic_raw = reverse_i_search(); | 2595 | ic = ic_raw = reverse_i_search(); |
@@ -2792,7 +2817,6 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman | |||
2792 | && ic_raw == initial_settings.c_cc[VINTR] | 2817 | && ic_raw == initial_settings.c_cc[VINTR] |
2793 | ) { | 2818 | ) { |
2794 | /* Ctrl-C (usually) - stop gathering input */ | 2819 | /* Ctrl-C (usually) - stop gathering input */ |
2795 | goto_new_line(); | ||
2796 | command_len = 0; | 2820 | command_len = 0; |
2797 | break_out = -1; /* "do not append '\n'" */ | 2821 | break_out = -1; /* "do not append '\n'" */ |
2798 | break; | 2822 | break; |
@@ -2914,7 +2938,7 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman | |||
2914 | /* restore initial_settings */ | 2938 | /* restore initial_settings */ |
2915 | tcsetattr_stdin_TCSANOW(&initial_settings); | 2939 | tcsetattr_stdin_TCSANOW(&initial_settings); |
2916 | /* restore SIGWINCH handler */ | 2940 | /* restore SIGWINCH handler */ |
2917 | signal(SIGWINCH, previous_SIGWINCH_handler); | 2941 | sigaction_set(SIGWINCH, &S.SIGWINCH_handler); |
2918 | fflush_all(); | 2942 | fflush_all(); |
2919 | 2943 | ||
2920 | len = command_len; | 2944 | len = command_len; |
diff --git a/libbb/read_key.c b/libbb/read_key.c index ace23defb..951786869 100644 --- a/libbb/read_key.c +++ b/libbb/read_key.c | |||
@@ -18,8 +18,20 @@ int64_t FAST_FUNC read_key(int fd, char *buffer, int timeout) | |||
18 | /* Known escape sequences for cursor and function keys. | 18 | /* Known escape sequences for cursor and function keys. |
19 | * See "Xterm Control Sequences" | 19 | * See "Xterm Control Sequences" |
20 | * http://invisible-island.net/xterm/ctlseqs/ctlseqs.html | 20 | * http://invisible-island.net/xterm/ctlseqs/ctlseqs.html |
21 | * Array should be sorted from shortest to longest. | ||
21 | */ | 22 | */ |
22 | static const char esccmds[] ALIGN1 = { | 23 | static const char esccmds[] ALIGN1 = { |
24 | '\x7f' |0x80,KEYCODE_ALT_BACKSPACE, | ||
25 | '\b' |0x80,KEYCODE_ALT_BACKSPACE, | ||
26 | 'd' |0x80,KEYCODE_ALT_D , | ||
27 | /* lineedit mimics bash: Alt-f and Alt-b are forward/backward | ||
28 | * word jumps. We cheat here and make them return ALT_LEFT/RIGHT | ||
29 | * keycodes. This way, lineedit need no special code to handle them. | ||
30 | * If we'll need to distinguish them, introduce new ALT_F/B keycodes, | ||
31 | * and update lineedit to react to them. | ||
32 | */ | ||
33 | 'f' |0x80,KEYCODE_ALT_RIGHT, | ||
34 | 'b' |0x80,KEYCODE_ALT_LEFT, | ||
23 | 'O','A' |0x80,KEYCODE_UP , | 35 | 'O','A' |0x80,KEYCODE_UP , |
24 | 'O','B' |0x80,KEYCODE_DOWN , | 36 | 'O','B' |0x80,KEYCODE_DOWN , |
25 | 'O','C' |0x80,KEYCODE_RIGHT , | 37 | 'O','C' |0x80,KEYCODE_RIGHT , |