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 {
|
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) {
|
||||||
|
|||||||
@@ -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") );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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')
|
||||||
|
|
||||||
|
|||||||
@@ -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) )
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user