1use std::ffi::CStr;
6use std::os::raw::{c_char, c_int, c_void};
7use std::{mem, ptr};
8
9use super::lauxlib::*;
10use super::lua::*;
11
12#[inline(always)]
13unsafe fn compat53_reverse(L: *mut lua_State, mut a: c_int, mut b: c_int) {
14 while a < b {
15 lua_pushvalue(L, a);
16 lua_pushvalue(L, b);
17 lua_replace(L, a);
18 lua_replace(L, b);
19 a += 1;
20 b -= 1;
21 }
22}
23
24const COMPAT53_LEVELS1: c_int = 10; const COMPAT53_LEVELS2: c_int = 11; unsafe fn compat53_countlevels(L: *mut lua_State) -> c_int {
28 let mut ar: lua_Debug = mem::zeroed();
29 let (mut li, mut le) = (1, 1);
30 while lua_getstack(L, le, &mut ar) != 0 {
32 li = le;
33 le *= 2;
34 }
35 while li < le {
37 let m = (li + le) / 2;
38 if lua_getstack(L, m, &mut ar) != 0 {
39 li = m + 1
40 } else {
41 le = m;
42 }
43 }
44 le - 1
45}
46
47unsafe fn compat53_checkmode(
48 L: *mut lua_State,
49 mode: *const c_char,
50 modename: *const c_char,
51 err: c_int,
52) -> c_int {
53 unsafe fn strchr(s: *const c_char, c: c_char) -> *const c_char {
54 let mut st = s;
55 while *st != 0 && *st != c {
56 st = st.offset(1);
57 }
58 if *st == c {
59 st
60 } else {
61 ptr::null()
62 }
63 }
64
65 if !mode.is_null() && strchr(mode, *modename).is_null() {
66 lua_pushfstring(
67 L,
68 cstr!("attempt to load a %s chunk (mode is '%s')"),
69 modename,
70 mode,
71 );
72 return err;
73 }
74 LUA_OK
75}
76
77unsafe fn compat53_findfield(L: *mut lua_State, objidx: c_int, level: c_int) -> c_int {
78 if level == 0 || lua_istable(L, -1) == 0 {
79 return 0; }
81
82 lua_pushnil(L); while lua_next(L, -2) != 0 {
84 if lua_type(L, -2) == LUA_TSTRING {
86 if lua_rawequal(L, objidx, -1) != 0 {
88 lua_pop(L, 1); return 1;
91 } else if compat53_findfield(L, objidx, level - 1) != 0 {
92 lua_pushliteral(L, c"."); lua_replace(L, -3); lua_concat(L, 3); return 1;
97 }
98 }
99 lua_pop(L, 1); }
101 0 }
103
104unsafe fn compat53_pushglobalfuncname(L: *mut lua_State, L1: *mut lua_State, ar: *mut lua_Debug) -> c_int {
105 let top = lua_gettop(L);
106 lua_getinfo(L1, cstr!("f"), ar); lua_xmove(L1, L, 1); lua_pushvalue(L, LUA_GLOBALSINDEX);
109 luaL_checkstack(L, 6, cstr!("not enough stack")); if compat53_findfield(L, top + 1, 2) != 0 {
111 let name = lua_tostring(L, -1);
112 if CStr::from_ptr(name).to_bytes().starts_with(b"_G.") {
113 lua_pushstring(L, name.add(3)); lua_remove(L, -2); }
116 lua_copy(L, -1, top + 1); lua_settop(L, top + 1); 1
119 } else {
120 lua_settop(L, top); 0
122 }
123}
124
125unsafe fn compat53_pushfuncname(L: *mut lua_State, L1: *mut lua_State, ar: *mut lua_Debug) {
126 if compat53_pushglobalfuncname(L, L1, ar) != 0 {
128 lua_pushfstring(L, cstr!("function '%s'"), lua_tostring(L, -1));
129 lua_remove(L, -2); } else if *(*ar).namewhat != b'\0' as c_char {
131 lua_pushfstring(L, cstr!("%s '%s'"), (*ar).namewhat, (*ar).name);
133 } else if *(*ar).what == b'm' as c_char {
134 lua_pushliteral(L, c"main chunk");
136 } else if *(*ar).what != b'C' as c_char {
137 let short_src = (*ar).short_src.as_ptr();
139 lua_pushfstring(L, cstr!("function <%s:%d>"), short_src, (*ar).linedefined);
140 } else {
141 lua_pushliteral(L, c"?");
142 }
143}
144
145#[inline(always)]
150pub unsafe fn lua_absindex(L: *mut lua_State, mut idx: c_int) -> c_int {
151 if idx < 0 && idx > LUA_REGISTRYINDEX {
152 idx += lua_gettop(L) + 1;
153 }
154 idx
155}
156
157pub unsafe fn lua_rotate(L: *mut lua_State, mut idx: c_int, mut n: c_int) {
158 idx = lua_absindex(L, idx);
159 if n > 0 {
160 for _ in 0..n {
162 lua_insert(L, idx);
163 }
164 return;
165 }
166 let n_elems = lua_gettop(L) - idx + 1;
167 if n < 0 {
168 n += n_elems;
169 }
170 if n > 0 && n < n_elems {
171 luaL_checkstack(L, 2, cstr!("not enough stack slots available"));
172 n = n_elems - n;
173 compat53_reverse(L, idx, idx + n - 1);
174 compat53_reverse(L, idx + n, idx + n_elems - 1);
175 compat53_reverse(L, idx, idx + n_elems - 1);
176 }
177}
178
179#[inline(always)]
180pub unsafe fn lua_copy(L: *mut lua_State, fromidx: c_int, toidx: c_int) {
181 let abs_to = lua_absindex(L, toidx);
182 luaL_checkstack(L, 1, cstr!("not enough stack slots available"));
183 lua_pushvalue(L, fromidx);
184 lua_replace(L, abs_to);
185}
186
187#[inline(always)]
188pub unsafe fn lua_isinteger(L: *mut lua_State, idx: c_int) -> c_int {
189 if lua_type(L, idx) == LUA_TNUMBER {
190 let n = lua_tonumber(L, idx);
191 let i = lua_tointeger(L, idx);
192 if n.to_bits() == (i as lua_Number).to_bits() {
194 return 1;
195 }
196 }
197 0
198}
199
200#[inline(always)]
201pub unsafe fn lua_tointeger(L: *mut lua_State, i: c_int) -> lua_Integer {
202 lua_tointegerx(L, i, ptr::null_mut())
203}
204
205#[inline(always)]
206pub unsafe fn lua_tonumberx(L: *mut lua_State, i: c_int, isnum: *mut c_int) -> lua_Number {
207 let n = lua_tonumber(L, i);
208 if !isnum.is_null() {
209 *isnum = (n != 0.0 || lua_isnumber(L, i) != 0) as c_int;
210 }
211 n
212}
213
214#[inline(always)]
215pub unsafe fn lua_tointegerx(L: *mut lua_State, i: c_int, isnum: *mut c_int) -> lua_Integer {
216 let mut ok = 0;
217 let n = lua_tonumberx(L, i, &mut ok);
218 let n_int = n as lua_Integer;
219 if ok != 0 && (n - n_int as lua_Number).abs() < lua_Number::EPSILON {
220 if !isnum.is_null() {
221 *isnum = 1;
222 }
223 return n_int;
224 }
225 if !isnum.is_null() {
226 *isnum = 0;
227 }
228 0
229}
230
231#[inline(always)]
232pub unsafe fn lua_rawlen(L: *mut lua_State, idx: c_int) -> usize {
233 lua_objlen(L, idx)
234}
235
236#[inline(always)]
237pub unsafe fn lua_pushlstring(L: *mut lua_State, s: *const c_char, l: usize) -> *const c_char {
238 if l == 0 {
239 lua_pushlstring_(L, cstr!(""), 0);
240 } else {
241 lua_pushlstring_(L, s, l);
242 }
243 lua_tostring(L, -1)
244}
245
246#[inline(always)]
247pub unsafe fn lua_pushstring(L: *mut lua_State, s: *const c_char) -> *const c_char {
248 lua_pushstring_(L, s);
249 lua_tostring(L, -1)
250}
251
252#[inline(always)]
253pub unsafe fn lua_getglobal(L: *mut lua_State, var: *const c_char) -> c_int {
254 lua_getglobal_(L, var);
255 lua_type(L, -1)
256}
257
258#[inline(always)]
259pub unsafe fn lua_gettable(L: *mut lua_State, idx: c_int) -> c_int {
260 lua_gettable_(L, idx);
261 lua_type(L, -1)
262}
263
264#[inline(always)]
265pub unsafe fn lua_getfield(L: *mut lua_State, idx: c_int, k: *const c_char) -> c_int {
266 lua_getfield_(L, idx, k);
267 lua_type(L, -1)
268}
269
270#[inline(always)]
271pub unsafe fn lua_geti(L: *mut lua_State, mut idx: c_int, n: lua_Integer) -> c_int {
272 idx = lua_absindex(L, idx);
273 lua_pushinteger(L, n);
274 lua_gettable(L, idx)
275}
276
277#[inline(always)]
278pub unsafe fn lua_rawget(L: *mut lua_State, idx: c_int) -> c_int {
279 lua_rawget_(L, idx);
280 lua_type(L, -1)
281}
282
283#[inline(always)]
284pub unsafe fn lua_rawgeti(L: *mut lua_State, idx: c_int, n: lua_Integer) -> c_int {
285 let n = n.try_into().expect("cannot convert index to lua_Integer");
286 lua_rawgeti_(L, idx, n);
287 lua_type(L, -1)
288}
289
290#[inline(always)]
291pub unsafe fn lua_rawgetp(L: *mut lua_State, idx: c_int, p: *const c_void) -> c_int {
292 let abs_i = lua_absindex(L, idx);
293 lua_pushlightuserdata(L, p as *mut c_void);
294 lua_rawget(L, abs_i)
295}
296
297#[inline(always)]
298pub unsafe fn lua_getuservalue(L: *mut lua_State, idx: c_int) -> c_int {
299 lua_getfenv(L, idx);
300 lua_type(L, -1)
301}
302
303#[inline(always)]
304pub unsafe fn lua_seti(L: *mut lua_State, mut idx: c_int, n: lua_Integer) {
305 luaL_checkstack(L, 1, cstr!("not enough stack slots available"));
306 idx = lua_absindex(L, idx);
307 lua_pushinteger(L, n);
308 lua_insert(L, -2);
309 lua_settable(L, idx);
310}
311
312#[inline(always)]
313pub unsafe fn lua_rawseti(L: *mut lua_State, idx: c_int, n: lua_Integer) {
314 let n = n.try_into().expect("cannot convert index from lua_Integer");
315 lua_rawseti_(L, idx, n)
316}
317
318#[inline(always)]
319pub unsafe fn lua_rawsetp(L: *mut lua_State, idx: c_int, p: *const c_void) {
320 let abs_i = lua_absindex(L, idx);
321 luaL_checkstack(L, 1, cstr!("not enough stack slots available"));
322 lua_pushlightuserdata(L, p as *mut c_void);
323 lua_insert(L, -2);
324 lua_rawset(L, abs_i);
325}
326
327#[inline(always)]
328pub unsafe fn lua_setuservalue(L: *mut lua_State, idx: c_int) {
329 luaL_checktype(L, -1, LUA_TTABLE);
330 lua_setfenv(L, idx);
331}
332
333#[inline(always)]
334pub unsafe fn lua_dump(L: *mut lua_State, writer: lua_Writer, data: *mut c_void, _strip: c_int) -> c_int {
335 lua_dump_(L, writer, data)
336}
337
338#[inline(always)]
339pub unsafe fn lua_len(L: *mut lua_State, idx: c_int) {
340 match lua_type(L, idx) {
341 LUA_TSTRING => {
342 lua_pushnumber(L, lua_objlen(L, idx) as lua_Number);
343 }
344 LUA_TTABLE => {
345 if luaL_callmeta(L, idx, cstr!("__len")) == 0 {
346 lua_pushnumber(L, lua_objlen(L, idx) as lua_Number);
347 }
348 }
349 LUA_TUSERDATA if luaL_callmeta(L, idx, cstr!("__len")) != 0 => {}
350 _ => {
351 luaL_error(
352 L,
353 cstr!("attempt to get length of a %s value"),
354 lua_typename(L, lua_type(L, idx)),
355 );
356 }
357 }
358}
359
360#[inline(always)]
361pub unsafe fn lua_pushglobaltable(L: *mut lua_State) {
362 lua_pushvalue(L, LUA_GLOBALSINDEX);
363}
364
365#[inline(always)]
366pub unsafe fn lua_resume(L: *mut lua_State, _from: *mut lua_State, narg: c_int, nres: *mut c_int) -> c_int {
367 let ret = lua_resume_(L, narg);
368 if (ret == LUA_OK || ret == LUA_YIELD) && !(nres.is_null()) {
369 *nres = lua_gettop(L);
370 }
371 ret
372}
373
374#[inline(always)]
379pub unsafe fn luaL_checkstack(L: *mut lua_State, sz: c_int, msg: *const c_char) {
380 if lua_checkstack(L, sz + LUA_MINSTACK) == 0 {
381 if !msg.is_null() {
382 luaL_error(L, cstr!("stack overflow (%s)"), msg);
383 } else {
384 lua_pushliteral(L, c"stack overflow");
385 lua_error(L);
386 }
387 }
388}
389
390#[inline(always)]
391pub unsafe fn luaL_getmetafield(L: *mut lua_State, obj: c_int, e: *const c_char) -> c_int {
392 if luaL_getmetafield_(L, obj, e) != 0 {
393 lua_type(L, -1)
394 } else {
395 LUA_TNIL
396 }
397}
398
399#[inline(always)]
400pub unsafe fn luaL_newmetatable(L: *mut lua_State, tname: *const c_char) -> c_int {
401 if luaL_newmetatable_(L, tname) != 0 {
402 lua_pushstring_(L, tname);
403 lua_setfield(L, -2, cstr!("__name"));
404 1
405 } else {
406 0
407 }
408}
409
410pub unsafe fn luaL_loadbufferenv(
411 L: *mut lua_State,
412 data: *const c_char,
413 size: usize,
414 name: *const c_char,
415 mode: *const c_char,
416 mut env: c_int,
417) -> c_int {
418 if env != 0 {
419 env = lua_absindex(L, env);
420 }
421 let status = luaL_loadbufferx(L, data, size, name, mode);
422 if status == LUA_OK && env != 0 {
423 lua_pushvalue(L, env);
424 lua_setfenv(L, -2);
425 }
426 status
427}
428
429#[inline(always)]
430pub unsafe fn luaL_loadbufferx(
431 L: *mut lua_State,
432 buff: *const c_char,
433 sz: usize,
434 name: *const c_char,
435 mode: *const c_char,
436) -> c_int {
437 let status = if sz > 0 && *buff as u8 == LUA_SIGNATURE[0] {
438 compat53_checkmode(L, mode, cstr!("binary"), LUA_ERRSYNTAX)
439 } else {
440 compat53_checkmode(L, mode, cstr!("text"), LUA_ERRSYNTAX)
441 };
442 if status != LUA_OK {
443 return status;
444 }
445 luaL_loadbuffer(L, buff, sz, name)
446}
447
448#[inline(always)]
449pub unsafe fn luaL_len(L: *mut lua_State, idx: c_int) -> lua_Integer {
450 let mut isnum = 0;
451 luaL_checkstack(L, 1, cstr!("not enough stack slots available"));
452 lua_len(L, idx);
453 let res = lua_tointegerx(L, -1, &mut isnum);
454 lua_pop(L, 1);
455 if isnum == 0 {
456 luaL_error(L, cstr!("object length is not an integer"));
457 }
458 res
459}
460
461pub unsafe fn luaL_traceback(L: *mut lua_State, L1: *mut lua_State, msg: *const c_char, mut level: c_int) {
462 let mut ar: lua_Debug = mem::zeroed();
463 let top = lua_gettop(L);
464 let numlevels = compat53_countlevels(L1);
465 #[rustfmt::skip]
466 let mut limit = if numlevels - level > COMPAT53_LEVELS1 + COMPAT53_LEVELS2 { COMPAT53_LEVELS1 } else { -1 };
467
468 if !msg.is_null() {
469 lua_pushfstring(L, cstr!("%s\n"), msg);
470 }
471 lua_pushliteral(L, c"stack traceback:");
472 while lua_getstack(L1, level, &mut ar) != 0 {
473 if limit == 0 {
474 let n = numlevels - level - COMPAT53_LEVELS2;
476 lua_pushfstring(L, cstr!("\n\t...\t(skipping %d levels)"), n + 1); level += n; } else {
480 lua_getinfo(L1, cstr!("Sln"), &mut ar);
481 if *ar.what != b't' as c_char {
482 if ar.currentline <= 0 {
483 lua_pushfstring(L, cstr!("\n\t%s: in "), ar.short_src.as_ptr());
484 } else {
485 lua_pushfstring(L, cstr!("\n\t%s:%d: in "), ar.short_src.as_ptr(), ar.currentline);
486 }
487 compat53_pushfuncname(L, L1, &mut ar);
488 lua_concat(L, lua_gettop(L) - top);
489 } else {
490 lua_pushstring(L, cstr!("\n\t(...tail calls...)"));
491 }
492 }
493 level += 1;
494 limit -= 1;
495 }
496 lua_concat(L, lua_gettop(L) - top);
497}
498
499pub unsafe fn luaL_tolstring(L: *mut lua_State, mut idx: c_int, len: *mut usize) -> *const c_char {
500 idx = lua_absindex(L, idx);
501 if luaL_callmeta(L, idx, cstr!("__tostring")) == 0 {
502 match lua_type(L, idx) {
503 LUA_TNIL => {
504 lua_pushliteral(L, c"nil");
505 }
506 LUA_TSTRING | LUA_TNUMBER => {
507 lua_pushvalue(L, idx);
508 }
509 LUA_TBOOLEAN => {
510 if lua_toboolean(L, idx) == 0 {
511 lua_pushliteral(L, c"false");
512 } else {
513 lua_pushliteral(L, c"true");
514 }
515 }
516 t => {
517 let tt = luaL_getmetafield(L, idx, cstr!("__name"));
518 let name = if tt == LUA_TSTRING {
519 lua_tostring(L, -1)
520 } else {
521 lua_typename(L, t)
522 };
523 lua_pushfstring(L, cstr!("%s: %p"), name, lua_topointer(L, idx));
524 if tt != LUA_TNIL {
525 lua_replace(L, -2); }
527 }
528 };
529 } else if lua_isstring(L, -1) == 0 {
530 luaL_error(L, cstr!("'__tostring' must return a string"));
531 }
532 lua_tolstring(L, -1, len)
533}
534
535#[inline(always)]
536pub unsafe fn luaL_setmetatable(L: *mut lua_State, tname: *const c_char) {
537 luaL_checkstack(L, 1, cstr!("not enough stack slots available"));
538 luaL_getmetatable(L, tname);
539 lua_setmetatable(L, -2);
540}
541
542pub unsafe fn luaL_getsubtable(L: *mut lua_State, idx: c_int, fname: *const c_char) -> c_int {
543 let abs_i = lua_absindex(L, idx);
544 luaL_checkstack(L, 3, cstr!("not enough stack slots available"));
545 lua_pushstring_(L, fname);
546 if lua_gettable(L, abs_i) == LUA_TTABLE {
547 return 1;
548 }
549 lua_pop(L, 1);
550 lua_newtable(L);
551 lua_pushstring_(L, fname);
552 lua_pushvalue(L, -2);
553 lua_settable(L, abs_i);
554 0
555}
556
557pub unsafe fn luaL_requiref(L: *mut lua_State, modname: *const c_char, openf: lua_CFunction, glb: c_int) {
558 luaL_checkstack(L, 3, cstr!("not enough stack slots available"));
559 luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE);
560 if lua_getfield(L, -1, modname) == LUA_TNIL {
561 lua_pop(L, 1);
562 lua_pushcfunction(L, openf);
563 lua_pushstring(L, modname);
564 #[cfg(feature = "lua51")]
565 {
566 lua_call(L, 1, 1);
567 lua_pushvalue(L, -1);
568 lua_setfield(L, -3, modname);
569 }
570 #[cfg(feature = "luajit")]
571 {
572 lua_call(L, 1, 0);
573 lua_getfield(L, -1, modname);
574 }
575 }
576 if glb != 0 {
577 lua_pushvalue(L, -1);
578 lua_setglobal(L, modname);
579 } else {
580 lua_pushnil(L);
581 lua_setglobal(L, modname);
582 }
583 lua_replace(L, -2);
584}