[m-rev.] For review: Java implementation of IO library

James Goddard goddardjames at yahoo.com
Wed Jan 14 14:27:32 AEDT 2004


This is the new diff for io.m
interdiff was impossible, since there were too many changes, so this is
the whole thing again.  It's probably easier to read this way anyway.

Index: io.m
===================================================================
RCS file: /home/mercury1/repository/mercury/library/io.m,v
retrieving revision 1.316
diff -u -d -r1.316 io.m
--- io.m	12 Jan 2004 04:39:33 -0000	1.316
+++ io.m	14 Jan 2004 03:24:43 -0000
@@ -1168,6 +1168,11 @@
 	% On other systems, the file will reside in /tmp if the TMPDIR
 	% environment variable is not set, or in the directory specified
 	% by TMPDIR if it is set.
+	% For the Java implementation, the system-dependent default
+	% temporary-file directory will be used, specified by the system
+	% property java.io.tmpdir. On UNIX systems the default value of this
+	% property is typically "/tmp" or "/var/tmp"; on Microsoft Windows
+	% systems it is typically "c:\\temp". 
 	% It is the responsibility of the program to delete the file
 	% when it is no longer needed.
 
@@ -1654,6 +1659,14 @@
 		ML_file_encoding_kind.ML_OS_text_encoding;
 ").
 
+:- pragma foreign_code("Java",
+"
+	static java.lang.Object	ML_io_stream_db =
+			new mercury.tree234.tree234_2.empty_0();
+	static java.lang.Object	ML_io_user_globals =
+			new mercury.tree234.tree234_2.empty_0();
+").
+
 
 :- type io__stream_putback ==	map(io__stream_id, list(char)).
 
@@ -1666,6 +1679,7 @@
 :- pragma foreign_type("C", io__stream, "MercuryFilePtr").
 :- pragma foreign_type("il", io__stream,
 	"class [mercury]mercury.io__csharp_code.MR_MercuryFileStruct").
+:- pragma foreign_type("Java", io__stream, "mercury.io.MR_MercuryFileStruct").
 
 	% a unique identifier for an IO stream
 :- type io__stream_id == int.
@@ -2164,6 +2178,12 @@
 	// in MF_Mercury_file for compatibility)
 }").
 
+:- pragma foreign_proc("Java",
+	io__clear_err(_Stream::in, _IO0::di, _IO::uo),
+	[will_not_call_mercury, promise_pure, thread_safe],
+"
+	// XXX as for .NET above
+").
 
 :- pred io__check_err(stream, io__res, io__state, io__state).
 :- mode io__check_err(in, out, di, uo) is det.
@@ -2203,6 +2223,14 @@
 	RetVal = 0;
 }").
 
+:- pragma foreign_proc("Java",
+	ferror(_Stream::in, RetVal::out, _RetStr::out, _IO0::di, _IO::uo),
+	[will_not_call_mercury, promise_pure, thread_safe],
+"{
+	// XXX see clearerr
+	RetVal = 0;
+}").
+
 :- pred io__make_err_msg(string, string, io__state, io__state).
 :- mode io__make_err_msg(in, out, di, uo) is det.
 
@@ -2228,6 +2256,13 @@
 	Error = MR_io_exception;
 }").
 
+:- pragma foreign_proc("Java",
+	io__get_system_error(Error::out, _IO0::di, _IO::uo),
+	[will_not_call_mercury, promise_pure, tabled_for_io, thread_safe],
+"{
+	Error = MR_io_exception;
+}").
+
 :- pragma export(make_err_msg(in, in, out, di, uo), "ML_make_err_msg").
 :- pragma foreign_proc("C",
 	make_err_msg(Error::in, Msg0::in, Msg::out, IO0::di, IO::uo),
@@ -2244,6 +2279,17 @@
 	Msg = System.String.Concat(Msg0, Error.Message);
 }").
 
+:- pragma foreign_proc("Java",
+	make_err_msg(Error::in, Msg0::in, Msg::out, _IO0::di, _IO::uo),
+	[will_not_call_mercury, promise_pure],
+"{
+	if (Error.getMessage() != null) {
+		Msg = Msg0 + Error.getMessage();
+	} else {
+		Msg = Msg0;
+	}
+}").
+
 have_win32 :- semidet_fail.
 
 :- pragma foreign_proc("C",
@@ -2353,6 +2399,13 @@
 	}
 }").
 
+:- pragma foreign_proc("Java",
+	io__stream_file_size(Stream::in, Size::out, _IO0::di, _IO::uo),
+	[will_not_call_mercury, promise_pure, thread_safe],
+"
+	Size = Stream.size();
+").
+
 io__file_modification_time(File, Result) -->
 	io__file_modification_time_2(File, Status, Msg, Time),
 	{ Status = 1 ->
@@ -2407,6 +2460,27 @@
 	}
 }").
 
