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