diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/nvim/eval.c | 29 | ||||
-rw-r--r-- | src/nvim/eval/typval.c | 24 | ||||
-rw-r--r-- | src/nvim/testdir/test_blob.vim | 14 |
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() |