Home | History | Annotate | Download | only in Modules
      1 
      2 /* DBM module using dictionary interface */
      3 
      4 
      5 #include "Python.h"
      6 
      7 #include <sys/types.h>
      8 #include <sys/stat.h>
      9 #include <fcntl.h>
     10 
     11 /* Some Linux systems install gdbm/ndbm.h, but not ndbm.h.  This supports
     12  * whichever configure was able to locate.
     13  */
     14 #if defined(HAVE_NDBM_H)
     15 #include <ndbm.h>
     16 #if defined(PYOS_OS2) && !defined(PYCC_GCC)
     17 static char *which_dbm = "ndbm";
     18 #else
     19 static char *which_dbm = "GNU gdbm";  /* EMX port of GDBM */
     20 #endif
     21 #elif defined(HAVE_GDBM_NDBM_H)
     22 #include <gdbm/ndbm.h>
     23 static char *which_dbm = "GNU gdbm";
     24 #elif defined(HAVE_GDBM_DASH_NDBM_H)
     25 #include <gdbm-ndbm.h>
     26 static char *which_dbm = "GNU gdbm";
     27 #elif defined(HAVE_BERKDB_H)
     28 #include <db.h>
     29 static char *which_dbm = "Berkeley DB";
     30 #else
     31 #error "No ndbm.h available!"
     32 #endif
     33 
     34 typedef struct {
     35     PyObject_HEAD
     36     int di_size;        /* -1 means recompute */
     37     DBM *di_dbm;
     38 } dbmobject;
     39 
     40 static PyTypeObject Dbmtype;
     41 
     42 #define is_dbmobject(v) (Py_TYPE(v) == &Dbmtype)
     43 #define check_dbmobject_open(v) if ((v)->di_dbm == NULL) \
     44                { PyErr_SetString(DbmError, "DBM object has already been closed"); \
     45                  return NULL; }
     46 
     47 static PyObject *DbmError;
     48 
     49 static PyObject *
     50 newdbmobject(char *file, int flags, int mode)
     51 {
     52     dbmobject *dp;
     53 
     54     dp = PyObject_New(dbmobject, &Dbmtype);
     55     if (dp == NULL)
     56         return NULL;
     57     dp->di_size = -1;
     58     if ( (dp->di_dbm = dbm_open(file, flags, mode)) == 0 ) {
     59         PyErr_SetFromErrno(DbmError);
     60         Py_DECREF(dp);
     61         return NULL;
     62     }
     63     return (PyObject *)dp;
     64 }
     65 
     66 /* Methods */
     67 
     68 static void
     69 dbm_dealloc(register dbmobject *dp)
     70 {
     71     if ( dp->di_dbm )
     72         dbm_close(dp->di_dbm);
     73     PyObject_Del(dp);
     74 }
     75 
     76 static Py_ssize_t
     77 dbm_length(dbmobject *dp)
     78 {
     79     if (dp->di_dbm == NULL) {
     80              PyErr_SetString(DbmError, "DBM object has already been closed");
     81              return -1;
     82     }
     83     if ( dp->di_size < 0 ) {
     84         datum key;
     85         int size;
     86 
     87         size = 0;
     88         for ( key=dbm_firstkey(dp->di_dbm); key.dptr;
     89               key = dbm_nextkey(dp->di_dbm))
     90             size++;
     91         dp->di_size = size;
     92     }
     93     return dp->di_size;
     94 }
     95 
     96 static PyObject *
     97 dbm_subscript(dbmobject *dp, register PyObject *key)
     98 {
     99     datum drec, krec;
    100     int tmp_size;
    101 
    102     if (!PyArg_Parse(key, "s#", &krec.dptr, &tmp_size) )
    103         return NULL;
    104 
    105     krec.dsize = tmp_size;
    106     check_dbmobject_open(dp);
    107     drec = dbm_fetch(dp->di_dbm, krec);
    108     if ( drec.dptr == 0 ) {
    109         PyErr_SetString(PyExc_KeyError,
    110                         PyString_AS_STRING((PyStringObject *)key));
    111         return NULL;
    112     }
    113     if ( dbm_error(dp->di_dbm) ) {
    114         dbm_clearerr(dp->di_dbm);
    115         PyErr_SetString(DbmError, "");
    116         return NULL;
    117     }
    118     return PyString_FromStringAndSize(drec.dptr, drec.dsize);
    119 }
    120 
    121 static int
    122 dbm_ass_sub(dbmobject *dp, PyObject *v, PyObject *w)
    123 {
    124     datum krec, drec;
    125     int tmp_size;
    126 
    127     if ( !PyArg_Parse(v, "s#", &krec.dptr, &tmp_size) ) {
    128         PyErr_SetString(PyExc_TypeError,
    129                         "dbm mappings have string indices only");
    130         return -1;
    131     }
    132     krec.dsize = tmp_size;
    133     if (dp->di_dbm == NULL) {
    134              PyErr_SetString(DbmError, "DBM object has already been closed");
    135              return -1;
    136     }
    137     dp->di_size = -1;
    138     if (w == NULL) {
    139         if ( dbm_delete(dp->di_dbm, krec) < 0 ) {
    140             dbm_clearerr(dp->di_dbm);
    141             PyErr_SetString(PyExc_KeyError,
    142                           PyString_AS_STRING((PyStringObject *)v));
    143             return -1;
    144         }
    145     } else {
    146         if ( !PyArg_Parse(w, "s#", &drec.dptr, &tmp_size) ) {
    147             PyErr_SetString(PyExc_TypeError,
    148                          "dbm mappings have string elements only");
    149             return -1;
    150         }
    151         drec.dsize = tmp_size;
    152         if ( dbm_store(dp->di_dbm, krec, drec, DBM_REPLACE) < 0 ) {
    153             dbm_clearerr(dp->di_dbm);
    154             PyErr_SetString(DbmError,
    155                             "cannot add item to database");
    156             return -1;
    157         }
    158     }
    159     if ( dbm_error(dp->di_dbm) ) {
    160         dbm_clearerr(dp->di_dbm);
    161         PyErr_SetString(DbmError, "");
    162         return -1;
    163     }
    164     return 0;
    165 }
    166 
    167 static int
    168 dbm_contains(register dbmobject *dp, PyObject *v)
    169 {
    170     datum key, val;
    171     char *ptr;
    172     Py_ssize_t size;
    173 
    174     if (PyString_AsStringAndSize(v, &ptr, &size))
    175         return -1;
    176     key.dptr = ptr;
    177     key.dsize = size;
    178 
    179     /* Expand check_dbmobject_open to return -1 */
    180     if (dp->di_dbm == NULL) {
    181         PyErr_SetString(DbmError, "DBM object has already been closed");
    182         return -1;
    183     }
    184     val = dbm_fetch(dp->di_dbm, key);
    185     return val.dptr != NULL;
    186 }
    187 
    188 static PySequenceMethods dbm_as_sequence = {
    189     (lenfunc)dbm_length,        /*_length*/
    190     0,                          /*sq_concat*/
    191     0,                          /*sq_repeat*/
    192     0,                          /*sq_item*/
    193     0,                          /*sq_slice*/
    194     0,                          /*sq_ass_item*/
    195     0,                          /*sq_ass_slice*/
    196     (objobjproc)dbm_contains,   /*sq_contains*/
    197     0,                          /*sq_inplace_concat*/
    198     0                           /*sq_inplace_repeat*/
    199 };
    200 
    201 static PyMappingMethods dbm_as_mapping = {
    202     (lenfunc)dbm_length,                /*mp_length*/
    203     (binaryfunc)dbm_subscript,          /*mp_subscript*/
    204     (objobjargproc)dbm_ass_sub,         /*mp_ass_subscript*/
    205 };
    206 
    207 static PyObject *
    208 dbm__close(register dbmobject *dp, PyObject *unused)
    209 {
    210     if (dp->di_dbm)
    211         dbm_close(dp->di_dbm);
    212     dp->di_dbm = NULL;
    213     Py_INCREF(Py_None);
    214     return Py_None;
    215 }
    216 
    217 static PyObject *
    218 dbm_keys(register dbmobject *dp, PyObject *unused)
    219 {
    220     register PyObject *v, *item;
    221     datum key;
    222     int err;
    223 
    224     check_dbmobject_open(dp);
    225     v = PyList_New(0);
    226     if (v == NULL)
    227         return NULL;
    228     for (key = dbm_firstkey(dp->di_dbm); key.dptr;
    229          key = dbm_nextkey(dp->di_dbm)) {
    230         item = PyString_FromStringAndSize(key.dptr, key.dsize);
    231         if (item == NULL) {
    232             Py_DECREF(v);
    233             return NULL;
    234         }
    235         err = PyList_Append(v, item);
    236         Py_DECREF(item);
    237         if (err != 0) {
    238             Py_DECREF(v);
    239             return NULL;
    240         }
    241     }
    242     return v;
    243 }
    244 
    245 static PyObject *
    246 dbm_has_key(register dbmobject *dp, PyObject *args)
    247 {
    248     char *tmp_ptr;
    249     datum key, val;
    250     int tmp_size;
    251 
    252     if (!PyArg_ParseTuple(args, "s#:has_key", &tmp_ptr, &tmp_size))
    253         return NULL;
    254     key.dptr = tmp_ptr;
    255     key.dsize = tmp_size;
    256     check_dbmobject_open(dp);
    257     val = dbm_fetch(dp->di_dbm, key);
    258     return PyInt_FromLong(val.dptr != NULL);
    259 }
    260 
    261 static PyObject *
    262 dbm_get(register dbmobject *dp, PyObject *args)
    263 {
    264     datum key, val;
    265     PyObject *defvalue = Py_None;
    266     char *tmp_ptr;
    267     int tmp_size;
    268 
    269     if (!PyArg_ParseTuple(args, "s#|O:get",
    270                           &tmp_ptr, &tmp_size, &defvalue))
    271         return NULL;
    272     key.dptr = tmp_ptr;
    273     key.dsize = tmp_size;
    274     check_dbmobject_open(dp);
    275     val = dbm_fetch(dp->di_dbm, key);
    276     if (val.dptr != NULL)
    277         return PyString_FromStringAndSize(val.dptr, val.dsize);
    278     else {
    279         Py_INCREF(defvalue);
    280         return defvalue;
    281     }
    282 }
    283 
    284 static PyObject *
    285 dbm_setdefault(register dbmobject *dp, PyObject *args)
    286 {
    287     datum key, val;
    288     PyObject *defvalue = NULL;
    289     char *tmp_ptr;
    290     int tmp_size;
    291 
    292     if (!PyArg_ParseTuple(args, "s#|S:setdefault",
    293                           &tmp_ptr, &tmp_size, &defvalue))
    294         return NULL;
    295     key.dptr = tmp_ptr;
    296     key.dsize = tmp_size;
    297     check_dbmobject_open(dp);
    298     val = dbm_fetch(dp->di_dbm, key);
    299     if (val.dptr != NULL)
    300         return PyString_FromStringAndSize(val.dptr, val.dsize);
    301     if (defvalue == NULL) {
    302         defvalue = PyString_FromStringAndSize(NULL, 0);
    303         if (defvalue == NULL)
    304             return NULL;
    305     }
    306     else
    307         Py_INCREF(defvalue);
    308     val.dptr = PyString_AS_STRING(defvalue);
    309     val.dsize = PyString_GET_SIZE(defvalue);
    310     if (dbm_store(dp->di_dbm, key, val, DBM_INSERT) < 0) {
    311         dbm_clearerr(dp->di_dbm);
    312         PyErr_SetString(DbmError, "cannot add item to database");
    313         return NULL;
    314     }
    315     return defvalue;
    316 }
    317 
    318 static PyMethodDef dbm_methods[] = {
    319     {"close",           (PyCFunction)dbm__close,        METH_NOARGS,
    320      "close()\nClose the database."},
    321     {"keys",            (PyCFunction)dbm_keys,          METH_NOARGS,
    322      "keys() -> list\nReturn a list of all keys in the database."},
    323     {"has_key",         (PyCFunction)dbm_has_key,       METH_VARARGS,
    324      "has_key(key} -> boolean\nReturn true iff key is in the database."},
    325     {"get",             (PyCFunction)dbm_get,           METH_VARARGS,
    326      "get(key[, default]) -> value\n"
    327      "Return the value for key if present, otherwise default."},
    328     {"setdefault",      (PyCFunction)dbm_setdefault,    METH_VARARGS,
    329      "setdefault(key[, default]) -> value\n"
    330      "Return the value for key if present, otherwise default.  If key\n"
    331      "is not in the database, it is inserted with default as the value."},
    332     {NULL,              NULL}           /* sentinel */
    333 };
    334 
    335 static PyObject *
    336 dbm_getattr(dbmobject *dp, char *name)
    337 {
    338     return Py_FindMethod(dbm_methods, (PyObject *)dp, name);
    339 }
    340 
    341 static PyTypeObject Dbmtype = {
    342     PyVarObject_HEAD_INIT(NULL, 0)
    343     "dbm.dbm",
    344     sizeof(dbmobject),
    345     0,
    346     (destructor)dbm_dealloc,  /*tp_dealloc*/
    347     0,                            /*tp_print*/
    348     (getattrfunc)dbm_getattr, /*tp_getattr*/
    349     0,                            /*tp_setattr*/
    350     0,                            /*tp_compare*/
    351     0,                            /*tp_repr*/
    352     0,                            /*tp_as_number*/
    353     &dbm_as_sequence,     /*tp_as_sequence*/
    354     &dbm_as_mapping,              /*tp_as_mapping*/
    355     0,                    /*tp_hash*/
    356     0,                    /*tp_call*/
    357     0,                    /*tp_str*/
    358     0,                    /*tp_getattro*/
    359     0,                    /*tp_setattro*/
    360     0,                    /*tp_as_buffer*/
    361     Py_TPFLAGS_DEFAULT,   /*tp_xxx4*/
    362 };
    363 
    364 /* ----------------------------------------------------------------- */
    365 
    366 static PyObject *
    367 dbmopen(PyObject *self, PyObject *args)
    368 {
    369     char *name;
    370     char *flags = "r";
    371     int iflags;
    372     int mode = 0666;
    373 
    374     if ( !PyArg_ParseTuple(args, "s|si:open", &name, &flags, &mode) )
    375         return NULL;
    376     if ( strcmp(flags, "r") == 0 )
    377         iflags = O_RDONLY;
    378     else if ( strcmp(flags, "w") == 0 )
    379         iflags = O_RDWR;
    380     else if ( strcmp(flags, "rw") == 0 ) /* B/W compat */
    381         iflags = O_RDWR|O_CREAT;
    382     else if ( strcmp(flags, "c") == 0 )
    383         iflags = O_RDWR|O_CREAT;
    384     else if ( strcmp(flags, "n") == 0 )
    385         iflags = O_RDWR|O_CREAT|O_TRUNC;
    386     else {
    387         PyErr_SetString(DbmError,
    388                         "arg 2 to open should be 'r', 'w', 'c', or 'n'");
    389         return NULL;
    390     }
    391     return newdbmobject(name, iflags, mode);
    392 }
    393 
    394 static PyMethodDef dbmmodule_methods[] = {
    395     { "open", (PyCFunction)dbmopen, METH_VARARGS,
    396       "open(path[, flag[, mode]]) -> mapping\n"
    397       "Return a database object."},
    398     { 0, 0 },
    399 };
    400 
    401 PyMODINIT_FUNC
    402 initdbm(void) {
    403     PyObject *m, *d, *s;
    404 
    405     Dbmtype.ob_type = &PyType_Type;
    406     m = Py_InitModule("dbm", dbmmodule_methods);
    407     if (m == NULL)
    408         return;
    409     d = PyModule_GetDict(m);
    410     if (DbmError == NULL)
    411         DbmError = PyErr_NewException("dbm.error", NULL, NULL);
    412     s = PyString_FromString(which_dbm);
    413     if (s != NULL) {
    414         PyDict_SetItemString(d, "library", s);
    415         Py_DECREF(s);
    416     }
    417     if (DbmError != NULL)
    418         PyDict_SetItemString(d, "error", DbmError);
    419 }
    420