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::*;
11use super::luacode::*;
12
13pub const LUA_RESUMEERROR: c_int = -1;
14
15const LBC_VERSION_MAX: u8 = 11;
17const LBC_TYPE_VERSION_MIN: u8 = 1;
18const LBC_TYPE_VERSION_MAX: u8 = 3;
19
20unsafe fn compat53_reverse(L: *mut lua_State, mut a: c_int, mut b: c_int) {
21 while a < b {
22 lua_pushvalue(L, a);
23 lua_pushvalue(L, b);
24 lua_replace(L, a);
25 lua_replace(L, b);
26 a += 1;
27 b -= 1;
28 }
29}
30
31const COMPAT53_LEVELS1: c_int = 10; const COMPAT53_LEVELS2: c_int = 11; unsafe fn compat53_findfield(L: *mut lua_State, objidx: c_int, level: c_int) -> c_int {
35 if level == 0 || lua_istable(L, -1) == 0 {
36 return 0; }
38
39 lua_pushnil(L); while lua_next(L, -2) != 0 {
41 if lua_type(L, -2) == LUA_TSTRING {
43 if lua_rawequal(L, objidx, -1) != 0 {
45 lua_pop(L, 1); return 1;
48 } else if compat53_findfield(L, objidx, level - 1) != 0 {
49 lua_pushliteral(L, c"."); lua_replace(L, -3); lua_concat(L, 3); return 1;
54 }
55 }
56 lua_pop(L, 1); }
58 0 }
60
61unsafe fn compat53_pushglobalfuncname(
62 L: *mut lua_State,
63 L1: *mut lua_State,
64 level: c_int,
65 ar: *mut lua_Debug,
66) -> c_int {
67 let top = lua_gettop(L);
68 lua_getinfo(L1, level, cstr!("f"), ar); lua_xmove(L1, L, 1); lua_pushvalue(L, LUA_GLOBALSINDEX);
71 luaL_checkstack(L, 6, cstr!("not enough stack")); if compat53_findfield(L, top + 1, 2) != 0 {
73 let name = lua_tostring(L, -1);
74 if CStr::from_ptr(name).to_bytes().starts_with(b"_G.") {
75 lua_pushstring(L, name.add(3)); lua_remove(L, -2); }
78 lua_copy(L, -1, top + 1); lua_settop(L, top + 1); 1
81 } else {
82 lua_settop(L, top); 0
84 }
85}
86
87unsafe fn compat53_pushfuncname(L: *mut lua_State, L1: *mut lua_State, level: c_int, ar: *mut lua_Debug) {
88 if !(*ar).name.is_null() {
89 lua_pushfstring(L, cstr!("function '%s'"), (*ar).name);
91 } else if compat53_pushglobalfuncname(L, L1, level, ar) != 0 {
92 lua_pushfstring(L, cstr!("function '%s'"), lua_tostring(L, -1));
93 lua_remove(L, -2); } else if *(*ar).what != b'C' as c_char {
95 lua_pushfstring(L, cstr!("function <%s:%d>"), (*ar).short_src, (*ar).linedefined);
97 } else {
98 lua_pushliteral(L, c"?");
99 }
100}
101
102pub unsafe fn lua_rotate(L: *mut lua_State, mut idx: c_int, mut n: c_int) {
107 idx = lua_absindex(L, idx);
108 if n > 0 {
109 for _ in 0..n {
111 lua_insert(L, idx);
112 }
113 return;
114 }
115 let n_elems = lua_gettop(L) - idx + 1;
116 if n < 0 {
117 n += n_elems;
118 }
119 if n > 0 && n < n_elems {
120 luaL_checkstack(L, 2, cstr!("not enough stack slots available"));
121 n = n_elems - n;
122 compat53_reverse(L, idx, idx + n - 1);
123 compat53_reverse(L, idx + n, idx + n_elems - 1);
124 compat53_reverse(L, idx, idx + n_elems - 1);
125 }
126}
127
128#[inline(always)]
129pub unsafe fn lua_copy(L: *mut lua_State, fromidx: c_int, toidx: c_int) {
130 let abs_to = lua_absindex(L, toidx);
131 luaL_checkstack(L, 1, cstr!("not enough stack slots available"));
132 lua_pushvalue(L, fromidx);
133 lua_replace(L, abs_to);
134}
135
136#[inline(always)]
137pub unsafe fn lua_isinteger(L: *mut lua_State, idx: c_int) -> c_int {
138 if lua_type(L, idx) == LUA_TNUMBER {
139 let n = lua_tonumber(L, idx);
140 let i = lua_tointeger(L, idx);
141 if n.to_bits() == (i as lua_Number).to_bits() {
143 return 1;
144 }
145 }
146 0
147}
148
149#[inline(always)]
150pub unsafe fn lua_pushinteger(L: *mut lua_State, i: lua_Integer) {
151 lua_pushnumber(L, i as lua_Number);
152}
153
154#[inline(always)]
155pub unsafe fn lua_tointeger(L: *mut lua_State, i: c_int) -> lua_Integer {
156 lua_tointegerx(L, i, ptr::null_mut())
157}
158
159pub unsafe fn lua_tointegerx(L: *mut lua_State, i: c_int, isnum: *mut c_int) -> lua_Integer {
160 let mut ok = 0;
161 let n = lua_tonumberx(L, i, &mut ok);
162 let n_int = n as lua_Integer;
163 if ok != 0 && (n - n_int as lua_Number).abs() < lua_Number::EPSILON {
164 if !isnum.is_null() {
165 *isnum = 1;
166 }
167 return n_int;
168 }
169 if !isnum.is_null() {
170 *isnum = 0;
171 }
172 0
173}
174
175#[inline(always)]
176pub unsafe fn lua_rawlen(L: *mut lua_State, idx: c_int) -> usize {
177 lua_objlen(L, idx)
178}
179
180#[inline(always)]
181pub unsafe fn lua_pushlstring(L: *mut lua_State, s: *const c_char, l: usize) -> *const c_char {
182 if l == 0 {
183 lua_pushlstring_(L, cstr!(""), 0);
184 } else {
185 lua_pushlstring_(L, s, l);
186 }
187 lua_tostring(L, -1)
188}
189
190#[inline(always)]
191pub unsafe fn lua_pushstring(L: *mut lua_State, s: *const c_char) -> *const c_char {
192 lua_pushstring_(L, s);
193 lua_tostring(L, -1)
194}
195
196#[inline(always)]
197pub unsafe fn lua_geti(L: *mut lua_State, mut idx: c_int, n: lua_Integer) -> c_int {
198 idx = lua_absindex(L, idx);
199 lua_pushinteger(L, n);
200 lua_gettable(L, idx)
201}
202
203#[inline(always)]
204pub unsafe fn lua_rawgeti(L: *mut lua_State, idx: c_int, n: lua_Integer) -> c_int {
205 let n = n.try_into().expect("cannot convert index from lua_Integer");
206 lua_rawgeti_(L, idx, n)
207}
208
209#[inline(always)]
210pub unsafe fn lua_rawgetp(L: *mut lua_State, idx: c_int, p: *const c_void) -> c_int {
211 lua_rawgetptagged(L, idx, p, 0)
212}
213
214#[inline(always)]
215pub unsafe fn lua_getuservalue(L: *mut lua_State, mut idx: c_int) -> c_int {
216 luaL_checkstack(L, 2, cstr!("not enough stack slots available"));
217 idx = lua_absindex(L, idx);
218 lua_pushliteral(L, c"__mlua_uservalues");
219 if lua_rawget(L, LUA_REGISTRYINDEX) != LUA_TTABLE {
220 return LUA_TNIL;
221 }
222 lua_pushvalue(L, idx);
223 lua_rawget(L, -2);
224 lua_remove(L, -2);
225 lua_type(L, -1)
226}
227
228#[inline(always)]
229pub unsafe fn lua_seti(L: *mut lua_State, mut idx: c_int, n: lua_Integer) {
230 luaL_checkstack(L, 1, cstr!("not enough stack slots available"));
231 idx = lua_absindex(L, idx);
232 lua_pushinteger(L, n);
233 lua_insert(L, -2);
234 lua_settable(L, idx);
235}
236
237#[inline(always)]
238pub unsafe fn lua_rawseti(L: *mut lua_State, idx: c_int, n: lua_Integer) {
239 let n = n.try_into().expect("cannot convert index from lua_Integer");
240 lua_rawseti_(L, idx, n)
241}
242
243#[inline(always)]
244pub unsafe fn lua_rawsetp(L: *mut lua_State, idx: c_int, p: *const c_void) {
245 lua_rawsetptagged(L, idx, p, 0)
246}
247
248#[inline(always)]
249pub unsafe fn lua_setuservalue(L: *mut lua_State, mut idx: c_int) {
250 luaL_checkstack(L, 4, cstr!("not enough stack slots available"));
251 idx = lua_absindex(L, idx);
252 lua_pushliteral(L, c"__mlua_uservalues");
253 lua_pushvalue(L, -1);
254 if lua_rawget(L, LUA_REGISTRYINDEX) != LUA_TTABLE {
255 lua_pop(L, 1);
256 lua_createtable(L, 0, 2); lua_createtable(L, 0, 1); lua_pushliteral(L, c"k");
259 lua_setfield(L, -2, cstr!("__mode"));
260 lua_setmetatable(L, -2);
261 lua_pushvalue(L, -2);
262 lua_pushvalue(L, -2);
263 lua_rawset(L, LUA_REGISTRYINDEX);
264 }
265 lua_replace(L, -2);
266 lua_pushvalue(L, idx);
267 lua_pushvalue(L, -3);
268 lua_remove(L, -4);
269 lua_rawset(L, -3);
270 lua_pop(L, 1);
271}
272
273#[inline(always)]
274pub unsafe fn lua_len(L: *mut lua_State, idx: c_int) {
275 match lua_type(L, idx) {
276 LUA_TSTRING => {
277 lua_pushnumber(L, lua_objlen(L, idx) as lua_Number);
278 }
279 LUA_TTABLE => {
280 if luaL_callmeta(L, idx, cstr!("__len")) == 0 {
281 lua_pushnumber(L, lua_objlen(L, idx) as lua_Number);
282 }
283 }
284 LUA_TUSERDATA if luaL_callmeta(L, idx, cstr!("__len")) != 0 => {}
285 _ => {
286 luaL_error(
287 L,
288 cstr!("attempt to get length of a %s value"),
289 lua_typename(L, lua_type(L, idx)),
290 );
291 }
292 }
293}
294
295#[inline(always)]
296pub unsafe fn lua_pushglobaltable(L: *mut lua_State) {
297 lua_pushvalue(L, LUA_GLOBALSINDEX);
298}
299
300#[inline(always)]
301pub unsafe fn lua_resume(L: *mut lua_State, from: *mut lua_State, narg: c_int, nres: *mut c_int) -> c_int {
302 let ret = lua_resume_(L, from, narg);
303 if (ret == LUA_OK || ret == LUA_YIELD) && !(nres.is_null()) {
304 *nres = lua_gettop(L);
305 }
306 ret
307}
308
309#[inline(always)]
310pub unsafe fn lua_resumex(L: *mut lua_State, from: *mut lua_State, narg: c_int, nres: *mut c_int) -> c_int {
311 let ret = if narg == LUA_RESUMEERROR {
312 lua_resumeerror(L, from)
313 } else {
314 lua_resume_(L, from, narg)
315 };
316 if (ret == LUA_OK || ret == LUA_YIELD) && !(nres.is_null()) {
317 *nres = lua_gettop(L);
318 }
319 ret
320}
321
322#[inline(always)]
327pub unsafe fn luaL_checkstack(L: *mut lua_State, sz: c_int, msg: *const c_char) {
328 if lua_checkstack(L, sz + LUA_MINSTACK) == 0 {
329 if !msg.is_null() {
330 luaL_error(L, cstr!("stack overflow (%s)"), msg);
331 } else {
332 lua_pushliteral(L, c"stack overflow");
333 lua_error(L);
334 }
335 }
336}
337
338#[inline(always)]
339pub unsafe fn luaL_checkinteger(L: *mut lua_State, narg: c_int) -> lua_Integer {
340 let mut isnum = 0;
341 let int = lua_tointegerx(L, narg, &mut isnum);
342 if isnum == 0 {
343 luaL_typeerror(L, narg, lua_typename(L, LUA_TNUMBER));
344 }
345 int
346}
347
348pub unsafe fn luaL_optinteger(L: *mut lua_State, narg: c_int, def: lua_Integer) -> lua_Integer {
349 if lua_isnoneornil(L, narg) != 0 {
350 def
351 } else {
352 luaL_checkinteger(L, narg)
353 }
354}
355
356#[inline(always)]
357pub unsafe fn luaL_getmetafield(L: *mut lua_State, obj: c_int, e: *const c_char) -> c_int {
358 if luaL_getmetafield_(L, obj, e) != 0 {
359 lua_type(L, -1)
360 } else {
361 LUA_TNIL
362 }
363}
364
365#[inline(always)]
366pub unsafe fn luaL_newmetatable(L: *mut lua_State, tname: *const c_char) -> c_int {
367 if luaL_newmetatable_(L, tname) != 0 {
368 lua_pushstring(L, tname);
369 lua_setfield(L, -2, cstr!("__type"));
370 1
371 } else {
372 0
373 }
374}
375
376pub unsafe fn luaL_isbytecode(data: *const c_char, size: usize) -> bool {
378 if size == 0 {
379 return false;
380 }
381 match *data as u8 {
382 b if b < b'\t' => true, b if b <= LBC_VERSION_MAX => {
384 let types_version = (size >= 2).then(|| *data.add(1) as u8);
385 match types_version {
386 Some(LBC_TYPE_VERSION_MIN..=LBC_TYPE_VERSION_MAX) => true, _ => false, }
389 }
390 _ => false, }
392}
393
394pub unsafe fn luaL_loadbufferenv(
395 L: *mut lua_State,
396 data: *const c_char,
397 mut size: usize,
398 name: *const c_char,
399 mode: *const c_char,
400 mut env: c_int,
401) -> c_int {
402 unsafe extern "C" {
403 fn free(p: *mut c_void);
404 }
405
406 unsafe extern "C" fn data_dtor(_: *mut lua_State, data: *mut c_void) {
407 free(*(data as *mut *mut c_char) as *mut c_void);
408 }
409
410 let is_bytecode = luaL_isbytecode(data, size);
411 if !mode.is_null() {
412 let modeb = CStr::from_ptr(mode).to_bytes();
413 let allow_binary = modeb.contains(&b'b');
414 let allow_text = modeb.contains(&b't');
415 if is_bytecode && !allow_binary {
416 lua_pushfstring(L, cstr!("attempt to load a binary chunk (mode is '%s')"), mode);
417 return LUA_ERRSYNTAX;
418 } else if !is_bytecode && !allow_text {
419 lua_pushfstring(L, cstr!("attempt to load a text chunk (mode is '%s')"), mode);
420 return LUA_ERRSYNTAX;
421 }
422 }
423
424 let status = if !is_bytecode {
425 if env < 0 {
426 env -= 1;
427 }
428 let data_ud = lua_newuserdatadtor(L, mem::size_of::<*mut c_char>(), data_dtor) as *mut *mut c_char;
429 let data = luau_compile_(data, size, ptr::null_mut(), &mut size);
430 ptr::write(data_ud, data);
431 let status = luau_load(L, name, data, size, env);
434 lua_replace(L, -2); status
436 } else {
437 luau_load(L, name, data, size, env)
438 };
439
440 if status != 0 {
441 if lua_isstring(L, -1) != 0 && CStr::from_ptr(lua_tostring(L, -1)) == c"not enough memory" {
442 return LUA_ERRMEM;
444 }
445 return LUA_ERRSYNTAX;
446 }
447
448 LUA_OK
449}
450
451#[inline(always)]
452pub unsafe fn luaL_loadbufferx(
453 L: *mut lua_State,
454 data: *const c_char,
455 size: usize,
456 name: *const c_char,
457 mode: *const c_char,
458) -> c_int {
459 luaL_loadbufferenv(L, data, size, name, mode, 0)
460}
461
462#[inline(always)]
463pub unsafe fn luaL_loadbuffer(
464 L: *mut lua_State,
465 data: *const c_char,
466 size: usize,
467 name: *const c_char,
468) -> c_int {
469 luaL_loadbufferenv(L, data, size, name, ptr::null(), 0)
470}
471
472#[inline(always)]
473pub unsafe fn luaL_len(L: *mut lua_State, idx: c_int) -> lua_Integer {
474 let mut isnum = 0;
475 luaL_checkstack(L, 1, cstr!("not enough stack slots available"));
476 lua_len(L, idx);
477 let res = lua_tointegerx(L, -1, &mut isnum);
478 lua_pop(L, 1);
479 if isnum == 0 {
480 luaL_error(L, cstr!("object length is not an integer"));
481 }
482 res
483}
484
485pub unsafe fn luaL_traceback(L: *mut lua_State, L1: *mut lua_State, msg: *const c_char, mut level: c_int) {
486 let mut ar: lua_Debug = mem::zeroed();
487 let numlevels = lua_stackdepth(L);
488 #[rustfmt::skip]
489 let mut limit = if numlevels - level > COMPAT53_LEVELS1 + COMPAT53_LEVELS2 { COMPAT53_LEVELS1 } else { -1 };
490
491 let mut buf: luaL_Strbuf = mem::zeroed();
492 luaL_buffinit(L, &mut buf);
493
494 if !msg.is_null() {
495 luaL_addstring(&mut buf, msg);
496 luaL_addstring(&mut buf, cstr!("\n"));
497 }
498 luaL_addstring(&mut buf, cstr!("stack traceback:"));
499 while lua_getinfo(L1, level, cstr!("sln"), &mut ar) != 0 {
500 if limit == 0 {
501 let n = numlevels - level - COMPAT53_LEVELS2;
503 lua_pushfstring(L, cstr!("\n\t...\t(skipping %d levels)"), n + 1);
505 luaL_addvalue(&mut buf);
506 level += n; } else {
508 luaL_addstring(&mut buf, cstr!("\n\t"));
509 luaL_addstring(&mut buf, ar.short_src);
510 luaL_addstring(&mut buf, cstr!(":"));
511 if ar.currentline > 0 {
512 luaL_addunsigned(&mut buf, ar.currentline as _);
513 luaL_addstring(&mut buf, cstr!(":"));
514 }
515 luaL_addstring(&mut buf, cstr!(" in "));
516 compat53_pushfuncname(L, L1, level, &mut ar);
517 luaL_addvalue(&mut buf);
518 }
519 level += 1;
520 limit -= 1;
521 }
522 luaL_pushresult(&mut buf);
523}
524
525pub unsafe fn luaL_tolstring(L: *mut lua_State, mut idx: c_int, len: *mut usize) -> *const c_char {
526 idx = lua_absindex(L, idx);
527 if luaL_callmeta(L, idx, cstr!("__tostring")) == 0 {
528 match lua_type(L, idx) {
529 LUA_TNIL => {
530 lua_pushliteral(L, c"nil");
531 }
532 LUA_TSTRING | LUA_TNUMBER => {
533 lua_pushvalue(L, idx);
534 }
535 LUA_TBOOLEAN => {
536 if lua_toboolean(L, idx) == 0 {
537 lua_pushliteral(L, c"false");
538 } else {
539 lua_pushliteral(L, c"true");
540 }
541 }
542 t => {
543 let tt = luaL_getmetafield(L, idx, cstr!("__type"));
544 let name = if tt == LUA_TSTRING {
545 lua_tostring(L, -1)
546 } else {
547 lua_typename(L, t)
548 };
549 lua_pushfstring(L, cstr!("%s: %p"), name, lua_topointer(L, idx));
550 if tt != LUA_TNIL {
551 lua_replace(L, -2); }
553 }
554 };
555 } else if lua_isstring(L, -1) == 0 {
556 luaL_error(L, cstr!("'__tostring' must return a string"));
557 }
558 lua_tolstring(L, -1, len)
559}
560
561#[inline(always)]
562pub unsafe fn luaL_setmetatable(L: *mut lua_State, tname: *const c_char) {
563 luaL_checkstack(L, 1, cstr!("not enough stack slots available"));
564 luaL_getmetatable(L, tname);
565 lua_setmetatable(L, -2);
566}
567
568pub unsafe fn luaL_getsubtable(L: *mut lua_State, idx: c_int, fname: *const c_char) -> c_int {
569 let abs_i = lua_absindex(L, idx);
570 luaL_checkstack(L, 3, cstr!("not enough stack slots available"));
571 lua_pushstring_(L, fname);
572 if lua_gettable(L, abs_i) == LUA_TTABLE {
573 return 1;
574 }
575 lua_pop(L, 1);
576 lua_newtable(L);
577 lua_pushstring_(L, fname);
578 lua_pushvalue(L, -2);
579 lua_settable(L, abs_i);
580 0
581}
582
583pub unsafe fn luaL_requiref(L: *mut lua_State, modname: *const c_char, openf: lua_CFunction, glb: c_int) {
584 luaL_checkstack(L, 3, cstr!("not enough stack slots available"));
585 luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE);
586 if lua_getfield(L, -1, modname) == LUA_TNIL {
587 lua_pop(L, 1);
588 lua_pushcfunction(L, openf);
589 lua_pushstring(L, modname);
590 lua_call(L, 1, 1);
591 lua_pushvalue(L, -1);
592 lua_setfield(L, -3, modname);
593 }
594 if glb != 0 {
595 lua_pushvalue(L, -1);
596 lua_setglobal(L, modname);
597 } else {
598 lua_pushnil(L);
599 lua_setglobal(L, modname);
600 }
601 lua_replace(L, -2);
602}