Python-2.7.3/Modules/gdbmmodule.c

No issues found

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