[m-dev.] for review: improvements to library/io.m

Fergus Henderson fjh at cs.mu.OZ.AU
Fri Sep 15 20:16:42 AEDT 2000


Tyson and/or Pete are probably the best people to review this one.

----------

Estimated hours taken: 2

library/io.m:
	Document that accessing a file which has been closed results
	in undefined behaviour.

	Change the code for closing files so that it does its best to
	ensure that the undefined behaviour is as nice as can be
	achieved without compromising efficiency.

	Change the code for io__read_file_into_buffer so that
	it handles the case when MR_READ() returns a negative value
	(rather than zero) on errors.

	Fix some grammar errors in the documentation.

Workspace: /home/pgrad/fjh/ws/hg
Index: library/io.m
===================================================================
RCS file: /home/mercury1/repository/mercury/library/io.m,v
retrieving revision 1.203
diff -u -d -r1.203 io.m
--- library/io.m	2000/09/15 08:11:59	1.203
+++ library/io.m	2000/09/15 09:00:15
@@ -16,6 +16,9 @@
 % of the world argument is properly single-threaded, and will also check
 % to ensure that you don't attempt to backtrack over any I/O.
 %
+% Attempting any operation on a stream which has already been closed results
+% in undefined behaviour.
+%
 %-----------------------------------------------------------------------------%
 %-----------------------------------------------------------------------------%
 
@@ -404,7 +407,7 @@
 :- mode io__seen(di, uo) is det.
 %		Closes the current input stream.
 %		The current input stream reverts to standard input.
