move sections
[python/dscho.git] / Modules / bsddbmodule.c
blob578cf3df069196890b071913782c424627bc486d
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 = NULL;
274 char buf[4096];
275 int size;
276 PyObject *result;
277 recno_t recno;
279 if (dp->di_type == DB_RECNO) {
280 if (!PyArg_Parse(key, "i", &recno)) {
281 PyErr_SetString(PyExc_TypeError,
282 "key type must be integer");
283 return NULL;
285 krec.data = &recno;
286 krec.size = sizeof(recno);
288 else {
289 if (!PyArg_Parse(key, "s#", &data, &size)) {
290 PyErr_SetString(PyExc_TypeError,
291 "key type must be string");
292 return NULL;
294 krec.data = data;
295 krec.size = size;
297 check_bsddbobject_open(dp, NULL);
299 BSDDB_BGN_SAVE(dp)
300 status = (dp->di_bsddb->get)(dp->di_bsddb, &krec, &drec, 0);
301 if (status == 0) {
302 if (drec.size > sizeof(buf)) data = malloc(drec.size);
303 else data = buf;
304 if (data!=NULL) memcpy(data,drec.data,drec.size);
306 BSDDB_END_SAVE(dp)
307 if (data==NULL) return PyErr_NoMemory();
308 if (status != 0) {
309 if (status < 0)
310 PyErr_SetFromErrno(BsddbError);
311 else
312 PyErr_SetObject(PyExc_KeyError, key);
313 return NULL;
316 result = PyString_FromStringAndSize(data, (int)drec.size);
317 if (data != buf) free(data);
318 return result;
321 static int
322 bsddb_ass_sub(bsddbobject *dp, PyObject *key, PyObject *value)
324 int status;
325 DBT krec, drec;
326 char *data;
327 int size;
328 recno_t recno;
330 if (dp->di_type == DB_RECNO) {
331 if (!PyArg_Parse(key, "i", &recno)) {
332 PyErr_SetString(PyExc_TypeError,
333 "bsddb key type must be integer");
334 return -1;
336 krec.data = &recno;
337 krec.size = sizeof(recno);
339 else {
340 if (!PyArg_Parse(key, "s#", &data, &size)) {
341 PyErr_SetString(PyExc_TypeError,
342 "bsddb key type must be string");
343 return -1;
345 krec.data = data;
346 krec.size = size;
348 check_bsddbobject_open(dp, -1);
349 dp->di_size = -1;
350 if (value == NULL) {
351 BSDDB_BGN_SAVE(dp)
352 status = (dp->di_bsddb->del)(dp->di_bsddb, &krec, 0);
353 BSDDB_END_SAVE(dp)
355 else {
356 if (!PyArg_Parse(value, "s#", &data, &size)) {
357 PyErr_SetString(PyExc_TypeError,
358 "bsddb value type must be string");
359 return -1;
361 drec.data = data;
362 drec.size = size;
363 BSDDB_BGN_SAVE(dp)
364 status = (dp->di_bsddb->put)(dp->di_bsddb, &krec, &drec, 0);
365 BSDDB_END_SAVE(dp)
367 if (status != 0) {
368 if (status < 0)
369 PyErr_SetFromErrno(BsddbError);
370 else
371 PyErr_SetObject(PyExc_KeyError, key);
372 return -1;
374 return 0;
377 static PyMappingMethods bsddb_as_mapping = {
378 (lenfunc)bsddb_length, /*mp_length*/
379 (binaryfunc)bsddb_subscript, /*mp_subscript*/
380 (objobjargproc)bsddb_ass_sub, /*mp_ass_subscript*/
383 static PyObject *
384 bsddb_close(bsddbobject *dp)
386 if (dp->di_bsddb != NULL) {
387 int status;
388 BSDDB_BGN_SAVE(dp)
389 status = (dp->di_bsddb->close)(dp->di_bsddb);
390 BSDDB_END_SAVE(dp)
391 if (status != 0) {
392 dp->di_bsddb = NULL;
393 PyErr_SetFromErrno(BsddbError);
394 return NULL;
397 dp->di_bsddb = NULL;
398 Py_INCREF(Py_None);
399 return Py_None;
402 static PyObject *
403 bsddb_keys(bsddbobject *dp)
405 PyObject *list, *item=NULL;
406 DBT krec, drec;
407 char *data=NULL,buf[4096];
408 int status;
409 int err;
411 check_bsddbobject_open(dp, NULL);
412 list = PyList_New(0);
413 if (list == NULL)
414 return NULL;
415 BSDDB_BGN_SAVE(dp)
416 status = (dp->di_bsddb->seq)(dp->di_bsddb, &krec, &drec, R_FIRST);
417 if (status == 0) {
418 if (krec.size > sizeof(buf)) data = malloc(krec.size);
419 else data = buf;
420 if (data != NULL) memcpy(data,krec.data,krec.size);
422 BSDDB_END_SAVE(dp)
423 if (status == 0 && data==NULL) return PyErr_NoMemory();
424 while (status == 0) {
425 if (dp->di_type == DB_RECNO)
426 item = PyInt_FromLong(*((int*)data));
427 else
428 item = PyString_FromStringAndSize(data,
429 (int)krec.size);
430 if (data != buf) free(data);
431 if (item == NULL) {
432 Py_DECREF(list);
433 return NULL;
435 err = PyList_Append(list, item);
436 Py_DECREF(item);
437 if (err != 0) {
438 Py_DECREF(list);
439 return NULL;
441 BSDDB_BGN_SAVE(dp)
442 status = (dp->di_bsddb->seq)
443 (dp->di_bsddb, &krec, &drec, R_NEXT);
444 if (status == 0) {
445 if (krec.size > sizeof(buf))
446 data = malloc(krec.size);
447 else data = buf;
448 if (data != NULL)
449 memcpy(data,krec.data,krec.size);
451 BSDDB_END_SAVE(dp)
452 if (data == NULL) return PyErr_NoMemory();
454 if (status < 0) {
455 PyErr_SetFromErrno(BsddbError);
456 Py_DECREF(list);
457 return NULL;
459 if (dp->di_size < 0)
460 dp->di_size = PyList_Size(list); /* We just did the work */
461 return list;
464 static PyObject *
465 bsddb_has_key(bsddbobject *dp, PyObject *args)
467 DBT krec, drec;
468 int status;
469 char *data;
470 int size;
471 recno_t recno;
473 if (dp->di_type == DB_RECNO) {
474 if (!PyArg_ParseTuple(args, "i;key type must be integer",
475 &recno)) {
476 return NULL;
478 krec.data = &recno;
479 krec.size = sizeof(recno);
481 else {
482 if (!PyArg_ParseTuple(args, "s#;key type must be string",
483 &data, &size)) {
484 return NULL;
486 krec.data = data;
487 krec.size = size;
489 check_bsddbobject_open(dp, NULL);
491 BSDDB_BGN_SAVE(dp)
492 status = (dp->di_bsddb->get)(dp->di_bsddb, &krec, &drec, 0);
493 BSDDB_END_SAVE(dp)
494 if (status < 0) {
495 PyErr_SetFromErrno(BsddbError);
496 return NULL;
499 return PyInt_FromLong(status == 0);
502 static PyObject *
503 bsddb_set_location(bsddbobject *dp, PyObject *key)
505 int status;
506 DBT krec, drec;
507 char *data = NULL;
508 char buf[4096];
509 int size;
510 PyObject *result;
511 recno_t recno;
513 if (dp->di_type == DB_RECNO) {
514 if (!PyArg_ParseTuple(key, "i;key type must be integer",
515 &recno)) {
516 return NULL;
518 krec.data = &recno;
519 krec.size = sizeof(recno);
521 else {
522 if (!PyArg_ParseTuple(key, "s#;key type must be string",
523 &data, &size)) {
524 return NULL;
526 krec.data = data;
527 krec.size = size;
529 check_bsddbobject_open(dp, NULL);
531 BSDDB_BGN_SAVE(dp)
532 status = (dp->di_bsddb->seq)(dp->di_bsddb, &krec, &drec, R_CURSOR);
533 if (status == 0) {
534 if (drec.size > sizeof(buf)) data = malloc(drec.size);
535 else data = buf;
536 if (data!=NULL) memcpy(data,drec.data,drec.size);
538 BSDDB_END_SAVE(dp)
539 if (data==NULL) return PyErr_NoMemory();
540 if (status != 0) {
541 if (status < 0)
542 PyErr_SetFromErrno(BsddbError);
543 else
544 PyErr_SetObject(PyExc_KeyError, key);
545 return NULL;
548 if (dp->di_type == DB_RECNO)
549 result = Py_BuildValue("is#", *((int*)krec.data),
550 data, drec.size);
551 else
552 result = Py_BuildValue("s#s#", krec.data, krec.size,
553 data, drec.size);
554 if (data != buf) free(data);
555 return result;
558 static PyObject *
559 bsddb_seq(bsddbobject *dp, int sequence_request)
561 int status;
562 DBT krec, drec;
563 char *kdata=NULL,kbuf[4096];
564 char *ddata=NULL,dbuf[4096];
565 PyObject *result;
567 check_bsddbobject_open(dp, NULL);
568 krec.data = 0;
569 krec.size = 0;
571 BSDDB_BGN_SAVE(dp)
572 status = (dp->di_bsddb->seq)(dp->di_bsddb, &krec,
573 &drec, sequence_request);
574 if (status == 0) {
575 if (krec.size > sizeof(kbuf)) kdata = malloc(krec.size);
576 else kdata = kbuf;
577 if (kdata != NULL) memcpy(kdata,krec.data,krec.size);
578 if (drec.size > sizeof(dbuf)) ddata = malloc(drec.size);
579 else ddata = dbuf;
580 if (ddata != NULL) memcpy(ddata,drec.data,drec.size);
582 BSDDB_END_SAVE(dp)
583 if (status == 0) {
584 if ((kdata == NULL) || (ddata == NULL))
585 return PyErr_NoMemory();
587 else {
588 /* (status != 0) */
589 if (status < 0)
590 PyErr_SetFromErrno(BsddbError);
591 else
592 PyErr_SetString(PyExc_KeyError, "no key/data pairs");
593 return NULL;
596 if (dp->di_type == DB_RECNO)
597 result = Py_BuildValue("is#", *((int*)kdata),
598 ddata, drec.size);
599 else
600 result = Py_BuildValue("s#s#", kdata, krec.size,
601 ddata, drec.size);
602 if (kdata != kbuf) free(kdata);
603 if (ddata != dbuf) free(ddata);
604 return result;
607 static PyObject *
608 bsddb_next(bsddbobject *dp)
610 return bsddb_seq(dp, R_NEXT);
612 static PyObject *
613 bsddb_previous(bsddbobject *dp)
615 return bsddb_seq(dp, R_PREV);
617 static PyObject *
618 bsddb_first(bsddbobject *dp)
620 return bsddb_seq(dp, R_FIRST);
622 static PyObject *
623 bsddb_last(bsddbobject *dp)
625 return bsddb_seq(dp, R_LAST);
627 static PyObject *
628 bsddb_sync(bsddbobject *dp)
630 int status;
632 check_bsddbobject_open(dp, NULL);
633 BSDDB_BGN_SAVE(dp)
634 status = (dp->di_bsddb->sync)(dp->di_bsddb, 0);
635 BSDDB_END_SAVE(dp)
636 if (status != 0) {
637 PyErr_SetFromErrno(BsddbError);
638 return NULL;
640 return PyInt_FromLong(0);
642 static PyMethodDef bsddb_methods[] = {
643 {"close", (PyCFunction)bsddb_close, METH_NOARGS},
644 {"keys", (PyCFunction)bsddb_keys, METH_NOARGS},
645 {"has_key", (PyCFunction)bsddb_has_key, METH_VARARGS},
646 {"set_location", (PyCFunction)bsddb_set_location, METH_VARARGS},
647 {"next", (PyCFunction)bsddb_next, METH_NOARGS},
648 {"previous", (PyCFunction)bsddb_previous, METH_NOARGS},
649 {"first", (PyCFunction)bsddb_first, METH_NOARGS},
650 {"last", (PyCFunction)bsddb_last, METH_NOARGS},
651 {"sync", (PyCFunction)bsddb_sync, METH_NOARGS},
652 {NULL, NULL} /* sentinel */
655 static PyObject *
656 bsddb_getattr(PyObject *dp, char *name)
658 return Py_FindMethod(bsddb_methods, dp, name);
661 static PyTypeObject Bsddbtype = {
662 PyObject_HEAD_INIT(NULL)
664 "bsddb.bsddb",
665 sizeof(bsddbobject),
667 (destructor)bsddb_dealloc, /*tp_dealloc*/
668 0, /*tp_print*/
669 (getattrfunc)bsddb_getattr, /*tp_getattr*/
670 0, /*tp_setattr*/
671 0, /*tp_compare*/
672 0, /*tp_repr*/
673 0, /*tp_as_number*/
674 0, /*tp_as_sequence*/
675 &bsddb_as_mapping, /*tp_as_mapping*/
678 static PyObject *
679 bsdhashopen(PyObject *self, PyObject *args)
681 char *file;
682 char *flag = NULL;
683 int flags = O_RDONLY;
684 int mode = 0666;
685 int bsize = 0;
686 int ffactor = 0;
687 int nelem = 0;
688 int cachesize = 0;
689 int hash = 0; /* XXX currently ignored */
690 int lorder = 0;
692 if (!PyArg_ParseTuple(args, "z|siiiiiii:hashopen",
693 &file, &flag, &mode,
694 &bsize, &ffactor, &nelem, &cachesize,
695 &hash, &lorder))
696 return NULL;
697 if (flag != NULL) {
698 /* XXX need to pass O_EXCL, O_EXLOCK, O_NONBLOCK, O_SHLOCK */
699 if (flag[0] == 'r')
700 flags = O_RDONLY;
701 else if (flag[0] == 'w')
702 flags = O_RDWR;
703 else if (flag[0] == 'c')
704 flags = O_RDWR|O_CREAT;
705 else if (flag[0] == 'n')
706 flags = O_RDWR|O_CREAT|O_TRUNC;
707 else {
708 PyErr_SetString(BsddbError,
709 "Flag should begin with 'r', 'w', 'c' or 'n'");
710 return NULL;
712 if (flag[1] == 'l') {
713 #if defined(O_EXLOCK) && defined(O_SHLOCK)
714 if (flag[0] == 'r')
715 flags |= O_SHLOCK;
716 else
717 flags |= O_EXLOCK;
718 #else
719 PyErr_SetString(BsddbError,
720 "locking not supported on this platform");
721 return NULL;
722 #endif
725 return newdbhashobject(file, flags, mode,
726 bsize, ffactor, nelem, cachesize, hash, lorder);
729 static PyObject *
730 bsdbtopen(PyObject *self, PyObject *args)
732 char *file;
733 char *flag = NULL;
734 int flags = O_RDONLY;
735 int mode = 0666;
736 int cachesize = 0;
737 int maxkeypage = 0;
738 int minkeypage = 0;
739 int btflags = 0;
740 unsigned int psize = 0;
741 int lorder = 0;
743 if (!PyArg_ParseTuple(args, "z|siiiiiii:btopen",
744 &file, &flag, &mode,
745 &btflags, &cachesize, &maxkeypage, &minkeypage,
746 &psize, &lorder))
747 return NULL;
748 if (flag != NULL) {
749 /* XXX need to pass O_EXCL, O_EXLOCK, O_NONBLOCK, O_SHLOCK */
750 if (flag[0] == 'r')
751 flags = O_RDONLY;
752 else if (flag[0] == 'w')
753 flags = O_RDWR;
754 else if (flag[0] == 'c')
755 flags = O_RDWR|O_CREAT;
756 else if (flag[0] == 'n')
757 flags = O_RDWR|O_CREAT|O_TRUNC;
758 else {
759 PyErr_SetString(BsddbError,
760 "Flag should begin with 'r', 'w', 'c' or 'n'");
761 return NULL;
763 if (flag[1] == 'l') {
764 #if defined(O_EXLOCK) && defined(O_SHLOCK)
765 if (flag[0] == 'r')
766 flags |= O_SHLOCK;
767 else
768 flags |= O_EXLOCK;
769 #else
770 PyErr_SetString(BsddbError,
771 "locking not supported on this platform");
772 return NULL;
773 #endif
776 return newdbbtobject(file, flags, mode,
777 btflags, cachesize, maxkeypage, minkeypage,
778 psize, lorder);
781 static PyObject *
782 bsdrnopen(PyObject *self, PyObject *args)
784 char *file;
785 char *flag = NULL;
786 int flags = O_RDONLY;
787 int mode = 0666;
788 int cachesize = 0;
789 int rnflags = 0;
790 unsigned int psize = 0;
791 int lorder = 0;
792 size_t reclen = 0;
793 char *bval = "";
794 char *bfname = NULL;
796 if (!PyArg_ParseTuple(args, "z|siiiiiiss:rnopen",
797 &file, &flag, &mode,
798 &rnflags, &cachesize, &psize, &lorder,
799 &reclen, &bval, &bfname))
800 return NULL;
802 if (flag != NULL) {
803 /* XXX need to pass O_EXCL, O_EXLOCK, O_NONBLOCK, O_SHLOCK */
804 if (flag[0] == 'r')
805 flags = O_RDONLY;
806 else if (flag[0] == 'w')
807 flags = O_RDWR;
808 else if (flag[0] == 'c')
809 flags = O_RDWR|O_CREAT;
810 else if (flag[0] == 'n')
811 flags = O_RDWR|O_CREAT|O_TRUNC;
812 else {
813 PyErr_SetString(BsddbError,
814 "Flag should begin with 'r', 'w', 'c' or 'n'");
815 return NULL;
817 if (flag[1] == 'l') {
818 #if defined(O_EXLOCK) && defined(O_SHLOCK)
819 if (flag[0] == 'r')
820 flags |= O_SHLOCK;
821 else
822 flags |= O_EXLOCK;
823 #else
824 PyErr_SetString(BsddbError,
825 "locking not supported on this platform");
826 return NULL;
827 #endif
829 else if (flag[1] != '\0') {
830 PyErr_SetString(BsddbError,
831 "Flag char 2 should be 'l' or absent");
832 return NULL;
835 return newdbrnobject(file, flags, mode, rnflags, cachesize,
836 psize, lorder, reclen, bval[0], bfname);
839 static PyMethodDef bsddbmodule_methods[] = {
840 {"hashopen", (PyCFunction)bsdhashopen, METH_VARARGS},
841 {"btopen", (PyCFunction)bsdbtopen, METH_VARARGS},
842 {"rnopen", (PyCFunction)bsdrnopen, METH_VARARGS},
843 /* strictly for use by dbhhash!!! */
844 {"open", (PyCFunction)bsdhashopen, METH_VARARGS},
845 {0, 0},
848 PyMODINIT_FUNC
849 initbsddb185(void) {
850 PyObject *m, *d;
852 if (PyErr_WarnPy3k("the bsddb185 module has been removed in "
853 "Python 3.0", 2) < 0)
854 return;
856 Bsddbtype.ob_type = &PyType_Type;
857 m = Py_InitModule("bsddb185", bsddbmodule_methods);
858 if (m == NULL)
859 return;
860 d = PyModule_GetDict(m);
861 BsddbError = PyErr_NewException("bsddb.error", NULL, NULL);
862 if (BsddbError != NULL)
863 PyDict_SetItemString(d, "error", BsddbError);