blob: 632846f2cc3636b57afbd512f317e4ecae4a6b6d [file] [log] [blame]
Guido van Rossum4b4c6641994-08-08 08:06:37 +00001/* GDBM module, hacked from the still-breathing corpse of the
2 DBM module by anthony.baxter@aaii.oz.au. Original copyright
3 follows:
4*/
5/***********************************************************
Guido van Rossum524b5881995-01-04 19:10:35 +00006Copyright 1991-1995 by Stichting Mathematisch Centrum, Amsterdam,
7The Netherlands.
Guido van Rossum4b4c6641994-08-08 08:06:37 +00008
9 All Rights Reserved
10
11Permission to use, copy, modify, and distribute this software and its
12documentation for any purpose and without fee is hereby granted,
13provided that the above copyright notice appear in all copies and that
14both that copyright notice and this permission notice appear in
15supporting documentation, and that the names of Stichting Mathematisch
16Centrum or CWI not be used in advertising or publicity pertaining to
17distribution of the software without specific, written prior permission.
18
19STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
20THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
21FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
22FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
23WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
24ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
25OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
26
27******************************************************************/
28
29/* DBM module using dictionary interface */
30
31
32#include "allobjects.h"
33#include "modsupport.h"
34
35#include <sys/types.h>
36#include <sys/stat.h>
37#include <fcntl.h>
38#include "gdbm.h"
39
40typedef struct {
41 OB_HEAD
42 int di_size; /* -1 means recompute */
43 GDBM_FILE di_dbm;
44} dbmobject;
45
46staticforward typeobject Dbmtype;
47
48#define is_dbmobject(v) ((v)->ob_type == &Dbmtype)
49
50static object *DbmError;
51
52static object *
53newdbmobject(file, flags, mode)
54 char *file;
55 int flags;
56 int mode;
57{
58 dbmobject *dp;
59
60 dp = NEWOBJ(dbmobject, &Dbmtype);
61 if (dp == NULL)
62 return NULL;
63 dp->di_size = -1;
Guido van Rossumb045afc1995-03-14 15:04:40 +000064 errno = 0;
Guido van Rossum4b4c6641994-08-08 08:06:37 +000065 if ( (dp->di_dbm = gdbm_open(file, 0, flags, mode, NULL)) == 0 ) {
Guido van Rossumb045afc1995-03-14 15:04:40 +000066 if (errno != 0)
67 err_errno(DbmError);
68 else
69 err_setstr(DbmError, (char *) gdbm_strerror(gdbm_errno));
Guido van Rossum4b4c6641994-08-08 08:06:37 +000070 DECREF(dp);
71 return 0;
72 }
73 return (object *)dp;
74}
75
76/* Methods */
77
78static void
79dbm_dealloc(dp)
80 register dbmobject *dp;
81{
82 if ( dp->di_dbm )
83 gdbm_close(dp->di_dbm);
84 DEL(dp);
85}
86
87static int
88dbm_length(dp)
89 dbmobject *dp;
90{
91 if ( dp->di_size < 0 ) {
92 datum key,okey;
93 int size;
94 okey.dsize=0;
95
96 size = 0;
97 for ( key=gdbm_firstkey(dp->di_dbm); key.dptr;
98 key = gdbm_nextkey(dp->di_dbm,okey)) {
99 size++;
Sjoerd Mullender2abc4941994-10-13 09:11:13 +0000100 if(okey.dsize) free(okey.dptr);
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000101 okey=key;
102 }
103 dp->di_size = size;
104 }
105 return dp->di_size;
106}
107
108static object *
109dbm_subscript(dp, key)
110 dbmobject *dp;
111 register object *key;
112{
113 object *v;
114 datum drec, krec;
115
116 if (!getargs(key, "s#", &krec.dptr, &krec.dsize) )
117 return NULL;
118
119 drec = gdbm_fetch(dp->di_dbm, krec);
120 if ( drec.dptr == 0 ) {
121 err_setstr(KeyError, GETSTRINGVALUE((stringobject *)key));
122 return 0;
123 }
Guido van Rossumb045afc1995-03-14 15:04:40 +0000124 v = newsizedstringobject(drec.dptr, drec.dsize);
125 free(drec.dptr);
126 return v;
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000127}
128
129static int
130dbm_ass_sub(dp, v, w)
131 dbmobject *dp;
132 object *v, *w;
133{
134 datum krec, drec;
135
136 if ( !getargs(v, "s#", &krec.dptr, &krec.dsize) ) {
137 err_setstr(TypeError, "gdbm mappings have string indices only");
138 return -1;
139 }
140 dp->di_size = -1;
141 if (w == NULL) {
142 if ( gdbm_delete(dp->di_dbm, krec) < 0 ) {
143 err_setstr(KeyError, GETSTRINGVALUE((stringobject *)v));
144 return -1;
145 }
146 } else {
147 if ( !getargs(w, "s#", &drec.dptr, &drec.dsize) ) {
148 err_setstr(TypeError,
149 "gdbm mappings have string elements only");
150 return -1;
151 }
Guido van Rossumb045afc1995-03-14 15:04:40 +0000152 errno = 0;
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000153 if ( gdbm_store(dp->di_dbm, krec, drec, GDBM_REPLACE) < 0 ) {
Guido van Rossumb045afc1995-03-14 15:04:40 +0000154 if (errno != 0)
155 err_errno(DbmError);
156 else
157 err_setstr(DbmError, (char *) gdbm_strerror(gdbm_errno));
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000158 return -1;
159 }
160 }
161 return 0;
162}
163
164static mapping_methods dbm_as_mapping = {
165 (inquiry)dbm_length, /*mp_length*/
166 (binaryfunc)dbm_subscript, /*mp_subscript*/
167 (objobjargproc)dbm_ass_sub, /*mp_ass_subscript*/
168};
169
170static object *
171dbm_keys(dp, args)
172 register dbmobject *dp;
173 object *args;
174{
175 register object *v, *item;
176 datum key, okey={ (char *)NULL, 0};
177
178 if (dp == NULL || !is_dbmobject(dp)) {
179 err_badcall();
180 return NULL;
181 }
182 if (!getnoarg(args))
183 return NULL;
184 v = newlistobject(0);
185 if (v == NULL)
186 return NULL;
187 for (key = gdbm_firstkey(dp->di_dbm); key.dptr;
188 key = gdbm_nextkey(dp->di_dbm,okey) ) {
189 item = newsizedstringobject(key.dptr, key.dsize);
190 if ( item == 0 )
191 return NULL;
192 addlistitem(v, item);
Sjoerd Mullender2abc4941994-10-13 09:11:13 +0000193 if(okey.dsize) free(okey.dptr);
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000194 okey=key;
195 }
196 return v;
197}
198
199
200static object *
201dbm_has_key(dp, args)
202 register dbmobject *dp;
203 object *args;
204{
Guido van Rossumb045afc1995-03-14 15:04:40 +0000205 datum key;
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000206
207 if (!getargs(args, "s#", &key.dptr, &key.dsize))
208 return NULL;
Guido van Rossumb045afc1995-03-14 15:04:40 +0000209 return newintobject((long) gdbm_exists(dp->di_dbm, key));
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000210}
211
Guido van Rossumfbd30e91995-03-16 16:07:34 +0000212static object *
213dbm_firstkey(dp, args)
214 register dbmobject *dp;
215 object *args;
216{
217 register object *v;
218 datum key;
219
220 if (!getnoarg(args))
221 return NULL;
222 key = gdbm_firstkey(dp->di_dbm);
223 if (key.dptr) {
224 v = newsizedstringobject(key.dptr, key.dsize);
225 free(key.dptr);
226 return v;
227 } else {
228 INCREF(None);
229 return None;
230 }
231}
232
233static object *
234dbm_nextkey(dp, args)
235 register dbmobject *dp;
236 object *args;
237{
238 register object *v;
239 datum key, nextkey;
240
241 if (!getargs(args, "s#", &key.dptr, &key.dsize))
242 return NULL;
243 nextkey = gdbm_nextkey(dp->di_dbm, key);
244 if (nextkey.dptr) {
245 v = newsizedstringobject(nextkey.dptr, nextkey.dsize);
246 free(nextkey.dptr);
247 return v;
248 } else {
249 INCREF(None);
250 return None;
251 }
252}
253
254static object *
255dbm_reorganize(dp, args)
256 register dbmobject *dp;
257 object *args;
258{
259 if (!getnoarg(args))
260 return NULL;
261 errno = 0;
262 if (gdbm_reorganize(dp->di_dbm) < 0) {
263 if (errno != 0)
264 err_errno(DbmError);
265 else
266 err_setstr(DbmError, (char *) gdbm_strerror(gdbm_errno));
267 return NULL;
268 }
269 INCREF(None);
270 return None;
271}
272
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000273static struct methodlist dbm_methods[] = {
274 {"keys", (method)dbm_keys},
275 {"has_key", (method)dbm_has_key},
Guido van Rossumfbd30e91995-03-16 16:07:34 +0000276 {"firstkey", (method)dbm_firstkey},
277 {"nextkey", (method)dbm_nextkey},
278 {"reorganize", (method)dbm_reorganize},
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000279 {NULL, NULL} /* sentinel */
280};
281
282static object *
283dbm_getattr(dp, name)
284 dbmobject *dp;
285 char *name;
286{
287 return findmethod(dbm_methods, (object *)dp, name);
288}
289
290static typeobject Dbmtype = {
291 OB_HEAD_INIT(&Typetype)
292 0,
293 "Gdbm_dictionary",
294 sizeof(dbmobject),
295 0,
296 (destructor)dbm_dealloc, /*tp_dealloc*/
297 0, /*tp_print*/
298 (getattrfunc)dbm_getattr, /*tp_getattr*/
299 0, /*tp_setattr*/
300 0, /*tp_compare*/
301 0, /*tp_repr*/
302 0, /*tp_as_number*/
303 0, /*tp_as_sequence*/
304 &dbm_as_mapping, /*tp_as_mapping*/
305};
306
307/* ----------------------------------------------------------------- */
308
309static object *
310dbmopen(self, args)
311 object *self;
312 object *args;
313{
314 char *name, *flags;
315 int iflags, mode;
316
317/* XXXX add other flags */
318 if ( !getargs(args, "(ssi)", &name, &flags, &mode) )
319 return 0;
320 if ( strcmp(flags, "r") == 0 )
321 iflags = GDBM_READER;
322 else if ( strcmp(flags, "w") == 0 )
323 iflags = GDBM_WRITER;
324 else if ( strcmp(flags, "c") == 0 )
325 iflags = GDBM_WRCREAT;
326 else if ( strcmp(flags, "n") == 0 )
327 iflags = GDBM_NEWDB;
328 else {
329 err_setstr(DbmError,
Guido van Rossumb045afc1995-03-14 15:04:40 +0000330 "Flags should be one of 'r', 'w', 'c' or 'n'");
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000331 return 0;
332 }
333 return newdbmobject(name, iflags, mode);
334}
335
336static struct methodlist dbmmodule_methods[] = {
337 { "open", (method)dbmopen },
338 { 0, 0 },
339};
340
341void
342initgdbm() {
343 object *m, *d;
344
345 m = initmodule("gdbm", dbmmodule_methods);
346 d = getmoduledict(m);
347 DbmError = newstringobject("gdbm.error");
348 if ( DbmError == NULL || dictinsert(d, "error", DbmError) )
349 fatal("can't define gdbm.error");
350}