blob: f3c7dfc9b9ef39f081b8b9f7890b110f5364df38 [file] [log] [blame]
Guido van Rossum81daa321993-05-20 14:24:46 +00001/***********************************************************
Guido van Rossum6610ad91995-01-04 19:07:38 +00002Copyright 1991-1995 by Stichting Mathematisch Centrum, Amsterdam,
3The Netherlands.
Guido van Rossum81daa321993-05-20 14:24:46 +00004
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
Guido van Rossum234f9421993-06-17 12:35:49 +000028 - __init__ and __del__ (and all other similar methods)
Guido van Rossumb6775db1994-08-01 11:34:53 +000029 should be usable even when private, not ignored
Guido van Rossum234f9421993-06-17 12:35:49 +000030*/
31
Guido van Rossum81daa321993-05-20 14:24:46 +000032#include "allobjects.h"
Guido van Rossumed18fdc1993-07-11 19:55:34 +000033#include "ceval.h"
Guido van Rossum81daa321993-05-20 14:24:46 +000034#include "structmember.h"
35#include "modsupport.h" /* For getargs() etc. */
36
37typedef struct {
38 OB_HEAD
39 object *ac_value;
Guido van Rossumeb6b33a1993-05-25 09:38:27 +000040 object *ac_owner;
Guido van Rossum81daa321993-05-20 14:24:46 +000041 typeobject *ac_type;
42 int ac_mode;
43} accessobject;
44
45/* Forward */
46static int typecheck PROTO((object *, typeobject *));
Guido van Rossumeb6b33a1993-05-25 09:38:27 +000047static int ownercheck PROTO((object *, object *, int, int));
Guido van Rossum81daa321993-05-20 14:24:46 +000048
49object *
Guido van Rossumeb6b33a1993-05-25 09:38:27 +000050newaccessobject(value, owner, type, mode)
Guido van Rossum81daa321993-05-20 14:24:46 +000051 object *value;
Guido van Rossumeb6b33a1993-05-25 09:38:27 +000052 object *owner;
Guido van Rossum81daa321993-05-20 14:24:46 +000053 typeobject *type;
54 int mode;
55{
56 accessobject *ap;
Guido van Rossum81daa321993-05-20 14:24:46 +000057 if (!typecheck(value, type)) {
58 err_setstr(AccessError,
59 "access: initial value has inappropriate type");
60 return NULL;
61 }
62 ap = NEWOBJ(accessobject, &Accesstype);
63 if (ap == NULL)
64 return NULL;
65 XINCREF(value);
66 ap->ac_value = value;
Guido van Rossumeb6b33a1993-05-25 09:38:27 +000067 XINCREF(owner);
68 ap->ac_owner = owner;
Guido van Rossum81daa321993-05-20 14:24:46 +000069 XINCREF(type);
70 ap->ac_type = (typeobject *)type;
71 ap->ac_mode = mode;
72 return (object *)ap;
73}
74
75object *
76cloneaccessobject(op)
77 object *op;
78{
79 register accessobject *ap;
80 if (!is_accessobject(op)) {
81 err_badcall();
82 return NULL;
83 }
84 ap = (accessobject *)op;
Guido van Rossumeb6b33a1993-05-25 09:38:27 +000085 return newaccessobject(ap->ac_value, ap->ac_owner,
Guido van Rossum81daa321993-05-20 14:24:46 +000086 ap->ac_type, ap->ac_mode);
87}
88
89void
Guido van Rossumeb6b33a1993-05-25 09:38:27 +000090setaccessowner(op, owner)
Guido van Rossum81daa321993-05-20 14:24:46 +000091 object *op;
Guido van Rossumeb6b33a1993-05-25 09:38:27 +000092 object *owner;
Guido van Rossum81daa321993-05-20 14:24:46 +000093{
94 register accessobject *ap;
Guido van Rossumeb6b33a1993-05-25 09:38:27 +000095 if (!is_accessobject(op))
Guido van Rossum81daa321993-05-20 14:24:46 +000096 return; /* XXX no error */
97 ap = (accessobject *)op;
Guido van Rossumeb6b33a1993-05-25 09:38:27 +000098 XDECREF(ap->ac_owner);
99 XINCREF(owner);
100 ap->ac_owner = owner;
Guido van Rossum81daa321993-05-20 14:24:46 +0000101}
102
Guido van Rossumb3f72581993-05-21 19:56:10 +0000103int
104hasaccessvalue(op)
105 object *op;
106{
107 if (!is_accessobject(op))
108 return 0;
109 return ((accessobject *)op)->ac_value != NULL;
110}
111
Guido van Rossum81daa321993-05-20 14:24:46 +0000112object *
Guido van Rossumed18fdc1993-07-11 19:55:34 +0000113getaccessvalue(op, caller)
Guido van Rossum81daa321993-05-20 14:24:46 +0000114 object *op;
Guido van Rossumed18fdc1993-07-11 19:55:34 +0000115 object *caller;
Guido van Rossum81daa321993-05-20 14:24:46 +0000116{
117 register accessobject *ap;
118 if (!is_accessobject(op)) {
119 err_badcall();
120 return NULL;
121 }
122 ap = (accessobject *)op;
123
Guido van Rossumed18fdc1993-07-11 19:55:34 +0000124 if (!ownercheck(caller, ap->ac_owner, AC_R, ap->ac_mode)) {
Guido van Rossum81daa321993-05-20 14:24:46 +0000125 err_setstr(AccessError, "read access denied");
126 return NULL;
127 }
128
129 if (ap->ac_value == NULL) {
130 err_setstr(AccessError, "no current value");
131 return NULL;
132 }
133 INCREF(ap->ac_value);
134 return ap->ac_value;
135}
136
137int
Guido van Rossumed18fdc1993-07-11 19:55:34 +0000138setaccessvalue(op, caller, value)
Guido van Rossum81daa321993-05-20 14:24:46 +0000139 object *op;
Guido van Rossumed18fdc1993-07-11 19:55:34 +0000140 object *caller;
Guido van Rossum81daa321993-05-20 14:24:46 +0000141 object *value;
142{
143 register accessobject *ap;
144 if (!is_accessobject(op)) {
145 err_badcall();
146 return -1;
147 }
148 ap = (accessobject *)op;
149
Guido van Rossumed18fdc1993-07-11 19:55:34 +0000150 if (!ownercheck(caller, ap->ac_owner, AC_W, ap->ac_mode)) {
Guido van Rossum81daa321993-05-20 14:24:46 +0000151 err_setstr(AccessError, "write access denied");
152 return -1;
153 }
154
155 if (!typecheck(value, ap->ac_type)) {
156 err_setstr(AccessError, "assign value of inappropriate type");
157 return -1;
158 }
159
160 if (value == NULL) { /* Delete it */
161 if (ap->ac_value == NULL) {
162 err_setstr(AccessError, "no current value");
163 return -1;
164 }
165 DECREF(ap->ac_value);
166 ap->ac_value = NULL;
167 return 0;
168 }
169 XDECREF(ap->ac_value);
170 INCREF(value);
171 ap->ac_value = value;
172 return 0;
173}
174
175static int
176typecheck(value, type)
177 object *value;
178 typeobject *type;
179{
180 object *x;
181 if (value == NULL || type == NULL)
182 return 1; /* No check */
183 if (value->ob_type == type)
184 return 1; /* Exact match */
185 if (type == &Anynumbertype) {
186 if (value->ob_type->tp_as_number == NULL)
187 return 0;
188 if (!is_instanceobject(value))
189 return 1;
190 /* For instances, make sure it really looks like a number */
191 x = getattr(value, "__sub__");
192 if (x == NULL) {
193 err_clear();
194 return 0;
195 }
196 DECREF(x);
197 return 1;
198 }
199 if (type == &Anysequencetype) {
200 if (value->ob_type->tp_as_sequence == NULL)
201 return 0;
202 if (!is_instanceobject(value))
203 return 1;
204 /* For instances, make sure it really looks like a sequence */
205 x = getattr(value, "__getslice__");
206 if (x == NULL) {
207 err_clear();
208 return 0;
209 }
210 DECREF(x);
211 return 1;
212 }
213 if (type == &Anymappingtype) {
214 if (value->ob_type->tp_as_mapping == NULL)
215 return 0;
216 if (!is_instanceobject(value))
217 return 1;
218 /* For instances, make sure it really looks like a mapping */
219 x = getattr(value, "__getitem__");
220 if (x == NULL) {
221 err_clear();
222 return 0;
223 }
224 DECREF(x);
225 return 1;
226 }
227 return 0;
228}
229
230static int
Guido van Rossumed18fdc1993-07-11 19:55:34 +0000231isprivileged(caller)
232 object *caller;
233{
234 object *g;
Sjoerd Mullender3bb8a051993-10-22 12:04:32 +0000235 static char privileged[] = "__privileged__";
236 if (caller != NULL && hasattr(caller, privileged))
Guido van Rossumed18fdc1993-07-11 19:55:34 +0000237 return 1;
238 g = getglobals();
Sjoerd Mullender3bb8a051993-10-22 12:04:32 +0000239 if (g != NULL && dictlookup(g, privileged))
Guido van Rossumed18fdc1993-07-11 19:55:34 +0000240 return 1;
241 return 0;
242}
243
244static int
Guido van Rossumeb6b33a1993-05-25 09:38:27 +0000245ownercheck(caller, owner, access, mode)
Guido van Rossum81daa321993-05-20 14:24:46 +0000246 object *caller;
247 object *owner;
248 int access;
249 int mode;
250{
Guido van Rossumeb6b33a1993-05-25 09:38:27 +0000251 int mask = AC_PUBLIC;
Guido van Rossumed18fdc1993-07-11 19:55:34 +0000252 if (caller == owner || isprivileged(caller))
253 mask |= AC_PRIVATE | AC_PROTECTED;
254 else if (caller != NULL && owner != NULL &&
255 is_classobject(owner) && is_classobject(caller) &&
256 (issubclass(caller, owner) ||
257 issubclass(owner, caller)))
Guido van Rossumeb6b33a1993-05-25 09:38:27 +0000258 mask |= AC_PROTECTED;
Guido van Rossumeb6b33a1993-05-25 09:38:27 +0000259 return access & mode & mask;
Guido van Rossum81daa321993-05-20 14:24:46 +0000260}
261
262/* Access methods */
263
264static void
265access_dealloc(ap)
266 accessobject *ap;
267{
268 XDECREF(ap->ac_value);
Guido van Rossumeb6b33a1993-05-25 09:38:27 +0000269 XDECREF(ap->ac_owner);
Guido van Rossum81daa321993-05-20 14:24:46 +0000270 XDECREF(ap->ac_type);
271 DEL(ap);
272}
273
274#define OFF(x) offsetof(accessobject, x)
275
276static struct memberlist access_memberlist[] = {
277 {"ac_value", T_OBJECT, OFF(ac_value)},
Guido van Rossumeb6b33a1993-05-25 09:38:27 +0000278 {"ac_owner", T_OBJECT, OFF(ac_owner)},
Guido van Rossum81daa321993-05-20 14:24:46 +0000279 {"ac_type", T_OBJECT, OFF(ac_type)},
280 {"ac_mode", T_INT, OFF(ac_mode)},
281 {NULL} /* Sentinel */
282};
283
284static object *
285access_getattr(ap, name)
286 accessobject *ap;
287 char *name;
288{
289 return getmember((char *)ap, access_memberlist, name);
290}
291
292static object *
293access_repr(ap)
294 accessobject *ap;
295{
296 char buf[300];
Guido van Rossumeb6b33a1993-05-25 09:38:27 +0000297 char buf2[20];
298 char *ownername;
Guido van Rossum81daa321993-05-20 14:24:46 +0000299 typeobject *type = ap->ac_type;
Guido van Rossumeb6b33a1993-05-25 09:38:27 +0000300 if (is_classobject(ap->ac_owner)) {
301 ownername =
302 getstringvalue(((classobject *)ap->ac_owner)->cl_name);
303 }
304 else {
305 sprintf(buf2, "0x%lx", (long)ap->ac_owner);
306 ownername = buf2;
307 }
Guido van Rossumb3f72581993-05-21 19:56:10 +0000308 sprintf(buf,
Guido van Rossumeb6b33a1993-05-25 09:38:27 +0000309 "<access object, value 0x%lx, owner %.100s, type %.100s, mode %04o>",
Guido van Rossumb3f72581993-05-21 19:56:10 +0000310 (long)(ap->ac_value),
Guido van Rossumeb6b33a1993-05-25 09:38:27 +0000311 ownername,
Guido van Rossum81daa321993-05-20 14:24:46 +0000312 type ? type->tp_name : "-",
313 ap->ac_mode);
314 return newstringobject(buf);
315}
316
317typeobject Accesstype = {
318 OB_HEAD_INIT(&Typetype)
319 0, /*ob_size*/
320 "access", /*tp_name*/
321 sizeof(accessobject), /*tp_size*/
322 0, /*tp_itemsize*/
323 /* methods */
Guido van Rossumb6775db1994-08-01 11:34:53 +0000324 (destructor)access_dealloc, /*tp_dealloc*/
Guido van Rossum81daa321993-05-20 14:24:46 +0000325 0, /*tp_print*/
Guido van Rossumb6775db1994-08-01 11:34:53 +0000326 (getattrfunc)access_getattr, /*tp_getattr*/
Guido van Rossum81daa321993-05-20 14:24:46 +0000327 0, /*tp_setattr*/
328 0, /*tp_compare*/
Guido van Rossumb6775db1994-08-01 11:34:53 +0000329 (reprfunc)access_repr, /*tp_repr*/
Guido van Rossum81daa321993-05-20 14:24:46 +0000330 0, /*tp_as_number*/
331 0, /*tp_as_sequence*/
332 0, /*tp_as_mapping*/
333 0, /*tp_hash*/
334};
335
Guido van Rossumeb6b33a1993-05-25 09:38:27 +0000336
337/* Pseudo type objects to indicate collections of types */
Guido van Rossum81daa321993-05-20 14:24:46 +0000338
339/* XXX This should be replaced by a more general "subclassing"
340 XXX mechanism for type objects... */
341
342typeobject Anynumbertype = {
343 OB_HEAD_INIT(&Typetype)
344 0, /*ob_size*/
345 "*number*", /*tp_name*/
346};
347
348/* XXX Should really distinguish mutable and immutable sequences as well */
349
350typeobject Anysequencetype = {
351 OB_HEAD_INIT(&Typetype)
352 0, /*ob_size*/
353 "*sequence*", /*tp_name*/
354};
355
356typeobject Anymappingtype = {
357 OB_HEAD_INIT(&Typetype)
358 0, /*ob_size*/
359 "*mapping*", /*tp_name*/
360};