Home | History | Annotate | Download | only in Modules
      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 (at) 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 *
     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 *
    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 *
    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
    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
    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 *
    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
    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 *
    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 *
    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 *
    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 *
    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 *
    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 *
    608 bsddb_next(bsddbobject *dp)
    609 {
    610     return bsddb_seq(dp, R_NEXT);
    611 }
    612 static PyObject *
    613 bsddb_previous(bsddbobject *dp)
    614 {
    615     return bsddb_seq(dp, R_PREV);
    616 }
    617 static PyObject *
    618 bsddb_first(bsddbobject *dp)
    619 {
    620     return bsddb_seq(dp, R_FIRST);
    621 }
    622 static PyObject *
    623 bsddb_last(bsddbobject *dp)
    624 {
    625     return bsddb_seq(dp, R_LAST);
    626 }
    627 static PyObject *
    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 *
    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 *
    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 *
    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 *
    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
    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