Remove FPS from being next to the version string
[oweals/minetest.git] / src / script / common / c_internal.cpp
1 /*
2 Minetest
3 Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include "common/c_internal.h"
21 #include "debug.h"
22 #include "log.h"
23 #include "main.h"
24 #include "settings.h"
25
26 std::string script_get_backtrace(lua_State *L)
27 {
28         std::string s;
29         lua_getglobal(L, "debug");
30         if(lua_istable(L, -1)){
31                 lua_getfield(L, -1, "traceback");
32                 if(lua_isfunction(L, -1)) {
33                         lua_call(L, 0, 1);
34                         if(lua_isstring(L, -1)){
35                                 s = lua_tostring(L, -1);
36                         }
37                 }
38                 lua_pop(L, 1);
39         }
40         lua_pop(L, 1);
41         return s;
42 }
43
44 int script_error_handler(lua_State *L) {
45         lua_getglobal(L, "debug");
46         if (!lua_istable(L, -1)) {
47                 lua_pop(L, 1);
48                 return 1;
49         }
50         lua_getfield(L, -1, "traceback");
51         if (!lua_isfunction(L, -1)) {
52                 lua_pop(L, 2);
53                 return 1;
54         }
55         lua_pushvalue(L, 1);
56         lua_pushinteger(L, 2);
57         lua_call(L, 2, 1);
58         return 1;
59 }
60
61 int script_exception_wrapper(lua_State *L, lua_CFunction f)
62 {
63         try {
64                 return f(L);  // Call wrapped function and return result.
65         } catch (const char *s) {  // Catch and convert exceptions.
66                 lua_pushstring(L, s);
67         } catch (LuaError& e) {
68                 lua_pushstring(L, e.what());
69         }
70         return lua_error(L);  // Rethrow as a Lua error.
71 }
72
73 void script_error(lua_State *L)
74 {
75         const char *s = lua_tostring(L, -1);
76         std::string str(s ? s : "");
77         throw LuaError(str);
78 }
79
80 // Push the list of callbacks (a lua table).
81 // Then push nargs arguments.
82 // Then call this function, which
83 // - runs the callbacks
84 // - replaces the table and arguments with the return value,
85 //     computed depending on mode
86 void script_run_callbacks(lua_State *L, int nargs, RunCallbacksMode mode)
87 {
88         assert(lua_gettop(L) >= nargs + 1);
89
90         // Insert error handler
91         lua_pushcfunction(L, script_error_handler);
92         int errorhandler = lua_gettop(L) - nargs - 1;
93         lua_insert(L, errorhandler);
94
95         // Insert run_callbacks between error handler and table
96         lua_getglobal(L, "core");
97         lua_getfield(L, -1, "run_callbacks");
98         lua_remove(L, -2);
99         lua_insert(L, errorhandler + 1);
100
101         // Insert mode after table
102         lua_pushnumber(L, (int) mode);
103         lua_insert(L, errorhandler + 3);
104
105         // Stack now looks like this:
106         // ... <error handler> <run_callbacks> <table> <mode> <arg#1> <arg#2> ... <arg#n>
107
108         if (lua_pcall(L, nargs + 2, 1, errorhandler)) {
109                 script_error(L);
110         }
111
112         lua_remove(L, -2); // Remove error handler
113 }
114
115 void log_deprecated(lua_State *L, std::string message)
116 {
117         static bool configured = false;
118         static bool dolog      = false;
119         static bool doerror    = false;
120
121         // performance optimization to not have to read and compare setting for every logline
122         if (!configured) {
123                 std::string value = g_settings->get("deprecated_lua_api_handling");
124                 if (value == "log") {
125                         dolog = true;
126                 }
127                 if (value == "error") {
128                         dolog = true;
129                         doerror = true;
130                 }
131         }
132
133         if (doerror) {
134                 if (L != NULL) {
135                         script_error(L);
136                 } else {
137                         /* As of april 2014 assert is not optimized to nop in release builds
138                          * therefore this is correct. */
139                         assert("Can't do a scripterror for this deprecated message, so exit completely!");
140                 }
141         }
142
143         if (dolog) {
144                 /* abusing actionstream because of lack of file-only-logged loglevel */
145                 actionstream << message << std::endl;
146                 if (L != NULL) {
147                         actionstream << script_get_backtrace(L) << std::endl;
148                 }
149         }
150 }
151