summaryrefslogtreecommitdiff
path: root/src/ffi/compat53.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/ffi/compat53.rs')
-rw-r--r--src/ffi/compat53.rs668
1 files changed, 668 insertions, 0 deletions
diff --git a/src/ffi/compat53.rs b/src/ffi/compat53.rs
new file mode 100644
index 0000000..2b58ebc
--- /dev/null
+++ b/src/ffi/compat53.rs
@@ -0,0 +1,668 @@
+// The MIT License (MIT)
+//
+// Copyright (c) 2019 A. Orlenko
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+// Based on github.com/keplerproject/lua-compat-5.3
+
+use std::mem;
+use std::os::raw::{c_char, c_int, c_void};
+use std::ptr;
+
+use super::lauxlib::{
+ luaL_Reg, luaL_callmeta, luaL_checkstack, luaL_checktype, luaL_error, luaL_getmetafield_51,
+ luaL_getmetatable, luaL_loadbuffer, luaL_newmetatable_51,
+};
+
+use super::lua::{
+ self, lua_CFunction, lua_Debug, lua_Integer, lua_Number, lua_State, lua_call, lua_concat,
+ lua_createtable, lua_equal, lua_error, lua_getfenv, lua_getfield_51, lua_getinfo,
+ lua_getmetatable, lua_getstack, lua_gettable_51, lua_gettop, lua_insert, lua_isnumber,
+ lua_isstring, lua_istable, lua_lessthan, lua_newtable, lua_newuserdata, lua_next, lua_objlen,
+ lua_pop, lua_pushboolean, lua_pushcclosure, lua_pushcfunction, lua_pushfstring,
+ lua_pushinteger, lua_pushlightuserdata, lua_pushliteral, lua_pushlstring_51, lua_pushnil,
+ lua_pushnumber, lua_pushstring_51, lua_pushthread, lua_pushvalue, lua_rawequal, lua_rawget_51,
+ lua_rawgeti_51, lua_rawset, lua_remove, lua_replace, lua_resume_51, lua_setfenv, lua_setfield,
+ lua_setglobal, lua_setmetatable, lua_settable, lua_settop, lua_toboolean, lua_tointeger,
+ lua_tolstring, lua_tonumber, lua_topointer, lua_tostring, lua_touserdata, lua_type,
+ lua_typename,
+};
+
+unsafe fn compat53_reverse(L: *mut lua_State, mut a: c_int, mut b: c_int) {
+ while a < b {
+ lua_pushvalue(L, a);
+ lua_pushvalue(L, b);
+ lua_replace(L, a);
+ lua_replace(L, b);
+ a += 1;
+ b -= 1;
+ }
+}
+
+const COMPAT53_LEVELS1: c_int = 12; // size of the first part of the stack
+const COMPAT53_LEVELS2: c_int = 10; // size of the second part of the stack
+
+unsafe fn compat53_countlevels(L: *mut lua_State) -> c_int {
+ let mut ar: lua_Debug = mem::zeroed();
+ let (mut li, mut le) = (1, 1);
+ // find an upper bound
+ while lua_getstack(L, le, &mut ar) != 0 {
+ li = le;
+ le *= 2;
+ }
+ // do a binary search
+ while li < le {
+ let m = (li + le) / 2;
+ if lua_getstack(L, m, &mut ar) != 0 {
+ li = m + 1
+ } else {
+ le = m;
+ }
+ }
+ le - 1
+}
+
+unsafe fn compat53_checkmode(
+ L: *mut lua_State,
+ mode: *const c_char,
+ modename: *const c_char,
+ err: c_int,
+) -> c_int {
+ unsafe fn strchr(s: *const c_char, c: c_char) -> *const c_char {
+ let mut st = s;
+ while *st != 0 && *st != c {
+ st = st.offset(1);
+ }
+ if *st == c {
+ st
+ } else {
+ ptr::null()
+ }
+ }
+
+ if mode != ptr::null() && strchr(mode, *modename) == ptr::null() {
+ lua_pushfstring(
+ L,
+ cstr!("attempt to load a %s chunk (mode is '%s')"),
+ modename,
+ mode,
+ );
+ return err;
+ }
+ lua::LUA_OK
+}
+
+unsafe fn compat53_findfield(L: *mut lua_State, objidx: c_int, level: c_int) -> c_int {
+ if level == 0 || lua_istable(L, -1) == 0 {
+ return 0; // not found
+ }
+
+ lua_pushnil(L); // start 'next' loop
+ while lua_next(L, -2) != 0 {
+ // for each pair in table
+ if lua_type(L, -2) == lua::LUA_TSTRING {
+ // ignore non-string keys
+ if lua_rawequal(L, objidx, -1) != 0 {
+ // found object?
+ lua_pop(L, 1); // remove value (but keep name)
+ return 1;
+ } else if compat53_findfield(L, objidx, level - 1) != 0 {
+ // try recursively
+ lua_remove(L, -2); // remove table (but keep name)
+ lua_pushliteral(L, ".");
+ lua_insert(L, -2); // place '.' between the two names
+ lua_concat(L, 3);
+ return 1;
+ }
+ }
+ lua_pop(L, 1); // remove value
+ }
+ return 0; // not found
+}
+
+unsafe fn compat53_pushglobalfuncname(L: *mut lua_State, ar: *mut lua_Debug) -> c_int {
+ let top = lua_gettop(L);
+ lua_getinfo(L, cstr!("f"), ar); // push function
+ lua_pushvalue(L, lua::LUA_GLOBALSINDEX);
+ if compat53_findfield(L, top + 1, 2) != 0 {
+ lua_copy(L, -1, top + 1); // move name to proper place
+ lua_pop(L, 2); // remove pushed values
+ return 1;
+ } else {
+ lua_settop(L, top); // remove function and global table
+ return 0;
+ }
+}
+
+unsafe fn compat53_pushfuncname(L: *mut lua_State, ar: *mut lua_Debug) {
+ if *(*ar).namewhat != b'\0' as c_char {
+ // is there a name?
+ lua_pushfstring(L, cstr!("function '%s'"), (*ar).name);
+ } else if *(*ar).what == b'm' as c_char {
+ // main?
+ lua_pushliteral(L, "main chunk");
+ } else if *(*ar).what == b'C' as c_char {
+ if compat53_pushglobalfuncname(L, ar) != 0 {
+ lua_pushfstring(L, cstr!("function '%s'"), lua_tostring(L, -1));
+ lua_remove(L, -2); // remove name
+ } else {
+ lua_pushliteral(L, "?");
+ }
+ } else {
+ lua_pushfstring(
+ L,
+ cstr!("function <%s:%d>"),
+ (*ar).short_src.as_ptr(),
+ (*ar).linedefined,
+ );
+ }
+}
+
+unsafe fn compat53_call_lua(L: *mut lua_State, code: &str, nargs: c_int, nret: c_int) {
+ lua_rawgetp(L, lua::LUA_REGISTRYINDEX, code.as_ptr() as *const c_void);
+ if lua_type(L, -1) != lua::LUA_TFUNCTION {
+ lua_pop(L, 1);
+ if luaL_loadbuffer(
+ L,
+ code.as_ptr() as *const c_char,
+ code.as_bytes().len(),
+ cstr!("=none"),
+ ) != 0
+ {
+ lua_error(L);
+ }
+ lua_pushvalue(L, -1);
+ lua_rawsetp(L, lua::LUA_REGISTRYINDEX, code.as_ptr() as *const c_void);
+ }
+ lua_insert(L, -nargs - 1);
+ lua_call(L, nargs, nret);
+}
+
+//
+// lua ported functions
+//
+
+#[inline(always)]
+pub fn lua_upvalueindex(i: c_int) -> c_int {
+ lua::LUA_GLOBALSINDEX - i
+}
+
+pub unsafe fn lua_absindex(L: *mut lua_State, mut idx: c_int) -> c_int {
+ if idx < 0 && idx > lua::LUA_REGISTRYINDEX {
+ idx += lua_gettop(L) + 1;
+ }
+ idx
+}
+
+pub unsafe fn lua_rotate(L: *mut lua_State, mut idx: c_int, mut n: c_int) {
+ idx = lua_absindex(L, idx);
+ let n_elems = lua_gettop(L) - idx + 1;
+ if n < 0 {
+ n += n_elems;
+ }
+ if n > 0 && n < n_elems {
+ luaL_checkstack(L, 2, cstr!("not enough stack slots available"));
+ n = n_elems - n;
+ compat53_reverse(L, idx, idx + n - 1);
+ compat53_reverse(L, idx + n, idx + n_elems - 1);
+ compat53_reverse(L, idx, idx + n_elems - 1);
+ }
+}
+
+pub unsafe fn lua_copy(L: *mut lua_State, fromidx: c_int, toidx: c_int) {
+ let abs_to = lua_absindex(L, toidx);
+ luaL_checkstack(L, 1, cstr!("not enough stack slots"));
+ lua_pushvalue(L, fromidx);
+ lua_replace(L, abs_to);
+}
+
+pub unsafe fn lua_isinteger(L: *mut lua_State, idx: c_int) -> c_int {
+ if lua_type(L, idx) == lua::LUA_TNUMBER {
+ let n = lua_tonumber(L, idx);
+ let i = lua_tointeger(L, idx);
+ if i as f64 == n {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+pub unsafe fn lua_tonumberx(L: *mut lua_State, i: c_int, isnum: *mut c_int) -> lua_Number {
+ let n = lua_tonumber(L, i);
+ if isnum != ptr::null_mut() {
+ *isnum = if n != 0.0 || lua_isnumber(L, i) != 0 {
+ 1
+ } else {
+ 0
+ };
+ }
+ return n;
+}
+
+pub unsafe fn lua_tointegerx(L: *mut lua_State, i: c_int, isnum: *mut c_int) -> lua_Integer {
+ let mut ok = 0;
+ let n = lua_tonumberx(L, i, &mut ok);
+ if ok != 0 {
+ if n == n as lua_Integer as lua_Number {
+ if isnum != ptr::null_mut() {
+ *isnum = 1;
+ }
+ return n as lua_Integer;
+ }
+ }
+ if isnum != ptr::null_mut() {
+ *isnum = 0;
+ }
+ return 0;
+}
+
+pub unsafe fn lua_rawlen(L: *mut lua_State, idx: c_int) -> usize {
+ lua_objlen(L, idx)
+}
+
+pub unsafe fn lua_compare(L: *mut lua_State, mut idx1: c_int, mut idx2: c_int, op: c_int) -> c_int {
+ match op {
+ lua::LUA_OPEQ => lua_equal(L, idx1, idx2),
+ lua::LUA_OPLT => lua_lessthan(L, idx1, idx2),
+ lua::LUA_OPLE => {
+ luaL_checkstack(L, 5, cstr!("not enough stack slots"));
+ idx1 = lua_absindex(L, idx1);
+ idx2 = lua_absindex(L, idx2);
+ lua_pushvalue(L, idx1);
+ lua_pushvalue(L, idx2);
+ compat53_call_lua(L, "local a,b=...\nreturn a<=b\n", 2, 1);
+ let result = lua_toboolean(L, -1);
+ lua_pop(L, 1);
+ result
+ }
+ _ => luaL_error(L, cstr!("invalid 'op' argument for lua_compare")),
+ }
+}
+
+pub unsafe fn lua_pushlstring(L: *mut lua_State, s: *const c_char, l: usize) -> *const c_char {
+ if l == 0 {
+ lua_pushlstring_51(L, cstr!(""), 0);
+ } else {
+ lua_pushlstring_51(L, s, l);
+ }
+ lua_tostring(L, -1)
+}
+
+pub unsafe fn lua_pushstring(L: *mut lua_State, s: *const c_char) -> *const c_char {
+ lua_pushstring_51(L, s);
+ lua_tostring(L, -1)
+}
+
+pub unsafe fn lua_gettable(L: *mut lua_State, idx: c_int) -> c_int {
+ lua_gettable_51(L, idx);
+ lua_type(L, -1)
+}
+
+pub unsafe fn lua_getfield(L: *mut lua_State, idx: c_int, k: *const c_char) -> c_int {
+ lua_getfield_51(L, idx, k);
+ lua_type(L, -1)
+}
+
+pub unsafe fn lua_geti(L: *mut lua_State, mut idx: c_int, n: lua_Integer) -> c_int {
+ idx = lua_absindex(L, idx);
+ lua_pushinteger(L, n);
+ lua_gettable(L, idx);
+ lua_type(L, -1)
+}
+
+// A new version which returns c_int
+pub unsafe fn lua_rawget(L: *mut lua_State, idx: c_int) -> c_int {
+ lua_rawget_51(L, idx);
+ lua_type(L, -1)
+}
+
+// A new version which returns c_int
+pub unsafe fn lua_rawgeti(L: *mut lua_State, idx: c_int, n: lua_Integer) -> c_int {
+ lua_rawgeti_51(L, idx, n);
+ lua_type(L, -1)
+}
+
+pub unsafe fn lua_rawgetp(L: *mut lua_State, idx: c_int, p: *const c_void) -> c_int {
+ let abs_i = lua_absindex(L, idx);
+ lua_pushlightuserdata(L, p as *mut c_void);
+ lua_rawget(L, abs_i);
+ lua_type(L, -1)
+}
+
+pub unsafe fn lua_getuservalue(L: *mut lua_State, idx: c_int) -> c_int {
+ lua_getfenv(L, idx);
+ lua_type(L, -1)
+}
+
+pub unsafe fn lua_seti(L: *mut lua_State, mut idx: c_int, n: lua_Integer) {
+ luaL_checkstack(L, 1, cstr!("not enough stack slots available"));
+ idx = lua_absindex(L, idx);
+ lua_pushinteger(L, n);
+ lua_insert(L, -2);
+ lua_settable(L, idx);
+}
+
+pub unsafe fn lua_rawsetp(L: *mut lua_State, idx: c_int, p: *const c_void) {
+ let abs_i = lua_absindex(L, idx);
+ luaL_checkstack(L, 1, cstr!("not enough stack slots"));
+ lua_pushlightuserdata(L, p as *mut c_void);
+ lua_insert(L, -2);
+ lua_rawset(L, abs_i);
+}
+
+pub unsafe fn lua_setuservalue(L: *mut lua_State, idx: c_int) {
+ luaL_checktype(L, -1, lua::LUA_TTABLE);
+ lua_setfenv(L, idx);
+}
+
+pub unsafe fn lua_resume(L: *mut lua_State, _from: *mut lua_State, narg: c_int) -> c_int {
+ lua_resume_51(L, narg)
+}
+
+pub unsafe fn lua_len(L: *mut lua_State, idx: c_int) {
+ match lua_type(L, idx) {
+ lua::LUA_TSTRING => {
+ lua_pushnumber(L, lua_objlen(L, idx) as lua_Number);
+ }
+ lua::LUA_TTABLE => {
+ if luaL_callmeta(L, idx, cstr!("__len")) == 0 {
+ lua_pushnumber(L, lua_objlen(L, idx) as lua_Number);
+ }
+ }
+ lua::LUA_TUSERDATA if luaL_callmeta(L, idx, cstr!("__len")) != 0 => {}
+ _ => {
+ luaL_error(
+ L,
+ cstr!("attempt to get length of a %s value"),
+ lua_typename(L, lua_type(L, idx)),
+ );
+ }
+ }
+}
+
+// TODO: lua_stringtonumber
+
+pub unsafe fn lua_getextraspace(L: *mut lua_State) -> *mut c_void {
+ use super::glue::LUA_EXTRASPACE;
+
+ luaL_checkstack(L, 4, cstr!("not enough stack slots available"));
+ lua_pushliteral(L, "__compat53_extraspace");
+ lua_pushvalue(L, -1);
+ lua_rawget(L, lua::LUA_REGISTRYINDEX);
+ if lua_istable(L, -1) == 0 {
+ lua_pop(L, 1);
+ lua_createtable(L, 0, 2);
+ lua_createtable(L, 0, 1);
+ lua_pushliteral(L, "k");
+ lua_setfield(L, -2, cstr!("__mode"));
+ lua_setmetatable(L, -2);
+ lua_pushvalue(L, -2);
+ lua_pushvalue(L, -2);
+ lua_rawset(L, lua::LUA_REGISTRYINDEX);
+ }
+ lua_replace(L, -2);
+ let is_main = lua_pushthread(L);
+ lua_rawget(L, -2);
+ let mut _ptr = lua_touserdata(L, -1);
+ if _ptr == ptr::null_mut() {
+ lua_pop(L, 1);
+ _ptr = lua_newuserdata(L, LUA_EXTRASPACE as usize);
+ if is_main != 0 {
+ // mem::size_of::<c_void>() == 1
+ ptr::write_bytes(_ptr, 0, LUA_EXTRASPACE as usize);
+ lua_pushthread(L);
+ lua_pushvalue(L, -2);
+ lua_rawset(L, -4);
+ lua_pushboolean(L, 1);
+ lua_pushvalue(L, -2);
+ lua_rawset(L, -4);
+ } else {
+ lua_pushboolean(L, 1);
+ lua_rawget(L, -3);
+ let mptr = lua_touserdata(L, -1);
+ if mptr != ptr::null_mut() {
+ ptr::copy_nonoverlapping(mptr, _ptr, LUA_EXTRASPACE as usize)
+ } else {
+ ptr::write_bytes(_ptr, 0, LUA_EXTRASPACE as usize);
+ }
+ lua_pop(L, 1);
+ lua_pushthread(L);
+ lua_pushvalue(L, -2);
+ lua_rawset(L, -4);
+ }
+ }
+ lua_pop(L, 2);
+ return _ptr;
+}
+
+#[inline(always)]
+pub unsafe fn lua_pushglobaltable(L: *mut lua_State) {
+ lua_pushvalue(L, lua::LUA_GLOBALSINDEX);
+}
+
+//
+// lauxlib ported functions
+//
+
+pub unsafe fn luaL_checkversion(_L: *mut lua_State) {
+ // Void
+}
+
+pub unsafe fn luaL_getmetafield(L: *mut lua_State, obj: c_int, e: *const c_char) -> c_int {
+ if luaL_getmetafield_51(L, obj, e) != 0 {
+ lua_type(L, -1)
+ } else {
+ lua::LUA_TNIL
+ }
+}
+
+pub unsafe fn luaL_newmetatable(L: *mut lua_State, tname: *const c_char) -> c_int {
+ if luaL_newmetatable_51(L, tname) != 0 {
+ lua_pushstring(L, tname);
+ lua_setfield(L, -2, cstr!("__name"));
+ 1
+ } else {
+ 0
+ }
+}
+
+pub unsafe fn luaL_loadbufferx(
+ L: *mut lua_State,
+ buff: *const c_char,
+ sz: usize,
+ name: *const c_char,
+ mode: *const c_char,
+) -> c_int {
+ let status = if sz > 0 && *buff as u8 == lua::LUA_SIGNATURE[0] {
+ compat53_checkmode(L, mode, cstr!("binary"), lua::LUA_ERRSYNTAX)
+ } else {
+ compat53_checkmode(L, mode, cstr!("text"), lua::LUA_ERRSYNTAX)
+ };
+ if status != lua::LUA_OK {
+ return status;
+ }
+ luaL_loadbuffer(L, buff, sz, name)
+}
+
+pub unsafe fn luaL_len(L: *mut lua_State, idx: c_int) -> lua_Integer {
+ let mut isnum = 0;
+ luaL_checkstack(L, 1, cstr!("not enough stack slots"));
+ lua_len(L, idx);
+ let res = lua_tointegerx(L, -1, &mut isnum);
+ lua::lua_pop(L, 1);
+ if isnum == 0 {
+ luaL_error(L, cstr!("object length is not an integer"));
+ }
+ res
+}
+
+pub unsafe fn luaL_traceback(
+ L: *mut lua_State,
+ L1: *mut lua_State,
+ msg: *const c_char,
+ mut level: c_int,
+) {
+ let mut ar: lua_Debug = std::mem::zeroed();
+ let top = lua_gettop(L);
+ let numlevels = compat53_countlevels(L1);
+ let mark = if numlevels > COMPAT53_LEVELS1 + COMPAT53_LEVELS2 {
+ COMPAT53_LEVELS1
+ } else {
+ 0
+ };
+
+ if msg != ptr::null() {
+ lua_pushfstring(L, cstr!("%s\n"), msg);
+ }
+ lua_pushliteral(L, "stack traceback:");
+ while lua_getstack(L1, level, &mut ar) != 0 {
+ level += 1;
+ if level == mark {
+ // too many levels?
+ lua_pushliteral(L, "\n\t..."); // add a '...'
+ level = numlevels - COMPAT53_LEVELS2; // and skip to last ones
+ } else {
+ lua_getinfo(L1, cstr!("Slnt"), &mut ar);
+ lua_pushfstring(L, cstr!("\n\t%s:"), cstr!("ok") /*ar.short_src*/);
+ if ar.currentline > 0 {
+ lua_pushfstring(L, cstr!("%d:"), ar.currentline);
+ }
+ lua_pushliteral(L, " in ");
+ compat53_pushfuncname(L, &mut ar);
+ lua_concat(L, lua_gettop(L) - top);
+ }
+ }
+ lua_concat(L, lua_gettop(L) - top);
+}
+
+pub unsafe fn luaL_tolstring(L: *mut lua_State, idx: c_int, len: *mut usize) -> *const c_char {
+ if luaL_callmeta(L, idx, cstr!("__tostring")) == 0 {
+ let t = lua_type(L, idx);
+ match t {
+ lua::LUA_TNIL => {
+ lua_pushliteral(L, "nil");
+ }
+ lua::LUA_TSTRING | lua::LUA_TNUMBER => {
+ lua_pushvalue(L, idx);
+ }
+ lua::LUA_TBOOLEAN => {
+ if lua_toboolean(L, idx) == 0 {
+ lua_pushliteral(L, "false");
+ } else {
+ lua_pushliteral(L, "true");
+ }
+ }
+ _ => {
+ let tt = luaL_getmetafield(L, idx, cstr!("__name"));
+ let name = if tt == lua::LUA_TSTRING {
+ lua_tostring(L, -1)
+ } else {
+ lua_typename(L, t)
+ };
+ lua_pushfstring(L, cstr!("%s: %p"), name, lua_topointer(L, idx));
+ if tt != lua::LUA_TNIL {
+ lua_replace(L, -2);
+ }
+ }
+ };
+ } else {
+ if lua_isstring(L, -1) == 0 {
+ luaL_error(L, cstr!("'__tostring' must return a string"));
+ }
+ }
+ lua_tolstring(L, -1, len)
+}
+
+pub unsafe fn luaL_setmetatable(L: *mut lua_State, tname: *const c_char) {
+ luaL_checkstack(L, 1, cstr!("not enough stack slots"));
+ luaL_getmetatable(L, tname);
+ lua_setmetatable(L, -2);
+}
+
+pub unsafe fn luaL_testudata(L: *mut lua_State, i: c_int, tname: *const c_char) -> *mut c_void {
+ let mut p = lua_touserdata(L, i);
+ luaL_checkstack(L, 2, cstr!("not enough stack slots"));
+ if p == ptr::null_mut() || lua_getmetatable(L, i) == 0 {
+ return ptr::null_mut();
+ } else {
+ luaL_getmetatable(L, tname);
+ let res = lua_rawequal(L, -1, -2);
+ lua_pop(L, 2);
+ if res == 0 {
+ p = ptr::null_mut();
+ }
+ }
+ return p;
+}
+
+pub unsafe fn luaL_setfuncs(L: *mut lua_State, mut l: *const luaL_Reg, nup: c_int) {
+ luaL_checkstack(L, nup + 1, cstr!("too many upvalues"));
+ while (*l).name != ptr::null() {
+ // fill the table with given functions
+ l = l.offset(1);
+ lua_pushstring(L, (*l).name);
+ for _ in 0..nup {
+ // copy upvalues to the top
+ lua_pushvalue(L, -(nup + 1));
+ }
+ lua_pushcclosure(L, (*l).func, nup); // closure with those upvalues
+ lua_settable(L, -(nup + 3)); // table must be below the upvalues, the name and the closure
+ }
+ lua_pop(L, nup); // remove upvalues
+}
+
+pub unsafe fn luaL_getsubtable(L: *mut lua_State, idx: c_int, fname: *const c_char) -> c_int {
+ let abs_i = lua_absindex(L, idx);
+ luaL_checkstack(L, 3, cstr!("not enough stack slots"));
+ lua_pushstring(L, fname);
+ lua_gettable(L, abs_i);
+ if lua_istable(L, -1) != 0 {
+ return 1;
+ }
+ lua_pop(L, 1);
+ lua_newtable(L);
+ lua_pushstring(L, fname);
+ lua_pushvalue(L, -2);
+ lua_settable(L, abs_i);
+ return 0;
+}
+
+pub unsafe fn luaL_requiref(
+ L: *mut lua_State,
+ modname: *const c_char,
+ openf: lua_CFunction,
+ glb: c_int,
+) {
+ luaL_checkstack(L, 3, cstr!("not enough stack slots available"));
+ luaL_getsubtable(L, lua::LUA_REGISTRYINDEX, cstr!("_LOADED"));
+ if lua_getfield(L, -1, modname) == lua::LUA_TNIL {
+ lua_pop(L, 1);
+ lua_pushcfunction(L, openf);
+ lua_pushstring(L, modname);
+ lua_call(L, 1, 1);
+ lua_pushvalue(L, -1);
+ lua_setfield(L, -3, modname);
+ }
+ if glb != 0 {
+ lua_pushvalue(L, -1);
+ lua_setglobal(L, modname);
+ }
+ lua_replace(L, -2);
+}