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