New errors.
diff --git a/Objects/classobject.c b/Objects/classobject.c
index 6ed97a9..edc6070 100644
--- a/Objects/classobject.c
+++ b/Objects/classobject.c
@@ -108,7 +108,7 @@
 {
 	register classmemberobject *cm;
 	if (!is_classobject(class)) {
-		errno = EINVAL;
+		err_badcall();
 		return NULL;
 	}
 	cm = NEWOBJ(classmemberobject, &Classmembertype);
@@ -148,14 +148,14 @@
 	}
 	v = class_getattr(cm->cm_class, name);
 	if (v == NULL)
-		return v; /* class_getattr() has set errno */
+		return v; /* class_getattr() has set the error */
 	if (is_funcobject(v)) {
 		object *w = newclassmethodobject(v, (object *)cm);
 		DECREF(v);
 		return w;
 	}
 	DECREF(v);
-	errno = ESRCH;
+	err_setstr(NameError, name);
 	return NULL;
 }
 
@@ -205,7 +205,7 @@
 {
 	register classmethodobject *cm;
 	if (!is_funcobject(func)) {
-		errno = EINVAL;
+		err_badcall();
 		return NULL;
 	}
 	cm = NEWOBJ(classmethodobject, &Classmethodtype);
@@ -223,7 +223,7 @@
 	register object *cm;
 {
 	if (!is_classmethodobject(cm)) {
-		errno = EINVAL;
+		err_badcall();
 		return NULL;
 	}
 	return ((classmethodobject *)cm)->cm_func;
@@ -234,7 +234,7 @@
 	register object *cm;
 {
 	if (!is_classmethodobject(cm)) {
-		errno = EINVAL;
+		err_badcall();
 		return NULL;
 	}
 	return ((classmethodobject *)cm)->cm_self;
diff --git a/Objects/floatobject.c b/Objects/floatobject.c
index f176333..d1ed9b9 100644
--- a/Objects/floatobject.c
+++ b/Objects/floatobject.c
@@ -1,5 +1,8 @@
 /* Float object implementation */
 
+/* XXX There should be overflow checks here, but it's hard to check
+   for any kind of float exception without losing portability. */
+
 #include <stdio.h>
 #include <math.h>
 #include <ctype.h>
@@ -9,6 +12,7 @@
 #include "floatobject.h"
 #include "stringobject.h"
 #include "objimpl.h"
+#include "errors.h"
 
 object *
 newfloatobject(fval)
@@ -16,14 +20,11 @@
 {
 	/* For efficiency, this code is copied from newobject() */
 	register floatobject *op = (floatobject *) malloc(sizeof(floatobject));
-	if (op == NULL) {
-		errno = ENOMEM;
-	}
-	else {
-		NEWREF(op);
-		op->ob_type = &Floattype;
-		op->ob_fval = fval;
-	}
+	if (op == NULL)
+		return err_nomem();
+	NEWREF(op);
+	op->ob_type = &Floattype;
+	op->ob_fval = fval;
 	return (object *) op;
 }
 
@@ -32,7 +33,7 @@
 	object *op;
 {
 	if (!is_floatobject(op)) {
-		errno = EBADF;
+		err_badarg();
 		return -1;
 	}
 	else
@@ -104,7 +105,7 @@
 	object *w;
 {
 	if (!is_floatobject(w)) {
-		errno = EINVAL;
+		err_badarg();
 		return NULL;
 	}
 	return newfloatobject(v->ob_fval + ((floatobject *)w) -> ob_fval);
@@ -116,7 +117,7 @@
 	object *w;
 {
 	if (!is_floatobject(w)) {
-		errno = EINVAL;
+		err_badarg();
 		return NULL;
 	}
 	return newfloatobject(v->ob_fval - ((floatobject *)w) -> ob_fval);
@@ -128,7 +129,7 @@
 	object *w;
 {
 	if (!is_floatobject(w)) {
-		errno = EINVAL;
+		err_badarg();
 		return NULL;
 	}
 	return newfloatobject(v->ob_fval * ((floatobject *)w) -> ob_fval);
@@ -140,11 +141,11 @@
 	object *w;
 {
 	if (!is_floatobject(w)) {
-		errno = EINVAL;
+		err_badarg();
 		return NULL;
 	}
 	if (((floatobject *)w) -> ob_fval == 0) {
-		errno = EDOM;
+		err_setstr(ZeroDivisionError, "float division by zero");
 		return NULL;
 	}
 	return newfloatobject(v->ob_fval / ((floatobject *)w) -> ob_fval);
@@ -158,12 +159,12 @@
 	double wx;
 	extern double fmod();
 	if (!is_floatobject(w)) {
-		errno = EINVAL;
+		err_badarg();
 		return NULL;
 	}
 	wx = ((floatobject *)w) -> ob_fval;
 	if (wx == 0.0) {
-		errno = EDOM;
+		err_setstr(ZeroDivisionError, "float division by zero");
 		return NULL;
 	}
 	return newfloatobject(fmod(v->ob_fval, wx));
@@ -177,17 +178,21 @@
 	double iv, iw, ix;
 	extern double pow();
 	if (!is_floatobject(w)) {
-		errno = EINVAL;
+		err_badarg();
 		return NULL;
 	}
 	iv = v->ob_fval;
 	iw = ((floatobject *)w)->ob_fval;
+	if (iw == 0.0)
+		return newfloatobject(1.0); /* x**0 is always 1, even 0**0 */
 	errno = 0;
 	ix = pow(iv, iw);
-	if (errno != 0)
+	if (errno != 0) {
+		/* XXX could it be another type of error? */
+		err_errno(OverflowError);
 		return NULL;
-	else
-		return newfloatobject(ix);
+	}
+	return newfloatobject(ix);
 }
 
 static object *
diff --git a/Objects/funcobject.c b/Objects/funcobject.c
index 1c6f6a6..1adc3bc 100644
--- a/Objects/funcobject.c
+++ b/Objects/funcobject.c
@@ -36,7 +36,7 @@
 	object *op;
 {
 	if (!is_funcobject(op)) {
-		errno = EBADF;
+		err_badcall();
 		return NULL;
 	}
 	return ((funcobject *) op) -> func_node;
@@ -47,7 +47,7 @@
 	object *op;
 {
 	if (!is_funcobject(op)) {
-		errno = EBADF;
+		err_badcall();
 		return NULL;
 	}
 	return ((funcobject *) op) -> func_globals;
diff --git a/Objects/listobject.c b/Objects/listobject.c
index 0ee76d1..b02a661 100644
--- a/Objects/listobject.c
+++ b/Objects/listobject.c
@@ -11,6 +11,7 @@
 #include "listobject.h"
 #include "objimpl.h"
 #include "modsupport.h"
+#include "errors.h"
 
 typedef struct {
 	OB_VARHEAD
@@ -24,13 +25,12 @@
 	int i;
 	listobject *op;
 	if (size < 0) {
-		errno = EINVAL;
+		err_badcall();
 		return NULL;
 	}
 	op = (listobject *) malloc(sizeof(listobject));
 	if (op == NULL) {
-		errno = ENOMEM;
-		return NULL;
+		return err_nomem();
 	}
 	if (size <= 0) {
 		op->ob_item = NULL;
@@ -39,8 +39,7 @@
 		op->ob_item = (object **) malloc(size * sizeof(object *));
 		if (op->ob_item == NULL) {
 			free((ANY *)op);
-			errno = ENOMEM;
-			return NULL;
+			return err_nomem();
 		}
 	}
 	NEWREF(op);
@@ -56,7 +55,7 @@
 	object *op;
 {
 	if (!is_listobject(op)) {
-		errno = EBADF;
+		err_badcall();
 		return -1;
 	}
 	else
@@ -69,11 +68,11 @@
 	int i;
 {
 	if (!is_listobject(op)) {
-		errno = EBADF;
+		err_badcall();
 		return NULL;
 	}
 	if (i < 0 || i >= ((listobject *)op) -> ob_size) {
-		errno = EDOM;
+		err_setstr(IndexError, "list index out of range");
 		return NULL;
 	}
 	return ((listobject *)op) -> ob_item[i];
@@ -89,12 +88,14 @@
 	if (!is_listobject(op)) {
 		if (newitem != NULL)
 			DECREF(newitem);
-		return errno = EBADF;
+		err_badcall();
+		return -1;
 	}
 	if (i < 0 || i >= ((listobject *)op) -> ob_size) {
 		if (newitem != NULL)
 			DECREF(newitem);
-		return errno = EDOM;
+		err_setstr(IndexError, "list assignment index out of range");
+		return -1;
 	}
 	olditem = ((listobject *)op) -> ob_item[i];
 	((listobject *)op) -> ob_item[i] = newitem;
@@ -111,12 +112,16 @@
 {
 	int i;
 	object **items;
-	if (v == NULL)
-		return errno = EINVAL;
+	if (v == NULL) {
+		err_badcall();
+		return -1;
+	}
 	items = self->ob_item;
 	RESIZE(items, object *, self->ob_size+1);
-	if (items == NULL)
-		return errno = ENOMEM;
+	if (items == NULL) {
+		err_nomem();
+		return -1;
+	}
 	if (where < 0)
 		where = 0;
 	if (where > self->ob_size)
@@ -136,8 +141,10 @@
 	int where;
 	object *newitem;
 {
-	if (!is_listobject(op))
-		return errno = EBADF;
+	if (!is_listobject(op)) {
+		err_badcall();
+		return -1;
+	}
 	return ins1((listobject *)op, where, newitem);
 }
 
@@ -146,8 +153,10 @@
 	object *op;
 	object *newitem;
 {
-	if (!is_listobject(op))
-		return errno = EBADF;
+	if (!is_listobject(op)) {
+		err_badcall();
+		return -1;
+	}
 	return ins1((listobject *)op,
 		(int) ((listobject *)op)->ob_size, newitem);
 }
@@ -234,7 +243,7 @@
 	int i;
 {
 	if (i < 0 || i >= a->ob_size) {
-		errno = EDOM;
+		err_setstr(IndexError, "list index out of range");
 		return NULL;
 	}
 	INCREF(a->ob_item[i]);
@@ -278,15 +287,14 @@
 	int i;
 	listobject *np;
 	if (!is_listobject(bb)) {
-		errno = EINVAL;
+		err_badarg();
 		return NULL;
 	}
 #define b ((listobject *)bb)
 	size = a->ob_size + b->ob_size;
 	np = (listobject *) newlistobject(size);
 	if (np == NULL) {
-		errno = ENOMEM;
-		return NULL;
+		return err_nomem();
 	}
 	for (i = 0; i < a->ob_size; i++) {
 		object *v = a->ob_item[i];
@@ -308,8 +316,10 @@
 	int i;
 	object *v;
 {
-	if (i < 0 || i >= a->ob_size)
-		return errno = EDOM;
+	if (i < 0 || i >= a->ob_size) {
+		err_setstr(IndexError, "list assignment index out of range");
+		return -1;
+	}
 	if (v == NULL)
 		return list_ass_slice(a, i, i+1, v);
 	INCREF(v);
@@ -333,8 +343,10 @@
 		n = 0;
 	else if (is_listobject(v))
 		n = b->ob_size;
-	else
-		return errno = EINVAL;
+	else {
+		err_badarg();
+		return -1;
+	}
 	if (ilow < 0)
 		ilow = 0;
 	else if (ilow > a->ob_size)
@@ -360,8 +372,10 @@
 	}
 	else { /* Insert d items; DECREF ihigh-ilow items */
 		RESIZE(item, object *, a->ob_size + d);
-		if (item == NULL)
-			return errno = ENOMEM;
+		if (item == NULL) {
+			err_nomem();
+			return -1;
+		}
 		for (k = a->ob_size; --k >= ihigh; )
 			item[k+d] = item[k];
 		for (/*k = ihigh-1*/; k >= ilow; --k)
@@ -397,7 +411,7 @@
 {
 	int i;
 	if (args == NULL || !is_tupleobject(args) || gettuplesize(args) != 2) {
-		errno = EINVAL;
+		err_badarg();
 		return NULL;
 	}
 	if (!getintarg(gettupleitem(args, 0), &i))
@@ -426,14 +440,14 @@
 	object *args;
 {
 	if (args != NULL) {
-		errno = EINVAL;
+		err_badarg();
 		return NULL;
 	}
-	errno = 0;
+	err_clear();
 	if (self->ob_size > 1)
 		qsort((char *)self->ob_item,
 				(int) self->ob_size, sizeof(object *), cmp);
-	if (errno != 0)
+	if (err_occurred())
 		return NULL;
 	INCREF(None);
 	return None;
diff --git a/Objects/methodobject.c b/Objects/methodobject.c
index 5015899..c8b5ee0 100644
--- a/Objects/methodobject.c
+++ b/Objects/methodobject.c
@@ -9,6 +9,7 @@
 #include "methodobject.h"
 #include "objimpl.h"
 #include "token.h"
+#include "errors.h"
 
 typedef struct {
 	OB_HEAD
@@ -39,7 +40,7 @@
 	object *op;
 {
 	if (!is_methodobject(op)) {
-		errno = EBADF;
+		err_badcall();
 		return NULL;
 	}
 	return ((methodobject *)op) -> m_meth;
@@ -50,7 +51,7 @@
 	object *op;
 {
 	if (!is_methodobject(op)) {
-		errno = EBADF;
+		err_badcall();
 		return NULL;
 	}
 	return ((methodobject *)op) -> m_self;
diff --git a/Objects/stringobject.c b/Objects/stringobject.c
index 6430c0f..7b02dc8 100644
--- a/Objects/stringobject.c
+++ b/Objects/stringobject.c
@@ -7,6 +7,7 @@
 #include "stringobject.h"
 #include "intobject.h"
 #include "objimpl.h"
+#include "errors.h"
 
 object *
 newsizedstringobject(str, size)
@@ -15,17 +16,14 @@
 {
 	register stringobject *op = (stringobject *)
 		malloc(sizeof(stringobject) + size * sizeof(char));
-	if (op == NULL) {
-		errno = ENOMEM;
-	}
-	else {
-		NEWREF(op);
-		op->ob_type = &Stringtype;
-		op->ob_size = size;
-		if (str != NULL)
-			memcpy(op->ob_sval, str, size);
-		op->ob_sval[size] = '\0';
-	}
+	if (op == NULL)
+		return err_nomem();
+	NEWREF(op);
+	op->ob_type = &Stringtype;
+	op->ob_size = size;
+	if (str != NULL)
+		memcpy(op->ob_sval, str, size);
+	op->ob_sval[size] = '\0';
 	return (object *) op;
 }
 
@@ -36,15 +34,12 @@
 	register unsigned int size = strlen(str);
 	register stringobject *op = (stringobject *)
 		malloc(sizeof(stringobject) + size * sizeof(char));
-	if (op == NULL) {
-		errno = ENOMEM;
-	}
-	else {
-		NEWREF(op);
-		op->ob_type = &Stringtype;
-		op->ob_size = size;
-		strcpy(op->ob_sval, str);
-	}
+	if (op == NULL)
+		return err_nomem();
+	NEWREF(op);
+	op->ob_type = &Stringtype;
+	op->ob_size = size;
+	strcpy(op->ob_sval, str);
 	return (object *) op;
 }
 
@@ -53,7 +48,7 @@
 	register object *op;
 {
 	if (!is_stringobject(op)) {
-		errno = EBADF;
+		err_badcall();
 		return -1;
 	}
 	return ((stringobject *)op) -> ob_size;
@@ -64,7 +59,7 @@
 	register object *op;
 {
 	if (!is_stringobject(op)) {
-		errno = EBADF;
+		err_badcall();
 		return NULL;
 	}
 	return ((stringobject *)op) -> ob_sval;
@@ -105,7 +100,7 @@
 	int newsize = 2 + 4 * op->ob_size * sizeof(char);
 	object *v = newsizedstringobject((char *)NULL, newsize);
 	if (v == NULL) {
-		errno = ENOMEM;
+		return err_nomem();
 	}
 	else {
 		register int i;
@@ -132,8 +127,8 @@
 		*p++ = '\'';
 		*p = '\0';
 		resizestring(&v, (int) (p - ((stringobject *)v)->ob_sval));
+		return v;
 	}
-	return v;
 }
 
 static int
@@ -151,7 +146,7 @@
 	register unsigned int size;
 	register stringobject *op;
 	if (!is_stringobject(bb)) {
-		errno = EINVAL;
+		err_badarg();
 		return NULL;
 	}
 #define b ((stringobject *)bb)
@@ -167,17 +162,14 @@
 	size = a->ob_size + b->ob_size;
 	op = (stringobject *)
 		malloc(sizeof(stringobject) + size * sizeof(char));
-	if (op == NULL) {
-		errno = ENOMEM;
-	}
-	else {
-		NEWREF(op);
-		op->ob_type = &Stringtype;
-		op->ob_size = size;
-		memcpy(op->ob_sval, a->ob_sval, (int) a->ob_size);
-		memcpy(op->ob_sval + a->ob_size, b->ob_sval, (int) b->ob_size);
-		op->ob_sval[size] = '\0';
-	}
+	if (op == NULL)
+		return err_nomem();
+	NEWREF(op);
+	op->ob_type = &Stringtype;
+	op->ob_size = size;
+	memcpy(op->ob_sval, a->ob_sval, (int) a->ob_size);
+	memcpy(op->ob_sval + a->ob_size, b->ob_sval, (int) b->ob_size);
+	op->ob_sval[size] = '\0';
 	return (object *) op;
 #undef b
 }
@@ -199,17 +191,14 @@
 	}
 	op = (stringobject *)
 		malloc(sizeof(stringobject) + size * sizeof(char));
-	if (op == NULL) {
-		errno = ENOMEM;
-	}
-	else {
-		NEWREF(op);
-		op->ob_type = &Stringtype;
-		op->ob_size = size;
-		for (i = 0; i < size; i += a->ob_size)
-			memcpy(op->ob_sval+i, a->ob_sval, (int) a->ob_size);
-		op->ob_sval[size] = '\0';
-	}
+	if (op == NULL)
+		return err_nomem();
+	NEWREF(op);
+	op->ob_type = &Stringtype;
+	op->ob_size = size;
+	for (i = 0; i < size; i += a->ob_size)
+		memcpy(op->ob_sval+i, a->ob_sval, (int) a->ob_size);
+	op->ob_sval[size] = '\0';
 	return (object *) op;
 }
 
@@ -241,7 +230,7 @@
 	register int i;
 {
 	if (i < 0 || i >= a->ob_size) {
-		errno = EDOM;
+		err_setstr(IndexError, "string index out of range");
 		return NULL;
 	}
 	return stringslice(a, i, i+1);
@@ -312,14 +301,16 @@
 	if (!is_stringobject(v) || v->ob_refcnt != 1) {
 		*pv = 0;
 		DECREF(v);
-		return errno = EBADF;
+		err_badcall();
+		return -1;
 	}
 	*pv = (object *)
 		realloc((char *)v,
 			sizeof(stringobject) + newsize * sizeof(char));
 	if (*pv == NULL) {
 		DECREF(v);
-		return errno = ENOMEM;
+		err_nomem();
+		return -1;
 	}
 	v = (stringobject *) *pv;
 	v->ob_size = newsize;
diff --git a/Objects/tupleobject.c b/Objects/tupleobject.c
index 02d68b3..960d78a 100644
--- a/Objects/tupleobject.c
+++ b/Objects/tupleobject.c
@@ -8,6 +8,7 @@
 #include "tupleobject.h"
 #include "intobject.h"
 #include "objimpl.h"
+#include "errors.h"
 
 typedef struct {
 	OB_VARHEAD
@@ -21,15 +22,13 @@
 	register int i;
 	register tupleobject *op;
 	if (size < 0) {
-		errno = EINVAL;
+		err_badcall();
 		return NULL;
 	}
 	op = (tupleobject *)
 		malloc(sizeof(tupleobject) + size * sizeof(object *));
-	if (op == NULL) {
-		errno = ENOMEM;
-		return NULL;
-	}
+	if (op == NULL)
+		return err_nomem();
 	NEWREF(op);
 	op->ob_type = &Tupletype;
 	op->ob_size = size;
@@ -43,7 +42,7 @@
 	register object *op;
 {
 	if (!is_tupleobject(op)) {
-		errno = EBADF;
+		err_badcall();
 		return -1;
 	}
 	else
@@ -56,11 +55,11 @@
 	register int i;
 {
 	if (!is_tupleobject(op)) {
-		errno = EBADF;
+		err_badcall();
 		return NULL;
 	}
 	if (i < 0 || i >= ((tupleobject *)op) -> ob_size) {
-		errno = EDOM;
+		err_setstr(IndexError, "tuple index out of range");
 		return NULL;
 	}
 	return ((tupleobject *)op) -> ob_item[i];
@@ -76,12 +75,14 @@
 	if (!is_tupleobject(op)) {
 		if (newitem != NULL)
 			DECREF(newitem);
-		return errno = EBADF;
+		err_badcall();
+		return -1;
 	}
 	if (i < 0 || i >= ((tupleobject *)op) -> ob_size) {
 		if (newitem != NULL)
 			DECREF(newitem);
-		return errno = EDOM;
+		err_setstr(IndexError, "tuple assignment index out of range");
+		return -1;
 	}
 	olditem = ((tupleobject *)op) -> ob_item[i];
 	((tupleobject *)op) -> ob_item[i] = newitem;
@@ -179,7 +180,7 @@
 	register int i;
 {
 	if (i < 0 || i >= a->ob_size) {
-		errno = EDOM;
+		err_setstr(IndexError, "tuple index out of range");
 		return NULL;
 	}
 	INCREF(a->ob_item[i]);
@@ -224,15 +225,14 @@
 	register int i;
 	tupleobject *np;
 	if (!is_tupleobject(bb)) {
-		errno = EINVAL;
+		err_badarg();
 		return NULL;
 	}
 #define b ((tupleobject *)bb)
 	size = a->ob_size + b->ob_size;
 	np = (tupleobject *) newtupleobject(size);
 	if (np == NULL) {
-		errno = ENOMEM;
-		return NULL;
+		return err_nomem();
 	}
 	for (i = 0; i < a->ob_size; i++) {
 		object *v = a->ob_item[i];