diff --git a/build/ldblib.c b/build/ldblib.c index 9d29afb..c225e74 100644 --- a/build/ldblib.c +++ b/build/ldblib.c @@ -38,49 +38,6 @@ static void checkstack (lua_State *L, lua_State *L1, int n) { } -static int db_getregistry (lua_State *L) { - lua_pushvalue(L, LUA_REGISTRYINDEX); - return 1; -} - - -static int db_getmetatable (lua_State *L) { - luaL_checkany(L, 1); - if (!lua_getmetatable(L, 1)) { - lua_pushnil(L); /* no metatable */ - } - return 1; -} - - -static int db_setmetatable (lua_State *L) { - int t = lua_type(L, 2); - luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2, - "nil or table expected"); - lua_settop(L, 2); - lua_setmetatable(L, 1); - return 1; /* return 1st argument */ -} - - -static int db_getuservalue (lua_State *L) { - if (lua_type(L, 1) != LUA_TUSERDATA) - lua_pushnil(L); - else - lua_getuservalue(L, 1); - return 1; -} - - -static int db_setuservalue (lua_State *L) { - luaL_checktype(L, 1, LUA_TUSERDATA); - luaL_checkany(L, 2); - lua_settop(L, 2); - lua_setuservalue(L, 1); - return 1; -} - - /* ** Auxiliary function used by several library functions: check for ** an optional thread as function's first argument and set 'arg' with @@ -142,7 +99,7 @@ static void treatstackoption (lua_State *L, lua_State *L1, const char *fname) { ** two optional outputs (function and line table) from function ** 'lua_getinfo'. */ -static int db_getinfo (lua_State *L) { +extern int db_getinfo (lua_State *L) { lua_Debug ar; int arg; lua_State *L1 = getthread(L, &arg); @@ -190,114 +147,6 @@ static int db_getinfo (lua_State *L) { } -static int db_getlocal (lua_State *L) { - int arg; - lua_State *L1 = getthread(L, &arg); - lua_Debug ar; - const char *name; - int nvar = (int)luaL_checkinteger(L, arg + 2); /* local-variable index */ - if (lua_isfunction(L, arg + 1)) { /* function argument? */ - lua_pushvalue(L, arg + 1); /* push function */ - lua_pushstring(L, lua_getlocal(L, NULL, nvar)); /* push local name */ - return 1; /* return only name (there is no value) */ - } - else { /* stack-level argument */ - int level = (int)luaL_checkinteger(L, arg + 1); - if (!lua_getstack(L1, level, &ar)) /* out of range? */ - return luaL_argerror(L, arg+1, "level out of range"); - checkstack(L, L1, 1); - name = lua_getlocal(L1, &ar, nvar); - if (name) { - lua_xmove(L1, L, 1); /* move local value */ - lua_pushstring(L, name); /* push name */ - lua_rotate(L, -2, 1); /* re-order */ - return 2; - } - else { - lua_pushnil(L); /* no name (nor value) */ - return 1; - } - } -} - - -static int db_setlocal (lua_State *L) { - int arg; - const char *name; - lua_State *L1 = getthread(L, &arg); - lua_Debug ar; - int level = (int)luaL_checkinteger(L, arg + 1); - int nvar = (int)luaL_checkinteger(L, arg + 2); - if (!lua_getstack(L1, level, &ar)) /* out of range? */ - return luaL_argerror(L, arg+1, "level out of range"); - luaL_checkany(L, arg+3); - lua_settop(L, arg+3); - checkstack(L, L1, 1); - lua_xmove(L, L1, 1); - name = lua_setlocal(L1, &ar, nvar); - if (name == NULL) - lua_pop(L1, 1); /* pop value (if not popped by 'lua_setlocal') */ - lua_pushstring(L, name); - return 1; -} - - -/* -** get (if 'get' is true) or set an upvalue from a closure -*/ -static int auxupvalue (lua_State *L, int get) { - const char *name; - int n = (int)luaL_checkinteger(L, 2); /* upvalue index */ - luaL_checktype(L, 1, LUA_TFUNCTION); /* closure */ - name = get ? lua_getupvalue(L, 1, n) : lua_setupvalue(L, 1, n); - if (name == NULL) return 0; - lua_pushstring(L, name); - lua_insert(L, -(get+1)); /* no-op if get is false */ - return get + 1; -} - - -static int db_getupvalue (lua_State *L) { - return auxupvalue(L, 1); -} - - -static int db_setupvalue (lua_State *L) { - luaL_checkany(L, 3); - return auxupvalue(L, 0); -} - - -/* -** Check whether a given upvalue from a given closure exists and -** returns its index -*/ -static int checkupval (lua_State *L, int argf, int argnup) { - int nup = (int)luaL_checkinteger(L, argnup); /* upvalue index */ - luaL_checktype(L, argf, LUA_TFUNCTION); /* closure */ - luaL_argcheck(L, (lua_getupvalue(L, argf, nup) != NULL), argnup, - "invalid upvalue index"); - return nup; -} - - -static int db_upvalueid (lua_State *L) { - int n = checkupval(L, 1, 2); - lua_pushlightuserdata(L, lua_upvalueid(L, 1, n)); - return 1; -} - - -static int db_upvaluejoin (lua_State *L) { - int n1 = checkupval(L, 1, 2); - int n2 = checkupval(L, 3, 4); - luaL_argcheck(L, !lua_iscfunction(L, 1), 1, "Lua function expected"); - luaL_argcheck(L, !lua_iscfunction(L, 3), 3, "Lua function expected"); - lua_upvaluejoin(L, 1, n1, 3, n2); - return 0; -} - - /* ** Call hook function registered at hook table for the current ** thread (if there is one) @@ -344,7 +193,7 @@ static char *unmakemask (int mask, char *smask) { } -static int db_sethook (lua_State *L) { +extern int db_sethook (lua_State *L) { int arg, mask, count; lua_Hook func; lua_State *L1 = getthread(L, &arg); @@ -376,7 +225,7 @@ static int db_sethook (lua_State *L) { } -static int db_gethook (lua_State *L) { +extern int db_gethook (lua_State *L) { int arg; lua_State *L1 = getthread(L, &arg); char buff[5]; @@ -397,60 +246,3 @@ static int db_gethook (lua_State *L) { lua_pushinteger(L, lua_gethookcount(L1)); /* 3rd result = count */ return 3; } - - -static int db_debug (lua_State *L) { - for (;;) { - char buffer[250]; - lua_writestringerror("%s", "lua_debug> "); - if (fgets(buffer, sizeof(buffer), stdin) == 0 || - strcmp(buffer, "cont\n") == 0) - return 0; - if (luaL_loadbuffer(L, buffer, strlen(buffer), "=(debug command)") || - lua_pcall(L, 0, 0, 0)) - lua_writestringerror("%s\n", lua_tostring(L, -1)); - lua_settop(L, 0); /* remove eventual returns */ - } -} - - -static int db_traceback (lua_State *L) { - int arg; - lua_State *L1 = getthread(L, &arg); - const char *msg = lua_tostring(L, arg + 1); - if (msg == NULL && !lua_isnoneornil(L, arg + 1)) /* non-string 'msg'? */ - lua_pushvalue(L, arg + 1); /* return it untouched */ - else { - int level = (int)luaL_optinteger(L, arg + 2, (L == L1) ? 1 : 0); - luaL_traceback(L, L1, msg, level); - } - return 1; -} - - -static const luaL_Reg dblib[] = { - {"debug", db_debug}, - {"getuservalue", db_getuservalue}, - {"gethook", db_gethook}, - {"getinfo", db_getinfo}, - {"getlocal", db_getlocal}, - {"getregistry", db_getregistry}, - {"getmetatable", db_getmetatable}, - {"getupvalue", db_getupvalue}, - {"upvaluejoin", db_upvaluejoin}, - {"upvalueid", db_upvalueid}, - {"setuservalue", db_setuservalue}, - {"sethook", db_sethook}, - {"setlocal", db_setlocal}, - {"setmetatable", db_setmetatable}, - {"setupvalue", db_setupvalue}, - {"traceback", db_traceback}, - {NULL, NULL} -}; - - -LUAMOD_API int luaopen_debug (lua_State *L) { - luaL_newlib(L, dblib); - return 1; -} - diff --git a/src/lapi.rs b/src/lapi.rs index 100cfa9..370325b 100644 --- a/src/lapi.rs +++ b/src/lapi.rs @@ -38,7 +38,7 @@ use crate::lzio::{luaZ_init, ZIO}; use crate::types::{ lua_Alloc, lua_CFunction, lua_Integer, lua_KContext, lua_KFunction, lua_Number, lua_Reader, lua_Writer, LUA_MULTRET, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS, LUA_TFUNCTION, LUA_TNIL, - LUA_TTABLE, LUA_VERSION_NUM, + LUA_TTABLE, LUA_TTHREAD, LUA_VERSION_NUM, }; #[inline(always)] @@ -619,6 +619,11 @@ pub unsafe extern "C" fn lua_touserdata(L: *mut lua_State, idx: c_int) -> *mut c }; } +#[no_mangle] +pub unsafe extern "C" fn lua_isthread(L: *mut lua_State, idx: c_int) -> bool { + return lua_type(L, idx) == LUA_TTHREAD; +} + #[no_mangle] pub unsafe extern "C" fn lua_tothread(L: *mut lua_State, idx: c_int) -> *mut lua_State { let o: StkId = index2addr(L, idx); diff --git a/src/lauxlib.rs b/src/lauxlib.rs index dd29bda..50757d4 100644 --- a/src/lauxlib.rs +++ b/src/lauxlib.rs @@ -1242,6 +1242,16 @@ pub unsafe extern "C" fn luaL_loadstring(L: *mut lua_State, s: *const libc::c_ch return luaL_loadbufferx(L, s, strlen(s), s, ptr::null_mut()); } +#[no_mangle] +pub unsafe fn luaL_loadbuffer( + L: *mut lua_State, + buff: *const c_char, + size: size_t, + name: *const c_char, +) -> c_int { + return luaL_loadbufferx(L, buff, size, name, 0 as *const i8); +} + /* }====================================================== */ #[no_mangle] diff --git a/src/ldblib.rs b/src/ldblib.rs new file mode 100644 index 0000000..e953a27 --- /dev/null +++ b/src/ldblib.rs @@ -0,0 +1,396 @@ +use std::ffi::c_char; +use std::io; + +use libc::{c_int, c_ulong, fflush, fgets, fprintf, intptr_t, strcmp, FILE}; + +use crate::lapi::{ + lua_checkstack, lua_getmetatable, lua_getupvalue, lua_getuservalue, lua_insert, lua_isfunction, + lua_isthread, lua_pcall, lua_pop, lua_pushlightuserdata, lua_pushnil, lua_pushstring, + lua_pushvalue, lua_rotate, lua_setmetatable, lua_settop, lua_setupvalue, lua_setuservalue, + lua_tolstring, lua_tostring, lua_tothread, lua_type, lua_upvalueid, lua_upvaluejoin, lua_xmove, +}; +use crate::lauxlib::{ + luaL_Reg, luaL_argerror, luaL_checkany, luaL_checkinteger, luaL_checktype, luaL_error, + luaL_loadbuffer, luaL_newlib, luaL_optinteger, luaL_traceback, lua_isnoneornil, +}; +use crate::ldebug::{lua_getlocal, lua_getstack, lua_setlocal}; +use crate::lstate::{lua_State, CallInfo}; +use crate::types::{ + lua_CFunction, lua_Debug, lua_Integer, LUA_REGISTRYINDEX, LUA_TFUNCTION, LUA_TNIL, LUA_TTABLE, + LUA_TUSERDATA, +}; + +static mut HOOKKEY: c_int = 0 as c_int; + +pub const NULL: c_int = 0 as c_int; + +unsafe extern "C" fn getthread(L: *mut lua_State, arg: *mut c_int) -> *mut lua_State { + if lua_isthread(L, 1) { + *arg = 1 as c_int; + return lua_tothread(L, 1 as c_int); + } else { + *arg = 0 as c_int; + return L; + }; +} + +unsafe extern "C" fn checkstack(L: *mut lua_State, L1: *mut lua_State, n: c_int) { + if L != L1 && lua_checkstack(L1, n) == 0 { + luaL_error(L, cstr!("stack overflow")); + } +} + +unsafe extern "C" fn db_debug(L: *mut lua_State) -> c_int { + loop { + let mut buffer: [c_char; 250] = [0; 250]; + if (fgets( + buffer.as_mut_ptr(), + ::core::mem::size_of::<[c_char; 250]>() as c_ulong as c_int, + io::stdin as *mut FILE, + )) + .is_null() + || strcmp(buffer.as_mut_ptr(), cstr!("cont\n")) == 0 as c_int + { + return 0; + } + let name = String::from("=(debug command)"); + if luaL_loadbuffer( + L, + buffer.as_ptr() as *const i8, + buffer.len(), + name.as_ptr() as *const i8, + ) != 0 + || lua_pcall(L, 0, 0, 0) != 0 + { + fprintf( + io::stderr as *mut FILE, + cstr!("%s\n"), + lua_tolstring(L, -(1 as c_int), 0 as *mut usize), + ); + fflush(io::stderr as *mut FILE); + } + lua_settop(L, 0 as c_int); + } +} + +unsafe extern "C" fn db_traceback(L: *mut lua_State) -> c_int { + let mut arg: c_int = 0; + let L1 = getthread(L, &mut arg); + let msg = lua_tostring(L, arg + 1); + if msg.is_null() && !lua_isnoneornil(L, arg + 1) { + lua_pushvalue(L, arg + 1 as c_int); + } else { + let level = luaL_optinteger( + L, + arg + 2 as c_int, + (if L == L1 { 1 as c_int } else { 0 as c_int }) as lua_Integer, + ) as c_int; + luaL_traceback(L, L1, msg, level); + } + return 1; +} + +unsafe extern "C" fn db_getuservalue(L: *mut lua_State) -> c_int { + if lua_type(L, 1 as c_int) != LUA_TUSERDATA { + lua_pushnil(L); + } else { + lua_getuservalue(L, 1 as c_int); + } + return 1; +} + +unsafe extern "C" fn db_setuservalue(L: *mut lua_State) -> c_int { + luaL_checktype(L, 1 as c_int, LUA_TUSERDATA); + luaL_checkany(L, 2 as c_int); + lua_settop(L, 2 as c_int); + lua_setuservalue(L, 1 as c_int); + return 1; +} + +unsafe extern "C" fn db_setlocal(L: *mut lua_State) -> c_int { + let mut arg: c_int = 0; + let name: *const c_char; + let L1 = getthread(L, &mut arg); + let mut ar = lua_Debug { + event: 0, + name: 0 as *const c_char, + namewhat: 0 as *const c_char, + what: 0 as *const c_char, + source: 0 as *const c_char, + currentline: 0, + linedefined: 0, + lastlinedefined: 0, + nups: 0, + nparams: 0, + isvararg: 0, + istailcall: 0, + short_src: [0; 60], + i_ci: 0 as *mut CallInfo, + }; + let level = luaL_checkinteger(L, arg + 1 as c_int) as c_int; + let nvar = luaL_checkinteger(L, arg + 2 as c_int) as c_int; + if lua_getstack(L1, level, &mut ar) == 0 { + return luaL_argerror(L, arg + 1 as c_int, cstr!("level out of range")); + } + luaL_checkany(L, arg + 3 as c_int); + lua_settop(L, arg + 3 as c_int); + checkstack(L, L1, 1 as c_int); + lua_xmove(L, L1, 1 as c_int); + name = lua_setlocal(L1, &mut ar, nvar); + if name.is_null() { + lua_pop(L1, 1); + } + lua_pushstring(L, name); + return 1; +} + +unsafe extern "C" fn db_getlocal(L: *mut lua_State) -> c_int { + let mut arg: c_int = 0; + let L1 = getthread(L, &mut arg); + let mut ar = lua_Debug { + event: 0, + name: 0 as *const c_char, + namewhat: 0 as *const c_char, + what: 0 as *const c_char, + source: 0 as *const c_char, + currentline: 0, + linedefined: 0, + lastlinedefined: 0, + nups: 0, + nparams: 0, + isvararg: 0, + istailcall: 0, + short_src: [0; 60], + i_ci: 0 as *mut CallInfo, + }; + let name: *const c_char; + let nvar = luaL_checkinteger(L, arg + 2 as c_int) as c_int; + if lua_isfunction(L, arg + 1) != 0 { + lua_pushvalue(L, arg + 1 as c_int); + lua_pushstring(L, lua_getlocal(L, NULL as *const lua_Debug, nvar)); + return 1; + } else { + let level = luaL_checkinteger(L, arg + 1 as c_int) as c_int; + if lua_getstack(L1, level, &mut ar) == 0 { + return luaL_argerror(L, arg + 1 as c_int, cstr!("level out of range")); + } + checkstack(L, L1, 1 as c_int); + name = lua_getlocal(L1, &mut ar, nvar); + if !name.is_null() { + lua_xmove(L1, L, 1 as c_int); + lua_pushstring(L, name); + lua_rotate(L, -(2 as c_int), 1 as c_int); + return 2 as c_int; + } else { + lua_pushnil(L); + return 1; + } + }; +} + +unsafe extern "C" fn db_getregistry(L: *mut lua_State) -> c_int { + lua_pushvalue(L, LUA_REGISTRYINDEX); + return 1; +} + +unsafe extern "C" fn db_setmetatable(L: *mut lua_State) -> c_int { + let t = lua_type(L, 2 as c_int); + if t != LUA_TNIL && t != LUA_TTABLE { + return luaL_argerror(L, 2, cstr!("nil or table expected")); + } + lua_settop(L, 2 as c_int); + lua_setmetatable(L, 1 as c_int); + return 1; +} + +unsafe extern "C" fn db_getmetatable(L: *mut lua_State) -> c_int { + luaL_checkany(L, 1 as c_int); + if lua_getmetatable(L, 1 as c_int) == 0 { + lua_pushnil(L); + } + return 1; +} + +unsafe extern "C" fn auxupvalue(L: *mut lua_State, get: c_int) -> c_int { + let name: *const c_char; + let n = luaL_checkinteger(L, 2 as c_int) as c_int; + luaL_checktype(L, 1 as c_int, LUA_TFUNCTION); + name = if get != 0 { + lua_getupvalue(L, 1 as c_int, n) + } else { + lua_setupvalue(L, 1 as c_int, n) + }; + if name.is_null() { + return 0; + } + lua_pushstring(L, name); + lua_insert(L, -(get + 1 as c_int)); + return get + 1 as c_int; +} + +unsafe extern "C" fn db_getupvalue(L: *mut lua_State) -> c_int { + return auxupvalue(L, 1 as c_int); +} + +unsafe extern "C" fn db_setupvalue(L: *mut lua_State) -> c_int { + luaL_checkany(L, 3 as c_int); + return auxupvalue(L, 0 as c_int); +} + +unsafe extern "C" fn checkupval(L: *mut lua_State, argf: c_int, argnup: c_int) -> c_int { + let nup = luaL_checkinteger(L, argnup) as c_int; + luaL_checktype(L, argf, LUA_TFUNCTION); + if lua_getupvalue(L, argf, nup) == 0 as *const c_char { + luaL_argerror(L, argf, cstr!("invalid upvalue index")); + } + return nup; +} + +unsafe extern "C" fn db_upvalueid(L: *mut lua_State) -> c_int { + let n = checkupval(L, 1 as c_int, 2 as c_int); + lua_pushlightuserdata(L, lua_upvalueid(L, 1 as c_int, n)); + return 1; +} + +unsafe extern "C" fn db_upvaluejoin(L: *mut lua_State) -> c_int { + let n1 = checkupval(L, 1 as c_int, 2 as c_int); + let n2 = checkupval(L, 3 as c_int, 4 as c_int); + lua_upvaluejoin(L, 1 as c_int, n1, 3 as c_int, n2); + return 0; +} + +static mut dblib: [luaL_Reg; 17] = unsafe { + [ + { + let init = luaL_Reg { + name: cstr!("debug"), + func: Some(db_debug as unsafe extern "C" fn(*mut lua_State) -> c_int), + }; + init + }, + { + let init = luaL_Reg { + name: cstr!("getuservalue"), + func: Some(db_getuservalue as unsafe extern "C" fn(*mut lua_State) -> c_int), + }; + init + }, + { + let init = luaL_Reg { + name: cstr!("gethook"), + func: Some(db_gethook as unsafe extern "C" fn(*mut lua_State) -> c_int), + }; + init + }, + { + let init = luaL_Reg { + name: cstr!("getinfo"), + func: Some(db_getinfo as unsafe extern "C" fn(*mut lua_State) -> c_int), + }; + init + }, + { + let init = luaL_Reg { + name: cstr!("getlocal"), + func: Some(db_getlocal as unsafe extern "C" fn(*mut lua_State) -> c_int), + }; + init + }, + { + let init = luaL_Reg { + name: cstr!("getregistry"), + func: Some(db_getregistry as unsafe extern "C" fn(*mut lua_State) -> c_int), + }; + init + }, + { + let init = luaL_Reg { + name: cstr!("getmetatable"), + func: Some(db_getmetatable as unsafe extern "C" fn(*mut lua_State) -> c_int), + }; + init + }, + { + let init = luaL_Reg { + name: cstr!("getupvalue"), + func: Some(db_getupvalue as unsafe extern "C" fn(*mut lua_State) -> c_int), + }; + init + }, + { + let init = luaL_Reg { + name: cstr!("upvaluejoin"), + func: Some(db_upvaluejoin as unsafe extern "C" fn(*mut lua_State) -> c_int), + }; + init + }, + { + let init = luaL_Reg { + name: cstr!("upvalueid"), + func: Some(db_upvalueid as unsafe extern "C" fn(*mut lua_State) -> c_int), + }; + init + }, + { + let init = luaL_Reg { + name: cstr!("setuservalue"), + func: Some(db_setuservalue as unsafe extern "C" fn(*mut lua_State) -> c_int), + }; + init + }, + { + let init = luaL_Reg { + name: cstr!("sethook"), + func: Some(db_sethook as unsafe extern "C" fn(*mut lua_State) -> c_int), + }; + init + }, + { + let init = luaL_Reg { + name: cstr!("setlocal"), + func: Some(db_setlocal as unsafe extern "C" fn(*mut lua_State) -> c_int), + }; + init + }, + { + let init = luaL_Reg { + name: cstr!("setmetatable"), + func: Some(db_setmetatable as unsafe extern "C" fn(*mut lua_State) -> c_int), + }; + init + }, + { + let init = luaL_Reg { + name: cstr!("setupvalue"), + func: Some(db_setupvalue as unsafe extern "C" fn(*mut lua_State) -> c_int), + }; + init + }, + { + let init = luaL_Reg { + name: cstr!("traceback"), + func: Some(db_traceback as unsafe extern "C" fn(*mut lua_State) -> c_int), + }; + init + }, + { + let init = luaL_Reg { + name: NULL as *const c_char, + func: ::core::mem::transmute::(NULL as intptr_t), + }; + init + }, + ] +}; + +#[no_mangle] +pub unsafe extern "C" fn luaopen_debug(L: *mut lua_State) -> c_int { + luaL_newlib(L, dblib.as_ptr()); + return 1; +} + +extern "C" { + fn db_gethook(L: *mut lua_State) -> c_int; + fn db_getinfo(L: *mut lua_State) -> c_int; + fn db_sethook(L: *mut lua_State) -> c_int; +} diff --git a/src/lib.rs b/src/lib.rs index beadc60..c07daf1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -17,6 +17,7 @@ pub(crate) mod lobject; pub(crate) mod lgc; pub(crate) mod lbaselib; +pub(crate) mod ldblib; pub(crate) mod ldebug; pub(crate) mod ldo; pub(crate) mod ldump;