blob: c9b7ce385b65dced4b61707e1a3b551dc6aff4c8 [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
Guido van Rossum234f9421993-06-17 12:35:49 +000027/* XXX TO DO LIST
28 - need a "super user" mechanism for debugger etc.
29 - __init__ and __del__ (and all other similar methods)
30 should be usable even when private, not ignored
31 - "from foo import bar" should check access of bar
32*/
33
Guido van Rossum81daa321993-05-20 14:24:46 +000034#include "allobjects.h"
35
36#include "structmember.h"
37#include "modsupport.h" /* For getargs() etc. */
38
39typedef struct {
40 OB_HEAD
41 object *ac_value;
Guido van Rossumeb6b33a1993-05-25 09:38:27 +000042 object *ac_owner;
Guido van Rossum81daa321993-05-20 14:24:46 +000043 typeobject *ac_type;
44 int ac_mode;
45} accessobject;
46
47/* Forward */
48static int typecheck PROTO((object *, typeobject *));
Guido van Rossumeb6b33a1993-05-25 09:38:27 +000049static int ownercheck PROTO((object *, object *, int, int));
Guido van Rossum81daa321993-05-20 14:24:46 +000050
51object *
Guido van Rossumeb6b33a1993-05-25 09:38:27 +000052newaccessobject(value, owner, type, mode)
Guido van Rossum81daa321993-05-20 14:24:46 +000053 object *value;
Guido van Rossumeb6b33a1993-05-25 09:38:27 +000054 object *owner;
Guido van Rossum81daa321993-05-20 14:24:46 +000055 typeobject *type;
56 int mode;
57{
58 accessobject *ap;
Guido van Rossum81daa321993-05-20 14:24:46 +000059 if (!typecheck(value, type)) {
60 err_setstr(AccessError,
61 "access: initial value has inappropriate type");
62 return NULL;
63 }
64 ap = NEWOBJ(accessobject, &Accesstype);
65 if (ap == NULL)
66 return NULL;
67 XINCREF(value);
68 ap->ac_value = value;
Guido van Rossumeb6b33a1993-05-25 09:38:27 +000069 XINCREF(owner);
70 ap->ac_owner = owner;
Guido van Rossum81daa321993-05-20 14:24:46 +000071 XINCREF(type);
72 ap->ac_type = (typeobject *)type;
73 ap->ac_mode = mode;
74 return (object *)ap;
75}
76
77object *
78cloneaccessobject(op)
79 object *op;
80{
81 register accessobject *ap;
82 if (!is_accessobject(op)) {
83 err_badcall();
84 return NULL;
85 }
86 ap = (accessobject *)op;
Guido van Rossumeb6b33a1993-05-25 09:38:27 +000087 return newaccessobject(ap->ac_value, ap->ac_owner,
Guido van Rossum81daa321993-05-20 14:24:46 +000088 ap->ac_type, ap->ac_mode);
89}
90
91void
Guido van Rossumeb6b33a1993-05-25 09:38:27 +000092setaccessowner(op, owner)
Guido van Rossum81daa321993-05-20 14:24:46 +000093 object *op;
Guido van Rossumeb6b33a1993-05-25 09:38:27 +000094 object *owner;
Guido van Rossum81daa321993-05-20 14:24:46 +000095{
96 register accessobject *ap;
Guido van Rossumeb6b33a1993-05-25 09:38:27 +000097 if (!is_accessobject(op))
Guido van Rossum81daa321993-05-20 14:24:46 +000098 return; /* XXX no error */
99 ap = (accessobject *)op;
Guido van Rossumeb6b33a1993-05-25 09:38:27 +0000100 XDECREF(ap->ac_owner);
101 XINCREF(owner);
102 ap->ac_owner = owner;
Guido van Rossum81daa321993-05-20 14:24:46 +0000103}
104
Guido van Rossumb3f72581993-05-21 19:56:10 +0000105int
106hasaccessvalue(op)
107 object *op;
108{
109 if (!is_accessobject(op))
110 return 0;
111 return ((accessobject *)op)->ac_value != NULL;
112}
113
Guido van Rossum81daa321993-05-20 14:24:46 +0000114object *
Guido van Rossumeb6b33a1993-05-25 09:38:27 +0000115getaccessvalue(op, owner)
Guido van Rossum81daa321993-05-20 14:24:46 +0000116 object *op;
Guido van Rossumeb6b33a1993-05-25 09:38:27 +0000117 object *owner;
Guido van Rossum81daa321993-05-20 14:24:46 +0000118{
119 register accessobject *ap;
120 if (!is_accessobject(op)) {
121 err_badcall();
122 return NULL;
123 }
124 ap = (accessobject *)op;
125
Guido van Rossumeb6b33a1993-05-25 09:38:27 +0000126 if (!ownercheck(owner, ap->ac_owner, AC_R, ap->ac_mode)) {
Guido van Rossum81daa321993-05-20 14:24:46 +0000127 err_setstr(AccessError, "read access denied");
128 return NULL;
129 }
130
131 if (ap->ac_value == NULL) {
132 err_setstr(AccessError, "no current value");
133 return NULL;
134 }
135 INCREF(ap->ac_value);
136 return ap->ac_value;
137}
138
139int
Guido van Rossumeb6b33a1993-05-25 09:38:27 +0000140setaccessvalue(op, owner, value)
Guido van Rossum81daa321993-05-20 14:24:46 +0000141 object *op;
Guido van Rossumeb6b33a1993-05-25 09:38:27 +0000142 object *owner;
Guido van Rossum81daa321993-05-20 14:24:46 +0000143 object *value;
144{
145 register accessobject *ap;
146 if (!is_accessobject(op)) {
147 err_badcall();
148 return -1;
149 }
150 ap = (accessobject *)op;
151
Guido van Rossumeb6b33a1993-05-25 09:38:27 +0000152 if (!ownercheck(owner, ap->ac_owner, AC_W, ap->ac_mode)) {
Guido van Rossum81daa321993-05-20 14:24:46 +0000153 err_setstr(AccessError, "write access denied");
154 return -1;
155 }
156
157 if (!typecheck(value, ap->ac_type)) {
158 err_setstr(AccessError, "assign value of inappropriate type");
159 return -1;
160 }
161
162 if (value == NULL) { /* Delete it */
163 if (ap->ac_value == NULL) {
164 err_setstr(AccessError, "no current value");
165 return -1;
166 }
167 DECREF(ap->ac_value);
168 ap->ac_value = NULL;
169 return 0;
170 }
171 XDECREF(ap->ac_value);
172 INCREF(value);
173 ap->ac_value = value;
174 return 0;
175}
176
177static int
178typecheck(value, type)
179 object *value;
180 typeobject *type;
181{
182 object *x;
183 if (value == NULL || type == NULL)
184 return 1; /* No check */
185 if (value->ob_type == type)
186 return 1; /* Exact match */
187 if (type == &Anynumbertype) {
188 if (value->ob_type->tp_as_number == NULL)
189 return 0;
190 if (!is_instanceobject(value))
191 return 1;
192 /* For instances, make sure it really looks like a number */
193 x = getattr(value, "__sub__");
194 if (x == NULL) {
195 err_clear();
196 return 0;
197 }
198 DECREF(x);
199 return 1;
200 }
201 if (type == &Anysequencetype) {
202 if (value->ob_type->tp_as_sequence == NULL)
203 return 0;
204 if (!is_instanceobject(value))
205 return 1;
206 /* For instances, make sure it really looks like a sequence */
207 x = getattr(value, "__getslice__");
208 if (x == NULL) {
209 err_clear();
210 return 0;
211 }
212 DECREF(x);
213 return 1;
214 }
215 if (type == &Anymappingtype) {
216 if (value->ob_type->tp_as_mapping == NULL)
217 return 0;
218 if (!is_instanceobject(value))
219 return 1;
220 /* For instances, make sure it really looks like a mapping */
221 x = getattr(value, "__getitem__");
222 if (x == NULL) {
223 err_clear();
224 return 0;
225 }
226 DECREF(x);
227 return 1;
228 }
229 return 0;
230}
231
232static int
Guido van Rossumeb6b33a1993-05-25 09:38:27 +0000233ownercheck(caller, owner, access, mode)
Guido van Rossum81daa321993-05-20 14:24:46 +0000234 object *caller;
235 object *owner;
236 int access;
237 int mode;
238{
Guido van Rossumeb6b33a1993-05-25 09:38:27 +0000239 int mask = AC_PUBLIC;
240 if (owner != NULL) {
241 if (caller == owner)
242 mask |= AC_PRIVATE | AC_PROTECTED;
243 else if (is_classobject(owner) && issubclass(caller, owner))
244 mask |= AC_PROTECTED;
245 }
246 return access & mode & mask;
Guido van Rossum81daa321993-05-20 14:24:46 +0000247}
248
249/* Access methods */
250
251static void
252access_dealloc(ap)
253 accessobject *ap;
254{
255 XDECREF(ap->ac_value);
Guido van Rossumeb6b33a1993-05-25 09:38:27 +0000256 XDECREF(ap->ac_owner);
Guido van Rossum81daa321993-05-20 14:24:46 +0000257 XDECREF(ap->ac_type);
258 DEL(ap);
259}
260
261#define OFF(x) offsetof(accessobject, x)
262
263static struct memberlist access_memberlist[] = {
264 {"ac_value", T_OBJECT, OFF(ac_value)},
Guido van Rossumeb6b33a1993-05-25 09:38:27 +0000265 {"ac_owner", T_OBJECT, OFF(ac_owner)},
Guido van Rossum81daa321993-05-20 14:24:46 +0000266 {"ac_type", T_OBJECT, OFF(ac_type)},
267 {"ac_mode", T_INT, OFF(ac_mode)},
268 {NULL} /* Sentinel */
269};
270
271static object *
272access_getattr(ap, name)
273 accessobject *ap;
274 char *name;
275{
276 return getmember((char *)ap, access_memberlist, name);
277}
278
279static object *
280access_repr(ap)
281 accessobject *ap;
282{
283 char buf[300];
Guido van Rossumeb6b33a1993-05-25 09:38:27 +0000284 char buf2[20];
285 char *ownername;
Guido van Rossum81daa321993-05-20 14:24:46 +0000286 typeobject *type = ap->ac_type;
Guido van Rossumeb6b33a1993-05-25 09:38:27 +0000287 if (is_classobject(ap->ac_owner)) {
288 ownername =
289 getstringvalue(((classobject *)ap->ac_owner)->cl_name);
290 }
291 else {
292 sprintf(buf2, "0x%lx", (long)ap->ac_owner);
293 ownername = buf2;
294 }
Guido van Rossumb3f72581993-05-21 19:56:10 +0000295 sprintf(buf,
Guido van Rossumeb6b33a1993-05-25 09:38:27 +0000296 "<access object, value 0x%lx, owner %.100s, type %.100s, mode %04o>",
Guido van Rossumb3f72581993-05-21 19:56:10 +0000297 (long)(ap->ac_value),
Guido van Rossumeb6b33a1993-05-25 09:38:27 +0000298 ownername,
Guido van Rossum81daa321993-05-20 14:24:46 +0000299 type ? type->tp_name : "-",
300 ap->ac_mode);
301 return newstringobject(buf);
302}
303
304typeobject Accesstype = {
305 OB_HEAD_INIT(&Typetype)
306 0, /*ob_size*/
307 "access", /*tp_name*/
308 sizeof(accessobject), /*tp_size*/
309 0, /*tp_itemsize*/
310 /* methods */
311 access_dealloc, /*tp_dealloc*/
312 0, /*tp_print*/
313 access_getattr, /*tp_getattr*/
314 0, /*tp_setattr*/
315 0, /*tp_compare*/
316 access_repr, /*tp_repr*/
317 0, /*tp_as_number*/
318 0, /*tp_as_sequence*/
319 0, /*tp_as_mapping*/
320 0, /*tp_hash*/
321};
322
Guido van Rossumeb6b33a1993-05-25 09:38:27 +0000323
324/* Pseudo type objects to indicate collections of types */
Guido van Rossum81daa321993-05-20 14:24:46 +0000325
326/* XXX This should be replaced by a more general "subclassing"
327 XXX mechanism for type objects... */
328
329typeobject Anynumbertype = {
330 OB_HEAD_INIT(&Typetype)
331 0, /*ob_size*/
332 "*number*", /*tp_name*/
333};
334
335/* XXX Should really distinguish mutable and immutable sequences as well */
336
337typeobject Anysequencetype = {
338 OB_HEAD_INIT(&Typetype)
339 0, /*ob_size*/
340 "*sequence*", /*tp_name*/
341};
342
343typeobject Anymappingtype = {
344 OB_HEAD_INIT(&Typetype)
345 0, /*ob_size*/
346 "*mapping*", /*tp_name*/
347};