summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/if_py_both.h241
-rw-r--r--src/if_python.c237
-rw-r--r--src/if_python3.c129
-rw-r--r--src/version.c2
4 files changed, 339 insertions, 270 deletions
diff --git a/src/if_py_both.h b/src/if_py_both.h
index f78eccbd..6cd1b23d 100644
--- a/src/if_py_both.h
+++ b/src/if_py_both.h
@@ -65,10 +65,10 @@ static struct PyMethodDef OutputMethods[] = {
OutputWrite(PyObject *self, PyObject *args)
{
int len;
- char *str;
+ char *str = NULL;
int error = ((OutputObject *)(self))->error;
- if (!PyArg_ParseTuple(args, "s#", &str, &len))
+ if (!PyArg_ParseTuple(args, "es#", p_enc, &str, &len))
return NULL;
Py_BEGIN_ALLOW_THREADS
@@ -76,6 +76,7 @@ OutputWrite(PyObject *self, PyObject *args)
writer((writefn)(error ? emsg : msg), (char_u *)str, len);
Python_Release_Vim();
Py_END_ALLOW_THREADS
+ PyMem_Free(str);
Py_INCREF(Py_None);
return Py_None;
@@ -104,10 +105,10 @@ OutputWritelines(PyObject *self, PyObject *args)
for (i = 0; i < n; ++i)
{
PyObject *line = PyList_GetItem(list, i);
- char *str;
+ char *str = NULL;
PyInt len;
- if (!PyArg_Parse(line, "s#", &str, &len)) {
+ if (!PyArg_Parse(line, "es#", p_enc, &str, &len)) {
PyErr_SetString(PyExc_TypeError, _("writelines() requires list of strings"));
Py_DECREF(list);
return NULL;
@@ -118,6 +119,7 @@ OutputWritelines(PyObject *self, PyObject *args)
writer((writefn)(error ? emsg : msg), (char_u *)str, len);
Python_Release_Vim();
Py_END_ALLOW_THREADS
+ PyMem_Free(str);
}
Py_DECREF(list);
@@ -681,6 +683,7 @@ StringToLine(PyObject *obj)
{
const char *str;
char *save;
+ PyObject *bytes;
PyInt len;
PyInt i;
char *p;
@@ -691,8 +694,9 @@ StringToLine(PyObject *obj)
return NULL;
}
- str = PyString_AsString(obj);
- len = PyString_Size(obj);
+ bytes = PyString_AsBytes(obj); /* for Python 2 this does nothing */
+ str = PyString_AsString(bytes);
+ len = PyString_Size(bytes);
/*
* Error checking: String must not contain newlines, as we
@@ -731,6 +735,7 @@ StringToLine(PyObject *obj)
}
save[i] = '\0';
+ PyString_FreeBytes(bytes); /* Python 2 does nothing here */
return save;
}
@@ -817,7 +822,8 @@ py_fix_cursor(linenr_T lo, linenr_T hi, linenr_T extra)
invalidate_botline();
}
-/* Replace a line in the specified buffer. The line number is
+/*
+ * Replace a line in the specified buffer. The line number is
* in Vim format (1-based). The replacement line is given as
* a Python string object. The object is checked for validity
* and correct format. Errors are returned as a value of FAIL.
@@ -908,6 +914,193 @@ SetBufferLine(buf_T *buf, PyInt n, PyObject *line, PyInt *len_change)
}
}
+/* Replace a range of lines in the specified buffer. The line numbers are in
+ * Vim format (1-based). The range is from lo up to, but not including, hi.
+ * The replacement lines are given as a Python list of string objects. The
+ * list is checked for validity and correct format. Errors are returned as a
+ * value of FAIL. The return value is OK on success.
+ * If OK is returned and len_change is not NULL, *len_change
+ * is set to the change in the buffer length.
+ */
+ static int
+SetBufferLineList(buf_T *buf, PyInt lo, PyInt hi, PyObject *list, PyInt *len_change)
+{
+ /* First of all, we check the thpe of the supplied Python object.
+ * There are three cases:
+ * 1. NULL, or None - this is a deletion.
+ * 2. A list - this is a replacement.
+ * 3. Anything else - this is an error.
+ */
+ if (list == Py_None || list == NULL)
+ {
+ PyInt i;
+ PyInt n = (int)(hi - lo);
+ buf_T *savebuf = curbuf;
+
+ PyErr_Clear();
+ curbuf = buf;
+
+ if (u_savedel((linenr_T)lo, (long)n) == FAIL)
+ PyErr_SetVim(_("cannot save undo information"));
+ else
+ {
+ for (i = 0; i < n; ++i)
+ {
+ if (ml_delete((linenr_T)lo, FALSE) == FAIL)
+ {
+ PyErr_SetVim(_("cannot delete line"));
+ break;
+ }
+ }
+ if (buf == curwin->w_buffer)
+ py_fix_cursor((linenr_T)lo, (linenr_T)hi, (linenr_T)-n);
+ deleted_lines_mark((linenr_T)lo, (long)i);
+ }
+
+ curbuf = savebuf;
+
+ if (PyErr_Occurred() || VimErrorCheck())
+ return FAIL;
+
+ if (len_change)
+ *len_change = -n;
+
+ return OK;
+ }
+ else if (PyList_Check(list))
+ {
+ PyInt i;
+ PyInt new_len = PyList_Size(list);
+ PyInt old_len = hi - lo;
+ PyInt extra = 0; /* lines added to text, can be negative */
+ char **array;
+ buf_T *savebuf;
+
+ if (new_len == 0) /* avoid allocating zero bytes */
+ array = NULL;
+ else
+ {
+ array = (char **)alloc((unsigned)(new_len * sizeof(char *)));
+ if (array == NULL)
+ {
+ PyErr_NoMemory();
+ return FAIL;
+ }
+ }
+
+ for (i = 0; i < new_len; ++i)
+ {
+ PyObject *line = PyList_GetItem(list, i);
+
+ array[i] = StringToLine(line);
+ if (array[i] == NULL)
+ {
+ while (i)
+ vim_free(array[--i]);
+ vim_free(array);
+ return FAIL;
+ }
+ }
+
+ savebuf = curbuf;
+
+ PyErr_Clear();
+ curbuf = buf;
+
+ if (u_save((linenr_T)(lo-1), (linenr_T)hi) == FAIL)
+ PyErr_SetVim(_("cannot save undo information"));
+
+ /* If the size of the range is reducing (ie, new_len < old_len) we
+ * need to delete some old_len. We do this at the start, by
+ * repeatedly deleting line "lo".
+ */
+ if (!PyErr_Occurred())
+ {
+ for (i = 0; i < old_len - new_len; ++i)
+ if (ml_delete((linenr_T)lo, FALSE) == FAIL)
+ {
+ PyErr_SetVim(_("cannot delete line"));
+ break;
+ }
+ extra -= i;
+ }
+
+ /* For as long as possible, replace the existing old_len with the
+ * new old_len. This is a more efficient operation, as it requires
+ * less memory allocation and freeing.
+ */
+ if (!PyErr_Occurred())
+ {
+ for (i = 0; i < old_len && i < new_len; ++i)
+ if (ml_replace((linenr_T)(lo+i), (char_u *)array[i], FALSE)
+ == FAIL)
+ {
+ PyErr_SetVim(_("cannot replace line"));
+ break;
+ }
+ }
+ else
+ i = 0;
+
+ /* Now we may need to insert the remaining new old_len. If we do, we
+ * must free the strings as we finish with them (we can't pass the
+ * responsibility to vim in this case).
+ */
+ if (!PyErr_Occurred())
+ {
+ while (i < new_len)
+ {
+ if (ml_append((linenr_T)(lo + i - 1),
+ (char_u *)array[i], 0, FALSE) == FAIL)
+ {
+ PyErr_SetVim(_("cannot insert line"));
+ break;
+ }
+ vim_free(array[i]);
+ ++i;
+ ++extra;
+ }
+ }
+
+ /* Free any left-over old_len, as a result of an error */
+ while (i < new_len)
+ {
+ vim_free(array[i]);
+ ++i;
+ }
+
+ /* Free the array of old_len. All of its contents have now
+ * been dealt with (either freed, or the responsibility passed
+ * to vim.
+ */
+ vim_free(array);
+
+ /* Adjust marks. Invalidate any which lie in the
+ * changed range, and move any in the remainder of the buffer.
+ */
+ mark_adjust((linenr_T)lo, (linenr_T)(hi - 1),
+ (long)MAXLNUM, (long)extra);
+ changed_lines((linenr_T)lo, 0, (linenr_T)hi, (long)extra);
+
+ if (buf == curwin->w_buffer)
+ py_fix_cursor((linenr_T)lo, (linenr_T)hi, (linenr_T)extra);
+
+ curbuf = savebuf;
+
+ if (PyErr_Occurred() || VimErrorCheck())
+ return FAIL;
+
+ if (len_change)
+ *len_change = new_len - old_len;
+
+ return OK;
+ }
+ else
+ {
+ PyErr_BadArgument();
+ return FAIL;
+ }
+}
/* Insert a number of lines into the specified buffer after the specifed line.
* The line number is in Vim format (1-based). The lines to be inserted are
@@ -1113,6 +1306,40 @@ RBAsItem(BufferObject *self, PyInt n, PyObject *val, PyInt start, PyInt end, PyI
return 0;
}
+ static PyInt
+RBAsSlice(BufferObject *self, PyInt lo, PyInt hi, PyObject *val, PyInt start, PyInt end, PyInt *new_end)
+{
+ PyInt size;
+ PyInt len_change;
+
+ /* Self must be a valid buffer */
+ if (CheckBuffer(self))
+ return -1;
+
+ /* Sort out the slice range */
+ size = end - start + 1;
+
+ if (lo < 0)
+ lo = 0;
+ else if (lo > size)
+ lo = size;
+ if (hi < 0)
+ hi = 0;
+ if (hi < lo)
+ hi = lo;
+ else if (hi > size)
+ hi = size;
+
+ if (SetBufferLineList(self->buf, lo + start, hi + start,
+ val, &len_change) == FAIL)
+ return -1;
+
+ if (new_end)
+ *new_end = end + len_change;
+
+ return 0;
+}
+
static PyObject *
RBAppend(BufferObject *self, PyObject *args, PyInt start, PyInt end, PyInt *new_end)
diff --git a/src/if_python.c b/src/if_python.c
index d35e9abe..f3b7e5b6 100644
--- a/src/if_python.c
+++ b/src/if_python.c
@@ -56,6 +56,10 @@
static void init_structs(void);
+/* No-op conversion functions, use with care! */
+#define PyString_AsBytes(obj) (obj)
+#define PyString_FreeBytes(obj)
+
#if !defined(FEAT_PYTHON) && defined(PROTO)
/* Use this to be able to generate prototypes without python being used. */
# define PyObject Py_ssize_t
@@ -129,6 +133,7 @@ struct PyMethodDef { Py_ssize_t a; };
*/
# define PyArg_Parse dll_PyArg_Parse
# define PyArg_ParseTuple dll_PyArg_ParseTuple
+# define PyMem_Free dll_PyMem_Free
# define PyDict_SetItemString dll_PyDict_SetItemString
# define PyErr_BadArgument dll_PyErr_BadArgument
# define PyErr_Clear dll_PyErr_Clear
@@ -189,6 +194,7 @@ struct PyMethodDef { Py_ssize_t a; };
*/
static int(*dll_PyArg_Parse)(PyObject *, char *, ...);
static int(*dll_PyArg_ParseTuple)(PyObject *, char *, ...);
+static int(*dll_PyMem_Free)(void *);
static int(*dll_PyDict_SetItemString)(PyObject *dp, char *key, PyObject *item);
static int(*dll_PyErr_BadArgument)(void);
static void(*dll_PyErr_Clear)(void);
@@ -271,6 +277,7 @@ static struct
{
{"PyArg_Parse", (PYTHON_PROC*)&dll_PyArg_Parse},
{"PyArg_ParseTuple", (PYTHON_PROC*)&dll_PyArg_ParseTuple},
+ {"PyMem_Free", (PYTHON_PROC*)&dll_PyMem_Free},
{"PyDict_SetItemString", (PYTHON_PROC*)&dll_PyDict_SetItemString},
{"PyErr_BadArgument", (PYTHON_PROC*)&dll_PyErr_BadArgument},
{"PyErr_Clear", (PYTHON_PROC*)&dll_PyErr_Clear},
@@ -833,44 +840,6 @@ static PyInt RangeAssSlice(PyObject *, PyInt, PyInt, PyObject *);
static PyObject *CurrentGetattr(PyObject *, char *);
static int CurrentSetattr(PyObject *, char *, PyObject *);
-/* Common routines for buffers and line ranges
- * -------------------------------------------
- */
-
- static PyInt
-RBAssSlice(BufferObject *self, PyInt lo, PyInt hi, PyObject *val, PyInt start, PyInt end, PyInt *new_end)
-{
- PyInt size;
- PyInt len_change;
-
- /* Self must be a valid buffer */
- if (CheckBuffer(self))
- return -1;
-
- /* Sort out the slice range */
- size = end - start + 1;
-
- if (lo < 0)
- lo = 0;
- else if (lo > size)
- lo = size;
- if (hi < 0)
- hi = 0;
- if (hi < lo)
- hi = lo;
- else if (hi > size)
- hi = size;
-
- if (SetBufferLineList(self->buf, lo + start, hi + start,
- val, &len_change) == FAIL)
- return -1;
-
- if (new_end)
- *new_end = end + len_change;
-
- return 0;
-}
-
static PySequenceMethods BufferAsSeq = {
(PyInquiry) BufferLength, /* sq_length, len(x) */
(binaryfunc) 0, /* BufferConcat, */ /* sq_concat, x+y */
@@ -1038,7 +1007,7 @@ BufferAssItem(PyObject *self, PyInt n, PyObject *val)
static PyInt
BufferAssSlice(PyObject *self, PyInt lo, PyInt hi, PyObject *val)
{
- return RBAssSlice((BufferObject *)(self), lo, hi, val, 1,
+ return RBAsSlice((BufferObject *)(self), lo, hi, val, 1,
(PyInt)((BufferObject *)(self))->buf->b_ml.ml_line_count,
NULL);
}
@@ -1088,7 +1057,7 @@ RangeAssItem(PyObject *self, PyInt n, PyObject *val)
static PyInt
RangeAssSlice(PyObject *self, PyInt lo, PyInt hi, PyObject *val)
{
- return RBAssSlice(((RangeObject *)(self))->buf, lo, hi, val,
+ return RBAsSlice(((RangeObject *)(self))->buf, lo, hi, val,
((RangeObject *)(self))->start,
((RangeObject *)(self))->end,
&((RangeObject *)(self))->end);
@@ -1435,194 +1404,6 @@ PythonMod_Init(void)
* 4. Utility functions for handling the interface between Vim and Python.
*/
-/* Replace a range of lines in the specified buffer. The line numbers are in
- * Vim format (1-based). The range is from lo up to, but not including, hi.
- * The replacement lines are given as a Python list of string objects. The
- * list is checked for validity and correct format. Errors are returned as a
- * value of FAIL. The return value is OK on success.
- * If OK is returned and len_change is not NULL, *len_change
- * is set to the change in the buffer length.
- */
- static int
-SetBufferLineList(buf_T *buf, PyInt lo, PyInt hi, PyObject *list, PyInt *len_change)
-{
- /* First of all, we check the thpe of the supplied Python object.
- * There are three cases:
- * 1. NULL, or None - this is a deletion.
- * 2. A list - this is a replacement.
- * 3. Anything else - this is an error.
- */
- if (list == Py_None || list == NULL)
- {
- PyInt i;
- PyInt n = (int)(hi - lo);
- buf_T *savebuf = curbuf;
-
- PyErr_Clear();
- curbuf = buf;
-
- if (u_savedel((linenr_T)lo, (long)n) == FAIL)
- PyErr_SetVim(_("cannot save undo information"));
- else
- {
- for (i = 0; i < n; ++i)
- {
- if (ml_delete((linenr_T)lo, FALSE) == FAIL)
- {
- PyErr_SetVim(_("cannot delete line"));
- break;
- }
- }
- if (buf == curwin->w_buffer)
- py_fix_cursor((linenr_T)lo, (linenr_T)hi, (linenr_T)-n);
- deleted_lines_mark((linenr_T)lo, (long)i);
- }
-
- curbuf = savebuf;
-
- if (PyErr_Occurred() || VimErrorCheck())
- return FAIL;
-
- if (len_change)
- *len_change = -n;
-
- return OK;
- }
- else if (PyList_Check(list))
- {
- PyInt i;
- PyInt new_len = PyList_Size(list);
- PyInt old_len = hi - lo;
- PyInt extra = 0; /* lines added to text, can be negative */
- char **array;
- buf_T *savebuf;
-
- if (new_len == 0) /* avoid allocating zero bytes */
- array = NULL;
- else
- {
- array = (char **)alloc((unsigned)(new_len * sizeof(char *)));
- if (array == NULL)
- {
- PyErr_NoMemory();
- return FAIL;
- }
- }
-
- for (i = 0; i < new_len; ++i)
- {
- PyObject *line = PyList_GetItem(list, i);
-
- array[i] = StringToLine(line);
- if (array[i] == NULL)
- {
- while (i)
- vim_free(array[--i]);
- vim_free(array);
- return FAIL;
- }
- }
-
- savebuf = curbuf;
-
- PyErr_Clear();
- curbuf = buf;
-
- if (u_save((linenr_T)(lo-1), (linenr_T)hi) == FAIL)
- PyErr_SetVim(_("cannot save undo information"));
-
- /* If the size of the range is reducing (ie, new_len < old_len) we
- * need to delete some old_len. We do this at the start, by
- * repeatedly deleting line "lo".
- */
- if (!PyErr_Occurred())
- {
- for (i = 0; i < old_len - new_len; ++i)
- if (ml_delete((linenr_T)lo, FALSE) == FAIL)
- {
- PyErr_SetVim(_("cannot delete line"));
- break;
- }
- extra -= i;
- }
-
- /* For as long as possible, replace the existing old_len with the
- * new old_len. This is a more efficient operation, as it requires
- * less memory allocation and freeing.
- */
- if (!PyErr_Occurred())
- {
- for (i = 0; i < old_len && i < new_len; ++i)
- if (ml_replace((linenr_T)(lo+i), (char_u *)array[i], FALSE)
- == FAIL)
- {
- PyErr_SetVim(_("cannot replace line"));
- break;
- }
- }
- else
- i = 0;
-
- /* Now we may need to insert the remaining new old_len. If we do, we
- * must free the strings as we finish with them (we can't pass the
- * responsibility to vim in this case).
- */
- if (!PyErr_Occurred())
- {
- while (i < new_len)
- {
- if (ml_append((linenr_T)(lo + i - 1),
- (char_u *)array[i], 0, FALSE) == FAIL)
- {
- PyErr_SetVim(_("cannot insert line"));
- break;
- }
- vim_free(array[i]);
- ++i;
- ++extra;
- }
- }
-
- /* Free any left-over old_len, as a result of an error */
- while (i < new_len)
- {
- vim_free(array[i]);
- ++i;
- }
-
- /* Free the array of old_len. All of its contents have now
- * been dealt with (either freed, or the responsibility passed
- * to vim.
- */
- vim_free(array);
-
- /* Adjust marks. Invalidate any which lie in the
- * changed range, and move any in the remainder of the buffer.
- */
- mark_adjust((linenr_T)lo, (linenr_T)(hi - 1),
- (long)MAXLNUM, (long)extra);
- changed_lines((linenr_T)lo, 0, (linenr_T)hi, (long)extra);
-
- if (buf == curwin->w_buffer)
- py_fix_cursor((linenr_T)lo, (linenr_T)hi, (linenr_T)extra);
-
- curbuf = savebuf;
-
- if (PyErr_Occurred() || VimErrorCheck())
- return FAIL;
-
- if (len_change)
- *len_change = new_len - old_len;
-
- return OK;
- }
- else
- {
- PyErr_BadArgument();
- return FAIL;
- }
-}
-
/* Convert a Vim line into a Python string.
* All internal newlines are replaced by null characters.
*
diff --git a/src/if_python3.c b/src/if_python3.c
index 1121802b..5f02a468 100644
--- a/src/if_python3.c
+++ b/src/if_python3.c
@@ -70,8 +70,10 @@ static void init_structs(void);
#define PyInt Py_ssize_t
#define PyString_Check(obj) PyUnicode_Check(obj)
-#define PyString_AsString(obj) _PyUnicode_AsString(obj)
-#define PyString_Size(obj) PyUnicode_GET_SIZE(obj)
+#define PyString_AsBytes(obj) PyUnicode_AsEncodedString(obj, (char *)p_enc, NULL);
+#define PyString_FreeBytes(obj) Py_XDECREF(bytes)
+#define PyString_AsString(obj) PyBytes_AsString(obj)
+#define PyString_Size(obj) PyBytes_GET_SIZE(bytes)
#define PyString_FromString(repr) PyUnicode_FromString(repr)
#if defined(DYNAMIC_PYTHON3) || defined(PROTO)
@@ -99,6 +101,7 @@ static void init_structs(void);
# define PyArg_Parse py3_PyArg_Parse
# undef PyArg_ParseTuple
# define PyArg_ParseTuple py3_PyArg_ParseTuple
+# define PyMem_Free py3_PyMem_Free
# define PyDict_SetItemString py3_PyDict_SetItemString
# define PyErr_BadArgument py3_PyErr_BadArgument
# define PyErr_Clear py3_PyErr_Clear
@@ -140,8 +143,13 @@ static void init_structs(void);
# define PyModule_AddObject py3_PyModule_AddObject
# define PyImport_AppendInittab py3_PyImport_AppendInittab
# define _PyUnicode_AsString py3__PyUnicode_AsString
+# undef PyUnicode_AsEncodedString
+# define PyUnicode_AsEncodedString py3_PyUnicode_AsEncodedString
+# undef PyBytes_AsString
+# define PyBytes_AsString py3_PyBytes_AsString
# define PyObject_GenericGetAttr py3_PyObject_GenericGetAttr
# define PySlice_Type (*py3_PySlice_Type)
+# define PyErr_NewException py3_PyErr_NewException
# ifdef Py_DEBUG
# define _Py_NegativeRefcount py3__Py_NegativeRefcount
# define _Py_RefTotal (*py3__Py_RefTotal)
@@ -157,8 +165,8 @@ static void init_structs(void);
# define PyModule_Create2 py3_PyModule_Create2
# undef PyUnicode_FromString
# define PyUnicode_FromString py3_PyUnicode_FromString
-# undef PyUnicode_FromStringAndSize
-# define PyUnicode_FromStringAndSize py3_PyUnicode_FromStringAndSize
+# undef PyUnicode_Decode
+# define PyUnicode_Decode py3_PyUnicode_Decode
# ifdef Py_DEBUG
# undef PyObject_NEW
@@ -199,7 +207,8 @@ static PyObject* (*py3_Py_BuildValue)(char *, ...);
static int (*py3_PyType_Ready)(PyTypeObject *type);
static int (*py3_PyDict_SetItemString)(PyObject *dp, char *key, PyObject *item);
static PyObject* (*py3_PyUnicode_FromString)(const char *u);
-static PyObject* (*py3_PyUnicode_FromStringAndSize)(const char *u, Py_ssize_t size);
+static PyObject* (*py3_PyUnicode_Decode)(const char *u, Py_ssize_t size,
+ const char *encoding, const char *errors);
static long (*py3_PyLong_AsLong)(PyObject *);
static void (*py3_PyErr_SetNone)(PyObject *);
static void (*py3_PyEval_InitThreads)(void);
@@ -207,6 +216,7 @@ static void(*py3_PyEval_RestoreThread)(PyThreadState *);
static PyThreadState*(*py3_PyEval_SaveThread)(void);
static int (*py3_PyArg_Parse)(PyObject *, char *, ...);
static int (*py3_PyArg_ParseTuple)(PyObject *, char *, ...);
+static int (*py3_PyMem_Free)(void *);
static int (*py3_Py_IsInitialized)(void);
static void (*py3_PyErr_Clear)(void);
static PyObject*(*py3__PyObject_Init)(PyObject *, PyTypeObject *);
@@ -214,11 +224,14 @@ static PyObject* py3__Py_NoneStruct;
static int (*py3_PyModule_AddObject)(PyObject *m, const char *name, PyObject *o);
static int (*py3_PyImport_AppendInittab)(const char *name, PyObject* (*initfunc)(void));
static char* (*py3__PyUnicode_AsString)(PyObject *unicode);
+static PyObject* (*py3_PyUnicode_AsEncodedString)(PyObject *unicode, const char* encoding, const char* errors);
+static char* (*py3_PyBytes_AsString)(PyObject *bytes);
static PyObject* (*py3_PyObject_GenericGetAttr)(PyObject *obj, PyObject *name);
static PyObject* (*py3_PyModule_Create2)(struct PyModuleDef* module, int module_api_version);
static PyObject* (*py3_PyType_GenericAlloc)(PyTypeObject *type, Py_ssize_t nitems);
static PyObject* (*py3_PyType_GenericNew)(PyTypeObject *type, PyObject *args, PyObject *kwds);
static PyTypeObject* py3_PySlice_Type;
+static PyObject* (*py3_PyErr_NewException)(char *name, PyObject *base, PyObject *dict);
# ifdef Py_DEBUG
static void (*py3__Py_NegativeRefcount)(const char *fname, int lineno, PyObject *op);
static Py_ssize_t* py3__Py_RefTotal;
@@ -259,6 +272,7 @@ static struct
{"Py_SetPythonHome", (PYTHON_PROC*)&py3_Py_SetPythonHome},
{"Py_Initialize", (PYTHON_PROC*)&py3_Py_Initialize},
{"PyArg_ParseTuple", (PYTHON_PROC*)&py3_PyArg_ParseTuple},
+ {"PyMem_Free", (PYTHON_PROC*)&py3_PyMem_Free},
{"PyList_New", (PYTHON_PROC*)&py3_PyList_New},
{"PyGILState_Ensure", (PYTHON_PROC*)&py3_PyGILState_Ensure},
{"PyGILState_Release", (PYTHON_PROC*)&py3_PyGILState_Release},
@@ -289,7 +303,6 @@ static struct
{"PyEval_RestoreThread", (PYTHON_PROC*)&py3_PyEval_RestoreThread},
{"PyEval_SaveThread", (PYTHON_PROC*)&py3_PyEval_SaveThread},
{"PyArg_Parse", (PYTHON_PROC*)&py3_PyArg_Parse},
- {"PyArg_ParseTuple", (PYTHON_PROC*)&py3_PyArg_ParseTuple},
{"Py_IsInitialized", (PYTHON_PROC*)&py3_Py_IsInitialized},
{"_Py_NoneStruct", (PYTHON_PROC*)&py3__Py_NoneStruct},
{"PyErr_Clear", (PYTHON_PROC*)&py3_PyErr_Clear},
@@ -297,11 +310,13 @@ static struct
{"PyModule_AddObject", (PYTHON_PROC*)&py3_PyModule_AddObject},
{"PyImport_AppendInittab", (PYTHON_PROC*)&py3_PyImport_AppendInittab},
{"_PyUnicode_AsString", (PYTHON_PROC*)&py3__PyUnicode_AsString},
+ {"PyBytes_AsString", (PYTHON_PROC*)&py3_PyBytes_AsString},
{"PyObject_GenericGetAttr", (PYTHON_PROC*)&py3_PyObject_GenericGetAttr},
{"PyModule_Create2", (PYTHON_PROC*)&py3_PyModule_Create2},
{"PyType_GenericAlloc", (PYTHON_PROC*)&py3_PyType_GenericAlloc},
{"PyType_GenericNew", (PYTHON_PROC*)&py3_PyType_GenericNew},
{"PySlice_Type", (PYTHON_PROC*)&py3_PySlice_Type},
+ {"PyErr_NewException", (PYTHON_PROC*)&py3_PyErr_NewException},
# ifdef Py_DEBUG
{"_Py_NegativeRefcount", (PYTHON_PROC*)&py3__Py_NegativeRefcount},
{"_Py_RefTotal", (PYTHON_PROC*)&py3__Py_RefTotal},
@@ -337,7 +352,7 @@ end_dynamic_python3(void)
py3_runtime_link_init(char *libname, int verbose)
{
int i;
- void *ucs_from_string, *ucs_from_string_and_size;
+ void *ucs_from_string, *ucs_decode, *ucs_as_encoded_string;
# if !(defined(PY_NO_RTLD_GLOBAL) && defined(PY3_NO_RTLD_GLOBAL)) && defined(UNIX) && defined(FEAT_PYTHON)
/* Can't have Python and Python3 loaded at the same time.
@@ -377,19 +392,24 @@ py3_runtime_link_init(char *libname, int verbose)
/* Load unicode functions separately as only the ucs2 or the ucs4 functions
* will be present in the library. */
ucs_from_string = symbol_from_dll(hinstPy3, "PyUnicodeUCS2_FromString");
- ucs_from_string_and_size = symbol_from_dll(hinstPy3,
- "PyUnicodeUCS2_FromStringAndSize");
- if (!ucs_from_string || !ucs_from_string_and_size)
+ ucs_decode = symbol_from_dll(hinstPy3,
+ "PyUnicodeUCS2_Decode");
+ ucs_as_encoded_string = symbol_from_dll(hinstPy3,
+ "PyUnicodeUCS2_AsEncodedString");
+ if (!ucs_from_string || !ucs_decode || !ucs_as_encoded_string)
{
ucs_from_string = symbol_from_dll(hinstPy3,
"PyUnicodeUCS4_FromString");
- ucs_from_string_and_size = symbol_from_dll(hinstPy3,
- "PyUnicodeUCS4_FromStringAndSize");
+ ucs_decode = symbol_from_dll(hinstPy3,
+ "PyUnicodeUCS4_Decode");
+ ucs_as_encoded_string = symbol_from_dll(hinstPy3,
+ "PyUnicodeUCS4_AsEncodedString");
}
- if (ucs_from_string && ucs_from_string_and_size)
+ if (ucs_from_string && ucs_decode && ucs_as_encoded_string)
{
py3_PyUnicode_FromString = ucs_from_string;
- py3_PyUnicode_FromStringAndSize = ucs_from_string_and_size;
+ py3_PyUnicode_Decode = ucs_decode;
+ py3_PyUnicode_AsEncodedString = ucs_as_encoded_string;
}
else
{
@@ -567,8 +587,11 @@ Python3_Init(void)
/* Remove the element from sys.path that was added because of our
* argv[0] value in Py3Init_vim(). Previously we used an empty
* string, but dependinding on the OS we then get an empty entry or
- * the current directory in sys.path. */
- PyRun_SimpleString("import sys; sys.path = list(filter(lambda x: x != '/must>not&exist', sys.path))");
+ * the current directory in sys.path.
+ * Only after vim has been imported, the element does exist in
+ * sys.path.
+ */
+ PyRun_SimpleString("import vim; import sys; sys.path = list(filter(lambda x: not x.endswith('must>not&exist'), sys.path))");
// lock is created and acquired in PyEval_InitThreads() and thread
// state is created in Py_Initialize()
@@ -605,6 +628,8 @@ DoPy3Command(exarg_T *eap, const char *cmd)
#if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
char *saved_locale;
#endif
+ PyObject *cmdstr;
+ PyObject *cmdbytes;
#if defined(MACOS) && !defined(MACOS_X_UNIX)
GetPort(&oldPort);
@@ -634,7 +659,13 @@ DoPy3Command(exarg_T *eap, const char *cmd)
pygilstate = PyGILState_Ensure();
- PyRun_SimpleString((char *)(cmd));
+ /* PyRun_SimpleString expects a UTF-8 string. Wrong encoding may cause
+ * SyntaxError (unicode error). */
+ cmdstr = PyUnicode_Decode(cmd, strlen(cmd), (char *)p_enc, NULL);
+ cmdbytes = PyUnicode_AsEncodedString(cmdstr, "utf-8", NULL);
+ Py_XDECREF(cmdstr);
+ PyRun_SimpleString(PyBytes_AsString(cmdbytes));
+ Py_XDECREF(cmdbytes);
PyGILState_Release(pygilstate);
@@ -693,7 +724,10 @@ ex_py3file(exarg_T *eap)
* different options under Windows, meaning that stdio pointers aren't
* compatible between the two. Yuk.
*
- * construct: exec(compile(open('a_filename').read(), 'a_filename', 'exec'))
+ * construct: exec(compile(open('a_filename', 'rb').read(), 'a_filename', 'exec'))
+ *
+ * Using bytes so that Python can detect the source encoding as it normally
+ * does. The doc does not say "compile" accept bytes, though.
*
* We need to escape any backslashes or single quotes in the file name, so that
* Python won't mangle the file name.
@@ -716,8 +750,8 @@ ex_py3file(exarg_T *eap)
return;
if (i==0)
{
- strcpy(p,"').read(),'");
- p += 11;
+ strcpy(p,"','rb').read(),'");
+ p += 16;
}
else
{
@@ -812,8 +846,8 @@ PythonIO_Fini(void)
static Py_ssize_t BufferLength(PyObject *);
static PyObject *BufferItem(PyObject *, Py_ssize_t);
-static Py_ssize_t BufferAsItem(PyObject *, Py_ssize_t, PyObject *);
static PyObject* BufferSubscript(PyObject *self, PyObject* idx);
+static Py_ssize_t BufferAsSubscript(PyObject *self, PyObject* idx, PyObject* val);
/* Line range type - Implementation functions
@@ -835,7 +869,7 @@ static PySequenceMethods BufferAsSeq = {
(ssizeargfunc) 0, /* sq_repeat, x*n */
(ssizeargfunc) BufferItem, /* sq_item, x[i] */
0, /* was_sq_slice, x[i:j] */
- (ssizeobjargproc) BufferAsItem, /* sq_ass_item, x[i]=v */
+ 0, /* sq_ass_item, x[i]=v */
0, /* sq_ass_slice, x[i:j]=v */
0, /* sq_contains */
0, /* sq_inplace_concat */
@@ -845,7 +879,7 @@ static PySequenceMethods BufferAsSeq = {
PyMappingMethods BufferAsMapping = {
/* mp_length */ (lenfunc)BufferLength,
/* mp_subscript */ (binaryfunc)BufferSubscript,
- /* mp_ass_subscript */ (objobjargproc)0,
+ /* mp_ass_subscript */ (objobjargproc)BufferAsSubscript,
};
@@ -897,6 +931,8 @@ BufferDestructor(PyObject *self)
if (this->buf && this->buf != INVALID_BUFFER_VALUE)
this->buf->b_python3_ref = NULL;
+
+ Py_TYPE(self)->tp_free((PyObject*)self);
}
static PyObject *
@@ -975,15 +1011,6 @@ BufferSlice(PyObject *self, Py_ssize_t lo, Py_ssize_t hi)
(Py_ssize_t)((BufferObject *)(self))->buf->b_ml.ml_line_count);
}
- static Py_ssize_t
-BufferAsItem(PyObject *self, Py_ssize_t n, PyObject *val)
-{
- return RBAsItem((BufferObject *)(self), n, val, 1,
- (Py_ssize_t)((BufferObject *)(self))->buf->b_ml.ml_line_count,
- NULL);
-}
-
-
static PyObject *
BufferSubscript(PyObject *self, PyObject* idx)
{
@@ -999,13 +1026,39 @@ BufferSubscript(PyObject *self, PyObject* idx)
&step, &slicelen) < 0) {
return NULL;
}
- return BufferSlice(self,start,stop+1);
+ return BufferSlice(self,start,stop);
} else {
PyErr_SetString(PyExc_IndexError, "Index must be int or slice");
return NULL;
}
}
+ static Py_ssize_t
+BufferAsSubscript(PyObject *self, PyObject* idx, PyObject* val)
+{
+ if (PyLong_Check(idx)) {
+ long n = PyLong_AsLong(idx);
+ return RBAsItem((BufferObject *)(self), n, val, 1,
+ (Py_ssize_t)((BufferObject *)(self))->buf->b_ml.ml_line_count,
+ NULL);
+ } else if (PySlice_Check(idx)) {
+ Py_ssize_t start, stop, step, slicelen;
+
+ if (PySlice_GetIndicesEx((PySliceObject *)idx,
+ (Py_ssize_t)((BufferObject *)(self))->buf->b_ml.ml_line_count+1,
+ &start, &stop,
+ &step, &slicelen) < 0) {
+ return -1;
+ }
+ return RBAsSlice((BufferObject *)(self), start, stop, val, 1,
+ (PyInt)((BufferObject *)(self))->buf->b_ml.ml_line_count,
+ NULL);
+ } else {
+ PyErr_SetString(PyExc_IndexError, "Index must be int or slice");
+ return -1;
+ }
+}
+
static PySequenceMethods RangeAsSeq = {
(lenfunc) RangeLength, /* sq_length, len(x) */
(binaryfunc) 0, /* RangeConcat, sq_concat, x+y */
@@ -1032,6 +1085,7 @@ PyMappingMethods RangeAsMapping = {
RangeDestructor(PyObject *self)
{
Py_DECREF(((RangeObject *)(self))->buf);
+ Py_TYPE(self)->tp_free((PyObject*)self);
}
static PyObject *
@@ -1159,6 +1213,8 @@ WindowDestructor(PyObject *self)
if (this->win && this->win != INVALID_WINDOW_VALUE)
this->win->w_python3_ref = NULL;
+
+ Py_TYPE(self)->tp_free((PyObject*)self);
}
static PyObject *
@@ -1350,8 +1406,11 @@ PyMODINIT_FUNC Py3Init_vim(void)
PySys_SetArgv(1, argv);
mod = PyModule_Create(&vimmodule);
+ if (mod == NULL)
+ return NULL;
- VimError = Py_BuildValue("s", "vim.error");
+ VimError = PyErr_NewException("vim.error", NULL, NULL);
+ Py_INCREF(VimError);
PyModule_AddObject(mod, "error", VimError);
Py_INCREF((PyObject *)(void *)&TheBufferList);
@@ -1404,7 +1463,7 @@ LineToString(const char *str)
}
*p = '\0';
- result = PyUnicode_FromStringAndSize(tmp, len);
+ result = PyUnicode_Decode(tmp, len, (char *)p_enc, NULL);
vim_free(tmp);
return result;
diff --git a/src/version.c b/src/version.c
index 34b9f691..7d75de88 100644
--- a/src/version.c
+++ b/src/version.c
@@ -710,6 +710,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 220,
+/**/
219,
/**/
218,