/* * Copyright (c) 2013 Remko Tronçon * Licensed under the GNU General Public License. * See the COPYING file for more information. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_EDITLINE #include #endif #include using namespace Swift; #ifdef SWIFTEN_PLATFORM_WINDOWS #define EXIT_KEY "Z" #else #define EXIT_KEY "D" #endif static const std::string SLUIFT_WELCOME_STRING( "== Sluift XMPP Console (" SLUIFT_VERSION_STRING ")\nPress Ctrl-" EXIT_KEY " to exit. Type help() for help."); static const luaL_Reg defaultLibraries[] = { {"", luaopen_base}, {LUA_LOADLIBNAME, luaopen_package}, {LUA_TABLIBNAME, luaopen_table}, {LUA_IOLIBNAME, luaopen_io}, {LUA_OSLIBNAME, luaopen_os}, {LUA_STRLIBNAME, luaopen_string}, {LUA_MATHLIBNAME, luaopen_math}, {LUA_DBLIBNAME, luaopen_debug}, {"sluift", luaopen_sluift}, {NULL, NULL} }; static void checkResult(lua_State* L, int result) { if (result && !lua_isnil(L, -1)) { const char* errorMessage = lua_tostring(L, -1); throw std::runtime_error(errorMessage ? errorMessage : "Unknown error"); } } static void initialize(lua_State* L) { lua_gc(L, LUA_GCSTOP, 0); for (const luaL_Reg* lib = defaultLibraries; lib->func; lib++) { #if LUA_VERSION_NUM >= 502 luaL_requiref(L, lib->name, lib->func, 1); lua_pop(L, 1); #else lua_pushcfunction(L, lib->func); lua_pushstring(L, lib->name); lua_call(L, 1, 0); #endif } lua_gc(L, LUA_GCRESTART, 0); } static void runScript(lua_State* L, const std::string& script, const std::vector& scriptArguments) { // Create arguments table lua_createtable(L, boost::numeric_cast(scriptArguments.size()), 0); for (size_t i = 0; i < scriptArguments.size(); ++i) { lua_pushstring(L, scriptArguments[i].c_str()); lua_rawseti(L, -2, boost::numeric_cast(i+1)); } lua_setglobal(L, "arg"); // Load file checkResult(L, luaL_loadfile(L, script.c_str())); foreach (const std::string& scriptArgument, scriptArguments) { lua_pushstring(L, scriptArgument.c_str()); } checkResult(L, Console::call(L, boost::numeric_cast(scriptArguments.size()), false)); } int main(int argc, char* argv[]) { // Parse program options boost::program_options::options_description visibleOptions("Options"); visibleOptions.add_options() ("help,h", "Display this help message") ("version,v", "Display version information") ("interactive,i", "Enter interactive mode after executing script") ; boost::program_options::options_description hiddenOptions("Hidden Options"); hiddenOptions.add_options() ("script", boost::program_options::value< std::string >(), "Script to be executed") ("script-arguments", boost::program_options::value< std::vector >(), "Script arguments") ; boost::program_options::options_description options("All Options"); options.add(visibleOptions).add(hiddenOptions); boost::program_options::positional_options_description positional_options; positional_options.add("script", 1).add("script-arguments", -1); boost::program_options::variables_map arguments; try { boost::program_options::store( boost::program_options::command_line_parser(argc, argv) .options(options) .positional(positional_options).run(), arguments); } catch (const boost::program_options::unknown_option& option) { #if BOOST_VERSION >= 104200 std::cout << "Ignoring unknown option " << option.get_option_name() << " but continuing." << std::endl; #else std::cout << "Error: " << option.what() << " (continuing)" << std::endl; #endif } catch (const std::exception& e) { std::cout << "Error: " << e.what() << std::endl; return -1; } boost::program_options::notify(arguments); // Help & version if (arguments.count("help")) { std::cout << visibleOptions << "\n"; return 0; } else if (arguments.count("version")) { std::cout << SLUIFT_VERSION_STRING; return 0; } lua_State* L = luaL_newstate(); initialize(L); try { // Run script if (arguments.count("script")) { std::vector scriptArguments; if (arguments.count("script-arguments")) { scriptArguments = arguments["script-arguments"].as< std::vector >(); } runScript(L, arguments["script"].as(), scriptArguments); } // Run console if (arguments.count("interactive") || arguments.count("script") == 0) { // Import some useful functions into the global namespace lua_getglobal(L, "sluift"); std::vector globalImports = boost::assign::list_of ("help")("with"); foreach (const std::string& globalImport, globalImports) { lua_getfield(L, -1, globalImport.c_str()); lua_setglobal(L, globalImport.c_str()); } lua_pop(L, 1); std::cout << SLUIFT_WELCOME_STRING << std::endl; #ifdef HAVE_EDITLINE EditlineTerminal& terminal = EditlineTerminal::getInstance(); #else StandardTerminal terminal; #endif Console console(L, &terminal); console.run(); } } catch (const std::exception& e) { std::cerr << e.what() << std::endl; lua_close(L); return -1; } lua_close(L); return 0; }