//*****************************************************************************
//
// pyauxiliary.c
//
// This is a wrapper around the auxiliary data system so python can make use
// of it. Allows python modules to install new auxiliary data on characters,
// rooms, objects, etc...
//
//*****************************************************************************
#include <Python.h>
#include <structmember.h>
#include "../mud.h"
#include "../utils.h"
#include "../storage.h"
#include "../auxiliary.h"
#include "pystorage.h"
//*****************************************************************************
// local variables and datastructures
//*****************************************************************************
// the minimum size of our aux table
#define MIN_AUX_TABLE_SIZE 50
// holds a map from auxiliary data names to their prototype
HASHTABLE *aux_table = NULL;
//*****************************************************************************
// the wrapper layer between python and C auxiliary data
//*****************************************************************************
PyObject *newPyAuxiliaryData(const char *keyword) {
// look up the prototype
PyObject *proto = hashGet(aux_table, keyword);
// make sure we've got an OK proto
if(proto == NULL)
return NULL;
else {
// create a new instance of the proto
PyObject *instance = PyInstance_New(proto, NULL, NULL);
return instance;
}
}
void deletePyAuxiliaryData(PyObject *data) {
Py_DECREF(data);
}
void pyAuxiliaryDataCopyTo(PyObject *from, PyObject *to) {
PyObject *retval = PyObject_CallMethod(from, "copyTo", "O", to);
Py_XDECREF(retval);
}
PyObject *pyAuxiliaryDataCopy(PyObject *data) {
PyObject *retval = PyObject_CallMethod(data, "copy", NULL);
return retval;
}
STORAGE_SET *pyAuxiliaryDataStore(PyObject *data) {
PyObject *pyset = PyObject_CallMethod(data, "store", NULL);
STORAGE_SET *set = NULL;
// make sure the set exists
if(pyset == NULL || pyset == Py_None)
set = new_storage_set();
else
set = PyStorageSet_AsSet(pyset);
Py_XDECREF(pyset);
return set;
}
PyObject *pyAuxiliaryDataRead(const char *keyword, STORAGE_SET *set) {
// look up the prototype
PyObject *proto = hashGet(aux_table, keyword);
// make sure we've got an OK proto
if(proto == NULL)
return NULL;
else {
// build our arguments and keywords
PyObject *pystore = newPyStorageSet(set);
PyObject *args = Py_BuildValue("(O)", newPyStorageSet(set));
PyObject *instance = PyInstance_New(proto, args, NULL);
Py_DECREF(args);
Py_DECREF(pystore);
return instance;
}
}
//*****************************************************************************
// implementation of the pyauxiliary method
//*****************************************************************************
//
// install new python auxiliary data. Auxiliary data must be a python CLASS
// OBJECT that has 4 functions:
// __init__ this function initializes the auxiliary data. It takes an
// optional argument that is a storage set which should be used
// to initialize the values of the auxiliary data if it is supplied
// copy returns a copy of the auxiliary data
// copyTo the values of the auxiliary data to another auxiliary data
// supplied as an argument to the function
// store returns a storage set representation of the auxiliary data
PyObject *PyAuxiliary_install(PyObject *self, PyObject *args) {
PyObject *proto = NULL; // the class proto
char *name = NULL; // the name of the auxiliary data
char *installs_on = NULL; // a list of datatypes it installs onto
bitvector_t type = 0; // bitvector representation of we we install on
// try parsing the install
if(!PyArg_ParseTuple(args, "sOs", &name, &proto, &installs_on)) {
PyErr_Format(PyExc_TypeError,
"Installed auxiliaries require a name, a proto class, and "
"a comma-separated list of datatypes to install onto");
return NULL;
}
// parse the data types that this auxiliary data installs to
if(is_keyword(installs_on, "character", FALSE))
SET_BIT(type, AUXILIARY_TYPE_CHAR);
if(is_keyword(installs_on, "room", FALSE))
SET_BIT(type, AUXILIARY_TYPE_ROOM);
if(is_keyword(installs_on, "object", FALSE))
SET_BIT(type, AUXILIARY_TYPE_OBJ);
if(is_keyword(installs_on, "account", FALSE))
SET_BIT(type, AUXILIARY_TYPE_ACCOUNT);
// more types to come soon!!
//***********
// FINISH ME
//***********
// add proto to our table
Py_INCREF(proto);
hashPut(aux_table, name, proto);
AUXILIARY_FUNCS *funcs = newAuxiliaryFuncs(type,
newPyAuxiliaryData, deletePyAuxiliaryData,
pyAuxiliaryDataCopyTo, pyAuxiliaryDataCopy,
pyAuxiliaryDataStore, pyAuxiliaryDataRead);
auxiliaryFuncSetIsPy(funcs, TRUE);
auxiliariesInstall(name, funcs);
return Py_BuildValue("i", 1);
}
PyMethodDef pyauxiliary_module_methods[] = {
{ "install", PyAuxiliary_install, METH_VARARGS,
"installs new python auxiliary data into the mud. Auxiliary Data must "
"take the form of an uninstanced class that has a ClassXXX(set = None) "
"init function, a copy() function, a copyTo(to) function, and a store() "
"function" },
{NULL, NULL, 0, NULL} /* Sentinel */
};
//*****************************************************************************
// implementation of pyauxiliary.h
//*****************************************************************************
// initialize python auxiliary data for use
PyMODINIT_FUNC init_PyAuxiliary(void) {
aux_table = newHashtableSize(MIN_AUX_TABLE_SIZE);
Py_InitModule3("auxiliary", pyauxiliary_module_methods,
"The module for installing auxiliary data");
}
// returns TRUE if auxiliary data of the given name has been installed by python
bool pyAuxiliaryDataExists(const char *name) {
return hashIn(aux_table, name);
}