1/*
2** Auxiliary library for the Lua/C API.
3** Copyright (C) 2005-2021 Mike Pall. See Copyright Notice in luajit.h
4**
5** Major parts taken verbatim or adapted from the Lua interpreter.
6** Copyright (C) 1994-2008 Lua.org, PUC-Rio. See Copyright Notice in lua.h
7*/
8
9#include <errno.h>
10#include <stdarg.h>
11#include <stdio.h>
12
13#define lib_aux_c
14#define LUA_LIB
15
16#include "lua.h"
17#include "lauxlib.h"
18
19#include "lj_obj.h"
20#include "lj_err.h"
21#include "lj_state.h"
22#include "lj_trace.h"
23#include "lj_lib.h"
24
25#if LJ_TARGET_POSIX
26#include <sys/wait.h>
27#endif
28
29/* -- I/O error handling -------------------------------------------------- */
30
31LUALIB_API int luaL_fileresult(lua_State *L, int stat, const char *fname)
32{
33 if (stat) {
34 setboolV(L->top++, 1);
35 return 1;
36 } else {
37 int en = errno; /* Lua API calls may change this value. */
38 setnilV(L->top++);
39 if (fname)
40 lua_pushfstring(L, "%s: %s", fname, strerror(en));
41 else
42 lua_pushfstring(L, "%s", strerror(en));
43 setintV(L->top++, en);
44 lj_trace_abort(G(L));
45 return 3;
46 }
47}
48
49LUALIB_API int luaL_execresult(lua_State *L, int stat)
50{
51 if (stat != -1) {
52#if LJ_TARGET_POSIX
53 if (WIFSIGNALED(stat)) {
54 stat = WTERMSIG(stat);
55 setnilV(L->top++);
56 lua_pushliteral(L, "signal");
57 } else {
58 if (WIFEXITED(stat))
59 stat = WEXITSTATUS(stat);
60 if (stat == 0)
61 setboolV(L->top++, 1);
62 else
63 setnilV(L->top++);
64 lua_pushliteral(L, "exit");
65 }
66#else
67 if (stat == 0)
68 setboolV(L->top++, 1);
69 else
70 setnilV(L->top++);
71 lua_pushliteral(L, "exit");
72#endif
73 setintV(L->top++, stat);
74 return 3;
75 }
76 return luaL_fileresult(L, 0, NULL);
77}
78
79/* -- Module registration ------------------------------------------------- */
80
81LUALIB_API const char *luaL_findtable(lua_State *L, int idx,
82 const char *fname, int szhint)
83{
84 const char *e;
85 lua_pushvalue(L, idx);
86 do {
87 e = strchr(fname, '.');
88 if (e == NULL) e = fname + strlen(fname);
89 lua_pushlstring(L, fname, (size_t)(e - fname));
90 lua_rawget(L, -2);
91 if (lua_isnil(L, -1)) { /* no such field? */
92 lua_pop(L, 1); /* remove this nil */
93 lua_createtable(L, 0, (*e == '.' ? 1 : szhint)); /* new table for field */
94 lua_pushlstring(L, fname, (size_t)(e - fname));
95 lua_pushvalue(L, -2);
96 lua_settable(L, -4); /* set new table into field */
97 } else if (!lua_istable(L, -1)) { /* field has a non-table value? */
98 lua_pop(L, 2); /* remove table and value */
99 return fname; /* return problematic part of the name */
100 }
101 lua_remove(L, -2); /* remove previous table */
102 fname = e + 1;
103 } while (*e == '.');
104 return NULL;
105}
106
107static int libsize(const luaL_Reg *l)
108{
109 int size = 0;
110 for (; l && l->name; l++) size++;
111 return size;
112}
113
114LUALIB_API void luaL_pushmodule(lua_State *L, const char *modname, int sizehint)
115{
116 luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 16);
117 lua_getfield(L, -1, modname);
118 if (!lua_istable(L, -1)) {
119 lua_pop(L, 1);
120 if (luaL_findtable(L, LUA_GLOBALSINDEX, modname, sizehint) != NULL)
121 lj_err_callerv(L, LJ_ERR_BADMODN, modname);
122 lua_pushvalue(L, -1);
123 lua_setfield(L, -3, modname); /* _LOADED[modname] = new table. */
124 }
125 lua_remove(L, -2); /* Remove _LOADED table. */
126}
127
128LUALIB_API void luaL_openlib(lua_State *L, const char *libname,
129 const luaL_Reg *l, int nup)
130{
131 lj_lib_checkfpu(L);
132 if (libname) {
133 luaL_pushmodule(L, libname, libsize(l));
134 lua_insert(L, -(nup + 1)); /* Move module table below upvalues. */
135 }
136 if (l)
137 luaL_setfuncs(L, l, nup);
138 else
139 lua_pop(L, nup); /* Remove upvalues. */
140}
141
142LUALIB_API void luaL_register(lua_State *L, const char *libname,
143 const luaL_Reg *l)
144{
145 luaL_openlib(L, libname, l, 0);
146}
147
148LUALIB_API void luaL_setfuncs(lua_State *L, const luaL_Reg *l, int nup)
149{
150 luaL_checkstack(L, nup, "too many upvalues");
151 for (; l->name; l++) {
152 int i;
153 for (i = 0; i < nup; i++) /* Copy upvalues to the top. */
154 lua_pushvalue(L, -nup);
155 lua_pushcclosure(L, l->func, nup);
156 lua_setfield(L, -(nup + 2), l->name);
157 }
158 lua_pop(L, nup); /* Remove upvalues. */
159}
160
161LUALIB_API const char *luaL_gsub(lua_State *L, const char *s,
162 const char *p, const char *r)
163{
164 const char *wild;
165 size_t l = strlen(p);
166 luaL_Buffer b;
167 luaL_buffinit(L, &b);
168 while ((wild = strstr(s, p)) != NULL) {
169 luaL_addlstring(&b, s, (size_t)(wild - s)); /* push prefix */
170 luaL_addstring(&b, r); /* push replacement in place of pattern */
171 s = wild + l; /* continue after `p' */
172 }
173 luaL_addstring(&b, s); /* push last suffix */
174 luaL_pushresult(&b);
175 return lua_tostring(L, -1);
176}
177
178/* -- Buffer handling ----------------------------------------------------- */
179
180#define bufflen(B) ((size_t)((B)->p - (B)->buffer))
181#define bufffree(B) ((size_t)(LUAL_BUFFERSIZE - bufflen(B)))
182
183static int emptybuffer(luaL_Buffer *B)
184{
185 size_t l = bufflen(B);
186 if (l == 0)
187 return 0; /* put nothing on stack */
188 lua_pushlstring(B->L, B->buffer, l);
189 B->p = B->buffer;
190 B->lvl++;
191 return 1;
192}
193
194static void adjuststack(luaL_Buffer *B)
195{
196 if (B->lvl > 1) {
197 lua_State *L = B->L;
198 int toget = 1; /* number of levels to concat */
199 size_t toplen = lua_strlen(L, -1);
200 do {
201 size_t l = lua_strlen(L, -(toget+1));
202 if (!(B->lvl - toget + 1 >= LUA_MINSTACK/2 || toplen > l))
203 break;
204 toplen += l;
205 toget++;
206 } while (toget < B->lvl);
207 lua_concat(L, toget);
208 B->lvl = B->lvl - toget + 1;
209 }
210}
211
212LUALIB_API char *luaL_prepbuffer(luaL_Buffer *B)
213{
214 if (emptybuffer(B))
215 adjuststack(B);
216 return B->buffer;
217}
218
219LUALIB_API void luaL_addlstring(luaL_Buffer *B, const char *s, size_t l)
220{
221 if (l <= bufffree(B)) {
222 memcpy(B->p, s, l);
223 B->p += l;
224 } else {
225 emptybuffer(B);
226 lua_pushlstring(B->L, s, l);
227 B->lvl++;
228 adjuststack(B);
229 }
230}
231
232LUALIB_API void luaL_addstring(luaL_Buffer *B, const char *s)
233{
234 luaL_addlstring(B, s, strlen(s));
235}
236
237LUALIB_API void luaL_pushresult(luaL_Buffer *B)
238{
239 emptybuffer(B);
240 lua_concat(B->L, B->lvl);
241 B->lvl = 1;
242}
243
244LUALIB_API void luaL_addvalue(luaL_Buffer *B)
245{
246 lua_State *L = B->L;
247 size_t vl;
248 const char *s = lua_tolstring(L, -1, &vl);
249 if (vl <= bufffree(B)) { /* fit into buffer? */
250 memcpy(B->p, s, vl); /* put it there */
251 B->p += vl;
252 lua_pop(L, 1); /* remove from stack */
253 } else {
254 if (emptybuffer(B))
255 lua_insert(L, -2); /* put buffer before new value */
256 B->lvl++; /* add new value into B stack */
257 adjuststack(B);
258 }
259}
260
261LUALIB_API void luaL_buffinit(lua_State *L, luaL_Buffer *B)
262{
263 B->L = L;
264 B->p = B->buffer;
265 B->lvl = 0;
266}
267
268/* -- Reference management ------------------------------------------------ */
269
270#define FREELIST_REF 0
271
272/* Convert a stack index to an absolute index. */
273#define abs_index(L, i) \
274 ((i) > 0 || (i) <= LUA_REGISTRYINDEX ? (i) : lua_gettop(L) + (i) + 1)
275
276LUALIB_API int luaL_ref(lua_State *L, int t)
277{
278 int ref;
279 t = abs_index(L, t);
280 if (lua_isnil(L, -1)) {
281 lua_pop(L, 1); /* remove from stack */
282 return LUA_REFNIL; /* `nil' has a unique fixed reference */
283 }
284 lua_rawgeti(L, t, FREELIST_REF); /* get first free element */
285 ref = (int)lua_tointeger(L, -1); /* ref = t[FREELIST_REF] */
286 lua_pop(L, 1); /* remove it from stack */
287 if (ref != 0) { /* any free element? */
288 lua_rawgeti(L, t, ref); /* remove it from list */
289 lua_rawseti(L, t, FREELIST_REF); /* (t[FREELIST_REF] = t[ref]) */
290 } else { /* no free elements */
291 ref = (int)lua_objlen(L, t);
292 ref++; /* create new reference */
293 }
294 lua_rawseti(L, t, ref);
295 return ref;
296}
297
298LUALIB_API void luaL_unref(lua_State *L, int t, int ref)
299{
300 if (ref >= 0) {
301 t = abs_index(L, t);
302 lua_rawgeti(L, t, FREELIST_REF);
303 lua_rawseti(L, t, ref); /* t[ref] = t[FREELIST_REF] */
304 lua_pushinteger(L, ref);
305 lua_rawseti(L, t, FREELIST_REF); /* t[FREELIST_REF] = ref */
306 }
307}
308
309/* -- Default allocator and panic function -------------------------------- */
310
311static int panic(lua_State *L)
312{
313 const char *s = lua_tostring(L, -1);
314 fputs("PANIC: unprotected error in call to Lua API (", stderr);
315 fputs(s ? s : "?", stderr);
316 fputc(')', stderr); fputc('\n', stderr);
317 fflush(stderr);
318 return 0;
319}
320
321#ifdef LUAJIT_USE_SYSMALLOC
322
323#if LJ_64 && !LJ_GC64 && !defined(LUAJIT_USE_VALGRIND)
324#error "Must use builtin allocator for 64 bit target"
325#endif
326
327static void *mem_alloc(void *ud, void *ptr, size_t osize, size_t nsize)
328{
329 (void)ud;
330 (void)osize;
331 if (nsize == 0) {
332 free(ptr);
333 return NULL;
334 } else {
335 return realloc(ptr, nsize);
336 }
337}
338
339LUALIB_API lua_State *luaL_newstate(void)
340{
341 lua_State *L = lua_newstate(mem_alloc, NULL);
342 if (L) G(L)->panic = panic;
343 return L;
344}
345
346#else
347
348LUALIB_API lua_State *luaL_newstate(void)
349{
350 lua_State *L;
351#if LJ_64 && !LJ_GC64
352 L = lj_state_newstate(LJ_ALLOCF_INTERNAL, NULL);
353#else
354 L = lua_newstate(LJ_ALLOCF_INTERNAL, NULL);
355#endif
356 if (L) G(L)->panic = panic;
357 return L;
358}
359
360#if LJ_64 && !LJ_GC64
361LUA_API lua_State *lua_newstate(lua_Alloc f, void *ud)
362{
363 UNUSED(f); UNUSED(ud);
364 fputs("Must use luaL_newstate() for 64 bit target\n", stderr);
365 return NULL;
366}
367#endif
368
369#endif
370
371