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