Issue #16612: Add "Argument Clinic", a compile-time preprocessor

for C files to generate argument parsing code.  (See PEP 436.)
This commit is contained in:
Larry Hastings 2013-10-19 00:09:25 -07:00
parent 5ceae41083
commit 3182680210
12 changed files with 4016 additions and 276 deletions

View file

@ -8,6 +8,7 @@
#include "structmember.h"
#include "zlib.h"
#ifdef WITH_THREAD
#include "pythread.h"
#define ENTER_ZLIB(obj) \
@ -626,87 +627,136 @@ save_unconsumed_input(compobject *self, int err)
return 0;
}
PyDoc_STRVAR(decomp_decompress__doc__,
"decompress(data, max_length) -- Return a string containing the decompressed\n"
"version of the data.\n"
/*[clinic]
module zlib
zlib.decompress
data: Py_buffer
The binary data to decompress.
max_length: int = 0
The maximum allowable length of the decompressed data.
Unconsumed input data will be stored in
the unconsumed_tail attribute.
/
Return a string containing the decompressed version of the data.
After calling this function, some of the input data may still be stored in
internal buffers for later processing.
Call the flush() method to clear these buffers.
[clinic]*/
PyDoc_STRVAR(zlib_decompress__doc__,
"Return a string containing the decompressed version of the data.\n"
"\n"
"zlib.decompress(data, max_length=0)\n"
" data\n"
" The binary data to decompress.\n"
" max_length\n"
" The maximum allowable length of the decompressed data.\n"
" Unconsumed input data will be stored in\n"
" the unconsumed_tail attribute.\n"
"\n"
"After calling this function, some of the input data may still be stored in\n"
"internal buffers for later processing.\n"
"Call the flush() method to clear these buffers.\n"
"If the max_length parameter is specified then the return value will be\n"
"no longer than max_length. Unconsumed input data will be stored in\n"
"the unconsumed_tail attribute.");
"Call the flush() method to clear these buffers.");
#define ZLIB_DECOMPRESS_METHODDEF \
{"decompress", (PyCFunction)zlib_decompress, METH_VARARGS, zlib_decompress__doc__},
static PyObject *
PyZlib_objdecompress(compobject *self, PyObject *args)
zlib_decompress_impl(PyObject *self, Py_buffer *data, int max_length);
static PyObject *
zlib_decompress(PyObject *self, PyObject *args)
{
int err, max_length = 0;
PyObject *return_value = NULL;
Py_buffer data;
int max_length = 0;
if (!PyArg_ParseTuple(args,
"y*|i:decompress",
&data, &max_length))
goto exit;
return_value = zlib_decompress_impl(self, &data, max_length);
exit:
/* Cleanup for data */
PyBuffer_Release(&data);
return return_value;
}
static PyObject *
zlib_decompress_impl(PyObject *self, Py_buffer *data, int max_length)
/*[clinic checksum: 168d093d400739dde947cca1f4fb0f9d51cdc2c9]*/
{
compobject *zself = (compobject *)self;
int err;
unsigned int inplen;
Py_ssize_t old_length, length = DEFAULTALLOC;
PyObject *RetVal = NULL;
Py_buffer pinput;
Byte *input;
unsigned long start_total_out;
if (!PyArg_ParseTuple(args, "y*|i:decompress", &pinput,
&max_length))
return NULL;
if (pinput.len > UINT_MAX) {
if (data->len > UINT_MAX) {
PyErr_SetString(PyExc_OverflowError,
"Size does not fit in an unsigned int");
goto error_outer;
return NULL;
}
input = pinput.buf;
inplen = pinput.len;
input = data->buf;
inplen = data->len;
if (max_length < 0) {
PyErr_SetString(PyExc_ValueError,
"max_length must be greater than zero");
goto error_outer;
return NULL;
}
/* limit amount of data allocated to max_length */
if (max_length && length > max_length)
length = max_length;
if (!(RetVal = PyBytes_FromStringAndSize(NULL, length)))
goto error_outer;
return NULL;
ENTER_ZLIB(self);
ENTER_ZLIB(zself);
start_total_out = self->zst.total_out;
self->zst.avail_in = inplen;
self->zst.next_in = input;
self->zst.avail_out = length;
self->zst.next_out = (unsigned char *)PyBytes_AS_STRING(RetVal);
start_total_out = zself->zst.total_out;
zself->zst.avail_in = inplen;
zself->zst.next_in = input;
zself->zst.avail_out = length;
zself->zst.next_out = (unsigned char *)PyBytes_AS_STRING(RetVal);
Py_BEGIN_ALLOW_THREADS
err = inflate(&(self->zst), Z_SYNC_FLUSH);
err = inflate(&(zself->zst), Z_SYNC_FLUSH);
Py_END_ALLOW_THREADS
if (err == Z_NEED_DICT && self->zdict != NULL) {
if (err == Z_NEED_DICT && zself->zdict != NULL) {
Py_buffer zdict_buf;
if (PyObject_GetBuffer(self->zdict, &zdict_buf, PyBUF_SIMPLE) == -1) {
if (PyObject_GetBuffer(zself->zdict, &zdict_buf, PyBUF_SIMPLE) == -1) {
Py_DECREF(RetVal);
RetVal = NULL;
goto error;
}
err = inflateSetDictionary(&(self->zst), zdict_buf.buf, zdict_buf.len);
err = inflateSetDictionary(&(zself->zst), zdict_buf.buf, zdict_buf.len);
PyBuffer_Release(&zdict_buf);
if (err != Z_OK) {
zlib_error(self->zst, err, "while decompressing data");
zlib_error(zself->zst, err, "while decompressing data");
Py_DECREF(RetVal);
RetVal = NULL;
goto error;
}
/* Repeat the call to inflate. */
Py_BEGIN_ALLOW_THREADS
err = inflate(&(self->zst), Z_SYNC_FLUSH);
err = inflate(&(zself->zst), Z_SYNC_FLUSH);
Py_END_ALLOW_THREADS
}
/* While Z_OK and the output buffer is full, there might be more output.
So extend the output buffer and try again.
*/
while (err == Z_OK && self->zst.avail_out == 0) {
while (err == Z_OK && zself->zst.avail_out == 0) {
/* If max_length set, don't continue decompressing if we've already
reached the limit.
*/
@ -723,16 +773,16 @@ PyZlib_objdecompress(compobject *self, PyObject *args)
Py_CLEAR(RetVal);
goto error;
}
self->zst.next_out =
zself->zst.next_out =
(unsigned char *)PyBytes_AS_STRING(RetVal) + old_length;
self->zst.avail_out = length - old_length;
zself->zst.avail_out = length - old_length;
Py_BEGIN_ALLOW_THREADS
err = inflate(&(self->zst), Z_SYNC_FLUSH);
err = inflate(&(zself->zst), Z_SYNC_FLUSH);
Py_END_ALLOW_THREADS
}
if (save_unconsumed_input(self, err) < 0) {
if (save_unconsumed_input(zself, err) < 0) {
Py_DECREF(RetVal);
RetVal = NULL;
goto error;
@ -741,26 +791,24 @@ PyZlib_objdecompress(compobject *self, PyObject *args)
if (err == Z_STREAM_END) {
/* This is the logical place to call inflateEnd, but the old behaviour
of only calling it on flush() is preserved. */
self->eof = 1;
zself->eof = 1;
} else if (err != Z_OK && err != Z_BUF_ERROR) {
/* We will only get Z_BUF_ERROR if the output buffer was full
but there wasn't more output when we tried again, so it is
not an error condition.
*/
zlib_error(self->zst, err, "while decompressing data");
zlib_error(zself->zst, err, "while decompressing data");
Py_DECREF(RetVal);
RetVal = NULL;
goto error;
}
if (_PyBytes_Resize(&RetVal, self->zst.total_out - start_total_out) < 0) {
if (_PyBytes_Resize(&RetVal, zself->zst.total_out - start_total_out) < 0) {
Py_CLEAR(RetVal);
}
error:
LEAVE_ZLIB(self);
error_outer:
PyBuffer_Release(&pinput);
LEAVE_ZLIB(zself);
return RetVal;
}
@ -856,12 +904,27 @@ PyZlib_flush(compobject *self, PyObject *args)
}
#ifdef HAVE_ZLIB_COPY
PyDoc_STRVAR(comp_copy__doc__,
"copy() -- Return a copy of the compression object.");
/*[clinic]
zlib.copy
Return a copy of the compression object.
[clinic]*/
PyDoc_STRVAR(zlib_copy__doc__,
"Return a copy of the compression object.\n"
"\n"
"zlib.copy()");
#define ZLIB_COPY_METHODDEF \
{"copy", (PyCFunction)zlib_copy, METH_NOARGS, zlib_copy__doc__},
static PyObject *
PyZlib_copy(compobject *self)
zlib_copy(PyObject *self)
/*[clinic checksum: 7b648de2c1f933ba2b9fa17331ff1a44d9a4a740]*/
{
compobject *zself = (compobject *)self;
compobject *retval = NULL;
int err;
@ -871,8 +934,8 @@ PyZlib_copy(compobject *self)
/* Copy the zstream state
* We use ENTER_ZLIB / LEAVE_ZLIB to make this thread-safe
*/
ENTER_ZLIB(self);
err = deflateCopy(&retval->zst, &self->zst);
ENTER_ZLIB(zself);
err = deflateCopy(&retval->zst, &zself->zst);
switch(err) {
case(Z_OK):
break;
@ -884,28 +947,28 @@ PyZlib_copy(compobject *self)
"Can't allocate memory for compression object");
goto error;
default:
zlib_error(self->zst, err, "while copying compression object");
zlib_error(zself->zst, err, "while copying compression object");
goto error;
}
Py_INCREF(self->unused_data);
Py_INCREF(self->unconsumed_tail);
Py_XINCREF(self->zdict);
Py_INCREF(zself->unused_data);
Py_INCREF(zself->unconsumed_tail);
Py_XINCREF(zself->zdict);
Py_XDECREF(retval->unused_data);
Py_XDECREF(retval->unconsumed_tail);
Py_XDECREF(retval->zdict);
retval->unused_data = self->unused_data;
retval->unconsumed_tail = self->unconsumed_tail;
retval->zdict = self->zdict;
retval->eof = self->eof;
retval->unused_data = zself->unused_data;
retval->unconsumed_tail = zself->unconsumed_tail;
retval->zdict = zself->zdict;
retval->eof = zself->eof;
/* Mark it as being initialized */
retval->is_initialised = 1;
LEAVE_ZLIB(self);
LEAVE_ZLIB(zself);
return (PyObject *)retval;
error:
LEAVE_ZLIB(self);
LEAVE_ZLIB(zself);
Py_XDECREF(retval);
return NULL;
}
@ -1055,16 +1118,14 @@ static PyMethodDef comp_methods[] =
{"flush", (binaryfunc)PyZlib_flush, METH_VARARGS,
comp_flush__doc__},
#ifdef HAVE_ZLIB_COPY
{"copy", (PyCFunction)PyZlib_copy, METH_NOARGS,
comp_copy__doc__},
ZLIB_COPY_METHODDEF
#endif
{NULL, NULL}
};
static PyMethodDef Decomp_methods[] =
{
{"decompress", (binaryfunc)PyZlib_objdecompress, METH_VARARGS,
decomp_decompress__doc__},
ZLIB_DECOMPRESS_METHODDEF
{"flush", (binaryfunc)PyZlib_unflush, METH_VARARGS,
decomp_flush__doc__},
#ifdef HAVE_ZLIB_COPY