Staging
v0.5.1
v0.5.1
https://github.com/python/cpython
Tip revision: 74f4bd53e03ded8408bcc2de67cf0f5a4ac5b1a1 authored by Barry Warsaw on 23 February 2012, 15:59:38 UTC
Bump some more copyright years (as per PEP 101), since this is the first
Bump some more copyright years (as per PEP 101), since this is the first
Tip revision: 74f4bd5
dbmmodule.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";
#elif defined(HAVE_GDBM_DASH_NDBM_H)
#include <gdbm-ndbm.h>
static char *which_dbm = "GNU gdbm";
#elif defined(HAVE_BERKDB_H)
#include <db.h>
static char *which_dbm = "Berkeley DB";
#else
#error "No ndbm.h available!"
#endif
typedef struct {
PyObject_HEAD
int di_size; /* -1 means recompute */
DBM *di_dbm;
} dbmobject;
static PyTypeObject Dbmtype;
#define is_dbmobject(v) (Py_TYPE(v) == &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 Py_ssize_t
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;
int tmp_size;
if (!PyArg_Parse(key, "s#", &krec.dptr, &tmp_size) )
return NULL;
krec.dsize = tmp_size;
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;
int tmp_size;
if ( !PyArg_Parse(v, "s#", &krec.dptr, &tmp_size) ) {
PyErr_SetString(PyExc_TypeError,
"dbm mappings have string indices only");
return -1;
}
krec.dsize = tmp_size;
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, &tmp_size) ) {
PyErr_SetString(PyExc_TypeError,
"dbm mappings have string elements only");
return -1;
}
drec.dsize = tmp_size;
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 int
dbm_contains(register dbmobject *dp, PyObject *v)
{
datum key, val;
if (PyString_AsStringAndSize(v, (char **)&key.dptr,
(Py_ssize_t *)&key.dsize)) {
return -1;
}
/* Expand check_dbmobject_open to return -1 */
if (dp->di_dbm == NULL) {
PyErr_SetString(DbmError, "DBM object has already been closed");
return -1;
}
val = dbm_fetch(dp->di_dbm, key);
return val.dptr != NULL;
}
static PySequenceMethods dbm_as_sequence = {
(lenfunc)dbm_length, /*_length*/
0, /*sq_concat*/
0, /*sq_repeat*/
0, /*sq_item*/
0, /*sq_slice*/
0, /*sq_ass_item*/
0, /*sq_ass_slice*/
(objobjproc)dbm_contains, /*sq_contains*/
0, /*sq_inplace_concat*/
0 /*sq_inplace_repeat*/
};
static PyMappingMethods dbm_as_mapping = {
(lenfunc)dbm_length, /*mp_length*/
(binaryfunc)dbm_subscript, /*mp_subscript*/
(objobjargproc)dbm_ass_sub, /*mp_ass_subscript*/
};
static PyObject *
dbm__close(register dbmobject *dp, PyObject *unused)
{
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 *unused)
{
register PyObject *v, *item;
datum key;
int err;
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)
{
char *tmp_ptr;
datum key, val;
int tmp_size;
if (!PyArg_ParseTuple(args, "s#:has_key", &tmp_ptr, &tmp_size))
return NULL;
key.dptr = tmp_ptr;
key.dsize = tmp_size;
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;
char *tmp_ptr;
int tmp_size;
if (!PyArg_ParseTuple(args, "s#|O:get",
&tmp_ptr, &tmp_size, &defvalue))
return NULL;
key.dptr = tmp_ptr;
key.dsize = tmp_size;
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;
char *tmp_ptr;
int tmp_size;
if (!PyArg_ParseTuple(args, "s#|S:setdefault",
&tmp_ptr, &tmp_size, &defvalue))
return NULL;
key.dptr = tmp_ptr;
key.dsize = tmp_size;
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_NOARGS,
"close()\nClose the database."},
{"keys", (PyCFunction)dbm_keys, METH_NOARGS,
"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 = {
PyVarObject_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*/
&dbm_as_sequence, /*tp_as_sequence*/
&dbm_as_mapping, /*tp_as_mapping*/
0, /*tp_hash*/
0, /*tp_call*/
0, /*tp_str*/
0, /*tp_getattro*/
0, /*tp_setattro*/
0, /*tp_as_buffer*/
Py_TPFLAGS_DEFAULT, /*tp_xxx4*/
};
/* ----------------------------------------------------------------- */
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 },
};
PyMODINIT_FUNC
initdbm(void) {
PyObject *m, *d, *s;
Dbmtype.ob_type = &PyType_Type;
m = Py_InitModule("dbm", dbmmodule_methods);
if (m == NULL)
return;
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);
}