aboutsummaryrefslogtreecommitdiff
path: root/libbb/lineedit.c
diff options
context:
space:
mode:
Diffstat (limited to 'libbb/lineedit.c')
-rw-r--r--libbb/lineedit.c126
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
367static void put_cur_glyph_and_inc_cursor(void) 367static 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
430static 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) */
430static void put_till_end_and_adv_cursor(void) 466static 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)
635static void input_forward(void) 673static 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
649static void free_tab_completion_data(void) 699static 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 */
683static char *username_path_completion(char *ud) 737static 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
733enum { 793enum {
@@ -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 */
2340int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *command, int maxsize) 2432int 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);