aboutsummaryrefslogtreecommitdiff
path: root/libbb
diff options
context:
space:
mode:
authorDenys Vlasenko <dvlasenk@redhat.com>2010-09-03 12:53:15 +0200
committerDenys Vlasenko <dvlasenk@redhat.com>2010-09-03 12:53:15 +0200
commit2679e3c8cccbf3ae4cac8e735e5430ebbe714b00 (patch)
tree343c83fc6ab474c5e0b352218326075cf1b994b8 /libbb
parent57ea9b488b096e17418a808d20f263daea468974 (diff)
downloadbusybox-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.c154
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
815static void collapse_pos(int beg, int end) 818static 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}
821static NOINLINE int build_match_prefix(char *matchBuf, int *len_with_quotes) 832static 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}