ref: 01d4cb8f03958e86a1c01ce3b2f6fb08df9a89db
dir: /lua9.c/
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
char flag[] = {
['i'] = 0, /* interactive */
['v'] = 0, /* print version */
['w'] = 0, /* enable warnings */
};
void
usage(void)
{
fprint(2, "usage: %s [-ivw] [script] [arg ...]\n", argv0);
exits("usage");
}
int
iscons(int fd)
{
int n, c;
char buf[64];
if(fd2path(fd, buf, sizeof buf) != 0)
sysfatal("fd2path: %r");
n = strlen(buf);
c = strlen("/dev/cons");
return n >= c && strcmp(buf + n - c, "/dev/cons") == 0;
}
void
luaerror(lua_State *L)
{
fprint(2, "%s: %s\n", argv0, lua_tostring(L, -1));
lua_pop(L, 1);
}
int
pcallerror(lua_State *L)
{
const char *m;
m = lua_tostring(L, 1);
if(m == nil){
if(luaL_callmeta(L, 1, "__tostring") && lua_type(L, -1) == LUA_TSTRING)
return 1;
else
m = lua_pushfstring(L,
"(error object is a %s value)", luaL_typename(L, 1));
}
luaL_traceback(L, L, m, 1);
return 1;
}
int
pcall(lua_State *L, int narg, int nres)
{
int r, base;
base = lua_gettop(L) - narg;
lua_pushcfunction(L, pcallerror);
lua_insert(L, base);
r = lua_pcall(L, narg, nres, base);
lua_remove(L, base);
return r;
}
int
pushargs(lua_State *L)
{
int i, n;
/* Push the 'arg' array to stack */
if(lua_getglobal(L, "arg") != LUA_TTABLE)
luaL_error(L, "'arg' is not a table");
n = luaL_len(L, -1);
luaL_checkstack(L, n + 1, "too many arguments");
for(i = 1; i <= n; i++)
lua_rawgeti(L, -i, i);
lua_remove(L, -i);
return n;
}
int
runrepl(lua_State *L)
{
int r, narg;
char *ln;
Biobuf bin;
if(Binit(&bin, 0, OREAD) == -1)
sysfatal("Binit: %r");
r = LUA_OK;
while(fprint(2, "> "), (ln = Brdstr(&bin, '\n', 1)) != nil){
if(luaL_loadstring(L, ln) != LUA_OK){
luaerror(L);
continue;
}
narg = pushargs(L);
if((r = pcall(L, narg, LUA_MULTRET)) != LUA_OK)
luaerror(L);
}
Bterm(&bin);
return r;
}
int
runfile(lua_State *L, char *file)
{
int narg, r;
if((r = luaL_loadfile(L, file)) == LUA_OK){
narg = pushargs(L);
r = pcall(L, narg, LUA_MULTRET);
}
if(r != LUA_OK)
luaerror(L);
return r;
}
int
luamain(lua_State *L)
{
int argc, i;
char **argv, *file;
argc = lua_tointeger(L, 1);
argv = lua_touserdata(L, 2);
file = argv[0];
if(flag['w'])
lua_warning(L, "@on", 0);
/* Signal for libraries to ignore LUA_* env. vars */
lua_pushboolean(L, 1);
lua_setfield(L, LUA_REGISTRYINDEX, "LUA_NOENV");
luaL_openlibs(L);
/* GC in generational mode */
lua_gc(L, LUA_GCGEN, 0, 0);
/* Create global 'arg' table */
lua_createtable(L, argc, 0);
lua_pushstring(L, argv0);
lua_rawseti(L, -2, 0);
for(i = 1; i < argc; i++){
lua_pushstring(L, argv[i]);
lua_rawseti(L, -2, i);
}
lua_setglobal(L, "arg");
if(file == nil){
file = "/fd/0";
if(flag['i'] && iscons(0))
file = nil;
}
if(file != nil)
runfile(L, file);
if(flag['i'])
runrepl(L);
lua_pushboolean(L, 1);
return 1;
}
void
main(int argc, char *argv[])
{
int r, v;
lua_State *L;
ARGBEGIN{
case 'i': flag['i'] = 1; break;
case 'v': flag['v'] = 1; break;
case 'w': flag['w'] = 1; break;
default: usage();
}ARGEND;
if(flag['v']){
print("%s\n", LUA_COPYRIGHT);
exits(nil);
}
setfcr(getfcr() & ~(FPZDIV | FPOVFL | FPINVAL));
if((L = luaL_newstate()) == NULL)
sysfatal("out of memory");
lua_pushcfunction(L, luamain);
lua_pushinteger(L, argc);
lua_pushlightuserdata(L, argv);
r = lua_pcall(L, 2, 1, 0);
if(r != LUA_OK)
luaerror(L);
v = lua_toboolean(L, -1);
lua_close(L);
exits(r == LUA_OK && v == 1 ? nil : "errors");
}