source: vendor/python/2.5/Modules/gdbmmodule.c

Last change on this file was 3225, checked in by bird, 18 years ago

Python 2.5

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