bsnes: redump sprite/palette functions
[lsnes.git] / src / library / string.cpp
blob04ee7750b1cf6bd40cdb389e31c6ddcbc8d0f021
1 #include "string.hpp"
2 #include "minmax.hpp"
3 #include "threadtypes.hpp"
4 #include "eatarg.hpp"
5 #include <cctype>
6 #include <boost/regex.hpp>
7 #include "map-pointer.hpp"
9 std::string strip_CR(const std::string& str)
11 std::string x = str;
12 istrip_CR(x);
13 return x;
16 void istrip_CR(std::string& str)
18 size_t crc = 0;
19 size_t xl = str.length();
20 while(crc < xl) {
21 char y = str[xl - crc - 1];
22 if(y != '\r' && y != '\n')
23 break;
24 crc++;
26 str = str.substr(0, xl - crc);
29 int firstchar(const std::string& str)
31 if(str.length())
32 return static_cast<unsigned char>(str[0]);
33 else
34 return -1;
37 int string_to_bool(const std::string& x)
39 std::string y = x;
40 for(size_t i = 0; i < y.length(); i++)
41 y[i] = tolower(y[i]);
42 if(y == "on" || y == "true" || y == "yes" || y == "1" || y == "enable" || y == "enabled")
43 return 1;
44 if(y == "off" || y == "false" || y == "no" || y == "0" || y == "disable" || y == "disabled")
45 return 0;
46 return -1;
49 regex_results::regex_results()
51 matched = false;
54 regex_results::regex_results(std::vector<std::string> res, std::vector<std::pair<size_t, size_t>> mch)
56 matched = true;
57 matches = mch;
58 results = res;
61 regex_results::operator bool() const
63 return matched;
66 bool regex_results::operator!() const
68 return !matched;
71 size_t regex_results::size() const
73 return results.size();
76 const std::string& regex_results::operator[](size_t i) const
78 return results[i];
81 std::pair<size_t, size_t> regex_results::match(size_t i) const
83 return matches[i];
86 regex_results regex(const std::string& regexp, const std::string& str, const char* ex) throw(std::bad_alloc,
87 std::runtime_error)
89 static mutex_class m;
90 umutex_class h(m);
91 static std::map<std::string, map_pointer<boost::regex>> regexps;
92 if(!regexps.count(regexp)) {
93 boost::regex* y = NULL;
94 try {
95 y = new boost::regex(regexp, boost::regex::extended & ~boost::regex::collate);
96 regexps[regexp] = y;
97 } catch(std::bad_alloc& e) {
98 delete y;
99 throw;
100 } catch(std::exception& e) {
101 throw std::runtime_error(e.what());
105 boost::smatch matches;
106 bool x = boost::regex_match(str.begin(), str.end(), matches, *(regexps[regexp]));
107 if(x) {
108 std::vector<std::string> res;
109 std::vector<std::pair<size_t, size_t>> mch;
110 for(size_t i = 0; i < matches.size(); i++) {
111 res.push_back(matches.str(i));
112 mch.push_back(std::make_pair(matches[i].first - str.begin(),
113 matches[i].second - matches[i].first));
115 return regex_results(res, mch);
116 } else if(ex)
117 throw std::runtime_error(ex);
118 else
119 return regex_results();
122 bool regex_match(const std::string& regexp, const std::string& str) throw(std::bad_alloc, std::runtime_error)
124 return regex(regexp, str);
127 namespace
129 template<typename ch>
130 std::list<std::basic_string<ch>> _split_on_codepoint(const std::basic_string<ch>& s,
131 const std::basic_string<ch>& cp)
133 std::list<std::basic_string<ch>> ret;
134 size_t start = 0;
135 size_t end = 0;
136 size_t len = s.length();
137 while(end < len) {
138 end = s.find(cp, start);
139 std::basic_string<ch> x;
140 if(end < len) {
141 x.resize(end - start);
142 std::copy(s.begin() + start, s.begin() + end, x.begin());
143 start = end + cp.length();
144 } else {
145 x.resize(len - start);
146 std::copy(s.begin() + start, s.end(), x.begin());
148 ret.push_back(x);
150 return ret;
154 template<typename T>
155 string_list<T>::string_list()
159 template<typename T>
160 string_list<T>::string_list(const std::list<std::basic_string<T>>& list)
162 v.resize(list.size());
163 std::copy(list.begin(), list.end(), v.begin());
166 template<typename T>
167 bool string_list<T>::empty()
169 return (v.size() == 0);
172 template<typename T>
173 string_list<T> string_list<T>::strip_one() const
175 return string_list<T>(&v[0], (v.size() > 0) ? (v.size() - 1) : 0);
178 template<typename T>
179 size_t string_list<T>::size() const
181 return v.size();
184 template<typename T>
185 const std::basic_string<T>& string_list<T>::operator[](size_t idx) const
187 if(idx >= v.size())
188 throw std::runtime_error("Index out of range");
189 return v[idx];
192 template<typename T>
193 string_list<T>::string_list(const std::basic_string<T>* array, size_t arrsize)
195 v.resize(arrsize);
196 std::copy(array, array + arrsize, v.begin());
199 template<typename T>
200 bool string_list<T>::operator<(const string_list<T>& x) const
202 for(size_t i = 0; i < v.size() && i < x.v.size(); i++)
203 if(v[i] < x.v[i])
204 return true;
205 else if(v[i] > x.v[i])
206 return false;
207 return (v.size() < x.v.size());
210 template<typename T>
211 bool string_list<T>::operator==(const string_list<T>& x) const
213 if(v.size() != x.v.size())
214 return false;
215 for(size_t i = 0; i < v.size(); i++)
216 if(v[i] != x.v[i])
217 return false;
218 return true;
221 template<typename T>
222 bool string_list<T>::prefix_of(const string_list<T>& x) const
224 if(v.size() > x.v.size())
225 return false;
226 for(size_t i = 0; i < v.size(); i++)
227 if(v[i] != x.v[i])
228 return false;
229 return true;
232 namespace
234 template<typename T> std::basic_string<T> separator();
235 template<> std::basic_string<char> separator()
237 return utf8::to8(U"\u2023");
240 template<> std::basic_string<char16_t> separator()
242 return u"\u2023";
245 template<> std::basic_string<char32_t> separator()
247 return U"\u2023";
250 template<> std::basic_string<wchar_t> separator()
252 return L"->";
256 template<typename T>
257 std::basic_string<T> string_list<T>::debug_name() const
259 std::basic_stringstream<T> x;
260 for(size_t i = 0; i < v.size(); i++)
261 if(i != 0)
262 x << separator<T>() << v[i];
263 else
264 x << v[i];
265 return x.str();
268 template class string_list<char>;
269 template class string_list<wchar_t>;
270 template class string_list<char16_t>;
271 template class string_list<char32_t>;
274 string_list<char> split_on_codepoint(const std::string& s, char32_t cp)
276 std::string _cp = utf8::to8(std::u32string(1, cp));
277 return _split_on_codepoint<char>(s, _cp);
280 string_list<char32_t> split_on_codepoint(const std::u32string& s, char32_t cp)
282 std::u32string _cp(1, cp);
283 return _split_on_codepoint<char32_t>(s, _cp);
286 template<typename T> void token_iterator<T>::ctor_eos()
288 is_end_iterator = true;
291 template<typename T> void token_iterator<T>::ctor_itr(std::initializer_list<const T*> sep, bool whole_sequence)
292 throw(std::bad_alloc)
294 whole_seq = whole_sequence;
295 is_end_iterator = false;
296 bidx = 0;
297 eidx = 0;
298 for(auto i : sep)
299 spliton.insert(i);
300 load_helper();
303 template<typename T> bool token_iterator<T>::equals_op(const token_iterator<T>& itr) const throw()
305 bool is_end_a = is_end_iterator || (bidx >= str.length());
306 bool is_end_b = itr.is_end_iterator || (itr.bidx >= itr.str.length());
307 if(is_end_a)
308 if(is_end_b)
309 return true;
310 else
311 return false;
312 else
313 if(is_end_b)
314 return false;
315 else
316 return bidx == itr.bidx;
319 template<typename T> const std::basic_string<T>& token_iterator<T>::dereference() const throw()
321 return tmp;
324 template<typename T> token_iterator<T> token_iterator<T>::postincrement() throw(std::bad_alloc)
326 token_iterator<T> t = *this;
327 ++*this;
328 return t;
331 template<typename T> token_iterator<T>& token_iterator<T>::preincrement() throw(std::bad_alloc)
333 bidx = eidx + is_sep(eidx);
334 load_helper();
335 return *this;
338 template<typename T> void token_iterator<T>::load_helper()
340 size_t t;
341 if(whole_seq)
342 while(bidx < str.length() && (t = is_sep(bidx)))
343 bidx += t;
344 eidx = bidx;
345 while(eidx < str.length() && !is_sep(eidx))
346 eidx++;
347 tmp.resize(eidx - bidx);
348 std::copy(str.begin() + bidx, str.begin() + eidx, tmp.begin());
351 template<typename T> size_t token_iterator<T>::is_sep(size_t pos)
353 if(pos >= str.length())
354 return 0;
355 std::basic_string<T> h(1, str[pos++]);
356 while(true) {
357 if(spliton.count(h))
358 return h.length();
359 auto i = spliton.lower_bound(h);
360 //If string at i is end-of-set or does not start with h, there can't be a match.
361 if(i == spliton.end())
362 return 0;
363 std::basic_string<T> i2 = *i;
364 if(i2.length() < h.length() || (i2.substr(0, h.length()) != h))
365 return 0;
366 h = h + std::basic_string<T>(1, str[pos++]);
370 template<typename T> void token_iterator<T>::pull_fn()
372 eat_argument(&token_iterator<T>::ctor_itr);
373 eat_argument(&token_iterator<T>::ctor_eos);
374 eat_argument(&token_iterator<T>::postincrement);
375 eat_argument(&token_iterator<T>::preincrement);
376 eat_argument(&token_iterator<T>::dereference);
377 eat_argument(&token_iterator<T>::equals_op);
378 eat_argument(&token_iterator<T>::is_sep);
379 eat_argument(&token_iterator<T>::load_helper);
382 namespace
384 template<typename T> void pull_token_itr()
386 token_iterator<T>::pull_fn();
389 void pull_token_itr2()
391 pull_token_itr<char>();
392 pull_token_itr<char32_t>();
396 void _dummy_63263896236732867328673826783276283673867()
398 pull_token_itr2();