vim-patch:7.4.243

Problem:    Cannot use setreg() to add text that includes a NUL.
Solution:   Make setreg() accept a list.

https://code.google.com/p/vim/source/detail?r=v7-4-243
This commit is contained in:
Scott Prager 2014-09-03 01:02:47 -04:00
parent 2f8cc3b9d5
commit 5fdca47962
5 changed files with 322 additions and 96 deletions

View File

@ -13328,7 +13328,6 @@ static void f_setreg(typval_T *argvars, typval_T *rettv)
int regname;
char_u *strregname;
char_u *stropt;
char_u *strval;
int append;
char_u yank_type;
long block_len;
@ -13345,8 +13344,6 @@ static void f_setreg(typval_T *argvars, typval_T *rettv)
regname = *strregname;
if (regname == 0 || regname == '@')
regname = '"';
else if (regname == '=')
return;
if (argvars[2].v_type != VAR_UNKNOWN) {
stropt = get_tv_string_chk(&argvars[2]);
@ -13374,10 +13371,32 @@ static void f_setreg(typval_T *argvars, typval_T *rettv)
}
}
strval = get_tv_string_chk(&argvars[1]);
if (strval != NULL)
write_reg_contents_ex(regname, strval, -1,
append, yank_type, block_len);
if (argvars[1].v_type == VAR_LIST) {
int len = argvars[1].vval.v_list->lv_len;
char_u **lstval = xmalloc(sizeof(char_u *) * (len + 1));
char_u **curval = lstval;
for (listitem_T *li = argvars[1].vval.v_list->lv_first;
li != NULL;
li = li->li_next) {
char_u *strval = get_tv_string_chk(&li->li_tv);
if (strval == NULL) {
free(lstval);
return;
}
*curval++ = strval;
}
*curval++ = NULL;
write_reg_contents_lst(regname, lstval, -1, append, yank_type, block_len);
free(lstval);
} else {
char_u *strval = get_tv_string_chk(&argvars[1]);
if (strval == NULL) {
return;
}
write_reg_contents_ex(regname, strval, -1, append, yank_type, block_len);
}
rettv->vval.v_number = 0;
}

View File

