blob: b95c0ba8534335c940f263ce059fc5dae24aa014 [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 *
Peter Schneider-Kampcb27c352000-07-10 17:06:38 +000037newdbmobject(char *file, int flags, int mode)
Guido van Rossumdd9ed831992-06-29 17:10:40 +000038{
39 dbmobject *dp;
40
Guido van Rossumb18618d2000-05-03 23:44:39 +000041 dp = PyObject_New(dbmobject, &Dbmtype);
Guido van Rossumdd9ed831992-06-29 17:10:40 +000042 if (dp == NULL)
43 return NULL;
44 dp->di_size = -1;
45 if ( (dp->di_dbm = dbm_open(file, flags, mode)) == 0 ) {
Roger E. Massee7ee8c31996-12-13 15:55:22 +000046 PyErr_SetFromErrno(DbmError);
47 Py_DECREF(dp);
48 return NULL;
Guido van Rossumdd9ed831992-06-29 17:10:40 +000049 }
Roger E. Masseb0dfe961996-12-10 00:07:00 +000050 return (PyObject *)dp;
Guido van Rossumdd9ed831992-06-29 17:10:40 +000051}
52
53/* Methods */
54
55static void
Peter Schneider-Kampcb27c352000-07-10 17:06:38 +000056dbm_dealloc(register dbmobject *dp)
Guido van Rossumdd9ed831992-06-29 17:10:40 +000057{
58 if ( dp->di_dbm )
Roger E. Massee7ee8c31996-12-13 15:55:22 +000059 dbm_close(dp->di_dbm);
Guido van Rossumb18618d2000-05-03 23:44:39 +000060 PyObject_Del(dp);
Guido van Rossumdd9ed831992-06-29 17:10:40 +000061}
62
63static int
Peter Schneider-Kampcb27c352000-07-10 17:06:38 +000064dbm_length(dbmobject *dp)
Guido van Rossumdd9ed831992-06-29 17:10:40 +000065{
Guido van Rossum77eecfa1997-07-17 22:56:01 +000066 if (dp->di_dbm == NULL) {
67 PyErr_SetString(DbmError, "DBM object has already been closed");
68 return -1;
69 }
Guido van Rossumdd9ed831992-06-29 17:10:40 +000070 if ( dp->di_size < 0 ) {
Roger E. Massee7ee8c31996-12-13 15:55:22 +000071 datum key;
72 int size;
Guido van Rossumdd9ed831992-06-29 17:10:40 +000073
Roger E. Massee7ee8c31996-12-13 15:55:22 +000074 size = 0;
75 for ( key=dbm_firstkey(dp->di_dbm); key.dptr;
76 key = dbm_nextkey(dp->di_dbm))
77 size++;
78 dp->di_size = size;
Guido van Rossumdd9ed831992-06-29 17:10:40 +000079 }
80 return dp->di_size;
81}
82
Roger E. Masseb0dfe961996-12-10 00:07:00 +000083static PyObject *
Peter Schneider-Kampcb27c352000-07-10 17:06:38 +000084dbm_subscript(dbmobject *dp, register PyObject *key)
Guido van Rossumdd9ed831992-06-29 17:10:40 +000085{
Guido van Rossumdd9ed831992-06-29 17:10:40 +000086 datum drec, krec;
87
Roger E. Masseb0dfe961996-12-10 00:07:00 +000088 if (!PyArg_Parse(key, "s#", &krec.dptr, &krec.dsize) )
Guido van Rossumdd9ed831992-06-29 17:10:40 +000089 return NULL;
90
Guido van Rossum77eecfa1997-07-17 22:56:01 +000091 check_dbmobject_open(dp);
Guido van Rossumdd9ed831992-06-29 17:10:40 +000092 drec = dbm_fetch(dp->di_dbm, krec);
93 if ( drec.dptr == 0 ) {
Roger E. Massee7ee8c31996-12-13 15:55:22 +000094 PyErr_SetString(PyExc_KeyError,
95 PyString_AS_STRING((PyStringObject *)key));
96 return NULL;
Guido van Rossumdd9ed831992-06-29 17:10:40 +000097 }
98 if ( dbm_error(dp->di_dbm) ) {
Roger E. Massee7ee8c31996-12-13 15:55:22 +000099 dbm_clearerr(dp->di_dbm);
100 PyErr_SetString(DbmError, "");
101 return NULL;
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000102 }
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000103 return PyString_FromStringAndSize(drec.dptr, drec.dsize);
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000104}
105
106static int
Peter Schneider-Kampcb27c352000-07-10 17:06:38 +0000107dbm_ass_sub(dbmobject *dp, PyObject *v, PyObject *w)
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000108{
109 datum krec, drec;
110
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000111 if ( !PyArg_Parse(v, "s#", &krec.dptr, &krec.dsize) ) {
Roger E. Massee7ee8c31996-12-13 15:55:22 +0000112 PyErr_SetString(PyExc_TypeError,
113 "dbm mappings have string indices only");
114 return -1;
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000115 }
Guido van Rossum77eecfa1997-07-17 22:56:01 +0000116 if (dp->di_dbm == NULL) {
117 PyErr_SetString(DbmError, "DBM object has already been closed");
118 return -1;
119 }
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000120 dp->di_size = -1;
121 if (w == NULL) {
Roger E. Massee7ee8c31996-12-13 15:55:22 +0000122 if ( dbm_delete(dp->di_dbm, krec) < 0 ) {
123 dbm_clearerr(dp->di_dbm);
124 PyErr_SetString(PyExc_KeyError,
Roger E. Massebd4b9611996-12-13 15:59:22 +0000125 PyString_AS_STRING((PyStringObject *)v));
Roger E. Massee7ee8c31996-12-13 15:55:22 +0000126 return -1;
127 }
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000128 } else {
Roger E. Massee7ee8c31996-12-13 15:55:22 +0000129 if ( !PyArg_Parse(w, "s#", &drec.dptr, &drec.dsize) ) {
130 PyErr_SetString(PyExc_TypeError,
Roger E. Massebd4b9611996-12-13 15:59:22 +0000131 "dbm mappings have string elements only");
Roger E. Massee7ee8c31996-12-13 15:55:22 +0000132 return -1;
133 }
134 if ( dbm_store(dp->di_dbm, krec, drec, DBM_REPLACE) < 0 ) {
135 dbm_clearerr(dp->di_dbm);
Roger E. Massebd4b9611996-12-13 15:59:22 +0000136 PyErr_SetString(DbmError,
137 "Cannot add item to database");
Roger E. Massee7ee8c31996-12-13 15:55:22 +0000138 return -1;
139 }
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000140 }
141 if ( dbm_error(dp->di_dbm) ) {
Roger E. Massee7ee8c31996-12-13 15:55:22 +0000142 dbm_clearerr(dp->di_dbm);
143 PyErr_SetString(DbmError, "");
144 return -1;
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000145 }
146 return 0;
147}
148
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000149static PyMappingMethods dbm_as_mapping = {
Guido van Rossumb6775db1994-08-01 11:34:53 +0000150 (inquiry)dbm_length, /*mp_length*/
151 (binaryfunc)dbm_subscript, /*mp_subscript*/
152 (objobjargproc)dbm_ass_sub, /*mp_ass_subscript*/
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000153};
154
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000155static PyObject *
Peter Schneider-Kampcb27c352000-07-10 17:06:38 +0000156dbm__close(register dbmobject *dp, PyObject *args)
Guido van Rossum807b7be1995-07-07 22:37:11 +0000157{
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000158 if ( !PyArg_NoArgs(args) )
Guido van Rossum807b7be1995-07-07 22:37:11 +0000159 return NULL;
160 if ( dp->di_dbm )
Roger E. Massee7ee8c31996-12-13 15:55:22 +0000161 dbm_close(dp->di_dbm);
Guido van Rossum807b7be1995-07-07 22:37:11 +0000162 dp->di_dbm = NULL;
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000163 Py_INCREF(Py_None);
164 return Py_None;
Guido van Rossum807b7be1995-07-07 22:37:11 +0000165}
166
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000167static PyObject *
Peter Schneider-Kampcb27c352000-07-10 17:06:38 +0000168dbm_keys(register dbmobject *dp, PyObject *args)
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000169{
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000170 register PyObject *v, *item;
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000171 datum key;
Guido van Rossumd5039131995-01-30 12:45:38 +0000172 int err;
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000173
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000174 if (!PyArg_NoArgs(args))
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000175 return NULL;
Guido van Rossum77eecfa1997-07-17 22:56:01 +0000176 check_dbmobject_open(dp);
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000177 v = PyList_New(0);
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000178 if (v == NULL)
179 return NULL;
180 for (key = dbm_firstkey(dp->di_dbm); key.dptr;
Guido van Rossumd5039131995-01-30 12:45:38 +0000181 key = dbm_nextkey(dp->di_dbm)) {
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000182 item = PyString_FromStringAndSize(key.dptr, key.dsize);
Guido van Rossumd5039131995-01-30 12:45:38 +0000183 if (item == NULL) {
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000184 Py_DECREF(v);
Guido van Rossumd5039131995-01-30 12:45:38 +0000185 return NULL;
186 }
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000187 err = PyList_Append(v, item);
188 Py_DECREF(item);
Guido van Rossumd5039131995-01-30 12:45:38 +0000189 if (err != 0) {
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000190 Py_DECREF(v);
Guido van Rossumd5039131995-01-30 12:45:38 +0000191 return NULL;
192 }
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000193 }
194 return v;
195}
196
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000197static PyObject *
Peter Schneider-Kampcb27c352000-07-10 17:06:38 +0000198dbm_has_key(register dbmobject *dp, PyObject *args)
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000199{
200 datum key, val;
201
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000202 if (!PyArg_Parse(args, "s#", &key.dptr, &key.dsize))
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000203 return NULL;
Guido van Rossum77eecfa1997-07-17 22:56:01 +0000204 check_dbmobject_open(dp);
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000205 val = dbm_fetch(dp->di_dbm, key);
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000206 return PyInt_FromLong(val.dptr != NULL);
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000207}
208
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000209static PyMethodDef dbm_methods[] = {
210 {"close", (PyCFunction)dbm__close},
211 {"keys", (PyCFunction)dbm_keys},
212 {"has_key", (PyCFunction)dbm_has_key},
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000213 {NULL, NULL} /* sentinel */
214};
215
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000216static PyObject *
Peter Schneider-Kampcb27c352000-07-10 17:06:38 +0000217dbm_getattr(dbmobject *dp, char *name)
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000218{
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000219 return Py_FindMethod(dbm_methods, (PyObject *)dp, name);
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000220}
221
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000222static PyTypeObject Dbmtype = {
223 PyObject_HEAD_INIT(&PyType_Type)
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000224 0,
Guido van Rossum807b7be1995-07-07 22:37:11 +0000225 "dbm",
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000226 sizeof(dbmobject),
227 0,
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000228 (destructor)dbm_dealloc, /*tp_dealloc*/
229 0, /*tp_print*/
Guido van Rossumb6775db1994-08-01 11:34:53 +0000230 (getattrfunc)dbm_getattr, /*tp_getattr*/
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000231 0, /*tp_setattr*/
232 0, /*tp_compare*/
233 0, /*tp_repr*/
234 0, /*tp_as_number*/
235 0, /*tp_as_sequence*/
236 &dbm_as_mapping, /*tp_as_mapping*/
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000237};
238
239/* ----------------------------------------------------------------- */
240
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000241static PyObject *
Peter Schneider-Kampcb27c352000-07-10 17:06:38 +0000242dbmopen(PyObject *self, PyObject *args)
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000243{
Guido van Rossum807b7be1995-07-07 22:37:11 +0000244 char *name;
245 char *flags = "r";
246 int iflags;
247 int mode = 0666;
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000248
Guido van Rossum43713e52000-02-29 13:59:29 +0000249 if ( !PyArg_ParseTuple(args, "s|si:open", &name, &flags, &mode) )
Roger E. Massee7ee8c31996-12-13 15:55:22 +0000250 return NULL;
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000251 if ( strcmp(flags, "r") == 0 )
Roger E. Massee7ee8c31996-12-13 15:55:22 +0000252 iflags = O_RDONLY;
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000253 else if ( strcmp(flags, "w") == 0 )
Roger E. Massee7ee8c31996-12-13 15:55:22 +0000254 iflags = O_RDWR;
Guido van Rossum807b7be1995-07-07 22:37:11 +0000255 else if ( strcmp(flags, "rw") == 0 ) /* B/W compat */
Roger E. Massee7ee8c31996-12-13 15:55:22 +0000256 iflags = O_RDWR|O_CREAT;
Guido van Rossum807b7be1995-07-07 22:37:11 +0000257 else if ( strcmp(flags, "c") == 0 )
Roger E. Massee7ee8c31996-12-13 15:55:22 +0000258 iflags = O_RDWR|O_CREAT;
Guido van Rossum807b7be1995-07-07 22:37:11 +0000259 else if ( strcmp(flags, "n") == 0 )
Roger E. Massee7ee8c31996-12-13 15:55:22 +0000260 iflags = O_RDWR|O_CREAT|O_TRUNC;
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000261 else {
Roger E. Massee7ee8c31996-12-13 15:55:22 +0000262 PyErr_SetString(DbmError,
263 "Flags should be one of 'r', 'w', 'c' or 'n'");
264 return NULL;
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000265 }
266 return newdbmobject(name, iflags, mode);
267}
268
Roger E. Masseb0dfe961996-12-10 00:07:00 +0000269static PyMethodDef dbmmodule_methods[] = {
Roger E. Massee7ee8c31996-12-13 15:55:22 +0000270 { "open", (PyCFunction)dbmopen, 1 },
271 { 0, 0 },
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000272};
273
Guido van Rossum3886bb61998-12-04 18:50:17 +0000274DL_EXPORT(void)
Thomas Wouters58d05102000-07-24 14:43:35 +0000275initdbm(void) {
Roger E. Massee7ee8c31996-12-13 15:55:22 +0000276 PyObject *m, *d;
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000277
Roger E. Massee7ee8c31996-12-13 15:55:22 +0000278 m = Py_InitModule("dbm", dbmmodule_methods);
279 d = PyModule_GetDict(m);
Guido van Rossum0cb96de1997-10-01 04:29:29 +0000280 DbmError = PyErr_NewException("dbm.error", NULL, NULL);
281 if (DbmError != NULL)
282 PyDict_SetItemString(d, "error", DbmError);
Guido van Rossumdd9ed831992-06-29 17:10:40 +0000283}