Lua: Don't lua_error() out of context with pending dtors
[lsnes.git] / src / library / memorywatch.cpp
blobb7f458b1f8145e79db3d41f07aebd2c03cc4fee7
1 #include "framebuffer-font2.hpp"
2 #include "memorywatch.hpp"
3 #include "memoryspace.hpp"
4 #include "int24.hpp"
5 #include "mathexpr-error.hpp"
6 #include "mathexpr.hpp"
7 #include <sstream>
8 #include "string.hpp"
10 namespace memorywatch
12 namespace
14 template<typename T> T* pointer_cast(char* ptr)
16 return reinterpret_cast<T*>(ptr);
20 memread_oper::memread_oper()
21 : operinfo("(readmemory)")
25 memread_oper::~memread_oper() {}
27 void memread_oper::evaluate(mathexpr::value target, std::vector<std::function<mathexpr::value()>> promises)
29 if(promises.size() != 1)
30 throw mathexpr::error(mathexpr::error::ARGCOUNT, "Memory read operator takes 1 argument");
31 static const int system_endian = memory_space::get_system_endian();
32 uint64_t addr;
33 mathexpr::value val;
34 try {
35 val = promises[0]();
36 void* res = val._value;
37 addr = val.type->tounsigned(res);
38 if(addr_size)
39 addr %= addr_size;
40 addr += addr_base;
41 } catch(std::exception& e) {
42 throw mathexpr::error(mathexpr::error::ADDR, e.what());
44 if(bytes > 8)
45 throw mathexpr::error(mathexpr::error::SIZE, "Memory read size out of range");
46 char buf[8];
47 mspace->read_range(addr, buf, bytes);
48 //Endian swap if needed.
49 if(system_endian != endianess)
50 for(unsigned i = 0; i < bytes / 2; i++)
51 std::swap(buf[i], buf[bytes - i - 1]);
52 switch(bytes) {
53 case 1:
54 if(float_flag)
55 throw mathexpr::error(mathexpr::error::SIZE, "1 byte floats not supported");
56 else if(signed_flag)
57 target.type->parse_s(target._value, *(const int8_t*)buf);
58 else
59 target.type->parse_u(target._value, *(const uint8_t*)buf);
60 break;
61 case 2:
62 if(float_flag)
63 throw mathexpr::error(mathexpr::error::SIZE, "2 byte floats not supported");
64 else if(signed_flag)
65 target.type->parse_s(target._value, *pointer_cast<int16_t>(buf));
66 else
67 target.type->parse_u(target._value, *pointer_cast<uint16_t>(buf));
68 break;
69 case 3:
70 if(float_flag)
71 throw mathexpr::error(mathexpr::error::SIZE, "3 byte floats not supported");
72 else if(signed_flag)
73 target.type->parse_s(target._value, *pointer_cast<ss_int24_t>(buf));
74 else
75 target.type->parse_u(target._value, *pointer_cast<ss_uint24_t>(buf));
76 break;
77 case 4:
78 if(float_flag)
79 target.type->parse_f(target._value, *pointer_cast<float>(buf));
80 else if(signed_flag)
81 target.type->parse_s(target._value, *pointer_cast<int32_t>(buf));
82 else
83 target.type->parse_u(target._value, *pointer_cast<uint32_t>(buf));
84 break;
85 case 8:
86 if(float_flag)
87 target.type->parse_f(target._value, *pointer_cast<double>(buf));
88 else if(signed_flag)
89 target.type->parse_s(target._value, *pointer_cast<int64_t>(buf));
90 else
91 target.type->parse_u(target._value, *pointer_cast<uint64_t>(buf));
92 break;
93 default:
94 throw mathexpr::error(mathexpr::error::SIZE, "Memory address size not supported");
96 if(scale_div > 1)
97 target.type->scale(target._value, scale_div);
100 namespace
102 bool is_terminal(char ch)
104 if(ch == '%') return true;
105 if(ch == 'b') return true;
106 if(ch == 'B') return true;
107 if(ch == 'd') return true;
108 if(ch == 'i') return true;
109 if(ch == 'o') return true;
110 if(ch == 's') return true;
111 if(ch == 'u') return true;
112 if(ch == 'x') return true;
113 if(ch == 'X') return true;
114 return false;
117 std::string get_placeholder(const std::string& str, size_t idx)
119 std::ostringstream p;
120 for(size_t i = idx; i < str.length(); i++) {
121 p << str[i];
122 if(is_terminal(str[idx]))
123 break;
125 return p.str();
129 bool showsign;
130 bool fillzeros;
131 int width;
132 int precision;
133 bool uppercasehex;
136 item_printer::~item_printer()
140 void item_printer::trace()
144 std::string item::get_value()
146 if(format == "") {
147 //Default.
148 mathexpr::_format fmt;
149 fmt.type = mathexpr::_format::DEFAULT;
150 mathexpr::value v = expr->evaluate();
151 return v.type->format(v._value, fmt);
153 std::ostringstream out;
154 for(size_t i = 0; i < format.length(); i++) {
155 if(format[i] != '%')
156 out << format[i];
157 else {
158 //Format placeholder.
159 std::string p = get_placeholder(format, i + 1);
160 if(p == "")
161 continue;
162 i += p.length();
163 if(p[p.length() - 1] == '%') {
164 out << '%';
165 continue;
167 mathexpr::_format fmt;
168 fmt.showsign = false;
169 fmt.fillzeros = false;
170 fmt.width = -1;
171 fmt.precision = -1;
172 fmt.uppercasehex = false;
173 auto r = regex("([+0]*)([1-9][0-9]*)?(\\.(0|[1-9][0-9]*))?([bBdiosuxX])", p);
174 if(!r) {
175 throw mathexpr::error(mathexpr::error::FORMAT, "Bad format placeholder");
176 continue;
178 std::string flags = r[1];
179 size_t i;
180 for(i = 0; i < flags.length(); i++) {
181 if(flags[i] == '+')
182 fmt.showsign = true;
183 if(flags[i] == '0')
184 fmt.fillzeros = true;
186 //The remaining part is width.precision.
187 if(r[2] != "")
188 try {
189 fmt.width = parse_value<int>(r[2]);
190 } catch(...) {}
191 if(r[4] != "")
192 try {
193 fmt.precision = parse_value<int>(r[4]);
194 } catch(...) {}
195 switch(r[5][0]) {
196 case 'b': fmt.type = mathexpr::_format::BINARY; break;
197 case 'B': fmt.type = mathexpr::_format::BOOLEAN; break;
198 case 'd': fmt.type = mathexpr::_format::DECIMAL; break;
199 case 'i': fmt.type = mathexpr::_format::DECIMAL; break;
200 case 'o': fmt.type = mathexpr::_format::OCTAL; break;
201 case 's': fmt.type = mathexpr::_format::STRING; break;
202 case 'u': fmt.type = mathexpr::_format::DECIMAL; break;
203 case 'x': fmt.type = mathexpr::_format::HEXADECIMAL; break;
204 case 'X': fmt.type = mathexpr::_format::HEXADECIMAL; fmt.uppercasehex = true; break;
206 mathexpr::value v = expr->evaluate();
207 out << v.type->format(v._value, fmt);
210 return out.str();
213 void item::show(const std::string& n)
215 std::string x;
216 try {
217 x = get_value();
218 } catch(std::bad_alloc& e) {
219 throw;
220 } catch(mathexpr::error& e) {
221 x = e.get_short_error();
222 } catch(std::runtime_error& e) {
223 x = e.what();
225 if(printer)
226 printer->show(n, x);
230 set::~set()
232 roots.clear();
233 GC::item::do_gc();
236 void set::reset()
238 for(auto& i : roots) {
239 if(i.second.printer)
240 i.second.printer->reset();
241 i.second.expr->reset();
245 void set::refresh()
247 for(auto& i : roots)
248 i.second.expr->reset();
249 for(auto& i : roots)
250 i.second.show(i.first);
253 std::set<std::string> set::names_set()
255 std::set<std::string> r;
256 for(auto i : roots)
257 r.insert(i.first);
258 return r;
261 item& set::get(const std::string& name)
263 auto i = get_soft(name);
264 if(!i)
265 throw std::runtime_error("No such watch '" + name + "'");
266 return *i;
269 item* set::get_soft(const std::string& name)
271 if(!roots.count(name))
272 return NULL;
273 return &(roots.find(name)->second);
276 item* set::create(const std::string& name, item& item)
278 roots.insert(std::make_pair(name, item));
279 return &(roots.find(name)->second);
282 void set::destroy(const std::string& name)
284 if(!roots.count(name))
285 return;
286 roots.erase(name);
287 GC::item::do_gc();
290 const std::string& set::get_longest_name(std::function<size_t(const std::string& n)> rate)
292 static std::string empty;
293 size_t best_len = 0;
294 const std::string* best = &empty;
295 for(auto& i : roots) {
296 size_t r = rate(i.first);
297 if(r > best_len) {
298 best = &i.first;
299 best_len = r;
302 return *best;
305 size_t set::utflength_rate(const std::string& n)
307 return utf8::strlen(n);
310 void set::foreach(std::function<void(item& item)> cb)
312 for(auto& i : roots)
313 cb(i.second);
316 void set::swap(set& s) throw()
318 std::swap(roots, s.roots);