blob: 53db0fa6a7e696c18da4c54fa487323c3ac05f7f [file] [log] [blame]
Guido van Rossumdd9ed831992-06-29 17:10:40 +00001/***********************************************************
Guido van Rossumfd71b9e2000-06-30 23:50:40 +00002Copyright (c) 2000, BeOpen.com.
3Copyright (c) 1995-2000, Corporation for National Research Initiatives.
4Copyright (c) 1990-1995, Stichting Mathematisch Centrum.
5All rights reserved.
Guido van Rossumdd9ed831992-06-29 17:10:40 +00006
Guido van Rossumfd71b9e2000-06-30 23:50:40 +00007See the file "Misc/COPYRIGHT" for information on usage and
8redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
Guido van Rossumdd9ed831992-06-29 17:10:40 +00009******************************************************************/
10
11/* DBM module using dictionary interface */
12
13
Roger E. Masseb0dfe961996-12-10 00:07:00 +000014#include "Python.h"
Guido van Rossumdd9ed831992-06-29 17:10:40 +000015
16#include <sys/types.h>
17#include <sys/stat.h>
18#include <fcntl.h>
19#include <ndbm.h>
20
21typedef struct {
Roger E. Masseb0dfe961996-12-10 00:07:00 +000022 PyObject_HEAD
Guido van Rossumdd9ed831992-06-29 17:10:40 +000023 int di_size; /* -1 means recompute */
24 DBM *di_dbm;
25} dbmobject;
26
Roger E. Masseb0dfe961996-12-10 00:07:00 +000027staticforward PyTypeObject Dbmtype;
Guido van Rossumdd9ed831992-06-29 17:10:40 +000028
29#define is_dbmobject(v) ((v)->ob_type == &Dbmtype)
Guido van Rossum77eecfa1997-07-17 22:56:01 +000030#define check_dbmobject_open(v) if ((v)->di_dbm == NULL) \
31 { PyErr_SetString(DbmError, "DBM object has already been closed"); \
32 return NULL; }
Guido van Rossumdd9ed831992-06-29 17:10:40 +000033
Roger E. Masseb0dfe961996-12-10 00:07:00 +000034static PyObject *DbmError;
Guido van Rossumdd9ed831992-06-29 17:10:40 +000035
Roger E. Masseb0dfe961996-12-10 00:07:00 +000036static PyObject *
Guido van Rossumdd9ed831992-06-29 17:10:40 +000037newdbmobject(file, flags, mode)
Roger E. Massee7ee8c31996-12-13 15:55:22 +000038 char *file;
39int flags;
40int mode;
Guido van Rossumdd9ed831992-06-29 17:10:40 +000041{
42 dbmobject *dp;
43
Guido van Rossumb18618d2000-05-03 23:44:39 +000044 dp = PyObject_New(dbmobject, &Dbmtype);
Guido van Rossumdd9ed831992-06-29 17:10:40 +000045 if (dp == NULL)
46 return NULL;
47 dp->di_size = -1;
48 if ( (dp->di_dbm = dbm_open(file, flags, mode)) == 0 ) {
Roger E. Massee7ee8c31996-12-13 15:55:22 +000049 PyErr_SetFromErrno(DbmError);
50 Py_DECREF(dp);
51 return NULL;
Guido van Rossumdd9ed831992-06-29 17:10:40 +000052 }
Roger E. Masseb0dfe961996-12-10 00:07:00 +000053 return (PyObject *)dp;
Guido van Rossumdd9ed831992-06-29 17:10:40 +000054}
55
56/* Methods */
57
58static void
59dbm_dealloc(dp)
60 register dbmobject *dp;
61{
62 if ( dp->di_dbm )
Roger E. Massee7ee8c31996-12-13 15:55:22 +000063 dbm_close(dp->di_dbm);
Guido van Rossumb18618d2000-05-03 23:44:39 +000064 PyObject_Del(dp);
Guido van Rossumdd9ed831992-06-29 17:10:40 +000065}
66
67static int
68dbm_length(dp)
69 dbmobject *dp;
70{
Guido van Rossum77eecfa1997-07-17 22:56:01 +000071 if (dp->di_dbm == NULL) {
72 PyErr_SetString(DbmError, "DBM object has already been closed");
73 return -1;
74 }
Guido van Rossumdd9ed831992-06-29 17:10:40 +000075 if ( dp->di_size < 0 ) {
Roger E. Massee7ee8c31996-12-13 15:55:22 +000076 datum key;
77 int size;
Guido van Rossumdd9ed831992-06-29 17:10:40 +000078
Roger E. Massee7ee8c31996-12-13 15:55:22 +000079 size = 0;
80 for ( key=dbm_firstkey(dp->di_dbm); key.dptr;
81 key = dbm_nextkey(dp->di_dbm))
82 size++;
83 dp->di_size = size;
Guido van Rossumdd9ed831992-06-29 17:10:40 +000084 }
85 return dp->di_size;
86}
87
Roger E. Masseb0dfe961996-12-10 00:07:00 +000088static PyObject *
Guido van Rossumdd9ed831992-06-29 17:10:40 +000089dbm_subscript(dp, key)
90 dbmobject *dp;
Roger E. Massee7ee8c31996-12-13 15:55:22 +000091register PyObject *key;
Guido van Rossumdd9ed831992-06-29 17:10:40 +000092{
Guido van Rossumdd9ed831992-06-29 17:10:40 +000093 datum drec, krec;
94
Roger E. Masseb0dfe961996-12-10 00:07:00 +000095 if (!PyArg_Parse(key, "s#", &krec.dptr, &krec.dsize) )
Guido van Rossumdd9ed831992-06-29 17:10:40 +000096 return NULL;
97
Guido van Rossum77eecfa1997-07-17 22:56:01 +000098 check_dbmobject_open(dp);
Guido van Rossumdd9ed831992-06-29 17:10:40 +000099 drec = dbm_fetch(dp->di_dbm, krec);
100 if ( drec.dptr == 0 ) {
Roger E. Massee7ee8c31996-12-13 15:55:22 +0000101 PyErr_SetString(PyExc_KeyError,
102 PyString_AS_STRING((PyStringObject *)key));
103 return NULL;
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000104 }
105 if ( dbm_error(dp->di_dbm) ) {
Roger E. Massee7ee8c31996-12-13 15:55:22 +0000106 dbm_clearerr(dp->di_dbm);
107 PyErr_SetString(DbmError, "");
108 return NULL;
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000109 }
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000110 return PyString_FromStringAndSize(drec.dptr, drec.dsize);
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000111}
112
113static int
114dbm_ass_sub(dp, v, w)
115 dbmobject *dp;
Roger E. Massee7ee8c31996-12-13 15:55:22 +0000116PyObject *v, *w;
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000117{
118 datum krec, drec;
119
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000120 if ( !PyArg_Parse(v, "s#", &krec.dptr, &krec.dsize) ) {
Roger E. Massee7ee8c31996-12-13 15:55:22 +0000121 PyErr_SetString(PyExc_TypeError,
122 "dbm mappings have string indices only");
123 return -1;
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000124 }
Guido van Rossum77eecfa1997-07-17 22:56:01 +0000125 if (dp->di_dbm == NULL) {
126 PyErr_SetString(DbmError, "DBM object has already been closed");
127 return -1;
128 }
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000129 dp->di_size = -1;
130 if (w == NULL) {
Roger E. Massee7ee8c31996-12-13 15:55:22 +0000131 if ( dbm_delete(dp->di_dbm, krec) < 0 ) {
132 dbm_clearerr(dp->di_dbm);
133 PyErr_SetString(PyExc_KeyError,
Roger E. Massebd4b9611996-12-13 15:59:22 +0000134 PyString_AS_STRING((PyStringObject *)v));
Roger E. Massee7ee8c31996-12-13 15:55:22 +0000135 return -1;
136 }
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000137 } else {
Roger E. Massee7ee8c31996-12-13 15:55:22 +0000138 if ( !PyArg_Parse(w, "s#", &drec.dptr, &drec.dsize) ) {
139 PyErr_SetString(PyExc_TypeError,
Roger E. Massebd4b9611996-12-13 15:59:22 +0000140 "dbm mappings have string elements only");
Roger E. Massee7ee8c31996-12-13 15:55:22 +0000141 return -1;
142 }
143 if ( dbm_store(dp->di_dbm, krec, drec, DBM_REPLACE) < 0 ) {
144 dbm_clearerr(dp->di_dbm);
Roger E. Massebd4b9611996-12-13 15:59:22 +0000145 PyErr_SetString(DbmError,
146 "Cannot add item to database");
Roger E. Massee7ee8c31996-12-13 15:55:22 +0000147 return -1;
148 }
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000149 }
150 if ( dbm_error(dp->di_dbm) ) {
Roger E. Massee7ee8c31996-12-13 15:55:22 +0000151 dbm_clearerr(dp->di_dbm);
152 PyErr_SetString(DbmError, "");
153 return -1;
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000154 }
155 return 0;
156}
157
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000158static PyMappingMethods dbm_as_mapping = {
Guido van Rossumb6775db1994-08-01 11:34:53 +0000159 (inquiry)dbm_length, /*mp_length*/
160 (binaryfunc)dbm_subscript, /*mp_subscript*/
161 (objobjargproc)dbm_ass_sub, /*mp_ass_subscript*/
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000162};
163
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000164static PyObject *
Guido van Rossum807b7be1995-07-07 22:37:11 +0000165dbm__close(dp, args)
166 register dbmobject *dp;
Roger E. Massee7ee8c31996-12-13 15:55:22 +0000167PyObject *args;
Guido van Rossum807b7be1995-07-07 22:37:11 +0000168{
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000169 if ( !PyArg_NoArgs(args) )
Guido van Rossum807b7be1995-07-07 22:37:11 +0000170 return NULL;
171 if ( dp->di_dbm )
Roger E. Massee7ee8c31996-12-13 15:55:22 +0000172 dbm_close(dp->di_dbm);
Guido van Rossum807b7be1995-07-07 22:37:11 +0000173 dp->di_dbm = NULL;
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000174 Py_INCREF(Py_None);
175 return Py_None;
Guido van Rossum807b7be1995-07-07 22:37:11 +0000176}
177
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000178static PyObject *
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000179dbm_keys(dp, args)
180 register dbmobject *dp;
Roger E. Massee7ee8c31996-12-13 15:55:22 +0000181PyObject *args;
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000182{
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000183 register PyObject *v, *item;
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000184 datum key;
Guido van Rossumd5039131995-01-30 12:45:38 +0000185 int err;
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000186
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000187 if (!PyArg_NoArgs(args))
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000188 return NULL;
Guido van Rossum77eecfa1997-07-17 22:56:01 +0000189 check_dbmobject_open(dp);
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000190 v = PyList_New(0);
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000191 if (v == NULL)
192 return NULL;
193 for (key = dbm_firstkey(dp->di_dbm); key.dptr;
Guido van Rossumd5039131995-01-30 12:45:38 +0000194 key = dbm_nextkey(dp->di_dbm)) {
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000195 item = PyString_FromStringAndSize(key.dptr, key.dsize);
Guido van Rossumd5039131995-01-30 12:45:38 +0000196 if (item == NULL) {
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000197 Py_DECREF(v);
Guido van Rossumd5039131995-01-30 12:45:38 +0000198 return NULL;
199 }
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000200 err = PyList_Append(v, item);
201 Py_DECREF(item);
Guido van Rossumd5039131995-01-30 12:45:38 +0000202 if (err != 0) {
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000203 Py_DECREF(v);
Guido van Rossumd5039131995-01-30 12:45:38 +0000204 return NULL;
205 }
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000206 }
207 return v;
208}
209
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000210static PyObject *
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000211dbm_has_key(dp, args)
212 register dbmobject *dp;
Roger E. Massee7ee8c31996-12-13 15:55:22 +0000213PyObject *args;
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000214{
215 datum key, val;
216
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000217 if (!PyArg_Parse(args, "s#", &key.dptr, &key.dsize))
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000218 return NULL;
Guido van Rossum77eecfa1997-07-17 22:56:01 +0000219 check_dbmobject_open(dp);
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000220 val = dbm_fetch(dp->di_dbm, key);
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000221 return PyInt_FromLong(val.dptr != NULL);
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000222}
223
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000224static PyMethodDef dbm_methods[] = {
225 {"close", (PyCFunction)dbm__close},
226 {"keys", (PyCFunction)dbm_keys},
227 {"has_key", (PyCFunction)dbm_has_key},
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000228 {NULL, NULL} /* sentinel */
229};
230
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000231static PyObject *
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000232dbm_getattr(dp, name)
233 dbmobject *dp;
Roger E. Massee7ee8c31996-12-13 15:55:22 +0000234char *name;
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000235{
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000236 return Py_FindMethod(dbm_methods, (PyObject *)dp, name);
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000237}
238
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000239static PyTypeObject Dbmtype = {
240 PyObject_HEAD_INIT(&PyType_Type)
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000241 0,
Guido van Rossum807b7be1995-07-07 22:37:11 +0000242 "dbm",
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000243 sizeof(dbmobject),
244 0,
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000245 (destructor)dbm_dealloc, /*tp_dealloc*/
246 0, /*tp_print*/
Guido van Rossumb6775db1994-08-01 11:34:53 +0000247 (getattrfunc)dbm_getattr, /*tp_getattr*/
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000248 0, /*tp_setattr*/
249 0, /*tp_compare*/
250 0, /*tp_repr*/
251 0, /*tp_as_number*/
252 0, /*tp_as_sequence*/
253 &dbm_as_mapping, /*tp_as_mapping*/
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000254};
255
256/* ----------------------------------------------------------------- */
257
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000258static PyObject *
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000259dbmopen(self, args)
Roger E. Massee7ee8c31996-12-13 15:55:22 +0000260 PyObject *self;
261PyObject *args;
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000262{
Guido van Rossum807b7be1995-07-07 22:37:11 +0000263 char *name;
264 char *flags = "r";
265 int iflags;
266 int mode = 0666;
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000267
Guido van Rossum43713e52000-02-29 13:59:29 +0000268 if ( !PyArg_ParseTuple(args, "s|si:open", &name, &flags, &mode) )
Roger E. Massee7ee8c31996-12-13 15:55:22 +0000269 return NULL;
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000270 if ( strcmp(flags, "r") == 0 )
Roger E. Massee7ee8c31996-12-13 15:55:22 +0000271 iflags = O_RDONLY;
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000272 else if ( strcmp(flags, "w") == 0 )
Roger E. Massee7ee8c31996-12-13 15:55:22 +0000273 iflags = O_RDWR;
Guido van Rossum807b7be1995-07-07 22:37:11 +0000274 else if ( strcmp(flags, "rw") == 0 ) /* B/W compat */
Roger E. Massee7ee8c31996-12-13 15:55:22 +0000275 iflags = O_RDWR|O_CREAT;
Guido van Rossum807b7be1995-07-07 22:37:11 +0000276 else if ( strcmp(flags, "c") == 0 )
Roger E. Massee7ee8c31996-12-13 15:55:22 +0000277 iflags = O_RDWR|O_CREAT;
Guido van Rossum807b7be1995-07-07 22:37:11 +0000278 else if ( strcmp(flags, "n") == 0 )
Roger E. Massee7ee8c31996-12-13 15:55:22 +0000279 iflags = O_RDWR|O_CREAT|O_TRUNC;
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000280 else {
Roger E. Massee7ee8c31996-12-13 15:55:22 +0000281 PyErr_SetString(DbmError,
282 "Flags should be one of 'r', 'w', 'c' or 'n'");
283 return NULL;
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000284 }
285 return newdbmobject(name, iflags, mode);
286}
287
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000288static PyMethodDef dbmmodule_methods[] = {
Roger E. Massee7ee8c31996-12-13 15:55:22 +0000289 { "open", (PyCFunction)dbmopen, 1 },
290 { 0, 0 },
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000291};
292
Guido van Rossum3886bb61998-12-04 18:50:17 +0000293DL_EXPORT(void)
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000294initdbm() {
Roger E. Massee7ee8c31996-12-13 15:55:22 +0000295 PyObject *m, *d;
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000296
Roger E. Massee7ee8c31996-12-13 15:55:22 +0000297 m = Py_InitModule("dbm", dbmmodule_methods);
298 d = PyModule_GetDict(m);
Guido van Rossum0cb96de1997-10-01 04:29:29 +0000299 DbmError = PyErr_NewException("dbm.error", NULL, NULL);
300 if (DbmError != NULL)
301 PyDict_SetItemString(d, "error", DbmError);
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000302}