/* ** $Id: lua.c $ ** Lua stand-alone interpreter ** See Copyright Notice in lua.h */ #include "lua/lprefix.h" #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <unistd.h> #include <signal.h> #include "lua/lua.h" #include "lua/lauxlib.h" #include "lua/lualib.h" #include <math.h> #include <ctype.h> #include <string.h> #include "lpoint.h" #include "lload.h" #include "lbind.h" #include "config.h" #define MAINPROGNAME "main.lua" #define TESTPROGNAME "testsuite/main.lua" //static lua_State* globalL = NULL; /* ** Hook set by signal function to stop the interpreter. */ //static void lstop (lua_State* L, lua_Debug* ar) { // (void)ar; /* unused arg. */ // lua_sethook(L, NULL, 0, 0); /* reset hook */ // luaL_error(L, "interrupted!"); //} /* ** Function to be called at a C signal. Because a C signal cannot ** just change a Lua state (as there is no proper synchronization), ** this function only sets a hook that, when called, will stop the ** interpreter. */ //static void laction (int i) { // int flag = LUA_MASKCALL | LUA_MASKRET | LUA_MASKLINE | LUA_MASKCOUNT; // signal(i, SIG_DFL); /* if another SIGINT happens, terminate process */ // lua_sethook(globalL, lstop, flag, 1); //} /* ** Message handler used to run all chunks */ static int msghandler (lua_State* L) { const char* msg = lua_tostring(L, 1); if (msg == NULL) /* is error object not a string? */ { if (luaL_callmeta(L, 1, "__tostring") && /* does it have a metamethod */ lua_type(L, -1) == LUA_TSTRING) /* that produces a string? */ { return 1; /* that is the message */ } else { msg = lua_pushfstring(L, "(error object is a %s value)", luaL_typename(L, 1)); } } luaL_traceback(L, L, msg, 2); return 1; } static void load_api(lua_State* L) { char* modules[] = { "config", "object", "shape", "geometry", "graphics", "pcell", "generics", "stringfile", "util", "aux", "funcobject", "reduce", "stack", "abstract", // this must be loaded AFTER geometry and graphics. Just leave this at the end NULL }; char** ptr = modules; lua_getglobal(L, "_load_module"); while(*ptr) { lua_pushvalue(L, -1); // copy _load_module lua_pushstring(L, *ptr); if(lua_pcall(L, 1, 1, 0) == LUA_OK) { lua_setglobal(L, *ptr); } else { fprintf(stderr, "%s\n", lua_tostring(L, -1)); lua_close(L); exit(1); } ++ptr; } lua_pop(L, 1); // remove _load_module } static void create_argument_table(lua_State* L, int argc, char** argv) { lua_newtable(L); int i; for(i = 1; i < argc; ++i) { lua_pushstring(L, argv[i]); lua_rawseti(L, -2, i); } lua_setglobal(L, "arg"); } static int call_main_program(lua_State* L, const char* filename) { int status = luaL_loadfile(L, filename); if (status == LUA_OK) { lua_pushcfunction(L, msghandler); lua_insert(L, 1); status = lua_pcall(L, 0, 0, 1); } if(status != LUA_OK) { const char* msg = lua_tostring(L, -1); fprintf(stderr, "%s\n", msg); lua_pop(L, 1); return LUA_ERRRUN; } return LUA_OK; } lua_State* create_and_initialize_lua() { lua_State* L = luaL_newstate(); if (L == NULL) { fprintf(stderr, "%s\n", "cannot create state: not enough memory"); exit(EXIT_FAILURE); } // lua libraries luaL_openlibs(L); // opc libraries open_lpoint_lib(L); open_lload_lib(L); open_lbind_lib(L); load_api(L); // could fail return L; } int main (int argc, char** argv) { lua_State* L = create_and_initialize_lua(); int status = LUA_OK; if(argc > 1 && (strcmp(argv[1], "test") == 0)) { create_argument_table(L, argc - 1, argv + 1); // remove 'test' from arguments status = call_main_program(L, OPC_HOME "/" TESTPROGNAME); } else if(argc > 1 && (strcmp(argv[1], "watch") == 0)) { // remove 'watch' from arguments argc = argc - 1; argv = argv + 1; pid_t pid = fork(); if(pid == 0) // child { while(1) { create_argument_table(L, argc, argv); status = call_main_program(L, OPC_HOME "/" MAINPROGNAME); // now reinitialize the program // this works as if the program had beed started again, which is what we want sleep(1); lua_close(L); L = create_and_initialize_lua(); } } else // parent { printf("created child process (pid: %d)\nyou have to kill it manually once you're done\n", pid); } } else if(argc > 2 && (strcmp(argv[1], "run") == 0)) { const char* filename = argv[2]; // remove 'watch' from arguments argc = argc - 2; argv = argv + 2; create_argument_table(L, argc, argv); char path[200]; snprintf(path, 200, "%s/%s", OPC_HOME, filename); status = call_main_program(L, path); } else { create_argument_table(L, argc, argv); status = call_main_program(L, OPC_HOME "/" MAINPROGNAME); } lua_close(L); return status == LUA_OK ? 0 : 1; }