mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 13:41:24 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			360 lines
		
	
	
	
		
			7.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			360 lines
		
	
	
	
		
			7.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /***********************************************************
 | |
| Copyright 1991, 1992, 1993 by Stichting Mathematisch Centrum,
 | |
| Amsterdam, The Netherlands.
 | |
| 
 | |
|                         All Rights Reserved
 | |
| 
 | |
| Permission to use, copy, modify, and distribute this software and its 
 | |
| documentation for any purpose and without fee is hereby granted, 
 | |
| provided that the above copyright notice appear in all copies and that
 | |
| both that copyright notice and this permission notice appear in 
 | |
| supporting documentation, and that the names of Stichting Mathematisch
 | |
| Centrum or CWI not be used in advertising or publicity pertaining to
 | |
| distribution of the software without specific, written prior permission.
 | |
| 
 | |
| STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
 | |
| THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
 | |
| FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
 | |
| FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 | |
| WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 | |
| ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
 | |
| OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 | |
| 
 | |
| ******************************************************************/
 | |
| 
 | |
| /* Access object implementation */
 | |
| 
 | |
| /* XXX TO DO LIST
 | |
|    - __init__ and __del__ (and all other similar methods)
 | |
|      should be usable even when private, not ignored (???)
 | |
| */
 | |
| 
 | |
| #include "allobjects.h"
 | |
| #include "ceval.h"
 | |
| #include "structmember.h"
 | |
| #include "modsupport.h"		/* For getargs() etc. */
 | |
| 
 | |
| typedef struct {
 | |
| 	OB_HEAD
 | |
| 	object		*ac_value;
 | |
| 	object		*ac_owner;
 | |
| 	typeobject	*ac_type;
 | |
| 	int		ac_mode;
 | |
| } accessobject;
 | |
| 
 | |
| /* Forward */
 | |
| static int typecheck PROTO((object *, typeobject *));
 | |
| static int ownercheck PROTO((object *, object *, int, int));
 | |
| 
 | |
| object *
 | |
| newaccessobject(value, owner, type, mode)
 | |
| 	object *value;
 | |
| 	object *owner;
 | |
| 	typeobject *type;
 | |
| 	int mode;
 | |
| {
 | |
| 	accessobject *ap;
 | |
| 	if (!typecheck(value, type)) {
 | |
| 		err_setstr(AccessError,
 | |
| 		"access: initial value has inappropriate type");
 | |
| 		return NULL;
 | |
| 	}
 | |
| 	ap = NEWOBJ(accessobject, &Accesstype);
 | |
| 	if (ap == NULL)
 | |
| 		return NULL;
 | |
| 	XINCREF(value);
 | |
| 	ap->ac_value = value;
 | |
| 	XINCREF(owner);
 | |
| 	ap->ac_owner = owner;
 | |
| 	XINCREF(type);
 | |
| 	ap->ac_type = (typeobject *)type;
 | |
| 	ap->ac_mode = mode;
 | |
| 	return (object *)ap;
 | |
| }
 | |
| 
 | |
| object *
 | |
| cloneaccessobject(op)
 | |
| 	object *op;
 | |
| {
 | |
| 	register accessobject *ap;
 | |
| 	if (!is_accessobject(op)) {
 | |
| 		err_badcall();
 | |
| 		return NULL;
 | |
| 	}
 | |
| 	ap = (accessobject *)op;
 | |
| 	return newaccessobject(ap->ac_value, ap->ac_owner,
 | |
| 			       ap->ac_type, ap->ac_mode);
 | |
| }
 | |
| 
 | |
| void
 | |
| setaccessowner(op, owner)
 | |
| 	object *op;
 | |
| 	object *owner;
 | |
| {
 | |
| 	register accessobject *ap;
 | |
| 	if (!is_accessobject(op))
 | |
| 		return; /* XXX no error */
 | |
| 	ap = (accessobject *)op;
 | |
| 	XDECREF(ap->ac_owner);
 | |
| 	XINCREF(owner);
 | |
| 	ap->ac_owner = owner;
 | |
| }
 | |
| 
 | |
| int
 | |
| hasaccessvalue(op)
 | |
| 	object *op;
 | |
| {	
 | |
| 	if (!is_accessobject(op))
 | |
| 		return 0;
 | |
| 	return ((accessobject *)op)->ac_value != NULL;
 | |
| }
 | |
| 
 | |
| object *
 | |
| getaccessvalue(op, caller)
 | |
| 	object *op;
 | |
| 	object *caller;
 | |
