Index: Python/getargs.c =================================================================== --- Python/getargs.c (Revision 65193) +++ 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++; @@ -1212,7 +1286,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 +1301,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 +1668,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 65193) +++ 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 65193) +++ 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 65193) +++ 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 65193) +++ 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 65193) +++ 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 65193) +++ Objects/stringobject.c (Arbeitskopie) @@ -1313,7 +1313,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 65193) +++ 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 65193) +++ 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 65193) +++ 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,29 @@ to tell how much data has been sent."); static PyObject * sock_sendto(PySocketSockObject *s, PyObject *args) { + Py_buffer pbuf; PyObject *addro; char *buf; sock_addr_t addrbuf; int addrlen, len, 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)) return NULL; } - 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 +2781,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 65193) +++ 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);