OSX/iOS: Fix SDK incompatibility.
[luajit-2.0.git] / src / lib_aux.c
blob7e81ac302eeec0bdf624f71d3111125ab90003a1
1 /*
2 ** Auxiliary library for the Lua/C API.
3 ** Copyright (C) 2005-2023 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 */
9 #include <errno.h>
10 #include <stdarg.h>
11 #include <stdio.h>
13 #define lib_aux_c
14 #define LUA_LIB
16 #include "lua.h"
17 #include "lauxlib.h"
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 #include "lj_vmevent.h"
26 #if LJ_TARGET_POSIX
27 #include <sys/wait.h>
28 #endif
30 /* -- I/O error handling -------------------------------------------------- */
32 LUALIB_API int luaL_fileresult(lua_State *L, int stat, const char *fname)
34 if (stat) {
35 setboolV(L->top++, 1);
36 return 1;
37 } else {
38 int en = errno; /* Lua API calls may change this value. */
39 setnilV(L->top++);
40 if (fname)
41 lua_pushfstring(L, "%s: %s", fname, strerror(en));
42 else
43 lua_pushfstring(L, "%s", strerror(en));
44 setintV(L->top++, en);
45 lj_trace_abort(G(L));
46 return 3;
50 LUALIB_API int luaL_execresult(lua_State *L, int stat)
52 if (stat != -1) {
53 #if LJ_TARGET_POSIX
54 if (WIFSIGNALED(stat)) {
55 stat = WTERMSIG(stat);
56 setnilV(L->top++);
57 lua_pushliteral(L, "signal");
58 } else {
59 if (WIFEXITED(stat))
60 stat = WEXITSTATUS(stat);
61 if (stat == 0)
62 setboolV(L->top++, 1);
63 else
64 setnilV(L->top++);
65 lua_pushliteral(L, "exit");
67 #else
68 if (stat == 0)
69 setboolV(L->top++, 1);
70 else
71 setnilV(L->top++);
72 lua_pushliteral(L, "exit");
73 #endif
74 setintV(L->top++, stat);
75 return 3;
77 return luaL_fileresult(L, 0, NULL);
80 /* -- Module registration ------------------------------------------------- */
82 LUALIB_API const char *luaL_findtable(lua_State *L, int idx,
83 const char *fname, int szhint)
85 const char *e;
86 lua_pushvalue(L, idx);
87 do {
88 e = strchr(fname, '.');
89 if (e == NULL) e = fname + strlen(fname);
90 lua_pushlstring(L, fname, (size_t)(e - fname));
91 lua_rawget(L, -2);
92 if (lua_isnil(L, -1)) { /* no such field? */
93 lua_pop(L, 1); /* remove this nil */
94 lua_createtable(L, 0, (*e == '.' ? 1 : szhint)); /* new table for field */
95 lua_pushlstring(L, fname, (size_t)(e - fname));
96 lua_pushvalue(L, -2);
97 lua_settable(L, -4); /* set new table into field */
98 } else if (!lua_istable(L, -1)) { /* field has a non-table value? */
99 lua_pop(L, 2); /* remove table and value */
100 return fname; /* return problematic part of the name */
102 lua_remove(L, -2); /* remove previous table */
103 fname = e + 1;
104 } while (*e == '.');
105 return NULL;
108 static int libsize(const luaL_Reg *l)
110 int size = 0;
111 for (; l && l->name; l++) size++;
112 return size;
115 LUALIB_API void luaL_pushmodule(lua_State *L, const char *modname, int sizehint)
117 luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 16);
118 lua_getfield(L, -1, modname);
119 if (!lua_istable(L, -1)) {
120 lua_pop(L, 1);
121 if (luaL_findtable(L, LUA_GLOBALSINDEX, modname, sizehint) != NULL)
122 lj_err_callerv(L, LJ_ERR_BADMODN, modname);
123 lua_pushvalue(L, -1);
124 lua_setfield(L, -3, modname); /* _LOADED[modname] = new table. */
126 lua_remove(L, -2); /* Remove _LOADED table. */
129 LUALIB_API void luaL_openlib(lua_State *L, const char *libname,
130 const luaL_Reg *l, int nup)
132 lj_lib_checkfpu(L);
133 if (libname) {
134 luaL_pushmodule(L, libname, libsize(l));
135 lua_insert(L, -(nup + 1)); /* Move module table below upvalues. */
137 if (l)
138 luaL_setfuncs(L, l, nup);
139 else
140 lua_pop(L, nup); /* Remove upvalues. */
143 LUALIB_API void luaL_register(lua_State *L, const char *libname,
144 const luaL_Reg *l)
146 luaL_openlib(L, libname, l, 0);
149 LUALIB_API void luaL_setfuncs(lua_State *L, const luaL_Reg *l, int nup)
151 luaL_checkstack(L, nup, "too many upvalues");
152 for (; l->name; l++) {
153 int i;
154 for (i = 0; i < nup; i++) /* Copy upvalues to the top. */
155 lua_pushvalue(L, -nup);
156 lua_pushcclosure(L, l->func, nup);
157 lua_setfield(L, -(nup + 2), l->name);
159 lua_pop(L, nup); /* Remove upvalues. */
162 LUALIB_API const char *luaL_gsub(lua_State *L, const char *s,
163 const char *p, const char *r)
165 const char *wild;
166 size_t l = strlen(p);
167 luaL_Buffer b;
168 luaL_buffinit(L, &b);
169 while ((wild = strstr(s, p)) != NULL) {
170 luaL_addlstring(&b, s, (size_t)(wild - s)); /* push prefix */
171 luaL_addstring(&b, r); /* push replacement in place of pattern */
172 s = wild + l; /* continue after `p' */
174 luaL_addstring(&b, s); /* push last suffix */
175 luaL_pushresult(&b);
176 return lua_tostring(L, -1);
179 /* -- Buffer handling ----------------------------------------------------- */
181 #define bufflen(B) ((size_t)((B)->p - (B)->buffer))
182 #define bufffree(B) ((size_t)(LUAL_BUFFERSIZE - bufflen(B)))
184 static int emptybuffer(luaL_Buffer *B)
186 size_t l = bufflen(B);
187 if (l == 0)
188 return 0; /* put nothing on stack */
189 lua_pushlstring(B->L, B->buffer, l);
190 B->p = B->buffer;
191 B->lvl++;
192 return 1;
195 static void adjuststack(luaL_Buffer *B)
197 if (B->lvl > 1) {
198 lua_State *L = B->L;
199 int toget = 1; /* number of levels to concat */
200 size_t toplen = lua_strlen(L, -1);
201 do {
202 size_t l = lua_strlen(L, -(toget+1));
203 if (!(B->lvl - toget + 1 >= LUA_MINSTACK/2 || toplen > l))
204 break;
205 toplen += l;
206 toget++;
207 } while (toget < B->lvl);
208 lua_concat(L, toget);
209 B->lvl = B->lvl - toget + 1;
213 LUALIB_API char *luaL_prepbuffer(luaL_Buffer *B)
215 if (emptybuffer(B))
216 adjuststack(B);
217 return B->buffer;
220 LUALIB_API void luaL_addlstring(luaL_Buffer *B, const char *s, size_t l)
222 if (l <= bufffree(B)) {
223 memcpy(B->p, s, l);
224 B->p += l;
225 } else {
226 emptybuffer(B);
227 lua_pushlstring(B->L, s, l);
228 B->lvl++;
229 adjuststack(B);
233 LUALIB_API void luaL_addstring(luaL_Buffer *B, const char *s)
235 luaL_addlstring(B, s, strlen(s));
238 LUALIB_API void luaL_pushresult(luaL_Buffer *B)
240 emptybuffer(B);
241 lua_concat(B->L, B->lvl);
242 B->lvl = 1;
245 LUALIB_API void luaL_addvalue(luaL_Buffer *B)
247 lua_State *L = B->L;
248 size_t vl;
249 const char *s = lua_tolstring(L, -1, &vl);
250 if (vl <= bufffree(B)) { /* fit into buffer? */
251 memcpy(B->p, s, vl); /* put it there */
252 B->p += vl;
253 lua_pop(L, 1); /* remove from stack */
254 } else {
255 if (emptybuffer(B))
256 lua_insert(L, -2); /* put buffer before new value */
257 B->lvl++; /* add new value into B stack */
258 adjuststack(B);
262 LUALIB_API void luaL_buffinit(lua_State *L, luaL_Buffer *B)
264 B->L = L;
265 B->p = B->buffer;
266 B->lvl = 0;
269 /* -- Reference management ------------------------------------------------ */
271 #define FREELIST_REF 0
273 /* Convert a stack index to an absolute index. */
274 #define abs_index(L, i) \
275 ((i) > 0 || (i) <= LUA_REGISTRYINDEX ? (i) : lua_gettop(L) + (i) + 1)
277 LUALIB_API int luaL_ref(lua_State *L, int t)
279 int ref;
280 t = abs_index(L, t);
281 if (lua_isnil(L, -1)) {
282 lua_pop(L, 1); /* remove from stack */
283 return LUA_REFNIL; /* `nil' has a unique fixed reference */
285 lua_rawgeti(L, t, FREELIST_REF); /* get first free element */
286 ref = (int)lua_tointeger(L, -1); /* ref = t[FREELIST_REF] */
287 lua_pop(L, 1); /* remove it from stack */
288 if (ref != 0) { /* any free element? */
289 lua_rawgeti(L, t, ref); /* remove it from list */
290 lua_rawseti(L, t, FREELIST_REF); /* (t[FREELIST_REF] = t[ref]) */
291 } else { /* no free elements */
292 ref = (int)lua_objlen(L, t);
293 ref++; /* create new reference */
295 lua_rawseti(L, t, ref);
296 return ref;
299 LUALIB_API void luaL_unref(lua_State *L, int t, int ref)
301 if (ref >= 0) {
302 t = abs_index(L, t);
303 lua_rawgeti(L, t, FREELIST_REF);
304 lua_rawseti(L, t, ref); /* t[ref] = t[FREELIST_REF] */
305 lua_pushinteger(L, ref);
306 lua_rawseti(L, t, FREELIST_REF); /* t[FREELIST_REF] = ref */
310 /* -- Default allocator and panic function -------------------------------- */
312 static int panic(lua_State *L)
314 const char *s = lua_tostring(L, -1);
315 fputs("PANIC: unprotected error in call to Lua API (", stderr);
316 fputs(s ? s : "?", stderr);
317 fputc(')', stderr); fputc('\n', stderr);
318 fflush(stderr);
319 return 0;
322 #ifndef LUAJIT_DISABLE_VMEVENT
323 static int error_finalizer(lua_State *L)
325 const char *s = lua_tostring(L, -1);
326 fputs("ERROR in finalizer: ", stderr);
327 fputs(s ? s : "?", stderr);
328 fputc('\n', stderr);
329 fflush(stderr);
330 return 0;
332 #endif
334 #ifdef LUAJIT_USE_SYSMALLOC
336 #if LJ_64 && !LJ_GC64 && !defined(LUAJIT_USE_VALGRIND)
337 #error "Must use builtin allocator for 64 bit target"
338 #endif
340 static void *mem_alloc(void *ud, void *ptr, size_t osize, size_t nsize)
342 (void)ud;
343 (void)osize;
344 if (nsize == 0) {
345 free(ptr);
346 return NULL;
347 } else {
348 return realloc(ptr, nsize);
352 LUALIB_API lua_State *luaL_newstate(void)
354 lua_State *L = lua_newstate(mem_alloc, NULL);
355 if (L) {
356 G(L)->panic = panic;
357 #ifndef LUAJIT_DISABLE_VMEVENT
358 luaL_findtable(L, LUA_REGISTRYINDEX, LJ_VMEVENTS_REGKEY, LJ_VMEVENTS_HSIZE);
359 lua_pushcfunction(L, error_finalizer);
360 lua_rawseti(L, -2, VMEVENT_HASH(LJ_VMEVENT_ERRFIN));
361 G(L)->vmevmask = VMEVENT_MASK(LJ_VMEVENT_ERRFIN);
362 L->top--;
363 #endif
365 return L;
368 #else
370 LUALIB_API lua_State *luaL_newstate(void)
372 lua_State *L;
373 #if LJ_64 && !LJ_GC64
374 L = lj_state_newstate(LJ_ALLOCF_INTERNAL, NULL);
375 #else
376 L = lua_newstate(LJ_ALLOCF_INTERNAL, NULL);
377 #endif
378 if (L) {
379 G(L)->panic = panic;
380 #ifndef LUAJIT_DISABLE_VMEVENT
381 luaL_findtable(L, LUA_REGISTRYINDEX, LJ_VMEVENTS_REGKEY, LJ_VMEVENTS_HSIZE);
382 lua_pushcfunction(L, error_finalizer);
383 lua_rawseti(L, -2, VMEVENT_HASH(LJ_VMEVENT_ERRFIN));
384 G(L)->vmevmask = VMEVENT_MASK(LJ_VMEVENT_ERRFIN);
385 L->top--;
386 #endif
388 return L;
391 #if LJ_64 && !LJ_GC64
392 LUA_API lua_State *lua_newstate(lua_Alloc f, void *ud)
394 UNUSED(f); UNUSED(ud);
395 fputs("Must use luaL_newstate() for 64 bit target\n", stderr);
396 return NULL;
398 #endif
400 #endif