/*** $Id: lbaselib.c,v 1.191.1.6 2008/02/14 16:46:22 roberto Exp $** Basic library** See Copyright Notice in lua.h*/#include <ctype.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#define lbaselib_c#define LUA_LIB#include"lua.h"#include"lauxlib.h"#include"lualib.h"/*** If your system does not support `stdout', you can just remove this function.** If you need, you can define your own `print' function, following this** model but changing `fputs' to put the strings at a proper place** (a console window or a log file, for instance).*/#if 0static intluaB_print(lua_State *L) {int n =lua_gettop(L);/* number of arguments */int i;lua_getglobal(L,"tostring");for(i=1; i<=n; i++) {const char*s;lua_pushvalue(L, -1);/* function to be called */lua_pushvalue(L, i);/* value to print */lua_call(L,1,1);
s =lua_tostring(L, -1);/* get result */if(s == NULL)returnluaL_error(L,LUA_QL("tostring")" must return a string to "LUA_QL("print"));if(i>1)fputs("\t", stdout);fputs(s, stdout);lua_pop(L,1);/* pop result */}fputs("\n", stdout);return0;}#endifstatic intluaB_tonumber(lua_State *L) {int base =luaL_optint(L,2,10);if(base ==10) {/* standard conversion */luaL_checkany(L,1);if(lua_isnumber(L,1)) {lua_pushnumber(L,lua_tonumber(L,1));return1;}}else{const char*s1 =luaL_checkstring(L,1);char*s2;unsigned long n;luaL_argcheck(L,2<= base && base <=36,2,"base out of range");
n =strtoul(s1, &s2, base);if(s1 != s2) {/* at least one valid digit? */while(isspace((unsigned char)(*s2))) s2++;/* skip trailing spaces */if(*s2 =='\0') {/* no invalid trailing characters? */lua_pushnumber(L, (lua_Number)n);return1;}}}lua_pushnil(L);/* else not a number */return1;}static intluaB_error(lua_State *L) {int level =luaL_optint(L,2,1);lua_settop(L,1);if(lua_isstring(L,1) && level >0) {/* add extra information? */luaL_where(L, level);lua_pushvalue(L,1);lua_concat(L,2);}returnlua_error(L);}static intluaB_getmetatable(lua_State *L) {luaL_checkany(L,1);if(!lua_getmetatable(L,1)) {lua_pushnil(L);return1;/* no metatable */}luaL_getmetafield(L,1,"__metatable");return1;/* returns either __metatable field (if present) or metatable */}static intluaB_setmetatable(lua_State *L) {int t =lua_type(L,2);luaL_checktype(L,1, LUA_TTABLE);luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE,2,"nil or table expected");if(luaL_getmetafield(L,1,"__metatable"))luaL_error(L,"cannot change a protected metatable");lua_settop(L,2);lua_setmetatable(L,1);return1;}static voidgetfunc(lua_State *L,int opt) {if(lua_isfunction(L,1))lua_pushvalue(L,1);else{
lua_Debug ar;int level = opt ? luaL_optint(L,1,1) :luaL_checkint(L,1);luaL_argcheck(L, level >=0,1,"level must be non-negative");if(lua_getstack(L, level, &ar) ==0)luaL_argerror(L,1,"invalid level");lua_getinfo(L,"f", &ar);if(lua_isnil(L, -1))luaL_error(L,"no function environment for tail call at level %d",
level);}}static intluaB_getfenv(lua_State *L) {getfunc(L,1);if(lua_iscfunction(L, -1))/* is a C function? */lua_pushvalue(L, LUA_GLOBALSINDEX);/* return the thread's global env. */elselua_getfenv(L, -1);return1;}static intluaB_setfenv(lua_State *L) {luaL_checktype(L,2, LUA_TTABLE);getfunc(L,0);lua_pushvalue(L,2);if(lua_isnumber(L,1) &&lua_tonumber(L,1) ==0) {/* change environment of current thread */lua_pushthread(L);lua_insert(L, -2);lua_setfenv(L, -2);return0;}else if(lua_iscfunction(L, -2) ||lua_setfenv(L, -2) ==0)luaL_error(L,LUA_QL("setfenv")" cannot change environment of given object");return1;}static intluaB_rawequal(lua_State *L) {luaL_checkany(L,1);luaL_checkany(L,2);lua_pushboolean(L,lua_rawequal(L,1,2));return1;}static intluaB_rawget(lua_State *L) {luaL_checktype(L,1, LUA_TTABLE);luaL_checkany(L,2);lua_settop(L,2);lua_rawget(L,1);return1;}static intluaB_rawset(lua_State *L) {luaL_checktype(L,1, LUA_TTABLE);luaL_checkany(L,2);luaL_checkany(L,3);lua_settop(L,3);lua_rawset(L,1);return1;}static intluaB_gcinfo(lua_State *L) {lua_pushinteger(L,lua_getgccount(L));return1;}static intluaB_collectgarbage(lua_State *L) {static const char*const opts[] = {"stop","restart","collect","count","step","setpause","setstepmul", NULL};static const int optsnum[] = {LUA_GCSTOP, LUA_GCRESTART, LUA_GCCOLLECT,
LUA_GCCOUNT, LUA_GCSTEP, LUA_GCSETPAUSE, LUA_GCSETSTEPMUL};int o =luaL_checkoption(L,1,"collect", opts);int ex =luaL_optint(L,2,0);int res =lua_gc(L, optsnum[o], ex);switch(optsnum[o]) {case LUA_GCCOUNT: {int b =lua_gc(L, LUA_GCCOUNTB,0);lua_pushnumber(L, res + ((lua_Number)b/1024));return1;}case LUA_GCSTEP: {lua_pushboolean(L, res);return1;}default: {lua_pushnumber(L, res);return1;}}}static intluaB_type(lua_State *L) {luaL_checkany(L,1);lua_pushstring(L,luaL_typename(L,1));return1;}static intluaB_next(lua_State *L) {luaL_checktype(L,1, LUA_TTABLE);lua_settop(L,2);/* create a 2nd argument if there isn't one */if(lua_next(L,1))return2;else{lua_pushnil(L);return1;}}static intluaB_pairs(lua_State *L) {luaL_checktype(L,1, LUA_TTABLE);lua_pushvalue(L,lua_upvalueindex(1));/* return generator, */lua_pushvalue(L,1);/* state, */lua_pushnil(L);/* and initial value */return3;}static intipairsaux(lua_State *L) {int i =luaL_checkint(L,2);luaL_checktype(L,1, LUA_TTABLE);
i++;/* next value */lua_pushinteger(L, i);lua_rawgeti(L,1, i);return(lua_isnil(L, -1)) ? 0:2;}static intluaB_ipairs(lua_State *L) {luaL_checktype(L,1, LUA_TTABLE);lua_pushvalue(L,lua_upvalueindex(1));/* return generator, */lua_pushvalue(L,1);/* state, */lua_pushinteger(L,0);/* and initial value */return3;}static intload_aux(lua_State *L,int status) {if(status ==0)/* OK? */return1;else{lua_pushnil(L);lua_insert(L, -2);/* put before error message */return2;/* return nil plus error message */}}static intluaB_loadstring(lua_State *L) {size_t l;const char*s =luaL_checklstring(L,1, &l);const char*chunkname =luaL_optstring(L,2, s);returnload_aux(L,luaL_loadbuffer(L, s, l, chunkname));}static intluaB_loadfile(lua_State *L) {const char*fname =luaL_optstring(L,1, NULL);returnload_aux(L,luaL_loadfile(L, fname));}/*** Reader for generic `load' function: `lua_load' uses the** stack for internal stuff, so the reader cannot change the** stack top. Instead, it keeps its resulting string in a** reserved slot inside the stack.*/static const char*generic_reader(lua_State *L,void*ud,size_t*size) {(void)ud;/* to avoid warnings */luaL_checkstack(L,2,"too many nested functions");lua_pushvalue(L,1);/* get function */lua_call(L,0,1);/* call it */if(lua_isnil(L, -1)) {*size =0;return NULL;}else if(lua_isstring(L, -1)) {lua_replace(L,3);/* save string in a reserved stack slot */returnlua_tolstring(L,3, size);}elseluaL_error(L,"reader function must return a string");return NULL;/* to avoid warnings */}static intluaB_load(lua_State *L) {int status;const char*cname =luaL_optstring(L,2,"=(load)");luaL_checktype(L,1, LUA_TFUNCTION);lua_settop(L,3);/* function, eventual name, plus one reserved slot */
status =lua_load(L, generic_reader, NULL, cname);returnload_aux(L, status);}static intluaB_dofile(lua_State *L) {const char*fname =luaL_optstring(L,1, NULL);int n =lua_gettop(L);if(luaL_loadfile(L, fname) !=0)lua_error(L);lua_call(L,0, LUA_MULTRET);returnlua_gettop(L) - n;}static intluaB_assert(lua_State *L) {luaL_checkany(L,1);if(!lua_toboolean(L,1))returnluaL_error(L,"%s",luaL_optstring(L,2,"assertion failed!"));returnlua_gettop(L);}static intluaB_unpack(lua_State *L) {int i, e, n;luaL_checktype(L,1, LUA_TTABLE);
i =luaL_optint(L,2,1);
e =luaL_opt(L, luaL_checkint,3,luaL_getn(L,1));if(i > e)return0;/* empty range */
n = e - i +1;/* number of elements */if(n <=0|| !lua_checkstack(L, n))/* n <= 0 means arith. overflow */returnluaL_error(L,"too many results to unpack");lua_rawgeti(L,1, i);/* push arg[i] (avoiding overflow problems) */while(i++ < e)/* push arg[i + 1...e] */lua_rawgeti(L,1, i);return n;}static intluaB_select(lua_State *L) {int n =lua_gettop(L);if(lua_type(L,1) == LUA_TSTRING && *lua_tostring(L,1) =='#') {lua_pushinteger(L, n-1);return1;}else{int i =luaL_checkint(L,1);if(i <0) i = n + i;else if(i > n) i = n;luaL_argcheck(L,1<= i,1,"index out of range");return n - i;}}static intluaB_pcall(lua_State *L) {int status;luaL_checkany(L,1);
status =lua_pcall(L,lua_gettop(L) -1, LUA_MULTRET,0);lua_pushboolean(L, (status ==0));lua_insert(L,1);returnlua_gettop(L);/* return status + all results */}static intluaB_xpcall(lua_State *L) {int status;luaL_checkany(L,2);lua_settop(L,2);lua_insert(L,1);/* put error function under function to be called */
status =lua_pcall(L,0, LUA_MULTRET,1);lua_pushboolean(L, (status ==0));lua_replace(L,1);returnlua_gettop(L);/* return status + all results */}static intluaB_tostring(lua_State *L) {luaL_checkany(L,1);if(luaL_callmeta(L,1,"__tostring"))/* is there a metafield? */return1;/* use its value */switch(lua_type(L,1)) {case LUA_TNUMBER:lua_pushstring(L,lua_tostring(L,1));break;case LUA_TSTRING:lua_pushvalue(L,1);break;case LUA_TBOOLEAN:lua_pushstring(L, (lua_toboolean(L,1) ? "true":"false"));break;case LUA_TNIL:lua_pushliteral(L,"nil");break;default:lua_pushfstring(L,"%s: %p",luaL_typename(L,1),lua_topointer(L,1));break;}return1;}static intluaB_newproxy(lua_State *L) {lua_settop(L,1);lua_newuserdata(L,0);/* create proxy */if(lua_toboolean(L,1) ==0)return1;/* no metatable */else if(lua_isboolean(L,1)) {lua_newtable(L);/* create a new metatable `m' ... */lua_pushvalue(L, -1);/* ... and mark `m' as a valid metatable */lua_pushboolean(L,1);lua_rawset(L,lua_upvalueindex(1));/* weaktable[m] = true */}else{int validproxy =0;/* to check if weaktable[metatable(u)] == true */if(lua_getmetatable(L,1)) {lua_rawget(L,lua_upvalueindex(1));
validproxy =lua_toboolean(L, -1);lua_pop(L,1);/* remove value */}luaL_argcheck(L, validproxy,1,"boolean or proxy expected");lua_getmetatable(L,1);/* metatable is valid; get it */}lua_setmetatable(L,2);return1;}static const luaL_Reg base_funcs[] = {{"assert", luaB_assert},{"collectgarbage", luaB_collectgarbage},{"dofile", luaB_dofile},{"error", luaB_error},{"gcinfo", luaB_gcinfo},{"getfenv", luaB_getfenv},{"getmetatable", luaB_getmetatable},{"loadfile", luaB_loadfile},{"load", luaB_load},{"loadstring", luaB_loadstring},{"next", luaB_next},{"pcall", luaB_pcall},#if 0{"print", luaB_print},#endif{"rawequal", luaB_rawequal},{"rawget", luaB_rawget},{"rawset", luaB_rawset},{"select", luaB_select},{"setfenv", luaB_setfenv},{"setmetatable", luaB_setmetatable},{"tonumber", luaB_tonumber},{"tostring", luaB_tostring},{"type", luaB_type},{"unpack", luaB_unpack},{"xpcall", luaB_xpcall},{NULL, NULL}};/*** {======================================================** Coroutine library** =======================================================*/#define CO_RUN 0/* running */#define CO_SUS 1/* suspended */#define CO_NOR 2/* 'normal' (it resumed another coroutine) */#define CO_DEAD 3static const char*const statnames[] ={"running","suspended","normal","dead"};static intcostatus(lua_State *L, lua_State *co) {if(L == co)return CO_RUN;switch(lua_status(co)) {case LUA_YIELD:return CO_SUS;case0: {
lua_Debug ar;if(lua_getstack(co,0, &ar) >0)/* does it have frames? */return CO_NOR;/* it is running */else if(lua_gettop(co) ==0)return CO_DEAD;elsereturn CO_SUS;/* initial state */}default:/* some error occured */return CO_DEAD;}}static intluaB_costatus(lua_State *L) {
lua_State *co =lua_tothread(L,1);luaL_argcheck(L, co,1,"coroutine expected");lua_pushstring(L, statnames[costatus(L, co)]);return1;}static intauxresume(lua_State *L, lua_State *co,int narg) {int status =costatus(L, co);if(!lua_checkstack(co, narg))luaL_error(L,"too many arguments to resume");if(status != CO_SUS) {lua_pushfstring(L,"cannot resume %s coroutine", statnames[status]);return-1;/* error flag */}lua_xmove(L, co, narg);lua_setlevel(L, co);
status =lua_resume(co, narg);if(status ==0|| status == LUA_YIELD) {int nres =lua_gettop(co);if(!lua_checkstack(L, nres +1))luaL_error(L,"too many results to resume");lua_xmove(co, L, nres);/* move yielded values */return nres;}else{lua_xmove(co, L,1);/* move error message */return-1;/* error flag */}}static intluaB_coresume(lua_State *L) {
lua_State *co =lua_tothread(L,1);int r;luaL_argcheck(L, co,1,"coroutine expected");
r =auxresume(L, co,lua_gettop(L) -1);if(r <0) {lua_pushboolean(L,0);lua_insert(L, -2);return2;/* return false + error message */}else{lua_pushboolean(L,1);lua_insert(L, -(r +1));return r +1;/* return true + `resume' returns */}}static intluaB_auxwrap(lua_State *L) {
lua_State *co =lua_tothread(L,lua_upvalueindex(1));int r =auxresume(L, co,lua_gettop(L));if(r <0) {if(lua_isstring(L, -1)) {/* error object is a string? */luaL_where(L,1);/* add extra info */lua_insert(L, -2);lua_concat(L,2);}lua_error(L);/* propagate error */}return r;}static intluaB_cocreate(lua_State *L) {
lua_State *NL =lua_newthread(L);luaL_argcheck(L,lua_isfunction(L,1) && !lua_iscfunction(L,1),1,"Lua function expected");lua_pushvalue(L,1);/* move function to top */lua_xmove(L, NL,1);/* move function from L to NL */return1;}static intluaB_cowrap(lua_State *L) {luaB_cocreate(L);lua_pushcclosure(L, luaB_auxwrap,1);return1;}static intluaB_yield(lua_State *L) {returnlua_yield(L,lua_gettop(L));}static intluaB_corunning(lua_State *L) {if(lua_pushthread(L))lua_pushnil(L);/* main thread is not a coroutine */return1;}static const luaL_Reg co_funcs[] = {{"create", luaB_cocreate},{"resume", luaB_coresume},{"running", luaB_corunning},{"status", luaB_costatus},{"wrap", luaB_cowrap},{"yield", luaB_yield},{NULL, NULL}};/* }====================================================== */static voidauxopen(lua_State *L,const char*name,
lua_CFunction f, lua_CFunction u) {lua_pushcfunction(L, u);lua_pushcclosure(L, f,1);lua_setfield(L, -2, name);}static voidbase_open(lua_State *L) {/* set global _G */lua_pushvalue(L, LUA_GLOBALSINDEX);lua_setglobal(L,"_G");/* open lib into global table */luaL_register(L,"_G", base_funcs);lua_pushliteral(L, LUA_VERSION);lua_setglobal(L,"_VERSION");/* set global _VERSION *//* `ipairs' and `pairs' need auxliliary functions as upvalues */auxopen(L,"ipairs", luaB_ipairs, ipairsaux);auxopen(L,"pairs", luaB_pairs, luaB_next);/* `newproxy' needs a weaktable as upvalue */lua_createtable(L,0,1);/* new table `w' */lua_pushvalue(L, -1);/* `w' will be its own metatable */lua_setmetatable(L, -2);lua_pushliteral(L,"kv");lua_setfield(L, -2,"__mode");/* metatable(w).__mode = "kv" */lua_pushcclosure(L, luaB_newproxy,1);lua_setglobal(L,"newproxy");/* set global `newproxy' */}
LUALIB_API intluaopen_base(lua_State *L) {base_open(L);luaL_register(L, LUA_COLIBNAME, co_funcs);return2;}