view Python/structmember.c @ 31058:bf7df48012cb 2.3

Py_Finalize(): disabled the second call of cyclic gc, and added extensive comments about why both calls to cyclic gc here can cause problems. Already fixed on the trunk. Since the calls were introduced in 2.3, that's the end of it.
author Tim Peters <tim.peters@gmail.com>
date Mon, 01 Dec 2003 22:13:12 +0000
parents ef6f692c76e2
children 86fdf8fe7f17
line wrap: on
line source


/* Map C struct members to Python object attributes */

#include "Python.h"

#include "structmember.h"

static PyObject *
listmembers(struct memberlist *mlist)
{
	int i, n;
	PyObject *v;
	for (n = 0; mlist[n].name != NULL; n++)
		;
	v = PyList_New(n);
	if (v != NULL) {
		for (i = 0; i < n; i++)
			PyList_SetItem(v, i,
				       PyString_FromString(mlist[i].name));
		if (PyErr_Occurred()) {
			Py_DECREF(v);
			v = NULL;
		}
		else {
			PyList_Sort(v);
		}
	}
	return v;
}

PyObject *
PyMember_Get(char *addr, struct memberlist *mlist, char *name)
{
	struct memberlist *l;

	if (strcmp(name, "__members__") == 0)
		return listmembers(mlist);
	for (l = mlist; l->name != NULL; l++) {
		if (strcmp(l->name, name) == 0) {
			PyMemberDef copy;
			copy.name = l->name;
			copy.type = l->type;
			copy.offset = l->offset;
			copy.flags = l->flags;
			copy.doc = NULL;
			return PyMember_GetOne(addr, &copy);
		}
	}
	PyErr_SetString(PyExc_AttributeError, name);
	return NULL;
}

PyObject *
PyMember_GetOne(char *addr, PyMemberDef *l)
{
	PyObject *v;
	if ((l->flags & READ_RESTRICTED) &&
	    PyEval_GetRestricted()) {
		PyErr_SetString(PyExc_RuntimeError, "restricted attribute");
		return NULL;
	}
	addr += l->offset;
	switch (l->type) {
	case T_BYTE:
		v = PyInt_FromLong(
			(long) (((*(char*)addr & 0xff) ^ 0x80) - 0x80));
		break;
	case T_UBYTE:
		v = PyInt_FromLong((long) *(char*)addr & 0xff);
		break;
	case T_SHORT:
		v = PyInt_FromLong((long) *(short*)addr);
		break;
	case T_USHORT:
		v = PyInt_FromLong((long) *(unsigned short*)addr);
		break;
	case T_INT:
		v = PyInt_FromLong((long) *(int*)addr);
		break;
	case T_UINT:
		v = PyInt_FromLong((long) *(unsigned int*)addr);
		break;
	case T_LONG:
		v = PyInt_FromLong(*(long*)addr);
		break;
	case T_ULONG:
		v = PyLong_FromDouble((double) *(unsigned long*)addr);
		break;
	case T_FLOAT:
		v = PyFloat_FromDouble((double)*(float*)addr);
		break;
	case T_DOUBLE:
		v = PyFloat_FromDouble(*(double*)addr);
		break;
	case T_STRING:
		if (*(char**)addr == NULL) {
			Py_INCREF(Py_None);
			v = Py_None;
		}
		else
			v = PyString_FromString(*(char**)addr);
		break;
	case T_STRING_INPLACE:
		v = PyString_FromString((char*)addr);
		break;
#ifdef macintosh
	case T_PSTRING:
		if (*(char**)addr == NULL) {
			Py_INCREF(Py_None);
			v = Py_None;
		}
		else
			v = PyString_FromStringAndSize(
				(*(char**)addr)+1,
				**(unsigned char**)addr);
		break;
	case T_PSTRING_INPLACE:
		v = PyString_FromStringAndSize(
			((char*)addr)+1,
			*(unsigned char*)addr);
		break;
#endif /* macintosh */
	case T_CHAR:
		v = PyString_FromStringAndSize((char*)addr, 1);
		break;
	case T_OBJECT:
		v = *(PyObject **)addr;
		if (v == NULL)
			v = Py_None;
		Py_INCREF(v);
		break;
	case T_OBJECT_EX:
		v = *(PyObject **)addr;
		if (v == NULL)
			PyErr_SetString(PyExc_AttributeError, l->name);
		Py_XINCREF(v);
		break;
	default:
		PyErr_SetString(PyExc_SystemError, "bad memberdescr type");
		v = NULL;
	}
	return v;
}

