Add CLDC-1.0 based implementation of io libraries.

This commit is contained in:
James Roseborough
2008-12-05 22:29:07 +00:00
parent b8237ec872
commit 308e909df1
7 changed files with 483 additions and 128 deletions

View File

@@ -84,19 +84,13 @@ The following pattern is used within J2SE
</pre>
<p>
You must include the library <b>lib/luaj-j2se-${VER}.jar</b> in your class path.
<p>
A working example may be found in
A simple example may be found in
<pre>
src/sample/SampleJ2seMain.java
</pre>
<p>
Additional usage may be found in
<pre>
src/sample/LuaRunner.java
</pre>
You must include the library <b>lib/luaj-j2se-${VER}.jar</b> in your class path.
<h2>Run a script in a MIDlet</h2>
@@ -120,6 +114,12 @@ The following pattern is used within MIDlets:
The file must be a resource within within the midlet jar for <em>dofile()</em> to find it.
Any files included via <em>require()</em> must also be part of the midlet resources.
<p>
A simple example may be found in
<pre>
src/sample/SampleMIDlet.java
</pre>
<p>
You must include the library <b>lib/luaj-j2me-${VER}.jar</b> 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.
<h2>Standard Libraries</h2>
<p>
The following libraries are loaded by default:
The following libraries are loaded by default in J2ME and J2SE platforms:
<pre>
base
coroutine
@@ -229,20 +229,37 @@ The following libraries are loaded by default:
table
</pre>
In addition, J2SE contains these two libraries:
<pre>
io
luajava
</pre>
See <a href="http://www.lua.org/manual/5.1/">standard lua documentation</a> for details on the library API's
<h2>Optional Libraries</h2>
A java library may be loaded dynamically if created properly. Currently, there is one such library, <em>luajava.</em>
<p>
There is a partial implementation of the <em>io</em> for J2ME in
<pre>
src/j2me/org/luaj/lib/j2me/Cldc10IoLib.java
</pre>
See the sample midlet to see how it is added to a platform.
<h2>The Luajava Library</h2>
The <em>luajava</em> 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.
<h3>LuaJava</h3>
The luajava library is used to easily bind to Java classes via reflection.
It is patterned after the original <a href="http://www.keplerproject.org/luajava/">luajava project</a>.
Because J2ME does not contain a reflection API, this library cannot be made to work on J2ME,
and is not included by default.
<h2>Unimplemented Libraries</h2>
The following libraries are not yet implemented:
<pre>
os
debug
io
</pre>
<h2>Building the jars</h2>

View File

@@ -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);
// 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 );
}
}
}

View File

@@ -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 ( ; i<length; ) {
n = is.read(bytes, offset+i, length-i);
if ( n < 0 )
return -1;
i += n;
}
} else {
notimplemented();
}
return length;
}
}
}

View File

