From fd9c99fb2046507807e1fb4cd4ad24c80efd572f Mon Sep 17 00:00:00 2001 From: SaloEater Date: Tue, 10 Jun 2025 22:28:30 -0500 Subject: [PATCH 01/27] luapanda --- src/3rd party/lua-extensions/base.cpp | 18 +- src/3rd party/lua-extensions/luapanda.cpp | 1114 +++++++++++++++++ src/3rd party/lua-extensions/luapanda.h | 222 ++++ .../lua-extensions/luasocket/auxiliar.c | 154 +++ .../lua-extensions/luasocket/auxiliar.h | 54 + .../lua-extensions/luasocket/buffer.c | 273 ++++ .../lua-extensions/luasocket/buffer.h | 52 + .../lua-extensions/luasocket/compat.c | 39 + .../lua-extensions/luasocket/compat.h | 22 + .../lua-extensions/luasocket/except.c | 129 ++ .../lua-extensions/luasocket/except.h | 46 + src/3rd party/lua-extensions/luasocket/inet.c | 537 ++++++++ src/3rd party/lua-extensions/luasocket/inet.h | 56 + src/3rd party/lua-extensions/luasocket/io.c | 28 + src/3rd party/lua-extensions/luasocket/io.h | 70 ++ .../lua-extensions/luasocket/luasocket.c | 126 ++ .../lua-extensions/luasocket/luasocket.h | 36 + src/3rd party/lua-extensions/luasocket/mime.c | 852 +++++++++++++ src/3rd party/lua-extensions/luasocket/mime.h | 22 + .../lua-extensions/luasocket/options.c | 507 ++++++++ .../lua-extensions/luasocket/options.h | 116 ++ .../lua-extensions/luasocket/pierror.h | 28 + .../lua-extensions/luasocket/select.c | 214 ++++ .../lua-extensions/luasocket/select.h | 23 + .../lua-extensions/luasocket/socket.h | 75 ++ src/3rd party/lua-extensions/luasocket/tcp.c | 482 +++++++ src/3rd party/lua-extensions/luasocket/tcp.h | 43 + .../lua-extensions/luasocket/timeout.c | 226 ++++ .../lua-extensions/luasocket/timeout.h | 40 + src/3rd party/lua-extensions/luasocket/udp.c | 488 ++++++++ src/3rd party/lua-extensions/luasocket/udp.h | 39 + src/3rd party/lua-extensions/luasocket/unix.c | 69 + src/3rd party/lua-extensions/luasocket/unix.h | 26 + .../lua-extensions/luasocket/unixdgram.c | 405 ++++++ .../lua-extensions/luasocket/unixdgram.h | 28 + .../lua-extensions/luasocket/unixstream.c | 355 ++++++ .../lua-extensions/luasocket/unixstream.h | 29 + .../lua-extensions/luasocket/usocket.c | 454 +++++++ .../lua-extensions/luasocket/usocket.h | 59 + .../lua-extensions/luasocket/wsocket.c | 436 +++++++ .../lua-extensions/luasocket/wsocket.h | 33 + .../vs2022/lua_extensions.vcxproj | 32 + .../vs2022/lua_extensions.vcxproj.filters | 32 + .../xrRender/ResourceManager_Scripting.cpp | 2 +- src/xrCore/string_concatenations.h | 31 +- src/xrEngine/stdafx.h | 2 +- src/xrEngine/vs2022/xrEngine.vcxproj | 10 +- src/xrEngine/vs2022/xrEngine.vcxproj.filters | 12 +- src/xrGame/vs2022/xrGame.vcxproj | 5 +- src/xrGame/xrGame.cpp | 2 +- src/xrServerEntities/opt.lua.h | 427 +++++++ src/xrServerEntities/opt_inline.lua.h | 372 ++++++ src/xrServerEntities/script_engine.cpp | 24 +- src/xrServerEntities/script_storage.cpp | 115 +- .../vs2022/xrServerEntities.vcxproj | 0 55 files changed, 9040 insertions(+), 51 deletions(-) create mode 100644 src/3rd party/lua-extensions/luapanda.cpp create mode 100644 src/3rd party/lua-extensions/luapanda.h create mode 100644 src/3rd party/lua-extensions/luasocket/auxiliar.c create mode 100644 src/3rd party/lua-extensions/luasocket/auxiliar.h create mode 100644 src/3rd party/lua-extensions/luasocket/buffer.c create mode 100644 src/3rd party/lua-extensions/luasocket/buffer.h create mode 100644 src/3rd party/lua-extensions/luasocket/compat.c create mode 100644 src/3rd party/lua-extensions/luasocket/compat.h create mode 100644 src/3rd party/lua-extensions/luasocket/except.c create mode 100644 src/3rd party/lua-extensions/luasocket/except.h create mode 100644 src/3rd party/lua-extensions/luasocket/inet.c create mode 100644 src/3rd party/lua-extensions/luasocket/inet.h create mode 100644 src/3rd party/lua-extensions/luasocket/io.c create mode 100644 src/3rd party/lua-extensions/luasocket/io.h create mode 100644 src/3rd party/lua-extensions/luasocket/luasocket.c create mode 100644 src/3rd party/lua-extensions/luasocket/luasocket.h create mode 100644 src/3rd party/lua-extensions/luasocket/mime.c create mode 100644 src/3rd party/lua-extensions/luasocket/mime.h create mode 100644 src/3rd party/lua-extensions/luasocket/options.c create mode 100644 src/3rd party/lua-extensions/luasocket/options.h create mode 100644 src/3rd party/lua-extensions/luasocket/pierror.h create mode 100644 src/3rd party/lua-extensions/luasocket/select.c create mode 100644 src/3rd party/lua-extensions/luasocket/select.h create mode 100644 src/3rd party/lua-extensions/luasocket/socket.h create mode 100644 src/3rd party/lua-extensions/luasocket/tcp.c create mode 100644 src/3rd party/lua-extensions/luasocket/tcp.h create mode 100644 src/3rd party/lua-extensions/luasocket/timeout.c create mode 100644 src/3rd party/lua-extensions/luasocket/timeout.h create mode 100644 src/3rd party/lua-extensions/luasocket/udp.c create mode 100644 src/3rd party/lua-extensions/luasocket/udp.h create mode 100644 src/3rd party/lua-extensions/luasocket/unix.c create mode 100644 src/3rd party/lua-extensions/luasocket/unix.h create mode 100644 src/3rd party/lua-extensions/luasocket/unixdgram.c create mode 100644 src/3rd party/lua-extensions/luasocket/unixdgram.h create mode 100644 src/3rd party/lua-extensions/luasocket/unixstream.c create mode 100644 src/3rd party/lua-extensions/luasocket/unixstream.h create mode 100644 src/3rd party/lua-extensions/luasocket/usocket.c create mode 100644 src/3rd party/lua-extensions/luasocket/usocket.h create mode 100644 src/3rd party/lua-extensions/luasocket/wsocket.c create mode 100644 src/3rd party/lua-extensions/luasocket/wsocket.h create mode 100644 src/xrServerEntities/opt.lua.h create mode 100644 src/xrServerEntities/opt_inline.lua.h create mode 100644 src/xrServerEntities/vs2022/xrServerEntities.vcxproj diff --git a/src/3rd party/lua-extensions/base.cpp b/src/3rd party/lua-extensions/base.cpp index 76a0f035b..ac126e6e3 100644 --- a/src/3rd party/lua-extensions/base.cpp +++ b/src/3rd party/lua-extensions/base.cpp @@ -1,7 +1,9 @@ #include "../../build_config_defines.h" +#include "luapanda.h" + #ifdef USE_LUAJIT_ONE -#pragma comment(lib, "LuaJIT-1.1.8.lib") +#pragma comment(lib, "LuaJIT-1.1.4.lib") #else #pragma comment(lib, "lua51.lib") #endif //-USE_LUAJIT_ONE @@ -14,6 +16,8 @@ extern "C"{ #include "lfs.h" #include "lmarshal.h" + #include "luasocket/socket.h" + #include "luasocket/luasocket.h" } //#include "Libs.h" @@ -26,7 +30,7 @@ static const struct luaL_reg R[] = //extern "C" __declspec(dllexport) int luaopen_lua_extensions(lua_State *L){ - //luaopen_debug(L); + luaopen_debug(L); open_additional_libs(L); @@ -36,8 +40,16 @@ int luaopen_lua_extensions(lua_State *L){ //open_table(L); luaopen_marshal(L); //open_kb(L); - //open_log(L); + //open_log(L); luaL_register(L, "lua_extensions", R); return 0; +} + +lua_CFunction luaopen_socket_core_init() { + return luaopen_socket_core; +} + +void pdebug_init_init(lua_State* L) { + pdebug_init(L); } \ No newline at end of file diff --git a/src/3rd party/lua-extensions/luapanda.cpp b/src/3rd party/lua-extensions/luapanda.cpp new file mode 100644 index 000000000..a79c3084d --- /dev/null +++ b/src/3rd party/lua-extensions/luapanda.cpp @@ -0,0 +1,1114 @@ +// Tencent is pleased to support the open source community by making LuaPanda available. +// Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. +// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at +// https://opensource.org/licenses/BSD-3-Clause +// 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. + +#include "luapanda.h" +#include +#include +#include +#include + +//using namespace std; +static int cur_run_state = 0; //当前运行状态, c 和 lua 都可能改变这个状态,要保持同步 +static int cur_hook_state = 0; //当前hook状态, c 和 lua 都可能改变这个状态 +static int logLevel = 1; //日志等级(从lua同步) +static int pathCaseSensitivity = 1; //大小写敏感标志位(从lua同步) +//static int autoPathMode = 0; //自动路径标是否开启志位 +static int BPhit = 0; //BP命中标志位 +static int stackdeep_counter = 0; //step用的栈深度计数器 +static char hookLog[1024] = { 0 }; +const char* debug_file_path; //debugger的文件路径 +int debug_file_path_len; +const char* tools_file_path; //tools的文件路径 +int tools_file_path_len; +char config_ext[32] = ""; //后缀(从lua同步) +const char* config_cwd = ""; //cwd(从lua同步) +const char* config_tempfile_path = ""; +time_t recvMsgSeconds = 0; +const char* last_source; +int ar_current_line = 0; +int ar_def_line = 0; +int ar_lastdef_line = 0; +int bp_twice_check_res = 1; +int lua_debugger_ver = 0; // luapanda.lua的版本,便于做向下兼容 +struct path_transfer_node; +struct breakpoint; +// 路径缓存队列 getinfo -> format +std::list getinfo_to_format_cache; +// 存放断点map,key为source +std::map> all_breakpoint_map; + +enum run_state +{ + DISCONNECT = 0, + WAIT_CMD = 1, + STOP_ON_ENTRY = 2, + RUN = 3, + STEPOVER = 4, + STEPIN = 5, + STEPOUT = 6, + STEPOVER_STOP = 7, + STEPIN_STOP = 8, + STEPOUT_STOP = 9, + HIT_BREAKPOINT = 10 +}; + +enum hook_state +{ + DISCONNECT_HOOK = 0, + LITE_HOOK = 1, //全局无断点 + MID_HOOK = 2, //全局有断点,本文件无断点 + ALL_HOOK = 3, +}; + +enum hook_event +{ + CALL = 0, + RETURN = 1, + LINE = 2, + TAILRET = 4 +}; + +enum breakpoint_type +{ + CONDITION_BREAKPOINT = 0, + LOG_POINT, + LINE_BREAKPOINT +}; + +//用来缓存路径的结构体 +struct path_transfer_node { + std::string src; + std::string dst; + path_transfer_node(std::string _src, std::string _dst) { + src = _src; + dst = _dst; + } +}; + +// 断点信息 +struct breakpoint { + breakpoint_type type; + std::string info; +}; + +struct debug_auto_stack +{ + explicit debug_auto_stack(lua_State* l) { + this->L = l; + this->top = lua_gettop(L); + } + ~debug_auto_stack() { + lua_settop(this->L, this->top); + } + lua_State* L; + int top; +}; + +//内部方法声明 +void debug_hook_c(lua_State* L, lua_Debug* ar); +void check_hook_state(lua_State* L, const char* source, int current_line, int def_line, int last_line, int event = -1); +void print_to_vscode(lua_State* L, const char* msg, int level = 0); +void load(lua_State* L); + +//打印断点信息 +void print_all_breakpoint_map(lua_State* L, int print_level = 0) { + if (print_level < logLevel) { + return; + } + std::map>::iterator iter1; + std::map::iterator iter2; + std::string log_message = "[breakpoints in chook:]\n"; + for (iter1 = all_breakpoint_map.begin(); iter1 != all_breakpoint_map.end(); ++iter1) { + log_message += iter1->first; + log_message += '\n'; + for (iter2 = iter1->second.begin(); iter2 != iter1->second.end(); ++iter2) { + log_message += std::string(" line: "); + log_message += std::to_string(iter2->first); + log_message += std::string(" type: "); + switch (iter2->second.type) { + case CONDITION_BREAKPOINT: + log_message += std::string("condition breakpoint info: "); + log_message += iter2->second.info; + break; + + case LOG_POINT: + log_message += std::string("log point info: "); + log_message += iter2->second.info; + break; + + case LINE_BREAKPOINT: + log_message += std::string("line breakpoint info: "); + log_message += iter2->second.info; + break; + + default: + log_message += std::string("Invalid breakpoint type!"); + log_message += std::to_string(iter2->second.type); + break; + } + log_message += '\n'; + } + } + print_to_vscode(L, log_message.c_str(), print_level); +} + +//push_arg Template +template +void push_arg(lua_State* L, T value); + +template <> +void push_arg(lua_State* L, int value) { + lua_pushnumber(L, value); +} + +template <> +void push_arg(lua_State* L, double value) { + lua_pushnumber(L, value); +} + +template <> +void push_arg(lua_State* L, const char* value) { + lua_pushstring(L, value); +} + +void push_args(lua_State* L) {} +//push_arg Template End + +template +void push_arg(lua_State* L, T value) { + push_arg(L, value); +} + +template +void push_args(lua_State* L, T value, ARGS... args) { + push_arg(L, value); + push_args(L, std::forward(args) ...); +} +//push_args End + +template +int call_lua_function(lua_State* L, const char* lua_function_name, int retCount, ARGS... args) { + lua_getglobal(L, LUA_DEBUGGER_NAME); + if (!lua_istable(L, -1)) { + const char* err_msg = "[C Module Error]:call_lua_function Get LUA_DEBUGGER_NAME error.\n"; + print_to_vscode(L, err_msg, 2); + return -1; + } + + lua_getfield(L, -1, lua_function_name); + if (!lua_isfunction(L, -1)) { + char err_msg[100]; + snprintf(err_msg, sizeof(err_msg), "[C Module Error]:call_lua_function Get lua function '%s' error\n.", lua_function_name); + print_to_vscode(L, err_msg, 2); + return -1; + } + + push_args(L, args...); + int err_code = lua_pcall(L, sizeof...(args), retCount, 0); + if (err_code) { + char err_msg[1024]; + const char* lua_error = lua_tostring(L, -1); + snprintf(err_msg, sizeof(err_msg), "[C Module Error]:call_lua_function Call '%s' error. ErrorCode: %d, ErrorMessage: %s.\n", lua_function_name, err_code, lua_error); + print_to_vscode(L, err_msg, 2); + lua_pop(L, 1); + return err_code; + } + + return 0; +} + + +//------------Lua同步数据接口------------ +//lua层主动清除路径缓存 +extern "C" int clear_pathcache(lua_State * L) +{ + getinfo_to_format_cache.clear(); + return 0; +} + +//lua主动调用从c获取current_hook_state状态 +extern "C" int get_libhook_state(lua_State * L) +{ + lua_pushnumber(L, cur_hook_state); + return 1; +} + +//lua主动调用从c获取last_source +extern "C" int get_last_source(lua_State * L) +{ + lua_pushstring(L, last_source); + return 1; +} + +//同步luapanda.lua的版本号 +extern "C" int sync_lua_debugger_ver(lua_State * L) +{ + lua_debugger_ver = static_cast(luaL_checkinteger(L, 1)); + return 0; +} + +//同步断点命中标识 +extern "C" int sync_bp_hit(lua_State * L) { + if (cur_hook_state == DISCONNECT_HOOK) { + //返回参数个数 + return 0; + } + + BPhit = static_cast(luaL_checkinteger(L, 1)); + return 0; +} + +//同步设置 -- 日志等级, 是否debug代码段, 是否使用忽略大小写 +extern "C" int sync_config(lua_State * L) { + logLevel = static_cast(luaL_checkinteger(L, 1)); + pathCaseSensitivity = static_cast(luaL_checkinteger(L, 2)); + // autoPathMode = static_cast(luaL_optinteger(L, 3, 0)); + return 0; +} + +//同步临时文件路径 +extern "C" int sync_tempfile_path(lua_State * L) { + config_tempfile_path = luaL_checkstring(L, 1); + return 0; +} + + +//同步临时文件路径 +extern "C" int set_bp_twice_check_res(lua_State * L) { + bp_twice_check_res = (int)luaL_checknumber(L, 1); + return 0; +} + +//lua 获取版本号 +extern "C" int sync_getLibVersion(lua_State * L) { + lua_pushstring(L, HOOK_LIB_VERSION); + lua_pushnumber(L, LUA_VERSION_NUM); + return 2; +} + +//同步文件后缀 +extern "C" int sync_file_ext(lua_State * L) { + const char* ext = luaL_checkstring(L, 1); + snprintf(config_ext, sizeof(config_ext), ".%s", ext); + return 0; +} + +//debugger路径 +extern "C" int sync_debugger_path(lua_State * L) { + debug_file_path = luaL_checkstring(L, 1); + debug_file_path_len = (int)strlen(debug_file_path); + return 0; +} + +//tools路径 +extern "C" int sync_tools_path(lua_State * L) { + tools_file_path = luaL_checkstring(L, 1); + tools_file_path_len = (int)strlen(tools_file_path); + return 0; +} + +//cwd +extern "C" int sync_cwd(lua_State * L) { + config_cwd = luaL_checkstring(L, 1); + return 0; +} + +//同步运行状态给Lua C->lua +void sync_runstate_toLua(lua_State* L, int state) { + debug_auto_stack _tt(L); + cur_run_state = state; + call_lua_function(L, "changeRunState", 0, state, 1); + return; +} + +//这个接口给lua调用,用来同步状态 lua->C +extern "C" int lua_set_runstate(lua_State * L) { + cur_run_state = static_cast(luaL_checkinteger(L, 1)); + return 0; +} + +//根据运行状态修改hook状态 +void sethookstate(lua_State* L, int state) { + cur_hook_state = state; + switch (state) { + case DISCONNECT_HOOK: + lua_sethook(L, debug_hook_c, LUA_MASKRET, 1000000); + break; + case LITE_HOOK: + lua_sethook(L, debug_hook_c, LUA_MASKRET, 0); + break; + case MID_HOOK: + lua_sethook(L, debug_hook_c, LUA_MASKCALL | LUA_MASKRET, 0); + break; + case ALL_HOOK: + lua_sethook(L, debug_hook_c, LUA_MASKCALL | LUA_MASKRET | LUA_MASKLINE, 0); + break; + } +} + +//这个接口给lua调用,用来同步hook状态 lua->C +extern "C" int lua_set_hookstate(lua_State * L) { + cur_hook_state = static_cast(luaL_checkinteger(L, 1)); + sethookstate(L, cur_hook_state); + return 0; +} + +void print_to_vscode(lua_State* L, const char* msg, int level) { + if (DISCONNECT != cur_run_state && level >= logLevel) { + //打印 + call_lua_function(L, "printToVSCode", 0, msg, level); + } +} + +//获取路径(带缓存) +const char* getPath(lua_State* L, const char* source) { + debug_auto_stack _tt(L); + + if (source == nullptr) { + print_to_vscode(L, "[C Module Error]: getPath Exception: source == nullptr", 2); + return ""; + } + + //检查缓存 + for (auto iter = getinfo_to_format_cache.begin(); iter != getinfo_to_format_cache.end(); iter++) + { + if (!strcmp((*iter)->src.c_str(), source)) { + return (*iter)->dst.c_str(); + } + } + + //若缓存中没有,到lua中转换 + int lua_ret = call_lua_function(L, "getPath", 1, source); + if (lua_ret != 0) { + return ""; + } + const char* retSource = lua_tostring(L, -1); + //加入缓存,返回 + path_transfer_node* nd = new path_transfer_node(source, retSource); + getinfo_to_format_cache.push_back(nd); + + return retSource; +} + +// 向 lua 中 checkRealHitBreakpoint 查询是否在缓存中,以判断是否真正命中断点 +const int checkRealHitBreakpoint(lua_State* L, const char* source, int line) { + debug_auto_stack _tt(L); + + if (source == nullptr) { + print_to_vscode(L, "[C Module Error]: checkRealHitBreakpoint Exception: source == nullptr", 2); + return 0; + } + + //若缓存中没有,到lua中转换 + int lua_ret = call_lua_function(L, "checkRealHitBreakpoint", 1, source, line); + if (lua_ret != 0) { + return 0; + } + int realHit = lua_toboolean(L, -1); + return realHit; +} + +//供lua调用,把断点列表同步给c端 +extern "C" int sync_breakpoints(lua_State * L) { + debug_auto_stack _tt(L); + //取数组 + lua_getglobal(L, LUA_DEBUGGER_NAME); //-1 LuaPanda + if (!lua_istable(L, -1)) { + print_to_vscode(L, "[C Module Error] debug_ishit_bk get LUA_DEBUGGER_NAME error", 2); + return -1; + } + + lua_getfield(L, -1, "breaks"); + if (!lua_istable(L, -1)) { + print_to_vscode(L, "[C Module Error] debug_ishit_bk get breaks error", 2); + return -1; + } + + //遍历breaks + all_breakpoint_map.clear(); + lua_pushnil(L);//breaks nil + while (lua_next(L, -2)) { + //breaks k(string) v(table) + const char* source = luaL_checkstring(L, -2); + + std::map file_breakpoint_map; + lua_pushnil(L);//k,v, nil + while (lua_next(L, -2)) { + if (lua_debugger_ver >= 30150) { + lua_pushnil(L);//k,v, nil + while (lua_next(L, -2)) { + //k,v,k,v + lua_getfield(L, -1, "line"); //k,v,k,v,line + int line = (int)lua_tointeger(L, -1); + lua_pop(L, 1); // line + + lua_getfield(L, -1, "type"); + int type = (int)lua_tointeger(L, -1); + lua_pop(L, 1); // type + + struct breakpoint bp; + switch (type) { + case CONDITION_BREAKPOINT: { + bp.type = CONDITION_BREAKPOINT; + + lua_getfield(L, -1, "condition"); + const char* condition = luaL_checkstring(L, -1); + lua_pop(L, 1); // condition + bp.info = condition; + break; + } + + case LOG_POINT: { + bp.type = LOG_POINT; + + lua_getfield(L, -1, "logMessage"); + const char* log_message = luaL_checkstring(L, -1); + lua_pop(L, 1); // logMessage + bp.info = log_message; + break; + } + + case LINE_BREAKPOINT: + bp.type = LINE_BREAKPOINT; + + bp.info = std::to_string(line); + break; + + default: + print_to_vscode(L, "[C Module Error] Invalid breakpoint type!", 2); + return -1; + } + + file_breakpoint_map[line] = bp; + + lua_pop(L, 1);//value + //k,v,k + } + lua_pop(L, 1);//value + } + else { + // 兼容 < 3.1.5 版本的luapanda.lua + + //k,v,k,v + lua_getfield(L, -1, "line"); //k,v,k,v,line + int line = (int)lua_tointeger(L, -1); + lua_pop(L, 1); // line + + lua_getfield(L, -1, "type"); + int type = (int)lua_tointeger(L, -1); + lua_pop(L, 1); // type + + struct breakpoint bp; + switch (type) { + case CONDITION_BREAKPOINT: { + bp.type = CONDITION_BREAKPOINT; + + lua_getfield(L, -1, "condition"); + const char* condition = luaL_checkstring(L, -1); + lua_pop(L, 1); // condition + bp.info = condition; + break; + } + + case LOG_POINT: { + bp.type = LOG_POINT; + + lua_getfield(L, -1, "logMessage"); + const char* log_message = luaL_checkstring(L, -1); + lua_pop(L, 1); // logMessage + bp.info = log_message; + break; + } + + case LINE_BREAKPOINT: + bp.type = LINE_BREAKPOINT; + + bp.info = std::to_string(line); + break; + + default: + print_to_vscode(L, "[C Module Error] Invalid breakpoint type!", 2); + return -1; + } + + file_breakpoint_map[line] = bp; + + lua_pop(L, 1);//value + + } + } + all_breakpoint_map[std::string(source)] = file_breakpoint_map; + //k,v + lua_pop(L, 1);//外部每次循环 + //k + } + lua_pop(L, 1);//外部每次循环 + + print_all_breakpoint_map(L); + check_hook_state(L, last_source, ar_current_line, ar_def_line, ar_lastdef_line); + return 0; +} + +//断点命中判断 +int debug_ishit_bk(lua_State* L, const char* curPath, int current_line) { + debug_auto_stack _tt(L); + // 获取标准路径[文件名.后缀] + const char* standardPath = getPath(L, curPath); + // 判断是否存在同名文件 + std::map>::const_iterator const_iter1 = all_breakpoint_map.find(std::string(standardPath)); + if (const_iter1 == all_breakpoint_map.end()) { + return 0; + } + + // c++ all_breakpoint_map 的数据结构保持不变,和lua不一样 + // 根据是否存在相同行号 + std::map::const_iterator const_iter2 = const_iter1->second.find(current_line); + if (const_iter2 == const_iter1->second.end()) { + return 0; + } + + if (lua_debugger_ver >= 30160) { + // luapanda.lua >= 3.1.6 才会调用 + // 初步命中,到lua层中检测是否真正命中,以及断点类型 + int lua_ret = call_lua_function(L, "isHitBreakpoint", 1, standardPath, curPath, current_line); + if (lua_ret != 0) { + // 调用出错时,按命中处理 + return 1; + } + + int realHit = lua_toboolean(L, -1); + return realHit; + } + else { + // 兼容旧版本 + // 条件断点 + if (const_iter2->second.type == CONDITION_BREAKPOINT) { + std::string condition = const_iter2->second.info; + int lua_ret = call_lua_function(L, "IsMeetCondition", 1, condition.c_str()); + if (lua_ret != 0) { + return 0; + } + // if (!lua_isboolean(L, -1)) { + // print_to_vscode(L, "[Debug Lib Error] debug_ishit_bk process condition expression result error!", 2); + // return 0; + // } + int is_meet_condition = lua_toboolean(L, -1); + lua_pop(L, 1); + return is_meet_condition; + } + + // 记录点 + if (const_iter2->second.type == LOG_POINT) { + std::string log_message = "[log point output]: "; + log_message.append(const_iter2->second.info); + print_to_vscode(L, log_message.c_str(), 1); + return 0; + } + return 1; + } +} + +//判断字符串是否匹配[string " +int isCodeSection(char* str) { + if (strlen(str) > 9) { + if (str[0] == '[' && str[7] == ' ' && str[8] == '"') { + return 1; + } + } + return 0; +} + +//断点命中判断 retuen : is_hit +int breakpoint_process(lua_State* L, lua_Debug* ar) { + int is_hit = 0; + if (ar->event == LINE) { + is_hit = debug_ishit_bk(L, ar->source, ar->currentline); + // 同名文件可能会命中假断点 folder1/a.lua 和 folder2/a.lua 截取文件名都是 a.lua, 可能导致命中混淆 + if (is_hit && lua_debugger_ver >= 30160) { + // luapanda.lua >= 3.1.6 版本才会调用 + is_hit = checkRealHitBreakpoint(L, ar->source, ar->currentline); + } + + if (is_hit == 1 || BPhit) { + print_to_vscode(L, "[C Module] Breakpoint hit!"); + int record_stackdeep_counter = stackdeep_counter; + int record_cur_run_state = cur_run_state; + stackdeep_counter = 0; + sync_runstate_toLua(L, HIT_BREAKPOINT); + bp_twice_check_res = 1; + //c层掌握 STEPOVER 计数器,状态机放在lua层,c主要去读(毕竟C作为lua的扩展) + //通知lua层,lua层阻塞,发消息 + if (BPhit) { + BPhit = 0; + call_lua_function(L, "SendMsgWithStack", 0, "stopOnCodeBreakpoint"); + } + else { + call_lua_function(L, "SendMsgWithStack", 0, "stopOnBreakpoint"); + if (bp_twice_check_res == 0) { + is_hit = 0; + stackdeep_counter = record_stackdeep_counter; + sync_runstate_toLua(L, record_cur_run_state); + } + } + } + } + return is_hit; +} + +//单步处理 +void step_process(lua_State* L, lua_Debug* ar) { + //目前没有判断jump flag + if (cur_run_state == STEPOVER) { + if (ar->event == LINE && stackdeep_counter <= 0) { + sync_runstate_toLua(L, STEPOVER_STOP); + call_lua_function(L, "SendMsgWithStack", 0, "stopOnStep"); + } + else if (ar->event == CALL) { + stackdeep_counter++; + } + //5.3 的tailcall暂时不需要处理。 + else if (ar->event == RETURN) { + if (stackdeep_counter != 0) { + stackdeep_counter--; + } + } + } + else if (cur_run_state == STEPIN) { + if (ar->event == LINE) { + sync_runstate_toLua(L, STEPIN_STOP); + call_lua_function(L, "SendMsgWithStack", 0, "stopOnStepIn"); + } + + } + else if (cur_run_state == STEPOUT) { + if (ar->event == LINE) { + if (stackdeep_counter <= -1) { + stackdeep_counter = 0; + sync_runstate_toLua(L, STEPOUT_STOP); + call_lua_function(L, "SendMsgWithStack", 0, "stopOnStepOut"); + } + } + else if (ar->event == CALL) { + stackdeep_counter++; + } + //5.3 的tailcall暂时不需要处理。 + else if (ar->event == RETURN) { + stackdeep_counter--; + } + } +} + +// 无需reconnect返回1 ,需要重连时返回0 +int hook_process_reconnect(lua_State* L) { + time_t currentSecs = time(static_cast(nullptr)); + if (cur_hook_state == DISCONNECT_HOOK) { + if (currentSecs - recvMsgSeconds > 1) { + call_lua_function(L, "reConnect", 0); + recvMsgSeconds = currentSecs; + } + return 0; + } + return 1; +} + +void litehook_recv_message(lua_State* L) { + time_t currentSecs = time(static_cast(nullptr)); + //2.定时接收消息 -- 这里的状态不只是run + if (cur_hook_state == LITE_HOOK && currentSecs - recvMsgSeconds > 1) { + call_lua_function(L, "debugger_wait_msg", 0); + recvMsgSeconds = currentSecs; + } +} + +void hook_process_recv_message(lua_State* L) { + time_t currentSecs = time(static_cast(nullptr)); + if ((cur_run_state == RUN || + cur_run_state == STEPOVER || + cur_run_state == STEPIN || + cur_run_state == STEPOUT) + && currentSecs - recvMsgSeconds > 1) { + call_lua_function(L, "debugger_wait_msg", 0); + recvMsgSeconds = currentSecs; + } +} + +int hook_process_cfunction(lua_State* L, lua_Debug* ar) { + if (!(strcmp(ar->what, "C")) || ar->currentline < 0) { + //Lua5.1 tail return会走到这里 + if (!(strcmp(ar->source, "=(tail call)")) && ar->event == TAILRET && (cur_run_state == STEPOVER || cur_run_state == STEPOUT)) { + stackdeep_counter--; + } + //5.1 + return 0; + } + return 1; +} + +int hook_process_code_section(lua_State* L, lua_Debug* ar) { + //测试[string ...]形式的路径 + int isCodeSec = isCodeSection(ar->short_src); + if (isCodeSec == 1) { + //short_src是[string ]开头 + if (strchr(ar->source, '\n') || strchr(ar->source, ';') || strchr(ar->source, '=')) { + print_to_vscode(L, "hook jump Code String"); + return 0; + } + } + return 1; +} + +//检查函数中是否有断点。int check_has_breakpoint 0:全局无断点 , 1:全局有断点但本文件中无断点 , 2:本文件中有断点 , 3:函数中有断点 +int checkHasBreakpoint(lua_State* L, const char* src1, int current_line, int sline, int eline) { + debug_auto_stack tt(L); + + const char* src = getPath(L, src1); + if (!strcmp(src, "")) { + // 路径完全一致 + return ALL_HOOK; + } + + if (all_breakpoint_map.empty() == true) { + // 全局没有断点 + return LITE_HOOK; + } + + std::map>::iterator iter1; + for (iter1 = all_breakpoint_map.begin(); iter1 != all_breakpoint_map.end(); ++iter1) { + if (iter1->first == std::string(src)) { + // compare() + return ALL_HOOK; + } + } + + //文件没有断点,MIDHOOK + return MID_HOOK; +} + +void check_hook_state(lua_State* L, const char* source, int current_line, int def_line, int last_line, int event) { + if (source == nullptr) { + return; + } + if (cur_run_state == RUN && cur_hook_state != DISCONNECT_HOOK) { + int stats = checkHasBreakpoint(L, source, current_line, def_line, last_line); + if (stats == LITE_HOOK) { + sethookstate(L, LITE_HOOK); + } + else if (stats == MID_HOOK) { + sethookstate(L, MID_HOOK); + } + else if (stats == ALL_HOOK) { + sethookstate(L, ALL_HOOK); + } + + if ((event == RETURN || event == TAILRET) && cur_hook_state == MID_HOOK) { + sethookstate(L, ALL_HOOK); + } + } +} + +//这个函数要获取的消息 当前状态,断点列表 +void debug_hook_c(lua_State* L, lua_Debug* ar) { + debug_auto_stack _tt(L); + if (!hook_process_reconnect(L)) return; + if (cur_hook_state == LITE_HOOK) { + litehook_recv_message(L); + return; + } + + hook_process_recv_message(L); + + if (lua_getinfo(L, "Slf", ar) != 0) { + //if in c function , return + if (!hook_process_cfunction(L, ar)) return; + //if in debugger , return + int source_len = (int)strlen(ar->source); + if (debug_file_path_len == source_len) { + if (!strcmp(debug_file_path, ar->source)) return; + } + if (tools_file_path_len == source_len) { + if (!strcmp(tools_file_path, ar->source)) return; + } + //slua "temp buffer" + if (11 == source_len) { + if (!strcmp("temp buffer", ar->source)) return; + } + //xlua "chunk" + if (5 == source_len) { + if (!strcmp("chunk", ar->source)) return; + } + + //code section + if (!hook_process_code_section(L, ar)) return; + + //output debug info + if (logLevel == 0) { + snprintf(hookLog, sizeof(hookLog), "[hook state] event:%d | source: %s | short_src: %s | line:%d | defined:%d | laseDefined:%d | currentState:%d | currentHookState:%d \n", ar->event, ar->source, ar->short_src, ar->currentline, ar->linedefined, ar->lastlinedefined, cur_run_state, cur_hook_state); + print_to_vscode(L, hookLog); + } + + //hook_state + last_source = ar->source; + ar_def_line = ar->linedefined; + ar_lastdef_line = ar->lastlinedefined; + ar_current_line = ar->currentline; + + int is_hit = breakpoint_process(L, ar); //断点命中标记位 //line + 预判 + + //STOP_ON_ENTRY + int stop_on_entry = 0; + if (cur_run_state == STOP_ON_ENTRY && is_hit != 1) { + //STOP_ON_ENTRY + if (ar->event == LINE) { + //命中 + stop_on_entry = 1; + stackdeep_counter = 0; + call_lua_function(L, "SendMsgWithStack", 0, "stopOnEntry"); + } + } + if (is_hit == 1 || stop_on_entry == 1) { + return; + } + step_process(L, ar); + check_hook_state(L, last_source, ar_current_line, ar_def_line, ar_lastdef_line, ar->event); + } +} + +//结束hook +extern "C" int endHook(lua_State * L) +{ + cur_hook_state = DISCONNECT_HOOK; + lua_sethook(L, nullptr, 0, 0); + all_breakpoint_map.clear(); + return 0; +} + +static luaL_Reg libpdebug[] = { + { "sync_breakpoints", sync_breakpoints }, //lua同步断点给c,同步发生在新增、删除断点,连接开始时 + { "lua_set_hookstate", lua_set_hookstate }, //lua设置hook状态。lua中发生状态切换时,同步到C + { "lua_set_runstate", lua_set_runstate }, //同步运行状态 + { "sync_debugger_path", sync_debugger_path }, //同步debugger文件路径 + { "sync_tools_path", sync_tools_path }, //同步debugger文件路径 + { "sync_config", sync_config }, //同步日志等级 + { "sync_cwd", sync_cwd }, //同步cwd + { "sync_file_ext", sync_file_ext }, //同步文件后缀 + { "sync_getLibVersion", sync_getLibVersion }, //hook version + { "sync_bp_hit", sync_bp_hit }, //set BP lua向C同步状态 + { "sync_tempfile_path", sync_tempfile_path }, //sync_tempfile_path + { "endHook", endHook }, //结束hook,停止调试 + { "get_libhook_state", get_libhook_state }, + { "get_last_source", get_last_source }, + { "clear_pathcache", clear_pathcache }, + { "set_bp_twice_check_res", set_bp_twice_check_res }, + { "sync_lua_debugger_ver", sync_lua_debugger_ver }, + { nullptr, nullptr } +}; + +#ifdef USE_SOURCE_CODE +extern "C" void pdebug_init(lua_State * L) { + debug_auto_stack _tt(L); + //把libhook压入_G,里面方法填上 + lua_newtable(L); + for (size_t i = 0; i < sizeof(libpdebug) / sizeof(luaL_Reg); i++) { + if (libpdebug[i].name == nullptr) { + break; + } + lua_pushcfunction(L, libpdebug[i].func); + lua_setfield(L, -2, libpdebug[i].name); + } + lua_setglobal(L, "luapanda_chook"); +} +#else // !USE_SOURCE_CODE + +#ifdef _WIN32 +#define DEBUG_API extern "C" __declspec(dllexport) +#else +#define DEBUG_API extern "C" +#endif + +DEBUG_API int luaopen_libpdebug(lua_State* L) +{ +#ifdef _WIN32 + load(L); +#endif + +#ifdef _WIN32 + +#if LUA_VERSION_NUM == 501 + // 在windows平台编译时,luaL_register等是函数指针,运行时查找。 + if (luaL_register != nullptr) { + luaL_register(L, "libpdebug", libpdebug); + } +#elif LUA_VERSION_NUM > 501 + if (lua_createtable != nullptr && luaL_setfuncs != nullptr) { + lua_newtable(L); + luaL_setfuncs(L, libpdebug, 0); + } +#endif // LUA_VERSION_NUM + +#else // !defined(_WIN32)) + +#if LUA_VERSION_NUM == 501 + // 在macOS编译时,luaL_register等是函数,定义在lua.h中。 + luaL_register(L, "libpdebug", libpdebug); +#elif LUA_VERSION_NUM > 501 + lua_newtable(L); + luaL_setfuncs(L, libpdebug, 0); +#endif // LUA_VERSION_NUM + +#endif // ifdef _WIN32 + + return 1; +} + +#endif // USE_SOURCE_CODE + +//WIN32下函数处理方法 +#if !defined(USE_SOURCE_CODE) && defined(_WIN32) +//slua-ue template function +#if LUA_VERSION_NUM > 501 +template +RET callLuaFunction(lua_State* L) { + return getInter()->T(L); +} + +template +struct Invoker; + +template +struct Invoker { + + static RET invoke(const ARGS&... args) { + return (getInter()->*F)(args...); + } + +}; + +template +struct Invoker { + + static void invoke(const ARGS&... args) { + return (getInter()->*F)(args...); + } + +}; + +template +struct LuaCppBinding; + +template +struct LuaCppBinding { + static RET luaCFunction(ARGS... args) { + return Invoker::invoke(args...); + } +}; + +template +struct LuaCppBinding { + + static void luaCFunction(ARGS... args) { + return Invoker::invoke(args...); + } +}; +#endif // LUA_VERSION_NUM > 501 + +void Slua_UE_find_function() +{ //slua - ue Lua 5.3 +#if LUA_VERSION_NUM > 501 +#define SLUABINDING(f) LuaCppBinding::luaCFunction; + lua_version = SLUABINDING(&slua::LuaInterface::lua_version); + lua_pushstring = SLUABINDING(&slua::LuaInterface::lua_pushstring); + lua_gettop = (luaDLL_gettop)SLUABINDING(&slua::LuaInterface::lua_gettop); + lua_settop = (luaDLL_settop)SLUABINDING(&slua::LuaInterface::lua_settop); + lua_pcallk = SLUABINDING(&slua::LuaInterface::lua_pcallk); + lua_pushnumber = (luaDLL_pushnumber)SLUABINDING(&slua::LuaInterface::lua_pushnumber); + luaL_checklstring = SLUABINDING(&slua::LuaInterface::luaL_checklstring); + lua_tolstring = (luaDLL_tolstring)SLUABINDING(&slua::LuaInterface::lua_tolstring); + lua_type = (luaDLL_type)SLUABINDING(&slua::LuaInterface::lua_type); + lua_tointegerx = (luaDLL_tointegerx)SLUABINDING(&slua::LuaInterface::lua_tointegerx); + lua_pushnil = (luaDLL_pushnil)SLUABINDING(&slua::LuaInterface::lua_pushnil); + lua_getfield = (luaDLL_getfield)SLUABINDING(&slua::LuaInterface::lua_getfield); + lua_next = (luaDLL_next)SLUABINDING(&slua::LuaInterface::lua_next); + lua_getinfo = (luaDLL_getinfo)SLUABINDING(&slua::LuaInterface::lua_getinfo); + lua_sethook = (luaDLL_sethook)SLUABINDING(&slua::LuaInterface::lua_sethook); + luaL_checknumber = SLUABINDING(&slua::LuaInterface::luaL_checknumber); + lua_createtable = (luaDLL_createtable)SLUABINDING(&slua::LuaInterface::lua_createtable); + luaL_setfuncs = SLUABINDING(&slua::LuaInterface::luaL_setfuncs); + lua_getglobal = SLUABINDING(&slua::LuaInterface::lua_getglobal); + lua_toboolean = (luaDLL_toboolean)SLUABINDING(&slua::LuaInterface::lua_toboolean); +#endif +} + +void general_find_function() { + //slua, xlua +#if LUA_VERSION_NUM == 501 + luaL_register = (luaLDLL_register)GetProcAddress(hInstLibrary, "luaL_register");//501 + lua_pcall = (luaDLL_pcall)GetProcAddress(hInstLibrary, "lua_pcall");//501 + lua_tointeger = (luaDLL_tointeger)GetProcAddress(hInstLibrary, "lua_tointeger");//501 +#endif + luaL_checkinteger = (luaDLL_checkinteger)GetProcAddress(hInstLibrary, "luaL_checkinteger"); + lua_version = (luaDLL_version)GetProcAddress(hInstLibrary, "lua_version"); + lua_pushstring = (luaDLL_pushstring)GetProcAddress(hInstLibrary, "lua_pushstring"); + lua_gettop = (luaDLL_gettop)GetProcAddress(hInstLibrary, "lua_gettop"); + lua_settop = (luaDLL_settop)GetProcAddress(hInstLibrary, "lua_settop"); + lua_pushnumber = (luaDLL_pushnumber)GetProcAddress(hInstLibrary, "lua_pushnumber"); + luaL_checklstring = (luaDLL_checklstring)GetProcAddress(hInstLibrary, "luaL_checklstring"); + lua_tolstring = (luaDLL_tolstring)GetProcAddress(hInstLibrary, "lua_tolstring"); + lua_type = (luaDLL_type)GetProcAddress(hInstLibrary, "lua_type"); + lua_pushnil = (luaDLL_pushnil)GetProcAddress(hInstLibrary, "lua_pushnil"); + lua_getfield = (luaDLL_getfield)GetProcAddress(hInstLibrary, "lua_getfield"); + lua_next = (luaDLL_next)GetProcAddress(hInstLibrary, "lua_next"); + lua_getinfo = (luaDLL_getinfo)GetProcAddress(hInstLibrary, "lua_getinfo"); + lua_sethook = (luaDLL_sethook)GetProcAddress(hInstLibrary, "lua_sethook"); + luaL_checknumber = (luaDLL_checknumber)GetProcAddress(hInstLibrary, "luaL_checknumber"); + lua_pushinteger = (luaDLL_pushinteger)GetProcAddress(hInstLibrary, "lua_pushinteger"); + lua_toboolean = (luaDLL_toboolean)GetProcAddress(hInstLibrary, "lua_toboolean"); + //5.3 +#if LUA_VERSION_NUM > 501 + lua_pcallk = (luaDLL_pcallk)GetProcAddress(hInstLibrary, "lua_pcallk"); + lua_tointegerx = (luaDLL_tointegerx)GetProcAddress(hInstLibrary, "lua_tointegerx"); + lua_createtable = (luaDLL_createtable)GetProcAddress(hInstLibrary, "lua_createtable"); + luaL_setfuncs = (luaDLL_setfuncs)GetProcAddress(hInstLibrary, "luaL_setfuncs"); + lua_getglobal = (luaDLL_getglobal)GetProcAddress(hInstLibrary, "lua_getglobal"); +#endif +} + +void load(lua_State* L) +{ + + HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, 0); + if (INVALID_HANDLE_VALUE == hSnapshot) + { + //load fail + return; + } + MODULEENTRY32 mi; + mi.dwSize = sizeof(MODULEENTRY32); + BOOL bRet = Module32First(hSnapshot, &mi); + while (bRet) + { +#if LUA_VERSION_NUM > 501 + // find slua-ue dll + dll_GetLuaInterface interPtr = (dll_GetLuaInterface)GetProcAddress(mi.hModule, "GetLuaInterface"); + if (interPtr != nullptr) { + hInstLibrary = mi.hModule; + getInter = interPtr; + Slua_UE_find_function(); + break; + } +#endif + // find general lua dll + void* versionPtr = (luaDLL_sethook)GetProcAddress(mi.hModule, "lua_sethook"); + if (versionPtr != nullptr) { + hInstLibrary = mi.hModule; + general_find_function(); + break; + } + + //travel next dll + bRet = Module32Next(hSnapshot, &mi); + } +} +#endif diff --git a/src/3rd party/lua-extensions/luapanda.h b/src/3rd party/lua-extensions/luapanda.h new file mode 100644 index 000000000..4ba919ee9 --- /dev/null +++ b/src/3rd party/lua-extensions/luapanda.h @@ -0,0 +1,222 @@ +#ifndef LIBPDEBUG_H +#define LIBPDEBUG_H + +#define USE_SOURCE_CODE +//1.使用源码编译,要打开宏USE_SOURCE_CODE. win下要设置LUA_INTEGER和lua版本号 +#define LUA_DEBUGGER_NAME "LuaPanda" //debugger's name in LuaDebug.lua +#define HOOK_LIB_VERSION "3.2.0" //lib version +//#define USE_SOURCE_CODE //using source code to build +#if !defined(USE_SOURCE_CODE) && defined(_WIN32) +#define LUA_INTEGER long long //set LUA_INTEGER. In 501 is ptrdiff_t. 503 can set longlong(64bit) or int(32bit) +#define LUA_VERSION_NUM 501 //lua version used by WIN32 build lib. eg. 501,503 +#endif +//setting end + +#if !defined(USE_SOURCE_CODE) && defined(_WIN32) +#include +#include +#else +//2.如果lua源码是C++形式,注释掉下面extern "C" +extern "C" { +#include "lua.h" +#include "lualib.h" +#include "lauxlib.h" +#include "luaconf.h" +} +#endif + +//3.如果lua代码在命名空间中,要设置用户命名空间. 防止找不到lua方法 +//using namespace slua; + +#ifdef USE_SOURCE_CODE +extern "C" void pdebug_init(lua_State * L); +#endif + +#if !defined(USE_SOURCE_CODE) && defined(_WIN32) +/* +** Lua - An Extensible Extension Language +** Lua.org, PUC-Rio, Brazil (http://www.lua.org) +** See Copyright Notice at the end of this file +*/ +#if LUA_VERSION_NUM == 501 +#define lua_getglobal(L,s) lua_getfield(L, LUA_GLOBALSINDEX, (s)) +#endif + +#define LUA_TNONE (-1) +#define LUA_TNIL 0 +#define LUA_TBOOLEAN 1 +#define LUA_TLIGHTUSERDATA 2 +#define LUA_TNUMBER 3 +#define LUA_TSTRING 4 +#define LUA_TTABLE 5 +#define LUA_TFUNCTION 6 +#define LUA_TUSERDATA 7 +#define LUA_TTHREAD 8 +#define LUA_NUMBER double +#define LUA_REGISTRYINDEX (-10000) +#define LUA_ENVIRONINDEX (-10001) +#define LUA_GLOBALSINDEX (-10002) +#define lua_upvalueindex(i) (LUA_GLOBALSINDEX-(i)) +#define LUA_IDSIZE 60 +#define LUA_HOOKCALL 0 +#define LUA_HOOKRET 1 +#define LUA_HOOKLINE 2 +#define LUA_HOOKCOUNT 3 +#define LUA_HOOKTAILRET 4 +#define LUA_MASKCALL (1 << LUA_HOOKCALL) +#define LUA_MASKRET (1 << LUA_HOOKRET) +#define LUA_MASKLINE (1 << LUA_HOOKLINE) +#define LUA_MASKCOUNT (1 << LUA_HOOKCOUNT) +#define luaL_checkstring(L,n) (luaL_checklstring(L, (n), NULL)) +#define lua_tostring(L,i) lua_tolstring(L, (i), NULL) +#define lua_istable(L,n) (lua_type(L, (n)) == LUA_TTABLE) +#define lua_isfunction(L,n) (lua_type(L, (n)) == LUA_TFUNCTION) +#define lua_pop(L,n) lua_settop(L, -(n)-1) +#define lua_newtable(L) lua_createtable(L, 0, 0) + +struct lua_State; +struct lua_Debug { + int event; + const char* name; /* (n) */ + const char* namewhat; /* (n) `global', `local', `field', `method' */ + const char* what; /* (S) `Lua', `C', `main', `tail' */ + const char* source; /* (S) */ + int currentline; /* (l) */ + int nups; /* (u) number of upvalues */ + int linedefined; /* (S) */ + int lastlinedefined; /* (S) */ + char short_src[LUA_IDSIZE]; /* (S) */ + /* private part */ + int i_ci; /* active function */ +}; + +typedef LUA_INTEGER lua_Integer; +typedef LUA_NUMBER lua_Number; +typedef int (*lua_CFunction) (lua_State* L); +typedef struct luaL_Reg { + const char* name; + lua_CFunction func; +} luaL_Reg; + +#define LUA_KCONTEXT ptrdiff_t +typedef LUA_KCONTEXT lua_KContext; +//lua function +typedef lua_Integer(*luaDLL_checkinteger) (lua_State* L, int numArg); +typedef void (*lua_Hook) (lua_State* L, lua_Debug* ar); +typedef int (*lua_KFunction) (lua_State* L, int status, lua_KContext ctx); +typedef const lua_Number* (*luaDLL_version)(lua_State* L); +typedef void (*luaLDLL_register)(lua_State* L, const char* libname, const luaL_Reg* l); +typedef int (*luaDLL_gettop)(lua_State* L); +typedef const char* (*luaDLL_pushstring)(lua_State* L, const char* s); +typedef int (*luaDLL_settop)(lua_State* L, int idx); +typedef int (*luaDLL_tointeger)(lua_State* L, int idx); +typedef int (*luaDLL_next)(lua_State* L, int idx); +typedef int (*luaDLL_pcall)(lua_State* L, int nargs, int nresults, int errfunc); +typedef void (*luaDLL_pushnil)(lua_State* L); +typedef void (*luaDLL_getfield)(lua_State* L, int idx, const char* k); +typedef int (*luaDLL_getinfo)(lua_State* L, const char* what, void* ar); +typedef void (*luaDLL_pushinteger) (lua_State* L, lua_Integer n); +#if LUA_VERSION_NUM == 501 +typedef int(*luaDLL_sethook)(lua_State* L, void* func, int mask, int count); +#else +typedef void (*luaDLL_sethook)(lua_State* L, lua_Hook f, int mask, int count); +#endif +typedef void (*luaDLL_pushnumber)(lua_State* L, lua_Number n); +typedef lua_Number(*luaDLL_checknumber)(lua_State* L, int narg); +typedef const char* (*luaDLL_checklstring)(lua_State* L, int narg, size_t* len); +typedef const char* (*luaDLL_tolstring)(lua_State* L, int idx, size_t* len); +typedef int (*luaDLL_type)(lua_State* L, int idx); +//5.3 +typedef void (*luaDLL_createtable)(lua_State* L, int narray, int nrec); +typedef void (*luaDLL_setfuncs)(lua_State* L, const luaL_Reg* l, int nup); +typedef lua_Integer(*luaDLL_tointegerx)(lua_State* L, int idx, int* pisnum); +typedef int (*luaDLL_getglobal)(lua_State* L, const char* name); +typedef int (*luaDLL_pcallk)(lua_State* L, int nargs, int nresults, int msgh, lua_KContext ctx, lua_KFunction k); +typedef int (*luaDLL_toboolean)(lua_State* L, int index); + +luaDLL_checkinteger luaL_checkinteger; +luaDLL_version lua_version; +luaDLL_gettop lua_gettop; +luaDLL_pushstring lua_pushstring; +luaLDLL_register luaL_register; +luaDLL_settop lua_settop; +luaDLL_pcall lua_pcall; +luaDLL_pushnumber lua_pushnumber; +luaDLL_checklstring luaL_checklstring; +luaDLL_tointeger lua_tointeger; +luaDLL_pushnil lua_pushnil; +luaDLL_getfield lua_getfield; +luaDLL_next lua_next; +luaDLL_getinfo lua_getinfo; +luaDLL_sethook lua_sethook; +luaDLL_checknumber luaL_checknumber; +luaDLL_type lua_type; +luaDLL_tolstring lua_tolstring; +luaDLL_pushinteger lua_pushinteger; +luaDLL_toboolean lua_toboolean; +// +HMODULE hInstLibrary; + +//slua-ue header +#if LUA_VERSION_NUM > 501 +//5.3 +luaDLL_createtable lua_createtable; +luaDLL_setfuncs luaL_setfuncs; +luaDLL_tointegerx lua_tointegerx; +luaDLL_getglobal lua_getglobal; +luaDLL_pcallk lua_pcallk; +#define lua_pcall(L,n,r,f) lua_pcallk(L, (n), (r), (f), 0, NULL) +#define lua_tointeger(L,i) lua_tointegerx(L,(i),NULL); + +#define PURE_API =0 +namespace slua { + struct LuaInterface { + virtual const lua_Number* lua_version(lua_State* L) PURE_API; + virtual const char* lua_pushstring(lua_State* L, const char* s) PURE_API; + virtual int lua_gettop(lua_State* L) PURE_API; + virtual void lua_settop(lua_State* L, int index) PURE_API; + virtual int lua_pcallk(lua_State* L, int nargs, int nresults, int msgh, lua_KContext ctx, lua_KFunction k) PURE_API; + virtual void lua_pushnumber(lua_State* L, lua_Number n) PURE_API; + virtual const char* luaL_checklstring(lua_State* L, int arg, size_t* l) PURE_API; + virtual const char* lua_tolstring(lua_State* L, int index, size_t* len) PURE_API; + virtual int lua_type(lua_State* L, int index) PURE_API; + virtual lua_Integer lua_tointegerx(lua_State* L, int index, int* isnum) PURE_API; + virtual void lua_pushnil(lua_State* L) PURE_API; + virtual int lua_getfield(lua_State* L, int index, const char* k) PURE_API; + virtual int lua_next(lua_State* L, int index) PURE_API; + virtual int lua_getinfo(lua_State* L, const char* what, lua_Debug* ar) PURE_API; + virtual void lua_sethook(lua_State* L, lua_Hook f, int mask, int count) PURE_API; + virtual lua_Number luaL_checknumber(lua_State* L, int arg) PURE_API; + virtual void lua_createtable(lua_State* L, int narr, int nrec) PURE_API; + virtual void luaL_setfuncs(lua_State* L, const luaL_Reg* l, int nup) PURE_API; + virtual int lua_getglobal(lua_State* L, const char* name) PURE_API; + virtual int lua_toboolean(lua_State* L, int index) PURE_API; + }; +} +typedef slua::LuaInterface* (*dll_GetLuaInterface)(); +dll_GetLuaInterface getInter; +#endif //LUA_VERSION_NUM > 501 +#endif //_WIN32 +#endif //LIBPDEBUG_H +/****************************************************************************** +* Copyright (C) 1994-2008 Lua.org, PUC-Rio. 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. +******************************************************************************/ diff --git a/src/3rd party/lua-extensions/luasocket/auxiliar.c b/src/3rd party/lua-extensions/luasocket/auxiliar.c new file mode 100644 index 000000000..93a66a09f --- /dev/null +++ b/src/3rd party/lua-extensions/luasocket/auxiliar.c @@ -0,0 +1,154 @@ +/*=========================================================================*\ +* Auxiliar routines for class hierarchy manipulation +* LuaSocket toolkit +\*=========================================================================*/ +#include "luasocket.h" +#include "auxiliar.h" +#include +#include + +/*-------------------------------------------------------------------------*\ +* Initializes the module +\*-------------------------------------------------------------------------*/ +int auxiliar_open(lua_State *L) { + (void) L; + return 0; +} + +/*-------------------------------------------------------------------------*\ +* Creates a new class with given methods +* Methods whose names start with __ are passed directly to the metatable. +\*-------------------------------------------------------------------------*/ +void auxiliar_newclass(lua_State *L, const char *classname, luaL_Reg *func) { + luaL_newmetatable(L, classname); /* mt */ + /* create __index table to place methods */ + lua_pushstring(L, "__index"); /* mt,"__index" */ + lua_newtable(L); /* mt,"__index",it */ + /* put class name into class metatable */ + lua_pushstring(L, "class"); /* mt,"__index",it,"class" */ + lua_pushstring(L, classname); /* mt,"__index",it,"class",classname */ + lua_rawset(L, -3); /* mt,"__index",it */ + /* pass all methods that start with _ to the metatable, and all others + * to the index table */ + for (; func->name; func++) { /* mt,"__index",it */ + lua_pushstring(L, func->name); + lua_pushcfunction(L, func->func); + lua_rawset(L, func->name[0] == '_' ? -5: -3); + } + lua_rawset(L, -3); /* mt */ + lua_pop(L, 1); +} + +/*-------------------------------------------------------------------------*\ +* Prints the value of a class in a nice way +\*-------------------------------------------------------------------------*/ +int auxiliar_tostring(lua_State *L) { + char buf[32]; + if (!lua_getmetatable(L, 1)) goto error; + lua_pushstring(L, "__index"); + lua_gettable(L, -2); + if (!lua_istable(L, -1)) goto error; + lua_pushstring(L, "class"); + lua_gettable(L, -2); + if (!lua_isstring(L, -1)) goto error; + sprintf(buf, "%p", lua_touserdata(L, 1)); + lua_pushfstring(L, "%s: %s", lua_tostring(L, -1), buf); + return 1; +error: + lua_pushstring(L, "invalid object passed to 'auxiliar.c:__tostring'"); + lua_error(L); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Insert class into group +\*-------------------------------------------------------------------------*/ +void auxiliar_add2group(lua_State *L, const char *classname, const char *groupname) { + luaL_getmetatable(L, classname); + lua_pushstring(L, groupname); + lua_pushboolean(L, 1); + lua_rawset(L, -3); + lua_pop(L, 1); +} + +/*-------------------------------------------------------------------------*\ +* Make sure argument is a boolean +\*-------------------------------------------------------------------------*/ +int auxiliar_checkboolean(lua_State *L, int objidx) { + if (!lua_isboolean(L, objidx)) + auxiliar_typeerror(L, objidx, lua_typename(L, LUA_TBOOLEAN)); + return lua_toboolean(L, objidx); +} + +/*-------------------------------------------------------------------------*\ +* Return userdata pointer if object belongs to a given class, abort with +* error otherwise +\*-------------------------------------------------------------------------*/ +void *auxiliar_checkclass(lua_State *L, const char *classname, int objidx) { + void *data = auxiliar_getclassudata(L, classname, objidx); + if (!data) { + char msg[45]; + sprintf(msg, "%.35s expected", classname); + luaL_argerror(L, objidx, msg); + } + return data; +} + +/*-------------------------------------------------------------------------*\ +* Return userdata pointer if object belongs to a given group, abort with +* error otherwise +\*-------------------------------------------------------------------------*/ +void *auxiliar_checkgroup(lua_State *L, const char *groupname, int objidx) { + void *data = auxiliar_getgroupudata(L, groupname, objidx); + if (!data) { + char msg[45]; + sprintf(msg, "%.35s expected", groupname); + luaL_argerror(L, objidx, msg); + } + return data; +} + +/*-------------------------------------------------------------------------*\ +* Set object class +\*-------------------------------------------------------------------------*/ +void auxiliar_setclass(lua_State *L, const char *classname, int objidx) { + luaL_getmetatable(L, classname); + if (objidx < 0) objidx--; + lua_setmetatable(L, objidx); +} + +/*-------------------------------------------------------------------------*\ +* Get a userdata pointer if object belongs to a given group. Return NULL +* otherwise +\*-------------------------------------------------------------------------*/ +void *auxiliar_getgroupudata(lua_State *L, const char *groupname, int objidx) { + if (!lua_getmetatable(L, objidx)) + return NULL; + lua_pushstring(L, groupname); + lua_rawget(L, -2); + if (lua_isnil(L, -1)) { + lua_pop(L, 2); + return NULL; + } else { + lua_pop(L, 2); + return lua_touserdata(L, objidx); + } +} + +/*-------------------------------------------------------------------------*\ +* Get a userdata pointer if object belongs to a given class. Return NULL +* otherwise +\*-------------------------------------------------------------------------*/ +void *auxiliar_getclassudata(lua_State *L, const char *classname, int objidx) { + return luaL_testudata(L, objidx, classname); +} + +/*-------------------------------------------------------------------------*\ +* Throws error when argument does not have correct type. +* Used to be part of lauxlib in Lua 5.1, was dropped from 5.2. +\*-------------------------------------------------------------------------*/ +int auxiliar_typeerror (lua_State *L, int narg, const char *tname) { + const char *msg = lua_pushfstring(L, "%s expected, got %s", tname, + luaL_typename(L, narg)); + return luaL_argerror(L, narg, msg); +} diff --git a/src/3rd party/lua-extensions/luasocket/auxiliar.h b/src/3rd party/lua-extensions/luasocket/auxiliar.h new file mode 100644 index 000000000..e8c3ead82 --- /dev/null +++ b/src/3rd party/lua-extensions/luasocket/auxiliar.h @@ -0,0 +1,54 @@ +#ifndef AUXILIAR_H +#define AUXILIAR_H +/*=========================================================================*\ +* Auxiliar routines for class hierarchy manipulation +* LuaSocket toolkit (but completely independent of other LuaSocket modules) +* +* A LuaSocket class is a name associated with Lua metatables. A LuaSocket +* group is a name associated with a class. A class can belong to any number +* of groups. This module provides the functionality to: +* +* - create new classes +* - add classes to groups +* - set the class of objects +* - check if an object belongs to a given class or group +* - get the userdata associated to objects +* - print objects in a pretty way +* +* LuaSocket class names follow the convention {}. Modules +* can define any number of classes and groups. The module tcp.c, for +* example, defines the classes tcp{master}, tcp{client} and tcp{server} and +* the groups tcp{client,server} and tcp{any}. Module functions can then +* perform type-checking on their arguments by either class or group. +* +* LuaSocket metatables define the __index metamethod as being a table. This +* table has one field for each method supported by the class, and a field +* "class" with the class name. +* +* The mapping from class name to the corresponding metatable and the +* reverse mapping are done using lauxlib. +\*=========================================================================*/ + +#include "luasocket.h" + +#ifndef _WIN32 +#pragma GCC visibility push(hidden) +#endif + +int auxiliar_open(lua_State *L); +void auxiliar_newclass(lua_State *L, const char *classname, luaL_Reg *func); +int auxiliar_tostring(lua_State *L); +void auxiliar_add2group(lua_State *L, const char *classname, const char *group); +int auxiliar_checkboolean(lua_State *L, int objidx); +void *auxiliar_checkclass(lua_State *L, const char *classname, int objidx); +void *auxiliar_checkgroup(lua_State *L, const char *groupname, int objidx); +void auxiliar_setclass(lua_State *L, const char *classname, int objidx); +void *auxiliar_getgroupudata(lua_State *L, const char *groupname, int objidx); +void *auxiliar_getclassudata(lua_State *L, const char *groupname, int objidx); +int auxiliar_typeerror(lua_State *L, int narg, const char *tname); + +#ifndef _WIN32 +#pragma GCC visibility pop +#endif + +#endif /* AUXILIAR_H */ diff --git a/src/3rd party/lua-extensions/luasocket/buffer.c b/src/3rd party/lua-extensions/luasocket/buffer.c new file mode 100644 index 000000000..7148be34f --- /dev/null +++ b/src/3rd party/lua-extensions/luasocket/buffer.c @@ -0,0 +1,273 @@ +/*=========================================================================*\ +* Input/Output interface for Lua programs +* LuaSocket toolkit +\*=========================================================================*/ +#include "luasocket.h" +#include "buffer.h" + +/*=========================================================================*\ +* Internal function prototypes +\*=========================================================================*/ +static int recvraw(p_buffer buf, size_t wanted, luaL_Buffer *b); +static int recvline(p_buffer buf, luaL_Buffer *b); +static int recvall(p_buffer buf, luaL_Buffer *b); +static int buffer_get(p_buffer buf, const char **data, size_t *count); +static void buffer_skip(p_buffer buf, size_t count); +static int sendraw(p_buffer buf, const char *data, size_t count, size_t *sent); + +/* min and max macros */ +#ifndef MIN +#define MIN(x, y) ((x) < (y) ? x : y) +#endif +#ifndef MAX +#define MAX(x, y) ((x) > (y) ? x : y) +#endif + +/*=========================================================================*\ +* Exported functions +\*=========================================================================*/ +/*-------------------------------------------------------------------------*\ +* Initializes module +\*-------------------------------------------------------------------------*/ +int buffer_open(lua_State *L) { + (void) L; + return 0; +} + +/*-------------------------------------------------------------------------*\ +* Initializes C structure +\*-------------------------------------------------------------------------*/ +void buffer_init(p_buffer buf, p_io io, p_timeout tm) { + buf->first = buf->last = 0; + buf->io = io; + buf->tm = tm; + buf->received = buf->sent = 0; + buf->birthday = timeout_gettime(); +} + +/*-------------------------------------------------------------------------*\ +* object:getstats() interface +\*-------------------------------------------------------------------------*/ +int buffer_meth_getstats(lua_State *L, p_buffer buf) { + lua_pushnumber(L, (lua_Number) buf->received); + lua_pushnumber(L, (lua_Number) buf->sent); + lua_pushnumber(L, timeout_gettime() - buf->birthday); + return 3; +} + +/*-------------------------------------------------------------------------*\ +* object:setstats() interface +\*-------------------------------------------------------------------------*/ +int buffer_meth_setstats(lua_State *L, p_buffer buf) { + buf->received = (long) luaL_optnumber(L, 2, (lua_Number) buf->received); + buf->sent = (long) luaL_optnumber(L, 3, (lua_Number) buf->sent); + if (lua_isnumber(L, 4)) buf->birthday = timeout_gettime() - lua_tonumber(L, 4); + lua_pushnumber(L, 1); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* object:send() interface +\*-------------------------------------------------------------------------*/ +int buffer_meth_send(lua_State *L, p_buffer buf) { + int top = lua_gettop(L); + int err = IO_DONE; + size_t size = 0, sent = 0; + const char *data = luaL_checklstring(L, 2, &size); + long start = (long) luaL_optnumber(L, 3, 1); + long end = (long) luaL_optnumber(L, 4, -1); + timeout_markstart(buf->tm); + if (start < 0) start = (long) (size+start+1); + if (end < 0) end = (long) (size+end+1); + if (start < 1) start = (long) 1; + if (end > (long) size) end = (long) size; + if (start <= end) err = sendraw(buf, data+start-1, end-start+1, &sent); + /* check if there was an error */ + if (err != IO_DONE) { + lua_pushnil(L); + lua_pushstring(L, buf->io->error(buf->io->ctx, err)); + lua_pushnumber(L, (lua_Number) (sent+start-1)); + } else { + lua_pushnumber(L, (lua_Number) (sent+start-1)); + lua_pushnil(L); + lua_pushnil(L); + } +#ifdef LUASOCKET_DEBUG + /* push time elapsed during operation as the last return value */ + lua_pushnumber(L, timeout_gettime() - timeout_getstart(buf->tm)); +#endif + return lua_gettop(L) - top; +} + +/*-------------------------------------------------------------------------*\ +* object:receive() interface +\*-------------------------------------------------------------------------*/ +int buffer_meth_receive(lua_State *L, p_buffer buf) { + int err = IO_DONE, top; + luaL_Buffer b; + size_t size; + const char *part = luaL_optlstring(L, 3, "", &size); + timeout_markstart(buf->tm); + /* make sure we don't confuse buffer stuff with arguments */ + lua_settop(L, 3); + top = lua_gettop(L); + /* initialize buffer with optional extra prefix + * (useful for concatenating previous partial results) */ + luaL_buffinit(L, &b); + luaL_addlstring(&b, part, size); + /* receive new patterns */ + if (!lua_isnumber(L, 2)) { + const char *p= luaL_optstring(L, 2, "*l"); + if (p[0] == '*' && p[1] == 'l') err = recvline(buf, &b); + else if (p[0] == '*' && p[1] == 'a') err = recvall(buf, &b); + else luaL_argcheck(L, 0, 2, "invalid receive pattern"); + /* get a fixed number of bytes (minus what was already partially + * received) */ + } else { + double n = lua_tonumber(L, 2); + size_t wanted = (size_t) n; + luaL_argcheck(L, n >= 0, 2, "invalid receive pattern"); + if (size == 0 || wanted > size) + err = recvraw(buf, wanted-size, &b); + } + /* check if there was an error */ + if (err != IO_DONE) { + /* we can't push anyting in the stack before pushing the + * contents of the buffer. this is the reason for the complication */ + luaL_pushresult(&b); + lua_pushstring(L, buf->io->error(buf->io->ctx, err)); + lua_pushvalue(L, -2); + lua_pushnil(L); + lua_replace(L, -4); + } else { + luaL_pushresult(&b); + lua_pushnil(L); + lua_pushnil(L); + } +#ifdef LUASOCKET_DEBUG + /* push time elapsed during operation as the last return value */ + lua_pushnumber(L, timeout_gettime() - timeout_getstart(buf->tm)); +#endif + return lua_gettop(L) - top; +} + +/*-------------------------------------------------------------------------*\ +* Determines if there is any data in the read buffer +\*-------------------------------------------------------------------------*/ +int buffer_isempty(p_buffer buf) { + return buf->first >= buf->last; +} + +/*=========================================================================*\ +* Internal functions +\*=========================================================================*/ +/*-------------------------------------------------------------------------*\ +* Sends a block of data (unbuffered) +\*-------------------------------------------------------------------------*/ +#define STEPSIZE 8192 +static int sendraw(p_buffer buf, const char *data, size_t count, size_t *sent) { + p_io io = buf->io; + p_timeout tm = buf->tm; + size_t total = 0; + int err = IO_DONE; + while (total < count && err == IO_DONE) { + size_t done = 0; + size_t step = (count-total <= STEPSIZE)? count-total: STEPSIZE; + err = io->send(io->ctx, data+total, step, &done, tm); + total += done; + } + *sent = total; + buf->sent += total; + return err; +} + +/*-------------------------------------------------------------------------*\ +* Reads a fixed number of bytes (buffered) +\*-------------------------------------------------------------------------*/ +static int recvraw(p_buffer buf, size_t wanted, luaL_Buffer *b) { + int err = IO_DONE; + size_t total = 0; + while (err == IO_DONE) { + size_t count; const char *data; + err = buffer_get(buf, &data, &count); + count = MIN(count, wanted - total); + luaL_addlstring(b, data, count); + buffer_skip(buf, count); + total += count; + if (total >= wanted) break; + } + return err; +} + +/*-------------------------------------------------------------------------*\ +* Reads everything until the connection is closed (buffered) +\*-------------------------------------------------------------------------*/ +static int recvall(p_buffer buf, luaL_Buffer *b) { + int err = IO_DONE; + size_t total = 0; + while (err == IO_DONE) { + const char *data; size_t count; + err = buffer_get(buf, &data, &count); + total += count; + luaL_addlstring(b, data, count); + buffer_skip(buf, count); + } + if (err == IO_CLOSED) { + if (total > 0) return IO_DONE; + else return IO_CLOSED; + } else return err; +} + +/*-------------------------------------------------------------------------*\ +* Reads a line terminated by a CR LF pair or just by a LF. The CR and LF +* are not returned by the function and are discarded from the buffer +\*-------------------------------------------------------------------------*/ +static int recvline(p_buffer buf, luaL_Buffer *b) { + int err = IO_DONE; + while (err == IO_DONE) { + size_t count, pos; const char *data; + err = buffer_get(buf, &data, &count); + pos = 0; + while (pos < count && data[pos] != '\n') { + /* we ignore all \r's */ + if (data[pos] != '\r') luaL_addchar(b, data[pos]); + pos++; + } + if (pos < count) { /* found '\n' */ + buffer_skip(buf, pos+1); /* skip '\n' too */ + break; /* we are done */ + } else /* reached the end of the buffer */ + buffer_skip(buf, pos); + } + return err; +} + +/*-------------------------------------------------------------------------*\ +* Skips a given number of bytes from read buffer. No data is read from the +* transport layer +\*-------------------------------------------------------------------------*/ +static void buffer_skip(p_buffer buf, size_t count) { + buf->received += count; + buf->first += count; + if (buffer_isempty(buf)) + buf->first = buf->last = 0; +} + +/*-------------------------------------------------------------------------*\ +* Return any data available in buffer, or get more data from transport layer +* if buffer is empty +\*-------------------------------------------------------------------------*/ +static int buffer_get(p_buffer buf, const char **data, size_t *count) { + int err = IO_DONE; + p_io io = buf->io; + p_timeout tm = buf->tm; + if (buffer_isempty(buf)) { + size_t got; + err = io->recv(io->ctx, buf->data, BUF_SIZE, &got, tm); + buf->first = 0; + buf->last = got; + } + *count = buf->last - buf->first; + *data = buf->data + buf->first; + return err; +} diff --git a/src/3rd party/lua-extensions/luasocket/buffer.h b/src/3rd party/lua-extensions/luasocket/buffer.h new file mode 100644 index 000000000..a0901fcc8 --- /dev/null +++ b/src/3rd party/lua-extensions/luasocket/buffer.h @@ -0,0 +1,52 @@ +#ifndef BUF_H +#define BUF_H +/*=========================================================================*\ +* Input/Output interface for Lua programs +* LuaSocket toolkit +* +* Line patterns require buffering. Reading one character at a time involves +* too many system calls and is very slow. This module implements the +* LuaSocket interface for input/output on connected objects, as seen by +* Lua programs. +* +* Input is buffered. Output is *not* buffered because there was no simple +* way of making sure the buffered output data would ever be sent. +* +* The module is built on top of the I/O abstraction defined in io.h and the +* timeout management is done with the timeout.h interface. +\*=========================================================================*/ +#include "luasocket.h" +#include "io.h" +#include "timeout.h" + +/* buffer size in bytes */ +#define BUF_SIZE 8192 + +/* buffer control structure */ +typedef struct t_buffer_ { + double birthday; /* throttle support info: creation time, */ + size_t sent, received; /* bytes sent, and bytes received */ + p_io io; /* IO driver used for this buffer */ + p_timeout tm; /* timeout management for this buffer */ + size_t first, last; /* index of first and last bytes of stored data */ + char data[BUF_SIZE]; /* storage space for buffer data */ +} t_buffer; +typedef t_buffer *p_buffer; + +#ifndef _WIN32 +#pragma GCC visibility push(hidden) +#endif + +int buffer_open(lua_State *L); +void buffer_init(p_buffer buf, p_io io, p_timeout tm); +int buffer_meth_getstats(lua_State *L, p_buffer buf); +int buffer_meth_setstats(lua_State *L, p_buffer buf); +int buffer_meth_send(lua_State *L, p_buffer buf); +int buffer_meth_receive(lua_State *L, p_buffer buf); +int buffer_isempty(p_buffer buf); + +#ifndef _WIN32 +#pragma GCC visibility pop +#endif + +#endif /* BUF_H */ diff --git a/src/3rd party/lua-extensions/luasocket/compat.c b/src/3rd party/lua-extensions/luasocket/compat.c new file mode 100644 index 000000000..34ffdaf71 --- /dev/null +++ b/src/3rd party/lua-extensions/luasocket/compat.c @@ -0,0 +1,39 @@ +#include "luasocket.h" +#include "compat.h" + +#if LUA_VERSION_NUM==501 + +/* +** Adapted from Lua 5.2 +*/ +void luasocket_setfuncs (lua_State *L, const luaL_Reg *l, int nup) { + luaL_checkstack(L, nup+1, "too many upvalues"); + for (; l->name != NULL; l++) { /* fill the table with given functions */ + int i; + lua_pushstring(L, l->name); + for (i = 0; i < nup; i++) /* copy upvalues to the top */ + lua_pushvalue(L, -(nup+1)); + lua_pushcclosure(L, l->func, nup); /* closure with those upvalues */ + lua_settable(L, -(nup + 3)); + } + lua_pop(L, nup); /* remove upvalues */ +} + +/* +** Duplicated from Lua 5.2 +*/ +void *luasocket_testudata (lua_State *L, int ud, const char *tname) { + void *p = lua_touserdata(L, ud); + if (p != NULL) { /* value is a userdata? */ + if (lua_getmetatable(L, ud)) { /* does it have a metatable? */ + luaL_getmetatable(L, tname); /* get correct metatable */ + if (!lua_rawequal(L, -1, -2)) /* not the same? */ + p = NULL; /* value is a userdata with wrong metatable */ + lua_pop(L, 2); /* remove both metatables */ + return p; + } + } + return NULL; /* value is not a userdata with a metatable */ +} + +#endif diff --git a/src/3rd party/lua-extensions/luasocket/compat.h b/src/3rd party/lua-extensions/luasocket/compat.h new file mode 100644 index 000000000..fa2d7d7c6 --- /dev/null +++ b/src/3rd party/lua-extensions/luasocket/compat.h @@ -0,0 +1,22 @@ +#ifndef COMPAT_H +#define COMPAT_H + +#if LUA_VERSION_NUM==501 + +#ifndef _WIN32 +#pragma GCC visibility push(hidden) +#endif + +void luasocket_setfuncs (lua_State *L, const luaL_Reg *l, int nup); +void *luasocket_testudata ( lua_State *L, int arg, const char *tname); + +#ifndef _WIN32 +#pragma GCC visibility pop +#endif + +#define luaL_setfuncs luasocket_setfuncs +#define luaL_testudata luasocket_testudata + +#endif + +#endif diff --git a/src/3rd party/lua-extensions/luasocket/except.c b/src/3rd party/lua-extensions/luasocket/except.c new file mode 100644 index 000000000..9c3317f26 --- /dev/null +++ b/src/3rd party/lua-extensions/luasocket/except.c @@ -0,0 +1,129 @@ +/*=========================================================================*\ +* Simple exception support +* LuaSocket toolkit +\*=========================================================================*/ +#include "luasocket.h" +#include "except.h" +#include + +#if LUA_VERSION_NUM < 502 +#define lua_pcallk(L, na, nr, err, ctx, cont) \ + (((void)ctx),((void)cont),lua_pcall(L, na, nr, err)) +#endif + +#if LUA_VERSION_NUM < 503 +typedef int lua_KContext; +#endif + +/*=========================================================================*\ +* Internal function prototypes. +\*=========================================================================*/ +static int global_protect(lua_State *L); +static int global_newtry(lua_State *L); +static int protected_(lua_State *L); +static int finalize(lua_State *L); +static int do_nothing(lua_State *L); + +/* except functions */ +static luaL_Reg func[] = { + {"newtry", global_newtry}, + {"protect", global_protect}, + {NULL, NULL} +}; + +/*-------------------------------------------------------------------------*\ +* Try factory +\*-------------------------------------------------------------------------*/ +static void wrap(lua_State *L) { + lua_createtable(L, 1, 0); + lua_pushvalue(L, -2); + lua_rawseti(L, -2, 1); + lua_pushvalue(L, lua_upvalueindex(1)); + lua_setmetatable(L, -2); +} + +static int finalize(lua_State *L) { + if (!lua_toboolean(L, 1)) { + lua_pushvalue(L, lua_upvalueindex(2)); + lua_call(L, 0, 0); + lua_settop(L, 2); + wrap(L); + lua_error(L); + return 0; + } else return lua_gettop(L); +} + +static int do_nothing(lua_State *L) { + (void) L; + return 0; +} + +static int global_newtry(lua_State *L) { + lua_settop(L, 1); + if (lua_isnil(L, 1)) lua_pushcfunction(L, do_nothing); + lua_pushvalue(L, lua_upvalueindex(1)); + lua_insert(L, -2); + lua_pushcclosure(L, finalize, 2); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Protect factory +\*-------------------------------------------------------------------------*/ +static int unwrap(lua_State *L) { + if (lua_istable(L, -1) && lua_getmetatable(L, -1)) { + int r = lua_rawequal(L, -1, lua_upvalueindex(1)); + lua_pop(L, 1); + if (r) { + lua_pushnil(L); + lua_rawgeti(L, -2, 1); + return 1; + } + } + return 0; +} + +static int protected_finish(lua_State *L, int status, lua_KContext ctx) { + (void)ctx; + if (status != 0 && status != LUA_YIELD) { + if (unwrap(L)) return 2; + else return lua_error(L); + } else return lua_gettop(L); +} + +#if LUA_VERSION_NUM == 502 +static int protected_cont(lua_State *L) { + int ctx = 0; + int status = lua_getctx(L, &ctx); + return protected_finish(L, status, ctx); +} +#else +#define protected_cont protected_finish +#endif + +static int protected_(lua_State *L) { + int status; + lua_pushvalue(L, lua_upvalueindex(2)); + lua_insert(L, 1); + status = lua_pcallk(L, lua_gettop(L) - 1, LUA_MULTRET, 0, 0, protected_cont); + return protected_finish(L, status, 0); +} + +static int global_protect(lua_State *L) { + lua_settop(L, 1); + lua_pushvalue(L, lua_upvalueindex(1)); + lua_insert(L, 1); + lua_pushcclosure(L, protected_, 2); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Init module +\*-------------------------------------------------------------------------*/ +int except_open(lua_State *L) { + lua_newtable(L); /* metatable for wrapped exceptions */ + lua_pushboolean(L, 0); + lua_setfield(L, -2, "__metatable"); + luaL_setfuncs(L, func, 1); + return 0; +} diff --git a/src/3rd party/lua-extensions/luasocket/except.h b/src/3rd party/lua-extensions/luasocket/except.h new file mode 100644 index 000000000..71c31fd4d --- /dev/null +++ b/src/3rd party/lua-extensions/luasocket/except.h @@ -0,0 +1,46 @@ +#ifndef EXCEPT_H +#define EXCEPT_H +/*=========================================================================*\ +* Exception control +* LuaSocket toolkit (but completely independent from other modules) +* +* This provides support for simple exceptions in Lua. During the +* development of the HTTP/FTP/SMTP support, it became aparent that +* error checking was taking a substantial amount of the coding. These +* function greatly simplify the task of checking errors. +* +* The main idea is that functions should return nil as their first return +* values when they find an error, and return an error message (or value) +* following nil. In case of success, as long as the first value is not nil, +* the other values don't matter. +* +* The idea is to nest function calls with the "try" function. This function +* checks the first value, and, if it's falsy, wraps the second value in a +* table with metatable and calls "error" on it. Otherwise, it returns all +* values it received. Basically, it works like the Lua "assert" function, +* but it creates errors targeted specifically at "protect". +* +* The "newtry" function is a factory for "try" functions that call a +* finalizer in protected mode before calling "error". +* +* The "protect" function returns a new function that behaves exactly like +* the function it receives, but the new function catches exceptions thrown +* by "try" functions and returns nil followed by the error message instead. +* +* With these three functions, it's easy to write functions that throw +* exceptions on error, but that don't interrupt the user script. +\*=========================================================================*/ + +#include "luasocket.h" + +#ifndef _WIN32 +#pragma GCC visibility push(hidden) +#endif + +int except_open(lua_State *L); + +#ifndef _WIN32 +#pragma GCC visibility pop +#endif + +#endif diff --git a/src/3rd party/lua-extensions/luasocket/inet.c b/src/3rd party/lua-extensions/luasocket/inet.c new file mode 100644 index 000000000..afef5f45b --- /dev/null +++ b/src/3rd party/lua-extensions/luasocket/inet.c @@ -0,0 +1,537 @@ +/*=========================================================================*\ +* Internet domain functions +* LuaSocket toolkit +\*=========================================================================*/ +#include "luasocket.h" +#include "inet.h" + +#include +#include +#include + +/*=========================================================================*\ +* Internal function prototypes. +\*=========================================================================*/ +static int inet_global_toip(lua_State *L); +static int inet_global_getaddrinfo(lua_State *L); +static int inet_global_tohostname(lua_State *L); +static int inet_global_getnameinfo(lua_State *L); +static void inet_pushresolved(lua_State *L, struct hostent *hp); +static int inet_global_gethostname(lua_State *L); + +/* DNS functions */ +static luaL_Reg func[] = { + { "toip", inet_global_toip}, + { "getaddrinfo", inet_global_getaddrinfo}, + { "tohostname", inet_global_tohostname}, + { "getnameinfo", inet_global_getnameinfo}, + { "gethostname", inet_global_gethostname}, + { NULL, NULL} +}; + +/*-------------------------------------------------------------------------*\ +* Initializes module +\*-------------------------------------------------------------------------*/ +int inet_open(lua_State *L) +{ + lua_pushstring(L, "dns"); + lua_newtable(L); + luaL_setfuncs(L, func, 0); + lua_settable(L, -3); + return 0; +} + +/*=========================================================================*\ +* Global Lua functions +\*=========================================================================*/ +/*-------------------------------------------------------------------------*\ +* Returns all information provided by the resolver given a host name +* or ip address +\*-------------------------------------------------------------------------*/ +static int inet_gethost(const char *address, struct hostent **hp) { + struct in_addr addr; + if (inet_aton(address, &addr)) + return socket_gethostbyaddr((char *) &addr, sizeof(addr), hp); + else + return socket_gethostbyname(address, hp); +} + +/*-------------------------------------------------------------------------*\ +* Returns all information provided by the resolver given a host name +* or ip address +\*-------------------------------------------------------------------------*/ +static int inet_global_tohostname(lua_State *L) { + const char *address = luaL_checkstring(L, 1); + struct hostent *hp = NULL; + int err = inet_gethost(address, &hp); + if (err != IO_DONE) { + lua_pushnil(L); + lua_pushstring(L, socket_hoststrerror(err)); + return 2; + } + lua_pushstring(L, hp->h_name); + inet_pushresolved(L, hp); + return 2; +} + +static int inet_global_getnameinfo(lua_State *L) { + char hbuf[NI_MAXHOST]; + char sbuf[NI_MAXSERV]; + int i, ret; + struct addrinfo hints; + struct addrinfo *resolved, *iter; + const char *host = luaL_optstring(L, 1, NULL); + const char *serv = luaL_optstring(L, 2, NULL); + + if (!(host || serv)) + luaL_error(L, "host and serv cannot be both nil"); + + memset(&hints, 0, sizeof(hints)); + hints.ai_socktype = SOCK_STREAM; + hints.ai_family = AF_UNSPEC; + + ret = getaddrinfo(host, serv, &hints, &resolved); + if (ret != 0) { + lua_pushnil(L); + lua_pushstring(L, socket_gaistrerror(ret)); + return 2; + } + + lua_newtable(L); + for (i = 1, iter = resolved; iter; i++, iter = iter->ai_next) { + getnameinfo(iter->ai_addr, (socklen_t) iter->ai_addrlen, + hbuf, host? (socklen_t) sizeof(hbuf): 0, + sbuf, serv? (socklen_t) sizeof(sbuf): 0, 0); + if (host) { + lua_pushnumber(L, i); + lua_pushstring(L, hbuf); + lua_settable(L, -3); + } + } + freeaddrinfo(resolved); + + if (serv) { + lua_pushstring(L, sbuf); + return 2; + } else { + return 1; + } +} + +/*-------------------------------------------------------------------------*\ +* Returns all information provided by the resolver given a host name +* or ip address +\*-------------------------------------------------------------------------*/ +static int inet_global_toip(lua_State *L) +{ + const char *address = luaL_checkstring(L, 1); + struct hostent *hp = NULL; + int err = inet_gethost(address, &hp); + if (err != IO_DONE) { + lua_pushnil(L); + lua_pushstring(L, socket_hoststrerror(err)); + return 2; + } + lua_pushstring(L, inet_ntoa(*((struct in_addr *) hp->h_addr))); + inet_pushresolved(L, hp); + return 2; +} + +int inet_optfamily(lua_State* L, int narg, const char* def) +{ + static const char* optname[] = { "unspec", "inet", "inet6", NULL }; + static int optvalue[] = { AF_UNSPEC, AF_INET, AF_INET6, 0 }; + + return optvalue[luaL_checkoption(L, narg, def, optname)]; +} + +int inet_optsocktype(lua_State* L, int narg, const char* def) +{ + static const char* optname[] = { "stream", "dgram", NULL }; + static int optvalue[] = { SOCK_STREAM, SOCK_DGRAM, 0 }; + + return optvalue[luaL_checkoption(L, narg, def, optname)]; +} + +static int inet_global_getaddrinfo(lua_State *L) +{ + const char *hostname = luaL_checkstring(L, 1); + struct addrinfo *iterator = NULL, *resolved = NULL; + struct addrinfo hints; + int i = 1, ret = 0; + memset(&hints, 0, sizeof(hints)); + hints.ai_socktype = SOCK_STREAM; + hints.ai_family = AF_UNSPEC; + ret = getaddrinfo(hostname, NULL, &hints, &resolved); + if (ret != 0) { + lua_pushnil(L); + lua_pushstring(L, socket_gaistrerror(ret)); + return 2; + } + lua_newtable(L); + for (iterator = resolved; iterator; iterator = iterator->ai_next) { + char hbuf[NI_MAXHOST]; + ret = getnameinfo(iterator->ai_addr, (socklen_t) iterator->ai_addrlen, + hbuf, (socklen_t) sizeof(hbuf), NULL, 0, NI_NUMERICHOST); + if (ret){ + freeaddrinfo(resolved); + lua_pushnil(L); + lua_pushstring(L, socket_gaistrerror(ret)); + return 2; + } + lua_pushnumber(L, i); + lua_newtable(L); + switch (iterator->ai_family) { + case AF_INET: + lua_pushliteral(L, "family"); + lua_pushliteral(L, "inet"); + lua_settable(L, -3); + break; + case AF_INET6: + lua_pushliteral(L, "family"); + lua_pushliteral(L, "inet6"); + lua_settable(L, -3); + break; + case AF_UNSPEC: + lua_pushliteral(L, "family"); + lua_pushliteral(L, "unspec"); + lua_settable(L, -3); + break; + default: + lua_pushliteral(L, "family"); + lua_pushliteral(L, "unknown"); + lua_settable(L, -3); + break; + } + lua_pushliteral(L, "addr"); + lua_pushstring(L, hbuf); + lua_settable(L, -3); + lua_settable(L, -3); + i++; + } + freeaddrinfo(resolved); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Gets the host name +\*-------------------------------------------------------------------------*/ +static int inet_global_gethostname(lua_State *L) +{ + char name[257]; + name[256] = '\0'; + if (gethostname(name, 256) < 0) { + lua_pushnil(L); + lua_pushstring(L, socket_strerror(errno)); + return 2; + } else { + lua_pushstring(L, name); + return 1; + } +} + +/*=========================================================================*\ +* Lua methods +\*=========================================================================*/ +/*-------------------------------------------------------------------------*\ +* Retrieves socket peer name +\*-------------------------------------------------------------------------*/ +int inet_meth_getpeername(lua_State *L, p_socket ps, int family) +{ + int err; + struct sockaddr_storage peer; + socklen_t peer_len = sizeof(peer); + char name[INET6_ADDRSTRLEN]; + char port[6]; /* 65535 = 5 bytes + 0 to terminate it */ + if (getpeername(*ps, (SA *) &peer, &peer_len) < 0) { + lua_pushnil(L); + lua_pushstring(L, socket_strerror(errno)); + return 2; + } + err = getnameinfo((struct sockaddr *) &peer, peer_len, + name, INET6_ADDRSTRLEN, + port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV); + if (err) { + lua_pushnil(L); + lua_pushstring(L, LUA_GAI_STRERROR(err)); + return 2; + } + lua_pushstring(L, name); + lua_pushinteger(L, (int) strtol(port, (char **) NULL, 10)); + switch (family) { + case AF_INET: lua_pushliteral(L, "inet"); break; + case AF_INET6: lua_pushliteral(L, "inet6"); break; + case AF_UNSPEC: lua_pushliteral(L, "unspec"); break; + default: lua_pushliteral(L, "unknown"); break; + } + return 3; +} + +/*-------------------------------------------------------------------------*\ +* Retrieves socket local name +\*-------------------------------------------------------------------------*/ +int inet_meth_getsockname(lua_State *L, p_socket ps, int family) +{ + int err; + struct sockaddr_storage peer; + socklen_t peer_len = sizeof(peer); + char name[INET6_ADDRSTRLEN]; + char port[6]; /* 65535 = 5 bytes + 0 to terminate it */ + if (getsockname(*ps, (SA *) &peer, &peer_len) < 0) { + lua_pushnil(L); + lua_pushstring(L, socket_strerror(errno)); + return 2; + } + err=getnameinfo((struct sockaddr *)&peer, peer_len, + name, INET6_ADDRSTRLEN, port, 6, NI_NUMERICHOST | NI_NUMERICSERV); + if (err) { + lua_pushnil(L); + lua_pushstring(L, LUA_GAI_STRERROR(err)); + return 2; + } + lua_pushstring(L, name); + lua_pushinteger(L, (int) strtol(port, (char **) NULL, 10)); + switch (family) { + case AF_INET: lua_pushliteral(L, "inet"); break; + case AF_INET6: lua_pushliteral(L, "inet6"); break; + case AF_UNSPEC: lua_pushliteral(L, "unspec"); break; + default: lua_pushliteral(L, "unknown"); break; + } + return 3; +} + +/*=========================================================================*\ +* Internal functions +\*=========================================================================*/ +/*-------------------------------------------------------------------------*\ +* Passes all resolver information to Lua as a table +\*-------------------------------------------------------------------------*/ +static void inet_pushresolved(lua_State *L, struct hostent *hp) +{ + char **alias; + struct in_addr **addr; + int i, resolved; + lua_newtable(L); resolved = lua_gettop(L); + lua_pushstring(L, "name"); + lua_pushstring(L, hp->h_name); + lua_settable(L, resolved); + lua_pushstring(L, "ip"); + lua_pushstring(L, "alias"); + i = 1; + alias = hp->h_aliases; + lua_newtable(L); + if (alias) { + while (*alias) { + lua_pushnumber(L, i); + lua_pushstring(L, *alias); + lua_settable(L, -3); + i++; alias++; + } + } + lua_settable(L, resolved); + i = 1; + lua_newtable(L); + addr = (struct in_addr **) hp->h_addr_list; + if (addr) { + while (*addr) { + lua_pushnumber(L, i); + lua_pushstring(L, inet_ntoa(**addr)); + lua_settable(L, -3); + i++; addr++; + } + } + lua_settable(L, resolved); +} + +/*-------------------------------------------------------------------------*\ +* Tries to create a new inet socket +\*-------------------------------------------------------------------------*/ +const char *inet_trycreate(p_socket ps, int family, int type, int protocol) { + const char *err = socket_strerror(socket_create(ps, family, type, protocol)); + if (err == NULL && family == AF_INET6) { + int yes = 1; + setsockopt(*ps, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&yes, sizeof(yes)); + } + return err; +} + +/*-------------------------------------------------------------------------*\ +* "Disconnects" a DGRAM socket +\*-------------------------------------------------------------------------*/ +const char *inet_trydisconnect(p_socket ps, int family, p_timeout tm) +{ + switch (family) { + case AF_INET: { + struct sockaddr_in sin; + memset((char *) &sin, 0, sizeof(sin)); + sin.sin_family = AF_UNSPEC; + sin.sin_addr.s_addr = INADDR_ANY; + return socket_strerror(socket_connect(ps, (SA *) &sin, + sizeof(sin), tm)); + } + case AF_INET6: { + struct sockaddr_in6 sin6; + struct in6_addr addrany = IN6ADDR_ANY_INIT; + memset((char *) &sin6, 0, sizeof(sin6)); + sin6.sin6_family = AF_UNSPEC; + sin6.sin6_addr = addrany; + return socket_strerror(socket_connect(ps, (SA *) &sin6, + sizeof(sin6), tm)); + } + } + return NULL; +} + +/*-------------------------------------------------------------------------*\ +* Tries to connect to remote address (address, port) +\*-------------------------------------------------------------------------*/ +const char *inet_tryconnect(p_socket ps, int *family, const char *address, + const char *serv, p_timeout tm, struct addrinfo *connecthints) +{ + struct addrinfo *iterator = NULL, *resolved = NULL; + const char *err = NULL; + int current_family = *family; + /* try resolving */ + err = socket_gaistrerror(getaddrinfo(address, serv, + connecthints, &resolved)); + if (err != NULL) { + if (resolved) freeaddrinfo(resolved); + return err; + } + for (iterator = resolved; iterator; iterator = iterator->ai_next) { + timeout_markstart(tm); + /* create new socket if necessary. if there was no + * bind, we need to create one for every new family + * that shows up while iterating. if there was a + * bind, all families will be the same and we will + * not enter this branch. */ + if (current_family != iterator->ai_family || *ps == SOCKET_INVALID) { + socket_destroy(ps); + err = inet_trycreate(ps, iterator->ai_family, + iterator->ai_socktype, iterator->ai_protocol); + if (err) continue; + current_family = iterator->ai_family; + /* set non-blocking before connect */ + socket_setnonblocking(ps); + } + /* try connecting to remote address */ + err = socket_strerror(socket_connect(ps, (SA *) iterator->ai_addr, + (socklen_t) iterator->ai_addrlen, tm)); + /* if success or timeout is zero, break out of loop */ + if (err == NULL || timeout_iszero(tm)) { + *family = current_family; + break; + } + } + freeaddrinfo(resolved); + /* here, if err is set, we failed */ + return err; +} + +/*-------------------------------------------------------------------------*\ +* Tries to accept a socket +\*-------------------------------------------------------------------------*/ +const char *inet_tryaccept(p_socket server, int family, p_socket client, + p_timeout tm) { + socklen_t len; + t_sockaddr_storage addr; + switch (family) { + case AF_INET6: len = sizeof(struct sockaddr_in6); break; + case AF_INET: len = sizeof(struct sockaddr_in); break; + default: len = sizeof(addr); break; + } + return socket_strerror(socket_accept(server, client, (SA *) &addr, + &len, tm)); +} + +/*-------------------------------------------------------------------------*\ +* Tries to bind socket to (address, port) +\*-------------------------------------------------------------------------*/ +const char *inet_trybind(p_socket ps, int *family, const char *address, + const char *serv, struct addrinfo *bindhints) { + struct addrinfo *iterator = NULL, *resolved = NULL; + const char *err = NULL; + int current_family = *family; + /* translate luasocket special values to C */ + if (strcmp(address, "*") == 0) address = NULL; + if (!serv) serv = "0"; + /* try resolving */ + err = socket_gaistrerror(getaddrinfo(address, serv, bindhints, &resolved)); + if (err) { + if (resolved) freeaddrinfo(resolved); + return err; + } + /* iterate over resolved addresses until one is good */ + for (iterator = resolved; iterator; iterator = iterator->ai_next) { + if (current_family != iterator->ai_family || *ps == SOCKET_INVALID) { + socket_destroy(ps); + err = inet_trycreate(ps, iterator->ai_family, + iterator->ai_socktype, iterator->ai_protocol); + if (err) continue; + current_family = iterator->ai_family; + } + /* try binding to local address */ + err = socket_strerror(socket_bind(ps, (SA *) iterator->ai_addr, + (socklen_t) iterator->ai_addrlen)); + /* keep trying unless bind succeeded */ + if (err == NULL) { + *family = current_family; + /* set to non-blocking after bind */ + socket_setnonblocking(ps); + break; + } + } + /* cleanup and return error */ + freeaddrinfo(resolved); + /* here, if err is set, we failed */ + return err; +} + +/*-------------------------------------------------------------------------*\ +* Some systems do not provide these so that we provide our own. +\*-------------------------------------------------------------------------*/ +#ifdef LUASOCKET_INET_ATON +int inet_aton(const char *cp, struct in_addr *inp) +{ + unsigned int a = 0, b = 0, c = 0, d = 0; + int n = 0, r; + unsigned long int addr = 0; + r = sscanf(cp, "%u.%u.%u.%u%n", &a, &b, &c, &d, &n); + if (r == 0 || n == 0) return 0; + cp += n; + if (*cp) return 0; + if (a > 255 || b > 255 || c > 255 || d > 255) return 0; + if (inp) { + addr += a; addr <<= 8; + addr += b; addr <<= 8; + addr += c; addr <<= 8; + addr += d; + inp->s_addr = htonl(addr); + } + return 1; +} +#endif + +#ifdef LUASOCKET_INET_PTON +int inet_pton(int af, const char *src, void *dst) +{ + struct addrinfo hints, *res; + int ret = 1; + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = af; + hints.ai_flags = AI_NUMERICHOST; + if (getaddrinfo(src, NULL, &hints, &res) != 0) return -1; + if (af == AF_INET) { + struct sockaddr_in *in = (struct sockaddr_in *) res->ai_addr; + memcpy(dst, &in->sin_addr, sizeof(in->sin_addr)); + } else if (af == AF_INET6) { + struct sockaddr_in6 *in = (struct sockaddr_in6 *) res->ai_addr; + memcpy(dst, &in->sin6_addr, sizeof(in->sin6_addr)); + } else { + ret = -1; + } + freeaddrinfo(res); + return ret; +} + +#endif diff --git a/src/3rd party/lua-extensions/luasocket/inet.h b/src/3rd party/lua-extensions/luasocket/inet.h new file mode 100644 index 000000000..5618b61b3 --- /dev/null +++ b/src/3rd party/lua-extensions/luasocket/inet.h @@ -0,0 +1,56 @@ +#ifndef INET_H +#define INET_H +/*=========================================================================*\ +* Internet domain functions +* LuaSocket toolkit +* +* This module implements the creation and connection of internet domain +* sockets, on top of the socket.h interface, and the interface of with the +* resolver. +* +* The function inet_aton is provided for the platforms where it is not +* available. The module also implements the interface of the internet +* getpeername and getsockname functions as seen by Lua programs. +* +* The Lua functions toip and tohostname are also implemented here. +\*=========================================================================*/ +#include "luasocket.h" +#include "socket.h" +#include "timeout.h" + +#ifdef _WIN32 +#define LUASOCKET_INET_ATON +#endif + +#ifndef _WIN32 +#pragma GCC visibility push(hidden) +#endif + +int inet_open(lua_State *L); + +int inet_optfamily(lua_State* L, int narg, const char* def); +int inet_optsocktype(lua_State* L, int narg, const char* def); + +int inet_meth_getpeername(lua_State *L, p_socket ps, int family); +int inet_meth_getsockname(lua_State *L, p_socket ps, int family); + +const char *inet_trycreate(p_socket ps, int family, int type, int protocol); +const char *inet_trydisconnect(p_socket ps, int family, p_timeout tm); +const char *inet_tryconnect(p_socket ps, int *family, const char *address, const char *serv, p_timeout tm, struct addrinfo *connecthints); +const char *inet_tryaccept(p_socket server, int family, p_socket client, p_timeout tm); +const char *inet_trybind(p_socket ps, int *family, const char *address, const char *serv, struct addrinfo *bindhints); + +#ifdef LUASOCKET_INET_ATON +int inet_aton(const char *cp, struct in_addr *inp); +#endif + +#ifdef LUASOCKET_INET_PTON +const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt); +int inet_pton(int af, const char *src, void *dst); +#endif + +#ifndef _WIN32 +#pragma GCC visibility pop +#endif + +#endif /* INET_H */ diff --git a/src/3rd party/lua-extensions/luasocket/io.c b/src/3rd party/lua-extensions/luasocket/io.c new file mode 100644 index 000000000..5ad4b3afc --- /dev/null +++ b/src/3rd party/lua-extensions/luasocket/io.c @@ -0,0 +1,28 @@ +/*=========================================================================*\ +* Input/Output abstraction +* LuaSocket toolkit +\*=========================================================================*/ +#include "luasocket.h" +#include "io.h" + +/*-------------------------------------------------------------------------*\ +* Initializes C structure +\*-------------------------------------------------------------------------*/ +void io_init(p_io io, p_send send, p_recv recv, p_error error, void *ctx) { + io->send = send; + io->recv = recv; + io->error = error; + io->ctx = ctx; +} + +/*-------------------------------------------------------------------------*\ +* I/O error strings +\*-------------------------------------------------------------------------*/ +const char *io_strerror(int err) { + switch (err) { + case IO_DONE: return NULL; + case IO_CLOSED: return "closed"; + case IO_TIMEOUT: return "timeout"; + default: return "unknown error"; + } +} diff --git a/src/3rd party/lua-extensions/luasocket/io.h b/src/3rd party/lua-extensions/luasocket/io.h new file mode 100644 index 000000000..b8a54df6e --- /dev/null +++ b/src/3rd party/lua-extensions/luasocket/io.h @@ -0,0 +1,70 @@ +#ifndef IO_H +#define IO_H +/*=========================================================================*\ +* Input/Output abstraction +* LuaSocket toolkit +* +* This module defines the interface that LuaSocket expects from the +* transport layer for streamed input/output. The idea is that if any +* transport implements this interface, then the buffer.c functions +* automatically work on it. +* +* The module socket.h implements this interface, and thus the module tcp.h +* is very simple. +\*=========================================================================*/ +#include "luasocket.h" +#include "timeout.h" + +/* IO error codes */ +enum { + IO_DONE = 0, /* operation completed successfully */ + IO_TIMEOUT = -1, /* operation timed out */ + IO_CLOSED = -2, /* the connection has been closed */ + IO_UNKNOWN = -3 +}; + +/* interface to error message function */ +typedef const char *(*p_error) ( + void *ctx, /* context needed by send */ + int err /* error code */ +); + +/* interface to send function */ +typedef int (*p_send) ( + void *ctx, /* context needed by send */ + const char *data, /* pointer to buffer with data to send */ + size_t count, /* number of bytes to send from buffer */ + size_t *sent, /* number of bytes sent uppon return */ + p_timeout tm /* timeout control */ +); + +/* interface to recv function */ +typedef int (*p_recv) ( + void *ctx, /* context needed by recv */ + char *data, /* pointer to buffer where data will be writen */ + size_t count, /* number of bytes to receive into buffer */ + size_t *got, /* number of bytes received uppon return */ + p_timeout tm /* timeout control */ +); + +/* IO driver definition */ +typedef struct t_io_ { + void *ctx; /* context needed by send/recv */ + p_send send; /* send function pointer */ + p_recv recv; /* receive function pointer */ + p_error error; /* strerror function */ +} t_io; +typedef t_io *p_io; + +#ifndef _WIN32 +#pragma GCC visibility push(hidden) +#endif + +void io_init(p_io io, p_send send, p_recv recv, p_error error, void *ctx); +const char *io_strerror(int err); + +#ifndef _WIN32 +#pragma GCC visibility pop +#endif + +#endif /* IO_H */ diff --git a/src/3rd party/lua-extensions/luasocket/luasocket.c b/src/3rd party/lua-extensions/luasocket/luasocket.c new file mode 100644 index 000000000..008fa7edf --- /dev/null +++ b/src/3rd party/lua-extensions/luasocket/luasocket.c @@ -0,0 +1,126 @@ +/*=========================================================================*\ +* LuaSocket toolkit +* Networking support for the Lua language +* Diego Nehab +* 26/11/1999 +* +* This library is part of an effort to progressively increase the network +* connectivity of the Lua language. The Lua interface to networking +* functions follows the Sockets API closely, trying to simplify all tasks +* involved in setting up both client and server connections. The provided +* IO routines, however, follow the Lua style, being very similar to the +* standard Lua read and write functions. +\*=========================================================================*/ + +#include "luasocket.h" +#include "auxiliar.h" +#include "except.h" +#include "timeout.h" +#include "buffer.h" +#include "inet.h" +#include "tcp.h" +#include "udp.h" +#include "select.h" + +/*-------------------------------------------------------------------------*\ +* Internal function prototypes +\*-------------------------------------------------------------------------*/ +static int global_skip(lua_State *L); +static int global_unload(lua_State *L); +static int base_open(lua_State *L); + +/*-------------------------------------------------------------------------*\ +* Modules and functions +\*-------------------------------------------------------------------------*/ +static const luaL_Reg mod[] = { + {"auxiliar", auxiliar_open}, + {"except", except_open}, + {"timeout", timeout_open}, + {"buffer", buffer_open}, + {"inet", inet_open}, + {"tcp", tcp_open}, + {"udp", udp_open}, + {"select", select_open}, + {NULL, NULL} +}; + +static luaL_Reg func[] = { + {"skip", global_skip}, + {"__unload", global_unload}, + {NULL, NULL} +}; + +/*-------------------------------------------------------------------------*\ +* Skip a few arguments +\*-------------------------------------------------------------------------*/ +static int global_skip(lua_State *L) { + int amount = (int) luaL_checkinteger(L, 1); + int ret = lua_gettop(L) - amount - 1; + return ret >= 0 ? ret : 0; +} + +/*-------------------------------------------------------------------------*\ +* Unloads the library +\*-------------------------------------------------------------------------*/ +static int global_unload(lua_State *L) { + (void) L; + socket_close(); + return 0; +} + +/*-------------------------------------------------------------------------*\ +* Setup basic stuff. +\*-------------------------------------------------------------------------*/ +static int base_open(lua_State *L) { + if (socket_open()) { + /* export functions (and leave namespace table on top of stack) */ + lua_newtable(L); + luaL_setfuncs(L, func, 0); +#ifdef LUASOCKET_DEBUG + lua_pushstring(L, "_DEBUG"); + lua_pushboolean(L, 1); + lua_rawset(L, -3); +#endif + /* make version string available to scripts */ + lua_pushstring(L, "_VERSION"); + lua_pushstring(L, LUASOCKET_VERSION); + lua_rawset(L, -3); + return 1; + } else { + lua_pushstring(L, "unable to initialize library"); + lua_error(L); + return 0; + } +} + +/*-------------------------------------------------------------------------*\ +* Initializes all library modules. +\*-------------------------------------------------------------------------*/ +void luaL_pushmodule(lua_State* L, const char* modname, int sizehint) +{ + luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 16); + lua_getfield(L, -1, modname); + if (!lua_istable(L, -1)) + { + lua_pop(L, 1); + luaL_findtable(L, LUA_GLOBALSINDEX, modname, sizehint); + lua_pushvalue(L, -1); + lua_setfield(L, -3, modname); + } + lua_remove(L, -2); +} + +LUASOCKET_API int luaopen_socket_core(lua_State* L) +{ + { + int i; + lua_newtable(L); + if (!base_open(L)) + return 0; + for (i = 0; mod[i].name; i++) mod[i].func(L); + lua_setfield(L, -2, "core"); + lua_setglobal(L, "socket"); + } + luaL_pushmodule(L, "socket.core", 0); + return 1; +} \ No newline at end of file diff --git a/src/3rd party/lua-extensions/luasocket/luasocket.h b/src/3rd party/lua-extensions/luasocket/luasocket.h new file mode 100644 index 000000000..1e3d3588c --- /dev/null +++ b/src/3rd party/lua-extensions/luasocket/luasocket.h @@ -0,0 +1,36 @@ +#ifndef LUASOCKET_H +#define LUASOCKET_H +/*=========================================================================*\ +* LuaSocket toolkit +* Networking support for the Lua language +* Diego Nehab +* 9/11/1999 +\*=========================================================================*/ + +/*-------------------------------------------------------------------------* \ +* Current socket library version +\*-------------------------------------------------------------------------*/ +#define LUASOCKET_VERSION "LuaSocket 3.1.0" +#define LUASOCKET_COPYRIGHT "Copyright (C) 1999-2013 Diego Nehab" + +/*-------------------------------------------------------------------------*\ +* This macro prefixes all exported API functions +\*-------------------------------------------------------------------------*/ +#ifndef LUASOCKET_API +#ifdef _WIN32 +#define LUASOCKET_API __declspec(dllexport) +#else +#define LUASOCKET_API __attribute__ ((visibility ("default"))) +#endif +#endif + +#include "lua.h" +#include "lauxlib.h" +#include "compat.h" + +/*-------------------------------------------------------------------------*\ +* Initializes the library. +\*-------------------------------------------------------------------------*/ +LUASOCKET_API int luaopen_socket_core(lua_State *L); + +#endif /* LUASOCKET_H */ diff --git a/src/3rd party/lua-extensions/luasocket/mime.c b/src/3rd party/lua-extensions/luasocket/mime.c new file mode 100644 index 000000000..05602f566 --- /dev/null +++ b/src/3rd party/lua-extensions/luasocket/mime.c @@ -0,0 +1,852 @@ +/*=========================================================================*\ +* MIME support functions +* LuaSocket toolkit +\*=========================================================================*/ +#include "luasocket.h" +#include "mime.h" +#include +#include + +/*=========================================================================*\ +* Don't want to trust escape character constants +\*=========================================================================*/ +typedef unsigned char UC; +static const char CRLF[] = "\r\n"; +static const char EQCRLF[] = "=\r\n"; + +/*=========================================================================*\ +* Internal function prototypes. +\*=========================================================================*/ +static int mime_global_wrp(lua_State *L); +static int mime_global_b64(lua_State *L); +static int mime_global_unb64(lua_State *L); +static int mime_global_qp(lua_State *L); +static int mime_global_unqp(lua_State *L); +static int mime_global_qpwrp(lua_State *L); +static int mime_global_eol(lua_State *L); +static int mime_global_dot(lua_State *L); + +static size_t dot(int c, size_t state, luaL_Buffer *buffer); +/*static void b64setup(UC *base);*/ +static size_t b64encode(UC c, UC *input, size_t size, luaL_Buffer *buffer); +static size_t b64pad(const UC *input, size_t size, luaL_Buffer *buffer); +static size_t b64decode(UC c, UC *input, size_t size, luaL_Buffer *buffer); + +/*static void qpsetup(UC *class, UC *unbase);*/ +static void qpquote(UC c, luaL_Buffer *buffer); +static size_t qpdecode(UC c, UC *input, size_t size, luaL_Buffer *buffer); +static size_t qpencode(UC c, UC *input, size_t size, + const char *marker, luaL_Buffer *buffer); +static size_t qppad(UC *input, size_t size, luaL_Buffer *buffer); + +/* code support functions */ +static luaL_Reg func[] = { + { "dot", mime_global_dot }, + { "b64", mime_global_b64 }, + { "eol", mime_global_eol }, + { "qp", mime_global_qp }, + { "qpwrp", mime_global_qpwrp }, + { "unb64", mime_global_unb64 }, + { "unqp", mime_global_unqp }, + { "wrp", mime_global_wrp }, + { NULL, NULL } +}; + +/*-------------------------------------------------------------------------*\ +* Quoted-printable globals +\*-------------------------------------------------------------------------*/ +enum {QP_PLAIN, QP_QUOTED, QP_CR, QP_IF_LAST}; + +static const UC qpclass[] = { + QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, + QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_IF_LAST, QP_QUOTED, QP_QUOTED, + QP_QUOTED, QP_CR, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, + QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, + QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, + QP_QUOTED, QP_QUOTED, QP_IF_LAST, QP_PLAIN, QP_PLAIN, QP_PLAIN, + QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, + QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, + QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, + QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, + QP_PLAIN, QP_QUOTED, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, + QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, + QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, + QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, + QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, + QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, + QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, + QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, + QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, + QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, + QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, QP_PLAIN, + QP_PLAIN, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, + QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, + QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, + QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, + QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, + QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, + QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, + QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, + QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, + QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, + QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, + QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, + QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, + QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, + QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, + QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, + QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, + QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, + QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, + QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, + QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED, + QP_QUOTED, QP_QUOTED, QP_QUOTED, QP_QUOTED +}; + +static const UC qpbase[] = "0123456789ABCDEF"; + +static const UC qpunbase[] = { + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255, + 255, 255, 255, 255, 255, 255, 10, 11, 12, 13, 14, 15, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 10, 11, 12, 13, 14, 15, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255 +}; + +/*-------------------------------------------------------------------------*\ +* Base64 globals +\*-------------------------------------------------------------------------*/ +static const UC b64base[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +static const UC b64unbase[] = { + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255, 0, + 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 255, 255, + 255, 255, 255, 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, + 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255 +}; + +/*=========================================================================*\ +* Exported functions +\*=========================================================================*/ +/*-------------------------------------------------------------------------*\ +* Initializes module +\*-------------------------------------------------------------------------*/ +LUASOCKET_API int luaopen_mime_core(lua_State *L) +{ + lua_newtable(L); + luaL_setfuncs(L, func, 0); + /* make version string available to scripts */ + lua_pushstring(L, "_VERSION"); + lua_pushstring(L, MIME_VERSION); + lua_rawset(L, -3); + /* initialize lookup tables */ + /*qpsetup(qpclass, qpunbase);*/ + /*b64setup(b64unbase);*/ + return 1; +} + +/*=========================================================================*\ +* Global Lua functions +\*=========================================================================*/ +/*-------------------------------------------------------------------------*\ +* Incrementaly breaks a string into lines. The string can have CRLF breaks. +* A, n = wrp(l, B, length) +* A is a copy of B, broken into lines of at most 'length' bytes. +* 'l' is how many bytes are left for the first line of B. +* 'n' is the number of bytes left in the last line of A. +\*-------------------------------------------------------------------------*/ +static int mime_global_wrp(lua_State *L) +{ + size_t size = 0; + int left = (int) luaL_checknumber(L, 1); + const UC *input = (const UC *) luaL_optlstring(L, 2, NULL, &size); + const UC *last = input + size; + int length = (int) luaL_optnumber(L, 3, 76); + luaL_Buffer buffer; + /* end of input black-hole */ + if (!input) { + /* if last line has not been terminated, add a line break */ + if (left < length) lua_pushstring(L, CRLF); + /* otherwise, we are done */ + else lua_pushnil(L); + lua_pushnumber(L, length); + return 2; + } + luaL_buffinit(L, &buffer); + while (input < last) { + switch (*input) { + case '\r': + break; + case '\n': + luaL_addstring(&buffer, CRLF); + left = length; + break; + default: + if (left <= 0) { + left = length; + luaL_addstring(&buffer, CRLF); + } + luaL_addchar(&buffer, *input); + left--; + break; + } + input++; + } + luaL_pushresult(&buffer); + lua_pushnumber(L, left); + return 2; +} + +#if 0 +/*-------------------------------------------------------------------------*\ +* Fill base64 decode map. +\*-------------------------------------------------------------------------*/ +static void b64setup(UC *unbase) +{ + int i; + for (i = 0; i <= 255; i++) unbase[i] = (UC) 255; + for (i = 0; i < 64; i++) unbase[b64base[i]] = (UC) i; + unbase['='] = 0; + + printf("static const UC b64unbase[] = {\n"); + for (int i = 0; i < 256; i++) { + printf("%d, ", unbase[i]); + } + printf("\n}\n;"); +} +#endif + +/*-------------------------------------------------------------------------*\ +* Acumulates bytes in input buffer until 3 bytes are available. +* Translate the 3 bytes into Base64 form and append to buffer. +* Returns new number of bytes in buffer. +\*-------------------------------------------------------------------------*/ +static size_t b64encode(UC c, UC *input, size_t size, + luaL_Buffer *buffer) +{ + input[size++] = c; + if (size == 3) { + UC code[4]; + unsigned long value = 0; + value += input[0]; value <<= 8; + value += input[1]; value <<= 8; + value += input[2]; + code[3] = b64base[value & 0x3f]; value >>= 6; + code[2] = b64base[value & 0x3f]; value >>= 6; + code[1] = b64base[value & 0x3f]; value >>= 6; + code[0] = b64base[value]; + luaL_addlstring(buffer, (char *) code, 4); + size = 0; + } + return size; +} + +/*-------------------------------------------------------------------------*\ +* Encodes the Base64 last 1 or 2 bytes and adds padding '=' +* Result, if any, is appended to buffer. +* Returns 0. +\*-------------------------------------------------------------------------*/ +static size_t b64pad(const UC *input, size_t size, + luaL_Buffer *buffer) +{ + unsigned long value = 0; + UC code[4] = {'=', '=', '=', '='}; + switch (size) { + case 1: + value = input[0] << 4; + code[1] = b64base[value & 0x3f]; value >>= 6; + code[0] = b64base[value]; + luaL_addlstring(buffer, (char *) code, 4); + break; + case 2: + value = input[0]; value <<= 8; + value |= input[1]; value <<= 2; + code[2] = b64base[value & 0x3f]; value >>= 6; + code[1] = b64base[value & 0x3f]; value >>= 6; + code[0] = b64base[value]; + luaL_addlstring(buffer, (char *) code, 4); + break; + default: + break; + } + return 0; +} + +/*-------------------------------------------------------------------------*\ +* Acumulates bytes in input buffer until 4 bytes are available. +* Translate the 4 bytes from Base64 form and append to buffer. +* Returns new number of bytes in buffer. +\*-------------------------------------------------------------------------*/ +static size_t b64decode(UC c, UC *input, size_t size, + luaL_Buffer *buffer) +{ + /* ignore invalid characters */ + if (b64unbase[c] > 64) return size; + input[size++] = c; + /* decode atom */ + if (size == 4) { + UC decoded[3]; + int valid, value = 0; + value = b64unbase[input[0]]; value <<= 6; + value |= b64unbase[input[1]]; value <<= 6; + value |= b64unbase[input[2]]; value <<= 6; + value |= b64unbase[input[3]]; + decoded[2] = (UC) (value & 0xff); value >>= 8; + decoded[1] = (UC) (value & 0xff); value >>= 8; + decoded[0] = (UC) value; + /* take care of paddding */ + valid = (input[2] == '=') ? 1 : (input[3] == '=') ? 2 : 3; + luaL_addlstring(buffer, (char *) decoded, valid); + return 0; + /* need more data */ + } else return size; +} + +/*-------------------------------------------------------------------------*\ +* Incrementally applies the Base64 transfer content encoding to a string +* A, B = b64(C, D) +* A is the encoded version of the largest prefix of C .. D that is +* divisible by 3. B has the remaining bytes of C .. D, *without* encoding. +* The easiest thing would be to concatenate the two strings and +* encode the result, but we can't afford that or Lua would dupplicate +* every chunk we received. +\*-------------------------------------------------------------------------*/ +static int mime_global_b64(lua_State *L) +{ + UC atom[3]; + size_t isize = 0, asize = 0; + const UC *input = (const UC *) luaL_optlstring(L, 1, NULL, &isize); + const UC *last = input + isize; + luaL_Buffer buffer; + /* end-of-input blackhole */ + if (!input) { + lua_pushnil(L); + lua_pushnil(L); + return 2; + } + /* make sure we don't confuse buffer stuff with arguments */ + lua_settop(L, 2); + /* process first part of the input */ + luaL_buffinit(L, &buffer); + while (input < last) + asize = b64encode(*input++, atom, asize, &buffer); + input = (const UC *) luaL_optlstring(L, 2, NULL, &isize); + /* if second part is nil, we are done */ + if (!input) { + size_t osize = 0; + asize = b64pad(atom, asize, &buffer); + luaL_pushresult(&buffer); + /* if the output is empty and the input is nil, return nil */ + lua_tolstring(L, -1, &osize); + if (osize == 0) lua_pushnil(L); + lua_pushnil(L); + return 2; + } + /* otherwise process the second part */ + last = input + isize; + while (input < last) + asize = b64encode(*input++, atom, asize, &buffer); + luaL_pushresult(&buffer); + lua_pushlstring(L, (char *) atom, asize); + return 2; +} + +/*-------------------------------------------------------------------------*\ +* Incrementally removes the Base64 transfer content encoding from a string +* A, B = b64(C, D) +* A is the encoded version of the largest prefix of C .. D that is +* divisible by 4. B has the remaining bytes of C .. D, *without* encoding. +\*-------------------------------------------------------------------------*/ +static int mime_global_unb64(lua_State *L) +{ + UC atom[4]; + size_t isize = 0, asize = 0; + const UC *input = (const UC *) luaL_optlstring(L, 1, NULL, &isize); + const UC *last = input + isize; + luaL_Buffer buffer; + /* end-of-input blackhole */ + if (!input) { + lua_pushnil(L); + lua_pushnil(L); + return 2; + } + /* make sure we don't confuse buffer stuff with arguments */ + lua_settop(L, 2); + /* process first part of the input */ + luaL_buffinit(L, &buffer); + while (input < last) + asize = b64decode(*input++, atom, asize, &buffer); + input = (const UC *) luaL_optlstring(L, 2, NULL, &isize); + /* if second is nil, we are done */ + if (!input) { + size_t osize = 0; + luaL_pushresult(&buffer); + /* if the output is empty and the input is nil, return nil */ + lua_tolstring(L, -1, &osize); + if (osize == 0) lua_pushnil(L); + lua_pushnil(L); + return 2; + } + /* otherwise, process the rest of the input */ + last = input + isize; + while (input < last) + asize = b64decode(*input++, atom, asize, &buffer); + luaL_pushresult(&buffer); + lua_pushlstring(L, (char *) atom, asize); + return 2; +} + +/*-------------------------------------------------------------------------*\ +* Quoted-printable encoding scheme +* all (except CRLF in text) can be =XX +* CLRL in not text must be =XX=XX +* 33 through 60 inclusive can be plain +* 62 through 126 inclusive can be plain +* 9 and 32 can be plain, unless in the end of a line, where must be =XX +* encoded lines must be no longer than 76 not counting CRLF +* soft line-break are =CRLF +* To encode one byte, we need to see the next two. +* Worst case is when we see a space, and wonder if a CRLF is comming +\*-------------------------------------------------------------------------*/ +#if 0 +/*-------------------------------------------------------------------------*\ +* Split quoted-printable characters into classes +* Precompute reverse map for encoding +\*-------------------------------------------------------------------------*/ +static void qpsetup(UC *cl, UC *unbase) +{ + + int i; + for (i = 0; i < 256; i++) cl[i] = QP_QUOTED; + for (i = 33; i <= 60; i++) cl[i] = QP_PLAIN; + for (i = 62; i <= 126; i++) cl[i] = QP_PLAIN; + cl['\t'] = QP_IF_LAST; + cl[' '] = QP_IF_LAST; + cl['\r'] = QP_CR; + for (i = 0; i < 256; i++) unbase[i] = 255; + unbase['0'] = 0; unbase['1'] = 1; unbase['2'] = 2; + unbase['3'] = 3; unbase['4'] = 4; unbase['5'] = 5; + unbase['6'] = 6; unbase['7'] = 7; unbase['8'] = 8; + unbase['9'] = 9; unbase['A'] = 10; unbase['a'] = 10; + unbase['B'] = 11; unbase['b'] = 11; unbase['C'] = 12; + unbase['c'] = 12; unbase['D'] = 13; unbase['d'] = 13; + unbase['E'] = 14; unbase['e'] = 14; unbase['F'] = 15; + unbase['f'] = 15; + +printf("static UC qpclass[] = {"); + for (int i = 0; i < 256; i++) { + if (i % 6 == 0) { + printf("\n "); + } + switch(cl[i]) { + case QP_QUOTED: + printf("QP_QUOTED, "); + break; + case QP_PLAIN: + printf("QP_PLAIN, "); + break; + case QP_CR: + printf("QP_CR, "); + break; + case QP_IF_LAST: + printf("QP_IF_LAST, "); + break; + } + } +printf("\n};\n"); + +printf("static const UC qpunbase[] = {"); + for (int i = 0; i < 256; i++) { + int c = qpunbase[i]; + printf("%d, ", c); + } +printf("\";\n"); +} +#endif + +/*-------------------------------------------------------------------------*\ +* Output one character in form =XX +\*-------------------------------------------------------------------------*/ +static void qpquote(UC c, luaL_Buffer *buffer) +{ + luaL_addchar(buffer, '='); + luaL_addchar(buffer, qpbase[c >> 4]); + luaL_addchar(buffer, qpbase[c & 0x0F]); +} + +/*-------------------------------------------------------------------------*\ +* Accumulate characters until we are sure about how to deal with them. +* Once we are sure, output to the buffer, in the correct form. +\*-------------------------------------------------------------------------*/ +static size_t qpencode(UC c, UC *input, size_t size, + const char *marker, luaL_Buffer *buffer) +{ + input[size++] = c; + /* deal with all characters we can have */ + while (size > 0) { + switch (qpclass[input[0]]) { + /* might be the CR of a CRLF sequence */ + case QP_CR: + if (size < 2) return size; + if (input[1] == '\n') { + luaL_addstring(buffer, marker); + return 0; + } else qpquote(input[0], buffer); + break; + /* might be a space and that has to be quoted if last in line */ + case QP_IF_LAST: + if (size < 3) return size; + /* if it is the last, quote it and we are done */ + if (input[1] == '\r' && input[2] == '\n') { + qpquote(input[0], buffer); + luaL_addstring(buffer, marker); + return 0; + } else luaL_addchar(buffer, input[0]); + break; + /* might have to be quoted always */ + case QP_QUOTED: + qpquote(input[0], buffer); + break; + /* might never have to be quoted */ + default: + luaL_addchar(buffer, input[0]); + break; + } + input[0] = input[1]; input[1] = input[2]; + size--; + } + return 0; +} + +/*-------------------------------------------------------------------------*\ +* Deal with the final characters +\*-------------------------------------------------------------------------*/ +static size_t qppad(UC *input, size_t size, luaL_Buffer *buffer) +{ + size_t i; + for (i = 0; i < size; i++) { + if (qpclass[input[i]] == QP_PLAIN) luaL_addchar(buffer, input[i]); + else qpquote(input[i], buffer); + } + if (size > 0) luaL_addstring(buffer, EQCRLF); + return 0; +} + +/*-------------------------------------------------------------------------*\ +* Incrementally converts a string to quoted-printable +* A, B = qp(C, D, marker) +* Marker is the text to be used to replace CRLF sequences found in A. +* A is the encoded version of the largest prefix of C .. D that +* can be encoded without doubts. +* B has the remaining bytes of C .. D, *without* encoding. +\*-------------------------------------------------------------------------*/ +static int mime_global_qp(lua_State *L) +{ + size_t asize = 0, isize = 0; + UC atom[3]; + const UC *input = (const UC *) luaL_optlstring(L, 1, NULL, &isize); + const UC *last = input + isize; + const char *marker = luaL_optstring(L, 3, CRLF); + luaL_Buffer buffer; + /* end-of-input blackhole */ + if (!input) { + lua_pushnil(L); + lua_pushnil(L); + return 2; + } + /* make sure we don't confuse buffer stuff with arguments */ + lua_settop(L, 3); + /* process first part of input */ + luaL_buffinit(L, &buffer); + while (input < last) + asize = qpencode(*input++, atom, asize, marker, &buffer); + input = (const UC *) luaL_optlstring(L, 2, NULL, &isize); + /* if second part is nil, we are done */ + if (!input) { + asize = qppad(atom, asize, &buffer); + luaL_pushresult(&buffer); + if (!(*lua_tostring(L, -1))) lua_pushnil(L); + lua_pushnil(L); + return 2; + } + /* otherwise process rest of input */ + last = input + isize; + while (input < last) + asize = qpencode(*input++, atom, asize, marker, &buffer); + luaL_pushresult(&buffer); + lua_pushlstring(L, (char *) atom, asize); + return 2; +} + +/*-------------------------------------------------------------------------*\ +* Accumulate characters until we are sure about how to deal with them. +* Once we are sure, output the to the buffer, in the correct form. +\*-------------------------------------------------------------------------*/ +static size_t qpdecode(UC c, UC *input, size_t size, luaL_Buffer *buffer) { + int d; + input[size++] = c; + /* deal with all characters we can deal */ + switch (input[0]) { + /* if we have an escape character */ + case '=': + if (size < 3) return size; + /* eliminate soft line break */ + if (input[1] == '\r' && input[2] == '\n') return 0; + /* decode quoted representation */ + c = qpunbase[input[1]]; d = qpunbase[input[2]]; + /* if it is an invalid, do not decode */ + if (c > 15 || d > 15) luaL_addlstring(buffer, (char *)input, 3); + else luaL_addchar(buffer, (char) ((c << 4) + d)); + return 0; + case '\r': + if (size < 2) return size; + if (input[1] == '\n') luaL_addlstring(buffer, (char *)input, 2); + return 0; + default: + if (input[0] == '\t' || (input[0] > 31 && input[0] < 127)) + luaL_addchar(buffer, input[0]); + return 0; + } +} + +/*-------------------------------------------------------------------------*\ +* Incrementally decodes a string in quoted-printable +* A, B = qp(C, D) +* A is the decoded version of the largest prefix of C .. D that +* can be decoded without doubts. +* B has the remaining bytes of C .. D, *without* decoding. +\*-------------------------------------------------------------------------*/ +static int mime_global_unqp(lua_State *L) +{ + size_t asize = 0, isize = 0; + UC atom[3]; + const UC *input = (const UC *) luaL_optlstring(L, 1, NULL, &isize); + const UC *last = input + isize; + luaL_Buffer buffer; + /* end-of-input blackhole */ + if (!input) { + lua_pushnil(L); + lua_pushnil(L); + return 2; + } + /* make sure we don't confuse buffer stuff with arguments */ + lua_settop(L, 2); + /* process first part of input */ + luaL_buffinit(L, &buffer); + while (input < last) + asize = qpdecode(*input++, atom, asize, &buffer); + input = (const UC *) luaL_optlstring(L, 2, NULL, &isize); + /* if second part is nil, we are done */ + if (!input) { + luaL_pushresult(&buffer); + if (!(*lua_tostring(L, -1))) lua_pushnil(L); + lua_pushnil(L); + return 2; + } + /* otherwise process rest of input */ + last = input + isize; + while (input < last) + asize = qpdecode(*input++, atom, asize, &buffer); + luaL_pushresult(&buffer); + lua_pushlstring(L, (char *) atom, asize); + return 2; +} + +/*-------------------------------------------------------------------------*\ +* Incrementally breaks a quoted-printed string into lines +* A, n = qpwrp(l, B, length) +* A is a copy of B, broken into lines of at most 'length' bytes. +* 'l' is how many bytes are left for the first line of B. +* 'n' is the number of bytes left in the last line of A. +* There are two complications: lines can't be broken in the middle +* of an encoded =XX, and there might be line breaks already +\*-------------------------------------------------------------------------*/ +static int mime_global_qpwrp(lua_State *L) +{ + size_t size = 0; + int left = (int) luaL_checknumber(L, 1); + const UC *input = (const UC *) luaL_optlstring(L, 2, NULL, &size); + const UC *last = input + size; + int length = (int) luaL_optnumber(L, 3, 76); + luaL_Buffer buffer; + /* end-of-input blackhole */ + if (!input) { + if (left < length) lua_pushstring(L, EQCRLF); + else lua_pushnil(L); + lua_pushnumber(L, length); + return 2; + } + /* process all input */ + luaL_buffinit(L, &buffer); + while (input < last) { + switch (*input) { + case '\r': + break; + case '\n': + left = length; + luaL_addstring(&buffer, CRLF); + break; + case '=': + if (left <= 3) { + left = length; + luaL_addstring(&buffer, EQCRLF); + } + luaL_addchar(&buffer, *input); + left--; + break; + default: + if (left <= 1) { + left = length; + luaL_addstring(&buffer, EQCRLF); + } + luaL_addchar(&buffer, *input); + left--; + break; + } + input++; + } + luaL_pushresult(&buffer); + lua_pushnumber(L, left); + return 2; +} + +/*-------------------------------------------------------------------------*\ +* Here is what we do: \n, and \r are considered candidates for line +* break. We issue *one* new line marker if any of them is seen alone, or +* followed by a different one. That is, \n\n and \r\r will issue two +* end of line markers each, but \r\n, \n\r etc will only issue *one* +* marker. This covers Mac OS, Mac OS X, VMS, Unix and DOS, as well as +* probably other more obscure conventions. +* +* c is the current character being processed +* last is the previous character +\*-------------------------------------------------------------------------*/ +#define eolcandidate(c) (c == '\r' || c == '\n') +static int eolprocess(int c, int last, const char *marker, + luaL_Buffer *buffer) +{ + if (eolcandidate(c)) { + if (eolcandidate(last)) { + if (c == last) luaL_addstring(buffer, marker); + return 0; + } else { + luaL_addstring(buffer, marker); + return c; + } + } else { + luaL_addchar(buffer, (char) c); + return 0; + } +} + +/*-------------------------------------------------------------------------*\ +* Converts a string to uniform EOL convention. +* A, n = eol(o, B, marker) +* A is the converted version of the largest prefix of B that can be +* converted unambiguously. 'o' is the context returned by the previous +* call. 'n' is the new context. +\*-------------------------------------------------------------------------*/ +static int mime_global_eol(lua_State *L) +{ + int ctx = (int) luaL_checkinteger(L, 1); + size_t isize = 0; + const char *input = luaL_optlstring(L, 2, NULL, &isize); + const char *last = input + isize; + const char *marker = luaL_optstring(L, 3, CRLF); + luaL_Buffer buffer; + luaL_buffinit(L, &buffer); + /* end of input blackhole */ + if (!input) { + lua_pushnil(L); + lua_pushnumber(L, 0); + return 2; + } + /* process all input */ + while (input < last) + ctx = eolprocess(*input++, ctx, marker, &buffer); + luaL_pushresult(&buffer); + lua_pushnumber(L, ctx); + return 2; +} + +/*-------------------------------------------------------------------------*\ +* Takes one byte and stuff it if needed. +\*-------------------------------------------------------------------------*/ +static size_t dot(int c, size_t state, luaL_Buffer *buffer) +{ + luaL_addchar(buffer, (char) c); + switch (c) { + case '\r': + return 1; + case '\n': + return (state == 1)? 2: 0; + case '.': + if (state == 2) + luaL_addchar(buffer, '.'); + /* Falls through. */ + default: + return 0; + } +} + +/*-------------------------------------------------------------------------*\ +* Incrementally applies smtp stuffing to a string +* A, n = dot(l, D) +\*-------------------------------------------------------------------------*/ +static int mime_global_dot(lua_State *L) +{ + size_t isize = 0, state = (size_t) luaL_checknumber(L, 1); + const char *input = luaL_optlstring(L, 2, NULL, &isize); + const char *last = input + isize; + luaL_Buffer buffer; + /* end-of-input blackhole */ + if (!input) { + lua_pushnil(L); + lua_pushnumber(L, 2); + return 2; + } + /* process all input */ + luaL_buffinit(L, &buffer); + while (input < last) + state = dot(*input++, state, &buffer); + luaL_pushresult(&buffer); + lua_pushnumber(L, (lua_Number) state); + return 2; +} + diff --git a/src/3rd party/lua-extensions/luasocket/mime.h b/src/3rd party/lua-extensions/luasocket/mime.h new file mode 100644 index 000000000..4d938f46e --- /dev/null +++ b/src/3rd party/lua-extensions/luasocket/mime.h @@ -0,0 +1,22 @@ +#ifndef MIME_H +#define MIME_H +/*=========================================================================*\ +* Core MIME support +* LuaSocket toolkit +* +* This module provides functions to implement transfer content encodings +* and formatting conforming to RFC 2045. It is used by mime.lua, which +* provide a higher level interface to this functionality. +\*=========================================================================*/ +#include "luasocket.h" + +/*-------------------------------------------------------------------------*\ +* Current MIME library version +\*-------------------------------------------------------------------------*/ +#define MIME_VERSION "MIME 1.0.3" +#define MIME_COPYRIGHT "Copyright (C) 2004-2013 Diego Nehab" +#define MIME_AUTHORS "Diego Nehab" + +LUASOCKET_API int luaopen_mime_core(lua_State *L); + +#endif /* MIME_H */ diff --git a/src/3rd party/lua-extensions/luasocket/options.c b/src/3rd party/lua-extensions/luasocket/options.c new file mode 100644 index 000000000..9dea6bda2 --- /dev/null +++ b/src/3rd party/lua-extensions/luasocket/options.c @@ -0,0 +1,507 @@ +/*=========================================================================*\ +* Common option interface +* LuaSocket toolkit +\*=========================================================================*/ +#include "luasocket.h" +#include "auxiliar.h" +#include "options.h" +#include "inet.h" +#include + +/*=========================================================================*\ +* Internal functions prototypes +\*=========================================================================*/ +static int opt_setmembership(lua_State *L, p_socket ps, int level, int name); +static int opt_ip6_setmembership(lua_State *L, p_socket ps, int level, int name); +static int opt_setboolean(lua_State *L, p_socket ps, int level, int name); +static int opt_getboolean(lua_State *L, p_socket ps, int level, int name); +static int opt_setint(lua_State *L, p_socket ps, int level, int name); +static int opt_getint(lua_State *L, p_socket ps, int level, int name); +static int opt_set(lua_State *L, p_socket ps, int level, int name, + void *val, int len); +static int opt_get(lua_State *L, p_socket ps, int level, int name, + void *val, int* len); + +/*=========================================================================*\ +* Exported functions +\*=========================================================================*/ +/*-------------------------------------------------------------------------*\ +* Calls appropriate option handler +\*-------------------------------------------------------------------------*/ +int opt_meth_setoption(lua_State *L, p_opt opt, p_socket ps) +{ + const char *name = luaL_checkstring(L, 2); /* obj, name, ... */ + while (opt->name && strcmp(name, opt->name)) + opt++; + if (!opt->func) { + char msg[57]; + sprintf(msg, "unsupported option `%.35s'", name); + luaL_argerror(L, 2, msg); + } + return opt->func(L, ps); +} + +int opt_meth_getoption(lua_State *L, p_opt opt, p_socket ps) +{ + const char *name = luaL_checkstring(L, 2); /* obj, name, ... */ + while (opt->name && strcmp(name, opt->name)) + opt++; + if (!opt->func) { + char msg[57]; + sprintf(msg, "unsupported option `%.35s'", name); + luaL_argerror(L, 2, msg); + } + return opt->func(L, ps); +} + +/*------------------------------------------------------*/ +/* binds socket to network interface */ +int opt_set_bindtodevice(lua_State *L, p_socket ps) +{ +#ifndef SO_BINDTODEVICE + return luaL_error(L, "SO_BINDTODEVICE is not supported on this operating system"); +#else + const char *dev = luaL_checkstring(L, 3); + return opt_set(L, ps, SOL_SOCKET, SO_BINDTODEVICE, (char*)dev, strlen(dev)+1); +#endif +} + +int opt_get_bindtodevice(lua_State *L, p_socket ps) +{ +#ifndef SO_BINDTODEVICE + return luaL_error(L, "SO_BINDTODEVICE is not supported on this operating system"); +#else + char dev[IFNAMSIZ]; + int len = sizeof(dev); + int err = opt_get(L, ps, SOL_SOCKET, SO_BINDTODEVICE, &dev, &len); + if (err) + return err; + lua_pushstring(L, dev); + return 1; +#endif +} + +/*------------------------------------------------------*/ +/* enables reuse of local address */ +int opt_set_reuseaddr(lua_State *L, p_socket ps) +{ + return opt_setboolean(L, ps, SOL_SOCKET, SO_REUSEADDR); +} + +int opt_get_reuseaddr(lua_State *L, p_socket ps) +{ + return opt_getboolean(L, ps, SOL_SOCKET, SO_REUSEADDR); +} + +/*------------------------------------------------------*/ +/* enables reuse of local port */ +int opt_set_reuseport(lua_State *L, p_socket ps) +{ + return opt_setboolean(L, ps, SOL_SOCKET, SO_REUSEPORT); +} + +int opt_get_reuseport(lua_State *L, p_socket ps) +{ + return opt_getboolean(L, ps, SOL_SOCKET, SO_REUSEPORT); +} + +/*------------------------------------------------------*/ +/* disables the Nagle algorithm */ +int opt_set_tcp_nodelay(lua_State *L, p_socket ps) +{ + return opt_setboolean(L, ps, IPPROTO_TCP, TCP_NODELAY); +} + +int opt_get_tcp_nodelay(lua_State *L, p_socket ps) +{ + return opt_getboolean(L, ps, IPPROTO_TCP, TCP_NODELAY); +} + +/*------------------------------------------------------*/ +#ifdef TCP_KEEPIDLE + +int opt_get_tcp_keepidle(lua_State *L, p_socket ps) +{ + return opt_getint(L, ps, IPPROTO_TCP, TCP_KEEPIDLE); +} + +int opt_set_tcp_keepidle(lua_State *L, p_socket ps) +{ + return opt_setint(L, ps, IPPROTO_TCP, TCP_KEEPIDLE); +} + +#endif + +/*------------------------------------------------------*/ +#ifdef TCP_KEEPCNT + +int opt_get_tcp_keepcnt(lua_State *L, p_socket ps) +{ + return opt_getint(L, ps, IPPROTO_TCP, TCP_KEEPCNT); +} + +int opt_set_tcp_keepcnt(lua_State *L, p_socket ps) +{ + return opt_setint(L, ps, IPPROTO_TCP, TCP_KEEPCNT); +} + +#endif + +/*------------------------------------------------------*/ +#ifdef TCP_KEEPINTVL + +int opt_get_tcp_keepintvl(lua_State *L, p_socket ps) +{ + return opt_getint(L, ps, IPPROTO_TCP, TCP_KEEPINTVL); +} + +int opt_set_tcp_keepintvl(lua_State *L, p_socket ps) +{ + return opt_setint(L, ps, IPPROTO_TCP, TCP_KEEPINTVL); +} + +#endif + +/*------------------------------------------------------*/ +int opt_set_keepalive(lua_State *L, p_socket ps) +{ + return opt_setboolean(L, ps, SOL_SOCKET, SO_KEEPALIVE); +} + +int opt_get_keepalive(lua_State *L, p_socket ps) +{ + return opt_getboolean(L, ps, SOL_SOCKET, SO_KEEPALIVE); +} + +/*------------------------------------------------------*/ +int opt_set_dontroute(lua_State *L, p_socket ps) +{ + return opt_setboolean(L, ps, SOL_SOCKET, SO_DONTROUTE); +} + +int opt_get_dontroute(lua_State *L, p_socket ps) +{ + return opt_getboolean(L, ps, SOL_SOCKET, SO_DONTROUTE); +} + +/*------------------------------------------------------*/ +int opt_set_broadcast(lua_State *L, p_socket ps) +{ + return opt_setboolean(L, ps, SOL_SOCKET, SO_BROADCAST); +} + +int opt_get_broadcast(lua_State *L, p_socket ps) +{ + return opt_getboolean(L, ps, SOL_SOCKET, SO_BROADCAST); +} + +/*------------------------------------------------------*/ +int opt_set_recv_buf_size(lua_State *L, p_socket ps) +{ + return opt_setint(L, ps, SOL_SOCKET, SO_RCVBUF); +} + +int opt_get_recv_buf_size(lua_State *L, p_socket ps) +{ + return opt_getint(L, ps, SOL_SOCKET, SO_RCVBUF); +} + +/*------------------------------------------------------*/ +int opt_get_send_buf_size(lua_State *L, p_socket ps) +{ + return opt_getint(L, ps, SOL_SOCKET, SO_SNDBUF); +} + +int opt_set_send_buf_size(lua_State *L, p_socket ps) +{ + return opt_setint(L, ps, SOL_SOCKET, SO_SNDBUF); +} + +/*------------------------------------------------------*/ + +#ifdef TCP_FASTOPEN +int opt_set_tcp_fastopen(lua_State *L, p_socket ps) +{ + return opt_setint(L, ps, IPPROTO_TCP, TCP_FASTOPEN); +} +#endif + +#ifdef TCP_FASTOPEN_CONNECT +int opt_set_tcp_fastopen_connect(lua_State *L, p_socket ps) +{ + return opt_setint(L, ps, IPPROTO_TCP, TCP_FASTOPEN_CONNECT); +} +#endif + +/*------------------------------------------------------*/ + +#ifdef TCP_DEFER_ACCEPT +int opt_set_tcp_defer_accept(lua_State *L, p_socket ps) +{ + return opt_setint(L, ps, IPPROTO_TCP, TCP_DEFER_ACCEPT); +} +#endif + +/*------------------------------------------------------*/ +int opt_set_ip6_unicast_hops(lua_State *L, p_socket ps) +{ + return opt_setint(L, ps, IPPROTO_IPV6, IPV6_UNICAST_HOPS); +} + +int opt_get_ip6_unicast_hops(lua_State *L, p_socket ps) +{ + return opt_getint(L, ps, IPPROTO_IPV6, IPV6_UNICAST_HOPS); +} + +/*------------------------------------------------------*/ +int opt_set_ip6_multicast_hops(lua_State *L, p_socket ps) +{ + return opt_setint(L, ps, IPPROTO_IPV6, IPV6_MULTICAST_HOPS); +} + +int opt_get_ip6_multicast_hops(lua_State *L, p_socket ps) +{ + return opt_getint(L, ps, IPPROTO_IPV6, IPV6_MULTICAST_HOPS); +} + +/*------------------------------------------------------*/ +int opt_set_ip_multicast_loop(lua_State *L, p_socket ps) +{ + return opt_setboolean(L, ps, IPPROTO_IP, IP_MULTICAST_LOOP); +} + +int opt_get_ip_multicast_loop(lua_State *L, p_socket ps) +{ + return opt_getboolean(L, ps, IPPROTO_IP, IP_MULTICAST_LOOP); +} + +/*------------------------------------------------------*/ +int opt_set_ip6_multicast_loop(lua_State *L, p_socket ps) +{ + return opt_setboolean(L, ps, IPPROTO_IPV6, IPV6_MULTICAST_LOOP); +} + +int opt_get_ip6_multicast_loop(lua_State *L, p_socket ps) +{ + return opt_getboolean(L, ps, IPPROTO_IPV6, IPV6_MULTICAST_LOOP); +} + +/*------------------------------------------------------*/ +int opt_set_linger(lua_State *L, p_socket ps) +{ + struct linger li; /* obj, name, table */ + if (!lua_istable(L, 3)) auxiliar_typeerror(L,3,lua_typename(L, LUA_TTABLE)); + lua_pushstring(L, "on"); + lua_gettable(L, 3); + if (!lua_isboolean(L, -1)) + luaL_argerror(L, 3, "boolean 'on' field expected"); + li.l_onoff = (u_short) lua_toboolean(L, -1); + lua_pushstring(L, "timeout"); + lua_gettable(L, 3); + if (!lua_isnumber(L, -1)) + luaL_argerror(L, 3, "number 'timeout' field expected"); + li.l_linger = (u_short) lua_tonumber(L, -1); + return opt_set(L, ps, SOL_SOCKET, SO_LINGER, (char *) &li, sizeof(li)); +} + +int opt_get_linger(lua_State *L, p_socket ps) +{ + struct linger li; /* obj, name */ + int len = sizeof(li); + int err = opt_get(L, ps, SOL_SOCKET, SO_LINGER, (char *) &li, &len); + if (err) + return err; + lua_newtable(L); + lua_pushboolean(L, li.l_onoff); + lua_setfield(L, -2, "on"); + lua_pushinteger(L, li.l_linger); + lua_setfield(L, -2, "timeout"); + return 1; +} + +/*------------------------------------------------------*/ +int opt_set_ip_multicast_ttl(lua_State *L, p_socket ps) +{ + return opt_setint(L, ps, IPPROTO_IP, IP_MULTICAST_TTL); +} + +/*------------------------------------------------------*/ +int opt_set_ip_multicast_if(lua_State *L, p_socket ps) +{ + const char *address = luaL_checkstring(L, 3); /* obj, name, ip */ + struct in_addr val; + val.s_addr = htonl(INADDR_ANY); + if (strcmp(address, "*") && !inet_aton(address, &val)) + luaL_argerror(L, 3, "ip expected"); + return opt_set(L, ps, IPPROTO_IP, IP_MULTICAST_IF, + (char *) &val, sizeof(val)); +} + +int opt_get_ip_multicast_if(lua_State *L, p_socket ps) +{ + struct in_addr val; + socklen_t len = sizeof(val); + if (getsockopt(*ps, IPPROTO_IP, IP_MULTICAST_IF, (char *) &val, &len) < 0) { + lua_pushnil(L); + lua_pushstring(L, "getsockopt failed"); + return 2; + } + lua_pushstring(L, inet_ntoa(val)); + return 1; +} + +/*------------------------------------------------------*/ +int opt_set_ip_add_membership(lua_State *L, p_socket ps) +{ + return opt_setmembership(L, ps, IPPROTO_IP, IP_ADD_MEMBERSHIP); +} + +int opt_set_ip_drop_membersip(lua_State *L, p_socket ps) +{ + return opt_setmembership(L, ps, IPPROTO_IP, IP_DROP_MEMBERSHIP); +} + +/*------------------------------------------------------*/ +int opt_set_ip6_add_membership(lua_State *L, p_socket ps) +{ + return opt_ip6_setmembership(L, ps, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP); +} + +int opt_set_ip6_drop_membersip(lua_State *L, p_socket ps) +{ + return opt_ip6_setmembership(L, ps, IPPROTO_IPV6, IPV6_DROP_MEMBERSHIP); +} + +/*------------------------------------------------------*/ +int opt_get_ip6_v6only(lua_State *L, p_socket ps) +{ + return opt_getboolean(L, ps, IPPROTO_IPV6, IPV6_V6ONLY); +} + +int opt_set_ip6_v6only(lua_State *L, p_socket ps) +{ + return opt_setboolean(L, ps, IPPROTO_IPV6, IPV6_V6ONLY); +} + +/*------------------------------------------------------*/ +int opt_get_error(lua_State *L, p_socket ps) +{ + int val = 0; + socklen_t len = sizeof(val); + if (getsockopt(*ps, SOL_SOCKET, SO_ERROR, (char *) &val, &len) < 0) { + lua_pushnil(L); + lua_pushstring(L, "getsockopt failed"); + return 2; + } + lua_pushstring(L, socket_strerror(val)); + return 1; +} + +/*=========================================================================*\ +* Auxiliar functions +\*=========================================================================*/ +static int opt_setmembership(lua_State *L, p_socket ps, int level, int name) +{ + struct ip_mreq val; /* obj, name, table */ + if (!lua_istable(L, 3)) auxiliar_typeerror(L,3,lua_typename(L, LUA_TTABLE)); + lua_pushstring(L, "multiaddr"); + lua_gettable(L, 3); + if (!lua_isstring(L, -1)) + luaL_argerror(L, 3, "string 'multiaddr' field expected"); + if (!inet_aton(lua_tostring(L, -1), &val.imr_multiaddr)) + luaL_argerror(L, 3, "invalid 'multiaddr' ip address"); + lua_pushstring(L, "interface"); + lua_gettable(L, 3); + if (!lua_isstring(L, -1)) + luaL_argerror(L, 3, "string 'interface' field expected"); + val.imr_interface.s_addr = htonl(INADDR_ANY); + if (strcmp(lua_tostring(L, -1), "*") && + !inet_aton(lua_tostring(L, -1), &val.imr_interface)) + luaL_argerror(L, 3, "invalid 'interface' ip address"); + return opt_set(L, ps, level, name, (char *) &val, sizeof(val)); +} + +static int opt_ip6_setmembership(lua_State *L, p_socket ps, int level, int name) +{ + struct ipv6_mreq val; /* obj, opt-name, table */ + memset(&val, 0, sizeof(val)); + if (!lua_istable(L, 3)) auxiliar_typeerror(L,3,lua_typename(L, LUA_TTABLE)); + lua_pushstring(L, "multiaddr"); + lua_gettable(L, 3); + if (!lua_isstring(L, -1)) + luaL_argerror(L, 3, "string 'multiaddr' field expected"); + if (!inet_pton(AF_INET6, lua_tostring(L, -1), &val.ipv6mr_multiaddr)) + luaL_argerror(L, 3, "invalid 'multiaddr' ip address"); + lua_pushstring(L, "interface"); + lua_gettable(L, 3); + /* By default we listen to interface on default route + * (sigh). However, interface= can override it. We should + * support either number, or name for it. Waiting for + * windows port of if_nametoindex */ + if (!lua_isnil(L, -1)) { + if (lua_isnumber(L, -1)) { + val.ipv6mr_interface = (unsigned int) lua_tonumber(L, -1); + } else + luaL_argerror(L, -1, "number 'interface' field expected"); + } + return opt_set(L, ps, level, name, (char *) &val, sizeof(val)); +} + +static +int opt_get(lua_State *L, p_socket ps, int level, int name, void *val, int* len) +{ + socklen_t socklen = *len; + if (getsockopt(*ps, level, name, (char *) val, &socklen) < 0) { + lua_pushnil(L); + lua_pushstring(L, "getsockopt failed"); + return 2; + } + *len = socklen; + return 0; +} + +static +int opt_set(lua_State *L, p_socket ps, int level, int name, void *val, int len) +{ + if (setsockopt(*ps, level, name, (char *) val, len) < 0) { + lua_pushnil(L); + lua_pushstring(L, "setsockopt failed"); + return 2; + } + lua_pushnumber(L, 1); + return 1; +} + +static int opt_getboolean(lua_State *L, p_socket ps, int level, int name) +{ + int val = 0; + int len = sizeof(val); + int err = opt_get(L, ps, level, name, (char *) &val, &len); + if (err) + return err; + lua_pushboolean(L, val); + return 1; +} + +static int opt_setboolean(lua_State *L, p_socket ps, int level, int name) +{ + int val = auxiliar_checkboolean(L, 3); /* obj, name, bool */ + return opt_set(L, ps, level, name, (char *) &val, sizeof(val)); +} + +static int opt_getint(lua_State *L, p_socket ps, int level, int name) +{ + int val = 0; + int len = sizeof(val); + int err = opt_get(L, ps, level, name, (char *) &val, &len); + if (err) + return err; + lua_pushnumber(L, val); + return 1; +} + +static int opt_setint(lua_State *L, p_socket ps, int level, int name) +{ + int val = (int) lua_tonumber(L, 3); /* obj, name, int */ + return opt_set(L, ps, level, name, (char *) &val, sizeof(val)); +} diff --git a/src/3rd party/lua-extensions/luasocket/options.h b/src/3rd party/lua-extensions/luasocket/options.h new file mode 100644 index 000000000..26d6f0250 --- /dev/null +++ b/src/3rd party/lua-extensions/luasocket/options.h @@ -0,0 +1,116 @@ +#ifndef OPTIONS_H +#define OPTIONS_H +/*=========================================================================*\ +* Common option interface +* LuaSocket toolkit +* +* This module provides a common interface to socket options, used mainly by +* modules UDP and TCP. +\*=========================================================================*/ + +#include "luasocket.h" +#include "socket.h" + +/* option registry */ +typedef struct t_opt { + const char *name; + int (*func)(lua_State *L, p_socket ps); +} t_opt; +typedef t_opt *p_opt; + +#ifndef _WIN32 +#pragma GCC visibility push(hidden) +#endif + +int opt_meth_setoption(lua_State *L, p_opt opt, p_socket ps); +int opt_meth_getoption(lua_State *L, p_opt opt, p_socket ps); + +int opt_set_reuseaddr(lua_State *L, p_socket ps); +int opt_get_reuseaddr(lua_State *L, p_socket ps); + +int opt_set_reuseport(lua_State *L, p_socket ps); +int opt_get_reuseport(lua_State *L, p_socket ps); + +int opt_set_tcp_nodelay(lua_State *L, p_socket ps); +int opt_get_tcp_nodelay(lua_State *L, p_socket ps); + +#ifdef TCP_KEEPIDLE +int opt_set_tcp_keepidle(lua_State *L, p_socket ps); +int opt_get_tcp_keepidle(lua_State *L, p_socket ps); +#endif + +#ifdef TCP_KEEPCNT +int opt_set_tcp_keepcnt(lua_State *L, p_socket ps); +int opt_get_tcp_keepcnt(lua_State *L, p_socket ps); +#endif + +#ifdef TCP_KEEPINTVL +int opt_set_tcp_keepintvl(lua_State *L, p_socket ps); +int opt_get_tcp_keepintvl(lua_State *L, p_socket ps); +#endif + +#ifdef TCP_DEFER_ACCEPT +int opt_set_tcp_defer_accept(lua_State *L, p_socket ps); +#endif + +int opt_set_bindtodevice(lua_State *L, p_socket ps); +int opt_get_bindtodevice(lua_State *L, p_socket ps); + +int opt_set_keepalive(lua_State *L, p_socket ps); +int opt_get_keepalive(lua_State *L, p_socket ps); + +int opt_set_dontroute(lua_State *L, p_socket ps); +int opt_get_dontroute(lua_State *L, p_socket ps); + +int opt_set_broadcast(lua_State *L, p_socket ps); +int opt_get_broadcast(lua_State *L, p_socket ps); + +int opt_set_recv_buf_size(lua_State *L, p_socket ps); +int opt_get_recv_buf_size(lua_State *L, p_socket ps); + +int opt_set_send_buf_size(lua_State *L, p_socket ps); +int opt_get_send_buf_size(lua_State *L, p_socket ps); + +#ifdef TCP_FASTOPEN +int opt_set_tcp_fastopen(lua_State *L, p_socket ps); +#endif +#ifdef TCP_FASTOPEN_CONNECT +int opt_set_tcp_fastopen_connect(lua_State *L, p_socket ps); +#endif + +int opt_set_ip6_unicast_hops(lua_State *L, p_socket ps); +int opt_get_ip6_unicast_hops(lua_State *L, p_socket ps); + +int opt_set_ip6_multicast_hops(lua_State *L, p_socket ps); +int opt_get_ip6_multicast_hops(lua_State *L, p_socket ps); + +int opt_set_ip_multicast_loop(lua_State *L, p_socket ps); +int opt_get_ip_multicast_loop(lua_State *L, p_socket ps); + +int opt_set_ip6_multicast_loop(lua_State *L, p_socket ps); +int opt_get_ip6_multicast_loop(lua_State *L, p_socket ps); + +int opt_set_linger(lua_State *L, p_socket ps); +int opt_get_linger(lua_State *L, p_socket ps); + +int opt_set_ip_multicast_ttl(lua_State *L, p_socket ps); + +int opt_set_ip_multicast_if(lua_State *L, p_socket ps); +int opt_get_ip_multicast_if(lua_State *L, p_socket ps); + +int opt_set_ip_add_membership(lua_State *L, p_socket ps); +int opt_set_ip_drop_membersip(lua_State *L, p_socket ps); + +int opt_set_ip6_add_membership(lua_State *L, p_socket ps); +int opt_set_ip6_drop_membersip(lua_State *L, p_socket ps); + +int opt_set_ip6_v6only(lua_State *L, p_socket ps); +int opt_get_ip6_v6only(lua_State *L, p_socket ps); + +int opt_get_error(lua_State *L, p_socket ps); + +#ifndef _WIN32 +#pragma GCC visibility pop +#endif + +#endif diff --git a/src/3rd party/lua-extensions/luasocket/pierror.h b/src/3rd party/lua-extensions/luasocket/pierror.h new file mode 100644 index 000000000..cb773ab7f --- /dev/null +++ b/src/3rd party/lua-extensions/luasocket/pierror.h @@ -0,0 +1,28 @@ +#ifndef PIERROR_H +#define PIERROR_H +/*=========================================================================*\ +* Error messages +* Defines platform independent error messages +\*=========================================================================*/ + +#define PIE_HOST_NOT_FOUND "host not found" +#define PIE_ADDRINUSE "address already in use" +#define PIE_ISCONN "already connected" +#define PIE_ACCESS "permission denied" +#define PIE_CONNREFUSED "connection refused" +#define PIE_CONNABORTED "closed" +#define PIE_CONNRESET "closed" +#define PIE_TIMEDOUT "timeout" +#define PIE_AGAIN "temporary failure in name resolution" +#define PIE_BADFLAGS "invalid value for ai_flags" +#define PIE_BADHINTS "invalid value for hints" +#define PIE_FAIL "non-recoverable failure in name resolution" +#define PIE_FAMILY "ai_family not supported" +#define PIE_MEMORY "memory allocation failure" +#define PIE_NONAME "host or service not provided, or not known" +#define PIE_OVERFLOW "argument buffer overflow" +#define PIE_PROTOCOL "resolved protocol is unknown" +#define PIE_SERVICE "service not supported for socket type" +#define PIE_SOCKTYPE "ai_socktype not supported" + +#endif diff --git a/src/3rd party/lua-extensions/luasocket/select.c b/src/3rd party/lua-extensions/luasocket/select.c new file mode 100644 index 000000000..bb47c4592 --- /dev/null +++ b/src/3rd party/lua-extensions/luasocket/select.c @@ -0,0 +1,214 @@ +/*=========================================================================*\ +* Select implementation +* LuaSocket toolkit +\*=========================================================================*/ +#include "luasocket.h" + +#include "socket.h" +#include "timeout.h" +#include "select.h" + +#include + +/*=========================================================================*\ +* Internal function prototypes. +\*=========================================================================*/ +static t_socket getfd(lua_State *L); +static int dirty(lua_State *L); +static void collect_fd(lua_State *L, int tab, int itab, + fd_set *set, t_socket *max_fd); +static int check_dirty(lua_State *L, int tab, int dtab, fd_set *set); +static void return_fd(lua_State *L, fd_set *set, t_socket max_fd, + int itab, int tab, int start); +static void make_assoc(lua_State *L, int tab); +static int global_select(lua_State *L); + +/* functions in library namespace */ +static luaL_Reg func[] = { + {"select", global_select}, + {NULL, NULL} +}; + +/*-------------------------------------------------------------------------*\ +* Initializes module +\*-------------------------------------------------------------------------*/ +int select_open(lua_State *L) { + lua_pushstring(L, "_SETSIZE"); + lua_pushinteger(L, FD_SETSIZE); + lua_rawset(L, -3); + lua_pushstring(L, "_SOCKETINVALID"); + lua_pushinteger(L, SOCKET_INVALID); + lua_rawset(L, -3); + luaL_setfuncs(L, func, 0); + return 0; +} + +/*=========================================================================*\ +* Global Lua functions +\*=========================================================================*/ +/*-------------------------------------------------------------------------*\ +* Waits for a set of sockets until a condition is met or timeout. +\*-------------------------------------------------------------------------*/ +static int global_select(lua_State *L) { + int rtab, wtab, itab, ret, ndirty; + t_socket max_fd = SOCKET_INVALID; + fd_set rset, wset; + t_timeout tm; + double t = luaL_optnumber(L, 3, -1); + FD_ZERO(&rset); FD_ZERO(&wset); + lua_settop(L, 3); + lua_newtable(L); itab = lua_gettop(L); + lua_newtable(L); rtab = lua_gettop(L); + lua_newtable(L); wtab = lua_gettop(L); + collect_fd(L, 1, itab, &rset, &max_fd); + collect_fd(L, 2, itab, &wset, &max_fd); + ndirty = check_dirty(L, 1, rtab, &rset); + t = ndirty > 0? 0.0: t; + timeout_init(&tm, t, -1); + timeout_markstart(&tm); + ret = socket_select(max_fd+1, &rset, &wset, NULL, &tm); + if (ret > 0 || ndirty > 0) { + return_fd(L, &rset, max_fd+1, itab, rtab, ndirty); + return_fd(L, &wset, max_fd+1, itab, wtab, 0); + make_assoc(L, rtab); + make_assoc(L, wtab); + return 2; + } else if (ret == 0) { + lua_pushstring(L, "timeout"); + return 3; + } else { + luaL_error(L, "select failed"); + return 3; + } +} + +/*=========================================================================*\ +* Internal functions +\*=========================================================================*/ +static t_socket getfd(lua_State *L) { + t_socket fd = SOCKET_INVALID; + lua_pushstring(L, "getfd"); + lua_gettable(L, -2); + if (!lua_isnil(L, -1)) { + lua_pushvalue(L, -2); + lua_call(L, 1, 1); + if (lua_isnumber(L, -1)) { + double numfd = lua_tonumber(L, -1); + fd = (numfd >= 0.0)? (t_socket) numfd: SOCKET_INVALID; + } + } + lua_pop(L, 1); + return fd; +} + +static int dirty(lua_State *L) { + int is = 0; + lua_pushstring(L, "dirty"); + lua_gettable(L, -2); + if (!lua_isnil(L, -1)) { + lua_pushvalue(L, -2); + lua_call(L, 1, 1); + is = lua_toboolean(L, -1); + } + lua_pop(L, 1); + return is; +} + +static void collect_fd(lua_State *L, int tab, int itab, + fd_set *set, t_socket *max_fd) { + int i = 1, n = 0; + /* nil is the same as an empty table */ + if (lua_isnil(L, tab)) return; + /* otherwise we need it to be a table */ + luaL_checktype(L, tab, LUA_TTABLE); + for ( ;; ) { + t_socket fd; + lua_pushnumber(L, i); + lua_gettable(L, tab); + if (lua_isnil(L, -1)) { + lua_pop(L, 1); + break; + } + /* getfd figures out if this is a socket */ + fd = getfd(L); + if (fd != SOCKET_INVALID) { + /* make sure we don't overflow the fd_set */ +#ifdef _WIN32 + if (n >= FD_SETSIZE) + luaL_argerror(L, tab, "too many sockets"); +#else + if (fd >= FD_SETSIZE) + luaL_argerror(L, tab, "descriptor too large for set size"); +#endif + FD_SET(fd, set); + n++; + /* keep track of the largest descriptor so far */ + if (*max_fd == SOCKET_INVALID || *max_fd < fd) + *max_fd = fd; + /* make sure we can map back from descriptor to the object */ + lua_pushnumber(L, (lua_Number) fd); + lua_pushvalue(L, -2); + lua_settable(L, itab); + } + lua_pop(L, 1); + i = i + 1; + } +} + +static int check_dirty(lua_State *L, int tab, int dtab, fd_set *set) { + int ndirty = 0, i = 1; + if (lua_isnil(L, tab)) + return 0; + for ( ;; ) { + t_socket fd; + lua_pushnumber(L, i); + lua_gettable(L, tab); + if (lua_isnil(L, -1)) { + lua_pop(L, 1); + break; + } + fd = getfd(L); + if (fd != SOCKET_INVALID && dirty(L)) { + lua_pushnumber(L, ++ndirty); + lua_pushvalue(L, -2); + lua_settable(L, dtab); + FD_CLR(fd, set); + } + lua_pop(L, 1); + i = i + 1; + } + return ndirty; +} + +static void return_fd(lua_State *L, fd_set *set, t_socket max_fd, + int itab, int tab, int start) { + t_socket fd; + for (fd = 0; fd < max_fd; fd++) { + if (FD_ISSET(fd, set)) { + lua_pushnumber(L, ++start); + lua_pushnumber(L, (lua_Number) fd); + lua_gettable(L, itab); + lua_settable(L, tab); + } + } +} + +static void make_assoc(lua_State *L, int tab) { + int i = 1, atab; + lua_newtable(L); atab = lua_gettop(L); + for ( ;; ) { + lua_pushnumber(L, i); + lua_gettable(L, tab); + if (!lua_isnil(L, -1)) { + lua_pushnumber(L, i); + lua_pushvalue(L, -2); + lua_settable(L, atab); + lua_pushnumber(L, i); + lua_settable(L, atab); + } else { + lua_pop(L, 1); + break; + } + i = i+1; + } +} diff --git a/src/3rd party/lua-extensions/luasocket/select.h b/src/3rd party/lua-extensions/luasocket/select.h new file mode 100644 index 000000000..5d45fe753 --- /dev/null +++ b/src/3rd party/lua-extensions/luasocket/select.h @@ -0,0 +1,23 @@ +#ifndef SELECT_H +#define SELECT_H +/*=========================================================================*\ +* Select implementation +* LuaSocket toolkit +* +* Each object that can be passed to the select function has to export +* method getfd() which returns the descriptor to be passed to the +* underlying select function. Another method, dirty(), should return +* true if there is data ready for reading (required for buffered input). +\*=========================================================================*/ + +#ifndef _WIN32 +#pragma GCC visibility push(hidden) +#endif + +int select_open(lua_State *L); + +#ifndef _WIN32 +#pragma GCC visibility pop +#endif + +#endif /* SELECT_H */ diff --git a/src/3rd party/lua-extensions/luasocket/socket.h b/src/3rd party/lua-extensions/luasocket/socket.h new file mode 100644 index 000000000..2555bab64 --- /dev/null +++ b/src/3rd party/lua-extensions/luasocket/socket.h @@ -0,0 +1,75 @@ +#ifndef SOCKET_H +#define SOCKET_H +/*=========================================================================*\ +* Socket compatibilization module +* LuaSocket toolkit +* +* BSD Sockets and WinSock are similar, but there are a few irritating +* differences. Also, not all *nix platforms behave the same. This module +* (and the associated usocket.h and wsocket.h) factor these differences and +* creates a interface compatible with the io.h module. +\*=========================================================================*/ +#include "io.h" + +/*=========================================================================*\ +* Platform specific compatibilization +\*=========================================================================*/ +#ifdef _WIN32 +#include "wsocket.h" +#define LUA_GAI_STRERROR gai_strerrorA +#else +#include "usocket.h" +#define LUA_GAI_STRERROR gai_strerror +#endif + +/*=========================================================================*\ +* The connect and accept functions accept a timeout and their +* implementations are somewhat complicated. We chose to move +* the timeout control into this module for these functions in +* order to simplify the modules that use them. +\*=========================================================================*/ +#include "timeout.h" + +/* convenient shorthand */ +typedef struct sockaddr SA; + +/*=========================================================================*\ +* Functions bellow implement a comfortable platform independent +* interface to sockets +\*=========================================================================*/ + +#ifndef _WIN32 +#pragma GCC visibility push(hidden) +#endif + +int socket_waitfd(p_socket ps, int sw, p_timeout tm); +int socket_open(void); +int socket_close(void); +void socket_destroy(p_socket ps); +int socket_select(t_socket n, fd_set *rfds, fd_set *wfds, fd_set *efds, p_timeout tm); +int socket_create(p_socket ps, int domain, int type, int protocol); +int socket_bind(p_socket ps, SA *addr, socklen_t addr_len); +int socket_listen(p_socket ps, int backlog); +void socket_shutdown(p_socket ps, int how); +int socket_connect(p_socket ps, SA *addr, socklen_t addr_len, p_timeout tm); +int socket_accept(p_socket ps, p_socket pa, SA *addr, socklen_t *addr_len, p_timeout tm); +int socket_send(p_socket ps, const char *data, size_t count, size_t *sent, p_timeout tm); +int socket_sendto(p_socket ps, const char *data, size_t count, size_t *sent, SA *addr, socklen_t addr_len, p_timeout tm); +int socket_recv(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm); +int socket_recvfrom(p_socket ps, char *data, size_t count, size_t *got, SA *addr, socklen_t *addr_len, p_timeout tm); +int socket_write(p_socket ps, const char *data, size_t count, size_t *sent, p_timeout tm); +int socket_read(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm); +void socket_setblocking(p_socket ps); +void socket_setnonblocking(p_socket ps); +int socket_gethostbyaddr(const char *addr, socklen_t len, struct hostent **hp); +int socket_gethostbyname(const char *addr, struct hostent **hp); +const char *socket_hoststrerror(int err); +const char *socket_strerror(int err); +const char *socket_ioerror(p_socket ps, int err); +const char *socket_gaistrerror(int err); + +#ifndef _WIN32 +#pragma GCC visibility pop +#endif + +#endif /* SOCKET_H */ diff --git a/src/3rd party/lua-extensions/luasocket/tcp.c b/src/3rd party/lua-extensions/luasocket/tcp.c new file mode 100644 index 000000000..f00120640 --- /dev/null +++ b/src/3rd party/lua-extensions/luasocket/tcp.c @@ -0,0 +1,482 @@ +/*=========================================================================*\ +* TCP object +* LuaSocket toolkit +\*=========================================================================*/ +#include "luasocket.h" + +#include "auxiliar.h" +#include "socket.h" +#include "inet.h" +#include "options.h" +#include "tcp.h" + +#include + +/*=========================================================================*\ +* Internal function prototypes +\*=========================================================================*/ +static int global_create(lua_State *L); +static int global_create4(lua_State *L); +static int global_create6(lua_State *L); +static int global_connect(lua_State *L); +static int meth_connect(lua_State *L); +static int meth_listen(lua_State *L); +static int meth_getfamily(lua_State *L); +static int meth_bind(lua_State *L); +static int meth_send(lua_State *L); +static int meth_getstats(lua_State *L); +static int meth_setstats(lua_State *L); +static int meth_getsockname(lua_State *L); +static int meth_getpeername(lua_State *L); +static int meth_shutdown(lua_State *L); +static int meth_receive(lua_State *L); +static int meth_accept(lua_State *L); +static int meth_close(lua_State *L); +static int meth_getoption(lua_State *L); +static int meth_setoption(lua_State *L); +static int meth_gettimeout(lua_State *L); +static int meth_settimeout(lua_State *L); +static int meth_getfd(lua_State *L); +static int meth_setfd(lua_State *L); +static int meth_dirty(lua_State *L); + +/* tcp object methods */ +static luaL_Reg tcp_methods[] = { + {"__gc", meth_close}, + {"__tostring", auxiliar_tostring}, + {"accept", meth_accept}, + {"bind", meth_bind}, + {"close", meth_close}, + {"connect", meth_connect}, + {"dirty", meth_dirty}, + {"getfamily", meth_getfamily}, + {"getfd", meth_getfd}, + {"getoption", meth_getoption}, + {"getpeername", meth_getpeername}, + {"getsockname", meth_getsockname}, + {"getstats", meth_getstats}, + {"setstats", meth_setstats}, + {"listen", meth_listen}, + {"receive", meth_receive}, + {"send", meth_send}, + {"setfd", meth_setfd}, + {"setoption", meth_setoption}, + {"setpeername", meth_connect}, + {"setsockname", meth_bind}, + {"settimeout", meth_settimeout}, + {"gettimeout", meth_gettimeout}, + {"shutdown", meth_shutdown}, + {NULL, NULL} +}; + +/* socket option handlers */ +static t_opt optget[] = { + {"bindtodevice", opt_get_bindtodevice}, + {"keepalive", opt_get_keepalive}, + {"reuseaddr", opt_get_reuseaddr}, + {"reuseport", opt_get_reuseport}, + {"tcp-nodelay", opt_get_tcp_nodelay}, +#ifdef TCP_KEEPIDLE + {"tcp-keepidle", opt_get_tcp_keepidle}, +#endif +#ifdef TCP_KEEPCNT + {"tcp-keepcnt", opt_get_tcp_keepcnt}, +#endif +#ifdef TCP_KEEPINTVL + {"tcp-keepintvl", opt_get_tcp_keepintvl}, +#endif + {"linger", opt_get_linger}, + {"error", opt_get_error}, + {"recv-buffer-size", opt_get_recv_buf_size}, + {"send-buffer-size", opt_get_send_buf_size}, + {NULL, NULL} +}; + +static t_opt optset[] = { + {"bindtodevice", opt_set_bindtodevice}, + {"keepalive", opt_set_keepalive}, + {"reuseaddr", opt_set_reuseaddr}, + {"reuseport", opt_set_reuseport}, + {"tcp-nodelay", opt_set_tcp_nodelay}, +#ifdef TCP_KEEPIDLE + {"tcp-keepidle", opt_set_tcp_keepidle}, +#endif +#ifdef TCP_KEEPCNT + {"tcp-keepcnt", opt_set_tcp_keepcnt}, +#endif +#ifdef TCP_KEEPINTVL + {"tcp-keepintvl", opt_set_tcp_keepintvl}, +#endif + {"ipv6-v6only", opt_set_ip6_v6only}, + {"linger", opt_set_linger}, + {"recv-buffer-size", opt_set_recv_buf_size}, + {"send-buffer-size", opt_set_send_buf_size}, +#ifdef TCP_DEFER_ACCEPT + {"tcp-defer-accept", opt_set_tcp_defer_accept}, +#endif +#ifdef TCP_FASTOPEN + {"tcp-fastopen", opt_set_tcp_fastopen}, +#endif +#ifdef TCP_FASTOPEN_CONNECT + {"tcp-fastopen-connect", opt_set_tcp_fastopen_connect}, +#endif + {NULL, NULL} +}; + +/* functions in library namespace */ +static luaL_Reg func[] = { + {"tcp", global_create}, + {"tcp4", global_create4}, + {"tcp6", global_create6}, + {"connect", global_connect}, + {NULL, NULL} +}; + +/*-------------------------------------------------------------------------*\ +* Initializes module +\*-------------------------------------------------------------------------*/ +int tcp_open(lua_State *L) +{ + /* create classes */ + auxiliar_newclass(L, "tcp{master}", tcp_methods); + auxiliar_newclass(L, "tcp{client}", tcp_methods); + auxiliar_newclass(L, "tcp{server}", tcp_methods); + /* create class groups */ + auxiliar_add2group(L, "tcp{master}", "tcp{any}"); + auxiliar_add2group(L, "tcp{client}", "tcp{any}"); + auxiliar_add2group(L, "tcp{server}", "tcp{any}"); + /* define library functions */ + luaL_setfuncs(L, func, 0); + return 0; +} + +/*=========================================================================*\ +* Lua methods +\*=========================================================================*/ +/*-------------------------------------------------------------------------*\ +* Just call buffered IO methods +\*-------------------------------------------------------------------------*/ +static int meth_send(lua_State *L) { + p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{client}", 1); + return buffer_meth_send(L, &tcp->buf); +} + +static int meth_receive(lua_State *L) { + p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{client}", 1); + return buffer_meth_receive(L, &tcp->buf); +} + +static int meth_getstats(lua_State *L) { + p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{client}", 1); + return buffer_meth_getstats(L, &tcp->buf); +} + +static int meth_setstats(lua_State *L) { + p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{client}", 1); + return buffer_meth_setstats(L, &tcp->buf); +} + +/*-------------------------------------------------------------------------*\ +* Just call option handler +\*-------------------------------------------------------------------------*/ +static int meth_getoption(lua_State *L) +{ + p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); + return opt_meth_getoption(L, optget, &tcp->sock); +} + +static int meth_setoption(lua_State *L) +{ + p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); + return opt_meth_setoption(L, optset, &tcp->sock); +} + +/*-------------------------------------------------------------------------*\ +* Select support methods +\*-------------------------------------------------------------------------*/ +static int meth_getfd(lua_State *L) +{ + p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); + lua_pushnumber(L, (int) tcp->sock); + return 1; +} + +/* this is very dangerous, but can be handy for those that are brave enough */ +static int meth_setfd(lua_State *L) +{ + p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); + tcp->sock = (t_socket) luaL_checknumber(L, 2); + return 0; +} + +static int meth_dirty(lua_State *L) +{ + p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); + lua_pushboolean(L, !buffer_isempty(&tcp->buf)); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Waits for and returns a client object attempting connection to the +* server object +\*-------------------------------------------------------------------------*/ +static int meth_accept(lua_State *L) +{ + p_tcp server = (p_tcp) auxiliar_checkclass(L, "tcp{server}", 1); + p_timeout tm = timeout_markstart(&server->tm); + t_socket sock; + const char *err = inet_tryaccept(&server->sock, server->family, &sock, tm); + /* if successful, push client socket */ + if (err == NULL) { + p_tcp clnt = (p_tcp) lua_newuserdata(L, sizeof(t_tcp)); + auxiliar_setclass(L, "tcp{client}", -1); + /* initialize structure fields */ + memset(clnt, 0, sizeof(t_tcp)); + socket_setnonblocking(&sock); + clnt->sock = sock; + io_init(&clnt->io, (p_send) socket_send, (p_recv) socket_recv, + (p_error) socket_ioerror, &clnt->sock); + timeout_init(&clnt->tm, -1, -1); + buffer_init(&clnt->buf, &clnt->io, &clnt->tm); + clnt->family = server->family; + return 1; + } else { + lua_pushnil(L); + lua_pushstring(L, err); + return 2; + } +} + +/*-------------------------------------------------------------------------*\ +* Binds an object to an address +\*-------------------------------------------------------------------------*/ +static int meth_bind(lua_State *L) { + p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{master}", 1); + const char *address = luaL_checkstring(L, 2); + const char *port = luaL_checkstring(L, 3); + const char *err; + struct addrinfo bindhints; + memset(&bindhints, 0, sizeof(bindhints)); + bindhints.ai_socktype = SOCK_STREAM; + bindhints.ai_family = tcp->family; + bindhints.ai_flags = AI_PASSIVE; + err = inet_trybind(&tcp->sock, &tcp->family, address, port, &bindhints); + if (err) { + lua_pushnil(L); + lua_pushstring(L, err); + return 2; + } + lua_pushnumber(L, 1); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Turns a master tcp object into a client object. +\*-------------------------------------------------------------------------*/ +static int meth_connect(lua_State *L) { + p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); + const char *address = luaL_checkstring(L, 2); + const char *port = luaL_checkstring(L, 3); + struct addrinfo connecthints; + const char *err; + memset(&connecthints, 0, sizeof(connecthints)); + connecthints.ai_socktype = SOCK_STREAM; + /* make sure we try to connect only to the same family */ + connecthints.ai_family = tcp->family; + timeout_markstart(&tcp->tm); + err = inet_tryconnect(&tcp->sock, &tcp->family, address, port, + &tcp->tm, &connecthints); + /* have to set the class even if it failed due to non-blocking connects */ + auxiliar_setclass(L, "tcp{client}", 1); + if (err) { + lua_pushnil(L); + lua_pushstring(L, err); + return 2; + } + lua_pushnumber(L, 1); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Closes socket used by object +\*-------------------------------------------------------------------------*/ +static int meth_close(lua_State *L) +{ + p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); + socket_destroy(&tcp->sock); + lua_pushnumber(L, 1); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Returns family as string +\*-------------------------------------------------------------------------*/ +static int meth_getfamily(lua_State *L) +{ + p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); + if (tcp->family == AF_INET6) { + lua_pushliteral(L, "inet6"); + return 1; + } else if (tcp->family == AF_INET) { + lua_pushliteral(L, "inet4"); + return 1; + } else { + lua_pushliteral(L, "inet4"); + return 1; + } +} + +/*-------------------------------------------------------------------------*\ +* Puts the sockt in listen mode +\*-------------------------------------------------------------------------*/ +static int meth_listen(lua_State *L) +{ + p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{master}", 1); + int backlog = (int) luaL_optnumber(L, 2, 32); + int err = socket_listen(&tcp->sock, backlog); + if (err != IO_DONE) { + lua_pushnil(L); + lua_pushstring(L, socket_strerror(err)); + return 2; + } + /* turn master object into a server object */ + auxiliar_setclass(L, "tcp{server}", 1); + lua_pushnumber(L, 1); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Shuts the connection down partially +\*-------------------------------------------------------------------------*/ +static int meth_shutdown(lua_State *L) +{ + /* SHUT_RD, SHUT_WR, SHUT_RDWR have the value 0, 1, 2, so we can use method index directly */ + static const char* methods[] = { "receive", "send", "both", NULL }; + p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{client}", 1); + int how = luaL_checkoption(L, 2, "both", methods); + socket_shutdown(&tcp->sock, how); + lua_pushnumber(L, 1); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Just call inet methods +\*-------------------------------------------------------------------------*/ +static int meth_getpeername(lua_State *L) +{ + p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); + return inet_meth_getpeername(L, &tcp->sock, tcp->family); +} + +static int meth_getsockname(lua_State *L) +{ + p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); + return inet_meth_getsockname(L, &tcp->sock, tcp->family); +} + +/*-------------------------------------------------------------------------*\ +* Just call tm methods +\*-------------------------------------------------------------------------*/ +static int meth_settimeout(lua_State *L) +{ + p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); + return timeout_meth_settimeout(L, &tcp->tm); +} + +static int meth_gettimeout(lua_State *L) +{ + p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); + return timeout_meth_gettimeout(L, &tcp->tm); +} + +/*=========================================================================*\ +* Library functions +\*=========================================================================*/ +/*-------------------------------------------------------------------------*\ +* Creates a master tcp object +\*-------------------------------------------------------------------------*/ +static int tcp_create(lua_State *L, int family) { + p_tcp tcp = (p_tcp) lua_newuserdata(L, sizeof(t_tcp)); + memset(tcp, 0, sizeof(t_tcp)); + /* set its type as master object */ + auxiliar_setclass(L, "tcp{master}", -1); + /* if family is AF_UNSPEC, we leave the socket invalid and + * store AF_UNSPEC into family. This will allow it to later be + * replaced with an AF_INET6 or AF_INET socket upon first use. */ + tcp->sock = SOCKET_INVALID; + tcp->family = family; + io_init(&tcp->io, (p_send) socket_send, (p_recv) socket_recv, + (p_error) socket_ioerror, &tcp->sock); + timeout_init(&tcp->tm, -1, -1); + buffer_init(&tcp->buf, &tcp->io, &tcp->tm); + if (family != AF_UNSPEC) { + const char *err = inet_trycreate(&tcp->sock, family, SOCK_STREAM, 0); + if (err != NULL) { + lua_pushnil(L); + lua_pushstring(L, err); + return 2; + } + socket_setnonblocking(&tcp->sock); + } + return 1; +} + +static int global_create(lua_State *L) { + return tcp_create(L, AF_UNSPEC); +} + +static int global_create4(lua_State *L) { + return tcp_create(L, AF_INET); +} + +static int global_create6(lua_State *L) { + return tcp_create(L, AF_INET6); +} + +static int global_connect(lua_State *L) { + const char *remoteaddr = luaL_checkstring(L, 1); + const char *remoteserv = luaL_checkstring(L, 2); + const char *localaddr = luaL_optstring(L, 3, NULL); + const char *localserv = luaL_optstring(L, 4, "0"); + int family = inet_optfamily(L, 5, "unspec"); + p_tcp tcp = (p_tcp) lua_newuserdata(L, sizeof(t_tcp)); + struct addrinfo bindhints, connecthints; + const char *err = NULL; + /* initialize tcp structure */ + memset(tcp, 0, sizeof(t_tcp)); + io_init(&tcp->io, (p_send) socket_send, (p_recv) socket_recv, + (p_error) socket_ioerror, &tcp->sock); + timeout_init(&tcp->tm, -1, -1); + buffer_init(&tcp->buf, &tcp->io, &tcp->tm); + tcp->sock = SOCKET_INVALID; + tcp->family = AF_UNSPEC; + /* allow user to pick local address and port */ + memset(&bindhints, 0, sizeof(bindhints)); + bindhints.ai_socktype = SOCK_STREAM; + bindhints.ai_family = family; + bindhints.ai_flags = AI_PASSIVE; + if (localaddr) { + err = inet_trybind(&tcp->sock, &tcp->family, localaddr, + localserv, &bindhints); + if (err) { + lua_pushnil(L); + lua_pushstring(L, err); + return 2; + } + } + /* try to connect to remote address and port */ + memset(&connecthints, 0, sizeof(connecthints)); + connecthints.ai_socktype = SOCK_STREAM; + /* make sure we try to connect only to the same family */ + connecthints.ai_family = tcp->family; + err = inet_tryconnect(&tcp->sock, &tcp->family, remoteaddr, remoteserv, + &tcp->tm, &connecthints); + if (err) { + socket_destroy(&tcp->sock); + lua_pushnil(L); + lua_pushstring(L, err); + return 2; + } + auxiliar_setclass(L, "tcp{client}", -1); + return 1; +} diff --git a/src/3rd party/lua-extensions/luasocket/tcp.h b/src/3rd party/lua-extensions/luasocket/tcp.h new file mode 100644 index 000000000..9b282efeb --- /dev/null +++ b/src/3rd party/lua-extensions/luasocket/tcp.h @@ -0,0 +1,43 @@ +#ifndef TCP_H +#define TCP_H +/*=========================================================================*\ +* TCP object +* LuaSocket toolkit +* +* The tcp.h module is basicly a glue that puts together modules buffer.h, +* timeout.h socket.h and inet.h to provide the LuaSocket TCP (AF_INET, +* SOCK_STREAM) support. +* +* Three classes are defined: master, client and server. The master class is +* a newly created tcp object, that has not been bound or connected. Server +* objects are tcp objects bound to some local address. Client objects are +* tcp objects either connected to some address or returned by the accept +* method of a server object. +\*=========================================================================*/ +#include "luasocket.h" + +#include "buffer.h" +#include "timeout.h" +#include "socket.h" + +typedef struct t_tcp_ { + t_socket sock; + t_io io; + t_buffer buf; + t_timeout tm; + int family; +} t_tcp; + +typedef t_tcp *p_tcp; + +#ifndef _WIN32 +#pragma GCC visibility push(hidden) +#endif + +int tcp_open(lua_State *L); + +#ifndef _WIN32 +#pragma GCC visibility pop +#endif + +#endif /* TCP_H */ diff --git a/src/3rd party/lua-extensions/luasocket/timeout.c b/src/3rd party/lua-extensions/luasocket/timeout.c new file mode 100644 index 000000000..2bdc0698c --- /dev/null +++ b/src/3rd party/lua-extensions/luasocket/timeout.c @@ -0,0 +1,226 @@ +/*=========================================================================*\ +* Timeout management functions +* LuaSocket toolkit +\*=========================================================================*/ +#include "luasocket.h" + +#include "auxiliar.h" +#include "timeout.h" + +#include +#include +#include + +#ifdef _WIN32 +#include +#else +#include +#include +#endif + +/* min and max macros */ +#ifndef MIN +#define MIN(x, y) ((x) < (y) ? x : y) +#endif +#ifndef MAX +#define MAX(x, y) ((x) > (y) ? x : y) +#endif + +/*=========================================================================*\ +* Internal function prototypes +\*=========================================================================*/ +static int timeout_lua_gettime(lua_State *L); +static int timeout_lua_sleep(lua_State *L); + +static luaL_Reg func[] = { + { "gettime", timeout_lua_gettime }, + { "sleep", timeout_lua_sleep }, + { NULL, NULL } +}; + +/*=========================================================================*\ +* Exported functions. +\*=========================================================================*/ +/*-------------------------------------------------------------------------*\ +* Initialize structure +\*-------------------------------------------------------------------------*/ +void timeout_init(p_timeout tm, double block, double total) { + tm->block = block; + tm->total = total; +} + +/*-------------------------------------------------------------------------*\ +* Determines how much time we have left for the next system call, +* if the previous call was successful +* Input +* tm: timeout control structure +* Returns +* the number of ms left or -1 if there is no time limit +\*-------------------------------------------------------------------------*/ +double timeout_get(p_timeout tm) { + if (tm->block < 0.0 && tm->total < 0.0) { + return -1; + } else if (tm->block < 0.0) { + double t = tm->total - timeout_gettime() + tm->start; + return MAX(t, 0.0); + } else if (tm->total < 0.0) { + return tm->block; + } else { + double t = tm->total - timeout_gettime() + tm->start; + return MIN(tm->block, MAX(t, 0.0)); + } +} + +/*-------------------------------------------------------------------------*\ +* Returns time since start of operation +* Input +* tm: timeout control structure +* Returns +* start field of structure +\*-------------------------------------------------------------------------*/ +double timeout_getstart(p_timeout tm) { + return tm->start; +} + +/*-------------------------------------------------------------------------*\ +* Determines how much time we have left for the next system call, +* if the previous call was a failure +* Input +* tm: timeout control structure +* Returns +* the number of ms left or -1 if there is no time limit +\*-------------------------------------------------------------------------*/ +double timeout_getretry(p_timeout tm) { + if (tm->block < 0.0 && tm->total < 0.0) { + return -1; + } else if (tm->block < 0.0) { + double t = tm->total - timeout_gettime() + tm->start; + return MAX(t, 0.0); + } else if (tm->total < 0.0) { + double t = tm->block - timeout_gettime() + tm->start; + return MAX(t, 0.0); + } else { + double t = tm->total - timeout_gettime() + tm->start; + return MIN(tm->block, MAX(t, 0.0)); + } +} + +/*-------------------------------------------------------------------------*\ +* Marks the operation start time in structure +* Input +* tm: timeout control structure +\*-------------------------------------------------------------------------*/ +p_timeout timeout_markstart(p_timeout tm) { + tm->start = timeout_gettime(); + return tm; +} + +/*-------------------------------------------------------------------------*\ +* Gets time in s, relative to January 1, 1970 (UTC) +* Returns +* time in s. +\*-------------------------------------------------------------------------*/ +#ifdef _WIN32 +double timeout_gettime(void) { + FILETIME ft; + double t; + GetSystemTimeAsFileTime(&ft); + /* Windows file time (time since January 1, 1601 (UTC)) */ + t = ft.dwLowDateTime/1.0e7 + ft.dwHighDateTime*(4294967296.0/1.0e7); + /* convert to Unix Epoch time (time since January 1, 1970 (UTC)) */ + return (t - 11644473600.0); +} +#else +double timeout_gettime(void) { + struct timeval v; + gettimeofday(&v, (struct timezone *) NULL); + /* Unix Epoch time (time since January 1, 1970 (UTC)) */ + return v.tv_sec + v.tv_usec/1.0e6; +} +#endif + +/*-------------------------------------------------------------------------*\ +* Initializes module +\*-------------------------------------------------------------------------*/ +int timeout_open(lua_State *L) { + luaL_setfuncs(L, func, 0); + return 0; +} + +/*-------------------------------------------------------------------------*\ +* Sets timeout values for IO operations +* Lua Input: base, time [, mode] +* time: time out value in seconds +* mode: "b" for block timeout, "t" for total timeout. (default: b) +\*-------------------------------------------------------------------------*/ +int timeout_meth_settimeout(lua_State *L, p_timeout tm) { + double t = luaL_optnumber(L, 2, -1); + const char *mode = luaL_optstring(L, 3, "b"); + switch (*mode) { + case 'b': + tm->block = t; + break; + case 'r': case 't': + tm->total = t; + break; + default: + luaL_argcheck(L, 0, 3, "invalid timeout mode"); + break; + } + lua_pushnumber(L, 1); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Gets timeout values for IO operations +* Lua Output: block, total +\*-------------------------------------------------------------------------*/ +int timeout_meth_gettimeout(lua_State *L, p_timeout tm) { + lua_pushnumber(L, tm->block); + lua_pushnumber(L, tm->total); + return 2; +} + +/*=========================================================================*\ +* Test support functions +\*=========================================================================*/ +/*-------------------------------------------------------------------------*\ +* Returns the time the system has been up, in secconds. +\*-------------------------------------------------------------------------*/ +static int timeout_lua_gettime(lua_State *L) +{ + lua_pushnumber(L, timeout_gettime()); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Sleep for n seconds. +\*-------------------------------------------------------------------------*/ +#ifdef _WIN32 +int timeout_lua_sleep(lua_State *L) +{ + double n = luaL_checknumber(L, 1); + if (n < 0.0) n = 0.0; + if (n < DBL_MAX/1000.0) n *= 1000.0; + if (n > INT_MAX) n = INT_MAX; + Sleep((int)n); + return 0; +} +#else +int timeout_lua_sleep(lua_State *L) +{ + double n = luaL_checknumber(L, 1); + struct timespec t, r; + if (n < 0.0) n = 0.0; + if (n > INT_MAX) n = INT_MAX; + t.tv_sec = (int) n; + n -= t.tv_sec; + t.tv_nsec = (int) (n * 1000000000); + if (t.tv_nsec >= 1000000000) t.tv_nsec = 999999999; + while (nanosleep(&t, &r) != 0) { + t.tv_sec = r.tv_sec; + t.tv_nsec = r.tv_nsec; + } + return 0; +} +#endif diff --git a/src/3rd party/lua-extensions/luasocket/timeout.h b/src/3rd party/lua-extensions/luasocket/timeout.h new file mode 100644 index 000000000..9e5250d33 --- /dev/null +++ b/src/3rd party/lua-extensions/luasocket/timeout.h @@ -0,0 +1,40 @@ +#ifndef TIMEOUT_H +#define TIMEOUT_H +/*=========================================================================*\ +* Timeout management functions +* LuaSocket toolkit +\*=========================================================================*/ +#include "luasocket.h" + +/* timeout control structure */ +typedef struct t_timeout_ { + double block; /* maximum time for blocking calls */ + double total; /* total number of miliseconds for operation */ + double start; /* time of start of operation */ +} t_timeout; +typedef t_timeout *p_timeout; + +#ifndef _WIN32 +#pragma GCC visibility push(hidden) +#endif + +void timeout_init(p_timeout tm, double block, double total); +double timeout_get(p_timeout tm); +double timeout_getstart(p_timeout tm); +double timeout_getretry(p_timeout tm); +p_timeout timeout_markstart(p_timeout tm); + +double timeout_gettime(void); + +int timeout_open(lua_State *L); + +int timeout_meth_settimeout(lua_State *L, p_timeout tm); +int timeout_meth_gettimeout(lua_State *L, p_timeout tm); + +#ifndef _WIN32 +#pragma GCC visibility pop +#endif + +#define timeout_iszero(tm) ((tm)->block == 0.0) + +#endif /* TIMEOUT_H */ diff --git a/src/3rd party/lua-extensions/luasocket/udp.c b/src/3rd party/lua-extensions/luasocket/udp.c new file mode 100644 index 000000000..712ad50fe --- /dev/null +++ b/src/3rd party/lua-extensions/luasocket/udp.c @@ -0,0 +1,488 @@ +/*=========================================================================*\ +* UDP object +* LuaSocket toolkit +\*=========================================================================*/ +#include "luasocket.h" + +#include "auxiliar.h" +#include "socket.h" +#include "inet.h" +#include "options.h" +#include "udp.h" + +#include +#include + +/* min and max macros */ +#ifndef MIN +#define MIN(x, y) ((x) < (y) ? x : y) +#endif +#ifndef MAX +#define MAX(x, y) ((x) > (y) ? x : y) +#endif + +/*=========================================================================*\ +* Internal function prototypes +\*=========================================================================*/ +static int global_create(lua_State *L); +static int global_create4(lua_State *L); +static int global_create6(lua_State *L); +static int meth_send(lua_State *L); +static int meth_sendto(lua_State *L); +static int meth_receive(lua_State *L); +static int meth_receivefrom(lua_State *L); +static int meth_getfamily(lua_State *L); +static int meth_getsockname(lua_State *L); +static int meth_getpeername(lua_State *L); +static int meth_gettimeout(lua_State *L); +static int meth_setsockname(lua_State *L); +static int meth_setpeername(lua_State *L); +static int meth_close(lua_State *L); +static int meth_setoption(lua_State *L); +static int meth_getoption(lua_State *L); +static int meth_settimeout(lua_State *L); +static int meth_getfd(lua_State *L); +static int meth_setfd(lua_State *L); +static int meth_dirty(lua_State *L); + +/* udp object methods */ +static luaL_Reg udp_methods[] = { + {"__gc", meth_close}, + {"__tostring", auxiliar_tostring}, + {"close", meth_close}, + {"dirty", meth_dirty}, + {"getfamily", meth_getfamily}, + {"getfd", meth_getfd}, + {"getpeername", meth_getpeername}, + {"getsockname", meth_getsockname}, + {"receive", meth_receive}, + {"receivefrom", meth_receivefrom}, + {"send", meth_send}, + {"sendto", meth_sendto}, + {"setfd", meth_setfd}, + {"setoption", meth_setoption}, + {"getoption", meth_getoption}, + {"setpeername", meth_setpeername}, + {"setsockname", meth_setsockname}, + {"settimeout", meth_settimeout}, + {"gettimeout", meth_gettimeout}, + {NULL, NULL} +}; + +/* socket options for setoption */ +static t_opt optset[] = { + {"dontroute", opt_set_dontroute}, + {"broadcast", opt_set_broadcast}, + {"reuseaddr", opt_set_reuseaddr}, + {"reuseport", opt_set_reuseport}, + {"ip-multicast-if", opt_set_ip_multicast_if}, + {"ip-multicast-ttl", opt_set_ip_multicast_ttl}, + {"ip-multicast-loop", opt_set_ip_multicast_loop}, + {"ip-add-membership", opt_set_ip_add_membership}, + {"ip-drop-membership", opt_set_ip_drop_membersip}, + {"ipv6-unicast-hops", opt_set_ip6_unicast_hops}, + {"ipv6-multicast-hops", opt_set_ip6_unicast_hops}, + {"ipv6-multicast-loop", opt_set_ip6_multicast_loop}, + {"ipv6-add-membership", opt_set_ip6_add_membership}, + {"ipv6-drop-membership", opt_set_ip6_drop_membersip}, + {"ipv6-v6only", opt_set_ip6_v6only}, + {"recv-buffer-size", opt_set_recv_buf_size}, + {"send-buffer-size", opt_set_send_buf_size}, + {NULL, NULL} +}; + +/* socket options for getoption */ +static t_opt optget[] = { + {"dontroute", opt_get_dontroute}, + {"broadcast", opt_get_broadcast}, + {"reuseaddr", opt_get_reuseaddr}, + {"reuseport", opt_get_reuseport}, + {"ip-multicast-if", opt_get_ip_multicast_if}, + {"ip-multicast-loop", opt_get_ip_multicast_loop}, + {"error", opt_get_error}, + {"ipv6-unicast-hops", opt_get_ip6_unicast_hops}, + {"ipv6-multicast-hops", opt_get_ip6_unicast_hops}, + {"ipv6-multicast-loop", opt_get_ip6_multicast_loop}, + {"ipv6-v6only", opt_get_ip6_v6only}, + {"recv-buffer-size", opt_get_recv_buf_size}, + {"send-buffer-size", opt_get_send_buf_size}, + {NULL, NULL} +}; + +/* functions in library namespace */ +static luaL_Reg func[] = { + {"udp", global_create}, + {"udp4", global_create4}, + {"udp6", global_create6}, + {NULL, NULL} +}; + +/*-------------------------------------------------------------------------*\ +* Initializes module +\*-------------------------------------------------------------------------*/ +int udp_open(lua_State *L) { + /* create classes */ + auxiliar_newclass(L, "udp{connected}", udp_methods); + auxiliar_newclass(L, "udp{unconnected}", udp_methods); + /* create class groups */ + auxiliar_add2group(L, "udp{connected}", "udp{any}"); + auxiliar_add2group(L, "udp{unconnected}", "udp{any}"); + auxiliar_add2group(L, "udp{connected}", "select{able}"); + auxiliar_add2group(L, "udp{unconnected}", "select{able}"); + /* define library functions */ + luaL_setfuncs(L, func, 0); + /* export default UDP size */ + lua_pushliteral(L, "_DATAGRAMSIZE"); + lua_pushinteger(L, UDP_DATAGRAMSIZE); + lua_rawset(L, -3); + return 0; +} + +/*=========================================================================*\ +* Lua methods +\*=========================================================================*/ +static const char *udp_strerror(int err) { + /* a 'closed' error on an unconnected means the target address was not + * accepted by the transport layer */ + if (err == IO_CLOSED) return "refused"; + else return socket_strerror(err); +} + +/*-------------------------------------------------------------------------*\ +* Send data through connected udp socket +\*-------------------------------------------------------------------------*/ +static int meth_send(lua_State *L) { + p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{connected}", 1); + p_timeout tm = &udp->tm; + size_t count, sent = 0; + int err; + const char *data = luaL_checklstring(L, 2, &count); + timeout_markstart(tm); + err = socket_send(&udp->sock, data, count, &sent, tm); + if (err != IO_DONE) { + lua_pushnil(L); + lua_pushstring(L, udp_strerror(err)); + return 2; + } + lua_pushnumber(L, (lua_Number) sent); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Send data through unconnected udp socket +\*-------------------------------------------------------------------------*/ +static int meth_sendto(lua_State *L) { + p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{unconnected}", 1); + size_t count, sent = 0; + const char *data = luaL_checklstring(L, 2, &count); + const char *ip = luaL_checkstring(L, 3); + const char *port = luaL_checkstring(L, 4); + p_timeout tm = &udp->tm; + int err; + struct addrinfo aihint; + struct addrinfo *ai; + memset(&aihint, 0, sizeof(aihint)); + aihint.ai_family = udp->family; + aihint.ai_socktype = SOCK_DGRAM; + aihint.ai_flags = AI_NUMERICHOST; +#ifdef AI_NUMERICSERV + aihint.ai_flags |= AI_NUMERICSERV; +#endif + err = getaddrinfo(ip, port, &aihint, &ai); + if (err) { + lua_pushnil(L); + lua_pushstring(L, LUA_GAI_STRERROR(err)); + return 2; + } + + /* create socket if on first sendto if AF_UNSPEC was set */ + if (udp->family == AF_UNSPEC && udp->sock == SOCKET_INVALID) { + struct addrinfo *ap; + const char *errstr = NULL; + for (ap = ai; ap != NULL; ap = ap->ai_next) { + errstr = inet_trycreate(&udp->sock, ap->ai_family, SOCK_DGRAM, 0); + if (errstr == NULL) { + socket_setnonblocking(&udp->sock); + udp->family = ap->ai_family; + break; + } + } + if (errstr != NULL) { + lua_pushnil(L); + lua_pushstring(L, errstr); + freeaddrinfo(ai); + return 2; + } + } + + timeout_markstart(tm); + err = socket_sendto(&udp->sock, data, count, &sent, ai->ai_addr, + (socklen_t) ai->ai_addrlen, tm); + freeaddrinfo(ai); + if (err != IO_DONE) { + lua_pushnil(L); + lua_pushstring(L, udp_strerror(err)); + return 2; + } + lua_pushnumber(L, (lua_Number) sent); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Receives data from a UDP socket +\*-------------------------------------------------------------------------*/ +static int meth_receive(lua_State *L) { + p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); + char buf[UDP_DATAGRAMSIZE]; + size_t got, wanted = (size_t) luaL_optnumber(L, 2, sizeof(buf)); + char *dgram = wanted > sizeof(buf)? (char *) malloc(wanted): buf; + int err; + p_timeout tm = &udp->tm; + timeout_markstart(tm); + if (!dgram) { + lua_pushnil(L); + lua_pushliteral(L, "out of memory"); + return 2; + } + err = socket_recv(&udp->sock, dgram, wanted, &got, tm); + /* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */ + if (err != IO_DONE && err != IO_CLOSED) { + lua_pushnil(L); + lua_pushstring(L, udp_strerror(err)); + if (wanted > sizeof(buf)) free(dgram); + return 2; + } + lua_pushlstring(L, dgram, got); + if (wanted > sizeof(buf)) free(dgram); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Receives data and sender from a UDP socket +\*-------------------------------------------------------------------------*/ +static int meth_receivefrom(lua_State *L) { + p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{unconnected}", 1); + char buf[UDP_DATAGRAMSIZE]; + size_t got, wanted = (size_t) luaL_optnumber(L, 2, sizeof(buf)); + char *dgram = wanted > sizeof(buf)? (char *) malloc(wanted): buf; + struct sockaddr_storage addr; + socklen_t addr_len = sizeof(addr); + char addrstr[INET6_ADDRSTRLEN]; + char portstr[6]; + int err; + p_timeout tm = &udp->tm; + timeout_markstart(tm); + if (!dgram) { + lua_pushnil(L); + lua_pushliteral(L, "out of memory"); + return 2; + } + err = socket_recvfrom(&udp->sock, dgram, wanted, &got, (SA *) &addr, + &addr_len, tm); + /* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */ + if (err != IO_DONE && err != IO_CLOSED) { + lua_pushnil(L); + lua_pushstring(L, udp_strerror(err)); + if (wanted > sizeof(buf)) free(dgram); + return 2; + } + err = getnameinfo((struct sockaddr *)&addr, addr_len, addrstr, + INET6_ADDRSTRLEN, portstr, 6, NI_NUMERICHOST | NI_NUMERICSERV); + if (err) { + lua_pushnil(L); + lua_pushstring(L, LUA_GAI_STRERROR(err)); + if (wanted > sizeof(buf)) free(dgram); + return 2; + } + lua_pushlstring(L, dgram, got); + lua_pushstring(L, addrstr); + lua_pushinteger(L, (int) strtol(portstr, (char **) NULL, 10)); + if (wanted > sizeof(buf)) free(dgram); + return 3; +} + +/*-------------------------------------------------------------------------*\ +* Returns family as string +\*-------------------------------------------------------------------------*/ +static int meth_getfamily(lua_State *L) { + p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); + if (udp->family == AF_INET6) { + lua_pushliteral(L, "inet6"); + return 1; + } else { + lua_pushliteral(L, "inet4"); + return 1; + } +} + +/*-------------------------------------------------------------------------*\ +* Select support methods +\*-------------------------------------------------------------------------*/ +static int meth_getfd(lua_State *L) { + p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); + lua_pushnumber(L, (int) udp->sock); + return 1; +} + +/* this is very dangerous, but can be handy for those that are brave enough */ +static int meth_setfd(lua_State *L) { + p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); + udp->sock = (t_socket) luaL_checknumber(L, 2); + return 0; +} + +static int meth_dirty(lua_State *L) { + p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); + (void) udp; + lua_pushboolean(L, 0); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Just call inet methods +\*-------------------------------------------------------------------------*/ +static int meth_getpeername(lua_State *L) { + p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{connected}", 1); + return inet_meth_getpeername(L, &udp->sock, udp->family); +} + +static int meth_getsockname(lua_State *L) { + p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); + return inet_meth_getsockname(L, &udp->sock, udp->family); +} + +/*-------------------------------------------------------------------------*\ +* Just call option handler +\*-------------------------------------------------------------------------*/ +static int meth_setoption(lua_State *L) { + p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); + return opt_meth_setoption(L, optset, &udp->sock); +} + +/*-------------------------------------------------------------------------*\ +* Just call option handler +\*-------------------------------------------------------------------------*/ +static int meth_getoption(lua_State *L) { + p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); + return opt_meth_getoption(L, optget, &udp->sock); +} + +/*-------------------------------------------------------------------------*\ +* Just call tm methods +\*-------------------------------------------------------------------------*/ +static int meth_settimeout(lua_State *L) { + p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); + return timeout_meth_settimeout(L, &udp->tm); +} + +static int meth_gettimeout(lua_State *L) { + p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); + return timeout_meth_gettimeout(L, &udp->tm); +} + +/*-------------------------------------------------------------------------*\ +* Turns a master udp object into a client object. +\*-------------------------------------------------------------------------*/ +static int meth_setpeername(lua_State *L) { + p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); + p_timeout tm = &udp->tm; + const char *address = luaL_checkstring(L, 2); + int connecting = strcmp(address, "*"); + const char *port = connecting? luaL_checkstring(L, 3): "0"; + struct addrinfo connecthints; + const char *err; + memset(&connecthints, 0, sizeof(connecthints)); + connecthints.ai_socktype = SOCK_DGRAM; + /* make sure we try to connect only to the same family */ + connecthints.ai_family = udp->family; + if (connecting) { + err = inet_tryconnect(&udp->sock, &udp->family, address, + port, tm, &connecthints); + if (err) { + lua_pushnil(L); + lua_pushstring(L, err); + return 2; + } + auxiliar_setclass(L, "udp{connected}", 1); + } else { + /* we ignore possible errors because Mac OS X always + * returns EAFNOSUPPORT */ + inet_trydisconnect(&udp->sock, udp->family, tm); + auxiliar_setclass(L, "udp{unconnected}", 1); + } + lua_pushnumber(L, 1); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Closes socket used by object +\*-------------------------------------------------------------------------*/ +static int meth_close(lua_State *L) { + p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); + socket_destroy(&udp->sock); + lua_pushnumber(L, 1); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Turns a master object into a server object +\*-------------------------------------------------------------------------*/ +static int meth_setsockname(lua_State *L) { + p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{unconnected}", 1); + const char *address = luaL_checkstring(L, 2); + const char *port = luaL_checkstring(L, 3); + const char *err; + struct addrinfo bindhints; + memset(&bindhints, 0, sizeof(bindhints)); + bindhints.ai_socktype = SOCK_DGRAM; + bindhints.ai_family = udp->family; + bindhints.ai_flags = AI_PASSIVE; + err = inet_trybind(&udp->sock, &udp->family, address, port, &bindhints); + if (err) { + lua_pushnil(L); + lua_pushstring(L, err); + return 2; + } + lua_pushnumber(L, 1); + return 1; +} + +/*=========================================================================*\ +* Library functions +\*=========================================================================*/ +/*-------------------------------------------------------------------------*\ +* Creates a master udp object +\*-------------------------------------------------------------------------*/ +static int udp_create(lua_State *L, int family) { + /* allocate udp object */ + p_udp udp = (p_udp) lua_newuserdata(L, sizeof(t_udp)); + auxiliar_setclass(L, "udp{unconnected}", -1); + /* if family is AF_UNSPEC, we leave the socket invalid and + * store AF_UNSPEC into family. This will allow it to later be + * replaced with an AF_INET6 or AF_INET socket upon first use. */ + udp->sock = SOCKET_INVALID; + timeout_init(&udp->tm, -1, -1); + udp->family = family; + if (family != AF_UNSPEC) { + const char *err = inet_trycreate(&udp->sock, family, SOCK_DGRAM, 0); + if (err != NULL) { + lua_pushnil(L); + lua_pushstring(L, err); + return 2; + } + socket_setnonblocking(&udp->sock); + } + return 1; +} + +static int global_create(lua_State *L) { + return udp_create(L, AF_UNSPEC); +} + +static int global_create4(lua_State *L) { + return udp_create(L, AF_INET); +} + +static int global_create6(lua_State *L) { + return udp_create(L, AF_INET6); +} diff --git a/src/3rd party/lua-extensions/luasocket/udp.h b/src/3rd party/lua-extensions/luasocket/udp.h new file mode 100644 index 000000000..07d5247fc --- /dev/null +++ b/src/3rd party/lua-extensions/luasocket/udp.h @@ -0,0 +1,39 @@ +#ifndef UDP_H +#define UDP_H +/*=========================================================================*\ +* UDP object +* LuaSocket toolkit +* +* The udp.h module provides LuaSocket with support for UDP protocol +* (AF_INET, SOCK_DGRAM). +* +* Two classes are defined: connected and unconnected. UDP objects are +* originally unconnected. They can be "connected" to a given address +* with a call to the setpeername function. The same function can be used to +* break the connection. +\*=========================================================================*/ +#include "luasocket.h" + +#include "timeout.h" +#include "socket.h" + +#define UDP_DATAGRAMSIZE 8192 + +typedef struct t_udp_ { + t_socket sock; + t_timeout tm; + int family; +} t_udp; +typedef t_udp *p_udp; + +#ifndef _WIN32 +#pragma GCC visibility push(hidden) +#endif + +int udp_open(lua_State *L); + +#ifndef _WIN32 +#pragma GCC visibility pop +#endif + +#endif /* UDP_H */ diff --git a/src/3rd party/lua-extensions/luasocket/unix.c b/src/3rd party/lua-extensions/luasocket/unix.c new file mode 100644 index 000000000..268d8b212 --- /dev/null +++ b/src/3rd party/lua-extensions/luasocket/unix.c @@ -0,0 +1,69 @@ +/*=========================================================================*\ +* Unix domain socket +* LuaSocket toolkit +\*=========================================================================*/ +#include "luasocket.h" + +#include "unixstream.h" +#include "unixdgram.h" + +/*-------------------------------------------------------------------------*\ +* Modules and functions +\*-------------------------------------------------------------------------*/ +static const luaL_Reg mod[] = { + {"stream", unixstream_open}, + {"dgram", unixdgram_open}, + {NULL, NULL} +}; + +static void add_alias(lua_State *L, int index, const char *name, const char *target) +{ + lua_getfield(L, index, target); + lua_setfield(L, index, name); +} + +static int compat_socket_unix_call(lua_State *L) +{ + /* Look up socket.unix.stream in the socket.unix table (which is the first + * argument). */ + lua_getfield(L, 1, "stream"); + + /* Replace the stack entry for the socket.unix table with the + * socket.unix.stream function. */ + lua_replace(L, 1); + + /* Call socket.unix.stream, passing along any arguments. */ + int n = lua_gettop(L); + lua_call(L, n-1, LUA_MULTRET); + + /* Pass along the return values from socket.unix.stream. */ + n = lua_gettop(L); + return n; +} + +/*-------------------------------------------------------------------------*\ +* Initializes module +\*-------------------------------------------------------------------------*/ +LUASOCKET_API int luaopen_socket_unix(lua_State *L) +{ + int i; + lua_newtable(L); + int socket_unix_table = lua_gettop(L); + + for (i = 0; mod[i].name; i++) + mod[i].func(L); + + /* Add backwards compatibility aliases "tcp" and "udp" for the "stream" and + * "dgram" functions. */ + add_alias(L, socket_unix_table, "tcp", "stream"); + add_alias(L, socket_unix_table, "udp", "dgram"); + + /* Add a backwards compatibility function and a metatable setup to call it + * for the old socket.unix() interface. */ + lua_pushcfunction(L, compat_socket_unix_call); + lua_setfield(L, socket_unix_table, "__call"); + lua_pushvalue(L, socket_unix_table); + lua_setmetatable(L, socket_unix_table); + + return 1; +} diff --git a/src/3rd party/lua-extensions/luasocket/unix.h b/src/3rd party/lua-extensions/luasocket/unix.h new file mode 100644 index 000000000..c20356189 --- /dev/null +++ b/src/3rd party/lua-extensions/luasocket/unix.h @@ -0,0 +1,26 @@ +#ifndef UNIX_H +#define UNIX_H +/*=========================================================================*\ +* Unix domain object +* LuaSocket toolkit +* +* This module is just an example of how to extend LuaSocket with a new +* domain. +\*=========================================================================*/ +#include "luasocket.h" + +#include "buffer.h" +#include "timeout.h" +#include "socket.h" + +typedef struct t_unix_ { + t_socket sock; + t_io io; + t_buffer buf; + t_timeout tm; +} t_unix; +typedef t_unix *p_unix; + +LUASOCKET_API int luaopen_socket_unix(lua_State *L); + +#endif /* UNIX_H */ diff --git a/src/3rd party/lua-extensions/luasocket/unixdgram.c b/src/3rd party/lua-extensions/luasocket/unixdgram.c new file mode 100644 index 000000000..69093d734 --- /dev/null +++ b/src/3rd party/lua-extensions/luasocket/unixdgram.c @@ -0,0 +1,405 @@ +/*=========================================================================*\ +* Unix domain socket dgram submodule +* LuaSocket toolkit +\*=========================================================================*/ +#include "luasocket.h" + +#include "auxiliar.h" +#include "socket.h" +#include "options.h" +#include "unix.h" + +#include +#include + +#include + +#define UNIXDGRAM_DATAGRAMSIZE 8192 + +/* provide a SUN_LEN macro if sys/un.h doesn't (e.g. Android) */ +#ifndef SUN_LEN +#define SUN_LEN(ptr) \ + ((size_t) (((struct sockaddr_un *) 0)->sun_path) \ + + strlen ((ptr)->sun_path)) +#endif + +/*=========================================================================*\ +* Internal function prototypes +\*=========================================================================*/ +static int global_create(lua_State *L); +static int meth_connect(lua_State *L); +static int meth_bind(lua_State *L); +static int meth_send(lua_State *L); +static int meth_receive(lua_State *L); +static int meth_close(lua_State *L); +static int meth_setoption(lua_State *L); +static int meth_settimeout(lua_State *L); +static int meth_gettimeout(lua_State *L); +static int meth_getfd(lua_State *L); +static int meth_setfd(lua_State *L); +static int meth_dirty(lua_State *L); +static int meth_receivefrom(lua_State *L); +static int meth_sendto(lua_State *L); +static int meth_getsockname(lua_State *L); + +static const char *unixdgram_tryconnect(p_unix un, const char *path); +static const char *unixdgram_trybind(p_unix un, const char *path); + +/* unixdgram object methods */ +static luaL_Reg unixdgram_methods[] = { + {"__gc", meth_close}, + {"__tostring", auxiliar_tostring}, + {"bind", meth_bind}, + {"close", meth_close}, + {"connect", meth_connect}, + {"dirty", meth_dirty}, + {"getfd", meth_getfd}, + {"send", meth_send}, + {"sendto", meth_sendto}, + {"receive", meth_receive}, + {"receivefrom", meth_receivefrom}, + {"setfd", meth_setfd}, + {"setoption", meth_setoption}, + {"setpeername", meth_connect}, + {"setsockname", meth_bind}, + {"getsockname", meth_getsockname}, + {"settimeout", meth_settimeout}, + {"gettimeout", meth_gettimeout}, + {NULL, NULL} +}; + +/* socket option handlers */ +static t_opt optset[] = { + {"reuseaddr", opt_set_reuseaddr}, + {NULL, NULL} +}; + +/* functions in library namespace */ +static luaL_Reg func[] = { + {"dgram", global_create}, + {NULL, NULL} +}; + +/*-------------------------------------------------------------------------*\ +* Initializes module +\*-------------------------------------------------------------------------*/ +int unixdgram_open(lua_State *L) +{ + /* create classes */ + auxiliar_newclass(L, "unixdgram{connected}", unixdgram_methods); + auxiliar_newclass(L, "unixdgram{unconnected}", unixdgram_methods); + /* create class groups */ + auxiliar_add2group(L, "unixdgram{connected}", "unixdgram{any}"); + auxiliar_add2group(L, "unixdgram{unconnected}", "unixdgram{any}"); + auxiliar_add2group(L, "unixdgram{connected}", "select{able}"); + auxiliar_add2group(L, "unixdgram{unconnected}", "select{able}"); + + luaL_setfuncs(L, func, 0); + return 0; +} + +/*=========================================================================*\ +* Lua methods +\*=========================================================================*/ +static const char *unixdgram_strerror(int err) +{ + /* a 'closed' error on an unconnected means the target address was not + * accepted by the transport layer */ + if (err == IO_CLOSED) return "refused"; + else return socket_strerror(err); +} + +static int meth_send(lua_State *L) +{ + p_unix un = (p_unix) auxiliar_checkclass(L, "unixdgram{connected}", 1); + p_timeout tm = &un->tm; + size_t count, sent = 0; + int err; + const char *data = luaL_checklstring(L, 2, &count); + timeout_markstart(tm); + err = socket_send(&un->sock, data, count, &sent, tm); + if (err != IO_DONE) { + lua_pushnil(L); + lua_pushstring(L, unixdgram_strerror(err)); + return 2; + } + lua_pushnumber(L, (lua_Number) sent); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Send data through unconnected unixdgram socket +\*-------------------------------------------------------------------------*/ +static int meth_sendto(lua_State *L) +{ + p_unix un = (p_unix) auxiliar_checkclass(L, "unixdgram{unconnected}", 1); + size_t count, sent = 0; + const char *data = luaL_checklstring(L, 2, &count); + const char *path = luaL_checkstring(L, 3); + p_timeout tm = &un->tm; + int err; + struct sockaddr_un remote; + size_t len = strlen(path); + + if (len >= sizeof(remote.sun_path)) { + lua_pushnil(L); + lua_pushstring(L, "path too long"); + return 2; + } + + memset(&remote, 0, sizeof(remote)); + strcpy(remote.sun_path, path); + remote.sun_family = AF_UNIX; + timeout_markstart(tm); +#ifdef UNIX_HAS_SUN_LEN + remote.sun_len = sizeof(remote.sun_family) + sizeof(remote.sun_len) + + len + 1; + err = socket_sendto(&un->sock, data, count, &sent, (SA *) &remote, remote.sun_len, tm); +#else + err = socket_sendto(&un->sock, data, count, &sent, (SA *) &remote, + sizeof(remote.sun_family) + len, tm); +#endif + if (err != IO_DONE) { + lua_pushnil(L); + lua_pushstring(L, unixdgram_strerror(err)); + return 2; + } + lua_pushnumber(L, (lua_Number) sent); + return 1; +} + +static int meth_receive(lua_State *L) { + p_unix un = (p_unix) auxiliar_checkgroup(L, "unixdgram{any}", 1); + char buf[UNIXDGRAM_DATAGRAMSIZE]; + size_t got, wanted = (size_t) luaL_optnumber(L, 2, sizeof(buf)); + char *dgram = wanted > sizeof(buf)? (char *) malloc(wanted): buf; + int err; + p_timeout tm = &un->tm; + timeout_markstart(tm); + if (!dgram) { + lua_pushnil(L); + lua_pushliteral(L, "out of memory"); + return 2; + } + err = socket_recv(&un->sock, dgram, wanted, &got, tm); + /* Unlike STREAM, recv() of zero is not closed, but a zero-length packet. */ + if (err != IO_DONE && err != IO_CLOSED) { + lua_pushnil(L); + lua_pushstring(L, unixdgram_strerror(err)); + if (wanted > sizeof(buf)) free(dgram); + return 2; + } + lua_pushlstring(L, dgram, got); + if (wanted > sizeof(buf)) free(dgram); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Receives data and sender from a DGRAM socket +\*-------------------------------------------------------------------------*/ +static int meth_receivefrom(lua_State *L) { + p_unix un = (p_unix) auxiliar_checkclass(L, "unixdgram{unconnected}", 1); + char buf[UNIXDGRAM_DATAGRAMSIZE]; + size_t got, wanted = (size_t) luaL_optnumber(L, 2, sizeof(buf)); + char *dgram = wanted > sizeof(buf)? (char *) malloc(wanted): buf; + struct sockaddr_un addr; + socklen_t addr_len = sizeof(addr); + int err; + p_timeout tm = &un->tm; + timeout_markstart(tm); + if (!dgram) { + lua_pushnil(L); + lua_pushliteral(L, "out of memory"); + return 2; + } + addr.sun_path[0] = '\0'; + err = socket_recvfrom(&un->sock, dgram, wanted, &got, (SA *) &addr, + &addr_len, tm); + /* Unlike STREAM, recv() of zero is not closed, but a zero-length packet. */ + if (err != IO_DONE && err != IO_CLOSED) { + lua_pushnil(L); + lua_pushstring(L, unixdgram_strerror(err)); + if (wanted > sizeof(buf)) free(dgram); + return 2; + } + + lua_pushlstring(L, dgram, got); + /* the path may be empty, when client send without bind */ + lua_pushstring(L, addr.sun_path); + if (wanted > sizeof(buf)) free(dgram); + return 2; +} + +/*-------------------------------------------------------------------------*\ +* Just call option handler +\*-------------------------------------------------------------------------*/ +static int meth_setoption(lua_State *L) { + p_unix un = (p_unix) auxiliar_checkgroup(L, "unixdgram{any}", 1); + return opt_meth_setoption(L, optset, &un->sock); +} + +/*-------------------------------------------------------------------------*\ +* Select support methods +\*-------------------------------------------------------------------------*/ +static int meth_getfd(lua_State *L) { + p_unix un = (p_unix) auxiliar_checkgroup(L, "unixdgram{any}", 1); + lua_pushnumber(L, (int) un->sock); + return 1; +} + +/* this is very dangerous, but can be handy for those that are brave enough */ +static int meth_setfd(lua_State *L) { + p_unix un = (p_unix) auxiliar_checkgroup(L, "unixdgram{any}", 1); + un->sock = (t_socket) luaL_checknumber(L, 2); + return 0; +} + +static int meth_dirty(lua_State *L) { + p_unix un = (p_unix) auxiliar_checkgroup(L, "unixdgram{any}", 1); + (void) un; + lua_pushboolean(L, 0); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Binds an object to an address +\*-------------------------------------------------------------------------*/ +static const char *unixdgram_trybind(p_unix un, const char *path) { + struct sockaddr_un local; + size_t len = strlen(path); + if (len >= sizeof(local.sun_path)) return "path too long"; + memset(&local, 0, sizeof(local)); + strcpy(local.sun_path, path); + local.sun_family = AF_UNIX; + size_t addrlen = SUN_LEN(&local); +#ifdef UNIX_HAS_SUN_LEN + local.sun_len = addrlen + 1; +#endif + int err = socket_bind(&un->sock, (SA *) &local, addrlen); + if (err != IO_DONE) socket_destroy(&un->sock); + return socket_strerror(err); +} + +static int meth_bind(lua_State *L) +{ + p_unix un = (p_unix) auxiliar_checkclass(L, "unixdgram{unconnected}", 1); + const char *path = luaL_checkstring(L, 2); + const char *err = unixdgram_trybind(un, path); + if (err) { + lua_pushnil(L); + lua_pushstring(L, err); + return 2; + } + lua_pushnumber(L, 1); + return 1; +} + +static int meth_getsockname(lua_State *L) +{ + p_unix un = (p_unix) auxiliar_checkgroup(L, "unixdgram{any}", 1); + struct sockaddr_un peer = {0}; + socklen_t peer_len = sizeof(peer); + + if (getsockname(un->sock, (SA *) &peer, &peer_len) < 0) { + lua_pushnil(L); + lua_pushstring(L, socket_strerror(errno)); + return 2; + } + + lua_pushstring(L, peer.sun_path); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Turns a master unixdgram object into a client object. +\*-------------------------------------------------------------------------*/ +static const char *unixdgram_tryconnect(p_unix un, const char *path) +{ + struct sockaddr_un remote; + size_t len = strlen(path); + if (len >= sizeof(remote.sun_path)) return "path too long"; + memset(&remote, 0, sizeof(remote)); + strcpy(remote.sun_path, path); + remote.sun_family = AF_UNIX; + timeout_markstart(&un->tm); + size_t addrlen = SUN_LEN(&remote); +#ifdef UNIX_HAS_SUN_LEN + remote.sun_len = addrlen + 1; +#endif + int err = socket_connect(&un->sock, (SA *) &remote, addrlen, &un->tm); + if (err != IO_DONE) socket_destroy(&un->sock); + return socket_strerror(err); +} + +static int meth_connect(lua_State *L) +{ + p_unix un = (p_unix) auxiliar_checkgroup(L, "unixdgram{any}", 1); + const char *path = luaL_checkstring(L, 2); + const char *err = unixdgram_tryconnect(un, path); + if (err) { + lua_pushnil(L); + lua_pushstring(L, err); + return 2; + } + /* turn unconnected object into a connected object */ + auxiliar_setclass(L, "unixdgram{connected}", 1); + lua_pushnumber(L, 1); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Closes socket used by object +\*-------------------------------------------------------------------------*/ +static int meth_close(lua_State *L) +{ + p_unix un = (p_unix) auxiliar_checkgroup(L, "unixdgram{any}", 1); + socket_destroy(&un->sock); + lua_pushnumber(L, 1); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Just call tm methods +\*-------------------------------------------------------------------------*/ +static int meth_settimeout(lua_State *L) +{ + p_unix un = (p_unix) auxiliar_checkgroup(L, "unixdgram{any}", 1); + return timeout_meth_settimeout(L, &un->tm); +} + +static int meth_gettimeout(lua_State *L) +{ + p_unix un = (p_unix) auxiliar_checkgroup(L, "unixdgram{any}", 1); + return timeout_meth_gettimeout(L, &un->tm); +} + +/*=========================================================================*\ +* Library functions +\*=========================================================================*/ +/*-------------------------------------------------------------------------*\ +* Creates a master unixdgram object +\*-------------------------------------------------------------------------*/ +static int global_create(lua_State *L) +{ + t_socket sock; + int err = socket_create(&sock, AF_UNIX, SOCK_DGRAM, 0); + /* try to allocate a system socket */ + if (err == IO_DONE) { + /* allocate unixdgram object */ + p_unix un = (p_unix) lua_newuserdata(L, sizeof(t_unix)); + /* set its type as master object */ + auxiliar_setclass(L, "unixdgram{unconnected}", -1); + /* initialize remaining structure fields */ + socket_setnonblocking(&sock); + un->sock = sock; + io_init(&un->io, (p_send) socket_send, (p_recv) socket_recv, + (p_error) socket_ioerror, &un->sock); + timeout_init(&un->tm, -1, -1); + buffer_init(&un->buf, &un->io, &un->tm); + return 1; + } else { + lua_pushnil(L); + lua_pushstring(L, socket_strerror(err)); + return 2; + } +} diff --git a/src/3rd party/lua-extensions/luasocket/unixdgram.h b/src/3rd party/lua-extensions/luasocket/unixdgram.h new file mode 100644 index 000000000..a1a0166bd --- /dev/null +++ b/src/3rd party/lua-extensions/luasocket/unixdgram.h @@ -0,0 +1,28 @@ +#ifndef UNIXDGRAM_H +#define UNIXDGRAM_H +/*=========================================================================*\ +* DGRAM object +* LuaSocket toolkit +* +* The dgram.h module provides LuaSocket with support for DGRAM protocol +* (AF_INET, SOCK_DGRAM). +* +* Two classes are defined: connected and unconnected. DGRAM objects are +* originally unconnected. They can be "connected" to a given address +* with a call to the setpeername function. The same function can be used to +* break the connection. +\*=========================================================================*/ + +#include "unix.h" + +#ifndef _WIN32 +#pragma GCC visibility push(hidden) +#endif + +int unixdgram_open(lua_State *L); + +#ifndef _WIN32 +#pragma GCC visibility pop +#endif + +#endif /* UNIXDGRAM_H */ diff --git a/src/3rd party/lua-extensions/luasocket/unixstream.c b/src/3rd party/lua-extensions/luasocket/unixstream.c new file mode 100644 index 000000000..02aced9c8 --- /dev/null +++ b/src/3rd party/lua-extensions/luasocket/unixstream.c @@ -0,0 +1,355 @@ +/*=========================================================================*\ +* Unix domain socket stream sub module +* LuaSocket toolkit +\*=========================================================================*/ +#include "luasocket.h" + +#include "auxiliar.h" +#include "socket.h" +#include "options.h" +#include "unixstream.h" + +#include +#include + +/*=========================================================================*\ +* Internal function prototypes +\*=========================================================================*/ +static int global_create(lua_State *L); +static int meth_connect(lua_State *L); +static int meth_listen(lua_State *L); +static int meth_bind(lua_State *L); +static int meth_send(lua_State *L); +static int meth_shutdown(lua_State *L); +static int meth_receive(lua_State *L); +static int meth_accept(lua_State *L); +static int meth_close(lua_State *L); +static int meth_setoption(lua_State *L); +static int meth_settimeout(lua_State *L); +static int meth_getfd(lua_State *L); +static int meth_setfd(lua_State *L); +static int meth_dirty(lua_State *L); +static int meth_getstats(lua_State *L); +static int meth_setstats(lua_State *L); +static int meth_getsockname(lua_State *L); + +static const char *unixstream_tryconnect(p_unix un, const char *path); +static const char *unixstream_trybind(p_unix un, const char *path); + +/* unixstream object methods */ +static luaL_Reg unixstream_methods[] = { + {"__gc", meth_close}, + {"__tostring", auxiliar_tostring}, + {"accept", meth_accept}, + {"bind", meth_bind}, + {"close", meth_close}, + {"connect", meth_connect}, + {"dirty", meth_dirty}, + {"getfd", meth_getfd}, + {"getstats", meth_getstats}, + {"setstats", meth_setstats}, + {"listen", meth_listen}, + {"receive", meth_receive}, + {"send", meth_send}, + {"setfd", meth_setfd}, + {"setoption", meth_setoption}, + {"setpeername", meth_connect}, + {"setsockname", meth_bind}, + {"getsockname", meth_getsockname}, + {"settimeout", meth_settimeout}, + {"shutdown", meth_shutdown}, + {NULL, NULL} +}; + +/* socket option handlers */ +static t_opt optset[] = { + {"keepalive", opt_set_keepalive}, + {"reuseaddr", opt_set_reuseaddr}, + {"linger", opt_set_linger}, + {NULL, NULL} +}; + +/* functions in library namespace */ +static luaL_Reg func[] = { + {"stream", global_create}, + {NULL, NULL} +}; + +/*-------------------------------------------------------------------------*\ +* Initializes module +\*-------------------------------------------------------------------------*/ +int unixstream_open(lua_State *L) +{ + /* create classes */ + auxiliar_newclass(L, "unixstream{master}", unixstream_methods); + auxiliar_newclass(L, "unixstream{client}", unixstream_methods); + auxiliar_newclass(L, "unixstream{server}", unixstream_methods); + + /* create class groups */ + auxiliar_add2group(L, "unixstream{master}", "unixstream{any}"); + auxiliar_add2group(L, "unixstream{client}", "unixstream{any}"); + auxiliar_add2group(L, "unixstream{server}", "unixstream{any}"); + + luaL_setfuncs(L, func, 0); + return 0; +} + +/*=========================================================================*\ +* Lua methods +\*=========================================================================*/ +/*-------------------------------------------------------------------------*\ +* Just call buffered IO methods +\*-------------------------------------------------------------------------*/ +static int meth_send(lua_State *L) { + p_unix un = (p_unix) auxiliar_checkclass(L, "unixstream{client}", 1); + return buffer_meth_send(L, &un->buf); +} + +static int meth_receive(lua_State *L) { + p_unix un = (p_unix) auxiliar_checkclass(L, "unixstream{client}", 1); + return buffer_meth_receive(L, &un->buf); +} + +static int meth_getstats(lua_State *L) { + p_unix un = (p_unix) auxiliar_checkclass(L, "unixstream{client}", 1); + return buffer_meth_getstats(L, &un->buf); +} + +static int meth_setstats(lua_State *L) { + p_unix un = (p_unix) auxiliar_checkclass(L, "unixstream{client}", 1); + return buffer_meth_setstats(L, &un->buf); +} + +/*-------------------------------------------------------------------------*\ +* Just call option handler +\*-------------------------------------------------------------------------*/ +static int meth_setoption(lua_State *L) { + p_unix un = (p_unix) auxiliar_checkgroup(L, "unixstream{any}", 1); + return opt_meth_setoption(L, optset, &un->sock); +} + +/*-------------------------------------------------------------------------*\ +* Select support methods +\*-------------------------------------------------------------------------*/ +static int meth_getfd(lua_State *L) { + p_unix un = (p_unix) auxiliar_checkgroup(L, "unixstream{any}", 1); + lua_pushnumber(L, (int) un->sock); + return 1; +} + +/* this is very dangerous, but can be handy for those that are brave enough */ +static int meth_setfd(lua_State *L) { + p_unix un = (p_unix) auxiliar_checkgroup(L, "unixstream{any}", 1); + un->sock = (t_socket) luaL_checknumber(L, 2); + return 0; +} + +static int meth_dirty(lua_State *L) { + p_unix un = (p_unix) auxiliar_checkgroup(L, "unixstream{any}", 1); + lua_pushboolean(L, !buffer_isempty(&un->buf)); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Waits for and returns a client object attempting connection to the +* server object +\*-------------------------------------------------------------------------*/ +static int meth_accept(lua_State *L) { + p_unix server = (p_unix) auxiliar_checkclass(L, "unixstream{server}", 1); + p_timeout tm = timeout_markstart(&server->tm); + t_socket sock; + int err = socket_accept(&server->sock, &sock, NULL, NULL, tm); + /* if successful, push client socket */ + if (err == IO_DONE) { + p_unix clnt = (p_unix) lua_newuserdata(L, sizeof(t_unix)); + auxiliar_setclass(L, "unixstream{client}", -1); + /* initialize structure fields */ + socket_setnonblocking(&sock); + clnt->sock = sock; + io_init(&clnt->io, (p_send)socket_send, (p_recv)socket_recv, + (p_error) socket_ioerror, &clnt->sock); + timeout_init(&clnt->tm, -1, -1); + buffer_init(&clnt->buf, &clnt->io, &clnt->tm); + return 1; + } else { + lua_pushnil(L); + lua_pushstring(L, socket_strerror(err)); + return 2; + } +} + +/*-------------------------------------------------------------------------*\ +* Binds an object to an address +\*-------------------------------------------------------------------------*/ +static const char *unixstream_trybind(p_unix un, const char *path) { + struct sockaddr_un local; + size_t len = strlen(path); + int err; + if (len >= sizeof(local.sun_path)) return "path too long"; + memset(&local, 0, sizeof(local)); + strcpy(local.sun_path, path); + local.sun_family = AF_UNIX; +#ifdef UNIX_HAS_SUN_LEN + local.sun_len = sizeof(local.sun_family) + sizeof(local.sun_len) + + len + 1; + err = socket_bind(&un->sock, (SA *) &local, local.sun_len); + +#else + err = socket_bind(&un->sock, (SA *) &local, + sizeof(local.sun_family) + len); +#endif + if (err != IO_DONE) socket_destroy(&un->sock); + return socket_strerror(err); +} + +static int meth_bind(lua_State *L) { + p_unix un = (p_unix) auxiliar_checkclass(L, "unixstream{master}", 1); + const char *path = luaL_checkstring(L, 2); + const char *err = unixstream_trybind(un, path); + if (err) { + lua_pushnil(L); + lua_pushstring(L, err); + return 2; + } + lua_pushnumber(L, 1); + return 1; +} + +static int meth_getsockname(lua_State *L) +{ + p_unix un = (p_unix) auxiliar_checkgroup(L, "unixstream{any}", 1); + struct sockaddr_un peer = {0}; + socklen_t peer_len = sizeof(peer); + + if (getsockname(un->sock, (SA *) &peer, &peer_len) < 0) { + lua_pushnil(L); + lua_pushstring(L, socket_strerror(errno)); + return 2; + } + + lua_pushstring(L, peer.sun_path); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Turns a master unixstream object into a client object. +\*-------------------------------------------------------------------------*/ +static const char *unixstream_tryconnect(p_unix un, const char *path) +{ + struct sockaddr_un remote; + int err; + size_t len = strlen(path); + if (len >= sizeof(remote.sun_path)) return "path too long"; + memset(&remote, 0, sizeof(remote)); + strcpy(remote.sun_path, path); + remote.sun_family = AF_UNIX; + timeout_markstart(&un->tm); +#ifdef UNIX_HAS_SUN_LEN + remote.sun_len = sizeof(remote.sun_family) + sizeof(remote.sun_len) + + len + 1; + err = socket_connect(&un->sock, (SA *) &remote, remote.sun_len, &un->tm); +#else + err = socket_connect(&un->sock, (SA *) &remote, + sizeof(remote.sun_family) + len, &un->tm); +#endif + if (err != IO_DONE) socket_destroy(&un->sock); + return socket_strerror(err); +} + +static int meth_connect(lua_State *L) +{ + p_unix un = (p_unix) auxiliar_checkclass(L, "unixstream{master}", 1); + const char *path = luaL_checkstring(L, 2); + const char *err = unixstream_tryconnect(un, path); + if (err) { + lua_pushnil(L); + lua_pushstring(L, err); + return 2; + } + /* turn master object into a client object */ + auxiliar_setclass(L, "unixstream{client}", 1); + lua_pushnumber(L, 1); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Closes socket used by object +\*-------------------------------------------------------------------------*/ +static int meth_close(lua_State *L) +{ + p_unix un = (p_unix) auxiliar_checkgroup(L, "unixstream{any}", 1); + socket_destroy(&un->sock); + lua_pushnumber(L, 1); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Puts the sockt in listen mode +\*-------------------------------------------------------------------------*/ +static int meth_listen(lua_State *L) +{ + p_unix un = (p_unix) auxiliar_checkclass(L, "unixstream{master}", 1); + int backlog = (int) luaL_optnumber(L, 2, 32); + int err = socket_listen(&un->sock, backlog); + if (err != IO_DONE) { + lua_pushnil(L); + lua_pushstring(L, socket_strerror(err)); + return 2; + } + /* turn master object into a server object */ + auxiliar_setclass(L, "unixstream{server}", 1); + lua_pushnumber(L, 1); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Shuts the connection down partially +\*-------------------------------------------------------------------------*/ +static int meth_shutdown(lua_State *L) +{ + /* SHUT_RD, SHUT_WR, SHUT_RDWR have the value 0, 1, 2, so we can use method index directly */ + static const char* methods[] = { "receive", "send", "both", NULL }; + p_unix stream = (p_unix) auxiliar_checkclass(L, "unixstream{client}", 1); + int how = luaL_checkoption(L, 2, "both", methods); + socket_shutdown(&stream->sock, how); + lua_pushnumber(L, 1); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Just call tm methods +\*-------------------------------------------------------------------------*/ +static int meth_settimeout(lua_State *L) { + p_unix un = (p_unix) auxiliar_checkgroup(L, "unixstream{any}", 1); + return timeout_meth_settimeout(L, &un->tm); +} + +/*=========================================================================*\ +* Library functions +\*=========================================================================*/ +/*-------------------------------------------------------------------------*\ +* Creates a master unixstream object +\*-------------------------------------------------------------------------*/ +static int global_create(lua_State *L) { + t_socket sock; + int err = socket_create(&sock, AF_UNIX, SOCK_STREAM, 0); + /* try to allocate a system socket */ + if (err == IO_DONE) { + /* allocate unixstream object */ + p_unix un = (p_unix) lua_newuserdata(L, sizeof(t_unix)); + /* set its type as master object */ + auxiliar_setclass(L, "unixstream{master}", -1); + /* initialize remaining structure fields */ + socket_setnonblocking(&sock); + un->sock = sock; + io_init(&un->io, (p_send) socket_send, (p_recv) socket_recv, + (p_error) socket_ioerror, &un->sock); + timeout_init(&un->tm, -1, -1); + buffer_init(&un->buf, &un->io, &un->tm); + return 1; + } else { + lua_pushnil(L); + lua_pushstring(L, socket_strerror(err)); + return 2; + } +} diff --git a/src/3rd party/lua-extensions/luasocket/unixstream.h b/src/3rd party/lua-extensions/luasocket/unixstream.h new file mode 100644 index 000000000..7916affa7 --- /dev/null +++ b/src/3rd party/lua-extensions/luasocket/unixstream.h @@ -0,0 +1,29 @@ +#ifndef UNIXSTREAM_H +#define UNIXSTREAM_H +/*=========================================================================*\ +* UNIX STREAM object +* LuaSocket toolkit +* +* The unixstream.h module is basicly a glue that puts together modules buffer.h, +* timeout.h socket.h and inet.h to provide the LuaSocket UNIX STREAM (AF_UNIX, +* SOCK_STREAM) support. +* +* Three classes are defined: master, client and server. The master class is +* a newly created unixstream object, that has not been bound or connected. Server +* objects are unixstream objects bound to some local address. Client objects are +* unixstream objects either connected to some address or returned by the accept +* method of a server object. +\*=========================================================================*/ +#include "unix.h" + +#ifndef _WIN32 +#pragma GCC visibility push(hidden) +#endif + +int unixstream_open(lua_State *L); + +#ifndef _WIN32 +#pragma GCC visibility pop +#endif + +#endif /* UNIXSTREAM_H */ diff --git a/src/3rd party/lua-extensions/luasocket/usocket.c b/src/3rd party/lua-extensions/luasocket/usocket.c new file mode 100644 index 000000000..7965db6c4 --- /dev/null +++ b/src/3rd party/lua-extensions/luasocket/usocket.c @@ -0,0 +1,454 @@ +/*=========================================================================*\ +* Socket compatibilization module for Unix +* LuaSocket toolkit +* +* The code is now interrupt-safe. +* The penalty of calling select to avoid busy-wait is only paid when +* the I/O call fail in the first place. +\*=========================================================================*/ +#include "luasocket.h" + +#include "socket.h" +#include "pierror.h" + +#include +#include + +/*-------------------------------------------------------------------------*\ +* Wait for readable/writable/connected socket with timeout +\*-------------------------------------------------------------------------*/ +#ifndef SOCKET_SELECT +#include + +#define WAITFD_R POLLIN +#define WAITFD_W POLLOUT +#define WAITFD_C (POLLIN|POLLOUT) +int socket_waitfd(p_socket ps, int sw, p_timeout tm) { + int ret; + struct pollfd pfd; + pfd.fd = *ps; + pfd.events = sw; + pfd.revents = 0; + if (timeout_iszero(tm)) return IO_TIMEOUT; /* optimize timeout == 0 case */ + do { + int t = (int)(timeout_getretry(tm)*1e3); + ret = poll(&pfd, 1, t >= 0? t: -1); + } while (ret == -1 && errno == EINTR); + if (ret == -1) return errno; + if (ret == 0) return IO_TIMEOUT; + if (sw == WAITFD_C && (pfd.revents & (POLLIN|POLLERR))) return IO_CLOSED; + return IO_DONE; +} +#else + +#define WAITFD_R 1 +#define WAITFD_W 2 +#define WAITFD_C (WAITFD_R|WAITFD_W) + +int socket_waitfd(p_socket ps, int sw, p_timeout tm) { + int ret; + fd_set rfds, wfds, *rp, *wp; + struct timeval tv, *tp; + double t; + if (*ps >= FD_SETSIZE) return EINVAL; + if (timeout_iszero(tm)) return IO_TIMEOUT; /* optimize timeout == 0 case */ + do { + /* must set bits within loop, because select may have modifed them */ + rp = wp = NULL; + if (sw & WAITFD_R) { FD_ZERO(&rfds); FD_SET(*ps, &rfds); rp = &rfds; } + if (sw & WAITFD_W) { FD_ZERO(&wfds); FD_SET(*ps, &wfds); wp = &wfds; } + t = timeout_getretry(tm); + tp = NULL; + if (t >= 0.0) { + tv.tv_sec = (int)t; + tv.tv_usec = (int)((t-tv.tv_sec)*1.0e6); + tp = &tv; + } + ret = select(*ps+1, rp, wp, NULL, tp); + } while (ret == -1 && errno == EINTR); + if (ret == -1) return errno; + if (ret == 0) return IO_TIMEOUT; + if (sw == WAITFD_C && FD_ISSET(*ps, &rfds)) return IO_CLOSED; + return IO_DONE; +} +#endif + + +/*-------------------------------------------------------------------------*\ +* Initializes module +\*-------------------------------------------------------------------------*/ +int socket_open(void) { + /* installs a handler to ignore sigpipe or it will crash us */ + signal(SIGPIPE, SIG_IGN); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Close module +\*-------------------------------------------------------------------------*/ +int socket_close(void) { + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Close and inutilize socket +\*-------------------------------------------------------------------------*/ +void socket_destroy(p_socket ps) { + if (*ps != SOCKET_INVALID) { + close(*ps); + *ps = SOCKET_INVALID; + } +} + +/*-------------------------------------------------------------------------*\ +* Select with timeout control +\*-------------------------------------------------------------------------*/ +int socket_select(t_socket n, fd_set *rfds, fd_set *wfds, fd_set *efds, + p_timeout tm) { + int ret; + do { + struct timeval tv; + double t = timeout_getretry(tm); + tv.tv_sec = (int) t; + tv.tv_usec = (int) ((t - tv.tv_sec) * 1.0e6); + /* timeout = 0 means no wait */ + ret = select(n, rfds, wfds, efds, t >= 0.0 ? &tv: NULL); + } while (ret < 0 && errno == EINTR); + return ret; +} + +/*-------------------------------------------------------------------------*\ +* Creates and sets up a socket +\*-------------------------------------------------------------------------*/ +int socket_create(p_socket ps, int domain, int type, int protocol) { + *ps = socket(domain, type, protocol); + if (*ps != SOCKET_INVALID) return IO_DONE; + else return errno; +} + +/*-------------------------------------------------------------------------*\ +* Binds or returns error message +\*-------------------------------------------------------------------------*/ +int socket_bind(p_socket ps, SA *addr, socklen_t len) { + int err = IO_DONE; + socket_setblocking(ps); + if (bind(*ps, addr, len) < 0) err = errno; + socket_setnonblocking(ps); + return err; +} + +/*-------------------------------------------------------------------------*\ +* +\*-------------------------------------------------------------------------*/ +int socket_listen(p_socket ps, int backlog) { + int err = IO_DONE; + if (listen(*ps, backlog)) err = errno; + return err; +} + +/*-------------------------------------------------------------------------*\ +* +\*-------------------------------------------------------------------------*/ +void socket_shutdown(p_socket ps, int how) { + shutdown(*ps, how); +} + +/*-------------------------------------------------------------------------*\ +* Connects or returns error message +\*-------------------------------------------------------------------------*/ +int socket_connect(p_socket ps, SA *addr, socklen_t len, p_timeout tm) { + int err; + /* avoid calling on closed sockets */ + if (*ps == SOCKET_INVALID) return IO_CLOSED; + /* call connect until done or failed without being interrupted */ + do if (connect(*ps, addr, len) == 0) return IO_DONE; + while ((err = errno) == EINTR); + /* if connection failed immediately, return error code */ + if (err != EINPROGRESS && err != EAGAIN) return err; + /* zero timeout case optimization */ + if (timeout_iszero(tm)) return IO_TIMEOUT; + /* wait until we have the result of the connection attempt or timeout */ + err = socket_waitfd(ps, WAITFD_C, tm); + if (err == IO_CLOSED) { + if (recv(*ps, (char *) &err, 0, 0) == 0) return IO_DONE; + else return errno; + } else return err; +} + +/*-------------------------------------------------------------------------*\ +* Accept with timeout +\*-------------------------------------------------------------------------*/ +int socket_accept(p_socket ps, p_socket pa, SA *addr, socklen_t *len, p_timeout tm) { + if (*ps == SOCKET_INVALID) return IO_CLOSED; + for ( ;; ) { + int err; + if ((*pa = accept(*ps, addr, len)) != SOCKET_INVALID) return IO_DONE; + err = errno; + if (err == EINTR) continue; + if (err != EAGAIN && err != ECONNABORTED) return err; + if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err; + } + /* can't reach here */ + return IO_UNKNOWN; +} + +/*-------------------------------------------------------------------------*\ +* Send with timeout +\*-------------------------------------------------------------------------*/ +int socket_send(p_socket ps, const char *data, size_t count, + size_t *sent, p_timeout tm) +{ + int err; + *sent = 0; + /* avoid making system calls on closed sockets */ + if (*ps == SOCKET_INVALID) return IO_CLOSED; + /* loop until we send something or we give up on error */ + for ( ;; ) { + long put = (long) send(*ps, data, count, 0); + /* if we sent anything, we are done */ + if (put >= 0) { + *sent = put; + return IO_DONE; + } + err = errno; + /* EPIPE means the connection was closed */ + if (err == EPIPE) return IO_CLOSED; + /* EPROTOTYPE means the connection is being closed (on Yosemite!)*/ + if (err == EPROTOTYPE) continue; + /* we call was interrupted, just try again */ + if (err == EINTR) continue; + /* if failed fatal reason, report error */ + if (err != EAGAIN) return err; + /* wait until we can send something or we timeout */ + if ((err = socket_waitfd(ps, WAITFD_W, tm)) != IO_DONE) return err; + } + /* can't reach here */ + return IO_UNKNOWN; +} + +/*-------------------------------------------------------------------------*\ +* Sendto with timeout +\*-------------------------------------------------------------------------*/ +int socket_sendto(p_socket ps, const char *data, size_t count, size_t *sent, + SA *addr, socklen_t len, p_timeout tm) +{ + int err; + *sent = 0; + if (*ps == SOCKET_INVALID) return IO_CLOSED; + for ( ;; ) { + long put = (long) sendto(*ps, data, count, 0, addr, len); + if (put >= 0) { + *sent = put; + return IO_DONE; + } + err = errno; + if (err == EPIPE) return IO_CLOSED; + if (err == EPROTOTYPE) continue; + if (err == EINTR) continue; + if (err != EAGAIN) return err; + if ((err = socket_waitfd(ps, WAITFD_W, tm)) != IO_DONE) return err; + } + return IO_UNKNOWN; +} + +/*-------------------------------------------------------------------------*\ +* Receive with timeout +\*-------------------------------------------------------------------------*/ +int socket_recv(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm) { + int err; + *got = 0; + if (*ps == SOCKET_INVALID) return IO_CLOSED; + for ( ;; ) { + long taken = (long) recv(*ps, data, count, 0); + if (taken > 0) { + *got = taken; + return IO_DONE; + } + err = errno; + if (taken == 0) return IO_CLOSED; + if (err == EINTR) continue; + if (err != EAGAIN) return err; + if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err; + } + return IO_UNKNOWN; +} + +/*-------------------------------------------------------------------------*\ +* Recvfrom with timeout +\*-------------------------------------------------------------------------*/ +int socket_recvfrom(p_socket ps, char *data, size_t count, size_t *got, + SA *addr, socklen_t *len, p_timeout tm) { + int err; + *got = 0; + if (*ps == SOCKET_INVALID) return IO_CLOSED; + for ( ;; ) { + long taken = (long) recvfrom(*ps, data, count, 0, addr, len); + if (taken > 0) { + *got = taken; + return IO_DONE; + } + err = errno; + if (taken == 0) return IO_CLOSED; + if (err == EINTR) continue; + if (err != EAGAIN) return err; + if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err; + } + return IO_UNKNOWN; +} + + +/*-------------------------------------------------------------------------*\ +* Write with timeout +* +* socket_read and socket_write are cut-n-paste of socket_send and socket_recv, +* with send/recv replaced with write/read. We can't just use write/read +* in the socket version, because behaviour when size is zero is different. +\*-------------------------------------------------------------------------*/ +int socket_write(p_socket ps, const char *data, size_t count, + size_t *sent, p_timeout tm) +{ + int err; + *sent = 0; + /* avoid making system calls on closed sockets */ + if (*ps == SOCKET_INVALID) return IO_CLOSED; + /* loop until we send something or we give up on error */ + for ( ;; ) { + long put = (long) write(*ps, data, count); + /* if we sent anything, we are done */ + if (put >= 0) { + *sent = put; + return IO_DONE; + } + err = errno; + /* EPIPE means the connection was closed */ + if (err == EPIPE) return IO_CLOSED; + /* EPROTOTYPE means the connection is being closed (on Yosemite!)*/ + if (err == EPROTOTYPE) continue; + /* we call was interrupted, just try again */ + if (err == EINTR) continue; + /* if failed fatal reason, report error */ + if (err != EAGAIN) return err; + /* wait until we can send something or we timeout */ + if ((err = socket_waitfd(ps, WAITFD_W, tm)) != IO_DONE) return err; + } + /* can't reach here */ + return IO_UNKNOWN; +} + +/*-------------------------------------------------------------------------*\ +* Read with timeout +* See note for socket_write +\*-------------------------------------------------------------------------*/ +int socket_read(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm) { + int err; + *got = 0; + if (*ps == SOCKET_INVALID) return IO_CLOSED; + for ( ;; ) { + long taken = (long) read(*ps, data, count); + if (taken > 0) { + *got = taken; + return IO_DONE; + } + err = errno; + if (taken == 0) return IO_CLOSED; + if (err == EINTR) continue; + if (err != EAGAIN) return err; + if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err; + } + return IO_UNKNOWN; +} + +/*-------------------------------------------------------------------------*\ +* Put socket into blocking mode +\*-------------------------------------------------------------------------*/ +void socket_setblocking(p_socket ps) { + int flags = fcntl(*ps, F_GETFL, 0); + flags &= (~(O_NONBLOCK)); + fcntl(*ps, F_SETFL, flags); +} + +/*-------------------------------------------------------------------------*\ +* Put socket into non-blocking mode +\*-------------------------------------------------------------------------*/ +void socket_setnonblocking(p_socket ps) { + int flags = fcntl(*ps, F_GETFL, 0); + flags |= O_NONBLOCK; + fcntl(*ps, F_SETFL, flags); +} + +/*-------------------------------------------------------------------------*\ +* DNS helpers +\*-------------------------------------------------------------------------*/ +int socket_gethostbyaddr(const char *addr, socklen_t len, struct hostent **hp) { + *hp = gethostbyaddr(addr, len, AF_INET); + if (*hp) return IO_DONE; + else if (h_errno) return h_errno; + else if (errno) return errno; + else return IO_UNKNOWN; +} + +int socket_gethostbyname(const char *addr, struct hostent **hp) { + *hp = gethostbyname(addr); + if (*hp) return IO_DONE; + else if (h_errno) return h_errno; + else if (errno) return errno; + else return IO_UNKNOWN; +} + +/*-------------------------------------------------------------------------*\ +* Error translation functions +* Make sure important error messages are standard +\*-------------------------------------------------------------------------*/ +const char *socket_hoststrerror(int err) { + if (err <= 0) return io_strerror(err); + switch (err) { + case HOST_NOT_FOUND: return PIE_HOST_NOT_FOUND; + default: return hstrerror(err); + } +} + +const char *socket_strerror(int err) { + if (err <= 0) return io_strerror(err); + switch (err) { + case EADDRINUSE: return PIE_ADDRINUSE; + case EISCONN: return PIE_ISCONN; + case EACCES: return PIE_ACCESS; + case ECONNREFUSED: return PIE_CONNREFUSED; + case ECONNABORTED: return PIE_CONNABORTED; + case ECONNRESET: return PIE_CONNRESET; + case ETIMEDOUT: return PIE_TIMEDOUT; + default: { + return strerror(err); + } + } +} + +const char *socket_ioerror(p_socket ps, int err) { + (void) ps; + return socket_strerror(err); +} + +const char *socket_gaistrerror(int err) { + if (err == 0) return NULL; + switch (err) { + case EAI_AGAIN: return PIE_AGAIN; + case EAI_BADFLAGS: return PIE_BADFLAGS; +#ifdef EAI_BADHINTS + case EAI_BADHINTS: return PIE_BADHINTS; +#endif + case EAI_FAIL: return PIE_FAIL; + case EAI_FAMILY: return PIE_FAMILY; + case EAI_MEMORY: return PIE_MEMORY; + case EAI_NONAME: return PIE_NONAME; +#ifdef EAI_OVERFLOW + case EAI_OVERFLOW: return PIE_OVERFLOW; +#endif +#ifdef EAI_PROTOCOL + case EAI_PROTOCOL: return PIE_PROTOCOL; +#endif + case EAI_SERVICE: return PIE_SERVICE; + case EAI_SOCKTYPE: return PIE_SOCKTYPE; + case EAI_SYSTEM: return strerror(errno); + default: return LUA_GAI_STRERROR(err); + } +} diff --git a/src/3rd party/lua-extensions/luasocket/usocket.h b/src/3rd party/lua-extensions/luasocket/usocket.h new file mode 100644 index 000000000..45f2f99f7 --- /dev/null +++ b/src/3rd party/lua-extensions/luasocket/usocket.h @@ -0,0 +1,59 @@ +#ifndef USOCKET_H +#define USOCKET_H +/*=========================================================================*\ +* Socket compatibilization module for Unix +* LuaSocket toolkit +\*=========================================================================*/ + +/*=========================================================================*\ +* BSD include files +\*=========================================================================*/ +/* error codes */ +#include +/* close function */ +#include +/* fnctnl function and associated constants */ +#include +/* struct sockaddr */ +#include +/* socket function */ +#include +/* struct timeval */ +#include +/* gethostbyname and gethostbyaddr functions */ +#include +/* sigpipe handling */ +#include +/* IP stuff*/ +#include +#include +/* TCP options (nagle algorithm disable) */ +#include +#include + +#ifndef SO_REUSEPORT +#define SO_REUSEPORT SO_REUSEADDR +#endif + +/* Some platforms use IPV6_JOIN_GROUP instead if + * IPV6_ADD_MEMBERSHIP. The semantics are same, though. */ +#ifndef IPV6_ADD_MEMBERSHIP +#ifdef IPV6_JOIN_GROUP +#define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP +#endif /* IPV6_JOIN_GROUP */ +#endif /* !IPV6_ADD_MEMBERSHIP */ + +/* Same with IPV6_DROP_MEMBERSHIP / IPV6_LEAVE_GROUP. */ +#ifndef IPV6_DROP_MEMBERSHIP +#ifdef IPV6_LEAVE_GROUP +#define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP +#endif /* IPV6_LEAVE_GROUP */ +#endif /* !IPV6_DROP_MEMBERSHIP */ + +typedef int t_socket; +typedef t_socket *p_socket; +typedef struct sockaddr_storage t_sockaddr_storage; + +#define SOCKET_INVALID (-1) + +#endif /* USOCKET_H */ diff --git a/src/3rd party/lua-extensions/luasocket/wsocket.c b/src/3rd party/lua-extensions/luasocket/wsocket.c new file mode 100644 index 000000000..d3af9d4a1 --- /dev/null +++ b/src/3rd party/lua-extensions/luasocket/wsocket.c @@ -0,0 +1,436 @@ +/*=========================================================================*\ +* Socket compatibilization module for Win32 +* LuaSocket toolkit +* +* The penalty of calling select to avoid busy-wait is only paid when +* the I/O call fail in the first place. +\*=========================================================================*/ +#include "luasocket.h" + +#include + +#include "socket.h" +#include "pierror.h" + +/* WinSock doesn't have a strerror... */ +static const char *wstrerror(int err); + +/*-------------------------------------------------------------------------*\ +* Initializes module +\*-------------------------------------------------------------------------*/ +int socket_open(void) { + WSADATA wsaData; + WORD wVersionRequested = MAKEWORD(2, 0); + int err = WSAStartup(wVersionRequested, &wsaData ); + if (err != 0) return 0; + if ((LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 0) && + (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1)) { + WSACleanup(); + return 0; + } + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Close module +\*-------------------------------------------------------------------------*/ +int socket_close(void) { + WSACleanup(); + return 1; +} + +/*-------------------------------------------------------------------------*\ +* Wait for readable/writable/connected socket with timeout +\*-------------------------------------------------------------------------*/ +#define WAITFD_R 1 +#define WAITFD_W 2 +#define WAITFD_E 4 +#define WAITFD_C (WAITFD_E|WAITFD_W) + +int socket_waitfd(p_socket ps, int sw, p_timeout tm) { + int ret; + fd_set rfds, wfds, efds, *rp = NULL, *wp = NULL, *ep = NULL; + struct timeval tv, *tp = NULL; + double t; + if (timeout_iszero(tm)) return IO_TIMEOUT; /* optimize timeout == 0 case */ + if (sw & WAITFD_R) { + FD_ZERO(&rfds); + FD_SET(*ps, &rfds); + rp = &rfds; + } + if (sw & WAITFD_W) { FD_ZERO(&wfds); FD_SET(*ps, &wfds); wp = &wfds; } + if (sw & WAITFD_C) { FD_ZERO(&efds); FD_SET(*ps, &efds); ep = &efds; } + if ((t = timeout_get(tm)) >= 0.0) { + tv.tv_sec = (int) t; + tv.tv_usec = (int) ((t-tv.tv_sec)*1.0e6); + tp = &tv; + } + ret = select(0, rp, wp, ep, tp); + if (ret == -1) return WSAGetLastError(); + if (ret == 0) return IO_TIMEOUT; + if (sw == WAITFD_C && FD_ISSET(*ps, &efds)) return IO_CLOSED; + return IO_DONE; +} + +/*-------------------------------------------------------------------------*\ +* Select with int timeout in ms +\*-------------------------------------------------------------------------*/ +int socket_select(t_socket n, fd_set *rfds, fd_set *wfds, fd_set *efds, + p_timeout tm) { + struct timeval tv; + double t = timeout_get(tm); + tv.tv_sec = (int) t; + tv.tv_usec = (int) ((t - tv.tv_sec) * 1.0e6); + if (n <= 0) { + Sleep((DWORD) (1000*t)); + return 0; + } else return select(0, rfds, wfds, efds, t >= 0.0? &tv: NULL); +} + +/*-------------------------------------------------------------------------*\ +* Close and inutilize socket +\*-------------------------------------------------------------------------*/ +void socket_destroy(p_socket ps) { + if (*ps != SOCKET_INVALID) { + socket_setblocking(ps); /* close can take a long time on WIN32 */ + closesocket(*ps); + *ps = SOCKET_INVALID; + } +} + +/*-------------------------------------------------------------------------*\ +* +\*-------------------------------------------------------------------------*/ +void socket_shutdown(p_socket ps, int how) { + socket_setblocking(ps); + shutdown(*ps, how); + socket_setnonblocking(ps); +} + +/*-------------------------------------------------------------------------*\ +* Creates and sets up a socket +\*-------------------------------------------------------------------------*/ +int socket_create(p_socket ps, int domain, int type, int protocol) { + *ps = socket(domain, type, protocol); + if (*ps != SOCKET_INVALID) return IO_DONE; + else return WSAGetLastError(); +} + +/*-------------------------------------------------------------------------*\ +* Connects or returns error message +\*-------------------------------------------------------------------------*/ +int socket_connect(p_socket ps, SA *addr, socklen_t len, p_timeout tm) { + int err; + /* don't call on closed socket */ + if (*ps == SOCKET_INVALID) return IO_CLOSED; + /* ask system to connect */ + if (connect(*ps, addr, len) == 0) return IO_DONE; + /* make sure the system is trying to connect */ + err = WSAGetLastError(); + if (err != WSAEWOULDBLOCK && err != WSAEINPROGRESS) return err; + /* zero timeout case optimization */ + if (timeout_iszero(tm)) return IO_TIMEOUT; + /* we wait until something happens */ + err = socket_waitfd(ps, WAITFD_C, tm); + if (err == IO_CLOSED) { + int elen = sizeof(err); + /* give windows time to set the error (yes, disgusting) */ + Sleep(10); + /* find out why we failed */ + getsockopt(*ps, SOL_SOCKET, SO_ERROR, (char *)&err, &elen); + /* we KNOW there was an error. if 'why' is 0, we will return + * "unknown error", but it's not really our fault */ + return err > 0? err: IO_UNKNOWN; + } else return err; + +} + +/*-------------------------------------------------------------------------*\ +* Binds or returns error message +\*-------------------------------------------------------------------------*/ +int socket_bind(p_socket ps, SA *addr, socklen_t len) { + int err = IO_DONE; + socket_setblocking(ps); + if (bind(*ps, addr, len) < 0) err = WSAGetLastError(); + socket_setnonblocking(ps); + return err; +} + +/*-------------------------------------------------------------------------*\ +* +\*-------------------------------------------------------------------------*/ +int socket_listen(p_socket ps, int backlog) { + int err = IO_DONE; + socket_setblocking(ps); + if (listen(*ps, backlog) < 0) err = WSAGetLastError(); + socket_setnonblocking(ps); + return err; +} + +/*-------------------------------------------------------------------------*\ +* Accept with timeout +\*-------------------------------------------------------------------------*/ +int socket_accept(p_socket ps, p_socket pa, SA *addr, socklen_t *len, + p_timeout tm) { + if (*ps == SOCKET_INVALID) return IO_CLOSED; + for ( ;; ) { + int err; + /* try to get client socket */ + if ((*pa = accept(*ps, addr, len)) != SOCKET_INVALID) return IO_DONE; + /* find out why we failed */ + err = WSAGetLastError(); + /* if we failed because there was no connectoin, keep trying */ + if (err != WSAEWOULDBLOCK && err != WSAECONNABORTED) return err; + /* call select to avoid busy wait */ + if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err; + } +} + +/*-------------------------------------------------------------------------*\ +* Send with timeout +* On windows, if you try to send 10MB, the OS will buffer EVERYTHING +* this can take an awful lot of time and we will end up blocked. +* Therefore, whoever calls this function should not pass a huge buffer. +\*-------------------------------------------------------------------------*/ +int socket_send(p_socket ps, const char *data, size_t count, + size_t *sent, p_timeout tm) +{ + int err; + *sent = 0; + /* avoid making system calls on closed sockets */ + if (*ps == SOCKET_INVALID) return IO_CLOSED; + /* loop until we send something or we give up on error */ + for ( ;; ) { + /* try to send something */ + int put = send(*ps, data, (int) count, 0); + /* if we sent something, we are done */ + if (put > 0) { + *sent = put; + return IO_DONE; + } + /* deal with failure */ + err = WSAGetLastError(); + /* we can only proceed if there was no serious error */ + if (err != WSAEWOULDBLOCK) return err; + /* avoid busy wait */ + if ((err = socket_waitfd(ps, WAITFD_W, tm)) != IO_DONE) return err; + } +} + +/*-------------------------------------------------------------------------*\ +* Sendto with timeout +\*-------------------------------------------------------------------------*/ +int socket_sendto(p_socket ps, const char *data, size_t count, size_t *sent, + SA *addr, socklen_t len, p_timeout tm) +{ + int err; + *sent = 0; + if (*ps == SOCKET_INVALID) return IO_CLOSED; + for ( ;; ) { + int put = sendto(*ps, data, (int) count, 0, addr, len); + if (put > 0) { + *sent = put; + return IO_DONE; + } + err = WSAGetLastError(); + if (err != WSAEWOULDBLOCK) return err; + if ((err = socket_waitfd(ps, WAITFD_W, tm)) != IO_DONE) return err; + } +} + +/*-------------------------------------------------------------------------*\ +* Receive with timeout +\*-------------------------------------------------------------------------*/ +int socket_recv(p_socket ps, char *data, size_t count, size_t *got, + p_timeout tm) +{ + int err, prev = IO_DONE; + *got = 0; + if (*ps == SOCKET_INVALID) return IO_CLOSED; + for ( ;; ) { + int taken = recv(*ps, data, (int) count, 0); + if (taken > 0) { + *got = taken; + return IO_DONE; + } + if (taken == 0) return IO_CLOSED; + err = WSAGetLastError(); + /* On UDP, a connreset simply means the previous send failed. + * So we try again. + * On TCP, it means our socket is now useless, so the error passes. + * (We will loop again, exiting because the same error will happen) */ + if (err != WSAEWOULDBLOCK) { + if (err != WSAECONNRESET || prev == WSAECONNRESET) return err; + prev = err; + continue; + } + if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err; + } +} + +/*-------------------------------------------------------------------------*\ +* Recvfrom with timeout +\*-------------------------------------------------------------------------*/ +int socket_recvfrom(p_socket ps, char *data, size_t count, size_t *got, + SA *addr, socklen_t *len, p_timeout tm) +{ + int err, prev = IO_DONE; + *got = 0; + if (*ps == SOCKET_INVALID) return IO_CLOSED; + for ( ;; ) { + int taken = recvfrom(*ps, data, (int) count, 0, addr, len); + if (taken > 0) { + *got = taken; + return IO_DONE; + } + if (taken == 0) return IO_CLOSED; + err = WSAGetLastError(); + /* On UDP, a connreset simply means the previous send failed. + * So we try again. + * On TCP, it means our socket is now useless, so the error passes. + * (We will loop again, exiting because the same error will happen) */ + if (err != WSAEWOULDBLOCK) { + if (err != WSAECONNRESET || prev == WSAECONNRESET) return err; + prev = err; + continue; + } + if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err; + } +} + +/*-------------------------------------------------------------------------*\ +* Put socket into blocking mode +\*-------------------------------------------------------------------------*/ +void socket_setblocking(p_socket ps) { + u_long argp = 0; + ioctlsocket(*ps, FIONBIO, &argp); +} + +/*-------------------------------------------------------------------------*\ +* Put socket into non-blocking mode +\*-------------------------------------------------------------------------*/ +void socket_setnonblocking(p_socket ps) { + u_long argp = 1; + ioctlsocket(*ps, FIONBIO, &argp); +} + +/*-------------------------------------------------------------------------*\ +* DNS helpers +\*-------------------------------------------------------------------------*/ +int socket_gethostbyaddr(const char *addr, socklen_t len, struct hostent **hp) { + *hp = gethostbyaddr(addr, len, AF_INET); + if (*hp) return IO_DONE; + else return WSAGetLastError(); +} + +int socket_gethostbyname(const char *addr, struct hostent **hp) { + *hp = gethostbyname(addr); + if (*hp) return IO_DONE; + else return WSAGetLastError(); +} + +/*-------------------------------------------------------------------------*\ +* Error translation functions +\*-------------------------------------------------------------------------*/ +const char *socket_hoststrerror(int err) { + if (err <= 0) return io_strerror(err); + switch (err) { + case WSAHOST_NOT_FOUND: return PIE_HOST_NOT_FOUND; + default: return wstrerror(err); + } +} + +const char *socket_strerror(int err) { + if (err <= 0) return io_strerror(err); + switch (err) { + case WSAEADDRINUSE: return PIE_ADDRINUSE; + case WSAECONNREFUSED : return PIE_CONNREFUSED; + case WSAEISCONN: return PIE_ISCONN; + case WSAEACCES: return PIE_ACCESS; + case WSAECONNABORTED: return PIE_CONNABORTED; + case WSAECONNRESET: return PIE_CONNRESET; + case WSAETIMEDOUT: return PIE_TIMEDOUT; + default: return wstrerror(err); + } +} + +const char *socket_ioerror(p_socket ps, int err) { + (void) ps; + return socket_strerror(err); +} + +static const char *wstrerror(int err) { + switch (err) { + case WSAEINTR: return "Interrupted function call"; + case WSAEACCES: return PIE_ACCESS; /* "Permission denied"; */ + case WSAEFAULT: return "Bad address"; + case WSAEINVAL: return "Invalid argument"; + case WSAEMFILE: return "Too many open files"; + case WSAEWOULDBLOCK: return "Resource temporarily unavailable"; + case WSAEINPROGRESS: return "Operation now in progress"; + case WSAEALREADY: return "Operation already in progress"; + case WSAENOTSOCK: return "Socket operation on nonsocket"; + case WSAEDESTADDRREQ: return "Destination address required"; + case WSAEMSGSIZE: return "Message too long"; + case WSAEPROTOTYPE: return "Protocol wrong type for socket"; + case WSAENOPROTOOPT: return "Bad protocol option"; + case WSAEPROTONOSUPPORT: return "Protocol not supported"; + case WSAESOCKTNOSUPPORT: return PIE_SOCKTYPE; /* "Socket type not supported"; */ + case WSAEOPNOTSUPP: return "Operation not supported"; + case WSAEPFNOSUPPORT: return "Protocol family not supported"; + case WSAEAFNOSUPPORT: return PIE_FAMILY; /* "Address family not supported by protocol family"; */ + case WSAEADDRINUSE: return PIE_ADDRINUSE; /* "Address already in use"; */ + case WSAEADDRNOTAVAIL: return "Cannot assign requested address"; + case WSAENETDOWN: return "Network is down"; + case WSAENETUNREACH: return "Network is unreachable"; + case WSAENETRESET: return "Network dropped connection on reset"; + case WSAECONNABORTED: return "Software caused connection abort"; + case WSAECONNRESET: return PIE_CONNRESET; /* "Connection reset by peer"; */ + case WSAENOBUFS: return "No buffer space available"; + case WSAEISCONN: return PIE_ISCONN; /* "Socket is already connected"; */ + case WSAENOTCONN: return "Socket is not connected"; + case WSAESHUTDOWN: return "Cannot send after socket shutdown"; + case WSAETIMEDOUT: return PIE_TIMEDOUT; /* "Connection timed out"; */ + case WSAECONNREFUSED: return PIE_CONNREFUSED; /* "Connection refused"; */ + case WSAEHOSTDOWN: return "Host is down"; + case WSAEHOSTUNREACH: return "No route to host"; + case WSAEPROCLIM: return "Too many processes"; + case WSASYSNOTREADY: return "Network subsystem is unavailable"; + case WSAVERNOTSUPPORTED: return "Winsock.dll version out of range"; + case WSANOTINITIALISED: + return "Successful WSAStartup not yet performed"; + case WSAEDISCON: return "Graceful shutdown in progress"; + case WSAHOST_NOT_FOUND: return PIE_HOST_NOT_FOUND; /* "Host not found"; */ + case WSATRY_AGAIN: return "Nonauthoritative host not found"; + case WSANO_RECOVERY: return PIE_FAIL; /* "Nonrecoverable name lookup error"; */ + case WSANO_DATA: return "Valid name, no data record of requested type"; + default: return "Unknown error"; + } +} + +const char *socket_gaistrerror(int err) { + if (err == 0) return NULL; + switch (err) { + case EAI_AGAIN: return PIE_AGAIN; + case EAI_BADFLAGS: return PIE_BADFLAGS; +#ifdef EAI_BADHINTS + case EAI_BADHINTS: return PIE_BADHINTS; +#endif + case EAI_FAIL: return PIE_FAIL; + case EAI_FAMILY: return PIE_FAMILY; + case EAI_MEMORY: return PIE_MEMORY; + case EAI_NONAME: return PIE_NONAME; +#ifdef EAI_OVERFLOW + case EAI_OVERFLOW: return PIE_OVERFLOW; +#endif +#ifdef EAI_PROTOCOL + case EAI_PROTOCOL: return PIE_PROTOCOL; +#endif + case EAI_SERVICE: return PIE_SERVICE; + case EAI_SOCKTYPE: return PIE_SOCKTYPE; +#ifdef EAI_SYSTEM + case EAI_SYSTEM: return strerror(errno); +#endif + default: return LUA_GAI_STRERROR(err); + } +} diff --git a/src/3rd party/lua-extensions/luasocket/wsocket.h b/src/3rd party/lua-extensions/luasocket/wsocket.h new file mode 100644 index 000000000..398664026 --- /dev/null +++ b/src/3rd party/lua-extensions/luasocket/wsocket.h @@ -0,0 +1,33 @@ +#ifndef WSOCKET_H +#define WSOCKET_H +/*=========================================================================*\ +* Socket compatibilization module for Win32 +* LuaSocket toolkit +\*=========================================================================*/ + +/*=========================================================================*\ +* WinSock include files +\*=========================================================================*/ +#include +#include + +typedef int socklen_t; +typedef SOCKADDR_STORAGE t_sockaddr_storage; +typedef SOCKET t_socket; +typedef t_socket *p_socket; + +#ifndef IPV6_V6ONLY +#define IPV6_V6ONLY 27 +#endif + +#define SOCKET_INVALID (INVALID_SOCKET) + +#ifndef SO_REUSEPORT +#define SO_REUSEPORT SO_REUSEADDR +#endif + +#ifndef AI_NUMERICSERV +#define AI_NUMERICSERV (0) +#endif + +#endif /* WSOCKET_H */ diff --git a/src/3rd party/lua-extensions/vs2022/lua_extensions.vcxproj b/src/3rd party/lua-extensions/vs2022/lua_extensions.vcxproj index 309839011..ed7d8343a 100644 --- a/src/3rd party/lua-extensions/vs2022/lua_extensions.vcxproj +++ b/src/3rd party/lua-extensions/vs2022/lua_extensions.vcxproj @@ -222,11 +222,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/3rd party/lua-extensions/vs2022/lua_extensions.vcxproj.filters b/src/3rd party/lua-extensions/vs2022/lua_extensions.vcxproj.filters index 378548dc1..cc4b9fb60 100644 --- a/src/3rd party/lua-extensions/vs2022/lua_extensions.vcxproj.filters +++ b/src/3rd party/lua-extensions/vs2022/lua_extensions.vcxproj.filters @@ -5,10 +5,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Layers/xrRender/ResourceManager_Scripting.cpp b/src/Layers/xrRender/ResourceManager_Scripting.cpp index af0f6efea..96a4b7d3d 100644 --- a/src/Layers/xrRender/ResourceManager_Scripting.cpp +++ b/src/Layers/xrRender/ResourceManager_Scripting.cpp @@ -3,7 +3,7 @@ //AVO: lua re-org #ifdef USE_LUAJIT_ONE //defined in project props -#pragma comment(lib, "LuaJIT-1.1.8.lib") +#pragma comment(lib, "lua51.lib") #else #pragma comment(lib, "lua51.lib" ) #endif diff --git a/src/xrCore/string_concatenations.h b/src/xrCore/string_concatenations.h index 822bd790c..a743661c0 100644 --- a/src/xrCore/string_concatenations.h +++ b/src/xrCore/string_concatenations.h @@ -74,5 +74,34 @@ IC char* strconcat(int dest_sz, char* dest, const char* S1, const char* S2, cons #endif //_EDITOR #include "string_concatenations_inline.h" +// Giperion XRay Oxygen - ultimate version of strconcat +template +char* xr_strconcat(StringReceiverType& receiver, ArgList... args) +{ + static_assert(std::is_array< StringReceiverType>::value); // must be array... + static_assert(std::is_same::type, char>::value); // ... of chars + + char* pStrCursor = &receiver[0]; + char* pStrEnd = &receiver[0] + sizeof(StringReceiverType); + int dummy[] = { _strconcatSingle(pStrCursor, pStrEnd, args)... }; + (void)dummy; + + *pStrCursor = '\0'; + return &receiver[0]; +} + +int XRCORE_API _strconcatSingle(char*& destPtr, char* pDestEnd, const char* Str) +{ + char* TargetStrCursor = const_cast (Str); + for (; *TargetStrCursor && destPtr < pDestEnd; destPtr++, TargetStrCursor++) + { + *destPtr = *TargetStrCursor; + } + + R_ASSERT3(!(*TargetStrCursor), "Failed to concatenate string", Str); + + return 0; +} + -#endif // #ifndef STRING_CONCATENATIONS_H +#endif // #ifndef STRING_CONCATENATIONS_H \ No newline at end of file diff --git a/src/xrEngine/stdafx.h b/src/xrEngine/stdafx.h index e7aa1b0e8..99db5b4c3 100644 --- a/src/xrEngine/stdafx.h +++ b/src/xrEngine/stdafx.h @@ -72,7 +72,7 @@ extern ENGINE_API CInifile* pGameIni; //AVO: lua re-org #ifdef USE_LUAJIT_ONE //defined in project props -#pragma comment(lib, "LuaJIT-1.1.8.lib") +#pragma comment(lib, "lua51.lib") #else #pragma comment(lib, "lua51.lib" ) #endif diff --git a/src/xrEngine/vs2022/xrEngine.vcxproj b/src/xrEngine/vs2022/xrEngine.vcxproj index aa84e67db..ad9d81237 100644 --- a/src/xrEngine/vs2022/xrEngine.vcxproj +++ b/src/xrEngine/vs2022/xrEngine.vcxproj @@ -295,14 +295,15 @@ .;$(SolutionDir)3rd party\luajit-2\src\;$(SolutionDir)3rd party\luabind\;$(DXSDK_DIR)Include;$(XRAY_16X_LIBS)OpenAutomate\inc;$(XRAY_16X_LIBS)libogg-1.1.4\include;$(XRAY_16X_LIBS)libtheora-1.1.1\include;$(xrSdkDir)include;$(xrSdkDir)include\OpenAutomate;%(AdditionalIncludeDirectories) - STATIC_RENDERER_R4;NDEBUG;WIN32;_WINDOWS;ENGINE_BUILD;_SECURE_SCL=0;%(PreprocessorDefinitions) + STATIC_RENDERER_R4;NDEBUG;WIN32;_WINDOWS;ENGINE_BUILD;_SECURE_SCL=0;USE_LUAJIT_ONE;%(PreprocessorDefinitions) false NotSet Use stdafx.h - USE_LUAJIT_ONE + + ProgramDatabase MaxSpeed true @@ -457,14 +458,15 @@ .;$(SolutionDir)3rd party\luajit-2\src\;$(SolutionDir)3rd party\luabind\;$(DXSDK_DIR)Include;$(XRAY_16X_LIBS)OpenAutomate\inc;$(XRAY_16X_LIBS)libogg-1.1.4\include;$(XRAY_16X_LIBS)libtheora-1.1.1\include;$(xrSdkDir)include;$(xrSdkDir)include\OpenAutomate;%(AdditionalIncludeDirectories) - STATIC_RENDERER_R3;NDEBUG;WIN32;_WINDOWS;ENGINE_BUILD;_SECURE_SCL=0;%(PreprocessorDefinitions) + STATIC_RENDERER_R3;NDEBUG;WIN32;_WINDOWS;ENGINE_BUILD;_SECURE_SCL=0;/DUSE_LUAJIT_ONE;USE_LUAJIT_ONE;DEBUG;%(PreprocessorDefinitions) false NotSet Use stdafx.h - USE_LUAJIT_ONE + + ProgramDatabase MaxSpeed true diff --git a/src/xrEngine/vs2022/xrEngine.vcxproj.filters b/src/xrEngine/vs2022/xrEngine.vcxproj.filters index e65d7474b..c66c4278b 100644 --- a/src/xrEngine/vs2022/xrEngine.vcxproj.filters +++ b/src/xrEngine/vs2022/xrEngine.vcxproj.filters @@ -781,16 +781,10 @@ - - General\Resources - + - - General\Resources - - - General\Resources - + + \ No newline at end of file diff --git a/src/xrGame/vs2022/xrGame.vcxproj b/src/xrGame/vs2022/xrGame.vcxproj index 2fcfa81f4..c75a37d67 100644 --- a/src/xrGame/vs2022/xrGame.vcxproj +++ b/src/xrGame/vs2022/xrGame.vcxproj @@ -105,14 +105,15 @@ vs2022;..;$(SolutionDir);$(SolutionDir)xrServerEntities;$(SolutionDir)3rd party\luajit-2\src\;$(SolutionDir)3rd party\luabind\;$(xrSdkDir)include;$(XRAY_16X_LIBS)OpenAutomate\inc;$(SolutionDir)3rd party\CxImage;%(AdditionalIncludeDirectories) - WIN32;NDEBUG;_WINDOWS;_USRDLL;XRGAME_EXPORTS;dSINGLE;MSVC;_SECURE_SCL=0;%(PreprocessorDefinitions) + WIN32;NDEBUG;_WINDOWS;_USRDLL;XRGAME_EXPORTS;dSINGLE;MSVC;_SECURE_SCL=0;USE_LUAJIT_ONE;%(PreprocessorDefinitions) NotSet Use stdafx.h 4995;4005;4237;%(DisableSpecificWarnings) - USE_LUAJIT_ONE + + false MaxSpeed true diff --git a/src/xrGame/xrGame.cpp b/src/xrGame/xrGame.cpp index 1b6a7f85b..b5ba7163c 100644 --- a/src/xrGame/xrGame.cpp +++ b/src/xrGame/xrGame.cpp @@ -14,7 +14,7 @@ //AVO: lua re-org #ifdef USE_LUAJIT_ONE //defined in project props -#pragma comment(lib, "LuaJIT-1.1.8.lib") +#pragma comment(lib, "lua51.lib") #else #pragma comment(lib, "lua51.lib" ) #endif diff --git a/src/xrServerEntities/opt.lua.h b/src/xrServerEntities/opt.lua.h new file mode 100644 index 000000000..e172a62d1 --- /dev/null +++ b/src/xrServerEntities/opt.lua.h @@ -0,0 +1,427 @@ +/* code automatically generated by bin2c -- DO NOT EDIT */ +/* #include'ing this file in a C program is equivalent to calling + if (luaL_loadfile(L,"luac.out")==0) lua_pcall(L, 0, 0, 0); +*/ +/* luac.out */ +static const unsigned char opt_lua_binary[] = { + 27, 76,117, 97, 81, 0, 1, 4, 4, 4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 2, 33,195, 0, 0, 0, 1, 0, 0, 0, 65, 64, 0, 0, +138, 64, 1, 0,137,192, 64,129,137, 64, 65,130,137,192, 65,131,137, 64, 66,132, +137,192, 66,133,197, 0, 3, 0, 1, 65, 3, 0,220,128, 0, 1, 5,129, 3, 0, + 70,193,195, 1, 87, 0,196, 2, 22, 0, 0,128, 66, 65, 0, 0, 66, 1,128, 0, +129, 65, 4, 0, 28, 65,128, 1, 5, 1, 3, 0, 65,129, 4, 0, 28,129, 0, 1, + 69,193, 4, 0,133, 1, 5, 0,197, 65, 5, 0, 5,130, 5, 0, 70,194, 69, 2, +134, 2, 70, 2,198, 66, 70, 2, 6,131, 70, 2, 69,195, 6, 0,134, 3,199, 1, +194, 3,128, 0, 2, 4,128, 0,156, 67,128, 1,129, 67, 7, 0,228, 3, 0, 0, + 0, 0,128, 4, 0, 0, 0, 2, 36, 68, 0, 0,100,132, 0, 0, 0, 0,128, 5, +164,196, 0, 0, 0, 0,128, 2, 0, 0,128, 5,228, 4, 1, 0, 0, 0,128, 2, + 0, 0,128, 5, 36, 69, 1, 0, 0, 0,128, 2, 0, 0, 0, 3, 0, 0,128, 6, + 0, 0,128, 3,100,133, 1, 0, 0, 0,128, 4,164,197, 1, 0, 0, 0,128, 2, + 0, 0,128, 5,228, 5, 2, 0, 0, 0,128, 10, 0, 0,128, 5, 10,134, 6, 0, +100, 70, 2, 0, 9, 70, 6,143,100,134, 2, 0, 0, 0, 0, 5, 9, 70,134,143, +100,198, 2, 0, 9, 70, 6,144,100, 6, 3, 0, 9, 70,134,144,100, 70, 3, 0, + 0, 0, 0, 2, 9, 70, 6,145,100,134, 3, 0, 0, 0, 0, 10, 0, 0, 0, 5, + 9, 70,134,145,100,198, 3, 0, 0, 0,128, 9, 0, 0, 0, 10, 9, 70, 6,146, + 9, 6,132,146, 9, 6, 4,147,100, 6, 4, 0, 0, 0,128, 9, 0, 0,128, 2, + 9, 70,134,147,100, 70, 4, 0, 9, 70, 6,148,100,134, 4, 0, 0, 0,128, 9, + 0, 0, 0, 10, 9, 70,134,148, 9,134, 5,149, 9,134,133,149, 9,134, 5,150, + 9,134,133,150, 9,134, 5,151, 9,134,133,151, 9,134, 5,152, 9,134,133,152, +100,198, 4, 0, 0, 0, 0, 11, 9, 70, 6,153,100, 6, 5, 0, 9, 70,134,153, +100, 70, 5, 0, 0, 0, 0, 9, 9, 70, 6,154,100,134, 5, 0, 0, 0,128, 2, + 0, 0,128, 5, 9, 70,134,154,100,198, 5, 0, 0, 0,128, 5, 9, 70, 6,155, +100, 6, 6, 0, 0, 0, 0, 9, 9, 70,134,155,100, 70, 6, 0, 0, 0,128, 11, + 9, 70, 6,156, 9,198,133,156,100,134, 6, 0, 0, 0,128, 8, 9, 70, 6,157, +100,198, 6, 0, 0, 0,128, 8, 9, 70,134,157,100, 6, 7, 0, 0, 0,128, 10, + 0, 0,128, 5, 9, 70, 6,158, 9, 6,132,158,100, 70, 7, 0, 0, 0,128, 10, + 0, 0,128, 2, 0, 0,128, 5, 9, 70, 6,159,100,134, 7, 0, 0, 0,128, 5, + 9, 70,134,159,100,198, 7, 0, 0, 0,128, 2, 9, 70, 6,160, 9, 6,132,160, +100, 6, 8, 0, 0, 0, 0, 8, 0, 0, 0, 2, 0, 0,128, 4, 9, 70, 6,161, +100, 70, 8, 0, 9, 70,134,161,100,134, 8, 0, 0, 0, 0, 2, 0, 0, 0, 1, + 0, 0,128, 7, 0, 0, 0, 8, 0, 0, 0, 5, 0, 0,128, 4, 0, 0, 0, 12, + 0, 0,128, 5, 0, 0, 0, 6,131, 6,128, 13, 36,199, 8, 0, 0, 0, 0, 7, + 0, 0, 0, 4, 0, 0,128, 12, 0, 0,128, 1, 0, 0, 0, 14, 0, 0, 0, 13, +100, 7, 9, 0, 0, 0, 0, 4,164, 71, 9, 0, 0, 0, 0, 13, 0, 0,128, 1, + 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0,128, 0, 0, 0,128, 14, + 0, 0,128, 13,197, 7, 17, 0, 37, 8, 0, 0,220, 71, 0, 0,228,135, 9, 0, + 0, 0,128, 8,199, 71, 17, 0,228,199, 9, 0, 0, 0, 0, 7,199,135, 17, 0, +135,199, 17, 0,135, 7, 18, 0, 30, 0,128, 0, 73, 0, 0, 0, 3, 0, 0, 0, + 0, 0, 0, 73, 64, 3, 0, 0, 0, 0, 0, 0, 0, 64, 4, 10, 0, 0, 0, 98, +121,116,101, 99,111,100,101,115, 0, 3, 0, 0, 0, 0, 0, 64,175, 64, 4, 11, + 0, 0, 0,115,116, 97, 99,107,115,108,111,116,115, 0, 3, 0, 0, 0, 0, 0, +192, 98, 64, 4, 7, 0, 0, 0,112, 97,114, 97,109,115, 0, 3, 0, 0, 0, 0, + 0, 0, 52, 64, 4, 7, 0, 0, 0, 99,111,110,115,116,115, 0, 3, 0, 0, 0, + 0, 0, 0,105, 64, 4, 5, 0, 0, 0,115,117, 98,115, 0, 3, 0, 0, 0, 0, + 0, 0, 62, 64, 4, 8, 0, 0, 0,114,101,113,117,105,114,101, 0, 4, 4, 0, + 0, 0,106,105,116, 0, 4, 7, 0, 0, 0, 97,115,115,101,114,116, 0, 4, 12, + 0, 0, 0,118,101,114,115,105,111,110, 95,110,117,109, 0, 3, 0, 0, 0, 0, + 0,188,195, 64, 4, 37, 0, 0, 0, 76,117, 97, 74, 73, 84, 32, 99,111,114,101, + 47,108,105, 98,114, 97,114,121, 32,118,101,114,115,105,111,110, 32,109,105,115, +109, 97,116, 99,104, 0, 4, 9, 0, 0, 0,106,105,116, 46,117,116,105,108, 0, + 4, 5, 0, 0, 0,116,121,112,101, 0, 4, 7, 0, 0, 0,114, 97,119,103,101, +116, 0, 4, 5, 0, 0, 0,110,101,120,116, 0, 4, 6, 0, 0, 0,112, 99, 97, +108,108, 0, 4, 9, 0, 0, 0, 98,121,116,101, 99,111,100,101, 0, 4, 6, 0, + 0, 0, 99,111,110,115,116, 0, 4, 6, 0, 0, 0,104,105,110,116,115, 0, 4, + 7, 0, 0, 0,102,104,105,110,116,115, 0, 4, 13, 0, 0, 0,103,101,116,109, +101,116, 97,116, 97, 98,108,101, 0, 4, 4, 0, 0, 0,111,102,102, 0, 3, 0, + 0, 0, 0, 0, 0,240,191, 4, 5, 0, 0, 0, 77, 79, 86, 69, 0, 4, 6, 0, + 0, 0, 76, 79, 65, 68, 75, 0, 4, 9, 0, 0, 0, 76, 79, 65, 68, 66, 79, 79, + 76, 0, 4, 8, 0, 0, 0, 76, 79, 65, 68, 78, 73, 76, 0, 4, 9, 0, 0, 0, + 71, 69, 84, 85, 80, 86, 65, 76, 0, 4, 10, 0, 0, 0, 71, 69, 84, 71, 76, 79, + 66, 65, 76, 0, 4, 9, 0, 0, 0, 71, 69, 84, 84, 65, 66, 76, 69, 0, 4, 10, + 0, 0, 0, 83, 69, 84, 71, 76, 79, 66, 65, 76, 0, 4, 9, 0, 0, 0, 83, 69, + 84, 85, 80, 86, 65, 76, 0, 4, 9, 0, 0, 0, 83, 69, 84, 84, 65, 66, 76, 69, + 0, 4, 9, 0, 0, 0, 78, 69, 87, 84, 65, 66, 76, 69, 0, 4, 5, 0, 0, 0, + 83, 69, 76, 70, 0, 4, 4, 0, 0, 0, 65, 68, 68, 0, 4, 4, 0, 0, 0, 83, + 85, 66, 0, 4, 4, 0, 0, 0, 77, 85, 76, 0, 4, 4, 0, 0, 0, 68, 73, 86, + 0, 4, 4, 0, 0, 0, 77, 79, 68, 0, 4, 4, 0, 0, 0, 80, 79, 87, 0, 4, + 3, 0, 0, 0, 76, 84, 0, 4, 3, 0, 0, 0, 76, 69, 0, 4, 4, 0, 0, 0, + 85, 78, 77, 0, 4, 4, 0, 0, 0, 78, 79, 84, 0, 4, 4, 0, 0, 0, 76, 69, + 78, 0, 4, 7, 0, 0, 0, 67, 79, 78, 67, 65, 84, 0, 4, 4, 0, 0, 0, 74, + 77, 80, 0, 4, 3, 0, 0, 0, 69, 81, 0, 4, 5, 0, 0, 0, 84, 69, 83, 84, + 0, 4, 8, 0, 0, 0, 84, 69, 83, 84, 83, 69, 84, 0, 4, 5, 0, 0, 0, 67, + 65, 76, 76, 0, 4, 9, 0, 0, 0, 84, 65, 73, 76, 67, 65, 76, 76, 0, 4, 7, + 0, 0, 0, 82, 69, 84, 85, 82, 78, 0, 4, 8, 0, 0, 0, 70, 79, 82, 76, 79, + 79, 80, 0, 4, 8, 0, 0, 0, 70, 79, 82, 80, 82, 69, 80, 0, 4, 9, 0, 0, + 0, 84, 70, 79, 82, 76, 79, 79, 80, 0, 4, 8, 0, 0, 0, 83, 69, 84, 76, 73, + 83, 84, 0, 4, 6, 0, 0, 0, 67, 76, 79, 83, 69, 0, 4, 8, 0, 0, 0, 67, + 76, 79, 83, 85, 82, 69, 0, 4, 7, 0, 0, 0, 86, 65, 82, 65, 82, 71, 0, 4, + 7, 0, 0, 0,109,111,100,117,108,101, 0, 4, 16, 0, 0, 0, 97,116,116, 97, + 99,104, 95, 99, 97,108,108,104,105,110,116, 0, 4, 9, 0, 0, 0,103,101,116, +108,101,118,101,108, 0, 4, 9, 0, 0, 0,115,101,116,108,101,118,101,108, 0, + 4, 6, 0, 0, 0,115,116, 97,114,116, 0, 40, 0, 0, 0, 0, 0, 0, 0, 64, + 0, 0, 0,100, 0, 0, 0, 2, 1, 0, 13, 68, 0, 0, 0, 74, 0, 0, 0,138, + 0, 0, 0,193, 0, 0, 0, 1, 65, 0, 0, 68, 1, 0, 0,128, 1, 0, 0,192, + 1, 0, 2, 92,129,129, 1, 73,128, 64, 2, 12, 65, 64, 2, 23,192,192, 2, 22, +192, 0,128, 12,193, 1, 2,146, 2, 0, 2, 73,128, 64, 5, 22, 64, 10,128, 23, + 0,193, 2, 22, 0, 1,128,146, 2, 0, 2,205,194, 1, 5, 73,128,192, 5, 73, +128, 64, 5, 22,128, 8,128, 23, 64,193, 2, 22, 64, 0,128, 22,128, 8,128, 22, +128, 7,128, 90, 2, 0, 0, 22,128, 1,128,140, 66, 64, 2,198,130,130, 0,218, + 66, 0, 0, 22, 0, 6,128,204, 64,192, 1,137,128,130, 1, 22, 64, 5,128, 23, +128,193, 2, 22,128, 1,128,132, 2,128, 0,134,194, 65, 5,192, 2, 0, 0, 0, + 3,128, 3,156,130,128, 1, 12,129, 2, 2, 22, 0, 3,128, 23, 0,194, 2, 22, + 64, 1,128, 87, 0, 64, 4, 22,192, 0,128, 12, 65, 64, 2,146, 2, 0, 2, 73, +128, 64, 5, 22, 0, 1,128, 23, 64,194, 2, 22,128, 0,128, 23, 0, 64, 4, 22, + 0, 0,128, 12, 65, 64, 2,134, 2,129, 0,154, 2, 0, 0, 22,128,241,127, 23, + 0,192, 1, 22, 0, 0,128, 94, 0, 0, 1, 6,193, 0, 1,205, 64,192, 1, 22, + 0,240,127, 30, 0,128, 0, 10, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, + 3, 0, 0, 0, 0, 0, 0,240, 63, 1, 1, 4, 4, 0, 0, 0, 74, 77, 80, 0, + 4, 8, 0, 0, 0, 70, 79, 82, 76, 79, 79, 80, 0, 4, 7, 0, 0, 0, 82, 69, + 84, 85, 82, 78, 0, 4, 8, 0, 0, 0, 67, 76, 79, 83, 85, 82, 69, 0, 4, 11, + 0, 0, 0, 99,108,111,115,117,114,101,110,117,112, 0, 4, 9, 0, 0, 0, 76, + 79, 65, 68, 66, 79, 79, 76, 0, 4, 8, 0, 0, 0, 83, 69, 84, 76, 73, 83, 84, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0,104, 0, 0, 0,104, 0, 0, 0, 0, 0, 0, 2, 1, 0, 0, 0, 30, 0,128, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0,107, 0, 0, 0,110, 0, 0, 0, 1, 6, 0, 10, 13, 0, 0, + 0,132, 1, 0, 0,134, 1, 64, 3,140,129, 1, 1,198,193,128, 0, 9,192, 1, + 3,128, 1,128, 1,204, 65,129, 1,205, 65,192, 3, 1, 66, 0, 0,160, 1, 0, +128, 73,128,192, 4,159, 65,255,127, 30, 0,128, 0, 3, 0, 0, 0, 4, 5, 0, + 0, 0, 84, 89, 80, 69, 0, 3, 0, 0, 0, 0, 0, 0,240, 63, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,113, 0, 0, + 0,118, 0, 0, 0, 2, 3, 0, 5, 14, 0, 0, 0,196, 0, 0, 0, 0, 1, 0, + 1,220,128, 0, 1, 87, 0,192, 1, 22,192, 0,128, 87, 64,192, 1, 22, 64, 0, +128, 23,128,192, 1, 22,192, 0,128, 4, 1,128, 0, 6,193, 64, 2, 12, 1,129, + 0, 9,128, 0, 2, 30, 0,128, 0, 4, 0, 0, 0, 4, 7, 0, 0, 0,110,117, +109, 98,101,114, 0, 4, 7, 0, 0, 0,115,116,114,105,110,103, 0, 4, 6, 0, + 0, 0,116, 97, 98,108,101, 0, 4, 5, 0, 0, 0, 84, 89, 80, 69, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,121, 0, + 0, 0,129, 0, 0, 0, 2, 5, 0, 9, 26, 0, 0, 0, 68, 1, 0, 0,128, 1, +128, 1, 92,129, 0, 1, 87, 0,192, 2, 22, 64, 0,128, 23, 64,192, 2, 22,192, + 0,128,132, 1,128, 0,134,129, 64, 3,140,129, 1, 1, 9,192, 0, 3, 25, 0, +129,129, 22,192, 2,128,134, 1,129, 0,196, 1, 0, 0, 0, 2, 0, 3,220,129, + 0, 1, 87, 0,193, 3, 22, 64, 0,128, 23, 64,193, 3, 22,192, 0,128, 4, 2, +128, 0, 6,130, 65, 4, 12, 2, 2, 1, 9,128, 1, 4, 30, 0,128, 0, 7, 0, + 0, 0, 4, 6, 0, 0, 0,116, 97, 98,108,101, 0, 4, 9, 0, 0, 0,117,115, +101,114,100, 97,116, 97, 0, 4, 5, 0, 0, 0, 84, 89, 80, 69, 0, 3, 0, 0, + 0, 0, 0, 0, 0, 0, 4, 7, 0, 0, 0,110,117,109, 98,101,114, 0, 4, 7, + 0, 0, 0,115,116,114,105,110,103, 0, 4, 8, 0, 0, 0, 84, 89, 80, 69, 75, + 69, 89, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0,132, 0, 0, 0,150, 0, 0, 0, 4, 3, 0, 8, 55, 0, 0, 0, 23, + 0, 64, 1, 22, 64, 0,128,195, 0,128, 1,222, 0, 0, 1,196, 0, 0, 0, 0, + 1,128, 0,220,128, 0, 1, 23, 64,192, 1, 22,128, 1,128,196, 0,128, 0, 0, + 1,128, 0, 64, 1, 0, 1,220,128,128, 1, 87, 0,192, 1, 22, 0, 0,128,222, + 0, 0, 1,196, 0, 0, 1, 0, 1,128, 0,220,128, 0, 1, 4, 1, 0, 0, 64, + 1,128, 1, 28,129, 0, 1, 23, 64, 64, 2, 22,192, 3,128, 4, 1,128, 0, 64, + 1,128, 1,129,129, 0, 0, 28,129,128, 1, 68, 1, 0, 0,128, 1, 0, 2, 92, +129, 0, 1, 23, 64,192, 2, 22,128, 1,128, 68, 1,128, 0,128, 1, 0, 2,192, + 1, 0, 1, 92,129,128, 1, 87, 0,192, 2, 22, 0, 0,128, 94, 1, 0, 1, 6, +193, 64, 0, 6, 65, 0, 2, 23, 0, 64, 2, 22, 0, 2,128, 68, 1, 0, 0,128, + 1,128, 0, 92,129, 0, 1, 23, 64,192, 2, 22,192, 0,128, 68, 1,128, 1,128, + 1,128, 0, 92,129, 0, 1, 0, 1,128, 2, 30, 1, 0, 1, 30, 0,128, 0, 4, + 0, 0, 0, 0, 4, 6, 0, 0, 0,116, 97, 98,108,101, 0, 4, 8, 0, 0, 0, + 95, 95,105,110,100,101,120, 0, 4, 9, 0, 0, 0,116, 97, 98,108,101,118, 97, +108, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0,153, 0, 0, 0,161, 0, 0, 0, 1, 4, 0, 9, 23, 0, 0, 0, 6, 1, + 64, 0, 82, 1, 0, 1, 6, 65, 1, 2, 23, 64, 64, 2, 22, 0, 4,128, 4, 1, + 0, 0, 70,129, 64, 0,141,193, 64, 1, 28, 1,129, 1, 23,192,128, 2, 22,128, + 2,128, 87, 0, 65, 2, 22, 64, 1,128, 87, 64, 65, 2, 22,192, 0,128, 23,128, + 65, 2, 22, 0, 1,128, 23,192, 0, 3, 22,128, 0,128,194, 1,128, 0, 6,194, +128, 0,222, 1,128, 1, 30, 0,128, 0, 7, 0, 0, 0, 4, 5, 0, 0, 0,108, +105,118,101, 0, 0, 4, 5, 0, 0, 0,102,117,110, 99, 0, 3, 0, 0, 0, 0, + 0, 0,240, 63, 4, 6, 0, 0, 0, 76, 79, 65, 68, 75, 0, 4, 9, 0, 0, 0, + 76, 79, 65, 68, 66, 79, 79, 76, 0, 4, 8, 0, 0, 0, 76, 79, 65, 68, 78, 73, + 76, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0,164, 0, 0, 0,183, 0, 0, 0, 2, 7, 0, 12, 47, 0, 0, 0,198, 1, +129, 0, 6, 66,129, 0, 23, 0,192, 3, 22, 64, 0,128,192, 1, 0, 4, 22,128, + 0,128, 23, 0, 64, 4, 22, 0, 0,128, 0, 2,128, 3, 68, 2, 0, 0,128, 2, +128, 3, 92,130, 0, 1,132, 2, 0, 0,192, 2, 0, 4,156,130, 0, 1, 23,128, +130, 4, 22,192, 4,128, 23, 64,192, 4, 22,128, 2,128, 87,128, 64, 3, 22, 64, + 1,128,208,194,192, 3, 23, 0,193, 5, 22,128, 0,128,208,194, 64, 4, 87, 0, +193, 5, 22, 64, 0,128,193, 65, 1, 0, 22, 0, 0,128,193,193, 0, 0, 87, 0, +192, 3, 22, 0, 2,128,196, 2,128, 0,198,130,193, 5,204,194, 2, 1, 9,192, +129, 5, 22,192, 0,128,196, 2,128, 0,198,130,193, 5,204,194, 2, 1, 9,192, +193, 5, 87, 0, 66, 3, 22,128, 0,128, 87, 64, 66, 3, 22, 0, 0,128, 73,192, +129, 1, 30, 0,128, 0, 10, 0, 0, 0, 0, 4, 7, 0, 0, 0,110,117,109, 98, +101,114, 0, 4, 4, 0, 0, 0, 68, 73, 86, 0, 3, 0, 0, 0, 0, 0, 0,240, + 63, 3, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0,224, 63, 4, + 5, 0, 0, 0, 84, 89, 80, 69, 0, 1, 0, 4, 3, 0, 0, 0, 76, 84, 0, 4, + 3, 0, 0, 0, 76, 69, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0,186, 0, 0, 0,194, 0, 0, 0, 2, 6, 0, 11, 22, + 0, 0, 0,132, 1, 0, 0,192, 1, 0, 0, 0, 2,128, 0, 64, 2, 0, 1,128, + 2, 0, 2,156,193,128, 2,218, 1, 0, 0, 22,128, 2,128, 23, 0,129, 1, 22, + 0, 2,128, 4, 2,128, 0, 6, 2, 64, 4, 12, 2, 2, 1, 9, 64, 64, 4, 23, +128,192, 2, 22,128, 0,128, 6,194, 64, 0, 76, 2, 65, 1, 9, 66,193, 4, 6, + 2,129, 0, 73, 0,130, 1, 30, 0,128, 0, 6, 0, 0, 0, 4, 8, 0, 0, 0, + 67, 79, 77, 66, 73, 78, 69, 0, 1, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 4, + 5, 0, 0, 0,108,105,118,101, 0, 3, 0, 0, 0, 0, 0, 0,240, 63, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,198, + 0, 0, 0,200, 0, 0, 0, 0, 6, 0, 7, 3, 0, 0, 0,134, 1,129, 0, 73, +128,129, 1, 30, 0,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,202, 0, 0, 0,204, 0, 0, 0, 1, + 6, 0, 9, 6, 0, 0, 0,132, 1, 0, 0,198, 1, 64, 0, 0, 2, 0, 2,156, +129,128, 1, 73,128,129, 1, 30, 0,128, 0, 1, 0, 0, 0, 4, 5, 0, 0, 0, +102,117,110, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0,206, 0, 0, 0,208, 0, 0, 0, 0, 6, 0, 7, 6, 0, 0, + 0, 87, 0, 64, 2, 22, 0, 0,128,130, 65, 0, 0,130, 1,128, 0, 73,128,129, + 1, 30, 0,128, 0, 1, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0,240, 63, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,210, 0, + 0, 0,212, 0, 0, 0, 0, 6, 0, 10, 7, 0, 0, 0,128, 1,128, 1,192, 1, + 0, 2, 1, 2, 0, 0,160, 1, 0,128, 73, 64,192, 4,159, 65,255,127, 30, 0, +128, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0,240, 63, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,214, 0, 0, 0, +216, 0, 0, 0, 1, 6, 0, 9, 7, 0, 0, 0,132, 1, 0, 0,134, 1, 64, 3, +198, 65, 64, 0, 0, 2, 0, 2,156,129,128, 1, 73,128,129, 1, 30, 0,128, 0, + 2, 0, 0, 0, 4, 8, 0, 0, 0,117,112,118, 97,108,117,101, 0, 4, 5, 0, + 0, 0,102,117,110, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0,218, 0, 0, 0,220, 0, 0, 0, 2, 6, 0, 12, 11, + 0, 0, 0,132, 1, 0, 0,192, 1, 0, 0, 6, 2, 64, 0, 6, 66, 64, 4, 68, + 2,128, 0,134,130, 64, 0,192, 2, 0, 2, 92, 2,128, 1,156,129, 0, 0, 73, +128,129, 1, 30, 0,128, 0, 3, 0, 0, 0, 4, 6, 0, 0, 0,115,116, 97,116, +115, 0, 4, 4, 0, 0, 0,101,110,118, 0, 4, 5, 0, 0, 0,102,117,110, 99, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0,222, 0, 0, 0,226, 0, 0, 0, 2, 6, 0, 13, 15, 0, 0, 0,134, 1,129, + 0,196, 1, 0, 0, 0, 2, 0, 0, 64, 2,128, 0,128, 2, 0, 1,192, 2, 0, + 3, 0, 3,128, 2,220, 65, 0, 3,196, 1,128, 0, 0, 2, 0, 0, 64, 2, 0, + 3,134, 66,129, 0,220,129, 0, 2, 73,192,129, 1, 30, 0,128, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0,232, 0, 0, 0,239, 0, 0, 0, 2, 6, 0, 13, 24, 0, 0, 0,134,193,128, + 0,196, 1, 0, 0, 0, 2, 0, 0, 64, 2,128, 0,128, 2, 0, 1,192, 2, 0, + 3, 0, 3, 0, 2,220, 65, 0, 3,196, 1,128, 0, 0, 2, 0, 3,220,129, 0, + 1, 87, 0,192, 3, 22, 0, 1,128,196, 1,128, 0, 0, 2, 0, 3,220,129, 0, + 1, 23, 64,192, 3, 22, 0, 1,128,198, 65,129, 0, 87,128,192, 3, 22, 64, 0, +128, 6,194, 64, 0, 9,194, 1, 3, 30, 0,128, 0, 4, 0, 0, 0, 4, 6, 0, + 0, 0,116, 97, 98,108,101, 0, 4, 9, 0, 0, 0,117,115,101,114,100, 97,116, + 97, 0, 0, 4, 9, 0, 0, 0,116, 97, 98,108,101,118, 97,108, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,241, 0, 0, + 0,243, 0, 0, 0, 0, 6, 0, 7, 3, 0, 0, 0,138, 1, 0, 0, 73,128,129, + 1, 30, 0,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0,245, 0, 0, 0,250, 0, 0, 0, 2, 6, 0, + 13, 17, 0, 0, 0,134, 1,129, 0,196, 1, 0, 0, 0, 2, 0, 0, 64, 2,128, + 0,128, 2, 0, 1,192, 2, 0, 3, 0, 3,128, 2,220, 65, 0, 3,204, 1,192, + 1, 73,128,129, 3,196, 1,128, 0, 0, 2, 0, 0, 64, 2, 0, 3,134, 66,129, + 0,220,129, 0, 2, 73,192,129, 1, 30, 0,128, 0, 1, 0, 0, 0, 3, 0, 0, + 0, 0, 0, 0,240, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0,255, 0, 0, 0, 1, 1, 0, 0, 1, 6, 0, 14, 11, 0, + 0, 0,132, 1, 0, 0,192, 1, 0, 0, 0, 2,128, 0, 64, 2, 0, 1,128, 2, +128, 1,192, 2, 0, 2, 0, 3, 0, 2, 65, 3, 0, 0,157, 1, 0, 4,158, 1, + 0, 0, 30, 0,128, 0, 1, 0, 0, 0, 4, 4, 0, 0, 0, 85, 78, 77, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, + 1, 0, 0, 5, 1, 0, 0, 0, 6, 0, 6, 2, 0, 0, 0, 73, 0,192, 1, 30, + 0,128, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 1, 0, 0, 10, 1, 0, 0, 1, 6, 0, + 10, 7, 0, 0, 0,132, 1, 0, 0,192, 1, 0, 0, 0, 2, 0, 1, 70, 2,129, + 0,156, 65, 0, 2, 73, 0,192, 1, 30, 0,128, 0, 1, 0, 0, 0, 3, 0, 0, + 0, 0, 0, 0,240, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 12, 1, 0, 0, 31, 1, 0, 0, 2, 6, 0, 16, 44, 0, + 0, 0,198, 1,129, 0, 12, 2, 64, 2, 64, 2,128, 2,129, 2, 0, 0, 32, 2, + 4,128, 6,195,130, 0, 23, 64,192, 3, 22, 64, 0,128,192, 1, 0, 6, 22,192, + 2,128, 87, 64, 64, 6, 22, 64, 2,128, 68, 3, 0, 0,128, 3,128, 3, 92,131, + 0, 1,132, 3, 0, 0,192, 3, 0, 6,156,131, 0, 1, 87,128,131, 6, 22, 64, + 0,128,130, 1,128, 0, 22, 0, 0,128, 31, 66,251,127, 23, 64,192, 3, 22, 64, + 0,128,193,129, 0, 0, 22,128, 3,128, 4, 2,128, 0, 6,194, 64, 4, 12, 2, + 2, 1,154, 65, 0, 0, 22, 64, 0,128, 91, 66,128, 3, 22, 0, 0,128, 66, 2, + 0, 0, 9, 64, 2, 4, 4, 2, 0, 0, 64, 2,128, 3, 28,130, 0, 1, 23, 0, + 65, 4, 22, 0, 0,128,193,129, 0, 0, 73,192,129, 1, 30, 0,128, 0, 5, 0, + 0, 0, 3, 0, 0, 0, 0, 0, 0,240, 63, 0, 4, 1, 0, 0, 0, 0, 4, 5, + 0, 0, 0, 84, 89, 80, 69, 0, 4, 7, 0, 0, 0,110,117,109, 98,101,114, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 33, 1, 0, 0, 39, 1, 0, 0, 1, 6, 0, 8, 16, 0, 0, 0, 25, 0, 1,128, + 22, 0, 3,128,140, 1, 1, 1,198, 65, 64, 0,198,129,129, 3,218, 65, 0, 0, + 22, 64, 0,128,141,129, 64, 3, 22, 64,254,127, 23,128, 0, 3, 22,192, 0,128, +196, 1, 0, 0,198,193,192, 3,204,193, 1, 1, 9, 0,193, 3, 30, 0,128, 0, + 5, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 4, 5, 0, 0, 0,108,105, +118,101, 0, 3, 0, 0, 0, 0, 0, 0,240, 63, 4, 8, 0, 0, 0, 67, 79, 77, + 66, 73, 78, 69, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 41, 1, 0, 0, 43, 1, 0, 0, 1, 6, 0, 10, 13, + 0, 0, 0, 25, 0, 1,128, 22, 64, 2,128, 25, 64, 1,128, 22,192, 1,128,132, + 1, 0, 0,192, 1, 0, 0, 0, 2, 0, 1, 70, 2,129, 0, 90, 66, 0, 0, 22, + 0, 0,128, 70, 66,129, 0,156, 65, 0, 2, 30, 0,128, 0, 1, 0, 0, 0, 3, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 45, 1, 0, 0, 47, 1, 0, 0, 1, 6, 0, 13, + 10, 0, 0, 0,132, 1, 0, 0,192, 1, 0, 0, 0, 2,128, 0, 64, 2, 0, 1, +128, 2,128, 1,192, 2,128, 1, 0, 3,128, 2,157, 1,128, 3,158, 1, 0, 0, + 30, 0,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 51, 1, 0, 0, 53, 1, 0, 0, 1, 6, 0, 13, + 9, 0, 0, 0,132, 1, 0, 0,192, 1, 0, 0, 0, 2,128, 0, 64, 2, 0, 1, +128, 2,128, 1,205, 2, 64, 2, 13, 3,192, 2,156, 65,128, 3, 30, 0,128, 0, + 1, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0,240, 63, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 1, 0, 0, 57, 1, 0, + 0, 1, 6, 0, 13, 9, 0, 0, 0,132, 1, 0, 0,192, 1, 0, 0, 0, 2,128, + 0, 64, 2, 0, 1,128, 2,128, 1,205, 2, 64, 2, 1, 67, 0, 0,156, 65,128, + 3, 30, 0,128, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0,240, 63, 3, 0, + 0, 0, 0, 0, 0,240,191, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 59, 1, 0, 0, 63, 1, 0, 0, 2, 6, 0, 11, 16, + 0, 0, 0, 23, 0, 64, 2, 22, 0, 3,128,132, 1, 0, 0,192, 1, 0, 0, 0, + 2,128, 0, 64, 2, 0, 1,128, 2,128, 1,156,129,128, 2,154, 1, 0, 0, 22, + 0, 1,128,141, 65, 64, 1,196, 1,128, 0,198,129,192, 3,140,193, 1, 3, 9, +192, 64, 3, 30, 0,128, 0, 4, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 64, + 3, 0, 0, 0, 0, 0, 0,240, 63, 4, 8, 0, 0, 0, 67, 79, 77, 66, 73, 78, + 69, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 67, 1, 0, 0, 81, 1, 0, 0, 3, 6, 0, 15, 55, 0, 0, 0, +132, 1, 0, 0,192, 1, 0, 0, 0, 2,128, 0, 64, 2, 0, 1,140, 2,192, 1, +156,193,128, 2, 4, 2,128, 0, 64, 2,128, 3, 28,130, 0, 1, 23, 64, 64, 4, + 22,192, 0,128, 4, 2, 0, 1, 6,130, 64, 4, 12, 2, 2, 1, 9,192, 1, 4, + 6,194,128, 0, 76, 2,192, 1, 70, 66,130, 0,132, 2,128, 0,192, 2, 0, 4, +156,130, 0, 1,196, 2,128, 0, 0, 3,128, 4,220,130, 0, 1, 23, 64, 64, 5, + 22,128, 0,128, 16,195, 64, 4, 23, 0, 65, 6, 22, 0, 1,128, 23, 64,192, 5, + 22, 64, 1,128, 16,195,192, 4, 87, 0, 65, 6, 22,128, 0,128, 1, 67, 1, 0, + 26, 67, 0, 0, 22, 0, 0,128, 1,195, 0, 0, 76,131,193, 1, 73, 0,131, 6, + 23, 64, 64, 5, 22,192, 2,128, 23, 64,192, 5, 22, 64, 2,128, 68, 3,128, 0, +140,195,192, 1,134,131,131, 0, 92,131, 0, 1, 23, 64,192, 6, 22,192, 0,128, + 68, 3, 0, 1, 70,195,193, 6, 76, 67, 3, 1, 9, 0,131, 6, 30, 0,128, 0, + 8, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 64, 4, 7, 0, 0, 0,110,117, +109, 98,101,114, 0, 4, 11, 0, 0, 0, 70, 79, 82, 95, 83, 84, 69, 80, 95, 75, + 0, 3, 0, 0, 0, 0, 0, 0,240, 63, 3, 0, 0, 0, 0, 0, 0, 0, 0, 3, + 0, 0, 0, 0, 0, 0,224, 63, 3, 0, 0, 0, 0, 0, 0, 8, 64, 4, 5, 0, + 0, 0, 84, 89, 80, 69, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 85, 1, 0, 0, 87, 1, 0, 0, 1, 6, 0, 8, 6, + 0, 0, 0,132, 1, 0, 0,134, 1, 64, 3,140,129, 1, 1,198,193,128, 0, 9, +192, 1, 3, 30, 0,128, 0, 1, 0, 0, 0, 4, 5, 0, 0, 0, 84, 89, 80, 69, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 89, 1, 0, 0, 94, 1, 0, 0, 1, 6, 0, 9, 11, 0, 0, 0,134,193,128, + 0,196, 1, 0, 0, 0, 2, 0, 3,220,129, 0, 1, 23, 0,192, 3, 22,192, 0, +128,198, 65, 64, 0, 12,130,192, 1, 6, 2,130, 0,201, 1, 2, 3, 30, 0,128, + 0, 3, 0, 0, 0, 4, 6, 0, 0, 0,116, 97, 98,108,101, 0, 4, 9, 0, 0, + 0,116, 97, 98,108,101,118, 97,108, 0, 3, 0, 0, 0, 0, 0, 0,240, 63, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 98, + 1, 0, 0,110, 1, 0, 0, 3, 6, 0, 14, 24, 0, 0, 0,132, 1, 0, 0, 73, +128,129, 1,134, 1, 64, 0,154, 1, 0, 0, 22, 64, 4,128,132, 1,128, 0,134, + 65, 64, 3,198,129, 64, 0, 0, 2, 0, 2,156,129,128, 1,204,193, 64, 1, 12, +130, 1, 1, 65,194, 0, 0,224,193, 1,128,196, 2, 0, 1, 6,131, 64, 0, 64, + 3, 0, 5,220,130,128, 1, 23, 0,193, 5, 22, 64, 0,128, 9, 64, 65,128, 30, + 0,128, 0,223,129,253,127, 30, 0,128, 0, 6, 0, 0, 0, 4, 8, 0, 0, 0, +110,111, 99,108,111,115,101, 0, 4, 11, 0, 0, 0, 99,108,111,115,117,114,101, +110,117,112, 0, 4, 5, 0, 0, 0,102,117,110, 99, 0, 3, 0, 0, 0, 0, 0, + 0,240, 63, 4, 5, 0, 0, 0, 77, 79, 86, 69, 0, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,112, 1, 0, 0,115, + 1, 0, 0, 0, 6, 0, 13, 13, 0, 0, 0,134, 1, 64, 0,134, 65, 64, 3,193, +129, 0, 0, 0, 2, 0, 2, 65,130, 0, 0,224, 1, 1,128,204,130,130, 1,205, +130,192, 5, 12,131, 2, 3, 6, 3, 3, 0, 73, 0,131, 5,223, 65,254,127, 30, + 0,128, 0, 3, 0, 0, 0, 4, 6, 0, 0, 0,115,116, 97,116,115, 0, 4, 7, + 0, 0, 0,112, 97,114, 97,109,115, 0, 3, 0, 0, 0, 0, 0, 0,240, 63, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,119, + 1, 0, 0,172, 1, 0, 0, 9, 1, 0, 22,115, 0, 0, 0, 70, 0, 64, 0, 90, + 0, 0, 0, 22, 0, 0,128, 30, 0,128, 0, 70, 64, 64, 0,132, 0, 0, 0,134, +128, 64, 1,192, 0,128, 0,156,128, 0, 1,154, 64, 0, 0, 22,192, 0,128,196, + 0, 0, 0,198,192,192, 1,198, 0,193, 1,222, 0, 0, 1,198, 64, 65, 1, 4, + 1,128, 0, 6, 65, 65, 2, 88,192, 0, 2, 22,192, 4,128,198,128, 65, 1, 4, + 1,128, 0, 6,129, 65, 2, 88,192, 0, 2, 22,128, 3,128,198,192, 65, 1, 4, + 1,128, 0, 6,193, 65, 2, 88,192, 0, 2, 22, 64, 2,128,198, 0, 66, 1, 4, + 1,128, 0, 6, 1, 66, 2, 88,192, 0, 2, 22, 0, 1,128,198, 64, 66, 1, 4, + 1,128, 0, 6, 65, 66, 2, 24,192, 0, 2, 22,192, 0,128,196, 0, 0, 0,198, +192,192, 1,198,128,194, 1,222, 0, 0, 1,196, 0, 0, 1, 0, 1,128, 0,220, +128, 0, 1, 9, 0,195,133, 9,128, 0,129, 9,192,128,134, 10, 65, 0, 0, 70, +193, 67, 1,132, 1,128, 1, 9,129,129, 2, 9, 0, 1,135, 10, 1, 0, 0, 65, + 1, 4, 0,134,193, 65, 1,193, 1, 4, 0, 96,129, 0,128, 77, 2, 68, 4,134, + 2, 2, 0, 9,129,130, 4, 95,193,254,127, 65, 65, 4, 0,129,129, 4, 0,193, + 65, 4, 0, 96,193, 1,128, 68, 2, 0, 2,128, 2,128, 0,192, 2, 0, 4, 92, +194,128, 1,154, 66, 0, 0, 22, 0, 0,128, 22, 64, 0,128, 9, 65, 2, 4, 95, +129,253,127, 65, 1, 4, 0,134, 65, 65, 1,193, 1, 4, 0, 96, 65, 5,128, 70, + 2,130, 1, 90, 2, 0, 0, 22,128, 3,128, 68, 2,128, 2,128, 2,128, 0,192, + 2, 0, 4, 92,130,129, 1,132, 3, 0, 3,134, 67, 2, 7,192, 3, 0, 0, 0, + 4, 0, 2, 64, 4, 0, 4,128, 4, 0, 5,192, 4,128, 5, 0, 5, 0, 6, 64, + 5,128, 4,156, 67, 0, 4, 22,192, 0,128, 68, 2,128, 3, 70,194,196, 4, 76, + 66, 2, 4, 9, 0,197, 4, 95, 1,250,127, 70,193, 66, 0, 90, 1, 0, 0, 22, +128, 0,128, 68, 1, 0, 4, 70, 65,197, 2, 9, 0,195, 2, 9,128,197,133, 9, +128, 69,129, 9,128,197,134, 9,128, 69,135, 30, 0,128, 0, 23, 0, 0, 0, 4, + 6, 0, 0, 0,100,101,111,112,116, 0, 4, 5, 0, 0, 0,102,117,110, 99, 0, + 4, 6, 0, 0, 0,115,116, 97,116,115, 0, 4, 7, 0, 0, 0,115,116, 97,116, +117,115, 0, 4, 15, 0, 0, 0, 67, 79, 77, 80, 73, 76, 69, 82, 95, 69, 82, 82, + 79, 82, 0, 4, 10, 0, 0, 0, 98,121,116,101, 99,111,100,101,115, 0, 4, 11, + 0, 0, 0,115,116, 97, 99,107,115,108,111,116,115, 0, 4, 7, 0, 0, 0,112, + 97,114, 97,109,115, 0, 4, 7, 0, 0, 0, 99,111,110,115,116,115, 0, 4, 5, + 0, 0, 0,115,117, 98,115, 0, 4, 9, 0, 0, 0, 84, 79, 79, 76, 65, 82, 71, + 69, 0, 4, 8, 0, 0, 0,110,111, 99,108,111,115,101, 0, 1, 1, 4, 5, 0, + 0, 0,108,105,118,101, 0, 4, 9, 0, 0, 0,116, 97, 98,108,101,118, 97,108, + 0, 4, 4, 0, 0, 0,101,110,118, 0, 3, 0, 0, 0, 0, 0, 0,240, 63, 3, + 0, 0, 0, 0, 0, 0,240,191, 3, 0, 0, 0, 0, 0, 0,112,192, 4, 8, 0, + 0, 0, 67, 79, 77, 66, 73, 78, 69, 0, 1, 0, 4, 8, 0, 0, 0, 78, 79, 67, + 76, 79, 83, 69, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0,179, 1, 0, 0,189, 1, 0, 0, 6, 1, 0, 8, 28, 0, + 0, 0, 68, 0, 0, 0, 25, 0,192, 0, 22, 0, 0,128, 30, 0,128, 0, 68, 0, +128, 0,132, 0, 0, 1,192, 0, 0, 0, 92,192,128, 1, 90, 64, 0, 0, 22, 64, + 3,128,197, 64, 0, 0,198,128,192, 1,203,192,192, 1, 65, 1, 1, 0,128, 1, + 0, 1,193, 65, 1, 0,220, 64,128, 2,196, 0,128, 1,198,128,193, 1, 4, 1, + 0, 2,220, 64, 0, 1,195, 0,128, 1,200, 0,128, 2, 22,128, 0,128,154, 0, + 0, 0, 22, 0, 0,128,158, 0, 0, 1, 30, 0,128, 0, 7, 0, 0, 0, 3, 0, + 0, 0, 0, 0, 0, 0, 0, 4, 3, 0, 0, 0,105,111, 0, 4, 7, 0, 0, 0, +115,116,100,101,114,114, 0, 4, 6, 0, 0, 0,119,114,105,116,101, 0, 4, 27, + 0, 0, 0, 10, 69, 82, 82, 79, 82, 58, 32,106,105,116, 46,111,112,116, 32,100, +105,115, 97, 98,108,101,100, 58, 32, 0, 4, 2, 0, 0, 0, 10, 0, 4, 7, 0, + 0, 0, 97,116,116, 97, 99,104, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0,192, 1, 0, 0,203, 1, 0, 0, 1, 1, 0, + 9, 38, 0, 0, 0, 69, 0, 0, 0, 70, 64,192, 0,128, 0, 0, 0,193,128, 0, + 0, 92,192,128, 1, 90, 64, 0, 0, 22, 0, 0,128, 64, 0, 0, 0,193,192, 0, + 0, 0, 1,128, 0, 85, 0,129, 1,196, 0, 0, 0, 5, 1, 1, 0, 64, 1,128, + 0,220,192,128, 1,218, 64, 0, 0, 22, 0, 4,128, 69, 1, 0, 0, 70, 65,193, + 2,128, 1, 0, 2,193,129, 1, 0, 1,194, 1, 0, 92,129, 0, 2, 87, 0,194, + 2, 22,192, 0,128, 69, 65, 2, 0,128, 1, 0, 2,193,129, 2, 0, 92, 65,128, + 1, 65,193, 2, 0,128, 1,128, 0,193, 1, 3, 0, 85,193,129, 2, 94, 1, 0, + 1, 70, 65, 67, 2,128, 1, 0, 1, 92, 65, 0, 1, 30, 0,128, 0, 14, 0, 0, + 0, 4, 7, 0, 0, 0,115,116,114,105,110,103, 0, 4, 6, 0, 0, 0,109, 97, +116, 99,104, 0, 4, 12, 0, 0, 0, 94, 40, 46, 45, 41, 61, 40, 46, 42, 41, 36, + 0, 4, 9, 0, 0, 0,106,105,116, 46,111,112,116, 95, 0, 4, 8, 0, 0, 0, +114,101,113,117,105,114,101, 0, 4, 4, 0, 0, 0,115,117, 98, 0, 3, 0, 0, + 0, 0, 0, 0,240, 63, 3, 0, 0, 0, 0, 0, 0, 28, 64, 4, 8, 0, 0, 0, +109,111,100,117,108,101, 32, 0, 4, 6, 0, 0, 0,101,114,114,111,114, 0, 3, + 0, 0, 0, 0, 0, 0, 0, 0, 4, 25, 0, 0, 0,111,112,116,105,109,105,122, +101,114, 32, 97,100,100, 45,111,110, 32,109,111,100,117,108,101, 32, 0, 4, 11, + 0, 0, 0, 32,110,111,116, 32,102,111,117,110,100, 0, 4, 6, 0, 0, 0,115, +116, 97,114,116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0,206, 1, 0, 0,235, 1, 0, 0, 8, 1, 0, 6, 59, 0, 0, + 0, 68, 0, 0, 0, 90, 64, 0, 0, 22,128, 1,128, 68, 0,128, 0, 70, 0,192, + 0,132, 0, 0, 1,196, 0,128, 1, 92, 64,128, 1, 66, 0,128, 0, 72, 0, 0, + 0, 87, 64, 64, 0, 22, 64, 0,128, 23,128, 64, 0, 22,128, 0,128, 68, 0,128, + 2, 72, 0, 0, 2, 22, 64, 7,128, 69,192, 0, 0,128, 0, 0, 0, 92,128, 0, + 1, 90, 0, 0, 0, 22,128, 2,128, 88, 0,193, 0, 22,128, 0,128,144, 64,193, + 0, 87, 0, 65, 1, 22,192, 0,128,133,128, 1, 0,193,192, 1, 0, 1, 1, 1, + 0,156, 64,128, 1, 72, 0, 0, 2, 22, 64, 3,128,132, 0, 0, 2, 23, 0, 66, + 1, 22, 64, 0,128,132, 0,128, 2,136, 0, 0, 2,132, 0, 0, 3,192, 0, 0, + 0,156,128, 0, 1,154, 0, 0, 0, 22,192, 0,128,197,128, 1, 0, 0, 1, 0, + 1, 65, 1, 1, 0,220, 64,128, 1, 68, 0,128, 3, 90, 64, 0, 0, 22,192, 1, +128, 68, 0, 0, 2, 25, 64,128,132, 22, 0, 1,128, 68, 0, 0, 3,129,128, 2, + 0, 92, 64, 0, 1, 66, 0,128, 0, 72, 0,128, 3, 30, 0,128, 0, 11, 0, 0, + 0, 4, 7, 0, 0, 0, 97,116,116, 97, 99,104, 0, 0, 4, 1, 0, 0, 0, 0, + 4, 9, 0, 0, 0,116,111,110,117,109, 98,101,114, 0, 3, 0, 0, 0, 0, 0, + 0, 0, 0, 3, 0, 0, 0, 0, 0, 0,240, 63, 4, 6, 0, 0, 0,101,114,114, +111,114, 0, 4, 20, 0, 0, 0, 98, 97,100, 32,111,112,116,105,109,105,122,101, +114, 32,108,101,118,101,108, 0, 3, 0, 0, 0, 0, 0, 0,240,191, 3, 0, 0, + 0, 0, 0, 0, 0, 64, 4, 7, 0, 0, 0,105,110,108,105,110,101, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,242, 1, + 0, 0,244, 1, 0, 0, 1, 1, 0, 2, 2, 0, 0, 0, 8, 0, 0, 0, 30, 0, +128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0,246, 1, 0, 0,248, 1, 0, 0, 1, 0, 0, 2, 3, 0, + 0, 0, 4, 0, 0, 0, 30, 0, 0, 1, 30, 0,128, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, +}; diff --git a/src/xrServerEntities/opt_inline.lua.h b/src/xrServerEntities/opt_inline.lua.h new file mode 100644 index 000000000..1466d013f --- /dev/null +++ b/src/xrServerEntities/opt_inline.lua.h @@ -0,0 +1,372 @@ +/* code automatically generated by bin2c -- DO NOT EDIT */ +/* #include'ing this file in a C program is equivalent to calling + if (luaL_loadfile(L,"luac.out")==0) lua_pcall(L, 0, 0, 0); +*/ +/* luac.out */ +static const unsigned char opt_inline_lua_binary[] = { + 27, 76,117, 97, 81, 0, 1, 4, 4, 4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 2, 31,240, 1, 0, 0, 5, 0, 0, 0, 65, 64, 0, 0, + 28,128, 0, 1, 69,128, 0, 0,134,192, 64, 0, 87, 0, 65, 1, 22, 0, 0,128, +130, 64, 0, 0,130, 0,128, 0,193, 64, 1, 0, 92, 64,128, 1, 69, 0, 0, 0, +129,128, 1, 0, 92,128, 0, 1,133,192, 1, 0,197, 0, 2, 0, 5, 65, 2, 0, + 70,129,194, 0,134,193,194, 0,197, 1, 3, 0,198, 65,195, 3, 5, 2, 3, 0, + 6,130, 67, 4, 69, 2, 3, 0, 70,194,195, 4,134, 2, 68, 0,194, 2,128, 0, + 2, 3,128, 0,156, 66,128, 1,138, 2, 0, 0,197, 66, 4, 0, 10, 3, 0, 0, +100, 3, 0, 0, 0, 0, 0, 6,131, 3, 0, 8,100, 68, 0, 0, 0, 0,128, 1, + 0, 0,128, 7, 0, 0, 0, 6, 0, 0, 0, 7, 0, 0, 0, 8,164,132, 0, 0, + 0, 0, 0, 6, 0, 0, 0, 7, 0, 0, 0, 8,228,196, 0, 0, 36, 5, 1, 0, + 0, 0,128, 0, 0, 0,128, 2, 0, 0,128, 5,100, 69, 1, 0, 0, 0, 0, 1, + 0, 0, 0, 2,131, 5, 0, 11,197,133, 4, 0, 1,196, 4, 0,192, 3,128, 11, +128, 3, 0, 11,128, 5,128, 8,193, 5, 5, 0, 1, 70, 5, 0, 65,134, 5, 0, +164,134, 1, 0, 0, 0,128, 10, 0, 0, 0, 10,156, 69,128, 2,128, 5,128, 8, +193,197, 5, 0, 1, 6, 6, 0, 65,134, 5, 0,164,198, 1, 0, 0, 0, 0, 1, + 0, 0,128, 1, 0, 0, 0, 10,156, 69,128, 2, 3, 4, 0, 8,128, 5,128, 8, +193, 69, 2, 0, 1, 70, 6, 0, 65,134, 6, 0,164, 6, 2, 0, 0, 0,128, 10, +156, 69,128, 2,128, 5,128, 8,193,197, 1, 0, 1,198, 6, 0, 65, 6, 7, 0, +156, 69, 0, 2,128, 5,128, 8,193, 69, 7, 0, 1,134, 5, 0, 65, 6, 7, 0, +156, 69, 0, 2,128, 5,128, 8,193,133, 7, 0, 1, 6, 7, 0, 65,198, 7, 0, +128, 6,128, 9,156, 69,128, 2,128, 5,128, 8,193, 5, 8, 0, 1, 70, 8, 0, + 65, 70, 6, 0,156, 69, 0, 2,128, 5,128, 8,193, 5, 2, 0, 1, 6, 7, 0, + 65,134, 8, 0,164, 70, 2, 0, 0, 0, 0, 1, 0, 0,128, 1,156, 69,128, 2, +128, 5,128, 8,193,197, 8, 0, 1, 6, 7, 0, 65, 6, 9, 0,128, 6,128, 9, +156, 69,128, 2,128, 5,128, 8,193,133, 0, 0, 1, 70, 9, 0, 65,134, 9, 0, +164,134, 2, 0,156, 69,128, 2,128, 5,128, 8,193,197, 9, 0, 1, 6, 10, 0, + 65, 70, 10, 0,156, 69, 0, 2,128, 5,128, 8,193,133, 10, 0, 1,198, 6, 0, + 65, 6, 7, 0,156, 69, 0, 2,128, 5,128, 8,193, 5, 0, 0, 1,134, 5, 0, + 65,198, 6, 0,156, 69, 0, 2,129,197, 10, 0,197,197, 10, 0, 1, 4, 11, 0, +192, 3,128, 11,128, 3, 0, 11,218, 3, 0, 0, 22, 0, 4,128,128, 5,128, 8, +193, 69, 11, 0, 1, 70, 9, 0, 65,134, 11, 0,156, 69, 0, 2,128, 5,128, 8, +193,197, 11, 0, 1, 70, 9, 0, 65, 6, 12, 0,164,198, 2, 0,156, 69,128, 2, + 3, 4, 0, 8,128, 5,128, 8,193, 69, 12, 0, 1,134, 12, 0, 65,198, 12, 0, +156, 69, 0, 2,129, 5, 3, 0,197, 5, 3, 0, 1, 4, 13, 0,192, 3,128, 11, +128, 3, 0, 11,218, 3, 0, 0, 22, 64, 17,128,128, 5,128, 8,193, 69, 13, 0, + 1, 6, 10, 0, 65,198, 6, 0,156, 69, 0, 2,128, 5,128, 8,193, 69, 3, 0, + 1,198, 6, 0, 65,134, 13, 0,156, 69, 0, 2,128, 5,128, 8,193,197, 13, 0, + 1,198, 6, 0, 65, 6, 14, 0,156, 69, 0, 2, 3, 4, 0, 8,128, 5,128, 8, +193, 69, 14, 0, 1, 6, 10, 0, 65,198, 6, 0,164, 6, 3, 0,156, 69,128, 2, +128, 5,128, 8,193,133, 14, 0, 1,198, 6, 0, 65,198, 14, 0,156, 69, 0, 2, +128, 5,128, 8,193, 5, 15, 0, 1,198, 6, 0, 65,198, 6, 0,156, 69, 0, 2, +128, 5,128, 8,193, 69, 15, 0, 1,198, 6, 0, 65,198, 6, 0,156, 69, 0, 2, +128, 5,128, 8,193,133, 15, 0, 1,198, 6, 0, 65,198, 6, 0,156, 69, 0, 2, +128, 5,128, 8,193,197, 15, 0, 1,198, 6, 0, 65, 6, 16, 0,156, 69, 0, 2, +128, 5,128, 8,193, 69, 16, 0, 1, 70, 9, 0, 65,134, 16, 0,164, 70, 3, 0, +156, 69,128, 2,128, 5,128, 8,193,133, 3, 0, 1, 70, 9, 0, 65,198, 16, 0, +164,134, 3, 0,156, 69,128, 2,128, 5,128, 8,193,197, 3, 0, 1,198, 14, 0, + 65, 6, 17, 0,156, 69, 0, 2,128, 5,128, 8,193, 69, 17, 0, 1,134, 17, 0, + 65,198, 17, 0,164,198, 3, 0,156, 69,128, 2,129, 5, 18, 0,197, 5, 18, 0, + 1, 68, 18, 0,192, 3,128, 11,128, 3, 0, 11,218, 3, 0, 0, 22,192, 5,128, +128, 5,128, 8,193,133, 18, 0, 1,198, 18, 0, 65, 6, 19, 0,156, 69, 0, 2, +128, 5,128, 8,193, 69, 19, 0, 1, 6, 7, 0, 65,134, 5, 0,164, 6, 4, 0, + 0, 0, 0, 1, 0, 0,128, 1,156, 69,128, 2,128, 5,128, 8,193,133, 19, 0, + 1, 6, 10, 0, 65,134, 5, 0,156, 69, 0, 2, 3, 4, 0, 8,128, 5,128, 8, +193,197, 19, 0, 1,198, 6, 0, 65, 6, 20, 0,156, 69, 0, 2,129, 69, 20, 0, +197, 69, 20, 0, 1,132, 20, 0,192, 3,128, 11,128, 3, 0, 11,218, 3, 0, 0, + 22,128, 36,128,128, 5,128, 8,193,197, 20, 0, 1, 6, 21, 0, 65, 6, 21, 0, +156, 69, 0, 2,128, 5,128, 8,193, 69, 21, 0, 1, 6, 21, 0, 65, 6, 21, 0, +156, 69, 0, 2,128, 5,128, 8,193,133, 21, 0, 1, 6, 21, 0, 65, 6, 21, 0, +156, 69, 0, 2,128, 5,128, 8,193,197, 21, 0, 1, 6, 21, 0, 65, 6, 21, 0, +156, 69, 0, 2,128, 5,128, 8,193, 5, 22, 0, 1, 6, 21, 0, 65, 6, 21, 0, +156, 69, 0, 2,128, 5,128, 8,193, 69, 22, 0, 1, 6, 21, 0, 65, 6, 21, 0, +156, 69, 0, 2,128, 5,128, 8,193,133, 22, 0, 1, 6, 21, 0, 65, 6, 21, 0, +156, 69, 0, 2,128, 5,128, 8,193,197, 22, 0, 1, 6, 21, 0, 65, 6, 21, 0, +156, 69, 0, 2,128, 5,128, 8,193, 5, 23, 0, 1, 6, 21, 0, 65, 6, 21, 0, +156, 69, 0, 2,128, 5,128, 8,193, 69, 23, 0, 1, 6, 21, 0, 65, 6, 21, 0, +156, 69, 0, 2,128, 5,128, 8,193,133, 23, 0, 1, 6, 21, 0, 65, 6, 21, 0, +156, 69, 0, 2,128, 5,128, 8,193,197, 23, 0, 1, 6, 21, 0, 65, 6, 21, 0, +156, 69, 0, 2,128, 5,128, 8,193, 5, 24, 0, 1, 6, 10, 0, 65, 6, 21, 0, +156, 69, 0, 2,128, 5,128, 8,193, 69, 24, 0, 1, 6, 10, 0, 65, 6, 21, 0, +156, 69, 0, 2,128, 5,128, 8,193,133, 24, 0, 1, 6, 7, 0, 65, 6, 21, 0, +128, 6,128, 9,156, 69,128, 2,128, 5,128, 8,193,197, 24, 0, 1, 6, 21, 0, + 65, 6, 21, 0,156, 69, 0, 2,128, 5,128, 8,193, 5, 25, 0, 1, 6, 7, 0, + 65, 70, 25, 0,164, 70, 4, 0,156, 69,128, 2,128, 5,128, 8,193,133, 25, 0, + 1, 6, 21, 0, 65, 70, 25, 0,156, 69, 0, 2, 3, 4, 0, 8,128, 5,128, 8, +193,197, 25, 0, 1, 6, 7, 0, 65, 6, 26, 0,128, 6,128, 9,156, 69,128, 2, +128, 5,128, 8,193, 69, 26, 0, 1, 6, 7, 0, 65, 6, 26, 0,128, 6,128, 9, +156, 69,128, 2,128, 5,128, 8,193,133, 26, 0, 1, 6, 21, 0, 65, 6, 21, 0, +156, 69, 0, 2,128, 5,128, 8,193,197, 26, 0, 1, 6, 21, 0, 65, 6, 21, 0, +156, 69, 0, 2,128, 5,128, 8,193, 5, 27, 0, 1, 70, 27, 0, 65, 6, 21, 0, +156, 69, 0, 2,128, 5,128, 8,193,133, 27, 0, 1,198, 27, 0, 65, 6, 21, 0, +156, 69, 0, 2,128, 5,128, 8,193, 5, 28, 0, 1, 6, 21, 0, 65, 70, 25, 0, +156, 69, 0, 2,128, 5,128, 8,193, 69, 28, 0, 1, 6, 7, 0, 65,198, 27, 0, +128, 6,128, 9,156, 69,128, 2,128, 5,128, 8,193,133, 28, 0, 1,198, 18, 0, + 65, 6, 10, 0,156, 69, 0, 2,128, 5,128, 8,193,197, 28, 0, 1, 6, 21, 0, + 65, 6, 29, 0,164,134, 4, 0,156, 69,128, 2,129, 69, 29, 0,197, 69, 29, 0, + 3, 4, 0, 8,192, 3,128, 11,128, 3, 0, 11,218, 3, 0, 0, 22, 64, 2,128, +128, 5,128, 8,193,133, 29, 0, 1,198, 29, 0, 65, 6, 30, 0,156, 69, 0, 2, +128, 5,128, 8,193, 69, 30, 0, 1,198, 6, 0, 65,198, 18, 0,156, 69, 0, 2, +138, 5, 2, 0,137,197, 94,189,137, 69, 95,190,137,197, 95,191,137, 5, 96,134, +137, 69, 96,164,137,197, 96,193,137, 69, 97,194,137,197, 97,195,202, 69, 2, 0, +201, 5,226,144,201, 69,226,141,201,133, 98,139,201,197,226,153,201, 69, 99,198, +201,197, 99,199,201, 5,100,170,201, 5,100,148,201,133,228,200, 10,198, 1, 0, + 9,198,228,144, 9,198,210,141, 74, 6, 0, 0, 9, 70, 6,139, 9, 6,101,170, + 9, 70,101,148,100,198, 4, 0, 9, 70, 6,203, 69, 70, 4, 0, 9, 70, 6,153, +100, 6, 5, 0, 0, 0,128, 4, 0, 0,128, 11,164, 70, 5, 0, 0, 0, 0, 11, + 0, 0, 0, 1, 0, 0, 0, 4, 0, 0,128, 12, 0, 0,128, 3, 0, 0, 0, 12, + 0, 0,128, 2,228,134, 5, 0, 0, 0,128, 2, 0, 0, 0, 1, 0, 0, 0, 6, + 0, 0, 0, 13, 36,199, 5, 0, 0, 0,128, 13, 69,199, 37, 0,165, 7, 0, 0, + 92, 71, 0, 0, 71, 3, 38, 0, 7, 71, 38, 0, 30, 0,128, 0,154, 0, 0, 0, + 4, 8, 0, 0, 0,114,101,113,117,105,114,101, 0, 4, 4, 0, 0, 0,106,105, +116, 0, 4, 7, 0, 0, 0, 97,115,115,101,114,116, 0, 4, 12, 0, 0, 0,118, +101,114,115,105,111,110, 95,110,117,109, 0, 3, 0, 0, 0, 0, 0,188,195, 64, + 4, 37, 0, 0, 0, 76,117, 97, 74, 73, 84, 32, 99,111,114,101, 47,108,105, 98, +114, 97,114,121, 32,118,101,114,115,105,111,110, 32,109,105,115,109, 97,116, 99, +104, 0, 4, 9, 0, 0, 0,106,105,116, 46,117,116,105,108, 0, 4, 5, 0, 0, + 0,116,121,112,101, 0, 4, 7, 0, 0, 0,114, 97,119,103,101,116, 0, 4, 5, + 0, 0, 0,110,101,120,116, 0, 4, 6, 0, 0, 0,104,105,110,116,115, 0, 4, + 7, 0, 0, 0,102,104,105,110,116,115, 0, 4, 7, 0, 0, 0,115,116,114,105, +110,103, 0, 4, 4, 0, 0, 0,115,117, 98, 0, 4, 6, 0, 0, 0,109, 97,116, + 99,104, 0, 4, 5, 0, 0, 0,103,115,117, 98, 0, 4, 4, 0, 0, 0,111,102, +102, 0, 4, 15, 0, 0, 0, 99,111,108,108,101, 99,116,103, 97,114, 98, 97,103, +101, 0, 4, 3, 0, 0, 0, 95, 71, 0, 3, 0, 0, 0, 0, 0, 0,240, 64, 4, + 6, 0, 0, 0,112, 97,105,114,115, 0, 4, 4, 0, 0, 0, 46, 46, 48, 0, 4, + 2, 0, 0, 0, 84, 0, 4, 7, 0, 0, 0,105,112, 97,105,114,115, 0, 4, 4, + 0, 0, 0, 46, 46, 73, 0, 4, 3, 0, 0, 0, 46, 46, 0, 4, 4, 0, 0, 0, + 84, 46, 63, 0, 4, 2, 0, 0, 0, 83, 0, 4, 2, 0, 0, 0, 46, 0, 4, 13, + 0, 0, 0,103,101,116,109,101,116, 97,116, 97, 98,108,101, 0, 4, 13, 0, 0, + 0,115,101,116,109,101,116, 97,116, 97, 98,108,101, 0, 4, 4, 0, 0, 0, 84, + 84, 63, 0, 4, 9, 0, 0, 0,114, 97,119,101,113,117, 97,108, 0, 4, 2, 0, + 0, 0, 66, 0, 4, 3, 0, 0, 0, 84, 46, 0, 4, 7, 0, 0, 0,114, 97,119, +115,101,116, 0, 4, 4, 0, 0, 0, 84, 46, 46, 0, 4, 2, 0, 0, 0, 42, 0, + 4, 4, 0, 0, 0, 46, 46, 42, 0, 4, 9, 0, 0, 0,116,111,110,117,109, 98, +101,114, 0, 4, 2, 0, 0, 0, 73, 0, 4, 4, 0, 0, 0, 46, 73, 63, 0, 4, + 9, 0, 0, 0,116,111,115,116,114,105,110,103, 0, 4, 10, 0, 0, 0, 99,111, +114,111,117,116,105,110,101, 0, 3, 0, 0, 0, 0, 0, 0, 0, 65, 4, 6, 0, + 0, 0,121,105,101,108,100, 0, 4, 3, 0, 0, 0, 46, 42, 0, 4, 7, 0, 0, + 0,114,101,115,117,109,101, 0, 4, 4, 0, 0, 0, 82, 46, 42, 0, 4, 5, 0, + 0, 0,119,114, 97,112, 0, 4, 2, 0, 0, 0, 67, 0, 4, 2, 0, 0, 0, 70, + 0, 3, 0, 0, 0, 0, 0, 0, 8, 65, 4, 4, 0, 0, 0,108,101,110, 0, 4, + 5, 0, 0, 0, 83, 73, 73, 63, 0, 4, 5, 0, 0, 0, 99,104, 97,114, 0, 4, + 3, 0, 0, 0, 73, 42, 0, 4, 5, 0, 0, 0, 98,121,116,101, 0, 4, 4, 0, + 0, 0,114,101,112, 0, 4, 3, 0, 0, 0, 83, 73, 0, 4, 8, 0, 0, 0,114, +101,118,101,114,115,101, 0, 4, 6, 0, 0, 0,117,112,112,101,114, 0, 4, 6, + 0, 0, 0,108,111,119,101,114, 0, 4, 7, 0, 0, 0,102,111,114,109, 97,116, + 0, 4, 4, 0, 0, 0, 83, 46, 42, 0, 4, 5, 0, 0, 0,102,105,110,100, 0, + 4, 7, 0, 0, 0, 83, 83, 73, 63, 46, 63, 0, 4, 5, 0, 0, 0, 83, 83, 73, + 63, 0, 4, 6, 0, 0, 0, 83, 83, 71, 73, 63, 0, 4, 7, 0, 0, 0,103,109, + 97,116, 99,104, 0, 4, 4, 0, 0, 0, 67, 48, 48, 0, 4, 3, 0, 0, 0, 83, + 83, 0, 4, 6, 0, 0, 0,116, 97, 98,108,101, 0, 3, 0, 0, 0, 0, 0, 0, + 16, 65, 4, 7, 0, 0, 0,105,110,115,101,114,116, 0, 4, 1, 0, 0, 0, 0, + 4, 5, 0, 0, 0, 84, 73, 63, 46, 0, 4, 7, 0, 0, 0,114,101,109,111,118, +101, 0, 4, 5, 0, 0, 0,103,101,116,110, 0, 4, 7, 0, 0, 0, 99,111,110, + 99, 97,116, 0, 4, 8, 0, 0, 0, 84, 83, 63, 73, 63, 73, 63, 0, 4, 5, 0, + 0, 0,109, 97,116,104, 0, 3, 0, 0, 0, 0, 0, 0, 20, 65, 4, 4, 0, 0, + 0,108,111,103, 0, 4, 2, 0, 0, 0, 78, 0, 4, 6, 0, 0, 0,108,111,103, + 49, 48, 0, 4, 4, 0, 0, 0,101,120,112, 0, 4, 5, 0, 0, 0,115,105,110, +104, 0, 4, 5, 0, 0, 0, 99,111,115,104, 0, 4, 5, 0, 0, 0,116, 97,110, +104, 0, 4, 5, 0, 0, 0, 97,115,105,110, 0, 4, 5, 0, 0, 0, 97, 99,111, +115, 0, 4, 5, 0, 0, 0, 97,116, 97,110, 0, 4, 4, 0, 0, 0,115,105,110, + 0, 4, 4, 0, 0, 0, 99,111,115, 0, 4, 4, 0, 0, 0,116, 97,110, 0, 4, + 5, 0, 0, 0, 99,101,105,108, 0, 4, 6, 0, 0, 0,102,108,111,111,114, 0, + 4, 4, 0, 0, 0, 97, 98,115, 0, 4, 5, 0, 0, 0,115,113,114,116, 0, 4, + 5, 0, 0, 0,102,109,111,100, 0, 4, 3, 0, 0, 0, 78, 78, 0, 4, 6, 0, + 0, 0, 97,116, 97,110, 50, 0, 4, 4, 0, 0, 0,109,105,110, 0, 4, 4, 0, + 0, 0, 78, 78, 42, 0, 4, 4, 0, 0, 0,109, 97,120, 0, 4, 4, 0, 0, 0, +100,101,103, 0, 4, 4, 0, 0, 0,114, 97,100, 0, 4, 5, 0, 0, 0,109,111, +100,102, 0, 4, 3, 0, 0, 0, 73, 78, 0, 4, 6, 0, 0, 0,102,114,101,120, +112, 0, 4, 3, 0, 0, 0, 78, 73, 0, 4, 4, 0, 0, 0,112,111,119, 0, 4, + 6, 0, 0, 0,108,100,101,120,112, 0, 4, 11, 0, 0, 0,114, 97,110,100,111, +109,115,101,101,100, 0, 4, 7, 0, 0, 0,114, 97,110,100,111,109, 0, 4, 5, + 0, 0, 0, 73, 63, 73, 63, 0, 4, 3, 0, 0, 0,105,111, 0, 4, 6, 0, 0, + 0,108,105,110,101,115, 0, 4, 5, 0, 0, 0, 67, 48, 48, 83, 0, 4, 3, 0, + 0, 0, 83, 63, 0, 4, 5, 0, 0, 0,114,101, 97,100, 0, 4, 4, 0, 0, 0, +110,105,108, 0, 4, 2, 0, 0, 0, 48, 0, 4, 8, 0, 0, 0, 98,111,111,108, +101, 97,110, 0, 4, 2, 0, 0, 0, 98, 0, 4, 7, 0, 0, 0,110,117,109, 98, +101,114, 0, 4, 2, 0, 0, 0,110, 0, 4, 2, 0, 0, 0,115, 0, 4, 2, 0, + 0, 0,116, 0, 4, 9, 0, 0, 0,102,117,110, 99,116,105,111,110, 0, 4, 2, + 0, 0, 0,102, 0, 4, 9, 0, 0, 0,117,115,101,114,100, 97,116, 97, 0, 4, + 2, 0, 0, 0,117, 0, 4, 7, 0, 0, 0,116,104,114,101, 97,100, 0, 4, 2, + 0, 0, 0,114, 0, 4, 5, 0, 0, 0, 91, 98, 48, 93, 0, 4, 5, 0, 0, 0, + 91,115, 48, 93, 0, 4, 5, 0, 0, 0, 91,116, 48, 93, 0, 4, 5, 0, 0, 0, + 91,102, 48, 93, 0, 4, 2, 0, 0, 0, 85, 0, 4, 5, 0, 0, 0, 91,117, 48, + 93, 0, 4, 2, 0, 0, 0, 82, 0, 4, 5, 0, 0, 0, 91,114, 48, 93, 0, 4, + 5, 0, 0, 0, 91,110, 48, 93, 0, 4, 2, 0, 0, 0, 71, 0, 4, 7, 0, 0, + 0, 91,115,116,102, 48, 93, 0, 1, 1, 3, 0, 0, 0, 0, 0, 0,224, 63, 3, + 0, 0, 0, 0, 0, 0,240, 63, 4, 2, 0, 0, 0, 76, 0, 4, 7, 0, 0, 0, +109,111,100,117,108,101, 0, 4, 8, 0, 0, 0,103,101,116,110, 97,109,101, 0, + 4, 6, 0, 0, 0,115,116, 97,114,116, 0, 24, 0, 0, 0, 0, 0, 0, 0, 38, + 0, 0, 0, 52, 0, 0, 0, 1, 2, 0, 8, 24, 0, 0, 0,132, 0, 0, 0,134, + 0, 0, 1,154, 0, 0, 0, 22,192, 2,128,198, 0, 64, 1, 6, 65, 64, 1,218, + 0, 0, 0, 22, 64, 1,128, 64, 1,128, 1,129,129, 0, 0,192, 1, 0, 2, 85, +193,129, 2, 94, 1, 0, 1, 22, 0, 2,128, 30, 1, 0, 1, 22,128, 1,128, 23, +192,192, 0, 22,128, 0,128,193, 0, 1, 0,222, 0, 0, 1, 22, 64, 0,128,193, + 64, 1, 0,222, 0, 0, 1, 30, 0,128, 0, 6, 0, 0, 0, 4, 8, 0, 0, 0, +108,105, 98,110, 97,109,101, 0, 4, 5, 0, 0, 0,110, 97,109,101, 0, 4, 2, + 0, 0, 0, 46, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 4, 10, 0, 0, 0,114, +101, 99,117,114,115,105,118,101, 0, 4, 2, 0, 0, 0, 63, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 58, 0, 0, 0, + 67, 0, 0, 0, 5, 4, 0, 8, 24, 0, 0, 0, 4, 1, 0, 0, 68, 1,128, 0, +128, 1, 0, 0, 28,129,128, 1, 26, 1, 0, 0, 22,128, 2,128, 68, 1, 0, 1, +138,129, 1, 0,196, 1,128, 1,137,193, 1,128,137, 1,128,128,196, 1, 0, 2, +137,193, 1,129,137, 65,128,129,137,129, 0,130,137,193,128,130, 73,129, 1, 2, + 68, 1, 0, 2, 90, 1, 0, 0, 22,128, 0,128, 68, 1, 0, 2, 76,129,193, 2, + 72, 1, 0, 2, 30, 0,128, 0, 7, 0, 0, 0, 4, 8, 0, 0, 0,108,105, 98, +110, 97,109,101, 0, 4, 5, 0, 0, 0,110, 97,109,101, 0, 4, 4, 0, 0, 0, +105,100,120, 0, 4, 8, 0, 0, 0,114,101,115,117,108,116,115, 0, 4, 5, 0, + 0, 0, 97,114,103,115, 0, 4, 8, 0, 0, 0,104, 97,110,100,108,101,114, 0, + 3, 0, 0, 0, 0, 0, 0,240, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 75, 0, 0, 0, 3, 5, 0, + 8, 18, 0, 0, 0, 68, 1, 0, 0,138,129, 1, 0,196, 1,128, 0,137,193, 1, +128,137, 1,128,128,196, 1, 0, 1,137,193, 1,129,137,129,128,129,137,193, 0, +130,137, 1,129,130, 73,129,129, 0, 68, 1, 0, 1, 90, 1, 0, 0, 22,128, 0, +128, 68, 1, 0, 1, 76,129,193, 2, 72, 1, 0, 1, 30, 0,128, 0, 7, 0, 0, + 0, 4, 8, 0, 0, 0,108,105, 98,110, 97,109,101, 0, 4, 5, 0, 0, 0,110, + 97,109,101, 0, 4, 4, 0, 0, 0,105,100,120, 0, 4, 8, 0, 0, 0,114,101, +115,117,108,116,115, 0, 4, 5, 0, 0, 0, 97,114,103,115, 0, 4, 8, 0, 0, + 0,104, 97,110,100,108,101,114, 0, 3, 0, 0, 0, 0, 0, 0,240, 63, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 79, 0, + 0, 0, 81, 0, 0, 0, 0, 6, 0, 7, 4, 0, 0, 0,140, 1,192, 1,134,129, +129, 0, 73,128,129, 1, 30, 0,128, 0, 1, 0, 0, 0, 3, 0, 0, 0, 0, 0, + 0,240, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 96, 0, 0, 0,115, 0, 0, 0, 3, 5, 0, 19, 42, 0, 0, 0, 26, + 1, 0, 0, 22,128, 8,128, 68, 1, 0, 0, 70, 1,192, 2,134, 65, 64, 0,192, + 1,128, 2, 0, 2, 0, 3, 76,130, 64, 1,220, 1,129, 1, 23,192,192, 3, 22, + 64, 6,128,140, 2, 65, 1,140, 66, 2, 5,192, 2,128, 2, 0, 3, 0, 3, 64, + 3, 0, 5,220, 66,129, 1, 23, 64,193, 5, 22, 64, 4,128, 23,192, 0, 6, 22, +192, 3,128, 25, 0, 65, 7, 22, 64, 3,128,192, 3,128, 2, 0, 4, 0, 3, 76, +132, 64, 5,220, 3,129, 1, 23,192,192, 7, 22,192, 1,128,140, 68,132, 4, 23, +128, 65, 9, 22, 0, 1,128,132, 4,128, 0,134,196, 65, 9,140,132, 4, 5, 9, + 0, 1, 9, 30, 0,128, 0, 68, 1, 0, 1, 73, 64,129, 1, 66, 1,128, 0, 94, + 1, 0, 1, 30, 0,128, 0, 8, 0, 0, 0, 4, 9, 0, 0, 0, 98,121,116,101, + 99,111,100,101, 0, 4, 5, 0, 0, 0,102,117,110, 99, 0, 3, 0, 0, 0, 0, + 0, 0,240, 63, 4, 4, 0, 0, 0, 74, 77, 80, 0, 3, 0, 0, 0, 0, 0, 0, + 0, 64, 4, 9, 0, 0, 0, 84, 70, 79, 82, 76, 79, 79, 80, 0, 3, 0, 0, 0, + 0, 0, 0, 0,192, 4, 7, 0, 0, 0, 73, 78, 76, 73, 78, 69, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,118, 0, 0, + 0,126, 0, 0, 0, 2, 4, 0, 9, 24, 0, 0, 0, 12, 1, 64, 1, 6, 1,129, + 0, 67, 1, 0, 3,196, 1, 0, 0, 0, 2, 0, 2,220,129, 0, 1, 23, 64,192, + 3, 22, 0, 2,128,196, 1,128, 0, 0, 2, 0, 2,220,193, 0, 1,128, 1, 0, + 4, 64, 1,128, 3, 23,128, 64, 3, 22, 64, 0,128,198,193, 64, 0,134, 1,129, + 3,219, 65,128, 2, 22, 0, 0,128,193, 1, 1, 0, 73,192,129, 1,204, 1,192, + 1, 73,128,129, 3, 30, 0,128, 0, 5, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, +240, 63, 4, 6, 0, 0, 0,116, 97, 98,108,101, 0, 0, 4, 9, 0, 0, 0,116, + 97, 98,108,101,118, 97,108, 0, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,133, 0, 0, 0,138, 0, + 0, 0, 2, 7, 0, 13, 15, 0, 0, 0,196, 1, 0, 0, 0, 2, 0, 0, 64, 2, +128, 0,128, 2,128, 1,204, 2,192, 1,220, 65,128, 2,196, 1,128, 0, 0, 2, + 0, 0, 64, 2,128, 0,128, 2, 0, 1,192, 2,128, 1, 0, 3, 0, 3,221, 1, + 0, 3,222, 1, 0, 0, 30, 0,128, 0, 1, 0, 0, 0, 3, 0, 0, 0, 0, 0, + 0, 8, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0,141, 0, 0, 0,153, 0, 0, 0, 3, 7, 0, 15, 30, 0, 0, 0,204, + 1,192, 1,198,193,129, 0, 12, 66,192, 1, 73, 0, 64, 4, 3, 2, 0, 4, 68, + 2, 0, 0,128, 2,128, 3, 92,130, 0, 1, 23,128,192, 4, 22, 0, 2,128, 68, + 2,128, 0,128, 2,128, 3,193, 2, 0, 0, 92,130,128, 1, 0, 2,128, 4, 23, +192, 64, 4, 22, 64, 0,128, 70, 2, 65, 0, 6,194,129, 4, 76, 66,193, 1, 73, + 0,130, 4, 68, 2, 0, 1,128, 2, 0, 0,192, 2,128, 0, 0, 3, 0, 1, 64, + 3,128, 1,128, 3, 0, 3, 93, 2, 0, 3, 94, 2, 0, 0, 30, 0,128, 0, 6, + 0, 0, 0, 3, 0, 0, 0, 0, 0, 0,240, 63, 3, 0, 0, 0, 0, 0, 0, 8, + 64, 4, 6, 0, 0, 0,116, 97, 98,108,101, 0, 0, 4, 9, 0, 0, 0,116, 97, + 98,108,101,118, 97,108, 0, 3, 0, 0, 0, 0, 0, 0, 16, 64, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,157, 0, 0, 0, +159, 0, 0, 0, 1, 6, 0, 11, 7, 0, 0, 0,132, 1, 0, 0,192, 1, 0, 0, + 0, 2,128, 0, 64, 2,128, 1,128, 2,128, 1,156, 65,128, 2, 30, 0,128, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0,165, 0, 0, 0,168, 0, 0, 0, 2, 6, 0, 10, 17, 0, 0, 0, +140, 1,192, 1,134,129,129, 0,196, 1, 0, 0, 0, 2, 0, 3,220,129, 0, 1, + 23, 64,192, 3, 22,128, 1,128,196, 1,128, 0, 0, 2, 0, 3, 76,130,192, 1, + 70, 66,130, 0,220,129,128, 1,218, 65, 0, 0, 22, 0, 0,128,193,193, 0, 0, + 73,192,129, 1, 30, 0,128, 0, 4, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0,240, + 63, 4, 6, 0, 0, 0,116, 97, 98,108,101, 0, 3, 0, 0, 0, 0, 0, 0, 0, + 64, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0,171, 0, 0, 0,173, 0, 0, 0, 0, 6, 0, 12, 16, + 0, 0, 0,129, 1, 0, 0,192, 1,128, 2, 1, 2, 0, 0,160, 65, 2,128,140, + 66,130, 1,141, 2, 64, 5, 25, 0,129, 4, 22,192, 0,128,204, 66,130, 1,198, +194,130, 0,218, 66, 0, 0, 22, 0, 0,128,195, 2,128, 5, 73,192, 2, 5,159, + 1,253,127, 30, 0,128, 0, 1, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0,240, 63, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +183, 0, 0, 0,186, 0, 0, 0, 0, 6, 0, 11, 9, 0, 0, 0, 73, 0,192, 1, +129, 65, 0, 0,205, 65,192, 2, 1, 66, 0, 0,160, 65, 0,128,140, 66,130, 1, + 73,128, 64, 5,159, 1,255,127, 30, 0,128, 0, 3, 0, 0, 0, 1, 1, 3, 0, + 0, 0, 0, 0, 0,240, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0,201, 0, 0, 0,203, 0, 0, 0, 0, 6, 0, 11, + 8, 0, 0, 0,129, 1, 0, 0,205, 65,192, 2, 1, 66, 0, 0,160, 65, 0,128, +140, 66,130, 1, 73, 64, 64, 5,159, 1,255,127, 30, 0,128, 0, 2, 0, 0, 0, + 3, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0,240, 63, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,211, 0, + 0, 0,215, 0, 0, 0, 0, 6, 0, 11, 11, 0, 0, 0, 73, 0,192, 1,140, 1, +192, 1, 73, 0, 64, 3,129, 65, 0, 0,205, 1,192, 2, 1, 2, 0, 0,160, 65, + 0,128,140, 66,130, 1, 73,128, 64, 5,159, 1,255,127, 30, 0,128, 0, 3, 0, + 0, 0, 3, 0, 0, 0, 0, 0, 0,240, 63, 3, 0, 0, 0, 0, 0, 0, 0, 64, + 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0,217, 0, 0, 0,219, 0, 0, 0, 0, 6, 0, 11, 8, 0, + 0, 0,129, 1, 0, 0,205, 65,192, 2, 1, 66, 0, 0,160, 65, 0,128,140, 66, +130, 1, 73,128, 64, 5,159, 1,255,127, 30, 0,128, 0, 3, 0, 0, 0, 3, 0, + 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0,240, 63, 4, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0,222, 0, 0, 0,225, 0, 0, 0, 0, 6, 0, 10, 9, 0, 0, 0,140, 1, +192, 1,198, 65, 64, 0,198,129,192, 3,205,193,192, 3, 1,194, 0, 0,160, 1, + 0,128, 73, 0,193, 4,159, 65,255,127, 30, 0,128, 0, 5, 0, 0, 0, 3, 0, + 0, 0, 0, 0, 0, 8, 64, 4, 6, 0, 0, 0,115,116, 97,116,115, 0, 4, 11, + 0, 0, 0,115,116, 97, 99,107,115,108,111,116,115, 0, 3, 0, 0, 0, 0, 0, + 0,240, 63, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0,234, 0, 0, 0,239, 0, 0, 0, 2, 6, 0, + 10, 18, 0, 0, 0, 25, 64, 1,128, 22,128, 3,128,140, 1,192, 1,134,129,129, + 0,196, 1, 0, 0, 0, 2, 0, 3,220,129, 0, 1, 23, 64,192, 3, 22, 64, 1, +128,196, 1,128, 0, 0, 2, 0, 3, 65, 2, 0, 0,220,129,128, 1,218, 65, 0, + 0, 22, 0, 0,128,193,129, 0, 0, 73,192,129, 1, 30, 0,128, 0, 3, 0, 0, + 0, 3, 0, 0, 0, 0, 0, 0,240, 63, 4, 6, 0, 0, 0,116, 97, 98,108,101, + 0, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 13, 1, 0, 0, 15, 1, 0, 0, 0, 6, 0, 7, 7, + 0, 0, 0,140, 1,192, 1,134,129,129, 0,154, 65, 0, 0, 22, 0, 0,128,129, + 65, 0, 0, 73,128,129, 1, 30, 0,128, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, + 0, 0, 0, 64, 3, 0, 0, 0, 0, 0, 0,240, 63, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 35, 1, 0, 0, 37, 1, 0, + 0, 0, 6, 0, 6, 4, 0, 0, 0, 24, 0, 1,128, 22, 0, 0,128, 73, 64,192, + 1, 30, 0,128, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, + 0, 0, 0, 0, 0,240, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 69, 1, 0, 0, 69, 1, 0, 0, 0, 0, 0, 2, 1, + 0, 0, 0, 30, 0,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 73, 1, 0, 0, 77, 1, 0, 0, 2, + 1, 0, 6, 11, 0, 0, 0, 65, 0, 0, 0,132, 0, 0, 0,198, 64, 64, 0, 1, +129, 0, 0, 68, 1,128, 0,156,128, 0, 2,193,192, 0, 0, 85,192,128, 0, 9, + 64, 0,130, 94, 0, 0, 1, 30, 0,128, 0, 5, 0, 0, 0, 4, 2, 0, 0, 0, + 94, 0, 4, 5, 0, 0, 0, 97,114,103,115, 0, 4, 2, 0, 0, 0, 46, 0, 4, + 4, 0, 0, 0, 48, 42, 36, 0, 4, 9, 0, 0, 0, 97,114,103,109, 97,116, 99, +104, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 80, 1, 0, 0,105, 1, 0, 0, 7, 7, 0, 18, 79, 0, 0, 0,198, 1, + 64, 0,218, 1, 0, 0, 22,192, 6,128, 87, 64,192, 2, 22, 64, 6,128, 1,130, + 0, 0, 65,194, 0, 0,128, 2,128, 2,193,194, 0, 0, 96,194, 1,128, 64, 3, + 0, 4,132, 3, 0, 0,196, 3,128, 0, 12, 4, 3, 2, 6, 4, 4, 1,220,131, + 0, 1,134,195, 3, 7, 21,130,131, 6, 95,130,253,127, 68, 2, 0, 1,128, 2, + 0, 4,198, 2, 65, 0,218, 66, 0, 0, 22,128, 0,128,196, 2,128, 1, 0, 3, + 0, 0,220,130, 0, 1, 92,130,128, 1, 90, 66, 0, 0, 22, 0, 0,128,195, 1, +128, 3, 6, 66, 65, 0, 87,128, 65, 4, 22,128, 5,128, 87, 64, 64, 3, 22, 0, + 5,128, 84, 2, 0, 4, 24,128,129, 4, 22, 0, 0,128,195, 1,128, 3, 65,194, + 0, 0,148, 2, 0, 4,193,194, 0, 0, 96,194, 2,128, 68, 3, 0, 2,128, 3, + 0, 4,192, 3, 0, 6, 0, 4, 0, 6, 92,131, 0, 2, 87,192,193, 6, 22, 0, + 1,128,140, 3, 3, 2,141,195, 64, 7,196, 3,128, 2,198, 67,131, 7,137,192, + 3, 7, 95,130,252,127, 70, 2, 66, 0, 90, 2, 0, 0, 22,192, 2,128,128, 2, +128, 4,192, 2,128, 0, 0, 3, 0, 1, 64, 3,128, 1,128, 3, 0, 2,192, 3, +128, 2, 0, 4, 0, 3, 64, 4,128, 3,156,130, 0, 4,154, 2, 0, 0, 22, 0, + 0,128,195, 1,128, 3,218, 1, 0, 0, 22,192, 0,128,132, 2, 0, 3,134, 66, + 66, 5,140,130,130, 1, 73,192, 1, 5, 30, 0,128, 0, 10, 0, 0, 0, 4, 4, + 0, 0, 0,105,100,120, 0, 3, 0, 0, 0, 0, 0, 0,240,191, 4, 1, 0, 0, + 0, 0, 3, 0, 0, 0, 0, 0, 0,240, 63, 4, 9, 0, 0, 0, 97,114,103,109, + 97,116, 99,104, 0, 4, 8, 0, 0, 0,114,101,115,117,108,116,115, 0, 4, 2, + 0, 0, 0, 42, 0, 4, 2, 0, 0, 0, 46, 0, 4, 8, 0, 0, 0,104, 97,110, +100,108,101,114, 0, 4, 7, 0, 0, 0, 73, 78, 76, 73, 78, 69, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,108, 1, 0, + 0,124, 1, 0, 0, 4, 6, 0, 16, 49, 0, 0, 0,134,193,128, 0,196, 1, 0, + 0,198, 1,192, 3,204,193, 1, 1, 9,128,129, 3,196, 1,128, 0, 0, 2, 0, + 3,220,129, 0, 1, 23, 64,192, 3, 22,128, 7,128,196, 1, 0, 1,198,129,129, + 3,218, 1, 0, 0, 22, 64, 2,128, 4, 2,128, 1, 64, 2,128, 3,128, 2, 0, + 0,192, 2,128, 0, 0, 3, 0, 1, 64, 3,128, 1,128, 3, 0, 2,192, 3,128, + 2, 28, 66, 0, 4, 30, 0,128, 0, 6,130, 64, 0, 23, 0, 2, 3, 22, 64, 3, +128, 6,194, 64, 0, 6, 2, 65, 4, 26, 66, 0, 0, 22, 64, 2,128, 87, 64, 65, + 2, 22,192, 0,128, 6,194, 64, 0, 6,130, 65, 4, 23, 0, 2, 2, 22,192, 0, +128, 4, 2, 0, 0, 6,194, 65, 4, 12, 2, 2, 1, 9, 0, 66, 4,192, 1,128, + 1, 12, 66,129, 1, 13, 66, 66, 4, 65, 66, 2, 0,224, 1, 0,128, 73,128, 66, + 5,223, 65,255,127, 30, 0,128, 0, 11, 0, 0, 0, 4, 5, 0, 0, 0, 84, 89, + 80, 69, 0, 4, 9, 0, 0, 0,102,117,110, 99,116,105,111,110, 0, 4, 5, 0, + 0, 0,102,117,110, 99, 0, 4, 6, 0, 0, 0,115,116, 97,116,115, 0, 4, 9, + 0, 0, 0,105,115,118, 97,114, 97,114,103, 0, 3, 0, 0, 0, 0, 0, 0,240, +191, 4, 7, 0, 0, 0,112, 97,114, 97,109,115, 0, 4, 7, 0, 0, 0, 73, 78, + 76, 73, 78, 69, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, + 0,240, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0,128, 1, 0, 0,132, 1, 0, 0, 1, 0, 0, 3, 7, 0, 0, 0, + 5, 0, 0, 0, 65, 64, 0, 0, 28,128, 0, 1, 70,128, 64, 0,132, 0, 0, 0, + 92, 64, 0, 1, 30, 0,128, 0, 3, 0, 0, 0, 4, 8, 0, 0, 0,114,101,113, +117,105,114,101, 0, 4, 8, 0, 0, 0,106,105,116, 46,111,112,116, 0, 4, 16, + 0, 0, 0, 97,116,116, 97, 99,104, 95, 99, 97,108,108,104,105,110,116, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, +}; \ No newline at end of file diff --git a/src/xrServerEntities/script_engine.cpp b/src/xrServerEntities/script_engine.cpp index a5bb90ff1..a576b14dd 100644 --- a/src/xrServerEntities/script_engine.cpp +++ b/src/xrServerEntities/script_engine.cpp @@ -15,6 +15,7 @@ #include "script_storage.h" #include #include +#include #ifdef USE_DEBUGGER # ifndef USE_LUA_STUDIO @@ -303,6 +304,7 @@ void CScriptEngine::setup_callbacks() #ifdef DEBUG # include "script_thread.h" +#include void CScriptEngine::lua_hook_call (lua_State *L, lua_Debug *dbg) { if (ai().script_engine().current_thread()) @@ -314,14 +316,28 @@ void CScriptEngine::lua_hook_call (lua_State *L, lua_Debug *dbg) int auto_load(lua_State* L) { - if ((lua_gettop(L) < 2) || !lua_istable(L, 1) || !lua_isstring(L, 2)) + int StackSize = lua_gettop(L); + bool IsTable = lua_istable(L, 1); + + if ((StackSize < 2) || !IsTable || !lua_isstring(L, 2)) { + lua_pushnil(L); + return (1); + } + + string_path S = {}; + string128 FullName = {}; + FS.update_path(S, "$game_scripts$", xr_strconcat(FullName, lua_tostring(L, 2), ".script")); + + if (FS.exist(S)) + { + ai().script_engine().process_file_if_exists(lua_tostring(L, 2), false); + lua_rawget(L, 1); + } + else { lua_pushnil(L); - return (1); } - ai().script_engine().process_file_if_exists(lua_tostring(L, 2), false); - lua_rawget(L, 1); return (1); } diff --git a/src/xrServerEntities/script_storage.cpp b/src/xrServerEntities/script_storage.cpp index 6f16bf430..53941befa 100644 --- a/src/xrServerEntities/script_storage.cpp +++ b/src/xrServerEntities/script_storage.cpp @@ -17,13 +17,33 @@ #include #if !defined(DEBUG) && defined(USE_LUAJIT_ONE) -# include "opt.lua.h" -# include "opt_inline.lua.h" +# include "../xrServerEntities/opt.lua.h" +# include "../xrServerEntities/opt_inline.lua.h" #endif //!DEBUG && USE_LUAJIT_ONE #ifndef USE_LUAJIT_ONE #include "lua.hpp" #endif +#ifdef USE_LUAJIT_ONE +extern "C" +{ +#include + int luaopen_marshal(lua_State* L); + int luaopen_LuaXML_lib(lua_State* L); + int luaopen_utf8(lua_State* L); + +} +struct luajit +{ + static void open_lib(lua_State* L, pcstr module_name, lua_CFunction function) + { + lua_pushcfunction(L, function); + lua_pushstring(L, module_name); + lua_call(L, 1, 0); + } +}; +#endif + LPCSTR file_header_old = "\ local function script_name() \ @@ -205,7 +225,7 @@ static int report(lua_State *L, int status) static int loadjitmodule(lua_State *L, const char *notfound) { - lua_getglobal(L, "require"); + lua_getglobal(L, "require"); lua_pushliteral(L, "jit."); lua_pushvalue(L, -3); lua_concat(L, 2); @@ -305,6 +325,9 @@ CScriptStorage::~CScriptStorage() } extern int luaopen_lua_extensions(lua_State* L); +extern lua_CFunction luaopen_socket_core_init(); +extern void pdebug_init_init(lua_State* L); +void DebbugerAttach(); void disable_os_funcs(lua_State* L) { @@ -325,6 +348,52 @@ void disable_os_funcs(lua_State* L) lua_pop(L, 1); } +bool LoadScriptToGlobal(lua_State* L, const char* name) +{ + string_path FileName; + xr_string FixedFileName = name; + + if (FS.exist(FileName, "$game_scripts$", FixedFileName.data())) + { + int start = lua_gettop(L); + IReader* l_tpFileReader = FS.r_open(FileName); + + string_path NameSpace; + xr_strcpy(NameSpace, name); + + if (strext(NameSpace)) + *strext(NameSpace) = 0; + + if (luaL_loadbuffer(L, (const char*)l_tpFileReader->pointer(), l_tpFileReader->length(), NameSpace)) + { + lua_settop(L, start); + return false; + } + else + { + int errFuncId = -1; + int l_iErrorCode = lua_pcall(L, 0, 0, (-1 == errFuncId) ? 0 : errFuncId); + if (l_iErrorCode) + { +#ifdef DEBUG + g_pScriptEngine->print_output(L, name, l_iErrorCode); +#endif + lua_settop(L, start); + return false; + } + } + + + FS.r_close(l_tpFileReader); + } + else + { + return false; + } + + return true; +}; + void CScriptStorage::reinit() { if (m_virtual_machine) @@ -348,16 +417,7 @@ void CScriptStorage::reinit() if (strstr(Core.Params, "-nojit")) luaJIT_setmode(lua(), 0, LUAJIT_MODE_ENGINE | LUAJIT_MODE_OFF); #else // USE_LUAJIT_ONE - // initialize lua standard library functions - struct luajit - { - static void open_lib(lua_State *L, pcstr module_name, lua_CFunction function) - { - lua_pushcfunction(L, function); - lua_pushstring(L, module_name); - lua_call(L, 1, 0); - } - }; // struct lua; + // initialize lua standard library functions luajit::open_lib(lua(), "", luaopen_base); luajit::open_lib(lua(), LUA_LOADLIBNAME, luaopen_package); @@ -366,6 +426,7 @@ void CScriptStorage::reinit() luajit::open_lib(lua(), LUA_OSLIBNAME, luaopen_os); luajit::open_lib(lua(), LUA_MATHLIBNAME, luaopen_math); luajit::open_lib(lua(), LUA_STRLIBNAME, luaopen_string); + luajit::open_lib(lua(), LUA_JITLIBNAME, luaopen_jit); #ifdef DEBUG luajit::open_lib(lua(), LUA_DBLIBNAME, luaopen_debug); @@ -374,21 +435,25 @@ void CScriptStorage::reinit() if (strstr(Core.Params, "-dbg")) luajit::open_lib(lua(), LUA_DBLIBNAME, luaopen_debug); #endif //-DEBUG - - if (!strstr(Core.Params, "-nojit")) - { - luajit::open_lib(lua(), LUA_JITLIBNAME, luaopen_jit); -#ifndef DEBUG - put_function(lua(), opt_lua_binary, sizeof(opt_lua_binary), "jit.opt"); - put_function(lua(), opt_inline_lua_binary, sizeof(opt_lua_binary), "jit.opt_inline"); - dojitopt(lua(), "2"); -#endif //!DEBUG - } - #endif //!USE_LUAJIT_ONE - + luaopen_lua_extensions(lua()); disable_os_funcs(lua()); + //loadjitmodule(lua(), "jit not found"); + + LoadScriptToGlobal(lua(), "global.lua"); + LoadScriptToGlobal(lua(), "dynamic_callbacks.lua"); + + // Sockets + luajit::open_lib(lua(), "socket.core", luaopen_socket_core_init()); + bool SocketTest = LoadScriptToGlobal(lua(), "socket.lua"); + + // Panda + if (SocketTest) + { + pdebug_init_init(lua()); + LoadScriptToGlobal(lua(), "LuaPanda.lua"); + } if (strstr(Core.Params, "-_g")) file_header = file_header_new; //AVO: I get fatal crash at the start if this is used diff --git a/src/xrServerEntities/vs2022/xrServerEntities.vcxproj b/src/xrServerEntities/vs2022/xrServerEntities.vcxproj new file mode 100644 index 000000000..e69de29bb From 7d77953e8076b1a171d7bd39e35b17b9fd87893f Mon Sep 17 00:00:00 2001 From: SaloEater Date: Tue, 10 Jun 2025 22:31:51 -0500 Subject: [PATCH 02/27] revert luajit lib for luaext --- src/3rd party/lua-extensions/base.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/3rd party/lua-extensions/base.cpp b/src/3rd party/lua-extensions/base.cpp index ac126e6e3..16f9fea21 100644 --- a/src/3rd party/lua-extensions/base.cpp +++ b/src/3rd party/lua-extensions/base.cpp @@ -3,7 +3,7 @@ #include "luapanda.h" #ifdef USE_LUAJIT_ONE -#pragma comment(lib, "LuaJIT-1.1.4.lib") +#pragma comment(lib, "LuaJIT-1.1.8.lib") #else #pragma comment(lib, "lua51.lib") #endif //-USE_LUAJIT_ONE From 06f0165e66388c733dc3c978d12f114452e66654 Mon Sep 17 00:00:00 2001 From: SaloEater Date: Wed, 11 Jun 2025 00:41:56 -0500 Subject: [PATCH 03/27] fix script buffer names --- gamedata/scripts/_g_patches.script | 8 ++++++++ src/docs/lua_jit_bit_ffi.md | 0 src/xrCore/string_concatenations.cpp | 13 +++++++++++++ src/xrCore/string_concatenations.h | 13 +------------ src/xrServerEntities/script_storage.cpp | 6 ++++-- 5 files changed, 26 insertions(+), 14 deletions(-) create mode 100644 src/docs/lua_jit_bit_ffi.md diff --git a/gamedata/scripts/_g_patches.script b/gamedata/scripts/_g_patches.script index a2a9730c4..2099cfc77 100644 --- a/gamedata/scripts/_g_patches.script +++ b/gamedata/scripts/_g_patches.script @@ -666,3 +666,11 @@ _G.IsLauncher = function(o, c) } return c and launcher[c] or false end + +log = _G.log +_G.log = function(str) + log(str) + if DebuggerMode then + LuaPanda.printToVSCode(str,1,2) + end +end \ No newline at end of file diff --git a/src/docs/lua_jit_bit_ffi.md b/src/docs/lua_jit_bit_ffi.md new file mode 100644 index 000000000..e69de29bb diff --git a/src/xrCore/string_concatenations.cpp b/src/xrCore/string_concatenations.cpp index 5ed2541c5..e85b18b86 100644 --- a/src/xrCore/string_concatenations.cpp +++ b/src/xrCore/string_concatenations.cpp @@ -309,3 +309,16 @@ LPSTR strconcat(int dest_sz, char* dest, const char* S1, const char* S2, const c return (dest); } + +int XRCORE_API _strconcatSingle(char*& destPtr, char* pDestEnd, const char* Str) +{ + char* TargetStrCursor = const_cast (Str); + for (; *TargetStrCursor && destPtr < pDestEnd; destPtr++, TargetStrCursor++) + { + *destPtr = *TargetStrCursor; + } + + R_ASSERT3(!(*TargetStrCursor), "Failed to concatenate string", Str); + + return 0; +} \ No newline at end of file diff --git a/src/xrCore/string_concatenations.h b/src/xrCore/string_concatenations.h index a743661c0..71f680cd8 100644 --- a/src/xrCore/string_concatenations.h +++ b/src/xrCore/string_concatenations.h @@ -90,18 +90,7 @@ char* xr_strconcat(StringReceiverType& receiver, ArgList... args) return &receiver[0]; } -int XRCORE_API _strconcatSingle(char*& destPtr, char* pDestEnd, const char* Str) -{ - char* TargetStrCursor = const_cast (Str); - for (; *TargetStrCursor && destPtr < pDestEnd; destPtr++, TargetStrCursor++) - { - *destPtr = *TargetStrCursor; - } - - R_ASSERT3(!(*TargetStrCursor), "Failed to concatenate string", Str); - - return 0; -} +int XRCORE_API _strconcatSingle(char*& destPtr, char* pDestEnd, const char* Str); #endif // #ifndef STRING_CONCATENATIONS_H \ No newline at end of file diff --git a/src/xrServerEntities/script_storage.cpp b/src/xrServerEntities/script_storage.cpp index 53941befa..aaccc1c77 100644 --- a/src/xrServerEntities/script_storage.cpp +++ b/src/xrServerEntities/script_storage.cpp @@ -427,6 +427,8 @@ void CScriptStorage::reinit() luajit::open_lib(lua(), LUA_MATHLIBNAME, luaopen_math); luajit::open_lib(lua(), LUA_STRLIBNAME, luaopen_string); luajit::open_lib(lua(), LUA_JITLIBNAME, luaopen_jit); + luajit::open_lib(lua(), LUA_BITLIBNAME, luaopen_bit); + luajit::open_lib(lua(), LUA_FFILIBNAME, luaopen_ffi); #ifdef DEBUG luajit::open_lib(lua(), LUA_DBLIBNAME, luaopen_debug); @@ -972,10 +974,10 @@ bool CScriptStorage::do_file(LPCSTR caScriptName, LPCSTR caNameSpaceName) bool bufferLoaded = false; if (unlocalPerformed) { - bufferLoaded = load_buffer(lua(), scriptContents, scriptLength, l_caLuaFileName, caNameSpaceName); + bufferLoaded = load_buffer(lua(), scriptContents, scriptLength, caNameSpaceName, caNameSpaceName); } else { l_tpFileReader->rewind(); - bufferLoaded = load_buffer(lua(), static_cast(l_tpFileReader->pointer()), (size_t)l_tpFileReader->length(), l_caLuaFileName, caNameSpaceName); + bufferLoaded = load_buffer(lua(), static_cast(l_tpFileReader->pointer()), (size_t)l_tpFileReader->length(), caNameSpaceName, caNameSpaceName); } if (!bufferLoaded) From f90c818f9b7e48c50d7c371c45a4f1b2ec52c611 Mon Sep 17 00:00:00 2001 From: SaloEater Date: Wed, 11 Jun 2025 15:07:43 -0500 Subject: [PATCH 04/27] imgui menu (not working), debug error, debug reconnect on level change (not working), lua files --- gamedata/scripts/LuaPanda.lua | 3626 +++++++++++++++++ gamedata/scripts/dynamic_callbacks.lua | 37 + gamedata/scripts/global.lua | 41 + gamedata/scripts/socket.lua | 149 + src/xrEngine/EngineAPI.h | 11 + src/xrEngine/imgui_base.cpp | 7 + src/xrEngine/imgui_tools.cpp | 16 + src/xrEngine/imgui_tools.h | 3 + src/xrEngine/vs2022/xrEngine.vcxproj | 2 + src/xrEngine/vs2022/xrEngine.vcxproj.filters | 5 + src/xrGame/vs2022/xrGame.vcxproj | 2 + src/xrGame/vs2022/xrGame.vcxproj.filters | 6 + src/xrServerEntities/script_engine.cpp | 28 +- .../script_engine_debugger.cpp | 33 + src/xrServerEntities/script_engine_debugger.h | 3 + src/xrServerEntities/script_storage.cpp | 12 +- 16 files changed, 3957 insertions(+), 24 deletions(-) create mode 100644 gamedata/scripts/LuaPanda.lua create mode 100644 gamedata/scripts/dynamic_callbacks.lua create mode 100644 gamedata/scripts/global.lua create mode 100644 gamedata/scripts/socket.lua create mode 100644 src/xrEngine/imgui_tools.cpp create mode 100644 src/xrEngine/imgui_tools.h create mode 100644 src/xrServerEntities/script_engine_debugger.cpp create mode 100644 src/xrServerEntities/script_engine_debugger.h diff --git a/gamedata/scripts/LuaPanda.lua b/gamedata/scripts/LuaPanda.lua new file mode 100644 index 000000000..5d1a871c3 --- /dev/null +++ b/gamedata/scripts/LuaPanda.lua @@ -0,0 +1,3626 @@ +-- Tencent is pleased to support the open source community by making LuaPanda available. +-- Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. +-- Licensed under the BSD 3-Clause License (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at +-- https://opensource.org/licenses/BSD-3-Clause +-- 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. + +-- API: +-- LuaPanda.printToVSCode(logStr, printLevel, type) +-- 打印日志到VSCode Output下 LuaPanda Debugger 中 +-- @printLevel: debug(0)/info(1)/error(2) 这里的日志等级需高于launch.json中配置等级日志才能输出 (可选参数,默认0) +-- @type(可选参数,默认0): 0:VSCode output console 1:VSCode tip 2:VSCode debug console + +-- LuaPanda.BP() +-- 强制打断点,可以在协程中使用。建议使用以下写法: +-- local ret = LuaPanda and LuaPanda.BP and LuaPanda.BP(); +-- 如果成功加入断点ret返回true,否则是nil + +-- LuaPanda.getInfo() +-- 返回获取调试器信息。包括版本号,是否使用lib库,系统是否支持loadstring(load方法)。返回值类型string, 推荐在调试控制台中使用。 + +-- LuaPanda.testBreakpoint() +-- 测试断点,用于分析路径错误导致断点无法停止的情况。测试方法是 +-- 1. launch.json 中开启 stopOnEntry, 或者在代码中加入LuaPanda.BP()。 +-- 2. 运行调试器和 lua 进程,当停止在 stopOnEntry 或者 LuaPanda.BP() 时在调试控制台输入 LuaPanda.testBreakpoint() +-- 3. 根据提示更新断点后再次输入 LuaPanda.testBreakpoint()。此时系统会输出一些提示,帮助用户分析断点可能无法停止的原因。 + +-- LuaPanda.doctor() +-- 返回对当前环境的诊断信息,提示可能存在的问题。返回值类型string, 推荐在调试控制台中使用。 + +-- LuaPanda.getBreaks() +-- 获取断点信息,推荐在调试控制台中使用。 + +-- LuaPanda.serializeTable(table) +-- 把table序列化为字符串,返回值类型是string。 + +-- LuaPanda.stopAttach() +-- 断开连接,停止attach,本次被调试程序运行过程无法再次进行attach连接。 + +-- 其他说明: +-- 关于真机调试,首次使用真机调试时要注意下方"用户设置项"中的配置 +-- 1. 确定 attach 开关打开: openAttachMode = true; 这样可以避免先启动手机app之后启动调试器无法连接。 +-- 2. 把连接时间放长: connectTimeoutSec 设置为 0.5 或者 1。首次尝试真机调试时这个值可以设置大一点,之后再根据自己的网络状况向下调整。 +-- 调试方法可以参考 github 文档 + +--用户设置项 +local openAttachMode = true; --是否开启attach模式。attach模式开启后可以在任意时刻启动vscode连接调试。缺点是没有连接调试时也会略降低lua执行效率(会不断进行attach请求) +local attachInterval = 1; --attach间隔时间(s) +local connectTimeoutSec = 0.005; --lua进程作为Client时, 连接超时时间, 单位s. 时间过长等待attach时会造成卡顿,时间过短可能无法连接。建议值0.005 - 0.05 +local listeningTimeoutSec = 0.5; -- lua进程作为Server时,连接超时时间, 单位s. 时间过长等待attach时会造成卡顿,时间过短可能无法连接。建议值0.1 - 1 +local userDotInRequire = true; --兼容require中使用 require(a.b) 和 require(a/b) 的形式引用文件夹中的文件,默认无需修改 +local traversalUserData = false; --如果可以的话(取决于userdata原表中的__pairs),展示userdata中的元素。 如果在调试器中展开userdata时有错误,请关闭此项. +local customGetSocketInstance = nil; --支持用户实现一个自定义调用luasocket的函数,函数返回值必须是一个socket实例。例: function() return require("socket.core").tcp() end; +local consoleLogLevel = 2; --打印在控制台(print)的日志等级 0 : all/ 1: info/ 2: error. +--用户设置项END + +local debuggerVer = "3.3.1"; --debugger版本号 +LuaPanda = {}; +local this = LuaPanda; +local tools = {}; --引用的开源工具,包括json解析和table展开工具等 +this.tools = tools; +this.curStackId = 0; +--json处理 +local json; +--hook状态列表 +local hookState = { + DISCONNECT_HOOK = 0, --断开连接 + LITE_HOOK = 1, --全局无断点 + MID_HOOK = 2, --全局有断点,本文件无断点 + ALL_HOOK = 3, --本文件有断点 +}; +--运行状态列表 +local runState = { + DISCONNECT = 0, --未连接 + WAIT_CMD = 1, --已连接,等待命令 + STOP_ON_ENTRY = 2, --初始状态 + RUN = 3, + STEPOVER = 4, + STEPIN = 5, + STEPOUT = 6, + STEPOVER_STOP = 7, + STEPIN_STOP = 8, + STEPOUT_STOP = 9, + HIT_BREAKPOINT = 10 +}; + +local TCPSplitChar = "|*|"; --json协议分隔符,请不要修改 +local MAX_TIMEOUT_SEC = 3600 * 24; --网络最大超时等待时间 +--当前运行状态 +local currentRunState; +local currentHookState; +--断点信息 +local breaks = {}; --保存断点的数组 +this.breaks = breaks; --供hookLib调用 +local recCallbackId = ""; +--VSCode端传过来的配置,在VSCode端的launch配置,传过来并赋值 +local luaFileExtension = ""; --vscode传过来的脚本后缀 +local cwd = ""; --工作路径 +local DebuggerFileName = ""; --Debugger文件名(原始,未经path处理), 函数中会自动获取 +local DebuggerToolsName = ""; +local lastRunFunction = {}; --上一个执行过的函数。在有些复杂场景下(find,getcomponent)一行会挺两次 +local currentCallStack = {}; --获取当前调用堆栈信息 +local hitBP = false; --BP()中的强制断点命中标记 +local TempFilePath_luaString = ""; --VSCode端配置的临时文件存放路径 +local recordHost; --记录连接端IP +local recordPort; --记录连接端口号 +local sock; --lua socket 文件描述符 +local server; --server 描述符 +local OSType; --VSCode识别出的系统类型,也可以自行设置。Windows_NT | Linux | Darwin +local clibPath; --chook库在VScode端的路径,也可自行设置。 +local hookLib; --chook库的引用实例 +local adapterVer; --VScode传来的adapter版本号 +local truncatedOPath; --VScode中用户设置的用于截断opath路径的标志,注意这里可以接受lua魔法字符 +local distinguishSameNameFile = false; --是否区分lua同名文件中的断点,在VScode launch.json 中 distinguishSameNameFile 控制 +--标记位 +local logLevel = 1; --日志等级all/info/error. 此设置对应的是VSCode端设置的日志等级. +local variableRefIdx = 1; --变量索引 +local variableRefTab = {}; --变量记录table +local lastRunFilePath = ""; --最后执行的文件路径 +local pathCaseSensitivity = true; --路径是否发大小写敏感,这个选项接收VScode设置,请勿在此处更改 +local recvMsgQueue = {}; --接收的消息队列 +local coroutinePool = setmetatable({}, {__mode = "v"}); --保存用户协程的队列 +local winDiskSymbolUpper = false;--设置win下盘符的大小写。以此确保从VSCode中传入的断点路径,cwd和从lua虚拟机获得的文件路径盘符大小写一致 +local isNeedB64EncodeStr = false;-- 记录是否使用base64编码字符串 +local loadclibErrReason = 'launch.json文件的配置项useCHook被设置为false.'; +local OSTypeErrTip = ""; +local pathErrTip = "" +local winDiskSymbolTip = ""; +local isAbsolutePath = false; +local stopOnEntry; --用户在VSCode端设置的是否打开stopOnEntry +local userSetUseClib; --用户在VSCode端设置的是否是用clib库 +local autoPathMode = false; +local autoExt; --调试器启动时自动获取到的后缀, 用于检测lua虚拟机返回的路径是否带有文件后缀。他可以是空值或者".lua"等 +local luaProcessAsServer; +local testBreakpointFlag = false; -- 测试断点的标志位。结合 LuaPanda.testBreakpoint() 测试断点无法停止的原因 +--Step控制标记位 +local stepOverCounter = 0; --STEPOVER over计数器 +local stepOutCounter = 0; --STEPOVER out计数器 +local HOOK_LEVEL = 3; --调用栈偏移量,使用clib时为3,lua中不再使用此变量,而是通过函数getSpecificFunctionStackLevel获取 +local isUseLoadstring = 0; +local debugger_loadString; +--临时变量 +local recordBreakPointPath; --记录最后一个[可能命中]的断点,用于getInfo以及doctor的断点测试 +local coroutineCreate; --用来记录lua原始的coroutine.create函数 +local stopConnectTime = 0; --用来临时记录stop断开连接的时间 +local isInMainThread; +local receiveMsgTimer = 0; +local isUserSetClibPath = false; --用户是否在本文件中自设了clib路径 +local hitBpTwiceCheck; -- 命中断点的Vscode校验结果,默认true (true是命中,false是未命中) +local formatPathCache = {}; -- getinfo -> format +function this.formatPathCache() return formatPathCache; end +local fakeBreakPointCache = {}; --其中用 路径-{行号列表} 形式保存错误命中信息 +function this.fakeBreakPointCache() return fakeBreakPointCache; end +--5.1/5.3兼容 +if _VERSION == "Lua 5.1" then + debugger_loadString = loadstring; +else + debugger_loadString = load; +end + +--用户在控制台输入信息的环境变量 +local env = setmetatable({ }, { + __index = function( _ , varName ) + local ret = this.getWatchedVariable( varName, _G.LuaPanda.curStackId , false); + return ret; + end, + + __newindex = function( _ , varName, newValue ) + this.setVariableValue( varName, _G.LuaPanda.curStackId, newValue); + end +}); + +----------------------------------------------------------------------------- +-- 流程 +----------------------------------------------------------------------------- + +---this.bindServer 当lua进程作为Server时,server绑定函数 +--- server 在bind时创建, 连接成功后关闭listen , disconnect时置空。reconnect时会查询server,没有的话重新绑定,如果已存在直接accept +function this.bindServer(host, port) + server = sock + server:settimeout(listeningTimeoutSec); + assert(server:bind(host, port)); + server:setoption("reuseaddr", true); --防止已连接状态下新的连接进入,不再reuse + assert(server:listen(0)); +end + +-- 以lua作为服务端的形式启动调试器 +-- @host 绑定ip , 默认 0.0.0.0 +-- @port 绑定port, 默认 8818 +function this.startServer(host, port) + host = tostring(host or "0.0.0.0") ; + port = tonumber(port) or 8818; + luaProcessAsServer = true; + this.printToConsole("Debugger start as SERVER. bind host:" .. host .. " port:".. tostring(port), 1); + if sock ~= nil then + this.printToConsole("[Warning] 调试器已经启动,请不要再次调用start()" , 1); + return; + end + + --尝试初次连接 + this.changeRunState(runState.DISCONNECT); + if not this.reGetSock() then + this.printToConsole("[Error] LuaPanda debugger start success , but get Socket fail , please install luasocket!", 2); + return; + end + recordHost = host; + recordPort = port; + + this.bindServer(recordHost, recordPort); + local connectSuccess = server:accept(); + sock = connectSuccess; + + if connectSuccess then + this.printToConsole("First connect success!"); + this.connectSuccess(); + else + this.printToConsole("First connect failed!"); + this.changeHookState(hookState.DISCONNECT_HOOK); + end +end + +-- 启动调试器 +-- @host adapter端ip, 默认127.0.0.1 +-- @port adapter端port ,默认8818 +function this.start(host, port) + host = tostring(host or "127.0.0.1") ; + port = tonumber(port) or 8818; + this.printToConsole("Debugger start as CLIENT. connect host:" .. host .. " port:".. tostring(port), 1); + if sock ~= nil then + this.printToConsole("[Warning] 调试器已经启动,请不要再次调用start()" , 1); + return; + end + + --尝试初次连接 + this.changeRunState(runState.DISCONNECT); + if not this.reGetSock() then + this.printToConsole("[Error] Start debugger but get Socket fail , please install luasocket!", 2); + return; + end + recordHost = host; + recordPort = port; + + sock:settimeout(connectTimeoutSec); + local connectSuccess = this.sockConnect(sock); + + if connectSuccess then + this.printToConsole("First connect success!"); + this.connectSuccess(); + else + this.printToConsole("First connect failed!"); + this.changeHookState(hookState.DISCONNECT_HOOK); + end +end + +function this.sockConnect(sock) + if sock then + local connectSuccess, status = sock:connect(recordHost, recordPort); + if status == "connection refused" or (not connectSuccess and status == "already connected") then + this.reGetSock(); + end + + return connectSuccess + end + return nil; +end + +-- 连接成功,开始初始化 +function this.connectSuccess() + if server then + server:close(); -- 停止listen + end + + this.changeRunState(runState.WAIT_CMD); + this.printToConsole("connectSuccess", 1); + --设置初始状态 + local ret = this.debugger_wait_msg(); + + --获取debugger文件路径 + if DebuggerFileName == "" then + local info = debug.getinfo(1, "S") + for k,v in pairs(info) do + if k == "source" then + DebuggerFileName = tostring(v); + -- 从代码中去后缀 + autoExt = DebuggerFileName:gsub('.*[Ll][Uu][Aa][Pp][Aa][Nn][Dd][Aa]', ''); + + if hookLib ~= nil then + hookLib.sync_debugger_path(DebuggerFileName); + end + end + end + end + if DebuggerToolsName == "" then + DebuggerToolsName = tools.getFileSource(); + if hookLib ~= nil then + hookLib.sync_tools_path(DebuggerToolsName); + end + end + + if ret == false then + this.printToVSCode("[debugger error]初始化未完成, 建立连接但接收初始化消息失败。请更换端口重试", 2); + return; + end + this.printToVSCode("debugger init success", 1); + + this.changeHookState(hookState.ALL_HOOK); + if hookLib == nil then + --协程调试 + this.changeCoroutinesHookState(); + end + +end + +--重置数据 +function this.clearData() + OSType = nil; + clibPath = nil; + -- reset breaks + breaks = {}; + formatPathCache = {}; + fakeBreakPointCache = {}; + this.breaks = breaks; + if hookLib ~= nil then + hookLib.sync_breakpoints(); --清空断点信息 + hookLib.clear_pathcache(); --清空路径缓存 + end +end + +-- 本次连接过程中停止attach ,以提高运行效率 +function this.stopAttach() + openAttachMode = false; + this.printToConsole("Debugger stopAttach", 1); + this.clearData() + this.changeHookState( hookState.DISCONNECT_HOOK ); + stopConnectTime = os.time(); + this.changeRunState(runState.DISCONNECT); + if sock ~= nil then + sock:close(); + if luaProcessAsServer and server then server = nil; end; + end +end + +--断开连接 +function this.disconnect() + this.printToConsole("Debugger disconnect", 1); + this.clearData() + this.changeHookState( hookState.DISCONNECT_HOOK ); + stopConnectTime = os.time(); + this.changeRunState(runState.DISCONNECT); + + if sock ~= nil then + sock:close(); + sock = nil; + server = nil; + end + + if recordHost == nil or recordPort == nil then + --异常情况处理, 在调用LuaPanda.start()前首先调用了LuaPanda.disconnect() + this.printToConsole("[Warning] User call LuaPanda.disconnect() before set debug ip & port, please call LuaPanda.start() first!", 2); + return; + end + + this.reGetSock(); +end + +function this.replaceCoroutineFuncs() + if hookLib == nil then + if coroutineCreate == nil and type(coroutine.create) == "function" then + this.printToConsole("change coroutine.create"); + coroutineCreate = coroutine.create; + coroutine.create = function(...) + local co = coroutineCreate(...) + table.insert(coroutinePool, co); + --运行状态下,创建协程即启动hook + this.changeCoroutineHookState(co, currentHookState); + return co; + end + end + end +end + +----------------------------------------------------------------------------- +-- 调试器通用方法 +----------------------------------------------------------------------------- +-- 返回断点信息 +function this.getBreaks() + return breaks; +end + +---testBreakpoint 测试断点 +function this.testBreakpoint() + if recordBreakPointPath and recordBreakPointPath ~= "" then + -- testBreakpointFlag = false; + return this.breakpointTestInfo(); + else + local strTable = {}; + strTable[#strTable + 1] = "正在准备进行断点测试,请按照如下步骤操作\n" + strTable[#strTable + 1] = "1. 请[删除]当前项目中所有断点;\n" + strTable[#strTable + 1] = "2. 在当前停止行打一个断点;\n" + strTable[#strTable + 1] = "3. 再次运行 'LuaPanda.testBreakpoint()'" + testBreakpointFlag = true; + + return table.concat(strTable); + end +end + +-- 返回路径相关信息 +-- cwd:配置的工程路径 | info["source"]:通过 debug.getinfo 获得执行文件的路径 | format:格式化后的文件路径 +function this.breakpointTestInfo() + local ly = this.getSpecificFunctionStackLevel(lastRunFunction.func); + if type(ly) ~= "number" then + ly = 2; + end + local runSource = lastRunFunction["source"]; + if runSource == nil and hookLib ~= nil then + runSource = this.getPath(tostring(hookLib.get_last_source())); + end + local info = debug.getinfo(ly, "S"); + local NormalizedPath = this.formatOpath(info["source"]); + NormalizedPath = this.truncatedPath(NormalizedPath, truncatedOPath); + + local strTable = {} + local FormatedPath = tostring(runSource); + strTable[#strTable + 1] = "\n- BreakPoint Test:" + strTable[#strTable + 1] = "\nUser set lua extension: ." .. tostring(luaFileExtension); + strTable[#strTable + 1] = "\nAuto get lua extension: " .. tostring(autoExt); + if truncatedOPath and truncatedOPath ~= '' then + strTable[#strTable + 1] = "\nUser set truncatedOPath: " .. truncatedOPath; + end + strTable[#strTable + 1] = "\nGetInfo: ".. info["source"]; + strTable[#strTable + 1] = "\nNormalized: " .. NormalizedPath; + strTable[#strTable + 1] = "\nFormated: " .. FormatedPath; + if recordBreakPointPath and recordBreakPointPath ~= "" then + strTable[#strTable + 1] = "\nBreakpoint: " .. recordBreakPointPath; + end + + if not autoPathMode then + if isAbsolutePath then + strTable[#strTable + 1] = "\n说明:从lua虚拟机获取到的是绝对路径,Formated使用GetInfo路径。" .. winDiskSymbolTip; + else + strTable[#strTable + 1] = "\n说明:从lua虚拟机获取到的路径(GetInfo)是相对路径,调试器运行依赖的绝对路径(Formated)是来源于cwd+GetInfo拼接。如Formated路径错误请尝试调整cwd或改变VSCode打开文件夹的位置。也可以在Formated对应的文件下打一个断点,调整直到Formated和Breaks Info中断点路径完全一致。" .. winDiskSymbolTip; + end + else + strTable[#strTable + 1] = "\n说明:自动路径(autoPathMode)模式已开启。"; + if recordBreakPointPath and recordBreakPointPath ~= "" then + if string.find(recordBreakPointPath , FormatedPath, (-1) * string.len(FormatedPath) , true) then + -- 短路径断点命中 + if distinguishSameNameFile == false then + strTable[#strTable + 1] = "本文件中断点可正常命中。" + strTable[#strTable + 1] = "同名文件中的断点识别(distinguishSameNameFile) 未开启,请确保 VSCode 断点不要存在于同名 lua 文件中。"; + else + strTable[#strTable + 1] = "同名文件中的断点识别(distinguishSameNameFile) 已开启。"; + if string.find(recordBreakPointPath, NormalizedPath, 1, true) then + strTable[#strTable + 1] = "本文件中断点可被正常命中" + else + strTable[#strTable + 1] = "断点可能无法被命中,因为 lua 虚拟机中获得的路径 Normalized 不是断点路径 Breakpoint 的子串。 如有需要,可以在 launch.json 中设置 truncatedOPath 来去除 Normalized 部分路径。" + end + end + else + strTable[#strTable + 1] = "断点未被命中,原因是 Formated 不是 Breakpoint 路径的子串,或者 Formated 和 Breakpoint 文件后缀不一致" + end + else + strTable[#strTable + 1] = "如果要进行断点测试,请使用 LuaPanda.testBreakpoint()。" + end + end + return table.concat(strTable) +end + +--返回版本号等配置 +function this.getBaseInfo() + local strTable = {}; + local jitVer = ""; + if jit and jit.version then + jitVer = "," .. tostring(jit.version); + end + + strTable[#strTable + 1] = "Lua Ver:" .. _VERSION .. jitVer .." | Adapter Ver:" .. tostring(adapterVer) .. " | Debugger Ver:" .. tostring(debuggerVer); + local moreInfoStr = ""; + if hookLib ~= nil then + local clibVer, forluaVer = hookLib.sync_getLibVersion(); + local clibStr = forluaVer ~= nil and tostring(clibVer) .. " for " .. tostring(math.ceil(forluaVer)) or tostring(clibVer); + strTable[#strTable + 1] = " | hookLib Ver:" .. clibStr; + moreInfoStr = moreInfoStr .. "说明: 已加载 libpdebug 库."; + else + moreInfoStr = moreInfoStr .. "说明: 未能加载 libpdebug 库。原因请使用 LuaPanda.doctor() 查看"; + end + + local outputIsUseLoadstring = false + if type(isUseLoadstring) == "number" and isUseLoadstring == 1 then + outputIsUseLoadstring = true; + end + + strTable[#strTable + 1] = " | supportREPL:".. tostring(outputIsUseLoadstring); + strTable[#strTable + 1] = " | useBase64EncodeString:".. tostring(isNeedB64EncodeStr); + strTable[#strTable + 1] = " | codeEnv:" .. tostring(OSType); + strTable[#strTable + 1] = " | distinguishSameNameFile:" .. tostring(distinguishSameNameFile) .. '\n'; + + strTable[#strTable + 1] = moreInfoStr; + if OSTypeErrTip ~= nil and OSTypeErrTip ~= '' then + strTable[#strTable + 1] = '\n' ..OSTypeErrTip; + end + return table.concat(strTable); +end + +--自动诊断当前环境的错误,并输出信息 +function this.doctor() + local strTable = {}; + if debuggerVer ~= adapterVer then + strTable[#strTable + 1] = "\n- 建议更新版本\nLuaPanda VSCode插件版本是" .. adapterVer .. ", LuaPanda.lua文件版本是" .. debuggerVer .. "。建议检查并更新到最新版本。"; + strTable[#strTable + 1] = "\n更新方式 : https://github.com/Tencent/LuaPanda/blob/master/Docs/Manual/update.md"; + strTable[#strTable + 1] = "\nRelease版本: https://github.com/Tencent/LuaPanda/releases"; + end + --plibdebug + if hookLib == nil then + strTable[#strTable + 1] = "\n\n- libpdebug 库没有加载\n"; + if userSetUseClib then + --用户允许使用clib插件 + if isUserSetClibPath == true then + --用户自设了clib地址 + strTable[#strTable + 1] = "用户使用 LuaPanda.lua 中 clibPath 变量指定了 plibdebug 的位置: " .. clibPath; + if this.tryRequireClib("libpdebug", clibPath) then + strTable[#strTable + 1] = "\n引用成功"; + else + strTable[#strTable + 1] = "\n引用错误:" .. loadclibErrReason; + end + else + --使用默认clib地址 + local clibExt, platform; + if OSType == "Darwin" then clibExt = "/?.so;"; platform = "mac"; + elseif OSType == "Linux" then clibExt = "/?.so;"; platform = "linux"; + else clibExt = "/?.dll;"; platform = "win"; end + local lua_ver; + if _VERSION == "Lua 5.1" then + lua_ver = "501"; + elseif _VERSION == "Lua 5.4" then + lua_ver = "504"; + else + lua_ver = "503"; + end + local x86Path = clibPath .. platform .."/x86/".. lua_ver .. clibExt; + local x64Path = clibPath .. platform .."/x86_64/".. lua_ver .. clibExt; + local armPath = clibPath .. platform .."/arm_64/".. lua_ver .. clibExt; + + if platform == "mac" then + -- mac下先检测arm库 + strTable[#strTable + 1] = "尝试引用arm库: ".. armPath; + if this.tryRequireClib("libpdebug", armPath) then + strTable[#strTable + 1] = "\n引用成功"; + return; + end + end + + strTable[#strTable + 1] = "尝试引用x64库: ".. x64Path; + if this.tryRequireClib("libpdebug", x64Path) then + strTable[#strTable + 1] = "\n引用成功"; + else + strTable[#strTable + 1] = "\n引用错误:" .. loadclibErrReason; + strTable[#strTable + 1] = "\n尝试引用x86库: ".. x86Path; + if this.tryRequireClib("libpdebug", x86Path) then + strTable[#strTable + 1] = "\n引用成功"; + else + strTable[#strTable + 1] = "\n引用错误:" .. loadclibErrReason; + end + end + end + else + strTable[#strTable + 1] = "原因是" .. loadclibErrReason; + end + end + + --path + --尝试直接读当前getinfo指向的文件,看能否找到。如果能,提示正确,如果找不到,给出提示,建议玩家在这个文件中打一个断点 + --检查断点,文件和当前文件的不同,给出建议 + local runSource = lastRunFilePath; + if hookLib ~= nil then + runSource = this.getPath(tostring(hookLib.get_last_source())); + end + + -- 在精确路径模式下的路径错误检测 + if not autoPathMode and runSource and runSource ~= "" then + -- 读文件 + local isFileExist = this.fileExists(runSource); + if not isFileExist then + strTable[#strTable + 1] = "\n\n- 路径存在问题\n"; + --解析路径,得到文件名,到断点路径中查这个文件名 + local pathArray = this.stringSplit(runSource, '/'); + --如果pathArray和断点能匹配上 + local fileMatch= false; + for key, _ in pairs(this.getBreaks()) do + if string.find(key, pathArray[#pathArray], 1, true) then + --和断点匹配了 + fileMatch = true; + -- retStr = retStr .. "\n请对比如下路径:\n"; + strTable[#strTable + 1] = this.breakpointTestInfo(); + strTable[#strTable + 1] = "\nfilepath: " .. key; + if isAbsolutePath then + strTable[#strTable + 1] = "\n说明:从lua虚拟机获取到的是绝对路径,format使用getinfo路径。"; + else + strTable[#strTable + 1] = "\n说明:从lua虚拟机获取到的是相对路径,调试器运行依赖的绝对路径(format)是来源于cwd+getinfo拼接。"; + end + strTable[#strTable + 1] = "\nfilepath是VSCode通过获取到的文件正确路径 , 对比format和filepath,调整launch.json中CWD,或改变VSCode打开文件夹的位置。使format和filepath一致即可。\n如果format和filepath路径仅大小写不一致,设置launch.json中 pathCaseSensitivity:false 可忽略路径大小写"; + end + end + + if fileMatch == false then + --未能和断点匹配 + strTable[#strTable + 1] = "\n找不到文件:" .. runSource .. ", 请检查路径是否正确。\n或者在VSCode文件" .. pathArray[#pathArray] .. "中打一个断点后,再执行一次doctor命令,查看路径分析结果。"; + end + end + end + + --日志等级对性能的影响 + if logLevel < 1 or consoleLogLevel < 1 then + strTable[#strTable + 1] = "\n\n- 日志等级\n"; + if logLevel < 1 then + strTable[#strTable + 1] = "当前日志等级是" .. logLevel .. ", 会产生大量日志,降低调试速度。建议调整launch.json中logLevel:1"; + end + if consoleLogLevel < 1 then + strTable[#strTable + 1] = "当前console日志等级是" .. consoleLogLevel .. ", 过低的日志等级会降低调试速度,建议调整LuaPanda.lua文件头部consoleLogLevel=2"; + end + end + + if #strTable == 0 then + strTable[#strTable + 1] = "未检测出问题"; + end + return table.concat(strTable); +end + +function this.fileExists(path) + local f=io.open(path,"r"); + if f~= nil then io.close(f) return true else return false end + end + +--返回一些信息,帮助用户定位问题 +function this.getInfo() + --用户设置项 + local strTable = {}; + strTable[#strTable + 1] = "\n- Base Info: \n"; + strTable[#strTable + 1] = this.getBaseInfo(); + --已经加载C库,x86/64 未能加载,原因 + strTable[#strTable + 1] = "\n\n- User Setting: \n"; + strTable[#strTable + 1] = "stopOnEntry:" .. tostring(stopOnEntry) .. ' | '; + -- strTable[#strTable + 1] = "luaFileExtension:" .. luaFileExtension .. ' | '; + strTable[#strTable + 1] = "logLevel:" .. logLevel .. ' | ' ; + strTable[#strTable + 1] = "consoleLogLevel:" .. consoleLogLevel .. ' | '; + strTable[#strTable + 1] = "pathCaseSensitivity:" .. tostring(pathCaseSensitivity) .. ' | '; + strTable[#strTable + 1] = "attachMode:".. tostring(openAttachMode).. ' | '; + strTable[#strTable + 1] = "autoPathMode:".. tostring(autoPathMode).. ' | '; + + if userSetUseClib then + strTable[#strTable + 1] = "useCHook:true"; + else + strTable[#strTable + 1] = "useCHook:false"; + end + + if logLevel == 0 or consoleLogLevel == 0 then + strTable[#strTable + 1] = "\n说明:日志等级过低,会影响执行效率。请调整logLevel和consoleLogLevel值 >= 1"; + end + + strTable[#strTable + 1] = "\n\n- Path Info: \n"; + strTable[#strTable + 1] = "clibPath: " .. tostring(clibPath) .. '\n'; + strTable[#strTable + 1] = "debugger: " .. DebuggerFileName .. " | " .. this.getPath(DebuggerFileName) .. '\n'; + strTable[#strTable + 1] = "cwd : " .. cwd .. '\n'; + strTable[#strTable + 1] = this.breakpointTestInfo(); + + if pathErrTip ~= nil and pathErrTip ~= '' then + strTable[#strTable + 1] = '\n' .. pathErrTip; + end + + strTable[#strTable + 1] = "\n\n- Breaks Info: \nUse 'LuaPanda.getBreaks()' to watch."; + return table.concat(strTable); +end + +--判断是否在协程中 +function this.isInMain() + return isInMainThread; +end + +--添加路径,尝试引用库。完成后把cpath还原,返回引用结果true/false +-- @libName 库名 +-- path lib的cpath路径 +function this.tryRequireClib(libName , libPath) + this.printToVSCode("tryRequireClib search : [" .. libName .. "] in "..libPath); + local savedCpath = package.cpath; + package.cpath = package.cpath .. ';' .. libPath; + this.printToVSCode("package.cpath:" .. package.cpath); + local status, err = pcall(function() hookLib = require(libName) end); + if status then + if type(hookLib) == "table" and this.getTableMemberNum(hookLib) > 0 then + this.printToVSCode("tryRequireClib success : [" .. libName .. "] in "..libPath); + package.cpath = savedCpath; + return true; + else + loadclibErrReason = "tryRequireClib fail : require success, but member function num <= 0; [" .. libName .. "] in "..libPath; + this.printToVSCode(loadclibErrReason); + hookLib = nil; + package.cpath = savedCpath; + return false; + end + else + -- 此处考虑到tryRequireClib会被调用两次,日志级别设置为0,防止输出不必要的信息。 + loadclibErrReason = err; + this.printToVSCode("[Require clib error]: " .. err, 0); + end + package.cpath = savedCpath; + return false +end +------------------------字符串处理------------------------- +-- 倒序查找字符串 a.b/c查找/ , 返回4 +-- @str 被查找的长串 +-- @subPattern 查找的子串, 也可以是pattern +-- @plain plane text / pattern +-- @return 未找到目标串返回nil. 否则返回倒序找到的字串位置 +function this.revFindString(str, subPattern, plain) + local revStr = string.reverse(str); + local _, idx = string.find(revStr, subPattern, 1, plain); + if idx == nil then return nil end; + return string.len(revStr) - idx + 1; +end + +-- 反序裁剪字符串 如:print(subString("a.b/c", "/"))输出c +-- @return 未找到目标串返回nil. 否则返回被裁剪后的字符串 +function this.revSubString(str, subStr, plain) + local idx = this.revFindString(str, subStr, plain) + if idx == nil then return nil end; + return string.sub(str, idx + 1, str.length) +end + +-- 把字符串按reps分割成并放入table +-- @str 目标串 +-- @reps 分割符。注意这个分隔符是一个pattern +function this.stringSplit( str, separator ) + local retStrTable = {} + string.gsub(str, '[^' .. separator ..']+', function ( word ) + table.insert(retStrTable, word) + end) + return retStrTable; +end + +-- 保存CallbackId(通信序列号) +function this.setCallbackId( id ) + if id ~= nil and id ~= "0" then + recCallbackId = tostring(id); + end +end + +-- 读取CallbackId(通信序列号)。读取后记录值将被置空 +function this.getCallbackId() + if recCallbackId == nil then + recCallbackId = "0"; + end + local id = recCallbackId; + recCallbackId = "0"; + return id; +end + +-- reference from https://www.lua.org/pil/20.1.html +function this.trim (s) + return (string.gsub(s, "^%s*(.-)%s*$", "%1")) +end + +--返回table中成员数量(数字key和非数字key之和) +-- @t 目标table +-- @return 元素数量 +function this.getTableMemberNum(t) + local retNum = 0; + if type(t) ~= "table" then + this.printToVSCode("[debugger Error] getTableMemberNum get "..tostring(type(t)), 2) + return retNum; + end + for k,v in pairs(t) do + retNum = retNum + 1; + end + return retNum; +end + +-- 生成一个消息Table +function this.getMsgTable(cmd ,callbackId) + callbackId = callbackId or 0; + local msgTable = {}; + msgTable["cmd"] = cmd; + msgTable["callbackId"] = callbackId; + msgTable["info"] = {}; + return msgTable; +end + +function this.serializeTable(tab, name) + local sTable = tools.serializeTable(tab, name); + return sTable; +end +------------------------日志打印相关------------------------- +-- 把日志打印在VSCode端 +-- @str: 日志内容 +-- @printLevel: all(0)/info(1)/error(2) +-- @type: 0:vscode console 1:vscode tip +function this.printToVSCode(str, printLevel, type) + type = type or 0; + printLevel = printLevel or 0; + if currentRunState == runState.DISCONNECT or logLevel > printLevel then + return; + end + + local sendTab = {}; + sendTab["callbackId"] = "0"; + if type == 0 then + sendTab["cmd"] = "output"; + elseif type == 1 then + sendTab["cmd"] = "tip"; + else -- type == 2 + sendTab["cmd"] = "debug_console"; + end + sendTab["info"] = {}; + sendTab["info"]["logInfo"] = tostring(str); + this.sendMsg(sendTab); +end + +-- 把日志打印在控制台 +-- @str: 日志内容 +-- @printLevel: all(0)/info(1)/error(2) +function this.printToConsole(str, printLevel) + printLevel = printLevel or 0; + if consoleLogLevel > printLevel then + return; + end + print("[LuaPanda] ".. tostring(str)); +end + +----------------------------------------------------------------------------- +-- 提升兼容性方法 +----------------------------------------------------------------------------- +--生成平台无关的路径。 +--return:nil(error)/path +function this.genUnifiedPath(path) + if path == "" or path == nil then + return ""; + end + --大小写不敏感时,路径全部转为小写 + if pathCaseSensitivity == false then + path = string.lower(path); + end + --统一路径全部替换成/ + path = string.gsub(path, [[\]], "/"); + --处理 /../ /./ + local pathTab = this.stringSplit(path, '/'); + local newPathTab = {}; + for k, v in ipairs(pathTab) do + if v == '.' then + --continue + elseif v == ".." and #newPathTab >= 1 and newPathTab[#newPathTab]:sub(2,2) ~= ':' then + --newPathTab有元素,最后一项不是X: + table.remove(newPathTab); + else + table.insert(newPathTab, v); + end + end + --重新拼合后如果是mac路径第一位是/ + local newpath = table.concat(newPathTab, '/'); + if path:sub(1,1) == '/' then + newpath = '/'.. newpath; + end + + --win下按照winDiskSymbolUpper的设置修改盘符大小 + if "Windows_NT" == OSType then + if winDiskSymbolUpper then + newpath = newpath:gsub("^%a:", string.upper); + winDiskSymbolTip = "路径中Windows盘符已转为大写。" + else + newpath = newpath:gsub("^%a:", string.lower); + winDiskSymbolTip = "路径中Windows盘符已转为小写。" + end + end + + return newpath; +end + +function this.getCacheFormatPath(source) + if source == nil then return formatPathCache end; + return formatPathCache[source]; +end + +function this.setCacheFormatPath(source, dest) + formatPathCache[source] = dest; +end + +-- 处理 opath(info.source) 的函数, 生成一个规范的路径函数(和VScode端checkRightPath逻辑完全一致) +function this.formatOpath(opath) + -- delete @ + if opath:sub(1,1) == '@' then + opath = opath:sub(2); + end + -- change ./ to / + if opath:sub(1,2) == './' then + opath = opath:sub(2); + end + + opath = this.genUnifiedPath(opath); + + -- lower + if pathCaseSensitivity == false then + opath = string.lower(opath); + end + --把filename去除后缀 + if autoExt == nil or autoExt == '' then + -- 在虚拟机返回路径没有后缀的情况下,用户必须自设后缀 + -- 确定filePath中最后一个.xxx 不等于用户配置的后缀, 则把所有的. 转为 / + if not opath:find(luaFileExtension , (-1) * luaFileExtension:len(), true) then + -- getinfo 路径没有后缀,把 . 全部替换成 / ,我们不允许用户在文件(或文件夹)名称中出现"." , 因为无法区分 + opath = string.gsub(opath, "%.", "/"); + else + -- 有后缀,那么把除后缀外的部分中的. 转为 / + opath = this.changePotToSep(opath, luaFileExtension); + end + else + -- 虚拟机路径有后缀 + opath = this.changePotToSep(opath, autoExt); + end + + -- 截取 路径+文件名 (不带后缀) + -- change pot to / + -- opath = string.gsub(opath, "%.", "/"); + return opath; +end + +----------------------------------------------------------------------------- +-- 内存相关 +----------------------------------------------------------------------------- +function this.sendLuaMemory() + local luaMem = collectgarbage("count"); + local sendTab = {}; + sendTab["callbackId"] = "0"; + sendTab["cmd"] = "refreshLuaMemory"; + sendTab["info"] = {}; + sendTab["info"]["memInfo"] = tostring(luaMem); + this.sendMsg(sendTab); +end + +----------------------------------------------------------------------------- +-- 网络相关方法 +----------------------------------------------------------------------------- +-- 刷新socket +-- @return true/false 刷新成功/失败 +function this.reGetSock() + if server then return true end + + if sock ~= nil then + pcall(function() sock:close() end); + end + + --call slua-unreal luasocket + sock = lua_extension and lua_extension.luasocket and lua_extension.luasocket().tcp(); + if sock == nil then + --call normal luasocket + if pcall(function() sock = require("socket.core").tcp(); end) then + this.printToConsole("reGetSock success"); + else + --call custom function to get socket + if customGetSocketInstance and pcall( function() sock = customGetSocketInstance(); end ) then + this.printToConsole("reGetSock custom success"); + else + this.printToConsole("[Error] reGetSock fail", 2); + return false; + end + end + else + --set ue4 luasocket + this.printToConsole("reGetSock ue4 success"); + end + return true; +end + +-- 定时(以函数return为时机) 进行attach连接 +-- 返回值 hook 可以继续往下走时返回1 ,无需继续时返回0 +function this.reConnect() + if currentHookState == hookState.DISCONNECT_HOOK then + if os.time() - stopConnectTime < attachInterval then + -- 未到重连时间 + -- this.printToConsole("Reconnect time less than 1s"); + -- this.printToConsole("os.time:".. os.time() .. " | stopConnectTime:" ..stopConnectTime); + return 0; + end + this.printToConsole("Reconnect !"); + if sock == nil then + this.reGetSock(); + end + + local connectSuccess; + if luaProcessAsServer == true and currentRunState == runState.DISCONNECT then + -- 在 Server 模式下,以及当前处于未连接状态下,才尝试accept新链接。如果不判断可能会出现多次连接,导致sock被覆盖 + if server == nil then + this.bindServer(recordHost, recordPort); + end + + sock = server:accept(); + connectSuccess = sock; + else + sock:settimeout(connectTimeoutSec); + connectSuccess = this.sockConnect(sock); + end + + if connectSuccess then + this.printToConsole("reconnect success"); + this.connectSuccess(); + return 1; + else + this.printToConsole("reconnect failed" ); + stopConnectTime = os.time(); + return 0; + end + end + -- 不必重连,正常继续运行 + return 1; +end + +-- 向adapter发消息 +-- @sendTab 消息体table +function this.sendMsg( sendTab ) + if isNeedB64EncodeStr and sendTab["info"] ~= nil then + for _, v in ipairs(sendTab["info"]) do + if v["type"] == "string" then + v["value"] = tools.base64encode(v["value"]) + end + end + end + + local sendStr = json.encode(sendTab); + if currentRunState == runState.DISCONNECT then + this.printToConsole("[debugger error] disconnect but want sendMsg:" .. sendStr, 2); + this.disconnect(); + return; + end + + local succ,err; + if pcall(function() succ,err = sock:send(sendStr..TCPSplitChar.."\n"); end) then + if succ == nil then + if err == "closed" then + this.disconnect(); + end + end + end +end + +-- 处理 收到的消息 +-- @dataStr 接收的消息json +function this.dataProcess( dataStr ) + this.printToVSCode("debugger get:"..dataStr); + local dataTable = json.decode(dataStr); + if dataTable == nil then + this.printToVSCode("[error] Json is error", 2); + return; + end + + if dataTable.callbackId ~= "0" then + this.setCallbackId(dataTable.callbackId); + end + + if dataTable.cmd == "continue" then + local info = dataTable.info; + if info.isFakeHit == "true" and info.fakeBKPath and info.fakeBKLine then + -- 设置校验结果标志位,以便hook流程知道结果 + hitBpTwiceCheck = false; + if hookLib ~= nil and hookLib.set_bp_twice_check_res then + -- 把结果同步给C + hookLib.set_bp_twice_check_res(0); + end + -- 把假断点的信息加入cache + if nil == fakeBreakPointCache[info.fakeBKPath] then + fakeBreakPointCache[info.fakeBKPath] = {}; + end + table.insert(fakeBreakPointCache[info.fakeBKPath] ,info.fakeBKLine); + else + this.changeRunState(runState.RUN); + end + local msgTab = this.getMsgTable("continue", this.getCallbackId()); + this.sendMsg(msgTab); + + elseif dataTable.cmd == "stopOnStep" then + this.changeRunState(runState.STEPOVER); + local msgTab = this.getMsgTable("stopOnStep", this.getCallbackId()); + this.sendMsg(msgTab); + this.changeHookState(hookState.ALL_HOOK); + + elseif dataTable.cmd == "stopOnStepIn" then + this.changeRunState(runState.STEPIN); + local msgTab = this.getMsgTable("stopOnStepIn", this.getCallbackId()); + this.sendMsg(msgTab); + this.changeHookState(hookState.ALL_HOOK); + + elseif dataTable.cmd == "stopOnStepOut" then + this.changeRunState(runState.STEPOUT); + local msgTab = this.getMsgTable("stopOnStepOut", this.getCallbackId()); + this.sendMsg(msgTab); + this.changeHookState(hookState.ALL_HOOK); + + elseif dataTable.cmd == "setBreakPoint" then + this.printToVSCode("dataTable.cmd == setBreakPoint"); + -- 设置断点时,把 fakeBreakPointCache 清空。这是一个简单的做法,也可以清除具体的条目 + fakeBreakPointCache = {} + local bkPath = dataTable.info.path; + bkPath = this.genUnifiedPath(bkPath); + if testBreakpointFlag then + recordBreakPointPath = bkPath; + end + if autoPathMode then + -- 自动路径模式下,仅保留文件名 + -- table[文件名.后缀] -- [fullpath] -- [line , type] + -- | - [fullpath] -- [line , type] + + local bkShortPath = this.getFilenameFromPath(bkPath); + if breaks[bkShortPath] == nil then + breaks[bkShortPath] = {}; + end + breaks[bkShortPath][bkPath] = dataTable.info.bks; + -- 当v为空时,从断点列表中去除文件 + for k, v in pairs(breaks[bkShortPath]) do + if next(v) == nil then + breaks[bkShortPath][k] = nil; + end + end + else + if breaks[bkPath] == nil then + breaks[bkPath] = {}; + end + -- 两级 bk path 是为了和自动路径模式结构保持一致 + breaks[bkPath][bkPath] = dataTable.info.bks; + -- 当v为空时,从断点列表中去除文件 + for k, v in pairs(breaks[bkPath]) do + if next(v) == nil then + breaks[bkPath][k] = nil; + end + end + end + + -- 当v为空时,从断点列表中去除文件 + for k, v in pairs(breaks) do + if next(v) == nil then + breaks[k] = nil; + end + end + + --sync breaks to c + if hookLib ~= nil then + hookLib.sync_breakpoints(); + end + + if currentRunState ~= runState.WAIT_CMD then + if hookLib == nil then + local fileBP, G_BP =this.checkHasBreakpoint(lastRunFilePath); + if fileBP == false then + if G_BP == true then + this.changeHookState(hookState.MID_HOOK); + else + this.changeHookState(hookState.LITE_HOOK); + end + else + this.changeHookState(hookState.ALL_HOOK); + end + end + else + local msgTab = this.getMsgTable("setBreakPoint", this.getCallbackId()); + this.sendMsg(msgTab); + return; + end + --其他时机收到breaks消息 + local msgTab = this.getMsgTable("setBreakPoint", this.getCallbackId()); + this.sendMsg(msgTab); + -- 打印调试信息 + this.printToVSCode("LuaPanda.getInfo()\n" .. this.getInfo()) + this.debugger_wait_msg(); + elseif dataTable.cmd == "setVariable" then + if currentRunState == runState.STOP_ON_ENTRY or + currentRunState == runState.HIT_BREAKPOINT or + currentRunState == runState.STEPOVER_STOP or + currentRunState == runState.STEPIN_STOP or + currentRunState == runState.STEPOUT_STOP then + local msgTab = this.getMsgTable("setVariable", this.getCallbackId()); + local varRefNum = tonumber(dataTable.info.varRef); + local newValue = tostring(dataTable.info.newValue); + local needFindVariable = true; --如果变量是基础类型,直接赋值,needFindVariable = false; 如果变量是引用类型,needFindVariable = true + local varName = tostring(dataTable.info.varName); + -- 根据首末含有" ' 判断 newValue 是否是字符串 + local first_chr = string.sub(newValue, 1, 1); + local end_chr = string.sub(newValue, -1, -1); + if first_chr == end_chr then + if first_chr == "'" or first_chr == '"' then + newValue = string.sub(newValue, 2, -2); + needFindVariable = false; + end + end + --数字,nil,false,true的处理 + if newValue == "nil" and needFindVariable == true then newValue = nil; needFindVariable = false; + elseif newValue == "true" and needFindVariable == true then newValue = true; needFindVariable = false; + elseif newValue == "false" and needFindVariable == true then newValue = false; needFindVariable = false; + elseif tonumber(newValue) and needFindVariable == true then newValue = tonumber(newValue); needFindVariable = false; + end + + -- 如果新值是基础类型,则不需遍历 + if dataTable.info.stackId ~= nil and tonumber(dataTable.info.stackId) ~= nil and tonumber(dataTable.info.stackId) > 1 then + this.curStackId = tonumber(dataTable.info.stackId); + else + this.printToVSCode("未能获取到堆栈层级,默认使用 this.curStackId;") + end + + if varRefNum < 10000 then + -- 如果修改的是一个 引用变量,那么可直接赋值。但还是要走变量查询过程。查找和赋值过程都需要steakId。 目前给引用变量赋值Object,steak可能有问题 + msgTab.info = this.createSetValueRetTable(varName, newValue, needFindVariable, this.curStackId, variableRefTab[varRefNum]); + else + -- 如果修改的是一个基础类型 + local setLimit; --设置检索变量的限定区域 + if varRefNum >= 10000 and varRefNum < 20000 then setLimit = "local"; + elseif varRefNum >= 20000 and varRefNum < 30000 then setLimit = "global"; + elseif varRefNum >= 30000 then setLimit = "upvalue"; + end + msgTab.info = this.createSetValueRetTable(varName, newValue, needFindVariable, this.curStackId, nil, setLimit); + end + + this.sendMsg(msgTab); + this.debugger_wait_msg(); + end + + elseif dataTable.cmd == "getVariable" then + --仅在停止时处理消息,其他时刻收到此消息,丢弃 + if currentRunState == runState.STOP_ON_ENTRY or + currentRunState == runState.HIT_BREAKPOINT or + currentRunState == runState.STEPOVER_STOP or + currentRunState == runState.STEPIN_STOP or + currentRunState == runState.STEPOUT_STOP then + --发送变量给游戏,并保持之前的状态,等待再次接收数据 + --dataTable.info.varRef 10000~20000局部变量 + -- 20000~30000全局变量 + -- 30000~ upvalue + -- 1000~2000局部变量的查询,2000~3000全局,3000~4000upvalue + local msgTab = this.getMsgTable("getVariable", this.getCallbackId()); + local varRefNum = tonumber(dataTable.info.varRef); + if varRefNum < 10000 then + --查询变量, 此时忽略 stackId + local varTable = this.getVariableRef(dataTable.info.varRef, true); + msgTab.info = varTable; + elseif varRefNum >= 10000 and varRefNum < 20000 then + --局部变量 + if dataTable.info.stackId ~= nil and tonumber(dataTable.info.stackId) > 1 then + this.curStackId = tonumber(dataTable.info.stackId); + if type(currentCallStack[this.curStackId - 1]) ~= "table" or type(currentCallStack[this.curStackId - 1].func) ~= "function" then + local str = "getVariable getLocal currentCallStack " .. this.curStackId - 1 .. " Error\n" .. this.serializeTable(currentCallStack, "currentCallStack"); + this.printToVSCode(str, 2); + msgTab.info = {}; + else + local stackId = this.getSpecificFunctionStackLevel(currentCallStack[this.curStackId - 1].func); --去除偏移量 + local varTable = this.getVariable(stackId, true); + msgTab.info = varTable; + end + end + + elseif varRefNum >= 20000 and varRefNum < 30000 then + --全局变量 + local varTable = this.getGlobalVariable(); + msgTab.info = varTable; + elseif varRefNum >= 30000 then + --upValue + if dataTable.info.stackId ~= nil and tonumber(dataTable.info.stackId) > 1 then + this.curStackId = tonumber(dataTable.info.stackId); + if type(currentCallStack[this.curStackId - 1]) ~= "table" or type(currentCallStack[this.curStackId - 1].func) ~= "function" then + local str = "getVariable getUpvalue currentCallStack " .. this.curStackId - 1 .. " Error\n" .. this.serializeTable(currentCallStack, "currentCallStack"); + this.printToVSCode(str, 2); + msgTab.info = {}; + else + local varTable = this.getUpValueVariable(currentCallStack[this.curStackId - 1 ].func, true); + msgTab.info = varTable; + end + end + end + this.sendMsg(msgTab); + this.debugger_wait_msg(); + end + elseif dataTable.cmd == "initSuccess" then + --初始化会传过来一些变量,这里记录这些变量 + --Base64 + if dataTable.info.isNeedB64EncodeStr == "true" then + isNeedB64EncodeStr = true; + else + isNeedB64EncodeStr = false; + end + --path + luaFileExtension = dataTable.info.luaFileExtension; + local TempFilePath = dataTable.info.TempFilePath; + if TempFilePath:sub(-1, -1) == [[\]] or TempFilePath:sub(-1, -1) == [[/]] then + TempFilePath = TempFilePath:sub(1, -2); + end + TempFilePath_luaString = TempFilePath; + cwd = this.genUnifiedPath(dataTable.info.cwd); + --logLevel + logLevel = tonumber(dataTable.info.logLevel) or 1; + --autoPathMode + if dataTable.info.autoPathMode == "true" then + autoPathMode = true; + else + autoPathMode = false; + end + + if dataTable.info.pathCaseSensitivity == "true" then + pathCaseSensitivity = true; + truncatedOPath = dataTable.info.truncatedOPath or ""; + else + pathCaseSensitivity = false; + truncatedOPath = string.lower(dataTable.info.truncatedOPath or ""); + end + + if dataTable.info.distinguishSameNameFile == "true" then + distinguishSameNameFile = true; + else + distinguishSameNameFile = false; + end + + --OS type + if nil == OSType then + --用户未主动设置OSType, 接收VSCode传来的数据 + if type(dataTable.info.OSType) == "string" then + OSType = dataTable.info.OSType; + else + OSType = "Windows_NT"; + OSTypeErrTip = "未能检测出OSType, 可能是node os库未能加载,系统使用默认设置Windows_NT" + end + else + --用户自设OSType, 使用用户的设置 + end + + --检测用户是否自设了clib路径 + isUserSetClibPath = false; + if nil == clibPath then + --用户未设置clibPath, 接收VSCode传来的数据 + if type(dataTable.info.clibPath) == "string" then + clibPath = dataTable.info.clibPath; + else + clibPath = ""; + pathErrTip = "未能正确获取libpdebug库所在位置, 可能无法加载libpdebug库。"; + end + else + --用户自设clibPath + isUserSetClibPath = true; + end + + --查找c++的hook库是否存在. 当lua5.4时默认不使用c库 + if tostring(dataTable.info.useCHook) == "true" then + userSetUseClib = true; --用户确定使用clib + if isUserSetClibPath == true then --如果用户自设了clib路径 + if luapanda_chook ~= nil then + hookLib = luapanda_chook; + else + if not(this.tryRequireClib("libpdebug", clibPath)) then + this.printToVSCode("Require clib failed, use Lua to continue debug, use LuaPanda.doctor() for more information.", 1); + end + end + else + local clibExt, platform; + if OSType == "Darwin" then clibExt = "/?.so;"; platform = "mac"; + elseif OSType == "Linux" then clibExt = "/?.so;"; platform = "linux"; + else clibExt = "/?.dll;"; platform = "win"; end + + local lua_ver; + if _VERSION == "Lua 5.1" then + lua_ver = "501"; + elseif _VERSION == "Lua 5.4" then + lua_ver = "504"; + else + lua_ver = "503"; + end + + local x86Path = clibPath.. platform .."/x86/".. lua_ver .. clibExt; + local x64Path = clibPath.. platform .."/x86_64/".. lua_ver .. clibExt; + local armPath = clibPath .. platform .."/arm_64/".. lua_ver .. clibExt; + + if luapanda_chook ~= nil then + hookLib = luapanda_chook; + else + local requireCLibSuccess = false; + if platform == "mac" then + requireCLibSuccess = this.tryRequireClib("libpdebug", armPath) + end + + if not requireCLibSuccess and not(this.tryRequireClib("libpdebug", x64Path) or this.tryRequireClib("libpdebug", x86Path)) then + this.printToVSCode("Require clib failed, use Lua to continue debug, use LuaPanda.doctor() for more information.", 1); + end + end + end + else + userSetUseClib = false; + end + + --adapter版本信息 + adapterVer = tostring(dataTable.info.adapterVersion); + local msgTab = this.getMsgTable("initSuccess", this.getCallbackId()); + --回传是否使用了lib,是否有loadstring函数 + local isUseHookLib = 0; + if hookLib ~= nil then + isUseHookLib = 1; + --同步数据给c hook + local luaVerTable = this.stringSplit(debuggerVer , '%.'); + local luaVerNum = luaVerTable[1] * 10000 + luaVerTable[2] * 100 + luaVerTable[3]; + if hookLib.sync_lua_debugger_ver then + hookLib.sync_lua_debugger_ver(luaVerNum); + end + -- hookLib.sync_config(logLevel, pathCaseSensitivity and 1 or 0, autoPathMode and 1 or 0); + hookLib.sync_config(logLevel, pathCaseSensitivity and 1 or 0); + hookLib.sync_tempfile_path(TempFilePath_luaString); + hookLib.sync_cwd(cwd); + hookLib.sync_file_ext(luaFileExtension); + end + --detect LoadString + isUseLoadstring = 0; + if debugger_loadString ~= nil and type(debugger_loadString) == "function" then + if(pcall(debugger_loadString("return 0"))) then + isUseLoadstring = 1; + end + end + local tab = { debuggerVer = tostring(debuggerVer) , UseHookLib = tostring(isUseHookLib) , UseLoadstring = tostring(isUseLoadstring), isNeedB64EncodeStr = tostring(isNeedB64EncodeStr) }; + msgTab.info = tab; + this.sendMsg(msgTab); + --上面getBK中会判断当前状态是否WAIT_CMD, 所以最后再切换状态。 + stopOnEntry = dataTable.info.stopOnEntry; + if dataTable.info.stopOnEntry == "true" then + this.changeRunState(runState.STOP_ON_ENTRY); --停止在STOP_ON_ENTRY再接收breaks消息 + else + this.debugger_wait_msg(1); --等待1s bk消息 如果收到或超时(没有断点)就开始运行 + this.changeRunState(runState.RUN); + end + + elseif dataTable.cmd == "getWatchedVariable" then + local msgTab = this.getMsgTable("getWatchedVariable", this.getCallbackId()); + local stackId = tonumber(dataTable.info.stackId); + --loadstring系统函数, watch插件加载 + if isUseLoadstring == 1 then + --使用loadstring + this.curStackId = stackId; + local retValue = this.processWatchedExp(dataTable.info); + msgTab.info = retValue + this.sendMsg(msgTab); + this.debugger_wait_msg(); + return; + else + --旧的查找方式 + local wv = this.getWatchedVariable(dataTable.info.varName, stackId, true); + if wv ~= nil then + msgTab.info = wv; + end + this.sendMsg(msgTab); + this.debugger_wait_msg(); + end + elseif dataTable.cmd == "stopRun" then + --停止hook,已不在处理任何断点信息,也就不会产生日志等。发送消息后等待前端主动断开连接 + local msgTab = this.getMsgTable("stopRun", this.getCallbackId()); + this.sendMsg(msgTab); + if not luaProcessAsServer then + this.disconnect(); + end + elseif "LuaGarbageCollect" == dataTable.cmd then + this.printToVSCode("collect garbage!"); + collectgarbage("collect"); + --回收后刷一下内存 + this.sendLuaMemory(); + this.debugger_wait_msg(); + elseif "runREPLExpression" == dataTable.cmd then + this.curStackId = tonumber(dataTable.info.stackId); + local retValue = this.processExp(dataTable.info); + local msgTab = this.getMsgTable("runREPLExpression", this.getCallbackId()); + msgTab.info = retValue + this.sendMsg(msgTab); + this.debugger_wait_msg(); + else + end +end + +-- 变量赋值的处理函数。基本逻辑是先从当前栈帧(curStackId)中取 newValue 代表的变量,找到之后再把找到的值通过setVariableValue写回。 +-- @varName 被设置值的变量名 +-- @newValue 新值的名字,它是一个string +-- @needFindVariable 是否需要查找引用变量。(用户输入的是否是一个Object) +-- @curStackId 当前栈帧(查找和变量赋值用) +-- @assigndVar 被直接赋值(省去查找过程) +-- @setLimit 赋值时的限制范围(local upvalue global) +function this.createSetValueRetTable(varName, newValue, needFindVariable, curStackId, assigndVar , setLimit) + local info; + local getVarRet; + -- needFindVariable == true,则使用getWatchedVariable处理(可选, 用来支持 a = b (b为变量的情况))。 + if needFindVariable == false then + getVarRet = {}; + getVarRet[1] = {variablesReference = 0, value = newValue, name = varName, type = type(newValue)}; + else + getVarRet = this.getWatchedVariable( tostring(newValue), curStackId, true); + end + if getVarRet ~= nil then + -- newValue赋变量真实值 + local realVarValue; + local displayVarValue = getVarRet[1].value; + if needFindVariable == true then + if tonumber(getVarRet[1].variablesReference) > 0 then + realVarValue = variableRefTab[tonumber(getVarRet[1].variablesReference)]; + else + if getVarRet[1].type == 'number' then realVarValue = tonumber(getVarRet[1].value) end + if getVarRet[1].type == 'string' then + realVarValue = tostring(getVarRet[1].value); + local first_chr = string.sub(realVarValue, 1, 1); + local end_chr = string.sub(realVarValue, -1, -1); + if first_chr == end_chr then + if first_chr == "'" or first_chr == '"' then + realVarValue = string.sub(realVarValue, 2, -2); + displayVarValue = realVarValue; + end + end + end + if getVarRet[1].type == 'boolean' then + if getVarRet[1].value == "true" then + realVarValue = true; + else + realVarValue = false; + end + end + if getVarRet[1].type == 'nil' then realVarValue = nil end + end + else + realVarValue = getVarRet[1].value; + end + + local setVarRet; + if type(assigndVar) ~= table then + setVarRet = this.setVariableValue( varName, curStackId, realVarValue, setLimit ); + else + assigndVar[varName] = realVarValue; + setVarRet = true; + end + + if getVarRet[1].type == "string" then + displayVarValue = '"' .. displayVarValue .. '"'; + end + + if setVarRet ~= false and setVarRet ~= nil then + local retTip = "变量 ".. varName .." 赋值成功"; + info = { success = "true", name = getVarRet[1].name , type = getVarRet[1].type , value = displayVarValue, variablesReference = tostring(getVarRet[1].variablesReference), tip = retTip}; + else + info = { success = "false", type = type(realVarValue), value = displayVarValue, tip = "找不到要设置的变量"}; + end + + else + info = { success = "false", type = nil, value = nil, tip = "输入的值无意义"}; + end + return info +end + +--接收消息 +--这里维护一个接收消息队列,因为Lua端未做隔断符保护,变量赋值时请注意其中不要包含隔断符 |*| +-- @timeoutSec 超时时间 +-- @return boolean 成功/失败 +function this.receiveMessage( timeoutSec ) + timeoutSec = timeoutSec or MAX_TIMEOUT_SEC; + sock:settimeout(timeoutSec); + --如果队列中还有消息,直接取出来交给dataProcess处理 + if #recvMsgQueue > 0 then + local saved_cmd = recvMsgQueue[1]; + table.remove(recvMsgQueue, 1); + this.dataProcess(saved_cmd); + return true; + end + + if currentRunState == runState.DISCONNECT then + this.disconnect(); + return false; + end + + if sock == nil then + this.printToConsole("[debugger error]接收信息失败 | reason: socket == nil", 2); + return; + end + local response, err = sock:receive("*l"); + if response == nil then + if err == "closed" then + this.printToConsole("[debugger error]接收信息失败 | reason:"..err, 2); + this.disconnect(); + end + return false; + else + + --判断是否是一条消息,分拆 + local proc_response = string.sub(response, 1, -1 * (TCPSplitChar:len() + 1 )); + local match_res = string.find(proc_response, TCPSplitChar, 1, true); + if match_res == nil then + --单条 + this.dataProcess(proc_response); + else + --有粘包 + repeat + --待处理命令 + local str1 = string.sub(proc_response, 1, match_res - 1); + table.insert(recvMsgQueue, str1); + --剩余匹配 + local str2 = string.sub(proc_response, match_res + TCPSplitChar:len() , -1); + match_res = string.find(str2, TCPSplitChar, 1, true); + until not match_res + this.receiveMessage(); + end + return true; + end +end + +--这里不用循环,在外面处理完消息会在调用回来 +-- @timeoutSec 等待时间s +-- @entryFlag 入口标记,用来标识是从哪里调入的 +function this.debugger_wait_msg(timeoutSec) + timeoutSec = timeoutSec or MAX_TIMEOUT_SEC; + + if currentRunState == runState.WAIT_CMD then + local ret = this.receiveMessage(timeoutSec); + return ret; + end + + if currentRunState == runState.STEPOVER or + currentRunState == runState.STEPIN or + currentRunState == runState.STEPOUT or + currentRunState == runState.RUN then + this.receiveMessage(0); + return + end + + if currentRunState == runState.STEPOVER_STOP or + currentRunState == runState.STEPIN_STOP or + currentRunState == runState.STEPOUT_STOP or + currentRunState == runState.HIT_BREAKPOINT or + currentRunState == runState.STOP_ON_ENTRY + then + this.sendLuaMemory(); + this.receiveMessage(MAX_TIMEOUT_SEC); + return + end +end + +----------------------------------------------------------------------------- +-- 调试器核心方法 +----------------------------------------------------------------------------- + +------------------------堆栈管理------------------------- + + +--getStackTable需要建立stackTable,保存每层的lua函数实例(用来取upvalue),保存函数展示层级和ly的关系(便于根据前端传来的stackId查局部变量) +-- @level 要获取的层级 +function this.getStackTable( level ) + local functionLevel = 0 + if hookLib ~= nil then + functionLevel = level or HOOK_LEVEL; + else + functionLevel = level or this.getSpecificFunctionStackLevel(lastRunFunction.func); + end + local stackTab = {}; + local userFuncSteakLevel = 0; --用户函数的steaklevel + local clevel = 0 + repeat + local info = debug.getinfo(functionLevel, "SlLnf") + if info == nil then + break; + end + if info.source ~= "=[C]" then + local ss = {}; + ss.file = this.getPath(info); + local oPathFormated = this.formatOpath(info.source) ; --从lua虚拟机获得的原始路径, 它用于帮助定位VScode端原始lua文件的位置(存在重名文件的情况)。 + ss.oPath = this.truncatedPath(oPathFormated, truncatedOPath); + ss.name = "文件名"; --这里要做截取 + ss.line = tostring(info.currentline); + --使用hookLib时,堆栈有偏移量,这里统一调用栈顶编号2 + local ssindex = functionLevel - 3; + if hookLib ~= nil then + ssindex = ssindex + 2; + end + ss.index = tostring(ssindex); + table.insert(stackTab,ss); + --把数据存入currentCallStack + local callStackInfo = {}; + callStackInfo.name = ss.file; + callStackInfo.line = ss.line; + callStackInfo.func = info.func; --保存的function + callStackInfo.realLy = functionLevel; --真实堆栈层functionLevel(仅debug时用) + table.insert(currentCallStack, callStackInfo); + + --level赋值 + if userFuncSteakLevel == 0 then + userFuncSteakLevel = functionLevel; + end + else + local callStackInfo = {}; + callStackInfo.name = info.source; + callStackInfo.line = info.currentline; --C函数行号 + callStackInfo.func = info.func; --保存的function + callStackInfo.realLy = functionLevel; --真实堆栈层functionLevel(仅debug时用) + table.insert(currentCallStack, callStackInfo); + clevel = clevel + 1 + end + functionLevel = functionLevel + 1; + until info == nil + return stackTab, userFuncSteakLevel; +end + +-- 把路径中去除后缀部分的.变为/, +-- @filePath 被替换的路径 +-- @ext 后缀(后缀前的 . 不会被替换) +function this.changePotToSep(filePath, ext) + local idx = filePath:find(ext, (-1) * ext:len() , true) + if idx then + local tmp = filePath:sub(1, idx - 1):gsub("%.", "/"); + filePath = tmp .. ext; + end + return filePath; +end + +--- this.truncatedPath 从 beTruncatedPath 字符串中去除 rep 匹配到的部分 +function this.truncatedPath(beTruncatedPath, rep) + if beTruncatedPath and beTruncatedPath ~= '' and rep and rep ~= "" then + local _, lastIdx = string.find(beTruncatedPath , rep); + if lastIdx then + beTruncatedPath = string.sub(beTruncatedPath, lastIdx + 1); + end + end + return beTruncatedPath; +end + +--这个方法是根据的cwd和luaFileExtension对getInfo获取到的路径进行标准化 +-- @info getInfo获取的包含调用信息table +function this.getPath( info ) + local filePath = info; + if type(info) == "table" then + filePath = info.source; + end + --尝试从Cache中获取路径 + local cachePath = this.getCacheFormatPath(filePath); + if cachePath~= nil and type(cachePath) == "string" then + return cachePath; + end + + -- originalPath是getInfo的原始路径,后面用来填充路径缓存的key + local originalPath = filePath; + + --如果路径头部有@,去除 + if filePath:sub(1,1) == '@' then + filePath = filePath:sub(2); + end + + --如果路径头部有./,去除 + if filePath:sub(1,2) == './' then + filePath = filePath:sub(3); + end + -- getPath的参数路径可能来自于hook, 也可能是一个已标准的路径 + if userDotInRequire then + if autoExt == nil or autoExt == '' then + -- 在虚拟机返回路径没有后缀的情况下,用户必须自设后缀 + -- 确定filePath中最后一个.xxx 不等于用户配置的后缀, 则把所有的. 转为 / + if not filePath:find(luaFileExtension , (-1) * luaFileExtension:len(), true) then + -- getinfo 路径没有后缀,把 . 全部替换成 / ,我们不允许用户在文件(或文件夹)名称中出现"." , 因为无法区分 + filePath = string.gsub(filePath, "%.", "/"); + else + -- 有后缀,那么把除后缀外的部分中的. 转为 / + filePath = this.changePotToSep(filePath, luaFileExtension); + end + + else + -- 虚拟机路径有后缀 + filePath = this.changePotToSep(filePath, autoExt); + end + end + + --后缀处理 + if luaFileExtension ~= "" then + --判断后缀中是否包含%1等魔法字符.用于从lua虚拟机获取到的路径含.的情况 + if string.find(luaFileExtension, "%%%d") then + filePath = string.gsub(filePath, "%.[%w%.]+$", luaFileExtension); + else + filePath = string.gsub(filePath, "%.[%w%.]+$", ""); + filePath = filePath .. "." .. luaFileExtension; + end + end + + + if not autoPathMode then + --绝对路径和相对路径的处理 | 若在Mac下以/开头,或者在Win下以*:开头,说明是绝对路径,不需要再拼。 + if filePath:sub(1,1) == [[/]] or filePath:sub(1,2):match("^%a:") then + isAbsolutePath = true; + else + isAbsolutePath = false; + if cwd ~= "" then + --查看filePath中是否包含cwd + local matchRes = string.find(filePath, cwd, 1, true); + if matchRes == nil then + filePath = cwd.."/"..filePath; + end + end + end + end + filePath = this.genUnifiedPath(filePath); + + if autoPathMode then + -- 自动路径模式下,只保留文件名 + filePath = this.getFilenameFromPath(filePath) + end + --放入Cache中缓存 + this.setCacheFormatPath(originalPath, filePath); + return filePath; +end + +--从路径中获取[文件名.后缀] +function this.getFilenameFromPath(path) + if path == nil then + return ''; + end + + return string.match(path, "([^/]*)$"); +end + +--获取当前函数的堆栈层级 +--原理是向上查找,遇到DebuggerFileName就调过。但是可能存在代码段和C导致不确定性。目前使用getSpecificFunctionStackLevel代替。 +function this.getCurrentFunctionStackLevel() + -- print(debug.traceback("===getCurrentFunctionStackLevel Stack trace===")) + local funclayer = 2; + repeat + local info = debug.getinfo(funclayer, "S"); --通过name来判断 + if info ~= nil then + local matchRes = ((info.source == DebuggerFileName) or (info.source == DebuggerToolsName)); + if matchRes == false then + return (funclayer - 1); + end + end + funclayer = funclayer + 1; + until not info + return 0; +end + +--获取指定函数的堆栈层级 +--通常用来获取最后一个用户函数的层级,用法是从currentCallStack取用户点击的栈,再使用本函数取对应层级。 +-- @func 被获取层级的function +function this.getSpecificFunctionStackLevel( func ) + local funclayer = 2; + repeat + local info = debug.getinfo(funclayer, "f"); --通过name来判断 + if info ~= nil then + if info.func == func then + return (funclayer - 1); + end + end + funclayer = funclayer + 1; + until not info + return 0; +end + +--检查当前堆栈是否是Lua +-- @checkLayer 指定的栈层 +function this.checkCurrentLayerisLua( checkLayer ) + local info = debug.getinfo(checkLayer, "S"); + if info == nil then + return nil; + end + info.source = this.genUnifiedPath(info.source); + if info ~= nil then + for k,v in pairs(info) do + if k == "what" then + if v == "C" then + return false; + else + return true; + end + end + end + end + return nil; +end + +-- 在 fakeBreakPointCache 中查询此断点是否真实存在 +-- 因为同名文件的影响, 有些断点是命中错误的。经过VScode校验后,这些错误命中的断点信息被存在fakeBreakPointCache中 +function this.checkRealHitBreakpoint( oPath, line ) + -- 在假命中列表中搜索,如果本行有过假命中记录,返回 false + if oPath and fakeBreakPointCache[oPath] then + for _, value in ipairs(fakeBreakPointCache[oPath]) do + if tonumber(value) == tonumber(line) then + this.printToVSCode("cache hit bp in same name file. source:" .. tostring(oPath) .. " line:" .. tostring(line)); + return false; + end + end + end + return true; +end + +------------------------断点处理------------------------- +--- this.isHitBreakpoint 判断断点是否命中。这个方法在c mod以及lua中都有调用 +-- @param breakpointPath 文件名+后缀 +-- @param opath getinfo path +-- @param curLine 当前执行行号 +function this.isHitBreakpoint(breakpointPath, opath, curLine) + if breaks[breakpointPath] then + local oPathFormated; + for fullpath, fullpathNode in pairs(breaks[breakpointPath]) do + recordBreakPointPath = fullpath; --这里是为了兼容用户断点行号没有打对的情况 + local line_hit,cur_node = false,{}; + for _, node in ipairs(fullpathNode) do + if tonumber(node["line"]) == tonumber(curLine) then + line_hit = true; -- fullpath 文件中 有行号命中 + cur_node = node; + recordBreakPointPath = fullpath; --行号命中后,再设置一次,保证路径准确 + break; + end + end + + -- 在lua端不知道是否有同名文件,基本思路是先取文件名,用文件名和breakpointArray 进行匹配。 + -- 当文件名匹配上时,可能存在多个同名文件中存在断点的情况。这时候需要用 oPath 和 fullpath 进行对比,取出正确的。 + -- 当本地文件中有断点,lua做了初步命中后,可能存在 stack , 断点文件有同名的情况。这就需要vscode端也需要checkfullpath函数,使用opath进行文件校验。 + if line_hit then + if oPathFormated == nil then + -- 为了避免性能消耗,仅在行号命中时才处理 opath 到标准化路径 + oPathFormated = this.formatOpath(opath); + -- 截取 + oPathFormated = this.truncatedPath(oPathFormated, truncatedOPath); + end + + if (not distinguishSameNameFile) or (string.match(fullpath, oPathFormated ) and this.checkRealHitBreakpoint(opath, curLine)) then + -- type是TS中的枚举类型,其定义在BreakPoint.tx文件中 + -- enum BreakpointType { + -- conditionBreakpoint = 0, + -- logPoint, + -- lineBreakpoint + -- } + + -- 处理断点 + if cur_node["type"] == "0" then + -- condition breakpoint + -- 注意此处不要使用尾调用,否则会影响调用栈,导致Lua5.3和Lua5.1中调用栈层级不同 + local conditionRet = this.IsMeetCondition(cur_node["condition"]); + -- this.printToVSCode("Condition BK: condition:" .. cur_node["condition"] .. " conditionRet " .. tostring(conditionRet)); + return conditionRet; + elseif cur_node["type"] == "1" then + -- log point + this.printToVSCode("[LogPoint Output]: " .. cur_node["logMessage"], 2, 2); + return false; + else + -- line breakpoint + return true; + end + end + end + end + else + testBreakpointFlag = false; --如果用户打开了测试断点的标志位而未主动关闭,会在lua继续运行时关闭。 + recordBreakPointPath = ''; --当切换文件时置空,避免提示给用户错误信息 + end + return false; +end + +-- 条件断点处理函数 +-- 返回true表示条件成立 +-- @conditionExp 条件表达式 +function this.IsMeetCondition(conditionExp) + -- 判断条件之前更新堆栈信息 + currentCallStack = {}; + variableRefTab = {}; + variableRefIdx = 1; + if hookLib then + this.getStackTable(4); + else + this.getStackTable(); + end + + this.curStackId = 2; --在用户空间最上层执行 + + local conditionExpTable = {["varName"] = conditionExp} + local retTable = this.processWatchedExp(conditionExpTable) + + local isMeetCondition = false; + local function HandleResult() + if retTable[1]["isSuccess"] == "true" then + if retTable[1]["value"] == "nil" or (retTable[1]["value"] == "false" and retTable[1]["type"] == "boolean") then + isMeetCondition = false; + else + isMeetCondition = true; + end + else + isMeetCondition = false; + end + end + + xpcall(HandleResult, function() isMeetCondition = false; end) + return isMeetCondition; +end + +--加入断点函数 +function this.BP() + this.printToConsole("BP()"); + if hookLib == nil then + if currentHookState == hookState.DISCONNECT_HOOK then + this.printToConsole("BP() but NO HOOK"); + return; + end + + local co, isMain = coroutine.running(); + if _VERSION == "Lua 5.1" then + if co == nil then + isMain = true; + else + isMain = false; + end + end + + if isMain == true then + this.printToConsole("BP() in main"); + else + this.printToConsole("BP() in coroutine"); + debug.sethook(co, this.debug_hook, "lrc"); + end + hitBP = true; + else + if hookLib.get_libhook_state() == hookState.DISCONNECT_HOOK then + this.printToConsole("BP() but NO C HOOK"); + return; + end + + --clib, set hitBP + hookLib.sync_bp_hit(1); + end + this.changeHookState(hookState.ALL_HOOK); + return true; +end + +-- 检查当前文件中是否有断点 +-- 如果填写参数fileName 返回fileName中有无断点, 全局有无断点 +-- fileName为空,返回全局是否有断点 +function this.checkHasBreakpoint(fileName) + local hasBk = false; + --有无全局断点 + if next(breaks) == nil then + hasBk = false; + else + hasBk = true; + end + --当前文件中是否有断点 + if fileName ~= nil then + return breaks[fileName] ~= nil, hasBk; + else + return hasBk; + end +end + +function this.checkfuncHasBreakpoint(sLine, eLine, fileName) + if breaks[fileName] == nil then + return false; + end + sLine = tonumber(sLine); + eLine = tonumber(eLine); + + --起始行号>结束行号,或者sLine = eLine = 0 + if sLine >= eLine then + return true; + end + + if this.getTableMemberNum(breaks[fileName]) <= 0 then + return false; + else + for k,v in pairs(breaks[fileName]) do + for _, node in ipairs(v) do + if tonumber(node.line) > sLine and tonumber(node.line) <= eLine then + return true; + end + end + end + end + return false; +end +------------------------HOOK模块------------------------- +-- 钩子函数 +-- @event 执行状态(call,return,line) +-- @line 行号 +function this.debug_hook(event, line) + if this.reConnect() == 0 then return; end + + if logLevel == 0 then + local logTable = {"-----enter debug_hook-----\n", "event:", event, " line:", tostring(line), " currentHookState:",currentHookState," currentRunState:", currentRunState}; + local logString = table.concat(logTable); + this.printToVSCode(logString); + end + + --litehook 仅非阻塞接收断点 + if currentHookState == hookState.LITE_HOOK then + local ti = os.time(); + if ti - receiveMsgTimer > 1 then + this.debugger_wait_msg(0); + receiveMsgTimer = ti; + end + return; + end + + --运行中 + local info; + local co, isMain = coroutine.running(); + if _VERSION == "Lua 5.1" then + if co == nil then + isMain = true; + else + isMain = false; + end + end + isInMainThread = isMain; + if isMain == true then + info = debug.getinfo(2, "Slf") + else + info = debug.getinfo(co, 2, "Slf") + end + info.event = event; + + this.real_hook_process(info); +end + +function this.real_hook_process(info) + local jumpFlag = false; + local event = info.event; + + --如果当前行在Debugger中,不做处理 + local matchRes = ((info.source == DebuggerFileName) or (info.source == DebuggerToolsName)); + if matchRes == true then + return; + end + + --即使MID hook在C中, 或者是Run或者单步时也接收消息 + if currentRunState == runState.RUN or + currentRunState == runState.STEPOVER or + currentRunState == runState.STEPIN or + currentRunState == runState.STEPOUT then + local ti = os.time(); + if ti - receiveMsgTimer > 1 then + this.debugger_wait_msg(0); + receiveMsgTimer = ti; + end + end + + --不处理C函数 + if info.source == "=[C]" then + this.printToVSCode("current method is C"); + return; + end + + --不处理 slua "temp buffer" + if info.source == "temp buffer" then + this.printToVSCode("current method is in temp buffer"); + return; + end + + --不处理 xlua "chunk" + if info.source == "chunk" then + this.printToVSCode("current method is in chunk"); + return; + end + + --lua 代码段的处理,目前暂不调试代码段。 + if info.short_src:match("%[string \"") then + --当shortSrc中出现[string时]。要检查一下source, 区别是路径还是代码段. 方法是看路径中有没有\t \n ; + if info.source:match("[\n;=]") then + --是代码段,调过 + this.printToVSCode("hook jump Code String!"); + jumpFlag = true; + end + end + + --标准路径处理 + if jumpFlag == false then + info.orininal_source = info.source; --使用 info.orininal_source 记录lua虚拟机传来的原始路径 + info.source = this.getPath(info); + end + --本次执行的函数和上次执行的函数作对比,防止在一行停留两次 + if lastRunFunction["currentline"] == info["currentline"] and lastRunFunction["source"] == info["source"] and lastRunFunction["func"] == info["func"] and lastRunFunction["event"] == event then + this.printToVSCode("run twice"); + end + --记录最后一次调用信息 + if jumpFlag == false then + lastRunFunction = info; + lastRunFunction["event"] = event; + lastRunFilePath = info.source; + end + --输出函数信息到前台 + if logLevel == 0 and jumpFlag == false then + local logTable = {"[lua hook] event:", tostring(event), " currentRunState:",tostring(currentRunState)," currentHookState:",tostring(currentHookState)," jumpFlag:", tostring(jumpFlag)}; + for k,v in pairs(info) do + table.insert(logTable, tostring(k)); + table.insert(logTable, ":"); + table.insert(logTable, tostring(v)); + table.insert(logTable, " "); + end + local logString = table.concat(logTable); + this.printToVSCode(logString); + end + + --仅在line时做断点判断。进了断点之后不再进入本次STEP类型的判断,用Aflag做标记 + local isHit = false; + if tostring(event) == "line" and jumpFlag == false then + if currentRunState == runState.RUN or currentRunState == runState.STEPOVER or currentRunState == runState.STEPIN or currentRunState == runState.STEPOUT then + --断点判断 + isHit = this.isHitBreakpoint(info.source, info.orininal_source, info.currentline) or hitBP; + if isHit == true then + this.printToVSCode("HitBreakpoint!"); + --备份信息 + local recordStepOverCounter = stepOverCounter; + local recordStepOutCounter = stepOutCounter; + local recordCurrentRunState = currentRunState; + --计数器清0 + stepOverCounter = 0; + stepOutCounter = 0; + this.changeRunState(runState.HIT_BREAKPOINT); + hitBpTwiceCheck = true; -- 命中标志默认设置为true, 如果校验通过,会保留这个标记,校验失败会修改 + if hitBP then + hitBP = false; --hitBP是断点硬性命中标记 + --发消息并等待 + this.SendMsgWithStack("stopOnCodeBreakpoint"); + else + --发消息并等待 + this.SendMsgWithStack("stopOnBreakpoint"); + --若二次校验未命中,恢复状态 + if hitBpTwiceCheck == false then + isHit = false; + -- 确认未命中,把状态恢复,继续运行 + this.changeRunState(recordCurrentRunState); + stepOverCounter = recordStepOverCounter; + stepOutCounter = recordStepOutCounter; + end + end + end + end + end + + if isHit == true then + return; + end + + if currentRunState == runState.STEPOVER then + -- line stepOverCounter!= 0 不作操作 + -- line stepOverCounter == 0 停止 + if event == "line" and stepOverCounter <= 0 and jumpFlag == false then + stepOverCounter = 0; + this.changeRunState(runState.STEPOVER_STOP) + this.SendMsgWithStack("stopOnStep"); + elseif event == "return" or event == "tail return" then + --5.1中是tail return + if stepOverCounter ~= 0 then + stepOverCounter = stepOverCounter - 1; + end + elseif event == "call" then + stepOverCounter = stepOverCounter + 1; + end + elseif currentRunState == runState.STOP_ON_ENTRY then + --在Lua入口点处直接停住 + if event == "line" and jumpFlag == false then + --初始化内存分析的变量 + -- MemProfiler.getSystemVar(); + --这里要判断一下是Lua的入口点,否则停到 + this.SendMsgWithStack("stopOnEntry"); + end + elseif currentRunState == runState.STEPIN then + if event == "line" and jumpFlag == false then + this.changeRunState(runState.STEPIN_STOP) + this.SendMsgWithStack("stopOnStepIn"); + end + elseif currentRunState == runState.STEPOUT then + --line 不做操作 + --in 计数器+1 + --out 计数器-1 + if jumpFlag == false then + if stepOutCounter <= -1 then + stepOutCounter = 0; + this.changeRunState(runState.STEPOUT_STOP) + this.SendMsgWithStack("stopOnStepOut"); + end + end + + if event == "return" or event == "tail return" then + stepOutCounter = stepOutCounter - 1; + elseif event == "call" then + stepOutCounter = stepOutCounter + 1; + end + end + + --在RUN时检查并改变状态 + if hookLib == nil then + if currentRunState == runState.RUN and jumpFlag == false and currentHookState ~= hookState.DISCONNECT_HOOK then + local fileBP, G_BP = this.checkHasBreakpoint(lastRunFilePath); + if fileBP == false then + --文件无断点 + if G_BP == true then + this.changeHookState(hookState.MID_HOOK); + else + this.changeHookState(hookState.LITE_HOOK); + end + else + --文件有断点, 判断函数内是否有断点 + local funHasBP = this.checkfuncHasBreakpoint(lastRunFunction.linedefined, lastRunFunction.lastlinedefined, lastRunFilePath); + if funHasBP then + --函数定义范围内 + this.changeHookState(hookState.ALL_HOOK); + else + this.changeHookState(hookState.MID_HOOK); + end + end + + --MID_HOOK状态下,return需要在下一次hook检查文件(return时,还是当前文件,检查文件时状态无法转换) + if (event == "return" or event == "tail return") and currentHookState == hookState.MID_HOOK then + this.changeHookState(hookState.ALL_HOOK); + end + end + end +end + +-- 向Vscode发送标准通知消息,cmdStr是消息类型 +-- @cmdStr 命令字 +function this.SendMsgWithStack(cmdStr) + local msgTab = this.getMsgTable(cmdStr); + local userFuncLevel = 0; + msgTab["stack"] , userFuncLevel= this.getStackTable(); + if userFuncLevel ~= 0 then + lastRunFunction["func"] = debug.getinfo( (userFuncLevel - 1) , 'f').func; + end + this.sendMsg(msgTab); + this.debugger_wait_msg(); +end + +-- hook状态改变 +-- @s 目标状态 +function this.changeHookState( s ) + if hookLib == nil and currentHookState == s then + return; + end + + this.printToConsole("change hook state :"..s) + if s ~= hookState.DISCONNECT_HOOK then + this.printToVSCode("change hook state : "..s) + end + + currentHookState = s; + if s == hookState.DISCONNECT_HOOK then + --为了实现通用attach模式,require即开始hook,利用r作为时机发起连接 + if openAttachMode == true then + if hookLib then hookLib.lua_set_hookstate(hookState.DISCONNECT_HOOK); else debug.sethook(this.debug_hook, "r", 1000000); end + else + if hookLib then hookLib.endHook(); else debug.sethook(); end + end + elseif s == hookState.LITE_HOOK then + if hookLib then hookLib.lua_set_hookstate(hookState.LITE_HOOK); else debug.sethook(this.debug_hook, "r"); end + elseif s == hookState.MID_HOOK then + if hookLib then hookLib.lua_set_hookstate(hookState.MID_HOOK); else debug.sethook(this.debug_hook, "rc"); end + elseif s == hookState.ALL_HOOK then + if hookLib then hookLib.lua_set_hookstate(hookState.ALL_HOOK); else debug.sethook(this.debug_hook, "lrc");end + end + --coroutine + if hookLib == nil then + this.changeCoroutinesHookState(); + end +end + +-- 运行状态机,状态变更 +-- @s 目标状态 +-- @isFromHooklib 1:从libc库中发来的状态改变 | 0:lua发来的状态改变 +function this.changeRunState(s , isFromHooklib) + local msgFrom; + if isFromHooklib == 1 then + msgFrom = "libc"; + else + msgFrom = "lua"; + end + + --WAIT_CMD状态会等待接收消息,以下两个状态下不能发消息 + this.printToConsole("changeRunState :"..s.. " | from:"..msgFrom); + if s ~= runState.DISCONNECT and s ~= runState.WAIT_CMD then + this.printToVSCode("changeRunState :"..s.." | from:"..msgFrom); + end + + if hookLib ~= nil and isFromHooklib ~= 1 then + hookLib.lua_set_runstate(s); + end + currentRunState = s; + --状态切换时,清除记录栈信息的状态 + currentCallStack = {}; + variableRefTab = {}; + variableRefIdx = 1; +end + +-- 修改协程状态 +-- @s hook标志位 +function this.changeCoroutinesHookState(s) + s = s or currentHookState; + this.printToConsole("change [Coroutine] HookState: "..tostring(s)); + for k ,co in pairs(coroutinePool) do + if coroutine.status(co) == "dead" then + coroutinePool[k] = nil + else + this.changeCoroutineHookState(co, s) + end + end +end + +function this.changeCoroutineHookState(co, s) + if s == hookState.DISCONNECT_HOOK then + if openAttachMode == true then + debug.sethook(co, this.debug_hook, "r", 1000000); + else + debug.sethook(co, this.debug_hook, ""); + end + elseif s == hookState.LITE_HOOK then + debug.sethook(co , this.debug_hook, "r"); + elseif s == hookState.MID_HOOK then + debug.sethook(co , this.debug_hook, "rc"); + elseif s == hookState.ALL_HOOK then + debug.sethook(co , this.debug_hook, "lrc"); + end +end +-------------------------变量处理相关----------------------------- + +--清空REPL的env环境 +function this.clearEnv() + if this.getTableMemberNum(env) > 0 then + --清空env table + env = setmetatable({}, getmetatable(env)); + end +end + +--返回REPL的env环境 +function this.showEnv() + return env; +end + +-- 用户观察table的查找函数。用tableVarName作为key去查逐层级查找realVar是否匹配 +-- @tableVarName 是用户观察的变量名,已经按层级被解析成table。比如用户输出a.b.c,tableVarName是 a = { b = { c } } +-- @realVar 是待查询 table +-- @return 返回查到的table。没查到返回nil +function this.findTableVar( tableVarName, realVar) + if type(tableVarName) ~= "table" or type(realVar) ~= "table" then + return nil; + end + + local layer = 2; + local curVar = realVar; + local jumpOutFlag = false; + repeat + if tableVarName[layer] ~= nil then + --这里优先展示数字key,比如a{"1" = "aa", [1] = "bb"} 会展示[1]的值 + local tmpCurVar = nil; + xpcall(function() tmpCurVar = curVar[tonumber(tableVarName[layer])]; end , function() tmpCurVar = nil end ); + if tmpCurVar == nil then + xpcall(function() curVar = curVar[tostring(tableVarName[layer])]; end , function() curVar = nil end ); + else + curVar = tmpCurVar; + end + layer = layer + 1; + if curVar == nil then + return nil; + end + else + --找到 + jumpOutFlag = true; + end + until(jumpOutFlag == true) + return curVar; +end + +-- 根据传入信息生成返回的变量信息 +-- @variableName 变量名 +-- @variableIns 变量实例 +-- @return 包含变量信息的格式化table +function this.createWatchedVariableInfo(variableName, variableIns) + local var = {}; + var.name = variableName; + var.type = tostring(type(variableIns)); + xpcall(function() var.value = tostring(variableIns) end , function() var.value = tostring(type(variableIns)) .. " [value can't trans to string]" end ); + var.variablesReference = "0"; --这个地方必须用“0”, 以免variableRefTab[0]出错 + + if var.type == "table" or var.type == "function" or var.type == "userdata" then + var.variablesReference = variableRefIdx; + variableRefTab[variableRefIdx] = variableIns; + variableRefIdx = variableRefIdx + 1; + if var.type == "table" then + local memberNum = this.getTableMemberNum(variableIns); + var.value = memberNum .." Members ".. var.value; + end + elseif var.type == "string" then + var.value = '"' ..variableIns.. '"'; + end + return var; +end + +-- 设置 global 变量 +-- @varName 被修改的变量名 +-- @newValue 新的值 +function this.setGlobal(varName, newValue) + _G[varName] = newValue; + this.printToVSCode("[setVariable success] 已设置 _G.".. varName .. " = " .. tostring(newValue) ); + return true; +end + +-- 设置 upvalue 变量 +-- @varName 被修改的变量名 +-- @newValue 新的值 +-- @stackId 变量所在stack栈层 +-- @tableVarName 变量名拆分成的数组 +function this.setUpvalue(varName, newValue, stackId, tableVarName) + local ret = false; + local upTable = this.getUpValueVariable(currentCallStack[stackId - 1 ].func, true); + for i, realVar in ipairs(upTable) do + if realVar.name == varName then + if #tableVarName > 0 and type(realVar) == "table" then + --处理a.b.c的table类型 + local findRes = this.findTableVar(tableVarName, variableRefTab[realVar.variablesReference]); + if findRes ~= nil then + --命中 + local setVarRet = debug.setupvalue (currentCallStack[stackId - 1 ].func, i, newValue); + if setVarRet == varName then + this.printToConsole("[setVariable success1] 已设置 upvalue ".. varName .. " = " .. tostring(newValue) ); + ret = true; + else + this.printToConsole("[setVariable error1] 未能设置 upvalue ".. varName .. " = " .. tostring(newValue).." , 返回结果: ".. tostring(setVarRet)); + end + return ret; + end + else + --命中 + local setVarRet = debug.setupvalue (currentCallStack[stackId - 1 ].func, i, newValue); + if setVarRet == varName then + this.printToConsole("[setVariable success] 已设置 upvalue ".. varName .. " = " .. tostring(newValue) ); + ret = true; + else + this.printToConsole("[setVariable error] 未能设置 upvalue ".. varName .. " = " .. tostring(newValue).." , 返回结果: ".. tostring(setVarRet)); + end + return ret; + end + end + end + return ret; +end + +-- 设置local 变量 +-- @varName 被修改的变量名 +-- @newValue 新的值 +-- @tableVarName 变量名拆分成的数组 +function this.setLocal( varName, newValue, tableVarName, stackId) + local istackId = tonumber(stackId); + local offset = (istackId and istackId - 2) or 0; + local layerVarTab, ly = this.getVariable(nil , true, offset); + local ret = false; + for i, realVar in ipairs(layerVarTab) do + if realVar.name == varName then + if #tableVarName > 0 and type(realVar) == "table" then + --处理a.b.c的table类型 + local findRes = this.findTableVar(tableVarName, variableRefTab[realVar.variablesReference]); + if findRes ~= nil then + --命中 + local setVarRet = debug.setlocal(ly , layerVarTab[i].index, newValue); + if setVarRet == varName then + this.printToConsole("[setVariable success1] 已设置 local ".. varName .. " = " .. tostring(newValue) ); + ret = true; + else + this.printToConsole("[setVariable error1] 未能设置 local ".. varName .. " = " .. tostring(newValue).." , 返回结果: ".. tostring(setVarRet)); + end + return ret; + end + else + + local setVarRet = debug.setlocal(ly , layerVarTab[i].index, newValue); + + if setVarRet == varName then + this.printToConsole("[setVariable success] 已设置 local ".. varName .. " = " .. tostring(newValue) ); + ret = true; + else + this.printToConsole("[setVariable error] 未能设置 local ".. varName .. " = " .. tostring(newValue) .." , 返回结果: ".. tostring(setVarRet)); + end + return ret; + end + end + end + return ret; +end + + +-- 设置变量的值 +-- @varName 被修改的变量名 +-- @curStackId 调用栈层级(仅在固定栈层查找) +-- @newValue 新的值 +-- @limit 限制符, 10000表示仅在局部变量查找 ,20000 global, 30000 upvalue +function this.setVariableValue (varName, stackId, newValue , limit) + this.printToConsole("setVariableValue | varName:" .. tostring(varName) .. " stackId:".. tostring(stackId) .." newValue:" .. tostring(newValue) .." limit:"..tostring(limit) ) + if tostring(varName) == nil or tostring(varName) == "" then + --赋值错误 + this.printToConsole("[setVariable Error] 被赋值的变量名为空", 2 ); + this.printToVSCode("[setVariable Error] 被赋值的变量名为空", 2 ); + return false; + end + + --支持a.b.c形式。切割varName + local tableVarName = {}; + if varName:match('%.') then + tableVarName = this.stringSplit(varName , '%.'); + if type(tableVarName) ~= "table" or #tableVarName < 1 then + return false; + end + varName = tableVarName[1]; + end + + if limit == "local" then + local ret = this.setLocal( varName, newValue, tableVarName, stackId); + return ret; + elseif limit == "upvalue" then + local ret = this.setUpvalue(varName, newValue, stackId, tableVarName); + return ret + elseif limit == "global" then + local ret = this.setGlobal(varName, newValue); + return ret; + else + local ret = this.setLocal( varName, newValue, tableVarName, stackId) or this.setUpvalue(varName, newValue, stackId, tableVarName) or this.setGlobal(varName, newValue); + this.printToConsole("set Value res :".. tostring(ret)); + return ret; + end +end + +-- 按照local -> upvalue -> _G 顺序查找观察变量 +-- @varName 用户输入的变量名 +-- @stackId 调用栈层级(仅在固定栈层查找) +-- @isFormatVariable 是否把变量格式化为VSCode接收的形式 +-- @return 查到返回信息,查不到返回nil +function this.getWatchedVariable( varName , stackId , isFormatVariable ) + this.printToConsole("getWatchedVariable | varName:" .. tostring(varName) .. " stackId:".. tostring(stackId) .." isFormatVariable:" .. tostring(isFormatVariable) ) + if tostring(varName) == nil or tostring(varName) == "" then + return nil; + end + + if type(currentCallStack[stackId - 1]) ~= "table" or type(currentCallStack[stackId - 1].func) ~= "function" then + local str = "getWatchedVariable currentCallStack " .. stackId - 1 .. " Error\n" .. this.serializeTable(currentCallStack, "currentCallStack"); + this.printToVSCode(str, 2); + return nil; + end + + --orgname 记录原名字. 用来处理a.b.c的形式 + local orgname = varName; + --支持a.b.c形式。切割varName + local tableVarName = {}; + if varName:match('%.') then + tableVarName = this.stringSplit(varName , '%.'); + if type(tableVarName) ~= "table" or #tableVarName < 1 then + return nil; + end + varName = tableVarName[1]; + end + --用来返回,带有查到变量的table + local varTab = {}; + local ly = this.getSpecificFunctionStackLevel(currentCallStack[stackId - 1].func); + + local layerVarTab = this.getVariable(ly, isFormatVariable); + local upTable = this.getUpValueVariable(currentCallStack[stackId - 1 ].func, isFormatVariable); + local travelTab = {}; + table.insert(travelTab, layerVarTab); + table.insert(travelTab, upTable); + for _, layerVarTab in ipairs(travelTab) do + for i,realVar in ipairs(layerVarTab) do + if realVar.name == varName then + if #tableVarName > 0 and type(realVar) == "table" then + --处理a.b.c的table类型 + local findRes = this.findTableVar(tableVarName, variableRefTab[realVar.variablesReference]); + if findRes ~= nil then + --命中 + if isFormatVariable then + local var = this.createWatchedVariableInfo( orgname , findRes ); + table.insert(varTab, var); + return varTab; + else + return findRes.value; + end + end + else + --命中 + if isFormatVariable then + table.insert(varTab, realVar); + return varTab; + else + return realVar.value; + end + end + end + end + end + + --在全局变量_G中查找 + if _G[varName] ~= nil then + --命中 + if #tableVarName > 0 and type(_G[varName]) == "table" then + local findRes = this.findTableVar(tableVarName, _G[varName]); + if findRes ~= nil then + if isFormatVariable then + local var = this.createWatchedVariableInfo( orgname , findRes ); + table.insert(varTab, var); + return varTab; + else + return findRes; + end + end + else + if isFormatVariable then + local var = this.createWatchedVariableInfo( varName , _G[varName] ); + table.insert(varTab, var); + return varTab; + else + return _G[varName]; + end + end + end + this.printToConsole("getWatchedVariable not find variable"); + return nil; +end + +-- 查询引用变量 +-- @refStr 变量记录id(variableRefTab索引) +-- @return 格式化的变量信息table +function this.getVariableRef( refStr ) + local varRef = tonumber(refStr); + local varTab = {}; + + if tostring(type(variableRefTab[varRef])) == "table" then + for n,v in pairs(variableRefTab[varRef]) do + local var = {}; + if type(n) == "string" then + var.name = '"' .. tostring(n) .. '"'; + else + var.name = tostring(n); + end + var.type = tostring(type(v)); + xpcall(function() var.value = tostring(v) end , function() var.value = tostring(type(v)) .. " [value can't trans to string]" end ); + var.variablesReference = "0"; + if var.type == "table" or var.type == "function" or var.type == "userdata" then + var.variablesReference = variableRefIdx; + variableRefTab[variableRefIdx] = v; + variableRefIdx = variableRefIdx + 1; + if var.type == "table" then + local memberNum = this.getTableMemberNum(v); + var.value = memberNum .." Members ".. ( var.value or '' ); + end + elseif var.type == "string" then + var.value = '"' ..v.. '"'; + end + table.insert(varTab, var); + end + --获取一下mtTable + local mtTab = getmetatable(variableRefTab[varRef]); + if mtTab ~= nil and type(mtTab) == "table" then + local var = {}; + var.name = "_Metatable_"; + var.type = tostring(type(mtTab)); + xpcall(function() var.value = "元表 "..tostring(mtTab); end , function() var.value = "元表 [value can't trans to string]" end ); + var.variablesReference = variableRefIdx; + variableRefTab[variableRefIdx] = mtTab; + variableRefIdx = variableRefIdx + 1; + table.insert(varTab, var); + end + elseif tostring(type(variableRefTab[varRef])) == "function" then + --取upvalue + varTab = this.getUpValueVariable(variableRefTab[varRef], true); + elseif tostring(type(variableRefTab[varRef])) == "userdata" then + --取mt table + local udMtTable = getmetatable(variableRefTab[varRef]); + if udMtTable ~= nil and type(udMtTable) == "table" then + local var = {}; + var.name = "_Metatable_"; + var.type = tostring(type(udMtTable)); + xpcall(function() var.value = "元表 "..tostring(udMtTable); end , function() var.value = "元表 [value can't trans to string]" end ); + var.variablesReference = variableRefIdx; + variableRefTab[variableRefIdx] = udMtTable; + variableRefIdx = variableRefIdx + 1; + table.insert(varTab, var); + + if traversalUserData and udMtTable.__pairs ~= nil and type(udMtTable.__pairs) == "function" then + for n,v in pairs(variableRefTab[varRef]) do + local var = {}; + var.name = tostring(n); + var.type = tostring(type(v)); + xpcall(function() var.value = tostring(v) end , function() var.value = tostring(type(v)) .. " [value can't trans to string]" end ); + var.variablesReference = "0"; + if var.type == "table" or var.type == "function" or var.type == "userdata" then + var.variablesReference = variableRefIdx; + variableRefTab[variableRefIdx] = v; + variableRefIdx = variableRefIdx + 1; + if var.type == "table" then + local memberNum = this.getTableMemberNum(v); + var.value = memberNum .." Members ".. ( var.value or '' ); + end + elseif var.type == "string" then + var.value = '"' ..v.. '"'; + end + table.insert(varTab, var); + end + end + end + end + return varTab; +end + +-- 获取全局变量。方法和内存管理中获取全局变量的方法一样 +-- @return 格式化的信息, 若未找到返回空table +function this.getGlobalVariable( ... ) + --成本比较高,这里只能遍历_G中的所有变量,并去除系统变量,再返回给客户端 + local varTab = {}; + for k,v in pairs(_G) do + local var = {}; + var.name = tostring(k); + var.type = tostring(type(v)); + xpcall(function() var.value = tostring(v) end , function() var.value = tostring(type(v)) .." [value can't trans to string]" end ); + var.variablesReference = "0"; + if var.type == "table" or var.type == "function" or var.type == "userdata" then + var.variablesReference = variableRefIdx; + variableRefTab[variableRefIdx] = v; + variableRefIdx = variableRefIdx + 1; + if var.type == "table" then + local memberNum = this.getTableMemberNum(v); + var.value = memberNum .." Members ".. ( var.value or '' ); + end + elseif var.type == "string" then + var.value = '"' ..v.. '"'; + end + table.insert(varTab, var); + end + return varTab; +end + +-- 获取upValues +-- @isFormatVariable true返回[值] true返回[格式化的数据] +function this.getUpValueVariable( checkFunc , isFormatVariable) + local isGetValue = true; + if isFormatVariable == true then + isGetValue = false; + end + + --通过Debug获取当前函数的Func + checkFunc = checkFunc or lastRunFunction.func; + + local varTab = {}; + if checkFunc == nil then + return varTab; + end + local i = 1 + repeat + local n, v = debug.getupvalue(checkFunc, i) + if n then + + local var = {}; + var.name = n; + var.type = tostring(type(v)); + var.variablesReference = "0"; + + if isGetValue == false then + xpcall(function() var.value = tostring(v) end , function() var.value = tostring(type(v)) .. " [value can't trans to string]" end ); + if var.type == "table" or var.type == "function" or var.type == "userdata" then + var.variablesReference = variableRefIdx; + variableRefTab[variableRefIdx] = v; + variableRefIdx = variableRefIdx + 1; + if var.type == "table" then + local memberNum = this.getTableMemberNum(v); + var.value = memberNum .." Members ".. ( var.value or '' ); + end + elseif var.type == "string" then + var.value = '"' ..v.. '"'; + end + else + var.value = v; + end + + table.insert(varTab, var); + i = i + 1 + end + until not n + return varTab; +end + +-- 获取局部变量 checkLayer是要查询的层级,如果不设置则查询当前层级 +-- @isFormatVariable 是否取值,true:取值的tostring +function this.getVariable( checkLayer, isFormatVariable , offset) + local isGetValue = true; + if isFormatVariable == true then + isGetValue = false; + end + + local ly = 0; + if checkLayer ~= nil and type(checkLayer) == "number" then ly = checkLayer + 1; + else ly = this.getSpecificFunctionStackLevel(lastRunFunction.func); end + + if ly == 0 then + this.printToVSCode("[error]获取层次失败!", 2); + return; + end + local varTab = {}; + local stacklayer = ly; + local k = 1; + + if type(offset) == 'number' then + stacklayer = stacklayer + offset; + end + + repeat + local n, v = debug.getlocal(stacklayer, k) + if n == nil then + break; + end + + --(*temporary)是系统变量,过滤掉。这里假设(*temporary)仅出现在最后 + if "(*temporary)" ~= tostring(n) and "(temporary)" ~= tostring(n) then + local var = {}; + var.name = n; + var.type = tostring(type(v)); + var.variablesReference = "0"; + var.index = k; + + if isGetValue == false then + xpcall(function() var.value = tostring(v) end , function() var.value = tostring(type(v)) .. " [value can't trans to string]" end ); + if var.type == "table" or var.type == "function" or var.type == "userdata" then + var.variablesReference = variableRefIdx; + variableRefTab[variableRefIdx] = v; + variableRefIdx = variableRefIdx + 1; + if var.type == "table" then + local memberNum = this.getTableMemberNum(v); + var.value = memberNum .." Members ".. ( var.value or '' ); + end + elseif var.type == "string" then + var.value = '"' ..v.. '"'; + end + else + var.value = v; + end + + local sameIdx = this.checkSameNameVar(varTab, var); + if sameIdx ~= 0 then + varTab[sameIdx] = var; + else + table.insert(varTab, var); + end + end + k = k + 1 + until n == nil + return varTab, stacklayer - 1; +end + +--检查变量列表中的同名变量 +function this.checkSameNameVar(varTab, var) + for k , v in pairs(varTab) do + if v.name == var.name then + return k; + end + end + return 0; +end + +-- 执行表达式 +function this.processExp(msgTable) + local retString; + local var = {}; + var.isSuccess = "true"; + if msgTable ~= nil then + local expression = this.trim(tostring(msgTable.Expression)); + local isCmd = false; + if isCmd == false then + --兼容旧版p 命令 + if expression:find("p ", 1, true) == 1 then + expression = expression:sub(3); + end + + local expressionWithReturn = "return " .. expression; + local f = debugger_loadString(expressionWithReturn) or debugger_loadString(expression); + --判断结果,如果表达式错误会返回nil + if type(f) == "function" then + if _VERSION == "Lua 5.1" then + setfenv(f , env); + else + debug.setupvalue(f, 1, env); + end + --表达式要有错误处理 + xpcall(function() retString = f() end , function() retString = "输入错误指令。\n + 请检查指令是否正确\n + 指令仅能在[暂停在断点时]输入, 请不要在程序持续运行时输入"; var.isSuccess = false; end) + else + retString = "指令执行错误。\n + 请检查指令是否正确\n + 可以直接输入表达式,执行函数或变量名,并观察执行结果"; + var.isSuccess = false; + end + end + end + + var.name = "Exp"; + var.type = tostring(type(retString)); + xpcall(function() var.value = tostring(retString) end , function(e) var.value = tostring(type(retString)) .. " [value can't trans to string] ".. e; var.isSuccess = false; end); + var.variablesReference = "0"; + if var.type == "table" or var.type == "function" or var.type == "userdata" then + variableRefTab[variableRefIdx] = retString; + var.variablesReference = variableRefIdx; + variableRefIdx = variableRefIdx + 1; + if var.type == "table" then + local memberNum = this.getTableMemberNum(retString); + var.value = memberNum .." Members ".. var.value; + end + elseif var.type == "string" then + var.value = '"' ..retString.. '"'; + end + --string执行完毕后清空env环境 + this.clearEnv(); + local retTab = {} + table.insert(retTab ,var); + return retTab; +end + +--执行变量观察表达式 +function this.processWatchedExp(msgTable) + local retString; + local expression = "return ".. tostring(msgTable.varName) + this.printToConsole("processWatchedExp | expression: " .. expression); + local f = debugger_loadString(expression); + local var = {}; + var.isSuccess = "true"; + --判断结果,如果表达式错误会返回nil + if type(f) == "function" then + --表达式正确 + if _VERSION == "Lua 5.1" then + setfenv(f , env); + else + debug.setupvalue(f, 1, env); + end + xpcall(function() retString = f() end , function() retString = "输入了错误的变量信息"; var.isSuccess = "false"; end) + else + retString = "未能找到变量的值"; + var.isSuccess = "false"; + end + + var.name = msgTable.varName; + var.type = tostring(type(retString)); + xpcall(function() var.value = tostring(retString) end , function() var.value = tostring(type(retString)) .. " [value can't trans to string]"; var.isSuccess = "false"; end ); + var.variablesReference = "0"; + + if var.type == "table" or var.type == "function" or var.type == "userdata" then + variableRefTab[variableRefIdx] = retString; + var.variablesReference = variableRefIdx; + variableRefIdx = variableRefIdx + 1; + if var.type == "table" then + local memberNum = this.getTableMemberNum(retString); + var.value = memberNum .." Members ".. var.value; + end + elseif var.type == "string" then + var.value = '"' ..retString.. '"'; + end + + local retTab = {} + table.insert(retTab ,var); + return retTab; +end + + +function tools.getFileSource() + local info = debug.getinfo(1, "S") + for k,v in pairs(info) do + if k == "source" then + return v; + end + end +end + +--序列化并打印table +function tools.printTable(t, name ,indent) + local str = (tools.show(t, name, indent)); + print(str); +end + +--序列化并返回table +function tools.serializeTable(t, name, indent) + local str = (tools.show(t, name, indent)) + return str +end + +--[[ +Author: Julio Manuel Fernandez-Diaz +Date: January 12, 2007 +Modified slightly by RiciLake to avoid the unnecessary table traversal in tablecount() +Formats tables with cycles recursively to any depth. +The output is returned as a string. +References to other tables are shown as values. +Self references are indicated. +The string returned is "Lua code", which can be procesed +(in the case in which indent is composed by spaces or "--"). +Userdata and function keys and values are shown as strings, +which logically are exactly not equivalent to the original code. +This routine can serve for pretty formating tables with +proper indentations, apart from printing them: +print(table.show(t, "t")) -- a typical use +Heavily based on "Saving tables with cycles", PIL2, p. 113. +Arguments: +t is the table. +name is the name of the table (optional) +indent is a first indentation (optional). +--]] +function tools.show(t, name, indent) + local cart -- a container + local autoref -- for self references + + local function isemptytable(t) return next(t) == nil end + + local function basicSerialize (o) + local so = tostring(o) + if type(o) == "function" then + local info = debug.getinfo(o, "S") + -- info.name is nil because o is not a calling level + if info.what == "C" then + return string.format("%q", so .. ", C function") + else + -- the information is defined through lines + return string.format("%q", so .. ", defined in (" .. + info.linedefined .. "-" .. info.lastlinedefined .. + ")" .. info.source) + end + elseif type(o) == "number" or type(o) == "boolean" then + return so + else + return string.format("%q", so) + end + end + + local function addtocart (value, name, indent, saved, field) + indent = indent or "" + saved = saved or {} + field = field or name + + cart = cart .. indent .. field + + if type(value) ~= "table" then + cart = cart .. " = " .. basicSerialize(value) .. ";\n" + else + if saved[value] then + cart = cart .. " = {}; -- " .. saved[value] + .. " (self reference)\n" + autoref = autoref .. name .. " = " .. saved[value] .. ";\n" + else + saved[value] = name + --if tablecount(value) == 0 then + if isemptytable(value) then + cart = cart .. " = {};\n" + else + cart = cart .. " = {\n" + for k, v in pairs(value) do + k = basicSerialize(k) + local fname = string.format("%s[%s]", name, k) + field = string.format("[%s]", k) + -- three spaces between levels + addtocart(v, fname, indent .. " ", saved, field) + end + cart = cart .. indent .. "};\n" + end + end + end + end + + name = name or "PRINT_Table" + if type(t) ~= "table" then + return name .. " = " .. basicSerialize(t) + end + cart, autoref = "", "" + addtocart(t, name, indent) + return cart .. autoref +end + +----------------------------------------------------------------------------- +-- JSON4Lua: JSON encoding / decoding support for the Lua language. +-- json Module. +-- Author: Craig Mason-Jones +-- Homepage: http://github.com/craigmj/json4lua/ +-- Version: 1.0.0 +-- This module is released under the MIT License (MIT). +-- Please see LICENCE.txt for details. +-- +-- USAGE: +-- This module exposes two functions: +-- json.encode(o) +-- Returns the table / string / boolean / number / nil / json.null value as a JSON-encoded string. +-- json.decode(json_string) +-- Returns a Lua object populated with the data encoded in the JSON string json_string. +-- +-- REQUIREMENTS: +-- compat-5.1 if using Lua 5.0 +-- +-- CHANGELOG +-- 0.9.20 Introduction of local Lua functions for private functions (removed _ function prefix). +-- Fixed Lua 5.1 compatibility issues. +-- Introduced json.null to have null values in associative arrays. +-- json.encode() performance improvement (more than 50%) through table.concat rather than .. +-- Introduced decode ability to ignore /**/ comments in the JSON string. +-- 0.9.10 Fix to array encoding / decoding to correctly manage nil/null values in arrays. +----------------------------------------------------------------------------- + +function tools.createJson() + ----------------------------------------------------------------------------- + -- Imports and dependencies + ----------------------------------------------------------------------------- + local math = require('math') + local string = require("string") + local table = require("table") + + ----------------------------------------------------------------------------- + -- Module declaration + ----------------------------------------------------------------------------- + local json = {} -- Public namespace + local json_private = {} -- Private namespace + + -- Public constants + json.EMPTY_ARRAY={} + json.EMPTY_OBJECT={} + + -- Public functions + + -- Private functions + local decode_scanArray + local decode_scanComment + local decode_scanConstant + local decode_scanNumber + local decode_scanObject + local decode_scanString + local decode_scanWhitespace + local encodeString + local isArray + local isEncodable + + ----------------------------------------------------------------------------- + -- PUBLIC FUNCTIONS + ----------------------------------------------------------------------------- + --- Encodes an arbitrary Lua object / variable. + -- @param v The Lua object / variable to be JSON encoded. + -- @return String containing the JSON encoding in internal Lua string format (i.e. not unicode) + function json.encode (v) + -- Handle nil values + if v==nil then + return "null" + end + + local vtype = type(v) + + -- Handle strings + if vtype=='string' then + return '"' .. json_private.encodeString(v) .. '"' -- Need to handle encoding in string + end + + -- Handle booleans + if vtype=='number' or vtype=='boolean' then + return tostring(v) + end + + -- Handle tables + if vtype=='table' then + local rval = {} + -- Consider arrays separately + local bArray, maxCount = isArray(v) + if bArray then + for i = 1,maxCount do + table.insert(rval, json.encode(v[i])) + end + else -- An object, not an array + for i,j in pairs(v) do + if isEncodable(i) and isEncodable(j) then + table.insert(rval, '"' .. json_private.encodeString(i) .. '":' .. json.encode(j)) + end + end + end + if bArray then + return '[' .. table.concat(rval,',') ..']' + else + return '{' .. table.concat(rval,',') .. '}' + end + end + + -- Handle null values + if vtype=='function' and v==json.null then + return 'null' + end + + assert(false,'encode attempt to encode unsupported type ' .. vtype .. ':' .. tostring(v)) + end + + + --- Decodes a JSON string and returns the decoded value as a Lua data structure / value. + -- @param s The string to scan. + -- @param [startPos] Optional starting position where the JSON string is located. Defaults to 1. + -- @param Lua object, number The object that was scanned, as a Lua table / string / number / boolean or nil, + -- and the position of the first character after + -- the scanned JSON object. + function json.decode(s, startPos) + startPos = startPos and startPos or 1 + startPos = decode_scanWhitespace(s,startPos) + assert(startPos<=string.len(s), 'Unterminated JSON encoded object found at position in [' .. s .. ']') + local curChar = string.sub(s,startPos,startPos) + -- Object + if curChar=='{' then + return decode_scanObject(s,startPos) + end + -- Array + if curChar=='[' then + return decode_scanArray(s,startPos) + end + -- Number + if string.find("+-0123456789.e", curChar, 1, true) then + return decode_scanNumber(s,startPos) + end + -- String + if curChar==[["]] or curChar==[[']] then + return decode_scanString(s,startPos) + end + if string.sub(s,startPos,startPos+1)=='/*' then + return json.decode(s, decode_scanComment(s,startPos)) + end + -- Otherwise, it must be a constant + return decode_scanConstant(s,startPos) + end + + --- The null function allows one to specify a null value in an associative array (which is otherwise + -- discarded if you set the value with 'nil' in Lua. Simply set t = { first=json.null } + function json.null() + return json.null -- so json.null() will also return null ;-) + end + ----------------------------------------------------------------------------- + -- Internal, PRIVATE functions. + -- Following a Python-like convention, I have prefixed all these 'PRIVATE' + -- functions with an underscore. + ----------------------------------------------------------------------------- + + --- Scans an array from JSON into a Lua object + -- startPos begins at the start of the array. + -- Returns the array and the next starting position + -- @param s The string being scanned. + -- @param startPos The starting position for the scan. + -- @return table, int The scanned array as a table, and the position of the next character to scan. + function decode_scanArray(s,startPos) + local array = {} -- The return value + local stringLen = string.len(s) + assert(string.sub(s,startPos,startPos)=='[','decode_scanArray called but array does not start at position ' .. startPos .. ' in string:\n'..s ) + startPos = startPos + 1 + -- Infinite loop for array elements + local index = 1 + repeat + startPos = decode_scanWhitespace(s,startPos) + assert(startPos<=stringLen,'JSON String ended unexpectedly scanning array.') + local curChar = string.sub(s,startPos,startPos) + if (curChar==']') then + return array, startPos+1 + end + if (curChar==',') then + startPos = decode_scanWhitespace(s,startPos+1) + end + assert(startPos<=stringLen, 'JSON String ended unexpectedly scanning array.') + local object + object, startPos = json.decode(s,startPos) + array[index] = object + index = index + 1 + until false + end + + --- Scans a comment and discards the comment. + -- Returns the position of the next character following the comment. + -- @param string s The JSON string to scan. + -- @param int startPos The starting position of the comment + function decode_scanComment(s, startPos) + assert( string.sub(s,startPos,startPos+1)=='/*', "decode_scanComment called but comment does not start at position " .. startPos) + local endPos = string.find(s,'*/',startPos+2) + assert(endPos~=nil, "Unterminated comment in string at " .. startPos) + return endPos+2 + end + + --- Scans for given constants: true, false or null + -- Returns the appropriate Lua type, and the position of the next character to read. + -- @param s The string being scanned. + -- @param startPos The position in the string at which to start scanning. + -- @return object, int The object (true, false or nil) and the position at which the next character should be + -- scanned. + function decode_scanConstant(s, startPos) + local consts = { ["true"] = true, ["false"] = false, ["null"] = nil } + local constNames = {"true","false","null"} + + for i,k in pairs(constNames) do + if string.sub(s,startPos, startPos + string.len(k) -1 )==k then + return consts[k], startPos + string.len(k) + end + end + assert(nil, 'Failed to scan constant from string ' .. s .. ' at starting position ' .. startPos) + end + + --- Scans a number from the JSON encoded string. + -- (in fact, also is able to scan numeric +- eqns, which is not + -- in the JSON spec.) + -- Returns the number, and the position of the next character + -- after the number. + -- @param s The string being scanned. + -- @param startPos The position at which to start scanning. + -- @return number, int The extracted number and the position of the next character to scan. + function decode_scanNumber(s,startPos) + local endPos = startPos+1 + local stringLen = string.len(s) + local acceptableChars = "+-0123456789.e" + while (string.find(acceptableChars, string.sub(s,endPos,endPos), 1, true) + and endPos<=stringLen + ) do + endPos = endPos + 1 + end + -- local stringValue = 'return ' .. string.sub(s, startPos, endPos - 1) + -- local stringEval = loadstring(stringValue) + -- assert(stringEval, 'Failed to scan number [ ' .. stringValue .. '] in JSON string at position ' .. startPos .. ' : ' .. endPos) + local numberValue = string.sub(s, startPos, endPos - 1) + return numberValue, endPos + end + + --- Scans a JSON object into a Lua object. + -- startPos begins at the start of the object. + -- Returns the object and the next starting position. + -- @param s The string being scanned. + -- @param startPos The starting position of the scan. + -- @return table, int The scanned object as a table and the position of the next character to scan. + function decode_scanObject(s,startPos) + local object = {} + local stringLen = string.len(s) + local key, value + assert(string.sub(s,startPos,startPos)=='{','decode_scanObject called but object does not start at position ' .. startPos .. ' in string:\n' .. s) + startPos = startPos + 1 + repeat + startPos = decode_scanWhitespace(s,startPos) + assert(startPos<=stringLen, 'JSON string ended unexpectedly while scanning object.') + local curChar = string.sub(s,startPos,startPos) + if (curChar=='}') then + return object,startPos+1 + end + if (curChar==',') then + startPos = decode_scanWhitespace(s,startPos+1) + end + assert(startPos<=stringLen, 'JSON string ended unexpectedly scanning object.') + -- Scan the key + key, startPos = json.decode(s,startPos) + assert(startPos<=stringLen, 'JSON string ended unexpectedly searching for value of key ' .. key) + startPos = decode_scanWhitespace(s,startPos) + assert(startPos<=stringLen, 'JSON string ended unexpectedly searching for value of key ' .. key) + assert(string.sub(s,startPos,startPos)==':','JSON object key-value assignment mal-formed at ' .. startPos) + startPos = decode_scanWhitespace(s,startPos+1) + assert(startPos<=stringLen, 'JSON string ended unexpectedly searching for value of key ' .. key) + value, startPos = json.decode(s,startPos) + object[key]=value + until false -- infinite loop while key-value pairs are found + end + + -- START SoniEx2 + -- Initialize some things used by decode_scanString + -- You know, for efficiency + local escapeSequences = { + ["\\t"] = "\t", + ["\\f"] = "\f", + ["\\r"] = "\r", + ["\\n"] = "\n", + ["\\b"] = "\b" + } + setmetatable(escapeSequences, {__index = function(t,k) + -- skip "\" aka strip escape + return string.sub(k,2) + end}) + -- END SoniEx2 + + --- Scans a JSON string from the opening inverted comma or single quote to the + -- end of the string. + -- Returns the string extracted as a Lua string, + -- and the position of the next non-string character + -- (after the closing inverted comma or single quote). + -- @param s The string being scanned. + -- @param startPos The starting position of the scan. + -- @return string, int The extracted string as a Lua string, and the next character to parse. + function decode_scanString(s,startPos) + assert(startPos, 'decode_scanString(..) called without start position') + local startChar = string.sub(s,startPos,startPos) + -- START SoniEx2 + -- PS: I don't think single quotes are valid JSON + assert(startChar == [["]] or startChar == [[']],'decode_scanString called for a non-string') + --assert(startPos, "String decoding failed: missing closing " .. startChar .. " for string at position " .. oldStart) + local t = {} + local i,j = startPos,startPos + while string.find(s, startChar, j+1) ~= j+1 do + local oldj = j + i,j = string.find(s, "\\.", j+1) + local x,y = string.find(s, startChar, oldj+1) + if not i or x < i then + i,j = x,y-1 + end + table.insert(t, string.sub(s, oldj+1, i-1)) + if string.sub(s, i, j) == "\\u" then + local a = string.sub(s,j+1,j+4) + j = j + 4 + local n = tonumber(a, 16) + assert(n, "String decoding failed: bad Unicode escape " .. a .. " at position " .. i .. " : " .. j) + -- math.floor(x/2^y) == lazy right shift + -- a % 2^b == bitwise_and(a, (2^b)-1) + -- 64 = 2^6 + -- 4096 = 2^12 (or 2^6 * 2^6) + local x + if n < 0x80 then + x = string.char(n % 0x80) + elseif n < 0x800 then + -- [110x xxxx] [10xx xxxx] + x = string.char(0xC0 + (math.floor(n/64) % 0x20), 0x80 + (n % 0x40)) + else + -- [1110 xxxx] [10xx xxxx] [10xx xxxx] + x = string.char(0xE0 + (math.floor(n/4096) % 0x10), 0x80 + (math.floor(n/64) % 0x40), 0x80 + (n % 0x40)) + end + table.insert(t, x) + else + table.insert(t, escapeSequences[string.sub(s, i, j)]) + end + end + table.insert(t,string.sub(j, j+1)) + assert(string.find(s, startChar, j+1), "String decoding failed: missing closing " .. startChar .. " at position " .. j .. "(for string at position " .. startPos .. ")") + return table.concat(t,""), j+2 + -- END SoniEx2 + end + + --- Scans a JSON string skipping all whitespace from the current start position. + -- Returns the position of the first non-whitespace character, or nil if the whole end of string is reached. + -- @param s The string being scanned + -- @param startPos The starting position where we should begin removing whitespace. + -- @return int The first position where non-whitespace was encountered, or string.len(s)+1 if the end of string + -- was reached. + function decode_scanWhitespace(s,startPos) + local whitespace=" \n\r\t" + local stringLen = string.len(s) + while ( string.find(whitespace, string.sub(s,startPos,startPos), 1, true) and startPos <= stringLen) do + startPos = startPos + 1 + end + return startPos + end + + --- Encodes a string to be JSON-compatible. + -- This just involves back-quoting inverted commas, back-quotes and newlines, I think ;-) + -- @param s The string to return as a JSON encoded (i.e. backquoted string) + -- @return The string appropriately escaped. + + local escapeList = { + ['"'] = '\\"', + ['\\'] = '\\\\', + ['/'] = '\\/', + ['\b'] = '\\b', + ['\f'] = '\\f', + ['\n'] = '\\n', + ['\r'] = '\\r', + ['\t'] = '\\t' + } + + function json_private.encodeString(s) + local s = tostring(s) + return s:gsub(".", function(c) return escapeList[c] end) -- SoniEx2: 5.0 compat + end + + -- Determines whether the given Lua type is an array or a table / dictionary. + -- We consider any table an array if it has indexes 1..n for its n items, and no + -- other data in the table. + -- I think this method is currently a little 'flaky', but can't think of a good way around it yet... + -- @param t The table to evaluate as an array + -- @return boolean, number True if the table can be represented as an array, false otherwise. If true, + -- the second returned value is the maximum + -- number of indexed elements in the array. + function isArray(t) + -- Next we count all the elements, ensuring that any non-indexed elements are not-encodable + -- (with the possible exception of 'n') + if (t == json.EMPTY_ARRAY) then return true, 0 end + if (t == json.EMPTY_OBJECT) then return false end + + local maxIndex = 0 + for k,v in pairs(t) do + if (type(k)=='number' and math.floor(k)==k and 1<=k) then -- k,v is an indexed pair + if (not isEncodable(v)) then return false end -- All array elements must be encodable + maxIndex = math.max(maxIndex,k) + else + if (k=='n') then + if v ~= (t.n or #t) then return false end -- False if n does not hold the number of elements + else -- Else of (k=='n') + if isEncodable(v) then return false end + end -- End of (k~='n') + end -- End of k,v not an indexed pair + end -- End of loop across all pairs + return true, maxIndex + end + + --- Determines whether the given Lua object / table / variable can be JSON encoded. The only + -- types that are JSON encodable are: string, boolean, number, nil, table and json.null. + -- In this implementation, all other types are ignored. + -- @param o The object to examine. + -- @return boolean True if the object should be JSON encoded, false if it should be ignored. + function isEncodable(o) + local t = type(o) + return (t=='string' or t=='boolean' or t=='number' or t=='nil' or t=='table') or + (t=='function' and o==json.null) + end + return json +end + +-- Sourced from http://lua-users.org/wiki/BaseSixtyFour + +-- Lua 5.1+ base64 v3.0 (c) 2009 by Alex Kloss +-- licensed under the terms of the LGPL2 + +-- character table string +local base64CharTable='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' + +-- encoding +function tools.base64encode(data) + return ((data:gsub('.', function(x) + local r,b='',x:byte() + for i=8,1,-1 do r=r..(b%2^i-b%2^(i-1)>0 and '1' or '0') end + return r; + end)..'0000'):gsub('%d%d%d?%d?%d?%d?', function(x) + if (#x < 6) then return '' end + local c=0 + for i=1,6 do c=c+(x:sub(i,i)=='1' and 2^(6-i) or 0) end + return base64CharTable:sub(c+1,c+1) + end)..({ '', '==', '=' })[#data%3+1]) +end + +-- decoding +function tools.base64decode(data) + data = string.gsub(data, '[^'..base64CharTable..'=]', '') + return (data:gsub('.', function(x) + if (x == '=') then return '' end + local r,f='',(base64CharTable:find(x)-1) + for i=6,1,-1 do r=r..(f%2^i-f%2^(i-1)>0 and '1' or '0') end + return r; + end):gsub('%d%d%d?%d?%d?%d?%d?%d?', function(x) + if (#x ~= 8) then return '' end + local c=0 + for i=1,8 do c=c+(x:sub(i,i)=='1' and 2^(8-i) or 0) end + return string.char(c) + end)) +end + +-- tools变量 +json = tools.createJson(); --json处理 +this.printToConsole("load LuaPanda success", 1); +this.replaceCoroutineFuncs() +return this; \ No newline at end of file diff --git a/gamedata/scripts/dynamic_callbacks.lua b/gamedata/scripts/dynamic_callbacks.lua new file mode 100644 index 000000000..71f720c8d --- /dev/null +++ b/gamedata/scripts/dynamic_callbacks.lua @@ -0,0 +1,37 @@ +local intercepts = +{ + save = {}, + load = {}, + update = {}, + + save_state = {}, + load_state = {} +} + +function RegisterScriptCallback(name, func_or_userdata) + if (func_or_userdata == nil) then + callstack() + end + + if (intercepts[name]) then + intercepts[name][func_or_userdata] = true + end +end + +function UnregisterScriptCallback(name, func_or_userdata) + if (intercepts[name]) then + intercepts[name][func_or_userdata] = nil + end +end + +function SendScriptCallback(name,...) + if (intercepts[name]) then + for func_or_userdata,v in pairs(intercepts[name]) do + if (type(func_or_userdata) == "function") then + func_or_userdata(...) + elseif (func_or_userdata[name]) then + func_or_userdata[name](func_or_userdata,...) + end + end + end +end \ No newline at end of file diff --git a/gamedata/scripts/global.lua b/gamedata/scripts/global.lua new file mode 100644 index 000000000..dae66ae31 --- /dev/null +++ b/gamedata/scripts/global.lua @@ -0,0 +1,41 @@ +--// General +jit.opt.start(2) + +string.gfind = string.gmatch +math.mod = math.fmod + +--// LuaPandas +DebuggerMode = false + +function debug_jit_off() + if DebuggerMode then + if jit then jit.off() end + end +end + +function debug_jit_on() + if DebuggerMode then + if jit then jit.on() end + end +end + +function debugger_attach() + if DebuggerMode then + log('LuaPanda: Disabling jit...') + debug_jit_off() + log('LuaPanda: Reconnecting') + LuaPanda.reConnect() + log('LuaPanda: reconnected') + debug_jit_on() + log('LuaPanda: Started') + else + log('LuaPanda: Disabling jit...') + debug_jit_off() + log('LuaPanda: Connecting') + LuaPanda.start("127.0.0.1", 8818) + log('LuaPanda: Connected') + DebuggerMode = true + debug_jit_on() + log('LuaPanda: Started') + end +end \ No newline at end of file diff --git a/gamedata/scripts/socket.lua b/gamedata/scripts/socket.lua new file mode 100644 index 000000000..65cb70936 --- /dev/null +++ b/gamedata/scripts/socket.lua @@ -0,0 +1,149 @@ +----------------------------------------------------------------------------- +-- LuaSocket helper module +-- Author: Diego Nehab +----------------------------------------------------------------------------- + +----------------------------------------------------------------------------- +-- Declare module and import dependencies +----------------------------------------------------------------------------- +local base = _G +local string = require("string") +local math = require("math") +local socket = require("socket.core") + +local _M = socket + +----------------------------------------------------------------------------- +-- Exported auxiliar functions +----------------------------------------------------------------------------- +function _M.connect4(address, port, laddress, lport) + return socket.connect(address, port, laddress, lport, "inet") +end + +function _M.connect6(address, port, laddress, lport) + return socket.connect(address, port, laddress, lport, "inet6") +end + +function _M.bind(host, port, backlog) + if host == "*" then host = "0.0.0.0" end + local addrinfo, err = socket.dns.getaddrinfo(host); + if not addrinfo then return nil, err end + local sock, res + err = "no info on address" + for i, alt in base.ipairs(addrinfo) do + if alt.family == "inet" then + sock, err = socket.tcp4() + else + sock, err = socket.tcp6() + end + if not sock then return nil, err end + sock:setoption("reuseaddr", true) + res, err = sock:bind(alt.addr, port) + if not res then + sock:close() + else + res, err = sock:listen(backlog) + if not res then + sock:close() + else + return sock + end + end + end + return nil, err +end + +_M.try = _M.newtry() + +function _M.choose(table) + return function(name, opt1, opt2) + if base.type(name) ~= "string" then + name, opt1, opt2 = "default", name, opt1 + end + local f = table[name or "nil"] + if not f then base.error("unknown key (".. base.tostring(name) ..")", 3) + else return f(opt1, opt2) end + end +end + +----------------------------------------------------------------------------- +-- Socket sources and sinks, conforming to LTN12 +----------------------------------------------------------------------------- +-- create namespaces inside LuaSocket namespace +local sourcet, sinkt = {}, {} +_M.sourcet = sourcet +_M.sinkt = sinkt + +_M.BLOCKSIZE = 2048 + +sinkt["close-when-done"] = function(sock) + return base.setmetatable({ + getfd = function() return sock:getfd() end, + dirty = function() return sock:dirty() end + }, { + __call = function(self, chunk, err) + if not chunk then + sock:close() + return 1 + else return sock:send(chunk) end + end + }) +end + +sinkt["keep-open"] = function(sock) + return base.setmetatable({ + getfd = function() return sock:getfd() end, + dirty = function() return sock:dirty() end + }, { + __call = function(self, chunk, err) + if chunk then return sock:send(chunk) + else return 1 end + end + }) +end + +sinkt["default"] = sinkt["keep-open"] + +_M.sink = _M.choose(sinkt) + +sourcet["by-length"] = function(sock, length) + return base.setmetatable({ + getfd = function() return sock:getfd() end, + dirty = function() return sock:dirty() end + }, { + __call = function() + if length <= 0 then return nil end + local size = math.min(socket.BLOCKSIZE, length) + local chunk, err = sock:receive(size) + if err then return nil, err end + length = length - string.len(chunk) + return chunk + end + }) +end + +sourcet["until-closed"] = function(sock) + local done + return base.setmetatable({ + getfd = function() return sock:getfd() end, + dirty = function() return sock:dirty() end + }, { + __call = function() + if done then return nil end + local chunk, err, partial = sock:receive(socket.BLOCKSIZE) + if not err then return chunk + elseif err == "closed" then + sock:close() + done = 1 + return partial + else return nil, err end + end + }) +end + + +sourcet["default"] = sourcet["until-closed"] + +_M.source = _M.choose(sourcet) + +return _M \ No newline at end of file diff --git a/src/xrEngine/EngineAPI.h b/src/xrEngine/EngineAPI.h index 1f699f656..60f024d5d 100644 --- a/src/xrEngine/EngineAPI.h +++ b/src/xrEngine/EngineAPI.h @@ -4,6 +4,8 @@ // Support for extension DLLs //**************************************************************************** +#include + #if !defined(AFX_ENGINEAPI_H__CF21372B_C8B8_4891_82FC_D872C84E1DD4__INCLUDED_) #define AFX_ENGINEAPI_H__CF21372B_C8B8_4891_82FC_D872C84E1DD4__INCLUDED_ #pragma once @@ -35,6 +37,12 @@ typedef void __cdecl VTPause(void); typedef void __cdecl VTResume(void); }; +enum class EditorUI : uint8_t +{ + LuaDebug, + Count +}; + class ENGINE_API CEngineAPI { private: @@ -48,6 +56,9 @@ class ENGINE_API CEngineAPI BOOL tune_enabled; VTPause* tune_pause; VTResume* tune_resume; + + std::array(EditorUI::Count)> EditorStates = { }; + void Initialize(); #ifndef DEDICATED_SERVER diff --git a/src/xrEngine/imgui_base.cpp b/src/xrEngine/imgui_base.cpp index 1b846062f..7e3d831c5 100644 --- a/src/xrEngine/imgui_base.cpp +++ b/src/xrEngine/imgui_base.cpp @@ -4,6 +4,7 @@ #include #include "device.h" #include "IGame_Persistent.h" +#include "imgui_tools.h" static const char* GetCustomCompressedFontDataTTF(int* out_size); static const char* GetIconCompressedFontDataTTF(int* out_size); @@ -212,6 +213,12 @@ namespace xr_imgui g_pGamePersistent->ImGui_OnRender("MenuBar"); + if (ImGui::BeginMenu("Tools")) + { + InitImguiTools(); + ImGui::EndMenu(); + } + if (ImGui::BeginMenu("About")) { if (ImGui::MenuItem("Demo", nullptr, imgui_demo)) diff --git a/src/xrEngine/imgui_tools.cpp b/src/xrEngine/imgui_tools.cpp new file mode 100644 index 000000000..0766ecfc1 --- /dev/null +++ b/src/xrEngine/imgui_tools.cpp @@ -0,0 +1,16 @@ +#include "stdafx.h" +#include +#include "../xrServerEntities/script_engine_debugger.h" + +void InitImguiTools() +{ + auto& States = Engine.External.EditorStates; + bool* luaDebug = &States[static_cast(EditorUI::LuaDebug)]; + if (ImGui::MenuItem("Lua: Attach to VSCode (Doesn't work)", nullptr, luaDebug)) + { + if (*luaDebug) + { + //AttachDebugger(); //Getting crash in ljtab.c after executing this function: Unhandled exception thrown: read access violation. + } + } +} \ No newline at end of file diff --git a/src/xrEngine/imgui_tools.h b/src/xrEngine/imgui_tools.h new file mode 100644 index 000000000..35cc02d43 --- /dev/null +++ b/src/xrEngine/imgui_tools.h @@ -0,0 +1,3 @@ +#pragma once + +void InitImguiTools(); \ No newline at end of file diff --git a/src/xrEngine/vs2022/xrEngine.vcxproj b/src/xrEngine/vs2022/xrEngine.vcxproj index 733f3c10c..95484d636 100644 --- a/src/xrEngine/vs2022/xrEngine.vcxproj +++ b/src/xrEngine/vs2022/xrEngine.vcxproj @@ -723,6 +723,7 @@ + @@ -781,6 +782,7 @@ + diff --git a/src/xrEngine/vs2022/xrEngine.vcxproj.filters b/src/xrEngine/vs2022/xrEngine.vcxproj.filters index 16a90fe56..f0730625d 100644 --- a/src/xrEngine/vs2022/xrEngine.vcxproj.filters +++ b/src/xrEngine/vs2022/xrEngine.vcxproj.filters @@ -489,6 +489,7 @@ Interfaces\ImGui + @@ -788,6 +789,10 @@ Interfaces\Discord + + + + diff --git a/src/xrGame/vs2022/xrGame.vcxproj b/src/xrGame/vs2022/xrGame.vcxproj index 892955968..b93f710dc 100644 --- a/src/xrGame/vs2022/xrGame.vcxproj +++ b/src/xrGame/vs2022/xrGame.vcxproj @@ -339,6 +339,7 @@ + @@ -1967,6 +1968,7 @@ pch_script.h $(IntDir)$(ProjectName)_script.pch + pch_script.h $(IntDir)$(ProjectName)_script.pch diff --git a/src/xrGame/vs2022/xrGame.vcxproj.filters b/src/xrGame/vs2022/xrGame.vcxproj.filters index 4d3352f16..3d1fb96c6 100644 --- a/src/xrGame/vs2022/xrGame.vcxproj.filters +++ b/src/xrGame/vs2022/xrGame.vcxproj.filters @@ -7404,6 +7404,9 @@ UI\Common\ImGui + + AI\AScript\ScriptEngine + @@ -11102,6 +11105,9 @@ UI\Common\ImGui + + AI\AScript\ScriptEngine + diff --git a/src/xrServerEntities/script_engine.cpp b/src/xrServerEntities/script_engine.cpp index a576b14dd..ceb849fb8 100644 --- a/src/xrServerEntities/script_engine.cpp +++ b/src/xrServerEntities/script_engine.cpp @@ -16,6 +16,7 @@ #include #include #include +#include "script_engine_debugger.h" #ifdef USE_DEBUGGER # ifndef USE_LUA_STUDIO @@ -316,28 +317,14 @@ void CScriptEngine::lua_hook_call (lua_State *L, lua_Debug *dbg) int auto_load(lua_State* L) { - int StackSize = lua_gettop(L); - bool IsTable = lua_istable(L, 1); - - if ((StackSize < 2) || !IsTable || !lua_isstring(L, 2)) { - lua_pushnil(L); - return (1); - } - - string_path S = {}; - string128 FullName = {}; - FS.update_path(S, "$game_scripts$", xr_strconcat(FullName, lua_tostring(L, 2), ".script")); - - if (FS.exist(S)) - { - ai().script_engine().process_file_if_exists(lua_tostring(L, 2), false); - lua_rawget(L, 1); - } - else + if ((lua_gettop(L) < 2) || !lua_istable(L, 1) || !lua_isstring(L, 2)) { lua_pushnil(L); + return (1); } + ai().script_engine().process_file_if_exists(lua_tostring(L, 2), false); + lua_rawget(L, 1); return (1); } @@ -418,6 +405,11 @@ void CScriptEngine::init() load_common_scripts(); #endif m_stack_level = lua_gettop(lua()); + + if (ShouldAttachDebugger()) + { + //AttachDebugger(); //Getting crash in ljtab.c after executing this function: Unhandled exception thrown: read access violation. + } } void CScriptEngine::remove_script_process(const EScriptProcessors& process_id) diff --git a/src/xrServerEntities/script_engine_debugger.cpp b/src/xrServerEntities/script_engine_debugger.cpp new file mode 100644 index 000000000..594041290 --- /dev/null +++ b/src/xrServerEntities/script_engine_debugger.cpp @@ -0,0 +1,33 @@ +#include "stdafx.h" +#include +#include "pch_script.h" +#include "script_engine.h" +#include "script_engine_debugger.h" + +static bool isEnabled = true; +bool ShouldAttachDebugger() +{ + return isEnabled; +} + +void AttachDebugger() +{ + const char* S = "debugger_attach()"; + shared_str m_script_name = "console_command"; + CScriptEngine se = ai().script_engine(); + lua_State* L = se.lua(); + int l_iErrorCode = luaL_loadbuffer(L, S, xr_strlen(S), "@console_command"); + + if (!l_iErrorCode) + { + l_iErrorCode = lua_pcall(L, 0, 0, 0); + if (l_iErrorCode) + { + se.print_output(L, *m_script_name, l_iErrorCode); + return; + } + } + + se.print_output(L, *m_script_name, l_iErrorCode); + isEnabled = true; +} diff --git a/src/xrServerEntities/script_engine_debugger.h b/src/xrServerEntities/script_engine_debugger.h new file mode 100644 index 000000000..5ce458c28 --- /dev/null +++ b/src/xrServerEntities/script_engine_debugger.h @@ -0,0 +1,3 @@ +#pragma once +void AttachDebugger(); +bool ShouldAttachDebugger(); \ No newline at end of file diff --git a/src/xrServerEntities/script_storage.cpp b/src/xrServerEntities/script_storage.cpp index aaccc1c77..598924153 100644 --- a/src/xrServerEntities/script_storage.cpp +++ b/src/xrServerEntities/script_storage.cpp @@ -327,7 +327,6 @@ CScriptStorage::~CScriptStorage() extern int luaopen_lua_extensions(lua_State* L); extern lua_CFunction luaopen_socket_core_init(); extern void pdebug_init_init(lua_State* L); -void DebbugerAttach(); void disable_os_funcs(lua_State* L) { @@ -348,10 +347,11 @@ void disable_os_funcs(lua_State* L) lua_pop(L, 1); } -bool LoadScriptToGlobal(lua_State* L, const char* name) +bool LoadKernelScriptToGlobal(lua_State* L, const char* name) { string_path FileName; xr_string FixedFileName = name; + //FixedFileName = "kernel\\" + FixedFileName; //When this line is enabled all lua files are not being loaded after loading a game if (FS.exist(FileName, "$game_scripts$", FixedFileName.data())) { @@ -443,18 +443,18 @@ void CScriptStorage::reinit() disable_os_funcs(lua()); //loadjitmodule(lua(), "jit not found"); - LoadScriptToGlobal(lua(), "global.lua"); - LoadScriptToGlobal(lua(), "dynamic_callbacks.lua"); + LoadKernelScriptToGlobal(lua(), "global.lua"); + LoadKernelScriptToGlobal(lua(), "dynamic_callbacks.lua"); // Sockets luajit::open_lib(lua(), "socket.core", luaopen_socket_core_init()); - bool SocketTest = LoadScriptToGlobal(lua(), "socket.lua"); + bool SocketTest = LoadKernelScriptToGlobal(lua(), "socket.lua"); // Panda if (SocketTest) { pdebug_init_init(lua()); - LoadScriptToGlobal(lua(), "LuaPanda.lua"); + LoadKernelScriptToGlobal(lua(), "LuaPanda.lua"); } if (strstr(Core.Params, "-_g")) From f0bd8f8df48f096dc46bc43b3374c5d3f2778b7b Mon Sep 17 00:00:00 2001 From: SaloEater Date: Wed, 11 Jun 2025 23:29:59 -0500 Subject: [PATCH 05/27] cleanup --- src/3rd party/lua-extensions/base.cpp | 2 +- src/Layers/xrRender/ResourceManager_Scripting.cpp | 2 +- src/docs/lua_jit_bit_ffi.md | 0 src/xrEngine/stdafx.h | 2 +- src/xrEngine/vs2022/xrEngine.vcxproj | 6 ++---- src/xrGame/xrGame.cpp | 2 +- src/xrServerEntities/script_storage.cpp | 5 ++--- 7 files changed, 8 insertions(+), 11 deletions(-) delete mode 100644 src/docs/lua_jit_bit_ffi.md diff --git a/src/3rd party/lua-extensions/base.cpp b/src/3rd party/lua-extensions/base.cpp index 16f9fea21..b3c7fdccd 100644 --- a/src/3rd party/lua-extensions/base.cpp +++ b/src/3rd party/lua-extensions/base.cpp @@ -3,7 +3,7 @@ #include "luapanda.h" #ifdef USE_LUAJIT_ONE -#pragma comment(lib, "LuaJIT-1.1.8.lib") +#pragma comment(lib, "lua51.lib") #else #pragma comment(lib, "lua51.lib") #endif //-USE_LUAJIT_ONE diff --git a/src/Layers/xrRender/ResourceManager_Scripting.cpp b/src/Layers/xrRender/ResourceManager_Scripting.cpp index 96a4b7d3d..af0f6efea 100644 --- a/src/Layers/xrRender/ResourceManager_Scripting.cpp +++ b/src/Layers/xrRender/ResourceManager_Scripting.cpp @@ -3,7 +3,7 @@ //AVO: lua re-org #ifdef USE_LUAJIT_ONE //defined in project props -#pragma comment(lib, "lua51.lib") +#pragma comment(lib, "LuaJIT-1.1.8.lib") #else #pragma comment(lib, "lua51.lib" ) #endif diff --git a/src/docs/lua_jit_bit_ffi.md b/src/docs/lua_jit_bit_ffi.md deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/xrEngine/stdafx.h b/src/xrEngine/stdafx.h index 99db5b4c3..99eae8c03 100644 --- a/src/xrEngine/stdafx.h +++ b/src/xrEngine/stdafx.h @@ -72,7 +72,7 @@ extern ENGINE_API CInifile* pGameIni; //AVO: lua re-org #ifdef USE_LUAJIT_ONE //defined in project props -#pragma comment(lib, "lua51.lib") +#pragma comment(lib, "lua51.lib" ) #else #pragma comment(lib, "lua51.lib" ) #endif diff --git a/src/xrEngine/vs2022/xrEngine.vcxproj b/src/xrEngine/vs2022/xrEngine.vcxproj index 95484d636..025606c6a 100644 --- a/src/xrEngine/vs2022/xrEngine.vcxproj +++ b/src/xrEngine/vs2022/xrEngine.vcxproj @@ -302,8 +302,7 @@ stdafx.h - - + USE_LUAJIT_ONE ProgramDatabase MaxSpeed true @@ -465,8 +464,7 @@ stdafx.h - - + USE_LUAJIT_ONE ProgramDatabase MaxSpeed true diff --git a/src/xrGame/xrGame.cpp b/src/xrGame/xrGame.cpp index b5ba7163c..1b6a7f85b 100644 --- a/src/xrGame/xrGame.cpp +++ b/src/xrGame/xrGame.cpp @@ -14,7 +14,7 @@ //AVO: lua re-org #ifdef USE_LUAJIT_ONE //defined in project props -#pragma comment(lib, "lua51.lib") +#pragma comment(lib, "LuaJIT-1.1.8.lib") #else #pragma comment(lib, "lua51.lib" ) #endif diff --git a/src/xrServerEntities/script_storage.cpp b/src/xrServerEntities/script_storage.cpp index 598924153..7d0701aa6 100644 --- a/src/xrServerEntities/script_storage.cpp +++ b/src/xrServerEntities/script_storage.cpp @@ -225,7 +225,7 @@ static int report(lua_State *L, int status) static int loadjitmodule(lua_State *L, const char *notfound) { - lua_getglobal(L, "require"); + lua_getglobal(L, "require"); lua_pushliteral(L, "jit."); lua_pushvalue(L, -3); lua_concat(L, 2); @@ -438,10 +438,9 @@ void CScriptStorage::reinit() luajit::open_lib(lua(), LUA_DBLIBNAME, luaopen_debug); #endif //-DEBUG #endif //!USE_LUAJIT_ONE - + luaopen_lua_extensions(lua()); disable_os_funcs(lua()); - //loadjitmodule(lua(), "jit not found"); LoadKernelScriptToGlobal(lua(), "global.lua"); LoadKernelScriptToGlobal(lua(), "dynamic_callbacks.lua"); From daddbc2180249b76039fd8233e73ffd97a244b5f Mon Sep 17 00:00:00 2001 From: SaloEater Date: Wed, 11 Jun 2025 23:34:40 -0500 Subject: [PATCH 06/27] vscode config --- gamedata/scripts/.vscode/launch.json | 22 ++++++++++++++++++++++ gamedata/scripts/.vscode/settings.json | 5 +++++ 2 files changed, 27 insertions(+) create mode 100644 gamedata/scripts/.vscode/launch.json create mode 100644 gamedata/scripts/.vscode/settings.json diff --git a/gamedata/scripts/.vscode/launch.json b/gamedata/scripts/.vscode/launch.json new file mode 100644 index 000000000..89967bda0 --- /dev/null +++ b/gamedata/scripts/.vscode/launch.json @@ -0,0 +1,22 @@ + +{ + // Используйте IntelliSense, чтобы узнать о возможных атрибутах. + // Наведите указатель мыши, чтобы просмотреть описания существующих атрибутов. + // Для получения дополнительной информации посетите: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "lua", + "request": "launch", + "name": "LuaPanda", + "description": "IX-Ray Lua Debug", + "cwd": "${workspaceFolder}", + "luaFileExtension": "script", + "connectionPort": 8818, + "stopOnEntry": true, + "useCHook": true, + "autoPathMode": true, + "updateTips": true + } + ] +} \ No newline at end of file diff --git a/gamedata/scripts/.vscode/settings.json b/gamedata/scripts/.vscode/settings.json new file mode 100644 index 000000000..52541506f --- /dev/null +++ b/gamedata/scripts/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "Lua.diagnostics.disable": [ + "undefined-global" + ] +} \ No newline at end of file From 3a0cf10c9590f7fb25b1b38094aed5ddf8f36ae2 Mon Sep 17 00:00:00 2001 From: SaloEater Date: Wed, 11 Jun 2025 23:42:49 -0500 Subject: [PATCH 07/27] readme --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index b8cd0bece..175ee2da1 100644 --- a/README.md +++ b/README.md @@ -164,6 +164,14 @@ The original engine is used in S.T.A.L.K.E.R. Call of Pripyat game released by G * The step of zoom adjustment is more precise. Also, it's possible to adjust the step of zoom with the console command zoom_step_count [1.0, 10.0], this option is also applicable to the binoculars. * In the new version all implementations from fakelens.script have moved directly to the engine. fakelens.script remained as a layer between the engine and scopeRadii.script +* Debug scripts with VSCode and LuaPanda support + * To use it, you need to install VSCode and LuaPanda extension: https://marketplace.visualstudio.com/items?itemName=stuartwang.luapanda + * Then you need to copy `.vscode` folder from the archive into your Anomaly `gamedata/scripts` folder: https://github.com/themrdemonized/xray-monolith/tree/all-in-one-vs2022-wpo/gamedata/scripts/.vscode + * Open the `gamedata/scripts` folder in VSCode, go to `Run and Debug` section and start debugging or press F5 key + * To start debugging, open in-game console with `~` key and type `run_string debugger_attach()`. If you do everything correctly and engine is working properly too, you will get an entry breakpoint at `global.lua` file in VSCode. + * You have to re-enable the debugger every time you start a new game or load a save, so you have to type `run_string debugger_attach()` in console again. + * Debugger is working dynamically, so you can add/remove files from your VSCode folder and it will automatically update the list of files available for debugging. + * All settings can be edited from the game options in "Modded Exes" tab ![image](http://puu.sh/JC40Y/9315119150.jpg) From 87250073a875d55caf6c74556d6cdd91a6af7bb4 Mon Sep 17 00:00:00 2001 From: SaloEater Date: Thu, 12 Jun 2025 00:03:47 -0500 Subject: [PATCH 08/27] use correct lua lib --- src/xrGame/xrGame.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xrGame/xrGame.cpp b/src/xrGame/xrGame.cpp index 1b6a7f85b..38df06763 100644 --- a/src/xrGame/xrGame.cpp +++ b/src/xrGame/xrGame.cpp @@ -14,7 +14,7 @@ //AVO: lua re-org #ifdef USE_LUAJIT_ONE //defined in project props -#pragma comment(lib, "LuaJIT-1.1.8.lib") +#pragma comment(lib, "lua51.lib" ) #else #pragma comment(lib, "lua51.lib" ) #endif From 45437b50b7e8e8a4074e5b6b12a9333505a7d2bc Mon Sep 17 00:00:00 2001 From: SaloEater Date: Thu, 12 Jun 2025 00:30:43 -0500 Subject: [PATCH 09/27] cleanup --- README.md | 2 +- gamedata/scripts/.vscode/launch.json | 3 --- src/3rd party/lua-extensions/base.cpp | 4 ++-- src/xrEngine/stdafx.h | 2 +- src/xrEngine/vs2022/xrEngine.vcxproj.filters | 2 +- src/xrServerEntities/script_storage.cpp | 11 +++++++++++ 6 files changed, 16 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 175ee2da1..bec60bbcc 100644 --- a/README.md +++ b/README.md @@ -164,7 +164,7 @@ The original engine is used in S.T.A.L.K.E.R. Call of Pripyat game released by G * The step of zoom adjustment is more precise. Also, it's possible to adjust the step of zoom with the console command zoom_step_count [1.0, 10.0], this option is also applicable to the binoculars. * In the new version all implementations from fakelens.script have moved directly to the engine. fakelens.script remained as a layer between the engine and scopeRadii.script -* Debug scripts with VSCode and LuaPanda support +* Debug scripts with VSCode and LuaPanda support by IXRay Platform * To use it, you need to install VSCode and LuaPanda extension: https://marketplace.visualstudio.com/items?itemName=stuartwang.luapanda * Then you need to copy `.vscode` folder from the archive into your Anomaly `gamedata/scripts` folder: https://github.com/themrdemonized/xray-monolith/tree/all-in-one-vs2022-wpo/gamedata/scripts/.vscode * Open the `gamedata/scripts` folder in VSCode, go to `Run and Debug` section and start debugging or press F5 key diff --git a/gamedata/scripts/.vscode/launch.json b/gamedata/scripts/.vscode/launch.json index 89967bda0..62fb45540 100644 --- a/gamedata/scripts/.vscode/launch.json +++ b/gamedata/scripts/.vscode/launch.json @@ -1,8 +1,5 @@ { - // Используйте IntelliSense, чтобы узнать о возможных атрибутах. - // Наведите указатель мыши, чтобы просмотреть описания существующих атрибутов. - // Для получения дополнительной информации посетите: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ { diff --git a/src/3rd party/lua-extensions/base.cpp b/src/3rd party/lua-extensions/base.cpp index b3c7fdccd..20a17fc5a 100644 --- a/src/3rd party/lua-extensions/base.cpp +++ b/src/3rd party/lua-extensions/base.cpp @@ -3,7 +3,7 @@ #include "luapanda.h" #ifdef USE_LUAJIT_ONE -#pragma comment(lib, "lua51.lib") +#pragma comment(lib, "LuaJIT-1.1.8.lib") #else #pragma comment(lib, "lua51.lib") #endif //-USE_LUAJIT_ONE @@ -40,7 +40,7 @@ int luaopen_lua_extensions(lua_State *L){ //open_table(L); luaopen_marshal(L); //open_kb(L); - //open_log(L); + //open_log(L); luaL_register(L, "lua_extensions", R); return 0; diff --git a/src/xrEngine/stdafx.h b/src/xrEngine/stdafx.h index 99eae8c03..e7aa1b0e8 100644 --- a/src/xrEngine/stdafx.h +++ b/src/xrEngine/stdafx.h @@ -72,7 +72,7 @@ extern ENGINE_API CInifile* pGameIni; //AVO: lua re-org #ifdef USE_LUAJIT_ONE //defined in project props -#pragma comment(lib, "lua51.lib" ) +#pragma comment(lib, "LuaJIT-1.1.8.lib") #else #pragma comment(lib, "lua51.lib" ) #endif diff --git a/src/xrEngine/vs2022/xrEngine.vcxproj.filters b/src/xrEngine/vs2022/xrEngine.vcxproj.filters index f0730625d..e3215c262 100644 --- a/src/xrEngine/vs2022/xrEngine.vcxproj.filters +++ b/src/xrEngine/vs2022/xrEngine.vcxproj.filters @@ -489,7 +489,7 @@ Interfaces\ImGui - + diff --git a/src/xrServerEntities/script_storage.cpp b/src/xrServerEntities/script_storage.cpp index 7d0701aa6..7d16ec2f3 100644 --- a/src/xrServerEntities/script_storage.cpp +++ b/src/xrServerEntities/script_storage.cpp @@ -437,6 +437,17 @@ void CScriptStorage::reinit() if (strstr(Core.Params, "-dbg")) luajit::open_lib(lua(), LUA_DBLIBNAME, luaopen_debug); #endif //-DEBUG + + if (!strstr(Core.Params, "-nojit")) + { + //luajit::open_lib(lua(), LUA_JITLIBNAME, luaopen_jit); +#ifndef DEBUG + put_function(lua(), opt_lua_binary, sizeof(opt_lua_binary), "jit.opt"); + put_function(lua(), opt_inline_lua_binary, sizeof(opt_lua_binary), "jit.opt_inline"); + dojitopt(lua(), "2"); +#endif //!DEBUG + } + #endif //!USE_LUAJIT_ONE luaopen_lua_extensions(lua()); From c0aebfc18dfde6e40eb064fecd055fe412b68698 Mon Sep 17 00:00:00 2001 From: SaloEater Date: Thu, 12 Jun 2025 00:33:28 -0500 Subject: [PATCH 10/27] revert lua lib --- src/xrEngine/stdafx.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xrEngine/stdafx.h b/src/xrEngine/stdafx.h index e7aa1b0e8..99db5b4c3 100644 --- a/src/xrEngine/stdafx.h +++ b/src/xrEngine/stdafx.h @@ -72,7 +72,7 @@ extern ENGINE_API CInifile* pGameIni; //AVO: lua re-org #ifdef USE_LUAJIT_ONE //defined in project props -#pragma comment(lib, "LuaJIT-1.1.8.lib") +#pragma comment(lib, "lua51.lib") #else #pragma comment(lib, "lua51.lib" ) #endif From f43e194487a3ef6d5596eac54475485156046dd5 Mon Sep 17 00:00:00 2001 From: SaloEater Date: Thu, 12 Jun 2025 00:46:01 -0500 Subject: [PATCH 11/27] readme --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index bec60bbcc..44088560f 100644 --- a/README.md +++ b/README.md @@ -166,9 +166,10 @@ The original engine is used in S.T.A.L.K.E.R. Call of Pripyat game released by G * Debug scripts with VSCode and LuaPanda support by IXRay Platform * To use it, you need to install VSCode and LuaPanda extension: https://marketplace.visualstudio.com/items?itemName=stuartwang.luapanda - * Then you need to copy `.vscode` folder from the archive into your Anomaly `gamedata/scripts` folder: https://github.com/themrdemonized/xray-monolith/tree/all-in-one-vs2022-wpo/gamedata/scripts/.vscode - * Open the `gamedata/scripts` folder in VSCode, go to `Run and Debug` section and start debugging or press F5 key - * To start debugging, open in-game console with `~` key and type `run_string debugger_attach()`. If you do everything correctly and engine is working properly too, you will get an entry breakpoint at `global.lua` file in VSCode. + * Open your `gamedata/scripts` folder in VSCode + * Copy `.vscode` folder from the archive into your `gamedata/scripts` folder: https://github.com/themrdemonized/xray-monolith/tree/all-in-one-vs2022-wpo/gamedata/scripts/.vscode + * Return to VSCode, go to `Run and Debug` section and start debugging or press F5 key + * Open in-game console with `~` key and type `run_string debugger_attach()`. If you do everything correctly and engine is working properly too, you will get an entry breakpoint at `global.lua` file in VSCode. * You have to re-enable the debugger every time you start a new game or load a save, so you have to type `run_string debugger_attach()` in console again. * Debugger is working dynamically, so you can add/remove files from your VSCode folder and it will automatically update the list of files available for debugging. From 31d03003738d4310dc686c0930fc30cd832e97ec Mon Sep 17 00:00:00 2001 From: SaloEater Date: Thu, 12 Jun 2025 00:55:12 -0500 Subject: [PATCH 12/27] mention lua files in readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 44088560f..5e0c8a73c 100644 --- a/README.md +++ b/README.md @@ -168,6 +168,7 @@ The original engine is used in S.T.A.L.K.E.R. Call of Pripyat game released by G * To use it, you need to install VSCode and LuaPanda extension: https://marketplace.visualstudio.com/items?itemName=stuartwang.luapanda * Open your `gamedata/scripts` folder in VSCode * Copy `.vscode` folder from the archive into your `gamedata/scripts` folder: https://github.com/themrdemonized/xray-monolith/tree/all-in-one-vs2022-wpo/gamedata/scripts/.vscode + * Copy `LuaPanda.lua`, `dynamic_callbacks.lua`, `global.lua`, `socket.lua` into your `gamedata/scripts` folder: https://github.com/themrdemonized/xray-monolith/tree/all-in-one-vs2022-wpo/gamedata/scripts * Return to VSCode, go to `Run and Debug` section and start debugging or press F5 key * Open in-game console with `~` key and type `run_string debugger_attach()`. If you do everything correctly and engine is working properly too, you will get an entry breakpoint at `global.lua` file in VSCode. * You have to re-enable the debugger every time you start a new game or load a save, so you have to type `run_string debugger_attach()` in console again. From 719d204a22392043707aa6baa73b7ffcbd1587de Mon Sep 17 00:00:00 2001 From: SaloEater Date: Thu, 12 Jun 2025 13:36:21 -0500 Subject: [PATCH 13/27] Actually, we don't need use_luajit_one define --- src/3rd party/lua-extensions/base.cpp | 10 ++++++++-- .../xrRender/ResourceManager_Scripting.cpp | 2 +- .../dx10ResourceManager_Scripting.cpp | 2 +- src/xrEngine/stdafx.h | 2 +- src/xrGame/vs2022/xrGame.vcxproj | 5 ++--- src/xrGame/xrGame.cpp | 2 +- src/xrServerEntities/script_storage.cpp | 16 ++++++---------- 7 files changed, 20 insertions(+), 19 deletions(-) diff --git a/src/3rd party/lua-extensions/base.cpp b/src/3rd party/lua-extensions/base.cpp index 20a17fc5a..5a7c7825a 100644 --- a/src/3rd party/lua-extensions/base.cpp +++ b/src/3rd party/lua-extensions/base.cpp @@ -29,8 +29,7 @@ static const struct luaL_reg R[] = }; //extern "C" __declspec(dllexport) -int luaopen_lua_extensions(lua_State *L){ - luaopen_debug(L); +int luaopen_lua_extensions(lua_State *L, bool IsDebug = false){ open_additional_libs(L); @@ -42,6 +41,13 @@ int luaopen_lua_extensions(lua_State *L){ //open_kb(L); //open_log(L); + if (IsDebug) + { + luaopen_jit(L); + luaopen_ffi(L); + luaopen_debug(L); + } + luaL_register(L, "lua_extensions", R); return 0; } diff --git a/src/Layers/xrRender/ResourceManager_Scripting.cpp b/src/Layers/xrRender/ResourceManager_Scripting.cpp index af0f6efea..ffdba037c 100644 --- a/src/Layers/xrRender/ResourceManager_Scripting.cpp +++ b/src/Layers/xrRender/ResourceManager_Scripting.cpp @@ -324,7 +324,7 @@ static void *lua_alloc (void *ud, void *ptr, size_t osize, size_t nsize) { #endif // USE_DL_ALLOCATOR // export -extern int luaopen_lua_extensions(lua_State* L); +extern int luaopen_lua_extensions(lua_State* L, bool IsDebug = false); void CResourceManager::LS_Load() { diff --git a/src/Layers/xrRenderDX10/dx10ResourceManager_Scripting.cpp b/src/Layers/xrRenderDX10/dx10ResourceManager_Scripting.cpp index 3ed193bae..d4243d493 100644 --- a/src/Layers/xrRenderDX10/dx10ResourceManager_Scripting.cpp +++ b/src/Layers/xrRenderDX10/dx10ResourceManager_Scripting.cpp @@ -327,7 +327,7 @@ static void *lua_alloc (void *ud, void *ptr, size_t osize, size_t nsize) { #endif // USE_DL_ALLOCATOR // export -extern int luaopen_lua_extensions(lua_State* L); +extern int luaopen_lua_extensions(lua_State* L, bool IsDebug = false); void CResourceManager::LS_Load() { diff --git a/src/xrEngine/stdafx.h b/src/xrEngine/stdafx.h index 99db5b4c3..e7aa1b0e8 100644 --- a/src/xrEngine/stdafx.h +++ b/src/xrEngine/stdafx.h @@ -72,7 +72,7 @@ extern ENGINE_API CInifile* pGameIni; //AVO: lua re-org #ifdef USE_LUAJIT_ONE //defined in project props -#pragma comment(lib, "lua51.lib") +#pragma comment(lib, "LuaJIT-1.1.8.lib") #else #pragma comment(lib, "lua51.lib" ) #endif diff --git a/src/xrGame/vs2022/xrGame.vcxproj b/src/xrGame/vs2022/xrGame.vcxproj index b93f710dc..00a5bee87 100644 --- a/src/xrGame/vs2022/xrGame.vcxproj +++ b/src/xrGame/vs2022/xrGame.vcxproj @@ -105,15 +105,14 @@ vs2022;..;$(SolutionDir);$(SolutionDir)xrServerEntities;$(SolutionDir)3rd party\luajit-2\src\;$(SolutionDir)3rd party\luabind\;$(xrSdkDir)include;$(XRAY_16X_LIBS)OpenAutomate\inc;$(SolutionDir)3rd party\CxImage;%(AdditionalIncludeDirectories) - WIN32;NDEBUG;_WINDOWS;_USRDLL;XRGAME_EXPORTS;dSINGLE;MSVC;_SECURE_SCL=0;USE_LUAJIT_ONE;%(PreprocessorDefinitions) + WIN32;NDEBUG;_WINDOWS;_USRDLL;XRGAME_EXPORTS;dSINGLE;MSVC;_SECURE_SCL=0;%(PreprocessorDefinitions) NotSet Use stdafx.h 4995;4005;4237;%(DisableSpecificWarnings) - - + USE_LUAJIT_ONE false MaxSpeed true diff --git a/src/xrGame/xrGame.cpp b/src/xrGame/xrGame.cpp index 38df06763..e776c24d1 100644 --- a/src/xrGame/xrGame.cpp +++ b/src/xrGame/xrGame.cpp @@ -14,7 +14,7 @@ //AVO: lua re-org #ifdef USE_LUAJIT_ONE //defined in project props -#pragma comment(lib, "lua51.lib" ) +#pragma comment(lib, "LuaJIT-1.1.8.lib" ) #else #pragma comment(lib, "lua51.lib" ) #endif diff --git a/src/xrServerEntities/script_storage.cpp b/src/xrServerEntities/script_storage.cpp index 7d16ec2f3..35c8fa831 100644 --- a/src/xrServerEntities/script_storage.cpp +++ b/src/xrServerEntities/script_storage.cpp @@ -17,21 +17,18 @@ #include #if !defined(DEBUG) && defined(USE_LUAJIT_ONE) -# include "../xrServerEntities/opt.lua.h" -# include "../xrServerEntities/opt_inline.lua.h" +# include "opt.lua.h" +# include "opt_inline.lua.h" #endif //!DEBUG && USE_LUAJIT_ONE #ifndef USE_LUAJIT_ONE #include "lua.hpp" #endif -#ifdef USE_LUAJIT_ONE extern "C" { #include int luaopen_marshal(lua_State* L); - int luaopen_LuaXML_lib(lua_State* L); - int luaopen_utf8(lua_State* L); - + } struct luajit { @@ -42,7 +39,6 @@ struct luajit lua_call(L, 1, 0); } }; -#endif LPCSTR file_header_old = "\ @@ -324,7 +320,7 @@ CScriptStorage::~CScriptStorage() lua_close(m_virtual_machine); } -extern int luaopen_lua_extensions(lua_State* L); +extern int luaopen_lua_extensions(lua_State* L, bool IsDebug = false); extern lua_CFunction luaopen_socket_core_init(); extern void pdebug_init_init(lua_State* L); @@ -449,8 +445,8 @@ void CScriptStorage::reinit() } #endif //!USE_LUAJIT_ONE - - luaopen_lua_extensions(lua()); + bool isDebugEnabled = strstr(Core.Params, "-dbg") != nullptr; + luaopen_lua_extensions(lua(), isDebugEnabled); disable_os_funcs(lua()); LoadKernelScriptToGlobal(lua(), "global.lua"); From c80406c3c6b9fd6840b4cf68089d292f12581587 Mon Sep 17 00:00:00 2001 From: SaloEater Date: Sat, 14 Jun 2025 22:31:25 -0500 Subject: [PATCH 14/27] restore code --- src/xrServerEntities/script_storage.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/xrServerEntities/script_storage.cpp b/src/xrServerEntities/script_storage.cpp index 35c8fa831..a06a9efd5 100644 --- a/src/xrServerEntities/script_storage.cpp +++ b/src/xrServerEntities/script_storage.cpp @@ -980,10 +980,10 @@ bool CScriptStorage::do_file(LPCSTR caScriptName, LPCSTR caNameSpaceName) bool bufferLoaded = false; if (unlocalPerformed) { - bufferLoaded = load_buffer(lua(), scriptContents, scriptLength, caNameSpaceName, caNameSpaceName); + bufferLoaded = load_buffer(lua(), scriptContents, scriptLength, l_caLuaFileName, caNameSpaceName); } else { l_tpFileReader->rewind(); - bufferLoaded = load_buffer(lua(), static_cast(l_tpFileReader->pointer()), (size_t)l_tpFileReader->length(), caNameSpaceName, caNameSpaceName); + bufferLoaded = load_buffer(lua(), static_cast(l_tpFileReader->pointer()), (size_t)l_tpFileReader->length(), l_caLuaFileName, caNameSpaceName); } if (!bufferLoaded) From 7534c826a6860366efeeed1d097734f89d31496c Mon Sep 17 00:00:00 2001 From: SaloEater Date: Sat, 14 Jun 2025 22:32:42 -0500 Subject: [PATCH 15/27] add lua files to solution --- src/engine-vs2022.sln | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/engine-vs2022.sln b/src/engine-vs2022.sln index c81a78e3e..63087506d 100644 --- a/src/engine-vs2022.sln +++ b/src/engine-vs2022.sln @@ -109,8 +109,11 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "scripts", "scripts", "{8EC4 ..\gamedata\scripts\callbacks_gameobject.script = ..\gamedata\scripts\callbacks_gameobject.script ..\gamedata\scripts\class_registrator_modded_exes.script = ..\gamedata\scripts\class_registrator_modded_exes.script ..\gamedata\scripts\dxml_core.script = ..\gamedata\scripts\dxml_core.script + ..\gamedata\scripts\dynamic_callbacks.lua = ..\gamedata\scripts\dynamic_callbacks.lua ..\gamedata\scripts\fakelens.script = ..\gamedata\scripts\fakelens.script + ..\gamedata\scripts\global.lua = ..\gamedata\scripts\global.lua ..\gamedata\scripts\ltx_help_ex.script = ..\gamedata\scripts\ltx_help_ex.script + ..\gamedata\scripts\LuaPanda.lua = ..\gamedata\scripts\LuaPanda.lua ..\gamedata\scripts\lua_help_ex.script = ..\gamedata\scripts\lua_help_ex.script ..\gamedata\scripts\modxml_inject_keybinds.script = ..\gamedata\scripts\modxml_inject_keybinds.script ..\gamedata\scripts\modxml_test.script = ..\gamedata\scripts\modxml_test.script @@ -142,6 +145,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "scripts", "scripts", "{8EC4 ..\gamedata\scripts\options_modded_exes_wallmarks.script = ..\gamedata\scripts\options_modded_exes_wallmarks.script ..\gamedata\scripts\scopeRadii.script = ..\gamedata\scripts\scopeRadii.script ..\gamedata\scripts\slaxml.script = ..\gamedata\scripts\slaxml.script + ..\gamedata\scripts\socket.lua = ..\gamedata\scripts\socket.lua ..\gamedata\scripts\true_first_person_death.script = ..\gamedata\scripts\true_first_person_death.script ..\gamedata\scripts\ui_options_modded_exes.script = ..\gamedata\scripts\ui_options_modded_exes.script ..\gamedata\scripts\_g_patches.script = ..\gamedata\scripts\_g_patches.script From 16b26bc9e147668a4abe4ae45c7625317b16d8fe Mon Sep 17 00:00:00 2001 From: SaloEater Date: Sat, 14 Jun 2025 22:34:33 -0500 Subject: [PATCH 16/27] change pot to sep correctly --- gamedata/scripts/LuaPanda.lua | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/gamedata/scripts/LuaPanda.lua b/gamedata/scripts/LuaPanda.lua index 5d1a871c3..8bd317a7a 100644 --- a/gamedata/scripts/LuaPanda.lua +++ b/gamedata/scripts/LuaPanda.lua @@ -1696,12 +1696,14 @@ end -- @filePath 被替换的路径 -- @ext 后缀(后缀前的 . 不会被替换) function this.changePotToSep(filePath, ext) - local idx = filePath:find(ext, (-1) * ext:len() , true) - if idx then - local tmp = filePath:sub(1, idx - 1):gsub("%.", "/"); - filePath = tmp .. ext; + local idx = filePath:find(ext, (-1) * ext:len(), true) + if idx then + local tmp = filePath:sub(1, idx - 2):gsub("%.", "/") -- Exclude the dot before the extension + filePath = tmp .. filePath:sub(idx - 1) -- Preserve the dot and extension + else + filePath = filePath:gsub("%.", "/") end - return filePath; + return filePath end --- this.truncatedPath 从 beTruncatedPath 字符串中去除 rep 匹配到的部分 From 3d0a60e9704eb116b6f34dd611b00819daed0bd5 Mon Sep 17 00:00:00 2001 From: SaloEater Date: Mon, 16 Jun 2025 14:05:29 -0500 Subject: [PATCH 17/27] remove everything else except luapanda itself --- src/xrEngine/EngineAPI.h | 10 - src/xrEngine/imgui_base.cpp | 7 - src/xrEngine/imgui_tools.cpp | 16 - src/xrEngine/imgui_tools.h | 3 - src/xrEngine/vs2022/xrEngine.vcxproj | 2 - src/xrEngine/vs2022/xrEngine.vcxproj.filters | 2 - src/xrGame/vs2022/xrGame.vcxproj | 2 - src/xrGame/vs2022/xrGame.vcxproj.filters | 6 - src/xrServerEntities/opt.lua.h | 427 ------------------ src/xrServerEntities/opt_inline.lua.h | 372 --------------- src/xrServerEntities/script_engine.cpp | 6 - .../script_engine_debugger.cpp | 33 -- src/xrServerEntities/script_engine_debugger.h | 3 - src/xrServerEntities/script_storage.cpp | 4 +- 14 files changed, 2 insertions(+), 891 deletions(-) delete mode 100644 src/xrEngine/imgui_tools.cpp delete mode 100644 src/xrEngine/imgui_tools.h delete mode 100644 src/xrServerEntities/opt.lua.h delete mode 100644 src/xrServerEntities/opt_inline.lua.h delete mode 100644 src/xrServerEntities/script_engine_debugger.cpp delete mode 100644 src/xrServerEntities/script_engine_debugger.h diff --git a/src/xrEngine/EngineAPI.h b/src/xrEngine/EngineAPI.h index 60f024d5d..ad2731322 100644 --- a/src/xrEngine/EngineAPI.h +++ b/src/xrEngine/EngineAPI.h @@ -4,8 +4,6 @@ // Support for extension DLLs //**************************************************************************** -#include - #if !defined(AFX_ENGINEAPI_H__CF21372B_C8B8_4891_82FC_D872C84E1DD4__INCLUDED_) #define AFX_ENGINEAPI_H__CF21372B_C8B8_4891_82FC_D872C84E1DD4__INCLUDED_ #pragma once @@ -37,12 +35,6 @@ typedef void __cdecl VTPause(void); typedef void __cdecl VTResume(void); }; -enum class EditorUI : uint8_t -{ - LuaDebug, - Count -}; - class ENGINE_API CEngineAPI { private: @@ -57,8 +49,6 @@ class ENGINE_API CEngineAPI VTPause* tune_pause; VTResume* tune_resume; - std::array(EditorUI::Count)> EditorStates = { }; - void Initialize(); #ifndef DEDICATED_SERVER diff --git a/src/xrEngine/imgui_base.cpp b/src/xrEngine/imgui_base.cpp index 7e3d831c5..1b846062f 100644 --- a/src/xrEngine/imgui_base.cpp +++ b/src/xrEngine/imgui_base.cpp @@ -4,7 +4,6 @@ #include #include "device.h" #include "IGame_Persistent.h" -#include "imgui_tools.h" static const char* GetCustomCompressedFontDataTTF(int* out_size); static const char* GetIconCompressedFontDataTTF(int* out_size); @@ -213,12 +212,6 @@ namespace xr_imgui g_pGamePersistent->ImGui_OnRender("MenuBar"); - if (ImGui::BeginMenu("Tools")) - { - InitImguiTools(); - ImGui::EndMenu(); - } - if (ImGui::BeginMenu("About")) { if (ImGui::MenuItem("Demo", nullptr, imgui_demo)) diff --git a/src/xrEngine/imgui_tools.cpp b/src/xrEngine/imgui_tools.cpp deleted file mode 100644 index 0766ecfc1..000000000 --- a/src/xrEngine/imgui_tools.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include "stdafx.h" -#include -#include "../xrServerEntities/script_engine_debugger.h" - -void InitImguiTools() -{ - auto& States = Engine.External.EditorStates; - bool* luaDebug = &States[static_cast(EditorUI::LuaDebug)]; - if (ImGui::MenuItem("Lua: Attach to VSCode (Doesn't work)", nullptr, luaDebug)) - { - if (*luaDebug) - { - //AttachDebugger(); //Getting crash in ljtab.c after executing this function: Unhandled exception thrown: read access violation. - } - } -} \ No newline at end of file diff --git a/src/xrEngine/imgui_tools.h b/src/xrEngine/imgui_tools.h deleted file mode 100644 index 35cc02d43..000000000 --- a/src/xrEngine/imgui_tools.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -void InitImguiTools(); \ No newline at end of file diff --git a/src/xrEngine/vs2022/xrEngine.vcxproj b/src/xrEngine/vs2022/xrEngine.vcxproj index 025606c6a..273fa2618 100644 --- a/src/xrEngine/vs2022/xrEngine.vcxproj +++ b/src/xrEngine/vs2022/xrEngine.vcxproj @@ -721,7 +721,6 @@ - @@ -780,7 +779,6 @@ - diff --git a/src/xrEngine/vs2022/xrEngine.vcxproj.filters b/src/xrEngine/vs2022/xrEngine.vcxproj.filters index e3215c262..56dda51ec 100644 --- a/src/xrEngine/vs2022/xrEngine.vcxproj.filters +++ b/src/xrEngine/vs2022/xrEngine.vcxproj.filters @@ -489,7 +489,6 @@ Interfaces\ImGui - @@ -792,7 +791,6 @@ - diff --git a/src/xrGame/vs2022/xrGame.vcxproj b/src/xrGame/vs2022/xrGame.vcxproj index 00a5bee87..5a2393d9c 100644 --- a/src/xrGame/vs2022/xrGame.vcxproj +++ b/src/xrGame/vs2022/xrGame.vcxproj @@ -338,7 +338,6 @@ - @@ -1967,7 +1966,6 @@ pch_script.h $(IntDir)$(ProjectName)_script.pch - pch_script.h $(IntDir)$(ProjectName)_script.pch diff --git a/src/xrGame/vs2022/xrGame.vcxproj.filters b/src/xrGame/vs2022/xrGame.vcxproj.filters index 3d1fb96c6..4d3352f16 100644 --- a/src/xrGame/vs2022/xrGame.vcxproj.filters +++ b/src/xrGame/vs2022/xrGame.vcxproj.filters @@ -7404,9 +7404,6 @@ UI\Common\ImGui - - AI\AScript\ScriptEngine - @@ -11105,9 +11102,6 @@ UI\Common\ImGui - - AI\AScript\ScriptEngine - diff --git a/src/xrServerEntities/opt.lua.h b/src/xrServerEntities/opt.lua.h deleted file mode 100644 index e172a62d1..000000000 --- a/src/xrServerEntities/opt.lua.h +++ /dev/null @@ -1,427 +0,0 @@ -/* code automatically generated by bin2c -- DO NOT EDIT */ -/* #include'ing this file in a C program is equivalent to calling - if (luaL_loadfile(L,"luac.out")==0) lua_pcall(L, 0, 0, 0); -*/ -/* luac.out */ -static const unsigned char opt_lua_binary[] = { - 27, 76,117, 97, 81, 0, 1, 4, 4, 4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 2, 33,195, 0, 0, 0, 1, 0, 0, 0, 65, 64, 0, 0, -138, 64, 1, 0,137,192, 64,129,137, 64, 65,130,137,192, 65,131,137, 64, 66,132, -137,192, 66,133,197, 0, 3, 0, 1, 65, 3, 0,220,128, 0, 1, 5,129, 3, 0, - 70,193,195, 1, 87, 0,196, 2, 22, 0, 0,128, 66, 65, 0, 0, 66, 1,128, 0, -129, 65, 4, 0, 28, 65,128, 1, 5, 1, 3, 0, 65,129, 4, 0, 28,129, 0, 1, - 69,193, 4, 0,133, 1, 5, 0,197, 65, 5, 0, 5,130, 5, 0, 70,194, 69, 2, -134, 2, 70, 2,198, 66, 70, 2, 6,131, 70, 2, 69,195, 6, 0,134, 3,199, 1, -194, 3,128, 0, 2, 4,128, 0,156, 67,128, 1,129, 67, 7, 0,228, 3, 0, 0, - 0, 0,128, 4, 0, 0, 0, 2, 36, 68, 0, 0,100,132, 0, 0, 0, 0,128, 5, -164,196, 0, 0, 0, 0,128, 2, 0, 0,128, 5,228, 4, 1, 0, 0, 0,128, 2, - 0, 0,128, 5, 36, 69, 1, 0, 0, 0,128, 2, 0, 0, 0, 3, 0, 0,128, 6, - 0, 0,128, 3,100,133, 1, 0, 0, 0,128, 4,164,197, 1, 0, 0, 0,128, 2, - 0, 0,128, 5,228, 5, 2, 0, 0, 0,128, 10, 0, 0,128, 5, 10,134, 6, 0, -100, 70, 2, 0, 9, 70, 6,143,100,134, 2, 0, 0, 0, 0, 5, 9, 70,134,143, -100,198, 2, 0, 9, 70, 6,144,100, 6, 3, 0, 9, 70,134,144,100, 70, 3, 0, - 0, 0, 0, 2, 9, 70, 6,145,100,134, 3, 0, 0, 0, 0, 10, 0, 0, 0, 5, - 9, 70,134,145,100,198, 3, 0, 0, 0,128, 9, 0, 0, 0, 10, 9, 70, 6,146, - 9, 6,132,146, 9, 6, 4,147,100, 6, 4, 0, 0, 0,128, 9, 0, 0,128, 2, - 9, 70,134,147,100, 70, 4, 0, 9, 70, 6,148,100,134, 4, 0, 0, 0,128, 9, - 0, 0, 0, 10, 9, 70,134,148, 9,134, 5,149, 9,134,133,149, 9,134, 5,150, - 9,134,133,150, 9,134, 5,151, 9,134,133,151, 9,134, 5,152, 9,134,133,152, -100,198, 4, 0, 0, 0, 0, 11, 9, 70, 6,153,100, 6, 5, 0, 9, 70,134,153, -100, 70, 5, 0, 0, 0, 0, 9, 9, 70, 6,154,100,134, 5, 0, 0, 0,128, 2, - 0, 0,128, 5, 9, 70,134,154,100,198, 5, 0, 0, 0,128, 5, 9, 70, 6,155, -100, 6, 6, 0, 0, 0, 0, 9, 9, 70,134,155,100, 70, 6, 0, 0, 0,128, 11, - 9, 70, 6,156, 9,198,133,156,100,134, 6, 0, 0, 0,128, 8, 9, 70, 6,157, -100,198, 6, 0, 0, 0,128, 8, 9, 70,134,157,100, 6, 7, 0, 0, 0,128, 10, - 0, 0,128, 5, 9, 70, 6,158, 9, 6,132,158,100, 70, 7, 0, 0, 0,128, 10, - 0, 0,128, 2, 0, 0,128, 5, 9, 70, 6,159,100,134, 7, 0, 0, 0,128, 5, - 9, 70,134,159,100,198, 7, 0, 0, 0,128, 2, 9, 70, 6,160, 9, 6,132,160, -100, 6, 8, 0, 0, 0, 0, 8, 0, 0, 0, 2, 0, 0,128, 4, 9, 70, 6,161, -100, 70, 8, 0, 9, 70,134,161,100,134, 8, 0, 0, 0, 0, 2, 0, 0, 0, 1, - 0, 0,128, 7, 0, 0, 0, 8, 0, 0, 0, 5, 0, 0,128, 4, 0, 0, 0, 12, - 0, 0,128, 5, 0, 0, 0, 6,131, 6,128, 13, 36,199, 8, 0, 0, 0, 0, 7, - 0, 0, 0, 4, 0, 0,128, 12, 0, 0,128, 1, 0, 0, 0, 14, 0, 0, 0, 13, -100, 7, 9, 0, 0, 0, 0, 4,164, 71, 9, 0, 0, 0, 0, 13, 0, 0,128, 1, - 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0,128, 0, 0, 0,128, 14, - 0, 0,128, 13,197, 7, 17, 0, 37, 8, 0, 0,220, 71, 0, 0,228,135, 9, 0, - 0, 0,128, 8,199, 71, 17, 0,228,199, 9, 0, 0, 0, 0, 7,199,135, 17, 0, -135,199, 17, 0,135, 7, 18, 0, 30, 0,128, 0, 73, 0, 0, 0, 3, 0, 0, 0, - 0, 0, 0, 73, 64, 3, 0, 0, 0, 0, 0, 0, 0, 64, 4, 10, 0, 0, 0, 98, -121,116,101, 99,111,100,101,115, 0, 3, 0, 0, 0, 0, 0, 64,175, 64, 4, 11, - 0, 0, 0,115,116, 97, 99,107,115,108,111,116,115, 0, 3, 0, 0, 0, 0, 0, -192, 98, 64, 4, 7, 0, 0, 0,112, 97,114, 97,109,115, 0, 3, 0, 0, 0, 0, - 0, 0, 52, 64, 4, 7, 0, 0, 0, 99,111,110,115,116,115, 0, 3, 0, 0, 0, - 0, 0, 0,105, 64, 4, 5, 0, 0, 0,115,117, 98,115, 0, 3, 0, 0, 0, 0, - 0, 0, 62, 64, 4, 8, 0, 0, 0,114,101,113,117,105,114,101, 0, 4, 4, 0, - 0, 0,106,105,116, 0, 4, 7, 0, 0, 0, 97,115,115,101,114,116, 0, 4, 12, - 0, 0, 0,118,101,114,115,105,111,110, 95,110,117,109, 0, 3, 0, 0, 0, 0, - 0,188,195, 64, 4, 37, 0, 0, 0, 76,117, 97, 74, 73, 84, 32, 99,111,114,101, - 47,108,105, 98,114, 97,114,121, 32,118,101,114,115,105,111,110, 32,109,105,115, -109, 97,116, 99,104, 0, 4, 9, 0, 0, 0,106,105,116, 46,117,116,105,108, 0, - 4, 5, 0, 0, 0,116,121,112,101, 0, 4, 7, 0, 0, 0,114, 97,119,103,101, -116, 0, 4, 5, 0, 0, 0,110,101,120,116, 0, 4, 6, 0, 0, 0,112, 99, 97, -108,108, 0, 4, 9, 0, 0, 0, 98,121,116,101, 99,111,100,101, 0, 4, 6, 0, - 0, 0, 99,111,110,115,116, 0, 4, 6, 0, 0, 0,104,105,110,116,115, 0, 4, - 7, 0, 0, 0,102,104,105,110,116,115, 0, 4, 13, 0, 0, 0,103,101,116,109, -101,116, 97,116, 97, 98,108,101, 0, 4, 4, 0, 0, 0,111,102,102, 0, 3, 0, - 0, 0, 0, 0, 0,240,191, 4, 5, 0, 0, 0, 77, 79, 86, 69, 0, 4, 6, 0, - 0, 0, 76, 79, 65, 68, 75, 0, 4, 9, 0, 0, 0, 76, 79, 65, 68, 66, 79, 79, - 76, 0, 4, 8, 0, 0, 0, 76, 79, 65, 68, 78, 73, 76, 0, 4, 9, 0, 0, 0, - 71, 69, 84, 85, 80, 86, 65, 76, 0, 4, 10, 0, 0, 0, 71, 69, 84, 71, 76, 79, - 66, 65, 76, 0, 4, 9, 0, 0, 0, 71, 69, 84, 84, 65, 66, 76, 69, 0, 4, 10, - 0, 0, 0, 83, 69, 84, 71, 76, 79, 66, 65, 76, 0, 4, 9, 0, 0, 0, 83, 69, - 84, 85, 80, 86, 65, 76, 0, 4, 9, 0, 0, 0, 83, 69, 84, 84, 65, 66, 76, 69, - 0, 4, 9, 0, 0, 0, 78, 69, 87, 84, 65, 66, 76, 69, 0, 4, 5, 0, 0, 0, - 83, 69, 76, 70, 0, 4, 4, 0, 0, 0, 65, 68, 68, 0, 4, 4, 0, 0, 0, 83, - 85, 66, 0, 4, 4, 0, 0, 0, 77, 85, 76, 0, 4, 4, 0, 0, 0, 68, 73, 86, - 0, 4, 4, 0, 0, 0, 77, 79, 68, 0, 4, 4, 0, 0, 0, 80, 79, 87, 0, 4, - 3, 0, 0, 0, 76, 84, 0, 4, 3, 0, 0, 0, 76, 69, 0, 4, 4, 0, 0, 0, - 85, 78, 77, 0, 4, 4, 0, 0, 0, 78, 79, 84, 0, 4, 4, 0, 0, 0, 76, 69, - 78, 0, 4, 7, 0, 0, 0, 67, 79, 78, 67, 65, 84, 0, 4, 4, 0, 0, 0, 74, - 77, 80, 0, 4, 3, 0, 0, 0, 69, 81, 0, 4, 5, 0, 0, 0, 84, 69, 83, 84, - 0, 4, 8, 0, 0, 0, 84, 69, 83, 84, 83, 69, 84, 0, 4, 5, 0, 0, 0, 67, - 65, 76, 76, 0, 4, 9, 0, 0, 0, 84, 65, 73, 76, 67, 65, 76, 76, 0, 4, 7, - 0, 0, 0, 82, 69, 84, 85, 82, 78, 0, 4, 8, 0, 0, 0, 70, 79, 82, 76, 79, - 79, 80, 0, 4, 8, 0, 0, 0, 70, 79, 82, 80, 82, 69, 80, 0, 4, 9, 0, 0, - 0, 84, 70, 79, 82, 76, 79, 79, 80, 0, 4, 8, 0, 0, 0, 83, 69, 84, 76, 73, - 83, 84, 0, 4, 6, 0, 0, 0, 67, 76, 79, 83, 69, 0, 4, 8, 0, 0, 0, 67, - 76, 79, 83, 85, 82, 69, 0, 4, 7, 0, 0, 0, 86, 65, 82, 65, 82, 71, 0, 4, - 7, 0, 0, 0,109,111,100,117,108,101, 0, 4, 16, 0, 0, 0, 97,116,116, 97, - 99,104, 95, 99, 97,108,108,104,105,110,116, 0, 4, 9, 0, 0, 0,103,101,116, -108,101,118,101,108, 0, 4, 9, 0, 0, 0,115,101,116,108,101,118,101,108, 0, - 4, 6, 0, 0, 0,115,116, 97,114,116, 0, 40, 0, 0, 0, 0, 0, 0, 0, 64, - 0, 0, 0,100, 0, 0, 0, 2, 1, 0, 13, 68, 0, 0, 0, 74, 0, 0, 0,138, - 0, 0, 0,193, 0, 0, 0, 1, 65, 0, 0, 68, 1, 0, 0,128, 1, 0, 0,192, - 1, 0, 2, 92,129,129, 1, 73,128, 64, 2, 12, 65, 64, 2, 23,192,192, 2, 22, -192, 0,128, 12,193, 1, 2,146, 2, 0, 2, 73,128, 64, 5, 22, 64, 10,128, 23, - 0,193, 2, 22, 0, 1,128,146, 2, 0, 2,205,194, 1, 5, 73,128,192, 5, 73, -128, 64, 5, 22,128, 8,128, 23, 64,193, 2, 22, 64, 0,128, 22,128, 8,128, 22, -128, 7,128, 90, 2, 0, 0, 22,128, 1,128,140, 66, 64, 2,198,130,130, 0,218, - 66, 0, 0, 22, 0, 6,128,204, 64,192, 1,137,128,130, 1, 22, 64, 5,128, 23, -128,193, 2, 22,128, 1,128,132, 2,128, 0,134,194, 65, 5,192, 2, 0, 0, 0, - 3,128, 3,156,130,128, 1, 12,129, 2, 2, 22, 0, 3,128, 23, 0,194, 2, 22, - 64, 1,128, 87, 0, 64, 4, 22,192, 0,128, 12, 65, 64, 2,146, 2, 0, 2, 73, -128, 64, 5, 22, 0, 1,128, 23, 64,194, 2, 22,128, 0,128, 23, 0, 64, 4, 22, - 0, 0,128, 12, 65, 64, 2,134, 2,129, 0,154, 2, 0, 0, 22,128,241,127, 23, - 0,192, 1, 22, 0, 0,128, 94, 0, 0, 1, 6,193, 0, 1,205, 64,192, 1, 22, - 0,240,127, 30, 0,128, 0, 10, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, - 3, 0, 0, 0, 0, 0, 0,240, 63, 1, 1, 4, 4, 0, 0, 0, 74, 77, 80, 0, - 4, 8, 0, 0, 0, 70, 79, 82, 76, 79, 79, 80, 0, 4, 7, 0, 0, 0, 82, 69, - 84, 85, 82, 78, 0, 4, 8, 0, 0, 0, 67, 76, 79, 83, 85, 82, 69, 0, 4, 11, - 0, 0, 0, 99,108,111,115,117,114,101,110,117,112, 0, 4, 9, 0, 0, 0, 76, - 79, 65, 68, 66, 79, 79, 76, 0, 4, 8, 0, 0, 0, 83, 69, 84, 76, 73, 83, 84, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0,104, 0, 0, 0,104, 0, 0, 0, 0, 0, 0, 2, 1, 0, 0, 0, 30, 0,128, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0,107, 0, 0, 0,110, 0, 0, 0, 1, 6, 0, 10, 13, 0, 0, - 0,132, 1, 0, 0,134, 1, 64, 3,140,129, 1, 1,198,193,128, 0, 9,192, 1, - 3,128, 1,128, 1,204, 65,129, 1,205, 65,192, 3, 1, 66, 0, 0,160, 1, 0, -128, 73,128,192, 4,159, 65,255,127, 30, 0,128, 0, 3, 0, 0, 0, 4, 5, 0, - 0, 0, 84, 89, 80, 69, 0, 3, 0, 0, 0, 0, 0, 0,240, 63, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,113, 0, 0, - 0,118, 0, 0, 0, 2, 3, 0, 5, 14, 0, 0, 0,196, 0, 0, 0, 0, 1, 0, - 1,220,128, 0, 1, 87, 0,192, 1, 22,192, 0,128, 87, 64,192, 1, 22, 64, 0, -128, 23,128,192, 1, 22,192, 0,128, 4, 1,128, 0, 6,193, 64, 2, 12, 1,129, - 0, 9,128, 0, 2, 30, 0,128, 0, 4, 0, 0, 0, 4, 7, 0, 0, 0,110,117, -109, 98,101,114, 0, 4, 7, 0, 0, 0,115,116,114,105,110,103, 0, 4, 6, 0, - 0, 0,116, 97, 98,108,101, 0, 4, 5, 0, 0, 0, 84, 89, 80, 69, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,121, 0, - 0, 0,129, 0, 0, 0, 2, 5, 0, 9, 26, 0, 0, 0, 68, 1, 0, 0,128, 1, -128, 1, 92,129, 0, 1, 87, 0,192, 2, 22, 64, 0,128, 23, 64,192, 2, 22,192, - 0,128,132, 1,128, 0,134,129, 64, 3,140,129, 1, 1, 9,192, 0, 3, 25, 0, -129,129, 22,192, 2,128,134, 1,129, 0,196, 1, 0, 0, 0, 2, 0, 3,220,129, - 0, 1, 87, 0,193, 3, 22, 64, 0,128, 23, 64,193, 3, 22,192, 0,128, 4, 2, -128, 0, 6,130, 65, 4, 12, 2, 2, 1, 9,128, 1, 4, 30, 0,128, 0, 7, 0, - 0, 0, 4, 6, 0, 0, 0,116, 97, 98,108,101, 0, 4, 9, 0, 0, 0,117,115, -101,114,100, 97,116, 97, 0, 4, 5, 0, 0, 0, 84, 89, 80, 69, 0, 3, 0, 0, - 0, 0, 0, 0, 0, 0, 4, 7, 0, 0, 0,110,117,109, 98,101,114, 0, 4, 7, - 0, 0, 0,115,116,114,105,110,103, 0, 4, 8, 0, 0, 0, 84, 89, 80, 69, 75, - 69, 89, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0,132, 0, 0, 0,150, 0, 0, 0, 4, 3, 0, 8, 55, 0, 0, 0, 23, - 0, 64, 1, 22, 64, 0,128,195, 0,128, 1,222, 0, 0, 1,196, 0, 0, 0, 0, - 1,128, 0,220,128, 0, 1, 23, 64,192, 1, 22,128, 1,128,196, 0,128, 0, 0, - 1,128, 0, 64, 1, 0, 1,220,128,128, 1, 87, 0,192, 1, 22, 0, 0,128,222, - 0, 0, 1,196, 0, 0, 1, 0, 1,128, 0,220,128, 0, 1, 4, 1, 0, 0, 64, - 1,128, 1, 28,129, 0, 1, 23, 64, 64, 2, 22,192, 3,128, 4, 1,128, 0, 64, - 1,128, 1,129,129, 0, 0, 28,129,128, 1, 68, 1, 0, 0,128, 1, 0, 2, 92, -129, 0, 1, 23, 64,192, 2, 22,128, 1,128, 68, 1,128, 0,128, 1, 0, 2,192, - 1, 0, 1, 92,129,128, 1, 87, 0,192, 2, 22, 0, 0,128, 94, 1, 0, 1, 6, -193, 64, 0, 6, 65, 0, 2, 23, 0, 64, 2, 22, 0, 2,128, 68, 1, 0, 0,128, - 1,128, 0, 92,129, 0, 1, 23, 64,192, 2, 22,192, 0,128, 68, 1,128, 1,128, - 1,128, 0, 92,129, 0, 1, 0, 1,128, 2, 30, 1, 0, 1, 30, 0,128, 0, 4, - 0, 0, 0, 0, 4, 6, 0, 0, 0,116, 97, 98,108,101, 0, 4, 8, 0, 0, 0, - 95, 95,105,110,100,101,120, 0, 4, 9, 0, 0, 0,116, 97, 98,108,101,118, 97, -108, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0,153, 0, 0, 0,161, 0, 0, 0, 1, 4, 0, 9, 23, 0, 0, 0, 6, 1, - 64, 0, 82, 1, 0, 1, 6, 65, 1, 2, 23, 64, 64, 2, 22, 0, 4,128, 4, 1, - 0, 0, 70,129, 64, 0,141,193, 64, 1, 28, 1,129, 1, 23,192,128, 2, 22,128, - 2,128, 87, 0, 65, 2, 22, 64, 1,128, 87, 64, 65, 2, 22,192, 0,128, 23,128, - 65, 2, 22, 0, 1,128, 23,192, 0, 3, 22,128, 0,128,194, 1,128, 0, 6,194, -128, 0,222, 1,128, 1, 30, 0,128, 0, 7, 0, 0, 0, 4, 5, 0, 0, 0,108, -105,118,101, 0, 0, 4, 5, 0, 0, 0,102,117,110, 99, 0, 3, 0, 0, 0, 0, - 0, 0,240, 63, 4, 6, 0, 0, 0, 76, 79, 65, 68, 75, 0, 4, 9, 0, 0, 0, - 76, 79, 65, 68, 66, 79, 79, 76, 0, 4, 8, 0, 0, 0, 76, 79, 65, 68, 78, 73, - 76, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0,164, 0, 0, 0,183, 0, 0, 0, 2, 7, 0, 12, 47, 0, 0, 0,198, 1, -129, 0, 6, 66,129, 0, 23, 0,192, 3, 22, 64, 0,128,192, 1, 0, 4, 22,128, - 0,128, 23, 0, 64, 4, 22, 0, 0,128, 0, 2,128, 3, 68, 2, 0, 0,128, 2, -128, 3, 92,130, 0, 1,132, 2, 0, 0,192, 2, 0, 4,156,130, 0, 1, 23,128, -130, 4, 22,192, 4,128, 23, 64,192, 4, 22,128, 2,128, 87,128, 64, 3, 22, 64, - 1,128,208,194,192, 3, 23, 0,193, 5, 22,128, 0,128,208,194, 64, 4, 87, 0, -193, 5, 22, 64, 0,128,193, 65, 1, 0, 22, 0, 0,128,193,193, 0, 0, 87, 0, -192, 3, 22, 0, 2,128,196, 2,128, 0,198,130,193, 5,204,194, 2, 1, 9,192, -129, 5, 22,192, 0,128,196, 2,128, 0,198,130,193, 5,204,194, 2, 1, 9,192, -193, 5, 87, 0, 66, 3, 22,128, 0,128, 87, 64, 66, 3, 22, 0, 0,128, 73,192, -129, 1, 30, 0,128, 0, 10, 0, 0, 0, 0, 4, 7, 0, 0, 0,110,117,109, 98, -101,114, 0, 4, 4, 0, 0, 0, 68, 73, 86, 0, 3, 0, 0, 0, 0, 0, 0,240, - 63, 3, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0,224, 63, 4, - 5, 0, 0, 0, 84, 89, 80, 69, 0, 1, 0, 4, 3, 0, 0, 0, 76, 84, 0, 4, - 3, 0, 0, 0, 76, 69, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0,186, 0, 0, 0,194, 0, 0, 0, 2, 6, 0, 11, 22, - 0, 0, 0,132, 1, 0, 0,192, 1, 0, 0, 0, 2,128, 0, 64, 2, 0, 1,128, - 2, 0, 2,156,193,128, 2,218, 1, 0, 0, 22,128, 2,128, 23, 0,129, 1, 22, - 0, 2,128, 4, 2,128, 0, 6, 2, 64, 4, 12, 2, 2, 1, 9, 64, 64, 4, 23, -128,192, 2, 22,128, 0,128, 6,194, 64, 0, 76, 2, 65, 1, 9, 66,193, 4, 6, - 2,129, 0, 73, 0,130, 1, 30, 0,128, 0, 6, 0, 0, 0, 4, 8, 0, 0, 0, - 67, 79, 77, 66, 73, 78, 69, 0, 1, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 4, - 5, 0, 0, 0,108,105,118,101, 0, 3, 0, 0, 0, 0, 0, 0,240, 63, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,198, - 0, 0, 0,200, 0, 0, 0, 0, 6, 0, 7, 3, 0, 0, 0,134, 1,129, 0, 73, -128,129, 1, 30, 0,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,202, 0, 0, 0,204, 0, 0, 0, 1, - 6, 0, 9, 6, 0, 0, 0,132, 1, 0, 0,198, 1, 64, 0, 0, 2, 0, 2,156, -129,128, 1, 73,128,129, 1, 30, 0,128, 0, 1, 0, 0, 0, 4, 5, 0, 0, 0, -102,117,110, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0,206, 0, 0, 0,208, 0, 0, 0, 0, 6, 0, 7, 6, 0, 0, - 0, 87, 0, 64, 2, 22, 0, 0,128,130, 65, 0, 0,130, 1,128, 0, 73,128,129, - 1, 30, 0,128, 0, 1, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0,240, 63, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,210, 0, - 0, 0,212, 0, 0, 0, 0, 6, 0, 10, 7, 0, 0, 0,128, 1,128, 1,192, 1, - 0, 2, 1, 2, 0, 0,160, 1, 0,128, 73, 64,192, 4,159, 65,255,127, 30, 0, -128, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0,240, 63, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,214, 0, 0, 0, -216, 0, 0, 0, 1, 6, 0, 9, 7, 0, 0, 0,132, 1, 0, 0,134, 1, 64, 3, -198, 65, 64, 0, 0, 2, 0, 2,156,129,128, 1, 73,128,129, 1, 30, 0,128, 0, - 2, 0, 0, 0, 4, 8, 0, 0, 0,117,112,118, 97,108,117,101, 0, 4, 5, 0, - 0, 0,102,117,110, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0,218, 0, 0, 0,220, 0, 0, 0, 2, 6, 0, 12, 11, - 0, 0, 0,132, 1, 0, 0,192, 1, 0, 0, 6, 2, 64, 0, 6, 66, 64, 4, 68, - 2,128, 0,134,130, 64, 0,192, 2, 0, 2, 92, 2,128, 1,156,129, 0, 0, 73, -128,129, 1, 30, 0,128, 0, 3, 0, 0, 0, 4, 6, 0, 0, 0,115,116, 97,116, -115, 0, 4, 4, 0, 0, 0,101,110,118, 0, 4, 5, 0, 0, 0,102,117,110, 99, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0,222, 0, 0, 0,226, 0, 0, 0, 2, 6, 0, 13, 15, 0, 0, 0,134, 1,129, - 0,196, 1, 0, 0, 0, 2, 0, 0, 64, 2,128, 0,128, 2, 0, 1,192, 2, 0, - 3, 0, 3,128, 2,220, 65, 0, 3,196, 1,128, 0, 0, 2, 0, 0, 64, 2, 0, - 3,134, 66,129, 0,220,129, 0, 2, 73,192,129, 1, 30, 0,128, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0,232, 0, 0, 0,239, 0, 0, 0, 2, 6, 0, 13, 24, 0, 0, 0,134,193,128, - 0,196, 1, 0, 0, 0, 2, 0, 0, 64, 2,128, 0,128, 2, 0, 1,192, 2, 0, - 3, 0, 3, 0, 2,220, 65, 0, 3,196, 1,128, 0, 0, 2, 0, 3,220,129, 0, - 1, 87, 0,192, 3, 22, 0, 1,128,196, 1,128, 0, 0, 2, 0, 3,220,129, 0, - 1, 23, 64,192, 3, 22, 0, 1,128,198, 65,129, 0, 87,128,192, 3, 22, 64, 0, -128, 6,194, 64, 0, 9,194, 1, 3, 30, 0,128, 0, 4, 0, 0, 0, 4, 6, 0, - 0, 0,116, 97, 98,108,101, 0, 4, 9, 0, 0, 0,117,115,101,114,100, 97,116, - 97, 0, 0, 4, 9, 0, 0, 0,116, 97, 98,108,101,118, 97,108, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,241, 0, 0, - 0,243, 0, 0, 0, 0, 6, 0, 7, 3, 0, 0, 0,138, 1, 0, 0, 73,128,129, - 1, 30, 0,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0,245, 0, 0, 0,250, 0, 0, 0, 2, 6, 0, - 13, 17, 0, 0, 0,134, 1,129, 0,196, 1, 0, 0, 0, 2, 0, 0, 64, 2,128, - 0,128, 2, 0, 1,192, 2, 0, 3, 0, 3,128, 2,220, 65, 0, 3,204, 1,192, - 1, 73,128,129, 3,196, 1,128, 0, 0, 2, 0, 0, 64, 2, 0, 3,134, 66,129, - 0,220,129, 0, 2, 73,192,129, 1, 30, 0,128, 0, 1, 0, 0, 0, 3, 0, 0, - 0, 0, 0, 0,240, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0,255, 0, 0, 0, 1, 1, 0, 0, 1, 6, 0, 14, 11, 0, - 0, 0,132, 1, 0, 0,192, 1, 0, 0, 0, 2,128, 0, 64, 2, 0, 1,128, 2, -128, 1,192, 2, 0, 2, 0, 3, 0, 2, 65, 3, 0, 0,157, 1, 0, 4,158, 1, - 0, 0, 30, 0,128, 0, 1, 0, 0, 0, 4, 4, 0, 0, 0, 85, 78, 77, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, - 1, 0, 0, 5, 1, 0, 0, 0, 6, 0, 6, 2, 0, 0, 0, 73, 0,192, 1, 30, - 0,128, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 1, 0, 0, 10, 1, 0, 0, 1, 6, 0, - 10, 7, 0, 0, 0,132, 1, 0, 0,192, 1, 0, 0, 0, 2, 0, 1, 70, 2,129, - 0,156, 65, 0, 2, 73, 0,192, 1, 30, 0,128, 0, 1, 0, 0, 0, 3, 0, 0, - 0, 0, 0, 0,240, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 12, 1, 0, 0, 31, 1, 0, 0, 2, 6, 0, 16, 44, 0, - 0, 0,198, 1,129, 0, 12, 2, 64, 2, 64, 2,128, 2,129, 2, 0, 0, 32, 2, - 4,128, 6,195,130, 0, 23, 64,192, 3, 22, 64, 0,128,192, 1, 0, 6, 22,192, - 2,128, 87, 64, 64, 6, 22, 64, 2,128, 68, 3, 0, 0,128, 3,128, 3, 92,131, - 0, 1,132, 3, 0, 0,192, 3, 0, 6,156,131, 0, 1, 87,128,131, 6, 22, 64, - 0,128,130, 1,128, 0, 22, 0, 0,128, 31, 66,251,127, 23, 64,192, 3, 22, 64, - 0,128,193,129, 0, 0, 22,128, 3,128, 4, 2,128, 0, 6,194, 64, 4, 12, 2, - 2, 1,154, 65, 0, 0, 22, 64, 0,128, 91, 66,128, 3, 22, 0, 0,128, 66, 2, - 0, 0, 9, 64, 2, 4, 4, 2, 0, 0, 64, 2,128, 3, 28,130, 0, 1, 23, 0, - 65, 4, 22, 0, 0,128,193,129, 0, 0, 73,192,129, 1, 30, 0,128, 0, 5, 0, - 0, 0, 3, 0, 0, 0, 0, 0, 0,240, 63, 0, 4, 1, 0, 0, 0, 0, 4, 5, - 0, 0, 0, 84, 89, 80, 69, 0, 4, 7, 0, 0, 0,110,117,109, 98,101,114, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 33, 1, 0, 0, 39, 1, 0, 0, 1, 6, 0, 8, 16, 0, 0, 0, 25, 0, 1,128, - 22, 0, 3,128,140, 1, 1, 1,198, 65, 64, 0,198,129,129, 3,218, 65, 0, 0, - 22, 64, 0,128,141,129, 64, 3, 22, 64,254,127, 23,128, 0, 3, 22,192, 0,128, -196, 1, 0, 0,198,193,192, 3,204,193, 1, 1, 9, 0,193, 3, 30, 0,128, 0, - 5, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 4, 5, 0, 0, 0,108,105, -118,101, 0, 3, 0, 0, 0, 0, 0, 0,240, 63, 4, 8, 0, 0, 0, 67, 79, 77, - 66, 73, 78, 69, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 41, 1, 0, 0, 43, 1, 0, 0, 1, 6, 0, 10, 13, - 0, 0, 0, 25, 0, 1,128, 22, 64, 2,128, 25, 64, 1,128, 22,192, 1,128,132, - 1, 0, 0,192, 1, 0, 0, 0, 2, 0, 1, 70, 2,129, 0, 90, 66, 0, 0, 22, - 0, 0,128, 70, 66,129, 0,156, 65, 0, 2, 30, 0,128, 0, 1, 0, 0, 0, 3, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 45, 1, 0, 0, 47, 1, 0, 0, 1, 6, 0, 13, - 10, 0, 0, 0,132, 1, 0, 0,192, 1, 0, 0, 0, 2,128, 0, 64, 2, 0, 1, -128, 2,128, 1,192, 2,128, 1, 0, 3,128, 2,157, 1,128, 3,158, 1, 0, 0, - 30, 0,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 51, 1, 0, 0, 53, 1, 0, 0, 1, 6, 0, 13, - 9, 0, 0, 0,132, 1, 0, 0,192, 1, 0, 0, 0, 2,128, 0, 64, 2, 0, 1, -128, 2,128, 1,205, 2, 64, 2, 13, 3,192, 2,156, 65,128, 3, 30, 0,128, 0, - 1, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0,240, 63, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 1, 0, 0, 57, 1, 0, - 0, 1, 6, 0, 13, 9, 0, 0, 0,132, 1, 0, 0,192, 1, 0, 0, 0, 2,128, - 0, 64, 2, 0, 1,128, 2,128, 1,205, 2, 64, 2, 1, 67, 0, 0,156, 65,128, - 3, 30, 0,128, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0,240, 63, 3, 0, - 0, 0, 0, 0, 0,240,191, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 59, 1, 0, 0, 63, 1, 0, 0, 2, 6, 0, 11, 16, - 0, 0, 0, 23, 0, 64, 2, 22, 0, 3,128,132, 1, 0, 0,192, 1, 0, 0, 0, - 2,128, 0, 64, 2, 0, 1,128, 2,128, 1,156,129,128, 2,154, 1, 0, 0, 22, - 0, 1,128,141, 65, 64, 1,196, 1,128, 0,198,129,192, 3,140,193, 1, 3, 9, -192, 64, 3, 30, 0,128, 0, 4, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 64, - 3, 0, 0, 0, 0, 0, 0,240, 63, 4, 8, 0, 0, 0, 67, 79, 77, 66, 73, 78, - 69, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 67, 1, 0, 0, 81, 1, 0, 0, 3, 6, 0, 15, 55, 0, 0, 0, -132, 1, 0, 0,192, 1, 0, 0, 0, 2,128, 0, 64, 2, 0, 1,140, 2,192, 1, -156,193,128, 2, 4, 2,128, 0, 64, 2,128, 3, 28,130, 0, 1, 23, 64, 64, 4, - 22,192, 0,128, 4, 2, 0, 1, 6,130, 64, 4, 12, 2, 2, 1, 9,192, 1, 4, - 6,194,128, 0, 76, 2,192, 1, 70, 66,130, 0,132, 2,128, 0,192, 2, 0, 4, -156,130, 0, 1,196, 2,128, 0, 0, 3,128, 4,220,130, 0, 1, 23, 64, 64, 5, - 22,128, 0,128, 16,195, 64, 4, 23, 0, 65, 6, 22, 0, 1,128, 23, 64,192, 5, - 22, 64, 1,128, 16,195,192, 4, 87, 0, 65, 6, 22,128, 0,128, 1, 67, 1, 0, - 26, 67, 0, 0, 22, 0, 0,128, 1,195, 0, 0, 76,131,193, 1, 73, 0,131, 6, - 23, 64, 64, 5, 22,192, 2,128, 23, 64,192, 5, 22, 64, 2,128, 68, 3,128, 0, -140,195,192, 1,134,131,131, 0, 92,131, 0, 1, 23, 64,192, 6, 22,192, 0,128, - 68, 3, 0, 1, 70,195,193, 6, 76, 67, 3, 1, 9, 0,131, 6, 30, 0,128, 0, - 8, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 64, 4, 7, 0, 0, 0,110,117, -109, 98,101,114, 0, 4, 11, 0, 0, 0, 70, 79, 82, 95, 83, 84, 69, 80, 95, 75, - 0, 3, 0, 0, 0, 0, 0, 0,240, 63, 3, 0, 0, 0, 0, 0, 0, 0, 0, 3, - 0, 0, 0, 0, 0, 0,224, 63, 3, 0, 0, 0, 0, 0, 0, 8, 64, 4, 5, 0, - 0, 0, 84, 89, 80, 69, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 85, 1, 0, 0, 87, 1, 0, 0, 1, 6, 0, 8, 6, - 0, 0, 0,132, 1, 0, 0,134, 1, 64, 3,140,129, 1, 1,198,193,128, 0, 9, -192, 1, 3, 30, 0,128, 0, 1, 0, 0, 0, 4, 5, 0, 0, 0, 84, 89, 80, 69, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 89, 1, 0, 0, 94, 1, 0, 0, 1, 6, 0, 9, 11, 0, 0, 0,134,193,128, - 0,196, 1, 0, 0, 0, 2, 0, 3,220,129, 0, 1, 23, 0,192, 3, 22,192, 0, -128,198, 65, 64, 0, 12,130,192, 1, 6, 2,130, 0,201, 1, 2, 3, 30, 0,128, - 0, 3, 0, 0, 0, 4, 6, 0, 0, 0,116, 97, 98,108,101, 0, 4, 9, 0, 0, - 0,116, 97, 98,108,101,118, 97,108, 0, 3, 0, 0, 0, 0, 0, 0,240, 63, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 98, - 1, 0, 0,110, 1, 0, 0, 3, 6, 0, 14, 24, 0, 0, 0,132, 1, 0, 0, 73, -128,129, 1,134, 1, 64, 0,154, 1, 0, 0, 22, 64, 4,128,132, 1,128, 0,134, - 65, 64, 3,198,129, 64, 0, 0, 2, 0, 2,156,129,128, 1,204,193, 64, 1, 12, -130, 1, 1, 65,194, 0, 0,224,193, 1,128,196, 2, 0, 1, 6,131, 64, 0, 64, - 3, 0, 5,220,130,128, 1, 23, 0,193, 5, 22, 64, 0,128, 9, 64, 65,128, 30, - 0,128, 0,223,129,253,127, 30, 0,128, 0, 6, 0, 0, 0, 4, 8, 0, 0, 0, -110,111, 99,108,111,115,101, 0, 4, 11, 0, 0, 0, 99,108,111,115,117,114,101, -110,117,112, 0, 4, 5, 0, 0, 0,102,117,110, 99, 0, 3, 0, 0, 0, 0, 0, - 0,240, 63, 4, 5, 0, 0, 0, 77, 79, 86, 69, 0, 1, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,112, 1, 0, 0,115, - 1, 0, 0, 0, 6, 0, 13, 13, 0, 0, 0,134, 1, 64, 0,134, 65, 64, 3,193, -129, 0, 0, 0, 2, 0, 2, 65,130, 0, 0,224, 1, 1,128,204,130,130, 1,205, -130,192, 5, 12,131, 2, 3, 6, 3, 3, 0, 73, 0,131, 5,223, 65,254,127, 30, - 0,128, 0, 3, 0, 0, 0, 4, 6, 0, 0, 0,115,116, 97,116,115, 0, 4, 7, - 0, 0, 0,112, 97,114, 97,109,115, 0, 3, 0, 0, 0, 0, 0, 0,240, 63, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,119, - 1, 0, 0,172, 1, 0, 0, 9, 1, 0, 22,115, 0, 0, 0, 70, 0, 64, 0, 90, - 0, 0, 0, 22, 0, 0,128, 30, 0,128, 0, 70, 64, 64, 0,132, 0, 0, 0,134, -128, 64, 1,192, 0,128, 0,156,128, 0, 1,154, 64, 0, 0, 22,192, 0,128,196, - 0, 0, 0,198,192,192, 1,198, 0,193, 1,222, 0, 0, 1,198, 64, 65, 1, 4, - 1,128, 0, 6, 65, 65, 2, 88,192, 0, 2, 22,192, 4,128,198,128, 65, 1, 4, - 1,128, 0, 6,129, 65, 2, 88,192, 0, 2, 22,128, 3,128,198,192, 65, 1, 4, - 1,128, 0, 6,193, 65, 2, 88,192, 0, 2, 22, 64, 2,128,198, 0, 66, 1, 4, - 1,128, 0, 6, 1, 66, 2, 88,192, 0, 2, 22, 0, 1,128,198, 64, 66, 1, 4, - 1,128, 0, 6, 65, 66, 2, 24,192, 0, 2, 22,192, 0,128,196, 0, 0, 0,198, -192,192, 1,198,128,194, 1,222, 0, 0, 1,196, 0, 0, 1, 0, 1,128, 0,220, -128, 0, 1, 9, 0,195,133, 9,128, 0,129, 9,192,128,134, 10, 65, 0, 0, 70, -193, 67, 1,132, 1,128, 1, 9,129,129, 2, 9, 0, 1,135, 10, 1, 0, 0, 65, - 1, 4, 0,134,193, 65, 1,193, 1, 4, 0, 96,129, 0,128, 77, 2, 68, 4,134, - 2, 2, 0, 9,129,130, 4, 95,193,254,127, 65, 65, 4, 0,129,129, 4, 0,193, - 65, 4, 0, 96,193, 1,128, 68, 2, 0, 2,128, 2,128, 0,192, 2, 0, 4, 92, -194,128, 1,154, 66, 0, 0, 22, 0, 0,128, 22, 64, 0,128, 9, 65, 2, 4, 95, -129,253,127, 65, 1, 4, 0,134, 65, 65, 1,193, 1, 4, 0, 96, 65, 5,128, 70, - 2,130, 1, 90, 2, 0, 0, 22,128, 3,128, 68, 2,128, 2,128, 2,128, 0,192, - 2, 0, 4, 92,130,129, 1,132, 3, 0, 3,134, 67, 2, 7,192, 3, 0, 0, 0, - 4, 0, 2, 64, 4, 0, 4,128, 4, 0, 5,192, 4,128, 5, 0, 5, 0, 6, 64, - 5,128, 4,156, 67, 0, 4, 22,192, 0,128, 68, 2,128, 3, 70,194,196, 4, 76, - 66, 2, 4, 9, 0,197, 4, 95, 1,250,127, 70,193, 66, 0, 90, 1, 0, 0, 22, -128, 0,128, 68, 1, 0, 4, 70, 65,197, 2, 9, 0,195, 2, 9,128,197,133, 9, -128, 69,129, 9,128,197,134, 9,128, 69,135, 30, 0,128, 0, 23, 0, 0, 0, 4, - 6, 0, 0, 0,100,101,111,112,116, 0, 4, 5, 0, 0, 0,102,117,110, 99, 0, - 4, 6, 0, 0, 0,115,116, 97,116,115, 0, 4, 7, 0, 0, 0,115,116, 97,116, -117,115, 0, 4, 15, 0, 0, 0, 67, 79, 77, 80, 73, 76, 69, 82, 95, 69, 82, 82, - 79, 82, 0, 4, 10, 0, 0, 0, 98,121,116,101, 99,111,100,101,115, 0, 4, 11, - 0, 0, 0,115,116, 97, 99,107,115,108,111,116,115, 0, 4, 7, 0, 0, 0,112, - 97,114, 97,109,115, 0, 4, 7, 0, 0, 0, 99,111,110,115,116,115, 0, 4, 5, - 0, 0, 0,115,117, 98,115, 0, 4, 9, 0, 0, 0, 84, 79, 79, 76, 65, 82, 71, - 69, 0, 4, 8, 0, 0, 0,110,111, 99,108,111,115,101, 0, 1, 1, 4, 5, 0, - 0, 0,108,105,118,101, 0, 4, 9, 0, 0, 0,116, 97, 98,108,101,118, 97,108, - 0, 4, 4, 0, 0, 0,101,110,118, 0, 3, 0, 0, 0, 0, 0, 0,240, 63, 3, - 0, 0, 0, 0, 0, 0,240,191, 3, 0, 0, 0, 0, 0, 0,112,192, 4, 8, 0, - 0, 0, 67, 79, 77, 66, 73, 78, 69, 0, 1, 0, 4, 8, 0, 0, 0, 78, 79, 67, - 76, 79, 83, 69, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0,179, 1, 0, 0,189, 1, 0, 0, 6, 1, 0, 8, 28, 0, - 0, 0, 68, 0, 0, 0, 25, 0,192, 0, 22, 0, 0,128, 30, 0,128, 0, 68, 0, -128, 0,132, 0, 0, 1,192, 0, 0, 0, 92,192,128, 1, 90, 64, 0, 0, 22, 64, - 3,128,197, 64, 0, 0,198,128,192, 1,203,192,192, 1, 65, 1, 1, 0,128, 1, - 0, 1,193, 65, 1, 0,220, 64,128, 2,196, 0,128, 1,198,128,193, 1, 4, 1, - 0, 2,220, 64, 0, 1,195, 0,128, 1,200, 0,128, 2, 22,128, 0,128,154, 0, - 0, 0, 22, 0, 0,128,158, 0, 0, 1, 30, 0,128, 0, 7, 0, 0, 0, 3, 0, - 0, 0, 0, 0, 0, 0, 0, 4, 3, 0, 0, 0,105,111, 0, 4, 7, 0, 0, 0, -115,116,100,101,114,114, 0, 4, 6, 0, 0, 0,119,114,105,116,101, 0, 4, 27, - 0, 0, 0, 10, 69, 82, 82, 79, 82, 58, 32,106,105,116, 46,111,112,116, 32,100, -105,115, 97, 98,108,101,100, 58, 32, 0, 4, 2, 0, 0, 0, 10, 0, 4, 7, 0, - 0, 0, 97,116,116, 97, 99,104, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0,192, 1, 0, 0,203, 1, 0, 0, 1, 1, 0, - 9, 38, 0, 0, 0, 69, 0, 0, 0, 70, 64,192, 0,128, 0, 0, 0,193,128, 0, - 0, 92,192,128, 1, 90, 64, 0, 0, 22, 0, 0,128, 64, 0, 0, 0,193,192, 0, - 0, 0, 1,128, 0, 85, 0,129, 1,196, 0, 0, 0, 5, 1, 1, 0, 64, 1,128, - 0,220,192,128, 1,218, 64, 0, 0, 22, 0, 4,128, 69, 1, 0, 0, 70, 65,193, - 2,128, 1, 0, 2,193,129, 1, 0, 1,194, 1, 0, 92,129, 0, 2, 87, 0,194, - 2, 22,192, 0,128, 69, 65, 2, 0,128, 1, 0, 2,193,129, 2, 0, 92, 65,128, - 1, 65,193, 2, 0,128, 1,128, 0,193, 1, 3, 0, 85,193,129, 2, 94, 1, 0, - 1, 70, 65, 67, 2,128, 1, 0, 1, 92, 65, 0, 1, 30, 0,128, 0, 14, 0, 0, - 0, 4, 7, 0, 0, 0,115,116,114,105,110,103, 0, 4, 6, 0, 0, 0,109, 97, -116, 99,104, 0, 4, 12, 0, 0, 0, 94, 40, 46, 45, 41, 61, 40, 46, 42, 41, 36, - 0, 4, 9, 0, 0, 0,106,105,116, 46,111,112,116, 95, 0, 4, 8, 0, 0, 0, -114,101,113,117,105,114,101, 0, 4, 4, 0, 0, 0,115,117, 98, 0, 3, 0, 0, - 0, 0, 0, 0,240, 63, 3, 0, 0, 0, 0, 0, 0, 28, 64, 4, 8, 0, 0, 0, -109,111,100,117,108,101, 32, 0, 4, 6, 0, 0, 0,101,114,114,111,114, 0, 3, - 0, 0, 0, 0, 0, 0, 0, 0, 4, 25, 0, 0, 0,111,112,116,105,109,105,122, -101,114, 32, 97,100,100, 45,111,110, 32,109,111,100,117,108,101, 32, 0, 4, 11, - 0, 0, 0, 32,110,111,116, 32,102,111,117,110,100, 0, 4, 6, 0, 0, 0,115, -116, 97,114,116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0,206, 1, 0, 0,235, 1, 0, 0, 8, 1, 0, 6, 59, 0, 0, - 0, 68, 0, 0, 0, 90, 64, 0, 0, 22,128, 1,128, 68, 0,128, 0, 70, 0,192, - 0,132, 0, 0, 1,196, 0,128, 1, 92, 64,128, 1, 66, 0,128, 0, 72, 0, 0, - 0, 87, 64, 64, 0, 22, 64, 0,128, 23,128, 64, 0, 22,128, 0,128, 68, 0,128, - 2, 72, 0, 0, 2, 22, 64, 7,128, 69,192, 0, 0,128, 0, 0, 0, 92,128, 0, - 1, 90, 0, 0, 0, 22,128, 2,128, 88, 0,193, 0, 22,128, 0,128,144, 64,193, - 0, 87, 0, 65, 1, 22,192, 0,128,133,128, 1, 0,193,192, 1, 0, 1, 1, 1, - 0,156, 64,128, 1, 72, 0, 0, 2, 22, 64, 3,128,132, 0, 0, 2, 23, 0, 66, - 1, 22, 64, 0,128,132, 0,128, 2,136, 0, 0, 2,132, 0, 0, 3,192, 0, 0, - 0,156,128, 0, 1,154, 0, 0, 0, 22,192, 0,128,197,128, 1, 0, 0, 1, 0, - 1, 65, 1, 1, 0,220, 64,128, 1, 68, 0,128, 3, 90, 64, 0, 0, 22,192, 1, -128, 68, 0, 0, 2, 25, 64,128,132, 22, 0, 1,128, 68, 0, 0, 3,129,128, 2, - 0, 92, 64, 0, 1, 66, 0,128, 0, 72, 0,128, 3, 30, 0,128, 0, 11, 0, 0, - 0, 4, 7, 0, 0, 0, 97,116,116, 97, 99,104, 0, 0, 4, 1, 0, 0, 0, 0, - 4, 9, 0, 0, 0,116,111,110,117,109, 98,101,114, 0, 3, 0, 0, 0, 0, 0, - 0, 0, 0, 3, 0, 0, 0, 0, 0, 0,240, 63, 4, 6, 0, 0, 0,101,114,114, -111,114, 0, 4, 20, 0, 0, 0, 98, 97,100, 32,111,112,116,105,109,105,122,101, -114, 32,108,101,118,101,108, 0, 3, 0, 0, 0, 0, 0, 0,240,191, 3, 0, 0, - 0, 0, 0, 0, 0, 64, 4, 7, 0, 0, 0,105,110,108,105,110,101, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,242, 1, - 0, 0,244, 1, 0, 0, 1, 1, 0, 2, 2, 0, 0, 0, 8, 0, 0, 0, 30, 0, -128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0,246, 1, 0, 0,248, 1, 0, 0, 1, 0, 0, 2, 3, 0, - 0, 0, 4, 0, 0, 0, 30, 0, 0, 1, 30, 0,128, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, -}; diff --git a/src/xrServerEntities/opt_inline.lua.h b/src/xrServerEntities/opt_inline.lua.h deleted file mode 100644 index 1466d013f..000000000 --- a/src/xrServerEntities/opt_inline.lua.h +++ /dev/null @@ -1,372 +0,0 @@ -/* code automatically generated by bin2c -- DO NOT EDIT */ -/* #include'ing this file in a C program is equivalent to calling - if (luaL_loadfile(L,"luac.out")==0) lua_pcall(L, 0, 0, 0); -*/ -/* luac.out */ -static const unsigned char opt_inline_lua_binary[] = { - 27, 76,117, 97, 81, 0, 1, 4, 4, 4, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 2, 31,240, 1, 0, 0, 5, 0, 0, 0, 65, 64, 0, 0, - 28,128, 0, 1, 69,128, 0, 0,134,192, 64, 0, 87, 0, 65, 1, 22, 0, 0,128, -130, 64, 0, 0,130, 0,128, 0,193, 64, 1, 0, 92, 64,128, 1, 69, 0, 0, 0, -129,128, 1, 0, 92,128, 0, 1,133,192, 1, 0,197, 0, 2, 0, 5, 65, 2, 0, - 70,129,194, 0,134,193,194, 0,197, 1, 3, 0,198, 65,195, 3, 5, 2, 3, 0, - 6,130, 67, 4, 69, 2, 3, 0, 70,194,195, 4,134, 2, 68, 0,194, 2,128, 0, - 2, 3,128, 0,156, 66,128, 1,138, 2, 0, 0,197, 66, 4, 0, 10, 3, 0, 0, -100, 3, 0, 0, 0, 0, 0, 6,131, 3, 0, 8,100, 68, 0, 0, 0, 0,128, 1, - 0, 0,128, 7, 0, 0, 0, 6, 0, 0, 0, 7, 0, 0, 0, 8,164,132, 0, 0, - 0, 0, 0, 6, 0, 0, 0, 7, 0, 0, 0, 8,228,196, 0, 0, 36, 5, 1, 0, - 0, 0,128, 0, 0, 0,128, 2, 0, 0,128, 5,100, 69, 1, 0, 0, 0, 0, 1, - 0, 0, 0, 2,131, 5, 0, 11,197,133, 4, 0, 1,196, 4, 0,192, 3,128, 11, -128, 3, 0, 11,128, 5,128, 8,193, 5, 5, 0, 1, 70, 5, 0, 65,134, 5, 0, -164,134, 1, 0, 0, 0,128, 10, 0, 0, 0, 10,156, 69,128, 2,128, 5,128, 8, -193,197, 5, 0, 1, 6, 6, 0, 65,134, 5, 0,164,198, 1, 0, 0, 0, 0, 1, - 0, 0,128, 1, 0, 0, 0, 10,156, 69,128, 2, 3, 4, 0, 8,128, 5,128, 8, -193, 69, 2, 0, 1, 70, 6, 0, 65,134, 6, 0,164, 6, 2, 0, 0, 0,128, 10, -156, 69,128, 2,128, 5,128, 8,193,197, 1, 0, 1,198, 6, 0, 65, 6, 7, 0, -156, 69, 0, 2,128, 5,128, 8,193, 69, 7, 0, 1,134, 5, 0, 65, 6, 7, 0, -156, 69, 0, 2,128, 5,128, 8,193,133, 7, 0, 1, 6, 7, 0, 65,198, 7, 0, -128, 6,128, 9,156, 69,128, 2,128, 5,128, 8,193, 5, 8, 0, 1, 70, 8, 0, - 65, 70, 6, 0,156, 69, 0, 2,128, 5,128, 8,193, 5, 2, 0, 1, 6, 7, 0, - 65,134, 8, 0,164, 70, 2, 0, 0, 0, 0, 1, 0, 0,128, 1,156, 69,128, 2, -128, 5,128, 8,193,197, 8, 0, 1, 6, 7, 0, 65, 6, 9, 0,128, 6,128, 9, -156, 69,128, 2,128, 5,128, 8,193,133, 0, 0, 1, 70, 9, 0, 65,134, 9, 0, -164,134, 2, 0,156, 69,128, 2,128, 5,128, 8,193,197, 9, 0, 1, 6, 10, 0, - 65, 70, 10, 0,156, 69, 0, 2,128, 5,128, 8,193,133, 10, 0, 1,198, 6, 0, - 65, 6, 7, 0,156, 69, 0, 2,128, 5,128, 8,193, 5, 0, 0, 1,134, 5, 0, - 65,198, 6, 0,156, 69, 0, 2,129,197, 10, 0,197,197, 10, 0, 1, 4, 11, 0, -192, 3,128, 11,128, 3, 0, 11,218, 3, 0, 0, 22, 0, 4,128,128, 5,128, 8, -193, 69, 11, 0, 1, 70, 9, 0, 65,134, 11, 0,156, 69, 0, 2,128, 5,128, 8, -193,197, 11, 0, 1, 70, 9, 0, 65, 6, 12, 0,164,198, 2, 0,156, 69,128, 2, - 3, 4, 0, 8,128, 5,128, 8,193, 69, 12, 0, 1,134, 12, 0, 65,198, 12, 0, -156, 69, 0, 2,129, 5, 3, 0,197, 5, 3, 0, 1, 4, 13, 0,192, 3,128, 11, -128, 3, 0, 11,218, 3, 0, 0, 22, 64, 17,128,128, 5,128, 8,193, 69, 13, 0, - 1, 6, 10, 0, 65,198, 6, 0,156, 69, 0, 2,128, 5,128, 8,193, 69, 3, 0, - 1,198, 6, 0, 65,134, 13, 0,156, 69, 0, 2,128, 5,128, 8,193,197, 13, 0, - 1,198, 6, 0, 65, 6, 14, 0,156, 69, 0, 2, 3, 4, 0, 8,128, 5,128, 8, -193, 69, 14, 0, 1, 6, 10, 0, 65,198, 6, 0,164, 6, 3, 0,156, 69,128, 2, -128, 5,128, 8,193,133, 14, 0, 1,198, 6, 0, 65,198, 14, 0,156, 69, 0, 2, -128, 5,128, 8,193, 5, 15, 0, 1,198, 6, 0, 65,198, 6, 0,156, 69, 0, 2, -128, 5,128, 8,193, 69, 15, 0, 1,198, 6, 0, 65,198, 6, 0,156, 69, 0, 2, -128, 5,128, 8,193,133, 15, 0, 1,198, 6, 0, 65,198, 6, 0,156, 69, 0, 2, -128, 5,128, 8,193,197, 15, 0, 1,198, 6, 0, 65, 6, 16, 0,156, 69, 0, 2, -128, 5,128, 8,193, 69, 16, 0, 1, 70, 9, 0, 65,134, 16, 0,164, 70, 3, 0, -156, 69,128, 2,128, 5,128, 8,193,133, 3, 0, 1, 70, 9, 0, 65,198, 16, 0, -164,134, 3, 0,156, 69,128, 2,128, 5,128, 8,193,197, 3, 0, 1,198, 14, 0, - 65, 6, 17, 0,156, 69, 0, 2,128, 5,128, 8,193, 69, 17, 0, 1,134, 17, 0, - 65,198, 17, 0,164,198, 3, 0,156, 69,128, 2,129, 5, 18, 0,197, 5, 18, 0, - 1, 68, 18, 0,192, 3,128, 11,128, 3, 0, 11,218, 3, 0, 0, 22,192, 5,128, -128, 5,128, 8,193,133, 18, 0, 1,198, 18, 0, 65, 6, 19, 0,156, 69, 0, 2, -128, 5,128, 8,193, 69, 19, 0, 1, 6, 7, 0, 65,134, 5, 0,164, 6, 4, 0, - 0, 0, 0, 1, 0, 0,128, 1,156, 69,128, 2,128, 5,128, 8,193,133, 19, 0, - 1, 6, 10, 0, 65,134, 5, 0,156, 69, 0, 2, 3, 4, 0, 8,128, 5,128, 8, -193,197, 19, 0, 1,198, 6, 0, 65, 6, 20, 0,156, 69, 0, 2,129, 69, 20, 0, -197, 69, 20, 0, 1,132, 20, 0,192, 3,128, 11,128, 3, 0, 11,218, 3, 0, 0, - 22,128, 36,128,128, 5,128, 8,193,197, 20, 0, 1, 6, 21, 0, 65, 6, 21, 0, -156, 69, 0, 2,128, 5,128, 8,193, 69, 21, 0, 1, 6, 21, 0, 65, 6, 21, 0, -156, 69, 0, 2,128, 5,128, 8,193,133, 21, 0, 1, 6, 21, 0, 65, 6, 21, 0, -156, 69, 0, 2,128, 5,128, 8,193,197, 21, 0, 1, 6, 21, 0, 65, 6, 21, 0, -156, 69, 0, 2,128, 5,128, 8,193, 5, 22, 0, 1, 6, 21, 0, 65, 6, 21, 0, -156, 69, 0, 2,128, 5,128, 8,193, 69, 22, 0, 1, 6, 21, 0, 65, 6, 21, 0, -156, 69, 0, 2,128, 5,128, 8,193,133, 22, 0, 1, 6, 21, 0, 65, 6, 21, 0, -156, 69, 0, 2,128, 5,128, 8,193,197, 22, 0, 1, 6, 21, 0, 65, 6, 21, 0, -156, 69, 0, 2,128, 5,128, 8,193, 5, 23, 0, 1, 6, 21, 0, 65, 6, 21, 0, -156, 69, 0, 2,128, 5,128, 8,193, 69, 23, 0, 1, 6, 21, 0, 65, 6, 21, 0, -156, 69, 0, 2,128, 5,128, 8,193,133, 23, 0, 1, 6, 21, 0, 65, 6, 21, 0, -156, 69, 0, 2,128, 5,128, 8,193,197, 23, 0, 1, 6, 21, 0, 65, 6, 21, 0, -156, 69, 0, 2,128, 5,128, 8,193, 5, 24, 0, 1, 6, 10, 0, 65, 6, 21, 0, -156, 69, 0, 2,128, 5,128, 8,193, 69, 24, 0, 1, 6, 10, 0, 65, 6, 21, 0, -156, 69, 0, 2,128, 5,128, 8,193,133, 24, 0, 1, 6, 7, 0, 65, 6, 21, 0, -128, 6,128, 9,156, 69,128, 2,128, 5,128, 8,193,197, 24, 0, 1, 6, 21, 0, - 65, 6, 21, 0,156, 69, 0, 2,128, 5,128, 8,193, 5, 25, 0, 1, 6, 7, 0, - 65, 70, 25, 0,164, 70, 4, 0,156, 69,128, 2,128, 5,128, 8,193,133, 25, 0, - 1, 6, 21, 0, 65, 70, 25, 0,156, 69, 0, 2, 3, 4, 0, 8,128, 5,128, 8, -193,197, 25, 0, 1, 6, 7, 0, 65, 6, 26, 0,128, 6,128, 9,156, 69,128, 2, -128, 5,128, 8,193, 69, 26, 0, 1, 6, 7, 0, 65, 6, 26, 0,128, 6,128, 9, -156, 69,128, 2,128, 5,128, 8,193,133, 26, 0, 1, 6, 21, 0, 65, 6, 21, 0, -156, 69, 0, 2,128, 5,128, 8,193,197, 26, 0, 1, 6, 21, 0, 65, 6, 21, 0, -156, 69, 0, 2,128, 5,128, 8,193, 5, 27, 0, 1, 70, 27, 0, 65, 6, 21, 0, -156, 69, 0, 2,128, 5,128, 8,193,133, 27, 0, 1,198, 27, 0, 65, 6, 21, 0, -156, 69, 0, 2,128, 5,128, 8,193, 5, 28, 0, 1, 6, 21, 0, 65, 70, 25, 0, -156, 69, 0, 2,128, 5,128, 8,193, 69, 28, 0, 1, 6, 7, 0, 65,198, 27, 0, -128, 6,128, 9,156, 69,128, 2,128, 5,128, 8,193,133, 28, 0, 1,198, 18, 0, - 65, 6, 10, 0,156, 69, 0, 2,128, 5,128, 8,193,197, 28, 0, 1, 6, 21, 0, - 65, 6, 29, 0,164,134, 4, 0,156, 69,128, 2,129, 69, 29, 0,197, 69, 29, 0, - 3, 4, 0, 8,192, 3,128, 11,128, 3, 0, 11,218, 3, 0, 0, 22, 64, 2,128, -128, 5,128, 8,193,133, 29, 0, 1,198, 29, 0, 65, 6, 30, 0,156, 69, 0, 2, -128, 5,128, 8,193, 69, 30, 0, 1,198, 6, 0, 65,198, 18, 0,156, 69, 0, 2, -138, 5, 2, 0,137,197, 94,189,137, 69, 95,190,137,197, 95,191,137, 5, 96,134, -137, 69, 96,164,137,197, 96,193,137, 69, 97,194,137,197, 97,195,202, 69, 2, 0, -201, 5,226,144,201, 69,226,141,201,133, 98,139,201,197,226,153,201, 69, 99,198, -201,197, 99,199,201, 5,100,170,201, 5,100,148,201,133,228,200, 10,198, 1, 0, - 9,198,228,144, 9,198,210,141, 74, 6, 0, 0, 9, 70, 6,139, 9, 6,101,170, - 9, 70,101,148,100,198, 4, 0, 9, 70, 6,203, 69, 70, 4, 0, 9, 70, 6,153, -100, 6, 5, 0, 0, 0,128, 4, 0, 0,128, 11,164, 70, 5, 0, 0, 0, 0, 11, - 0, 0, 0, 1, 0, 0, 0, 4, 0, 0,128, 12, 0, 0,128, 3, 0, 0, 0, 12, - 0, 0,128, 2,228,134, 5, 0, 0, 0,128, 2, 0, 0, 0, 1, 0, 0, 0, 6, - 0, 0, 0, 13, 36,199, 5, 0, 0, 0,128, 13, 69,199, 37, 0,165, 7, 0, 0, - 92, 71, 0, 0, 71, 3, 38, 0, 7, 71, 38, 0, 30, 0,128, 0,154, 0, 0, 0, - 4, 8, 0, 0, 0,114,101,113,117,105,114,101, 0, 4, 4, 0, 0, 0,106,105, -116, 0, 4, 7, 0, 0, 0, 97,115,115,101,114,116, 0, 4, 12, 0, 0, 0,118, -101,114,115,105,111,110, 95,110,117,109, 0, 3, 0, 0, 0, 0, 0,188,195, 64, - 4, 37, 0, 0, 0, 76,117, 97, 74, 73, 84, 32, 99,111,114,101, 47,108,105, 98, -114, 97,114,121, 32,118,101,114,115,105,111,110, 32,109,105,115,109, 97,116, 99, -104, 0, 4, 9, 0, 0, 0,106,105,116, 46,117,116,105,108, 0, 4, 5, 0, 0, - 0,116,121,112,101, 0, 4, 7, 0, 0, 0,114, 97,119,103,101,116, 0, 4, 5, - 0, 0, 0,110,101,120,116, 0, 4, 6, 0, 0, 0,104,105,110,116,115, 0, 4, - 7, 0, 0, 0,102,104,105,110,116,115, 0, 4, 7, 0, 0, 0,115,116,114,105, -110,103, 0, 4, 4, 0, 0, 0,115,117, 98, 0, 4, 6, 0, 0, 0,109, 97,116, - 99,104, 0, 4, 5, 0, 0, 0,103,115,117, 98, 0, 4, 4, 0, 0, 0,111,102, -102, 0, 4, 15, 0, 0, 0, 99,111,108,108,101, 99,116,103, 97,114, 98, 97,103, -101, 0, 4, 3, 0, 0, 0, 95, 71, 0, 3, 0, 0, 0, 0, 0, 0,240, 64, 4, - 6, 0, 0, 0,112, 97,105,114,115, 0, 4, 4, 0, 0, 0, 46, 46, 48, 0, 4, - 2, 0, 0, 0, 84, 0, 4, 7, 0, 0, 0,105,112, 97,105,114,115, 0, 4, 4, - 0, 0, 0, 46, 46, 73, 0, 4, 3, 0, 0, 0, 46, 46, 0, 4, 4, 0, 0, 0, - 84, 46, 63, 0, 4, 2, 0, 0, 0, 83, 0, 4, 2, 0, 0, 0, 46, 0, 4, 13, - 0, 0, 0,103,101,116,109,101,116, 97,116, 97, 98,108,101, 0, 4, 13, 0, 0, - 0,115,101,116,109,101,116, 97,116, 97, 98,108,101, 0, 4, 4, 0, 0, 0, 84, - 84, 63, 0, 4, 9, 0, 0, 0,114, 97,119,101,113,117, 97,108, 0, 4, 2, 0, - 0, 0, 66, 0, 4, 3, 0, 0, 0, 84, 46, 0, 4, 7, 0, 0, 0,114, 97,119, -115,101,116, 0, 4, 4, 0, 0, 0, 84, 46, 46, 0, 4, 2, 0, 0, 0, 42, 0, - 4, 4, 0, 0, 0, 46, 46, 42, 0, 4, 9, 0, 0, 0,116,111,110,117,109, 98, -101,114, 0, 4, 2, 0, 0, 0, 73, 0, 4, 4, 0, 0, 0, 46, 73, 63, 0, 4, - 9, 0, 0, 0,116,111,115,116,114,105,110,103, 0, 4, 10, 0, 0, 0, 99,111, -114,111,117,116,105,110,101, 0, 3, 0, 0, 0, 0, 0, 0, 0, 65, 4, 6, 0, - 0, 0,121,105,101,108,100, 0, 4, 3, 0, 0, 0, 46, 42, 0, 4, 7, 0, 0, - 0,114,101,115,117,109,101, 0, 4, 4, 0, 0, 0, 82, 46, 42, 0, 4, 5, 0, - 0, 0,119,114, 97,112, 0, 4, 2, 0, 0, 0, 67, 0, 4, 2, 0, 0, 0, 70, - 0, 3, 0, 0, 0, 0, 0, 0, 8, 65, 4, 4, 0, 0, 0,108,101,110, 0, 4, - 5, 0, 0, 0, 83, 73, 73, 63, 0, 4, 5, 0, 0, 0, 99,104, 97,114, 0, 4, - 3, 0, 0, 0, 73, 42, 0, 4, 5, 0, 0, 0, 98,121,116,101, 0, 4, 4, 0, - 0, 0,114,101,112, 0, 4, 3, 0, 0, 0, 83, 73, 0, 4, 8, 0, 0, 0,114, -101,118,101,114,115,101, 0, 4, 6, 0, 0, 0,117,112,112,101,114, 0, 4, 6, - 0, 0, 0,108,111,119,101,114, 0, 4, 7, 0, 0, 0,102,111,114,109, 97,116, - 0, 4, 4, 0, 0, 0, 83, 46, 42, 0, 4, 5, 0, 0, 0,102,105,110,100, 0, - 4, 7, 0, 0, 0, 83, 83, 73, 63, 46, 63, 0, 4, 5, 0, 0, 0, 83, 83, 73, - 63, 0, 4, 6, 0, 0, 0, 83, 83, 71, 73, 63, 0, 4, 7, 0, 0, 0,103,109, - 97,116, 99,104, 0, 4, 4, 0, 0, 0, 67, 48, 48, 0, 4, 3, 0, 0, 0, 83, - 83, 0, 4, 6, 0, 0, 0,116, 97, 98,108,101, 0, 3, 0, 0, 0, 0, 0, 0, - 16, 65, 4, 7, 0, 0, 0,105,110,115,101,114,116, 0, 4, 1, 0, 0, 0, 0, - 4, 5, 0, 0, 0, 84, 73, 63, 46, 0, 4, 7, 0, 0, 0,114,101,109,111,118, -101, 0, 4, 5, 0, 0, 0,103,101,116,110, 0, 4, 7, 0, 0, 0, 99,111,110, - 99, 97,116, 0, 4, 8, 0, 0, 0, 84, 83, 63, 73, 63, 73, 63, 0, 4, 5, 0, - 0, 0,109, 97,116,104, 0, 3, 0, 0, 0, 0, 0, 0, 20, 65, 4, 4, 0, 0, - 0,108,111,103, 0, 4, 2, 0, 0, 0, 78, 0, 4, 6, 0, 0, 0,108,111,103, - 49, 48, 0, 4, 4, 0, 0, 0,101,120,112, 0, 4, 5, 0, 0, 0,115,105,110, -104, 0, 4, 5, 0, 0, 0, 99,111,115,104, 0, 4, 5, 0, 0, 0,116, 97,110, -104, 0, 4, 5, 0, 0, 0, 97,115,105,110, 0, 4, 5, 0, 0, 0, 97, 99,111, -115, 0, 4, 5, 0, 0, 0, 97,116, 97,110, 0, 4, 4, 0, 0, 0,115,105,110, - 0, 4, 4, 0, 0, 0, 99,111,115, 0, 4, 4, 0, 0, 0,116, 97,110, 0, 4, - 5, 0, 0, 0, 99,101,105,108, 0, 4, 6, 0, 0, 0,102,108,111,111,114, 0, - 4, 4, 0, 0, 0, 97, 98,115, 0, 4, 5, 0, 0, 0,115,113,114,116, 0, 4, - 5, 0, 0, 0,102,109,111,100, 0, 4, 3, 0, 0, 0, 78, 78, 0, 4, 6, 0, - 0, 0, 97,116, 97,110, 50, 0, 4, 4, 0, 0, 0,109,105,110, 0, 4, 4, 0, - 0, 0, 78, 78, 42, 0, 4, 4, 0, 0, 0,109, 97,120, 0, 4, 4, 0, 0, 0, -100,101,103, 0, 4, 4, 0, 0, 0,114, 97,100, 0, 4, 5, 0, 0, 0,109,111, -100,102, 0, 4, 3, 0, 0, 0, 73, 78, 0, 4, 6, 0, 0, 0,102,114,101,120, -112, 0, 4, 3, 0, 0, 0, 78, 73, 0, 4, 4, 0, 0, 0,112,111,119, 0, 4, - 6, 0, 0, 0,108,100,101,120,112, 0, 4, 11, 0, 0, 0,114, 97,110,100,111, -109,115,101,101,100, 0, 4, 7, 0, 0, 0,114, 97,110,100,111,109, 0, 4, 5, - 0, 0, 0, 73, 63, 73, 63, 0, 4, 3, 0, 0, 0,105,111, 0, 4, 6, 0, 0, - 0,108,105,110,101,115, 0, 4, 5, 0, 0, 0, 67, 48, 48, 83, 0, 4, 3, 0, - 0, 0, 83, 63, 0, 4, 5, 0, 0, 0,114,101, 97,100, 0, 4, 4, 0, 0, 0, -110,105,108, 0, 4, 2, 0, 0, 0, 48, 0, 4, 8, 0, 0, 0, 98,111,111,108, -101, 97,110, 0, 4, 2, 0, 0, 0, 98, 0, 4, 7, 0, 0, 0,110,117,109, 98, -101,114, 0, 4, 2, 0, 0, 0,110, 0, 4, 2, 0, 0, 0,115, 0, 4, 2, 0, - 0, 0,116, 0, 4, 9, 0, 0, 0,102,117,110, 99,116,105,111,110, 0, 4, 2, - 0, 0, 0,102, 0, 4, 9, 0, 0, 0,117,115,101,114,100, 97,116, 97, 0, 4, - 2, 0, 0, 0,117, 0, 4, 7, 0, 0, 0,116,104,114,101, 97,100, 0, 4, 2, - 0, 0, 0,114, 0, 4, 5, 0, 0, 0, 91, 98, 48, 93, 0, 4, 5, 0, 0, 0, - 91,115, 48, 93, 0, 4, 5, 0, 0, 0, 91,116, 48, 93, 0, 4, 5, 0, 0, 0, - 91,102, 48, 93, 0, 4, 2, 0, 0, 0, 85, 0, 4, 5, 0, 0, 0, 91,117, 48, - 93, 0, 4, 2, 0, 0, 0, 82, 0, 4, 5, 0, 0, 0, 91,114, 48, 93, 0, 4, - 5, 0, 0, 0, 91,110, 48, 93, 0, 4, 2, 0, 0, 0, 71, 0, 4, 7, 0, 0, - 0, 91,115,116,102, 48, 93, 0, 1, 1, 3, 0, 0, 0, 0, 0, 0,224, 63, 3, - 0, 0, 0, 0, 0, 0,240, 63, 4, 2, 0, 0, 0, 76, 0, 4, 7, 0, 0, 0, -109,111,100,117,108,101, 0, 4, 8, 0, 0, 0,103,101,116,110, 97,109,101, 0, - 4, 6, 0, 0, 0,115,116, 97,114,116, 0, 24, 0, 0, 0, 0, 0, 0, 0, 38, - 0, 0, 0, 52, 0, 0, 0, 1, 2, 0, 8, 24, 0, 0, 0,132, 0, 0, 0,134, - 0, 0, 1,154, 0, 0, 0, 22,192, 2,128,198, 0, 64, 1, 6, 65, 64, 1,218, - 0, 0, 0, 22, 64, 1,128, 64, 1,128, 1,129,129, 0, 0,192, 1, 0, 2, 85, -193,129, 2, 94, 1, 0, 1, 22, 0, 2,128, 30, 1, 0, 1, 22,128, 1,128, 23, -192,192, 0, 22,128, 0,128,193, 0, 1, 0,222, 0, 0, 1, 22, 64, 0,128,193, - 64, 1, 0,222, 0, 0, 1, 30, 0,128, 0, 6, 0, 0, 0, 4, 8, 0, 0, 0, -108,105, 98,110, 97,109,101, 0, 4, 5, 0, 0, 0,110, 97,109,101, 0, 4, 2, - 0, 0, 0, 46, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 4, 10, 0, 0, 0,114, -101, 99,117,114,115,105,118,101, 0, 4, 2, 0, 0, 0, 63, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 58, 0, 0, 0, - 67, 0, 0, 0, 5, 4, 0, 8, 24, 0, 0, 0, 4, 1, 0, 0, 68, 1,128, 0, -128, 1, 0, 0, 28,129,128, 1, 26, 1, 0, 0, 22,128, 2,128, 68, 1, 0, 1, -138,129, 1, 0,196, 1,128, 1,137,193, 1,128,137, 1,128,128,196, 1, 0, 2, -137,193, 1,129,137, 65,128,129,137,129, 0,130,137,193,128,130, 73,129, 1, 2, - 68, 1, 0, 2, 90, 1, 0, 0, 22,128, 0,128, 68, 1, 0, 2, 76,129,193, 2, - 72, 1, 0, 2, 30, 0,128, 0, 7, 0, 0, 0, 4, 8, 0, 0, 0,108,105, 98, -110, 97,109,101, 0, 4, 5, 0, 0, 0,110, 97,109,101, 0, 4, 4, 0, 0, 0, -105,100,120, 0, 4, 8, 0, 0, 0,114,101,115,117,108,116,115, 0, 4, 5, 0, - 0, 0, 97,114,103,115, 0, 4, 8, 0, 0, 0,104, 97,110,100,108,101,114, 0, - 3, 0, 0, 0, 0, 0, 0,240, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 75, 0, 0, 0, 3, 5, 0, - 8, 18, 0, 0, 0, 68, 1, 0, 0,138,129, 1, 0,196, 1,128, 0,137,193, 1, -128,137, 1,128,128,196, 1, 0, 1,137,193, 1,129,137,129,128,129,137,193, 0, -130,137, 1,129,130, 73,129,129, 0, 68, 1, 0, 1, 90, 1, 0, 0, 22,128, 0, -128, 68, 1, 0, 1, 76,129,193, 2, 72, 1, 0, 1, 30, 0,128, 0, 7, 0, 0, - 0, 4, 8, 0, 0, 0,108,105, 98,110, 97,109,101, 0, 4, 5, 0, 0, 0,110, - 97,109,101, 0, 4, 4, 0, 0, 0,105,100,120, 0, 4, 8, 0, 0, 0,114,101, -115,117,108,116,115, 0, 4, 5, 0, 0, 0, 97,114,103,115, 0, 4, 8, 0, 0, - 0,104, 97,110,100,108,101,114, 0, 3, 0, 0, 0, 0, 0, 0,240, 63, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 79, 0, - 0, 0, 81, 0, 0, 0, 0, 6, 0, 7, 4, 0, 0, 0,140, 1,192, 1,134,129, -129, 0, 73,128,129, 1, 30, 0,128, 0, 1, 0, 0, 0, 3, 0, 0, 0, 0, 0, - 0,240, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 96, 0, 0, 0,115, 0, 0, 0, 3, 5, 0, 19, 42, 0, 0, 0, 26, - 1, 0, 0, 22,128, 8,128, 68, 1, 0, 0, 70, 1,192, 2,134, 65, 64, 0,192, - 1,128, 2, 0, 2, 0, 3, 76,130, 64, 1,220, 1,129, 1, 23,192,192, 3, 22, - 64, 6,128,140, 2, 65, 1,140, 66, 2, 5,192, 2,128, 2, 0, 3, 0, 3, 64, - 3, 0, 5,220, 66,129, 1, 23, 64,193, 5, 22, 64, 4,128, 23,192, 0, 6, 22, -192, 3,128, 25, 0, 65, 7, 22, 64, 3,128,192, 3,128, 2, 0, 4, 0, 3, 76, -132, 64, 5,220, 3,129, 1, 23,192,192, 7, 22,192, 1,128,140, 68,132, 4, 23, -128, 65, 9, 22, 0, 1,128,132, 4,128, 0,134,196, 65, 9,140,132, 4, 5, 9, - 0, 1, 9, 30, 0,128, 0, 68, 1, 0, 1, 73, 64,129, 1, 66, 1,128, 0, 94, - 1, 0, 1, 30, 0,128, 0, 8, 0, 0, 0, 4, 9, 0, 0, 0, 98,121,116,101, - 99,111,100,101, 0, 4, 5, 0, 0, 0,102,117,110, 99, 0, 3, 0, 0, 0, 0, - 0, 0,240, 63, 4, 4, 0, 0, 0, 74, 77, 80, 0, 3, 0, 0, 0, 0, 0, 0, - 0, 64, 4, 9, 0, 0, 0, 84, 70, 79, 82, 76, 79, 79, 80, 0, 3, 0, 0, 0, - 0, 0, 0, 0,192, 4, 7, 0, 0, 0, 73, 78, 76, 73, 78, 69, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,118, 0, 0, - 0,126, 0, 0, 0, 2, 4, 0, 9, 24, 0, 0, 0, 12, 1, 64, 1, 6, 1,129, - 0, 67, 1, 0, 3,196, 1, 0, 0, 0, 2, 0, 2,220,129, 0, 1, 23, 64,192, - 3, 22, 0, 2,128,196, 1,128, 0, 0, 2, 0, 2,220,193, 0, 1,128, 1, 0, - 4, 64, 1,128, 3, 23,128, 64, 3, 22, 64, 0,128,198,193, 64, 0,134, 1,129, - 3,219, 65,128, 2, 22, 0, 0,128,193, 1, 1, 0, 73,192,129, 1,204, 1,192, - 1, 73,128,129, 3, 30, 0,128, 0, 5, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, -240, 63, 4, 6, 0, 0, 0,116, 97, 98,108,101, 0, 0, 4, 9, 0, 0, 0,116, - 97, 98,108,101,118, 97,108, 0, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,133, 0, 0, 0,138, 0, - 0, 0, 2, 7, 0, 13, 15, 0, 0, 0,196, 1, 0, 0, 0, 2, 0, 0, 64, 2, -128, 0,128, 2,128, 1,204, 2,192, 1,220, 65,128, 2,196, 1,128, 0, 0, 2, - 0, 0, 64, 2,128, 0,128, 2, 0, 1,192, 2,128, 1, 0, 3, 0, 3,221, 1, - 0, 3,222, 1, 0, 0, 30, 0,128, 0, 1, 0, 0, 0, 3, 0, 0, 0, 0, 0, - 0, 8, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0,141, 0, 0, 0,153, 0, 0, 0, 3, 7, 0, 15, 30, 0, 0, 0,204, - 1,192, 1,198,193,129, 0, 12, 66,192, 1, 73, 0, 64, 4, 3, 2, 0, 4, 68, - 2, 0, 0,128, 2,128, 3, 92,130, 0, 1, 23,128,192, 4, 22, 0, 2,128, 68, - 2,128, 0,128, 2,128, 3,193, 2, 0, 0, 92,130,128, 1, 0, 2,128, 4, 23, -192, 64, 4, 22, 64, 0,128, 70, 2, 65, 0, 6,194,129, 4, 76, 66,193, 1, 73, - 0,130, 4, 68, 2, 0, 1,128, 2, 0, 0,192, 2,128, 0, 0, 3, 0, 1, 64, - 3,128, 1,128, 3, 0, 3, 93, 2, 0, 3, 94, 2, 0, 0, 30, 0,128, 0, 6, - 0, 0, 0, 3, 0, 0, 0, 0, 0, 0,240, 63, 3, 0, 0, 0, 0, 0, 0, 8, - 64, 4, 6, 0, 0, 0,116, 97, 98,108,101, 0, 0, 4, 9, 0, 0, 0,116, 97, - 98,108,101,118, 97,108, 0, 3, 0, 0, 0, 0, 0, 0, 16, 64, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,157, 0, 0, 0, -159, 0, 0, 0, 1, 6, 0, 11, 7, 0, 0, 0,132, 1, 0, 0,192, 1, 0, 0, - 0, 2,128, 0, 64, 2,128, 1,128, 2,128, 1,156, 65,128, 2, 30, 0,128, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0,165, 0, 0, 0,168, 0, 0, 0, 2, 6, 0, 10, 17, 0, 0, 0, -140, 1,192, 1,134,129,129, 0,196, 1, 0, 0, 0, 2, 0, 3,220,129, 0, 1, - 23, 64,192, 3, 22,128, 1,128,196, 1,128, 0, 0, 2, 0, 3, 76,130,192, 1, - 70, 66,130, 0,220,129,128, 1,218, 65, 0, 0, 22, 0, 0,128,193,193, 0, 0, - 73,192,129, 1, 30, 0,128, 0, 4, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0,240, - 63, 4, 6, 0, 0, 0,116, 97, 98,108,101, 0, 3, 0, 0, 0, 0, 0, 0, 0, - 64, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0,171, 0, 0, 0,173, 0, 0, 0, 0, 6, 0, 12, 16, - 0, 0, 0,129, 1, 0, 0,192, 1,128, 2, 1, 2, 0, 0,160, 65, 2,128,140, - 66,130, 1,141, 2, 64, 5, 25, 0,129, 4, 22,192, 0,128,204, 66,130, 1,198, -194,130, 0,218, 66, 0, 0, 22, 0, 0,128,195, 2,128, 5, 73,192, 2, 5,159, - 1,253,127, 30, 0,128, 0, 1, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0,240, 63, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -183, 0, 0, 0,186, 0, 0, 0, 0, 6, 0, 11, 9, 0, 0, 0, 73, 0,192, 1, -129, 65, 0, 0,205, 65,192, 2, 1, 66, 0, 0,160, 65, 0,128,140, 66,130, 1, - 73,128, 64, 5,159, 1,255,127, 30, 0,128, 0, 3, 0, 0, 0, 1, 1, 3, 0, - 0, 0, 0, 0, 0,240, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0,201, 0, 0, 0,203, 0, 0, 0, 0, 6, 0, 11, - 8, 0, 0, 0,129, 1, 0, 0,205, 65,192, 2, 1, 66, 0, 0,160, 65, 0,128, -140, 66,130, 1, 73, 64, 64, 5,159, 1,255,127, 30, 0,128, 0, 2, 0, 0, 0, - 3, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0,240, 63, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,211, 0, - 0, 0,215, 0, 0, 0, 0, 6, 0, 11, 11, 0, 0, 0, 73, 0,192, 1,140, 1, -192, 1, 73, 0, 64, 3,129, 65, 0, 0,205, 1,192, 2, 1, 2, 0, 0,160, 65, - 0,128,140, 66,130, 1, 73,128, 64, 5,159, 1,255,127, 30, 0,128, 0, 3, 0, - 0, 0, 3, 0, 0, 0, 0, 0, 0,240, 63, 3, 0, 0, 0, 0, 0, 0, 0, 64, - 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0,217, 0, 0, 0,219, 0, 0, 0, 0, 6, 0, 11, 8, 0, - 0, 0,129, 1, 0, 0,205, 65,192, 2, 1, 66, 0, 0,160, 65, 0,128,140, 66, -130, 1, 73,128, 64, 5,159, 1,255,127, 30, 0,128, 0, 3, 0, 0, 0, 3, 0, - 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0,240, 63, 4, 1, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0,222, 0, 0, 0,225, 0, 0, 0, 0, 6, 0, 10, 9, 0, 0, 0,140, 1, -192, 1,198, 65, 64, 0,198,129,192, 3,205,193,192, 3, 1,194, 0, 0,160, 1, - 0,128, 73, 0,193, 4,159, 65,255,127, 30, 0,128, 0, 5, 0, 0, 0, 3, 0, - 0, 0, 0, 0, 0, 8, 64, 4, 6, 0, 0, 0,115,116, 97,116,115, 0, 4, 11, - 0, 0, 0,115,116, 97, 99,107,115,108,111,116,115, 0, 3, 0, 0, 0, 0, 0, - 0,240, 63, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0,234, 0, 0, 0,239, 0, 0, 0, 2, 6, 0, - 10, 18, 0, 0, 0, 25, 64, 1,128, 22,128, 3,128,140, 1,192, 1,134,129,129, - 0,196, 1, 0, 0, 0, 2, 0, 3,220,129, 0, 1, 23, 64,192, 3, 22, 64, 1, -128,196, 1,128, 0, 0, 2, 0, 3, 65, 2, 0, 0,220,129,128, 1,218, 65, 0, - 0, 22, 0, 0,128,193,129, 0, 0, 73,192,129, 1, 30, 0,128, 0, 3, 0, 0, - 0, 3, 0, 0, 0, 0, 0, 0,240, 63, 4, 6, 0, 0, 0,116, 97, 98,108,101, - 0, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 13, 1, 0, 0, 15, 1, 0, 0, 0, 6, 0, 7, 7, - 0, 0, 0,140, 1,192, 1,134,129,129, 0,154, 65, 0, 0, 22, 0, 0,128,129, - 65, 0, 0, 73,128,129, 1, 30, 0,128, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, - 0, 0, 0, 64, 3, 0, 0, 0, 0, 0, 0,240, 63, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 35, 1, 0, 0, 37, 1, 0, - 0, 0, 6, 0, 6, 4, 0, 0, 0, 24, 0, 1,128, 22, 0, 0,128, 73, 64,192, - 1, 30, 0,128, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, - 0, 0, 0, 0, 0,240, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 69, 1, 0, 0, 69, 1, 0, 0, 0, 0, 0, 2, 1, - 0, 0, 0, 30, 0,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 73, 1, 0, 0, 77, 1, 0, 0, 2, - 1, 0, 6, 11, 0, 0, 0, 65, 0, 0, 0,132, 0, 0, 0,198, 64, 64, 0, 1, -129, 0, 0, 68, 1,128, 0,156,128, 0, 2,193,192, 0, 0, 85,192,128, 0, 9, - 64, 0,130, 94, 0, 0, 1, 30, 0,128, 0, 5, 0, 0, 0, 4, 2, 0, 0, 0, - 94, 0, 4, 5, 0, 0, 0, 97,114,103,115, 0, 4, 2, 0, 0, 0, 46, 0, 4, - 4, 0, 0, 0, 48, 42, 36, 0, 4, 9, 0, 0, 0, 97,114,103,109, 97,116, 99, -104, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 80, 1, 0, 0,105, 1, 0, 0, 7, 7, 0, 18, 79, 0, 0, 0,198, 1, - 64, 0,218, 1, 0, 0, 22,192, 6,128, 87, 64,192, 2, 22, 64, 6,128, 1,130, - 0, 0, 65,194, 0, 0,128, 2,128, 2,193,194, 0, 0, 96,194, 1,128, 64, 3, - 0, 4,132, 3, 0, 0,196, 3,128, 0, 12, 4, 3, 2, 6, 4, 4, 1,220,131, - 0, 1,134,195, 3, 7, 21,130,131, 6, 95,130,253,127, 68, 2, 0, 1,128, 2, - 0, 4,198, 2, 65, 0,218, 66, 0, 0, 22,128, 0,128,196, 2,128, 1, 0, 3, - 0, 0,220,130, 0, 1, 92,130,128, 1, 90, 66, 0, 0, 22, 0, 0,128,195, 1, -128, 3, 6, 66, 65, 0, 87,128, 65, 4, 22,128, 5,128, 87, 64, 64, 3, 22, 0, - 5,128, 84, 2, 0, 4, 24,128,129, 4, 22, 0, 0,128,195, 1,128, 3, 65,194, - 0, 0,148, 2, 0, 4,193,194, 0, 0, 96,194, 2,128, 68, 3, 0, 2,128, 3, - 0, 4,192, 3, 0, 6, 0, 4, 0, 6, 92,131, 0, 2, 87,192,193, 6, 22, 0, - 1,128,140, 3, 3, 2,141,195, 64, 7,196, 3,128, 2,198, 67,131, 7,137,192, - 3, 7, 95,130,252,127, 70, 2, 66, 0, 90, 2, 0, 0, 22,192, 2,128,128, 2, -128, 4,192, 2,128, 0, 0, 3, 0, 1, 64, 3,128, 1,128, 3, 0, 2,192, 3, -128, 2, 0, 4, 0, 3, 64, 4,128, 3,156,130, 0, 4,154, 2, 0, 0, 22, 0, - 0,128,195, 1,128, 3,218, 1, 0, 0, 22,192, 0,128,132, 2, 0, 3,134, 66, - 66, 5,140,130,130, 1, 73,192, 1, 5, 30, 0,128, 0, 10, 0, 0, 0, 4, 4, - 0, 0, 0,105,100,120, 0, 3, 0, 0, 0, 0, 0, 0,240,191, 4, 1, 0, 0, - 0, 0, 3, 0, 0, 0, 0, 0, 0,240, 63, 4, 9, 0, 0, 0, 97,114,103,109, - 97,116, 99,104, 0, 4, 8, 0, 0, 0,114,101,115,117,108,116,115, 0, 4, 2, - 0, 0, 0, 42, 0, 4, 2, 0, 0, 0, 46, 0, 4, 8, 0, 0, 0,104, 97,110, -100,108,101,114, 0, 4, 7, 0, 0, 0, 73, 78, 76, 73, 78, 69, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,108, 1, 0, - 0,124, 1, 0, 0, 4, 6, 0, 16, 49, 0, 0, 0,134,193,128, 0,196, 1, 0, - 0,198, 1,192, 3,204,193, 1, 1, 9,128,129, 3,196, 1,128, 0, 0, 2, 0, - 3,220,129, 0, 1, 23, 64,192, 3, 22,128, 7,128,196, 1, 0, 1,198,129,129, - 3,218, 1, 0, 0, 22, 64, 2,128, 4, 2,128, 1, 64, 2,128, 3,128, 2, 0, - 0,192, 2,128, 0, 0, 3, 0, 1, 64, 3,128, 1,128, 3, 0, 2,192, 3,128, - 2, 28, 66, 0, 4, 30, 0,128, 0, 6,130, 64, 0, 23, 0, 2, 3, 22, 64, 3, -128, 6,194, 64, 0, 6, 2, 65, 4, 26, 66, 0, 0, 22, 64, 2,128, 87, 64, 65, - 2, 22,192, 0,128, 6,194, 64, 0, 6,130, 65, 4, 23, 0, 2, 2, 22,192, 0, -128, 4, 2, 0, 0, 6,194, 65, 4, 12, 2, 2, 1, 9, 0, 66, 4,192, 1,128, - 1, 12, 66,129, 1, 13, 66, 66, 4, 65, 66, 2, 0,224, 1, 0,128, 73,128, 66, - 5,223, 65,255,127, 30, 0,128, 0, 11, 0, 0, 0, 4, 5, 0, 0, 0, 84, 89, - 80, 69, 0, 4, 9, 0, 0, 0,102,117,110, 99,116,105,111,110, 0, 4, 5, 0, - 0, 0,102,117,110, 99, 0, 4, 6, 0, 0, 0,115,116, 97,116,115, 0, 4, 9, - 0, 0, 0,105,115,118, 97,114, 97,114,103, 0, 3, 0, 0, 0, 0, 0, 0,240, -191, 4, 7, 0, 0, 0,112, 97,114, 97,109,115, 0, 4, 7, 0, 0, 0, 73, 78, - 76, 73, 78, 69, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, - 0,240, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0,128, 1, 0, 0,132, 1, 0, 0, 1, 0, 0, 3, 7, 0, 0, 0, - 5, 0, 0, 0, 65, 64, 0, 0, 28,128, 0, 1, 70,128, 64, 0,132, 0, 0, 0, - 92, 64, 0, 1, 30, 0,128, 0, 3, 0, 0, 0, 4, 8, 0, 0, 0,114,101,113, -117,105,114,101, 0, 4, 8, 0, 0, 0,106,105,116, 46,111,112,116, 0, 4, 16, - 0, 0, 0, 97,116,116, 97, 99,104, 95, 99, 97,108,108,104,105,110,116, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, -}; \ No newline at end of file diff --git a/src/xrServerEntities/script_engine.cpp b/src/xrServerEntities/script_engine.cpp index ceb849fb8..f823dd97f 100644 --- a/src/xrServerEntities/script_engine.cpp +++ b/src/xrServerEntities/script_engine.cpp @@ -16,7 +16,6 @@ #include #include #include -#include "script_engine_debugger.h" #ifdef USE_DEBUGGER # ifndef USE_LUA_STUDIO @@ -405,11 +404,6 @@ void CScriptEngine::init() load_common_scripts(); #endif m_stack_level = lua_gettop(lua()); - - if (ShouldAttachDebugger()) - { - //AttachDebugger(); //Getting crash in ljtab.c after executing this function: Unhandled exception thrown: read access violation. - } } void CScriptEngine::remove_script_process(const EScriptProcessors& process_id) diff --git a/src/xrServerEntities/script_engine_debugger.cpp b/src/xrServerEntities/script_engine_debugger.cpp deleted file mode 100644 index 594041290..000000000 --- a/src/xrServerEntities/script_engine_debugger.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include "stdafx.h" -#include -#include "pch_script.h" -#include "script_engine.h" -#include "script_engine_debugger.h" - -static bool isEnabled = true; -bool ShouldAttachDebugger() -{ - return isEnabled; -} - -void AttachDebugger() -{ - const char* S = "debugger_attach()"; - shared_str m_script_name = "console_command"; - CScriptEngine se = ai().script_engine(); - lua_State* L = se.lua(); - int l_iErrorCode = luaL_loadbuffer(L, S, xr_strlen(S), "@console_command"); - - if (!l_iErrorCode) - { - l_iErrorCode = lua_pcall(L, 0, 0, 0); - if (l_iErrorCode) - { - se.print_output(L, *m_script_name, l_iErrorCode); - return; - } - } - - se.print_output(L, *m_script_name, l_iErrorCode); - isEnabled = true; -} diff --git a/src/xrServerEntities/script_engine_debugger.h b/src/xrServerEntities/script_engine_debugger.h deleted file mode 100644 index 5ce458c28..000000000 --- a/src/xrServerEntities/script_engine_debugger.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once -void AttachDebugger(); -bool ShouldAttachDebugger(); \ No newline at end of file diff --git a/src/xrServerEntities/script_storage.cpp b/src/xrServerEntities/script_storage.cpp index a06a9efd5..8906295d1 100644 --- a/src/xrServerEntities/script_storage.cpp +++ b/src/xrServerEntities/script_storage.cpp @@ -433,10 +433,10 @@ void CScriptStorage::reinit() if (strstr(Core.Params, "-dbg")) luajit::open_lib(lua(), LUA_DBLIBNAME, luaopen_debug); #endif //-DEBUG - + if (!strstr(Core.Params, "-nojit")) { - //luajit::open_lib(lua(), LUA_JITLIBNAME, luaopen_jit); + luajit::open_lib(lua(), LUA_JITLIBNAME, luaopen_jit); #ifndef DEBUG put_function(lua(), opt_lua_binary, sizeof(opt_lua_binary), "jit.opt"); put_function(lua(), opt_inline_lua_binary, sizeof(opt_lua_binary), "jit.opt_inline"); From 9c41016d4109110bbdbe62ce6c7459378cffecc1 Mon Sep 17 00:00:00 2001 From: SaloEater Date: Mon, 16 Jun 2025 14:19:14 -0500 Subject: [PATCH 18/27] finish cleaning up the code --- src/xrServerEntities/script_engine.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/xrServerEntities/script_engine.cpp b/src/xrServerEntities/script_engine.cpp index f823dd97f..a5bb90ff1 100644 --- a/src/xrServerEntities/script_engine.cpp +++ b/src/xrServerEntities/script_engine.cpp @@ -15,7 +15,6 @@ #include "script_storage.h" #include #include -#include #ifdef USE_DEBUGGER # ifndef USE_LUA_STUDIO @@ -304,7 +303,6 @@ void CScriptEngine::setup_callbacks() #ifdef DEBUG # include "script_thread.h" -#include void CScriptEngine::lua_hook_call (lua_State *L, lua_Debug *dbg) { if (ai().script_engine().current_thread()) From 7318881708d2aa22f6a047372e79a6cb408a4d5e Mon Sep 17 00:00:00 2001 From: ProfLander <1253239+ProfLander@users.noreply.github.com.> Date: Wed, 18 Jun 2025 18:31:03 +0100 Subject: [PATCH 19/27] Update `gamedata` directory tree in VS solution --- src/engine-vs2022.sln | 58 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/src/engine-vs2022.sln b/src/engine-vs2022.sln index 79fb40121..370331170 100644 --- a/src/engine-vs2022.sln +++ b/src/engine-vs2022.sln @@ -110,8 +110,11 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "scripts", "scripts", "{8EC4 ..\gamedata\scripts\class_registrator_modded_exes.script = ..\gamedata\scripts\class_registrator_modded_exes.script ..\gamedata\scripts\dxml_core.script = ..\gamedata\scripts\dxml_core.script ..\gamedata\scripts\fakelens.script = ..\gamedata\scripts\fakelens.script + ..\gamedata\scripts\imgui_helper.script = ..\gamedata\scripts\imgui_helper.script + ..\gamedata\scripts\init.lua = ..\gamedata\scripts\init.lua ..\gamedata\scripts\ltx_help_ex.script = ..\gamedata\scripts\ltx_help_ex.script ..\gamedata\scripts\lua_help_ex.script = ..\gamedata\scripts\lua_help_ex.script + ..\gamedata\scripts\lua_help_imgui.script = ..\gamedata\scripts\lua_help_imgui.script ..\gamedata\scripts\modxml_inject_keybinds.script = ..\gamedata\scripts\modxml_inject_keybinds.script ..\gamedata\scripts\modxml_test.script = ..\gamedata\scripts\modxml_test.script ..\gamedata\scripts\options_builder.script = ..\gamedata\scripts\options_builder.script @@ -251,6 +254,54 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "imgui", "3rd party\imgui\im {A0F7D1FB-59A7-4717-A7E4-96F37E91998E} = {A0F7D1FB-59A7-4717-A7E4-96F37E91998E} EndProjectSection EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "amx", "amx", "{04EC24DC-AB94-4F19-8056-23DE855052D7}" + ProjectSection(SolutionItems) = preProject + ..\gamedata\scripts\amx\init.lua = ..\gamedata\scripts\amx\init.lua + ..\gamedata\scripts\amx\registrator.lua = ..\gamedata\scripts\amx\registrator.lua + ..\gamedata\scripts\amx\unlocalize.lua = ..\gamedata\scripts\amx\unlocalize.lua + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "boot", "boot", "{2B4D82D1-8DFD-4CF4-A8B5-923ED00EFFC1}" + ProjectSection(SolutionItems) = preProject + ..\gamedata\scripts\boot\function_object.lua = ..\gamedata\scripts\boot\function_object.lua + ..\gamedata\scripts\boot\init.lua = ..\gamedata\scripts\boot\init.lua + ..\gamedata\scripts\boot\loader.lua = ..\gamedata\scripts\boot\loader.lua + ..\gamedata\scripts\boot\paths.lua = ..\gamedata\scripts\boot\paths.lua + ..\gamedata\scripts\boot\sandbox.lua = ..\gamedata\scripts\boot\sandbox.lua + ..\gamedata\scripts\boot\scripts.lua = ..\gamedata\scripts\boot\scripts.lua + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{7188B178-0BAC-4DB1-80EE-0B3C32775905}" + ProjectSection(SolutionItems) = preProject + ..\gamedata\scripts\tests\init.lua = ..\gamedata\scripts\tests\init.lua + ..\gamedata\scripts\tests\util.lua = ..\gamedata\scripts\tests\util.lua + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "xr", "xr", "{277AEE51-4F38-46F9-BF6E-78F198D718B5}" + ProjectSection(SolutionItems) = preProject + ..\gamedata\scripts\xr\classes.lua = ..\gamedata\scripts\xr\classes.lua + ..\gamedata\scripts\xr\compiler.lua = ..\gamedata\scripts\xr\compiler.lua + ..\gamedata\scripts\xr\init.lua = ..\gamedata\scripts\xr\init.lua + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "lua", "lua", "{EC96D3E8-1D33-4EAD-9D67-01A07903C3FC}" + ProjectSection(SolutionItems) = preProject + ..\gamedata\scripts\amx\lua\init.lua = ..\gamedata\scripts\amx\lua\init.lua + ..\gamedata\scripts\amx\lua\tests.lua = ..\gamedata\scripts\amx\lua\tests.lua + ..\gamedata\scripts\amx\lua\unlocalize.lua = ..\gamedata\scripts\amx\lua\unlocalize.lua + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "lua", "lua", "{3CC5A577-05F4-4C38-946B-FB99F37CCA19}" + ProjectSection(SolutionItems) = preProject + ..\gamedata\scripts\xr\lua\init.lua = ..\gamedata\scripts\xr\lua\init.lua + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "processes", "processes", "{96150BF0-7065-45D8-8ACB-47D2B6646849}" + ProjectSection(SolutionItems) = preProject + ..\gamedata\scripts\xr\processes\init.lua = ..\gamedata\scripts\xr\processes\init.lua + ..\gamedata\scripts\xr\processes\process.lua = ..\gamedata\scripts\xr\processes\process.lua + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution DX10|x64 = DX10|x64 @@ -1053,6 +1104,13 @@ Global {44A08F7F-E393-4E0B-B9E6-94AF30774CE7} = {8537520E-5391-4DA0-A369-D7B22852C696} {91413BC1-731E-470B-AA8C-8C1F6290D8D7} = {44A08F7F-E393-4E0B-B9E6-94AF30774CE7} {D0843040-7706-4FBF-A931-582748BAFBB1} = {2BFC806B-CE92-4EA4-8FE8-5F2EA54BA348} + {04EC24DC-AB94-4F19-8056-23DE855052D7} = {8EC462FD-D22E-90A8-E5CE-7E832BA40C5D} + {2B4D82D1-8DFD-4CF4-A8B5-923ED00EFFC1} = {8EC462FD-D22E-90A8-E5CE-7E832BA40C5D} + {7188B178-0BAC-4DB1-80EE-0B3C32775905} = {8EC462FD-D22E-90A8-E5CE-7E832BA40C5D} + {277AEE51-4F38-46F9-BF6E-78F198D718B5} = {8EC462FD-D22E-90A8-E5CE-7E832BA40C5D} + {EC96D3E8-1D33-4EAD-9D67-01A07903C3FC} = {04EC24DC-AB94-4F19-8056-23DE855052D7} + {3CC5A577-05F4-4C38-946B-FB99F37CCA19} = {277AEE51-4F38-46F9-BF6E-78F198D718B5} + {96150BF0-7065-45D8-8ACB-47D2B6646849} = {277AEE51-4F38-46F9-BF6E-78F198D718B5} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {76CF157A-A169-443B-AE3A-F17AD29325C6} From 089135f73e4a10d0d50db551bbccf79bb8d61b3f Mon Sep 17 00:00:00 2001 From: "DEMONIZED-PC\\demonized" Date: Wed, 18 Jun 2025 11:02:45 +1000 Subject: [PATCH 20/27] put lua debug stuff behind `lua_debug 1` console command instead of -dbg flag --- README.md | 3 ++- src/xrGame/console_commands.cpp | 7 +++++- src/xrServerEntities/script_storage.cpp | 29 +++++++++++++++---------- 3 files changed, 25 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 5e0c8a73c..eeaebb858 100644 --- a/README.md +++ b/README.md @@ -164,7 +164,8 @@ The original engine is used in S.T.A.L.K.E.R. Call of Pripyat game released by G * The step of zoom adjustment is more precise. Also, it's possible to adjust the step of zoom with the console command zoom_step_count [1.0, 10.0], this option is also applicable to the binoculars. * In the new version all implementations from fakelens.script have moved directly to the engine. fakelens.script remained as a layer between the engine and scopeRadii.script -* Debug scripts with VSCode and LuaPanda support by IXRay Platform +* Debug scripts with VSCode and LuaPanda, support by IXRay Platform + * Type `lua_debug 1` in console and reload the save or start a new game * To use it, you need to install VSCode and LuaPanda extension: https://marketplace.visualstudio.com/items?itemName=stuartwang.luapanda * Open your `gamedata/scripts` folder in VSCode * Copy `.vscode` folder from the archive into your `gamedata/scripts` folder: https://github.com/themrdemonized/xray-monolith/tree/all-in-one-vs2022-wpo/gamedata/scripts/.vscode diff --git a/src/xrGame/console_commands.cpp b/src/xrGame/console_commands.cpp index 65c717d58..25fc41cbb 100644 --- a/src/xrGame/console_commands.cpp +++ b/src/xrGame/console_commands.cpp @@ -79,7 +79,10 @@ extern u64 g_qwEStartGameTime; ENGINE_API extern float psHUD_FOV_def; extern float psSqueezeVelocity; + +// Lua extern int psLUA_GCSTEP; +extern BOOL lua_debug; float g_end_modif = 0.f; @@ -2414,8 +2417,10 @@ void CCC_RegisterCommands() CMD3(CCC_Mask, "ai_dbg_lua", &psAI_Flags, aiLua); #endif // MASTER_GOLD - // Moved lua_gcstep outside of DEBUG to allow for easier experimentation. + // Moved lua_gcstep outside of DEBUG to allow for easier experimentation. CMD4(CCC_Integer, "lua_gcstep", &psLUA_GCSTEP, 1, 1000); + CMD4(CCC_Integer, "lua_debug", &lua_debug, 0, 1); + #ifdef DEBUG CMD3(CCC_Mask, "ai_debug", &psAI_Flags, aiDebug); CMD3(CCC_Mask, "ai_dbg_brain", &psAI_Flags, aiBrain); diff --git a/src/xrServerEntities/script_storage.cpp b/src/xrServerEntities/script_storage.cpp index 8906295d1..37c85ee92 100644 --- a/src/xrServerEntities/script_storage.cpp +++ b/src/xrServerEntities/script_storage.cpp @@ -390,6 +390,7 @@ bool LoadKernelScriptToGlobal(lua_State* L, const char* name) return true; }; +BOOL lua_debug = FALSE; void CScriptStorage::reinit() { if (m_virtual_machine) @@ -445,24 +446,28 @@ void CScriptStorage::reinit() } #endif //!USE_LUAJIT_ONE - bool isDebugEnabled = strstr(Core.Params, "-dbg") != nullptr; + bool isDebugEnabled = lua_debug; luaopen_lua_extensions(lua(), isDebugEnabled); disable_os_funcs(lua()); - LoadKernelScriptToGlobal(lua(), "global.lua"); - LoadKernelScriptToGlobal(lua(), "dynamic_callbacks.lua"); + if (isDebugEnabled) + { + Msg("!lua_debug 1, opening socket and initializing LuaPanda"); + LoadKernelScriptToGlobal(lua(), "global.lua"); + LoadKernelScriptToGlobal(lua(), "dynamic_callbacks.lua"); - // Sockets - luajit::open_lib(lua(), "socket.core", luaopen_socket_core_init()); - bool SocketTest = LoadKernelScriptToGlobal(lua(), "socket.lua"); + // Sockets + luajit::open_lib(lua(), "socket.core", luaopen_socket_core_init()); + bool SocketTest = LoadKernelScriptToGlobal(lua(), "socket.lua"); - // Panda - if (SocketTest) - { - pdebug_init_init(lua()); - LoadKernelScriptToGlobal(lua(), "LuaPanda.lua"); + // Panda + if (SocketTest) + { + pdebug_init_init(lua()); + LoadKernelScriptToGlobal(lua(), "LuaPanda.lua"); + } } - + if (strstr(Core.Params, "-_g")) file_header = file_header_new; //AVO: I get fatal crash at the start if this is used else From 3e031c6e1351da300764517f6482b8df567ef74e Mon Sep 17 00:00:00 2001 From: SaloEater Date: Thu, 19 Jun 2025 00:16:09 -0500 Subject: [PATCH 21/27] libs --- gamedata/scripts/{ => packages/lib}/LuaPanda.lua | 0 gamedata/scripts/{ => packages/lib}/dynamic_callbacks.lua | 0 gamedata/scripts/{ => packages/lib}/global.lua | 0 gamedata/scripts/{ => packages/lib}/socket.lua | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename gamedata/scripts/{ => packages/lib}/LuaPanda.lua (100%) rename gamedata/scripts/{ => packages/lib}/dynamic_callbacks.lua (100%) rename gamedata/scripts/{ => packages/lib}/global.lua (100%) rename gamedata/scripts/{ => packages/lib}/socket.lua (100%) diff --git a/gamedata/scripts/LuaPanda.lua b/gamedata/scripts/packages/lib/LuaPanda.lua similarity index 100% rename from gamedata/scripts/LuaPanda.lua rename to gamedata/scripts/packages/lib/LuaPanda.lua diff --git a/gamedata/scripts/dynamic_callbacks.lua b/gamedata/scripts/packages/lib/dynamic_callbacks.lua similarity index 100% rename from gamedata/scripts/dynamic_callbacks.lua rename to gamedata/scripts/packages/lib/dynamic_callbacks.lua diff --git a/gamedata/scripts/global.lua b/gamedata/scripts/packages/lib/global.lua similarity index 100% rename from gamedata/scripts/global.lua rename to gamedata/scripts/packages/lib/global.lua diff --git a/gamedata/scripts/socket.lua b/gamedata/scripts/packages/lib/socket.lua similarity index 100% rename from gamedata/scripts/socket.lua rename to gamedata/scripts/packages/lib/socket.lua From 0b0cf88e52875cc048e2093fd2217614deb2da54 Mon Sep 17 00:00:00 2001 From: SaloEater Date: Thu, 19 Jun 2025 05:13:22 -0500 Subject: [PATCH 22/27] move lua libraries to scripts --- gamedata/scripts/boot/debug.lua | 1 + gamedata/scripts/boot/init.lua | 3 ++ gamedata/scripts/init.lua | 4 +- .../packages/lib/dynamic_callbacks.lua | 37 ---------------- gamedata/scripts/packages/lib/global.lua | 41 ----------------- .../scripts/packages/lib/luapanda/init.lua | 44 +++++++++++++++++++ .../{LuaPanda.lua => luapanda/lua_panda.lua} | 10 ++--- .../packages/lib/{ => luapanda}/socket.lua | 0 src/3rd party/lua-extensions/base.cpp | 14 ++++++ src/xrCore/string_concatenations.cpp | 13 ------ src/xrCore/string_concatenations.h | 20 +-------- src/xrEngine/EngineAPI.h | 1 - src/xrServerEntities/script_engine.cpp | 14 +++++- 13 files changed, 82 insertions(+), 120 deletions(-) create mode 100644 gamedata/scripts/boot/debug.lua delete mode 100644 gamedata/scripts/packages/lib/dynamic_callbacks.lua delete mode 100644 gamedata/scripts/packages/lib/global.lua create mode 100644 gamedata/scripts/packages/lib/luapanda/init.lua rename gamedata/scripts/packages/lib/{LuaPanda.lua => luapanda/lua_panda.lua} (99%) rename gamedata/scripts/packages/lib/{ => luapanda}/socket.lua (100%) diff --git a/gamedata/scripts/boot/debug.lua b/gamedata/scripts/boot/debug.lua new file mode 100644 index 000000000..44c925ae5 --- /dev/null +++ b/gamedata/scripts/boot/debug.lua @@ -0,0 +1 @@ +require("luapanda") \ No newline at end of file diff --git a/gamedata/scripts/boot/init.lua b/gamedata/scripts/boot/init.lua index 070003591..691b68055 100644 --- a/gamedata/scripts/boot/init.lua +++ b/gamedata/scripts/boot/init.lua @@ -12,6 +12,9 @@ require("boot.paths") -- Setup package.loaders machinery require("boot.loader") +-- Setup luapanda +require("boot.debug") + -- Setup engine interface require("boot.function_object") diff --git a/gamedata/scripts/init.lua b/gamedata/scripts/init.lua index 68ac855e7..8ba951974 100644 --- a/gamedata/scripts/init.lua +++ b/gamedata/scripts/init.lua @@ -43,7 +43,9 @@ _LUA_G = _G --- Emplace an error-checked lua compiler with customizable environment _LOADSTRING = loadstring function loadstring(src, namespace_name, script_name) - print("* [lua] loading " .. namespace_name) + if namespace_name then + print("* [lua] loading " .. namespace_name) + end local f, err = _LOADSTRING(src, namespace_name) if not f then diff --git a/gamedata/scripts/packages/lib/dynamic_callbacks.lua b/gamedata/scripts/packages/lib/dynamic_callbacks.lua deleted file mode 100644 index 71f720c8d..000000000 --- a/gamedata/scripts/packages/lib/dynamic_callbacks.lua +++ /dev/null @@ -1,37 +0,0 @@ -local intercepts = -{ - save = {}, - load = {}, - update = {}, - - save_state = {}, - load_state = {} -} - -function RegisterScriptCallback(name, func_or_userdata) - if (func_or_userdata == nil) then - callstack() - end - - if (intercepts[name]) then - intercepts[name][func_or_userdata] = true - end -end - -function UnregisterScriptCallback(name, func_or_userdata) - if (intercepts[name]) then - intercepts[name][func_or_userdata] = nil - end -end - -function SendScriptCallback(name,...) - if (intercepts[name]) then - for func_or_userdata,v in pairs(intercepts[name]) do - if (type(func_or_userdata) == "function") then - func_or_userdata(...) - elseif (func_or_userdata[name]) then - func_or_userdata[name](func_or_userdata,...) - end - end - end -end \ No newline at end of file diff --git a/gamedata/scripts/packages/lib/global.lua b/gamedata/scripts/packages/lib/global.lua deleted file mode 100644 index dae66ae31..000000000 --- a/gamedata/scripts/packages/lib/global.lua +++ /dev/null @@ -1,41 +0,0 @@ ---// General -jit.opt.start(2) - -string.gfind = string.gmatch -math.mod = math.fmod - ---// LuaPandas -DebuggerMode = false - -function debug_jit_off() - if DebuggerMode then - if jit then jit.off() end - end -end - -function debug_jit_on() - if DebuggerMode then - if jit then jit.on() end - end -end - -function debugger_attach() - if DebuggerMode then - log('LuaPanda: Disabling jit...') - debug_jit_off() - log('LuaPanda: Reconnecting') - LuaPanda.reConnect() - log('LuaPanda: reconnected') - debug_jit_on() - log('LuaPanda: Started') - else - log('LuaPanda: Disabling jit...') - debug_jit_off() - log('LuaPanda: Connecting') - LuaPanda.start("127.0.0.1", 8818) - log('LuaPanda: Connected') - DebuggerMode = true - debug_jit_on() - log('LuaPanda: Started') - end -end \ No newline at end of file diff --git a/gamedata/scripts/packages/lib/luapanda/init.lua b/gamedata/scripts/packages/lib/luapanda/init.lua new file mode 100644 index 000000000..33b9d41ca --- /dev/null +++ b/gamedata/scripts/packages/lib/luapanda/init.lua @@ -0,0 +1,44 @@ +require("luapanda.lua_panda") +--// General +jit.opt.start(2) + +string.gfind = string.gmatch +math.mod = math.fmod + +--// LuaPandas +DebuggerMode = false + +log('LuaPanda: Loading...') + +function debug_jit_off() + if DebuggerMode then + if jit then jit.off() end + end +end + +function debug_jit_on() + if DebuggerMode then + if jit then jit.on() end + end +end + +function attach_debugger_internal() + if DebuggerMode then + log('LuaPanda: Disabling jit...') + debug_jit_off() + log('LuaPanda: Reconnecting') + LuaPanda.reConnect() + log('LuaPanda: reconnected') + debug_jit_on() + log('LuaPanda: Started') + else + log('LuaPanda: Disabling jit...') + debug_jit_off() + log('LuaPanda: Connecting') + LuaPanda.start("127.0.0.1", 8818) + log('LuaPanda: Connected') + DebuggerMode = true + debug_jit_on() + log('LuaPanda: Started') + end +end \ No newline at end of file diff --git a/gamedata/scripts/packages/lib/LuaPanda.lua b/gamedata/scripts/packages/lib/luapanda/lua_panda.lua similarity index 99% rename from gamedata/scripts/packages/lib/LuaPanda.lua rename to gamedata/scripts/packages/lib/luapanda/lua_panda.lua index 8bd317a7a..7efa2c181 100644 --- a/gamedata/scripts/packages/lib/LuaPanda.lua +++ b/gamedata/scripts/packages/lib/luapanda/lua_panda.lua @@ -1696,14 +1696,12 @@ end -- @filePath 被替换的路径 -- @ext 后缀(后缀前的 . 不会被替换) function this.changePotToSep(filePath, ext) - local idx = filePath:find(ext, (-1) * ext:len(), true) + local idx = filePath:find(ext, (-1) * ext:len() , true) if idx then - local tmp = filePath:sub(1, idx - 2):gsub("%.", "/") -- Exclude the dot before the extension - filePath = tmp .. filePath:sub(idx - 1) -- Preserve the dot and extension - else - filePath = filePath:gsub("%.", "/") + local tmp = filePath:sub(1, idx - 1):gsub("%.", "/"); + filePath = tmp .. ext; end - return filePath + return filePath; end --- this.truncatedPath 从 beTruncatedPath 字符串中去除 rep 匹配到的部分 diff --git a/gamedata/scripts/packages/lib/socket.lua b/gamedata/scripts/packages/lib/luapanda/socket.lua similarity index 100% rename from gamedata/scripts/packages/lib/socket.lua rename to gamedata/scripts/packages/lib/luapanda/socket.lua diff --git a/src/3rd party/lua-extensions/base.cpp b/src/3rd party/lua-extensions/base.cpp index 5a7c7825a..f9ee55bd0 100644 --- a/src/3rd party/lua-extensions/base.cpp +++ b/src/3rd party/lua-extensions/base.cpp @@ -18,8 +18,18 @@ extern "C"{ #include "lmarshal.h" #include "luasocket/socket.h" #include "luasocket/luasocket.h" + #include } +struct luajit { + static void open_lib(lua_State* L, LPCSTR module_name, lua_CFunction function) + { + lua_pushcfunction(L, function); + lua_pushstring(L, module_name); + lua_call(L, 1, 0); + } +}; + //#include "Libs.h" #include "script_additional_libs.h" @@ -58,4 +68,8 @@ lua_CFunction luaopen_socket_core_init() { void pdebug_init_init(lua_State* L) { pdebug_init(L); +} + +void init_socket_core(lua_State* L) { + luajit::open_lib(L, "socket.core", luaopen_socket_core_init()); } \ No newline at end of file diff --git a/src/xrCore/string_concatenations.cpp b/src/xrCore/string_concatenations.cpp index e85b18b86..5ed2541c5 100644 --- a/src/xrCore/string_concatenations.cpp +++ b/src/xrCore/string_concatenations.cpp @@ -309,16 +309,3 @@ LPSTR strconcat(int dest_sz, char* dest, const char* S1, const char* S2, const c return (dest); } - -int XRCORE_API _strconcatSingle(char*& destPtr, char* pDestEnd, const char* Str) -{ - char* TargetStrCursor = const_cast (Str); - for (; *TargetStrCursor && destPtr < pDestEnd; destPtr++, TargetStrCursor++) - { - *destPtr = *TargetStrCursor; - } - - R_ASSERT3(!(*TargetStrCursor), "Failed to concatenate string", Str); - - return 0; -} \ No newline at end of file diff --git a/src/xrCore/string_concatenations.h b/src/xrCore/string_concatenations.h index 71f680cd8..822bd790c 100644 --- a/src/xrCore/string_concatenations.h +++ b/src/xrCore/string_concatenations.h @@ -74,23 +74,5 @@ IC char* strconcat(int dest_sz, char* dest, const char* S1, const char* S2, cons #endif //_EDITOR #include "string_concatenations_inline.h" -// Giperion XRay Oxygen - ultimate version of strconcat -template -char* xr_strconcat(StringReceiverType& receiver, ArgList... args) -{ - static_assert(std::is_array< StringReceiverType>::value); // must be array... - static_assert(std::is_same::type, char>::value); // ... of chars - - char* pStrCursor = &receiver[0]; - char* pStrEnd = &receiver[0] + sizeof(StringReceiverType); - int dummy[] = { _strconcatSingle(pStrCursor, pStrEnd, args)... }; - (void)dummy; - - *pStrCursor = '\0'; - return &receiver[0]; -} - -int XRCORE_API _strconcatSingle(char*& destPtr, char* pDestEnd, const char* Str); - -#endif // #ifndef STRING_CONCATENATIONS_H \ No newline at end of file +#endif // #ifndef STRING_CONCATENATIONS_H diff --git a/src/xrEngine/EngineAPI.h b/src/xrEngine/EngineAPI.h index ad2731322..1f699f656 100644 --- a/src/xrEngine/EngineAPI.h +++ b/src/xrEngine/EngineAPI.h @@ -48,7 +48,6 @@ class ENGINE_API CEngineAPI BOOL tune_enabled; VTPause* tune_pause; VTResume* tune_resume; - void Initialize(); #ifndef DEDICATED_SERVER diff --git a/src/xrServerEntities/script_engine.cpp b/src/xrServerEntities/script_engine.cpp index c839b3d61..b32f8b8d7 100644 --- a/src/xrServerEntities/script_engine.cpp +++ b/src/xrServerEntities/script_engine.cpp @@ -52,7 +52,11 @@ using namespace ScriptEngine; #endif //!PURE_ALLOC extern void export_classes(lua_State* L); -extern int luaopen_lua_extensions(lua_State* L); +extern int luaopen_lua_extensions(lua_State* L, bool IsDebug = false); +extern void init_socket_core(lua_State* L); +extern void pdebug_init_init(lua_State* L); + +BOOL lua_debug = FALSE; struct raii_guard : private boost::noncopyable { @@ -537,8 +541,14 @@ void CScriptEngine::reinit() } #endif //!USE_LUAJIT_ONE - + bool isDebugEnabled = lua_debug; luaopen_lua_extensions(lua()); + + if (isDebugEnabled || true) + { + init_socket_core(lua()); + pdebug_init_init(lua()); + } } void CScriptEngine::unload() From 581dfd5e582258e79b9eb3a828ccf7a55a460eca Mon Sep 17 00:00:00 2001 From: SaloEater Date: Thu, 19 Jun 2025 05:26:34 -0500 Subject: [PATCH 23/27] fixes --- src/xrServerEntities/script_engine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xrServerEntities/script_engine.cpp b/src/xrServerEntities/script_engine.cpp index b32f8b8d7..be0fe538a 100644 --- a/src/xrServerEntities/script_engine.cpp +++ b/src/xrServerEntities/script_engine.cpp @@ -544,7 +544,7 @@ void CScriptEngine::reinit() bool isDebugEnabled = lua_debug; luaopen_lua_extensions(lua()); - if (isDebugEnabled || true) + if (isDebugEnabled) { init_socket_core(lua()); pdebug_init_init(lua()); From 30634e890004d6d6b2f87a4b71225fa345ab8e41 Mon Sep 17 00:00:00 2001 From: SaloEater Date: Thu, 19 Jun 2025 05:38:45 -0500 Subject: [PATCH 24/27] reduce console command to argument --- README.md | 5 ++--- src/xrGame/console_commands.cpp | 3 --- src/xrServerEntities/script_engine.cpp | 4 +--- 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index e65525fe0..8162a52e8 100644 --- a/README.md +++ b/README.md @@ -164,12 +164,11 @@ The original engine is used in S.T.A.L.K.E.R. Call of Pripyat game released by G * The step of zoom adjustment is more precise. Also, it's possible to adjust the step of zoom with the console command zoom_step_count [1.0, 10.0], this option is also applicable to the binoculars. * In the new version all implementations from fakelens.script have moved directly to the engine. fakelens.script remained as a layer between the engine and scopeRadii.script -* Debug scripts with VSCode and LuaPanda, support by IXRay Platform - * Type `lua_debug 1` in console and reload the save or start a new game +* Debug scripts with VSCode and LuaPanda, made by IXRay Platform + * Add `-luapanda` arguments when launching your game * To use it, you need to install VSCode and LuaPanda extension: https://marketplace.visualstudio.com/items?itemName=stuartwang.luapanda * Open your `gamedata/scripts` folder in VSCode * Copy `.vscode` folder from the archive into your `gamedata/scripts` folder: https://github.com/themrdemonized/xray-monolith/tree/all-in-one-vs2022-wpo/gamedata/scripts/.vscode - * Copy `LuaPanda.lua`, `dynamic_callbacks.lua`, `global.lua`, `socket.lua` into your `gamedata/scripts` folder: https://github.com/themrdemonized/xray-monolith/tree/all-in-one-vs2022-wpo/gamedata/scripts * Return to VSCode, go to `Run and Debug` section and start debugging or press F5 key * Open in-game console with `~` key and type `run_string debugger_attach()`. If you do everything correctly and engine is working properly too, you will get an entry breakpoint at `global.lua` file in VSCode. * You have to re-enable the debugger every time you start a new game or load a save, so you have to type `run_string debugger_attach()` in console again. diff --git a/src/xrGame/console_commands.cpp b/src/xrGame/console_commands.cpp index cb6052816..bc0c42cbc 100644 --- a/src/xrGame/console_commands.cpp +++ b/src/xrGame/console_commands.cpp @@ -78,9 +78,7 @@ ENGINE_API extern float psHUD_FOV_def; extern float psSqueezeVelocity; -// Lua extern int psLUA_GCSTEP; -extern BOOL lua_debug; float g_end_modif = 0.f; @@ -2420,7 +2418,6 @@ void CCC_RegisterCommands() // Moved lua_gcstep outside of DEBUG to allow for easier experimentation. CMD4(CCC_Integer, "lua_gcstep", &psLUA_GCSTEP, 1, 1000); - CMD4(CCC_Integer, "lua_debug", &lua_debug, 0, 1); #ifdef DEBUG CMD3(CCC_Mask, "ai_debug", &psAI_Flags, aiDebug); diff --git a/src/xrServerEntities/script_engine.cpp b/src/xrServerEntities/script_engine.cpp index be0fe538a..ad0d35af5 100644 --- a/src/xrServerEntities/script_engine.cpp +++ b/src/xrServerEntities/script_engine.cpp @@ -56,8 +56,6 @@ extern int luaopen_lua_extensions(lua_State* L, bool IsDebug = false); extern void init_socket_core(lua_State* L); extern void pdebug_init_init(lua_State* L); -BOOL lua_debug = FALSE; - struct raii_guard : private boost::noncopyable { int m_error_code; @@ -541,7 +539,7 @@ void CScriptEngine::reinit() } #endif //!USE_LUAJIT_ONE - bool isDebugEnabled = lua_debug; + bool isDebugEnabled = strstr(Core.Params, "-luapanda") != nullptr;; luaopen_lua_extensions(lua()); if (isDebugEnabled) From f01e5f4eb1216a42eab59abbcaba383945170ea2 Mon Sep 17 00:00:00 2001 From: SaloEater Date: Thu, 19 Jun 2025 05:40:56 -0500 Subject: [PATCH 25/27] reduce console command to argument, continuation --- gamedata/scripts/boot/debug.lua | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/gamedata/scripts/boot/debug.lua b/gamedata/scripts/boot/debug.lua index 44c925ae5..1eb9d5637 100644 --- a/gamedata/scripts/boot/debug.lua +++ b/gamedata/scripts/boot/debug.lua @@ -1 +1,3 @@ -require("luapanda") \ No newline at end of file +if string.find(command_line(), "-luapanda") then + require("luapanda") +end \ No newline at end of file From 968371c397717f7e980908c456b136166ea1821a Mon Sep 17 00:00:00 2001 From: SaloEater Date: Thu, 19 Jun 2025 18:39:50 -0500 Subject: [PATCH 26/27] fixes --- src/xrServerEntities/vs2022/xrServerEntities.vcxproj | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 src/xrServerEntities/vs2022/xrServerEntities.vcxproj diff --git a/src/xrServerEntities/vs2022/xrServerEntities.vcxproj b/src/xrServerEntities/vs2022/xrServerEntities.vcxproj deleted file mode 100644 index e69de29bb..000000000 From d3ba1e80c019f58c8b3ee2119d312b8021f4651b Mon Sep 17 00:00:00 2001 From: SaloEater Date: Fri, 20 Jun 2025 02:15:07 -0500 Subject: [PATCH 27/27] change command name --- README.md | 4 ++-- gamedata/scripts/packages/lib/luapanda/init.lua | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 8162a52e8..85a4fa6bd 100644 --- a/README.md +++ b/README.md @@ -170,8 +170,8 @@ The original engine is used in S.T.A.L.K.E.R. Call of Pripyat game released by G * Open your `gamedata/scripts` folder in VSCode * Copy `.vscode` folder from the archive into your `gamedata/scripts` folder: https://github.com/themrdemonized/xray-monolith/tree/all-in-one-vs2022-wpo/gamedata/scripts/.vscode * Return to VSCode, go to `Run and Debug` section and start debugging or press F5 key - * Open in-game console with `~` key and type `run_string debugger_attach()`. If you do everything correctly and engine is working properly too, you will get an entry breakpoint at `global.lua` file in VSCode. - * You have to re-enable the debugger every time you start a new game or load a save, so you have to type `run_string debugger_attach()` in console again. + * Open in-game console with `~` key and type `run_string attach_debugger()`. If you do everything correctly and engine is working properly too, you will get an entry breakpoint at `global.lua` file in VSCode. + * You have to re-enable the debugger every time you start a new game or load a save, so you have to type `run_string attach_debugger()` in console again. * Debugger is working dynamically, so you can add/remove files from your VSCode folder and it will automatically update the list of files available for debugging. * All settings can be edited from the game options in "Modded Exes" tab diff --git a/gamedata/scripts/packages/lib/luapanda/init.lua b/gamedata/scripts/packages/lib/luapanda/init.lua index 33b9d41ca..c486575c4 100644 --- a/gamedata/scripts/packages/lib/luapanda/init.lua +++ b/gamedata/scripts/packages/lib/luapanda/init.lua @@ -22,7 +22,7 @@ function debug_jit_on() end end -function attach_debugger_internal() +function attach_debugger() if DebuggerMode then log('LuaPanda: Disabling jit...') debug_jit_off()