aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/eval.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/eval.c')
-rw-r--r--src/nvim/eval.c50
1 files changed, 40 insertions, 10 deletions
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 698172442e..c2f84735b2 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -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
+ }
+
+ 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;
}
- const int size = (int)os_fileinfo_size(&file_info);
- ga_grow(&blob->bv_ga, size);
- blob->bv_ga.ga_len = size;
+
+ 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.