aboutsummaryrefslogtreecommitdiff
path: root/libbb
diff options
context:
space:
mode:
authorDenys Vlasenko <dvlasenk@redhat.com>2010-09-03 12:59:15 +0200
committerDenys Vlasenko <dvlasenk@redhat.com>2010-09-03 12:59:15 +0200
commit81254ed3875f7be81b98266866de7f990bcd06c8 (patch)
tree53b1ebe15e0736714fa3bbc40b5a81dfe9690130 /libbb
parent3c460b005c3c422fe73dc464902e0626fc57938a (diff)
downloadbusybox-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.c132
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
101enum { 101enum {
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
829static void collapse_pos(int beg, int end) 826static 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,