From de6ac03ffc36843bbbb0d496007b3046a4422ee1 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Wed, 16 Jun 2010 15:58:05 +0000 Subject: [PATCH] Add framework necessary to support more modular tools --- Makefile | 3 +- source/commandinterpreter.cpp | 176 +++++++++++++++++----------------- source/commandinterpreter.h | 57 +++++++++-- source/gldbg.cpp | 11 ++- source/gldbg.h | 6 +- source/tool.cpp | 22 +++++ source/tool.h | 57 +++++++++++ 7 files changed, 229 insertions(+), 103 deletions(-) create mode 100644 source/tool.cpp create mode 100644 source/tool.h diff --git a/Makefile b/Makefile index 119aef3..1adeb64 100644 --- a/Makefile +++ b/Makefile @@ -30,7 +30,8 @@ SOURCES_gldbg := source/gldbg.cpp \ source/texturestate.cpp \ source/bufferstate.cpp \ source/profiler.cpp \ - source/arraystate.cpp + source/arraystate.cpp \ + source/tool.cpp TEMPLATES := source/functions.enum.t \ source/gldecoder.funcs.t \ source/gldecoder.struct.t \ diff --git a/source/commandinterpreter.cpp b/source/commandinterpreter.cpp index e73494c..367ac17 100644 --- a/source/commandinterpreter.cpp +++ b/source/commandinterpreter.cpp @@ -23,66 +23,66 @@ using namespace Msp; CommandInterpreter::CommandInterpreter(GlDbg &d): gldbg(d) { - commands["help"] = Command(&CommandInterpreter::cmd_help, - "Provides help on commands", - "help\n" - " Displays a list of commands\n\n" - "help COMMAND\n" - " Gives detailed information on a command\n"); - commands["exit"] = Command(&CommandInterpreter::cmd_exit, - "Ends the debugging session"); - commands["quit"] = Command(&commands["exit"]); - - commands["run"] = Command(&CommandInterpreter::cmd_run, - "Starts the program"); - commands["continue"] = Command(&CommandInterpreter::cmd_continue, - "Resumes program execution"); - commands["kill"] = Command(&CommandInterpreter::cmd_kill, - "Terminates the program immediately"); - commands["signal"] = Command(&CommandInterpreter::cmd_signal, - "Resumes execution with a signal", - "signal NUM\n" - "signal NAME\n" - " Sends the signal identified by NUM or NAME to the program and resumes\n" - " execution. Currently recognized signal names are HUP, INT, TERM, SEGV\n" - " and TERM.\n"); - - commands["trace"] = Command(&CommandInterpreter::cmd_trace, - "Traces GL function calls", - "trace\n" - " Send trace output to stdout.\n\n" - "trace FILE\n" - " Send trace output to FILE (- for stdout).\n\n" - "trace {off|on}\n" - " Temporarily suspend or resume trace without closing the file.\n\n" - "trace end\n" - " Terminate trace, closing the file.\n"); - - commands["profile"] = Command(&CommandInterpreter::cmd_profile, - "Profiles GL usage and performance", - "profile {on|off}\n" - " Enables or disables profiling\n"); - - commands["state"] = Command(&CommandInterpreter::cmd_state, - "Inspects general GL state", - "state vertex\n" - " Print current vertex attributes\n\n" - "state bind\n" - " Show current bindings\n"); - - commands["texture"] = Command(&CommandInterpreter::cmd_texture, - "Inspect texture state", - "texture\n" - " Lists texture objects\n\n" - "texture ID\n" - " Print information about a texture object\n"); - - commands["buffer"] = Command(&CommandInterpreter::cmd_buffer, - "Inspect buffer object state", - "buffer\n" - " Lists buffer objects\n\n" - "buffer ID\n" - " Print information about a buffer object\n"); + register_command("help", this, &CommandInterpreter::cmd_help) + .set_help("Provides help on commands", + "help\n" + " Displays a list of commands\n\n" + "help COMMAND\n" + " Gives detailed information on a command\n"); + register_command("exit", this, &CommandInterpreter::cmd_exit) + .set_help("Ends the debugging session"); + commands["quit"] = new CommandAlias(commands["exit"]); + + register_command("run", this, &CommandInterpreter::cmd_run) + .set_help("Starts the program"); + register_command("continue", this, &CommandInterpreter::cmd_continue) + .set_help("Resumes program execution"); + register_command("kill", this, &CommandInterpreter::cmd_kill) + .set_help("Terminates the program immediately"); + register_command("signal", this, &CommandInterpreter::cmd_signal) + .set_help("Resumes execution with a signal", + "signal NUM\n" + "signal NAME\n" + " Sends the signal identified by NUM or NAME to the program and resumes\n" + " execution. Currently recognized signal names are HUP, INT, TERM, SEGV\n" + " and TERM.\n"); + + register_command("trace", this, &CommandInterpreter::cmd_trace) + .set_help("Traces GL function calls", + "trace\n" + " Send trace output to stdout.\n\n" + "trace FILE\n" + " Send trace output to FILE (- for stdout).\n\n" + "trace {off|on}\n" + " Temporarily suspend or resume trace without closing the file.\n\n" + "trace end\n" + " Terminate trace, closing the file.\n"); + + register_command("profile", this, &CommandInterpreter::cmd_profile) + .set_help("Profiles GL usage and performance", + "profile {on|off}\n" + " Enables or disables profiling\n"); + + register_command("state", this, &CommandInterpreter::cmd_state) + .set_help("Inspects general GL state", + "state vertex\n" + " Print current vertex attributes\n\n" + "state bind\n" + " Show current bindings\n"); + + register_command("texture", this, &CommandInterpreter::cmd_texture) + .set_help("Inspect texture state", + "texture\n" + " Lists texture objects\n\n" + "texture ID\n" + " Print information about a texture object\n"); + + register_command("buffer", this, &CommandInterpreter::cmd_buffer) + .set_help("Inspect buffer object state", + "buffer\n" + " Lists buffer objects\n\n" + "buffer ID\n" + " Print information about a buffer object\n"); } void CommandInterpreter::execute(const string &cmd) @@ -103,30 +103,30 @@ void CommandInterpreter::execute(const string &cmd) if(space!=string::npos) args = cmd.substr(space+1); - (this->*(i->second.func))(args); + i->second->execute(args); } void CommandInterpreter::cmd_help(const string &args) { if(args.empty()) { - for(map::const_iterator i=commands.begin(); i!=commands.end(); ++i) - if(!i->second.alias_for) - IO::print("%-10s : %s\n", i->first, i->second.description); + for(CommandMap::const_iterator i=commands.begin(); i!=commands.end(); ++i) + if(!dynamic_cast(i->second)) + IO::print("%-10s : %s\n", i->first, i->second->get_description()); } else { - map::const_iterator i = commands.find(args); + CommandMap::const_iterator i = commands.find(args); if(i==commands.end()) throw KeyError("Unknown command", args); - const Command *cmd = &i->second; - while(cmd->alias_for) - cmd = cmd->alias_for; + const Command *cmd = i->second; + while(const CommandAlias *alias = dynamic_cast(cmd)) + cmd = alias->get_target(); - IO::print("%s : %s\n", i->first, cmd->description); - if(!i->second.help.empty()) - IO::print("\n%s", cmd->help); + IO::print("%s : %s\n", i->first, cmd->get_description()); + if(!cmd->get_help().empty()) + IO::print("\n%s", cmd->get_help()); } } @@ -397,25 +397,23 @@ void CommandInterpreter::cmd_buffer(const string &args) } -CommandInterpreter::Command::Command(): - func(0), - alias_for(0) -{ } +void CommandInterpreter::Command::set_help(const string &d) +{ + description = d; +} -CommandInterpreter::Command::Command(Command *cmd): - func(cmd->func), - alias_for(cmd) -{ } +void CommandInterpreter::Command::set_help(const string &d, const string &h) +{ + description = d; + help = h; +} -CommandInterpreter::Command::Command(Func f, const string &d): - func(f), - description(d), - alias_for(0) -{ } -CommandInterpreter::Command::Command(Func f, const string &d, const string &h): - func(f), - description(d), - help(h), - alias_for(0) +CommandInterpreter::CommandAlias::CommandAlias(Command *t): + target(t) { } + +void CommandInterpreter::CommandAlias::execute(const string &a) +{ + target->execute(a); +} diff --git a/source/commandinterpreter.h b/source/commandinterpreter.h index 537245f..487abb2 100644 --- a/source/commandinterpreter.h +++ b/source/commandinterpreter.h @@ -15,29 +15,66 @@ class GlDbg; class CommandInterpreter { -private: +public: struct Command { - typedef void (CommandInterpreter::*Func)(const std::string &); - - Func func; + private: std::string description; std::string help; - Command *alias_for; - Command(); - Command(Command *); - Command(Func, const std::string &); - Command(Func, const std::string &, const std::string &); + protected: + Command() { } + + public: + void set_help(const std::string &); + void set_help(const std::string &, const std::string &); + const std::string &get_description() const { return description; } + const std::string &get_help() const { return help; } + + virtual void execute(const std::string &) = 0; }; - typedef std::map CommandMap; +private: + template + class CommandFunction: public Command + { + private: + typedef void (T::*Func)(const std::string &); + + T *obj; + Func func; + public: + CommandFunction(T *o, Func f): obj(o), func(f) { } + + virtual void execute(const std::string &a) + { (obj->*func)(a); } + }; + + class CommandAlias: public Command + { + private: + Command *target; + + public: + CommandAlias(Command *); + + const Command *get_target() const { return target; } + + virtual void execute(const std::string &); + }; + + typedef std::map CommandMap; GlDbg &gldbg; CommandMap commands; public: CommandInterpreter(GlDbg &); + + template + Command ®ister_command(const std::string &n, T *o, void (T::*f)(const std::string &)) + { return *(commands[n] = new CommandFunction(o, f)); } + void execute(const std::string &); private: diff --git a/source/gldbg.cpp b/source/gldbg.cpp index d18ff51..bc621ce 100644 --- a/source/gldbg.cpp +++ b/source/gldbg.cpp @@ -1,7 +1,7 @@ /* $Id$ This file is part of gldbg -Copyright © 2009 Mikko Rasa, Mikkosoft Productions +Copyright © 2009-2010 Mikko Rasa, Mikkosoft Productions Distributed under the GPL */ @@ -17,6 +17,7 @@ Distributed under the GPL #include #include "gldbg.h" #include "glprint.h" +#include "tool.h" using namespace std; using namespace Msp; @@ -32,6 +33,10 @@ GlDbg::GlDbg(int argc, char **argv): { FS::Path libdir = FS::get_sys_lib_dir(argv[0], "gldbg"); process.setenv("LD_PRELOAD", (libdir/"glwrap.so").str().c_str()); + + const list &factories = Tool::get_factories(); + for(list::const_iterator i=factories.begin(); i!=factories.end(); ++i) + tools.push_back((*i)->create(*this)); } int GlDbg::main() @@ -133,6 +138,8 @@ void GlDbg::read_stream() int size = gldecoder_decode(0, data, len); if(size<0) break; + for(list::iterator i=tools.begin(); i!=tools.end(); ++i) + (*i)->decode(data, size); tracer.decode(data, len); glstate.decode(data, len); profiler.decode(data, len); @@ -141,7 +148,7 @@ void GlDbg::read_stream() if(buf_offset>8192) { buffer.erase(0, buf_offset); - buf_offset=0; + buf_offset = 0; } } } diff --git a/source/gldbg.h b/source/gldbg.h index e42e4aa..543df05 100644 --- a/source/gldbg.h +++ b/source/gldbg.h @@ -1,7 +1,7 @@ /* $Id$ This file is part of gldbg -Copyright © 2009 Mikko Rasa, Mikkosoft Productions +Copyright © 2009-2010 Mikko Rasa, Mikkosoft Productions Distributed under the GPL */ @@ -18,6 +18,8 @@ Distributed under the GPL #include "profiler.h" #include "tracer.h" +class Tool; + class GlDbg: public Msp::Application { private: @@ -27,6 +29,7 @@ private: std::string buffer; unsigned buf_offset; bool flushing; + std::list tools; Tracer tracer; GlState glstate; Profiler profiler; @@ -37,6 +40,7 @@ private: public: GlDbg(int, char **); int main(); + CommandInterpreter &get_command_interpreter() { return cmd_interp; } Tracer &get_tracer() { return tracer; } GlState &get_glstate() { return glstate; } Profiler &get_profiler() { return profiler; } diff --git a/source/tool.cpp b/source/tool.cpp new file mode 100644 index 0000000..0e2cae1 --- /dev/null +++ b/source/tool.cpp @@ -0,0 +1,22 @@ +/* $Id$ + +This file is part of gldbg +Copyright © 2010 Mikko Rasa, Mikkosoft Productions +Distributed under the GPL +*/ + +#include "tool.h" + +using namespace std; + +list &Tool::get_factories() +{ + static list factories; + return factories; +} + + +Tool::Factory::Factory() +{ + get_factories().push_back(this); +} diff --git a/source/tool.h b/source/tool.h new file mode 100644 index 0000000..b299e2a --- /dev/null +++ b/source/tool.h @@ -0,0 +1,57 @@ +/* $Id$ + +This file is part of gldbg +Copyright © 2010 Mikko Rasa, Mikkosoft Productions +Distributed under the GPL +*/ + +#ifndef TOOL_H_ +#define TOOL_H_ + +#include + +class GlDbg; + +class Tool +{ +public: + class Factory + { + protected: + Factory(); + + public: + virtual Tool *create(GlDbg &) const = 0; + }; + +protected: + Tool() { } +public: + virtual ~Tool() { } + + virtual void decode(const char *, unsigned) = 0; + + static std::list &get_factories(); +}; + + +template +class RegisteredTool: public Tool +{ +protected: + class Factory: public Tool::Factory + { + virtual Tool *create(GlDbg &g) const { return new T(g); } + }; + + static Factory factory; + +protected: + // The no-op expression is necessary to instantiate the static member + RegisteredTool() { (void)factory; } +}; + +template +typename RegisteredTool::Factory RegisteredTool::factory; + +#endif -- 2.43.0