Some tweaks to Lua docs
[lsnes.git] / src / library / memorywatch.cpp
blob268269cd0ecad92e0517222ce2cae176aa6e2c60
1 #include "memorywatch.hpp"
2 #include "int24.hpp"
3 #include "mathexpr-error.hpp"
4 #include <sstream>
5 #include "string.hpp"
7 memorywatch_memread_oper::memorywatch_memread_oper()
8 : mathexpr_operinfo("(readmemory)")
12 memorywatch_memread_oper::~memorywatch_memread_oper() {}
14 void memorywatch_memread_oper::evaluate(mathexpr_value target, std::vector<std::function<mathexpr_value()>> promises)
16 if(promises.size() != 1)
17 throw mathexpr_error(mathexpr_error::ARGCOUNT, "Memory read operator takes 1 argument");
18 static const int system_endian = memory_space::get_system_endian();
19 uint64_t addr;
20 mathexpr_value val;
21 try {
22 val = promises[0]();
23 void* res = val.value;
24 addr = val.type->tounsigned(res);
25 if(addr_size)
26 addr %= addr_size;
27 addr += addr_base;
28 } catch(std::exception& e) {
29 throw mathexpr_error(mathexpr_error::ADDR, e.what());
31 if(bytes > 8)
32 throw mathexpr_error(mathexpr_error::SIZE, "Memory read size out of range");
33 char buf[8];
34 mspace->read_range(addr, buf, bytes);
35 //Endian swap if needed.
36 if(system_endian != endianess)
37 for(unsigned i = 0; i < bytes / 2; i++)
38 std::swap(buf[i], buf[bytes - i - 1]);
39 switch(bytes) {
40 case 1:
41 if(float_flag)
42 throw mathexpr_error(mathexpr_error::SIZE, "1 byte floats not supported");
43 else if(signed_flag)
44 target.type->parse_s(target.value, *(int8_t*)buf);
45 else
46 target.type->parse_u(target.value, *(uint8_t*)buf);
47 break;
48 case 2:
49 if(float_flag)
50 throw mathexpr_error(mathexpr_error::SIZE, "2 byte floats not supported");
51 else if(signed_flag)
52 target.type->parse_s(target.value, *(int16_t*)buf);
53 else
54 target.type->parse_u(target.value, *(uint16_t*)buf);
55 break;
56 case 3:
57 if(float_flag)
58 throw mathexpr_error(mathexpr_error::SIZE, "3 byte floats not supported");
59 else if(signed_flag)
60 target.type->parse_s(target.value, *(ss_int24_t*)buf);
61 else
62 target.type->parse_u(target.value, *(ss_uint24_t*)buf);
63 break;
64 case 4:
65 if(float_flag)
66 target.type->parse_f(target.value, *(float*)buf);
67 else if(signed_flag)
68 target.type->parse_s(target.value, *(int32_t*)buf);
69 else
70 target.type->parse_u(target.value, *(uint32_t*)buf);
71 break;
72 case 8:
73 if(float_flag)
74 target.type->parse_f(target.value, *(double*)buf);
75 else if(signed_flag)
76 target.type->parse_s(target.value, *(int64_t*)buf);
77 else
78 target.type->parse_u(target.value, *(uint64_t*)buf);
79 break;
80 default:
81 throw mathexpr_error(mathexpr_error::SIZE, "Memory address size not supported");
83 if(scale_div > 1)
84 target.type->scale(target.value, scale_div);
87 namespace
89 bool is_terminal(char ch)
91 if(ch == '%') return true;
92 if(ch == 'b') return true;
93 if(ch == 'B') return true;
94 if(ch == 'd') return true;
95 if(ch == 'i') return true;
96 if(ch == 'o') return true;
97 if(ch == 's') return true;
98 if(ch == 'u') return true;
99 if(ch == 'x') return true;
100 if(ch == 'X') return true;
101 return false;
104 std::string get_placeholder(const std::string& str, size_t idx)
106 std::ostringstream p;
107 for(size_t i = idx; i < str.length(); i++) {
108 p << str[i];
109 if(is_terminal(str[idx]))
110 break;
112 return p.str();
116 bool showsign;
117 bool fillzeros;
118 int width;
119 int precision;
120 bool uppercasehex;
123 memorywatch_item_printer::~memorywatch_item_printer()
127 void memorywatch_item_printer::trace()
131 std::string memorywatch_item::get_value()
133 if(format == "") {
134 //Default.
135 mathexpr_format fmt;
136 fmt.type = mathexpr_format::DEFAULT;
137 mathexpr_value v = expr->evaluate();
138 return v.type->format(v.value, fmt);
140 std::ostringstream out;
141 for(size_t i = 0; i < format.length(); i++) {
142 if(format[i] != '%')
143 out << format[i];
144 else {
145 //Format placeholder.
146 std::string p = get_placeholder(format, i + 1);
147 if(p == "")
148 continue;
149 i += p.length();
150 if(p[p.length() - 1] == '%') {
151 out << '%';
152 continue;
154 mathexpr_format fmt;
155 fmt.showsign = false;
156 fmt.fillzeros = false;
157 fmt.width = -1;
158 fmt.precision = -1;
159 fmt.uppercasehex = false;
160 auto r = regex("([+0]*)([1-9][0-9]*)?(\\.(0|[1-9][0-9]*))?([bBdiosuxX])", p);
161 if(!r) {
162 throw mathexpr_error(mathexpr_error::FORMAT, "Bad format placeholder");
163 continue;
165 std::string flags = r[1];
166 size_t i;
167 for(i = 0; i < flags.length(); i++) {
168 if(flags[i] == '+')
169 fmt.showsign = true;
170 if(flags[i] == '0')
171 fmt.fillzeros = true;
173 //The remaining part is width.precision.
174 if(r[2] != "")
175 try {
176 fmt.width = parse_value<int>(r[2]);
177 } catch(...) {}
178 if(r[4] != "")
179 try {
180 fmt.precision = parse_value<int>(r[4]);
181 } catch(...) {}
182 switch(r[5][0]) {
183 case 'b': fmt.type = mathexpr_format::BINARY; break;
184 case 'B': fmt.type = mathexpr_format::BOOLEAN; break;
185 case 'd': fmt.type = mathexpr_format::DECIMAL; break;
186 case 'i': fmt.type = mathexpr_format::DECIMAL; break;
187 case 'o': fmt.type = mathexpr_format::OCTAL; break;
188 case 's': fmt.type = mathexpr_format::STRING; break;
189 case 'u': fmt.type = mathexpr_format::DECIMAL; break;
190 case 'x': fmt.type = mathexpr_format::HEXADECIMAL; break;
191 case 'X': fmt.type = mathexpr_format::HEXADECIMAL; fmt.uppercasehex = true; break;
193 mathexpr_value v = expr->evaluate();
194 out << v.type->format(v.value, fmt);
197 return out.str();
200 void memorywatch_item::show(const std::string& n)
202 std::string x;
203 try {
204 x = get_value();
205 } catch(std::bad_alloc& e) {
206 throw;
207 } catch(mathexpr_error& e) {
208 x = e.get_short_error();
209 } catch(std::runtime_error& e) {
210 x = e.what();
212 if(printer)
213 printer->show(n, x);
217 memorywatch_set::~memorywatch_set()
219 roots.clear();
220 garbage_collectable::do_gc();
223 void memorywatch_set::reset()
225 for(auto& i : roots) {
226 if(i.second.printer)
227 i.second.printer->reset();
228 i.second.expr->reset();
232 void memorywatch_set::refresh()
234 for(auto& i : roots)
235 i.second.expr->reset();
236 for(auto& i : roots)
237 i.second.show(i.first);
240 std::set<std::string> memorywatch_set::set()
242 std::set<std::string> r;
243 for(auto i : roots)
244 r.insert(i.first);
245 return r;
248 memorywatch_item& memorywatch_set::get(const std::string& name)
250 auto i = get_soft(name);
251 if(!i)
252 throw std::runtime_error("No such watch '" + name + "'");
253 return *i;
256 memorywatch_item* memorywatch_set::get_soft(const std::string& name)
258 if(!roots.count(name))
259 return NULL;
260 return &(roots.find(name)->second);
263 memorywatch_item* memorywatch_set::create(const std::string& name, memorywatch_item& item)
265 roots.insert(std::make_pair(name, item));
266 return &(roots.find(name)->second);
269 void memorywatch_set::destroy(const std::string& name)
271 if(!roots.count(name))
272 return;
273 roots.erase(name);
274 garbage_collectable::do_gc();
277 const std::string& memorywatch_set::get_longest_name(std::function<size_t(const std::string& n)> rate)
279 static std::string empty;
280 size_t best_len = 0;
281 const std::string* best = &empty;
282 for(auto& i : roots) {
283 size_t r = rate(i.first);
284 if(r > best_len) {
285 best = &i.first;
286 best_len = r;
289 return *best;
292 size_t memorywatch_set::utflength_rate(const std::string& n)
294 return utf8::strlen(n);
297 void memorywatch_set::foreach(std::function<void(memorywatch_item& item)> cb)
299 for(auto& i : roots)
300 cb(i.second);
303 void memorywatch_set::swap(memorywatch_set& s) throw()
305 std::swap(roots, s.roots);
308 #ifdef TEST_MEMORYWATCH
309 #include "mathexpr-ntype.hpp"
311 struct stdout_item_printer : public memorywatch_item_printer
313 ~stdout_item_printer()
316 void show(const std::string& n, const std::string& v)
318 std::cout << n << " --> " << v << std::endl;
320 void reset()
325 int main2(int argc, char** argv)
327 memorywatch_set mset;
328 gcroot_pointer<memorywatch_item_printer> printer(new stdout_item_printer);
329 std::function<gcroot_pointer<mathexpr>(const std::string&)> vars_fn = [&mset]
330 (const std::string& n) -> gcroot_pointer<mathexpr> {
331 auto p = mset.get_soft(n);
332 if(!p) {
333 memorywatch_item i(*expression_value());
334 p = mset.create(n, i);
336 return p->expr;
338 for(int i = 1; i < argc; i++) {
339 regex_results r = regex("([^=]+)=\\[(.*)\\](.*)", argv[i]);
340 if(!r)
341 throw std::runtime_error("Bad argument '" + std::string(argv[i]) + "'");
342 *vars_fn(r[1]) = *mathexpr::parse(*expression_value(), r[3], vars_fn);
343 mset.get(r[1]).format = r[2];
344 mset.get(r[1]).printer = printer;
346 garbage_collectable::do_gc();
347 garbage_collectable::do_gc();
348 mset.refresh();
349 return 0;
352 int main(int argc, char** argv)
354 int r = main2(argc, argv);
355 garbage_collectable::do_gc();
356 return r;
359 #endif