vi: fix incorrect memory access on brace matching. Closes 7256

While at it, fix brace matching to actually show the match
(missed fflush was causing cursor positioning to be buffered);
shorten brace matching code; remove unused macro indirection
in indicate_error().

Custom linker script 'busybox_ldscript' found, using it
function                                             old     new   delta
indicate_error                                         -      61     +61
mysleep                                               43      56     +13
char_insert                                          483     486      +3
find_pair                                            167     124     -43
Indicate_Error                                        61       -     -61
------------------------------------------------------------------------------
(add/remove: 1/1 grow/shrink: 2/1 up/down: 77/-104)           Total: -27 bytes

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
Denys Vlasenko 2014-09-15 17:06:10 +02:00
parent 26a8b9f196
commit 05399fc53d

View File

@ -566,8 +566,7 @@ static void redraw(int); // force a full screen refresh
static char* format_line(char* /*, int*/); static char* format_line(char* /*, int*/);
static void refresh(int); // update the terminal from screen[] static void refresh(int); // update the terminal from screen[]
static void Indicate_Error(void); // use flash or beep to indicate error static void indicate_error(void); // use flash or beep to indicate error
#define indicate_error(c) Indicate_Error()
static void Hit_Return(void); static void Hit_Return(void);
#if ENABLE_FEATURE_VI_SEARCH #if ENABLE_FEATURE_VI_SEARCH
@ -1840,11 +1839,11 @@ static char *bound_dot(char *p) // make sure text[0] <= P < "end"
{ {
if (p >= end && end > text) { if (p >= end && end > text) {
p = end - 1; p = end - 1;
indicate_error('1'); indicate_error();
} }
if (p < text) { if (p < text) {
p = text; p = text;
indicate_error('2'); indicate_error();
} }
return p; return p;
} }
@ -2023,16 +2022,9 @@ static char *char_insert(char *p, char c, int undo) // insert the char c at 'p'
p = text_hole_delete(p, p, ALLOW_UNDO_QUEUED); // shrink buffer 1 char p = text_hole_delete(p, p, ALLOW_UNDO_QUEUED); // shrink buffer 1 char
} }
} else { } else {
#if ENABLE_FEATURE_VI_SETOPTS
// insert a char into text[] // insert a char into text[]
char *sp; // "save p"
#endif
if (c == 13) if (c == 13)
c = '\n'; // translate \r to \n c = '\n'; // translate \r to \n
#if ENABLE_FEATURE_VI_SETOPTS
sp = p; // remember addr of insert
#endif
#if ENABLE_FEATURE_VI_UNDO #if ENABLE_FEATURE_VI_UNDO
# if ENABLE_FEATURE_VI_UNDO_QUEUE # if ENABLE_FEATURE_VI_UNDO_QUEUE
if (c == '\n') if (c == '\n')
@ -2056,8 +2048,8 @@ static char *char_insert(char *p, char c, int undo) // insert the char c at 'p'
#endif /* ENABLE_FEATURE_VI_UNDO */ #endif /* ENABLE_FEATURE_VI_UNDO */
p += 1 + stupid_insert(p, c); // insert the char p += 1 + stupid_insert(p, c); // insert the char
#if ENABLE_FEATURE_VI_SETOPTS #if ENABLE_FEATURE_VI_SETOPTS
if (showmatch && strchr(")]}", *sp) != NULL) { if (showmatch && strchr(")]}", c) != NULL) {
showmatching(sp); showmatching(p - 1);
} }
if (autoindent && c == '\n') { // auto indent the new line if (autoindent && c == '\n') { // auto indent the new line
char *q; char *q;
@ -2217,34 +2209,32 @@ static char *skip_thing(char *p, int linecnt, int dir, int type)
} }
// find matching char of pair () [] {} // find matching char of pair () [] {}
// will crash if c is not one of these
static char *find_pair(char *p, const char c) static char *find_pair(char *p, const char c)
{ {
char match, *q; const char *braces = "()[]{}";
char match;
int dir, level; int dir, level;
match = ')'; dir = strchr(braces, c) - braces;
dir ^= 1;
match = braces[dir];
dir = ((dir & 1) << 1) - 1; /* 1 for ([{, -1 for )\} */
// look for match, count levels of pairs (( ))
level = 1; level = 1;
dir = 1; // assume forward for (;;) {
switch (c) { p += dir;
case '(': match = ')'; break; if (p < text || p >= end)
case '[': match = ']'; break; return NULL;
case '{': match = '}'; break; if (*p == c)
case ')': match = '('; dir = -1; break;
case ']': match = '['; dir = -1; break;
case '}': match = '{'; dir = -1; break;
}
for (q = p + dir; text <= q && q < end; q += dir) {
// look for match, count levels of pairs (( ))
if (*q == c)
level++; // increase pair levels level++; // increase pair levels
if (*q == match) if (*p == match) {
level--; // reduce pair level level--; // reduce pair level
if (level == 0) if (level == 0)
break; // found matching pair return p; // found matching pair
}
} }
if (level != 0)
q = NULL; // indicate no match
return q;
} }
#if ENABLE_FEATURE_VI_SETOPTS #if ENABLE_FEATURE_VI_SETOPTS
@ -2256,7 +2246,7 @@ static void showmatching(char *p)
// we found half of a pair // we found half of a pair
q = find_pair(p, *p); // get loc of matching char q = find_pair(p, *p); // get loc of matching char
if (q == NULL) { if (q == NULL) {
indicate_error('3'); // no matching char indicate_error(); // no matching char
} else { } else {
// "q" now points to matching pair // "q" now points to matching pair
save_dot = dot; // remember where we are save_dot = dot; // remember where we are
@ -2815,6 +2805,9 @@ static int mysleep(int hund) // sleep for 'hund' 1/100 seconds or stdin ready
{ {
struct pollfd pfd[1]; struct pollfd pfd[1];
if (hund != 0)
fflush_all();
pfd[0].fd = STDIN_FILENO; pfd[0].fd = STDIN_FILENO;
pfd[0].events = POLLIN; pfd[0].events = POLLIN;
return safe_poll(pfd, 1, hund*10) > 0; return safe_poll(pfd, 1, hund*10) > 0;
@ -3059,7 +3052,7 @@ static void flash(int h)
redraw(TRUE); redraw(TRUE);
} }
static void Indicate_Error(void) static void indicate_error(void)
{ {
#if ENABLE_FEATURE_VI_CRASHME #if ENABLE_FEATURE_VI_CRASHME
if (crashme > 0) if (crashme > 0)
@ -3602,7 +3595,7 @@ static void do_cmd(int c)
break; break;
case 27: // esc case 27: // esc
if (cmd_mode == 0) if (cmd_mode == 0)
indicate_error(c); indicate_error();
cmd_mode = 0; // stop insrting cmd_mode = 0; // stop insrting
undo_queue_commit(); undo_queue_commit();
end_cmd_q(); end_cmd_q();
@ -3621,7 +3614,7 @@ static void do_cmd(int c)
if ((unsigned)c1 <= 25) { // a-z? if ((unsigned)c1 <= 25) { // a-z?
YDreg = c1; YDreg = c1;
} else { } else {
indicate_error(c); indicate_error();
} }
break; break;
case '\'': // '- goto a specific mark case '\'': // '- goto a specific mark
@ -3639,7 +3632,7 @@ static void do_cmd(int c)
dot_begin(); // go to B-o-l dot_begin(); // go to B-o-l
dot_skip_over_ws(); dot_skip_over_ws();
} else { } else {
indicate_error(c); indicate_error();
} }
break; break;
case 'm': // m- Mark a line case 'm': // m- Mark a line
@ -3652,7 +3645,7 @@ static void do_cmd(int c)
// remember the line // remember the line
mark[c1] = dot; mark[c1] = dot;
} else { } else {
indicate_error(c); indicate_error();
} }
break; break;
case 'P': // P- Put register before case 'P': // P- Put register before
@ -3713,7 +3706,7 @@ static void do_cmd(int c)
// we found half of a pair // we found half of a pair
p = find_pair(q, *q); p = find_pair(q, *q);
if (p == NULL) { if (p == NULL) {
indicate_error(c); indicate_error();
} else { } else {
dot = p; dot = p;
} }
@ -3721,7 +3714,7 @@ static void do_cmd(int c)
} }
} }
if (*q == '\n') if (*q == '\n')
indicate_error(c); indicate_error();
break; break;
case 'f': // f- forward to a user specified char case 'f': // f- forward to a user specified char
last_forward_char = get_one_char(); // get the search char last_forward_char = get_one_char(); // get the search char
@ -4054,7 +4047,7 @@ static void do_cmd(int c)
// ZZ means to save file (if necessary), then exit // ZZ means to save file (if necessary), then exit
c1 = get_one_char(); c1 = get_one_char();
if (c1 != 'Z') { if (c1 != 'Z') {
indicate_error(c); indicate_error();
break; break;
} }
if (modified_count) { if (modified_count) {
@ -4138,7 +4131,7 @@ static void do_cmd(int c)
// could not recognize object // could not recognize object
c = c1 = 27; // error- c = c1 = 27; // error-
ml = 0; ml = 0;
indicate_error(c); indicate_error();
} }
if (ml && whole) { if (ml && whole) {
if (c == 'c') { if (c == 'c') {