Splits Modules/_bsddb.c up into bsddb.h and _bsddb.c and adds a C API
object available as bsddb.db.api.  This is based on the patch submitted
by Duncan Grisby here:
  http://sourceforge.net/tracker/index.php?func=detail&aid=1551895&group_id=13900&atid=313900
See this thread for additional info:
  http://sourceforge.net/mailarchive/forum.php?thread_name=E1GAVDK-0002rk-Iw%40apasphere.com&forum_name=pybsddb-users

It also cleans up the code a little by removing some ifdef/endifs for
python prior to 2.1 and for unsupported Berkeley DB <= 3.2.
diff --git a/Modules/_bsddb.c b/Modules/_bsddb.c
index 1c57f07..c840eaf 100644
--- a/Modules/_bsddb.c
+++ b/Modules/_bsddb.c
@@ -87,21 +87,16 @@
 
 #include <stddef.h>   /* for offsetof() */
 #include <Python.h>
-#include <db.h>
+
+#define COMPILING_BSDDB_C
+#include "bsddb.h"
+#undef COMPILING_BSDDB_C
+
+static char *rcs_id = "$Id$";
 
 /* --------------------------------------------------------------------- */
 /* Various macro definitions */
 
-/* 40 = 4.0, 33 = 3.3; this will break if the second number is > 9 */
-#define DBVER (DB_VERSION_MAJOR * 10 + DB_VERSION_MINOR)
-#if DB_VERSION_MINOR > 9
-#error "eek! DBVER can't handle minor versions > 9"
-#endif
-
-#define PY_BSDDB_VERSION "4.5.0"
-static char *rcs_id = "$Id$";
-
-
 #if (PY_VERSION_HEX < 0x02050000)
 typedef int Py_ssize_t;
 #endif
@@ -196,107 +191,15 @@
 /* --------------------------------------------------------------------- */
 /* Structure definitions */
 
-#if PYTHON_API_VERSION >= 1010       /* python >= 2.1 support weak references */
-#define HAVE_WEAKREF
-#else
-#undef HAVE_WEAKREF
+#if PYTHON_API_VERSION < 1010
+#error "Python 2.1 or later required"
 #endif
 
-/* if Python >= 2.1 better support warnings */
-#if PYTHON_API_VERSION >= 1010
-#define HAVE_WARNINGS
-#else
-#undef HAVE_WARNINGS
-#endif
 
-#if PYTHON_API_VERSION <= 1007
-    /* 1.5 compatibility */
-#define PyObject_New PyObject_NEW
-#define PyObject_Del PyMem_DEL
-#endif
-
-struct behaviourFlags {
-    /* What is the default behaviour when DB->get or DBCursor->get returns a
-       DB_NOTFOUND || DB_KEYEMPTY error?  Return None or raise an exception? */
-    unsigned int getReturnsNone : 1;
-    /* What is the default behaviour for DBCursor.set* methods when DBCursor->get
-     * returns a DB_NOTFOUND || DB_KEYEMPTY  error?  Return None or raise? */
-    unsigned int cursorSetReturnsNone : 1;
-};
-
+/* Defaults for moduleFlags in DBEnvObject and DBObject. */
 #define DEFAULT_GET_RETURNS_NONE                1
 #define DEFAULT_CURSOR_SET_RETURNS_NONE         1   /* 0 in pybsddb < 4.2, python < 2.4 */
 