| {
 | |
| 	register accessobject *ap;
 | |
| 	if (!is_accessobject(op)) {
 | |
| 		err_badcall();
 | |
| 		return NULL;
 | |
| 	}
 | |
| 	ap = (accessobject *)op;
 | |
| 	
 | |
| 	if (!ownercheck(caller, ap->ac_owner, AC_R, ap->ac_mode)) {
 | |
| 		err_setstr(AccessError, "read access denied");
 | |
| 		return NULL;
 | |
| 	}
 | |
| 	
 | |
| 	if (ap->ac_value == NULL) {
 | |
| 		err_setstr(AccessError, "no current value");
 | |
| 		return NULL;
 | |
| 	}
 | |
| 	INCREF(ap->ac_value);
 | |
| 	return ap->ac_value;
 | |
| }
 | |
| 
 | |
| int
 | |
| setaccessvalue(op, caller, value)
 | |
| 	object *op;
 | |
| 	object *caller;
 | |
| 	object *value;
 | |
| {
 | |
| 	register accessobject *ap;
 | |
| 	if (!is_accessobject(op)) {
 | |
| 		err_badcall();
 | |
| 		return -1;
 | |
| 	}
 | |
| 	ap = (accessobject *)op;
 | |
| 	
 | |
| 	if (!ownercheck(caller, ap->ac_owner, AC_W, ap->ac_mode)) {
 | |
| 		err_setstr(AccessError, "write access denied");
 | |
| 		return -1;
 | |
| 	}
 | |
| 	
 | |
| 	if (!typecheck(value, ap->ac_type)) {
 | |
| 		err_setstr(AccessError, "assign value of inappropriate type");
 | |
| 		return -1;
 | |
| 	}
 | |
| 	
 | |
| 	if (value == NULL) { /* Delete it */
 | |
| 		if (ap->ac_value == NULL) {
 | |
| 			err_setstr(AccessError, "no current value");
 | |
| 			return -1;
 | |
| 		}
 | |
| 		DECREF(ap->ac_value);
 | |
| 		ap->ac_value = NULL;
 | |
| 		return 0;
 | |
| 	}
 | |
| 	XDECREF(ap->ac_value);
 | |
| 	INCREF(value);
 | |
| 	ap->ac_value = value;
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int
 | |
| typecheck(value, type)
 | |
| 	object *value;
 | |
| 	typeobject *type;
 | |
| {
 | |
| 	object *x;
 | |
| 	if (value == NULL || type == NULL)
 | |
| 		return 1; /* No check */
 | |
| 	if (value->ob_type == type)
 | |
| 		return 1; /* Exact match */
 | |
| 	if (type == &Anynumbertype) {
 | |
| 		if (value->ob_type->tp_as_number == NULL)
 | |
| 			return 0;
 | |
| 		if (!is_instanceobject(value))
 | |
| 			return 1;
 | |
| 		/* For instances, make sure it really looks like a number */
 | |
| 		x = getattr(value, "__sub__");
 | |
| 		if (x == NULL) {
 | |
| 			err_clear();
 | |
| 			return 0;
 | |
| 		}
 | |
| 		DECREF(x);
 | |
| 		return 1;
 | |
| 	}
 | |
| 	if (type == &Anysequencetype) {
 | |
| 		if (value->ob_type->tp_as_sequence == NULL)
 | |
| 			return 0;
 | |
| 		if (!is_instanceobject(value))
 | |
| 			return 1;
 | |
| 		/* For instances, make sure it really looks like a sequence */
 | |
| 		x = getattr(value, "__getslice__");
 | |
| 		if (x == NULL) {
 | |
| 			err_clear();
 | |
| 			return 0;
 | |
| 		}
 | |
| 		DECREF(x);
 | |
| 		return 1;
 | |
| 	}
 | |
| 	if (type == &Anymappingtype) {
 | |
| 		if (value->ob_type->tp_as_mapping == NULL)
 | |
| 			return 0;
 | |
| 		if (!is_instanceobject(value))
 | |
| 			return 1;
 | |
| 		/* For instances, make sure it really looks like a mapping */
 | |
| 		x = getattr(value, "__getitem__");
 | |
| 		if (x == NULL) {
 | |
| 			err_clear();
 | |
| 			return 0;
 | |
| 		}
 | |
| 		DECREF(x);
 | |
| 		return 1;
 | |
| 	}
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int
 | |
| isprivileged(caller)
 | |
| 	object *caller;
 | |
| {
 | |
| 	object *g;
 | |
| 	static char privileged[] = "__privileged__";
 | |
| 	if (caller != NULL && hasattr(caller, privileged))
 | |
| 		return 1;
 | |
| 	g = getglobals();
 | |
| 	if (g != NULL && dictlookup(g, privileged))
 | |
| 		return 1;
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int
 | |
| ownercheck(caller, owner, access, mode)
 | |
| 	object *caller;
 | |
| 	object *owner;
 | |
| 	int access;
 | |
| 	int mode;
 | |
| {
 | |
| 	int mask = AC_PUBLIC;
 | |
| 	if (caller == owner || isprivileged(caller))
 | |
| 		mask |= AC_PRIVATE | AC_PROTECTED;
 | |
| 	else if (caller != NULL && owner != NULL &&
 | |
| 		 is_classobject(owner) && is_classobject(caller) &&
 | |
| 		 (issubclass(caller, owner) ||
 | |
| 		  issubclass(owner, caller)))
 | |
| 			mask |= AC_PROTECTED;
 | |
| 	return access & mode & mask;
 | |
| }
 | |
| 
 | |
| /* Access methods */
 | |
| 
 | |
| static void
 | |
| access_dealloc(ap)
 | |
| 	accessobject *ap;
 | |
| {
 | |
| 	XDECREF(ap->ac_value);
 | |
| 	XDECREF(ap->ac_owner);
 | |
| 	XDECREF(ap->ac_type);
 | |
| 	DEL(ap);
 | |
| }
 | |
| 
 | |
| #define OFF(x) offsetof(accessobject, x)
 | |
| 
 | |
| static struct memberlist access_memberlist[] = {
 | |
| 	{"ac_value",	T_OBJECT,	OFF(ac_value)},
 | |
| 	{"ac_owner",	T_OBJECT,	OFF(ac_owner)},
 | |
| 	{"ac_type",	T_OBJECT,	OFF(ac_type)},
 | |
| 	{"ac_mode",	T_INT,		OFF(ac_mode)},
 | |
| 	{NULL}	/* Sentinel */
 | |
| };
 | |
| 
 | |
| static object *
 | |
| access_getattr(ap, name)
 | |
| 	accessobject *ap;
 | |
| 	char *name;
 | |
| {
 | |
| 	return getmember((char *)ap, access_memberlist, name);
 | |
| }
 | |
| 
 | |
| static object *
 | |
| access_repr(ap)
 | |
| 	accessobject *ap;
 | |
| {
 | |
| 	char buf[300];
 | |
| 	char buf2[20];
 | |
| 	char *ownername;
 | |
| 	typeobject *type = ap->ac_type;
 | |
| 	if (is_classobject(ap->ac_owner)) {
 | |
| 		ownername =
 | |
| 			getstringvalue(((classobject *)ap->ac_owner)->cl_name);
 | |
| 	}
 | |
| 	else {
 | |
| 		sprintf(buf2, "0x%lx", (long)ap->ac_owner);
 | |
| 		ownername = buf2;
 | |
| 	}
 | |
| 	sprintf(buf,
 | |
| 	"<access object, value 0x%lx, owner %.100s, type %.100s, mode %04o>",
 | |
| 		(long)(ap->ac_value),
 | |
| 		ownername,
 | |
| 		type ? type->tp_name : "-",
 | |
| 		ap->ac_mode);
 | |
| 	return newstringobject(buf);
 | |
| }
 | |
| 
 | |
| typeobject Accesstype = {
 | |
| 	OB_HEAD_INIT(&Typetype)
 | |
| 	0,			/*ob_size*/
 | |
| 	"access",		/*tp_name*/
 | |
| 	sizeof(accessobject),	/*tp_size*/
 | |
| 	0,			/*tp_itemsize*/
 | |
| 	/* methods */
 | |
| 	access_dealloc,		/*tp_dealloc*/
 | |
| 	0,			/*tp_print*/
 | |
| 	access_getattr,		/*tp_getattr*/
 | |
| 	0,			/*tp_setattr*/
 | |
| 	0,			/*tp_compare*/
 | |
| 	access_repr,		/*tp_repr*/
 | |
| 	0,			/*tp_as_number*/
 | |
| 	0,			/*tp_as_sequence*/
 | |
| 	0,			/*tp_as_mapping*/
 | |
| 	0,			/*tp_hash*/
 | |
| };
 | |
| 
 | |
| 
 | |
| /* Pseudo type objects to indicate collections of types */
 | |
| 
 | |
| /* XXX This should be replaced by a more general "subclassing"
 | |
|    XXX mechanism for type objects... */
 | |
| 
 | |
| typeobject Anynumbertype = {
 | |
| 	OB_HEAD_INIT(&Typetype)
 | |
| 	0,			/*ob_size*/
 | |
| 	"*number*",		/*tp_name*/
 | |
| };
 | |
| 
 | |
| /* XXX Should really distinguish mutable and immutable sequences as well */
 | |
| 
 | |
| typeobject Anysequencetype = {
 | |
| 	OB_HEAD_INIT(&Typetype)
 | |
| 	0,			/*ob_size*/
 | |
| 	"*sequence*",		/*tp_name*/
 | |
| };
 | |
| 
 | |
| typeobject Anymappingtype = {
 | |
| 	OB_HEAD_INIT(&Typetype)
 | |
| 	0,			/*ob_size*/
 | |
| 	"*mapping*",		/*tp_name*/
 | |
| };
 | 
