diff options
author | Denys Vlasenko <dvlasenk@redhat.com> | 2010-09-03 12:53:15 +0200 |
---|---|---|
committer | Denys Vlasenko <dvlasenk@redhat.com> | 2010-09-03 12:53:15 +0200 |
commit | 2679e3c8cccbf3ae4cac8e735e5430ebbe714b00 (patch) | |
tree | 343c83fc6ab474c5e0b352218326075cf1b994b8 /libbb | |
parent | 57ea9b488b096e17418a808d20f263daea468974 (diff) | |
download | busybox-w32-2679e3c8cccbf3ae4cac8e735e5430ebbe714b00.tar.gz busybox-w32-2679e3c8cccbf3ae4cac8e735e5430ebbe714b00.tar.bz2 busybox-w32-2679e3c8cccbf3ae4cac8e735e5430ebbe714b00.zip |
lineedit: clean up tab completion code (variable reuse, comments)
Noted bugs in behavior.
Added debugging machinery.
Decoupled variables reused for unrelated purposes: apparently,
when not forced to use liveness analysis, gcc fares better.
function old new delta
complete_cmd_dir_file 699 705 +6
collapse_pos 75 79 +4
build_match_prefix 892 838 -54
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 2/1 up/down: 10/-54) Total: -44 bytes
Signed-off-by: Denys Vlasenko <dvlasenk@redhat.com>
Diffstat (limited to 'libbb')
-rw-r--r-- | libbb/lineedit.c | 154 |
1 files changed, 85 insertions, 69 deletions
diff --git a/libbb/lineedit.c b/libbb/lineedit.c index 7bb709f9d..dd9d85b28 100644 --- a/libbb/lineedit.c +++ b/libbb/lineedit.c | |||
@@ -716,6 +716,7 @@ static NOINLINE void complete_cmd_dir_file(char *command, int type) | |||
716 | char **paths = path1; | 716 | char **paths = path1; |
717 | int npaths; | 717 | int npaths; |
718 | int i; | 718 | int i; |
719 | unsigned pf_len; | ||
719 | char *pfind; | 720 | char *pfind; |
720 | char *dirbuf = NULL; | 721 | char *dirbuf = NULL; |
721 | 722 | ||
@@ -738,6 +739,7 @@ static NOINLINE void complete_cmd_dir_file(char *command, int type) | |||
738 | #endif | 739 | #endif |
739 | path1[0] = dirbuf; | 740 | path1[0] = dirbuf; |
740 | } | 741 | } |
742 | pf_len = strlen(pfind); | ||
741 | 743 | ||
742 | for (i = 0; i < npaths; i++) { | 744 | for (i = 0; i < npaths; i++) { |
743 | DIR *dir; | 745 | DIR *dir; |
@@ -756,7 +758,7 @@ static NOINLINE void complete_cmd_dir_file(char *command, int type) | |||
756 | if (!pfind[0] && DOT_OR_DOTDOT(name_found)) | 758 | if (!pfind[0] && DOT_OR_DOTDOT(name_found)) |
757 | continue; | 759 | continue; |
758 | /* match? */ | 760 | /* match? */ |
759 | if (strncmp(name_found, pfind, strlen(pfind)) != 0) | 761 | if (strncmp(name_found, pfind, pf_len) != 0) |
760 | continue; /* no */ | 762 | continue; /* no */ |
761 | 763 | ||
762 | found = concat_path_file(paths[i], name_found); | 764 | found = concat_path_file(paths[i], name_found); |
@@ -812,21 +814,31 @@ static NOINLINE void complete_cmd_dir_file(char *command, int type) | |||
812 | #define QUOT (UCHAR_MAX+1) | 814 | #define QUOT (UCHAR_MAX+1) |
813 | #define int_buf (S.find_match__int_buf) | 815 | #define int_buf (S.find_match__int_buf) |
814 | #define pos_buf (S.find_match__pos_buf) | 816 | #define pos_buf (S.find_match__pos_buf) |
817 | #define dbg_bmp 0 | ||
815 | static void collapse_pos(int beg, int end) | 818 | static void collapse_pos(int beg, int end) |
816 | { | 819 | { |
817 | /* beg must be <= end */ | 820 | /* beg must be <= end */ |
821 | if (beg == end) | ||
822 | return; | ||
818 | memmove(int_buf+beg, int_buf+end, (MAX_LINELEN+1-end) * sizeof(int_buf[0])); | 823 | memmove(int_buf+beg, int_buf+end, (MAX_LINELEN+1-end) * sizeof(int_buf[0])); |
819 | memmove(pos_buf+beg, pos_buf+end, (MAX_LINELEN+1-end) * sizeof(pos_buf[0])); | 824 | memmove(pos_buf+beg, pos_buf+end, (MAX_LINELEN+1-end) * sizeof(pos_buf[0])); |
825 | if (dbg_bmp) { | ||
826 | int i; | ||
827 | for (i = 0; int_buf[i]; i++) | ||
828 | bb_putchar((unsigned char)int_buf[i]); | ||
829 | bb_putchar('\n'); | ||
830 | } | ||
820 | } | 831 | } |
821 | static NOINLINE int build_match_prefix(char *matchBuf, int *len_with_quotes) | 832 | static NOINLINE int build_match_prefix(char *matchBuf, int *len_with_quotes) |
822 | { | 833 | { |
823 | int i, j; | 834 | int i, j; |
824 | int command_mode; | 835 | int command_mode; |
825 | int c, c2; | ||
826 | /* Were local, but it used too much stack */ | 836 | /* Were local, but it used too much stack */ |
827 | /* int16_t int_buf[MAX_LINELEN + 1]; */ | 837 | /* int16_t int_buf[MAX_LINELEN + 1]; */ |
828 | /* int16_t pos_buf[MAX_LINELEN + 1]; */ | 838 | /* int16_t pos_buf[MAX_LINELEN + 1]; */ |
829 | 839 | ||
840 | if (dbg_bmp) printf("\n%s\n", matchBuf); | ||
841 | |||
830 | for (i = 0;; i++) { | 842 | for (i = 0;; i++) { |
831 | int_buf[i] = (unsigned char)matchBuf[i]; | 843 | int_buf[i] = (unsigned char)matchBuf[i]; |
832 | if (int_buf[i] == 0) { | 844 | if (int_buf[i] == 0) { |
@@ -845,20 +857,21 @@ static NOINLINE int build_match_prefix(char *matchBuf, int *len_with_quotes) | |||
845 | } | 857 | } |
846 | } | 858 | } |
847 | /* Quote-mark "chars" and 'chars' */ | 859 | /* Quote-mark "chars" and 'chars' */ |
848 | c2 = 0; | 860 | { |
849 | for (i = 0; int_buf[i]; i++) { | 861 | int in_quote = 0; |
850 | c = int_buf[i]; | 862 | for (i = 0; int_buf[i]; i++) { |
851 | if (c == '\'' || c == '"') { | 863 | int cur = int_buf[i]; |
852 | if (c2 == 0) | 864 | if (cur == '\'' || cur == '"') { |
853 | c2 = c; | 865 | if (!in_quote) |
854 | else { | 866 | in_quote = cur; |
855 | if (c == c2) | 867 | else if (cur == in_quote) |
856 | c2 = 0; | 868 | in_quote = 0; |
857 | else | 869 | else |
858 | int_buf[i] |= QUOT; | 870 | int_buf[i] |= QUOT; |
871 | } else if (in_quote && cur != '$') { | ||
872 | int_buf[i] |= QUOT; | ||
859 | } | 873 | } |
860 | } else if (c2 != 0 && c != '$') | 874 | } |
861 | int_buf[i] |= QUOT; | ||
862 | } | 875 | } |
863 | 876 | ||
864 | /* Remove everything up to command delimiters: | 877 | /* Remove everything up to command delimiters: |
@@ -866,64 +879,61 @@ static NOINLINE int build_match_prefix(char *matchBuf, int *len_with_quotes) | |||
866 | * but careful with '>&' '<&' '>|' | 879 | * but careful with '>&' '<&' '>|' |
867 | */ | 880 | */ |
868 | for (i = 0; int_buf[i]; i++) { | 881 | for (i = 0; int_buf[i]; i++) { |
869 | int n; | 882 | int cur = int_buf[i]; |
870 | c = int_buf[i]; | 883 | if (cur == ';' || cur == '&' || cur == '|') { |
871 | c2 = int_buf[i + 1]; | 884 | int prev = i ? int_buf[i - 1] : 0; |
872 | j = i ? int_buf[i - 1] : -1; | 885 | if (cur == '&' && (prev == '>' || prev == '<')) { |
873 | n = 0; | 886 | continue; |
874 | if (c == ';' || c == '&' || c == '|') { | 887 | } else if (cur == '|' && prev == '>') { |
875 | n = 1 + (c == c2); | 888 | continue; |
876 | if (c == '&') { | 889 | } |
877 | if (j == '>' || j == '<') | 890 | collapse_pos(0, i + 1 + (cur == int_buf[i + 1])); |
878 | n = 0; | 891 | i = -1; /* back to square 1 */ |
879 | } else if (c == '|' && j == '>') | ||
880 | n = 0; | ||
881 | } | ||
882 | if (n) { | ||
883 | collapse_pos(0, i + n); | ||
884 | i = -1; /* hack increment */ | ||
885 | } | 892 | } |
886 | } | 893 | } |
887 | /* Remove all `cmd` */ | 894 | /* Remove all `cmd` */ |
895 | //BUG: `cmd` should count as a word: `cmd` c<tab> should search for files c*, not commands c* | ||
888 | for (i = 0; int_buf[i]; i++) { | 896 | for (i = 0; int_buf[i]; i++) { |
889 | if (int_buf[i] == '`') { | 897 | if (int_buf[i] == '`') { |
890 | for (j = i + 1; int_buf[j]; j++) { | 898 | for (j = i + 1; int_buf[j]; j++) { |
891 | if (int_buf[j] == '`') { | 899 | if (int_buf[j] == '`') { |
892 | collapse_pos(i, j + 1); | 900 | collapse_pos(i, j + 1); |
893 | j = 0; | 901 | goto next; |
894 | break; | ||
895 | } | 902 | } |
896 | } | 903 | } |
897 | if (j) { | 904 | /* No closing ` - command mode, remove all up to ` */ |
898 | /* No closing ` - command mode, remove all up to ` */ | 905 | collapse_pos(0, i + 1); |
899 | collapse_pos(0, i + 1); | 906 | break; |
900 | break; | 907 | next: |
901 | } | ||
902 | i--; /* hack increment */ | 908 | i--; /* hack increment */ |
903 | } | 909 | } |
904 | } | 910 | } |
905 | 911 | ||
906 | /* Remove (command...(command...)...) and {command...{command...}...} */ | 912 | /* Remove (command...(command...)...) and {command...{command...}...} */ |
907 | c = 0; /* "recursive" level */ | 913 | { |
908 | c2 = 0; | 914 | int paren_lvl = 0; |
909 | for (i = 0; int_buf[i]; i++) { | 915 | int curly_lvl = 0; |
910 | if (int_buf[i] == '(' || int_buf[i] == '{') { | 916 | for (i = 0; int_buf[i]; i++) { |
911 | if (int_buf[i] == '(') | 917 | if (int_buf[i] == '(' || int_buf[i] == '{') { |
912 | c++; | 918 | if (int_buf[i] == '(') |
913 | else | 919 | paren_lvl++; |
914 | c2++; | 920 | else |
915 | collapse_pos(0, i + 1); | 921 | curly_lvl++; |
916 | i = -1; /* hack increment */ | 922 | collapse_pos(0, i + 1); |
923 | i = -1; /* hack increment */ | ||
924 | } | ||
917 | } | 925 | } |
918 | } | 926 | for (i = 0; pos_buf[i] >= 0 && (paren_lvl > 0 || curly_lvl > 0); i++) { |
919 | for (i = 0; pos_buf[i] >= 0 && (c > 0 || c2 > 0); i++) { | 927 | if ((int_buf[i] == ')' && paren_lvl > 0) |
920 | if ((int_buf[i] == ')' && c > 0) || (int_buf[i] == '}' && c2 > 0)) { | 928 | || (int_buf[i] == '}' && curly_lvl > 0) |
921 | if (int_buf[i] == ')') | 929 | ) { |
922 | c--; | 930 | if (int_buf[i] == ')') |
923 | else | 931 | paren_lvl--; |
924 | c2--; | 932 | else |
925 | collapse_pos(0, i + 1); | 933 | curly_lvl--; |
926 | i = -1; /* hack increment */ | 934 | collapse_pos(0, i + 1); |
935 | i = -1; /* hack increment */ | ||
936 | } | ||
927 | } | 937 | } |
928 | } | 938 | } |
929 | 939 | ||
@@ -931,8 +941,7 @@ static NOINLINE int build_match_prefix(char *matchBuf, int *len_with_quotes) | |||
931 | for (i = 0; int_buf[i]; i++) | 941 | for (i = 0; int_buf[i]; i++) |
932 | if (int_buf[i] != ' ') | 942 | if (int_buf[i] != ' ') |
933 | break; | 943 | break; |
934 | if (i) | 944 | collapse_pos(0, i); |
935 | collapse_pos(0, i); | ||
936 | 945 | ||
937 | /* Determine completion mode */ | 946 | /* Determine completion mode */ |
938 | command_mode = FIND_EXE_ONLY; | 947 | command_mode = FIND_EXE_ONLY; |
@@ -942,6 +951,7 @@ static NOINLINE int build_match_prefix(char *matchBuf, int *len_with_quotes) | |||
942 | && command_mode == FIND_EXE_ONLY | 951 | && command_mode == FIND_EXE_ONLY |
943 | && matchBuf[pos_buf[0]] == 'c' | 952 | && matchBuf[pos_buf[0]] == 'c' |
944 | && matchBuf[pos_buf[1]] == 'd' | 953 | && matchBuf[pos_buf[1]] == 'd' |
954 | //BUG: must check "cd ", not "cd" | ||
945 | ) { | 955 | ) { |
946 | command_mode = FIND_DIR_ONLY; | 956 | command_mode = FIND_DIR_ONLY; |
947 | } else { | 957 | } else { |
@@ -950,36 +960,42 @@ static NOINLINE int build_match_prefix(char *matchBuf, int *len_with_quotes) | |||
950 | } | 960 | } |
951 | } | 961 | } |
952 | } | 962 | } |
963 | if (dbg_bmp) printf("command_mode(0:exe/1:dir/2:file):%d\n", command_mode); | ||
953 | 964 | ||
954 | /* Remove everything except last word */ | 965 | /* Remove everything except last word */ |
955 | for (i = 0; int_buf[i]; i++) /* quasi-strlen(int_buf) */ | 966 | for (i = 0; int_buf[i]; i++) /* quasi-strlen(int_buf) */ |
956 | continue; | 967 | continue; |
957 | for (--i; i >= 0; i--) { | 968 | for (--i; i >= 0; i--) { |
958 | c = int_buf[i]; | 969 | int cur = int_buf[i]; |
959 | if (c == ' ' || c == '<' || c == '>' || c == '|' || c == '&') { | 970 | if (cur == ' ' || cur == '<' || cur == '>' || cur == '|' || cur == '&') { |
960 | collapse_pos(0, i + 1); | 971 | collapse_pos(0, i + 1); |
961 | break; | 972 | break; |
962 | } | 973 | } |
963 | } | 974 | } |
964 | /* Skip all leading unquoted ' or " */ | 975 | /* Skip all leading unquoted ' or " */ |
976 | //BUG: bash doesn't do this | ||
965 | for (i = 0; int_buf[i] == '\'' || int_buf[i] == '"'; i++) | 977 | for (i = 0; int_buf[i] == '\'' || int_buf[i] == '"'; i++) |
966 | continue; | 978 | continue; |
967 | /* collapse quote or unquote // or /~ */ | 979 | /* Skip quoted or unquoted // or /~ */ |
968 | while ((int_buf[i] & ~QUOT) == '/' | 980 | //BUG: bash doesn't do this |
969 | && ((int_buf[i+1] & ~QUOT) == '/' || (int_buf[i+1] & ~QUOT) == '~') | 981 | while ((char)int_buf[i] == '/' |
982 | && ((char)int_buf[i+1] == '/' || (char)int_buf[i+1] == '~') | ||
970 | ) { | 983 | ) { |
971 | i++; | 984 | i++; |
972 | } | 985 | } |
973 | 986 | ||
974 | /* set only match and destroy quotes */ | 987 | /* set only match and destroy quotes */ |
975 | j = 0; | 988 | { |
976 | for (c = 0; pos_buf[i] >= 0; i++) { | 989 | int pos = 0; |
977 | matchBuf[c++] = matchBuf[pos_buf[i]]; | 990 | for (j = 0; pos_buf[i] >= 0; i++) { |
978 | j = pos_buf[i] + 1; | 991 | matchBuf[j++] = matchBuf[pos_buf[i]]; |
992 | pos = pos_buf[i] + 1; | ||
993 | } | ||
994 | matchBuf[j] = '\0'; | ||
995 | /* old length matchBuf with quotes symbols */ | ||
996 | *len_with_quotes = pos ? pos - pos_buf[0] : 0; | ||
997 | if (dbg_bmp) printf("len_with_quotes:%d\n", *len_with_quotes); | ||
979 | } | 998 | } |
980 | matchBuf[c] = '\0'; | ||
981 | /* old length matchBuf with quotes symbols */ | ||
982 | *len_with_quotes = j ? j - pos_buf[0] : 0; | ||
983 | 999 | ||
984 | return command_mode; | 1000 | return command_mode; |
985 | } | 1001 | } |