|
|
|
@ -1,9 +1,14 @@
|
|
|
|
|
/*
|
|
|
|
|
** $Id: lauxlib.c,v 1.248.1.1 2013/04/12 18:48:47 roberto Exp $
|
|
|
|
|
** $Id: lauxlib.c,v 1.286 2016/01/08 15:33:09 roberto Exp $
|
|
|
|
|
** Auxiliary functions for building Lua libraries
|
|
|
|
|
** See Copyright Notice in lua.h
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#define lauxlib_c
|
|
|
|
|
#define LUA_LIB
|
|
|
|
|
|
|
|
|
|
#include "lprefix.h"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
#include <stdarg.h>
|
|
|
|
@ -12,13 +17,11 @@
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* This file uses only the official API of Lua.
|
|
|
|
|
/*
|
|
|
|
|
** This file uses only the official API of Lua.
|
|
|
|
|
** Any function declared here could be written as an application function.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#define lauxlib_c
|
|
|
|
|
#define LUA_LIB
|
|
|
|
|
|
|
|
|
|
#include "lua.h"
|
|
|
|
|
|
|
|
|
|
#include "lauxlib.h"
|
|
|
|
@ -31,8 +34,8 @@
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define LEVELS1 12 /* size of the first part of the stack */
|
|
|
|
|
#define LEVELS2 10 /* size of the second part of the stack */
|
|
|
|
|
#define LEVELS1 10 /* size of the first part of the stack */
|
|
|
|
|
#define LEVELS2 11 /* size of the second part of the stack */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -64,11 +67,20 @@ static int findfield (lua_State *L, int objidx, int level) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
** Search for a name for a function in all loaded modules
|
|
|
|
|
** (registry._LOADED).
|
|
|
|
|
*/
|
|
|
|
|
static int pushglobalfuncname (lua_State *L, lua_Debug *ar) {
|
|
|
|
|
int top = lua_gettop(L);
|
|
|
|
|
lua_getinfo(L, "f", ar); /* push function */
|
|
|
|
|
lua_pushglobaltable(L);
|
|
|
|
|
lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED");
|
|
|
|
|
if (findfield(L, top + 1, 2)) {
|
|
|
|
|
const char *name = lua_tostring(L, -1);
|
|
|
|
|
if (strncmp(name, "_G.", 3) == 0) { /* name start with '_G.'? */
|
|
|
|
|
lua_pushstring(L, name + 3); /* push name without prefix */
|
|
|
|
|
lua_remove(L, -2); /* remove original name */
|
|
|
|
|
}
|
|
|
|
|
lua_copy(L, -1, top + 1); /* move name to proper place */
|
|
|
|
|
lua_pop(L, 2); /* remove pushed values */
|
|
|
|
|
return 1;
|
|
|
|
@ -81,24 +93,22 @@ static int pushglobalfuncname (lua_State *L, lua_Debug *ar) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void pushfuncname (lua_State *L, lua_Debug *ar) {
|
|
|
|
|
if (*ar->namewhat != '\0') /* is there a name? */
|
|
|
|
|
lua_pushfstring(L, "function " LUA_QS, ar->name);
|
|
|
|
|
else if (*ar->what == 'm') /* main? */
|
|
|
|
|
lua_pushliteral(L, "main chunk");
|
|
|
|
|
else if (*ar->what == 'C') {
|
|
|
|
|
if (pushglobalfuncname(L, ar)) {
|
|
|
|
|
lua_pushfstring(L, "function " LUA_QS, lua_tostring(L, -1));
|
|
|
|
|
if (pushglobalfuncname(L, ar)) { /* try first a global name */
|
|
|
|
|
lua_pushfstring(L, "function '%s'", lua_tostring(L, -1));
|
|
|
|
|
lua_remove(L, -2); /* remove name */
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
lua_pushliteral(L, "?");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
else if (*ar->namewhat != '\0') /* is there a name from code? */
|
|
|
|
|
lua_pushfstring(L, "%s '%s'", ar->namewhat, ar->name); /* use it */
|
|
|
|
|
else if (*ar->what == 'm') /* main? */
|
|
|
|
|
lua_pushliteral(L, "main chunk");
|
|
|
|
|
else if (*ar->what != 'C') /* for Lua functions, use <file:line> */
|
|
|
|
|
lua_pushfstring(L, "function <%s:%d>", ar->short_src, ar->linedefined);
|
|
|
|
|
else /* nothing left... */
|
|
|
|
|
lua_pushliteral(L, "?");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int countlevels (lua_State *L) {
|
|
|
|
|
static int lastlevel (lua_State *L) {
|
|
|
|
|
lua_Debug ar;
|
|
|
|
|
int li = 1, le = 1;
|
|
|
|
|
/* find an upper bound */
|
|
|
|
@ -117,14 +127,16 @@ LUALIB_API void luaL_traceback (lua_State *L, lua_State *L1,
|
|
|
|
|
const char *msg, int level) {
|
|
|
|
|
lua_Debug ar;
|
|
|
|
|
int top = lua_gettop(L);
|
|
|
|
|
int numlevels = countlevels(L1);
|
|
|
|
|
int mark = (numlevels > LEVELS1 + LEVELS2) ? LEVELS1 : 0;
|
|
|
|
|
if (msg) lua_pushfstring(L, "%s\n", msg);
|
|
|
|
|
int last = lastlevel(L1);
|
|
|
|
|
int n1 = (last - level > LEVELS1 + LEVELS2) ? LEVELS1 : -1;
|
|
|
|
|
if (msg)
|
|
|
|
|
lua_pushfstring(L, "%s\n", msg);
|
|
|
|
|
luaL_checkstack(L, 10, NULL);
|
|
|
|
|
lua_pushliteral(L, "stack traceback:");
|
|
|
|
|
while (lua_getstack(L1, level++, &ar)) {
|
|
|
|
|
if (level == mark) { /* too many levels? */
|
|
|
|
|
if (n1-- == 0) { /* too many levels? */
|
|
|
|
|
lua_pushliteral(L, "\n\t..."); /* add a '...' */
|
|
|
|
|
level = numlevels - LEVELS2; /* and skip to last ones */
|
|
|
|
|
level = last - LEVELS2 + 1; /* and skip to last ones */
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
lua_getinfo(L1, "Slnt", &ar);
|
|
|
|
@ -150,36 +162,47 @@ LUALIB_API void luaL_traceback (lua_State *L, lua_State *L1,
|
|
|
|
|
** =======================================================
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
LUALIB_API int luaL_argerror (lua_State *L, int narg, const char *extramsg) {
|
|
|
|
|
LUALIB_API int luaL_argerror (lua_State *L, int arg, const char *extramsg) {
|
|
|
|
|
lua_Debug ar;
|
|
|
|
|
if (!lua_getstack(L, 0, &ar)) /* no stack frame? */
|
|
|
|
|
return luaL_error(L, "bad argument #%d (%s)", narg, extramsg);
|
|
|
|
|
return luaL_error(L, "bad argument #%d (%s)", arg, extramsg);
|
|
|
|
|
lua_getinfo(L, "n", &ar);
|
|
|
|
|
if (strcmp(ar.namewhat, "method") == 0) {
|
|
|
|
|
narg--; /* do not count `self' */
|
|
|
|
|
if (narg == 0) /* error is in the self argument itself? */
|
|
|
|
|
return luaL_error(L, "calling " LUA_QS " on bad self (%s)",
|
|
|
|
|
arg--; /* do not count 'self' */
|
|
|
|
|
if (arg == 0) /* error is in the self argument itself? */
|
|
|
|
|
return luaL_error(L, "calling '%s' on bad self (%s)",
|
|
|
|
|
ar.name, extramsg);
|
|
|
|
|
}
|
|
|
|
|
if (ar.name == NULL)
|
|
|
|
|
ar.name = (pushglobalfuncname(L, &ar)) ? lua_tostring(L, -1) : "?";
|
|
|
|
|
return luaL_error(L, "bad argument #%d to " LUA_QS " (%s)",
|
|
|
|
|
narg, ar.name, extramsg);
|
|
|
|
|
return luaL_error(L, "bad argument #%d to '%s' (%s)",
|
|
|
|
|
arg, ar.name, extramsg);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int typeerror (lua_State *L, int narg, const char *tname) {
|
|
|
|
|
const char *msg = lua_pushfstring(L, "%s expected, got %s",
|
|
|
|
|
tname, luaL_typename(L, narg));
|
|
|
|
|
return luaL_argerror(L, narg, msg);
|
|
|
|
|
static int typeerror (lua_State *L, int arg, const char *tname) {
|
|
|
|
|
const char *msg;
|
|
|
|
|
const char *typearg; /* name for the type of the actual argument */
|
|
|
|
|
if (luaL_getmetafield(L, arg, "__name") == LUA_TSTRING)
|
|
|
|
|
typearg = lua_tostring(L, -1); /* use the given type name */
|
|
|
|
|
else if (lua_type(L, arg) == LUA_TLIGHTUSERDATA)
|
|
|
|
|
typearg = "light userdata"; /* special name for messages */
|
|
|
|
|
else
|
|
|
|
|
typearg = luaL_typename(L, arg); /* standard name */
|
|
|
|
|
msg = lua_pushfstring(L, "%s expected, got %s", tname, typearg);
|
|
|
|
|
return luaL_argerror(L, arg, msg);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void tag_error (lua_State *L, int narg, int tag) {
|
|
|
|
|
typeerror(L, narg, lua_typename(L, tag));
|
|
|
|
|
static void tag_error (lua_State *L, int arg, int tag) {
|
|
|
|
|
typeerror(L, arg, lua_typename(L, tag));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
** The use of 'lua_pushfstring' ensures this function does not
|
|
|
|
|
** need reserved stack space when called.
|
|
|
|
|
*/
|
|
|
|
|
LUALIB_API void luaL_where (lua_State *L, int level) {
|
|
|
|
|
lua_Debug ar;
|
|
|
|
|
if (lua_getstack(L, level, &ar)) { /* check function at level */
|
|
|
|
@ -189,10 +212,15 @@ LUALIB_API void luaL_where (lua_State *L, int level) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
lua_pushliteral(L, ""); /* else, no information available... */
|
|
|
|
|
lua_pushfstring(L, ""); /* else, no information available... */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
** Again, the use of 'lua_pushvfstring' ensures this function does
|
|
|
|
|
** not need reserved stack space when called. (At worst, it generates
|
|
|
|
|
** an error with "stack overflow" instead of the given message.)
|
|
|
|
|
*/
|
|
|
|
|
LUALIB_API int luaL_error (lua_State *L, const char *fmt, ...) {
|
|
|
|
|
va_list argp;
|
|
|
|
|
va_start(argp, fmt);
|
|
|
|
@ -222,7 +250,7 @@ LUALIB_API int luaL_fileresult (lua_State *L, int stat, const char *fname) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#if !defined(inspectstat) /* { */
|
|
|
|
|
#if !defined(l_inspectstat) /* { */
|
|
|
|
|
|
|
|
|
|
#if defined(LUA_USE_POSIX)
|
|
|
|
|
|
|
|
|
@ -231,13 +259,13 @@ LUALIB_API int luaL_fileresult (lua_State *L, int stat, const char *fname) {
|
|
|
|
|
/*
|
|
|
|
|
** use appropriate macros to interpret 'pclose' return status
|
|
|
|
|
*/
|
|
|
|
|
#define inspectstat(stat,what) \
|
|
|
|
|
#define l_inspectstat(stat,what) \
|
|
|
|
|
if (WIFEXITED(stat)) { stat = WEXITSTATUS(stat); } \
|
|
|
|
|
else if (WIFSIGNALED(stat)) { stat = WTERMSIG(stat); what = "signal"; }
|
|
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
|
|
#define inspectstat(stat,what) /* no op */
|
|
|
|
|
#define l_inspectstat(stat,what) /* no op */
|
|
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
@ -249,7 +277,7 @@ LUALIB_API int luaL_execresult (lua_State *L, int stat) {
|
|
|
|
|
if (stat == -1) /* error? */
|
|
|
|
|
return luaL_fileresult(L, 0, NULL);
|
|
|
|
|
else {
|
|
|
|
|
inspectstat(stat, what); /* interpret result */
|
|
|
|
|
l_inspectstat(stat, what); /* interpret result */
|
|
|
|
|
if (*what == 'e' && stat == 0) /* successful termination? */
|
|
|
|
|
lua_pushboolean(L, 1);
|
|
|
|
|
else
|
|
|
|
@ -270,11 +298,12 @@ LUALIB_API int luaL_execresult (lua_State *L, int stat) {
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
LUALIB_API int luaL_newmetatable (lua_State *L, const char *tname) {
|
|
|
|
|
luaL_getmetatable(L, tname); /* try to get metatable */
|
|
|
|
|
if (!lua_isnil(L, -1)) /* name already in use? */
|
|
|
|
|
if (luaL_getmetatable(L, tname) != LUA_TNIL) /* name already in use? */
|
|
|
|
|
return 0; /* leave previous value on top, but return 0 */
|
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
lua_newtable(L); /* create metatable */
|
|
|
|
|
lua_createtable(L, 0, 2); /* create metatable */
|
|
|
|
|
lua_pushstring(L, tname);
|
|
|
|
|
lua_setfield(L, -2, "__name"); /* metatable.__name = tname */
|
|
|
|
|
lua_pushvalue(L, -1);
|
|
|
|
|
lua_setfield(L, LUA_REGISTRYINDEX, tname); /* registry.name = metatable */
|
|
|
|
|
return 1;
|
|
|
|
@ -317,23 +346,28 @@ LUALIB_API void *luaL_checkudata (lua_State *L, int ud, const char *tname) {
|
|
|
|
|
** =======================================================
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
LUALIB_API int luaL_checkoption (lua_State *L, int narg, const char *def,
|
|
|
|
|
LUALIB_API int luaL_checkoption (lua_State *L, int arg, const char *def,
|
|
|
|
|
const char *const lst[]) {
|
|
|
|
|
const char *name = (def) ? luaL_optstring(L, narg, def) :
|
|
|
|
|
luaL_checkstring(L, narg);
|
|
|
|
|
const char *name = (def) ? luaL_optstring(L, arg, def) :
|
|
|
|
|
luaL_checkstring(L, arg);
|
|
|
|
|
int i;
|
|
|
|
|
for (i=0; lst[i]; i++)
|
|
|
|
|
if (strcmp(lst[i], name) == 0)
|
|
|
|
|
return i;
|
|
|
|
|
return luaL_argerror(L, narg,
|
|
|
|
|
lua_pushfstring(L, "invalid option " LUA_QS, name));
|
|
|
|
|
return luaL_argerror(L, arg,
|
|
|
|
|
lua_pushfstring(L, "invalid option '%s'", name));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
** Ensures the stack has at least 'space' extra slots, raising an error
|
|
|
|
|
** if it cannot fulfill the request. (The error handling needs a few
|
|
|
|
|
** extra slots to format the error message. In case of an error without
|
|
|
|
|
** this extra space, Lua will generate the same 'stack overflow' error,
|
|
|
|
|
** but without 'msg'.)
|
|
|
|
|
*/
|
|
|
|
|
LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *msg) {
|
|
|
|
|
/* keep some extra space to run error routines, if needed */
|
|
|
|
|
const int extra = LUA_MINSTACK;
|
|
|
|
|
if (!lua_checkstack(L, space + extra)) {
|
|
|
|
|
if (!lua_checkstack(L, space)) {
|
|
|
|
|
if (msg)
|
|
|
|
|
luaL_error(L, "stack overflow (%s)", msg);
|
|
|
|
|
else
|
|
|
|
@ -342,77 +376,71 @@ LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *msg) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
LUALIB_API void luaL_checktype (lua_State *L, int narg, int t) {
|
|
|
|
|
if (lua_type(L, narg) != t)
|
|
|
|
|
tag_error(L, narg, t);
|
|
|
|
|
LUALIB_API void luaL_checktype (lua_State *L, int arg, int t) {
|
|
|
|
|
if (lua_type(L, arg) != t)
|
|
|
|
|
tag_error(L, arg, t);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
LUALIB_API void luaL_checkany (lua_State *L, int narg) {
|
|
|
|
|
if (lua_type(L, narg) == LUA_TNONE)
|
|
|
|
|
luaL_argerror(L, narg, "value expected");
|
|
|
|
|
LUALIB_API void luaL_checkany (lua_State *L, int arg) {
|
|
|
|
|
if (lua_type(L, arg) == LUA_TNONE)
|
|
|
|
|
luaL_argerror(L, arg, "value expected");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
LUALIB_API const char *luaL_checklstring (lua_State *L, int narg, size_t *len) {
|
|
|
|
|
const char *s = lua_tolstring(L, narg, len);
|
|
|
|
|
if (!s) tag_error(L, narg, LUA_TSTRING);
|
|
|
|
|
LUALIB_API const char *luaL_checklstring (lua_State *L, int arg, size_t *len) {
|
|
|
|
|
const char *s = lua_tolstring(L, arg, len);
|
|
|
|
|
if (!s) tag_error(L, arg, LUA_TSTRING);
|
|
|
|
|
return s;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
LUALIB_API const char *luaL_optlstring (lua_State *L, int narg,
|
|
|
|
|
LUALIB_API const char *luaL_optlstring (lua_State *L, int arg,
|
|
|
|
|
const char *def, size_t *len) {
|
|
|
|
|
if (lua_isnoneornil(L, narg)) {
|
|
|
|
|
if (lua_isnoneornil(L, arg)) {
|
|
|
|
|
if (len)
|
|
|
|
|
*len = (def ? strlen(def) : 0);
|
|
|
|
|
return def;
|
|
|
|
|
}
|
|
|
|
|
else return luaL_checklstring(L, narg, len);
|
|
|
|
|
else return luaL_checklstring(L, arg, len);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
LUALIB_API lua_Number luaL_checknumber (lua_State *L, int narg) {
|
|
|
|
|
LUALIB_API lua_Number luaL_checknumber (lua_State *L, int arg) {
|
|
|
|
|
int isnum;
|
|
|
|
|
lua_Number d = lua_tonumberx(L, narg, &isnum);
|
|
|
|
|
lua_Number d = lua_tonumberx(L, arg, &isnum);
|
|
|
|
|
if (!isnum)
|
|
|
|
|
tag_error(L, narg, LUA_TNUMBER);
|
|
|
|
|
tag_error(L, arg, LUA_TNUMBER);
|
|
|
|
|
return d;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
LUALIB_API lua_Number luaL_optnumber (lua_State *L, int narg, lua_Number def) {
|
|
|
|
|
return luaL_opt(L, luaL_checknumber, narg, def);
|
|
|
|
|
LUALIB_API lua_Number luaL_optnumber (lua_State *L, int arg, lua_Number def) {
|
|
|
|
|
return luaL_opt(L, luaL_checknumber, arg, def);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
LUALIB_API lua_Integer luaL_checkinteger (lua_State *L, int narg) {
|
|
|
|
|
int isnum;
|
|
|
|
|
lua_Integer d = lua_tointegerx(L, narg, &isnum);
|
|
|
|
|
if (!isnum)
|
|
|
|
|
tag_error(L, narg, LUA_TNUMBER);
|
|
|
|
|
return d;
|
|
|
|
|
static void interror (lua_State *L, int arg) {
|
|
|
|
|
if (lua_isnumber(L, arg))
|
|
|
|
|
luaL_argerror(L, arg, "number has no integer representation");
|
|
|
|
|
else
|
|
|
|
|
tag_error(L, arg, LUA_TNUMBER);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
LUALIB_API lua_Unsigned luaL_checkunsigned (lua_State *L, int narg) {
|
|
|
|
|
LUALIB_API lua_Integer luaL_checkinteger (lua_State *L, int arg) {
|
|
|
|
|
int isnum;
|
|
|
|
|
lua_Unsigned d = lua_tounsignedx(L, narg, &isnum);
|
|
|
|
|
if (!isnum)
|
|
|
|
|
tag_error(L, narg, LUA_TNUMBER);
|
|
|
|
|
lua_Integer d = lua_tointegerx(L, arg, &isnum);
|
|
|
|
|
if (!isnum) {
|
|
|
|
|
interror(L, arg);
|
|
|
|
|
}
|
|
|
|
|
return d;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
LUALIB_API lua_Integer luaL_optinteger (lua_State *L, int narg,
|
|
|
|
|
LUALIB_API lua_Integer luaL_optinteger (lua_State *L, int arg,
|
|
|
|
|
lua_Integer def) {
|
|
|
|
|
return luaL_opt(L, luaL_checkinteger, narg, def);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
LUALIB_API lua_Unsigned luaL_optunsigned (lua_State *L, int narg,
|
|
|
|
|
lua_Unsigned def) {
|
|
|
|
|
return luaL_opt(L, luaL_checkunsigned, narg, def);
|
|
|
|
|
return luaL_opt(L, luaL_checkinteger, arg, def);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* }====================================================== */
|
|
|
|
@ -424,6 +452,47 @@ LUALIB_API lua_Unsigned luaL_optunsigned (lua_State *L, int narg,
|
|
|
|
|
** =======================================================
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* userdata to box arbitrary data */
|
|
|
|
|
typedef struct UBox {
|
|
|
|
|
void *box;
|
|
|
|
|
size_t bsize;
|
|
|
|
|
} UBox;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void *resizebox (lua_State *L, int idx, size_t newsize) {
|
|
|
|
|
void *ud;
|
|
|
|
|
lua_Alloc allocf = lua_getallocf(L, &ud);
|
|
|
|
|
UBox *box = (UBox *)lua_touserdata(L, idx);
|
|
|
|
|
void *temp = allocf(ud, box->box, box->bsize, newsize);
|
|
|
|
|
if (temp == NULL && newsize > 0) { /* allocation error? */
|
|
|
|
|
resizebox(L, idx, 0); /* free buffer */
|
|
|
|
|
luaL_error(L, "not enough memory for buffer allocation");
|
|
|
|
|
}
|
|
|
|
|
box->box = temp;
|
|
|
|
|
box->bsize = newsize;
|
|
|
|
|
return temp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int boxgc (lua_State *L) {
|
|
|
|
|
resizebox(L, 1, 0);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void *newbox (lua_State *L, size_t newsize) {
|
|
|
|
|
UBox *box = (UBox *)lua_newuserdata(L, sizeof(UBox));
|
|
|
|
|
box->box = NULL;
|
|
|
|
|
box->bsize = 0;
|
|
|
|
|
if (luaL_newmetatable(L, "LUABOX")) { /* creating metatable? */
|
|
|
|
|
lua_pushcfunction(L, boxgc);
|
|
|
|
|
lua_setfield(L, -2, "__gc"); /* metatable.__gc = boxgc */
|
|
|
|
|
}
|
|
|
|
|
lua_setmetatable(L, -2);
|
|
|
|
|
return resizebox(L, -1, newsize);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
** check whether buffer is using a userdata on the stack as a temporary
|
|
|
|
|
** buffer
|
|
|
|
@ -444,11 +513,12 @@ LUALIB_API char *luaL_prepbuffsize (luaL_Buffer *B, size_t sz) {
|
|
|
|
|
if (newsize < B->n || newsize - B->n < sz)
|
|
|
|
|
luaL_error(L, "buffer too large");
|
|
|
|
|
/* create larger buffer */
|
|
|
|
|
newbuff = (char *)lua_newuserdata(L, newsize * sizeof(char));
|
|
|
|
|
/* move content to new buffer */
|
|
|
|
|
memcpy(newbuff, B->b, B->n * sizeof(char));
|
|
|
|
|
if (buffonstack(B))
|
|
|
|
|
lua_remove(L, -2); /* remove old buffer */
|
|
|
|
|
newbuff = (char *)resizebox(L, -1, newsize);
|
|
|
|
|
else { /* no buffer yet */
|
|
|
|
|
newbuff = (char *)newbox(L, newsize);
|
|
|
|
|
memcpy(newbuff, B->b, B->n * sizeof(char)); /* copy original content */
|
|
|
|
|
}
|
|
|
|
|
B->b = newbuff;
|
|
|
|
|
B->size = newsize;
|
|
|
|
|
}
|
|
|
|
@ -457,10 +527,12 @@ LUALIB_API char *luaL_prepbuffsize (luaL_Buffer *B, size_t sz) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
LUALIB_API void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l) {
|
|
|
|
|
if (l > 0) { /* avoid 'memcpy' when 's' can be NULL */
|
|
|
|
|
char *b = luaL_prepbuffsize(B, l);
|
|
|
|
|
memcpy(b, s, l * sizeof(char));
|
|
|
|
|
luaL_addsize(B, l);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
LUALIB_API void luaL_addstring (luaL_Buffer *B, const char *s) {
|
|
|
|
@ -471,8 +543,10 @@ LUALIB_API void luaL_addstring (luaL_Buffer *B, const char *s) {
|
|
|
|
|
LUALIB_API void luaL_pushresult (luaL_Buffer *B) {
|
|
|
|
|
lua_State *L = B->L;
|
|
|
|
|
lua_pushlstring(L, B->b, B->n);
|
|
|
|
|
if (buffonstack(B))
|
|
|
|
|
lua_remove(L, -2); /* remove old buffer */
|
|
|
|
|
if (buffonstack(B)) {
|
|
|
|
|
resizebox(L, -2, 0); /* delete old buffer */
|
|
|
|
|
lua_remove(L, -2); /* remove its header from the stack */
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -523,7 +597,7 @@ LUALIB_API int luaL_ref (lua_State *L, int t) {
|
|
|
|
|
int ref;
|
|
|
|
|
if (lua_isnil(L, -1)) {
|
|
|
|
|
lua_pop(L, 1); /* remove from stack */
|
|
|
|
|
return LUA_REFNIL; /* `nil' has a unique fixed reference */
|
|
|
|
|
return LUA_REFNIL; /* 'nil' has a unique fixed reference */
|
|
|
|
|
}
|
|
|
|
|
t = lua_absindex(L, t);
|
|
|
|
|
lua_rawgeti(L, t, freelist); /* get first free element */
|
|
|
|
@ -562,7 +636,7 @@ LUALIB_API void luaL_unref (lua_State *L, int t, int ref) {
|
|
|
|
|
typedef struct LoadF {
|
|
|
|
|
int n; /* number of pre-read characters */
|
|
|
|
|
FILE *f; /* file being read */
|
|
|
|
|
char buff[LUAL_BUFFERSIZE]; /* area for reading file */
|
|
|
|
|
char buff[BUFSIZ]; /* area for reading file */
|
|
|
|
|
} LoadF;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -594,7 +668,7 @@ static int errfile (lua_State *L, const char *what, int fnameindex) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int skipBOM (LoadF *lf) {
|
|
|
|
|
const char *p = "\xEF\xBB\xBF"; /* Utf8 BOM mark */
|
|
|
|
|
const char *p = "\xEF\xBB\xBF"; /* UTF-8 BOM mark */
|
|
|
|
|
int c;
|
|
|
|
|
lf->n = 0;
|
|
|
|
|
do {
|
|
|
|
@ -655,7 +729,7 @@ LUALIB_API int luaL_loadfilex (lua_State *L, const char *filename,
|
|
|
|
|
readstatus = ferror(lf.f);
|
|
|
|
|
if (filename) fclose(lf.f); /* close file (even in case of errors) */
|
|
|
|
|
if (readstatus) {
|
|
|
|
|
lua_settop(L, fnameindex); /* ignore results from `lua_load' */
|
|
|
|
|
lua_settop(L, fnameindex); /* ignore results from 'lua_load' */
|
|
|
|
|
return errfile(L, "read", fnameindex);
|
|
|
|
|
}
|
|
|
|
|
lua_remove(L, fnameindex);
|
|
|
|
@ -698,23 +772,23 @@ LUALIB_API int luaL_loadstring (lua_State *L, const char *s) {
|
|
|
|
|
|
|
|
|
|
LUALIB_API int luaL_getmetafield (lua_State *L, int obj, const char *event) {
|
|
|
|
|
if (!lua_getmetatable(L, obj)) /* no metatable? */
|
|
|
|
|
return 0;
|
|
|
|
|
return LUA_TNIL;
|
|
|
|
|
else {
|
|
|
|
|
int tt;
|
|
|
|
|
lua_pushstring(L, event);
|
|
|
|
|
lua_rawget(L, -2);
|
|
|
|
|
if (lua_isnil(L, -1)) {
|
|
|
|
|
tt = lua_rawget(L, -2);
|
|
|
|
|
if (tt == LUA_TNIL) /* is metafield nil? */
|
|
|
|
|
lua_pop(L, 2); /* remove metatable and metafield */
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
else
|
|
|
|
|
lua_remove(L, -2); /* remove only metatable */
|
|
|
|
|
return 1;
|
|
|
|
|
return tt; /* return metafield type */
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
LUALIB_API int luaL_callmeta (lua_State *L, int obj, const char *event) {
|
|
|
|
|
obj = lua_absindex(L, obj);
|
|
|
|
|
if (!luaL_getmetafield(L, obj, event)) /* no metafield? */
|
|
|
|
|
if (luaL_getmetafield(L, obj, event) == LUA_TNIL) /* no metafield? */
|
|
|
|
|
return 0;
|
|
|
|
|
lua_pushvalue(L, obj);
|
|
|
|
|
lua_call(L, 1, 1);
|
|
|
|
@ -722,13 +796,13 @@ LUALIB_API int luaL_callmeta (lua_State *L, int obj, const char *event) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
LUALIB_API int luaL_len (lua_State *L, int idx) {
|
|
|
|
|
int l;
|
|
|
|
|
LUALIB_API lua_Integer luaL_len (lua_State *L, int idx) {
|
|
|
|
|
lua_Integer l;
|
|
|
|
|
int isnum;
|
|
|
|
|
lua_len(L, idx);
|
|
|
|
|
l = (int)lua_tointegerx(L, -1, &isnum);
|
|
|
|
|
l = lua_tointegerx(L, -1, &isnum);
|
|
|
|
|
if (!isnum)
|
|
|
|
|
luaL_error(L, "object length is not a number");
|
|
|
|
|
luaL_error(L, "object length is not an integer");
|
|
|
|
|
lua_pop(L, 1); /* remove object */
|
|
|
|
|
return l;
|
|
|
|
|
}
|
|
|
|
@ -737,7 +811,13 @@ LUALIB_API int luaL_len (lua_State *L, int idx) {
|
|
|
|
|
LUALIB_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len) {
|
|
|
|
|
if (!luaL_callmeta(L, idx, "__tostring")) { /* no metafield? */
|
|
|
|
|
switch (lua_type(L, idx)) {
|
|
|
|
|
case LUA_TNUMBER:
|
|
|
|
|
case LUA_TNUMBER: {
|
|
|
|
|
if (lua_isinteger(L, idx))
|
|
|
|
|
lua_pushfstring(L, "%I", lua_tointeger(L, idx));
|
|
|
|
|
else
|
|
|
|
|
lua_pushfstring(L, "%f", lua_tonumber(L, idx));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case LUA_TSTRING:
|
|
|
|
|
lua_pushvalue(L, idx);
|
|
|
|
|
break;
|
|
|
|
@ -772,8 +852,7 @@ static const char *luaL_findtable (lua_State *L, int idx,
|
|
|
|
|
e = strchr(fname, '.');
|
|
|
|
|
if (e == NULL) e = fname + strlen(fname);
|
|
|
|
|
lua_pushlstring(L, fname, e - fname);
|
|
|
|
|
lua_rawget(L, -2);
|
|
|
|
|
if (lua_isnil(L, -1)) { /* no such field? */
|
|
|
|
|
if (lua_rawget(L, -2) == LUA_TNIL) { /* no such field? */
|
|
|
|
|
lua_pop(L, 1); /* remove this nil */
|
|
|
|
|
lua_createtable(L, 0, (*e == '.' ? 1 : szhint)); /* new table for field */
|
|
|
|
|
lua_pushlstring(L, fname, e - fname);
|
|
|
|
@ -810,13 +889,12 @@ static int libsize (const luaL_Reg *l) {
|
|
|
|
|
LUALIB_API void luaL_pushmodule (lua_State *L, const char *modname,
|
|
|
|
|
int sizehint) {
|
|
|
|
|
luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 1); /* get _LOADED table */
|
|
|
|
|
lua_getfield(L, -1, modname); /* get _LOADED[modname] */
|
|
|
|
|
if (!lua_istable(L, -1)) { /* not found? */
|
|
|
|
|
if (lua_getfield(L, -1, modname) != LUA_TTABLE) { /* no _LOADED[modname]? */
|
|
|
|
|
lua_pop(L, 1); /* remove previous result */
|
|
|
|
|
/* try global variable (and create one if it does not exist) */
|
|
|
|
|
lua_pushglobaltable(L);
|
|
|
|
|
if (luaL_findtable(L, 0, modname, sizehint) != NULL)
|
|
|
|
|
luaL_error(L, "name conflict for module " LUA_QS, modname);
|
|
|
|
|
luaL_error(L, "name conflict for module '%s'", modname);
|
|
|
|
|
lua_pushvalue(L, -1);
|
|
|
|
|
lua_setfield(L, -3, modname); /* _LOADED[modname] = new table */
|
|
|
|
|
}
|
|
|
|
@ -846,7 +924,6 @@ LUALIB_API void luaL_openlib (lua_State *L, const char *libname,
|
|
|
|
|
** Returns with only the table at the stack.
|
|
|
|
|
*/
|
|
|
|
|
LUALIB_API void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) {
|
|
|
|
|
luaL_checkversion(L);
|
|
|
|
|
luaL_checkstack(L, nup, "too many upvalues");
|
|
|
|
|
for (; l->name != NULL; l++) { /* fill the table with given functions */
|
|
|
|
|
int i;
|
|
|
|
@ -864,8 +941,8 @@ LUALIB_API void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) {
|
|
|
|
|
** into the stack
|
|
|
|
|
*/
|
|
|
|
|
LUALIB_API int luaL_getsubtable (lua_State *L, int idx, const char *fname) {
|
|
|
|
|
lua_getfield(L, idx, fname);
|
|
|
|
|
if (lua_istable(L, -1)) return 1; /* table already there */
|
|
|
|
|
if (lua_getfield(L, idx, fname) == LUA_TTABLE)
|
|
|
|
|
return 1; /* table already there */
|
|
|
|
|
else {
|
|
|
|
|
lua_pop(L, 1); /* remove previous result */
|
|
|
|
|
idx = lua_absindex(L, idx);
|
|
|
|
@ -878,22 +955,26 @@ LUALIB_API int luaL_getsubtable (lua_State *L, int idx, const char *fname) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
** stripped-down 'require'. Calls 'openf' to open a module,
|
|
|
|
|
** registers the result in 'package.loaded' table and, if 'glb'
|
|
|
|
|
** is true, also registers the result in the global table.
|
|
|
|
|
** Stripped-down 'require': After checking "loaded" table, calls 'openf'
|
|
|
|
|
** to open a module, registers the result in 'package.loaded' table and,
|
|
|
|
|
** if 'glb' is true, also registers the result in the global table.
|
|
|
|
|
** Leaves resulting module on the top.
|
|
|
|
|
*/
|
|
|
|
|
LUALIB_API void luaL_requiref (lua_State *L, const char *modname,
|
|
|
|
|
lua_CFunction openf, int glb) {
|
|
|
|
|
luaL_getsubtable(L, LUA_REGISTRYINDEX, "_LOADED");
|
|
|
|
|
lua_getfield(L, -1, modname); /* _LOADED[modname] */
|
|
|
|
|
if (!lua_toboolean(L, -1)) { /* package not already loaded? */
|
|
|
|
|
lua_pop(L, 1); /* remove field */
|
|
|
|
|
lua_pushcfunction(L, openf);
|
|
|
|
|
lua_pushstring(L, modname); /* argument to open function */
|
|
|
|
|
lua_call(L, 1, 1); /* open module */
|
|
|
|
|
luaL_getsubtable(L, LUA_REGISTRYINDEX, "_LOADED");
|
|
|
|
|
lua_pushvalue(L, -2); /* make copy of module (call result) */
|
|
|
|
|
lua_setfield(L, -2, modname); /* _LOADED[modname] = module */
|
|
|
|
|
lua_pop(L, 1); /* remove _LOADED table */
|
|
|
|
|
lua_call(L, 1, 1); /* call 'openf' to open module */
|
|
|
|
|
lua_pushvalue(L, -1); /* make copy of module (call result) */
|
|
|
|
|
lua_setfield(L, -3, modname); /* _LOADED[modname] = module */
|
|
|
|
|
}
|
|
|
|
|
lua_remove(L, -2); /* remove _LOADED table */
|
|
|
|
|
if (glb) {
|
|
|
|
|
lua_pushvalue(L, -1); /* copy of 'mod' */
|
|
|
|
|
lua_pushvalue(L, -1); /* copy of module */
|
|
|
|
|
lua_setglobal(L, modname); /* _G[modname] = module */
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -908,7 +989,7 @@ LUALIB_API const char *luaL_gsub (lua_State *L, const char *s, const char *p,
|
|
|
|
|
while ((wild = strstr(s, p)) != NULL) {
|
|
|
|
|
luaL_addlstring(&b, s, wild - s); /* push prefix */
|
|
|
|
|
luaL_addstring(&b, r); /* push replacement in place of pattern */
|
|
|
|
|
s = wild + l; /* continue after `p' */
|
|
|
|
|
s = wild + l; /* continue after 'p' */
|
|
|
|
|
}
|
|
|
|
|
luaL_addstring(&b, s); /* push last suffix */
|
|
|
|
|
luaL_pushresult(&b);
|
|
|
|
@ -928,7 +1009,7 @@ static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int panic (lua_State *L) {
|
|
|
|
|
luai_writestringerror("PANIC: unprotected error in call to Lua API (%s)\n",
|
|
|
|
|
lua_writestringerror("PANIC: unprotected error in call to Lua API (%s)\n",
|
|
|
|
|
lua_tostring(L, -1));
|
|
|
|
|
return 0; /* return to Lua to abort */
|
|
|
|
|
}
|
|
|
|
@ -941,19 +1022,14 @@ LUALIB_API lua_State *luaL_newstate (void) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
LUALIB_API void luaL_checkversion_ (lua_State *L, lua_Number ver) {
|
|
|
|
|
LUALIB_API void luaL_checkversion_ (lua_State *L, lua_Number ver, size_t sz) {
|
|
|
|
|
const lua_Number *v = lua_version(L);
|
|
|
|
|
if (sz != LUAL_NUMSIZES) /* check numeric types */
|
|
|
|
|
luaL_error(L, "core and library have incompatible numeric types");
|
|
|
|
|
if (v != lua_version(NULL))
|
|
|
|
|
luaL_error(L, "multiple Lua VMs detected");
|
|
|
|
|
else if (*v != ver)
|
|
|
|
|
luaL_error(L, "version mismatch: app. needs %f, Lua core provides %f",
|
|
|
|
|
ver, *v);
|
|
|
|
|
/* check conversions number -> integer types */
|
|
|
|
|
lua_pushnumber(L, -(lua_Number)0x1234);
|
|
|
|
|
if (lua_tointeger(L, -1) != -0x1234 ||
|
|
|
|
|
lua_tounsigned(L, -1) != (lua_Unsigned)-0x1234)
|
|
|
|
|
luaL_error(L, "bad conversion number->int;"
|
|
|
|
|
" must recompile Lua with proper settings");
|
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|