Merge branch 'main' into nevack/mojave-infowindow-fix
|
@ -61,6 +61,7 @@ If you're new to building programs from source code, this is typically easier th
|
|||
|
||||
$ cd Transmission/build
|
||||
$ make clean
|
||||
$ git submodule foreach --recursive git clean -xfd
|
||||
$ git pull --rebase --prune
|
||||
$ git submodule update --recursive
|
||||
$ # Use -DCMAKE_BUILD_TYPE=RelWithDebInfo to build optimized binary.
|
||||
|
|
103
cli/cli.cc
|
@ -10,6 +10,8 @@
|
|||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include <libtransmission/transmission.h>
|
||||
|
||||
#include <libtransmission/error.h>
|
||||
|
@ -96,30 +98,29 @@ static int parseCommandLine(tr_variant*, int argc, char const** argv);
|
|||
|
||||
static void sigHandler(int signal);
|
||||
|
||||
static char* tr_strlratio(char* buf, double ratio, size_t buflen)
|
||||
static std::string tr_strlratio(double ratio)
|
||||
{
|
||||
if ((int)ratio == TR_RATIO_NA)
|
||||
if (static_cast<int>(ratio) == TR_RATIO_NA)
|
||||
{
|
||||
tr_strlcpy(buf, _("None"), buflen);
|
||||
}
|
||||
else if ((int)ratio == TR_RATIO_INF)
|
||||
{
|
||||
tr_strlcpy(buf, "Inf", buflen);
|
||||
}
|
||||
else if (ratio < 10.0)
|
||||
{
|
||||
tr_snprintf(buf, buflen, "%.2f", ratio);
|
||||
}
|
||||
else if (ratio < 100.0)
|
||||
{
|
||||
tr_snprintf(buf, buflen, "%.1f", ratio);
|
||||
}
|
||||
else
|
||||
{
|
||||
tr_snprintf(buf, buflen, "%.0f", ratio);
|
||||
return _("None");
|
||||
}
|
||||
|
||||
return buf;
|
||||
if (static_cast<int>(ratio) == TR_RATIO_INF)
|
||||
{
|
||||
return _("Inf");
|
||||
}
|
||||
|
||||
if (ratio < 10.0)
|
||||
{
|
||||
return fmt::format(FMT_STRING("{:.2f}"), ratio);
|
||||
}
|
||||
|
||||
if (ratio < 100.0)
|
||||
{
|
||||
return fmt::format(FMT_STRING("{:.1f}"), ratio);
|
||||
}
|
||||
|
||||
return fmt::format(FMT_STRING("{:.0f}"), ratio);
|
||||
}
|
||||
|
||||
static bool waitingOnWeb;
|
||||
|
@ -131,56 +132,45 @@ static void onTorrentFileDownloaded(tr_web::FetchResponse const& response)
|
|||
waitingOnWeb = false;
|
||||
}
|
||||
|
||||
static void getStatusStr(tr_stat const* st, char* buf, size_t buflen)
|
||||
static std::string getStatusStr(tr_stat const* st)
|
||||
{
|
||||
if (st->activity == TR_STATUS_CHECK_WAIT)
|
||||
{
|
||||
tr_snprintf(buf, buflen, "Waiting to verify local files");
|
||||
return "Waiting to verify local files";
|
||||
}
|
||||
else if (st->activity == TR_STATUS_CHECK)
|
||||
|
||||
if (st->activity == TR_STATUS_CHECK)
|
||||
{
|
||||
tr_snprintf(
|
||||
buf,
|
||||
buflen,
|
||||
"Verifying local files (%.2f%%, %.2f%% valid)",
|
||||
return fmt::format(
|
||||
FMT_STRING("Verifying local files ({:.2f}%, {:.2f}% valid)"),
|
||||
tr_truncd(100 * st->recheckProgress, 2),
|
||||
tr_truncd(100 * st->percentDone, 2));
|
||||
}
|
||||
else if (st->activity == TR_STATUS_DOWNLOAD)
|
||||
{
|
||||
char ratioStr[80];
|
||||
tr_strlratio(ratioStr, st->ratio, sizeof(ratioStr));
|
||||
|
||||
tr_snprintf(
|
||||
buf,
|
||||
buflen,
|
||||
"Progress: %.1f%%, dl from %d of %d peers (%s), ul to %d (%s) [%s]",
|
||||
if (st->activity == TR_STATUS_DOWNLOAD)
|
||||
{
|
||||
return fmt::format(
|
||||
FMT_STRING("Progress: {:.1f}%, dl from {:d} of {:d} peers ({:s}), ul to {:d} ({:s}) [{:s}]"),
|
||||
tr_truncd(100 * st->percentDone, 1),
|
||||
st->peersSendingToUs,
|
||||
st->peersConnected,
|
||||
tr_formatter_speed_KBps(st->pieceDownloadSpeed_KBps).c_str(),
|
||||
tr_formatter_speed_KBps(st->pieceDownloadSpeed_KBps),
|
||||
st->peersGettingFromUs,
|
||||
tr_formatter_speed_KBps(st->pieceUploadSpeed_KBps).c_str(),
|
||||
ratioStr);
|
||||
tr_formatter_speed_KBps(st->pieceUploadSpeed_KBps),
|
||||
tr_strlratio(st->ratio));
|
||||
}
|
||||
else if (st->activity == TR_STATUS_SEED)
|
||||
{
|
||||
char ratioStr[80];
|
||||
tr_strlratio(ratioStr, st->ratio, sizeof(ratioStr));
|
||||
|
||||
tr_snprintf(
|
||||
buf,
|
||||
buflen,
|
||||
"Seeding, uploading to %d of %d peer(s), %s [%s]",
|
||||
if (st->activity == TR_STATUS_SEED)
|
||||
{
|
||||
return fmt::format(
|
||||
FMT_STRING("Seeding, uploading to {:d} of {:d} peer(s), {:s} [{:s}]"),
|
||||
st->peersGettingFromUs,
|
||||
st->peersConnected,
|
||||
tr_formatter_speed_KBps(st->pieceUploadSpeed_KBps).c_str(),
|
||||
ratioStr);
|
||||
}
|
||||
else
|
||||
{
|
||||
*buf = '\0';
|
||||
tr_formatter_speed_KBps(st->pieceUploadSpeed_KBps),
|
||||
tr_strlratio(st->ratio));
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
static char const* getConfigDir(int argc, char const** argv)
|
||||
|
@ -319,8 +309,6 @@ int tr_main(int argc, char* argv[])
|
|||
|
||||
for (;;)
|
||||
{
|
||||
char line[LineWidth];
|
||||
tr_stat const* st;
|
||||
static auto constexpr messageName = std::array<char const*, 4>{
|
||||
nullptr,
|
||||
"Tracker gave a warning:",
|
||||
|
@ -352,15 +340,14 @@ int tr_main(int argc, char* argv[])
|
|||
}
|
||||
}
|
||||
|
||||
st = tr_torrentStat(tor);
|
||||
|
||||
auto const* const st = tr_torrentStat(tor);
|
||||
if (st->activity == TR_STATUS_STOPPED)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
getStatusStr(st, line, sizeof(line));
|
||||
printf("\r%-*s", TR_ARG_TUPLE(LineWidth, line));
|
||||
auto const status_str = getStatusStr(st);
|
||||
printf("\r%-*s", TR_ARG_TUPLE(LineWidth, status_str.c_str()));
|
||||
|
||||
if (messageName[st->error])
|
||||
{
|
||||
|
|
|
@ -692,9 +692,12 @@ static int daemon_start(void* varg, [[maybe_unused]] bool foreground)
|
|||
|
||||
if (ev_base == nullptr)
|
||||
{
|
||||
char buf[256];
|
||||
tr_snprintf(buf, sizeof(buf), "Couldn't initialize daemon event state: %s", tr_strerror(errno));
|
||||
printMessage(logfile, TR_LOG_ERROR, MyName, buf, __FILE__, __LINE__);
|
||||
auto const error_code = errno;
|
||||
auto const errmsg = fmt::format(
|
||||
_("Couldn't initialize daemon: {error} ({error_code})"),
|
||||
fmt::arg("error", tr_strerror(error_code)),
|
||||
fmt::arg("error_code", error_code));
|
||||
printMessage(logfile, TR_LOG_ERROR, MyName, errmsg, __FILE__, __LINE__);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -304,7 +304,7 @@ bool Application::Impl::refresh_actions()
|
|||
sel_->selected_foreach(
|
||||
[&canUpdate](auto const& /*path*/, auto const& iter)
|
||||
{
|
||||
auto* tor = static_cast<tr_torrent*>(iter->get_value(torrent_cols.torrent));
|
||||
auto const* tor = static_cast<tr_torrent const*>(iter->get_value(torrent_cols.torrent));
|
||||
canUpdate = canUpdate || tr_torrentCanManualUpdate(tor);
|
||||
});
|
||||
gtr_action_set_sensitive("torrent-reannounce", canUpdate);
|
||||
|
@ -424,7 +424,7 @@ bool Application::Impl::on_rpc_changed_idle(tr_rpc_callback_type type, int torre
|
|||
tr_variant* oldvals = gtr_pref_get_all();
|
||||
tr_quark key;
|
||||
std::vector<tr_quark> changed_keys;
|
||||
auto* session = core_->get_session();
|
||||
auto const* const session = core_->get_session();
|
||||
tr_variantInitDict(&tmp, 100);
|
||||
tr_sessionGetSettings(session, &tmp);
|
||||
|
||||
|
@ -1319,7 +1319,7 @@ bool Application::Impl::call_rpc_for_selected_torrents(std::string const& method
|
|||
sel_->selected_foreach(
|
||||
[ids](auto const& /*path*/, auto const& iter)
|
||||
{
|
||||
auto* tor = static_cast<tr_torrent*>(iter->get_value(torrent_cols.torrent));
|
||||
auto const* const tor = static_cast<tr_torrent*>(iter->get_value(torrent_cols.torrent));
|
||||
tr_variantListAddInt(ids, tr_torrentId(tor));
|
||||
});
|
||||
|
||||
|
|
|
@ -1353,7 +1353,7 @@ void refreshPeerRow(Gtk::TreeIter const& iter, tr_peer_stat const* peer)
|
|||
void DetailsDialog::Impl::refreshPeerList(std::vector<tr_torrent*> const& torrents)
|
||||
{
|
||||
auto& hash = peer_hash_;
|
||||
auto& store = peer_store_;
|
||||
auto const& store = peer_store_;
|
||||
|
||||
/* step 1: get all the peers */
|
||||
std::vector<tr_peer_stat*> peers;
|
||||
|
@ -1440,7 +1440,7 @@ void DetailsDialog::Impl::refreshWebseedList(std::vector<tr_torrent*> const& tor
|
|||
{
|
||||
auto has_any_webseeds = bool{ false };
|
||||
auto& hash = webseed_hash_;
|
||||
auto& store = webseed_store_;
|
||||
auto const& store = webseed_store_;
|
||||
|
||||
auto make_key = [](tr_torrent const* tor, char const* url)
|
||||
{
|
||||
|
@ -2152,7 +2152,7 @@ void DetailsDialog::Impl::refreshTracker(std::vector<tr_torrent*> const& torrent
|
|||
{
|
||||
std::ostringstream gstr;
|
||||
auto& hash = tracker_hash_;
|
||||
auto& store = tracker_store_;
|
||||
auto const& store = tracker_store_;
|
||||
auto* session = core_->get_session();
|
||||
bool const showScrape = scrape_check_->get_active();
|
||||
|
||||
|
@ -2261,7 +2261,7 @@ void DetailsDialog::Impl::on_edit_trackers_response(int response, std::shared_pt
|
|||
if (response == Gtk::RESPONSE_ACCEPT)
|
||||
{
|
||||
auto const torrent_id = GPOINTER_TO_INT(dialog->get_data(TORRENT_ID_KEY));
|
||||
auto* const text_buffer = static_cast<Gtk::TextBuffer*>(dialog->get_data(TEXT_BUFFER_KEY));
|
||||
auto const* const text_buffer = static_cast<Gtk::TextBuffer*>(dialog->get_data(TEXT_BUFFER_KEY));
|
||||
|
||||
if (auto* const tor = core_->find_torrent(torrent_id); tor != nullptr)
|
||||
{
|
||||
|
@ -2360,7 +2360,7 @@ void DetailsDialog::Impl::on_edit_trackers()
|
|||
void DetailsDialog::Impl::on_tracker_list_selection_changed()
|
||||
{
|
||||
int const n = tracker_view_->get_selection()->count_selected_rows();
|
||||
auto* tor = tracker_list_get_current_torrent();
|
||||
auto const* const tor = tracker_list_get_current_torrent();
|
||||
|
||||
remove_tracker_button_->set_sensitive(n > 0);
|
||||
add_tracker_button_->set_sensitive(tor != nullptr);
|
||||
|
@ -2373,7 +2373,7 @@ void DetailsDialog::Impl::on_add_tracker_response(int response, std::shared_ptr<
|
|||
|
||||
if (response == Gtk::RESPONSE_ACCEPT)
|
||||
{
|
||||
auto* e = static_cast<Gtk::Entry*>(dialog->get_data(URL_ENTRY_KEY));
|
||||
auto const* const e = static_cast<Gtk::Entry*>(dialog->get_data(URL_ENTRY_KEY));
|
||||
auto const torrent_id = GPOINTER_TO_INT(dialog->get_data(TORRENT_ID_KEY));
|
||||
auto const url = gtr_str_strip(e->get_text());
|
||||
|
||||
|
|
|
@ -421,7 +421,7 @@ using FileRowNode = Glib::NodeTree<row_struct>;
|
|||
|
||||
void buildTree(FileRowNode& node, build_data& build)
|
||||
{
|
||||
auto& child_data = node.data();
|
||||
auto const& child_data = node.data();
|
||||
bool const isLeaf = node.child_count() == 0;
|
||||
|
||||
auto const mime_type = isLeaf ? gtr_get_mime_type_from_filename(child_data.name) : DirectoryMimeType;
|
||||
|
|
|
@ -62,7 +62,7 @@ std::string _icon_cache_get_icon_key(Glib::RefPtr<Gio::Icon> const& icon)
|
|||
{
|
||||
std::string key;
|
||||
|
||||
if (auto* const ticon = dynamic_cast<Gio::ThemedIcon*>(gtr_get_ptr(icon)); ticon != nullptr)
|
||||
if (auto const* const ticon = dynamic_cast<Gio::ThemedIcon*>(gtr_get_ptr(icon)); ticon != nullptr)
|
||||
{
|
||||
std::ostringstream names;
|
||||
for (auto const& name : ticon->get_names())
|
||||
|
|
|
@ -413,7 +413,7 @@ void TorrentFileChooserDialog::onOpenDialogResponse(int response, Glib::RefPtr<S
|
|||
|
||||
if (response == Gtk::RESPONSE_ACCEPT)
|
||||
{
|
||||
auto* tb = static_cast<Gtk::CheckButton*>(get_extra_widget());
|
||||
auto const* const tb = static_cast<Gtk::CheckButton*>(get_extra_widget());
|
||||
bool const do_start = gtr_pref_flag_get(TR_KEY_start_added_torrents);
|
||||
bool const do_prompt = tb->get_active();
|
||||
bool const do_notify = false;
|
||||
|
|
|
@ -99,7 +99,7 @@ bool spun_cb_idle(Gtk::SpinButton* spin, tr_quark const key, Glib::RefPtr<Sessio
|
|||
bool keep_waiting = true;
|
||||
|
||||
/* has the user stopped making changes? */
|
||||
if (auto* last_change = static_cast<Glib::Timer*>(spin->get_data(IdleDataKey)); last_change->elapsed() > 0.33)
|
||||
if (auto const* const last_change = static_cast<Glib::Timer*>(spin->get_data(IdleDataKey)); last_change->elapsed() > 0.33)
|
||||
{
|
||||
/* update the core */
|
||||
if (isDouble)
|
||||
|
|
|
@ -393,7 +393,7 @@ auto const ChildHiddenKey = Glib::Quark("gtr-child-hidden");
|
|||
void gtr_widget_set_visible(Gtk::Widget& w, bool b)
|
||||
{
|
||||
/* toggle the transient children, too */
|
||||
if (auto* const window = dynamic_cast<Gtk::Window*>(&w); window != nullptr)
|
||||
if (auto const* const window = dynamic_cast<Gtk::Window*>(&w); window != nullptr)
|
||||
{
|
||||
for (auto* const l : Gtk::Window::list_toplevels())
|
||||
{
|
||||
|
|
|
@ -194,8 +194,8 @@ static tr_scrape_info* tr_announcerGetScrapeInfo(tr_announcer* announcer, tr_int
|
|||
}
|
||||
|
||||
auto& scrapes = announcer->scrape_info;
|
||||
auto const it = scrapes.try_emplace(url, url, TR_MULTISCRAPE_MAX);
|
||||
return &it.first->second;
|
||||
auto const [it, is_new] = scrapes.try_emplace(url, url, TR_MULTISCRAPE_MAX);
|
||||
return &it->second;
|
||||
}
|
||||
|
||||
void tr_announcerInit(tr_session* session)
|
||||
|
@ -403,7 +403,7 @@ struct tr_tier
|
|||
auto const* const torrent_name = tr_torrentName(tor);
|
||||
auto const* const current_tracker = currentTracker();
|
||||
auto const host_sv = current_tracker == nullptr ? "?"sv : current_tracker->host.sv();
|
||||
tr_snprintf(buf, buflen, "%s at %" TR_PRIsv, torrent_name, TR_PRIsv_ARG(host_sv));
|
||||
*fmt::format_to_n(buf, buflen - 1, FMT_STRING("{:s} at {:s}"), torrent_name, host_sv).out = '\0';
|
||||
}
|
||||
|
||||
[[nodiscard]] bool canManualAnnounce() const
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
|
||||
#include <event2/util.h> /* evutil_ascii_strcasecmp() */
|
||||
|
||||
#include <fmt/core.h>
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include "transmission.h"
|
||||
|
@ -326,7 +325,7 @@ static std::vector<std::byte> getHashInfo(tr_metainfo_builder* b)
|
|||
if (!digest)
|
||||
{
|
||||
b->my_errno = EIO;
|
||||
tr_snprintf(b->errfile, sizeof(b->errfile), "error hashing piece %" PRIu32, b->pieceIndex);
|
||||
*fmt::format_to_n(b->errfile, sizeof(b->errfile) - 1, "error hashing piece {:d}", b->pieceIndex).out = '\0';
|
||||
b->result = TrMakemetaResult::ERR_IO_READ;
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -65,7 +65,7 @@ char const* tr_address_and_port_to_string(char* buf, size_t buflen, tr_address c
|
|||
{
|
||||
char addr_buf[INET6_ADDRSTRLEN];
|
||||
tr_address_to_string_with_buf(addr, addr_buf, sizeof(addr_buf));
|
||||
tr_snprintf(buf, buflen, "[%s]:%u", addr_buf, ntohs(port));
|
||||
*fmt::format_to_n(buf, buflen - 1, FMT_STRING("[{:s}]:{:d}"), addr_buf, ntohs(port)).out = '\0';
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
|
|
@ -182,7 +182,7 @@ std::vector<tr_peer*> ActiveRequests::remove(tr_block_index_t block)
|
|||
impl_->blocks_.erase(block);
|
||||
}
|
||||
|
||||
for (auto* peer : removed)
|
||||
for (auto const* const peer : removed)
|
||||
{
|
||||
impl_->decCount(peer);
|
||||
}
|
||||
|
@ -221,7 +221,7 @@ std::vector<std::pair<tr_block_index_t, tr_peer*>> ActiveRequests::sentBefore(ti
|
|||
auto sent_before = std::vector<std::pair<tr_block_index_t, tr_peer*>>{};
|
||||
sent_before.reserve(std::size(impl_->blocks_));
|
||||
|
||||
for (auto& [block, peers_at] : impl_->blocks_)
|
||||
for (auto const& [block, peers_at] : impl_->blocks_)
|
||||
{
|
||||
for (auto const& sent : peers_at)
|
||||
{
|
||||
|
|
|
@ -2111,7 +2111,7 @@ static void rechokeUploads(tr_swarm* s, uint64_t const now)
|
|||
for (int i = 0; i < peerCount; ++i)
|
||||
{
|
||||
auto* const peer = peers[i];
|
||||
struct peer_atom* const atom = peer->atom;
|
||||
peer_atom const* const atom = peer->atom;
|
||||
|
||||
if (tr_peerIsSeed(peer))
|
||||
{
|
||||
|
@ -2363,7 +2363,7 @@ static void removePeer(tr_peer* peer)
|
|||
static void closePeer(tr_peer* peer)
|
||||
{
|
||||
TR_ASSERT(peer != nullptr);
|
||||
auto* const s = peer->swarm;
|
||||
auto const* const s = peer->swarm;
|
||||
|
||||
/* if we transferred piece data, then they might be good peers,
|
||||
so reset their `numFails' weight to zero. otherwise we connected
|
||||
|
|
|
@ -86,13 +86,10 @@ struct tr_rpc_idle_data
|
|||
void* callback_user_data;
|
||||
};
|
||||
|
||||
static void tr_idle_function_done(struct tr_rpc_idle_data* data, char const* result)
|
||||
{
|
||||
if (result == nullptr)
|
||||
{
|
||||
result = "success";
|
||||
}
|
||||
static auto constexpr SuccessResult = "success"sv;
|
||||
|
||||
static void tr_idle_function_done(struct tr_rpc_idle_data* data, std::string_view result)
|
||||
{
|
||||
tr_variantDictAddStr(data->response, TR_KEY_result, result);
|
||||
|
||||
(*data->callback)(data->session, data->response, data->callback_user_data);
|
||||
|
@ -1069,7 +1066,7 @@ static char const* addTrackerUrls(tr_torrent* tor, tr_variant* urls)
|
|||
for (size_t i = 0, n = tr_variantListSize(urls); i < n; ++i)
|
||||
{
|
||||
auto announce = std::string_view();
|
||||
auto* const val = tr_variantListChild(urls, i);
|
||||
auto const* const val = tr_variantListChild(urls, i);
|
||||
if (val == nullptr || !tr_variantGetStrView(val, &announce))
|
||||
{
|
||||
continue;
|
||||
|
@ -1121,7 +1118,7 @@ static char const* removeTrackers(tr_torrent* tor, tr_variant* ids)
|
|||
for (size_t i = 0, n = tr_variantListSize(ids); i < n; ++i)
|
||||
{
|
||||
auto id = int64_t{};
|
||||
auto* const val = tr_variantListChild(ids, i);
|
||||
auto const* const val = tr_variantListChild(ids, i);
|
||||
if (val == nullptr || !tr_variantGetInt(val, &id))
|
||||
{
|
||||
continue;
|
||||
|
@ -1326,8 +1323,7 @@ static void torrentRenamePathDone(tr_torrent* tor, char const* oldpath, char con
|
|||
tr_variantDictAddStr(data->args_out, TR_KEY_path, oldpath);
|
||||
tr_variantDictAddStr(data->args_out, TR_KEY_name, newname);
|
||||
|
||||
char const* const result = error == 0 ? nullptr : tr_strerror(error);
|
||||
tr_idle_function_done(data, result);
|
||||
tr_idle_function_done(data, error != 0 ? tr_strerror(error) : SuccessResult);
|
||||
}
|
||||
|
||||
static char const* torrentRenamePath(
|
||||
|
@ -1363,21 +1359,23 @@ static char const* torrentRenamePath(
|
|||
static void onPortTested(tr_web::FetchResponse const& web_response)
|
||||
{
|
||||
auto const& [status, body, did_connect, did_tmieout, user_data] = web_response;
|
||||
char result[1024];
|
||||
auto* data = static_cast<struct tr_rpc_idle_data*>(user_data);
|
||||
|
||||
if (status != 200)
|
||||
{
|
||||
tr_snprintf(result, sizeof(result), "portTested: http error %ld: %s", status, tr_webGetResponseStr(status));
|
||||
tr_idle_function_done(
|
||||
data,
|
||||
fmt::format(
|
||||
_("Couldn't test port: {error} ({error_code})"),
|
||||
fmt::arg("error", tr_webGetResponseStr(status)),
|
||||
fmt::arg("error_code", status)));
|
||||
}
|
||||
else /* success */
|
||||
{
|
||||
bool const isOpen = tr_strvStartsWith(body, '1');
|
||||
tr_variantDictAddBool(data->args_out, TR_KEY_port_is_open, isOpen);
|
||||
tr_snprintf(result, sizeof(result), "success");
|
||||
tr_idle_function_done(data, SuccessResult);
|
||||
}
|
||||
|
||||
tr_idle_function_done(data, result);
|
||||
}
|
||||
|
||||
static char const* portTest(
|
||||
|
@ -1402,13 +1400,15 @@ static void onBlocklistFetched(tr_web::FetchResponse const& web_response)
|
|||
auto* data = static_cast<struct tr_rpc_idle_data*>(user_data);
|
||||
auto* const session = data->session;
|
||||
|
||||
char result[1024] = {};
|
||||
|
||||
if (status != 200)
|
||||
{
|
||||
// we failed to download the blocklist...
|
||||
tr_snprintf(result, sizeof(result), "gotNewBlocklist: http error %ld: %s", status, tr_webGetResponseStr(status));
|
||||
tr_idle_function_done(data, result);
|
||||
tr_idle_function_done(
|
||||
data,
|
||||
fmt::format(
|
||||
_("Couldn't fetch blocklist: {error} ({error_code})"),
|
||||
fmt::arg("error", tr_webGetResponseStr(status)),
|
||||
fmt::arg("error_code", status)));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1446,15 +1446,14 @@ static void onBlocklistFetched(tr_web::FetchResponse const& web_response)
|
|||
auto const filename = tr_pathbuf{ session->config_dir, "/blocklist.tmp"sv };
|
||||
if (tr_error* error = nullptr; !tr_saveFile(filename, content, &error))
|
||||
{
|
||||
fmt::format_to_n(
|
||||
result,
|
||||
sizeof(result),
|
||||
_("Couldn't save '{path}': {error} ({error_code})"),
|
||||
fmt::arg("path", filename),
|
||||
fmt::arg("error", error->message),
|
||||
fmt::arg("error_code", error->code));
|
||||
tr_idle_function_done(
|
||||
data,
|
||||
fmt::format(
|
||||
_("Couldn't save '{path}': {error} ({error_code})"),
|
||||
fmt::arg("path", filename),
|
||||
fmt::arg("error", error->message),
|
||||
fmt::arg("error_code", error->code)));
|
||||
tr_error_clear(&error);
|
||||
tr_idle_function_done(data, result);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1462,7 +1461,7 @@ static void onBlocklistFetched(tr_web::FetchResponse const& web_response)
|
|||
int const rule_count = tr_blocklistSetContent(session, filename);
|
||||
tr_variantDictAddInt(data->args_out, TR_KEY_blocklist_size, rule_count);
|
||||
tr_sys_path_remove(filename);
|
||||
tr_idle_function_done(data, "success");
|
||||
tr_idle_function_done(data, SuccessResult);
|
||||
}
|
||||
|
||||
static char const* blocklistUpdate(
|
||||
|
@ -1485,39 +1484,33 @@ static void addTorrentImpl(struct tr_rpc_idle_data* data, tr_ctor* ctor)
|
|||
tr_torrent* tor = tr_torrentNew(ctor, &duplicate_of);
|
||||
tr_ctorFree(ctor);
|
||||
|
||||
auto key = tr_quark{};
|
||||
char const* result = "invalid or corrupt torrent file";
|
||||
if (tor != nullptr)
|
||||
if (tor == nullptr && duplicate_of == nullptr)
|
||||
{
|
||||
key = TR_KEY_torrent_added;
|
||||
result = nullptr;
|
||||
}
|
||||
else if (duplicate_of != nullptr)
|
||||
{
|
||||
tor = duplicate_of;
|
||||
key = TR_KEY_torrent_duplicate;
|
||||
result = "duplicate torrent";
|
||||
tr_idle_function_done(data, "invalid or corrupt torrent file"sv);
|
||||
return;
|
||||
}
|
||||
|
||||
if (tor != nullptr && key != 0)
|
||||
static auto constexpr Fields = std::array<tr_quark, 3>{ TR_KEY_id, TR_KEY_name, TR_KEY_hashString };
|
||||
if (duplicate_of != nullptr)
|
||||
{
|
||||
tr_quark const fields[] = {
|
||||
TR_KEY_id,
|
||||
TR_KEY_name,
|
||||
TR_KEY_hashString,
|
||||
};
|
||||
|
||||
addTorrentInfo(tor, TrFormat::Object, tr_variantDictAdd(data->args_out, key), fields, TR_N_ELEMENTS(fields));
|
||||
|
||||
if (result == nullptr)
|
||||
{
|
||||
notify(data->session, TR_RPC_TORRENT_ADDED, tor);
|
||||
}
|
||||
|
||||
result = nullptr;
|
||||
addTorrentInfo(
|
||||
duplicate_of,
|
||||
TrFormat::Object,
|
||||
tr_variantDictAdd(data->args_out, TR_KEY_torrent_duplicate),
|
||||
std::data(Fields),
|
||||
std::size(Fields));
|
||||
tr_idle_function_done(data, "duplicate torrent"sv);
|
||||
return;
|
||||
}
|
||||
|
||||
tr_idle_function_done(data, result);
|
||||
notify(data->session, TR_RPC_TORRENT_ADDED, tor);
|
||||
addTorrentInfo(
|
||||
tor,
|
||||
TrFormat::Object,
|
||||
tr_variantDictAdd(data->args_out, TR_KEY_torrent_added),
|
||||
std::data(Fields),
|
||||
std::size(Fields));
|
||||
tr_idle_function_done(data, SuccessResult);
|
||||
}
|
||||
|
||||
struct add_torrent_idle_data
|
||||
|
@ -1544,9 +1537,12 @@ static void onMetadataFetched(tr_web::FetchResponse const& web_response)
|
|||
}
|
||||
else
|
||||
{
|
||||
char result[1024];
|
||||
tr_snprintf(result, sizeof(result), "onMetadataFetched: http error %ld: %s", status, tr_webGetResponseStr(status));
|
||||
tr_idle_function_done(data->data, result);
|
||||
tr_idle_function_done(
|
||||
data->data,
|
||||
fmt::format(
|
||||
_("Couldn't fetch torrent: {error} ({error_code})"),
|
||||
fmt::arg("error", tr_webGetResponseStr(status)),
|
||||
fmt::arg("error_code", status)));
|
||||
}
|
||||
|
||||
tr_free(data);
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
|
||||
#include <event2/event.h>
|
||||
|
||||
#include <fmt/core.h>
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include "transmission.h"
|
||||
|
||||
|
@ -106,12 +106,11 @@ static void bootstrap_from_name(char const* name, tr_port port, int af)
|
|||
hints.ai_socktype = SOCK_DGRAM;
|
||||
hints.ai_family = af;
|
||||
|
||||
/* No, just passing p + 1 to gai won't work. */
|
||||
char pp[10];
|
||||
tr_snprintf(pp, sizeof(pp), "%d", (int)port);
|
||||
auto port_str = std::array<char, 16>{};
|
||||
*fmt::format_to(std::data(port_str), FMT_STRING("{:d}"), port) = '\0';
|
||||
|
||||
addrinfo* info = nullptr;
|
||||
if (int const rc = getaddrinfo(name, pp, &hints, &info); rc != 0)
|
||||
if (int const rc = getaddrinfo(name, std::data(port_str), &hints, &info); rc != 0)
|
||||
{
|
||||
tr_logAddWarn(fmt::format(
|
||||
_("Couldn't look up '{addresss}:{port}': {error} ({error_code})"),
|
||||
|
|
|
@ -114,6 +114,12 @@ public:
|
|||
return std::basic_string_view<Char>{ data(), size() };
|
||||
}
|
||||
|
||||
template<typename ContiguousRange>
|
||||
[[nodiscard]] constexpr auto operator==(ContiguousRange const& x) const noexcept
|
||||
{
|
||||
return sv() == x;
|
||||
}
|
||||
|
||||
///
|
||||
|
||||
[[nodiscard]] constexpr bool ends_with(Char const& x) const noexcept
|
||||
|
|
|
@ -140,18 +140,17 @@ static int tr_upnpGetSpecificPortMappingEntry(tr_upnp* handle, char const* proto
|
|||
{
|
||||
char intClient[16];
|
||||
char intPort[16];
|
||||
char portStr[16];
|
||||
|
||||
*intClient = '\0';
|
||||
*intPort = '\0';
|
||||
|
||||
tr_snprintf(portStr, sizeof(portStr), "%d", handle->port);
|
||||
auto const port_str = fmt::format(FMT_STRING("{:d}"), handle->port);
|
||||
|
||||
#if (MINIUPNPC_API_VERSION >= 10) /* adds remoteHost arg */
|
||||
int const err = UPNP_GetSpecificPortMappingEntry(
|
||||
handle->urls.controlURL,
|
||||
handle->data.first.servicetype,
|
||||
portStr,
|
||||
port_str.c_str(),
|
||||
proto,
|
||||
nullptr /*remoteHost*/,
|
||||
intClient,
|
||||
|
@ -163,7 +162,7 @@ static int tr_upnpGetSpecificPortMappingEntry(tr_upnp* handle, char const* proto
|
|||
int const err = UPNP_GetSpecificPortMappingEntry(
|
||||
handle->urls.controlURL,
|
||||
handle->data.first.servicetype,
|
||||
portStr,
|
||||
port_str.c_str(),
|
||||
proto,
|
||||
intClient,
|
||||
intPort,
|
||||
|
@ -174,7 +173,7 @@ static int tr_upnpGetSpecificPortMappingEntry(tr_upnp* handle, char const* proto
|
|||
int const err = UPNP_GetSpecificPortMappingEntry(
|
||||
handle->urls.controlURL,
|
||||
handle->data.first.servicetype,
|
||||
portStr,
|
||||
port_str.c_str(),
|
||||
proto,
|
||||
intClient,
|
||||
intPort);
|
||||
|
@ -186,17 +185,16 @@ static int tr_upnpGetSpecificPortMappingEntry(tr_upnp* handle, char const* proto
|
|||
static int tr_upnpAddPortMapping(tr_upnp const* handle, char const* proto, tr_port port, char const* desc)
|
||||
{
|
||||
int const old_errno = errno;
|
||||
char portStr[16];
|
||||
errno = 0;
|
||||
|
||||
tr_snprintf(portStr, sizeof(portStr), "%d", (int)port);
|
||||
auto const port_str = fmt::format(FMT_STRING("{:d}"), port);
|
||||
|
||||
#if (MINIUPNPC_API_VERSION >= 8)
|
||||
int err = UPNP_AddPortMapping(
|
||||
handle->urls.controlURL,
|
||||
handle->data.first.servicetype,
|
||||
portStr,
|
||||
portStr,
|
||||
port_str.c_str(),
|
||||
port_str.c_str(),
|
||||
handle->lanaddr,
|
||||
desc,
|
||||
proto,
|
||||
|
@ -206,8 +204,8 @@ static int tr_upnpAddPortMapping(tr_upnp const* handle, char const* proto, tr_po
|
|||
int err = UPNP_AddPortMapping(
|
||||
handle->urls.controlURL,
|
||||
handle->data.first.servicetype,
|
||||
portStr,
|
||||
portStr,
|
||||
port_str.c_str(),
|
||||
port_str.c_str(),
|
||||
handle->lanaddr,
|
||||
desc,
|
||||
proto,
|
||||
|
@ -225,11 +223,9 @@ static int tr_upnpAddPortMapping(tr_upnp const* handle, char const* proto, tr_po
|
|||
|
||||
static void tr_upnpDeletePortMapping(tr_upnp const* handle, char const* proto, tr_port port)
|
||||
{
|
||||
char portStr[16];
|
||||
auto const port_str = fmt::format(FMT_STRING("{:d}"), port);
|
||||
|
||||
tr_snprintf(portStr, sizeof(portStr), "%d", (int)port);
|
||||
|
||||
UPNP_DeletePortMapping(handle->urls.controlURL, handle->data.first.servicetype, portStr, proto, nullptr);
|
||||
UPNP_DeletePortMapping(handle->urls.controlURL, handle->data.first.servicetype, port_str.c_str(), proto, nullptr);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -338,11 +334,9 @@ tr_port_forwarding tr_upnpPulse(tr_upnp* handle, tr_port port, bool isEnabled, b
|
|||
}
|
||||
else
|
||||
{
|
||||
char desc[64];
|
||||
tr_snprintf(desc, sizeof(desc), "%s at %d", TR_NAME, port);
|
||||
|
||||
int const err_tcp = tr_upnpAddPortMapping(handle, "TCP", port, desc);
|
||||
int const err_udp = tr_upnpAddPortMapping(handle, "UDP", port, desc);
|
||||
auto const desc = fmt::format(FMT_STRING("{:s} at {:d}"), TR_NAME, port);
|
||||
int const err_tcp = tr_upnpAddPortMapping(handle, "TCP", port, desc.c_str());
|
||||
int const err_udp = tr_upnpAddPortMapping(handle, "UDP", port, desc.c_str());
|
||||
|
||||
handle->isMapped = err_tcp == 0 || err_udp == 0;
|
||||
}
|
||||
|
|
|
@ -428,12 +428,6 @@ char* tr_strvDup(std::string_view in)
|
|||
return ret;
|
||||
}
|
||||
|
||||
char* tr_strndup(void const* vin, size_t len)
|
||||
{
|
||||
auto const* const in = static_cast<char const*>(vin);
|
||||
return in == nullptr ? nullptr : tr_strvDup({ in, len });
|
||||
}
|
||||
|
||||
char* tr_strdup(void const* in)
|
||||
{
|
||||
return in == nullptr ? nullptr : tr_strvDup(static_cast<char const*>(in));
|
||||
|
@ -722,7 +716,7 @@ static char* to_utf8(std::string_view sv)
|
|||
iconv_close(cd);
|
||||
if (rv != size_t(-1))
|
||||
{
|
||||
char* const ret = tr_strndup(out, buflen - outbytesleft);
|
||||
char* const ret = tr_strvDup({ out, buflen - outbytesleft });
|
||||
tr_free(out);
|
||||
return ret;
|
||||
}
|
||||
|
@ -1129,18 +1123,14 @@ bool tr_moveFile(char const* oldpath, char const* newpath, tr_error** error)
|
|||
return false;
|
||||
}
|
||||
|
||||
if (tr_error* my_error = nullptr; !tr_sys_path_remove(oldpath, &my_error))
|
||||
{
|
||||
tr_error* my_error = nullptr;
|
||||
|
||||
if (!tr_sys_path_remove(oldpath, &my_error))
|
||||
{
|
||||
tr_logAddError(fmt::format(
|
||||
_("Couldn't remove '{path}': {error} ({error_code})"),
|
||||
fmt::arg("path", oldpath),
|
||||
fmt::arg("error", my_error->message),
|
||||
fmt::arg("error_code", my_error->code)));
|
||||
tr_error_free(my_error);
|
||||
}
|
||||
tr_logAddError(fmt::format(
|
||||
_("Couldn't remove '{path}': {error} ({error_code})"),
|
||||
fmt::arg("path", oldpath),
|
||||
fmt::arg("error", my_error->message),
|
||||
fmt::arg("error_code", my_error->code)));
|
||||
tr_error_free(my_error);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
@ -242,14 +242,6 @@ void* tr_memdup(void const* src, size_t byteCount);
|
|||
#define tr_renew(struct_type, mem, n_structs) \
|
||||
(static_cast<struct_type*>(tr_realloc((mem), sizeof(struct_type) * (size_t)(n_structs))))
|
||||
|
||||
/**
|
||||
* @brief make a newly-allocated copy of a substring
|
||||
* @param in is a void* so that callers can pass in both signed & unsigned without a cast
|
||||
* @param len length of the substring to copy. if a length less than zero is passed in, strlen(len) is used
|
||||
* @return a newly-allocated copy of `in' that can be freed with tr_free()
|
||||
*/
|
||||
char* tr_strndup(void const* in, size_t len) TR_GNUC_MALLOC;
|
||||
|
||||
/**
|
||||
* @brief make a newly-allocated copy of a string
|
||||
* @param in is a void* so that callers can pass in both signed & unsigned without a cast
|
||||
|
|
|
@ -12,6 +12,9 @@
|
|||
|
||||
#include <event2/buffer.h>
|
||||
|
||||
#include <fmt/compile.h>
|
||||
#include <fmt/format.h>
|
||||
|
||||
#define LIBTRANSMISSION_VARIANT_MODULE
|
||||
|
||||
#include "transmission.h"
|
||||
|
@ -19,7 +22,7 @@
|
|||
#include "benc.h"
|
||||
#include "tr-assert.h"
|
||||
#include "quark.h"
|
||||
#include "utils.h" /* tr_snprintf() */
|
||||
#include "utils.h"
|
||||
#include "variant-common.h"
|
||||
#include "variant.h"
|
||||
|
||||
|
@ -256,13 +259,15 @@ bool tr_variantParseBenc(tr_variant& top, int parse_opts, std::string_view benc,
|
|||
|
||||
static void saveIntFunc(tr_variant const* val, void* vevbuf)
|
||||
{
|
||||
auto* evbuf = static_cast<struct evbuffer*>(vevbuf);
|
||||
evbuffer_add_printf(evbuf, "i%" PRId64 "e", val->val.i);
|
||||
auto buf = std::array<char, 64>{};
|
||||
auto const out = fmt::format_to(std::data(buf), FMT_COMPILE("i{:d}e"), val->val.i);
|
||||
auto* const evbuf = static_cast<evbuffer*>(vevbuf);
|
||||
evbuffer_add(evbuf, std::data(buf), static_cast<size_t>(out - std::data(buf)));
|
||||
}
|
||||
|
||||
static void saveBoolFunc(tr_variant const* val, void* vevbuf)
|
||||
{
|
||||
auto* evbuf = static_cast<struct evbuffer*>(vevbuf);
|
||||
auto* const evbuf = static_cast<evbuffer*>(vevbuf);
|
||||
if (val->val.b)
|
||||
{
|
||||
evbuffer_add(evbuf, "i1e", 3);
|
||||
|
@ -273,41 +278,48 @@ static void saveBoolFunc(tr_variant const* val, void* vevbuf)
|
|||
}
|
||||
}
|
||||
|
||||
static void saveRealFunc(tr_variant const* val, void* vevbuf)
|
||||
static void saveStringImpl(evbuffer* evbuf, std::string_view sv)
|
||||
{
|
||||
auto buf = std::array<char, 64>{};
|
||||
int const len = tr_snprintf(std::data(buf), std::size(buf), "%f", val->val.d);
|
||||
|
||||
auto* evbuf = static_cast<evbuffer*>(vevbuf);
|
||||
evbuffer_add_printf(evbuf, "%d:", len);
|
||||
evbuffer_add(evbuf, std::data(buf), len);
|
||||
// `${sv.size()}:${sv}`
|
||||
auto prefix = std::array<char, 32>{};
|
||||
auto out = fmt::format_to(std::data(prefix), FMT_COMPILE("{:d}:"), std::size(sv));
|
||||
evbuffer_add(evbuf, std::data(prefix), out - std::data(prefix));
|
||||
evbuffer_add(evbuf, std::data(sv), std::size(sv));
|
||||
}
|
||||
|
||||
static void saveStringFunc(tr_variant const* v, void* vevbuf)
|
||||
{
|
||||
auto sv = std::string_view{};
|
||||
(void)!tr_variantGetStrView(v, &sv);
|
||||
auto* const evbuf = static_cast<evbuffer*>(vevbuf);
|
||||
saveStringImpl(evbuf, sv);
|
||||
}
|
||||
|
||||
auto* evbuf = static_cast<struct evbuffer*>(vevbuf);
|
||||
evbuffer_add_printf(evbuf, "%zu:", std::size(sv));
|
||||
evbuffer_add(evbuf, std::data(sv), std::size(sv));
|
||||
static void saveRealFunc(tr_variant const* val, void* vevbuf)
|
||||
{
|
||||
// the benc spec doesn't handle floats; save it as a string.
|
||||
|
||||
auto buf = std::array<char, 64>{};
|
||||
auto out = fmt::format_to(std::data(buf), FMT_COMPILE("{:f}"), val->val.d);
|
||||
auto* const evbuf = static_cast<evbuffer*>(vevbuf);
|
||||
saveStringImpl(evbuf, { std::data(buf), static_cast<size_t>(out - std::data(buf)) });
|
||||
}
|
||||
|
||||
static void saveDictBeginFunc(tr_variant const* /*val*/, void* vevbuf)
|
||||
{
|
||||
auto* evbuf = static_cast<struct evbuffer*>(vevbuf);
|
||||
auto* const evbuf = static_cast<evbuffer*>(vevbuf);
|
||||
evbuffer_add(evbuf, "d", 1);
|
||||
}
|
||||
|
||||
static void saveListBeginFunc(tr_variant const* /*val*/, void* vevbuf)
|
||||
{
|
||||
auto* evbuf = static_cast<struct evbuffer*>(vevbuf);
|
||||
auto* const evbuf = static_cast<evbuffer*>(vevbuf);
|
||||
evbuffer_add(evbuf, "l", 1);
|
||||
}
|
||||
|
||||
static void saveContainerEndFunc(tr_variant const* /*val*/, void* vevbuf)
|
||||
{
|
||||
auto* evbuf = static_cast<struct evbuffer*>(vevbuf);
|
||||
auto* const evbuf = static_cast<evbuffer*>(vevbuf);
|
||||
evbuffer_add(evbuf, "e", 1);
|
||||
}
|
||||
|
||||
|
@ -321,7 +333,7 @@ static struct VariantWalkFuncs const walk_funcs = {
|
|||
saveContainerEndFunc, //
|
||||
};
|
||||
|
||||
void tr_variantToBufBenc(tr_variant const* top, struct evbuffer* buf)
|
||||
void tr_variantToBufBenc(tr_variant const* top, evbuffer* buf)
|
||||
{
|
||||
tr_variantWalk(top, &walk_funcs, buf, true);
|
||||
}
|
||||
|
|
|
@ -16,7 +16,8 @@
|
|||
|
||||
#include <event2/buffer.h>
|
||||
|
||||
#include <fmt/core.h>
|
||||
#include <fmt/compile.h>
|
||||
#include <fmt/format.h>
|
||||
|
||||
#define LIBTRANSMISSION_VARIANT_MODULE
|
||||
|
||||
|
@ -162,7 +163,7 @@ static bool decode_hex_string(char const* in, unsigned int* setme)
|
|||
return true;
|
||||
}
|
||||
|
||||
static std::string_view extract_escaped_string(char const* in, size_t in_len, struct evbuffer* buf)
|
||||
static std::string_view extract_escaped_string(char const* in, size_t in_len, evbuffer* buf)
|
||||
{
|
||||
char const* const in_end = in + in_len;
|
||||
|
||||
|
@ -225,27 +226,25 @@ static std::string_view extract_escaped_string(char const* in, size_t in_len, st
|
|||
break;
|
||||
|
||||
case 'u':
|
||||
if (in_end - in >= 6)
|
||||
{
|
||||
if (in_end - in >= 6)
|
||||
{
|
||||
unsigned int val = 0;
|
||||
unsigned int val = 0;
|
||||
|
||||
if (decode_hex_string(in, &val))
|
||||
if (decode_hex_string(in, &val))
|
||||
{
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
auto buf8 = std::array<char, 8>{};
|
||||
auto const it = utf8::append(val, std::data(buf8));
|
||||
evbuffer_add(buf, std::data(buf8), it - std::data(buf8));
|
||||
}
|
||||
catch (utf8::exception const&)
|
||||
{ // invalid codepoint
|
||||
evbuffer_add(buf, "?", 1);
|
||||
}
|
||||
unescaped = true;
|
||||
in += 6;
|
||||
break;
|
||||
auto buf8 = std::array<char, 8>{};
|
||||
auto const it = utf8::append(val, std::data(buf8));
|
||||
evbuffer_add(buf, std::data(buf8), it - std::data(buf8));
|
||||
}
|
||||
catch (utf8::exception const&)
|
||||
{ // invalid codepoint
|
||||
evbuffer_add(buf, "?", 1);
|
||||
}
|
||||
unescaped = true;
|
||||
in += 6;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -261,7 +260,7 @@ static std::string_view extract_escaped_string(char const* in, size_t in_len, st
|
|||
return { (char const*)evbuffer_pullup(buf, -1), evbuffer_get_length(buf) };
|
||||
}
|
||||
|
||||
static std::pair<std::string_view, bool> extract_string(jsonsl_t jsn, struct jsonsl_state_st* state, struct evbuffer* buf)
|
||||
static std::pair<std::string_view, bool> extract_string(jsonsl_t jsn, struct jsonsl_state_st* state, evbuffer* buf)
|
||||
{
|
||||
// figure out where the string is
|
||||
char const* in_begin = jsn->base + state->pos_begin;
|
||||
|
@ -311,7 +310,7 @@ static void action_callback_POP(
|
|||
else if (state->type == JSONSL_T_LIST || state->type == JSONSL_T_OBJECT)
|
||||
{
|
||||
int const depth = std::size(data->stack);
|
||||
auto* v = data->stack.back();
|
||||
auto const* const v = data->stack.back();
|
||||
data->stack.pop_back();
|
||||
if (depth < MaxDepth)
|
||||
{
|
||||
|
@ -407,7 +406,7 @@ struct jsonWalk
|
|||
{
|
||||
bool doIndent;
|
||||
std::deque<ParentState> parents;
|
||||
struct evbuffer* out;
|
||||
evbuffer* out;
|
||||
};
|
||||
|
||||
static void jsonIndent(struct jsonWalk* data)
|
||||
|
@ -457,17 +456,15 @@ static void jsonChildFunc(struct jsonWalk* data)
|
|||
}
|
||||
|
||||
case TR_VARIANT_TYPE_LIST:
|
||||
++pstate.childIndex;
|
||||
if (bool const is_last = pstate.childIndex == pstate.childCount; !is_last)
|
||||
{
|
||||
++pstate.childIndex;
|
||||
if (bool const is_last = pstate.childIndex == pstate.childCount; !is_last)
|
||||
{
|
||||
evbuffer_add(data->out, ",", 1);
|
||||
jsonIndent(data);
|
||||
}
|
||||
|
||||
break;
|
||||
evbuffer_add(data->out, ",", 1);
|
||||
jsonIndent(data);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -487,8 +484,10 @@ static void jsonPopParent(struct jsonWalk* data)
|
|||
|
||||
static void jsonIntFunc(tr_variant const* val, void* vdata)
|
||||
{
|
||||
auto* data = static_cast<struct jsonWalk*>(vdata);
|
||||
evbuffer_add_printf(data->out, "%" PRId64, val->val.i);
|
||||
auto buf = std::array<char, 64>{};
|
||||
auto const out = fmt::format_to(std::data(buf), FMT_COMPILE("{:d}"), val->val.i);
|
||||
auto* const data = static_cast<jsonWalk*>(vdata);
|
||||
evbuffer_add(data->out, std::data(buf), static_cast<size_t>(out - std::data(buf)));
|
||||
jsonChildFunc(data);
|
||||
}
|
||||
|
||||
|
@ -514,11 +513,15 @@ static void jsonRealFunc(tr_variant const* val, void* vdata)
|
|||
|
||||
if (fabs(val->val.d - (int)val->val.d) < 0.00001)
|
||||
{
|
||||
evbuffer_add_printf(data->out, "%d", (int)val->val.d);
|
||||
auto buf = std::array<char, 64>{};
|
||||
auto const out = fmt::format_to(std::data(buf), FMT_COMPILE("{:.0f}"), val->val.d);
|
||||
evbuffer_add(data->out, std::data(buf), static_cast<size_t>(out - std::data(buf)));
|
||||
}
|
||||
else
|
||||
{
|
||||
evbuffer_add_printf(data->out, "%.4f", tr_truncd(val->val.d, 4));
|
||||
auto buf = std::array<char, 64>{};
|
||||
auto const out = fmt::format_to(std::data(buf), FMT_COMPILE("{:.4f}"), val->val.d);
|
||||
evbuffer_add(data->out, std::data(buf), static_cast<size_t>(out - std::data(buf)));
|
||||
}
|
||||
|
||||
jsonChildFunc(data);
|
||||
|
@ -526,7 +529,7 @@ static void jsonRealFunc(tr_variant const* val, void* vdata)
|
|||
|
||||
static void jsonStringFunc(tr_variant const* val, void* vdata)
|
||||
{
|
||||
struct evbuffer_iovec vec[1];
|
||||
evbuffer_iovec vec[1];
|
||||
auto* data = static_cast<struct jsonWalk*>(vdata);
|
||||
|
||||
auto sv = std::string_view{};
|
||||
|
@ -591,7 +594,7 @@ static void jsonStringFunc(tr_variant const* val, void* vdata)
|
|||
auto const* const end8 = begin8 + std::size(sv);
|
||||
auto const* walk8 = begin8;
|
||||
auto const uch32 = utf8::next(walk8, end8);
|
||||
outwalk += tr_snprintf(outwalk, outend - outwalk, "\\u%04x", uch32);
|
||||
outwalk = fmt::format_to_n(outwalk, outend - outwalk - 1, FMT_COMPILE("\\u{:04x}"), uch32).out;
|
||||
sv.remove_prefix(walk8 - begin8 - 1);
|
||||
}
|
||||
catch (utf8::exception const&)
|
||||
|
@ -667,7 +670,7 @@ static struct VariantWalkFuncs const walk_funcs = {
|
|||
jsonContainerEndFunc, //
|
||||
};
|
||||
|
||||
void tr_variantToBufJson(tr_variant const* top, struct evbuffer* buf, bool lean)
|
||||
void tr_variantToBufJson(tr_variant const* top, evbuffer* buf, bool lean)
|
||||
{
|
||||
struct jsonWalk data;
|
||||
|
||||
|
|
|
@ -239,6 +239,7 @@ set(${PROJECT_NAME}_HIDPI_IMAGES
|
|||
ActionHover
|
||||
ActionOn
|
||||
Bandwidth
|
||||
BlueDotFlat
|
||||
CleanupTemplate
|
||||
CompleteCheck
|
||||
CreateLarge
|
||||
|
@ -246,6 +247,7 @@ set(${PROJECT_NAME}_HIDPI_IMAGES
|
|||
DownArrowTemplate
|
||||
FavIcon
|
||||
Globe
|
||||
GreenDotFlat
|
||||
Groups
|
||||
GroupsNoneTemplate
|
||||
InfoActivity
|
||||
|
@ -256,6 +258,7 @@ set(${PROJECT_NAME}_HIDPI_IMAGES
|
|||
InfoTracker
|
||||
Lock
|
||||
Magnet
|
||||
OrangeDotFlat
|
||||
PauseHover
|
||||
PauseOff
|
||||
PauseOn
|
||||
|
|
After Width: | Height: | Size: 357 B |
After Width: | Height: | Size: 520 B |
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"filename" : "BlueDotFlat.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"filename" : "BlueDotFlat@2x.png",
|
||||
"scale" : "2x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
},
|
||||
"properties" : {
|
||||
"template-rendering-intent" : "original"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"filename" : "GreenDotFlat.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"filename" : "GreenDotFlat@2x.png",
|
||||
"scale" : "2x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
},
|
||||
"properties" : {
|
||||
"template-rendering-intent" : "original"
|
||||
}
|
||||
}
|
After Width: | Height: | Size: 424 B |
After Width: | Height: | Size: 611 B |
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"filename" : "OrangeDotFlat.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "mac",
|
||||
"filename" : "OrangeDotFlat@2x.png",
|
||||
"scale" : "2x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
},
|
||||
"properties" : {
|
||||
"template-rendering-intent" : "original"
|
||||
}
|
||||
}
|
After Width: | Height: | Size: 371 B |
After Width: | Height: | Size: 532 B |
Before Width: | Height: | Size: 189 B After Width: | Height: | Size: 381 B |
Before Width: | Height: | Size: 274 B After Width: | Height: | Size: 543 B |
Before Width: | Height: | Size: 184 B After Width: | Height: | Size: 340 B |
Before Width: | Height: | Size: 278 B After Width: | Height: | Size: 542 B |
Before Width: | Height: | Size: 184 B After Width: | Height: | Size: 418 B |
Before Width: | Height: | Size: 274 B After Width: | Height: | Size: 575 B |
|
@ -47,11 +47,11 @@
|
|||
<font key="font" metaFont="menu"/>
|
||||
<menu key="menu" title="OtherViews" id="16">
|
||||
<items>
|
||||
<menuItem title="Error" state="on" image="RedDotFlat" id="17"/>
|
||||
<menuItem title="Warn" image="RedDotFlat" id="yoL-9H-kTt"/>
|
||||
<menuItem title="Info" image="YellowDotFlat" id="18"/>
|
||||
<menuItem title="Debug" image="PurpleDotFlat" id="19"/>
|
||||
<menuItem title="Trace" image="PurpleDotFlat" id="2hu-LL-6A5"/>
|
||||
<menuItem title="Error" state="on" image="RedDotFlat"/>
|
||||
<menuItem title="Warn" image="OrangeDotFlat"/>
|
||||
<menuItem title="Info" image="GreenDotFlat"/>
|
||||
<menuItem title="Debug" image="BlueDotFlat"/>
|
||||
<menuItem title="Trace" image="PurpleDotFlat"/>
|
||||
</items>
|
||||
</menu>
|
||||
</popUpButtonCell>
|
||||
|
|
|
@ -270,13 +270,17 @@
|
|||
{
|
||||
case TR_LOG_CRITICAL:
|
||||
case TR_LOG_ERROR:
|
||||
case TR_LOG_WARN:
|
||||
return [NSImage imageNamed:@"RedDotFlat"];
|
||||
|
||||
case TR_LOG_WARN:
|
||||
return [NSImage imageNamed:@"OrangeDotFlat"];
|
||||
|
||||
case TR_LOG_INFO:
|
||||
return [NSImage imageNamed:@"YellowDotFlat"];
|
||||
return [NSImage imageNamed:@"GreenDotFlat"];
|
||||
|
||||
case TR_LOG_DEBUG:
|
||||
return [NSImage imageNamed:@"BlueDotFlat"];
|
||||
|
||||
case TR_LOG_TRACE:
|
||||
return [NSImage imageNamed:@"PurpleDotFlat"];
|
||||
|
||||
|
|
|
@ -1462,7 +1462,7 @@ void DetailsDialog::initTrackerTab()
|
|||
ui_.trackersView->setModel(tracker_filter_.get());
|
||||
ui_.trackersView->setItemDelegate(tracker_delegate_.get());
|
||||
|
||||
auto& icons = IconCache::get();
|
||||
auto const& icons = IconCache::get();
|
||||
ui_.addTrackerButton->setIcon(icons.getThemeIcon(QStringLiteral("list-add"), QStyle::SP_DialogOpenButton));
|
||||
ui_.editTrackersButton->setIcon(icons.getThemeIcon(QStringLiteral("document-properties"), QStyle::SP_DesktopIcon));
|
||||
ui_.removeTrackerButton->setIcon(icons.getThemeIcon(QStringLiteral("list-remove"), QStyle::SP_TrashIcon));
|
||||
|
|
|
@ -51,7 +51,7 @@ FilterBarComboBox* FilterBar::createActivityCombo()
|
|||
model->appendRow(new QStandardItem); // separator
|
||||
FilterBarComboBoxDelegate::setSeparator(model, model->index(1, 0));
|
||||
|
||||
auto& icons = IconCache::get();
|
||||
auto const& icons = IconCache::get();
|
||||
|
||||
row = new QStandardItem(icons.getThemeIcon(QStringLiteral("system-run")), tr("Active"));
|
||||
row->setData(FilterMode::SHOW_ACTIVE, ACTIVITY_ROLE);
|
||||
|
@ -279,7 +279,7 @@ void FilterBar::refreshPref(int key)
|
|||
case Prefs::FILTER_MODE:
|
||||
{
|
||||
auto const m = prefs_.get<FilterMode>(key);
|
||||
QAbstractItemModel* model = activity_combo_->model();
|
||||
QAbstractItemModel const* const model = activity_combo_->model();
|
||||
QModelIndexList indices = model->match(model->index(0, 0), ACTIVITY_ROLE, m.mode());
|
||||
activity_combo_->setCurrentIndex(indices.isEmpty() ? 0 : indices.first().row());
|
||||
break;
|
||||
|
|
|
@ -87,7 +87,7 @@ void FilterBarComboBox::paintEvent(QPaintEvent* e)
|
|||
|
||||
if (model_index.isValid())
|
||||
{
|
||||
QStyle* s = style();
|
||||
QStyle const* const s = style();
|
||||
int const hmargin = getHSpacing(this);
|
||||
|
||||
QRect rect = s->subControlRect(QStyle::CC_ComboBox, &opt, QStyle::SC_ComboBoxEditField, this);
|
||||
|
|
|
@ -38,7 +38,7 @@ void FilterBarComboBoxDelegate::setSeparator(QAbstractItemModel* model, QModelIn
|
|||
{
|
||||
model->setData(index, QStringLiteral("separator"), Qt::AccessibleDescriptionRole);
|
||||
|
||||
if (auto* m = qobject_cast<QStandardItemModel*>(model))
|
||||
if (auto const* const m = qobject_cast<QStandardItemModel*>(model))
|
||||
{
|
||||
if (QStandardItem* item = m->itemFromIndex(index))
|
||||
{
|
||||
|
@ -109,7 +109,7 @@ QSize FilterBarComboBoxDelegate::sizeHint(QStyleOptionViewItem const& option, QM
|
|||
return { pm, pm + 10 };
|
||||
}
|
||||
|
||||
QStyle* s = combo_->style();
|
||||
QStyle const* const s = combo_->style();
|
||||
int const hmargin = getHSpacing(combo_);
|
||||
|
||||
QSize size = QItemDelegate::sizeHint(option, index);
|
||||
|
|
|
@ -84,7 +84,7 @@ QIcon MainWindow::addEmblem(QIcon base_icon, QStringList const& emblem_names) co
|
|||
return base_icon;
|
||||
}
|
||||
|
||||
auto& icons = IconCache::get();
|
||||
auto const& icons = IconCache::get();
|
||||
QIcon emblem_icon;
|
||||
|
||||
for (QString const& emblem_name : emblem_names)
|
||||
|
@ -144,7 +144,7 @@ MainWindow::MainWindow(Session& session, Prefs& prefs, TorrentModel& model, bool
|
|||
ui_.listView->setStyle(lvp_style_.get());
|
||||
ui_.listView->setAttribute(Qt::WA_MacShowFocusRect, false);
|
||||
|
||||
auto& icons = IconCache::get();
|
||||
auto const& icons = IconCache::get();
|
||||
|
||||
// icons
|
||||
QIcon const icon_play = icons.getThemeIcon(QStringLiteral("media-playback-start"), QStyle::SP_MediaPlay);
|
||||
|
|
|
@ -123,7 +123,7 @@ void TorrentModel::removeTorrents(tr_variant* list)
|
|||
torrents.reserve(tr_variantListSize(list));
|
||||
|
||||
int i = 0;
|
||||
tr_variant* child = nullptr;
|
||||
tr_variant const* child = nullptr;
|
||||
while ((child = tr_variantListChild(list, i++)) != nullptr)
|
||||
{
|
||||
if (auto const id = getValue<int>(child); id)
|
||||
|
|
|
@ -30,7 +30,7 @@ protected:
|
|||
auto const path1 = tr_strvPath(sandboxDir(), filename1);
|
||||
|
||||
/* Create a file. */
|
||||
char* file_content = static_cast<char*>(tr_malloc(file_length));
|
||||
auto* file_content = static_cast<char*>(tr_malloc(file_length));
|
||||
tr_rand_buffer(file_content, file_length);
|
||||
createFileWithContents(path1, file_content, file_length);
|
||||
tr_free(file_content);
|
||||
|
@ -91,8 +91,8 @@ private:
|
|||
uint64_t bytes_left2 = info2.size;
|
||||
|
||||
size_t const buflen = 2 * 1024 * 1024; /* 2 MiB buffer */
|
||||
char* readbuf1 = static_cast<char*>(tr_malloc(buflen));
|
||||
char* readbuf2 = static_cast<char*>(tr_malloc(buflen));
|
||||
auto* readbuf1 = static_cast<char*>(tr_malloc(buflen));
|
||||
auto* readbuf2 = static_cast<char*>(tr_malloc(buflen));
|
||||
|
||||
while (bytes_left1 > 0 || bytes_left2 > 0)
|
||||
{
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include "transmission.h"
|
||||
|
||||
#include "crypto-utils.h"
|
||||
|
@ -44,10 +46,10 @@ protected:
|
|||
{
|
||||
|
||||
// create a single input file
|
||||
auto input_file = tr_strvPath(sandboxDir().data(), "test.XXXXXX");
|
||||
createTmpfileWithContents(input_file, payload, payloadSize);
|
||||
auto input_file = tr_pathbuf{ sandboxDir(), '/', "test.XXXXXX" };
|
||||
createTmpfileWithContents(std::data(input_file), payload, payloadSize);
|
||||
tr_sys_path_native_separators(std::data(input_file));
|
||||
auto* builder = tr_metaInfoBuilderCreate(input_file.c_str());
|
||||
auto* builder = tr_metaInfoBuilderCreate(input_file);
|
||||
EXPECT_EQ(tr_file_index_t{ 1 }, builder->fileCount);
|
||||
EXPECT_EQ(input_file, builder->top);
|
||||
EXPECT_EQ(input_file, builder->files[0].filename);
|
||||
|
@ -57,10 +59,10 @@ protected:
|
|||
EXPECT_FALSE(builder->abortFlag);
|
||||
|
||||
// have tr_makeMetaInfo() build the torrent file
|
||||
auto const torrent_file = tr_strvJoin(input_file, ".torrent"sv);
|
||||
auto const torrent_file = tr_pathbuf{ input_file, ".torrent"sv };
|
||||
tr_makeMetaInfo(
|
||||
builder,
|
||||
torrent_file.c_str(),
|
||||
torrent_file,
|
||||
trackers,
|
||||
trackerCount,
|
||||
webseeds,
|
||||
|
@ -111,7 +113,7 @@ protected:
|
|||
char const* source)
|
||||
{
|
||||
// create the top temp directory
|
||||
auto top = tr_strvPath(sandboxDir(), "folder.XXXXXX");
|
||||
auto top = tr_pathbuf{ sandboxDir(), '/', "folder.XXXXXX"sv };
|
||||
tr_sys_path_native_separators(std::data(top));
|
||||
tr_sys_dir_create_temp(std::data(top));
|
||||
|
||||
|
@ -122,10 +124,8 @@ protected:
|
|||
|
||||
for (size_t i = 0; i < payload_count; i++)
|
||||
{
|
||||
auto tmpl = std::array<char, 16>{};
|
||||
tr_snprintf(tmpl.data(), tmpl.size(), "file.%04zu%s", i, "XXXXXX");
|
||||
auto path = tr_strvPath(top, std::data(tmpl));
|
||||
createTmpfileWithContents(path, payloads[i], payload_sizes[i]);
|
||||
auto path = fmt::format(FMT_STRING("{:s}/file.{:04}XXXXXX"), top.sv(), i);
|
||||
createTmpfileWithContents(std::data(path), payloads[i], payload_sizes[i]);
|
||||
tr_sys_path_native_separators(std::data(path));
|
||||
files.push_back(path);
|
||||
total_size += payload_sizes[i];
|
||||
|
@ -134,7 +134,7 @@ protected:
|
|||
sync();
|
||||
|
||||
// init the builder
|
||||
auto* builder = tr_metaInfoBuilderCreate(top.c_str());
|
||||
auto* builder = tr_metaInfoBuilderCreate(top);
|
||||
EXPECT_FALSE(builder->abortFlag);
|
||||
EXPECT_EQ(top, builder->top);
|
||||
EXPECT_EQ(payload_count, builder->fileCount);
|
||||
|
@ -148,7 +148,7 @@ protected:
|
|||
}
|
||||
|
||||
// build the torrent file
|
||||
auto torrent_file = tr_strvJoin(top, ".torrent"sv);
|
||||
auto const torrent_file = tr_pathbuf{ top, ".torrent"sv };
|
||||
tr_makeMetaInfo(
|
||||
builder,
|
||||
torrent_file.c_str(),
|
||||
|
@ -201,8 +201,8 @@ protected:
|
|||
{
|
||||
// build random payloads
|
||||
size_t payload_count = 1 + tr_rand_int_weak(max_file_count);
|
||||
void** payloads = tr_new0(void*, payload_count);
|
||||
size_t* payload_sizes = tr_new0(size_t, payload_count);
|
||||
auto** payloads = tr_new0(void*, payload_count);
|
||||
auto* payload_sizes = tr_new0(size_t, payload_count);
|
||||
|
||||
for (size_t i = 0; i < payload_count; i++)
|
||||
{
|
||||
|
|
|
@ -93,7 +93,7 @@ TEST_P(IncompleteDirTest, incompleteDir)
|
|||
|
||||
// now finish writing it
|
||||
{
|
||||
char* zero_block = tr_new0(char, tr_block_info::BlockSize);
|
||||
auto* const zero_block = tr_new0(char, tr_block_info::BlockSize);
|
||||
|
||||
struct TestIncompleteDirData data = {};
|
||||
data.session = session_;
|
||||
|
|
|
@ -88,17 +88,16 @@ public:
|
|||
protected:
|
||||
static std::string get_default_parent_dir()
|
||||
{
|
||||
auto* path = getenv("TMPDIR");
|
||||
if (path != NULL)
|
||||
if (auto* const path = getenv("TMPDIR"); path != nullptr)
|
||||
{
|
||||
return path;
|
||||
}
|
||||
|
||||
tr_error* error = nullptr;
|
||||
path = tr_sys_dir_get_current(&error);
|
||||
if (path != nullptr)
|
||||
|
||||
if (auto* path = tr_sys_dir_get_current(&error); path != nullptr)
|
||||
{
|
||||
std::string const ret = path;
|
||||
auto ret = std::string{ path };
|
||||
tr_free(path);
|
||||
return ret;
|
||||
}
|
||||
|
@ -179,7 +178,7 @@ protected:
|
|||
return child;
|
||||
}
|
||||
|
||||
void buildParentDir(std::string const& path) const
|
||||
void buildParentDir(std::string_view path) const
|
||||
{
|
||||
auto const tmperr = errno;
|
||||
|
||||
|
@ -212,14 +211,14 @@ protected:
|
|||
}
|
||||
}
|
||||
|
||||
void createTmpfileWithContents(std::string& tmpl, void const* payload, size_t n) const
|
||||
void createTmpfileWithContents(char* tmpl, void const* payload, size_t n) const
|
||||
{
|
||||
auto const tmperr = errno;
|
||||
|
||||
buildParentDir(tmpl);
|
||||
|
||||
// NOLINTNEXTLINE(clang-analyzer-cplusplus.InnerPointer)
|
||||
auto const fd = tr_sys_file_open_temp(&tmpl.front());
|
||||
auto const fd = tr_sys_file_open_temp(tmpl);
|
||||
blockingFileWrite(fd, payload, n);
|
||||
tr_sys_file_close(fd);
|
||||
sync();
|
||||
|
|
|
@ -3,7 +3,15 @@
|
|||
// or any future license endorsed by Mnemosyne LLC.
|
||||
// License text can be found in the licenses/ folder.
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cmath> // sqrt()
|
||||
#include <cstdlib> // setenv(), unsetenv()
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
|
@ -21,14 +29,6 @@
|
|||
|
||||
#include "test-fixtures.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cmath> // sqrt()
|
||||
#include <cstdlib> // setenv(), unsetenv()
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
using ::libtransmission::test::makeString;
|
||||
using UtilsTest = ::testing::Test;
|
||||
using namespace std::literals;
|
||||
|
@ -344,7 +344,7 @@ TEST_F(UtilsTest, trStrlcpy)
|
|||
"This, very usefull string contains total of 104 characters not counting null. Almost like an easter egg!"
|
||||
};
|
||||
|
||||
for (auto& test : tests)
|
||||
for (auto const& test : tests)
|
||||
{
|
||||
auto c_string = test.c_str();
|
||||
auto length = strlen(c_string);
|
||||
|
@ -458,12 +458,22 @@ TEST_F(UtilsTest, saveFile)
|
|||
TEST_F(UtilsTest, ratioToString)
|
||||
{
|
||||
// Testpairs contain ratio as a double and a string
|
||||
std::vector<std::pair<double, std::string>> const tests{
|
||||
{ 0.0, "0.00" }, { 0.01, "0.01" }, { 0.1, "0.10" }, { 1.0, "1.00" }, { 1.015, "1.01" },
|
||||
{ 4.99, "4.99" }, { 4.996, "4.99" }, { 5.0, "5.0" }, { 5.09999, "5.0" }, { 5.1, "5.1" },
|
||||
{ 99.99, "99.9" }, { 100.0, "100" }, { 4000.4, "4000" }, { 600000.0, "600000" }, { 900000000.0, "900000000" },
|
||||
{ TR_RATIO_INF, "inf" }
|
||||
};
|
||||
static auto constexpr Tests = std::array<std::pair<double, std::string_view>, 16>{ { { 0.0, "0.00" },
|
||||
{ 0.01, "0.01" },
|
||||
{ 0.1, "0.10" },
|
||||
{ 1.0, "1.00" },
|
||||
{ 1.015, "1.01" },
|
||||
{ 4.99, "4.99" },
|
||||
{ 4.996, "4.99" },
|
||||
{ 5.0, "5.0" },
|
||||
{ 5.09999, "5.0" },
|
||||
{ 5.1, "5.1" },
|
||||
{ 99.99, "99.9" },
|
||||
{ 100.0, "100" },
|
||||
{ 4000.4, "4000" },
|
||||
{ 600000.0, "600000" },
|
||||
{ 900000000.0, "900000000" },
|
||||
{ TR_RATIO_INF, "inf" } } };
|
||||
char const nullchar = '\0';
|
||||
|
||||
ASSERT_EQ(tr_strratio(TR_RATIO_NA, "Ratio is NaN"), "None");
|
||||
|
@ -471,8 +481,8 @@ TEST_F(UtilsTest, ratioToString)
|
|||
// Inf contains only null character
|
||||
ASSERT_EQ(tr_strratio(TR_RATIO_INF, &nullchar), "");
|
||||
|
||||
for (auto& test : tests)
|
||||
for (auto const& [input, expected] : Tests)
|
||||
{
|
||||
ASSERT_EQ(tr_strratio(test.first, "inf"), test.second);
|
||||
ASSERT_EQ(tr_strratio(input, "inf"), expected);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -208,8 +208,8 @@ TEST_F(WebUtilsTest, urlPercentDecode)
|
|||
"http://www.example.com/~user/?test=1&test1=2"sv },
|
||||
} };
|
||||
|
||||
for (auto const& test : Tests)
|
||||
for (auto const& [encoded, decoded] : Tests)
|
||||
{
|
||||
EXPECT_EQ(test.second, tr_urlPercentDecode(test.first));
|
||||
EXPECT_EQ(decoded, tr_urlPercentDecode(encoded));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 68ca04c261ded1b936ef5c121618247f7010d445
|
||||
Subproject commit af29db7ec28d6df1c7f0f745186884091e602e07
|
|
@ -324,7 +324,7 @@ int tr_main(int argc, char* argv[])
|
|||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (options.add == nullptr && options.deleteme == nullptr && options.replace[0] == 0)
|
||||
if (options.add == nullptr && options.deleteme == nullptr && options.replace[0] == nullptr)
|
||||
{
|
||||
fprintf(stderr, "ERROR: Must specify -a, -d or -r\n");
|
||||
tr_getopt_usage(MyName, Usage, std::data(Options));
|
||||
|
|
344
utils/remote.cc
|
@ -80,38 +80,33 @@ static char constexpr SpeedTStr[] = "TB/s";
|
|||
****
|
||||
***/
|
||||
|
||||
static void etaToString(char* buf, size_t buflen, int64_t eta)
|
||||
static std::string etaToString(int64_t eta)
|
||||
{
|
||||
if (eta < 0)
|
||||
{
|
||||
tr_snprintf(buf, buflen, "Unknown");
|
||||
return "Unknown";
|
||||
}
|
||||
else if (eta < 60)
|
||||
|
||||
if (eta < 60)
|
||||
{
|
||||
tr_snprintf(buf, buflen, "%" PRId64 " sec", eta);
|
||||
return fmt::format(FMT_STRING("{:d} sec"), eta);
|
||||
}
|
||||
else if (eta < (60 * 60))
|
||||
|
||||
if (eta < (60 * 60))
|
||||
{
|
||||
tr_snprintf(buf, buflen, "%" PRId64 " min", eta / 60);
|
||||
return fmt::format(FMT_STRING("{:d} min"), eta / 60);
|
||||
}
|
||||
else if (eta < (60 * 60 * 24))
|
||||
|
||||
if (eta < (60 * 60 * 24))
|
||||
{
|
||||
tr_snprintf(buf, buflen, "%" PRId64 " hrs", eta / (60 * 60));
|
||||
}
|
||||
else
|
||||
{
|
||||
tr_snprintf(buf, buflen, "%" PRId64 " days", eta / (60 * 60 * 24));
|
||||
return fmt::format(FMT_STRING("{:d} hrs"), eta / (60 * 60));
|
||||
}
|
||||
|
||||
return fmt::format(FMT_STRING("{:d} days"), eta / (60 * 60 * 24));
|
||||
}
|
||||
|
||||
static char* tr_strltime(char* buf, int seconds, size_t buflen)
|
||||
static std::string tr_strltime(int seconds)
|
||||
{
|
||||
char b[128];
|
||||
char h[128];
|
||||
char m[128];
|
||||
char s[128];
|
||||
char t[128];
|
||||
|
||||
if (seconds < 0)
|
||||
{
|
||||
seconds = 0;
|
||||
|
@ -123,54 +118,32 @@ static char* tr_strltime(char* buf, int seconds, size_t buflen)
|
|||
auto const minutes = (seconds % 3600) / 60;
|
||||
seconds = (seconds % 3600) % 60;
|
||||
|
||||
tr_snprintf(h, sizeof(h), "%d %s", hours, hours == 1 ? "hour" : "hours");
|
||||
tr_snprintf(m, sizeof(m), "%d %s", minutes, minutes == 1 ? "minute" : "minutes");
|
||||
tr_snprintf(s, sizeof(s), "%d %s", seconds, seconds == 1 ? "second" : "seconds");
|
||||
tr_snprintf(t, sizeof(t), "%d %s", total_seconds, total_seconds == 1 ? "second" : "seconds");
|
||||
auto tmpstr = std::string{};
|
||||
|
||||
if (days != 0)
|
||||
{
|
||||
char d[128];
|
||||
tr_snprintf(d, sizeof(d), "%d %s", days, days == 1 ? "day" : "days");
|
||||
auto const hstr = fmt::format(FMT_STRING("{:d} {:s}"), hours, ngettext("hour", "hours", hours));
|
||||
auto const mstr = fmt::format(FMT_STRING("{:d} {:s}"), minutes, ngettext("minute", "minutes", minutes));
|
||||
auto const sstr = fmt::format(FMT_STRING("{:d} {:s}"), seconds, ngettext("seconds", "seconds", seconds));
|
||||
|
||||
if (days >= 4 || hours == 0)
|
||||
{
|
||||
tr_strlcpy(b, d, sizeof(b));
|
||||
}
|
||||
else
|
||||
{
|
||||
tr_snprintf(b, sizeof(b), "%s, %s", d, h);
|
||||
}
|
||||
}
|
||||
else if (hours != 0)
|
||||
if (days > 0)
|
||||
{
|
||||
if (hours >= 4 || minutes == 0)
|
||||
{
|
||||
tr_strlcpy(b, h, sizeof(b));
|
||||
}
|
||||
else
|
||||
{
|
||||
tr_snprintf(b, sizeof(b), "%s, %s", h, m);
|
||||
}
|
||||
auto const dstr = fmt::format(FMT_STRING("{:d} {:s}"), hours, ngettext("day", "days", days));
|
||||
tmpstr = days >= 4 || hours == 0 ? dstr : fmt::format(FMT_STRING("{:s}, {:s}"), dstr, hstr);
|
||||
}
|
||||
else if (minutes != 0)
|
||||
else if (hours > 0)
|
||||
{
|
||||
if (minutes >= 4 || seconds == 0)
|
||||
{
|
||||
tr_strlcpy(b, m, sizeof(b));
|
||||
}
|
||||
else
|
||||
{
|
||||
tr_snprintf(b, sizeof(b), "%s, %s", m, s);
|
||||
}
|
||||
tmpstr = hours >= 4 || minutes == 0 ? hstr : fmt::format(FMT_STRING("{:s}, {:s}"), hstr, mstr);
|
||||
}
|
||||
else if (minutes > 0)
|
||||
{
|
||||
tmpstr = minutes >= 4 || seconds == 0 ? mstr : fmt::format(FMT_STRING("{:s}, {:s}"), mstr, sstr);
|
||||
}
|
||||
else
|
||||
{
|
||||
tr_strlcpy(b, s, sizeof(b));
|
||||
tmpstr = sstr;
|
||||
}
|
||||
|
||||
tr_snprintf(buf, buflen, "%s (%s)", b, t);
|
||||
return buf;
|
||||
auto const totstr = fmt::format(FMT_STRING("{:d} {:s}"), total_seconds, ngettext("seconds", "seconds", total_seconds));
|
||||
return fmt::format(FMT_STRING("{:s} ({:s})"), tmpstr, totstr);
|
||||
}
|
||||
|
||||
static std::string strlpercent(double x)
|
||||
|
@ -826,99 +799,70 @@ static long getTimeoutSecs(std::string_view req)
|
|||
return 60L; /* default value */
|
||||
}
|
||||
|
||||
static char* getStatusString(tr_variant* t, char* buf, size_t buflen)
|
||||
static std::string getStatusString(tr_variant* t)
|
||||
{
|
||||
int64_t status;
|
||||
bool boolVal;
|
||||
auto from_us = int64_t{};
|
||||
auto status = int64_t{};
|
||||
auto to_us = int64_t{};
|
||||
|
||||
if (!tr_variantDictFindInt(t, TR_KEY_status, &status))
|
||||
{
|
||||
*buf = '\0';
|
||||
return "";
|
||||
}
|
||||
else
|
||||
|
||||
switch (status)
|
||||
{
|
||||
switch (status)
|
||||
case TR_STATUS_DOWNLOAD_WAIT:
|
||||
case TR_STATUS_SEED_WAIT:
|
||||
return "Queued";
|
||||
|
||||
case TR_STATUS_STOPPED:
|
||||
if (auto flag = bool{}; tr_variantDictFindBool(t, TR_KEY_isFinished, &flag) && flag)
|
||||
{
|
||||
case TR_STATUS_DOWNLOAD_WAIT:
|
||||
case TR_STATUS_SEED_WAIT:
|
||||
tr_strlcpy(buf, "Queued", buflen);
|
||||
break;
|
||||
|
||||
case TR_STATUS_STOPPED:
|
||||
if (tr_variantDictFindBool(t, TR_KEY_isFinished, &boolVal) && boolVal)
|
||||
{
|
||||
tr_strlcpy(buf, "Finished", buflen);
|
||||
}
|
||||
else
|
||||
{
|
||||
tr_strlcpy(buf, "Stopped", buflen);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case TR_STATUS_CHECK_WAIT:
|
||||
case TR_STATUS_CHECK:
|
||||
{
|
||||
char const* str = status == TR_STATUS_CHECK_WAIT ? "Will Verify" : "Verifying";
|
||||
double percent;
|
||||
|
||||
if (tr_variantDictFindReal(t, TR_KEY_recheckProgress, &percent))
|
||||
{
|
||||
tr_snprintf(buf, buflen, "%s (%.0f%%)", str, floor(percent * 100.0));
|
||||
}
|
||||
else
|
||||
{
|
||||
tr_strlcpy(buf, str, buflen);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case TR_STATUS_DOWNLOAD:
|
||||
case TR_STATUS_SEED:
|
||||
{
|
||||
int64_t fromUs = 0;
|
||||
int64_t toUs = 0;
|
||||
tr_variantDictFindInt(t, TR_KEY_peersGettingFromUs, &fromUs);
|
||||
tr_variantDictFindInt(t, TR_KEY_peersSendingToUs, &toUs);
|
||||
|
||||
if (fromUs != 0 && toUs != 0)
|
||||
{
|
||||
tr_strlcpy(buf, "Up & Down", buflen);
|
||||
}
|
||||
else if (toUs != 0)
|
||||
{
|
||||
tr_strlcpy(buf, "Downloading", buflen);
|
||||
}
|
||||
else if (fromUs != 0)
|
||||
{
|
||||
int64_t leftUntilDone = 0;
|
||||
tr_variantDictFindInt(t, TR_KEY_leftUntilDone, &leftUntilDone);
|
||||
|
||||
if (leftUntilDone > 0)
|
||||
{
|
||||
tr_strlcpy(buf, "Uploading", buflen);
|
||||
}
|
||||
else
|
||||
{
|
||||
tr_strlcpy(buf, "Seeding", buflen);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
tr_strlcpy(buf, "Idle", buflen);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
tr_strlcpy(buf, "Unknown", buflen);
|
||||
break;
|
||||
return "Finished";
|
||||
}
|
||||
}
|
||||
return "Stopped";
|
||||
|
||||
return buf;
|
||||
case TR_STATUS_CHECK_WAIT:
|
||||
if (auto percent = double{}; tr_variantDictFindReal(t, TR_KEY_recheckProgress, &percent))
|
||||
{
|
||||
return fmt::format(FMT_STRING("Will Verify ({:.0f}%)"), floor(percent * 100.0));
|
||||
}
|
||||
return "Will Verify";
|
||||
|
||||
case TR_STATUS_CHECK:
|
||||
if (auto percent = double{}; tr_variantDictFindReal(t, TR_KEY_recheckProgress, &percent))
|
||||
{
|
||||
return fmt::format(FMT_STRING("Verifying ({:.0f}%)"), floor(percent * 100.0));
|
||||
}
|
||||
return "Verifying";
|
||||
|
||||
case TR_STATUS_DOWNLOAD:
|
||||
case TR_STATUS_SEED:
|
||||
tr_variantDictFindInt(t, TR_KEY_peersGettingFromUs, &from_us);
|
||||
tr_variantDictFindInt(t, TR_KEY_peersSendingToUs, &to_us);
|
||||
if (from_us != 0 && to_us != 0)
|
||||
{
|
||||
return "Up & Down";
|
||||
}
|
||||
if (to_us != 0)
|
||||
{
|
||||
return "Downloading";
|
||||
}
|
||||
if (from_us == 0)
|
||||
{
|
||||
return "Idle";
|
||||
}
|
||||
if (auto left_until_done = int64_t{};
|
||||
tr_variantDictFindInt(t, TR_KEY_leftUntilDone, &left_until_done) && left_until_done > 0)
|
||||
{
|
||||
return "Uploading";
|
||||
}
|
||||
return "Seeding";
|
||||
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
static char const* bandwidthPriorityNames[] = {
|
||||
|
@ -1002,8 +946,7 @@ static void printDetails(tr_variant* top)
|
|||
printf("\n");
|
||||
|
||||
printf("TRANSFER\n");
|
||||
getStatusString(t, buf, sizeof(buf));
|
||||
printf(" State: %s\n", buf);
|
||||
printf(" State: %s\n", getStatusString(t).c_str());
|
||||
|
||||
if (tr_variantDictFindStrView(t, TR_KEY_downloadDir, &sv))
|
||||
{
|
||||
|
@ -1017,7 +960,7 @@ static void printDetails(tr_variant* top)
|
|||
|
||||
if (tr_variantDictFindInt(t, TR_KEY_eta, &i))
|
||||
{
|
||||
printf(" ETA: %s\n", tr_strltime(buf, i, sizeof(buf)));
|
||||
printf(" ETA: %s\n", tr_strltime(i).c_str());
|
||||
}
|
||||
|
||||
if (tr_variantDictFindInt(t, TR_KEY_rateDownload, &i))
|
||||
|
@ -1144,12 +1087,12 @@ static void printDetails(tr_variant* top)
|
|||
|
||||
if (tr_variantDictFindInt(t, TR_KEY_secondsDownloading, &i) && i > 0)
|
||||
{
|
||||
printf(" Downloading Time: %s\n", tr_strltime(buf, i, sizeof(buf)));
|
||||
printf(" Downloading Time: %s\n", tr_strltime(i).c_str());
|
||||
}
|
||||
|
||||
if (tr_variantDictFindInt(t, TR_KEY_secondsSeeding, &i) && i > 0)
|
||||
{
|
||||
printf(" Seeding Time: %s\n", tr_strltime(buf, i, sizeof(buf)));
|
||||
printf(" Seeding Time: %s\n", tr_strltime(i).c_str());
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
@ -1508,50 +1451,25 @@ static void printTorrentList(tr_variant* top)
|
|||
tr_variantDictFindInt(d, TR_KEY_sizeWhenDone, &sizeWhenDone) &&
|
||||
tr_variantDictFindInt(d, TR_KEY_status, &status) && tr_variantDictFindReal(d, TR_KEY_uploadRatio, &ratio))
|
||||
{
|
||||
char etaStr[16];
|
||||
char statusStr[64];
|
||||
char doneStr[8];
|
||||
int64_t error;
|
||||
char errorMark;
|
||||
|
||||
if (sizeWhenDone != 0)
|
||||
{
|
||||
tr_snprintf(doneStr, sizeof(doneStr), "%d%%", (int)(100.0 * (sizeWhenDone - leftUntilDone) / sizeWhenDone));
|
||||
}
|
||||
else
|
||||
{
|
||||
tr_strlcpy(doneStr, "n/a", sizeof(doneStr));
|
||||
}
|
||||
|
||||
if (leftUntilDone != 0 || eta != -1)
|
||||
{
|
||||
etaToString(etaStr, sizeof(etaStr), eta);
|
||||
}
|
||||
else
|
||||
{
|
||||
tr_snprintf(etaStr, sizeof(etaStr), "Done");
|
||||
}
|
||||
|
||||
if (tr_variantDictFindInt(d, TR_KEY_error, &error) && error)
|
||||
{
|
||||
errorMark = '*';
|
||||
}
|
||||
else
|
||||
{
|
||||
errorMark = ' ';
|
||||
}
|
||||
auto const eta_str = leftUntilDone != 0 || eta != -1 ? etaToString(eta) : "Done";
|
||||
auto const error_mark = tr_variantDictFindInt(d, TR_KEY_error, &error) && error ? '*' : ' ';
|
||||
auto const done_str = sizeWhenDone != 0 ?
|
||||
fmt::format(FMT_STRING("{:.0f}%"), (100.0 * (sizeWhenDone - leftUntilDone) / sizeWhenDone)) :
|
||||
std::string{ "n/a" };
|
||||
|
||||
printf(
|
||||
"%6d%c %4s %9s %-8s %6.1f %6.1f %5s %-11s %" TR_PRIsv "\n",
|
||||
(int)torId,
|
||||
errorMark,
|
||||
doneStr,
|
||||
error_mark,
|
||||
done_str.c_str(),
|
||||
strlsize(sizeWhenDone - leftUntilDone).c_str(),
|
||||
etaStr,
|
||||
eta_str.c_str(),
|
||||
up / (double)tr_speed_K,
|
||||
down / (double)tr_speed_K,
|
||||
strlratio2(ratio).c_str(),
|
||||
getStatusString(d, statusStr, sizeof(statusStr)),
|
||||
getStatusString(d).c_str(),
|
||||
TR_PRIsv_ARG(name));
|
||||
|
||||
total_up += up;
|
||||
|
@ -1570,8 +1488,6 @@ static void printTorrentList(tr_variant* top)
|
|||
|
||||
static void printTrackersImpl(tr_variant* trackerStats)
|
||||
{
|
||||
char buf[512];
|
||||
|
||||
for (size_t i = 0, n = tr_variantListSize(trackerStats); i < n; ++i)
|
||||
{
|
||||
tr_variant* const t = tr_variantListChild(trackerStats, i);
|
||||
|
@ -1641,11 +1557,11 @@ static void printTrackersImpl(tr_variant* trackerStats)
|
|||
{
|
||||
if (hasAnnounced && announceState != TR_TRACKER_INACTIVE)
|
||||
{
|
||||
tr_strltime(buf, now - lastAnnounceTime, sizeof(buf));
|
||||
auto const timestr = tr_strltime(now - lastAnnounceTime);
|
||||
|
||||
if (lastAnnounceSucceeded)
|
||||
{
|
||||
printf(" Got a list of %d peers %s ago\n", (int)lastAnnouncePeerCount, buf);
|
||||
printf(" Got a list of %d peers %s ago\n", (int)lastAnnouncePeerCount, timestr.c_str());
|
||||
}
|
||||
else if (lastAnnounceTimedOut)
|
||||
{
|
||||
|
@ -1653,7 +1569,7 @@ static void printTrackersImpl(tr_variant* trackerStats)
|
|||
}
|
||||
else
|
||||
{
|
||||
printf(" Got an error \"%" TR_PRIsv "\" %s ago\n", TR_PRIsv_ARG(lastAnnounceResult), buf);
|
||||
printf(" Got an error \"%" TR_PRIsv "\" %s ago\n", TR_PRIsv_ARG(lastAnnounceResult), timestr.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1664,8 +1580,7 @@ static void printTrackersImpl(tr_variant* trackerStats)
|
|||
break;
|
||||
|
||||
case TR_TRACKER_WAITING:
|
||||
tr_strltime(buf, nextAnnounceTime - now, sizeof(buf));
|
||||
printf(" Asking for more peers in %s\n", buf);
|
||||
printf(" Asking for more peers in %s\n", tr_strltime(nextAnnounceTime - now).c_str());
|
||||
break;
|
||||
|
||||
case TR_TRACKER_QUEUED:
|
||||
|
@ -1673,18 +1588,21 @@ static void printTrackersImpl(tr_variant* trackerStats)
|
|||
break;
|
||||
|
||||
case TR_TRACKER_ACTIVE:
|
||||
tr_strltime(buf, now - lastAnnounceStartTime, sizeof(buf));
|
||||
printf(" Asking for more peers now... %s\n", buf);
|
||||
printf(" Asking for more peers now... %s\n", tr_strltime(now - lastAnnounceStartTime).c_str());
|
||||
break;
|
||||
}
|
||||
|
||||
if (hasScraped)
|
||||
{
|
||||
tr_strltime(buf, now - lastScrapeTime, sizeof(buf));
|
||||
auto const timestr = tr_strltime(now - lastScrapeTime);
|
||||
|
||||
if (lastScrapeSucceeded)
|
||||
{
|
||||
printf(" Tracker had %d seeders and %d leechers %s ago\n", (int)seederCount, (int)leecherCount, buf);
|
||||
printf(
|
||||
" Tracker had %d seeders and %d leechers %s ago\n",
|
||||
(int)seederCount,
|
||||
(int)leecherCount,
|
||||
timestr.c_str());
|
||||
}
|
||||
else if (lastScrapeTimedOut)
|
||||
{
|
||||
|
@ -1692,7 +1610,10 @@ static void printTrackersImpl(tr_variant* trackerStats)
|
|||
}
|
||||
else
|
||||
{
|
||||
printf(" Got a scrape error \"%" TR_PRIsv "\" %s ago\n", TR_PRIsv_ARG(lastScrapeResult), buf);
|
||||
printf(
|
||||
" Got a scrape error \"%" TR_PRIsv "\" %s ago\n",
|
||||
TR_PRIsv_ARG(lastScrapeResult),
|
||||
timestr.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1702,8 +1623,7 @@ static void printTrackersImpl(tr_variant* trackerStats)
|
|||
break;
|
||||
|
||||
case TR_TRACKER_WAITING:
|
||||
tr_strltime(buf, nextScrapeTime - now, sizeof(buf));
|
||||
printf(" Asking for peer counts in %s\n", buf);
|
||||
printf(" Asking for peer counts in %s\n", tr_strltime(nextScrapeTime - now).c_str());
|
||||
break;
|
||||
|
||||
case TR_TRACKER_QUEUED:
|
||||
|
@ -1711,8 +1631,7 @@ static void printTrackersImpl(tr_variant* trackerStats)
|
|||
break;
|
||||
|
||||
case TR_TRACKER_ACTIVE:
|
||||
tr_strltime(buf, now - lastScrapeStartTime, sizeof(buf));
|
||||
printf(" Asking for peer counts now... %s\n", buf);
|
||||
printf(" Asking for peer counts now... %s\n", tr_strltime(now - lastScrapeStartTime).c_str());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1982,7 +1901,6 @@ static void printSessionStats(tr_variant* top)
|
|||
|
||||
if (tr_variantDictFindDict(top, TR_KEY_arguments, &args))
|
||||
{
|
||||
char buf[512];
|
||||
int64_t up;
|
||||
int64_t down;
|
||||
int64_t secs;
|
||||
|
@ -1995,7 +1913,7 @@ static void printSessionStats(tr_variant* top)
|
|||
printf(" Uploaded: %s\n", strlsize(up).c_str());
|
||||
printf(" Downloaded: %s\n", strlsize(down).c_str());
|
||||
printf(" Ratio: %s\n", strlratio(up, down).c_str());
|
||||
printf(" Duration: %s\n", tr_strltime(buf, secs, sizeof(buf)));
|
||||
printf(" Duration: %s\n", tr_strltime(secs).c_str());
|
||||
}
|
||||
|
||||
if (tr_variantDictFindDict(args, TR_KEY_cumulative_stats, &d) &&
|
||||
|
@ -2007,7 +1925,7 @@ static void printSessionStats(tr_variant* top)
|
|||
printf(" Uploaded: %s\n", strlsize(up).c_str());
|
||||
printf(" Downloaded: %s\n", strlsize(down).c_str());
|
||||
printf(" Ratio: %s\n", strlratio(up, down).c_str());
|
||||
printf(" Duration: %s\n", tr_strltime(buf, secs, sizeof(buf)));
|
||||
printf(" Duration: %s\n", tr_strltime(secs).c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2132,7 +2050,8 @@ static int processResponse(char const* rpcurl, std::string_view response)
|
|||
if (tr_variantDictFindDict(&top, Arguments, &b) &&
|
||||
tr_variantDictFindDict(b, TR_KEY_torrent_added, &b) && tr_variantDictFindInt(b, TR_KEY_id, &i))
|
||||
{
|
||||
tr_snprintf(id, sizeof(id), "%" PRId64, i);
|
||||
auto const [out, len] = fmt::format_to_n(id, sizeof(id) - 1, FMT_STRING("{:d}"), i);
|
||||
*out = '\0';
|
||||
}
|
||||
[[fallthrough]];
|
||||
}
|
||||
|
@ -2925,22 +2844,19 @@ static int processArgs(char const* rpcurl, int argc, char const* const* argv)
|
|||
}
|
||||
|
||||
case 's': /* start */
|
||||
if (tadd != nullptr)
|
||||
{
|
||||
if (tadd != nullptr)
|
||||
{
|
||||
tr_variantDictAddBool(tr_variantDictFind(tadd, TR_KEY_arguments), TR_KEY_paused, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto* top = tr_new0(tr_variant, 1);
|
||||
tr_variantInitDict(top, 2);
|
||||
tr_variantDictAddStrView(top, TR_KEY_method, "torrent-start"sv);
|
||||
addIdArg(tr_variantDictAddDict(top, Arguments, 1), id, nullptr);
|
||||
status |= flush(rpcurl, &top);
|
||||
}
|
||||
|
||||
break;
|
||||
tr_variantDictAddBool(tr_variantDictFind(tadd, TR_KEY_arguments), TR_KEY_paused, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto* top = tr_new0(tr_variant, 1);
|
||||
tr_variantInitDict(top, 2);
|
||||
tr_variantDictAddStrView(top, TR_KEY_method, "torrent-start"sv);
|
||||
addIdArg(tr_variantDictAddDict(top, Arguments, 1), id, nullptr);
|
||||
status |= flush(rpcurl, &top);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'S': /* stop */
|
||||
if (tadd != nullptr)
|
||||
|
|