-%		This will all throw an io__error exception
+%		This will throw an io__error exception
 %		if an I/O error occurs.
 
 :- pred io__open_input(string, io__res(io__input_stream),
@@ -418,7 +421,7 @@
 :- mode io__close_input(in, di, uo) is det.
 %	io__close_input(File, IO0, IO1).
 %		Closes an open input stream.
-%		This will all throw an io__error exception
+%		This will throw an io__error exception
 %		if an I/O error occurs.
 
 :- pred io__input_stream(io__input_stream, io__state, io__state).
@@ -489,7 +492,7 @@
 %		Closes the current output stream.
 %		The default output stream reverts to standard output.
 %		As per Prolog told/0.
-%		This will all throw an io__error exception
+%		This will throw an io__error exception
 %		if an I/O error occurs.
 
 :- pred io__open_output(string, io__res(io__output_stream),
@@ -510,7 +513,7 @@
 :- mode io__close_output(in, di, uo) is det.
 %	io__close_output(File, IO0, IO1).
 %		Closes an open output stream.
-%		This will all throw an io__error exception
+%		This will throw an io__error exception
 %		if an I/O error occurs.
 
 :- pred io__output_stream(io__output_stream, io__state, io__state).
@@ -707,7 +710,7 @@
 :- mode io__seen_binary(di, uo) is det.
 %		Closes the current input stream.
 %		The current input stream reverts to standard input.
-%		This will all throw an io__error exception
+%		This will throw an io__error exception
 %		if an I/O error occurs.
 
 :- pred io__open_binary_input(string, io__res(io__binary_input_stream),
@@ -721,7 +724,7 @@
 :- mode io__close_binary_input(in, di, uo) is det.
 %	io__close_binary_input(File, IO0, IO1).
 %		Closes an open binary input stream.
-%		This will all throw an io__error exception
+%		This will throw an io__error exception
 %		if an I/O error occurs.
 
 :- pred io__binary_input_stream(io__binary_input_stream,
@@ -774,7 +777,7 @@
 %		Closes the current binary output stream.
 %		The default binary output stream reverts to standard output.
 %		As per Prolog told/0.
-%		This will all throw an io__error exception
+%		This will throw an io__error exception
 %		if an I/O error occurs.
 
 :- pred io__open_binary_output(string, io__res(io__binary_output_stream),
@@ -796,7 +799,7 @@
 :- mode io__close_binary_output(in, di, uo) is det.
 %	io__close_binary_output(File, IO0, IO1).
 %		Closes an open binary output stream.
-%		This will all throw an io__error exception
+%		This will throw an io__error exception
 %		if an I/O error occurs.
 
 :- pred io__binary_output_stream(io__binary_output_stream,
@@ -1468,10 +1471,10 @@
 io__read_file_as_string_2(Stream, Buffer0, Pos0, Size0, Buffer, Pos, Size) -->
 	io__read_into_buffer(Stream, Buffer0, Pos0, Size0,
 		Buffer1, Pos1),
-	( { Pos1 = Pos0 } ->
-		% end of file (or error)
+	( { Pos1 =< Pos0 } ->
+		% end-of-file or error
 		{ Size = Size0 },
-		{ Pos = Pos1 },
+		{ Pos = Pos0 },
 		{ Buffer = Buffer1 }
 	; { Pos1 = Size0 } ->
 		% full buffer
@@ -2856,8 +2859,96 @@
 
 ").
 
+%------------------------------------------------------------------------------%
+%------------------------------------------------------------------------------%
+
 :- pragma c_code("
 
+#ifdef MR_NEW_MERCURYFILE_STRUCT
+
+#include <errno.h>
+
+#ifdef EBADF
+  #define MR_CLOSED_FILE_ERROR	EBADF
+#else
+  /* ANSI/ISO C guarantees that EDOM will exist */
+  #define MR_CLOSED_FILE_ERROR	EDOM
+#endif
+
+static int
+ME_closed_stream_close(MR_StreamInfo *info)
+{
+	errno = MR_CLOSED_FILE_ERROR;
+	return EOF;
+}
+
+static int
+ME_closed_stream_read(MR_StreamInfo *info, void *buffer, size_t size)
+{ 
+	errno = MR_CLOSED_FILE_ERROR;
+	return -1;	/* XXX should this be 0? */
+}
+
+static int
+ME_closed_stream_write(MR_StreamInfo *info, const void *buffer, size_t size)
+{
+	errno = MR_CLOSED_FILE_ERROR;
+	return -1;	/* XXX should this be 0? */
+}
+  
+static int
+ME_closed_stream_flush(MR_StreamInfo *info)
+{
+	errno = MR_CLOSED_FILE_ERROR;
+	return EOF;
+}
+
+static int
+ME_closed_stream_ungetch(MR_StreamInfo *info, int ch)
+{
+	errno = MR_CLOSED_FILE_ERROR;
+	return EOF;
+}
+
+static int
+ME_closed_stream_getch(MR_StreamInfo *info) 
+{
+	errno = MR_CLOSED_FILE_ERROR;
+	return EOF;
+}
+ 
+static int
+ME_closed_stream_vfprintf(MR_StreamInfo *info, const char *format, va_list ap)
+{
+	errno = MR_CLOSED_FILE_ERROR;
+	return EOF;
+}
+
+static int
+ME_closed_stream_putch(MR_StreamInfo *info, int ch)
+{
+	errno = MR_CLOSED_FILE_ERROR;
+	return EOF;
+}
+
+static const MercuryFile MR_closed_stream = {
+	/* stream_type	= */	MR_USER_STREAM,
+	/* stream_info	= */	{ NULL },
+	/* line_number	= */	0,
+
+	/* close	= */	ME_closed_stream_close,
+	/* read		= */	ME_closed_stream_read,
+	/* write	= */	ME_closed_stream_write,
+
+	/* flush	= */	ME_closed_stream_flush,
+	/* ungetc	= */	ME_closed_stream_ungetch,
+	/* getc		= */	ME_closed_stream_getch,
+	/* vprintf	= */	ME_closed_stream_vfprintf,
+	/* putc		= */	ME_closed_stream_putch
+};
+
+#endif /* MR_NEW_MERCURYFILE_STRUCT */
+
 void
 mercury_close(MercuryFile* mf)
 {
@@ -2869,7 +2960,48 @@
 			mercury_io_error(mf, ""error closing file: %s"",
 				strerror(errno));
 		}
-		MR_GC_free(mf);
+
+#ifdef MR_NEW_MERCURYFILE_STRUCT
+
+		/*
+		** MR_closed_stream is a dummy stream object containing
+		** pointers to functions that always return an error
+		** indication.
+		** Doing this ensures that future accesses to the file
+		** will fail nicely.
+		*/
+		*mf = MR_closed_stream;
+
+/*
+** XXX it would be nice to have an autoconf check
+** for the GNU libc function fopencookie();
+** we could use that to do a similar thing to what
+** we do in the MR_NEW_MERCURYFILE_STRUCT case.
+*/
+
+/****
+#elif defined(HAVE_FOPENCOOKIE)
+		MR_file(*mf) = MR_closed_file;
+****/
+
+#else
+
+		/*
+		** We want future accesses to the file to fail nicely.
+		** Ideally they would throw an exception, but that would
+		** require a check at every I/O operation, and for simple
+		** operations like putchar() or getchar(), that would be
+		** too expensive.  Instead we just set the file pointer
+		** to NULL; on systems which trap null pointer dereferences,
+		** or if library/io.m is compiled with MR_assert assertions
+		** enabled (i.e. -DMR_LOWLEVEL_DEBUG), this will ensure that
+		** accessing closed files traps immediately rather than
+		** causing problems at some later point.
+		*/
+		MR_mercuryfile_init(NULL, 0, mf);
+
+#endif /* ! MR_NEW_MERCURYFILE_STRUCT */
+
 	}
 }
 

-- 
Fergus Henderson <fjh at cs.mu.oz.au>  |  "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh>  |  of excellence is a lethal habit"
PGP: finger fjh at 128.250.37.3        |     -- the last words of T. S. Garp.
--------------------------------------------------------------------------
mercury-developers mailing list
Post messages to:       mercury-developers at cs.mu.oz.au
Administrative Queries: owner-mercury-developers at cs.mu.oz.au
Subscriptions:          mercury-developers-request at cs.mu.oz.au
--------------------------------------------------------------------------



More information about the developers mailing list