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

James Goddard goddardjames at yahoo.com
Thu Jan 15 17:46:57 AEDT 2004


> I think it would be possible to use reflection to do it correctly for
> Java 1.4, by extracting the FileChannel for System.out and System.in,
> and invoking seek on that.  If you use Reflection for everything, the
> code for it should compile fine in Java < 1.4.  This code is a bit
> implementation-dependent, but if it doesn't work it will just throw
> an exception.

Ok, here's my next attempt.  I've copied your get_output_channel()
function in and altered it to make get_input_channel() as well.
seek(), size() and getOffset() all use Reflection to access those
FileChannels now.

It's all getting so ugly!! =(

diff -u io.m io.m
--- io.m	15 Jan 2004 01:49:26 -0000
+++ io.m	15 Jan 2004 06:38:28 -0000
@@ -4851,7 +4851,9 @@
 		private java.io.BufferedInputStream	binary_input	= null;
 		/* binary_stdout only */
 		private java.io.BufferedOutputStream	binary_output	= null;
+
 		int					position	= 0;
+		private java.lang.Object		channel		= null;
 
 		/*
 		** This constructor is for text input streams.
@@ -4900,49 +4902,36 @@
 			}
 		}
 
-		/*
-		** This constructor is only used for mercury_stdin_binary. It
-		** opens stdin as an approximation of a binary file and allows
-		** a limited amount of seeking.
-		*/
 		public MR_MercuryFileStruct(java.io.InputStream stream,
 				boolean openAsBinary)
 		{
+			id		= ML_next_stream_id++;
+			mode		= INPUT;
+			pushback	= new java.util.Stack();
+			
 			if (!openAsBinary) {
-				id		= ML_next_stream_id++;
-				mode		= INPUT;
-				pushback	= new java.util.Stack();
 				input		= new java.io.
 						InputStreamReader(stream);
 			} else {
-				id		= ML_next_stream_id++;
-				mode		= INPUT;
-				pushback	= new java.util.Stack();
-				
 				binary_input = new java.io.BufferedInputStream(
 						stream);
+				channel = get_in_channel();
 			}
 		}
 
-		/*
-		** This constructor is only used for mercury_stdout_binary. It
-		** opens stdout as an approximation of a binary file and allows
-		** a limited amount of seeking.
-		*/
 		public MR_MercuryFileStruct(java.io.OutputStream stream,
 				boolean openAsBinary)
 		{
+			id		= ML_next_stream_id++;
+			mode		= OUTPUT;
+
 			if (!openAsBinary) {
-				id		= ML_next_stream_id++;
-				mode		= OUTPUT;
 				output		= new java.io.
 						OutputStreamWriter(stream);
 			} else {
-				id		= ML_next_stream_id++;
-				mode		= OUTPUT;
-				
 				binary_output = new java.io.
 						BufferedOutputStream(stream);
+				channel = get_out_channel();
 			}
 		}
 		
@@ -4950,7 +4939,8 @@
 		** size():
 		**	Returns the length of a binary file. XXX Note that this
 		**	method will return -1 for mercury_stdin_binary and
-		**	the current position for mercury_stdout_binary.
+		**	the current position for mercury_stdout_binary in Java
+		**	versions < 1.4.
 		*/
 		public int size() {
 			if (randomaccess != null) {
@@ -4959,10 +4949,20 @@
 				} catch (java.io.IOException e) {
 					return -1;
 				}
-			} else if (binary_output != null) {
-				return position;
-			} else {
-				return -1;
+			}
+
+			try {
+				java.lang.reflect.Method size_mth =
+						channel.getClass().
+						getMethod(""size"", null);
+				return ((Long) size_mth.invoke(channel, null)).
+						intValue();
+			} catch (java.lang.Exception e) {
+				if (binary_output != null) {
+					return position;
+				} else {
+					return -1;
+				}
 			}
 		}
 
@@ -4971,11 +4971,21 @@
 		**	seek relative to start, current position or end
 		**	depending on the flag.
 		**	This function only works for binary files.
