diff options
Diffstat (limited to 'Objects/moduleobject.c')
| -rw-r--r-- | Objects/moduleobject.c | 159 | 
1 files changed, 155 insertions, 4 deletions
diff --git a/Objects/moduleobject.c b/Objects/moduleobject.c index e13233a..228ffee 100644 --- a/Objects/moduleobject.c +++ b/Objects/moduleobject.c @@ -4,9 +4,13 @@  #include "Python.h"  #include "structmember.h" +static Py_ssize_t max_module_number; +  typedef struct {  	PyObject_HEAD  	PyObject *md_dict; +	struct PyModuleDef *md_def; +	void *md_state;  } PyModuleObject;  static PyMemberDef module_members[] = { @@ -14,6 +18,14 @@ static PyMemberDef module_members[] = {  	{0}  }; +static PyTypeObject moduledef_type = { +	PyVarObject_HEAD_INIT(&PyType_Type, 0) +	"moduledef",				/* tp_name */ +	sizeof(struct PyModuleDef),		/* tp_size */ +	0,					/* tp_itemsize */ +}; + +  PyObject *  PyModule_New(const char *name)  { @@ -22,6 +34,8 @@ PyModule_New(const char *name)  	m = PyObject_GC_New(PyModuleObject, &PyModule_Type);  	if (m == NULL)  		return NULL; +	m->md_def = NULL; +	m->md_state = NULL;  	nameobj = PyUnicode_FromString(name);  	m->md_dict = PyDict_New();  	if (m->md_dict == NULL || nameobj == NULL) @@ -42,6 +56,106 @@ PyModule_New(const char *name)  	return NULL;  } +static char api_version_warning[] = +"Python C API version mismatch for module %.100s:\ + This Python has API version %d, module %.100s has version %d."; + +PyObject * +PyModule_Create2(struct PyModuleDef* module, int module_api_version) +{ +	PyObject *d, *v, *n; +	PyMethodDef *ml; +	const char* name; +	PyModuleObject *m; +	if (!Py_IsInitialized()) +	    Py_FatalError("Interpreter not initialized (version mismatch?)"); +	if (PyType_Ready(&moduledef_type) < 0) +		return NULL; +	if (module->m_base.m_index == 0) { +		max_module_number++; +		Py_REFCNT(module) = 1; +		Py_TYPE(module) = &moduledef_type; +		module->m_base.m_index = max_module_number; +	} +	name = module->m_name; +	if (module_api_version != PYTHON_API_VERSION) { +		char message[512]; +		PyOS_snprintf(message, sizeof(message),  +			      api_version_warning, name,  +			      PYTHON_API_VERSION, name,  +			      module_api_version); +		if (PyErr_WarnEx(PyExc_RuntimeWarning, message, 1))  +			return NULL; +	} +	/* Make sure name is fully qualified. + +	   This is a bit of a hack: when the shared library is loaded, +	   the module name is "package.module", but the module calls +	   Py_InitModule*() with just "module" for the name.  The shared +	   library loader squirrels away the true name of the module in +	   _Py_PackageContext, and Py_InitModule*() will substitute this +	   (if the name actually matches). +	*/ +	if (_Py_PackageContext != NULL) { +		char *p = strrchr(_Py_PackageContext, '.'); +		if (p != NULL && strcmp(module->m_name, p+1) == 0) { +			name = _Py_PackageContext; +			_Py_PackageContext = NULL; +		} +	} +	if ((m = (PyModuleObject*)PyModule_New(name)) == NULL) +		return NULL; + +	if (module->m_size > 0) { +		m->md_state = PyMem_MALLOC(module->m_size); +		if (!m->md_state) { +			PyErr_NoMemory(); +			Py_DECREF(m); +			return NULL; +		} +	} +			 +	d = PyModule_GetDict((PyObject*)m); +	if (module->m_methods != NULL) { +		n = PyUnicode_FromString(name); +		if (n == NULL) +			return NULL; +		for (ml = module->m_methods; ml->ml_name != NULL; ml++) { +			if ((ml->ml_flags & METH_CLASS) || +			    (ml->ml_flags & METH_STATIC)) { +				PyErr_SetString(PyExc_ValueError, +						"module functions cannot set" +						" METH_CLASS or METH_STATIC"); +				Py_DECREF(n); +				return NULL; +			} +			v = PyCFunction_NewEx(ml, (PyObject*)m, n); +			if (v == NULL) { +				Py_DECREF(n); +				return NULL; +			} +			if (PyDict_SetItemString(d, ml->ml_name, v) != 0) { +				Py_DECREF(v); +				Py_DECREF(n); +				return NULL; +			} +			Py_DECREF(v); +		} +		Py_DECREF(n); +	} +	if (module->m_doc != NULL) { +		v = PyUnicode_FromString(module->m_doc); +		if (v == NULL || PyDict_SetItemString(d, "__doc__", v) != 0) { +			Py_XDECREF(v); +			return NULL; +		} +		Py_DECREF(v); +	} +	m->md_def = module; +	return (PyObject*)m; +} + +  PyObject *  PyModule_GetDict(PyObject *m)  { @@ -96,6 +210,26 @@ PyModule_GetFilename(PyObject *m)  	return PyUnicode_AsString(fileobj);  } +PyModuleDef* +PyModule_GetDef(PyObject* m) +{ +	if (!PyModule_Check(m)) { +		PyErr_BadArgument(); +		return NULL; +	} +	return ((PyModuleObject *)m)->md_def; +} + +void* +PyModule_GetState(PyObject* m) +{ +	if (!PyModule_Check(m)) { +		PyErr_BadArgument(); +		return NULL; +	} +	return ((PyModuleObject *)m)->md_state; +} +  void  _PyModule_Clear(PyObject *m)  { @@ -174,6 +308,8 @@ static void  module_dealloc(PyModuleObject *m)  {  	PyObject_GC_UnTrack(m); +	if (m->md_def && m->md_def->m_free) +		m->md_def->m_free(m);  	if (m->md_dict != NULL) {  		_PyModule_Clear((PyObject *)m);  		Py_DECREF(m->md_dict); @@ -200,16 +336,31 @@ module_repr(PyModuleObject *m)  	return PyUnicode_FromFormat("<module '%s' from '%s'>", name, filename);  } -/* We only need a traverse function, no clear function: If the module -   is in a cycle, md_dict will be cleared as well, which will break -   the cycle. */  static int  module_traverse(PyModuleObject *m, visitproc visit, void *arg)  { +	if (m->md_def && m->md_def->m_traverse) { +		int res = m->md_def->m_traverse((PyObject*)m, visit, arg); +		if (res) +			return res; +	}  	Py_VISIT(m->md_dict);  	return 0;  } +static int +module_clear(PyModuleObject *m) +{ +	if (m->md_def && m->md_def->m_clear) { +		int res = m->md_def->m_clear((PyObject*)m); +		if (res) +			return res; +	} +	Py_CLEAR(m->md_dict); +	return 0; +} +	 +  PyDoc_STRVAR(module_doc,  "module(name[, doc])\n\  \n\ @@ -240,7 +391,7 @@ PyTypeObject PyModule_Type = {  		Py_TPFLAGS_BASETYPE,		/* tp_flags */  	module_doc,				/* tp_doc */  	(traverseproc)module_traverse,		/* tp_traverse */ -	0,					/* tp_clear */ +	(inquiry)module_clear,			/* tp_clear */  	0,					/* tp_richcompare */  	0,					/* tp_weaklistoffset */  	0,					/* tp_iter */  | 
