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>
This commit is contained in:
parent
3c460b005c
commit
81254ed387
126
libbb/lineedit.c
126
libbb/lineedit.c
@ -99,7 +99,6 @@ static bool BB_ispunct(CHAR_T c) { return ((unsigned)c < 256 && ispunct(c)); }
|
|||||||
|
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
/* We use int16_t for positions, need to limit line len */
|
|
||||||
MAX_LINELEN = CONFIG_FEATURE_EDITING_MAX_LEN < 0x7ff0
|
MAX_LINELEN = CONFIG_FEATURE_EDITING_MAX_LEN < 0x7ff0
|
||||||
? CONFIG_FEATURE_EDITING_MAX_LEN
|
? CONFIG_FEATURE_EDITING_MAX_LEN
|
||||||
: 0x7ff0
|
: 0x7ff0
|
||||||
@ -156,7 +155,6 @@ struct lineedit_statics {
|
|||||||
#if ENABLE_FEATURE_TAB_COMPLETION
|
#if ENABLE_FEATURE_TAB_COMPLETION
|
||||||
char input_tab__matchBuf[MAX_LINELEN];
|
char input_tab__matchBuf[MAX_LINELEN];
|
||||||
int16_t find_match__int_buf[MAX_LINELEN + 1]; /* need to have 9 bits at least */
|
int16_t find_match__int_buf[MAX_LINELEN + 1]; /* need to have 9 bits at least */
|
||||||
int16_t find_match__pos_buf[MAX_LINELEN + 1];
|
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -824,15 +822,16 @@ static NOINLINE unsigned complete_cmd_dir_file(const char *command, int type)
|
|||||||
*/
|
*/
|
||||||
#define QUOT (UCHAR_MAX+1)
|
#define QUOT (UCHAR_MAX+1)
|
||||||
#define int_buf (S.find_match__int_buf)
|
#define int_buf (S.find_match__int_buf)
|
||||||
#define pos_buf (S.find_match__pos_buf)
|
|
||||||
#define dbg_bmp 0
|
#define dbg_bmp 0
|
||||||
static void collapse_pos(int beg, int end)
|
static void remove_chunk(int beg, int end)
|
||||||
{
|
{
|
||||||
/* beg must be <= end */
|
/* beg must be <= end */
|
||||||
if (beg == end)
|
if (beg == end)
|
||||||
return;
|
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]));
|
while ((int_buf[beg] = int_buf[end]) != 0)
|
||||||
|
beg++, end++;
|
||||||
|
|
||||||
if (dbg_bmp) {
|
if (dbg_bmp) {
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; int_buf[i]; i++)
|
for (i = 0; int_buf[i]; i++)
|
||||||
@ -846,43 +845,40 @@ static NOINLINE int build_match_prefix(char *matchBuf)
|
|||||||
int command_mode;
|
int command_mode;
|
||||||
/* Were local, but it used too much stack */
|
/* Were local, but it used too much stack */
|
||||||
/* int16_t int_buf[MAX_LINELEN + 1]; */
|
/* int16_t int_buf[MAX_LINELEN + 1]; */
|
||||||
/* int16_t pos_buf[MAX_LINELEN + 1]; */
|
|
||||||
|
|
||||||
if (dbg_bmp) printf("\n%s\n", matchBuf);
|
if (dbg_bmp) printf("\n%s\n", matchBuf);
|
||||||
|
|
||||||
for (i = 0;; i++) {
|
i = 0;
|
||||||
int_buf[i] = (unsigned char)matchBuf[i];
|
while ((int_buf[i] = (unsigned char)matchBuf[i]) != '\0')
|
||||||
if (int_buf[i] == 0) {
|
i++;
|
||||||
pos_buf[i] = -1; /* end-of-line indicator */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
pos_buf[i] = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Mark every \c as "quoted c" */
|
/* Mark every \c as "quoted c" */
|
||||||
for (i = j = 0; matchBuf[i]; i++, j++) {
|
for (i = j = 0; matchBuf[i]; i++, j++) {
|
||||||
if (matchBuf[i] == '\\') {
|
if (matchBuf[i] == '\\') {
|
||||||
collapse_pos(j, j + 1);
|
remove_chunk(j, j + 1);
|
||||||
int_buf[j] |= QUOT;
|
int_buf[j] |= QUOT;
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Quote-mark "chars" and 'chars' */
|
/* Quote-mark "chars" and 'chars', drop delimiters */
|
||||||
{
|
{
|
||||||
int in_quote = 0;
|
int in_quote = 0;
|
||||||
for (i = 0; int_buf[i]; i++) {
|
i = 0;
|
||||||
|
while (int_buf[i]) {
|
||||||
int cur = int_buf[i];
|
int cur = int_buf[i];
|
||||||
|
if (!cur)
|
||||||
|
break;
|
||||||
if (cur == '\'' || cur == '"') {
|
if (cur == '\'' || cur == '"') {
|
||||||
if (!in_quote)
|
if (!in_quote || (cur == in_quote)) {
|
||||||
in_quote = cur;
|
in_quote ^= cur;
|
||||||
else if (cur == in_quote)
|
remove_chunk(i, i + 1);
|
||||||
in_quote = 0;
|
continue;
|
||||||
else
|
|
||||||
int_buf[i] |= QUOT;
|
|
||||||
} else if (in_quote && cur != '$') {
|
|
||||||
int_buf[i] |= QUOT;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (in_quote)
|
||||||
|
int_buf[i] = cur | QUOT;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Remove everything up to command delimiters:
|
/* Remove everything up to command delimiters:
|
||||||
@ -898,61 +894,47 @@ static NOINLINE int build_match_prefix(char *matchBuf)
|
|||||||
} else if (cur == '|' && prev == '>') {
|
} else if (cur == '|' && prev == '>') {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
collapse_pos(0, i + 1 + (cur == int_buf[i + 1]));
|
remove_chunk(0, i + 1 + (cur == int_buf[i + 1]));
|
||||||
i = -1; /* back to square 1 */
|
i = -1; /* back to square 1 */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Remove all `cmd` */
|
/* 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++) {
|
for (i = 0; int_buf[i]; i++) {
|
||||||
if (int_buf[i] == '`') {
|
if (int_buf[i] == '`') {
|
||||||
for (j = i + 1; int_buf[j]; j++) {
|
for (j = i + 1; int_buf[j]; j++) {
|
||||||
if (int_buf[j] == '`') {
|
if (int_buf[j] == '`') {
|
||||||
collapse_pos(i, j + 1);
|
/* `cmd` should count as a word:
|
||||||
|
* `cmd` c<tab> should search for files c*,
|
||||||
|
* not commands c*. Therefore we don't drop
|
||||||
|
* `cmd` entirely, we replace it with single `.
|
||||||
|
*/
|
||||||
|
remove_chunk(i, j);
|
||||||
goto next;
|
goto next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* No closing ` - command mode, remove all up to ` */
|
/* No closing ` - command mode, remove all up to ` */
|
||||||
collapse_pos(0, i + 1);
|
remove_chunk(0, i + 1);
|
||||||
break;
|
break;
|
||||||
next:
|
next: ;
|
||||||
i--; /* hack increment */
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Remove (command...(command...)...) and {command...{command...}...} */
|
/* Remove "cmd (" and "cmd {"
|
||||||
{
|
* Example: "if { c<tab>"
|
||||||
int paren_lvl = 0;
|
* In this example, c should be matched as command pfx.
|
||||||
int curly_lvl = 0;
|
*/
|
||||||
for (i = 0; int_buf[i]; i++) {
|
for (i = 0; int_buf[i]; i++) {
|
||||||
if (int_buf[i] == '(' || int_buf[i] == '{') {
|
if (int_buf[i] == '(' || int_buf[i] == '{') {
|
||||||
if (int_buf[i] == '(')
|
remove_chunk(0, i + 1);
|
||||||
paren_lvl++;
|
|
||||||
else
|
|
||||||
curly_lvl++;
|
|
||||||
collapse_pos(0, i + 1);
|
|
||||||
i = -1; /* hack increment */
|
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 */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Remove leading unquoted spaces */
|
/* Remove leading unquoted spaces */
|
||||||
for (i = 0; int_buf[i]; i++)
|
for (i = 0; int_buf[i]; i++)
|
||||||
if (int_buf[i] != ' ')
|
if (int_buf[i] != ' ')
|
||||||
break;
|
break;
|
||||||
collapse_pos(0, i);
|
remove_chunk(0, i);
|
||||||
|
|
||||||
/* Determine completion mode */
|
/* Determine completion mode */
|
||||||
command_mode = FIND_EXE_ONLY;
|
command_mode = FIND_EXE_ONLY;
|
||||||
@ -960,9 +942,9 @@ static NOINLINE int build_match_prefix(char *matchBuf)
|
|||||||
if (int_buf[i] == ' ' || int_buf[i] == '<' || int_buf[i] == '>') {
|
if (int_buf[i] == ' ' || int_buf[i] == '<' || int_buf[i] == '>') {
|
||||||
if (int_buf[i] == ' '
|
if (int_buf[i] == ' '
|
||||||
&& command_mode == FIND_EXE_ONLY
|
&& command_mode == FIND_EXE_ONLY
|
||||||
&& matchBuf[pos_buf[0]] == 'c'
|
&& (char)int_buf[0] == 'c'
|
||||||
&& matchBuf[pos_buf[1]] == 'd'
|
&& (char)int_buf[1] == 'd'
|
||||||
//BUG: must check "cd ", not "cd"
|
&& i == 2 /* -> int_buf[2] == ' ' */
|
||||||
) {
|
) {
|
||||||
command_mode = FIND_DIR_ONLY;
|
command_mode = FIND_DIR_ONLY;
|
||||||
} else {
|
} else {
|
||||||
@ -979,36 +961,20 @@ static NOINLINE int build_match_prefix(char *matchBuf)
|
|||||||
for (--i; i >= 0; i--) {
|
for (--i; i >= 0; i--) {
|
||||||
int cur = int_buf[i];
|
int cur = int_buf[i];
|
||||||
if (cur == ' ' || cur == '<' || cur == '>' || cur == '|' || cur == '&') {
|
if (cur == ' ' || cur == '<' || cur == '>' || cur == '|' || cur == '&') {
|
||||||
collapse_pos(0, i + 1);
|
remove_chunk(0, i + 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Skip all leading unquoted ' or " */
|
|
||||||
//BUG: bash doesn't do this
|
|
||||||
for (i = 0; int_buf[i] == '\'' || int_buf[i] == '"'; i++)
|
|
||||||
continue;
|
|
||||||
/* 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 */
|
/* Store only match prefix */
|
||||||
{
|
i = 0;
|
||||||
int pos = 0;
|
while ((matchBuf[i] = int_buf[i]) != '\0')
|
||||||
for (j = 0; pos_buf[i] >= 0; i++) {
|
i++;
|
||||||
matchBuf[j++] = matchBuf[pos_buf[i]];
|
if (dbg_bmp) printf("final matchBuf:'%s'\n", matchBuf);
|
||||||
pos = pos_buf[i] + 1;
|
|
||||||
}
|
|
||||||
matchBuf[j] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
return command_mode;
|
return command_mode;
|
||||||
}
|
}
|
||||||
#undef int_buf
|
#undef int_buf
|
||||||
#undef pos_buf
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Display by column (original idea from ls applet,
|
* Display by column (original idea from ls applet,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user