diff --git a/README.html b/README.html index a3a481cd..6ad3c359 100644 --- a/README.html +++ b/README.html @@ -84,19 +84,13 @@ The following pattern is used within J2SE

-You must include the library lib/luaj-j2se-${VER}.jar in your class path. - -

-A working example may be found in +A simple example may be found in

 	src/sample/SampleJ2seMain.java
 

-Additional usage may be found in -

-	src/sample/LuaRunner.java
-
+You must include the library lib/luaj-j2se-${VER}.jar in your class path.

Run a script in a MIDlet

@@ -120,6 +114,12 @@ The following pattern is used within MIDlets: The file must be a resource within within the midlet jar for dofile() to find it. Any files included via require() must also be part of the midlet resources. +

+A simple example may be found in +

+	src/sample/SampleMIDlet.java
+
+

You must include the library lib/luaj-j2me-${VER}.jar in your midlet jar. They can be obfuscated if desired. @@ -219,7 +219,7 @@ and the math operations are limited to those supported by J2ME.

Standard Libraries

-The following libraries are loaded by default: +The following libraries are loaded by default in J2ME and J2SE platforms:

 	base
 	coroutine
@@ -229,20 +229,37 @@ The following libraries are loaded by default:
 	table
 
+In addition, J2SE contains these two libraries: +
+	io
+	luajava
+
+ See standard lua documentation for details on the library API's -

Optional Libraries

-A java library may be loaded dynamically if created properly. Currently, there is one such library, luajava. +

+There is a partial implementation of the io for J2ME in +

+	src/j2me/org/luaj/lib/j2me/Cldc10IoLib.java
+
+See the sample midlet to see how it is added to a platform. + +

The Luajava Library

+The luajava library implements a few functions which allow access to most classes +within the host J2SE runtime. They are included as part of the standard J2SE platform.

LuaJava

The luajava library is used to easily bind to Java classes via reflection. It is patterned after the original luajava project. +Because J2ME does not contain a reflection API, this library cannot be made to work on J2ME, +and is not included by default. +

Unimplemented Libraries

The following libraries are not yet implemented:
+	os
 	debug
-	io
 

Building the jars

