summaryrefslogtreecommitdiff
path: root/libbb/lineedit.c
diff options
context:
space:
mode:
authorDenys Vlasenko2010-09-03 12:53:15 +0200
committerDenys Vlasenko2010-09-03 12:53:15 +0200
commit2679e3c8cccbf3ae4cac8e735e5430ebbe714b00 (patch)
tree343c83fc6ab474c5e0b352218326075cf1b994b8 /libbb/lineedit.c
parent57ea9b488b096e17418a808d20f263daea468974 (diff)
downloadbusybox-2679e3c8cccbf3ae4cac8e735e5430ebbe714b00.zip
busybox-2679e3c8cccbf3ae4cac8e735e5430ebbe714b00.tar.gz
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/lineedit.c')
-rw-r--r--libbb/lineedit.c154
1 files changed, 85 insertions, 69 deletions
diff --git a/libbb/lineedit.c b/libbb/lineedit.c
index 7bb709f..dd9d85b 100644
--- a/libbb/lineedit.c
+++ b/libbb/lineedit.c
@@ -716,6 +716,7 @@ static NOINLINE void complete_cmd_dir_file(char *command, int type)
char **paths = path1;
int npaths;
int i;
+ unsigned pf_len;
char *pfind;
char *dirbuf = NULL;
@@ -738,6 +739,7 @@ static NOINLINE void complete_cmd_dir_file(char *command, int type)
#endif
path1[0] = dirbuf;
}
+ pf_len = strlen(pfind);
for (i = 0; i < npaths; i++) {
DIR *dir;
@@ -756,7 +758,7 @@ static NOINLINE void complete_cmd_dir_file(char *command, int type)
if (!pfind[0] && DOT_OR_DOTDOT(name_found))
continue;
/* match? */
- if (strncmp(name_found, pfind, strlen(pfind)) != 0)
+ if (strncmp(name_found, pfind, pf_len) != 0)
continue; /* no */
found = concat_path_file(paths[i], name_found);
@@ -812,21 +814,31 @@ static NOINLINE void complete_cmd_dir_file(char *command, int type)
#define QUOT (UCHAR_MAX+1)
#define int_buf (S.find_match__int_buf)
#define pos_buf (S.find_match__pos_buf)
+#define dbg_bmp 0
static void collapse_pos(int beg, int end)
{
/* beg must be <= end */
+ if (beg == end)
+ return;
memmove(int_buf+beg, int_buf+end, (MAX_LINELEN+1-end) * sizeof(int_buf[0]));
memmove(pos_buf+beg, pos_buf+end, (MAX_LINELEN+1-end) * sizeof(pos_buf[0]));
+ if (dbg_bmp) {
+ int i;
+ for (i = 0; int_buf[i]; i++)
+ bb_putchar((unsigned char)int_buf[i]);
+ bb_putchar('\n');
+ }
}
static NOINLINE int build_match_prefix(char *matchBuf, int *len_with_quotes)
{
int i, j;
int command_mode;
- int c, c2;
/* Were local, but it used too much stack */
/* int16_t int_buf[MAX_LINELEN + 1]; */
/* int16_t pos_buf[MAX_LINELEN + 1]; */
+ if (dbg_bmp) printf("\n%s\n", matchBuf);
+
for (i = 0;; i++) {
int_buf[i] = (unsigned char)matchBuf[i];
if (int_buf[i] == 0) {
@@ -845,20 +857,21 @@ static NOINLINE int build_match_prefix(char *matchBuf, int *len_with_quotes)
}
}
/* Quote-mark "chars" and 'chars' */
- c2 = 0;
- for (i = 0; int_buf[i]; i++) {
- c = int_buf[i];
- if (c == '\'' || c == '"') {
- if (c2 == 0)
- c2 = c;
- else {
- if (c == c2)
- c2 = 0;
+ {
+ int in_quote = 0;
+ for (i = 0; int_buf[i]; i++) {
+ int cur = int_buf[i];
+ if (cur == '\'' || cur == '"') {
+ if (!in_quote)
+ in_quote = cur;
+ else if (cur == in_quote)
+ in_quote = 0;
else
int_buf[i] |= QUOT;
+ } else if (in_quote && cur != '$') {
+ int_buf[i] |= QUOT;
}
- } else if (c2 != 0 && c != '$')
- int_buf[i] |= QUOT;
+ }
}
/* Remove everything up to command delimiters:
@@ -866,64 +879,61 @@ static NOINLINE int build_match_prefix(char *matchBuf, int *len_with_quotes)
* but careful with '>&' '<&' '>|'
*/
for (i = 0; int_buf[i]; i++) {
- int n;
- c = int_buf[i];
- c2 = int_buf[i + 1];
- j = i ? int_buf[i - 1] : -1;
- n = 0;
- if (c == ';' || c == '&' || c == '|') {
- n = 1 + (c == c2);
- if (c == '&') {
- if (j == '>' || j == '<')
- n = 0;
- } else if (c == '|' && j == '>')
- n = 0;
- }
- if (n) {
- collapse_pos(0, i + n);
- i = -1; /* hack increment */
+ int cur = int_buf[i];
+ if (cur == ';' || cur == '&' || cur == '|') {
+ int prev = i ? int_buf[i - 1] : 0;
+ if (cur == '&' && (prev == '>' || prev == '<')) {
+ continue;
+ } else if (cur == '|' && prev == '>') {
+ continue;
+ }
+ collapse_pos(0, i + 1 + (cur == int_buf[i + 1]));
+ i = -1; /* back to square 1 */
}
}
/* Remove all `cmd` */
+//BUG: `cmd` should count as a word: `cmd` c<tab> should search for files c*, not commands c*
for (i = 0; int_buf[i]; i++) {
if (int_buf[i] == '`') {
for (j = i + 1; int_buf[j]; j++) {
if (int_buf[j] == '`') {
collapse_pos(i, j + 1);
- j = 0;
- break;
+ goto next;
}
}
- if (j) {
- /* No closing ` - command mode, remove all up to ` */
- collapse_pos(0, i + 1);
- break;
- }
+ /* No closing ` - command mode, remove all up to ` */
+ collapse_pos(0, i + 1);
+ break;
+ next:
i--; /* hack increment */
}
}
/* Remove (command...(command...)...) and {command...{command...}...} */
- c = 0; /* "recursive" level */
- c2 = 0;
- for (i = 0; int_buf[i]; i++) {
- if (int_buf[i] == '(' || int_buf[i] == '{') {
- if (int_buf[i] == '(')
- c++;
- else
- c2++;
- collapse_pos(0, i + 1);
- i = -1; /* hack increment */
+ {
+ int paren_lvl = 0;
+ int curly_lvl = 0;
+ for (i = 0; int_buf[i]; i++) {
+ if (int_buf[i] == '(' || int_buf[i] == '{') {
+ if (int_buf[i] == '(')
+ paren_lvl++;
+ else
+ curly_lvl++;
+ collapse_pos(0, i + 1);
+ i = -1; /* hack increment */
+ }
}
- }
- for (i = 0; pos_buf[i] >= 0 && (c > 0 || c2 > 0); i++) {
- if ((int_buf[i] == ')' && c > 0) || (int_buf[i] == '}' && c2 > 0)) {
- if (int_buf[i] == ')')
- c--;
- else
- c2--;
- collapse_pos(0, i + 1);
- i = -1; /* hack increment */
+ for (i = 0; pos_buf[i] >= 0 && (paren_lvl > 0 || curly_lvl > 0); i++) {
+ if ((int_buf[i] == ')' && paren_lvl > 0)
+ || (int_buf[i] == '}' && curly_lvl > 0)
+ ) {
+ if (int_buf[i] == ')')
+ paren_lvl--;
+ else
+ curly_lvl--;
+ collapse_pos(0, i + 1);
+ i = -1; /* hack increment */
+ }
}
}
@@ -931,8 +941,7 @@ static NOINLINE int build_match_prefix(char *matchBuf, int *len_with_quotes)
for (i = 0; int_buf[i]; i++)
if (int_buf[i] != ' ')
break;
- if (i)
- collapse_pos(0, i);
+ collapse_pos(0, i);
/* Determine completion mode */
command_mode = FIND_EXE_ONLY;
@@ -942,6 +951,7 @@ static NOINLINE int build_match_prefix(char *matchBuf, int *len_with_quotes)
&& command_mode == FIND_EXE_ONLY
&& matchBuf[pos_buf[0]] == 'c'
&& matchBuf[pos_buf[1]] == 'd'
+//BUG: must check "cd ", not "cd"
) {
command_mode = FIND_DIR_ONLY;
} else {
@@ -950,36 +960,42 @@ static NOINLINE int build_match_prefix(char *matchBuf, int *len_with_quotes)
}
}
}
+ if (dbg_bmp) printf("command_mode(0:exe/1:dir/2:file):%d\n", command_mode);
/* Remove everything except last word */
for (i = 0; int_buf[i]; i++) /* quasi-strlen(int_buf) */
continue;
for (--i; i >= 0; i--) {
- c = int_buf[i];
- if (c == ' ' || c == '<' || c == '>' || c == '|' || c == '&') {
+ int cur = int_buf[i];
+ if (cur == ' ' || cur == '<' || cur == '>' || cur == '|' || cur == '&') {
collapse_pos(0, i + 1);
break;
}
}
/* Skip all leading unquoted ' or " */
+//BUG: bash doesn't do this
for (i = 0; int_buf[i] == '\'' || int_buf[i] == '"'; i++)
continue;
- /* collapse quote or unquote // or /~ */
- while ((int_buf[i] & ~QUOT) == '/'
- && ((int_buf[i+1] & ~QUOT) == '/' || (int_buf[i+1] & ~QUOT) == '~')
+ /* Skip quoted or unquoted // or /~ */
+//BUG: bash doesn't do this
+ while ((char)int_buf[i] == '/'
+ && ((char)int_buf[i+1] == '/' || (char)int_buf[i+1] == '~')
) {
i++;
}
/* set only match and destroy quotes */
- j = 0;
- for (c = 0; pos_buf[i] >= 0; i++) {
- matchBuf[c++] = matchBuf[pos_buf[i]];
- j = pos_buf[i] + 1;
+ {
+ int pos = 0;
+ for (j = 0; pos_buf[i] >= 0; i++) {
+ matchBuf[j++] = matchBuf[pos_buf[i]];
+ pos = pos_buf[i] + 1;
+ }
+ matchBuf[j] = '\0';
+ /* old length matchBuf with quotes symbols */
+ *len_with_quotes = pos ? pos - pos_buf[0] : 0;
+ if (dbg_bmp) printf("len_with_quotes:%d\n", *len_with_quotes);
}
- matchBuf[c] = '\0';
- /* old length matchBuf with quotes symbols */
- *len_with_quotes = j ? j - pos_buf[0] : 0;
return command_mode;
}