vim-patch:9.1.0824: too many strlen() calls in register.c (#31022)

Problem:  too many strlen() calls in register.c
Solution: refactor code, add string_T struct to keep track
          of string lengths (John Marriott)

closes: vim/vim#15952

79f6ffd388

Co-authored-by: John Marriott <basilisk@internode.on.net>
This commit is contained in:
zeertzjq 2024-11-01 17:34:19 +08:00 committed by GitHub
parent 9b357e30fd
commit cbd8b2c162
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 152 additions and 126 deletions

View File

@ -111,6 +111,12 @@ typedef kvec_withinit_t(Object, 16) ArrayBuilder;
#define STATIC_CSTR_AS_OBJ(s) STRING_OBJ(STATIC_CSTR_AS_STRING(s)) #define STATIC_CSTR_AS_OBJ(s) STRING_OBJ(STATIC_CSTR_AS_STRING(s))
#define STATIC_CSTR_TO_OBJ(s) STRING_OBJ(STATIC_CSTR_TO_STRING(s)) #define STATIC_CSTR_TO_OBJ(s) STRING_OBJ(STATIC_CSTR_TO_STRING(s))
#define API_CLEAR_STRING(s) \
do { \
XFREE_CLEAR(s.data); \
s.size = 0; \
} while (0)
// Helpers used by the generated msgpack-rpc api wrappers // Helpers used by the generated msgpack-rpc api wrappers
#define api_init_boolean #define api_init_boolean
#define api_init_integer #define api_init_integer

View File

@ -1317,15 +1317,15 @@ void nvim_put(ArrayOf(String) lines, String type, Boolean after, Boolean follow,
return; // Nothing to do. return; // Nothing to do.
} }
reg->y_array = arena_alloc(arena, lines.size * sizeof(uint8_t *), true); reg->y_array = arena_alloc(arena, lines.size * sizeof(String), true);
reg->y_size = lines.size; reg->y_size = lines.size;
for (size_t i = 0; i < lines.size; i++) { for (size_t i = 0; i < lines.size; i++) {
VALIDATE_T("line", kObjectTypeString, lines.items[i].type, { VALIDATE_T("line", kObjectTypeString, lines.items[i].type, {
return; return;
}); });
String line = lines.items[i].data.string; String line = lines.items[i].data.string;
reg->y_array[i] = arena_memdupz(arena, line.data, line.size); reg->y_array[i] = copy_string(line, arena);
memchrsub(reg->y_array[i], NUL, NL, line.size); memchrsub(reg->y_array[i].data, NUL, NL, line.size);
} }
finish_yankreg_from_object(reg, false); finish_yankreg_from_object(reg, false);

View File

