diff options
Diffstat (limited to 'libbb')
| -rw-r--r-- | libbb/lineedit.c | 251 | ||||
| -rw-r--r-- | libbb/unicode.c | 2 |
2 files changed, 135 insertions, 118 deletions
diff --git a/libbb/lineedit.c b/libbb/lineedit.c index a9b790cf7..453e873ad 100644 --- a/libbb/lineedit.c +++ b/libbb/lineedit.c | |||
| @@ -156,7 +156,6 @@ struct lineedit_statics { | |||
| 156 | 156 | ||
| 157 | /* Formerly these were big buffers on stack: */ | 157 | /* Formerly these were big buffers on stack: */ |
| 158 | #if ENABLE_FEATURE_TAB_COMPLETION | 158 | #if ENABLE_FEATURE_TAB_COMPLETION |
| 159 | char exe_n_cwd_tab_completion__dirbuf[MAX_LINELEN]; | ||
| 160 | char input_tab__matchBuf[MAX_LINELEN]; | 159 | char input_tab__matchBuf[MAX_LINELEN]; |
| 161 | int16_t find_match__int_buf[MAX_LINELEN + 1]; /* need to have 9 bits at least */ | 160 | int16_t find_match__int_buf[MAX_LINELEN + 1]; /* need to have 9 bits at least */ |
| 162 | int16_t find_match__pos_buf[MAX_LINELEN + 1]; | 161 | int16_t find_match__pos_buf[MAX_LINELEN + 1]; |
| @@ -235,6 +234,8 @@ static unsigned save_string(char *dst, unsigned maxsize) | |||
| 235 | while (dstpos < maxsize) { | 234 | while (dstpos < maxsize) { |
| 236 | wchar_t wc; | 235 | wchar_t wc; |
| 237 | int n = srcpos; | 236 | int n = srcpos; |
| 237 | |||
| 238 | /* Convert up to 1st invalid byte (or up to end) */ | ||
| 238 | while ((wc = command_ps[srcpos]) != 0 | 239 | while ((wc = command_ps[srcpos]) != 0 |
| 239 | && !unicode_is_raw_byte(wc) | 240 | && !unicode_is_raw_byte(wc) |
| 240 | ) { | 241 | ) { |
| @@ -247,6 +248,7 @@ static unsigned save_string(char *dst, unsigned maxsize) | |||
| 247 | dstpos += n; | 248 | dstpos += n; |
| 248 | if (wc == 0) /* usually is */ | 249 | if (wc == 0) /* usually is */ |
| 249 | break; | 250 | break; |
| 251 | |||
| 250 | /* We do have invalid byte here! */ | 252 | /* We do have invalid byte here! */ |
| 251 | command_ps[srcpos] = wc; /* restore it */ | 253 | command_ps[srcpos] = wc; /* restore it */ |
| 252 | srcpos++; | 254 | srcpos++; |
| @@ -608,53 +610,56 @@ static void add_match(char *matched) | |||
| 608 | } | 610 | } |
| 609 | 611 | ||
| 610 | #if ENABLE_FEATURE_USERNAME_COMPLETION | 612 | #if ENABLE_FEATURE_USERNAME_COMPLETION |
| 611 | static void username_tab_completion(char *ud, char *with_shash_flg) | 613 | /* Replace "~user/..." with "/homedir/...". |
| 614 | * The parameter is malloced, free it or return it | ||
| 615 | * unchanged if no user is matched. | ||
| 616 | */ | ||
| 617 | static char *username_path_completion(char *ud) | ||
| 612 | { | 618 | { |
| 613 | struct passwd *entry; | 619 | struct passwd *entry; |
| 620 | char *tilde_name = ud; | ||
| 621 | char *home = NULL; | ||
| 622 | |||
| 623 | ud++; /* skip ~ */ | ||
| 624 | if (*ud == '/') { /* "~/..." */ | ||
| 625 | home = home_pwd_buf; | ||
| 626 | } else { | ||
| 627 | /* "~user/..." */ | ||
| 628 | ud = strchr(ud, '/'); | ||
| 629 | *ud = '\0'; /* "~user" */ | ||
| 630 | entry = getpwnam(tilde_name + 1); | ||
| 631 | *ud = '/'; /* restore "~user/..." */ | ||
| 632 | if (entry) | ||
| 633 | home = entry->pw_dir; | ||
| 634 | } | ||
| 635 | if (home) { | ||
| 636 | ud = concat_path_file(home, ud); | ||
| 637 | free(tilde_name); | ||
| 638 | tilde_name = ud; | ||
| 639 | } | ||
| 640 | return tilde_name; | ||
| 641 | } | ||
| 642 | |||
| 643 | /* ~use<tab> - find all users with this prefix */ | ||
| 644 | static NOINLINE void username_completion(const char *ud) | ||
| 645 | { | ||
| 646 | /* Using _r function to avoid pulling in static buffers */ | ||
| 647 | char line_buff[256]; | ||
| 648 | struct passwd pwd; | ||
| 649 | struct passwd *result; | ||
| 614 | int userlen; | 650 | int userlen; |
| 615 | 651 | ||
| 616 | ud++; /* ~user/... to user/... */ | 652 | ud++; /* skip ~ */ |
| 617 | userlen = strlen(ud); | 653 | userlen = strlen(ud); |
| 618 | 654 | ||
| 619 | if (with_shash_flg) { /* "~/..." or "~user/..." */ | 655 | setpwent(); |
| 620 | char *sav_ud = ud - 1; | 656 | while (!getpwent_r(&pwd, line_buff, sizeof(line_buff), &result)) { |
| 621 | char *home = NULL; | 657 | /* Null usernames should result in all users as possible completions. */ |
| 622 | 658 | if (/*!userlen || */ strncmp(ud, pwd.pw_name, userlen) == 0) { | |
| 623 | if (*ud == '/') { /* "~/..." */ | 659 | add_match(xasprintf("~%s/", pwd.pw_name)); |
| 624 | home = home_pwd_buf; | ||
| 625 | } else { | ||
| 626 | /* "~user/..." */ | ||
| 627 | char *temp; | ||
| 628 | temp = strchr(ud, '/'); | ||
| 629 | *temp = '\0'; /* ~user\0 */ | ||
| 630 | entry = getpwnam(ud); | ||
| 631 | *temp = '/'; /* restore ~user/... */ | ||
| 632 | ud = temp; | ||
| 633 | if (entry) | ||
| 634 | home = entry->pw_dir; | ||
| 635 | } | ||
| 636 | if (home) { | ||
| 637 | if ((userlen + strlen(home) + 1) < MAX_LINELEN) { | ||
| 638 | /* /home/user/... */ | ||
| 639 | sprintf(sav_ud, "%s%s", home, ud); | ||
| 640 | } | ||
| 641 | } | ||
| 642 | } else { | ||
| 643 | /* "~[^/]*" */ | ||
| 644 | /* Using _r function to avoid pulling in static buffers */ | ||
| 645 | char line_buff[256]; | ||
| 646 | struct passwd pwd; | ||
| 647 | struct passwd *result; | ||
| 648 | |||
| 649 | setpwent(); | ||
| 650 | while (!getpwent_r(&pwd, line_buff, sizeof(line_buff), &result)) { | ||
| 651 | /* Null usernames should result in all users as possible completions. */ | ||
| 652 | if (/*!userlen || */ strncmp(ud, pwd.pw_name, userlen) == 0) { | ||
| 653 | add_match(xasprintf("~%s/", pwd.pw_name)); | ||
| 654 | } | ||
| 655 | } | 660 | } |
| 656 | endpwent(); | ||
| 657 | } | 661 | } |
| 662 | endpwent(); | ||
| 658 | } | 663 | } |
| 659 | #endif /* FEATURE_COMMAND_USERNAME_COMPLETION */ | 664 | #endif /* FEATURE_COMMAND_USERNAME_COMPLETION */ |
| 660 | 665 | ||
| @@ -664,22 +669,19 @@ enum { | |||
| 664 | FIND_FILE_ONLY = 2, | 669 | FIND_FILE_ONLY = 2, |
| 665 | }; | 670 | }; |
| 666 | 671 | ||
| 667 | static int path_parse(char ***p, int flags) | 672 | static int path_parse(char ***p) |
| 668 | { | 673 | { |
| 669 | int npth; | 674 | int npth; |
| 670 | const char *pth; | 675 | const char *pth; |
| 671 | char *tmp; | 676 | char *tmp; |
| 672 | char **res; | 677 | char **res; |
| 673 | 678 | ||
| 674 | /* if not setenv PATH variable, to search cur dir "." */ | ||
| 675 | if (flags != FIND_EXE_ONLY) | ||
| 676 | return 1; | ||
| 677 | |||
| 678 | if (state->flags & WITH_PATH_LOOKUP) | 679 | if (state->flags & WITH_PATH_LOOKUP) |
| 679 | pth = state->path_lookup; | 680 | pth = state->path_lookup; |
| 680 | else | 681 | else |
| 681 | pth = getenv("PATH"); | 682 | pth = getenv("PATH"); |
| 682 | /* PATH=<empty> or PATH=:<empty> */ | 683 | |
| 684 | /* PATH="" or PATH=":"? */ | ||
| 683 | if (!pth || !pth[0] || LONE_CHAR(pth, ':')) | 685 | if (!pth || !pth[0] || LONE_CHAR(pth, ':')) |
| 684 | return 1; | 686 | return 1; |
| 685 | 687 | ||
| @@ -689,12 +691,13 @@ static int path_parse(char ***p, int flags) | |||
| 689 | tmp = strchr(tmp, ':'); | 691 | tmp = strchr(tmp, ':'); |
| 690 | if (!tmp) | 692 | if (!tmp) |
| 691 | break; | 693 | break; |
| 692 | if (*++tmp == '\0') | 694 | tmp++; |
| 695 | if (*tmp == '\0') | ||
| 693 | break; /* :<empty> */ | 696 | break; /* :<empty> */ |
| 694 | npth++; | 697 | npth++; |
| 695 | } | 698 | } |
| 696 | 699 | ||
| 697 | res = xmalloc(npth * sizeof(char*)); | 700 | *p = res = xmalloc(npth * sizeof(res[0])); |
| 698 | res[0] = tmp = xstrdup(pth); | 701 | res[0] = tmp = xstrdup(pth); |
| 699 | npth = 1; | 702 | npth = 1; |
| 700 | while (1) { | 703 | while (1) { |
| @@ -706,100 +709,96 @@ static int path_parse(char ***p, int flags) | |||
| 706 | break; /* :<empty> */ | 709 | break; /* :<empty> */ |
| 707 | res[npth++] = tmp; | 710 | res[npth++] = tmp; |
| 708 | } | 711 | } |
| 709 | *p = res; | ||
| 710 | return npth; | 712 | return npth; |
| 711 | } | 713 | } |
| 712 | 714 | ||
| 713 | static void exe_n_cwd_tab_completion(char *command, int type) | 715 | static void exe_n_cwd_tab_completion(char *command, int type) |
| 714 | { | 716 | { |
| 715 | DIR *dir; | ||
| 716 | struct dirent *next; | ||
| 717 | struct stat st; | ||
| 718 | char *path1[1]; | 717 | char *path1[1]; |
| 719 | char **paths = path1; | 718 | char **paths = path1; |
| 720 | int npaths; | 719 | int npaths; |
| 721 | int i; | 720 | int i; |
| 722 | char *found; | 721 | char *pfind; |
| 723 | char *pfind = strrchr(command, '/'); | 722 | char *dirbuf = NULL; |
| 724 | /* char dirbuf[MAX_LINELEN]; */ | ||
| 725 | #define dirbuf (S.exe_n_cwd_tab_completion__dirbuf) | ||
| 726 | 723 | ||
| 727 | npaths = 1; | 724 | npaths = 1; |
| 728 | path1[0] = (char*)"."; | 725 | path1[0] = (char*)"."; |
| 729 | 726 | ||
| 730 | if (pfind == NULL) { | 727 | pfind = strrchr(command, '/'); |
| 731 | /* no dir, if flags==EXE_ONLY - get paths, else "." */ | 728 | if (!pfind) { |
| 732 | npaths = path_parse(&paths, type); | 729 | if (type == FIND_EXE_ONLY) |
| 730 | npaths = path_parse(&paths); | ||
| 733 | pfind = command; | 731 | pfind = command; |
| 734 | } else { | 732 | } else { |
| 733 | /* point to 'l' in "..../last_component" */ | ||
| 734 | pfind++; | ||
| 735 | /* dirbuf = ".../.../.../" */ | 735 | /* dirbuf = ".../.../.../" */ |
| 736 | safe_strncpy(dirbuf, command, (pfind - command) + 2); | 736 | dirbuf = xstrndup(command, pfind - command); |
| 737 | #if ENABLE_FEATURE_USERNAME_COMPLETION | 737 | #if ENABLE_FEATURE_USERNAME_COMPLETION |
| 738 | if (dirbuf[0] == '~') /* ~/... or ~user/... */ | 738 | if (dirbuf[0] == '~') /* ~/... or ~user/... */ |
| 739 | username_tab_completion(dirbuf, dirbuf); | 739 | dirbuf = username_path_completion(dirbuf); |
| 740 | #endif | 740 | #endif |
| 741 | paths[0] = dirbuf; | 741 | path1[0] = dirbuf; |
| 742 | /* point to 'l' in "..../last_component" */ | ||
| 743 | pfind++; | ||
| 744 | } | 742 | } |
| 745 | 743 | ||
| 746 | for (i = 0; i < npaths; i++) { | 744 | for (i = 0; i < npaths; i++) { |
| 745 | DIR *dir; | ||
| 746 | struct dirent *next; | ||
| 747 | struct stat st; | ||
| 748 | char *found; | ||
| 749 | |||
| 747 | dir = opendir(paths[i]); | 750 | dir = opendir(paths[i]); |
| 748 | if (!dir) | 751 | if (!dir) |
| 749 | continue; /* don't print an error */ | 752 | continue; /* don't print an error */ |
| 750 | 753 | ||
| 751 | while ((next = readdir(dir)) != NULL) { | 754 | while ((next = readdir(dir)) != NULL) { |
| 752 | int len1; | 755 | const char *name_found = next->d_name; |
| 753 | const char *str_found = next->d_name; | ||
| 754 | 756 | ||
| 755 | /* matched? */ | 757 | /* .../<tab>: bash 3.2.0 shows dotfiles, but not . and .. */ |
| 756 | if (strncmp(str_found, pfind, strlen(pfind))) | 758 | if (!pfind[0] && DOT_OR_DOTDOT(name_found)) |
| 757 | continue; | 759 | continue; |
| 758 | /* not see .name without .match */ | 760 | /* match? */ |
| 759 | if (*str_found == '.' && *pfind == '\0') { | 761 | if (strncmp(name_found, pfind, strlen(pfind)) != 0) |
| 760 | if (NOT_LONE_CHAR(paths[i], '/') || str_found[1]) | 762 | continue; /* no */ |
| 761 | continue; | 763 | |
| 762 | str_found = ""; /* only "/" */ | 764 | found = concat_path_file(paths[i], name_found); |
| 763 | } | ||
| 764 | found = concat_path_file(paths[i], str_found); | ||
| 765 | /* hmm, remove in progress? */ | ||
| 766 | /* NB: stat() first so that we see is it a directory; | 765 | /* NB: stat() first so that we see is it a directory; |
| 767 | * but if that fails, use lstat() so that | 766 | * but if that fails, use lstat() so that |
| 768 | * we still match dangling links */ | 767 | * we still match dangling links */ |
| 769 | if (stat(found, &st) && lstat(found, &st)) | 768 | if (stat(found, &st) && lstat(found, &st)) |
| 770 | goto cont; | 769 | goto cont; /* hmm, remove in progress? */ |
| 771 | /* find with dirs? */ | ||
| 772 | if (paths[i] != dirbuf) | ||
| 773 | strcpy(found, next->d_name); /* only name */ | ||
| 774 | 770 | ||
| 775 | len1 = strlen(found); | 771 | /* save only name if we scan PATH */ |
| 776 | found = xrealloc(found, len1 + 2); | 772 | if (paths[i] != dirbuf) |
| 777 | found[len1] = '\0'; | 773 | strcpy(found, name_found); |
| 778 | found[len1+1] = '\0'; | ||
| 779 | 774 | ||
| 780 | if (S_ISDIR(st.st_mode)) { | 775 | if (S_ISDIR(st.st_mode)) { |
| 776 | unsigned len1 = strlen(found); | ||
| 781 | /* name is a directory */ | 777 | /* name is a directory */ |
| 782 | if (found[len1-1] != '/') { | 778 | if (found[len1-1] != '/') { |
| 779 | found = xrealloc(found, len1 + 2); | ||
| 783 | found[len1] = '/'; | 780 | found[len1] = '/'; |
| 781 | found[len1 + 1] = '\0'; | ||
| 784 | } | 782 | } |
| 785 | } else { | 783 | } else { |
| 786 | /* not put found file if search only dirs for cd */ | 784 | /* skip files if looking for dirs only (example: cd) */ |
| 787 | if (type == FIND_DIR_ONLY) | 785 | if (type == FIND_DIR_ONLY) |
| 788 | goto cont; | 786 | goto cont; |
| 789 | } | 787 | } |
| 790 | /* Add it to the list */ | 788 | /* add it to the list */ |
| 791 | add_match(found); | 789 | add_match(found); |
| 792 | continue; | 790 | continue; |
| 793 | cont: | 791 | cont: |
| 794 | free(found); | 792 | free(found); |
| 795 | } | 793 | } |
| 796 | closedir(dir); | 794 | closedir(dir); |
| 797 | } | 795 | } /* for every path */ |
| 796 | |||
| 798 | if (paths != path1) { | 797 | if (paths != path1) { |
| 799 | free(paths[0]); /* allocated memory is only in first member */ | 798 | free(paths[0]); /* allocated memory is only in first member */ |
| 800 | free(paths); | 799 | free(paths); |
| 801 | } | 800 | } |
| 802 | #undef dirbuf | 801 | free(dirbuf); |
| 803 | } | 802 | } |
| 804 | 803 | ||
| 805 | /* QUOT is used on elements of int_buf[], which are bytes, | 804 | /* QUOT is used on elements of int_buf[], which are bytes, |
| @@ -812,15 +811,20 @@ static void exe_n_cwd_tab_completion(char *command, int type) | |||
| 812 | /* is must be <= in */ | 811 | /* is must be <= in */ |
| 813 | static void collapse_pos(int is, int in) | 812 | static void collapse_pos(int is, int in) |
| 814 | { | 813 | { |
| 815 | memmove(int_buf+is, int_buf+in, (MAX_LINELEN+1-in)*sizeof(int_buf[0])); | 814 | memmove(int_buf+is, int_buf+in, (MAX_LINELEN+1-in) * sizeof(int_buf[0])); |
| 816 | memmove(pos_buf+is, pos_buf+in, (MAX_LINELEN+1-in)*sizeof(pos_buf[0])); | 815 | memmove(pos_buf+is, pos_buf+in, (MAX_LINELEN+1-in) * sizeof(pos_buf[0])); |
| 817 | } | 816 | } |
| 818 | static NOINLINE int find_match(char *matchBuf, int *len_with_quotes) | 817 | /* On entry, matchBuf contains everything up to cursor at the moment <tab> |
| 818 | * was pressed. This function looks at it, figures out what part of it | ||
| 819 | * constitutes the command/file/directory prefix to use for completion, | ||
| 820 | * and rewrites matchBuf to contain only that part. | ||
| 821 | */ | ||
| 822 | static NOINLINE int build_match_prefix(char *matchBuf, int *len_with_quotes) | ||
| 819 | { | 823 | { |
| 820 | int i, j; | 824 | int i, j; |
| 821 | int command_mode; | 825 | int command_mode; |
| 822 | int c, c2; | 826 | int c, c2; |
| 823 | /* Were local, but it uses too much stack */ | 827 | /* Were local, but it used too much stack */ |
| 824 | /* int16_t int_buf[MAX_LINELEN + 1]; */ | 828 | /* int16_t int_buf[MAX_LINELEN + 1]; */ |
| 825 | /* int16_t pos_buf[MAX_LINELEN + 1]; */ | 829 | /* int16_t pos_buf[MAX_LINELEN + 1]; */ |
| 826 | 830 | ||
| @@ -860,22 +864,23 @@ static NOINLINE int find_match(char *matchBuf, int *len_with_quotes) | |||
| 860 | } | 864 | } |
| 861 | 865 | ||
| 862 | /* skip commands with arguments if line has commands delimiters */ | 866 | /* skip commands with arguments if line has commands delimiters */ |
| 863 | /* ';' ';;' '&' '|' '&&' '||' but `>&' `<&' `>|' */ | 867 | /* ';' ';;' '&' '|' '&&' '||' but '>&' '<&' '>|' */ |
| 864 | for (i = 0; int_buf[i]; i++) { | 868 | for (i = 0; int_buf[i]; i++) { |
| 869 | int n; | ||
| 865 | c = int_buf[i]; | 870 | c = int_buf[i]; |
| 866 | c2 = int_buf[i + 1]; | 871 | c2 = int_buf[i + 1]; |
| 867 | j = i ? int_buf[i - 1] : -1; | 872 | j = i ? int_buf[i - 1] : -1; |
| 868 | command_mode = 0; | 873 | n = 0; |
| 869 | if (c == ';' || c == '&' || c == '|') { | 874 | if (c == ';' || c == '&' || c == '|') { |
| 870 | command_mode = 1 + (c == c2); | 875 | n = 1 + (c == c2); |
| 871 | if (c == '&') { | 876 | if (c == '&') { |
| 872 | if (j == '>' || j == '<') | 877 | if (j == '>' || j == '<') |
| 873 | command_mode = 0; | 878 | n = 0; |
| 874 | } else if (c == '|' && j == '>') | 879 | } else if (c == '|' && j == '>') |
| 875 | command_mode = 0; | 880 | n = 0; |
| 876 | } | 881 | } |
| 877 | if (command_mode) { | 882 | if (n) { |
| 878 | collapse_pos(0, i + command_mode); | 883 | collapse_pos(0, i + n); |
| 879 | i = -1; /* hack incremet */ | 884 | i = -1; /* hack incremet */ |
| 880 | } | 885 | } |
| 881 | } | 886 | } |
| @@ -943,8 +948,8 @@ static NOINLINE int find_match(char *matchBuf, int *len_with_quotes) | |||
| 943 | } | 948 | } |
| 944 | } | 949 | } |
| 945 | } | 950 | } |
| 946 | for (i = 0; int_buf[i]; i++) | 951 | for (i = 0; int_buf[i]; i++) /* quasi-strlen(int_buf) */ |
| 947 | /* "strlen" */; | 952 | continue; |
| 948 | /* find last word */ | 953 | /* find last word */ |
| 949 | for (--i; i >= 0; i--) { | 954 | for (--i; i >= 0; i--) { |
| 950 | c = int_buf[i]; | 955 | c = int_buf[i]; |
| @@ -955,7 +960,7 @@ static NOINLINE int find_match(char *matchBuf, int *len_with_quotes) | |||
| 955 | } | 960 | } |
| 956 | /* skip first not quoted '\'' or '"' */ | 961 | /* skip first not quoted '\'' or '"' */ |
| 957 | for (i = 0; int_buf[i] == '\'' || int_buf[i] == '"'; i++) | 962 | for (i = 0; int_buf[i] == '\'' || int_buf[i] == '"'; i++) |
| 958 | /*skip*/; | 963 | continue; |
| 959 | /* collapse quote or unquote // or /~ */ | 964 | /* collapse quote or unquote // or /~ */ |
| 960 | while ((int_buf[i] & ~QUOT) == '/' | 965 | while ((int_buf[i] & ~QUOT) == '/' |
| 961 | && ((int_buf[i+1] & ~QUOT) == '/' || (int_buf[i+1] & ~QUOT) == '~') | 966 | && ((int_buf[i+1] & ~QUOT) == '/' || (int_buf[i+1] & ~QUOT) == '~') |
| @@ -1058,13 +1063,20 @@ static void input_tab(smallint *lastWasTab) | |||
| 1058 | 1063 | ||
| 1059 | /* Make a local copy of the string -- | 1064 | /* Make a local copy of the string -- |
| 1060 | * up to the position of the cursor */ | 1065 | * up to the position of the cursor */ |
| 1066 | #if !ENABLE_UNICODE_SUPPORT | ||
| 1061 | save_string(matchBuf, cursor + 1); | 1067 | save_string(matchBuf, cursor + 1); |
| 1062 | #if ENABLE_UNICODE_SUPPORT | 1068 | #else |
| 1063 | cursor_mb = strlen(matchBuf); | 1069 | { |
| 1070 | CHAR_T wc = command_ps[cursor]; | ||
| 1071 | command_ps[cursor] = 0; | ||
| 1072 | save_string(matchBuf, MAX_LINELEN); | ||
| 1073 | command_ps[cursor] = wc; | ||
| 1074 | cursor_mb = strlen(matchBuf); | ||
| 1075 | } | ||
| 1064 | #endif | 1076 | #endif |
| 1065 | tmp = matchBuf; | 1077 | tmp = matchBuf; |
| 1066 | 1078 | ||
| 1067 | find_type = find_match(matchBuf, &recalc_pos); | 1079 | find_type = build_match_prefix(matchBuf, &recalc_pos); |
| 1068 | 1080 | ||
| 1069 | /* Free up any memory already allocated */ | 1081 | /* Free up any memory already allocated */ |
| 1070 | free_tab_completion_data(); | 1082 | free_tab_completion_data(); |
| @@ -1074,7 +1086,7 @@ static void input_tab(smallint *lastWasTab) | |||
| 1074 | * then try completing this word as a username. */ | 1086 | * then try completing this word as a username. */ |
| 1075 | if (state->flags & USERNAME_COMPLETION) | 1087 | if (state->flags & USERNAME_COMPLETION) |
| 1076 | if (matchBuf[0] == '~' && strchr(matchBuf, '/') == NULL) | 1088 | if (matchBuf[0] == '~' && strchr(matchBuf, '/') == NULL) |
| 1077 | username_tab_completion(matchBuf, NULL); | 1089 | username_completion(matchBuf); |
| 1078 | #endif | 1090 | #endif |
| 1079 | /* Try to match any executable in our path and everything | 1091 | /* Try to match any executable in our path and everything |
| 1080 | * in the current working directory */ | 1092 | * in the current working directory */ |
| @@ -1083,7 +1095,7 @@ static void input_tab(smallint *lastWasTab) | |||
| 1083 | /* Sort, then remove any duplicates found */ | 1095 | /* Sort, then remove any duplicates found */ |
| 1084 | if (matches) { | 1096 | if (matches) { |
| 1085 | unsigned i; | 1097 | unsigned i; |
| 1086 | int n = 0; | 1098 | unsigned n = 0; |
| 1087 | qsort_string_vector(matches, num_matches); | 1099 | qsort_string_vector(matches, num_matches); |
| 1088 | for (i = 0; i < num_matches - 1; ++i) { | 1100 | for (i = 0; i < num_matches - 1; ++i) { |
| 1089 | if (matches[i] && matches[i+1]) { /* paranoia */ | 1101 | if (matches[i] && matches[i+1]) { /* paranoia */ |
| @@ -1095,14 +1107,14 @@ static void input_tab(smallint *lastWasTab) | |||
| 1095 | } | 1107 | } |
| 1096 | } | 1108 | } |
| 1097 | } | 1109 | } |
| 1098 | matches[n] = matches[i]; | 1110 | matches[n++] = matches[i]; |
| 1099 | num_matches = n + 1; | 1111 | num_matches = n; |
| 1100 | } | 1112 | } |
| 1101 | /* Did we find exactly one match? */ | 1113 | /* Did we find exactly one match? */ |
| 1102 | if (!matches || num_matches > 1) { /* no */ | 1114 | if (num_matches != 1) { /* no */ |
| 1103 | beep(); | 1115 | beep(); |
| 1104 | if (!matches) | 1116 | if (!matches) |
| 1105 | return; /* not found */ | 1117 | return; /* no matches at all */ |
| 1106 | /* find minimal match */ | 1118 | /* find minimal match */ |
| 1107 | tmp1 = xstrdup(matches[0]); | 1119 | tmp1 = xstrdup(matches[0]); |
| 1108 | for (tmp = tmp1; *tmp; tmp++) { | 1120 | for (tmp = tmp1; *tmp; tmp++) { |
| @@ -1113,13 +1125,14 @@ static void input_tab(smallint *lastWasTab) | |||
| 1113 | } | 1125 | } |
| 1114 | } | 1126 | } |
| 1115 | } | 1127 | } |
| 1116 | if (*tmp1 == '\0') { /* have unique */ | 1128 | if (*tmp1 == '\0') { /* have unique pfx? */ |
| 1117 | free(tmp1); | 1129 | free(tmp1); /* no */ |
| 1118 | return; | 1130 | return; |
| 1119 | } | 1131 | } |
| 1120 | tmp = add_quote_for_spec_chars(tmp1); | 1132 | tmp = add_quote_for_spec_chars(tmp1); |
| 1121 | free(tmp1); | 1133 | free(tmp1); |
| 1122 | } else { /* one match */ | 1134 | len_found = strlen(tmp); |
| 1135 | } else { /* exactly one match */ | ||
| 1123 | tmp = add_quote_for_spec_chars(matches[0]); | 1136 | tmp = add_quote_for_spec_chars(matches[0]); |
| 1124 | /* for next completion current found */ | 1137 | /* for next completion current found */ |
| 1125 | *lastWasTab = FALSE; | 1138 | *lastWasTab = FALSE; |
| @@ -1127,11 +1140,10 @@ static void input_tab(smallint *lastWasTab) | |||
| 1127 | len_found = strlen(tmp); | 1140 | len_found = strlen(tmp); |
| 1128 | if (tmp[len_found-1] != '/') { | 1141 | if (tmp[len_found-1] != '/') { |
| 1129 | tmp[len_found] = ' '; | 1142 | tmp[len_found] = ' '; |
| 1130 | tmp[len_found+1] = '\0'; | 1143 | tmp[++len_found] = '\0'; |
| 1131 | } | 1144 | } |
| 1132 | } | 1145 | } |
| 1133 | 1146 | ||
| 1134 | len_found = strlen(tmp); | ||
| 1135 | #if !ENABLE_UNICODE_SUPPORT | 1147 | #if !ENABLE_UNICODE_SUPPORT |
| 1136 | /* have space to place the match? */ | 1148 | /* have space to place the match? */ |
| 1137 | /* The result consists of three parts with these lengths: */ | 1149 | /* The result consists of three parts with these lengths: */ |
| @@ -1164,7 +1176,10 @@ static void input_tab(smallint *lastWasTab) | |||
| 1164 | sprintf(&command[cursor_mb - recalc_pos], "%s%s", tmp, matchBuf); | 1176 | sprintf(&command[cursor_mb - recalc_pos], "%s%s", tmp, matchBuf); |
| 1165 | command_len = load_string(command, S.maxsize); | 1177 | command_len = load_string(command, S.maxsize); |
| 1166 | /* write out the matched command */ | 1178 | /* write out the matched command */ |
| 1167 | redraw(cmdedit_y, command_len - len); | 1179 | /* paranoia: load_string can return 0 on conv error, |
| 1180 | * prevent passing len = (0 - 12) to redraw */ | ||
| 1181 | len = command_len - len; | ||
| 1182 | redraw(cmdedit_y, len >= 0 ? len : 0); | ||
| 1168 | } | 1183 | } |
| 1169 | } | 1184 | } |
| 1170 | #endif | 1185 | #endif |
| @@ -2297,6 +2312,8 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li | |||
| 2297 | * or exit if len=0 and no chars to delete */ | 2312 | * or exit if len=0 and no chars to delete */ |
| 2298 | if (command_len == 0) { | 2313 | if (command_len == 0) { |
| 2299 | errno = 0; | 2314 | errno = 0; |
| 2315 | |||
| 2316 | case -1: /* error (e.g. EIO when tty is destroyed) */ | ||
| 2300 | #if ENABLE_FEATURE_EDITING_VI | 2317 | #if ENABLE_FEATURE_EDITING_VI |
| 2301 | prepare_to_die: | 2318 | prepare_to_die: |
| 2302 | #endif | 2319 | #endif |
diff --git a/libbb/unicode.c b/libbb/unicode.c index d6fcf7a43..5a657b2d7 100644 --- a/libbb/unicode.c +++ b/libbb/unicode.c | |||
| @@ -131,7 +131,7 @@ size_t FAST_FUNC wcstombs(char *dest, const wchar_t *src, size_t n) | |||
| 131 | size_t len = wcrtomb_internal(tbuf, wc); | 131 | size_t len = wcrtomb_internal(tbuf, wc); |
| 132 | 132 | ||
| 133 | if (len > n) | 133 | if (len > n) |
| 134 | len = n; | 134 | break; |
| 135 | memcpy(dest, tbuf, len); | 135 | memcpy(dest, tbuf, len); |
| 136 | if (wc == L'\0') | 136 | if (wc == L'\0') |
| 137 | return org_n - n; | 137 | return org_n - n; |
