Add std::string StartsWith*/EndsWith* overloads.
We should have done this from the beginning. Thanks to Windows, we're not
going to be able to switch libbase over to std::string_view any time soon.
Bug: N/A
Test: ran tests
Change-Id: Iff2f56986e39de53f3ac484415378af17dacf26b
diff --git a/adb/socket_spec.cpp b/adb/socket_spec.cpp
index 14eb16b..eb4df97 100644
--- a/adb/socket_spec.cpp
+++ b/adb/socket_spec.cpp
@@ -118,7 +118,7 @@
bool is_socket_spec(const std::string& spec) {
for (const auto& it : kLocalSocketTypes) {
std::string prefix = it.first + ":";
- if (StartsWith(spec, prefix.c_str())) {
+ if (StartsWith(spec, prefix)) {
return true;
}
}
@@ -128,7 +128,7 @@
bool is_local_socket_spec(const std::string& spec) {
for (const auto& it : kLocalSocketTypes) {
std::string prefix = it.first + ":";
- if (StartsWith(spec, prefix.c_str())) {
+ if (StartsWith(spec, prefix)) {
return true;
}
}
@@ -170,7 +170,7 @@
for (const auto& it : kLocalSocketTypes) {
std::string prefix = it.first + ":";
- if (StartsWith(spec, prefix.c_str())) {
+ if (StartsWith(spec, prefix)) {
if (!it.second.available) {
*error = StringPrintf("socket type %s is unavailable on this platform",
it.first.c_str());
@@ -213,7 +213,7 @@
for (const auto& it : kLocalSocketTypes) {
std::string prefix = it.first + ":";
- if (StartsWith(spec, prefix.c_str())) {
+ if (StartsWith(spec, prefix)) {
if (!it.second.available) {
*error = StringPrintf("attempted to listen on unavailable socket type: '%s'",
spec.c_str());
diff --git a/base/include/android-base/strings.h b/base/include/android-base/strings.h
index f5f5c11..c11acb1 100644
--- a/base/include/android-base/strings.h
+++ b/base/include/android-base/strings.h
@@ -57,12 +57,18 @@
extern template std::string Join(const std::vector<const char*>&, const std::string&);
// Tests whether 's' starts with 'prefix'.
+// TODO: string_view
bool StartsWith(const std::string& s, const char* prefix);
bool StartsWithIgnoreCase(const std::string& s, const char* prefix);
+bool StartsWith(const std::string& s, const std::string& prefix);
+bool StartsWithIgnoreCase(const std::string& s, const std::string& prefix);
// Tests whether 's' ends with 'suffix'.
+// TODO: string_view
bool EndsWith(const std::string& s, const char* suffix);
bool EndsWithIgnoreCase(const std::string& s, const char* suffix);
+bool EndsWith(const std::string& s, const std::string& prefix);
+bool EndsWithIgnoreCase(const std::string& s, const std::string& prefix);
// Tests whether 'lhs' equals 'rhs', ignoring case.
bool EqualsIgnoreCase(const std::string& lhs, const std::string& rhs);
diff --git a/base/strings.cpp b/base/strings.cpp
index bfdaf12..a8bb2a9 100644
--- a/base/strings.cpp
+++ b/base/strings.cpp
@@ -91,12 +91,20 @@
return strncmp(s.c_str(), prefix, strlen(prefix)) == 0;
}
+bool StartsWith(const std::string& s, const std::string& prefix) {
+ return strncmp(s.c_str(), prefix.c_str(), prefix.size()) == 0;
+}
+
bool StartsWithIgnoreCase(const std::string& s, const char* prefix) {
return strncasecmp(s.c_str(), prefix, strlen(prefix)) == 0;
}
-static bool EndsWith(const std::string& s, const char* suffix, bool case_sensitive) {
- size_t suffix_length = strlen(suffix);
+bool StartsWithIgnoreCase(const std::string& s, const std::string& prefix) {
+ return strncasecmp(s.c_str(), prefix.c_str(), prefix.size()) == 0;
+}
+
+static bool EndsWith(const std::string& s, const char* suffix, size_t suffix_length,
+ bool case_sensitive) {
size_t string_length = s.size();
if (suffix_length > string_length) {
return false;
@@ -106,11 +114,19 @@
}
bool EndsWith(const std::string& s, const char* suffix) {
- return EndsWith(s, suffix, true);
+ return EndsWith(s, suffix, strlen(suffix), true);
+}
+
+bool EndsWith(const std::string& s, const std::string& suffix) {
+ return EndsWith(s, suffix.c_str(), suffix.size(), true);
}
bool EndsWithIgnoreCase(const std::string& s, const char* suffix) {
- return EndsWith(s, suffix, false);
+ return EndsWith(s, suffix, strlen(suffix), false);
+}
+
+bool EndsWithIgnoreCase(const std::string& s, const std::string& suffix) {
+ return EndsWith(s, suffix.c_str(), suffix.size(), false);
}
bool EqualsIgnoreCase(const std::string& lhs, const std::string& rhs) {
diff --git a/base/strings_test.cpp b/base/strings_test.cpp
index 121197c..b8639ea 100644
--- a/base/strings_test.cpp
+++ b/base/strings_test.cpp
@@ -253,6 +253,26 @@
ASSERT_FALSE(android::base::EndsWithIgnoreCase("foobar", "FOO"));
}
+TEST(strings, StartsWith_std_string) {
+ ASSERT_TRUE(android::base::StartsWith("hello", std::string{"hell"}));
+ ASSERT_FALSE(android::base::StartsWith("goodbye", std::string{"hell"}));
+}
+
+TEST(strings, StartsWithIgnoreCase_std_string) {
+ ASSERT_TRUE(android::base::StartsWithIgnoreCase("HeLlO", std::string{"hell"}));
+ ASSERT_FALSE(android::base::StartsWithIgnoreCase("GoOdByE", std::string{"hell"}));
+}
+
+TEST(strings, EndsWith_std_string) {
+ ASSERT_TRUE(android::base::EndsWith("hello", std::string{"lo"}));
+ ASSERT_FALSE(android::base::EndsWith("goodbye", std::string{"lo"}));
+}
+
+TEST(strings, EndsWithIgnoreCase_std_string) {
+ ASSERT_TRUE(android::base::EndsWithIgnoreCase("HeLlO", std::string{"lo"}));
+ ASSERT_FALSE(android::base::EndsWithIgnoreCase("GoOdByE", std::string{"lo"}));
+}
+
TEST(strings, EqualsIgnoreCase) {
ASSERT_TRUE(android::base::EqualsIgnoreCase("foo", "FOO"));
ASSERT_TRUE(android::base::EqualsIgnoreCase("FOO", "foo"));
diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp
index b19ab78..f81206a 100644
--- a/bootstat/bootstat.cpp
+++ b/bootstat/bootstat.cpp
@@ -315,8 +315,7 @@
for (auto& s : knownReasons) {
if (s == "cold") break;
// Prefix defined as terminated by a nul or comma (,).
- if (android::base::StartsWith(r, s.c_str()) &&
- ((r.length() == s.length()) || (r[s.length()] == ','))) {
+ if (android::base::StartsWith(r, s) && ((r.length() == s.length()) || (r[s.length()] == ','))) {
return true;
}
}
@@ -328,8 +327,7 @@
for (auto& s : knownReasons) {
if (s == "recovery") break;
// Prefix defined as terminated by a nul or comma (,).
- if (android::base::StartsWith(r, s.c_str()) &&
- ((r.length() == s.length()) || (r[s.length()] == ','))) {
+ if (android::base::StartsWith(r, s) && ((r.length() == s.length()) || (r[s.length()] == ','))) {
return true;
}
}
@@ -340,8 +338,7 @@
bool isKnownRebootReason(const std::string& r) {
for (auto& s : knownReasons) {
// Prefix defined as terminated by a nul or comma (,).
- if (android::base::StartsWith(r, s.c_str()) &&
- ((r.length() == s.length()) || (r[s.length()] == ','))) {
+ if (android::base::StartsWith(r, s) && ((r.length() == s.length()) || (r[s.length()] == ','))) {
return true;
}
}
diff --git a/init/action.cpp b/init/action.cpp
index 5fa6bec..ab51eea 100644
--- a/init/action.cpp
+++ b/init/action.cpp
@@ -358,7 +358,7 @@
Subcontext* action_subcontext = nullptr;
if (subcontexts_) {
for (auto& subcontext : *subcontexts_) {
- if (StartsWith(filename, subcontext.path_prefix().c_str())) {
+ if (StartsWith(filename, subcontext.path_prefix())) {
action_subcontext = &subcontext;
break;
}
diff --git a/init/devices.cpp b/init/devices.cpp
index af6b50a..8d27f4f 100644
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -127,7 +127,7 @@
}
bool Permissions::Match(const std::string& path) const {
- if (prefix_) return StartsWith(path, name_.c_str());
+ if (prefix_) return StartsWith(path, name_);
if (wildcard_) return fnmatch(name_.c_str(), path.c_str(), FNM_PATHNAME) == 0;
return path == name_;
}
@@ -300,9 +300,9 @@
static const std::string devices_platform_prefix = "/devices/platform/";
static const std::string devices_prefix = "/devices/";
- if (StartsWith(device, devices_platform_prefix.c_str())) {
+ if (StartsWith(device, devices_platform_prefix)) {
device = device.substr(devices_platform_prefix.length());
- } else if (StartsWith(device, devices_prefix.c_str())) {
+ } else if (StartsWith(device, devices_prefix)) {
device = device.substr(devices_prefix.length());
}
diff --git a/init/parser.cpp b/init/parser.cpp
index 6ddb09f..4c69bac 100644
--- a/init/parser.cpp
+++ b/init/parser.cpp
@@ -76,7 +76,7 @@
// current section parsers. This is meant for /sys/ and /dev/ line entries for
// uevent.
for (const auto& [prefix, callback] : line_callbacks_) {
- if (android::base::StartsWith(args[0], prefix.c_str())) {
+ if (android::base::StartsWith(args[0], prefix)) {
end_section();
if (auto result = callback(std::move(args)); !result) {
diff --git a/init/service.cpp b/init/service.cpp
index 331b859..a4e33f7 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -1125,7 +1125,7 @@
Subcontext* restart_action_subcontext = nullptr;
if (subcontexts_) {
for (auto& subcontext : *subcontexts_) {
- if (StartsWith(filename, subcontext.path_prefix().c_str())) {
+ if (StartsWith(filename, subcontext.path_prefix())) {
restart_action_subcontext = &subcontext;
break;
}
diff --git a/libcutils/tests/fs_config.cpp b/libcutils/tests/fs_config.cpp
index 391adb6..d5dc66a 100644
--- a/libcutils/tests/fs_config.cpp
+++ b/libcutils/tests/fs_config.cpp
@@ -81,7 +81,7 @@
}
// check if path is <partition>/
- if (android::base::StartsWith(path, prefix.c_str())) {
+ if (android::base::StartsWith(path, prefix)) {
// rebuild path to be system/<partition>/... to check for alias
path = alternate + path.substr(prefix.size());
for (second = 0; second < paths.size(); ++second) {
@@ -97,7 +97,7 @@
}
// check if path is system/<partition>/
- if (android::base::StartsWith(path, alternate.c_str())) {
+ if (android::base::StartsWith(path, alternate)) {
// rebuild path to be <partition>/... to check for alias
path = prefix + path.substr(alternate.size());
for (second = 0; second < paths.size(); ++second) {
diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp
index 8c8d064..e9f0c0f 100644
--- a/libnativeloader/native_loader.cpp
+++ b/libnativeloader/native_loader.cpp
@@ -382,7 +382,7 @@
config_file_path, &sonames,
[&company_name](const std::string& soname, std::string* error_msg) {
if (android::base::StartsWith(soname, "lib") &&
- android::base::EndsWith(soname, ("." + company_name + ".so").c_str())) {
+ android::base::EndsWith(soname, "." + company_name + ".so")) {
return true;
} else {
*error_msg = "Library name \"" + soname +