Fixed bug in time-to-midnight calculation.
[python.git] / Modules / gdbmmodule.c
blob03e664d6bc30cb60dea16bb93f6f3b46b6f89802
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) ((v)->ob_type == &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 int
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;
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;
108 dp->di_size = size;
110 return dp->di_size;
113 static PyObject *
114 dbm_subscript(dbmobject *dp, register PyObject *key)
116 PyObject *v;
117 datum drec, krec;
119 if (!PyArg_Parse(key, "s#", &krec.dptr, &krec.dsize) )
120 return NULL;
122 if (dp->di_dbm == NULL) {
123 PyErr_SetString(DbmError,
124 "GDBM object has already been closed");
125 return NULL;
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;
133 v = PyString_FromStringAndSize(drec.dptr, drec.dsize);
134 free(drec.dptr);
135 return v;
138 static int
139 dbm_ass_sub(dbmobject *dp, PyObject *v, PyObject *w)
141 datum krec, drec;
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;
148 if (dp->di_dbm == NULL) {
149 PyErr_SetString(DbmError,
150 "GDBM object has already been closed");
151 return -1;
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;
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;
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;
177 return 0;
180 static PyMappingMethods dbm_as_mapping = {
181 (inquiry)dbm_length, /*mp_length*/
182 (binaryfunc)dbm_subscript, /*mp_subscript*/
183 (objobjargproc)dbm_ass_sub, /*mp_ass_subscript*/
186 PyDoc_STRVAR(dbm_close__doc__,
187 "close() -> None\n\
188 Closes the database.");
190 static PyObject *
191 dbm_close(register dbmobject *dp, PyObject *args)
193 if (!PyArg_ParseTuple(args, ":close"))
194 return NULL;
195 if (dp->di_dbm)
196 gdbm_close(dp->di_dbm);
197 dp->di_dbm = NULL;
198 Py_INCREF(Py_None);
199 return Py_None;
202 PyDoc_STRVAR(dbm_keys__doc__,
203 "keys() -> list_of_keys\n\
204 Get a list of all keys in the database.");
206 static PyObject *
207 dbm_keys(register dbmobject *dp, PyObject *args)
209 register PyObject *v, *item;
210 datum key, nextkey;
211 int err;
213 if (dp == NULL || !is_dbmobject(dp)) {
214 PyErr_BadInternalCall();
215 return NULL;
217 if (!PyArg_ParseTuple(args, ":keys"))
218 return NULL;
220 check_dbmobject_open(dp);
222 v = PyList_New(0);
223 if (v == NULL)
224 return NULL;
226 key = gdbm_firstkey(dp->di_dbm);
227 while (key.dptr) {
228 item = PyString_FromStringAndSize(key.dptr, key.dsize);
229 if (item == NULL) {
230 free(key.dptr);
231 Py_DECREF(v);
232 return NULL;
234 err = PyList_Append(v, item);
235 Py_DECREF(item);
236 if (err != 0) {
237 free(key.dptr);
238 Py_DECREF(v);
239 return NULL;
241 nextkey = gdbm_nextkey(dp->di_dbm, key);
242 free(key.dptr);
243 key = nextkey;
245 return v;
248 PyDoc_STRVAR(dbm_has_key__doc__,
249 "has_key(key) -> boolean\n\
250 Find out whether or not the database contains a given key.");
252 static PyObject *
253 dbm_has_key(register dbmobject *dp, PyObject *args)
255 datum key;
257 if (!PyArg_ParseTuple(args, "s#:has_key", &key.dptr, &key.dsize))
258 return NULL;
259 check_dbmobject_open(dp);
260 return PyInt_FromLong((long) gdbm_exists(dp->di_dbm, key));
263 PyDoc_STRVAR(dbm_firstkey__doc__,
264 "firstkey() -> key\n\
265 It's possible to loop over every key in the database using this method\n\
266 and the nextkey() method. The traversal is ordered by GDBM's internal\n\
267 hash values, and won't be sorted by the key values. This method\n\
268 returns the starting key.");
270 static PyObject *
271 dbm_firstkey(register dbmobject *dp, PyObject *args)
273 register PyObject *v;
274 datum key;
276 if (!PyArg_ParseTuple(args, ":firstkey"))
277 return NULL;
278 check_dbmobject_open(dp);
279 key = gdbm_firstkey(dp->di_dbm);
280 if (key.dptr) {
281 v = PyString_FromStringAndSize(key.dptr, key.dsize);
282 free(key.dptr);
283 return v;
285 else {
286 Py_INCREF(Py_None);
287 return Py_None;
291 PyDoc_STRVAR(dbm_nextkey__doc__,
292 "nextkey(key) -> next_key\n\
293 Returns the key that follows key in the traversal.\n\
294 The following code prints every key in the database db, without having\n\
295 to create a list in memory that contains them all:\n\
297 k = db.firstkey()\n\
298 while k != None:\n\
299 print k\n\
300 k = db.nextkey(k)");
302 static PyObject *
303 dbm_nextkey(register dbmobject *dp, PyObject *args)
305 register PyObject *v;
306 datum key, nextkey;
308 if (!PyArg_ParseTuple(args, "s#:nextkey", &key.dptr, &key.dsize))
309 return NULL;
310 check_dbmobject_open(dp);
311 nextkey = gdbm_nextkey(dp->di_dbm, key);
312 if (nextkey.dptr) {
313 v = PyString_FromStringAndSize(nextkey.dptr, nextkey.dsize);
314 free(nextkey.dptr);
315 return v;
317 else {
318 Py_INCREF(Py_None);
319 return Py_None;
323 PyDoc_STRVAR(dbm_reorganize__doc__,
324 "reorganize() -> None\n\
325 If you have carried out a lot of deletions and would like to shrink\n\
326 the space used by the GDBM file, this routine will reorganize the\n\
327 database. GDBM will not shorten the length of a database file except\n\
328 by using this reorganization; otherwise, deleted file space will be\n\
329 kept and reused as new (key,value) pairs are added.");
331 static PyObject *
332 dbm_reorganize(register dbmobject *dp, PyObject *args)
334 if (!PyArg_ParseTuple(args, ":reorganize"))
335 return NULL;
336 check_dbmobject_open(dp);
337 errno = 0;
338 if (gdbm_reorganize(dp->di_dbm) < 0) {
339 if (errno != 0)
340 PyErr_SetFromErrno(DbmError);
341 else
342 PyErr_SetString(DbmError, gdbm_strerror(gdbm_errno));
343 return NULL;
345 Py_INCREF(Py_None);
346 return Py_None;
349 PyDoc_STRVAR(dbm_sync__doc__,
350 "sync() -> None\n\
351 When the database has been opened in fast mode, this method forces\n\
352 any unwritten data to be written to the disk.");
354 static PyObject *
355 dbm_sync(register dbmobject *dp, PyObject *args)
357 if (!PyArg_ParseTuple(args, ":sync"))
358 return NULL;
359 check_dbmobject_open(dp);
360 gdbm_sync(dp->di_dbm);
361 Py_INCREF(Py_None);
362 return Py_None;
365 static PyMethodDef dbm_methods[] = {
366 {"close", (PyCFunction)dbm_close, METH_VARARGS, dbm_close__doc__},
367 {"keys", (PyCFunction)dbm_keys, METH_VARARGS, dbm_keys__doc__},
368 {"has_key", (PyCFunction)dbm_has_key, METH_VARARGS, dbm_has_key__doc__},
369 {"firstkey", (PyCFunction)dbm_firstkey,METH_VARARGS, dbm_firstkey__doc__},
370 {"nextkey", (PyCFunction)dbm_nextkey, METH_VARARGS, dbm_nextkey__doc__},
371 {"reorganize",(PyCFunction)dbm_reorganize,METH_VARARGS, dbm_reorganize__doc__},
372 {"sync", (PyCFunction)dbm_sync, METH_VARARGS, dbm_sync__doc__},
373 {NULL, NULL} /* sentinel */
376 static PyObject *
377 dbm_getattr(dbmobject *dp, char *name)
379 return Py_FindMethod(dbm_methods, (PyObject *)dp, name);
382 static PyTypeObject Dbmtype = {
383 PyObject_HEAD_INIT(0)
385 "gdbm.gdbm",
386 sizeof(dbmobject),
388 (destructor)dbm_dealloc, /*tp_dealloc*/
389 0, /*tp_print*/
390 (getattrfunc)dbm_getattr, /*tp_getattr*/
391 0, /*tp_setattr*/
392 0, /*tp_compare*/
393 0, /*tp_repr*/
394 0, /*tp_as_number*/
395 0, /*tp_as_sequence*/
396 &dbm_as_mapping, /*tp_as_mapping*/
397 0, /*tp_hash*/
398 0, /*tp_call*/
399 0, /*tp_str*/
400 0, /*tp_getattro*/
401 0, /*tp_setattro*/
402 0, /*tp_as_buffer*/
403 0, /*tp_xxx4*/
404 gdbm_object__doc__, /*tp_doc*/
407 /* ----------------------------------------------------------------- */
409 PyDoc_STRVAR(dbmopen__doc__,
410 "open(filename, [flags, [mode]]) -> dbm_object\n\
411 Open a dbm database and return a dbm object. The filename argument is\n\
412 the name of the database file.\n\
414 The optional flags argument can be 'r' (to open an existing database\n\
415 for reading only -- default), 'w' (to open an existing database for\n\
416 reading and writing), 'c' (which creates the database if it doesn't\n\
417 exist), or 'n' (which always creates a new empty database).\n\
419 Some versions of gdbm support additional flags which must be\n\
420 appended to one of the flags described above. The module constant\n\
421 'open_flags' is a string of valid additional flags. The 'f' flag\n\
422 opens the database in fast mode; altered data will not automatically\n\
423 be written to the disk after every change. This results in faster\n\
424 writes to the database, but may result in an inconsistent database\n\
425 if the program crashes while the database is still open. Use the\n\
426 sync() method to force any unwritten data to be written to the disk.\n\
427 The 's' flag causes all database operations to be synchronized to\n\
428 disk. The 'u' flag disables locking of the database file.\n\
430 The optional mode argument is the Unix mode of the file, used only\n\
431 when the database has to be created. It defaults to octal 0666. ");
433 static PyObject *
434 dbmopen(PyObject *self, PyObject *args)
436 char *name;
437 char *flags = "r";
438 int iflags;
439 int mode = 0666;
441 if (!PyArg_ParseTuple(args, "s|si:open", &name, &flags, &mode))
442 return NULL;
443 switch (flags[0]) {
444 case 'r':
445 iflags = GDBM_READER;
446 break;
447 case 'w':
448 iflags = GDBM_WRITER;
449 break;
450 case 'c':
451 iflags = GDBM_WRCREAT;
452 break;
453 case 'n':
454 iflags = GDBM_NEWDB;
455 break;
456 default:
457 PyErr_SetString(DbmError,
458 "First flag must be one of 'r', 'w', 'c' or 'n'");
459 return NULL;
461 for (flags++; *flags != '\0'; flags++) {
462 char buf[40];
463 switch (*flags) {
464 #ifdef GDBM_FAST
465 case 'f':
466 iflags |= GDBM_FAST;
467 break;
468 #endif
469 #ifdef GDBM_SYNC
470 case 's':
471 iflags |= GDBM_SYNC;
472 break;
473 #endif
474 #ifdef GDBM_NOLOCK
475 case 'u':
476 iflags |= GDBM_NOLOCK;
477 break;
478 #endif
479 default:
480 PyOS_snprintf(buf, sizeof(buf), "Flag '%c' is not supported.",
481 *flags);
482 PyErr_SetString(DbmError, buf);
483 return NULL;
487 return newdbmobject(name, iflags, mode);
490 static char dbmmodule_open_flags[] = "rwcn"
491 #ifdef GDBM_FAST
493 #endif
494 #ifdef GDBM_SYNC
496 #endif
497 #ifdef GDBM_NOLOCK
499 #endif
502 static PyMethodDef dbmmodule_methods[] = {
503 { "open", (PyCFunction)dbmopen, METH_VARARGS, dbmopen__doc__},
504 { 0, 0 },
507 PyMODINIT_FUNC
508 initgdbm(void) {
509 PyObject *m, *d, *s;
511 Dbmtype.ob_type = &PyType_Type;
512 m = Py_InitModule4("gdbm", dbmmodule_methods,
513 gdbmmodule__doc__, (PyObject *)NULL,
514 PYTHON_API_VERSION);
515 d = PyModule_GetDict(m);
516 DbmError = PyErr_NewException("gdbm.error", NULL, NULL);
517 if (DbmError != NULL) {
518 PyDict_SetItemString(d, "error", DbmError);
519 s = PyString_FromString(dbmmodule_open_flags);
520 PyDict_SetItemString(d, "open_flags", s);
521 Py_DECREF(s);