Improve compatibility with lua 5.2.

This commit is contained in:
James Roseborough
2012-09-30 15:42:36 +00:00
parent a529cbaf5c
commit 8b50a3b36b
5 changed files with 209 additions and 140 deletions

View File

@@ -23,9 +23,19 @@ package org.luaj.vm2.lib;
import java.io.IOException; import java.io.IOException;
import org.luaj.vm2.Globals;
import org.luaj.vm2.LuaTable; import org.luaj.vm2.LuaTable;
import org.luaj.vm2.LuaValue; import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs; import org.luaj.vm2.Varargs;
import org.luaj.vm2.lib.PackageLib.java_searcher;
import org.luaj.vm2.lib.PackageLib.loadlib;
import org.luaj.vm2.lib.PackageLib.lua_searcher;
import org.luaj.vm2.lib.PackageLib.preload_searcher;
import org.luaj.vm2.lib.PackageLib.require;
import org.luaj.vm2.lib.PackageLib.searchpath;
import org.luaj.vm2.lib.jme.JmePlatform;
import org.luaj.vm2.lib.jse.JseOsLib;
import org.luaj.vm2.lib.jse.JsePlatform;
/** /**
* Subclass of {@link LibFunction} which implements the standard lua {@code os} library. * Subclass of {@link LibFunction} which implements the standard lua {@code os} library.
@@ -72,22 +82,21 @@ import org.luaj.vm2.Varargs;
* @see JmePlatform * @see JmePlatform
* @see <a href="http://www.lua.org/manual/5.1/manual.html#5.8">http://www.lua.org/manual/5.1/manual.html#5.8</a> * @see <a href="http://www.lua.org/manual/5.1/manual.html#5.8">http://www.lua.org/manual/5.1/manual.html#5.8</a>
*/ */
public class OsLib extends VarArgFunction { public class OsLib extends OneArgFunction {
public static String TMP_PREFIX = ".luaj"; public static String TMP_PREFIX = ".luaj";
public static String TMP_SUFFIX = "tmp"; public static String TMP_SUFFIX = "tmp";
private static final int INIT = 0; private static final int CLOCK = 0;
private static final int CLOCK = 1; private static final int DATE = 1;
private static final int DATE = 2; private static final int DIFFTIME = 2;
private static final int DIFFTIME = 3; private static final int EXECUTE = 3;
private static final int EXECUTE = 4; private static final int EXIT = 4;
private static final int EXIT = 5; private static final int GETENV = 5;
private static final int GETENV = 6; private static final int REMOVE = 6;
private static final int REMOVE = 7; private static final int RENAME = 7;
private static final int RENAME = 8; private static final int SETLOCALE = 8;
private static final int SETLOCALE = 9; private static final int TIME = 9;
private static final int TIME = 10; private static final int TMPNAME = 10;
private static final int TMPNAME = 11;
private static final String[] NAMES = { private static final String[] NAMES = {
"clock", "clock",
@@ -106,25 +115,32 @@ public class OsLib extends VarArgFunction {
private static final long t0 = System.currentTimeMillis(); private static final long t0 = System.currentTimeMillis();
private static long tmpnames = t0; private static long tmpnames = t0;
protected Globals globals;
/** /**
* Create and OsLib instance. * Create and OsLib instance.
*/ */
public OsLib() { public OsLib() {
} }
public LuaValue init(LuaValue env) { public LuaValue call(LuaValue env) {
LuaTable t = new LuaTable(); globals = env.checkglobals();
bind(t, this.getClass(), NAMES, CLOCK); LuaTable os = new LuaTable();
env.set("os", t); for (int i = 0; i < NAMES.length; ++i)
env.get("package").get("loaded").set("os", t); os.set(NAMES[i], new OsLibFunc(i, NAMES[i]));
return t; env.set("os", os);
globals.package_.loaded.set("os", os);
return os;
} }
class OsLibFunc extends VarArgFunction {
public OsLibFunc(int opcode, String name) {
this.opcode = opcode;
this.name = name;
}
public Varargs invoke(Varargs args) { public Varargs invoke(Varargs args) {
try { try {
switch ( opcode ) { switch ( opcode ) {
case INIT:
return init(args.arg1());
case CLOCK: case CLOCK:
return valueOf(clock()); return valueOf(clock());
case DATE: { case DATE: {
@@ -135,7 +151,7 @@ public class OsLib extends VarArgFunction {
case DIFFTIME: case DIFFTIME:
return valueOf(difftime(args.checkdouble(1),args.checkdouble(2))); return valueOf(difftime(args.checkdouble(1),args.checkdouble(2)));
case EXECUTE: case EXECUTE:
return valueOf(execute(args.optjstring(1, null))); return execute(args.optjstring(1, null));
case EXIT: case EXIT:
exit(args.optint(1, 0)); exit(args.optint(1, 0));
return NONE; return NONE;
@@ -163,6 +179,7 @@ public class OsLib extends VarArgFunction {
return varargsOf(NIL, valueOf(e.getMessage())); return varargsOf(NIL, valueOf(e.getMessage()));
} }
} }
}
/** /**
* @return an approximation of the amount in seconds of CPU time used by * @return an approximation of the amount in seconds of CPU time used by
@@ -219,8 +236,8 @@ public class OsLib extends VarArgFunction {
* is available and zero otherwise. * is available and zero otherwise.
* @param command command to pass to the system * @param command command to pass to the system
*/ */
protected int execute(String command) { protected Varargs execute(String command) {
return 0; return varargsOf(NIL, valueOf("exit"), ONE);
} }
/** /**

View File

@@ -24,6 +24,7 @@ import java.io.File;
import java.io.IOException; import java.io.IOException;
import org.luaj.vm2.LuaValue; import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs;
import org.luaj.vm2.lib.LibFunction; import org.luaj.vm2.lib.LibFunction;
/** /**
@@ -79,23 +80,20 @@ public class JseOsLib extends org.luaj.vm2.lib.OsLib {
public JseOsLib() { public JseOsLib() {
} }
protected int execute(String command) { protected Varargs execute(String command) {
Runtime r = Runtime.getRuntime(); int exitValue;
try { try {
final Process p = r.exec(command); exitValue = new JseProcess(command, null, globals.STDOUT, globals.STDERR).waitFor();
try {
p.waitFor();
return p.exitValue();
} finally {
p.destroy();
}
} catch (IOException ioe) { } catch (IOException ioe) {
return EXEC_IOEXCEPTION; exitValue = EXEC_IOEXCEPTION;
} catch (InterruptedException e) { } catch (InterruptedException e) {
return EXEC_INTERRUPTED; exitValue = EXEC_INTERRUPTED;
} catch (Throwable t) { } catch (Throwable t) {
return EXEC_ERROR; exitValue = EXEC_ERROR;
} }
if (exitValue == 0)
return varargsOf(TRUE, valueOf("exit"), ZERO);
return varargsOf(NIL, valueOf("signal"), valueOf(exitValue));
} }
protected void remove(String filename) throws IOException { protected void remove(String filename) throws IOException {

View File

@@ -0,0 +1,116 @@
/*******************************************************************************
* Copyright (c) 2012 Luaj.org. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
******************************************************************************/
package org.luaj.vm2.lib.jse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/** Analog of Process that pipes input and output to client-specified streams.
*/
public class JseProcess {
final Process process;
final Thread input,output,error;
/** Construct a process around a command, with specified streams to redirect input and output to.
*
* @param cmd The command to execute, including arguments, if any
* @param stdin Optional InputStream to read from as process input, or null if input is not needed.
* @param stdout Optional OutputStream to copy process output to, or null if output is ignored.
* @param stderr Optinoal OutputStream to copy process stderr output to, or null if output is ignored.
* @throws IOException If the system process could not be created.
* @see Process
*/
public JseProcess(String[] cmd, InputStream stdin, OutputStream stdout, OutputStream stderr) throws IOException {
this(Runtime.getRuntime().exec(cmd), stdin, stdout, stderr);
}
/** Construct a process around a command, with specified streams to redirect input and output to.
*
* @param cmd The command to execute, including arguments, if any
* @param stdin Optional InputStream to read from as process input, or null if input is not needed.
* @param stdout Optional OutputStream to copy process output to, or null if output is ignored.
* @param stderr Optinoal OutputStream to copy process stderr output to, or null if output is ignored.
* @throws IOException If the system process could not be created.
* @see Process
*/
public JseProcess(String cmd, InputStream stdin, OutputStream stdout, OutputStream stderr) throws IOException {
this(Runtime.getRuntime().exec(cmd), stdin, stdout, stderr);
}
private JseProcess(Process process, InputStream stdin, OutputStream stdout, OutputStream stderr) {
this.process = process;
input = stdin == null? null: copyBytes(stdin, process.getOutputStream(), null, process.getOutputStream());
output = stdout == null? null: copyBytes(process.getInputStream(), stdout, process.getInputStream(), null);
error = stderr == null? null: copyBytes(process.getErrorStream(), stderr, process.getErrorStream(), null);
}
/** Get the exit value of the process. */
public int exitValue() {
return process.exitValue();
}
/** Wait for the process to complete, and all pending output to finish.
* @return The exit status.
* @throws InterruptedException
*/
public int waitFor() throws InterruptedException {
int r = process.waitFor();
if (input != null)
input.join();
if (output != null)
output.join();
if (error != null)
error.join();
process.destroy();
return r;
}
/** Create a thread to copy bytes from input to output. */
private Thread copyBytes(final InputStream input,
final OutputStream output, final InputStream ownedInput,
final OutputStream ownedOutput) {
Thread t = (new Thread() {
public void run() {
try {
byte[] buf = new byte[1024];
int r;
try {
while ((r = input.read(buf)) >= 0) {
output.write(buf, 0, r);
}
} finally {
if (ownedInput != null)
ownedInput.close();
if (ownedOutput != null)
ownedOutput.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
});
t.start();
return t;
}
}

View File

@@ -34,8 +34,8 @@ import java.net.URL;
import junit.framework.TestCase; import junit.framework.TestCase;
import org.luaj.vm2.lib.BaseLib;
import org.luaj.vm2.lib.ResourceFinder; import org.luaj.vm2.lib.ResourceFinder;
import org.luaj.vm2.lib.jse.JseProcess;
import org.luaj.vm2.luajc.LuaJC; import org.luaj.vm2.luajc.LuaJC;
abstract abstract
@@ -235,69 +235,8 @@ public class ScriptDrivenTest extends TestCase implements ResourceFinder {
throws IOException, InterruptedException { throws IOException, InterruptedException {
Runtime r = Runtime.getRuntime(); Runtime r = Runtime.getRuntime();
final ByteArrayOutputStream baos = new ByteArrayOutputStream(); final ByteArrayOutputStream baos = new ByteArrayOutputStream();
final Process p = r.exec(cmd); new JseProcess(cmd, input, baos, System.err).waitFor();
try {
// start a thread to write the given input to the subprocess.
Thread inputCopier = (new Thread() {
public void run() {
try {
OutputStream processStdIn = p.getOutputStream();
try {
copy(input, processStdIn);
} finally {
processStdIn.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
});
inputCopier.start();
// start another thread to read output from the subprocess.
Thread outputCopier = (new Thread() {
public void run() {
try {
InputStream processStdOut = p.getInputStream();
try {
copy(processStdOut, baos);
} finally {
processStdOut.close();
}
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
});
outputCopier.start();
// start another thread to read output from the subprocess.
Thread errorCopier = (new Thread() {
public void run() {
try {
InputStream processError = p.getErrorStream();
try {
copy(processError, System.err);
} finally {
processError.close();
}
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
});
errorCopier.start();
p.waitFor();
inputCopier.join();
outputCopier.join();
errorCopier.join();
return new String(baos.toByteArray()); return new String(baos.toByteArray());
} finally {
p.destroy();
}
} }
private String readString(InputStream is) throws IOException { private String readString(InputStream is) throws IOException {

View File

@@ -8,13 +8,12 @@
-- --
local pcall = function(...) local pcall = function(...)
local s,e,f = pcall(...) local s,e,f = pcall(...)
return s,type(e) return s,type(e),type(f)
end end
print( 'os', type(os) ) print( 'os', type(os) )
print( 'os.clock()', pcall( os.clock ) ) print( 'os.clock()', pcall( os.clock ) )
print( 'os.date()', pcall( os.date ) ) print( 'os.date()', pcall( os.date ) )
print( 'os.difftime(123000, 21500)', pcall( os.difftime, 123000, 21250 ) ) print( 'os.difftime(123000, 21500)', pcall( os.difftime, 123000, 21250 ) )
print( 'os.execute("bogus")', pcall( os.execute, '' ) )
print( 'os.getenv()', pcall( os.getenv ) ) print( 'os.getenv()', pcall( os.getenv ) )
print( 'os.getenv("bogus.key")', pcall( os.getenv, 'bogus.key' ) ) print( 'os.getenv("bogus.key")', pcall( os.getenv, 'bogus.key' ) )
local s,p = pcall( os.tmpname ) local s,p = pcall( os.tmpname )