summaryrefslogtreecommitdiff
path: root/src/if_py_both.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/if_py_both.h')
-rw-r--r--src/if_py_both.h1087
1 files changed, 1078 insertions, 9 deletions
diff --git a/src/if_py_both.h b/src/if_py_both.h
index cbfbaa767..f627f67af 100644
--- a/src/if_py_both.h
+++ b/src/if_py_both.h
@@ -1,4 +1,4 @@
-/* vi:set ts=8 sts=4 sw=4:
+/* vi:set ts=8 sts=4 sw=4 noet:
*
* VIM - Vi IMproved by Bram Moolenaar
*
@@ -105,7 +105,8 @@ OutputWritelines(PyObject *self, PyObject *args)
return NULL;
Py_INCREF(list);
- if (!PyList_Check(list)) {
+ if (!PyList_Check(list))
+ {
PyErr_SetString(PyExc_TypeError, _("writelines() requires list of strings"));
Py_DECREF(list);
return NULL;
@@ -119,7 +120,8 @@ OutputWritelines(PyObject *self, PyObject *args)
char *str = NULL;
PyInt len;
- if (!PyArg_Parse(line, "et#", ENC_OPT, &str, &len)) {
+ if (!PyArg_Parse(line, "et#", ENC_OPT, &str, &len))
+ {
PyErr_SetString(PyExc_TypeError, _("writelines() requires list of strings"));
Py_DECREF(list);
return NULL;
@@ -297,7 +299,7 @@ VimToPython(typval_T *our_tv, int depth, PyObject *lookupDict)
{
PyObject *result;
PyObject *newObj;
- char ptrBuf[NUMBUFLEN];
+ char ptrBuf[sizeof(void *) * 2 + 3];
/* Avoid infinite recursion */
if (depth > 100)
@@ -312,9 +314,9 @@ VimToPython(typval_T *our_tv, int depth, PyObject *lookupDict)
if ((our_tv->v_type == VAR_LIST && our_tv->vval.v_list != NULL)
|| (our_tv->v_type == VAR_DICT && our_tv->vval.v_dict != NULL))
{
- sprintf(ptrBuf, PRINTF_DECIMAL_LONG_U,
- our_tv->v_type == VAR_LIST ? (long_u)our_tv->vval.v_list
- : (long_u)our_tv->vval.v_dict);
+ sprintf(ptrBuf, "%p",
+ our_tv->v_type == VAR_LIST ? (void *)our_tv->vval.v_list
+ : (void *)our_tv->vval.v_dict);
result = PyDict_GetItemString(lookupDict, ptrBuf);
if (result != NULL)
{
@@ -445,6 +447,57 @@ VimEval(PyObject *self UNUSED, PyObject *args UNUSED)
#endif
}
+static PyObject *ConvertToPyObject(typval_T *);
+
+ static PyObject *
+VimEvalPy(PyObject *self UNUSED, PyObject *args UNUSED)
+{
+#ifdef FEAT_EVAL
+ char *expr;
+ typval_T *our_tv;
+ PyObject *result;
+
+ if (!PyArg_ParseTuple(args, "s", &expr))
+ return NULL;
+
+ Py_BEGIN_ALLOW_THREADS
+ Python_Lock_Vim();
+ our_tv = eval_expr((char_u *)expr, NULL);
+
+ Python_Release_Vim();
+ Py_END_ALLOW_THREADS
+
+ if (our_tv == NULL)
+ {
+ PyErr_SetVim(_("invalid expression"));
+ return NULL;
+ }
+
+ result = ConvertToPyObject(our_tv);
+ Py_BEGIN_ALLOW_THREADS
+ Python_Lock_Vim();
+ free_tv(our_tv);
+ Python_Release_Vim();
+ Py_END_ALLOW_THREADS
+
+ return result;
+#else
+ PyErr_SetVim(_("expressions disabled at compile time"));
+ return NULL;
+#endif
+}
+
+ static PyObject *
+VimStrwidth(PyObject *self UNUSED, PyObject *args)
+{
+ char *expr;
+
+ if (!PyArg_ParseTuple(args, "s", &expr))
+ return NULL;
+
+ return PyLong_FromLong(mb_string2cells((char_u *)expr, STRLEN(expr)));
+}
+
/*
* Vim module - Definitions
*/
@@ -453,6 +506,8 @@ static struct PyMethodDef VimMethods[] = {
/* name, function, calling, documentation */
{"command", VimCommand, 1, "Execute a Vim ex-mode command" },
{"eval", VimEval, 1, "Evaluate an expression using Vim evaluator" },
+ {"bindeval", VimEvalPy, 1, "Like eval(), but returns objects attached to vim ones"},
+ {"strwidth", VimStrwidth, 1, "Screen string width, counts <Tab> as having width 1"},
{ NULL, NULL, 0, NULL }
};
@@ -460,8 +515,7 @@ typedef struct
{
PyObject_HEAD
buf_T *buf;
-}
-BufferObject;
+} BufferObject;
#define INVALID_BUFFER_VALUE ((buf_T *)(-1))
@@ -505,6 +559,768 @@ typedef struct
win_T *win;
} WindowObject;
+static int ConvertFromPyObject(PyObject *, typval_T *);
+static int _ConvertFromPyObject(PyObject *, typval_T *, PyObject *);
+
+typedef struct pylinkedlist_S {
+ struct pylinkedlist_S *pll_next;
+ struct pylinkedlist_S *pll_prev;
+ PyObject *pll_obj;
+} pylinkedlist_T;
+
+static pylinkedlist_T *lastdict = NULL;
+static pylinkedlist_T *lastlist = NULL;
+
+ static void
+pyll_remove(pylinkedlist_T *ref, pylinkedlist_T **last)
+{
+ if (ref->pll_prev == NULL)
+ {
+ if (ref->pll_next == NULL)
+ {
+ *last = NULL;
+ return;
+ }
+ }
+ else
+ ref->pll_prev->pll_next = ref->pll_next;
+
+ if (ref->pll_next == NULL)
+ *last = ref->pll_prev;
+ else
+ ref->pll_next->pll_prev = ref->pll_prev;
+}
+
+ static void
+pyll_add(PyObject *self, pylinkedlist_T *ref, pylinkedlist_T **last)
+{
+ if (*last == NULL)
+ ref->pll_prev = NULL;
+ else
+ {
+ (*last)->pll_next = ref;
+ ref->pll_prev = *last;
+ }
+ ref->pll_next = NULL;
+ ref->pll_obj = self;
+ *last = ref;
+}
+
+static PyTypeObject DictionaryType;
+
+typedef struct
+{
+ PyObject_HEAD
+ dict_T *dict;
+ pylinkedlist_T ref;
+} DictionaryObject;
+
+ static PyObject *
+DictionaryNew(dict_T *dict)
+{
+ DictionaryObject *self;
+
+ self = PyObject_NEW(DictionaryObject, &DictionaryType);
+ if (self == NULL)
+ return NULL;
+ self->dict = dict;
+ ++dict->dv_refcount;
+
+ pyll_add((PyObject *)(self), &self->ref, &lastdict);
+
+ return (PyObject *)(self);
+}
+
+ static int
+pydict_to_tv(PyObject *obj, typval_T *tv, PyObject *lookupDict)
+{
+ dict_T *d;
+ char_u *key;
+ dictitem_T *di;
+ PyObject *keyObject;
+ PyObject *valObject;
+ Py_ssize_t iter = 0;
+
+ d = dict_alloc();
+ if (d == NULL)
+ {
+ PyErr_NoMemory();
+ return -1;
+ }
+
+ tv->v_type = VAR_DICT;
+ tv->vval.v_dict = d;
+
+ while (PyDict_Next(obj, &iter, &keyObject, &valObject))
+ {
+ DICTKEY_DECL
+
+ if (keyObject == NULL)
+ return -1;
+ if (valObject == NULL)
+ return -1;
+
+ DICTKEY_GET(-1)
+
+ di = dictitem_alloc(key);
+
+ DICTKEY_UNREF
+
+ if (di == NULL)
+ {
+ PyErr_NoMemory();
+ return -1;
+ }
+ di->di_tv.v_lock = 0;
+
+ if (_ConvertFromPyObject(valObject, &di->di_tv, lookupDict) == -1)
+ {
+ vim_free(di);
+ return -1;
+ }
+ if (dict_add(d, di) == FAIL)
+ {
+ vim_free(di);
+ PyErr_SetVim(_("failed to add key to dictionary"));
+ return -1;
+ }
+ }
+ return 0;
+}
+
+ static int
+pymap_to_tv(PyObject *obj, typval_T *tv, PyObject *lookupDict)
+{
+ dict_T *d;
+ char_u *key;
+ dictitem_T *di;
+ PyObject *list;
+ PyObject *litem;
+ PyObject *keyObject;
+ PyObject *valObject;
+ Py_ssize_t lsize;
+
+ d = dict_alloc();
+ if (d == NULL)
+ {
+ PyErr_NoMemory();
+ return -1;
+ }
+
+ tv->v_type = VAR_DICT;
+ tv->vval.v_dict = d;
+
+ list = PyMapping_Items(obj);
+ lsize = PyList_Size(list);
+ while (lsize--)
+ {
+ DICTKEY_DECL
+
+ litem = PyList_GetItem(list, lsize);
+ if (litem == NULL)
+ {
+ Py_DECREF(list);
+ return -1;
+ }
+
+ keyObject = PyTuple_GetItem(litem, 0);
+ if (keyObject == NULL)
+ {
+ Py_DECREF(list);
+ Py_DECREF(litem);
+ return -1;
+ }
+
+ DICTKEY_GET(-1)
+
+ valObject = PyTuple_GetItem(litem, 1);
+ if (valObject == NULL)
+ {
+ Py_DECREF(list);
+ Py_DECREF(litem);
+ return -1;
+ }
+
+ di = dictitem_alloc(key);
+
+ DICTKEY_UNREF
+
+ if (di == NULL)
+ {
+ Py_DECREF(list);
+ Py_DECREF(litem);
+ PyErr_NoMemory();
+ return -1;
+ }
+ di->di_tv.v_lock = 0;
+
+ if (_ConvertFromPyObject(valObject, &di->di_tv, lookupDict) == -1)
+ {
+ vim_free(di);
+ Py_DECREF(list);
+ Py_DECREF(litem);
+ return -1;
+ }
+ if (dict_add(d, di) == FAIL)
+ {
+ vim_free(di);
+ Py_DECREF(list);
+ Py_DECREF(litem);
+ PyErr_SetVim(_("failed to add key to dictionary"));
+ return -1;
+ }
+ Py_DECREF(litem);
+ }
+ Py_DECREF(list);
+ return 0;
+}
+
+ static PyInt
+DictionaryLength(PyObject *self)
+{
+ return ((PyInt) ((((DictionaryObject *)(self))->dict->dv_hashtab.ht_used)));
+}
+
+ static PyObject *
+DictionaryItem(PyObject *self, PyObject *keyObject)
+{
+ char_u *key;
+ dictitem_T *val;
+ DICTKEY_DECL
+
+ DICTKEY_GET(NULL)
+
+ val = dict_find(((DictionaryObject *) (self))->dict, key, -1);
+
+ DICTKEY_UNREF
+
+ return ConvertToPyObject(&val->di_tv);
+}
+
+ static PyInt
+DictionaryAssItem(PyObject *self, PyObject *keyObject, PyObject *valObject)
+{
+ char_u *key;
+ typval_T tv;
+ dict_T *d = ((DictionaryObject *)(self))->dict;
+ dictitem_T *di;
+ DICTKEY_DECL
+
+ if (d->dv_lock)
+ {
+ PyErr_SetVim(_("dict is locked"));
+ return -1;
+ }
+
+ DICTKEY_GET(-1)
+
+ di = dict_find(d, key, -1);
+
+ if (valObject == NULL)
+ {
+ if (di == NULL)
+ {
+ PyErr_SetString(PyExc_IndexError, _("no such key in dictionary"));
+ return -1;
+ }
+ hashitem_T *hi = hash_find(&d->dv_hashtab, di->di_key);
+ hash_remove(&d->dv_hashtab, hi);
+ dictitem_free(di);
+ return 0;
+ }
+
+ if (ConvertFromPyObject(valObject, &tv) == -1)
+ {
+ return -1;
+ }
+
+ if (di == NULL)
+ {
+ di = dictitem_alloc(key);
+ if (di == NULL)
+ {
+ PyErr_NoMemory();
+ return -1;
+ }
+ di->di_tv.v_lock = 0;
+
+ if (dict_add(d, di) == FAIL)
+ {
+ vim_free(di);
+ PyErr_SetVim(_("failed to add key to dictionary"));
+ return -1;
+ }
+ }
+ else
+ clear_tv(&di->di_tv);
+
+ DICTKEY_UNREF
+
+ copy_tv(&tv, &di->di_tv);
+ return 0;
+}
+
+ static PyObject *
+DictionaryListKeys(PyObject *self)
+{
+ dict_T *dict = ((DictionaryObject *)(self))->dict;
+ long_u todo = dict->dv_hashtab.ht_used;
+ Py_ssize_t i = 0;
+ PyObject *r;
+ hashitem_T *hi;
+
+ r = PyList_New(todo);
+ for (hi = dict->dv_hashtab.ht_array; todo > 0; ++hi)
+ {
+ if (!HASHITEM_EMPTY(hi))
+ {
+ PyList_SetItem(r, i, PyBytes_FromString((char *)(hi->hi_key)));
+ --todo;
+ ++i;
+ }
+ }
+ return r;
+}
+
+static struct PyMethodDef DictionaryMethods[] = {
+ {"keys", (PyCFunction)DictionaryListKeys, METH_NOARGS, ""},
+ { NULL, NULL, 0, NULL }
+};
+
+static PyTypeObject ListType;
+
+typedef struct
+{
+ PyObject_HEAD
+ list_T *list;
+ pylinkedlist_T ref;
+} ListObject;
+
+ static PyObject *
+ListNew(list_T *list)
+{
+ ListObject *self;
+
+ self = PyObject_NEW(ListObject, &ListType);
+ if (self == NULL)
+ return NULL;
+ self->list = list;
+ ++list->lv_refcount;
+
+ pyll_add((PyObject *)(self), &self->ref, &lastlist);
+
+ return (PyObject *)(self);
+}
+
+ static int
+list_py_concat(list_T *l, PyObject *obj, PyObject *lookupDict)
+{
+ Py_ssize_t i;
+ Py_ssize_t lsize = PySequence_Size(obj);
+ PyObject *litem;
+ listitem_T *li;
+
+ for(i=0; i<lsize; i++)
+ {
+ li = listitem_alloc();
+ if (li == NULL)
+ {
+ PyErr_NoMemory();
+ return -1;
+ }
+ li->li_tv.v_lock = 0;
+
+ litem = PySequence_GetItem(obj, i);
+ if (litem == NULL)
+ return -1;
+ if (_ConvertFromPyObject(litem, &li->li_tv, lookupDict) == -1)
+ return -1;
+
+ list_append(l, li);
+ }
+ return 0;
+}
+
+ static int
+pyseq_to_tv(PyObject *obj, typval_T *tv, PyObject *lookupDict)
+{
+ list_T *l;
+
+ l = list_alloc();
+ if (l == NULL)
+ {
+ PyErr_NoMemory();
+ return -1;
+ }
+
+ tv->v_type = VAR_LIST;
+ tv->vval.v_list = l;
+
+ if (list_py_concat(l, obj, lookupDict) == -1)
+ return -1;
+
+ return 0;
+}
+
+ static int
+pyiter_to_tv(PyObject *obj, typval_T *tv, PyObject *lookupDict)
+{
+ PyObject *iterator = PyObject_GetIter(obj);
+ PyObject *item;
+ list_T *l;
+ listitem_T *li;
+
+ l = list_alloc();
+
+ if (l == NULL)
+ {
+ PyErr_NoMemory();
+ return -1;
+ }
+
+ tv->vval.v_list = l;
+ tv->v_type = VAR_LIST;
+
+
+ if (iterator == NULL)
+ return -1;
+
+ while ((item = PyIter_Next(obj)))
+ {
+ li = listitem_alloc();
+ if (li == NULL)
+ {
+ PyErr_NoMemory();
+ return -1;
+ }
+ li->li_tv.v_lock = 0;
+
+ if (_ConvertFromPyObject(item, &li->li_tv, lookupDict) == -1)
+ return -1;
+
+ list_append(l, li);
+
+ Py_DECREF(item);
+ }
+
+ Py_DECREF(iterator);
+ return 0;
+}
+
+ static PyInt
+ListLength(PyObject *self)
+{
+ return ((PyInt) (((ListObject *) (self))->list->lv_len));
+}
+
+ static PyObject *
+ListItem(PyObject *self, Py_ssize_t index)
+{
+ listitem_T *li;
+
+ if (index>=ListLength(self))
+ {
+ PyErr_SetString(PyExc_IndexError, "list index out of range");
+ return NULL;
+ }
+ li = list_find(((ListObject *) (self))->list, (long) index);
+ if (li == NULL)
+ {
+ PyErr_SetVim(_("internal error: failed to get vim list item"));
+ return NULL;
+ }
+ return ConvertToPyObject(&li->li_tv);
+}
+
+#define PROC_RANGE \
+ if (last < 0) {\
+ if (last < -size) \
+ last = 0; \
+ else \
+ last += size; \
+ } \
+ if (first < 0) \
+ first = 0; \
+ if (first > size) \
+ first = size; \
+ if (last > size) \
+ last = size;
+
+ static PyObject *
+ListSlice(PyObject *self, Py_ssize_t first, Py_ssize_t last)
+{
+ PyInt i;
+ PyInt size = ListLength(self);
+ PyInt n;
+ PyObject *list;
+ int reversed = 0;
+
+ PROC_RANGE
+ if (first >= last)
+ first = last;
+
+ n = last-first;
+ list = PyList_New(n);
+ if (list == NULL)
+ return NULL;
+
+ for (i = 0; i < n; ++i)
+ {
+ PyObject *item = ListItem(self, i);
+ if (item == NULL)
+ {
+ Py_DECREF(list);
+ return NULL;
+ }
+
+ if ((PyList_SetItem(list, ((reversed)?(n-i-1):(i)), item)))
+ {
+ Py_DECREF(item);
+ Py_DECREF(list);
+ return NULL;
+ }
+ }
+
+ return list;
+}
+
+ static int
+ListAssItem(PyObject *self, Py_ssize_t index, PyObject *obj)
+{
+ typval_T tv;
+ list_T *l = ((ListObject *) (self))->list;
+ listitem_T *li;
+ Py_ssize_t length = ListLength(self);
+
+ if (l->lv_lock)
+ {
+ PyErr_SetVim(_("list is locked"));
+ return -1;
+ }
+ if (index>length || (index==length && obj==NULL))
+ {
+ PyErr_SetString(PyExc_IndexError, "list index out of range");
+ return -1;
+ }
+
+ if (obj == NULL)
+ {
+ li = list_find(l, (long) index);
+ list_remove(l, li, li);
+ clear_tv(&li->li_tv);
+ vim_free(li);
+ return 0;
+ }
+
+ if (ConvertFromPyObject(obj, &tv) == -1)
+ return -1;
+
+ if (index == length)
+ {
+ if (list_append_tv(l, &tv) == FAIL)
+ {
+ PyErr_SetVim(_("Failed to add item to list"));
+ return -1;
+ }
+ }
+ else
+ {
+ li = list_find(l, (long) index);
+ clear_tv(&li->li_tv);
+ copy_tv(&tv, &li->li_tv);
+ }
+ return 0;
+}
+
+ static int
+ListAssSlice(PyObject *self, Py_ssize_t first, Py_ssize_t last, PyObject *obj)
+{
+ PyInt size = ListLength(self);
+ Py_ssize_t i;
+ Py_ssize_t lsize;
+ PyObject *litem;
+ listitem_T *li;
+ listitem_T *next;
+ typval_T v;
+ list_T *l = ((ListObject *) (self))->list;
+
+ if (l->lv_lock)
+ {
+ PyErr_SetVim(_("list is locked"));
+ return -1;
+ }
+
+ PROC_RANGE
+
+ if (first == size)
+ li = NULL;
+ else
+ {
+ li = list_find(l, (long) first);
+ if (li == NULL)
+ {
+ PyErr_SetVim(_("internal error: no vim list item"));
+ return -1;
+ }
+ if (last > first)
+ {
+ i = last - first;
+ while (i-- && li != NULL)
+ {
+ next = li->li_next;
+ listitem_remove(l, li);
+ li = next;
+ }
+ }
+ }
+
+ if (obj == NULL)
+ return 0;
+
+ if (!PyList_Check(obj))
+ {
+ PyErr_SetString(PyExc_TypeError, _("can only assign lists to slice"));
+ return -1;
+ }
+
+ lsize = PyList_Size(obj);
+
+ for(i=0; i<lsize; i++)
+ {
+ litem = PyList_GetItem(obj, i);
+ if (litem == NULL)
+ return -1;
+ if (ConvertFromPyObject(litem, &v) == -1)
+ return -1;
+ if (list_insert_tv(l, &v, li) == FAIL)
+ {
+ PyErr_SetVim(_("internal error: failed to add item to list"));
+ return -1;
+ }
+ }
+ return 0;
+}
+
+ static PyObject *
+ListConcatInPlace(PyObject *self, PyObject *obj)
+{
+ list_T *l = ((ListObject *) (self))->list;
+ PyObject *lookup_dict;
+
+ if (l->lv_lock)
+ {
+ PyErr_SetVim(_("list is locked"));
+ return NULL;
+ }
+
+ if (!PySequence_Check(obj))
+ {
+ PyErr_SetString(PyExc_TypeError, _("can only concatenate with lists"));
+ return NULL;
+ }
+
+ lookup_dict = PyDict_New();
+ if (list_py_concat(l, obj, lookup_dict) == -1)
+ {
+ Py_DECREF(lookup_dict);
+ return NULL;
+ }
+ Py_DECREF(lookup_dict);
+
+ Py_INCREF(self);
+ return self;
+}
+
+static struct PyMethodDef ListMethods[] = {
+ {"extend", (PyCFunction)ListConcatInPlace, METH_O, ""},
+ { NULL, NULL, 0, NULL }
+};
+
+typedef struct
+{
+ PyObject_HEAD
+ char_u *name;
+} FunctionObject;
+
+static PyTypeObject FunctionType;
+
+ static PyObject *
+FunctionNew(char_u *name)
+{
+ FunctionObject *self;
+
+ self = PyObject_NEW(FunctionObject, &FunctionType);
+ if (self == NULL)
+ return NULL;
+ self->name = PyMem_New(char_u, STRLEN(name) + 1);
+ if (self->name == NULL)
+ {
+ PyErr_NoMemory();
+ return NULL;
+ }
+ STRCPY(self->name, name);
+ func_ref(name);
+ return (PyObject *)(self);
+}
+
+ static PyObject *
+FunctionCall(PyObject *self, PyObject *argsObject, PyObject *kwargs)
+{
+ FunctionObject *this = (FunctionObject *)(self);
+ char_u *name = this->name;
+ typval_T args;
+ typval_T selfdicttv;
+ typval_T rettv;
+ dict_T *selfdict = NULL;
+ PyObject *selfdictObject;
+ PyObject *result;
+ int error;
+
+ if (ConvertFromPyObject(argsObject, &args) == -1)
+ return NULL;
+
+ if (kwargs != NULL)
+ {
+ selfdictObject = PyDict_GetItemString(kwargs, "self");
+ if (selfdictObject != NULL)
+ {
+ if (!PyDict_Check(selfdictObject))
+ {
+ PyErr_SetString(PyExc_TypeError, _("'self' argument must be a dictionary"));
+ clear_tv(&args);
+ return NULL;
+ }
+ if (ConvertFromPyObject(selfdictObject, &selfdicttv) == -1)
+ return NULL;
+ selfdict = selfdicttv.vval.v_dict;
+ }
+ }
+
+ error = func_call(name, &args, selfdict, &rettv);
+ if (error != OK)
+ {
+ result = NULL;
+ PyErr_SetVim(_("failed to run function"));
+ }
+ else
+ result = ConvertToPyObject(&rettv);
+
+ /* FIXME Check what should really be cleared. */
+ clear_tv(&args);
+ clear_tv(&rettv);
+ /*
+ * if (selfdict!=NULL)
+ * clear_tv(selfdicttv);
+ */
+
+ return result;
+}
+
+static struct PyMethodDef FunctionMethods[] = {
+ {"__call__", (PyCFunction)FunctionCall, METH_VARARGS|METH_KEYWORDS, ""},
+ { NULL, NULL, 0, NULL }
+};
+
#define INVALID_WINDOW_VALUE ((win_T *)(-1))
static int
@@ -1567,3 +2383,256 @@ static struct PyMethodDef RangeMethods[] = {
{ NULL, NULL, 0, NULL }
};
+ static void
+set_ref_in_py(const int copyID)
+{
+ pylinkedlist_T *cur;
+ dict_T *dd;
+ list_T *ll;
+
+ if (lastdict != NULL)
+ for(cur = lastdict ; cur != NULL ; cur = cur->pll_prev)
+ {
+ dd = ((DictionaryObject *) (cur->pll_obj))->dict;
+ if (dd->dv_copyID != copyID)
+ {
+ dd->dv_copyID = copyID;
+ set_ref_in_ht(&dd->dv_hashtab, copyID);
+ }
+ }
+
+ if (lastlist != NULL)
+ for(cur = lastlist ; cur != NULL ; cur = cur->pll_prev)
+ {
+ ll = ((ListObject *) (cur->pll_obj))->list;
+ if (ll->lv_copyID != copyID)
+ {
+ ll->lv_copyID = copyID;
+ set_ref_in_list(ll, copyID);
+ }
+ }
+}
+
+ static int
+set_string_copy(char_u *str, typval_T *tv)
+{
+ tv->vval.v_string = vim_strsave(str);
+ if (tv->vval.v_string == NULL)
+ {
+ PyErr_NoMemory();
+ return -1;
+ }
+ return 0;
+}
+
+#ifdef FEAT_EVAL
+typedef int (*pytotvfunc)(PyObject *, typval_T *, PyObject *);
+
+ static int
+convert_dl(PyObject *obj, typval_T *tv,
+ pytotvfunc py_to_tv, PyObject *lookupDict)
+{
+ PyObject *capsule;
+ char hexBuf[sizeof(void *) * 2 + 3];
+
+ sprintf(hexBuf, "%p", obj);
+
+ capsule = PyDict_GetItemString(lookupDict, hexBuf);
+ if (capsule == NULL)
+ {
+ capsule = PyCapsule_New(tv, NULL, NULL);
+ PyDict_SetItemString(lookupDict, hexBuf, capsule);
+ Py_DECREF(capsule);
+ if (py_to_tv(obj, tv, lookupDict) == -1)
+ {
+ tv->v_type = VAR_UNKNOWN;
+ return -1;
+ }
+ /* As we are not using copy_tv which increments reference count we must
+ * do it ourself. */
+ switch(tv->v_type)
+ {
+ case VAR_DICT: ++tv->vval.v_dict->dv_refcount; break;
+ case VAR_LIST: ++tv->vval.v_list->lv_refcount; break;
+ }
+ }
+ else
+ {
+ typval_T *v = PyCapsule_GetPointer(capsule, NULL);
+ copy_tv(v, tv);
+ }
+ return 0;
+}
+
+ static int
+ConvertFromPyObject(PyObject *obj, typval_T *tv)
+{
+ PyObject *lookup_dict;
+ int r;
+
+ lookup_dict = PyDict_New();
+ r = _ConvertFromPyObject(obj, tv, lookup_dict);
+ Py_DECREF(lookup_dict);
+ return r;
+}
+
+ static int
+_ConvertFromPyObject(PyObject *obj, typval_T *tv, PyObject *lookupDict)
+{
+ if (obj->ob_type == &DictionaryType)
+ {
+ tv->v_type = VAR_DICT;
+ tv->vval.v_dict = (((DictionaryObject *)(obj))->dict);
+ ++tv->vval.v_dict->dv_refcount;
+ }
+ else if (obj->ob_type == &ListType)
+ {
+ tv->v_type = VAR_LIST;
+ tv->vval.v_list = (((ListObject *)(obj))->list);
+ ++tv->vval.v_list->lv_refcount;
+ }
+ else if (obj->ob_type == &FunctionType)
+ {
+ if (set_string_copy(((FunctionObject *) (obj))->name, tv) == -1)
+ return -1;
+
+ tv->v_type = VAR_FUNC;
+ func_ref(tv->vval.v_string);
+ }
+#if PY_MAJOR_VERSION >= 3
+ else if (PyBytes_Check(obj))
+ {
+ char_u *result = (char_u *) PyBytes_AsString(obj);
+
+ if (result == NULL)
+ return -1;
+
+ if (set_string_copy(result, tv) == -1)
+ return -1;
+
+ tv->v_type = VAR_STRING;
+ }
+ else if (PyUnicode_Check(obj))
+ {
+ PyObject *bytes;
+ char_u *result;
+
+ bytes = PyString_AsBytes(obj);
+ if (bytes == NULL)
+ return -1;
+
+ result = (char_u *) PyBytes_AsString(bytes);
+ if (result == NULL)
+ return -1;
+
+ if (set_string_copy(result, tv) == -1)
+ {
+ Py_XDECREF(bytes);
+ return -1;
+ }
+ Py_XDECREF(bytes);
+
+ tv->v_type = VAR_STRING;
+ }
+#else
+ else if (PyUnicode_Check(obj))
+ {
+ PyObject *bytes;
+ char_u *result;
+
+ bytes = PyUnicode_AsEncodedString(obj, (char *)ENC_OPT, NULL);
+ if (bytes == NULL)
+ return -1;
+
+ result=(char_u *) PyString_AsString(bytes);
+ if (result == NULL)
+ return -1;
+
+ if (set_string_copy(result, tv) == -1)
+ {
+ Py_XDECREF(bytes);
+ return -1;
+ }
+ Py_XDECREF(bytes);
+
+ tv->v_type = VAR_STRING;
+ }
+ else if (PyString_Check(obj))
+ {
+ char_u *result = (char_u *) PyString_AsString(obj);
+
+ if (result == NULL)
+ return -1;
+
+ if (set_string_copy(result, tv) == -1)
+ return -1;
+
+ tv->v_type = VAR_STRING;
+ }
+ else if (PyInt_Check(obj))
+ {
+ tv->v_type = VAR_NUMBER;
+ tv->vval.v_number = (varnumber_T) PyInt_AsLong(obj);
+ }
+#endif
+ else if (PyLong_Check(obj))
+ {
+ tv->v_type = VAR_NUMBER;
+ tv->vval.v_number = (varnumber_T) PyLong_AsLong(obj);
+ }
+ else if (PyDict_Check(obj))
+ return convert_dl(obj, tv, pydict_to_tv, lookupDict);
+#ifdef FEAT_FLOAT
+ else if (PyFloat_Check(obj))
+ {
+ tv->v_type = VAR_FLOAT;
+ tv->vval.v_float = (float_T) PyFloat_AsDouble(obj);
+ }
+#endif
+ else if (PyIter_Check(obj))
+ return convert_dl(obj, tv, pyiter_to_tv, lookupDict);
+ else if (PySequence_Check(obj))
+ return convert_dl(obj, tv, pyseq_to_tv, lookupDict);
+ else if (PyMapping_Check(obj))
+ return convert_dl(obj, tv, pymap_to_tv, lookupDict);
+ else
+ {
+ PyErr_SetString(PyExc_TypeError, _("unable to convert to vim structure"));
+ return -1;
+ }
+ return 0;
+}
+
+ static PyObject *
+ConvertToPyObject(typval_T *tv)
+{
+ if (tv == NULL)
+ {
+ PyErr_SetVim(_("NULL reference passed"));
+ return NULL;
+ }
+ switch (tv->v_type)
+ {
+ case VAR_STRING:
+ return PyBytes_FromString((char *) tv->vval.v_string);
+ case VAR_NUMBER:
+ return PyLong_FromLong((long) tv->vval.v_number);
+#ifdef FEAT_FLOAT
+ case VAR_FLOAT:
+ return PyFloat_FromDouble((double) tv->vval.v_float);
+#endif
+ case VAR_LIST:
+ return ListNew(tv->vval.v_list);
+ case VAR_DICT:
+ return DictionaryNew(tv->vval.v_dict);
+ case VAR_FUNC:
+ return FunctionNew(tv->vval.v_string);
+ case VAR_UNKNOWN:
+ Py_INCREF(Py_None);
+ return Py_None;
+ default:
+ PyErr_SetVim(_("internal error: invalid value type"));
+ return NULL;
+ }
+}
+#endif