Implement io.tmpfile(), io.setvbuf(), and tests for both
This commit is contained in:
@@ -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) {
|
||||
|
||||
@@ -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") );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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')
|
||||
|
||||
|
||||
@@ -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) )
|
||||
|
||||
|
||||
Reference in New Issue
Block a user