+:- pragma foreign_proc("Java",
+	io__file_modification_time_2(FileName::in, Status::out, Msg::out,
+		Time::out, _IO0::di, _IO::uo),
+	[will_not_call_mercury, promise_pure, tabled_for_io, thread_safe],
+"
+	java.util.Date date = new java.util.Date();
+	try {
+		long time = (new java.io.File(FileName)).lastModified();
+		if (time == 0) {
+			throw new java.lang.Exception(
+					""File not found or I/O error"");
+		}
+		date.setTime(time);
+		Msg = """";
+		Status = 1;
+	} catch (java.lang.Exception e) {
+		Msg = ""lastModified() failed: "" + e.getMessage();
+		Status = 0;
+	}
+	Time = date;
+").
 
 
 %-----------------------------------------------------------------------------%
@@ -2436,6 +2510,11 @@
 	[will_not_call_mercury, promise_pure, thread_safe],
 	"SUCCESS_INDICATOR = true;"
 ).
+:- pragma foreign_proc("Java", file_type_implemented,
+	[will_not_call_mercury, promise_pure, thread_safe],
+"
+	succeeded = true;
+").
 
 :- pred io__file_type_2(int, string, io__res(io__file_type),
 		io__state, io__state).
@@ -2605,6 +2684,28 @@
     }
 ").
 
+:- pragma foreign_proc("Java",
+	io__file_type_2(_FollowSymLinks::in, FileName::in,
+		Result::out, _IO0::di, _IO::uo),
+	[may_call_mercury, promise_pure, tabled_for_io, thread_safe],
+"
+	java.io.File file = new java.io.File(FileName);
+
+	// The Java implementation can distinguish between regular files and
+	// directories, and for everything else it just returns unknown.
+
+	if (file.isFile()) {
+		Result = new mercury.io.res_1.ok_1(new mercury.io.file_type_0(
+				mercury.io.file_type_0.regular_file));
+	} else if (file.isDirectory()) {
+		Result = new mercury.io.res_1.ok_1(new mercury.io.file_type_0(
+				mercury.io.file_type_0.directory));
+	} else {
+		Result = new mercury.io.res_1.ok_1(new mercury.io.file_type_0(
+				mercury.io.file_type_0.unknown));
+	}
+").
+
 :- func file_type_character_device = file_type.
 :- func file_type_block_device = file_type.
 :- func file_type_fifo = file_type.
@@ -2707,6 +2808,52 @@
 	IO = IO0;
 }").
 
+:- pragma foreign_proc("Java",
+	io__check_file_accessibility_2(FileName::in, AccessTypes::in,
+		Result::out, _IO0::di, _IO::uo),
+	[may_call_mercury, promise_pure, tabled_for_io, thread_safe],
+"
+	java.lang.String permissions = null;
+
+	if (access_types_includes_read_1_p_0(
+			(mercury.list.list_1) AccessTypes))
+	{
+		permissions = ""read"";
+	}
+
+	if (access_types_includes_write_1_p_0(
+			(mercury.list.list_1) AccessTypes))
+	{
+		if (permissions == null) {
+			permissions = ""write"";
+		} else {
+			permissions = ""read,write"";
+		}
+	}
+
+	if (access_types_includes_execute_1_p_0(
+			(mercury.list.list_1) AccessTypes))
+	{
+		if (permissions == null) {
+			permissions = ""execute"";
+		} else {
+			permissions = permissions + "",execute"";
+		}
+	}
+
+	try {
+		if (permissions != null) {
+			java.lang.System.getSecurityManager().checkPermission(
+					new java.io.FilePermission(
+					FileName, permissions));
+		}
+		Result = make_io_res_0_ok_0_f_0();
+	}
+	catch (java.lang.Exception e) {
+		Result = make_io_res_0_error_msg_1_f_0(e.getMessage());
+	}
+").
+
 	% The .NET CLI doesn't provide an equivalent of access(), so
 	% we have to try to open the file to see if it is accessible.
 :- pred io__check_file_accessibility_dotnet(string::in, list(access_type)::in,
@@ -2974,6 +3121,14 @@
 	}
 ").
 
+:- pragma foreign_proc("Java",
+	compare_file_id_2(_Res::out, _FileId1::in, _FileId2::in),
+	[will_not_call_mercury, promise_pure, thread_safe],
+"
+	throw new java.lang.RuntimeException(
+			""File IDs are not supported by Java."");
+").
+
 io__file_id(FileName, Result) -->
 	( { have_file_ids } ->
 		io__file_id_2(FileName, Status, Msg, FileId),
@@ -3013,6 +3168,19 @@
 #endif
 }").
 
+:- pragma foreign_proc("Java",
+	io__file_id_2(_FileName::in, _Status::out, _Msg::out,
+		_FileId::out, _IO0::di, _IO::uo),
+	[will_not_call_mercury, promise_pure, tabled_for_io, thread_safe],
+"
+	// This function should never be called, since have_file_ids will
+	// fail for Java.
+	if (true) {	// otherwise Java complains about unreachable stmts.
+		throw new RuntimeException(
+				""io.file_id_2 called but not supported"");
+	}
+").
+
 % Can we retrieve inode numbers on this system.
 have_file_ids :- semidet_fail.
 :- pragma foreign_proc("C", have_file_ids,
@@ -4211,6 +4379,20 @@
 	ML_io_stream_db = StreamDb;
 ").
 
+:- pragma foreign_proc("Java", 
+	io__get_stream_db(StreamDb::out, _IO0::di, _IO::uo), 
+	[will_not_call_mercury, promise_pure, tabled_for_io],
+"
+	StreamDb = ML_io_stream_db;
+").
+
+:- pragma foreign_proc("Java", 
+	io__set_stream_db(StreamDb::in, _IO0::di, _IO::uo), 
+	[will_not_call_mercury, promise_pure, tabled_for_io],
+"
+	ML_io_stream_db = StreamDb;
+").
+
 %-----------------------------------------------------------------------------%
 
 :- pred io__insert_stream_info(io__stream::in, stream_info::in,
@@ -4294,6 +4476,20 @@
 	ML_io_user_globals = Globals;
 ").
 
+:- pragma foreign_proc("Java", 
+	io__get_globals(Globals::uo, _IOState0::di, _IOState::uo), 
+	[will_not_call_mercury, promise_pure, tabled_for_io],
+"
+	Globals = ML_io_user_globals;
+").
+
+:- pragma foreign_proc("Java", 
+	io__set_globals(Globals::di, _IOState0::di, _IOState::uo), 
+	[will_not_call_mercury, promise_pure, tabled_for_io],
+"
+	ML_io_user_globals = Globals;
+").
+
 io__progname_base(DefaultName, PrognameBase) -->
 	io__progname(DefaultName, Progname),
 	{ PrognameBase = dir__basename_det(Progname) }.
@@ -4326,6 +4522,13 @@
 	Id = Stream.id;
 ").
 
+:- pragma foreign_proc("Java",
+	io__get_stream_id(Stream::in) = (Id::out), 
+	[will_not_call_mercury, promise_pure],
+"
+	Id = Stream.id;
+").
+
 %-----------------------------------------------------------------------------%
 %-----------------------------------------------------------------------------%
 
@@ -4615,6 +4818,332 @@
 }
 ").
 
+:- pragma foreign_code("Java",
+"
+	// stdin, stdout, stderr and all text files are run through stream
+	// readers/writers, which use the default charset encoding.  In other
+	// words, while strings and characters are stored internally using
+	// unicode, all files are read and written using the default system
+	// charset.
+	// Binary files are opened via RandomAccessFile, which supports seek,
+	// but not character encoding/decoding or buffering.
+	
+	public static class MR_MercuryFileStruct {
+		public	static int			ML_next_stream_id = 0;
+		public	int				id;
+
+		public	int				line_number;
+
+		public	static final int		INPUT		= 0;
+		public	static final int		OUTPUT		= 1;
+		private int				mode;
+
+		private static final int		SEEK_SET	= 0;
+		private static final int		SEEK_CUR	= 1;
+		private static final int		SEEK_END	= 2;
+
+		private	java.util.Stack			pushback	= null;
+		private java.io.InputStreamReader	input		= null;
+		private java.io.OutputStreamWriter	output		= null;
+		private java.io.RandomAccessFile	randomaccess	= null;
+
+		private java.lang.String		filename	= null;
+
+		public MR_MercuryFileStruct(java.io.InputStream stream) {
+			line_number	= 1;
+			id		= ML_next_stream_id++;
+			mode		= INPUT;
+			pushback	= new java.util.Stack();
+			input		= new java.io.InputStreamReader(
+							stream);
+		}
+
+		public MR_MercuryFileStruct(java.io.OutputStream stream) {
+			line_number	= 1;
+			id		= ML_next_stream_id++;
+			mode		= OUTPUT;
+			output		= new java.io.OutputStreamWriter(
+							stream);
+		}
+
+		public MR_MercuryFileStruct(java.lang.String file, char mode) {
+			line_number	= 1;
+			id		= ML_next_stream_id++;
+			filename	= file;
+			String openstring;
+			if (mode == 'r') {
+				openstring = ""r"";
+				this.mode = INPUT;
+				pushback = new java.util.Stack();
+			} else if (mode == 'r' || mode == 'a') {
+				openstring = ""rw"";
+				this.mode = OUTPUT;
+				// There is no such mode as ""w"", which could
+				// be a problem for write-only files.
+			} else {
+				throw new RuntimeException(
+						""Invalid file opening mode"");
+			}
+			try {
+				randomaccess	= new java.io.RandomAccessFile(
+						file, openstring);
+				if (mode == 'a') {
+					seek(SEEK_END, 0);
+				}
+			} catch (java.lang.Exception e) {
+				throw new RuntimeException(e.getMessage());
+				// We can't just throw e or the Java compiler
+				// will complain about unreported exceptions.
+			}
+		}
+
+		public int size() {
+			try {
+				return (int) randomaccess.length();
+			} catch (java.lang.Exception e) {
+				return -1;
+			}
+		}
+
+		public void seek(int flag, int offset) {
+			if (randomaccess == null) {
+				throw new java.lang.RuntimeException(
+						""Stream not seekable"");
+				// this applies to stdin, stdout and stderr
+			}
+			pushback = new java.util.Stack();
+			try {
+				switch (flag) {
+					case SEEK_SET:
+						randomaccess.seek(offset);
+						break;
+					case SEEK_CUR:
+						randomaccess.seek(
+							randomaccess.
+							getFilePointer() +
+							offset);
+						break;
+					case SEEK_END:
+						randomaccess.seek(
+							randomaccess.length() +
+							offset);
+						break;
+					default:
+						throw new java.lang.
+							RuntimeException(
+							""Invalid seek flag"");
+				}
+			} catch (java.lang.Exception e) {
+				throw new java.lang.RuntimeException(
+						e.getMessage());
+			}
+		}
+
+		public int getOffset() {
+			try {
+				return (int) randomaccess.getFilePointer();
+			} catch (java.lang.Exception e) {
+				return -1;
+			}
+		}
+
+		/* read_char():
+		**	Reads one character in using the default charset
+		**	decoding.  Returns -1 at end of file.
+		*/
+		public int read_char() {
+			int c;
+			if (input == null) {
+				throw new java.lang.RuntimeException(
+					""read_char_code may only be called"" +
+					"" on text input streams"");
+			}
+			if (pushback.empty()) {
+				try {
+					c = input.read();
+				} catch (java.io.IOException e) {
+					throw new java.lang.RuntimeException(
+							e.getMessage());
+				}
+			} else {
+				c = ((java.lang.Integer)pushback.pop()).
+						intValue();
+			}
+			if (c == '\\n') {
+				line_number++;
+			}
+
+			return c;
+		}
+
+		/* read_char():
+		**	Reads one byte in from a binary file.
+		**	Returns -1 at end of file.
+		*/
+		public int read_byte() {
+			int c;
+			if (mode == OUTPUT) {
+				throw new java.lang.RuntimeException(
+					""Attempted to read output stream"");
+			}
+			if (randomaccess == null) {
+				throw new java.lang.RuntimeException(
+					""read_byte_val may only be called"" +
+					"" on binary input streams"");
+			}
+			if (pushback.empty()) {
+				try {
+					c = randomaccess.read();
+				} catch (java.io.IOException e) {
+					throw new java.lang.RuntimeException(
+							e.getMessage());
+				}
+			} else {
+				c = ((java.lang.Integer)pushback.pop()).
+						intValue();
+			}
+			if (c == '\\n') {
+				line_number++;
+			}
+
+			return c;
+		}
+
+		public void ungetc(int c) {
+			if (mode == OUTPUT) {
+				throw new java.lang.RuntimeException(
+				""Attempted to unget char to output stream"");
+			}
+			if (c == '\\n') {
+				line_number--;
+			}
+
+			pushback.push(new Integer(c));
+		}
+
+		public void putc(int c) {
+			if (mode == INPUT) {
+				throw new java.lang.RuntimeException(
+					""Attempted to write to input stream"");
+			}
+			if (c == '\\n') {
+				line_number++;
+			}
+	
+			try {
+				if (output != null) {
+					output.write(c);
+				} else {
+					randomaccess.write(c);
+				}
+			} catch (java.io.IOException e) {
+				throw new java.lang.RuntimeException(
+						e.getMessage());
+			}
+		}
+
+		public void write(java.lang.String s) {
+			if (mode == INPUT) {
+				throw new java.lang.RuntimeException(
+					""Attempted to write to input stream"");
+			}
+			for (int i = 0; i < s.length(); i++) {
+				if (s.charAt(i) == '\\n') {
+					line_number++;
+				}
+			}
+			
+			try {
+				if (output != null) {
+					output.write(s);
+				} else {
+					randomaccess.write(s.getBytes());
+					// XXX for binary files, the call to
+					// getBytes() results in unspecified
+					// behaviour if the string cannot be
+					// decoded.
+				}
+			} catch (java.io.IOException e) {
+				throw new java.lang.RuntimeException(
+						e.getMessage());
+			}
+		}
+
+		public void flush() {
+			if (mode == INPUT) {
+				throw new java.lang.RuntimeException(
+					""Attempted to flush input stream"");
+			}
+
+			try {
+				if (output != null) {
+					output.flush();
+				}
+				// else randomaccess is already unbuffered.
+			} catch (java.io.IOException e) {
+				throw new java.lang.RuntimeException(
+						e.getMessage());
+			}
+		}
+
+		public void close() {
+			try {
+				if (input != null) {
+					input.close();
+				} else if (output != null) {
+					output.close();
+				} else {
+					randomaccess.close();
+				}
+			} catch (java.io.IOException e) {
+				throw new java.lang.RuntimeException(
+						""Error closing stream"");
+			}
+		}
+	} // class MR_MercuryFileStruct
+
+	// StreamPipe is a mechanism for connecting streams to those of a
+	// Runtime.exec() Process.
+
+	private static class StreamPipe extends java.lang.Thread {
+		MR_MercuryFileStruct in;
+		MR_MercuryFileStruct out;
+		boolean live			= true;
+		boolean closeOutput		= false;
+		java.lang.Exception exception	= null;
+
+		StreamPipe(java.io.InputStream in, MR_MercuryFileStruct out) {
+			this.in  = new MR_MercuryFileStruct(in);
+			this.out = out;
+		}
+
+		StreamPipe(MR_MercuryFileStruct in, java.io.OutputStream out) {
+			this.in  = in;
+			this.out = new MR_MercuryFileStruct(out);
+			closeOutput = true;
+		}
+
+		public void run() {
+			try {
+				while (live) {
+					int b = in.read_char();
+					if (b == -1) {
+						break;
+					}
+					out.putc(b);
+				}
+				out.flush();
+				if (closeOutput) {
+					out.close();
+				}
+			}
+			catch (java.lang.Exception e) {
+				exception = e;
+			}
+		}
+	} // class StreamPipe
+").
+
 :- pragma foreign_code("C", "
 
 MercuryFile mercury_stdin;
@@ -4716,6 +5245,28 @@
 
 ").
 
+:- pragma foreign_code("Java",
+"
+static MR_MercuryFileStruct mercury_stdin =
+		new MR_MercuryFileStruct(java.lang.System.in);
+static MR_MercuryFileStruct mercury_stdout =
+		new MR_MercuryFileStruct(java.lang.System.out);
+static MR_MercuryFileStruct mercury_stderr =
+		new MR_MercuryFileStruct(java.lang.System.err);
+static MR_MercuryFileStruct mercury_stdin_binary =
+		new MR_MercuryFileStruct(java.lang.System.in);
+static MR_MercuryFileStruct mercury_stdout_binary =
+		new MR_MercuryFileStruct(java.lang.System.out);
+
+static MR_MercuryFileStruct mercury_current_text_input = mercury_stdin;
+static MR_MercuryFileStruct mercury_current_text_output = mercury_stdout;
+static MR_MercuryFileStruct mercury_current_binary_input = mercury_stdin_binary;
+static MR_MercuryFileStruct mercury_current_binary_output =
+		mercury_stdout_binary;
+		
+static java.lang.Exception MR_io_exception;
+").
+
 
 :- pragma foreign_code("C", "
 
@@ -4795,7 +5346,6 @@
 
 ").
 
-
 :- pred throw_io_error(string::in) is erroneous.
 :- pragma export(throw_io_error(in), "ML_throw_io_error").
 throw_io_error(Message) :- throw(io_error(Message)).
@@ -4922,6 +5472,7 @@
 
 ").
 
+
 :- pragma foreign_code("C", "
 
 void
@@ -5399,6 +5950,35 @@
 	mf.putback = Byte;
 }").
 
+:- pragma foreign_proc("Java", 
+	io__read_char_code(File::in, CharCode::out, _IO0::di, _IO::uo),
+	[will_not_call_mercury, promise_pure],
+"
+	CharCode = File.read_char();
+").
+
+:- pragma foreign_proc("Java", 
+	io__read_byte_val(File::in, ByteVal::out, _IO0::di, _IO::uo),
+	[will_not_call_mercury, promise_pure],
+"
+	ByteVal = File.read_byte();
+").
+
+:- pragma foreign_proc("Java",
+	io__putback_char(File::in, Character::in, _IO0::di, _IO::uo),
+	[may_call_mercury, promise_pure],
+"
+	File.ungetc(Character);
+").
+
+:- pragma foreign_proc("Java",
+	io__putback_byte(File::in, Byte::in, _IO0::di, _IO::uo),
+	[may_call_mercury, promise_pure],
+"
+	File.ungetc(Byte);
+").
+
+
 /* output predicates - with output to mercury_current_text_output */
 
 :- pragma foreign_proc("C", 
@@ -5581,6 +6161,34 @@
 	System.out.print(Val);
 ").
 
+:- pragma foreign_proc("Java",
+	io__write_byte(Byte::in, _IO0::di, _IO::uo),
+	[may_call_mercury, promise_pure, thread_safe, tabled_for_io],
+"
+	mercury_current_binary_output.putc(Byte);
+").
+
+:- pragma foreign_proc("Java",
+	io__write_bytes(Message::in, _IO0::di, _IO::uo),
+	[may_call_mercury, promise_pure, thread_safe, tabled_for_io],
+"{
+	mercury_current_binary_output.write(Message);
+}").
+
+:- pragma foreign_proc("Java",
+	io__flush_output(_IO0::di, _IO::uo),
+	[may_call_mercury, promise_pure, thread_safe, tabled_for_io],
+"
+	mercury_current_text_output.flush();
+").
+
+:- pragma foreign_proc("Java",
+	io__flush_binary_output(_IO0::di, _IO::uo),
+	[may_call_mercury, promise_pure, thread_safe, tabled_for_io],
+"
+	mercury_current_binary_output.flush();
+").
+
 io__write_float(Float) -->
 	io__write_string(string__float_to_string(Float)).
 
@@ -5784,6 +6392,76 @@
 	Stream.stream.Flush();
 }").
 
+:- pragma foreign_proc("Java",
+	io__seek_binary_2(Stream::in, Flag::in, Off::in, _IO0::di, _IO::uo),
+	[will_not_call_mercury, promise_pure, tabled_for_io, thread_safe],
+"
+	Stream.seek(Flag, Off);
+").
+
+:- pragma foreign_proc("Java",
+	io__binary_stream_offset(Stream::in, Offset::out, _IO0::di, _IO::uo),
+	[will_not_call_mercury, promise_pure, tabled_for_io, thread_safe],
+"
+	Offset = Stream.getOffset();
+").
+
+:- pragma foreign_proc("Java",
+	io__write_string(Stream::in, Message::in, _IO0::di, _IO::uo),
+	[may_call_mercury, promise_pure, thread_safe, tabled_for_io], 
+"
+	Stream.write(Message);
+").
+
+:- pragma foreign_proc("Java",
+	io__write_char(Stream::in, Character::in, _IO0::di, _IO::uo),
+	[may_call_mercury, promise_pure, thread_safe, tabled_for_io],
+"
+	Stream.putc(Character);
+").
+
+:- pragma foreign_proc("Java",
+	io__write_int(Stream::in, Val::in, _IO0::di, _IO::uo),
+	[may_call_mercury, promise_pure, tabled_for_io, thread_safe],
+"
+	Stream.write(java.lang.String.valueOf(Val));
+").
+
+:- pragma foreign_proc("Java",
+	io__write_float(Stream::in, Val::in, _IO0::di, _IO::uo),
+	[may_call_mercury, promise_pure, tabled_for_io, thread_safe],
+"
+	Stream.write(java.lang.String.valueOf(Val));
+").
+
+:- pragma foreign_proc("Java",
+	io__write_byte(Stream::in, Byte::in, _IO0::di, _IO::uo),
+	[may_call_mercury, promise_pure, thread_safe, tabled_for_io],
+"
+	Stream.putc(Byte);
+").
+
+:- pragma foreign_proc("Java",
+	io__write_bytes(Stream::in, Message::in, _IO0::di, _IO::uo),
+	[may_call_mercury, promise_pure, thread_safe, tabled_for_io],
+"
+	Stream.write(Message);
+").
+
+:- pragma foreign_proc("Java",
+	io__flush_output(Stream::in, _IO0::di, _IO::uo),
+	[may_call_mercury, promise_pure, thread_safe, tabled_for_io],
+"
+	Stream.flush();
+").
+
+:- pragma foreign_proc("Java",
+	io__flush_binary_output(Stream::in, _IO0::di, _IO::uo),
+	[may_call_mercury, promise_pure, thread_safe, tabled_for_io],
+"
+	Stream.flush();
+").
+
 io__write_float(Stream, Float) -->
 	io__write_string(Stream, string__float_to_string(Float)).
 
@@ -6131,6 +6809,162 @@
 	mercury_current_binary_output = NewStream;
 ").
 
+:- pragma foreign_proc("Java",
+	io__stdin_stream(Stream::out, _IO0::di, _IO::uo),
+	[will_not_call_mercury, promise_pure, thread_safe, tabled_for_io],
+"
+	Stream = mercury_stdin;
+").
+
+:- pragma foreign_proc("Java",
+	io__stdout_stream(Stream::out, _IO0::di, _IO::uo),
+	[will_not_call_mercury, promise_pure, thread_safe, tabled_for_io],
+"
+	Stream = mercury_stdout;
+").
+
+:- pragma foreign_proc("Java",
+	io__stderr_stream(Stream::out, _IO0::di, _IO::uo),
+	[will_not_call_mercury, promise_pure, thread_safe, tabled_for_io],
+"
+	Stream = mercury_stderr;
+").
+
+:- pragma foreign_proc("Java",
+	io__stdin_binary_stream(Stream::out, _IO0::di, _IO::uo),
+	[will_not_call_mercury, promise_pure, thread_safe, tabled_for_io],
+"
+	Stream = mercury_stdin_binary;
+").
+
+:- pragma foreign_proc("Java",
+	io__stdout_binary_stream(Stream::out, _IO0::di, _IO::uo),
+	[will_not_call_mercury, promise_pure, thread_safe, tabled_for_io],
+"
+	Stream = mercury_stdout_binary;
+").
+
+:- pragma foreign_proc("Java",
+	io__input_stream(Stream::out, _IO0::di, _IO::uo),
+	[will_not_call_mercury, promise_pure, tabled_for_io],
+"
+	Stream = mercury_current_text_input;
+").
+
+:- pragma foreign_proc("Java",
+	io__output_stream(Stream::out, _IO0::di, _IO::uo),
+	[will_not_call_mercury, promise_pure, tabled_for_io],
+"
+	Stream = mercury_current_text_output;
+").
+
+:- pragma foreign_proc("Java",
+	io__binary_input_stream(Stream::out, _IO0::di, _IO::uo),
+	[will_not_call_mercury, promise_pure, tabled_for_io],
+"
+	Stream = mercury_current_binary_input;
+").
+
+:- pragma foreign_proc("Java",
+	io__binary_output_stream(Stream::out, _IO0::di, _IO::uo),
+	[will_not_call_mercury, promise_pure, tabled_for_io],
+"
+	Stream = mercury_current_binary_output;
+").
+
+:- pragma foreign_proc("Java",
+	io__get_line_number(LineNum::out, _IO0::di, _IO::uo),
+	[will_not_call_mercury, promise_pure, tabled_for_io],
+"
+	LineNum = mercury_current_text_input.line_number;
+").
+
+:- pragma foreign_proc("Java",
+	io__get_line_number(Stream::in, LineNum::out, _IO0::di, _IO::uo),
+	[will_not_call_mercury, promise_pure, tabled_for_io],
+"{
+	LineNum = Stream.line_number;
+}").
+
+:- pragma foreign_proc("Java",
+	io__set_line_number(LineNum::in, _IO0::di, _IO::uo),
+	[will_not_call_mercury, promise_pure, tabled_for_io],
+"
+	mercury_current_text_input.line_number = LineNum;
+").
+
+:- pragma foreign_proc("Java",
+	io__set_line_number(Stream::in, LineNum::in, _IO0::di, _IO::uo),
+	[will_not_call_mercury, promise_pure, tabled_for_io],
+"{
+	Stream.line_number = LineNum;
+}").
+
+:- pragma foreign_proc("Java",
+	io__get_output_line_number(LineNum::out, _IO0::di, _IO::uo),
+	[will_not_call_mercury, promise_pure, tabled_for_io],
+"
+	LineNum = mercury_current_text_output.line_number;
+").
+
+:- pragma foreign_proc("Java",
+	io__get_output_line_number(Stream::in, LineNum::out, _IO0::di, _IO::uo),
+	[will_not_call_mercury, promise_pure, tabled_for_io],
+"{
+	LineNum = Stream.line_number;
+}").
+
+:- pragma foreign_proc("Java",
+	io__set_output_line_number(LineNum::in, _IO0::di, _IO::uo),
+	[will_not_call_mercury, promise_pure, tabled_for_io],
+"
+	mercury_current_text_output.line_number = LineNum;
+").
+
+:- pragma foreign_proc("Java",
+	io__set_output_line_number(Stream::in, LineNum::in, _IO0::di, _IO::uo),
+	[will_not_call_mercury, promise_pure, tabled_for_io],
+"{
+	Stream.line_number = LineNum;
+}").
+
+% io__set_input_stream(NewStream, OldStream, IO0, IO1)
+%	Changes the current input stream to the stream specified.
+%	Returns the previous stream.
+:- pragma foreign_proc("Java",
+	io__set_input_stream(NewStream::in, OutStream::out, _IO0::di, _IO::uo),
+	[will_not_call_mercury, promise_pure, tabled_for_io],
+"
+	OutStream = mercury_current_text_input;
+	mercury_current_text_input = NewStream;
+").
+
+:- pragma foreign_proc("Java",
+	io__set_output_stream(NewStream::in, OutStream::out, _IO0::di, _IO::uo),
+	[will_not_call_mercury, promise_pure, tabled_for_io],
+"
+	OutStream = mercury_current_text_output;
+	mercury_current_text_output = NewStream;
+").
+
+:- pragma foreign_proc("Java",
+	io__set_binary_input_stream(NewStream::in, OutStream::out,
+		_IO0::di, _IO::uo), 
+	[will_not_call_mercury, promise_pure, tabled_for_io],
+"
+	OutStream = mercury_current_binary_input;
+	mercury_current_binary_input = NewStream;
+").
+
+:- pragma foreign_proc("Java",
+	io__set_binary_output_stream(NewStream::in, OutStream::out,
+		_IO0::di, _IO::uo), 
+	[will_not_call_mercury, promise_pure, tabled_for_io],
+"
+	OutStream = mercury_current_binary_output;
+	mercury_current_binary_output = NewStream;
+").
+
 /* stream open/close predicates */
 
 %	io__do_open_binary(File, Mode, ResultCode, StreamId, Stream, IO0, IO):
@@ -6203,6 +7037,55 @@
 	}
 ").
 
+:- pragma foreign_proc("Java",
+	io__do_open_text(FileName::in, Mode::in, ResultCode::out,
+		StreamId::out, Stream::out, _IO0::di, _IO::uo),
+	[will_not_call_mercury, promise_pure, tabled_for_io, thread_safe],
+"
+	try {
+		if (Mode.charAt(0) == 'r') {
+			Stream = new MR_MercuryFileStruct(
+					new java.io.FileInputStream(FileName));
+		} else if (Mode.charAt(0) == 'w') {
+			Stream = new MR_MercuryFileStruct(
+					new java.io.FileOutputStream(
+					FileName));
+		} else if (Mode.charAt(0) == 'a') {
+			Stream = new MR_MercuryFileStruct(
+					new java.io.FileOutputStream(
+					FileName, true));
+		} else {
+			throw new java.lang.RuntimeException(
+					""io__do_open_text: Invalid open mode""
+					+ "" \\"""" + Mode + ""\\"""");
+		}
+		StreamId = Stream.id;
+		ResultCode = 0;
+	} catch (java.lang.Exception e) {
+		MR_io_exception = e;
+		Stream = null;
+		StreamId = -1;
+		ResultCode = -1;
+	}
+").
+
+:- pragma foreign_proc("Java",
+	io__do_open_binary(FileName::in, Mode::in, ResultCode::out,
+		StreamId::out, Stream::out, _IO0::di, _IO::uo),
+	[will_not_call_mercury, promise_pure, tabled_for_io, thread_safe],
+"
+	try {
+		Stream = new MR_MercuryFileStruct(FileName, Mode.charAt(0));
+		StreamId = Stream.id;
+		ResultCode = 0;
+	} catch (java.lang.Exception e) {
+		MR_io_exception = e;
+		Stream = null;
+		StreamId = -1;
+		ResultCode = -1;
+	}
+").
+
 io__close_input(Stream) -->
 	io__maybe_delete_stream_info(Stream),
 	io__close_stream(Stream).
@@ -6236,6 +7119,13 @@
 	mercury_close(Stream);
 ").
 
+:- pragma foreign_proc("Java",
+	io__close_stream(Stream::in, _IO0::di, _IO::uo),
+	[may_call_mercury, promise_pure, tabled_for_io, thread_safe],
+"
+	Stream.close();
+").
+
 /* miscellaneous predicates */
 
 :- pragma foreign_proc("C",
@@ -6438,6 +7328,95 @@
 	}
 ").
 
+:- pragma foreign_proc("Java",
+	io__progname(_Default::in, PrognameOut::out, _IO0::di, _IO::uo),
+	[will_not_call_mercury, promise_pure, tabled_for_io, thread_safe],
+"
+	PrognameOut = mercury.runtime.JavaInternal.progname;
+").
+
+:- pragma foreign_proc("Java",
+	io__get_exit_status(ExitStatus::out, _IO0::di, _IO::uo),
+	[will_not_call_mercury, promise_pure, tabled_for_io], 
+"
+	ExitStatus = mercury.runtime.JavaInternal.exit_status;
+").
+
+:- pragma foreign_proc("Java",
+	io__set_exit_status(ExitStatus::in, _IO0::di, _IO::uo),
+	[will_not_call_mercury, promise_pure, tabled_for_io], 
+"
+	mercury.runtime.JavaInternal.exit_status = ExitStatus;
+").
+
+io__command_line_arguments(Args, IO, IO) :-
+	build_command_line_args(0, Args).
+
+:- pred build_command_line_args(int, list(string)).
+:- mode build_command_line_args(in, out) is det.
+
+build_command_line_args(ArgNumber, Args) :-
+	( command_line_argument(ArgNumber, Arg) ->
+		Args = [Arg|MoreArgs],
+		build_command_line_args(ArgNumber + 1, MoreArgs)
+	;
+		Args = []
+	).
+
+:- pred command_line_argument(int, string).
+:- mode command_line_argument(in, out) is semidet.
+
+:- pragma foreign_proc("Java",
+	command_line_argument(ArgNum::in, Arg::out),
+	[will_not_call_mercury, promise_pure, thread_safe],
+"
+	String[] arg_vector = mercury.runtime.JavaInternal.args;
+
+	if (ArgNum < arg_vector.length && ArgNum >= 0) {
+		Arg = arg_vector[ArgNum];
+		succeeded = true;
+	} else {
+		Arg = null;
+		succeeded = false;
+	}
+").
+
+:- pragma foreign_proc("Java",
+	io__call_system_code(Command::in, Status::out, Msg::out,
+			_IO0::di, _IO::uo),
+	[will_not_call_mercury, promise_pure, tabled_for_io],
+"
+	try {
+		java.lang.Process process = java.lang.Runtime.getRuntime().
+				exec(Command);
+		StreamPipe stdin = new StreamPipe(mercury_stdin,
+				process.getOutputStream());
+		StreamPipe stdout = new StreamPipe(process.getInputStream(),
+				mercury_stdout);
+		StreamPipe stderr = new StreamPipe(process.getErrorStream(),
+				mercury_stderr);
+		stdin.start();
+		stdout.start();
+		stderr.start();
+
+		Status	= process.waitFor();
+		Msg	= null;
+
+		if (stdin.exception != null) {
+			throw stdin.exception;
+		}
+		if (stdout.exception != null) {
+			throw stdout.exception;
+		}
+		if (stderr.exception != null) {
+			throw stderr.exception;
+		}
+	} catch (java.lang.Exception e) {
+		Status	= 127;
+		Msg	= e.getMessage();
+	}
+").
+
 /*---------------------------------------------------------------------------*/
 
 /* io__getenv and io__setenv */
@@ -6464,6 +7443,29 @@
 	SUCCESS_INDICATOR = (Value != null);
 }").
 
+:- pragma foreign_proc("Java",
+	io__getenv(Var::in, Value::out),
+	[will_not_call_mercury, tabled_for_io],
+"
+	// Note that this approach only works for environmental variables that
+	// are recognized by Java and hava a special format.
+	// (eg os.name, user.timezone etc)
+	// To add custom environmental variables, they must be set at the
+	// command line with java's -D option
+	// (ie java -DENV_VARIABLE_NAME=$ENV_VARIABLE_NAME ClassName)
+	// XXX Perhaps a better approach would be to determine the OS at
+	// runtime and then Runtime.exec() the equivalent of 'env'?
+
+	try {
+		Value = java.lang.System.getProperty(Var);
+		succeeded = (Value != null);
+	} catch (java.lang.Exception e) {
+		Value = null;
+		succeeded = false;
+	}
+").
+
+
 io__setenv(Var, Value) :-
 	impure io__putenv(Var ++ "=" ++ Value).
 
@@ -6497,6 +7499,33 @@
 	SUCCESS_INDICATOR = (mercury.runtime.PInvoke._putenv(VarAndValue) == 0);
 ").
 
+:- pragma foreign_proc("Java",
+	io__setenv(Var::in, Value::in),
+	[will_not_call_mercury, tabled_for_io],
+"
+	// XXX see io__getenv/2
+
+	try {
+		Value = java.lang.System.setProperty(Var, Value);
+		succeeded = true;
+	} catch (java.lang.Exception e) {
+		succeeded = false;
+	}
+").
+
+:- pragma foreign_proc("Java",
+	io__putenv(VarAndValue::in),
+	[will_not_call_mercury, tabled_for_io],
+"
+	// This procedure should never be called, as io__setenv/2 has been
+	// implemented directly for Java.
+	// This implementation is included only to suppress warnings.
+
+	throw new RuntimeException(
+			""io__putenv/1 not implemented for Java: "" +
+			VarAndValue);
+").
+
 /*---------------------------------------------------------------------------*/
 
 io__tmpnam(Name) -->
@@ -6675,6 +7704,60 @@
 	}
 }").
 
+% For the Java implementation, io__make_temp/3 is overwritten directly, since
+% Java is capable of locating the default temp directory itself.
+
+:- pragma foreign_proc("Java",
+	io__do_make_temp(_Dir::in, _Prefix::in, _Sep::in, _FileName::out,
+		_Error::out, _ErrorMessage::out, _IO0::di, _IO::uo),
+        [will_not_call_mercury, promise_pure, tabled_for_io, thread_safe],
+"
+	// this function should never be called.
+
+	throw new RuntimeException(""io__do_make_temp not implemented"");
+").
+
+:- pragma foreign_proc("Java",
+        io__make_temp(FileName::out, _IO0::di, _IO::uo),
+        [will_not_call_mercury, promise_pure, tabled_for_io, thread_safe],
+"
+	try {
+		java.io.File tmpdir = new java.io.File(
+				java.lang.System.getProperty(
+				""java.io.tmpdir""));
+		FileName = java.io.File.createTempFile(""mtmp"", null, tmpdir).
+				getName();
+	} catch (java.lang.Exception e) {
+		throw new RuntimeException(e.getMessage());
+		// This is done instead of just 'throw e' because otherwise
+		// the java compiler complains about unreported exceptions.
+	}
+").
+
+:- pragma foreign_proc("Java",
+        io__make_temp(Dir::in, Prefix::in, FileName::out, _IO0::di, _IO::uo),
+        [will_not_call_mercury, promise_pure, tabled_for_io, thread_safe],
+"
+	try {
+		if (Prefix.length() < 3) {
+			// File.createTempFile() requires a Prefix which is
+			// at least 3 characters long.
+			Prefix = Prefix + ""tmp"";
+		} else if (Prefix.length() > 5) {
+			// The documentation for io__make_temp says that
+			// we should only use the first five characters
+			// of Prefix.
+			Prefix = Prefix.substring(0, 5);
+		}
+		FileName = java.io.File.createTempFile(Prefix, null,
+				new java.io.File(Dir)).getName();
+	} catch (java.lang.Exception e) {
+		throw new RuntimeException(e.getMessage());
+		// This is done instead of just 'throw e' because otherwise
+		// the java compiler complains about unreported exceptions.
+	}
+").
+
 /*---------------------------------------------------------------------------*/
 
 :- pragma foreign_decl("C", "
@@ -6831,6 +7914,27 @@
 	}
 }").
 
+:- pragma foreign_proc("Java",
+	io__remove_file_2(FileName::in, RetVal::out, RetStr::out,
+		_IO0::di, _IO::uo),
+	[will_not_call_mercury, promise_pure, tabled_for_io, thread_safe],
+"
+	try {
+		java.io.File file = new java.io.File(FileName);
+
+		if (file.delete()) {
+			RetVal = 0;
+			RetStr = """";
+		} else {
+			RetVal = -1;
+			RetStr = ""remove_file failed"";
+		}
+	} catch (java.lang.Exception e) {
+		RetVal = -1;
+		RetStr = e.getMessage();
+	}
+").
+
 io__rename_file(OldFileName, NewFileName, Result, IO0, IO) :-
 	io__rename_file_2(OldFileName, NewFileName, Res, ResString, IO0, IO),
 	( Res \= 0 ->
@@ -6874,6 +7978,32 @@
 	}
 }").
 
