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