Added better handling of unsigned longs -- a Python long returned by

unpack('L', ...) is now acceptable to pack('L', ...).
This commit is contained in:
Guido van Rossum 1996-12-31 16:29:52 +00:00
parent 36bb181cdf
commit 60c50614e1
1 changed files with 163 additions and 27 deletions

View File

@ -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**<bits-per-long> */
static PyObject *offset = NULL;
/* Helper to create 2**<bits-per-long> */
/* 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}
};