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
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 = 12; const COMPAT53_LEVELS2: c_int = 10; unsafe fn compat53_findfield(L: *mut lua_State, objidx: c_int, level: c_int) -> c_int {
28 if level == 0 || lua_istable(L, -1) == 0 {
29 return 0; }
31
32 lua_pushnil(L); while lua_next(L, -2) != 0 {
34 if lua_type(L, -2) == LUA_TSTRING {
36 if lua_rawequal(L, objidx, -1) != 0 {
38 lua_pop(L, 1); return 1;
41 } else if compat53_findfield(L, objidx, level - 1) != 0 {
42 lua_remove(L, -2); lua_pushliteral(L, ".");
45 lua_insert(L, -2); lua_concat(L, 3);
47 return 1;
48 }
49 }
50 lua_pop(L, 1); }
52 0 }
54
55unsafe fn compat53_pushglobalfuncname(L: *mut lua_State, level: c_int, ar: *mut lua_Debug) -> c_int {
56 let top = lua_gettop(L);
57 lua_getinfo(L, level, cstr!("f"), ar);
59 lua_pushvalue(L, LUA_GLOBALSINDEX);
60 if compat53_findfield(L, top + 1, 2) != 0 {
61 lua_copy(L, -1, top + 1); lua_pop(L, 2); 1
64 } else {
65 lua_settop(L, top); 0
67 }
68}
69
70unsafe fn compat53_pushfuncname(L: *mut lua_State, level: c_int, ar: *mut lua_Debug) {
71 if !(*ar).name.is_null() {
72 lua_pushfstring(L, cstr!("function '%s'"), (*ar).name);
74 } else if compat53_pushglobalfuncname(L, level, ar) != 0 {
75 lua_pushfstring(L, cstr!("function '%s'"), lua_tostring(L, -1));
76 lua_remove(L, -2); } else {
78 lua_pushliteral(L, "?");
79 }
80}
81
82pub unsafe fn lua_rotate(L: *mut lua_State, mut idx: c_int, mut n: c_int) {
87 idx = lua_absindex(L, idx);
88 if n > 0 {
89 for _ in 0..n {
91 lua_insert(L, idx);
92 }
93 return;
94 }
95 let n_elems = lua_gettop(L) - idx + 1;
96 if n < 0 {
97 n += n_elems;
98 }
99 if n > 0 && n < n_elems {
100 luaL_checkstack(L, 2, cstr!("not enough stack slots available"));
101 n = n_elems - n;
102 compat53_reverse(L, idx, idx + n - 1);
103 compat53_reverse(L, idx + n, idx + n_elems - 1);
104 compat53_reverse(L, idx, idx + n_elems - 1);
105 }
106}
107
108#[inline(always)]
109pub unsafe fn lua_copy(L: *mut lua_State, fromidx: c_int, toidx: c_int) {
110 let abs_to = lua_absindex(L, toidx);
111 luaL_checkstack(L, 1, cstr!("not enough stack slots available"));
112 lua_pushvalue(L, fromidx);
113 lua_replace(L, abs_to);
114}
115
116#[inline(always)]
117pub unsafe fn lua_isinteger(L: *mut lua_State, idx: c_int) -> c_int {
118 if lua_type(L, idx) == LUA_TNUMBER {
119 let n = lua_tonumber(L, idx);
120 let i = lua_tointeger(L, idx);
121 if (n - i as lua_Number).abs() < lua_Number::EPSILON {
122 return 1;
123 }
124 }
125 0
126}
127
128#[inline(always)]
129pub unsafe fn lua_tointeger(L: *mut lua_State, i: c_int) -> lua_Integer {
130 lua_tointegerx(L, i, ptr::null_mut())
131}
132
133pub unsafe fn lua_tointegerx(L: *mut lua_State, i: c_int, isnum: *mut c_int) -> lua_Integer {
134 let mut ok = 0;
135 let n = lua_tonumberx(L, i, &mut ok);
136 let n_int = n as lua_Integer;
137 if ok != 0 && (n - n_int as lua_Number).abs() < lua_Number::EPSILON {
138 if !isnum.is_null() {
139 *isnum = 1;
140 }
141 return n_int;
142 }
143 if !isnum.is_null() {
144 *isnum = 0;
145 }
146 0
147}
148
149#[inline(always)]
150pub unsafe fn lua_rawlen(L: *mut lua_State, idx: c_int) -> usize {
151 lua_objlen(L, idx)
152}
153
154#[inline(always)]
155pub unsafe fn lua_pushlstring(L: *mut lua_State, s: *const c_char, l: usize) -> *const c_char {
156 if l == 0 {
157 lua_pushlstring_(L, cstr!(""), 0);
158 } else {
159 lua_pushlstring_(L, s, l);
160 }
161 lua_tostring(L, -1)
162}
163
164#[inline(always)]
165pub unsafe fn lua_pushstring(L: *mut lua_State, s: *const c_char) -> *const c_char {
166 lua_pushstring_(L, s);
167 lua_tostring(L, -1)
168}
169
170#[inline(always)]
171pub unsafe fn lua_geti(L: *mut lua_State, mut idx: c_int, n: lua_Integer) -> c_int {
172 idx = lua_absindex(L, idx);
173 lua_pushinteger(L, n);
174 lua_gettable(L, idx)
175}
176
177#[inline(always)]
178pub unsafe fn lua_rawgeti(L: *mut lua_State, idx: c_int, n: lua_Integer) -> c_int {
179 lua_rawgeti_(L, idx, n)
180}
181
182#[inline(always)]
183pub unsafe fn lua_rawgetp(L: *mut lua_State, idx: c_int, p: *const c_void) -> c_int {
184 let abs_i = lua_absindex(L, idx);
185 lua_pushlightuserdata(L, p as *mut c_void);
186 lua_rawget(L, abs_i)
187}
188
189#[inline(always)]
190pub unsafe fn lua_getuservalue(L: *mut lua_State, mut idx: c_int) -> c_int {
191 luaL_checkstack(L, 2, cstr!("not enough stack slots available"));
192 idx = lua_absindex(L, idx);
193 lua_pushliteral(L, "__mlua_uservalues");
194 if lua_rawget(L, LUA_REGISTRYINDEX) != LUA_TTABLE {
195 return LUA_TNIL;
196 }
197 lua_pushvalue(L, idx);
198 lua_rawget(L, -2);
199 lua_remove(L, -2);
200 lua_type(L, -1)
201}
202
203#[inline(always)]
204pub unsafe fn lua_seti(L: *mut lua_State, mut idx: c_int, n: lua_Integer) {
205 luaL_checkstack(L, 1, cstr!("not enough stack slots available"));
206 idx = lua_absindex(L, idx);
207 lua_pushinteger(L, n);
208 lua_insert(L, -2);
209 lua_settable(L, idx);
210}
211
212#[inline(always)]
213pub unsafe fn lua_rawseti(L: *mut lua_State, idx: c_int, n: lua_Integer) {
214 lua_rawseti_(L, idx, n)
215}
216
217#[inline(always)]
218pub unsafe fn lua_rawsetp(L: *mut lua_State, idx: c_int, p: *const c_void) {
219 let abs_i = lua_absindex(L, idx);
220 luaL_checkstack(L, 1, cstr!("not enough stack slots available"));
221 lua_pushlightuserdata(L, p as *mut c_void);
222 lua_insert(L, -2);
223 lua_rawset(L, abs_i);
224}
225
226#[inline(always)]
227pub unsafe fn lua_setuservalue(L: *mut lua_State, mut idx: c_int) {
228 luaL_checkstack(L, 4, cstr!("not enough stack slots available"));
229 idx = lua_absindex(L, idx);
230 lua_pushliteral(L, "__mlua_uservalues");
231 lua_pushvalue(L, -1);
232 if lua_rawget(L, LUA_REGISTRYINDEX) != LUA_TTABLE {
233 lua_pop(L, 1);
234 lua_createtable(L, 0, 2); lua_createtable(L, 0, 1); lua_pushliteral(L, "k");
237 lua_setfield(L, -2, cstr!("__mode"));
238 lua_setmetatable(L, -2);
239 lua_pushvalue(L, -2);
240 lua_pushvalue(L, -2);
241 lua_rawset(L, LUA_REGISTRYINDEX);
242 }
243 lua_replace(L, -2);
244 lua_pushvalue(L, idx);
245 lua_pushvalue(L, -3);
246 lua_remove(L, -4);
247 lua_rawset(L, -3);
248 lua_pop(L, 1);
249}
250
251#[inline(always)]
252pub unsafe fn lua_len(L: *mut lua_State, idx: c_int) {
253 match lua_type(L, idx) {
254 LUA_TSTRING => {
255 lua_pushnumber(L, lua_objlen(L, idx) as lua_Number);
256 }
257 LUA_TTABLE => {
258 if luaL_callmeta(L, idx, cstr!("__len")) == 0 {
259 lua_pushnumber(L, lua_objlen(L, idx) as lua_Number);
260 }
261 }
262 LUA_TUSERDATA if luaL_callmeta(L, idx, cstr!("__len")) != 0 => {}
263 _ => {
264 luaL_error(
265 L,
266 cstr!("attempt to get length of a %s value"),
267 lua_typename(L, lua_type(L, idx)),
268 );
269 }
270 }
271}
272
273#[inline(always)]
274pub unsafe fn lua_pushglobaltable(L: *mut lua_State) {
275 lua_pushvalue(L, LUA_GLOBALSINDEX);
276}
277
278#[inline(always)]
279pub unsafe fn lua_resume(L: *mut lua_State, from: *mut lua_State, narg: c_int, nres: *mut c_int) -> c_int {
280 let ret = lua_resume_(L, from, narg);
281 if (ret == LUA_OK || ret == LUA_YIELD) && !(nres.is_null()) {
282 *nres = lua_gettop(L);
283 }
284 ret
285}
286
287#[inline(always)]
292pub unsafe fn luaL_checkstack(L: *mut lua_State, sz: c_int, msg: *const c_char) {
293 if lua_checkstack(L, sz + LUA_MINSTACK) == 0 {
294 if !msg.is_null() {
295 luaL_error(L, cstr!("stack overflow (%s)"), msg);
296 } else {
297 lua_pushliteral(L, "stack overflow");
298 lua_error(L);
299 }
300 }
301}
302
303#[inline(always)]
304pub unsafe fn luaL_getmetafield(L: *mut lua_State, obj: c_int, e: *const c_char) -> c_int {
305 if luaL_getmetafield_(L, obj, e) != 0 {
306 lua_type(L, -1)
307 } else {
308 LUA_TNIL
309 }
310}
311
312#[inline(always)]
313pub unsafe fn luaL_newmetatable(L: *mut lua_State, tname: *const c_char) -> c_int {
314 if luaL_newmetatable_(L, tname) != 0 {
315 lua_pushstring(L, tname);
316 lua_setfield(L, -2, cstr!("__type"));
317 1
318 } else {
319 0
320 }
321}
322
323pub unsafe fn luaL_loadbufferenv(
324 L: *mut lua_State,
325 data: *const c_char,
326 mut size: usize,
327 name: *const c_char,
328 mode: *const c_char,
329 mut env: c_int,
330) -> c_int {
331 extern "C" {
332 fn free(p: *mut c_void);
333 }
334
335 unsafe extern "C-unwind" fn data_dtor(data: *mut c_void) {
336 free(*(data as *mut *mut c_char) as *mut c_void);
337 }
338
339 let chunk_is_text = size == 0 || (*data as u8) >= b'\t';
340 if !mode.is_null() {
341 let modeb = CStr::from_ptr(mode).to_bytes();
342 if !chunk_is_text && !modeb.contains(&b'b') {
343 lua_pushfstring(L, cstr!("attempt to load a binary chunk (mode is '%s')"), mode);
344 return LUA_ERRSYNTAX;
345 } else if chunk_is_text && !modeb.contains(&b't') {
346 lua_pushfstring(L, cstr!("attempt to load a text chunk (mode is '%s')"), mode);
347 return LUA_ERRSYNTAX;
348 }
349 }
350
351 if chunk_is_text {
352 if env < 0 {
353 env -= 1;
354 }
355 let data_ud = lua_newuserdatadtor(L, mem::size_of::<*mut c_char>(), data_dtor) as *mut *mut c_char;
356 let data = luau_compile_(data, size, ptr::null_mut(), &mut size);
357 ptr::write(data_ud, data);
358 let ok = luau_load(L, name, data, size, env) == 0;
361 lua_replace(L, -2); if !ok {
363 return LUA_ERRSYNTAX;
364 }
365 } else if luau_load(L, name, data, size, env) != 0 {
366 return LUA_ERRSYNTAX;
367 }
368 LUA_OK
369}
370
371#[inline(always)]
372pub unsafe fn luaL_loadbufferx(
373 L: *mut lua_State,
374 data: *const c_char,
375 size: usize,
376 name: *const c_char,
377 mode: *const c_char,
378) -> c_int {
379 luaL_loadbufferenv(L, data, size, name, mode, 0)
380}
381
382#[inline(always)]
383pub unsafe fn luaL_loadbuffer(
384 L: *mut lua_State,
385 data: *const c_char,
386 size: usize,
387 name: *const c_char,
388) -> c_int {
389 luaL_loadbufferenv(L, data, size, name, ptr::null(), 0)
390}
391
392#[inline(always)]
393pub unsafe fn luaL_len(L: *mut lua_State, idx: c_int) -> lua_Integer {
394 let mut isnum = 0;
395 luaL_checkstack(L, 1, cstr!("not enough stack slots available"));
396 lua_len(L, idx);
397 let res = lua_tointegerx(L, -1, &mut isnum);
398 lua_pop(L, 1);
399 if isnum == 0 {
400 luaL_error(L, cstr!("object length is not an integer"));
401 }
402 res
403}
404
405pub unsafe fn luaL_traceback(L: *mut lua_State, L1: *mut lua_State, msg: *const c_char, mut level: c_int) {
406 let mut ar: lua_Debug = mem::zeroed();
407 let top = lua_gettop(L);
408 let numlevels = lua_stackdepth(L);
409 let mark = if numlevels > COMPAT53_LEVELS1 + COMPAT53_LEVELS2 {
410 COMPAT53_LEVELS1
411 } else {
412 0
413 };
414
415 if !msg.is_null() {
416 lua_pushfstring(L, cstr!("%s\n"), msg);
417 }
418 lua_pushliteral(L, "stack traceback:");
419 while lua_getinfo(L1, level, cstr!(""), &mut ar) != 0 {
420 if level + 1 == mark {
421 lua_pushliteral(L, "\n\t..."); level = numlevels - COMPAT53_LEVELS2; } else {
425 lua_getinfo(L1, level, cstr!("sln"), &mut ar);
426 lua_pushfstring(L, cstr!("\n\t%s:"), ar.short_src);
427 if ar.currentline > 0 {
428 lua_pushfstring(L, cstr!("%d:"), ar.currentline);
429 }
430 lua_pushliteral(L, " in ");
431 compat53_pushfuncname(L, level, &mut ar);
432 lua_concat(L, lua_gettop(L) - top);
433 }
434 level += 1;
435 }
436 lua_concat(L, lua_gettop(L) - top);
437}
438
439pub unsafe fn luaL_tolstring(L: *mut lua_State, mut idx: c_int, len: *mut usize) -> *const c_char {
440 idx = lua_absindex(L, idx);
441 if luaL_callmeta(L, idx, cstr!("__tostring")) == 0 {
442 match lua_type(L, idx) {
443 LUA_TNIL => {
444 lua_pushliteral(L, "nil");
445 }
446 LUA_TSTRING | LUA_TNUMBER => {
447 lua_pushvalue(L, idx);
448 }
449 LUA_TBOOLEAN => {
450 if lua_toboolean(L, idx) == 0 {
451 lua_pushliteral(L, "false");
452 } else {
453 lua_pushliteral(L, "true");
454 }
455 }
456 t => {
457 let tt = luaL_getmetafield(L, idx, cstr!("__type"));
458 let name = if tt == LUA_TSTRING {
459 lua_tostring(L, -1)
460 } else {
461 lua_typename(L, t)
462 };
463 lua_pushfstring(L, cstr!("%s: %p"), name, lua_topointer(L, idx));
464 if tt != LUA_TNIL {
465 lua_replace(L, -2); }
467 }
468 };
469 } else if lua_isstring(L, -1) == 0 {
470 luaL_error(L, cstr!("'__tostring' must return a string"));
471 }
472 lua_tolstring(L, -1, len)
473}
474
475#[inline(always)]
476pub unsafe fn luaL_setmetatable(L: *mut lua_State, tname: *const c_char) {
477 luaL_checkstack(L, 1, cstr!("not enough stack slots available"));
478 luaL_getmetatable(L, tname);
479 lua_setmetatable(L, -2);
480}
481
482pub unsafe fn luaL_getsubtable(L: *mut lua_State, idx: c_int, fname: *const c_char) -> c_int {
483 let abs_i = lua_absindex(L, idx);
484 luaL_checkstack(L, 3, cstr!("not enough stack slots available"));
485 lua_pushstring_(L, fname);
486 if lua_gettable(L, abs_i) == LUA_TTABLE {
487 return 1;
488 }
489 lua_pop(L, 1);
490 lua_newtable(L);
491 lua_pushstring_(L, fname);
492 lua_pushvalue(L, -2);
493 lua_settable(L, abs_i);
494 0
495}
496
497pub unsafe fn luaL_requiref(L: *mut lua_State, modname: *const c_char, openf: lua_CFunction, glb: c_int) {
498 luaL_checkstack(L, 3, cstr!("not enough stack slots available"));
499 luaL_getsubtable(L, LUA_REGISTRYINDEX, cstr!("_LOADED"));
500 if lua_getfield(L, -1, modname) == LUA_TNIL {
501 lua_pop(L, 1);
502 lua_pushcfunction(L, openf);
503 lua_pushstring(L, modname);
504 lua_call(L, 1, 1);
505 lua_pushvalue(L, -1);
506 lua_setfield(L, -3, modname);
507 }
508 if glb != 0 {
509 lua_pushvalue(L, -1);
510 lua_setglobal(L, modname);
511 } else {
512 lua_pushnil(L);
513 lua_setglobal(L, modname);
514 }
515 lua_replace(L, -2);
516}