No issues found
1 /* DBM module using dictionary interface */
2 /* Author: Anthony Baxter, after dbmmodule.c */
3 /* Doc strings: Mitch Chapman */
4
5
6 #include "Python.h"
7
8 #include <sys/types.h>
9 #include <sys/stat.h>
10 #include <fcntl.h>
11 #include "gdbm.h"
12
13 #if defined(WIN32) && !defined(__CYGWIN__)
14 #include "gdbmerrno.h"
15 extern const char * gdbm_strerror(gdbm_error);
16 #endif
17
18 PyDoc_STRVAR(gdbmmodule__doc__,
19 "This module provides an interface to the GNU DBM (GDBM) library.\n\
20 \n\
21 This module is quite similar to the dbm module, but uses GDBM instead to\n\
22 provide some additional functionality. Please note that the file formats\n\
23 created by GDBM and dbm are incompatible. \n\
24 \n\
25 GDBM objects behave like mappings (dictionaries), except that keys and\n\
26 values are always strings. Printing a GDBM object doesn't print the\n\
27 keys and values, and the items() and values() methods are not\n\
28 supported.");
29
30 typedef struct {
31 PyObject_HEAD
32 int di_size; /* -1 means recompute */
33 GDBM_FILE di_dbm;
34 } dbmobject;
35
36 static PyTypeObject Dbmtype;
37
38 #define is_dbmobject(v) (Py_TYPE(v) == &Dbmtype)
39 #define check_dbmobject_open(v) if ((v)->di_dbm == NULL) \
40 { PyErr_SetString(DbmError, "GDBM object has already been closed"); \
41 return NULL; }
42
43
44
45 static PyObject *DbmError;
46
47 PyDoc_STRVAR(gdbm_object__doc__,
48 "This object represents a GDBM database.\n\
49 GDBM objects behave like mappings (dictionaries), except that keys and\n\
50 values are always strings. Printing a GDBM object doesn't print the\n\
51 keys and values, and the items() and values() methods are not\n\
52 supported.\n\
53 \n\
54 GDBM objects also support additional operations such as firstkey,\n\
55 nextkey, reorganize, and sync.");
56
57 static PyObject *
58 newdbmobject(char *file, int flags, int mode)
59 {
60 dbmobject *dp;
61
62 dp = PyObject_New(dbmobject, &Dbmtype);
63 if (dp == NULL)
64 return NULL;
65 dp->di_size = -1;
66 errno = 0;
67 if ((dp->di_dbm = gdbm_open(file, 0, flags, mode, NULL)) == 0) {
68 if (errno != 0)
69 PyErr_SetFromErrno(DbmError);
70 else
71 PyErr_SetString(DbmError, gdbm_strerror(gdbm_errno));
72 Py_DECREF(dp);
73 return NULL;
74 }
75 return (PyObject *)dp;
76 }
77
78 /* Methods */
79
80 static void
81 dbm_dealloc(register dbmobject *dp)
82 {
83 if (dp->di_dbm)
84 gdbm_close(dp->di_dbm);
85 PyObject_Del(dp);
86 }
87
88 static Py_ssize_t
89 dbm_length(dbmobject *dp)
90 {
91 if (dp->di_dbm == NULL) {
92 PyErr_SetString(DbmError, "GDBM object has already been closed");
93 return -1;
94 }
95 if (dp->di_size < 0) {
96 datum key,okey;
97 int size;
98 okey.dsize=0;
99 okey.dptr=NULL;
100
101 size = 0;
102 for (key=gdbm_firstkey(dp->di_dbm); key.dptr;
103 key = gdbm_nextkey(dp->di_dbm,okey)) {
104 size++;
105 if(okey.dsize) free(okey.dptr);
106 okey=key;
107 }
108 dp->di_size = size;
109 }
110 return dp->di_size;
111 }
112
113 static PyObject *
114 dbm_subscript(dbmobject *dp, register PyObject *key)
115 {
116 PyObject *v;
117 datum drec, krec;
118
119 if (!PyArg_Parse(key, "s#", &krec.dptr, &krec.dsize) )
120 return NULL;
121
122 if (dp->di_dbm == NULL) {
123 PyErr_SetString(DbmError,
124 "GDBM object has already been closed");
125 return NULL;
126 }
127 drec = gdbm_fetch(dp->di_dbm, krec);
128 if (drec.dptr == 0) {
129 PyErr_SetString(PyExc_KeyError,
130 PyString_AS_STRING((PyStringObject *)key));
131 return NULL;
132 }
133 v = PyString_FromStringAndSize(drec.dptr, drec.dsize);
134 free(drec.dptr);
135 return v;
136 }
137
138 static int
139 dbm_ass_sub(dbmobject *dp, PyObject *v, PyObject *w)
140 {
141 datum krec, drec;
142
143 if (!PyArg_Parse(v, "s#", &krec.dptr, &krec.dsize) ) {
144 PyErr_SetString(PyExc_TypeError,
145 "gdbm mappings have string indices only");
146 return -1;
147 }
148 if (dp->di_dbm == NULL) {
149 PyErr_SetString(DbmError,
150 "GDBM object has already been closed");
151 return -1;
152 }
153 dp->di_size = -1;
154 if (w == NULL) {
155 if (gdbm_delete(dp->di_dbm, krec) < 0) {
156 PyErr_SetString(PyExc_KeyError,
157 PyString_AS_STRING((PyStringObject *)v));
158 return -1;
159 }
160 }
161 else {
162 if (!PyArg_Parse(w, "s#", &drec.dptr, &drec.dsize)) {
163 PyErr_SetString(PyExc_TypeError,
164 "gdbm mappings have string elements only");
165 return -1;
166 }
167 errno = 0;
168 if (gdbm_store(dp->di_dbm, krec, drec, GDBM_REPLACE) < 0) {
169 if (errno != 0)
170 PyErr_SetFromErrno(DbmError);
171 else
172 PyErr_SetString(DbmError,
173 gdbm_strerror(gdbm_errno));
174 return -1;
175 }
176 }
177 return 0;
178 }
179
180 static int
181 dbm_contains(register dbmobject *dp, PyObject *arg)
182 {
183 datum key;
184
185 if ((dp)->di_dbm == NULL) {
186 PyErr_SetString(DbmError,
187 "GDBM object has already been closed");
188 return -1;
189 }
190 if (!PyString_Check(arg)) {
191 PyErr_Format(PyExc_TypeError,
192 "gdbm key must be string, not %.100s",
193 arg->ob_type->tp_name);
194 return -1;
195 }
196 key.dptr = PyString_AS_STRING(arg);
197 key.dsize = PyString_GET_SIZE(arg);
198 return gdbm_exists(dp->di_dbm, key);
199 }
200
201 static PySequenceMethods dbm_as_sequence = {
202 (lenfunc)dbm_length, /*_length*/
203 0, /*sq_concat*/
204 0, /*sq_repeat*/
205 0, /*sq_item*/
206 0, /*sq_slice*/
207 0, /*sq_ass_item*/
208 0, /*sq_ass_slice*/
209 (objobjproc)dbm_contains, /*sq_contains*/
210 0, /*sq_inplace_concat*/
211 0 /*sq_inplace_repeat*/
212 };
213
214 static PyMappingMethods dbm_as_mapping = {
215 (lenfunc)dbm_length, /*mp_length*/
216 (binaryfunc)dbm_subscript, /*mp_subscript*/
217 (objobjargproc)dbm_ass_sub, /*mp_ass_subscript*/
218 };
219
220 PyDoc_STRVAR(dbm_close__doc__,
221 "close() -> None\n\
222 Closes the database.");
223
224 static PyObject *
225 dbm_close(register dbmobject *dp, PyObject *unused)
226 {
227 if (dp->di_dbm)
228 gdbm_close(dp->di_dbm);
229 dp->di_dbm = NULL;
230 Py_INCREF(Py_None);
231 return Py_None;
232 }
233
234 PyDoc_STRVAR(dbm_keys__doc__,
235 "keys() -> list_of_keys\n\
236 Get a list of all keys in the database.");
237
238 static PyObject *
239 dbm_keys(register dbmobject *dp, PyObject *unused)
240 {
241 register PyObject *v, *item;
242 datum key, nextkey;
243 int err;
244
245 if (dp == NULL || !is_dbmobject(dp)) {
246 PyErr_BadInternalCall();
247 return NULL;
248 }
249 check_dbmobject_open(dp);
250
251 v = PyList_New(0);
252 if (v == NULL)
253 return NULL;
254
255 key = gdbm_firstkey(dp->di_dbm);
256 while (key.dptr) {
257 item = PyString_FromStringAndSize(key.dptr, key.dsize);
258 if (item == NULL) {
259 free(key.dptr);
260 Py_DECREF(v);
261 return NULL;
262 }
263 err = PyList_Append(v, item);
264 Py_DECREF(item);
265 if (err != 0) {
266 free(key.dptr);
267 Py_DECREF(v);
268 return NULL;
269 }
270 nextkey = gdbm_nextkey(dp->di_dbm, key);
271 free(key.dptr);
272 key = nextkey;
273 }
274 return v;
275 }
276
277 PyDoc_STRVAR(dbm_has_key__doc__,
278 "has_key(key) -> boolean\n\
279 Find out whether or not the database contains a given key.");
280
281 static PyObject *
282 dbm_has_key(register dbmobject *dp, PyObject *args)
283 {
284 datum key;
285
286 if (!PyArg_ParseTuple(args, "s#:has_key", &key.dptr, &key.dsize))
287 return NULL;
288 check_dbmobject_open(dp);
289 return PyInt_FromLong((long) gdbm_exists(dp->di_dbm, key));
290 }
291
292 PyDoc_STRVAR(dbm_firstkey__doc__,
293 "firstkey() -> key\n\
294 It's possible to loop over every key in the database using this method\n\
295 and the nextkey() method. The traversal is ordered by GDBM's internal\n\
296 hash values, and won't be sorted by the key values. This method\n\
297 returns the starting key.");
298
299 static PyObject *
300 dbm_firstkey(register dbmobject *dp, PyObject *unused)
301 {
302 register PyObject *v;
303 datum key;
304
305 check_dbmobject_open(dp);
306 key = gdbm_firstkey(dp->di_dbm);
307 if (key.dptr) {
308 v = PyString_FromStringAndSize(key.dptr, key.dsize);
309 free(key.dptr);
310 return v;
311 }
312 else {
313 Py_INCREF(Py_None);
314 return Py_None;
315 }
316 }
317
318 PyDoc_STRVAR(dbm_nextkey__doc__,
319 "nextkey(key) -> next_key\n\
320 Returns the key that follows key in the traversal.\n\
321 The following code prints every key in the database db, without having\n\
322 to create a list in memory that contains them all:\n\
323 \n\
324 k = db.firstkey()\n\
325 while k != None:\n\
326 print k\n\
327 k = db.nextkey(k)");
328
329 static PyObject *
330 dbm_nextkey(register dbmobject *dp, PyObject *args)
331 {
332 register PyObject *v;
333 datum key, nextkey;
334
335 if (!PyArg_ParseTuple(args, "s#:nextkey", &key.dptr, &key.dsize))
336 return NULL;
337 check_dbmobject_open(dp);
338 nextkey = gdbm_nextkey(dp->di_dbm, key);
339 if (nextkey.dptr) {
340 v = PyString_FromStringAndSize(nextkey.dptr, nextkey.dsize);
341 free(nextkey.dptr);
342 return v;
343 }
344 else {
345 Py_INCREF(Py_None);
346 return Py_None;
347 }
348 }
349
350 PyDoc_STRVAR(dbm_reorganize__doc__,
351 "reorganize() -> None\n\
352 If you have carried out a lot of deletions and would like to shrink\n\
353 the space used by the GDBM file, this routine will reorganize the\n\
354 database. GDBM will not shorten the length of a database file except\n\
355 by using this reorganization; otherwise, deleted file space will be\n\
356 kept and reused as new (key,value) pairs are added.");
357
358 static PyObject *
359 dbm_reorganize(register dbmobject *dp, PyObject *unused)
360 {
361 check_dbmobject_open(dp);
362 errno = 0;
363 if (gdbm_reorganize(dp->di_dbm) < 0) {
364 if (errno != 0)
365 PyErr_SetFromErrno(DbmError);
366 else
367 PyErr_SetString(DbmError, gdbm_strerror(gdbm_errno));
368 return NULL;
369 }
370 Py_INCREF(Py_None);
371 return Py_None;
372 }
373
374 PyDoc_STRVAR(dbm_sync__doc__,
375 "sync() -> None\n\
376 When the database has been opened in fast mode, this method forces\n\
377 any unwritten data to be written to the disk.");
378
379 static PyObject *
380 dbm_sync(register dbmobject *dp, PyObject *unused)
381 {
382 check_dbmobject_open(dp);
383 gdbm_sync(dp->di_dbm);
384 Py_INCREF(Py_None);
385 return Py_None;
386 }
387
388 static PyMethodDef dbm_methods[] = {
389 {"close", (PyCFunction)dbm_close, METH_NOARGS, dbm_close__doc__},
390 {"keys", (PyCFunction)dbm_keys, METH_NOARGS, dbm_keys__doc__},
391 {"has_key", (PyCFunction)dbm_has_key, METH_VARARGS, dbm_has_key__doc__},
392 {"firstkey", (PyCFunction)dbm_firstkey,METH_NOARGS, dbm_firstkey__doc__},
393 {"nextkey", (PyCFunction)dbm_nextkey, METH_VARARGS, dbm_nextkey__doc__},
394 {"reorganize",(PyCFunction)dbm_reorganize,METH_NOARGS, dbm_reorganize__doc__},
395 {"sync", (PyCFunction)dbm_sync, METH_NOARGS, dbm_sync__doc__},
396 {NULL, NULL} /* sentinel */
397 };
398
399 static PyObject *
400 dbm_getattr(dbmobject *dp, char *name)
401 {
402 return Py_FindMethod(dbm_methods, (PyObject *)dp, name);
403 }
404
405 static PyTypeObject Dbmtype = {
406 PyVarObject_HEAD_INIT(0, 0)
407 "gdbm.gdbm",
408 sizeof(dbmobject),
409 0,
410 (destructor)dbm_dealloc, /*tp_dealloc*/
411 0, /*tp_print*/
412 (getattrfunc)dbm_getattr, /*tp_getattr*/
413 0, /*tp_setattr*/
414 0, /*tp_compare*/
415 0, /*tp_repr*/
416 0, /*tp_as_number*/
417 &dbm_as_sequence, /*tp_as_sequence*/
418 &dbm_as_mapping, /*tp_as_mapping*/
419 0, /*tp_hash*/
420 0, /*tp_call*/
421 0, /*tp_str*/
422 0, /*tp_getattro*/
423 0, /*tp_setattro*/
424 0, /*tp_as_buffer*/
425 Py_TPFLAGS_DEFAULT, /*tp_xxx4*/
426 gdbm_object__doc__, /*tp_doc*/
427 };
428
429 /* ----------------------------------------------------------------- */
430
431 PyDoc_STRVAR(dbmopen__doc__,
432 "open(filename, [flags, [mode]]) -> dbm_object\n\
433 Open a dbm database and return a dbm object. The filename argument is\n\
434 the name of the database file.\n\
435 \n\
436 The optional flags argument can be 'r' (to open an existing database\n\
437 for reading only -- default), 'w' (to open an existing database for\n\
438 reading and writing), 'c' (which creates the database if it doesn't\n\
439 exist), or 'n' (which always creates a new empty database).\n\
440 \n\
441 Some versions of gdbm support additional flags which must be\n\
442 appended to one of the flags described above. The module constant\n\
443 'open_flags' is a string of valid additional flags. The 'f' flag\n\
444 opens the database in fast mode; altered data will not automatically\n\
445 be written to the disk after every change. This results in faster\n\
446 writes to the database, but may result in an inconsistent database\n\
447 if the program crashes while the database is still open. Use the\n\
448 sync() method to force any unwritten data to be written to the disk.\n\
449 The 's' flag causes all database operations to be synchronized to\n\
450 disk. The 'u' flag disables locking of the database file.\n\
451 \n\
452 The optional mode argument is the Unix mode of the file, used only\n\
453 when the database has to be created. It defaults to octal 0666. ");
454
455 static PyObject *
456 dbmopen(PyObject *self, PyObject *args)
457 {
458 char *name;
459 char *flags = "r";
460 int iflags;
461 int mode = 0666;
462
463 if (!PyArg_ParseTuple(args, "s|si:open", &name, &flags, &mode))
464 return NULL;
465 switch (flags[0]) {
466 case 'r':
467 iflags = GDBM_READER;
468 break;
469 case 'w':
470 iflags = GDBM_WRITER;
471 break;
472 case 'c':
473 iflags = GDBM_WRCREAT;
474 break;
475 case 'n':
476 iflags = GDBM_NEWDB;
477 break;
478 default:
479 PyErr_SetString(DbmError,
480 "First flag must be one of 'r', 'w', 'c' or 'n'");
481 return NULL;
482 }
483 for (flags++; *flags != '\0'; flags++) {
484 char buf[40];
485 switch (*flags) {
486 #ifdef GDBM_FAST
487 case 'f':
488 iflags |= GDBM_FAST;
489 break;
490 #endif
491 #ifdef GDBM_SYNC
492 case 's':
493 iflags |= GDBM_SYNC;
494 break;
495 #endif
496 #ifdef GDBM_NOLOCK
497 case 'u':
498 iflags |= GDBM_NOLOCK;
499 break;
500 #endif
501 default:
502 PyOS_snprintf(buf, sizeof(buf), "Flag '%c' is not supported.",
503 *flags);
504 PyErr_SetString(DbmError, buf);
505 return NULL;
506 }
507 }
508
509 return newdbmobject(name, iflags, mode);
510 }
511
512 static char dbmmodule_open_flags[] = "rwcn"
513 #ifdef GDBM_FAST
514 "f"
515 #endif
516 #ifdef GDBM_SYNC
517 "s"
518 #endif
519 #ifdef GDBM_NOLOCK
520 "u"
521 #endif
522 ;
523
524 static PyMethodDef dbmmodule_methods[] = {
525 { "open", (PyCFunction)dbmopen, METH_VARARGS, dbmopen__doc__},
526 { 0, 0 },
527 };
528
529 PyMODINIT_FUNC
530 initgdbm(void) {
531 PyObject *m, *d, *s;
532
533 Dbmtype.ob_type = &PyType_Type;
534 m = Py_InitModule4("gdbm", dbmmodule_methods,
535 gdbmmodule__doc__, (PyObject *)NULL,
536 PYTHON_API_VERSION);
537 if (m == NULL)
538 return;
539 d = PyModule_GetDict(m);
540 DbmError = PyErr_NewException("gdbm.error", NULL, NULL);
541 if (DbmError != NULL) {
542 PyDict_SetItemString(d, "error", DbmError);
543 s = PyString_FromString(dbmmodule_open_flags);
544 PyDict_SetItemString(d, "open_flags", s);
545 Py_DECREF(s);
546 }
547 }