[Python-checkins] CVS: python/dist/src/Modules structmodule.c,2.42,2.43

Tim Peters tim_one@users.sourceforge.net
2001年6月10日 16:40:21 -0700


Update of /cvsroot/python/python/dist/src/Modules
In directory usw-pr-cvs1:/tmp/cvs-serv6496/python/dist/src/Modules
Modified Files:
	structmodule.c 
Log Message:
Initial support for 'q' and 'Q' struct format codes: for now, only in
native mode, and only when config #defines HAVE_LONG_LONG. Standard mode
will eventually treat them as 8-byte ints across all platforms, but that
likely requires a new set of routines in longobject.c first (while
sizeof(long) >= 4 is guaranteed by C, there's nothing in C we can rely
on x-platform to hold 8 bytes of int, so we'll have to roll our own;
I'm thinking of a simple pair of conversion functions, Python long
to/from sized vector of unsigned bytes; that may be useful for GMP
conversions too; std q/Q would call them with size fixed at 8).
test_struct.py: In addition to adding some native-mode 'q' and 'Q' tests,
got rid of unused code, and repaired a non-portable assumption about
native sizeof(short) (it isn't 2 on some Cray boxes).
libstruct.tex: In addition to adding a bit of 'q'/'Q' docs (more needed
later), removed an erroneous footnote about 'I' behavior.
Index: structmodule.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Modules/structmodule.c,v
retrieving revision 2.42
retrieving revision 2.43
diff -C2 -r2.42 -r2.43
*** structmodule.c	2001年04月08日 23:39:38	2.42
--- structmodule.c	2001年06月10日 23:40:19	2.43
***************
*** 23,29 ****
 l:long; L:unsigned long; f:float; d:double.\n\
 Special cases (preceding decimal count indicates length):\n\
! s:string (array of char); p: pascal string (w. count byte).\n\
 Special case (only available in native format):\n\
 P:an integer type that is wide enough to hold a pointer.\n\
 Whitespace between formats is ignored.\n\
 \n\
--- 23,31 ----
 l:long; L:unsigned long; f:float; d:double.\n\
 Special cases (preceding decimal count indicates length):\n\
! s:string (array of char); p: pascal string (with count byte).\n\
 Special case (only available in native format):\n\
 P:an integer type that is wide enough to hold a pointer.\n\
+ Special case (not in native mode unless 'long long' in platform C):\n\
+ q:long long; Q:unsigned long long\n\
 Whitespace between formats is ignored.\n\
 \n\
***************
*** 66,69 ****
--- 68,83 ----
 #define VOID_P_ALIGN (sizeof(s_void_p) - sizeof(void *))
 
+ /* We can't support q and Q in native mode unless the compiler does;
+ in std mode, they're 8 bytes on all platforms. */
+ #ifdef HAVE_LONG_LONG
+ typedef struct { char c; LONG_LONG x; } s_long_long;
+ #define LONG_LONG_ALIGN (sizeof(s_long_long) - sizeof(LONG_LONG))
+ 
+ #else
+ static char qQ_error_msg[] =
+ "q and Q unavailable in native mode on this platform; use a standard mode.0円";
+ 
+ #endif
+ 
 #define STRINGIFY(x) #x
 
***************
*** 107,111 ****
--- 121,212 ----
 }
 
+ #ifdef HAVE_LONG_LONG
+ 
+ /* Same, but handling native long long. */
+ 
+ static int
+ get_longlong(PyObject *v, LONG_LONG *p)
+ {
+ 	LONG_LONG x;
+ 	int v_needs_decref = 0;
+ 
+ 	if (PyInt_Check(v)) {
+ 		x = (LONG_LONG)PyInt_AS_LONG(v);
+ 		*p = x;
+ 		return 0;
+ 	}
+ 	if (!PyLong_Check(v)) {
+ 		PyNumberMethods *m = v->ob_type->tp_as_number;
+ 		if (m != NULL && m->nb_long != NULL) {
+ 			v = m->nb_long(v);
+ 			if (v == NULL)
+ 				return -1;
+ 			v_needs_decref = 1;
+ 		}
+ 		if (!PyLong_Check(v)) {
+ 			PyErr_SetString(StructError,
+ 					"cannot convert argument to long");
+ 			if (v_needs_decref)
+ 				Py_DECREF(v);
+ 			return -1;
+ 		}
+ 	}
+ 	assert(PyLong_Check(v));
+ 	x = PyLong_AsLongLong(v);
+ 	if (v_needs_decref)
+ 		Py_DECREF(v);
+ 	if (x == (LONG_LONG)-1 && PyErr_Occurred())
+ 		return -1;
+ 	*p = x;
+ 	return 0;
+ }
+ 
+ /* Same, but handling native unsigned long long. */
 
