* Set SO_REUSEADDR for the listening socket.

* Moved several settings to use the new variables and made the parser
better.

* Use "-O2" rather than "-O3".


git-svn-id: svn://rakshasa.no/libtorrent/trunk/rtorrent@623 e378c898-3ddf-0310-93e7-cc216c733640
This commit is contained in:
rakshasa
2006-01-17 17:23:32 +00:00
parent 4028ab2295
commit e8cd37ea3a
15 changed files with 207 additions and 129 deletions
+1 -1
View File
@@ -5,7 +5,7 @@ AC_DEFUN([TORRENT_CHECK_CXXFLAGS], [
if test -n "$CXXFLAGS"; then
AC_MSG_RESULT([user-defined "$CXXFLAGS"])
else
CXXFLAGS="-O3 -Wall"
CXXFLAGS="-O2 -Wall"
AC_MSG_RESULT([default "$CXXFLAGS"])
fi
])
+2 -2
View File
@@ -38,10 +38,10 @@
#define RTORRENT_CONTROL_H
#include <inttypes.h>
#include <rak/timer.h>
#include <rak/priority_queue_default.h>
#include <torrent/torrent.h>
#include "globals.h"
namespace ui {
class Root;
}
+7 -5
View File
@@ -50,6 +50,9 @@
#include <torrent/bencode.h>
#include <torrent/exceptions.h>
#include "utils/variable_map.h"
#include "globals.h"
#include "curl_get.h"
#include "download.h"
#include "download_factory.h"
@@ -85,10 +88,8 @@ delete_tied(Download* d) {
Manager::Manager() :
m_pollManager(NULL),
m_portRandom(false),
m_portFirst(6890),
m_portLast(6999),
m_checkHash(true) {
m_portLast(6999) {
}
void
@@ -245,7 +246,7 @@ Manager::check_hash(Download* d) {
void
Manager::receive_download_done(Download* d) {
if (m_checkHash) {
if (control->variables()->get("check_hash").as_string() == "yes") {
// Start the hash checking, send completed to tracker after
// finishing.
prepare_hash_check(d);
@@ -263,7 +264,7 @@ Manager::listen_open() {
if (m_portFirst > m_portLast)
throw torrent::input_error("Invalid port range for listening");
if (m_portRandom) {
if (control->variables()->get("port_random").as_string() == "yes") {
int boundary = m_portFirst + random() % (m_portLast - m_portFirst + 1);
if (!torrent::listen_open(boundary, m_portLast) &&
@@ -273,6 +274,7 @@ Manager::listen_open() {
} else {
if (!torrent::listen_open(m_portFirst, m_portLast))
throw torrent::input_error("Could not open/bind a port for listening.");
}
}
-6
View File
@@ -69,11 +69,8 @@ public:
Log& get_log_important() { return m_logImportant; }
Log& get_log_complete() { return m_logComplete; }
void set_port_random(bool v) { m_portRandom = v; }
void set_port_range(int a, int b) { m_portFirst = a; m_portLast = b; }
void set_check_hash(bool state) { m_checkHash = state; }
// Really should find a more descriptive name.
void initialize_first();
void initialize_second();
@@ -121,11 +118,8 @@ private:
Log m_logImportant;
Log m_logComplete;
bool m_portRandom;
int m_portFirst;
int m_portLast;
bool m_checkHash;
};
}
+7 -6
View File
@@ -121,30 +121,31 @@ print_download_info(char* buf, unsigned int length, core::Download* d) {
(double)d->get_download().down_rate()->rate() / (1 << 10),
(double)d->get_download().up_rate()->total() / (1 << 20)), 0);
//buf += std::max(0, snprintf(buf, length, " Left: "));
buf = print_download_time_left(buf, length, d);
buf = print_download_time_left(buf, last - buf, d);
return buf;
}
char*
print_download_status(char* buf, unsigned int length, core::Download* d) {
char* last = buf + length;
if (!d->get_download().is_active())
buf += std::max(snprintf(buf, length, "Inactive: "), 0);
buf += std::max(snprintf(buf, last - buf, "Inactive: "), 0);
if (d->get_download().is_hash_checking())
buf += std::max(snprintf(buf, length, "Checking hash [%2i%%]",
buf += std::max(snprintf(buf, last - buf, "Checking hash [%2i%%]",
(d->get_download().chunks_hashed() * 100) / d->get_download().chunks_total()), 0);
else if (d->get_download().is_tracker_busy() &&
d->get_download().tracker_focus() < d->get_download().size_trackers())
buf += std::max(snprintf(buf, length, "Tracker[%i:%i]: Connecting to %s",
buf += std::max(snprintf(buf, last - buf, "Tracker[%i:%i]: Connecting to %s",
d->get_download().tracker(d->get_download().tracker_focus()).group(),
d->get_download().tracker_focus(),
d->get_download().tracker(d->get_download().tracker_focus()).url().c_str()), 0);
else if (!d->get_message().empty())
buf += std::max(snprintf(buf, length, "%s", d->get_message().c_str()), 0);
buf += std::max(snprintf(buf, last - buf, "%s", d->get_message().c_str()), 0);
else
buf[0] = '\0';
+1 -1
View File
@@ -120,7 +120,7 @@ WindowFileList::redraw() {
m_canvas->print(84, pos, "%i - %i",
e.chunk_begin(),
e.chunk_end());
e.chunk_begin() != e.chunk_end() ? (e.chunk_end() - 1) : e.chunk_end());
++range.first;
++pos;
+2
View File
@@ -40,3 +40,5 @@
rak::priority_queue_default taskScheduler;
rak::timer cachedTime;
Control* control = NULL;
+4
View File
@@ -40,7 +40,11 @@
#include <rak/timer.h>
#include <rak/priority_queue_default.h>
#include "control.h"
extern rak::priority_queue_default taskScheduler;
extern rak::timer cachedTime;
extern Control* control;
#endif
+18 -14
View File
@@ -159,12 +159,12 @@ main(int argc, char** argv) {
cachedTime = rak::timer::current();
Control control;
control = new Control;
srandom(cachedTime.usec());
srand48(cachedTime.usec());
initialize_option_handler(&control);
initialize_option_handler(control);
SignalHandler::set_ignore(SIGPIPE);
SignalHandler::set_handler(SIGINT, sigc::mem_fun(control, &Control::receive_shutdown));
@@ -172,17 +172,17 @@ main(int argc, char** argv) {
SignalHandler::set_handler(SIGBUS, sigc::bind(sigc::ptr_fun(&do_panic), SIGBUS));
SignalHandler::set_handler(SIGFPE, sigc::bind(sigc::ptr_fun(&do_panic), SIGFPE));
control.core()->initialize_first();
control->core()->initialize_first();
OptionFile optionFile;
optionFile.slot_option(sigc::mem_fun(control.variables(), &utils::VariableMap::set));
optionFile.slot_option(sigc::mem_fun(control->variables(), &utils::VariableMap::process_command));
if (getenv("HOME") && !optionFile.process_file(getenv("HOME") + std::string("/.rtorrent.rc")))
control.core()->get_log_important().push_front("Could not load \"~/.rtorrent.rc\".");
control->core()->get_log_important().push_front("Could not load \"~/.rtorrent.rc\".");
int firstArg = parse_options(&control, control.variables(), argc, argv);
int firstArg = parse_options(control, control->variables(), argc, argv);
control.initialize();
control->initialize();
// Just to make sure we did all the stuff on the queue before
// loading any torrents.
@@ -192,38 +192,42 @@ main(int argc, char** argv) {
// Load session torrents and perform scheduled tasks to ensure
// session torrents are loaded before arg torrents.
load_session_torrents(&control);
load_session_torrents(control);
rak::priority_queue_perform(&taskScheduler, cachedTime);
load_arg_torrents(&control, argv + firstArg, argv + argc);
load_arg_torrents(control, argv + firstArg, argv + argc);
control.display()->adjust_layout();
control->display()->adjust_layout();
while (!control.is_shutdown_completed()) {
control.inc_tick();
while (!control->is_shutdown_completed()) {
control->inc_tick();
cachedTime = rak::timer::current();
rak::priority_queue_perform(&taskScheduler, cachedTime);
// Do shutdown check before poll, not after.
control.core()->get_poll_manager()->poll(client_next_timeout());
control->core()->get_poll_manager()->poll(client_next_timeout());
}
control.cleanup();
control->cleanup();
} catch (torrent::base_error& e) {
display::Canvas::cleanup();
delete control;
std::cout << "Caught exception: " << e.what() << std::endl;
return -1;
} catch (std::exception& e) {
display::Canvas::cleanup();
delete control;
std::cout << e.what() << std::endl;
return -1;
}
delete control;
return 0;
}
+19 -19
View File
@@ -57,7 +57,7 @@ OptionFile::process_file(const std::string& filename) {
while (file.getline(buffer, max_size_line).good()) {
lineNumber++;
parse_line(buffer);
m_slotOption(buffer);
}
} catch (torrent::input_error& e) {
@@ -69,28 +69,28 @@ OptionFile::process_file(const std::string& filename) {
return true;
}
void
OptionFile::parse_line(const char* line) {
// void
// OptionFile::parse_line(const char* line) {
//const char* last = std::find(line, line + max_size_line, '\0');
if (line[0] == '#')
return;
// if (line[0] == '#')
// return;
int result;
char key[64];
char opt[512];
// int result;
// char key[64];
// char opt[512];
opt[0] = '\0';
// opt[0] = '\0';
// Check for empty lines, and options within "abc".
if ((result = std::sscanf(line, "%63s = \"%511[^\"]", key, opt)) != 2 &&
(result = std::sscanf(line, "%63s = %511s", key, opt)) != 2 &&
result == 1)
throw torrent::input_error("Error parseing option file.");
// // Check for empty lines, and options within "abc".
// if ((result = std::sscanf(line, "%63s = \"%511[^\"]", key, opt)) != 2 &&
// (result = std::sscanf(line, "%63s = %511s", key, opt)) != 2 &&
// result == 1)
// throw torrent::input_error("Error parseing option file.");
if (opt[0] == '"' && opt[1] == '"')
opt[0] = '\0';
// if (opt[0] == '"' && opt[1] == '"')
// opt[0] = '\0';
if (result >= 1)
m_slotOption(key, opt);
}
// if (result >= 1)
// m_slotOption(key, opt);
// }
+1 -1
View File
@@ -46,7 +46,7 @@ public:
static const int max_size_opt = 1024;
static const int max_size_line = max_size_key + max_size_opt + 64;
typedef sigc::slot2<void, const std::string&, const std::string&> SlotStringPair;
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);
+36 -43
View File
@@ -55,6 +55,7 @@
#include "utils/variable_generic.h"
#include "utils/variable_map.h"
#include "globals.h"
#include "control.h"
#include "option_handler_rules.h"
#include "command_scheduler.h"
@@ -178,11 +179,6 @@ apply_port_range(Control* m, const std::string& arg) {
m->core()->set_port_range(a, b);
}
void
apply_port_random(Control* m, const std::string& arg) {
m->core()->set_port_random(arg == "yes");
}
void
apply_tracker_dump(Control* m, const std::string& arg) {
if (arg == "yes")
@@ -199,14 +195,6 @@ apply_use_udp_trackers(Control* m, const std::string& arg) {
m->core()->get_download_list().slot_map_insert()["1_use_udp_trackers"] = sigc::bind(sigc::mem_fun(&core::Download::enable_udp_trackers), false);
}
void
apply_check_hash(Control* m, const std::string& arg) {
if (arg == "yes")
m->core()->set_check_hash(true);
else
m->core()->set_check_hash(false);
}
void
apply_http_proxy(Control* m, const std::string& arg) {
m->core()->get_poll_manager()->get_http_stack()->set_http_proxy(arg);
@@ -299,44 +287,49 @@ apply_schedule_remove(Control* m, const std::string& arg) {
void
initialize_option_handler(Control* c) {
c->variables()->insert("bind", new utils::VariableSlotString<>(NULL, rak::mem_fn(c->core(), &core::Manager::bind)));
utils::VariableMap* variables = control->variables();
c->variables()->insert("ip", new utils::VariableSlotString<>(NULL, rak::bind_ptr_fn(&apply_ip, c)));
c->variables()->insert("port_range", new utils::VariableSlotString<>(NULL, rak::bind_ptr_fn(&apply_port_range, c)));
c->variables()->insert("port_random", new utils::VariableSlotString<>(NULL, rak::bind_ptr_fn(&apply_port_random, c)));
// Cleaned up.
variables->insert("check_hash", new utils::VariableValue("yes"));
variables->insert("port_random", new utils::VariableValue("yes"));
variables->insert("session", new utils::VariableSlotString<>(NULL, rak::mem_fn(&control->core()->get_download_store(), &core::DownloadStore::use)));
c->variables()->insert("check_hash", new utils::VariableSlotString<>(NULL, rak::bind_ptr_fn(&apply_check_hash, c)));
c->variables()->insert("directory", new utils::VariableSlotString<>(NULL, rak::bind_ptr_fn(&apply_download_directory, c)));
// Old.
variables->insert("bind", new utils::VariableSlotString<>(NULL, rak::mem_fn(control->core(), &core::Manager::bind)));
c->variables()->insert("max_peers", new utils::VariableSlotValue<int, int>(NULL, rak::bind_ptr_fn(&apply_download_max_peers, c), "%i"));
c->variables()->insert("min_peers", new utils::VariableSlotValue<int, int>(NULL, rak::bind_ptr_fn(&apply_download_min_peers, c), "%i"));
c->variables()->insert("max_uploads", new utils::VariableSlotValue<int, int>(NULL, rak::bind_ptr_fn(&apply_download_max_uploads, c), "%i"));
variables->insert("ip", new utils::VariableSlotString<>(NULL, rak::bind_ptr_fn(&apply_ip, c)));
variables->insert("port_range", new utils::VariableSlotString<>(NULL, rak::bind_ptr_fn(&apply_port_range, c)));
c->variables()->insert("download_rate", new utils::VariableSlotValue<int, int>(NULL, rak::bind_ptr_fn(&apply_global_download_rate, c), "%i"));
c->variables()->insert("upload_rate", new utils::VariableSlotValue<int, int>(NULL, rak::bind_ptr_fn(&apply_global_upload_rate, c), "%i"));
variables->insert("directory", new utils::VariableSlotString<>(NULL, rak::bind_ptr_fn(&apply_download_directory, c)));
c->variables()->insert("hash_read_ahead", new utils::VariableSlotValue<int, int>(NULL, rak::bind_ptr_fn(&apply_hash_read_ahead, c), "%i"));
c->variables()->insert("hash_interval", new utils::VariableSlotValue<int, int>(NULL, rak::bind_ptr_fn(&apply_hash_interval, c), "%i"));
c->variables()->insert("hash_max_tries", new utils::VariableSlotValue<int, int>(NULL, rak::bind_ptr_fn(&apply_hash_max_tries, c), "%i"));
c->variables()->insert("max_open_files", new utils::VariableSlotValue<int, int>(NULL, rak::bind_ptr_fn(&apply_max_open_files, c), "%i"));
c->variables()->insert("max_open_sockets", new utils::VariableSlotValue<int, int>(NULL, rak::bind_ptr_fn(&apply_max_open_sockets, c), "%i"));
variables->insert("max_peers", new utils::VariableSlotValue<int, int>(NULL, rak::bind_ptr_fn(&apply_download_max_peers, c), "%i"));
variables->insert("min_peers", new utils::VariableSlotValue<int, int>(NULL, rak::bind_ptr_fn(&apply_download_min_peers, c), "%i"));
variables->insert("max_uploads", new utils::VariableSlotValue<int, int>(NULL, rak::bind_ptr_fn(&apply_download_max_uploads, c), "%i"));
c->variables()->insert("umask", new utils::VariableSlotValue<int, int>(NULL, rak::bind_ptr_fn(&apply_umask, c), "%o"));
variables->insert("download_rate", new utils::VariableSlotValue<int, int>(NULL, rak::bind_ptr_fn(&apply_global_download_rate, c), "%i"));
variables->insert("upload_rate", new utils::VariableSlotValue<int, int>(NULL, rak::bind_ptr_fn(&apply_global_upload_rate, c), "%i"));
c->variables()->insert("connection_leech", new utils::VariableSlotString<>(NULL, rak::bind_ptr_fn(&apply_connection_leech, c)));
c->variables()->insert("connection_seed", new utils::VariableSlotString<>(NULL, rak::bind_ptr_fn(&apply_connection_seed, c)));
variables->insert("hash_read_ahead", new utils::VariableSlotValue<int, int>(NULL, rak::bind_ptr_fn(&apply_hash_read_ahead, c), "%i"));
variables->insert("hash_interval", new utils::VariableSlotValue<int, int>(NULL, rak::bind_ptr_fn(&apply_hash_interval, c), "%i"));
variables->insert("hash_max_tries", new utils::VariableSlotValue<int, int>(NULL, rak::bind_ptr_fn(&apply_hash_max_tries, c), "%i"));
variables->insert("max_open_files", new utils::VariableSlotValue<int, int>(NULL, rak::bind_ptr_fn(&apply_max_open_files, c), "%i"));
variables->insert("max_open_sockets", new utils::VariableSlotValue<int, int>(NULL, rak::bind_ptr_fn(&apply_max_open_sockets, c), "%i"));
c->variables()->insert("load", new utils::VariableSlotString<>(NULL, rak::bind_ptr_fn(&apply_load, c)));
c->variables()->insert("load_start", new utils::VariableSlotString<>(NULL, rak::bind_ptr_fn(&apply_load_start, c)));
c->variables()->insert("stop_untied", new utils::VariableSlotString<>(NULL, rak::bind_ptr_fn(&apply_stop_untied, c)));
c->variables()->insert("remove_untied", new utils::VariableSlotString<>(NULL, rak::bind_ptr_fn(&apply_remove_untied, c)));
variables->insert("umask", new utils::VariableSlotValue<int, int>(NULL, rak::bind_ptr_fn(&apply_umask, c), "%o"));
c->variables()->insert("session", new utils::VariableSlotString<>(NULL, rak::bind_ptr_fn(&apply_session_directory, c)));
c->variables()->insert("encoding_list", new utils::VariableSlotString<>(NULL, rak::bind_ptr_fn(&apply_encoding_list, c)));
c->variables()->insert("tracker_dump", new utils::VariableSlotString<>(NULL, rak::bind_ptr_fn(&apply_tracker_dump, c)));
c->variables()->insert("use_udp_trackers", new utils::VariableSlotString<>(NULL, rak::bind_ptr_fn(&apply_use_udp_trackers, c)));
variables->insert("connection_leech", new utils::VariableSlotString<>(NULL, rak::bind_ptr_fn(&apply_connection_leech, c)));
variables->insert("connection_seed", new utils::VariableSlotString<>(NULL, rak::bind_ptr_fn(&apply_connection_seed, c)));
c->variables()->insert("http_proxy", new utils::VariableSlotString<>(NULL, rak::bind_ptr_fn(&apply_http_proxy, c)));
c->variables()->insert("schedule", new utils::VariableSlotString<>(NULL, rak::bind_ptr_fn(&apply_schedule, c)));
c->variables()->insert("schedule_remove", new utils::VariableSlotString<>(NULL, rak::bind_ptr_fn(&apply_schedule_remove, c)));
variables->insert("load", new utils::VariableSlotString<>(NULL, rak::bind_ptr_fn(&apply_load, c)));
variables->insert("load_start", new utils::VariableSlotString<>(NULL, rak::bind_ptr_fn(&apply_load_start, c)));
variables->insert("stop_untied", new utils::VariableSlotString<>(NULL, rak::bind_ptr_fn(&apply_stop_untied, c)));
variables->insert("remove_untied", new utils::VariableSlotString<>(NULL, rak::bind_ptr_fn(&apply_remove_untied, c)));
variables->insert("encoding_list", new utils::VariableSlotString<>(NULL, rak::bind_ptr_fn(&apply_encoding_list, c)));
variables->insert("tracker_dump", new utils::VariableSlotString<>(NULL, rak::bind_ptr_fn(&apply_tracker_dump, c)));
variables->insert("use_udp_trackers", new utils::VariableSlotString<>(NULL, rak::bind_ptr_fn(&apply_use_udp_trackers, c)));
variables->insert("http_proxy", new utils::VariableSlotString<>(NULL, rak::bind_ptr_fn(&apply_http_proxy, c)));
variables->insert("schedule", new utils::VariableSlotString<>(NULL, rak::bind_ptr_fn(&apply_schedule, c)));
variables->insert("schedule_remove", new utils::VariableSlotString<>(NULL, rak::bind_ptr_fn(&apply_schedule_remove, c)));
}
+10 -10
View File
@@ -40,17 +40,17 @@
namespace utils {
// VariableString::~VariableString() {
// }
VariableValue::~VariableValue() {
}
// std::string
// VariableString::get() {
// return m_variable;
// }
const torrent::Bencode&
VariableValue::get() {
return m_variable;
}
// void
// VariableString::set(const std::string& arg) {
// m_variable = arg;
// }
void
VariableValue::set(const torrent::Bencode& arg) {
m_variable = arg;
}
}
+27 -16
View File
@@ -39,6 +39,7 @@
#include <cstdio>
#include <string>
#include <limits>
#include <inttypes.h>
#include <rak/functional_fun.h>
#include <torrent/bencode.h>
@@ -48,19 +49,18 @@
namespace utils {
// class VariableS : public Variable {
// public:
// VariableString(const std::string& v = "") : m_variable(v) {}
// virtual ~VariableString();
class VariableValue : public Variable {
public:
VariableValue(const torrent::Bencode& v = torrent::Bencode()) : m_variable(v) {}
virtual ~VariableValue();
// virtual const torrent::Bencode& get();
// virtual void set(const torrent::Bencode& arg);
virtual const torrent::Bencode& get();
virtual void set(const torrent::Bencode& arg);
// private:
// std::string m_variable;
// };
private:
torrent::Bencode m_variable;
};
// VariableSlot?
template <typename Get = std::string, typename Set = const std::string&>
class VariableSlotString : public Variable {
public:
@@ -84,10 +84,16 @@ public:
}
virtual void set(const torrent::Bencode& arg) {
if (!arg.is_string())
switch (arg.get_type()) {
case torrent::Bencode::TYPE_STRING:
m_slotSet(arg.as_string());
break;
case torrent::Bencode::TYPE_NONE:
m_slotSet("");
break;
default:
throw torrent::internal_error("VariableSlotString::set(...) got wrong type.");
m_slotSet(arg.as_string());
}
}
private:
@@ -103,15 +109,19 @@ private:
template <typename Get, typename Set>
class VariableSlotValue : public Variable {
public:
typedef rak::function0<Get> SlotGet;
typedef rak::function1<void, Set> SlotSet;
typedef rak::function0<Get> SlotGet;
typedef rak::function1<void, Set> SlotSet;
typedef std::pair<int64_t, int64_t> Range;
VariableSlotValue(typename SlotGet::base_type* slotGet,
typename SlotSet::base_type* slotSet,
const char* pattern) {
const char* pattern,
Range range = Range(std::numeric_limits<int64_t>::min(),
std::numeric_limits<int64_t>::max())) {
m_slotGet.set(slotGet);
m_slotSet.set(slotSet);
m_pattern = pattern;
m_range = range;
}
virtual ~VariableSlotValue() {}
@@ -148,6 +158,7 @@ private:
SlotSet m_slotSet;
const char* m_pattern;
Range m_range;
// Store the cache here to avoid unnessesary copying and such. This
// should not result in any unresonable memory usage since few
+72 -5
View File
@@ -82,16 +82,83 @@ VariableMap::set(const std::string& key, const torrent::Bencode& arg) {
itr->second->set(arg);
}
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))
throw torrent::input_error("Invalid start of name.");
for ( ; first != last && (std::isalnum(*first) || *first == '_'); ++first)
dest->push_back(*first);
return first;
}
std::string::const_iterator
parse_unknown(std::string::const_iterator first, std::string::const_iterator last, torrent::Bencode* dest) {
if (*first == '"') {
std::string::const_iterator next = std::find_if(++first, last, std::bind2nd(std::equal_to<char>(), '"'));
if (first == last ||
first == next ||
next == last)
throw torrent::input_error("Could not find closing '\"'.");
*dest = std::string(first, next);
return ++next;
} else {
// Add rak::or and check for ','.
std::string::const_iterator next = std::find_if(first, last, std::ptr_fun(&std::isspace));
*dest = std::string(first, next);
return next;
}
}
std::string::const_iterator
parse_args(std::string::const_iterator first, std::string::const_iterator last, torrent::Bencode::List* dest) {
first = std::find_if(first, last, std::not1(std::ptr_fun(&std::isspace)));
while (first != last) {
dest->push_back(torrent::Bencode());
first = parse_unknown(first, last, &dest->back());
first = std::find_if(first, last, std::not1(std::ptr_fun(&std::isspace)));
if (first != last && *first != ',')
throw torrent::input_error("A string with blanks must be quoted.");
}
return first;
}
void
VariableMap::process_command(const std::string& command) {
std::string::size_type pos = command.find('=');
std::string::const_iterator pos = command.begin();
pos = std::find_if(pos, command.end(), std::not1(std::ptr_fun(&std::isspace)));
if (pos == std::string::npos)
throw torrent::input_error("Option handler could not find '=' in command.");
if (pos == command.end() || *pos == '#')
return;
// Do sscanf, check for integer. Later move and make it smarter.
// 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)));
if (pos == command.end() || *pos != '=')
throw torrent::input_error("Could not find '='.");
set(command.substr(0, pos), torrent::Bencode(command.substr(pos + 1, std::string::npos)));
torrent::Bencode args(torrent::Bencode::TYPE_LIST);
parse_args(pos + 1, command.end(), &args.as_list());
if (args.as_list().empty())
set(key, torrent::Bencode());
else if (++args.as_list().begin() == args.as_list().end())
set(key, *args.as_list().begin());
else
set(key, args);
}
}