Generic Abstract Object Interface
diff --git a/Objects/abstract.c b/Objects/abstract.c
new file mode 100644
index 0000000..a2099c7
--- /dev/null
+++ b/Objects/abstract.c
@@ -0,0 +1,972 @@
+/***********************************************************
+Copyright 1991-1995 by Stichting Mathematisch Centrum, Amsterdam,
+The Netherlands.
+
+                        All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its 
+documentation for any purpose and without fee is hereby granted, 
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in 
+supporting documentation, and that the names of Stichting Mathematisch
+Centrum or CWI not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior permission.
+
+STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
+THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
+FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+******************************************************************/
+
+/* Abstract Object Interface (many thanks to Jim Fulton) */
+ 
+#include "Python.h"
+
+#define Py_TRY(E) if(!(E)) return NULL
+#define Py_ASSERT(EXP,E,V) if(!(EXP)) return PyErr_SetString(E,V), (void*)NULL
+#define SPAM printf("line %d\n",__LINE__)
+
+static PyObject *
+Py_ReturnMethodError(char *name)
+{
+  if(! name) name = "Unknown Error";
+  PyErr_SetString(PyExc_AttributeError,name);
+  return 0;
+}
+
+PyObject *
+Py_ReturnNullError()
+{
+  if(! PyErr_Occurred())
+    PyErr_SetString(PyExc_SystemError,
+		    "null argument to internal routine");
+  return 0;
+}
+
+int 
+PyObject_Cmp(PyObject *o1, PyObject *o2, int *result)
+{
+  int r;
+
+  if(! o1 || ! o2) return Py_ReturnNullError(),-1;
+  r=PyObject_Compare(o1,o2);
+  if(PyErr_Occurred()) return -1;
+  *result=r;
+  return 0;
+}
+
+#if 0 /* Already in object.c */
+int
+PyCallable_Check(PyObject *x)
+{
+	if (x == NULL)
+		return 0;
+	if (x->ob_type->tp_call != NULL ||
+	    PyFunction_Check(x) ||
+	    PyMethod_Check(x) ||
+	    PyCFunction_Check(x) ||
+	    PyClass_Check(x))
+		return 1;
+	if (PyInstance_Check(x)) {
+		PyObject *call = PyObject_GetAttrString(x, "__call__");
+		if (call == NULL) {
+			err_clear();
+			return 0;
+		}
+		/* Could test recursively but don't, for fear of endless
+		   recursion if some joker sets self.__call__ = self */
+		Py_DECREF(call);
+		return 1;
+	}
+	return 0;
+}
+#endif
+
+PyObject *
+PyObject_Type(PyObject *o)
+{
+	PyObject *v;
+
+	if(! o) return Py_ReturnNullError();
+	v = (PyObject *)o->ob_type;
+	Py_INCREF(v);
+	return v;
+}
+
+int
+PyObject_Length(PyObject *o)
+{
+  PySequenceMethods *m;
+
+  if(! o) return Py_ReturnNullError(),-1;
+
+  if((m=o->ob_type->tp_as_sequence) && m->sq_length)
+    return m->sq_length(o);
+
+  return PyMapping_Length(o);
+}
+
+PyObject *
+PyObject_GetItem(PyObject *o, PyObject *key)
+{
+  PyMappingMethods *m;
+
+  if(! o || ! key) return Py_ReturnNullError();
+
+  if((m=o->ob_type->tp_as_mapping) && m->mp_subscript)
+    return m->mp_subscript(o,key);
+  
+  if(PyInt_Check(key))
+    return PySequence_GetItem(o,PyInt_AsLong(key));
+
+  PyErr_SetString(PyExc_TypeError,"expected integer index");
+  return NULL;
+}
+
+int
+PyObject_SetItem(PyObject *o, PyObject *key, PyObject *value)
+{
+  PyMappingMethods *m;
+
+  if(! o || ! key || ! value) return Py_ReturnNullError(),-1;
+  if((m=o->ob_type->tp_as_mapping) && m->mp_ass_subscript)
+    return m->mp_ass_subscript(o,key,value);
+  
+  if(PyInt_Check(key))
+    return PySequence_SetItem(o,PyInt_AsLong(key),value);
+
+  PyErr_SetString(PyExc_TypeError,"expeced integer index");
+  return -1;
+}
+
+int 
+PyNumber_Check(PyObject *o)
+{
+  return o && o->ob_type->tp_as_number;
+}
+
+
+#define BINOP(opname, ropname, thisfunc) \
+	if (!PyInstance_Check(v) && !PyInstance_Check(w)) \
+		; \
+	else \
+		return PyInstance_DoBinOp(v, w, opname, ropname, thisfunc)
+
+PyObject *
+PyNumber_Or(v, w)
+	PyObject *v, *w;
+{
+        extern int PyNumber_Coerce();
+
+	BINOP("__or__", "__ror__", PyNumber_Or);
+	if (v->ob_type->tp_as_number != NULL) {
+		PyObject *x;
+		PyObject * (*f) Py_FPROTO((PyObject *, PyObject *));
+		if (PyNumber_Coerce(&v, &w) != 0)
+			return NULL;
+		if ((f = v->ob_type->tp_as_number->nb_or) != NULL)
+			x = (*f)(v, w);
+		Py_DECREF(v);
+		Py_DECREF(w);
+		if (f != NULL)
+			return x;
+	}
+	PyErr_SetString(PyExc_TypeError, "bad operand type(s) for |");
+	return NULL;
+}
+
+PyObject *
+PyNumber_Xor(v, w)
+	PyObject *v, *w;
+{
+        extern int PyNumber_Coerce();
+
+	BINOP("__xor__", "__rxor__", PyNumber_Xor);
+	if (v->ob_type->tp_as_number != NULL) {
+		PyObject *x;
+		PyObject * (*f) Py_FPROTO((PyObject *, PyObject *));
+		if (PyNumber_Coerce(&v, &w) != 0)
+			return NULL;
+		if ((f = v->ob_type->tp_as_number->nb_xor) != NULL)
+			x = (*f)(v, w);
+		Py_DECREF(v);
+		Py_DECREF(w);
+		if (f != NULL)
+			return x;
+	}
+	PyErr_SetString(PyExc_TypeError, "bad operand type(s) for ^");
+	return NULL;
+}
+
+PyObject *
+PyNumber_And(v, w)
+	PyObject *v, *w;
+{
+	BINOP("__and__", "__rand__", PyNumber_And);
+	if (v->ob_type->tp_as_number != NULL) {
+		PyObject *x;
+		PyObject * (*f) Py_FPROTO((PyObject *, PyObject *));
+		if (PyNumber_Coerce(&v, &w) != 0)
+			return NULL;
+		if ((f = v->ob_type->tp_as_number->nb_and) != NULL)
+			x = (*f)(v, w);
+		Py_DECREF(v);
+		Py_DECREF(w);
+		if (f != NULL)
+			return x;
+	}
+	PyErr_SetString(PyExc_TypeError, "bad operand type(s) for &");
+	return NULL;
+}
+
+PyObject *
+PyNumber_Lshift(v, w)
+	PyObject *v, *w;
+{
+	BINOP("__lshift__", "__rlshift__", PyNumber_Lshift);
+	if (v->ob_type->tp_as_number != NULL) {
+		PyObject *x;
+		PyObject * (*f) Py_FPROTO((PyObject *, PyObject *));
+		if (PyNumber_Coerce(&v, &w) != 0)
+			return NULL;
+		if ((f = v->ob_type->tp_as_number->nb_lshift) != NULL)
+			x = (*f)(v, w);
+		Py_DECREF(v);
+		Py_DECREF(w);
+		if (f != NULL)
+			return x;
+	}
+	PyErr_SetString(PyExc_TypeError, "bad operand type(s) for <<");
+	return NULL;
+}
+
+PyObject *
+PyNumber_Rshift(v, w)
+	PyObject *v, *w;
+{
+	BINOP("__rshift__", "__rrshift__", PyNumber_Rshift);
+	if (v->ob_type->tp_as_number != NULL) {
+		PyObject *x;
+		PyObject * (*f) Py_FPROTO((PyObject *, PyObject *));
+		if (PyNumber_Coerce(&v, &w) != 0)
+			return NULL;
+		if ((f = v->ob_type->tp_as_number->nb_rshift) != NULL)
+			x = (*f)(v, w);
+		Py_DECREF(v);
+		Py_DECREF(w);
+		if (f != NULL)
+			return x;
+	}
+	PyErr_SetString(PyExc_TypeError, "bad operand type(s) for >>");
+	return NULL;
+}
+
+PyObject *
+PyNumber_Add(v, w)
+	PyObject *v, *w;
+{
+	BINOP("__add__", "__radd__", PyNumber_Add);
+	if (v->ob_type->tp_as_sequence != NULL)
+		return (*v->ob_type->tp_as_sequence->sq_concat)(v, w);
+	else if (v->ob_type->tp_as_number != NULL) {
+		PyObject *x;
+		if (PyNumber_Coerce(&v, &w) != 0)
+			return NULL;
+		x = (*v->ob_type->tp_as_number->nb_add)(v, w);
+		Py_DECREF(v);
+		Py_DECREF(w);
+		return x;
+	}
+	PyErr_SetString(PyExc_TypeError, "bad operand type(s) for +");
+	return NULL;
+}
+
+PyObject *
+PyNumber_Subtract(v, w)
+	PyObject *v, *w;
+{
+	BINOP("__sub__", "__rsub__", PyNumber_Subtract);
+	if (v->ob_type->tp_as_number != NULL) {
+		PyObject *x;
+		if (PyNumber_Coerce(&v, &w) != 0)
+			return NULL;
+		x = (*v->ob_type->tp_as_number->nb_subtract)(v, w);
+		Py_DECREF(v);
+		Py_DECREF(w);
+		return x;
+	}
+	PyErr_SetString(PyExc_TypeError, "bad operand type(s) for -");
+	return NULL;
+}
+
+PyObject *
+PyNumber_Multiply(v, w)
+	PyObject *v, *w;
+{
+	PyTypeObject *tp;
+	tp = v->ob_type;
+	BINOP("__mul__", "__rmul__", PyNumber_Multiply);
+	if (tp->tp_as_number != NULL &&
+	    w->ob_type->tp_as_sequence != NULL &&
+	    !PyInstance_Check(v)) {
+		/* number*sequence -- swap v and w */
+		PyObject *tmp = v;
+		v = w;
+		w = tmp;
+		tp = v->ob_type;
+	}
+	if (tp->tp_as_number != NULL) {
+		PyObject *x;
+		if (PyInstance_Check(v)) {
+			/* Instances of user-defined classes get their
+			   other argument uncoerced, so they may
+			   implement sequence*number as well as
+			   number*number. */
+			Py_INCREF(v);
+			Py_INCREF(w);
+		}
+		else if (PyNumber_Coerce(&v, &w) != 0)
+			return NULL;
+		x = (*v->ob_type->tp_as_number->nb_multiply)(v, w);
+		Py_DECREF(v);
+		Py_DECREF(w);
+		return x;
+	}
+	if (tp->tp_as_sequence != NULL) {
+		if (!PyInt_Check(w)) {
+			PyErr_SetString(PyExc_TypeError,
+				"can't multiply sequence with non-int");
+			return NULL;
+		}
+		return (*tp->tp_as_sequence->sq_repeat)
+						(v, (int)PyInt_AsLong(w));
+	}
+	PyErr_SetString(PyExc_TypeError, "bad operand type(s) for *");
+	return NULL;
+}
+
+PyObject *
+PyNumber_Divide(v, w)
+	PyObject *v, *w;
+{
+	BINOP("__div__", "__rdiv__", PyNumber_Divide);
+	if (v->ob_type->tp_as_number != NULL) {
+		PyObject *x;
+		if (PyNumber_Coerce(&v, &w) != 0)
+			return NULL;
+		x = (*v->ob_type->tp_as_number->nb_divide)(v, w);
+		Py_DECREF(v);
+		Py_DECREF(w);
+		return x;
+	}
+	PyErr_SetString(PyExc_TypeError, "bad operand type(s) for /");
+	return NULL;
+}
+
+PyObject *
+PyNumber_Remainder(v, w)
+	PyObject *v, *w;
+{
+	if (PyString_Check(v)) {
+		return PyString_Format(v, w);
+	}
+	BINOP("__mod__", "__rmod__", PyNumber_Remainder);
+	if (v->ob_type->tp_as_number != NULL) {
+		PyObject *x;
+		if (PyNumber_Coerce(&v, &w) != 0)
+			return NULL;
+		x = (*v->ob_type->tp_as_number->nb_remainder)(v, w);
+		Py_DECREF(v);
+		Py_DECREF(w);
+		return x;
+	}
+	PyErr_SetString(PyExc_TypeError, "bad operand type(s) for %");
+	return NULL;
+}
+
+PyObject *
+PyNumber_Divmod(v, w)
+	PyObject *v, *w;
+{
+	PyObject *res;
+
+	if (PyInstance_Check(v) || PyInstance_Check(w))
+		return PyInstance_DoBinOp(v, w, "__divmod__", "__rdivmod__",
+				     PyNumber_Divmod);
+	if (v->ob_type->tp_as_number == NULL ||
+				w->ob_type->tp_as_number == NULL) {
+		PyErr_SetString(PyExc_TypeError,
+		    "divmod() requires numeric or class instance arguments");
+		return NULL;
+	}
+	if (PyNumber_Coerce(&v, &w) != 0)
+		return NULL;
+	res = (*v->ob_type->tp_as_number->nb_divmod)(v, w);
+	Py_DECREF(v);
+	Py_DECREF(w);
+	return res;
+}
+
+
+static PyObject *
+do_pow(v, w)
+	PyObject *v, *w;
+{
+	PyObject *res;
+	if (PyInstance_Check(v) || PyInstance_Check(w))
+		return PyInstance_DoBinOp(v, w, "__pow__", "__rpow__", do_pow);
+	if (v->ob_type->tp_as_number == NULL ||
+	    w->ob_type->tp_as_number == NULL) {
+		PyErr_SetString(PyExc_TypeError,
+				"pow() requires numeric arguments");
+		return NULL;
+	}
+	if (PyFloat_Check(w) && PyFloat_AsDouble(v) < 0.0) {
+		if (!PyErr_Occurred())
+		    PyErr_SetString(PyExc_ValueError,
+				    "negative number to float power");
+		return NULL;
+	}
+	if (PyNumber_Coerce(&v, &w) != 0)
+		return NULL;
+	res = (*v->ob_type->tp_as_number->nb_power)(v, w, Py_None);
+	Py_DECREF(v);
+	Py_DECREF(w);
+	return res;
+}
+
+PyObject *
+PyNumber_Power(v,w,z)
+	PyObject *v, *w, *z;
+{
+	PyObject *res;
+	PyObject *v1, *z1, *w2, *z2;
+
+	if (z == Py_None)
+		return do_pow(v, w);
+	/* XXX The ternary version doesn't do class instance coercions */
+	if (PyInstance_Check(v))
+		return v->ob_type->tp_as_number->nb_power(v, w, z);
+	if (v->ob_type->tp_as_number == NULL ||
+	    z->ob_type->tp_as_number == NULL ||
+	    w->ob_type->tp_as_number == NULL) {
+		PyErr_SetString(PyExc_TypeError, "pow() requires numeric arguments");
+		return NULL;
+	}
+	if (PyNumber_Coerce(&v, &w) != 0)
+		return NULL;
+	res = NULL;
+	v1 = v;
+	z1 = z;
+	if (PyNumber_Coerce(&v1, &z1) != 0)
+		goto error2;
+	w2 = w;
+	z2 = z1;
+ 	if (PyNumber_Coerce(&w2, &z2) != 0)
+		goto error1;
+	res = (*v1->ob_type->tp_as_number->nb_power)(v1, w2, z2);
+	Py_DECREF(w2);
+	Py_DECREF(z2);
+ error1:
+	Py_DECREF(v1);
+	Py_DECREF(z1);
+ error2:
+	Py_DECREF(v);
+	Py_DECREF(w);
+	return res;
+}
+
+
+PyObject *
+PyNumber_Negative(v)
+	PyObject *v;
+{
+	if (v->ob_type->tp_as_number != NULL)
+		return (*v->ob_type->tp_as_number->nb_negative)(v);
+	PyErr_SetString(PyExc_TypeError, "bad operand type(s) for unary -");
+	return NULL;
+}
+
+PyObject *
+PyNumber_Positive(v)
+	PyObject *v;
+{
+	if (v->ob_type->tp_as_number != NULL)
+		return (*v->ob_type->tp_as_number->nb_positive)(v);
+	PyErr_SetString(PyExc_TypeError, "bad operand type(s) for unary +");
+	return NULL;
+}
+
+PyObject *
+PyNumber_Invert(v)
+	PyObject *v;
+{
+	PyObject * (*f) Py_FPROTO((PyObject *));
+	if (v->ob_type->tp_as_number != NULL &&
+		(f = v->ob_type->tp_as_number->nb_invert) != NULL)
+		return (*f)(v);
+	PyErr_SetString(PyExc_TypeError, "bad operand type(s) for unary ~");
+	return NULL;
+}
+
+PyObject *
+PyNumber_Absolute(PyObject *o)
+{
+  PyNumberMethods *m;
+
+  if(! o) return Py_ReturnNullError();
+  if((m=o->ob_type->tp_as_number) && m->nb_absolute)
+    return m->nb_absolute(o);
+
+  return Py_ReturnMethodError("__abs__");  
+}
+
+PyObject *
+PyNumber_Int(PyObject *o)
+{
+  PyNumberMethods *m;
+
+  if(! o) return Py_ReturnNullError();
+  if((m=o->ob_type->tp_as_number) && m->nb_int)
+    return m->nb_int(o);
+
+  return Py_ReturnMethodError("__int__");  
+}
+
+PyObject *
+PyNumber_Long(PyObject *o)
+{
+  PyNumberMethods *m;
+
+  if(! o) return Py_ReturnNullError();
+  if((m=o->ob_type->tp_as_number) && m->nb_long)
+    return m->nb_long(o);
+
+  return Py_ReturnMethodError("__long__");  
+}
+
+PyObject *
+PyNumber_Float(PyObject *o)
+{
+  PyNumberMethods *m;
+
+  if(! o) return Py_ReturnNullError();
+  if((m=o->ob_type->tp_as_number) && m->nb_float)
+    return m->nb_float(o);
+
+  return Py_ReturnMethodError("__float__");  
+}
+
+
+int 
+PySequence_Check(PyObject *o)
+{
+  return o && o->ob_type->tp_as_sequence;
+}
+
+int 
+PySequence_Length(PyObject *s)
+{
+  PySequenceMethods *m;
+
+  if(! s) return Py_ReturnNullError(),-1;
+
+  if((m=s->ob_type->tp_as_sequence) && m->sq_length)
+    return m->sq_length(s);
+
+  Py_ReturnMethodError("__len__");
+  return -1;
+}
+
+PyObject *
+PySequence_Concat(PyObject *s, PyObject *o)
+{
+  PySequenceMethods *m;
+
+  if(! s || ! o) return Py_ReturnNullError();
+      
+  if((m=s->ob_type->tp_as_sequence) && m->sq_concat)
+    return m->sq_concat(s,o);
+
+  return Py_ReturnMethodError("__concat__");
+}
+
+PyObject *
+PySequence_Repeat(PyObject *o, int count)
+{
+  PySequenceMethods *m;
+
+  if(! o) return Py_ReturnNullError();
+      
+  if((m=o->ob_type->tp_as_sequence) && m->sq_repeat)
+    return m->sq_repeat(o,count);
+
+  return Py_ReturnMethodError("__repeat__");
+}
+
+PyObject *
+PySequence_GetItem(PyObject *s, int i)
+{
+  PySequenceMethods *m;
+  int l;
+
+  if(! s) return Py_ReturnNullError();
+
+  if(! ((m=s->ob_type->tp_as_sequence) && m->sq_length && m->sq_item))
+    return Py_ReturnMethodError("__getitem__");  
+
+  if(0 > (l=m->sq_length(s))) return NULL;
+
+  if(i < 0) i += l;
+      
+  return m->sq_item(s,i);
+}
+
+PyObject *
+PySequence_GetSlice(PyObject *s, int i1, int i2)
+{
+  PySequenceMethods *m;
+  int l;
+
+  if(! s) return Py_ReturnNullError();
+
+  if(! ((m=s->ob_type->tp_as_sequence) && m->sq_length && m->sq_slice))
+    return Py_ReturnMethodError("__getslice__");  
+
+  if(0 > (l=m->sq_length(s))) return NULL;
+
+  if(i1 < 0) i1 += l;
+  if(i2 < 0) i2 += l;
+      
+  return m->sq_slice(s,i1,i2);
+}
+
+int
+PySequence_SetItem(PyObject *s, int i, PyObject *o)
+{
+  PySequenceMethods *m;
+  int l;
+  if(! s) return Py_ReturnNullError(),-1;
+
+  if(! ((m=s->ob_type->tp_as_sequence) && m->sq_length && m->sq_ass_item))
+    return Py_ReturnMethodError("__setitem__"),-1;  
+
+  if(i < 0)
+    {
+      if(0 > (l=m->sq_length(s))) return -1;
+      i += l;
+    }
+      
+  return m->sq_ass_item(s,i,o);
+}
+
+int 
+PySequence_SetSlice(PyObject *s, int i1, int i2, PyObject *o)
+{
+  PySequenceMethods *m;
+  int l;
+
+  if(! s) return Py_ReturnNullError(),-1;
+
+  if(! ((m=s->ob_type->tp_as_sequence) && m->sq_length && m->sq_ass_slice))
+    return Py_ReturnMethodError("__setslice__"),-1;  
+
+  if(0 > (l=m->sq_length(s))) return -1;
+
+  if(i1 < 0) i1 += l;
+  if(i2 < 0) i2 += l;
+      
+  return m->sq_ass_slice(s,i1,i2,o);
+}
+
+PyObject *
+PySequence_Tuple(PyObject *s)
+{
+  int l, i;
+  PyObject *t, *item;
+
+  if(! s) return Py_ReturnNullError();
+
+  Py_TRY((l=PySequence_Length(s)) != -1);
+  Py_TRY(t=PyTuple_New(l));
+
+  for(i=0; i < l; i++)
+    {
+      if(item=PySequence_GetItem(s,i))
+	{
+	  if(PyTuple_SetItem(t,i,item) == -1)
+	    {
+	      Py_DECREF(item);
+	      Py_DECREF(t);
+	      return NULL;
+	    }
+	}
+      else
+	{
+	  Py_DECREF(t);
+	  return NULL;
+	}
+    }
+  return t;
+}
+
+int 
+PySequence_Count(PyObject *s, PyObject *o)
+{
+  int l, i, n=0, not_equal, err;
+  PyObject *item;
+
+  if(! s || ! o) return Py_ReturnNullError(), -1;
+  Py_TRY((l=PySequence_Length(s)) != -1),-1;
+
+  for(i=0; i < l; i++)
+    {
+      Py_TRY(item=PySequence_GetItem(s,i)),-1;
+      err=PyObject_Cmp(item,o,&not_equal) == -1;
+      Py_DECREF(item);
+      if(err) return -1;
+      n += ! not_equal;
+    }
+  return n;
+}
+
+int 
+PySequence_In(PyObject *s, PyObject *o)
+{
+  int l, i, not_equal, err;
+  PyObject *item;
+
+  if(! o || ! s) return Py_ReturnNullError(), -1;
+  Py_TRY((l=PySequence_Length(s)) != -1),-1;
+
+  for(i=0; i < l; i++)
+    {
+      Py_TRY(item=PySequence_GetItem(s,i)),-1;
+      err=PyObject_Cmp(item,o,&not_equal) == -1;
+      Py_DECREF(item);
+      if(err) return -1;
+      if(! not_equal) return 1;
+    }
+  return 0;
+}
+
+int 
+PySequence_Index(PyObject *s, PyObject *o)
+{
+  int l, i, n=0, not_equal, err;
+  PyObject *item;
+
+  if(! s || ! o) return Py_ReturnNullError(), -1;
+  Py_TRY((l=PySequence_Length(s)) != -1),-1;
+
+  for(i=0; i < l; i++)
+    {
+      Py_TRY(item=PySequence_GetItem(s,i)),-1;
+      err=PyObject_Cmp(item,o,&not_equal) == -1;
+      Py_DECREF(item);
+      if(err) return -1;
+      if(! not_equal) return n;
+    }
+  return -1;
+}
+
+int 
+PyMapping_Check(PyObject *o)
+{
+  return o && o->ob_type->tp_as_mapping;
+}
+
+int 
+PyMapping_Length(PyObject *s)
+{
+  PyMappingMethods *m;
+
+  if(! s) return Py_ReturnNullError(),-1;
+
+  if((m=s->ob_type->tp_as_mapping) && m->mp_length)
+    return m->mp_length(s);
+
+  Py_ReturnMethodError("__len__");
+  return -1;
+}
+
+int 
+PyMapping_HasKeyString(PyObject *o, char *key)
+{
+  PyObject *v;
+
+  v=PyMapping_GetItemString(o,key);
+  if(v) return 1;
+  err_clear();
+  return 0;
+}
+
+int 
+PyMapping_HasKey(PyObject *o, PyObject *key)
+{
+  PyObject *v;
+
+  v=PyObject_GetItem(o,key);
+  if(v) return 1;
+  err_clear();
+  return 0;
+}
+
+PyObject *
+PyObject_CallObject(o,a)
+     PyObject *o, *a;
+{
+  PyObject *r;
+
+  if(a) return PyEval_CallObject(o,a);
+
+  if(! (a=PyTuple_New(0)))
+    return NULL;
+  r=PyEval_CallObject(o,a);
+  Py_DECREF(a);
+  return r;
+} 
+
+PyObject *
+#ifdef HAVE_STDARG_PROTOTYPES
+/* VARARGS 2 */
+PyObject_CallFunction(PyObject *callable, char *format, ...)
+#else
+/* VARARGS */
+PyObject_CallFunction(va_alist) va_dcl
+#endif
+{
+  va_list va;
+  PyObject *args, *retval;
+#ifdef HAVE_STDARG_PROTOTYPES
+  va_start(va, format);
+#else
+  PyObject *callable;
+  char *format;
+  va_start(va);
+  callable = va_arg(va, PyObject *);
+  format   = va_arg(va, char *);
+#endif
+
+  if( ! callable)
+    {
+      va_end(va);
+      return Py_ReturnNullError();
+    }
+
+  if(format)
+    args = Py_VaBuildValue(format, va);
+  else
+    args = PyTuple_New(0);
+  
+  va_end(va);
+  if(! args) return NULL;
+
+  if(! PyTuple_Check(args))
+    {
+      PyObject *a;
+      
+      Py_TRY(a=PyTuple_New(1));
+      Py_TRY(PyTuple_SetItem(a,0,args) != -1);
+      args=a;
+    }
+  retval = PyObject_CallObject(callable,args);
+  Py_DECREF(args);
+  return retval;
+}
+
+PyObject *
+#ifdef HAVE_STDARG_PROTOTYPES
+/* VARARGS 2 */
+PyObject_CallMethod(PyObject *o, char *name, char *format, ...)
+#else
+/* VARARGS */
+PyObject_CallMethod(va_alist) va_dcl
+#endif
+{
+  va_list va;
+  PyObject *args, *method=0, *retval;
+#ifdef HAVE_STDARG_PROTOTYPES
+  va_start(va, format);
+#else
+  PyObject *o;
+  char *format;
+  va_start(va);
+  o      = va_arg(va, PyObject *);
+  name   = va_arg(va, char *);
+  format = va_arg(va, char *);
+#endif
+
+  if( ! o || ! name)
+    {
+      va_end(va);
+      return Py_ReturnNullError();
+    }
+
+  method=PyObject_GetAttrString(o,name);
+  if(! method)
+    {
+      va_end(va);
+      PyErr_SetString(PyExc_AttributeError,name);
+      return 0;
+    }
+   
+  if(! (PyCallable_Check(method)))
+    {
+      va_end(va);
+      PyErr_SetString(PyExc_TypeError,"call of non-callable attribute");
+      return 0;
+    }
+
+  if(format)
+    args = Py_VaBuildValue(format, va);
+  else
+    args = PyTuple_New(0);
+  
+  va_end(va);
+
+  if(! args) return NULL;
+
+  if(! PyTuple_Check(args))
+    {
+      PyObject *a;
+      
+      Py_TRY(a=PyTuple_New(1));
+      Py_TRY(PyTuple_SetItem(a,0,args) != -1);
+      args=a;
+    }
+
+  retval = PyObject_CallObject(method,args);
+  Py_DECREF(args);
+  Py_DECREF(method);
+  return retval;
+}
+
+PyObject *
+PyMapping_GetItemString(PyObject *o, char *key)
+{
+  PyObject *okey, *r;
+
+  if( ! key) return Py_ReturnNullError();
+  Py_TRY(okey=PyString_FromString(key));
+  r = PyObject_GetItem(o,okey);
+  Py_DECREF(okey);
+  return r;
+}
+
+int
+PyMapping_SetItemString(PyObject *o, char *key, PyObject *value)
+{
+  PyObject *okey;
+  int r;
+
+  if( ! key) return Py_ReturnNullError(),-1;
+  if (!(okey=PyString_FromString(key))) return -1;
+  r = PyObject_SetItem(o,okey,value);
+  Py_DECREF(okey);
+  return r;
+}