@ -12,6 +12,7 @@
#include <uv.h> #include <uv.h>
#include "nvim/api/private/defs.h" #include "nvim/api/private/defs.h"
#include "nvim/api/private/helpers.h"
#include "nvim/ascii_defs.h" #include "nvim/ascii_defs.h"
#include "nvim/assert_defs.h" #include "nvim/assert_defs.h"
#include "nvim/autocmd.h" #include "nvim/autocmd.h"
@ -841,9 +842,9 @@ yankreg_T *copy_register(int name)
if (copy->y_size == 0) { if (copy->y_size == 0) {
copy->y_array = NULL; copy->y_array = NULL;
} else { } else {
copy->y_array = xcalloc(copy->y_size, sizeof(char *)); copy->y_array = xcalloc(copy->y_size, sizeof(String));
for (size_t i = 0; i < copy->y_size; i++) { for (size_t i = 0; i < copy->y_size; i++) {
copy->y_array[i] = xstrdup(reg->y_array[i]); copy->y_array[i] = copy_string(reg->y_array[i], NULL);
} }
} }
return copy; return copy;
@ -946,23 +947,24 @@ static int stuff_yank(int regname, char *p)
xfree(p); xfree(p);
return OK; return OK;
} }
const size_t plen = strlen(p);
yankreg_T *reg = get_yank_register(regname, YREG_YANK); yankreg_T *reg = get_yank_register(regname, YREG_YANK);
if (is_append_register(regname) && reg->y_array != NULL) { if (is_append_register(regname) && reg->y_array != NULL) {
char **pp = &(reg->y_array[reg->y_size - 1]); String *pp = &(reg->y_array[reg->y_size - 1]);
const size_t ppl = strlen(*pp); const size_t tmplen = pp->size + plen;
const size_t pl = strlen(p); char *tmp = xmalloc(tmplen + 1);
char *lp = xmalloc(ppl + pl + 1); memcpy(tmp, pp->data, pp->size);
memcpy(lp, *pp, ppl); memcpy(tmp + pp->size, p, plen);
memcpy(lp + ppl, p, pl); *(tmp + tmplen) = NUL;
*(lp + ppl + pl) = NUL;
xfree(p); xfree(p);
xfree(*pp); xfree(pp->data);
*pp = lp; *pp = cbuf_as_string(tmp, tmplen);
} else { } else {
free_register(reg); free_register(reg);
reg->additional_data = NULL; reg->additional_data = NULL;
reg->y_array = xmalloc(sizeof(char *)); reg->y_array = xmalloc(sizeof(String));
reg->y_array[0] = p; reg->y_array[0] = cbuf_as_string(p, plen);
reg->y_size = 1; reg->y_size = 1;
reg->y_type = kMTCharWise; reg->y_type = kMTCharWise;
} }
@ -983,7 +985,7 @@ static int execreg_lastc = NUL;
/// with a \. Lines that start with a comment "\ character are ignored. /// with a \. Lines that start with a comment "\ character are ignored.
/// @returns the concatenated line. The index of the line that should be /// @returns the concatenated line. The index of the line that should be
/// processed next is returned in idx. /// processed next is returned in idx.
static char *execreg_line_continuation(char **lines, size_t *idx) static char *execreg_line_continuation(String *lines, size_t *idx)
{ {
size_t i = *idx; size_t i = *idx;
assert(i > 0); assert(i > 0);
@ -996,7 +998,7 @@ static char *execreg_line_continuation(char **lines, size_t *idx)
// Any line not starting with \ or "\ is the start of the // Any line not starting with \ or "\ is the start of the
// command. // command.
while (--i > 0) { while (--i > 0) {
char *p = skipwhite(lines[i]); char *p = skipwhite(lines[i].data);
if (*p != '\\' && (p[0] != '"' || p[1] != '\\' || p[2] != ' ')) { if (*p != '\\' && (p[0] != '"' || p[1] != '\\' || p[2] != ' ')) {
break; break;
} }
@ -1004,9 +1006,9 @@ static char *execreg_line_continuation(char **lines, size_t *idx)
const size_t cmd_start = i; const size_t cmd_start = i;
// join all the lines // join all the lines
ga_concat(&ga, lines[cmd_start]); ga_concat(&ga, lines[cmd_start].data);
for (size_t j = cmd_start + 1; j <= cmd_end; j++) { for (size_t j = cmd_start + 1; j <= cmd_end; j++) {
char *p = skipwhite(lines[j]); char *p = skipwhite(lines[j].data);
if (*p == '\\') { if (*p == '\\') {
// Adjust the growsize to the current length to // Adjust the growsize to the current length to
// speed up concatenating many lines. // speed up concatenating many lines.
@ -1017,7 +1019,7 @@ static char *execreg_line_continuation(char **lines, size_t *idx)
} }
} }
ga_append(&ga, NUL); ga_append(&ga, NUL);
char *str = xstrdup(ga.ga_data); char *str = xmemdupz(ga.ga_data, (size_t)ga.ga_len);
ga_clear(&ga); ga_clear(&ga);
*idx = i; *idx = i;
@ -1110,7 +1112,7 @@ int do_execreg(int regname, int colon, int addcr, int silent)
} }
// Handle line-continuation for :@<register> // Handle line-continuation for :@<register>
char *str = reg->y_array[i]; char *str = reg->y_array[i].data;
bool free_str = false; bool free_str = false;
if (colon && i > 0) { if (colon && i > 0) {
char *p = skipwhite(str); char *p = skipwhite(str);
@ -1248,7 +1250,7 @@ int insert_reg(int regname, bool literally_arg)
if (u_save_cursor() == FAIL) { if (u_save_cursor() == FAIL) {
return FAIL; return FAIL;
} }
del_chars(mb_charlen(reg->y_array[0]), true); del_chars(mb_charlen(reg->y_array[0].data), true);
curpos = curwin->w_cursor; curpos = curwin->w_cursor;
if (oneright() == FAIL) { if (oneright() == FAIL) {
// hit end of line, need to put forward (after the current position) // hit end of line, need to put forward (after the current position)
@ -1261,7 +1263,7 @@ int insert_reg(int regname, bool literally_arg)
AppendCharToRedobuff(regname); AppendCharToRedobuff(regname);
do_put(regname, NULL, dir, 1, PUT_CURSEND); do_put(regname, NULL, dir, 1, PUT_CURSEND);
} else { } else {
stuffescaped(reg->y_array[i], literally); stuffescaped(reg->y_array[i].data, literally);
} }
// Insert a newline between lines and after last line if // Insert a newline between lines and after last line if
// y_type is kMTLineWise. // y_type is kMTLineWise.
@ -1384,7 +1386,7 @@ bool cmdline_paste_reg(int regname, bool literally_arg, bool remcr)
} }
for (size_t i = 0; i < reg->y_size; i++) { for (size_t i = 0; i < reg->y_size; i++) {
cmdline_paste_str(reg->y_array[i], literally); cmdline_paste_str(reg->y_array[i].data, literally);
// Insert ^M between lines, unless `remcr` is true. // Insert ^M between lines, unless `remcr` is true.
if (i < reg->y_size - 1 && !remcr) { if (i < reg->y_size - 1 && !remcr) {
@ -2504,7 +2506,7 @@ void free_register(yankreg_T *reg)
} }
for (size_t i = reg->y_size; i-- > 0;) { // from y_size - 1 to 0 included for (size_t i = reg->y_size; i-- > 0;) { // from y_size - 1 to 0 included
xfree(reg->y_array[i]); API_CLEAR_STRING(reg->y_array[i]);
} }
XFREE_CLEAR(reg->y_array); XFREE_CLEAR(reg->y_array);
} }
@ -2533,7 +2535,6 @@ bool op_yank(oparg_T *oap, bool message)
op_yank_reg(oap, message, reg, is_append_register(oap->regname)); op_yank_reg(oap, message, reg, is_append_register(oap->regname));
set_clipboard(oap->regname, reg); set_clipboard(oap->regname, reg);
do_autocmd_textyankpost(oap, reg); do_autocmd_textyankpost(oap, reg);
return true; return true;
} }
@ -2569,7 +2570,7 @@ static void op_yank_reg(oparg_T *oap, bool message, yankreg_T *reg, bool append)
reg->y_size = yanklines; reg->y_size = yanklines;
reg->y_type = yank_type; // set the yank register type reg->y_type = yank_type; // set the yank register type
reg->y_width = 0; reg->y_width = 0;
reg->y_array = xcalloc(yanklines, sizeof(char *)); reg->y_array = xcalloc(yanklines, sizeof(String));
reg->additional_data = NULL; reg->additional_data = NULL;
reg->timestamp = os_time(); reg->timestamp = os_time();
@ -2593,11 +2594,16 @@ static void op_yank_reg(oparg_T *oap, bool message, yankreg_T *reg, bool append)
break; break;
case kMTLineWise: case kMTLineWise:
reg->y_array[y_idx] = xstrdup(ml_get(lnum)); reg->y_array[y_idx] = cbuf_to_string(ml_get(lnum), (size_t)ml_get_len(lnum));
break; break;
case kMTCharWise: case kMTCharWise:
charwise_block_prep(oap->start, oap->end, &bd, lnum, oap->inclusive); charwise_block_prep(oap->start, oap->end, &bd, lnum, oap->inclusive);
// make sure bd.textlen is not longer than the text
int tmp = (int)strlen(bd.textstart);
if (tmp < bd.textlen) {
bd.textlen = tmp;
}
yank_copy_line(reg, &bd, y_idx, false); yank_copy_line(reg, &bd, y_idx, false);
break; break;
@ -2609,7 +2615,7 @@ static void op_yank_reg(oparg_T *oap, bool message, yankreg_T *reg, bool append)
if (curr != reg) { // append the new block to the old block if (curr != reg) { // append the new block to the old block
size_t j; size_t j;
char **new_ptr = xmalloc(sizeof(char *) * (curr->y_size + reg->y_size)); String *new_ptr = xmalloc(sizeof(String) * (curr->y_size + reg->y_size));
for (j = 0; j < curr->y_size; j++) { for (j = 0; j < curr->y_size; j++) {
new_ptr[j] = curr->y_array[j]; new_ptr[j] = curr->y_array[j];
} }
@ -2625,13 +2631,16 @@ static void op_yank_reg(oparg_T *oap, bool message, yankreg_T *reg, bool append)
// the new block, unless being Vi compatible. // the new block, unless being Vi compatible.
if (curr->y_type == kMTCharWise if (curr->y_type == kMTCharWise
&& vim_strchr(p_cpo, CPO_REGAPPEND) == NULL) { && vim_strchr(p_cpo, CPO_REGAPPEND) == NULL) {
char *pnew = xmalloc(strlen(curr->y_array[curr->y_size - 1]) char *pnew = xmalloc(curr->y_array[curr->y_size - 1].size
+ strlen(reg->y_array[0]) + 1); + reg->y_array[0].size + 1);
STRCPY(pnew, curr->y_array[--j]); j--;
strcat(pnew, reg->y_array[0]); STRCPY(pnew, curr->y_array[j].data);
xfree(curr->y_array[j]); STRCPY(pnew + curr->y_array[j].size, reg->y_array[0].data);
xfree(reg->y_array[0]); xfree(curr->y_array[j].data);
curr->y_array[j++] = pnew; curr->y_array[j] = cbuf_as_string(pnew,
curr->y_array[j].size + reg->y_array[0].size);
j++;
API_CLEAR_STRING(reg->y_array[0]);
y_idx = 1; y_idx = 1;
} else { } else {
y_idx = 0; y_idx = 0;
@ -2698,7 +2707,7 @@ static void yank_copy_line(yankreg_T *reg, struct block_def *bd, size_t y_idx,
int size = bd->startspaces + bd->endspaces + bd->textlen; int size = bd->startspaces + bd->endspaces + bd->textlen;
assert(size >= 0); assert(size >= 0);
char *pnew = xmallocz((size_t)size); char *pnew = xmallocz((size_t)size);
reg->y_array[y_idx] = pnew; reg->y_array[y_idx].data = pnew;
memset(pnew, ' ', (size_t)bd->startspaces); memset(pnew, ' ', (size_t)bd->startspaces);
pnew += bd->startspaces; pnew += bd->startspaces;
memmove(pnew, bd->textstart, (size_t)bd->textlen); memmove(pnew, bd->textstart, (size_t)bd->textlen);
@ -2714,6 +2723,7 @@ static void yank_copy_line(yankreg_T *reg, struct block_def *bd, size_t y_idx,
} }
} }
*pnew = NUL; *pnew = NUL;
reg->y_array[y_idx].size = (size_t)(pnew - reg->y_array[y_idx].data);
} }
/// Execute autocommands for TextYankPost. /// Execute autocommands for TextYankPost.
@ -2739,7 +2749,7 @@ static void do_autocmd_textyankpost(oparg_T *oap, yankreg_T *reg)
// The yanked text contents. // The yanked text contents.
list_T *const list = tv_list_alloc((ptrdiff_t)reg->y_size); list_T *const list = tv_list_alloc((ptrdiff_t)reg->y_size);
for (size_t i = 0; i < reg->y_size; i++) { for (size_t i = 0; i < reg->y_size; i++) {
tv_list_append_string(list, reg->y_array[i], -1); tv_list_append_string(list, reg->y_array[i].data, -1);
} }
tv_list_set_lock(list, VAR_FIXED); tv_list_set_lock(list, VAR_FIXED);
tv_dict_add_list(dict, S_LEN("regcontents"), list); tv_dict_add_list(dict, S_LEN("regcontents"), list);
@ -2792,25 +2802,13 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags)
size_t y_size; size_t y_size;
int y_width = 0; int y_width = 0;
colnr_T vcol = 0; colnr_T vcol = 0;
int incr = 0; String *y_array = NULL;
struct block_def bd;
char **y_array = NULL;
linenr_T nr_lines = 0; linenr_T nr_lines = 0;
int indent;
int orig_indent = 0; // init for gcc
int indent_diff = 0; // init for gcc
bool first_indent = true;
int lendiff = 0;
char *insert_string = NULL;
bool allocated = false; bool allocated = false;
const pos_T orig_start = curbuf->b_op_start; const pos_T orig_start = curbuf->b_op_start;
const pos_T orig_end = curbuf->b_op_end; const pos_T orig_end = curbuf->b_op_end;
unsigned cur_ve_flags = get_ve_flags(curwin); unsigned cur_ve_flags = get_ve_flags(curwin);
if (flags & PUT_FIXINDENT) {
orig_indent = get_indent();
}
curbuf->b_op_start = curwin->w_cursor; // default for '[ mark curbuf->b_op_start = curwin->w_cursor; // default for '[ mark
curbuf->b_op_end = curwin->w_cursor; // default for '] mark curbuf->b_op_end = curwin->w_cursor; // default for '] mark
@ -2898,8 +2896,9 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags)
// For special registers '%' (file name), '#' (alternate file name) and // For special registers '%' (file name), '#' (alternate file name) and
// ':' (last command line), etc. we have to create a fake yank register. // ':' (last command line), etc. we have to create a fake yank register.
if (!reg && get_spec_reg(regname, &insert_string, &allocated, true)) { String insert_string = STRING_INIT;
if (insert_string == NULL) { if (!reg && get_spec_reg(regname, &insert_string.data, &allocated, true)) {
if (insert_string.data == NULL) {
return; return;
} }
} }
@ -2912,7 +2911,8 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags)
} }
} }
if (insert_string != NULL) { if (insert_string.data != NULL) {
insert_string.size = strlen(insert_string.data);
y_type = kMTCharWise; y_type = kMTCharWise;
if (regname == '=') { if (regname == '=') {
// For the = register we need to split the string at NL // For the = register we need to split the string at NL
@ -2920,29 +2920,37 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags)
// Loop twice: count the number of lines and save them. // Loop twice: count the number of lines and save them.
while (true) { while (true) {
y_size = 0; y_size = 0;
char *ptr = insert_string; char *ptr = insert_string.data;
size_t ptrlen = insert_string.size;
while (ptr != NULL) { while (ptr != NULL) {
if (y_array != NULL) { if (y_array != NULL) {
y_array[y_size] = ptr; y_array[y_size].data = ptr;
} }
y_size++; y_size++;
ptr = vim_strchr(ptr, '\n'); char *tmp = vim_strchr(ptr, '\n');
if (ptr != NULL) { if (tmp == NULL) {
if (y_array != NULL) { if (y_array != NULL) {
*ptr = NUL; y_array[y_size - 1].size = ptrlen;
} }
ptr++; } else {
if (y_array != NULL) {
*tmp = NUL;
y_array[y_size - 1].size = (size_t)(tmp - ptr);
ptrlen -= y_array[y_size - 1].size + 1;
}
tmp++;
// A trailing '\n' makes the register linewise. // A trailing '\n' makes the register linewise.
if (*ptr == NUL) { if (*tmp == NUL) {
y_type = kMTLineWise; y_type = kMTLineWise;
break; break;
} }
} }
ptr = tmp;
} }
if (y_array != NULL) { if (y_array != NULL) {
break; break;
} }
y_array = xmalloc(y_size * sizeof(char *)); y_array = xmalloc(y_size * sizeof(String));
} }
} else { } else {
y_size = 1; // use fake one-line yank register y_size = 1; // use fake one-line yank register
@ -2976,14 +2984,16 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags)
goto end; goto end;
} }
char *curline = get_cursor_line_ptr(); char *curline = get_cursor_line_ptr();
char *p = curline + curwin->w_cursor.col; char *p = get_cursor_pos_ptr();
char *const p_orig = p;
const size_t plen = (size_t)get_cursor_pos_len();
if (dir == FORWARD && *p != NUL) { if (dir == FORWARD && *p != NUL) {
MB_PTR_ADV(p); MB_PTR_ADV(p);
} }
// we need this later for the correct extmark_splice() event // we need this later for the correct extmark_splice() event
split_pos = (colnr_T)(p - curline); split_pos = (colnr_T)(p - curline);
char *ptr = xstrdup(p); char *ptr = xmemdupz(p, plen - (size_t)(p - p_orig));
ml_append(curwin->w_cursor.lnum, ptr, 0, false); ml_append(curwin->w_cursor.lnum, ptr, 0, false);
xfree(ptr); xfree(ptr);
@ -3047,8 +3057,6 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags)
goto end; goto end;
} }
int yanklen = (int)strlen(y_array[0]);
if (cur_ve_flags == VE_ALL && y_type == kMTCharWise) { if (cur_ve_flags == VE_ALL && y_type == kMTCharWise) {
if (gchar_cursor() == TAB) { if (gchar_cursor() == TAB) {
int viscol = getviscol(); int viscol = getviscol();
@ -3072,6 +3080,8 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags)
// Block mode // Block mode
if (y_type == kMTBlockWise) { if (y_type == kMTBlockWise) {
int incr = 0;
struct block_def bd;
int c = gchar_cursor(); int c = gchar_cursor();
colnr_T endcol2 = 0; colnr_T endcol2 = 0;
@ -3164,14 +3174,14 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags)
} }
} }
yanklen = (int)strlen(y_array[i]); const int yanklen = (int)y_array[i].size;
if ((flags & PUT_BLOCK_INNER) == 0) { if ((flags & PUT_BLOCK_INNER) == 0) {
// calculate number of spaces required to fill right side of block // calculate number of spaces required to fill right side of block
spaces = y_width + 1; spaces = y_width + 1;
cstype = init_charsize_arg(&csarg, curwin, 0, y_array[i]); cstype = init_charsize_arg(&csarg, curwin, 0, y_array[i].data);
ci = utf_ptr2StrCharInfo(y_array[i]); ci = utf_ptr2StrCharInfo(y_array[i].data);
while (*ci.ptr != NUL) { while (*ci.ptr != NUL) {
spaces -= win_charsize(cstype, 0, ci.ptr, ci.chr.value, &csarg).width; spaces -= win_charsize(cstype, 0, ci.ptr, ci.chr.value, &csarg).width;
ci = utfc_next(ci); ci = utfc_next(ci);
@ -3202,7 +3212,7 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags)
// insert the new text // insert the new text
for (int j = 0; j < count; j++) { for (int j = 0; j < count; j++) {
memmove(ptr, y_array[i], (size_t)yanklen); memmove(ptr, y_array[i].data, (size_t)yanklen);
ptr += yanklen; ptr += yanklen;
// insert block's trailing spaces only if there's text behind // insert block's trailing spaces only if there's text behind
@ -3254,6 +3264,8 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags)
curwin->w_cursor.lnum = lnum; curwin->w_cursor.lnum = lnum;
} }
} else { } else {
const int yanklen = (int)y_array[0].size;
// Character or Line mode // Character or Line mode
if (y_type == kMTCharWise) { if (y_type == kMTCharWise) {
// if type is kMTCharWise, FORWARD is the same as BACKWARD on the next // if type is kMTCharWise, FORWARD is the same as BACKWARD on the next
@ -3326,10 +3338,10 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags)
memmove(newp, oldp, (size_t)col); memmove(newp, oldp, (size_t)col);
char *ptr = newp + col; char *ptr = newp + col;
for (size_t i = 0; i < (size_t)count; i++) { for (size_t i = 0; i < (size_t)count; i++) {
memmove(ptr, y_array[0], (size_t)yanklen); memmove(ptr, y_array[0].data, (size_t)yanklen);
ptr += yanklen; ptr += yanklen;
} }
STRMOVE(ptr, oldp + col); memmove(ptr, oldp + col, (size_t)(oldlen - col) + 1); // +1 for NUL
ml_replace(lnum, newp, false); ml_replace(lnum, newp, false);
// compute the byte offset for the last character // compute the byte offset for the last character
@ -3367,6 +3379,15 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags)
} }
} else { } else {
linenr_T new_lnum = new_cursor.lnum; linenr_T new_lnum = new_cursor.lnum;
int indent;
int orig_indent = 0;
int indent_diff = 0; // init for gcc
bool first_indent = true;
int lendiff = 0;
if (flags & PUT_FIXINDENT) {
orig_indent = get_indent();
}
// Insert at least one line. When y_type is kMTCharWise, break the first // Insert at least one line. When y_type is kMTCharWise, break the first
// line in two. // line in two.
@ -3378,10 +3399,11 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags)
// Then append y_array[0] to first line. // Then append y_array[0] to first line.
lnum = new_cursor.lnum; lnum = new_cursor.lnum;
char *ptr = ml_get(lnum) + col; char *ptr = ml_get(lnum) + col;
totlen = strlen(y_array[y_size - 1]); size_t ptrlen = (size_t)ml_get_len(lnum) - (size_t)col;
char *newp = xmalloc((size_t)ml_get_len(lnum) - (size_t)col + totlen + 1); totlen = y_array[y_size - 1].size;
STRCPY(newp, y_array[y_size - 1]); char *newp = xmalloc(ptrlen + totlen + 1);
strcat(newp, ptr); STRCPY(newp, y_array[y_size - 1].data);
STRCPY(newp + totlen, ptr);
// insert second line // insert second line
ml_append(lnum, newp, 0, false); ml_append(lnum, newp, 0, false);
new_lnum++; new_lnum++;
@ -3392,7 +3414,7 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags)
// copy first part of line // copy first part of line
memmove(newp, oldp, (size_t)col); memmove(newp, oldp, (size_t)col);
// append to first line // append to first line
memmove(newp + col, y_array[0], (size_t)yanklen + 1); memmove(newp + col, y_array[0].data, (size_t)yanklen + 1);
ml_replace(lnum, newp, false); ml_replace(lnum, newp, false);
curwin->w_cursor.lnum = lnum; curwin->w_cursor.lnum = lnum;
@ -3401,7 +3423,7 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags)
for (; i < y_size; i++) { for (; i < y_size; i++) {
if ((y_type != kMTCharWise || i < y_size - 1)) { if ((y_type != kMTCharWise || i < y_size - 1)) {
if (ml_append(lnum, y_array[i], 0, false) == FAIL) { if (ml_append(lnum, y_array[i].data, 0, false) == FAIL) {
goto error; goto error;
} }
new_lnum++; new_lnum++;
@ -3440,9 +3462,9 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags)
if (y_type == kMTCharWise if (y_type == kMTCharWise
|| (y_type == kMTLineWise && (flags & PUT_LINE_SPLIT))) { || (y_type == kMTLineWise && (flags & PUT_LINE_SPLIT))) {
for (i = 0; i < y_size - 1; i++) { for (i = 0; i < y_size - 1; i++) {
totsize += (bcount_t)strlen(y_array[i]) + 1; totsize += (bcount_t)y_array[i].size + 1;
} }
lastsize = (int)strlen(y_array[y_size - 1]); lastsize = (int)y_array[y_size - 1].size;
totsize += lastsize; totsize += lastsize;
} }
if (y_type == kMTCharWise) { if (y_type == kMTCharWise) {
@ -3486,13 +3508,13 @@ error:
// Put the '] mark on the first byte of the last inserted character. // Put the '] mark on the first byte of the last inserted character.
// Correct the length for change in indent. // Correct the length for change in indent.
curbuf->b_op_end.lnum = new_lnum; curbuf->b_op_end.lnum = new_lnum;
size_t len = strlen(y_array[y_size - 1]); col = (colnr_T)y_array[y_size - 1].size - lendiff;
col = (colnr_T)len - lendiff;
if (col > 1) { if (col > 1) {
curbuf->b_op_end.col = col - 1; curbuf->b_op_end.col = col - 1;
if (len > 0) { if (y_array[y_size - 1].size > 0) {
curbuf->b_op_end.col -= utf_head_off(y_array[y_size - 1], curbuf->b_op_end.col -= utf_head_off(y_array[y_size - 1].data,
y_array[y_size - 1] + len - 1); y_array[y_size - 1].data
+ y_array[y_size - 1].size - 1);
} }
} else { } else {
curbuf->b_op_end.col = 0; curbuf->b_op_end.col = 0;
@ -3550,7 +3572,7 @@ end:
curbuf->b_op_end = orig_end; curbuf->b_op_end = orig_end;
} }
if (allocated) { if (allocated) {
xfree(insert_string); xfree(insert_string.data);
} }
if (regname == '=') { if (regname == '=') {
xfree(y_array); xfree(y_array);
@ -3672,7 +3694,7 @@ void ex_display(exarg_T *eap)
bool do_show = false; bool do_show = false;
for (size_t j = 0; !do_show && j < yb->y_size; j++) { for (size_t j = 0; !do_show && j < yb->y_size; j++) {
do_show = !message_filtered(yb->y_array[j]); do_show = !message_filtered(yb->y_array[j].data);
} }
if (do_show || yb->y_size == 0) { if (do_show || yb->y_size == 0) {
@ -3690,7 +3712,7 @@ void ex_display(exarg_T *eap)
msg_puts_attr("^J", attr); msg_puts_attr("^J", attr);
n -= 2; n -= 2;
} }
for (p = yb->y_array[j]; for (p = yb->y_array[j].data;
*p != NUL && (n -= ptr2cells(p)) >= 0; p++) { *p != NUL && (n -= ptr2cells(p)) >= 0; p++) {
int clen = utfc_ptr2len(p); int clen = utfc_ptr2len(p);
msg_outtrans_len(p, clen, 0); msg_outtrans_len(p, clen, 0);
@ -4849,7 +4871,7 @@ void *get_reg_contents(int regname, int flags)
if (flags & kGRegList) { if (flags & kGRegList) {
list_T *const list = tv_list_alloc((ptrdiff_t)reg->y_size); list_T *const list = tv_list_alloc((ptrdiff_t)reg->y_size);
for (size_t i = 0; i < reg->y_size; i++) { for (size_t i = 0; i < reg->y_size; i++) {
tv_list_append_string(list, reg->y_array[i], -1); tv_list_append_string(list, reg->y_array[i].data, -1);
} }
return list; return list;
@ -4858,9 +4880,8 @@ void *get_reg_contents(int regname, int flags)
// Compute length of resulting string. // Compute length of resulting string.
size_t len = 0; size_t len = 0;
for (size_t i = 0; i < reg->y_size; i++) { for (size_t i = 0; i < reg->y_size; i++) {
len += strlen(reg->y_array[i]); len += reg->y_array[i].size;
// Insert a newline between lines and after last line if // Insert a newline between lines and after last line if y_type is kMTLineWise.
// y_type is kMTLineWise.
if (reg->y_type == kMTLineWise || i < reg->y_size - 1) { if (reg->y_type == kMTLineWise || i < reg->y_size - 1) {
len++; len++;
} }
@ -4871,11 +4892,10 @@ void *get_reg_contents(int regname, int flags)
// Copy the lines of the yank register into the string. // Copy the lines of the yank register into the string.
len = 0; len = 0;
for (size_t i = 0; i < reg->y_size; i++) { for (size_t i = 0; i < reg->y_size; i++) {
STRCPY(retval + len, reg->y_array[i]); STRCPY(retval + len, reg->y_array[i].data);
len += strlen(retval + len); len += reg->y_array[i].size;
// Insert a NL between lines and after the last line if y_type is // Insert a newline between lines and after the last line if y_type is kMTLineWise.
// kMTLineWise.
if (reg->y_type == kMTLineWise || i < reg->y_size - 1) { if (reg->y_type == kMTLineWise || i < reg->y_size - 1) {
retval[len++] = '\n'; retval[len++] = '\n';
} }
@ -4993,8 +5013,7 @@ void write_reg_contents_ex(int name, const char *str, ssize_t len, bool must_app
semsg(_(e_nobufnr), (int64_t)num); semsg(_(e_nobufnr), (int64_t)num);
} }
} else { } else {
buf = buflist_findnr(buflist_findpat(str, str + strlen(str), buf = buflist_findnr(buflist_findpat(str, str + len, true, false, false));
true, false, false));
} }
if (buf == NULL) { if (buf == NULL) {
return; return;
@ -5090,7 +5109,7 @@ static void str_to_reg(yankreg_T *y_ptr, MotionType yank_type, const char *str,
} }
// Grow the register array to hold the pointers to the new lines. // Grow the register array to hold the pointers to the new lines.
char **pp = xrealloc(y_ptr->y_array, (y_ptr->y_size + newlines) * sizeof(char *)); String *pp = xrealloc(y_ptr->y_array, (y_ptr->y_size + newlines) * sizeof(String));
y_ptr->y_array = pp; y_ptr->y_array = pp;
size_t lnum = y_ptr->y_size; // The current line number. size_t lnum = y_ptr->y_size; // The current line number.
@ -5102,7 +5121,7 @@ static void str_to_reg(yankreg_T *y_ptr, MotionType yank_type, const char *str,
if (str_list) { if (str_list) {
for (char **ss = (char **)str; *ss != NULL; ss++, lnum++) { for (char **ss = (char **)str; *ss != NULL; ss++, lnum++) {
size_t ss_len = strlen(*ss); size_t ss_len = strlen(*ss);
pp[lnum] = xmemdupz(*ss, ss_len); pp[lnum] = cbuf_to_string(*ss, ss_len);
maxlen = MAX(maxlen, ss_len); maxlen = MAX(maxlen, ss_len);
} }
} else { } else {
@ -5115,22 +5134,22 @@ static void str_to_reg(yankreg_T *y_ptr, MotionType yank_type, const char *str,
maxlen = MAX(maxlen, line_len); maxlen = MAX(maxlen, line_len);
// When appending, copy the previous line and free it after. // When appending, copy the previous line and free it after.
size_t extra = append ? strlen(pp[--lnum]) : 0; size_t extra = append ? pp[--lnum].size : 0;
char *s = xmallocz(line_len + extra); char *s = xmallocz(line_len + extra);
if (extra > 0) { if (extra > 0) {
memcpy(s, pp[lnum], extra); memcpy(s, pp[lnum].data, extra);
} }
memcpy(s + extra, start, line_len); memcpy(s + extra, start, line_len);
size_t s_len = extra + line_len; size_t s_len = extra + line_len;
if (append) { if (append) {
xfree(pp[lnum]); xfree(pp[lnum].data);
append = false; // only first line is appended append = false; // only first line is appended
} }
pp[lnum] = s; pp[lnum] = cbuf_as_string(s, s_len);
// Convert NULs to '\n' to prevent truncation. // Convert NULs to '\n' to prevent truncation.
memchrsub(pp[lnum], NUL, '\n', s_len); memchrsub(pp[lnum].data, NUL, '\n', s_len);
} }
} }
y_ptr->y_type = yank_type; y_ptr->y_type = yank_type;
@ -6421,7 +6440,7 @@ bool prepare_yankreg_from_object(yankreg_T *reg, String regtype, size_t lines)
void finish_yankreg_from_object(yankreg_T *reg, bool clipboard_adjust) void finish_yankreg_from_object(yankreg_T *reg, bool clipboard_adjust)
{ {
if (reg->y_size > 0 && strlen(reg->y_array[reg->y_size - 1]) == 0) { if (reg->y_size > 0 && reg->y_array[reg->y_size - 1].size == 0) {
// a known-to-be charwise yank might have a final linebreak // a known-to-be charwise yank might have a final linebreak
// but otherwise there is no line after the final newline // but otherwise there is no line after the final newline
if (reg->y_type != kMTCharWise) { if (reg->y_type != kMTCharWise) {
@ -6441,7 +6460,7 @@ void finish_yankreg_from_object(yankreg_T *reg, bool clipboard_adjust)
if (reg->y_type == kMTBlockWise) { if (reg->y_type == kMTBlockWise) {
size_t maxlen = 0; size_t maxlen = 0;
for (size_t i = 0; i < reg->y_size; i++) { for (size_t i = 0; i < reg->y_size; i++) {
size_t rowlen = strlen(reg->y_array[i]); size_t rowlen = reg->y_array[i].size;
maxlen = MAX(maxlen, rowlen); maxlen = MAX(maxlen, rowlen);
} }
assert(maxlen <= INT_MAX); assert(maxlen <= INT_MAX);
@ -6511,7 +6530,7 @@ static bool get_clipboard(int name, yankreg_T **target, bool quiet)
reg->y_type = kMTUnknown; reg->y_type = kMTUnknown;
} }
reg->y_array = xcalloc((size_t)tv_list_len(lines), sizeof(char *)); reg->y_array = xcalloc((size_t)tv_list_len(lines), sizeof(String));
reg->y_size = (size_t)tv_list_len(lines); reg->y_size = (size_t)tv_list_len(lines);
reg->additional_data = NULL; reg->additional_data = NULL;
reg->timestamp = 0; reg->timestamp = 0;
@ -6523,14 +6542,15 @@ static bool get_clipboard(int name, yankreg_T **target, bool quiet)
if (TV_LIST_ITEM_TV(li)->v_type != VAR_STRING) { if (TV_LIST_ITEM_TV(li)->v_type != VAR_STRING) {
goto err; goto err;
} }
reg->y_array[tv_idx++] = xstrdupnul(TV_LIST_ITEM_TV(li)->vval.v_string); const char *s = TV_LIST_ITEM_TV(li)->vval.v_string;
reg->y_array[tv_idx++] = cstr_to_string(s != NULL ? s : "");
}); });
if (reg->y_size > 0 && strlen(reg->y_array[reg->y_size - 1]) == 0) { if (reg->y_size > 0 && reg->y_array[reg->y_size - 1].size == 0) {
// a known-to-be charwise yank might have a final linebreak // a known-to-be charwise yank might have a final linebreak
// but otherwise there is no line after the final newline // but otherwise there is no line after the final newline
if (reg->y_type != kMTCharWise) { if (reg->y_type != kMTCharWise) {
xfree(reg->y_array[reg->y_size - 1]); xfree(reg->y_array[reg->y_size - 1].data);
reg->y_size--; reg->y_size--;
if (reg->y_type == kMTUnknown) { if (reg->y_type == kMTUnknown) {
reg->y_type = kMTLineWise; reg->y_type = kMTLineWise;
@ -6545,7 +6565,7 @@ static bool get_clipboard(int name, yankreg_T **target, bool quiet)
if (reg->y_type == kMTBlockWise) { if (reg->y_type == kMTBlockWise) {
size_t maxlen = 0; size_t maxlen = 0;
for (size_t i = 0; i < reg->y_size; i++) { for (size_t i = 0; i < reg->y_size; i++) {
size_t rowlen = strlen(reg->y_array[i]); size_t rowlen = reg->y_array[i].size;
maxlen = MAX(maxlen, rowlen); maxlen = MAX(maxlen, rowlen);
} }
assert(maxlen <= INT_MAX); assert(maxlen <= INT_MAX);
@ -6558,7 +6578,7 @@ static bool get_clipboard(int name, yankreg_T **target, bool quiet)
err: err:
if (reg->y_array) { if (reg->y_array) {
for (size_t i = 0; i < reg->y_size; i++) { for (size_t i = 0; i < reg->y_size; i++) {
xfree(reg->y_array[i]); xfree(reg->y_array[i].data);
} }
xfree(reg->y_array); xfree(reg->y_array);
} }
@ -6582,7 +6602,7 @@ static void set_clipboard(int name, yankreg_T *reg)
list_T *const lines = tv_list_alloc((ptrdiff_t)reg->y_size + (reg->y_type != kMTCharWise)); list_T *const lines = tv_list_alloc((ptrdiff_t)reg->y_size + (reg->y_type != kMTCharWise));
for (size_t i = 0; i < reg->y_size; i++) { for (size_t i = 0; i < reg->y_size; i++) {
tv_list_append_string(lines, reg->y_array[i], -1); tv_list_append_string(lines, reg->y_array[i].data, -1);
} }
char regtype; char regtype;
@ -6666,7 +6686,7 @@ static inline bool reg_empty(const yankreg_T *const reg)
|| reg->y_size == 0 || reg->y_size == 0
|| (reg->y_size == 1 || (reg->y_size == 1
&& reg->y_type == kMTCharWise && reg->y_type == kMTCharWise
&& *(reg->y_array[0]) == NUL)); && reg->y_array[0].size == 0));
} }
/// Iterate over global registers. /// Iterate over global registers.

View File

@ -105,7 +105,7 @@ enum GRegFlags {
/// Definition of one register /// Definition of one register
typedef struct { typedef struct {
char **y_array; ///< Pointer to an array of line pointers. String *y_array; ///< Pointer to an array of Strings.
size_t y_size; ///< Number of lines in y_array. size_t y_size; ///< Number of lines in y_array.
MotionType y_type; ///< Register type MotionType y_type; ///< Register type
colnr_T y_width; ///< Register width (only valid for y_type == kBlockWise). colnr_T y_width; ///< Register width (only valid for y_type == kBlockWise).

View File

@ -246,7 +246,7 @@ typedef struct {
struct reg { // yankreg_T struct reg { // yankreg_T
char name; char name;
MotionType type; MotionType type;
char **contents; String *contents;
bool is_unnamed; bool is_unnamed;
size_t contents_size; size_t contents_size;
size_t width; size_t width;
@ -1491,7 +1491,7 @@ static ShaDaWriteResult shada_pack_entry(PackerBuffer *const packer, ShadaEntry
PACK_KEY(REG_KEY_CONTENTS); PACK_KEY(REG_KEY_CONTENTS);
mpack_array(&sbuf.ptr, (uint32_t)entry.data.reg.contents_size); mpack_array(&sbuf.ptr, (uint32_t)entry.data.reg.contents_size);
for (size_t i = 0; i < entry.data.reg.contents_size; i++) { for (size_t i = 0; i < entry.data.reg.contents_size; i++) {
mpack_bin(cstr_as_string(entry.data.reg.contents[i]), &sbuf); mpack_bin(entry.data.reg.contents[i], &sbuf);
} }
PACK_KEY(KEY_NAME_CHAR); PACK_KEY(KEY_NAME_CHAR);
mpack_uint(&sbuf.ptr, (uint8_t)entry.data.reg.name); mpack_uint(&sbuf.ptr, (uint8_t)entry.data.reg.name);
@ -2930,7 +2930,7 @@ static void shada_free_shada_entry(ShadaEntry *const entry)
break; break;
case kSDItemRegister: case kSDItemRegister:
for (size_t i = 0; i < entry->data.reg.contents_size; i++) { for (size_t i = 0; i < entry->data.reg.contents_size; i++) {
xfree(entry->data.reg.contents[i]); api_free_string(entry->data.reg.contents[i]);
} }
xfree(entry->data.reg.contents); xfree(entry->data.reg.contents);
break; break;
@ -3312,9 +3312,9 @@ shada_read_next_item_start:
goto shada_read_next_item_error; goto shada_read_next_item_error;
} }
entry->data.reg.contents_size = it.rc.size; entry->data.reg.contents_size = it.rc.size;
entry->data.reg.contents = xmalloc(it.rc.size * sizeof(char *)); entry->data.reg.contents = xmalloc(it.rc.size * sizeof(String));
for (size_t j = 0; j < it.rc.size; j++) { for (size_t j = 0; j < it.rc.size; j++) {
entry->data.reg.contents[j] = xmemdupz(it.rc.items[j].data, it.rc.items[j].size); entry->data.reg.contents[j] = copy_string(it.rc.items[j], NULL);
} }
kv_destroy(it.rc); kv_destroy(it.rc);

View File

@ -895,13 +895,13 @@ static bool is_filter_char(int c)
return !!(tpf_flags & flag); return !!(tpf_flags & flag);
} }
void terminal_paste(int count, char **y_array, size_t y_size) void terminal_paste(int count, String *y_array, size_t y_size)
{ {
if (y_size == 0) { if (y_size == 0) {
return; return;
} }
vterm_keyboard_start_paste(curbuf->terminal->vt); vterm_keyboard_start_paste(curbuf->terminal->vt);
size_t buff_len = strlen(y_array[0]); size_t buff_len = y_array[0].size;
char *buff = xmalloc(buff_len); char *buff = xmalloc(buff_len);
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
// feed the lines to the terminal // feed the lines to the terminal
@ -914,13 +914,13 @@ void terminal_paste(int count, char **y_array, size_t y_size)
terminal_send(curbuf->terminal, "\n", 1); terminal_send(curbuf->terminal, "\n", 1);
#endif #endif
} }
size_t len = strlen(y_array[j]); size_t len = y_array[j].size;
if (len > buff_len) { if (len > buff_len) {
buff = xrealloc(buff, len); buff = xrealloc(buff, len);
buff_len = len; buff_len = len;
} }
char *dst = buff; char *dst = buff;
char *src = y_array[j]; char *src = y_array[j].data;
while (*src != NUL) { while (*src != NUL) {
len = (size_t)utf_ptr2len(src); len = (size_t)utf_ptr2len(src);
int c = utf_ptr2char(src); int c = utf_ptr2char(src);