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