-		**	XXX Note that for mercury_stdin_binary, seek may be
+		**	The binary versions of stdin and stdout are treated
+		**	specially.  For java version 1.4, Reflection is used to
+		**	obtain and use the neccessary FileChannel object needed
+		**	to perform seeking on each.
+		**	For older versions, seeking is rather limited.
+		**	For mercury_stdin_binary, seek may be
 		**	only be done forwards from the current position and for
 		**	mercury_stdout_binary seek is not supported at all.
 		*/
 		public void seek(int flag, int offset) {
+			if (channel != null) {
+				channelSeek(flag, offset);
+				return;
+			}
+
 			if (input != null || output != null) {
 				throw new java.lang.RuntimeException(
 						""text streams are not "" +
@@ -4996,6 +5006,8 @@
 			}
 
 			pushback = new java.util.Stack();
+			line_number = 1;
+
 			try {
 				switch (flag) {
 					case SEEK_SET:
@@ -5027,6 +5039,42 @@
 			}
 		}
 
+		private void channelSeek(int flag, int offset) {
+			pushback = new java.util.Stack();
+			line_number = 1;
+
+			try {
+				switch (flag) {
+					case SEEK_SET:
+						position = offset;
+						break;
+					case SEEK_CUR:
+						position = getOffset() +
+								offset;
+						break;
+					case SEEK_END:
+						position = size() + offset;
+						break;
+					default:
+						throw new java.lang.
+							RuntimeException(
+							""Invalid seek flag"");
+				}
+
+				Class[] argTypes = {Long.TYPE};
+				java.lang.reflect.Method seek_mth =
+						channel.getClass().getMethod(
+						""position"", argTypes);
+
+				Object[] args = {new Long(position)};
+				seek_mth.invoke(channel, args);
+			}
+			catch (java.lang.Exception e) {
+				throw new java.lang.RuntimeException(
+						e.getMessage());
+			}
+		}
+
 		/*
 		** getOffset():
 		**	Returns the current position in a binary file.
@@ -5039,12 +5087,22 @@
 				} catch (java.io.IOException e) {
 					return -1;
 				}
-			} else if (binary_input != null ||
-					binary_output != null)
-			{
-				return position;
-			} else {
-				return -1;
+			}
+
+			try {
+				java.lang.reflect.Method posn_mth =
+						channel.getClass().
+						getMethod(""position"", null);
+				return ((Long) posn_mth.invoke(channel, null)).
+						intValue();
+			} catch (java.lang.Exception e) {
+				if (binary_input != null ||
+						binary_output != null)
+				{
+					return position;
+				} else {
+					return -1;
+				}
 			}
 		}
 
@@ -5287,6 +5345,97 @@
 			}
 		}
 	} // class StreamPipe
+
+	/*
+	** get_out_channel():
+	**	Uses reflection to retrieve the FileChannel for System.out on
+	**	platforms supporting Java v1.4
+	*/
+	static java.lang.Object/*FileChannel*/ get_out_channel() {
+		try {
+			java.lang.Object/*PrintStream*/ ps =
+					java.lang.System.out;
+
+			// Simulate
+			//	BufferedOutputStream bos =
+			//		(BufferedOutputStream) ps.out;
+			// using reflection.
+			java.lang.reflect.Field out_fld =
+					ps.getClass().getSuperclass().
+					getDeclaredField(""out"");
+			out_fld.setAccessible(true);
+			java.lang.Object/*BufferedOutputStream*/ bos =
+					out_fld.get(ps);
+
+			// Simulate
+			//	FileOutputStream fs =
+			//		(FileOutputStream) bos.out;
+			// using reflection.
+			java.lang.reflect.Field out_fld2 =
+					bos.getClass().getSuperclass().
+					getDeclaredField(""out"");
+			out_fld2.setAccessible(true);
+			java.lang.Object/*FileStream*/ fs = out_fld2.get(bos);
+
+			// Simulate
+			//	FileChannel channel = fs.getChannel();
+			// using reflection.
+			java.lang.reflect.Method getChannel_mth =
+					fs.getClass().getMethod(
+					""getChannel"", null);
+			java.lang.Object/*FileChannel*/ channel =
+					getChannel_mth.invoke(fs, null);
+
+			return channel;
+		} catch (java.lang.Exception e) {
+			return null;
+		}
+	}
+
+	/*
+	** get_in_channel():
+	**	Uses reflection to retrieve the FileChannel for System.in on
+	**	platforms supporting Java v1.4
+	*/
+	static java.lang.Object/*FileChannel*/ get_in_channel() {
+		try {
+			java.lang.Object/*InputStream*/ is = System.in;
+
+			// Simulate
+			//	BufferedInputStream bis =
+			//		(BufferedInputStream) is.in;
+			// using reflection.
+			java.lang.reflect.Field in_fld =
+					is.getClass().getSuperclass().
+					getDeclaredField(""in"");
+			in_fld.setAccessible(true);
+			java.lang.Object/*BufferedInputStream*/ bis =
+					in_fld.get(is);
+
+			// Simulate
+			//	FileInputStream fs =
+			//		(FileInputStream) bis.in;
+			// using reflection.
+			java.lang.reflect.Field in_fld2 =
+					bis.getClass().getSuperclass().
+					getDeclaredField(""in"");
+			in_fld2.setAccessible(true);
+			java.lang.Object/*FileStream*/ fs = in_fld2.get(bis);
+
+			// Simulate
+			//	FileChannel channel = fs.getChannel();
+			// using reflection.
+			java.lang.reflect.Method getChannel_mth =
+					fs.getClass().getMethod(
+					""getChannel"", null);
+			java.lang.Object/*FileChannel*/ channel =
+					getChannel_mth.invoke(fs, null);
+
+			return channel;
+		} catch (java.lang.Exception e) {
+			return null;
+		}
+	}
 ").
 
 :- pragma foreign_code("C", "
--------------------------------------------------------------------------
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