diff --git a/src/command_helpers.cc b/src/command_helpers.cc index 736d21ca..65610905 100644 --- a/src/command_helpers.cc +++ b/src/command_helpers.cc @@ -49,6 +49,8 @@ rpc::CommandSlot commandSlots[COMMAND_SLOTS_SIZE]; rpc::CommandSlot* commandSlotsItr = commandSlots; rpc::CommandVariable commandVariables[COMMAND_VARIABLES_SIZE]; rpc::CommandVariable* commandVariablesItr = commandVariables; +rpc::CommandObjectPtr commandObjectPtrs[COMMAND_OBJECT_PTR_SIZE]; +rpc::CommandObjectPtr* commandObjectPtrsItr = commandObjectPtrs; rpc::CommandSlot commandDownloadSlots[COMMAND_DOWNLOAD_SLOTS_SIZE]; rpc::CommandSlot* commandDownloadSlotsItr = commandDownloadSlots; rpc::CommandSlot commandFileSlots[COMMAND_FILE_SLOTS_SIZE]; @@ -89,6 +91,7 @@ initialize_commands() { #ifdef ADDING_COMMANDS if (commandSlotsItr > commandSlots + COMMAND_SLOTS_SIZE || commandVariablesItr > commandVariables + COMMAND_VARIABLES_SIZE || + commandObjectPtrsItr > commandObjectPtrs + COMMAND_OBJECT_PTR_SIZE || commandDownloadSlotsItr > commandDownloadSlots + COMMAND_DOWNLOAD_SLOTS_SIZE || commandFileSlotsItr > commandFileSlots + COMMAND_FILE_SLOTS_SIZE || commandFileItrSlotsItr > commandFileItrSlots + COMMAND_FILE_ITR_SLOTS_SIZE || @@ -98,6 +101,7 @@ initialize_commands() { #else if (commandSlotsItr != commandSlots + COMMAND_SLOTS_SIZE || commandVariablesItr != commandVariables + COMMAND_VARIABLES_SIZE || + commandObjectPtrsItr != commandObjectPtrs + COMMAND_OBJECT_PTR_SIZE || commandDownloadSlotsItr != commandDownloadSlots + COMMAND_DOWNLOAD_SLOTS_SIZE || commandFileSlotsItr != commandFileSlots + COMMAND_FILE_SLOTS_SIZE || commandFileItrSlotsItr != commandFileItrSlots + COMMAND_FILE_ITR_SLOTS_SIZE || diff --git a/src/command_helpers.h b/src/command_helpers.h index 6931d5b4..199df106 100644 --- a/src/command_helpers.h +++ b/src/command_helpers.h @@ -43,12 +43,14 @@ namespace rpc { class CommandVariable; + class CommandObjectPtr; } // By using a static array we avoid allocating the variables on the // heap. This should reduce memory use and improve cache locality. #define COMMAND_SLOTS_SIZE 200 #define COMMAND_VARIABLES_SIZE 100 +#define COMMAND_OBJECT_PTR_SIZE 20 #define COMMAND_DOWNLOAD_SLOTS_SIZE 150 #define COMMAND_FILE_SLOTS_SIZE 30 #define COMMAND_FILE_ITR_SLOTS_SIZE 10 @@ -62,6 +64,8 @@ extern rpc::CommandSlot commandSlots[COMMAND_SLOTS_SIZE]; extern rpc::CommandSlot* commandSlotsItr; extern rpc::CommandVariable commandVariables[COMMAND_VARIABLES_SIZE]; extern rpc::CommandVariable* commandVariablesItr; +extern rpc::CommandObjectPtr commandObjectPtrs[COMMAND_OBJECT_PTR_SIZE]; +extern rpc::CommandObjectPtr* commandObjectPtrsItr; extern rpc::CommandSlot commandDownloadSlots[COMMAND_DOWNLOAD_SLOTS_SIZE]; extern rpc::CommandSlot* commandDownloadSlotsItr; extern rpc::CommandSlot commandFileSlots[COMMAND_FILE_SLOTS_SIZE]; @@ -220,4 +224,8 @@ add_variable(key, NULL, NULL, &rpc::CommandVariable::get_string, NULL, std::stri #define CMD_FUNC_SINGLE(key, command) \ rpc::commands.insert_type(key, new rpc::CommandFunction(command), &rpc::CommandFunction::call, rpc::CommandMap::flag_public_xmlrpc, NULL, NULL); +#define CMD_OBJ_P(key, function, target) \ + commandObjectPtrsItr->set_object(target); \ + rpc::commands.insert_type(key, commandObjectPtrsItr++, &rpc::CommandObjectPtr::function, rpc::CommandMap::flag_dont_delete | rpc::CommandMap::flag_public_xmlrpc, NULL, NULL); + #endif diff --git a/src/command_local.cc b/src/command_local.cc index fc095ca4..4ea6ba8c 100644 --- a/src/command_local.cc +++ b/src/command_local.cc @@ -169,4 +169,13 @@ initialize_command_local() { ADD_COMMAND_LIST("execute_raw_nothrow", rak::bind2_mem_fn(&rpc::execFile, &rpc::ExecFile::execute_object, 0)); ADD_COMMAND_STRING_UN("execute_log", std::ptr_fun(&apply_execute_log)); + + *rpc::Command::argument(0) = "placeholder.0"; + *rpc::Command::argument(1) = "placeholder.1"; + *rpc::Command::argument(2) = "placeholder.2"; + *rpc::Command::argument(3) = "placeholder.3"; + CMD_OBJ_P("argument.0", get_generic, rpc::Command::argument(0)); + CMD_OBJ_P("argument.1", get_generic, rpc::Command::argument(1)); + CMD_OBJ_P("argument.2", get_generic, rpc::Command::argument(2)); + CMD_OBJ_P("argument.3", get_generic, rpc::Command::argument(3)); } diff --git a/src/main.cc b/src/main.cc index b999a712..d5aaef0f 100644 --- a/src/main.cc +++ b/src/main.cc @@ -179,6 +179,8 @@ main(int argc, char** argv) { // "system.method.insert = test.string,string,6\n" // "system.method.insert = test.bool,bool,true\n" + "system.method.insert = test.method.simple,simple,\"print=simple_test_,$argument.0=\"\n" + "system.method.insert = event.download.inserted,list\n" "system.method.insert = event.download.inserted_new,list\n" "system.method.insert = event.download.inserted_session,list\n" diff --git a/src/rpc/command.h b/src/rpc/command.h index 17919803..7d50dd81 100644 --- a/src/rpc/command.h +++ b/src/rpc/command.h @@ -132,9 +132,18 @@ public: Command() {} virtual ~Command() {} + static torrent::Object* argument(unsigned int index) { return m_arguments + index; } + protected: Command(const Command&); void operator = (const Command&); + + // For use by functions that need to use placeholders to arguments + // within commands. E.d. callable command strings where one of the + // arguments within the command needs to be supplied by the caller. + static const unsigned int max_arguments = 10; + + static torrent::Object m_arguments[max_arguments]; }; template diff --git a/src/rpc/command_function.cc b/src/rpc/command_function.cc index 8e42bddb..45e41d96 100644 --- a/src/rpc/command_function.cc +++ b/src/rpc/command_function.cc @@ -48,20 +48,66 @@ namespace rpc { const torrent::Object CommandFunction::call(Command* rawCommand, target_type target, const torrent::Object& args) { + char* buffer[sizeof(torrent::Object) * Command::max_arguments]; + torrent::Object* stack = (torrent::Object*)buffer; + torrent::Object* first = (torrent::Object*)buffer; + + if (args.is_list()) { + // Do nothing for now. + for (torrent::Object::list_const_iterator itr = args.as_list().begin(), last = args.as_list().end(); + itr != last && first != stack + Command::max_arguments; + itr++, first++) { + new (first) torrent::Object(*itr); + first->swap(*argument(std::distance(stack, first))); + } + + } else if (args.type() != torrent::Object::TYPE_NONE) { + new (first) torrent::Object(args); + (first++)->swap(*argument(0)); + } + CommandFunction* command = reinterpret_cast(rawCommand); parse_command_multiple(target, command->m_command.c_str(), command->m_command.c_str() + command->m_command.size()); + while (first-- != stack) { + first->swap(*argument(std::distance(stack, first))); + first->~Object(); + } + return torrent::Object(); } const torrent::Object CommandFunctionList::call(Command* rawCommand, target_type target, const torrent::Object& args) { + char* buffer[sizeof(torrent::Object) * Command::max_arguments]; + torrent::Object* stack = (torrent::Object*)buffer; + torrent::Object* first = (torrent::Object*)buffer; + + if (args.is_list()) { + // Do nothing for now. + for (torrent::Object::list_const_iterator itr = args.as_list().begin(), last = args.as_list().end(); + itr != last && first != stack + Command::max_arguments; + itr++, first++) { + new (first) torrent::Object(*itr); + first->swap(*argument(std::distance(stack, first))); + } + + } else if (args.type() != torrent::Object::TYPE_NONE) { + new (first) torrent::Object(args); + (first++)->swap(*argument(0)); + } + CommandFunctionList* command = reinterpret_cast(rawCommand); for (base_type::const_iterator itr = command->begin(), last = command->end(); itr != last; itr++) parse_command_multiple(target, itr->second.c_str(), itr->second.c_str() + itr->second.size()); + while (first-- != stack) { + first->swap(*argument(std::distance(stack, first))); + first->~Object(); + } + return torrent::Object(); } diff --git a/src/rpc/command_map.cc b/src/rpc/command_map.cc index 9c1f8ccf..48910013 100644 --- a/src/rpc/command_map.cc +++ b/src/rpc/command_map.cc @@ -55,6 +55,8 @@ namespace rpc { +torrent::Object Command::m_arguments[Command::max_arguments]; + CommandMap::~CommandMap() { std::vector keys; diff --git a/src/rpc/command_variable.cc b/src/rpc/command_variable.cc index e6602bdd..fb2e6647 100644 --- a/src/rpc/command_variable.cc +++ b/src/rpc/command_variable.cc @@ -148,4 +148,22 @@ CommandVariable::get_string(Command* rawCommand, cleaned_type target, const torr return variable->m_variable; } +// +// ObjectPtr +// + +const torrent::Object +CommandObjectPtr::set_generic(Command* rawCommand, cleaned_type target, const torrent::Object& rawArgs) { + CommandObjectPtr* command = static_cast(rawCommand); + + return (*command->m_object = rawArgs); +} + +const torrent::Object +CommandObjectPtr::get_generic(Command* rawCommand, cleaned_type target, const torrent::Object& args) { + CommandObjectPtr* command = static_cast(rawCommand); + + return *command->m_object; +} + } diff --git a/src/rpc/command_variable.h b/src/rpc/command_variable.h index bad29c84..06f64b5f 100644 --- a/src/rpc/command_variable.h +++ b/src/rpc/command_variable.h @@ -68,6 +68,31 @@ private: torrent::Object m_variable; }; +class CommandObjectPtr : public Command { +public: + typedef target_wrapper::cleaned_type cleaned_type; + + CommandObjectPtr(torrent::Object* obj = NULL) : m_object(obj) {} + + const torrent::Object* object() const { return m_object; } + void set_object(torrent::Object* obj) { m_object = obj; } + + static const torrent::Object set_generic(Command* rawCommand, cleaned_type target, const torrent::Object& args); + static const torrent::Object get_generic(Command* rawCommand, cleaned_type target, const torrent::Object& args); + +// static const torrent::Object set_bool(Command* rawCommand, cleaned_type target, const torrent::Object& args); +// static const torrent::Object get_bool(Command* rawCommand, cleaned_type target, const torrent::Object& args); + +// static const torrent::Object set_value(Command* rawCommand, cleaned_type target, const torrent::Object& args); +// static const torrent::Object get_value(Command* rawCommand, cleaned_type target, const torrent::Object& args); + +// static const torrent::Object set_string(Command* rawCommand, cleaned_type target, const torrent::Object& args); +// static const torrent::Object get_string(Command* rawCommand, cleaned_type target, const torrent::Object& args); + +private: + torrent::Object* m_object; +}; + } #endif