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