Modified most (but not yet all) I/O to always go through sys.stdout or
sys.stderr or sys.stdin, and to work with any object as long as it has
a write() (respectively readline()) methods.  Some functions that took
a FILE* argument now take an object* argument.
diff --git a/Include/ceval.h b/Include/ceval.h
index dc31255..e7281f4 100644
--- a/Include/ceval.h
+++ b/Include/ceval.h
@@ -29,7 +29,7 @@
 object *getglobals PROTO((void));
 object *getlocals PROTO((void));
 
-void printtraceback PROTO((FILE *));
+void printtraceback PROTO((object *));
 void flushline PROTO((void));
 
 
diff --git a/Include/traceback.h b/Include/traceback.h
index c9fb17a..08370e3 100644
--- a/Include/traceback.h
+++ b/Include/traceback.h
@@ -27,4 +27,4 @@
 int tb_here PROTO((struct _frame *));
 object *tb_fetch PROTO((void));
 int tb_store PROTO((object *));
-int tb_print PROTO((object *, FILE *));
+int tb_print PROTO((object *, object *));
diff --git a/Objects/fileobject.c b/Objects/fileobject.c
index dd47905..52dd668 100644
--- a/Objects/fileobject.c
+++ b/Objects/fileobject.c
@@ -48,11 +48,10 @@
 getfilefile(f)
 	object *f;
 {
-	if (!is_fileobject(f) || ((fileobject *)f)->f_fp == NULL) {
-		err_badcall();
+	if (f == NULL || !is_fileobject(f))
 		return NULL;
-	}
-	return ((fileobject *)f)->f_fp;
+	else
+		return ((fileobject *)f)->f_fp;
 }
 
 object *
