mirror of
https://github.com/python/cpython.git
synced 2025-07-31 07:04:42 +00:00

library. Since multiple versions can be installed simultaneously, it's crucial that you only select libraries and header files which are compatible with each other. Version checking is done from highest version to lowest. Building using version 1 of Berkeley DB is disabled by default because of the hash file bugs people keep rediscovering. It can be enabled by uncommenting a few lines in setup.py. Closes patch 553108.
358 lines
8.5 KiB
C
358 lines
8.5 KiB
C
|
|
/* DBM module using dictionary interface */
|
|
|
|
|
|
#include "Python.h"
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <fcntl.h>
|
|
|
|
/* Some Linux systems install gdbm/ndbm.h, but not ndbm.h. This supports
|
|
* whichever configure was able to locate.
|
|
*/
|
|
#if defined(HAVE_NDBM_H)
|
|
#include <ndbm.h>
|
|
#if defined(PYOS_OS2) && !defined(PYCC_GCC)
|
|
static char *which_dbm = "ndbm";
|
|
#else
|
|
static char *which_dbm = "GNU gdbm"; /* EMX port of GDBM */
|
|
#endif
|
|
#elif defined(HAVE_GDBM_NDBM_H)
|
|
#include <gdbm/ndbm.h>
|
|
static char *which_dbm = "GNU gdbm";
|
|
#else
|
|
#error "No ndbm.h available!"
|
|
#endif
|
|
|
|
typedef struct {
|
|
PyObject_HEAD
|
|
int di_size; /* -1 means recompute */
|
|
DBM *di_dbm;
|
|
} dbmobject;
|
|
|
|
staticforward PyTypeObject Dbmtype;
|
|
|
|
#define is_dbmobject(v) ((v)->ob_type == &Dbmtype)
|
|
#define check_dbmobject_open(v) if ((v)->di_dbm == NULL) \
|
|
{ PyErr_SetString(DbmError, "DBM object has already been closed"); \
|
|
return NULL; }
|
|
|
|
static PyObject *DbmError;
|
|
|
|
static PyObject *
|
|
newdbmobject(char *file, int flags, int mode)
|
|
{
|
|
dbmobject *dp;
|
|
|
|
dp = PyObject_New(dbmobject, &Dbmtype);
|
|
if (dp == NULL)
|
|
return NULL;
|
|
dp->di_size = -1;
|
|
if ( (dp->di_dbm = dbm_open(file, flags, mode)) == 0 ) {
|
|
PyErr_SetFromErrno(DbmError);
|
|
Py_DECREF(dp);
|
|
return NULL;
|
|
}
|
|
return (PyObject *)dp;
|
|
}
|
|
|
|
/* Methods */
|
|
|
|
static void
|
|
dbm_dealloc(register dbmobject *dp)
|
|
{
|
|
if ( dp->di_dbm )
|
|
dbm_close(dp->di_dbm);
|
|
PyObject_Del(dp);
|
|
}
|
|
|
|
static int
|
|
dbm_length(dbmobject *dp)
|
|
{
|
|
if (dp->di_dbm == NULL) {
|
|
PyErr_SetString(DbmError, "DBM object has already been closed");
|
|
return -1;
|
|
}
|
|
if ( dp->di_size < 0 ) {
|
|
datum key;
|
|
int size;
|
|
|
|
size = 0;
|
|
for ( key=dbm_firstkey(dp->di_dbm); key.dptr;
|
|
key = dbm_nextkey(dp->di_dbm))
|
|
size++;
|
|
dp->di_size = size;
|
|
}
|
|
return dp->di_size;
|
|
}
|
|
|
|
static PyObject *
|
|
dbm_subscript(dbmobject *dp, register PyObject *key)
|
|
{
|
|
datum drec, krec;
|
|
|
|
if (!PyArg_Parse(key, "s#", &krec.dptr, &krec.dsize) )
|
|
return NULL;
|
|
|
|
check_dbmobject_open(dp);
|
|
drec = dbm_fetch(dp->di_dbm, krec);
|
|
if ( drec.dptr == 0 ) {
|
|
PyErr_SetString(PyExc_KeyError,
|
|
PyString_AS_STRING((PyStringObject *)key));
|
|
return NULL;
|
|
}
|
|
if ( dbm_error(dp->di_dbm) ) {
|
|
dbm_clearerr(dp->di_dbm);
|
|
PyErr_SetString(DbmError, "");
|
|
return NULL;
|
|
}
|
|
return PyString_FromStringAndSize(drec.dptr, drec.dsize);
|
|
}
|
|
|
|
static int
|
|
dbm_ass_sub(dbmobject *dp, PyObject *v, PyObject *w)
|
|
{
|
|
datum krec, drec;
|
|
|
|
if ( !PyArg_Parse(v, "s#", &krec.dptr, &krec.dsize) ) {
|
|
PyErr_SetString(PyExc_TypeError,
|
|
"dbm mappings have string indices only");
|
|
return -1;
|
|
}
|
|
if (dp->di_dbm == NULL) {
|
|
PyErr_SetString(DbmError, "DBM object has already been closed");
|
|
return -1;
|
|
}
|
|
dp->di_size = -1;
|
|
if (w == NULL) {
|
|
if ( dbm_delete(dp->di_dbm, krec) < 0 ) {
|
|
dbm_clearerr(dp->di_dbm);
|
|
PyErr_SetString(PyExc_KeyError,
|
|
PyString_AS_STRING((PyStringObject *)v));
|
|
return -1;
|
|
}
|
|
} else {
|
|
if ( !PyArg_Parse(w, "s#", &drec.dptr, &drec.dsize) ) {
|
|
PyErr_SetString(PyExc_TypeError,
|
|
"dbm mappings have string elements only");
|
|
return -1;
|
|
}
|
|
if ( dbm_store(dp->di_dbm, krec, drec, DBM_REPLACE) < 0 ) {
|
|
dbm_clearerr(dp->di_dbm);
|
|
PyErr_SetString(DbmError,
|
|
"cannot add item to database");
|
|
return -1;
|
|
}
|
|
}
|
|
if ( dbm_error(dp->di_dbm) ) {
|
|
dbm_clearerr(dp->di_dbm);
|
|
PyErr_SetString(DbmError, "");
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static PyMappingMethods dbm_as_mapping = {
|
|
(inquiry)dbm_length, /*mp_length*/
|
|
(binaryfunc)dbm_subscript, /*mp_subscript*/
|
|
(objobjargproc)dbm_ass_sub, /*mp_ass_subscript*/
|
|
};
|
|
|
|
static PyObject *
|
|
dbm__close(register dbmobject *dp, PyObject *args)
|
|
{
|
|
if (!PyArg_ParseTuple(args, ":close"))
|
|
return NULL;
|
|
if (dp->di_dbm)
|
|
dbm_close(dp->di_dbm);
|
|
dp->di_dbm = NULL;
|
|
Py_INCREF(Py_None);
|
|
return Py_None;
|
|
}
|
|
|
|
static PyObject *
|
|
dbm_keys(register dbmobject *dp, PyObject *args)
|
|
{
|
|
register PyObject *v, *item;
|
|
datum key;
|
|
int err;
|
|
|
|
if (!PyArg_ParseTuple(args, ":keys"))
|
|
return NULL;
|
|
check_dbmobject_open(dp);
|
|
v = PyList_New(0);
|
|
if (v == NULL)
|
|
return NULL;
|
|
for (key = dbm_firstkey(dp->di_dbm); key.dptr;
|
|
key = dbm_nextkey(dp->di_dbm)) {
|
|
item = PyString_FromStringAndSize(key.dptr, key.dsize);
|
|
if (item == NULL) {
|
|
Py_DECREF(v);
|
|
return NULL;
|
|
}
|
|
err = PyList_Append(v, item);
|
|
Py_DECREF(item);
|
|
if (err != 0) {
|
|
Py_DECREF(v);
|
|
return NULL;
|
|
}
|
|
}
|
|
return v;
|
|
}
|
|
|
|
static PyObject *
|
|
dbm_has_key(register dbmobject *dp, PyObject *args)
|
|
{
|
|
datum key, val;
|
|
|
|
if (!PyArg_ParseTuple(args, "s#:has_key", &key.dptr, &key.dsize))
|
|
return NULL;
|
|
check_dbmobject_open(dp);
|
|
val = dbm_fetch(dp->di_dbm, key);
|
|
return PyInt_FromLong(val.dptr != NULL);
|
|
}
|
|
|
|
static PyObject *
|
|
dbm_get(register dbmobject *dp, PyObject *args)
|
|
{
|
|
datum key, val;
|
|
PyObject *defvalue = Py_None;
|
|
|
|
if (!PyArg_ParseTuple(args, "s#|O:get",
|
|
&key.dptr, &key.dsize, &defvalue))
|
|
return NULL;
|
|
check_dbmobject_open(dp);
|
|
val = dbm_fetch(dp->di_dbm, key);
|
|
if (val.dptr != NULL)
|
|
return PyString_FromStringAndSize(val.dptr, val.dsize);
|
|
else {
|
|
Py_INCREF(defvalue);
|
|
return defvalue;
|
|
}
|
|
}
|
|
|
|
static PyObject *
|
|
dbm_setdefault(register dbmobject *dp, PyObject *args)
|
|
{
|
|
datum key, val;
|
|
PyObject *defvalue = NULL;
|
|
|
|
if (!PyArg_ParseTuple(args, "s#|S:setdefault",
|
|
&key.dptr, &key.dsize, &defvalue))
|
|
return NULL;
|
|
check_dbmobject_open(dp);
|
|
val = dbm_fetch(dp->di_dbm, key);
|
|
if (val.dptr != NULL)
|
|
return PyString_FromStringAndSize(val.dptr, val.dsize);
|
|
if (defvalue == NULL) {
|
|
defvalue = PyString_FromStringAndSize(NULL, 0);
|
|
if (defvalue == NULL)
|
|
return NULL;
|
|
}
|
|
else
|
|
Py_INCREF(defvalue);
|
|
val.dptr = PyString_AS_STRING(defvalue);
|
|
val.dsize = PyString_GET_SIZE(defvalue);
|
|
if (dbm_store(dp->di_dbm, key, val, DBM_INSERT) < 0) {
|
|
dbm_clearerr(dp->di_dbm);
|
|
PyErr_SetString(DbmError, "cannot add item to database");
|
|
return NULL;
|
|
}
|
|
return defvalue;
|
|
}
|
|
|
|
static PyMethodDef dbm_methods[] = {
|
|
{"close", (PyCFunction)dbm__close, METH_VARARGS,
|
|
"close()\nClose the database."},
|
|
{"keys", (PyCFunction)dbm_keys, METH_VARARGS,
|
|
"keys() -> list\nReturn a list of all keys in the database."},
|
|
{"has_key", (PyCFunction)dbm_has_key, METH_VARARGS,
|
|
"has_key(key} -> boolean\nReturn true iff key is in the database."},
|
|
{"get", (PyCFunction)dbm_get, METH_VARARGS,
|
|
"get(key[, default]) -> value\n"
|
|
"Return the value for key if present, otherwise default."},
|
|
{"setdefault", (PyCFunction)dbm_setdefault, METH_VARARGS,
|
|
"setdefault(key[, default]) -> value\n"
|
|
"Return the value for key if present, otherwise default. If key\n"
|
|
"is not in the database, it is inserted with default as the value."},
|
|
{NULL, NULL} /* sentinel */
|
|
};
|
|
|
|
static PyObject *
|
|
dbm_getattr(dbmobject *dp, char *name)
|
|
{
|
|
return Py_FindMethod(dbm_methods, (PyObject *)dp, name);
|
|
}
|
|
|
|
static PyTypeObject Dbmtype = {
|
|
PyObject_HEAD_INIT(NULL)
|
|
0,
|
|
"dbm.dbm",
|
|
sizeof(dbmobject),
|
|
0,
|
|
(destructor)dbm_dealloc, /*tp_dealloc*/
|
|
0, /*tp_print*/
|
|
(getattrfunc)dbm_getattr, /*tp_getattr*/
|
|
0, /*tp_setattr*/
|
|
0, /*tp_compare*/
|
|
0, /*tp_repr*/
|
|
0, /*tp_as_number*/
|
|
0, /*tp_as_sequence*/
|
|
&dbm_as_mapping, /*tp_as_mapping*/
|
|
};
|
|
|
|
/* ----------------------------------------------------------------- */
|
|
|
|
static PyObject *
|
|
dbmopen(PyObject *self, PyObject *args)
|
|
{
|
|
char *name;
|
|
char *flags = "r";
|
|
int iflags;
|
|
int mode = 0666;
|
|
|
|
if ( !PyArg_ParseTuple(args, "s|si:open", &name, &flags, &mode) )
|
|
return NULL;
|
|
if ( strcmp(flags, "r") == 0 )
|
|
iflags = O_RDONLY;
|
|
else if ( strcmp(flags, "w") == 0 )
|
|
iflags = O_RDWR;
|
|
else if ( strcmp(flags, "rw") == 0 ) /* B/W compat */
|
|
iflags = O_RDWR|O_CREAT;
|
|
else if ( strcmp(flags, "c") == 0 )
|
|
iflags = O_RDWR|O_CREAT;
|
|
else if ( strcmp(flags, "n") == 0 )
|
|
iflags = O_RDWR|O_CREAT|O_TRUNC;
|
|
else {
|
|
PyErr_SetString(DbmError,
|
|
"arg 2 to open should be 'r', 'w', 'c', or 'n'");
|
|
return NULL;
|
|
}
|
|
return newdbmobject(name, iflags, mode);
|
|
}
|
|
|
|
static PyMethodDef dbmmodule_methods[] = {
|
|
{ "open", (PyCFunction)dbmopen, METH_VARARGS,
|
|
"open(path[, flag[, mode]]) -> mapping\n"
|
|
"Return a database object."},
|
|
{ 0, 0 },
|
|
};
|
|
|
|
DL_EXPORT(void)
|
|
initdbm(void) {
|
|
PyObject *m, *d, *s;
|
|
|
|
Dbmtype.ob_type = &PyType_Type;
|
|
m = Py_InitModule("dbm", dbmmodule_methods);
|
|
d = PyModule_GetDict(m);
|
|
if (DbmError == NULL)
|
|
DbmError = PyErr_NewException("dbm.error", NULL, NULL);
|
|
s = PyString_FromString(which_dbm);
|
|
if (s != NULL) {
|
|
PyDict_SetItemString(d, "library", s);
|
|
Py_DECREF(s);
|
|
}
|
|
if (DbmError != NULL)
|
|
PyDict_SetItemString(d, "error", DbmError);
|
|
}
|