diff --git a/src/core/org/luaj/lib/IoLib.java b/src/core/org/luaj/lib/IoLib.java index 580055e7..2eb19f58 100644 --- a/src/core/org/luaj/lib/IoLib.java +++ b/src/core/org/luaj/lib/IoLib.java @@ -21,6 +21,8 @@ ******************************************************************************/ package org.luaj.lib; +import java.io.ByteArrayOutputStream; +import java.io.EOFException; import java.io.IOException; import org.luaj.vm.LFunction; @@ -41,13 +43,17 @@ public class IoLib extends LFunction { public boolean isstdfile(); public void close() throws IOException; public boolean isclosed(); - /** returns new position */ + // returns new position public int seek(String option, int bytecount) throws IOException; - public LValue readBytes(int count) throws IOException; - public Double readNumber() throws IOException; - public LValue readLine() throws IOException; - public LValue readFile() throws IOException; - public void setvbuf(String mode, int size); + public void setvbuf(String mode, int size); + // get length remaining to read + public int remaining() throws IOException; + // peek ahead one character + public int peek() throws IOException, EOFException; + // return char if read, -1 if eof, throw IOException on other exception + public int read() throws IOException, EOFException; + // return length if fully read, false if eof, throw IOException on other exception + public int readFully(byte[] bytes, int offset, int length) throws IOException; } @@ -56,6 +62,20 @@ public class IoLib extends LFunction { */ abstract protected IoLib newInstance( int index ); + /** + * Wrap the standard input. + * @return File + * @throws IOException + */ + abstract protected File wrapStdin() throws IOException; + + /** + * Wrap the standard output. + * @return File + * @throws IOException + */ + abstract protected File wrapStdout() throws IOException; + /** * Open a file in a particular mode. * @param filename @@ -63,7 +83,7 @@ public class IoLib extends LFunction { * @return File object if successful * @throws IOException if could not be opened */ - abstract protected File openFile(String filename, String mode) throws IOException; + abstract protected File openFile( String filename, boolean readMode, boolean appendMode, boolean updateMode, boolean binaryMode ) throws IOException; /** * Open a temporary file. @@ -233,7 +253,7 @@ public class IoLib extends LFunction { vm.pushlvalue(lines(vm,INPUT)); break; case IO_OPEN: - setresult(vm, openFile(vm.checkstring(2), vm.optstring(3,"r"))); + setresult(vm, rawopenfile(vm.checkstring(2), vm.optstring(3,"r"))); break; case IO_OUTPUT: OUTPUT = vm.isnoneornil(2)? @@ -343,7 +363,7 @@ public class IoLib extends LFunction { public boolean luaStackCall(LuaState vm) { vm.resettop(); try { - vm.pushlvalue(f.readLine()); + vm.pushlvalue(freadline(f)); } catch (IOException e) { seterrorresult(vm,e); } @@ -363,15 +383,15 @@ public class IoLib extends LFunction { int i,n=vm.gettop(); for ( i=2; i<=n; i++ ) { if ( vm.isnumber(i) ) { - vm.pushlvalue(f.readBytes(vm.tointeger(i))); + vm.pushlvalue(freadbytes(f,vm.tointeger(i))); } else { String format = vm.checkstring(i); if ( "*n".equals(format) ) - vm.pushnumber(f.readNumber()); + vm.pushnumber(freadnumber(f)); else if ( "*a".equals(format) ) - vm.pushlvalue(f.readFile()); + vm.pushlvalue(freadall(f)); else if ( "*l".equals(format) ) - vm.pushlvalue(f.readLine()); + vm.pushlvalue(freadline(f)); else vm.typerror( i, "(invalid format)" ); } @@ -408,12 +428,92 @@ public class IoLib extends LFunction { private File ioopenfile(LuaState vm, String filename, String mode) { try { - File f = openFile( filename, mode ); - return f; + return rawopenfile(filename, mode); } catch ( Exception e ) { vm.error("io error: "+e.getMessage()); return null; } } + + private File rawopenfile(String filename, String mode) throws IOException { + boolean isstdfile = "-".equals(filename); + boolean isreadmode = mode.startsWith("r"); + if ( isstdfile ) { + return isreadmode? + wrapStdin(): + wrapStdout(); + } + boolean isappend = mode.startsWith("a"); + boolean isupdate = mode.indexOf("+") > 0; + boolean isbinary = mode.endsWith("b"); + return openFile( filename, isreadmode, isappend, isupdate, isbinary ); + } + + + // ------------- file reading utilitied ------------------ + + public static LValue freadbytes(File f, int count) throws IOException { + byte[] b = new byte[count]; + if ( f.readFully(b,0,b.length) < 0 ) + return LNil.NIL; + return new LString(b); + } + public static LValue freaduntil(File f,int delim) throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + int c; + try { + while ( true ) { + c = f.read(); + if ( c < 0 || c == delim ) + break; + baos.write(c); + } + } catch ( EOFException e ) { + c = -1; + } + return ( c < 0 && baos.size() == 0 )? + (LValue) LNil.NIL: + (LValue) new LString(baos.toByteArray()); + } + public static LValue freadline(File f) throws IOException { + return freaduntil(f,'\n'); + } + public static LValue freadall(File f) throws IOException { + int n = f.remaining(); + if ( n >= 0 ) { + return freadbytes(f, n); + } else { + return freaduntil(f,-1); + } + } + public static Double freadnumber(File f) throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + freadchars(f," \t\r\n",null); + freadchars(f,"-+",baos); + //freadchars(f,"0",baos); + //freadchars(f,"xX",baos); + freadchars(f,"0123456789",baos); + freadchars(f,".",baos); + freadchars(f,"0123456789",baos); + //freadchars(f,"eEfFgG",baos); + // freadchars(f,"+-",baos); + //freadchars(f,"0123456789",baos); + String s = baos.toString(); + return s.length()>0? Double.valueOf(s): null; + } + private static void freadchars(File f, String chars, ByteArrayOutputStream baos) throws IOException { + int c; + while ( true ) { + c = f.peek(); + if ( chars.indexOf(c) < 0 ) { + return; + } + f.read(); + if ( baos != null ) + baos.write( c ); + } + } + + } diff --git a/src/j2me/org/luaj/lib/j2me/Cldc10IoLib.java b/src/j2me/org/luaj/lib/j2me/Cldc10IoLib.java new file mode 100644 index 00000000..32cdfc6c --- /dev/null +++ b/src/j2me/org/luaj/lib/j2me/Cldc10IoLib.java @@ -0,0 +1,211 @@ +/******************************************************************************* +* Copyright (c) 2008 LuaJ. All rights reserved. +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +* THE SOFTWARE. +******************************************************************************/ +package org.luaj.lib.j2me; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import javax.microedition.io.Connector; +import javax.microedition.io.StreamConnection; + +import org.luaj.lib.BaseLib; +import org.luaj.lib.IoLib; +import org.luaj.vm.LString; +import org.luaj.vm.LTable; + +/** + * Implementation of the lua io library based on CLDC 1.0 and StreamConnection. + * + * Seek is not supported. + */ +public class Cldc10IoLib extends IoLib { + + public static void install( LTable globals ) { + new Cldc10IoLib().initialize(globals); + } + + public Cldc10IoLib() { + super(); + } + + public Cldc10IoLib(int index) { + super(index); + } + + protected IoLib newInstance(int index) { + return new Cldc10IoLib(index); + } + + protected File wrapStdin() throws IOException { + return new FileImpl(BaseLib.STDIN); + } + + protected File wrapStdout() throws IOException { + return new FileImpl(BaseLib.STDOUT != null? BaseLib.STDOUT: System.out); + } + + protected File openFile( String filename, boolean readMode, boolean appendMode, boolean updateMode, boolean binaryMode ) throws IOException { + String url = "file:///" + filename; + int mode = readMode? Connector.READ: Connector.READ_WRITE; + StreamConnection conn = (StreamConnection) Connector.open( url, mode ); + File f = readMode? + new FileImpl(conn, conn.openInputStream(), null): + new FileImpl(conn, conn.openInputStream(), conn.openOutputStream()); + /* + if ( appendMode ) { + f.seek("end",0); + } else { + if ( ! readMode ) + conn.truncate(0); + } + */ + return f; + } + + private static void notimplemented() throws IOException { + throw new IOException("not implemented"); + } + + protected File openProgram(String prog, String mode) throws IOException { + notimplemented(); + return null; + } + + protected File tmpFile() throws IOException { + notimplemented(); + return null; + } + + private static final class FileImpl implements File { + private final StreamConnection conn; + private final InputStream is; + private final OutputStream os; + private boolean closed = false; + private boolean nobuffer = false; + private int lookahead = -1; + private FileImpl( StreamConnection conn, InputStream is, OutputStream os ) { + this.conn = conn; + this.is = is; + this.os = os; + } + private FileImpl( InputStream i ) { + this( null, i, null ); + } + private FileImpl( OutputStream o ) { + this( null, null, o ); + } + public String toString() { + return "file ("+this.hashCode()+")"; + } + public boolean isstdfile() { + return conn == null; + } + public void close() throws IOException { + closed = true; + if ( conn != null ) { + conn.close(); + } + } + public void flush() throws IOException { + if ( os != null ) + os.flush(); + } + public void write(LString s) throws IOException { + if ( os != null ) + os.write( s.m_bytes, s.m_offset, s.m_length ); + else + notimplemented(); + if ( nobuffer ) + flush(); + } + public boolean isclosed() { + return closed; + } + public int seek(String option, int pos) throws IOException { + /* + if ( conn != null ) { + if ( "set".equals(option) ) { + conn.seek(pos); + return (int) conn.getFilePointer(); + } else if ( "end".equals(option) ) { + conn.seek(conn.length()+1+pos); + return (int) conn.length()+1; + } else { + conn.seek(conn.getFilePointer()+pos); + return (int) conn.getFilePointer(); + } + } + */ + notimplemented(); + return 0; + } + public void setvbuf(String mode, int size) { + nobuffer = "no".equals(mode); + } + + // get length remaining to read + public int remaining() throws IOException { + return -1; + } + + // peek ahead one character + public int peek() throws IOException { + if ( lookahead < 0 ) + lookahead = is.read(); + return lookahead; + } + + // return char if read, -1 if eof, throw IOException on other exception + public int read() throws IOException { + if ( lookahead >= 0 ) { + int c = lookahead; + lookahead = -1; + return c; + } + if ( is != null ) + return is.read(); + notimplemented(); + return 0; + } + + // return length if fully read, -1 if eof, throws IOException + public int readFully(byte[] bytes, int offset, int length) throws IOException { + int n,i=0; + if (is!=null) { + if ( length > 0 && lookahead >= 0 ) { + bytes[offset] = (byte) lookahead; + lookahead = -1; + i += 1; + } + for ( ; i0? Double.valueOf(s): null; - } - private void readChars(String chars, ByteArrayOutputStream baos) throws IOException { - int c; - while ( true ) { - if ( is != null ) { - is.mark(1); - c = is.read(); - } else { - c = file.read(); - } - if ( chars.indexOf(c) < 0 ) { - if ( is != null ) - is.reset(); - else if ( file != null ) - file.seek(file.getFilePointer()-1); - return; - } - if ( baos != null ) - baos.write( c ); - } - } - } - - protected File openProgram(String prog, String mode) throws IOException { - final Process p = Runtime.getRuntime().exec(prog); - return "w".equals(mode)? - new FileImpl( p.getOutputStream() ): - new FileImpl( p.getInputStream() ); - } - protected File tmpFile() throws IOException { - java.io.File f = java.io.File.createTempFile(".luaj","bin"); - f.deleteOnExit(); - return new FileImpl( new RandomAccessFile(f,"rw") ); + // get length remaining to read + public int remaining() throws IOException { + return file!=null? (int) (file.length()-file.getFilePointer()): -1; + } + + // peek ahead one character + public int peek() throws IOException { + if ( is != null ) { + is.mark(1); + int c = is.read(); + is.reset(); + return c; + } else if ( file != null ) { + int c = file.read(); + file.seek(file.getFilePointer()-1); + return c; + } + notimplemented(); + return 0; + } + + // return char if read, -1 if eof, throw IOException on other exception + public int read() throws IOException { + if ( is != null ) + return is.read(); + else if ( file != null ) { + return file.read(); + } + notimplemented(); + return 0; + } + + // return length if fully read, -1 if eof, throws IOException + public int readFully(byte[] bytes, int offset, int length) throws IOException { + if (file!=null) { + file.readFully(bytes, offset, length); + } else if (is!=null) { + for ( int i=0; i