2 Python wrappers for TDB module
4 Copyright (C) Tim Potter, 2002-2003
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 NOTE: Since tdb is licenced under the GPL any program that uses these bindings
23 must be distributed under the GPL license terms since this is what
26 http://www.gnu.org/licenses/gpl-faq.html#IfInterpreterIsGPL
31 /* This symbol is used in both includes.h and Python.h which causes an
32 annoying compiler warning. */
42 PyObject *py_tdb_error;
44 /* tdb handle object */
51 PyTypeObject tdb_hnd_type;
53 PyObject *new_tdb_hnd_object(TDB_CONTEXT *tdb)
57 obj = PyObject_New(tdb_hnd_object, &tdb_hnd_type);
60 return (PyObject *)obj;
63 PyObject *py_tdb_close(PyObject *self, PyObject *args)
67 if (!PyArg_ParseTuple(args, "O!", &tdb_hnd_type, &obj))
70 if (tdb_close(obj->tdb) == -1) {
72 PyErr_SetString(py_tdb_error, strerror(errno));
82 PyObject *py_tdb_open(PyObject *self, PyObject *args, PyObject *kw)
84 static char *kwlist[] = { "name", "hash_size", "tdb_flags",
85 "open_flags", "mode", NULL };
87 int hash_size = 0, flags = TDB_DEFAULT, open_flags = -1, open_mode = 0600;
90 if (!PyArg_ParseTupleAndKeywords(
91 args, kw, "s|iiii", kwlist, &name, &hash_size, &flags,
92 &open_flags, &open_mode))
95 /* Default open_flags to read/write */
97 if (open_flags == -1) {
98 if (access(name, W_OK) == -1)
99 open_flags = O_RDONLY;
104 if (!(tdb = tdb_open(name, hash_size, flags, open_flags, open_mode))) {
105 PyErr_SetString(py_tdb_error, strerror(errno));
109 return new_tdb_hnd_object(tdb);
113 * Allow a tdb to act as a python mapping (dictionary)
116 static int tdb_traverse_count(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA value,
119 /* Do nothing - tdb_traverse will return the number of records
125 static int tdb_hnd_length(tdb_hnd_object *obj)
129 result = tdb_traverse(obj->tdb, tdb_traverse_count, NULL);
134 static PyObject *tdb_hnd_subscript(tdb_hnd_object *obj, PyObject *key)
139 if (!PyArg_Parse(key, "s#", &krec.dptr, &krec.dsize))
142 drec = tdb_fetch(obj->tdb, krec);
145 PyErr_SetString(PyExc_KeyError,
146 PyString_AsString(key));
150 result = PyString_FromStringAndSize(drec.dptr, drec.dsize);
156 static int tdb_ass_subscript(tdb_hnd_object *obj, PyObject *key, PyObject *value)
160 if (!PyArg_Parse(key, "s#", &krec.dptr, &krec.dsize)) {
161 PyErr_SetString(PyExc_TypeError,
162 "tdb mappings have string indices only");
168 py_tdb_error, "tdb object has been closed");
176 if (tdb_delete(obj->tdb, krec) == -1) {
177 PyErr_SetString(PyExc_KeyError,
178 PyString_AsString(value));
186 if (!PyArg_Parse(value, "s#", &drec.dptr, &drec.dsize)) {
187 PyErr_SetString(PyExc_TypeError,
188 "tdb mappings have string elements only");
194 if (tdb_store(obj->tdb, krec, drec, 0) < 0 ) {
196 PyErr_SetFromErrno(py_tdb_error);
200 (char *)tdb_errorstr(obj->tdb));
209 static PyMappingMethods tdb_mapping = {
210 (inquiry) tdb_hnd_length,
211 (binaryfunc) tdb_hnd_subscript,
212 (objobjargproc) tdb_ass_subscript
219 /* Return non-zero if a given key exists in the tdb */
221 PyObject *py_tdb_hnd_has_key(PyObject *self, PyObject *args)
223 tdb_hnd_object *obj = (tdb_hnd_object *)self;
226 if (!PyArg_ParseTuple(args, "s#", &key.dptr, &key.dsize))
231 py_tdb_error, "tdb object has been closed");
235 return PyInt_FromLong(tdb_exists(obj->tdb, key));
238 /* Return a list of keys in the tdb */
240 static int tdb_traverse_keys(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA value,
243 PyObject *key_list = (PyObject *)state;
245 PyList_Append(key_list,
246 PyString_FromStringAndSize(key.dptr, key.dsize));
251 PyObject *py_tdb_hnd_keys(PyObject *self, PyObject *args)
253 tdb_hnd_object *obj = (tdb_hnd_object *)self;
254 PyObject *key_list = PyList_New(0);
257 PyErr_SetString(py_tdb_error, "tdb object has been closed");
261 if (tdb_traverse(obj->tdb, tdb_traverse_keys, key_list) == -1) {
262 PyErr_SetString(py_tdb_error, "error traversing tdb");
270 PyObject *py_tdb_hnd_first_key(PyObject *self, PyObject *args)
272 tdb_hnd_object *obj = (tdb_hnd_object *)self;
276 PyErr_SetString(py_tdb_error, "tdb object has been closed");
280 key = tdb_firstkey(obj->tdb);
282 return Py_BuildValue("s#", key.dptr, key.dsize);
285 PyObject *py_tdb_hnd_next_key(PyObject *self, PyObject *py_oldkey)
287 tdb_hnd_object *obj = (tdb_hnd_object *)self;
288 TDB_DATA key, oldkey;
291 PyErr_SetString(py_tdb_error, "tdb object has been closed");
295 if (!PyArg_Parse(py_oldkey, "s#", &oldkey.dptr, &oldkey.dsize))
298 key = tdb_nextkey(obj->tdb, oldkey);
300 return Py_BuildValue("s#", key.dptr, key.dsize);
307 PyObject *py_tdb_hnd_lock_all(PyObject *self, PyObject *args)
309 tdb_hnd_object *obj = (tdb_hnd_object *)self;
313 PyErr_SetString(py_tdb_error, "tdb object has been closed");
317 result = tdb_lockall(obj->tdb);
319 return PyInt_FromLong(result != -1);
322 PyObject *py_tdb_hnd_unlock_all(PyObject *self, PyObject *args)
324 tdb_hnd_object *obj = (tdb_hnd_object *)self;
327 PyErr_SetString(py_tdb_error, "tdb object has been closed");
331 tdb_unlockall(obj->tdb);
337 /* Return an array of keys from a python object which must be a string or a
340 static BOOL make_lock_list(PyObject *py_keys, TDB_DATA **keys, int *num_keys)
342 /* Are we a list or a string? */
344 if (!PyList_Check(py_keys) && !PyString_Check(py_keys)) {
345 PyErr_SetString(PyExc_TypeError, "arg must be list of string");
349 if (PyList_Check(py_keys)) {
352 /* Turn python list into array of keys */
354 *num_keys = PyList_Size(py_keys);
355 *keys = (TDB_DATA *)malloc(sizeof(TDB_DATA) * (*num_keys));
357 for (i = 0; i < *num_keys; i++) {
358 PyObject *key = PyList_GetItem(py_keys, i);
360 if (!PyString_Check(key)) {
363 "list elements must be strings");
367 PyArg_Parse(key, "s#", &(*keys)[i].dptr,
373 /* Turn python string into a single key */
375 *keys = (TDB_DATA *)malloc(sizeof(TDB_DATA));
377 PyArg_Parse(py_keys, "s#", &(*keys)->dptr, &(*keys)->dsize);
383 PyObject *py_tdb_hnd_lock(PyObject *self, PyObject *args)
385 tdb_hnd_object *obj = (tdb_hnd_object *)self;
388 int num_keys, result;
391 PyErr_SetString(py_tdb_error, "tdb object has been closed");
395 if (!PyArg_ParseTuple(args, "O", &py_keys))
398 if (!make_lock_list(py_keys, &keys, &num_keys))
401 result = tdb_lockkeys(obj->tdb, num_keys, keys);
405 return PyInt_FromLong(result != -1);
408 PyObject *py_tdb_hnd_unlock(PyObject *self, PyObject *args)
410 tdb_hnd_object *obj = (tdb_hnd_object *)self;
413 PyErr_SetString(py_tdb_error, "tdb object has been closed");
417 if (!PyArg_ParseTuple(args, ""))
420 tdb_unlockkeys(obj->tdb);
430 struct traverse_info {
435 static int tdb_traverse_traverse(TDB_CONTEXT *tdb, TDB_DATA key, TDB_DATA value,
438 struct traverse_info *info = state;
439 PyObject *arglist, *py_result;
442 arglist = Py_BuildValue("(s#s#O)", key.dptr, key.dsize, value.dptr,
443 value.dsize, info->state);
445 py_result = PyEval_CallObject(info->callback, arglist);
449 if (!PyInt_Check(py_result)) {
450 result = 1; /* Hmm - non-integer object returned by callback */
454 result = PyInt_AsLong(py_result);
457 Py_DECREF(py_result);
461 PyObject *py_tdb_hnd_traverse(PyObject *self, PyObject *args, PyObject *kw)
463 tdb_hnd_object *obj = (tdb_hnd_object *)self;
464 static char *kwlist[] = { "traverse_fn", "state", NULL };
465 PyObject *state = Py_None, *callback;
466 struct traverse_info info;
469 if (!PyArg_ParseTupleAndKeywords(
470 args, kw, "O|O", kwlist, &callback, &state))
473 if (!PyCallable_Check(callback)) {
474 PyErr_SetString(PyExc_TypeError, "parameter must be callable");
481 info.callback = callback;
484 result = tdb_traverse(obj->tdb, tdb_traverse_traverse, &info);
489 return PyInt_FromLong(result);
492 PyObject *py_tdb_hnd_chainlock(PyObject *self, PyObject *args)
494 tdb_hnd_object *obj = (tdb_hnd_object *)self;
499 PyErr_SetString(py_tdb_error, "tdb object has been closed");
503 if (!PyArg_ParseTuple(args, "s#", &key.dptr, &key.dsize))
506 result = tdb_chainlock(obj->tdb, key);
508 return PyInt_FromLong(result != -1);
511 PyObject *py_tdb_hnd_chainunlock(PyObject *self, PyObject *args)
513 tdb_hnd_object *obj = (tdb_hnd_object *)self;
518 PyErr_SetString(py_tdb_error, "tdb object has been closed");
522 if (!PyArg_ParseTuple(args, "s#", &key.dptr, &key.dsize))
525 result = tdb_chainunlock(obj->tdb, key);
527 return PyInt_FromLong(result != -1);
530 PyObject *py_tdb_hnd_lock_bystring(PyObject *self, PyObject *args)
532 tdb_hnd_object *obj = (tdb_hnd_object *)self;
533 int result, timeout = 30;
537 PyErr_SetString(py_tdb_error, "tdb object has been closed");
541 if (!PyArg_ParseTuple(args, "s|i", &s, &timeout))
544 result = tdb_lock_bystring(obj->tdb, s, timeout);
546 return PyInt_FromLong(result != -1);
549 PyObject *py_tdb_hnd_unlock_bystring(PyObject *self, PyObject *args)
551 tdb_hnd_object *obj = (tdb_hnd_object *)self;
555 PyErr_SetString(py_tdb_error, "tdb object has been closed");
559 if (!PyArg_ParseTuple(args, "s", &s))
562 tdb_unlock_bystring(obj->tdb, s);
569 * Method dispatch table for this module
572 static PyMethodDef tdb_methods[] = {
573 { "open", (PyCFunction)py_tdb_open, METH_VARARGS | METH_KEYWORDS },
574 { "close", (PyCFunction)py_tdb_close, METH_VARARGS },
579 * Methods on a tdb object
582 static PyMethodDef tdb_hnd_methods[] = {
583 { "keys", (PyCFunction)py_tdb_hnd_keys, METH_VARARGS },
584 { "has_key", (PyCFunction)py_tdb_hnd_has_key, METH_VARARGS },
585 { "first_key", (PyCFunction)py_tdb_hnd_first_key, METH_VARARGS },
586 { "next_key", (PyCFunction)py_tdb_hnd_next_key, METH_VARARGS },
587 { "lock_all", (PyCFunction)py_tdb_hnd_lock_all, METH_VARARGS },
588 { "unlock_all", (PyCFunction)py_tdb_hnd_unlock_all, METH_VARARGS },
589 { "lock", (PyCFunction)py_tdb_hnd_lock, METH_VARARGS },
590 { "unlock", (PyCFunction)py_tdb_hnd_unlock, METH_VARARGS },
591 { "traverse", (PyCFunction)py_tdb_hnd_traverse, METH_VARARGS | METH_KEYWORDS },
592 { "chainlock", (PyCFunction)py_tdb_hnd_chainlock, METH_VARARGS | METH_KEYWORDS },
593 { "chainunlock", (PyCFunction)py_tdb_hnd_chainunlock, METH_VARARGS | METH_KEYWORDS },
594 { "lock_bystring", (PyCFunction)py_tdb_hnd_lock_bystring, METH_VARARGS | METH_KEYWORDS },
595 { "unlock_bystring", (PyCFunction)py_tdb_hnd_unlock_bystring, METH_VARARGS | METH_KEYWORDS },
599 /* Deallocate a tdb handle object */
601 static void tdb_hnd_dealloc(PyObject* self)
603 tdb_hnd_object *hnd = (tdb_hnd_object *)self;
611 /* Return tdb handle attributes */
613 static PyObject *tdb_hnd_getattr(PyObject *self, char *attrname)
615 return Py_FindMethod(tdb_hnd_methods, self, attrname);
618 static char tdb_hnd_type_doc[] =
619 "Python wrapper for tdb.";
621 PyTypeObject tdb_hnd_type = {
622 PyObject_HEAD_INIT(NULL)
625 sizeof(tdb_hnd_object),
627 tdb_hnd_dealloc, /* tp_dealloc*/
629 tdb_hnd_getattr, /* tp_getattr*/
634 0, /* tp_as_sequence*/
635 &tdb_mapping, /* tp_as_mapping*/
642 Py_TPFLAGS_DEFAULT, /* tp_flags */
643 tdb_hnd_type_doc, /* tp_doc */
648 static struct const_vals {
651 } module_const_vals[] = {
653 /* Flags for tdb_open() */
655 { "TDB_DEFAULT", TDB_DEFAULT },
656 { "TDB_CLEAR_IF_FIRST", TDB_CLEAR_IF_FIRST },
657 { "TDB_INTERNAL", TDB_INTERNAL },
658 { "TDB_NOLOCK", TDB_NOLOCK },
659 { "TDB_NOMMAP", TDB_NOMMAP },
660 { "TDB_CONVERT", TDB_CONVERT },
661 { "TDB_BIGENDIAN", TDB_BIGENDIAN },
666 static void const_init(PyObject *dict)
668 struct const_vals *tmp;
671 for (tmp = module_const_vals; tmp->name; tmp++) {
672 obj = PyInt_FromLong(tmp->value);
673 PyDict_SetItemString(dict, tmp->name, obj);
678 /* Module initialisation */
682 PyObject *module, *dict;
684 /* Initialise module */
686 module = Py_InitModule("tdb", tdb_methods);
687 dict = PyModule_GetDict(module);
689 py_tdb_error = PyErr_NewException("tdb.error", NULL, NULL);
690 PyDict_SetItemString(dict, "error", py_tdb_error);
692 /* Initialise policy handle object */
694 tdb_hnd_type.ob_type = &PyType_Type;
696 PyDict_SetItemString(dict, "tdb.hnd",
697 (PyObject *)&tdb_hnd_type);
699 /* Initialise constants */