From 3bd0d6fb27890168f418bc2790e18618985fee03 Mon Sep 17 00:00:00 2001 From: rakshasa Date: Tue, 27 Mar 2007 15:45:18 +0000 Subject: [PATCH] * Allow certain commands, like schedule and on_* to take unquoted multi-arg commands. So "on_start = link1,create_link=tied,,.started" now works again. git-svn-id: svn://rakshasa.no/libtorrent/trunk/rtorrent@879 e378c898-3ddf-0310-93e7-cc216c733640 --- src/option_handler_rules.cc | 12 +++--- src/utils/parse.cc | 73 +++++++++++++++++++++++++++++++++++-- src/utils/parse.h | 3 ++ 3 files changed, 78 insertions(+), 10 deletions(-) diff --git a/src/option_handler_rules.cc b/src/option_handler_rules.cc index bdcb5a52..2e4d0635 100644 --- a/src/option_handler_rules.cc +++ b/src/option_handler_rules.cc @@ -210,7 +210,7 @@ apply_stop_on_ratio(const torrent::Object::list_type& args) { void apply_on_state_change(core::DownloadList::slot_map* slotMap, const torrent::Object::list_type& args) { - if (args.size() != 2) + if (args.size() < 2) throw torrent::input_error("Too few arguments."); if (args.front().as_string().empty()) @@ -221,7 +221,8 @@ apply_on_state_change(core::DownloadList::slot_map* slotMap, const torrent::Obje if (args.back().as_string().empty()) slotMap->erase(key); else - (*slotMap)[key] = sigc::bind(sigc::mem_fun(control->download_variables(), &utils::VariableMap::process_d_std_single), args.back().as_string()); + (*slotMap)[key] = sigc::bind(sigc::mem_fun(control->download_variables(), &utils::VariableMap::process_d_std_single), + utils::convert_list_to_command(++args.begin(), args.end())); } void @@ -406,17 +407,16 @@ apply_try_import(const std::string& path) { void apply_schedule(const torrent::Object::list_type& args) { - if (args.size() != 4) - throw torrent::input_error("Wrong argument count."); + if (args.size() < 4) + throw torrent::input_error("Too few arguments."); torrent::Object::list_type::const_iterator itr = args.begin(); const std::string& arg1 = (itr++)->as_string(); const std::string& arg2 = (itr++)->as_string(); const std::string& arg3 = (itr++)->as_string(); - const std::string& arg4 = (itr++)->as_string(); - control->command_scheduler()->parse(arg1, arg2, arg3, arg4); + control->command_scheduler()->parse(arg1, arg2, arg3, utils::convert_list_to_command(itr, args.end())); } void diff --git a/src/utils/parse.cc b/src/utils/parse.cc index 711738fd..d72d0a7b 100644 --- a/src/utils/parse.cc +++ b/src/utils/parse.cc @@ -184,17 +184,82 @@ convert_list_to_string(const torrent::Object& src) { if (!src.is_list()) throw torrent::internal_error("convert_list_to_string(...) !src->is_list()."); + return convert_list_to_string(src.as_list().begin(), src.as_list().end()); +} + +std::string +convert_list_to_string(torrent::Object::list_type::const_iterator first, + torrent::Object::list_type::const_iterator last) { std::string dest; - for (torrent::Object::list_type::const_iterator itr = src.as_list().begin(), last = src.as_list().end(); itr != last; itr++) { - if (!itr->is_string()) + while (first != last) { + if (!first->is_string()) throw torrent::input_error("Could not convert non-string list element to string."); // Meh. if (!dest.empty()) - dest += ","; + dest += ",\""; + else + dest += '"'; - dest += itr->as_string(); + std::string::size_type quoteItr = dest.size(); + dest += first->as_string(); + + // Finding a quote inside the string should be relatively rare, so + // use something that is fast in the general case and ignore the + // cost of the unusual one. + while (quoteItr != dest.size()) { + if (dest[quoteItr] == '"' || dest[quoteItr] == '\\') + dest.insert(quoteItr++, 1, '\\'); + + quoteItr++; + } + + dest += '"'; + first++; + } + + return dest; +} + +std::string +convert_list_to_command(torrent::Object::list_type::const_iterator first, + torrent::Object::list_type::const_iterator last) { + if (first == last) + throw torrent::input_error("Too few arguments."); + + std::string dest = (first++)->as_string(); + std::string::size_type quoteItr = dest.find('='); + + if (quoteItr == std::string::npos) + throw torrent::input_error("Could not find '=' in command."); + + // We should only escape backslash, not quote here as the string + // will start with the command name which isn't quoted. + while ((quoteItr = dest.find('\\', quoteItr + 1)) != std::string::npos) + dest.insert(quoteItr++, 1, '\\'); + + while (first != last) { + if (!first->is_string()) + throw torrent::input_error("Could not convert non-string list element to string."); + + dest += ",\""; + + std::string::size_type quoteItr = dest.size(); + dest += first->as_string(); + + // Finding a quote inside the string should be relatively rare, so + // use something that is fast in the general case and ignore the + // cost of the unusual one. + while (quoteItr != dest.size()) { + if (dest[quoteItr] == '"' || dest[quoteItr] == '\\') + dest.insert(quoteItr++, 1, '\\'); + + quoteItr++; + } + + dest += '"'; + first++; } return dest; diff --git a/src/utils/parse.h b/src/utils/parse.h index 0b2a9e94..4fb09740 100644 --- a/src/utils/parse.h +++ b/src/utils/parse.h @@ -61,6 +61,9 @@ const char* parse_list(const char* first, const char* last, torrent::Object* des const char* parse_whole_list(const char* first, const char* last, torrent::Object* dest); std::string convert_list_to_string(const torrent::Object& src); +std::string convert_list_to_string(torrent::Object::list_type::const_iterator first, torrent::Object::list_type::const_iterator last); +std::string convert_list_to_command(torrent::Object::list_type::const_iterator first, torrent::Object::list_type::const_iterator last); + int64_t convert_to_value(const torrent::Object& src, int base = 0, int unit = 1); }