mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
vim-patch:9.0.0795: readblob() always reads the whole file
Problem: readblob() always reads the whole file.
Solution: Add arguments to read part of the file. (Ken Takata,
closes vim/vim#11402)
11df3aeee5
Remove trailing whitespace in test as done in patch 9.0.1257.
Move the help for rand() before range().
Co-authored-by: K.Takata <kentkt@csc.jp>
This commit is contained in:
parent
3b92776226
commit
bfa0bc7df0
@ -359,7 +359,8 @@ pyxeval({expr}) any evaluate |python_x| expression
|
||||
rand([{expr}]) Number get pseudo-random number
|
||||
range({expr} [, {max} [, {stride}]])
|
||||
List items from {expr} to {max}
|
||||
readblob({fname}) Blob read a |Blob| from {fname}
|
||||
readblob({fname} [, {offset} [, {size}]])
|
||||
Blob read a |Blob| from {fname}
|
||||
readdir({dir} [, {expr}]) List file names in {dir} selected by {expr}
|
||||
readfile({fname} [, {type} [, {max}]])
|
||||
List get list of lines from file {fname}
|
||||
@ -6110,6 +6111,25 @@ pyxeval({expr}) *pyxeval()*
|
||||
Can also be used as a |method|: >
|
||||
GetExpr()->pyxeval()
|
||||
<
|
||||
rand([{expr}]) *rand()*
|
||||
Return a pseudo-random Number generated with an xoshiro128**
|
||||
algorithm using seed {expr}. The returned number is 32 bits,
|
||||
also on 64 bits systems, for consistency.
|
||||
{expr} can be initialized by |srand()| and will be updated by
|
||||
rand(). If {expr} is omitted, an internal seed value is used
|
||||
and updated.
|
||||
Returns -1 if {expr} is invalid.
|
||||
|
||||
Examples: >
|
||||
:echo rand()
|
||||
:let seed = srand()
|
||||
:echo rand(seed)
|
||||
:echo rand(seed) % 16 " random number 0 - 15
|
||||
<
|
||||
Can also be used as a |method|: >
|
||||
seed->rand()
|
||||
<
|
||||
|
||||
*E726* *E727*
|
||||
range({expr} [, {max} [, {stride}]]) *range()*
|
||||
Returns a |List| with Numbers:
|
||||
@ -6132,29 +6152,22 @@ range({expr} [, {max} [, {stride}]]) *range()*
|
||||
Can also be used as a |method|: >
|
||||
GetExpr()->range()
|
||||
<
|
||||
rand([{expr}]) *rand()*
|
||||
Return a pseudo-random Number generated with an xoshiro128**
|
||||
algorithm using seed {expr}. The returned number is 32 bits,
|
||||
also on 64 bits systems, for consistency.
|
||||
{expr} can be initialized by |srand()| and will be updated by
|
||||
rand(). If {expr} is omitted, an internal seed value is used
|
||||
and updated.
|
||||
Returns -1 if {expr} is invalid.
|
||||
|
||||
Examples: >
|
||||
:echo rand()
|
||||
:let seed = srand()
|
||||
:echo rand(seed)
|
||||
:echo rand(seed) % 16 " random number 0 - 15
|
||||
<
|
||||
Can also be used as a |method|: >
|
||||
seed->rand()
|
||||
<
|
||||
|
||||
readblob({fname}) *readblob()*
|
||||
readblob({fname} [, {offset} [, {size}]]) *readblob()*
|
||||
Read file {fname} in binary mode and return a |Blob|.
|
||||
If {offset} is specified, read the file from the specified
|
||||
offset. If it is a negative value, it is used as an offset
|
||||
from the end of the file. E.g., to read the last 12 bytes: >
|
||||
readblob('file.bin', -12)
|
||||
< If {size} is specified, only the specified size will be read.
|
||||
E.g. to read the first 100 bytes of a file: >
|
||||
readblob('file.bin', 0, 100)
|
||||
< If {size} is -1 or omitted, the whole data starting from
|
||||
{offset} will be read.
|
||||
When the file can't be opened an error message is given and
|
||||
the result is an empty |Blob|.
|
||||
When trying to read bytes beyond the end of the file the
|
||||
result is an empty blob.
|
||||
Also see |readfile()| and |writefile()|.
|
||||
|
||||
|
||||
|
@ -5859,27 +5859,57 @@ write_blob_error:
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Read a blob from a file `fd`.
|
||||
/// Read blob from file "fd".
|
||||
/// Caller has allocated a blob in "rettv".
|
||||
///
|
||||
/// @param[in] fd File to read from.
|
||||
/// @param[in,out] blob Blob to write to.
|
||||
/// @param[in,out] rettv Blob to write to.
|
||||
/// @param[in] offset Read the file from the specified offset.
|
||||
/// @param[in] size Read the specified size, or -1 if no limit.
|
||||
///
|
||||
/// @return true on success, or false on failure.
|
||||
bool read_blob(FILE *const fd, blob_T *const blob)
|
||||
/// @return OK on success, or FAIL on failure.
|
||||
int read_blob(FILE *const fd, typval_T *rettv, off_T offset, off_T size_arg)
|
||||
FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
blob_T *const blob = rettv->vval.v_blob;
|
||||
FileInfo file_info;
|
||||
if (!os_fileinfo_fd(fileno(fd), &file_info)) {
|
||||
return false;
|
||||
return FAIL; // can't read the file, error
|
||||
}
|
||||
const int size = (int)os_fileinfo_size(&file_info);
|
||||
ga_grow(&blob->bv_ga, size);
|
||||
blob->bv_ga.ga_len = size;
|
||||
|
||||
int whence;
|
||||
off_T size = size_arg;
|
||||
if (offset >= 0) {
|
||||
if (size == -1) {
|
||||
// size may become negative, checked below
|
||||
size = (off_T)os_fileinfo_size(&file_info) - offset;
|
||||
}
|
||||
whence = SEEK_SET;
|
||||
} else {
|
||||
if (size == -1) {
|
||||
size = -offset;
|
||||
}
|
||||
whence = SEEK_END;
|
||||
}
|
||||
// Trying to read bytes that aren't there results in an empty blob, not an
|
||||
// error.
|
||||
if (size < 0 || size > (off_T)os_fileinfo_size(&file_info)) {
|
||||
return OK;
|
||||
}
|
||||
if (vim_fseek(fd, offset, whence) != 0) {
|
||||
return OK;
|
||||
}
|
||||
|
||||
ga_grow(&blob->bv_ga, (int)size);
|
||||
blob->bv_ga.ga_len = (int)size;
|
||||
if (fread(blob->bv_ga.ga_data, 1, (size_t)blob->bv_ga.ga_len, fd)
|
||||
< (size_t)blob->bv_ga.ga_len) {
|
||||
return false;
|
||||
// An empty blob is returned on error.
|
||||
tv_blob_free(rettv->vval.v_blob);
|
||||
rettv->vval.v_blob = NULL;
|
||||
return FAIL;
|
||||
}
|
||||
return true;
|
||||
return OK;
|
||||
}
|
||||
|
||||
/// Saves a typval_T as a string.
|
||||
|
@ -296,7 +296,7 @@ return {
|
||||
perleval={args=1, base=1},
|
||||
rand={args={0, 1}, base=1},
|
||||
range={args={1, 3}, base=1},
|
||||
readblob={args=1, base=1},
|
||||
readblob={args={1, 3}, base=1},
|
||||
readdir={args={1, 2}, base=1},
|
||||
readfile={args={1, 3}, base=1},
|
||||
reduce={args={2, 3}, base=1},
|
||||
|
@ -5592,15 +5592,24 @@ static void read_file_or_blob(typval_T *argvars, typval_T *rettv, bool always_bl
|
||||
ptrdiff_t prevlen = 0; // length of data in prev
|
||||
ptrdiff_t prevsize = 0; // size of prev buffer
|
||||
int64_t maxline = MAXLNUM;
|
||||
off_T offset = 0;
|
||||
off_T size = -1;
|
||||
|
||||
if (argvars[1].v_type != VAR_UNKNOWN) {
|
||||
if (strcmp(tv_get_string(&argvars[1]), "b") == 0) {
|
||||
binary = true;
|
||||
} else if (strcmp(tv_get_string(&argvars[1]), "B") == 0) {
|
||||
blob = true;
|
||||
}
|
||||
if (argvars[2].v_type != VAR_UNKNOWN) {
|
||||
maxline = tv_get_number(&argvars[2]);
|
||||
if (always_blob) {
|
||||
offset = (off_T)tv_get_number(&argvars[1]);
|
||||
if (argvars[2].v_type != VAR_UNKNOWN) {
|
||||
size = (off_T)tv_get_number(&argvars[2]);
|
||||
}
|
||||
} else {
|
||||
if (strcmp(tv_get_string(&argvars[1]), "b") == 0) {
|
||||
binary = true;
|
||||
} else if (strcmp(tv_get_string(&argvars[1]), "B") == 0) {
|
||||
blob = true;
|
||||
}
|
||||
if (argvars[2].v_type != VAR_UNKNOWN) {
|
||||
maxline = tv_get_number(&argvars[2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -5619,11 +5628,8 @@ static void read_file_or_blob(typval_T *argvars, typval_T *rettv, bool always_bl
|
||||
|
||||
if (blob) {
|
||||
tv_blob_alloc_ret(rettv);
|
||||
if (!read_blob(fd, rettv->vval.v_blob)) {
|
||||
if (read_blob(fd, rettv, offset, size) == FAIL) {
|
||||
semsg(_(e_notread), fname);
|
||||
// An empty blob is returned on error.
|
||||
tv_blob_free(rettv->vval.v_blob);
|
||||
rettv->vval.v_blob = NULL;
|
||||
}
|
||||
fclose(fd);
|
||||
return;
|
||||
|
@ -439,10 +439,29 @@ func Test_blob_read_write()
|
||||
call writefile(b, 'Xblob')
|
||||
VAR br = readfile('Xblob', 'B')
|
||||
call assert_equal(b, br)
|
||||
VAR br2 = readblob('Xblob')
|
||||
call assert_equal(b, br2)
|
||||
VAR br3 = readblob('Xblob', 1)
|
||||
call assert_equal(b[1 :], br3)
|
||||
VAR br4 = readblob('Xblob', 1, 2)
|
||||
call assert_equal(b[1 : 2], br4)
|
||||
VAR br5 = readblob('Xblob', -3)
|
||||
call assert_equal(b[-3 :], br5)
|
||||
VAR br6 = readblob('Xblob', -3, 2)
|
||||
call assert_equal(b[-3 : -2], br6)
|
||||
|
||||
VAR br1e = readblob('Xblob', 10000)
|
||||
call assert_equal(0z, br1e)
|
||||
VAR br2e = readblob('Xblob', -10000)
|
||||
call assert_equal(0z, br2e)
|
||||
|
||||
call delete('Xblob')
|
||||
END
|
||||
call CheckLegacyAndVim9Success(lines)
|
||||
|
||||
call assert_fails("call readblob('notexist')", 'E484:')
|
||||
" TODO: How do we test for the E485 error?
|
||||
|
||||
" This was crashing when calling readfile() with a directory.
|
||||
call assert_fails("call readfile('.', 'B')", 'E17: "." is a directory')
|
||||
endfunc
|
||||
|
Loading…
Reference in New Issue
Block a user