PageRenderTime 326ms CodeModel.GetById 121ms app.highlight 109ms RepoModel.GetById 92ms app.codeStats 0ms

/Python/structmember.c

http://unladen-swallow.googlecode.com/
C | 348 lines | 326 code | 13 blank | 9 comment | 103 complexity | 251600bf811a4b1fc817bf7063bd7e9e MD5 | raw file
  1
  2/* Map C struct members to Python object attributes */
  3
  4#include "Python.h"
  5
  6#include "structmember.h"
  7
  8static PyObject *
  9listmembers(struct memberlist *mlist)
 10{
 11	int i, n;
 12	PyObject *v;
 13	for (n = 0; mlist[n].name != NULL; n++)
 14		;
 15	v = PyList_New(n);
 16	if (v != NULL) {
 17		for (i = 0; i < n; i++)
 18			PyList_SetItem(v, i,
 19				       PyString_FromString(mlist[i].name));
 20		if (PyErr_Occurred()) {
 21			Py_DECREF(v);
 22			v = NULL;
 23		}
 24		else {
 25			PyList_Sort(v);
 26		}
 27	}
 28	return v;
 29}
 30
 31PyObject *
 32PyMember_Get(const char *addr, struct memberlist *mlist, const char *name)
 33{
 34	struct memberlist *l;
 35
 36	if (strcmp(name, "__members__") == 0)
 37		return listmembers(mlist);
 38	for (l = mlist; l->name != NULL; l++) {
 39		if (strcmp(l->name, name) == 0) {
 40			PyMemberDef copy;
 41			copy.name = l->name;
 42			copy.type = l->type;
 43			copy.offset = l->offset;
 44			copy.flags = l->flags;
 45			copy.doc = NULL;
 46			return PyMember_GetOne(addr, &copy);
 47		}
 48	}
 49	PyErr_SetString(PyExc_AttributeError, name);
 50	return NULL;
 51}
 52
 53PyObject *
 54PyMember_GetOne(const char *addr, PyMemberDef *l)
 55{
 56	PyObject *v;
 57	if ((l->flags & READ_RESTRICTED) &&
 58	    PyEval_GetRestricted()) {
 59		PyErr_SetString(PyExc_RuntimeError, "restricted attribute");
 60		return NULL;
 61	}
 62	addr += l->offset;
 63	switch (l->type) {
 64	case T_BOOL:
 65		v = PyBool_FromLong(*(char*)addr);
 66		break;
 67	case T_BYTE:
 68		v = PyInt_FromLong(*(char*)addr);
 69		break;
 70	case T_UBYTE:
 71		v = PyLong_FromUnsignedLong(*(unsigned char*)addr);
 72		break;
 73	case T_SHORT:
 74		v = PyInt_FromLong(*(short*)addr);
 75		break;
 76	case T_USHORT:
 77		v = PyLong_FromUnsignedLong(*(unsigned short*)addr);
 78		break;
 79	case T_INT:
 80		v = PyInt_FromLong(*(int*)addr);
 81		break;
 82	case T_UINT:
 83		v = PyLong_FromUnsignedLong(*(unsigned int*)addr);
 84		break;
 85	case T_LONG:
 86		v = PyInt_FromLong(*(long*)addr);
 87		break;
 88	case T_ULONG:
 89		v = PyLong_FromUnsignedLong(*(unsigned long*)addr);
 90		break;
 91	case T_PYSSIZET:
 92		v = PyInt_FromSsize_t(*(Py_ssize_t*)addr);
 93		break;
 94	case T_FLOAT:
 95		v = PyFloat_FromDouble((double)*(float*)addr);
 96		break;
 97	case T_DOUBLE:
 98		v = PyFloat_FromDouble(*(double*)addr);
 99		break;
100	case T_STRING:
101		if (*(char**)addr == NULL) {
102			Py_INCREF(Py_None);
103			v = Py_None;
104		}
105		else
106			v = PyString_FromString(*(char**)addr);
107		break;
108	case T_STRING_INPLACE:
109		v = PyString_FromString((char*)addr);
110		break;
111	case T_CHAR:
112		v = PyString_FromStringAndSize((char*)addr, 1);
113		break;
114	case T_OBJECT:
115		v = *(PyObject **)addr;
116		if (v == NULL)
117			v = Py_None;
118		Py_INCREF(v);
119		break;
120	case T_OBJECT_EX:
121		v = *(PyObject **)addr;
122		if (v == NULL)
123			PyErr_SetString(PyExc_AttributeError, l->name);
124		Py_XINCREF(v);
125		break;
126#ifdef HAVE_LONG_LONG
127	case T_LONGLONG:
128		v = PyLong_FromLongLong(*(PY_LONG_LONG *)addr);
129		break;
130	case T_ULONGLONG:
131		v = PyLong_FromUnsignedLongLong(*(unsigned PY_LONG_LONG *)addr);
132		break;
133#endif /* HAVE_LONG_LONG */
134	default:
135		PyErr_SetString(PyExc_SystemError, "bad memberdescr type");
136		v = NULL;
137	}
138	return v;
139}
140
141int
142PyMember_Set(char *addr, struct memberlist *mlist, const char *name, PyObject *v)
143{
144	struct memberlist *l;
145
146	for (l = mlist; l->name != NULL; l++) {
147		if (strcmp(l->name, name) == 0) {
148			PyMemberDef copy;
149			copy.name = l->name;
150			copy.type = l->type;
151			copy.offset = l->offset;
152			copy.flags = l->flags;
153			copy.doc = NULL;
154			return PyMember_SetOne(addr, &copy, v);
155		}
156	}
157
158	PyErr_SetString(PyExc_AttributeError, name);
159	return -1;
160}
161
162#define WARN(msg)					\
163    do {						\
164	if (PyErr_Warn(PyExc_RuntimeWarning, msg) < 0)	\
165		return -1;				\
166    } while (0)
167
168int
169PyMember_SetOne(char *addr, PyMemberDef *l, PyObject *v)
170{
171	PyObject *oldv;
172
173	if ((l->flags & READONLY) || l->type == T_STRING)
174	{
175		PyErr_SetString(PyExc_TypeError, "readonly attribute");
176		return -1;
177	}
178	if ((l->flags & PY_WRITE_RESTRICTED) && PyEval_GetRestricted()) {
179		PyErr_SetString(PyExc_RuntimeError, "restricted attribute");
180		return -1;
181	}
182	if (v == NULL && l->type != T_OBJECT_EX && l->type != T_OBJECT) {
183		PyErr_SetString(PyExc_TypeError,
184				"can't delete numeric/char attribute");
185		return -1;
186	}
187	addr += l->offset;
188	switch (l->type) {
189	case T_BOOL:{
190		if (!PyBool_Check(v)) {
191			PyErr_SetString(PyExc_TypeError,
192					"attribute value type must be bool");
193			return -1;
194		}
195		if (v == Py_True)
196			*(char*)addr = (char) 1;
197		else
198			*(char*)addr = (char) 0;
199		break;
200		}
201	case T_BYTE:{
202		long long_val = PyInt_AsLong(v);
203		if ((long_val == -1) && PyErr_Occurred())
204			return -1;
205		*(char*)addr = (char)long_val;
206		/* XXX: For compatibility, only warn about truncations
207		   for now. */
208		if ((long_val > CHAR_MAX) || (long_val < CHAR_MIN))
209			WARN("Truncation of value to char");
210		break;
211		}
212	case T_UBYTE:{
213		long long_val = PyInt_AsLong(v);
214		if ((long_val == -1) && PyErr_Occurred())
215			return -1;
216		*(unsigned char*)addr = (unsigned char)long_val;
217		if ((long_val > UCHAR_MAX) || (long_val < 0))
218			WARN("Truncation of value to unsigned char");
219		break;
220		}
221	case T_SHORT:{
222		long long_val = PyInt_AsLong(v);
223		if ((long_val == -1) && PyErr_Occurred())
224			return -1;
225		*(short*)addr = (short)long_val;
226		if ((long_val > SHRT_MAX) || (long_val < SHRT_MIN))
227			WARN("Truncation of value to short");
228		break;
229		}
230	case T_USHORT:{
231		long long_val = PyInt_AsLong(v);
232		if ((long_val == -1) && PyErr_Occurred())
233			return -1;
234		*(unsigned short*)addr = (unsigned short)long_val;
235		if ((long_val > USHRT_MAX) || (long_val < 0))
236			WARN("Truncation of value to unsigned short");
237		break;
238		}
239  	case T_INT:{
240		long long_val = PyInt_AsLong(v);
241		if ((long_val == -1) && PyErr_Occurred())
242			return -1;
243		*(int *)addr = (int)long_val;
244		if ((long_val > INT_MAX) || (long_val < INT_MIN))
245			WARN("Truncation of value to int");
246		break;
247		}
248	case T_UINT:{
249		unsigned long ulong_val = PyLong_AsUnsignedLong(v);
250		if ((ulong_val == (unsigned int)-1) && PyErr_Occurred()) {
251			/* XXX: For compatibility, accept negative int values
252			   as well. */
253			PyErr_Clear();
254			ulong_val = PyLong_AsLong(v);
255			if ((ulong_val == (unsigned int)-1) && PyErr_Occurred())
256				return -1;
257			*(unsigned int *)addr = (unsigned int)ulong_val;
258			WARN("Writing negative value into unsigned field");
259		} else
260			*(unsigned int *)addr = (unsigned int)ulong_val;
261		if (ulong_val > UINT_MAX)
262			WARN("Truncation of value to unsigned int");
263		break;
264		}
265	case T_LONG:{
266		*(long*)addr = PyLong_AsLong(v);
267		if ((*(long*)addr == -1) && PyErr_Occurred())
268			return -1;
269		break;
270		}
271	case T_ULONG:{
272		*(unsigned long*)addr = PyLong_AsUnsignedLong(v);
273		if ((*(unsigned long*)addr == (unsigned long)-1)
274		    && PyErr_Occurred()) {
275			/* XXX: For compatibility, accept negative int values
276			   as well. */
277			PyErr_Clear();
278			*(unsigned long*)addr = PyLong_AsLong(v);
279			if ((*(unsigned long*)addr == (unsigned int)-1)
280			    && PyErr_Occurred())
281				return -1;
282			WARN("Writing negative value into unsigned field");
283		}
284		break;
285		}
286	case T_PYSSIZET:{
287		*(Py_ssize_t*)addr = PyInt_AsSsize_t(v);
288		if ((*(Py_ssize_t*)addr == (Py_ssize_t)-1)
289		    && PyErr_Occurred())
290				return -1;
291		break;
292		}
293	case T_FLOAT:{
294		double double_val = PyFloat_AsDouble(v);
295		if ((double_val == -1) && PyErr_Occurred())
296			return -1;
297		*(float*)addr = (float)double_val;
298		break;
299		}
300	case T_DOUBLE:
301		*(double*)addr = PyFloat_AsDouble(v);
302		if ((*(double*)addr == -1) && PyErr_Occurred())
303			return -1;
304		break;
305	case T_OBJECT:
306	case T_OBJECT_EX:
307		Py_XINCREF(v);
308		oldv = *(PyObject **)addr;
309		*(PyObject **)addr = v;
310		Py_XDECREF(oldv);
311		break;
312	case T_CHAR:
313		if (PyString_Check(v) && PyString_Size(v) == 1) {
314			*(char*)addr = PyString_AsString(v)[0];
315		}
316		else {
317			PyErr_BadArgument();
318			return -1;
319		}
320		break;
321#ifdef HAVE_LONG_LONG
322	case T_LONGLONG:{
323		PY_LONG_LONG value;
324		*(PY_LONG_LONG*)addr = value = PyLong_AsLongLong(v);
325		if ((value == -1) && PyErr_Occurred())
326			return -1;
327		break;
328		}
329	case T_ULONGLONG:{
330		unsigned PY_LONG_LONG value;
331		/* ??? PyLong_AsLongLong accepts an int, but PyLong_AsUnsignedLongLong
332			doesn't ??? */
333		if (PyLong_Check(v))
334			*(unsigned PY_LONG_LONG*)addr = value = PyLong_AsUnsignedLongLong(v);
335		else
336			*(unsigned PY_LONG_LONG*)addr = value = PyInt_AsLong(v);
337		if ((value == (unsigned PY_LONG_LONG)-1) && PyErr_Occurred())
338			return -1;
339		break;
340		}
341#endif /* HAVE_LONG_LONG */
342	default:
343		PyErr_Format(PyExc_SystemError,
344			     "bad memberdescr type for %s", l->name);
345		return -1;
346	}
347	return 0;
348}