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