* Allow inlining functions in commands with parantheses, e.g:

print = (convert.time,(system.time))
  schedule2 = test_print_2,2,2,((print,"current ",((convert.time,((system.time))))))

  Multiple parantheses need to be used in schedule to ensure the command doesn't get evaluated at the time of calling schedule.


git-svn-id: svn://rakshasa.no/libtorrent/trunk/rtorrent@1191 e378c898-3ddf-0310-93e7-cc216c733640
This commit is contained in:
rakshasa
2011-02-12 12:20:09 +00:00
parent 5691233bf1
commit 7b2fae35d5
12 changed files with 198 additions and 24 deletions
+24 -3
View File
@@ -97,7 +97,22 @@ CommandScheduler::call_item(value_type item) {
// removed.
try {
rpc::parse_command_multiple_std(item->command());
if (item->command().is_string()) {
rpc::parse_command_multiple_std(item->command().as_string());
} else if (item->command().is_dict_key()) {
// This can/should be optimized...
torrent::Object tmp_command = item->command();
// Unquote the root function object so 'parse_command_execute'
// doesn't end up calling it.
uint32_t flags = tmp_command.flags() & torrent::Object::mask_function;
tmp_command.unset_flags(torrent::Object::mask_function);
tmp_command.set_flags((flags >> 1) & torrent::Object::mask_function);
rpc::parse_command_execute(rpc::make_target(), &tmp_command);
rpc::commands.call_command(tmp_command.as_dict_key().c_str(), tmp_command.as_dict_obj());
}
} catch (torrent::input_error& e) {
if (m_slotErrorMessage.is_valid())
@@ -119,13 +134,19 @@ CommandScheduler::call_item(value_type item) {
}
void
CommandScheduler::parse(const std::string& key, const std::string& bufAbsolute, const std::string& bufInterval, const std::string& command) {
CommandScheduler::parse(const std::string& key,
const std::string& bufAbsolute,
const std::string& bufInterval,
const torrent::Object& command) {
if (!command.is_string() && !command.is_dict_key())
throw torrent::bencode_error("Invalid type passed to command scheduler.");
uint32_t absolute = parse_absolute(bufAbsolute.c_str());
uint32_t interval = parse_interval(bufInterval.c_str());
CommandSchedulerItem* item = *insert(key);
item->set_command(command);
item->command() = command;
item->set_interval(interval);
item->enable((cachedTime + rak::timer::from_seconds(absolute)).round_seconds());
+6 -1
View File
@@ -42,6 +42,10 @@
#include <inttypes.h>
#include <rak/functional_fun.h>
namespace torrent {
class Object;
}
namespace rpc {
class CommandSchedulerItem;
@@ -71,7 +75,8 @@ public:
void erase(iterator itr);
void erase_str(const std::string& key) { erase(find(key)); }
void parse(const std::string& key, const std::string& bufAbsolute, const std::string& bufInterval, const std::string& command);
void parse(const std::string& key, const std::string& bufAbsolute,
const std::string& bufInterval, const torrent::Object& command);
static uint32_t parse_absolute(const char* str);
static uint32_t parse_interval(const char* str);
+4 -4
View File
@@ -39,6 +39,8 @@
#include "globals.h"
#include <torrent/object.h>
namespace rpc {
class CommandSchedulerItem {
@@ -54,9 +56,7 @@ public:
void disable();
const std::string& key() const { return m_key; }
const std::string& command() const { return m_command; }
void set_command(const std::string& s) { m_command = s; }
torrent::Object& command() { return m_command; }
// 'interval()' should in the future return some more dynamic values.
uint32_t interval() const { return m_interval; }
@@ -72,7 +72,7 @@ private:
void operator = (const CommandSchedulerItem&);
std::string m_key;
std::string m_command;
torrent::Object m_command;
uint32_t m_interval;
rak::timer m_timeScheduled;
+4 -3
View File
@@ -62,13 +62,14 @@ object_storage::insert(const char* key_data, uint32_t key_size, const torrent::O
// Check for size > key_size.
// Check for empty string.
bool use_raw = false;
torrent::Object object;
switch (flags & mask_type) {
case flag_bool_type: object = !!convert_to_value(rawObject); break;
case flag_value_type: object = convert_to_value(rawObject); break;
case flag_string_type: object = convert_to_string(rawObject); break;
case flag_function_type: object = convert_to_string(rawObject); break;
case flag_function_type: use_raw = true; break;
case flag_multi_type: object = torrent::Object::create_map(); break;
}
@@ -81,7 +82,7 @@ object_storage::insert(const char* key_data, uint32_t key_size, const torrent::O
throw torrent::input_error("Key already exists in object_storage.");
result.first->second.flags = flags;
result.first->second.object = object;
result.first->second.object = use_raw ? rawObject : object;
return result.first;
}
@@ -147,7 +148,7 @@ object_storage::call_function(const torrent::raw_string& key, target_type target
switch (itr->second.flags & mask_type) {
case flag_function_type:
return command_function_call_str(itr->second.object.as_string(), target, object);
return command_function_call_object(itr->second.object, target, object);
case flag_multi_type:
return command_function_multi_call(itr->second.object.as_map(), target, object);
default:
+37
View File
@@ -181,6 +181,43 @@ parse_object(const char* first, const char* last, torrent::Object* dest, bool (*
return ++first;
} else if (*first == '(') {
int32_t depth = 1;
while (first + 1 != last && *(first + 1) == '(') {
first++;
depth++;
}
if (depth > 3)
throw torrent::input_error("Max 3 parantheses per object allowed.");
*dest = torrent::Object::create_dict_key();
dest->set_flags(torrent::Object::flag_function << (depth - 1));
first = parse_string(first + 1, last, &dest->as_dict_key(), &parse_is_delim_func);
first = parse_skip_wspace(first, last);
if (first == last || !parse_is_delim_func(*first))
throw torrent::input_error("Could not find closing ')'.");
if (*first == ',') {
// This will always create a list even for single argument functions...
dest->as_dict_obj() = torrent::Object::create_list();
first = parse_list(first + 1, last, &dest->as_dict_obj(), &parse_is_delim_func);
first = parse_skip_wspace(first, last);
}
while (depth != 0 && first != last && *first == ')') {
first++;
depth--;
}
if (depth != 0)
throw torrent::input_error("Parantheses mismatch.");
return first;
} else {
*dest = std::string();
+1
View File
@@ -64,6 +64,7 @@ inline bool parse_is_delim_list(const char c) { return parse_is_seperator(c)
inline bool parse_is_delim_command(const char c) { return parse_is_seperator(c) || c == ';' || std::isspace(c); }
// inline bool parse_is_delim_block(const char c) { return c == ';' || c == '}'; }
inline bool parse_is_delim_block(const char c) { return parse_is_seperator(c) || c == '}'; }
inline bool parse_is_delim_func(const char c) { return parse_is_seperator(c) || c == ')'; }
const char* parse_skip_wspace(const char* first);
const char* parse_skip_wspace(const char* first, const char* last);
+55 -1
View File
@@ -93,7 +93,19 @@ parse_command_execute(target_type target, torrent::Object* object) {
parse_command_execute(target, &*itr);
}
} else if (*object->as_string().c_str() == '$') {
} else if (object->is_dict_key()) {
parse_command_execute(target, &object->as_dict_obj());
if (object->flags() & torrent::Object::flag_function) {
*object = rpc::commands.call_command(object->as_dict_key().c_str(), object->as_dict_obj(), target);
} else {
uint32_t flags = object->flags() & torrent::Object::mask_function;
object->unset_flags(torrent::Object::mask_function);
object->set_flags((flags >> 1) & torrent::Object::mask_function);
}
} else if (object->is_string() && *object->as_string().c_str() == '$') {
const std::string& str = object->as_string();
*object = parse_command(target, str.c_str() + 1, str.c_str() + str.size()).first;
@@ -252,6 +264,48 @@ command_function_call(const torrent::raw_string& cmd, target_type target, const
}
}
const torrent::Object
command_function_call_object(const torrent::Object& cmd, target_type target, const torrent::Object& args) {
rpc::command_base::stack_type stack;
torrent::Object* last_stack;
if (args.is_list())
last_stack = rpc::command_base::push_stack(args.as_list(), &stack);
else if (args.type() != torrent::Object::TYPE_NONE)
last_stack = rpc::command_base::push_stack(&args, &args + 1, &stack);
else
last_stack = rpc::command_base::push_stack(NULL, NULL, &stack);
try {
torrent::Object result;
if (cmd.is_string()) {
result = parse_command_multiple(target, cmd.as_string().c_str(), cmd.as_string().c_str() + cmd.as_string().size());
} else if (cmd.is_list()){
for (torrent::Object::list_const_iterator first = cmd.as_list().begin(), last = cmd.as_list().end(); first != last; first++) {
torrent::Object tmp_cmd = *first;
rpc::parse_command_execute(target, &tmp_cmd);
result = rpc::commands.call_command(tmp_cmd.as_dict_key().c_str(), tmp_cmd.as_dict_obj());
}
} else {
torrent::Object tmp_cmd = cmd;
rpc::parse_command_execute(target, &tmp_cmd);
result = rpc::commands.call_command(tmp_cmd.as_dict_key().c_str(), tmp_cmd.as_dict_obj());
}
rpc::command_base::pop_stack(&stack, last_stack);
return result;
} catch (torrent::bencode_error& e) {
rpc::command_base::pop_stack(&stack, last_stack);
throw e;
}
}
const torrent::Object
command_function_multi_call(const torrent::Object::map_type& cmd, target_type target, const torrent::Object& args) {
rpc::command_base::stack_type stack;
+4
View File
@@ -62,6 +62,8 @@ typedef std::pair<torrent::Object, const char*> parse_command_type;
parse_command_type parse_command(target_type target, const char* first, const char* last);
torrent::Object parse_command_multiple(target_type target, const char* first, const char* last);
void parse_command_execute(target_type target, torrent::Object* object);
// Make this take care of lists too.
parse_command_type parse_command_object(target_type target, const torrent::Object& object);
@@ -130,6 +132,8 @@ call_command_d_range(const char* key, core::Download* download, torrent::Object:
const torrent::Object
command_function_call(const torrent::raw_string& cmd, target_type target, const torrent::Object& args);
const torrent::Object
command_function_call_object(const torrent::Object& cmd, target_type target, const torrent::Object& args);
const torrent::Object
command_function_multi_call(const torrent::Object::map_type& cmd, target_type target, const torrent::Object& args);
inline const torrent::Object