diff --git a/Makefile.am b/Makefile.am index 18df34ab..3b81f032 100644 --- a/Makefile.am +++ b/Makefile.am @@ -9,6 +9,7 @@ EXTRA_DIST= \ rak/file_stat.h \ rak/functional.h \ rak/functional_fun.h \ + rak/path.h \ rak/priority_queue.h \ rak/priority_queue_default.h \ rak/regex.h \ diff --git a/src/option_file.cc b/rak/path.h similarity index 69% rename from src/option_file.cc rename to rak/path.h index fc888ce7..c4047f71 100644 --- a/src/option_file.cc +++ b/rak/path.h @@ -1,4 +1,4 @@ -// rTorrent - BitTorrent client +// rak - Rakshasa's toolbox // Copyright (C) 2005-2006, Jari Sundell // // This program is free software; you can redistribute it and/or modify @@ -34,37 +34,30 @@ // Skomakerveien 33 // 3185 Skoppum, NORWAY -#include "config.h" +// Various functions for manipulating file paths. Also consider making +// a directory iterator. -#include -#include -#include -#include +#ifndef RAK_PATH_H +#define RAK_PATH_H -#include "option_file.h" +#include +#include -bool -OptionFile::process_file(const std::string& filename) { - std::fstream file(filename.c_str(), std::ios::in); +namespace rak { - if (!file.good()) - return false; +inline std::string +path_expand(const std::string& path) { + if (path.empty() || path[0] != '~') + return path; - int lineNumber = 0; - char buffer[max_size_line]; + char* home = std::getenv("HOME"); - try { - - while (file.getline(buffer, max_size_line).good()) { - lineNumber++; - m_slotOption(buffer); - } - - } catch (torrent::input_error& e) { - snprintf(buffer, max_size_line, "Error in option file: %s:%i: %s", filename.c_str(), lineNumber, e.what()); - - throw std::runtime_error(buffer); - } - - return true; + if (home == NULL) + return path; + + return home + path.substr(1); } + +} + +#endif diff --git a/src/Makefile.am b/src/Makefile.am index 0d2b631f..7c60c6bb 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -24,8 +24,6 @@ rtorrent_SOURCES = \ globals.cc \ globals.h \ main.cc \ - option_file.cc \ - option_file.h \ option_handler_rules.cc \ option_handler_rules.h \ option_parser.cc \ diff --git a/src/core/download.cc b/src/core/download.cc index 9b47b6ab..61963b20 100644 --- a/src/core/download.cc +++ b/src/core/download.cc @@ -40,6 +40,7 @@ #include #include #include +#include #include #include @@ -217,15 +218,19 @@ Download::receive_chunk_failed(__UNUSED uint32_t idx) { // Clean up. void -Download::set_root_directory(const std::string& d) { - if (d.empty()) +Download::set_root_directory(const std::string& path) { + if (path.empty()) { m_download.set_root_dir("./" + (m_download.size_file_entries() > 1 ? m_download.name() : std::string())); - else - m_download.set_root_dir(d + - (*d.rbegin() != '/' ? "/" : "") + + + } else { + std::string fullPath = rak::path_expand(path); + + m_download.set_root_dir(fullPath + + (*fullPath.rbegin() != '/' ? "/" : "") + (m_download.size_file_entries() > 1 ? m_download.name() : "")); + } - m_download.bencode().get_key("rtorrent").insert_key("directory", d); + m_download.bencode().get_key("rtorrent").insert_key("directory", path); } } diff --git a/src/core/download.h b/src/core/download.h index 1557491f..c7187582 100644 --- a/src/core/download.h +++ b/src/core/download.h @@ -104,7 +104,7 @@ private: const char* connection_current() const { return connection_type_to_string(m_download.connection_type()); } void set_connection_current(const std::string& t) { return m_download.set_connection_type(string_to_connection_type(t.c_str())); } - void set_root_directory(const std::string& d); + void set_root_directory(const std::string& path); torrent::Download m_download; diff --git a/src/core/download_factory.cc b/src/core/download_factory.cc index b0455bf2..9f2b4407 100644 --- a/src/core/download_factory.cc +++ b/src/core/download_factory.cc @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -108,7 +109,7 @@ DownloadFactory::receive_load() { m_variables.set("tied_to_file", (int64_t)false); } else { - m_stream = new std::fstream(m_uri.c_str(), std::ios::in); + m_stream = new std::fstream(rak::path_expand(m_uri).c_str(), std::ios::in); if (m_stream->good()) receive_loaded(); diff --git a/src/core/download_store.cc b/src/core/download_store.cc index 47fb92a4..5a7a216b 100644 --- a/src/core/download_store.cc +++ b/src/core/download_store.cc @@ -41,6 +41,7 @@ #include #include #include +#include #include #include #include @@ -82,9 +83,9 @@ DownloadStore::set_path(const std::string& path) { throw torrent::input_error("Tried to change session directory while it is enabled."); if (!path.empty() && *path.rbegin() != '/') - m_path = path + '/'; + m_path = rak::path_expand(path + '/'); else - m_path = path; + m_path = rak::path_expand(path); } void diff --git a/src/main.cc b/src/main.cc index 9d4b7e32..70e86d4a 100644 --- a/src/main.cc +++ b/src/main.cc @@ -68,7 +68,6 @@ #include "control.h" #include "globals.h" #include "signal_handler.h" -#include "option_file.h" #include "option_handler_rules.h" #include "option_parser.h" #include "command_scheduler.h" @@ -166,10 +165,8 @@ main(int argc, char** argv) { control->core()->initialize_first(); - OptionFile optionFile; - optionFile.slot_option(sigc::mem_fun(control->variables(), &utils::VariableMap::process_command)); - - if (getenv("HOME") && !optionFile.process_file(getenv("HOME") + std::string("/.rtorrent.rc"))) + // Move env and go through "try_import". + if (!control->variables()->process_file("~/.rtorrent.rc")) control->core()->get_log_important().push_front("Could not load \"~/.rtorrent.rc\"."); int firstArg = parse_options(control, control->variables(), argc, argv); diff --git a/src/option_file.h b/src/option_file.h deleted file mode 100644 index 7d04f86f..00000000 --- a/src/option_file.h +++ /dev/null @@ -1,64 +0,0 @@ -// rTorrent - BitTorrent client -// Copyright (C) 2005-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 - -#ifndef RTORRENT_OPTION_FILE_H -#define RTORRENT_OPTION_FILE_H - -#include -#include - -class OptionFile { -public: - static const int max_size_key = 128; - static const int max_size_opt = 1024; - static const int max_size_line = max_size_key + max_size_opt + 64; - - typedef sigc::slot1 SlotStringPair; - - // Returns false when the file doesn't exist or cannot be opened. - bool process_file(const std::string& filename); - - void slot_option(const SlotStringPair& s) { m_slotOption = s; } - -private: - void parse_line(const char* line); - - static char* fill_buffer(int fd, char* buffer, char* first, char* last); - - SlotStringPair m_slotOption; -}; - -#endif diff --git a/src/option_handler_rules.cc b/src/option_handler_rules.cc index 8276d411..7c639725 100644 --- a/src/option_handler_rules.cc +++ b/src/option_handler_rules.cc @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -116,7 +117,7 @@ apply_stop_untied(Control* m, __UNUSED const std::string& arg) { != m->core()->download_list().end()) { rak::file_stat fs; - if (!fs.update((*itr)->variable_string("tied_to_file"))) { + if (!fs.update(rak::path_expand((*itr)->variable_string("tied_to_file")))) { (*itr)->variables()->set("tied_to_file", std::string()); m->core()->stop(*itr); } @@ -135,7 +136,7 @@ apply_remove_untied(Control* m, __UNUSED const std::string& arg) { != m->core()->download_list().end()) { rak::file_stat fs; - if (!fs.update((*itr)->variable_string("tied_to_file"))) { + if (!fs.update(rak::path_expand((*itr)->variable_string("tied_to_file")))) { (*itr)->variables()->set("tied_to_file", std::string()); m->core()->stop(*itr); itr = m->core()->erase(itr); @@ -183,6 +184,8 @@ initialize_option_handler(Control* c) { variables->insert("max_open_sockets", new utils::VariableSlotValue(NULL, rak::ptr_fn(&torrent::set_max_open_sockets), "%i")); 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->variables(), &utils::VariableMap::process_file_throw))); + variables->insert("try_import", new utils::VariableSlotString<>(NULL, rak::mem_fn(control->variables(), &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))); diff --git a/src/utils/directory.cc b/src/utils/directory.cc index 79f97fc7..b692ff54 100644 --- a/src/utils/directory.cc +++ b/src/utils/directory.cc @@ -40,6 +40,7 @@ #include #include #include +#include #include "directory.h" @@ -50,7 +51,7 @@ Directory::is_valid() const { if (m_path.empty()) return false; - DIR* d = opendir(m_path.c_str()); + DIR* d = opendir(rak::path_expand(m_path).c_str()); closedir(d); return d; @@ -61,7 +62,7 @@ Directory::update(bool hideDot) { if (m_path.empty()) throw std::logic_error("Directory::update() tried to open an empty path"); - DIR* d = opendir(m_path.c_str()); + DIR* d = opendir(rak::path_expand(m_path).c_str()); if (d == NULL) return false; diff --git a/src/utils/variable_map.cc b/src/utils/variable_map.cc index a18e7659..d4fd33f8 100644 --- a/src/utils/variable_map.cc +++ b/src/utils/variable_map.cc @@ -36,9 +36,12 @@ #include "config.h" -#include #include +#include +#include +#include #include +#include #include #include @@ -83,6 +86,12 @@ VariableMap::set(const std::string& key, const mapped_type& arg) { itr->second->set(arg); } +struct variable_map_is_space : std::unary_function { + bool operator () (char c) const { + return std::isspace(c); + } +}; + std::string::const_iterator parse_name(std::string::const_iterator first, std::string::const_iterator last, std::string* dest) { if (first == last || !std::isalpha(*first)) @@ -109,7 +118,7 @@ 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, std::ptr_fun(&std::isspace)); + std::string::const_iterator next = std::find_if(first, last, variable_map_is_space()); *dest = std::string(first, next); return next; @@ -118,13 +127,13 @@ parse_unknown(std::string::const_iterator first, std::string::const_iterator las std::string::const_iterator parse_args(std::string::const_iterator first, std::string::const_iterator last, VariableMap::mapped_type::List* dest) { - first = std::find_if(first, last, std::not1(std::ptr_fun(&std::isspace))); + first = std::find_if(first, last, std::not1(variable_map_is_space())); while (first != last) { dest->push_back(VariableMap::mapped_type()); first = parse_unknown(first, last, &dest->back()); - first = std::find_if(first, last, std::not1(std::ptr_fun(&std::isspace))); + first = std::find_if(first, last, std::not1(variable_map_is_space())); if (first != last && *first != ',') throw torrent::input_error("A string with blanks must be quoted."); @@ -136,7 +145,7 @@ parse_args(std::string::const_iterator first, std::string::const_iterator last, void VariableMap::process_command(const std::string& command) { std::string::const_iterator pos = command.begin(); - pos = std::find_if(pos, command.end(), std::not1(std::ptr_fun(&std::isspace))); + pos = std::find_if(pos, command.end(), std::not1(variable_map_is_space())); if (pos == command.end() || *pos == '#') return; @@ -144,7 +153,7 @@ VariableMap::process_command(const std::string& command) { // Replace with parse_unknown? std::string key; pos = parse_name(pos, command.end(), &key); - pos = std::find_if(pos, command.end(), std::not1(std::ptr_fun(&std::isspace))); + 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 '='."); @@ -162,4 +171,42 @@ VariableMap::process_command(const std::string& command) { set(key, args); } +bool +VariableMap::process_file(const std::string& path) { + std::fstream file(rak::path_expand(path).c_str(), std::ios::in); + + if (!file.good()) + return false; + + int lineNumber = 0; + char buffer[max_size_line]; + + try { + + while (file.getline(buffer, max_size_line).good()) { + lineNumber++; + // Would be nice to make this zero-copy. + process_command(buffer); + } + + } catch (torrent::input_error& e) { + snprintf(buffer, max_size_line, "Error in option file: %s:%i: %s", path.c_str(), lineNumber, e.what()); + + throw torrent::input_error(buffer); + } + + return true; +} + +void +VariableMap::process_file_throw(const std::string& path) { + if (!process_file(path)) + throw torrent::input_error("Could not open option file: " + path); +} + +void +VariableMap::process_file_nothrow(const std::string& path) { + process_file(path); +} + } diff --git a/src/utils/variable_map.h b/src/utils/variable_map.h index b1c00551..3b4beb62 100644 --- a/src/utils/variable_map.h +++ b/src/utils/variable_map.h @@ -39,6 +39,7 @@ #include #include +#include #include namespace utils { @@ -50,6 +51,10 @@ public: typedef std::map base_type; typedef torrent::Bencode mapped_type; + static const int max_size_key = 128; + static const int max_size_opt = 1024; + static const int max_size_line = max_size_key + max_size_opt + 64; + using base_type::iterator; using base_type::value_type; @@ -66,8 +71,12 @@ public: void set(const std::string& key, const mapped_type& arg); void set_string(const std::string& key, const std::string& arg) { set(key, mapped_type(arg)); } - // Temporary. + // Relocate. void process_command(const std::string& command); + void process_stream(std::istream* str); + bool process_file(const std::string& path); + void process_file_throw(const std::string& path); + void process_file_nothrow(const std::string& path); private: VariableMap(const VariableMap&);