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 {
public void write( LString string ) throws IOException;
public void flush() throws IOException;
public boolean isstdfile();
public void close() throws IOException;
public boolean isclosed();
/** returns new position */
@@ -46,6 +47,7 @@ public class IoLib extends LFunction {
public Double readNumber() throws IOException;
public LValue readLine() 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;
/**
* 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
* @param prog the program to execute
@@ -198,9 +207,8 @@ public class IoLib extends LFunction {
f = vm.isnoneornil(2)?
output(vm):
checkfile(vm,2);
f.close();
vm.resettop();
vm.pushboolean(true);
checkopen(vm, f);
ioclose(vm,f);
break;
case IO_FLUSH:
checkopen(vm,output(vm));
@@ -220,8 +228,9 @@ public class IoLib extends LFunction {
INPUT = vm.isnoneornil(2)?
input(vm):
ioopenfile(vm,vm.checkstring(2),"r");
checkopen(vm, INPUT);
vm.resettop();
vm.pushlvalue(lines(INPUT));
vm.pushlvalue(lines(vm,INPUT));
break;
case IO_OPEN:
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")));
break;
case IO_READ:
checkopen(vm, INPUT);
ioread( vm, INPUT );
break;
case IO_TMPFILE:
setresult(vm, tmpFile());
break;
case IO_TYPE:
f = optfile(vm,2);
@@ -251,22 +262,23 @@ public class IoLib extends LFunction {
vm.pushnil();
break;
case IO_WRITE:
checkopen(vm, output(vm));
iowrite( vm, OUTPUT );
break;
case FILE_CLOSE:
checkfile(vm,2).close();
vm.resettop();
vm.pushboolean(true);
f = checkfile(vm,2);
ioclose(vm, f);
break;
case FILE_FLUSH:
checkfile(vm,2).flush();
f = checkfile(vm,2);
f.flush();
vm.resettop();
vm.pushboolean(true);
break;
case FILE_LINES:
f = checkfile(vm,2);
vm.resettop();
vm.pushlvalue(lines(f));
vm.pushlvalue(lines(vm,f));
break;
case FILE_READ:
f = checkfile(vm,2);
@@ -281,7 +293,11 @@ public class IoLib extends LFunction {
vm.pushinteger(n);
break;
case FILE_SETVBUF:
f = checkfile(vm,2);
vm.remove(2);
f.setvbuf(vm.checkstring(2),vm.optint(3, 1024));
vm.resettop();
vm.pushboolean(true);
break;
case FILE_WRITE:
f = checkfile(vm,2);
@@ -292,22 +308,44 @@ public class IoLib extends LFunction {
LuaState.vmerror( "bad io id" );
}
} catch ( IOException ioe ) {
vm.resettop();
vm.pushnil();
vm.pushstring("io error: "+ioe.getMessage());
seterrorresult(vm,ioe);
}
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() {
public boolean luaStackCall(LuaState vm) {
vm.resettop();
try {
vm.pushlvalue(f.readLine());
} catch (IOException e) {
vm.pushnil();
vm.pushstring("io error: "+e);
seterrorresult(vm,e);
}
return false;
}
@@ -315,7 +353,6 @@ public class IoLib extends LFunction {
}
private static void iowrite(LuaState vm, File f) throws IOException {
checkopen(vm,f);
for ( int i=2, n=vm.gettop(); i<=n; i++ )
f.write( vm.checklstring(i) );
vm.resettop();
@@ -323,7 +360,6 @@ public class IoLib extends LFunction {
}
private static void ioread(LuaState vm, File f) throws IOException {
checkopen( vm, f );
int i,n=vm.gettop();
for ( i=2; i<=n; i++ ) {
if ( vm.isnumber(i) ) {
@@ -345,7 +381,9 @@ public class IoLib extends LFunction {
}
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) {
@@ -353,9 +391,10 @@ public class IoLib extends LFunction {
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() )
vm.error("attempt to use a closed file");
return 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 OutputStream os;
private boolean closed = false;
private boolean nobuffer = false;
private FileImpl( RandomAccessFile file, InputStream is, OutputStream os ) {
this.file = file;
this.is = is!=null? is.markSupported()? is: new BufferedInputStream(is): null;
@@ -99,14 +100,14 @@ public class J2seIoLib extends IoLib {
public String toString() {
return "file ("+this.hashCode()+")";
}
public boolean isstdfile() {
return file == null;
}
public void close() throws IOException {
closed = true;
if ( file != null )
if ( file != null ) {
file.close();
else if ( os != null )
os.close();
else if ( is != null )
is.close();
}
}
public void flush() throws IOException {
if ( os != null )
@@ -119,6 +120,8 @@ public class J2seIoLib extends IoLib {
file.write( s.m_bytes, s.m_offset, s.m_length );
else
notimplemented();
if ( nobuffer )
flush();
}
public boolean isclosed() {
return closed;
@@ -139,6 +142,9 @@ public class J2seIoLib extends IoLib {
notimplemented();
return 0;
}
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];
@@ -217,4 +223,10 @@ public class J2seIoLib extends IoLib {
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

@@ -66,3 +66,10 @@ checkallerrors('file.seek',{},'bad argument #1')
checkallerrors('file.seek',{{file},nonstring},'bad argument #1')
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) )
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) )