-typedef struct {
-    PyObject_HEAD
-    DB_ENV*     db_env;
-    u_int32_t   flags;             /* saved flags from open() */
-    int         closed;
-    struct behaviourFlags moduleFlags;
-#ifdef HAVE_WEAKREF
-    PyObject        *in_weakreflist; /* List of weak references */
-#endif
-} DBEnvObject;
-
-
-typedef struct {
-    PyObject_HEAD
-    DB*             db;
-    DBEnvObject*    myenvobj;  /* PyObject containing the DB_ENV */
-    u_int32_t       flags;     /* saved flags from open() */
-    u_int32_t       setflags;  /* saved flags from set_flags() */
-    int             haveStat;
-    struct behaviourFlags moduleFlags;
-#if (DBVER >= 33)
-    PyObject*       associateCallback;
-    PyObject*       btCompareCallback;
-    int             primaryDBType;
-#endif
-#ifdef HAVE_WEAKREF
-    PyObject        *in_weakreflist; /* List of weak references */
-#endif
-} DBObject;
-
-
-typedef struct {
-    PyObject_HEAD
-    DBC*            dbc;
-    DBObject*       mydb;
-#ifdef HAVE_WEAKREF
-    PyObject        *in_weakreflist; /* List of weak references */
-#endif
-} DBCursorObject;
-
-
-typedef struct {
-    PyObject_HEAD
-    DB_TXN*         txn;
-    PyObject        *env;
-#ifdef HAVE_WEAKREF
-    PyObject        *in_weakreflist; /* List of weak references */
-#endif
-} DBTxnObject;
-
-
-typedef struct {
-    PyObject_HEAD
-    DB_LOCK         lock;
-#ifdef HAVE_WEAKREF
-    PyObject        *in_weakreflist; /* List of weak references */
-#endif
-} DBLockObject;
-
-#if (DBVER >= 43)
-typedef struct {
-    PyObject_HEAD
-    DB_SEQUENCE*     sequence;
-    DBObject*        mydb;
-#ifdef HAVE_WEAKREF
-    PyObject        *in_weakreflist; /* List of weak references */
-#endif
-} DBSequenceObject;
-staticforward PyTypeObject DBSequence_Type;
-#endif
 
 staticforward PyTypeObject DB_Type, DBCursor_Type, DBEnv_Type, DBTxn_Type, DBLock_Type;
 
@@ -545,12 +448,7 @@
                 strncat(errTxt, _db_errmsg, bytes_left);
             }
             _db_errmsg[0] = 0;
-#ifdef HAVE_WARNINGS
             exceptionRaised = PyErr_Warn(PyExc_RuntimeWarning, errTxt);
-#else
-            fprintf(stderr, errTxt);
-            fprintf(stderr, "\n");
-#endif
 
 #else  /* do an exception instead */
         errObj = DBIncompleteError;
@@ -804,9 +702,7 @@
     self->btCompareCallback = NULL;
     self->primaryDBType = 0;
 #endif
-#ifdef HAVE_WEAKREF
     self->in_weakreflist = NULL;
-#endif
 
     /* keep a reference to our python DBEnv object */
     if (arg) {
@@ -857,19 +753,15 @@
             MYDB_BEGIN_ALLOW_THREADS;
             self->db->close(self->db, 0);
             MYDB_END_ALLOW_THREADS;
-#ifdef HAVE_WARNINGS
         } else {
             PyErr_Warn(PyExc_RuntimeWarning,
                 "DB could not be closed in destructor: DBEnv already closed");
-#endif
         }
         self->db = NULL;
     }
-#ifdef HAVE_WEAKREF
     if (self->in_weakreflist != NULL) {
         PyObject_ClearWeakRefs((PyObject *) self);
     }
-#endif
     if (self->myenvobj) {
         Py_DECREF(self->myenvobj);
         self->myenvobj = NULL;
@@ -897,9 +789,7 @@
 
     self->dbc = dbc;
     self->mydb = db;
-#ifdef HAVE_WEAKREF
     self->in_weakreflist = NULL;
-#endif
     Py_INCREF(self->mydb);
     return self;
 }
