Added Py_UseClassExceptionsFlag, the variable containing the state of
the -X command line option.

Py_Initialize(): Handle the two phase initialization of the built-in
module.

Py_Finalize(): Handle the two phase finalization of the built-in
module.

parse_syntax_error(): New function which parses syntax errors that
PyErr_Print() will catch.  This correctly parses such errors
regardless of whether PyExc_SyntaxError is an old-style string
exception or new-fangled class exception.

PyErr_Print(): Many changes:

    1. Normalize the exception.

    2. Handle SystemExit exceptions which might be class based.  Digs
       the exit code out of the "code" attribute.  String based
       SystemExit is handled the same as before.

    3. Handle SyntaxError exceptions which might be class based.  Digs
       the various information bits out of the instance's attributes
       (see parse_syntax_error() for details).  String based
       SyntaxError still works too.

    4. Don't write the `:' after the exception if the exception is
       class based and has an empty string str() value.
diff --git a/Python/pythonrun.c b/Python/pythonrun.c
index c1c5d36..f9b33fc 100644
--- a/Python/pythonrun.c
+++ b/Python/pythonrun.c
@@ -75,6 +75,7 @@
 int Py_DebugFlag; /* Needed by parser.c */
 int Py_VerboseFlag; /* Needed by import.c */
 int Py_InteractiveFlag; /* Needed by Py_FdIsInteractive() below */
+int Py_UseClassExceptionsFlag; /* Needed by bltinmodule.c */
 
 static int initialized = 0;
 
@@ -127,7 +128,7 @@
 	if (interp->modules == NULL)
 		Py_FatalError("Py_Initialize: can't make modules dictionary");
 
-	bimod = _PyBuiltin_Init();
+	bimod = _PyBuiltin_Init_1();
 	if (bimod == NULL)
 		Py_FatalError("Py_Initialize: can't initialize __builtin__");
 	interp->builtins = PyModule_GetDict(bimod);
@@ -144,6 +145,9 @@
 	PyDict_SetItemString(interp->sysdict, "modules",
 			     interp->modules);
 
+	/* phase 2 of builtins */
+	_PyBuiltin_Init_2(interp->builtins);
+
 	_PyImport_Init();
 
 	initsigs(); /* Signal handling stuff, including initintr() */
@@ -178,6 +182,12 @@
 	if (initialized < 0)
 		Py_FatalError("Py_Finalize: not initialized");
 
+	/* We must call this before the current thread gets removed because
+	   it decrefs class instances, which in turn save and restore the
+	   current error state, which is a per thread data structure.
+	*/
+	_PyBuiltin_Fini_1();
+
 	tstate = PyThreadState_Get();
 	interp = tstate->interp;
 
@@ -188,7 +198,13 @@
 
 	finisigs();
 	_PyImport_Fini();
-	_PyBuiltin_Fini();
+
+	/* Now we decref the exception classes.  After this point nothing
+	   can raise an exception.  That's okay, because each Fini() method
+	   below has been checked to make sure no exceptions are ever
+	   raised.
+	*/
+	_PyBuiltin_Fini_2();
 	PyMethod_Fini();
 	PyFrame_Fini();
 	PyCFunction_Fini();
@@ -522,19 +538,99 @@
 	return 0;
 }
 
+static int
+parse_syntax_error(err, message, filename, lineno, offset, text)
+     PyObject* err;
+     PyObject** message;
+     char** filename;
+     int* lineno;
+     int* offset;
+     char** text;
+{
+	long hold;
+	PyObject *v;
+
+	/* old style errors */
+	if (PyTuple_Check(err))
+		return PyArg_Parse(err, "(O(ziiz))", message, filename,
+				   lineno, offset, text);
+
+	/* new style errors.  `err' is an instance */
+
+	if (! (v = PyObject_GetAttrString(err, "msg")))
+		goto finally;
+	*message = v;
+
+	if (!(v = PyObject_GetAttrString(err, "filename")))
+		goto finally;
+	if (v == Py_None)
+		*filename = NULL;
+	else if (! (*filename = PyString_AsString(v)))
+		goto finally;
+
+	Py_DECREF(v);
+	if (!(v = PyObject_GetAttrString(err, "lineno")))
+		goto finally;
+	hold = PyInt_AsLong(v);
+	Py_DECREF(v);
+	v = NULL;
+	if (hold < 0 && PyErr_Occurred())
+		goto finally;
+	*lineno = (int)hold;
+
+	if (!(v = PyObject_GetAttrString(err, "offset")))
+		goto finally;
+	hold = PyInt_AsLong(v);
+	Py_DECREF(v);
+	v = NULL;
+	if (hold < 0 && PyErr_Occurred())
+		goto finally;
+	*offset = (int)hold;
+
+	if (!(v = PyObject_GetAttrString(err, "text")))
+		goto finally;
+	if (v == Py_None)
+		*text = NULL;
+	else if (! (*text = PyString_AsString(v)))
+		goto finally;
+	Py_DECREF(v);
+	return 1;
+
+finally:
+	Py_XDECREF(v);
+	return 0;
+}
+
 void
 PyErr_Print()
 {
 	int err = 0;
 	PyObject *exception, *v, *tb, *f;
 	PyErr_Fetch(&exception, &v, &tb);
+	PyErr_NormalizeException(&exception, &v, &tb);
+
 	if (exception == NULL)
 		return;
+
 	if (PyErr_GivenExceptionMatches(exception, PyExc_SystemExit)) {
 		err = Py_FlushLine();
 		fflush(stdout);
 		if (v == NULL || v == Py_None)
 			Py_Exit(0);
+		if (PyInstance_Check(v)) {
+			/* we expect the error code to be store in the
+			   `code' attribute
+			*/
+			PyObject *code = PyObject_GetAttrString(v, "code");
+			if (code) {
+				Py_DECREF(v);
+				v = code;
+			}
+			/* if we failed to dig out the "code" attribute,
+			   then just let the else clause below print the
+			   error
+			*/
+		}
 		if (PyInt_Check(v))
 			Py_Exit((int)PyInt_AsLong(v));
 		else {
@@ -561,8 +657,8 @@
 			PyObject *message;
 			char *filename, *text;
 			int lineno, offset;
-			if (!PyArg_Parse(v, "(O(ziiz))", &message,
-				     &filename, &lineno, &offset, &text))
+			if (!parse_syntax_error(v, &message, &filename,
+						&lineno, &offset, &text))
 				PyErr_Clear();
 			else {
 				char buf[10];
@@ -630,7 +726,12 @@
 			err = PyFile_WriteObject(exception, f, Py_PRINT_RAW);
 		if (err == 0) {
 			if (v != NULL && v != Py_None) {
-				err = PyFile_WriteString(": ", f);
+				PyObject *s = PyObject_Str(v);
+				/* only print colon if the str() of the
+				   object is not the empty string
+				*/
+				if (s && strcmp(PyString_AsString(s), ""))
+					err = PyFile_WriteString(": ", f);
 				if (err == 0)
 				  err = PyFile_WriteObject(v, f, Py_PRINT_RAW);
 			}