Clarify portability and main program.
[python/dscho.git] / Modules / gdbmmodule.c
blobae716ac4949e6de8b4c0fdfc3bd981ca02000483
1 /***********************************************************
2 Copyright 1991-1995 by Stichting Mathematisch Centrum, Amsterdam,
3 The Netherlands.
5 All Rights Reserved
7 Permission to use, copy, modify, and distribute this software and its
8 documentation for any purpose and without fee is hereby granted,
9 provided that the above copyright notice appear in all copies and that
10 both that copyright notice and this permission notice appear in
11 supporting documentation, and that the names of Stichting Mathematisch
12 Centrum or CWI or Corporation for National Research Initiatives or
13 CNRI not be used in advertising or publicity pertaining to
14 distribution of the software without specific, written prior
15 permission.
17 While CWI is the initial source for this software, a modified version
18 is made available by the Corporation for National Research Initiatives
19 (CNRI) at the Internet address ftp://ftp.python.org.
21 STICHTING MATHEMATISCH CENTRUM AND CNRI DISCLAIM ALL WARRANTIES WITH
22 REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
23 MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH
24 CENTRUM OR CNRI BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
25 DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
26 PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
27 TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
28 PERFORMANCE OF THIS SOFTWARE.
30 ******************************************************************/
32 /* DBM module using dictionary interface */
33 /* Author: Anthony Baxter, after dbmmodule.c */
34 /* Doc strings: Mitch Chapman */
37 #include "Python.h"
39 #include <sys/types.h>
40 #include <sys/stat.h>
41 #include <fcntl.h>
42 #include "gdbm.h"
44 #ifdef WIN32
45 #include "gdbmerrno.h"
46 extern const char * gdbm_strerror(gdbm_error);
47 #endif
49 static char gdbmmodule__doc__[] = "\
50 This module provides an interface to the GNU DBM (GDBM) library.\n\
51 \n\
52 This module is quite similar to the dbm module, but uses GDBM instead to\n\
53 provide some additional functionality. Please note that the file formats\n\
54 created by GDBM and dbm are incompatible. \n\
55 \n\
56 GDBM objects behave like mappings (dictionaries), except that keys and\n\
57 values are always strings. Printing a GDBM object doesn't print the\n\
58 keys and values, and the items() and values() methods are not\n\
59 supported.";
61 typedef struct {
62 PyObject_HEAD
63 int di_size; /* -1 means recompute */
64 GDBM_FILE di_dbm;
65 } dbmobject;
67 staticforward PyTypeObject Dbmtype;
69 #define is_dbmobject(v) ((v)->ob_type == &Dbmtype)
70 #define check_dbmobject_open(v) if ((v)->di_dbm == NULL) \
71 { PyErr_SetString(DbmError, "GDBM object has already been closed"); \
72 return NULL; }
76 static PyObject *DbmError;
78 static char gdbm_object__doc__[] = "\
79 This object represents a GDBM database.\n\
80 GDBM objects behave like mappings (dictionaries), except that keys and\n\
81 values are always strings. Printing a GDBM object doesn't print the\n\
82 keys and values, and the items() and values() methods are not\n\
83 supported.\n\
84 \n\
85 GDBM objects also support additional operations such as firstkey,\n\
86 nextkey, reorganize, and sync.";
88 static PyObject *
89 newdbmobject(file, flags, mode)
90 char *file;
91 int flags;
92 int mode;
94 dbmobject *dp;
96 dp = PyObject_NEW(dbmobject, &Dbmtype);
97 if (dp == NULL)
98 return NULL;
99 dp->di_size = -1;
100 errno = 0;
101 if ( (dp->di_dbm = gdbm_open(file, 0, flags, mode, NULL)) == 0 ) {
102 if (errno != 0)
103 PyErr_SetFromErrno(DbmError);
104 else
105 PyErr_SetString(DbmError, gdbm_strerror(gdbm_errno));
106 Py_DECREF(dp);
107 return NULL;
109 return (PyObject *)dp;
112 /* Methods */
114 static void
115 dbm_dealloc(dp)
116 register dbmobject *dp;
118 if ( dp->di_dbm )
119 gdbm_close(dp->di_dbm);
120 PyMem_DEL(dp);
123 static int
124 dbm_length(dp)
125 dbmobject *dp;
127 if (dp->di_dbm == NULL) {
128 PyErr_SetString(DbmError, "GDBM object has already been closed");
129 return -1;
131 if ( dp->di_size < 0 ) {
132 datum key,okey;
133 int size;
134 okey.dsize=0;
136 size = 0;
137 for ( key=gdbm_firstkey(dp->di_dbm); key.dptr;
138 key = gdbm_nextkey(dp->di_dbm,okey)) {
139 size++;
140 if(okey.dsize) free(okey.dptr);
141 okey=key;
143 dp->di_size = size;
145 return dp->di_size;
148 static PyObject *
149 dbm_subscript(dp, key)
150 dbmobject *dp;
151 register PyObject *key;
153 PyObject *v;
154 datum drec, krec;
156 if (!PyArg_Parse(key, "s#", &krec.dptr, &krec.dsize) )
157 return NULL;
159 drec = gdbm_fetch(dp->di_dbm, krec);
160 if ( drec.dptr == 0 ) {
161 PyErr_SetString(PyExc_KeyError,
162 PyString_AS_STRING((PyStringObject *)key));
163 return NULL;
165 v = PyString_FromStringAndSize(drec.dptr, drec.dsize);
166 free(drec.dptr);
167 return v;
170 static int
171 dbm_ass_sub(dp, v, w)
172 dbmobject *dp;
173 PyObject *v, *w;
175 datum krec, drec;
177 if ( !PyArg_Parse(v, "s#", &krec.dptr, &krec.dsize) ) {
178 PyErr_SetString(PyExc_TypeError,
179 "gdbm mappings have string indices only");
180 return -1;
182 if (dp->di_dbm == NULL) {
183 PyErr_SetString(DbmError, "GDBM object has already been closed");
184 return -1;
186 dp->di_size = -1;
187 if (w == NULL) {
188 if ( gdbm_delete(dp->di_dbm, krec) < 0 ) {
189 PyErr_SetString(PyExc_KeyError,
190 PyString_AS_STRING((PyStringObject *)v));
191 return -1;
193 } else {
194 if ( !PyArg_Parse(w, "s#", &drec.dptr, &drec.dsize) ) {
195 PyErr_SetString(PyExc_TypeError,
196 "gdbm mappings have string elements only");
197 return -1;
199 errno = 0;
200 if ( gdbm_store(dp->di_dbm, krec, drec, GDBM_REPLACE) < 0 ) {
201 if (errno != 0)
202 PyErr_SetFromErrno(DbmError);
203 else
204 PyErr_SetString(DbmError,
205 gdbm_strerror(gdbm_errno));
206 return -1;
209 return 0;
212 static PyMappingMethods dbm_as_mapping = {
213 (inquiry)dbm_length, /*mp_length*/
214 (binaryfunc)dbm_subscript, /*mp_subscript*/
215 (objobjargproc)dbm_ass_sub, /*mp_ass_subscript*/
218 static char dbm_close__doc__[] = "\
219 close() -> None\n\
220 Closes the database.";
222 static PyObject *
223 dbm_close(dp, args)
224 register dbmobject *dp;
225 PyObject *args;
227 if ( !PyArg_NoArgs(args) )
228 return NULL;
229 if ( dp->di_dbm )
230 gdbm_close(dp->di_dbm);
231 dp->di_dbm = NULL;
232 Py_INCREF(Py_None);
233 return Py_None;
236 static char dbm_keys__doc__[] = "\
237 keys() -> list_of_keys\n\
238 Get a list of all keys in the database.";
240 static PyObject *
241 dbm_keys(dp, args)
242 register dbmobject *dp;
243 PyObject *args;
245 register PyObject *v, *item;
246 datum key, nextkey;
247 int err;
249 if (dp == NULL || !is_dbmobject(dp)) {
250 PyErr_BadInternalCall();
251 return NULL;
254 if (!PyArg_NoArgs(args))
255 return NULL;
257 check_dbmobject_open(dp);
259 v = PyList_New(0);
260 if (v == NULL)
261 return NULL;
263 key = gdbm_firstkey(dp->di_dbm);
264 while (key.dptr) {
265 item = PyString_FromStringAndSize(key.dptr, key.dsize);
266 if (item == NULL) {
267 free(key.dptr);
268 Py_DECREF(v);
269 return NULL;
271 err = PyList_Append(v, item);
272 Py_DECREF(item);
273 if (err != 0) {
274 free(key.dptr);
275 Py_DECREF(v);
276 return NULL;
278 nextkey = gdbm_nextkey(dp->di_dbm, key);
279 free(key.dptr);
280 key = nextkey;
283 return v;
286 static char dbm_has_key__doc__[] = "\
287 has_key(key) -> boolean\n\
288 Find out whether or not the database contains a given key.";
290 static PyObject *
291 dbm_has_key(dp, args)
292 register dbmobject *dp;
293 PyObject *args;
295 datum key;
297 if (!PyArg_Parse(args, "s#", &key.dptr, &key.dsize))
298 return NULL;
299 check_dbmobject_open(dp);
300 return PyInt_FromLong((long) gdbm_exists(dp->di_dbm, key));
303 static char dbm_firstkey__doc__[] = "\
304 firstkey() -> key\n\
305 It's possible to loop over every key in the database using this method\n\
306 and the nextkey() method. The traversal is ordered by GDBM's internal\n\
307 hash values, and won't be sorted by the key values. This method\n\
308 returns the starting key.";
310 static PyObject *
311 dbm_firstkey(dp, args)
312 register dbmobject *dp;
313 PyObject *args;
315 register PyObject *v;
316 datum key;
318 if (!PyArg_NoArgs(args))
319 return NULL;
320 check_dbmobject_open(dp);
321 key = gdbm_firstkey(dp->di_dbm);
322 if (key.dptr) {
323 v = PyString_FromStringAndSize(key.dptr, key.dsize);
324 free(key.dptr);
325 return v;
326 } else {
327 Py_INCREF(Py_None);
328 return Py_None;
332 static char dbm_nextkey__doc__[] = "\
333 nextkey(key) -> next_key\n\
334 Returns the key that follows key in the traversal.\n\
335 The following code prints every key in the database db, without having\n\
336 to create a list in memory that contains them all:\n\
338 k = db.firstkey()\n\
339 while k != None:\n\
340 print k\n\
341 k = db.nextkey(k)";
343 static PyObject *
344 dbm_nextkey(dp, args)
345 register dbmobject *dp;
346 PyObject *args;
348 register PyObject *v;
349 datum key, nextkey;
351 if (!PyArg_Parse(args, "s#", &key.dptr, &key.dsize))
352 return NULL;
353 check_dbmobject_open(dp);
354 nextkey = gdbm_nextkey(dp->di_dbm, key);
355 if (nextkey.dptr) {
356 v = PyString_FromStringAndSize(nextkey.dptr, nextkey.dsize);
357 free(nextkey.dptr);
358 return v;
359 } else {
360 Py_INCREF(Py_None);
361 return Py_None;
365 static char dbm_reorganize__doc__[] = "\
366 reorganize() -> None\n\
367 If you have carried out a lot of deletions and would like to shrink\n\
368 the space used by the GDBM file, this routine will reorganize the\n\
369 database. GDBM will not shorten the length of a database file except\n\
370 by using this reorganization; otherwise, deleted file space will be\n\
371 kept and reused as new (key,value) pairs are added.";
373 static PyObject *
374 dbm_reorganize(dp, args)
375 register dbmobject *dp;
376 PyObject *args;
378 if (!PyArg_NoArgs(args))
379 return NULL;
380 check_dbmobject_open(dp);
381 errno = 0;
382 if (gdbm_reorganize(dp->di_dbm) < 0) {
383 if (errno != 0)
384 PyErr_SetFromErrno(DbmError);
385 else
386 PyErr_SetString(DbmError, gdbm_strerror(gdbm_errno));
387 return NULL;
389 Py_INCREF(Py_None);
390 return Py_None;
393 static char dbm_sync__doc__[] = "\
394 sync() -> None\n\
395 When the database has been opened in fast mode, this method forces\n\
396 any unwritten data to be written to the disk.";
398 static PyObject *
399 dbm_sync(dp, args)
400 register dbmobject *dp;
401 PyObject *args;
403 if (!PyArg_NoArgs(args))
404 return NULL;
405 check_dbmobject_open(dp);
406 gdbm_sync(dp->di_dbm);
407 Py_INCREF(Py_None);
408 return Py_None;
411 static PyMethodDef dbm_methods[] = {
412 {"close", (PyCFunction)dbm_close, 0, dbm_close__doc__},
413 {"keys", (PyCFunction)dbm_keys, 0, dbm_keys__doc__},
414 {"has_key", (PyCFunction)dbm_has_key, 0, dbm_has_key__doc__},
415 {"firstkey", (PyCFunction)dbm_firstkey, 0, dbm_firstkey__doc__},
416 {"nextkey", (PyCFunction)dbm_nextkey, 0, dbm_nextkey__doc__},
417 {"reorganize", (PyCFunction)dbm_reorganize, 0, dbm_reorganize__doc__},
418 {"sync", (PyCFunction)dbm_sync, 0, dbm_sync__doc__},
419 {NULL, NULL} /* sentinel */
422 static PyObject *
423 dbm_getattr(dp, name)
424 dbmobject *dp;
425 char *name;
427 return Py_FindMethod(dbm_methods, (PyObject *)dp, name);
430 static PyTypeObject Dbmtype = {
431 PyObject_HEAD_INIT(0)
433 "gdbm",
434 sizeof(dbmobject),
436 (destructor)dbm_dealloc, /*tp_dealloc*/
437 0, /*tp_print*/
438 (getattrfunc)dbm_getattr, /*tp_getattr*/
439 0, /*tp_setattr*/
440 0, /*tp_compare*/
441 0, /*tp_repr*/
442 0, /*tp_as_number*/
443 0, /*tp_as_sequence*/
444 &dbm_as_mapping, /*tp_as_mapping*/
445 0, /*tp_hash*/
446 0, /*tp_call*/
447 0, /*tp_str*/
448 0, /*tp_getattro*/
449 0, /*tp_setattro*/
450 0, /*tp_as_buffer*/
451 0, /*tp_xxx4*/
452 gdbm_object__doc__, /*tp_doc*/
455 /* ----------------------------------------------------------------- */
457 static char dbmopen__doc__[] = "\
458 open(filename, [flag, [mode]]) -> dbm_object\n\
459 Open a dbm database and return a dbm object. The filename argument is\n\
460 the name of the database file.\n\
462 The optional flag argument can be 'r' (to open an existing database\n\
463 for reading only -- default), 'w' (to open an existing database for\n\
464 reading and writing), 'c' (which creates the database if it doesn't\n\
465 exist), or 'n' (which always creates a new empty database).\n\
467 Appending f to the flag opens the database in fast mode; altered\n\
468 data will not automatically be written to the disk after every\n\
469 change. This results in faster writes to the database, but may\n\
470 result in an inconsistent database if the program crashes while the\n\
471 database is still open. Use the sync() method to force any\n\
472 unwritten data to be written to the disk.\n\
474 The optional mode argument is the Unix mode of the file, used only\n\
475 when the database has to be created. It defaults to octal 0666. ";
477 static PyObject *
478 dbmopen(self, args)
479 PyObject *self;
480 PyObject *args;
482 char *name;
483 char *flags = "r ";
484 int iflags;
485 int mode = 0666;
487 if ( !PyArg_ParseTuple(args, "s|si", &name, &flags, &mode) )
488 return NULL;
489 switch (flags[0]) {
490 case 'r':
491 iflags = GDBM_READER;
492 break;
493 case 'w':
494 iflags = GDBM_WRITER;
495 break;
496 case 'c':
497 iflags = GDBM_WRCREAT;
498 break;
499 case 'n':
500 iflags = GDBM_NEWDB;
501 break;
502 default:
503 PyErr_SetString(DbmError,
504 "Flags should be one of 'r', 'w', 'c' or 'n'");
505 return NULL;
507 if (flags[1] == 'f')
508 iflags |= GDBM_FAST;
509 return newdbmobject(name, iflags, mode);
512 static PyMethodDef dbmmodule_methods[] = {
513 { "open", (PyCFunction)dbmopen, 1, dbmopen__doc__},
514 { 0, 0 },
517 void
518 initgdbm() {
519 PyObject *m, *d;
521 Dbmtype.ob_type = &PyType_Type;
522 m = Py_InitModule4("gdbm", dbmmodule_methods,
523 gdbmmodule__doc__, (PyObject *)NULL,
524 PYTHON_API_VERSION);
525 d = PyModule_GetDict(m);
526 DbmError = PyErr_NewException("gdbm.error", NULL, NULL);
527 if (DbmError != NULL)
528 PyDict_SetItemString(d, "error", DbmError);