diff options
Diffstat (limited to 'libbb/lineedit.c')
-rw-r--r-- | libbb/lineedit.c | 126 |
1 files changed, 121 insertions, 5 deletions
diff --git a/libbb/lineedit.c b/libbb/lineedit.c index fbabc6c12..9781b4a08 100644 --- a/libbb/lineedit.c +++ b/libbb/lineedit.c | |||
@@ -363,7 +363,7 @@ int adjust_width_and_validate_wc(unsigned *width_adj, int wc); | |||
363 | /* Put 'command_ps[cursor]', cursor++. | 363 | /* Put 'command_ps[cursor]', cursor++. |
364 | * Advance cursor on screen. If we reached right margin, scroll text up | 364 | * Advance cursor on screen. If we reached right margin, scroll text up |
365 | * and remove terminal margin effect by printing 'next_char' */ | 365 | * and remove terminal margin effect by printing 'next_char' */ |
366 | #define HACK_FOR_WRONG_WIDTH 1 | 366 | #define HACK_FOR_WRONG_WIDTH 1 && !ENABLE_PLATFORM_MINGW32 |
367 | static void put_cur_glyph_and_inc_cursor(void) | 367 | static void put_cur_glyph_and_inc_cursor(void) |
368 | { | 368 | { |
369 | CHAR_T c = command_ps[cursor]; | 369 | CHAR_T c = command_ps[cursor]; |
@@ -426,6 +426,42 @@ static void put_cur_glyph_and_inc_cursor(void) | |||
426 | } | 426 | } |
427 | } | 427 | } |
428 | 428 | ||
429 | #if ENABLE_PLATFORM_MINGW32 | ||
430 | static void inc_cursor(void) | ||
431 | { | ||
432 | CHAR_T c = command_ps[cursor]; | ||
433 | unsigned width = 0; | ||
434 | int ofs_to_right; | ||
435 | |||
436 | /* advance cursor */ | ||
437 | cursor++; | ||
438 | if (unicode_status == UNICODE_ON) { | ||
439 | IF_UNICODE_WIDE_WCHARS(width = cmdedit_x;) | ||
440 | c = adjust_width_and_validate_wc(&cmdedit_x, c); | ||
441 | IF_UNICODE_WIDE_WCHARS(width = cmdedit_x - width;) | ||
442 | } else { | ||
443 | cmdedit_x++; | ||
444 | } | ||
445 | |||
446 | ofs_to_right = cmdedit_x - cmdedit_termw; | ||
447 | if (!ENABLE_UNICODE_WIDE_WCHARS || ofs_to_right <= 0) { | ||
448 | /* cursor remains on this line */ | ||
449 | printf(ESC"[1C"); | ||
450 | } | ||
451 | |||
452 | if (ofs_to_right >= 0) { | ||
453 | /* we go to the next line */ | ||
454 | printf(ESC"[1B"); | ||
455 | bb_putchar('\r'); | ||
456 | cmdedit_y++; | ||
457 | if (!ENABLE_UNICODE_WIDE_WCHARS || ofs_to_right == 0) { | ||
458 | width = 0; | ||
459 | } | ||
460 | cmdedit_x = width; | ||
461 | } | ||
462 | } | ||
463 | #endif | ||
464 | |||
429 | /* Move to end of line (by printing all chars till the end) */ | 465 | /* Move to end of line (by printing all chars till the end) */ |
430 | static void put_till_end_and_adv_cursor(void) | 466 | static void put_till_end_and_adv_cursor(void) |
431 | { | 467 | { |
@@ -485,6 +521,7 @@ static void input_backward(unsigned num) | |||
485 | 521 | ||
486 | if (cmdedit_x >= num) { | 522 | if (cmdedit_x >= num) { |
487 | cmdedit_x -= num; | 523 | cmdedit_x -= num; |
524 | #if !ENABLE_PLATFORM_MINGW32 | ||
488 | if (num <= 4) { | 525 | if (num <= 4) { |
489 | /* This is longer by 5 bytes on x86. | 526 | /* This is longer by 5 bytes on x86. |
490 | * Also gets miscompiled for ARM users | 527 | * Also gets miscompiled for ARM users |
@@ -497,6 +534,7 @@ static void input_backward(unsigned num) | |||
497 | } while (--num); | 534 | } while (--num); |
498 | return; | 535 | return; |
499 | } | 536 | } |
537 | #endif | ||
500 | printf(ESC"[%uD", num); | 538 | printf(ESC"[%uD", num); |
501 | return; | 539 | return; |
502 | } | 540 | } |
@@ -635,7 +673,11 @@ static void input_backspace(void) | |||
635 | static void input_forward(void) | 673 | static void input_forward(void) |
636 | { | 674 | { |
637 | if (cursor < command_len) | 675 | if (cursor < command_len) |
676 | #if !ENABLE_PLATFORM_MINGW32 | ||
638 | put_cur_glyph_and_inc_cursor(); | 677 | put_cur_glyph_and_inc_cursor(); |
678 | #else | ||
679 | inc_cursor(); | ||
680 | #endif | ||
639 | } | 681 | } |
640 | 682 | ||
641 | #if ENABLE_FEATURE_TAB_COMPLETION | 683 | #if ENABLE_FEATURE_TAB_COMPLETION |
@@ -646,6 +688,14 @@ static void input_forward(void) | |||
646 | //Also, perhaps "foo b<TAB> needs to complete to "foo bar" <cursor>, | 688 | //Also, perhaps "foo b<TAB> needs to complete to "foo bar" <cursor>, |
647 | //not "foo bar <cursor>... | 689 | //not "foo bar <cursor>... |
648 | 690 | ||
691 | # if ENABLE_PLATFORM_MINGW32 | ||
692 | /* use case-insensitive comparisons for filenames */ | ||
693 | # define is_prefixed_with(s, k) is_prefixed_with_case(s, k) | ||
694 | # define qsort_string_vector(s, c) qsort_string_vector_case(s, c) | ||
695 | # define strcmp(s, t) strcasecmp(s, t) | ||
696 | # define strncmp(s, t, n) strncasecmp(s, t, n) | ||
697 | # endif | ||
698 | |||
649 | static void free_tab_completion_data(void) | 699 | static void free_tab_completion_data(void) |
650 | { | 700 | { |
651 | if (matches) { | 701 | if (matches) { |
@@ -662,8 +712,12 @@ static void add_match(char *matched) | |||
662 | while (*p) { | 712 | while (*p) { |
663 | /* ESC attack fix: drop any string with control chars */ | 713 | /* ESC attack fix: drop any string with control chars */ |
664 | if (*p < ' ' | 714 | if (*p < ' ' |
715 | # if !ENABLE_PLATFORM_MINGW32 | ||
665 | || (!ENABLE_UNICODE_SUPPORT && *p >= 0x7f) | 716 | || (!ENABLE_UNICODE_SUPPORT && *p >= 0x7f) |
666 | || (ENABLE_UNICODE_SUPPORT && *p == 0x7f) | 717 | || (ENABLE_UNICODE_SUPPORT && *p == 0x7f) |
718 | # else | ||
719 | || *p == 0x7f | ||
720 | # endif | ||
667 | ) { | 721 | ) { |
668 | free(matched); | 722 | free(matched); |
669 | return; | 723 | return; |
@@ -682,13 +736,16 @@ static void add_match(char *matched) | |||
682 | */ | 736 | */ |
683 | static char *username_path_completion(char *ud) | 737 | static char *username_path_completion(char *ud) |
684 | { | 738 | { |
739 | # if !ENABLE_PLATFORM_MINGW32 | ||
685 | struct passwd *entry; | 740 | struct passwd *entry; |
741 | #endif | ||
686 | char *tilde_name = ud; | 742 | char *tilde_name = ud; |
687 | char *home = NULL; | 743 | char *home = NULL; |
688 | 744 | ||
689 | ud++; /* skip ~ */ | 745 | ud++; /* skip ~ */ |
690 | if (*ud == '/') { /* "~/..." */ | 746 | if (*ud == '/') { /* "~/..." */ |
691 | home = home_pwd_buf; | 747 | home = home_pwd_buf; |
748 | # if !ENABLE_PLATFORM_MINGW32 | ||
692 | } else { | 749 | } else { |
693 | /* "~user/..." */ | 750 | /* "~user/..." */ |
694 | ud = strchr(ud, '/'); | 751 | ud = strchr(ud, '/'); |
@@ -697,6 +754,7 @@ static char *username_path_completion(char *ud) | |||
697 | *ud = '/'; /* restore "~user/..." */ | 754 | *ud = '/'; /* restore "~user/..." */ |
698 | if (entry) | 755 | if (entry) |
699 | home = entry->pw_dir; | 756 | home = entry->pw_dir; |
757 | # endif | ||
700 | } | 758 | } |
701 | if (home) { | 759 | if (home) { |
702 | ud = concat_path_file(home, ud); | 760 | ud = concat_path_file(home, ud); |
@@ -706,6 +764,7 @@ static char *username_path_completion(char *ud) | |||
706 | return tilde_name; | 764 | return tilde_name; |
707 | } | 765 | } |
708 | 766 | ||
767 | # if !ENABLE_PLATFORM_MINGW32 | ||
709 | /* ~use<tab> - find all users with this prefix. | 768 | /* ~use<tab> - find all users with this prefix. |
710 | * Return the length of the prefix used for matching. | 769 | * Return the length of the prefix used for matching. |
711 | */ | 770 | */ |
@@ -728,6 +787,7 @@ static NOINLINE unsigned complete_username(const char *ud) | |||
728 | 787 | ||
729 | return 1 + userlen; | 788 | return 1 + userlen; |
730 | } | 789 | } |
790 | # endif | ||
731 | # endif /* FEATURE_USERNAME_COMPLETION */ | 791 | # endif /* FEATURE_USERNAME_COMPLETION */ |
732 | 792 | ||
733 | enum { | 793 | enum { |
@@ -755,7 +815,7 @@ static int path_parse(char ***p) | |||
755 | tmp = (char*)pth; | 815 | tmp = (char*)pth; |
756 | npth = 1; /* path component count */ | 816 | npth = 1; /* path component count */ |
757 | while (1) { | 817 | while (1) { |
758 | tmp = strchr(tmp, ':'); | 818 | tmp = strchr(tmp, PATH_SEP); |
759 | if (!tmp) | 819 | if (!tmp) |
760 | break; | 820 | break; |
761 | tmp++; | 821 | tmp++; |
@@ -768,7 +828,7 @@ static int path_parse(char ***p) | |||
768 | res[0] = tmp = xstrdup(pth); | 828 | res[0] = tmp = xstrdup(pth); |
769 | npth = 1; | 829 | npth = 1; |
770 | while (1) { | 830 | while (1) { |
771 | tmp = strchr(tmp, ':'); | 831 | tmp = strchr(tmp, PATH_SEP); |
772 | if (!tmp) | 832 | if (!tmp) |
773 | break; | 833 | break; |
774 | *tmp++ = '\0'; /* ':' -> '\0' */ | 834 | *tmp++ = '\0'; /* ':' -> '\0' */ |
@@ -796,6 +856,17 @@ static NOINLINE unsigned complete_cmd_dir_file(const char *command, int type) | |||
796 | path1[0] = (char*)"."; | 856 | path1[0] = (char*)"."; |
797 | 857 | ||
798 | pfind = strrchr(command, '/'); | 858 | pfind = strrchr(command, '/'); |
859 | #if ENABLE_PLATFORM_MINGW32 | ||
860 | if (!pfind && has_dos_drive_prefix(command) && command[2] != '\0') { | ||
861 | char buffer[PATH_MAX]; | ||
862 | |||
863 | /* path is of form c:path with no '/' */ | ||
864 | if (get_drive_cwd(command, buffer, PATH_MAX)) { | ||
865 | pfind = command + 2; | ||
866 | path1[0] = xstrdup(buffer); | ||
867 | } | ||
868 | } else | ||
869 | #endif | ||
799 | if (!pfind) { | 870 | if (!pfind) { |
800 | if (type == FIND_EXE_ONLY) | 871 | if (type == FIND_EXE_ONLY) |
801 | npaths = path_parse(&paths); | 872 | npaths = path_parse(&paths); |
@@ -854,6 +925,12 @@ static NOINLINE unsigned complete_cmd_dir_file(const char *command, int type) | |||
854 | if (stat(found, &st) && lstat(found, &st)) | 925 | if (stat(found, &st) && lstat(found, &st)) |
855 | goto cont; /* hmm, remove in progress? */ | 926 | goto cont; /* hmm, remove in progress? */ |
856 | 927 | ||
928 | # if ENABLE_PLATFORM_MINGW32 | ||
929 | if (type == FIND_EXE_ONLY && !S_ISDIR(st.st_mode) && | ||
930 | !file_is_executable(found)) | ||
931 | goto cont; | ||
932 | # endif | ||
933 | |||
857 | /* Save only name */ | 934 | /* Save only name */ |
858 | len = strlen(name_found); | 935 | len = strlen(name_found); |
859 | found = xrealloc(found, len + 2); /* +2: for slash and NUL */ | 936 | found = xrealloc(found, len + 2); /* +2: for slash and NUL */ |
@@ -1173,7 +1250,7 @@ static NOINLINE void input_tab(smallint *lastWasTab) | |||
1173 | /* Free up any memory already allocated */ | 1250 | /* Free up any memory already allocated */ |
1174 | free_tab_completion_data(); | 1251 | free_tab_completion_data(); |
1175 | 1252 | ||
1176 | # if ENABLE_FEATURE_USERNAME_COMPLETION | 1253 | # if ENABLE_FEATURE_USERNAME_COMPLETION && !ENABLE_PLATFORM_MINGW32 |
1177 | /* If the word starts with ~ and there is no slash in the word, | 1254 | /* If the word starts with ~ and there is no slash in the word, |
1178 | * then try completing this word as a username. */ | 1255 | * then try completing this word as a username. */ |
1179 | if (state->flags & USERNAME_COMPLETION) | 1256 | if (state->flags & USERNAME_COMPLETION) |
@@ -1224,7 +1301,11 @@ static NOINLINE void input_tab(smallint *lastWasTab) | |||
1224 | for (cp = chosen_match; *cp; cp++) { | 1301 | for (cp = chosen_match; *cp; cp++) { |
1225 | unsigned n; | 1302 | unsigned n; |
1226 | for (n = 1; n < num_matches; n++) { | 1303 | for (n = 1; n < num_matches; n++) { |
1304 | # if !ENABLE_PLATFORM_MINGW32 | ||
1227 | if (matches[n][cp - chosen_match] != *cp) { | 1305 | if (matches[n][cp - chosen_match] != *cp) { |
1306 | # else | ||
1307 | if (tolower(matches[n][cp - chosen_match]) != tolower(*cp)) { | ||
1308 | # endif | ||
1228 | goto stop; | 1309 | goto stop; |
1229 | } | 1310 | } |
1230 | } | 1311 | } |
@@ -1260,7 +1341,11 @@ static NOINLINE void input_tab(smallint *lastWasTab) | |||
1260 | /* save tail */ | 1341 | /* save tail */ |
1261 | strcpy(match_buf, &command_ps[cursor]); | 1342 | strcpy(match_buf, &command_ps[cursor]); |
1262 | /* add match and tail */ | 1343 | /* add match and tail */ |
1344 | #if ENABLE_PLATFORM_MINGW32 | ||
1345 | sprintf(&command_ps[cursor-match_pfx_len], "%s%s", chosen_match, match_buf); | ||
1346 | #else | ||
1263 | sprintf(&command_ps[cursor], "%s%s", chosen_match + match_pfx_len, match_buf); | 1347 | sprintf(&command_ps[cursor], "%s%s", chosen_match + match_pfx_len, match_buf); |
1348 | #endif | ||
1264 | command_len = strlen(command_ps); | 1349 | command_len = strlen(command_ps); |
1265 | /* new pos */ | 1350 | /* new pos */ |
1266 | pos = cursor + len_found - match_pfx_len; | 1351 | pos = cursor + len_found - match_pfx_len; |
@@ -1297,6 +1382,13 @@ static NOINLINE void input_tab(smallint *lastWasTab) | |||
1297 | free(match_buf); | 1382 | free(match_buf); |
1298 | } | 1383 | } |
1299 | 1384 | ||
1385 | # if ENABLE_PLATFORM_MINGW32 | ||
1386 | # undef is_prefixed_with | ||
1387 | # undef qsort_string_vector | ||
1388 | # undef strcmp | ||
1389 | # undef strncmp | ||
1390 | # endif | ||
1391 | |||
1300 | #endif /* FEATURE_TAB_COMPLETION */ | 1392 | #endif /* FEATURE_TAB_COMPLETION */ |
1301 | 1393 | ||
1302 | 1394 | ||
@@ -2339,7 +2431,7 @@ static void sigaction2(int sig, struct sigaction *act) | |||
2339 | */ | 2431 | */ |
2340 | int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *command, int maxsize) | 2432 | int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *command, int maxsize) |
2341 | { | 2433 | { |
2342 | int len, n; | 2434 | int len IF_NOT_PLATFORM_MINGW32(, n); |
2343 | int timeout; | 2435 | int timeout; |
2344 | #if ENABLE_FEATURE_TAB_COMPLETION | 2436 | #if ENABLE_FEATURE_TAB_COMPLETION |
2345 | smallint lastWasTab = 0; | 2437 | smallint lastWasTab = 0; |
@@ -2349,15 +2441,23 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman | |||
2349 | smallint vi_cmdmode = 0; | 2441 | smallint vi_cmdmode = 0; |
2350 | #endif | 2442 | #endif |
2351 | struct termios initial_settings; | 2443 | struct termios initial_settings; |
2444 | #if !ENABLE_PLATFORM_MINGW32 | ||
2352 | struct termios new_settings; | 2445 | struct termios new_settings; |
2446 | #endif | ||
2353 | char read_key_buffer[KEYCODE_BUFFER_SIZE]; | 2447 | char read_key_buffer[KEYCODE_BUFFER_SIZE]; |
2354 | 2448 | ||
2355 | INIT_S(); | 2449 | INIT_S(); |
2356 | 2450 | ||
2451 | #if !ENABLE_PLATFORM_MINGW32 | ||
2357 | n = get_termios_and_make_raw(STDIN_FILENO, &new_settings, &initial_settings, 0 | 2452 | n = get_termios_and_make_raw(STDIN_FILENO, &new_settings, &initial_settings, 0 |
2358 | | TERMIOS_CLEAR_ISIG /* turn off INTR (ctrl-C), QUIT, SUSP */ | 2453 | | TERMIOS_CLEAR_ISIG /* turn off INTR (ctrl-C), QUIT, SUSP */ |
2359 | ); | 2454 | ); |
2360 | if (n != 0 || (initial_settings.c_lflag & (ECHO|ICANON)) == ICANON) { | 2455 | if (n != 0 || (initial_settings.c_lflag & (ECHO|ICANON)) == ICANON) { |
2456 | #else | ||
2457 | initial_settings.c_cc[VINTR] = CTRL('C'); | ||
2458 | initial_settings.c_cc[VEOF] = CTRL('D'); | ||
2459 | if (!isatty(0) || !isatty(1)) { | ||
2460 | #endif | ||
2361 | /* Happens when e.g. stty -echo was run before. | 2461 | /* Happens when e.g. stty -echo was run before. |
2362 | * But if ICANON is not set, we don't come here. | 2462 | * But if ICANON is not set, we don't come here. |
2363 | * (example: interactive python ^Z-backgrounded, | 2463 | * (example: interactive python ^Z-backgrounded, |
@@ -2411,7 +2511,9 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman | |||
2411 | #endif | 2511 | #endif |
2412 | #define command command_must_not_be_used | 2512 | #define command command_must_not_be_used |
2413 | 2513 | ||
2514 | #if !ENABLE_PLATFORM_MINGW32 | ||
2414 | tcsetattr_stdin_TCSANOW(&new_settings); | 2515 | tcsetattr_stdin_TCSANOW(&new_settings); |
2516 | #endif | ||
2415 | 2517 | ||
2416 | #if ENABLE_USERNAME_OR_HOMEDIR | 2518 | #if ENABLE_USERNAME_OR_HOMEDIR |
2417 | { | 2519 | { |
@@ -2464,6 +2566,11 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman | |||
2464 | } | 2566 | } |
2465 | #endif | 2567 | #endif |
2466 | ic = ic_raw = lineedit_read_key(read_key_buffer, timeout); | 2568 | ic = ic_raw = lineedit_read_key(read_key_buffer, timeout); |
2569 | #if ENABLE_PLATFORM_MINGW32 | ||
2570 | /* scroll to cursor position on any keypress */ | ||
2571 | if (isatty(fileno(stdin)) && isatty(fileno(stdout))) | ||
2572 | move_cursor_row(0); | ||
2573 | #endif | ||
2467 | 2574 | ||
2468 | #if ENABLE_FEATURE_REVERSE_SEARCH | 2575 | #if ENABLE_FEATURE_REVERSE_SEARCH |
2469 | again: | 2576 | again: |
@@ -2525,6 +2632,13 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman | |||
2525 | input_tab(&lastWasTab); | 2632 | input_tab(&lastWasTab); |
2526 | break; | 2633 | break; |
2527 | #endif | 2634 | #endif |
2635 | #if ENABLE_PLATFORM_MINGW32 | ||
2636 | case CTRL('Z'): | ||
2637 | command_ps[command_len] = '\0'; | ||
2638 | bs_to_slash(command_ps); | ||
2639 | redraw(cmdedit_y, 0); | ||
2640 | break; | ||
2641 | #endif | ||
2528 | case CTRL('K'): | 2642 | case CTRL('K'): |
2529 | /* Control-k -- clear to end of line */ | 2643 | /* Control-k -- clear to end of line */ |
2530 | command_ps[cursor] = BB_NUL; | 2644 | command_ps[cursor] = BB_NUL; |
@@ -2897,8 +3011,10 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman | |||
2897 | free_tab_completion_data(); | 3011 | free_tab_completion_data(); |
2898 | #endif | 3012 | #endif |
2899 | 3013 | ||
3014 | #if !ENABLE_PLATFORM_MINGW32 | ||
2900 | /* restore initial_settings */ | 3015 | /* restore initial_settings */ |
2901 | tcsetattr_stdin_TCSANOW(&initial_settings); | 3016 | tcsetattr_stdin_TCSANOW(&initial_settings); |
3017 | #endif | ||
2902 | #if ENABLE_FEATURE_EDITING_WINCH | 3018 | #if ENABLE_FEATURE_EDITING_WINCH |
2903 | /* restore SIGWINCH handler */ | 3019 | /* restore SIGWINCH handler */ |
2904 | sigaction_set(SIGWINCH, &S.SIGWINCH_handler); | 3020 | sigaction_set(SIGWINCH, &S.SIGWINCH_handler); |