blob: 46559798a01c7479ec7b226d203493fcf29878ca [file] [log] [blame]
Guido van Rossumdd9ed831992-06-29 17:10:40 +00001/***********************************************************
2Copyright 1991, 1992 by Stichting Mathematisch Centrum, Amsterdam, The
3Netherlands.
4
5 All Rights Reserved
6
7Permission to use, copy, modify, and distribute this software and its
8documentation for any purpose and without fee is hereby granted,
9provided that the above copyright notice appear in all copies and that
10both that copyright notice and this permission notice appear in
11supporting documentation, and that the names of Stichting Mathematisch
12Centrum or CWI not be used in advertising or publicity pertaining to
13distribution of the software without specific, written prior permission.
14
15STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
16THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
18FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
21OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22
23******************************************************************/
24
25/* DBM module using dictionary interface */
26
27
28#include "allobjects.h"
29#include "modsupport.h"
30
31#include <sys/types.h>
32#include <sys/stat.h>
33#include <fcntl.h>
34#include <ndbm.h>
35
36typedef struct {
37 OB_HEAD
38 int di_size; /* -1 means recompute */
39 DBM *di_dbm;
40} dbmobject;
41
42extern typeobject Dbmtype; /* Really forward */
43
44#define is_dbmobject(v) ((v)->ob_type == &Dbmtype)
45
46static object *DbmError;
47
48static object *
49newdbmobject(file, flags, mode)
50 char *file;
51 int flags;
52 int mode;
53{
54 dbmobject *dp;
55
56 dp = NEWOBJ(dbmobject, &Dbmtype);
57 if (dp == NULL)
58 return NULL;
59 dp->di_size = -1;
60 if ( (dp->di_dbm = dbm_open(file, flags, mode)) == 0 ) {
61 err_errno(DbmError);
62 DECREF(dp);
63 return 0;
64 }
65 return (object *)dp;
66}
67
68/* Methods */
69
70static void
71dbm_dealloc(dp)
72 register dbmobject *dp;
73{
74 if ( dp->di_dbm )
75 dbm_close(dp->di_dbm);
76 DEL(dp);
77}
78
79static int
80dbm_length(dp)
81 dbmobject *dp;
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
96static object *
97dbm_subscript(dp, key)
98 dbmobject *dp;
99 register object *key;
100{
101 object *v;
102 datum drec, krec;
103
104 if (!getargs(key, "s#", &krec.dptr, &krec.dsize) )
105 return NULL;
106
107 drec = dbm_fetch(dp->di_dbm, krec);
108 if ( drec.dptr == 0 ) {
109 err_setstr(KeyError, GETSTRINGVALUE((stringobject *)key));
110 return 0;
111 }
112 if ( dbm_error(dp->di_dbm) ) {
113 dbm_clearerr(dp->di_dbm);
114 err_setstr(DbmError, "");
115 return 0;
116 }
117 return newsizedstringobject(drec.dptr, drec.dsize);
118}
119
120static int
121dbm_ass_sub(dp, v, w)
122 dbmobject *dp;
123 object *v, *w;
124{
125 datum krec, drec;
126
127 if ( !getargs(v, "s#", &krec.dptr, &krec.dsize) ) {
128 err_setstr(TypeError, "dbm mappings have string indices only");
129 return -1;
130 }
131 dp->di_size = -1;
132 if (w == NULL) {
133 if ( dbm_delete(dp->di_dbm, krec) < 0 ) {
134 err_setstr(KeyError, GETSTRINGVALUE((stringobject *)v));
135 return -1;
136 }
137 } else {
138 if ( !getargs(w, "s#", &drec.dptr, &drec.dsize) ) {
139 err_setstr(TypeError,
140 "dbm mappings have string elements only");
141 return -1;
142 }
143 if ( dbm_store(dp->di_dbm, krec, drec, DBM_REPLACE) < 0 ) {
144 err_setstr(DbmError, "Cannot add item to database");
145 return -1;
146 }
147 }
148 if ( dbm_error(dp->di_dbm) ) {
149 dbm_clearerr(dp->di_dbm);
150 err_setstr(DbmError, "");
151 return -1;
152 }
153 return 0;
154}
155
156static mapping_methods dbm_as_mapping = {
157 dbm_length, /*mp_length*/
158 dbm_subscript, /*mp_subscript*/
159 dbm_ass_sub, /*mp_ass_subscript*/
160};
161
162static object *
163dbm_keys(dp, args)
164 register dbmobject *dp;
165 object *args;
166{
167 register object *v, *item;
168 datum key;
169
170 if (dp == NULL || !is_dbmobject(dp)) {
171 err_badcall();
172 return NULL;
173 }
174 if (!getnoarg(args))
175 return NULL;
176 v = newlistobject(0);
177 if (v == NULL)
178 return NULL;
179 for (key = dbm_firstkey(dp->di_dbm); key.dptr;
180 key = dbm_nextkey(dp->di_dbm) ) {
181 item = newsizedstringobject(key.dptr, key.dsize);
182 if ( item == 0 )
183 return NULL;
184 addlistitem(v, item);
185 }
186 return v;
187}
188
189
190static object *
191dbm_has_key(dp, args)
192 register dbmobject *dp;
193 object *args;
194{
195 datum key, val;
196
197 if (!getargs(args, "s#", &key.dptr, &key.dsize))
198 return NULL;
199 val = dbm_fetch(dp->di_dbm, key);
200 return newintobject(val.dptr != NULL);
201}
202
203static struct methodlist dbm_methods[] = {
204 {"keys", dbm_keys},
205 {"has_key", dbm_has_key},
206 {NULL, NULL} /* sentinel */
207};
208
209static object *
210dbm_getattr(dp, name)
211 dbmobject *dp;
212 char *name;
213{
214 return findmethod(dbm_methods, (object *)dp, name);
215}
216
217typeobject Dbmtype = {
218 OB_HEAD_INIT(&Typetype)
219 0,
220 "Dbm_dictionary",
221 sizeof(dbmobject),
222 0,
223 dbm_dealloc, /*tp_dealloc*/
224 0, /*tp_print*/
225 dbm_getattr, /*tp_getattr*/
226 0, /*tp_setattr*/
227 0, /*tp_compare*/
228 0, /*tp_repr*/
229 0, /*tp_as_number*/
230 0, /*tp_as_sequence*/
231 &dbm_as_mapping, /*tp_as_mapping*/
232};
233
234/* ----------------------------------------------------------------- */
235
236static object *
237dbmopen(self, args)
238 object *self;
239 object *args;
240{
241 char *name, *flags;
242 int iflags, mode;
243
244 if ( !getargs(args, "(ssi)", &name, &flags, &mode) )
245 return 0;
246 if ( strcmp(flags, "r") == 0 )
247 iflags = O_RDONLY;
248 else if ( strcmp(flags, "w") == 0 )
249 iflags = O_WRONLY|O_CREAT;
250 else if ( strcmp(flags, "rw") == 0 )
251 iflags = O_RDWR|O_CREAT;
252 else {
253 err_setstr(DbmError,
254 "Flags should be one of 'r', 'w' or 'rw'");
255 return 0;
256 }
257 return newdbmobject(name, iflags, mode);
258}
259
260static struct methodlist dbmmodule_methods[] = {
261 { "open", dbmopen },
262 { 0, 0 },
263};
264
265void
266initdbm() {
267 object *m, *d;
268
269 m = initmodule("dbm", dbmmodule_methods);
270 d = getmoduledict(m);
271 DbmError = newstringobject("dbm.error");
272 if ( DbmError == NULL || dictinsert(d, "error", DbmError) )
273 fatal("can't define dbm.error");
274}
275
276