summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorruki <[email protected]>2017-05-02 12:51:30 +0800
committerruki <[email protected]>2017-05-02 12:51:30 +0800
commite269996c0e8e09596622b378874d06e931f1f109 (patch)
treea5a740ff4838c404bd25c62647669db94880db6b
parent690218ac54b965536a740782f8c93bec75224339 (diff)
add sandbox interactive
-rw-r--r--core/src/xmake/machine.c13
-rw-r--r--core/src/xmake/makefile3
-rw-r--r--core/src/xmake/sandbox/interactive.c255
-rw-r--r--core/src/xmake/sandbox/prefix.h36
-rw-r--r--xmake/core/sandbox/modules/import/core/sandbox/sandbox.lua38
-rw-r--r--xmake/plugins/lua/xmake.lua17
6 files changed, 354 insertions, 8 deletions
diff --git a/core/src/xmake/machine.c b/core/src/xmake/machine.c
index d1e86ab68..547279bb9 100644
--- a/core/src/xmake/machine.c
+++ b/core/src/xmake/machine.c
@@ -99,6 +99,9 @@ tb_int_t xm_process_wait(lua_State* lua);
tb_int_t xm_process_waitlist(lua_State* lua);
tb_int_t xm_process_close(lua_State* lua);
+// the sandbox functions
+tb_int_t xm_sandbox_interactive(lua_State* lua);
+
/* //////////////////////////////////////////////////////////////////////////////////////
* globals
*/
@@ -161,6 +164,13 @@ static luaL_Reg const g_process_functions[] =
, { tb_null, tb_null }
};
+// the sandbox functions
+static luaL_Reg const g_sandbox_functions[] =
+{
+ { "interactive", xm_sandbox_interactive }
+, { tb_null, tb_null }
+};
+
/* //////////////////////////////////////////////////////////////////////////////////////
* private implementation
*/
@@ -364,6 +374,9 @@ xm_machine_ref_t xm_machine_init()
// bind process functions
luaL_register(impl->lua, "process", g_process_functions);
+ // bind sandbox functions
+ luaL_register(impl->lua, "sandbox", g_sandbox_functions);
+
// init host
#if defined(TB_CONFIG_OS_WINDOWS)
lua_pushstring(impl->lua, "windows");
diff --git a/core/src/xmake/makefile b/core/src/xmake/makefile
index 4b7c5192e..ef1be7390 100644
--- a/core/src/xmake/makefile
+++ b/core/src/xmake/makefile
@@ -47,7 +47,8 @@ xmake_C_FILES += \
process/openv \
process/wait \
process/waitlist \
- process/close
+ process/close \
+ sandbox/interactive
# flags
diff --git a/core/src/xmake/sandbox/interactive.c b/core/src/xmake/sandbox/interactive.c
new file mode 100644
index 000000000..8a3db4ca1
--- /dev/null
+++ b/core/src/xmake/sandbox/interactive.c
@@ -0,0 +1,255 @@
+/*!The Make-like Build Utility based on Lua
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Copyright (C) 2015 - 2017, TBOOX Open Source Group.
+ *
+ * @author ruki
+ * @file interactive.c
+ *
+ */
+
+/* Runs interactive commands, read-eval-print (REPL)
+ *
+ * Major portions taken verbatim or adapted from LuaJIT frontend and the Lua interpreter.
+ * Copyright (C) 2005-2015 Mike Pall. See Copyright Notice in luajit.h
+ * Copyright (C) 1994-2008 Lua.org, PUC-Rio. See Copyright Notice in lua.h
+ */
+
+/* //////////////////////////////////////////////////////////////////////////////////////
+ * trace
+ */
+#define TB_TRACE_MODULE_NAME "sandbox.interactive"
+#define TB_TRACE_MODULE_DEBUG (0)
+
+/* //////////////////////////////////////////////////////////////////////////////////////
+ * includes
+ */
+#include "prefix.h"
+
+/* //////////////////////////////////////////////////////////////////////////////////////
+ * macros
+ */
+
+// interactive prompt
+#define LUA_PROMPT "> "
+
+// continuation prompt
+#define LUA_PROMPT2 ">> "
+
+/* //////////////////////////////////////////////////////////////////////////////////////
+ * private implementation
+ */
+
+// report results
+static tb_void_t report(lua_State *lua, tb_int_t status)
+{
+ if (!lua_isnil(lua, -1))
+ {
+ // get message
+ tb_char_t const* msg = lua_tostring(lua, -1);
+ if (!msg) msg = "(error object is not a string)";
+
+ // print it
+ tb_printl(msg);
+ tb_print_sync();
+
+ // pop this message
+ lua_pop(lua, 1);
+ }
+}
+
+// the traceback function
+static tb_int_t traceback(lua_State *lua)
+{
+ if (!lua_isstring(lua, 1))
+ {
+ // non-string error object? try metamethod.
+ if (lua_isnoneornil(lua, 1) || !luaL_callmeta(lua, 1, "__tostring") || !lua_isstring(lua, -1))
+ return 1; // return non-string error object.
+
+ // replace object by result of __tostring metamethod.
+ lua_remove(lua, 1);
+ }
+
+ // return backtrace
+ luaL_traceback(lua, lua, lua_tostring(lua, 1), 1);
+ return 1;
+}
+
+// execute codes
+static tb_int_t docall(lua_State *lua, tb_int_t narg, tb_int_t clear)
+{
+ // get function index
+ tb_int_t base = lua_gettop(lua) - narg;
+
+ // push traceback function
+ lua_pushcfunction(lua, traceback);
+
+ // put it under chunk and args
+ lua_insert(lua, base);
+
+ // execute it
+ tb_int_t status = lua_pcall(lua, narg, (clear? 0 : LUA_MULTRET), base);
+
+ // remove traceback function
+ lua_remove(lua, base);
+
+ // force a complete garbage collection in case of errors
+ if (status != 0) lua_gc(lua, LUA_GCCOLLECT, 0);
+
+ // ok?
+ return status;
+}
+
+// print prompt
+static tb_void_t write_prompt(lua_State *lua, tb_int_t firstline)
+{
+ // get prompt characters
+ lua_getfield(lua, LUA_GLOBALSINDEX, firstline ? "_PROMPT" : "_PROMPT2");
+ tb_char_t const* p = lua_tostring(lua, -1);
+ if (!p) p = firstline? LUA_PROMPT : LUA_PROMPT2;
+
+ // print prompt
+ tb_printf(p);
+ tb_print_sync();
+
+ // remove global
+ lua_pop(lua, 1);
+}
+
+// this line is incomplete?
+static tb_int_t incomplete(lua_State *lua, tb_int_t status)
+{
+ // syntax error?
+ if (status == LUA_ERRSYNTAX)
+ {
+ size_t lmsg;
+ tb_char_t const* msg = lua_tolstring(lua, -1, &lmsg);
+ tb_char_t const* tp = msg + lmsg - (sizeof(LUA_QL("<eof>")) - 1);
+ if (tb_strstr(msg, LUA_QL("<eof>")) == tp)
+ {
+ lua_pop(lua, 1);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+// get input line
+static tb_int_t pushline(lua_State *lua, tb_int_t firstline)
+{
+ // print prompt
+ write_prompt(lua, firstline);
+
+ // get input buffer
+ tb_char_t buffer[1024];
+ if (fgets(buffer, sizeof(buffer), stdin))
+ {
+ // split line '\0'
+ tb_int_t n = tb_strlen(buffer);
+ if (n > 0 && buffer[n - 1] == '\n')
+ buffer[n - 1] = '\0';
+
+ // eval expression? .e.g = 1 + 2 * ..
+ if (firstline && buffer[0] == '=')
+ lua_pushfstring(lua, "return %s", buffer + 1);
+ else
+ lua_pushstring(lua, buffer);
+
+ // ok
+ return 1;
+ }
+
+ // no input
+ return 0;
+}
+
+// load code line
+static tb_int_t loadline(lua_State *lua)
+{
+ // get input line first
+ lua_settop(lua, 0);
+ if (!pushline(lua, 1)) // no input?
+ return -1;
+
+ // load input line
+ tb_int_t status;
+ while (1)
+ {
+ // repeat until gets a complete line
+ status = luaL_loadbuffer(lua, lua_tostring(lua, 1), lua_strlen(lua, 1), "=stdin");
+
+ // cannot try to add lines?
+ if (!incomplete(lua, status)) break;
+
+ // get more input
+ if (!pushline(lua, 0))
+ return -1;
+
+ // add a new line
+ lua_pushliteral(lua, "\n");
+
+ // cannot try to add lines?
+ lua_insert(lua, -2);
+
+ // join them
+ lua_concat(lua, 3);
+ }
+
+ // remove line
+ lua_remove(lua, 1);
+ return status;
+}
+
+/* //////////////////////////////////////////////////////////////////////////////////////
+ * implementation
+ */
+
+// sandbox.interactive()
+tb_int_t xm_sandbox_interactive(lua_State* lua)
+{
+ // check
+ tb_assert_and_check_return_val(lua, 0);
+
+ // enter interactive
+ tb_int_t status;
+ while ((status = loadline(lua)) != -1)
+ {
+ // execute codes
+ if (status == 0) status = docall(lua, 0, 0);
+
+ // report results
+ report(lua, status);
+ if (status == 0 && lua_gettop(lua) > 0)
+ {
+ // print errors
+ lua_getglobal(lua, "print");
+ lua_insert(lua, 1);
+ if (lua_pcall(lua, lua_gettop(lua)-1, 0, 0) != 0)
+ tb_printl(lua_pushfstring(lua, "error calling " LUA_QL("print") " (%s)", lua_tostring(lua, -1)));
+ }
+ }
+
+ // clear stack
+ lua_settop(lua, 0);
+ tb_printl("");
+ tb_print_sync();
+
+ // end
+ return 0;
+}
diff --git a/core/src/xmake/sandbox/prefix.h b/core/src/xmake/sandbox/prefix.h
new file mode 100644
index 000000000..a953cc85e
--- /dev/null
+++ b/core/src/xmake/sandbox/prefix.h
@@ -0,0 +1,36 @@
+/*!The Make-like Build Utility based on Lua
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Copyright (C) 2015 - 2017, TBOOX Open Source Group.
+ *
+ * @author ruki
+ * @file prefix.h
+ *
+ */
+#ifndef XM_SANDBOX_PREFIX_H
+#define XM_SANDBOX_PREFIX_H
+
+/* //////////////////////////////////////////////////////////////////////////////////////
+ * includes
+ */
+#include "../prefix.h"
+
+
+#endif
+
+
diff --git a/xmake/core/sandbox/modules/import/core/sandbox/sandbox.lua b/xmake/core/sandbox/modules/import/core/sandbox/sandbox.lua
new file mode 100644
index 000000000..ba0481726
--- /dev/null
+++ b/xmake/core/sandbox/modules/import/core/sandbox/sandbox.lua
@@ -0,0 +1,38 @@
+--!The Make-like Build Utility based on Lua
+--
+-- Licensed to the Apache Software Foundation (ASF) under one
+-- or more contributor license agreements. See the NOTICE file
+-- distributed with this work for additional information
+-- regarding copyright ownership. The ASF licenses this file
+-- to you under the Apache License, Version 2.0 (the
+-- "License"); you may not use this file except in compliance
+-- with the License. You may obtain a copy of the License at
+--
+-- http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+--
+-- Copyright (C) 2015 - 2017, TBOOX Open Source Group.
+--
+-- @author ruki
+-- @file sandbox.lua
+--
+
+-- define module
+local sandbox_core_sandbox = sandbox_core_sandbox or {}
+
+-- load modules
+local sandbox = require("sandbox/sandbox")
+local raise = require("sandbox/modules/raise")
+
+-- enter interactive mode
+function sandbox_core_sandbox.interactive()
+ sandbox.interactive()
+end
+
+-- return module
+return sandbox_core_sandbox
diff --git a/xmake/plugins/lua/xmake.lua b/xmake/plugins/lua/xmake.lua
index 917d66119..1c6b2bf27 100644
--- a/xmake/plugins/lua/xmake.lua
+++ b/xmake/plugins/lua/xmake.lua
@@ -33,6 +33,7 @@ task("lua")
-- imports
import("core.base.option")
+ import("core.sandbox.sandbox")
-- list all scripts?
if option.get("list") then
@@ -46,15 +47,17 @@ task("lua")
-- get script name
local name = option.get("script")
- if not name then
- raise("no script!")
- end
+ if name then
- -- import script
- if os.isfile(name) then
- import(path.basename(name), {rootdir = path.directory(name)}).main(unpack(option.get("arguments") or {}))
+ -- import and run script
+ if os.isfile(name) then
+ import(path.basename(name), {rootdir = path.directory(name)}).main(unpack(option.get("arguments") or {}))
+ else
+ import("scripts." .. name).main(unpack(option.get("arguments") or {}))
+ end
else
- import("scripts." .. name).main(unpack(option.get("arguments") or {}))
+ -- enter interactive mode
+ sandbox.interactive()
end
end)