@ -4762,17 +4762,77 @@ void *get_reg_contents(int regname, int flags)
return retval;
}
static bool init_write_reg(int name, struct yankreg **old_y_previous,
struct yankreg **old_y_current, int must_append)
{
if (!valid_yank_reg(name, true)) { // check for valid reg name
emsg_invreg(name);
return false;
}
// Don't want to change the current (unnamed) register.
*old_y_previous = y_previous;
*old_y_current = y_current;
get_yank_register(name, true);
if (!y_append && !must_append) {
free_yank_all();
}
return true;
}
static void finish_write_reg(int name, struct yankreg *old_y_previous,
struct yankreg *old_y_current)
{
// Send text of clipboard register to the clipboard.
set_clipboard(name);
// ':let @" = "val"' should change the meaning of the "" register
if (name != '"') {
y_previous = old_y_previous;
}
y_current = old_y_current;
}
/// write_reg_contents - store `str` in register `name`
///
/// @see write_reg_contents_ex
void write_reg_contents(int name,
const char_u *str,
ssize_t len,
void write_reg_contents(int name, const char_u *str, ssize_t len,
int must_append)
{
write_reg_contents_ex(name, str, len, must_append, MAUTO, 0L);
}
void write_reg_contents_lst(int name, char_u **strings, int maxlen,
int must_append, int yank_type, long block_len)
{
if (name == '/' || name == '=') {
char_u *s = strings[0];
if (strings[0] == NULL) {
s = (char_u *)"";
} else if (strings[1] != NULL) {
EMSG(_("E883: search pattern and expression register may not "
"contain two or more lines"));
return;
}
write_reg_contents_ex(name, s, -1, must_append, yank_type, block_len);
return;
}
// black hole: nothing to do
if (name == '_') {
return;
}
struct yankreg *old_y_previous, *old_y_current;
if (!init_write_reg(name, &old_y_previous, &old_y_current, must_append)) {
return;
}
str_to_reg(y_current, yank_type, (char_u *) strings, -1, block_len, true);
finish_write_reg(name, old_y_previous, old_y_current);
}
/// write_reg_contents_ex - store `str` in register `name`
///
/// If `str` ends in '\n' or '\r', use linewise, otherwise use
@ -4799,8 +4859,6 @@ void write_reg_contents_ex(int name,
int yank_type,
long block_len)
{
struct yankreg *old_y_previous, *old_y_current;
if (len < 0) {
len = (ssize_t) STRLEN(str);
}
@ -4834,29 +4892,16 @@ void write_reg_contents_ex(int name,
return;
}
if (!valid_yank_reg(name, TRUE)) { /* check for valid reg name */
emsg_invreg(name);
if (name == '_') { // black hole: nothing to do
return;
}
if (name == '_') /* black hole: nothing to do */
return;
/* Don't want to change the current (unnamed) register */
old_y_previous = y_previous;
old_y_current = y_current;
get_yank_register(name, TRUE);
if (!y_append && !must_append)
free_yank_all();
str_to_reg(y_current, yank_type, str, len, block_len);
set_clipboard(name);
/* ':let @" = "val"' should change the meaning of the "" register */
if (name != '"')
y_previous = old_y_previous;
y_current = old_y_current;
struct yankreg *old_y_previous, *old_y_current;
if (!init_write_reg(name, &old_y_previous, &old_y_current, must_append)) {
return;
}
str_to_reg(y_current, yank_type, str, len, block_len, false);
finish_write_reg(name, old_y_previous, old_y_current);
}
/// str_to_reg - Put a string into a register.
@ -4868,97 +4913,114 @@ void write_reg_contents_ex(int name,
/// @param str string to put in register
/// @param len length of the string
/// @param blocklen width of visual block
static void str_to_reg(struct yankreg *y_ptr,
int yank_type,
const char_u *str,
long len,
long blocklen)
/// @param str_list True if str is `char_u **`.
static void str_to_reg(struct yankreg *y_ptr, int yank_type, const char_u *str,
long len, long blocklen, bool str_list)
{
int type; /* MCHAR, MLINE or MBLOCK */
int lnum;
long start;
long i;
int extra;
size_t newlines; /* number of lines added */
int extraline = 0; /* extra line at the end */
int append = FALSE; /* append to last line in register */
char_u *s;
char_u **pp;
long maxlen;
if (y_ptr->y_array == NULL) /* NULL means empty register */
y_ptr->y_size = 0;
if (yank_type == MAUTO)
type = ((len > 0 && (str[len - 1] == NL || str[len - 1] == CAR))
if (yank_type == MAUTO) {
type = ((str_list ||
(len > 0 && (str[len - 1] == NL || str[len - 1] == CAR)))
? MLINE : MCHAR);
else
} else {
type = yank_type;
/*
* Count the number of lines within the string
*/
newlines = 0;
for (i = 0; i < len; i++)
if (str[i] == '\n')
++newlines;
if (type == MCHAR || len == 0 || str[len - 1] != '\n') {
extraline = 1;
++newlines; /* count extra newline at the end */
}
if (y_ptr->y_size > 0 && y_ptr->y_type == MCHAR) {
append = TRUE;
--newlines; /* uncount newline when appending first line */
}
/*
* Allocate an array to hold the pointers to the new register lines.
* If the register was not empty, move the existing lines to the new array.
*/
pp = xcalloc((y_ptr->y_size + newlines), sizeof(char_u *));
for (lnum = 0; lnum < y_ptr->y_size; ++lnum)
// Count the number of lines within the string
size_t newlines = 0;
if (str_list) {
for (char_u **ss = (char_u **) str; *ss != NULL; ++ss) {
newlines++;
}
} else {
for (i = 0; i < len; i++) {
if (str[i] == '\n') {
++newlines;
}
}
if (type == MCHAR || len == 0 || str[len - 1] != '\n') {
extraline = 1;
++newlines; // count extra newline at the end
}
if (y_ptr->y_size > 0 && y_ptr->y_type == MCHAR) {
append = true;
--newlines; // uncount newline when appending first line
}
}
// Allocate an array to hold the pointers to the new register lines.
// If the register was not empty, move the existing lines to the new array.
char_u **pp = xcalloc(y_ptr->y_size + newlines, sizeof(char_u *));
for (lnum = 0; lnum < y_ptr->y_size; ++lnum) {
pp[lnum] = y_ptr->y_array[lnum];
}
free(y_ptr->y_array);
y_ptr->y_array = pp;
maxlen = 0;
/*
* Find the end of each line and save it into the array.
*/
for (start = 0; start < len + extraline; start += i + 1) {
// Let i represent the length of one line.
const char_u *p = str + start;
i = (char_u *)xmemscan(p, '\n', len - start) - p;
if (i > maxlen)
maxlen = i;
if (append) {
--lnum;
extra = (int)STRLEN(y_ptr->y_array[lnum]);
} else
extra = 0;
s = xmalloc(i + extra + 1);
if (extra)
memmove(s, y_ptr->y_array[lnum], (size_t)extra);
if (append)
free(y_ptr->y_array[lnum]);
if (i)
memmove(s + extra, str + start, (size_t)i);
extra += i;
s[extra] = NUL;
y_ptr->y_array[lnum++] = s;
while (--extra >= 0) {
if (*s == NUL)
*s = '\n'; /* replace NUL with newline */
++s;
// Find the end of each line and save it into the array.
if (str_list) {
for (char_u **ss = (char_u **) str; *ss != NULL; ++ss, ++lnum) {
int i = STRLEN(*ss);
pp[lnum] = vim_strnsave(*ss, i);
if (i > maxlen) {
maxlen = i;
}
}
} else {
for (start = 0; start < len + extraline; start += i + 1) {
// Let i represent the length of one line.
const char_u *p = str + start;
i = (char_u *)xmemscan(p, '\n', len - start) - p;
if (i > maxlen) {
maxlen = i;
}
if (append) {
--lnum;
extra = (int)STRLEN(y_ptr->y_array[lnum]);
} else {
extra = 0;
}
char_u *s = xmalloc(i + extra + 1);
if (extra) {
memmove(s, y_ptr->y_array[lnum], (size_t)extra);
}
if (append) {
free(y_ptr->y_array[lnum]);
}
if (i) {
memmove(s + extra, str + start, (size_t)i);
}
extra += i;
s[extra] = NUL;
y_ptr->y_array[lnum++] = s;
while (--extra >= 0) {
if (*s == NUL) {
*s = '\n'; // replace NUL with newline
}
++s;
}
append = FALSE; // only first line is appended
}
append = FALSE; /* only first line is appended */
}
y_ptr->y_type = type;
y_ptr->y_size = lnum;
if (type == MBLOCK)
if (type == MBLOCK) {
y_ptr->y_width = (blocklen < 0 ? maxlen - 1 : blocklen);
else
} else {
y_ptr->y_width = 0;
}
}
void clear_oparg(oparg_T *oap)

View File

@ -1,7 +1,152 @@
Test for various eval features. vim: set ft=vim :
Note: system clipboard support is not tested. I do not think anybody will thank
me for messing with clipboard.
STARTTEST
:so small.vim
:set encoding=latin1
:set noswapfile
:lang C
:fun AppendRegContents(reg)
call append('$', printf('%s: type %s; value: %s (%s), expr: %s (%s)', a:reg, getregtype(a:reg), getreg(a:reg), string(getreg(a:reg, 0, 1)), getreg(a:reg, 1), string(getreg(a:reg, 1, 1))))
endfun
:command -nargs=? AR :call AppendRegContents(<q-args>)
:fun SetReg(...)
call call('setreg', a:000)
call append('$', printf('{{{2 setreg(%s)', string(a:000)[1:-2]))
call AppendRegContents(a:1)
if a:1 isnot# '='
execute "silent normal! Go==\n==\e\"".a:1."P"
endif
endfun
:fun ErrExe(str)
call append('$', 'Executing '.a:str)
try
execute a:str
catch
$put =v:exception
endtry
endfun
:fun Test()
$put ='{{{1 let tests'
let @" = 'abc'
AR "
let @" = "abc\n"
AR "
let @" = "abc\<C-m>"
AR "
let @= = '"abc"'
AR =
$put ='{{{1 Basic setreg tests'
call SetReg('a', 'abcA', 'c')
call SetReg('b', 'abcB', 'v')
call SetReg('c', 'abcC', 'l')
call SetReg('d', 'abcD', 'V')
call SetReg('e', 'abcE', 'b')
call SetReg('f', 'abcF', "\<C-v>")
call SetReg('g', 'abcG', 'b10')
call SetReg('h', 'abcH', "\<C-v>10")
call SetReg('I', 'abcI')
$put ='{{{1 Appending single lines with setreg()'
call SetReg('A', 'abcAc', 'c')
call SetReg('A', 'abcAl', 'l')
call SetReg('A', 'abcAc2','c')
call SetReg('b', 'abcBc', 'ca')
call SetReg('b', 'abcBb', 'ba')
call SetReg('b', 'abcBc2','ca')
call SetReg('b', 'abcBb2','b50a')
call SetReg('C', 'abcCl', 'l')
call SetReg('C', 'abcCc', 'c')
call SetReg('D', 'abcDb', 'b')
call SetReg('E', 'abcEb', 'b')
call SetReg('E', 'abcEl', 'l')
call SetReg('F', 'abcFc', 'c')
$put ='{{{1 Appending NL with setreg()'
call setreg('a', 'abcA2', 'c')
call setreg('b', 'abcB2', 'v')
call setreg('c', 'abcC2', 'l')
call setreg('d', 'abcD2', 'V')
call setreg('e', 'abcE2', 'b')
call setreg('f', 'abcF2', "\<C-v>")
call setreg('g', 'abcG2', 'b10')
call setreg('h', 'abcH2', "\<C-v>10")
call setreg('I', 'abcI2')
call SetReg('A', "\n")
call SetReg('B', "\n", 'c')
call SetReg('C', "\n")
call SetReg('D', "\n", 'l')
call SetReg('E', "\n")
call SetReg('F', "\n", 'b')
$put ='{{{1 Setting lists with setreg()'
call SetReg('a', ['abcA3'], 'c')
call SetReg('b', ['abcB3'], 'l')
call SetReg('c', ['abcC3'], 'b')
call SetReg('d', ['abcD3'])
$put ='{{{1 Appending lists with setreg()'
call SetReg('A', ['abcA3c'], 'c')
call SetReg('b', ['abcB3l'], 'la')
call SetReg('C', ['abcC3b'], 'lb')
call SetReg('D', ['abcD32'])
call SetReg('A', ['abcA32'])
call SetReg('B', ['abcB3c'], 'c')
call SetReg('C', ['abcC3l'], 'l')
call SetReg('D', ['abcD3b'], 'b')
$put ='{{{1 Appending lists with NL with setreg()'
call SetReg('A', ["\n", 'abcA3l2'], 'l')
call SetReg('B', ["\n", 'abcB3c2'], 'c')
call SetReg('C', ["\n", 'abcC3b2'], 'b')
call SetReg('D', ["\n", 'abcD3b50'],'b50')
$put ='{{{1 Setting lists with NLs with setreg()'
call SetReg('a', ['abcA4-0', "\n", "abcA4-2\n", "\nabcA4-3", "abcA4-4\nabcA4-4-2"])
call SetReg('b', ['abcB4c-0', "\n", "abcB4c-2\n", "\nabcB4c-3", "abcB4c-4\nabcB4c-4-2"], 'c')
call SetReg('c', ['abcC4l-0', "\n", "abcC4l-2\n", "\nabcC4l-3", "abcC4l-4\nabcC4l-4-2"], 'l')
call SetReg('d', ['abcD4b-0', "\n", "abcD4b-2\n", "\nabcD4b-3", "abcD4b-4\nabcD4b-4-2"], 'b')
call SetReg('e', ['abcE4b10-0', "\n", "abcE4b10-2\n", "\nabcE4b10-3", "abcE4b10-4\nabcE4b10-4-2"], 'b10')
$put ='{{{1 Search and expressions'
call SetReg('/', ['abc/'])
call SetReg('/', ["abc/\n"])
call SetReg('=', ['"abc/"'])
call SetReg('=', ["\"abc/\n\""])
$put ='{{{1 Errors'
call ErrExe('call setreg()')
call ErrExe('call setreg(1)')
call ErrExe('call setreg(1, 2, 3, 4)')
call ErrExe('call setreg([], 2)')
call ErrExe('call setreg(1, {})')
call ErrExe('call setreg(1, 2, [])')
call ErrExe('call setreg("/", [1, 2])')
call ErrExe('call setreg("=", [1, 2])')
call ErrExe('call setreg(1, ["", "", [], ""])')
endfun
:"
:call Test()
:"
:delfunction SetReg
:delfunction AppendRegContents
:delfunction ErrExe
:delfunction Test
:delcommand AR
:call garbagecollect(1)
:"
:/^start:/+1,$wq! test.out
:" vim: et ts=4 isk-=\: fmr=???,???
:call getchar()
:e test.out
:%d
:" function name not starting with a capital
:try

Binary file not shown.

View File

@ -422,7 +422,7 @@ static int included_patches[] = {
//246,
245,
//244,
//243,
243,
242,
241,
240,