@@ -21,7 +21,6 @@
******************************************************************************/
package org.luaj.lib.j2se;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@@ -29,12 +28,13 @@ import java.io.RandomAccessFile;
import org.luaj.lib.BaseLib;
import org.luaj.lib.IoLib;
import org.luaj.vm.LNil;
import org.luaj.vm.LString;
import org.luaj.vm.LTable;
import org.luaj.vm.LValue;
/**
* Implementation of the lua io library for J2se using RandomAccessFile
* to implement seek.
*/
public class J2seIoLib extends IoLib {
public static void install( LTable globals ) {
@@ -53,26 +53,38 @@ public class J2seIoLib extends IoLib {
return new J2seIoLib(index);
}
protected File openFile(String filename, String mode) throws IOException {
boolean isstdfile = "-".equals(filename);
boolean isreadmode = mode.startsWith("r");
if ( isstdfile )
return isreadmode?
new FileImpl(BaseLib.STDIN != null? BaseLib.STDIN: System.in):
new FileImpl(BaseLib.STDOUT != null? BaseLib.STDOUT: System.out);
boolean isappend = mode.startsWith("a");
// TODO: handle update mode
// boolean isupdate = mode.endsWith("+");
RandomAccessFile f = new RandomAccessFile(filename,isreadmode? "r": "rw");
if ( isappend ) {
protected File wrapStdin() throws IOException {
return new FileImpl(BaseLib.STDIN != null? BaseLib.STDIN: System.in);
}
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 {
RandomAccessFile f = new RandomAccessFile(filename,readMode? "r": "rw");
if ( appendMode ) {
f.seek(f.length());
} else {
if ( ! isreadmode )
if ( ! readMode )
f.setLength(0);
}
return new FileImpl( f );
}
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") );
}
private static void notimplemented() {
throw new RuntimeException("not implemented");
}
@@ -145,88 +157,54 @@ public class J2seIoLib extends IoLib {
public void setvbuf(String mode, int size) {
nobuffer = "no".equals(mode);
}
public LValue readBytes(int count) throws IOException {
if ( file != null ) {
byte[] b = new byte[count];
file.readFully(b);
return new LString(b);
// 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 LNil.NIL;
return 0;
}
public LValue readLine() throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int c;
while ( true ) {
if ( is != null ) {
c = is.read();
} else {
c = file.read();
// 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<length; i++, offset++ ) {
int c = is.read();
if ( c < 0 )
return -1;
bytes[offset++] = (byte) c;
}
if ( c < 0 || c == '\n' )
break;
baos.write(c);
}
return ( c < 0 && baos.size() == 0 )?
LNil.NIL:
new LString(baos.toByteArray());
}
public LValue readFile() throws IOException {
if ( file != null ) {
return readBytes((int) (file.length() - file.getFilePointer()));
}
notimplemented();
return null;
}
public Double readNumber() throws IOException {
if ( is == null && file == null )
} else {
notimplemented();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
readChars(" \t\r\n",null);
readChars("-+",baos);
//readChars("0",baos);
//readChars("xX",baos);
readChars("0123456789",baos);
readChars(".",baos);
readChars("0123456789",baos);
//readChars("eEfFgG",baos);
// readChars("+-",baos);
//readChars("0123456789",baos);
String s = baos.toString();
return s.length()>0? 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 );
}
return length;
}
}
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") );
}
}

View File

@@ -0,0 +1,42 @@
package org.luaj.sample;
import javax.microedition.midlet.MIDlet;
import javax.microedition.midlet.MIDletStateChangeException;
import org.luaj.lib.j2me.Cldc10IoLib;
import org.luaj.platform.J2meMidp20Cldc11Platform;
import org.luaj.vm.LuaState;
import org.luaj.vm.Platform;
public class SampleMIDlet extends MIDlet {
// the script will be loaded as a resource
private static final String DEFAULT_SCRIPT = "test1.lua";
protected void startApp() throws MIDletStateChangeException {
// get the script as an app property
String script = this.getAppProperty("script");
if ( script == null )
script = DEFAULT_SCRIPT;
// set up the j2me platform. files will be loaded as resources
Platform.setInstance( new J2meMidp20Cldc11Platform(this) );
LuaState vm = Platform.newLuaState();
// extend the basic vm to include the compiler and io packages
org.luaj.compiler.LuaC.install();
Cldc10IoLib.install(vm._G);
// run the script
vm.getglobal( "dofile" );
vm.pushstring( script );
vm.call( 1, 0 );
}
protected void destroyApp(boolean arg0) throws MIDletStateChangeException {
}
protected void pauseApp() {
}
}

View File

@@ -11,6 +11,7 @@ checkallpass('io.close',{{f}})
checkallerrors('io.close',{notanil},'bad argument #1')
-- io.input ([file])
f = io.open("abc.txt","r")
checkallpass('io.input',{{nil,f,"abc.txt"}})
checkallerrors('io.input',{nonstring},'bad argument #1')

View File

@@ -24,8 +24,8 @@ for i,v in ipairs(t) do
print( string.format("%q",tostring(v)), type(v))
end
local h = io.open("abc.txt", "a")
print( 'h', io.type(h) )
local h,s = io.open("abc.txt", "a")
print( 'h', io.type(h), s )
print( 'write', h:write('\nmore text\neven more text\n') )
print( 'close', h:close() )
@@ -61,6 +61,12 @@ for l in io.lines() do
print( string.format('%q',l) )
end
local count = 0
io.tmpfile = function()
count = count + 1
return io.open("tmp"..count..".out","w")
end
local a = io.tmpfile()
local b = io.tmpfile()
print( io.type(a) )