3 #include "core/advdumper.hpp"
4 #include "core/command.hpp"
5 #include "core/dispatch.hpp"
6 #include "core/framerate.hpp"
7 #include "core/keymapper.hpp"
8 #include "interface/romtype.hpp"
9 #include "core/loadlib.hpp"
10 #include "lua/lua.hpp"
11 #include "core/mainloop.hpp"
12 #include "core/misc.hpp"
13 #include "core/moviedata.hpp"
14 #include "core/rom.hpp"
15 #include "core/rrdata.hpp"
16 #include "core/settings.hpp"
17 #include "core/window.hpp"
18 #include "library/string.hpp"
25 class myavsnoop
: public information_dispatch
28 myavsnoop(adv_dumper
& _dumper
, uint64_t frames_to_dump
)
29 : information_dispatch("myavsnoop-monitor"), dumper(_dumper
)
32 total
= frames_to_dump
;
39 void on_frame(struct framebuffer_raw
& _frame
, uint32_t fps_n
, uint32_t fps_d
)
42 if(frames_dumped
% 100 == 0) {
43 std::cout
<< "Dumping frame " << frames_dumped
<< "/" << total
<< " ("
44 << (100 * frames_dumped
/ total
) << "%)" << std::endl
;
46 if(frames_dumped
== total
) {
47 //Rough way to end it.
49 information_dispatch::do_dump_end();
56 std::cout
<< "Finished!" << std::endl
;
59 uint64_t frames_dumped
;
64 void dumper_startup(adv_dumper
& dumper
, const std::string
& mode
, const std::string
& prefix
, uint64_t length
)
66 std::cout
<< "Invoking dumper" << std::endl
;
68 dumper
.start(mode
, prefix
);
69 } catch(std::exception
& e
) {
70 std::cerr
<< "Can't start dumper: " << e
.what() << std::endl
;
73 if(information_dispatch::get_dumper_count()) {
74 std::cout
<< "Dumper attach confirmed" << std::endl
;
76 std::cout
<< "Can't start dumper!" << std::endl
;
79 myavsnoop
* s
= new myavsnoop(dumper
, length
);
82 void startup_lua_scripts(const std::vector
<std::string
>& cmdline
)
84 for(auto i
= cmdline
.begin(); i
!= cmdline
.end(); i
++) {
86 if(a
.length() > 6 && a
.substr(0, 6) == "--lua=") {
87 lsnes_cmd
.invoke("run-lua " + a
.substr(6));
92 struct adv_dumper
& locate_dumper(const std::string
& name
)
94 adv_dumper
* _dumper
= NULL
;
95 std::set
<adv_dumper
*> dumpers
= adv_dumper::get_dumper_set();
100 std::cerr
<< "No such dumper '" << name
<< "' found (try --dumper=list)" << std::endl
;
106 std::string
format_details(unsigned detail
)
109 if((detail
& adv_dumper::target_type_mask
) == adv_dumper::target_type_file
)
110 r
= r
+ "TARGET_FILE";
111 else if((detail
& adv_dumper::target_type_mask
) == adv_dumper::target_type_prefix
)
112 r
= r
+ "TARGET_PREFIX";
113 else if((detail
& adv_dumper::target_type_mask
) == adv_dumper::target_type_special
)
114 r
= r
+ "TARGET_SPECIAL";
116 r
= r
+ "TARGET_UNKNOWN";
120 adv_dumper
& get_dumper(const std::vector
<std::string
>& cmdline
, std::string
& mode
, std::string
& prefix
,
123 bool dumper_given
= false;
125 bool mode_given
= false;
126 bool length_given
= false;
129 for(auto i
= cmdline
.begin(); i
!= cmdline
.end(); i
++) {
131 if(a
.length() >= 9 && a
.substr(0, 9) == "--dumper=") {
133 dumper
= a
.substr(9);
134 } else if(a
.length() >= 7 && a
.substr(0, 7) == "--mode=") {
137 } else if(a
.length() >= 9 && a
.substr(0, 9) == "--prefix=")
138 prefix
= a
.substr(9);
139 else if(a
.length() >= 9 && a
.substr(0, 9) == "--length=")
141 length
= boost::lexical_cast
<uint64_t>(a
.substr(9));
143 throw std::runtime_error("Length out of range (1-)");
144 } catch(std::exception
& e
) {
145 std::cerr
<< "Bad --length: " << e
.what() << std::endl
;
148 else if(a
.length() >= 9 && a
.substr(0, 9) == "--option=") {
149 std::string nameval
= a
.substr(9);
150 size_t s
= nameval
.find_first_of("=");
151 if(s
>= nameval
.length()) {
152 std::cerr
<< "Invalid option syntax (expected --option=foo=bar)" << std::endl
;
155 std::string name
= nameval
.substr(0, s
);
156 std::string val
= nameval
.substr(s
+ 1);
158 lsnes_set
.set(name
, val
);
159 } catch(std::exception
& e
) {
160 std::cerr
<< "Can't set '" << name
<< "' to '" << val
<< "': " << e
.what()
164 } else if(a
.length() >= 12 && a
.substr(0, 15) == "--load-library=")
166 new loaded_library(a
.substr(15));
167 handle_post_loadlibrary();
168 } catch(std::runtime_error
& e
) {
169 std::cerr
<< "Can't load '" << a
.substr(15) << "': " << e
.what() << std::endl
;
173 if(dumper
== "list") {
175 std::set
<adv_dumper
*> dumpers
= adv_dumper::get_dumper_set();
176 std::cout
<< "Dumpers available:" << std::endl
;
177 for(auto i
: dumpers
)
178 std::cout
<< i
->id() << "\t" << i
->name() << std::endl
;
182 std::cerr
<< "Dumper required (--dumper=foo)" << std::endl
;
187 adv_dumper
& _dumper
= locate_dumper(dumper
);
188 std::set
<std::string
> modes
= _dumper
.list_submodes();
190 unsigned d
= _dumper
.mode_details("");
191 std::cout
<< "No modes available for " << dumper
<< " (" << format_details(d
) << ")"
195 std::cout
<< "Modes available for " << dumper
<< ":" << std::endl
;
196 for(auto i
: modes
) {
197 unsigned d
= _dumper
.mode_details(i
);
198 std::cout
<< i
<< "\t" << _dumper
.modename(i
) << "\t(" << format_details(d
) << ")"
203 adv_dumper
& _dumper
= locate_dumper(dumper
);
204 if(!mode_given
&& !_dumper
.list_submodes().empty()) {
205 std::cerr
<< "Mode required for this dumper" << std::endl
;
208 if(mode_given
&& _dumper
.list_submodes().empty()) {
209 std::cerr
<< "This dumper does not have mode select" << std::endl
;
212 if(mode_given
&& !_dumper
.list_submodes().count(mode
)) {
213 std::cerr
<< "'" << mode
<< "' is not a valid mode for '" << dumper
<< "'" << std::endl
;
217 std::cerr
<< "--length=<frames> has to be specified" << std::endl
;
220 return locate_dumper(dumper
);
224 int main(int argc
, char** argv
)
227 std::vector
<std::string
> cmdline
;
228 for(int i
= 1; i
< argc
; i
++)
229 cmdline
.push_back(argv
[i
]);
231 std::string mode
, prefix
;
233 adv_dumper
& dumper
= get_dumper(cmdline
, mode
, prefix
, length
);
239 messages
<< "lsnes version: lsnes rr" << lsnes_version
<< std::endl
;
240 messages
<< "Command line is: ";
241 for(auto k
= cmdline
.begin(); k
!= cmdline
.end(); k
++)
242 messages
<< "\"" << *k
<< "\" ";
243 messages
<< std::endl
;
245 std::string cfgpath
= get_config_path();
246 autoload_libraries();
248 for(auto i
: cmdline
) {
250 if(r
= regex("--setting-(.*)=(.*)", i
)) {
252 lsnes_set
.set(r
[1], r
[2]);
253 std::cerr
<< "Set " << r
[1] << " to '" << r
[2] << "'" << std::endl
;
254 } catch(std::exception
& e
) {
255 std::cerr
<< "Can't set " << r
[1] << " to '" << r
[2] << "': " << e
.what() << std::endl
;
258 if(r
= regex("--clear-setting-(.*)", i
)) {
260 lsnes_set
.blank(r
[1]);
261 std::cerr
<< "Blanked " << r
[1] << std::endl
;
262 } catch(std::exception
& e
) {
263 std::cerr
<< "Can't blank " << r
[1] << ": " << e
.what() << std::endl
;
268 messages
<< "--- Loading ROM ---" << std::endl
;
271 std::map
<std::string
, std::string
> tmp
;
272 r
= load_rom_from_commandline(cmdline
);
273 r
.load(tmp
, 1000000000, 0);
274 messages
<< "Using core: " << r
.rtype
->get_core_identifier() << std::endl
;
275 } catch(std::bad_alloc
& e
) {
277 } catch(std::exception
& e
) {
278 messages
<< "FATAL: Can't load ROM: " << e
.what() << std::endl
;
282 messages
<< "Detected region: " << r
.rtype
->combine_region(*r
.region
).get_name() << std::endl
;
283 set_nominal_framerate(r
.region
->approx_framerate());
285 messages
<< "--- Internal memory mappings ---" << std::endl
;
287 messages
<< "--- End of Startup --- " << std::endl
;
293 for(auto i
= cmdline
.begin(); i
!= cmdline
.end(); i
++)
294 if(i
->length() > 0 && (*i
)[0] != '-') {
297 movie
= moviefile(*i
, *r
.rtype
);
299 } catch(std::bad_alloc
& e
) {
301 } catch(std::exception
& e
) {
302 messages
<< "Error loading '" << *i
<< "': " << e
.what() << std::endl
;
306 throw std::runtime_error("Specifying movie is required");
308 throw std::runtime_error("Can't load any of the movies specified");
309 //Load ROM before starting the dumper.
311 messages
<< "Using core: " << our_rom
->rtype
->get_core_identifier() << std::endl
;
312 our_rom
->region
= &movie
.gametype
->get_region();
313 our_rom
->load(movie
.settings
, movie
.movie_rtc_second
, movie
.movie_rtc_subsecond
);
314 startup_lua_scripts(cmdline
);
315 dumper_startup(dumper
, mode
, prefix
, length
);
316 main_loop(r
, movie
, true);
317 } catch(std::bad_alloc
& e
) {
319 } catch(std::exception
& e
) {
320 messages
<< "FATAL: " << e
.what() << std::endl
;
324 information_dispatch::do_dump_end();