Index: Python/getargs.c
===================================================================
--- Python/getargs.c (Revision 65367)
+++ Python/getargs.c (Arbeitskopie)
@@ -44,6 +44,7 @@ static char *converttuple(PyObject *, co
static char *convertsimple(PyObject *, const char **, va_list *, int, char *,
size_t, PyObject **);
static Py_ssize_t convertbuffer(PyObject *, void **p, char **);
+static int getbuffer(PyObject *, Py_buffer *, char**);
static int vgetargskeywords(PyObject *, PyObject *,
const char *, char **, va_list *, int);
@@ -773,7 +774,32 @@ convertsimple(PyObject *arg, const char
}
case 's': {/* string */
- if (*format == '#') {
+ if (*format == '*') {
+ Py_buffer *p = (Py_buffer *)va_arg(*p_va, Py_buffer *);
+
+ if (PyString_Check(arg)) {
+ PyBuffer_FillInfo(p, arg,
+ PyString_AS_STRING(arg), PyString_GET_SIZE(arg),
+ 1, 0);
+ }
+#ifdef Py_USING_UNICODE
+ else if (PyUnicode_Check(arg)) {
+ uarg = UNICODE_DEFAULT_ENCODING(arg);
+ if (uarg == NULL)
+ return converterr(CONV_UNICODE,
+ arg, msgbuf, bufsize);
+ PyBuffer_FillInfo(p, arg,
+ PyString_AS_STRING(uarg), PyString_GET_SIZE(uarg),
+ 1, 0);
+ }
+#endif
+ else { /* any buffer-like object */
+ char *buf;
+ if (getbuffer(arg, p, &buf) < 0)
+ return converterr(buf, arg, msgbuf, bufsize);
+ }
+ format++;
+ } else if (*format == '#') {
void **p = (void **)va_arg(*p_va, char **);
FETCH_SIZE;
@@ -823,7 +849,34 @@ convertsimple(PyObject *arg, const char
}
case 'z': {/* string, may be NULL (None) */
- if (*format == '#') { /* any buffer-like object */
+ if (*format == '*') {
+ Py_buffer *p = (Py_buffer *)va_arg(*p_va, Py_buffer *);
+
+ if (arg == Py_None)
+ PyBuffer_FillInfo(p, NULL, NULL, 0, 1, 0);
+ else if (PyString_Check(arg)) {
+ PyBuffer_FillInfo(p, arg,
+ PyString_AS_STRING(arg), PyString_GET_SIZE(arg),
+ 1, 0);
+ }
+#ifdef Py_USING_UNICODE
+ else if (PyUnicode_Check(arg)) {
+ uarg = UNICODE_DEFAULT_ENCODING(arg);
+ if (uarg == NULL)
+ return converterr(CONV_UNICODE,
+ arg, msgbuf, bufsize);
+ PyBuffer_FillInfo(p, arg,
+ PyString_AS_STRING(uarg), PyString_GET_SIZE(uarg),
+ 1, 0);
+ }
+#endif
+ else { /* any buffer-like object */
+ char *buf;
+ if (getbuffer(arg, p, &buf) < 0)
+ return converterr(buf, arg, msgbuf, bufsize);
+ }
+ format++;
+ } else if (*format == '#') { /* any buffer-like object */
void **p = (void **)va_arg(*p_va, char **);
FETCH_SIZE;
@@ -1144,9 +1197,26 @@ convertsimple(PyObject *arg, const char
case 'w': { /* memory buffer, read-write access */
void **p = va_arg(*p_va, void **);
+ void *res;
PyBufferProcs *pb = arg->ob_type->tp_as_buffer;
Py_ssize_t count;
-
+
+ if (pb && pb->bf_releasebuffer && *format != '*')
+ /* Buffer must be released, yet caller does not use
+ the Py_buffer protocol. */
+ return converterr("pinned buffer", arg, msgbuf, bufsize);
+
+ if (pb && pb->bf_getbuffer && *format == '*') {
+ /* Caller is interested in Py_buffer, and the object
+ supports it directly. */
+ format++;
+ if (pb->bf_getbuffer(arg, (Py_buffer*)p, 0) < 0)
+ return converterr("(buffer error)", arg, msgbuf, bufsize);
+ if (!PyBuffer_IsContiguous((Py_buffer*)p, 'C'))
+ return converterr("contiguous buffer", arg, msgbuf, bufsize);
+ break;
+ }
+
if (pb == NULL ||
pb->bf_getwritebuffer == NULL ||
pb->bf_getsegcount == NULL)
@@ -1154,9 +1224,13 @@ convertsimple(PyObject *arg, const char
if ((*pb->bf_getsegcount)(arg, NULL) != 1)
return converterr("single-segment read-write buffer",
arg, msgbuf, bufsize);
- if ((count = pb->bf_getwritebuffer(arg, 0, p)) < 0)
+ if ((count = pb->bf_getwritebuffer(arg, 0, res)) < 0)
return converterr("(unspecified)", arg, msgbuf, bufsize);
- if (*format == '#') {
+ if (*format == '*') {
+ PyBuffer_FillInfo((Py_buffer*)p, arg, res, count, 1, 0);
+ format++;
+ }
+ else if (*format == '#') {
FETCH_SIZE;
STORE_SIZE(count);
format++;
@@ -1186,6 +1260,11 @@ convertsimple(PyObject *arg, const char
"string or single-segment read-only buffer",
arg, msgbuf, bufsize);
+ if (pb->bf_releasebuffer)
+ return converterr(
+ "string or pinned buffer",
+ arg, msgbuf, bufsize);
+
count = pb->bf_getcharbuffer(arg, 0, p);
if (count < 0)
return converterr("(unspecified)", arg, msgbuf, bufsize);
@@ -1212,7 +1291,8 @@ convertbuffer(PyObject *arg, void **p, c
Py_ssize_t count;
if (pb == NULL ||
pb->bf_getreadbuffer == NULL ||
- pb->bf_getsegcount == NULL) {
+ pb->bf_getsegcount == NULL ||
+ pb->bf_releasebuffer != NULL) {
*errmsg = "string or read-only buffer";
return -1;
}
@@ -1226,6 +1306,33 @@ convertbuffer(PyObject *arg, void **p, c
return count;
}
+static int
+getbuffer(PyObject *arg, Py_buffer *view, char**errmsg)
+{
+ void *buf;
+ Py_ssize_t count;
+ PyBufferProcs *pb = arg->ob_type->tp_as_buffer;
+ if (pb == NULL) {
+ *errmsg = "string or buffer";
+ return -1;
+ }
+ if (pb->bf_getbuffer) {
+ if (pb->bf_getbuffer(arg, view, 0) < 0)
+ return -1;
+ if (!PyBuffer_IsContiguous(view, 'C')) {
+ *errmsg = "contiguous buffer";
+ return -1;
+ }
+ return 0;
+ }
+
+ count = convertbuffer(arg, &buf, errmsg);
+ if (count < 0)
+ return count;
+ PyBuffer_FillInfo(view, NULL, buf, count, 1, 0);
+ return 0;
+}
+
/* Support for keyword arguments donated by
Geoff Philbrick */
@@ -1566,6 +1673,8 @@ skipitem(const char **p_format, va_list
else
(void) va_arg(*p_va, int *);
format++;
+ } else if ((c == 's' || c == 'z') && *format == '*') {
+ format++;
}
break;
}
Index: Include/abstract.h
===================================================================
--- Include/abstract.h (Revision 65367)
+++ Include/abstract.h (Arbeitskopie)
@@ -623,7 +623,7 @@ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
per element.
*/
- PyAPI_FUNC(int) PyBuffer_FillInfo(Py_buffer *view, void *buf,
+ PyAPI_FUNC(int) PyBuffer_FillInfo(Py_buffer *view, PyObject *o, void *buf,
Py_ssize_t len, int readonly,
int flags);
@@ -633,6 +633,11 @@ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
and -1 (with raising an error) on error.
*/
+ PyAPI_FUNC(void) PyBuffer_Release(Py_buffer *view);
+
+ /* Releases a Py_buffer obtained from getbuffer ParseTuple's s*.
+ */
+
PyAPI_FUNC(PyObject *) PyObject_Format(PyObject* obj,
PyObject *format_spec);
/*
Index: Include/object.h
===================================================================
--- Include/object.h (Revision 65367)
+++ Include/object.h (Arbeitskopie)
@@ -162,7 +162,8 @@ typedef Py_ssize_t (*charbufferproc)(PyO
/* Py3k buffer interface */
typedef struct bufferinfo {
- void *buf;
+ void *buf;
+ PyObject *obj; /* borrowed reference */
Py_ssize_t len;
Py_ssize_t itemsize; /* This is Py_ssize_t so it can be
pointed to by strides in simple case.*/
Index: Objects/abstract.c
===================================================================
--- Objects/abstract.c (Revision 65367)
+++ Objects/abstract.c (Arbeitskopie)
@@ -681,7 +681,7 @@ PyBuffer_FillContiguousStrides(int nd, P
}
int
-PyBuffer_FillInfo(Py_buffer *view, void *buf, Py_ssize_t len,
+PyBuffer_FillInfo(Py_buffer *view, PyObject *obj, void *buf, Py_ssize_t len,
int readonly, int flags)
{
if (view == NULL) return 0;
@@ -692,6 +692,7 @@ PyBuffer_FillInfo(Py_buffer *view, void
return -1;
}
+ view->obj = obj;
view->buf = buf;
view->len = len;
view->readonly = readonly;
@@ -711,6 +712,17 @@ PyBuffer_FillInfo(Py_buffer *view, void
return 0;
}
+void
+PyBuffer_Release(Py_buffer *view)
+{
+ PyObject *obj = view->obj;
+ if (!obj || !Py_TYPE(obj)->tp_as_buffer || !Py_TYPE(obj)->tp_as_buffer->bf_releasebuffer)
+ /* Unmanaged buffer */
+ return;
+ Py_TYPE(obj)->tp_as_buffer->bf_releasebuffer(obj, view);
+
+}
+
PyObject *
PyObject_Format(PyObject* obj, PyObject *format_spec)
{
Index: Objects/fileobject.c
===================================================================
--- Objects/fileobject.c (Revision 65367)
+++ Objects/fileobject.c (Arbeitskopie)
@@ -1611,17 +1611,26 @@ error:
static PyObject *
file_write(PyFileObject *f, PyObject *args)
{
+ Py_buffer pbuf;
char *s;
Py_ssize_t n, n2;
if (f->f_fp == NULL)
return err_closed();
- if (!PyArg_ParseTuple(args, f->f_binary ? "s#" : "t#", &s, &n))
+ if (f->f_binary) {
+ if (!PyArg_ParseTuple(args, "s*", &pbuf))
+ return NULL;
+ s = pbuf.buf;
+ n = pbuf.len;
+ } else
+ if (!PyArg_ParseTuple(args, "t#", &s, &n))
return NULL;
f->f_softspace = 0;
FILE_BEGIN_ALLOW_THREADS(f)
errno = 0;
n2 = fwrite(s, 1, n, f->f_fp);
FILE_END_ALLOW_THREADS(f)
+ if (f->f_binary)
+ PyBuffer_Release(&pbuf);
if (n2 != n) {
PyErr_SetFromErrno(PyExc_IOError);
clearerr(f->f_fp);
Index: Objects/bytearrayobject.c
===================================================================
--- Objects/bytearrayobject.c (Revision 65367)
+++ Objects/bytearrayobject.c (Arbeitskopie)
@@ -123,7 +123,7 @@ bytes_getbuffer(PyByteArrayObject *obj,
ptr = "";
else
ptr = obj->ob_bytes;
- ret = PyBuffer_FillInfo(view, ptr, Py_SIZE(obj), 0, flags);
+ ret = PyBuffer_FillInfo(view, (PyObject*)obj, ptr, Py_SIZE(obj), 0, flags);
if (ret >= 0) {
obj->ob_exports++;
}
Index: Objects/stringobject.c
===================================================================
--- Objects/stringobject.c (Revision 65367)
+++ Objects/stringobject.c (Arbeitskopie)
@@ -1328,7 +1328,8 @@ string_buffer_getcharbuf(PyStringObject
static int
string_buffer_getbuffer(PyStringObject *self, Py_buffer *view, int flags)
{
- return PyBuffer_FillInfo(view, (void *)self->ob_sval, Py_SIZE(self),
+ return PyBuffer_FillInfo(view, (PyObject*)self,
+ (void *)self->ob_sval, Py_SIZE(self),
0, flags);
}
Index: Doc/c-api/arg.rst
===================================================================
--- Doc/c-api/arg.rst (Revision 65367)
+++ Doc/c-api/arg.rst (Arbeitskopie)
@@ -40,6 +40,14 @@ variable(s) whose address should be pass
other read-buffer compatible objects pass back a reference to the raw internal
data representation.
+``s*`` (string, Unicode, or any buffer compatible object) [Py_buffer \*]
+ Similar to ``s#``, this code fills a Py_buffer structure provided by the caller.
+ The buffer gets locked, so that the caller can subsequently use the buffer even
+ inside a ``Py_BEGIN_ALLOW_THREADS`` block; the caller is responsible for calling
+ ``PyBuffer_Release`` with the structure after it has processed the data.
+
+ .. versionadded:: 2.6
+
``z`` (string or ``None``) [const char \*]
Like ``s``, but the Python object may also be ``None``, in which case the C
pointer is set to *NULL*.
@@ -47,6 +55,10 @@ variable(s) whose address should be pass
``z#`` (string or ``None`` or any read buffer compatible object) [const char \*, int]
This is to ``s#`` as ``z`` is to ``s``.
+``z*`` (string or ``None`` or any buffer compatible object) [Py_buffer*]
+ This is to ``s*`` as ``z`` is to ``s``.
+ .. versionadded:: 2.6
+
``u`` (Unicode object) [Py_UNICODE \*]
Convert a Python Unicode object to a C pointer to a NUL-terminated buffer of
16-bit Unicode (UTF-16) data. As with ``s``, there is no need to provide
@@ -240,6 +252,10 @@ variable(s) whose address should be pass
single-segment buffer objects are accepted; :exc:`TypeError` is raised for all
others.
+``w*`` (read-write byte-oriented buffer) [Py_buffer \*]
+ This is to ``w`` what ``s*`` is to ``s``.
+ .. versionadded:: 2.6
+
``(items)`` (tuple) [*matching-items*]
The object must be a Python sequence whose length is the number of format units
in *items*. The C arguments must correspond to the individual format units in
Index: Modules/_fileio.c
===================================================================
--- Modules/_fileio.c (Revision 65367)
+++ Modules/_fileio.c (Arbeitskopie)
@@ -357,7 +357,7 @@ fileio_seekable(PyFileIOObject *self)
static PyObject *
fileio_readinto(PyFileIOObject *self, PyObject *args)
{
- char *ptr;
+ Py_buffer pbuf;
Py_ssize_t n;
if (self->fd < 0)
@@ -365,13 +365,14 @@ fileio_readinto(PyFileIOObject *self, Py
if (!self->readable)
return err_mode("reading");
- if (!PyArg_ParseTuple(args, "w#", &ptr, &n))
+ if (!PyArg_ParseTuple(args, "w*", &pbuf))
return NULL;
Py_BEGIN_ALLOW_THREADS
errno = 0;
- n = read(self->fd, ptr, n);
+ n = read(self->fd, pbuf.buf, pbuf.len);
Py_END_ALLOW_THREADS
+ PyBuffer_Release(&pbuf);
if (n < 0) {
if (errno == EAGAIN)
Py_RETURN_NONE;
@@ -489,22 +490,24 @@ fileio_read(PyFileIOObject *self, PyObje
static PyObject *
fileio_write(PyFileIOObject *self, PyObject *args)
{
+ Py_buffer pbuf;
Py_ssize_t n;
- char *ptr;
if (self->fd < 0)
return err_closed();
if (!self->writable)
return err_mode("writing");
- if (!PyArg_ParseTuple(args, "s#", &ptr, &n))
+ if (!PyArg_ParseTuple(args, "s*", &pbuf))
return NULL;
Py_BEGIN_ALLOW_THREADS
errno = 0;
- n = write(self->fd, ptr, n);
+ n = write(self->fd, pbuf.buf, pbuf.len);
Py_END_ALLOW_THREADS
+ PyBuffer_Release(&pbuf);
+
if (n < 0) {
if (errno == EAGAIN)
Py_RETURN_NONE;
Index: Modules/socketmodule.c
===================================================================
--- Modules/socketmodule.c (Revision 65367)
+++ Modules/socketmodule.c (Arbeitskopie)
@@ -2647,12 +2647,17 @@ sock_send(PySocketSockObject *s, PyObjec
{
char *buf;
int len, n = -1, flags = 0, timeout;
+ Py_buffer pbuf;
- if (!PyArg_ParseTuple(args, "s#|i:send", &buf, &len, &flags))
+ if (!PyArg_ParseTuple(args, "s*|i:send", &pbuf, &flags))
return NULL;
- if (!IS_SELECTABLE(s))
+ if (!IS_SELECTABLE(s)) {
+ PyBuffer_Release(&pbuf);
return select_error();
+ }
+ buf = pbuf.buf;
+ len = pbuf.len;
Py_BEGIN_ALLOW_THREADS
timeout = internal_select(s, 1);
@@ -2664,6 +2669,8 @@ sock_send(PySocketSockObject *s, PyObjec
#endif
Py_END_ALLOW_THREADS
+ PyBuffer_Release(&pbuf);
+
if (timeout == 1) {
PyErr_SetString(socket_timeout, "timed out");
return NULL;
@@ -2688,12 +2695,17 @@ sock_sendall(PySocketSockObject *s, PyOb
{
char *buf;
int len, n = -1, flags = 0, timeout;
+ Py_buffer pbuf;
- if (!PyArg_ParseTuple(args, "s#|i:sendall", &buf, &len, &flags))
+ if (!PyArg_ParseTuple(args, "s*|i:sendall", &pbuf, &flags))
return NULL;
+ buf = pbuf.buf;
+ len = pbuf.len;
- if (!IS_SELECTABLE(s))
+ if (!IS_SELECTABLE(s)) {
+ PyBuffer_Release(&pbuf);
return select_error();
+ }
Py_BEGIN_ALLOW_THREADS
do {
@@ -2712,6 +2724,7 @@ sock_sendall(PySocketSockObject *s, PyOb
len -= n;
} while (len > 0);
Py_END_ALLOW_THREADS
+ PyBuffer_Release(&pbuf);
if (timeout == 1) {
PyErr_SetString(socket_timeout, "timed out");
@@ -2738,24 +2751,32 @@ to tell how much data has been sent.");
static PyObject *
sock_sendto(PySocketSockObject *s, PyObject *args)
{
+ Py_buffer pbuf;
PyObject *addro;
char *buf;
+ Py_ssize_t len;
sock_addr_t addrbuf;
- int addrlen, len, n = -1, flags, timeout;
+ int addrlen, n = -1, flags, timeout;
flags = 0;
- if (!PyArg_ParseTuple(args, "s#O:sendto", &buf, &len, &addro)) {
+ if (!PyArg_ParseTuple(args, "s*O:sendto", &pbuf, &addro)) {
PyErr_Clear();
- if (!PyArg_ParseTuple(args, "s#iO:sendto",
- &buf, &len, &flags, &addro))
+ if (!PyArg_ParseTuple(args, "s*iO:sendto",
+ &pbuf, &flags, &addro))
return NULL;
}
+ buf = pbuf.buf;
+ len = pbuf.len;
- if (!IS_SELECTABLE(s))
+ if (!IS_SELECTABLE(s)) {
+ PyBuffer_Release(&pbuf);
return select_error();
+ }
- if (!getsockaddrarg(s, addro, SAS2SA(&addrbuf), &addrlen))
+ if (!getsockaddrarg(s, addro, SAS2SA(&addrbuf), &addrlen)) {
+ PyBuffer_Release(&pbuf);
return NULL;
+ }
Py_BEGIN_ALLOW_THREADS
timeout = internal_select(s, 1);
@@ -2763,6 +2784,7 @@ sock_sendto(PySocketSockObject *s, PyObj
n = sendto(s->sock_fd, buf, len, flags, SAS2SA(&addrbuf), addrlen);
Py_END_ALLOW_THREADS
+ PyBuffer_Release(&pbuf);
if (timeout == 1) {
PyErr_SetString(socket_timeout, "timed out");
return NULL;
Index: Modules/posixmodule.c
===================================================================
--- Modules/posixmodule.c (Revision 65367)
+++ Modules/posixmodule.c (Arbeitskopie)
@@ -6334,15 +6334,16 @@ Write a string to a file descriptor.");
static PyObject *
posix_write(PyObject *self, PyObject *args)
{
+ Py_buffer pbuf;
int fd;
Py_ssize_t size;
- char *buffer;
- if (!PyArg_ParseTuple(args, "is#:write", &fd, &buffer, &size))
+ if (!PyArg_ParseTuple(args, "is*:write", &fd, &pbuf))
return NULL;
Py_BEGIN_ALLOW_THREADS
- size = write(fd, buffer, (size_t)size);
+ size = write(fd, pbuf.buf, (size_t)pbuf.len);
Py_END_ALLOW_THREADS
+ PyBuffer_Release(&pbuf);
if (size < 0)
return posix_error();
return PyInt_FromSsize_t(size);