openMSX
StringOp.cc
Go to the documentation of this file.
1 #include "StringOp.hh"
2 #include "MSXException.hh"
3 #include "likely.hh"
4 #include "ranges.hh"
5 #include "stl.hh"
6 #include "view.hh"
7 #include <cstdlib>
8 #include <stdexcept>
9 
10 using std::string;
11 using std::string_view;
12 using std::vector;
13 
14 namespace StringOp {
15 
16 bool stringToBool(string_view str)
17 {
18  if (str == "1") return true;
19  if ((str.size() == 4) && (strncasecmp(str.data(), "true", 4) == 0))
20  return true;
21  if ((str.size() == 3) && (strncasecmp(str.data(), "yes", 3) == 0))
22  return true;
23  return false;
24 }
25 
26 //string toLower(string_view str)
27 //{
28 // string result(str);
29 // transform_in_place(result, ::tolower);
30 // return result;
31 //}
32 
33 bool startsWith(string_view total, string_view part)
34 {
35  return (total.size() >= part.size()) &&
36  (memcmp(total.data(), part.data(), part.size()) == 0);
37 }
38 bool startsWith(string_view total, char part)
39 {
40  return !total.empty() && (total.front() == part);
41 }
42 
43 bool endsWith(string_view total, string_view part)
44 {
45  return (total.size() >= part.size()) &&
46  (memcmp(total.data() + total.size() - part.size(), part.data(), part.size()) == 0);
47 }
48 bool endsWith(string_view total, char part)
49 {
50  return !total.empty() && (total.back() == part);
51 }
52 
53 void trimRight(string& str, const char* chars)
54 {
55  if (auto pos = str.find_last_not_of(chars); pos != string::npos) {
56  str.erase(pos + 1);
57  } else {
58  str.clear();
59  }
60 }
61 void trimRight(string& str, char chars)
62 {
63  if (auto pos = str.find_last_not_of(chars); pos != string::npos) {
64  str.erase(pos + 1);
65  } else {
66  str.clear();
67  }
68 }
69 void trimRight(string_view& str, string_view chars)
70 {
71  while (!str.empty() && (chars.find(str.back()) != string_view::npos)) {
72  str.remove_suffix(1);
73  }
74 }
75 void trimRight(string_view& str, char chars)
76 {
77  while (!str.empty() && (str.back() == chars)) {
78  str.remove_suffix(1);
79  }
80 }
81 
82 void trimLeft(string& str, const char* chars)
83 {
84  str.erase(0, str.find_first_not_of(chars));
85 }
86 void trimLeft(string& str, char chars)
87 {
88  str.erase(0, str.find_first_not_of(chars));
89 }
90 void trimLeft(string_view& str, string_view chars)
91 {
92  while (!str.empty() && (chars.find(str.front()) != string_view::npos)) {
93  str.remove_prefix(1);
94  }
95 }
96 void trimLeft(string_view& str, char chars)
97 {
98  while (!str.empty() && (str.front() == chars)) {
99  str.remove_prefix(1);
100  }
101 }
102 
103 void trim(string_view& str, string_view chars)
104 {
105  trimRight(str, chars);
106  trimLeft (str, chars);
107 }
108 
109 void trim(string_view& str, char chars)
110 {
111  trimRight(str, chars);
112  trimLeft (str, chars);
113 }
114 
115 std::pair<string_view, string_view> splitOnFirst(string_view str, string_view chars)
116 {
117  if (auto pos = str.find_first_of(chars); pos == string_view::npos) {
118  return {str, string_view{}};
119  } else {
120  return {str.substr(0, pos), str.substr(pos + 1)};
121  }
122 }
123 std::pair<string_view, string_view> splitOnFirst(string_view str, char chars)
124 {
125  if (auto pos = str.find_first_of(chars); pos == string_view::npos) {
126  return {str, string_view{}};
127  } else {
128  return {str.substr(0, pos), str.substr(pos + 1)};
129  }
130 }
131 
132 std::pair<string_view, string_view> splitOnLast(string_view str, string_view chars)
133 {
134  if (auto pos = str.find_last_of(chars); pos == string_view::npos) {
135  return {string_view{}, str};
136  } else {
137  return {str.substr(0, pos), str.substr(pos + 1)};
138  }
139 }
140 std::pair<string_view, string_view> splitOnLast(string_view str, char chars)
141 {
142  if (auto pos = str.find_last_of(chars); pos == string_view::npos) {
143  return {string_view{}, str};
144  } else {
145  return {str.substr(0, pos), str.substr(pos + 1)};
146  }
147 }
148 
149 vector<string_view> split(string_view str, char chars)
150 {
151  vector<string_view> result;
152  while (!str.empty()) {
153  auto [first, last] = splitOnFirst(str, chars);
154  result.push_back(first);
155  str = last;
156  }
157  return result;
158 }
159 
160 static unsigned parseNumber(string_view str)
161 {
162  trim(str, " \t");
163  auto r = stringToBase<10, unsigned>(str);
164  if (!r) {
165  throw openmsx::MSXException("Invalid integer: ", str);
166  }
167  return *r;
168 }
169 
170 static void insert(unsigned x, vector<unsigned>& result, unsigned min, unsigned max)
171 {
172  if ((x < min) || (x > max)) {
173  throw openmsx::MSXException("Out of range");
174  }
175  if (auto it = ranges::lower_bound(result, x);
176  (it == end(result)) || (*it != x)) {
177  result.insert(it, x);
178  }
179 }
180 
181 static void parseRange2(string_view str, vector<unsigned>& result,
182  unsigned min, unsigned max)
183 {
184  // trimRight only: here we only care about all spaces
185  trimRight(str, " \t");
186  if (str.empty()) return;
187 
188  if (auto pos = str.find('-'); pos == string_view::npos) {
189  insert(parseNumber(str), result, min, max);
190  } else {
191  unsigned begin = parseNumber(str.substr(0, pos));
192  unsigned end = parseNumber(str.substr(pos + 1));
193  if (end < begin) {
194  std::swap(begin, end);
195  }
196  for (unsigned i = begin; i <= end; ++i) {
197  insert(i, result, min, max);
198  }
199  }
200 }
201 
202 vector<unsigned> parseRange(string_view str, unsigned min, unsigned max)
203 {
204  vector<unsigned> result;
205  while (true) {
206  auto next = str.find(',');
207  string_view sub = (next == string_view::npos)
208  ? str
209  : str.substr(0, next++);
210  parseRange2(sub, result, min, max);
211  if (next == string_view::npos) break;
212  str = str.substr(next);
213  }
214  return result;
215 }
216 
217 #if defined(__APPLE__)
218 
219 std::string fromCFString(CFStringRef str)
220 {
221  // Try the quick route first.
222  const char *cstr = CFStringGetCStringPtr(str, kCFStringEncodingUTF8);
223  if (cstr) {
224  // String was already in UTF8 encoding.
225  return std::string(cstr);
226  }
227 
228  // Convert to UTF8 encoding.
229  CFIndex len = CFStringGetLength(str);
230  CFRange range = CFRangeMake(0, len);
231  CFIndex usedBufLen = 0;
232  CFStringGetBytes(
233  str, range, kCFStringEncodingUTF8, '?', false, nullptr, len, &usedBufLen);
234  UInt8 buffer[usedBufLen];
235  CFStringGetBytes(
236  str, range, kCFStringEncodingUTF8, '?', false, buffer, len, &usedBufLen);
237  return std::string(reinterpret_cast<const char *>(buffer), usedBufLen);
238 }
239 
240 #endif
241 
242 } // namespace StringOp
void swap(openmsx::MemBuffer< T > &l, openmsx::MemBuffer< T > &r) noexcept
Definition: MemBuffer.hh:202
void trim(string_view &str, string_view chars)
Definition: StringOp.cc:103
bool stringToBool(string_view str)
Definition: StringOp.cc:16
std::pair< string_view, string_view > splitOnLast(string_view str, string_view chars)
Definition: StringOp.cc:132
vector< unsigned > parseRange(string_view str, unsigned min, unsigned max)
Definition: StringOp.cc:202
void trimRight(string &str, const char *chars)
Definition: StringOp.cc:53
std::pair< string_view, string_view > splitOnFirst(string_view str, string_view chars)
Definition: StringOp.cc:115
bool endsWith(string_view total, string_view part)
Definition: StringOp.cc:43
void trimLeft(string &str, const char *chars)
Definition: StringOp.cc:82
vector< string_view > split(string_view str, char chars)
Definition: StringOp.cc:149
bool startsWith(string_view total, string_view part)
Definition: StringOp.cc:33
constexpr vecN< N, T > min(const vecN< N, T > &x, const vecN< N, T > &y)
Definition: gl_vec.hh:269
constexpr vecN< N, T > max(const vecN< N, T > &x, const vecN< N, T > &y)
Definition: gl_vec.hh:287
constexpr KeyMatrixPosition x
Keyboard bindings.
Definition: Keyboard.cc:124
auto lower_bound(ForwardRange &&range, const T &value)
Definition: ranges.hh:71
constexpr auto begin(const zstring_view &x)
Definition: zstring_view.hh:82
constexpr auto end(const zstring_view &x)
Definition: zstring_view.hh:83