blob: 6fd9bd56084d6362a3e7fde24827255e3802051d [file] [log] [blame]
Guido van Rossum81daa321993-05-20 14:24:46 +00001/***********************************************************
2Copyright 1991, 1992, 1993 by Stichting Mathematisch Centrum,
3Amsterdam, The Netherlands.
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/* Access object implementation */
26
27#include "allobjects.h"
28
29#include "structmember.h"
30#include "modsupport.h" /* For getargs() etc. */
31
32typedef struct {
33 OB_HEAD
34 object *ac_value;
35 object *ac_class;
36 typeobject *ac_type;
37 int ac_mode;
38} accessobject;
39
40/* Forward */
41static int typecheck PROTO((object *, typeobject *));
42static int classcheck PROTO((object *, object *, int, int));
43
44object *
45newaccessobject(value, class, type, mode)
46 object *value;
47 object *class;
48 typeobject *type;
49 int mode;
50{
51 accessobject *ap;
52 if (class != NULL && !is_classobject(class)) {
53 err_badcall();
54 return NULL;
55 }
56 if (!typecheck(value, type)) {
57 err_setstr(AccessError,
58 "access: initial value has inappropriate type");
59 return NULL;
60 }
61 ap = NEWOBJ(accessobject, &Accesstype);
62 if (ap == NULL)
63 return NULL;
64 XINCREF(value);
65 ap->ac_value = value;
66 XINCREF(class);
67 ap->ac_class = class;
68 XINCREF(type);
69 ap->ac_type = (typeobject *)type;
70 ap->ac_mode = mode;
71 return (object *)ap;
72}
73
74object *
75cloneaccessobject(op)
76 object *op;
77{
78 register accessobject *ap;
79 if (!is_accessobject(op)) {
80 err_badcall();
81 return NULL;
82 }
83 ap = (accessobject *)op;
84 return newaccessobject(ap->ac_value, ap->ac_class,
85 ap->ac_type, ap->ac_mode);
86}
87
88void
89setaccessowner(op, class)
90 object *op;
91 object *class;
92{
93 register accessobject *ap;
94 if (!is_accessobject(op) || class != NULL && !is_classobject(class))
95 return; /* XXX no error */
96 ap = (accessobject *)op;
97 XDECREF(ap->ac_class);
98 XINCREF(class);
99 ap->ac_class = class;
100}
101
Guido van Rossumb3f72581993-05-21 19:56:10 +0000102int
103hasaccessvalue(op)
104 object *op;
105{
106 if (!is_accessobject(op))
107 return 0;
108 return ((accessobject *)op)->ac_value != NULL;
109}
110
Guido van Rossum81daa321993-05-20 14:24:46 +0000111object *
112getaccessvalue(op, class)
113 object *op;
114 object *class;
115{
116 register accessobject *ap;
117 if (!is_accessobject(op)) {
118 err_badcall();
119 return NULL;
120 }
121 ap = (accessobject *)op;
122
123 if (!classcheck(class, ap->ac_class, AC_R, ap->ac_mode)) {
124 err_setstr(AccessError, "read access denied");
125 return NULL;
126 }
127
128 if (ap->ac_value == NULL) {
129 err_setstr(AccessError, "no current value");
130 return NULL;
131 }
132 INCREF(ap->ac_value);
133 return ap->ac_value;
134}
135
136int
137setaccessvalue(op, class, value)
138 object *op;
139 object *class;
140 object *value;
141{
142 register accessobject *ap;
143 if (!is_accessobject(op)) {
144 err_badcall();
145 return -1;
146 }
147 ap = (accessobject *)op;
148
149 if (!classcheck(class, ap->ac_class, AC_W, ap->ac_mode)) {
150 err_setstr(AccessError, "write access denied");
151 return -1;
152 }
153
154 if (!typecheck(value, ap->ac_type)) {
155 err_setstr(AccessError, "assign value of inappropriate type");
156 return -1;
157 }
158
159 if (value == NULL) { /* Delete it */
160 if (ap->ac_value == NULL) {
161 err_setstr(AccessError, "no current value");
162 return -1;
163 }
164 DECREF(ap->ac_value);
165 ap->ac_value = NULL;
166 return 0;
167 }
168 XDECREF(ap->ac_value);
169 INCREF(value);
170 ap->ac_value = value;
171 return 0;
172}
173
174static int
175typecheck(value, type)
176 object *value;
177 typeobject *type;
178{
179 object *x;
180 if (value == NULL || type == NULL)
181 return 1; /* No check */
182 if (value->ob_type == type)
183 return 1; /* Exact match */
184 if (type == &Anynumbertype) {
185 if (value->ob_type->tp_as_number == NULL)
186 return 0;
187 if (!is_instanceobject(value))
188 return 1;
189 /* For instances, make sure it really looks like a number */
190 x = getattr(value, "__sub__");
191 if (x == NULL) {
192 err_clear();
193 return 0;
194 }
195 DECREF(x);
196 return 1;
197 }
198 if (type == &Anysequencetype) {
199 if (value->ob_type->tp_as_sequence == NULL)
200 return 0;
201 if (!is_instanceobject(value))
202 return 1;
203 /* For instances, make sure it really looks like a sequence */
204 x = getattr(value, "__getslice__");
205 if (x == NULL) {
206 err_clear();
207 return 0;
208 }
209 DECREF(x);
210 return 1;
211 }
212 if (type == &Anymappingtype) {
213 if (value->ob_type->tp_as_mapping == NULL)
214 return 0;
215 if (!is_instanceobject(value))
216 return 1;
217 /* For instances, make sure it really looks like a mapping */
218 x = getattr(value, "__getitem__");
219 if (x == NULL) {
220 err_clear();
221 return 0;
222 }
223 DECREF(x);
224 return 1;
225 }
226 return 0;
227}
228
229static int
230classcheck(caller, owner, access, mode)
231 object *caller;
232 object *owner;
233 int access;
234 int mode;
235{
236 if (caller == owner && owner != NULL)
237 return access & mode & (AC_PRIVATE|AC_PROTECTED|AC_PUBLIC);
238 if (caller != NULL && owner != NULL && issubclass(caller, owner))
239 return access & mode & (AC_PROTECTED|AC_PUBLIC);
240 return access & mode & AC_PUBLIC;
241}
242
243/* Access methods */
244
245static void
246access_dealloc(ap)
247 accessobject *ap;
248{
249 XDECREF(ap->ac_value);
250 XDECREF(ap->ac_class);
251 XDECREF(ap->ac_type);
252 DEL(ap);
253}
254
255#define OFF(x) offsetof(accessobject, x)
256
257static struct memberlist access_memberlist[] = {
258 {"ac_value", T_OBJECT, OFF(ac_value)},
259 {"ac_class", T_OBJECT, OFF(ac_class)},
260 {"ac_type", T_OBJECT, OFF(ac_type)},
261 {"ac_mode", T_INT, OFF(ac_mode)},
262 {NULL} /* Sentinel */
263};
264
265static object *
266access_getattr(ap, name)
267 accessobject *ap;
268 char *name;
269{
270 return getmember((char *)ap, access_memberlist, name);
271}
272
273static object *
274access_repr(ap)
275 accessobject *ap;
276{
277 char buf[300];
278 classobject *class = (classobject *)ap->ac_class;
279 typeobject *type = ap->ac_type;
Guido van Rossumb3f72581993-05-21 19:56:10 +0000280 sprintf(buf,
281 "<access object, value 0x%lx, class %.100s, type %.100s, mode %04o>",
282 (long)(ap->ac_value),
Guido van Rossum81daa321993-05-20 14:24:46 +0000283 class ? getstringvalue(class->cl_name) : "-",
284 type ? type->tp_name : "-",
285 ap->ac_mode);
286 return newstringobject(buf);
287}
288
289typeobject Accesstype = {
290 OB_HEAD_INIT(&Typetype)
291 0, /*ob_size*/
292 "access", /*tp_name*/
293 sizeof(accessobject), /*tp_size*/
294 0, /*tp_itemsize*/
295 /* methods */
296 access_dealloc, /*tp_dealloc*/
297 0, /*tp_print*/
298 access_getattr, /*tp_getattr*/
299 0, /*tp_setattr*/
300 0, /*tp_compare*/
301 access_repr, /*tp_repr*/
302 0, /*tp_as_number*/
303 0, /*tp_as_sequence*/
304 0, /*tp_as_mapping*/
305 0, /*tp_hash*/
306};
307
308/* Dummy type objects to indicate classes of types */
309
310/* XXX This should be replaced by a more general "subclassing"
311 XXX mechanism for type objects... */
312
313typeobject Anynumbertype = {
314 OB_HEAD_INIT(&Typetype)
315 0, /*ob_size*/
316 "*number*", /*tp_name*/
317};
318
319/* XXX Should really distinguish mutable and immutable sequences as well */
320
321typeobject Anysequencetype = {
322 OB_HEAD_INIT(&Typetype)
323 0, /*ob_size*/
324 "*sequence*", /*tp_name*/
325};
326
327typeobject Anymappingtype = {
328 OB_HEAD_INIT(&Typetype)
329 0, /*ob_size*/
330 "*mapping*", /*tp_name*/
331};