]> granicus.if.org Git - python/commitdiff
Added better handling of unsigned longs -- a Python long returned by
authorGuido van Rossum <guido@python.org>
Tue, 31 Dec 1996 16:29:52 +0000 (16:29 +0000)
committerGuido van Rossum <guido@python.org>
Tue, 31 Dec 1996 16:29:52 +0000 (16:29 +0000)
unpack('L', ...) is now acceptable to pack('L', ...).

Modules/structmodule.c

index a96606b3b3ef0348d8265569abb6ee10e370d3c4..5eb7922c6c3f775a4f5c139ea4d2131b299e346b 100644 (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}
 };