refactor: remove tr_strvJoin() (#2896)

This commit is contained in:
Charles Kerr 2022-04-07 17:26:59 -05:00 committed by GitHub
parent ffda5bb68a
commit 31c65eec1f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 97 additions and 105 deletions

View File

@ -11,6 +11,8 @@
#include <fcntl.h> /* open() */
#include <unistd.h> /* fork(), setsid(), chdir(), dup2(), close(), pipe() */
#include <fmt/format.h>
#include <libtransmission/transmission.h>
#include <libtransmission/error.h>
#include <libtransmission/utils.h>
@ -34,7 +36,7 @@ static int signal_pipe[2];
static void set_system_error(tr_error** error, int code, std::string_view message)
{
tr_error_set(error, code, tr_strvJoin(message, " ("sv, std::to_string(code), "): "sv, tr_strerror(code)));
tr_error_set(error, code, fmt::format(FMT_STRING("{:s}: {:s} ({:d}"), message, tr_strerror(code), code));
}
/***

View File

@ -339,14 +339,14 @@ static void printMessage(
std::string_view filename,
int line)
{
auto const out = std::empty(name) ? tr_strvJoin(message, " ("sv, filename, ":"sv, std::to_string(line), ")"sv) :
tr_strvJoin(name, " "sv, message, " ("sv, filename, ":"sv, std::to_string(line), ")"sv);
auto const out = std::empty(name) ? fmt::format(FMT_STRING("{:s} ({:s}:{:d}"), message, filename, line) :
fmt::format(FMT_STRING("{:s} {:s} ({:s}:{:d}"), name, message, filename, line);
if (file != TR_BAD_SYS_FILE)
{
auto timestr = std::array<char, 64>{};
tr_logGetTimeStr(std::data(timestr), std::size(timestr));
tr_sys_file_write_line(file, tr_strvJoin("["sv, std::data(timestr), "] "sv, levelName(level), " "sv, out));
tr_sys_file_write_line(file, fmt::format(FMT_STRING("[{:s}] {:s} {:s}"), std::data(timestr), levelName(level), out));
}
#ifdef HAVE_SYSLOG
@ -980,7 +980,8 @@ int tr_main(int argc, char* argv[])
if (tr_error* error = nullptr; !dtr_daemon(&cb, &data, foreground, &ret, &error))
{
printMessage(logfile, TR_LOG_ERROR, MyName, tr_strvJoin("Couldn't daemonize: ", error->message), __FILE__, __LINE__);
auto const errmsg = fmt::format(FMT_STRING("Couldn't daemonize: {:s} ({:d})"), error->message, error->code);
printMessage(logfile, TR_LOG_ERROR, MyName, errmsg, __FILE__, __LINE__);
tr_error_free(error);
}

View File

@ -85,7 +85,7 @@ bool tr_announce_list::add(std::string_view announce_url_sv, tr_tracker_tier_t t
tracker.announce = *tr_urlParseTracker(tracker.announce_str.sv());
tracker.tier = getTier(tier, *announce);
tracker.id = nextUniqueId();
tracker.host = tr_strvJoin(tracker.announce.host, ":"sv, tracker.announce.portstr);
tracker.host = fmt::format(FMT_STRING("{:s}:{:d}"), tracker.announce.host, tracker.announce.port);
if (auto const scrape_str = announceToScrape(announce_url_sv); scrape_str)
{
@ -134,7 +134,7 @@ std::optional<std::string> tr_announce_list::announceToScrape(std::string_view a
{
auto const prefix = announce.substr(0, pos);
auto const suffix = announce.substr(pos + std::size(oldval));
return tr_strvJoin(prefix, std::string_view{ "/scrape" }, suffix);
return fmt::format(FMT_STRING("{:s}/scrape{:s}"), prefix, suffix);
}
// some torrents with UDP announce URLs don't have /announce

View File

@ -20,6 +20,8 @@ extern "C"
#include <b64/cencode.h>
}
#include <fmt/format.h>
#include "transmission.h"
#include "crypto-utils.h"
#include "tr-assert.h"
@ -94,7 +96,7 @@ std::string tr_salt(std::string_view plaintext, std::string_view salt)
// convert it to a string. string holds three parts:
// DigestPrefix, stringified digest of plaintext + salt, and the salt.
return tr_strvJoin(SaltedPrefix, tr_sha1_to_string(*digest), salt);
return fmt::format(FMT_STRING("{:s}{:s}{:s}"), SaltedPrefix, tr_sha1_to_string(*digest), salt);
}
} // namespace

View File

@ -9,6 +9,8 @@
#include <string>
#include <string_view>
#include <fmt/format.h>
#include "transmission.h"
#include "crypto-utils.h"
@ -184,7 +186,7 @@ bool tr_magnet_metainfo::parseMagnet(std::string_view magnet_link, tr_error** er
magnet_link = tr_strvStrip(magnet_link);
if (auto const hash = parseHash(magnet_link); hash)
{
return parseMagnet(tr_strvJoin("magnet:?xt=urn:btih:", tr_sha1_to_string(*hash)));
return parseMagnet(fmt::format(FMT_STRING("magnet:?xt=urn:btih:{:s}"), tr_sha1_to_string(*hash)));
}
auto const parsed = tr_urlParse(magnet_link);

View File

@ -32,7 +32,7 @@
#include <FindDirectory.h>
#endif
#include <fmt/core.h>
#include <fmt/format.h>
#include "transmission.h"
@ -210,7 +210,7 @@ static std::string getXdgEntryFromUserDirs(std::string_view key)
}
// search for key="val" and extract val
auto const search = tr_strvJoin(key, R"(=")");
auto const search = fmt::format(FMT_STRING("{:s}=\""), key);
auto begin = std::search(std::begin(content), std::end(content), std::begin(search), std::end(search));
if (begin == std::end(content))
{
@ -386,7 +386,7 @@ char const* tr_getWebClientDir([[maybe_unused]] tr_session const* session)
{
char const* const pkg = PACKAGE_DATA_DIR;
auto* xdg = tr_env_get_string("XDG_DATA_DIRS", "");
auto const buf = tr_strvJoin(pkg, ":", xdg, ":/usr/local/share:/usr/share");
auto const buf = fmt::format(FMT_STRING("{:s}:{:s}:/usr/local/share:/usr/share"), pkg, xdg);
tr_free(xdg);
auto sv = std::string_view{ buf };

View File

@ -234,7 +234,7 @@ static void serve_file(struct evhttp_request* req, tr_rpc_server* server, std::s
if (file == nullptr)
{
auto const tmp = tr_strvJoin(filename, " ("sv, error->message, ")"sv);
auto const tmp = fmt::format(FMT_STRING("{:s} ({:s})"), filename, error->message);
send_simple_response(req, HTTP_NOTFOUND, tmp.c_str());
tr_error_free(error);
}
@ -507,10 +507,9 @@ static void handle_request(struct evhttp_request* req, void* arg)
++server->loginattempts;
}
auto const unauthuser = tr_strvJoin(
"<p>Unauthorized User. "sv,
std::to_string(server->loginattempts),
" unsuccessful login attempts.</p>"sv);
auto const unauthuser = fmt::format(
FMT_STRING("<p>Unauthorized User. {:d} unsuccessful login attempts.</p>"),
server->loginattempts);
send_simple_response(req, 401, unauthuser.c_str());
return;
}
@ -522,7 +521,7 @@ static void handle_request(struct evhttp_request* req, void* arg)
if (std::empty(location) || location == "web"sv)
{
auto const new_location = tr_strvJoin(server->url, "web/");
auto const new_location = fmt::format(FMT_STRING("{:s}web/"), server->url);
evhttp_add_header(req->output_headers, "Location", new_location.c_str());
send_simple_response(req, HTTP_MOVEPERM, nullptr);
}
@ -549,20 +548,19 @@ static void handle_request(struct evhttp_request* req, void* arg)
else if (!test_session_id(server, req))
{
char const* sessionId = get_current_session_id(server);
auto const tmp = tr_strvJoin(
"<p>Your request had an invalid session-id header.</p>"
"<p>To fix this, follow these steps:"
"<ol><li> When reading a response, get its X-Transmission-Session-Id header and remember it"
"<li> Add the updated header to your outgoing requests"
"<li> When you get this 409 error message, resend your request with the updated header"
"</ol></p>"
"<p>This requirement has been added to help prevent "
"<a href=\"https://en.wikipedia.org/wiki/Cross-site_request_forgery\">CSRF</a> "
"attacks.</p>"
"<p><code>" TR_RPC_SESSION_ID_HEADER,
": "sv,
sessionId,
"</code></p>");
auto const tmp = fmt::format(
FMT_STRING("<p>Your request had an invalid session-id header.</p>"
"<p>To fix this, follow these steps:"
"<ol><li> When reading a response, get its X-Transmission-Session-Id header and remember it"
"<li> Add the updated header to your outgoing requests"
"<li> When you get this 409 error message, resend your request with the updated header"
"</ol></p>"
"<p>This requirement has been added to help prevent "
"<a href=\"https://en.wikipedia.org/wiki/Cross-site_request_forgery\">CSRF</a> "
"attacks.</p>"
"<p><code>{:s}: {:s}</code></p>"),
TR_RPC_SESSION_ID_HEADER,
sessionId);
evhttp_add_header(req->output_headers, TR_RPC_SESSION_ID_HEADER, sessionId);
evhttp_add_header(req->output_headers, "Access-Control-Expose-Headers", TR_RPC_SESSION_ID_HEADER);
send_simple_response(req, 409, tmp.c_str());
@ -1061,7 +1059,7 @@ tr_rpc_server::tr_rpc_server(tr_session* session_in, tr_variant* settings)
}
else if (std::empty(sv) || sv.back() != '/')
{
this->url = tr_strvJoin(sv, "/"sv);
this->url = fmt::format(FMT_STRING("{:s}/"), sv);
}
else
{

View File

@ -1385,7 +1385,7 @@ static char const* portTest(
struct tr_rpc_idle_data* idle_data)
{
auto const port = tr_sessionGetPeerPort(session);
auto const url = tr_strvJoin("https://portcheck.transmissionbt.com/"sv, std::to_string(port));
auto const url = fmt::format(FMT_STRING("https://portcheck.transmissionbt.com/{:d}"), port);
session->web->fetch({ url, onPortTested, idle_data });
return nullptr;
}

View File

@ -10,7 +10,7 @@
#include <sys/stat.h>
#endif
#include <fmt/core.h>
#include <fmt/format.h>
#include "transmission.h"
#include "crypto-utils.h"
@ -57,7 +57,7 @@ static char* generate_new_session_id_value()
static std::string get_session_id_lock_file_path(std::string_view session_id)
{
return tr_strvJoin(tr_getSessionIdDir(), TR_PATH_DELIMITER_STR, "tr_session_id_"sv, session_id);
return fmt::format(FMT_STRING("{:s}/tr_session_id_{:s}"), tr_getSessionIdDir(), session_id);
}
static tr_sys_file_t create_session_id_lock_file(char const* session_id)

View File

@ -136,7 +136,7 @@ std::optional<std::string> tr_session::WebMediator::cookieFile() const
std::optional<std::string> tr_session::WebMediator::userAgent() const
{
return tr_strvJoin(TR_NAME, "/"sv, SHORT_VERSION_STRING);
return fmt::format(FMT_STRING("{:s}/{:s}"), TR_NAME, SHORT_VERSION_STRING);
}
std::optional<std::string> tr_session::WebMediator::publicAddress() const
@ -2359,11 +2359,11 @@ static void loadBlocklists(tr_session* session)
tr_sys_path_info path_info;
tr_sys_path_info binname_info;
auto const binname = tr_strvJoin(dirname, TR_PATH_DELIMITER_STR, name, ".bin"sv);
auto const binname = tr_pathbuf{ dirname, '/', name, ".bin"sv };
if (!tr_sys_path_get_info(binname.c_str(), 0, &binname_info)) /* create it */
if (!tr_sys_path_get_info(binname, 0, &binname_info)) /* create it */
{
tr_blocklistFile* b = tr_blocklistFileNew(binname.c_str(), isEnabled);
tr_blocklistFile* b = tr_blocklistFileNew(binname, isEnabled);
if (auto const n = tr_blocklistFileSetContent(b, path.c_str()); n > 0)
{
@ -2376,19 +2376,19 @@ static void loadBlocklists(tr_session* session)
tr_sys_path_get_info(path.c_str(), 0, &path_info) &&
path_info.last_modified_at >= binname_info.last_modified_at) /* update it */
{
auto const old = binname + ".old";
tr_sys_path_remove(old.c_str());
tr_sys_path_rename(binname.c_str(), old.c_str());
auto* const b = tr_blocklistFileNew(binname.c_str(), isEnabled);
auto const old = tr_pathbuf{ binname, ".old"sv };
tr_sys_path_remove(old);
tr_sys_path_rename(binname, old);
auto* const b = tr_blocklistFileNew(binname, isEnabled);
if (tr_blocklistFileSetContent(b, path.c_str()) > 0)
{
tr_sys_path_remove(old.c_str());
tr_sys_path_remove(old);
}
else
{
tr_sys_path_remove(binname.c_str());
tr_sys_path_rename(old.c_str(), binname.c_str());
tr_sys_path_remove(binname);
tr_sys_path_rename(old, binname);
}
tr_blocklistFileFree(b);
@ -2485,8 +2485,7 @@ int tr_blocklistSetContent(tr_session* session, char const* contentFilename)
if (it == std::end(src))
{
auto path = tr_strvJoin(session->config_dir, "blocklists"sv, name);
b = tr_blocklistFileNew(path.c_str(), session->useBlocklist());
b = tr_blocklistFileNew(tr_pathbuf{ session->config_dir, "/blocklists/"sv, name }, session->useBlocklist());
src.push_back(b);
}
else

View File

@ -129,9 +129,9 @@ static wchar_t** to_wide_env(std::map<std::string_view, std::string_view> const&
wchar_t** const wide_env = tr_new(wchar_t*, part_count + 1);
int i = 0;
for (auto const& [key_sv, val_sv] : env)
for (auto const& [key, val] : env)
{
auto const line = tr_strvJoin(key_sv, "="sv, val_sv);
auto const line = fmt::format(FMT_STRING("{:s}={:s}"), key, val);
wide_env[i++] = tr_win32_utf8_to_native(std::data(line), std::size(line));
}
wide_env[i] = nullptr;

View File

@ -2881,7 +2881,7 @@ static bool renameArgsAreValid(char const* oldpath, char const* newname)
static auto renameFindAffectedFiles(tr_torrent const* tor, std::string_view oldpath)
{
auto indices = std::vector<tr_file_index_t>{};
auto oldpath_as_dir = tr_strvJoin(oldpath, "/"sv);
auto const oldpath_as_dir = tr_pathbuf{ oldpath, '/' };
auto const n_files = tor->fileCount();
for (tr_file_index_t i = 0; i < n_files; ++i)
@ -2913,11 +2913,11 @@ static int renamePath(tr_torrent* tor, char const* oldpath, char const* newname)
{
auto const parent = tr_sys_path_dirname(src);
auto const tgt = tr_strvEndsWith(src, tr_torrent::PartialFileSuffix) ?
tr_strvJoin(parent, TR_PATH_DELIMITER_STR, newname, tr_torrent::PartialFileSuffix) :
tr_strvPath(parent, newname);
tr_pathbuf{ parent, '/', newname, tr_torrent::PartialFileSuffix } :
tr_pathbuf{ parent, '/', newname };
auto tmp = errno;
bool const tgt_exists = tr_sys_path_exists(tgt.c_str());
bool const tgt_exists = tr_sys_path_exists(tgt);
errno = tmp;
if (!tgt_exists)
@ -2926,7 +2926,7 @@ static int renamePath(tr_torrent* tor, char const* oldpath, char const* newname)
tmp = errno;
if (!tr_sys_path_rename(src.c_str(), tgt.c_str(), &error))
if (!tr_sys_path_rename(src.c_str(), tgt, &error))
{
err = error->code;
tr_error_free(error);

View File

@ -305,19 +305,6 @@ template<typename... T, typename std::enable_if_t<(std::is_convertible_v<T, std:
return setme;
}
template<typename... T, typename std::enable_if_t<(std::is_convertible_v<T, std::string_view> && ...), bool> = true>
[[nodiscard]] std::string tr_strvJoin(T... args)
{
auto setme = std::string{};
auto const n = (std::size(std::string_view{ args }) + ...);
if (setme.capacity() < n)
{
setme.reserve(n);
}
((setme += args), ...);
return setme;
}
template<typename T>
[[nodiscard]] constexpr bool tr_strvContains(std::string_view sv, T key) // c++23
{

View File

@ -4,11 +4,13 @@
#include <optional>
#include <fmt/format.h>
#include <libtransmission/transmission.h>
#include <libtransmission/error.h>
#include <libtransmission/log.h>
#include <libtransmission/utils.h> // tr_free(), tr_strvJoin()
#include <libtransmission/utils.h> // tr_free()
#import "Torrent.h"
#import "GroupsController.h"
@ -717,7 +719,7 @@ bool trashDataFile(char const* filename, tr_error** error)
}
char* old_list = tr_torrentGetTrackerList(self.fHandle);
auto new_list = tr_strvJoin(old_list, "\n\n", new_tracker.UTF8String);
auto const new_list = fmt::format(FMT_STRING("{:s}\n\n{:s}"), old_list, new_tracker.UTF8String);
BOOL const success = tr_torrentSetTrackerList(self.fHandle, new_list.c_str());
tr_free(old_list);

View File

@ -421,7 +421,7 @@ TEST_F(AnnounceListTest, parseThreeTier)
EXPECT_EQ(1U, announce_list.at(1).tier);
EXPECT_EQ("https://www.example.com/c/announce", announce_list.at(2).announce.full);
EXPECT_EQ(2U, announce_list.at(2).tier);
EXPECT_EQ(tr_strvJoin(Text, "\n"sv), announce_list.toString());
EXPECT_EQ(fmt::format("{:s}\n", Text), announce_list.toString());
}
TEST_F(AnnounceListTest, parseThreeTierWithTrailingLf)

View File

@ -3,6 +3,8 @@
// or any future license endorsed by Mnemosyne LLC.
// License text can be found in the licenses/ folder.
#include <fmt/format.h>
#include "transmission.h"
#include "benc.h"
@ -82,15 +84,13 @@ TEST_F(BencTest, ContextTokenIsCorrect)
bool Int64(int64_t value, Context const& context) override
{
auto const expected = tr_strvJoin("i"sv, std::to_string(value), "e"sv);
EXPECT_EQ(expected, context.raw());
EXPECT_EQ(fmt::format(FMT_STRING("i{:d}e"), value), context.raw());
return true;
}
bool String(std::string_view value, Context const& context) override
{
auto const key = tr_strvJoin(std::to_string(std::size(value)), ":"sv, value);
EXPECT_EQ(key, context.raw());
EXPECT_EQ(fmt::format(FMT_STRING("{:d}:{:s}"), std::size(value), value), context.raw());
return true;
}
};

View File

@ -5,6 +5,7 @@
#include <iostream>
#include <string>
#include <string_view>
#include <utility>
#include <event2/buffer.h>
@ -18,6 +19,8 @@
#include "test-fixtures.h"
using namespace std::literals;
namespace libtransmission
{
@ -53,8 +56,12 @@ TEST_P(IncompleteDirTest, incompleteDir)
// init an incomplete torrent.
// the test zero_torrent will be missing its first piece.
auto* const tor = zeroTorrentInit(ZeroTorrentState::Partial);
EXPECT_EQ(tr_strvJoin(incomplete_dir, "/", tr_torrentFile(tor, 0).name, ".part"), makeString(tr_torrentFindFile(tor, 0)));
EXPECT_EQ(tr_strvPath(incomplete_dir, tr_torrentFile(tor, 1).name), makeString(tr_torrentFindFile(tor, 1)));
auto path = tr_pathbuf{};
path.assign(incomplete_dir, '/', tr_torrentFile(tor, 0).name, ".part"sv);
EXPECT_EQ(path, makeString(tr_torrentFindFile(tor, 0)));
path.assign(incomplete_dir, '/', tr_torrentFile(tor, 1).name);
EXPECT_EQ(path, makeString(tr_torrentFindFile(tor, 1)));
EXPECT_EQ(tor->pieceSize(), tr_torrentStat(tor)->leftUntilDone);
// auto constexpr completeness_unset = tr_completeness { -1 };

View File

@ -172,7 +172,7 @@ TEST_F(TorrentMetainfoTest, sanitize)
TEST_F(TorrentMetainfoTest, AndroidTorrent)
{
auto const filename = tr_strvJoin(LIBTRANSMISSION_TEST_ASSETS_DIR, "/Android-x86 8.1 r6 iso.torrent"sv);
auto const filename = tr_pathbuf{ LIBTRANSMISSION_TEST_ASSETS_DIR, "/Android-x86 8.1 r6 iso.torrent"sv };
auto* ctor = tr_ctorNew(session_);
tr_error* error = nullptr;

View File

@ -63,7 +63,7 @@ TEST_F(TorrentsTest, rangedLoop)
for (auto const& name : Filenames)
{
auto const path = tr_strvJoin(LIBTRANSMISSION_TEST_ASSETS_DIR, "/"sv, name);
auto const path = tr_pathbuf{ LIBTRANSMISSION_TEST_ASSETS_DIR, '/', name };
auto tm = tr_torrent_metainfo{};
EXPECT_TRUE(tm.parseTorrentFile(path));
auto* const tor = new tr_torrent{ std::move(tm) };
@ -95,7 +95,7 @@ TEST_F(TorrentsTest, removedSince)
// setup: add the torrents
for (auto const& name : Filenames)
{
auto const path = tr_strvJoin(LIBTRANSMISSION_TEST_ASSETS_DIR, "/"sv, name);
auto const path = tr_pathbuf{ LIBTRANSMISSION_TEST_ASSETS_DIR, '/', name };
auto tm = tr_torrent_metainfo{};
auto* const tor = new tr_torrent{ std::move(tm) };
tor->uniqueId = torrents.add(tor);

View File

@ -33,14 +33,6 @@ using ::libtransmission::test::makeString;
using UtilsTest = ::testing::Test;
using namespace std::literals;
TEST_F(UtilsTest, trStrvJoin)
{
EXPECT_EQ(""sv, tr_strvJoin(""sv));
EXPECT_EQ("test"sv, tr_strvJoin("test"sv));
EXPECT_EQ("foo/bar"sv, tr_strvJoin("foo"sv, "/", std::string{ "bar" }));
EXPECT_EQ("abcde"sv, tr_strvJoin("a", "b", "c", "d", "e"));
}
TEST_F(UtilsTest, trStrvContains)
{
EXPECT_FALSE(tr_strvContains("a test is this"sv, "TEST"sv));

View File

@ -17,6 +17,7 @@
#include <libtransmission/log.h>
#include <libtransmission/makemeta.h>
#include <libtransmission/tr-getopt.h>
#include <libtransmission/tr-strbuf.h>
#include <libtransmission/utils.h>
#include <libtransmission/version.h>
@ -179,9 +180,8 @@ int tr_main(int argc, char* argv[])
return EXIT_FAILURE;
}
auto const end = tr_strvJoin(base, ".torrent"sv);
char* cwd = tr_getcwd();
options.outfile = tr_strvDup(tr_strvPath(cwd, end.c_str()));
char* const cwd = tr_getcwd();
options.outfile = tr_strvDup(tr_pathbuf{ std::string_view{ cwd }, '/', base, ".torrent"sv });
tr_free(cwd);
}

View File

@ -19,7 +19,7 @@
#include <event2/buffer.h>
#include <event2/util.h>
#include <fmt/core.h>
#include <fmt/format.h>
#include <libtransmission/transmission.h>
#include <libtransmission/crypto-utils.h>
@ -2090,7 +2090,7 @@ static int processResponse(char const* rpcurl, std::string_view response)
static CURL* tr_curl_easy_init(struct evbuffer* writebuf)
{
CURL* curl = curl_easy_init();
curl_easy_setopt(curl, CURLOPT_USERAGENT, tr_strvJoin(MyName, "/", LONG_VERSION_STRING).c_str());
curl_easy_setopt(curl, CURLOPT_USERAGENT, fmt::format(FMT_STRING("{:s}/{:s}"), MyName, LONG_VERSION_STRING).c_str());
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeFunc);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, writebuf);
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, parseResponseHeader);
@ -2118,7 +2118,7 @@ static CURL* tr_curl_easy_init(struct evbuffer* writebuf)
if (!tr_str_is_empty(session_id))
{
auto const h = tr_strvJoin(TR_RPC_SESSION_ID_HEADER, ": "sv, session_id);
auto const h = fmt::format(FMT_STRING("{:s}: {:s}"), TR_RPC_SESSION_ID_HEADER, session_id);
auto* const custom_headers = curl_slist_append(nullptr, h.c_str());
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, custom_headers);
@ -2145,7 +2145,7 @@ static int flush(char const* rpcurl, tr_variant** benc)
{
int status = EXIT_SUCCESS;
auto const json = tr_variantToStr(*benc, TR_VARIANT_FMT_JSON_LEAN);
auto const rpcurl_http = tr_strvJoin(UseSSL ? "https://" : "http://", rpcurl);
auto const rpcurl_http = fmt::format(FMT_STRING("{:s}://{:s}"), UseSSL ? "https" : "http", rpcurl);
auto* const buf = evbuffer_new();
auto* curl = tr_curl_easy_init(buf);
@ -3047,12 +3047,12 @@ static void getHostAndPortAndRpcUrl(int* argc, char** argv, std::string* host, i
if (strncmp(s, "http://", 7) == 0) /* user passed in http rpc url */
{
*rpcurl = tr_strvJoin(s + 7, "/rpc/"sv);
*rpcurl = fmt::format(FMT_STRING("{:s}/rpc/"), s + 7);
}
else if (strncmp(s, "https://", 8) == 0) /* user passed in https rpc url */
{
UseSSL = true;
*rpcurl = tr_strvJoin(s + 8, "/rpc/"sv);
*rpcurl = fmt::format(FMT_STRING("{:s}/rpc/"), s + 8);
}
else if (parsePortString(s, port))
{
@ -3080,7 +3080,7 @@ static void getHostAndPortAndRpcUrl(int* argc, char** argv, std::string* host, i
bool const is_unbracketed_ipv6 = (*s != '[') && (memchr(s, ':', hend - s) != nullptr);
auto const sv = std::string_view{ s, size_t(hend - s) };
*host = is_unbracketed_ipv6 ? tr_strvJoin("[", sv, "]") : sv;
*host = is_unbracketed_ipv6 ? fmt::format(FMT_STRING("[{:s}]"), sv) : sv;
}
*argc -= 1;
@ -3116,7 +3116,7 @@ int tr_main(int argc, char* argv[])
if (std::empty(rpcurl))
{
rpcurl = tr_strvJoin(host, ":", std::to_string(port), DefaultUrl);
rpcurl = fmt::format(FMT_STRING("{:s}:{:d}{:s}"), host, port, DefaultUrl);
}
return processArgs(rpcurl.c_str(), argc, (char const* const*)argv);

View File

@ -22,6 +22,7 @@
#include <libtransmission/torrent-metainfo.h>
#include <libtransmission/tr-getopt.h>
#include <libtransmission/tr-macros.h>
#include <libtransmission/tr-strbuf.h>
#include <libtransmission/utils.h>
#include <libtransmission/variant.h>
#include <libtransmission/version.h>
@ -338,11 +339,10 @@ void doScrape(tr_torrent_metainfo const& metainfo)
auto escaped = std::array<char, TR_SHA1_DIGEST_LEN * 3 + 1>{};
tr_http_escape_sha1(std::data(escaped), metainfo.infoHash());
auto const scrape = tracker.scrape.full;
auto const url = tr_strvJoin(
scrape,
(tr_strvContains(scrape, '?') ? "&"sv : "?"sv),
"info_hash="sv,
std::data(escaped));
auto const url = tr_urlbuf{ scrape,
tr_strvContains(scrape, '?') ? '&' : '?',
"info_hash="sv,
std::string_view{ std::data(escaped) } };
printf("%" TR_PRIsv " ... ", TR_PRIsv_ARG(url));
fflush(stdout);