view Modules/dlmodule.c @ 16798:258dcafe2d0b legacy-trunk

Gustavo Niemeyer <niemeyer@conectiva.com>: Fixed recno support (keys are integers rather than strings). Work around DB bug that cause stdin to be closed by rnopen() when the DB file needed to exist but did not (no longer segfaults). This closes SF tracker patch #403445. Also wrapped some long lines and added whitespace around operators -- FLD.
author Fred Drake <fdrake@acm.org>
date Tue, 27 Feb 2001 18:56:46 +0000
parents 9f86cba4766b
children 8156879fe60d
line wrap: on
line source


/* dl module */

#include "Python.h"

#include <dlfcn.h>

#ifndef RTLD_LAZY
#define RTLD_LAZY 1
#endif

typedef void *PyUnivPtr;
typedef struct {
	PyObject_HEAD
	PyUnivPtr *dl_handle;
} dlobject;

staticforward PyTypeObject Dltype;

static PyObject *Dlerror;

static PyObject *
newdlobject(PyUnivPtr *handle)
{
	dlobject *xp;
	xp = PyObject_New(dlobject, &Dltype);
	if (xp == NULL)
		return NULL;
	xp->dl_handle = handle;
	return (PyObject *)xp;
}

static void
dl_dealloc(dlobject *xp)
{
	if (xp->dl_handle != NULL)
		dlclose(xp->dl_handle);
	PyObject_Del(xp);
}

static PyObject *
dl_close(dlobject *xp, PyObject *args)
{
	if (!PyArg_Parse(args, ""))
		return NULL;
	if (xp->dl_handle != NULL) {
		dlclose(xp->dl_handle);
		xp->dl_handle = NULL;
	}
	Py_INCREF(Py_None);
	return Py_None;
}

static PyObject *
dl_sym(dlobject *xp, PyObject *args)
{
	char *name;
	PyUnivPtr *func;
	if (!PyArg_Parse(args, "s", &name))
		return NULL;
	func = dlsym(xp->dl_handle, name);
	if (func == NULL) {
		Py_INCREF(Py_None);
		return Py_None;
	}
	return PyInt_FromLong((long)func);
}

static PyObject *
dl_call(dlobject *xp, PyObject *args)
{
	PyObject *name;
	long (*func)(long, long, long, long, long,
                     long, long, long, long, long);
	long alist[10];
	long res;
	int i;
	int n = PyTuple_Size(args);
	if (n < 1) {
		PyErr_SetString(PyExc_TypeError, "at least a name is needed");
		return NULL;
	}
	name = PyTuple_GetItem(args, 0);
	if (!PyString_Check(name)) {
		PyErr_SetString(PyExc_TypeError,
				"function name must be a string");
		return NULL;
	}
	func = (long (*)(long, long, long, long, long, 
                         long, long, long, long, long)) 
          dlsym(xp->dl_handle, PyString_AsString(name));
	if (func == NULL) {
		PyErr_SetString(PyExc_ValueError, dlerror());
		return NULL;
	}
	if (n-1 > 10) {
		PyErr_SetString(PyExc_TypeError,
				"too many arguments (max 10)");
		return NULL;
	}
	for (i = 1; i < n; i++) {
		PyObject *v = PyTuple_GetItem(args, i);
		if (PyInt_Check(v))
			alist[i-1] = PyInt_AsLong(v);
		else if (PyString_Check(v))
			alist[i-1] = (long)PyString_AsString(v);
		else if (v == Py_None)
			alist[i-1] = (long) ((char *)NULL);
		else {
			PyErr_SetString(PyExc_TypeError,
				   "arguments must be int, string or None");
			return NULL;
		}
	}
	for (; i <= 10; i++)
		alist[i-1] = 0;
	res = (*func)(alist[0], alist[1], alist[2], alist[3], alist[4],
		      alist[5], alist[6], alist[7], alist[8], alist[9]);
	return PyInt_FromLong(res);
}

