aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/nvim/eval.c29
-rw-r--r--src/nvim/eval/typval.c24
-rw-r--r--src/nvim/testdir/test_blob.vim14
3 files changed, 48 insertions, 19 deletions
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index 596ed19ff9..b7dc00dc08 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -2599,15 +2599,16 @@ void *eval_for_line(const char_u *arg, bool *errp, char_u **nextcmdp, int skip)
fi->fi_lw.lw_item = tv_list_first(l);
}
} else if (tv.v_type == VAR_BLOB) {
- blob_T *const b = tv.vval.v_blob;
- if (b == NULL) {
- tv_clear(&tv);
- } else {
- // No need to increment the refcount, it's already set for
- // the blob being used in "tv".
- fi->fi_blob = b;
- fi->fi_bi = 0;
+ fi->fi_bi = 0;
+ if (tv.vval.v_blob != NULL) {
+ typval_T btv;
+
+ // Make a copy, so that the iteration still works when the
+ // blob is changed.
+ tv_blob_copy(&tv, &btv);
+ fi->fi_blob = btv.vval.v_blob;
}
+ tv_clear(&tv);
} else {
EMSG(_(e_listreq));
tv_clear(&tv);
@@ -9737,17 +9738,7 @@ int var_item_copy(const vimconv_T *const conv,
}
break;
case VAR_BLOB:
- to->v_type = VAR_BLOB;
- if (from->vval.v_blob == NULL) {
- to->vval.v_blob = NULL;
- } else {
- tv_blob_alloc_ret(to);
- const int len = from->vval.v_blob->bv_ga.ga_len;
-
- to->vval.v_blob->bv_ga.ga_data
- = xmemdup(from->vval.v_blob->bv_ga.ga_data, (size_t)len);
- to->vval.v_blob->bv_ga.ga_len = len;
- }
+ tv_blob_copy(from, to);
break;
case VAR_DICT:
to->v_type = VAR_DICT;
diff --git a/src/nvim/eval/typval.c b/src/nvim/eval/typval.c
index e689571788..68fab1dacd 100644
--- a/src/nvim/eval/typval.c
+++ b/src/nvim/eval/typval.c
@@ -2252,6 +2252,30 @@ void tv_blob_alloc_ret(typval_T *const ret_tv)
tv_blob_set_ret(ret_tv, b);
}
+/// Copy a blob typval to a different typval.
+///
+/// @param[in] from Blob object to copy from.
+/// @param[out] to Blob object to copy to.
+void tv_blob_copy(typval_T *const from, typval_T *const to)
+ FUNC_ATTR_NONNULL_ALL
+{
+ assert(from->v_type == VAR_BLOB);
+
+ to->v_type = VAR_BLOB;
+ if (from->vval.v_blob == NULL) {
+ to->vval.v_blob = NULL;
+ } else {
+ tv_blob_alloc_ret(to);
+ const int len = from->vval.v_blob->bv_ga.ga_len;
+
+ if (len > 0) {
+ to->vval.v_blob->bv_ga.ga_data
+ = xmemdup(from->vval.v_blob->bv_ga.ga_data, (size_t)len);
+ }
+ to->vval.v_blob->bv_ga.ga_len = len;
+ }
+}
+
//{{{3 Clear
#define TYPVAL_ENCODE_ALLOW_SPECIALS false
diff --git a/src/nvim/testdir/test_blob.vim b/src/nvim/testdir/test_blob.vim
index 08342e35d2..568821f564 100644
--- a/src/nvim/testdir/test_blob.vim
+++ b/src/nvim/testdir/test_blob.vim
@@ -154,6 +154,7 @@ func Test_blob_for_loop()
call assert_equal(i, byte)
let i += 1
endfor
+ call assert_equal(4, i)
let blob = 0z00
call remove(blob, 0)
@@ -161,6 +162,19 @@ func Test_blob_for_loop()
for byte in blob
call assert_error('loop over empty blob')
endfor
+
+ let blob = 0z0001020304
+ let i = 0
+ for byte in blob
+ call assert_equal(i, byte)
+ if i == 1
+ call remove(blob, 0)
+ elseif i == 3
+ call remove(blob, 3)
+ endif
+ let i += 1
+ endfor
+ call assert_equal(5, i)
endfunc
func Test_blob_concatenate()