From 12e154f0cf4dba7bc508356649f8d57ec1dbef37 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 9 Sep 2011 12:35:49 +0200 Subject: [PATCH] vi: prevent unlimited recursion in do_cmd(). Closes 4153 function old new delta do_cmd 4284 4194 -90 Signed-off-by: Denys Vlasenko --- editors/vi.c | 298 ++++++++++++++++++++++++--------------------------- 1 file changed, 141 insertions(+), 157 deletions(-) diff --git a/editors/vi.c b/editors/vi.c index 96a0c8df7..71d600834 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -3063,7 +3063,6 @@ static void refresh(int full_screen) //----- Execute a Vi Command ----------------------------------- static void do_cmd(int c) { - const char *msg = msg; // for compiler char *p, *q, *save_dot; char buf[12]; int dir; @@ -3072,8 +3071,8 @@ static void do_cmd(int c) // c1 = c; // quiet the compiler // cnt = yf = 0; // quiet the compiler -// msg = p = q = save_dot = buf; // quiet the compiler - memset(buf, '\0', 12); +// p = q = save_dot = buf; // quiet the compiler + memset(buf, '\0', sizeof(buf)); show_status_line(); @@ -3189,19 +3188,18 @@ static void do_cmd(int c) case KEYCODE_LEFT: // cursor key Left case 8: // ctrl-H- move left (This may be ERASE char) case 0x7f: // DEL- move left (This may be ERASE char) - if (--cmdcnt > 0) { - do_cmd(c); - } - dot_left(); + do { + dot_left(); + } while (--cmdcnt > 0); break; case 10: // Newline ^J case 'j': // j- goto next line, same col case KEYCODE_DOWN: // cursor key Down - if (--cmdcnt > 0) { - do_cmd(c); - } - dot_next(); // go to next B-o-l - dot = move_to_col(dot, ccol + offset); // try stay in same col + do { + dot_next(); // go to next B-o-l + // try stay in same col + dot = move_to_col(dot, ccol + offset); + } while (--cmdcnt > 0); break; case 12: // ctrl-L force redraw whole screen case 18: // ctrl-R force redraw @@ -3214,11 +3212,10 @@ static void do_cmd(int c) break; case 13: // Carriage Return ^M case '+': // +- goto next line - if (--cmdcnt > 0) { - do_cmd(c); - } - dot_next(); - dot_skip_over_ws(); + do { + dot_next(); + dot_skip_over_ws(); + } while (--cmdcnt > 0); break; case 21: // ctrl-U scroll up half screen dot_scroll((rows - 2) / 2, -1); @@ -3236,10 +3233,9 @@ static void do_cmd(int c) case ' ': // move right case 'l': // move right case KEYCODE_RIGHT: // Cursor Key Right - if (--cmdcnt > 0) { - do_cmd(c); - } - dot_right(); + do { + dot_right(); + } while (--cmdcnt > 0); break; #if ENABLE_FEATURE_VI_YANKMARK case '"': // "- name a register to use for Delete/Yank @@ -3321,11 +3317,12 @@ static void do_cmd(int c) #endif /* FEATURE_VI_YANKMARK */ case '$': // $- goto end of line case KEYCODE_END: // Cursor Key End - if (--cmdcnt > 0) { + for (;;) { + dot = end_line(dot); + if (--cmdcnt > 0) + break; dot_next(); - do_cmd(c); } - dot = end_line(dot); break; case '%': // %- find matching char of pair () [] {} for (q = dot; q < end && *q != '\n'; q++) { @@ -3350,38 +3347,35 @@ static void do_cmd(int c) // //**** fall through to ... ';' case ';': // ;- look at rest of line for last forward char - if (--cmdcnt > 0) { - do_cmd(';'); - } - if (last_forward_char == 0) - break; - q = dot + 1; - while (q < end - 1 && *q != '\n' && *q != last_forward_char) { - q++; - } - if (*q == last_forward_char) - dot = q; + do { + if (last_forward_char == 0) + break; + q = dot + 1; + while (q < end - 1 && *q != '\n' && *q != last_forward_char) { + q++; + } + if (*q == last_forward_char) + dot = q; + } while (--cmdcnt > 0); break; case ',': // repeat latest 'f' in opposite direction - if (--cmdcnt > 0) { - do_cmd(','); - } if (last_forward_char == 0) break; - q = dot - 1; - while (q >= text && *q != '\n' && *q != last_forward_char) { - q--; - } - if (q >= text && *q == last_forward_char) - dot = q; + do { + q = dot - 1; + while (q >= text && *q != '\n' && *q != last_forward_char) { + q--; + } + if (q >= text && *q == last_forward_char) + dot = q; + } while (--cmdcnt > 0); break; case '-': // -- goto prev line - if (--cmdcnt > 0) { - do_cmd(c); - } - dot_prev(); - dot_skip_over_ws(); + do { + dot_prev(); + dot_skip_over_ws(); + } while (--cmdcnt > 0); break; #if ENABLE_FEATURE_VI_DOT_CMD case '.': // .- repeat the last modifying command @@ -3413,9 +3407,6 @@ static void do_cmd(int c) // user changed mind and erased the "/"- do nothing break; case 'N': // N- backward search for last pattern - if (--cmdcnt > 0) { - do_cmd(c); - } dir = BACK; // assume BACKWARD search p = dot - 1; if (last_search_pattern[0] == '?') { @@ -3427,41 +3418,41 @@ static void do_cmd(int c) case 'n': // n- repeat search for last pattern // search rest of text[] starting at next char // if search fails return orignal "p" not the "p+1" address - if (--cmdcnt > 0) { - do_cmd(c); - } + do { + const char *msg; dc3: - dir = FORWARD; // assume FORWARD search - p = dot + 1; - if (last_search_pattern[0] == '?') { - dir = BACK; - p = dot - 1; - } - dc4: - q = char_search(p, last_search_pattern + 1, dir, FULL); - if (q != NULL) { - dot = q; // good search, update "dot" - msg = ""; - goto dc2; - } - // no pattern found between "dot" and "end"- continue at top - p = text; - if (dir == BACK) { - p = end - 1; - } - q = char_search(p, last_search_pattern + 1, dir, FULL); - if (q != NULL) { // found something - dot = q; // found new pattern- goto it - msg = "search hit BOTTOM, continuing at TOP"; - if (dir == BACK) { - msg = "search hit TOP, continuing at BOTTOM"; + dir = FORWARD; // assume FORWARD search + p = dot + 1; + if (last_search_pattern[0] == '?') { + dir = BACK; + p = dot - 1; + } + dc4: + q = char_search(p, last_search_pattern + 1, dir, FULL); + if (q != NULL) { + dot = q; // good search, update "dot" + msg = NULL; + goto dc2; + } + // no pattern found between "dot" and "end"- continue at top + p = text; + if (dir == BACK) { + p = end - 1; + } + q = char_search(p, last_search_pattern + 1, dir, FULL); + if (q != NULL) { // found something + dot = q; // found new pattern- goto it + msg = "search hit BOTTOM, continuing at TOP"; + if (dir == BACK) { + msg = "search hit TOP, continuing at BOTTOM"; + } + } else { + msg = "Pattern not found"; } - } else { - msg = "Pattern not found"; - } dc2: - if (*msg) - status_line_bold("%s", msg); + if (msg) + status_line_bold("%s", msg); + } while (--cmdcnt > 0); break; case '{': // {- move backward paragraph q = char_search(dot, "\n\n", BACK, FULL); @@ -3580,18 +3571,17 @@ static void do_cmd(int c) case 'B': // B- back a blank-delimited Word case 'E': // E- end of a blank-delimited word case 'W': // W- forward a blank-delimited word - if (--cmdcnt > 0) { - do_cmd(c); - } dir = FORWARD; if (c == 'B') dir = BACK; - if (c == 'W' || isspace(dot[dir])) { - dot = skip_thing(dot, 1, dir, S_TO_WS); - dot = skip_thing(dot, 2, dir, S_OVER_WS); - } - if (c != 'W') - dot = skip_thing(dot, 1, dir, S_BEFORE_WS); + do { + if (c == 'W' || isspace(dot[dir])) { + dot = skip_thing(dot, 1, dir, S_TO_WS); + dot = skip_thing(dot, 2, dir, S_OVER_WS); + } + if (c != 'W') + dot = skip_thing(dot, 1, dir, S_BEFORE_WS); + } while (--cmdcnt > 0); break; case 'C': // C- Change to e-o-l case 'D': // D- delete to e-o-l @@ -3642,20 +3632,19 @@ static void do_cmd(int c) case 'i': // i- insert before current char case KEYCODE_INSERT: // Cursor Key Insert dc_i: - cmd_mode = 1; // start insrting + cmd_mode = 1; // start inserting break; case 'J': // J- join current and next lines together - if (--cmdcnt > 1) { - do_cmd(c); - } - dot_end(); // move to NL - if (dot < end - 1) { // make sure not last char in text[] - *dot++ = ' '; // replace NL with space - file_modified++; - while (isblank(*dot)) { // delete leading WS - dot_delete(); + do { + dot_end(); // move to NL + if (dot < end - 1) { // make sure not last char in text[] + *dot++ = ' '; // replace NL with space + file_modified++; + while (isblank(*dot)) { // delete leading WS + dot_delete(); + } } - } + } while (--cmdcnt > 0); end_cmd_q(); // stop adding to q break; case 'L': // L- goto bottom line on screen @@ -3699,20 +3688,19 @@ static void do_cmd(int c) case 'X': // X- delete char before dot case 'x': // x- delete the current char case 's': // s- substitute the current char - if (--cmdcnt > 0) { - do_cmd(c); - } dir = 0; if (c == 'X') dir = -1; - if (dot[dir] != '\n') { - if (c == 'X') - dot--; // delete prev char - dot = yank_delete(dot, dot, 0, YANKDEL); // delete char - } - if (c == 's') - goto dc_i; // start insrting + do { + if (dot[dir] != '\n') { + if (c == 'X') + dot--; // delete prev char + dot = yank_delete(dot, dot, 0, YANKDEL); // delete char + } + } while (--cmdcnt > 0); end_cmd_q(); // stop adding to q + if (c == 's') + goto dc_i; // start inserting break; case 'Z': // Z- if modified, {write}; exit // ZZ means to save file (if necessary), then exit @@ -3743,23 +3731,22 @@ static void do_cmd(int c) break; case 'b': // b- back a word case 'e': // e- end of word - if (--cmdcnt > 0) { - do_cmd(c); - } dir = FORWARD; if (c == 'b') dir = BACK; - if ((dot + dir) < text || (dot + dir) > end - 1) - break; - dot += dir; - if (isspace(*dot)) { - dot = skip_thing(dot, (c == 'e') ? 2 : 1, dir, S_OVER_WS); - } - if (isalnum(*dot) || *dot == '_') { - dot = skip_thing(dot, 1, dir, S_END_ALNUM); - } else if (ispunct(*dot)) { - dot = skip_thing(dot, 1, dir, S_END_PUNCT); - } + do { + if ((dot + dir) < text || (dot + dir) > end - 1) + break; + dot += dir; + if (isspace(*dot)) { + dot = skip_thing(dot, (c == 'e') ? 2 : 1, dir, S_OVER_WS); + } + if (isalnum(*dot) || *dot == '_') { + dot = skip_thing(dot, 1, dir, S_END_ALNUM); + } else if (ispunct(*dot)) { + dot = skip_thing(dot, 1, dir, S_END_PUNCT); + } + } while (--cmdcnt > 0); break; case 'c': // c- change something case 'd': // d- delete something @@ -3844,11 +3831,10 @@ static void do_cmd(int c) } case 'k': // k- goto prev line, same col case KEYCODE_UP: // cursor key Up - if (--cmdcnt > 0) { - do_cmd(c); - } - dot_prev(); - dot = move_to_col(dot, ccol + offset); // try stay in same col + do { + dot_prev(); + dot = move_to_col(dot, ccol + offset); // try stay in same col + } while (--cmdcnt > 0); break; case 'r': // r- replace the current char with user input c1 = get_one_char(); // get the replacement char @@ -3866,19 +3852,18 @@ static void do_cmd(int c) last_forward_char = 0; break; case 'w': // w- forward a word - if (--cmdcnt > 0) { - do_cmd(c); - } - if (isalnum(*dot) || *dot == '_') { // we are on ALNUM - dot = skip_thing(dot, 1, FORWARD, S_END_ALNUM); - } else if (ispunct(*dot)) { // we are on PUNCT - dot = skip_thing(dot, 1, FORWARD, S_END_PUNCT); - } - if (dot < end - 1) - dot++; // move over word - if (isspace(*dot)) { - dot = skip_thing(dot, 2, FORWARD, S_OVER_WS); - } + do { + if (isalnum(*dot) || *dot == '_') { // we are on ALNUM + dot = skip_thing(dot, 1, FORWARD, S_END_ALNUM); + } else if (ispunct(*dot)) { // we are on PUNCT + dot = skip_thing(dot, 1, FORWARD, S_END_PUNCT); + } + if (dot < end - 1) + dot++; // move over word + if (isspace(*dot)) { + dot = skip_thing(dot, 2, FORWARD, S_OVER_WS); + } + } while (--cmdcnt > 0); break; case 'z': // z- c1 = get_one_char(); // get the replacement char @@ -3894,17 +3879,16 @@ static void do_cmd(int c) dot = move_to_col(dot, cmdcnt - 1); // try to move to column break; case '~': // ~- flip the case of letters a-z -> A-Z - if (--cmdcnt > 0) { - do_cmd(c); - } - if (islower(*dot)) { - *dot = toupper(*dot); - file_modified++; - } else if (isupper(*dot)) { - *dot = tolower(*dot); - file_modified++; - } - dot_right(); + do { + if (islower(*dot)) { + *dot = toupper(*dot); + file_modified++; + } else if (isupper(*dot)) { + *dot = tolower(*dot); + file_modified++; + } + dot_right(); + } while (--cmdcnt > 0); end_cmd_q(); // stop adding to q break; //----- The Cursor and Function Keys -----------------------------