No issues found
1 /* DBM module using dictionary interface */
2
3
4 #include "Python.h"
5
6 #include <sys/types.h>
7 #include <sys/stat.h>
8 #include <fcntl.h>
9
10 /* Some Linux systems install gdbm/ndbm.h, but not ndbm.h. This supports
11 * whichever configure was able to locate.
12 */
13 #if defined(HAVE_NDBM_H)
14 #include <ndbm.h>
15 #if defined(PYOS_OS2) && !defined(PYCC_GCC)
16 static char *which_dbm = "ndbm";
17 #else
18 static char *which_dbm = "GNU gdbm"; /* EMX port of GDBM */
19 #endif
20 #elif defined(HAVE_GDBM_NDBM_H)
21 #include <gdbm/ndbm.h>
22 static char *which_dbm = "GNU gdbm";
23 #elif defined(HAVE_GDBM_DASH_NDBM_H)
24 #include <gdbm-ndbm.h>
25 static char *which_dbm = "GNU gdbm";
26 #elif defined(HAVE_BERKDB_H)
27 #include <db.h>
28 static char *which_dbm = "Berkeley DB";
29 #else
30 #error "No ndbm.h available!"
31 #endif
32
33 typedef struct {
34 PyObject_HEAD
35 int di_size; /* -1 means recompute */
36 DBM *di_dbm;
37 } dbmobject;
38
39 static PyTypeObject Dbmtype;
40
41 #define is_dbmobject(v) (Py_TYPE(v) == &Dbmtype)
42 #define check_dbmobject_open(v) if ((v)->di_dbm == NULL) \
43 { PyErr_SetString(DbmError, "DBM object has already been closed"); \
44 return NULL; }
45
46 static PyObject *DbmError;
47
48 static PyObject *
49 newdbmobject(char *file, int flags, int mode)
50 {
51 dbmobject *dp;
52
53 dp = PyObject_New(dbmobject, &Dbmtype);
54 if (dp == NULL)
55 return NULL;
56 dp->di_size = -1;
57 if ( (dp->di_dbm = dbm_open(file, flags, mode)) == 0 ) {
58 PyErr_SetFromErrno(DbmError);
59 Py_DECREF(dp);
60 return NULL;
61 }
62 return (PyObject *)dp;
63 }
64
65 /* Methods */
66
67 static void
68 dbm_dealloc(register dbmobject *dp)
69 {
70 if ( dp->di_dbm )
71 dbm_close(dp->di_dbm);
72 PyObject_Del(dp);
73 }
74
75 static Py_ssize_t
76 dbm_length(dbmobject *dp)
77 {
78 if (dp->di_dbm == NULL) {
79 PyErr_SetString(DbmError, "DBM object has already been closed");
80 return -1;
81 }
82 if ( dp->di_size < 0 ) {
83 datum key;
84 int size;
85
86 size = 0;
87 for ( key=dbm_firstkey(dp->di_dbm); key.dptr;
88 key = dbm_nextkey(dp->di_dbm))
89 size++;
90 dp->di_size = size;
91 }
92 return dp->di_size;
93 }
94
95 static PyObject *
96 dbm_subscript(dbmobject *dp, register PyObject *key)
97 {
98 datum drec, krec;
99 int tmp_size;
100
101 if (!PyArg_Parse(key, "s#", &krec.dptr, &tmp_size) )
102 return NULL;
103
104 krec.dsize = tmp_size;
105 check_dbmobject_open(dp);
106 drec = dbm_fetch(dp->di_dbm, krec);
107 if ( drec.dptr == 0 ) {
108 PyErr_SetString(PyExc_KeyError,
109 PyString_AS_STRING((PyStringObject *)key));
110 return NULL;
111 }
112 if ( dbm_error(dp->di_dbm) ) {
113 dbm_clearerr(dp->di_dbm);
114 PyErr_SetString(DbmError, "");
115 return NULL;
116 }
117 return PyString_FromStringAndSize(drec.dptr, drec.dsize);
118 }
119
120 static int
121 dbm_ass_sub(dbmobject *dp, PyObject *v, PyObject *w)
122 {
123 datum krec, drec;
124 int tmp_size;
125
126 if ( !PyArg_Parse(v, "s#", &krec.dptr, &tmp_size) ) {
127 PyErr_SetString(PyExc_TypeError,
128 "dbm mappings have string indices only");
129 return -1;
130 }
131 krec.dsize = tmp_size;
132 if (dp->di_dbm == NULL) {
133 PyErr_SetString(DbmError, "DBM object has already been closed");
134 return -1;
135 }
136 dp->di_size = -1;
137 if (w == NULL) {
138 if ( dbm_delete(dp->di_dbm, krec) < 0 ) {
139 dbm_clearerr(dp->di_dbm);
140 PyErr_SetString(PyExc_KeyError,
141 PyString_AS_STRING((PyStringObject *)v));
142 return -1;
143 }
144 } else {
145 if ( !PyArg_Parse(w, "s#", &drec.dptr, &tmp_size) ) {
146 PyErr_SetString(PyExc_TypeError,
147 "dbm mappings have string elements only");
148 return -1;
149 }
150 drec.dsize = tmp_size;
151 if ( dbm_store(dp->di_dbm, krec, drec, DBM_REPLACE) < 0 ) {
152 dbm_clearerr(dp->di_dbm);
153 PyErr_SetString(DbmError,
154 "cannot add item to database");
155 return -1;
156 }
157 }
158 if ( dbm_error(dp->di_dbm) ) {
159 dbm_clearerr(dp->di_dbm);
160 PyErr_SetString(DbmError, "");
161 return -1;
162 }
163 return 0;
164 }
165
166 static int
167 dbm_contains(register dbmobject *dp, PyObject *v)
168 {
169 datum key, val;
170 Py_ssize_t dsize;
171
172 if (PyString_AsStringAndSize(v, (char **)&key.dptr, &dsize)) {
173 return -1;
174 }
175
176 /* Coerce from Py_ssize_t down to int: */
177 if (dsize > INT_MAX) {
178 return -1;
179 }
180 key.dsize = dsize;
181
182 /* Expand check_dbmobject_open to return -1 */
183 if (dp->di_dbm == NULL) {
184 PyErr_SetString(DbmError, "DBM object has already been closed");
185 return -1;
186 }
187 val = dbm_fetch(dp->di_dbm, key);
188 return val.dptr != NULL;
189 }
190
191 static PySequenceMethods dbm_as_sequence = {
192 (lenfunc)dbm_length, /*_length*/
193 0, /*sq_concat*/
194 0, /*sq_repeat*/
195 0, /*sq_item*/
196 0, /*sq_slice*/
197 0, /*sq_ass_item*/
198 0, /*sq_ass_slice*/
199 (objobjproc)dbm_contains, /*sq_contains*/
200 0, /*sq_inplace_concat*/
201 0 /*sq_inplace_repeat*/
202 };
203
204 static PyMappingMethods dbm_as_mapping = {
205 (lenfunc)dbm_length, /*mp_length*/
206 (binaryfunc)dbm_subscript, /*mp_subscript*/
207 (objobjargproc)dbm_ass_sub, /*mp_ass_subscript*/
208 };
209
210 static PyObject *
211 dbm__close(register dbmobject *dp, PyObject *unused)
212 {
213 if (dp->di_dbm)
214 dbm_close(dp->di_dbm);
215 dp->di_dbm = NULL;
216 Py_INCREF(Py_None);
217 return Py_None;
218 }
219
220 static PyObject *
221 dbm_keys(register dbmobject *dp, PyObject *unused)
222 {
223 register PyObject *v, *item;
224 datum key;
225 int err;
226
227 check_dbmobject_open(dp);
228 v = PyList_New(0);
229 if (v == NULL)
230 return NULL;
231 for (key = dbm_firstkey(dp->di_dbm); key.dptr;
232 key = dbm_nextkey(dp->di_dbm)) {
233 item = PyString_FromStringAndSize(key.dptr, key.dsize);
234 if (item == NULL) {
235 Py_DECREF(v);
236 return NULL;
237 }
238 err = PyList_Append(v, item);
239 Py_DECREF(item);
240 if (err != 0) {
241 Py_DECREF(v);
242 return NULL;
243 }
244 }
245 return v;
246 }
247
248 static PyObject *
249 dbm_has_key(register dbmobject *dp, PyObject *args)
250 {
251 char *tmp_ptr;
252 datum key, val;
253 int tmp_size;
254
255 if (!PyArg_ParseTuple(args, "s#:has_key", &tmp_ptr, &tmp_size))
256 return NULL;
257 key.dptr = tmp_ptr;
258 key.dsize = tmp_size;
259 check_dbmobject_open(dp);
260 val = dbm_fetch(dp->di_dbm, key);
261 return PyInt_FromLong(val.dptr != NULL);
262 }
263
264 static PyObject *
265 dbm_get(register dbmobject *dp, PyObject *args)
266 {
267 datum key, val;
268 PyObject *defvalue = Py_None;
269 char *tmp_ptr;
270 int tmp_size;
271
272 if (!PyArg_ParseTuple(args, "s#|O:get",
273 &tmp_ptr, &tmp_size, &defvalue))
274 return NULL;
275 key.dptr = tmp_ptr;
276 key.dsize = tmp_size;
277 check_dbmobject_open(dp);
278 val = dbm_fetch(dp->di_dbm, key);
279 if (val.dptr != NULL)
280 return PyString_FromStringAndSize(val.dptr, val.dsize);
281 else {
282 Py_INCREF(defvalue);
283 return defvalue;
284 }
285 }
286
287 static PyObject *
288 dbm_setdefault(register dbmobject *dp, PyObject *args)
289 {
290 datum key, val;
291 PyObject *defvalue = NULL;
292 char *tmp_ptr;
293 int tmp_size;
294
295 if (!PyArg_ParseTuple(args, "s#|S:setdefault",
296 &tmp_ptr, &tmp_size, &defvalue))
297 return NULL;
298 key.dptr = tmp_ptr;
299 key.dsize = tmp_size;
300 check_dbmobject_open(dp);
301 val = dbm_fetch(dp->di_dbm, key);
302 if (val.dptr != NULL)
303 return PyString_FromStringAndSize(val.dptr, val.dsize);
304 if (defvalue == NULL) {
305 defvalue = PyString_FromStringAndSize(NULL, 0);
306 if (defvalue == NULL)
307 return NULL;
308 }
309 else
310 Py_INCREF(defvalue);
311 val.dptr = PyString_AS_STRING(defvalue);
312 val.dsize = PyString_GET_SIZE(defvalue);
313 if (dbm_store(dp->di_dbm, key, val, DBM_INSERT) < 0) {
314 dbm_clearerr(dp->di_dbm);
315 PyErr_SetString(DbmError, "cannot add item to database");
316 return NULL;
317 }
318 return defvalue;
319 }
320
321 static PyMethodDef dbm_methods[] = {
322 {"close", (PyCFunction)dbm__close, METH_NOARGS,
323 "close()\nClose the database."},
324 {"keys", (PyCFunction)dbm_keys, METH_NOARGS,
325 "keys() -> list\nReturn a list of all keys in the database."},
326 {"has_key", (PyCFunction)dbm_has_key, METH_VARARGS,
327 "has_key(key} -> boolean\nReturn true iff key is in the database."},
328 {"get", (PyCFunction)dbm_get, METH_VARARGS,
329 "get(key[, default]) -> value\n"
330 "Return the value for key if present, otherwise default."},
331 {"setdefault", (PyCFunction)dbm_setdefault, METH_VARARGS,
332 "setdefault(key[, default]) -> value\n"
333 "Return the value for key if present, otherwise default. If key\n"
334 "is not in the database, it is inserted with default as the value."},
335 {NULL, NULL} /* sentinel */
336 };
337
338 static PyObject *
339 dbm_getattr(dbmobject *dp, char *name)
340 {
341 return Py_FindMethod(dbm_methods, (PyObject *)dp, name);
342 }
343
344 static PyTypeObject Dbmtype = {
345 PyVarObject_HEAD_INIT(NULL, 0)
346 "dbm.dbm",
347 sizeof(dbmobject),
348 0,
349 (destructor)dbm_dealloc, /*tp_dealloc*/
350 0, /*tp_print*/
351 (getattrfunc)dbm_getattr, /*tp_getattr*/
352 0, /*tp_setattr*/
353 0, /*tp_compare*/
354 0, /*tp_repr*/
355 0, /*tp_as_number*/
356 &dbm_as_sequence, /*tp_as_sequence*/
357 &dbm_as_mapping, /*tp_as_mapping*/
358 0, /*tp_hash*/
359 0, /*tp_call*/
360 0, /*tp_str*/
361 0, /*tp_getattro*/
362 0, /*tp_setattro*/
363 0, /*tp_as_buffer*/
364 Py_TPFLAGS_DEFAULT, /*tp_xxx4*/
365 };
366
367 /* ----------------------------------------------------------------- */
368
369 static PyObject *
370 dbmopen(PyObject *self, PyObject *args)
371 {
372 char *name;
373 char *flags = "r";
374 int iflags;
375 int mode = 0666;
376
377 if ( !PyArg_ParseTuple(args, "s|si:open", &name, &flags, &mode) )
378 return NULL;
379 if ( strcmp(flags, "r") == 0 )
380 iflags = O_RDONLY;
381 else if ( strcmp(flags, "w") == 0 )
382 iflags = O_RDWR;
383 else if ( strcmp(flags, "rw") == 0 ) /* B/W compat */
384 iflags = O_RDWR|O_CREAT;
385 else if ( strcmp(flags, "c") == 0 )
386 iflags = O_RDWR|O_CREAT;
387 else if ( strcmp(flags, "n") == 0 )
388 iflags = O_RDWR|O_CREAT|O_TRUNC;
389 else {
390 PyErr_SetString(DbmError,
391 "arg 2 to open should be 'r', 'w', 'c', or 'n'");
392 return NULL;
393 }
394 return newdbmobject(name, iflags, mode);
395 }
396
397 static PyMethodDef dbmmodule_methods[] = {
398 { "open", (PyCFunction)dbmopen, METH_VARARGS,
399 "open(path[, flag[, mode]]) -> mapping\n"
400 "Return a database object."},
401 { 0, 0 },
402 };
403
404 PyMODINIT_FUNC
405 initdbm(void) {
406 PyObject *m, *d, *s;
407
408 Dbmtype.ob_type = &PyType_Type;
409 m = Py_InitModule("dbm", dbmmodule_methods);
410 if (m == NULL)
411 return;
412 d = PyModule_GetDict(m);
413 if (DbmError == NULL)
414 DbmError = PyErr_NewException("dbm.error", NULL, NULL);
415 s = PyString_FromString(which_dbm);
416 if (s != NULL) {
417 PyDict_SetItemString(d, "library", s);
418 Py_DECREF(s);
419 }
420 if (DbmError != NULL)
421 PyDict_SetItemString(d, "error", DbmError);
422 }