From 83e993a1ebd1c4720f4e7089103c5e4062e62959 Mon Sep 17 00:00:00 2001 From: rakshasa Date: Sun, 21 Mar 2010 09:45:45 +0000 Subject: [PATCH] * Added missing command_new_slot.{cc,h} files. * Converted more commands. git-svn-id: svn://rakshasa.no/libtorrent/trunk/rtorrent@1150 e378c898-3ddf-0310-93e7-cc216c733640 --- src/command_events.cc | 48 +++++--------- src/command_helpers.h | 58 +++++++++++----- src/command_local.cc | 22 +++---- src/command_network.cc | 35 ++++------ src/command_ui.cc | 102 +++++++++++++---------------- src/rpc/command_new_slot.cc | 97 +++++++++++++++++++++++++++ src/rpc/command_new_slot.h | 120 ++++++++++++++++++++++++++++++++++ test/rpc/command_map_test.cc | 13 +++- test/rpc/command_slot_test.cc | 25 +++++++ test/rpc/command_slot_test.h | 2 + 10 files changed, 380 insertions(+), 142 deletions(-) create mode 100644 src/rpc/command_new_slot.cc create mode 100644 src/rpc/command_new_slot.h diff --git a/src/command_events.cc b/src/command_events.cc index bea02178..d73b2a87 100644 --- a/src/command_events.cc +++ b/src/command_events.cc @@ -179,9 +179,7 @@ apply_remove_untied() { } torrent::Object -apply_schedule(const torrent::Object& rawArgs) { - const torrent::Object::list_type& args = rawArgs.as_list(); - +apply_schedule(const torrent::Object::list_type& args) { if (args.size() != 4) throw torrent::input_error("Wrong number of arguments."); @@ -198,8 +196,7 @@ apply_schedule(const torrent::Object& rawArgs) { } torrent::Object -apply_load(int flags, const torrent::Object& rawArgs) { - const torrent::Object::list_type& args = rawArgs.as_list(); +apply_load(const torrent::Object::list_type& args, int flags) { torrent::Object::list_const_iterator argsItr = args.begin(); if (argsItr == args.end()) @@ -245,8 +242,7 @@ apply_close_low_diskspace(int64_t arg) { } torrent::Object -apply_download_list(const torrent::Object& rawArgs) { - const torrent::Object::list_type& args = rawArgs.as_list(); +apply_download_list(const torrent::Object::list_type& args) { torrent::Object::list_const_iterator argsItr = args.begin(); core::ViewManager* viewManager = control->view_manager(); @@ -273,23 +269,10 @@ apply_download_list(const torrent::Object& rawArgs) { } torrent::Object -d_multicall(const torrent::Object& rawArgs) { - const torrent::Object::list_type& args = rawArgs.as_list(); - +d_multicall(const torrent::Object::list_type& args) { if (args.empty()) throw torrent::input_error("Too few arguments."); -// const torrent::Object::string_type& infoHash = args.begin()->as_string(); - -// core::DownloadList* dList = control->core()->download_list(); -// core::DownloadList::iterator dItr = dList->end(); - -// if (infoHash.size() == 40) -// dItr = dList->find_hex(infoHash.c_str()); - -// if (dItr == dList->end()) -// throw torrent::input_error("Not a valid info-hash."); - core::ViewManager* viewManager = control->view_manager(); core::ViewManager::iterator viewItr; @@ -334,30 +317,29 @@ initialize_command_events() { rpc::commands.call("method.insert", rpc::create_object_list("system.session.use_lock", "bool|const", true)); rpc::commands.call("method.insert", rpc::create_object_list("system.session.on_completion", "bool|const", true)); - ADD_COMMAND_STRING("on_ratio", rak::ptr_fn(&apply_on_ratio)); + CMD2_ANY_STRING("on_ratio", std::tr1::bind(&apply_on_ratio, std::tr1::placeholders::_2)); ADD_COMMAND_VOID("start_tied", &apply_start_tied); ADD_COMMAND_VOID("stop_untied", &apply_stop_untied); ADD_COMMAND_VOID("close_untied", &apply_close_untied); ADD_COMMAND_VOID("remove_untied", &apply_remove_untied); - ADD_COMMAND_LIST("schedule", rak::ptr_fn(&apply_schedule)); + CMD2_ANY_LIST("schedule", std::tr1::bind(&apply_schedule, std::tr1::placeholders::_2)); ADD_COMMAND_STRING_UN("schedule_remove", rak::make_mem_fun(control->command_scheduler(), &rpc::CommandScheduler::erase_str)); ADD_COMMAND_STRING_UN("import", std::ptr_fun(&apply_import)); ADD_COMMAND_STRING_UN("try_import", std::ptr_fun(&apply_try_import)); - ADD_COMMAND_LIST("load", rak::bind_ptr_fn(&apply_load, core::Manager::create_quiet | core::Manager::create_tied)); - ADD_COMMAND_LIST("load_verbose", rak::bind_ptr_fn(&apply_load, core::Manager::create_tied)); - ADD_COMMAND_LIST("load_start", rak::bind_ptr_fn(&apply_load, core::Manager::create_quiet | core::Manager::create_tied | core::Manager::create_start)); - ADD_COMMAND_LIST("load_start_verbose", rak::bind_ptr_fn(&apply_load, core::Manager::create_tied | core::Manager::create_start)); - ADD_COMMAND_LIST("load_raw", rak::bind_ptr_fn(&apply_load, core::Manager::create_quiet | core::Manager::create_raw_data)); - ADD_COMMAND_LIST("load_raw_verbose", rak::bind_ptr_fn(&apply_load, core::Manager::create_raw_data)); - ADD_COMMAND_LIST("load_raw_start", rak::bind_ptr_fn(&apply_load, core::Manager::create_quiet | core::Manager::create_start | core::Manager::create_raw_data)); + CMD2_ANY_LIST("load", std::tr1::bind(&apply_load, std::tr1::placeholders::_2, core::Manager::create_quiet | core::Manager::create_tied)); + CMD2_ANY_LIST("load_verbose", std::tr1::bind(&apply_load, std::tr1::placeholders::_2, core::Manager::create_tied)); + CMD2_ANY_LIST("load_start", std::tr1::bind(&apply_load, std::tr1::placeholders::_2, core::Manager::create_quiet | core::Manager::create_tied | core::Manager::create_start)); + CMD2_ANY_LIST("load_start_verbose", std::tr1::bind(&apply_load, std::tr1::placeholders::_2, core::Manager::create_tied | core::Manager::create_start)); + CMD2_ANY_LIST("load_raw", std::tr1::bind(&apply_load, std::tr1::placeholders::_2, core::Manager::create_quiet | core::Manager::create_raw_data)); + CMD2_ANY_LIST("load_raw_verbose", std::tr1::bind(&apply_load, std::tr1::placeholders::_2, core::Manager::create_raw_data)); + CMD2_ANY_LIST("load_raw_start", std::tr1::bind(&apply_load, std::tr1::placeholders::_2, core::Manager::create_quiet | core::Manager::create_start | core::Manager::create_raw_data)); ADD_COMMAND_VALUE_UN("close_low_diskspace", std::ptr_fun(&apply_close_low_diskspace)); - ADD_COMMAND_LIST("download_list", rak::ptr_fn(&apply_download_list)); - ADD_COMMAND_LIST("d.multicall", rak::ptr_fn(&d_multicall)); - ADD_COMMAND_COPY("call_download", call_list, "i:", ""); + CMD2_ANY_LIST("download_list", std::tr1::bind(&apply_download_list, std::tr1::placeholders::_2)); + CMD2_ANY_LIST("d.multicall", std::tr1::bind(&d_multicall, std::tr1::placeholders::_2)); } diff --git a/src/command_helpers.h b/src/command_helpers.h index ed2a1793..aceab329 100644 --- a/src/command_helpers.h +++ b/src/command_helpers.h @@ -152,9 +152,6 @@ add_variable(key, NULL, NULL, &rpc::CommandVariable::get_string, NULL, std::stri #define ADD_COMMAND_VOID(key, slot) \ ADD_COMMAND_SLOT(key, call_unknown, rpc::object_void_fn(slot), "i:", "") -#define ADD_COMMAND_VALUE(key, slot) \ - ADD_COMMAND_SLOT(key, call_value, slot, "i:i", "") - #define ADD_COMMAND_VALUE_UN(key, slot) \ ADD_COMMAND_SLOT(key, call_value, rpc::object_value_fn(slot), "i:i", "") @@ -164,21 +161,9 @@ add_variable(key, NULL, NULL, &rpc::CommandVariable::get_string, NULL, std::stri #define ADD_COMMAND_STRING_UN(key, slot) \ ADD_COMMAND_SLOT(key, call_string, rpc::object_string_fn(slot), "i:s", "") -#define ADD_COMMAND_LIST(key, slot) \ - ADD_COMMAND_SLOT(key, call_list, slot, "i:", "") - #define ADD_COMMAND_NONE(key, slot) \ ADD_COMMAND_SLOT(key, call_unknown, slot, "i:", "") -#define ADD_ANY_NONE(key, slot) \ - ADD_ANY_SLOT(key, call_unknown, slot, "i:", "") - -#define ADD_ANY_VALUE(key, slot) \ - ADD_ANY_SLOT(key, call_value, slot, "i:i", "") - -#define ADD_ANY_LIST(key, slot) \ - ADD_ANY_SLOT(key, call_list, slot, "i:i", "") - #define ADD_COMMAND_NONE_L(key, slot) \ ADD_COMMAND_SLOT(key, call_unknown, slot, "A:", "") @@ -250,14 +235,51 @@ add_variable(key, NULL, NULL, &rpc::CommandVariable::get_string, NULL, std::stri #define CMD2_A_FUNCTION(key, function, func_type, slot, parm, doc) \ commandNewSlotItr->set_function(slot); \ - m_map.insert_type(key, commandNewSlotItr++, &rpc::function, \ + rpc::commands.insert_type(key, commandNewSlotItr++, &rpc::function, \ rpc::CommandMap::flag_dont_delete | rpc::CommandMap::flag_public_xmlrpc, NULL, NULL); -#define CMD2_A(key, slot) \ +#define CMD2_ANY(key, slot) \ CMD2_A_FUNCTION(key, command_base_call_any, any_function, slot, "i:", "") -#define CMD2_A_STRING(key, slot) \ +#define CMD2_ANY_L(key, slot) \ + CMD2_A_FUNCTION(key, command_base_call_any_list, any_list_function, slot, "A:", "") + +#define CMD2_ANY_VALUE(key, slot) \ + CMD2_A_FUNCTION(key, command_base_call_any_value, any_value_function, slot, "i:i", "") + +#define CMD2_ANY_STRING(key, slot) \ CMD2_A_FUNCTION(key, command_base_call_any_string, any_string_function, slot, "i:s", "") +#define CMD2_ANY_LIST(key, slot) \ + CMD2_A_FUNCTION(key, command_base_call_any_list, any_list_function, slot, "i:", "") + +// +// Conversion of return types: +// + +template +struct object_convert_type; + +template +struct object_convert_type { + + template struct result { + typedef torrent::Object type; + }; + + object_convert_type(Functor s) : m_slot(s) {} + + torrent::Object operator () () { m_slot(); return torrent::Object(); } + template + torrent::Object operator () (Arg1& arg1) { m_slot(arg1); return torrent::Object(); } + template + torrent::Object operator () (Arg1& arg1, Arg2& arg2) { m_slot(arg1, arg2); return torrent::Object(); } + + Functor m_slot; +}; + +template +object_convert_type +object_convert_void(T f) { return f; } #endif diff --git a/src/command_local.cc b/src/command_local.cc index bd4d6d8f..66e1f1c1 100644 --- a/src/command_local.cc +++ b/src/command_local.cc @@ -64,7 +64,7 @@ typedef torrent::ChunkManager CM_t; typedef torrent::FileManager FM_t; torrent::Object -apply_log(int logType, const torrent::Object& rawArgs) { +apply_log(const torrent::Object::string_type& arg, int logType) { if (rpc::execFile.log_fd() != -1) { switch (logType) { case 0: ::close(rpc::execFile.log_fd()); rpc::execFile.set_log_fd(-1); break; @@ -78,8 +78,8 @@ apply_log(int logType, const torrent::Object& rawArgs) { } } - if (rawArgs.is_string() && !rawArgs.as_string().empty()) { - int logFd = open(rak::path_expand(rawArgs.as_string()).c_str(), O_WRONLY | O_APPEND | O_CREAT, 0644); + if (arg.empty()) { + int logFd = open(rak::path_expand(arg).c_str(), O_WRONLY | O_APPEND | O_CREAT, 0644); if (logFd < 0) throw torrent::input_error("Could not open execute log file."); @@ -229,15 +229,15 @@ initialize_command_local() { ADD_COMMAND_STRING_TRI("session", rak::make_mem_fun(dStore, &core::DownloadStore::set_path), rak::make_mem_fun(dStore, &core::DownloadStore::path)); ADD_COMMAND_VOID("session_save", rak::make_mem_fun(dList, &core::DownloadList::session_save)); - ADD_COMMAND_LIST("execute", rak::bind2_mem_fn(&rpc::execFile, &rpc::ExecFile::execute_object, rpc::ExecFile::flag_throw | rpc::ExecFile::flag_expand_tilde)); - ADD_COMMAND_LIST("execute_nothrow", rak::bind2_mem_fn(&rpc::execFile, &rpc::ExecFile::execute_object, rpc::ExecFile::flag_expand_tilde)); - ADD_COMMAND_LIST("execute_raw", rak::bind2_mem_fn(&rpc::execFile, &rpc::ExecFile::execute_object, rpc::ExecFile::flag_throw)); - ADD_COMMAND_LIST("execute_raw_nothrow", rak::bind2_mem_fn(&rpc::execFile, &rpc::ExecFile::execute_object, 0)); - ADD_COMMAND_LIST("execute_capture", rak::bind2_mem_fn(&rpc::execFile, &rpc::ExecFile::execute_object, rpc::ExecFile::flag_throw | rpc::ExecFile::flag_expand_tilde | rpc::ExecFile::flag_capture)); - ADD_COMMAND_LIST("execute_capture_nothrow", rak::bind2_mem_fn(&rpc::execFile, &rpc::ExecFile::execute_object, rpc::ExecFile::flag_expand_tilde | rpc::ExecFile::flag_capture)); + CMD2_ANY("execute", std::tr1::bind(&rpc::ExecFile::execute_object, &rpc::execFile, std::tr1::placeholders::_2, rpc::ExecFile::flag_throw | rpc::ExecFile::flag_expand_tilde)); + CMD2_ANY("execute_nothrow", std::tr1::bind(&rpc::ExecFile::execute_object, &rpc::execFile, std::tr1::placeholders::_2, rpc::ExecFile::flag_expand_tilde)); + CMD2_ANY("execute_raw", std::tr1::bind(&rpc::ExecFile::execute_object, &rpc::execFile, std::tr1::placeholders::_2, rpc::ExecFile::flag_throw)); + CMD2_ANY("execute_raw_nothrow", std::tr1::bind(&rpc::ExecFile::execute_object, &rpc::execFile, std::tr1::placeholders::_2, 0)); + CMD2_ANY("execute_capture", std::tr1::bind(&rpc::ExecFile::execute_object, &rpc::execFile, std::tr1::placeholders::_2, rpc::ExecFile::flag_throw | rpc::ExecFile::flag_expand_tilde | rpc::ExecFile::flag_capture)); + CMD2_ANY("execute_capture_nothrow", std::tr1::bind(&rpc::ExecFile::execute_object, &rpc::execFile, std::tr1::placeholders::_2, rpc::ExecFile::flag_expand_tilde | rpc::ExecFile::flag_capture)); - ADD_COMMAND_STRING("log.execute", rak::bind_ptr_fn(&apply_log, 0)); - ADD_COMMAND_STRING("log.xmlrpc", rak::bind_ptr_fn(&apply_log, 1)); + CMD2_ANY_STRING("log.execute", std::tr1::bind(&apply_log, std::tr1::placeholders::_2, 0)); + CMD2_ANY_STRING("log.xmlrpc", std::tr1::bind(&apply_log, std::tr1::placeholders::_2, 1)); *rpc::Command::argument(0) = "placeholder.0"; *rpc::Command::argument(1) = "placeholder.1"; diff --git a/src/command_network.cc b/src/command_network.cc index 4aa52894..566de2d1 100644 --- a/src/command_network.cc +++ b/src/command_network.cc @@ -63,8 +63,7 @@ #include "command_helpers.h" torrent::Object -apply_throttle(bool up, const torrent::Object& rawArgs) { - const torrent::Object::list_type& args = rawArgs.as_list(); +apply_throttle(const torrent::Object::list_type& args, bool up) { torrent::Object::list_const_iterator argItr = args.begin(); const std::string& name = argItr->as_string(); @@ -100,8 +99,7 @@ static const int throttle_info_max = (1 << 2); static const int throttle_info_rate = (1 << 3); torrent::Object -retrieve_throttle_info(int flags, const torrent::Object& rawArgs) { - const std::string& name = rawArgs.as_string(); +retrieve_throttle_info(const torrent::Object::string_type& name, int flags) { core::ThrottleMap::iterator itr = control->core()->throttles().find(name); torrent::ThrottlePair throttles = itr == control->core()->throttles().end() ? torrent::ThrottlePair(NULL, NULL) : itr->second; torrent::Throttle* throttle = flags & throttle_info_down ? throttles.second : throttles.first; @@ -162,8 +160,7 @@ parse_address_range(const torrent::Object::list_type& args, torrent::Object::lis } torrent::Object -apply_address_throttle(const torrent::Object& rawArgs) { - const torrent::Object::list_type& args = rawArgs.as_list(); +apply_address_throttle(const torrent::Object::list_type& args) { if (args.size() < 2 || args.size() > 3) throw torrent::input_error("Incorrect number of arguments."); @@ -177,9 +174,7 @@ apply_address_throttle(const torrent::Object& rawArgs) { } torrent::Object -apply_encryption(const torrent::Object& rawArgs) { - const torrent::Object::list_type& args = rawArgs.as_list(); - +apply_encryption(const torrent::Object::list_type& args) { uint32_t options_mask = torrent::ConnectionManager::encryption_none; for (torrent::Object::list_const_iterator itr = args.begin(), last = args.end(); itr != last; itr++) { @@ -209,12 +204,10 @@ apply_encryption(const torrent::Object& rawArgs) { } torrent::Object -apply_tos(const torrent::Object& rawArg) { +apply_tos(const torrent::Object::string_type& arg) { rpc::Command::value_type value; torrent::ConnectionManager* cm = torrent::connection_manager(); - const std::string& arg = rawArg.as_string(); - if (arg == "default") value = torrent::ConnectionManager::iptos_default; else if (arg == "lowdelay") @@ -443,18 +436,18 @@ initialize_command_network() { ADD_VARIABLE_VALUE("tracker_numwant", -1); - ADD_COMMAND_LIST("throttle_up", rak::bind_ptr_fn(&apply_throttle, true)); - ADD_COMMAND_LIST("throttle_down", rak::bind_ptr_fn(&apply_throttle, false)); - ADD_COMMAND_LIST("throttle_ip", rak::ptr_fn(&apply_address_throttle)); + CMD2_ANY_LIST("throttle_up", std::tr1::bind(&apply_throttle, std::tr1::placeholders::_2, true)); + CMD2_ANY_LIST("throttle_down", std::tr1::bind(&apply_throttle, std::tr1::placeholders::_2, false)); + CMD2_ANY_LIST("throttle_ip", std::tr1::bind(&apply_address_throttle, std::tr1::placeholders::_2)); - ADD_COMMAND_STRING("get_throttle_up_max", rak::bind_ptr_fn(&retrieve_throttle_info, throttle_info_up | throttle_info_max)); - ADD_COMMAND_STRING("get_throttle_up_rate", rak::bind_ptr_fn(&retrieve_throttle_info, throttle_info_up | throttle_info_rate)); - ADD_COMMAND_STRING("get_throttle_down_max", rak::bind_ptr_fn(&retrieve_throttle_info, throttle_info_down | throttle_info_max)); - ADD_COMMAND_STRING("get_throttle_down_rate", rak::bind_ptr_fn(&retrieve_throttle_info, throttle_info_down | throttle_info_rate)); + CMD2_ANY_STRING("get_throttle_up_max", std::tr1::bind(&retrieve_throttle_info, std::tr1::placeholders::_2, throttle_info_up | throttle_info_max)); + CMD2_ANY_STRING("get_throttle_up_rate", std::tr1::bind(&retrieve_throttle_info, std::tr1::placeholders::_2, throttle_info_up | throttle_info_rate)); + CMD2_ANY_STRING("get_throttle_down_max", std::tr1::bind(&retrieve_throttle_info, std::tr1::placeholders::_2, throttle_info_down | throttle_info_max)); + CMD2_ANY_STRING("get_throttle_down_rate", std::tr1::bind(&retrieve_throttle_info, std::tr1::placeholders::_2, throttle_info_down | throttle_info_rate)); - ADD_COMMAND_LIST("encryption", rak::ptr_fn(&apply_encryption)); + CMD2_ANY_STRING("tos", std::tr1::bind(&apply_tos, std::tr1::placeholders::_2)); - ADD_COMMAND_STRING("tos", rak::ptr_fn(&apply_tos)); + CMD2_ANY_LIST("encryption", std::tr1::bind(&apply_encryption, std::tr1::placeholders::_2)); ADD_COMMAND_STRING_TRI("bind", rak::make_mem_fun(control->core(), &core::Manager::set_bind_address), rak::make_mem_fun(control->core(), &core::Manager::bind_address)); ADD_COMMAND_STRING_TRI("ip", rak::make_mem_fun(control->core(), &core::Manager::set_local_address), rak::make_mem_fun(control->core(), &core::Manager::local_address)); diff --git a/src/command_ui.cc b/src/command_ui.cc index e9e05894..94360d96 100644 --- a/src/command_ui.cc +++ b/src/command_ui.cc @@ -58,9 +58,7 @@ typedef void (core::ViewManager::*view_cfilter_slot)(const std::string&, const std::string&); torrent::Object -apply_view_filter_on(const torrent::Object& rawArgs) { - const torrent::Object::list_type& args = rawArgs.as_list(); - +apply_view_filter_on(const torrent::Object::list_type& args) { if (args.size() < 1) throw torrent::input_error("Too few arguments."); @@ -80,9 +78,7 @@ apply_view_filter_on(const torrent::Object& rawArgs) { } torrent::Object -apply_view_cfilter(view_cfilter_slot viewFilterSlot, const torrent::Object& rawArgs) { - const torrent::Object::list_type& args = rawArgs.as_list(); - +apply_view_cfilter(view_cfilter_slot viewFilterSlot, const torrent::Object::list_type& args) { if (args.size() != 2) throw torrent::input_error("Too few arguments."); @@ -97,9 +93,7 @@ apply_view_cfilter(view_cfilter_slot viewFilterSlot, const torrent::Object& rawA } torrent::Object -apply_view_sort(const torrent::Object& rawArgs) { - const torrent::Object::list_type& args = rawArgs.as_list(); - +apply_view_sort(const torrent::Object::list_type& args) { if (args.size() <= 0 || args.size() > 2) throw torrent::input_error("Wrong argument count."); @@ -119,7 +113,7 @@ apply_view_sort(const torrent::Object& rawArgs) { } torrent::Object -apply_view_list(const torrent::Object&) { +apply_view_list() { torrent::Object rawResult = torrent::Object::create_list(); torrent::Object::list_type& result = rawResult.as_list(); @@ -130,9 +124,7 @@ apply_view_list(const torrent::Object&) { } torrent::Object -apply_view_set(const torrent::Object& rawArgs) { - const torrent::Object::list_type& args = rawArgs.as_list(); - +apply_view_set(const torrent::Object::list_type& args) { if (args.size() != 2) throw torrent::input_error("Wrong argument count."); @@ -212,9 +204,7 @@ apply_or(rpc::target_type target, const torrent::Object& rawArgs) { } torrent::Object -apply_cmp(rpc::target_type target, const torrent::Object& rawArgs) { - const torrent::Object::list_type& args = rawArgs.as_list(); - +apply_cmp(rpc::target_type target, const torrent::Object::list_type& args) { // We only need to check if empty() since if size() == 1 it calls // the same command for both, or if size() == 2 then each side of // the comparison has different commands. @@ -245,23 +235,23 @@ apply_cmp(rpc::target_type target, const torrent::Object& rawArgs) { } } -torrent::Object apply_less(rpc::target_type target, const torrent::Object& rawArgs) { - torrent::Object result = apply_cmp(target, rawArgs); +torrent::Object apply_less(rpc::target_type target, const torrent::Object::list_type& args) { + torrent::Object result = apply_cmp(target, args); return result.is_value() ? result.as_value() < 0 : (int64_t)false; } -torrent::Object apply_greater(rpc::target_type target, const torrent::Object& rawArgs) { - torrent::Object result = apply_cmp(target, rawArgs); +torrent::Object apply_greater(rpc::target_type target, const torrent::Object::list_type& args) { + torrent::Object result = apply_cmp(target, args); return result.is_value() ? result.as_value() > 0 : (int64_t)false; } -torrent::Object apply_equal(rpc::target_type target, const torrent::Object& rawArgs) { - torrent::Object result = apply_cmp(target, rawArgs); +torrent::Object apply_equal(rpc::target_type target, const torrent::Object::list_type& args) { + torrent::Object result = apply_cmp(target, args); return result.is_value() ? result.as_value() == 0 : (int64_t)false; } torrent::Object -apply_to_time(int flags, const torrent::Object& rawArgs) { +apply_to_time(const torrent::Object& rawArgs, int flags) { std::tm *u; time_t t = (uint64_t)rawArgs.as_value(); @@ -349,7 +339,7 @@ apply_to_throttle(const torrent::Object& rawArgs) { // if (cond1) { branch1 } else if (cond2) { branch2 } else { branch3 } // ,,,, torrent::Object -apply_if(int flags, rpc::target_type target, const torrent::Object& rawArgs) { +apply_if(rpc::target_type target, const torrent::Object& rawArgs, int flags) { const torrent::Object::list_type& args = rawArgs.as_list(); torrent::Object::list_const_iterator itr = args.begin(); @@ -472,19 +462,20 @@ void initialize_command_ui() { ADD_VARIABLE_STRING("key_layout", "qwerty"); - ADD_COMMAND_STRING("view_add", rpc::object_string_fn(rak::make_mem_fun(control->view_manager(), &core::ViewManager::insert_throw))); - ADD_COMMAND_NONE_L("view_list", rak::ptr_fn(&apply_view_list)); - ADD_COMMAND_NONE_L("view_set", rak::ptr_fn(&apply_view_set)); + CMD2_ANY_STRING("view_add", object_convert_void(std::tr1::bind(&core::ViewManager::insert_throw, control->view_manager(), std::tr1::placeholders::_2))); - ADD_COMMAND_LIST("view_filter", rak::bind_ptr_fn(&apply_view_cfilter, &core::ViewManager::set_filter)); - ADD_COMMAND_LIST("view_filter_on", rak::ptr_fn(&apply_view_filter_on)); + CMD2_ANY_L("view_list", std::tr1::bind(&apply_view_list)); + CMD2_ANY_LIST("view_set", std::tr1::bind(&apply_view_set, std::tr1::placeholders::_2)); - ADD_COMMAND_LIST("view_sort", rak::ptr_fn(&apply_view_sort)); - ADD_COMMAND_LIST("view_sort_new", rak::bind_ptr_fn(&apply_view_cfilter, &core::ViewManager::set_sort_new)); - ADD_COMMAND_LIST("view_sort_current", rak::bind_ptr_fn(&apply_view_cfilter, &core::ViewManager::set_sort_current)); + CMD2_ANY_LIST("view_filter", std::tr1::bind(&apply_view_cfilter, &core::ViewManager::set_filter, std::tr1::placeholders::_2)); + CMD2_ANY_LIST("view_filter_on", std::tr1::bind(&apply_view_filter_on, std::tr1::placeholders::_2)); - ADD_COMMAND_LIST("view.event_added", rak::bind_ptr_fn(&apply_view_cfilter, &core::ViewManager::set_event_added)); - ADD_COMMAND_LIST("view.event_removed", rak::bind_ptr_fn(&apply_view_cfilter, &core::ViewManager::set_event_removed)); + CMD2_ANY_LIST("view_sort", std::tr1::bind(&apply_view_sort, std::tr1::placeholders::_2)); + CMD2_ANY_LIST("view_sort_new", std::tr1::bind(&apply_view_cfilter, &core::ViewManager::set_sort_new, std::tr1::placeholders::_2)); + CMD2_ANY_LIST("view_sort_current", std::tr1::bind(&apply_view_cfilter, &core::ViewManager::set_sort_current, std::tr1::placeholders::_2)); + + CMD2_ANY_LIST("view.event_added", std::tr1::bind(&apply_view_cfilter, &core::ViewManager::set_event_added, std::tr1::placeholders::_2)); + CMD2_ANY_LIST("view.event_removed", std::tr1::bind(&apply_view_cfilter, &core::ViewManager::set_event_removed, std::tr1::placeholders::_2)); // Cleanup and add . to view. @@ -503,30 +494,29 @@ initialize_command_ui() { CMD_N_STRING("ui.current_view.set", rak::ptr_fn(&cmd_ui_set_view)); // Move. - - ADD_ANY_NONE("print", rak::ptr_fn(&apply_print)); - ADD_ANY_NONE("cat", rak::ptr_fn(&apply_cat)); - ADD_ANY_NONE("if", rak::bind_ptr_fn(&apply_if, 0)); - ADD_ANY_NONE("not", rak::ptr_fn(&apply_not)); - ADD_ANY_NONE("false", rak::ptr_fn(&apply_false)); - ADD_ANY_NONE("and", rak::ptr_fn(&apply_and)); - ADD_ANY_NONE("or", rak::ptr_fn(&apply_or)); - - ADD_ANY_LIST("less", rak::ptr_fn(&apply_less)); - ADD_ANY_LIST("greater", rak::ptr_fn(&apply_greater)); - ADD_ANY_LIST("equal", rak::ptr_fn(&apply_equal)); + CMD2_ANY("print", &apply_print); + CMD2_ANY("cat", &apply_cat); + CMD2_ANY("if", std::tr1::bind(&apply_if, std::tr1::placeholders::_1, std::tr1::placeholders::_2, 0)); + CMD2_ANY("not", &apply_not); + CMD2_ANY("false", &apply_false); + CMD2_ANY("and", &apply_and); + CMD2_ANY("or", &apply_or); // A temporary command for handling stuff until we get proper // support for seperation of commands and literals. - ADD_ANY_NONE("branch", rak::bind_ptr_fn(&apply_if, 1)); + CMD2_ANY("branch", std::tr1::bind(&apply_if, std::tr1::placeholders::_1, std::tr1::placeholders::_2, 1)); - ADD_COMMAND_VALUE("to_gm_time", rak::bind_ptr_fn(&apply_to_time, 0)); - ADD_COMMAND_VALUE("to_gm_date", rak::bind_ptr_fn(&apply_to_time, 0x2)); - ADD_COMMAND_VALUE("to_time", rak::bind_ptr_fn(&apply_to_time, 0x1)); - ADD_COMMAND_VALUE("to_date", rak::bind_ptr_fn(&apply_to_time, 0x1 | 0x2)); - ADD_COMMAND_VALUE("to_elapsed_time", rak::ptr_fn(&apply_to_elapsed_time)); - ADD_COMMAND_VALUE("to_kb", rak::ptr_fn(&apply_to_kb)); - ADD_COMMAND_VALUE("to_mb", rak::ptr_fn(&apply_to_mb)); - ADD_COMMAND_VALUE("to_xb", rak::ptr_fn(&apply_to_xb)); - ADD_COMMAND_VALUE("to_throttle", rak::ptr_fn(&apply_to_throttle)); + CMD2_ANY_LIST("less", &apply_less); + CMD2_ANY_LIST("greater", &apply_greater); + CMD2_ANY_LIST("equal", &apply_equal); + + CMD2_ANY_VALUE("to_gm_time", std::tr1::bind(&apply_to_time, std::tr1::placeholders::_2, 0)); + CMD2_ANY_VALUE("to_gm_date", std::tr1::bind(&apply_to_time, std::tr1::placeholders::_2, 0x2)); + CMD2_ANY_VALUE("to_time", std::tr1::bind(&apply_to_time, std::tr1::placeholders::_2, 0x1)); + CMD2_ANY_VALUE("to_date", std::tr1::bind(&apply_to_time, std::tr1::placeholders::_2, 0x1 | 0x2)); + CMD2_ANY_VALUE("to_elapsed_time", std::tr1::bind(&apply_to_elapsed_time, std::tr1::placeholders::_2)); + CMD2_ANY_VALUE("to_kb", std::tr1::bind(&apply_to_kb, std::tr1::placeholders::_2)); + CMD2_ANY_VALUE("to_mb", std::tr1::bind(&apply_to_mb, std::tr1::placeholders::_2)); + CMD2_ANY_VALUE("to_xb", std::tr1::bind(&apply_to_xb, std::tr1::placeholders::_2)); + CMD2_ANY_VALUE("to_throttle", std::tr1::bind(&apply_to_throttle, std::tr1::placeholders::_2)); } diff --git a/src/rpc/command_new_slot.cc b/src/rpc/command_new_slot.cc new file mode 100644 index 00000000..42699aab --- /dev/null +++ b/src/rpc/command_new_slot.cc @@ -0,0 +1,97 @@ +// rTorrent - BitTorrent client +// Copyright (C) 2005-2007, 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 "core/download.h" +#include "parse.h" + +#include "command_new_slot.h" + +namespace rpc { + +const torrent::Object +command_base_call_any(Command* rawCommand, target_type target, const torrent::Object& args) { + return static_cast(rawCommand)->_pod()(target, args); +} + +const torrent::Object +command_base_call_any_value_base(Command* rawCommand, target_type target, const torrent::Object& rawArgs, int base, int unit) { + const torrent::Object& arg = convert_to_single_argument(rawArgs); + + if (arg.type() == torrent::Object::TYPE_STRING) { + torrent::Object::value_type val; + + if (!parse_whole_value_nothrow(arg.as_string().c_str(), &val, base, unit)) + throw torrent::input_error("Not a value."); + + return static_cast(rawCommand)->_pod()(target, val); + } + + return static_cast(rawCommand)->_pod()(target, arg.as_value()); +} + +const torrent::Object +command_base_call_any_value(Command* rawCommand, target_type target, const torrent::Object& rawArgs) { + return command_base_call_any_value_base(rawCommand, target, rawArgs, 0, 1); +} + + +const torrent::Object +command_base_call_any_string(Command* rawCommand, target_type target, const torrent::Object& rawArgs) { + const torrent::Object& arg = convert_to_single_argument(rawArgs); + + if (arg.type() == torrent::Object::TYPE_RAW_STRING) + return static_cast(rawCommand)->_pod()(target, arg.as_raw_string().as_string()); + + return static_cast(rawCommand)->_pod()(target, arg.as_string()); +} + +const torrent::Object +command_base_call_any_list(Command* rawCommand, target_type target, const torrent::Object& rawArgs) { + if (rawArgs.type() != torrent::Object::TYPE_LIST) { + torrent::Object::list_type arg; + + if (!rawArgs.is_empty()) + arg.push_back(rawArgs); + + return static_cast(rawCommand)->_pod()(target, arg); + } + + return static_cast(rawCommand)->_pod()(target, rawArgs.as_list()); +} + +} diff --git a/src/rpc/command_new_slot.h b/src/rpc/command_new_slot.h new file mode 100644 index 00000000..295e3036 --- /dev/null +++ b/src/rpc/command_new_slot.h @@ -0,0 +1,120 @@ +// rTorrent - BitTorrent client +// Copyright (C) 2005-2007, 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 + +// The command_new_slot object aims at replacing the current crop of +// Command* objects with a new type that is safe to cast from the base +// command type and thus allows for static initialization and fixed +// sized objects. +// +// All commands changed to this new class shall be safe to call with +// the raw object types. + +#ifndef RTORRENT_RPC_COMMAND_NEW_SLOT_H +#define RTORRENT_RPC_COMMAND_NEW_SLOT_H + +#include +#include +#include +#include +#include + +#include "command.h" + +namespace rpc { + +typedef const torrent::Object (*command_base_call_type)(Command*, target_type, const torrent::Object&); +typedef std::tr1::function base_function; + +template struct command_base_is_valid {}; +template struct command_base_is_type {}; + +class command_base : public Command { +public: + command_base() { new (&_pod()) base_function(); } + ~command_base() { _pod().~base_function(); } + + template + void set_function(T s, int value = command_base_is_valid::value) { _pod() = s; } + + // The std::function object in GCC is castable between types with a + // pointer to a struct of ctor/dtor/calls for non-POD slots. As such + // it should be safe to cast between different std::function + // template types, yet what the C++0x standard will say about this I + // have no idea atm. + template tmpl& _pod() { return reinterpret_cast(t_pod); } + +protected: + + union { + char t_pod[sizeof(base_function)]; + }; +}; + +#define COMMAND_BASE_TYPE(func_type, func_parm) \ + typedef std::tr1::function func_type; \ + template <> struct command_base_is_valid { static const int value = 1; }; + +#define COMMAND_BASE_CALL(func_name, func_type) \ + const torrent::Object func_name(Command* rawCommand, target_type target, const torrent::Object& args); \ + template <> struct command_base_is_type { static const int value = 1; }; + +// template <> struct command_base_is_valid { static const int value = 1; }; + +// const torrent::Object command_base_call_any(Command* rawCommand, target_type target, const torrent::Object& args); +// template <> struct command_base_is_type { static const int value = 1; }; + +// +// Declare valid parameters and functions: +// + +// typedef std::tr1::function any_function; +// typedef std::tr1::function any_string_function; + +COMMAND_BASE_TYPE(any_function, torrent::Object (target_type, const torrent::Object&)); +COMMAND_BASE_TYPE(any_value_function, torrent::Object (target_type, const torrent::Object::value_type&)); +COMMAND_BASE_TYPE(any_string_function, torrent::Object (target_type, const std::string&)); +COMMAND_BASE_TYPE(any_list_function, torrent::Object (target_type, const torrent::Object::list_type&)); + +COMMAND_BASE_CALL(command_base_call_any, any_function); +COMMAND_BASE_CALL(command_base_call_any_value, any_value_function); +COMMAND_BASE_CALL(command_base_call_any_string, any_string_function); +COMMAND_BASE_CALL(command_base_call_any_list, any_list_function); + +} + +#endif + + diff --git a/test/rpc/command_map_test.cc b/test/rpc/command_map_test.cc index 89c2ea84..400b53fd 100644 --- a/test/rpc/command_map_test.cc +++ b/test/rpc/command_map_test.cc @@ -7,6 +7,13 @@ CPPUNIT_TEST_SUITE_REGISTRATION(CommandMapTest); +#undef CMD2_A_FUNCTION + +#define CMD2_A_FUNCTION(key, function, func_type, slot, parm, doc) \ + commandNewSlotItr->set_function(slot); \ + m_map.insert_type(key, commandNewSlotItr++, &rpc::function, \ + rpc::CommandMap::flag_dont_delete | rpc::CommandMap::flag_public_xmlrpc, NULL, NULL); + torrent::Object cmd_test_map_a(rpc::target_type t, const torrent::Object& obj) { return obj; } torrent::Object cmd_test_map_b(rpc::target_type t, const torrent::Object& obj, uint64_t c) { return torrent::Object(c); } @@ -14,9 +21,9 @@ torrent::Object cmd_test_any_string(__UNUSED rpc::target_type target, const std: void CommandMapTest::test_basics() { - CMD2_A("test_a", &cmd_test_map_a); - CMD2_A("test_b", std::tr1::bind(&cmd_test_map_b, std::tr1::placeholders::_1, std::tr1::placeholders::_2, (uint64_t)2)); - CMD2_A_STRING("any_string", &cmd_test_any_string); + CMD2_ANY("test_a", &cmd_test_map_a); + CMD2_ANY("test_b", std::tr1::bind(&cmd_test_map_b, std::tr1::placeholders::_1, std::tr1::placeholders::_2, (uint64_t)2)); + CMD2_ANY_STRING("any_string", &cmd_test_any_string); CPPUNIT_ASSERT(m_map.call_command("test_a", (int64_t)1).as_value() == 1); CPPUNIT_ASSERT(m_map.call_command("test_b", (int64_t)1).as_value() == 2); diff --git a/test/rpc/command_slot_test.cc b/test/rpc/command_slot_test.cc index 13f2565a..a360ee4a 100644 --- a/test/rpc/command_slot_test.cc +++ b/test/rpc/command_slot_test.cc @@ -11,6 +11,14 @@ CPPUNIT_TEST_SUITE_REGISTRATION(CommandSlotTest); torrent::Object cmd_test_a(rpc::target_type t, const torrent::Object& obj) { return obj; } torrent::Object cmd_test_b(rpc::target_type t, const torrent::Object& obj, uint64_t c) { return torrent::Object(c); } +torrent::Object cmd_test_list(rpc::target_type t, const torrent::Object::list_type& obj) { return torrent::Object(obj.front()); } + +void cmd_test_convert_void(rpc::target_type t, const torrent::Object& obj) {} +int32_t cmd_test_convert_int32_t(rpc::target_type t, const torrent::Object& obj) { return 9; } +int64_t cmd_test_convert_int64_t(rpc::target_type t, const torrent::Object& obj) { return 10; } +std::string cmd_test_convert_string(rpc::target_type t, const torrent::Object& obj) { return "test_1"; } +const std::string& cmd_test_convert_const_string(rpc::target_type t, const torrent::Object& obj) { static const std::string ret = "test_2"; return ret; } + void CommandSlotTest::test_basics() { rpc::command_base test_any; @@ -19,6 +27,9 @@ CommandSlotTest::test_basics() { test_any.set_function(std::tr1::bind(&cmd_test_b, std::tr1::placeholders::_1, std::tr1::placeholders::_2, (uint64_t)2)); CPPUNIT_ASSERT(rpc::command_base_call_any(&test_any, rpc::make_target(), (int64_t)1).as_value() == 2); + + test_any.set_function(&cmd_test_list); + CPPUNIT_ASSERT(rpc::command_base_call_any_list(&test_any, rpc::make_target(), (int64_t)3).as_value() == 3); } void @@ -26,3 +37,17 @@ CommandSlotTest::test_type_validity() { CPPUNIT_ASSERT((rpc::command_base_is_type::value)); CPPUNIT_ASSERT((rpc::command_base_is_type::value)); } + +void +CommandSlotTest::test_convert_return() { + rpc::command_base test_any; + + test_any.set_function(&cmd_test_convert_string); + CPPUNIT_ASSERT(rpc::command_base_call_any(&test_any, rpc::make_target(), (int64_t)1).as_string() == "test_1"); + + test_any.set_function(&cmd_test_convert_const_string); + CPPUNIT_ASSERT(rpc::command_base_call_any(&test_any, rpc::make_target(), (int64_t)1).as_string() == "test_2"); + +// test_any.set_function(object_convert_void(&cmd_test_convert_void)); +// CPPUNIT_ASSERT(rpc::command_base_call_any(&test_any, rpc::make_target(), (int64_t)1).is_empty()); +} diff --git a/test/rpc/command_slot_test.h b/test/rpc/command_slot_test.h index d8bfd3e6..3af4d4f6 100644 --- a/test/rpc/command_slot_test.h +++ b/test/rpc/command_slot_test.h @@ -6,6 +6,7 @@ class CommandSlotTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(CommandSlotTest); CPPUNIT_TEST(test_basics); CPPUNIT_TEST(test_type_validity); + CPPUNIT_TEST(test_convert_return); CPPUNIT_TEST_SUITE_END(); public: @@ -14,4 +15,5 @@ public: void test_basics(); void test_type_validity(); + void test_convert_return(); };