diff --git a/src/control.cc b/src/control.cc index 01b442b6..bcdd8d3a 100644 --- a/src/control.cc +++ b/src/control.cc @@ -79,7 +79,7 @@ Control::Control() : m_taskShutdown.set_slot(rak::mem_fn(this, &Control::handle_shutdown)); - m_commandScheduler->set_slot_command(rak::mem_fn(m_variables, &utils::VariableMap::process_command)); + m_commandScheduler->set_slot_command(rak::mem_fn(m_variables, &utils::VariableMap::process_std_single)); m_commandScheduler->set_slot_error_message(rak::mem_fn(m_core, &core::Manager::push_log)); } diff --git a/src/main.cc b/src/main.cc index 0350a7e8..a3f687c1 100644 --- a/src/main.cc +++ b/src/main.cc @@ -87,7 +87,7 @@ parse_options(Control* c, int argc, char** argv) { optionParser.insert_option('p', sigc::bind<0>(sigc::mem_fun(c->variable(), &utils::VariableMap::set_string), "port_range")); optionParser.insert_option('s', sigc::bind<0>(sigc::mem_fun(c->variable(), &utils::VariableMap::set_string), "session")); - optionParser.insert_option('O', sigc::mem_fun(c->variable(), &utils::VariableMap::process_command)); + optionParser.insert_option('O', sigc::mem_fun(c->variable(), &utils::VariableMap::process_std_single)); optionParser.insert_option_list('o', sigc::mem_fun(c->variable(), &utils::VariableMap::set_std_string)); return optionParser.process(argc, argv); @@ -165,66 +165,68 @@ main(int argc, char** argv) { // torrent::ConnectionManager* is valid etc. initialize_option_handler(control); - // Currently not doing any sorting on main. - control->variable()->process_command("view_add = main"); - //control->variable()->process_command("view_sort_current = name,started,name"); + control->variable()->process_multiple + ( + // Currently not doing any sorting on main. + "view_add = main\n" - control->variable()->process_command("view_add = name"); - control->variable()->process_command("view_sort_new = name,name"); - control->variable()->process_command("view_sort_current = name,name"); + "view_add = name\n" + "view_sort_new = name,name\n" + "view_sort_current = name,name\n" - control->variable()->process_command("view_add = started"); - control->variable()->process_command("view_filter = started,started"); - control->variable()->process_command("view_filter_on = started,start,stop"); - control->variable()->process_command("view_sort_new = started,name"); - control->variable()->process_command("view_sort_current = started,name"); + "view_add = started\n" + "view_filter = started,started\n" + "view_filter_on = started,start,stop\n" + "view_sort_new = started,name\n" + "view_sort_current = started,name\n" - control->variable()->process_command("view_add = stopped"); - control->variable()->process_command("view_filter = stopped,stopped"); - control->variable()->process_command("view_filter_on = stopped,start,stop"); - control->variable()->process_command("view_sort_new = stopped,name"); - control->variable()->process_command("view_sort_current = stopped,name"); + "view_add = stopped\n" + "view_filter = stopped,stopped\n" + "view_filter_on = stopped,start,stop\n" + "view_sort_new = stopped,name\n" + "view_sort_current = stopped,name\n" - control->variable()->process_command("view_add = complete"); - control->variable()->process_command("view_filter = complete,complete"); - control->variable()->process_command("view_filter_on = complete,hash_done,finished"); - control->variable()->process_command("view_sort_new = complete,state_changed"); - control->variable()->process_command("view_sort_current = complete,state_changed_reverse"); + "view_add = complete\n" + "view_filter = complete,complete\n" + "view_filter_on = complete,hash_done,finished\n" + "view_sort_new = complete,state_changed\n" + "view_sort_current = complete,state_changed_reverse\n" - control->variable()->process_command("view_add = incomplete"); - control->variable()->process_command("view_filter = incomplete,incomplete"); - control->variable()->process_command("view_filter_on = incomplete,hash_done,finished"); - control->variable()->process_command("view_sort_new = incomplete,state_changed"); - control->variable()->process_command("view_sort_current = incomplete,state_changed_reverse"); + "view_add = incomplete\n" + "view_filter = incomplete,incomplete\n" + "view_filter_on = incomplete,hash_done,finished\n" + "view_sort_new = incomplete,state_changed\n" + "view_sort_current = incomplete,state_changed_reverse\n" - // The hashing view does not include stopped torrents. - control->variable()->process_command("view_add = hashing"); - control->variable()->process_command("view_filter = hashing,hashing"); - control->variable()->process_command("view_filter_on = hashing,hash_queued,hash_removed,hash_done"); - control->variable()->process_command("view_sort_new = hashing,state_changed"); - control->variable()->process_command("view_sort_current = hashing,state_changed"); + // The hashing view does not include stopped torrents. + "view_add = hashing\n" + "view_filter = hashing,hashing\n" + "view_filter_on = hashing,hash_queued,hash_removed,hash_done\n" + "view_sort_new = hashing,state_changed\n" + "view_sort_current = hashing,state_changed\n" - control->variable()->process_command("schedule = view_main,10,10,view_sort=main,20"); - control->variable()->process_command("schedule = view_name,10,10,view_sort=name,20"); -// control->variable()->process_command("schedule = view_started,10,10,view_sort=started,5"); -// control->variable()->process_command("schedule = view_stopped,10,10,view_sort=stopped,5"); -// control->variable()->process_command("schedule = view_complete,10,10,view_sort=complete,5"); -// control->variable()->process_command("schedule = view_incomplete,10,10,view_sort=incomplete,5"); + "schedule = view_main,10,10,view_sort=main,20\n" + "schedule = view_name,10,10,view_sort=name,20\n" + // "schedule = view_started,10,10,view_sort=started,5\n" + // "schedule = view_stopped,10,10,view_sort=stopped,5\n" + // "schedule = view_complete,10,10,view_sort=complete,5\n" + // "schedule = view_incomplete,10,10,view_sort=incomplete,5\n" - //control->variable()->process_command("schedule = scheduler,10,10,download_scheduler="); - control->variable()->process_command("schedule = session_save,1800,1800,session_save="); + //"schedule = scheduler,10,10,download_scheduler=\n" + "schedule = session_save,1800,1800,session_save=\n" - // Changing these will bork the (non-existant) scheduler. - control->variable()->process_command("view_add = scheduler"); - control->variable()->process_command("view_sort_new = scheduler,state_changed"); // add started? - control->variable()->process_command("view_sort_current = scheduler,state_changed"); + // Changing these will bork the (non-existant) scheduler. + "view_add = scheduler\n" + "view_sort_new = scheduler,state_changed\n" // add started? + "view_sort_current = scheduler,state_changed\n" - // control->variable()->process_command("schedule = scheduler,10,10,download_scheduler="); + // "schedule = scheduler,10,10,download_scheduler=\n" + ); if (OptionParser::has_flag('n', argc, argv)) control->core()->push_log("Ignoring ~/.rtorrent.rc."); else - control->variable()->process_command("try_import = ~/.rtorrent.rc"); + control->variable()->process_single("try_import = ~/.rtorrent.rc"); int firstArg = parse_options(control, argc, argv); diff --git a/src/ui/download_list.cc b/src/ui/download_list.cc index 8e7b3e49..c8be083d 100644 --- a/src/ui/download_list.cc +++ b/src/ui/download_list.cc @@ -288,7 +288,7 @@ DownloadList::receive_exit_input(Input type) { break; case INPUT_COMMAND: - control->variable()->process_command(input->str()); + control->variable()->process_std_single(input->str()); break; default: diff --git a/src/utils/variable_map.cc b/src/utils/variable_map.cc index 480c14a9..2aabbeaa 100644 --- a/src/utils/variable_map.cc +++ b/src/utils/variable_map.cc @@ -92,8 +92,15 @@ struct variable_map_is_space : std::unary_function { } }; -std::string::const_iterator -parse_name(std::string::const_iterator first, std::string::const_iterator last, std::string* dest) { +struct variable_map_is_newline : std::unary_function { + bool operator () (char c) const { + return c == '\n' || c == '\0'; + } +}; + +// Use a static length buffer for dest. +const char* +parse_name(const char* first, const char* last, std::string* dest) { if (first == last || !std::isalpha(*first)) throw torrent::input_error("Invalid start of name."); @@ -103,10 +110,10 @@ parse_name(std::string::const_iterator first, std::string::const_iterator last, return first; } -std::string::const_iterator -parse_unknown(std::string::const_iterator first, std::string::const_iterator last, VariableMap::mapped_type* dest) { +const char* +parse_unknown(const char* first, const char* last, VariableMap::mapped_type* dest) { if (*first == '"') { - std::string::const_iterator next = std::find_if(++first, last, std::bind2nd(std::equal_to(), '"')); + const char* next = std::find_if(++first, last, std::bind2nd(std::equal_to(), '"')); if (first == last || first == next || next == last) throw torrent::input_error("Could not find closing '\"'."); @@ -116,15 +123,15 @@ parse_unknown(std::string::const_iterator first, std::string::const_iterator las } else { // Add rak::or and check for ','. - std::string::const_iterator next = std::find_if(first, last, variable_map_is_space()); + const char* next = std::find_if(first, last, variable_map_is_space()); *dest = std::string(first, next); return next; } } -std::string::const_iterator -parse_args(std::string::const_iterator first, std::string::const_iterator last, VariableMap::mapped_type::list_type* dest) { +const char* +parse_args(const char* first, const char* last, VariableMap::mapped_type::list_type* dest) { first = std::find_if(first, last, std::not1(variable_map_is_space())); while (first != last) { @@ -140,24 +147,29 @@ parse_args(std::string::const_iterator first, std::string::const_iterator last, return first; } -void -VariableMap::process_command(const std::string& command) { - std::string::const_iterator pos = command.begin(); - pos = std::find_if(pos, command.end(), std::not1(variable_map_is_space())); +const char* +VariableMap::process_single(const char* first) { + // This could be optimized, but dunno if there's any point in doing + // it. + return process_single(first, first + std::strlen(first)); +} - if (pos == command.end() || *pos == '#') - return; +const char* +VariableMap::process_single(const char* first, const char* last) { + first = std::find_if(first, last, std::not1(variable_map_is_space())); - // Replace with parse_unknown? - std::string key; - pos = parse_name(pos, command.end(), &key); - pos = std::find_if(pos, command.end(), std::not1(variable_map_is_space())); + if (first == last || *first == '#') + return last; - if (pos == command.end() || *pos != '=') + std::string key; + first = parse_name(first, last, &key); + first = std::find_if(first, last, std::not1(variable_map_is_space())); + + if (first == last || *first != '=') throw torrent::input_error("Could not find '='."); mapped_type args(mapped_type::TYPE_LIST); - parse_args(pos + 1, command.end(), &args.as_list()); + first = parse_args(first + 1, last, &args.as_list()); if (args.as_list().empty()) set(key.c_str(), mapped_type()); @@ -167,6 +179,57 @@ VariableMap::process_command(const std::string& command) { else set(key.c_str(), args); + + return std::find_if(first, last, std::not1(variable_map_is_space())); +} + +// void +// VariableMap::process_command(const std::string& command) { +// std::string::const_iterator pos = command.begin(); +// pos = std::find_if(pos, command.end(), std::not1(variable_map_is_space())); + +// if (pos == command.end() || *pos == '#') +// return; + +// // Replace with parse_unknown? +// std::string key; +// pos = parse_name(pos, command.end(), &key); +// pos = std::find_if(pos, command.end(), std::not1(variable_map_is_space())); + +// if (pos == command.end() || *pos != '=') +// throw torrent::input_error("Could not find '='."); + +// mapped_type args(mapped_type::TYPE_LIST); +// parse_args(pos + 1, command.end(), &args.as_list()); + +// if (args.as_list().empty()) +// set(key.c_str(), mapped_type()); + +// else if (++args.as_list().begin() == args.as_list().end()) +// set(key.c_str(), *args.as_list().begin()); + +// else +// set(key.c_str(), args); + + +// Consider what the command scheduler should do. + +void +VariableMap::process_multiple(const char* first) { + while (first != '\0') { + const char* last = first; + + while (*last != '\n' && *last != '\0') last++; + + // Should we check the return value? Probably not necessary as + // parse_args throws on unquoted multi-word input. + process_single(first, last); + + if (*last == '\0') + return; + + first = last + 1; + } } bool @@ -184,7 +247,7 @@ VariableMap::process_file(key_type path) { while (file.getline(buffer, max_size_line).good()) { lineNumber++; // Would be nice to make this zero-copy. - process_command(buffer); + process_single(buffer, buffer + std::strlen(buffer)); } } catch (torrent::input_error& e) { diff --git a/src/utils/variable_map.h b/src/utils/variable_map.h index 7da01a33..f16a0ce5 100644 --- a/src/utils/variable_map.h +++ b/src/utils/variable_map.h @@ -87,8 +87,12 @@ public: void set_std_string(const std::string& key, const std::string& arg) { set(key.c_str(), mapped_type(arg)); } - // Relocate. - void process_command(const std::string& command); + const char* process_single(const char* first); + const char* process_single(const char* first, const char* last); + void process_std_single(const std::string& cmd) { process_single(cmd.c_str(), cmd.c_str() + cmd.size()); } + + void process_multiple(const char* first); + void process_stream(std::istream* str); bool process_file(key_type path);