//***************************************************************************** // // 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) { // are we building this from a Python list? PyObject *pylist = NULL; if(!PyArg_ParseTuple(args, "|O", &pylist)) { PyErr_Format(PyExc_TypeError, "unexpected arguments passed to StorageList."); return -1; } // if we received something, make sure it's a list if(pylist != NULL && !PyList_Check(pylist)) { PyErr_Format(PyExc_TypeError, "StorageList expected a list argument."); return -1; } // create the storage list self->list = new_storage_list(); // try adding contents to the storage list if(pylist != NULL) { int i; // first, make sure they're all storage sets for(i = 0; i < PyList_Size(pylist); i++) { PyObject *set = PyList_GetItem(pylist, i); if(!PyStorageSet_Check(set)) { PyErr_Format(PyExc_TypeError, "StorageList list content to be a StorageSet."); return -1; } } // all good, append them for(i = 0; i < PyList_Size(pylist); i++) { PyObject *set = PyList_GetItem(pylist, i); storage_list_put(self->list, PyStorageSet_AsSet(set)); } } 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; PyObject *list = PyList_New(0); STORAGE_SET *set = NULL; // 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 return list; } // // 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, "sets()\n\n" "Returns a python list of all the sets in the storage list." }, {"add", PyStorageList_add, METH_VARARGS, "add(storage_set)\n\n" "Append a new storage set to the storage 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*/ "__init__(self, list=None)\n\n" "Create a new storage list. A Python list of storage sets may be\n" "supplied, from which to build the storage list.", 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) { bool val = read_bool(((PyStorageSet *)self)->set, key); return Py_BuildValue("O", (val ? Py_True : Py_False)); } 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 return newPyStorageList(read_list(((PyStorageSet*)self)->set, key)); } // // 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 return newPyStorageSet(read_set(((PyStorageSet *)self)->set, key)); } // // 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, "readString(name)\n\n" "Read a string value from the storage set. Return empty string if the\n" "storage set does not contain an entry by the given name." }, { "readInt", PyStorageSet_readInt, METH_VARARGS, "Same as readString, for integers. Returns 0 if entry does not exist." }, { "readDouble", PyStorageSet_readDouble, METH_VARARGS, "Same as readString, for floating points. Returns 0 if entry does not exist.." }, { "readBool", PyStorageSet_readBool, METH_VARARGS, "Same as readString, for booleans. Returns False if entry does not exist."}, { "readList", PyStorageSet_readList, METH_VARARGS, "Same as readString, for storage lists. Returns an empty storage list\n" "if entry does not exist." }, { "readSet", PyStorageSet_readSet, METH_VARARGS, "Same as readString, for storage sets. Returns an empty set if entry\n" "does not exist." }, // write store functions { "storeString", PyStorageSet_storeString, METH_VARARGS, "storeString(name, val)\n\n" "Store a string value in the storage set." }, { "storeInt", PyStorageSet_storeInt, METH_VARARGS, "Same as storeString, for integers." }, { "storeDouble", PyStorageSet_storeDouble, METH_VARARGS, "Same as storeString, for floating point values." }, { "storeBool", PyStorageSet_storeBool, METH_VARARGS, "Same as storeString, for boolean values." }, { "storeList", PyStorageSet_storeList, METH_VARARGS, "Same as storeString, for storage lists." }, { "storeSet", PyStorageSet_storeSet, METH_VARARGS, "Same as storeString, for storage sets." }, // other functions { "write", PyStorageSet_write, METH_VARARGS, "write(filename)\n\n" "Write the contents of a storage set to the specified file name." }, { "close", PyStorageSet_close, METH_NOARGS, "close()\n\n" "Recursively close a storage set and all of its children sets and lists.\n" "MUST be called when the storage set has finished being used. Garbage\n" "collection will not delete the set." }, { "contains", PyStorageSet_contains, METH_VARARGS, "contains(name)\n\n" "Returns True or False if the set contains an entry by the given name." }, { "__contains__", PyStorageSet_contains, METH_VARARGS, "__contains__(name) <==> name in self" }, {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*/ "__init__(self, filename=None)\n\n" "Create a new storage set. If a file name is supplied, read a storage set\n" "in from the specified file.", 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, "The storage module allows users to save information to disk as key:value\n" "pairs without having to interact with files directly. This module gives\n" "users access to two classes: StorageSets and StorageLists. Sets match\n" "keys to values. Lists hold multiple 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; }