Implement io.tmpfile(), io.setvbuf(), and tests for both

This commit is contained in:
James Roseborough
2008-12-05 18:25:30 +00:00
parent 5e734e1650
commit b8237ec872
4 changed files with 128 additions and 24 deletions

View File

@@ -38,6 +38,7 @@ public class IoLib extends LFunction {
protected interface File { protected interface File {
public void write( LString string ) throws IOException; public void write( LString string ) throws IOException;
public void flush() throws IOException; public void flush() throws IOException;
public boolean isstdfile();
public void close() throws IOException; public void close() throws IOException;
public boolean isclosed(); public boolean isclosed();
/** returns new position */ /** returns new position */
@@ -46,6 +47,7 @@ public class IoLib extends LFunction {
public Double readNumber() throws IOException; public Double readNumber() throws IOException;
public LValue readLine() throws IOException; public LValue readLine() throws IOException;
public LValue readFile() throws IOException; public LValue readFile() throws IOException;
public void setvbuf(String mode, int size);
} }
@@ -63,6 +65,13 @@ public class IoLib extends LFunction {
*/ */
abstract protected File openFile(String filename, String mode) throws IOException; abstract protected File openFile(String filename, String mode) throws IOException;
/**
* Open a temporary file.
* @return File object if successful
* @throws IOException if could not be opened
*/
abstract protected File tmpFile() throws IOException;
/** /**
* Start a new process and return a file for input or output * Start a new process and return a file for input or output
* @param prog the program to execute * @param prog the program to execute
@@ -198,9 +207,8 @@ public class IoLib extends LFunction {
f = vm.isnoneornil(2)? f = vm.isnoneornil(2)?
output(vm): output(vm):
checkfile(vm,2); checkfile(vm,2);
f.close(); checkopen(vm, f);
vm.resettop(); ioclose(vm,f);
vm.pushboolean(true);
break; break;
case IO_FLUSH: case IO_FLUSH:
checkopen(vm,output(vm)); checkopen(vm,output(vm));
@@ -220,8 +228,9 @@ public class IoLib extends LFunction {
INPUT = vm.isnoneornil(2)? INPUT = vm.isnoneornil(2)?
input(vm): input(vm):
ioopenfile(vm,vm.checkstring(2),"r"); ioopenfile(vm,vm.checkstring(2),"r");
checkopen(vm, INPUT);
vm.resettop(); vm.resettop();
vm.pushlvalue(lines(INPUT)); vm.pushlvalue(lines(vm,INPUT));
break; break;
case IO_OPEN: case IO_OPEN:
setresult(vm, openFile(vm.checkstring(2), vm.optstring(3,"r"))); setresult(vm, openFile(vm.checkstring(2), vm.optstring(3,"r")));
@@ -238,9 +247,11 @@ public class IoLib extends LFunction {
setresult(vm, openProgram(vm.checkstring(2),vm.optstring(3, "r"))); setresult(vm, openProgram(vm.checkstring(2),vm.optstring(3, "r")));
break; break;
case IO_READ: case IO_READ:
checkopen(vm, INPUT);
ioread( vm, INPUT ); ioread( vm, INPUT );
break; break;
case IO_TMPFILE: case IO_TMPFILE:
setresult(vm, tmpFile());
break; break;
case IO_TYPE: case IO_TYPE:
f = optfile(vm,2); f = optfile(vm,2);
@@ -251,22 +262,23 @@ public class IoLib extends LFunction {
vm.pushnil(); vm.pushnil();
break; break;
case IO_WRITE: case IO_WRITE:
checkopen(vm, output(vm));
iowrite( vm, OUTPUT ); iowrite( vm, OUTPUT );
break; break;
case FILE_CLOSE: case FILE_CLOSE:
checkfile(vm,2).close(); f = checkfile(vm,2);
vm.resettop(); ioclose(vm, f);
vm.pushboolean(true);
break; break;
case FILE_FLUSH: case FILE_FLUSH:
checkfile(vm,2).flush(); f = checkfile(vm,2);
f.flush();
vm.resettop(); vm.resettop();
vm.pushboolean(true); vm.pushboolean(true);
break; break;
case FILE_LINES: case FILE_LINES:
f = checkfile(vm,2); f = checkfile(vm,2);
vm.resettop(); vm.resettop();
vm.pushlvalue(lines(f)); vm.pushlvalue(lines(vm,f));
break; break;
case FILE_READ: case FILE_READ:
f = checkfile(vm,2); f = checkfile(vm,2);
@@ -281,7 +293,11 @@ public class IoLib extends LFunction {
vm.pushinteger(n); vm.pushinteger(n);
break; break;
case FILE_SETVBUF: case FILE_SETVBUF:
f = checkfile(vm,2);
vm.remove(2);
f.setvbuf(vm.checkstring(2),vm.optint(3, 1024));
vm.resettop(); vm.resettop();
vm.pushboolean(true);
break; break;
case FILE_WRITE: case FILE_WRITE:
f = checkfile(vm,2); f = checkfile(vm,2);
@@ -292,22 +308,44 @@ public class IoLib extends LFunction {
LuaState.vmerror( "bad io id" ); LuaState.vmerror( "bad io id" );
} }
} catch ( IOException ioe ) { } catch ( IOException ioe ) {
vm.resettop(); seterrorresult(vm,ioe);
vm.pushnil();
vm.pushstring("io error: "+ioe.getMessage());
} }
return false; return false;
} }
private LValue lines(final File f) { private static void ioclose(LuaState vm, File f) throws IOException {
if ( f.isstdfile() )
seterrorresult(vm,"cannot close standard file");
else {
f.close();
setsuccessresult(vm);
}
}
private static void setsuccessresult(LuaState vm) {
vm.resettop();
vm.pushboolean(true);
}
private static void seterrorresult(LuaState vm, IOException ioe) {
String s = ioe.getMessage();
seterrorresult(vm, "io error: "+(s!=null? s: ioe.toString()));
}
private static void seterrorresult(LuaState vm, String errortext) {
vm.resettop();
vm.pushnil();
vm.pushstring(errortext);
}
private LValue lines(LuaState vm, final File f) {
return new LFunction() { return new LFunction() {
public boolean luaStackCall(LuaState vm) { public boolean luaStackCall(LuaState vm) {
vm.resettop(); vm.resettop();
try { try {
vm.pushlvalue(f.readLine()); vm.pushlvalue(f.readLine());
} catch (IOException e) { } catch (IOException e) {
vm.pushnil(); seterrorresult(vm,e);
vm.pushstring("io error: "+e);
} }
return false; return false;
} }
@@ -315,7 +353,6 @@ public class IoLib extends LFunction {
} }
private static void iowrite(LuaState vm, File f) throws IOException { private static void iowrite(LuaState vm, File f) throws IOException {
checkopen(vm,f);
for ( int i=2, n=vm.gettop(); i<=n; i++ ) for ( int i=2, n=vm.gettop(); i<=n; i++ )
f.write( vm.checklstring(i) ); f.write( vm.checklstring(i) );
vm.resettop(); vm.resettop();
@@ -323,7 +360,6 @@ public class IoLib extends LFunction {
} }
private static void ioread(LuaState vm, File f) throws IOException { private static void ioread(LuaState vm, File f) throws IOException {
checkopen( vm, f );
int i,n=vm.gettop(); int i,n=vm.gettop();
for ( i=2; i<=n; i++ ) { for ( i=2; i<=n; i++ ) {
if ( vm.isnumber(i) ) { if ( vm.isnumber(i) ) {
@@ -345,7 +381,9 @@ public class IoLib extends LFunction {
} }
private static File checkfile(LuaState vm, int index) { private static File checkfile(LuaState vm, int index) {
return (File) vm.checkudata(index, File.class); File f = (File) vm.checkudata(index, File.class);
checkopen( vm, f );
return f;
} }
private File optfile(LuaState vm, int index) { private File optfile(LuaState vm, int index) {
@@ -353,9 +391,10 @@ public class IoLib extends LFunction {
return (u instanceof File? (File) u: null); return (u instanceof File? (File) u: null);
} }
private static void checkopen(LuaState vm, File file) { private static File checkopen(LuaState vm, File file) {
if ( file.isclosed() ) if ( file.isclosed() )
vm.error("attempt to use a closed file"); vm.error("attempt to use a closed file");
return file;
} }
private static void setresult(LuaState vm, File file) { private static void setresult(LuaState vm, File file) {

View File

@@ -82,6 +82,7 @@ public class J2seIoLib extends IoLib {
private final InputStream is; private final InputStream is;
private final OutputStream os; private final OutputStream os;
private boolean closed = false; private boolean closed = false;
private boolean nobuffer = false;
private FileImpl( RandomAccessFile file, InputStream is, OutputStream os ) { private FileImpl( RandomAccessFile file, InputStream is, OutputStream os ) {
this.file = file; this.file = file;
this.is = is!=null? is.markSupported()? is: new BufferedInputStream(is): null; this.is = is!=null? is.markSupported()? is: new BufferedInputStream(is): null;
@@ -99,14 +100,14 @@ public class J2seIoLib extends IoLib {
public String toString() { public String toString() {
return "file ("+this.hashCode()+")"; return "file ("+this.hashCode()+")";
} }
public boolean isstdfile() {
return file == null;
}
public void close() throws IOException { public void close() throws IOException {
closed = true; closed = true;
if ( file != null ) if ( file != null ) {
file.close(); file.close();
else if ( os != null ) }
os.close();
else if ( is != null )
is.close();
} }
public void flush() throws IOException { public void flush() throws IOException {
if ( os != null ) if ( os != null )
@@ -119,6 +120,8 @@ public class J2seIoLib extends IoLib {
file.write( s.m_bytes, s.m_offset, s.m_length ); file.write( s.m_bytes, s.m_offset, s.m_length );
else else
notimplemented(); notimplemented();
if ( nobuffer )
flush();
} }
public boolean isclosed() { public boolean isclosed() {
return closed; return closed;
@@ -139,6 +142,9 @@ public class J2seIoLib extends IoLib {
notimplemented(); notimplemented();
return 0; return 0;
} }
public void setvbuf(String mode, int size) {
nobuffer = "no".equals(mode);
}
public LValue readBytes(int count) throws IOException { public LValue readBytes(int count) throws IOException {
if ( file != null ) { if ( file != null ) {
byte[] b = new byte[count]; byte[] b = new byte[count];
@@ -217,4 +223,10 @@ public class J2seIoLib extends IoLib {
new FileImpl( p.getOutputStream() ): new FileImpl( p.getOutputStream() ):
new FileImpl( p.getInputStream() ); 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

@@ -66,3 +66,10 @@ checkallerrors('file.seek',{},'bad argument #1')
checkallerrors('file.seek',{{file},nonstring},'bad argument #1') checkallerrors('file.seek',{{file},nonstring},'bad argument #1')
checkallerrors('file.seek',{{file},{"set","cur","end"},nonnumber},'bad argument #2') checkallerrors('file.seek',{{file},{"set","cur","end"},nonnumber},'bad argument #2')
-- file:setvbuf (mode [, size])
checkallpass('file.setvbuf',{{file},{"no","full","line"}})
checkallpass('file.setvbuf',{{file},{"full"},{1024,"512"}})
checkallerrors('file.setvbuf',{},'bad argument #1')
checkallerrors('file.setvbuf',{{file},notastring},'bad argument #1')
checkallerrors('file.setvbuf',{{file},{"full"},nonnumber},'bad argument #2')

View File

@@ -61,3 +61,49 @@ for l in io.lines() do
print( string.format('%q',l) ) print( string.format('%q',l) )
end end
local a = io.tmpfile()
local b = io.tmpfile()
print( io.type(a) )
print( io.type(b) )
print( "a:write", a:write('aaaaaaa') )
print( "b:write", b:write('bbbbbbb') )
print( "a:setvbuf", a:setvbuf("no") )
print( "a:setvbuf", a:setvbuf("full",1024) )
print( "a:setvbuf", a:setvbuf("line") )
print( "a:write", a:write('ccccc') )
print( "b:write", b:write('ddddd') )
print( "a:flush", a:flush() )
print( "b:flush", b:flush() )
--[[
print( "a:read", a:read(7) )
print( "b:read", b:read(7) )
print( "a:seek", a:seek("cur",-4) )
print( "b:seek", b:seek("cur",-4) )
print( "a:write", a:read(7) )
print( "b:write", b:read(7) )
--]]
local pcall = function(...) return ( pcall(...) )end
print( 'a:close', pcall( a.close, a ) )
print( 'a:write', pcall( a.write, a, 'eee') )
print( 'a:flush', pcall( a.flush, a) )
print( 'a:read', pcall( a.read, a, 5) )
print( 'a:lines', pcall( a.lines, a) )
print( 'a:seek', pcall( a.seek, a, "cur", -2) )
print( 'a:setvbuf', pcall( a.setvbuf, a, "no") )
print( 'a:close', pcall( a.close, a ) )
print( 'io.type(a)', pcall( io.type, a ) )
print( 'io.close()', pcall( io.close ) )
print( 'io.close(io.output())', pcall( io.close, io.output() ) )
io.output('abc.txt')
print( 'io.close()', pcall( io.close ) )
print( 'io.write', pcall( io.write, 'eee') )
print( 'io.flush', pcall( io.flush) )
print( 'io.close', pcall( io.close ) )
io.input('abc.txt'):close()
print( 'io.read', pcall( io.read, 5) )
print( 'io.lines', pcall( io.lines) )