dbmmodule.c 7.51 KB
Newer Older
1
/***********************************************************
2 3
Copyright 1991-1995 by Stichting Mathematisch Centrum, Amsterdam,
The Netherlands.
4 5 6

                        All Rights Reserved

7 8
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted,
9
provided that the above copyright notice appear in all copies and that
10
both that copyright notice and this permission notice appear in
11
supporting documentation, and that the names of Stichting Mathematisch
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
Centrum or CWI or Corporation for National Research Initiatives or
CNRI not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior
permission.

While CWI is the initial source for this software, a modified version
is made available by the Corporation for National Research Initiatives
(CNRI) at the Internet address ftp://ftp.python.org.

STICHTING MATHEMATISCH CENTRUM AND CNRI DISCLAIM ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH
CENTRUM OR CNRI BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
29 30 31 32 33 34

******************************************************************/

/* DBM module using dictionary interface */


35
#include "Python.h"
36 37 38 39 40 41 42

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <ndbm.h>

typedef struct {
43
	PyObject_HEAD
44 45 46 47
	int di_size;	/* -1 means recompute */
	DBM *di_dbm;
} dbmobject;

48
staticforward PyTypeObject Dbmtype;
49 50

#define is_dbmobject(v) ((v)->ob_type == &Dbmtype)
51 52 53
#define check_dbmobject_open(v) if ((v)->di_dbm == NULL) \
               { PyErr_SetString(DbmError, "DBM object has already been closed"); \
                 return NULL; }
54

55
static PyObject *DbmError;
56

57
static PyObject *
58
newdbmobject(file, flags, mode)
59 60 61
	char *file;
int flags;
int mode;
62 63 64
{
        dbmobject *dp;

65
	dp = PyObject_NEW(dbmobject, &Dbmtype);
66 67 68 69
	if (dp == NULL)
		return NULL;
	dp->di_size = -1;
	if ( (dp->di_dbm = dbm_open(file, flags, mode)) == 0 ) {
70 71 72
		PyErr_SetFromErrno(DbmError);
		Py_DECREF(dp);
		return NULL;
73
	}
74
	return (PyObject *)dp;
75 76 77 78 79 80 81 82 83
}

/* Methods */

static void
dbm_dealloc(dp)
	register dbmobject *dp;
{
        if ( dp->di_dbm )
84
		dbm_close(dp->di_dbm);
85
	PyMem_DEL(dp);
86 87 88 89 90 91
}

static int
dbm_length(dp)
	dbmobject *dp;
{
92 93 94 95
        if (dp->di_dbm == NULL) {
                 PyErr_SetString(DbmError, "DBM object has already been closed"); 
                 return -1; 
        }
96
        if ( dp->di_size < 0 ) {
97 98 99 100 101 102 103 104
		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;
105 106 107 108
	}
	return dp->di_size;
}

109
static PyObject *
110 111
dbm_subscript(dp, key)
	dbmobject *dp;
112
register PyObject *key;
113 114 115
{
	datum drec, krec;
	
116
	if (!PyArg_Parse(key, "s#", &krec.dptr, &krec.dsize) )
117 118
		return NULL;
	
119
        check_dbmobject_open(dp);
120 121
	drec = dbm_fetch(dp->di_dbm, krec);
	if ( drec.dptr == 0 ) {
122 123 124
		PyErr_SetString(PyExc_KeyError,
				PyString_AS_STRING((PyStringObject *)key));
		return NULL;
125 126
	}
	if ( dbm_error(dp->di_dbm) ) {
127 128 129
		dbm_clearerr(dp->di_dbm);
		PyErr_SetString(DbmError, "");
		return NULL;
130
	}
131
	return PyString_FromStringAndSize(drec.dptr, drec.dsize);
132 133 134 135 136
}

static int
dbm_ass_sub(dp, v, w)
	dbmobject *dp;
137
PyObject *v, *w;
138 139 140
{
        datum krec, drec;
	
141
        if ( !PyArg_Parse(v, "s#", &krec.dptr, &krec.dsize) ) {
142 143 144
		PyErr_SetString(PyExc_TypeError,
				"dbm mappings have string indices only");
		return -1;
145
	}
146 147 148 149
        if (dp->di_dbm == NULL) {
                 PyErr_SetString(DbmError, "DBM object has already been closed"); 
                 return -1;
        }
150 151
	dp->di_size = -1;
	if (w == NULL) {
152 153 154
		if ( dbm_delete(dp->di_dbm, krec) < 0 ) {
			dbm_clearerr(dp->di_dbm);
			PyErr_SetString(PyExc_KeyError,
155
				      PyString_AS_STRING((PyStringObject *)v));
156 157
			return -1;
		}
158
	} else {
159 160
		if ( !PyArg_Parse(w, "s#", &drec.dptr, &drec.dsize) ) {
			PyErr_SetString(PyExc_TypeError,
161
				     "dbm mappings have string elements only");
162 163 164 165
			return -1;
		}
		if ( dbm_store(dp->di_dbm, krec, drec, DBM_REPLACE) < 0 ) {
			dbm_clearerr(dp->di_dbm);
166 167
			PyErr_SetString(DbmError,
					"Cannot add item to database");
168 169
			return -1;
		}
170 171
	}
	if ( dbm_error(dp->di_dbm) ) {
172 173 174
		dbm_clearerr(dp->di_dbm);
		PyErr_SetString(DbmError, "");
		return -1;
175 176 177 178
	}
	return 0;
}

