From e59b5bf7b6b1618ffbe28f16474b3613a4694b32 Mon Sep 17 00:00:00 2001 From: rakshasa Date: Wed, 17 Jan 2007 15:18:33 +0000 Subject: [PATCH] * Make VariableMap handle both global and core::Download variables. Variable now has functions for both void and core::Download*, where the core::Download* is discarded if necessary. git-svn-id: svn://rakshasa.no/libtorrent/trunk/rtorrent@847 e378c898-3ddf-0310-93e7-cc216c733640 --- rak/functional.h | 20 ++++++ rak/functional_fun.h | 98 +++++++++++++++++++++++++++++- src/core/download.cc | 23 ++++--- src/core/download.h | 25 ++++---- src/core/download_factory.cc | 34 +++++------ src/core/download_list.cc | 62 +++++++++---------- src/core/manager.cc | 14 ++--- src/core/view_manager.cc | 10 +-- src/display/text_element_helpers.h | 4 +- src/display/utils.cc | 6 +- src/option_handler_rules.cc | 44 +++++++++++--- src/ui/download_list.cc | 4 +- src/ui/element_download_list.cc | 12 ++-- src/utils/variable.cc | 20 ++++++ src/utils/variable.h | 12 +++- src/utils/variable_generic.cc | 61 ++++++++++++++++--- src/utils/variable_generic.h | 50 +++++++++++---- src/utils/variable_map.cc | 22 +++++++ src/utils/variable_map.h | 26 ++++++-- 19 files changed, 414 insertions(+), 133 deletions(-) diff --git a/rak/functional.h b/rak/functional.h index 661175e1..97a40f93 100644 --- a/rak/functional.h +++ b/rak/functional.h @@ -294,6 +294,26 @@ on(Src s, Dest d) { return on_t(s, d); } +template +struct on2_t : public std::binary_function { + typedef typename Dest::result_type result_type; + + on2_t(Src s, Dest d) : m_dest(d), m_src(s) {} + + result_type operator () (typename reference_fix::type first, typename reference_fix::type second) { + return m_dest(m_src(first), second); + } + + Dest m_dest; + Src m_src; +}; + +template +inline on2_t +on2(Src s, Dest d) { + return on2_t(s, d); +} + // Creates a functor for accessing a member. template struct mem_ptr_t : public std::unary_function { diff --git a/rak/functional_fun.h b/rak/functional_fun.h index 93cc2243..336f6725 100644 --- a/rak/functional_fun.h +++ b/rak/functional_fun.h @@ -52,6 +52,7 @@ #define RAK_FUNCTIONAL_FUN_H #include +#include namespace rak { @@ -64,13 +65,21 @@ public: }; template -class function_base1 { +class function_base1 : public std::unary_function { public: virtual ~function_base1() {} virtual Result operator () (Arg1 arg1) = 0; }; +template +class function_base2 : public std::binary_function { +public: + virtual ~function_base2() {} + + virtual Result operator () (Arg1 arg1, Arg2 arg2) = 0; +}; + template class function0 { public: @@ -105,6 +114,23 @@ private: std::auto_ptr m_base; }; +template +class function2 { +public: + typedef Result result_type; + typedef function_base2 base_type; + + bool is_valid() const { return m_base.get() != NULL; } + + void set(base_type* base) { m_base = std::auto_ptr(base); } + base_type* release() { return m_base.release(); } + + Result operator () (Arg1 arg1, Arg2 arg2) { return (*m_base)(arg1, arg2); } + +private: + std::auto_ptr m_base; +}; + template class ptr_fn0_t : public function_base0 { public: @@ -256,6 +282,37 @@ private: Arg1 m_arg1; }; +template +class ftor_fn1_t : public function_base1 { +public: + typedef typename Ftor::result_type result_type; + typedef typename Ftor::argument_type argument_type; + + ftor_fn1_t(Ftor ftor) : m_ftor(ftor) {} + virtual ~ftor_fn1_t() {} + + virtual result_type operator () (argument_type arg1) { return m_ftor(arg1); } + +private: + Ftor m_ftor; +}; + +template +class ftor_fn2_t : public function_base2 { +public: + typedef typename Ftor::result_type result_type; + typedef typename Ftor::first_argument_type first_argument_type; + typedef typename Ftor::second_argument_type second_argument_type; + + ftor_fn2_t(Ftor ftor) : m_ftor(ftor) {} + virtual ~ftor_fn2_t() {} + + virtual result_type operator () (first_argument_type arg1, second_argument_type arg2) { return m_ftor(arg1, arg2); } + +private: + Ftor m_ftor; +}; + template class value_fn0_t : public function_base0 { public: @@ -299,6 +356,22 @@ private: src_type m_object; }; +template +class convert_fn2_t : public function_base2 { +public: + typedef function2 src_type; + + convert_fn2_t(typename src_type::base_type* object) { m_object.set(object); } + virtual ~convert_fn2_t() {} + + virtual Result operator () (Arg1 arg1, Arg2 arg2) { + return m_object(arg1, arg2); + } + +private: + src_type m_object; +}; + template inline function_base0* ptr_fn(Result (*func)()) { @@ -359,6 +432,18 @@ bind_ptr_fn(Result (*func)(Arg1, Arg2), const Arg1 arg1) { return new ptr_fn1_b1_t(func, arg1); } +template +inline function_base1* +ftor_fn1(Ftor ftor) { + return new ftor_fn1_t(ftor); +} + +template +inline function_base2* +ftor_fn2(Ftor ftor) { + return new ftor_fn2_t(ftor); +} + template inline function_base0* value_fn(const Result& val) { @@ -403,6 +488,17 @@ convert_fn(function_base1* src) { return new convert_fn1_t(src); } +template +inline function_base2* +convert_fn(function_base2* src) { + if (equal_types_t, function_base2 >::result) + // The pointer cast never gets done if the types are different, + // but needs to be here to pleasant the compiler. + return reinterpret_cast, function_base2 >::first_type*>(src); + else + return new convert_fn2_t(src); +} + } #endif diff --git a/src/core/download.cc b/src/core/download.cc index fff2e5f7..c3b55018 100644 --- a/src/core/download.cc +++ b/src/core/download.cc @@ -36,11 +36,11 @@ #include "config.h" -#include #include #include #include #include +#include #include #include #include @@ -68,29 +68,32 @@ Download::Download(download_type d) : m_download.signal_chunk_failed(sigc::mem_fun(*this, &Download::receive_chunk_failed)); - m_variables.insert("connection_current", new utils::VariableStringSlot(rak::mem_fn(this, &Download::connection_current), - rak::mem_fn(this, &Download::set_connection_current))); + m_variables.insert("connection_current", new utils::VariableStringSlot(NULL, NULL, + rak::ftor_fn1(std::mem_fun(&Download::connection_current)), + rak::ftor_fn2(std::mem_fun(&Download::set_connection_current)))); m_variables.insert("connection_leech", new utils::VariableAny(connection_type_to_string(download_type::CONNECTION_LEECH))); m_variables.insert("connection_seed", new utils::VariableAny(connection_type_to_string(download_type::CONNECTION_SEED))); // 0 - stopped // 1 - started - m_variables.insert("state", new utils::VariableObject(bencode(), "rtorrent", "state", torrent::Object::TYPE_VALUE)); - m_variables.insert("complete", new utils::VariableObject(bencode(), "rtorrent", "complete", torrent::Object::TYPE_VALUE)); + m_variables.insert("state", new utils::VariableObject("rtorrent", "state", torrent::Object::TYPE_VALUE)); + m_variables.insert("complete", new utils::VariableObject("rtorrent", "complete", torrent::Object::TYPE_VALUE)); // 0 - Not hashing // 1 - Normal hashing // 2 - Download finished, hashing - m_variables.insert("hashing", new utils::VariableObject(bencode(), "rtorrent", "hashing", torrent::Object::TYPE_VALUE)); - m_variables.insert("tied_to_file", new utils::VariableObject(bencode(), "rtorrent", "tied_to_file", torrent::Object::TYPE_STRING)); + m_variables.insert("hashing", new utils::VariableObject("rtorrent", "hashing", torrent::Object::TYPE_VALUE)); + m_variables.insert("tied_to_file", new utils::VariableObject("rtorrent", "tied_to_file", torrent::Object::TYPE_STRING)); // The "state_changed" variable is required to be a valid unix time // value, it indicates the last time the torrent changed its state, // resume/pause. - m_variables.insert("state_changed", new utils::VariableObject(bencode(), "rtorrent", "state_changed", torrent::Object::TYPE_VALUE)); + m_variables.insert("state_changed", new utils::VariableObject("rtorrent", "state_changed", torrent::Object::TYPE_VALUE)); - m_variables.insert("directory", new utils::VariableStringSlot(rak::mem_fn(m_download.file_list(), &torrent::FileList::root_dir), rak::mem_fn(this, &Download::set_root_directory))); + m_variables.insert("directory", new utils::VariableStringSlot(NULL, NULL, + rak::ftor_fn1(rak::on(std::mem_fun(&Download::file_list), std::mem_fun(&torrent::FileList::root_dir))), + rak::ftor_fn2(std::mem_fun(&Download::set_root_directory)))); // m_variables.insert("info_hash", new utils::VariableStringSlot(rak::mem_fn(&m_download, &torrent::Download::info_hash), NULL)); @@ -113,7 +116,7 @@ Download::Download(download_type d) : m_variables.insert("tracker_numwant", new utils::VariableValueSlot(rak::mem_fn(&m_trackerList, &tracker_list_type::numwant), rak::mem_fn(&m_trackerList, &tracker_list_type::set_numwant))); - m_variables.insert("ignore_commands", new utils::VariableObject(bencode(), "rtorrent", "ignore_commands", torrent::Object::TYPE_VALUE)); + m_variables.insert("ignore_commands", new utils::VariableObject("rtorrent", "ignore_commands", torrent::Object::TYPE_VALUE)); } Download::~Download() { diff --git a/src/core/download.h b/src/core/download.h index dea54856..e092b5b2 100644 --- a/src/core/download.h +++ b/src/core/download.h @@ -82,14 +82,6 @@ public: bool is_hash_failed() const { return m_hashFailed; } void set_hash_failed(bool v) { m_hashFailed = v; } - variable_map_type* variable() { return &m_variables; } - - int64_t variable_value(const std::string& key) const { return m_variables.get_value(key.c_str()); } - const std::string& variable_string(const std::string& key) const { return m_variables.get_string(key.c_str()); } - - int64_t variable_value_c(const char* key) const { return m_variables.get_value(key); } - const std::string& variable_string_c(const char* key) const { return m_variables.get_string(key); } - download_type* download() { return &m_download; } const download_type* c_download() const { return &m_download; } @@ -109,13 +101,18 @@ public: uint32_t priority(); void set_priority(uint32_t p); - // Helper functions for calling functions in download_type - // through sigc++. - template - void call() { (m_download.*func)(); } +// variable_map_type* variable() { return &m_variables; } - template - void call(Arg1 a1) { (m_download.*func)(a1); } + int64_t get_value(const char* key) { return m_variables.get_d_value(this, key); } + const std::string& get_string(const char* key) { return m_variables.get_d_string(this, key); } + + int64_t get_std_value(const std::string& key) { return m_variables.get_d_value(this, key.c_str()); } + const std::string& get_std_string(const std::string& key) { return m_variables.get_d_string(this, key.c_str()); } + + void set(const char* key, const torrent::Object& value) { return m_variables.set_d(this, key, value); } + + void set_value(const char* key, int64_t value) { return m_variables.set_d_value(this, key, value); } + void set_string(const char* key, const std::string& value) { return m_variables.set_d_string(this, key, value); } bool operator == (const std::string& str) const; diff --git a/src/core/download_factory.cc b/src/core/download_factory.cc index fead33b9..2820e437 100644 --- a/src/core/download_factory.cc +++ b/src/core/download_factory.cc @@ -172,27 +172,27 @@ DownloadFactory::receive_success() { initialize_rtorrent(download, rtorrent); // Move to 'rtorrent'. - download->variable()->set("connection_leech", m_variables.get("connection_leech")); - download->variable()->set("connection_seed", m_variables.get("connection_seed")); + download->set("connection_leech", m_variables.get("connection_leech")); + download->set("connection_seed", m_variables.get("connection_seed")); - download->variable()->set("max_uploads", control->variable()->get("max_uploads")); - download->variable()->set("min_peers", control->variable()->get("min_peers")); - download->variable()->set("max_peers", control->variable()->get("max_peers")); - download->variable()->set("tracker_numwant", control->variable()->get("tracker_numwant")); + download->set("max_uploads", control->variable()->get("max_uploads")); + download->set("min_peers", control->variable()->get("min_peers")); + download->set("max_peers", control->variable()->get("max_peers")); + download->set("tracker_numwant", control->variable()->get("tracker_numwant")); - if (download->variable()->get_value("complete") != 0) { + if (download->get_value("complete") != 0) { if (control->variable()->get_value("min_peers_seed") >= 0) - download->variable()->set("min_peers", control->variable()->get("min_peers_seed")); + download->set("min_peers", control->variable()->get("min_peers_seed")); if (control->variable()->get_value("max_peers_seed") >= 0) - download->variable()->set("max_peers", control->variable()->get("max_peers_seed")); + download->set("max_peers", control->variable()->get("max_peers_seed")); } if (!control->variable()->get_value("use_udp_trackers")) download->enable_udp_trackers(false); if (control->variable()->get_value("max_file_size") > 0) - download->variable()->set("max_file_size", control->variable()->get("max_file_size")); + download->set("max_file_size", control->variable()->get("max_file_size")); // Check first if we already have these values set in the session // torrent, so that it is safe to change the values. @@ -204,12 +204,12 @@ DownloadFactory::receive_success() { control->variable()->get_string("split_suffix")); if (!rtorrent->has_key_string("directory")) - download->variable()->set("directory", m_variables.get("directory")); + download->set("directory", m_variables.get("directory")); else - download->variable()->set("directory", rtorrent->get_key("directory")); + download->set("directory", rtorrent->get_key("directory")); if (!m_session && m_variables.get("tied_to_file").as_value()) - download->variable()->set("tied_to_file", m_uri); + download->set("tied_to_file", m_uri); torrent::Object& resumeObject = root->has_key_map("libtorrent_resume") ? root->get_key("libtorrent_resume") @@ -234,8 +234,8 @@ DownloadFactory::receive_success() { if (m_session) { // This torrent was queued for hashing or hashing when the session // file was saved. Or it was in a started state. - if (download->variable()->get_value("hashing") != Download::variable_hashing_stopped || - download->variable()->get_value("state") != 0) + if (download->get_value("hashing") != Download::variable_hashing_stopped || + download->get_value("state") != 0) m_manager->download_list()->resume(download); } else { @@ -284,9 +284,9 @@ DownloadFactory::initialize_rtorrent(Download* download, torrent::Object* rtorre rtorrent->insert_key("tied_to_file", std::string()); if (rtorrent->has_key_value("priority")) - download->variable()->set("priority", rtorrent->get_key_value("priority") % 4); + download->set("priority", rtorrent->get_key_value("priority") % 4); else - download->variable()->set("priority", (int64_t)2); + download->set("priority", (int64_t)2); if (rtorrent->has_key_value("key")) { download->tracker_list()->set_key(rtorrent->get_key_value("key")); diff --git a/src/core/download_list.cc b/src/core/download_list.cc index 13346d0b..b000650f 100644 --- a/src/core/download_list.cc +++ b/src/core/download_list.cc @@ -229,7 +229,7 @@ DownloadList::close_throw(Download* download) { download->download()->close(); - if (!download->is_hash_failed() && download->variable()->get_value("hashing") != Download::variable_hashing_stopped) + if (!download->is_hash_failed() && download->get_value("hashing") != Download::variable_hashing_stopped) throw torrent::internal_error("DownloadList::close_throw(...) called but we're going into a hashing loop."); std::for_each(slot_map_hash_removed().begin(), slot_map_hash_removed().end(), download_list_call(download)); @@ -243,7 +243,7 @@ DownloadList::start_normal(Download* download) { // Clear hash failed as we're doing a manual start and want to try // hashing again. download->set_hash_failed(false); - download->variable()->set("state", (int64_t)1); + download->set("state", (int64_t)1); resume(download); } @@ -255,12 +255,12 @@ DownloadList::start_try(Download* download) { // Also don't start if the state is one of those that indicate we // were manually stopped? - if (download->is_hash_failed() || download->variable()->get_value("ignore_commands") != 0) + if (download->is_hash_failed() || download->get_value("ignore_commands") != 0) return false; // Don't clear the hash failed as this function is used by scripts, // etc. - download->variable()->set("state", (int64_t)1); + download->set("state", (int64_t)1); resume(download); return true; @@ -270,7 +270,7 @@ void DownloadList::stop_normal(Download* download) { check_contains(download); - download->variable()->set("state", (int64_t)0); + download->set("state", (int64_t)0); pause(download); } @@ -279,10 +279,10 @@ bool DownloadList::stop_try(Download* download) { check_contains(download); - if (download->variable()->get_value("ignore_commands") != 0) + if (download->get_value("ignore_commands") != 0) return false; - download->variable()->set("state", (int64_t)0); + download->set("state", (int64_t)0); pause(download); return true; @@ -308,8 +308,8 @@ DownloadList::resume(Download* download) { if (download->is_hash_failed()) return; - if (download->variable()->get_value("hashing") == Download::variable_hashing_stopped) - download->variable()->set("hashing", Download::variable_hashing_initial); + if (download->get_value("hashing") == Download::variable_hashing_stopped) + download->set("hashing", Download::variable_hashing_initial); std::for_each(slot_map_hash_queued().begin(), slot_map_hash_queued().end(), download_list_call(download)); return; @@ -318,12 +318,12 @@ DownloadList::resume(Download* download) { // This will never actually do anything due to the above hash check. // open_throw(download); - download->variable()->set("state_changed", cachedTime.seconds()); + download->set("state_changed", cachedTime.seconds()); if (download->is_done()) { - download->set_connection_type(download->variable()->get_string("connection_seed")); + download->set_connection_type(download->get_string("connection_seed")); } else { - download->set_connection_type(download->variable()->get_string("connection_leech")); + download->set_connection_type(download->get_string("connection_leech")); // For the moment, clear the resume data so we force hash-check // on non-complete downloads after a crash. This shouldn't be @@ -352,9 +352,9 @@ DownloadList::pause(Download* download) { // Always clear hashing on pause. When a hashing request is added, // it should have cleared the hash resume data. - if (download->variable()->get_value("hashing") != Download::variable_hashing_stopped) { + if (download->get_value("hashing") != Download::variable_hashing_stopped) { download->download()->hash_stop(); - download->variable()->set_value("hashing", Download::variable_hashing_stopped); + download->set_value("hashing", Download::variable_hashing_stopped); std::for_each(slot_map_hash_removed().begin(), slot_map_hash_removed().end(), download_list_call(download)); } @@ -367,7 +367,7 @@ DownloadList::pause(Download* download) { std::for_each(slot_map_stop().begin(), slot_map_stop().end(), download_list_call(download)); - download->variable()->set("state_changed", cachedTime.seconds()); + download->set("state_changed", cachedTime.seconds()); // Save the state after all the slots, etc have been called so we // include the modifications they may make. @@ -384,7 +384,7 @@ DownloadList::check_hash(Download* download) { try { - if (download->variable()->get_value("hashing") != Download::variable_hashing_stopped) + if (download->get_value("hashing") != Download::variable_hashing_stopped) return; hash_queue(download, Download::variable_hashing_rehash); @@ -417,8 +417,8 @@ DownloadList::hash_done(Download* download) { // confirm all the data, avoiding large BW usage on f.ex. the // ReiserFS bug with >4GB files. - int64_t hashing = download->variable()->get_value("hashing"); - download->variable()->set_value("hashing", Download::variable_hashing_stopped); + int64_t hashing = download->get_value("hashing"); + download->set_value("hashing", Download::variable_hashing_stopped); switch (hashing) { case Download::variable_hashing_initial: @@ -427,17 +427,17 @@ DownloadList::hash_done(Download* download) { // If the download was previously completed but the files were // f.ex deleted, then we clear the state and complete. - if (download->variable()->get_value("complete") && !download->is_done()) { - download->variable()->set("state", (int64_t)0); + if (download->get_value("complete") && !download->is_done()) { + download->set("state", (int64_t)0); download->set_message("Download registered as completed, but hash check returned unfinished chunks."); } // Save resume data so we update time-stamps and priorities if // they were invalid/changed while loading/hashing. - download->variable()->set("complete", (int64_t)download->is_done()); + download->set("complete", (int64_t)download->is_done()); torrent::resume_save_progress(*download->download(), download->download()->bencode()->get_key("libtorrent_resume")); - if (download->variable()->get_value("state") == 1) + if (download->get_value("state") == 1) resume(download); break; @@ -467,14 +467,14 @@ void DownloadList::hash_queue(Download* download, int type) { check_contains(download); - if (download->variable()->get_value("hashing") != Download::variable_hashing_stopped) + if (download->get_value("hashing") != Download::variable_hashing_stopped) throw torrent::internal_error("DownloadList::hash_queue(...) hashing already queued."); close_throw(download); torrent::resume_clear_progress(*download->download(), download->download()->bencode()->get_key("libtorrent_resume")); download->set_hash_failed(false); - download->variable()->set_value("hashing", type); + download->set_value("hashing", type); if (download->is_open()) throw torrent::internal_error("DownloadList::hash_clear(...) download still open."); @@ -503,16 +503,16 @@ void DownloadList::confirm_finished(Download* download) { check_contains(download); - download->variable()->set("complete", (int64_t)1); + download->set("complete", (int64_t)1); - download->set_connection_type(download->variable()->get_string("connection_seed")); + download->set_connection_type(download->get_string("connection_seed")); download->set_priority(download->priority()); - if (download->variable_value("min_peers") == control->variable()->get_value("min_peers") && control->variable()->get_value("min_peers_seed") >= 0) - download->variable()->set("min_peers", control->variable()->get("min_peers_seed")); + if (download->get_value("min_peers") == control->variable()->get_value("min_peers") && control->variable()->get_value("min_peers_seed") >= 0) + download->set("min_peers", control->variable()->get("min_peers_seed")); - if (download->variable_value("max_peers") == control->variable()->get_value("max_peers") && control->variable()->get_value("max_peers_seed") >= 0) - download->variable()->set("max_peers", control->variable()->get("max_peers_seed")); + if (download->get_value("max_peers") == control->variable()->get_value("max_peers") && control->variable()->get_value("max_peers_seed") >= 0) + download->set("max_peers", control->variable()->get("max_peers_seed")); // Do this before the slots are called in case one of them closes // the download. @@ -527,7 +527,7 @@ DownloadList::confirm_finished(Download* download) { std::for_each(slot_map_finished().begin(), slot_map_finished().end(), download_list_call(download)); - if (!download->is_active() && download->variable()->get_value("state") == 1) + if (!download->is_active() && download->get_value("state") == 1) resume(download); } diff --git a/src/core/manager.cc b/src/core/manager.cc index 2d7d81e0..7770228d 100644 --- a/src/core/manager.cc +++ b/src/core/manager.cc @@ -166,8 +166,8 @@ Manager::handshake_log(const sockaddr* sa, int msg, int err, const torrent::Hash // Hmm... find some better place for all this. void -Manager::delete_tied(Download* d) { - const std::string& tie = d->variable()->get_string("tied_to_file"); +Manager::delete_tied(Download* download) { + const std::string& tie = download->get_string("tied_to_file"); // This should be configurable, need to wait for the variable // thingie to be implemented. @@ -177,7 +177,7 @@ Manager::delete_tied(Download* d) { if (::unlink(rak::path_expand(tie).c_str()) == -1) push_log("Could not unlink tied file: " + std::string(rak::error_number::current().c_str())); - d->variable()->set("tied_to_file", std::string()); + download->set("tied_to_file", std::string()); } Manager::Manager() : @@ -468,7 +468,7 @@ Manager::try_create_download_expand(const std::string& uri, bool start, bool pri if (tied) for (std::vector::iterator itr = paths.begin(); itr != paths.end(); ) - if (std::find_if(m_downloadList->begin(), m_downloadList->end(), rak::equal(*itr, rak::bind2nd(std::mem_fun(&Download::variable_string), "tied_to_file"))) + if (std::find_if(m_downloadList->begin(), m_downloadList->end(), rak::equal(*itr, rak::bind2nd(std::mem_fun(&Download::get_string), "tied_to_file"))) != m_downloadList->end()) itr = paths.erase(itr); else @@ -504,7 +504,7 @@ Manager::receive_hashing_changed() { continue; bool tryQuick = - (*itr)->variable()->get_value("hashing") == Download::variable_hashing_initial && + (*itr)->get_value("hashing") == Download::variable_hashing_initial && (*itr)->download()->file_list()->bitfield()->empty(); if (!tryQuick && foundHashing) @@ -526,7 +526,7 @@ Manager::receive_hashing_changed() { (*itr)->download()->hash_stop(); // Make sure we don't repeat the quick hashing. - (*itr)->variable()->set_value("hashing", Download::variable_hashing_rehash); + (*itr)->set_value("hashing", Download::variable_hashing_rehash); } else { (*itr)->download()->hash_check(false); @@ -535,7 +535,7 @@ Manager::receive_hashing_changed() { } catch (torrent::local_error& e) { if (tryQuick) { // Make sure we don't repeat the quick hashing. - (*itr)->variable()->set_value("hashing", Download::variable_hashing_rehash); + (*itr)->set_value("hashing", Download::variable_hashing_rehash); } else { (*itr)->set_hash_failed(true); diff --git a/src/core/view_manager.cc b/src/core/view_manager.cc index db978471..eb2f24a9 100644 --- a/src/core/view_manager.cc +++ b/src/core/view_manager.cc @@ -70,8 +70,8 @@ public: virtual bool operator () (Download* d1, Download* d2) const { return - d1->variable()->get_string(m_name) == m_value && - d2->variable()->get_string(m_name) != m_value; + d1->get_string(m_name) == m_value && + d2->get_string(m_name) != m_value; } private: @@ -85,9 +85,9 @@ public: virtual bool operator () (Download* d1, Download* d2) const { if (m_reverse) - return d2->variable()->get_value(m_name) < d1->variable()->get_value(m_name); + return d2->get_value(m_name) < d1->get_value(m_name); else - return d1->variable()->get_value(m_name) < d2->variable()->get_value(m_name); + return d1->get_value(m_name) < d2->get_value(m_name); } private: @@ -114,7 +114,7 @@ public: m_name(name), m_value(v), m_inverse(inverse) {} virtual bool operator () (Download* d1) const { - return (d1->variable()->get_value(m_name) == m_value) != m_inverse; + return (d1->get_value(m_name) == m_value) != m_inverse; } private: diff --git a/src/display/text_element_helpers.h b/src/display/text_element_helpers.h index 90962021..56e8b419 100644 --- a/src/display/text_element_helpers.h +++ b/src/display/text_element_helpers.h @@ -93,7 +93,7 @@ te_string(Return (torrent::FileList::*fptr)() const, int flags = TextElementStri inline TextElementStringBase* te_variable_string(const std::string& variable, int flags = TextElementStringBase::flag_normal, int attributes = Attributes::a_invalid) { - return text_element_string_slot(rak::bind2nd(std::mem_fun(&core::Download::variable_string), variable), flags, attributes); + return text_element_string_slot(rak::bind2nd(std::mem_fun(&core::Download::get_std_string), variable), flags, attributes); } // Value stuff: @@ -118,7 +118,7 @@ te_value(Return (torrent::File::*fptr)() const, int flags = TextElementValueBase inline TextElementValueBase* te_variable_value(const std::string& variable, int flags = TextElementValueBase::flag_normal, int attributes = Attributes::a_invalid) { - return text_element_value_slot(rak::bind2nd(std::mem_fun(&core::Download::variable_value), variable), flags, attributes); + return text_element_value_slot(rak::bind2nd(std::mem_fun(&core::Download::get_std_value), variable), flags, attributes); } template diff --git a/src/display/utils.cc b/src/display/utils.cc index 239b1596..1bef4e6f 100644 --- a/src/display/utils.cc +++ b/src/display/utils.cc @@ -158,8 +158,8 @@ print_download_info(char* first, char* last, core::Download* d) { } first = print_buffer(first, last, " [%c%c R: %3.2f", - d->variable()->get_string("tied_to_file").empty() ? ' ' : 'T', - d->variable()->get_value("ignore_commands") == 0 ? ' ' : 'I', + d->get_string("tied_to_file").empty() ? ' ' : 'T', + d->get_value("ignore_commands") == 0 ? ' ' : 'I', d->download()->bytes_done() > 0 ? (double)(100 * d->download()->up_rate()->total() / d->download()->bytes_done()) / 100 : 0.0); if (d->priority() != 2) @@ -177,7 +177,7 @@ char* print_download_status(char* first, char* last, core::Download* d) { if (d->is_active()) ; - else if (d->variable_value("hashing") != 0) + else if (d->get_value("hashing") != 0) first = print_buffer(first, last, "Hashing: "); else if (!d->is_active()) first = print_buffer(first, last, "Inactive: "); diff --git a/src/option_handler_rules.cc b/src/option_handler_rules.cc index 04ef6554..e4443133 100644 --- a/src/option_handler_rules.cc +++ b/src/option_handler_rules.cc @@ -78,6 +78,17 @@ namespace core { path_expand(std::vector* paths, const std::string& pattern); } +// void +// apply_new_string(const std::string& args) { +// std::string::const_iterator split = std::find(args.begin(), args.end(), ','); + +// std::string key = + +// if (control->variable()->has(args)) + +// variables->insert("tracker_dump", new utils::VariableAny(std::string())); +// } + void apply_hash_read_ahead(__UNUSED Control* m, int arg) { torrent::set_hash_read_ahead(arg << 20); @@ -122,11 +133,11 @@ apply_load_start_verbose(Control* m, const std::string& arg) { void apply_start_tied(Control* m) { for (core::DownloadList::iterator itr = m->core()->download_list()->begin(); itr != m->core()->download_list()->end(); ++itr) { - if ((*itr)->variable_value("state") == 1) + if ((*itr)->get_value("state") == 1) continue; rak::file_stat fs; - const std::string& tiedToFile = (*itr)->variable_string("tied_to_file"); + const std::string& tiedToFile = (*itr)->get_string("tied_to_file"); if (!tiedToFile.empty() && fs.update(rak::path_expand(tiedToFile))) m->core()->download_list()->start_try(*itr); @@ -136,11 +147,11 @@ apply_start_tied(Control* m) { void apply_stop_untied(Control* m) { for (core::DownloadList::iterator itr = m->core()->download_list()->begin(); itr != m->core()->download_list()->end(); ++itr) { - if ((*itr)->variable_value("state") == 0) + if ((*itr)->get_value("state") == 0) continue; rak::file_stat fs; - const std::string& tiedToFile = (*itr)->variable_string("tied_to_file"); + const std::string& tiedToFile = (*itr)->get_string("tied_to_file"); if (!tiedToFile.empty() && !fs.update(rak::path_expand(tiedToFile))) m->core()->download_list()->stop_try(*itr); @@ -151,7 +162,7 @@ void apply_close_untied(Control* m) { for (core::DownloadList::iterator itr = m->core()->download_list()->begin(); itr != m->core()->download_list()->end(); ++itr) { rak::file_stat fs; - const std::string& tiedToFile = (*itr)->variable_string("tied_to_file"); + const std::string& tiedToFile = (*itr)->get_string("tied_to_file"); if (!tiedToFile.empty() && !fs.update(rak::path_expand(tiedToFile)) && m->core()->download_list()->stop_try(*itr)) m->core()->download_list()->close(*itr); @@ -162,7 +173,7 @@ void apply_remove_untied(Control* m) { for (core::DownloadList::iterator itr = m->core()->download_list()->begin(); itr != m->core()->download_list()->end(); ) { rak::file_stat fs; - const std::string& tiedToFile = (*itr)->variable_string("tied_to_file"); + const std::string& tiedToFile = (*itr)->get_string("tied_to_file"); if (!tiedToFile.empty() && !fs.update(rak::path_expand(tiedToFile)) && m->core()->download_list()->stop_try(*itr)) itr = m->core()->download_list()->erase(itr); @@ -211,13 +222,30 @@ apply_stop_on_ratio(Control* m, const std::string& arg) { if ((totalUpload >= minUpload && totalUpload * 100 >= totalDone * minRatio) || (maxRatio > 0 && totalUpload * 100 > totalDone * maxRatio)) { m->core()->download_list()->stop_try(*itr); - (*itr)->variable()->set("ignore_commands", (int64_t)1); + (*itr)->set("ignore_commands", (int64_t)1); } ++itr; } } +// void +// apply_on_finished(const std::string& arg) { +// std::string::const_iterator itr = std::find(arg.begin(), arg.end(), ','); + +// std::string key = rak::trim(std::string(arg.begin(), itr)); +// std::string value = rak::trim(std::string(itr != arg.end() ? itr + 1 : itr, arg.end())); + +// if (key.empty()) +// throw torrent::input_error("Empty key."); + +// if (value.empty()) +// control->core()->download_list()->slot_map_finished().erase("0_finished_" + key); +// else +// control->core()->download_list()->slot_map_finished().insert("0_finished_" + key, ); +// ->process_std_single(value); +// } + void apply_encoding_list(__UNUSED Control* m, const std::string& arg) { torrent::encoding_list()->push_back(arg); @@ -548,6 +576,8 @@ initialize_option_handler(Control* c) { variables->insert("close_low_diskspace", new utils::VariableValueSlot(rak::value_fn(int64_t()), rak::bind_ptr_fn(&apply_close_low_diskspace, c))); variables->insert("stop_on_ratio", new utils::VariableStringSlot(rak::value_fn(std::string()), rak::bind_ptr_fn(&apply_stop_on_ratio, c))); +// variables->insert("on_finished", new utils::VariableStringSlot(rak::value_fn(std::string()), rak::ptr_fn(&apply_on_finished))); + variables->insert("enable_trackers", new utils::VariableStringSlot(rak::value_fn(std::string()), rak::bind_ptr_fn(&apply_enable_trackers, c))); variables->insert("encoding_list", new utils::VariableStringSlot(rak::value_fn(std::string()), rak::bind_ptr_fn(&apply_encoding_list, c))); diff --git a/src/ui/download_list.cc b/src/ui/download_list.cc index c8be083d..4c2616a5 100644 --- a/src/ui/download_list.cc +++ b/src/ui/download_list.cc @@ -283,8 +283,8 @@ DownloadList::receive_exit_input(Input type) { if (current_view()->focus() == current_view()->end_visible()) throw torrent::input_error("No download in focus to change root directory."); - (*current_view()->focus())->variable()->set("directory", rak::trim(input->str())); - control->core()->push_log("New root directory \"" + (*current_view()->focus())->variable()->get_string("directory") + "\" for torrent."); + (*current_view()->focus())->set("directory", rak::trim(input->str())); + control->core()->push_log("New root directory \"" + (*current_view()->focus())->get_string("directory") + "\" for torrent."); break; case INPUT_COMMAND: diff --git a/src/ui/element_download_list.cc b/src/ui/element_download_list.cc index 21b93df8..c4867aee 100644 --- a/src/ui/element_download_list.cc +++ b/src/ui/element_download_list.cc @@ -149,7 +149,7 @@ ElementDownloadList::receive_stop_download() { if (m_view->focus() == m_view->end_visible()) return; - if ((*m_view->focus())->variable()->get_value("state") == 1) + if ((*m_view->focus())->get_value("state") == 1) control->core()->download_list()->stop_normal(*m_view->focus()); else control->core()->download_list()->erase(*m_view->focus()); @@ -164,7 +164,7 @@ ElementDownloadList::receive_close_download() { core::Download* download = *m_view->focus(); - download->variable()->set("ignore_commands", (int64_t)1); + download->set("ignore_commands", (int64_t)1); control->core()->download_list()->stop_normal(download); control->core()->download_list()->close(download); @@ -203,11 +203,11 @@ ElementDownloadList::receive_ignore_ratio() { if (m_view->focus() == m_view->end_visible()) return; - if ((*m_view->focus())->variable()->get_value("ignore_commands") != 0) { - (*m_view->focus())->variable()->set("ignore_commands", (int64_t)0); + if ((*m_view->focus())->get_value("ignore_commands") != 0) { + (*m_view->focus())->set("ignore_commands", (int64_t)0); control->core()->push_log("Torrent set to heed commands."); } else { - (*m_view->focus())->variable()->set("ignore_commands", (int64_t)1); + (*m_view->focus())->set("ignore_commands", (int64_t)1); control->core()->push_log("Torrent set to ignore commands."); } } @@ -217,7 +217,7 @@ ElementDownloadList::receive_clear_tied() { if (m_view->focus() == m_view->end_visible()) return; - const std::string& tiedFile = (*m_view->focus())->variable()->get_string("tied_to_file"); + const std::string& tiedFile = (*m_view->focus())->get_string("tied_to_file"); if (!tiedFile.empty()) { // Move this into core? diff --git a/src/utils/variable.cc b/src/utils/variable.cc index 42e8c260..158af345 100644 --- a/src/utils/variable.cc +++ b/src/utils/variable.cc @@ -44,6 +44,26 @@ namespace utils { const torrent::Object Variable::m_emptyObject; +// Consider throwing an exception. +const torrent::Object& +Variable::get() { + return m_emptyObject; +} + +void +Variable::set(const torrent::Object& arg) { +} + +const torrent::Object& +Variable::get_d(core::Download* download) { + return get(); +} + +void +Variable::set_d(core::Download* download, const torrent::Object& arg) { + set(arg); +} + const char* Variable::string_to_value_unit(const char* pos, value_type* value, int base, int unit) { char* last; diff --git a/src/utils/variable.h b/src/utils/variable.h index b2a4048e..e0f6b172 100644 --- a/src/utils/variable.h +++ b/src/utils/variable.h @@ -39,6 +39,10 @@ #include +namespace core { + class Download; +} + namespace utils { class Variable { @@ -52,8 +56,12 @@ public: Variable() {} virtual ~Variable() {} - virtual const torrent::Object& get() = 0; - virtual void set(const torrent::Object& arg) = 0; + virtual const torrent::Object& get(); + virtual void set(const torrent::Object& arg); + + // The default action is to throw away the 'download' argument. + virtual const torrent::Object& get_d(core::Download* download); + virtual void set_d(core::Download* download, const torrent::Object& arg); static const char* string_to_value_unit(const char* pos, value_type* value, int base, int unit); static bool string_to_value_unit_nothrow(const char* pos, value_type* value, int base, int unit); diff --git a/src/utils/variable_generic.cc b/src/utils/variable_generic.cc index d4b09651..13b36f88 100644 --- a/src/utils/variable_generic.cc +++ b/src/utils/variable_generic.cc @@ -102,22 +102,22 @@ VariableBool::set(const torrent::Object& arg) { } const torrent::Object& -VariableObject::get() { +VariableObject::get_d(core::Download* download) { if (m_root.empty()) - return m_bencode->get_key(m_key); + return download->bencode()->get_key(m_key); else - return m_bencode->get_key(m_root).get_key(m_key); + return download->bencode()->get_key(m_root).get_key(m_key); } void -VariableObject::set(const torrent::Object& arg) { +VariableObject::set_d(core::Download* download, const torrent::Object& arg) { // Consider removing if TYPE_NONE. torrent::Object* root; if (m_root.empty()) - root = m_bencode; + root = download->bencode(); else - root = &m_bencode->get_key(m_root); + root = &download->bencode()->get_key(m_root); switch (m_type) { case torrent::Object::TYPE_NONE: @@ -200,7 +200,7 @@ VariableValueSlot::set(const torrent::Object& arg) { const torrent::Object& VariableStringSlot::get() { if (!m_slotGet.is_valid()) - return m_cache; + return m_cache = torrent::Object(); m_cache = m_slotGet(); @@ -224,4 +224,51 @@ VariableStringSlot::set(const torrent::Object& arg) { } } +const torrent::Object& +VariableStringSlot::get_d(core::Download* download) { + // Should clear the cache. + if (!m_slotGetDownload.is_valid()) { + if (!m_slotGet.is_valid()) + return m_cache = torrent::Object(); + + m_cache = m_slotGet(); + + } else { + m_cache = m_slotGetDownload(download); + } + + return m_cache; +} + +void +VariableStringSlot::set_d(core::Download* download, const torrent::Object& arg) { + if (!m_slotSetDownload.is_valid()) { + if (!m_slotSet.is_valid()) + return; + + switch (arg.type()) { + case torrent::Object::TYPE_STRING: + m_slotSet(arg.as_string()); + break; + case torrent::Object::TYPE_NONE: + m_slotSet(std::string()); + break; + default: + throw torrent::input_error("Not a string."); + } + + } else { + switch (arg.type()) { + case torrent::Object::TYPE_STRING: + m_slotSetDownload(download, arg.as_string()); + break; + case torrent::Object::TYPE_NONE: + m_slotSetDownload(download, std::string()); + break; + default: + throw torrent::input_error("Not a string."); + } + } +} + } diff --git a/src/utils/variable_generic.h b/src/utils/variable_generic.h index d2f78df2..c76bec85 100644 --- a/src/utils/variable_generic.h +++ b/src/utils/variable_generic.h @@ -49,6 +49,7 @@ #include #include "variable.h" +#include "core/download.h" namespace utils { @@ -82,17 +83,13 @@ class VariableObject : public Variable { public: typedef torrent::Object::type_type Type; - VariableObject(torrent::Object* b, - const std::string& root, - const std::string& key, - Type t = torrent::Object::TYPE_NONE) : - m_bencode(b), m_root(root), m_key(key), m_type(t) {} + VariableObject(const std::string& root, const std::string& key, Type t = torrent::Object::TYPE_NONE) : + m_root(root), m_key(key), m_type(t) {} - virtual const torrent::Object& get(); - virtual void set(const torrent::Object& arg); + virtual const torrent::Object& get_d(core::Download* download); + virtual void set_d(core::Download* download, const torrent::Object& arg); private: - torrent::Object* m_bencode; std::string m_root; std::string m_key; Type m_type; @@ -169,27 +166,54 @@ private: class VariableStringSlot : public Variable { public: - typedef rak::function0 slot_get_type; - typedef rak::function1 slot_set_type; + typedef rak::function0 slot_get_type; + typedef rak::function1 slot_get_d_type; + typedef rak::function1 slot_set_type; + typedef rak::function2 slot_set_d_type; template VariableStringSlot(SlotGet* slotGet, SlotSet* slotSet) { m_slotGet.set(rak::convert_fn(slotGet)); m_slotSet.set(rak::convert_fn(slotSet)); + m_slotGetDownload.set(NULL); + m_slotSetDownload.set(NULL); } - template - VariableStringSlot(SlotGet* slotGet, void* slotSet) { - m_slotGet.set(rak::convert_fn(slotGet)); + template + VariableStringSlot(void* slotGet, void* slotSet, SlotGetDownload* slotGetDownload, void* slotSetDownload) { + m_slotGet.set(NULL); m_slotSet.set(NULL); + m_slotGetDownload.set(rak::convert_fn(slotGetDownload)); + m_slotSetDownload.set(NULL); } + template + VariableStringSlot(void* slotGet, void* slotSet, SlotGetDownload* slotGetDownload, SlotSetDownload* slotSetDownload) { + m_slotGet.set(NULL); + m_slotSet.set(NULL); + m_slotGetDownload.set(rak::convert_fn(slotGetDownload)); + m_slotSetDownload.set(rak::convert_fn(slotSetDownload)); + } + +// template +// VariableStringSlot(SlotGet* slotGet, SlotSet* slotSet, SlotGetDownload* slotGetDownload, SlotSetDownload* slotSetDownload) { +// m_slotGet.set(slotGet != NULL ? rak::convert_fn(slotGet) : NULL); +// m_slotSet.set(slotSet != NULL ? rak::convert_fn(slotSet) : NULL); +// m_slotGetDownload.set(slotGetDownload != NULL ? rak::convert_fn(slotGetDownload) : NULL); +// m_slotSetDownload.set(slotSetDownload != NULL ? rak::convert_fn(slotSetDownload) : NULL); +// } + virtual const torrent::Object& get(); virtual void set(const torrent::Object& arg); + virtual const torrent::Object& get_d(core::Download* download); + virtual void set_d(core::Download* download, const torrent::Object& arg); + private: slot_get_type m_slotGet; slot_set_type m_slotSet; + slot_get_d_type m_slotGetDownload; + slot_set_d_type m_slotSetDownload; // Store the cache here to avoid unnessesary copying and such. This // should not result in any unresonable memory usage since few diff --git a/src/utils/variable_map.cc b/src/utils/variable_map.cc index 2aabbeaa..00e623e7 100644 --- a/src/utils/variable_map.cc +++ b/src/utils/variable_map.cc @@ -74,6 +74,16 @@ VariableMap::get(key_type key) const { return itr->second->get(); } +const VariableMap::mapped_type& +VariableMap::get_d(core::Download* download, key_type key) const { + const_iterator itr = base_type::find(key); + + if (itr == base_type::end()) + throw torrent::input_error("Variable \"" + std::string(key) + "\" does not exist."); + + return itr->second->get_d(download); +} + void VariableMap::set(key_type key, const mapped_type& arg) { iterator itr = base_type::find(key); @@ -86,6 +96,18 @@ VariableMap::set(key_type key, const mapped_type& arg) { itr->second->set(arg); } +void +VariableMap::set_d(core::Download* download, key_type key, const mapped_type& arg) { + iterator itr = base_type::find(key); + + // Later, allow the user to create new variables. Have a slot to + // register that thing. + if (itr == base_type::end()) + throw torrent::input_error("Variable \"" + std::string(key) + "\" does not exist."); + + itr->second->set_d(download, arg); +} + struct variable_map_is_space : std::unary_function { bool operator () (char c) const { return std::isspace(c); diff --git a/src/utils/variable_map.h b/src/utils/variable_map.h index a58ad03c..6091c5d5 100644 --- a/src/utils/variable_map.h +++ b/src/utils/variable_map.h @@ -43,6 +43,10 @@ #include #include +namespace core { + class Download; +} + namespace torrent { class Object; } @@ -78,15 +82,25 @@ public: void insert(key_type key, Variable* v); - // Consider taking char* start and finish instead of std::string to - // avoid copying. Or make a view class. + // Consider uninlining the helper functions. + const mapped_type& get(key_type key) const; - const std::string& get_string(key_type key) const { return get(key).as_string(); } - mapped_value_type get_value(key_type key) const { return get(key).as_value(); } + const mapped_type& get_d(core::Download* download, key_type key) const; + + const std::string& get_string(key_type key) const { return get(key).as_string(); } + const std::string& get_d_string(core::Download* download, key_type key) const { return get_d(download, key).as_string(); } + + mapped_value_type get_value(key_type key) const { return get(key).as_value(); } + mapped_value_type get_d_value(core::Download* download, key_type key) const { return get_d(download, key).as_value(); } void set(key_type key, const mapped_type& arg); - void set_string(key_type key, const std::string& arg) { set(key, mapped_type(arg)); } - void set_value(key_type key, mapped_value_type arg) { set(key, mapped_type(arg)); } + void set_d(core::Download* download, key_type key, const mapped_type& arg); + + void set_string(key_type key, const std::string& arg) { set(key, mapped_type(arg)); } + void set_d_string(core::Download* download, key_type key, const std::string& arg) { set_d(download, key, mapped_type(arg)); } + + void set_value(key_type key, mapped_value_type arg) { set(key, mapped_type(arg)); } + void set_d_value(core::Download* download, key_type key, mapped_value_type arg) { set_d(download, key, mapped_type(arg)); } void set_std_string(const std::string& key, const std::string& arg) { set(key.c_str(), mapped_type(arg)); }