@@ -399,10 +398,56 @@
 	object *f;
 	int n;
 {
-	if (f == NULL || !is_fileobject(f)) {
+	if (f == NULL) {
 		err_badcall();
 		return NULL;
 	}
+	if (!is_fileobject(f)) {
+		object *reader;
+		object *args;
+		object *result;
+		reader = getattr(f, "readline");
+		if (reader == NULL)
+			return NULL;
+		if (n <= 0)
+			args = mkvalue("()");
+		else
+			args = mkvalue("(i)", n);
+		if (args == NULL) {
+			DECREF(reader);
+			return NULL;
+		}
+		result = call_object(reader, args);
+		DECREF(reader);
+		DECREF(args);
+		if (result != NULL && !is_stringobject(result)) {
+			DECREF(result);
+			result = NULL;
+			err_setstr(TypeError,
+				   "object.readline() returned non-string");
+		}
+		if (n < 0 && result != NULL) {
+			char *s = getstringvalue(result);
+			int len = getstringsize(result);
+			if (len == 0) {
+				DECREF(result);
+				result = NULL;
+				err_setstr(EOFError,
+					   "EOF when reading a line");
+			}
+			else if (s[len-1] == '\n') {
+				if (result->ob_refcnt == 1)
+					resizestring(&result, len-1);
+				else {
+					object *v;
+					v == newsizedstringobject(s, len-1);
+					DECREF(result);
+					result = v;
+				}
+			}
+		}
+		return result;
+	}
 	if (((fileobject*)f)->f_fp == NULL)
 		return err_closed();
 	return getline((fileobject *)f, n);
@@ -532,9 +577,101 @@
 	int newflag;
 {
 	int oldflag = 0;
-	if (f != NULL && is_fileobject(f)) {
+	if (f == NULL) {
+		/* Do nothing */
+	}
+	if (is_fileobject(f)) {
 		oldflag = ((fileobject *)f)->f_softspace;
 		((fileobject *)f)->f_softspace = newflag;
 	}
+	else {
+		object *v;
+		v = getattr(f, "softspace");
+		if (v == NULL)
+			err_clear();
+		else {
+			if (is_intobject(v))
+				oldflag = getintvalue(v);
+			DECREF(v);
+		}
+		v = newintobject((long)newflag);
+		if (v == NULL)
+			err_clear();
+		else {
+			if (setattr(f, "softspace", v) != 0)
+				err_clear();
+			DECREF(v);
+		}
+	}
 	return oldflag;
 }
+
+/* Interfaces to write objects/strings to file-like objects */
+
+int
+writeobject(v, f, flags)
+	object *v;
+	object *f;
+	int flags;
+{
+	object *writer, *value, *result;
+	if (f == NULL) {
+		err_setstr(TypeError, "writeobject with NULL file");
+		return -1;
+	}
+	else if (is_fileobject(f)) {
+		FILE *fp = getfilefile(f);
+		if (fp == NULL) {
+			err_closed();
+			return -1;
+		}
+		return printobject(v, fp, flags);
+	}
+	writer = getattr(f, "write");
+	if (writer == NULL)
+		return -1;
+	if ((flags & PRINT_RAW) && is_stringobject(v)) {
+		value = v;
+		INCREF(value);
+	}
+	else {
+		value = reprobject(v);
+		if (value == NULL) {
+			DECREF(writer);
+			return -1;
+		}
+	}
+	result = call_object(writer, value);
+	DECREF(writer);
+	DECREF(value);
+	if (result == NULL)
+		return -1;
+	DECREF(result);
+	return 0;
+}
+
+void
+writestring(s, f)
+	char *s;
+	object *f;
+{
+	if (f == NULL) {
+		/* Do nothing */
+	}
+	else if (is_fileobject(f)) {
+		FILE *fp = getfilefile(f);
+		if (fp != NULL)
+			fputs(s, fp);
+	}
+	else {
+		object *v = newstringobject(s);
+		if (v == NULL) {
+			err_clear();
+		}
+		else {
+			if (writeobject(v, f, PRINT_RAW) != NULL)
+				err_clear();
+			DECREF(v);
+		}
+	}
+}
diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c
index 2f46931..9ba07af 100644
--- a/Python/bltinmodule.c
+++ b/Python/bltinmodule.c
@@ -308,28 +308,19 @@
 	return (*nb->nb_hex)(v);
 }
 
+static object *builtin_raw_input PROTO((object *, object *));
+
 static object *
 builtin_input(self, v)
 	object *self;
 	object *v;
 {
-	FILE *in = sysgetfile("stdin", stdin);
-	FILE *out = sysgetfile("stdout", stdout);
-	int c;
-	object *m, *d;
-	flushline();
-	if (v != NULL) {
-		if (printobject(v, out, PRINT_RAW) != 0)
-			return NULL;
-	}
-	m = add_module("__main__");
-	d = getmoduledict(m);
-	BGN_SAVE
-	while ((c = getc(in)) != EOF && (c == ' ' || c == '\t'))
-		;
-	ungetc(c, in);
-	END_SAVE
-	return run_file(in, "<stdin>", expr_input, d, d);
+	object *line = builtin_raw_input(self, v);
+	if (line == NULL)
+		return line;
+	v = exec_eval(line, eval_input);
+	DECREF(line);
+	return v;
 }
 
 static object *
@@ -578,10 +569,14 @@
 	object *self;
 	object *v;
 {
-	FILE *out = sysgetfile("stdout", stdout);
+	object *f = sysget("stdout");
+	if (f == NULL) {
+		err_setstr(RuntimeError, "lost sys.stdout");
+		return NULL;
+	}
 	flushline();
 	if (v != NULL) {
-		if (printobject(v, out, PRINT_RAW) != 0)
+		if (writeobject(v, f, PRINT_RAW) != 0)
 			return NULL;
 	}
 	return filegetline(sysget("stdin"), -1);
diff --git a/Python/ceval.c b/Python/ceval.c
index 469068e..4637d35 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -176,7 +176,6 @@
 	object *trace = NULL;	/* Trace function or NULL */
 	object *retval;		/* Return value iff why == WHY_RETURN */
 	char *name;		/* Name used by some instructions */
-	FILE *fp;		/* Used by print operations */
 #ifdef LLTRACE
 	int lltrace = dictlookup(globals, "__lltrace__") != NULL;
 #endif
@@ -598,12 +597,12 @@
 		
 		case PRINT_EXPR:
 			v = POP();
-			fp = sysgetfile("stdout", stdout);
 			/* Print value except if procedure result */
 			if (v != None) {
 				flushline();
-				softspace(sysget("stdout"), 1);
-				err = printobject(v, fp, 0);
+				x = sysget("stdout");
+				softspace(x, 1);
+				err = writeobject(v, x, 0);
 				flushline();
 			}
 			DECREF(v);
@@ -611,30 +610,30 @@
 		
 		case PRINT_ITEM:
 			v = POP();
-			fp = sysgetfile("stdout", stdout);
-			if (softspace(sysget("stdout"), 1))
-				fprintf(fp, " ");
+			w = sysget("stdout");
+			if (softspace(w, 1))
+				writestring(" ", w);
 			if (is_stringobject(v)) {
 				char *s = getstringvalue(v);
 				int len = getstringsize(v);
-				fwrite(s, 1, len, fp);
-				if (ferror(fp)) {
-					err_errno(IOError);
-					err = -1;
-				}
-				else if (len > 0 && s[len-1] == '\n')
-					softspace(sysget("stdout"), 0);
+				err = writeobject(v, w, PRINT_RAW);
+				if (err == 0 && len > 0 && s[len-1] == '\n')
+					softspace(w, 0);
 			}
 			else {
-				err = printobject(v, fp, 0);
+				err = writeobject(v, w, 0);
 			}
 			DECREF(v);
 			break;
 		
 		case PRINT_NEWLINE:
-			fp = sysgetfile("stdout", stdout);
-			fprintf(fp, "\n");
-			softspace(sysget("stdout"), 0);
+			x = sysget("stdout");
+			if (x == NULL)
+				err_setstr(RuntimeError, "lost sys.stdout");
+			else {
+				writestring("\n", x);
+				softspace(x, 0);
+			}
 			break;
 		
 		case BREAK_LOOP:
@@ -1395,13 +1394,13 @@
 }
 
 void
-printtraceback(fp)
-	FILE *fp;
+printtraceback(f)
+	object *f;
 {
 	object *v = tb_fetch();
 	if (v != NULL) {
-		fprintf(fp, "Stack backtrace (innermost last):\n");
-		tb_print(v, fp);
+		writestring("Stack backtrace (innermost last):\n", f);
+		tb_print(v, f);
 		DECREF(v);
 	}
 }
@@ -1410,8 +1409,9 @@
 void
 flushline()
 {
-	if (softspace(sysget("stdout"), 0))
-		fprintf(sysgetfile("stdout", stdout), "\n");
+	object *f = sysget("stdout");
+	if (softspace(f, 0))
+		writestring("\n", f);
 }
 
 
diff --git a/Python/pythonrun.c b/Python/pythonrun.c
index 35b1815..90a4294 100644
--- a/Python/pythonrun.c
+++ b/Python/pythonrun.c
@@ -214,7 +214,7 @@
 void
 print_error()
 {
-	object *exception, *v;
+	object *exception, *v, *f;
 	err_get(&exception, &v);
 	if (exception == SystemExit) {
 		if (v == NULL || v == None)
@@ -222,6 +222,7 @@
 		if (is_intobject(v))
 			goaway((int)getintvalue(v));
 		else {
+			/* OK to use real stderr here */
 			printobject(v, stderr, PRINT_RAW);
 			fprintf(stderr, "\n");
 			goaway(1);
@@ -229,17 +230,22 @@
 	}
 	sysset("last_type", exception);
 	sysset("last_value", v);
-	if (printobject(exception, stderr, PRINT_RAW) != 0)
-		err_clear();
-	if (v != NULL && v != None) {
-		fprintf(stderr, ": ");
-		if (printobject(v, stderr, PRINT_RAW) != 0)
+	f = sysget("stderr");
+	if (f == NULL)
+		fprintf(stderr, "lost sys.stderr\n");
+	else {
+		if (writeobject(exception, f, PRINT_RAW) != 0)
 			err_clear();
+		if (v != NULL && v != None) {
+			writestring(": ", f);
+			if (writeobject(v, f, PRINT_RAW) != 0)
+				err_clear();
+		}
+		writestring("\n", f);
+		printtraceback(f);
 	}
-	fprintf(stderr, "\n");
 	XDECREF(exception);
 	XDECREF(v);
-	printtraceback(stderr);
 }
 
 object *
diff --git a/Python/sysmodule.c b/Python/sysmodule.c
index a83ec46..5dff38e 100644
--- a/Python/sysmodule.c
+++ b/Python/sysmodule.c
@@ -62,7 +62,7 @@
 {
 	FILE *fp = NULL;
 	object *v = sysget(name);
-	if (v != NULL)
+	if (v != NULL && is_fileobject(v))
 		fp = getfilefile(v);
 	if (fp == NULL)
 		fp = def;
diff --git a/Python/traceback.c b/Python/traceback.c
index bcd2f76..3c246b5 100644
--- a/Python/traceback.c
+++ b/Python/traceback.c
@@ -150,8 +150,8 @@
 }
 
 static void
-tb_displayline(fp, filename, lineno)
-	FILE *fp;
+tb_displayline(f, filename, lineno)
+	object *f;
 	char *filename;
 	int lineno;
 {
@@ -189,15 +189,17 @@
 			}
 		}
 	}
-	fprintf(fp, "  File \"%s\"", filename);
+	sprintf(linebuf, "  File \"%.900s\"%s line %d\n",
+		filename,
 #ifdef applec /* MPW */
-	/* This is needed by MPW's File and Line commands */
-	fprintf(fp, "; ");
+		/* This is needed by MPW's File and Line commands */
+		";",
 #else
-	/* This is needed by Emacs' compile command */
-	fprintf(fp, ", ");
+		/* This is needed by Emacs' compile command */
+		",",
 #endif
-	fprintf(fp, "line %d\n", lineno);
+		lineno);
+	writestring(linebuf, f);
 	if (xfp == NULL)
 		return;
 	for (i = 0; i < lineno; i++) {
@@ -208,20 +210,21 @@
 		char *p = linebuf;
 		while (*p == ' ' || *p == '\t')
 			p++;
-		fprintf(fp, "    %s", p);
+		writestring("    ", f);
+		writestring(p, f);
 		if (strchr(p, '\n') == NULL)
-			fprintf(fp, "\n");
+			writestring("\n", f);
 	}
 	fclose(xfp);
 }
 
 static void
-tb_printinternal(tb, fp)
+tb_printinternal(tb, f)
 	tracebackobject *tb;
-	FILE *fp;
+	object *f;
 {
 	while (tb != NULL && !intrcheck()) {
-		tb_displayline(fp,
+		tb_displayline(f,
 		     getstringvalue(tb->tb_frame->f_code->co_filename),
 							tb->tb_lineno);
 		tb = tb->tb_next;
@@ -229,9 +232,9 @@
 }
 
 int
-tb_print(v, fp)
+tb_print(v, f)
 	object *v;
-	FILE *fp;
+	object *f;
 {
 	if (v == NULL)
 		return 0;
@@ -240,6 +243,6 @@
 		return -1;
 	}
 	sysset("last_traceback", v);
-	tb_printinternal((tracebackobject *)v, fp);
+	tb_printinternal((tracebackobject *)v, f);
 	return 0;
 }