179
static PyMappingMethods dbm_as_mapping = {
180 181 182
	(inquiry)dbm_length,		/*mp_length*/
	(binaryfunc)dbm_subscript,	/*mp_subscript*/
	(objobjargproc)dbm_ass_sub,	/*mp_ass_subscript*/
183 184
};

185
static PyObject *
186 187
dbm__close(dp, args)
	register dbmobject *dp;
188
PyObject *args;
189
{
190
	if ( !PyArg_NoArgs(args) )
191 192
		return NULL;
        if ( dp->di_dbm )
193
		dbm_close(dp->di_dbm);
194
	dp->di_dbm = NULL;
195 196
	Py_INCREF(Py_None);
	return Py_None;
197 198
}

199
static PyObject *
200 201
dbm_keys(dp, args)
	register dbmobject *dp;
202
PyObject *args;
203
{
204
	register PyObject *v, *item;
205
	datum key;
206
	int err;
207

208
	if (!PyArg_NoArgs(args))
209
		return NULL;
210
        check_dbmobject_open(dp);
211
	v = PyList_New(0);
212 213 214
	if (v == NULL)
		return NULL;
	for (key = dbm_firstkey(dp->di_dbm); key.dptr;
215
	     key = dbm_nextkey(dp->di_dbm)) {
216
		item = PyString_FromStringAndSize(key.dptr, key.dsize);
217
		if (item == NULL) {
218
			Py_DECREF(v);
219 220
			return NULL;
		}
221 222
		err = PyList_Append(v, item);
		Py_DECREF(item);
223
		if (err != 0) {
224
			Py_DECREF(v);
225 226
			return NULL;
		}
227 228 229 230
	}
	return v;
}

231
static PyObject *
232 233
dbm_has_key(dp, args)
	register dbmobject *dp;
234
PyObject *args;
235 236 237
{
	datum key, val;
	
238
	if (!PyArg_Parse(args, "s#", &key.dptr, &key.dsize))
239
		return NULL;
240
        check_dbmobject_open(dp);
241
	val = dbm_fetch(dp->di_dbm, key);
242
	return PyInt_FromLong(val.dptr != NULL);
243 244
}

245 246 247 248
static PyMethodDef dbm_methods[] = {
	{"close",	(PyCFunction)dbm__close},
	{"keys",	(PyCFunction)dbm_keys},
	{"has_key",	(PyCFunction)dbm_has_key},
249 250 251
	{NULL,		NULL}		/* sentinel */
};

252
static PyObject *
253 254
dbm_getattr(dp, name)
	dbmobject *dp;
255
char *name;
256
{
257
	return Py_FindMethod(dbm_methods, (PyObject *)dp, name);
258 259
}

260 261
static PyTypeObject Dbmtype = {
	PyObject_HEAD_INIT(&PyType_Type)
262
	0,
263
	"dbm",
264 265
	sizeof(dbmobject),
	0,
266 267
	(destructor)dbm_dealloc,  /*tp_dealloc*/
	0,			  /*tp_print*/
268
	(getattrfunc)dbm_getattr, /*tp_getattr*/
269 270 271 272 273 274
	0,			  /*tp_setattr*/
	0,			  /*tp_compare*/
	0,			  /*tp_repr*/
	0,			  /*tp_as_number*/
	0,			  /*tp_as_sequence*/
	&dbm_as_mapping,	  /*tp_as_mapping*/
275 276 277 278
};

/* ----------------------------------------------------------------- */

279
static PyObject *
280
dbmopen(self, args)
281 282
	PyObject *self;
PyObject *args;
283
{
284 285 286 287
	char *name;
	char *flags = "r";
	int iflags;
	int mode = 0666;
288

289
        if ( !PyArg_ParseTuple(args, "s|si", &name, &flags, &mode) )
290
		return NULL;
291
	if ( strcmp(flags, "r") == 0 )
292
		iflags = O_RDONLY;
293
	else if ( strcmp(flags, "w") == 0 )
294
		iflags = O_RDWR;
295
	else if ( strcmp(flags, "rw") == 0 ) /* B/W compat */
296
		iflags = O_RDWR|O_CREAT; 
297
	else if ( strcmp(flags, "c") == 0 )
298
		iflags = O_RDWR|O_CREAT;
299
	else if ( strcmp(flags, "n") == 0 )
300
		iflags = O_RDWR|O_CREAT|O_TRUNC;
301
	else {
302 303 304
		PyErr_SetString(DbmError,
				"Flags should be one of 'r', 'w', 'c' or 'n'");
		return NULL;
305 306 307 308
	}
        return newdbmobject(name, iflags, mode);
}

309
static PyMethodDef dbmmodule_methods[] = {
310 311
	{ "open", (PyCFunction)dbmopen, 1 },
	{ 0, 0 },
312 313
};

314
DL_EXPORT(void)
315
initdbm() {
316
	PyObject *m, *d;
317

318 319
	m = Py_InitModule("dbm", dbmmodule_methods);
	d = PyModule_GetDict(m);
320 321 322
	DbmError = PyErr_NewException("dbm.error", NULL, NULL);
	if (DbmError != NULL)
		PyDict_SetItemString(d, "error", DbmError);
323
}