+:- pragma foreign_proc("Java",
+	io__rename_file_2(OldFileName::in, NewFileName::in, RetVal::out,
+		RetStr::out, _IO0::di, _IO::uo),
+	[will_not_call_mercury, promise_pure, tabled_for_io, thread_safe],
+"
+	try {
+		java.io.File file = new java.io.File(OldFileName);
+
+		if (file.exists()) {
+			if (file.renameTo(new java.io.File(NewFileName))) {
+				RetVal = 0;
+				RetStr = """";
+			} else {
+				RetVal = -1;
+				RetStr = ""rename_file failed"";
+			}
+		} else {
+			RetVal = -1;
+			RetStr = ""rename failed: No such file or directory"";
+		}
+	} catch (java.lang.Exception e) {
+		RetVal = -1;
+		RetStr = e.getMessage();
+	}
+").
+
 io__have_symlinks :- semidet_fail.
 
 :- pragma foreign_proc("C", io__have_symlinks,
@@ -6984,6 +8114,30 @@
 	MR_update_io(IO0, IO);
 }").
 
+% Since io__have_symlinks will fail for Java, these procedures should never be
+% called:
+
+:- pragma foreign_proc("Java",
+	io__make_symlink_2(_FileName::in, _LinkFileName::in,
+		_Status::out, _IO0::di, _IO::uo), 
+	[will_not_call_mercury, promise_pure, tabled_for_io, thread_safe],
+"
+	if (true) {
+		throw new java.lang.RuntimeException(
+				""io__make_symlink_2 not implemented"");
+	}
+").
+
+:- pragma foreign_proc("Java",
+	io__read_symlink_2(_FileName::in, _TargetFileName::out,
+		_Status::out, _Error::out, _IO0::di, _IO::uo), 
+	[will_not_call_mercury, promise_pure, tabled_for_io, thread_safe],
+"
+	if (true) {
+		throw new java.lang.RuntimeException(
+				""io__read_symlink_2 not implemented"");
+	}
+").
 
 /*---------------------------------------------------------------------------*/
 
--------------------------------------------------------------------------
mercury-reviews mailing list
post:  mercury-reviews at cs.mu.oz.au
administrative address: owner-mercury-reviews at cs.mu.oz.au
unsubscribe: Address: mercury-reviews-request at cs.mu.oz.au Message: unsubscribe
subscribe:   Address: mercury-reviews-request at cs.mu.oz.au Message: subscribe
--------------------------------------------------------------------------



More information about the reviews mailing list