diff --git a/Modules/structmodule.c b/Modules/structmodule.c index a96606b3b3e..5eb7922c6c3 100644 --- a/Modules/structmodule.c +++ b/Modules/structmodule.c @@ -73,34 +73,75 @@ typedef struct { char c; double x; } s_double; #endif -/* Helper routine to turn a (signed) long into an unsigned long */ +/* Global that will contain 2** */ + +static PyObject *offset = NULL; + + +/* Helper to create 2** */ /* XXX This assumes 2's complement arithmetic */ +static PyObject * +init_offset() +{ + PyObject *result = NULL; + PyObject *one = PyLong_FromLong(1L); + PyObject *shiftcount = PyLong_FromLong(8 * sizeof(long)); + if (one == NULL || shiftcount == NULL) + goto finally; + result = PyNumber_Lshift(one, shiftcount); + finally: + Py_XDECREF(one); + Py_XDECREF(shiftcount); + return result; +} + + +/* Helper to add offset to a number */ + +static PyObject * +add_offset(v) + PyObject *v; +{ + PyObject *result = NULL; + if (offset == NULL) { + if ((offset = init_offset()) == NULL) + goto finally; + } + result = PyNumber_Add(v, offset); + finally: + return result; +} + + +/* Same, but subtracting */ + +static PyObject * +sub_offset(v) + PyObject *v; +{ + PyObject *result = NULL; + if (offset == NULL) { + if ((offset = init_offset()) == NULL) + goto finally; + } + result = PyNumber_Subtract(v, offset); + finally: + return result; +} + + +/* Helper routine to turn a (signed) long into an unsigned long */ + static PyObject * make_ulong(x) long x; { PyObject *v = PyLong_FromLong(x); if (x < 0 && v != NULL) { - static PyObject *offset = NULL; - PyObject *result = NULL; - if (offset == NULL) { - PyObject *one = PyLong_FromLong(1L); - PyObject *shiftcount = - PyLong_FromLong(8 * sizeof(long)); - if (one == NULL || shiftcount == NULL) - goto bad; - offset = PyNumber_Lshift(one, shiftcount); - bad: - Py_XDECREF(one); - Py_XDECREF(shiftcount); - if (offset == NULL) - goto finally; - } - result = PyNumber_Add(v, offset); - finally: + PyObject *w = add_offset(v); Py_DECREF(v); - return result; + return w; } else return v; @@ -126,6 +167,39 @@ get_long(v, p) } +/* Same, but handling unsigned long */ + +static int +get_ulong(v, p) + PyObject *v; + unsigned long *p; +{ + long x = PyInt_AsLong(v); + PyObject *exc; + if (x == -1 && (exc = PyErr_Occurred()) != NULL) { + if (exc == PyExc_OverflowError) { + /* Try again after subtracting offset */ + PyObject *w; + PyErr_Clear(); + if ((w = sub_offset(v)) == NULL) + return -1; + x = PyInt_AsLong(w); + Py_DECREF(w); + if (x != -1 || (exc = PyErr_Occurred()) == NULL) + goto okay; + } + if (exc == PyExc_TypeError) + PyErr_SetString(StructError, + "required argument is not an integer"); + else + return -1; + } + okay: + *p = x; + return 0; +} + + /* The translation function for each format character is table driven */ typedef struct _formatdef { @@ -290,6 +364,19 @@ np_int(p, v, f) return 0; } +static int +np_uint(p, v, f) + char *p; + PyObject *v; + const formatdef *f; +{ + unsigned long x; + if (get_ulong(v, &x) < 0) + return -1; + * (unsigned int *)p = x; + return 0; +} + static int np_long(p, v, f) char *p; @@ -303,6 +390,19 @@ np_long(p, v, f) return 0; } +static int +np_ulong(p, v, f) + char *p; + PyObject *v; + const formatdef *f; +{ + unsigned long x; + if (get_ulong(v, &x) < 0) + return -1; + * (unsigned long *)p = x; + return 0; +} + static int np_float(p, v, f) char *p; @@ -344,9 +444,9 @@ static formatdef native_table[] = { {'h', sizeof(short), SHORT_ALIGN, nu_short, np_short}, {'H', sizeof(short), SHORT_ALIGN, nu_ushort, np_short}, {'i', sizeof(int), INT_ALIGN, nu_int, np_int}, - {'I', sizeof(int), INT_ALIGN, nu_uint, np_int}, + {'I', sizeof(int), INT_ALIGN, nu_uint, np_uint}, {'l', sizeof(long), LONG_ALIGN, nu_long, np_long}, - {'L', sizeof(long), LONG_ALIGN, nu_ulong, np_long}, + {'L', sizeof(long), LONG_ALIGN, nu_ulong, np_ulong}, {'f', sizeof(float), FLOAT_ALIGN, nu_float, np_float}, {'d', sizeof(double), DOUBLE_ALIGN, nu_double, np_double}, {0} @@ -404,6 +504,24 @@ bp_int(p, v, f) return 0; } +static int +bp_uint(p, v, f) + char *p; + PyObject *v; + const formatdef *f; +{ + unsigned long x; + int i; + if (get_ulong(v, &x) < 0) + return -1; + i = f->size; + do { + p[--i] = x; + x >>= 8; + } while (i > 0); + return 0; +} + static formatdef bigendian_table[] = { {'x', 1, 0, NULL}, {'b', 1, 0, bu_int, bp_int}, @@ -411,11 +529,11 @@ static formatdef bigendian_table[] = { {'c', 1, 0, nu_char, np_char}, {'s', 1, 0, NULL}, {'h', 2, 0, bu_int, bp_int}, - {'H', 2, 0, bu_uint, bp_int}, + {'H', 2, 0, bu_uint, bp_uint}, {'i', 4, 0, bu_int, bp_int}, - {'I', 4, 0, bu_uint, bp_int}, + {'I', 4, 0, bu_uint, bp_uint}, {'l', 4, 0, bu_int, bp_int}, - {'L', 4, 0, bu_uint, bp_int}, + {'L', 4, 0, bu_uint, bp_uint}, /* No float and double! */ {0} }; @@ -472,6 +590,24 @@ lp_int(p, v, f) return 0; } +static int +lp_uint(p, v, f) + char *p; + PyObject *v; + const formatdef *f; +{ + unsigned long x; + int i; + if (get_ulong(v, &x) < 0) + return -1; + i = f->size; + do { + *p++ = x; + x >>= 8; + } while (--i > 0); + return 0; +} + static formatdef lilendian_table[] = { {'x', 1, 0, NULL}, {'b', 1, 0, lu_int, lp_int}, @@ -479,11 +615,11 @@ static formatdef lilendian_table[] = { {'c', 1, 0, nu_char, np_char}, {'s', 1, 0, NULL}, {'h', 2, 0, lu_int, lp_int}, - {'H', 2, 0, lu_uint, lp_int}, + {'H', 2, 0, lu_uint, lp_uint}, {'i', 4, 0, lu_int, lp_int}, - {'I', 4, 0, lu_uint, lp_int}, + {'I', 4, 0, lu_uint, lp_uint}, {'l', 4, 0, lu_int, lp_int}, - {'L', 4, 0, lu_uint, lp_int}, + {'L', 4, 0, lu_uint, lp_uint}, /* No float and double! */ {0} };