mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-09-11 21:20:39 +02:00
util: make ReplaceAll literal
`ReplaceAll()` substitutes fixed tokens in notification commands and other strings. PR #25803 replaced the Boost helper with `std::regex_replace()`, treating searches as regular expressions and substitutes as replacement-format syntax. Restore literal, non-recursive replacement so callers match fixed tokens and preserve replacement bytes exactly, while avoiding a new string when the search text is absent. Co-authored-by: Rob Hamilton <6456095+Rob1Ham@users.noreply.github.com>
This commit is contained in:
@@ -311,8 +311,8 @@ BOOST_AUTO_TEST_CASE(util_ReplaceAll)
|
||||
test_replaceall(original, "%s", "foo", "A test \"foo\" string 'foo'.");
|
||||
test_replaceall(original, "\"", "foo", "A test foo%sfoo string '%s'.");
|
||||
test_replaceall(original, "'", "foo", "A test \"%s\" string foo%sfoo.");
|
||||
test_replaceall("a.b", ".", "x", "xxx"); // TODO: Search text must remain literal.
|
||||
test_replaceall("%w and %w", "%w", "$&$`$'$1$$", "%w and %w$ and %w and $"); // TODO: Replacement bytes must remain literal.
|
||||
test_replaceall("a.b", ".", "x", "axb");
|
||||
test_replaceall("%w and %w", "%w", "$&$`$'$1$$", "$&$`$'$1$$ and $&$`$'$1$$");
|
||||
test_replaceall("x", "x", "xx", "xx");
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <regex>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
@@ -14,7 +13,19 @@ namespace util {
|
||||
void ReplaceAll(std::string& in_out, const std::string& search, const std::string& substitute)
|
||||
{
|
||||
if (search.empty()) return;
|
||||
in_out = std::regex_replace(in_out, std::regex(search), substitute);
|
||||
auto pos{in_out.find(search)};
|
||||
if (pos == std::string::npos) return;
|
||||
|
||||
// Build separately because repeated std::string::replace() calls move the remaining suffix when sizes differ
|
||||
std::string result;
|
||||
result.reserve(in_out.size());
|
||||
std::string::size_type start{0};
|
||||
for (; pos != std::string::npos; pos = in_out.find(search, start)) {
|
||||
result.append(in_out, start, pos - start).append(substitute);
|
||||
start = pos + search.size();
|
||||
}
|
||||
result.append(in_out, start);
|
||||
in_out.swap(result);
|
||||
}
|
||||
|
||||
LineReader::LineReader(std::string_view str, size_t max_line_length)
|
||||
|
||||
@@ -98,6 +98,7 @@ struct ConstevalFormatString {
|
||||
consteval ConstevalFormatString(const char* str) : fmt{str} { detail::CheckNumFormatSpecifiers<num_params>(fmt); }
|
||||
};
|
||||
|
||||
/// Replace every non-overlapping occurrence of `search` with `substitute`, treating both literally; the replacement text is not searched again.
|
||||
void ReplaceAll(std::string& in_out, const std::string& search, const std::string& substitute);
|
||||
|
||||
/** Split a string on any char found in separators, returning a vector.
|
||||
|
||||
@@ -186,8 +186,8 @@ class NotificationsTest(BitcoinTestFramework):
|
||||
self.sync_mempools()
|
||||
notify_path = os.path.join(self.walletnotify_dir, notify_outputname(wallet_name, txid))
|
||||
self.wait_until(lambda: os.path.exists(command_marker) or os.path.exists(notify_path), timeout=10)
|
||||
assert os.path.exists(command_marker) # TODO: Wallet names must not inject shell commands.
|
||||
assert not os.path.exists(notify_path) # TODO: Wallet names must remain literal in notification paths.
|
||||
assert not os.path.exists(command_marker)
|
||||
assert os.path.exists(notify_path)
|
||||
|
||||
self.log.info("test -alertnotify with large work invalid chain")
|
||||
# create a bunch of invalid blocks
|
||||
|
||||
Reference in New Issue
Block a user