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
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;
41
42 static 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
50 static PyObject *BsddbError;
51
52 static PyObject *
newdbhashobject(char * file,int flags,int mode,int bsize,int ffactor,int nelem,int cachesize,int hash,int lorder)53 newdbhashobject(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
100 static PyObject *
newdbbtobject(char * file,int flags,int mode,int btflags,int cachesize,int maxkeypage,int minkeypage,int psize,int lorder)101 newdbbtobject(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
150 static PyObject *
newdbrnobject(char * file,int flags,int mode,int rnflags,int cachesize,int psize,int lorder,size_t reclen,u_char bval,char * bfname)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)
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
209 static void
bsddb_dealloc(bsddbobject * dp)210 bsddb_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
243 static Py_ssize_t
bsddb_length(bsddbobject * dp)244 bsddb_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
268 static PyObject *
bsddb_subscript(bsddbobject * dp,PyObject * key)269 bsddb_subscript(bsddbobject *dp, PyObject *key)
270 {
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;
278
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;
284 }
285 krec.data = &recno;
286 krec.size = sizeof(recno);
287 }
288 else {
289 if (!PyArg_Parse(key, "s#", &data, &size)) {
290 PyErr_SetString(PyExc_TypeError,
291 "key type must be string");
292 return NULL;
293 }
294 krec.data = data;
295 krec.size = size;
296 }
297 check_bsddbobject_open(dp, NULL);
298
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);
305 }
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;
314 }
315
316 result = PyString_FromStringAndSize(data, (int)drec.size);
317 if (data != buf) free(data);
318 return result;
319 }
320
321 static int
bsddb_ass_sub(bsddbobject * dp,PyObject * key,PyObject * value)322 bsddb_ass_sub(bsddbobject *dp, PyObject *key, PyObject *value)
323 {
324 int status;
325 DBT krec, drec;
326 char *data;
327 int size;
328 recno_t recno;
329
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;
335 }
336 krec.data = &recno;
337 krec.size = sizeof(recno);
338 }
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;
344 }
345 krec.data = data;
346 krec.size = size;
347 }
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)
354 }
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;
360 }
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)
366 }
367 if (status != 0) {
368 if (status < 0)
369 PyErr_SetFromErrno(BsddbError);
370 else
371 PyErr_SetObject(PyExc_KeyError, key);
372 return -1;
373 }
374 return 0;
375 }
376
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*/
381 };
382
383 static PyObject *
bsddb_close(bsddbobject * dp)384 bsddb_close(bsddbobject *dp)
385 {
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;
395 }
396 }
397 dp->di_bsddb = NULL;
398 Py_INCREF(Py_None);
399 return Py_None;
400 }
401
402 static PyObject *
bsddb_keys(bsddbobject * dp)403 bsddb_keys(bsddbobject *dp)
404 {
405 PyObject *list, *item=NULL;
406 DBT krec, drec;
407 char *data=NULL,buf[4096];
408 int status;
409 int err;
410
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);
421 }
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;
434 }
435 err = PyList_Append(list, item);
436 Py_DECREF(item);
437 if (err != 0) {
438 Py_DECREF(list);
439 return NULL;
440 }
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);
450 }
451 BSDDB_END_SAVE(dp)
452 if (data == NULL) return PyErr_NoMemory();
453 }
454 if (status < 0) {
455 PyErr_SetFromErrno(BsddbError);
456 Py_DECREF(list);
457 return NULL;
458 }
459 if (dp->di_size < 0)
460 dp->di_size = PyList_Size(list); /* We just did the work */
461 return list;
462 }
463
464 static PyObject *
bsddb_has_key(bsddbobject * dp,PyObject * args)465 bsddb_has_key(bsddbobject *dp, PyObject *args)
466 {
467 DBT krec, drec;
468 int status;
469 char *data;
470 int size;
471 recno_t recno;
472
473 if (dp->di_type == DB_RECNO) {
474 if (!PyArg_ParseTuple(args, "i;key type must be integer",
475 &recno)) {
476 return NULL;
477 }
478 krec.data = &recno;
479 krec.size = sizeof(recno);
480 }
481 else {
482 if (!PyArg_ParseTuple(args, "s#;key type must be string",
483 &data, &size)) {
484 return NULL;
485 }
486 krec.data = data;
487 krec.size = size;
488 }
489 check_bsddbobject_open(dp, NULL);
490
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;
497 }
498
499 return PyInt_FromLong(status == 0);
500 }
501
502 static PyObject *
bsddb_set_location(bsddbobject * dp,PyObject * key)503 bsddb_set_location(bsddbobject *dp, PyObject *key)
504 {
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;
512
513 if (dp->di_type == DB_RECNO) {
514 if (!PyArg_ParseTuple(key, "i;key type must be integer",
515 &recno)) {
516 return NULL;
517 }
518 krec.data = &recno;
519 krec.size = sizeof(recno);
520 }
521 else {
522 if (!PyArg_ParseTuple(key, "s#;key type must be string",
523 &data, &size)) {
524 return NULL;
525 }
526 krec.data = data;
527 krec.size = size;
528 }
529 check_bsddbobject_open(dp, NULL);
530
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);
537 }
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;
546 }
547
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;
556 }
557
558 static PyObject *
bsddb_seq(bsddbobject * dp,int sequence_request)559 bsddb_seq(bsddbobject *dp, int sequence_request)
560 {
561 int status;
562 DBT krec, drec;
563 char *kdata=NULL,kbuf[4096];
564 char *ddata=NULL,dbuf[4096];
565 PyObject *result;
566
567 check_bsddbobject_open(dp, NULL);
568 krec.data = 0;
569 krec.size = 0;
570
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);
581 }
582 BSDDB_END_SAVE(dp)
583 if (status == 0) {
584 if ((kdata == NULL) || (ddata == NULL))
585 return PyErr_NoMemory();
586 }
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;
594 }
595
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;
605 }
606
607 static PyObject *
bsddb_next(bsddbobject * dp)608 bsddb_next(bsddbobject *dp)
609 {
610 return bsddb_seq(dp, R_NEXT);
611 }
612 static PyObject *
bsddb_previous(bsddbobject * dp)613 bsddb_previous(bsddbobject *dp)
614 {
615 return bsddb_seq(dp, R_PREV);
616 }
617 static PyObject *
bsddb_first(bsddbobject * dp)618 bsddb_first(bsddbobject *dp)
619 {
620 return bsddb_seq(dp, R_FIRST);
621 }
622 static PyObject *
bsddb_last(bsddbobject * dp)623 bsddb_last(bsddbobject *dp)
624 {
625 return bsddb_seq(dp, R_LAST);
626 }
627 static PyObject *
bsddb_sync(bsddbobject * dp)628 bsddb_sync(bsddbobject *dp)
629 {
630 int status;
631
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;
639 }
640 return PyInt_FromLong(0);
641 }
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 */
653 };
654
655 static PyObject *
bsddb_getattr(PyObject * dp,char * name)656 bsddb_getattr(PyObject *dp, char *name)
657 {
658 return Py_FindMethod(bsddb_methods, dp, name);
659 }
660
661 static PyTypeObject Bsddbtype = {
662 PyObject_HEAD_INIT(NULL)
663 0,
664 "bsddb.bsddb",
665 sizeof(bsddbobject),
666 0,
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*/
676 };
677
678 static PyObject *
bsdhashopen(PyObject * self,PyObject * args)679 bsdhashopen(PyObject *self, PyObject *args)
680 {
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;
691
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;
711 }
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
723 }
724 }
725 return newdbhashobject(file, flags, mode,
726 bsize, ffactor, nelem, cachesize, hash, lorder);
727 }
728
729 static PyObject *
bsdbtopen(PyObject * self,PyObject * args)730 bsdbtopen(PyObject *self, PyObject *args)
731 {
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;
742
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;
762 }
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
774 }
775 }
776 return newdbbtobject(file, flags, mode,
777 btflags, cachesize, maxkeypage, minkeypage,
778 psize, lorder);
779 }
780
781 static PyObject *
bsdrnopen(PyObject * self,PyObject * args)782 bsdrnopen(PyObject *self, PyObject *args)
783 {
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;
795
796 if (!PyArg_ParseTuple(args, "z|siiiiiiss:rnopen",
797 &file, &flag, &mode,
798 &rnflags, &cachesize, &psize, &lorder,
799 &reclen, &bval, &bfname))
800 return NULL;
801
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;
816 }
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
828 }
829 else if (flag[1] != '\0') {
830 PyErr_SetString(BsddbError,
831 "Flag char 2 should be 'l' or absent");
832 return NULL;
833 }
834 }
835 return newdbrnobject(file, flags, mode, rnflags, cachesize,
836 psize, lorder, reclen, bval[0], bfname);
837 }
838
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},
846 };
847
848 PyMODINIT_FUNC
initbsddb185(void)849 initbsddb185(void) {
850 PyObject *m, *d;
851
852 if (PyErr_WarnPy3k("the bsddb185 module has been removed in "
853 "Python 3.0", 2) < 0)
854 return;
855
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);
864 }
865