|
|
@ -1,5 +1,5 @@ |
|
|
|
/*
|
|
|
|
** $Id: lauxlib.c,v 1.167 2007/05/15 18:46:12 roberto Exp roberto $ |
|
|
|
** $Id: lauxlib.c,v 1.168 2007/06/21 13:48:04 roberto Exp roberto $ |
|
|
|
** Auxiliary functions for building Lua libraries |
|
|
|
** See Copyright Notice in lua.h |
|
|
|
*/ |
|
|
@ -25,13 +25,6 @@ |
|
|
|
#include "lauxlib.h" |
|
|
|
|
|
|
|
|
|
|
|
/* number of prereserved references (for internal use) */ |
|
|
|
#define RESERVED_REFS 1 /* only FREELIST_REF is reserved */ |
|
|
|
|
|
|
|
#define FREELIST_REF 1 /* free list of references */ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* convert a stack index to positive */ |
|
|
|
#define abs_index(L, i) ((i) > 0 || (i) <= LUA_REGISTRYINDEX ? (i) : \ |
|
|
|
lua_gettop(L) + (i) + 1) |
|
|
@ -43,7 +36,6 @@ |
|
|
|
** ======================================================= |
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
LUALIB_API int luaL_argerror (lua_State *L, int narg, const char *extramsg) { |
|
|
|
lua_Debug ar; |
|
|
|
if (!lua_getstack(L, 0, &ar)) /* no stack frame? */ |
|
|
@ -100,18 +92,11 @@ LUALIB_API int luaL_error (lua_State *L, const char *fmt, ...) { |
|
|
|
/* }====================================================== */ |
|
|
|
|
|
|
|
|
|
|
|
LUALIB_API int luaL_checkoption (lua_State *L, int narg, const char *def, |
|
|
|
const char *const lst[]) { |
|
|
|
const char *name = (def) ? luaL_optstring(L, narg, def) : |
|
|
|
luaL_checkstring(L, narg); |
|
|
|
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)); |
|
|
|
} |
|
|
|
|
|
|
|
/*
|
|
|
|
** {====================================================== |
|
|
|
** Userdata's metatable manipulation |
|
|
|
** ======================================================= |
|
|
|
*/ |
|
|
|
|
|
|
|
LUALIB_API int luaL_newmetatable (lua_State *L, const char *tname) { |
|
|
|
lua_getfield(L, LUA_REGISTRYINDEX, tname); /* get registry.name */ |
|
|
@ -146,6 +131,27 @@ LUALIB_API void *luaL_checkudata (lua_State *L, int ud, const char *tname) { |
|
|
|
return p; |
|
|
|
} |
|
|
|
|
|
|
|
/* }====================================================== */ |
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
** {====================================================== |
|
|
|
** Argument check functions |
|
|
|
** ======================================================= |
|
|
|
*/ |
|
|
|
|
|
|
|
LUALIB_API int luaL_checkoption (lua_State *L, int narg, const char *def, |
|
|
|
const char *const lst[]) { |
|
|
|
const char *name = (def) ? luaL_optstring(L, narg, def) : |
|
|
|
luaL_checkstring(L, narg); |
|
|
|
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)); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *mes) { |
|
|
|
if (!lua_checkstack(L, space)) |
|
|
@ -209,128 +215,7 @@ LUALIB_API lua_Integer luaL_optinteger (lua_State *L, int narg, |
|
|
|
return luaL_opt(L, luaL_checkinteger, narg, def); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
LUALIB_API int luaL_getmetafield (lua_State *L, int obj, const char *event) { |
|
|
|
if (!lua_getmetatable(L, obj)) /* no metatable? */ |
|
|
|
return 0; |
|
|
|
lua_pushstring(L, event); |
|
|
|
lua_rawget(L, -2); |
|
|
|
if (lua_isnil(L, -1)) { |
|
|
|
lua_pop(L, 2); /* remove metatable and metafield */ |
|
|
|
return 0; |
|
|
|
} |
|
|
|
else { |
|
|
|
lua_remove(L, -2); /* remove only metatable */ |
|
|
|
return 1; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
LUALIB_API int luaL_callmeta (lua_State *L, int obj, const char *event) { |
|
|
|
obj = abs_index(L, obj); |
|
|
|
if (!luaL_getmetafield(L, obj, event)) /* no metafield? */ |
|
|
|
return 0; |
|
|
|
lua_pushvalue(L, obj); |
|
|
|
lua_call(L, 1, 1); |
|
|
|
return 1; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
LUALIB_API const char *luaL_tostring (lua_State *L, int idx) { |
|
|
|
if (!luaL_callmeta(L, idx, "__tostring")) { /* no metafield? */ |
|
|
|
switch (lua_type(L, idx)) { |
|
|
|
case LUA_TNUMBER: |
|
|
|
return lua_pushstring(L, lua_tostring(L, idx)); |
|
|
|
case LUA_TSTRING: |
|
|
|
lua_pushvalue(L, idx); |
|
|
|
break; |
|
|
|
case LUA_TBOOLEAN: |
|
|
|
return lua_pushstring(L, (lua_toboolean(L, idx) ? "true" : "false")); |
|
|
|
case LUA_TNIL: |
|
|
|
return lua_pushliteral(L, "nil"); |
|
|
|
default: |
|
|
|
return lua_pushfstring(L, "%s: %p", luaL_typename(L, idx), |
|
|
|
lua_topointer(L, idx)); |
|
|
|
} |
|
|
|
} |
|
|
|
return lua_tostring(L, -1); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static int libsize (const luaL_Reg *l) { |
|
|
|
int size = 0; |
|
|
|
for (; l->name; l++) size++; |
|
|
|
return size; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
LUALIB_API void luaL_register (lua_State *L, const char *libname, |
|
|
|
const luaL_Reg *l) { |
|
|
|
if (libname) { |
|
|
|
int size = libsize(l); |
|
|
|
/* check whether lib already exists */ |
|
|
|
luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", size); |
|
|
|
lua_getfield(L, -1, libname); /* get _LOADED[libname] */ |
|
|
|
if (!lua_istable(L, -1)) { /* not found? */ |
|
|
|
lua_pop(L, 1); /* remove previous result */ |
|
|
|
/* try global variable (and create one if it does not exist) */ |
|
|
|
if (luaL_findtable(L, LUA_GLOBALSINDEX, libname, size) != NULL) |
|
|
|
luaL_error(L, "name conflict for module " LUA_QS, libname); |
|
|
|
lua_pushvalue(L, -1); |
|
|
|
lua_setfield(L, -3, libname); /* _LOADED[libname] = new table */ |
|
|
|
} |
|
|
|
lua_remove(L, -2); /* remove _LOADED table */ |
|
|
|
} |
|
|
|
for (; l->name; l++) { |
|
|
|
lua_pushcfunction(L, l->func); |
|
|
|
lua_setfield(L, -2, l->name); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
LUALIB_API const char *luaL_gsub (lua_State *L, const char *s, const char *p, |
|
|
|
const char *r) { |
|
|
|
const char *wild; |
|
|
|
size_t l = strlen(p); |
|
|
|
luaL_Buffer b; |
|
|
|
luaL_buffinit(L, &b); |
|
|
|
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' */ |
|
|
|
} |
|
|
|
luaL_addstring(&b, s); /* push last suffix */ |
|
|
|
luaL_pushresult(&b); |
|
|
|
return lua_tostring(L, -1); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
LUALIB_API const char *luaL_findtable (lua_State *L, int idx, |
|
|
|
const char *fname, int szhint) { |
|
|
|
const char *e; |
|
|
|
lua_pushvalue(L, idx); |
|
|
|
do { |
|
|
|
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? */ |
|
|
|
lua_pop(L, 1); /* remove this nil */ |
|
|
|
lua_createtable(L, 0, (*e == '.' ? 1 : szhint)); /* new table for field */ |
|
|
|
lua_pushlstring(L, fname, e - fname); |
|
|
|
lua_pushvalue(L, -2); |
|
|
|
lua_settable(L, -4); /* set new table into field */ |
|
|
|
} |
|
|
|
else if (!lua_istable(L, -1)) { /* field has a non-table value? */ |
|
|
|
lua_pop(L, 2); /* remove table and value */ |
|
|
|
return fname; /* return problematic part of the name */ |
|
|
|
} |
|
|
|
lua_remove(L, -2); /* remove previous table */ |
|
|
|
fname = e + 1; |
|
|
|
} while (*e == '.'); |
|
|
|
return NULL; |
|
|
|
} |
|
|
|
|
|
|
|
/* }====================================================== */ |
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
@ -429,6 +314,18 @@ LUALIB_API void luaL_buffinit (lua_State *L, luaL_Buffer *B) { |
|
|
|
/* }====================================================== */ |
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
** {====================================================== |
|
|
|
** Reference system |
|
|
|
** ======================================================= |
|
|
|
*/ |
|
|
|
|
|
|
|
/* number of prereserved references (for internal use) */ |
|
|
|
#define RESERVED_REFS 1 /* only FREELIST_REF is reserved */ |
|
|
|
|
|
|
|
#define FREELIST_REF 1 /* free list of references */ |
|
|
|
|
|
|
|
|
|
|
|
LUALIB_API int luaL_ref (lua_State *L, int t) { |
|
|
|
int ref; |
|
|
|
t = abs_index(L, t); |
|
|
@ -464,6 +361,7 @@ LUALIB_API void luaL_unref (lua_State *L, int t, int ref) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/* }====================================================== */ |
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
@ -572,9 +470,130 @@ LUALIB_API int luaL_loadstring (lua_State *L, const char *s) { |
|
|
|
return luaL_loadbuffer(L, s, strlen(s), s); |
|
|
|
} |
|
|
|
|
|
|
|
/* }====================================================== */ |
|
|
|
|
|
|
|
|
|
|
|
/* }====================================================== */ |
|
|
|
|
|
|
|
LUALIB_API int luaL_getmetafield (lua_State *L, int obj, const char *event) { |
|
|
|
if (!lua_getmetatable(L, obj)) /* no metatable? */ |
|
|
|
return 0; |
|
|
|
lua_pushstring(L, event); |
|
|
|
lua_rawget(L, -2); |
|
|
|
if (lua_isnil(L, -1)) { |
|
|
|
lua_pop(L, 2); /* remove metatable and metafield */ |
|
|
|
return 0; |
|
|
|
} |
|
|
|
else { |
|
|
|
lua_remove(L, -2); /* remove only metatable */ |
|
|
|
return 1; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
LUALIB_API int luaL_callmeta (lua_State *L, int obj, const char *event) { |
|
|
|
obj = abs_index(L, obj); |
|
|
|
if (!luaL_getmetafield(L, obj, event)) /* no metafield? */ |
|
|
|
return 0; |
|
|
|
lua_pushvalue(L, obj); |
|
|
|
lua_call(L, 1, 1); |
|
|
|
return 1; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
LUALIB_API const char *luaL_tostring (lua_State *L, int idx) { |
|
|
|
if (!luaL_callmeta(L, idx, "__tostring")) { /* no metafield? */ |
|
|
|
switch (lua_type(L, idx)) { |
|
|
|
case LUA_TNUMBER: |
|
|
|
return lua_pushstring(L, lua_tostring(L, idx)); |
|
|
|
case LUA_TSTRING: |
|
|
|
lua_pushvalue(L, idx); |
|
|
|
break; |
|
|
|
case LUA_TBOOLEAN: |
|
|
|
return lua_pushstring(L, (lua_toboolean(L, idx) ? "true" : "false")); |
|
|
|
case LUA_TNIL: |
|
|
|
return lua_pushliteral(L, "nil"); |
|
|
|
default: |
|
|
|
return lua_pushfstring(L, "%s: %p", luaL_typename(L, idx), |
|
|
|
lua_topointer(L, idx)); |
|
|
|
} |
|
|
|
} |
|
|
|
return lua_tostring(L, -1); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static int libsize (const luaL_Reg *l) { |
|
|
|
int size = 0; |
|
|
|
for (; l->name; l++) size++; |
|
|
|
return size; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
LUALIB_API void luaL_register (lua_State *L, const char *libname, |
|
|
|
const luaL_Reg *l) { |
|
|
|
if (libname) { |
|
|
|
int size = libsize(l); |
|
|
|
/* check whether lib already exists */ |
|
|
|
luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", size); |
|
|
|
lua_getfield(L, -1, libname); /* get _LOADED[libname] */ |
|
|
|
if (!lua_istable(L, -1)) { /* not found? */ |
|
|
|
lua_pop(L, 1); /* remove previous result */ |
|
|
|
/* try global variable (and create one if it does not exist) */ |
|
|
|
if (luaL_findtable(L, LUA_GLOBALSINDEX, libname, size) != NULL) |
|
|
|
luaL_error(L, "name conflict for module " LUA_QS, libname); |
|
|
|
lua_pushvalue(L, -1); |
|
|
|
lua_setfield(L, -3, libname); /* _LOADED[libname] = new table */ |
|
|
|
} |
|
|
|
lua_remove(L, -2); /* remove _LOADED table */ |
|
|
|
} |
|
|
|
for (; l->name; l++) { |
|
|
|
lua_pushcfunction(L, l->func); |
|
|
|
lua_setfield(L, -2, l->name); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
LUALIB_API const char *luaL_gsub (lua_State *L, const char *s, const char *p, |
|
|
|
const char *r) { |
|
|
|
const char *wild; |
|
|
|
size_t l = strlen(p); |
|
|
|
luaL_Buffer b; |
|
|
|
luaL_buffinit(L, &b); |
|
|
|
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' */ |
|
|
|
} |
|
|
|
luaL_addstring(&b, s); /* push last suffix */ |
|
|
|
luaL_pushresult(&b); |
|
|
|
return lua_tostring(L, -1); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
LUALIB_API const char *luaL_findtable (lua_State *L, int idx, |
|
|
|
const char *fname, int szhint) { |
|
|
|
const char *e; |
|
|
|
lua_pushvalue(L, idx); |
|
|
|
do { |
|
|
|
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? */ |
|
|
|
lua_pop(L, 1); /* remove this nil */ |
|
|
|
lua_createtable(L, 0, (*e == '.' ? 1 : szhint)); /* new table for field */ |
|
|
|
lua_pushlstring(L, fname, e - fname); |
|
|
|
lua_pushvalue(L, -2); |
|
|
|
lua_settable(L, -4); /* set new table into field */ |
|
|
|
} |
|
|
|
else if (!lua_istable(L, -1)) { /* field has a non-table value? */ |
|
|
|
lua_pop(L, 2); /* remove table and value */ |
|
|
|
return fname; /* return problematic part of the name */ |
|
|
|
} |
|
|
|
lua_remove(L, -2); /* remove previous table */ |
|
|
|
fname = e + 1; |
|
|
|
} while (*e == '.'); |
|
|
|
return NULL; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) { |
|
|
|