* 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:
rakshasa
2006-02-11 15:34:53 +00:00
parent e5c5f7ecb1
commit 4dea195340
13 changed files with 112 additions and 120 deletions
+1
View File
@@ -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 \
+21 -28
View File
@@ -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
-2
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+2 -1
View File
@@ -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();
+3 -2
View File
@@ -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
View File
@@ -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);
-64
View File
@@ -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
+5 -2
View File
@@ -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)));
+3 -2
View File
@@ -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;
+53 -6
View File
@@ -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);
}
}
+10 -1
View File
@@ -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&);