blob: 9fb122569a3e32b26cb640fe2dfd1d7ed4ab9780 [file] [log] [blame]
Guido van Rossumdd9ed831992-06-29 17:10:40 +00001
2/* DBM module using dictionary interface */
3
4
Roger E. Masseb0dfe961996-12-10 00:07:00 +00005#include "Python.h"
Guido van Rossumdd9ed831992-06-29 17:10:40 +00006
7#include <sys/types.h>
8#include <sys/stat.h>
9#include <fcntl.h>
Fred Draked94f7072000-09-14 15:48:06 +000010
11/* Some Linux systems install gdbm/ndbm.h, but not ndbm.h. This supports
12 * whichever configure was able to locate.
13 */
14#if defined(HAVE_NDBM_H)
Guido van Rossumdd9ed831992-06-29 17:10:40 +000015#include <ndbm.h>
Fred Drakeae90f8d2000-09-15 03:38:12 +000016#elif defined(HAVE_DB1_NDBM_H)
17#include <db1/ndbm.h>
Fred Draked94f7072000-09-14 15:48:06 +000018#elif defined(HAVE_GDBM_NDBM_H)
19#include <gdbm/ndbm.h>
20#else
21#error "No ndbm.h available!"
22#endif
Guido van Rossumdd9ed831992-06-29 17:10:40 +000023
24typedef struct {
Roger E. Masseb0dfe961996-12-10 00:07:00 +000025 PyObject_HEAD
Guido van Rossumdd9ed831992-06-29 17:10:40 +000026 int di_size; /* -1 means recompute */
27 DBM *di_dbm;
28} dbmobject;
29
Roger E. Masseb0dfe961996-12-10 00:07:00 +000030staticforward PyTypeObject Dbmtype;
Guido van Rossumdd9ed831992-06-29 17:10:40 +000031
32#define is_dbmobject(v) ((v)->ob_type == &Dbmtype)
Guido van Rossum77eecfa1997-07-17 22:56:01 +000033#define check_dbmobject_open(v) if ((v)->di_dbm == NULL) \
34 { PyErr_SetString(DbmError, "DBM object has already been closed"); \
35 return NULL; }
Guido van Rossumdd9ed831992-06-29 17:10:40 +000036
Roger E. Masseb0dfe961996-12-10 00:07:00 +000037static PyObject *DbmError;
Guido van Rossumdd9ed831992-06-29 17:10:40 +000038
Roger E. Masseb0dfe961996-12-10 00:07:00 +000039static PyObject *
Peter Schneider-Kampcb27c352000-07-10 17:06:38 +000040newdbmobject(char *file, int flags, int 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
Peter Schneider-Kampcb27c352000-07-10 17:06:38 +000059dbm_dealloc(register dbmobject *dp)
Guido van Rossumdd9ed831992-06-29 17:10:40 +000060{
61 if ( dp->di_dbm )
Roger E. Massee7ee8c31996-12-13 15:55:22 +000062 dbm_close(dp->di_dbm);
Guido van Rossumb18618d2000-05-03 23:44:39 +000063 PyObject_Del(dp);
Guido van Rossumdd9ed831992-06-29 17:10:40 +000064}
65
66static int
Peter Schneider-Kampcb27c352000-07-10 17:06:38 +000067dbm_length(dbmobject *dp)
Guido van Rossumdd9ed831992-06-29 17:10:40 +000068{
Guido van Rossum77eecfa1997-07-17 22:56:01 +000069 if (dp->di_dbm == NULL) {
70 PyErr_SetString(DbmError, "DBM object has already been closed");
71 return -1;
72 }
Guido van Rossumdd9ed831992-06-29 17:10:40 +000073 if ( dp->di_size < 0 ) {
Roger E. Massee7ee8c31996-12-13 15:55:22 +000074 datum key;
75 int size;
Guido van Rossumdd9ed831992-06-29 17:10:40 +000076
Roger E. Massee7ee8c31996-12-13 15:55:22 +000077 size = 0;
78 for ( key=dbm_firstkey(dp->di_dbm); key.dptr;
79 key = dbm_nextkey(dp->di_dbm))
80 size++;
81 dp->di_size = size;
Guido van Rossumdd9ed831992-06-29 17:10:40 +000082 }
83 return dp->di_size;
84}
85
Roger E. Masseb0dfe961996-12-10 00:07:00 +000086static PyObject *
Peter Schneider-Kampcb27c352000-07-10 17:06:38 +000087dbm_subscript(dbmobject *dp, register PyObject *key)
Guido van Rossumdd9ed831992-06-29 17:10:40 +000088{
Guido van Rossumdd9ed831992-06-29 17:10:40 +000089 datum drec, krec;
90
Roger E. Masseb0dfe961996-12-10 00:07:00 +000091 if (!PyArg_Parse(key, "s#", &krec.dptr, &krec.dsize) )
Guido van Rossumdd9ed831992-06-29 17:10:40 +000092 return NULL;
93
Guido van Rossum77eecfa1997-07-17 22:56:01 +000094 check_dbmobject_open(dp);
Guido van Rossumdd9ed831992-06-29 17:10:40 +000095 drec = dbm_fetch(dp->di_dbm, krec);
96 if ( drec.dptr == 0 ) {
Roger E. Massee7ee8c31996-12-13 15:55:22 +000097 PyErr_SetString(PyExc_KeyError,
98 PyString_AS_STRING((PyStringObject *)key));
99 return NULL;
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000100 }
101 if ( dbm_error(dp->di_dbm) ) {
Roger E. Massee7ee8c31996-12-13 15:55:22 +0000102 dbm_clearerr(dp->di_dbm);
103 PyErr_SetString(DbmError, "");
104 return NULL;
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000105 }
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000106 return PyString_FromStringAndSize(drec.dptr, drec.dsize);
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000107}
108
109static int
Peter Schneider-Kampcb27c352000-07-10 17:06:38 +0000110dbm_ass_sub(dbmobject *dp, PyObject *v, PyObject *w)
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000111{
112 datum krec, drec;
113
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000114 if ( !PyArg_Parse(v, "s#", &krec.dptr, &krec.dsize) ) {
Roger E. Massee7ee8c31996-12-13 15:55:22 +0000115 PyErr_SetString(PyExc_TypeError,
116 "dbm mappings have string indices only");
117 return -1;
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000118 }
Guido van Rossum77eecfa1997-07-17 22:56:01 +0000119 if (dp->di_dbm == NULL) {
120 PyErr_SetString(DbmError, "DBM object has already been closed");
121 return -1;
122 }
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000123 dp->di_size = -1;
124 if (w == NULL) {
Roger E. Massee7ee8c31996-12-13 15:55:22 +0000125 if ( dbm_delete(dp->di_dbm, krec) < 0 ) {
126 dbm_clearerr(dp->di_dbm);
127 PyErr_SetString(PyExc_KeyError,
Roger E. Massebd4b9611996-12-13 15:59:22 +0000128 PyString_AS_STRING((PyStringObject *)v));
Roger E. Massee7ee8c31996-12-13 15:55:22 +0000129 return -1;
130 }
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000131 } else {
Roger E. Massee7ee8c31996-12-13 15:55:22 +0000132 if ( !PyArg_Parse(w, "s#", &drec.dptr, &drec.dsize) ) {
133 PyErr_SetString(PyExc_TypeError,
Roger E. Massebd4b9611996-12-13 15:59:22 +0000134 "dbm mappings have string elements only");
Roger E. Massee7ee8c31996-12-13 15:55:22 +0000135 return -1;
136 }
137 if ( dbm_store(dp->di_dbm, krec, drec, DBM_REPLACE) < 0 ) {
138 dbm_clearerr(dp->di_dbm);
Roger E. Massebd4b9611996-12-13 15:59:22 +0000139 PyErr_SetString(DbmError,
140 "Cannot add item to database");
Roger E. Massee7ee8c31996-12-13 15:55:22 +0000141 return -1;
142 }
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000143 }
144 if ( dbm_error(dp->di_dbm) ) {
Roger E. Massee7ee8c31996-12-13 15:55:22 +0000145 dbm_clearerr(dp->di_dbm);
146 PyErr_SetString(DbmError, "");
147 return -1;
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000148 }
149 return 0;
150}
151
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000152static PyMappingMethods dbm_as_mapping = {
Guido van Rossumb6775db1994-08-01 11:34:53 +0000153 (inquiry)dbm_length, /*mp_length*/
154 (binaryfunc)dbm_subscript, /*mp_subscript*/
155 (objobjargproc)dbm_ass_sub, /*mp_ass_subscript*/
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000156};
157
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000158static PyObject *
Peter Schneider-Kampcb27c352000-07-10 17:06:38 +0000159dbm__close(register dbmobject *dp, PyObject *args)
Guido van Rossum807b7be1995-07-07 22:37:11 +0000160{
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000161 if ( !PyArg_NoArgs(args) )
Guido van Rossum807b7be1995-07-07 22:37:11 +0000162 return NULL;
163 if ( dp->di_dbm )
Roger E. Massee7ee8c31996-12-13 15:55:22 +0000164 dbm_close(dp->di_dbm);
Guido van Rossum807b7be1995-07-07 22:37:11 +0000165 dp->di_dbm = NULL;
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000166 Py_INCREF(Py_None);
167 return Py_None;
Guido van Rossum807b7be1995-07-07 22:37:11 +0000168}
169
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000170static PyObject *
Peter Schneider-Kampcb27c352000-07-10 17:06:38 +0000171dbm_keys(register dbmobject *dp, PyObject *args)
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000172{
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000173 register PyObject *v, *item;
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000174 datum key;
Guido van Rossumd5039131995-01-30 12:45:38 +0000175 int err;
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000176
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000177 if (!PyArg_NoArgs(args))
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000178 return NULL;
Guido van Rossum77eecfa1997-07-17 22:56:01 +0000179 check_dbmobject_open(dp);
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000180 v = PyList_New(0);
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000181 if (v == NULL)
182 return NULL;
183 for (key = dbm_firstkey(dp->di_dbm); key.dptr;
Guido van Rossumd5039131995-01-30 12:45:38 +0000184 key = dbm_nextkey(dp->di_dbm)) {
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000185 item = PyString_FromStringAndSize(key.dptr, key.dsize);
Guido van Rossumd5039131995-01-30 12:45:38 +0000186 if (item == NULL) {
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000187 Py_DECREF(v);
Guido van Rossumd5039131995-01-30 12:45:38 +0000188 return NULL;
189 }
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000190 err = PyList_Append(v, item);
191 Py_DECREF(item);
Guido van Rossumd5039131995-01-30 12:45:38 +0000192 if (err != 0) {
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000193 Py_DECREF(v);
Guido van Rossumd5039131995-01-30 12:45:38 +0000194 return NULL;
195 }
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000196 }
197 return v;
198}
199
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000200static PyObject *
Peter Schneider-Kampcb27c352000-07-10 17:06:38 +0000201dbm_has_key(register dbmobject *dp, PyObject *args)
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000202{
203 datum key, val;
204
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000205 if (!PyArg_Parse(args, "s#", &key.dptr, &key.dsize))
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000206 return NULL;
Guido van Rossum77eecfa1997-07-17 22:56:01 +0000207 check_dbmobject_open(dp);
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000208 val = dbm_fetch(dp->di_dbm, key);
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000209 return PyInt_FromLong(val.dptr != NULL);
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000210}
211
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000212static PyMethodDef dbm_methods[] = {
213 {"close", (PyCFunction)dbm__close},
214 {"keys", (PyCFunction)dbm_keys},
215 {"has_key", (PyCFunction)dbm_has_key},
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000216 {NULL, NULL} /* sentinel */
217};
218
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000219static PyObject *
Peter Schneider-Kampcb27c352000-07-10 17:06:38 +0000220dbm_getattr(dbmobject *dp, char *name)
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000221{
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000222 return Py_FindMethod(dbm_methods, (PyObject *)dp, name);
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000223}
224
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000225static PyTypeObject Dbmtype = {
226 PyObject_HEAD_INIT(&PyType_Type)
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000227 0,
Guido van Rossum807b7be1995-07-07 22:37:11 +0000228 "dbm",
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000229 sizeof(dbmobject),
230 0,
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000231 (destructor)dbm_dealloc, /*tp_dealloc*/
232 0, /*tp_print*/
Guido van Rossumb6775db1994-08-01 11:34:53 +0000233 (getattrfunc)dbm_getattr, /*tp_getattr*/
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000234 0, /*tp_setattr*/
235 0, /*tp_compare*/
236 0, /*tp_repr*/
237 0, /*tp_as_number*/
238 0, /*tp_as_sequence*/
239 &dbm_as_mapping, /*tp_as_mapping*/
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000240};
241
242/* ----------------------------------------------------------------- */
243
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000244static PyObject *
Peter Schneider-Kampcb27c352000-07-10 17:06:38 +0000245dbmopen(PyObject *self, PyObject *args)
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000246{
Guido van Rossum807b7be1995-07-07 22:37:11 +0000247 char *name;
248 char *flags = "r";
249 int iflags;
250 int mode = 0666;
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000251
Guido van Rossum43713e52000-02-29 13:59:29 +0000252 if ( !PyArg_ParseTuple(args, "s|si:open", &name, &flags, &mode) )
Roger E. Massee7ee8c31996-12-13 15:55:22 +0000253 return NULL;
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000254 if ( strcmp(flags, "r") == 0 )
Roger E. Massee7ee8c31996-12-13 15:55:22 +0000255 iflags = O_RDONLY;
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000256 else if ( strcmp(flags, "w") == 0 )
Roger E. Massee7ee8c31996-12-13 15:55:22 +0000257 iflags = O_RDWR;
Guido van Rossum807b7be1995-07-07 22:37:11 +0000258 else if ( strcmp(flags, "rw") == 0 ) /* B/W compat */
Roger E. Massee7ee8c31996-12-13 15:55:22 +0000259 iflags = O_RDWR|O_CREAT;
Guido van Rossum807b7be1995-07-07 22:37:11 +0000260 else if ( strcmp(flags, "c") == 0 )
Roger E. Massee7ee8c31996-12-13 15:55:22 +0000261 iflags = O_RDWR|O_CREAT;
Guido van Rossum807b7be1995-07-07 22:37:11 +0000262 else if ( strcmp(flags, "n") == 0 )
Roger E. Massee7ee8c31996-12-13 15:55:22 +0000263 iflags = O_RDWR|O_CREAT|O_TRUNC;
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000264 else {
Roger E. Massee7ee8c31996-12-13 15:55:22 +0000265 PyErr_SetString(DbmError,
266 "Flags should be one of 'r', 'w', 'c' or 'n'");
267 return NULL;
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000268 }
269 return newdbmobject(name, iflags, mode);
270}
271
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000272static PyMethodDef dbmmodule_methods[] = {
Roger E. Massee7ee8c31996-12-13 15:55:22 +0000273 { "open", (PyCFunction)dbmopen, 1 },
274 { 0, 0 },
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000275};
276
Guido van Rossum3886bb61998-12-04 18:50:17 +0000277DL_EXPORT(void)
Thomas Wouters58d05102000-07-24 14:43:35 +0000278initdbm(void) {
Roger E. Massee7ee8c31996-12-13 15:55:22 +0000279 PyObject *m, *d;
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000280
Roger E. Massee7ee8c31996-12-13 15:55:22 +0000281 m = Py_InitModule("dbm", dbmmodule_methods);
282 d = PyModule_GetDict(m);
Guido van Rossum0cb96de1997-10-01 04:29:29 +0000283 DbmError = PyErr_NewException("dbm.error", NULL, NULL);
284 if (DbmError != NULL)
285 PyDict_SetItemString(d, "error", DbmError);
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000286}