int
PyMember_Set(char *addr, struct memberlist *mlist, char *name, PyObject *v)
{
	struct memberlist *l;

	for (l = mlist; l->name != NULL; l++) {
		if (strcmp(l->name, name) == 0) {
			PyMemberDef copy;
			copy.name = l->name;
			copy.type = l->type;
			copy.offset = l->offset;
			copy.flags = l->flags;
			copy.doc = NULL;
			return PyMember_SetOne(addr, &copy, v);
		}
	}

	PyErr_SetString(PyExc_AttributeError, name);
	return -1;
}

int
PyMember_SetOne(char *addr, PyMemberDef *l, PyObject *v)
{
	PyObject *oldv;

	if ((l->flags & READONLY) || l->type == T_STRING
#ifdef macintosh
	    || l->type == T_PSTRING
#endif
		)
	{
		PyErr_SetString(PyExc_TypeError, "readonly attribute");
		return -1;
	}
	if ((l->flags & WRITE_RESTRICTED) && PyEval_GetRestricted()) {
		PyErr_SetString(PyExc_RuntimeError, "restricted attribute");
		return -1;
	}
	if (v == NULL && l->type != T_OBJECT_EX && l->type != T_OBJECT) {
		PyErr_SetString(PyExc_TypeError,
				"can't delete numeric/char attribute");
		return -1;
	}
	addr += l->offset;
	switch (l->type) {
	case T_BYTE:
	case T_UBYTE:
		if (!PyInt_Check(v)) {
			PyErr_BadArgument();
			return -1;
		}
		*(char*)addr = (char) PyInt_AsLong(v);
		break;
	case T_SHORT:
	case T_USHORT:
		if (!PyInt_Check(v)) {
			PyErr_BadArgument();
			return -1;
		}
		*(short*)addr = (short) PyInt_AsLong(v);
		break;
	case T_UINT:
	case T_INT:
		if (!PyInt_Check(v)) {
			PyErr_BadArgument();
			return -1;
		}
		*(int*)addr = (int) PyInt_AsLong(v);
		break;
	case T_LONG:
		if (!PyInt_Check(v)) {
			PyErr_BadArgument();
			return -1;
		}
		*(long*)addr = PyInt_AsLong(v);
		break;
	case T_ULONG:
		if (PyInt_Check(v))
			*(long*)addr = PyInt_AsLong(v);
		else if (PyLong_Check(v))
			*(long*)addr = PyLong_AsLong(v);
		else {
			PyErr_BadArgument();
			return -1;
		}
		break;
	case T_FLOAT:
		if (PyInt_Check(v))
			*(float*)addr =
				(float) PyInt_AsLong(v);
		else if (PyFloat_Check(v))
			*(float*)addr =
				(float) PyFloat_AsDouble(v);
		else {
			PyErr_BadArgument();
			return -1;
		}
		break;
	case T_DOUBLE:
		if (PyInt_Check(v))
			*(double*)addr = (double) PyInt_AsLong(v);
		else if (PyFloat_Check(v))
			*(double*)addr = PyFloat_AsDouble(v);
		else {
			PyErr_BadArgument();
			return -1;
		}
		break;
	case T_OBJECT:
	case T_OBJECT_EX:
		Py_XINCREF(v);
		oldv = *(PyObject **)addr;
		*(PyObject **)addr = v;
		Py_XDECREF(oldv);
		break;
	case T_CHAR:
		if (PyString_Check(v) && PyString_Size(v) == 1) {
			*(char*)addr = PyString_AsString(v)[0];
		}
		else {
			PyErr_BadArgument();
			return -1;
		}
		break;
	default:
		PyErr_Format(PyExc_SystemError,
			     "bad memberdescr type for %s", l->name);
		return -1;
	}
	return 0;
}