aboutsummaryrefslogtreecommitdiff
path: root/libbb/lineedit.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--libbb/lineedit.c254
1 files changed, 238 insertions, 16 deletions
diff --git a/libbb/lineedit.c b/libbb/lineedit.c
index 43d1da35c..77207a427 100644
--- a/libbb/lineedit.c
+++ b/libbb/lineedit.c
@@ -258,8 +258,14 @@ static NOINLINE const char *get_homedir_or_NULL(void)
258# else 258# else
259 home = getenv("HOME"); 259 home = getenv("HOME");
260# endif 260# endif
261 if (home != NULL && home[0] != '\0') 261 if (home != NULL && home[0] != '\0') {
262# if ENABLE_PLATFORM_MINGW32
263 char *t = auto_string(xstrdup(home));
264 bs_to_slash(t);
265 home = t;
266# endif
262 return home; 267 return home;
268 }
263 269
264 if (!got_user_strings) 270 if (!got_user_strings)
265 get_user_strings(); 271 get_user_strings();
@@ -413,7 +419,7 @@ int adjust_width_and_validate_wc(unsigned *width_adj, int wc);
413/* Put 'command_ps[cursor]', cursor++. 419/* Put 'command_ps[cursor]', cursor++.
414 * Advance cursor on screen. If we reached right margin, scroll text up 420 * Advance cursor on screen. If we reached right margin, scroll text up
415 * and remove terminal margin effect by printing 'next_char' */ 421 * and remove terminal margin effect by printing 'next_char' */
416#define HACK_FOR_WRONG_WIDTH 1 422#define HACK_FOR_WRONG_WIDTH 1 && !ENABLE_PLATFORM_MINGW32
417static void put_cur_glyph_and_inc_cursor(void) 423static void put_cur_glyph_and_inc_cursor(void)
418{ 424{
419 CHAR_T c = command_ps[cursor]; 425 CHAR_T c = command_ps[cursor];
@@ -476,6 +482,42 @@ static void put_cur_glyph_and_inc_cursor(void)
476 } 482 }
477} 483}
478 484
485#if ENABLE_PLATFORM_MINGW32
486static void inc_cursor(void)
487{
488 CHAR_T c = command_ps[cursor];
489 unsigned width = 0;
490 int ofs_to_right;
491
492 /* advance cursor */
493 cursor++;
494 if (unicode_status == UNICODE_ON) {
495 IF_UNICODE_WIDE_WCHARS(width = cmdedit_x;)
496 c = adjust_width_and_validate_wc(&cmdedit_x, c);
497 IF_UNICODE_WIDE_WCHARS(width = cmdedit_x - width;)
498 } else {
499 cmdedit_x++;
500 }
501
502 ofs_to_right = cmdedit_x - cmdedit_termw;
503 if (!ENABLE_UNICODE_WIDE_WCHARS || ofs_to_right <= 0) {
504 /* cursor remains on this line */
505 printf(ESC"[1C");
506 }
507
508 if (ofs_to_right >= 0) {
509 /* we go to the next line */
510 printf(ESC"[1B");
511 bb_putchar('\r');
512 cmdedit_y++;
513 if (!ENABLE_UNICODE_WIDE_WCHARS || ofs_to_right == 0) {
514 width = 0;
515 }
516 cmdedit_x = width;
517 }
518}
519#endif
520
479/* Move to end of line (by printing all chars till the end) */ 521/* Move to end of line (by printing all chars till the end) */
480static void put_till_end_and_adv_cursor(void) 522static void put_till_end_and_adv_cursor(void)
481{ 523{
@@ -538,6 +580,7 @@ static void input_backward(unsigned num)
538 580
539 if (cmdedit_x >= num) { 581 if (cmdedit_x >= num) {
540 cmdedit_x -= num; 582 cmdedit_x -= num;
583#if !ENABLE_PLATFORM_MINGW32
541 if (num <= 4) { 584 if (num <= 4) {
542 /* This is longer by 5 bytes on x86. 585 /* This is longer by 5 bytes on x86.
543 * Also gets miscompiled for ARM users 586 * Also gets miscompiled for ARM users
@@ -550,6 +593,7 @@ static void input_backward(unsigned num)
550 } while (--num); 593 } while (--num);
551 return; 594 return;
552 } 595 }
596#endif
553 fprintf(stderr, ESC"[%uD", num); 597 fprintf(stderr, ESC"[%uD", num);
554 return; 598 return;
555 } 599 }
@@ -688,7 +732,23 @@ static void input_backspace(void)
688static void input_forward(void) 732static void input_forward(void)
689{ 733{
690 if (cursor < command_len) 734 if (cursor < command_len)
735#if !ENABLE_PLATFORM_MINGW32
691 put_cur_glyph_and_inc_cursor(); 736 put_cur_glyph_and_inc_cursor();
737#else
738 /*
739 * inc_cursor improves forward cursor movement appearance on
740 * win 7/8 console, but it's broken with unicode wide-glyphs,
741 * e.g. paste and move forward over: echo 开开心心过每一天
742 * so disable inc_cursor when unicode is active (which is only
743 * windows 10+, where inc_cursor is not needed anyway).
744 */
745 {
746 if (unicode_status == UNICODE_ON)
747 put_cur_glyph_and_inc_cursor();
748 else
749 inc_cursor();
750 }
751#endif
692} 752}
693 753
694#if ENABLE_FEATURE_TAB_COMPLETION 754#if ENABLE_FEATURE_TAB_COMPLETION
@@ -709,25 +769,56 @@ static void free_tab_completion_data(void)
709 } 769 }
710} 770}
711 771
712static void add_match(char *matched) 772#if !ENABLE_PLATFORM_MINGW32
773# define add_match(m, s) add_match(m)
774#endif
775
776static void add_match(char *matched, int sensitive)
713{ 777{
778# if ENABLE_PLATFORM_MINGW32
779 size_t len;
780# endif
714 unsigned char *p = (unsigned char*)matched; 781 unsigned char *p = (unsigned char*)matched;
715 while (*p) { 782 while (*p) {
716 /* ESC attack fix: drop any string with control chars */ 783 /* ESC attack fix: drop any string with control chars */
717 if (*p < ' ' 784 if (*p < ' '
785# if !ENABLE_PLATFORM_MINGW32
718 || (!ENABLE_UNICODE_SUPPORT && *p >= 0x7f) 786 || (!ENABLE_UNICODE_SUPPORT && *p >= 0x7f)
719 || (ENABLE_UNICODE_SUPPORT && *p == 0x7f) 787 || (ENABLE_UNICODE_SUPPORT && *p == 0x7f)
788# else
789 /*
790 * on Windows, *p > 0x7f is never control:
791 * without unicode active: these are normal codepage chars.
792 * with unicode active: these are UTF8 continuation bytes.
793 */
794 || *p == 0x7f
795# endif
720 ) { 796 ) {
721 free(matched); 797 free(matched);
722 return; 798 return;
723 } 799 }
724 p++; 800 p++;
725 } 801 }
802# if ENABLE_PLATFORM_MINGW32
803 /* The case-sensitivity flag is stored after NUL terminator */
804 len = strlen(matched);
805 matched = xrealloc(matched, len + 2);
806 matched[len + 1] = sensitive;
807# endif
726 matches = xrealloc_vector(matches, 4, num_matches); 808 matches = xrealloc_vector(matches, 4, num_matches);
727 matches[num_matches] = matched; 809 matches[num_matches] = matched;
728 num_matches++; 810 num_matches++;
729} 811}
730 812
813# if ENABLE_PLATFORM_MINGW32
814static int is_case_sensitive(const char *p)
815{
816 while (*p++)
817 ;
818 return *p;
819}
820# endif
821
731# if ENABLE_FEATURE_USERNAME_COMPLETION 822# if ENABLE_FEATURE_USERNAME_COMPLETION
732/* Replace "~user/..." with "/homedir/...". 823/* Replace "~user/..." with "/homedir/...".
733 * The parameter is malloced, free it or return it 824 * The parameter is malloced, free it or return it
@@ -735,13 +826,16 @@ static void add_match(char *matched)
735 */ 826 */
736static char *username_path_completion(char *ud) 827static char *username_path_completion(char *ud)
737{ 828{
829# if !ENABLE_PLATFORM_MINGW32
738 struct passwd *entry; 830 struct passwd *entry;
831#endif
739 char *tilde_name = ud; 832 char *tilde_name = ud;
740 const char *home = NULL; 833 const char *home = NULL;
741 834
742 ud++; /* skip ~ */ 835 ud++; /* skip ~ */
743 if (*ud == '/') { /* "~/..." */ 836 if (*ud == '/') { /* "~/..." */
744 home = get_homedir_or_NULL(); 837 home = get_homedir_or_NULL();
838# if !ENABLE_PLATFORM_MINGW32
745 } else { 839 } else {
746 /* "~user/..." */ 840 /* "~user/..." */
747 ud = strchr(ud, '/'); 841 ud = strchr(ud, '/');
@@ -750,6 +844,7 @@ static char *username_path_completion(char *ud)
750 *ud = '/'; /* restore "~user/..." */ 844 *ud = '/'; /* restore "~user/..." */
751 if (entry) 845 if (entry)
752 home = entry->pw_dir; 846 home = entry->pw_dir;
847# endif
753 } 848 }
754 if (home) { 849 if (home) {
755 ud = concat_path_file(home, ud); 850 ud = concat_path_file(home, ud);
@@ -759,6 +854,7 @@ static char *username_path_completion(char *ud)
759 return tilde_name; 854 return tilde_name;
760} 855}
761 856
857# if !ENABLE_PLATFORM_MINGW32
762/* ~use<tab> - find all users with this prefix. 858/* ~use<tab> - find all users with this prefix.
763 * Return the length of the prefix used for matching. 859 * Return the length of the prefix used for matching.
764 */ 860 */
@@ -774,13 +870,14 @@ static NOINLINE unsigned complete_username(const char *ud)
774 while ((pw = getpwent()) != NULL) { 870 while ((pw = getpwent()) != NULL) {
775 /* Null usernames should result in all users as possible completions. */ 871 /* Null usernames should result in all users as possible completions. */
776 if (/* !ud[0] || */ is_prefixed_with(pw->pw_name, ud)) { 872 if (/* !ud[0] || */ is_prefixed_with(pw->pw_name, ud)) {
777 add_match(xasprintf("~%s/", pw->pw_name)); 873 add_match(xasprintf("~%s/", pw->pw_name), TRUE);
778 } 874 }
779 } 875 }
780 endpwent(); /* don't keep password file open */ 876 endpwent(); /* don't keep password file open */
781 877
782 return 1 + userlen; 878 return 1 + userlen;
783} 879}
880# endif
784# endif /* FEATURE_USERNAME_COMPLETION */ 881# endif /* FEATURE_USERNAME_COMPLETION */
785 882
786enum { 883enum {
@@ -810,7 +907,7 @@ static unsigned path_parse(char ***p)
810 tmp = (char*)pth; 907 tmp = (char*)pth;
811 npth = 1; /* path component count */ 908 npth = 1; /* path component count */
812 while (1) { 909 while (1) {
813 tmp = strchr(tmp, ':'); 910 tmp = strchr(tmp, PATH_SEP);
814 if (!tmp) 911 if (!tmp)
815 break; 912 break;
816 tmp++; 913 tmp++;
@@ -821,7 +918,7 @@ static unsigned path_parse(char ***p)
821 res[0] = tmp = xstrdup(pth); 918 res[0] = tmp = xstrdup(pth);
822 npth = 1; 919 npth = 1;
823 while (1) { 920 while (1) {
824 tmp = strchr(tmp, ':'); 921 tmp = strchr(tmp, PATH_SEP);
825 if (!tmp) 922 if (!tmp)
826 break; 923 break;
827 *tmp++ = '\0'; /* ':' -> '\0' */ 924 *tmp++ = '\0'; /* ':' -> '\0' */
@@ -849,6 +946,17 @@ static NOINLINE unsigned complete_cmd_dir_file(const char *command, int type)
849 path1[0] = (char*)"."; 946 path1[0] = (char*)".";
850 947
851 basecmd = strrchr(command, '/'); 948 basecmd = strrchr(command, '/');
949#if ENABLE_PLATFORM_MINGW32
950 if (!basecmd && has_dos_drive_prefix(command) && command[2] != '\0') {
951 char buffer[PATH_MAX];
952
953 /* path is of form c:path with no '/' */
954 if (get_drive_cwd(command, buffer, PATH_MAX)) {
955 basecmd = command + 2;
956 path1[0] = dirbuf = xstrdup(buffer);
957 }
958 } else
959#endif
852 if (!basecmd) { 960 if (!basecmd) {
853 if (type == FIND_EXE_ONLY) 961 if (type == FIND_EXE_ONLY)
854 npaths = path_parse(&paths); 962 npaths = path_parse(&paths);
@@ -869,9 +977,13 @@ static NOINLINE unsigned complete_cmd_dir_file(const char *command, int type)
869 if (type == FIND_EXE_ONLY && !dirbuf) { 977 if (type == FIND_EXE_ONLY && !dirbuf) {
870# if ENABLE_FEATURE_SH_STANDALONE && NUM_APPLETS != 1 978# if ENABLE_FEATURE_SH_STANDALONE && NUM_APPLETS != 1
871 const char *p = applet_names; 979 const char *p = applet_names;
980# if ENABLE_PLATFORM_MINGW32
981 const char *shpath = state->flags & WITH_PATH_LOOKUP ?
982 state->path_lookup : NULL;
983# endif
872 while (*p) { 984 while (*p) {
873 if (strncmp(basecmd, p, baselen) == 0) 985 if (strncmp(basecmd, p, baselen) == 0 && prefer_applet(p, shpath))
874 add_match(xstrdup(p)); 986 add_match(xstrdup(p), TRUE);
875 while (*p++ != '\0') 987 while (*p++ != '\0')
876 continue; 988 continue;
877 } 989 }
@@ -884,7 +996,7 @@ static NOINLINE unsigned complete_cmd_dir_file(const char *command, int type)
884 if (!b) 996 if (!b)
885 break; 997 break;
886 if (strncmp(basecmd, b, baselen) == 0) 998 if (strncmp(basecmd, b, baselen) == 0)
887 add_match(xstrdup(b)); 999 add_match(xstrdup(b), TRUE);
888 } 1000 }
889 } 1001 }
890# endif 1002# endif
@@ -918,7 +1030,11 @@ static NOINLINE unsigned complete_cmd_dir_file(const char *command, int type)
918 if (!basecmd[0] && DOT_OR_DOTDOT(name_found)) 1030 if (!basecmd[0] && DOT_OR_DOTDOT(name_found))
919 continue; 1031 continue;
920 /* match? */ 1032 /* match? */
1033# if ENABLE_PLATFORM_MINGW32
1034 if (strncasecmp(basecmd, name_found, baselen) != 0)
1035# else
921 if (strncmp(basecmd, name_found, baselen) != 0) 1036 if (strncmp(basecmd, name_found, baselen) != 0)
1037# endif
922 continue; /* no */ 1038 continue; /* no */
923 1039
924 found = concat_path_file(lpath, name_found); 1040 found = concat_path_file(lpath, name_found);
@@ -928,6 +1044,16 @@ static NOINLINE unsigned complete_cmd_dir_file(const char *command, int type)
928 if (stat(found, &st) && lstat(found, &st)) 1044 if (stat(found, &st) && lstat(found, &st))
929 goto cont; /* hmm, remove in progress? */ 1045 goto cont; /* hmm, remove in progress? */
930 1046
1047# if ENABLE_PLATFORM_MINGW32
1048# if ENABLE_ASH_GLOB_OPTIONS
1049 if (state->sh_accept_glob && !state->sh_accept_glob(found))
1050 goto cont;
1051# endif
1052 if (type == FIND_EXE_ONLY && S_ISREG(st.st_mode) &&
1053 !(st.st_mode & S_IXUSR))
1054 goto cont;
1055# endif
1056
931 /* Save only name */ 1057 /* Save only name */
932 len = strlen(name_found); 1058 len = strlen(name_found);
933 found = xrealloc(found, len + 2); /* +2: for slash and NUL */ 1059 found = xrealloc(found, len + 2); /* +2: for slash and NUL */
@@ -946,7 +1072,7 @@ static NOINLINE unsigned complete_cmd_dir_file(const char *command, int type)
946 goto cont; 1072 goto cont;
947 } 1073 }
948 /* add it to the list */ 1074 /* add it to the list */
949 add_match(found); 1075 add_match(found, FALSE);
950 continue; 1076 continue;
951 cont: 1077 cont:
952 free(found); 1078 free(found);
@@ -1011,7 +1137,13 @@ static NOINLINE int build_match_prefix(char *match_buf)
1011 1137
1012 /* Mark every \c as "quoted c" */ 1138 /* Mark every \c as "quoted c" */
1013 for (i = 0; int_buf[i]; i++) { 1139 for (i = 0; int_buf[i]; i++) {
1140#if ENABLE_PLATFORM_MINGW32
1141 /* Trailing backslash is effectively removed which confuses
1142 * the code to display case-preserved filenames. */
1143 if (int_buf[i] == '\\' && int_buf[i+1] != '\0') {
1144#else
1014 if (int_buf[i] == '\\') { 1145 if (int_buf[i] == '\\') {
1146#endif
1015 remove_chunk(int_buf, i, i + 1); 1147 remove_chunk(int_buf, i, i + 1);
1016 int_buf[i] |= QUOT; 1148 int_buf[i] |= QUOT;
1017 } 1149 }
@@ -1213,6 +1345,25 @@ static NOINLINE void input_tab(smallint *lastWasTab)
1213 size_t len_found; 1345 size_t len_found;
1214 /* Length of string used for matching */ 1346 /* Length of string used for matching */
1215 unsigned match_pfx_len = match_pfx_len; 1347 unsigned match_pfx_len = match_pfx_len;
1348# if ENABLE_PLATFORM_MINGW32
1349 int chosen_index = 0;
1350 int chosen_sens = FALSE;
1351# if !ENABLE_UNICODE_SUPPORT
1352 /*
1353 * FIXME: the next three vars are unused with ENABLE_UNICODE_SUPPORT
1354 * because the mingw code which uses them to update a tab-completion
1355 * prefix to the correct case (e.g. ~/desk<tab> to ~/Desktop/) is
1356 * not compiled, and so e.g. ~/desk<tab> completes to ~/desktop/ .
1357 */
1358 unsigned orig_pfx_len;
1359 char *target;
1360 const char *source;
1361# endif
1362# define first_match 0
1363# else
1364# define chosen_index 0
1365# define first_match 1
1366# endif
1216 int find_type; 1367 int find_type;
1217# if ENABLE_UNICODE_SUPPORT 1368# if ENABLE_UNICODE_SUPPORT
1218 /* cursor pos in command converted to multibyte form */ 1369 /* cursor pos in command converted to multibyte form */
@@ -1260,7 +1411,7 @@ static NOINLINE void input_tab(smallint *lastWasTab)
1260 /* Free up any memory already allocated */ 1411 /* Free up any memory already allocated */
1261 free_tab_completion_data(); 1412 free_tab_completion_data();
1262 1413
1263# if ENABLE_FEATURE_USERNAME_COMPLETION 1414# if ENABLE_FEATURE_USERNAME_COMPLETION && !ENABLE_PLATFORM_MINGW32
1264 /* If the word starts with ~ and there is no slash in the word, 1415 /* If the word starts with ~ and there is no slash in the word,
1265 * then try completing this word as a username. */ 1416 * then try completing this word as a username. */
1266 if (state->flags & USERNAME_COMPLETION) 1417 if (state->flags & USERNAME_COMPLETION)
@@ -1277,6 +1428,9 @@ static NOINLINE void input_tab(smallint *lastWasTab)
1277 { 1428 {
1278 const char *e = match_buf + strlen(match_buf); 1429 const char *e = match_buf + strlen(match_buf);
1279 const char *s = e - match_pfx_len; 1430 const char *s = e - match_pfx_len;
1431# if ENABLE_PLATFORM_MINGW32 && !ENABLE_UNICODE_SUPPORT
1432 orig_pfx_len = match_pfx_len;
1433# endif
1280 while (s < e) 1434 while (s < e)
1281 if (is_special_char(*s++)) 1435 if (is_special_char(*s++))
1282 match_pfx_len++; 1436 match_pfx_len++;
@@ -1307,10 +1461,29 @@ static NOINLINE void input_tab(smallint *lastWasTab)
1307 if (!matches) 1461 if (!matches)
1308 goto ret; /* no matches at all */ 1462 goto ret; /* no matches at all */
1309 /* Find common prefix */ 1463 /* Find common prefix */
1310 chosen_match = xstrdup(matches[0]); 1464# if ENABLE_PLATFORM_MINGW32
1465 /* Any comparison involving a filename must be case-insensitive.
1466 * The chosen match should be case-sensitive, if possible */
1467 for (unsigned i = 0; i < num_matches; ++i) {
1468 if (is_case_sensitive(matches[i])) {
1469 chosen_index = i;
1470 chosen_sens = TRUE;
1471 break;
1472 }
1473 }
1474# endif
1475 chosen_match = xstrdup(matches[chosen_index]);
1311 for (cp = chosen_match; *cp; cp++) { 1476 for (cp = chosen_match; *cp; cp++) {
1312 unsigned n; 1477 unsigned n;
1313 for (n = 1; n < num_matches; n++) { 1478 for (n = first_match; n < num_matches; n++) {
1479# if ENABLE_PLATFORM_MINGW32
1480 if (!is_case_sensitive(matches[n]) || !chosen_sens) {
1481 if (tolower(matches[n][cp - chosen_match]) !=
1482 tolower(*cp)) {
1483 goto stop;
1484 }
1485 } else
1486# endif
1314 if (matches[n][cp - chosen_match] != *cp) { 1487 if (matches[n][cp - chosen_match] != *cp) {
1315 goto stop; 1488 goto stop;
1316 } 1489 }
@@ -1347,7 +1520,21 @@ static NOINLINE void input_tab(smallint *lastWasTab)
1347 /* save tail */ 1520 /* save tail */
1348 strcpy(match_buf, &command_ps[cursor]); 1521 strcpy(match_buf, &command_ps[cursor]);
1349 /* add match and tail */ 1522 /* add match and tail */
1523# if ENABLE_PLATFORM_MINGW32
1524 if (match_pfx_len == orig_pfx_len) {
1525 /* replace match prefix to allow for altered case */
1526 target = &command_ps[cursor-match_pfx_len];
1527 source = chosen_match;
1528 }
1529 else {
1530 /* only replace tail of match if special characters are quoted */
1531 target = &command_ps[cursor];
1532 source = chosen_match + match_pfx_len;
1533 }
1534 strcpy(stpcpy(target, source), match_buf);
1535# else
1350 sprintf(&command_ps[cursor], "%s%s", chosen_match + match_pfx_len, match_buf); 1536 sprintf(&command_ps[cursor], "%s%s", chosen_match + match_pfx_len, match_buf);
1537# endif
1351 command_len = strlen(command_ps); 1538 command_len = strlen(command_ps);
1352 /* new pos */ 1539 /* new pos */
1353 pos = cursor + len_found - match_pfx_len; 1540 pos = cursor + len_found - match_pfx_len;
@@ -1383,7 +1570,6 @@ static NOINLINE void input_tab(smallint *lastWasTab)
1383 free(chosen_match); 1570 free(chosen_match);
1384 free(match_buf); 1571 free(match_buf);
1385} 1572}
1386
1387#endif /* FEATURE_TAB_COMPLETION */ 1573#endif /* FEATURE_TAB_COMPLETION */
1388 1574
1389 1575
@@ -1403,7 +1589,11 @@ line_input_t* FAST_FUNC new_line_input_t(int flags)
1403 1589
1404unsigned FAST_FUNC size_from_HISTFILESIZE(const char *hp) 1590unsigned FAST_FUNC size_from_HISTFILESIZE(const char *hp)
1405{ 1591{
1592# if ENABLE_PLATFORM_MINGW32 && DEFAULT_HISTORY > 0 && DEFAULT_HISTORY <= MAX_HISTORY
1593 int size = DEFAULT_HISTORY;
1594# else
1406 int size = MAX_HISTORY; 1595 int size = MAX_HISTORY;
1596# endif
1407 if (hp) { 1597 if (hp) {
1408 size = atoi(hp); 1598 size = atoi(hp);
1409 if (size < 0) 1599 if (size < 0)
@@ -1564,7 +1754,7 @@ void FAST_FUNC save_history(line_input_t *st)
1564 FILE *fp; 1754 FILE *fp;
1565 1755
1566 /* bash compat: HISTFILE="" disables history saving */ 1756 /* bash compat: HISTFILE="" disables history saving */
1567 if (!st || !st->hist_file || !state->hist_file[0]) 1757 if (!st || !st->hist_file || !st->hist_file[0])
1568 return; 1758 return;
1569 if (st->cnt_history <= st->cnt_history_in_file) 1759 if (st->cnt_history <= st->cnt_history_in_file)
1570 return; /* no new entries were added */ 1760 return; /* no new entries were added */
@@ -2066,7 +2256,11 @@ static void parse_and_put_prompt(const char *prmt_ptr)
2066 char *after_home_user; 2256 char *after_home_user;
2067 2257
2068 /* /home/user[/something] -> ~[/something] */ 2258 /* /home/user[/something] -> ~[/something] */
2259#if !ENABLE_PLATFORM_MINGW32
2069 after_home_user = is_prefixed_with(cwd_buf, home); 2260 after_home_user = is_prefixed_with(cwd_buf, home);
2261#else
2262 after_home_user = is_prefixed_with_case(cwd_buf, home);
2263#endif
2070 if (after_home_user 2264 if (after_home_user
2071 && (*after_home_user == '/' || *after_home_user == '\0') 2265 && (*after_home_user == '/' || *after_home_user == '\0')
2072 ) { 2266 ) {
@@ -2496,7 +2690,11 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman
2496 n = get_termios_and_make_raw(STDIN_FILENO, &new_settings, &initial_settings, 0 2690 n = get_termios_and_make_raw(STDIN_FILENO, &new_settings, &initial_settings, 0
2497 | TERMIOS_CLEAR_ISIG /* turn off INTR (ctrl-C), QUIT, SUSP */ 2691 | TERMIOS_CLEAR_ISIG /* turn off INTR (ctrl-C), QUIT, SUSP */
2498 ); 2692 );
2693#if !ENABLE_PLATFORM_MINGW32
2499 if (n != 0 || (initial_settings.c_lflag & (ECHO|ICANON)) == ICANON) { 2694 if (n != 0 || (initial_settings.c_lflag & (ECHO|ICANON)) == ICANON) {
2695#else
2696 if (n != 0 || !isatty(0)) {
2697#endif
2500 /* Happens when e.g. stty -echo was run before. 2698 /* Happens when e.g. stty -echo was run before.
2501 * But if ICANON is not set, we don't come here. 2699 * But if ICANON is not set, we don't come here.
2502 * (example: interactive python ^Z-backgrounded, 2700 * (example: interactive python ^Z-backgrounded,
@@ -2506,8 +2704,12 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman
2506 fflush_all(); 2704 fflush_all();
2507 if (fgets(command, maxsize, stdin) == NULL) 2705 if (fgets(command, maxsize, stdin) == NULL)
2508 len = -1; /* EOF or error */ 2706 len = -1; /* EOF or error */
2509 else 2707 else {
2510 len = strlen(command); 2708 len = strlen(command);
2709#if ENABLE_PLATFORM_MINGW32
2710 len = remove_cr(command, len);
2711#endif
2712 }
2511 DEINIT_S(); 2713 DEINIT_S();
2512 return len; 2714 return len;
2513 } 2715 }
@@ -2589,6 +2791,11 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman
2589 } 2791 }
2590#endif 2792#endif
2591 ic = ic_raw = lineedit_read_key(read_key_buffer, timeout); 2793 ic = ic_raw = lineedit_read_key(read_key_buffer, timeout);
2794#if ENABLE_PLATFORM_MINGW32
2795 /* scroll to cursor position on any keypress */
2796 if (isatty(fileno(stdin)) && isatty(fileno(stdout)))
2797 move_cursor_row(0);
2798#endif
2592 2799
2593#if ENABLE_FEATURE_REVERSE_SEARCH 2800#if ENABLE_FEATURE_REVERSE_SEARCH
2594 again: 2801 again:
@@ -2650,6 +2857,17 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman
2650 input_tab(&lastWasTab); 2857 input_tab(&lastWasTab);
2651 break; 2858 break;
2652#endif 2859#endif
2860#if ENABLE_PLATFORM_MINGW32
2861 case CTRL('Z'):
2862 command_ps[command_len] = '\0';
2863 #if ENABLE_UNICODE_SUPPORT
2864 bs_to_slash_u(command_ps);
2865 #else
2866 bs_to_slash(command_ps);
2867 #endif
2868 redraw(cmdedit_y, 0);
2869 break;
2870#endif
2653 case CTRL('K'): 2871 case CTRL('K'):
2654 /* Control-k -- clear to end of line */ 2872 /* Control-k -- clear to end of line */
2655 command_ps[cursor] = BB_NUL; 2873 command_ps[cursor] = BB_NUL;
@@ -2904,6 +3122,10 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman
2904 && ic_raw == initial_settings.c_cc[VINTR] 3122 && ic_raw == initial_settings.c_cc[VINTR]
2905 ) { 3123 ) {
2906 /* Ctrl-C (usually) - stop gathering input */ 3124 /* Ctrl-C (usually) - stop gathering input */
3125#if ENABLE_PLATFORM_MINGW32
3126 if (state->flags & IGNORE_CTRL_C)
3127 break;
3128#endif
2907 command_len = 0; 3129 command_len = 0;
2908 break_out = -1; /* "do not append '\n'" */ 3130 break_out = -1; /* "do not append '\n'" */
2909 break; 3131 break;