1/*
2** Auxiliary library for the Lua/C API.
3** Copyright (C) 2005-2014 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->name; l++) size++;
111 return size;
112}
113
114LUALIB_API void luaL_openlib(lua_State *L, const char *libname,
115 const luaL_Reg *l, int nup)
116{
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 */
130 }
131 lua_remove(L, -2); /* remove _LOADED table */
132 lua_insert(L, -(nup+1)); /* move library table to below upvalues */
133 }
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);
140 }
141 lua_pop(L, nup); /* remove upvalues */
142}
143
144LUALIB_API void luaL_register(lua_State *L, const char *libname,
145 const luaL_Reg *l)
146{
147 luaL_openlib(L, libname, l, 0);
148}
149
150LUALIB_API const char *luaL_gsub(lua_State *L, const char *s,
151 const char *p, const char *r)
152{
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' */
161 }
162 luaL_addstring(&b, s); /* push last suffix */
163 luaL_pushresult(&b);
164 return lua_tostring(L, -1);
165}
166
167/* -- Buffer handling ----------------------------------------------------- */
168
169#define bufflen(B) ((size_t)((B)->p - (B)->buffer))
170#define bufffree(B) ((size_t)(LUAL_BUFFERSIZE - bufflen(B)))
171
172static int emptybuffer(luaL_Buffer *B)
173{
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;
181}
182
183static void adjuststack(luaL_Buffer *B)
184{
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;
198 }
199}
200
201LUALIB_API char *luaL_prepbuffer(luaL_Buffer *B)
202{
203 if (emptybuffer(B))
204 adjuststack(B);
205 return B->buffer;
206}
207
208LUALIB_API void luaL_addlstring(luaL_Buffer *B, const char *s, size_t l)
209{
210 while (l--)
211 luaL_addchar(B, *s++);
212}
213
214LUALIB_API void luaL_addstring(luaL_Buffer *B, const char *s)
215{
216 luaL_addlstring(B, s, strlen(s));
217}
218
219LUALIB_API void luaL_pushresult(luaL_Buffer *B)
220{
221 emptybuffer(B);
222 lua_concat(B->L, B->lvl);
223 B->lvl = 1;
224}
225
226LUALIB_API void luaL_addvalue(luaL_Buffer *B)
227{
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);
240 }
241}
242
243LUALIB_API void luaL_buffinit(lua_State *L, luaL_Buffer *B)
244{
245 B->L = L;
246 B->p = B->buffer;
247 B->lvl = 0;
248}
249
250/* -- Reference management ------------------------------------------------ */
251
252#define FREELIST_REF 0
253
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)
257
258LUALIB_API int luaL_ref(lua_State *L, int t)
259{
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 */
265 }
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 */
275 }
276 lua_rawseti(L, t, ref);
277 return ref;
278}
279
280LUALIB_API void luaL_unref(lua_State *L, int t, int ref)
281{
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 */
288 }
289}
290
291/* -- Default allocator and panic function -------------------------------- */
292
293static int panic(lua_State *L)
294{
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;
301}
302
303#ifdef LUAJIT_USE_SYSMALLOC
304
305#if LJ_64
306#error "Must use builtin allocator for 64 bit target"
307#endif
308
309static void *mem_alloc(void *ud, void *ptr, size_t osize, size_t nsize)
310{
311 (void)ud;
312 (void)osize;
313 if (nsize == 0) {
314 free(ptr);
315 return NULL;
316 } else {
317 return realloc(ptr, nsize);
318 }
319}
320
321LUALIB_API lua_State *luaL_newstate(void)
322{
323 lua_State *L = lua_newstate(mem_alloc, NULL);
324 if (L) G(L)->panic = panic;
325 return L;
326}
327
328#else
329
330#include "lj_alloc.h"
331
332LUALIB_API lua_State *luaL_newstate(void)
333{
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;
344}
345
346#if LJ_64
347LUA_API lua_State *lua_newstate(lua_Alloc f, void *ud)
348{
349 UNUSED(f); UNUSED(ud);
350 fputs("Must use luaL_newstate() for 64 bit target\n", stderr);
351 return NULL;
352}
353#endif
354
355#endif
356
357