1 // The MIT License (MIT)
2 //
3 // Copyright (c) 2019-2021 A. Orlenko
4 //
5 // Permission is hereby granted, free of charge, to any person obtaining a copy
6 // of this software and associated documentation files (the "Software"), to deal
7 // in the Software without restriction, including without limitation the rights
8 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 // copies of the Software, and to permit persons to whom the Software is
10 // furnished to do so, subject to the following conditions:
11 //
12 // The above copyright notice and this permission notice shall be included in
13 // all copies or substantial portions of the Software.
14 //
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 // THE SOFTWARE.
22 
23 // Based on github.com/keplerproject/lua-compat-5.3
24 
25 #![allow(clippy::needless_return)]
26 
27 use std::ffi::CStr;
28 use std::mem;
29 use std::os::raw::{c_char, c_int, c_void};
30 use std::ptr;
31 
32 use super::lauxlib::{
33     luaL_callmeta, luaL_error, luaL_getmetafield_old, luaL_loadbuffer, luaL_newmetatable_old,
34 };
35 
36 #[cfg(any(feature = "lua51", feature = "luajit"))]
37 use super::lauxlib::{luaL_Reg, luaL_checktype, luaL_getmetatable};
38 
39 #[cfg(feature = "lua52")]
40 use super::lauxlib::{luaL_checkstack, luaL_getsubtable};
41 
42 use super::lua::{
43     self, lua_CFunction, lua_Debug, lua_Integer, lua_Number, lua_State, lua_Writer, lua_call,
44     lua_createtable, lua_dump_old, lua_error, lua_getfield_old, lua_getstack, lua_gettable_old,
45     lua_gettop, lua_insert, lua_isstring, lua_istable, lua_newuserdata, lua_pop, lua_pushboolean,
46     lua_pushcfunction, lua_pushfstring, lua_pushinteger, lua_pushliteral, lua_pushlstring_old,
47     lua_pushnil, lua_pushnumber, lua_pushthread, lua_pushvalue, lua_rawget_old, lua_rawgeti_old,
48     lua_rawset, lua_replace, lua_setfield, lua_setglobal, lua_setmetatable, lua_settable,
49     lua_toboolean, lua_tointeger, lua_tolstring, lua_tonumber, lua_topointer, lua_tostring,
50     lua_touserdata, lua_type, lua_typename,
51 };
52 
53 #[cfg(any(feature = "lua51", feature = "luajit"))]
54 use super::lua::{
55     lua_checkstack, lua_concat, lua_equal, lua_getfenv, lua_getinfo, lua_getmetatable,
56     lua_isnumber, lua_lessthan, lua_newtable, lua_next, lua_objlen, lua_pushcclosure,
57     lua_pushlightuserdata, lua_pushstring_old, lua_rawequal, lua_remove, lua_resume_old,
58     lua_setfenv, lua_settop, LUA_OPADD, LUA_OPUNM,
59 };
60 
61 #[cfg(feature = "lua52")]
62 use super::lua::{
63     lua_absindex, lua_getglobal_old, lua_getuservalue_old, lua_pushstring, lua_rawgetp_old,
64     lua_rawsetp, lua_tonumberx,
65 };
66 
compat53_reverse(L: *mut lua_State, mut a: c_int, mut b: c_int)67 unsafe fn compat53_reverse(L: *mut lua_State, mut a: c_int, mut b: c_int) {
68     while a < b {
69         lua_pushvalue(L, a);
70         lua_pushvalue(L, b);
71         lua_replace(L, a);
72         lua_replace(L, b);
73         a += 1;
74         b -= 1;
75     }
76 }
77 
78 const COMPAT53_LEVELS1: c_int = 12; // size of the first part of the stack
79 const COMPAT53_LEVELS2: c_int = 10; // size of the second part of the stack
80 
compat53_countlevels(L: *mut lua_State) -> c_int81 unsafe fn compat53_countlevels(L: *mut lua_State) -> c_int {
82     let mut ar: lua_Debug = mem::zeroed();
83     let (mut li, mut le) = (1, 1);
84     // find an upper bound
85     while lua_getstack(L, le, &mut ar) != 0 {
86         li = le;
87         le *= 2;
88     }
89     // do a binary search
90     while li < le {
91         let m = (li + le) / 2;
92         if lua_getstack(L, m, &mut ar) != 0 {
93             li = m + 1
94         } else {
95             le = m;
96         }
97     }
98     le - 1
99 }
100 
compat53_checkmode( L: *mut lua_State, mode: *const c_char, modename: *const c_char, err: c_int, ) -> c_int101 unsafe fn compat53_checkmode(
102     L: *mut lua_State,
103     mode: *const c_char,
104     modename: *const c_char,
105     err: c_int,
106 ) -> c_int {
107     unsafe fn strchr(s: *const c_char, c: c_char) -> *const c_char {
108         let mut st = s;
109         while *st != 0 && *st != c {
110             st = st.offset(1);
111         }
112         if *st == c {
113             st
114         } else {
115             ptr::null()
116         }
117     }
118 
119     if !mode.is_null() && strchr(mode, *modename).is_null() {
120         lua_pushfstring(
121             L,
122             cstr!("attempt to load a %s chunk (mode is '%s')"),
123             modename,
124             mode,
125         );
126         return err;
127     }
128     lua::LUA_OK
129 }
130 
131 #[cfg(any(feature = "lua51", feature = "luajit"))]
compat53_findfield(L: *mut lua_State, objidx: c_int, level: c_int) -> c_int132 unsafe fn compat53_findfield(L: *mut lua_State, objidx: c_int, level: c_int) -> c_int {
133     if level == 0 || lua_istable(L, -1) == 0 {
134         return 0; // not found
135     }
136 
137     lua_pushnil(L); // start 'next' loop
138     while lua_next(L, -2) != 0 {
139         // for each pair in table
140         if lua_type(L, -2) == lua::LUA_TSTRING {
141             // ignore non-string keys
142             if lua_rawequal(L, objidx, -1) != 0 {
143                 // found object?
144                 lua_pop(L, 1); // remove value (but keep name)
145                 return 1;
146             } else if compat53_findfield(L, objidx, level - 1) != 0 {
147                 // try recursively
148                 lua_remove(L, -2); // remove table (but keep name)
149                 lua_pushliteral(L, ".");
150                 lua_insert(L, -2); // place '.' between the two names
151                 lua_concat(L, 3);
152                 return 1;
153             }
154         }
155         lua_pop(L, 1); // remove value
156     }
157     return 0; // not found
158 }
159 
160 #[cfg(any(feature = "lua51", feature = "luajit"))]
compat53_pushglobalfuncname(L: *mut lua_State, ar: *mut lua_Debug) -> c_int161 unsafe fn compat53_pushglobalfuncname(L: *mut lua_State, ar: *mut lua_Debug) -> c_int {
162     let top = lua_gettop(L);
163     lua_getinfo(L, cstr!("f"), ar); // push function
164     lua_pushvalue(L, lua::LUA_GLOBALSINDEX);
165     if compat53_findfield(L, top + 1, 2) != 0 {
166         lua_copy(L, -1, top + 1); // move name to proper place
167         lua_pop(L, 2); // remove pushed values
168         return 1;
169     } else {
170         lua_settop(L, top); // remove function and global table
171         return 0;
172     }
173 }
174 
175 #[cfg(any(feature = "lua51", feature = "luajit"))]
compat53_pushfuncname(L: *mut lua_State, ar: *mut lua_Debug)176 unsafe fn compat53_pushfuncname(L: *mut lua_State, ar: *mut lua_Debug) {
177     if *(*ar).namewhat != b'\0' as c_char {
178         // is there a name?
179         lua_pushfstring(L, cstr!("function '%s'"), (*ar).name);
180     } else if *(*ar).what == b'm' as c_char {
181         // main?
182         lua_pushliteral(L, "main chunk");
183     } else if *(*ar).what == b'C' as c_char {
184         if compat53_pushglobalfuncname(L, ar) != 0 {
185             lua_pushfstring(L, cstr!("function '%s'"), lua_tostring(L, -1));
186             lua_remove(L, -2); // remove name
187         } else {
188             lua_pushliteral(L, "?");
189         }
190     } else {
191         lua_pushfstring(
192             L,
193             cstr!("function <%s:%d>"),
194             (*ar).short_src.as_ptr(),
195             (*ar).linedefined,
196         );
197     }
198 }
199 
compat53_call_lua(L: *mut lua_State, code: &str, nargs: c_int, nret: c_int)200 unsafe fn compat53_call_lua(L: *mut lua_State, code: &str, nargs: c_int, nret: c_int) {
201     lua_rawgetp(L, lua::LUA_REGISTRYINDEX, code.as_ptr() as *const c_void);
202     if lua_type(L, -1) != lua::LUA_TFUNCTION {
203         lua_pop(L, 1);
204         if luaL_loadbuffer(
205             L,
206             code.as_ptr() as *const c_char,
207             code.as_bytes().len(),
208             cstr!("=none"),
209         ) != 0
210         {
211             lua_error(L);
212         }
213         lua_pushvalue(L, -1);
214         lua_rawsetp(L, lua::LUA_REGISTRYINDEX, code.as_ptr() as *const c_void);
215     }
216     lua_insert(L, -nargs - 1);
217     lua_call(L, nargs, nret);
218 }
219 
220 //
221 // lua ported functions
222 //
223 
224 #[cfg(any(feature = "lua51", feature = "luajit"))]
225 #[inline(always)]
lua_upvalueindex(i: c_int) -> c_int226 pub fn lua_upvalueindex(i: c_int) -> c_int {
227     lua::LUA_GLOBALSINDEX - i
228 }
229 
230 #[cfg(any(feature = "lua51", feature = "luajit"))]
231 #[inline(always)]
lua_absindex(L: *mut lua_State, mut idx: c_int) -> c_int232 pub unsafe fn lua_absindex(L: *mut lua_State, mut idx: c_int) -> c_int {
233     if idx < 0 && idx > lua::LUA_REGISTRYINDEX {
234         idx += lua_gettop(L) + 1;
235     }
236     idx
237 }
238 
239 #[cfg(any(feature = "lua51", feature = "luajit"))]
240 static COMPAT53_ARITH_CODE: &str = r#"
241 local op,a,b=...
242 if op == 0 then return a+b
243 elseif op == 1 then return a-b
244 elseif op == 2 then return a*b
245 elseif op == 3 then return a/b
246 elseif op == 4 then return a%b
247 elseif op == 5 then return a^b
248 elseif op == 6 then return -a
249 end
250 "#;
251 
252 #[cfg(any(feature = "lua51", feature = "luajit"))]
lua_arith(L: *mut lua_State, op: c_int)253 pub unsafe fn lua_arith(L: *mut lua_State, op: c_int) {
254     #[allow(clippy::manual_range_contains)]
255     if op < LUA_OPADD || op > LUA_OPUNM {
256         luaL_error(L, cstr!("invalid 'op' argument for lua_arith"));
257     }
258     luaL_checkstack(L, 5, cstr!("not enough stack slots"));
259     if op == LUA_OPUNM {
260         lua_pushvalue(L, -1);
261     }
262     lua_pushnumber(L, op as lua_Number);
263     lua_insert(L, -3);
264     compat53_call_lua(L, COMPAT53_ARITH_CODE, 3, 1);
265 }
266 
lua_rotate(L: *mut lua_State, mut idx: c_int, mut n: c_int)267 pub unsafe fn lua_rotate(L: *mut lua_State, mut idx: c_int, mut n: c_int) {
268     idx = lua_absindex(L, idx);
269     let n_elems = lua_gettop(L) - idx + 1;
270     if n < 0 {
271         n += n_elems;
272     }
273     if n > 0 && n < n_elems {
274         luaL_checkstack(L, 2, cstr!("not enough stack slots available"));
275         n = n_elems - n;
276         compat53_reverse(L, idx, idx + n - 1);
277         compat53_reverse(L, idx + n, idx + n_elems - 1);
278         compat53_reverse(L, idx, idx + n_elems - 1);
279     }
280 }
281 
282 #[cfg(any(feature = "lua51", feature = "luajit"))]
283 #[inline(always)]
lua_copy(L: *mut lua_State, fromidx: c_int, toidx: c_int)284 pub unsafe fn lua_copy(L: *mut lua_State, fromidx: c_int, toidx: c_int) {
285     let abs_to = lua_absindex(L, toidx);
286     luaL_checkstack(L, 1, cstr!("not enough stack slots"));
287     lua_pushvalue(L, fromidx);
288     lua_replace(L, abs_to);
289 }
290 
291 #[inline(always)]
lua_isinteger(L: *mut lua_State, idx: c_int) -> c_int292 pub unsafe fn lua_isinteger(L: *mut lua_State, idx: c_int) -> c_int {
293     if lua_type(L, idx) == lua::LUA_TNUMBER {
294         let n = lua_tonumber(L, idx);
295         let i = lua_tointeger(L, idx);
296         if (n - i as lua_Number).abs() < lua_Number::EPSILON {
297             return 1;
298         }
299     }
300     return 0;
301 }
302 
303 #[cfg(any(feature = "lua51", feature = "luajit"))]
304 #[inline(always)]
lua_tonumberx(L: *mut lua_State, i: c_int, isnum: *mut c_int) -> lua_Number305 pub unsafe fn lua_tonumberx(L: *mut lua_State, i: c_int, isnum: *mut c_int) -> lua_Number {
306     let n = lua_tonumber(L, i);
307     if !isnum.is_null() {
308         *isnum = if n != 0.0 || lua_isnumber(L, i) != 0 {
309             1
310         } else {
311             0
312         };
313     }
314     return n;
315 }
316 
317 // Implemented for Lua 5.2 as well
318 // See https://github.com/keplerproject/lua-compat-5.3/issues/40
319 #[inline(always)]
lua_tointegerx(L: *mut lua_State, i: c_int, isnum: *mut c_int) -> lua_Integer320 pub unsafe fn lua_tointegerx(L: *mut lua_State, i: c_int, isnum: *mut c_int) -> lua_Integer {
321     let mut ok = 0;
322     let n = lua_tonumberx(L, i, &mut ok);
323     let n_int = n as lua_Integer;
324     if ok != 0 && (n - n_int as lua_Number).abs() < lua_Number::EPSILON {
325         if !isnum.is_null() {
326             *isnum = 1;
327         }
328         return n_int;
329     }
330     if !isnum.is_null() {
331         *isnum = 0;
332     }
333     return 0;
334 }
335 
336 #[cfg(any(feature = "lua51", feature = "luajit"))]
337 #[inline(always)]
lua_rawlen(L: *mut lua_State, idx: c_int) -> usize338 pub unsafe fn lua_rawlen(L: *mut lua_State, idx: c_int) -> usize {
339     lua_objlen(L, idx)
340 }
341 
342 #[cfg(any(feature = "lua51", feature = "luajit"))]
343 #[inline(always)]
lua_compare(L: *mut lua_State, mut idx1: c_int, mut idx2: c_int, op: c_int) -> c_int344 pub unsafe fn lua_compare(L: *mut lua_State, mut idx1: c_int, mut idx2: c_int, op: c_int) -> c_int {
345     match op {
346         lua::LUA_OPEQ => lua_equal(L, idx1, idx2),
347         lua::LUA_OPLT => lua_lessthan(L, idx1, idx2),
348         lua::LUA_OPLE => {
349             luaL_checkstack(L, 5, cstr!("not enough stack slots"));
350             idx1 = lua_absindex(L, idx1);
351             idx2 = lua_absindex(L, idx2);
352             lua_pushvalue(L, idx1);
353             lua_pushvalue(L, idx2);
354             compat53_call_lua(L, "local a,b=...\nreturn a<=b\n", 2, 1);
355             let result = lua_toboolean(L, -1);
356             lua_pop(L, 1);
357             result
358         }
359         _ => luaL_error(L, cstr!("invalid 'op' argument for lua_compare")),
360     }
361 }
362 
363 #[cfg(any(feature = "lua51", feature = "luajit"))]
364 #[inline(always)]
lua_pushlstring(L: *mut lua_State, s: *const c_char, l: usize) -> *const c_char365 pub unsafe fn lua_pushlstring(L: *mut lua_State, s: *const c_char, l: usize) -> *const c_char {
366     if l == 0 {
367         lua_pushlstring_old(L, cstr!(""), 0);
368     } else {
369         lua_pushlstring_old(L, s, l);
370     }
371     lua_tostring(L, -1)
372 }
373 
374 #[cfg(feature = "lua52")]
375 #[inline(always)]
lua_pushlstring(L: *mut lua_State, s: *const c_char, l: usize) -> *const c_char376 pub unsafe fn lua_pushlstring(L: *mut lua_State, s: *const c_char, l: usize) -> *const c_char {
377     if l == 0 {
378         lua_pushlstring_old(L, cstr!(""), 0)
379     } else {
380         lua_pushlstring_old(L, s, l)
381     }
382 }
383 
384 #[cfg(any(feature = "lua51", feature = "luajit"))]
385 #[inline(always)]
lua_pushstring(L: *mut lua_State, s: *const c_char) -> *const c_char386 pub unsafe fn lua_pushstring(L: *mut lua_State, s: *const c_char) -> *const c_char {
387     lua_pushstring_old(L, s);
388     lua_tostring(L, -1)
389 }
390 
391 #[cfg(feature = "lua52")]
392 #[inline(always)]
lua_getglobal(L: *mut lua_State, var: *const c_char) -> c_int393 pub unsafe fn lua_getglobal(L: *mut lua_State, var: *const c_char) -> c_int {
394     lua_getglobal_old(L, var);
395     lua_type(L, -1)
396 }
397 
398 #[inline(always)]
lua_gettable(L: *mut lua_State, idx: c_int) -> c_int399 pub unsafe fn lua_gettable(L: *mut lua_State, idx: c_int) -> c_int {
400     lua_gettable_old(L, idx);
401     lua_type(L, -1)
402 }
403 
404 #[inline(always)]
lua_getfield(L: *mut lua_State, idx: c_int, k: *const c_char) -> c_int405 pub unsafe fn lua_getfield(L: *mut lua_State, idx: c_int, k: *const c_char) -> c_int {
406     lua_getfield_old(L, idx, k);
407     lua_type(L, -1)
408 }
409 
410 #[inline(always)]
lua_geti(L: *mut lua_State, mut idx: c_int, n: lua_Integer) -> c_int411 pub unsafe fn lua_geti(L: *mut lua_State, mut idx: c_int, n: lua_Integer) -> c_int {
412     idx = lua_absindex(L, idx);
413     lua_pushinteger(L, n);
414     lua_gettable(L, idx);
415     lua_type(L, -1)
416 }
417 
418 // A new version which returns c_int
419 #[inline(always)]
lua_rawget(L: *mut lua_State, idx: c_int) -> c_int420 pub unsafe fn lua_rawget(L: *mut lua_State, idx: c_int) -> c_int {
421     lua_rawget_old(L, idx);
422     lua_type(L, -1)
423 }
424 
425 // A new version which returns c_int
426 #[inline(always)]
lua_rawgeti(L: *mut lua_State, idx: c_int, n: lua_Integer) -> c_int427 pub unsafe fn lua_rawgeti(L: *mut lua_State, idx: c_int, n: lua_Integer) -> c_int {
428     lua_rawgeti_old(L, idx, n);
429     lua_type(L, -1)
430 }
431 
432 #[cfg(any(feature = "lua51", feature = "luajit"))]
433 #[inline(always)]
lua_rawgetp(L: *mut lua_State, idx: c_int, p: *const c_void) -> c_int434 pub unsafe fn lua_rawgetp(L: *mut lua_State, idx: c_int, p: *const c_void) -> c_int {
435     let abs_i = lua_absindex(L, idx);
436     lua_pushlightuserdata(L, p as *mut c_void);
437     lua_rawget(L, abs_i);
438     lua_type(L, -1)
439 }
440 
441 #[cfg(feature = "lua52")]
442 #[inline(always)]
lua_rawgetp(L: *mut lua_State, idx: c_int, p: *const c_void) -> c_int443 pub unsafe fn lua_rawgetp(L: *mut lua_State, idx: c_int, p: *const c_void) -> c_int {
444     lua_rawgetp_old(L, idx, p);
445     lua_type(L, -1)
446 }
447 
448 #[cfg(any(feature = "lua51", feature = "luajit"))]
449 #[inline(always)]
lua_getuservalue(L: *mut lua_State, idx: c_int) -> c_int450 pub unsafe fn lua_getuservalue(L: *mut lua_State, idx: c_int) -> c_int {
451     lua_getfenv(L, idx);
452     lua_type(L, -1)
453 }
454 
455 #[cfg(feature = "lua52")]
456 #[inline(always)]
lua_getuservalue(L: *mut lua_State, idx: c_int) -> c_int457 pub unsafe fn lua_getuservalue(L: *mut lua_State, idx: c_int) -> c_int {
458     lua_getuservalue_old(L, idx);
459     lua_type(L, -1)
460 }
461 
462 #[inline(always)]
lua_seti(L: *mut lua_State, mut idx: c_int, n: lua_Integer)463 pub unsafe fn lua_seti(L: *mut lua_State, mut idx: c_int, n: lua_Integer) {
464     luaL_checkstack(L, 1, cstr!("not enough stack slots available"));
465     idx = lua_absindex(L, idx);
466     lua_pushinteger(L, n);
467     lua_insert(L, -2);
468     lua_settable(L, idx);
469 }
470 
471 #[cfg(any(feature = "lua51", feature = "luajit"))]
472 #[inline(always)]
lua_rawsetp(L: *mut lua_State, idx: c_int, p: *const c_void)473 pub unsafe fn lua_rawsetp(L: *mut lua_State, idx: c_int, p: *const c_void) {
474     let abs_i = lua_absindex(L, idx);
475     luaL_checkstack(L, 1, cstr!("not enough stack slots"));
476     lua_pushlightuserdata(L, p as *mut c_void);
477     lua_insert(L, -2);
478     lua_rawset(L, abs_i);
479 }
480 
481 #[cfg(any(feature = "lua51", feature = "luajit"))]
482 #[inline(always)]
lua_setuservalue(L: *mut lua_State, idx: c_int)483 pub unsafe fn lua_setuservalue(L: *mut lua_State, idx: c_int) {
484     luaL_checktype(L, -1, lua::LUA_TTABLE);
485     lua_setfenv(L, idx);
486 }
487 
488 #[inline(always)]
lua_dump( L: *mut lua_State, writer: lua_Writer, data: *mut c_void, _strip: c_int, ) -> c_int489 pub unsafe fn lua_dump(
490     L: *mut lua_State,
491     writer: lua_Writer,
492     data: *mut c_void,
493     _strip: c_int,
494 ) -> c_int {
495     lua_dump_old(L, writer, data)
496 }
497 
498 #[cfg(any(feature = "lua51", feature = "luajit"))]
499 #[inline(always)]
lua_resume(L: *mut lua_State, _from: *mut lua_State, narg: c_int) -> c_int500 pub unsafe fn lua_resume(L: *mut lua_State, _from: *mut lua_State, narg: c_int) -> c_int {
501     lua_resume_old(L, narg)
502 }
503 
504 #[cfg(any(feature = "lua51", feature = "luajit"))]
505 #[inline(always)]
lua_len(L: *mut lua_State, idx: c_int)506 pub unsafe fn lua_len(L: *mut lua_State, idx: c_int) {
507     match lua_type(L, idx) {
508         lua::LUA_TSTRING => {
509             lua_pushnumber(L, lua_objlen(L, idx) as lua_Number);
510         }
511         lua::LUA_TTABLE => {
512             if luaL_callmeta(L, idx, cstr!("__len")) == 0 {
513                 lua_pushnumber(L, lua_objlen(L, idx) as lua_Number);
514             }
515         }
516         lua::LUA_TUSERDATA if luaL_callmeta(L, idx, cstr!("__len")) != 0 => {}
517         _ => {
518             luaL_error(
519                 L,
520                 cstr!("attempt to get length of a %s value"),
521                 lua_typename(L, lua_type(L, idx)),
522             );
523         }
524     }
525 }
526 
527 #[inline(always)]
lua_stringtonumber(L: *mut lua_State, s: *const c_char) -> usize528 pub unsafe fn lua_stringtonumber(L: *mut lua_State, s: *const c_char) -> usize {
529     use std::str::FromStr;
530 
531     let cs = CStr::from_ptr(s);
532     if let Ok(rs) = cs.to_str() {
533         if let Ok(n) = f64::from_str(rs.trim()) {
534             lua_pushnumber(L, n as lua_Number);
535             return cs.to_bytes_with_nul().len();
536         }
537     }
538     0
539 }
540 
541 #[allow(clippy::branches_sharing_code)]
lua_getextraspace(L: *mut lua_State) -> *mut c_void542 pub unsafe fn lua_getextraspace(L: *mut lua_State) -> *mut c_void {
543     use super::glue::LUA_EXTRASPACE;
544 
545     luaL_checkstack(L, 4, cstr!("not enough stack slots available"));
546     lua_pushliteral(L, "__compat53_extraspace");
547     lua_pushvalue(L, -1);
548     lua_rawget(L, lua::LUA_REGISTRYINDEX);
549     if lua_istable(L, -1) == 0 {
550         lua_pop(L, 1);
551         lua_createtable(L, 0, 2);
552         lua_createtable(L, 0, 1);
553         lua_pushliteral(L, "k");
554         lua_setfield(L, -2, cstr!("__mode"));
555         lua_setmetatable(L, -2);
556         lua_pushvalue(L, -2);
557         lua_pushvalue(L, -2);
558         lua_rawset(L, lua::LUA_REGISTRYINDEX);
559     }
560     lua_replace(L, -2);
561     let is_main = lua_pushthread(L);
562     lua_rawget(L, -2);
563     let mut _ptr = lua_touserdata(L, -1);
564     if _ptr.is_null() {
565         lua_pop(L, 1);
566         _ptr = lua_newuserdata(L, LUA_EXTRASPACE as usize);
567         if is_main != 0 {
568             // mem::size_of::<c_void>() == 1
569             ptr::write_bytes(_ptr, 0, LUA_EXTRASPACE as usize);
570             lua_pushthread(L);
571             lua_pushvalue(L, -2);
572             lua_rawset(L, -4);
573             lua_pushboolean(L, 1);
574             lua_pushvalue(L, -2);
575             lua_rawset(L, -4);
576         } else {
577             lua_pushboolean(L, 1);
578             lua_rawget(L, -3);
579             let mptr = lua_touserdata(L, -1);
580             if !mptr.is_null() {
581                 ptr::copy_nonoverlapping(mptr, _ptr, LUA_EXTRASPACE as usize)
582             } else {
583                 ptr::write_bytes(_ptr, 0, LUA_EXTRASPACE as usize);
584             }
585             lua_pop(L, 1);
586             lua_pushthread(L);
587             lua_pushvalue(L, -2);
588             lua_rawset(L, -4);
589         }
590     }
591     lua_pop(L, 2);
592     return _ptr;
593 }
594 
595 #[cfg(any(feature = "lua51", feature = "luajit"))]
596 #[inline(always)]
lua_pushglobaltable(L: *mut lua_State)597 pub unsafe fn lua_pushglobaltable(L: *mut lua_State) {
598     lua_pushvalue(L, lua::LUA_GLOBALSINDEX);
599 }
600 
601 //
602 // lauxlib ported functions
603 //
604 
605 #[cfg(any(feature = "lua51", feature = "luajit"))]
606 #[inline(always)]
luaL_checkstack(L: *mut lua_State, sz: c_int, msg: *const c_char)607 pub unsafe fn luaL_checkstack(L: *mut lua_State, sz: c_int, msg: *const c_char) {
608     if lua_checkstack(L, sz + lua::LUA_MINSTACK) == 0 {
609         if !msg.is_null() {
610             luaL_error(L, cstr!("stack overflow (%s)"), msg);
611         } else {
612             lua_pushliteral(L, "stack overflow");
613             lua_error(L);
614         }
615     }
616 }
617 
luaL_checkversion(_L: *mut lua_State)618 pub unsafe fn luaL_checkversion(_L: *mut lua_State) {
619     // Void
620 }
621 
622 #[inline(always)]
luaL_getmetafield(L: *mut lua_State, obj: c_int, e: *const c_char) -> c_int623 pub unsafe fn luaL_getmetafield(L: *mut lua_State, obj: c_int, e: *const c_char) -> c_int {
624     if luaL_getmetafield_old(L, obj, e) != 0 {
625         lua_type(L, -1)
626     } else {
627         lua::LUA_TNIL
628     }
629 }
630 
631 #[inline(always)]
luaL_newmetatable(L: *mut lua_State, tname: *const c_char) -> c_int632 pub unsafe fn luaL_newmetatable(L: *mut lua_State, tname: *const c_char) -> c_int {
633     if luaL_newmetatable_old(L, tname) != 0 {
634         lua_pushstring(L, tname);
635         lua_setfield(L, -2, cstr!("__name"));
636         1
637     } else {
638         0
639     }
640 }
641 
642 #[cfg(any(feature = "lua51", feature = "luajit"))]
643 #[inline(always)]
luaL_loadbufferx( L: *mut lua_State, buff: *const c_char, sz: usize, name: *const c_char, mode: *const c_char, ) -> c_int644 pub unsafe fn luaL_loadbufferx(
645     L: *mut lua_State,
646     buff: *const c_char,
647     sz: usize,
648     name: *const c_char,
649     mode: *const c_char,
650 ) -> c_int {
651     let status = if sz > 0 && *buff as u8 == lua::LUA_SIGNATURE[0] {
652         compat53_checkmode(L, mode, cstr!("binary"), lua::LUA_ERRSYNTAX)
653     } else {
654         compat53_checkmode(L, mode, cstr!("text"), lua::LUA_ERRSYNTAX)
655     };
656     if status != lua::LUA_OK {
657         return status;
658     }
659     luaL_loadbuffer(L, buff, sz, name)
660 }
661 
662 #[cfg(any(feature = "lua51", feature = "luajit"))]
663 #[inline(always)]
luaL_len(L: *mut lua_State, idx: c_int) -> lua_Integer664 pub unsafe fn luaL_len(L: *mut lua_State, idx: c_int) -> lua_Integer {
665     let mut isnum = 0;
666     luaL_checkstack(L, 1, cstr!("not enough stack slots"));
667     lua_len(L, idx);
668     let res = lua_tointegerx(L, -1, &mut isnum);
669     lua::lua_pop(L, 1);
670     if isnum == 0 {
671         luaL_error(L, cstr!("object length is not an integer"));
672     }
673     res
674 }
675 
676 #[cfg(any(feature = "lua51", feature = "luajit"))]
luaL_traceback( L: *mut lua_State, L1: *mut lua_State, msg: *const c_char, mut level: c_int, )677 pub unsafe fn luaL_traceback(
678     L: *mut lua_State,
679     L1: *mut lua_State,
680     msg: *const c_char,
681     mut level: c_int,
682 ) {
683     let mut ar: lua_Debug = mem::zeroed();
684     let top = lua_gettop(L);
685     let numlevels = compat53_countlevels(L1);
686     let mark = if numlevels > COMPAT53_LEVELS1 + COMPAT53_LEVELS2 {
687         COMPAT53_LEVELS1
688     } else {
689         0
690     };
691 
692     if !msg.is_null() {
693         lua_pushfstring(L, cstr!("%s\n"), msg);
694     }
695     lua_pushliteral(L, "stack traceback:");
696     while lua_getstack(L1, level, &mut ar) != 0 {
697         level += 1;
698         if level == mark {
699             // too many levels?
700             lua_pushliteral(L, "\n\t..."); // add a '...'
701             level = numlevels - COMPAT53_LEVELS2; // and skip to last ones
702         } else {
703             lua_getinfo(L1, cstr!("Slnt"), &mut ar);
704             lua_pushfstring(L, cstr!("\n\t%s:"), ar.short_src.as_ptr());
705             if ar.currentline > 0 {
706                 lua_pushfstring(L, cstr!("%d:"), ar.currentline);
707             }
708             lua_pushliteral(L, " in ");
709             compat53_pushfuncname(L, &mut ar);
710             lua_concat(L, lua_gettop(L) - top);
711         }
712     }
713     lua_concat(L, lua_gettop(L) - top);
714 }
715 
luaL_tolstring(L: *mut lua_State, idx: c_int, len: *mut usize) -> *const c_char716 pub unsafe fn luaL_tolstring(L: *mut lua_State, idx: c_int, len: *mut usize) -> *const c_char {
717     if luaL_callmeta(L, idx, cstr!("__tostring")) == 0 {
718         let t = lua_type(L, idx);
719         match t {
720             lua::LUA_TNIL => {
721                 lua_pushliteral(L, "nil");
722             }
723             lua::LUA_TSTRING | lua::LUA_TNUMBER => {
724                 lua_pushvalue(L, idx);
725             }
726             lua::LUA_TBOOLEAN => {
727                 if lua_toboolean(L, idx) == 0 {
728                     lua_pushliteral(L, "false");
729                 } else {
730                     lua_pushliteral(L, "true");
731                 }
732             }
733             _ => {
734                 let tt = luaL_getmetafield(L, idx, cstr!("__name"));
735                 let name = if tt == lua::LUA_TSTRING {
736                     lua_tostring(L, -1)
737                 } else {
738                     lua_typename(L, t)
739                 };
740                 lua_pushfstring(L, cstr!("%s: %p"), name, lua_topointer(L, idx));
741                 if tt != lua::LUA_TNIL {
742                     lua_replace(L, -2);
743                 }
744             }
745         };
746     } else if lua_isstring(L, -1) == 0 {
747         luaL_error(L, cstr!("'__tostring' must return a string"));
748     }
749     lua_tolstring(L, -1, len)
750 }
751 
752 #[cfg(any(feature = "lua51", feature = "luajit"))]
753 #[inline(always)]
luaL_setmetatable(L: *mut lua_State, tname: *const c_char)754 pub unsafe fn luaL_setmetatable(L: *mut lua_State, tname: *const c_char) {
755     luaL_checkstack(L, 1, cstr!("not enough stack slots"));
756     luaL_getmetatable(L, tname);
757     lua_setmetatable(L, -2);
758 }
759 
760 #[cfg(any(feature = "lua51", feature = "luajit"))]
761 #[inline(always)]
luaL_testudata(L: *mut lua_State, i: c_int, tname: *const c_char) -> *mut c_void762 pub unsafe fn luaL_testudata(L: *mut lua_State, i: c_int, tname: *const c_char) -> *mut c_void {
763     let mut p = lua_touserdata(L, i);
764     luaL_checkstack(L, 2, cstr!("not enough stack slots"));
765     if p.is_null() || lua_getmetatable(L, i) == 0 {
766         return ptr::null_mut();
767     } else {
768         luaL_getmetatable(L, tname);
769         let res = lua_rawequal(L, -1, -2);
770         lua_pop(L, 2);
771         if res == 0 {
772             p = ptr::null_mut();
773         }
774     }
775     return p;
776 }
777 
778 #[cfg(any(feature = "lua51", feature = "luajit"))]
779 #[inline(always)]
luaL_setfuncs(L: *mut lua_State, mut l: *const luaL_Reg, nup: c_int)780 pub unsafe fn luaL_setfuncs(L: *mut lua_State, mut l: *const luaL_Reg, nup: c_int) {
781     luaL_checkstack(L, nup + 1, cstr!("too many upvalues"));
782     while !(*l).name.is_null() {
783         // fill the table with given functions
784         l = l.offset(1);
785         lua_pushstring(L, (*l).name);
786         for _ in 0..nup {
787             // copy upvalues to the top
788             lua_pushvalue(L, -(nup + 1));
789         }
790         lua_pushcclosure(L, (*l).func, nup); // closure with those upvalues
791         lua_settable(L, -(nup + 3)); // table must be below the upvalues, the name and the closure
792     }
793     lua_pop(L, nup); // remove upvalues
794 }
795 
796 #[cfg(any(feature = "lua51", feature = "luajit"))]
luaL_getsubtable(L: *mut lua_State, idx: c_int, fname: *const c_char) -> c_int797 pub unsafe fn luaL_getsubtable(L: *mut lua_State, idx: c_int, fname: *const c_char) -> c_int {
798     let abs_i = lua_absindex(L, idx);
799     luaL_checkstack(L, 3, cstr!("not enough stack slots"));
800     lua_pushstring(L, fname);
801     lua_gettable(L, abs_i);
802     if lua_istable(L, -1) != 0 {
803         return 1;
804     }
805     lua_pop(L, 1);
806     lua_newtable(L);
807     lua_pushstring(L, fname);
808     lua_pushvalue(L, -2);
809     lua_settable(L, abs_i);
810     return 0;
811 }
812 
luaL_requiref( L: *mut lua_State, modname: *const c_char, openf: lua_CFunction, glb: c_int, )813 pub unsafe fn luaL_requiref(
814     L: *mut lua_State,
815     modname: *const c_char,
816     openf: lua_CFunction,
817     glb: c_int,
818 ) {
819     luaL_checkstack(L, 3, cstr!("not enough stack slots available"));
820     luaL_getsubtable(L, lua::LUA_REGISTRYINDEX, cstr!("_LOADED"));
821     if lua_getfield(L, -1, modname) == lua::LUA_TNIL {
822         lua_pop(L, 1);
823         lua_pushcfunction(L, openf);
824         lua_pushstring(L, modname);
825         #[cfg(any(feature = "lua52", feature = "lua51"))]
826         {
827             lua_call(L, 1, 1);
828             lua_pushvalue(L, -1);
829             lua_setfield(L, -3, modname);
830         }
831         #[cfg(feature = "luajit")]
832         {
833             lua_call(L, 1, 0);
834             lua_getfield(L, -1, modname);
835         }
836     }
837     if cfg!(any(feature = "lua52", feature = "lua51")) && glb != 0 {
838         lua_pushvalue(L, -1);
839         lua_setglobal(L, modname);
840     }
841     if cfg!(feature = "luajit") && glb == 0 {
842         lua_pushnil(L);
843         lua_setglobal(L, modname);
844     }
845     lua_replace(L, -2);
846 }
847