Update j2se IO implementation to use RandomAccessFile to support seek.

This commit is contained in:
James Roseborough
2008-12-04 19:37:02 +00:00
parent f382aa552d
commit b54ef775d2
3 changed files with 237 additions and 155 deletions

View File

@@ -24,9 +24,11 @@ package org.luaj.lib;
import java.io.IOException;
import org.luaj.vm.LFunction;
import org.luaj.vm.LNil;
import org.luaj.vm.LString;
import org.luaj.vm.LTable;
import org.luaj.vm.LUserData;
import org.luaj.vm.LValue;
import org.luaj.vm.LuaState;
@@ -40,10 +42,10 @@ public class IoLib extends LFunction {
public boolean isclosed();
/** returns new position */
public int seek(String option, int bytecount) throws IOException;
public byte[] readBytes(int count) throws IOException;
public LValue readBytes(int count) throws IOException;
public Double readNumber() throws IOException;
public LString readLine() throws IOException;
public LString readFile() throws IOException;
public LValue readLine() throws IOException;
public LValue readFile() throws IOException;
}
@@ -64,6 +66,7 @@ public class IoLib extends LFunction {
public static final String[] NAMES = {
"io",
"__index",
"close",
"flush",
"input",
@@ -85,51 +88,51 @@ public class IoLib extends LFunction {
};
private static final int INSTALL = 0;
private static final int IO_CLOSE = 1;
private static final int IO_FLUSH = 2;
private static final int IO_INPUT = 3;
private static final int IO_LINES = 4;
private static final int IO_OPEN = 5;
private static final int IO_OUTPUT = 6;
private static final int IO_POPEN = 7;
private static final int IO_READ = 8;
private static final int IO_TMPFILE = 9;
private static final int IO_TYPE = 10;
private static final int IO_WRITE = 11;
private static final int FILE_CLOSE = 12;
private static final int FILE_FLUSH = 13;
private static final int FILE_LINES = 14;
private static final int FILE_READ = 15;
private static final int FILE_SEEK = 16;
private static final int FILE_SETVBUF = 17;
private static final int FILE_WRITE = 18;
private static final int IO_INDEX = 1;
private static final int IO_CLOSE = 2;
private static final int IO_FLUSH = 3;
private static final int IO_INPUT = 4;
private static final int IO_LINES = 5;
private static final int IO_OPEN = 6;
private static final int IO_OUTPUT = 7;
private static final int IO_POPEN = 8;
private static final int IO_READ = 9;
private static final int IO_TMPFILE = 10;
private static final int IO_TYPE = 11;
private static final int IO_WRITE = 12;
private static final int FILE_CLOSE = 13;
private static final int FILE_FLUSH = 14;
private static final int FILE_LINES = 15;
private static final int FILE_READ = 16;
private static final int FILE_SEEK = 17;
private static final int FILE_SETVBUF = 18;
private static final int FILE_WRITE = 19;
private static File INPUT = null;
private static File OUTPUT = null;
private static File ERROR = null;
private static final LTable FILE_MT = new LTable();
private static LTable FILE_MT;
protected void initialize( LTable globals ) {
try {
LTable io = new LTable();
for ( int i=IO_CLOSE; i<=IO_WRITE; i++ )
io.put(NAMES[i], newInstance(i));
INPUT = openFile("-", "r");
OUTPUT = openFile("-", "w");
ERROR = OUTPUT;
io.put("stdin", new LUserData(INPUT));
io.put("stdout", new LUserData(OUTPUT));
io.put("stderr", new LUserData(ERROR));
for ( int i=FILE_CLOSE; i<=FILE_WRITE; i++ )
FILE_MT.put(NAMES[i], newInstance(i));
FILE_MT.put("__index", FILE_MT);
globals.put( "io", io );
PackageLib.setIsLoaded("io", io);
} catch ( IOException ioe ) {
throw new RuntimeException("io error: "+ioe.getMessage());
}
LTable io = new LTable();
for ( int i=IO_INDEX; i<=IO_WRITE; i++ )
io.put(NAMES[i], newInstance(i));
io.luaSetMetatable(io);
FILE_MT = new LTable();
for ( int i=FILE_CLOSE; i<=FILE_WRITE; i++ )
FILE_MT.put(NAMES[i], newInstance(i));
FILE_MT.put("__index", FILE_MT);
INPUT = null;
OUTPUT = null;
ERROR = null;
globals.put( "io", io );
PackageLib.setIsLoaded("io", io);
}
private static final char DEFVAL_NONE = 0;
private static final char DEFVAL_STDIN = 'r';
private static final char DEFVAL_STDOUT= 'w';
private final int id;
@@ -141,14 +144,46 @@ public class IoLib extends LFunction {
this.id = id;
}
public LString luaAsString() {
return new LString(toJavaString());
}
public String toJavaString() {
return "io."+toString();
}
public String toString() {
return NAMES[id]+"()";
}
private File input(LuaState vm) {
return INPUT!=null? INPUT: (INPUT=ioopenfile(vm,"-","r"));
}
private File output(LuaState vm) {
return OUTPUT!=null? OUTPUT: (OUTPUT=ioopenfile(vm,"-","w"));
}
private File error(LuaState vm) {
return ERROR!=null? ERROR: (ERROR=ioopenfile(vm,"-","w"));
}
public LValue __index(LuaState vm, LValue table, LValue key) {
String k = key.toJavaString();
if ( "stdout".equals(k) )
return touserdata(output(vm));
else if ( "stdin".equals(k) )
return touserdata(input(vm));
else if ( "stderr".equals(k) )
return touserdata(error(vm));
else
return LNil.NIL;
}
public boolean luaStackCall( LuaState vm ) {
File f;
String s;
int i,n;
int n;
try {
switch ( id ) {
/* Load the table library dynamically */
@@ -156,12 +191,12 @@ public class IoLib extends LFunction {
initialize(vm._G);
break;
case IO_CLOSE:
optfile(vm, 2, OUTPUT).close();
optfile(vm,2,DEFVAL_STDOUT).close();
vm.resettop();
vm.pushboolean(true);
break;
case IO_FLUSH:
checkopen(vm,OUTPUT);
checkopen(vm,output(vm));
OUTPUT.flush();
vm.resettop();
vm.pushboolean(true);
@@ -169,10 +204,15 @@ public class IoLib extends LFunction {
case IO_INPUT:
INPUT = ((s = vm.optstring(1, null)) != null)?
ioopenfile(vm,s,"r"):
optfile(vm,1,INPUT);
optfile(vm,2,DEFVAL_STDIN);
setresult(vm, INPUT);
break;
case IO_LINES:
INPUT = ((s = vm.optstring(1, null)) != null)?
ioopenfile(vm,s,"r"):
optfile(vm,2,DEFVAL_STDIN);
vm.resettop();
vm.pushlvalue(lines(INPUT));
break;
case IO_OPEN:
setresult(vm, openFile(vm.checkstring(2), vm.optstring(3,"r")));
@@ -180,7 +220,7 @@ public class IoLib extends LFunction {
case IO_OUTPUT:
OUTPUT = ((s = vm.optstring(2, null)) != null)?
ioopenfile(vm,s,"w"):
optfile(vm,1,OUTPUT);
optfile(vm,2,DEFVAL_STDOUT);
setresult(vm, OUTPUT);
break;
case IO_POPEN:
@@ -191,7 +231,7 @@ public class IoLib extends LFunction {
case IO_TMPFILE:
break;
case IO_TYPE:
f = optfile(vm,2,null);
f = optfile(vm,2,DEFVAL_NONE);
vm.resettop();
if ( f != null )
vm.pushstring(f.isclosed()? "closed file": "file");
@@ -212,6 +252,9 @@ public class IoLib extends LFunction {
vm.pushboolean(true);
break;
case FILE_LINES:
f = checkfile(vm,2);
vm.resettop();
vm.pushlvalue(lines(f));
break;
case FILE_READ:
f = checkfile(vm,2);
@@ -224,6 +267,7 @@ public class IoLib extends LFunction {
vm.pushinteger(n);
break;
case FILE_SETVBUF:
vm.resettop();
break;
case FILE_WRITE:
f = checkfile(vm,2);
@@ -241,6 +285,21 @@ public class IoLib extends LFunction {
return false;
}
private LValue lines(final File f) {
return new LFunction() {
public boolean luaStackCall(LuaState vm) {
vm.resettop();
try {
vm.pushlvalue(f.readLine());
} catch (IOException e) {
vm.pushnil();
vm.pushstring("io error: "+e);
}
return false;
}
};
}
private static void iowrite(LuaState vm, File f) throws IOException {
checkopen(vm,f);
for ( int i=2, n=vm.gettop(); i<=n; i++ )
@@ -254,15 +313,15 @@ public class IoLib extends LFunction {
int i,n=vm.gettop();
for ( i=2; i<=n; i++ ) {
if ( vm.isnumber(i) ) {
vm.pushlstring(f.readBytes(vm.tointeger(i)));
vm.pushlvalue(f.readBytes(vm.tointeger(i)));
} else {
String format = vm.checkstring(i);
if ( "*n".equals(format) )
vm.pushnumber(f.readNumber());
else if ( "*a".equals(format) )
vm.pushlstring(f.readFile());
vm.pushlvalue(f.readFile());
else if ( "*l".equals(format) )
vm.pushlstring(f.readLine());
vm.pushlvalue(f.readLine());
else
vm.typerror( i, "(invalid format)" );
}
@@ -275,9 +334,12 @@ public class IoLib extends LFunction {
return (File) vm.checkudata(index, File.class);
}
private static File optfile(LuaState vm, int index, File defval) {
private File optfile(LuaState vm, int index, char defval) {
Object u = vm.touserdata(index);
return (u instanceof File? (File) u: defval);
return (u instanceof File? (File) u:
defval==DEFVAL_STDOUT? output(vm):
defval==DEFVAL_STDIN? input(vm):
null);
}
private static void checkopen(LuaState vm, File file) {
@@ -287,13 +349,16 @@ public class IoLib extends LFunction {
private static void setresult(LuaState vm, File file) {
vm.settop(0);
vm.pushlvalue(new LUserData(file, FILE_MT));
vm.pushlvalue(touserdata(file));
}
private static LUserData touserdata(File file) {
return new LUserData(file, FILE_MT);
}
private File ioopenfile(LuaState vm, String filename, String mode) {
try {
File f = openFile( filename, mode );
setresult( vm, f );
return f;
} catch ( Exception e ) {
vm.error("io error: "+e.getMessage());

View File

@@ -22,16 +22,22 @@
package org.luaj.lib.j2se;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.Closeable;
import java.io.DataInput;
import java.io.DataInputStream;
import java.io.DataOutput;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
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;
public class J2seIoLib extends IoLib {
@@ -53,143 +59,153 @@ public class J2seIoLib extends IoLib {
}
protected File openFile(String filename, String mode) throws IOException {
return ( mode == null || mode.startsWith("r") )?
new InputFileImpl(
"-".equals(filename)?
System.in:
new FileInputStream(filename) ):
new OutputFileImpl(
"-".equals(filename)?
System.out:
new FileOutputStream(filename, mode.endsWith("+")) );
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 )
f.seek(f.length());
return new FileImpl( f );
}
private static void notimplemented() {
throw new RuntimeException("not implemented");
}
private static final class InputFileImpl implements File {
private static final class FileImpl implements File {
private final RandomAccessFile file;
private final InputStream is;
private final OutputStream os;
private final Closeable closer;
private final DataInput din;
private final DataOutput dout;
private boolean closed = false;
private InputFileImpl( InputStream is ) {
this.is = is.markSupported()? is: new BufferedInputStream(is);
private FileImpl( RandomAccessFile file, InputStream is, OutputStream os, DataInput din, DataOutput dout, Closeable closer ) {
this.file = file;
this.is = is!=null? is.markSupported()? is: new BufferedInputStream(is): null;
this.os = os;
this.din = din;
this.dout = dout;
this.closer = closer;
}
private FileImpl( RandomAccessFile f ) {
this( f, null, null, f, f, f );
}
private FileImpl( InputStream i ) {
this( null, i, null, new DataInputStream(i), null, i );
}
private FileImpl( OutputStream o ) {
this( null, null, o, null, new DataOutputStream(o), o );
}
public String toString() {
return "file ("+this.hashCode()+")";
}
public void close() throws IOException {
closed = true;
is.close();
closer.close();
}
public void flush() {
notimplemented();
public void flush() throws IOException {
if ( os != null )
os.flush();
}
public void write(LString string) {
notimplemented();
public void write(LString s) throws IOException {
if ( dout != null )
dout.write( s.m_bytes, s.m_offset, s.m_length );
else
notimplemented();
}
public boolean isclosed() {
return closed;
}
public int seek(String option, int bytecount) throws IOException {
public int seek(String option, int pos) throws IOException {
if ( file != null ) {
if ( "set".equals(option) )
file.seek(pos);
else if ( "end".equals(option) )
file.seek(file.length()+pos);
else
file.seek(file.getFilePointer()+pos);
return (int) file.getFilePointer();
}
notimplemented();
return 0;
}
public byte[] readBytes(int count) throws IOException {
byte[] b = new byte[count];
int n;
for ( int i=0; i<count; ) {
n = is.read(b,i,count-i);
if ( n < 0 )
throw new java.io.EOFException("eof");
i += n;
public LValue readBytes(int count) throws IOException {
if ( din != null ) {
byte[] b = new byte[count];
din.readFully(b);
return new LString(b);
}
return b;
notimplemented();
return LNil.NIL;
}
public LString readLine() throws IOException {
public LValue readLine() throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int c;
while ( true ) {
int c = is.read();
if ( is != null ) {
c = is.read();
} else {
c = file.read();
}
if ( c < 0 || c == '\n' )
break;
baos.write(c);
}
return new LString(baos.toByteArray());
return ( c < 0 && baos.size() == 0 )?
LNil.NIL:
new LString(baos.toByteArray());
}
public LString readFile() throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
while ( true ) {
int c = is.read();
if ( c < 0 )
break;
baos.write(c);
}
return 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 )
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 ) {
c = is.read();
if ( c < 0 )
return null;
if ( "\t\r\n ".indexOf(c) < 0 )
break;
}
if ( (c < '0' || c > '9') && c != '-' && c != '.' )
return null;
baos.write(c);
while ( true ) {
is.mark(1);
c = is.read();
if ( c < 0 )
break;
if ( (c < '0' || c > '9') && c != '-' && c != '.' ) {
is.reset();
break;
if ( is != null ) {
is.mark(1);
c = is.read();
} else {
baos.write( c );
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 Double.valueOf(baos.toString());
}
}
private static final class OutputFileImpl implements File {
private final OutputStream os;
private boolean closed = false;
private OutputFileImpl( OutputStream os ) {
this.os = os;
}
public void close() throws IOException {
closed = true;
os.close();
}
public void flush() throws IOException {
os.flush();
}
public void write(LString s) throws IOException {
os.write(s.m_bytes, s.m_offset, s.m_length);
}
public boolean isclosed() {
return closed;
}
public int seek(String option, int bytecount) throws IOException {
notimplemented();
return 0;
}
public byte[] readBytes(int count) throws IOException {
notimplemented();
return null;
}
public LString readLine() throws IOException {
notimplemented();
return null;
}
public Double readNumber() throws IOException {
notimplemented();
return null;
}
public LString readFile() throws IOException {
notimplemented();
return null;
}
}
}

View File

@@ -1,5 +1,6 @@
-- simple io-library tests
print( io ~= nil )
print( io.open ~= nil )
print( io.stdin ~= nil )
print( io.stdout ~= nil )
print( io.stderr ~= nil )