Documentation clarified to mention optional parameters.
[python.git] / Modules / bsddbmodule.c
blob61c656437e3b8e2a50b185dcbfc4b452a1301f04
1 /* Berkeley DB interface.
2 Author: Michael McLay
3 Hacked: Guido van Rossum
4 Btree and Recno additions plus sequence methods: David Ely
5 Hacked by Gustavo Niemeyer <niemeyer@conectiva.com> fixing recno
6 support.
8 XXX To do:
9 - provide a way to access the various hash functions
10 - support more open flags
12 The windows port of the Berkeley DB code is hard to find on the web:
13 www.nightmare.com/software.html
16 #include "Python.h"
17 #ifdef WITH_THREAD
18 #include "pythread.h"
19 #endif
21 #include <sys/types.h>
22 #include <sys/stat.h>
23 #include <fcntl.h>
24 #ifdef HAVE_DB_185_H
25 #include <db_185.h>
26 #else
27 #include <db.h>
28 #endif
29 /* Please don't include internal header files of the Berkeley db package
30 (it messes up the info required in the Setup file) */
32 typedef struct {
33 PyObject_HEAD
34 DB *di_bsddb;
35 int di_size; /* -1 means recompute */
36 int di_type;
37 #ifdef WITH_THREAD
38 PyThread_type_lock di_lock;
39 #endif
40 } bsddbobject;
42 static PyTypeObject Bsddbtype;
44 #define is_bsddbobject(v) ((v)->ob_type == &Bsddbtype)
45 #define check_bsddbobject_open(v, r) if ((v)->di_bsddb == NULL) \
46 { PyErr_SetString(BsddbError, \
47 "BSDDB object has already been closed"); \
48 return r; }
50 static PyObject *BsddbError;
52 static PyObject *
53 newdbhashobject(char *file, int flags, int mode,
54 int bsize, int ffactor, int nelem, int cachesize,
55 int hash, int lorder)
57 bsddbobject *dp;
58 HASHINFO info;
60 if ((dp = PyObject_New(bsddbobject, &Bsddbtype)) == NULL)
61 return NULL;
63 info.bsize = bsize;
64 info.ffactor = ffactor;
65 info.nelem = nelem;
66 info.cachesize = cachesize;
67 info.hash = NULL; /* XXX should derive from hash argument */
68 info.lorder = lorder;
70 #ifdef O_BINARY
71 flags |= O_BINARY;
72 #endif
73 Py_BEGIN_ALLOW_THREADS
74 dp->di_bsddb = dbopen(file, flags, mode, DB_HASH, &info);
75 Py_END_ALLOW_THREADS
76 if (dp->di_bsddb == NULL) {
77 PyErr_SetFromErrno(BsddbError);
78 #ifdef WITH_THREAD
79 dp->di_lock = NULL;
80 #endif
81 Py_DECREF(dp);
82 return NULL;
85 dp->di_size = -1;
86 dp->di_type = DB_HASH;
88 #ifdef WITH_THREAD
89 dp->di_lock = PyThread_allocate_lock();
90 if (dp->di_lock == NULL) {
91 PyErr_SetString(BsddbError, "can't allocate lock");
92 Py_DECREF(dp);
93 return NULL;
95 #endif
97 return (PyObject *)dp;
100 static PyObject *
101 newdbbtobject(char *file, int flags, int mode,
102 int btflags, int cachesize, int maxkeypage,
103 int minkeypage, int psize, int lorder)
105 bsddbobject *dp;
106 BTREEINFO info;
108 if ((dp = PyObject_New(bsddbobject, &Bsddbtype)) == NULL)
109 return NULL;
111 info.flags = btflags;
112 info.cachesize = cachesize;
113 info.maxkeypage = maxkeypage;
114 info.minkeypage = minkeypage;
115 info.psize = psize;
116 info.lorder = lorder;
117 info.compare = 0; /* Use default comparison functions, for now..*/
118 info.prefix = 0;
120 #ifdef O_BINARY
121 flags |= O_BINARY;
122 #endif
123 Py_BEGIN_ALLOW_THREADS
124 dp->di_bsddb = dbopen(file, flags, mode, DB_BTREE, &info);
125 Py_END_ALLOW_THREADS
126 if (dp->di_bsddb == NULL) {
127 PyErr_SetFromErrno(BsddbError);
128 #ifdef WITH_THREAD
129 dp->di_lock = NULL;
130 #endif
131 Py_DECREF(dp);
132 return NULL;
135 dp->di_size = -1;
136 dp->di_type = DB_BTREE;
138 #ifdef WITH_THREAD
139 dp->di_lock = PyThread_allocate_lock();
140 if (dp->di_lock == NULL) {
141 PyErr_SetString(BsddbError, "can't allocate lock");
142 Py_DECREF(dp);
143 return NULL;
145 #endif
147 return (PyObject *)dp;
150 static PyObject *
151 newdbrnobject(char *file, int flags, int mode,
152 int rnflags, int cachesize, int psize, int lorder,
153 size_t reclen, u_char bval, char *bfname)
155 bsddbobject *dp;
156 RECNOINFO info;
157 int fd;
159 if ((dp = PyObject_New(bsddbobject, &Bsddbtype)) == NULL)
160 return NULL;
162 info.flags = rnflags;
163 info.cachesize = cachesize;
164 info.psize = psize;
165 info.lorder = lorder;
166 info.reclen = reclen;
167 info.bval = bval;
168 info.bfname = bfname;
170 #ifdef O_BINARY
171 flags |= O_BINARY;
172 #endif
173 /* This is a hack to avoid a dbopen() bug that happens when
174 * it fails. */
175 fd = open(file, flags);
176 if (fd == -1) {
177 dp->di_bsddb = NULL;
179 else {
180 close(fd);
181 Py_BEGIN_ALLOW_THREADS
182 dp->di_bsddb = dbopen(file, flags, mode, DB_RECNO, &info);
183 Py_END_ALLOW_THREADS
185 if (dp->di_bsddb == NULL) {
186 PyErr_SetFromErrno(BsddbError);
187 #ifdef WITH_THREAD
188 dp->di_lock = NULL;
189 #endif
190 Py_DECREF(dp);
191 return NULL;
194 dp->di_size = -1;
195 dp->di_type = DB_RECNO;
197 #ifdef WITH_THREAD
198 dp->di_lock = PyThread_allocate_lock();
199 if (dp->di_lock == NULL) {
200 PyErr_SetString(BsddbError, "can't allocate lock");
201 Py_DECREF(dp);
202 return NULL;
204 #endif
206 return (PyObject *)dp;
209 static void
210 bsddb_dealloc(bsddbobject *dp)
212 #ifdef WITH_THREAD
213 if (dp->di_lock) {
214 PyThread_acquire_lock(dp->di_lock, 0);
215 PyThread_release_lock(dp->di_lock);
216 PyThread_free_lock(dp->di_lock);
217 dp->di_lock = NULL;
219 #endif
220 if (dp->di_bsddb != NULL) {
221 int status;
222 Py_BEGIN_ALLOW_THREADS
223 status = (dp->di_bsddb->close)(dp->di_bsddb);
224 Py_END_ALLOW_THREADS
225 if (status != 0)
226 fprintf(stderr,
227 "Python bsddb: close errno %d in dealloc\n",
228 errno);
230 PyObject_Del(dp);
233 #ifdef WITH_THREAD
234 #define BSDDB_BGN_SAVE(_dp) \
235 Py_BEGIN_ALLOW_THREADS PyThread_acquire_lock(_dp->di_lock,1);
236 #define BSDDB_END_SAVE(_dp) \
237 PyThread_release_lock(_dp->di_lock); Py_END_ALLOW_THREADS
238 #else
239 #define BSDDB_BGN_SAVE(_dp) Py_BEGIN_ALLOW_THREADS
240 #define BSDDB_END_SAVE(_dp) Py_END_ALLOW_THREADS
241 #endif
243 static Py_ssize_t
244 bsddb_length(bsddbobject *dp)
246 check_bsddbobject_open(dp, -1);
247 if (dp->di_size < 0) {
248 DBT krec, drec;
249 int status;
250 int size = 0;
251 BSDDB_BGN_SAVE(dp)
252 for (status = (dp->di_bsddb->seq)(dp->di_bsddb,
253 &krec, &drec,R_FIRST);
254 status == 0;
255 status = (dp->di_bsddb->seq)(dp->di_bsddb,
256 &krec, &drec, R_NEXT))
257 size++;
258 BSDDB_END_SAVE(dp)
259 if (status < 0) {
260 PyErr_SetFromErrno(BsddbError);
261 return -1;
263 dp->di_size = size;
265 return dp->di_size;
268 static PyObject *
269 bsddb_subscript(bsddbobject *dp, PyObject *key)
271 int status;
272 DBT krec, drec;
273 char *data,buf[4096];
274 int size;
275 PyObject *result;
276 recno_t recno;
278 if (dp->di_type == DB_RECNO) {
279 if (!PyArg_Parse(key, "i", &recno)) {
280 PyErr_SetString(PyExc_TypeError,
281 "key type must be integer");
282 return NULL;
284 krec.data = &recno;
285 krec.size = sizeof(recno);
287 else {
288 if (!PyArg_Parse(key, "s#", &data, &size)) {
289 PyErr_SetString(PyExc_TypeError,
290 "key type must be string");
291 return NULL;
293 krec.data = data;
294 krec.size = size;
296 check_bsddbobject_open(dp, NULL);
298 BSDDB_BGN_SAVE(dp)
299 status = (dp->di_bsddb->get)(dp->di_bsddb, &krec, &drec, 0);
300 if (status == 0) {
301 if (drec.size > sizeof(buf)) data = malloc(drec.size);
302 else data = buf;
303 if (data!=NULL) memcpy(data,drec.data,drec.size);
305 BSDDB_END_SAVE(dp)
306 if (data==NULL) return PyErr_NoMemory();
307 if (status != 0) {
308 if (status < 0)
309 PyErr_SetFromErrno(BsddbError);
310 else
311 PyErr_SetObject(PyExc_KeyError, key);
312 return NULL;
315 result = PyString_FromStringAndSize(data, (int)drec.size);
316 if (data != buf) free(data);
317 return result;
320 static int
321 bsddb_ass_sub(bsddbobject *dp, PyObject *key, PyObject *value)
323 int status;
324 DBT krec, drec;
325 char *data;
326 int size;
327 recno_t recno;
329 if (dp->di_type == DB_RECNO) {
330 if (!PyArg_Parse(key, "i", &recno)) {
331 PyErr_SetString(PyExc_TypeError,
332 "bsddb key type must be integer");
333 return -1;
335 krec.data = &recno;
336 krec.size = sizeof(recno);
338 else {
339 if (!PyArg_Parse(key, "s#", &data, &size)) {
340 PyErr_SetString(PyExc_TypeError,
341 "bsddb key type must be string");
342 return -1;
344 krec.data = data;
345 krec.size = size;
347 check_bsddbobject_open(dp, -1);
348 dp->di_size = -1;
349 if (value == NULL) {
350 BSDDB_BGN_SAVE(dp)
351 status = (dp->di_bsddb->del)(dp->di_bsddb, &krec, 0);
352 BSDDB_END_SAVE(dp)
354 else {
355 if (!PyArg_Parse(value, "s#", &data, &size)) {
356 PyErr_SetString(PyExc_TypeError,
357 "bsddb value type must be string");
358 return -1;
360 drec.data = data;
361 drec.size = size;
362 BSDDB_BGN_SAVE(dp)
363 status = (dp->di_bsddb->put)(dp->di_bsddb, &krec, &drec, 0);
364 BSDDB_END_SAVE(dp)
366 if (status != 0) {
367 if (status < 0)
368 PyErr_SetFromErrno(BsddbError);
369 else
370 PyErr_SetObject(PyExc_KeyError, key);
371 return -1;
373 return 0;
376 static PyMappingMethods bsddb_as_mapping = {
377 (lenfunc)bsddb_length, /*mp_length*/
378 (binaryfunc)bsddb_subscript, /*mp_subscript*/
379 (objobjargproc)bsddb_ass_sub, /*mp_ass_subscript*/
382 static PyObject *
383 bsddb_close(bsddbobject *dp)
385 if (dp->di_bsddb != NULL) {
386 int status;
387 BSDDB_BGN_SAVE(dp)
388 status = (dp->di_bsddb->close)(dp->di_bsddb);
389 BSDDB_END_SAVE(dp)
390 if (status != 0) {
391 dp->di_bsddb = NULL;
392 PyErr_SetFromErrno(BsddbError);
393 return NULL;
396 dp->di_bsddb = NULL;
397 Py_INCREF(Py_None);
398 return Py_None;
401 static PyObject *
402 bsddb_keys(bsddbobject *dp)
404 PyObject *list, *item=NULL;
405 DBT krec, drec;
406 char *data=NULL,buf[4096];
407 int status;
408 int err;
410 check_bsddbobject_open(dp, NULL);
411 list = PyList_New(0);
412 if (list == NULL)
413 return NULL;
414 BSDDB_BGN_SAVE(dp)
415 status = (dp->di_bsddb->seq)(dp->di_bsddb, &krec, &drec, R_FIRST);
416 if (status == 0) {
417 if (krec.size > sizeof(buf)) data = malloc(krec.size);
418 else data = buf;
419 if (data != NULL) memcpy(data,krec.data,krec.size);
421 BSDDB_END_SAVE(dp)
422 if (status == 0 && data==NULL) return PyErr_NoMemory();
423 while (status == 0) {
424 if (dp->di_type == DB_RECNO)
425 item = PyInt_FromLong(*((int*)data));
426 else
427 item = PyString_FromStringAndSize(data,
428 (int)krec.size);
429 if (data != buf) free(data);
430 if (item == NULL) {
431 Py_DECREF(list);
432 return NULL;
434 err = PyList_Append(list, item);
435 Py_DECREF(item);
436 if (err != 0) {
437 Py_DECREF(list);
438 return NULL;
440 BSDDB_BGN_SAVE(dp)
441 status = (dp->di_bsddb->seq)
442 (dp->di_bsddb, &krec, &drec, R_NEXT);
443 if (status == 0) {
444 if (krec.size > sizeof(buf))
445 data = malloc(krec.size);
446 else data = buf;
447 if (data != NULL)
448 memcpy(data,krec.data,krec.size);
450 BSDDB_END_SAVE(dp)
451 if (data == NULL) return PyErr_NoMemory();
453 if (status < 0) {
454 PyErr_SetFromErrno(BsddbError);
455 Py_DECREF(list);
456 return NULL;
458 if (dp->di_size < 0)
459 dp->di_size = PyList_Size(list); /* We just did the work */
460 return list;
463 static PyObject *
464 bsddb_has_key(bsddbobject *dp, PyObject *args)
466 DBT krec, drec;
467 int status;
468 char *data;
469 int size;
470 recno_t recno;
472 if (dp->di_type == DB_RECNO) {
473 if (!PyArg_ParseTuple(args, "i;key type must be integer",
474 &recno)) {
475 return NULL;
477 krec.data = &recno;
478 krec.size = sizeof(recno);
480 else {
481 if (!PyArg_ParseTuple(args, "s#;key type must be string",
482 &data, &size)) {
483 return NULL;
485 krec.data = data;
486 krec.size = size;
488 check_bsddbobject_open(dp, NULL);
490 BSDDB_BGN_SAVE(dp)
491 status = (dp->di_bsddb->get)(dp->di_bsddb, &krec, &drec, 0);
492 BSDDB_END_SAVE(dp)
493 if (status < 0) {
494 PyErr_SetFromErrno(BsddbError);
495 return NULL;
498 return PyInt_FromLong(status == 0);
501 static PyObject *
502 bsddb_set_location(bsddbobject *dp, PyObject *key)
504 int status;
505 DBT krec, drec;
506 char *data,buf[4096];
507 int size;
508 PyObject *result;
509 recno_t recno;
511 if (dp->di_type == DB_RECNO) {
512 if (!PyArg_ParseTuple(key, "i;key type must be integer",
513 &recno)) {
514 return NULL;
516 krec.data = &recno;
517 krec.size = sizeof(recno);
519 else {
520 if (!PyArg_ParseTuple(key, "s#;key type must be string",
521 &data, &size)) {
522 return NULL;
524 krec.data = data;
525 krec.size = size;
527 check_bsddbobject_open(dp, NULL);
529 BSDDB_BGN_SAVE(dp)
530 status = (dp->di_bsddb->seq)(dp->di_bsddb, &krec, &drec, R_CURSOR);
531 if (status == 0) {
532 if (drec.size > sizeof(buf)) data = malloc(drec.size);
533 else data = buf;
534 if (data!=NULL) memcpy(data,drec.data,drec.size);
536 BSDDB_END_SAVE(dp)
537 if (data==NULL) return PyErr_NoMemory();
538 if (status != 0) {
539 if (status < 0)
540 PyErr_SetFromErrno(BsddbError);
541 else
542 PyErr_SetObject(PyExc_KeyError, key);
543 return NULL;
546 if (dp->di_type == DB_RECNO)
547 result = Py_BuildValue("is#", *((int*)krec.data),
548 data, drec.size);
549 else
550 result = Py_BuildValue("s#s#", krec.data, krec.size,
551 data, drec.size);
552 if (data != buf) free(data);
553 return result;
556 static PyObject *
557 bsddb_seq(bsddbobject *dp, int sequence_request)
559 int status;
560 DBT krec, drec;
561 char *kdata=NULL,kbuf[4096];
562 char *ddata=NULL,dbuf[4096];
563 PyObject *result;
565 check_bsddbobject_open(dp, NULL);
566 krec.data = 0;
567 krec.size = 0;
569 BSDDB_BGN_SAVE(dp)
570 status = (dp->di_bsddb->seq)(dp->di_bsddb, &krec,
571 &drec, sequence_request);
572 if (status == 0) {
573 if (krec.size > sizeof(kbuf)) kdata = malloc(krec.size);
574 else kdata = kbuf;
575 if (kdata != NULL) memcpy(kdata,krec.data,krec.size);
576 if (drec.size > sizeof(dbuf)) ddata = malloc(drec.size);
577 else ddata = dbuf;
578 if (ddata != NULL) memcpy(ddata,drec.data,drec.size);
580 BSDDB_END_SAVE(dp)
581 if (status == 0) {
582 if ((kdata == NULL) || (ddata == NULL))
583 return PyErr_NoMemory();
585 else {
586 /* (status != 0) */
587 if (status < 0)
588 PyErr_SetFromErrno(BsddbError);
589 else
590 PyErr_SetString(PyExc_KeyError, "no key/data pairs");
591 return NULL;
594 if (dp->di_type == DB_RECNO)
595 result = Py_BuildValue("is#", *((int*)kdata),
596 ddata, drec.size);
597 else
598 result = Py_BuildValue("s#s#", kdata, krec.size,
599 ddata, drec.size);
600 if (kdata != kbuf) free(kdata);
601 if (ddata != dbuf) free(ddata);
602 return result;
605 static PyObject *
606 bsddb_next(bsddbobject *dp)
608 return bsddb_seq(dp, R_NEXT);
610 static PyObject *
611 bsddb_previous(bsddbobject *dp)
613 return bsddb_seq(dp, R_PREV);
615 static PyObject *
616 bsddb_first(bsddbobject *dp)
618 return bsddb_seq(dp, R_FIRST);
620 static PyObject *
621 bsddb_last(bsddbobject *dp)
623 return bsddb_seq(dp, R_LAST);
625 static PyObject *
626 bsddb_sync(bsddbobject *dp)
628 int status;
630 check_bsddbobject_open(dp, NULL);
631 BSDDB_BGN_SAVE(dp)
632 status = (dp->di_bsddb->sync)(dp->di_bsddb, 0);
633 BSDDB_END_SAVE(dp)
634 if (status != 0) {
635 PyErr_SetFromErrno(BsddbError);
636 return NULL;
638 return PyInt_FromLong(status = 0);
640 static PyMethodDef bsddb_methods[] = {
641 {"close", (PyCFunction)bsddb_close, METH_NOARGS},
642 {"keys", (PyCFunction)bsddb_keys, METH_NOARGS},
643 {"has_key", (PyCFunction)bsddb_has_key, METH_VARARGS},
644 {"set_location", (PyCFunction)bsddb_set_location, METH_VARARGS},
645 {"next", (PyCFunction)bsddb_next, METH_NOARGS},
646 {"previous", (PyCFunction)bsddb_previous, METH_NOARGS},
647 {"first", (PyCFunction)bsddb_first, METH_NOARGS},
648 {"last", (PyCFunction)bsddb_last, METH_NOARGS},
649 {"sync", (PyCFunction)bsddb_sync, METH_NOARGS},
650 {NULL, NULL} /* sentinel */
653 static PyObject *
654 bsddb_getattr(PyObject *dp, char *name)
656 return Py_FindMethod(bsddb_methods, dp, name);
659 static PyTypeObject Bsddbtype = {
660 PyObject_HEAD_INIT(NULL)
662 "bsddb.bsddb",
663 sizeof(bsddbobject),
665 (destructor)bsddb_dealloc, /*tp_dealloc*/
666 0, /*tp_print*/
667 (getattrfunc)bsddb_getattr, /*tp_getattr*/
668 0, /*tp_setattr*/
669 0, /*tp_compare*/
670 0, /*tp_repr*/
671 0, /*tp_as_number*/
672 0, /*tp_as_sequence*/
673 &bsddb_as_mapping, /*tp_as_mapping*/
676 static PyObject *
677 bsdhashopen(PyObject *self, PyObject *args)
679 char *file;
680 char *flag = NULL;
681 int flags = O_RDONLY;
682 int mode = 0666;
683 int bsize = 0;
684 int ffactor = 0;
685 int nelem = 0;
686 int cachesize = 0;
687 int hash = 0; /* XXX currently ignored */
688 int lorder = 0;
690 if (!PyArg_ParseTuple(args, "z|siiiiiii:hashopen",
691 &file, &flag, &mode,
692 &bsize, &ffactor, &nelem, &cachesize,
693 &hash, &lorder))
694 return NULL;
695 if (flag != NULL) {
696 /* XXX need to pass O_EXCL, O_EXLOCK, O_NONBLOCK, O_SHLOCK */
697 if (flag[0] == 'r')
698 flags = O_RDONLY;
699 else if (flag[0] == 'w')
700 flags = O_RDWR;
701 else if (flag[0] == 'c')
702 flags = O_RDWR|O_CREAT;
703 else if (flag[0] == 'n')
704 flags = O_RDWR|O_CREAT|O_TRUNC;
705 else {
706 PyErr_SetString(BsddbError,
707 "Flag should begin with 'r', 'w', 'c' or 'n'");
708 return NULL;
710 if (flag[1] == 'l') {
711 #if defined(O_EXLOCK) && defined(O_SHLOCK)
712 if (flag[0] == 'r')
713 flags |= O_SHLOCK;
714 else
715 flags |= O_EXLOCK;
716 #else
717 PyErr_SetString(BsddbError,
718 "locking not supported on this platform");
719 return NULL;
720 #endif
723 return newdbhashobject(file, flags, mode,
724 bsize, ffactor, nelem, cachesize, hash, lorder);
727 static PyObject *
728 bsdbtopen(PyObject *self, PyObject *args)
730 char *file;
731 char *flag = NULL;
732 int flags = O_RDONLY;
733 int mode = 0666;
734 int cachesize = 0;
735 int maxkeypage = 0;
736 int minkeypage = 0;
737 int btflags = 0;
738 unsigned int psize = 0;
739 int lorder = 0;
741 if (!PyArg_ParseTuple(args, "z|siiiiiii:btopen",
742 &file, &flag, &mode,
743 &btflags, &cachesize, &maxkeypage, &minkeypage,
744 &psize, &lorder))
745 return NULL;
746 if (flag != NULL) {
747 /* XXX need to pass O_EXCL, O_EXLOCK, O_NONBLOCK, O_SHLOCK */
748 if (flag[0] == 'r')
749 flags = O_RDONLY;
750 else if (flag[0] == 'w')
751 flags = O_RDWR;
752 else if (flag[0] == 'c')
753 flags = O_RDWR|O_CREAT;
754 else if (flag[0] == 'n')
755 flags = O_RDWR|O_CREAT|O_TRUNC;
756 else {
757 PyErr_SetString(BsddbError,
758 "Flag should begin with 'r', 'w', 'c' or 'n'");
759 return NULL;
761 if (flag[1] == 'l') {
762 #if defined(O_EXLOCK) && defined(O_SHLOCK)
763 if (flag[0] == 'r')
764 flags |= O_SHLOCK;
765 else
766 flags |= O_EXLOCK;
767 #else
768 PyErr_SetString(BsddbError,
769 "locking not supported on this platform");
770 return NULL;
771 #endif
774 return newdbbtobject(file, flags, mode,
775 btflags, cachesize, maxkeypage, minkeypage,
776 psize, lorder);
779 static PyObject *
780 bsdrnopen(PyObject *self, PyObject *args)
782 char *file;
783 char *flag = NULL;
784 int flags = O_RDONLY;
785 int mode = 0666;
786 int cachesize = 0;
787 int rnflags = 0;
788 unsigned int psize = 0;
789 int lorder = 0;
790 size_t reclen = 0;
791 char *bval = "";
792 char *bfname = NULL;
794 if (!PyArg_ParseTuple(args, "z|siiiiiiss:rnopen",
795 &file, &flag, &mode,
796 &rnflags, &cachesize, &psize, &lorder,
797 &reclen, &bval, &bfname))
798 return NULL;
800 if (flag != NULL) {
801 /* XXX need to pass O_EXCL, O_EXLOCK, O_NONBLOCK, O_SHLOCK */
802 if (flag[0] == 'r')
803 flags = O_RDONLY;
804 else if (flag[0] == 'w')
805 flags = O_RDWR;
806 else if (flag[0] == 'c')
807 flags = O_RDWR|O_CREAT;
808 else if (flag[0] == 'n')
809 flags = O_RDWR|O_CREAT|O_TRUNC;
810 else {
811 PyErr_SetString(BsddbError,
812 "Flag should begin with 'r', 'w', 'c' or 'n'");
813 return NULL;
815 if (flag[1] == 'l') {
816 #if defined(O_EXLOCK) && defined(O_SHLOCK)
817 if (flag[0] == 'r')
818 flags |= O_SHLOCK;
819 else
820 flags |= O_EXLOCK;
821 #else
822 PyErr_SetString(BsddbError,
823 "locking not supported on this platform");
824 return NULL;
825 #endif
827 else if (flag[1] != '\0') {
828 PyErr_SetString(BsddbError,
829 "Flag char 2 should be 'l' or absent");
830 return NULL;
833 return newdbrnobject(file, flags, mode, rnflags, cachesize,
834 psize, lorder, reclen, bval[0], bfname);
837 static PyMethodDef bsddbmodule_methods[] = {
838 {"hashopen", (PyCFunction)bsdhashopen, METH_VARARGS},
839 {"btopen", (PyCFunction)bsdbtopen, METH_VARARGS},
840 {"rnopen", (PyCFunction)bsdrnopen, METH_VARARGS},
841 /* strictly for use by dbhhash!!! */
842 {"open", (PyCFunction)bsdhashopen, METH_VARARGS},
843 {0, 0},
846 PyMODINIT_FUNC
847 initbsddb185(void) {
848 PyObject *m, *d;
850 Bsddbtype.ob_type = &PyType_Type;
851 m = Py_InitModule("bsddb185", bsddbmodule_methods);
852 if (m == NULL)
853 return;
854 d = PyModule_GetDict(m);
855 BsddbError = PyErr_NewException("bsddb.error", NULL, NULL);
856 if (BsddbError != NULL)
857 PyDict_SetItemString(d, "error", BsddbError);