diff options
| author | ruki <[email protected]> | 2017-05-02 12:51:30 +0800 |
|---|---|---|
| committer | ruki <[email protected]> | 2017-05-02 12:51:30 +0800 |
| commit | e269996c0e8e09596622b378874d06e931f1f109 (patch) | |
| tree | a5a740ff4838c404bd25c62647669db94880db6b | |
| parent | 690218ac54b965536a740782f8c93bec75224339 (diff) | |
add sandbox interactive
| -rw-r--r-- | core/src/xmake/machine.c | 13 | ||||
| -rw-r--r-- | core/src/xmake/makefile | 3 | ||||
| -rw-r--r-- | core/src/xmake/sandbox/interactive.c | 255 | ||||
| -rw-r--r-- | core/src/xmake/sandbox/prefix.h | 36 | ||||
| -rw-r--r-- | xmake/core/sandbox/modules/import/core/sandbox/sandbox.lua | 38 | ||||
| -rw-r--r-- | xmake/plugins/lua/xmake.lua | 17 |
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) |
