vi: move mark[i] pointers if text[] moves after realloc

While at it, optimized :s/find/repl/ a bit

function                                             old     new   delta
text_hole_make                                       120     150     +30
colon                                               2848    2844      -4

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
Denys Vlasenko 2012-01-31 14:10:26 +01:00
parent 7eaa03709b
commit 800a9a056a

View File

@ -1040,13 +1040,13 @@ static void colon(char *buf)
goto ret; goto ret;
#if ENABLE_FEATURE_VI_YANKMARK #if ENABLE_FEATURE_VI_YANKMARK
if (Ureg >= 0 && Ureg < 28 && reg[Ureg] != 0) { if (Ureg >= 0 && Ureg < 28) {
free(reg[Ureg]); // free orig line reg- for 'U' free(reg[Ureg]); // free orig line reg- for 'U'
reg[Ureg]= 0; reg[Ureg] = NULL;
} }
if (YDreg >= 0 && YDreg < 28 && reg[YDreg] != 0) { if (YDreg >= 0 && YDreg < 28) {
free(reg[YDreg]); // free default yank/delete register free(reg[YDreg]); // free default yank/delete register
reg[YDreg]= 0; reg[YDreg] = NULL;
} }
#endif #endif
// how many lines in text[]? // how many lines in text[]?
@ -1225,51 +1225,53 @@ static void colon(char *buf)
#endif /* FEATURE_VI_SET */ #endif /* FEATURE_VI_SET */
#if ENABLE_FEATURE_VI_SEARCH #if ENABLE_FEATURE_VI_SEARCH
} else if (cmd[0] == 's') { // substitute a pattern with a replacement pattern } else if (cmd[0] == 's') { // substitute a pattern with a replacement pattern
char *ls, *F, *R; char *F, *R, *flags;
int gflag; size_t len_F, len_R;
int gflag; // global replace flag
// F points to the "find" pattern // F points to the "find" pattern
// R points to the "replace" pattern // R points to the "replace" pattern
// replace the cmd line delimiters "/" with NULLs // replace the cmd line delimiters "/" with NULs
gflag = 0; // global replace flag
c = orig_buf[1]; // what is the delimiter c = orig_buf[1]; // what is the delimiter
F = orig_buf + 2; // start of "find" F = orig_buf + 2; // start of "find"
R = strchr(F, c); // middle delimiter R = strchr(F, c); // middle delimiter
if (!R) if (!R)
goto colon_s_fail; goto colon_s_fail;
len_F = R - F;
*R++ = '\0'; // terminate "find" *R++ = '\0'; // terminate "find"
buf1 = strchr(R, c); flags = strchr(R, c);
if (!buf1) if (!flags)
goto colon_s_fail; goto colon_s_fail;
*buf1++ = '\0'; // terminate "replace" len_R = flags - R;
if (*buf1 == 'g') { // :s/foo/bar/g *flags++ = '\0'; // terminate "replace"
buf1++; gflag = *flags;
gflag++; // turn on gflag
}
q = begin_line(q); q = begin_line(q);
if (b < 0) { // maybe :s/foo/bar/ if (b < 0) { // maybe :s/foo/bar/
q = begin_line(dot); // start with cur line q = begin_line(dot); // start with cur line
b = count_lines(text, q); // cur line number b = count_lines(text, q); // cur line number
} }
if (e < 0) if (e < 0)
e = b; // maybe :.s/foo/bar/ e = b; // maybe :.s/foo/bar/
for (i = b; i <= e; i++) { // so, :20,23 s \0 find \0 replace \0 for (i = b; i <= e; i++) { // so, :20,23 s \0 find \0 replace \0
ls = q; // orig line start char *ls = q; // orig line start
char *found;
vc4: vc4:
buf1 = char_search(q, F, FORWARD, LIMITED); // search cur line only for "find" found = char_search(q, F, FORWARD, LIMITED); // search cur line only for "find"
if (buf1) { if (found) {
uintptr_t bias; uintptr_t bias;
// we found the "find" pattern - delete it // we found the "find" pattern - delete it
text_hole_delete(buf1, buf1 + strlen(F) - 1); text_hole_delete(found, found + len_F - 1);
// inset the "replace" patern // inset the "replace" patern
bias = string_insert(buf1, R); // insert the string bias = string_insert(found, R); // insert the string
buf1 += bias; found += bias;
ls += bias; ls += bias;
/*q += bias; - recalculated anyway */ /*q += bias; - recalculated anyway */
// check for "global" :s/foo/bar/g // check for "global" :s/foo/bar/g
if (gflag == 1) { if (gflag == 'g') {
if ((buf1 + strlen(R)) < end_line(ls)) { if ((found + len_R) < end_line(ls)) {
q = buf1 + strlen(R); q = found + len_R;
goto vc4; // don't let q move past cur line goto vc4; // don't let q move past cur line
} }
} }
@ -2073,6 +2075,14 @@ static uintptr_t text_hole_make(char *p, int size) // at "p", make a 'size' byte
dot += bias; dot += bias;
end += bias; end += bias;
p += bias; p += bias;
#if ENABLE_FEATURE_VI_YANKMARK
{
int i;
for (i = 0; i < ARRAY_SIZE(mark); i++)
if (mark[i])
mark[i] += bias;
}
#endif
text = new_text; text = new_text;
} }
memmove(p + size, p, end - size - p); memmove(p + size, p, end - size - p);
@ -3305,7 +3315,7 @@ static void do_cmd(int c)
end_cmd_q(); // stop adding to q end_cmd_q(); // stop adding to q
break; break;
case 'U': // U- Undo; replace current line with original version case 'U': // U- Undo; replace current line with original version
if (reg[Ureg] != 0) { if (reg[Ureg] != NULL) {
p = begin_line(dot); p = begin_line(dot);
q = end_line(dot); q = end_line(dot);
p = text_hole_delete(p, q); // delete cur line p = text_hole_delete(p, q); // delete cur line