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; int regname;
char_u *strregname; char_u *strregname;
char_u *stropt; char_u *stropt;
char_u *strval;
int append; int append;
char_u yank_type; char_u yank_type;
long block_len; long block_len;
@ -13345,8 +13344,6 @@ static void f_setreg(typval_T *argvars, typval_T *rettv)
regname = *strregname; regname = *strregname;
if (regname == 0 || regname == '@') if (regname == 0 || regname == '@')
regname = '"'; regname = '"';
else if (regname == '=')
return;
if (argvars[2].v_type != VAR_UNKNOWN) { if (argvars[2].v_type != VAR_UNKNOWN) {
stropt = get_tv_string_chk(&argvars[2]); 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 (argvars[1].v_type == VAR_LIST) {
if (strval != NULL) int len = argvars[1].vval.v_list->lv_len;
write_reg_contents_ex(regname, strval, -1, char_u **lstval = xmalloc(sizeof(char_u *) * (len + 1));
append, yank_type, block_len); 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; rettv->vval.v_number = 0;
} }

View File

@ -4762,17 +4762,77 @@ void *get_reg_contents(int regname, int flags)
return retval; 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` /// write_reg_contents - store `str` in register `name`
/// ///
/// @see write_reg_contents_ex /// @see write_reg_contents_ex
void write_reg_contents(int name, void write_reg_contents(int name, const char_u *str, ssize_t len,
const char_u *str,
ssize_t len,
int must_append) int must_append)
{ {
write_reg_contents_ex(name, str, len, must_append, MAUTO, 0L); 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` /// write_reg_contents_ex - store `str` in register `name`
/// ///
/// If `str` ends in '\n' or '\r', use linewise, otherwise use /// 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, int yank_type,
long block_len) long block_len)
{ {
struct yankreg *old_y_previous, *old_y_current;
if (len < 0) { if (len < 0) {
len = (ssize_t) STRLEN(str); len = (ssize_t) STRLEN(str);
} }
@ -4834,29 +4892,16 @@ void write_reg_contents_ex(int name,
return; return;
} }
if (!valid_yank_reg(name, TRUE)) { /* check for valid reg name */ if (name == '_') { // black hole: nothing to do
emsg_invreg(name);
return; return;
} }
if (name == '_') /* black hole: nothing to do */ struct yankreg *old_y_previous, *old_y_current;
if (!init_write_reg(name, &old_y_previous, &old_y_current, must_append)) {
return; return;
}
/* Don't want to change the current (unnamed) register */ str_to_reg(y_current, yank_type, str, len, block_len, false);
old_y_previous = y_previous; finish_write_reg(name, old_y_previous, old_y_current);
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;
} }
/// str_to_reg - Put a string into a register. /// str_to_reg - Put a string into a register.
@ -4868,98 +4913,115 @@ void write_reg_contents_ex(int name,
/// @param str string to put in register /// @param str string to put in register
/// @param len length of the string /// @param len length of the string
/// @param blocklen width of visual block /// @param blocklen width of visual block
static void str_to_reg(struct yankreg *y_ptr, /// @param str_list True if str is `char_u **`.
int yank_type, static void str_to_reg(struct yankreg *y_ptr, int yank_type, const char_u *str,
const char_u *str, long len, long blocklen, bool str_list)
long len,
long blocklen)
{ {
int type; /* MCHAR, MLINE or MBLOCK */ int type; /* MCHAR, MLINE or MBLOCK */
int lnum; int lnum;
long start; long start;
long i; long i;
int extra; int extra;
size_t newlines; /* number of lines added */
int extraline = 0; /* extra line at the end */ int extraline = 0; /* extra line at the end */
int append = FALSE; /* append to last line in register */ int append = FALSE; /* append to last line in register */
char_u *s;
char_u **pp;
long maxlen; long maxlen;
if (y_ptr->y_array == NULL) /* NULL means empty register */ if (y_ptr->y_array == NULL) /* NULL means empty register */
y_ptr->y_size = 0; y_ptr->y_size = 0;
if (yank_type == MAUTO) if (yank_type == MAUTO) {
type = ((len > 0 && (str[len - 1] == NL || str[len - 1] == CAR)) type = ((str_list ||
(len > 0 && (str[len - 1] == NL || str[len - 1] == CAR)))
? MLINE : MCHAR); ? MLINE : MCHAR);
else } else {
type = yank_type; type = yank_type;
}
/* // Count the number of lines within the string
* Count the number of lines within the string size_t newlines = 0;
*/ if (str_list) {
newlines = 0; for (char_u **ss = (char_u **) str; *ss != NULL; ++ss) {
for (i = 0; i < len; i++) newlines++;
if (str[i] == '\n') }
} else {
for (i = 0; i < len; i++) {
if (str[i] == '\n') {
++newlines; ++newlines;
}
}
if (type == MCHAR || len == 0 || str[len - 1] != '\n') { if (type == MCHAR || len == 0 || str[len - 1] != '\n') {
extraline = 1; extraline = 1;
++newlines; /* count extra newline at the end */ ++newlines; // count extra newline at the end
} }
if (y_ptr->y_size > 0 && y_ptr->y_type == MCHAR) { if (y_ptr->y_size > 0 && y_ptr->y_type == MCHAR) {
append = TRUE; append = true;
--newlines; /* uncount newline when appending first line */ --newlines; // uncount newline when appending first line
}
} }
/* // Allocate an array to hold the pointers to the new register lines.
* 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.
* 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 = 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]; pp[lnum] = y_ptr->y_array[lnum];
}
free(y_ptr->y_array); free(y_ptr->y_array);
y_ptr->y_array = pp; y_ptr->y_array = pp;
maxlen = 0; maxlen = 0;
/* // Find the end of each line and save it into the array.
* 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) { for (start = 0; start < len + extraline; start += i + 1) {
// Let i represent the length of one line. // Let i represent the length of one line.
const char_u *p = str + start; const char_u *p = str + start;
i = (char_u *)xmemscan(p, '\n', len - start) - p; i = (char_u *)xmemscan(p, '\n', len - start) - p;
if (i > maxlen) if (i > maxlen) {
maxlen = i; maxlen = i;
}
if (append) { if (append) {
--lnum; --lnum;
extra = (int)STRLEN(y_ptr->y_array[lnum]); extra = (int)STRLEN(y_ptr->y_array[lnum]);
} else } else {
extra = 0; extra = 0;
s = xmalloc(i + extra + 1); }
if (extra) char_u *s = xmalloc(i + extra + 1);
if (extra) {
memmove(s, y_ptr->y_array[lnum], (size_t)extra); memmove(s, y_ptr->y_array[lnum], (size_t)extra);
if (append) }
if (append) {
free(y_ptr->y_array[lnum]); free(y_ptr->y_array[lnum]);
if (i) }
if (i) {
memmove(s + extra, str + start, (size_t)i); memmove(s + extra, str + start, (size_t)i);
}
extra += i; extra += i;
s[extra] = NUL; s[extra] = NUL;
y_ptr->y_array[lnum++] = s; y_ptr->y_array[lnum++] = s;
while (--extra >= 0) { while (--extra >= 0) {
if (*s == NUL) if (*s == NUL) {
*s = '\n'; /* replace NUL with newline */ *s = '\n'; // replace NUL with newline
}
++s; ++s;
} }
append = FALSE; /* only first line is appended */ append = FALSE; // only first line is appended
}
} }
y_ptr->y_type = type; y_ptr->y_type = type;
y_ptr->y_size = lnum; y_ptr->y_size = lnum;
if (type == MBLOCK) if (type == MBLOCK) {
y_ptr->y_width = (blocklen < 0 ? maxlen - 1 : blocklen); y_ptr->y_width = (blocklen < 0 ? maxlen - 1 : blocklen);
else } else {
y_ptr->y_width = 0; y_ptr->y_width = 0;
} }
}
void clear_oparg(oparg_T *oap) 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 STARTTEST
:so small.vim :so small.vim
:set encoding=latin1 :set encoding=latin1
:set noswapfile :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 :" function name not starting with a capital
:try :try

Binary file not shown.

View File

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