Fix SA1 open bus
[lsnes.git] / src / core / actions.cpp
blobe45f74ae80692110b2db17aeb807923312d9b155
1 #include "core/command.hpp"
2 #include "core/rom.hpp"
3 #include "core/moviedata.hpp"
4 #include "interface/romtype.hpp"
6 namespace
8 command::fnptr<const std::string&> action(lsnes_cmd, "action", "Execute core action",
9 "Syntax: action <name> [<params>...]\nExecutes core action.\n",
10 [](const std::string& _args) throw(std::bad_alloc, std::runtime_error) {
11 if(_args == "") {
12 messages << "Action name required." << std::endl;
13 return;
15 token_iterator<char> itr(_args, {" ", "\t"});
16 token_iterator<char> itre;
17 std::string sym = *itr++;
18 const interface_action* act = NULL;
19 for(auto i : our_rom.rtype->get_actions())
20 if(i->get_symbol() == sym) {
21 act = i;
22 break;
24 if(!act) {
25 messages << "No such action." << std::endl;
26 return;
28 if(!(our_rom.rtype->action_flags(act->id) & 1)) {
29 messages << "Action not enabled." << std::endl;
30 return;
32 std::vector<interface_action_paramval> params;
33 for(auto i : act->params) {
34 if(regex_match("toggle", i.model)) {
35 interface_action_paramval pv;
36 params.push_back(pv);
37 continue;
39 if(itr == itre) {
40 messages << "Action needs more parameters." << std::endl;
41 return;
43 std::string p = *itr++;
44 regex_results r;
45 interface_action_paramval pv;
46 if(r = regex("string(:(.*))?", i.model)) {
47 try {
48 if(r[2] != "" && !regex_match(r[2], p)) {
49 messages << "String does not satisfy constraints."
50 << std::endl;
51 return;
53 } catch(...) {
54 messages << "Internal error: Bad constraint in '" << i.model << "'."
55 << std::endl;
56 return;
58 pv.s = p;
59 } else if(r = regex("int:([0-9]+),([0-9]+)", i.model)) {
60 int64_t low, high, v;
61 try {
62 low = parse_value<int64_t>(r[1]);
63 high = parse_value<int64_t>(r[2]);
64 } catch(...) {
65 messages << "Internal error: Unknown limits in '" << i.model << "'."
66 << std::endl;
67 return;
69 try {
70 v = parse_value<int64_t>(p);
71 } catch(...) {
72 messages << "Can't parse parameter as integer." << std::endl;
73 return;
75 if(v < low || v > high) {
76 messages << "Parameter out of limits." << std::endl;
77 return;
79 pv.i = v;
80 } else if(r = regex("enum:(.*)", i.model)) {
81 try {
82 JSON::node e(r[1]);
83 unsigned num = 0;
84 for(auto i : e) {
85 std::string n;
86 if(i.type() == JSON::string)
87 n = i.as_string8();
88 else if(i.type() == JSON::array)
89 n = i.index(0).as_string8();
90 else
91 throw std::runtime_error("Choice not array nor "
92 "string");
93 if(n == p)
94 goto out;
95 num++;
97 messages << "Invalid choice for enumeration." << std::endl;
98 return;
99 out:
100 pv.i = num;
101 } catch(std::exception& e) {
102 messages << "JSON parse error parsing " << "model: "
103 << e.what() << std::endl;
104 return;
106 } else if(regex_match("bool", i.model)) {
107 int r = string_to_bool(p);
108 if(r < 0) {
109 messages << "Bad value for boolean parameter." << std::endl;
110 return;
112 pv.b = (r > 0);
113 } else if(regex_match("toggle", i.model)) {
114 } else {
115 messages << "Internal error: Unknown parameter model '" << i.model << "'."
116 << std::endl;
117 return;
119 params.push_back(pv);
121 if(itr != itre) {
122 messages << "Excess parameters for action." << std::endl;
123 return;
125 our_rom.rtype->execute_action(act->id, params);