summaryrefslogtreecommitdiffstats
path: root/Modules/_struct.c
diff options
context:
space:
mode:
Diffstat (limited to 'Modules/_struct.c')
-rw-r--r--Modules/_struct.c95
1 files changed, 76 insertions, 19 deletions
diff --git a/Modules/_struct.c b/Modules/_struct.c
index df243ec..8d0a3bc 100644
--- a/Modules/_struct.c
+++ b/Modules/_struct.c
@@ -31,6 +31,17 @@ static PyObject *pylong_ulong_mask = NULL;
static PyObject *pyint_zero = NULL;
#endif
+/* If PY_STRUCT_FLOAT_COERCE is defined, the struct module will allow float
+ arguments for integer formats with a warning for backwards
+ compatibility. */
+
+#define PY_STRUCT_FLOAT_COERCE 1
+
+#ifdef PY_STRUCT_FLOAT_COERCE
+#define FLOAT_COERCE "integer argument expected, got float"
+#endif
+
+
/* The translation function for each format character is table driven */
typedef struct _formatdef {
char format;
@@ -135,6 +146,21 @@ get_long(PyObject *v, long *p)
{
long x = PyInt_AsLong(v);
if (x == -1 && PyErr_Occurred()) {
+#ifdef PY_STRUCT_FLOAT_COERCE
+ if (PyFloat_Check(v)) {
+ PyObject *o;
+ int res;
+ PyErr_Clear();
+ if (PyErr_WarnEx(PyExc_DeprecationWarning, FLOAT_COERCE, 2) < 0)
+ return -1;
+ o = PyNumber_Int(v);
+ if (o == NULL)
+ return -1;
+ res = get_long(o, p);
+ Py_DECREF(o);
+ return res;
+ }
+#endif
if (PyErr_ExceptionMatches(PyExc_TypeError))
PyErr_SetString(StructError,
"required argument is not an integer");
@@ -214,15 +240,33 @@ get_ulonglong(PyObject *v, unsigned PY_LONG_LONG *p)
/* Helper routine to get a Python integer and raise the appropriate error
if it isn't one */
+#define INT_OVERFLOW "struct integer overflow masking is deprecated"
+
static int
get_wrapped_long(PyObject *v, long *p)
{
if (get_long(v, p) < 0) {
- if (PyLong_Check(v) && PyErr_ExceptionMatches(PyExc_OverflowError)) {
+ if (PyLong_Check(v) &&
+ PyErr_ExceptionMatches(PyExc_OverflowError)) {
PyObject *wrapped;
long x;
PyErr_Clear();
- if (PyErr_Warn(PyExc_DeprecationWarning, "struct integer overflow masking is deprecated") < 0)
+#ifdef PY_STRUCT_FLOAT_COERCE
+ if (PyFloat_Check(v)) {
+ PyObject *o;
+ int res;
+ PyErr_Clear();
+ if (PyErr_WarnEx(PyExc_DeprecationWarning, FLOAT_COERCE, 2) < 0)
+ return -1;
+ o = PyNumber_Int(v);
+ if (o == NULL)
+ return -1;
+ res = get_wrapped_long(o, p);
+ Py_DECREF(o);
+ return res;
+ }
+#endif
+ if (PyErr_WarnEx(PyExc_DeprecationWarning, INT_OVERFLOW, 2) < 0)
return -1;
wrapped = PyNumber_And(v, pylong_ulong_mask);
if (wrapped == NULL)
@@ -246,10 +290,25 @@ get_wrapped_ulong(PyObject *v, unsigned long *p)
if (x == -1 && PyErr_Occurred()) {
PyObject *wrapped;
PyErr_Clear();
+#ifdef PY_STRUCT_FLOAT_COERCE
+ if (PyFloat_Check(v)) {
+ PyObject *o;
+ int res;
+ PyErr_Clear();
+ if (PyErr_WarnEx(PyExc_DeprecationWarning, FLOAT_COERCE, 2) < 0)
+ return -1;
+ o = PyNumber_Int(v);
+ if (o == NULL)
+ return -1;
+ res = get_wrapped_ulong(o, p);
+ Py_DECREF(o);
+ return res;
+ }
+#endif
wrapped = PyNumber_And(v, pylong_ulong_mask);
if (wrapped == NULL)
return -1;
- if (PyErr_Warn(PyExc_DeprecationWarning, "struct integer overflow masking is deprecated") < 0) {
+ if (PyErr_WarnEx(PyExc_DeprecationWarning, INT_OVERFLOW, 2) < 0) {
Py_DECREF(wrapped);
return -1;
}
@@ -344,8 +403,8 @@ _range_error(const formatdef *f, int is_unsigned)
Py_XDECREF(ptraceback);
if (msg == NULL)
return -1;
- rval = PyErr_Warn(PyExc_DeprecationWarning,
- PyString_AS_STRING(msg));
+ rval = PyErr_WarnEx(PyExc_DeprecationWarning,
+ PyString_AS_STRING(msg), 2);
Py_DECREF(msg);
if (rval == 0)
return 0;
@@ -1396,23 +1455,17 @@ s_unpack_internal(PyStructObject *soself, char *startfrom) {
const char *res = startfrom + code->offset;
if (e->format == 's') {
v = PyString_FromStringAndSize(res, code->size);
- if (v == NULL)
- goto fail;
- PyTuple_SET_ITEM(result, i++, v);
} else if (e->format == 'p') {
Py_ssize_t n = *(unsigned char*)res;
if (n >= code->size)
n = code->size - 1;
v = PyString_FromStringAndSize(res + 1, n);
- if (v == NULL)
- goto fail;
- PyTuple_SET_ITEM(result, i++, v);
} else {
v = e->unpack(res, e);
- if (v == NULL)
- goto fail;
- PyTuple_SET_ITEM(result, i++, v);
}
+ if (v == NULL)
+ goto fail;
+ PyTuple_SET_ITEM(result, i++, v);
}
return result;
@@ -1438,7 +1491,8 @@ s_unpack(PyObject *self, PyObject *inputstr)
if (inputstr == NULL || !PyString_Check(inputstr) ||
PyString_GET_SIZE(inputstr) != soself->s_size) {
PyErr_Format(StructError,
- "unpack requires a string argument of length %zd", soself->s_size);
+ "unpack requires a string argument of length %zd",
+ soself->s_size);
return NULL;
}
return s_unpack_internal(soself, PyString_AS_STRING(inputstr));
@@ -1504,17 +1558,18 @@ static int
s_pack_internal(PyStructObject *soself, PyObject *args, int offset, char* buf)
{
formatcode *code;
+ /* XXX(nnorwitz): why does i need to be a local? can we use
+ the offset parameter or do we need the wider width? */
Py_ssize_t i;
memset(buf, '\0', soself->s_size);
i = offset;
for (code = soself->s_codes; code->fmtdef != NULL; code++) {
Py_ssize_t n;
- PyObject *v;
+ PyObject *v = PyTuple_GET_ITEM(args, i++);
const formatdef *e = code->fmtdef;
char *res = buf + code->offset;
if (e->format == 's') {
- v = PyTuple_GET_ITEM(args, i++);
if (!PyString_Check(v)) {
PyErr_SetString(StructError,
"argument for 's' must be a string");
@@ -1526,7 +1581,6 @@ s_pack_internal(PyStructObject *soself, PyObject *args, int offset, char* buf)
if (n > 0)
memcpy(res, PyString_AS_STRING(v), n);
} else if (e->format == 'p') {
- v = PyTuple_GET_ITEM(args, i++);
if (!PyString_Check(v)) {
PyErr_SetString(StructError,
"argument for 'p' must be a string");
@@ -1541,7 +1595,6 @@ s_pack_internal(PyStructObject *soself, PyObject *args, int offset, char* buf)
n = 255;
*res = Py_SAFE_DOWNCAST(n, Py_ssize_t, unsigned char);
} else {
- v = PyTuple_GET_ITEM(args, i++);
if (e->pack(res, v, e) < 0) {
if (PyLong_Check(v) && PyErr_ExceptionMatches(PyExc_OverflowError))
PyErr_SetString(StructError,
@@ -1818,4 +1871,8 @@ init_struct(void)
#ifdef PY_STRUCT_OVERFLOW_MASKING
PyModule_AddIntConstant(m, "_PY_STRUCT_OVERFLOW_MASKING", 1);
#endif
+#ifdef PY_STRUCT_FLOAT_COERCE
+ PyModule_AddIntConstant(m, "_PY_STRUCT_FLOAT_COERCE", 1);
+#endif
+
}