forked from redo/BlockLua
Compare commits
31 Commits
01f216f31e
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| b328f0b21a | |||
| 71b73c816b | |||
| c5dc8b15f9 | |||
|
|
8399b11322 | ||
| d494f02fe3 | |||
| a7db0d8e81 | |||
| 33f5ec9bbe | |||
| f6bf18efaa | |||
| 4f42801da6 | |||
| 15f67e0eef | |||
| 5885dcbed3 | |||
| d9a416f5d5 | |||
|
|
2191e004ad | ||
|
|
ae34bb8b7a | ||
|
|
b71bfdb73e | ||
|
|
7232ede09d | ||
| ed5c254480 | |||
| 5718ba8e6b | |||
| a4f78b7425 | |||
| e47f6d4651 | |||
| 93a47d54be | |||
|
|
76c758a47b | ||
| 87e199ea5c | |||
| 66ed695010 | |||
| e309e2427b | |||
|
|
5f98dc017b | ||
|
|
edf31c178c | ||
|
|
7da249cca1 | ||
| ee784869f1 | |||
| 0815a6d229 | |||
| cbd0c29495 |
42
.clang-format
Normal file
42
.clang-format
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
BasedOnStyle: LLVM
|
||||||
|
|
||||||
|
# Include sorting and grouping
|
||||||
|
SortIncludes: CaseSensitive
|
||||||
|
IncludeBlocks: Preserve
|
||||||
|
IncludeCategories:
|
||||||
|
- Regex: '<Windows\.h>'
|
||||||
|
Priority: 1
|
||||||
|
- Regex: '<Psapi\.h>'
|
||||||
|
Priority: 2
|
||||||
|
- Regex: '"BlHooks\\.hpp"'
|
||||||
|
Priority: 3
|
||||||
|
- Regex: '"BlFuncs\\.hpp"'
|
||||||
|
Priority: 4
|
||||||
|
- Regex: ".*"
|
||||||
|
Priority: 5
|
||||||
|
|
||||||
|
# Indentation settings
|
||||||
|
IndentWidth: 2
|
||||||
|
UseTab: Never
|
||||||
|
IndentAccessModifiers: false
|
||||||
|
AccessModifierOffset: 0
|
||||||
|
NamespaceIndentation: All
|
||||||
|
|
||||||
|
# Line breaking and wrapping
|
||||||
|
ColumnLimit: 120
|
||||||
|
BreakBeforeTernaryOperators: false
|
||||||
|
BreakBeforeBinaryOperators: None
|
||||||
|
AlwaysBreakAfterReturnType: None
|
||||||
|
AlwaysBreakAfterDefinitionReturnType: None
|
||||||
|
|
||||||
|
# Alignment
|
||||||
|
AlignOperands: DontAlign
|
||||||
|
AlignAfterOpenBracket: AlwaysBreak
|
||||||
|
PointerAlignment: Left
|
||||||
|
|
||||||
|
# Parameter formatting
|
||||||
|
BinPackParameters: false
|
||||||
|
AllowAllParametersOfDeclarationOnNextLine: false
|
||||||
|
|
||||||
|
# Code organization
|
||||||
|
SeparateDefinitionBlocks: Always
|
||||||
9
.editorconfig
Normal file
9
.editorconfig
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
end_of_line = lf
|
||||||
|
charset = utf-8
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
insert_final_newline = true
|
||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1 +1,2 @@
|
|||||||
build/
|
build/
|
||||||
|
.cache/
|
||||||
|
|||||||
11
.vscode/settings.json
vendored
Normal file
11
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"Lua.diagnostics.globals": [
|
||||||
|
"_bllua_ts",
|
||||||
|
"_bllua_requiresecure",
|
||||||
|
"_bllua_on_unload"
|
||||||
|
],
|
||||||
|
"Lua.runtime.version": "Lua 5.1",
|
||||||
|
"Lua.diagnostics.disable": ["lowercase-global", "undefined-global"],
|
||||||
|
"C_Cpp.default.compileCommands": "${workspaceFolder}/build/compile_commands.json",
|
||||||
|
"C_Cpp.default.compilerPath": "C:/msys64/mingw32/bin/g++.exe"
|
||||||
|
}
|
||||||
56
CMakeLists.txt
Normal file
56
CMakeLists.txt
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.10)
|
||||||
|
|
||||||
|
project(BlockLua CXX)
|
||||||
|
|
||||||
|
# Export compile_commands.json for VSCode IntelliSense
|
||||||
|
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||||
|
|
||||||
|
# Output directories to mirror build.bat's build folder
|
||||||
|
set(OUTPUT_DIR ${CMAKE_SOURCE_DIR}/build)
|
||||||
|
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${OUTPUT_DIR})
|
||||||
|
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${OUTPUT_DIR})
|
||||||
|
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${OUTPUT_DIR})
|
||||||
|
|
||||||
|
# Global build options to mirror build.bat
|
||||||
|
add_compile_options(
|
||||||
|
-Wall
|
||||||
|
-Werror
|
||||||
|
-m32
|
||||||
|
-static-libgcc
|
||||||
|
-static-libstdc++
|
||||||
|
)
|
||||||
|
|
||||||
|
# Include paths
|
||||||
|
include_directories(
|
||||||
|
${CMAKE_SOURCE_DIR}/src
|
||||||
|
${CMAKE_SOURCE_DIR}/inc/tsfuncs
|
||||||
|
${CMAKE_SOURCE_DIR}/inc/lua
|
||||||
|
)
|
||||||
|
|
||||||
|
# Link directories (for -L.) and libraries from build.bat
|
||||||
|
link_directories(
|
||||||
|
${CMAKE_SOURCE_DIR}
|
||||||
|
)
|
||||||
|
|
||||||
|
# Safe DLL
|
||||||
|
add_library(BlockLua SHARED src/bllua4.cpp)
|
||||||
|
# Ensure output name matches build.bat
|
||||||
|
set_target_properties(BlockLua PROPERTIES OUTPUT_NAME "BlockLua")
|
||||||
|
# Linker flags and libraries
|
||||||
|
if(MSVC)
|
||||||
|
# Not expected with mingw, but keep placeholder
|
||||||
|
else()
|
||||||
|
target_link_libraries(BlockLua PRIVATE psapi lua5.1)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Unsafe DLL (with BLLUA_UNSAFE definition)
|
||||||
|
add_library(BlockLuaUnsafe SHARED src/bllua4.cpp)
|
||||||
|
set_target_properties(BlockLuaUnsafe PROPERTIES OUTPUT_NAME "BlockLua-Unsafe")
|
||||||
|
|
||||||
|
target_compile_definitions(BlockLuaUnsafe PRIVATE BLLUA_UNSAFE)
|
||||||
|
|
||||||
|
if(MSVC)
|
||||||
|
# Not expected with mingw, but keep placeholder
|
||||||
|
else()
|
||||||
|
target_link_libraries(BlockLuaUnsafe PRIVATE psapi lua5.1)
|
||||||
|
endif()
|
||||||
27
build.bat
Normal file
27
build.bat
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
@echo off
|
||||||
|
cd /d %~dp0
|
||||||
|
|
||||||
|
REM Ensure MinGW32 toolchain is first in PATH
|
||||||
|
set "PATH=C:\msys64\mingw32\bin;%PATH%"
|
||||||
|
|
||||||
|
REM Configure CMake (generate into build/)
|
||||||
|
cmake -S . -B build -G "MinGW Makefiles"
|
||||||
|
if errorlevel 1 goto :error
|
||||||
|
|
||||||
|
REM Build (Release by default)
|
||||||
|
cmake --build build --config Release -j
|
||||||
|
if errorlevel 1 goto :error
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo Build completed.
|
||||||
|
echo Outputs in .\build :
|
||||||
|
echo - BlockLua.dll
|
||||||
|
|
||||||
|
echo - BlockLua-Unsafe.dll
|
||||||
|
|
||||||
|
exit /b 0
|
||||||
|
|
||||||
|
:error
|
||||||
|
echo.
|
||||||
|
echo Build failed. See errors above.
|
||||||
|
exit /b 1
|
||||||
19
compile.bat
19
compile.bat
@@ -1,19 +0,0 @@
|
|||||||
@echo off
|
|
||||||
cd /d %~dp0
|
|
||||||
|
|
||||||
rem ensure build directory exists
|
|
||||||
if not exist build mkdir build
|
|
||||||
|
|
||||||
set buildargs=-Wall -Werror -m32 -shared -Isrc -Iinc/tsfuncs -Iinc/lua -lpsapi -L. -llua5.1 -static-libgcc -static-libstdc++
|
|
||||||
|
|
||||||
echo on
|
|
||||||
|
|
||||||
g++ src/bllua4.cpp %buildargs% -o build\BlockLua.dll
|
|
||||||
@rem g++ -DBLLUA_UNSAFE src/bllua4.cpp %buildargs% -o BlockLua-Unsafe.dll
|
|
||||||
|
|
||||||
@echo off
|
|
||||||
|
|
||||||
rem objdump -d build\BlockLua.dll > build\BlockLua.dll.dump.txt
|
|
||||||
rem objdump -d build\BlockLua-Unsafe.dll > build\BlockLua-Unsafe.dll.dump.txt
|
|
||||||
|
|
||||||
pause
|
|
||||||
@@ -27,7 +27,7 @@ What these packages are for:
|
|||||||
- Run the script:
|
- Run the script:
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
msys_compile.bat
|
build.bat
|
||||||
```
|
```
|
||||||
|
|
||||||
What the script does:
|
What the script does:
|
||||||
@@ -48,5 +48,5 @@ You should see `architecture: i386` in the output.
|
|||||||
|
|
||||||
### Notes
|
### Notes
|
||||||
|
|
||||||
- Ensure you installed the i686 (32-bit) variants of the packages; x86_64 packages won’t work for a 32-bit build.
|
- Ensure you installed the i686 (32-bit) variants of the packages; x86_64 packages won't work for a 32-bit build.
|
||||||
- If the linker cannot find `-llua5.1`, confirm `mingw-w64-i686-lua51` is installed and you are using the `mingw32` toolchain (not `x86_64`).
|
- If the linker cannot find `-llua5.1`, confirm `mingw-w64-i686-lua51` is installed and you are using the `mingw32` toolchain (not `x86_64`).
|
||||||
|
|||||||
@@ -4,93 +4,75 @@
|
|||||||
** See Copyright Notice in lua.h
|
** See Copyright Notice in lua.h
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#ifndef lauxlib_h
|
#ifndef lauxlib_h
|
||||||
#define lauxlib_h
|
#define lauxlib_h
|
||||||
|
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#include "lua.h"
|
#include "lua.h"
|
||||||
|
|
||||||
|
|
||||||
/* extra error code for `luaL_load' */
|
/* extra error code for `luaL_load' */
|
||||||
#define LUA_ERRFILE (LUA_ERRERR+1)
|
#define LUA_ERRFILE (LUA_ERRERR + 1)
|
||||||
|
|
||||||
typedef struct luaL_Reg {
|
typedef struct luaL_Reg {
|
||||||
const char *name;
|
const char* name;
|
||||||
lua_CFunction func;
|
lua_CFunction func;
|
||||||
} luaL_Reg;
|
} luaL_Reg;
|
||||||
|
|
||||||
LUALIB_API void (luaL_openlib) (lua_State *L, const char *libname,
|
LUALIB_API void(luaL_openlib)(lua_State* L, const char* libname, const luaL_Reg* l, int nup);
|
||||||
const luaL_Reg *l, int nup);
|
LUALIB_API void(luaL_register)(lua_State* L, const char* libname, const luaL_Reg* l);
|
||||||
LUALIB_API void (luaL_register) (lua_State *L, const char *libname,
|
LUALIB_API int(luaL_getmetafield)(lua_State* L, int obj, const char* e);
|
||||||
const luaL_Reg *l);
|
LUALIB_API int(luaL_callmeta)(lua_State* L, int obj, const char* e);
|
||||||
LUALIB_API int (luaL_getmetafield) (lua_State *L, int obj, const char *e);
|
LUALIB_API int(luaL_typerror)(lua_State* L, int narg, const char* tname);
|
||||||
LUALIB_API int (luaL_callmeta) (lua_State *L, int obj, const char *e);
|
LUALIB_API int(luaL_argerror)(lua_State* L, int numarg, const char* extramsg);
|
||||||
LUALIB_API int (luaL_typerror) (lua_State *L, int narg, const char *tname);
|
LUALIB_API const char*(luaL_checklstring)(lua_State * L, int numArg, size_t* l);
|
||||||
LUALIB_API int (luaL_argerror) (lua_State *L, int numarg, const char *extramsg);
|
LUALIB_API const char*(luaL_optlstring)(lua_State * L, int numArg, const char* def, size_t* l);
|
||||||
LUALIB_API const char *(luaL_checklstring) (lua_State *L, int numArg,
|
LUALIB_API lua_Number(luaL_checknumber)(lua_State* L, int numArg);
|
||||||
size_t *l);
|
LUALIB_API lua_Number(luaL_optnumber)(lua_State* L, int nArg, lua_Number def);
|
||||||
LUALIB_API const char *(luaL_optlstring) (lua_State *L, int numArg,
|
|
||||||
const char *def, size_t *l);
|
|
||||||
LUALIB_API lua_Number (luaL_checknumber) (lua_State *L, int numArg);
|
|
||||||
LUALIB_API lua_Number (luaL_optnumber) (lua_State *L, int nArg, lua_Number def);
|
|
||||||
|
|
||||||
LUALIB_API lua_Integer (luaL_checkinteger) (lua_State *L, int numArg);
|
LUALIB_API lua_Integer(luaL_checkinteger)(lua_State* L, int numArg);
|
||||||
LUALIB_API lua_Integer (luaL_optinteger) (lua_State *L, int nArg,
|
LUALIB_API lua_Integer(luaL_optinteger)(lua_State* L, int nArg, lua_Integer def);
|
||||||
lua_Integer def);
|
|
||||||
|
|
||||||
LUALIB_API void (luaL_checkstack) (lua_State *L, int sz, const char *msg);
|
LUALIB_API void(luaL_checkstack)(lua_State* L, int sz, const char* msg);
|
||||||
LUALIB_API void (luaL_checktype) (lua_State *L, int narg, int t);
|
LUALIB_API void(luaL_checktype)(lua_State* L, int narg, int t);
|
||||||
LUALIB_API void (luaL_checkany) (lua_State *L, int narg);
|
LUALIB_API void(luaL_checkany)(lua_State* L, int narg);
|
||||||
|
|
||||||
LUALIB_API int (luaL_newmetatable) (lua_State *L, const char *tname);
|
LUALIB_API int(luaL_newmetatable)(lua_State* L, const char* tname);
|
||||||
LUALIB_API void *(luaL_checkudata) (lua_State *L, int ud, const char *tname);
|
LUALIB_API void*(luaL_checkudata)(lua_State * L, int ud, const char* tname);
|
||||||
|
|
||||||
LUALIB_API void (luaL_where) (lua_State *L, int lvl);
|
LUALIB_API void(luaL_where)(lua_State* L, int lvl);
|
||||||
LUALIB_API int (luaL_error) (lua_State *L, const char *fmt, ...);
|
LUALIB_API int(luaL_error)(lua_State* L, const char* fmt, ...);
|
||||||
|
|
||||||
LUALIB_API int (luaL_checkoption) (lua_State *L, int narg, const char *def,
|
LUALIB_API int(luaL_checkoption)(lua_State* L, int narg, const char* def, const char* const lst[]);
|
||||||
const char *const lst[]);
|
|
||||||
|
|
||||||
/* pre-defined references */
|
/* pre-defined references */
|
||||||
#define LUA_NOREF (-2)
|
#define LUA_NOREF (-2)
|
||||||
#define LUA_REFNIL (-1)
|
#define LUA_REFNIL (-1)
|
||||||
|
|
||||||
LUALIB_API int (luaL_ref) (lua_State *L, int t);
|
LUALIB_API int(luaL_ref)(lua_State* L, int t);
|
||||||
LUALIB_API void (luaL_unref) (lua_State *L, int t, int ref);
|
LUALIB_API void(luaL_unref)(lua_State* L, int t, int ref);
|
||||||
|
|
||||||
LUALIB_API int (luaL_loadfile) (lua_State *L, const char *filename);
|
LUALIB_API int(luaL_loadfile)(lua_State* L, const char* filename);
|
||||||
LUALIB_API int (luaL_loadbuffer) (lua_State *L, const char *buff, size_t sz,
|
LUALIB_API int(luaL_loadbuffer)(lua_State* L, const char* buff, size_t sz, const char* name);
|
||||||
const char *name);
|
LUALIB_API int(luaL_loadstring)(lua_State* L, const char* s);
|
||||||
LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s);
|
|
||||||
|
|
||||||
LUALIB_API lua_State *(luaL_newstate) (void);
|
LUALIB_API lua_State*(luaL_newstate)(void);
|
||||||
|
|
||||||
|
LUALIB_API const char*(luaL_gsub)(lua_State * L, const char* s, const char* p, const char* r);
|
||||||
|
|
||||||
LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s, const char *p,
|
LUALIB_API const char*(luaL_findtable)(lua_State * L, int idx, const char* fname, int szhint);
|
||||||
const char *r);
|
|
||||||
|
|
||||||
LUALIB_API const char *(luaL_findtable) (lua_State *L, int idx,
|
|
||||||
const char *fname, int szhint);
|
|
||||||
|
|
||||||
/* From Lua 5.2. */
|
/* From Lua 5.2. */
|
||||||
LUALIB_API int luaL_fileresult(lua_State *L, int stat, const char *fname);
|
LUALIB_API int luaL_fileresult(lua_State* L, int stat, const char* fname);
|
||||||
LUALIB_API int luaL_execresult(lua_State *L, int stat);
|
LUALIB_API int luaL_execresult(lua_State* L, int stat);
|
||||||
LUALIB_API int (luaL_loadfilex) (lua_State *L, const char *filename,
|
LUALIB_API int(luaL_loadfilex)(lua_State* L, const char* filename, const char* mode);
|
||||||
const char *mode);
|
LUALIB_API int(luaL_loadbufferx)(lua_State* L, const char* buff, size_t sz, const char* name, const char* mode);
|
||||||
LUALIB_API int (luaL_loadbufferx) (lua_State *L, const char *buff, size_t sz,
|
LUALIB_API void luaL_traceback(lua_State* L, lua_State* L1, const char* msg, int level);
|
||||||
const char *name, const char *mode);
|
LUALIB_API void(luaL_setfuncs)(lua_State* L, const luaL_Reg* l, int nup);
|
||||||
LUALIB_API void luaL_traceback (lua_State *L, lua_State *L1, const char *msg,
|
LUALIB_API void(luaL_pushmodule)(lua_State* L, const char* modname, int sizehint);
|
||||||
int level);
|
LUALIB_API void*(luaL_testudata)(lua_State * L, int ud, const char* tname);
|
||||||
LUALIB_API void (luaL_setfuncs) (lua_State *L, const luaL_Reg *l, int nup);
|
LUALIB_API void(luaL_setmetatable)(lua_State* L, const char* tname);
|
||||||
LUALIB_API void (luaL_pushmodule) (lua_State *L, const char *modname,
|
|
||||||
int sizehint);
|
|
||||||
LUALIB_API void *(luaL_testudata) (lua_State *L, int ud, const char *tname);
|
|
||||||
LUALIB_API void (luaL_setmetatable) (lua_State *L, const char *tname);
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** ===============================================================
|
** ===============================================================
|
||||||
@@ -98,30 +80,26 @@ LUALIB_API void (luaL_setmetatable) (lua_State *L, const char *tname);
|
|||||||
** ===============================================================
|
** ===============================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define luaL_argcheck(L, cond,numarg,extramsg) \
|
#define luaL_argcheck(L, cond, numarg, extramsg) ((void)((cond) || luaL_argerror(L, (numarg), (extramsg))))
|
||||||
((void)((cond) || luaL_argerror(L, (numarg), (extramsg))))
|
#define luaL_checkstring(L, n) (luaL_checklstring(L, (n), NULL))
|
||||||
#define luaL_checkstring(L,n) (luaL_checklstring(L, (n), NULL))
|
#define luaL_optstring(L, n, d) (luaL_optlstring(L, (n), (d), NULL))
|
||||||
#define luaL_optstring(L,n,d) (luaL_optlstring(L, (n), (d), NULL))
|
#define luaL_checkint(L, n) ((int)luaL_checkinteger(L, (n)))
|
||||||
#define luaL_checkint(L,n) ((int)luaL_checkinteger(L, (n)))
|
#define luaL_optint(L, n, d) ((int)luaL_optinteger(L, (n), (d)))
|
||||||
#define luaL_optint(L,n,d) ((int)luaL_optinteger(L, (n), (d)))
|
#define luaL_checklong(L, n) ((long)luaL_checkinteger(L, (n)))
|
||||||
#define luaL_checklong(L,n) ((long)luaL_checkinteger(L, (n)))
|
#define luaL_optlong(L, n, d) ((long)luaL_optinteger(L, (n), (d)))
|
||||||
#define luaL_optlong(L,n,d) ((long)luaL_optinteger(L, (n), (d)))
|
|
||||||
|
|
||||||
#define luaL_typename(L,i) lua_typename(L, lua_type(L,(i)))
|
#define luaL_typename(L, i) lua_typename(L, lua_type(L, (i)))
|
||||||
|
|
||||||
#define luaL_dofile(L, fn) \
|
#define luaL_dofile(L, fn) (luaL_loadfile(L, fn) || lua_pcall(L, 0, LUA_MULTRET, 0))
|
||||||
(luaL_loadfile(L, fn) || lua_pcall(L, 0, LUA_MULTRET, 0))
|
|
||||||
|
|
||||||
#define luaL_dostring(L, s) \
|
#define luaL_dostring(L, s) (luaL_loadstring(L, s) || lua_pcall(L, 0, LUA_MULTRET, 0))
|
||||||
(luaL_loadstring(L, s) || lua_pcall(L, 0, LUA_MULTRET, 0))
|
|
||||||
|
|
||||||
#define luaL_getmetatable(L,n) (lua_getfield(L, LUA_REGISTRYINDEX, (n)))
|
#define luaL_getmetatable(L, n) (lua_getfield(L, LUA_REGISTRYINDEX, (n)))
|
||||||
|
|
||||||
#define luaL_opt(L,f,n,d) (lua_isnoneornil(L,(n)) ? (d) : f(L,(n)))
|
#define luaL_opt(L, f, n, d) (lua_isnoneornil(L, (n)) ? (d) : f(L, (n)))
|
||||||
|
|
||||||
/* From Lua 5.2. */
|
/* From Lua 5.2. */
|
||||||
#define luaL_newlibtable(L, l) \
|
#define luaL_newlibtable(L, l) lua_createtable(L, 0, sizeof(l) / sizeof((l)[0]) - 1)
|
||||||
lua_createtable(L, 0, sizeof(l)/sizeof((l)[0]) - 1)
|
|
||||||
#define luaL_newlib(L, l) (luaL_newlibtable(L, l), luaL_setfuncs(L, l, 0))
|
#define luaL_newlib(L, l) (luaL_newlibtable(L, l), luaL_setfuncs(L, l, 0))
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -130,31 +108,27 @@ LUALIB_API void (luaL_setmetatable) (lua_State *L, const char *tname);
|
|||||||
** =======================================================
|
** =======================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct luaL_Buffer {
|
typedef struct luaL_Buffer {
|
||||||
char *p; /* current position in buffer */
|
char* p; /* current position in buffer */
|
||||||
int lvl; /* number of strings in the stack (level) */
|
int lvl; /* number of strings in the stack (level) */
|
||||||
lua_State *L;
|
lua_State* L;
|
||||||
char buffer[LUAL_BUFFERSIZE];
|
char buffer[LUAL_BUFFERSIZE];
|
||||||
} luaL_Buffer;
|
} luaL_Buffer;
|
||||||
|
|
||||||
#define luaL_addchar(B,c) \
|
#define luaL_addchar(B, c) \
|
||||||
((void)((B)->p < ((B)->buffer+LUAL_BUFFERSIZE) || luaL_prepbuffer(B)), \
|
((void)((B)->p < ((B)->buffer + LUAL_BUFFERSIZE) || luaL_prepbuffer(B)), (*(B)->p++ = (char)(c)))
|
||||||
(*(B)->p++ = (char)(c)))
|
|
||||||
|
|
||||||
/* compatibility only */
|
/* compatibility only */
|
||||||
#define luaL_putchar(B,c) luaL_addchar(B,c)
|
#define luaL_putchar(B, c) luaL_addchar(B, c)
|
||||||
|
|
||||||
#define luaL_addsize(B,n) ((B)->p += (n))
|
#define luaL_addsize(B, n) ((B)->p += (n))
|
||||||
|
|
||||||
LUALIB_API void (luaL_buffinit) (lua_State *L, luaL_Buffer *B);
|
|
||||||
LUALIB_API char *(luaL_prepbuffer) (luaL_Buffer *B);
|
|
||||||
LUALIB_API void (luaL_addlstring) (luaL_Buffer *B, const char *s, size_t l);
|
|
||||||
LUALIB_API void (luaL_addstring) (luaL_Buffer *B, const char *s);
|
|
||||||
LUALIB_API void (luaL_addvalue) (luaL_Buffer *B);
|
|
||||||
LUALIB_API void (luaL_pushresult) (luaL_Buffer *B);
|
|
||||||
|
|
||||||
|
LUALIB_API void(luaL_buffinit)(lua_State* L, luaL_Buffer* B);
|
||||||
|
LUALIB_API char*(luaL_prepbuffer)(luaL_Buffer * B);
|
||||||
|
LUALIB_API void(luaL_addlstring)(luaL_Buffer* B, const char* s, size_t l);
|
||||||
|
LUALIB_API void(luaL_addstring)(luaL_Buffer* B, const char* s);
|
||||||
|
LUALIB_API void(luaL_addvalue)(luaL_Buffer* B);
|
||||||
|
LUALIB_API void(luaL_pushresult)(luaL_Buffer* B);
|
||||||
|
|
||||||
/* }====================================================== */
|
/* }====================================================== */
|
||||||
|
|
||||||
|
|||||||
310
inc/lua/lua.h
310
inc/lua/lua.h
@@ -5,39 +5,33 @@
|
|||||||
** See Copyright Notice at the end of this file
|
** See Copyright Notice at the end of this file
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#ifndef lua_h
|
#ifndef lua_h
|
||||||
#define lua_h
|
#define lua_h
|
||||||
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
|
|
||||||
#include "luaconf.h"
|
#include "luaconf.h"
|
||||||
|
|
||||||
|
|
||||||
#define LUA_VERSION "Lua 5.1"
|
#define LUA_VERSION "Lua 5.1"
|
||||||
#define LUA_RELEASE "Lua 5.1.4"
|
#define LUA_RELEASE "Lua 5.1.4"
|
||||||
#define LUA_VERSION_NUM 501
|
#define LUA_VERSION_NUM 501
|
||||||
#define LUA_COPYRIGHT "Copyright (C) 1994-2008 Lua.org, PUC-Rio"
|
#define LUA_COPYRIGHT "Copyright (C) 1994-2008 Lua.org, PUC-Rio"
|
||||||
#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo & W. Celes"
|
#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo & W. Celes"
|
||||||
|
|
||||||
|
|
||||||
/* mark for precompiled code (`<esc>Lua') */
|
/* mark for precompiled code (`<esc>Lua') */
|
||||||
#define LUA_SIGNATURE "\033Lua"
|
#define LUA_SIGNATURE "\033Lua"
|
||||||
|
|
||||||
/* option for multiple returns in `lua_pcall' and `lua_call' */
|
/* option for multiple returns in `lua_pcall' and `lua_call' */
|
||||||
#define LUA_MULTRET (-1)
|
#define LUA_MULTRET (-1)
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** pseudo-indices
|
** pseudo-indices
|
||||||
*/
|
*/
|
||||||
#define LUA_REGISTRYINDEX (-10000)
|
#define LUA_REGISTRYINDEX (-10000)
|
||||||
#define LUA_ENVIRONINDEX (-10001)
|
#define LUA_ENVIRONINDEX (-10001)
|
||||||
#define LUA_GLOBALSINDEX (-10002)
|
#define LUA_GLOBALSINDEX (-10002)
|
||||||
#define lua_upvalueindex(i) (LUA_GLOBALSINDEX-(i))
|
#define lua_upvalueindex(i) (LUA_GLOBALSINDEX - (i))
|
||||||
|
|
||||||
|
|
||||||
/* thread status */
|
/* thread status */
|
||||||
#define LUA_OK 0
|
#define LUA_OK 0
|
||||||
@@ -47,25 +41,21 @@
|
|||||||
#define LUA_ERRMEM 4
|
#define LUA_ERRMEM 4
|
||||||
#define LUA_ERRERR 5
|
#define LUA_ERRERR 5
|
||||||
|
|
||||||
|
|
||||||
typedef struct lua_State lua_State;
|
typedef struct lua_State lua_State;
|
||||||
|
|
||||||
typedef int (*lua_CFunction) (lua_State *L);
|
typedef int (*lua_CFunction)(lua_State* L);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** functions that read/write blocks when loading/dumping Lua chunks
|
** functions that read/write blocks when loading/dumping Lua chunks
|
||||||
*/
|
*/
|
||||||
typedef const char * (*lua_Reader) (lua_State *L, void *ud, size_t *sz);
|
typedef const char* (*lua_Reader)(lua_State* L, void* ud, size_t* sz);
|
||||||
|
|
||||||
typedef int (*lua_Writer) (lua_State *L, const void* p, size_t sz, void* ud);
|
|
||||||
|
|
||||||
|
typedef int (*lua_Writer)(lua_State* L, const void* p, size_t sz, void* ud);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** prototype for memory-allocation functions
|
** prototype for memory-allocation functions
|
||||||
*/
|
*/
|
||||||
typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize);
|
typedef void* (*lua_Alloc)(void* ud, void* ptr, size_t osize, size_t nsize);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** basic types
|
** basic types
|
||||||
@@ -82,12 +72,9 @@ typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize);
|
|||||||
#define LUA_TUSERDATA 7
|
#define LUA_TUSERDATA 7
|
||||||
#define LUA_TTHREAD 8
|
#define LUA_TTHREAD 8
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* minimum Lua stack available to a C function */
|
/* minimum Lua stack available to a C function */
|
||||||
#define LUA_MINSTACK 20
|
#define LUA_MINSTACK 20
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** generic extra include file
|
** generic extra include file
|
||||||
*/
|
*/
|
||||||
@@ -95,125 +82,112 @@ typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize);
|
|||||||
#include LUA_USER_H
|
#include LUA_USER_H
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* type of numbers in Lua */
|
/* type of numbers in Lua */
|
||||||
typedef LUA_NUMBER lua_Number;
|
typedef LUA_NUMBER lua_Number;
|
||||||
|
|
||||||
|
|
||||||
/* type for integer functions */
|
/* type for integer functions */
|
||||||
typedef LUA_INTEGER lua_Integer;
|
typedef LUA_INTEGER lua_Integer;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** state manipulation
|
** state manipulation
|
||||||
*/
|
*/
|
||||||
LUA_API lua_State *(lua_newstate) (lua_Alloc f, void *ud);
|
LUA_API lua_State*(lua_newstate)(lua_Alloc f, void* ud);
|
||||||
LUA_API void (lua_close) (lua_State *L);
|
LUA_API void(lua_close)(lua_State* L);
|
||||||
LUA_API lua_State *(lua_newthread) (lua_State *L);
|
LUA_API lua_State*(lua_newthread)(lua_State * L);
|
||||||
|
|
||||||
LUA_API lua_CFunction (lua_atpanic) (lua_State *L, lua_CFunction panicf);
|
|
||||||
|
|
||||||
|
LUA_API lua_CFunction(lua_atpanic)(lua_State* L, lua_CFunction panicf);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** basic stack manipulation
|
** basic stack manipulation
|
||||||
*/
|
*/
|
||||||
LUA_API int (lua_gettop) (lua_State *L);
|
LUA_API int(lua_gettop)(lua_State* L);
|
||||||
LUA_API void (lua_settop) (lua_State *L, int idx);
|
LUA_API void(lua_settop)(lua_State* L, int idx);
|
||||||
LUA_API void (lua_pushvalue) (lua_State *L, int idx);
|
LUA_API void(lua_pushvalue)(lua_State* L, int idx);
|
||||||
LUA_API void (lua_remove) (lua_State *L, int idx);
|
LUA_API void(lua_remove)(lua_State* L, int idx);
|
||||||
LUA_API void (lua_insert) (lua_State *L, int idx);
|
LUA_API void(lua_insert)(lua_State* L, int idx);
|
||||||
LUA_API void (lua_replace) (lua_State *L, int idx);
|
LUA_API void(lua_replace)(lua_State* L, int idx);
|
||||||
LUA_API int (lua_checkstack) (lua_State *L, int sz);
|
LUA_API int(lua_checkstack)(lua_State* L, int sz);
|
||||||
|
|
||||||
LUA_API void (lua_xmove) (lua_State *from, lua_State *to, int n);
|
|
||||||
|
|
||||||
|
LUA_API void(lua_xmove)(lua_State* from, lua_State* to, int n);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** access functions (stack -> C)
|
** access functions (stack -> C)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
LUA_API int (lua_isnumber) (lua_State *L, int idx);
|
LUA_API int(lua_isnumber)(lua_State* L, int idx);
|
||||||
LUA_API int (lua_isstring) (lua_State *L, int idx);
|
LUA_API int(lua_isstring)(lua_State* L, int idx);
|
||||||
LUA_API int (lua_iscfunction) (lua_State *L, int idx);
|
LUA_API int(lua_iscfunction)(lua_State* L, int idx);
|
||||||
LUA_API int (lua_isuserdata) (lua_State *L, int idx);
|
LUA_API int(lua_isuserdata)(lua_State* L, int idx);
|
||||||
LUA_API int (lua_type) (lua_State *L, int idx);
|
LUA_API int(lua_type)(lua_State* L, int idx);
|
||||||
LUA_API const char *(lua_typename) (lua_State *L, int tp);
|
LUA_API const char*(lua_typename)(lua_State * L, int tp);
|
||||||
|
|
||||||
LUA_API int (lua_equal) (lua_State *L, int idx1, int idx2);
|
LUA_API int(lua_equal)(lua_State* L, int idx1, int idx2);
|
||||||
LUA_API int (lua_rawequal) (lua_State *L, int idx1, int idx2);
|
LUA_API int(lua_rawequal)(lua_State* L, int idx1, int idx2);
|
||||||
LUA_API int (lua_lessthan) (lua_State *L, int idx1, int idx2);
|
LUA_API int(lua_lessthan)(lua_State* L, int idx1, int idx2);
|
||||||
|
|
||||||
LUA_API lua_Number (lua_tonumber) (lua_State *L, int idx);
|
|
||||||
LUA_API lua_Integer (lua_tointeger) (lua_State *L, int idx);
|
|
||||||
LUA_API int (lua_toboolean) (lua_State *L, int idx);
|
|
||||||
LUA_API const char *(lua_tolstring) (lua_State *L, int idx, size_t *len);
|
|
||||||
LUA_API size_t (lua_objlen) (lua_State *L, int idx);
|
|
||||||
LUA_API lua_CFunction (lua_tocfunction) (lua_State *L, int idx);
|
|
||||||
LUA_API void *(lua_touserdata) (lua_State *L, int idx);
|
|
||||||
LUA_API lua_State *(lua_tothread) (lua_State *L, int idx);
|
|
||||||
LUA_API const void *(lua_topointer) (lua_State *L, int idx);
|
|
||||||
|
|
||||||
|
LUA_API lua_Number(lua_tonumber)(lua_State* L, int idx);
|
||||||
|
LUA_API lua_Integer(lua_tointeger)(lua_State* L, int idx);
|
||||||
|
LUA_API int(lua_toboolean)(lua_State* L, int idx);
|
||||||
|
LUA_API const char*(lua_tolstring)(lua_State * L, int idx, size_t* len);
|
||||||
|
LUA_API size_t(lua_objlen)(lua_State* L, int idx);
|
||||||
|
LUA_API lua_CFunction(lua_tocfunction)(lua_State* L, int idx);
|
||||||
|
LUA_API void*(lua_touserdata)(lua_State * L, int idx);
|
||||||
|
LUA_API lua_State*(lua_tothread)(lua_State * L, int idx);
|
||||||
|
LUA_API const void*(lua_topointer)(lua_State * L, int idx);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** push functions (C -> stack)
|
** push functions (C -> stack)
|
||||||
*/
|
*/
|
||||||
LUA_API void (lua_pushnil) (lua_State *L);
|
LUA_API void(lua_pushnil)(lua_State* L);
|
||||||
LUA_API void (lua_pushnumber) (lua_State *L, lua_Number n);
|
LUA_API void(lua_pushnumber)(lua_State* L, lua_Number n);
|
||||||
LUA_API void (lua_pushinteger) (lua_State *L, lua_Integer n);
|
LUA_API void(lua_pushinteger)(lua_State* L, lua_Integer n);
|
||||||
LUA_API void (lua_pushlstring) (lua_State *L, const char *s, size_t l);
|
LUA_API void(lua_pushlstring)(lua_State* L, const char* s, size_t l);
|
||||||
LUA_API void (lua_pushstring) (lua_State *L, const char *s);
|
LUA_API void(lua_pushstring)(lua_State* L, const char* s);
|
||||||
LUA_API const char *(lua_pushvfstring) (lua_State *L, const char *fmt,
|
LUA_API const char*(lua_pushvfstring)(lua_State * L, const char* fmt, va_list argp);
|
||||||
va_list argp);
|
LUA_API const char*(lua_pushfstring)(lua_State * L, const char* fmt, ...);
|
||||||
LUA_API const char *(lua_pushfstring) (lua_State *L, const char *fmt, ...);
|
LUA_API void(lua_pushcclosure)(lua_State* L, lua_CFunction fn, int n);
|
||||||
LUA_API void (lua_pushcclosure) (lua_State *L, lua_CFunction fn, int n);
|
LUA_API void(lua_pushboolean)(lua_State* L, int b);
|
||||||
LUA_API void (lua_pushboolean) (lua_State *L, int b);
|
LUA_API void(lua_pushlightuserdata)(lua_State* L, void* p);
|
||||||
LUA_API void (lua_pushlightuserdata) (lua_State *L, void *p);
|
LUA_API int(lua_pushthread)(lua_State* L);
|
||||||
LUA_API int (lua_pushthread) (lua_State *L);
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** get functions (Lua -> stack)
|
** get functions (Lua -> stack)
|
||||||
*/
|
*/
|
||||||
LUA_API void (lua_gettable) (lua_State *L, int idx);
|
LUA_API void(lua_gettable)(lua_State* L, int idx);
|
||||||
LUA_API void (lua_getfield) (lua_State *L, int idx, const char *k);
|
LUA_API void(lua_getfield)(lua_State* L, int idx, const char* k);
|
||||||
LUA_API void (lua_rawget) (lua_State *L, int idx);
|
LUA_API void(lua_rawget)(lua_State* L, int idx);
|
||||||
LUA_API void (lua_rawgeti) (lua_State *L, int idx, int n);
|
LUA_API void(lua_rawgeti)(lua_State* L, int idx, int n);
|
||||||
LUA_API void (lua_createtable) (lua_State *L, int narr, int nrec);
|
LUA_API void(lua_createtable)(lua_State* L, int narr, int nrec);
|
||||||
LUA_API void *(lua_newuserdata) (lua_State *L, size_t sz);
|
LUA_API void*(lua_newuserdata)(lua_State * L, size_t sz);
|
||||||
LUA_API int (lua_getmetatable) (lua_State *L, int objindex);
|
LUA_API int(lua_getmetatable)(lua_State* L, int objindex);
|
||||||
LUA_API void (lua_getfenv) (lua_State *L, int idx);
|
LUA_API void(lua_getfenv)(lua_State* L, int idx);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** set functions (stack -> Lua)
|
** set functions (stack -> Lua)
|
||||||
*/
|
*/
|
||||||
LUA_API void (lua_settable) (lua_State *L, int idx);
|
LUA_API void(lua_settable)(lua_State* L, int idx);
|
||||||
LUA_API void (lua_setfield) (lua_State *L, int idx, const char *k);
|
LUA_API void(lua_setfield)(lua_State* L, int idx, const char* k);
|
||||||
LUA_API void (lua_rawset) (lua_State *L, int idx);
|
LUA_API void(lua_rawset)(lua_State* L, int idx);
|
||||||
LUA_API void (lua_rawseti) (lua_State *L, int idx, int n);
|
LUA_API void(lua_rawseti)(lua_State* L, int idx, int n);
|
||||||
LUA_API int (lua_setmetatable) (lua_State *L, int objindex);
|
LUA_API int(lua_setmetatable)(lua_State* L, int objindex);
|
||||||
LUA_API int (lua_setfenv) (lua_State *L, int idx);
|
LUA_API int(lua_setfenv)(lua_State* L, int idx);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** `load' and `call' functions (load and run Lua code)
|
** `load' and `call' functions (load and run Lua code)
|
||||||
*/
|
*/
|
||||||
LUA_API void (lua_call) (lua_State *L, int nargs, int nresults);
|
LUA_API void(lua_call)(lua_State* L, int nargs, int nresults);
|
||||||
LUA_API int (lua_pcall) (lua_State *L, int nargs, int nresults, int errfunc);
|
LUA_API int(lua_pcall)(lua_State* L, int nargs, int nresults, int errfunc);
|
||||||
LUA_API int (lua_cpcall) (lua_State *L, lua_CFunction func, void *ud);
|
LUA_API int(lua_cpcall)(lua_State* L, lua_CFunction func, void* ud);
|
||||||
LUA_API int (lua_load) (lua_State *L, lua_Reader reader, void *dt,
|
LUA_API int(lua_load)(lua_State* L, lua_Reader reader, void* dt, const char* chunkname);
|
||||||
const char *chunkname);
|
|
||||||
|
|
||||||
LUA_API int (lua_dump) (lua_State *L, lua_Writer writer, void *data);
|
|
||||||
|
|
||||||
|
LUA_API int(lua_dump)(lua_State* L, lua_Writer writer, void* data);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** coroutine functions
|
** coroutine functions
|
||||||
*/
|
*/
|
||||||
LUA_API int (lua_yield) (lua_State *L, int nresults);
|
LUA_API int(lua_yield)(lua_State* L, int nresults);
|
||||||
LUA_API int (lua_resume) (lua_State *L, int narg);
|
LUA_API int(lua_resume)(lua_State* L, int narg);
|
||||||
LUA_API int (lua_status) (lua_State *L);
|
LUA_API int(lua_status)(lua_State* L);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** garbage-collection function and options
|
** garbage-collection function and options
|
||||||
@@ -229,23 +203,20 @@ LUA_API int (lua_status) (lua_State *L);
|
|||||||
#define LUA_GCSETSTEPMUL 7
|
#define LUA_GCSETSTEPMUL 7
|
||||||
#define LUA_GCISRUNNING 9
|
#define LUA_GCISRUNNING 9
|
||||||
|
|
||||||
LUA_API int (lua_gc) (lua_State *L, int what, int data);
|
LUA_API int(lua_gc)(lua_State* L, int what, int data);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** miscellaneous functions
|
** miscellaneous functions
|
||||||
*/
|
*/
|
||||||
|
|
||||||
LUA_API int (lua_error) (lua_State *L);
|
LUA_API int(lua_error)(lua_State* L);
|
||||||
|
|
||||||
LUA_API int (lua_next) (lua_State *L, int idx);
|
LUA_API int(lua_next)(lua_State* L, int idx);
|
||||||
|
|
||||||
LUA_API void (lua_concat) (lua_State *L, int n);
|
|
||||||
|
|
||||||
LUA_API lua_Alloc (lua_getallocf) (lua_State *L, void **ud);
|
|
||||||
LUA_API void lua_setallocf (lua_State *L, lua_Alloc f, void *ud);
|
|
||||||
|
|
||||||
|
LUA_API void(lua_concat)(lua_State* L, int n);
|
||||||
|
|
||||||
|
LUA_API lua_Alloc(lua_getallocf)(lua_State* L, void** ud);
|
||||||
|
LUA_API void lua_setallocf(lua_State* L, lua_Alloc f, void* ud);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** ===============================================================
|
** ===============================================================
|
||||||
@@ -253,34 +224,31 @@ LUA_API void lua_setallocf (lua_State *L, lua_Alloc f, void *ud);
|
|||||||
** ===============================================================
|
** ===============================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define lua_pop(L,n) lua_settop(L, -(n)-1)
|
#define lua_pop(L, n) lua_settop(L, -(n) - 1)
|
||||||
|
|
||||||
#define lua_newtable(L) lua_createtable(L, 0, 0)
|
#define lua_newtable(L) lua_createtable(L, 0, 0)
|
||||||
|
|
||||||
#define lua_register(L,n,f) (lua_pushcfunction(L, (f)), lua_setglobal(L, (n)))
|
#define lua_register(L, n, f) (lua_pushcfunction(L, (f)), lua_setglobal(L, (n)))
|
||||||
|
|
||||||
#define lua_pushcfunction(L,f) lua_pushcclosure(L, (f), 0)
|
#define lua_pushcfunction(L, f) lua_pushcclosure(L, (f), 0)
|
||||||
|
|
||||||
#define lua_strlen(L,i) lua_objlen(L, (i))
|
#define lua_strlen(L, i) lua_objlen(L, (i))
|
||||||
|
|
||||||
#define lua_isfunction(L,n) (lua_type(L, (n)) == LUA_TFUNCTION)
|
#define lua_isfunction(L, n) (lua_type(L, (n)) == LUA_TFUNCTION)
|
||||||
#define lua_istable(L,n) (lua_type(L, (n)) == LUA_TTABLE)
|
#define lua_istable(L, n) (lua_type(L, (n)) == LUA_TTABLE)
|
||||||
#define lua_islightuserdata(L,n) (lua_type(L, (n)) == LUA_TLIGHTUSERDATA)
|
#define lua_islightuserdata(L, n) (lua_type(L, (n)) == LUA_TLIGHTUSERDATA)
|
||||||
#define lua_isnil(L,n) (lua_type(L, (n)) == LUA_TNIL)
|
#define lua_isnil(L, n) (lua_type(L, (n)) == LUA_TNIL)
|
||||||
#define lua_isboolean(L,n) (lua_type(L, (n)) == LUA_TBOOLEAN)
|
#define lua_isboolean(L, n) (lua_type(L, (n)) == LUA_TBOOLEAN)
|
||||||
#define lua_isthread(L,n) (lua_type(L, (n)) == LUA_TTHREAD)
|
#define lua_isthread(L, n) (lua_type(L, (n)) == LUA_TTHREAD)
|
||||||
#define lua_isnone(L,n) (lua_type(L, (n)) == LUA_TNONE)
|
#define lua_isnone(L, n) (lua_type(L, (n)) == LUA_TNONE)
|
||||||
#define lua_isnoneornil(L, n) (lua_type(L, (n)) <= 0)
|
#define lua_isnoneornil(L, n) (lua_type(L, (n)) <= 0)
|
||||||
|
|
||||||
#define lua_pushliteral(L, s) \
|
#define lua_pushliteral(L, s) lua_pushlstring(L, "" s, (sizeof(s) / sizeof(char)) - 1)
|
||||||
lua_pushlstring(L, "" s, (sizeof(s)/sizeof(char))-1)
|
|
||||||
|
|
||||||
#define lua_setglobal(L,s) lua_setfield(L, LUA_GLOBALSINDEX, (s))
|
|
||||||
#define lua_getglobal(L,s) lua_getfield(L, LUA_GLOBALSINDEX, (s))
|
|
||||||
|
|
||||||
#define lua_tostring(L,i) lua_tolstring(L, (i), NULL)
|
|
||||||
|
|
||||||
|
#define lua_setglobal(L, s) lua_setfield(L, LUA_GLOBALSINDEX, (s))
|
||||||
|
#define lua_getglobal(L, s) lua_getfield(L, LUA_GLOBALSINDEX, (s))
|
||||||
|
|
||||||
|
#define lua_tostring(L, i) lua_tolstring(L, (i), NULL)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** compatibility macros and functions
|
** compatibility macros and functions
|
||||||
@@ -295,10 +263,8 @@ LUA_API void lua_setallocf (lua_State *L, lua_Alloc f, void *ud);
|
|||||||
#define lua_Chunkreader lua_Reader
|
#define lua_Chunkreader lua_Reader
|
||||||
#define lua_Chunkwriter lua_Writer
|
#define lua_Chunkwriter lua_Writer
|
||||||
|
|
||||||
|
|
||||||
/* hack */
|
/* hack */
|
||||||
LUA_API void lua_setlevel (lua_State *from, lua_State *to);
|
LUA_API void lua_setlevel(lua_State* from, lua_State* to);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** {======================================================================
|
** {======================================================================
|
||||||
@@ -306,7 +272,6 @@ LUA_API void lua_setlevel (lua_State *from, lua_State *to);
|
|||||||
** =======================================================================
|
** =======================================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Event codes
|
** Event codes
|
||||||
*/
|
*/
|
||||||
@@ -316,7 +281,6 @@ LUA_API void lua_setlevel (lua_State *from, lua_State *to);
|
|||||||
#define LUA_HOOKCOUNT 3
|
#define LUA_HOOKCOUNT 3
|
||||||
#define LUA_HOOKTAILRET 4
|
#define LUA_HOOKTAILRET 4
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Event masks
|
** Event masks
|
||||||
*/
|
*/
|
||||||
@@ -327,42 +291,38 @@ LUA_API void lua_setlevel (lua_State *from, lua_State *to);
|
|||||||
|
|
||||||
typedef struct lua_Debug lua_Debug; /* activation record */
|
typedef struct lua_Debug lua_Debug; /* activation record */
|
||||||
|
|
||||||
|
|
||||||
/* Functions to be called by the debuger in specific events */
|
/* Functions to be called by the debuger in specific events */
|
||||||
typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);
|
typedef void (*lua_Hook)(lua_State* L, lua_Debug* ar);
|
||||||
|
|
||||||
|
LUA_API int lua_getstack(lua_State* L, int level, lua_Debug* ar);
|
||||||
LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar);
|
LUA_API int lua_getinfo(lua_State* L, const char* what, lua_Debug* ar);
|
||||||
LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar);
|
LUA_API const char* lua_getlocal(lua_State* L, const lua_Debug* ar, int n);
|
||||||
LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n);
|
LUA_API const char* lua_setlocal(lua_State* L, const lua_Debug* ar, int n);
|
||||||
LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n);
|
LUA_API const char* lua_getupvalue(lua_State* L, int funcindex, int n);
|
||||||
LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n);
|
LUA_API const char* lua_setupvalue(lua_State* L, int funcindex, int n);
|
||||||
LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n);
|
LUA_API int lua_sethook(lua_State* L, lua_Hook func, int mask, int count);
|
||||||
LUA_API int lua_sethook (lua_State *L, lua_Hook func, int mask, int count);
|
LUA_API lua_Hook lua_gethook(lua_State* L);
|
||||||
LUA_API lua_Hook lua_gethook (lua_State *L);
|
LUA_API int lua_gethookmask(lua_State* L);
|
||||||
LUA_API int lua_gethookmask (lua_State *L);
|
LUA_API int lua_gethookcount(lua_State* L);
|
||||||
LUA_API int lua_gethookcount (lua_State *L);
|
|
||||||
|
|
||||||
/* From Lua 5.2. */
|
/* From Lua 5.2. */
|
||||||
LUA_API void *lua_upvalueid (lua_State *L, int idx, int n);
|
LUA_API void* lua_upvalueid(lua_State* L, int idx, int n);
|
||||||
LUA_API void lua_upvaluejoin (lua_State *L, int idx1, int n1, int idx2, int n2);
|
LUA_API void lua_upvaluejoin(lua_State* L, int idx1, int n1, int idx2, int n2);
|
||||||
LUA_API int lua_loadx (lua_State *L, lua_Reader reader, void *dt,
|
LUA_API int lua_loadx(lua_State* L, lua_Reader reader, void* dt, const char* chunkname, const char* mode);
|
||||||
const char *chunkname, const char *mode);
|
LUA_API const lua_Number* lua_version(lua_State* L);
|
||||||
LUA_API const lua_Number *lua_version (lua_State *L);
|
LUA_API void lua_copy(lua_State* L, int fromidx, int toidx);
|
||||||
LUA_API void lua_copy (lua_State *L, int fromidx, int toidx);
|
LUA_API lua_Number lua_tonumberx(lua_State* L, int idx, int* isnum);
|
||||||
LUA_API lua_Number lua_tonumberx (lua_State *L, int idx, int *isnum);
|
LUA_API lua_Integer lua_tointegerx(lua_State* L, int idx, int* isnum);
|
||||||
LUA_API lua_Integer lua_tointegerx (lua_State *L, int idx, int *isnum);
|
|
||||||
|
|
||||||
/* From Lua 5.3. */
|
/* From Lua 5.3. */
|
||||||
LUA_API int lua_isyieldable (lua_State *L);
|
LUA_API int lua_isyieldable(lua_State* L);
|
||||||
|
|
||||||
|
|
||||||
struct lua_Debug {
|
struct lua_Debug {
|
||||||
int event;
|
int event;
|
||||||
const char *name; /* (n) */
|
const char* name; /* (n) */
|
||||||
const char *namewhat; /* (n) `global', `local', `field', `method' */
|
const char* namewhat; /* (n) `global', `local', `field', `method' */
|
||||||
const char *what; /* (S) `Lua', `C', `main', `tail' */
|
const char* what; /* (S) `Lua', `C', `main', `tail' */
|
||||||
const char *source; /* (S) */
|
const char* source; /* (S) */
|
||||||
int currentline; /* (l) */
|
int currentline; /* (l) */
|
||||||
int nups; /* (u) number of upvalues */
|
int nups; /* (u) number of upvalues */
|
||||||
int linedefined; /* (S) */
|
int linedefined; /* (S) */
|
||||||
@@ -374,29 +334,27 @@ struct lua_Debug {
|
|||||||
|
|
||||||
/* }====================================================================== */
|
/* }====================================================================== */
|
||||||
|
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* Copyright (C) 1994-2008 Lua.org, PUC-Rio. All rights reserved.
|
* Copyright (C) 1994-2008 Lua.org, PUC-Rio. All rights reserved.
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
* a copy of this software and associated documentation files (the
|
* a copy of this software and associated documentation files (the
|
||||||
* "Software"), to deal in the Software without restriction, including
|
* "Software"), to deal in the Software without restriction, including
|
||||||
* without limitation the rights to use, copy, modify, merge, publish,
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
* permit persons to whom the Software is furnished to do so, subject to
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
* the following conditions:
|
* the following conditions:
|
||||||
*
|
*
|
||||||
* The above copyright notice and this permission notice shall be
|
* The above copyright notice and this permission notice shall be
|
||||||
* included in all copies or substantial portions of the Software.
|
* included in all copies or substantial portions of the Software.
|
||||||
*
|
*
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
// C++ wrapper for LuaJIT header files.
|
// C++ wrapper for LuaJIT header files.
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include "lua.h"
|
|
||||||
#include "lauxlib.h"
|
#include "lauxlib.h"
|
||||||
#include "lualib.h"
|
#include "lua.h"
|
||||||
#include "luajit.h"
|
#include "luajit.h"
|
||||||
|
#include "lualib.h"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#ifndef WINVER
|
#ifndef WINVER
|
||||||
#define WINVER 0x0501
|
#define WINVER 0x0501
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
@@ -20,10 +21,8 @@
|
|||||||
*/
|
*/
|
||||||
#define LUA_LDIR "!\\lua\\"
|
#define LUA_LDIR "!\\lua\\"
|
||||||
#define LUA_CDIR "!\\"
|
#define LUA_CDIR "!\\"
|
||||||
#define LUA_PATH_DEFAULT \
|
#define LUA_PATH_DEFAULT ".\\?.lua;" LUA_LDIR "?.lua;" LUA_LDIR "?\\init.lua;"
|
||||||
".\\?.lua;" LUA_LDIR"?.lua;" LUA_LDIR"?\\init.lua;"
|
#define LUA_CPATH_DEFAULT ".\\?.dll;" LUA_CDIR "?.dll;" LUA_CDIR "loadall.dll"
|
||||||
#define LUA_CPATH_DEFAULT \
|
|
||||||
".\\?.dll;" LUA_CDIR"?.dll;" LUA_CDIR"loadall.dll"
|
|
||||||
#else
|
#else
|
||||||
/*
|
/*
|
||||||
** Note to distribution maintainers: do NOT patch the following lines!
|
** Note to distribution maintainers: do NOT patch the following lines!
|
||||||
@@ -77,9 +76,7 @@
|
|||||||
#define LUA_PATH_MARK "?"
|
#define LUA_PATH_MARK "?"
|
||||||
#define LUA_EXECDIR "!"
|
#define LUA_EXECDIR "!"
|
||||||
#define LUA_IGMARK "-"
|
#define LUA_IGMARK "-"
|
||||||
#define LUA_PATH_CONFIG \
|
#define LUA_PATH_CONFIG LUA_DIRSEP "\n" LUA_PATHSEP "\n" LUA_PATH_MARK "\n" LUA_EXECDIR "\n" LUA_IGMARK "\n"
|
||||||
LUA_DIRSEP "\n" LUA_PATHSEP "\n" LUA_PATH_MARK "\n" \
|
|
||||||
LUA_EXECDIR "\n" LUA_IGMARK "\n"
|
|
||||||
|
|
||||||
/* Quoting in error messages. */
|
/* Quoting in error messages. */
|
||||||
#define LUA_QL(x) "'" x "'"
|
#define LUA_QL(x) "'" x "'"
|
||||||
@@ -144,9 +141,16 @@
|
|||||||
#define lua_assert(x) assert(x)
|
#define lua_assert(x) assert(x)
|
||||||
#endif
|
#endif
|
||||||
#ifdef LUA_USE_APICHECK
|
#ifdef LUA_USE_APICHECK
|
||||||
#define luai_apicheck(L, o) { (void)L; assert(o); }
|
#define luai_apicheck(L, o) \
|
||||||
|
{ \
|
||||||
|
(void)L; \
|
||||||
|
assert(o); \
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
#define luai_apicheck(L, o) { (void)L; }
|
#define luai_apicheck(L, o) \
|
||||||
|
{ \
|
||||||
|
(void)L; \
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -62,16 +62,13 @@ enum {
|
|||||||
/* LuaJIT public C API. */
|
/* LuaJIT public C API. */
|
||||||
|
|
||||||
/* Control the JIT engine. */
|
/* Control the JIT engine. */
|
||||||
LUA_API int luaJIT_setmode(lua_State *L, int idx, int mode);
|
LUA_API int luaJIT_setmode(lua_State* L, int idx, int mode);
|
||||||
|
|
||||||
/* Low-overhead profiling API. */
|
/* Low-overhead profiling API. */
|
||||||
typedef void (*luaJIT_profile_callback)(void *data, lua_State *L,
|
typedef void (*luaJIT_profile_callback)(void* data, lua_State* L, int samples, int vmstate);
|
||||||
int samples, int vmstate);
|
LUA_API void luaJIT_profile_start(lua_State* L, const char* mode, luaJIT_profile_callback cb, void* data);
|
||||||
LUA_API void luaJIT_profile_start(lua_State *L, const char *mode,
|
LUA_API void luaJIT_profile_stop(lua_State* L);
|
||||||
luaJIT_profile_callback cb, void *data);
|
LUA_API const char* luaJIT_profile_dumpstack(lua_State* L, const char* fmt, int depth, size_t* len);
|
||||||
LUA_API void luaJIT_profile_stop(lua_State *L);
|
|
||||||
LUA_API const char *luaJIT_profile_dumpstack(lua_State *L, const char *fmt,
|
|
||||||
int depth, size_t *len);
|
|
||||||
|
|
||||||
/* Enforce (dynamic) linker error for version mismatches. Call from main. */
|
/* Enforce (dynamic) linker error for version mismatches. Call from main. */
|
||||||
LUA_API void LUAJIT_VERSION_SYM(void);
|
LUA_API void LUAJIT_VERSION_SYM(void);
|
||||||
|
|||||||
@@ -22,19 +22,19 @@
|
|||||||
#define LUA_JITLIBNAME "jit"
|
#define LUA_JITLIBNAME "jit"
|
||||||
#define LUA_FFILIBNAME "ffi"
|
#define LUA_FFILIBNAME "ffi"
|
||||||
|
|
||||||
LUALIB_API int luaopen_base(lua_State *L);
|
LUALIB_API int luaopen_base(lua_State* L);
|
||||||
LUALIB_API int luaopen_math(lua_State *L);
|
LUALIB_API int luaopen_math(lua_State* L);
|
||||||
LUALIB_API int luaopen_string(lua_State *L);
|
LUALIB_API int luaopen_string(lua_State* L);
|
||||||
LUALIB_API int luaopen_table(lua_State *L);
|
LUALIB_API int luaopen_table(lua_State* L);
|
||||||
LUALIB_API int luaopen_io(lua_State *L);
|
LUALIB_API int luaopen_io(lua_State* L);
|
||||||
LUALIB_API int luaopen_os(lua_State *L);
|
LUALIB_API int luaopen_os(lua_State* L);
|
||||||
LUALIB_API int luaopen_package(lua_State *L);
|
LUALIB_API int luaopen_package(lua_State* L);
|
||||||
LUALIB_API int luaopen_debug(lua_State *L);
|
LUALIB_API int luaopen_debug(lua_State* L);
|
||||||
LUALIB_API int luaopen_bit(lua_State *L);
|
LUALIB_API int luaopen_bit(lua_State* L);
|
||||||
LUALIB_API int luaopen_jit(lua_State *L);
|
LUALIB_API int luaopen_jit(lua_State* L);
|
||||||
LUALIB_API int luaopen_ffi(lua_State *L);
|
LUALIB_API int luaopen_ffi(lua_State* L);
|
||||||
|
|
||||||
LUALIB_API void luaL_openlibs(lua_State *L);
|
LUALIB_API void luaL_openlibs(lua_State* L);
|
||||||
|
|
||||||
#ifndef lua_assert
|
#ifndef lua_assert
|
||||||
#define lua_assert(x) ((void)0)
|
#define lua_assert(x) ((void)0)
|
||||||
|
|||||||
@@ -2,15 +2,18 @@
|
|||||||
//////////////////////////////////////////////////
|
//////////////////////////////////////////////////
|
||||||
// BlFuncs Version 1.0
|
// BlFuncs Version 1.0
|
||||||
|
|
||||||
|
|
||||||
// Includes
|
// Includes
|
||||||
|
#ifndef WIN32_LEAN_AND_MEAN
|
||||||
#include "BlHooks.hpp"
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#endif
|
||||||
#include "BlFuncs.hpp"
|
#include "BlFuncs.hpp"
|
||||||
|
#include <Windows.h>
|
||||||
|
#include "BlHooks.hpp"
|
||||||
|
|
||||||
|
#include <cstdarg>
|
||||||
|
#include <cstring>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
|
||||||
// Scanned structures
|
// Scanned structures
|
||||||
|
|
||||||
ADDR tsf_mCacheSequence;
|
ADDR tsf_mCacheSequence;
|
||||||
@@ -18,21 +21,20 @@ ADDR tsf_mCacheAllocator;
|
|||||||
ADDR tsf_gIdDictionary;
|
ADDR tsf_gIdDictionary;
|
||||||
ADDR tsf_gEvalState_globalVars;
|
ADDR tsf_gEvalState_globalVars;
|
||||||
|
|
||||||
BlFunctionDefIntern(tsf_BlStringTable__insert );
|
BlFunctionDefIntern(tsf_BlStringTable__insert);
|
||||||
BlFunctionDefIntern(tsf_BlNamespace__find );
|
BlFunctionDefIntern(tsf_BlNamespace__find);
|
||||||
BlFunctionDefIntern(tsf_BlNamespace__createLocalEntry);
|
BlFunctionDefIntern(tsf_BlNamespace__createLocalEntry);
|
||||||
BlFunctionDefIntern(tsf_BlDataChunker__freeBlocks );
|
BlFunctionDefIntern(tsf_BlDataChunker__freeBlocks);
|
||||||
BlFunctionDefIntern(tsf_BlCon__evaluate );
|
BlFunctionDefIntern(tsf_BlCon__evaluate);
|
||||||
BlFunctionDefIntern(tsf_BlCon__executef );
|
BlFunctionDefIntern(tsf_BlCon__executef);
|
||||||
BlFunctionDefIntern(tsf_BlCon__executefSimObj );
|
BlFunctionDefIntern(tsf_BlCon__executefSimObj);
|
||||||
BlFunctionDefIntern(tsf_BlCon__getVariable );
|
BlFunctionDefIntern(tsf_BlCon__getVariable);
|
||||||
BlFunctionDefIntern(tsf_BlDictionary__addVariable );
|
BlFunctionDefIntern(tsf_BlDictionary__addVariable);
|
||||||
BlFunctionDefIntern(tsf_BlSim__findObject_name );
|
BlFunctionDefIntern(tsf_BlSim__findObject_name);
|
||||||
BlFunctionDefIntern(tsf_BlStringStack__getArgBuffer );
|
BlFunctionDefIntern(tsf_BlStringStack__getArgBuffer);
|
||||||
BlFunctionDefIntern(tsf_BlSimObject__getDataField );
|
BlFunctionDefIntern(tsf_BlSimObject__getDataField);
|
||||||
BlFunctionDefIntern(tsf_BlSimObject__setDataField );
|
BlFunctionDefIntern(tsf_BlSimObject__setDataField);
|
||||||
BlFunctionDefIntern(tsf_BlCon__getReturnBuffer );
|
BlFunctionDefIntern(tsf_BlCon__getReturnBuffer);
|
||||||
|
|
||||||
|
|
||||||
// C->TS Args
|
// C->TS Args
|
||||||
|
|
||||||
@@ -41,30 +43,30 @@ char* tsf_GetIntArg(signed int value) {
|
|||||||
snprintf(ret, 16, "%d", value);
|
snprintf(ret, 16, "%d", value);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
char* tsf_GetFloatArg(float value) {
|
char* tsf_GetFloatArg(float value) {
|
||||||
char* ret = tsf_BlStringStack__getArgBuffer(32);
|
char* ret = tsf_BlStringStack__getArgBuffer(32);
|
||||||
snprintf(ret, 32, "%g", value);
|
snprintf(ret, 32, "%g", value);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
char* tsf_GetStringArg(char* value) {
|
char* tsf_GetStringArg(char* value) {
|
||||||
int len = strlen(value)+1;
|
int len = strlen(value) + 1;
|
||||||
char* ret = tsf_BlStringStack__getArgBuffer(len);
|
char* ret = tsf_BlStringStack__getArgBuffer(len);
|
||||||
memcpy(ret, value, len);
|
memcpy(ret, value, len);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
char* tsf_GetThisArg(ADDR obj) {
|
|
||||||
return tsf_GetIntArg(*(signed int *)(obj + 32));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
char* tsf_GetThisArg(ADDR obj) { return tsf_GetIntArg(*(signed int*)(obj + 32)); }
|
||||||
|
|
||||||
// Eval
|
// Eval
|
||||||
|
|
||||||
const char* tsf_Eval(const char *code) {
|
const char* tsf_Eval(const char* code) {
|
||||||
const char *argv[] = {nullptr, code};
|
const char* argv[] = {nullptr, code};
|
||||||
return tsf_BlCon__evaluate(0, 2, argv);
|
return tsf_BlCon__evaluate(0, 2, argv);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* tsf_Evalf(const char *fmt, ...) {
|
const char* tsf_Evalf(const char* fmt, ...) {
|
||||||
va_list args;
|
va_list args;
|
||||||
char code[4096];
|
char code[4096];
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
@@ -74,50 +76,47 @@ const char* tsf_Evalf(const char *fmt, ...) {
|
|||||||
return tsf_Eval((const char*)code);
|
return tsf_Eval((const char*)code);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Objects
|
// Objects
|
||||||
|
|
||||||
ADDR tsf_FindObject(unsigned int id) {
|
ADDR tsf_FindObject(unsigned int id) {
|
||||||
ADDR obj = *(ADDR*)(*(ADDR*)(tsf_gIdDictionary) + 4*(id & 0xFFF));
|
ADDR obj = *(ADDR*)(*(ADDR*)(tsf_gIdDictionary) + 4 * (id & 0xFFF));
|
||||||
if(!obj) return 0;
|
if (!obj)
|
||||||
|
return 0;
|
||||||
|
|
||||||
while(obj && *(unsigned int *)(obj + 32) != id) {
|
while (obj && *(unsigned int*)(obj + 32) != id) {
|
||||||
obj = *(ADDR*)(obj + 16);
|
obj = *(ADDR*)(obj + 16);
|
||||||
if(!obj) return 0;
|
if (!obj)
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
ADDR tsf_FindObject(const char* name) {
|
ADDR tsf_FindObject(const char* name) { return (ADDR)tsf_BlSim__findObject_name(name); }
|
||||||
return (ADDR)tsf_BlSim__findObject_name(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
ADDR tsf_LookupNamespace(const char* ns, const char* package) {
|
ADDR tsf_LookupNamespace(const char* ns, const char* package) {
|
||||||
const char* ste_package;
|
const char* ste_package;
|
||||||
if(package) {
|
if (package) {
|
||||||
ste_package = tsf_BlStringTable__insert(package, 0);
|
ste_package = tsf_BlStringTable__insert(package, 0);
|
||||||
} else {
|
} else {
|
||||||
ste_package = nullptr;
|
ste_package = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(ns) {
|
if (ns) {
|
||||||
const char* ste_namespace = tsf_BlStringTable__insert(ns, 0);
|
const char* ste_namespace = tsf_BlStringTable__insert(ns, 0);
|
||||||
return tsf_BlNamespace__find(ste_namespace, ste_package);
|
return tsf_BlNamespace__find(ste_namespace, ste_package);
|
||||||
} else {
|
} else {
|
||||||
return tsf_BlNamespace__find(nullptr, ste_package);
|
return tsf_BlNamespace__find(nullptr, ste_package);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ADDR tsf_LookupNamespace(const char* ns) {
|
|
||||||
return tsf_LookupNamespace(ns, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
ADDR tsf_LookupNamespace(const char* ns) { return tsf_LookupNamespace(ns, nullptr); }
|
||||||
|
|
||||||
// Object Fields
|
// Object Fields
|
||||||
|
|
||||||
const char* tsf_GetDataField(ADDR simObject, const char* slotName, const char* array) {
|
const char* tsf_GetDataField(ADDR simObject, const char* slotName, const char* array) {
|
||||||
const char *ste_slotName;
|
const char* ste_slotName;
|
||||||
if(slotName) {
|
if (slotName) {
|
||||||
ste_slotName = tsf_BlStringTable__insert(slotName, 0);
|
ste_slotName = tsf_BlStringTable__insert(slotName, 0);
|
||||||
} else {
|
} else {
|
||||||
ste_slotName = nullptr;
|
ste_slotName = nullptr;
|
||||||
@@ -128,7 +127,7 @@ const char* tsf_GetDataField(ADDR simObject, const char* slotName, const char* a
|
|||||||
|
|
||||||
void tsf_SetDataField(ADDR simObject, const char* slotName, const char* array, const char* value) {
|
void tsf_SetDataField(ADDR simObject, const char* slotName, const char* array, const char* value) {
|
||||||
const char* ste_slotName;
|
const char* ste_slotName;
|
||||||
if(slotName) {
|
if (slotName) {
|
||||||
ste_slotName = tsf_BlStringTable__insert(slotName, 0);
|
ste_slotName = tsf_BlStringTable__insert(slotName, 0);
|
||||||
} else {
|
} else {
|
||||||
ste_slotName = nullptr;
|
ste_slotName = nullptr;
|
||||||
@@ -137,93 +136,162 @@ void tsf_SetDataField(ADDR simObject, const char* slotName, const char* array, c
|
|||||||
tsf_BlSimObject__setDataField(simObject, ste_slotName, array, value);
|
tsf_BlSimObject__setDataField(simObject, ste_slotName, array, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// TS Global Variables
|
// TS Global Variables
|
||||||
|
|
||||||
const char *tsf_GetVar(const char* name) {
|
const char* tsf_GetVar(const char* name) { return tsf_BlCon__getVariable(name); }
|
||||||
return tsf_BlCon__getVariable(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
void tsf_AddVarInternal(const char* name, signed int varType, void* data) {
|
void tsf_AddVarInternal(const char* name, signed int varType, void* data) {
|
||||||
tsf_BlDictionary__addVariable((ADDR *)tsf_gEvalState_globalVars, name, varType, data);
|
tsf_BlDictionary__addVariable((ADDR*)tsf_gEvalState_globalVars, name, varType, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void tsf_AddVar(const char* name, const char** data) {
|
void tsf_AddVar(const char* name, const char** data) { tsf_AddVarInternal(name, 10, data); }
|
||||||
tsf_AddVarInternal(name, 10, data);
|
|
||||||
}
|
|
||||||
void tsf_AddVar(const char* name, signed int* data) {
|
|
||||||
tsf_AddVarInternal(name, 4, data);
|
|
||||||
}
|
|
||||||
void tsf_AddVar(const char* name, float* data) {
|
|
||||||
tsf_AddVarInternal(name, 8, data);
|
|
||||||
}
|
|
||||||
void tsf_AddVar(const char* name, bool* data) {
|
|
||||||
tsf_AddVarInternal(name, 6, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
void tsf_AddVar(const char* name, signed int* data) { tsf_AddVarInternal(name, 4, data); }
|
||||||
|
|
||||||
|
void tsf_AddVar(const char* name, float* data) { tsf_AddVarInternal(name, 8, data); }
|
||||||
|
|
||||||
|
void tsf_AddVar(const char* name, bool* data) { tsf_AddVarInternal(name, 6, data); }
|
||||||
|
|
||||||
// TS->C Functions
|
// TS->C Functions
|
||||||
|
|
||||||
ADDR tsf_AddConsoleFuncInternal(const char* pname, const char* cname, const char* fname, signed int cbtype, const char* usage, signed int mina, signed int maxa) {
|
ADDR tsf_AddConsoleFuncInternal(
|
||||||
const char *ste_fname = tsf_BlStringTable__insert(fname, 0);
|
const char* pname,
|
||||||
|
const char* cname,
|
||||||
|
const char* fname,
|
||||||
|
signed int cbtype,
|
||||||
|
const char* usage,
|
||||||
|
signed int mina,
|
||||||
|
signed int maxa) {
|
||||||
|
const char* ste_fname = tsf_BlStringTable__insert(fname, 0);
|
||||||
ADDR ns = tsf_LookupNamespace(cname, pname);
|
ADDR ns = tsf_LookupNamespace(cname, pname);
|
||||||
ADDR ent = tsf_BlNamespace__createLocalEntry(ns, ste_fname);
|
ADDR ent = tsf_BlNamespace__createLocalEntry(ns, ste_fname);
|
||||||
|
|
||||||
*(signed int *)tsf_mCacheSequence += 1;
|
*(signed int*)tsf_mCacheSequence += 1;
|
||||||
tsf_BlDataChunker__freeBlocks(*(ADDR *)tsf_mCacheAllocator);
|
tsf_BlDataChunker__freeBlocks(*(ADDR*)tsf_mCacheAllocator);
|
||||||
|
|
||||||
*(const char**)(ent + 24) = usage ;
|
*(const char**)(ent + 24) = usage;
|
||||||
*(signed int* )(ent + 16) = mina ;
|
*(signed int*)(ent + 16) = mina;
|
||||||
*(signed int* )(ent + 20) = maxa ;
|
*(signed int*)(ent + 20) = maxa;
|
||||||
*(signed int* )(ent + 12) = cbtype;
|
*(signed int*)(ent + 12) = cbtype;
|
||||||
|
|
||||||
return ent;
|
return ent;
|
||||||
}
|
}
|
||||||
|
|
||||||
void tsf_AddConsoleFunc(const char* pname, const char* cname, const char* fname, tsf_StringCallback sc, const char* usage, signed int mina, signed int maxa) {
|
void tsf_AddConsoleFunc(
|
||||||
|
const char* pname,
|
||||||
|
const char* cname,
|
||||||
|
const char* fname,
|
||||||
|
tsf_StringCallback sc,
|
||||||
|
const char* usage,
|
||||||
|
signed int mina,
|
||||||
|
signed int maxa) {
|
||||||
ADDR ent = tsf_AddConsoleFuncInternal(pname, cname, fname, 1, usage, mina, maxa);
|
ADDR ent = tsf_AddConsoleFuncInternal(pname, cname, fname, 1, usage, mina, maxa);
|
||||||
*(tsf_StringCallback *)(ent + 40) = sc;
|
*(tsf_StringCallback*)(ent + 40) = sc;
|
||||||
}
|
|
||||||
void tsf_AddConsoleFunc(const char* pname, const char* cname, const char* fname, tsf_IntCallback ic, const char* usage, signed int mina, signed int maxa) {
|
|
||||||
ADDR ent = tsf_AddConsoleFuncInternal(pname, cname, fname, 2, usage, mina, maxa);
|
|
||||||
*(tsf_IntCallback *)(ent + 40) = ic;
|
|
||||||
}
|
|
||||||
void tsf_AddConsoleFunc(const char* pname, const char* cname, const char* fname, tsf_FloatCallback fc, const char* usage, signed int mina, signed int maxa) {
|
|
||||||
ADDR ent = tsf_AddConsoleFuncInternal(pname, cname, fname, 3, usage, mina, maxa);
|
|
||||||
*(tsf_FloatCallback *)(ent + 40) = fc;
|
|
||||||
}
|
|
||||||
void tsf_AddConsoleFunc(const char* pname, const char* cname, const char* fname, tsf_VoidCallback vc, const char* usage, signed int mina, signed int maxa) {
|
|
||||||
ADDR ent = tsf_AddConsoleFuncInternal(pname, cname, fname, 4, usage, mina, maxa);
|
|
||||||
*(tsf_VoidCallback *)(ent + 40) = vc;
|
|
||||||
}
|
|
||||||
void tsf_AddConsoleFunc(const char* pname, const char* cname, const char* fname, tsf_BoolCallback bc, const char* usage, signed int mina, signed int maxa) {
|
|
||||||
ADDR ent = tsf_AddConsoleFuncInternal(pname, cname, fname, 5, usage, mina, maxa);
|
|
||||||
*(tsf_BoolCallback *)(ent + 40) = bc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tsf_AddConsoleFunc(
|
||||||
|
const char* pname,
|
||||||
|
const char* cname,
|
||||||
|
const char* fname,
|
||||||
|
tsf_IntCallback ic,
|
||||||
|
const char* usage,
|
||||||
|
signed int mina,
|
||||||
|
signed int maxa) {
|
||||||
|
ADDR ent = tsf_AddConsoleFuncInternal(pname, cname, fname, 2, usage, mina, maxa);
|
||||||
|
*(tsf_IntCallback*)(ent + 40) = ic;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tsf_AddConsoleFunc(
|
||||||
|
const char* pname,
|
||||||
|
const char* cname,
|
||||||
|
const char* fname,
|
||||||
|
tsf_FloatCallback fc,
|
||||||
|
const char* usage,
|
||||||
|
signed int mina,
|
||||||
|
signed int maxa) {
|
||||||
|
ADDR ent = tsf_AddConsoleFuncInternal(pname, cname, fname, 3, usage, mina, maxa);
|
||||||
|
*(tsf_FloatCallback*)(ent + 40) = fc;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tsf_AddConsoleFunc(
|
||||||
|
const char* pname,
|
||||||
|
const char* cname,
|
||||||
|
const char* fname,
|
||||||
|
tsf_VoidCallback vc,
|
||||||
|
const char* usage,
|
||||||
|
signed int mina,
|
||||||
|
signed int maxa) {
|
||||||
|
ADDR ent = tsf_AddConsoleFuncInternal(pname, cname, fname, 4, usage, mina, maxa);
|
||||||
|
*(tsf_VoidCallback*)(ent + 40) = vc;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tsf_AddConsoleFunc(
|
||||||
|
const char* pname,
|
||||||
|
const char* cname,
|
||||||
|
const char* fname,
|
||||||
|
tsf_BoolCallback bc,
|
||||||
|
const char* usage,
|
||||||
|
signed int mina,
|
||||||
|
signed int maxa) {
|
||||||
|
ADDR ent = tsf_AddConsoleFuncInternal(pname, cname, fname, 5, usage, mina, maxa);
|
||||||
|
*(tsf_BoolCallback*)(ent + 40) = bc;
|
||||||
|
}
|
||||||
|
|
||||||
// Initialization
|
// Initialization
|
||||||
|
|
||||||
bool tsf_InitInternal() {
|
bool tsf_InitInternal() {
|
||||||
BlScanFunctionText(tsf_BlStringTable__insert , "83 EC 0C 80 3D ? ? ? ? ?" );
|
BlScanFunctionText(tsf_BlStringTable__insert, "83 EC 0C 80 3D ? ? ? ? ?");
|
||||||
BlScanFunctionText(tsf_BlNamespace__find , "55 8B EC 6A FF 68 ? ? ? ? 64 A1 ? ? ? ? 50 83 EC 0C 53 56 57 A1 ? ? ? ? 33 C5 50 8D 45 F4 64 A3 ? ? ? ? 8B DA 8B D1" );
|
BlScanFunctionText(
|
||||||
BlScanFunctionText(tsf_BlNamespace__createLocalEntry, "55 8B EC 6A FF 68 ? ? ? ? 64 A1 ? ? ? ? 50 83 EC 08 53 56 57 A1 ? ? ? ? 33 C5 50 8D 45 F4 64 A3 ? ? ? ? 89 4D F0" );
|
tsf_BlNamespace__find,
|
||||||
BlScanFunctionText(tsf_BlDataChunker__freeBlocks , "55 8B EC 6A FF 68 ? ? ? ? 64 A1 ? ? ? ? 50 51 53 56 57 A1 ? ? ? ? 33 C5 50 8D 45 F4 64 A3 ? ? ? ? 8B D9 8B 33" );
|
"55 8B EC 6A FF 68 ? ? ? ? 64 A1 ? ? ? ? 50 83 EC 0C 53 56 57 A1 ? ? ? ? "
|
||||||
BlScanFunctionText(tsf_BlCon__evaluate , "55 8B EC 6A FF 68 ? ? ? ? 64 A1 ? ? ? ? 50 56 57 A1 ? ? ? ? 33 C5 50 8D 45 F4 64 A3 ? ? ? ? 8B 75 10" );
|
"33 C5 50 8D 45 F4 64 A3 ? ? ? ? 8B DA 8B D1");
|
||||||
BlScanFunctionText(tsf_BlCon__executef , "81 EC ? ? ? ? A1 ? ? ? ? 33 C4 89 84 24 ? ? ? ? 53 55 56 8B B4 24 ? ? ? ? 33 C9" );
|
BlScanFunctionText(
|
||||||
BlScanFunctionText(tsf_BlCon__executefSimObj , "81 EC ? ? ? ? A1 ? ? ? ? 33 C4 89 84 24 ? ? ? ? 53 56 8B B4 24 ? ? ? ? 33 C9" );
|
tsf_BlNamespace__createLocalEntry,
|
||||||
BlScanFunctionText(tsf_BlCon__getVariable , "53 56 8B F1 57 85 F6 0F 84 ? ? ? ?" );
|
"55 8B EC 6A FF 68 ? ? ? ? 64 A1 ? ? ? ? 50 83 EC 08 53 56 57 A1 ? ? ? ? "
|
||||||
BlScanFunctionText(tsf_BlDictionary__addVariable , "8B 44 24 04 56 57 8B F9" );
|
"33 C5 50 8D 45 F4 64 A3 ? ? ? ? 89 4D F0");
|
||||||
BlScanFunctionText(tsf_BlSim__findObject_name , "57 8B F9 8A 17" );
|
BlScanFunctionText(
|
||||||
BlScanFunctionText(tsf_BlStringStack__getArgBuffer , "55 8B EC 83 E4 F8 8B 0D ? ? ? ? A1 ? ? ? ? 56 57 8B 7D 08 8D 14 01 03 D7 3B 15 ? ? ? ? 72 2C 8B 0D" );
|
tsf_BlDataChunker__freeBlocks,
|
||||||
BlScanFunctionText(tsf_BlSimObject__getDataField , "51 53 8B D9 55 56 8B 74 24 14" );
|
"55 8B EC 6A FF 68 ? ? ? ? 64 A1 ? ? ? ? 50 51 53 56 57 "
|
||||||
BlScanFunctionText(tsf_BlSimObject__setDataField , "81 EC ? ? ? ? A1 ? ? ? ? 33 C4 89 84 24 ? ? ? ? 8B 84 24 ? ? ? ? 53 8B D9 89 44 24 04" );
|
"A1 ? ? ? ? 33 C5 50 8D 45 F4 64 A3 ? ? ? ? 8B D9 8B 33");
|
||||||
BlScanFunctionText(tsf_BlCon__getReturnBuffer , "81 F9 ? ? ? ? 76 2B" );
|
BlScanFunctionText(
|
||||||
|
tsf_BlCon__evaluate,
|
||||||
|
"55 8B EC 6A FF 68 ? ? ? ? 64 A1 ? ? ? ? 50 56 57 A1 ? ? "
|
||||||
|
"? ? 33 C5 50 8D 45 F4 64 A3 ? ? ? ? 8B 75 10");
|
||||||
|
BlScanFunctionText(
|
||||||
|
tsf_BlCon__executef,
|
||||||
|
"81 EC ? ? ? ? A1 ? ? ? ? 33 C4 89 84 24 ? ? ? ? 53 55 56 "
|
||||||
|
"8B B4 24 ? ? ? ? 33 C9");
|
||||||
|
BlScanFunctionText(
|
||||||
|
tsf_BlCon__executefSimObj,
|
||||||
|
"81 EC ? ? ? ? A1 ? ? ? ? 33 C4 89 84 24 ? ? ? ? 53 56 8B "
|
||||||
|
"B4 24 ? ? ? ? 33 C9");
|
||||||
|
BlScanFunctionText(tsf_BlCon__getVariable, "53 56 8B F1 57 85 F6 0F 84 ? ? ? ?");
|
||||||
|
BlScanFunctionText(tsf_BlDictionary__addVariable, "8B 44 24 04 56 57 8B F9");
|
||||||
|
BlScanFunctionText(tsf_BlSim__findObject_name, "57 8B F9 8A 17");
|
||||||
|
BlScanFunctionText(
|
||||||
|
tsf_BlStringStack__getArgBuffer,
|
||||||
|
"55 8B EC 83 E4 F8 8B 0D ? ? ? ? A1 ? ? ? ? 56 57 8B 7D "
|
||||||
|
"08 8D 14 01 03 D7 3B 15 ? ? ? ? 72 2C 8B 0D");
|
||||||
|
BlScanFunctionText(tsf_BlSimObject__getDataField, "51 53 8B D9 55 56 8B 74 24 14");
|
||||||
|
BlScanFunctionText(
|
||||||
|
tsf_BlSimObject__setDataField,
|
||||||
|
"81 EC ? ? ? ? A1 ? ? ? ? 33 C4 89 84 24 ? ? ? ? 8B 84 24 "
|
||||||
|
"? ? ? ? 53 8B D9 89 44 24 04");
|
||||||
|
BlScanFunctionText(tsf_BlCon__getReturnBuffer, "81 F9 ? ? ? ? 76 2B");
|
||||||
|
|
||||||
ADDR BlScanText (tsf_mCacheSequenceLoc , "FF 05 ? ? ? ? B9 ? ? ? ? 8B F8 E8 ? ? ? ? 8B 44 24 1C 89 47 18 8B 44 24 14" );
|
ADDR BlScanText(
|
||||||
ADDR BlScanText (tsf_mCacheAllocatorLoc , "89 35 ? ? ? ? C7 06 ? ? ? ? A1 ? ? ? ? 68 ? ? ? ? C7 40 ? ? ? ? ? E8 ? ? ? ? 83 C4 04 8B 4D F4 64 89 0D ? ? ? ? 59 5E 8B E5 5D C3");
|
tsf_mCacheSequenceLoc,
|
||||||
ADDR BlScanText (tsf_gIdDictionaryLoc , "89 15 ? ? ? ? E8 ? ? ? ? 8B F0 89 75 F0" );
|
"FF 05 ? ? ? ? B9 ? ? ? ? 8B F8 E8 ? ? ? ? 8B 44 24 1C 89 47 "
|
||||||
ADDR BlScanText (tsf_gEvalState_globalVarsLoc , "B9 ? ? ? ? E8 ? ? ? ? 68 ? ? ? ? 6A 0A 68 ? ? ? ? B9 ? ? ? ? E8 ? ? ? ? E8 ? ? ? ?" );
|
"18 8B 44 24 14");
|
||||||
|
ADDR BlScanText(
|
||||||
|
tsf_mCacheAllocatorLoc,
|
||||||
|
"89 35 ? ? ? ? C7 06 ? ? ? ? A1 ? ? ? ? 68 ? ? ? ? C7 40 ? ? ? ? ? E8 ? "
|
||||||
|
"? ? ? 83 C4 04 8B 4D F4 64 89 0D ? ? ? ? 59 5E 8B E5 5D C3");
|
||||||
|
ADDR BlScanText(tsf_gIdDictionaryLoc, "89 15 ? ? ? ? E8 ? ? ? ? 8B F0 89 75 F0");
|
||||||
|
ADDR BlScanText(
|
||||||
|
tsf_gEvalState_globalVarsLoc,
|
||||||
|
"B9 ? ? ? ? E8 ? ? ? ? 68 ? ? ? ? 6A 0A 68 ? ? ? ? B9 ? ? ? "
|
||||||
|
"? E8 ? ? ? ? E8 ? ? ? ?");
|
||||||
|
|
||||||
tsf_mCacheSequence = *(ADDR*)(tsf_mCacheSequenceLoc + 2);
|
tsf_mCacheSequence = *(ADDR*)(tsf_mCacheSequenceLoc + 2);
|
||||||
tsf_mCacheAllocator = *(ADDR*)(tsf_mCacheAllocatorLoc + 2);
|
tsf_mCacheAllocator = *(ADDR*)(tsf_mCacheAllocatorLoc + 2);
|
||||||
@@ -233,6 +301,4 @@ bool tsf_InitInternal() {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool tsf_DeinitInternal() {
|
bool tsf_DeinitInternal() { return true; }
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -5,49 +5,49 @@
|
|||||||
#ifndef _H_BLFUNCS
|
#ifndef _H_BLFUNCS
|
||||||
#define _H_BLFUNCS
|
#define _H_BLFUNCS
|
||||||
|
|
||||||
// Require BlHooks to be included before this header
|
// Ensure BlHooks is available (include it if not already included)
|
||||||
#ifndef _H_BLHOOKS
|
#ifndef _H_BLHOOKS
|
||||||
#error "BlFuncs.hpp: You must include BlHooks.hpp first"
|
#include "BlHooks.hpp"
|
||||||
#else
|
#endif
|
||||||
|
|
||||||
typedef const char * (*tsf_StringCallback)(ADDR, signed int, const char *[]);
|
typedef const char* (*tsf_StringCallback)(ADDR, signed int, const char*[]);
|
||||||
typedef signed int (*tsf_IntCallback )(ADDR, signed int, const char *[]);
|
typedef signed int (*tsf_IntCallback)(ADDR, signed int, const char*[]);
|
||||||
typedef float (*tsf_FloatCallback )(ADDR, signed int, const char *[]);
|
typedef float (*tsf_FloatCallback)(ADDR, signed int, const char*[]);
|
||||||
typedef void (*tsf_VoidCallback )(ADDR, signed int, const char *[]);
|
typedef void (*tsf_VoidCallback)(ADDR, signed int, const char*[]);
|
||||||
typedef bool (*tsf_BoolCallback )(ADDR, signed int, const char *[]);
|
typedef bool (*tsf_BoolCallback)(ADDR, signed int, const char*[]);
|
||||||
|
|
||||||
/* These functions are used for tsf_BlCon__executefSimObj.
|
/* These functions are used for tsf_BlCon__executefSimObj.
|
||||||
They refer to a special buffer for the argument stack.
|
They refer to a special buffer for the argument stack.
|
||||||
For tsf_BlCon__executef, you need to use your own buffers. */
|
For tsf_BlCon__executef, you need to use your own buffers. */
|
||||||
char *tsf_GetIntArg(int);
|
char* tsf_GetIntArg(int);
|
||||||
char *tsf_GetFloatArg(float);
|
char* tsf_GetFloatArg(float);
|
||||||
char *tsf_ScriptThis(ADDR);
|
char* tsf_ScriptThis(ADDR);
|
||||||
|
|
||||||
const char *tsf_Eval(const char *);
|
const char* tsf_Eval(const char*);
|
||||||
const char *tsf_Evalf(const char *, ...);
|
const char* tsf_Evalf(const char*, ...);
|
||||||
|
|
||||||
ADDR tsf_FindObject(unsigned int);
|
ADDR tsf_FindObject(unsigned int);
|
||||||
ADDR tsf_FindObject(const char *);
|
ADDR tsf_FindObject(const char*);
|
||||||
|
|
||||||
ADDR tsf_LookupNamespace(const char *, const char *);
|
ADDR tsf_LookupNamespace(const char*, const char*);
|
||||||
|
|
||||||
const char *tsf_GetDataField(ADDR, const char *, const char *);
|
const char* tsf_GetDataField(ADDR, const char*, const char*);
|
||||||
void tsf_SetDataField(ADDR, const char *, const char *, const char *);
|
void tsf_SetDataField(ADDR, const char*, const char*, const char*);
|
||||||
|
|
||||||
const char *tsf_GetVar(const char *);
|
const char* tsf_GetVar(const char*);
|
||||||
|
|
||||||
void tsf_AddVarInternal(const char *, signed int, void *);
|
void tsf_AddVarInternal(const char*, signed int, void*);
|
||||||
void tsf_AddVar(const char *, const char **);
|
void tsf_AddVar(const char*, const char**);
|
||||||
void tsf_AddVar(const char *, signed int *);
|
void tsf_AddVar(const char*, signed int*);
|
||||||
void tsf_AddVar(const char *, float *);
|
void tsf_AddVar(const char*, float*);
|
||||||
void tsf_AddVar(const char *, bool *);
|
void tsf_AddVar(const char*, bool*);
|
||||||
|
|
||||||
ADDR tsf_AddConsoleFuncInternal(const char *, const char *, const char *, signed int, const char *, signed int, signed int);
|
ADDR tsf_AddConsoleFuncInternal(const char*, const char*, const char*, signed int, const char*, signed int, signed int);
|
||||||
void tsf_AddConsoleFunc(const char *, const char *, const char *, tsf_StringCallback, const char *, signed int, signed int);
|
void tsf_AddConsoleFunc(const char*, const char*, const char*, tsf_StringCallback, const char*, signed int, signed int);
|
||||||
void tsf_AddConsoleFunc(const char *, const char *, const char *, tsf_IntCallback, const char *, signed int, signed int);
|
void tsf_AddConsoleFunc(const char*, const char*, const char*, tsf_IntCallback, const char*, signed int, signed int);
|
||||||
void tsf_AddConsoleFunc(const char *, const char *, const char *, tsf_FloatCallback, const char *, signed int, signed int);
|
void tsf_AddConsoleFunc(const char*, const char*, const char*, tsf_FloatCallback, const char*, signed int, signed int);
|
||||||
void tsf_AddConsoleFunc(const char *, const char *, const char *, tsf_VoidCallback, const char *, signed int, signed int);
|
void tsf_AddConsoleFunc(const char*, const char*, const char*, tsf_VoidCallback, const char*, signed int, signed int);
|
||||||
void tsf_AddConsoleFunc(const char *, const char *, const char *, tsf_BoolCallback, const char *, signed int, signed int);
|
void tsf_AddConsoleFunc(const char*, const char*, const char*, tsf_BoolCallback, const char*, signed int, signed int);
|
||||||
|
|
||||||
bool tsf_InitInternal();
|
bool tsf_InitInternal();
|
||||||
|
|
||||||
@@ -56,21 +56,20 @@ extern ADDR tsf_mCacheAllocator;
|
|||||||
extern ADDR tsf_gIdDictionary;
|
extern ADDR tsf_gIdDictionary;
|
||||||
extern ADDR tsf_gEvalState_globalVars;
|
extern ADDR tsf_gEvalState_globalVars;
|
||||||
|
|
||||||
BlFunctionDefExtern(const char *, __stdcall, tsf_BlStringTable__insert, const char *, bool);
|
BlFunctionDefExtern(const char*, __stdcall, tsf_BlStringTable__insert, const char*, bool);
|
||||||
BlFunctionDefExtern(ADDR, __fastcall, tsf_BlNamespace__find, const char *, const char *);
|
BlFunctionDefExtern(ADDR, __fastcall, tsf_BlNamespace__find, const char*, const char*);
|
||||||
BlFunctionDefExtern(ADDR, __thiscall, tsf_BlNamespace__createLocalEntry, ADDR, const char *);
|
BlFunctionDefExtern(ADDR, __thiscall, tsf_BlNamespace__createLocalEntry, ADDR, const char*);
|
||||||
BlFunctionDefExtern(void, __thiscall, tsf_BlDataChunker__freeBlocks, ADDR);
|
BlFunctionDefExtern(void, __thiscall, tsf_BlDataChunker__freeBlocks, ADDR);
|
||||||
BlFunctionDefExtern(const char *, , tsf_BlCon__evaluate, ADDR, signed int, const char **);
|
BlFunctionDefExtern(const char*, , tsf_BlCon__evaluate, ADDR, signed int, const char**);
|
||||||
BlFunctionDefExtern(const char *, , tsf_BlCon__executef, signed int, ...);
|
BlFunctionDefExtern(const char*, , tsf_BlCon__executef, signed int, ...);
|
||||||
BlFunctionDefExtern(const char *, , tsf_BlCon__executefSimObj, ADDR *, signed int, ...);
|
BlFunctionDefExtern(const char*, , tsf_BlCon__executefSimObj, ADDR*, signed int, ...);
|
||||||
BlFunctionDefExtern(const char *, __thiscall, tsf_BlCon__getVariable, const char *);
|
BlFunctionDefExtern(const char*, __thiscall, tsf_BlCon__getVariable, const char*);
|
||||||
BlFunctionDefExtern(void, __thiscall, tsf_BlDictionary__addVariable, ADDR *, const char *, signed int, void *);
|
BlFunctionDefExtern(void, __thiscall, tsf_BlDictionary__addVariable, ADDR*, const char*, signed int, void*);
|
||||||
BlFunctionDefExtern(ADDR *, __thiscall, tsf_BlSim__findObject_name, const char *);
|
BlFunctionDefExtern(ADDR*, __thiscall, tsf_BlSim__findObject_name, const char*);
|
||||||
BlFunctionDefExtern(char *, __stdcall, tsf_BlStringStack__getArgBuffer, unsigned int);
|
BlFunctionDefExtern(char*, __stdcall, tsf_BlStringStack__getArgBuffer, unsigned int);
|
||||||
BlFunctionDefExtern(const char *, __thiscall, tsf_BlSimObject__getDataField, ADDR, const char *, const char *);
|
BlFunctionDefExtern(const char*, __thiscall, tsf_BlSimObject__getDataField, ADDR, const char*, const char*);
|
||||||
BlFunctionDefExtern(void, __thiscall, tsf_BlSimObject__setDataField, ADDR, const char *, const char *, const char *);
|
BlFunctionDefExtern(void, __thiscall, tsf_BlSimObject__setDataField, ADDR, const char*, const char*, const char*);
|
||||||
BlFunctionDefExtern(char *, __fastcall, tsf_BlCon__getReturnBuffer, unsigned int);
|
BlFunctionDefExtern(char*, __fastcall, tsf_BlCon__getReturnBuffer, unsigned int);
|
||||||
|
|
||||||
|
|
||||||
// Function short names
|
// Function short names
|
||||||
|
|
||||||
@@ -94,16 +93,21 @@ BlFunctionDefExtern(char *, __fastcall, tsf_BlCon__getReturnBuffer, unsigned int
|
|||||||
|
|
||||||
#define BlAddFunction tsf_AddConsoleFunc
|
#define BlAddFunction tsf_AddConsoleFunc
|
||||||
|
|
||||||
#define __22ND_ARGUMENT(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, ...) a22
|
#define __22ND_ARGUMENT( \
|
||||||
#define __NUM_LIST(...) __22ND_ARGUMENT(dummy, ##__VA_ARGS__, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
|
a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, ...) \
|
||||||
#define BlCall(...) \
|
a22
|
||||||
tsf_BlCon__executef(__NUM_LIST(__VA_ARGS__), __VA_ARGS__)
|
#define __NUM_LIST(...) \
|
||||||
#define BlCallObj(obj, ...) \
|
__22ND_ARGUMENT(dummy, ##__VA_ARGS__, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
|
||||||
tsf_BlCon__executefSimObj((ADDR*)obj, __NUM_LIST(__VA_ARGS__), __VA_ARGS__)
|
#define BlCall(...) tsf_BlCon__executef(__NUM_LIST(__VA_ARGS__), __VA_ARGS__)
|
||||||
|
#define BlCallObj(obj, ...) tsf_BlCon__executefSimObj((ADDR*)obj, __NUM_LIST(__VA_ARGS__), __VA_ARGS__)
|
||||||
#define BlFuncsInit() if(!tsf_InitInternal()) { return false; }
|
|
||||||
#define BlFuncsDeinit() if(!tsf_DeinitInternal()) { return false; }
|
|
||||||
|
|
||||||
|
#define BlFuncsInit() \
|
||||||
|
if (!tsf_InitInternal()) { \
|
||||||
|
return false; \
|
||||||
|
}
|
||||||
|
#define BlFuncsDeinit() \
|
||||||
|
if (!tsf_DeinitInternal()) { \
|
||||||
|
return false; \
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
#endif
|
|
||||||
|
|||||||
@@ -2,29 +2,30 @@
|
|||||||
//////////////////////////////////////////////////
|
//////////////////////////////////////////////////
|
||||||
// RedoBlHooks Version 3.0
|
// RedoBlHooks Version 3.0
|
||||||
|
|
||||||
|
|
||||||
// Includes
|
// Includes
|
||||||
|
|
||||||
|
#ifndef WIN32_LEAN_AND_MEAN
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#include <cstdlib>
|
||||||
|
#endif
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
#include <Psapi.h>
|
#include <Psapi.h>
|
||||||
//#include <map>
|
// #include <map>
|
||||||
|
|
||||||
#include "BlHooks.hpp"
|
#include "BlHooks.hpp"
|
||||||
|
|
||||||
|
|
||||||
// Scanned structures
|
// Scanned structures
|
||||||
|
|
||||||
BlFunctionDefIntern(tsh_BlPrintf);
|
BlFunctionDefIntern(tsh_BlPrintf);
|
||||||
|
|
||||||
|
|
||||||
// Sig Scanning
|
// Sig Scanning
|
||||||
|
|
||||||
ADDR ImageBase;
|
ADDR ImageBase;
|
||||||
ADDR ImageSize;
|
ADDR ImageSize;
|
||||||
|
|
||||||
void tsh_i_InitScanner(){
|
void tsh_i_InitScanner() {
|
||||||
HMODULE module = GetModuleHandle(NULL);
|
HMODULE module = GetModuleHandle(NULL);
|
||||||
if(module) {
|
if (module) {
|
||||||
MODULEINFO info;
|
MODULEINFO info;
|
||||||
GetModuleInformation(GetCurrentProcess(), module, &info, sizeof(MODULEINFO));
|
GetModuleInformation(GetCurrentProcess(), module, &info, sizeof(MODULEINFO));
|
||||||
ImageBase = (ADDR)info.lpBaseOfDll;
|
ImageBase = (ADDR)info.lpBaseOfDll;
|
||||||
@@ -32,17 +33,17 @@ void tsh_i_InitScanner(){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool tsh_i_CompareData(BYTE *data, BYTE *pattern, char* mask){
|
bool tsh_i_CompareData(BYTE* data, BYTE* pattern, char* mask) {
|
||||||
for (; *mask; ++data, ++pattern, ++mask){
|
for (; *mask; ++data, ++pattern, ++mask) {
|
||||||
if (*mask=='x' && *data!=*pattern)
|
if (*mask == 'x' && *data != *pattern)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return (*mask)==0;
|
return (*mask) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ADDR tsh_i_FindPattern(ADDR imageBase, ADDR imageSize, BYTE *pattern, char *mask){
|
ADDR tsh_i_FindPattern(ADDR imageBase, ADDR imageSize, BYTE* pattern, char* mask) {
|
||||||
for (ADDR i=imageBase; i < imageBase+imageSize; i++){
|
for (ADDR i = imageBase; i < imageBase + imageSize; i++) {
|
||||||
if(tsh_i_CompareData((PBYTE)i, pattern, mask)){
|
if (tsh_i_CompareData((PBYTE)i, pattern, mask)) {
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -58,17 +59,17 @@ void tsh_i_PatternTextToCode(char* text, char** opatt, char** omask) {
|
|||||||
int outidx = 0;
|
int outidx = 0;
|
||||||
int val = 0;
|
int val = 0;
|
||||||
bool uk = false;
|
bool uk = false;
|
||||||
for(unsigned int i=0; i<len; i++){
|
for (unsigned int i = 0; i < len; i++) {
|
||||||
char c = text[i];
|
char c = text[i];
|
||||||
if(c=='?'){
|
if (c == '?') {
|
||||||
uk = true;
|
uk = true;
|
||||||
}else if(c>='0' && c<='9'){
|
} else if (c >= '0' && c <= '9') {
|
||||||
val = (val<<4) + (c-'0');
|
val = (val << 4) + (c - '0');
|
||||||
}else if(c>='A' && c<='F'){
|
} else if (c >= 'A' && c <= 'F') {
|
||||||
val = (val<<4) + (c-'A'+10);
|
val = (val << 4) + (c - 'A' + 10);
|
||||||
}else if(c>='a' && c<='f'){
|
} else if (c >= 'a' && c <= 'f') {
|
||||||
val = (val<<4) + (c-'a'+10);
|
val = (val << 4) + (c - 'a' + 10);
|
||||||
}else if(c==' '){
|
} else if (c == ' ') {
|
||||||
patt[outidx] = uk ? 0 : val;
|
patt[outidx] = uk ? 0 : val;
|
||||||
mask[outidx] = uk ? '?' : 'x';
|
mask[outidx] = uk ? '?' : 'x';
|
||||||
val = 0;
|
val = 0;
|
||||||
@@ -87,12 +88,11 @@ void tsh_i_PatternTextToCode(char* text, char** opatt, char** omask) {
|
|||||||
*omask = mask;
|
*omask = mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Public functions for sig scanning
|
// Public functions for sig scanning
|
||||||
|
|
||||||
// Scan using code-style pattern
|
// Scan using code-style pattern
|
||||||
ADDR tsh_ScanCode(char* pattern, char* mask) {
|
ADDR tsh_ScanCode(char* pattern, char* mask) {
|
||||||
return tsh_i_FindPattern(ImageBase, ImageSize-strlen(mask), (BYTE*)pattern, mask);
|
return tsh_i_FindPattern(ImageBase, ImageSize - strlen(mask), (BYTE*)pattern, mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scan using a text-style pattern
|
// Scan using a text-style pattern
|
||||||
@@ -109,16 +109,15 @@ ADDR tsh_ScanText(char* text) {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Call Patching and Hooking
|
// Call Patching and Hooking
|
||||||
|
|
||||||
// Remove protection from address
|
// Remove protection from address
|
||||||
//std::map<ADDR, std::pair<ADDR, ADDR>> tsh_DeprotectedAddresses;
|
// std::map<ADDR, std::pair<ADDR, ADDR>> tsh_DeprotectedAddresses;
|
||||||
|
|
||||||
void tsh_DeprotectAddress(ADDR length, ADDR location) {
|
void tsh_DeprotectAddress(ADDR length, ADDR location) {
|
||||||
DWORD oldProtection;
|
DWORD oldProtection;
|
||||||
VirtualProtect((void*)location, length, PAGE_EXECUTE_READWRITE, &oldProtection);
|
VirtualProtect((void*)location, length, PAGE_EXECUTE_READWRITE, &oldProtection);
|
||||||
//tsh_DeprotectedAddresses[location] = {length, oldProtection};
|
// tsh_DeprotectedAddresses[location] = {length, oldProtection};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Patch a string of bytes by deprotecting and then overwriting
|
// Patch a string of bytes by deprotecting and then overwriting
|
||||||
@@ -127,50 +126,43 @@ void tsh_PatchBytes(ADDR length, ADDR location, BYTE* repl) {
|
|||||||
memcpy((void*)location, (void*)repl, (size_t)length);
|
memcpy((void*)location, (void*)repl, (size_t)length);
|
||||||
}
|
}
|
||||||
|
|
||||||
void tsh_PatchByte(ADDR location, BYTE value) {
|
void tsh_PatchByte(ADDR location, BYTE value) { tsh_PatchBytes(location, 1, &value); }
|
||||||
tsh_PatchBytes(location, 1, &value);
|
|
||||||
}
|
|
||||||
|
|
||||||
void tsh_ReplaceInt(ADDR addr, int rval) {
|
void tsh_ReplaceInt(ADDR addr, int rval) { tsh_PatchBytes(4, addr, (BYTE*)(&rval)); }
|
||||||
tsh_PatchBytes(4, addr, (BYTE*)(&rval));
|
|
||||||
}
|
|
||||||
|
|
||||||
int tsh_i_CallOffset(ADDR instr, ADDR func) {
|
int tsh_i_CallOffset(ADDR instr, ADDR func) { return func - (instr + 4); }
|
||||||
return func - (instr+4);
|
|
||||||
}
|
|
||||||
|
|
||||||
void tsh_i_ReplaceCall(ADDR instr, ADDR target) {
|
void tsh_i_ReplaceCall(ADDR instr, ADDR target) { tsh_ReplaceInt(instr, tsh_i_CallOffset(instr, target)); }
|
||||||
tsh_ReplaceInt(instr, tsh_i_CallOffset(instr, target));
|
|
||||||
}
|
|
||||||
|
|
||||||
void tsh_i_PatchCopy(ADDR dest, ADDR src, unsigned int len) {
|
void tsh_i_PatchCopy(ADDR dest, ADDR src, unsigned int len) {
|
||||||
for(unsigned int i=0; i<len; i++){
|
for (unsigned int i = 0; i < len; i++) {
|
||||||
tsh_PatchByte(dest+i, *((BYTE*)(src+i)));
|
tsh_PatchByte(dest + i, *((BYTE*)(src + i)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void tsh_HookFunction(ADDR victim, ADDR detour, BYTE* origbytes) {
|
void tsh_HookFunction(ADDR victim, ADDR detour, BYTE* origbytes) {
|
||||||
memcpy(origbytes, (BYTE*)victim, 6); //save old data
|
memcpy(origbytes, (BYTE*)victim, 6); // save old data
|
||||||
|
|
||||||
*(BYTE*)victim = 0xE9; //jmp rel32
|
*(BYTE*)victim = 0xE9; // jmp rel32
|
||||||
*(ADDR*)(victim+1) = (detour - (victim+5)); // jump offset
|
*(ADDR*)(victim + 1) = (detour - (victim + 5)); // jump offset
|
||||||
*(BYTE*)(victim+5) = 0xC3; //retn
|
*(BYTE*)(victim + 5) = 0xC3; // retn
|
||||||
}
|
}
|
||||||
|
|
||||||
void tsh_UnhookFunction(ADDR victim, BYTE* origbytes){
|
void tsh_UnhookFunction(ADDR victim, BYTE* origbytes) {
|
||||||
tsh_i_PatchCopy(victim, (ADDR)origbytes, 6); //restore old data
|
tsh_i_PatchCopy(victim, (ADDR)origbytes, 6); // restore old data
|
||||||
}
|
}
|
||||||
|
|
||||||
int tsh_PatchAllMatchesCode(ADDR len, char* patt, char* mask, char* replace, bool debugprint){
|
int tsh_PatchAllMatchesCode(ADDR len, char* patt, char* mask, char* replace, bool debugprint) {
|
||||||
int numpatched = 0;
|
int numpatched = 0;
|
||||||
for(ADDR i=ImageBase; i<ImageBase+ImageSize-len; i++){
|
for (ADDR i = ImageBase; i < ImageBase + ImageSize - len; i++) {
|
||||||
if(tsh_i_CompareData((BYTE*)i, (BYTE*)patt, mask)){
|
if (tsh_i_CompareData((BYTE*)i, (BYTE*)patt, mask)) {
|
||||||
if(debugprint) BlPrintf("RedoBlHooks: Patching call at %08x", i);
|
if (debugprint)
|
||||||
|
BlPrintf("RedoBlHooks: Patching call at %08x", i);
|
||||||
|
|
||||||
numpatched++;
|
numpatched++;
|
||||||
tsh_DeprotectAddress(i, len);
|
tsh_DeprotectAddress(i, len);
|
||||||
for(ADDR c=0; c<len; c++){
|
for (ADDR c = 0; c < len; c++) {
|
||||||
tsh_PatchByte(i+c, replace[c]);
|
tsh_PatchByte(i + c, replace[c]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -190,10 +182,9 @@ int tsh_PatchAllMatchesHex(ADDR len, char* text, char* replace, bool debugprint)
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Initialization
|
// Initialization
|
||||||
|
|
||||||
bool tsh_InitInternal(){
|
bool tsh_InitInternal() {
|
||||||
tsh_i_InitScanner();
|
tsh_i_InitScanner();
|
||||||
|
|
||||||
BlScanFunctionText(tsh_BlPrintf, "8D 44 24 08 33 D2 50 FF 74 24 08 33 C9 E8 ? ? ? ? 83 C4 08 C3");
|
BlScanFunctionText(tsh_BlPrintf, "8D 44 24 08 33 D2 50 FF 74 24 08 33 C9 E8 ? ? ? ? 83 C4 08 C3");
|
||||||
@@ -201,7 +192,4 @@ bool tsh_InitInternal(){
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool tsh_DeinitInternal() {
|
bool tsh_DeinitInternal() { return true; }
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|||||||
@@ -5,13 +5,11 @@
|
|||||||
#ifndef _H_BLHOOKS
|
#ifndef _H_BLHOOKS
|
||||||
#define _H_BLHOOKS
|
#define _H_BLHOOKS
|
||||||
|
|
||||||
|
|
||||||
// Typedefs
|
// Typedefs
|
||||||
|
|
||||||
typedef unsigned char BYTE;
|
typedef unsigned char BYTE;
|
||||||
typedef unsigned int ADDR;
|
typedef unsigned int ADDR;
|
||||||
|
|
||||||
|
|
||||||
// Prototypes
|
// Prototypes
|
||||||
|
|
||||||
bool tsh_InitInternal();
|
bool tsh_InitInternal();
|
||||||
@@ -25,69 +23,73 @@ void tsh_PatchByte(ADDR, BYTE);
|
|||||||
void tsh_PatchBytes(unsigned int, ADDR, BYTE*);
|
void tsh_PatchBytes(unsigned int, ADDR, BYTE*);
|
||||||
void tsh_PatchInt(ADDR, int);
|
void tsh_PatchInt(ADDR, int);
|
||||||
|
|
||||||
|
|
||||||
// Debug print settings
|
// Debug print settings
|
||||||
|
|
||||||
#ifndef TSH_NO_DEBUG_PRINT
|
#ifndef TSH_NO_DEBUG_PRINT
|
||||||
#define tsh_DEBUGPRINT false
|
#define tsh_DEBUGPRINT false
|
||||||
#else
|
#else
|
||||||
#define tsh_DEBUGPRINT true
|
#define tsh_DEBUGPRINT true
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
// Function short names
|
// Function short names
|
||||||
|
|
||||||
// Use in code when the def is not shared in a header
|
// Use in code when the def is not shared in a header
|
||||||
#define BlFunctionDef(returnType, convention, name, ...) \
|
#define BlFunctionDef(returnType, convention, name, ...) \
|
||||||
typedef returnType (convention *tsh_##name##FnT)(__VA_ARGS__); \
|
typedef returnType(convention* tsh_##name##FnT)(__VA_ARGS__); \
|
||||||
tsh_##name##FnT name;
|
tsh_##name##FnT name;
|
||||||
// Use in header for shared function defs when a BlFunctionDefIntern exists in code
|
// Use in header for shared function defs when a BlFunctionDefIntern exists in
|
||||||
|
// code
|
||||||
#define BlFunctionDefExtern(returnType, convention, name, ...) \
|
#define BlFunctionDefExtern(returnType, convention, name, ...) \
|
||||||
typedef returnType (convention *tsh_##name##FnT)(__VA_ARGS__); \
|
typedef returnType(convention* tsh_##name##FnT)(__VA_ARGS__); \
|
||||||
extern tsh_##name##FnT name;
|
extern tsh_##name##FnT name;
|
||||||
// Use in code for shared function defs when a BlFunctionDefExtern exists in header
|
// Use in code for shared function defs when a BlFunctionDefExtern exists in
|
||||||
#define BlFunctionDefIntern(name) \
|
// header
|
||||||
tsh_##name##FnT name;
|
#define BlFunctionDefIntern(name) tsh_##name##FnT name;
|
||||||
|
|
||||||
// Scan for and assign the pattern to the variable, or err and return if not found
|
// Scan for and assign the pattern to the variable, or err and return if not
|
||||||
|
// found
|
||||||
#define BlScanFunctionCode(target, patt, mask) \
|
#define BlScanFunctionCode(target, patt, mask) \
|
||||||
target = (tsh_##target##FnT)tsh_ScanCode((char*)patt, (char*)mask); \
|
target = (tsh_##target##FnT)tsh_ScanCode((char*)patt, (char*)mask); \
|
||||||
if(!target){ \
|
if (!target) { \
|
||||||
BlPrintf("RedoBlHooks | Cannot find function "#target"!"); \
|
BlPrintf("RedoBlHooks | Cannot find function " #target "!"); \
|
||||||
return false; \
|
return false; \
|
||||||
}else{ \
|
} else { \
|
||||||
if(tsh_DEBUGPRINT) BlPrintf("RedoBlHooks | Found function "#target" at %08x", (int)target); \
|
if (tsh_DEBUGPRINT) \
|
||||||
|
BlPrintf("RedoBlHooks | Found function " #target " at %08x", (int)target); \
|
||||||
}
|
}
|
||||||
#define BlScanFunctionText(target, text) \
|
#define BlScanFunctionText(target, text) \
|
||||||
target = (tsh_##target##FnT)tsh_ScanText((char*)text); \
|
target = (tsh_##target##FnT)tsh_ScanText((char*)text); \
|
||||||
if(!target){ \
|
if (!target) { \
|
||||||
BlPrintf("RedoBlHooks | Cannot find function "#target"!"); \
|
BlPrintf("RedoBlHooks | Cannot find function " #target "!"); \
|
||||||
return false; \
|
return false; \
|
||||||
}else{ \
|
} else { \
|
||||||
if(tsh_DEBUGPRINT) BlPrintf("RedoBlHooks | Found function "#target" at %08x", (int)target); \
|
if (tsh_DEBUGPRINT) \
|
||||||
|
BlPrintf("RedoBlHooks | Found function " #target " at %08x", (int)target); \
|
||||||
}
|
}
|
||||||
#define BlScanCode(target, patt, mask) \
|
#define BlScanCode(target, patt, mask) \
|
||||||
target = tsh_ScanCode((char*)patt, (char*)mask); \
|
target = tsh_ScanCode((char*)patt, (char*)mask); \
|
||||||
if(!target){ \
|
if (!target) { \
|
||||||
BlPrintf("RedoBlHooks | Cannot find pattern "#target"!"); \
|
BlPrintf("RedoBlHooks | Cannot find pattern " #target "!"); \
|
||||||
return false; \
|
return false; \
|
||||||
}else{ \
|
} else { \
|
||||||
if(tsh_DEBUGPRINT) BlPrintf("RedoBlHooks | Found "#target" at %08x", (int)target); \
|
if (tsh_DEBUGPRINT) \
|
||||||
|
BlPrintf("RedoBlHooks | Found " #target " at %08x", (int)target); \
|
||||||
}
|
}
|
||||||
#define BlScanText(target, text) \
|
#define BlScanText(target, text) \
|
||||||
target = tsh_ScanText((char*)text); \
|
target = tsh_ScanText((char*)text); \
|
||||||
if(!target){ \
|
if (!target) { \
|
||||||
BlPrintf("RedoBlHooks | Cannot find "#target"!"); \
|
BlPrintf("RedoBlHooks | Cannot find " #target "!"); \
|
||||||
return false; \
|
return false; \
|
||||||
}else{ \
|
} else { \
|
||||||
if(tsh_DEBUGPRINT) BlPrintf("RedoBlHooks | Found "#target" at %08x", (int)target); \
|
if (tsh_DEBUGPRINT) \
|
||||||
|
BlPrintf("RedoBlHooks | Found " #target " at %08x", (int)target); \
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use in code to define the data and functions for hooking a function
|
// Use in code to define the data and functions for hooking a function
|
||||||
#define BlFunctionHookDef(func) \
|
#define BlFunctionHookDef(func) \
|
||||||
BYTE tsh_BlFunctionHook##func##Data[6]; \
|
BYTE tsh_BlFunctionHook##func##Data[6]; \
|
||||||
void func##HookOn(){ tsh_HookFunction((ADDR)func, (ADDR)func##Hook, tsh_BlFunctionHook##func##Data); } \
|
void func##HookOn() { tsh_HookFunction((ADDR)func, (ADDR)func##Hook, tsh_BlFunctionHook##func##Data); } \
|
||||||
void func##HookOff(){ tsh_UnhookFunction((ADDR)func, tsh_BlFunctionHook##func##Data); }
|
void func##HookOff() { tsh_UnhookFunction((ADDR)func, tsh_BlFunctionHook##func##Data); }
|
||||||
// Use in code to initialize the hook once
|
// Use in code to initialize the hook once
|
||||||
#define BlFunctionHookInit(func) \
|
#define BlFunctionHookInit(func) \
|
||||||
tsh_DeprotectAddress(6, (ADDR)func); \
|
tsh_DeprotectAddress(6, (ADDR)func); \
|
||||||
@@ -100,23 +102,30 @@ void tsh_PatchInt(ADDR, int);
|
|||||||
tsh_PatchAllMatchesCode((ADDR)len, (char*)text, (char*)repl, tsh_DEBUGPRINT);
|
tsh_PatchAllMatchesCode((ADDR)len, (char*)text, (char*)repl, tsh_DEBUGPRINT);
|
||||||
|
|
||||||
// Deprotect and replace one byte
|
// Deprotect and replace one byte
|
||||||
#define BlPatchByte(addr, byte) \
|
#define BlPatchByte(addr, byte) tsh_PatchByte((ADDR)addr, (BYTE)byte);
|
||||||
tsh_PatchByte((ADDR)addr, (BYTE)byte);
|
|
||||||
// Deprotect and replace a byte string
|
// Deprotect and replace a byte string
|
||||||
#define BlPatchBytes(len, addr, repl) \
|
#define BlPatchBytes(len, addr, repl) tsh_PatchBytes((ADDR)len, (ADDR)addr, (BYTE*)repl);
|
||||||
tsh_PatchBytes((ADDR)len, (ADDR)addr, (BYTE*)repl);
|
|
||||||
|
|
||||||
// BlPrintf(char* format, ...)
|
// BlPrintf(char* format, ...)
|
||||||
#define BlPrintf(...) if(tsh_BlPrintf) { tsh_BlPrintf(__VA_ARGS__); }
|
#define BlPrintf(...) \
|
||||||
|
if (tsh_BlPrintf) { \
|
||||||
|
tsh_BlPrintf(__VA_ARGS__); \
|
||||||
|
}
|
||||||
// BlHooksInit() -> bool: success
|
// BlHooksInit() -> bool: success
|
||||||
#define BlHooksInit() if(!tsh_InitInternal()) { BlPrintf("BlHooksInit failed"); return false; }
|
#define BlHooksInit() \
|
||||||
|
if (!tsh_InitInternal()) { \
|
||||||
|
BlPrintf("BlHooksInit failed"); \
|
||||||
|
return false; \
|
||||||
|
}
|
||||||
// BlHooksDeinit() -> bool: success
|
// BlHooksDeinit() -> bool: success
|
||||||
#define BlHooksDeinit() if(!tsh_DeinitInternal()) { BlPrintf("BlHooksDeinit failed"); return false; }
|
#define BlHooksDeinit() \
|
||||||
|
if (!tsh_DeinitInternal()) { \
|
||||||
|
BlPrintf("BlHooksDeinit failed"); \
|
||||||
|
return false; \
|
||||||
|
}
|
||||||
|
|
||||||
// Scanned structures
|
// Scanned structures
|
||||||
|
|
||||||
BlFunctionDefExtern(void, , tsh_BlPrintf, const char*, ...);
|
BlFunctionDefExtern(void, , tsh_BlPrintf, const char*, ...);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
BIN
lualib/https.dll
BIN
lualib/https.dll
Binary file not shown.
323
lualib/ltn12.lua
323
lualib/ltn12.lua
@@ -1,323 +0,0 @@
|
|||||||
-----------------------------------------------------------------------------
|
|
||||||
-- LTN12 - Filters, sources, sinks and pumps.
|
|
||||||
-- LuaSocket toolkit.
|
|
||||||
-- Author: Diego Nehab
|
|
||||||
-- RCS ID: $Id: ltn12.lua,v 1.31 2006/04/03 04:45:42 diego Exp $
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
-- Declare module
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
local string = require("string")
|
|
||||||
local table = require("table")
|
|
||||||
local base = _G
|
|
||||||
module("ltn12")
|
|
||||||
|
|
||||||
filter = {}
|
|
||||||
source = {}
|
|
||||||
sink = {}
|
|
||||||
pump = {}
|
|
||||||
|
|
||||||
-- 2048 seems to be better in windows...
|
|
||||||
BLOCKSIZE = 2048
|
|
||||||
_VERSION = "LTN12 1.0.1"
|
|
||||||
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
-- Filter stuff
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
-- returns a high level filter that cycles a low-level filter
|
|
||||||
function filter.cycle(low, ctx, extra)
|
|
||||||
base.assert(low)
|
|
||||||
return function(chunk)
|
|
||||||
local ret
|
|
||||||
ret, ctx = low(ctx, chunk, extra)
|
|
||||||
return ret
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- chains a bunch of filters together
|
|
||||||
-- (thanks to Wim Couwenberg)
|
|
||||||
function filter.chain(...)
|
|
||||||
local n = #arg
|
|
||||||
local top, index = 1, 1
|
|
||||||
local retry = ""
|
|
||||||
return function(chunk)
|
|
||||||
retry = chunk and retry
|
|
||||||
while true do
|
|
||||||
if index == top then
|
|
||||||
chunk = arg[index](chunk)
|
|
||||||
if chunk == "" or top == n then
|
|
||||||
return chunk
|
|
||||||
elseif chunk then
|
|
||||||
index = index + 1
|
|
||||||
else
|
|
||||||
top = top + 1
|
|
||||||
index = top
|
|
||||||
end
|
|
||||||
else
|
|
||||||
chunk = arg[index](chunk or "")
|
|
||||||
if chunk == "" then
|
|
||||||
index = index - 1
|
|
||||||
chunk = retry
|
|
||||||
elseif chunk then
|
|
||||||
if index == n then
|
|
||||||
return chunk
|
|
||||||
else
|
|
||||||
index = index + 1
|
|
||||||
end
|
|
||||||
else
|
|
||||||
base.error("filter returned inappropriate nil")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
-- Source stuff
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
-- create an empty source
|
|
||||||
local function empty()
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
|
|
||||||
function source.empty()
|
|
||||||
return empty
|
|
||||||
end
|
|
||||||
|
|
||||||
-- returns a source that just outputs an error
|
|
||||||
function source.error(err)
|
|
||||||
return function()
|
|
||||||
return nil, err
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- creates a file source
|
|
||||||
function source.file(handle, io_err)
|
|
||||||
if handle then
|
|
||||||
return function()
|
|
||||||
local chunk = handle:read(BLOCKSIZE)
|
|
||||||
if not chunk then handle:close() end
|
|
||||||
return chunk
|
|
||||||
end
|
|
||||||
else
|
|
||||||
return source.error(io_err or "unable to open file")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- turns a fancy source into a simple source
|
|
||||||
function source.simplify(src)
|
|
||||||
base.assert(src)
|
|
||||||
return function()
|
|
||||||
local chunk, err_or_new = src()
|
|
||||||
src = err_or_new or src
|
|
||||||
if not chunk then
|
|
||||||
return nil, err_or_new
|
|
||||||
else
|
|
||||||
return chunk
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- creates string source
|
|
||||||
function source.string(s)
|
|
||||||
if s then
|
|
||||||
local i = 1
|
|
||||||
return function()
|
|
||||||
local chunk = string.sub(s, i, i + BLOCKSIZE - 1)
|
|
||||||
i = i + BLOCKSIZE
|
|
||||||
if chunk ~= "" then
|
|
||||||
return chunk
|
|
||||||
else
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
|
||||||
return source.empty()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- creates rewindable source
|
|
||||||
function source.rewind(src)
|
|
||||||
base.assert(src)
|
|
||||||
local t = {}
|
|
||||||
return function(chunk)
|
|
||||||
if not chunk then
|
|
||||||
chunk = table.remove(t)
|
|
||||||
if not chunk then
|
|
||||||
return src()
|
|
||||||
else
|
|
||||||
return chunk
|
|
||||||
end
|
|
||||||
else
|
|
||||||
table.insert(t, chunk)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function source.chain(src, f)
|
|
||||||
base.assert(src and f)
|
|
||||||
local last_in, last_out = "", ""
|
|
||||||
local state = "feeding"
|
|
||||||
local err
|
|
||||||
return function()
|
|
||||||
if not last_out then
|
|
||||||
base.error('source is empty!', 2)
|
|
||||||
end
|
|
||||||
while true do
|
|
||||||
if state == "feeding" then
|
|
||||||
last_in, err = src()
|
|
||||||
if err then return nil, err end
|
|
||||||
last_out = f(last_in)
|
|
||||||
if not last_out then
|
|
||||||
if last_in then
|
|
||||||
base.error('filter returned inappropriate nil')
|
|
||||||
else
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
elseif last_out ~= "" then
|
|
||||||
state = "eating"
|
|
||||||
if last_in then last_in = "" end
|
|
||||||
return last_out
|
|
||||||
end
|
|
||||||
else
|
|
||||||
last_out = f(last_in)
|
|
||||||
if last_out == "" then
|
|
||||||
if last_in == "" then
|
|
||||||
state = "feeding"
|
|
||||||
else
|
|
||||||
base.error('filter returned ""')
|
|
||||||
end
|
|
||||||
elseif not last_out then
|
|
||||||
if last_in then
|
|
||||||
base.error('filter returned inappropriate nil')
|
|
||||||
else
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
else
|
|
||||||
return last_out
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- creates a source that produces contents of several sources, one after the
|
|
||||||
-- other, as if they were concatenated
|
|
||||||
-- (thanks to Wim Couwenberg)
|
|
||||||
function source.cat(...)
|
|
||||||
local src = table.remove(arg, 1)
|
|
||||||
return function()
|
|
||||||
while src do
|
|
||||||
local chunk, err = src()
|
|
||||||
if chunk then return chunk end
|
|
||||||
if err then return nil, err end
|
|
||||||
src = table.remove(arg, 1)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
-- Sink stuff
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
-- creates a sink that stores into a table
|
|
||||||
function sink.table(t)
|
|
||||||
t = t or {}
|
|
||||||
local f = function(chunk, err)
|
|
||||||
if chunk then table.insert(t, chunk) end
|
|
||||||
return 1
|
|
||||||
end
|
|
||||||
return f, t
|
|
||||||
end
|
|
||||||
|
|
||||||
-- turns a fancy sink into a simple sink
|
|
||||||
function sink.simplify(snk)
|
|
||||||
base.assert(snk)
|
|
||||||
return function(chunk, err)
|
|
||||||
local ret, err_or_new = snk(chunk, err)
|
|
||||||
if not ret then return nil, err_or_new end
|
|
||||||
snk = err_or_new or snk
|
|
||||||
return 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- creates a file sink
|
|
||||||
function sink.file(handle, io_err)
|
|
||||||
if handle then
|
|
||||||
return function(chunk, err)
|
|
||||||
if not chunk then
|
|
||||||
handle:close()
|
|
||||||
return 1
|
|
||||||
else
|
|
||||||
return handle:write(chunk)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
|
||||||
return sink.error(io_err or "unable to open file")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- creates a sink that discards data
|
|
||||||
local function null()
|
|
||||||
return 1
|
|
||||||
end
|
|
||||||
|
|
||||||
function sink.null()
|
|
||||||
return null
|
|
||||||
end
|
|
||||||
|
|
||||||
-- creates a sink that just returns an error
|
|
||||||
function sink.error(err)
|
|
||||||
return function()
|
|
||||||
return nil, err
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- chains a sink with a filter
|
|
||||||
function sink.chain(f, snk)
|
|
||||||
base.assert(f and snk)
|
|
||||||
return function(chunk, err)
|
|
||||||
if chunk ~= "" then
|
|
||||||
local filtered = f(chunk)
|
|
||||||
local done = chunk and ""
|
|
||||||
while true do
|
|
||||||
local ret, snkerr = snk(filtered, err)
|
|
||||||
if not ret then return nil, snkerr end
|
|
||||||
if filtered == done then return 1 end
|
|
||||||
filtered = f(done)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
return 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
-- Pump stuff
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
-- pumps one chunk from the source to the sink
|
|
||||||
function pump.step(src, snk)
|
|
||||||
local chunk, src_err = src()
|
|
||||||
local ret, snk_err = snk(chunk, src_err)
|
|
||||||
if chunk and ret then
|
|
||||||
return 1
|
|
||||||
else
|
|
||||||
return nil, src_err or snk_err
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- pumps all data from a source to a sink, using a step function
|
|
||||||
function pump.all(src, snk, step)
|
|
||||||
base.assert(src and snk)
|
|
||||||
step = step or pump.step
|
|
||||||
while true do
|
|
||||||
local ret, err = step(src, snk)
|
|
||||||
if not ret then
|
|
||||||
if err then
|
|
||||||
return nil, err
|
|
||||||
else
|
|
||||||
return 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@@ -1,94 +0,0 @@
|
|||||||
-----------------------------------------------------------------------------
|
|
||||||
-- MIME support for the Lua language.
|
|
||||||
-- Author: Diego Nehab
|
|
||||||
-- Conforming to RFCs 2045-2049
|
|
||||||
-- RCS ID: $Id: mime.lua,v 1.29 2007/06/11 23:44:54 diego Exp $
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
-- Declare module and import dependencies
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
local base = _G
|
|
||||||
local ltn12 = require("ltn12")
|
|
||||||
local mime = require("mime.core")
|
|
||||||
--local io = require("io")
|
|
||||||
local string = require("string")
|
|
||||||
module("mime")
|
|
||||||
|
|
||||||
-- encode, decode and wrap algorithm tables
|
|
||||||
encodet = {}
|
|
||||||
decodet = {}
|
|
||||||
wrapt = {}
|
|
||||||
|
|
||||||
-- creates a function that chooses a filter by name from a given table
|
|
||||||
local function 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
|
|
||||||
|
|
||||||
-- define the encoding filters
|
|
||||||
encodet['base64'] = function()
|
|
||||||
return ltn12.filter.cycle(b64, "")
|
|
||||||
end
|
|
||||||
|
|
||||||
encodet['quoted-printable'] = function(mode)
|
|
||||||
return ltn12.filter.cycle(qp, "",
|
|
||||||
(mode == "binary") and "=0D=0A" or "\r\n")
|
|
||||||
end
|
|
||||||
|
|
||||||
-- define the decoding filters
|
|
||||||
decodet['base64'] = function()
|
|
||||||
return ltn12.filter.cycle(unb64, "")
|
|
||||||
end
|
|
||||||
|
|
||||||
decodet['quoted-printable'] = function()
|
|
||||||
return ltn12.filter.cycle(unqp, "")
|
|
||||||
end
|
|
||||||
|
|
||||||
local function format(chunk)
|
|
||||||
if chunk then
|
|
||||||
if chunk == "" then
|
|
||||||
return "''"
|
|
||||||
else
|
|
||||||
return string.len(chunk)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
return "nil"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- define the line-wrap filters
|
|
||||||
wrapt['text'] = function(length)
|
|
||||||
length = length or 76
|
|
||||||
return ltn12.filter.cycle(wrp, length, length)
|
|
||||||
end
|
|
||||||
wrapt['base64'] = wrapt['text']
|
|
||||||
wrapt['default'] = wrapt['text']
|
|
||||||
|
|
||||||
wrapt['quoted-printable'] = function()
|
|
||||||
return ltn12.filter.cycle(qpwrp, 76, 76)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- function that choose the encoding, decoding or wrap algorithm
|
|
||||||
encode = choose(encodet)
|
|
||||||
decode = choose(decodet)
|
|
||||||
wrap = choose(wrapt)
|
|
||||||
|
|
||||||
-- define the end-of-line normalization filter
|
|
||||||
function normalize(marker)
|
|
||||||
return ltn12.filter.cycle(eol, 0, marker)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- high level stuffing filter
|
|
||||||
function stuff()
|
|
||||||
return ltn12.filter.cycle(dot, 2)
|
|
||||||
end
|
|
||||||
Binary file not shown.
@@ -1,143 +0,0 @@
|
|||||||
-----------------------------------------------------------------------------
|
|
||||||
-- LuaSocket helper module
|
|
||||||
-- Author: Diego Nehab
|
|
||||||
-- RCS ID: $Id: socket.lua,v 1.22 2005/11/22 08:33:29 diego Exp $
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
-- Declare module and import dependencies
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
local base = _G
|
|
||||||
local string = require("string")
|
|
||||||
local math = require("math")
|
|
||||||
local socket = require("socket.core")
|
|
||||||
module("socket")
|
|
||||||
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
-- Exported auxiliar functions
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
function connect(address, port, laddress, lport)
|
|
||||||
local sock, err = socket.tcp()
|
|
||||||
if not sock then return nil, err end
|
|
||||||
if laddress then
|
|
||||||
local res, err = sock:bind(laddress, lport, -1)
|
|
||||||
if not res then return nil, err end
|
|
||||||
end
|
|
||||||
local res, err = sock:connect(address, port)
|
|
||||||
if not res then return nil, err end
|
|
||||||
return sock
|
|
||||||
end
|
|
||||||
|
|
||||||
function bind(host, port, backlog)
|
|
||||||
local sock, err = socket.tcp()
|
|
||||||
if not sock then return nil, err end
|
|
||||||
sock:setoption("reuseaddr", true)
|
|
||||||
local res, err = sock:bind(host, port)
|
|
||||||
if not res then return nil, err end
|
|
||||||
res, err = sock:listen(backlog)
|
|
||||||
if not res then return nil, err end
|
|
||||||
return sock
|
|
||||||
end
|
|
||||||
|
|
||||||
try = newtry()
|
|
||||||
|
|
||||||
function 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
|
|
||||||
sourcet = {}
|
|
||||||
sinkt = {}
|
|
||||||
|
|
||||||
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"]
|
|
||||||
|
|
||||||
sink = 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"]
|
|
||||||
|
|
||||||
source = choose(sourcet)
|
|
||||||
Binary file not shown.
@@ -1,288 +0,0 @@
|
|||||||
-----------------------------------------------------------------------------
|
|
||||||
-- FTP support for the Lua language
|
|
||||||
-- LuaSocket toolkit.
|
|
||||||
-- Author: Diego Nehab
|
|
||||||
-- RCS ID: $Id: ftp.lua,v 1.45 2007/07/11 19:25:47 diego Exp $
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
-- Declare module and import dependencies
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
local base = _G
|
|
||||||
local table = require("table")
|
|
||||||
local string = require("string")
|
|
||||||
local math = require("math")
|
|
||||||
local socket = require("socket")
|
|
||||||
local url = require("socket.url")
|
|
||||||
local tp = require("socket.tp")
|
|
||||||
local ltn12 = require("ltn12")
|
|
||||||
module("socket.ftp")
|
|
||||||
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
-- Program constants
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
-- timeout in seconds before the program gives up on a connection
|
|
||||||
TIMEOUT = 60
|
|
||||||
-- default port for ftp service
|
|
||||||
PORT = 21
|
|
||||||
-- this is the default anonymous password. used when no password is
|
|
||||||
-- provided in url. should be changed to your e-mail.
|
|
||||||
USER = "ftp"
|
|
||||||
PASSWORD = "anonymous@anonymous.org"
|
|
||||||
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
-- Low level FTP API
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
local metat = { __index = {} }
|
|
||||||
|
|
||||||
function open(server, port, create)
|
|
||||||
local tp = socket.try(tp.connect(server, port or PORT, TIMEOUT, create))
|
|
||||||
local f = base.setmetatable({ tp = tp }, metat)
|
|
||||||
-- make sure everything gets closed in an exception
|
|
||||||
f.try = socket.newtry(function() f:close() end)
|
|
||||||
return f
|
|
||||||
end
|
|
||||||
|
|
||||||
function metat.__index:portconnect()
|
|
||||||
self.try(self.server:settimeout(TIMEOUT))
|
|
||||||
self.data = self.try(self.server:accept())
|
|
||||||
self.try(self.data:settimeout(TIMEOUT))
|
|
||||||
end
|
|
||||||
|
|
||||||
function metat.__index:pasvconnect()
|
|
||||||
self.data = self.try(socket.tcp())
|
|
||||||
self.try(self.data:settimeout(TIMEOUT))
|
|
||||||
self.try(self.data:connect(self.pasvt.ip, self.pasvt.port))
|
|
||||||
end
|
|
||||||
|
|
||||||
function metat.__index:login(user, password)
|
|
||||||
self.try(self.tp:command("user", user or USER))
|
|
||||||
local code, reply = self.try(self.tp:check { "2..", 331 })
|
|
||||||
if code == 331 then
|
|
||||||
self.try(self.tp:command("pass", password or PASSWORD))
|
|
||||||
self.try(self.tp:check("2.."))
|
|
||||||
end
|
|
||||||
return 1
|
|
||||||
end
|
|
||||||
|
|
||||||
function metat.__index:pasv()
|
|
||||||
self.try(self.tp:command("pasv"))
|
|
||||||
local code, reply = self.try(self.tp:check("2.."))
|
|
||||||
local pattern = "(%d+)%D(%d+)%D(%d+)%D(%d+)%D(%d+)%D(%d+)"
|
|
||||||
local a, b, c, d, p1, p2 = socket.skip(2, string.find(reply, pattern))
|
|
||||||
self.try(a and b and c and d and p1 and p2, reply)
|
|
||||||
self.pasvt = {
|
|
||||||
ip = string.format("%d.%d.%d.%d", a, b, c, d),
|
|
||||||
port = p1 * 256 + p2
|
|
||||||
}
|
|
||||||
if self.server then
|
|
||||||
self.server:close()
|
|
||||||
self.server = nil
|
|
||||||
end
|
|
||||||
return self.pasvt.ip, self.pasvt.port
|
|
||||||
end
|
|
||||||
|
|
||||||
function metat.__index:port(ip, port)
|
|
||||||
self.pasvt = nil
|
|
||||||
if not ip then
|
|
||||||
ip, port = self.try(self.tp:getcontrol():getsockname())
|
|
||||||
self.server = self.try(socket.bind(ip, 0))
|
|
||||||
ip, port = self.try(self.server:getsockname())
|
|
||||||
self.try(self.server:settimeout(TIMEOUT))
|
|
||||||
end
|
|
||||||
local pl = math.mod(port, 256)
|
|
||||||
local ph = (port - pl) / 256
|
|
||||||
local arg = string.gsub(string.format("%s,%d,%d", ip, ph, pl), "%.", ",")
|
|
||||||
self.try(self.tp:command("port", arg))
|
|
||||||
self.try(self.tp:check("2.."))
|
|
||||||
return 1
|
|
||||||
end
|
|
||||||
|
|
||||||
function metat.__index:send(sendt)
|
|
||||||
self.try(self.pasvt or self.server, "need port or pasv first")
|
|
||||||
-- if there is a pasvt table, we already sent a PASV command
|
|
||||||
-- we just get the data connection into self.data
|
|
||||||
if self.pasvt then self:pasvconnect() end
|
|
||||||
-- get the transfer argument and command
|
|
||||||
local argument = sendt.argument or
|
|
||||||
url.unescape(string.gsub(sendt.path or "", "^[/\\]", ""))
|
|
||||||
if argument == "" then argument = nil end
|
|
||||||
local command = sendt.command or "stor"
|
|
||||||
-- send the transfer command and check the reply
|
|
||||||
self.try(self.tp:command(command, argument))
|
|
||||||
local code, reply = self.try(self.tp:check { "2..", "1.." })
|
|
||||||
-- if there is not a a pasvt table, then there is a server
|
|
||||||
-- and we already sent a PORT command
|
|
||||||
if not self.pasvt then self:portconnect() end
|
|
||||||
-- get the sink, source and step for the transfer
|
|
||||||
local step = sendt.step or ltn12.pump.step
|
|
||||||
local readt = { self.tp.c }
|
|
||||||
local checkstep = function(src, snk)
|
|
||||||
-- check status in control connection while downloading
|
|
||||||
local readyt = socket.select(readt, nil, 0)
|
|
||||||
if readyt[tp] then code = self.try(self.tp:check("2..")) end
|
|
||||||
return step(src, snk)
|
|
||||||
end
|
|
||||||
local sink = socket.sink("close-when-done", self.data)
|
|
||||||
-- transfer all data and check error
|
|
||||||
self.try(ltn12.pump.all(sendt.source, sink, checkstep))
|
|
||||||
if string.find(code, "1..") then self.try(self.tp:check("2..")) end
|
|
||||||
-- done with data connection
|
|
||||||
self.data:close()
|
|
||||||
-- find out how many bytes were sent
|
|
||||||
local sent = socket.skip(1, self.data:getstats())
|
|
||||||
self.data = nil
|
|
||||||
return sent
|
|
||||||
end
|
|
||||||
|
|
||||||
function metat.__index:receive(recvt)
|
|
||||||
self.try(self.pasvt or self.server, "need port or pasv first")
|
|
||||||
if self.pasvt then self:pasvconnect() end
|
|
||||||
local argument = recvt.argument or
|
|
||||||
url.unescape(string.gsub(recvt.path or "", "^[/\\]", ""))
|
|
||||||
if argument == "" then argument = nil end
|
|
||||||
local command = recvt.command or "retr"
|
|
||||||
self.try(self.tp:command(command, argument))
|
|
||||||
local code = self.try(self.tp:check { "1..", "2.." })
|
|
||||||
if not self.pasvt then self:portconnect() end
|
|
||||||
local source = socket.source("until-closed", self.data)
|
|
||||||
local step = recvt.step or ltn12.pump.step
|
|
||||||
self.try(ltn12.pump.all(source, recvt.sink, step))
|
|
||||||
if string.find(code, "1..") then self.try(self.tp:check("2..")) end
|
|
||||||
self.data:close()
|
|
||||||
self.data = nil
|
|
||||||
return 1
|
|
||||||
end
|
|
||||||
|
|
||||||
function metat.__index:cwd(dir)
|
|
||||||
self.try(self.tp:command("cwd", dir))
|
|
||||||
self.try(self.tp:check(250))
|
|
||||||
return 1
|
|
||||||
end
|
|
||||||
|
|
||||||
function metat.__index:type(type)
|
|
||||||
self.try(self.tp:command("type", type))
|
|
||||||
self.try(self.tp:check(200))
|
|
||||||
return 1
|
|
||||||
end
|
|
||||||
|
|
||||||
function metat.__index:greet()
|
|
||||||
local code = self.try(self.tp:check { "1..", "2.." })
|
|
||||||
if string.find(code, "1..") then self.try(self.tp:check("2..")) end
|
|
||||||
return 1
|
|
||||||
end
|
|
||||||
|
|
||||||
function metat.__index:quit()
|
|
||||||
self.try(self.tp:command("quit"))
|
|
||||||
self.try(self.tp:check("2.."))
|
|
||||||
return 1
|
|
||||||
end
|
|
||||||
|
|
||||||
function metat.__index:close()
|
|
||||||
if self.data then self.data:close() end
|
|
||||||
if self.server then self.server:close() end
|
|
||||||
return self.tp:close()
|
|
||||||
end
|
|
||||||
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
-- High level FTP API
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
local function override(t)
|
|
||||||
if t.url then
|
|
||||||
local u = url.parse(t.url)
|
|
||||||
for i, v in base.pairs(t) do
|
|
||||||
u[i] = v
|
|
||||||
end
|
|
||||||
return u
|
|
||||||
else
|
|
||||||
return t
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function tput(putt)
|
|
||||||
putt = override(putt)
|
|
||||||
socket.try(putt.host, "missing hostname")
|
|
||||||
local f = open(putt.host, putt.port, putt.create)
|
|
||||||
f:greet()
|
|
||||||
f:login(putt.user, putt.password)
|
|
||||||
if putt.type then f:type(putt.type) end
|
|
||||||
f:pasv()
|
|
||||||
local sent = f:send(putt)
|
|
||||||
f:quit()
|
|
||||||
f:close()
|
|
||||||
return sent
|
|
||||||
end
|
|
||||||
|
|
||||||
local default = {
|
|
||||||
path = "/",
|
|
||||||
scheme = "ftp"
|
|
||||||
}
|
|
||||||
|
|
||||||
local function parse(u)
|
|
||||||
local t = socket.try(url.parse(u, default))
|
|
||||||
socket.try(t.scheme == "ftp", "wrong scheme '" .. t.scheme .. "'")
|
|
||||||
socket.try(t.host, "missing hostname")
|
|
||||||
local pat = "^type=(.)$"
|
|
||||||
if t.params then
|
|
||||||
t.type = socket.skip(2, string.find(t.params, pat))
|
|
||||||
socket.try(t.type == "a" or t.type == "i",
|
|
||||||
"invalid type '" .. t.type .. "'")
|
|
||||||
end
|
|
||||||
return t
|
|
||||||
end
|
|
||||||
|
|
||||||
local function sput(u, body)
|
|
||||||
local putt = parse(u)
|
|
||||||
putt.source = ltn12.source.string(body)
|
|
||||||
return tput(putt)
|
|
||||||
end
|
|
||||||
|
|
||||||
put = socket.protect(function(putt, body)
|
|
||||||
if base.type(putt) == "string" then
|
|
||||||
return sput(putt, body)
|
|
||||||
else
|
|
||||||
return tput(putt)
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
|
|
||||||
local function tget(gett)
|
|
||||||
gett = override(gett)
|
|
||||||
socket.try(gett.host, "missing hostname")
|
|
||||||
local f = open(gett.host, gett.port, gett.create)
|
|
||||||
f:greet()
|
|
||||||
f:login(gett.user, gett.password)
|
|
||||||
if gett.type then f:type(gett.type) end
|
|
||||||
f:pasv()
|
|
||||||
f:receive(gett)
|
|
||||||
f:quit()
|
|
||||||
return f:close()
|
|
||||||
end
|
|
||||||
|
|
||||||
local function sget(u)
|
|
||||||
local gett = parse(u)
|
|
||||||
local t = {}
|
|
||||||
gett.sink = ltn12.sink.table(t)
|
|
||||||
tget(gett)
|
|
||||||
return table.concat(t)
|
|
||||||
end
|
|
||||||
|
|
||||||
command = socket.protect(function(cmdt)
|
|
||||||
cmdt = override(cmdt)
|
|
||||||
socket.try(cmdt.host, "missing hostname")
|
|
||||||
socket.try(cmdt.command, "missing command")
|
|
||||||
local f = open(cmdt.host, cmdt.port, cmdt.create)
|
|
||||||
f:greet()
|
|
||||||
f:login(cmdt.user, cmdt.password)
|
|
||||||
f.try(f.tp:command(cmdt.command, cmdt.argument))
|
|
||||||
if cmdt.check then f.try(f.tp:check(cmdt.check)) end
|
|
||||||
f:quit()
|
|
||||||
return f:close()
|
|
||||||
end)
|
|
||||||
|
|
||||||
get = socket.protect(function(gett)
|
|
||||||
if base.type(gett) == "string" then
|
|
||||||
return sget(gett)
|
|
||||||
else
|
|
||||||
return tget(gett)
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
@@ -1,359 +0,0 @@
|
|||||||
-----------------------------------------------------------------------------
|
|
||||||
-- HTTP/1.1 client support for the Lua language.
|
|
||||||
-- LuaSocket toolkit.
|
|
||||||
-- Author: Diego Nehab
|
|
||||||
-- RCS ID: $Id: http.lua,v 1.70 2007/03/12 04:08:40 diego Exp $
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
-- Declare module and import dependencies
|
|
||||||
-------------------------------------------------------------------------------
|
|
||||||
local socket = require("socket")
|
|
||||||
local url = require("socket.url")
|
|
||||||
local ltn12 = require("ltn12")
|
|
||||||
local mime = require("mime")
|
|
||||||
local string = require("string")
|
|
||||||
local base = _G
|
|
||||||
local table = require("table")
|
|
||||||
module("socket.http")
|
|
||||||
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
-- Program constants
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
-- connection timeout in seconds
|
|
||||||
TIMEOUT = 60
|
|
||||||
-- default port for document retrieval
|
|
||||||
PORT = 80
|
|
||||||
-- user agent field sent in request
|
|
||||||
USERAGENT = socket._VERSION
|
|
||||||
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
-- Reads MIME headers from a connection, unfolding where needed
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
local function receiveheaders(sock, headers)
|
|
||||||
local line, name, value, err
|
|
||||||
headers = headers or {}
|
|
||||||
-- get first line
|
|
||||||
line, err = sock:receive()
|
|
||||||
if err then return nil, err end
|
|
||||||
-- headers go until a blank line is found
|
|
||||||
while line ~= "" do
|
|
||||||
-- get field-name and value
|
|
||||||
name, value = socket.skip(2, string.find(line, "^(.-):%s*(.*)"))
|
|
||||||
if not (name and value) then return nil, "malformed reponse headers" end
|
|
||||||
name = string.lower(name)
|
|
||||||
-- get next line (value might be folded)
|
|
||||||
line, err = sock:receive()
|
|
||||||
if err then return nil, err end
|
|
||||||
-- unfold any folded values
|
|
||||||
while string.find(line, "^%s") do
|
|
||||||
value = value .. line
|
|
||||||
line = sock:receive()
|
|
||||||
if err then return nil, err end
|
|
||||||
end
|
|
||||||
-- save pair in table
|
|
||||||
if headers[name] then
|
|
||||||
headers[name] = headers[name] .. ", " .. value
|
|
||||||
else
|
|
||||||
headers[name] = value
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return headers
|
|
||||||
end
|
|
||||||
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
-- Extra sources and sinks
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
socket.sourcet["http-chunked"] = function(sock, headers)
|
|
||||||
return base.setmetatable({
|
|
||||||
getfd = function() return sock:getfd() end,
|
|
||||||
dirty = function() return sock:dirty() end
|
|
||||||
}, {
|
|
||||||
__call = function()
|
|
||||||
-- get chunk size, skip extention
|
|
||||||
local line, err = sock:receive()
|
|
||||||
if err then return nil, err end
|
|
||||||
local size = base.tonumber(string.gsub(line, ";.*", ""), 16)
|
|
||||||
if not size then return nil, "invalid chunk size" end
|
|
||||||
-- was it the last chunk?
|
|
||||||
if size > 0 then
|
|
||||||
-- if not, get chunk and skip terminating CRLF
|
|
||||||
local chunk, err, part = sock:receive(size)
|
|
||||||
if chunk then sock:receive() end
|
|
||||||
return chunk, err
|
|
||||||
else
|
|
||||||
-- if it was, read trailers into headers table
|
|
||||||
headers, err = receiveheaders(sock, headers)
|
|
||||||
if not headers then return nil, err end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
})
|
|
||||||
end
|
|
||||||
|
|
||||||
socket.sinkt["http-chunked"] = 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 return sock:send("0\r\n\r\n") end
|
|
||||||
local size = string.format("%X\r\n", string.len(chunk))
|
|
||||||
return sock:send(size .. chunk .. "\r\n")
|
|
||||||
end
|
|
||||||
})
|
|
||||||
end
|
|
||||||
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
-- Low level HTTP API
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
local metat = { __index = {} }
|
|
||||||
|
|
||||||
function open(host, port, create)
|
|
||||||
-- create socket with user connect function, or with default
|
|
||||||
local c = socket.try((create or socket.tcp)())
|
|
||||||
local h = base.setmetatable({ c = c }, metat)
|
|
||||||
-- create finalized try
|
|
||||||
h.try = socket.newtry(function() h:close() end)
|
|
||||||
-- set timeout before connecting
|
|
||||||
h.try(c:settimeout(TIMEOUT))
|
|
||||||
h.try(c:connect(host, port or PORT))
|
|
||||||
-- here everything worked
|
|
||||||
return h
|
|
||||||
end
|
|
||||||
|
|
||||||
function metat.__index:sendrequestline(method, uri)
|
|
||||||
local reqline = string.format("%s %s HTTP/1.1\r\n", method or "GET", uri)
|
|
||||||
return self.try(self.c:send(reqline))
|
|
||||||
end
|
|
||||||
|
|
||||||
function metat.__index:sendheaders(headers)
|
|
||||||
local h = "\r\n"
|
|
||||||
for i, v in base.pairs(headers) do
|
|
||||||
h = i .. ": " .. v .. "\r\n" .. h
|
|
||||||
end
|
|
||||||
self.try(self.c:send(h))
|
|
||||||
return 1
|
|
||||||
end
|
|
||||||
|
|
||||||
function metat.__index:sendbody(headers, source, step)
|
|
||||||
source = source or ltn12.source.empty()
|
|
||||||
step = step or ltn12.pump.step
|
|
||||||
-- if we don't know the size in advance, send chunked and hope for the best
|
|
||||||
local mode = "http-chunked"
|
|
||||||
if headers["content-length"] then mode = "keep-open" end
|
|
||||||
return self.try(ltn12.pump.all(source, socket.sink(mode, self.c), step))
|
|
||||||
end
|
|
||||||
|
|
||||||
function metat.__index:receivestatusline()
|
|
||||||
local status = self.try(self.c:receive(5))
|
|
||||||
-- identify HTTP/0.9 responses, which do not contain a status line
|
|
||||||
-- this is just a heuristic, but is what the RFC recommends
|
|
||||||
if status ~= "HTTP/" then return nil, status end
|
|
||||||
-- otherwise proceed reading a status line
|
|
||||||
status = self.try(self.c:receive("*l", status))
|
|
||||||
local code = socket.skip(2, string.find(status, "HTTP/%d*%.%d* (%d%d%d)"))
|
|
||||||
return self.try(base.tonumber(code), status)
|
|
||||||
end
|
|
||||||
|
|
||||||
function metat.__index:receiveheaders()
|
|
||||||
return self.try(receiveheaders(self.c))
|
|
||||||
end
|
|
||||||
|
|
||||||
function metat.__index:receivebody(headers, sink, step)
|
|
||||||
sink = sink or ltn12.sink.null()
|
|
||||||
step = step or ltn12.pump.step
|
|
||||||
local length = base.tonumber(headers["content-length"])
|
|
||||||
local t = headers["transfer-encoding"] -- shortcut
|
|
||||||
local mode = "default" -- connection close
|
|
||||||
if t and t ~= "identity" then
|
|
||||||
mode = "http-chunked"
|
|
||||||
elseif base.tonumber(headers["content-length"]) then
|
|
||||||
mode = "by-length"
|
|
||||||
end
|
|
||||||
return self.try(ltn12.pump.all(socket.source(mode, self.c, length),
|
|
||||||
sink, step))
|
|
||||||
end
|
|
||||||
|
|
||||||
function metat.__index:receive09body(status, sink, step)
|
|
||||||
local source = ltn12.source.rewind(socket.source("until-closed", self.c))
|
|
||||||
source(status)
|
|
||||||
return self.try(ltn12.pump.all(source, sink, step))
|
|
||||||
end
|
|
||||||
|
|
||||||
function metat.__index:close()
|
|
||||||
return self.c:close()
|
|
||||||
end
|
|
||||||
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
-- High level HTTP API
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
local function adjusturi(reqt)
|
|
||||||
local u = reqt
|
|
||||||
-- if there is a proxy, we need the full url. otherwise, just a part.
|
|
||||||
if not reqt.proxy and not PROXY then
|
|
||||||
u = {
|
|
||||||
path = socket.try(reqt.path, "invalid path 'nil'"),
|
|
||||||
params = reqt.params,
|
|
||||||
query = reqt.query,
|
|
||||||
fragment = reqt.fragment
|
|
||||||
}
|
|
||||||
end
|
|
||||||
return url.build(u)
|
|
||||||
end
|
|
||||||
|
|
||||||
local function adjustproxy(reqt)
|
|
||||||
local proxy = reqt.proxy or PROXY
|
|
||||||
if proxy then
|
|
||||||
proxy = url.parse(proxy)
|
|
||||||
return proxy.host, proxy.port or 3128
|
|
||||||
else
|
|
||||||
return reqt.host, reqt.port
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function adjustheaders(reqt)
|
|
||||||
-- default headers
|
|
||||||
local lower = {
|
|
||||||
["user-agent"] = USERAGENT,
|
|
||||||
["host"] = reqt.host,
|
|
||||||
["connection"] = "close, TE",
|
|
||||||
["te"] = "trailers"
|
|
||||||
}
|
|
||||||
-- if we have authentication information, pass it along
|
|
||||||
if reqt.user and reqt.password then
|
|
||||||
lower["authorization"] =
|
|
||||||
"Basic " .. (mime.b64(reqt.user .. ":" .. reqt.password))
|
|
||||||
end
|
|
||||||
-- override with user headers
|
|
||||||
for i, v in base.pairs(reqt.headers or lower) do
|
|
||||||
lower[string.lower(i)] = v
|
|
||||||
end
|
|
||||||
return lower
|
|
||||||
end
|
|
||||||
|
|
||||||
-- default url parts
|
|
||||||
local default = {
|
|
||||||
host = "",
|
|
||||||
port = PORT,
|
|
||||||
path = "/",
|
|
||||||
scheme = "http"
|
|
||||||
}
|
|
||||||
|
|
||||||
local function adjustrequest(reqt)
|
|
||||||
-- parse url if provided
|
|
||||||
local nreqt = reqt.url and url.parse(reqt.url, default) or {}
|
|
||||||
-- explicit components override url
|
|
||||||
for i, v in base.pairs(reqt) do nreqt[i] = v end
|
|
||||||
if nreqt.port == "" then nreqt.port = 80 end
|
|
||||||
socket.try(nreqt.host and nreqt.host ~= "",
|
|
||||||
"invalid host '" .. base.tostring(nreqt.host) .. "'")
|
|
||||||
-- compute uri if user hasn't overriden
|
|
||||||
nreqt.uri = reqt.uri or adjusturi(nreqt)
|
|
||||||
-- ajust host and port if there is a proxy
|
|
||||||
nreqt.host, nreqt.port = adjustproxy(nreqt)
|
|
||||||
-- adjust headers in request
|
|
||||||
nreqt.headers = adjustheaders(nreqt)
|
|
||||||
return nreqt
|
|
||||||
end
|
|
||||||
|
|
||||||
local function shouldredirect(reqt, code, headers)
|
|
||||||
return headers.location and
|
|
||||||
string.gsub(headers.location, "%s", "") ~= "" and
|
|
||||||
(reqt.redirect ~= false) and
|
|
||||||
(code == 301 or code == 302) and
|
|
||||||
(not reqt.method or reqt.method == "GET" or reqt.method == "HEAD")
|
|
||||||
and (not reqt.nredirects or reqt.nredirects < 5)
|
|
||||||
end
|
|
||||||
|
|
||||||
local function shouldreceivebody(reqt, code)
|
|
||||||
if reqt.method == "HEAD" then return nil end
|
|
||||||
if code == 204 or code == 304 then return nil end
|
|
||||||
if code >= 100 and code < 200 then return nil end
|
|
||||||
return 1
|
|
||||||
end
|
|
||||||
|
|
||||||
-- forward declarations
|
|
||||||
local trequest, tredirect
|
|
||||||
|
|
||||||
function tredirect(reqt, location)
|
|
||||||
local result, code, headers, status = trequest {
|
|
||||||
-- the RFC says the redirect URL has to be absolute, but some
|
|
||||||
-- servers do not respect that
|
|
||||||
url = url.absolute(reqt.url, location),
|
|
||||||
source = reqt.source,
|
|
||||||
sink = reqt.sink,
|
|
||||||
headers = reqt.headers,
|
|
||||||
proxy = reqt.proxy,
|
|
||||||
nredirects = (reqt.nredirects or 0) + 1,
|
|
||||||
create = reqt.create
|
|
||||||
}
|
|
||||||
-- pass location header back as a hint we redirected
|
|
||||||
headers = headers or {}
|
|
||||||
headers.location = headers.location or location
|
|
||||||
return result, code, headers, status
|
|
||||||
end
|
|
||||||
|
|
||||||
function trequest(reqt)
|
|
||||||
-- we loop until we get what we want, or
|
|
||||||
-- until we are sure there is no way to get it
|
|
||||||
local nreqt = adjustrequest(reqt)
|
|
||||||
local h = open(nreqt.host, nreqt.port, nreqt.create)
|
|
||||||
-- send request line and headers
|
|
||||||
h:sendrequestline(nreqt.method, nreqt.uri)
|
|
||||||
h:sendheaders(nreqt.headers)
|
|
||||||
-- if there is a body, send it
|
|
||||||
if nreqt.source then
|
|
||||||
h:sendbody(nreqt.headers, nreqt.source, nreqt.step)
|
|
||||||
end
|
|
||||||
local code, status = h:receivestatusline()
|
|
||||||
-- if it is an HTTP/0.9 server, simply get the body and we are done
|
|
||||||
if not code then
|
|
||||||
h:receive09body(status, nreqt.sink, nreqt.step)
|
|
||||||
return 1, 200
|
|
||||||
end
|
|
||||||
local headers
|
|
||||||
-- ignore any 100-continue messages
|
|
||||||
while code == 100 do
|
|
||||||
headers = h:receiveheaders()
|
|
||||||
code, status = h:receivestatusline()
|
|
||||||
end
|
|
||||||
headers = h:receiveheaders()
|
|
||||||
-- at this point we should have a honest reply from the server
|
|
||||||
-- we can't redirect if we already used the source, so we report the error
|
|
||||||
if shouldredirect(nreqt, code, headers) and not nreqt.source then
|
|
||||||
h:close()
|
|
||||||
return tredirect(reqt, headers.location)
|
|
||||||
end
|
|
||||||
-- here we are finally done
|
|
||||||
if shouldreceivebody(nreqt, code) then
|
|
||||||
h:receivebody(headers, nreqt.sink, nreqt.step)
|
|
||||||
end
|
|
||||||
h:close()
|
|
||||||
return 1, code, headers, status
|
|
||||||
end
|
|
||||||
|
|
||||||
local function srequest(u, b)
|
|
||||||
local t = {}
|
|
||||||
local reqt = {
|
|
||||||
url = u,
|
|
||||||
sink = ltn12.sink.table(t)
|
|
||||||
}
|
|
||||||
if b then
|
|
||||||
reqt.source = ltn12.source.string(b)
|
|
||||||
reqt.headers = {
|
|
||||||
["content-length"] = string.len(b),
|
|
||||||
["content-type"] = "application/x-www-form-urlencoded"
|
|
||||||
}
|
|
||||||
reqt.method = "POST"
|
|
||||||
end
|
|
||||||
local code, headers, status = socket.skip(1, trequest(reqt))
|
|
||||||
return table.concat(t), code, headers, status
|
|
||||||
end
|
|
||||||
|
|
||||||
request = socket.protect(function(reqt, body)
|
|
||||||
if base.type(reqt) == "string" then
|
|
||||||
return srequest(reqt, body)
|
|
||||||
else
|
|
||||||
return trequest(reqt)
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
@@ -1,262 +0,0 @@
|
|||||||
-----------------------------------------------------------------------------
|
|
||||||
-- SMTP client support for the Lua language.
|
|
||||||
-- LuaSocket toolkit.
|
|
||||||
-- Author: Diego Nehab
|
|
||||||
-- RCS ID: $Id: smtp.lua,v 1.46 2007/03/12 04:08:40 diego Exp $
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
-- Declare module and import dependencies
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
local base = _G
|
|
||||||
local coroutine = require("coroutine")
|
|
||||||
local string = require("string")
|
|
||||||
local math = require("math")
|
|
||||||
local os = require("os")
|
|
||||||
local socket = require("socket")
|
|
||||||
local tp = require("socket.tp")
|
|
||||||
local ltn12 = require("ltn12")
|
|
||||||
local mime = require("mime")
|
|
||||||
module("socket.smtp")
|
|
||||||
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
-- Program constants
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
-- timeout for connection
|
|
||||||
TIMEOUT = 60
|
|
||||||
-- default server used to send e-mails
|
|
||||||
SERVER = "localhost"
|
|
||||||
-- default port
|
|
||||||
PORT = 25
|
|
||||||
-- domain used in HELO command and default sendmail
|
|
||||||
-- If we are under a CGI, try to get from environment
|
|
||||||
DOMAIN = os.getenv("SERVER_NAME") or "localhost"
|
|
||||||
-- default time zone (means we don't know)
|
|
||||||
ZONE = "-0000"
|
|
||||||
|
|
||||||
---------------------------------------------------------------------------
|
|
||||||
-- Low level SMTP API
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
local metat = { __index = {} }
|
|
||||||
|
|
||||||
function metat.__index:greet(domain)
|
|
||||||
self.try(self.tp:check("2.."))
|
|
||||||
self.try(self.tp:command("EHLO", domain or DOMAIN))
|
|
||||||
return socket.skip(1, self.try(self.tp:check("2..")))
|
|
||||||
end
|
|
||||||
|
|
||||||
function metat.__index:mail(from)
|
|
||||||
self.try(self.tp:command("MAIL", "FROM:" .. from))
|
|
||||||
return self.try(self.tp:check("2.."))
|
|
||||||
end
|
|
||||||
|
|
||||||
function metat.__index:rcpt(to)
|
|
||||||
self.try(self.tp:command("RCPT", "TO:" .. to))
|
|
||||||
return self.try(self.tp:check("2.."))
|
|
||||||
end
|
|
||||||
|
|
||||||
function metat.__index:data(src, step)
|
|
||||||
self.try(self.tp:command("DATA"))
|
|
||||||
self.try(self.tp:check("3.."))
|
|
||||||
self.try(self.tp:source(src, step))
|
|
||||||
self.try(self.tp:send("\r\n.\r\n"))
|
|
||||||
return self.try(self.tp:check("2.."))
|
|
||||||
end
|
|
||||||
|
|
||||||
function metat.__index:quit()
|
|
||||||
self.try(self.tp:command("QUIT"))
|
|
||||||
return self.try(self.tp:check("2.."))
|
|
||||||
end
|
|
||||||
|
|
||||||
function metat.__index:close()
|
|
||||||
return self.tp:close()
|
|
||||||
end
|
|
||||||
|
|
||||||
function metat.__index:login(user, password)
|
|
||||||
self.try(self.tp:command("AUTH", "LOGIN"))
|
|
||||||
self.try(self.tp:check("3.."))
|
|
||||||
self.try(self.tp:command(mime.b64(user)))
|
|
||||||
self.try(self.tp:check("3.."))
|
|
||||||
self.try(self.tp:command(mime.b64(password)))
|
|
||||||
return self.try(self.tp:check("2.."))
|
|
||||||
end
|
|
||||||
|
|
||||||
function metat.__index:plain(user, password)
|
|
||||||
local auth = "PLAIN " .. mime.b64("\0" .. user .. "\0" .. password)
|
|
||||||
self.try(self.tp:command("AUTH", auth))
|
|
||||||
return self.try(self.tp:check("2.."))
|
|
||||||
end
|
|
||||||
|
|
||||||
function metat.__index:auth(user, password, ext)
|
|
||||||
if not user or not password then return 1 end
|
|
||||||
if string.find(ext, "AUTH[^\n]+LOGIN") then
|
|
||||||
return self:login(user, password)
|
|
||||||
elseif string.find(ext, "AUTH[^\n]+PLAIN") then
|
|
||||||
return self:plain(user, password)
|
|
||||||
else
|
|
||||||
self.try(nil, "authentication not supported")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- send message or throw an exception
|
|
||||||
function metat.__index:send(mailt)
|
|
||||||
self:mail(mailt.from)
|
|
||||||
if base.type(mailt.rcpt) == "table" then
|
|
||||||
for i, v in base.ipairs(mailt.rcpt) do
|
|
||||||
self:rcpt(v)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
self:rcpt(mailt.rcpt)
|
|
||||||
end
|
|
||||||
self:data(ltn12.source.chain(mailt.source, mime.stuff()), mailt.step)
|
|
||||||
end
|
|
||||||
|
|
||||||
function open(server, port, create)
|
|
||||||
local tp = socket.try(tp.connect(server or SERVER, port or PORT,
|
|
||||||
TIMEOUT, create))
|
|
||||||
local s = base.setmetatable({ tp = tp }, metat)
|
|
||||||
-- make sure tp is closed if we get an exception
|
|
||||||
s.try = socket.newtry(function()
|
|
||||||
s:close()
|
|
||||||
end)
|
|
||||||
return s
|
|
||||||
end
|
|
||||||
|
|
||||||
-- convert headers to lowercase
|
|
||||||
local function lower_headers(headers)
|
|
||||||
local lower = {}
|
|
||||||
for i, v in base.pairs(headers or lower) do
|
|
||||||
lower[string.lower(i)] = v
|
|
||||||
end
|
|
||||||
return lower
|
|
||||||
end
|
|
||||||
|
|
||||||
---------------------------------------------------------------------------
|
|
||||||
-- Multipart message source
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
-- returns a hopefully unique mime boundary
|
|
||||||
local seqno = 0
|
|
||||||
local function newboundary()
|
|
||||||
seqno = seqno + 1
|
|
||||||
return string.format('%s%05d==%05u', os.date('%d%m%Y%H%M%S'),
|
|
||||||
math.random(0, 99999), seqno)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- send_message forward declaration
|
|
||||||
local send_message
|
|
||||||
|
|
||||||
-- yield the headers all at once, it's faster
|
|
||||||
local function send_headers(headers)
|
|
||||||
local h = "\r\n"
|
|
||||||
for i, v in base.pairs(headers) do
|
|
||||||
h = i .. ': ' .. v .. "\r\n" .. h
|
|
||||||
end
|
|
||||||
coroutine.yield(h)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- yield multipart message body from a multipart message table
|
|
||||||
local function send_multipart(mesgt)
|
|
||||||
-- make sure we have our boundary and send headers
|
|
||||||
local bd = newboundary()
|
|
||||||
local headers = lower_headers(mesgt.headers or {})
|
|
||||||
headers['content-type'] = headers['content-type'] or 'multipart/mixed'
|
|
||||||
headers['content-type'] = headers['content-type'] ..
|
|
||||||
'; boundary="' .. bd .. '"'
|
|
||||||
send_headers(headers)
|
|
||||||
-- send preamble
|
|
||||||
if mesgt.body.preamble then
|
|
||||||
coroutine.yield(mesgt.body.preamble)
|
|
||||||
coroutine.yield("\r\n")
|
|
||||||
end
|
|
||||||
-- send each part separated by a boundary
|
|
||||||
for i, m in base.ipairs(mesgt.body) do
|
|
||||||
coroutine.yield("\r\n--" .. bd .. "\r\n")
|
|
||||||
send_message(m)
|
|
||||||
end
|
|
||||||
-- send last boundary
|
|
||||||
coroutine.yield("\r\n--" .. bd .. "--\r\n\r\n")
|
|
||||||
-- send epilogue
|
|
||||||
if mesgt.body.epilogue then
|
|
||||||
coroutine.yield(mesgt.body.epilogue)
|
|
||||||
coroutine.yield("\r\n")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- yield message body from a source
|
|
||||||
local function send_source(mesgt)
|
|
||||||
-- make sure we have a content-type
|
|
||||||
local headers = lower_headers(mesgt.headers or {})
|
|
||||||
headers['content-type'] = headers['content-type'] or
|
|
||||||
'text/plain; charset="iso-8859-1"'
|
|
||||||
send_headers(headers)
|
|
||||||
-- send body from source
|
|
||||||
while true do
|
|
||||||
local chunk, err = mesgt.body()
|
|
||||||
if err then
|
|
||||||
coroutine.yield(nil, err)
|
|
||||||
elseif chunk then
|
|
||||||
coroutine.yield(chunk)
|
|
||||||
else
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- yield message body from a string
|
|
||||||
local function send_string(mesgt)
|
|
||||||
-- make sure we have a content-type
|
|
||||||
local headers = lower_headers(mesgt.headers or {})
|
|
||||||
headers['content-type'] = headers['content-type'] or
|
|
||||||
'text/plain; charset="iso-8859-1"'
|
|
||||||
send_headers(headers)
|
|
||||||
-- send body from string
|
|
||||||
coroutine.yield(mesgt.body)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- message source
|
|
||||||
function send_message(mesgt)
|
|
||||||
if base.type(mesgt.body) == "table" then
|
|
||||||
send_multipart(mesgt)
|
|
||||||
elseif base.type(mesgt.body) == "function" then
|
|
||||||
send_source(mesgt)
|
|
||||||
else
|
|
||||||
send_string(mesgt)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- set defaul headers
|
|
||||||
local function adjust_headers(mesgt)
|
|
||||||
local lower = lower_headers(mesgt.headers)
|
|
||||||
lower["date"] = lower["date"] or
|
|
||||||
os.date("!%a, %d %b %Y %H:%M:%S ") .. (mesgt.zone or ZONE)
|
|
||||||
lower["x-mailer"] = lower["x-mailer"] or socket._VERSION
|
|
||||||
-- this can't be overriden
|
|
||||||
lower["mime-version"] = "1.0"
|
|
||||||
return lower
|
|
||||||
end
|
|
||||||
|
|
||||||
function message(mesgt)
|
|
||||||
mesgt.headers = adjust_headers(mesgt)
|
|
||||||
-- create and return message source
|
|
||||||
local co = coroutine.create(function() send_message(mesgt) end)
|
|
||||||
return function()
|
|
||||||
local ret, a, b = coroutine.resume(co)
|
|
||||||
if ret then
|
|
||||||
return a, b
|
|
||||||
else
|
|
||||||
return nil, a
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
---------------------------------------------------------------------------
|
|
||||||
-- High level SMTP API
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
send = socket.protect(function(mailt)
|
|
||||||
local s = open(mailt.server, mailt.port, mailt.create)
|
|
||||||
local ext = s:greet(mailt.domain)
|
|
||||||
s:auth(mailt.user, mailt.password, ext)
|
|
||||||
s:send(mailt)
|
|
||||||
s:quit()
|
|
||||||
return s:close()
|
|
||||||
end)
|
|
||||||
@@ -1,127 +0,0 @@
|
|||||||
-----------------------------------------------------------------------------
|
|
||||||
-- Unified SMTP/FTP subsystem
|
|
||||||
-- LuaSocket toolkit.
|
|
||||||
-- Author: Diego Nehab
|
|
||||||
-- RCS ID: $Id: tp.lua,v 1.22 2006/03/14 09:04:15 diego Exp $
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
-- Declare module and import dependencies
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
local base = _G
|
|
||||||
local string = require("string")
|
|
||||||
local socket = require("socket")
|
|
||||||
local ltn12 = require("ltn12")
|
|
||||||
module("socket.tp")
|
|
||||||
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
-- Program constants
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
TIMEOUT = 60
|
|
||||||
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
-- Implementation
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
-- gets server reply (works for SMTP and FTP)
|
|
||||||
local function get_reply(c)
|
|
||||||
local code, current, sep
|
|
||||||
local line, err = c:receive()
|
|
||||||
local reply = line
|
|
||||||
if err then return nil, err end
|
|
||||||
code, sep = socket.skip(2, string.find(line, "^(%d%d%d)(.?)"))
|
|
||||||
if not code then return nil, "invalid server reply" end
|
|
||||||
if sep == "-" then -- reply is multiline
|
|
||||||
repeat
|
|
||||||
line, err = c:receive()
|
|
||||||
if err then return nil, err end
|
|
||||||
current, sep = socket.skip(2, string.find(line, "^(%d%d%d)(.?)"))
|
|
||||||
reply = reply .. "\n" .. line
|
|
||||||
-- reply ends with same code
|
|
||||||
until code == current and sep == " "
|
|
||||||
end
|
|
||||||
return code, reply
|
|
||||||
end
|
|
||||||
|
|
||||||
-- metatable for sock object
|
|
||||||
local metat = { __index = {} }
|
|
||||||
|
|
||||||
function metat.__index:check(ok)
|
|
||||||
local code, reply = get_reply(self.c)
|
|
||||||
if not code then return nil, reply end
|
|
||||||
if base.type(ok) ~= "function" then
|
|
||||||
if base.type(ok) == "table" then
|
|
||||||
for i, v in base.ipairs(ok) do
|
|
||||||
if string.find(code, v) then
|
|
||||||
return base.tonumber(code), reply
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return nil, reply
|
|
||||||
else
|
|
||||||
if string.find(code, ok) then
|
|
||||||
return base.tonumber(code), reply
|
|
||||||
else
|
|
||||||
return nil, reply
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
|
||||||
return ok(base.tonumber(code), reply)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function metat.__index:command(cmd, arg)
|
|
||||||
if arg then
|
|
||||||
return self.c:send(cmd .. " " .. arg .. "\r\n")
|
|
||||||
else
|
|
||||||
return self.c:send(cmd .. "\r\n")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function metat.__index:sink(snk, pat)
|
|
||||||
local chunk, err = c:receive(pat)
|
|
||||||
return snk(chunk, err)
|
|
||||||
end
|
|
||||||
|
|
||||||
function metat.__index:send(data)
|
|
||||||
return self.c:send(data)
|
|
||||||
end
|
|
||||||
|
|
||||||
function metat.__index:receive(pat)
|
|
||||||
return self.c:receive(pat)
|
|
||||||
end
|
|
||||||
|
|
||||||
function metat.__index:getfd()
|
|
||||||
return self.c:getfd()
|
|
||||||
end
|
|
||||||
|
|
||||||
function metat.__index:dirty()
|
|
||||||
return self.c:dirty()
|
|
||||||
end
|
|
||||||
|
|
||||||
function metat.__index:getcontrol()
|
|
||||||
return self.c
|
|
||||||
end
|
|
||||||
|
|
||||||
function metat.__index:source(source, step)
|
|
||||||
local sink = socket.sink("keep-open", self.c)
|
|
||||||
local ret, err = ltn12.pump.all(source, sink, step or ltn12.pump.step)
|
|
||||||
return ret, err
|
|
||||||
end
|
|
||||||
|
|
||||||
-- closes the underlying c
|
|
||||||
function metat.__index:close()
|
|
||||||
self.c:close()
|
|
||||||
return 1
|
|
||||||
end
|
|
||||||
|
|
||||||
-- connect with server and return c object
|
|
||||||
function connect(host, port, timeout, create)
|
|
||||||
local c, e = (create or socket.tcp)()
|
|
||||||
if not c then return nil, e end
|
|
||||||
c:settimeout(timeout or TIMEOUT)
|
|
||||||
local r, e = c:connect(host, port)
|
|
||||||
if not r then
|
|
||||||
c:close()
|
|
||||||
return nil, e
|
|
||||||
end
|
|
||||||
return base.setmetatable({ c = c }, metat)
|
|
||||||
end
|
|
||||||
@@ -1,311 +0,0 @@
|
|||||||
-----------------------------------------------------------------------------
|
|
||||||
-- URI parsing, composition and relative URL resolution
|
|
||||||
-- LuaSocket toolkit.
|
|
||||||
-- Author: Diego Nehab
|
|
||||||
-- RCS ID: $Id: url.lua,v 1.38 2006/04/03 04:45:42 diego Exp $
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
-- Declare module
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
local string = require("string")
|
|
||||||
local base = _G
|
|
||||||
local table = require("table")
|
|
||||||
module("socket.url")
|
|
||||||
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
-- Module version
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
_VERSION = "URL 1.0.1"
|
|
||||||
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
-- Encodes a string into its escaped hexadecimal representation
|
|
||||||
-- Input
|
|
||||||
-- s: binary string to be encoded
|
|
||||||
-- Returns
|
|
||||||
-- escaped representation of string binary
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
function escape(s)
|
|
||||||
return string.gsub(s, "([^A-Za-z0-9_])", function(c)
|
|
||||||
return string.format("%%%02x", string.byte(c))
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
-- Protects a path segment, to prevent it from interfering with the
|
|
||||||
-- url parsing.
|
|
||||||
-- Input
|
|
||||||
-- s: binary string to be encoded
|
|
||||||
-- Returns
|
|
||||||
-- escaped representation of string binary
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
local function make_set(t)
|
|
||||||
local s = {}
|
|
||||||
for i, v in base.ipairs(t) do
|
|
||||||
s[t[i]] = 1
|
|
||||||
end
|
|
||||||
return s
|
|
||||||
end
|
|
||||||
|
|
||||||
-- these are allowed withing a path segment, along with alphanum
|
|
||||||
-- other characters must be escaped
|
|
||||||
local segment_set = make_set {
|
|
||||||
"-", "_", ".", "!", "~", "*", "'", "(",
|
|
||||||
")", ":", "@", "&", "=", "+", "$", ",",
|
|
||||||
}
|
|
||||||
|
|
||||||
local function protect_segment(s)
|
|
||||||
return string.gsub(s, "([^A-Za-z0-9_])", function(c)
|
|
||||||
if segment_set[c] then
|
|
||||||
return c
|
|
||||||
else
|
|
||||||
return string.format("%%%02x", string.byte(c))
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
-- Encodes a string into its escaped hexadecimal representation
|
|
||||||
-- Input
|
|
||||||
-- s: binary string to be encoded
|
|
||||||
-- Returns
|
|
||||||
-- escaped representation of string binary
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
function unescape(s)
|
|
||||||
return string.gsub(s, "%%(%x%x)", function(hex)
|
|
||||||
return string.char(base.tonumber(hex, 16))
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
-- Builds a path from a base path and a relative path
|
|
||||||
-- Input
|
|
||||||
-- base_path
|
|
||||||
-- relative_path
|
|
||||||
-- Returns
|
|
||||||
-- corresponding absolute path
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
local function absolute_path(base_path, relative_path)
|
|
||||||
if string.sub(relative_path, 1, 1) == "/" then return relative_path end
|
|
||||||
local path = string.gsub(base_path, "[^/]*$", "")
|
|
||||||
path = path .. relative_path
|
|
||||||
path = string.gsub(path, "([^/]*%./)", function(s)
|
|
||||||
if s ~= "./" then return s else return "" end
|
|
||||||
end)
|
|
||||||
path = string.gsub(path, "/%.$", "/")
|
|
||||||
local reduced
|
|
||||||
while reduced ~= path do
|
|
||||||
reduced = path
|
|
||||||
path = string.gsub(reduced, "([^/]*/%.%./)", function(s)
|
|
||||||
if s ~= "../../" then return "" else return s end
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
path = string.gsub(reduced, "([^/]*/%.%.)$", function(s)
|
|
||||||
if s ~= "../.." then return "" else return s end
|
|
||||||
end)
|
|
||||||
return path
|
|
||||||
end
|
|
||||||
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
-- Parses a url and returns a table with all its parts according to RFC 2396
|
|
||||||
-- The following grammar describes the names given to the URL parts
|
|
||||||
-- <url> ::= <scheme>://<authority>/<path>;<params>?<query>#<fragment>
|
|
||||||
-- <authority> ::= <userinfo>@<host>:<port>
|
|
||||||
-- <userinfo> ::= <user>[:<password>]
|
|
||||||
-- <path> :: = {<segment>/}<segment>
|
|
||||||
-- Input
|
|
||||||
-- url: uniform resource locator of request
|
|
||||||
-- default: table with default values for each field
|
|
||||||
-- Returns
|
|
||||||
-- table with the following fields, where RFC naming conventions have
|
|
||||||
-- been preserved:
|
|
||||||
-- scheme, authority, userinfo, user, password, host, port,
|
|
||||||
-- path, params, query, fragment
|
|
||||||
-- Obs:
|
|
||||||
-- the leading '/' in {/<path>} is considered part of <path>
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
function parse(url, default)
|
|
||||||
-- initialize default parameters
|
|
||||||
local parsed = {}
|
|
||||||
for i, v in base.pairs(default or parsed) do parsed[i] = v end
|
|
||||||
-- empty url is parsed to nil
|
|
||||||
if not url or url == "" then return nil, "invalid url" end
|
|
||||||
-- remove whitespace
|
|
||||||
-- url = string.gsub(url, "%s", "")
|
|
||||||
-- get fragment
|
|
||||||
url = string.gsub(url, "#(.*)$", function(f)
|
|
||||||
parsed.fragment = f
|
|
||||||
return ""
|
|
||||||
end)
|
|
||||||
-- get scheme
|
|
||||||
url = string.gsub(url, "^([%w][%w%+%-%.]*)%:",
|
|
||||||
function(s)
|
|
||||||
parsed.scheme = s; return ""
|
|
||||||
end)
|
|
||||||
-- get authority
|
|
||||||
url = string.gsub(url, "^//([^/]*)", function(n)
|
|
||||||
parsed.authority = n
|
|
||||||
return ""
|
|
||||||
end)
|
|
||||||
-- get query stringing
|
|
||||||
url = string.gsub(url, "%?(.*)", function(q)
|
|
||||||
parsed.query = q
|
|
||||||
return ""
|
|
||||||
end)
|
|
||||||
-- get params
|
|
||||||
url = string.gsub(url, "%;(.*)", function(p)
|
|
||||||
parsed.params = p
|
|
||||||
return ""
|
|
||||||
end)
|
|
||||||
-- path is whatever was left
|
|
||||||
if url ~= "" then parsed.path = url end
|
|
||||||
local authority = parsed.authority
|
|
||||||
if not authority then return parsed end
|
|
||||||
authority = string.gsub(authority, "^([^@]*)@",
|
|
||||||
function(u)
|
|
||||||
parsed.userinfo = u; return ""
|
|
||||||
end)
|
|
||||||
authority = string.gsub(authority, ":([^:]*)$",
|
|
||||||
function(p)
|
|
||||||
parsed.port = p; return ""
|
|
||||||
end)
|
|
||||||
if authority ~= "" then parsed.host = authority end
|
|
||||||
local userinfo = parsed.userinfo
|
|
||||||
if not userinfo then return parsed end
|
|
||||||
userinfo = string.gsub(userinfo, ":([^:]*)$",
|
|
||||||
function(p)
|
|
||||||
parsed.password = p; return ""
|
|
||||||
end)
|
|
||||||
parsed.user = userinfo
|
|
||||||
return parsed
|
|
||||||
end
|
|
||||||
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
-- Rebuilds a parsed URL from its components.
|
|
||||||
-- Components are protected if any reserved or unallowed characters are found
|
|
||||||
-- Input
|
|
||||||
-- parsed: parsed URL, as returned by parse
|
|
||||||
-- Returns
|
|
||||||
-- a stringing with the corresponding URL
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
function build(parsed)
|
|
||||||
local ppath = parse_path(parsed.path or "")
|
|
||||||
local url = build_path(ppath)
|
|
||||||
if parsed.params then url = url .. ";" .. parsed.params end
|
|
||||||
if parsed.query then url = url .. "?" .. parsed.query end
|
|
||||||
local authority = parsed.authority
|
|
||||||
if parsed.host then
|
|
||||||
authority = parsed.host
|
|
||||||
if parsed.port then authority = authority .. ":" .. parsed.port end
|
|
||||||
local userinfo = parsed.userinfo
|
|
||||||
if parsed.user then
|
|
||||||
userinfo = parsed.user
|
|
||||||
if parsed.password then
|
|
||||||
userinfo = userinfo .. ":" .. parsed.password
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if userinfo then authority = userinfo .. "@" .. authority end
|
|
||||||
end
|
|
||||||
if authority then url = "//" .. authority .. url end
|
|
||||||
if parsed.scheme then url = parsed.scheme .. ":" .. url end
|
|
||||||
if parsed.fragment then url = url .. "#" .. parsed.fragment end
|
|
||||||
-- url = string.gsub(url, "%s", "")
|
|
||||||
return url
|
|
||||||
end
|
|
||||||
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
-- Builds a absolute URL from a base and a relative URL according to RFC 2396
|
|
||||||
-- Input
|
|
||||||
-- base_url
|
|
||||||
-- relative_url
|
|
||||||
-- Returns
|
|
||||||
-- corresponding absolute url
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
function absolute(base_url, relative_url)
|
|
||||||
if base.type(base_url) == "table" then
|
|
||||||
base_parsed = base_url
|
|
||||||
base_url = build(base_parsed)
|
|
||||||
else
|
|
||||||
base_parsed = parse(base_url)
|
|
||||||
end
|
|
||||||
local relative_parsed = parse(relative_url)
|
|
||||||
if not base_parsed then
|
|
||||||
return relative_url
|
|
||||||
elseif not relative_parsed then
|
|
||||||
return base_url
|
|
||||||
elseif relative_parsed.scheme then
|
|
||||||
return relative_url
|
|
||||||
else
|
|
||||||
relative_parsed.scheme = base_parsed.scheme
|
|
||||||
if not relative_parsed.authority then
|
|
||||||
relative_parsed.authority = base_parsed.authority
|
|
||||||
if not relative_parsed.path then
|
|
||||||
relative_parsed.path = base_parsed.path
|
|
||||||
if not relative_parsed.params then
|
|
||||||
relative_parsed.params = base_parsed.params
|
|
||||||
if not relative_parsed.query then
|
|
||||||
relative_parsed.query = base_parsed.query
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
|
||||||
relative_parsed.path = absolute_path(base_parsed.path or "",
|
|
||||||
relative_parsed.path)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return build(relative_parsed)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
-- Breaks a path into its segments, unescaping the segments
|
|
||||||
-- Input
|
|
||||||
-- path
|
|
||||||
-- Returns
|
|
||||||
-- segment: a table with one entry per segment
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
function parse_path(path)
|
|
||||||
local parsed = {}
|
|
||||||
path = path or ""
|
|
||||||
--path = string.gsub(path, "%s", "")
|
|
||||||
string.gsub(path, "([^/]+)", function(s) table.insert(parsed, s) end)
|
|
||||||
for i = 1, #parsed do
|
|
||||||
parsed[i] = unescape(parsed[i])
|
|
||||||
end
|
|
||||||
if string.sub(path, 1, 1) == "/" then parsed.is_absolute = 1 end
|
|
||||||
if string.sub(path, -1, -1) == "/" then parsed.is_directory = 1 end
|
|
||||||
return parsed
|
|
||||||
end
|
|
||||||
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
-- Builds a path component from its segments, escaping protected characters.
|
|
||||||
-- Input
|
|
||||||
-- parsed: path segments
|
|
||||||
-- unsafe: if true, segments are not protected before path is built
|
|
||||||
-- Returns
|
|
||||||
-- path: corresponding path stringing
|
|
||||||
-----------------------------------------------------------------------------
|
|
||||||
function build_path(parsed, unsafe)
|
|
||||||
local path = ""
|
|
||||||
local n = #parsed
|
|
||||||
if unsafe then
|
|
||||||
for i = 1, n - 1 do
|
|
||||||
path = path .. parsed[i]
|
|
||||||
path = path .. "/"
|
|
||||||
end
|
|
||||||
if n > 0 then
|
|
||||||
path = path .. parsed[n]
|
|
||||||
if parsed.is_directory then path = path .. "/" end
|
|
||||||
end
|
|
||||||
else
|
|
||||||
for i = 1, n - 1 do
|
|
||||||
path = path .. protect_segment(parsed[i])
|
|
||||||
path = path .. "/"
|
|
||||||
end
|
|
||||||
if n > 0 then
|
|
||||||
path = path .. protect_segment(parsed[n])
|
|
||||||
if parsed.is_directory then path = path .. "/" end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if parsed.is_absolute then path = "/" .. path end
|
|
||||||
return path
|
|
||||||
end
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
@echo off
|
|
||||||
cd /d %~dp0
|
|
||||||
|
|
||||||
set "PATH=C:\msys64\mingw32\bin;%PATH%"
|
|
||||||
|
|
||||||
if not exist build mkdir build
|
|
||||||
|
|
||||||
set buildargs=-Wall -Werror -m32 -shared -Isrc -Iinc/tsfuncs -Iinc/lua -lpsapi -L. -llua5.1 -static-libgcc -static-libstdc++
|
|
||||||
|
|
||||||
echo on
|
|
||||||
g++ src/bllua4.cpp %buildargs% -o build\BlockLua.dll
|
|
||||||
g++ -DBLLUA_UNSAFE src/bllua4.cpp %buildargs% -o build\BlockLua-Unsafe.dll
|
|
||||||
@echo off
|
|
||||||
126
readme.md
126
readme.md
@@ -1,33 +1,35 @@
|
|||||||
|
|
||||||
# BlockLua
|
# BlockLua
|
||||||
|
|
||||||
Lua scripting for Blockland
|
Lua scripting for Blockland
|
||||||
|
|
||||||
## How to Install
|
## How to Install
|
||||||
|
|
||||||
- Install RedBlocklandLoader
|
- Install RedBlocklandLoader
|
||||||
- Copy `lua5.1.dll` into your Blockland install folder, next to `Blockland.exe`
|
- Copy `lua5.1.dll` into your Blockland install folder, next to `Blockland.exe`
|
||||||
- Copy `BlockLua.dll` into the `modules` folder within the Blockland folder
|
- Copy `BlockLua.dll` into the `modules` folder within the Blockland folder
|
||||||
- Optional: Copy the `lualib` folder into `modules`
|
|
||||||
|
|
||||||
|
|
||||||
## Quick Reference
|
## Quick Reference
|
||||||
|
|
||||||
### From TorqueScript
|
### From TorqueScript
|
||||||
`'print('hello world')` - Execute Lua code in the console by prepending a `'` (single quote)
|
|
||||||
`luaeval("code");` - Eval Lua code
|
`'print('hello world')` - Execute Lua in the console by prepending a `'` (single quote)
|
||||||
`luacall("funcName", %args);` - Call a Lua global function
|
`luaeval("code");` - Execute Lua code
|
||||||
`luaexec("fileName");` - Execute a Lua file. Path rules are the same as executing .cs files.
|
`luacall("funcName", %args...);` - Call a Lua function (supports indexing tables and object methods)
|
||||||
`luaget("varName");` - Read a Lua global variable
|
`luaexec("fileName");` - Execute a Lua file. Path rules are the same as when executing .cs files, relative paths are allowed.
|
||||||
`luaset("varName");` - Write a Lua global variable
|
`luaget("varName");` - Read a Lua global variable (supports indexing tables)
|
||||||
|
`luaset("varName", %value);` - Write a Lua global variable (supports indexing tables)
|
||||||
|
|
||||||
### From Lua
|
### From Lua
|
||||||
|
|
||||||
`bl.eval('code')` - Eval TorqueScript code
|
`bl.eval('code')` - Eval TorqueScript code
|
||||||
`bl.funcName(args)` - Call a TorqueScript function
|
`bl.funcName(args)` - Call a TorqueScript function
|
||||||
`bl.varName` - Read a TorqueScript global variable
|
`bl.varName` - Read a TorqueScript global variable
|
||||||
`bl['varName']` - Read a TorqueScript global variable (i.e. with special characters in the name, or from an array)
|
`bl['varName']` - Read a TorqueScript global variable (i.e. with special characters in the name, or from an array)
|
||||||
`bl.set('varName', value)` - Write a TorqueScript global variable
|
`bl.set('varName', value)` - Write a TorqueScript global variable
|
||||||
|
`bl['namespaceName::funcName'](args)` - Call a namespaced TorqueScript function
|
||||||
|
|
||||||
### Accessing Torque Objects from Lua
|
### Accessing Torque Objects from Lua
|
||||||
|
|
||||||
`bl.objectName` - Access a Torque object by name
|
`bl.objectName` - Access a Torque object by name
|
||||||
`bl[objectID]` - Access a Torque object by ID (or name)
|
`bl[objectID]` - Access a Torque object by ID (or name)
|
||||||
`object.fieldOrKey` - Read a field or Lua key from a Torque object
|
`object.fieldOrKey` - Read a field or Lua key from a Torque object
|
||||||
@@ -35,26 +37,43 @@ Lua scripting for Blockland
|
|||||||
`object.key = value` - Associate Lua data with a Torque object
|
`object.key = value` - Associate Lua data with a Torque object
|
||||||
`object:method(args)` - Call a Torque object method
|
`object:method(args)` - Call a Torque object method
|
||||||
`object[index]` - Access a member of a Torque set or group
|
`object[index]` - Access a member of a Torque set or group
|
||||||
`for childIndex, child in object:members() do` - Iterate objects within of a Torque set or group. Indices start at 0 like in Torque.
|
`for child in object:members() do` - Iterate objects within of a Torque set or group. Indices start at 0 like in Torque.
|
||||||
|
`bl.isObject(object, objectID, or 'objectName')` - Check if an object exists
|
||||||
|
`object:exists()` - Check if an object exists
|
||||||
|
|
||||||
### Timing/Schedules
|
### Timing/Schedules
|
||||||
|
|
||||||
`sched = bl.schedule(timeMs, function, args...)` - Schedule a Lua function to be called later, similar to schedule in Torque
|
`sched = bl.schedule(timeMs, function, args...)` - Schedule a Lua function to be called later, similar to schedule in Torque
|
||||||
`sched:cancel()` - Cancel a previously scheduled timer
|
`sched:cancel()` - Cancel a previously scheduled timer
|
||||||
|
|
||||||
### Raycasts and Searches
|
### Raycasts and Searches
|
||||||
|
|
||||||
`hitObject, hitPos, hitNormal = bl.raycast(vector{startPosX,y,z}, vector{endPosX,y,z}, 'objtype'/{'objtypes',...}, ignoreObjects...?)` - Cast a ray in the world over objects of the specified type(s) (possibly excluding some objects), and return the object hit, the position of the hit, and the normal vector to the surface hit. See the Types section for a list of valid object types.
|
`hitObject, hitPos, hitNormal = bl.raycast(vector{startPosX,y,z}, vector{endPosX,y,z}, 'objtype'/{'objtypes',...}, ignoreObjects...?)` - Cast a ray in the world over objects of the specified type(s) (possibly excluding some objects), and return the object hit, the position of the hit, and the normal vector to the surface hit. See the Types section for a list of valid object types.
|
||||||
`for object in bl.boxSearch(vector{centerX,y,z}, vector{sizeX,y,z}, 'objtype'/{'objtypes',...}) do` - Find all objects in the world of the specified type(s) whose bounding box overlaps with the specified box. See the Types section for a list of valid object types.
|
`for object in bl.boxSearch(vector{centerX,y,z}, vector{sizeX,y,z}, 'objtype'/{'objtypes',...}) do` - Find all objects in the world of the specified type(s) whose bounding box overlaps with the specified box. See the Types section for a list of valid object types.
|
||||||
`for object in bl.radiusSearch(vector{centerX,y,z}, radius, 'objtype'/{'objtypes',...}) do` - Find all objects of the specified type(s) whose bounding box overlaps with the specified sphere. See the Types section for a list of valid object types.
|
`for object in bl.radiusSearch(vector{centerX,y,z}, radius, 'objtype'/{'objtypes',...}) do` - Find all objects of the specified type(s) whose bounding box overlaps with the specified sphere. See the Types section for a list of valid object types.
|
||||||
|
|
||||||
|
### List of Object Classes (for raycasts and searches)
|
||||||
|
|
||||||
|
`'all'` - Any object
|
||||||
|
`'player'` - Players or bots
|
||||||
|
`'item'` - Items
|
||||||
|
`'vehicle'` - Vehicles
|
||||||
|
`'projectile'` - Projectiles
|
||||||
|
`'brick'` - Bricks with raycasting enabled
|
||||||
|
`'brickalways'` - All bricks including those with raycasting disabled
|
||||||
|
Other types: `'static'`, `'environment'`, `'terrain'`, `'water'`, `'trigger'`, `'marker'`, `'gamebase'`, `'shapebase'`, `'camera'`, `'staticshape'`, `'vehicleblocker'`, `'explosion'`, `'corpse'`, `'debris'`, `'physicalzone'`, `'staticts'`, `'staticrendered'`, `'damagableitem'`
|
||||||
|
|
||||||
### Server-Client Communication
|
### Server-Client Communication
|
||||||
`bl.addServerCmd('commandName', function(client, args...) yourCode end)` - Register a /command on the server
|
|
||||||
`bl.addClientCmd('commandName', function(args...) yourCode end)` - Register a client command on the client
|
`bl.addServerCmd('commandName', function(client, args...) ... end)` - Register a /command on the server
|
||||||
`bl.commandToServer('commandName', args...)` - Execute a server command as a client
|
`bl.addClientCmd('commandName', function(args...) ... end)` - Register a client command on the client
|
||||||
`bl.commandToClient('commandName', args...)` - As the server, execute a client command on a specific client
|
`bl.commandToServer('commandName', args...)` - As a client, execute a server command
|
||||||
|
`bl.commandToClient(client, 'commandName', args...)` - As the server, execute a client command on a specific client
|
||||||
`bl.commandToAll('commandName', args...)` - As the server, execute a client command on all clients
|
`bl.commandToAll('commandName', args...)` - As the server, execute a client command on all clients
|
||||||
|
|
||||||
### Packages/Hooks
|
### Packages/Hooks
|
||||||
`bl.hook('packageName', 'functionName', 'before'/'after', function(args) yourCode end)` - Hook a Torque function with a Lua function.
|
|
||||||
|
`bl.hook('packageName', 'functionName', 'before'/'after', function(args) ... end)` - Hook a Torque function with a Lua function.
|
||||||
`args` is an array containing the arguments provided to the function. If the hook is `before`, these can be modified before being passed to the parent function.
|
`args` is an array containing the arguments provided to the function. If the hook is `before`, these can be modified before being passed to the parent function.
|
||||||
If `args._return` is set to anything other than nil by a `before` hook, the parent function will not be called, and the function will simply return that value. Also in this case, any `after` hook will not be executed.
|
If `args._return` is set to anything other than nil by a `before` hook, the parent function will not be called, and the function will simply return that value. Also in this case, any `after` hook will not be executed.
|
||||||
In an `after` hook, `args._return` is set to the value returned by the parent function, and can be modified.
|
In an `after` hook, `args._return` is set to the value returned by the parent function, and can be modified.
|
||||||
@@ -63,10 +82,12 @@ In an `after` hook, `args._return` is set to the value returned by the parent fu
|
|||||||
`bl.unhook('packageName')` - Remove any previously defined hooks within the package
|
`bl.unhook('packageName')` - Remove any previously defined hooks within the package
|
||||||
|
|
||||||
### Modules and Dependencies
|
### Modules and Dependencies
|
||||||
|
|
||||||
`dofile('Add-Ons/Path/file.lua')` - Execute a Lua file. Relative paths (`./file.lua`) are allowed. `..` is not allowed.
|
`dofile('Add-Ons/Path/file.lua')` - Execute a Lua file. Relative paths (`./file.lua`) are allowed. `..` is not allowed.
|
||||||
|
|
||||||
`require('modulePath.moduleName')` - Load a Lua file or external library.
|
`require('modulePath.moduleName')` - Load a Lua file or external library.
|
||||||
`require` replaces `.` with `/` in the path, and then searches for files in the following order:
|
`require` replaces `.` with `/` in the path, and then searches for files in the following order:
|
||||||
|
|
||||||
- `./modulePath/moduleName.lua`
|
- `./modulePath/moduleName.lua`
|
||||||
- `./modulePath/moduleName/init.lua`
|
- `./modulePath/moduleName/init.lua`
|
||||||
- `modulePath/moduleName.lua` (Relative to game directory)
|
- `modulePath/moduleName.lua` (Relative to game directory)
|
||||||
@@ -78,6 +99,7 @@ In an `after` hook, `args._return` is set to the value returned by the parent fu
|
|||||||
Like in standard Lua, modules loaded using `require` are only executed the first time `require` is called with that path (from anywhere). Subsequent calls simply return the result from the initial execution. To allow hot reloading, use `dofile`.
|
Like in standard Lua, modules loaded using `require` are only executed the first time `require` is called with that path (from anywhere). Subsequent calls simply return the result from the initial execution. To allow hot reloading, use `dofile`.
|
||||||
|
|
||||||
### File I/O
|
### File I/O
|
||||||
|
|
||||||
Lua's builtin file I/O is emulated, and is confined to the same directories as TorqueScript file I/O.
|
Lua's builtin file I/O is emulated, and is confined to the same directories as TorqueScript file I/O.
|
||||||
Relative paths (`./`) are allowed. `..` is not allowed.
|
Relative paths (`./`) are allowed. `..` is not allowed.
|
||||||
`file = io.open('./file.txt', 'r'/'w'/'a'/'rb'/'wb'/'ab')` - Open a file
|
`file = io.open('./file.txt', 'r'/'w'/'a'/'rb'/'wb'/'ab')` - Open a file
|
||||||
@@ -88,6 +110,7 @@ Reading files from ZIPs is supported, with caveats. Null characters are not allo
|
|||||||
When reading from outside ZIPs, binary files are fully supported.
|
When reading from outside ZIPs, binary files are fully supported.
|
||||||
|
|
||||||
### Object Creation
|
### Object Creation
|
||||||
|
|
||||||
`bl.new('className')` - Create a new Torque object
|
`bl.new('className')` - Create a new Torque object
|
||||||
`bl.new('className', {fieldName = value, ...})` - Create a new Torque object with the given fields
|
`bl.new('className', {fieldName = value, ...})` - Create a new Torque object with the given fields
|
||||||
`bl.new('className objectName', fields?)` - Create a new named Torque object
|
`bl.new('className objectName', fields?)` - Create a new named Torque object
|
||||||
@@ -96,15 +119,18 @@ When reading from outside ZIPs, binary files are fully supported.
|
|||||||
`bl.datablock('datablockClassName datablockName:parentDatablockName', fields?)` - Create a new datablock with inheritance
|
`bl.datablock('datablockClassName datablockName:parentDatablockName', fields?)` - Create a new datablock with inheritance
|
||||||
|
|
||||||
### Classes and Types
|
### Classes and Types
|
||||||
`bl.type('varName', 'type')` - Register the type of a Torque global variable, for conversion when accessing from Lua. Valid types are 'boolean', 'object', and nil (default is nil, which applies automatic conversion).
|
|
||||||
|
`bl.type('varName', 'type')` - Register the type of a Torque global variable, for conversion when accessing from Lua. Valid types are 'boolean', 'object', 'string' (prevents automatic conversion), and nil (default, applies automatic conversion).
|
||||||
`bl.type('funcName', 'type')` - Register the return type of a Torque function, for conversion when calling from Lua. Valid types are 'bool', 'object', and nil - all other conversion is automatic. Already done for all default functions.
|
`bl.type('funcName', 'type')` - Register the return type of a Torque function, for conversion when calling from Lua. Valid types are 'bool', 'object', and nil - all other conversion is automatic. Already done for all default functions.
|
||||||
`bl.type('className::funcName', 'type')` - Register the return type of a Torque object method.
|
`bl.type('className::funcName', 'type')` - Register the return type of a Torque object method.
|
||||||
`bl.class('className')` - Register an existing Torque class to be used from Lua. Already done for all built-in classes.
|
`bl.class('className')` - Register an existing Torque class to be used from Lua. Already done for all built-in classes.
|
||||||
`bl.class('className', 'parentClassName')` - Same as above, with inheritance
|
`bl.class('className', 'parentClassName')` - Same as above, with inheritance
|
||||||
`bl.boolean(thing)` - Manually convert a Torque boolean (0 or 1) into a Lua boolean.
|
`bl.boolean(arg)` - Manually convert a Torque boolean (0 or 1) into a Lua boolean.
|
||||||
`bl.object(thing)` - Manually convert a Torque object reference (object ID or name) into a Lua object.
|
`bl.object(arg)` - Manually convert a Torque object reference (object ID or name) into a Lua object.
|
||||||
|
`bl.string(arg)` - Manually convert any automatically-converted Torque value back into a string. This is not as reliable as using `bl.type` to specify the type as a string beforehand.
|
||||||
|
|
||||||
|
### Vector
|
||||||
|
|
||||||
### Vectors
|
|
||||||
`vec = vector{x,y,z}` - Create a vector. Can have any number of elements
|
`vec = vector{x,y,z}` - Create a vector. Can have any number of elements
|
||||||
`vec1 + vec2` - Add
|
`vec1 + vec2` - Add
|
||||||
`vec1 - vec2` - Subtract
|
`vec1 - vec2` - Subtract
|
||||||
@@ -129,15 +155,22 @@ When reading from outside ZIPs, binary files are fully supported.
|
|||||||
`vec1:distance(vec2)` - Distance between two points
|
`vec1:distance(vec2)` - Distance between two points
|
||||||
`vec2 = vec:copy()` - Clone a vector so its elements can be modified without affecting the original. Usually not needed - the builtin vector functions never modify vectors in-place.
|
`vec2 = vec:copy()` - Clone a vector so its elements can be modified without affecting the original. Usually not needed - the builtin vector functions never modify vectors in-place.
|
||||||
|
|
||||||
|
### Matrix
|
||||||
|
|
||||||
|
WIP
|
||||||
|
|
||||||
### Extended Standard Lua Library
|
### Extended Standard Lua Library
|
||||||
`string[index]`
|
|
||||||
`string[{start,stop}]`
|
`str[index]`
|
||||||
|
`str[{start,stop}]`
|
||||||
`string.split(str, separator='' (splits into chars), noregex=false)`
|
`string.split(str, separator='' (splits into chars), noregex=false)`
|
||||||
`string.bytes(str)`
|
`string.bytes(str)`
|
||||||
`string.trim(str, charsToTrim=' \t\r\n')`
|
`string.trim(str, charsToTrim=' \t\r\n')`
|
||||||
`table.empty`
|
`table.empty`
|
||||||
`table.map(func, ...)`
|
`table.map(func, ...)`
|
||||||
|
`table.mapk(func, ...)`
|
||||||
`table.map_list(func, ...)`
|
`table.map_list(func, ...)`
|
||||||
|
`table.mapi_list(func, ...)`
|
||||||
`table.swap(tbl)`
|
`table.swap(tbl)`
|
||||||
`table.reverse(list)`
|
`table.reverse(list)`
|
||||||
`table.islist(list)`
|
`table.islist(list)`
|
||||||
@@ -161,38 +194,47 @@ When reading from outside ZIPs, binary files are fully supported.
|
|||||||
`math.clamp(num, min, max)`
|
`math.clamp(num, min, max)`
|
||||||
|
|
||||||
## Type Conversion
|
## Type Conversion
|
||||||
|
|
||||||
When a TorqueScript function is called from Lua or vice-versa, the arguments and return value must be converted between the two languages' type systems.
|
When a TorqueScript function is called from Lua or vice-versa, the arguments and return value must be converted between the two languages' type systems.
|
||||||
TorqueScript stores no type information; all values in TorqueScript are strings. So it's necessary to make some inferences when converting values between the two languages.
|
TorqueScript stores no type information; all values in TorqueScript are strings. So it's necessary to make some inferences when converting values between the two languages.
|
||||||
### From TorqueScript to Lua
|
|
||||||
- Any numeric value becomes a Lua `number`, except as specified with `bl.type`, which may convert a value into a `boolean` or a Torque object container.
|
|
||||||
- The empty string "" becomes `nil`
|
|
||||||
- A string containing three numbers separated by spaces becomes a `vector`
|
|
||||||
- A string containing six numbers separated by spaces becomes a table of two vectors
|
|
||||||
- Any other string is passed directly as a `string`
|
|
||||||
### From Lua to TorqueScript
|
### From Lua to TorqueScript
|
||||||
|
|
||||||
- `nil` becomes the empty string ""
|
- `nil` becomes the empty string ""
|
||||||
- `true` and `false` become "1" and "0" respectively
|
- `true` and `false` become "1" and "0" respectively
|
||||||
- Torque containers become their object ID
|
- A Torque object container becomes its object ID
|
||||||
- A `vector` becomes a string containing three numbers separated by spaces
|
- A `vector` becomes a string containing three numbers separated by spaces
|
||||||
- A table of two vectors becomes a string containing six numbers separated by spaces
|
- A table of two `vector`s becomes a string containing six numbers separated by spaces
|
||||||
|
- (WIP) A `matrix` is converted into an axis-angle (a "transform"), a string containing seven numbers separated by spaces
|
||||||
- Any `string` is passed directly as a string
|
- Any `string` is passed directly as a string
|
||||||
- Tables cannot be passed and will throw an error
|
- Tables cannot be passed and will throw an error
|
||||||
|
|
||||||
|
### From TorqueScript to Lua
|
||||||
|
|
||||||
|
- The empty string "" becomes `nil`
|
||||||
|
- Any numeric value becomes a Lua `number`, except as specified with `bl.type`, which may convert a value into a `boolean` or a Torque object container.
|
||||||
|
- A string containing two or three numbers separated by single spaces becomes a `vector`
|
||||||
|
- A string containing six numbers separated by single spaces becomes a table of two vectors, usually defining the corners a bounding box
|
||||||
|
- (WIP) A string containing seven numbers separated by single spaces is treated as an axis-angle (a "transform"), and is converted into a `matrix` representing the translation and rotation
|
||||||
|
- Any other string is passed directly as a `string`
|
||||||
|
|
||||||
|
For scenarios where the automatic TorqueScript->Lua conversion rules are insufficient or incorrect, use `bl.type`.
|
||||||
|
To convert things by hand, use `bl.object`, `bl.boolean`, or `bl.string`.
|
||||||
|
|
||||||
## I/O and Safety
|
## I/O and Safety
|
||||||
All Lua code is sandboxed, and file access is confied to the default directories in the same way TorqueScript is.
|
|
||||||
|
All Lua code is sandboxed, and file access is confined to the default directories in the same way TorqueScript is.
|
||||||
BlockLua also has access to any C libraries installed in the `modules/lualib` folder, so be careful throwing things in there.
|
BlockLua also has access to any C libraries installed in the `modules/lualib` folder, so be careful throwing things in there.
|
||||||
|
|
||||||
### Unsafe Mode
|
### Unsafe Mode
|
||||||
BlockLua-Unsafe.dll can be built and used in place of BlockLua.dll (see compile.bat), to remove the sandboxing of Lua code. This allows Lua code to access any file and use any library, including ffi.
|
|
||||||
Please do not publish add-ons that require unsafe mode.
|
|
||||||
|
|
||||||
## Other Reference
|
BlockLua can be built in Unsafe Mode by specifying the `-DBLLUA_UNSAFE` compiler flag. This removes the sandboxing of Lua code, allowing it to access any file and use any library, including ffi.
|
||||||
|
A more limited option is `-DBLLUA_ALLOWFFI`, which allows the use of the `ffi` library. This can still be exploited to grant all the same access as full unsafe mode.
|
||||||
|
Please do not publish add-ons that require either of these.
|
||||||
|
|
||||||
### List of Object Types
|
## Compiling
|
||||||
`'all'` - Any object
|
|
||||||
`'player'` - Players or bots
|
With any _32-bit_ variant of GCC installed (such as MinGW or MSYS2), run the following command in the repo directory:
|
||||||
`'item'` - Items
|
`g++ src/bllua4.cpp -o BlockLua.dll -m32 -shared -static-libgcc -Isrc -Iinc/tsfuncs -Iinc/lua -lpsapi -L. -llua5.1`
|
||||||
`'vehicle'` - Vehicles
|
|
||||||
`'projectile'` - Projectiles
|
LuaJIT (lua5.1.dll) can be obtained from https://luajit.org/
|
||||||
`'brick'` - Bricks with raycasting enabled
|
|
||||||
`'brickalways'` - All bricks including those with raycasting disabled
|
|
||||||
Other types: `'static'`, `'environment'`, `'terrain'`, `'water'`, `'trigger'`, `'marker'`, `'gamebase'`, `'shapebase'`, `'camera'`, `'staticshape'`, `'vehicleblocker'`, `'explosion'`, `'corpse'`, `'debris'`, `'physicalzone'`, `'staticts'`, `'staticrendered'`, `'damagableitem'`
|
|
||||||
|
|||||||
@@ -1,13 +1,16 @@
|
|||||||
// BlockLua (bllua4): Simple Lua interface for TorqueScript
|
// BlockLua (bllua4): Advanced Lua interface for TorqueScript
|
||||||
|
|
||||||
// Includes
|
// Includes
|
||||||
|
|
||||||
|
#ifndef WIN32_LEAN_AND_MEAN
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#endif
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
#include <Psapi.h>
|
#include <Psapi.h>
|
||||||
|
|
||||||
#include "lua.hpp"
|
|
||||||
#include "BlHooks.cpp"
|
|
||||||
#include "BlFuncs.cpp"
|
#include "BlFuncs.cpp"
|
||||||
|
#include "BlHooks.cpp"
|
||||||
|
#include "lua.hpp"
|
||||||
|
|
||||||
#include "luainterp.cpp"
|
#include "luainterp.cpp"
|
||||||
#include "lualibts.cpp"
|
#include "lualibts.cpp"
|
||||||
@@ -24,19 +27,20 @@ lua_State* gL;
|
|||||||
asm(".byte 0"); \
|
asm(".byte 0"); \
|
||||||
extern char varname[];
|
extern char varname[];
|
||||||
INCLUDE_BIN(bll_fileLuaEnvSafe, "lua-env-safe.lua");
|
INCLUDE_BIN(bll_fileLuaEnvSafe, "lua-env-safe.lua");
|
||||||
INCLUDE_BIN(bll_fileLuaEnv , "lua-env.lua");
|
INCLUDE_BIN(bll_fileLuaEnv, "lua-env.lua");
|
||||||
INCLUDE_BIN(bll_fileTsEnv , "ts-env.cs" );
|
INCLUDE_BIN(bll_fileTsEnv, "ts-env.cs");
|
||||||
INCLUDE_BIN(bll_fileLuaStd , "util/std.lua");
|
INCLUDE_BIN(bll_fileLuaStd, "util/std.lua");
|
||||||
INCLUDE_BIN(bll_fileLuaVector , "util/vector.lua");
|
INCLUDE_BIN(bll_fileLuaVector, "util/vector.lua");
|
||||||
INCLUDE_BIN(bll_fileLuaLibts , "util/libts-lua.lua");
|
INCLUDE_BIN(bll_fileLuaMatrix, "util/matrix.lua");
|
||||||
INCLUDE_BIN(bll_fileTsLibts , "util/libts-ts.cs");
|
INCLUDE_BIN(bll_fileLuaLibts, "util/libts-lua.lua");
|
||||||
INCLUDE_BIN(bll_fileLuaLibbl , "util/libbl.lua" );
|
INCLUDE_BIN(bll_fileTsLibts, "util/libts-ts.cs");
|
||||||
INCLUDE_BIN(bll_fileLuaLibblTypes , "util/libbl-types.lua");
|
INCLUDE_BIN(bll_fileLuaLibbl, "util/libbl.lua");
|
||||||
|
INCLUDE_BIN(bll_fileLuaLibblTypes, "util/libbl-types.lua");
|
||||||
INCLUDE_BIN(bll_fileTsLibblSupport, "util/libbl-support.cs");
|
INCLUDE_BIN(bll_fileTsLibblSupport, "util/libbl-support.cs");
|
||||||
INCLUDE_BIN(bll_fileLoadaddons , "util/loadaddons.cs");
|
INCLUDE_BIN(bll_fileLoadaddons, "util/loadaddons.cs");
|
||||||
|
|
||||||
#define BLL_LOAD_LUA(lstate, vname) \
|
#define BLL_LOAD_LUA(lstate, vname) \
|
||||||
if(!bll_LuaEval(lstate, vname)) { \
|
if (!bll_LuaEval(lstate, vname)) { \
|
||||||
BlPrintf(" Error executing " #vname); \
|
BlPrintf(" Error executing " #vname); \
|
||||||
return false; \
|
return false; \
|
||||||
}
|
}
|
||||||
@@ -56,21 +60,27 @@ bool init() {
|
|||||||
|
|
||||||
// Set up Lua environment
|
// Set up Lua environment
|
||||||
BLL_LOAD_LUA(gL, bll_fileLuaEnv);
|
BLL_LOAD_LUA(gL, bll_fileLuaEnv);
|
||||||
#ifndef BLLUA_UNSAFE
|
#ifdef BLLUA_ALLOWFFI
|
||||||
|
lua_pushboolean(gL, true);
|
||||||
|
lua_setglobal(gL, "_bllua_allowffi");
|
||||||
|
#endif
|
||||||
|
#ifndef BLLUA_UNSAFE
|
||||||
BLL_LOAD_LUA(gL, bll_fileLuaEnvSafe);
|
BLL_LOAD_LUA(gL, bll_fileLuaEnvSafe);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Expose Lua API to TS
|
// Load utilities in Lua
|
||||||
BlAddFunction(NULL, NULL, "_bllua_luacall", bll_ts_luacall, "LuaCall(name, ...) - Call Lua function and return result", 2, 20);
|
|
||||||
BlEval(bll_fileTsEnv);
|
|
||||||
|
|
||||||
// Load utilities
|
|
||||||
BLL_LOAD_LUA(gL, bll_fileLuaStd);
|
BLL_LOAD_LUA(gL, bll_fileLuaStd);
|
||||||
BLL_LOAD_LUA(gL, bll_fileLuaVector);
|
BLL_LOAD_LUA(gL, bll_fileLuaVector);
|
||||||
|
BLL_LOAD_LUA(gL, bll_fileLuaMatrix);
|
||||||
BLL_LOAD_LUA(gL, bll_fileLuaLibts);
|
BLL_LOAD_LUA(gL, bll_fileLuaLibts);
|
||||||
BlEval(bll_fileTsLibts);
|
|
||||||
BLL_LOAD_LUA(gL, bll_fileLuaLibbl);
|
BLL_LOAD_LUA(gL, bll_fileLuaLibbl);
|
||||||
BLL_LOAD_LUA(gL, bll_fileLuaLibblTypes);
|
BLL_LOAD_LUA(gL, bll_fileLuaLibblTypes);
|
||||||
|
|
||||||
|
// Expose Lua API to TS
|
||||||
|
BlAddFunction(
|
||||||
|
NULL, NULL, "_bllua_luacall", bll_ts_luacall, "LuaCall(name, ...) - Call Lua function and return result", 2, 20);
|
||||||
|
BlEval(bll_fileTsEnv);
|
||||||
|
BlEval(bll_fileTsLibts);
|
||||||
BlEval(bll_fileTsLibblSupport);
|
BlEval(bll_fileTsLibblSupport);
|
||||||
BlEval(bll_fileLoadaddons);
|
BlEval(bll_fileLoadaddons);
|
||||||
|
|
||||||
@@ -83,8 +93,7 @@ bool init() {
|
|||||||
bool deinit() {
|
bool deinit() {
|
||||||
BlPrintf("BlockLua: Unloading");
|
BlPrintf("BlockLua: Unloading");
|
||||||
|
|
||||||
BlEval("deactivatePackage(_bllua_main);");
|
BlEval("$_bllua_active=0;deactivatePackage(_bllua_main);");
|
||||||
BlEval("$_bllua_active = 0;");
|
|
||||||
bll_LuaEval(gL, "for _,f in pairs(_bllua_on_unload) do f() end");
|
bll_LuaEval(gL, "for _,f in pairs(_bllua_on_unload) do f() end");
|
||||||
|
|
||||||
lua_close(gL);
|
lua_close(gL);
|
||||||
@@ -97,9 +106,12 @@ bool deinit() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool __stdcall DllMain(HINSTANCE hinstance, DWORD reason, void* reserved) {
|
bool __stdcall DllMain(HINSTANCE hinstance, DWORD reason, void* reserved) {
|
||||||
switch(reason) {
|
switch (reason) {
|
||||||
case DLL_PROCESS_ATTACH: return init();
|
case DLL_PROCESS_ATTACH:
|
||||||
case DLL_PROCESS_DETACH: return deinit();
|
return init();
|
||||||
default : return true;
|
case DLL_PROCESS_DETACH:
|
||||||
|
return deinit();
|
||||||
|
default:
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ local old_require = require
|
|||||||
local old_os = os
|
local old_os = os
|
||||||
local old_debug = debug
|
local old_debug = debug
|
||||||
local old_package = package
|
local old_package = package
|
||||||
|
local old_allowffi = _bllua_allowffi
|
||||||
|
|
||||||
-- Remove all global variables except a whitelist
|
-- Remove all global variables except a whitelist
|
||||||
local ok_names = tmap {
|
local ok_names = tmap {
|
||||||
@@ -39,13 +40,10 @@ end
|
|||||||
|
|
||||||
-- Sanitize file paths to point only to allowed files within the game directory
|
-- Sanitize file paths to point only to allowed files within the game directory
|
||||||
-- List of allowed directories for reading/writing
|
-- List of allowed directories for reading/writing
|
||||||
|
-- modules/lualib is also allowed as read-only
|
||||||
local allowed_dirs = tmap {
|
local allowed_dirs = tmap {
|
||||||
'add-ons', 'base', 'config', 'saves', 'screenshots', 'shaders'
|
'add-ons', 'base', 'config', 'saves', 'screenshots', 'shaders'
|
||||||
}
|
}
|
||||||
-- List of allowed directories for reading only
|
|
||||||
local allowed_dirs_readonly = tmap {
|
|
||||||
'lualib'
|
|
||||||
}
|
|
||||||
-- List of disallowed file extensions - basically executable file extensions
|
-- List of disallowed file extensions - basically executable file extensions
|
||||||
-- Note that even without this protection, exploiting would still require somehow
|
-- Note that even without this protection, exploiting would still require somehow
|
||||||
-- getting a file within the allowed directories to autorun,
|
-- getting a file within the allowed directories to autorun,
|
||||||
@@ -64,6 +62,9 @@ local disallowed_exts = tmap {
|
|||||||
-- Return: clean file path if allowed (or nil if disallowed),
|
-- Return: clean file path if allowed (or nil if disallowed),
|
||||||
-- error string (or nil if allowed)
|
-- error string (or nil if allowed)
|
||||||
local function safe_path(fn, readonly)
|
local function safe_path(fn, readonly)
|
||||||
|
if type(fn) ~= 'string' then
|
||||||
|
return nil, 'Filename must be a string'
|
||||||
|
end
|
||||||
fn = fn:gsub('\\', '/')
|
fn = fn:gsub('\\', '/')
|
||||||
fn = fn:gsub('^ +', '')
|
fn = fn:gsub('^ +', '')
|
||||||
fn = fn:gsub(' +$', '')
|
fn = fn:gsub(' +$', '')
|
||||||
@@ -81,14 +82,15 @@ local function safe_path(fn, readonly)
|
|||||||
end
|
end
|
||||||
-- allow only whitelisted dirs
|
-- allow only whitelisted dirs
|
||||||
local dir = fn:match('^([^/]+)/')
|
local dir = fn:match('^([^/]+)/')
|
||||||
if (not dir) or (
|
if not (dir and (
|
||||||
(not allowed_dirs[dir:lower()]) and
|
allowed_dirs[dir:lower()] or
|
||||||
((not readonly) or (not allowed_dirs_readonly[dir:lower()]))) then
|
(readonly and fn:find('^modules/lualib/'))))
|
||||||
return nil, 'filename is in disallowed directory ' .. (dir or 'nil')
|
then
|
||||||
|
return nil, 'File is in disallowed directory ' .. (dir or 'nil')
|
||||||
end
|
end
|
||||||
-- disallow blacklisted extensions or no extension
|
-- disallow blacklisted extensions
|
||||||
local ext = fn:match('%.([^/%.]+)$')
|
local ext = fn:match('%.([^/%.]+)$')
|
||||||
if (not ext) or (disallowed_exts[ext:lower()]) then
|
if ext and disallowed_exts[ext:lower()] then
|
||||||
return nil, 'Filename \'' .. fn .. '\' has disallowed extension \'' ..
|
return nil, 'Filename \'' .. fn .. '\' has disallowed extension \'' ..
|
||||||
(ext or '') .. '\''
|
(ext or '') .. '\''
|
||||||
end
|
end
|
||||||
@@ -120,6 +122,7 @@ local disallowed_packages = tmap {
|
|||||||
'ffi', 'debug', 'package', 'io', 'os',
|
'ffi', 'debug', 'package', 'io', 'os',
|
||||||
'_bllua_ts',
|
'_bllua_ts',
|
||||||
}
|
}
|
||||||
|
if old_allowffi then disallowed_packages['ffi'] = nil end
|
||||||
function _bllua_requiresecure(name)
|
function _bllua_requiresecure(name)
|
||||||
if name:find('[^a-zA-Z0-9_%-%.]') or name:find('%.%.') or
|
if name:find('[^a-zA-Z0-9_%-%.]') or name:find('%.%.') or
|
||||||
name:find('^%.') or name:find('%.$') then
|
name:find('^%.') or name:find('%.$') then
|
||||||
@@ -143,4 +146,5 @@ debug = {
|
|||||||
getfilename = old_debug.getfilename, -- defined in lua.env.lua
|
getfilename = old_debug.getfilename, -- defined in lua.env.lua
|
||||||
}
|
}
|
||||||
|
|
||||||
_bllua_ts.echo(' Executed bllua-env-safe.lua')
|
print = _bllua_ts.echo
|
||||||
|
print(' Executed bllua-env-safe.lua')
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ end
|
|||||||
|
|
||||||
-- Called when pcall fails on a ts->lua call, used to print detailed error info
|
-- Called when pcall fails on a ts->lua call, used to print detailed error info
|
||||||
function _bllua_on_error(err)
|
function _bllua_on_error(err)
|
||||||
|
-- Convert error to string if it's not already
|
||||||
|
err = tostring(err)
|
||||||
err = err:match(': (.+)$') or err
|
err = err:match(': (.+)$') or err
|
||||||
local tracelines = { err }
|
local tracelines = { err }
|
||||||
local level = 2
|
local level = 2
|
||||||
@@ -25,7 +27,7 @@ function _bllua_on_error(err)
|
|||||||
local info = debug.getinfo(level)
|
local info = debug.getinfo(level)
|
||||||
if not info then break end
|
if not info then break end
|
||||||
local filename = debug.getfilename(level) or info.short_src
|
local filename = debug.getfilename(level) or info.short_src
|
||||||
local funcname = info.name
|
local funcname = info.name or '<unknown>'
|
||||||
if funcname == 'dofile' then break end
|
if funcname == 'dofile' then break end
|
||||||
table.insert(tracelines, string.format('%s:%s in function \'%s\'',
|
table.insert(tracelines, string.format('%s:%s in function \'%s\'',
|
||||||
filename,
|
filename,
|
||||||
@@ -37,4 +39,9 @@ function _bllua_on_error(err)
|
|||||||
return table.concat(tracelines, '\n')
|
return table.concat(tracelines, '\n')
|
||||||
end
|
end
|
||||||
|
|
||||||
_bllua_ts.echo(' Executed bllua-env.lua')
|
-- overridden in lua-env-safe.lua (executed if not BLLUA_UNSAFE)
|
||||||
|
_bllua_io_open = io.open
|
||||||
|
_bllua_requiresecure = require
|
||||||
|
|
||||||
|
print = _bllua_ts.echo
|
||||||
|
print(' Executed bllua-env.lua')
|
||||||
|
|||||||
@@ -1,6 +1,12 @@
|
|||||||
|
|
||||||
// Handle errors with a Lua function, defined in lua-env.lua
|
// Handle errors with a Lua function, defined in lua-env.lua
|
||||||
int bll_error_handler(lua_State *L) {
|
#include "luainterp.hpp"
|
||||||
|
#include "BlHooks.hpp"
|
||||||
|
#include "lauxlib.h"
|
||||||
|
#include "lua.h"
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
int bll_error_handler(lua_State* L) {
|
||||||
lua_getfield(L, LUA_GLOBALSINDEX, "_bllua_on_error");
|
lua_getfield(L, LUA_GLOBALSINDEX, "_bllua_on_error");
|
||||||
if (!lua_isfunction(L, -1)) {
|
if (!lua_isfunction(L, -1)) {
|
||||||
BlPrintf(" Lua error handler: _bllua_on_error not defined.");
|
BlPrintf(" Lua error handler: _bllua_on_error not defined.");
|
||||||
@@ -15,6 +21,7 @@ int bll_error_handler(lua_State *L) {
|
|||||||
lua_pcall(L, 1, 1, 0);
|
lua_pcall(L, 1, 1, 0);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int bll_pcall(lua_State* L, int nargs, int nret) {
|
int bll_pcall(lua_State* L, int nargs, int nret) {
|
||||||
// calculate stack position for message handler
|
// calculate stack position for message handler
|
||||||
int hpos = lua_gettop(L) - nargs;
|
int hpos = lua_gettop(L) - nargs;
|
||||||
@@ -31,7 +38,7 @@ int bll_pcall(lua_State* L, int nargs, int nret) {
|
|||||||
|
|
||||||
// Display the last Lua error in the BL console
|
// Display the last Lua error in the BL console
|
||||||
void bll_printError(lua_State* L, const char* operation, const char* item) {
|
void bll_printError(lua_State* L, const char* operation, const char* item) {
|
||||||
//error_handler(L);
|
// error_handler(L);
|
||||||
BlPrintf("\x03Lua error: %s", lua_tostring(L, -1));
|
BlPrintf("\x03Lua error: %s", lua_tostring(L, -1));
|
||||||
BlPrintf("\x03 (%s: %s)", operation, item);
|
BlPrintf("\x03 (%s: %s)", operation, item);
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
@@ -39,7 +46,7 @@ void bll_printError(lua_State* L, const char* operation, const char* item) {
|
|||||||
|
|
||||||
// Eval a string of Lua code
|
// Eval a string of Lua code
|
||||||
bool bll_LuaEval(lua_State* L, const char* str) {
|
bool bll_LuaEval(lua_State* L, const char* str) {
|
||||||
if(luaL_loadbuffer(L, str, strlen(str), "input") || bll_pcall(L, 0, 1)) {
|
if (luaL_loadbuffer(L, str, strlen(str), "input") || bll_pcall(L, 0, 1)) {
|
||||||
bll_printError(L, "eval", str);
|
bll_printError(L, "eval", str);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -48,21 +55,27 @@ bool bll_LuaEval(lua_State* L, const char* str) {
|
|||||||
|
|
||||||
// Convert a Lua stack entry into a string for providing to TS
|
// Convert a Lua stack entry into a string for providing to TS
|
||||||
// Use static buffer to avoid excessive malloc
|
// Use static buffer to avoid excessive malloc
|
||||||
#define BLL_ARG_COUNT 20
|
|
||||||
#define BLL_ARG_MAX 8192
|
|
||||||
char bll_arg_buffer[BLL_ARG_COUNT][BLL_ARG_MAX];
|
char bll_arg_buffer[BLL_ARG_COUNT][BLL_ARG_MAX];
|
||||||
|
|
||||||
bool bll_toarg(lua_State* L, char* buf, int i, bool err) {
|
bool bll_toarg(lua_State* L, char* buf, int i, bool err) {
|
||||||
if(lua_isstring(L, i)) {
|
if (lua_isstring(L, i)) {
|
||||||
const char* str = lua_tostring(L, i);
|
const char* str = lua_tostring(L, i);
|
||||||
if(strlen(str) >= BLL_ARG_MAX) {
|
if (strlen(str) >= BLL_ARG_MAX) {
|
||||||
if(err) luaL_error(L, "argument to TS is too long - max length is 8192");
|
if (err)
|
||||||
|
luaL_error(L, "argument to TS is too long - max length is 8192");
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
strcpy(buf, str);
|
#ifdef _MSC_VER
|
||||||
|
strncpy_s(buf, BLL_ARG_MAX, str, _TRUNCATE);
|
||||||
|
#else
|
||||||
|
strncpy(buf, str, BLL_ARG_MAX - 1);
|
||||||
|
buf[BLL_ARG_MAX - 1] = '\0';
|
||||||
|
#endif
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if(err) luaL_error(L, "argument to TS must be a string");
|
if (err)
|
||||||
|
luaL_error(L, "argument to TS must be a string");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
17
src/luainterp.hpp
Normal file
17
src/luainterp.hpp
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
// Shared declarations for Lua <-> TS argument handling
|
||||||
|
#ifndef _H_LUAINTERP_SHARED
|
||||||
|
#define _H_LUAINTERP_SHARED
|
||||||
|
|
||||||
|
#include "lua.h"
|
||||||
|
|
||||||
|
#define BLL_ARG_COUNT 20
|
||||||
|
#define BLL_ARG_MAX 8192
|
||||||
|
|
||||||
|
extern char bll_arg_buffer[BLL_ARG_COUNT][BLL_ARG_MAX];
|
||||||
|
bool bll_toarg(lua_State* L, char* buf, int i, bool err);
|
||||||
|
int bll_pcall(lua_State* L, int nargs, int nret);
|
||||||
|
void bll_printError(lua_State* L, const char* operation, const char* item);
|
||||||
|
|
||||||
|
extern lua_State* gL;
|
||||||
|
|
||||||
|
#endif
|
||||||
274
src/lualibts.cpp
274
src/lualibts.cpp
@@ -1,74 +1,206 @@
|
|||||||
//run ../compile
|
// run ../compile
|
||||||
|
|
||||||
// TS -> Lua API
|
// TS -> Lua API
|
||||||
|
|
||||||
// Call a TS function from Lua, push the result to Lua stack
|
// Call a TS function from Lua, push the result to Lua stack
|
||||||
|
#include "BlFuncs.hpp"
|
||||||
|
#include "BlHooks.hpp"
|
||||||
|
#include "lauxlib.h"
|
||||||
|
#include "lua.h"
|
||||||
|
#include "luainterp.hpp"
|
||||||
|
|
||||||
int bll_TsCall(lua_State* L, const char* oname, const char* fname, int argc, int ofs) {
|
int bll_TsCall(lua_State* L, const char* oname, const char* fname, int argc, int ofs) {
|
||||||
ADDR obj = (ADDR)NULL;
|
ADDR obj = (ADDR)NULL;
|
||||||
if(oname) {
|
if (oname) {
|
||||||
obj = BlObject(oname);
|
obj = BlObject(oname);
|
||||||
if(!obj) { return luaL_error(L, "Lua->TS call: Object not found"); }
|
if (!obj) {
|
||||||
|
return luaL_error(L, "Lua->TS call: Object not found");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(argc > BLL_ARG_COUNT) { return luaL_error(L, "Lua->TS call: Too many arguments (Max is 19)"); }
|
if (argc > BLL_ARG_COUNT) {
|
||||||
|
return luaL_error(L, "Lua->TS call: Too many arguments (Max is 19)");
|
||||||
|
}
|
||||||
|
|
||||||
char* argv[BLL_ARG_COUNT];
|
char* argv[BLL_ARG_COUNT];
|
||||||
for(int i=0; i<argc; i++) {
|
for (int i = 0; i < argc; i++) {
|
||||||
char* argbuf = bll_arg_buffer[i];
|
char* argbuf = bll_arg_buffer[i];
|
||||||
argv[i] = argbuf;
|
argv[i] = argbuf;
|
||||||
bll_toarg(L, argbuf, i+ofs+1, true);
|
bll_toarg(L, argbuf, i + ofs + 1, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// /:^| /
|
// /:^| /
|
||||||
const char* res;
|
const char* res;
|
||||||
if(obj) {
|
if (obj) {
|
||||||
switch(argc) {
|
switch (argc) {
|
||||||
case 0: res = BlCallObj(obj, fname); break; // no idea why this happens sometimes, it shouldnt be possible
|
case 0:
|
||||||
case 1: res = BlCallObj(obj, fname); break;
|
res = BlCallObj(obj, fname);
|
||||||
case 2: res = BlCallObj(obj, fname, argv[0]); break;
|
break; // no idea why this happens sometimes, it shouldnt be possible
|
||||||
case 3: res = BlCallObj(obj, fname, argv[0], argv[1]); break;
|
case 1:
|
||||||
case 4: res = BlCallObj(obj, fname, argv[0], argv[1], argv[2]); break;
|
res = BlCallObj(obj, fname);
|
||||||
case 5: res = BlCallObj(obj, fname, argv[0], argv[1], argv[2], argv[3]); break;
|
break;
|
||||||
case 6: res = BlCallObj(obj, fname, argv[0], argv[1], argv[2], argv[3], argv[4]); break;
|
case 2:
|
||||||
case 7: res = BlCallObj(obj, fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5]); break;
|
res = BlCallObj(obj, fname, argv[0]);
|
||||||
case 8: res = BlCallObj(obj, fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6]); break;
|
break;
|
||||||
case 9: res = BlCallObj(obj, fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7]); break;
|
case 3:
|
||||||
case 10: res = BlCallObj(obj, fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8]); break;
|
res = BlCallObj(obj, fname, argv[0], argv[1]);
|
||||||
case 11: res = BlCallObj(obj, fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9]); break;
|
break;
|
||||||
case 12: res = BlCallObj(obj, fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10]); break;
|
case 4:
|
||||||
case 13: res = BlCallObj(obj, fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11]); break;
|
res = BlCallObj(obj, fname, argv[0], argv[1], argv[2]);
|
||||||
case 14: res = BlCallObj(obj, fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12]); break;
|
break;
|
||||||
case 15: res = BlCallObj(obj, fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12], argv[13]); break;
|
case 5:
|
||||||
case 16: res = BlCallObj(obj, fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12], argv[13], argv[14]); break;
|
res = BlCallObj(obj, fname, argv[0], argv[1], argv[2], argv[3]);
|
||||||
case 17: res = BlCallObj(obj, fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12], argv[13], argv[14], argv[15]); break;
|
break;
|
||||||
case 18: res = BlCallObj(obj, fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12], argv[13], argv[14], argv[15], argv[16]); break;
|
case 6:
|
||||||
case 19: res = BlCallObj(obj, fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12], argv[13], argv[14], argv[15], argv[16], argv[17]); break;
|
res = BlCallObj(obj, fname, argv[0], argv[1], argv[2], argv[3], argv[4]);
|
||||||
case 20: res = BlCallObj(obj, fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12], argv[13], argv[14], argv[15], argv[16], argv[17], argv[18]); break;
|
break;
|
||||||
default: res = ""; luaL_error(L, "Lua->TS object call: Too many arguments (Max is 19)");
|
case 7:
|
||||||
|
res = BlCallObj(obj, fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5]);
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
res = BlCallObj(obj, fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6]);
|
||||||
|
break;
|
||||||
|
case 9:
|
||||||
|
res = BlCallObj(obj, fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7]);
|
||||||
|
break;
|
||||||
|
case 10:
|
||||||
|
res = BlCallObj(obj, fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8]);
|
||||||
|
break;
|
||||||
|
case 11:
|
||||||
|
res = BlCallObj(
|
||||||
|
obj, fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9]);
|
||||||
|
break;
|
||||||
|
case 12:
|
||||||
|
res = BlCallObj(
|
||||||
|
obj, fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9],
|
||||||
|
argv[10]);
|
||||||
|
break;
|
||||||
|
case 13:
|
||||||
|
res = BlCallObj(
|
||||||
|
obj, fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9],
|
||||||
|
argv[10], argv[11]);
|
||||||
|
break;
|
||||||
|
case 14:
|
||||||
|
res = BlCallObj(
|
||||||
|
obj, fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9],
|
||||||
|
argv[10], argv[11], argv[12]);
|
||||||
|
break;
|
||||||
|
case 15:
|
||||||
|
res = BlCallObj(
|
||||||
|
obj, fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9],
|
||||||
|
argv[10], argv[11], argv[12], argv[13]);
|
||||||
|
break;
|
||||||
|
case 16:
|
||||||
|
res = BlCallObj(
|
||||||
|
obj, fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9],
|
||||||
|
argv[10], argv[11], argv[12], argv[13], argv[14]);
|
||||||
|
break;
|
||||||
|
case 17:
|
||||||
|
res = BlCallObj(
|
||||||
|
obj, fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9],
|
||||||
|
argv[10], argv[11], argv[12], argv[13], argv[14], argv[15]);
|
||||||
|
break;
|
||||||
|
case 18:
|
||||||
|
res = BlCallObj(
|
||||||
|
obj, fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9],
|
||||||
|
argv[10], argv[11], argv[12], argv[13], argv[14], argv[15], argv[16]);
|
||||||
|
break;
|
||||||
|
case 19:
|
||||||
|
res = BlCallObj(
|
||||||
|
obj, fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9],
|
||||||
|
argv[10], argv[11], argv[12], argv[13], argv[14], argv[15], argv[16], argv[17]);
|
||||||
|
break;
|
||||||
|
case 20:
|
||||||
|
res = BlCallObj(
|
||||||
|
obj, fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9],
|
||||||
|
argv[10], argv[11], argv[12], argv[13], argv[14], argv[15], argv[16], argv[17], argv[18]);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
res = "";
|
||||||
|
luaL_error(L, "Lua->TS object call: Too many arguments (Max is 19)");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
switch(argc) {
|
switch (argc) {
|
||||||
case 0: res = BlCall(fname); break;
|
case 0:
|
||||||
case 1: res = BlCall(fname, argv[0]); break;
|
res = BlCall(fname);
|
||||||
case 2: res = BlCall(fname, argv[0], argv[1]); break;
|
break;
|
||||||
case 3: res = BlCall(fname, argv[0], argv[1], argv[2]); break;
|
case 1:
|
||||||
case 4: res = BlCall(fname, argv[0], argv[1], argv[2], argv[3]); break;
|
res = BlCall(fname, argv[0]);
|
||||||
case 5: res = BlCall(fname, argv[0], argv[1], argv[2], argv[3], argv[4]); break;
|
break;
|
||||||
case 6: res = BlCall(fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5]); break;
|
case 2:
|
||||||
case 7: res = BlCall(fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6]); break;
|
res = BlCall(fname, argv[0], argv[1]);
|
||||||
case 8: res = BlCall(fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7]); break;
|
break;
|
||||||
case 9: res = BlCall(fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8]); break;
|
case 3:
|
||||||
case 10: res = BlCall(fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9]); break;
|
res = BlCall(fname, argv[0], argv[1], argv[2]);
|
||||||
case 11: res = BlCall(fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10]); break;
|
break;
|
||||||
case 12: res = BlCall(fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11]); break;
|
case 4:
|
||||||
case 13: res = BlCall(fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12]); break;
|
res = BlCall(fname, argv[0], argv[1], argv[2], argv[3]);
|
||||||
case 14: res = BlCall(fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12], argv[13]); break;
|
break;
|
||||||
case 15: res = BlCall(fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12], argv[13], argv[14]); break;
|
case 5:
|
||||||
case 16: res = BlCall(fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12], argv[13], argv[14], argv[15]); break;
|
res = BlCall(fname, argv[0], argv[1], argv[2], argv[3], argv[4]);
|
||||||
case 17: res = BlCall(fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12], argv[13], argv[14], argv[15], argv[16]); break;
|
break;
|
||||||
case 18: res = BlCall(fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12], argv[13], argv[14], argv[15], argv[16], argv[17]); break;
|
case 6:
|
||||||
case 19: res = BlCall(fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10], argv[11], argv[12], argv[13], argv[14], argv[15], argv[16], argv[17], argv[18]); break;
|
res = BlCall(fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5]);
|
||||||
default: res = ""; luaL_error(L, "Lua->TS call: Too many arguments (Max is 19)");
|
break;
|
||||||
|
case 7:
|
||||||
|
res = BlCall(fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6]);
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
res = BlCall(fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7]);
|
||||||
|
break;
|
||||||
|
case 9:
|
||||||
|
res = BlCall(fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8]);
|
||||||
|
break;
|
||||||
|
case 10:
|
||||||
|
res = BlCall(fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9]);
|
||||||
|
break;
|
||||||
|
case 11:
|
||||||
|
res = BlCall(
|
||||||
|
fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10]);
|
||||||
|
break;
|
||||||
|
case 12:
|
||||||
|
res = BlCall(
|
||||||
|
fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10],
|
||||||
|
argv[11]);
|
||||||
|
break;
|
||||||
|
case 13:
|
||||||
|
res = BlCall(
|
||||||
|
fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10],
|
||||||
|
argv[11], argv[12]);
|
||||||
|
break;
|
||||||
|
case 14:
|
||||||
|
res = BlCall(
|
||||||
|
fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10],
|
||||||
|
argv[11], argv[12], argv[13]);
|
||||||
|
break;
|
||||||
|
case 15:
|
||||||
|
res = BlCall(
|
||||||
|
fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10],
|
||||||
|
argv[11], argv[12], argv[13], argv[14]);
|
||||||
|
break;
|
||||||
|
case 16:
|
||||||
|
res = BlCall(
|
||||||
|
fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10],
|
||||||
|
argv[11], argv[12], argv[13], argv[14], argv[15]);
|
||||||
|
break;
|
||||||
|
case 17:
|
||||||
|
res = BlCall(
|
||||||
|
fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10],
|
||||||
|
argv[11], argv[12], argv[13], argv[14], argv[15], argv[16]);
|
||||||
|
break;
|
||||||
|
case 18:
|
||||||
|
res = BlCall(
|
||||||
|
fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10],
|
||||||
|
argv[11], argv[12], argv[13], argv[14], argv[15], argv[16], argv[17]);
|
||||||
|
break;
|
||||||
|
case 19:
|
||||||
|
res = BlCall(
|
||||||
|
fname, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], argv[8], argv[9], argv[10],
|
||||||
|
argv[11], argv[12], argv[13], argv[14], argv[15], argv[16], argv[17], argv[18]);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
res = "";
|
||||||
|
luaL_error(L, "Lua->TS call: Too many arguments (Max is 19)");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,19 +208,23 @@ int bll_TsCall(lua_State* L, const char* oname, const char* fname, int argc, int
|
|||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lua lib function: ts.call
|
// Lua lib function: ts.call
|
||||||
int bll_lua_tscall(lua_State* L) {
|
int bll_lua_tscall(lua_State* L) {
|
||||||
int argc = lua_gettop(L)-1; // number of arguments after function name
|
int argc = lua_gettop(L) - 1; // number of arguments after function name
|
||||||
if(argc < 0) return luaL_error(L, "_bllua_ts.call: Must provide a function name");
|
if (argc < 0)
|
||||||
|
return luaL_error(L, "_bllua_ts.call: Must provide a function name");
|
||||||
|
|
||||||
const char* fname = luaL_checkstring(L, 1);
|
const char* fname = luaL_checkstring(L, 1);
|
||||||
|
|
||||||
return bll_TsCall(L, NULL, fname, argc, 1);
|
return bll_TsCall(L, NULL, fname, argc, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lua lib function: ts.callobj
|
// Lua lib function: ts.callobj
|
||||||
int bll_lua_tscallobj(lua_State* L) {
|
int bll_lua_tscallobj(lua_State* L) {
|
||||||
int argc = lua_gettop(L)-2; // number of arguments after function name and object?
|
int argc = lua_gettop(L) - 2; // number of arguments after function name and object?
|
||||||
if(argc < 0) return luaL_error(L, "_bllua_ts.callobj: Must provide an object and function name");
|
if (argc < 0)
|
||||||
|
return luaL_error(L, "_bllua_ts.callobj: Must provide an object and function name");
|
||||||
|
|
||||||
const char* oname = luaL_checkstring(L, 1);
|
const char* oname = luaL_checkstring(L, 1);
|
||||||
const char* fname = luaL_checkstring(L, 2);
|
const char* fname = luaL_checkstring(L, 2);
|
||||||
@@ -110,19 +246,24 @@ int bll_lua_tsgetfield(lua_State* L) {
|
|||||||
const char* oname = luaL_checkstring(L, 1);
|
const char* oname = luaL_checkstring(L, 1);
|
||||||
const char* vname = luaL_checkstring(L, 2);
|
const char* vname = luaL_checkstring(L, 2);
|
||||||
ADDR obj = BlObject(oname);
|
ADDR obj = BlObject(oname);
|
||||||
if(!obj) { return luaL_error(L, "_bllua_ts.getfield: Object not found"); }
|
if (!obj) {
|
||||||
|
return luaL_error(L, "_bllua_ts.getfield: Object not found");
|
||||||
|
}
|
||||||
|
|
||||||
const char* val = BlGetField(obj, vname, NULL);
|
const char* val = BlGetField(obj, vname, NULL);
|
||||||
lua_pushstring(L, val);
|
lua_pushstring(L, val);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lua lib function: ts.setfield
|
// Lua lib function: ts.setfield
|
||||||
int bll_lua_tssetfield(lua_State* L) {
|
int bll_lua_tssetfield(lua_State* L) {
|
||||||
const char* oname = luaL_checkstring(L, 1);
|
const char* oname = luaL_checkstring(L, 1);
|
||||||
const char* vname = luaL_checkstring(L, 2);
|
const char* vname = luaL_checkstring(L, 2);
|
||||||
const char* val = luaL_checkstring(L, 3);
|
const char* val = luaL_checkstring(L, 3);
|
||||||
ADDR obj = BlObject(oname);
|
ADDR obj = BlObject(oname);
|
||||||
if(!obj) { return luaL_error(L, "_bllua_ts.setfield: Object not found"); }
|
if (!obj) {
|
||||||
|
return luaL_error(L, "_bllua_ts.setfield: Object not found");
|
||||||
|
}
|
||||||
|
|
||||||
BlSetField(obj, vname, NULL, val);
|
BlSetField(obj, vname, NULL, val);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -145,15 +286,10 @@ int bll_lua_tsecho(lua_State* L) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const luaL_Reg bll_lua_reg[] = {
|
const luaL_Reg bll_lua_reg[] = {
|
||||||
{"call" , bll_lua_tscall },
|
{"call", bll_lua_tscall}, {"callobj", bll_lua_tscallobj},
|
||||||
{"callobj" , bll_lua_tscallobj },
|
{"getvar", bll_lua_tsgetvar}, {"getfield", bll_lua_tsgetfield},
|
||||||
{"getvar" , bll_lua_tsgetvar },
|
{"setfield", bll_lua_tssetfield}, {"eval", bll_lua_tseval},
|
||||||
{"getfield", bll_lua_tsgetfield},
|
{"echo", bll_lua_tsecho}, {NULL, NULL},
|
||||||
{"setfield", bll_lua_tssetfield},
|
|
||||||
{"eval" , bll_lua_tseval },
|
|
||||||
{"echo" , bll_lua_tsecho },
|
|
||||||
{NULL, NULL},
|
|
||||||
};
|
};
|
||||||
void llibbl_init(lua_State* L) {
|
|
||||||
luaL_register(L, "_bllua_ts", bll_lua_reg);
|
void llibbl_init(lua_State* L) { luaL_register(L, "_bllua_ts", bll_lua_reg); }
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,11 +1,16 @@
|
|||||||
|
|
||||||
// Call a Lua function from TS, return true if success - result will be on Lua stack
|
// Call a Lua function from TS, return true if success - result will be on Lua
|
||||||
|
// stack
|
||||||
|
#include "BlFuncs.hpp"
|
||||||
|
#include "BlHooks.hpp"
|
||||||
|
#include "luainterp.hpp"
|
||||||
|
|
||||||
bool bll_LuaCall(const char* fname, int argc, const char* argv[]) {
|
bool bll_LuaCall(const char* fname, int argc, const char* argv[]) {
|
||||||
lua_getglobal(gL, fname);
|
lua_getglobal(gL, fname);
|
||||||
for(int i=0; i<argc; i++) {
|
for (int i = 0; i < argc; i++) {
|
||||||
lua_pushstring(gL, argv[i]);
|
lua_pushstring(gL, argv[i]);
|
||||||
}
|
}
|
||||||
if(bll_pcall(gL, argc, 1)) {
|
if (bll_pcall(gL, argc, 1)) {
|
||||||
bll_printError(gL, "call", fname);
|
bll_printError(gL, "call", fname);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -14,9 +19,12 @@ bool bll_LuaCall(const char* fname, int argc, const char* argv[]) {
|
|||||||
|
|
||||||
// TS lib function: luacall
|
// TS lib function: luacall
|
||||||
const char* bll_ts_luacall(ADDR obj, int argc, const char* argv[]) {
|
const char* bll_ts_luacall(ADDR obj, int argc, const char* argv[]) {
|
||||||
if(argc<2) return "";
|
if (argc < 2)
|
||||||
|
return "";
|
||||||
|
|
||||||
if(!bll_LuaCall(argv[1], argc-2, &argv[2])) { return ""; }
|
if (!bll_LuaCall(argv[1], argc - 2, &argv[2])) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
char* retbuf = BlReturnBuffer(BLL_ARG_MAX);
|
char* retbuf = BlReturnBuffer(BLL_ARG_MAX);
|
||||||
bll_toarg(gL, retbuf, -1, false); // provide returned value to ts
|
bll_toarg(gL, retbuf, -1, false); // provide returned value to ts
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
// Private - Utilities used by libbl from the Lua side
|
// Private - Utilities used by libbl from the Lua side
|
||||||
|
|
||||||
package _bllua_smartEval {
|
package smartEval {
|
||||||
// Allow prepending ' to console commands to eval in lua instead of TS
|
// Allow prepending ' to console commands to eval in lua instead of TS
|
||||||
// Also wraps TS lines with echo(...); if they don't end in ; or }
|
// Also wraps TS lines with echo(...); if they don't end in ; or }
|
||||||
function ConsoleEntry::eval() {
|
function ConsoleEntry::eval() {
|
||||||
@@ -28,7 +28,7 @@ package _bllua_smartEval {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
activatePackage(_bllua_smartEval);
|
activatePackage(smartEval);
|
||||||
|
|
||||||
package _bllua_objectDeletionHook {
|
package _bllua_objectDeletionHook {
|
||||||
// Hook object deletion to clean up its lua data
|
// Hook object deletion to clean up its lua data
|
||||||
@@ -42,4 +42,26 @@ package _bllua_objectDeletionHook {
|
|||||||
};
|
};
|
||||||
activatePackage(_bllua_objectDeletionHook);
|
activatePackage(_bllua_objectDeletionHook);
|
||||||
|
|
||||||
|
// Public Lua library for TS
|
||||||
|
function luacall(%func, %a,%b,%c,%d,%e,%f,%g,%h,%i,%j,%k,%l,%m,%n,%o,%p) {
|
||||||
|
if($_bllua_active)
|
||||||
|
return _bllua_luacall("_bllua_call", %func, %a,%b,%c,%d,%e,%f,%g,%h,%i,%j,%k,%l,%m,%n,%o,%p);
|
||||||
|
}
|
||||||
|
function luaexec(%fn) {
|
||||||
|
if($_bllua_active)
|
||||||
|
return _bllua_luacall("_bllua_exec", %fn);
|
||||||
|
}
|
||||||
|
function luaeval(%code) {
|
||||||
|
if($_bllua_active)
|
||||||
|
return _bllua_luacall("_bllua_eval", %code);
|
||||||
|
}
|
||||||
|
function luaget(%name) {
|
||||||
|
if($_bllua_active)
|
||||||
|
return _bllua_luacall("_bllua_getvar", %name);
|
||||||
|
}
|
||||||
|
function luaset(%name, %val) {
|
||||||
|
if($_bllua_active)
|
||||||
|
_bllua_luacall("_bllua_setvar", %name, %val);
|
||||||
|
}
|
||||||
|
|
||||||
echo(" Executed libbl-support.cs");
|
echo(" Executed libbl-support.cs");
|
||||||
|
|||||||
@@ -2,23 +2,39 @@
|
|||||||
-- Main lua-side functionality of bllua,
|
-- Main lua-side functionality of bllua,
|
||||||
-- provided through the global table 'bl.'
|
-- provided through the global table 'bl.'
|
||||||
|
|
||||||
-- todo: set
|
|
||||||
|
|
||||||
local _bllua_ts = ts
|
local _bllua_ts = ts
|
||||||
|
|
||||||
bl = bl or {}
|
bl = bl or {}
|
||||||
|
|
||||||
|
-- Config
|
||||||
|
local tsMaxArgs = 16
|
||||||
|
local tsArgsLocal = '%a,%b,%c,%d,%e,%f,%g,%h,%i,%j,%k,%l,%m,%n,%o,%p'
|
||||||
|
local tsArgsGlobal =
|
||||||
|
'$_bllua_hook_arg1,$_bllua_hook_arg2,$_bllua_hook_arg3,$_bllua_hook_arg4,' ..
|
||||||
|
'$_bllua_hook_arg5,$_bllua_hook_arg6,$_bllua_hook_arg7,$_bllua_hook_arg8,' ..
|
||||||
|
'$_bllua_hook_arg9,$_bllua_hook_arg10,$_bllua_hook_arg11,$_bllua_hook_arg12,' ..
|
||||||
|
'$_bllua_hook_arg13,$_bllua_hook_arg14,$_bllua_hook_arg15,$_bllua_hook_arg16'
|
||||||
|
|
||||||
-- Misc
|
-- Misc
|
||||||
-- Apply a function to each element in a list, building a new list from the returns
|
local function ipairsNilable(t)
|
||||||
local function map(t, f)
|
local maxk = 0
|
||||||
local u = {}
|
for k, _ in pairs(t) do
|
||||||
for i, v in ipairs(t) do
|
if k > maxk then maxk = k end
|
||||||
u[i] = f(v)
|
end
|
||||||
|
local i = 0
|
||||||
|
return function()
|
||||||
|
i = i + 1
|
||||||
|
if i > maxk then
|
||||||
|
return nil
|
||||||
|
else
|
||||||
|
return i, t[i]
|
||||||
|
end
|
||||||
end
|
end
|
||||||
return u
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Validation
|
||||||
local function isValidFuncName(name)
|
local function isValidFuncName(name)
|
||||||
return type(name) == 'string' and name:find('^[a-zA-Z0-9_]+$')
|
return type(name) == 'string' and name:find('^[a-zA-Z_][a-zA-Z0-9_]*$')
|
||||||
end
|
end
|
||||||
local function isValidFuncNameNs(name)
|
local function isValidFuncNameNs(name)
|
||||||
return type(name) == 'string' and (
|
return type(name) == 'string' and (
|
||||||
@@ -76,7 +92,7 @@ for k, v in pairs(tsTypesByName) do
|
|||||||
tsTypesByNum[v] = k
|
tsTypesByNum[v] = k
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Type conversion
|
-- Type conversion from Lua to TS
|
||||||
local toTsObject
|
local toTsObject
|
||||||
-- Convert a string from TS into a boolean
|
-- Convert a string from TS into a boolean
|
||||||
-- Note: Nonempty nonnumeric strings evaluate to 1, unlike in TS
|
-- Note: Nonempty nonnumeric strings evaluate to 1, unlike in TS
|
||||||
@@ -100,36 +116,84 @@ local function valToTs(val)
|
|||||||
-- box - > 6 numbers
|
-- box - > 6 numbers
|
||||||
return table.concat(val[1], ' ') .. ' ' .. table.concat(val[2], ' ')
|
return table.concat(val[1], ' ') .. ' ' .. table.concat(val[2], ' ')
|
||||||
else
|
else
|
||||||
error('valToTs: could not convert table', 3)
|
error('valToTs: cannot pass Lua tables to TorqueScript.', 3)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
error('valToTs: could not convert ' .. type(val), 3)
|
error('valToTs: could not convert value to TorqueScript: ' .. tostring(val), 3)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
local function convertValFromTs(val, typ)
|
|
||||||
if typ == 'boolean' then
|
-- Type conversion from TS to Lua
|
||||||
return tsBool(val)
|
local fromTsForceTypes = {
|
||||||
elseif typ == 'object' then
|
['boolean'] = function(val) return tsBool(val) end,
|
||||||
return toTsObject(val)
|
['object'] = function(val) return toTsObject(val) end, -- wrap because toTsObject not defined yet
|
||||||
|
['string'] = function(val) return val end,
|
||||||
|
}
|
||||||
|
local function forceValFromTs(val, typ)
|
||||||
|
local func = fromTsForceTypes[typ]
|
||||||
|
if not func then error('valFromTs: invalid force type \'' .. typ .. '\'', 4) end
|
||||||
|
return func(val)
|
||||||
|
end
|
||||||
|
local function vectorFromTs(val)
|
||||||
|
local xS, yS, zS = val:match('^(%-?[0-9%.e]+) (%-?[0-9%.e]+) (%-?[0-9%.e]+)$')
|
||||||
|
if xS then
|
||||||
|
return vector { tonumber(xS), tonumber(yS), tonumber(zS) }
|
||||||
else
|
else
|
||||||
error('valFromTs: invalid force type ' .. typ, 4)
|
return nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local function boxFromTs(val)
|
||||||
|
local x1S, y1S, z1S, x2S, y2S, z2S = val:match(
|
||||||
|
'^(%-?[0-9%.e]+) (%-?[0-9%.e]+) (%-?[0-9%.e]+) ' ..
|
||||||
|
'(%-?[0-9%.e]+) (%-?[0-9%.e]+) (%-?[0-9%.e]+)$')
|
||||||
|
if x1S then
|
||||||
|
return {
|
||||||
|
vector { tonumber(x1S), tonumber(y1S), tonumber(z1S) },
|
||||||
|
vector { tonumber(x2S), tonumber(y2S), tonumber(z2S) } }
|
||||||
|
else
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local function multinumericFromTs(val)
|
||||||
|
local tsNumPat = '%-?[0-9]+%.?[0-9]*e?[0-9]*'
|
||||||
|
if val:find('^' .. tsNumPat) then
|
||||||
|
local nums = {}
|
||||||
|
for _, part in ipairs(val:split(' ')) do
|
||||||
|
if part:find('^' .. tsNumPat .. '$') then
|
||||||
|
table.insert(nums, tonumber(part))
|
||||||
|
else
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if #nums == 2 or #nums == 3 then
|
||||||
|
return vector(nums)
|
||||||
|
elseif #nums == 6 then -- box
|
||||||
|
return {
|
||||||
|
vector { nums[1], nums[2], nums[3] },
|
||||||
|
vector { nums[4], nums[5], nums[6] } }
|
||||||
|
elseif #nums == 7 then -- axis
|
||||||
|
return nil --return matrix(nums)
|
||||||
|
else
|
||||||
|
return nil
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
bl._forceType = bl._forceType or {}
|
bl._forceType = bl._forceType or {}
|
||||||
local function valFromTs(val, name, name2) -- todo: ensure name and name2 are already lowercase
|
-- todo: ensure name and name2 are already lowercase
|
||||||
|
local function valFromTs(val, name, name2)
|
||||||
if type(val) ~= 'string' then
|
if type(val) ~= 'string' then
|
||||||
error('valFromTs: expected string, got ' .. type(val), 3)
|
error('valFromTs: expected string, got ' .. type(val), 3)
|
||||||
end
|
end
|
||||||
if name then
|
if name then
|
||||||
name = name:lower()
|
name = name:lower()
|
||||||
if bl._forceType[name] then
|
if bl._forceType[name] then
|
||||||
return convertValFromTs(val, bl._forceType[name])
|
return forceValFromTs(val, bl._forceType[name])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if name2 then
|
if name2 then
|
||||||
name2 = name2:lower()
|
name2 = name2:lower()
|
||||||
if bl._forceType[name2] then
|
if bl._forceType[name2] then
|
||||||
return convertValFromTs(val, bl._forceType[name2])
|
return forceValFromTs(val, bl._forceType[name2])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
-- '' -> nil
|
-- '' -> nil
|
||||||
@@ -137,30 +201,29 @@ local function valFromTs(val, name, name2) -- todo: ensure name and name2 are al
|
|||||||
-- number
|
-- number
|
||||||
local num = tonumber(val)
|
local num = tonumber(val)
|
||||||
if num then return num end
|
if num then return num end
|
||||||
-- vector
|
-- vector, box, or axis->matrix
|
||||||
local xS, yS, zS = val:match('^(%-?[0-9%.e]+) (%-?[0-9%.e]+) (%-?[0-9%.e]+)$')
|
local vec = multinumericFromTs(val)
|
||||||
if xS then return vector { tonumber(xS), tonumber(yS), tonumber(zS) } end
|
if vec then return vec end
|
||||||
local x1S, y1S, z1S, x2S, y2S, z2S = val:match(
|
-- net string
|
||||||
'^(%-?[0-9%.e]+) (%-?[0-9%.e]+) (%-?[0-9%.e]+) ' ..
|
if val:sub(1, 1) == '\001' then
|
||||||
'(%-?[0-9%.e]+) (%-?[0-9%.e]+) (%-?[0-9%.e]+)$')
|
return _bllua_ts.call('getTaggedString', val)
|
||||||
-- box (2 vectors)
|
|
||||||
if x1S then
|
|
||||||
return {
|
|
||||||
vector { tonumber(x1S), tonumber(y1S), tonumber(z1S) },
|
|
||||||
vector { tonumber(x2S), tonumber(y2S), tonumber(z2S) } }
|
|
||||||
end
|
end
|
||||||
-- string
|
-- string
|
||||||
return val
|
return val
|
||||||
end
|
end
|
||||||
local function arglistFromTs(name, argsS)
|
local function arglistFromTs(name, argsS)
|
||||||
local args = {}
|
local args = {}
|
||||||
for i, arg in ipairs(argsS) do
|
for i, arg in ipairsNilable(argsS) do
|
||||||
args[i] = valFromTs(arg, name .. ':' .. i)
|
args[i] = valFromTs(arg, name .. ':' .. i)
|
||||||
end
|
end
|
||||||
return args
|
return args
|
||||||
end
|
end
|
||||||
local function arglistToTs(args)
|
local function arglistToTs(args)
|
||||||
return map(args, valToTs)
|
local argsS = {}
|
||||||
|
for i, v in ipairsNilable(args) do
|
||||||
|
table.insert(argsS, valToTs(v))
|
||||||
|
end
|
||||||
|
return argsS
|
||||||
end
|
end
|
||||||
local function classFromForceTypeStr(name)
|
local function classFromForceTypeStr(name)
|
||||||
local class, rest = name:match('^([a-zA-Z0-9_]+)(::.+)$')
|
local class, rest = name:match('^([a-zA-Z0-9_]+)(::.+)$')
|
||||||
@@ -171,8 +234,8 @@ local function classFromForceTypeStr(name)
|
|||||||
end
|
end
|
||||||
local setForceType
|
local setForceType
|
||||||
setForceType = function(ftname, typ)
|
setForceType = function(ftname, typ)
|
||||||
if typ ~= 'boolean' and typ ~= 'object' and typ ~= nil then
|
if typ ~= nil and not fromTsForceTypes[typ] then
|
||||||
error('bl.type: can only set type to \'boolean\', \'object\', or nil', 2)
|
error('bl.type: invalid type \'' .. typ .. '\'', 2)
|
||||||
end
|
end
|
||||||
if not isValidFuncNameNsArgn(ftname) then
|
if not isValidFuncNameNsArgn(ftname) then
|
||||||
error('bl.type: invalid function or variable name \'' .. ftname .. '\'', 2)
|
error('bl.type: invalid function or variable name \'' .. ftname .. '\'', 2)
|
||||||
@@ -195,13 +258,33 @@ setForceType = function(ftname, typ)
|
|||||||
end
|
end
|
||||||
bl.type = setForceType
|
bl.type = setForceType
|
||||||
|
|
||||||
|
-- Type conversion TS->Lua backwards, convert back to string
|
||||||
|
local function numFromTsTostring(val)
|
||||||
|
-- todo: as-good-as-possible scientific notation for numbers
|
||||||
|
return tostring(val)
|
||||||
|
end
|
||||||
|
local function valFromTsTostring(val)
|
||||||
|
if type(val) == 'string' then
|
||||||
|
return val
|
||||||
|
elseif type(val) == 'number' then
|
||||||
|
return numFromTsTostring(val)
|
||||||
|
elseif type(val) == 'table' then
|
||||||
|
if val.__is_vector then
|
||||||
|
local strs = {}
|
||||||
|
for i = 1, #val do strs[i] = numFromTsTostring(val[i]) end
|
||||||
|
return table.concat(strs, ' ')
|
||||||
|
elseif val.__is_matrix then
|
||||||
|
-- todo: matrix back to axis-angle string
|
||||||
|
error('bl.string: matrix not yet supported', 3)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
error('bl.string: cannot convert \'' .. type(val) .. '\'', 3)
|
||||||
|
end
|
||||||
|
|
||||||
-- Value detection
|
-- Getting info from TS about functions and objects
|
||||||
|
|
||||||
local function isTsObject(t)
|
local function isTsObject(t)
|
||||||
return type(t) == 'table' and t._tsObjectId ~= nil
|
return type(t) == 'table' and t._tsObjectId ~= nil
|
||||||
end
|
end
|
||||||
|
|
||||||
local function tsIsObject(name) return tsBool(_bllua_ts.call('isObject', name)) end
|
local function tsIsObject(name) return tsBool(_bllua_ts.call('isObject', name)) end
|
||||||
local function tsIsFunction(name) return tsBool(_bllua_ts.call('isFunction', name)) end
|
local function tsIsFunction(name) return tsBool(_bllua_ts.call('isFunction', name)) end
|
||||||
local function tsIsFunctionNs(ns, name) return tsBool(_bllua_ts.call('isFunction', ns, name)) end
|
local function tsIsFunctionNs(ns, name) return tsBool(_bllua_ts.call('isFunction', ns, name)) end
|
||||||
@@ -213,30 +296,33 @@ local function tsIsFunctionNsname(nsname)
|
|||||||
return tsIsFunction(nsname)
|
return tsIsFunction(nsname)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
-- sanity check to make sure objects that don't isObject are always marked as ._deleted
|
||||||
|
-- can be removed later
|
||||||
|
local function assertTsObjectExists(obj)
|
||||||
|
local is = tsIsObject(obj._tsObjectId)
|
||||||
|
if not is then
|
||||||
|
print('Warning: TS object :exists or isobject from lua but no longer exists')
|
||||||
|
end
|
||||||
|
return is
|
||||||
|
end
|
||||||
function bl.isObject(obj)
|
function bl.isObject(obj)
|
||||||
if isTsObject(obj) then
|
if type(obj) == 'number' then -- object id
|
||||||
obj = obj._tsObjectId
|
return tsIsObject(tostring(obj))
|
||||||
elseif type(obj) == 'number' then
|
elseif type(obj) == 'string' then -- object name
|
||||||
obj = tostring(obj)
|
return tsIsObject(obj)
|
||||||
elseif type(obj) ~= 'string' then
|
elseif isTsObject(obj) then -- lua object
|
||||||
|
if obj._deleted then
|
||||||
|
return false
|
||||||
|
else
|
||||||
|
return assertTsObjectExists(obj)
|
||||||
|
end
|
||||||
|
else
|
||||||
error('bl.isObject: argument #1: expected torque object, number, or string', 2)
|
error('bl.isObject: argument #1: expected torque object, number, or string', 2)
|
||||||
end
|
end
|
||||||
return tsIsObject(obj)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function bl.isFunction(a1, a2)
|
function bl.isFunction(name)
|
||||||
if type(a1) ~= 'string' then
|
return tsIsFunctionNsname(name)
|
||||||
error('bl.isFunction: argument #1: expected string', 2)
|
|
||||||
end
|
|
||||||
if a2 then
|
|
||||||
if type(a2) ~= 'string' then
|
|
||||||
error('bl.isFunction: argument #2: expected string', 2)
|
|
||||||
end
|
|
||||||
return tsIsFunctionNs(a1, a2)
|
|
||||||
else
|
|
||||||
return tsIsFunction(a1)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Torque object pseudo-class
|
-- Torque object pseudo-class
|
||||||
@@ -324,18 +410,24 @@ local tsObjectMeta = {
|
|||||||
for inh in objectInheritedMetas(rawget(t, '_tsClassName')) do
|
for inh in objectInheritedMetas(rawget(t, '_tsClassName')) do
|
||||||
if inh[name] then return inh[name] end
|
if inh[name] then return inh[name] end
|
||||||
end
|
end
|
||||||
if tsIsFunctionNs(rawget(t, '_tsNamespace'), name) then
|
if
|
||||||
return function(t, ...)
|
tsIsFunctionNs(rawget(t, '_tsNamespace'), name) or
|
||||||
local args = { ... }
|
tsIsFunctionNs(rawget(t, '_tsName'), name)
|
||||||
local argsS = arglistToTs(args)
|
then
|
||||||
return valFromTs(
|
return function(t2, ...)
|
||||||
_bllua_ts.callobj(rawget(t, '_tsObjectId'), name, unpack(argsS)),
|
if t2 == nil or type(t2) ~= 'table' or not t2._tsObjectId then
|
||||||
rawget(t, '_tsName') and rawget(t, '_tsName') .. '::' .. name,
|
error('ts object method: be sure to use :func() not .func()', 2)
|
||||||
rawget(t, '_tsNamespace') .. '::' .. name)
|
end
|
||||||
|
local argsS = arglistToTs({ ... })
|
||||||
|
local res =
|
||||||
|
_bllua_ts.callobj(t2._tsObjectId, name, unpack(argsS))
|
||||||
|
return valFromTs(res,
|
||||||
|
t2._tsName and t2._tsName .. '::' .. name,
|
||||||
|
t2._tsNamespace .. '::' .. name)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
return valFromTs(
|
local res = _bllua_ts.getfield(rawget(t, '_tsObjectId'), name)
|
||||||
_bllua_ts.getfield(rawget(t, '_tsObjectId'), name),
|
return valFromTs(res,
|
||||||
rawget(t, '_tsName') and rawget(t, '_tsName') .. '.' .. name,
|
rawget(t, '_tsName') and rawget(t, '_tsName') .. '.' .. name,
|
||||||
rawget(t, '_tsNamespace') .. '.' .. name)
|
rawget(t, '_tsNamespace') .. '.' .. name)
|
||||||
end
|
end
|
||||||
@@ -373,7 +465,8 @@ local tsObjectMeta = {
|
|||||||
-- Display a nice info string
|
-- Display a nice info string
|
||||||
__tostring = function(t)
|
__tostring = function(t)
|
||||||
return 'torque:' .. t._tsNamespace .. ':' .. t._tsObjectId ..
|
return 'torque:' .. t._tsNamespace .. ':' .. t._tsObjectId ..
|
||||||
(t._tsName ~= '' and ('(' .. t._tsName .. ')') or '')
|
(t._tsName ~= '' and ('(' .. t._tsName .. ')') or '') ..
|
||||||
|
(t._deleted and '(deleted)' or '')
|
||||||
end,
|
end,
|
||||||
-- #object
|
-- #object
|
||||||
-- If the object has a getCount method, return its count
|
-- If the object has a getCount method, return its count
|
||||||
@@ -409,7 +502,8 @@ local tsObjectMeta = {
|
|||||||
local obj = toTsObject(_bllua_ts.callobj(t._tsObjectId,
|
local obj = toTsObject(_bllua_ts.callobj(t._tsObjectId,
|
||||||
'getObject', tostring(idx)))
|
'getObject', tostring(idx)))
|
||||||
idx = idx + 1
|
idx = idx + 1
|
||||||
return idx - 1, obj
|
--return idx-1, obj
|
||||||
|
return obj
|
||||||
else
|
else
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
@@ -466,8 +560,9 @@ local tsObjectMeta = {
|
|||||||
end
|
end
|
||||||
if t._deleted then
|
if t._deleted then
|
||||||
return false
|
return false
|
||||||
|
else
|
||||||
|
return assertTsObjectExists(t)
|
||||||
end
|
end
|
||||||
return tsIsObject(t._tsObjectId)
|
|
||||||
end,
|
end,
|
||||||
}
|
}
|
||||||
-- Weak-values table for caching Torque object references
|
-- Weak-values table for caching Torque object references
|
||||||
@@ -501,7 +596,7 @@ toTsObject = function(idiS)
|
|||||||
idiS = idiS:lower()
|
idiS = idiS:lower()
|
||||||
if bl._objectsWeak[idiS] then return bl._objectsWeak[idiS] end
|
if bl._objectsWeak[idiS] then return bl._objectsWeak[idiS] end
|
||||||
|
|
||||||
if not tsBool(_bllua_ts.call('isObject', idiS)) then
|
if not tsIsObject(idiS) then
|
||||||
--error('toTsObject: object \''..idiS..'\' does not exist', 2) end
|
--error('toTsObject: object \''..idiS..'\' does not exist', 2) end
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
@@ -520,6 +615,30 @@ toTsObject = function(idiS)
|
|||||||
return obj
|
return obj
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Allow bl['namespaced::function']()
|
||||||
|
local function safeNamespaceName(name)
|
||||||
|
return tostring(name:gsub(':', '_'))
|
||||||
|
end
|
||||||
|
bl._cachedNamespaceCalls = {}
|
||||||
|
local function tsNamespacedCallTfname(name)
|
||||||
|
local tfname = bl._cachedNamespaceCalls[name]
|
||||||
|
if not tfname then
|
||||||
|
tfname = '_bllua_nscall_' .. safeNamespaceName(name)
|
||||||
|
local tfcode = 'function ' .. tfname .. '(' .. tsArgsLocal .. '){' ..
|
||||||
|
name .. '(' .. tsArgsLocal .. ');}'
|
||||||
|
_bllua_ts.eval(tfcode)
|
||||||
|
bl._cachedNamespaceCalls[name] = tfname
|
||||||
|
end
|
||||||
|
return tfname
|
||||||
|
end
|
||||||
|
local function tsCallGen(name)
|
||||||
|
return function(...)
|
||||||
|
local argsS = arglistToTs({ ... })
|
||||||
|
local res = _bllua_ts.call(name, unpack(argsS))
|
||||||
|
return valFromTs(res, name)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
-- Metatable for the global bl library
|
-- Metatable for the global bl library
|
||||||
-- Allows accessing Torque objects, variables, and functions by indexing it
|
-- Allows accessing Torque objects, variables, and functions by indexing it
|
||||||
local tsMeta = {
|
local tsMeta = {
|
||||||
@@ -540,20 +659,18 @@ local tsMeta = {
|
|||||||
local ns, rest = name:match('^([^:]+)::(.+)$')
|
local ns, rest = name:match('^([^:]+)::(.+)$')
|
||||||
if not ns then error('ts index: invalid name \'' .. name .. '\'', 2) end
|
if not ns then error('ts index: invalid name \'' .. name .. '\'', 2) end
|
||||||
if not rest:find('::') and tsIsFunctionNs(ns, rest) then
|
if not rest:find('::') and tsIsFunctionNs(ns, rest) then
|
||||||
error('ts index: can\'t call a namespaced function from lua', 2)
|
return tsCallGen(tsNamespacedCallTfname(name))
|
||||||
else
|
else
|
||||||
return valFromTs(_bllua_ts.getvar(name), name)
|
local res = _bllua_ts.getvar(name)
|
||||||
|
return valFromTs(res, name)
|
||||||
end
|
end
|
||||||
elseif tsIsFunction(name) then
|
elseif tsIsFunction(name) then
|
||||||
return function(...)
|
return tsCallGen(name)
|
||||||
local args = { ... }
|
|
||||||
local argsS = arglistToTs(args)
|
|
||||||
return valFromTs(_bllua_ts.call(name, unpack(argsS)), name)
|
|
||||||
end
|
|
||||||
elseif tsIsObject(name) then
|
elseif tsIsObject(name) then
|
||||||
return toTsObject(name)
|
return toTsObject(name)
|
||||||
else
|
else
|
||||||
return valFromTs(_bllua_ts.getvar(name), name)
|
local res = _bllua_ts.getvar(name)
|
||||||
|
return valFromTs(res, name)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
@@ -573,11 +690,18 @@ function bl.call(func, ...)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function bl.eval(code)
|
function bl.eval(code)
|
||||||
return valFromTs(_bllua_ts.eval(code))
|
local res = _bllua_ts.eval(code)
|
||||||
|
return valFromTs(res)
|
||||||
end
|
end
|
||||||
|
|
||||||
function bl.exec(file)
|
function bl.exec(file)
|
||||||
return valFromTs(_bllua_ts.call('exec', file))
|
local res = _bllua_ts.call('exec', file)
|
||||||
|
return valFromTs(res)
|
||||||
|
end
|
||||||
|
|
||||||
|
function bl.array(name, ...)
|
||||||
|
local rest = { ... }
|
||||||
|
return name .. table.concat(rest, '_')
|
||||||
end
|
end
|
||||||
|
|
||||||
function bl.boolean(val)
|
function bl.boolean(val)
|
||||||
@@ -594,25 +718,81 @@ function bl.object(id)
|
|||||||
elseif type(id) == 'string' or type(id) == 'number' then
|
elseif type(id) == 'string' or type(id) == 'number' then
|
||||||
return toTsObject(tostring(id))
|
return toTsObject(tostring(id))
|
||||||
else
|
else
|
||||||
error('bl.toobject: id must be a ts object, number, or string', 2)
|
error('bl.object: id must be a ts object, number, or string', 2)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function bl.array(name, ...)
|
function bl.string(val)
|
||||||
local rest = { ... }
|
return valFromTsTostring(val)
|
||||||
return name .. table.concat(rest, '_')
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function _bllua_call(fnameS, ...)
|
-- Lua calling from TS
|
||||||
local args = arglistFromTs(fnameS:lower(), { ... })
|
local luaLookup
|
||||||
if not _G[fnameS] then
|
luaLookup = function(tbl, name, set, val)
|
||||||
error('luacall: no global lua function named \'' .. fnameS .. '\'')
|
if name:find('%.') then
|
||||||
|
local first, rest = name:match('^([^%.:]+)%.(.+)$')
|
||||||
|
if not isValidFuncName(first) then
|
||||||
|
error('luaLookup: invalid name \'' .. tostring(first) .. '\'', 3)
|
||||||
end
|
end
|
||||||
-- todo: library fields and object methods
|
if tbl[first] == nil then
|
||||||
local res = _G[fnameS](args)
|
if set then
|
||||||
|
tbl[first] = {}
|
||||||
|
else
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return luaLookup(tbl[first], rest, set, val)
|
||||||
|
elseif name:find(':') then
|
||||||
|
local first, rest = name:match('^([^%.:]+):(.*)$')
|
||||||
|
if rest:find('[%.:]') then
|
||||||
|
error('luacall: cannot have : or . after :', 3)
|
||||||
|
end
|
||||||
|
if not isValidFuncName(first) then
|
||||||
|
error('luacall: invalid name \'' .. tostring(first) .. '\'', 3)
|
||||||
|
end
|
||||||
|
if not isValidFuncName(rest) then
|
||||||
|
error('luacall: invalid method name \'' .. tostring(first) .. '\'', 3)
|
||||||
|
end
|
||||||
|
if not tbl[first] then
|
||||||
|
error('luacall: no object named \'' .. rest .. '\'', 3)
|
||||||
|
end
|
||||||
|
if tbl[first][rest] == nil then
|
||||||
|
error('luacall: no method named \'' .. rest .. '\'', 3)
|
||||||
|
end
|
||||||
|
return function(...)
|
||||||
|
tbl[first][rest](tbl[first], ...)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if set then
|
||||||
|
tbl[name] = val
|
||||||
|
else
|
||||||
|
return tbl[name]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- Todo: similar deep access for luaget and luaset
|
||||||
|
function _bllua_call(fname, ...)
|
||||||
|
local args = arglistFromTs(fname:lower(), { ... }) -- todo: separate lua from ts func names?
|
||||||
|
local func = luaLookup(_G, fname)
|
||||||
|
if not func then
|
||||||
|
error('luacall: no global in lua named \'' .. fname .. '\'', 2)
|
||||||
|
end
|
||||||
|
local res = func(unpack(args))
|
||||||
return valToTs(res)
|
return valToTs(res)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function _bllua_getvar(vname)
|
||||||
|
return valToTs(luaLookup(_G, vname))
|
||||||
|
end
|
||||||
|
|
||||||
|
function _bllua_setvar(vname, valS)
|
||||||
|
return valToTs(luaLookup(_G, vname, true, valFromTs(valS, vname))) -- todo: separate lua from ts var names?
|
||||||
|
end
|
||||||
|
|
||||||
|
function _bllua_eval(code) return loadstring(code)() end
|
||||||
|
|
||||||
|
function _bllua_exec(fn) return dofile(fn, 2) end
|
||||||
|
|
||||||
-- bl.schedule: Use TS's schedule function to schedule lua calls
|
-- bl.schedule: Use TS's schedule function to schedule lua calls
|
||||||
-- bl.schedule(time, function, args...)
|
-- bl.schedule(time, function, args...)
|
||||||
bl._scheduleTable = bl._scheduleTable or {}
|
bl._scheduleTable = bl._scheduleTable or {}
|
||||||
@@ -664,9 +844,8 @@ local function addCmd(cmd, func)
|
|||||||
error('addCmd: invalid function name \'' .. tostring(cmd) .. '\'')
|
error('addCmd: invalid function name \'' .. tostring(cmd) .. '\'')
|
||||||
end
|
end
|
||||||
bl._cmds[cmd] = func
|
bl._cmds[cmd] = func
|
||||||
local arglist = '%a,%b,%c,%d,%e,%f,%g,%h,%i,%j,%k,%l,%m,%n,%o,%p'
|
_bllua_ts.eval('function ' .. cmd .. '(' .. tsArgsLocal .. '){' ..
|
||||||
_bllua_ts.eval('function ' .. cmd .. '(' .. arglist .. '){' ..
|
'_bllua_luacall(_bllua_process_cmd,"' .. cmd .. '",' .. tsArgsLocal .. ');}')
|
||||||
'_bllua_luacall(_bllua_process_cmd,"' .. cmd .. '",' .. arglist .. ');}')
|
|
||||||
end
|
end
|
||||||
function bl.addServerCmd(name, func)
|
function bl.addServerCmd(name, func)
|
||||||
name = name:lower()
|
name = name:lower()
|
||||||
@@ -686,8 +865,9 @@ function bl.commandToServer(cmd, ...)
|
|||||||
unpack(arglistToTs({ ... })))
|
unpack(arglistToTs({ ... })))
|
||||||
end
|
end
|
||||||
|
|
||||||
function bl.commandToClient(cmd, ...)
|
function bl.commandToClient(client, cmd, ...)
|
||||||
_bllua_ts.call('commandToClient',
|
_bllua_ts.call('commandToClient',
|
||||||
|
valToTs(client),
|
||||||
_bllua_ts.call('addTaggedString', cmd),
|
_bllua_ts.call('addTaggedString', cmd),
|
||||||
unpack(arglistToTs({ ... })))
|
unpack(arglistToTs({ ... })))
|
||||||
end
|
end
|
||||||
@@ -717,10 +897,6 @@ local function deactivatePackage(pkg)
|
|||||||
_bllua_ts.call('deactivatePackage', pkg)
|
_bllua_ts.call('deactivatePackage', pkg)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
local hookNargs = 8
|
|
||||||
local hookArglistLocal = '%a,%b,%c,%d,%e,%f,%g,%h'
|
|
||||||
local hookArglistGlobal =
|
|
||||||
'$_bllua_hook_arg1,$_bllua_hook_arg2,$_bllua_hook_arg3,$_bllua_hook_arg4,$_bllua_hook_arg5,$_bllua_hook_arg6,$_bllua_hook_arg7,$_bllua_hook_arg8'
|
|
||||||
bl._hooks = bl._hooks or {}
|
bl._hooks = bl._hooks or {}
|
||||||
function _bllua_process_hook_before(pkgS, nameS, ...)
|
function _bllua_process_hook_before(pkgS, nameS, ...)
|
||||||
local args = arglistFromTs(nameS, { ... })
|
local args = arglistFromTs(nameS, { ... })
|
||||||
@@ -735,7 +911,7 @@ function _bllua_process_hook_before(pkgS, nameS, ...)
|
|||||||
_bllua_ts.setvar('_bllua_hook_abort', '1')
|
_bllua_ts.setvar('_bllua_hook_abort', '1')
|
||||||
_bllua_ts.setvar('_bllua_hook_return', valToTs(args._return))
|
_bllua_ts.setvar('_bllua_hook_return', valToTs(args._return))
|
||||||
end
|
end
|
||||||
for i = 1, hookNargs do
|
for i = 1, tsMaxArgs do
|
||||||
_bllua_ts.setvar('_bllua_hook_arg' .. i, valToTs(args[i]))
|
_bllua_ts.setvar('_bllua_hook_arg' .. i, valToTs(args[i]))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -755,13 +931,13 @@ end
|
|||||||
|
|
||||||
local function updateHook(pkg, name, hk)
|
local function updateHook(pkg, name, hk)
|
||||||
local beforeCode = hk.before and
|
local beforeCode = hk.before and
|
||||||
('_bllua_luacall("_bllua_process_hook_before", "' .. pkg .. '","' .. name ..
|
('_bllua_luacall("_bllua_process_hook_before","' .. pkg .. '","' .. name ..
|
||||||
'",' .. hookArglistLocal .. ');') or ''
|
'",' .. tsArgsLocal .. ');') or ''
|
||||||
local arglist = (hk.before and hookArglistGlobal or hookArglistLocal)
|
local arglist = (hk.before and tsArgsGlobal or tsArgsLocal)
|
||||||
local parentCode =
|
local parentCode =
|
||||||
tsIsFunctionNsname(name) and -- only call parent if it exists
|
tsIsFunctionNsname(name) and -- only call parent if it exists
|
||||||
(hk.before and
|
(hk.before and
|
||||||
'if($_bllua_hook_abort)return $_bllua_hook_return; else ' or '') ..
|
'if($_bllua_hook_abort)return $_bllua_hook_return;else ' or '') ..
|
||||||
((hk.after and '%result=' or 'return ') ..
|
((hk.after and '%result=' or 'return ') ..
|
||||||
'parent::' .. name:match('[^:]+$') ..
|
'parent::' .. name:match('[^:]+$') ..
|
||||||
'(' .. arglist .. ');') or ''
|
'(' .. arglist .. ');') or ''
|
||||||
@@ -770,10 +946,11 @@ local function updateHook(pkg, name, hk)
|
|||||||
arglist .. ');') or ''
|
arglist .. ');') or ''
|
||||||
local code =
|
local code =
|
||||||
'package ' .. pkg .. '{' ..
|
'package ' .. pkg .. '{' ..
|
||||||
'function ' .. name .. '(' .. hookArglistLocal .. '){' ..
|
'function ' .. name .. '(' .. tsArgsLocal .. '){' ..
|
||||||
beforeCode .. parentCode .. afterCode ..
|
beforeCode .. parentCode .. afterCode ..
|
||||||
'}' ..
|
'}' ..
|
||||||
'};'
|
'};'
|
||||||
|
print('bl.hook eval output: [[' .. code .. ']]')
|
||||||
_bllua_ts.eval(code)
|
_bllua_ts.eval(code)
|
||||||
end
|
end
|
||||||
function bl.hook(pkg, name, time, func)
|
function bl.hook(pkg, name, time, func)
|
||||||
@@ -805,10 +982,10 @@ function bl.unhook(pkg, name, time)
|
|||||||
if not isValidFuncName(pkg) then
|
if not isValidFuncName(pkg) then
|
||||||
error('bl.unhook: argument #1: invalid package name \'' .. tostring(pkg) .. '\'', 2)
|
error('bl.unhook: argument #1: invalid package name \'' .. tostring(pkg) .. '\'', 2)
|
||||||
end
|
end
|
||||||
if not isValidFuncNameNs(name) then
|
if name and not isValidFuncNameNs(name) then
|
||||||
error('bl.unhook: argument #2: invalid function name \'' .. tostring(name) .. '\'', 2)
|
error('bl.unhook: argument #2: invalid function name \'' .. tostring(name) .. '\'', 2)
|
||||||
end
|
end
|
||||||
if time ~= 'before' and time ~= 'after' then
|
if time and time ~= 'before' and time ~= 'after' then
|
||||||
error('bl.unhook: argument #3: time must be \'before\' or \'after\'', 2)
|
error('bl.unhook: argument #3: time must be \'before\' or \'after\'', 2)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -837,10 +1014,13 @@ function bl.unhook(pkg, name, time)
|
|||||||
error('bl.unhook: argument #3: time must be nil, \'before\', or \'after\'', 2)
|
error('bl.unhook: argument #3: time must be nil, \'before\', or \'after\'', 2)
|
||||||
end
|
end
|
||||||
bl._hooks[pkg][name][time] = nil
|
bl._hooks[pkg][name][time] = nil
|
||||||
if tableEmpty(bl._hooks[pkg][name]) and tableEmpty(bl._hooks[pkg]) then
|
if tableEmpty(bl._hooks[pkg][name]) then
|
||||||
|
bl._hooks[pkg][name] = nil
|
||||||
|
end
|
||||||
|
if tableEmpty(bl._hooks[pkg]) then
|
||||||
bl._hooks[pkg] = nil
|
bl._hooks[pkg] = nil
|
||||||
deactivatePackage(pkg)
|
|
||||||
updateHook(pkg, name, {})
|
updateHook(pkg, name, {})
|
||||||
|
deactivatePackage(pkg)
|
||||||
else
|
else
|
||||||
updateHook(pkg, name, bl._hooks[pkg][name])
|
updateHook(pkg, name, bl._hooks[pkg][name])
|
||||||
end
|
end
|
||||||
@@ -899,7 +1079,7 @@ function bl.raycast(start, stop, mask, ignores)
|
|||||||
local stopS = vecToTs(start)
|
local stopS = vecToTs(start)
|
||||||
local maskS = maskToTs(mask)
|
local maskS = maskToTs(mask)
|
||||||
local ignoresS = {}
|
local ignoresS = {}
|
||||||
for _, v in ipairs(ignores) do
|
for _, v in ipairsNilable(ignores) do
|
||||||
table.insert(ignoresS, objToTs(v))
|
table.insert(ignoresS, objToTs(v))
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -951,7 +1131,7 @@ end
|
|||||||
local maxTsArgLen = 8192
|
local maxTsArgLen = 8192
|
||||||
local function valsToString(vals)
|
local function valsToString(vals)
|
||||||
local strs = {}
|
local strs = {}
|
||||||
for i, v in ipairs(vals) do
|
for i, v in ipairsNilable(vals) do
|
||||||
local tstr = table.tostring(v)
|
local tstr = table.tostring(v)
|
||||||
if #tstr > maxTsArgLen then
|
if #tstr > maxTsArgLen then
|
||||||
tstr = tostring(v)
|
tstr = tostring(v)
|
||||||
@@ -974,12 +1154,14 @@ end
|
|||||||
-- bl.new and bl.datablock
|
-- bl.new and bl.datablock
|
||||||
local function createTsObj(keyword, class, name, inherit, props)
|
local function createTsObj(keyword, class, name, inherit, props)
|
||||||
local propsT = {}
|
local propsT = {}
|
||||||
|
if props then
|
||||||
for k, v in pairs(props) do
|
for k, v in pairs(props) do
|
||||||
if not isValidFuncName(k) then
|
if not isValidFuncName(k) then
|
||||||
error('bl.new/bl.datablock: invalid property name \'' .. k .. '\'')
|
error('bl.new/bl.datablock: invalid property name \'' .. k .. '\'')
|
||||||
end
|
end
|
||||||
table.insert(propsT, k .. '="' .. valToTs(v) .. '";')
|
table.insert(propsT, k .. '="' .. valToTs(v) .. '";')
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
local objS = _bllua_ts.eval(
|
local objS = _bllua_ts.eval(
|
||||||
'return ' .. keyword .. ' ' .. class .. '(' ..
|
'return ' .. keyword .. ' ' .. class .. '(' ..
|
||||||
|
|||||||
@@ -93,11 +93,15 @@ local allowed_zip_dirs = tflip {
|
|||||||
local function io_open_absolute(fn, mode)
|
local function io_open_absolute(fn, mode)
|
||||||
-- if file exists, use original mode
|
-- if file exists, use original mode
|
||||||
local res, err = _bllua_io_open(fn, mode)
|
local res, err = _bllua_io_open(fn, mode)
|
||||||
if res then return res end
|
if res then
|
||||||
|
return res
|
||||||
|
elseif err and not err:find('No such file or directory$') then
|
||||||
|
return nil, err
|
||||||
|
end
|
||||||
|
|
||||||
-- otherwise, if TS sees file but Lua doesn't, it must be in a zip, so use TS reader
|
-- otherwise, if TS sees file but Lua doesn't, it must be in a zip, so use TS reader
|
||||||
local dir = fn:match('^[^/]+')
|
local dir = fn:match('^[^/]+')
|
||||||
if not allowed_zip_dirs[dir:lower()] then return nil, 'File is not in one of the allowed directories' end
|
if not allowed_zip_dirs[dir:lower()] then return nil, 'Zip is not in one of the allowed directories' end
|
||||||
local exist = _bllua_ts.call('isFile', fn) == '1'
|
local exist = _bllua_ts.call('isFile', fn) == '1'
|
||||||
if not exist then return nil, err end
|
if not exist then return nil, err end
|
||||||
|
|
||||||
@@ -204,15 +208,6 @@ function require(mod)
|
|||||||
return _bllua_requiresecure(mod)
|
return _bllua_requiresecure(mod)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Exposure to TS
|
|
||||||
function _bllua_getvar(name) return _G[name] end
|
|
||||||
|
|
||||||
function _bllua_setvar(name, val) _G[name] = val end
|
|
||||||
|
|
||||||
function _bllua_eval(code) return loadstring(code)() end
|
|
||||||
|
|
||||||
function _bllua_exec(fn) return dofile(fn, 2) end
|
|
||||||
|
|
||||||
local function isValidCode(code)
|
local function isValidCode(code)
|
||||||
local f, e = loadstring(code)
|
local f, e = loadstring(code)
|
||||||
return f ~= nil
|
return f ~= nil
|
||||||
|
|||||||
@@ -49,26 +49,4 @@ function _bllua_set_var(%name, %val) {
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Public Lua library for TS
|
|
||||||
function luacall(%func, %a,%b,%c,%d,%e,%f,%g,%h,%i,%j,%k,%l,%m,%n,%o,%p) {
|
|
||||||
if($_bllua_active)
|
|
||||||
return _bllua_luacall("_bllua_call", %func, %a,%b,%c,%d,%e,%f,%g,%h,%i,%j,%k,%l,%m,%n,%o,%p);
|
|
||||||
}
|
|
||||||
function luaexec(%fn) {
|
|
||||||
if($_bllua_active)
|
|
||||||
return _bllua_luacall("_bllua_exec", %fn);
|
|
||||||
}
|
|
||||||
function luaeval(%code) {
|
|
||||||
if($_bllua_active)
|
|
||||||
return _bllua_luacall("_bllua_eval", %code);
|
|
||||||
}
|
|
||||||
function luaget(%name) {
|
|
||||||
if($_bllua_active)
|
|
||||||
return _bllua_luacall("_bllua_getvar", %name);
|
|
||||||
}
|
|
||||||
function luaset(%name, %val) {
|
|
||||||
if($_bllua_active)
|
|
||||||
_bllua_luacall("_bllua_setvar", %name, %val);
|
|
||||||
}
|
|
||||||
|
|
||||||
echo(" Executed libts-ts.cs");
|
echo(" Executed libts-ts.cs");
|
||||||
|
|||||||
6
src/util/matrix.lua
Normal file
6
src/util/matrix.lua
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
-- todo
|
||||||
|
-- Matrix class with math operators
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
print(' Executed matrix.lua')
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
-- Table / List
|
-- Table / List
|
||||||
-- Whether a table contains no keys
|
-- Whether a table contains no keys
|
||||||
function table.empty(t)
|
function table.empty(t)
|
||||||
return next(t) ~= nil
|
return next(t) == nil
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Apply a function to each key in a table
|
-- Apply a function to each key in a table
|
||||||
@@ -13,8 +13,19 @@ function table.map(f, ...)
|
|||||||
local u = {}
|
local u = {}
|
||||||
for k, _ in pairs(ts[1]) do
|
for k, _ in pairs(ts[1]) do
|
||||||
local args = {}
|
local args = {}
|
||||||
for j = 1, #ts do args[j] = ts[j][i] end
|
for j = 1, #ts do args[j] = ts[j][k] end
|
||||||
u[i] = f(unpack(args))
|
u[k] = f(unpack(args))
|
||||||
|
end
|
||||||
|
return u
|
||||||
|
end
|
||||||
|
|
||||||
|
function table.mapk(f, ...)
|
||||||
|
local ts = { ... }
|
||||||
|
local u = {}
|
||||||
|
for k, _ in pairs(ts[1]) do
|
||||||
|
local args = {}
|
||||||
|
for j = 1, #ts do args[j] = ts[j][k] end
|
||||||
|
u[k] = f(k, unpack(args))
|
||||||
end
|
end
|
||||||
return u
|
return u
|
||||||
end
|
end
|
||||||
@@ -30,6 +41,17 @@ function table.map_list(f, ...)
|
|||||||
return u
|
return u
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function table.mapi_list(f, ...)
|
||||||
|
local ts = { ... }
|
||||||
|
local u = {}
|
||||||
|
for i = 1, #ts[1] do
|
||||||
|
local args = {}
|
||||||
|
for j = 1, #ts do args[j] = ts[j][i] end
|
||||||
|
u[i] = f(i, unpack(args))
|
||||||
|
end
|
||||||
|
return u
|
||||||
|
end
|
||||||
|
|
||||||
-- Swap keys/values
|
-- Swap keys/values
|
||||||
function table.swap(t)
|
function table.swap(t)
|
||||||
local u = {}
|
local u = {}
|
||||||
@@ -193,7 +215,7 @@ valueToString = function(v, tabLevel, seen)
|
|||||||
return tostring(v)
|
return tostring(v)
|
||||||
else
|
else
|
||||||
--error('table.tostring: table contains a '..t..' value, cannot serialize')
|
--error('table.tostring: table contains a '..t..' value, cannot serialize')
|
||||||
return 'nil --[[ cannot serialize ' .. t .. ': ' .. tostring(v) .. ' ]]'
|
return 'nil --[[ ' .. tostring(v) .. ' ]]'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
function table.tostring(t)
|
function table.tostring(t)
|
||||||
@@ -372,3 +394,5 @@ end
|
|||||||
function math.clamp(v, n, x)
|
function math.clamp(v, n, x)
|
||||||
return math.min(x, math.max(v, n))
|
return math.min(x, math.max(v, n))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
print(' Executed std.lua')
|
||||||
|
|||||||
@@ -235,4 +235,7 @@ vector_new = function(vi)
|
|||||||
end
|
end
|
||||||
|
|
||||||
vector = vector_new
|
vector = vector_new
|
||||||
|
|
||||||
|
print(' Executed vector.lua')
|
||||||
|
|
||||||
return vector_new
|
return vector_new
|
||||||
|
|||||||
Reference in New Issue
Block a user