aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/eval/typval.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/eval/typval.c')
-rw-r--r--src/nvim/eval/typval.c86
1 files changed, 73 insertions, 13 deletions
diff --git a/src/nvim/eval/typval.c b/src/nvim/eval/typval.c
index 78eca15fec..8a407a4513 100644
--- a/src/nvim/eval/typval.c
+++ b/src/nvim/eval/typval.c
@@ -1,6 +1,8 @@
+#include <stdio.h>
#include <stddef.h>
-#include <stdbool.h>
+#include <string.h>
#include <assert.h>
+#include <stdbool.h>
#include "nvim/lib/queue.h"
#include "nvim/eval/typval.h"
@@ -276,7 +278,7 @@ void tv_list_insert(list_T *const l, listitem_T *const ni,
/// Insert VimL value into a list
///
/// @param[out] l List to insert to.
-/// @param[in,out] tv Value to insert. Is copied (@see copy_tv()) to an
+/// @param[in,out] tv Value to insert. Is copied (@see tv_copy()) to an
/// allocated listitem_T and inserted.
/// @param[in] item Item to insert before. If NULL, inserts at the end of the
/// list.
@@ -285,7 +287,7 @@ void tv_list_insert_tv(list_T *const l, typval_T *const tv,
{
listitem_T *const ni = tv_list_item_alloc();
- copy_tv(tv, &ni->li_tv);
+ tv_copy(tv, &ni->li_tv);
tv_list_insert(l, ni, item);
}
@@ -313,13 +315,13 @@ void tv_list_append(list_T *const l, listitem_T *const item)
/// Append VimL value to the end of list
///
/// @param[out] l List to append to.
-/// @param[in,out] tv Value to append. Is copied (@see copy_tv()) to an
+/// @param[in,out] tv Value to append. Is copied (@see tv_copy()) to an
/// allocated listitem_T.
void tv_list_append_tv(list_T *const l, typval_T *const tv)
FUNC_ATTR_NONNULL_ALL
{
listitem_T *const li = tv_list_item_alloc();
- copy_tv(tv, &li->li_tv);
+ tv_copy(tv, &li->li_tv);
tv_list_append(l, li);
}
@@ -447,7 +449,7 @@ list_T *tv_list_copy(const vimconv_T *const conv, list_T *const orig,
break;
}
} else {
- copy_tv(&item->li_tv, &ni->li_tv);
+ tv_copy(&item->li_tv, &ni->li_tv);
}
tv_list_append(copy, ni);
}
@@ -828,13 +830,13 @@ void tv_dict_watcher_notify(dict_T *const dict, const char *const key,
if (newtv) {
dictitem_T *const v = tv_dict_item_alloc_len(S_LEN("new"));
- copy_tv(newtv, &v->di_tv);
+ tv_copy(newtv, &v->di_tv);
tv_dict_add(argv[2].vval.v_dict, v);
}
if (oldtv) {
dictitem_T *const v = tv_dict_item_alloc_len(S_LEN("old"));
- copy_tv(oldtv, &v->di_tv);
+ tv_copy(oldtv, &v->di_tv);
tv_dict_add(argv[2].vval.v_dict, v);
}
@@ -926,7 +928,7 @@ static dictitem_T *tv_dict_item_copy(dictitem_T *const di)
FUNC_ATTR_MALLOC
{
dictitem_T *const new_di = tv_dict_item_alloc((const char *)di->di_key);
- copy_tv(&di->di_tv, &new_di->di_tv);
+ tv_copy(&di->di_tv, &new_di->di_tv);
return new_di;
}
@@ -1161,7 +1163,7 @@ bool tv_dict_get_callback(dict_T *const d,
}
typval_T tv;
- copy_tv(&di->di_tv, &tv);
+ tv_copy(&di->di_tv, &tv);
set_selfdict(&tv, d);
bool res = callback_from_typval(result, &tv);
tv_clear(&tv);
@@ -1338,11 +1340,11 @@ void tv_dict_extend(dict_T *const d1, dict_T *const d2,
}
if (watched) {
- copy_tv(&di1->di_tv, &oldtv);
+ tv_copy(&di1->di_tv, &oldtv);
}
tv_clear(&di1->di_tv);
- copy_tv(&di2->di_tv, &di1->di_tv);
+ tv_copy(&di2->di_tv, &di1->di_tv);
if (watched) {
tv_dict_watcher_notify(d1, (const char *)di1->di_key, &di1->di_tv,
@@ -1433,7 +1435,7 @@ dict_T *tv_dict_copy(const vimconv_T *const conv,
break;
}
} else {
- copy_tv(&di->di_tv, &new_di->di_tv);
+ tv_copy(&di->di_tv, &new_di->di_tv);
}
if (tv_dict_add(copy, new_di) == FAIL) {
tv_dict_item_free(new_di);
@@ -1782,6 +1784,64 @@ void tv_free(typval_T *tv)
}
}
+//{{{3 Copy
+
+/// Copy typval from one location to another
+///
+/// When needed allocates string or increases reference count. Does not make
+/// a copy of a container, but copies its reference!
+///
+/// It is OK for `from` and `to` to point to the same location; this is used to
+/// make a copy later.
+///
+/// @param[in] from Location to copy from.
+/// @param[out] to Location to copy to.
+void tv_copy(typval_T *const from, typval_T *const to)
+{
+ to->v_type = from->v_type;
+ to->v_lock = VAR_UNLOCKED;
+ memmove(&to->vval, &from->vval, sizeof(to->vval));
+ switch (from->v_type) {
+ case VAR_NUMBER:
+ case VAR_FLOAT:
+ case VAR_SPECIAL: {
+ break;
+ }
+ case VAR_STRING:
+ case VAR_FUNC: {
+ if (from->vval.v_string != NULL) {
+ to->vval.v_string = vim_strsave(from->vval.v_string);
+ if (from->v_type == VAR_FUNC) {
+ func_ref(to->vval.v_string);
+ }
+ }
+ break;
+ }
+ case VAR_PARTIAL: {
+ if (to->vval.v_partial != NULL) {
+ to->vval.v_partial->pt_refcount++;
+ }
+ break;
+ }
+ case VAR_LIST: {
+ if (from->vval.v_list != NULL) {
+ to->vval.v_list->lv_refcount++;
+ }
+ break;
+ }
+ case VAR_DICT: {
+ if (from->vval.v_dict != NULL) {
+ to->vval.v_dict->dv_refcount++;
+ }
+ break;
+ }
+ case VAR_UNKNOWN: {
+ EMSG2(_(e_intern2), "tv_copy(UNKNOWN)");
+ break;
+ }
+ }
+}
+
//{{{2 Locks
/// Lock or unlock an item