static PyMethodDef dlobject_methods[] = {
	{"call",	(PyCFunction)dl_call,	1 /* varargs */},
	{"sym", 	(PyCFunction)dl_sym},
	{"close",	(PyCFunction)dl_close},
	{NULL,  	NULL}			 /* Sentinel */
};

static PyObject *
dl_getattr(dlobject *xp, char *name)
{
	return Py_FindMethod(dlobject_methods, (PyObject *)xp, name);
}


static PyTypeObject Dltype = {
	PyObject_HEAD_INIT(&PyType_Type)
	0,			/*ob_size*/
	"dl",			/*tp_name*/
	sizeof(dlobject),	/*tp_basicsize*/
	0,			/*tp_itemsize*/
	/* methods */
	(destructor)dl_dealloc, /*tp_dealloc*/
	0,			/*tp_print*/
	(getattrfunc)dl_getattr,/*tp_getattr*/
	0,			/*tp_setattr*/
	0,			/*tp_compare*/
	0,			/*tp_repr*/
	0,			/*tp_as_number*/
	0,			/*tp_as_sequence*/
	0,			/*tp_as_mapping*/
	0,			/*tp_hash*/
};

static PyObject *
dl_open(PyObject *self, PyObject *args)
{
	char *name;
	int mode;
	PyUnivPtr *handle;
	if (PyArg_Parse(args, "z", &name))
		mode = RTLD_LAZY;
	else {
		PyErr_Clear();
		if (!PyArg_Parse(args, "(zi)", &name, &mode))
			return NULL;
#ifndef RTLD_NOW
		if (mode != RTLD_LAZY) {
			PyErr_SetString(PyExc_ValueError, "mode must be 1");
			return NULL;
		}
#endif
	}
	handle = dlopen(name, mode);
	if (handle == NULL) {
		PyErr_SetString(Dlerror, dlerror());
		return NULL;
	}
	return newdlobject(handle);
}

static PyMethodDef dl_methods[] = {
	{"open",	dl_open},
	{NULL,		NULL}		/* sentinel */
};

/* From socketmodule.c
 * Convenience routine to export an integer value.
 *
 * Errors are silently ignored, for better or for worse...
 */
static void
insint(PyObject *d, char *name, int value)
{
	PyObject *v = PyInt_FromLong((long) value);
	if (!v || PyDict_SetItemString(d, name, v))
		PyErr_Clear();

	Py_XDECREF(v);
}

void
initdl(void)
{
	PyObject *m, *d, *x;

	if (sizeof(int) != sizeof(long) ||
	    sizeof(long) != sizeof(char *)) {
		PyErr_SetString(PyExc_SystemError,
 "module dl requires sizeof(int) == sizeof(long) == sizeof(char*)");
		return;
	}

	/* Create the module and add the functions */
	m = Py_InitModule("dl", dl_methods);

	/* Add some symbolic constants to the module */
	d = PyModule_GetDict(m);
	Dlerror = x = PyErr_NewException("dl.error", NULL, NULL);
	PyDict_SetItemString(d, "error", x);
	x = PyInt_FromLong((long)RTLD_LAZY);
	PyDict_SetItemString(d, "RTLD_LAZY", x);
#define INSINT(X)    insint(d,#X,X)
#ifdef RTLD_NOW
        INSINT(RTLD_NOW);
#endif
#ifdef RTLD_NOLOAD
        INSINT(RTLD_NOLOAD);
#endif
#ifdef RTLD_GLOBAL
        INSINT(RTLD_GLOBAL);
#endif
#ifdef RTLD_LOCAL
        INSINT(RTLD_LOCAL);
#endif
#ifdef RTLD_PARENT
        INSINT(RTLD_PARENT);
#endif
#ifdef RTLD_GROUP
        INSINT(RTLD_GROUP);
#endif
#ifdef RTLD_WORLD
        INSINT(RTLD_WORLD);
#endif
#ifdef RTLD_NODELETE
        INSINT(RTLD_NODELETE);
#endif
}