PageRenderTime 632ms CodeModel.GetById 121ms app.highlight 305ms RepoModel.GetById 198ms app.codeStats 0ms

/Modules/bsddbmodule.c

http://unladen-swallow.googlecode.com/
C | 862 lines | 772 code | 67 blank | 23 comment | 215 complexity | 3a64b37be820f8880087a48014bc6938 MD5 | raw file
  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.
  7
  8   XXX To do:
  9   - provide a way to access the various hash functions
 10   - support more open flags
 11
 12   The windows port of the Berkeley DB code is hard to find on the web:
 13   www.nightmare.com/software.html
 14*/
 15
 16#include "Python.h"
 17#ifdef WITH_THREAD
 18#include "pythread.h"
 19#endif
 20
 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) */
 31
 32typedef 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;
 41
 42static PyTypeObject Bsddbtype;
 43
 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; }
 49
 50static PyObject *BsddbError;
 51
 52static PyObject *
 53newdbhashobject(char *file, int flags, int mode,
 54		int bsize, int ffactor, int nelem, int cachesize,
 55		int hash, int lorder)
 56{
 57	bsddbobject *dp;
 58	HASHINFO info;
 59
 60	if ((dp = PyObject_New(bsddbobject, &Bsddbtype)) == NULL)
 61		return NULL;
 62
 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;
 69
 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;
 83	}
 84
 85	dp->di_size = -1;
 86	dp->di_type = DB_HASH;
 87
 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;
 94	}
 95#endif
 96
 97	return (PyObject *)dp;
 98}
 99
