Lua: Don't lua_error() out of context with pending dtors
[lsnes.git] / src / library / recentfiles.cpp
blob369fae26875c90130566e749304871786bb5d059
1 #include "recentfiles.hpp"
2 #include "zip.hpp"
3 #include "eatarg.hpp"
4 #include "json.hpp"
5 #include "string.hpp"
6 #include <fstream>
8 namespace recentfiles
10 path::path()
14 path::path(const std::string& p)
16 pth = p;
19 std::string path::serialize() const
21 return pth;
24 path path::deserialize(const std::string& s)
26 path p(s);
27 return p;
30 std::string path::get_path() const
32 return pth;
35 bool path::check() const
37 if(pth == "")
38 return false;
39 try {
40 return zip::file_exists(pth);
41 } catch(...) {
42 return false;
46 std::string path::display() const
48 return pth;
51 bool path::operator==(const path& p) const
53 return p.pth == pth;
56 multirom::multirom()
58 //Nothing to do.
61 std::string multirom::serialize() const
63 bool any = false;
64 JSON::node output(JSON::object);
65 if(packfile != "") {
66 output["pack"] = JSON::string(packfile);
67 } else if(singlefile != "") {
68 output["file"] = JSON::string(singlefile);
69 if(core != "") output["core"] = JSON::string(core);
70 if(system != "") output["system"] = JSON::string(system);
71 if(region != "") output["region"] = JSON::string(region);
72 } else {
73 output["files"] = JSON::array();
74 JSON::node& f = output["files"];
75 for(auto i : files) {
76 f.append(JSON::string(i));
77 if(i != "")
78 any = true;
80 if(core != "") output["core"] = JSON::string(core);
81 if(system != "") output["system"] = JSON::string(system);
82 if(region != "") output["region"] = JSON::string(region);
84 if(packfile != "" || singlefile != "" || core != "" || system != "" || region != "") any = true;
85 if(!any) return "";
86 return output.serialize();
89 multirom multirom::deserialize(const std::string& s)
91 multirom r;
92 if(s.length() > 0 && s[0] == '{') {
93 //JSON.
94 try {
95 JSON::node d(s);
96 if(d.field_exists("pack")) r.packfile = d["pack"].as_string8();
97 if(d.field_exists("file")) r.singlefile = d["file"].as_string8();
98 if(d.field_exists("core")) r.core = d["core"].as_string8();
99 if(d.field_exists("system")) r.system = d["system"].as_string8();
100 if(d.field_exists("region")) r.region= d["region"].as_string8();
101 if(d.field_exists("files")) {
102 size_t cnt = d["files"].index_count();
103 r.files.resize(cnt);
104 for(unsigned i = 0; i < cnt; i++)
105 r.files[i] = d["files"].index(i).as_string8();
107 } catch(...) {
108 r.packfile = "";
109 r.singlefile = "";
110 r.core = "";
111 r.system = "";
112 r.region = "";
113 r.files.clear();
115 } else {
116 //Legacy form.
117 r.packfile = s;
119 return r;
122 bool multirom::check() const
124 if(packfile == "" && singlefile == "" && core == "" && system == "" && region == "" && files.empty())
125 return false;
126 if(packfile != "" && !zip::file_exists(packfile))
127 return false;
128 if(singlefile != "" && !zip::file_exists(singlefile))
129 return false;
130 for(auto i : files)
131 if(i != "" && !zip::file_exists(i))
132 return false;
133 return true;
136 std::string multirom::display() const
138 if(packfile != "")
139 return packfile;
140 if(singlefile != "") {
141 return singlefile + " <" + core + "/" + system + ">";
142 } else {
143 if(files.size() > 1 && files[1] != "")
144 return (stringfmt() << files[1] << " (+" << files.size() << ")").str();
145 else if(files.size() > 0)
146 return (stringfmt() << files[0] << " (+" << files.size() << ")").str();
147 else
148 return "(blank) <" + core + "/" + system + ">";
152 bool multirom::operator==(const multirom& p) const
154 if(packfile != p.packfile)
155 return false;
156 if(singlefile != p.singlefile)
157 return false;
158 if(core != p.core)
159 return false;
160 if(system != p.system)
161 return false;
162 if(region != p.region)
163 return false;
164 if(files.size() != p.files.size())
165 return false;
166 for(unsigned i = 0; i < files.size(); i++)
167 if(files[i] != p.files[i])
168 return false;
169 return true;
172 namedobj::namedobj()
176 std::string namedobj::serialize() const
178 if(_id == "" && _filename == "" && _display == "") return "";
179 JSON::node output(JSON::object);
180 output["id"] = JSON::string(_id);
181 output["filename"] = JSON::string(_filename);
182 output["display"] = JSON::string(_display);
183 return output.serialize();
186 namedobj namedobj::deserialize(const std::string& s)
188 namedobj obj;
189 JSON::node d(s);
190 if(d.field_exists("id")) obj._id = d["id"].as_string8();
191 if(d.field_exists("filename")) obj._filename = d["filename"].as_string8();
192 if(d.field_exists("display")) obj._display = d["display"].as_string8();
193 return obj;
196 bool namedobj::check() const
198 return zip::file_exists(_filename);
201 std::string namedobj::display() const
203 return _display;
206 bool namedobj::operator==(const namedobj& p) const
208 return (_id == p._id);
211 template<class T> set<T>::set(const std::string& _cfgfile, size_t _maxcount)
213 cfgfile = _cfgfile;
214 maxcount = _maxcount;
217 template<class T> void set<T>::add(const T& file)
219 std::list<T> ents;
220 //Load the list.
222 std::ifstream in(cfgfile);
223 std::string f;
224 while(in) {
225 std::getline(in, f);
226 T g;
227 try {
228 g = T::deserialize(f);
229 } catch(...) {
230 continue;
232 if(g.check())
233 ents.push_back(g);
236 //Search for matches. If found, move to front, otherwise push to first.
237 auto itr = ents.begin();
238 for(; itr != ents.end(); itr++)
239 if(*itr == file)
240 break;
241 if(itr != ents.end())
242 ents.erase(itr);
243 ents.push_front(file);
244 //Write up to maxcount entries.
246 size_t i = 0;
247 std::ofstream out(cfgfile);
248 for(itr = ents.begin(); itr != ents.end() && i < maxcount; itr++, i++)
249 out << itr->serialize() << std::endl;
251 for(auto i : hooks)
252 (*i)();
255 template<class T> void set<T>::add_hook(hook& h)
257 hooks.push_back(&h);
260 template<class T> void set<T>::remove_hook(hook& h)
262 for(auto itr = hooks.begin(); itr != hooks.end(); itr++)
263 if(*itr == &h) {
264 hooks.erase(itr);
265 break;
269 template<class T> std::list<T> set<T>::get()
271 size_t c = 0;
272 std::list<T> ents;
273 //Load the list.
275 std::ifstream in(cfgfile);
276 std::string f;
277 while(in) {
278 std::getline(in, f);
279 T g;
280 try {
281 g = T::deserialize(f);
282 } catch(...) {
283 continue;
285 if(c < maxcount && g.check()) {
286 ents.push_back(g);
287 c++;
291 return ents;
294 hook::~hook()
298 void _dummy_63263632747434353545()
300 set<path> x("", 0);
301 eat_argument(&set<path>::add);
302 eat_argument(&set<path>::add_hook);
303 eat_argument(&set<path>::remove_hook);
304 eat_argument(&set<path>::get);
305 set<multirom> y("", 0);
306 eat_argument(&set<multirom>::add);
307 eat_argument(&set<multirom>::add_hook);
308 eat_argument(&set<multirom>::remove_hook);
309 eat_argument(&set<multirom>::get);
310 set<namedobj> z("", 0);
311 eat_argument(&set<namedobj>::add);
312 eat_argument(&set<namedobj>::add_hook);
313 eat_argument(&set<namedobj>::remove_hook);
314 eat_argument(&set<namedobj>::get);