Commit f2637647 authored by Jim Fulton's avatar Jim Fulton

moved source files to src directory

parent 7dbb8830
/*
Copyright (c) 1996-1998, Digital Creations, Fredericksburg, VA, USA.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
o Redistributions of source code must retain the above copyright
notice, this list of conditions, and the disclaimer that follows.
o Redistributions in binary form must reproduce the above copyright
notice, this list of conditions, and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
o Neither the name of Digital Creations nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS AND CONTRIBUTORS *AS
IS* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DIGITAL
CREATIONS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
$Id: Acquisition.c,v 1.47 2001/02/19 19:16:07 jeremy Exp $
If you have questions regarding this software,
contact:
Digital Creations L.C.
info@digicool.com
(540) 371-6909
*/
#include "ExtensionClass.h"
static void
PyVar_Assign(PyObject **v, PyObject *e)
{
Py_XDECREF(*v);
*v=e;
}
#define ASSIGN(V,E) PyVar_Assign(&(V),(E))
#define UNLESS(E) if (!(E))
#define UNLESS_ASSIGN(V,E) ASSIGN(V,E); UNLESS(V)
#define OBJECT(O) ((PyObject*)(O))
static PyObject *py__add__, *py__sub__, *py__mul__, *py__div__,
*py__mod__, *py__pow__, *py__divmod__, *py__lshift__, *py__rshift__,
*py__and__, *py__or__, *py__xor__, *py__coerce__, *py__neg__,
*py__pos__, *py__abs__, *py__nonzero__, *py__invert__, *py__int__,
*py__long__, *py__float__, *py__oct__, *py__hex__,
*py__getitem__, *py__setitem__, *py__delitem__,
*py__getslice__, *py__setslice__, *py__delslice__,
*py__len__, *py__of__, *py__call__, *py__repr__, *py__str__, *py__cmp__;
static PyObject *Acquired=0;
static void
init_py_names()
{
#define INIT_PY_NAME(N) py ## N = PyString_FromString(#N)
INIT_PY_NAME(__add__);
INIT_PY_NAME(__sub__);
INIT_PY_NAME(__mul__);
INIT_PY_NAME(__div__);
INIT_PY_NAME(__mod__);
INIT_PY_NAME(__pow__);
INIT_PY_NAME(__divmod__);
INIT_PY_NAME(__lshift__);
INIT_PY_NAME(__rshift__);
INIT_PY_NAME(__and__);
INIT_PY_NAME(__or__);
INIT_PY_NAME(__xor__);
INIT_PY_NAME(__coerce__);
INIT_PY_NAME(__neg__);
INIT_PY_NAME(__pos__);
INIT_PY_NAME(__abs__);
INIT_PY_NAME(__nonzero__);
INIT_PY_NAME(__invert__);
INIT_PY_NAME(__int__);
INIT_PY_NAME(__long__);
INIT_PY_NAME(__float__);
INIT_PY_NAME(__oct__);
INIT_PY_NAME(__hex__);
INIT_PY_NAME(__getitem__);
INIT_PY_NAME(__setitem__);
INIT_PY_NAME(__delitem__);
INIT_PY_NAME(__getslice__);
INIT_PY_NAME(__setslice__);
INIT_PY_NAME(__delslice__);
INIT_PY_NAME(__len__);
INIT_PY_NAME(__of__);
INIT_PY_NAME(__call__);
INIT_PY_NAME(__repr__);
INIT_PY_NAME(__str__);
INIT_PY_NAME(__cmp__);
#undef INIT_PY_NAME
}
static PyObject *
CallMethodO(PyObject *self, PyObject *name,
PyObject *args, PyObject *kw)
{
if (! args && PyErr_Occurred()) return NULL;
UNLESS(name=PyObject_GetAttr(self,name)) {
if (args) { Py_DECREF(args); }
return NULL;
}
ASSIGN(name,PyEval_CallObjectWithKeywords(name,args,kw));
if (args) { Py_DECREF(args); }
return name;
}
#define Build Py_BuildValue
/* Declarations for objects of type Wrapper */
typedef struct {
PyObject_HEAD
PyObject *obj;
PyObject *container;
} Wrapper;
staticforward PyExtensionClass Wrappertype, XaqWrappertype;
#define isWrapper(O) ((O)->ob_type==(PyTypeObject*)&Wrappertype || \
(O)->ob_type==(PyTypeObject*)&XaqWrappertype)
#define WRAPPER(O) ((Wrapper*)(O))
static PyObject *
Wrapper__init__(Wrapper *self, PyObject *args)
{
PyObject *obj, *container;
UNLESS(PyArg_Parse(args,"(OO)",&obj,&container)) return NULL;
Py_INCREF(obj);
Py_INCREF(container);
self->obj=obj;
self->container=container;
Py_INCREF(Py_None);
return Py_None;
}
/* ---------------------------------------------------------------- */
static PyObject *
__of__(PyObject *inst, PyObject *parent)
{
PyObject *r, *t;
UNLESS(r=PyObject_GetAttr(inst, py__of__)) return NULL;
UNLESS(t=PyTuple_New(1)) goto err;
PyTuple_SET_ITEM(t,0,parent);
ASSIGN(r,PyObject_CallObject(r,t));
PyTuple_SET_ITEM(t,0,NULL);
Py_DECREF(t);
if (r
&& r->ob_refcnt==1
&& isWrapper(r)
&& WRAPPER(r)->container && isWrapper(WRAPPER(r)->container)
)
while (WRAPPER(r)->obj && isWrapper(WRAPPER(r)->obj)
&& (WRAPPER(WRAPPER(r)->obj)->container ==
WRAPPER(WRAPPER(r)->container)->obj)
)
{
/* Simplify wrapper */
Py_XINCREF(WRAPPER(WRAPPER(r)->obj)->obj);
ASSIGN(WRAPPER(r)->obj, WRAPPER(WRAPPER(r)->obj)->obj);
}
return r;
err:
Py_DECREF(r);
return NULL;
}
static Wrapper *freeWrappers=0;
static int nWrappers=0;
#define MAX_CACHED_WRAPPERS 200
static PyObject *
newWrapper(PyObject *obj, PyObject *container, PyTypeObject *Wrappertype)
{
Wrapper *self;
if (freeWrappers)
{
self=freeWrappers;
freeWrappers=(Wrapper*)self->obj;
self->ob_type=Wrappertype;
self->ob_refcnt=1;
nWrappers--;
}
else
{
UNLESS(self = PyObject_NEW(Wrapper, Wrappertype)) return NULL;
}
Py_INCREF(Wrappertype);
Py_XINCREF(obj);
Py_XINCREF(container);
self->obj=obj;
self->container=container;
return OBJECT(self);
}
static void
Wrapper_dealloc(Wrapper *self)
{
Py_XDECREF(self->obj);
Py_XDECREF(self->container);
Py_DECREF(self->ob_type);
if (nWrappers < MAX_CACHED_WRAPPERS)
{
self->obj=OBJECT(freeWrappers);
freeWrappers=self;
nWrappers++;
}
else
{
PyMem_DEL(self);
}
}
static PyObject *
Wrapper_special(Wrapper *self, char *name, PyObject *oname)
{
PyObject *r=0;
switch(*name)
{
case 'b':
if (strcmp(name,"base")==0)
{
if (self->obj)
{
r=self->obj;
while (isWrapper(r) && WRAPPER(r)->obj) r=WRAPPER(r)->obj;
}
else r=Py_None;
Py_INCREF(r);
return r;
}
break;
case 'p':
if (strcmp(name,"parent")==0)
{
if (self->container) r=self->container;
else r=Py_None;
Py_INCREF(r);
return r;
}
break;
case 's':
if (strcmp(name,"self")==0)
{
if (self->obj) r=self->obj;
else r=Py_None;
Py_INCREF(r);
return r;
}
break;
case 'e':
if (strcmp(name,"explicit")==0)
{
if (self->ob_type != (PyTypeObject *)&XaqWrappertype)
return newWrapper(self->obj, self->container,
(PyTypeObject *)&XaqWrappertype);
Py_INCREF(self);
return OBJECT(self);
}
break;
case 'a':
if (strcmp(name,"acquire")==0)
{
return Py_FindAttr(OBJECT(self),oname);
}
break;
case 'c':
if (strcmp(name,"chain")==0)
{
if ((r = PyList_New(0)))
while (1)
{
if (PyList_Append(r,OBJECT(self)) >= 0)
{
if (isWrapper(self) && self->container)
{
self=WRAPPER(self->container);
continue;
}
}
else
{
Py_DECREF(r);
}
break;
}
return r;
}
break;
case 'i':
if (strcmp(name,"inContextOf")==0)
{
return Py_FindAttr(OBJECT(self),oname);
}
if (strcmp(name,"inner")==0)
{
if (self->obj)
{
r=self->obj;
while (isWrapper(r) && WRAPPER(r)->obj)
{
self=WRAPPER(r);
r=WRAPPER(r)->obj;
}
r=OBJECT(self);
}
else r=Py_None;
Py_INCREF(r);
return r;
}
break;
case 'u':
if (strcmp(name,"uncle")==0)
{
return PyString_FromString("Bob");
}
break;
}
return NULL;
}
static int
apply_filter(PyObject *filter, PyObject *inst, PyObject *oname, PyObject *r,
PyObject *extra, PyObject *orig)
{
PyObject *fr;
int ir;
UNLESS(fr=PyTuple_New(5)) goto err;
PyTuple_SET_ITEM(fr,0,orig);
Py_INCREF(orig);
PyTuple_SET_ITEM(fr,1,inst);
Py_INCREF(inst);
PyTuple_SET_ITEM(fr,2,oname);
Py_INCREF(oname);
PyTuple_SET_ITEM(fr,3,r);
Py_INCREF(r);
PyTuple_SET_ITEM(fr,4,extra);
Py_INCREF(extra);
UNLESS_ASSIGN(fr,PyObject_CallObject(filter, fr)) goto err;
ir=PyObject_IsTrue(fr);
Py_DECREF(fr);
if (ir) return 1;
Py_DECREF(r);
return 0;
err:
Py_DECREF(r);
return -1;
}
static PyObject *
Wrapper_acquire(Wrapper *self, PyObject *oname,
PyObject *filter, PyObject *extra, PyObject *orig,
int explicit, int containment);
static PyObject *
Wrapper_findattr(Wrapper *self, PyObject *oname,
PyObject *filter, PyObject *extra, PyObject *orig,
int sob, int sco, int explicit, int containment)
{
PyObject *r, *v, *tb;
char *name="";
if (PyString_Check(oname)) name=PyString_AS_STRING(oname);
if (*name=='a' && name[1]=='q' && name[2]=='_')
if ((r=Wrapper_special(self, name+3, oname)))
{
if (filter)
switch(apply_filter(filter,OBJECT(self),oname,r,extra,orig))
{
case -1: return NULL;
case 1: return r;
}
else return r;
}
else PyErr_Clear();
else if (*name=='_' && name[1]=='_' && strcmp(name+2,"reduce__")==0)
{
PyErr_SetString(PyExc_TypeError,
"Can't pickle objects in acquisition wrappers.");
return NULL;
}
/* If we are doing a containment search, then replace self with aq_inner */
if (containment)
while (self->obj && isWrapper(self->obj))
self=WRAPPER(self->obj);
if (sob && self->obj)
{
if (isWrapper(self->obj))
{
if ((r=Wrapper_findattr(WRAPPER(self->obj),
oname, filter, extra, orig, 1,
/* Search object container if explicit,
or object is implicit acquirer */
explicit ||
self->obj->ob_type ==
(PyTypeObject*)&Wrappertype,
explicit, containment)))
{
if (PyECMethod_Check(r) && PyECMethod_Self(r)==self->obj)
ASSIGN(r,PyECMethod_New(r,OBJECT(self)));
else if (has__of__(r)) ASSIGN(r,__of__(r,OBJECT(self)));
return r;
}
PyErr_Fetch(&r,&v,&tb);
if (r && (r != PyExc_AttributeError))
{
PyErr_Restore(r,v,tb);
return NULL;
}
Py_XDECREF(r); Py_XDECREF(v); Py_XDECREF(tb);
r=NULL;
}
else if ((r=PyObject_GetAttr(self->obj,oname)))
{
if (r==Acquired)
{
Py_DECREF(r);
return Wrapper_acquire(self, oname, filter, extra, orig, 1,
containment);
}
if (PyECMethod_Check(r) && PyECMethod_Self(r)==self->obj)
ASSIGN(r,PyECMethod_New(r,OBJECT(self)));
else if (has__of__(r)) ASSIGN(r,__of__(r,OBJECT(self)));
if (filter)
switch(apply_filter(filter,OBJECT(self),oname,r,extra,orig))
{
case -1: return NULL;
case 1: return r;
}
else return r;
}
else {
PyErr_Fetch(&r,&v,&tb);
if (r != PyExc_AttributeError)
{
PyErr_Restore(r,v,tb);
return NULL;
}
Py_XDECREF(r); Py_XDECREF(v); Py_XDECREF(tb);
r=NULL;
}
PyErr_Clear();
}
if (sco && (*name != '_' || explicit))
return Wrapper_acquire(self, oname, filter, extra, orig, explicit,
containment);
PyErr_SetObject(PyExc_AttributeError,oname);
return NULL;
}
static PyObject *
Wrapper_acquire(Wrapper *self, PyObject *oname,
PyObject *filter, PyObject *extra, PyObject *orig,
int explicit, int containment)
{
PyObject *r;
int sob=1, sco=1;
if (self->container)
{
if (isWrapper(self->container))
{
if (self->obj && isWrapper(self->obj))
{
/* Try to optimize search by recognizing repeated obs in path */
if (WRAPPER(self->obj)->container==
WRAPPER(self->container)->container)
sco=0;
else if (WRAPPER(self->obj)->container==
WRAPPER(self->container)->obj)
sob=0;
}
r=Wrapper_findattr((Wrapper*)self->container,
oname, filter, extra, orig, sob, sco, explicit,
containment);
if (r && has__of__(r)) ASSIGN(r,__of__(r,OBJECT(self)));
return r;
}
else
{
if ((r=PyObject_GetAttr(self->container,oname))) {
if (r == Acquired)
{
Py_DECREF(r);
}
else {
if (filter)
switch(apply_filter(filter,self->container,oname,r,
extra,orig))
{
case -1:
return NULL;
case 1:
if (has__of__(r)) ASSIGN(r,__of__(r,OBJECT(self)));
return r;
}
else
{
if (has__of__(r)) ASSIGN(r,__of__(r,OBJECT(self)));
return r;
}
}
}
}
}
PyErr_SetObject(PyExc_AttributeError, oname);
return NULL;
}
static PyObject *
Wrapper_getattro(Wrapper *self, PyObject *oname)
{
if (self->obj || self->container)
return Wrapper_findattr(self, oname, NULL, NULL, NULL, 1, 1, 0, 0);
/* Maybe we are getting initialized? */
return Py_FindAttr(OBJECT(self),oname);
}
static PyObject *
Xaq_getattro(Wrapper *self, PyObject *oname)
{
char *name="";
/* Special case backward-compatible acquire method. */
if (PyString_Check(oname)) name=PyString_AS_STRING(oname);
if (*name=='a' && name[1]=='c' && strcmp(name+2,"quire")==0)
return Py_FindAttr(OBJECT(self),oname);
if (self->obj || self->container)
return Wrapper_findattr(self, oname, NULL, NULL, NULL, 1, 0, 0, 0);
/* Maybe we are getting initialized? */
return Py_FindAttr(OBJECT(self),oname);
}
static int
Wrapper_setattro(Wrapper *self, PyObject *oname, PyObject *v)
{
char *name="";
/* Allow assignment to parent, to change context. */
if (PyString_Check(oname)) name=PyString_AS_STRING(oname);
if (*name=='a' && name[1]=='q' && name[2]=='_'
&& strcmp(name+3,"parent")==0)
{
Py_XINCREF(v);
ASSIGN(self->container, v);
return 0;
}
if (self->obj)
{
/* Unwrap passed in wrappers! */
while (v && isWrapper(v))
v=WRAPPER(v)->obj;
if (v) return PyObject_SetAttr(self->obj, oname, v);
else return PyObject_DelAttr(self->obj, oname);
}
PyErr_SetString(PyExc_AttributeError,
"Attempt to set attribute on empty acquisition wrapper");
return -1;
}
static int
Wrapper_compare(Wrapper *self, PyObject *w)
{
PyObject *obj, *wobj;
PyObject *m;
int r;
if (OBJECT(self) == w) return 0;
UNLESS (m=PyObject_GetAttr(OBJECT(self), py__cmp__))
{
/* Unwrap self completely -> obj. */
while (self->obj && isWrapper(self->obj))
self=WRAPPER(self->obj);
obj = self->obj;
/* Unwrap w completely -> wobj. */
if (isWrapper(w))
{
while (WRAPPER(w)->obj && isWrapper(WRAPPER(w)->obj))
w=WRAPPER(w)->obj;
wobj = WRAPPER(w)->obj;
}
else wobj = w;
PyErr_Clear();
if (obj == wobj) return 0;
return (obj < w) ? -1 : 1;
}
ASSIGN(m, PyObject_CallFunction(m, "O", w));
UNLESS (m) return -1;
r=PyInt_AsLong(m);
Py_DECREF(m);
return r;
}
static PyObject *
Wrapper_repr(Wrapper *self)
{
PyObject *r;
if ((r=PyObject_GetAttr(OBJECT(self),py__repr__)))
{
ASSIGN(r,PyObject_CallFunction(r,NULL,NULL));
return r;
}
else
{
PyErr_Clear();
return PyObject_Repr(self->obj);
}
}
static PyObject *
Wrapper_str(Wrapper *self)
{
PyObject *r;
if ((r=PyObject_GetAttr(OBJECT(self),py__str__)))
{
ASSIGN(r,PyObject_CallFunction(r,NULL,NULL));
return r;
}
else
{
PyErr_Clear();
return PyObject_Str(self->obj);
}
}
static long
Wrapper_hash(Wrapper *self)
{
return PyObject_Hash(self->obj);
}
static PyObject *
Wrapper_call(Wrapper *self, PyObject *args, PyObject *kw)
{
Py_INCREF(args);
return CallMethodO(OBJECT(self),py__call__,args,kw);
}
/* Code to handle accessing Wrapper objects as sequence objects */
static int
Wrapper_length(Wrapper *self)
{
long l;
PyObject *r;
UNLESS(r=PyObject_GetAttr(OBJECT(self), py__len__))
{
/* Hm. Maybe we are being checked to see if we are true.
Check to see if we have a __getitem__. If we don't, then
answer that we are true, otherwise raise an error.
*/
PyErr_Clear();
if ((r=PyObject_GetAttr(OBJECT(self), py__getitem__)))
{
/* Hm, we have getitem, must be error */
Py_DECREF(r);
PyErr_SetObject(PyExc_AttributeError, py__len__);
return -1;
}
PyErr_Clear();
/* Try nonzero */
UNLESS(r=PyObject_GetAttr(OBJECT(self), py__nonzero__))
{
/* No nonzero, it's true :-) */
PyErr_Clear();
return 1;
}
}
UNLESS_ASSIGN(r,PyObject_CallObject(r,NULL)) return -1;
l=PyInt_AsLong(r);
Py_DECREF(r);
return l;
}
static PyObject *
Wrapper_add(Wrapper *self, PyObject *bb)
{
return CallMethodO(OBJECT(self),py__add__,Build("(O)", bb) ,NULL);
}
static PyObject *
Wrapper_mul(Wrapper *self, int n)
{
return CallMethodO(OBJECT(self),py__mul__,Build("(i)", n),NULL);
}
static PyObject *
Wrapper_item(Wrapper *self, int i)
{
return CallMethodO(OBJECT(self),py__getitem__, Build("(i)", i),NULL);
}
static PyObject *
Wrapper_slice(Wrapper *self, int ilow, int ihigh)
{
return CallMethodO(OBJECT(self),py__getslice__,
Build("(ii)", ilow, ihigh),NULL);
}
static int
Wrapper_ass_item(Wrapper *self, int i, PyObject *v)
{
if (v)
{
UNLESS(v=CallMethodO(OBJECT(self),py__setitem__,
Build("(iO)", i, v),NULL))
return -1;
}
else
{
UNLESS(v=CallMethodO(OBJECT(self),py__delitem__,
Build("(i)", i),NULL))
return -1;
}
Py_DECREF(v);
return 0;
}
static int
Wrapper_ass_slice(Wrapper *self, int ilow, int ihigh, PyObject *v)
{
if (v)
{
UNLESS(v=CallMethodO(OBJECT(self),py__setslice__,
Build("(iiO)", ilow, ihigh, v),NULL))
return -1;
}
else
{
UNLESS(v=CallMethodO(OBJECT(self),py__delslice__,
Build("(ii)", ilow, ihigh),NULL))
return -1;
}
Py_DECREF(v);
return 0;
}
static PySequenceMethods Wrapper_as_sequence = {
(inquiry)Wrapper_length, /*sq_length*/
(binaryfunc)Wrapper_add, /*sq_concat*/
(intargfunc)Wrapper_mul, /*sq_repeat*/
(intargfunc)Wrapper_item, /*sq_item*/
(intintargfunc)Wrapper_slice, /*sq_slice*/
(intobjargproc)Wrapper_ass_item, /*sq_ass_item*/
(intintobjargproc)Wrapper_ass_slice, /*sq_ass_slice*/
};
/* -------------------------------------------------------------- */
/* Code to access Wrapper objects as mappings */
static PyObject *
Wrapper_subscript(Wrapper *self, PyObject *key)
{
return CallMethodO(OBJECT(self),py__getitem__,Build("(O)", key),NULL);
}
static int
Wrapper_ass_sub(Wrapper *self, PyObject *key, PyObject *v)
{
if (v)
{
UNLESS(v=CallMethodO(OBJECT(self),py__setitem__,
Build("(OO)", key, v),NULL))
return -1;
}
else
{
UNLESS(v=CallMethodO(OBJECT(self),py__delitem__,
Build("(O)", key),NULL))
return -1;
}
Py_XDECREF(v);
return 0;
}
static PyMappingMethods Wrapper_as_mapping = {
(inquiry)Wrapper_length, /*mp_length*/
(binaryfunc)Wrapper_subscript, /*mp_subscript*/
(objobjargproc)Wrapper_ass_sub, /*mp_ass_subscript*/
};
/* -------------------------------------------------------------- */
/* Code to access Wrapper objects as numbers */
static PyObject *
Wrapper_sub(Wrapper *self, PyObject *o)
{
return CallMethodO(OBJECT(self),py__sub__,Build("(O)", o),NULL);
}
static PyObject *
Wrapper_div(Wrapper *self, PyObject *o)
{
return CallMethodO(OBJECT(self),py__div__,Build("(O)", o),NULL);
}
static PyObject *
Wrapper_mod(Wrapper *self, PyObject *o)
{
return CallMethodO(OBJECT(self),py__mod__,Build("(O)", o),NULL);
}
static PyObject *
Wrapper_divmod(Wrapper *self, PyObject *o)
{
return CallMethodO(OBJECT(self),py__divmod__,Build("(O)", o),NULL);
}
static PyObject *
Wrapper_pow(Wrapper *self, PyObject *o, PyObject *m)
{
return CallMethodO(OBJECT(self),py__pow__,Build("(OO)", o, m),NULL);
}
static PyObject *
Wrapper_neg(Wrapper *self)
{
return CallMethodO(OBJECT(self), py__neg__, NULL, NULL);
}
static PyObject *
Wrapper_pos(Wrapper *self)
{
return CallMethodO(OBJECT(self), py__pos__, NULL, NULL);
}
static PyObject *
Wrapper_abs(Wrapper *self)
{
return CallMethodO(OBJECT(self), py__abs__, NULL, NULL);
}
static PyObject *
Wrapper_invert(Wrapper *self)
{
return CallMethodO(OBJECT(self), py__invert__, NULL, NULL);
}
static PyObject *
Wrapper_lshift(Wrapper *self, PyObject *o)
{
return CallMethodO(OBJECT(self),py__lshift__,Build("(O)", o),NULL);
}
static PyObject *
Wrapper_rshift(Wrapper *self, PyObject *o)
{
return CallMethodO(OBJECT(self),py__rshift__,Build("(O)", o),NULL);
}
static PyObject *
Wrapper_and(Wrapper *self, PyObject *o)
{
return CallMethodO(OBJECT(self),py__and__,Build("(O)", o),NULL);
}
static PyObject *
Wrapper_xor(Wrapper *self, PyObject *o)
{
return CallMethodO(OBJECT(self),py__xor__,Build("(O)", o),NULL);
}
static PyObject *
Wrapper_or(Wrapper *self, PyObject *o)
{
return CallMethodO(OBJECT(self),py__or__,Build("(O)", o),NULL);
}
static int
Wrapper_coerce(Wrapper **self, PyObject **o)
{
PyObject *m;
UNLESS (m=PyObject_GetAttr(OBJECT(*self), py__coerce__))
{
PyErr_Clear();
Py_INCREF(*self);
Py_INCREF(*o);
return 0;
}
ASSIGN(m, PyObject_CallFunction(m, "O", *o));
UNLESS (m) return -1;
UNLESS (PyArg_ParseTuple(m,"OO", self, o)) goto err;
Py_INCREF(*self);
Py_INCREF(*o);
Py_DECREF(m);
return 0;
err:
Py_DECREF(m);
return -1;
}
static PyObject *
Wrapper_int(Wrapper *self)
{
return CallMethodO(OBJECT(self), py__int__, NULL, NULL);
}
static PyObject *
Wrapper_long(Wrapper *self)
{
return CallMethodO(OBJECT(self), py__long__, NULL, NULL);
}
static PyObject *
Wrapper_float(Wrapper *self)
{
return CallMethodO(OBJECT(self), py__float__, NULL, NULL);
}
static PyObject *
Wrapper_oct(Wrapper *self)
{
return CallMethodO(OBJECT(self), py__oct__, NULL, NULL);
}
static PyObject *
Wrapper_hex(Wrapper *self)
{
return CallMethodO(OBJECT(self), py__hex__, NULL, NULL);
}
static PyNumberMethods Wrapper_as_number = {
(binaryfunc)Wrapper_add, /*nb_add*/
(binaryfunc)Wrapper_sub, /*nb_subtract*/
(binaryfunc)Wrapper_mul, /*nb_multiply*/
(binaryfunc)Wrapper_div, /*nb_divide*/
(binaryfunc)Wrapper_mod, /*nb_remainder*/
(binaryfunc)Wrapper_divmod, /*nb_divmod*/
(ternaryfunc)Wrapper_pow, /*nb_power*/
(unaryfunc)Wrapper_neg, /*nb_negative*/
(unaryfunc)Wrapper_pos, /*nb_positive*/
(unaryfunc)Wrapper_abs, /*nb_absolute*/
(inquiry)Wrapper_length, /*nb_nonzero*/
(unaryfunc)Wrapper_invert, /*nb_invert*/
(binaryfunc)Wrapper_lshift, /*nb_lshift*/
(binaryfunc)Wrapper_rshift, /*nb_rshift*/
(binaryfunc)Wrapper_and, /*nb_and*/
(binaryfunc)Wrapper_xor, /*nb_xor*/
(binaryfunc)Wrapper_or, /*nb_or*/
(coercion)Wrapper_coerce, /*nb_coerce*/
(unaryfunc)Wrapper_int, /*nb_int*/
(unaryfunc)Wrapper_long, /*nb_long*/
(unaryfunc)Wrapper_float, /*nb_float*/
(unaryfunc)Wrapper_oct, /*nb_oct*/
(unaryfunc)Wrapper_hex, /*nb_hex*/
};
/* -------------------------------------------------------- */
static char *acquire_args[] = {"object", "name", "filter", "extra", "explicit",
"default", "containment", NULL};
static PyObject *
Wrapper_acquire_method(Wrapper *self, PyObject *args, PyObject *kw)
{
PyObject *name, *filter=0, *extra=Py_None;
PyObject *expl=0, *defalt=0;
int explicit=1;
int containment=0;
UNLESS (PyArg_ParseTupleAndKeywords(
args, kw, "O|OOOOi", acquire_args+1,
&name, &filter, &extra, &explicit, &defalt, &containment
))
return NULL;
if (expl) explicit=PyObject_IsTrue(expl);
if (filter==Py_None) filter=0;
return Wrapper_findattr(self,name,filter,extra,OBJECT(self),1,
explicit ||
self->ob_type==(PyTypeObject*)&Wrappertype,
explicit, containment);
}
static PyObject *
Wrapper_inContextOf(Wrapper *self, PyObject *args)
{
PyObject *o, *c, *bc;
int inner=0;
UNLESS(PyArg_ParseTuple(args,"O|i",&o,&inner)) return NULL;
if (inner)
while (self->obj && isWrapper(self->obj))
self=WRAPPER(self->obj);
c = OBJECT(self);
while (1)
{
if (c==o) return PyInt_FromLong(1);
if (c && isWrapper(c)) c=WRAPPER(c)->container;
else break;
}
/* Now try harder: Compare each object in the containment chain that
starts at self, with the object of the wrapper passed in to this
method. If a match is found, return 1. Thanks to Toby Dickenson.*/
while (isWrapper(o) && WRAPPER(o)->obj) o=WRAPPER(o)->obj;
c = OBJECT(self);
while (1)
{
bc=c;
while (isWrapper(bc) && WRAPPER(bc)->obj) bc=WRAPPER(bc)->obj;
if (bc==o) return PyInt_FromLong(1);
if (c && isWrapper(c)) c=WRAPPER(c)->container;
else break;
}
return PyInt_FromLong(0);
}
static struct PyMethodDef Wrapper_methods[] = {
{"__init__", (PyCFunction)Wrapper__init__, 0,
"Initialize an Acquirer Wrapper"},
{"acquire", (PyCFunction)Wrapper_acquire_method,
METH_VARARGS|METH_KEYWORDS,
"Get an attribute, acquiring it if necessary"},
{"aq_acquire", (PyCFunction)Wrapper_acquire_method,
METH_VARARGS|METH_KEYWORDS,
"Get an attribute, acquiring it if necessary"},
{"aq_inContextOf", (PyCFunction)Wrapper_inContextOf, METH_VARARGS,
"Test whether the object is currently in the context of the argument"},
{NULL, NULL} /* sentinel */
};
static PyExtensionClass Wrappertype = {
PyObject_HEAD_INIT(NULL)
0, /*ob_size*/
"ImplicitAcquirerWrapper", /*tp_name*/
sizeof(Wrapper), /*tp_basicsize*/
0, /*tp_itemsize*/
/* methods */
(destructor)Wrapper_dealloc, /*tp_dealloc*/
(printfunc)0, /*tp_print*/
(getattrfunc)0, /*tp_getattr*/
(setattrfunc)0, /*tp_setattr*/
(cmpfunc)Wrapper_compare, /*tp_compare*/
(reprfunc)Wrapper_repr, /*tp_repr*/
&Wrapper_as_number, /*tp_as_number*/
&Wrapper_as_sequence, /*tp_as_sequence*/
&Wrapper_as_mapping, /*tp_as_mapping*/
(hashfunc)Wrapper_hash, /*tp_hash*/
(ternaryfunc)Wrapper_call, /*tp_call*/
(reprfunc)Wrapper_str, /*tp_str*/
(getattrofunc)Wrapper_getattro, /*tp_getattr with object key*/
(setattrofunc)Wrapper_setattro, /*tp_setattr with object key*/
/* Space for future expansion */
0L,0L,
"Wrapper object for implicit acquisition", /* Documentation string */
METHOD_CHAIN(Wrapper_methods),
EXTENSIONCLASS_BINDABLE_FLAG,
};
static PyExtensionClass XaqWrappertype = {
PyObject_HEAD_INIT(NULL)
0, /*ob_size*/
"ExplicitAcquirerWrapper", /*tp_name*/
sizeof(Wrapper), /*tp_basicsize*/
0, /*tp_itemsize*/
/* methods */
(destructor)Wrapper_dealloc, /*tp_dealloc*/
(printfunc)0, /*tp_print*/
(getattrfunc)0, /*tp_getattr*/
(setattrfunc)0, /*tp_setattr*/
(cmpfunc)Wrapper_compare, /*tp_compare*/
(reprfunc)Wrapper_repr, /*tp_repr*/
0, /*tp_as_number*/
&Wrapper_as_sequence, /*tp_as_sequence*/
&Wrapper_as_mapping, /*tp_as_mapping*/
(hashfunc)Wrapper_hash, /*tp_hash*/
(ternaryfunc)Wrapper_call, /*tp_call*/
(reprfunc)Wrapper_str, /*tp_str*/
(getattrofunc)Xaq_getattro, /*tp_getattr with object key*/
(setattrofunc)Wrapper_setattro, /*tp_setattr with object key*/
/* Space for future expansion */
0L,0L,
"Wrapper object for explicit acquisition", /* Documentation string */
METHOD_CHAIN(Wrapper_methods),
EXTENSIONCLASS_BINDABLE_FLAG,
};
static PyObject *
acquire_of(PyObject *self, PyObject *args)
{
PyObject *inst;
UNLESS(PyArg_ParseTuple(args, "O", &inst)) return NULL;
UNLESS(PyExtensionInstance_Check(inst))
{
PyErr_SetString(PyExc_TypeError,
"attempt to wrap extension method using an object that\n"
"is not an extension class instance.");
return NULL;
}
return newWrapper(self, inst, (PyTypeObject *)&Wrappertype);
}
static PyObject *
xaq_of(PyObject *self, PyObject *args)
{
PyObject *inst;
UNLESS(PyArg_ParseTuple(args, "O", &inst)) return NULL;
UNLESS(PyExtensionInstance_Check(inst))
{
PyErr_SetString(PyExc_TypeError,
"attempt to wrap extension method using an object that\n"
"is not an extension class instance.");
return NULL;
}
return newWrapper(self, inst, (PyTypeObject *)&XaqWrappertype);
}
static struct PyMethodDef Acquirer_methods[] = {
{"__of__",(PyCFunction)acquire_of, METH_VARARGS,
"__of__(context) -- return the object in a context"},
{NULL, NULL} /* sentinel */
};
static struct PyMethodDef Xaq_methods[] = {
{"__of__",(PyCFunction)xaq_of, METH_VARARGS,""},
{NULL, NULL} /* sentinel */
};
static PyObject *
module_aq_acquire(PyObject *ignored, PyObject *args, PyObject *kw)
{
PyObject *self;
PyObject *name, *filter=0, *extra=Py_None;
PyObject *expl=0, *defalt=0;
int explicit=1, containment=0;
UNLESS (PyArg_ParseTupleAndKeywords(
args, kw, "OO|OOOOi", acquire_args,
&self, &name, &filter, &extra, &explicit, &defalt, &containment
))
return NULL;
if (expl) explicit=PyObject_IsTrue(expl);
if (filter==Py_None) filter=0;
/* We got a wrapped object, so business as usual */
if (isWrapper(self))
return Wrapper_findattr(
WRAPPER(self), name, filter, extra, OBJECT(self),1,
explicit ||
WRAPPER(self)->ob_type==(PyTypeObject*)&Wrappertype,
explicit, containment);
/* Not wrapped and no filter, so just getattr */
if (! filter) return PyObject_GetAttr(self, name);
/* Crap, we've got to construct a wrapper so we can use Wrapper_findattr */
UNLESS (self=newWrapper(self, NULL, (PyTypeObject*)&Wrappertype))
return NULL;
ignored=Wrapper_findattr(WRAPPER(self), name, filter, extra, OBJECT(self),
1, 1, explicit, containment);
/* get rid of temp wrapper */
Py_DECREF(self);
return ignored;
}
static PyObject *
module_aq_get(PyObject *r, PyObject *args)
{
PyObject *self, *name, *defalt=0;
int containment=0;
UNLESS (PyArg_ParseTuple(args, "OO|Oi",
&self, &name, &defalt, &containment
)) return NULL;
/* We got a wrapped object, so business as usual */
if (isWrapper(self))
r=Wrapper_findattr(WRAPPER(self), name, 0, 0, OBJECT(self), 1, 1, 1,
containment);
else
r=PyObject_GetAttr(self, name);
if (! r && defalt)
{
PyErr_Clear();
r=defalt;
Py_INCREF(r);
}
return r;
}
static PyObject *
module_aq_base(PyObject *ignored, PyObject *args)
{
PyObject *self, *r;
UNLESS (PyArg_ParseTuple(args, "O", &self)) return NULL;
if (! isWrapper(self))
{
Py_INCREF(self);
return self;
}
if (WRAPPER(self)->obj)
{
r=WRAPPER(self)->obj;
while (isWrapper(r) && WRAPPER(r)->obj) r=WRAPPER(r)->obj;
}
else r=Py_None;
Py_INCREF(r);
return r;
}
static PyObject *
module_aq_parent(PyObject *ignored, PyObject *args)
{
PyObject *self, *r=Py_None;
UNLESS (PyArg_ParseTuple(args, "O", &self)) return NULL;
if (isWrapper(self) && WRAPPER(self)->container) r=WRAPPER(self)->container;
Py_INCREF(r);
return r;
}
static PyObject *
module_aq_self(PyObject *ignored, PyObject *args)
{
PyObject *self, *r;
UNLESS (PyArg_ParseTuple(args, "O", &self)) return NULL;
if (! isWrapper(self))
{
Py_INCREF(self);
return self;
}
if (WRAPPER(self)->obj) r=WRAPPER(self)->obj;
else r=Py_None;
Py_INCREF(r);
return r;
}
static PyObject *
module_aq_inner(PyObject *ignored, PyObject *args)
{
PyObject *self, *r;
UNLESS (PyArg_ParseTuple(args, "O", &self)) return NULL;
if (! isWrapper(self))
{
Py_INCREF(self);
return self;
}
if (WRAPPER(self)->obj)
{
r=WRAPPER(self)->obj;
while (isWrapper(r) && WRAPPER(r)->obj)
{
self=r;
r=WRAPPER(r)->obj;
}
r=self;
}
else r=Py_None;
Py_INCREF(r);
return r;
}
static PyObject *
module_aq_chain(PyObject *ignored, PyObject *args)
{
PyObject *self, *r;
int containment=0;
UNLESS (PyArg_ParseTuple(args, "O|i", &self, &containment))
return NULL;
UNLESS (r=PyList_New(0)) return NULL;
while (1)
{
if (isWrapper(self))
{
if (WRAPPER(self)->obj)
{
if (containment)
while (WRAPPER(self)->obj && isWrapper(WRAPPER(self)->obj))
self=WRAPPER(self)->obj;
if (PyList_Append(r,OBJECT(self)) < 0)
goto err;
}
if (WRAPPER(self)->container)
{
self=WRAPPER(self)->container;
continue;
}
}
else
if (PyList_Append(r, self) < 0)
goto err;
break;
}
return r;
err:
Py_DECREF(r);
return r;
}
static struct PyMethodDef methods[] = {
{"aq_acquire", (PyCFunction)module_aq_acquire, METH_VARARGS|METH_KEYWORDS,
"aq_acquire(ob, name [, filter, extra, explicit]) -- "
"Get an attribute, acquiring it if necessary"
},
{"aq_get", (PyCFunction)module_aq_get, METH_VARARGS,
"aq_get(ob, name [, default]) -- "
"Get an attribute, acquiring it if necessary."
},
{"aq_base", (PyCFunction)module_aq_base, METH_VARARGS,
"aq_base(ob) -- Get the object unwrapped"},
{"aq_parent", (PyCFunction)module_aq_parent, METH_VARARGS,
"aq_parent(ob) -- Get the parent of an object"},
{"aq_self", (PyCFunction)module_aq_self, METH_VARARGS,
"aq_self(ob) -- Get the object with the outermost wrapper removed"},
{"aq_inner", (PyCFunction)module_aq_inner, METH_VARARGS,
"aq_inner(ob) -- "
"Get the object with alll but the innermost wrapper removed"},
{"aq_chain", (PyCFunction)module_aq_chain, METH_VARARGS,
"aq_chain(ob [, containment]) -- "
"Get a list of objects in the acquisition environment"},
{NULL, NULL}
};
void
initAcquisition()
{
PyObject *m, *d;
char *rev="$Revision: 1.47 $";
PURE_MIXIN_CLASS(Acquirer,
"Base class for objects that implicitly"
" acquire attributes from containers\n"
, Acquirer_methods);
PURE_MIXIN_CLASS(ExplicitAcquirer,
"Base class for objects that explicitly"
" acquire attributes from containers\n"
, Xaq_methods);
UNLESS(ExtensionClassImported) return;
UNLESS(Acquired=PyString_FromStringAndSize(NULL,42)) return;
strcpy(PyString_AsString(Acquired),
"<Special Object Used to Force Acquisition>");
/* Create the module and add the functions */
m = Py_InitModule4("Acquisition", methods,
"Provide base classes for acquiring objects\n\n"
"$Id: Acquisition.c,v 1.47 2001/02/19 19:16:07 jeremy Exp $\n",
OBJECT(NULL),PYTHON_API_VERSION);
d = PyModule_GetDict(m);
init_py_names();
PyExtensionClass_Export(d,"Acquirer",AcquirerType);
PyExtensionClass_Export(d,"ImplicitAcquisitionWrapper",Wrappertype);
PyExtensionClass_Export(d,"ExplicitAcquirer",ExplicitAcquirerType);
PyExtensionClass_Export(d,"ExplicitAcquisitionWrapper",XaqWrappertype);
/* Create aliases */
PyDict_SetItemString(d,"Implicit",OBJECT(&AcquirerType));
PyDict_SetItemString(d,"Explicit",OBJECT(&ExplicitAcquirerType));
PyDict_SetItemString(d,"__version__",
PyString_FromStringAndSize(rev+11,strlen(rev+11)-2));
PyDict_SetItemString(d,"Acquired",Acquired);
CHECK_FOR_ERRORS("can't initialize module Acquisition");
}
/*
Copyright (c) 1996-1998, Digital Creations, Fredericksburg, VA, USA.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
o Redistributions of source code must retain the above copyright
notice, this list of conditions, and the disclaimer that follows.
o Redistributions in binary form must reproduce the above copyright
notice, this list of conditions, and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
o Neither the name of Digital Creations nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS AND CONTRIBUTORS *AS
IS* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DIGITAL
CREATIONS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
$Id: ComputedAttribute.c,v 1.4 2001/01/23 14:37:20 jim Exp $
If you have questions regarding this software,
contact:
Digital Creations L.C.
info@digicool.com
(540) 371-6909
*/
#include "ExtensionClass.h"
static void
PyVar_Assign(PyObject **v, PyObject *e)
{
Py_XDECREF(*v);
*v=e;
}
#define ASSIGN(V,E) PyVar_Assign(&(V),(E))
#define UNLESS(E) if(!(E))
#define UNLESS_ASSIGN(V,E) ASSIGN(V,E); UNLESS(V)
#define OBJECT(O) ((PyObject*)(O))
typedef struct {
PyObject_HEAD
PyObject *callable;
int level;
} CA;
static PyObject *
CA__init__(CA *self, PyObject *args)
{
PyObject *callable;
int level=0;
UNLESS(PyArg_ParseTuple(args,"O|i",&callable, &level)) return NULL;
if (level > 0)
{
callable=PyObject_CallFunction(OBJECT(self->ob_type), "Oi",
callable, self->level-1);
UNLESS (callable) return NULL;
self->level=level;
}
else
{
Py_INCREF(callable);
self->level=0;
}
self->callable=callable;
Py_INCREF(Py_None);
return Py_None;
}
static void
CA_dealloc(CA *self)
{
Py_DECREF(self->callable);
Py_DECREF(self->ob_type);
PyMem_DEL(self);
}
static PyObject *
CA_of(CA *self, PyObject *args)
{
if (self->level > 0)
{
Py_INCREF(self->callable);
return self->callable;
}
if (PyString_Check(self->callable))
{
/* Special case string as simple alias. */
PyObject *o;
UNLESS (PyArg_ParseTuple(args,"O", &o)) return NULL;
return PyObject_GetAttr(o, self->callable);
}
return PyObject_CallObject(self->callable, args);
}
static struct PyMethodDef CA_methods[] = {
{"__init__",(PyCFunction)CA__init__, METH_VARARGS, ""},
{"__of__", (PyCFunction)CA_of, METH_VARARGS, ""},
{NULL, NULL} /* sentinel */
};
static PyExtensionClass ComputedAttributeType = {
PyObject_HEAD_INIT(NULL) 0,
"ComputedAttribute", sizeof(CA),
0,
(destructor)CA_dealloc,
0,0,0,0,0, 0,0,0, 0,0,0,0,0, 0,0,
"ComputedAttribute(callable) -- Create a computed attribute",
METHOD_CHAIN(CA_methods),
EXTENSIONCLASS_BINDABLE_FLAG
};
static struct PyMethodDef methods[] = {
{NULL, NULL}
};
void
initComputedAttribute()
{
PyObject *m, *d;
char *rev="$Revision: 1.4 $";
UNLESS(ExtensionClassImported) return;
ComputedAttributeType.tp_getattro=
(getattrofunc)PyExtensionClassCAPI->getattro;
/* Create the module and add the functions */
m = Py_InitModule4("ComputedAttribute", methods,
"Provide Computed Attributes\n\n"
"$Id: ComputedAttribute.c,v 1.4 2001/01/23 14:37:20 jim Exp $\n",
OBJECT(NULL),PYTHON_API_VERSION);
d = PyModule_GetDict(m);
PyExtensionClass_Export(d,"ComputedAttribute",ComputedAttributeType);
PyDict_SetItemString(d,"__version__",
PyString_FromStringAndSize(rev+11,strlen(rev+11)-2));
CHECK_FOR_ERRORS("can't initialize module Acquisition");
}
/*
Copyright (c) 1996-2000, Digital Creations, Fredericksburg, VA, USA.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
o Redistributions of source code must retain the above copyright
notice, this list of conditions, and the disclaimer that follows.
o Redistributions in binary form must reproduce the above copyright
notice, this list of conditions, and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
o Neither the name of Digital Creations nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS AND CONTRIBUTORS *AS
IS* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DIGITAL
CREATIONS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
$Id: ExtensionClass.c,v 1.44 2001/02/19 19:16:07 jeremy Exp $
If you have questions regarding this software,
contact:
Digital Creations L.C.
info@digicool.com
(540) 371-6909
*/
static char ExtensionClass_module_documentation[] =
"ExtensionClass - Classes implemented in c\n"
"\n"
"Built-in C classes are like Built-in types except that\n"
"they provide some of the behavior of Python classes:\n"
"\n"
" - They provide access to unbound methods,\n"
" - They can be called to create instances.\n"
"\n"
"$Id: ExtensionClass.c,v 1.44 2001/02/19 19:16:07 jeremy Exp $\n"
;
#include <stdio.h>
#include "ExtensionClass.h"
static void
PyVar_Assign(PyObject **v, PyObject *e)
{
Py_XDECREF(*v);
*v=e;
}
#define ASSIGN(V,E) PyVar_Assign(&(V),(E))
#define UNLESS(E) if (!(E))
#define UNLESS_ASSIGN(V,E) ASSIGN(V,E); UNLESS(V)
#define OBJECT(O) ((PyObject*)O)
/* Declarations for objects of type ExtensionClass */
staticforward PyExtensionClass ECType;
#define ExtensionClass_Check(O) ((O)->ob_type == (PyTypeObject*)&ECType)
#define ExtensionInstance_Check(O) \
((O)->ob_type->ob_type == (PyTypeObject*)&ECType)
#define AsExtensionClass(O) ((PyExtensionClass*)(O))
#define ExtensionClassOf(O) ((PyExtensionClass*)((O)->ob_type))
#define AsPyObject(O) ((PyObject*)(O))
#define NeedsToBeBound(O) \
((O)->ob_type->ob_type == (PyTypeObject*)&ECType && \
(((PyExtensionClass*)((O)->ob_type))->class_flags & \
EXTENSIONCLASS_BINDABLE_FLAG))
#define HasMethodHook(O) \
((O)->ob_type->ob_type == (PyTypeObject*)&ECType && \
(((PyExtensionClass*)((O)->ob_type))->class_flags & \
EXTENSIONCLASS_METHODHOOK_FLAG))
#define ALLOC_FREE(T) \
if (free ## T) { \
self=free ## T; \
free ## T=(T*)self->self; \
self->ob_refcnt=1; \
} \
else UNLESS(self = PyObject_NEW(T, & T ## Type)) return NULL;
#define METH_BY_NAME (2 << 16)
static PyObject *py__add__, *py__sub__, *py__mul__, *py__div__,
*py__mod__, *py__pow__, *py__divmod__, *py__lshift__, *py__rshift__,
*py__and__, *py__or__, *py__xor__, *py__coerce__, *py__neg__,
*py__pos__, *py__abs__, *py__nonzero__, *py__inv__, *py__int__,
*py__long__, *py__float__, *py__oct__, *py__hex__,
*py__of__, *py__call__, *py__call_method__,
*py__getitem__, *py__setitem__, *py__delitem__,
*py__getslice__, *py__setslice__, *py__delslice__, *py__len__,
*py__getattr__, *py__setattr__, *py__delattr__,
*py__del__, *py__repr__, *py__str__, *py__class__, *py__name__,
*py__hash__, *py__cmp__, *py__var_size__, *py__init__, *py__getinitargs__,
*py__getstate__, *py__setstate__, *py__dict__, *pyclass_,
*py__module__;
static PyObject *concat_fmt=0;
static PyObject *subclass_watcher=0; /* Object that subclass events */
static void
init_py_names()
{
#define INIT_PY_NAME(N) py ## N = PyString_FromString(#N)
INIT_PY_NAME(__add__);
INIT_PY_NAME(__sub__);
INIT_PY_NAME(__mul__);
INIT_PY_NAME(__div__);
INIT_PY_NAME(__mod__);
INIT_PY_NAME(__pow__);
INIT_PY_NAME(__divmod__);
INIT_PY_NAME(__lshift__);
INIT_PY_NAME(__rshift__);
INIT_PY_NAME(__and__);
INIT_PY_NAME(__or__);
INIT_PY_NAME(__xor__);
INIT_PY_NAME(__coerce__);
INIT_PY_NAME(__neg__);
INIT_PY_NAME(__pos__);
INIT_PY_NAME(__abs__);
INIT_PY_NAME(__nonzero__);
INIT_PY_NAME(__inv__);
INIT_PY_NAME(__int__);
INIT_PY_NAME(__long__);
INIT_PY_NAME(__float__);
INIT_PY_NAME(__oct__);
INIT_PY_NAME(__hex__);
INIT_PY_NAME(__getitem__);
INIT_PY_NAME(__setitem__);
INIT_PY_NAME(__delitem__);
INIT_PY_NAME(__getslice__);
INIT_PY_NAME(__setslice__);
INIT_PY_NAME(__delslice__);
INIT_PY_NAME(__len__);
INIT_PY_NAME(__of__);
INIT_PY_NAME(__call__);
INIT_PY_NAME(__call_method__);
INIT_PY_NAME(__getattr__);
INIT_PY_NAME(__setattr__);
INIT_PY_NAME(__delattr__);
INIT_PY_NAME(__del__);
INIT_PY_NAME(__repr__);
INIT_PY_NAME(__str__);
INIT_PY_NAME(__class__);
INIT_PY_NAME(__name__);
INIT_PY_NAME(__hash__);
INIT_PY_NAME(__cmp__);
INIT_PY_NAME(__var_size__);
INIT_PY_NAME(__init__);
INIT_PY_NAME(__getinitargs__);
INIT_PY_NAME(__getstate__);
INIT_PY_NAME(__setstate__);
INIT_PY_NAME(__dict__);
INIT_PY_NAME(class_);
INIT_PY_NAME(__module__);
#undef INIT_PY_NAME
}
static PyObject *
CallMethodO(PyObject *self, PyObject *name,
PyObject *args, PyObject *kw)
{
if (! args && PyErr_Occurred()) return NULL;
UNLESS(name=PyObject_GetAttr(self,name)) return NULL;
ASSIGN(name,PyEval_CallObjectWithKeywords(name,args,kw));
if (args) { Py_DECREF(args); }
return name;
}
#define Build Py_BuildValue
/* CMethod objects: */
typedef struct {
PyObject_HEAD
PyTypeObject *type;
PyObject *self;
char *name;
PyCFunction meth;
int flags;
char *doc;
} CMethod;
staticforward PyTypeObject CMethodType;
#define CMethod_Check(O) ((O)->ob_type==&CMethodType)
#define UnboundCMethod_Check(O) \
((O)->ob_type==&CMethodType && ! ((CMethod*)(O))->self)
#define AsCMethod(O) ((CMethod*)(O))
#define CMETHOD(O) ((CMethod*)(O))
#define PMethod PyECMethodObject
#define PMethodType PyECMethodObjectType
staticforward PyTypeObject PMethodType;
#define PMethod_Check(O) ((O)->ob_type==&PMethodType)
#define UnboundPMethod_Check(O) \
((O)->ob_type==&PMethodType && ! ((PMethod*)(O))->self)
#define UnboundEMethod_Check(O) \
(((O)->ob_type==&PMethodType ||(O)->ob_type==&CMethodType) \
&& ! ((PMethod*)(O))->self)
#define PMETHOD(O) ((PMethod*)(O))
static PyObject *
bindPMethod(PMethod *m, PyObject *inst);
static PyObject *
#ifdef HAVE_STDARG_PROTOTYPES
/* VARARGS 2 */
JimErr_Format(PyObject *ErrType, char *stringformat, char *format, ...)
#else
/* VARARGS */
JimErr_Format(va_alist) va_dcl
#endif
{
va_list va;
PyObject *args=0, *retval=0;
#ifdef HAVE_STDARG_PROTOTYPES
va_start(va, format);
#else
PyObject *ErrType;
char *stringformat, *format;
va_start(va);
ErrType = va_arg(va, PyObject *);
stringformat = va_arg(va, char *);
format = va_arg(va, char *);
#endif
if (format) args = Py_VaBuildValue(format, va);
va_end(va);
if (format && ! args) return NULL;
if (stringformat && !(retval=PyString_FromString(stringformat))) return NULL;
if (retval)
{
if (args)
{
PyObject *v;
v=PyString_Format(retval, args);
Py_DECREF(retval);
Py_DECREF(args);
if (! v) return NULL;
retval=v;
}
}
else
if (args) retval=args;
else
{
PyErr_SetObject(ErrType,Py_None);
return NULL;
}
PyErr_SetObject(ErrType,retval);
Py_DECREF(retval);
return NULL;
}
static PyObject *
#ifdef HAVE_STDARG_PROTOTYPES
/* VARARGS 2 */
JimString_Build(char *out_format, char *build_format, ...)
#else
/* VARARGS */
JimString_Build(va_alist) va_dcl
#endif
{
va_list va;
PyObject *args, *retval, *fmt;
#ifdef HAVE_STDARG_PROTOTYPES
va_start(va, build_format);
#else
char *build_format;
char *out_format;
va_start(va);
out_format = va_arg(va, char *);
build_format = va_arg(va, char *);
#endif
if (build_format)
args = Py_VaBuildValue(build_format, va);
else
args = PyTuple_New(0);
va_end(va);
if (! args)
return NULL;
if (! PyTuple_Check(args))
{
PyObject *a;
a=PyTuple_New(1);
if (! a)
return NULL;
if (PyTuple_SetItem(a,0,args) == -1)
return NULL;
args=a;
}
fmt = PyString_FromString(out_format);
retval = PyString_Format(fmt, args);
Py_DECREF(args);
Py_DECREF(fmt);
return retval;
}
static int
CMethod_issubclass(PyExtensionClass *sub, PyExtensionClass *type)
{
int i,l;
PyObject *t;
if (sub==type) return 1;
if (! sub->bases) return 0;
l=PyTuple_Size(sub->bases);
for (i=0; i < l; i++)
{
t=PyTuple_GET_ITEM(sub->bases, i);
if (t==(PyObject*)type) return 1;
if (ExtensionClass_Check(t)
&& AsExtensionClass(t)->bases
&& CMethod_issubclass(AsExtensionClass(t),type)
) return 1;
}
return 0;
}
#define Subclass_Check(C1,C2) \
CMethod_issubclass((PyExtensionClass *)(C1), (PyExtensionClass *)(C2))
#define SubclassInstance_Check(C1,C2) \
CMethod_issubclass((PyExtensionClass *)((C1)->ob_type), \
(PyExtensionClass *)(C2))
static CMethod *freeCMethod=0;
static PyObject *
newCMethod(PyExtensionClass *type, PyObject *inst,
char *name, PyCFunction meth, int flags, char *doc)
{
CMethod *self;
ALLOC_FREE(CMethod);
Py_INCREF(type);
Py_XINCREF(inst);
self->type=(PyTypeObject*)type;
self->self=inst;
self->name=name;
self->meth=meth;
self->flags=flags;
self->doc=doc;
return (PyObject*)self;
}
static CMethod *
bindCMethod(CMethod *m, PyObject *inst)
{
CMethod *self;
UNLESS(inst->ob_type==m->type
|| (ExtensionInstance_Check(inst)
&& SubclassInstance_Check(inst,m->type))
|| ((m->flags & METH_CLASS_METHOD) && ExtensionClass_Check(inst))
)
{
Py_INCREF(m);
return m;
}
ALLOC_FREE(CMethod);
Py_INCREF(inst);
Py_INCREF(m->type);
self->type=m->type;
self->self=inst;
self->name=m->name;
self->meth=m->meth;
self->flags=m->flags;
self->doc=m->doc;
return self;
}
static void
CMethod_dealloc(CMethod *self)
{
#ifdef TRACE_DEALLOC
fprintf(stderr,"Deallocating C method %s\n", self->name);
#endif
Py_XDECREF(self->type);
Py_XDECREF(self->self);
self->self=(PyObject*)freeCMethod;
freeCMethod=self;
}
typedef PyObject *(*call_by_name_type)(PyObject*,PyObject*,PyObject*,
PyTypeObject*);
typedef PyObject *(*by_name_type)(PyObject*,PyObject*,
PyTypeObject*);
static PyObject *
call_cmethod(CMethod *self, PyObject *inst, PyObject *args, PyObject *kw)
{
if (!(self->flags & METH_VARARGS))
{
int size = PyTuple_Size(args);
if (size == 1) args = PyTuple_GET_ITEM(args, 0);
else if (size == 0) args = NULL;
}
if (self->flags & METH_KEYWORDS)
{
if (self->flags & METH_BY_NAME)
return (*(call_by_name_type)self->meth)(inst, args, kw,
self->type);
else
return (*(PyCFunctionWithKeywords)self->meth)(inst, args, kw);
}
else if (self->flags & METH_BY_NAME)
return (*(by_name_type)self->meth)(inst, args, self->type);
else
{
if (kw != NULL && PyDict_Size(kw) != 0)
{
PyErr_SetString(PyExc_TypeError,
"this function takes no keyword arguments");
return NULL;
}
return (*self->meth)(inst, args);
}
}
static char *hook_mark="C method being called through a hook.";
static PyObject *
callCMethodWithHook(CMethod *self, PyObject *inst,
PyObject *args, PyObject *kw)
{
PyObject *hook, *m;
UNLESS(m=newCMethod(AsExtensionClass(self->type),
inst, self->name, self->meth,
self->flags, hook_mark)) return NULL;
if ((hook=PyObject_GetAttr(inst,py__call_method__)))
{
if ((CMethod_Check(hook) && CMETHOD(hook)->meth==self->meth)
||
(PMethod_Check(hook)
&& CMethod_Check(PMETHOD(hook)->meth)
&& CMETHOD(PMETHOD(hook)->meth)->meth==self->meth)
)
{
/* Oops, we are already calling the hook! */
Py_DECREF(hook);
return PyEval_CallObjectWithKeywords(m,args,kw);
}
if (kw)
ASSIGN(hook,PyObject_CallFunction(hook,"OOO",m,args,kw));
else
ASSIGN(hook,PyObject_CallFunction(hook,"OO",m,args));
}
else
{
PyErr_Clear();
hook=PyEval_CallObjectWithKeywords(m,args,kw);
}
Py_DECREF(m);
return hook;
}
static PyObject *
CMethod_call(CMethod *self, PyObject *args, PyObject *kw)
{
int size;
if (self->self)
{
if (HasMethodHook(self->self) &&
self->doc != hook_mark /* This check prevents infinite recursion */
)
return callCMethodWithHook(self,self->self,args,kw);
return call_cmethod(self,self->self,args,kw);
}
if ((size=PyTuple_Size(args)) > 0)
{
PyObject *first=0;
UNLESS(first=PyTuple_GET_ITEM(args, 0)) return NULL;
if (
first->ob_type==self->type
||
(ExtensionInstance_Check(first)
&&
CMethod_issubclass(ExtensionClassOf(first),
AsExtensionClass(self->type))
)
)
{
PyObject *rest=0;
UNLESS (rest=PySequence_GetSlice(args,1,size)) return NULL;
if (HasMethodHook(first) &&
self->doc != hook_mark /* This check prevents infinite recursion */
)
ASSIGN(rest, callCMethodWithHook(self, first, rest, kw) );
else
ASSIGN(rest, call_cmethod(self, first, rest, kw) );
return rest;
}
}
return JimErr_Format(PyExc_TypeError,
"unbound C method must be called with %s 1st argument",
"s", self->type->tp_name);
}
static PyObject *
CMethod_getattro(CMethod *self, PyObject *oname)
{
PyObject *r;
if (PyString_Check(oname))
{
char *name;
UNLESS(name=PyString_AsString(oname)) return NULL;
if (name[0] != '_' && name[0] && name[1] != '_' &&
PyEval_GetRestricted())
{
PyErr_SetString(PyExc_RuntimeError,
"function attributes not accessible in restricted mode");
return NULL;
}
if (strcmp(name,"__name__")==0 || strcmp(name,"func_name")==0 )
return PyString_FromString(self->name);
if (strcmp(name,"func_code")==0 ||
strcmp(name,"im_func")==0)
{
Py_INCREF(self);
return (PyObject *)self;
}
if (strcmp(name,"__doc__")==0 ||
strcmp(name,"func_doc")==0)
{
if (self->doc)
return PyString_FromString(self->doc);
else
return PyString_FromString("");
}
if (strcmp(name,"im_class")==0)
{
Py_INCREF(self->type);
return (PyObject *)self->type;
}
if (strcmp(name,"im_self")==0)
{
if (self->self) r=self->self;
else r=Py_None;
Py_INCREF(r);
return r;
}
}
if (self->self) /* Psuedo attributes */
{
UNLESS(oname=Py_BuildValue("sO", self->name, oname)) return NULL;
UNLESS_ASSIGN(oname,PyString_Format(concat_fmt, oname)) return NULL;
r=PyObject_GetAttr(OBJECT(self->self), py__class__);
if (r)
{
ASSIGN(r, PyObject_GetAttr(r, oname));
if (r) {
if (UnboundCMethod_Check(r))
ASSIGN(r, (PyObject*)bindCMethod((CMethod*)r, self->self));
else if (UnboundPMethod_Check(r))
ASSIGN(r, bindPMethod((PMethod*)r, self->self));
}
}
Py_DECREF(oname);
return r;
}
PyErr_SetObject(PyExc_AttributeError, oname);
return NULL;
}
static int
CMethod_setattro(CMethod *self, PyObject *oname, PyObject *v)
{
int r;
if (self->self && ! PyEval_GetRestricted()) /* Psuedo attributes */
{
UNLESS(oname=Py_BuildValue("sO", self->name, oname)) return -1;
UNLESS_ASSIGN(oname,PyString_Format(concat_fmt, oname)) return -1;
r=PyObject_SetAttr(self->self, oname, v);
Py_DECREF(oname);
return r;
}
PyErr_SetObject(PyExc_AttributeError, oname);
return -1;
}
static PyTypeObject CMethodType = {
PyObject_HEAD_INIT(NULL)
0, /*ob_size*/
"CMethod", /*tp_name*/
sizeof(CMethod), /*tp_basicsize*/
0, /*tp_itemsize*/
/* methods */
(destructor)CMethod_dealloc, /*tp_dealloc*/
(printfunc)0, /*tp_print*/
0, /*tp_getattr*/
(setattrfunc)0, /*tp_setattr*/
(cmpfunc)0, /*tp_compare*/
(reprfunc)0, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
(hashfunc)0, /*tp_hash*/
(ternaryfunc)CMethod_call, /*tp_call*/
(reprfunc)0, /*tp_str*/
(getattrofunc)CMethod_getattro, /* tp_getattro */
(setattrofunc)0 /*CMethod_setattro*/, /* tp_setattro */
/* Space for future expansion */
0L,0L,
"Storage manager for unbound C function PyObject data"
/* Documentation string */
};
/* PMethod objects: */
static PMethod *freePMethod=0;
static PyObject *
newPMethod(PyExtensionClass *type, PyObject *meth)
{
PMethod *self;
ALLOC_FREE(PMethod);
Py_INCREF(type);
Py_INCREF(meth);
self->type=(PyTypeObject*)type;
self->self=NULL;
self->meth=meth;
return (PyObject*)self;
}
static PyObject *
bindPMethod(PMethod *m, PyObject *inst)
{
PMethod *self;
if (NeedsToBeBound(m->meth))
return CallMethodO(m->meth, py__of__, Build("(O)", inst), NULL);
if (m->ob_refcnt==1)
{
Py_INCREF(inst);
ASSIGN(m->self, inst);
Py_INCREF(m);
return (PyObject*)m;
}
ALLOC_FREE(PMethod);
Py_INCREF(inst);
Py_INCREF(m->type);
Py_INCREF(m->meth);
self->type=m->type;
self->self=inst;
self->meth=m->meth;
return (PyObject*)self;
}
static PyObject *
PMethod_New(PyObject *meth, PyObject *inst)
{
if (PMethod_Check(meth)) return bindPMethod((PMethod*)meth,inst);
UNLESS(ExtensionInstance_Check(inst))
return JimErr_Format(PyExc_TypeError,
"Attempt to use %s as method for %s, which is "
"not an extension class instance.",
"OO",meth,inst);
if ((meth=newPMethod(ExtensionClassOf(inst), meth)))
UNLESS_ASSIGN(((PMethod*)meth)->self,inst) return NULL;
Py_INCREF(inst);
return meth;
}
static void
PMethod_dealloc(PMethod *self)
{
#ifdef TRACE_DEALLOC
fprintf(stderr,"Deallocating PM ... ");
#endif
Py_XDECREF(self->type);
Py_XDECREF(self->self);
Py_XDECREF(self->meth);
self->self=(PyObject*)freePMethod;
freePMethod=self;
#ifdef TRACE_DEALLOC
fprintf(stderr," Done Deallocating PM\n");
#endif
}
static PyObject *
callMethodWithPossibleHook(PyObject *inst,
PyObject *meth, PyObject *args, PyObject *kw)
{
if (HasMethodHook(inst))
{
PyObject *hook;
if ((hook=PyObject_GetAttr(inst,py__call_method__)))
{
if (PMethod_Check(hook) && ((PMethod*)hook)->meth==meth)
{
/* Oops, we are already calling the hook! */
Py_DECREF(hook);
return PyEval_CallObjectWithKeywords(meth,args,kw);
}
if (kw)
ASSIGN(hook,PyObject_CallFunction(hook,"OOO",meth,args,kw));
else
ASSIGN(hook,PyObject_CallFunction(hook,"OO",meth,args));
return hook;
}
PyErr_Clear();
}
return PyEval_CallObjectWithKeywords(meth,args,kw);
}
static PyObject *
call_PMethod(PMethod *self, PyObject *inst, PyObject *args, PyObject *kw)
{
PyObject *a;
if (CMethod_Check(self->meth)
&& CMETHOD(self->meth)->type->tp_basicsize == sizeof(PyPureMixinObject)
&& ! (CMETHOD(self->meth)->self)
)
{
/* Special HACK^H^H^Hcase:
we are wrapping an abstract unbound CMethod */
if (HasMethodHook(inst) &&
/* This check prevents infinite recursion: */
CMETHOD(self->meth)->doc != hook_mark
)
return callCMethodWithHook(CMETHOD(self->meth),inst,args,kw);
return call_cmethod(CMETHOD(self->meth),inst,args,kw);
}
else
{
a=Py_BuildValue("(O)",inst);
if (a) ASSIGN(a,PySequence_Concat(a,args));
if (a) ASSIGN(a,callMethodWithPossibleHook(inst,self->meth,a,kw));
return a;
}
}
static PyObject *
PMethod_call(PMethod *self, PyObject *args, PyObject *kw)
{
int size;
if (self->self) return call_PMethod(self,self->self,args,kw);
if ((size=PyTuple_Size(args)) > 0)
{
PyObject *first=0, *ftype=0;
UNLESS(first=PyTuple_GET_ITEM(args, 0)) return NULL;
if (! self->type ||
((ftype=PyObject_GetAttr(first,py__class__)) &&
(ftype==(PyObject*)self->type ||
(ExtensionClass_Check(ftype) &&
CMethod_issubclass(AsExtensionClass(ftype),
AsExtensionClass(self->type))
)
)
)
)
{
if (NeedsToBeBound(self->meth))
{
PyObject *r, *rest;
UNLESS(r=CallMethodO(self->meth,py__of__,Build("(O)", first),
NULL))
return NULL;
UNLESS(rest=PySequence_GetSlice(args,1,size))
{
Py_DECREF(r);
return NULL;
}
ASSIGN(r,callMethodWithPossibleHook(first,r,rest,kw));
Py_DECREF(rest);
return r;
}
Py_DECREF(ftype);
return callMethodWithPossibleHook(first,self->meth,args,kw);
}
Py_XDECREF(ftype);
}
return JimErr_Format(PyExc_TypeError,
"unbound Python method must be called with %s"
" 1st argument",
"s", self->type->tp_name);
}
static PyObject *
PMethod_getattro(PMethod *self, PyObject *oname)
{
PyObject *r;
if (PyString_Check(oname))
{
char *name;
UNLESS(name=PyString_AsString(oname)) return NULL;
if (name[0]=='_' && name[1]=='_')
{
if (strcmp(name+2,"name__")==0)
return PyObject_GetAttrString(self->meth,"__name__");
if (strcmp(name+2,"doc__")==0)
return PyObject_GetAttrString(self->meth,"__doc__");
}
else if (PyEval_GetRestricted())
{
PyErr_SetString(PyExc_RuntimeError,
"function attributes not accessible in restricted mode");
return NULL;
}
else if (name[0]=='f' && name[1]=='u' && name[2]=='n' && name[3]=='c'
&& name[4]=='_')
{
if (strcmp(name+5,"name")==0 )
return PyObject_GetAttrString(self->meth,"__name__");
if (strcmp(name+5,"doc")==0)
return PyObject_GetAttrString(self->meth,"__doc__");
}
if (*name++=='i' && *name++=='m' && *name++=='_')
{
if (strcmp(name,"func")==0)
{
Py_INCREF(self->meth);
return self->meth;
}
if (strcmp(name,"class")==0)
{
Py_INCREF(self->type);
return (PyObject *)self->type;
}
if (strcmp(name,"self")==0)
{
if (self->self) r=self->self;
else r=Py_None;
Py_INCREF(r);
return r;
}
}
}
if (self->meth)
{
if ((r=PyObject_GetAttr(self->meth, oname))) return r;
PyErr_Clear();
if (self->self) /* Psuedo attrs */
{
PyObject *myname;
UNLESS(myname=PyObject_GetAttr(self->meth, py__name__)) return NULL;
oname=Py_BuildValue("OO", myname, oname);
Py_DECREF(myname);
UNLESS(oname) return NULL;
UNLESS_ASSIGN(oname,PyString_Format(concat_fmt, oname)) return NULL;
r=PyObject_GetAttr(OBJECT(self->self), py__class__);
if (r)
{
ASSIGN(r, PyObject_GetAttr(r, oname));
if (r) {
if (UnboundCMethod_Check(r))
ASSIGN(r, (PyObject*)bindCMethod((CMethod*)r, self->self));
else if (UnboundPMethod_Check(r))
ASSIGN(r, bindPMethod((PMethod*)r, self->self));
}
}
Py_DECREF(oname);
return r;
}
}
PyErr_SetObject(PyExc_AttributeError, oname);
return NULL;
return PyObject_GetAttr(self->meth, oname);
}
static int
PMethod_setattro(PMethod *self, PyObject *oname, PyObject *v)
{
int r;
PyObject *spam;
if (self->meth)
{
if ((spam=PyObject_GetAttr(self->meth, oname)))
{
Py_DECREF(spam);
PyErr_SetString(PyExc_TypeError,
"Attempt to overwrite shared method attribute");
return -1;
}
else PyErr_Clear();
if (self->self && ! PyEval_GetRestricted()) /* Psuedo attrs */
{
PyObject *myname;
UNLESS(myname=PyObject_GetAttr(self->meth, py__name__)) return -1;
oname=Py_BuildValue("OO", myname, oname);
Py_DECREF(myname);
UNLESS(oname) return -1;
UNLESS_ASSIGN(oname,PyString_Format(concat_fmt, oname)) return -1;
r=PyObject_SetAttr(self->self, oname, v);
Py_DECREF(oname);
return r;
}
}
PyErr_SetObject(PyExc_AttributeError, oname);
return -1;
}
static PyTypeObject PMethodType = {
PyObject_HEAD_INIT(NULL)
0, /*ob_size*/
"Python Method", /*tp_name*/
sizeof(PMethod), /*tp_basicsize*/
0, /*tp_itemsize*/
/* methods */
(destructor)PMethod_dealloc, /*tp_dealloc*/
(printfunc)0, /*tp_print*/
0, /*tp_getattr*/
(setattrfunc)0, /*tp_setattr*/
(cmpfunc)0, /*tp_compare*/
(reprfunc)0, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
(hashfunc)0, /*tp_hash*/
(ternaryfunc)PMethod_call, /*tp_call*/
(reprfunc)0, /*tp_str*/
(getattrofunc)PMethod_getattro, /*tp_getattro*/
(setattrofunc)0 /*PMethod_setattro*/, /* tp_setattro */
/* Space for future expansion */
0L,0L,
"Storage manager for unbound C function PyObject data"
/* Documentation string */
};
static PyObject *CCL_getattr(PyExtensionClass*,PyObject*,int);
static int
CCL_hasattr(PyExtensionClass *self,PyObject *name)
{
PyObject *r;
r=CCL_getattr(self, name, 0);
if (r)
{
Py_DECREF(r);
return 1;
}
else
PyErr_Clear();
return 0;
}
/* Special Methods */
#define UNARY_OP(OP) \
static PyObject * \
OP ## _by_name(PyObject *self, PyObject *args, PyTypeObject *ob_type) { \
UNLESS(PyArg_ParseTuple(args,"")) return NULL; \
return ob_type->tp_ ## OP(self); \
}
UNARY_OP(repr)
UNARY_OP(str)
static PyObject *
hash_by_name(PyObject *self, PyObject *args, PyTypeObject *ob_type) {
long r;
UNLESS(PyArg_ParseTuple(args,"")) return NULL;
UNLESS(-1 != (r=ob_type->tp_hash(self))) return NULL;
return PyInt_FromLong(r);
}
static PyObject *
call_by_name(PyObject *self, PyObject *args, PyObject *kw,
PyTypeObject *ob_type)
{
return ob_type->tp_call(self,args,kw);
}
static PyObject *
compare_by_name(PyObject *self, PyObject *args, PyTypeObject *ob_type)
{
PyObject *other;
UNLESS(PyArg_ParseTuple(args,"O", &other)) return NULL;
return PyInt_FromLong(ob_type->tp_compare(self,other));
}
static PyObject *
getattr_by_name(PyObject *self, PyObject *args, PyTypeObject *ob_type)
{
char *name;
UNLESS(PyArg_ParseTuple(args,"s",&name)) return NULL;
return ob_type->tp_getattr(self,name);
}
static PyObject *
setattr_by_name(PyObject *self, PyObject *args, PyTypeObject *ob_type)
{
char *name;
PyObject *v;
UNLESS(PyArg_ParseTuple(args,"sO",&name,&v)) return NULL;
UNLESS(-1 != ob_type->tp_setattr(self,name,v)) return NULL;
Py_INCREF(Py_None);
return Py_None;
}
static PyObject *
delsetattr_by_name(PyObject *self, PyObject *args, PyTypeObject *ob_type)
{
char *name;
UNLESS(PyArg_ParseTuple(args,"s",&name)) return NULL;
UNLESS(-1 != ob_type->tp_setattr(self,name,NULL)) return NULL;
Py_INCREF(Py_None);
return Py_None;
}
static PyObject *
getattro_by_name(PyObject *self, PyObject *args, PyTypeObject *ob_type)
{
PyObject *name;
UNLESS(PyArg_ParseTuple(args,"O",&name)) return NULL;
return ob_type->tp_getattro(self,name);
}
static PyObject *
setattro_by_name(PyObject *self, PyObject *args, PyTypeObject *ob_type)
{
PyObject *name;
PyObject *v;
UNLESS(PyArg_ParseTuple(args,"OO",&name,&v)) return NULL;
UNLESS(-1 != ob_type->tp_setattro(self,name,v)) return NULL;
Py_INCREF(Py_None);
return Py_None;
}
static PyObject *
delsetattro_by_name(PyObject *self, PyObject *args, PyTypeObject *ob_type)
{
PyObject *name;
UNLESS(PyArg_ParseTuple(args,"O",&name)) return NULL;
UNLESS(-1 != ob_type->tp_setattro(self,name,NULL)) return NULL;
Py_INCREF(Py_None);
return Py_None;
}
static PyObject *
length_by_name(PyObject *self, PyObject *args, PyTypeObject *ob_type)
{
long r;
UNLESS(PyArg_ParseTuple(args,"")) return NULL;
if (ob_type->tp_as_sequence)
{
UNLESS(-1 != (r=ob_type->tp_as_sequence->sq_length(self)))
return NULL;
}
else
{
UNLESS(-1 != (r=ob_type->tp_as_mapping->mp_length(self)))
return NULL;
}
return PyInt_FromLong(r);
}
static PyObject *
getitem_by_name(PyObject *self, PyObject *args, PyTypeObject *ob_type)
{
PyObject *key;
UNLESS(PyArg_ParseTuple(args,"O",&key)) return NULL;
if (ob_type->tp_as_mapping)
return ob_type->tp_as_mapping->mp_subscript(self,key);
else
{
int index;
UNLESS(-1 != (index=PyInt_AsLong(key))) return NULL;
return ob_type->tp_as_sequence->sq_item(self,index);
}
}
static PyCFunction item_by_name=(PyCFunction)getitem_by_name;
static PyCFunction subscript_by_name=(PyCFunction)getitem_by_name;
static PyObject *
setitem_by_name(PyObject *self, PyObject *args, PyTypeObject *ob_type)
{
PyObject *key, *v;
long r;
UNLESS(PyArg_ParseTuple(args,"OO",&key,&v)) return NULL;
if (ob_type->tp_as_mapping)
r=ob_type->tp_as_mapping->mp_ass_subscript(self,key,v);
else
{
int index;
UNLESS(-1 != (index=PyInt_AsLong(key))) return NULL;
r=ob_type->tp_as_sequence->sq_ass_item(self,index,v);
}
if (r < 0) return NULL;
Py_INCREF(Py_None);
return Py_None;
}
static PyCFunction ass_item_by_name=(PyCFunction)setitem_by_name;
static PyCFunction ass_subscript_by_name=(PyCFunction)setitem_by_name;
static PyObject *
slice_by_name(PyObject *self, PyObject *args, PyTypeObject *ob_type)
{
int i1,i2;
UNLESS(PyArg_ParseTuple(args,"ii",&i1,&i2)) return NULL;
return ob_type->tp_as_sequence->sq_slice(self,i1,i2);
}
static PyObject *
ass_slice_by_name(PyObject *self, PyObject *args, PyTypeObject *ob_type)
{
int i1,i2;
PyObject *v;
long r;
UNLESS(PyArg_ParseTuple(args,"iiO",&i1,&i2,&v)) return NULL;
r=ob_type->tp_as_sequence->sq_ass_slice(self,i1,i2,v);
if (r<0) return NULL;
Py_INCREF(Py_None);
return Py_None;
}
static PyObject *
concat_by_name(PyObject *self, PyObject *args, PyTypeObject *ob_type)
{
PyObject *other;
UNLESS(PyArg_ParseTuple(args,"O",&other)) return NULL;
return ob_type->tp_as_sequence->sq_concat(self,other);
}
static PyObject *
repeat_by_name(PyObject *self, PyObject *args, PyTypeObject *ob_type)
{
int r;
UNLESS(PyArg_ParseTuple(args,"i",&r)) return NULL;
return ob_type->tp_as_sequence->sq_repeat(self,r);
}
#define BINOP(OP,AOP) \
static PyObject * \
OP ## _by_name(PyObject *self, PyObject *args, PyTypeObject *ob_type) { \
PyObject *v; \
UNLESS(PyArg_ParseTuple(args,"O",&v)) return NULL; \
return ob_type->tp_as_number->nb_ ## OP(self, v); \
}
BINOP(add,Add)
BINOP(subtract,Subtract)
BINOP(multiply,Multiply)
BINOP(divide,Divide)
BINOP(remainder,Remainder)
BINOP(divmod,Divmod)
static PyObject *
power_by_name(PyObject *self, PyObject *args, PyTypeObject *ob_type)
{
PyObject *v, *z=NULL;
UNLESS(PyArg_ParseTuple(args,"O|O",&v,&z)) return NULL;
return ob_type->tp_as_number->nb_power(self,v,z);
}
#define UNOP(OP) \
static PyObject * \
OP ## _by_name(PyObject *self, PyObject *args, PyTypeObject *ob_type) { \
UNLESS(PyArg_ParseTuple(args,"")) return NULL; \
return ob_type->tp_as_number->nb_ ## OP(self); \
}
UNOP(negative)
UNOP(positive)
UNOP(absolute)
static PyObject *
nonzero_by_name(PyObject *self, PyObject *args, PyTypeObject *ob_type) {
long r;
UNLESS(PyArg_ParseTuple(args,"")) return NULL;
UNLESS(-1 != (r=ob_type->tp_as_number->nb_nonzero(self))) return NULL;
return PyInt_FromLong(r);
}
UNOP(invert)
BINOP(lshift,Lshift)
BINOP(rshift,Rshift)
BINOP(and,And)
BINOP(or,Or)
BINOP(xor,Xor)
static PyObject *
coerce_by_name(PyObject *self, PyObject *args, PyTypeObject *ob_type)
{
PyObject *v;
int r;
UNLESS(PyArg_ParseTuple(args,"O", &v)) return NULL;
UNLESS(-1 != (r=ob_type->tp_as_number->nb_coerce(&self,&v)))
{
Py_INCREF(Py_None);
return Py_None;
}
args=Py_BuildValue("OO",self,v);
Py_DECREF(self);
Py_DECREF(v);
return args;
}
UNOP(long)
UNOP(int)
UNOP(float)
UNOP(oct)
UNOP(hex)
#define FILLENTRY(T,MN,N,F,D) if (T ## _ ## MN) { \
UNLESS(-1 != PyMapping_SetItemString(dict,"__" # N "__", \
newCMethod(type, NULL, "__" # N "__", \
(PyCFunction)MN ## _by_name, F | METH_BY_NAME, # D))) \
goto err; }
#define delFILLENTRY(T,MN,N,F,D) if (T ## _ ## MN) { \
UNLESS(-1 != PyMapping_SetItemString(dict,"__" # N "__", \
newCMethod(type, NULL, "__" # N "__", \
(PyCFunction)del ## MN ## _by_name, F | METH_BY_NAME, # D))) \
goto err; }
static PyObject *
getBaseDictionary(PyExtensionClass *type)
{
PyNumberMethods *nm;
PySequenceMethods *sm;
PyMappingMethods *mm;
PyObject *dict;
UNLESS(dict=type->class_dictionary)
UNLESS(dict=PyDict_New()) return NULL;
FILLENTRY(type->tp, repr, repr, METH_VARARGS,
"convert to an expression string");
FILLENTRY(type->tp, hash, hash, METH_VARARGS, "compute a hash value");
FILLENTRY(type->tp, call, call, METH_VARARGS | METH_KEYWORDS,
"call as a function");
FILLENTRY(type->tp, compare, comp, METH_VARARGS,
"compare with another object");
UNLESS (type->class_flags & EXTENSIONCLASS_PYTHONICATTR_FLAG)
{
FILLENTRY(type->tp, getattr, getattr, METH_VARARGS, "Get an attribute");
FILLENTRY(type->tp, setattr, setattr, METH_VARARGS, "Set an attribute");
delFILLENTRY(type->tp, setattr, delattr, METH_VARARGS,
"Delete an attribute");
FILLENTRY(type->tp, getattro, getattr, METH_VARARGS, "Get an attribute");
FILLENTRY(type->tp, setattro, setattr, METH_VARARGS, "Set an attribute");
delFILLENTRY(type->tp, setattro, delattr, METH_VARARGS,
"Delete an attribute");
}
if ((sm=type->tp_as_sequence))
{
FILLENTRY(sm->sq, length, len, METH_VARARGS, "Get the object length");
FILLENTRY(sm->sq, repeat, mul, METH_VARARGS,
"Get a new object that is the object repeated.");
FILLENTRY(sm->sq, item, getitem, METH_VARARGS, "Get an item");
FILLENTRY(sm->sq, slice, getslice, METH_VARARGS, "Get a slice");
FILLENTRY(sm->sq, ass_item, setitem, METH_VARARGS, "Assign an item");
FILLENTRY(sm->sq, ass_slice, setslice, METH_VARARGS, "Assign a slice");
}
if ((mm=type->tp_as_mapping))
{
FILLENTRY(mm->mp, length, len, METH_VARARGS, "Get the object length");
FILLENTRY(mm->mp, subscript, getitem, METH_VARARGS, "Get an item");
FILLENTRY(mm->mp, ass_subscript, setitem, METH_VARARGS,
"Assign an item");
}
if ((nm=type->tp_as_number) != NULL)
{
FILLENTRY(nm->nb, add, add, METH_VARARGS, "Add to another");
FILLENTRY(nm->nb, subtract, sub, METH_VARARGS, "Subtract another");
FILLENTRY(nm->nb, multiply, mul, METH_VARARGS, "Multiple by another");
FILLENTRY(nm->nb, divide, div, METH_VARARGS, "Divide by another");
FILLENTRY(nm->nb, remainder, mod, METH_VARARGS, "Compute a remainder");
FILLENTRY(nm->nb, power, pow, METH_VARARGS, "Raise to a power");
FILLENTRY(nm->nb, divmod, divmod, METH_VARARGS,
"Compute the whole result and remainder of dividing\n"
"by another");
FILLENTRY(nm->nb, negative, neg, METH_VARARGS,
"Get the negative value.");
FILLENTRY(nm->nb, positive, pos, METH_VARARGS, "Compute positive value");
FILLENTRY(nm->nb, absolute, abs, METH_VARARGS, "Compute absolute value");
FILLENTRY(nm->nb, nonzero, nonzero, METH_VARARGS,
"Determine whether nonzero");
FILLENTRY(nm->nb, invert, inv, METH_VARARGS, "Compute inverse");
FILLENTRY(nm->nb, lshift, lshift, METH_VARARGS, "Shist left");
FILLENTRY(nm->nb, rshift, rshift, METH_VARARGS, "Shist right");
FILLENTRY(nm->nb, and, and, METH_VARARGS, "bitwize logical and");
FILLENTRY(nm->nb, or, or, METH_VARARGS, "bitwize logical or");
FILLENTRY(nm->nb, xor, xor, METH_VARARGS, "bitwize logical excusive or");
FILLENTRY(nm->nb, coerce, coerce, METH_VARARGS,
"Coerce woth another to a common type");
FILLENTRY(nm->nb, int, int, METH_VARARGS, "Convert to an integer");
FILLENTRY(nm->nb, long, long, METH_VARARGS,
"Convert to an infinite-precision integer");
FILLENTRY(nm->nb, float, float, METH_VARARGS,
"Convert to floating point number");
FILLENTRY(nm->nb, oct, oct, METH_VARARGS, "Convert to an octal string");
FILLENTRY(nm->nb, hex, hex, METH_VARARGS,
"Convert to a hexadecimal string");
}
if ((sm=type->tp_as_sequence))
{
FILLENTRY(sm->sq, concat, add, METH_VARARGS,
"Concatinate the object with another");
}
return dict;
err:
Py_DECREF(dict);
return NULL;
}
#undef UNARY_OP
#undef BINOP
#undef UNOP
#undef FILLENTRY
PyObject *
EC_reduce(PyObject *self, PyObject *args)
{
PyObject *state=0;
if ((args=PyObject_GetAttr(self,py__getinitargs__)))
{
UNLESS_ASSIGN(args,PyEval_CallObject(args,NULL)) return NULL;
UNLESS_ASSIGN(args,PySequence_Tuple(args)) return NULL;
}
else
{
PyErr_Clear();
if (ExtensionClassOf(self)->class_flags & EXTENSIONCLASS_BASICNEW_FLAG)
{
args=Py_None;
Py_INCREF(args);
}
else args=PyTuple_New(0);
}
if ((state=PyObject_GetAttr(self,py__getstate__)))
{
UNLESS_ASSIGN(state,PyEval_CallObject(state,NULL)) goto err;
ASSIGN(args,Py_BuildValue("OOO", self->ob_type, args, state));
Py_DECREF(state);
}
else
{
PyErr_Clear();
if ((state=PyObject_GetAttr(self, py__dict__)))
{
ASSIGN(args,Py_BuildValue("OOO", self->ob_type, args, state));
Py_DECREF(state);
}
else
{
PyErr_Clear();
ASSIGN(args, Py_BuildValue("OO", self->ob_type, args));
}
}
return args;
err:
Py_DECREF(args);
return NULL;
}
static PyObject *
inheritedAttribute(PyExtensionClass *self, PyObject *args)
{
PyObject *name;
UNLESS(PyArg_ParseTuple(args,"O!",&PyString_Type, &name)) return NULL;
return CCL_getattr(AsExtensionClass(self),name,1);
}
static PyObject *
basicnew(PyExtensionClass *self, PyObject *args)
{
PyObject *inst=0;
typedef struct { PyObject_VAR_HEAD } PyVarObject__;
if (! self->tp_dealloc)
{
PyErr_SetString(PyExc_TypeError,
"Attempt to create instance of an abstract type");
return NULL;
}
UNLESS(self->class_flags & EXTENSIONCLASS_BASICNEW_FLAG)
return PyObject_CallObject(OBJECT(self), NULL);
if (self->tp_itemsize)
{
/* We have a variable-sized object, we need to get it's size */
PyObject *var_size;
int size;
UNLESS(var_size=CCL_getattr(self, py__var_size__, 0)) return NULL;
UNLESS_ASSIGN(var_size,PyObject_CallObject(var_size,NULL)) return NULL;
size=PyInt_AsLong(var_size);
if (PyErr_Occurred()) return NULL;
UNLESS(inst=PyObject_NEW_VAR(PyObject,(PyTypeObject *)self, size))
return NULL;
memset(inst,0,self->tp_basicsize+self->tp_itemsize*size);
((PyVarObject__*)inst)->ob_size=size;
}
else
{
UNLESS(inst=PyObject_NEW(PyObject,(PyTypeObject *)self)) return NULL;
memset(inst,0,self->tp_basicsize);
}
inst->ob_refcnt=1;
inst->ob_type=(PyTypeObject *)self;
Py_INCREF(self);
if (ClassHasInstDict(self))
UNLESS(INSTANCE_DICT(inst)=PyDict_New()) goto err;
if (self->bases && subclass_watcher &&
! PyObject_CallMethod(subclass_watcher,"created","O",inst))
PyErr_Clear();
return inst;
err:
Py_DECREF(inst);
return NULL;
}
struct PyMethodDef ECI_methods[] = {
{"__reduce__",(PyCFunction)EC_reduce, METH_VARARGS,
"__reduce__() -- Reduce an instance into it's class and creation data"
},
{"inheritedAttribute",(PyCFunction)inheritedAttribute,
METH_VARARGS | METH_CLASS_METHOD,
"inheritedAttribute(class,name) -- Get an inherited attribute\n\n"
"Get an attribute that would be inherited if the given (extension)\n"
"class did not define it. This method is used when overriding\n"
"inherited methods. It provides 2 advantages over accessing\n"
"\n"
"attributes directly through a superclass:\n"
"\n"
"1. The superclass need not be known,\n"
"\n"
"2. The superclass may be a Python class. Without this method, it would\n"
" be possible to override methods inherited from python classes because\n"
" unbound methods gotten from Python classes cannot be called with \n"
" extension class instances. \n"
},
{"__basicnew__",(PyCFunction)basicnew,
METH_VARARGS | METH_CLASS_METHOD,
"__basicnew__() -- return a new uninitialized instance"
},
{NULL, NULL} /* sentinel */
};
static PyObject *
initializeBaseExtensionClass(PyExtensionClass *self)
{
static PyMethodChain top = { ECI_methods, NULL };
PyMethodChain *chain;
PyObject *dict;
int abstract;
/* Is this an abstract, or at least a dataless, class? */
abstract=self->tp_basicsize == sizeof(PyPureMixinObject);
self->ob_type=(PyTypeObject*)&ECType;
Py_INCREF(self->ob_type);
UNLESS(dict=self->class_dictionary=getBaseDictionary(self)) return NULL;
if (self->tp_name)
{
PyObject *name;
UNLESS(name=PyString_FromString(self->tp_name)) goto err;
if (0 > PyMapping_SetItemString(dict,"__doc__",name)) goto err;
Py_DECREF(name);
}
else if (0 > PyMapping_SetItemString(dict,"__doc__",Py_None)) goto err;
if (&self->methods) chain=&(self->methods);
else chain=&top;
while (1)
{
PyMethodDef *ml = chain->methods;
for (; ml && ml->ml_name != NULL; ml++)
{
if (ml->ml_meth)
{
if (! PyMapping_HasKeyString(dict,ml->ml_name))
{
PyObject *m;
/* Note that we create a circular reference here.
I suppose that this isn't so bad, since this is
probably a static thing anyway. Still, it is a
bit troubling. Oh well.
*/
if (ml->ml_flags & METH_CLASS_METHOD)
{
UNLESS(m=newCMethod(
AsExtensionClass(self->ob_type), NULL,
ml->ml_name, ml->ml_meth,
ml->ml_flags, ml->ml_doc))
return NULL;
}
else
{
UNLESS(m=newCMethod(self, NULL, ml->ml_name, ml->ml_meth,
ml->ml_flags, ml->ml_doc))
return NULL;
if (abstract)
UNLESS_ASSIGN(m, newPMethod(self, m))
return NULL;
}
if (PyMapping_SetItemString(dict,ml->ml_name,m) < 0)
return NULL;
}
}
else if (ml->ml_doc && *(ml->ml_doc))
{
/* No actual meth, this is probably to hook a doc string
onto a special method. */
PyObject *m;
if ((m=PyMapping_GetItemString(dict,ml->ml_name)))
{
if (m->ob_type==&CMethodType)
((CMethod *)(m))->doc=ml->ml_doc;
}
else
PyErr_Clear();
}
}
if (chain == &top) break;
UNLESS(chain=chain->link) chain=&top;
}
return (PyObject*)self;
err:
Py_DECREF(dict);
return NULL;
}
static void
CCL_dealloc(PyExtensionClass *self)
{
#ifdef TRACE_DEALLOC
fprintf(stderr,"Deallocating %s\n", self->tp_name);
#endif
Py_XDECREF(self->class_dictionary);
if (self->bases)
{
/* If we are a subclass, then we strduped our name */
free(self->tp_name);
/* And we allocated our own protocol structures */
if (self->tp_as_number) free(self->tp_as_number);
if (self->tp_as_sequence) free(self->tp_as_sequence);
if (self->tp_as_mapping) free(self->tp_as_mapping);
Py_DECREF(self->bases);
}
if (((PyExtensionClass*)self->ob_type) != self) {
Py_XDECREF(self->ob_type);
}
PyMem_DEL(self);
}
static PyObject *
ExtensionClass_FindInstanceAttribute(PyObject *inst, PyObject *oname,
char *name)
{
/* Look up an attribute for an instance from:
The instance dictionary,
The class dictionary, or
The base objects.
*/
PyObject *r=0;
PyExtensionClass *self;
if (! name) return NULL;
self=(PyExtensionClass*)(inst->ob_type);
if (*name=='_' && name[1]=='_')
{
char *n=name+2;
if (*n == 'c' && strcmp(n,"class__")==0)
{
Py_INCREF(self);
return (PyObject*)self;
}
if (ClassHasInstDict(self) && *n=='d' && strcmp(n,"dict__")==0)
{
r = INSTANCE_DICT(inst);
Py_INCREF(r);
return r;
}
}
if (ClassHasInstDict(self))
{
r= INSTANCE_DICT(inst);
if ((r = PyObject_GetItem(r,oname)) && NeedsToBeBound(r))
{
ASSIGN(r, CallMethodO(r, py__of__, Build("(O)", inst), NULL));
UNLESS(r) return NULL;
}
}
UNLESS(r)
{
if (*name=='_' && name[1]=='_'
&&
( (name[2]=='b' && strcmp(name+2,"bases__")==0)
|| (name[2]=='d' && strcmp(name+2,"dict__")==0)
)
)
{
PyErr_SetObject(PyExc_AttributeError, oname);
return NULL;
}
PyErr_Clear();
UNLESS(r=CCL_getattr(self,oname,0)) return NULL;
/* We got something from our class, maybe its an unbound method. */
if (UnboundCMethod_Check(r))
ASSIGN(r,(PyObject*)bindCMethod((CMethod*)r,inst));
else if (UnboundPMethod_Check(r))
ASSIGN(r,bindPMethod((PMethod*)r,inst));
}
return r;
}
static PyObject *
EC_findiattrs(PyObject *self, char *name)
{
PyObject *s, *r;
UNLESS(s=PyString_FromString(name)) return NULL;
r=ExtensionClass_FindInstanceAttribute(self,s,name);
Py_DECREF(s);
return r;
}
static PyObject *
EC_findiattro(PyObject *self, PyObject *name)
{
return ExtensionClass_FindInstanceAttribute(self,name,
PyString_AsString(name));
}
static int
subclass_simple_setattr(PyObject *self, char *name, PyObject *v);
static PyObject *
CCL_getattr(PyExtensionClass *self, PyObject *oname, int look_super)
{
PyObject *r=0;
if (! look_super) r=PyObject_GetItem(self->class_dictionary,oname);
UNLESS(r)
{
if (self->bases)
{
int n, i;
PyObject *c;
n=PyTuple_Size(self->bases);
for (i=0; i < n; i++)
{
PyErr_Clear();
c=PyTuple_GET_ITEM(self->bases, i);
if (ExtensionClass_Check(c))
r=CCL_getattr(AsExtensionClass(c),oname,0);
else
r=PyObject_GetAttr(c,oname);
if (r) break;
}
}
UNLESS(r)
{
PyObject *t, *v, *tb;
PyErr_Fetch(&t,&v,&tb);
if (t==PyExc_KeyError && PyObject_Compare(v,oname) == 0)
{
Py_DECREF(t);
t=PyExc_AttributeError;
Py_INCREF(t);
}
PyErr_Restore(t,v,tb);
return NULL;
}
}
if (PyFunction_Check(r) || NeedsToBeBound(r))
ASSIGN(r,newPMethod(self,r));
else if (PyMethod_Check(r) && ! PyMethod_Self(r))
ASSIGN(r,newPMethod(self, PyMethod_Function(r)));
return r;
}
static PyObject *
CCL_reduce(PyExtensionClass *self, PyObject *args)
{
return PyString_FromString(self->tp_name);
}
PyObject *
CCL_getattro(PyExtensionClass *self, PyObject *name)
{
char *n, *nm=0;
PyObject *r;
if (PyString_Check(name) && (n=nm=PyString_AS_STRING((PyStringObject*)name)))
{
if (*n=='_' && *++n=='_')
{
switch (*++n)
{
case 's':
if (strcmp(n,"safe_for_unpickling__")==0)
return PyInt_FromLong(1);
break;
case 'n':
if (strcmp(n,"name__")==0)
return PyString_FromString(self->tp_name);
break;
case 'b':
if (strcmp(n,"bases__")==0)
{
if (self->bases)
{
Py_INCREF(self->bases);
return self->bases;
}
else
return PyTuple_New(0);
}
break;
case 'r':
if (strcmp(n,"reduce__")==0)
return newCMethod(self,(PyObject*)self,
"__reduce__",(PyCFunction)CCL_reduce,0,
"__reduce__() -- Reduce the class to a class name");
break;
case 'd':
if (strcmp(n,"dict__")==0)
{
Py_INCREF(self->class_dictionary);
return self->class_dictionary;
}
break;
case 'c':
if (strcmp(n,"class__")==0)
{
Py_INCREF(self->ob_type);
return OBJECT(self->ob_type);
}
break;
}
}
}
if ((r=CCL_getattr(self,name,0)))
{
if (UnboundCMethod_Check(r) && (AsCMethod(r)->flags & METH_CLASS_METHOD))
ASSIGN(r,(PyObject*)bindCMethod((CMethod*)r,OBJECT(self)));
}
return r;
}
static int
CCL_setattro(PyExtensionClass *self, PyObject *name, PyObject *v)
{
if (! v) return PyObject_DelItem(self->class_dictionary, name);
if (v && UnboundCMethod_Check(v) &&
! (self->class_flags & EXTENSIONCLASS_METHODHOOK_FLAG)
)
{
char *n;
PyNumberMethods *nm;
PySequenceMethods *s, *ms;
PyMappingMethods *m, *mm;
UNLESS(n=PyString_AsString(name)) return -1;
if (*n++=='_' && *n++=='_')
{
#define SET_SPECIAL(C,P) \
if (strcmp(n,#P "__")==0 \
&& AsCMethod(v)->meth==(PyCFunction)C ## _by_name \
&& Subclass_Check(self,AsCMethod(v)->type)) { \
self->tp_ ## C=AsCMethod(v)->type->tp_ ## C; \
return PyObject_SetItem(self->class_dictionary, name, v); }
/*
SET_SPECIAL(setattr,setattr);
SET_SPECIAL(setattro,setattr);
*/
SET_SPECIAL(compare,cmp);
SET_SPECIAL(hash,hash);
SET_SPECIAL(repr,repr);
SET_SPECIAL(call,call);
SET_SPECIAL(str,str);
#undef SET_SPECIAL
#define SET_SPECIAL(C,P) \
if (strcmp(n,#P "__")==0 \
&& AsCMethod(v)->meth==(PyCFunction)C ## _by_name \
&& Subclass_Check(self,AsCMethod(v)->type) \
&& (nm=self->tp_as_number)) { \
nm->nb_ ## C=AsCMethod(v)->type->tp_as_number->nb_ ## C; \
return PyObject_SetItem(self->class_dictionary, name, v); }
SET_SPECIAL(add,add);
SET_SPECIAL(subtract,sub);
SET_SPECIAL(multiply,mult);
SET_SPECIAL(divide,div);
SET_SPECIAL(remainder,mod);
SET_SPECIAL(power,pow);
SET_SPECIAL(divmod,divmod);
SET_SPECIAL(lshift,lshift);
SET_SPECIAL(rshift,rshift);
SET_SPECIAL(and,and);
SET_SPECIAL(or,or);
SET_SPECIAL(xor,xor);
SET_SPECIAL(coerce,coerce);
SET_SPECIAL(negative,neg);
SET_SPECIAL(positive,pos);
SET_SPECIAL(absolute,abs);
SET_SPECIAL(nonzero,nonzero);
SET_SPECIAL(invert,inv);
SET_SPECIAL(int,int);
SET_SPECIAL(long,long);
SET_SPECIAL(float,float);
SET_SPECIAL(oct,oct);
SET_SPECIAL(hex,hex);
#undef SET_SPECIAL
if (strcmp(n,"len__")==0
&& AsCMethod(v)->meth==(PyCFunction)length_by_name
&& Subclass_Check(self,AsCMethod(v)->type))
{
if ((s=self->tp_as_sequence) &&
(ms=AsCMethod(v)->type->tp_as_sequence) &&
ms->sq_length)
s->sq_length=ms->sq_length;
if ((m=self->tp_as_mapping) &&
(mm=AsCMethod(v)->type->tp_as_mapping) &&
mm->mp_length)
m->mp_length=mm->mp_length;
return PyObject_SetItem(self->class_dictionary, name, v);
}
if (strcmp(n,"getitem__")==0
&& AsCMethod(v)->meth==(PyCFunction)getitem_by_name
&& Subclass_Check(self,AsCMethod(v)->type))
{
if ((s=self->tp_as_sequence) &&
(ms=AsCMethod(v)->type->tp_as_sequence) &&
ms->sq_item)
s->sq_item=ms->sq_item;
if ((m=self->tp_as_mapping) &&
(mm=AsCMethod(v)->type->tp_as_mapping) &&
mm->mp_subscript)
m->mp_subscript=mm->mp_subscript;
return PyObject_SetItem(self->class_dictionary, name, v);
}
if (strcmp(n,"setitem__")==0 &&
AsCMethod(v)->meth==(PyCFunction)setitem_by_name
&& Subclass_Check(self,AsCMethod(v)->type))
{
if ((s=self->tp_as_sequence) &&
(ms=AsCMethod(v)->type->tp_as_sequence) &&
ms->sq_ass_item)
s->sq_ass_item=ms->sq_ass_item;
if ((m=self->tp_as_mapping) &&
(mm=AsCMethod(v)->type->tp_as_mapping) &&
mm->mp_ass_subscript)
m->mp_ass_subscript=mm->mp_ass_subscript;
return PyObject_SetItem(self->class_dictionary, name, v);
}
#define SET_SPECIAL(C,P) \
if (strcmp(n,#P "__")==0 \
&& AsCMethod(v)->meth==(PyCFunction)C ## _by_name \
&& Subclass_Check(self,AsCMethod(v)->type) \
&& (s=self->tp_as_sequence)) { \
s->sq_ ## C=AsCMethod(v)->type->tp_as_sequence->sq_ ## C; \
return PyObject_SetItem(self->class_dictionary, name, v); }
SET_SPECIAL(slice,getslice);
SET_SPECIAL(ass_slice,setslice);
SET_SPECIAL(concat,concat);
SET_SPECIAL(repeat,repeat);
#undef SET_SPECIAL
}
}
return PyObject_SetItem(self->class_dictionary, name, v);
}
static PyObject *
CCL_call(PyExtensionClass *self, PyObject *arg, PyObject *kw)
{
PyObject *inst=0, *init=0, *args=0;
typedef struct { PyObject_VAR_HEAD } PyVarObject__;
if (! self->tp_dealloc)
{
PyErr_SetString(PyExc_TypeError,
"Attempt to create instance of an abstract type");
return NULL;
}
if (self->tp_itemsize)
{
/* We have a variable-sized object, we need to get it's size */
PyObject *var_size;
int size;
if ((var_size=CCL_getattr(self,py__var_size__, 0)))
{
UNLESS_ASSIGN(var_size,PyObject_CallObject(var_size,arg))
return NULL;
size=PyInt_AsLong(var_size);
if (PyErr_Occurred()) return NULL;
}
else
{
UNLESS(-1 != (size=PyTuple_Size(arg))) return NULL;
if (size > 0)
{
var_size=PyTuple_GET_ITEM(arg, 0);
if (PyInt_Check(var_size))
size=PyInt_AsLong(var_size);
else
size=-1;
}
else
size=-1;
if (size < 0)
{
PyErr_SetString(PyExc_TypeError,
"object size expected as first argument");
return NULL;
}
}
UNLESS(inst=PyObject_NEW_VAR(PyObject,(PyTypeObject *)self, size))
return NULL;
memset(inst,0,self->tp_basicsize+self->tp_itemsize*size);
((PyVarObject__*)inst)->ob_size=size;
}
else
{
UNLESS(inst=PyObject_NEW(PyObject,(PyTypeObject *)self)) return NULL;
memset(inst,0,self->tp_basicsize);
}
inst->ob_refcnt=1;
inst->ob_type=(PyTypeObject *)self;
Py_INCREF(self);
if (ClassHasInstDict(self))
UNLESS(INSTANCE_DICT(inst)=PyDict_New()) goto err;
if ((init=CCL_getattr(self,py__init__,0)))
{
UNLESS(args=Py_BuildValue("(O)",inst)) goto err;
if (arg) UNLESS_ASSIGN(args,PySequence_Concat(args,arg)) goto err;
UNLESS_ASSIGN(args,PyEval_CallObjectWithKeywords(init,args,kw)) goto err;
Py_DECREF(args);
Py_DECREF(init);
}
else PyErr_Clear();
if (self->bases && subclass_watcher &&
! PyObject_CallMethod(subclass_watcher,"created","O",inst))
PyErr_Clear();
return inst;
err:
Py_DECREF(inst);
Py_XDECREF(init);
Py_XDECREF(args);
return NULL;
}
static PyObject *
CCL_repr(PyExtensionClass *self)
{
char p[128], *pp;
PyObject *m;
if ((m=PyObject_GetAttr(OBJECT(self), py__module__)))
{
if (! PyObject_IsTrue(m))
{
Py_DECREF(m);
m=0;
}
}
else PyErr_Clear();
sprintf(p,"%p",self);
if (*p=='0' && p[1]=='x') pp=p+2;
else pp=p;
if (m) ASSIGN(m, JimString_Build("<extension class %s.%s at %s>","Oss",
m, self->tp_name, pp));
else m= JimString_Build("<extension class %s at %s>","ss",
self->tp_name, pp);
return m;
}
static PyTypeObject ECTypeType = {
PyObject_HEAD_INIT(NULL)
0, /*ob_size*/
"ExtensionClass Class", /*tp_name*/
sizeof(PyExtensionClass), /*tp_basicsize*/
0, /*tp_itemsize*/
/* methods */
(destructor)CCL_dealloc, /*tp_dealloc*/
(printfunc)0, /*tp_print*/
(getattrfunc)0, /*tp_getattr*/
(setattrfunc)0, /*tp_setattr*/
(cmpfunc)0, /*tp_compare*/
(reprfunc)CCL_repr, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
(hashfunc)0, /*tp_hash*/
(ternaryfunc)CCL_call, /*tp_call*/
(reprfunc)0, /*tp_str*/
(getattrofunc)CCL_getattro, /*tp_getattr with object key*/
(setattrofunc)CCL_setattro, /*tp_setattr with object key*/
/* Space for future expansion */
0L,0L,
"Class of C classes" /* Documentation string */
};
/* End of code for ExtensionClass objects */
/* -------------------------------------------------------- */
/* subclassing code: */
static PyObject *
subclass_getspecial(PyObject *inst, PyObject *oname)
{
PyObject *r=0;
PyExtensionClass *self;
self=(PyExtensionClass*)(inst->ob_type);
if (HasInstDict(inst))
{
r= INSTANCE_DICT(inst);
r = PyObject_GetItem(r,oname);
UNLESS(r)
{
PyErr_Clear();
r=CCL_getattr(self,oname,0);
}
}
else r=CCL_getattr(self,oname,0);
return r;
}
static PyObject *
subclass_getattro(PyObject *self, PyObject *name)
{
PyObject *r;
if (! name) return NULL;
UNLESS(r=EC_findiattro(self,name))
{
PyErr_Clear();
r=EC_findiattro(self,py__getattr__);
if (r) ASSIGN(r,PyObject_CallFunction(r,"O",name));
if (r && NeedsToBeBound(r))
ASSIGN(r, CallMethodO(r, py__of__, Build("(O)", self), NULL));
}
return r;
}
static int
subclass_simple_setattro(PyObject *self, PyObject *name, PyObject *v)
{
if (! HasInstDict(self))
{
PyErr_SetObject(PyExc_AttributeError, name);
return -1;
}
if (v)
return PyDict_SetItem(INSTANCE_DICT(self),name,v);
else
return PyDict_DelItem(INSTANCE_DICT(self),name);
}
static int
subclass_simple_setattr(PyObject *self, char *name, PyObject *v)
{
if (! HasInstDict(self))
{
PyErr_SetString(PyExc_AttributeError, name);
return -1;
}
if (v)
return PyDict_SetItemString(INSTANCE_DICT(self),name,v);
else
return PyDict_DelItemString(INSTANCE_DICT(self),name);
}
static int
subclass_setattr(PyObject *self, PyObject *oname, char *name, PyObject *v)
{
PyObject *m=0, *et, *ev, *etb;
if (! name) return -1;
if (!v && (m=subclass_getspecial(self,py__delattr__)))
{
if (UnboundEMethod_Check(m))
{
UNLESS_ASSIGN(m,PyObject_CallFunction(m,"OO",self,oname)) return -1;
}
else UNLESS_ASSIGN(m,PyObject_CallFunction(m,"O",oname)) return -1;
Py_DECREF(m);
return 0;
}
UNLESS(m=subclass_getspecial(self,py__setattr__))
goto default_setattr;
if (UnboundCMethod_Check(m)
&& AsCMethod(m)->meth==(PyCFunction)setattr_by_name
&& SubclassInstance_Check(self,AsCMethod(m)->type))
{
UNLESS(-1 != AsCMethod(m)->type->tp_setattr(self,name,v))
goto dictionary_setattr;
return 0;
}
else
if (UnboundCMethod_Check(m)
&& AsCMethod(m)->meth==(PyCFunction)setattro_by_name
&& SubclassInstance_Check(self,AsCMethod(m)->type))
{
UNLESS(-1 != AsCMethod(m)->type->tp_setattro(self,oname,v))
goto dictionary_setattr;
return 0;
}
if (! v) goto default_setattr;
if (UnboundEMethod_Check(m))
{
UNLESS_ASSIGN(m,PyObject_CallFunction(m,"OOO",self,oname,v)) return -1;
}
else UNLESS_ASSIGN(m,PyObject_CallFunction(m,"OO",oname,v)) return -1;
Py_DECREF(m);
return 0;
dictionary_setattr:
Py_XDECREF(m);
PyErr_Fetch(&et, &ev, &etb);
if (et==PyExc_AttributeError)
{
char *s;
if (ev && PyString_Check(ev) && (s=PyString_AsString(ev)) &&
strcmp(s,name)==0)
{
Py_XDECREF(et);
Py_XDECREF(ev);
Py_XDECREF(etb);
et=0;
}
}
if (et)
{
PyErr_Restore(et,ev,etb);
return -1;
}
default_setattr:
PyErr_Clear();
return subclass_simple_setattro(self, oname, v);
}
static int
subclass_setattro(PyObject *self, PyObject *name, PyObject *v)
{
return subclass_setattr(self,name,PyString_AsString(name),v);
}
static int
subclass_compare(PyObject *self, PyObject *v)
{
PyObject *m;
long r;
UNLESS(m=subclass_getspecial(self,py__cmp__))
{
PyErr_Clear();
return self-v;
}
if (UnboundCMethod_Check(m)
&& AsCMethod(m)->meth==(PyCFunction)compare_by_name
&& SubclassInstance_Check(self,AsCMethod(m)->type)
&& ! HasMethodHook(self))
r=AsCMethod(m)->type->tp_compare(self,v);
else
{
if (UnboundEMethod_Check(m))
{
UNLESS_ASSIGN(m,PyObject_CallFunction(m,"OO",self,v))
return -1;
}
else UNLESS_ASSIGN(m,PyObject_CallFunction(m,"O",v)) return -1;
r=PyInt_AsLong(m);
}
Py_DECREF(m);
return r;
}
static long
subclass_hash(PyObject *self)
{
PyObject *m;
long r;
UNLESS(m=subclass_getspecial(self,py__hash__)) return -1;
if (UnboundCMethod_Check(m)
&& AsCMethod(m)->meth==(PyCFunction)hash_by_name
&& SubclassInstance_Check(self,AsCMethod(m)->type)
&& ! HasMethodHook(self))
r=AsCMethod(m)->type->tp_hash(self);
else
{
if (UnboundEMethod_Check(m))
{
UNLESS_ASSIGN(m,PyObject_CallFunction(m,"O",self))
return -1;
}
else UNLESS_ASSIGN(m,PyObject_CallFunction(m,"")) return -1;
r=PyInt_AsLong(m);
}
Py_DECREF(m);
return r;
}
static PyObject *
default_subclass_repr(PyObject *self)
{
char p[128], *pp;
PyErr_Clear();
sprintf(p,"%p",self);
if (*p=='0' && p[1]=='x') pp=p+2;
else pp=p;
return JimString_Build("<%s instance at %s>","ss",
self->ob_type->tp_name, pp);
}
static PyObject *
subclass_repr(PyObject *self)
{
PyObject *m;
UNLESS(m=subclass_getspecial(self,py__repr__))
return default_subclass_repr(self);
if (UnboundCMethod_Check(m)
&& AsCMethod(m)->meth==(PyCFunction)repr_by_name
&& SubclassInstance_Check(self,AsCMethod(m)->type)
&& ! HasMethodHook(self))
ASSIGN(m,AsCMethod(m)->type->tp_repr(self));
else if (UnboundEMethod_Check(m))
ASSIGN(m,PyObject_CallFunction(m,"O",self));
else
ASSIGN(m,PyObject_CallFunction(m,""));
return m;
}
static PyObject *
subclass_call(PyObject *self, PyObject *args, PyObject *kw)
{
PyObject *m;
UNLESS(m=subclass_getspecial(self,py__call__)) return NULL;
if (UnboundCMethod_Check(m) && AsCMethod(m)->meth==(PyCFunction)call_by_name
&& SubclassInstance_Check(self,AsCMethod(m)->type)
&& ! HasMethodHook(self))
ASSIGN(m,AsCMethod(m)->type->tp_call(self,args,kw));
else
{
if (UnboundEMethod_Check(m))
{
PyObject *a;
a=Py_BuildValue("(O)",self);
if (a) ASSIGN(a,PySequence_Concat(a,args));
if (a) ASSIGN(m,PyEval_CallObjectWithKeywords(m,a,kw));
else ASSIGN(m,NULL);
Py_XDECREF(a);
}
else
ASSIGN(m,PyEval_CallObjectWithKeywords(m,args,kw));
}
return m;
}
static PyObject *
subclass_str(PyObject *self)
{
PyObject *m;
UNLESS(m=subclass_getspecial(self,py__str__))
{
PyErr_Clear();
return subclass_repr(self);
}
if (UnboundCMethod_Check(m)
&& AsCMethod(m)->meth==(PyCFunction)str_by_name
&& SubclassInstance_Check(self,AsCMethod(m)->type)
&& ! HasMethodHook(self))
ASSIGN(m,AsCMethod(m)->type->tp_str(self));
else if (UnboundEMethod_Check(m))
ASSIGN(m,PyObject_CallFunction(m,"O",self));
else
ASSIGN(m,PyObject_CallFunction(m,""));
return m;
}
#define BINSUB(M,N,A) \
static PyObject * \
subclass_ ## M(PyObject *self, PyObject *v) \
{ \
PyObject *m; \
UNLESS(m=subclass_getspecial(self,py__ ## N ## __)) return NULL; \
if (UnboundCMethod_Check(m) \
&& AsCMethod(m)->meth==(PyCFunction)M ## _by_name \
&& SubclassInstance_Check(self,AsCMethod(m)->type) \
&& ! HasMethodHook(self)) \
ASSIGN(m,AsCMethod(m)->type->tp_as_number->nb_ ## M(self,v)); \
else if (UnboundEMethod_Check(m)) \
ASSIGN(m,PyObject_CallFunction(m,"OO",self,v)); \
else \
ASSIGN(m,PyObject_CallFunction(m,"O",v)); \
return m; \
}
static PyObject *
subclass_add(PyObject *self, PyObject *v)
{
PyObject *m;
UNLESS(m=subclass_getspecial(self,py__add__)) return NULL;
if (UnboundCMethod_Check(m)
&& AsCMethod(m)->meth==(PyCFunction)concat_by_name
&& SubclassInstance_Check(self,AsCMethod(m)->type)
&& ! HasMethodHook(self))
ASSIGN(m,AsCMethod(m)->type->tp_as_sequence->sq_concat(self,v));
else if (UnboundCMethod_Check(m)
&& AsCMethod(m)->meth==(PyCFunction)add_by_name
&& SubclassInstance_Check(self,AsCMethod(m)->type)
&& ! HasMethodHook(self))
ASSIGN(m,AsCMethod(m)->type->tp_as_number->nb_add(self,v));
else if (UnboundEMethod_Check(m))
ASSIGN(m,PyObject_CallFunction(m,"OO",self,v));
else
ASSIGN(m,PyObject_CallFunction(m,"O",v));
return m;
}
BINSUB(subtract,sub,Subtract)
static PyObject *
subclass_multiply(PyObject *self, PyObject *v)
{
PyObject *m;
UNLESS(m=subclass_getspecial(self,py__mul__)) return NULL;
if (UnboundCMethod_Check(m)
&& AsCMethod(m)->meth==(PyCFunction)repeat_by_name
&& SubclassInstance_Check(self,AsCMethod(m)->type)
&& ! HasMethodHook(self))
{
int i;
i=PyInt_AsLong(v);
if (i==-1 && PyErr_Occurred()) return NULL;
ASSIGN(m,AsCMethod(m)->type->tp_as_sequence->sq_repeat(self,i));
}
else if (UnboundCMethod_Check(m)
&& AsCMethod(m)->meth==(PyCFunction)multiply_by_name
&& SubclassInstance_Check(self,AsCMethod(m)->type)
&& ! HasMethodHook(self))
ASSIGN(m,AsCMethod(m)->type->tp_as_number->nb_multiply(self,v));
else if (UnboundEMethod_Check(m))
ASSIGN(m,PyObject_CallFunction(m,"OO",self,v));
else
ASSIGN(m,PyObject_CallFunction(m,"O",v));
return m;
}
BINSUB(divide,div,Divide)
BINSUB(remainder,mod,Remainder)
static PyObject *
subclass_power(PyObject *self, PyObject *v, PyObject *w)
{
PyObject *m;
UNLESS(m=subclass_getspecial(self,py__pow__)) return NULL;
if (UnboundCMethod_Check(m)
&& AsCMethod(m)->meth==(PyCFunction)power_by_name
&& SubclassInstance_Check(self,AsCMethod(m)->type)
&& ! HasMethodHook(self))
ASSIGN(m,AsCMethod(m)->type->tp_as_number->nb_power(self,v,w));
else if (UnboundEMethod_Check(m))
ASSIGN(m,PyObject_CallFunction(m,"OOO",self,v,w));
else
ASSIGN(m,PyObject_CallFunction(m,"OO",v,w));
return m;
}
BINSUB(divmod,divmod,Divmod)
BINSUB(lshift,lshift,Lshift)
BINSUB(rshift,rshift,Rshift)
BINSUB(and,and,And)
BINSUB(or,or,Or)
BINSUB(xor,xor,Xor)
static int
subclass_coerce(PyObject **self, PyObject **v)
{
PyObject *m;
int r;
UNLESS(m=subclass_getspecial(*self,py__coerce__))
{
PyErr_Clear();
Py_INCREF(*self);
Py_INCREF(*v);
return 0;
}
if (UnboundCMethod_Check(m)
&& AsCMethod(m)->meth==(PyCFunction)coerce_by_name
&& SubclassInstance_Check(*self,AsCMethod(m)->type)
&& ! HasMethodHook(*self))
r=AsCMethod(m)->type->tp_as_number->nb_coerce(self,v);
else
{
if (UnboundEMethod_Check(m))
ASSIGN(m,PyObject_CallFunction(m,"OO",*self,*v));
else
ASSIGN(m,PyObject_CallFunction(m,"O",*v));
UNLESS (m) return -1;
if (m==Py_None) r=-1;
else
{
if (PyArg_ParseTuple(m,"OO", self, v))
{
Py_INCREF(*self);
Py_INCREF(*v);
r=0;
}
else r=-1;
}
}
Py_DECREF(m);
return r;
}
#define UNSUB(M,N) \
static PyObject * \
subclass_ ## M(PyObject *self) \
{ \
PyObject *m; \
UNLESS(m=subclass_getspecial(self,py__ ## N ## __)) return NULL; \
if (UnboundCMethod_Check(m) \
&& AsCMethod(m)->meth==(PyCFunction)M ## _by_name \
&& SubclassInstance_Check(self,AsCMethod(m)->type) \
&& ! HasMethodHook(self)) \
ASSIGN(m,AsCMethod(m)->type->tp_as_number->nb_ ## M(self)); \
else if (UnboundEMethod_Check(m)) \
ASSIGN(m,PyObject_CallFunction(m,"O",self)); \
else \
ASSIGN(m,PyObject_CallFunction(m,"")); \
return m; \
}
UNSUB(negative, neg)
UNSUB(positive, pos)
UNSUB(absolute, abs)
static int
subclass_nonzero(PyObject *self)
{
PyObject *m;
long r;
UNLESS(m=subclass_getspecial(self,py__nonzero__))
{ /* We are being asked is we are true
Check out len, and if that fails, say we are true.
*/
PyErr_Clear();
UNLESS(m=subclass_getspecial(self,py__len__))
{
PyErr_Clear();
return 1;
}
}
if (UnboundCMethod_Check(m)
&& AsCMethod(m)->meth==(PyCFunction)nonzero_by_name
&& SubclassInstance_Check(self,AsCMethod(m)->type)
&& ! HasMethodHook(self))
r=AsCMethod(m)->type->tp_as_number->nb_nonzero(self);
else
{
if (UnboundEMethod_Check(m))
{
UNLESS_ASSIGN(m,PyObject_CallFunction(m,"O",self))
return -1;
}
else UNLESS_ASSIGN(m,PyObject_CallFunction(m,"")) return -1;
r=PyInt_AsLong(m);
}
Py_DECREF(m);
return r;
}
UNSUB(invert, inv)
UNSUB(int, int)
UNSUB(long, long)
UNSUB(float, float)
UNSUB(oct, oct)
UNSUB(hex, hex)
#undef UNSUB
#undef BINSUB
static PyNumberMethods subclass_as_number = {
(binaryfunc)subclass_add, /*nb_add*/
(binaryfunc)subclass_subtract, /*nb_subtract*/
(binaryfunc)subclass_multiply, /*nb_multiply*/
(binaryfunc)subclass_divide, /*nb_divide*/
(binaryfunc)subclass_remainder, /*nb_remainder*/
(binaryfunc)subclass_divmod, /*nb_divmod*/
(ternaryfunc)subclass_power, /*nb_power*/
(unaryfunc)subclass_negative, /*nb_negative*/
(unaryfunc)subclass_positive, /*nb_positive*/
(unaryfunc)subclass_absolute, /*nb_absolute*/
(inquiry)subclass_nonzero, /*nb_nonzero*/
(unaryfunc)subclass_invert, /*nb_invert*/
(binaryfunc)subclass_lshift, /*nb_lshift*/
(binaryfunc)subclass_rshift, /*nb_rshift*/
(binaryfunc)subclass_and, /*nb_and*/
(binaryfunc)subclass_xor, /*nb_xor*/
(binaryfunc)subclass_or, /*nb_or*/
(coercion)subclass_coerce, /*nb_coerce*/
(unaryfunc)subclass_int, /*nb_int*/
(unaryfunc)subclass_long, /*nb_long*/
(unaryfunc)subclass_float, /*nb_float*/
(unaryfunc)subclass_oct, /*nb_oct*/
(unaryfunc)subclass_hex, /*nb_hex*/
};
static long
subclass_length(PyObject *self)
{
PyObject *m;
long r;
PyExtensionClass *t;
UNLESS(m=subclass_getspecial(self,py__len__))
{
/* Hm. Maybe we are being checked to see if we are true.
Check to see if we have a __getitem__. If we don't, then
answer that we are true.
*/
PyErr_Clear();
if ((m=subclass_getspecial(self,py__getitem__)))
{
/* Hm, we have getitem, must be error */
Py_DECREF(m);
PyErr_SetObject(PyExc_AttributeError, py__len__);
return -1;
}
PyErr_Clear();
return subclass_nonzero(self);
}
if (UnboundCMethod_Check(m)
&& AsCMethod(m)->meth==(PyCFunction)length_by_name
&& SubclassInstance_Check(self,AsCMethod(m)->type)
&& ! HasMethodHook(self))
{
t=(PyExtensionClass*)AsCMethod(m)->type;
Py_DECREF(m);
if (t->tp_as_sequence)
return t->tp_as_sequence->sq_length(self);
else
return t->tp_as_mapping->mp_length(self);
}
if (UnboundEMethod_Check(m))
{
UNLESS_ASSIGN(m,PyObject_CallFunction(m,"O",self)) return -1;
}
else UNLESS_ASSIGN(m,PyObject_CallFunction(m,"")) return -1;
r=PyInt_AsLong(m);
Py_DECREF(m);
return r;
}
static PyObject *
subclass_item(PyObject *self, int index)
{
PyObject *m;
PyExtensionClass *t;
UNLESS(m=subclass_getspecial(self,py__getitem__)) return NULL;
if (UnboundCMethod_Check(m)
&& AsCMethod(m)->meth==(PyCFunction)getitem_by_name
&& SubclassInstance_Check(self,AsCMethod(m)->type)
&& ! HasMethodHook(self))
{
t=(PyExtensionClass*)AsCMethod(m)->type;
if (t->tp_as_sequence && t->tp_as_sequence->sq_item)
{
Py_DECREF(m);
return t->tp_as_sequence->sq_item(self,index);
}
}
if (UnboundEMethod_Check(m))
ASSIGN(m,PyObject_CallFunction(m,"Oi",self,index));
else
ASSIGN(m,PyObject_CallFunction(m,"i",index));
return m;
}
static PyObject *
subclass_slice(PyObject *self, int i1, int i2)
{
PyObject *m;
UNLESS(m=subclass_getspecial(self,py__getslice__)) return NULL;
if (UnboundCMethod_Check(m)
&& AsCMethod(m)->meth==(PyCFunction)slice_by_name
&& SubclassInstance_Check(self,AsCMethod(m)->type)
&& ! HasMethodHook(self))
ASSIGN(m,AsCMethod(m)->type->tp_as_sequence->sq_slice(self,i1,i2));
else if (UnboundEMethod_Check(m))
ASSIGN(m,PyObject_CallFunction(m,"Oii",self,i1,i2));
else
ASSIGN(m,PyObject_CallFunction(m,"ii",i1,i2));
return m;
}
static long
subclass_ass_item(PyObject *self, int index, PyObject *v)
{
PyObject *m;
PyExtensionClass *t;
if (! v && (m=subclass_getspecial(self,py__delitem__)))
{
if (UnboundEMethod_Check(m))
{
UNLESS_ASSIGN(m,PyObject_CallFunction(m,"Oi",self,index)) return -1;
}
else UNLESS_ASSIGN(m,PyObject_CallFunction(m,"i",index)) return -1;
Py_DECREF(m);
return 0;
}
UNLESS(m=subclass_getspecial(self,py__setitem__)) return -1;
if (UnboundCMethod_Check(m) &&
AsCMethod(m)->meth==(PyCFunction)setitem_by_name
&& SubclassInstance_Check(self,AsCMethod(m)->type)
&& ! HasMethodHook(self))
{
t=(PyExtensionClass*)AsCMethod(m)->type;
if (t->tp_as_sequence && t->tp_as_sequence->sq_ass_item)
{
Py_DECREF(m);
return t->tp_as_sequence->sq_ass_item(self,index,v);
}
}
if (! v)
{
PyErr_SetObject(PyExc_AttributeError, py__delitem__);
return -1;
}
if (UnboundEMethod_Check(m))
{
UNLESS_ASSIGN(m,PyObject_CallFunction(m,"OiO",self,index,v)) return -1;
}
else UNLESS_ASSIGN(m,PyObject_CallFunction(m,"iO",index,v)) return -1;
Py_DECREF(m);
return 0;
}
static int
subclass_ass_slice(PyObject *self, int i1, int i2, PyObject *v)
{
PyObject *m;
long r;
if (! v && (m=subclass_getspecial(self,py__delslice__)))
{
if (UnboundEMethod_Check(m))
{
UNLESS_ASSIGN(m,PyObject_CallFunction(m,"Oii",self,i1,i2)) return -1;
}
else UNLESS_ASSIGN(m,PyObject_CallFunction(m,"ii",i1,i2)) return -1;
Py_DECREF(m);
return 0;
}
UNLESS(m=subclass_getspecial(self,py__setslice__)) return -1;
if (UnboundCMethod_Check(m) &&
AsCMethod(m)->meth==(PyCFunction)ass_slice_by_name
&& SubclassInstance_Check(self,AsCMethod(m)->type)
&& ! HasMethodHook(self))
{
r=AsCMethod(m)->type->tp_as_sequence->sq_ass_slice(self,i1,i2,v);
Py_DECREF(m);
return r;
}
if (! v)
{
PyErr_SetObject(PyExc_AttributeError, py__delslice__);
return -1;
}
if (UnboundEMethod_Check(m))
{
UNLESS_ASSIGN(m,PyObject_CallFunction(m,"OiiO",self,i1,i2,v))
return -1;
}
else UNLESS_ASSIGN(m,PyObject_CallFunction(m,"iiO",i1,i2,v)) return -1;
Py_DECREF(m);
return 0;
}
static PyObject *
subclass_repeat(PyObject *self, int v)
{
PyObject *m;
UNLESS(m=subclass_getspecial(self,py__mul__)) return NULL;
if (UnboundCMethod_Check(m)
&& AsCMethod(m)->meth==(PyCFunction)repeat_by_name
&& SubclassInstance_Check(self,AsCMethod(m)->type)
&& ! HasMethodHook(self))
ASSIGN(m,AsCMethod(m)->type->tp_as_sequence->sq_repeat(self,v));
else if (UnboundEMethod_Check(m))
ASSIGN(m,PyObject_CallFunction(m,"Oi",self,v));
else
ASSIGN(m,PyObject_CallFunction(m,"i",v));
return m;
}
PySequenceMethods subclass_as_sequence = {
(inquiry)subclass_length, /*sq_length*/
(binaryfunc)subclass_add, /*sq_concat*/
(intargfunc)subclass_repeat, /*sq_repeat*/
(intargfunc)subclass_item, /*sq_item*/
(intintargfunc)subclass_slice, /*sq_slice*/
(intobjargproc)subclass_ass_item, /*sq_ass_item*/
(intintobjargproc)subclass_ass_slice, /*sq_ass_slice*/
};
static PyObject *
subclass_subscript(PyObject *self, PyObject *key)
{
PyObject *m;
PyExtensionClass *t;
UNLESS(m=subclass_getspecial(self,py__getitem__)) return NULL;
if (UnboundCMethod_Check(m) &&
AsCMethod(m)->meth==(PyCFunction)getitem_by_name
&& SubclassInstance_Check(self,AsCMethod(m)->type)
&& ! HasMethodHook(self))
{
t=(PyExtensionClass*)AsCMethod(m)->type;
if (t->tp_as_mapping && t->tp_as_mapping->mp_subscript)
{
Py_DECREF(m);
return t->tp_as_mapping->mp_subscript(self,key);
}
else if (t->tp_as_sequence && t->tp_as_sequence->sq_item)
{
int i, l;
Py_DECREF(m);
UNLESS(PyInt_Check(key))
{
PyErr_SetString(PyExc_TypeError, "sequence subscript not int");
return NULL;
}
i=PyInt_AsLong(key);
if (i < 0)
{
if ((l=PyObject_Length(self)) < 0) return NULL;
i+=l;
}
return t->tp_as_sequence->sq_item(self,i);
}
}
if (UnboundEMethod_Check(m))
ASSIGN(m,PyObject_CallFunction(m,"OO",self,key));
else
ASSIGN(m,PyObject_CallFunction(m,"O",key));
return m;
}
static long
subclass_ass_subscript(PyObject *self, PyObject *index, PyObject *v)
{
PyObject *m;
PyExtensionClass *t;
if (! v && (m=subclass_getspecial(self,py__delitem__)))
{
if (UnboundEMethod_Check(m))
{
UNLESS_ASSIGN(m,PyObject_CallFunction(m,"OO",self,index)) return -1;
}
else UNLESS_ASSIGN(m,PyObject_CallFunction(m,"O",index)) return -1;
Py_DECREF(m);
return 0;
}
UNLESS(m=subclass_getspecial(self,py__setitem__)) return -1;
if (UnboundCMethod_Check(m) &&
AsCMethod(m)->meth==(PyCFunction)setitem_by_name
&& SubclassInstance_Check(self,AsCMethod(m)->type)
&& ! HasMethodHook(self))
{
t=(PyExtensionClass*)AsCMethod(m)->type;
if (t->tp_as_mapping && t->tp_as_mapping->mp_ass_subscript)
{
Py_DECREF(m);
return t->tp_as_mapping->mp_ass_subscript(self,index,v);
}
else if (t->tp_as_sequence && t->tp_as_sequence->sq_ass_item)
{
int i, l;
Py_DECREF(m);
UNLESS(PyInt_Check(index))
{
PyErr_SetString(PyExc_TypeError, "sequence subscript not int");
return -1;
}
i=PyInt_AsLong(index);
if (i < 0)
{
if ((l=PyObject_Length(self)) < 0) return -1;
i+=l;
}
return t->tp_as_sequence->sq_ass_item(self,i,v);
}
}
if (! v)
{
PyErr_SetObject(PyExc_AttributeError, py__delitem__);
return -1;
}
if (UnboundEMethod_Check(m))
{
UNLESS_ASSIGN(m,PyObject_CallFunction(m,"OOO",self,index,v)) return -1;
}
else UNLESS_ASSIGN(m,PyObject_CallFunction(m,"OO",index,v)) return -1;
Py_DECREF(m);
return 0;
}
PyMappingMethods subclass_as_mapping = {
(inquiry)subclass_length, /*mp_length*/
(binaryfunc)subclass_subscript, /*mp_subscript*/
(objobjargproc)subclass_ass_subscript, /*mp_ass_subscript*/
};
static int
dealloc_base(PyObject *inst, PyExtensionClass* self)
{
int i,l;
PyObject *t;
l=PyTuple_Size(self->bases);
for (i=0; i < l; i++)
{
t=PyTuple_GET_ITEM(self->bases, i);
if (ExtensionClass_Check(t))
{
if (AsExtensionClass(t)->bases)
{
if (dealloc_base(inst,AsExtensionClass(t))) return 1;
}
else
{
if (((PyExtensionClass*)t)->tp_dealloc)
{
((PyExtensionClass*)t)->tp_dealloc(inst);
return 1;
}
}
}
}
return 0;
}
static void
subclass_dealloc(PyObject *self)
{
PyObject *m, *t, *v, *tb;
int base_dealloced;
#ifdef TRACE_DEALLOC
fprintf(stderr,"Deallocating a %s\n", self->ob_type->tp_name);
#endif
PyErr_Fetch(&t,&v,&tb);
Py_INCREF(self); /* Give us a new lease on life */
if (subclass_watcher &&
! PyObject_CallMethod(subclass_watcher,"destroying","O",self))
PyErr_Clear();
if ((m=subclass_getspecial(self,py__del__)))
{
if (UnboundEMethod_Check(m))
ASSIGN(m,PyObject_CallFunction(m,"O",self));
else
ASSIGN(m,PyObject_CallFunction(m,""));
Py_XDECREF(m);
}
PyErr_Clear();
if (--self->ob_refcnt > 0)
{
PyErr_Restore(t,v,tb);
return; /* we added a reference; don't delete now */
}
if (HasInstDict(self)) {
Py_XDECREF(INSTANCE_DICT(self));
}
/* See if there was a dealloc handler in a (C) base class.
If there was, then it deallocates the object and we
get a true value back.
Note that if there *is* a base class dealloc, then
*it* should decref the class.
*/
base_dealloced=dealloc_base(self,(PyExtensionClass*)self->ob_type);
/* We only deallocate ourselves if a base class didn't */
UNLESS(base_dealloced)
{
Py_DECREF(self->ob_type);
PyMem_DEL(self);
}
PyErr_Restore(t,v,tb);
}
static void
datafull_baseclassesf(PyExtensionClass *type, PyObject **c1, PyObject **c2)
{
/* Find the number of classes that have data and return them.
There should be no more than one.
*/
int l, i;
PyObject *base;
l=PyTuple_Size(type->bases);
for (i=0; i < l && ! (*c1 && *c2); i++)
{
base=PyTuple_GET_ITEM(type->bases, i);
if (ExtensionClass_Check(base))
{
if (AsExtensionClass(base)->bases)
datafull_baseclassesf(AsExtensionClass(base),c1,c2);
else
{
if (AsExtensionClass(base)->tp_basicsize >
sizeof(PyPureMixinObject) ||
AsExtensionClass(base)->tp_itemsize > 0)
{
if (! *c1)
*c1=base;
else if (*c1 != base)
*c2=base;
}
}
}
}
}
static int
datafull_baseclasses(PyExtensionClass *type)
{
PyObject *c1=0, *c2=0;
datafull_baseclassesf(type, &c1, &c2);
if (c2) return 2;
if (c1) return 1;
return 0;
}
static PyObject *
datafull_baseclass(PyExtensionClass *type)
{
/* Find the baseclass that has data and. There should be only one. */
int l, i;
PyObject *base, *dbase;
l=PyTuple_Size(type->bases);
for (i=0; i < l; i++)
{
base=PyTuple_GET_ITEM(type->bases, i);
if (ExtensionClass_Check(base))
{
if (AsExtensionClass(base)->bases)
{
if ((dbase=datafull_baseclass(AsExtensionClass(base))))
return dbase;
}
else
{
if (AsExtensionClass(base)->tp_basicsize >
sizeof(PyPureMixinObject) ||
AsExtensionClass(base)->tp_itemsize > 0)
return base;
}
}
}
return NULL;
}
static PyObject *
extension_baseclass(PyExtensionClass *type)
{
/* Find the first immediate base class that is an extension class */
int l, i;
PyObject *base;
l=PyTuple_Size(type->bases);
for (i=0; i < l; i++)
{
base=PyTuple_GET_ITEM(type->bases, i);
if (ExtensionClass_Check(base)) return base;
}
return JimErr_Format(PyExc_TypeError,
"No extension class found in subclass", NULL);
}
static int
subclass_hasattr(PyExtensionClass *type, PyObject *name)
{
PyObject *o;
if ((o=CCL_getattro(type,name)))
{
Py_DECREF(o);
return 1;
}
PyErr_Clear();
return 0;
}
static void
subclass_init_getattr(PyExtensionClass *self, PyObject *methods)
{
PyObject *m;
if ((m=CCL_getattr(self,py__getattr__,0)))
{
if (UnboundCMethod_Check(m)
&& AsCMethod(m)->meth==(PyCFunction)getattr_by_name
&& Subclass_Check(self,AsCMethod(m)->type))
{
self->tp_getattr=AsCMethod(m)->type->tp_getattr;
}
else if (UnboundCMethod_Check(m)
&& AsCMethod(m)->meth==(PyCFunction)getattro_by_name
&& Subclass_Check(self,AsCMethod(m)->type))
{
self->tp_getattro=AsCMethod(m)->type->tp_getattro;
}
else
{
PyObject_SetItem(methods,py__getattr__,m);
self->tp_getattro=subclass_getattro;
}
Py_DECREF(m);
}
else
{
PyErr_Clear();
self->tp_getattro=EC_findiattro;
}
}
static void
subclass_init_setattr(PyExtensionClass *self, PyObject *methods)
{
PyObject *m;
if ((m=CCL_getattr(self,py__setattr__,0)))
{
if (UnboundCMethod_Check(m)
&& AsCMethod(m)->meth==(PyCFunction)setattr_by_name
&& Subclass_Check(self,AsCMethod(m)->type))
{
self->tp_setattr=AsCMethod(m)->type->tp_setattr;
}
else if (UnboundCMethod_Check(m)
&& AsCMethod(m)->meth==(PyCFunction)setattro_by_name
&& Subclass_Check(self,AsCMethod(m)->type))
{
self->tp_setattro=AsCMethod(m)->type->tp_setattro;
}
else
{
PyObject_SetItem(methods,py__setattr__,m);
self->tp_setattro=subclass_setattro;
}
Py_DECREF(m);
}
else
{
PyErr_Clear();
self->tp_setattro=subclass_simple_setattro;
}
}
static PyObject *
CopyMethods(PyExtensionClass *type, PyObject *base_methods)
{
PyObject *methods, *key, *v;
int pos;
UNLESS(type->class_dictionary && PyDict_Check(base_methods) &&
ExtensionInstance_Check(type->class_dictionary))
{
Py_INCREF(base_methods);
return base_methods;
}
UNLESS(methods=
PyObject_CallObject((PyObject*)type->class_dictionary->ob_type, NULL))
return NULL;
for (pos=0; PyDict_Next(base_methods, &pos, &key, &v); )
UNLESS(0 <= PyObject_SetItem(methods,key,v)) goto err;
return methods;
err:
Py_DECREF(methods);
return NULL;
}
/* Constructor for building subclasses of C classes.
That is, we want to build a C class object that described a
subclass of a built-in type.
*/
static PyObject *
subclass__init__(PyExtensionClass *self, PyObject *args)
{
PyObject *bases, *methods, *class_init;
PyExtensionClass *type;
char *name, *p;
int l;
UNLESS(PyArg_ParseTuple(args,"sOO", &name, &bases, &methods)) return NULL;
l=strlen(name)+1;
UNLESS(p=(char*)malloc(l*sizeof(char))) return PyErr_NoMemory();
memcpy(p,name,l);
name=p;
UNLESS(PyTuple_Check(bases) && PyTuple_Size(bases))
{
PyErr_SetString
(PyExc_TypeError,
"second argument must be a tuple of 1 or more base classes");
}
self->bases=bases;
Py_INCREF(bases);
if (datafull_baseclasses(self) > 1)
{
PyErr_SetString(PyExc_TypeError, "too many datafull base classes");
return NULL;
}
UNLESS(type=(PyExtensionClass *)datafull_baseclass(self))
UNLESS(type=(PyExtensionClass *)extension_baseclass(self)) return NULL;
self->tp_name=name;
UNLESS(self->class_dictionary=CopyMethods(type,methods)) return NULL;
#define copy_member(M) self->M=type->M
copy_member(ob_size);
copy_member(class_flags);
copy_member(tp_itemsize);
copy_member(tp_print);
self->tp_dealloc=subclass_dealloc;
if (type->class_flags & EXTENSIONCLASS_PYTHONICATTR_FLAG)
{
/* The base class wants subclass __get/setattr__ to have
Python class semantics and *it* will be providing them.
That means that we simply copy the base class
get/setattr.
*/
copy_member(tp_getattr);
copy_member(tp_getattro);
copy_member(tp_setattr);
copy_member(tp_setattro);
self->class_flags |= EXTENSIONCLASS_PYTHONICATTR_FLAG;
if (CCL_hasattr(self, py__getattr__))
self->class_flags |= EXTENSIONCLASS_USERGETATTR_FLAG;
if (CCL_hasattr(self, py__setattr__))
self->class_flags |= EXTENSIONCLASS_USERSETATTR_FLAG;
if (CCL_hasattr(self, py__delattr__))
self->class_flags |= EXTENSIONCLASS_USERDELATTR_FLAG;
}
else
{
subclass_init_getattr(self, methods);
subclass_init_setattr(self, methods);
}
#define subclass_set(OP,N) \
self->tp_ ##OP = subclass_ ##OP
subclass_set(compare,cmp);
subclass_set(repr,repr);
if (subclass_hasattr(self,py__of__))
self->class_flags |= EXTENSIONCLASS_BINDABLE_FLAG;
if (subclass_hasattr(self,py__call_method__))
self->class_flags |= EXTENSIONCLASS_METHODHOOK_FLAG;
UNLESS(self->class_flags & EXTENSIONCLASS_NOINSTDICT_FLAG)
self->class_flags |= EXTENSIONCLASS_INSTDICT_FLAG;
if (type->bases || ! ClassHasInstDict(self))
copy_member(tp_basicsize);
else
{
self->tp_basicsize=type->tp_basicsize/sizeof(PyObject*)*sizeof(PyObject*);
if (self->tp_basicsize < type->tp_basicsize)
self->tp_basicsize += sizeof(PyObject*); /* To align on PyObject */
self->tp_basicsize += sizeof(PyObject*); /* For instance dictionary */
}
self->tp_as_number=(PyNumberMethods*)malloc(sizeof(PyNumberMethods));
UNLESS(self->tp_as_number) return PyErr_NoMemory();
*(self->tp_as_number)=subclass_as_number;
self->tp_as_sequence=
(PySequenceMethods*)malloc(sizeof(PySequenceMethods));
UNLESS(self->tp_as_sequence) return PyErr_NoMemory();
*(self->tp_as_sequence)=subclass_as_sequence;
self->tp_as_mapping=(PyMappingMethods*)malloc(sizeof(PyMappingMethods));
UNLESS(self->tp_as_mapping) return PyErr_NoMemory();
*(self->tp_as_mapping)=subclass_as_mapping;
subclass_set(hash,hash);
subclass_set(call,call);
subclass_set(str,str);
self->tp_doc=0;
/* Implement __module__=__name__ */
if (PyDict_GetItem(methods, py__module__) == NULL)
{
PyObject *globals = PyEval_GetGlobals();
if (globals != NULL)
{
PyObject *modname = PyDict_GetItem(globals, py__name__);
if (modname != NULL) {
if (PyDict_SetItem(methods, py__module__, modname) < 0)
return NULL;
}
}
}
/* Check for and use __class_init__ */
if ((class_init=PyObject_GetAttrString(AsPyObject(self),"__class_init__")))
{
UNLESS_ASSIGN(class_init,PyObject_GetAttrString(class_init,"im_func"))
return NULL;
UNLESS_ASSIGN(class_init,PyObject_CallFunction(class_init,"O",self))
return NULL;
Py_DECREF(class_init);
}
else
PyErr_Clear();
Py_INCREF(Py_None);
return Py_None;
}
struct PyMethodDef ExtensionClass_methods[] = {
{"__init__",(PyCFunction)subclass__init__,1,""},
{NULL, NULL} /* sentinel */
};
static PyExtensionClass ECType = {
PyObject_HEAD_INIT(NULL)
0, /*ob_size*/
"ExtensionClass", /*tp_name*/
sizeof(PyExtensionClass), /*tp_basicsize*/
0, /*tp_itemsize*/
/* methods */
(destructor)CCL_dealloc, /*tp_dealloc*/
(printfunc)0, /*tp_print*/
(getattrfunc)0, /*tp_getattr*/
(setattrfunc)0, /*tp_setattr*/
(cmpfunc)0, /*tp_compare*/
(reprfunc)CCL_repr, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
(hashfunc)0, /*tp_hash*/
(ternaryfunc)CCL_call, /*tp_call*/
(reprfunc)0, /*tp_str*/
(getattrofunc)CCL_getattro, /*tp_getattr with object key*/
(setattrofunc)CCL_setattro, /*tp_setattr with object key*/
/* Space for future expansion */
0L,0L,
"C classes", /* Documentation string */
METHOD_CHAIN(ExtensionClass_methods)
};
/* List of methods defined in the module */
static PyObject *
set_subclass_watcher(PyObject *ignored, PyObject *args)
{
PyObject *old, *sw=0;
UNLESS(PyArg_ParseTuple(args,"|O",&sw)) return NULL;
old=subclass_watcher;
subclass_watcher=sw;
if (sw) Py_INCREF(sw);
if (old) return old;
Py_INCREF(Py_None);
return Py_None;
}
static struct PyMethodDef CC_methods[] = {
{"subclass_watcher", (PyCFunction)set_subclass_watcher, 1,
"subclass_watcher(ob) -- "
"Register an object to watch subclass instance events"
},
{NULL, NULL} /* sentinel */
};
static int
export_type(PyObject *dict, char *name, PyExtensionClass *typ)
{
initializeBaseExtensionClass(typ);
if (PyErr_Occurred()) return -1;
if (PyDict_GetItem(typ->class_dictionary, py__module__) == NULL)
{
PyObject *modname = PyDict_GetItem(dict, py__name__);
if (modname != NULL) {
if (PyDict_SetItem(typ->class_dictionary, py__module__, modname) < 0)
return -1;
}
}
PyErr_Clear();
return PyMapping_SetItemString(dict,name,(PyObject*)typ);
}
static struct ExtensionClassCAPIstruct
TrueExtensionClassCAPI = {
export_type, /* Export */
EC_findiattrs, /* getattrs */
EC_findiattro, /* getattro */
subclass_simple_setattr, /* setattrs */
subclass_simple_setattro, /* setattro */
(PyObject*)&ECType, /* ExtensionClassType */
(PyObject*)&PMethodType, /* MethodType */
PMethod_New, /* Method_New */
CMethod_issubclass, /* issubclass */
};
void
initExtensionClass()
{
PyObject *m, *d;
char *rev="$Revision: 1.44 $";
PURE_MIXIN_CLASS(Base, "Minimalbase class for Extension Classes", NULL);
PMethodType.ob_type=&PyType_Type;
CMethodType.ob_type=&PyType_Type;
ECTypeType.ob_type=&PyType_Type;
ECType.ob_type=&ECTypeType;
UNLESS(concat_fmt=PyString_FromString("%s%s"));
m = Py_InitModule4("ExtensionClass", CC_methods,
ExtensionClass_module_documentation,
(PyObject*)NULL,PYTHON_API_VERSION);
d = PyModule_GetDict(m);
PyDict_SetItemString(d,"__version__",
PyString_FromStringAndSize(rev+11,strlen(rev+11)-2));
init_py_names();
if (0) PyCObject_Import14("this will go away", "in 1.5 :-)");
initializeBaseExtensionClass(&ECType);
PyDict_SetItemString(d, "ExtensionClass", (PyObject*)&ECType);
initializeBaseExtensionClass(&BaseType);
PyDict_SetItemString(d, "Base", (PyObject*)&BaseType);
PyDict_SetItemString(d, "PythonMethodType", (PyObject*)&PMethodType);
PyDict_SetItemString(d, "ExtensionMethodType", (PyObject*)&CMethodType);
/* Export C attribute lookup API */
PyExtensionClassCAPI=&TrueExtensionClassCAPI;
PyDict_SetItemString(d, "CAPI",
PyCObject_FromVoidPtr(PyExtensionClassCAPI,NULL));
CHECK_FOR_ERRORS("can't initialize module ExtensionClass");
}
/*
$Id: ExtensionClass.h,v 1.16 2000/12/26 15:17:59 jim Exp $
Extension Class Definitions
Copyright (c) 1996-1998, Digital Creations, Fredericksburg, VA, USA.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
o Redistributions of source code must retain the above copyright
notice, this list of conditions, and the disclaimer that follows.
o Redistributions in binary form must reproduce the above copyright
notice, this list of conditions, and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
o Neither the name of Digital Creations nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS AND CONTRIBUTORS *AS
IS* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DIGITAL
CREATIONS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
Implementing base extension classes
A base extension class is implemented in much the same way that an
extension type is implemented, except:
- The include file, 'ExtensionClass.h', must be included.
- The type structure is declared to be of type
'PyExtensionClass', rather than of type 'PyTypeObject'.
- The type structure has an additional member that must be defined
after the documentation string. This extra member is a method chain
('PyMethodChain') containing a linked list of method definition
('PyMethodDef') lists. Method chains can be used to implement
method inheritance in C. Most extensions don't use method chains,
but simply define method lists, which are null-terminated arrays
of method definitions. A macro, 'METHOD_CHAIN' is defined in
'ExtensionClass.h' that converts a method list to a method chain.
(See the example below.)
- Module functions that create new instances must be replaced by an
'__init__' method that initializes, but does not create storage for
instances.
- The extension class must be initialized and exported to the module
with::
PyExtensionClass_Export(d,"name",type);
where 'name' is the module name and 'type' is the extension class
type object.
Attribute lookup
Attribute lookup is performed by calling the base extension class
'getattr' operation for the base extension class that includes C
data, or for the first base extension class, if none of the base
extension classes include C data. 'ExtensionClass.h' defines a
macro 'Py_FindAttrString' that can be used to find an object's
attributes that are stored in the object's instance dictionary or
in the object's class or base classes::
v = Py_FindAttrString(self,name);
In addition, a macro is provided that replaces 'Py_FindMethod'
calls with logic to perform the same sort of lookup that is
provided by 'Py_FindAttrString'.
Linking
The extension class mechanism was designed to be useful with
dynamically linked extension modules. Modules that implement
extension classes do not have to be linked against an extension
class library. The macro 'PyExtensionClass_Export' imports the
'ExtensionClass' module and uses objects imported from this module
to initialize an extension class with necessary behavior.
If you have questions regarding this software,
contact:
If you have questions regarding this software,
contact:
Digital Creations L.C.
info@digicool.com
(540) 371-6909
*/
#ifndef EXTENSIONCLASS_H
#define EXTENSIONCLASS_H
#include "Python.h"
#include "import.h"
/* Declarations for objects of type ExtensionClass */
typedef struct {
PyObject_VAR_HEAD
char *tp_name; /* For printing */
int tp_basicsize, tp_itemsize; /* For allocation */
/* Methods to implement standard operations */
destructor tp_dealloc;
printfunc tp_print;
getattrfunc tp_getattr;
setattrfunc tp_setattr;
cmpfunc tp_compare;
reprfunc tp_repr;
/* Method suites for standard classes */
PyNumberMethods *tp_as_number;
PySequenceMethods *tp_as_sequence;
PyMappingMethods *tp_as_mapping;
/* More standard operations (at end for binary compatibility) */
hashfunc tp_hash;
ternaryfunc tp_call;
reprfunc tp_str;
getattrofunc tp_getattro;
setattrofunc tp_setattro;
/* Space for future expansion */
long tp_xxx3;
long tp_xxx4;
char *tp_doc; /* Documentation string */
#ifdef COUNT_ALLOCS
/* these must be last */
int tp_alloc;
int tp_free;
int tp_maxalloc;
struct _typeobject *tp_next;
#endif
/* Here's the juicy stuff: */
/* Put your method chain here. If you just have a method
list, you can use the METHON_CHAIN macro to make a chain.
*/
PyMethodChain methods;
/* You may set certain flags here. */
long class_flags;
/* The following flags are used by ExtensionClass */
#define EXTENSIONCLASS_DYNAMIC_FLAG 1 << 0
#define EXTENSIONCLASS_BINDABLE_FLAG 1 << 2
#define EXTENSIONCLASS_METHODHOOK_FLAG 1 << 3
#define EXTENSIONCLASS_INSTDICT_FLAG 1 << 4
#define EXTENSIONCLASS_NOINSTDICT_FLAG 1 << 5
#define EXTENSIONCLASS_BASICNEW_FLAG 1 << 6
#define EXTENSIONCLASS_PYTHONICATTR_FLAG 1 << 7
#define EXTENSIONCLASS_USERGETATTR_FLAG 1 << 8
#define EXTENSIONCLASS_USERSETATTR_FLAG 1 << 9
#define EXTENSIONCLASS_USERDELATTR_FLAG 1 << 10
/* The following flags are for use by extension class developers. */
#define EXTENSIONCLASS_USER_FLAG1 1 << 16
#define EXTENSIONCLASS_USER_FLAG2 1 << 17
#define EXTENSIONCLASS_USER_FLAG3 1 << 18
#define EXTENSIONCLASS_USER_FLAG4 1 << 19
#define EXTENSIONCLASS_USER_FLAG5 1 << 20
#define EXTENSIONCLASS_USER_FLAG6 1 << 21
#define EXTENSIONCLASS_USER_FLAG7 1 << 22
#define EXTENSIONCLASS_USER_FLAG8 1 << 23
#define EXTENSIONCLASS_USER_FLAG9 1 << 24
#define EXTENSIONCLASS_USER_FLAG10 1 << 25
#define EXTENSIONCLASS_USER_FLAG11 1 << 26
#define EXTENSIONCLASS_USER_FLAG12 1 << 27
#define EXTENSIONCLASS_USER_FLAG13 1 << 28
#define EXTENSIONCLASS_USER_FLAG14 1 << 29
#define EXTENSIONCLASS_USER_FLAG15 1 << 30
#define EXTENSIONCLASS_USER_FLAG16 1 << 31
/* This is the class dictionary, which is normally created for you.
If you wish, you can provide your own class dictionary object.
If you do provide your own class dictionary, it *must* be
a mapping object. If the object given is also an extension
instance, then sub-class instance dictionaries will be created
by calling the class dictionary's class with zero argumemts.
Otherwise, subclass dictionaries will be of the default type.
*/
PyObject *class_dictionary;
/* You should not set the remaining members. */
PyObject *bases;
PyObject *reserved;
} PyExtensionClass;
/* Following are macros that are needed or useful for defining extension
classes:
*/
/* This macro redefines Py_FindMethod to do attribute for an attribute
name given by a C string lookup using extension class meta-data.
This is used by older getattr implementations.
This macro is used in base class implementations of tp_getattr to
lookup methods or attributes that are not managed by the base type
directly. The macro is generally used to search for attributes
after other attribute searches have failed.
Note that in Python 1.4, a getattr operation may be provided that
uses an object argument. Classes that support this new operation
should use Py_FindAttr.
*/
#define Py_FindMethod(M,SELF,NAME) \
(PyExtensionClassCAPI->getattrs((SELF),(NAME)))
/* Do method or attribute lookup for an attribute name given by a C
string using extension class meta-data.
This macro is used in base class implementations of tp_getattro to
lookup methods or attributes that are not managed by the base type
directly. The macro is generally used to search for attributes
after other attribute searches have failed.
Note that in Python 1.4, a getattr operation may be provided that
uses an object argument. Classes that support this new operation
should use Py_FindAttr.
*/
#define Py_FindAttrString(SELF,NAME) \
(PyExtensionClassCAPI->getattrs((SELF),(NAME)))
/* Do method or attribute lookup using extension class meta-data.
This macro is used in base class implementations of tp_getattr to
lookup methods or attributes that are not managed by the base type
directly. The macro is generally used to search for attributes
after other attribute searches have failed. */
#define Py_FindAttr(SELF,NAME) (PyExtensionClassCAPI->getattro((SELF),(NAME)))
/* Do method or attribute assignment for an attribute name given by a
C string using extension class meta-data.
This macro is used in base class implementations of tp_setattr to
set attributes that are not managed by the base type directly. The
macro is generally used to assign attributes after other attribute
attempts to assign attributes have failed.
Note that in Python 1.4, a setattr operation may be provided that
uses an object argument. Classes that support this new operation
should use PyEC_SetAttr.
*/
#define PyEC_SetAttrString(SELF,NAME,V) \
(PyExtensionClassCAPI->setattrs((SELF),(NAME),(V)))
/* Do attribute assignment for an attribute.
This macro is used in base class implementations of tp_setattro to
set attributes that are not managed by the base type directly. The
macro is generally used to assign attributes after other attribute
attempts to assign attributes have failed.
*/
#define PyEC_SetAttr(SELF,NAME,V) \
(PyExtensionClassCAPI->setattro((SELF),(NAME),(V)))
/* Import the ExtensionClass CAPI */
#define ExtensionClassImported \
(PyExtensionClassCAPI=PyCObject_Import("ExtensionClass","CAPI"))
/* Make sure the C interface has been imported and import it if necessary.
This can be used in an if.
*/
#define MakeSureExtensionClassImported \
(PyExtensionClassCAPI || \
(PyExtensionClassCAPI=PyCObject_Import("ExtensionClass","CAPI")))
/* Export an Extension Base class in a given module dictionary with a
given name and ExtensionClass structure.
*/
#define PyExtensionClass_Export(D,N,T) \
if(PyExtensionClassCAPI || \
(PyExtensionClassCAPI= (struct ExtensionClassCAPIstruct*) \
PyCObject_Import("ExtensionClass","CAPI"))) \
{ PyExtensionClassCAPI->Export(D,N,&T); }
/* Convert a method list to a method chain. */
#define METHOD_CHAIN(DEF) { DEF, NULL }
/* The following macro checks whether a type is an extension class: */
#define PyExtensionClass_Check(TYPE) \
((PyObject*)(TYPE)->ob_type==PyExtensionClassCAPI->ExtensionClassType)
/* The following macro checks whether an instance is an extension instance: */
#define PyExtensionInstance_Check(INST) \
((PyObject*)(INST)->ob_type->ob_type== \
PyExtensionClassCAPI->ExtensionClassType)
/* The following macro checks for errors and prints out an error
message that is more informative than the one given by Python when
an extension module initialization fails.
*/
#define CHECK_FOR_ERRORS(MESS) \
if(PyErr_Occurred()) { \
PyObject *__sys_exc_type, *__sys_exc_value, *__sys_exc_traceback; \
PyErr_Fetch( &__sys_exc_type, &__sys_exc_value, \
&__sys_exc_traceback); \
fprintf(stderr, # MESS ":\n\t"); \
PyObject_Print(__sys_exc_type, stderr,0); \
fprintf(stderr,", "); \
PyObject_Print(__sys_exc_value, stderr,0); \
fprintf(stderr,"\n"); \
fflush(stderr); \
Py_FatalError(# MESS); \
}
/* The following macro can be used to define an extension base class
that only provides method and that is used as a pure mix-in class. */
#define PURE_MIXIN_CLASS(NAME,DOC,METHODS) \
static PyExtensionClass NAME ## Type = { PyObject_HEAD_INIT(NULL) \
0, # NAME, sizeof(PyPureMixinObject), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
0, 0, 0, 0, 0, 0, 0, DOC, {METHODS, NULL}, \
EXTENSIONCLASS_BASICNEW_FLAG}
/* The following macros provide limited access to extension-class
method facilities. */
/* Test for an ExtensionClass method: */
#define PyECMethod_Check(O) \
((PyObject*)(O)->ob_type==PyExtensionClassCAPI->MethodType)
/* Create a method object that wraps a callable object and an
instance. Note that if the callable object is an extension class
method, then the new method will wrap the callable object that is
wrapped by the extension class method. Also note that if the
callable object is an extension class method with a reference
count of 1, then the callable object will be rebound to the
instance and returned with an incremented reference count.
*/
#define PyECMethod_New(CALLABLE,INST) \
(PyExtensionClassCAPI->Method_New(CALLABLE,INST))
/* Return the instance that is bound by an extension class method. */
#define PyECMethod_Self(M) (((PyECMethodObject*)M)->self)
/* Check whether an object has an __of__ method for returning itself
in the context of it's container. */
#define has__of__(O) \
((O)->ob_type->ob_type == \
(PyTypeObject*)PyExtensionClassCAPI->ExtensionClassType && \
(((PyExtensionClass*)((O)->ob_type))->class_flags & \
EXTENSIONCLASS_BINDABLE_FLAG))
/* The following macros are used to check whether an instance
or a class' instanses have instance dictionaries: */
#define HasInstDict(O) \
((((PyExtensionClass*)((O)->ob_type))->class_flags & \
EXTENSIONCLASS_INSTDICT_FLAG))
#define ClassHasInstDict(O) (O->class_flags & EXTENSIONCLASS_INSTDICT_FLAG)
/* Get an object's instance dictionary. Use with caution */
#define INSTANCE_DICT(inst) \
*(((PyObject**)inst) + (inst->ob_type->tp_basicsize/sizeof(PyObject*) - 1))
/* Test whether an ExtensionClass, S, is a subclass of ExtensionClass C. */
#define ExtensionClassSubclass_Check(S,C) ( \
((PyObject*)(S)->ob_type==PyExtensionClassCAPI->ExtensionClassType) && \
((PyObject*)(C)->ob_type==PyExtensionClassCAPI->ExtensionClassType) && \
(PyExtensionClassCAPI->issubclass((PyExtensionClass *)(S), \
(PyExtensionClass *)(C))))
/* Test whether an ExtensionClass instance , I, is a subclass of
ExtensionClass C. */
#define ExtensionClassSubclassInstance_Check(I,C) ( \
((PyObject*)(I)->ob_type->ob_type== \
PyExtensionClassCAPI->ExtensionClassType) && \
((PyObject*)(C)->ob_type==PyExtensionClassCAPI->ExtensionClassType) && \
(PyExtensionClassCAPI->issubclass((PyExtensionClass *)((I)->ob_type), \
(PyExtensionClass *)(C))))
/* This let's you define built-in class methods. */
#define METH_CLASS_METHOD (2 << 17)
/*****************************************************************************
WARNING: EVERYTHING BELOW HERE IS PRIVATE TO THE EXTENSION CLASS INTERFACE
IMPLEMENTATION AND IS SUBJECT TO CHANGE !!!
*****************************************************************************/
static struct ExtensionClassCAPIstruct {
int (*Export)(PyObject *dict, char *name, PyExtensionClass *ob_type);
PyObject *(*getattrs)(PyObject *, char *);
PyObject *(*getattro)(PyObject *, PyObject *);
int (*setattrs)(PyObject *, char *, PyObject *);
int (*setattro)(PyObject *, PyObject *, PyObject *);
PyObject *ExtensionClassType;
PyObject *MethodType;
PyObject *(*Method_New)(PyObject *callable, PyObject *inst);
int (*issubclass)(PyExtensionClass *sub, PyExtensionClass *type);
} *PyExtensionClassCAPI = NULL;
typedef struct { PyObject_HEAD } PyPureMixinObject;
typedef struct {
PyObject_HEAD
PyTypeObject *type;
PyObject *self;
PyObject *meth;
} PyECMethodObject; /* AKA PMethod */
/* The following is to avoid whining from 1.5 :-) */
#define PyCObject_Import PyCObject_Import14
static void *
PyCObject_Import14(char *module_name, char *name)
{
PyObject *m, *c;
void *r=NULL;
if((m=PyImport_ImportModule(module_name)))
{
if((c=PyObject_GetAttrString(m,name)))
{
r=PyCObject_AsVoidPtr(c);
Py_DECREF(c);
}
Py_DECREF(m);
}
return r;
}
#endif
/*
Copyright (c) 1996-1998, Digital Creations, Fredericksburg, VA, USA.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
o Redistributions of source code must retain the above copyright
notice, this list of conditions, and the disclaimer that follows.
o Redistributions in binary form must reproduce the above copyright
notice, this list of conditions, and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
o Neither the name of Digital Creations nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS AND CONTRIBUTORS *AS
IS* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DIGITAL
CREATIONS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
$Id: MethodObject.c,v 1.5 1998/11/17 19:50:20 jim Exp $
If you have questions regarding this software,
contact:
Digital Creations L.C.
info@digicool.com
(540) 371-6909
*/
#include "ExtensionClass.h"
static PyObject *
of(PyObject *self, PyObject *args)
{
PyObject *inst;
if(PyArg_Parse(args,"O",&inst)) return PyECMethod_New(self,inst);
else return NULL;
}
struct PyMethodDef Method_methods[] = {
{"__of__",(PyCFunction)of,0,""},
{NULL, NULL} /* sentinel */
};
static struct PyMethodDef methods[] = {{NULL, NULL}};
void
initMethodObject()
{
PyObject *m, *d;
char *rev="$Revision: 1.5 $";
PURE_MIXIN_CLASS(Method,
"Base class for objects that want to be treated as methods\n"
"\n"
"The method class provides a method, __of__, that\n"
"binds an object to an instance. If a method is a subobject\n"
"of an extension-class instance, the the method will be bound\n"
"to the instance and when the resulting object is called, it\n"
"will call the method and pass the instance in addition to\n"
"other arguments. It is the responsibility of Method objects\n"
"to implement (or inherit) a __call__ method.\n",
Method_methods);
/* Create the module and add the functions */
m = Py_InitModule4("MethodObject", methods,
"Method-object mix-in class module\n\n"
"$Id: MethodObject.c,v 1.5 1998/11/17 19:50:20 jim Exp $\n",
(PyObject*)NULL,PYTHON_API_VERSION);
d = PyModule_GetDict(m);
PyExtensionClass_Export(d,"Method",MethodType);
PyDict_SetItemString(d,"__version__",
PyString_FromStringAndSize(rev+11,strlen(rev+11)-2));
/* Check for errors */
CHECK_FOR_ERRORS("can't initialize module MethodObject");
}
/*
Copyright (c) 1996-1998, Digital Creations, Fredericksburg, VA, USA.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
o Redistributions of source code must retain the above copyright
notice, this list of conditions, and the disclaimer that follows.
o Redistributions in binary form must reproduce the above copyright
notice, this list of conditions, and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
o Neither the name of Digital Creations nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS AND CONTRIBUTORS *AS
IS* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DIGITAL
CREATIONS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
$Id: Missing.c,v 1.10 1999/08/25 20:15:29 jim Exp $
If you have questions regarding this software,
contact:
Digital Creations L.C.
info@digicool.com
(540) 371-6909
*/
static char Missing_module_documentation[] =
""
"\n$Id: Missing.c,v 1.10 1999/08/25 20:15:29 jim Exp $"
;
#include <string.h>
#include "ExtensionClass.h"
/* Declarations for objects of type Missing */
typedef struct {
PyObject_HEAD
} Missing;
static PyObject *vname=0, *Missing_dot_Value=0, *empty_string=0, *reduce=0;
static PyObject *theValue;
static void
Missing_dealloc(Missing *self)
{
Py_DECREF(self->ob_type);
PyMem_DEL(self);
}
static PyObject *
Missing_repr(Missing *self)
{
Py_INCREF(Missing_dot_Value);
return Missing_dot_Value;
}
static PyObject *
Missing_str(Missing *self)
{
Py_INCREF(empty_string);
return empty_string;
}
/* Code to access Missing objects as numbers */
static PyObject *
Missing_bin(PyObject *v, PyObject *w)
{
Py_INCREF(v);
return v;
}
static PyObject *
Missing_pow(PyObject *v, PyObject *w, PyObject *z)
{
Py_INCREF(v);
return v;
}
static PyObject *
Missing_un(PyObject *v)
{
Py_INCREF(v);
return v;
}
static int
Missing_nonzero(PyObject *v)
{
return 0;
}
static int
Missing_coerce(PyObject **pv, PyObject **pw)
{
Py_INCREF(*pv);
Py_INCREF(*pw);
return 0;
}
static PyObject *
Missing_int(Missing *v)
{
PyErr_SetString(PyExc_TypeError,
"Missing objects do not support conversion to integer");
return NULL;
}
static PyObject *
Missing_long(Missing *v)
{
PyErr_SetString(PyExc_TypeError,
"Missing objects do not support conversion to long");
return NULL;
}
static PyObject *
Missing_float(Missing *v)
{
PyErr_SetString(PyExc_TypeError,
"Missing objects do not support conversion to float");
return NULL;
}
static PyObject *
Missing_oct(Missing *v)
{
PyErr_SetString(PyExc_TypeError,
"Missing objects do not support conversion to an octal string");
return NULL;
}
static PyObject *
Missing_hex(Missing *v)
{
PyErr_SetString(PyExc_TypeError,
"Missing objects do not support conversion to hexadecimal strings");
return NULL;
}
static PyNumberMethods Missing_as_number = {
(binaryfunc)Missing_bin, /*nb_add*/
(binaryfunc)Missing_bin, /*nb_subtract*/
(binaryfunc)Missing_bin, /*nb_multiply*/
(binaryfunc)Missing_bin, /*nb_divide*/
(binaryfunc)Missing_bin, /*nb_remainder*/
(binaryfunc)Missing_bin, /*nb_divmod*/
(ternaryfunc)Missing_pow, /*nb_power*/
(unaryfunc)Missing_un, /*nb_negative*/
(unaryfunc)Missing_un, /*nb_positive*/
(unaryfunc)Missing_un, /*nb_absolute*/
(inquiry)Missing_nonzero, /*nb_nonzero*/
(unaryfunc)Missing_un, /*nb_invert*/
(binaryfunc)Missing_bin, /*nb_lshift*/
(binaryfunc)Missing_bin, /*nb_rshift*/
(binaryfunc)Missing_bin, /*nb_and*/
(binaryfunc)Missing_bin, /*nb_xor*/
(binaryfunc)Missing_bin, /*nb_or*/
(coercion)Missing_coerce, /*nb_coerce*/
(unaryfunc)Missing_int, /*nb_int*/
(unaryfunc)Missing_long, /*nb_long*/
(unaryfunc)Missing_float, /*nb_float*/
(unaryfunc)Missing_oct, /*nb_oct*/
(unaryfunc)Missing_hex, /*nb_hex*/
};
/* ------------------------------------------------------- */
static PyObject *
Missing_reduce(PyObject *self, PyObject *args, PyObject *kw)
{
if(self==theValue)
{
Py_INCREF(vname);
return vname;
}
return Py_BuildValue("O()",self->ob_type);
}
static struct PyMethodDef reduce_ml[] = {
{"__reduce__", (PyCFunction)Missing_reduce, 1,
"Return a missing value reduced to standard python objects"
}
};
static PyObject *
Missing_getattr(PyObject *self, PyObject *name)
{
char *c, *legal;
if(!(c=PyString_AsString(name))) return NULL;
legal=c;
if (strchr("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",
*legal) != NULL)
{
for (legal++; *legal; legal++)
if (strchr("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_",
*legal) == NULL)
{
legal=NULL;
break;
}
}
else legal=NULL;
if(! legal)
{
if(strcmp(c,"__reduce__")==0)
{
if(self==theValue)
{
Py_INCREF(reduce);
return reduce;
}
return PyCFunction_New(reduce_ml, self);
}
PyErr_SetObject(PyExc_AttributeError, name);
return NULL;
}
Py_INCREF(self);
return self;
}
static PyObject *
Missing_call(PyObject *self, PyObject *args, PyObject *kw)
{
Py_INCREF(self);
return self;
}
static int
Missing_cmp(Missing *m1, Missing *m2)
{
return m1->ob_type != m2->ob_type ;
}
static PyExtensionClass MissingType = {
PyObject_HEAD_INIT(NULL)
0, /*ob_size*/
"Missing", /*tp_name*/
sizeof(Missing), /*tp_basicsize*/
0, /*tp_itemsize*/
/* methods */
(destructor)Missing_dealloc, /*tp_dealloc*/
(printfunc)0, /*tp_print*/
(getattrfunc)0, /*obsolete tp_getattr*/
(setattrfunc)0, /*obsolete tp_setattr*/
(cmpfunc)Missing_cmp, /*tp_compare*/
(reprfunc)Missing_repr, /*tp_repr*/
&Missing_as_number, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
(hashfunc)0, /*tp_hash*/
(ternaryfunc)Missing_call, /*tp_call*/
(reprfunc)Missing_str, /*tp_str*/
(getattrofunc)Missing_getattr, /*tp_getattro*/
(setattrofunc)0, /*tp_setattro*/
/* Space for future expansion */
0L,0L,
"Represent totally unknown quantities\n"
"\n"
"Missing values are used to represent numberic quantities that are\n"
"unknown. They support all mathematical operations except\n"
"conversions by returning themselves.\n",
METHOD_CHAIN(NULL)
};
/* End of code for Missing objects */
/* -------------------------------------------------------- */
/* List of methods defined in the module */
static struct PyMethodDef Module_Level__methods[] = {
{NULL, (PyCFunction)NULL, 0, NULL} /* sentinel */
};
void
initMissing()
{
PyObject *m, *d;
char *rev="$Revision: 1.10 $";
if(! ((vname=PyString_FromString("V"))
&& (Missing_dot_Value=PyString_FromString("Missing.Value"))
&& (empty_string=PyString_FromString(""))
)) return;
/* Create the module and add the functions */
m = Py_InitModule4("Missing", Module_Level__methods,
Missing_module_documentation,
(PyObject*)NULL,PYTHON_API_VERSION);
/* Add some symbolic constants to the module */
d = PyModule_GetDict(m);
PyDict_SetItemString(d, "__version__",
PyString_FromStringAndSize(rev+11,strlen(rev+11)-2));
PyExtensionClass_Export(d,"Missing",MissingType);
theValue=PyObject_CallObject((PyObject*)&MissingType, NULL);
reduce=PyCFunction_New(reduce_ml, theValue);
PyDict_SetItemString(d, "Value", theValue);
PyDict_SetItemString(d, "V", theValue);
PyDict_SetItemString(d, "MV", theValue);
/* Check for errors */
if (PyErr_Occurred())
Py_FatalError("can't initialize module Missing");
}
/*****************************************************************************
Revision Log:
$Log: Missing.c,v $
Revision 1.10 1999/08/25 20:15:29 jim
Made getattr a bit pickler to prevent getting attributes like "%f5.3".
Revision 1.9 1999/06/10 20:09:47 jim
Updated to use new ExtensionClass destructor protocol.
Revision 1.8 1998/11/17 19:54:33 jim
new copyright.
Revision 1.7 1997/10/03 14:43:27 jim
Fixed comparison bug, again :-(
Revision 1.6 1997/09/23 16:06:03 jim
Added MV member.
Revision 1.5 1997/09/23 15:17:12 jim
Added cmp.
Revision 1.4 1997/09/18 21:01:33 jim
Added check to getattr to fail on methods that begin with underscore.
Note that Missing really defeats testing from protocols by testing for
attributes.
Revision 1.3 1997/09/17 22:49:35 jim
Fixed refcount bug.
Added logic so: Missing.Value.spam() returns Missing.Value.
Added logic to make Missing.Value picklable.
Revision 1.2 1997/07/02 20:19:37 jim
Got rid of unused macros and ErrorObject.
Revision 1.1 1997/07/01 21:36:34 jim
*****************************************************************************/
/*
Copyright (c) 1996-1998, Digital Creations, Fredericksburg, VA, USA.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
o Redistributions of source code must retain the above copyright
notice, this list of conditions, and the disclaimer that follows.
o Redistributions in binary form must reproduce the above copyright
notice, this list of conditions, and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
o Neither the name of Digital Creations nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS AND CONTRIBUTORS *AS
IS* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DIGITAL
CREATIONS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
$Id: MultiMapping.c,v 1.8 1999/06/10 20:10:46 jim Exp $
If you have questions regarding this software,
contact:
Digital Creations L.C.
info@digicool.com
(540) 371-6909
*/
#include "Python.h"
#include "ExtensionClass.h"
#define UNLESS(E) if(!(E))
typedef struct {
PyObject_HEAD
PyObject *data;
} MMobject;
staticforward PyExtensionClass MMtype;
static PyObject *
MM_push(MMobject *self, PyObject *args)
{
PyObject *src;
UNLESS(PyArg_ParseTuple(args, "O", &src)) return NULL;
UNLESS(-1 != PyList_Append(self->data,src)) return NULL;
Py_INCREF(Py_None);
return Py_None;
}
static PyObject *
MM_pop(MMobject *self, PyObject *args)
{
int i=1, l;
PyObject *r;
if(args) UNLESS(PyArg_ParseTuple(args, "|i", &i)) return NULL;
if((l=PyList_Size(self->data)) < 0) return NULL;
i=l-i;
UNLESS(r=PySequence_GetItem(self->data,l-1)) return NULL;
if(PyList_SetSlice(self->data,i,l,NULL) < 0) goto err;
return r;
err:
Py_DECREF(r);
return NULL;
}
static PyObject *
MM__init__(MMobject *self, PyObject *args)
{
UNLESS(self->data=PyList_New(0)) return NULL;
if (args)
{
int l, i;
if ((l=PyTuple_Size(args)) < 0) return NULL;
for (i=0; i < l; i++)
if (PyList_Append(self->data, PyTuple_GET_ITEM(args, i)) < 0)
return NULL;
}
Py_INCREF(Py_None);
return Py_None;
}
static PyObject *
MM_subscript(MMobject *self, PyObject *key)
{
long i;
PyObject *e;
UNLESS(-1 != (i=PyList_Size(self->data))) return NULL;
while(--i >= 0)
{
e=PyList_GetItem(self->data,i);
if((e=PyObject_GetItem(e,key))) return e;
PyErr_Clear();
}
PyErr_SetObject(PyExc_KeyError,key);
return NULL;
}
static PyObject *
MM_has_key(MMobject *self, PyObject *args)
{
PyObject *key;
UNLESS(PyArg_ParseTuple(args,"O",&key)) return NULL;
if((key=MM_subscript(self, key)))
{
Py_DECREF(key);
return PyInt_FromLong(1);
}
PyErr_Clear();
return PyInt_FromLong(0);
}
static PyObject *
MM_get(MMobject *self, PyObject *args)
{
PyObject *key, *d=Py_None;
UNLESS(PyArg_ParseTuple(args,"O|O",&key,&d)) return NULL;
if((key=MM_subscript(self, key))) return key;
PyErr_Clear();
Py_INCREF(d);
return d;
}
static struct PyMethodDef MM_methods[] = {
{"__init__", (PyCFunction)MM__init__, METH_VARARGS,
"__init__([m1, m2, ...]) -- Create a new empty multi-mapping"},
{"get", (PyCFunction) MM_get, METH_VARARGS,
"get(key,[default]) -- Return a value for the given key or a default"},
{"has_key", (PyCFunction) MM_has_key, METH_VARARGS,
"has_key(key) -- Return 1 if the mapping has the key, and 0 otherwise"},
{"push", (PyCFunction) MM_push, METH_VARARGS,
"push(mapping_object) -- Add a data source"},
{"pop", (PyCFunction) MM_pop, METH_VARARGS,
"pop([n]) -- Remove and return the last data source added"},
{NULL, NULL} /* sentinel */
};
static void
MM_dealloc(MMobject *self)
{
Py_XDECREF(self->data);
Py_DECREF(self->ob_type);
PyMem_DEL(self);
}
static PyObject *
MM_getattr(MMobject *self, char *name)
{
return Py_FindMethod(MM_methods, (PyObject *)self, name);
}
static int
MM_length(MMobject *self)
{
long l=0, el, i;
PyObject *e=0;
UNLESS(-1 != (i=PyList_Size(self->data))) return -1;
while(--i >= 0)
{
e=PyList_GetItem(self->data,i);
UNLESS(-1 != (el=PyObject_Length(e))) return -1;
l+=el;
}
return l;
}
static PyMappingMethods MM_as_mapping = {
(inquiry)MM_length, /*mp_length*/
(binaryfunc)MM_subscript, /*mp_subscript*/
(objobjargproc)NULL, /*mp_ass_subscript*/
};
/* -------------------------------------------------------- */
static char MMtype__doc__[] =
"MultiMapping -- Combine multiple mapping objects for lookup"
;
static PyExtensionClass MMtype = {
PyObject_HEAD_INIT(NULL)
0, /*ob_size*/
"MultiMapping", /*tp_name*/
sizeof(MMobject), /*tp_basicsize*/
0, /*tp_itemsize*/
/* methods */
(destructor)MM_dealloc, /*tp_dealloc*/
(printfunc)0, /*tp_print*/
(getattrfunc)MM_getattr, /*tp_getattr*/
(setattrfunc)0, /*tp_setattr*/
(cmpfunc)0, /*tp_compare*/
(reprfunc)0, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
&MM_as_mapping, /*tp_as_mapping*/
(hashfunc)0, /*tp_hash*/
(ternaryfunc)0, /*tp_call*/
(reprfunc)0, /*tp_str*/
/* Space for future expansion */
0L,0L,0L,0L,
MMtype__doc__, /* Documentation string */
METHOD_CHAIN(MM_methods)
};
static struct PyMethodDef MultiMapping_methods[] = {
{NULL, NULL} /* sentinel */
};
void
initMultiMapping()
{
PyObject *m, *d;
char *rev="$Revision: 1.8 $";
m = Py_InitModule4(
"MultiMapping", MultiMapping_methods,
"MultiMapping -- Wrap multiple mapping objects for lookup"
"\n\n"
"$Id: MultiMapping.c,v 1.8 1999/06/10 20:10:46 jim Exp $\n",
(PyObject*)NULL,PYTHON_API_VERSION);
d = PyModule_GetDict(m);
PyExtensionClass_Export(d,"MultiMapping",MMtype);
PyDict_SetItemString(d,"__version__",
PyString_FromStringAndSize(rev+11,strlen(rev+11)-2));
if (PyErr_Occurred()) Py_FatalError("can't initialize module MultiMapping");
}
/*****************************************************************************
Zope Public License (ZPL) Version 1.0
-------------------------------------
Copyright (c) Digital Creations. All rights reserved.
This license has been certified as Open Source(tm).
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions in source code must retain the above copyright
notice, this list of conditions, and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions, and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
3. Digital Creations requests that attribution be given to Zope
in any manner possible. Zope includes a "Powered by Zope"
button that is installed by default. While it is not a license
violation to remove this button, it is requested that the
attribution remain. A significant investment has been put
into Zope, and this effort will continue if the Zope community
continues to grow. This is one way to assure that growth.
4. All advertising materials and documentation mentioning
features derived from or use of this software must display
the following acknowledgement:
"This product includes software developed by Digital Creations
for use in the Z Object Publishing Environment
(http://www.zope.org/)."
In the event that the product being advertised includes an
intact Zope distribution (with copyright and license included)
then this clause is waived.
5. Names associated with Zope or Digital Creations must not be used to
endorse or promote products derived from this software without
prior written permission from Digital Creations.
6. Modified redistributions of any form whatsoever must retain
the following acknowledgment:
"This product includes software developed by Digital Creations
for use in the Z Object Publishing Environment
(http://www.zope.org/)."
Intact (re-)distributions of any official Zope release do not
require an external acknowledgement.
7. Modifications are encouraged but must be packaged separately as
patches to official Zope releases. Distributions that do not
clearly separate the patches from the original work must be clearly
labeled as unofficial distributions. Modifications which do not
carry the name Zope may be packaged in any form, as long as they
conform to all of the clauses above.
Disclaimer
THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS ``AS IS'' AND ANY
EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DIGITAL CREATIONS OR ITS
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
This software consists of contributions made by Digital Creations and
many individuals on behalf of Digital Creations. Specific
attributions are listed in the accompanying credits file.
****************************************************************************/
static char Record_module_documentation[] =
""
"\n$Id: Record.c,v 1.10 2001/02/19 19:16:07 jeremy Exp $"
;
#ifdef PERSISTENCE
#include "cPersistence.h"
#else
#include "ExtensionClass.h"
#endif
/* ----------------------------------------------------- */
static void PyVar_Assign(PyObject **v, PyObject *e) { Py_XDECREF(*v); *v=e;}
#define ASSIGN(V,E) PyVar_Assign(&(V),(E))
#define UNLESS(E) if(!(E))
#define UNLESS_ASSIGN(V,E) ASSIGN(V,E); UNLESS(V)
#define OBJECT(O) ((PyObject*)(O))
static PyObject *py___record_schema__;
/* Declarations for objects of type Record */
typedef struct {
#ifdef PERSISTENCE
cPersistent_HEAD
#else
PyObject_HEAD
#endif
PyObject **data;
PyObject *schema;
} Record;
staticforward PyExtensionClass RecordType;
/* ---------------------------------------------------------------- */
static int
Record_init(Record *self)
{
int l;
UNLESS(self->schema)
UNLESS(self->schema=PyObject_GetAttr(OBJECT(self->ob_type),
py___record_schema__)) return -1;
if((l=PyObject_Length(self->schema)) < 0) return -1;
UNLESS(self->data)
{
UNLESS(self->data=malloc(sizeof(PyObject*)*(l+1)))
{
PyErr_NoMemory();
return -1;
}
memset(self->data, 0, sizeof(PyObject*)*(l+1));
}
return l;
}
static PyObject *
Record___setstate__(Record *self, PyObject *args)
{
PyObject *state=0, *parent, **d;
int l, ls, i;
if((l=Record_init(self)) < 0) return NULL;
UNLESS(PyArg_ParseTuple(args, "|OO", &state, &parent)) return NULL;
if(state) {
if(PyDict_Check(state))
{
PyObject *k, *v;
for(i=0; PyDict_Next(state, &i, &k, &v);)
if(k && v && PyObject_SetAttr(OBJECT(self),k,v) < 0)
PyErr_Clear();
}
else
{
if((ls=PyObject_Length(state)) < 0) return NULL;
for(i=0, d=self->data; i < l && i < ls; i++, d++)
{
ASSIGN(*d, PySequence_GetItem(state, i));
UNLESS(*d) return NULL;
}
}
}
Py_INCREF(Py_None);
return Py_None;
}
static PyObject *
Record___getstate__( Record *self, PyObject *args)
{
PyObject *r, **d, *v;
int i, l;
UNLESS(self->data) return PyTuple_New(0);
if((l=Record_init(self)) < 0) return NULL;
UNLESS(r=PyTuple_New(l)) return NULL;
for(d=self->data, i=0; i < l; i++, d++)
{
v= *d;
if(!v) v=Py_None;
Py_INCREF(v);
PyTuple_SET_ITEM(r,i,v);
}
return r;
}
static void
Record_deal(Record *self)
{
int l;
PyObject **d;
if(self->schema)
{
l=PyObject_Length(self->schema);
for(d=self->data; --l >= 0; d++)
{
Py_XDECREF(*d);
}
Py_DECREF(self->schema);
free(self->data);
}
}
#ifdef PERSISTENCE
static PyObject *
Record__p_deactivate(Record *self, PyObject *args)
{
Record_deal(self);
self->schema=NULL;
self->data=NULL;
self->state=cPersistent_GHOST_STATE;
Py_INCREF(Py_None);
return Py_None;
}
#endif
static struct PyMethodDef Record_methods[] = {
{"__getstate__", (PyCFunction)Record___getstate__, METH_VARARGS,
"__getstate__() -- Get the record's data"
},
{"__setstate__", (PyCFunction)Record___setstate__, METH_VARARGS,
"__setstate__(v) -- Set the record's data"
},
{"__init__", (PyCFunction)Record___setstate__, METH_VARARGS,
"__init__([v]) -- Initialize a record, possibly with state"
},
#ifdef PERSISTENCE
{"_p_deactivate", (PyCFunction)Record__p_deactivate, METH_VARARGS,
"_p_deactivate() -- Reset the record's data"
},
#endif
{NULL, NULL} /* sentinel */
};
/* ---------- */
static void
Record_dealloc(Record *self)
{
Record_deal(self);
Py_DECREF(self->ob_type);
PyMem_DEL(self);
}
static PyObject *
Record_getattr(Record *self, PyObject *name)
{
int l, i;
PyObject *io;
if((l=Record_init(self)) < 0) return NULL;
if ((io=Py_FindAttr((PyObject *)self, name))) return io;
PyErr_Clear();
if((io=PyObject_GetItem(self->schema, name)))
{
UNLESS(PyInt_Check(io))
{
PyErr_SetString(PyExc_TypeError, "invalid record schema");
return NULL;
}
i=PyInt_AsLong(io);
if(i >= 0 && i < l)
{
ASSIGN(io, self->data[i]);
UNLESS(io) io=Py_None;
}
else ASSIGN(io, Py_None);
Py_INCREF(io);
return io;
}
PyErr_SetObject(PyExc_AttributeError, name);
return NULL;
}
static int
Record_setattr(Record *self, PyObject *name, PyObject *v)
{
int l, i;
PyObject *io;
if((l=Record_init(self)) < 0) return -1;
if((io=PyObject_GetItem(self->schema, name)))
{
UNLESS(PyInt_Check(io))
{
PyErr_SetString(PyExc_TypeError, "invalid record schema");
return -1;
}
i=PyInt_AsLong(io);
Py_DECREF(io);
if(i >= 0 && i < l)
{
Py_XINCREF(v);
ASSIGN(self->data[i],v);
return 0;
}
}
PyErr_SetObject(PyExc_AttributeError, name);
return -1;
}
#ifdef PERSISTENCE
static PyObject *
pRecord_getattr(Record *self, PyObject *name)
{
char *c;
UNLESS(c=PyString_AsString(name)) return NULL;
return cPersistenceCAPI->pergetattro(OBJECT(self),name,c,
Record_getattr);
}
static int
pRecord_setattr(Record *self, PyObject *name, PyObject *v)
{
return cPersistenceCAPI->persetattro(OBJECT(self),name,v,Record_setattr);
}
#endif
static int
Record_compare(Record *v, Record *w)
{
int lv, lw, i, c;
PyObject **dv, **dw;
if((lv=Record_init(v)) < 0) return -1;
if((lw=Record_init(w)) < 0) return -1;
if(lw < lv) lv=lw;
for(i=0, dv=v->data, dw=w->data; i < lv; i++, dv++, dw++)
{
if(*dv)
if(*dw)
{
if((c=PyObject_Compare(*dv,*dw))) return c;
}
else return 1;
else if(*dw) return -1;
}
if(*dv) return 1;
if(*dw) return -1;
return 0;
}
/* Code to handle accessing Record objects as sequence objects */
static PyObject *
Record_concat(Record *self, PyObject *bb)
{
PyErr_SetString(PyExc_TypeError,
"Record objects do not support concatenation");
return NULL;
}
static PyObject *
Record_repeat(Record *self, int n)
{
PyErr_SetString(PyExc_TypeError,
"Record objects do not support repetition");
return NULL;
}
static PyObject *
IndexError(int i)
{
PyObject *v;
if((v=PyInt_FromLong(i)))
{
PyErr_SetObject(PyExc_IndexError, v);
Py_DECREF(v);
}
return NULL;
}
static PyObject *
Record_item(Record *self, int i)
{
PyObject *o;
int l;
if((l=Record_init(self)) < 0) return NULL;
if(i < 0 || i >= l) return IndexError(i);
o=self->data[i];
UNLESS(o) o=Py_None;
Py_INCREF(o);
return o;
}
static PyObject *
Record_slice(Record *self, int ilow, int ihigh)
{
PyErr_SetString(PyExc_TypeError,
"Record objects do not support slicing");
return NULL;
}
static int
Record_ass_item(Record *self, int i, PyObject *v)
{
int l;
if((l=Record_init(self)) < 0) return -1;
if(i < 0 || i >= l)
{
IndexError(i);
return -1;
}
UNLESS(v)
{
PyErr_SetString(PyExc_TypeError,"cannot delete record items");
return -1;
}
Py_INCREF(v);
ASSIGN(self->data[i], v);
return 0;
}
static int
Record_ass_slice(Record *self, int ilow, int ihigh, PyObject *v)
{
PyErr_SetString(PyExc_TypeError,
"Record objects do not support slice assignment");
return -1;
}
static PySequenceMethods Record_as_sequence = {
(inquiry)Record_init, /*sq_length*/
(binaryfunc)Record_concat, /*sq_concat*/
(intargfunc)Record_repeat, /*sq_repeat*/
(intargfunc)Record_item, /*sq_item*/
(intintargfunc)Record_slice, /*sq_slice*/
(intobjargproc)Record_ass_item, /*sq_ass_item*/
(intintobjargproc)Record_ass_slice, /*sq_ass_slice*/
};
/* -------------------------------------------------------------- */
static PyObject *
Record_subscript(Record *self, PyObject *key)
{
int i, l;
PyObject *io;
if((l=Record_init(self)) < 0) return NULL;
if(PyInt_Check(key))
{
i=PyInt_AsLong(key);
if(i<0) i+=l;
return Record_item(self, i);
}
if((io=PyObject_GetItem(self->schema, key)))
{
UNLESS(PyInt_Check(io))
{
PyErr_SetString(PyExc_TypeError, "invalid record schema");
return NULL;
}
i=PyInt_AsLong(io);
if(i >= 0 && i < l)
{
ASSIGN(io, self->data[i]);
UNLESS(io) io=Py_None;
}
else ASSIGN(io, Py_None);
Py_INCREF(io);
return io;
}
PyErr_Clear();
if ((io=PyObject_GetAttr(OBJECT(self), key))) return io;
PyErr_SetObject(PyExc_KeyError, key);
return NULL;
}
static int
Record_ass_sub(Record *self, PyObject *key, PyObject *v)
{
int i, l;
PyObject *io;
if((l=Record_init(self)) < 0) return -1;
if(PyInt_Check(key))
{
i=PyInt_AsLong(key);
if(i<0) i+=l;
return Record_ass_item(self, i, v);
}
if((io=PyObject_GetItem(self->schema, key)))
{
UNLESS(PyInt_Check(io))
{
PyErr_SetString(PyExc_TypeError, "invalid record schema");
return -1;
}
i=PyInt_AsLong(io);
Py_DECREF(io);
if(i >= 0 && i < l)
{
Py_XINCREF(v);
ASSIGN(self->data[i],v);
return 0;
}
}
return -1;
}
static PyMappingMethods Record_as_mapping = {
(inquiry)Record_init, /*mp_length*/
(binaryfunc)Record_subscript, /*mp_subscript*/
(objobjargproc)Record_ass_sub, /*mp_ass_subscript*/
};
/* -------------------------------------------------------- */
static PyExtensionClass RecordType = {
PyObject_HEAD_INIT(NULL)
0, /*ob_size*/
"Record", /*tp_name*/
sizeof(Record), /*tp_basicsize*/
0, /*tp_itemsize*/
/* methods */
(destructor)Record_dealloc, /*tp_dealloc*/
(printfunc)0, /*tp_print*/
(getattrfunc)0, /*obsolete tp_getattr*/
(setattrfunc)0, /*obsolete tp_setattr*/
(cmpfunc)Record_compare, /*tp_compare*/
(reprfunc)0, /*tp_repr*/
0, /*tp_as_number*/
&Record_as_sequence, /*tp_as_sequence*/
&Record_as_mapping, /*tp_as_mapping*/
(hashfunc)0, /*tp_hash*/
(ternaryfunc)0, /*tp_call*/
(reprfunc)0, /*tp_str*/
#ifdef PERSISTENCE
(getattrofunc)pRecord_getattr, /*tp_getattro*/
(setattrofunc)pRecord_setattr, /*tp_setattro*/
#else
(getattrofunc)Record_getattr, /*tp_getattro*/
(setattrofunc)Record_setattr, /*tp_setattro*/
#endif
/* Space for future expansion */
0L,0L,
"Simple Record Types", /* Documentation string */
METHOD_CHAIN(Record_methods),
EXTENSIONCLASS_NOINSTDICT_FLAG,
};
/* End of code for Record objects */
/* -------------------------------------------------------- */
/* List of methods defined in the module */
static struct PyMethodDef Module_Level__methods[] = {
{NULL, (PyCFunction)NULL, 0, NULL} /* sentinel */
};
/* Initialization function for the module (*must* be called initRecord) */
void
initRecord()
{
PyObject *m, *d;
char *rev="$Revision: 1.10 $";
UNLESS(py___record_schema__=PyString_FromString("__record_schema__")) return;
UNLESS(ExtensionClassImported) return;
#ifdef PERSISTENCE
if(cPersistenceCAPI=PyCObject_Import("cPersistence","CAPI"))
{
static PyMethodChain m;
m.methods=RecordType.methods.methods;
RecordType.methods.methods=cPersistenceCAPI->methods->methods;
RecordType.methods.link=&m;
}
else return;
#endif
/* Create the module and add the functions */
m = Py_InitModule4("Record", Module_Level__methods,
Record_module_documentation,
(PyObject*)NULL,PYTHON_API_VERSION);
/* Add some symbolic constants to the module */
d = PyModule_GetDict(m);
PyExtensionClass_Export(d,"Record",RecordType);
PyDict_SetItemString(d, "__version__",
PyString_FromStringAndSize(rev+11,strlen(rev+11)-2));
/* Check for errors */
if (PyErr_Occurred()) Py_FatalError("can't initialize module Record");
}
/*****************************************************************************
Revision Log:
$Log: Record.c,v $
Revision 1.10 2001/02/19 19:16:07 jeremy
silence compiler warnings
(2 remain)
Revision 1.9 2000/04/21 14:17:23 tseaver
Collector #1012: Guarantee null-terminated buffer in Record_init() so Record_compare doesn't UMR
Revision 1.8.6.1 2000/04/11 20:39:17 tseaver
Guarantee null-terminated buffer in Record_init() so Record_compare doesn't UMR
Revision 1.8 1999/06/10 20:11:53 jim
Updated to use new ExtensionClass destructor protocol.
Revision 1.7 1999/04/16 15:21:40 jim
Added logic to fall back to getattr when getitem fails.
This is needed to make computed attributes work in ZTables,
but it might be better to expand the schema notion to accomidate
computed attributes.
Revision 1.6 1999/03/10 00:14:41 klm
Committing with version 1.0 of the license.
Revision 1.5 1998/12/04 20:15:24 jim
Detabification and new copyright.
Revision 1.4 1998/07/27 13:09:58 jim
Changed _p___reinit__ to _p_deactivate.
Revision 1.3 1998/01/16 21:13:28 jim
Added extra ignored parent object argument to __init__ and
__setstate__.
Revision 1.2 1997/09/26 15:05:17 jim
Added sequence and mapping behavior.
Revision 1.1 1997/09/25 22:12:28 jim
*** empty log message ***
Revision 1.5 1997/07/16 20:17:45 jim
*** empty log message ***
Revision 1.4 1997/06/06 18:31:54 jim
Fixed bug in __getstate__ that caused core dumps when some attributes
were unset.
Revision 1.3 1997/05/19 14:05:46 jim
Fixed several bugs.
Revision 1.2 1997/04/30 11:37:35 jim
Fixed bug in reinitialization that probably explains the bug that
Ellen reported where ad attributes were set to None.
Revision 1.1 1997/04/27 09:18:42 jim
*** empty log message ***
$Revision 1.1 1997/02/24 23:25:42 jim
$initial
$
*****************************************************************************/
/*
Copyright (c) 1996-1998, Digital Creations, Fredericksburg, VA, USA.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
o Redistributions of source code must retain the above copyright
notice, this list of conditions, and the disclaimer that follows.
o Redistributions in binary form must reproduce the above copyright
notice, this list of conditions, and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
o Neither the name of Digital Creations nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS AND CONTRIBUTORS *AS
IS* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DIGITAL
CREATIONS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
$Id: Sync.c,v 1.2 1998/11/17 20:22:34 jim Exp $
If you have questions regarding this software,
contact:
Digital Creations L.C.
info@digicool.com
(540) 371-6909
*/
static char Sync_module_documentation[] =
""
"\n$Id: Sync.c,v 1.2 1998/11/17 20:22:34 jim Exp $"
;
#include "ExtensionClass.h"
static PyObject *ErrorObject;
/* ----------------------------------------------------- */
static void PyVar_Assign(PyObject **v, PyObject *e) { Py_XDECREF(*v); *v=e;}
#define ASSIGN(V,E) PyVar_Assign(&(V),(E))
#define UNLESS(E) if(!(E))
#define UNLESS_ASSIGN(V,E) ASSIGN(V,E); UNLESS(V)
#define OBJECT(O) ((PyObject*)(O))
PyObject *lockstr, *aqstr, *restr, *newlock;
static PyObject *
Synchronized___call_method__(PyObject *self, PyObject *args)
{
PyObject *f, *a, *k=0, *l=0, *aq=0, *t, *v, *tb, *r;
UNLESS(PyArg_ParseTuple(args, "OO|O", &f, &a, &k)) return NULL;
UNLESS(l=PyObject_GetAttr(self, lockstr))
{
PyErr_Clear();
UNLESS(l=PyObject_CallObject(newlock, NULL)) return NULL;
if(PyObject_SetAttr(self, lockstr, l) < 0) goto err;
}
UNLESS(aq=PyObject_GetAttr(l, aqstr)) goto err;
UNLESS_ASSIGN(aq,PyObject_CallObject(aq,NULL)) goto err;
if(k) r=PyEval_CallObjectWithKeywords(f,a,k);
else r=PyObject_CallObject(f,a);
PyErr_Fetch(&t, &v, &tb);
ASSIGN(aq,PyObject_GetAttr(l, restr));
if(aq) ASSIGN(aq,PyObject_CallObject(aq,NULL));
Py_XDECREF(aq);
Py_DECREF(l);
PyErr_Restore(t, v, tb);
return r;
err:
Py_DECREF(l);
return NULL;
}
static struct PyMethodDef Synchronized_methods[] = {
{"__call_method__", (PyCFunction)Synchronized___call_method__, METH_VARARGS,
"Call a method by first getting a thread lock"
},
{NULL, NULL}
};
static struct PyMethodDef Module_Level__methods[] = {
{NULL, (PyCFunction)NULL, 0, NULL}
};
void
initSync()
{
PyObject *m, *d;
char *rev="$Revision: 1.2 $";
PURE_MIXIN_CLASS(
Synchronized,
"Mix-in class that provides synchonization of method calls\n"
"\n"
"Only one thread is allowed to call a synchronized \n"
"object's methods.\n",
Synchronized_methods);
UNLESS((lockstr=PyString_FromString("_sync__lock")) &&
(aqstr=PyString_FromString("acquire")) &&
(restr=PyString_FromString("release")) &&
(newlock=PyImport_ImportModule("ThreadLock"))
) return;
ASSIGN(newlock, PyObject_GetAttrString(newlock, "allocate_lock"));
UNLESS(newlock) return;
m = Py_InitModule4("Sync", Module_Level__methods,
Sync_module_documentation,
(PyObject*)NULL,PYTHON_API_VERSION);
d = PyModule_GetDict(m);
PyExtensionClass_Export(d,"Synchronized",SynchronizedType);
PyDict_SetItemString(d,"__version__",
PyString_FromStringAndSize(rev+11,strlen(rev+11)-2));
CHECK_FOR_ERRORS("can't initialize module MethodObject");
}
/*
Copyright (c) 1996-1998, Digital Creations, Fredericksburg, VA, USA.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
o Redistributions of source code must retain the above copyright
notice, this list of conditions, and the disclaimer that follows.
o Redistributions in binary form must reproduce the above copyright
notice, this list of conditions, and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
o Neither the name of Digital Creations nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS AND CONTRIBUTORS *AS
IS* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DIGITAL
CREATIONS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
$Id: ThreadLock.c,v 1.7 1999/02/19 16:10:05 jim Exp $
If you have questions regarding this software,
contact:
Digital Creations L.C.
info@digicool.com
(540) 371-6909
*/
static char ThreadLock_module_documentation[] =
""
"\n$Id: ThreadLock.c,v 1.7 1999/02/19 16:10:05 jim Exp $"
;
#include "Python.h"
#ifdef WITH_THREAD
#include "listobject.h"
#ifdef PyList_SET_ITEM
#include "pythread.h"
#define get_thread_ident PyThread_get_thread_ident
#define acquire_lock PyThread_acquire_lock
#define release_lock PyThread_release_lock
#define type_lock PyThread_type_lock
#define free_lock PyThread_free_lock
#define allocate_lock PyThread_allocate_lock
#else
#include "thread.h"
#endif
#endif
static PyObject *ErrorObject;
/* ----------------------------------------------------- */
#define UNLESS(E) if(!(E))
/* Declarations for objects of type ThreadLock */
typedef struct {
PyObject_HEAD
int count;
long id;
#ifdef WITH_THREAD
type_lock lock;
#endif
} ThreadLockObject;
staticforward PyTypeObject ThreadLockType;
static int
cacquire(ThreadLockObject *self)
{
#ifdef WITH_THREAD
long id = get_thread_ident();
#else
long id = 1;
#endif
if(self->count >= 0 && self->id==id)
{
/* Somebody has locked me. It is either the current thread or
another thread. */
/* So this thread has it. I can't have a race condition, because,
if another thread had the lock, then the id would not be this
one. */
self->count++;
}
else
{
#ifdef WITH_THREAD
Py_BEGIN_ALLOW_THREADS
acquire_lock(self->lock, 1);
Py_END_ALLOW_THREADS
#endif
self->count=0;
self->id=id;
}
return 0;
}
static PyObject *
acquire(ThreadLockObject *self, PyObject *args)
{
if(cacquire(self) < 0) return NULL;
Py_INCREF(Py_None);
return Py_None;
}
static int
crelease(ThreadLockObject *self)
{
#ifdef WITH_THREAD
long id = get_thread_ident();
#else
long id = 1;
#endif
if(self->count >= 0 && self->id==id)
{
/* Somebody has locked me. It is either the current thread or
another thread. */
/* So this thread has it. I can't have a race condition, because,
if another thread had the lock, then the id would not be this
one. */
self->count--;
#ifdef WITH_THREAD
if(self->count < 0) release_lock(self->lock);
#endif
}
else
{
PyErr_SetString(ErrorObject, "release unlocked lock");
return -1;
}
return 0;
}
static PyObject *
release(ThreadLockObject *self, PyObject *args)
{
if(crelease(self) < 0) return NULL;
Py_INCREF(Py_None);
return Py_None;
}
static PyObject *
call_method(ThreadLockObject *self, PyObject *args)
{
PyObject *f, *a=0, *k=0;
UNLESS(PyArg_ParseTuple(args,"OO|O",&f, &a, &k)) return NULL;
if(cacquire(self) < 0) return NULL;
f=PyEval_CallObjectWithKeywords(f,a,k);
if(crelease(self) < 0)
{
Py_XDECREF(f);
f=NULL;
}
return f;
}
static struct PyMethodDef ThreadLock_methods[] = {
{"guarded_apply", (PyCFunction)call_method, 1,
"guarded_apply(FUNCTION, ARGS[, KEYWORDS]) -- Make a guarded function call\n"
"\n"
"Acquire the lock, call the function, and then release the lock.\n"
},
{"acquire", (PyCFunction)acquire, 1,
"acquire() -- Acquire a lock, taking the thread ID into account"
},
{"release", (PyCFunction)release, 1,
"release() -- Release a lock, taking the thread ID into account"
},
{NULL, NULL} /* sentinel */
};
static void
ThreadLock_dealloc(ThreadLockObject *self)
{
#ifdef WITH_THREAD
free_lock(self->lock);
#endif
PyMem_DEL(self);
}
static PyObject *
ThreadLock_getattr(ThreadLockObject *self, PyObject *name)
{
char *cname;
if((cname=PyString_AsString(name)))
{
if(*cname=='c' && strcmp(cname,"count")==0)
return PyInt_FromLong(self->count);
if(*cname=='i' && strcmp(cname,"id")==0)
return PyInt_FromLong(self->id);
return Py_FindMethod(ThreadLock_methods, (PyObject *)self, cname);
}
PyErr_SetObject(PyExc_AttributeError, name);
return NULL;
}
static PyTypeObject ThreadLockType = {
PyObject_HEAD_INIT(NULL)
0, /*ob_size*/
"ThreadLock", /*tp_name*/
sizeof(ThreadLockObject), /*tp_basicsize*/
0, /*tp_itemsize*/
/* methods */
(destructor)ThreadLock_dealloc, /*tp_dealloc*/
(printfunc)0, /*tp_print*/
(getattrfunc)0, /*obsolete tp_getattr*/
(setattrfunc)0, /*obsolete tp_setattr*/
(cmpfunc)0, /*tp_compare*/
(reprfunc)0, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
(hashfunc)0, /*tp_hash*/
(ternaryfunc)0, /*tp_call*/
(reprfunc)0, /*tp_str*/
(getattrofunc)ThreadLock_getattr, /*tp_getattro*/
0, /*tp_setattro*/
/* Space for future expansion */
0L,0L,
"Thread-based lock objects\n"
"\n"
"These lock objects may be allocated multiple times by the same\n"
"thread, but may only be allocated by one thread at a time.\n"
"This is useful for locking instances in possibly nested method calls\n"
};
static PyObject *
newThreadLockObject(ThreadLockObject *self, PyObject *args)
{
UNLESS(PyArg_ParseTuple(args,"")) return NULL;
UNLESS(self = PyObject_NEW(ThreadLockObject, &ThreadLockType)) return NULL;
self->count=-1;
#ifdef WITH_THREAD
self->lock = allocate_lock();
if (self->lock == NULL) {
PyMem_DEL(self);
self = NULL;
PyErr_SetString(ErrorObject, "can't allocate lock");
}
#endif
return (PyObject*)self;
}
static PyObject *
ident(PyObject *self, PyObject *args)
{
#ifdef WITH_THREAD
return PyInt_FromLong(get_thread_ident());
#else
return PyInt_FromLong(0);
#endif
}
static struct PyMethodDef Module_methods[] = {
{ "allocate_lock", (PyCFunction)newThreadLockObject, 1,
"allocate_lock() -- Return a new lock object"
},
{ "get_ident", (PyCFunction)ident, 1,
"get_ident() -- Get the id of the current thread"
},
{NULL, (PyCFunction)NULL, 0, NULL} /* sentinel */
};
void
initThreadLock()
{
PyObject *m, *d;
char *rev="$Revision: 1.7 $";
m = Py_InitModule4("ThreadLock", Module_methods,
ThreadLock_module_documentation,
(PyObject*)NULL,PYTHON_API_VERSION);
d = PyModule_GetDict(m);
ThreadLockType.ob_type=&PyType_Type;
PyDict_SetItemString(d,"ThreadLockType", (PyObject*)&ThreadLockType);
ErrorObject = PyString_FromString("ThreadLock.error");
PyDict_SetItemString(d, "error", ErrorObject);
PyDict_SetItemString(d, "__version__",
PyString_FromStringAndSize(rev+11,strlen(rev+11)-2));
#ifdef WITH_THREAD
PyDict_SetItemString(d, "WITH_THREAD", PyInt_FromLong(1));
#else
PyDict_SetItemString(d, "WITH_THREAD", Py_None);
#endif
/* Check for errors */
if (PyErr_Occurred())
Py_FatalError("can't initialize module ThreadLock");
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment