1e27640f98511cbb0810747a80ab80f8eb7a493b
[supertux.git] / src / scripting / scripting.cpp
1 //  SuperTux
2 //  Copyright (C) 2014 Ingo Ruhnke <grumbel@gmail.com>
3 //
4 //  This program is free software: you can redistribute it and/or modify
5 //  it under the terms of the GNU General Public License as published by
6 //  the Free Software Foundation, either version 3 of the License, or
7 //  (at your option) any later version.
8 //
9 //  This program is distributed in the hope that it will be useful,
10 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
11 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 //  GNU General Public License for more details.
13 //
14 //  You should have received a copy of the GNU General Public License
15 //  along with this program.  If not, see <http://www.gnu.org/licenses/>.
16
17 #include "scripting/scripting.hpp"
18
19 #include <sqstdaux.h>
20 #include <sqstdblob.h>
21 #include <sqstdmath.h>
22 #include <sqstdstring.h>
23 #include <stdarg.h>
24 #include <stdio.h>
25
26 #include "physfs/ifile_stream.hpp"
27 #include "scripting/squirrel_error.hpp"
28 #include "scripting/wrapper.hpp"
29 #include "squirrel_util.hpp"
30 #include "supertux/console.hpp"
31 #include "util/log.hpp"
32
33 #ifdef ENABLE_SQDBG
34 #  include "../../external/squirrel/sqdbg/sqrdbg.h"
35 namespace {
36 HSQREMOTEDBG debugger = NULL;
37 } // namespace
38 #endif
39
40 namespace {
41
42 #ifdef __clang__
43 __attribute__((__format__ (__printf__, 2, 0)))
44 #endif
45 void printfunc(HSQUIRRELVM, const char* fmt, ...)
46 {
47   char buf[4096];
48   va_list arglist;
49   va_start(arglist, fmt);
50   vsnprintf(buf, sizeof(buf), fmt, arglist);
51   ConsoleBuffer::output << "[SQUIRREL] " << (const char*) buf << std::flush;
52   va_end(arglist);
53 }
54
55 } // namespace
56
57 namespace scripting {
58
59 HSQUIRRELVM global_vm = NULL;
60
61 Scripting::Scripting(bool enable_debugger)
62 {
63   global_vm = sq_open(64);
64   if(global_vm == NULL)
65     throw std::runtime_error("Couldn't initialize squirrel vm");
66
67   if(enable_debugger) {
68 #ifdef ENABLE_SQDBG
69     sq_enabledebuginfo(global_vm, SQTrue);
70     debugger = sq_rdbg_init(global_vm, 1234, SQFalse);
71     if(debugger == NULL)
72       throw SquirrelError(global_vm, "Couldn't initialize squirrel debugger");
73
74     sq_enabledebuginfo(global_vm, SQTrue);
75     log_info << "Waiting for debug client..." << std::endl;
76     if(SQ_FAILED(sq_rdbg_waitforconnections(debugger)))
77       throw SquirrelError(global_vm, "Waiting for debug clients failed");
78     log_info << "debug client connected." << std::endl;
79 #endif
80   }
81
82   sq_pushroottable(global_vm);
83   if(SQ_FAILED(sqstd_register_bloblib(global_vm)))
84     throw SquirrelError(global_vm, "Couldn't register blob lib");
85   if(SQ_FAILED(sqstd_register_mathlib(global_vm)))
86     throw SquirrelError(global_vm, "Couldn't register math lib");
87   if(SQ_FAILED(sqstd_register_stringlib(global_vm)))
88     throw SquirrelError(global_vm, "Couldn't register string lib");
89
90   // remove rand and srand calls from sqstdmath, we'll provide our own
91   sq_pushstring(global_vm, "srand", -1);
92   sq_deleteslot(global_vm, -2, SQFalse);
93   sq_pushstring(global_vm, "rand", -1);
94   sq_deleteslot(global_vm, -2, SQFalse);
95
96   // register supertux API
97   register_supertux_wrapper(global_vm);
98
99   sq_pop(global_vm, 1);
100
101   // register print function
102   sq_setprintfunc(global_vm, printfunc, printfunc);
103   // register default error handlers
104   sqstd_seterrorhandlers(global_vm);
105
106   // try to load default script
107   try {
108     std::string filename = "scripts/default.nut";
109     IFileStream stream(filename);
110     scripting::compile_and_run(global_vm, stream, filename);
111   } catch(std::exception& e) {
112     log_warning << "Couldn't load default.nut: " << e.what() << std::endl;
113   }
114 }
115
116 Scripting::~Scripting()
117 {
118 #ifdef ENABLE_SQDBG
119   if(debugger != NULL) {
120     sq_rdbg_shutdown(debugger);
121     debugger = NULL;
122   }
123 #endif
124
125   if (global_vm)
126     sq_close(global_vm);
127
128   global_vm = NULL;
129 }
130
131 void
132 Scripting::update_debugger()
133 {
134 #ifdef ENABLE_SQDBG
135   if(debugger != NULL)
136     sq_rdbg_update(debugger);
137 #endif
138 }
139
140 } // namespace scripting
141
142 /* EOF */