@@ -910,11 +800,9 @@
 {
     int err;
 
-#ifdef HAVE_WEAKREF
     if (self->in_weakreflist != NULL) {
         PyObject_ClearWeakRefs((PyObject *) self);
     }
-#endif
 
     if (self->dbc != NULL) {
         MYDB_BEGIN_ALLOW_THREADS;
@@ -947,9 +835,7 @@
     self->flags = flags;
     self->moduleFlags.getReturnsNone = DEFAULT_GET_RETURNS_NONE;
     self->moduleFlags.cursorSetReturnsNone = DEFAULT_CURSOR_SET_RETURNS_NONE;
-#ifdef HAVE_WEAKREF
     self->in_weakreflist = NULL;
-#endif
 
     MYDB_BEGIN_ALLOW_THREADS;
     err = db_env_create(&self->db_env, flags);
@@ -968,11 +854,9 @@
 static void
 DBEnv_dealloc(DBEnvObject* self)
 {
-#ifdef HAVE_WEAKREF
     if (self->in_weakreflist != NULL) {
         PyObject_ClearWeakRefs((PyObject *) self);
     }
-#endif
 
     if (self->db_env && !self->closed) {
         MYDB_BEGIN_ALLOW_THREADS;
@@ -992,9 +876,7 @@
         return NULL;
     Py_INCREF(myenv);
     self->env = (PyObject*)myenv;
-#ifdef HAVE_WEAKREF
     self->in_weakreflist = NULL;
-#endif
 
     MYDB_BEGIN_ALLOW_THREADS;
 #if (DBVER >= 40)
@@ -1015,13 +897,10 @@
 static void
 DBTxn_dealloc(DBTxnObject* self)
 {
-#ifdef HAVE_WEAKREF
     if (self->in_weakreflist != NULL) {
         PyObject_ClearWeakRefs((PyObject *) self);
     }
-#endif
 
-#ifdef HAVE_WARNINGS
     if (self->txn) {
         /* it hasn't been finalized, abort it! */
         MYDB_BEGIN_ALLOW_THREADS;
@@ -1034,7 +913,6 @@
         PyErr_Warn(PyExc_RuntimeWarning,
             "DBTxn aborted in destructor.  No prior commit() or abort().");
     }
-#endif
 
     Py_DECREF(self->env);
     PyObject_Del(self);
@@ -1049,9 +927,7 @@
     DBLockObject* self = PyObject_New(DBLockObject, &DBLock_Type);
     if (self == NULL)
         return NULL;
-#ifdef HAVE_WEAKREF
     self->in_weakreflist = NULL;
-#endif
 
     MYDB_BEGIN_ALLOW_THREADS;
 #if (DBVER >= 40)
@@ -1073,11 +949,9 @@
 static void
 DBLock_dealloc(DBLockObject* self)
 {
-#ifdef HAVE_WEAKREF
     if (self->in_weakreflist != NULL) {
         PyObject_ClearWeakRefs((PyObject *) self);
     }
-#endif
     /* TODO: is this lock held? should we release it? */
 
     PyObject_Del(self);
@@ -1094,9 +968,7 @@
         return NULL;
     Py_INCREF(mydb);
     self->mydb = mydb;
-#ifdef HAVE_WEAKREF
     self->in_weakreflist = NULL;
-#endif
 
 
     MYDB_BEGIN_ALLOW_THREADS;
@@ -1115,11 +987,9 @@
 static void
 DBSequence_dealloc(DBSequenceObject* self)
 {
-#ifdef HAVE_WEAKREF
     if (self->in_weakreflist != NULL) {
         PyObject_ClearWeakRefs((PyObject *) self);
     }
-#endif
 
     Py_DECREF(self->mydb);
     PyObject_Del(self);
@@ -1201,13 +1071,7 @@
             Py_ssize_t size;
 
             CLEAR_DBT(*secKey);
-#if PYTHON_API_VERSION <= 1007
-            /* 1.5 compatibility */
-            size = PyString_Size(result);
-            data = PyString_AsString(result);
-#else
             PyString_AsStringAndSize(result, &data, &size);
-#endif
             secKey->flags = DB_DBT_APPMALLOC;   /* DB will free */
             secKey->data = malloc(size);        /* TODO, check this */
 	    if (secKey->data) {
@@ -1346,7 +1210,6 @@
 }
 
 
-#if (DBVER >= 32)
 static PyObject*
 _DB_consume(DBObject* self, PyObject* args, PyObject* kwargs, int consume_flag)
 {
@@ -1414,8 +1277,6 @@
 {
     return _DB_consume(self, args, kwargs, DB_CONSUME_WAIT);
 }
-#endif
-
 
 
 static PyObject*
@@ -2423,7 +2284,6 @@
 }
 
 
-#if (DBVER >= 32)
 static PyObject*
 DB_set_q_extentsize(DBObject* self, PyObject* args)
 {
@@ -2440,7 +2300,6 @@
     RETURN_IF_ERR();
     RETURN_NONE();
 }
-#endif
 
 static PyObject*
 DB_stat(DBObject* self, PyObject* args, PyObject* kwargs)
@@ -4025,7 +3884,6 @@
 }
 
 
-#if (DBVER >= 32)
 static PyObject*
 DBEnv_set_flags(DBEnvObject* self, PyObject* args)
 {
@@ -4042,7 +3900,6 @@
     RETURN_IF_ERR();
     RETURN_NONE();
 }
-#endif
 
 
 static PyObject*
@@ -4169,7 +4026,6 @@
 #endif
 
 
-#if (DBVER >= 32)
 
 static PyObject*
 DBEnv_set_lk_max_locks(DBEnvObject* self, PyObject* args)
@@ -4221,8 +4077,6 @@
     RETURN_NONE();
 }
 
-#endif
-
 
 static PyObject*
 DBEnv_set_mp_mmapsize(DBEnvObject* self, PyObject* args)
@@ -4543,19 +4397,15 @@
     MAKE_ENTRY(lastid);
 #endif
     MAKE_ENTRY(nmodes);
-#if (DBVER >= 32)
     MAKE_ENTRY(maxlocks);
     MAKE_ENTRY(maxlockers);
     MAKE_ENTRY(maxobjects);
     MAKE_ENTRY(nlocks);
     MAKE_ENTRY(maxnlocks);
-#endif
     MAKE_ENTRY(nlockers);
     MAKE_ENTRY(maxnlockers);
-#if (DBVER >= 32)
     MAKE_ENTRY(nobjects);
     MAKE_ENTRY(maxnobjects);
-#endif
     MAKE_ENTRY(nrequests);
     MAKE_ENTRY(nreleases);
 #if (DBVER < 44)
@@ -5143,10 +4993,8 @@
     {"associate",       (PyCFunction)DB_associate,      METH_VARARGS|METH_KEYWORDS},
 #endif
     {"close",           (PyCFunction)DB_close,          METH_VARARGS},
-#if (DBVER >= 32)
     {"consume",         (PyCFunction)DB_consume,        METH_VARARGS|METH_KEYWORDS},
     {"consume_wait",    (PyCFunction)DB_consume_wait,   METH_VARARGS|METH_KEYWORDS},
-#endif
     {"cursor",          (PyCFunction)DB_cursor,         METH_VARARGS|METH_KEYWORDS},
     {"delete",          (PyCFunction)DB_delete,         METH_VARARGS|METH_KEYWORDS},
     {"fd",              (PyCFunction)DB_fd,             METH_VARARGS},
@@ -5184,9 +5032,7 @@
     {"set_re_len",      (PyCFunction)DB_set_re_len,     METH_VARARGS},
     {"set_re_pad",      (PyCFunction)DB_set_re_pad,     METH_VARARGS},
     {"set_re_source",   (PyCFunction)DB_set_re_source,  METH_VARARGS},
-#if (DBVER >= 32)
     {"set_q_extentsize",(PyCFunction)DB_set_q_extentsize,METH_VARARGS},
-#endif
     {"stat",            (PyCFunction)DB_stat,           METH_VARARGS|METH_KEYWORDS},
     {"sync",            (PyCFunction)DB_sync,           METH_VARARGS},
 #if (DBVER >= 33)
@@ -5254,9 +5100,7 @@
     {"set_shm_key",     (PyCFunction)DBEnv_set_shm_key,      METH_VARARGS},
     {"set_cachesize",   (PyCFunction)DBEnv_set_cachesize,    METH_VARARGS},
     {"set_data_dir",    (PyCFunction)DBEnv_set_data_dir,     METH_VARARGS},
-#if (DBVER >= 32)
     {"set_flags",       (PyCFunction)DBEnv_set_flags,        METH_VARARGS},
-#endif
     {"set_lg_bsize",    (PyCFunction)DBEnv_set_lg_bsize,     METH_VARARGS},
     {"set_lg_dir",      (PyCFunction)DBEnv_set_lg_dir,       METH_VARARGS},
     {"set_lg_max",      (PyCFunction)DBEnv_set_lg_max,       METH_VARARGS},
@@ -5267,11 +5111,9 @@
 #if (DBVER < 45)
     {"set_lk_max",      (PyCFunction)DBEnv_set_lk_max,       METH_VARARGS},
 #endif
-#if (DBVER >= 32)
     {"set_lk_max_locks", (PyCFunction)DBEnv_set_lk_max_locks, METH_VARARGS},
     {"set_lk_max_lockers", (PyCFunction)DBEnv_set_lk_max_lockers, METH_VARARGS},
     {"set_lk_max_objects", (PyCFunction)DBEnv_set_lk_max_objects, METH_VARARGS},
-#endif
     {"set_mp_mmapsize", (PyCFunction)DBEnv_set_mp_mmapsize,  METH_VARARGS},
     {"set_tmp_dir",     (PyCFunction)DBEnv_set_tmp_dir,      METH_VARARGS},
     {"txn_begin",       (PyCFunction)DBEnv_txn_begin,        METH_VARARGS|METH_KEYWORDS},
@@ -5391,7 +5233,6 @@
     0,          /*tp_as_sequence*/
     &DB_mapping,/*tp_as_mapping*/
     0,          /*tp_hash*/
-#ifdef HAVE_WEAKREF
     0,			/* tp_call */
     0,			/* tp_str */
     0,  		/* tp_getattro */
@@ -5403,7 +5244,6 @@
     0,			/* tp_clear */
     0,			/* tp_richcompare */
     offsetof(DBObject, in_weakreflist),   /* tp_weaklistoffset */
-#endif
 };
 
 
@@ -5424,7 +5264,6 @@
     0,                  /*tp_as_sequence*/
     0,                  /*tp_as_mapping*/
     0,                  /*tp_hash*/
-#ifdef HAVE_WEAKREF
     0,			/* tp_call */
     0,			/* tp_str */
     0,  		/* tp_getattro */
@@ -5436,7 +5275,6 @@
     0,			/* tp_clear */
     0,			/* tp_richcompare */
     offsetof(DBCursorObject, in_weakreflist),   /* tp_weaklistoffset */
-#endif
 };
 
 
@@ -5457,7 +5295,6 @@
     0,          /*tp_as_sequence*/
     0,          /*tp_as_mapping*/
     0,          /*tp_hash*/
-#ifdef HAVE_WEAKREF
     0,			/* tp_call */
     0,			/* tp_str */
     0,  		/* tp_getattro */
@@ -5469,7 +5306,6 @@
     0,			/* tp_clear */
     0,			/* tp_richcompare */
     offsetof(DBEnvObject, in_weakreflist),   /* tp_weaklistoffset */
-#endif
 };
 
 statichere PyTypeObject DBTxn_Type = {
@@ -5489,7 +5325,6 @@
     0,          /*tp_as_sequence*/
     0,          /*tp_as_mapping*/
     0,          /*tp_hash*/
-#ifdef HAVE_WEAKREF
     0,			/* tp_call */
     0,			/* tp_str */
     0,  		/* tp_getattro */
@@ -5501,7 +5336,6 @@
     0,			/* tp_clear */
     0,			/* tp_richcompare */
     offsetof(DBTxnObject, in_weakreflist),   /* tp_weaklistoffset */
-#endif
 };
 
 
@@ -5522,7 +5356,6 @@
     0,          /*tp_as_sequence*/
     0,          /*tp_as_mapping*/
     0,          /*tp_hash*/
-#ifdef HAVE_WEAKREF
     0,			/* tp_call */
     0,			/* tp_str */
     0,  		/* tp_getattro */
@@ -5534,7 +5367,6 @@
     0,			/* tp_clear */
     0,			/* tp_richcompare */
     offsetof(DBLockObject, in_weakreflist),   /* tp_weaklistoffset */
-#endif
 };
 
 #if (DBVER >= 43)
@@ -5555,7 +5387,6 @@
     0,          /*tp_as_sequence*/
     0,          /*tp_as_mapping*/
     0,          /*tp_hash*/
-#ifdef HAVE_WEAKREF
     0,			/* tp_call */
     0,			/* tp_str */
     0,  		/* tp_getattro */
@@ -5567,7 +5398,6 @@
     0,			/* tp_clear */
     0,			/* tp_richcompare */
     offsetof(DBSequenceObject, in_weakreflist),   /* tp_weaklistoffset */
-#endif
 };
 #endif
 
