Lua: Fix type confusion between signed and unsigned
[lsnes.git] / src / core / misc.cpp
blob4bb8c13ad6efcbb9268c87cd09df90dd74b08ffa
1 #include "lsnes.hpp"
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"
17 #include <cstdlib>
18 #include <csignal>
19 #include <sstream>
20 #include <iostream>
21 #include <iomanip>
22 #include <fstream>
23 #include <string>
24 #include <vector>
25 #include <algorithm>
26 #include <ctime>
27 #include <cstdlib>
28 #include <cstring>
29 #include <sys/time.h>
30 #include <unistd.h>
31 #include <boost/filesystem.hpp>
32 #if defined(_WIN32) || defined(_WIN64)
33 #include <windows.h>
34 #endif
36 #ifdef USE_LIBGCRYPT_SHA256
37 #include <gcrypt.h>
38 #endif
40 namespace
42 bool reached_main_flag;
43 bool crashing = false;
45 void fatal_signal_handler(int sig)
47 if(crashing) {
48 write(2, "Double fault, exiting!\n", 23);
49 signal(sig, SIG_DFL);
50 raise(sig);
52 crashing = true;
53 write(2, "Caught fatal signal!\n", 21);
54 if(lsnes_instance.mlogic) emerg_save_movie(lsnes_instance.mlogic->get_mfile(),
55 lsnes_instance.mlogic->get_rrdata());
56 signal(sig, SIG_DFL);
57 raise(sig);
60 void terminate_handler()
62 if(crashing) {
63 write(2, "Double fault, exiting!\n", 23);
64 exit(1);
66 crashing = true;
67 write(2, "Terminating abnormally!\n", 24);
68 if(lsnes_instance.mlogic) emerg_save_movie(lsnes_instance.mlogic->get_mfile(),
69 lsnes_instance.mlogic->get_rrdata());
70 std::cerr << "Exiting on fatal error" << std::endl;
71 exit(1);
74 //% is intentionally missing.
75 const char* allowed_filename_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
76 "^&'@{}[],$?!-#().+~_";
79 std::string safe_filename(const std::string& str)
81 std::ostringstream o;
82 for(size_t i = 0; i < str.length(); i++) {
83 unsigned char ch = static_cast<unsigned char>(str[i]);
84 if(strchr(allowed_filename_chars, ch))
85 o << str[i];
86 else
87 o << "%" << hex::to8(ch);
89 return o.str();
92 void fatal_error() throw()
94 platform::fatal_error();
95 std::cout << "PANIC: Fatal error, can't continue." << std::endl;
96 exit(1);
99 std::string get_config_path() throw(std::bad_alloc)
101 const char* tmp;
102 std::string basedir;
103 if((tmp = getenv("APPDATA"))) {
104 //If $APPDATA exists, it is the base directory
105 basedir = tmp;
106 } else if((tmp = getenv("XDG_CONFIG_HOME"))) {
107 //If $XDG_CONFIG_HOME exists, it is the base directory
108 basedir = tmp;
109 } else if((tmp = getenv("HOME"))) {
110 //If $HOME exists, the base directory is '.config' there.
111 basedir = std::string(tmp) + "/.config";
112 } else {
113 //Last chance: Return current directory.
114 return ".";
116 //Try to create 'lsnes'. If it exists (or is created) and is directory, great. Otherwise error out.
117 std::string lsnes_path = basedir + "/lsnes";
118 if(!directory::ensure_exists(lsnes_path)) {
119 messages << "FATAL: Can't create configuration directory '" << lsnes_path << "'" << std::endl;
120 fatal_error();
122 //Yes, this is racy, but portability is more important than being absolutely correct...
123 std::string tfile = lsnes_path + "/test";
124 remove(tfile.c_str());
125 FILE* x;
126 if(!(x = fopen(tfile.c_str(), "w+"))) {
127 messages << "FATAL: Configuration directory '" << lsnes_path << "' is not writable" << std::endl;
128 fatal_error();
130 fclose(x);
131 remove(tfile.c_str());
132 return lsnes_path;
135 void OOM_panic()
137 if(lsnes_instance.mlogic) emerg_save_movie(lsnes_instance.mlogic->get_mfile(),
138 lsnes_instance.mlogic->get_rrdata());
139 messages << "FATAL: Out of memory!" << std::endl;
140 fatal_error();
143 uint32_t gcd(uint32_t a, uint32_t b) throw()
145 if(b == 0)
146 return a;
147 else
148 return gcd(b, a % b);
151 std::string format_address(void* addr)
153 return hex::to((uint64_t)addr);
156 bool in_global_ctors()
158 return !reached_main_flag;
161 void reached_main()
163 notify_new_core.errors_to(&messages.getstream());
164 crandom::init();
165 new_core_flag = false; //We'll process the static cores anyway.
166 reached_main_flag = true;
167 lsnes_instance.command->set_oom_panic(OOM_panic);
168 lsnes_instance.command->set_output(platform::out());
169 loadlib::module::run_initializers();
170 std::set_terminate(terminate_handler);
171 #ifdef SIGHUP
172 signal(SIGHUP, fatal_signal_handler);
173 #endif
174 #ifdef SIGINT
175 signal(SIGINT, fatal_signal_handler);
176 #endif
177 #ifdef SIGQUIT
178 signal(SIGQUIT, fatal_signal_handler);
179 #endif
180 #ifdef SIGILL
181 signal(SIGILL, fatal_signal_handler);
182 #endif
183 #ifdef SIGABRT
184 signal(SIGABRT, fatal_signal_handler);
185 #endif
186 #ifdef SIGSEGV
187 signal(SIGSEGV, fatal_signal_handler);
188 #endif
189 #ifdef SIGFPE
190 signal(SIGFPE, fatal_signal_handler);
191 #endif
192 #ifdef SIGPIPE
193 signal(SIGPIPE, fatal_signal_handler);
194 #endif
195 #ifdef SIGBUS
196 signal(SIGBUS, fatal_signal_handler);
197 #endif
198 #ifdef SIGTRAP
199 signal(SIGTRAP, fatal_signal_handler);
200 #endif
201 #ifdef SIGTERM
202 signal(SIGTERM, fatal_signal_handler);
203 #endif
206 std::string mangle_name(const std::string& orig)
208 std::ostringstream out;
209 for(auto i : orig) {
210 if(i == '(')
211 out << "[";
212 else if(i == ')')
213 out << "]";
214 else if(i == '|')
215 out << "\xE2\x8F\xBF";
216 else if(i == '/')
217 out << "\xE2\x8B\xBF";
218 else
219 out << i;
221 return out.str();
224 std::string get_temp_file()
226 #if !defined(_WIN32) && !defined(_WIN64)
227 char tname[512];
228 strcpy(tname, "/tmp/lsnestmp_XXXXXX");
229 int h = mkstemp(tname);
230 if(h < 0)
231 throw std::runtime_error("Failed to get new tempfile name");
232 close(h);
233 return tname;
234 #else
235 char tpath[512];
236 char tname[512];
237 if(!GetTempPathA(512, tpath))
238 throw std::runtime_error("Failed to get new tempfile name");
239 if(!GetTempFileNameA(tpath, "lsn", 0, tname))
240 throw std::runtime_error("Failed to get new tempfile name");
241 return tname;
242 #endif