//*****************************************************************************
//
// pystorage.c
//
// Provides a wrapper around NakedMud's storage structure for use by scripts
// and python modules.
//
//*****************************************************************************
#include <Python.h>
#include <structmember.h>
#include "../mud.h"
#include "../storage.h"
#include "pystorage.h"
//*****************************************************************************
// local data structures
//*****************************************************************************
typedef struct {
PyObject_HEAD
STORAGE_SET *set;
} PyStorageSet;
typedef struct {
PyObject_HEAD
STORAGE_SET_LIST *list;
} PyStorageList;
//*****************************************************************************
// local function prototypes
//*****************************************************************************
PyObject *newPyStorageList(STORAGE_SET_LIST *list);
int PyStorageSet_Check(PyObject *value);
int PyStorageList_Check(PyObject *value);
//*****************************************************************************
// py storage lists
//*****************************************************************************
//
// deallocate the storage list
void PyStorageList_dealloc(PyStorageList *self) {
// do NOT free this!! People will need to close the encapsulating set
// if(self->list) storage_list_delete(self->list);
self->ob_type->tp_free((PyObject*)self);
}
//
// create a new python storage list
PyObject *PyStorageList_new(PyTypeObject *type, PyObject *args, PyObject *kwds){
PyStorageList *self = (PyStorageList *)type->tp_alloc(type, 0);
self->list = NULL;
return (PyObject *)self;
}
//
// initialize a new storage list
int PyStorageList_init(PyStorageList *self, PyObject *args, PyObject *kwds) {
self->list = new_storage_list();
return 0;
}
//
// return a python list of the sets in our storage list
PyObject *PyStorageList_sets(PyObject *self, PyObject *args) {
STORAGE_SET_LIST *set_list = ((PyStorageList *)self)->list;
STORAGE_SET *set = NULL;
PyObject *list = PyList_New(0);
// add in all of the elements
while( (set = storage_list_next(set_list)) != NULL) {
PyObject *pyset = newPyStorageSet(set);
PyList_Append(list, pyset);
Py_DECREF(pyset);
}
// return the new list
PyObject *retval = Py_BuildValue("O", list);
Py_DECREF(list);
return retval;
}
//
// add a new set to the storage list
PyObject *PyStorageList_add(PyObject *self, PyObject *args) {
PyStorageSet *set = NULL;
if(!PyArg_ParseTuple(args, "O", &set)) {
PyErr_Format(PyExc_TypeError,
"Only storage sets can be added to storage lists");
return NULL;
}
// make sure it is indeed a storage set
if(!PyStorageSet_Check((PyObject *)set)) {
PyErr_Format(PyExc_TypeError,
"Only storage sets can be added to storage lists");
return NULL;
}
// add it to the list and return
storage_list_put(((PyStorageList *)self)->list, set->set);
return Py_BuildValue("i", 1);
}
//*****************************************************************************
// The type object for PyStorageLists and method list
//*****************************************************************************
PyMethodDef PyStorageList_class_methods[] = {
{"sets", PyStorageList_sets, METH_VARARGS,
"Returns a python list of all the sets in the storage list" },
{"add", PyStorageList_add, METH_VARARGS,
"Adds a new storage set to the list" },
{NULL, NULL, 0, NULL} /* Sentinel */
};
PyTypeObject PyStorageList_Type = {
PyObject_HEAD_INIT(NULL)
0, /*ob_size*/
"storage.StorageList", /*tp_name*/
sizeof(PyStorageList), /*tp_basicsize*/
0, /*tp_itemsize*/
(destructor)PyStorageList_dealloc,/*tp_dealloc*/
0, /*tp_print*/
0, /*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 */
0, /*tp_call*/
0, /*tp_str*/
0, /*tp_getattro*/
0, /*tp_setattro*/
0, /*tp_as_buffer*/
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
"storage lists", /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
PyStorageList_class_methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
(initproc)PyStorageList_init, /* tp_init */
0, /* tp_alloc */
PyStorageList_new, /* tp_new */
};
//*****************************************************************************
// py storage sets
//*****************************************************************************
//
// deallocate the storage set
void PyStorageSet_dealloc(PyStorageSet *self) {
// do NOT close or free this!! People will need to use the close() function
// if(self->set) storage_close(self->set);
self->ob_type->tp_free((PyObject*)self);
}
//
// create a new python storage set
PyObject *PyStorageSet_new(PyTypeObject *type, PyObject *args, PyObject *kwds) {
PyStorageSet *self = (PyStorageSet *)type->tp_alloc(type, 0);
self->set = NULL;
return (PyObject *)self;
}
//
// initialize a new storage set
int PyStorageSet_init(PyStorageSet *self, PyObject *args, PyObject *kwds) {
static char *kwlist[] = {"file", NULL};
char *file = NULL;
// get the universal id
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|s", kwlist, &file)) {
PyErr_Format(PyExc_TypeError,
"Storage Set initializers may only take filename args.");
return -1;
}
// if we have a filename, load up the storage set there
if(file != NULL) {
self->set = storage_read(file);
// the file doesn't exist... just make a blank storage set
if(self->set == NULL)
self->set = new_storage_set();
}
// no argument... make a new storage set
else
self->set = new_storage_set();
// no errors
return 0;
}
//
// parses out the key of some argument list provided to a read function
char *PyStorageSet_readParseKey(PyObject *args) {
char *key = NULL;
if(!PyArg_ParseTuple(args, "s", &key)) {
PyErr_Format(PyExc_TypeError,
"String keys must be provided for storage read methods");
return NULL;
}
return key;
}
//
// read a string from the storage set
PyObject *PyStorageSet_readString(PyObject *self, PyObject *args) {
char *key = PyStorageSet_readParseKey(args);
if(key != NULL)
return Py_BuildValue("s", read_string(((PyStorageSet *)self)->set, key));
else
return NULL;
}
//
// read an integer value from the storage set
PyObject *PyStorageSet_readInt (PyObject *self, PyObject *args) {
char *key = PyStorageSet_readParseKey(args);
if(key != NULL)
return Py_BuildValue("i", read_int(((PyStorageSet *)self)->set, key));
else
return NULL;
}
//
// read a double value from the storage set
PyObject *PyStorageSet_readDouble(PyObject *self, PyObject *args) {
char *key = PyStorageSet_readParseKey(args);
if(key != NULL)
return Py_BuildValue("d", read_double(((PyStorageSet *)self)->set, key));
else
return NULL;
}
//
// read a boolean value from the storage set
PyObject *PyStorageSet_readBool (PyObject *self, PyObject *args) {
char *key = PyStorageSet_readParseKey(args);
if(key != NULL)
return Py_BuildValue("i", read_bool(((PyStorageSet *)self)->set, key));
else
return NULL;
}
//
// read a storage list from the storage set
PyObject *PyStorageSet_readList (PyObject *self, PyObject *args) {
char *key = PyStorageSet_readParseKey(args);
if(key == NULL)
return NULL;
else {
PyObject *pylist =
newPyStorageList(read_list(((PyStorageSet*)self)->set, key));
PyObject *retval = Py_BuildValue("O", pylist);
Py_DECREF(pylist);
return retval;
}
}
//
// read a storage set from within the set
PyObject *PyStorageSet_readSet (PyObject *self, PyObject *args) {
char *key = PyStorageSet_readParseKey(args);
if(key == NULL)
return NULL;
else {
PyObject *pyset =
newPyStorageSet(read_set(((PyStorageSet *)self)->set, key));
PyObject *retval = Py_BuildValue("O", pyset);
Py_DECREF(pyset);
return retval;
}
}
//
// here's a yucky macro for handling to store end of thigns
#define PYSTORE_PARSE(args, key, val, fmt) \
if(!PyArg_ParseTuple(args, fmt, &key, &val)) { \
PyErr_Format(PyExc_TypeError, \
"Invalid types supplied to storage method"); \
return NULL; \
}
//
// store a string in the set
PyObject *PyStorageSet_storeString(PyObject *self, PyObject *args) {
char *key = NULL;
char *val = NULL;
PYSTORE_PARSE(args, key, val, "ss");
store_string(((PyStorageSet *)self)->set, key, val);
return Py_BuildValue("i", 1);
}
//
// store an integer in the set
PyObject *PyStorageSet_storeInt (PyObject *self, PyObject *args) {
char *key = NULL;
int val = 0;
PYSTORE_PARSE(args, key, val, "si");
store_int(((PyStorageSet *)self)->set, key, val);
return Py_BuildValue("i", 1);
}
//
// store a double in the set
PyObject *PyStorageSet_storeDouble(PyObject *self, PyObject *args) {
char *key = NULL;
double val = 0;
PYSTORE_PARSE(args, key, val, "sd");
store_double(((PyStorageSet *)self)->set, key, val);
return Py_BuildValue("i", 1);
}
//
// store a boolean in the set
PyObject *PyStorageSet_storeBool (PyObject *self, PyObject *args) {
return PyStorageSet_storeInt(self, args);
}
//
// store a list in the set
PyObject *PyStorageSet_storeList (PyObject *self, PyObject *args) {
PyStorageList *val = NULL;
char *key = NULL;
PYSTORE_PARSE(args, key, val, "sO");
store_list(((PyStorageSet *)self)->set, key, val->list);
return Py_BuildValue("i", 1);
}
//
// store a set in the set
PyObject *PyStorageSet_storeSet (PyObject *self, PyObject *args) {
PyStorageSet *val = NULL;
char *key = NULL;
PYSTORE_PARSE(args, key, val, "sO");
store_set(((PyStorageSet *)self)->set, key, val->set);
return Py_BuildValue("i", 1);
}
//
// write the set to file
PyObject *PyStorageSet_write (PyObject *self, PyObject *args) {
char *fname = NULL;
if(!PyArg_ParseTuple(args, "s", &fname)) {
PyErr_Format(PyExc_TypeError,
"Filenames must be in string form");
return NULL;
}
storage_write(((PyStorageSet *)self)->set, fname);
return Py_BuildValue("i", 1);
}
//
// close a storage set, and clean up its memory
PyObject *PyStorageSet_close (PyObject *self, PyObject *args) {
storage_close(((PyStorageSet *)self)->set);
((PyStorageSet *)self)->set = NULL;
return Py_BuildValue("i", 1);
}
//
// return whether or not the set contains a given key
PyObject *PyStorageSet_contains (PyObject *self, PyObject *args) {
char *key = NULL;
if(!PyArg_ParseTuple(args, "s", &key)) {
PyErr_Format(PyExc_TypeError,
"You can only check if storage sets contain string key values");
return NULL;
}
return Py_BuildValue("i", storage_contains(((PyStorageSet *)self)->set, key));
}
//*****************************************************************************
// The type object for PyStorageSets and method list
//*****************************************************************************
PyMethodDef PyStorageSet_class_methods[] = {
// read functions
{ "readString", PyStorageSet_readString, METH_VARARGS,
"Read in the string value of a storage set entry, by key." },
{ "readInt", PyStorageSet_readInt, METH_VARARGS,
"Read in the integer value of a storage set entry, by key." },
{ "readDouble", PyStorageSet_readDouble, METH_VARARGS,
"Read in the double value of a storage set entry, by key." },
{ "readBool", PyStorageSet_readBool, METH_VARARGS,
"Read in the boolean value of a storage set entry, by key." },
{ "readList", PyStorageSet_readList, METH_VARARGS,
"Read in the list value of a storage set entry, by key." },
{ "readSet", PyStorageSet_readSet, METH_VARARGS,
"Read in the set value of a storage set entry, by key." },
// write store functions
{ "storeString", PyStorageSet_storeString, METH_VARARGS,
"Store the string value of a storage set entry, by key." },
{ "storeInt", PyStorageSet_storeInt, METH_VARARGS,
"Store the integer value of a storage set entry, by key." },
{ "storeDouble", PyStorageSet_storeDouble, METH_VARARGS,
"Store the double value of a storage set entry, by key." },
{ "storeBool", PyStorageSet_storeBool, METH_VARARGS,
"Store the boolean value of a storage set entry, by key." },
{ "storeList", PyStorageSet_storeList, METH_VARARGS,
"Store the list value of a storage set entry, by key." },
{ "storeSet", PyStorageSet_storeSet, METH_VARARGS,
"Store the set value of a storage set entry, by key." },
// other functions
{ "write", PyStorageSet_write, METH_VARARGS,
"Store the contents of the storage set to the specified filename" },
{ "close", PyStorageSet_close, METH_VARARGS,
"Close a storage set. MUST be called when the storage set is done "
"being used. Garbage collection will not delete the set." },
{ "contains", PyStorageSet_contains, METH_VARARGS,
"Returns True if the set contains the given key, and false otherwise." },
{NULL, NULL, 0, NULL} /* Sentinel */
};
PyTypeObject PyStorageSet_Type = {
PyObject_HEAD_INIT(NULL)
0, /*ob_size*/
"storage.StorageSet", /*tp_name*/
sizeof(PyStorageSet), /*tp_basicsize*/
0, /*tp_itemsize*/
(destructor)PyStorageSet_dealloc, /*tp_dealloc*/
0, /*tp_print*/
0, /*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 */
0, /*tp_call*/
0, /*tp_str*/
0, /*tp_getattro*/
0, /*tp_setattro*/
0, /*tp_as_buffer*/
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
"storage sets", /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
PyStorageSet_class_methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
(initproc)PyStorageSet_init, /* tp_init */
0, /* tp_alloc */
PyStorageSet_new, /* tp_new */
};
//
// all of the methods assocciated with the storage module
PyMethodDef PyStorage_module_methods[] = {
{NULL, NULL, 0, NULL} /* Sentinel */
};
//*****************************************************************************
// implementation of pystorage.h
//*****************************************************************************
PyMODINIT_FUNC init_PyStorage(void) {
PyObject *module = Py_InitModule3("storage", PyStorage_module_methods,
"Python wrapper for storage sets.");
// something went wrong... abort!
if(module == NULL)
return;
// make sure the storage class is ready to be made
if (!(PyType_Ready(&PyStorageSet_Type) < 0)) {
// add our two classes
PyTypeObject *type = &PyStorageSet_Type;
Py_INCREF(&PyStorageSet_Type);
PyModule_AddObject(module, "StorageSet", (PyObject *)type);
}
// make sure the list calss is ready to be made
if(!(PyType_Ready(&PyStorageList_Type) < 0)) {
PyTypeObject *type = &PyStorageList_Type;
Py_INCREF(&PyStorageList_Type);
PyModule_AddObject(module, "StorageList", (PyObject *)type);
}
}
//
// create a new python representation of a storage set
PyObject *newPyStorageSet(STORAGE_SET *set) {
PyStorageSet *pyset =
(PyStorageSet *)PyStorageSet_new(&PyStorageSet_Type, NULL, NULL);
pyset->set = set;
return (PyObject *)pyset;
}
//
// create a new list representation of a storage set
PyObject *newPyStorageList(STORAGE_SET_LIST *list) {
PyStorageList *pylist =
(PyStorageList *)PyStorageList_new(&PyStorageList_Type, NULL, NULL);
pylist->list = list;
return (PyObject *)pylist;
}
//
// checks to see if the python object is a storage set
int PyStorageSet_Check(PyObject *value) {
return PyObject_TypeCheck(value, &PyStorageSet_Type);
}
//
// checks to see if the python object is a storage list
int PyStorageList_Check(PyObject *value) {
return PyObject_TypeCheck(value, &PyStorageList_Type);
}
//
// return the storage set that is contained within it.
STORAGE_SET *PyStorageSet_AsSet(PyObject *set) {
return ((PyStorageSet *)set)->set;
}