@@ -5649,6 +5479,9 @@
     {NULL,      NULL}       /* sentinel */
 };
 
+/* API structure */
+static BSDDB_api bsddb_api;
+
 
 /* --------------------------------------------------------------------- */
 /* Module initialization */
@@ -5669,6 +5502,7 @@
     PyObject* pybsddb_version_s = PyString_FromString( PY_BSDDB_VERSION );
     PyObject* db_version_s = PyString_FromString( DB_VERSION_STRING );
     PyObject* cvsid_s = PyString_FromString( rcs_id );
+    PyObject* py_api;
 
     /* Initialize the type of the new type objects here; doing it here
        is required for portability to Windows without requiring C++. */
@@ -5730,9 +5564,7 @@
     ADD_INT(d, DB_INIT_LOG);
     ADD_INT(d, DB_INIT_MPOOL);
     ADD_INT(d, DB_INIT_TXN);
-#if (DBVER >= 32)
     ADD_INT(d, DB_JOINENV);
-#endif
 
     ADD_INT(d, DB_RECOVER);
     ADD_INT(d, DB_RECOVER_FATAL);
@@ -5753,11 +5585,9 @@
     ADD_INT(d, DB_RDWRMASTER);
     ADD_INT(d, DB_RDONLY);
     ADD_INT(d, DB_TRUNCATE);
