Initial revision
diff --git a/Objects/tupleobject.c b/Objects/tupleobject.c
new file mode 100644
index 0000000..02d68b3
--- /dev/null
+++ b/Objects/tupleobject.c
@@ -0,0 +1,276 @@
+/* Tuple object implementation */
+
+#include <stdio.h>
+
+#include "PROTO.h"
+#include "object.h"
+#include "stringobject.h"
+#include "tupleobject.h"
+#include "intobject.h"
+#include "objimpl.h"
+
+typedef struct {
+	OB_VARHEAD
+	object *ob_item[1];
+} tupleobject;
+
+object *
+newtupleobject(size)
+	register int size;
+{
+	register int i;
+	register tupleobject *op;
+	if (size < 0) {
+		errno = EINVAL;
+		return NULL;
+	}
+	op = (tupleobject *)
+		malloc(sizeof(tupleobject) + size * sizeof(object *));
+	if (op == NULL) {
+		errno = ENOMEM;
+		return NULL;
+	}
+	NEWREF(op);
+	op->ob_type = &Tupletype;
+	op->ob_size = size;
+	for (i = 0; i < size; i++)
+		op->ob_item[i] = NULL;
+	return (object *) op;
+}
+
+int
+gettuplesize(op)
+	register object *op;
+{
+	if (!is_tupleobject(op)) {
+		errno = EBADF;
+		return -1;
+	}
+	else
+		return ((tupleobject *)op)->ob_size;
+}
+
+object *
+gettupleitem(op, i)
+	register object *op;
+	register int i;
+{
+	if (!is_tupleobject(op)) {
+		errno = EBADF;
+		return NULL;
+	}
+	if (i < 0 || i >= ((tupleobject *)op) -> ob_size) {
+		errno = EDOM;
+		return NULL;
+	}
+	return ((tupleobject *)op) -> ob_item[i];
+}
+
+int
+settupleitem(op, i, newitem)
+	register object *op;
+	register int i;
+	register object *newitem;
+{
+	register object *olditem;
+	if (!is_tupleobject(op)) {
+		if (newitem != NULL)
+			DECREF(newitem);
+		return errno = EBADF;
+	}
+	if (i < 0 || i >= ((tupleobject *)op) -> ob_size) {
+		if (newitem != NULL)
+			DECREF(newitem);
+		return errno = EDOM;
+	}
+	olditem = ((tupleobject *)op) -> ob_item[i];
+	((tupleobject *)op) -> ob_item[i] = newitem;
+	if (olditem != NULL)
+		DECREF(olditem);
+	return 0;
+}
+
+/* Methods */
+
+static void
+tupledealloc(op)
+	register tupleobject *op;
+{
+	register int i;
+	for (i = 0; i < op->ob_size; i++) {
+		if (op->ob_item[i] != NULL)
+			DECREF(op->ob_item[i]);
+	}
+	free((ANY *)op);
+}
+
+static void
+tupleprint(op, fp, flags)
+	tupleobject *op;
+	FILE *fp;
+	int flags;
+{
+	int i;
+	fprintf(fp, "(");
+	for (i = 0; i < op->ob_size && !StopPrint; i++) {
+		if (i > 0) {
+			fprintf(fp, ", ");
+		}
+		printobject(op->ob_item[i], fp, flags);
+	}
+	if (op->ob_size == 1)
+		fprintf(fp, ",");
+	fprintf(fp, ")");
+}
+
+object *
+tuplerepr(v)
+	tupleobject *v;
+{
+	object *s, *t, *comma;
+	int i;
+	s = newstringobject("(");
+	comma = newstringobject(", ");
+	for (i = 0; i < v->ob_size && s != NULL; i++) {
+		if (i > 0)
+			joinstring(&s, comma);
+		t = reprobject(v->ob_item[i]);
+		joinstring(&s, t);
+		if (t != NULL)
+			DECREF(t);
+	}
+	DECREF(comma);
+	if (v->ob_size == 1) {
+		t = newstringobject(",");
+		joinstring(&s, t);
+		DECREF(t);
+	}
+	t = newstringobject(")");
+	joinstring(&s, t);
+	DECREF(t);
+	return s;
+}
+
+static int
+tuplecompare(v, w)
+	register tupleobject *v, *w;
+{
+	register int len =
+		(v->ob_size < w->ob_size) ? v->ob_size : w->ob_size;
+	register int i;
+	for (i = 0; i < len; i++) {
+		int cmp = cmpobject(v->ob_item[i], w->ob_item[i]);
+		if (cmp != 0)
+			return cmp;
+	}
+	return v->ob_size - w->ob_size;
+}
+
+static int
+tuplelength(a)
+	tupleobject *a;
+{
+	return a->ob_size;
+}
+
+static object *
+tupleitem(a, i)
+	register tupleobject *a;
+	register int i;
+{
+	if (i < 0 || i >= a->ob_size) {
+		errno = EDOM;
+		return NULL;
+	}
+	INCREF(a->ob_item[i]);
+	return a->ob_item[i];
+}
+
+static object *
+tupleslice(a, ilow, ihigh)
+	register tupleobject *a;
+	register int ilow, ihigh;
+{
+	register tupleobject *np;
+	register int i;
+	if (ilow < 0)
+		ilow = 0;
+	if (ihigh > a->ob_size)
+		ihigh = a->ob_size;
+	if (ihigh < ilow)
+		ihigh = ilow;
+	if (ilow == 0 && ihigh == a->ob_size) {
+		/* XXX can only do this if tuples are immutable! */
+		INCREF(a);
+		return (object *)a;
+	}
+	np = (tupleobject *)newtupleobject(ihigh - ilow);
+	if (np == NULL)
+		return NULL;
+	for (i = ilow; i < ihigh; i++) {
+		object *v = a->ob_item[i];
+		INCREF(v);
+		np->ob_item[i - ilow] = v;
+	}
+	return (object *)np;
+}
+
+static object *
+tupleconcat(a, bb)
+	register tupleobject *a;
+	register object *bb;
+{
+	register int size;
+	register int i;
+	tupleobject *np;
+	if (!is_tupleobject(bb)) {
+		errno = EINVAL;
+		return NULL;
+	}
+#define b ((tupleobject *)bb)
+	size = a->ob_size + b->ob_size;
+	np = (tupleobject *) newtupleobject(size);
+	if (np == NULL) {
+		errno = ENOMEM;
+		return NULL;
+	}
+	for (i = 0; i < a->ob_size; i++) {
+		object *v = a->ob_item[i];
+		INCREF(v);
+		np->ob_item[i] = v;
+	}
+	for (i = 0; i < b->ob_size; i++) {
+		object *v = b->ob_item[i];
+		INCREF(v);
+		np->ob_item[i + a->ob_size] = v;
+	}
+	return (object *)np;
+#undef b
+}
+
+static sequence_methods tuple_as_sequence = {
+	tuplelength,	/*sq_length*/
+	tupleconcat,	/*sq_concat*/
+	0,		/*sq_repeat*/
+	tupleitem,	/*sq_item*/
+	tupleslice,	/*sq_slice*/
+	0,		/*sq_ass_item*/
+	0,		/*sq_ass_slice*/
+};
+
+typeobject Tupletype = {
+	OB_HEAD_INIT(&Typetype)
+	0,
+	"tuple",
+	sizeof(tupleobject) - sizeof(object *),
+	sizeof(object *),
+	tupledealloc,	/*tp_dealloc*/
+	tupleprint,	/*tp_print*/
+	0,		/*tp_getattr*/
+	0,		/*tp_setattr*/
+	tuplecompare,	/*tp_compare*/
+	tuplerepr,	/*tp_repr*/
+	0,		/*tp_as_number*/
+	&tuple_as_sequence,	/*tp_as_sequence*/
+	0,		/*tp_as_mapping*/
+};