#endif
int save_do_all; // remember user specified 'g' flag
int save_do_ask; // remember user specified 'c' flag
- char_u *pat = NULL, *sub = NULL; // init for GCC
- size_t patlen = 0;
+ char_u *sub = NULL; // init for GCC
+ string_T pat = {NULL, 0};
int delimiter;
- int sublen;
+ size_t sublen;
int got_quit = FALSE;
int got_match = FALSE;
int which_pat;
char_u *p;
int save_State;
linenr_T first_line = 0; // first changed line
- linenr_T last_line= 0; // below last changed line AFTER the
+ linenr_T last_line = 0; // below last changed line AFTER the
// change
linenr_T old_line_count = curbuf->b_ml.ml_line_count;
linenr_T line2;
long nmatch; // number of lines in match
- char_u *sub_firstline; // allocated copy of first sub line
+ string_T sub_firstline; // allocated copy of first sub line
int endcolumn = FALSE; // cursor in last column when done
pos_T old_cursor = curwin->w_cursor;
int start_nsubs;
if (eap->cmd[0] == 's' && *cmd != NUL && !VIM_ISWHITE(*cmd)
&& vim_strchr((char_u *)"0123456789cegriIp|\"", *cmd) == NULL)
{
- // don't accept alphanumeric for separator
+ // don't accept alphanumeric for separator
if (check_regexp_delim(*cmd) == FAIL)
return;
#ifdef FEAT_EVAL
}
if (*cmd != '&')
which_pat = RE_SEARCH; // use last '/' pattern
- pat = (char_u *)""; // empty search pattern
- patlen = 0;
+ STR_LITERAL_SET(pat, ""); // empty search pattern
delimiter = *cmd++; // remember delimiter character
}
else // find the end of the regexp
{
which_pat = RE_LAST; // use last used regexp
delimiter = *cmd++; // remember delimiter character
- pat = cmd; // remember start of search pat
+ pat.string = cmd; // remember start of search pat
cmd = skip_regexp_ex(cmd, delimiter, magic_isset(),
&eap->arg, NULL, NULL);
+ pat.length = (size_t)(cmd - pat.string);
if (cmd[0] == delimiter) // end delimiter found
*cmd++ = NUL; // replace it with a NUL
- patlen = STRLEN(pat);
}
/*
emsg(_(e_no_previous_substitute_regular_expression));
return;
}
- pat = NULL; // search_regcomp() will use previous pattern
- patlen = 0;
+ pat.string = NULL; // search_regcomp() will use previous pattern
+ pat.length = 0;
sub = vim_strsave(old_sub);
if (sub == NULL)
return;
// more efficient.
// TODO: find a generic solution to make line-joining operations more
// efficient, avoid allocating a string that grows in size.
- if (pat != NULL && STRCMP(pat, "\\n") == 0
+ if (pat.string != NULL && STRCMP(pat.string, "\\n") == 0
&& *sub == NUL
&& (*cmd == NUL || (cmd[1] == NUL && (*cmd == 'g' || *cmd == 'l'
|| *cmd == 'p' || *cmd == '#'))))
}
if (!keeppatterns)
- save_re_pat(RE_SUBST, pat, patlen, magic_isset());
+ save_re_pat(RE_SUBST, pat.string, pat.length, magic_isset());
// put pattern in history
- add_to_history(HIST_SEARCH, pat, patlen, TRUE, NUL);
+ add_to_history(HIST_SEARCH, pat.string, pat.length, TRUE, NUL);
vim_free(sub);
return;
return;
}
- if (search_regcomp(pat, patlen, NULL, RE_SUBST, which_pat, SEARCH_HIS, ®match) == FAIL)
+ if (search_regcomp(pat.string, pat.length, NULL, RE_SUBST, which_pat, SEARCH_HIS, ®match) == FAIL)
{
if (subflags.do_error)
emsg(_(e_invalid_command));
else if (subflags.do_ic == 'I')
regmatch.rmm_ic = FALSE;
- sub_firstline = NULL;
+ sub_firstline.string = NULL;
+ sub_firstline.length = 0;
/*
* If the substitute pattern starts with "\=" then it's an expression.
colnr_T copycol;
colnr_T matchcol;
colnr_T prev_matchcol = MAXCOL;
- char_u *new_end, *new_start = NULL;
- unsigned new_start_len = 0;
- char_u *p1;
+ string_T new_start = {NULL, 0};
+ size_t new_start_size = 0;
+ char_u *new_end;
int did_sub = FALSE;
int lastone;
- int len, copy_len, needed_len;
+ size_t copy_len;
+ size_t needed_size;
long nmatch_tl = 0; // nr of lines matched below lnum
int do_again; // do it again after joining lines
int skip_match = FALSE;
* accordingly.
*
* The new text is built up in new_start[]. It has some extra
- * room to avoid using alloc()/free() too often. new_start_len is
+ * room to avoid using alloc()/free() too often. new_start_size is
* the length of the allocated memory at new_start.
*
* Make a copy of the old line, so it won't be taken away when
*/
for (;;)
{
+ string_T tmp;
+ char_u *p1;
+ size_t n;
+
// Advance "lnum" to the line where the match starts. The
// match does not start in the first line when there is a line
// break before \zs.
lnum += regmatch.startpos[0].lnum;
sub_firstlnum += regmatch.startpos[0].lnum;
nmatch -= regmatch.startpos[0].lnum;
- VIM_CLEAR(sub_firstline);
+ VIM_CLEAR_STRING(sub_firstline);
}
// Match might be after the last line for "\n\zs" matching at
if (lnum > curbuf->b_ml.ml_line_count)
break;
- if (sub_firstline == NULL)
+ if (sub_firstline.string == NULL)
{
- sub_firstline = vim_strnsave(ml_get(sub_firstlnum),
- ml_get_len(sub_firstlnum));
- if (sub_firstline == NULL)
+ sub_firstline.length = ml_get_len(sub_firstlnum);
+ sub_firstline.string =
+ vim_strnsave(ml_get(sub_firstlnum), sub_firstline.length);
+ if (sub_firstline.string == NULL)
{
- vim_free(new_start);
+ vim_free(new_start.string);
goto outofmem;
}
}
&& regmatch.endpos[0].lnum == 0
&& matchcol == regmatch.endpos[0].col)
{
- if (sub_firstline[matchcol] == NUL)
+ if (sub_firstline.string[matchcol] == NUL)
// We already were at the end of the line. Don't look
// for a match in this line again.
skip_match = TRUE;
{
// search for a match at next column
if (has_mbyte)
- matchcol += mb_ptr2len(sub_firstline + matchcol);
+ matchcol += mb_ptr2len(sub_firstline.string + matchcol);
else
++matchcol;
}
// Avoids that ":s/\nB\@=//gc" get stuck.
if (nmatch > 1)
{
- matchcol = (colnr_T)STRLEN(sub_firstline);
+ matchcol = (colnr_T)sub_firstline.length;
nmatch = 1;
skip_match = TRUE;
}
}
else
{
- char_u *orig_line = NULL;
+ string_T orig_line = {NULL, 0};
int len_change = 0;
int save_p_lz = p_lz;
#ifdef FEAT_FOLDING
// avoid calling update_screen() in vgetorpeek()
p_lz = FALSE;
- if (new_start != NULL)
+ if (new_start.string != NULL)
{
// There already was a substitution, we would
// like to show this to the user. We cannot
// really update the line, it would change
// what matches. Temporarily replace the line
// and change it back afterwards.
- orig_line = vim_strnsave(ml_get(lnum),
- ml_get_len(lnum));
- if (orig_line != NULL)
+ orig_line.length = ml_get_len(lnum);
+ orig_line.string = vim_strnsave(ml_get(lnum), orig_line.length);
+ if (orig_line.string != NULL)
{
- char_u *new_line = concat_str(new_start,
- sub_firstline + copycol);
+ string_T new_line;
- if (new_line == NULL)
- VIM_CLEAR(orig_line);
+ new_line.string = concat_str(new_start.string,
+ sub_firstline.string + copycol);
+ if (new_line.string == NULL)
+ VIM_CLEAR_STRING(orig_line);
else
{
+ new_line.length =
+ new_start.length + (sub_firstline.length - copycol);
// Position the cursor relative to the
// end of the line, the previous
// substitute may have inserted or
// deleted characters before the
// cursor.
- len_change = (int)STRLEN(new_line)
- - (int)STRLEN(orig_line);
+ len_change =
+ (int)new_line.length - (int)orig_line.length;
curwin->w_cursor.col += len_change;
- ml_replace(lnum, new_line, FALSE);
+ ml_replace(lnum, new_line.string, FALSE);
}
}
}
p_lz = save_p_lz;
// restore the line
- if (orig_line != NULL)
- ml_replace(lnum, orig_line, FALSE);
+ if (orig_line.string != NULL)
+ ml_replace(lnum, orig_line.string, FALSE);
}
need_wait_return = FALSE; // no hit-return prompt
// get stuck when pressing 'n'.
if (nmatch > 1)
{
- matchcol = (colnr_T)STRLEN(sub_firstline);
+ matchcol = (colnr_T)sub_firstline.length;
skip_match = TRUE;
}
goto skip;
#endif
// Get length of substitution part, including the NUL.
// When it fails sublen is zero.
- sublen = vim_regsub_multi(®match,
- sub_firstlnum - regmatch.startpos[0].lnum,
- sub, sub_firstline, 0,
- REGSUB_BACKSLASH
- | (magic_isset() ? REGSUB_MAGIC : 0));
+ sublen = (size_t)vim_regsub_multi(®match,
+ sub_firstlnum - regmatch.startpos[0].lnum,
+ sub, sub_firstline.string, 0,
+ REGSUB_BACKSLASH | (magic_isset() ? REGSUB_MAGIC : 0));
#ifdef FEAT_EVAL
--textlock;
// needed.
if (nmatch == 1)
{
- p1 = sub_firstline;
+ tmp.string = sub_firstline.string;
+ tmp.length = sub_firstline.length;
#ifdef FEAT_PROP_POPUP
if (curbuf->b_has_textprop)
{
apc_flags &= ~APC_SAVE_FOR_UNDO;
// Offset for column byte number of the text property
// in the resulting buffer afterwards.
- total_added += bytes_added;
+ total_added += (colnr_T)bytes_added;
}
#endif
}
total_added + regmatch.startpos[0].col,
-MAXCOL, apc_flags))
apc_flags &= ~APC_SAVE_FOR_UNDO;
- total_added -= (colnr_T)STRLEN(
- sub_firstline + regmatch.startpos[0].col);
+ total_added -=
+ (colnr_T)(sub_firstline.length - regmatch.startpos[0].col);
// Props in the last line may be moved or deleted
if (adjust_prop_columns(lastlnum,
}
}
#endif
- p1 = ml_get(lastlnum);
+ tmp.string = ml_get(lastlnum);
+ tmp.length = ml_get_len(lastlnum);
nmatch_tl += nmatch - 1;
#ifdef FEAT_PROP_POPUP
if (curbuf->b_has_textprop)
- total_added += (colnr_T)STRLEN(
- p1 + regmatch.endpos[0].col);
+ total_added +=
+ (colnr_T)(tmp.length - regmatch.endpos[0].col);
#endif
}
- copy_len = regmatch.startpos[0].col - copycol;
- needed_len = copy_len + ((unsigned)STRLEN(p1)
- - regmatch.endpos[0].col) + sublen + 1;
- if (new_start == NULL)
+
+ copy_len = (size_t)(regmatch.startpos[0].col - copycol);
+ needed_size = copy_len
+ + (tmp.length - (size_t)regmatch.endpos[0].col) + sublen + 1;
+
+ if (new_start.string == NULL)
{
/*
* Get some space for a temporary buffer to do the
* substitution into (and some extra space to avoid
* too many calls to alloc()/free()).
*/
- new_start_len = needed_len + 50;
- if ((new_start = alloc_clear(new_start_len)) == NULL)
+ new_start_size = needed_size + 50;
+ if ((new_start.string = alloc_clear(new_start_size)) == NULL)
goto outofmem;
- *new_start = NUL;
- new_end = new_start;
+ *new_start.string = NUL;
+ new_start.length = 0;
}
else
{
* substitution into. If not, make it larger (with a bit
* extra to avoid too many calls to alloc()/free()).
*/
- len = (unsigned)STRLEN(new_start);
- needed_len += len;
- if (needed_len > (int)new_start_len)
+ needed_size += new_start.length;
+ if (needed_size > new_start_size)
{
- new_start_len = needed_len + 50;
- if ((p1 = alloc_clear(new_start_len)) == NULL)
+ new_start_size = needed_size + 50;
+ if ((p1 = alloc_clear(new_start_size)) == NULL)
{
- vim_free(new_start);
+ vim_free(new_start.string);
goto outofmem;
}
- mch_memmove(p1, new_start, (size_t)(len + 1));
- vim_free(new_start);
- new_start = p1;
+ mch_memmove(p1, new_start.string, new_start.length + 1);
+ vim_free(new_start.string);
+ new_start.string = p1;
}
- new_end = new_start + len;
}
/*
* copy the text up to the part that matched
*/
- mch_memmove(new_end, sub_firstline + copycol, (size_t)copy_len);
- new_end += copy_len;
+ mch_memmove(new_start.string + new_start.length,
+ sub_firstline.string + copycol, copy_len);
+ new_start.length += copy_len;
- if ((int)new_start_len - copy_len < sublen)
- sublen = new_start_len - copy_len - 1;
+ // new text added here
+ new_end = new_start.string + new_start.length;
+
+ if (new_start_size - copy_len < sublen)
+ sublen = new_start_size - copy_len - 1;
#ifdef FEAT_EVAL
++textlock;
#endif
- (void)vim_regsub_multi(®match,
- sub_firstlnum - regmatch.startpos[0].lnum,
- sub, new_end, sublen,
- REGSUB_COPY | REGSUB_BACKSLASH
- | (magic_isset() ? REGSUB_MAGIC : 0));
+ n = (size_t)vim_regsub_multi(®match,
+ sub_firstlnum - regmatch.startpos[0].lnum,
+ sub, new_end, (int)sublen,
+ REGSUB_COPY | REGSUB_BACKSLASH | (magic_isset() ? REGSUB_MAGIC : 0));
+
+ if (n > 0)
+ new_start.length += n - 1; // remove 1 for the NUL
+
#ifdef FEAT_EVAL
--textlock;
#endif
if (nmatch > 1)
{
sub_firstlnum += nmatch - 1;
- vim_free(sub_firstline);
- sub_firstline = vim_strnsave(ml_get(sub_firstlnum),
- ml_get_len(sub_firstlnum));
- if (sub_firstline == NULL)
+ vim_free(sub_firstline.string);
+ sub_firstline.length = ml_get_len(sub_firstlnum);
+ sub_firstline.string =
+ vim_strnsave(ml_get(sub_firstlnum), sub_firstline.length);
+ if (sub_firstline.string == NULL)
{
- vim_free(new_start);
+ vim_free(new_start.string);
goto outofmem;
}
-
// When going beyond the last line, stop substituting.
if (sub_firstlnum <= line2)
do_again = TRUE;
{
// Already hit end of the buffer, sub_firstlnum is one
// less than what it ought to be.
- vim_free(sub_firstline);
- sub_firstline = vim_strsave((char_u *)"");
- if (sub_firstline == NULL)
+ vim_free(sub_firstline.string);
+ sub_firstline.string = vim_strnsave((char_u *)"", 0);
+ if (sub_firstline.string == NULL)
{
- vim_free(new_start);
+ vim_free(new_start.string);
goto outofmem;
}
+ sub_firstline.length = 0;
copycol = 0;
}
{
if (p1[0] == '\\' && p1[1] != NUL) // remove backslash
{
- STRMOVE(p1, p1 + 1);
+ n = (size_t)(new_start.length - (p1 - new_start.string));
+ mch_memmove(p1, p1 + 1, n + 1);
+ --new_start.length;
#ifdef FEAT_PROP_POPUP
if (curbuf->b_has_textprop)
{
// When text properties are changed, need to save
// for undo first, unless done already.
if (adjust_prop_columns(lnum,
- (colnr_T)(p1 - new_start), -1,
+ (colnr_T)(p1 - new_start.string), -1,
apc_flags))
apc_flags &= ~APC_SAVE_FOR_UNDO;
}
{
if (u_inssub(lnum) == OK) // prepare for undo
{
- colnr_T plen = (colnr_T)(p1 - new_start + 1);
+ colnr_T plen = (colnr_T)(p1 - new_start.string + 1);
*p1 = NUL; // truncate up to the CR
- ml_append(lnum - 1, new_start, plen, FALSE);
+ ml_append(lnum - 1, new_start.string, plen, FALSE);
mark_adjust(lnum + 1, (linenr_T)MAXLNUM, 1L, 0L);
if (subflags.do_ask)
appended_lines(lnum - 1, 1L);
// move the cursor to the new line, like Vi
++curwin->w_cursor.lnum;
// copy the rest
- STRMOVE(new_start, p1 + 1);
- p1 = new_start - 1;
+ n = new_start.length - (size_t)plen;
+ mch_memmove(new_start.string, p1 + 1, n + 1);
+ new_start.length = n;
+ p1 = new_start.string - 1;
}
}
else if (has_mbyte)
|| got_quit
|| lnum > line2
|| !(subflags.do_all || do_again)
- || (sub_firstline[matchcol] == NUL && nmatch <= 1
+ || (sub_firstline.string[matchcol] == NUL && nmatch <= 1
&& !re_multiline(regmatch.regprog)));
nmatch = -1;
matchcol, NULL)) == 0
|| regmatch.startpos[0].lnum > 0)
{
- if (new_start != NULL)
+ if (new_start.string != NULL)
{
/*
* Copy the rest of the line, that didn't match.
* have changed the number of characters. Same for
* "prev_matchcol".
*/
- STRCAT(new_start, sub_firstline + copycol);
- matchcol = (colnr_T)STRLEN(sub_firstline) - matchcol;
- prev_matchcol = (colnr_T)STRLEN(sub_firstline)
- - prev_matchcol;
+ STRCPY(new_start.string + new_start.length,
+ sub_firstline.string + copycol);
+ new_start.length += sub_firstline.length - (size_t)copycol;
+ matchcol = (colnr_T)(sub_firstline.length - matchcol);
+ prev_matchcol = (colnr_T)(sub_firstline.length
+ - prev_matchcol);
if (u_savesub(lnum) != OK)
break;
- ml_replace(lnum, new_start, TRUE);
+ ml_replace(lnum, new_start.string, TRUE);
#ifdef FEAT_PROP_POPUP
if (text_props != NULL)
add_text_props(lnum, text_props, text_prop_count);
}
sub_firstlnum = lnum;
- vim_free(sub_firstline); // free the temp buffer
- sub_firstline = new_start;
- new_start = NULL;
- matchcol = (colnr_T)STRLEN(sub_firstline) - matchcol;
- prev_matchcol = (colnr_T)STRLEN(sub_firstline)
- - prev_matchcol;
+ vim_free(sub_firstline.string); // free the temp buffer
+ sub_firstline.string = new_start.string;
+ sub_firstline.length = new_start.length;
+ new_start.string = NULL;
+ new_start.length = 0;
+ matchcol = (colnr_T)(sub_firstline.length - matchcol);
+ prev_matchcol = (colnr_T)(sub_firstline.length
+ - prev_matchcol);
copycol = 0;
}
if (nmatch == -1 && !lastone)
if (did_sub)
++sub_nlines;
- vim_free(new_start); // for when substitute was cancelled
- VIM_CLEAR(sub_firstline); // free the copy of the original line
+ vim_free(new_start.string); // for when substitute was cancelled
+ VIM_CLEAR_STRING(sub_firstline); // free the copy of the original line
}
line_breakcheck();
}
outofmem:
- vim_free(sub_firstline); // may have to free allocated copy of the line
+ vim_free(sub_firstline.string); // may have to free allocated copy of the line
#ifdef FEAT_PROP_POPUP
vim_free(text_props);