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