blob: e5bc4ac110c0e8bd85d0900ec918bd5f21051996 [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);
Guido van Rossum807b7be1995-07-07 22:37:11 +000071 return NULL;
Guido van Rossum4b4c6641994-08-08 08:06:37 +000072 }
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));
Guido van Rossum807b7be1995-07-07 22:37:11 +0000122 return NULL;
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000123 }
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 *
Guido van Rossum807b7be1995-07-07 22:37:11 +0000171dbm_close(dp, args)
172 register dbmobject *dp;
173 object *args;
174{
175 if ( !getnoarg(args) )
176 return NULL;
177 if ( dp->di_dbm )
178 gdbm_close(dp->di_dbm);
179 dp->di_dbm = NULL;
Guido van Rossum807b7be1995-07-07 22:37:11 +0000180 INCREF(None);
181 return None;
182}
183
184static object *
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000185dbm_keys(dp, args)
186 register dbmobject *dp;
187 object *args;
188{
189 register object *v, *item;
190 datum key, okey={ (char *)NULL, 0};
Guido van Rossum66017aa1995-08-28 02:58:00 +0000191 int err;
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000192
193 if (dp == NULL || !is_dbmobject(dp)) {
194 err_badcall();
195 return NULL;
196 }
197 if (!getnoarg(args))
198 return NULL;
199 v = newlistobject(0);
200 if (v == NULL)
201 return NULL;
202 for (key = gdbm_firstkey(dp->di_dbm); key.dptr;
203 key = gdbm_nextkey(dp->di_dbm,okey) ) {
204 item = newsizedstringobject(key.dptr, key.dsize);
Guido van Rossum66017aa1995-08-28 02:58:00 +0000205 if (item == 0) {
206 DECREF(v);
207 return NULL;
208 }
209 err = addlistitem(v, item);
210 DECREF(item);
Sjoerd Mullender2abc4941994-10-13 09:11:13 +0000211 if(okey.dsize) free(okey.dptr);
Guido van Rossum66017aa1995-08-28 02:58:00 +0000212 if (err != 0) {
213 DECREF(v);
214 return NULL;
215 }
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000216 okey=key;
217 }
218 return v;
219}
220
221
222static object *
223dbm_has_key(dp, args)
224 register dbmobject *dp;
225 object *args;
226{
Guido van Rossumb045afc1995-03-14 15:04:40 +0000227 datum key;
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000228
229 if (!getargs(args, "s#", &key.dptr, &key.dsize))
230 return NULL;
Guido van Rossumb045afc1995-03-14 15:04:40 +0000231 return newintobject((long) gdbm_exists(dp->di_dbm, key));
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000232}
233
Guido van Rossumfbd30e91995-03-16 16:07:34 +0000234static object *
235dbm_firstkey(dp, args)
236 register dbmobject *dp;
237 object *args;
238{
239 register object *v;
240 datum key;
241
242 if (!getnoarg(args))
243 return NULL;
244 key = gdbm_firstkey(dp->di_dbm);
245 if (key.dptr) {
246 v = newsizedstringobject(key.dptr, key.dsize);
247 free(key.dptr);
248 return v;
249 } else {
250 INCREF(None);
251 return None;
252 }
253}
254
255static object *
256dbm_nextkey(dp, args)
257 register dbmobject *dp;
258 object *args;
259{
260 register object *v;
261 datum key, nextkey;
262
263 if (!getargs(args, "s#", &key.dptr, &key.dsize))
264 return NULL;
265 nextkey = gdbm_nextkey(dp->di_dbm, key);
266 if (nextkey.dptr) {
267 v = newsizedstringobject(nextkey.dptr, nextkey.dsize);
268 free(nextkey.dptr);
269 return v;
270 } else {
271 INCREF(None);
272 return None;
273 }
274}
275
276static object *
277dbm_reorganize(dp, args)
278 register dbmobject *dp;
279 object *args;
280{
281 if (!getnoarg(args))
282 return NULL;
283 errno = 0;
284 if (gdbm_reorganize(dp->di_dbm) < 0) {
285 if (errno != 0)
286 err_errno(DbmError);
287 else
288 err_setstr(DbmError, (char *) gdbm_strerror(gdbm_errno));
289 return NULL;
290 }
291 INCREF(None);
292 return None;
293}
294
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000295static struct methodlist dbm_methods[] = {
Guido van Rossum807b7be1995-07-07 22:37:11 +0000296 {"close", (method)dbm_close},
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000297 {"keys", (method)dbm_keys},
298 {"has_key", (method)dbm_has_key},
Guido van Rossumfbd30e91995-03-16 16:07:34 +0000299 {"firstkey", (method)dbm_firstkey},
300 {"nextkey", (method)dbm_nextkey},
301 {"reorganize", (method)dbm_reorganize},
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000302 {NULL, NULL} /* sentinel */
303};
304
305static object *
306dbm_getattr(dp, name)
307 dbmobject *dp;
308 char *name;
309{
310 return findmethod(dbm_methods, (object *)dp, name);
311}
312
313static typeobject Dbmtype = {
314 OB_HEAD_INIT(&Typetype)
315 0,
Guido van Rossum807b7be1995-07-07 22:37:11 +0000316 "gdbm",
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000317 sizeof(dbmobject),
318 0,
319 (destructor)dbm_dealloc, /*tp_dealloc*/
320 0, /*tp_print*/
321 (getattrfunc)dbm_getattr, /*tp_getattr*/
322 0, /*tp_setattr*/
323 0, /*tp_compare*/
324 0, /*tp_repr*/
325 0, /*tp_as_number*/
326 0, /*tp_as_sequence*/
327 &dbm_as_mapping, /*tp_as_mapping*/
328};
329
330/* ----------------------------------------------------------------- */
331
332static object *
333dbmopen(self, args)
334 object *self;
335 object *args;
336{
Guido van Rossum807b7be1995-07-07 22:37:11 +0000337 char *name;
338 char *flags = "r";
339 int iflags;
340 int mode = 0666;
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000341
342/* XXXX add other flags */
Guido van Rossum807b7be1995-07-07 22:37:11 +0000343 if ( !newgetargs(args, "s|si", &name, &flags, &mode) )
344 return NULL;
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000345 if ( strcmp(flags, "r") == 0 )
346 iflags = GDBM_READER;
347 else if ( strcmp(flags, "w") == 0 )
348 iflags = GDBM_WRITER;
349 else if ( strcmp(flags, "c") == 0 )
350 iflags = GDBM_WRCREAT;
351 else if ( strcmp(flags, "n") == 0 )
352 iflags = GDBM_NEWDB;
353 else {
354 err_setstr(DbmError,
Guido van Rossumb045afc1995-03-14 15:04:40 +0000355 "Flags should be one of 'r', 'w', 'c' or 'n'");
Guido van Rossum807b7be1995-07-07 22:37:11 +0000356 return NULL;
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000357 }
358 return newdbmobject(name, iflags, mode);
359}
360
361static struct methodlist dbmmodule_methods[] = {
Guido van Rossum807b7be1995-07-07 22:37:11 +0000362 { "open", (method)dbmopen, 1 },
Guido van Rossum4b4c6641994-08-08 08:06:37 +0000363 { 0, 0 },
364};
365
366void
367initgdbm() {
368 object *m, *d;
369
370 m = initmodule("gdbm", dbmmodule_methods);
371 d = getmoduledict(m);
372 DbmError = newstringobject("gdbm.error");
373 if ( DbmError == NULL || dictinsert(d, "error", DbmError) )
374 fatal("can't define gdbm.error");
375}