]> git.lizzy.rs Git - dragonfireclient.git/blob - src/script/common/c_internal.cpp
90846676ffebcecc6d33a1083b25b88927df5846
[dragonfireclient.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
23 std::string script_get_backtrace(lua_State *L)
24 {
25         std::string s;
26         lua_getglobal(L, "debug");
27         if(lua_istable(L, -1)){
28                 lua_getfield(L, -1, "traceback");
29                 if(lua_isfunction(L, -1)) {
30                         lua_call(L, 0, 1);
31                         if(lua_isstring(L, -1)){
32                                 s = lua_tostring(L, -1);
33                         }
34                 }
35                 lua_pop(L, 1);
36         }
37         lua_pop(L, 1);
38         return s;
39 }
40
41 int script_error_handler(lua_State *L) {
42         lua_getglobal(L, "debug");
43         if (!lua_istable(L, -1)) {
44                 lua_pop(L, 1);
45                 return 1;
46         }
47         lua_getfield(L, -1, "traceback");
48         if (!lua_isfunction(L, -1)) {
49                 lua_pop(L, 2);
50                 return 1;
51         }
52         lua_pushvalue(L, 1);
53         lua_pushinteger(L, 2);
54         lua_call(L, 2, 1);
55         return 1;
56 }
57
58 int script_exception_wrapper(lua_State *L, lua_CFunction f)
59 {
60         try {
61                 return f(L);  // Call wrapped function and return result.
62         } catch (const char *s) {  // Catch and convert exceptions.
63                 lua_pushstring(L, s);
64         } catch (LuaError& e) {
65                 lua_pushstring(L, e.what());
66         }
67         return lua_error(L);  // Rethrow as a Lua error.
68 }
69
70 void script_error(lua_State *L)
71 {
72         const char *s = lua_tostring(L, -1);
73         std::string str(s ? s : "");
74         throw LuaError(NULL, str);
75 }
76
77 // Push the list of callbacks (a lua table).
78 // Then push nargs arguments.
79 // Then call this function, which
80 // - runs the callbacks
81 // - replaces the table and arguments with the return value,
82 //     computed depending on mode
83 void script_run_callbacks(lua_State *L, int nargs, RunCallbacksMode mode)
84 {
85         assert(lua_gettop(L) >= nargs + 1);
86
87         // Insert error handler
88         lua_pushcfunction(L, script_error_handler);
89         int errorhandler = lua_gettop(L) - nargs - 1;
90         lua_insert(L, errorhandler);
91
92         // Insert minetest.run_callbacks between error handler and table
93         lua_getglobal(L, "minetest");
94         lua_getfield(L, -1, "run_callbacks");
95         lua_remove(L, -2);
96         lua_insert(L, errorhandler + 1);
97
98         // Insert mode after table
99         lua_pushnumber(L, (int) mode);
100         lua_insert(L, errorhandler + 3);
101
102         // Stack now looks like this:
103         // ... <error handler> <run_callbacks> <table> <mode> <arg#1> <arg#2> ... <arg#n>
104
105         if (lua_pcall(L, nargs + 2, 1, errorhandler)) {
106                 script_error(L);
107         }
108
109         lua_remove(L, -2); // Remove error handler
110 }
111
112