3 #include "core/command.hpp"
4 #include "core/controllerframe.hpp"
5 #include "core/dispatch.hpp"
6 #include "core/instance.hpp"
7 #include "core/messages.hpp"
8 #include "core/misc.hpp"
9 #include "core/movie.hpp"
10 #include "core/window.hpp"
11 #include "library/crandom.hpp"
12 #include "library/directory.hpp"
13 #include "library/hex.hpp"
14 #include "library/loadlib.hpp"
15 #include "library/string.hpp"
31 #include <boost/filesystem.hpp>
32 #if defined(_WIN32) || defined(_WIN64)
36 #ifdef USE_LIBGCRYPT_SHA256
42 bool reached_main_flag
;
44 void fatal_signal_handler(int sig
)
46 write(2, "Caught fatal signal!\n", 21);
47 if(lsnes_instance
.mlogic
) emerg_save_movie(lsnes_instance
.mlogic
->get_mfile(),
48 lsnes_instance
.mlogic
->get_rrdata());
53 void terminate_handler()
55 write(2, "Terminating abnormally!\n", 24);
56 if(lsnes_instance
.mlogic
) emerg_save_movie(lsnes_instance
.mlogic
->get_mfile(),
57 lsnes_instance
.mlogic
->get_rrdata());
58 std::cerr
<< "Exiting on fatal error" << std::endl
;
62 command::fnptr
<const std::string
&> test4(lsnes_cmds
, "panicsave-movie", "", "",
63 [](const std::string
& args
) throw(std::bad_alloc
, std::runtime_error
) {
65 if(*core
.mlogic
) emerg_save_movie(core
.mlogic
->get_mfile(), core
.mlogic
->get_rrdata());
68 //% is intentionally missing.
69 const char* allowed_filename_chars
= "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
70 "^&'@{}[],$?!-#().+~_";
73 std::string
safe_filename(const std::string
& str
)
76 for(size_t i
= 0; i
< str
.length(); i
++) {
77 unsigned char ch
= static_cast<unsigned char>(str
[i
]);
78 if(strchr(allowed_filename_chars
, ch
))
81 o
<< "%" << hex::to8(ch
);
86 void fatal_error() throw()
88 platform::fatal_error();
89 std::cout
<< "PANIC: Fatal error, can't continue." << std::endl
;
93 std::string
get_config_path() throw(std::bad_alloc
)
97 if((tmp
= getenv("APPDATA"))) {
98 //If $APPDATA exists, it is the base directory
100 } else if((tmp
= getenv("XDG_CONFIG_HOME"))) {
101 //If $XDG_CONFIG_HOME exists, it is the base directory
103 } else if((tmp
= getenv("HOME"))) {
104 //If $HOME exists, the base directory is '.config' there.
105 basedir
= std::string(tmp
) + "/.config";
107 //Last chance: Return current directory.
110 //Try to create 'lsnes'. If it exists (or is created) and is directory, great. Otherwise error out.
111 std::string lsnes_path
= basedir
+ "/lsnes";
112 if(!directory::ensure_exists(lsnes_path
)) {
113 messages
<< "FATAL: Can't create configuration directory '" << lsnes_path
<< "'" << std::endl
;
116 //Yes, this is racy, but portability is more important than being absolutely correct...
117 std::string tfile
= lsnes_path
+ "/test";
118 remove(tfile
.c_str());
120 if(!(x
= fopen(tfile
.c_str(), "w+"))) {
121 messages
<< "FATAL: Configuration directory '" << lsnes_path
<< "' is not writable" << std::endl
;
125 remove(tfile
.c_str());
131 if(lsnes_instance
.mlogic
) emerg_save_movie(lsnes_instance
.mlogic
->get_mfile(),
132 lsnes_instance
.mlogic
->get_rrdata());
133 messages
<< "FATAL: Out of memory!" << std::endl
;
137 uint32_t gcd(uint32_t a
, uint32_t b
) throw()
142 return gcd(b
, a
% b
);
145 std::string
format_address(void* addr
)
147 return hex::to((uint64_t)addr
);
150 bool in_global_ctors()
152 return !reached_main_flag
;
157 notify_new_core
.errors_to(&messages
.getstream());
159 new_core_flag
= false; //We'll process the static cores anyway.
160 reached_main_flag
= true;
161 lsnes_instance
.command
->set_oom_panic(OOM_panic
);
162 lsnes_instance
.command
->set_output(platform::out());
163 loadlib::module::run_initializers();
164 std::set_terminate(terminate_handler
);
166 signal(SIGHUP
, fatal_signal_handler
);
169 signal(SIGINT
, fatal_signal_handler
);
172 signal(SIGQUIT
, fatal_signal_handler
);
175 signal(SIGILL
, fatal_signal_handler
);
178 signal(SIGABRT
, fatal_signal_handler
);
181 signal(SIGSEGV
, fatal_signal_handler
);
184 signal(SIGFPE
, fatal_signal_handler
);
187 signal(SIGPIPE
, fatal_signal_handler
);
190 signal(SIGBUS
, fatal_signal_handler
);
193 signal(SIGTRAP
, fatal_signal_handler
);
196 signal(SIGTERM
, fatal_signal_handler
);
200 std::string
mangle_name(const std::string
& orig
)
202 std::ostringstream out
;
209 out
<< "\xE2\x8F\xBF";
211 out
<< "\xE2\x8B\xBF";
218 std::string
get_temp_file()
220 #if !defined(_WIN32) && !defined(_WIN64)
222 strcpy(tname
, "/tmp/lsnestmp_XXXXXX");
223 int h
= mkstemp(tname
);
225 throw std::runtime_error("Failed to get new tempfile name");
231 if(!GetTempPathA(512, tpath
))
232 throw std::runtime_error("Failed to get new tempfile name");
233 if(!GetTempFileNameA(tpath
, "lsn", 0, tname
))
234 throw std::runtime_error("Failed to get new tempfile name");
239 command::fnptr
<const std::string
&> macro_test(lsnes_cmds
, "test-macro", "", "",
240 [](const std::string
& args
) throw(std::bad_alloc
, std::runtime_error
) {
242 regex_results r
= regex("([0-9]+)[ \t](.*)", args
);
244 messages
<< "Bad syntax" << std::endl
;
247 unsigned ctrl
= parse_value
<unsigned>(r
[1]);
248 auto pcid
= core
.controls
->lcid_to_pcid(ctrl
);
250 messages
<< "Bad controller" << std::endl
;
254 const portctrl::controller
* _ctrl
=
255 core
.controls
->get_blank().porttypes().port_type(pcid
.first
).
256 controller_info
->get(pcid
.second
);
258 messages
<< "No controller data for controller" << std::endl
;
261 portctrl::macro_data
mdata(r
[2].c_str(), portctrl::macro_data::make_descriptor(*_ctrl
), 0);
262 messages
<< "Macro: " << mdata
.dump(*_ctrl
) << std::endl
;
263 } catch(std::exception
& e
) {
264 messages
<< "Exception: " << e
.what() << std::endl
;