-#if (DBVER >= 32)
     ADD_INT(d, DB_EXTENT);
     ADD_INT(d, DB_CDB_ALLDB);
     ADD_INT(d, DB_VERIFY);
-#endif
     ADD_INT(d, DB_UPGRADE);
 
     ADD_INT(d, DB_AGGRESSIVE);
@@ -5801,9 +5631,7 @@
     ADD_INT(d, DB_LOCK_READ);
     ADD_INT(d, DB_LOCK_WRITE);
     ADD_INT(d, DB_LOCK_NOWAIT);
-#if (DBVER >= 32)
     ADD_INT(d, DB_LOCK_WAIT);
-#endif
     ADD_INT(d, DB_LOCK_IWRITE);
     ADD_INT(d, DB_LOCK_IREAD);
     ADD_INT(d, DB_LOCK_IWR);
@@ -5818,9 +5646,7 @@
 
     ADD_INT(d, DB_LOCK_RECORD);
     ADD_INT(d, DB_LOCK_UPGRADE);
-#if (DBVER >= 32)
     ADD_INT(d, DB_LOCK_SWITCH);
-#endif
 #if (DBVER >= 33)
     ADD_INT(d, DB_LOCK_UPGRADE_WRITE);
 #endif
@@ -5881,9 +5707,7 @@
     ADD_INT(d, DB_COMMIT);
 #endif
     ADD_INT(d, DB_CONSUME);
-#if (DBVER >= 32)
     ADD_INT(d, DB_CONSUME_WAIT);
-#endif
     ADD_INT(d, DB_CURRENT);
 #if (DBVER >= 33)
     ADD_INT(d, DB_FAST_STAT);
@@ -6061,6 +5885,19 @@
 
 #undef MAKE_EX
 
+    /* Initiliase the C API structure and add it to the module */
+    bsddb_api.db_type         = &DB_Type;
+    bsddb_api.dbcursor_type   = &DBCursor_Type;
+    bsddb_api.dbenv_type      = &DBEnv_Type;
+    bsddb_api.dbtxn_type      = &DBTxn_Type;
+    bsddb_api.dblock_type     = &DBLock_Type;
+    bsddb_api.dbsequence_type = &DBSequence_Type;
+    bsddb_api.makeDBError     = makeDBError;
+
+    py_api = PyCObject_FromVoidPtr((void*)&bsddb_api, NULL);
+    PyDict_SetItemString(d, "api", py_api);
+    Py_DECREF(py_api);
+
     /* Check for errors */
     if (PyErr_Occurred()) {
         PyErr_Print();