blob: 41790cd30633058ce2188f55b4fcdb0c2acab797 [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
102object *
103getaccessvalue(op, class)
104 object *op;
105 object *class;
106{
107 register accessobject *ap;
108 if (!is_accessobject(op)) {
109 err_badcall();
110 return NULL;
111 }
112 ap = (accessobject *)op;
113
114 if (!classcheck(class, ap->ac_class, AC_R, ap->ac_mode)) {
115 err_setstr(AccessError, "read access denied");
116 return NULL;
117 }
118
119 if (ap->ac_value == NULL) {
120 err_setstr(AccessError, "no current value");
121 return NULL;
122 }
123 INCREF(ap->ac_value);
124 return ap->ac_value;
125}
126
127int
128setaccessvalue(op, class, value)
129 object *op;
130 object *class;
131 object *value;
132{
133 register accessobject *ap;
134 if (!is_accessobject(op)) {
135 err_badcall();
136 return -1;
137 }
138 ap = (accessobject *)op;
139
140 if (!classcheck(class, ap->ac_class, AC_W, ap->ac_mode)) {
141 err_setstr(AccessError, "write access denied");
142 return -1;
143 }
144
145 if (!typecheck(value, ap->ac_type)) {
146 err_setstr(AccessError, "assign value of inappropriate type");
147 return -1;
148 }
149
150 if (value == NULL) { /* Delete it */
151 if (ap->ac_value == NULL) {
152 err_setstr(AccessError, "no current value");
153 return -1;
154 }
155 DECREF(ap->ac_value);
156 ap->ac_value = NULL;
157 return 0;
158 }
159 XDECREF(ap->ac_value);
160 INCREF(value);
161 ap->ac_value = value;
162 return 0;
163}
164
165static int
166typecheck(value, type)
167 object *value;
168 typeobject *type;
169{
170 object *x;
171 if (value == NULL || type == NULL)
172 return 1; /* No check */
173 if (value->ob_type == type)
174 return 1; /* Exact match */
175 if (type == &Anynumbertype) {
176 if (value->ob_type->tp_as_number == NULL)
177 return 0;
178 if (!is_instanceobject(value))
179 return 1;
180 /* For instances, make sure it really looks like a number */
181 x = getattr(value, "__sub__");
182 if (x == NULL) {
183 err_clear();
184 return 0;
185 }
186 DECREF(x);
187 return 1;
188 }
189 if (type == &Anysequencetype) {
190 if (value->ob_type->tp_as_sequence == NULL)
191 return 0;
192 if (!is_instanceobject(value))
193 return 1;
194 /* For instances, make sure it really looks like a sequence */
195 x = getattr(value, "__getslice__");
196 if (x == NULL) {
197 err_clear();
198 return 0;
199 }
200 DECREF(x);
201 return 1;
202 }
203 if (type == &Anymappingtype) {
204 if (value->ob_type->tp_as_mapping == NULL)
205 return 0;
206 if (!is_instanceobject(value))
207 return 1;
208 /* For instances, make sure it really looks like a mapping */
209 x = getattr(value, "__getitem__");
210 if (x == NULL) {
211 err_clear();
212 return 0;
213 }
214 DECREF(x);
215 return 1;
216 }
217 return 0;
218}
219
220static int
221classcheck(caller, owner, access, mode)
222 object *caller;
223 object *owner;
224 int access;
225 int mode;
226{
227 if (caller == owner && owner != NULL)
228 return access & mode & (AC_PRIVATE|AC_PROTECTED|AC_PUBLIC);
229 if (caller != NULL && owner != NULL && issubclass(caller, owner))
230 return access & mode & (AC_PROTECTED|AC_PUBLIC);
231 return access & mode & AC_PUBLIC;
232}
233
234/* Access methods */
235
236static void
237access_dealloc(ap)
238 accessobject *ap;
239{
240 XDECREF(ap->ac_value);
241 XDECREF(ap->ac_class);
242 XDECREF(ap->ac_type);
243 DEL(ap);
244}
245
246#define OFF(x) offsetof(accessobject, x)
247
248static struct memberlist access_memberlist[] = {
249 {"ac_value", T_OBJECT, OFF(ac_value)},
250 {"ac_class", T_OBJECT, OFF(ac_class)},
251 {"ac_type", T_OBJECT, OFF(ac_type)},
252 {"ac_mode", T_INT, OFF(ac_mode)},
253 {NULL} /* Sentinel */
254};
255
256static object *
257access_getattr(ap, name)
258 accessobject *ap;
259 char *name;
260{
261 return getmember((char *)ap, access_memberlist, name);
262}
263
264static object *
265access_repr(ap)
266 accessobject *ap;
267{
268 char buf[300];
269 classobject *class = (classobject *)ap->ac_class;
270 typeobject *type = ap->ac_type;
271 sprintf(buf, "<access object, class %.100s, type %.100s, mode 0%o>",
272 class ? getstringvalue(class->cl_name) : "-",
273 type ? type->tp_name : "-",
274 ap->ac_mode);
275 return newstringobject(buf);
276}
277
278typeobject Accesstype = {
279 OB_HEAD_INIT(&Typetype)
280 0, /*ob_size*/
281 "access", /*tp_name*/
282 sizeof(accessobject), /*tp_size*/
283 0, /*tp_itemsize*/
284 /* methods */
285 access_dealloc, /*tp_dealloc*/
286 0, /*tp_print*/
287 access_getattr, /*tp_getattr*/
288 0, /*tp_setattr*/
289 0, /*tp_compare*/
290 access_repr, /*tp_repr*/
291 0, /*tp_as_number*/
292 0, /*tp_as_sequence*/
293 0, /*tp_as_mapping*/
294 0, /*tp_hash*/
295};
296
297/* Dummy type objects to indicate classes of types */
298
299/* XXX This should be replaced by a more general "subclassing"
300 XXX mechanism for type objects... */
301
302typeobject Anynumbertype = {
303 OB_HEAD_INIT(&Typetype)
304 0, /*ob_size*/
305 "*number*", /*tp_name*/
306};
307
308/* XXX Should really distinguish mutable and immutable sequences as well */
309
310typeobject Anysequencetype = {
311 OB_HEAD_INIT(&Typetype)
312 0, /*ob_size*/
313 "*sequence*", /*tp_name*/
314};
315
316typeobject Anymappingtype = {
317 OB_HEAD_INIT(&Typetype)
318 0, /*ob_size*/
319 "*mapping*", /*tp_name*/
320};