+ static int
+ get_ulonglong(PyObject *v, unsigned LONG_LONG *p)
+ {
+ 	unsigned LONG_LONG x;
+ 	int v_needs_decref = 0;
+ 
+ 	if (PyInt_Check(v)) {
+ 		long i = PyInt_AS_LONG(v);
+ 		if (i < 0) {
+ 			PyErr_SetString(StructError, "can't convert negative "
+ 					"int to unsigned");
+ 			return -1;
+ 		}
+ 		x = (unsigned LONG_LONG)i;
+ 		*p = x;
+ 		return 0;
+ 	}
+ 	if (!PyLong_Check(v)) {
+ 		PyNumberMethods *m = v->ob_type->tp_as_number;
+ 		if (m != NULL && m->nb_long != NULL) {
+ 			v = m->nb_long(v);
+ 			if (v == NULL)
+ 				return -1;
+ 			v_needs_decref = 1;
+ 		}
+ 		if (!PyLong_Check(v)) {
+ 			PyErr_SetString(StructError,
+ 					"cannot convert argument to long");
+ 			if (v_needs_decref)
+ 				Py_DECREF(v);
+ 			return -1;
+ 		}
+ 	}
+ 	assert(PyLong_Check(v));
+ 	x = PyLong_AsUnsignedLongLong(v);
+ 	if (v_needs_decref)
+ 		Py_DECREF(v);
+ 	if (x == (unsigned LONG_LONG)-1 && PyErr_Occurred())
+ 		return -1;
+ 	*p = x;
+ 	return 0;
+ }
+ 
+ #endif
+ 
 /* Floating point helpers */
 
***************
*** 396,399 ****
--- 497,511 ----
 } formatdef;
 
+ /* A large number of small routines follow, with names of the form
+ 
+ 	[bln][up]_TYPE
+ 
+ [bln] distiguishes among big-endian, little-endian and native.
+ [pu] distiguishes between pack (to struct) and unpack (from struct).
+ TYPE is one of char, byte, ubyte, etc.
+ */
+ 
+ /* Native mode routines. */
+ 
 static PyObject *
 nu_char(const char *p, const formatdef *f)
***************
*** 451,454 ****
--- 563,594 ----
 }
 
+ /* Native mode doesn't support q or Q unless the platform C supports
+ long long (or, on Windows, __int64). */
+ 
+ #ifdef HAVE_LONG_LONG
+ 
+ static PyObject *
+ nu_longlong(const char *p, const formatdef *f)
+ {
+ 	return PyLong_FromLongLong(*(LONG_LONG *)p);
+ }
+ 
+ static PyObject *
+ nu_ulonglong(const char *p, const formatdef *f)
+ {
+ 	return PyLong_FromUnsignedLongLong(*(unsigned LONG_LONG *)p);
+ }
+ 
+ #else
+ 
+ static PyObject *
+ nu_qQerror(const char *p, const formatdef *f)
+ {
+ 	PyErr_SetString(StructError, qQ_error_msg);
+ 	return NULL;
+ }
+ 
+ #endif
+ 
 static PyObject *
 nu_float(const char *p, const formatdef *f)
***************
*** 586,590 ****
--- 726,763 ----
 }
 
+ #ifdef HAVE_LONG_LONG
+ 
 static int
+ np_longlong(char *p, PyObject *v, const formatdef *f)
+ {
+ 	LONG_LONG x;
+ 	if (get_longlong(v, &x) < 0)
+ 		return -1;
+ 	* (LONG_LONG *)p = x;
+ 	return 0;
+ }
+ 
+ static int
+ np_ulonglong(char *p, PyObject *v, const formatdef *f)
+ {
+ 	unsigned LONG_LONG x;
+ 	if (get_ulonglong(v, &x) < 0)
+ 		return -1;
+ 	* (unsigned LONG_LONG *)p = x;
+ 	return 0;
+ }
+ 
+ #else
+ 
+ static int
+ np_qQerror(char *p, PyObject *v, const formatdef *f)
+ {
+ 	PyErr_SetString(StructError, qQ_error_msg);
+ 	return -1;
+ }
+ 
+ #endif
+ 
+ static int
 np_float(char *p, PyObject *v, const formatdef *f)
 {
***************
*** 643,646 ****
--- 816,831 ----
 	{'d',	sizeof(double),	DOUBLE_ALIGN,	nu_double,	np_double},
 	{'P',	sizeof(void *),	VOID_P_ALIGN,	nu_void_p,	np_void_p},
+ #ifdef HAVE_LONG_LONG
+ 	{'q',	sizeof(LONG_LONG), LONG_LONG_ALIGN, nu_longlong, np_longlong},
+ 	{'Q',	sizeof(LONG_LONG), LONG_LONG_ALIGN, nu_ulonglong,np_ulonglong},
+ #else
+ 	/* n[pu]_qQerror just raise errors, but give them "the expected" size
+ 	 and alignment anyway so that calcsize returns something reasonable,
+ 	 and so unpack code that works on a 'long long' platform ends up in
+ 	 the error routine instead of with a mysterious "unpack str size
+ 	 does not match format" msg when run on a non-'long long' box. */
+ 	{'q',	8,		8, 		nu_qQerror,	 np_qQerror},
+ 	{'Q',	8,		8, 		nu_qQerror,	 np_qQerror},
+ #endif
 	{0}
 };

AltStyle によって変換されたページ (->オリジナル) /