diff options
author | Denys Vlasenko <dvlasenk@redhat.com> | 2010-09-03 12:59:15 +0200 |
---|---|---|
committer | Denys Vlasenko <dvlasenk@redhat.com> | 2010-09-03 12:59:15 +0200 |
commit | 81254ed3875f7be81b98266866de7f990bcd06c8 (patch) | |
tree | 53b1ebe15e0736714fa3bbc40b5a81dfe9690130 /libbb | |
parent | 3c460b005c3c422fe73dc464902e0626fc57938a (diff) | |
download | busybox-w32-81254ed3875f7be81b98266866de7f990bcd06c8.tar.gz busybox-w32-81254ed3875f7be81b98266866de7f990bcd06c8.tar.bz2 busybox-w32-81254ed3875f7be81b98266866de7f990bcd06c8.zip |
lineedit: remove pos_buf[] array (up to 16k!); fix compat bugs
pos_buf is a strange hack, easy to do without it.
This also allows lines >32k long to be handled.
Also simplified match prefix generations and made behavior more like bash.
function old new delta
remove_chunk - 43 +43
collapse_pos 79 - -79
build_match_prefix 804 579 -225
------------------------------------------------------------------------------
(add/remove: 1/1 grow/shrink: 0/1 up/down: 43/-304) Total: -261 bytes
Signed-off-by: Denys Vlasenko <dvlasenk@redhat.com>
Diffstat (limited to 'libbb')
-rw-r--r-- | libbb/lineedit.c | 132 |
1 files changed, 49 insertions, 83 deletions
diff --git a/libbb/lineedit.c b/libbb/lineedit.c index e40917f62..fff5c1a89 100644 --- a/libbb/lineedit.c +++ b/libbb/lineedit.c | |||
@@ -99,7 +99,6 @@ static bool BB_ispunct(CHAR_T c) { return ((unsigned)c < 256 && ispunct(c)); } | |||
99 | 99 | ||
100 | 100 | ||
101 | enum { | 101 | enum { |
102 | /* We use int16_t for positions, need to limit line len */ | ||
103 | MAX_LINELEN = CONFIG_FEATURE_EDITING_MAX_LEN < 0x7ff0 | 102 | MAX_LINELEN = CONFIG_FEATURE_EDITING_MAX_LEN < 0x7ff0 |
104 | ? CONFIG_FEATURE_EDITING_MAX_LEN | 103 | ? CONFIG_FEATURE_EDITING_MAX_LEN |
105 | : 0x7ff0 | 104 | : 0x7ff0 |
@@ -156,7 +155,6 @@ struct lineedit_statics { | |||
156 | #if ENABLE_FEATURE_TAB_COMPLETION | 155 | #if ENABLE_FEATURE_TAB_COMPLETION |
157 | char input_tab__matchBuf[MAX_LINELEN]; | 156 | char input_tab__matchBuf[MAX_LINELEN]; |
158 | int16_t find_match__int_buf[MAX_LINELEN + 1]; /* need to have 9 bits at least */ | 157 | int16_t find_match__int_buf[MAX_LINELEN + 1]; /* need to have 9 bits at least */ |
159 | int16_t find_match__pos_buf[MAX_LINELEN + 1]; | ||
160 | #endif | 158 | #endif |
161 | }; | 159 | }; |
162 | 160 | ||
@@ -824,15 +822,16 @@ static NOINLINE unsigned complete_cmd_dir_file(const char *command, int type) | |||
824 | */ | 822 | */ |
825 | #define QUOT (UCHAR_MAX+1) | 823 | #define QUOT (UCHAR_MAX+1) |
826 | #define int_buf (S.find_match__int_buf) | 824 | #define int_buf (S.find_match__int_buf) |
827 | #define pos_buf (S.find_match__pos_buf) | ||
828 | #define dbg_bmp 0 | 825 | #define dbg_bmp 0 |
829 | static void collapse_pos(int beg, int end) | 826 | static void remove_chunk(int beg, int end) |
830 | { | 827 | { |
831 | /* beg must be <= end */ | 828 | /* beg must be <= end */ |
832 | if (beg == end) | 829 | if (beg == end) |
833 | return; | 830 | return; |
834 | memmove(int_buf+beg, int_buf+end, (MAX_LINELEN+1-end) * sizeof(int_buf[0])); | 831 | |
835 | memmove(pos_buf+beg, pos_buf+end, (MAX_LINELEN+1-end) * sizeof(pos_buf[0])); | 832 | while ((int_buf[beg] = int_buf[end]) != 0) |
833 | beg++, end++; | ||
834 | |||
836 | if (dbg_bmp) { | 835 | if (dbg_bmp) { |
837 | int i; | 836 | int i; |
838 | for (i = 0; int_buf[i]; i++) | 837 | for (i = 0; int_buf[i]; i++) |
@@ -846,42 +845,39 @@ static NOINLINE int build_match_prefix(char *matchBuf) | |||
846 | int command_mode; | 845 | int command_mode; |
847 | /* Were local, but it used too much stack */ | 846 | /* Were local, but it used too much stack */ |
848 | /* int16_t int_buf[MAX_LINELEN + 1]; */ | 847 | /* int16_t int_buf[MAX_LINELEN + 1]; */ |
849 | /* int16_t pos_buf[MAX_LINELEN + 1]; */ | ||
850 | 848 | ||
851 | if (dbg_bmp) printf("\n%s\n", matchBuf); | 849 | if (dbg_bmp) printf("\n%s\n", matchBuf); |
852 | 850 | ||
853 | for (i = 0;; i++) { | 851 | i = 0; |
854 | int_buf[i] = (unsigned char)matchBuf[i]; | 852 | while ((int_buf[i] = (unsigned char)matchBuf[i]) != '\0') |
855 | if (int_buf[i] == 0) { | 853 | i++; |
856 | pos_buf[i] = -1; /* end-of-line indicator */ | ||
857 | break; | ||
858 | } | ||
859 | pos_buf[i] = i; | ||
860 | } | ||
861 | 854 | ||
862 | /* Mark every \c as "quoted c" */ | 855 | /* Mark every \c as "quoted c" */ |
863 | for (i = j = 0; matchBuf[i]; i++, j++) { | 856 | for (i = j = 0; matchBuf[i]; i++, j++) { |
864 | if (matchBuf[i] == '\\') { | 857 | if (matchBuf[i] == '\\') { |
865 | collapse_pos(j, j + 1); | 858 | remove_chunk(j, j + 1); |
866 | int_buf[j] |= QUOT; | 859 | int_buf[j] |= QUOT; |
867 | i++; | 860 | i++; |
868 | } | 861 | } |
869 | } | 862 | } |
870 | /* Quote-mark "chars" and 'chars' */ | 863 | /* Quote-mark "chars" and 'chars', drop delimiters */ |
871 | { | 864 | { |
872 | int in_quote = 0; | 865 | int in_quote = 0; |
873 | for (i = 0; int_buf[i]; i++) { | 866 | i = 0; |
867 | while (int_buf[i]) { | ||
874 | int cur = int_buf[i]; | 868 | int cur = int_buf[i]; |
869 | if (!cur) | ||
870 | break; | ||
875 | if (cur == '\'' || cur == '"') { | 871 | if (cur == '\'' || cur == '"') { |
876 | if (!in_quote) | 872 | if (!in_quote || (cur == in_quote)) { |
877 | in_quote = cur; | 873 | in_quote ^= cur; |
878 | else if (cur == in_quote) | 874 | remove_chunk(i, i + 1); |
879 | in_quote = 0; | 875 | continue; |
880 | else | 876 | } |
881 | int_buf[i] |= QUOT; | ||
882 | } else if (in_quote && cur != '$') { | ||
883 | int_buf[i] |= QUOT; | ||
884 | } | 877 | } |
878 | if (in_quote) | ||
879 | int_buf[i] = cur | QUOT; | ||
880 | i++; | ||
885 | } | 881 | } |
886 | } | 882 | } |
887 | 883 | ||
@@ -898,53 +894,39 @@ static NOINLINE int build_match_prefix(char *matchBuf) | |||
898 | } else if (cur == '|' && prev == '>') { | 894 | } else if (cur == '|' && prev == '>') { |
899 | continue; | 895 | continue; |
900 | } | 896 | } |
901 | collapse_pos(0, i + 1 + (cur == int_buf[i + 1])); | 897 | remove_chunk(0, i + 1 + (cur == int_buf[i + 1])); |
902 | i = -1; /* back to square 1 */ | 898 | i = -1; /* back to square 1 */ |
903 | } | 899 | } |
904 | } | 900 | } |
905 | /* Remove all `cmd` */ | 901 | /* Remove all `cmd` */ |
906 | //BUG: `cmd` should count as a word: `cmd` c<tab> should search for files c*, not commands c* | ||
907 | for (i = 0; int_buf[i]; i++) { | 902 | for (i = 0; int_buf[i]; i++) { |
908 | if (int_buf[i] == '`') { | 903 | if (int_buf[i] == '`') { |
909 | for (j = i + 1; int_buf[j]; j++) { | 904 | for (j = i + 1; int_buf[j]; j++) { |
910 | if (int_buf[j] == '`') { | 905 | if (int_buf[j] == '`') { |
911 | collapse_pos(i, j + 1); | 906 | /* `cmd` should count as a word: |
907 | * `cmd` c<tab> should search for files c*, | ||
908 | * not commands c*. Therefore we don't drop | ||
909 | * `cmd` entirely, we replace it with single `. | ||
910 | */ | ||
911 | remove_chunk(i, j); | ||
912 | goto next; | 912 | goto next; |
913 | } | 913 | } |
914 | } | 914 | } |
915 | /* No closing ` - command mode, remove all up to ` */ | 915 | /* No closing ` - command mode, remove all up to ` */ |
916 | collapse_pos(0, i + 1); | 916 | remove_chunk(0, i + 1); |
917 | break; | 917 | break; |
918 | next: | 918 | next: ; |
919 | i--; /* hack increment */ | ||
920 | } | 919 | } |
921 | } | 920 | } |
922 | 921 | ||
923 | /* Remove (command...(command...)...) and {command...{command...}...} */ | 922 | /* Remove "cmd (" and "cmd {" |
924 | { | 923 | * Example: "if { c<tab>" |
925 | int paren_lvl = 0; | 924 | * In this example, c should be matched as command pfx. |
926 | int curly_lvl = 0; | 925 | */ |
927 | for (i = 0; int_buf[i]; i++) { | 926 | for (i = 0; int_buf[i]; i++) { |
928 | if (int_buf[i] == '(' || int_buf[i] == '{') { | 927 | if (int_buf[i] == '(' || int_buf[i] == '{') { |
929 | if (int_buf[i] == '(') | 928 | remove_chunk(0, i + 1); |
930 | paren_lvl++; | 929 | i = -1; /* hack increment */ |
931 | else | ||
932 | curly_lvl++; | ||
933 | collapse_pos(0, i + 1); | ||
934 | i = -1; /* hack increment */ | ||
935 | } | ||
936 | } | ||
937 | for (i = 0; pos_buf[i] >= 0 && (paren_lvl > 0 || curly_lvl > 0); i++) { | ||
938 | if ((int_buf[i] == ')' && paren_lvl > 0) | ||
939 | || (int_buf[i] == '}' && curly_lvl > 0) | ||
940 | ) { | ||
941 | if (int_buf[i] == ')') | ||
942 | paren_lvl--; | ||
943 | else | ||
944 | curly_lvl--; | ||
945 | collapse_pos(0, i + 1); | ||
946 | i = -1; /* hack increment */ | ||
947 | } | ||
948 | } | 930 | } |
949 | } | 931 | } |
950 | 932 | ||
@@ -952,7 +934,7 @@ static NOINLINE int build_match_prefix(char *matchBuf) | |||
952 | for (i = 0; int_buf[i]; i++) | 934 | for (i = 0; int_buf[i]; i++) |
953 | if (int_buf[i] != ' ') | 935 | if (int_buf[i] != ' ') |
954 | break; | 936 | break; |
955 | collapse_pos(0, i); | 937 | remove_chunk(0, i); |
956 | 938 | ||
957 | /* Determine completion mode */ | 939 | /* Determine completion mode */ |
958 | command_mode = FIND_EXE_ONLY; | 940 | command_mode = FIND_EXE_ONLY; |
@@ -960,9 +942,9 @@ static NOINLINE int build_match_prefix(char *matchBuf) | |||
960 | if (int_buf[i] == ' ' || int_buf[i] == '<' || int_buf[i] == '>') { | 942 | if (int_buf[i] == ' ' || int_buf[i] == '<' || int_buf[i] == '>') { |
961 | if (int_buf[i] == ' ' | 943 | if (int_buf[i] == ' ' |
962 | && command_mode == FIND_EXE_ONLY | 944 | && command_mode == FIND_EXE_ONLY |
963 | && matchBuf[pos_buf[0]] == 'c' | 945 | && (char)int_buf[0] == 'c' |
964 | && matchBuf[pos_buf[1]] == 'd' | 946 | && (char)int_buf[1] == 'd' |
965 | //BUG: must check "cd ", not "cd" | 947 | && i == 2 /* -> int_buf[2] == ' ' */ |
966 | ) { | 948 | ) { |
967 | command_mode = FIND_DIR_ONLY; | 949 | command_mode = FIND_DIR_ONLY; |
968 | } else { | 950 | } else { |
@@ -979,36 +961,20 @@ static NOINLINE int build_match_prefix(char *matchBuf) | |||
979 | for (--i; i >= 0; i--) { | 961 | for (--i; i >= 0; i--) { |
980 | int cur = int_buf[i]; | 962 | int cur = int_buf[i]; |
981 | if (cur == ' ' || cur == '<' || cur == '>' || cur == '|' || cur == '&') { | 963 | if (cur == ' ' || cur == '<' || cur == '>' || cur == '|' || cur == '&') { |
982 | collapse_pos(0, i + 1); | 964 | remove_chunk(0, i + 1); |
983 | break; | 965 | break; |
984 | } | 966 | } |
985 | } | 967 | } |
986 | /* Skip all leading unquoted ' or " */ | ||
987 | //BUG: bash doesn't do this | ||
988 | for (i = 0; int_buf[i] == '\'' || int_buf[i] == '"'; i++) | ||
989 | continue; | ||
990 | /* Skip quoted or unquoted // or /~ */ | ||
991 | //BUG: bash doesn't do this | ||
992 | while ((char)int_buf[i] == '/' | ||
993 | && ((char)int_buf[i+1] == '/' || (char)int_buf[i+1] == '~') | ||
994 | ) { | ||
995 | i++; | ||
996 | } | ||
997 | 968 | ||
998 | /* set only match and destroy quotes */ | 969 | /* Store only match prefix */ |
999 | { | 970 | i = 0; |
1000 | int pos = 0; | 971 | while ((matchBuf[i] = int_buf[i]) != '\0') |
1001 | for (j = 0; pos_buf[i] >= 0; i++) { | 972 | i++; |
1002 | matchBuf[j++] = matchBuf[pos_buf[i]]; | 973 | if (dbg_bmp) printf("final matchBuf:'%s'\n", matchBuf); |
1003 | pos = pos_buf[i] + 1; | ||
1004 | } | ||
1005 | matchBuf[j] = '\0'; | ||
1006 | } | ||
1007 | 974 | ||
1008 | return command_mode; | 975 | return command_mode; |
1009 | } | 976 | } |
1010 | #undef int_buf | 977 | #undef int_buf |
1011 | #undef pos_buf | ||
1012 | 978 | ||
1013 | /* | 979 | /* |
1014 | * Display by column (original idea from ls applet, | 980 | * Display by column (original idea from ls applet, |