100static PyObject *
101newdbbtobject(char *file, int flags, int mode,
102	      int btflags, int cachesize, int maxkeypage,
103	      int minkeypage, int psize, int lorder)
104{
105	bsddbobject *dp;
106	BTREEINFO info;
107
108	if ((dp = PyObject_New(bsddbobject, &Bsddbtype)) == NULL)
109		return NULL;
110
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;
119
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;
133	}
134
135	dp->di_size = -1;
136	dp->di_type = DB_BTREE;
137
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;
144	}
145#endif
146
147	return (PyObject *)dp;
148}
149
150static PyObject *
151newdbrnobject(char *file, int flags, int mode,
152	      int rnflags, int cachesize, int psize, int lorder,
153	      size_t reclen, u_char bval, char *bfname)
154{
155	bsddbobject *dp;
156	RECNOINFO info;
157	int fd;
158
159	if ((dp = PyObject_New(bsddbobject, &Bsddbtype)) == NULL)
160		return NULL;
161
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;
169
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;
178	}
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
184	}
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;
192	}
193
194	dp->di_size = -1;
195	dp->di_type = DB_RECNO;
196
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;
203	}
204#endif
205
206	return (PyObject *)dp;
207}
208
209static void
210bsddb_dealloc(bsddbobject *dp)
211{
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;
218	}
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);
229	}
230	PyObject_Del(dp);
231}
232
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
242
243static Py_ssize_t
244bsddb_length(bsddbobject *dp)
245{
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;
262		}
263		dp->di_size = size;
264	}
265	return dp->di_size;
266}
267
268static PyObject *
269bsddb_subscript(bsddbobject *dp, PyObject *key)
270{
271	int status;
272	DBT krec, drec;
273	char *data,buf[4096];
274	int size;
275	PyObject *result;
276	recno_t recno;
277	
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;
283		}
284		krec.data = &recno;
285		krec.size = sizeof(recno);
286	}
287	else {
288		if (!PyArg_Parse(key, "s#", &data, &size)) {
289			PyErr_SetString(PyExc_TypeError,
290					"key type must be string");
291			return NULL;
292		}
293		krec.data = data;
294		krec.size = size;
295	}
296        check_bsddbobject_open(dp, NULL);
297
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);
304	}
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;
313	}
314
315	result = PyString_FromStringAndSize(data, (int)drec.size);
316	if (data != buf) free(data);
317	return result;
318}
319
320static int
321bsddb_ass_sub(bsddbobject *dp, PyObject *key, PyObject *value)
322{
323	int status;
324	DBT krec, drec;
325	char *data;
326	int size;
327	recno_t recno;
328
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;
334		}
335		krec.data = &recno;
336		krec.size = sizeof(recno);
337	}
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;
343		}
344		krec.data = data;
345		krec.size = size;
346	}
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)
353	}
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;
359		}
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)
365	}
366	if (status != 0) {
367		if (status < 0)
368			PyErr_SetFromErrno(BsddbError);
369		else
370			PyErr_SetObject(PyExc_KeyError, key);
371		return -1;
372	}
373	return 0;
374}
375
376static PyMappingMethods bsddb_as_mapping = {
377	(lenfunc)bsddb_length,		/*mp_length*/
378	(binaryfunc)bsddb_subscript,	/*mp_subscript*/
379	(objobjargproc)bsddb_ass_sub,	/*mp_ass_subscript*/
380};
381
382static PyObject *
383bsddb_close(bsddbobject *dp)
384{
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;
394		}
395	}
396	dp->di_bsddb = NULL;
397	Py_INCREF(Py_None);
398	return Py_None;
399}
400
401static PyObject *
402bsddb_keys(bsddbobject *dp)
403{
404	PyObject *list, *item=NULL;
405	DBT krec, drec;
406	char *data=NULL,buf[4096];
407	int status;
408	int err;
409
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);
420	}
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;
433		}
434		err = PyList_Append(list, item);
435		Py_DECREF(item);
436		if (err != 0) {
437			Py_DECREF(list);
438			return NULL;
439		}
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);
449		}
450		BSDDB_END_SAVE(dp)
451		if (data == NULL) return PyErr_NoMemory();
452	}
453	if (status < 0) {
454		PyErr_SetFromErrno(BsddbError);
455		Py_DECREF(list);
456		return NULL;
457	}
458	if (dp->di_size < 0)
459		dp->di_size = PyList_Size(list); /* We just did the work */
460	return list;
461}
462
463static PyObject *
464bsddb_has_key(bsddbobject *dp, PyObject *args)
465{
466	DBT krec, drec;
467	int status;
468	char *data;
469	int size;
470	recno_t recno;
471
472	if (dp->di_type == DB_RECNO) {
473		if (!PyArg_ParseTuple(args, "i;key type must be integer",
474				      &recno)) {
475			return NULL;
476		}
477		krec.data = &recno;
478		krec.size = sizeof(recno);
479	}
480	else {
481		if (!PyArg_ParseTuple(args, "s#;key type must be string",
482				      &data, &size)) {
483			return NULL;
484		}
485		krec.data = data;
486		krec.size = size;
487	}
488	check_bsddbobject_open(dp, NULL);
489
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;
496	}
497
498	return PyInt_FromLong(status == 0);
499}
500
501static PyObject *
502bsddb_set_location(bsddbobject *dp, PyObject *key)
503{
504	int status;
505	DBT krec, drec;
506	char *data,buf[4096];
507	int size;
508	PyObject *result;
509	recno_t recno;
510
511	if (dp->di_type == DB_RECNO) {
512		if (!PyArg_ParseTuple(key, "i;key type must be integer",
513				      &recno)) {
514			return NULL;
515		}
516		krec.data = &recno;
517		krec.size = sizeof(recno);
518	}
519	else {
520		if (!PyArg_ParseTuple(key, "s#;key type must be string",
521				      &data, &size)) {
522			return NULL;
523		}
524		krec.data = data;
525		krec.size = size;
526	}
527	check_bsddbobject_open(dp, NULL);
528
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);
535	}
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;
544	}
545
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;
554}
555
556static PyObject *
557bsddb_seq(bsddbobject *dp, int sequence_request)
558{
559	int status;
560	DBT krec, drec;
561	char *kdata=NULL,kbuf[4096];
562	char *ddata=NULL,dbuf[4096];
563	PyObject *result;
564
565	check_bsddbobject_open(dp, NULL);
566	krec.data = 0;
567	krec.size = 0;
568
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);
579	}
580	BSDDB_END_SAVE(dp)
581	if (status == 0) {
582		if ((kdata == NULL) || (ddata == NULL)) 
583			return PyErr_NoMemory();
584	}
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;
592	}
593
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;
603}
604
605static PyObject *
606bsddb_next(bsddbobject *dp)
607{
608	return bsddb_seq(dp, R_NEXT);
609}
610static PyObject *
611bsddb_previous(bsddbobject *dp)
612{
613	return bsddb_seq(dp, R_PREV);
614}
615static PyObject *
616bsddb_first(bsddbobject *dp)
617{
618	return bsddb_seq(dp, R_FIRST);
619}
620static PyObject *
621bsddb_last(bsddbobject *dp)
622{
623	return bsddb_seq(dp, R_LAST);
624}
625static PyObject *
626bsddb_sync(bsddbobject *dp)
627{
628	int status;
629
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;
637	}
638	return PyInt_FromLong(status = 0);
639}
640static 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 */
651};
652
653static PyObject *
654bsddb_getattr(PyObject *dp, char *name)
655{
656	return Py_FindMethod(bsddb_methods, dp, name);
657}
658
659static PyTypeObject Bsddbtype = {
660	PyObject_HEAD_INIT(NULL)
661	0,
662	"bsddb.bsddb",
663	sizeof(bsddbobject),
664	0,
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*/
674};
675
676static PyObject *
677bsdhashopen(PyObject *self, PyObject *args)
678{
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;
689
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;
709		}
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
721		}
722	}
723	return newdbhashobject(file, flags, mode,
724			       bsize, ffactor, nelem, cachesize, hash, lorder);
725}
726
727static PyObject *
728bsdbtopen(PyObject *self, PyObject *args)
729{
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;
740
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;
760		}
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
772		}
773	}
774	return newdbbtobject(file, flags, mode,
775			     btflags, cachesize, maxkeypage, minkeypage,
776			     psize, lorder);
777}
778
779static PyObject *
780bsdrnopen(PyObject *self, PyObject *args)
781{
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;
793
794	if (!PyArg_ParseTuple(args, "z|siiiiiiss:rnopen",
795			      &file, &flag, &mode,
796			      &rnflags, &cachesize, &psize, &lorder,
797			      &reclen, &bval, &bfname))
798		return NULL;
799
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;
814		}
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
826		}
827		else if (flag[1] != '\0') {
828			PyErr_SetString(BsddbError,
829				       "Flag char 2 should be 'l' or absent");
830			return NULL;
831		}
832	}
833	return newdbrnobject(file, flags, mode, rnflags, cachesize,
834			     psize, lorder, reclen, bval[0], bfname);
835}
836
837static 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},
844};
845
846PyMODINIT_FUNC
847initbsddb185(void) {
848	PyObject *m, *d;
849
850    if (PyErr_WarnPy3k("the bsddb185 module has been removed in "
851                       "Python 3.0", 2) < 0)
852        return;    
853
854	Bsddbtype.ob_type = &PyType_Type;
855	m = Py_InitModule("bsddb185", bsddbmodule_methods);
856	if (m == NULL)
857		return;
858	d = PyModule_GetDict(m);
859	BsddbError = PyErr_NewException("bsddb.error", NULL, NULL);
860	if (BsddbError != NULL)
861		PyDict_SetItemString(d, "error", BsddbError);
862}