diff --git a/configure.ac b/configure.ac index 8fb460e6..23a7d979 100644 --- a/configure.ac +++ b/configure.ac @@ -1,4 +1,4 @@ -AC_INIT(rtorrent, 0.5.0, jaris@ifi.uio.no) +AC_INIT(rtorrent, 0.5.1, jaris@ifi.uio.no) AM_INIT_AUTOMAKE AM_CONFIG_HEADER(config.h) diff --git a/rak/functional_fun.h b/rak/functional_fun.h index c8ba1c5e..2c1c7baa 100644 --- a/rak/functional_fun.h +++ b/rak/functional_fun.h @@ -77,11 +77,12 @@ public: typedef Result result_type; typedef function_base0 base_type; - bool is_valid() const { return m_base.get() != NULL; } + bool is_valid() const { return m_base.get() != NULL; } - void set(base_type* base) { m_base = std::auto_ptr(base); } + void set(base_type* base) { m_base = std::auto_ptr(base); } + base_type* release() { return m_base.release(); } - Result operator () () { return (*m_base)(); } + Result operator () () { return (*m_base)(); } private: std::auto_ptr m_base; @@ -93,16 +94,45 @@ public: typedef Result result_type; typedef function_base1 base_type; - bool is_valid() const { return m_base.get() != NULL; } + bool is_valid() const { return m_base.get() != NULL; } - void set(base_type* base) { m_base = std::auto_ptr(base); } + void set(base_type* base) { m_base = std::auto_ptr(base); } + base_type* release() { return m_base.release(); } - Result operator () (Arg1 arg1) { return (*m_base)(arg1); } + Result operator () (Arg1 arg1) { return (*m_base)(arg1); } private: std::auto_ptr m_base; }; +template +class ptr_fn0_t : public function_base0 { +public: + typedef Result (*Func)(); + + ptr_fn0_t(Func func) : m_func(func) {} + virtual ~ptr_fn0_t() {} + + virtual Result operator () () { return m_func(); } + +private: + Func m_func; +}; + +template +class ptr_fn1_t : public function_base1 { +public: + typedef Result (*Func)(Arg1); + + ptr_fn1_t(Func func) : m_func(func) {} + virtual ~ptr_fn1_t() {} + + virtual Result operator () (Arg1 arg1) { return m_func(arg1); } + +private: + Func m_func; +}; + template class mem_fn0_t : public function_base0 { public: @@ -180,20 +210,6 @@ private: const Arg1 m_arg1; }; -template -class ptr_fn1_t : public function_base1 { -public: - typedef Result (*Func)(Arg1); - - ptr_fn1_t(Func func) : m_func(func) {} - virtual ~ptr_fn1_t() {} - - virtual Result operator () (Arg1 arg1) { return m_func(arg1); } - -private: - Func m_func; -}; - template class ptr_fn0_b1_t : public function_base0 { public: @@ -224,54 +240,137 @@ private: Arg1 m_arg1; }; +template +class value_fn0_t : public function_base0 { +public: + value_fn0_t(const Result& val) : m_value(val) {} + + virtual Result operator () () { return m_value; } + +private: + Result m_value; +}; + +template +class convert_fn0_t : public function_base0 { +public: + typedef function0 src_type; + + convert_fn0_t(typename src_type::base_type* object) { m_object.set(object); } + virtual ~convert_fn0_t() {} + + virtual Result operator () () { + return m_object(); + } + +private: + src_type m_object; +}; + +template +class convert_fn1_t : public function_base1 { +public: + typedef function1 src_type; + + convert_fn1_t(typename src_type::base_type* object) { m_object.set(object); } + virtual ~convert_fn1_t() {} + + virtual Result operator () (Arg1 arg1) { + return m_object(arg1); + } + +private: + src_type m_object; +}; + +template +inline function_base0* +ptr_fn(Result (*func)()) { + return new ptr_fn0_t(func); +} + +template +inline function_base1* +ptr_fn(Result (*func)(Arg1)) { + return new ptr_fn1_t(func); +} + template -function_base0* +inline function_base0* mem_fn(Object* object, Result (Object::*func)()) { return new mem_fn0_t(object, func); } template -function_base1* +inline function_base1* mem_fn(Object* object, Result (Object::*func)(Arg1)) { return new mem_fn1_t(object, func); } template -function_base0* +inline function_base0* mem_fn(const Object* object, Result (Object::*func)() const) { return new const_mem_fn0_t(object, func); } template -function_base1* +inline function_base1* mem_fn(const Object* object, Result (Object::*func)(Arg1) const) { return new const_mem_fn1_t(object, func); } template -function_base0* +inline function_base0* bind_mem_fn(Object* object, Result (Object::*func)(Arg1), const Arg1 arg1) { return new mem_fn0_b1_t(object, func, arg1); } template -function_base1* -ptr_fn(Result (*func)(Arg1)) { - return new ptr_fn1_t(func); -} - -template -function_base0* +inline function_base0* bind_ptr_fn(Result (*func)(Arg1), const Arg1 arg1) { return new ptr_fn0_b1_t(func, arg1); } template -function_base1* +inline function_base1* bind_ptr_fn(Result (*func)(Arg1, Arg2), const Arg1 arg1) { return new ptr_fn1_b1_t(func, arg1); } +template +inline function_base0* +value_fn(const Result& val) { + return new value_fn0_t(val); +} + +template +inline function_base0* +convert_fn(function_base0* src) { + return new convert_fn0_t(src); +} + +// This overload ensures that if we try to convert to the same type, +// it will optimize away the unneeded layer. +template +inline function_base0* +convert_fn(function_base0* src) { + return src; +} + +template +inline function_base1* +convert_fn(function_base1* src) { + return new convert_fn1_t(src); +} + +// This overload ensures that if we try to convert to the same type, +// it will optimize away the unneeded layer. +template +inline function_base1* +convert_fn(function_base1* src) { + return src; +} + } #endif diff --git a/rak/socket_address.h b/rak/socket_address.h index dad2cfa0..0276c4e8 100644 --- a/rak/socket_address.h +++ b/rak/socket_address.h @@ -93,18 +93,21 @@ public: uint32_t length() const; socket_address_inet* sa_inet() { return reinterpret_cast(this); } - socket_address_inet6* sa_inet6() { return reinterpret_cast(this); } - const socket_address_inet* sa_inet() const { return reinterpret_cast(this); } - const socket_address_inet6* sa_inet6() const { return reinterpret_cast(this); } sockaddr* c_sockaddr() { return &m_sa.m_sockaddr; } sockaddr_in* c_sockaddr_inet() { return &m_sa.m_sockaddrInet; } - sockaddr_in6* c_sockaddr_inet6() { return &m_sa.m_sockaddrInet6; } const sockaddr* c_sockaddr() const { return &m_sa.m_sockaddr; } const sockaddr_in* c_sockaddr_inet() const { return &m_sa.m_sockaddrInet; } + +#ifdef RAK_USE_INET6 + socket_address_inet6* sa_inet6() { return reinterpret_cast(this); } + const socket_address_inet6* sa_inet6() const { return reinterpret_cast(this); } + + sockaddr_in6* c_sockaddr_inet6() { return &m_sa.m_sockaddrInet6; } const sockaddr_in6* c_sockaddr_inet6() const { return &m_sa.m_sockaddrInet6; } +#endif // Copy a socket address which has the length 'length. Zero out any // extranous bytes and ensure it does not go beyond the size of this @@ -123,7 +126,9 @@ private: union sa_union { sockaddr m_sockaddr; sockaddr_in m_sockaddrInet; +#ifdef RAK_USE_INET6 sockaddr_in6 m_sockaddrInet6; +#endif }; sa_union m_sa; diff --git a/src/control.cc b/src/control.cc index f660f0ef..c47115ea 100644 --- a/src/control.cc +++ b/src/control.cc @@ -37,6 +37,7 @@ #include "config.h" #include +#include #include #include "core/manager.h" @@ -143,3 +144,10 @@ Control::handle_shutdown() { m_shutdownQuick = true; m_shutdownReceived = false; } + +void +Control::set_umask(mode_t m) { + ::umask(m); + + m_umask = m; +} diff --git a/src/control.h b/src/control.h index dfa5e7cb..66a26136 100644 --- a/src/control.h +++ b/src/control.h @@ -38,6 +38,7 @@ #define RTORRENT_CONTROL_H #include +#include #include #include #include @@ -96,6 +97,9 @@ public: uint64_t tick() const { return m_tick; } void inc_tick() { m_tick++; } + mode_t umask() const { return m_umask; } + void set_umask(mode_t m); + private: Control(const Control&); void operator = (const Control&); @@ -115,6 +119,7 @@ private: display::ClientInfo* m_clientInfo; uint64_t m_tick; + mode_t m_umask; rak::priority_item m_taskShutdown; }; diff --git a/src/core/download.cc b/src/core/download.cc index b6a61aeb..08a7cdff 100644 --- a/src/core/download.cc +++ b/src/core/download.cc @@ -65,28 +65,25 @@ 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::VariableSlotString(rak::mem_fn(this, &Download::connection_current), - rak::mem_fn(this, &Download::set_connection_current))); + 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_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))); m_variables.insert("state", new utils::VariableObject(bencode(), "rtorrent", "state", torrent::Object::TYPE_STRING)); m_variables.insert("tied_to_file", new utils::VariableObject(bencode(), "rtorrent", "tied_to_file", torrent::Object::TYPE_STRING)); - m_variables.insert("directory", new utils::VariableSlotString(rak::mem_fn(&m_fileList, &torrent::FileList::root_dir), - rak::mem_fn(this, &Download::set_root_directory))); + m_variables.insert("directory", new utils::VariableStringSlot(rak::mem_fn(&m_fileList, &torrent::FileList::root_dir), + rak::mem_fn(this, &Download::set_root_directory))); - m_variables.insert("min_peers", new utils::VariableSlotValue(rak::mem_fn(&m_download, &download_type::peers_min), - rak::mem_fn(&m_download, &download_type::set_peers_min), - "%u")); - m_variables.insert("max_peers", new utils::VariableSlotValue(rak::mem_fn(&m_download, &download_type::peers_max), - rak::mem_fn(&m_download, &download_type::set_peers_max), - "%u")); - m_variables.insert("max_uploads", new utils::VariableSlotValue(rak::mem_fn(&m_download, &download_type::uploads_max), - rak::mem_fn(&m_download, &download_type::set_uploads_max), - "%u")); - m_variables.insert("priority", new utils::VariableSlotValue(rak::mem_fn(this, &Download::priority), - rak::mem_fn(this, &Download::set_priority), - "%u")); + m_variables.insert("min_peers", new utils::VariableValueSlot(rak::mem_fn(&m_download, &download_type::peers_min), + rak::mem_fn(&m_download, &download_type::set_peers_min))); + m_variables.insert("max_peers", new utils::VariableValueSlot(rak::mem_fn(&m_download, &download_type::peers_max), + rak::mem_fn(&m_download, &download_type::set_peers_max))); + m_variables.insert("max_uploads", new utils::VariableValueSlot(rak::mem_fn(&m_download, &download_type::uploads_max), + rak::mem_fn(&m_download, &download_type::set_uploads_max))); + m_variables.insert("priority", new utils::VariableValueSlot(rak::mem_fn(this, &Download::priority), + rak::mem_fn(this, &Download::set_priority))); } Download::~Download() { diff --git a/src/core/manager.cc b/src/core/manager.cc index 72c0afe8..8bbeb3ae 100644 --- a/src/core/manager.cc +++ b/src/core/manager.cc @@ -239,6 +239,11 @@ Manager::listen_open() { throw torrent::input_error("Could not open/bind a port for listening: " + std::string(rak::error_number::current().c_str())); } +std::string +Manager::bind_address() const { + return rak::socket_address::cast_from(torrent::connection_manager()->bind_address())->address_str(); +} + void Manager::set_bind_address(const std::string& addr) { int err; @@ -268,6 +273,11 @@ Manager::set_bind_address(const std::string& addr) { } } +std::string +Manager::local_address() const { + return rak::socket_address::cast_from(torrent::connection_manager()->local_address())->address_str(); +} + void Manager::set_local_address(const std::string& addr) { int err; diff --git a/src/core/manager.h b/src/core/manager.h index 35be6945..3371092f 100644 --- a/src/core/manager.h +++ b/src/core/manager.h @@ -78,7 +78,10 @@ public: void listen_open(); + std::string bind_address() const; void set_bind_address(const std::string& addr); + + std::string local_address() const; void set_local_address(const std::string& addr); void shutdown(bool force); diff --git a/src/option_handler_rules.cc b/src/option_handler_rules.cc index 05ec6e61..4d9ccd55 100644 --- a/src/option_handler_rules.cc +++ b/src/option_handler_rules.cc @@ -63,11 +63,6 @@ #include "option_handler_rules.h" #include "command_scheduler.h" -void -apply_umask(int arg) { - umask(arg); -} - void apply_working_directory(const std::string& path) { if (chdir(path.c_str()) != 0) @@ -209,7 +204,8 @@ initialize_option_handler(Control* c) { variables->insert("tracker_dump", new utils::VariableAny(std::string())); - variables->insert("session", new utils::VariableSlotString<>(NULL, rak::mem_fn(&control->core()->download_store(), &core::DownloadStore::set_path))); + variables->insert("session", new utils::VariableStringSlot(rak::mem_fn(&control->core()->download_store(), &core::DownloadStore::path), + rak::mem_fn(&control->core()->download_store(), &core::DownloadStore::set_path))); variables->insert("session_lock", new utils::VariableAny("yes")); variables->insert("session_on_completion", new utils::VariableAny("yes")); @@ -217,52 +213,59 @@ initialize_option_handler(Control* c) { variables->insert("connection_seed", new utils::VariableAny("seed")); variables->insert("directory", new utils::VariableAny("./")); - variables->insert("working_directory", new utils::VariableSlotString<>(NULL, rak::ptr_fn(&apply_working_directory))); - variables->insert("bind", new utils::VariableSlotString<>(NULL, rak::mem_fn(control->core(), &core::Manager::set_bind_address))); - variables->insert("ip", new utils::VariableSlotString<>(NULL, rak::mem_fn(control->core(), &core::Manager::set_local_address))); - variables->insert("tos", new utils::VariableSlotString<>(NULL, rak::ptr_fn(&apply_tos))); + variables->insert("working_directory", new utils::VariableStringSlot(rak::value_fn(std::string()), rak::ptr_fn(&apply_working_directory))); + variables->insert("tos", new utils::VariableStringSlot(rak::value_fn(std::string()), rak::ptr_fn(&apply_tos))); + + variables->insert("bind", new utils::VariableStringSlot(rak::mem_fn(control->core(), &core::Manager::bind_address), + rak::mem_fn(control->core(), &core::Manager::set_bind_address))); + variables->insert("ip", new utils::VariableStringSlot(rak::mem_fn(control->core(), &core::Manager::local_address), + rak::mem_fn(control->core(), &core::Manager::set_local_address))); variables->insert("min_peers", new utils::VariableValue(40)); variables->insert("max_peers", new utils::VariableValue(100)); variables->insert("max_uploads", new utils::VariableValue(15)); - variables->insert("download_rate", new utils::VariableSlotValue(NULL, rak::mem_fn(control->ui(), &ui::Root::set_down_throttle), "%i")); - variables->insert("upload_rate", new utils::VariableSlotValue(NULL, rak::mem_fn(control->ui(), &ui::Root::set_up_throttle), "%i")); + variables->insert("download_rate", new utils::VariableValueSlot(rak::ptr_fn(&torrent::down_throttle), rak::mem_fn(control->ui(), &ui::Root::set_down_throttle_i64), + 0, (1 << 10))); + variables->insert("upload_rate", new utils::VariableValueSlot(rak::ptr_fn(&torrent::up_throttle), rak::mem_fn(control->ui(), &ui::Root::set_up_throttle_i64), + 0, (1 << 10))); - variables->insert("hash_max_tries", new utils::VariableSlotValue(NULL, rak::ptr_fn(&torrent::set_hash_max_tries), "%i")); - variables->insert("max_open_files", new utils::VariableSlotValue(NULL, rak::ptr_fn(&torrent::set_max_open_files), "%i")); - variables->insert("max_open_sockets", new utils::VariableSlotValue(NULL, rak::ptr_fn(&torrent::set_max_open_sockets), "%i")); + variables->insert("hash_max_tries", new utils::VariableValueSlot(rak::ptr_fn(&torrent::hash_max_tries), rak::ptr_fn(&torrent::set_hash_max_tries))); + variables->insert("max_open_files", new utils::VariableValueSlot(rak::ptr_fn(&torrent::max_open_files), rak::ptr_fn(&torrent::set_max_open_files))); + variables->insert("max_open_sockets", new utils::VariableValueSlot(rak::ptr_fn(&torrent::max_open_sockets), rak::ptr_fn(&torrent::set_max_open_sockets))); - variables->insert("print", new utils::VariableSlotString<>(NULL, rak::mem_fn(control->core(), &core::Manager::push_log))); - variables->insert("import", new utils::VariableSlotString<>(NULL, rak::mem_fn(control->variable(), &utils::VariableMap::process_file_throw))); - variables->insert("try_import", new utils::VariableSlotString<>(NULL, rak::mem_fn(control->variable(), &utils::VariableMap::process_file_nothrow))); + variables->insert("print", new utils::VariableStringSlot(rak::value_fn(std::string()), + rak::mem_fn(control->core(), &core::Manager::push_log))); + variables->insert("import", new utils::VariableStringSlot(rak::value_fn(std::string()), + rak::mem_fn(control->variable(), &utils::VariableMap::process_file_throw))); + variables->insert("try_import", new utils::VariableStringSlot(rak::value_fn(std::string()), + rak::mem_fn(control->variable(), &utils::VariableMap::process_file_nothrow))); - variables->insert("schedule", new utils::VariableSlotString<>(NULL, rak::mem_fn(c->command_scheduler(), &CommandScheduler::parse))); - variables->insert("schedule_remove", new utils::VariableSlotString<>(NULL, rak::mem_fn(c->command_scheduler(), &CommandScheduler::erase))); + variables->insert("schedule", new utils::VariableStringSlot(rak::value_fn(std::string()), + rak::mem_fn(c->command_scheduler(), &CommandScheduler::parse))); + variables->insert("schedule_remove", new utils::VariableStringSlot(rak::value_fn(std::string()), + rak::mem_fn(c->command_scheduler(), &CommandScheduler::erase))); - variables->insert("send_buffer_size", new utils::VariableSlotValue(NULL, rak::mem_fn(torrent::connection_manager(), - &torrent::ConnectionManager::set_send_buffer_size), "%u")); + variables->insert("send_buffer_size", new utils::VariableValueSlot(rak::mem_fn(torrent::connection_manager(), &torrent::ConnectionManager::send_buffer_size), + rak::mem_fn(torrent::connection_manager(), &torrent::ConnectionManager::set_send_buffer_size))); - variables->insert("receive_buffer_size", new utils::VariableSlotValue(NULL, rak::mem_fn(torrent::connection_manager(), - &torrent::ConnectionManager::set_receive_buffer_size), "%u")); + variables->insert("receive_buffer_size", new utils::VariableValueSlot(rak::mem_fn(torrent::connection_manager(), &torrent::ConnectionManager::receive_buffer_size), + rak::mem_fn(torrent::connection_manager(), &torrent::ConnectionManager::set_receive_buffer_size))); - // Old. - variables->insert("port_range", new utils::VariableSlotString<>(NULL, rak::bind_ptr_fn(&apply_port_range, c))); + variables->insert("port_range", new utils::VariableStringSlot(rak::value_fn(std::string()), rak::bind_ptr_fn(&apply_port_range, c))); - variables->insert("hash_read_ahead", new utils::VariableSlotValue(NULL, rak::bind_ptr_fn(&apply_hash_read_ahead, c), "%i")); - variables->insert("hash_interval", new utils::VariableSlotValue(NULL, rak::bind_ptr_fn(&apply_hash_interval, c), "%i")); + variables->insert("hash_read_ahead", new utils::VariableValueSlot(rak::ptr_fn(torrent::hash_read_ahead), rak::bind_ptr_fn(&apply_hash_read_ahead, c))); + variables->insert("hash_interval", new utils::VariableValueSlot(rak::ptr_fn(torrent::hash_interval), rak::bind_ptr_fn(&apply_hash_interval, c))); - variables->insert("umask", new utils::VariableSlotValue(NULL, rak::ptr_fn(&apply_umask), "%o")); + variables->insert("umask", new utils::VariableValueSlot(rak::mem_fn(control, &Control::umask), rak::mem_fn(control, &Control::set_umask), 8)); - variables->insert("load", new utils::VariableSlotString<>(NULL, rak::bind_ptr_fn(&apply_load, c))); - variables->insert("load_start", new utils::VariableSlotString<>(NULL, rak::bind_ptr_fn(&apply_load_start, c))); - variables->insert("stop_untied", new utils::VariableSlotString<>(NULL, rak::bind_ptr_fn(&apply_stop_untied, c))); - variables->insert("remove_untied", new utils::VariableSlotString<>(NULL, rak::bind_ptr_fn(&apply_remove_untied, c))); + variables->insert("load", new utils::VariableStringSlot(rak::value_fn(std::string()), rak::bind_ptr_fn(&apply_load, c))); + variables->insert("load_start", new utils::VariableStringSlot(rak::value_fn(std::string()), rak::bind_ptr_fn(&apply_load_start, c))); + variables->insert("stop_untied", new utils::VariableStringSlot(rak::value_fn(std::string()), rak::bind_ptr_fn(&apply_stop_untied, c))); + variables->insert("remove_untied", new utils::VariableStringSlot(rak::value_fn(std::string()), rak::bind_ptr_fn(&apply_remove_untied, c))); - variables->insert("enable_trackers", new utils::VariableSlotString<>(NULL, rak::bind_ptr_fn(&apply_enable_trackers, c))); - - variables->insert("encoding_list", new utils::VariableSlotString<>(NULL, rak::bind_ptr_fn(&apply_encoding_list, c))); - - variables->insert("http_proxy", new utils::VariableSlotString<>(NULL, rak::bind_ptr_fn(&apply_http_proxy, c))); + 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))); + variables->insert("http_proxy", new utils::VariableStringSlot(rak::value_fn(std::string()), rak::bind_ptr_fn(&apply_http_proxy, c))); } diff --git a/src/ui/root.h b/src/ui/root.h index aac6906b..7f5ce4c5 100644 --- a/src/ui/root.h +++ b/src/ui/root.h @@ -37,6 +37,7 @@ #ifndef RTORRENT_UI_ROOT_H #define RTORRENT_UI_ROOT_H +#include #include "input/bindings.h" class Control; @@ -63,6 +64,10 @@ public: void set_down_throttle(unsigned int throttle); void set_up_throttle(unsigned int throttle); + // Rename to raw or something, make base function. + void set_down_throttle_i64(int64_t throttle) { set_down_throttle(throttle >> 10); } + void set_up_throttle_i64(int64_t throttle) { set_up_throttle(throttle >> 10); } + void adjust_down_throttle(int throttle); void adjust_up_throttle(int throttle); diff --git a/src/utils/Makefile.am b/src/utils/Makefile.am index 88b80a6b..07f5b5fb 100644 --- a/src/utils/Makefile.am +++ b/src/utils/Makefile.am @@ -6,6 +6,7 @@ libsub_utils_a_SOURCES = \ list_focus.h \ lockfile.cc \ lockfile.h \ + variable.cc \ variable.h \ variable_generic.cc \ variable_generic.h \ diff --git a/src/utils/variable.cc b/src/utils/variable.cc new file mode 100644 index 00000000..c3e534a5 --- /dev/null +++ b/src/utils/variable.cc @@ -0,0 +1,92 @@ +// rTorrent - BitTorrent client +// Copyright (C) 2006, Jari Sundell +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// In addition, as a special exception, the copyright holders give +// permission to link the code of portions of this program with the +// OpenSSL library under certain conditions as described in each +// individual source file, and distribute linked combinations +// including the two. +// +// You must obey the GNU General Public License in all respects for +// all of the code used other than OpenSSL. If you modify file(s) +// with this exception, you may extend this exception to your version +// of the file(s), but you are not obligated to do so. If you do not +// wish to do so, delete this exception statement from your version. +// If you delete this exception statement from all source files in the +// program, then also delete it here. +// +// Contact: Jari Sundell +// +// Skomakerveien 33 +// 3185 Skoppum, NORWAY + +#include "config.h" + +#include + +#include "variable.h" + +namespace utils { + +const torrent::Object Variable::m_emptyObject; + +const char* +Variable::string_to_value_unit(const char* pos, value_type* value, int base, int unit) { + char* last; + + *value = strtoll(pos, &last, base); + + if (last == pos) + throw torrent::input_error("Could not convert string to value."); + + switch (*last) { + case 'b': + case 'B': + ++last; + break; + + case 'k': + case 'K': + *value = *value << 10; + ++last; + break; + + case 'm': + case 'M': + *value = *value << 20; + ++last; + break; + + case 'g': + case 'G': + *value = *value << 30; + ++last; + break; + + case ' ': + case '\0': + *value = *value * unit; + break; + + default: + throw torrent::input_error("Could not parse value."); + } + + return last; +} + +} diff --git a/src/utils/variable.h b/src/utils/variable.h index 5ecc241f..dfd3f37b 100644 --- a/src/utils/variable.h +++ b/src/utils/variable.h @@ -37,25 +37,33 @@ #ifndef RTORRENT_UTILS_VARIABLE_H #define RTORRENT_UTILS_VARIABLE_H -#include - -namespace torrent { - class Object; -} +#include namespace utils { class Variable { public: + typedef torrent::Object::value_type value_type; + typedef torrent::Object::string_type string_type; + typedef torrent::Object::list_type list_type; + typedef torrent::Object::map_type map_type; + typedef torrent::Object::key_type key_type; + Variable() {} virtual ~Variable() {} virtual const torrent::Object& get() = 0; - virtual void set(const torrent::Object& arg) = 0; + virtual void set(const torrent::Object& arg) = 0; protected: Variable(const Variable&); void operator = (const Variable&); + + static const char* string_to_value_unit(const char* pos, value_type* value, int base, int unit); + + // Temporary hack, until torrent::Object is extended to allow + // references so we can return a copy, not a const reference. + static const torrent::Object m_emptyObject; }; } diff --git a/src/utils/variable_generic.cc b/src/utils/variable_generic.cc index 8ea2478c..91c1b325 100644 --- a/src/utils/variable_generic.cc +++ b/src/utils/variable_generic.cc @@ -163,4 +163,58 @@ VariableObject::set(const torrent::Object& arg) { } } +// +// New and prettified. +// + +const torrent::Object& +VariableValueSlot::get() { + m_cache = m_slotGet() / m_unit; + + return m_cache; +} + +void +VariableValueSlot::set(const torrent::Object& arg) { + value_type value; + + switch (arg.type()) { + case torrent::Object::TYPE_STRING: + string_to_value_unit(arg.as_string().c_str(), &value, m_base, m_unit); + + // Check if we hit the end of the input. + + m_slotSet(value); + break; + + case torrent::Object::TYPE_VALUE: + m_slotSet(arg.as_value()); + break; + + default: + throw torrent::input_error("Not a value"); + } +} + +const torrent::Object& +VariableStringSlot::get() { + m_cache = m_slotGet(); + + return m_cache; +} + +void +VariableStringSlot::set(const torrent::Object& arg) { + 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."); + } +} + } diff --git a/src/utils/variable_generic.h b/src/utils/variable_generic.h index f5e164a4..40c66f43 100644 --- a/src/utils/variable_generic.h +++ b/src/utils/variable_generic.h @@ -111,111 +111,69 @@ private: Type m_type; }; -template -class VariableSlotString : public Variable { +// +// New and pretty. +// + +class VariableValueSlot : public Variable { public: - typedef rak::function0 SlotGet; - typedef rak::function1 SlotSet; + typedef rak::function0 slot_get_type; + typedef rak::function1 slot_set_type; + typedef std::pair range_type; - VariableSlotString(typename SlotGet::base_type* slotGet, typename SlotSet::base_type* slotSet) { - m_slotGet.set(slotGet); - m_slotSet.set(slotSet); + template + VariableValueSlot(SlotGet* slotGet, SlotSet* slotSet, unsigned int base = 0, unsigned int unit = 1, + range_type range = range_type(std::numeric_limits::min(), std::numeric_limits::max())) : + m_base(base), + m_unit(unit), + m_range(range) { + + m_slotGet.set(rak::convert_fn(slotGet)); + m_slotSet.set(rak::convert_fn(slotSet)); } - virtual ~VariableSlotString() {} - - virtual const torrent::Object& get() { - m_cache = m_slotGet(); - - if (!m_cache.is_string()) - throw torrent::internal_error("VariableSlotString::get() got wrong type."); - - return m_cache; - } - - virtual void set(const torrent::Object& arg) { - switch (arg.type()) { - case torrent::Object::TYPE_STRING: - m_slotSet(arg.as_string()); - break; - case torrent::Object::TYPE_NONE: - m_slotSet(""); - break; - default: - throw torrent::internal_error("VariableSlotString::set(...) got wrong type."); - } - } + virtual const torrent::Object& get(); + virtual void set(const torrent::Object& arg); private: - SlotGet m_slotGet; - SlotSet m_slotSet; + slot_get_type m_slotGet; + slot_set_type m_slotSet; + + unsigned int m_base; + unsigned int m_unit; + range_type m_range; // Store the cache here to avoid unnessesary copying and such. This // should not result in any unresonable memory usage since few // strings will be very large. - torrent::Object m_cache; + torrent::Object m_cache; }; -template -class VariableSlotValue : public Variable { +class VariableStringSlot : public Variable { public: - typedef rak::function0 SlotGet; - typedef rak::function1 SlotSet; - typedef std::pair Range; + typedef rak::function0 slot_get_type; + typedef rak::function1 slot_set_type; - VariableSlotValue(typename SlotGet::base_type* slotGet, - typename SlotSet::base_type* slotSet, - const char* pattern, - Range range = Range(std::numeric_limits::min(), - std::numeric_limits::max())) { - m_slotGet.set(slotGet); - m_slotSet.set(slotSet); - m_pattern = pattern; - m_range = range; + template + VariableStringSlot(SlotGet* slotGet, SlotSet* slotSet) { + m_slotGet.set(rak::convert_fn(slotGet)); + m_slotSet.set(rak::convert_fn(slotSet)); } - virtual ~VariableSlotValue() {} - - virtual const torrent::Object& get() { - m_cache = m_slotGet(); - - // Need this? - if (!m_cache.is_value()) - throw torrent::internal_error("VariableSlotValue::get() got wrong type."); - - return m_cache; - } - - virtual void set(const torrent::Object& arg) { - if (arg.is_string()) { - Set v; - - if (std::sscanf(arg.as_string().c_str(), m_pattern, &v) != 1) - throw torrent::input_error("Not a value."); - - m_slotSet(v); - - } else if (arg.is_value()) { - m_slotSet(arg.as_value()); - - } else { - throw torrent::input_error("Not a value"); - } - } + virtual const torrent::Object& get(); + virtual void set(const torrent::Object& arg); private: - SlotGet m_slotGet; - SlotSet m_slotSet; - - const char* m_pattern; - Range m_range; + slot_get_type m_slotGet; + slot_set_type m_slotSet; // Store the cache here to avoid unnessesary copying and such. This // should not result in any unresonable memory usage since few // strings will be very large. - torrent::Object m_cache; + torrent::Object m_cache; }; + } #endif