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); |
