Fix call unroll checks in the presence of metamethod frames.
[luajit-2.0.git] / src / lib_aux.c
blob05fa6b1018a04768d4b2c310cde8211b6efe671d
1 /*
2 ** Auxiliary library for the Lua/C API.
3 ** Copyright (C) 2005-2013 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"
25 #if LJ_TARGET_POSIX
26 #include <sys/wait.h>
27 #endif
29 /* -- I/O error handling -------------------------------------------------- */
31 LUALIB_API int luaL_fileresult(lua_State *L, int stat, const char *fname)
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;
49 LUALIB_API int luaL_execresult(lua_State *L, int stat)
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");
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;
76 return luaL_fileresult(L, 0, NULL);
79 /* -- Module registration ------------------------------------------------- */
81 LUALIB_API const char *luaL_findtable(lua_State *L, int idx,
82 const char *fname, int szhint)
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 */
101 lua_remove(L, -2); /* remove previous table */
102 fname = e + 1;
103 } while (*e == '.');
104 return NULL;
107 static int libsize(const luaL_Reg *l)
109 int size = 0;
110 for (; l->name; l++) size++;
111 return size;
114 LUALIB_API void luaL_openlib(lua_State *L, const char *libname,
115 const luaL_Reg *l, int nup)
117 lj_lib_checkfpu(L);
118 if (libname) {
119 int size = libsize(l);
120 /* check whether lib already exists */
121 luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 16);
122 lua_getfield(L, -1, libname); /* get _LOADED[libname] */
123 if (!lua_istable(L, -1)) { /* not found? */
124 lua_pop(L, 1); /* remove previous result */
125 /* try global variable (and create one if it does not exist) */
126 if (luaL_findtable(L, LUA_GLOBALSINDEX, libname, size) != NULL)
127 lj_err_callerv(L, LJ_ERR_BADMODN, libname);
128 lua_pushvalue(L, -1);
129 lua_setfield(L, -3, libname); /* _LOADED[libname] = new table */
131 lua_remove(L, -2); /* remove _LOADED table */
132 lua_insert(L, -(nup+1)); /* move library table to below upvalues */
134 for (; l->name; l++) {
135 int i;
136 for (i = 0; i < nup; i++) /* copy upvalues to the top */
137 lua_pushvalue(L, -nup);
138 lua_pushcclosure(L, l->func, nup);
139 lua_setfield(L, -(nup+2), l->name);
141 lua_pop(L, nup); /* remove upvalues */
144 LUALIB_API void luaL_register(lua_State *L, const char *libname,
145 const luaL_Reg *l)
147 luaL_openlib(L, libname, l, 0);
150 LUALIB_API const char *luaL_gsub(lua_State *L, const char *s,
151 const char *p, const char *r)
153 const char *wild;
154 size_t l = strlen(p);
155 luaL_Buffer b;
156 luaL_buffinit(L, &b);
157 while ((wild = strstr(s, p)) != NULL) {
158 luaL_addlstring(&b, s, (size_t)(wild - s)); /* push prefix */
159 luaL_addstring(&b, r); /* push replacement in place of pattern */
160 s = wild + l; /* continue after `p' */
162 luaL_addstring(&b, s); /* push last suffix */
163 luaL_pushresult(&b);
164 return lua_tostring(L, -1);
167 /* -- Buffer handling ----------------------------------------------------- */
169 #define bufflen(B) ((size_t)((B)->p - (B)->buffer))
170 #define bufffree(B) ((size_t)(LUAL_BUFFERSIZE - bufflen(B)))
172 static int emptybuffer(luaL_Buffer *B)
174 size_t l = bufflen(B);
175 if (l == 0)
176 return 0; /* put nothing on stack */
177 lua_pushlstring(B->L, B->buffer, l);
178 B->p = B->buffer;
179 B->lvl++;
180 return 1;
183 static void adjuststack(luaL_Buffer *B)
185 if (B->lvl > 1) {
186 lua_State *L = B->L;
187 int toget = 1; /* number of levels to concat */
188 size_t toplen = lua_strlen(L, -1);
189 do {
190 size_t l = lua_strlen(L, -(toget+1));
191 if (!(B->lvl - toget + 1 >= LUA_MINSTACK/2 || toplen > l))
192 break;
193 toplen += l;
194 toget++;
195 } while (toget < B->lvl);
196 lua_concat(L, toget);
197 B->lvl = B->lvl - toget + 1;
201 LUALIB_API char *luaL_prepbuffer(luaL_Buffer *B)
203 if (emptybuffer(B))
204 adjuststack(B);
205 return B->buffer;
208 LUALIB_API void luaL_addlstring(luaL_Buffer *B, const char *s, size_t l)
210 while (l--)
211 luaL_addchar(B, *s++);
214 LUALIB_API void luaL_addstring(luaL_Buffer *B, const char *s)
216 luaL_addlstring(B, s, strlen(s));
219 LUALIB_API void luaL_pushresult(luaL_Buffer *B)
221 emptybuffer(B);
222 lua_concat(B->L, B->lvl);
223 B->lvl = 1;
226 LUALIB_API void luaL_addvalue(luaL_Buffer *B)
228 lua_State *L = B->L;
229 size_t vl;
230 const char *s = lua_tolstring(L, -1, &vl);
231 if (vl <= bufffree(B)) { /* fit into buffer? */
232 memcpy(B->p, s, vl); /* put it there */
233 B->p += vl;
234 lua_pop(L, 1); /* remove from stack */
235 } else {
236 if (emptybuffer(B))
237 lua_insert(L, -2); /* put buffer before new value */
238 B->lvl++; /* add new value into B stack */
239 adjuststack(B);
243 LUALIB_API void luaL_buffinit(lua_State *L, luaL_Buffer *B)
245 B->L = L;
246 B->p = B->buffer;
247 B->lvl = 0;
250 /* -- Reference management ------------------------------------------------ */
252 #define FREELIST_REF 0
254 /* Convert a stack index to an absolute index. */
255 #define abs_index(L, i) \
256 ((i) > 0 || (i) <= LUA_REGISTRYINDEX ? (i) : lua_gettop(L) + (i) + 1)
258 LUALIB_API int luaL_ref(lua_State *L, int t)
260 int ref;
261 t = abs_index(L, t);
262 if (lua_isnil(L, -1)) {
263 lua_pop(L, 1); /* remove from stack */
264 return LUA_REFNIL; /* `nil' has a unique fixed reference */
266 lua_rawgeti(L, t, FREELIST_REF); /* get first free element */
267 ref = (int)lua_tointeger(L, -1); /* ref = t[FREELIST_REF] */
268 lua_pop(L, 1); /* remove it from stack */
269 if (ref != 0) { /* any free element? */
270 lua_rawgeti(L, t, ref); /* remove it from list */
271 lua_rawseti(L, t, FREELIST_REF); /* (t[FREELIST_REF] = t[ref]) */
272 } else { /* no free elements */
273 ref = (int)lua_objlen(L, t);
274 ref++; /* create new reference */
276 lua_rawseti(L, t, ref);
277 return ref;
280 LUALIB_API void luaL_unref(lua_State *L, int t, int ref)
282 if (ref >= 0) {
283 t = abs_index(L, t);
284 lua_rawgeti(L, t, FREELIST_REF);
285 lua_rawseti(L, t, ref); /* t[ref] = t[FREELIST_REF] */
286 lua_pushinteger(L, ref);
287 lua_rawseti(L, t, FREELIST_REF); /* t[FREELIST_REF] = ref */
291 /* -- Default allocator and panic function -------------------------------- */
293 static int panic(lua_State *L)
295 const char *s = lua_tostring(L, -1);
296 fputs("PANIC: unprotected error in call to Lua API (", stderr);
297 fputs(s ? s : "?", stderr);
298 fputc(')', stderr); fputc('\n', stderr);
299 fflush(stderr);
300 return 0;
303 #ifdef LUAJIT_USE_SYSMALLOC
305 #if LJ_64
306 #error "Must use builtin allocator for 64 bit target"
307 #endif
309 static void *mem_alloc(void *ud, void *ptr, size_t osize, size_t nsize)
311 (void)ud;
312 (void)osize;
313 if (nsize == 0) {
314 free(ptr);
315 return NULL;
316 } else {
317 return realloc(ptr, nsize);
321 LUALIB_API lua_State *luaL_newstate(void)
323 lua_State *L = lua_newstate(mem_alloc, NULL);
324 if (L) G(L)->panic = panic;
325 return L;
328 #else
330 #include "lj_alloc.h"
332 LUALIB_API lua_State *luaL_newstate(void)
334 lua_State *L;
335 void *ud = lj_alloc_create();
336 if (ud == NULL) return NULL;
337 #if LJ_64
338 L = lj_state_newstate(lj_alloc_f, ud);
339 #else
340 L = lua_newstate(lj_alloc_f, ud);
341 #endif
342 if (L) G(L)->panic = panic;
343 return L;
346 #if LJ_64
347 LUA_API lua_State *lua_newstate(lua_Alloc f, void *ud)
349 UNUSED(f); UNUSED(ud);
350 fputs("Must use luaL_newstate() for 64 bit target\n", stderr);
351 return NULL;
353 #endif
355 #endif