Merged revisions 84359-84360 via svnmerge from
[python/dscho.git] / Modules / _gdbmmodule.c
blobf15fefdf8222cddf3ec2c983e6d13b6a10cd83a2
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_SetObject(PyExc_KeyError, key);
131 return NULL;
133 v = PyBytes_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 bytes or 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_SetObject(PyExc_KeyError, v);
157 return -1;
160 else {
161 if (!PyArg_Parse(w, "s#", &drec.dptr, &drec.dsize)) {
162 PyErr_SetString(PyExc_TypeError,
163 "gdbm mappings have byte or string elements only");
164 return -1;
166 errno = 0;
167 if (gdbm_store(dp->di_dbm, krec, drec, GDBM_REPLACE) < 0) {
168 if (errno != 0)
169 PyErr_SetFromErrno(DbmError);
170 else
171 PyErr_SetString(DbmError,
172 gdbm_strerror(gdbm_errno));
173 return -1;
176 return 0;
179 static PyMappingMethods dbm_as_mapping = {
180 (lenfunc)dbm_length, /*mp_length*/
181 (binaryfunc)dbm_subscript, /*mp_subscript*/
182 (objobjargproc)dbm_ass_sub, /*mp_ass_subscript*/
185 PyDoc_STRVAR(dbm_close__doc__,
186 "close() -> None\n\
187 Closes the database.");
189 static PyObject *
190 dbm_close(register dbmobject *dp, PyObject *unused)
192 if (dp->di_dbm)
193 gdbm_close(dp->di_dbm);
194 dp->di_dbm = NULL;
195 Py_INCREF(Py_None);
196 return Py_None;
199 /* XXX Should return a set or a set view */
200 PyDoc_STRVAR(dbm_keys__doc__,
201 "keys() -> list_of_keys\n\
202 Get a list of all keys in the database.");
204 static PyObject *
205 dbm_keys(register dbmobject *dp, PyObject *unused)
207 register PyObject *v, *item;
208 datum key, nextkey;
209 int err;
211 if (dp == NULL || !is_dbmobject(dp)) {
212 PyErr_BadInternalCall();
213 return NULL;
215 check_dbmobject_open(dp);
217 v = PyList_New(0);
218 if (v == NULL)
219 return NULL;
221 key = gdbm_firstkey(dp->di_dbm);
222 while (key.dptr) {
223 item = PyBytes_FromStringAndSize(key.dptr, key.dsize);
224 if (item == NULL) {
225 free(key.dptr);
226 Py_DECREF(v);
227 return NULL;
229 err = PyList_Append(v, item);
230 Py_DECREF(item);
231 if (err != 0) {
232 free(key.dptr);
233 Py_DECREF(v);
234 return NULL;
236 nextkey = gdbm_nextkey(dp->di_dbm, key);
237 free(key.dptr);
238 key = nextkey;
240 return v;
243 static int
244 dbm_contains(PyObject *self, PyObject *arg)
246 dbmobject *dp = (dbmobject *)self;
247 datum key;
249 if ((dp)->di_dbm == NULL) {
250 PyErr_SetString(DbmError,
251 "GDBM object has already been closed");
252 return -1;
254 if (!PyBytes_Check(arg)) {
255 PyErr_Format(PyExc_TypeError,
256 "gdbm key must be bytes, not %.100s",
257 arg->ob_type->tp_name);
258 return -1;
260 key.dptr = PyBytes_AS_STRING(arg);
261 key.dsize = PyBytes_GET_SIZE(arg);
262 return gdbm_exists(dp->di_dbm, key);
265 static PySequenceMethods dbm_as_sequence = {
266 0, /* sq_length */
267 0, /* sq_concat */
268 0, /* sq_repeat */
269 0, /* sq_item */
270 0, /* sq_slice */
271 0, /* sq_ass_item */
272 0, /* sq_ass_slice */
273 dbm_contains, /* sq_contains */
274 0, /* sq_inplace_concat */
275 0, /* sq_inplace_repeat */
278 PyDoc_STRVAR(dbm_firstkey__doc__,
279 "firstkey() -> key\n\
280 It's possible to loop over every key in the database using this method\n\
281 and the nextkey() method. The traversal is ordered by GDBM's internal\n\
282 hash values, and won't be sorted by the key values. This method\n\
283 returns the starting key.");
285 static PyObject *
286 dbm_firstkey(register dbmobject *dp, PyObject *unused)
288 register PyObject *v;
289 datum key;
291 check_dbmobject_open(dp);
292 key = gdbm_firstkey(dp->di_dbm);
293 if (key.dptr) {
294 v = PyBytes_FromStringAndSize(key.dptr, key.dsize);
295 free(key.dptr);
296 return v;
298 else {
299 Py_INCREF(Py_None);
300 return Py_None;
304 PyDoc_STRVAR(dbm_nextkey__doc__,
305 "nextkey(key) -> next_key\n\
306 Returns the key that follows key in the traversal.\n\
307 The following code prints every key in the database db, without having\n\
308 to create a list in memory that contains them all:\n\
310 k = db.firstkey()\n\
311 while k != None:\n\
312 print k\n\
313 k = db.nextkey(k)");
315 static PyObject *
316 dbm_nextkey(register dbmobject *dp, PyObject *args)
318 register PyObject *v;
319 datum key, nextkey;
321 if (!PyArg_ParseTuple(args, "s#:nextkey", &key.dptr, &key.dsize))
322 return NULL;
323 check_dbmobject_open(dp);
324 nextkey = gdbm_nextkey(dp->di_dbm, key);
325 if (nextkey.dptr) {
326 v = PyBytes_FromStringAndSize(nextkey.dptr, nextkey.dsize);
327 free(nextkey.dptr);
328 return v;
330 else {
331 Py_INCREF(Py_None);
332 return Py_None;
336 PyDoc_STRVAR(dbm_reorganize__doc__,
337 "reorganize() -> None\n\
338 If you have carried out a lot of deletions and would like to shrink\n\
339 the space used by the GDBM file, this routine will reorganize the\n\
340 database. GDBM will not shorten the length of a database file except\n\
341 by using this reorganization; otherwise, deleted file space will be\n\
342 kept and reused as new (key,value) pairs are added.");
344 static PyObject *
345 dbm_reorganize(register dbmobject *dp, PyObject *unused)
347 check_dbmobject_open(dp);
348 errno = 0;
349 if (gdbm_reorganize(dp->di_dbm) < 0) {
350 if (errno != 0)
351 PyErr_SetFromErrno(DbmError);
352 else
353 PyErr_SetString(DbmError, gdbm_strerror(gdbm_errno));
354 return NULL;
356 Py_INCREF(Py_None);
357 return Py_None;
360 PyDoc_STRVAR(dbm_sync__doc__,
361 "sync() -> None\n\
362 When the database has been opened in fast mode, this method forces\n\
363 any unwritten data to be written to the disk.");
365 static PyObject *
366 dbm_sync(register dbmobject *dp, PyObject *unused)
368 check_dbmobject_open(dp);
369 gdbm_sync(dp->di_dbm);
370 Py_INCREF(Py_None);
371 return Py_None;
374 static PyMethodDef dbm_methods[] = {
375 {"close", (PyCFunction)dbm_close, METH_NOARGS, dbm_close__doc__},
376 {"keys", (PyCFunction)dbm_keys, METH_NOARGS, dbm_keys__doc__},
377 {"firstkey", (PyCFunction)dbm_firstkey,METH_NOARGS, dbm_firstkey__doc__},
378 {"nextkey", (PyCFunction)dbm_nextkey, METH_VARARGS, dbm_nextkey__doc__},
379 {"reorganize",(PyCFunction)dbm_reorganize,METH_NOARGS, dbm_reorganize__doc__},
380 {"sync", (PyCFunction)dbm_sync, METH_NOARGS, dbm_sync__doc__},
381 {NULL, NULL} /* sentinel */
384 static PyTypeObject Dbmtype = {
385 PyVarObject_HEAD_INIT(0, 0)
386 "_gdbm.gdbm",
387 sizeof(dbmobject),
389 (destructor)dbm_dealloc, /*tp_dealloc*/
390 0, /*tp_print*/
391 0, /*tp_getattr*/
392 0, /*tp_setattr*/
393 0, /*tp_reserved*/
394 0, /*tp_repr*/
395 0, /*tp_as_number*/
396 &dbm_as_sequence, /*tp_as_sequence*/
397 &dbm_as_mapping, /*tp_as_mapping*/
398 0, /*tp_hash*/
399 0, /*tp_call*/
400 0, /*tp_str*/
401 0, /*tp_getattro*/
402 0, /*tp_setattro*/
403 0, /*tp_as_buffer*/
404 Py_TPFLAGS_DEFAULT, /*tp_xxx4*/
405 gdbm_object__doc__, /*tp_doc*/
406 0, /*tp_traverse*/
407 0, /*tp_clear*/
408 0, /*tp_richcompare*/
409 0, /*tp_weaklistoffset*/
410 0, /*tp_iter*/
411 0, /*tp_iternext*/
412 dbm_methods, /*tp_methods*/
415 /* ----------------------------------------------------------------- */
417 PyDoc_STRVAR(dbmopen__doc__,
418 "open(filename, [flags, [mode]]) -> dbm_object\n\
419 Open a dbm database and return a dbm object. The filename argument is\n\
420 the name of the database file.\n\
422 The optional flags argument can be 'r' (to open an existing database\n\
423 for reading only -- default), 'w' (to open an existing database for\n\
424 reading and writing), 'c' (which creates the database if it doesn't\n\
425 exist), or 'n' (which always creates a new empty database).\n\
427 Some versions of gdbm support additional flags which must be\n\
428 appended to one of the flags described above. The module constant\n\
429 'open_flags' is a string of valid additional flags. The 'f' flag\n\
430 opens the database in fast mode; altered data will not automatically\n\
431 be written to the disk after every change. This results in faster\n\
432 writes to the database, but may result in an inconsistent database\n\
433 if the program crashes while the database is still open. Use the\n\
434 sync() method to force any unwritten data to be written to the disk.\n\
435 The 's' flag causes all database operations to be synchronized to\n\
436 disk. The 'u' flag disables locking of the database file.\n\
438 The optional mode argument is the Unix mode of the file, used only\n\
439 when the database has to be created. It defaults to octal 0666. ");
441 static PyObject *
442 dbmopen(PyObject *self, PyObject *args)
444 char *name;
445 char *flags = "r";
446 int iflags;
447 int mode = 0666;
449 if (!PyArg_ParseTuple(args, "s|si:open", &name, &flags, &mode))
450 return NULL;
451 switch (flags[0]) {
452 case 'r':
453 iflags = GDBM_READER;
454 break;
455 case 'w':
456 iflags = GDBM_WRITER;
457 break;
458 case 'c':
459 iflags = GDBM_WRCREAT;
460 break;
461 case 'n':
462 iflags = GDBM_NEWDB;
463 break;
464 default:
465 PyErr_SetString(DbmError,
466 "First flag must be one of 'r', 'w', 'c' or 'n'");
467 return NULL;
469 for (flags++; *flags != '\0'; flags++) {
470 char buf[40];
471 switch (*flags) {
472 #ifdef GDBM_FAST
473 case 'f':
474 iflags |= GDBM_FAST;
475 break;
476 #endif
477 #ifdef GDBM_SYNC
478 case 's':
479 iflags |= GDBM_SYNC;
480 break;
481 #endif
482 #ifdef GDBM_NOLOCK
483 case 'u':
484 iflags |= GDBM_NOLOCK;
485 break;
486 #endif
487 default:
488 PyOS_snprintf(buf, sizeof(buf), "Flag '%c' is not supported.",
489 *flags);
490 PyErr_SetString(DbmError, buf);
491 return NULL;
495 return newdbmobject(name, iflags, mode);
498 static char dbmmodule_open_flags[] = "rwcn"
499 #ifdef GDBM_FAST
501 #endif
502 #ifdef GDBM_SYNC
504 #endif
505 #ifdef GDBM_NOLOCK
507 #endif
510 static PyMethodDef dbmmodule_methods[] = {
511 { "open", (PyCFunction)dbmopen, METH_VARARGS, dbmopen__doc__},
512 { 0, 0 },
516 static struct PyModuleDef _gdbmmodule = {
517 PyModuleDef_HEAD_INIT,
518 "_gdbm",
519 gdbmmodule__doc__,
521 dbmmodule_methods,
522 NULL,
523 NULL,
524 NULL,
525 NULL
528 PyMODINIT_FUNC
529 PyInit__gdbm(void) {
530 PyObject *m, *d, *s;
532 if (PyType_Ready(&Dbmtype) < 0)
533 return NULL;
534 m = PyModule_Create(&_gdbmmodule);
535 if (m == NULL)
536 return NULL;
537 d = PyModule_GetDict(m);
538 DbmError = PyErr_NewException("_gdbm.error", PyExc_IOError, NULL);
539 if (DbmError != NULL) {
540 PyDict_SetItemString(d, "error", DbmError);
541 s = PyUnicode_FromString(dbmmodule_open_flags);
542 PyDict_SetItemString(d, "open_flags", s);
543 Py_DECREF(s);
545 return m;