Tweak format of command help files and do some further command cleanup
[lsnes.git] / src / core / misc.cpp
blob2454edbe12ca27603201bcce954b92c4d97cc91f
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;
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());
49 signal(sig, SIG_DFL);
50 raise(sig);
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;
59 exit(1);
62 //% is intentionally missing.
63 const char* allowed_filename_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
64 "^&'@{}[],$?!-#().+~_";
67 std::string safe_filename(const std::string& str)
69 std::ostringstream o;
70 for(size_t i = 0; i < str.length(); i++) {
71 unsigned char ch = static_cast<unsigned char>(str[i]);
72 if(strchr(allowed_filename_chars, ch))
73 o << str[i];
74 else
75 o << "%" << hex::to8(ch);
77 return o.str();
80 void fatal_error() throw()
82 platform::fatal_error();
83 std::cout << "PANIC: Fatal error, can't continue." << std::endl;
84 exit(1);
87 std::string get_config_path() throw(std::bad_alloc)
89 const char* tmp;
90 std::string basedir;
91 if((tmp = getenv("APPDATA"))) {
92 //If $APPDATA exists, it is the base directory
93 basedir = tmp;
94 } else if((tmp = getenv("XDG_CONFIG_HOME"))) {
95 //If $XDG_CONFIG_HOME exists, it is the base directory
96 basedir = tmp;
97 } else if((tmp = getenv("HOME"))) {
98 //If $HOME exists, the base directory is '.config' there.
99 basedir = std::string(tmp) + "/.config";
100 } else {
101 //Last chance: Return current directory.
102 return ".";
104 //Try to create 'lsnes'. If it exists (or is created) and is directory, great. Otherwise error out.
105 std::string lsnes_path = basedir + "/lsnes";
106 if(!directory::ensure_exists(lsnes_path)) {
107 messages << "FATAL: Can't create configuration directory '" << lsnes_path << "'" << std::endl;
108 fatal_error();
110 //Yes, this is racy, but portability is more important than being absolutely correct...
111 std::string tfile = lsnes_path + "/test";
112 remove(tfile.c_str());
113 FILE* x;
114 if(!(x = fopen(tfile.c_str(), "w+"))) {
115 messages << "FATAL: Configuration directory '" << lsnes_path << "' is not writable" << std::endl;
116 fatal_error();
118 fclose(x);
119 remove(tfile.c_str());
120 return lsnes_path;
123 void OOM_panic()
125 if(lsnes_instance.mlogic) emerg_save_movie(lsnes_instance.mlogic->get_mfile(),
126 lsnes_instance.mlogic->get_rrdata());
127 messages << "FATAL: Out of memory!" << std::endl;
128 fatal_error();
131 uint32_t gcd(uint32_t a, uint32_t b) throw()
133 if(b == 0)
134 return a;
135 else
136 return gcd(b, a % b);
139 std::string format_address(void* addr)
141 return hex::to((uint64_t)addr);
144 bool in_global_ctors()
146 return !reached_main_flag;
149 void reached_main()
151 notify_new_core.errors_to(&messages.getstream());
152 crandom::init();
153 new_core_flag = false; //We'll process the static cores anyway.
154 reached_main_flag = true;
155 lsnes_instance.command->set_oom_panic(OOM_panic);
156 lsnes_instance.command->set_output(platform::out());
157 loadlib::module::run_initializers();
158 std::set_terminate(terminate_handler);
159 #ifdef SIGHUP
160 signal(SIGHUP, fatal_signal_handler);
161 #endif
162 #ifdef SIGINT
163 signal(SIGINT, fatal_signal_handler);
164 #endif
165 #ifdef SIGQUIT
166 signal(SIGQUIT, fatal_signal_handler);
167 #endif
168 #ifdef SIGILL
169 signal(SIGILL, fatal_signal_handler);
170 #endif
171 #ifdef SIGABRT
172 signal(SIGABRT, fatal_signal_handler);
173 #endif
174 #ifdef SIGSEGV
175 signal(SIGSEGV, fatal_signal_handler);
176 #endif
177 #ifdef SIGFPE
178 signal(SIGFPE, fatal_signal_handler);
179 #endif
180 #ifdef SIGPIPE
181 signal(SIGPIPE, fatal_signal_handler);
182 #endif
183 #ifdef SIGBUS
184 signal(SIGBUS, fatal_signal_handler);
185 #endif
186 #ifdef SIGTRAP
187 signal(SIGTRAP, fatal_signal_handler);
188 #endif
189 #ifdef SIGTERM
190 signal(SIGTERM, fatal_signal_handler);
191 #endif
194 std::string mangle_name(const std::string& orig)
196 std::ostringstream out;
197 for(auto i : orig) {
198 if(i == '(')
199 out << "[";
200 else if(i == ')')
201 out << "]";
202 else if(i == '|')
203 out << "\xE2\x8F\xBF";
204 else if(i == '/')
205 out << "\xE2\x8B\xBF";
206 else
207 out << i;
209 return out.str();
212 std::string get_temp_file()
214 #if !defined(_WIN32) && !defined(_WIN64)
215 char tname[512];
216 strcpy(tname, "/tmp/lsnestmp_XXXXXX");
217 int h = mkstemp(tname);
218 if(h < 0)
219 throw std::runtime_error("Failed to get new tempfile name");
220 close(h);
221 return tname;
222 #else
223 char tpath[512];
224 char tname[512];
225 if(!GetTempPathA(512, tpath))
226 throw std::runtime_error("Failed to get new tempfile name");
227 if(!GetTempFileNameA(tpath, "lsn", 0, tname))
228 throw std::runtime_error("Failed to get new tempfile name");
229 return tname;
230 #endif