1 /*
2 Copyright (c) 2009 Peter "Corsix" Cawley
3
4 Permission is hereby granted, free of charge, to any person obtaining a copy of
5 this software and associated documentation files (the "Software"), to deal in
6 the Software without restriction, including without limitation the rights to
7 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
8 of the Software, and to permit persons to whom the Software is furnished to do
9 so, subject to the following conditions:
10
11 The above copyright notice and this permission notice shall be included in all
12 copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 SOFTWARE.
21 */
22
23 #include "config.h"
24
25 #include <cstdio>
26 #include <cstring>
27 #include <string>
28
29 #include "iso_fs.h"
30 #include "lua.hpp"
31 #include "lua_rnc.h"
32 #include "lua_sdl.h"
33 #include "persist_lua.h"
34 #include "th_lua.h"
35
36 // Config file checking
37 #ifndef CORSIX_TH_USE_PACK_PRAGMAS
38 #error "config.h is out of date - please rerun CMake"
39 #endif
40 // End of config file checking
41
42 extern "C" {
43 int luaopen_random(lua_State* L);
44 }
45
46 namespace {
47
preload_lua_package(lua_State * L,const char * name,lua_CFunction fn)48 inline void preload_lua_package(lua_State* L, const char* name,
49 lua_CFunction fn) {
50 luaT_execute(
51 L, std::string("package.preload.").append(name).append(" = ...").c_str(),
52 fn);
53 }
54
55 } // namespace
56
lua_main_no_eval(lua_State * L)57 int lua_main_no_eval(lua_State* L) {
58 // assert(_VERSION == LUA_VERSION)
59 size_t iLength;
60 lua_getglobal(L, "_VERSION");
61 const char* sVersion = lua_tolstring(L, -1, &iLength);
62 if (iLength != std::strlen(LUA_VERSION) ||
63 std::strcmp(sVersion, LUA_VERSION) != 0) {
64 lua_pushliteral(
65 L,
66 "Linked against a version of Lua different to the one used "
67 "when compiling.\nPlease recompile CorsixTH against the same "
68 "Lua version it is linked against.");
69 return lua_error(L);
70 }
71 lua_pop(L, 1);
72
73 // math.random* = Mersenne twister variant
74 luaT_cpcall(L, luaopen_random, nullptr);
75
76 // Fill in package.preload table so that calls to require("X") from Lua
77 // will call the appropriate luaopen_X function in C.
78 preload_lua_package(L, "rnc", luaopen_rnc);
79 preload_lua_package(L, "TH", luaopen_th);
80 preload_lua_package(L, "persist", luaopen_persist);
81 preload_lua_package(L, "sdl", luaopen_sdl);
82
83 // require "debug" (Harmless in Lua 5.1, useful in 5.2 for compatibility)
84 luaT_execute(L, "require \"debug\"");
85
86 // Check for --interpreter and run that instead of CorsixTH.lua
87 bool bGotScriptFile = false;
88 int iNArgs = lua_gettop(L);
89 for (int i = 1; i <= iNArgs; ++i) {
90 if (lua_type(L, i) == LUA_TSTRING) {
91 size_t iLen;
92 const char* sCmd = lua_tolstring(L, i, &iLen);
93 if (iLen > 14 && std::memcmp(sCmd, "--interpreter=", 14) == 0) {
94 lua_getglobal(L, "assert");
95 lua_getglobal(L, "loadfile");
96 lua_pushlstring(L, sCmd + 14, iLen - 14);
97 bGotScriptFile = true;
98 break;
99 }
100 }
101 }
102
103 if (!bGotScriptFile) {
104 lua_getglobal(L, "assert");
105 lua_getglobal(L, "loadfile");
106 lua_pushstring(L, CORSIX_TH_INTERPRETER_PATH);
107 }
108
109 lua_call(L, 1, 2);
110 lua_call(L, 2, 1);
111 lua_insert(L, 1);
112 return lua_gettop(L);
113 }
114
lua_main(lua_State * L)115 int lua_main(lua_State* L) {
116 lua_call(L, lua_main_no_eval(L) - 1, LUA_MULTRET);
117 return lua_gettop(L);
118 }
119
lua_stacktrace(lua_State * L)120 int lua_stacktrace(lua_State* L) {
121 // err = tostring(err)
122 lua_settop(L, 1);
123 lua_getglobal(L, "tostring");
124 lua_insert(L, 1);
125 lua_call(L, 1, 1);
126
127 // err = <description> .. err
128 lua_pushliteral(L, "An error has occurred in CorsixTH:\n");
129 lua_insert(L, 1);
130 lua_concat(L, 2);
131
132 // return debug.traceback(err, 2)
133 lua_getglobal(L, "debug");
134 lua_getfield(L, -1, "traceback");
135 lua_pushvalue(L, 1);
136 lua_pushinteger(L, 2);
137 lua_call(L, 2, 1);
138
139 return 1;
140 }
141
lua_panic(lua_State * L)142 int lua_panic(lua_State* L) {
143 std::fprintf(stderr,
144 "A Lua error has occurred in CorsixTH outside of protected "
145 "mode!\n");
146 std::fflush(stderr);
147
148 if (lua_type(L, -1) == LUA_TSTRING)
149 std::fprintf(stderr, "%s\n", lua_tostring(L, -1));
150 else
151 std::fprintf(stderr, "%p\n", lua_topointer(L, -1));
152 std::fflush(stderr);
153
154 // A stack trace would be nice, but they cannot be done in a panic.
155
156 return 0;
157 }
158