mirror of
https://github.com/rakshasa/rtorrent.git
synced 2026-08-15 06:32:31 +00:00
* Expand ~ in paths, all uses should be covered.
* Moved option file parsing to VariableMap and added "import" and "try_import" options for loading option files. git-svn-id: svn://rakshasa.no/libtorrent/trunk/rtorrent@636 e378c898-3ddf-0310-93e7-cc216c733640
This commit is contained in:
@@ -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 \
|
||||
|
||||
@@ -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 <fstream>
|
||||
#include <stdexcept>
|
||||
#include <stdio.h>
|
||||
#include <torrent/exceptions.h>
|
||||
#ifndef RAK_PATH_H
|
||||
#define RAK_PATH_H
|
||||
|
||||
#include "option_file.h"
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
|
||||
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
|
||||
@@ -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 \
|
||||
|
||||
+11
-6
@@ -40,6 +40,7 @@
|
||||
#include <sigc++/bind.h>
|
||||
#include <sigc++/hide.h>
|
||||
#include <sigc++/signal.h>
|
||||
#include <rak/path.h>
|
||||
#include <torrent/exceptions.h>
|
||||
#include <torrent/torrent.h>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
-1
@@ -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;
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <rak/path.h>
|
||||
#include <torrent/bencode.h>
|
||||
#include <torrent/exceptions.h>
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
#include <fstream>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <rak/path.h>
|
||||
#include <rak/string_manip.h>
|
||||
#include <torrent/bencode.h>
|
||||
#include <torrent/exceptions.h>
|
||||
@@ -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
|
||||
|
||||
+2
-5
@@ -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);
|
||||
|
||||
@@ -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 <jaris@ifi.uio.no>
|
||||
//
|
||||
// Skomakerveien 33
|
||||
// 3185 Skoppum, NORWAY
|
||||
|
||||
#ifndef RTORRENT_OPTION_FILE_H
|
||||
#define RTORRENT_OPTION_FILE_H
|
||||
|
||||
#include <string>
|
||||
#include <sigc++/slot.h>
|
||||
|
||||
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<void, const std::string&> 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
|
||||
@@ -42,6 +42,7 @@
|
||||
#include <sys/stat.h>
|
||||
#include <rak/file_stat.h>
|
||||
#include <rak/functional.h>
|
||||
#include <rak/path.h>
|
||||
#include <rak/string_manip.h>
|
||||
#include <torrent/bencode.h>
|
||||
#include <torrent/exceptions.h>
|
||||
@@ -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<int, uint32_t>(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<const std::string&>(c->command_scheduler(), &CommandScheduler::parse)));
|
||||
variables->insert("schedule_remove", new utils::VariableSlotString<>(NULL, rak::mem_fn<const std::string&>(c->command_scheduler(), &CommandScheduler::erase)));
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
#include <functional>
|
||||
#include <stdexcept>
|
||||
#include <dirent.h>
|
||||
#include <rak/path.h>
|
||||
|
||||
#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;
|
||||
|
||||
@@ -36,9 +36,12 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <cctype>
|
||||
#include <algorithm>
|
||||
#include <cstdio>
|
||||
#include <cctype>
|
||||
#include <fstream>
|
||||
#include <rak/functional.h>
|
||||
#include <rak/path.h>
|
||||
#include <torrent/exceptions.h>
|
||||
#include <torrent/bencode.h>
|
||||
|
||||
@@ -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<char, bool> {
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <iosfwd>
|
||||
#include <torrent/bencode.h>
|
||||
|
||||
namespace utils {
|
||||
@@ -50,6 +51,10 @@ public:
|
||||
typedef std::map<std::string, Variable*> 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&);
|
||||
|
||||
Reference in New Issue
Block a user