/* $Id$
This file is part of gldbg
-Copyright © 2009 Mikko Rasa, Mikkosoft Productions
+Copyright © 2009-2010 Mikko Rasa, Mikkosoft Productions
Distributed under the GPL
*/
#include <signal.h>
#include <readline/readline.h>
#include <msp/core/except.h>
-#include <msp/io/file.h>
#include <msp/io/print.h>
#include <msp/strings/lexicalcast.h>
#include <msp/strings/utils.h>
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");
+ 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");
- 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"
- "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");
}
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<string, Command>::const_iterator i=commands.begin(); i!=commands.end(); ++i)
- IO::print("%-10s : %s\n", i->first, i->second.description);
+ for(CommandMap::const_iterator i=commands.begin(); i!=commands.end(); ++i)
+ if(!dynamic_cast<const CommandAlias *>(i->second))
+ IO::print("%-10s : %s\n", i->first, i->second->get_description());
}
else
{
- map<string, Command>::const_iterator i = commands.find(args);
+ CommandMap::const_iterator i = commands.find(args);
if(i==commands.end())
throw KeyError("Unknown command", args);
- IO::print("%s : %s\n", i->first, i->second.description);
- if(!i->second.help.empty())
- IO::print("\n%s", i->second.help);
+
+ const Command *cmd = i->second;
+ while(const CommandAlias *alias = dynamic_cast<const CommandAlias *>(cmd))
+ cmd = alias->get_target();
+
+ IO::print("%s : %s\n", i->first, cmd->get_description());
+ if(!cmd->get_help().empty())
+ IO::print("\n%s", cmd->get_help());
}
}
gldbg.quit(false);
}
-void CommandInterpreter::cmd_trace(const string &args)
-{
- Tracer &tracer = gldbg.get_tracer();
- if(args.empty() || args=="-")
- {
- tracer.set_output(IO::cout);
- IO::print("Tracing to stdout\n");
- }
- else if(args=="on")
- {
- tracer.enable();
- IO::print("Tracing enabled\n");
- }
- else if(args=="off")
- {
- tracer.disable();
- IO::print("Tracing disabled\n");
- }
- else if(args=="end")
- {
- tracer.set_output(0);
- IO::print("Tracing terminated\n");
- }
- else
- {
- tracer.set_output(new IO::File(args, IO::M_WRITE));
- IO::print("Tracing to %s\n", args);
- }
-}
-void CommandInterpreter::cmd_profile(const string &args)
+void CommandInterpreter::Command::set_help(const string &d)
{
- Profiler &profiler = gldbg.get_profiler();
- if(args.empty() || args=="on")
- profiler.enable();
- else if(args=="off")
- profiler.disable();
- else
- throw InvalidParameterValue("Invalid argument");
+ description = d;
}
-void CommandInterpreter::cmd_state(const string &args)
+void CommandInterpreter::Command::set_help(const string &d, const string &h)
{
- const GlState &glstate = gldbg.get_glstate();
- if(args=="vertex")
- {
- IO::print("Current vertex attributes:\n");
- const Vector4 &color = glstate.get_color();
- IO::print(" Color: [%05.3f, %05.3f, %05.3f, %05.3f]\n", color.r, color.g, color.b, color.a);
- for(unsigned i=0; i<8; ++i)
- {
- const Vector4 &texcoord = glstate.get_texcoord(i);
- IO::print(" TexCoord%d: [%05.3f, %05.3f, %05.3f, %05.3f]\n", i, texcoord.s, texcoord.t, texcoord.p, texcoord.q);
- }
- const Vector3 &normal = glstate.get_normal();
- IO::print(" Normal: [%05.3f, %05.3f, %05.3f]\n", normal.x, normal.y, normal.z);
- }
- else if(args=="bind")
- {
- IO::print("Current bindings:\n");
- for(unsigned i=0; i<8; ++i)
- {
- IO::print(" Texture unit %d:\n", i);
- const TexUnitState &unit = glstate.get_texture_unit(i);
- IO::print(" GL_TEXTURE_2D: %s\n", unit.describe_binding(GL_TEXTURE_2D));
- IO::print(" GL_TEXTURE_3D: %s\n", unit.describe_binding(GL_TEXTURE_3D));
- }
- IO::print(" Buffers:\n");
- const BufferState *buf = glstate.get_current_buffer(GL_ARRAY_BUFFER);
- IO::print(" GL_ARRAY_BUFFER: %d\n", (buf ? buf->id : 0));
- buf = glstate.get_current_buffer(GL_ELEMENT_ARRAY_BUFFER);
- IO::print(" GL_ELEMENT_ARRAY_BUFFER: %d\n", (buf ? buf->id : 0));
- }
- else
- throw InvalidParameterValue("Invalid or missing argument");
-}
-
-void CommandInterpreter::cmd_texture(const string &args)
-{
- if(args.empty())
- {
- const map<unsigned, TextureState> &textures = gldbg.get_glstate().get_textures();
- IO::print("%d texture objects:\n", textures.size());
- for(map<unsigned, TextureState>::const_iterator i = textures.begin(); i!=textures.end(); ++i)
- {
- const TextureState &tex = i->second;
- IO::print(" %d: %s, %d images\n", i->first, tex.describe(), tex.images.size());
- }
- }
- else
- {
- unsigned id = lexical_cast<unsigned>(args);
- const TextureState &tex = gldbg.get_glstate().get_texture(id);
- IO::print("Texture object %d\n", id);
- IO::print(" Target: %s\n", describe_enum(tex.target, "TextureTarget"));
- IO::print(" Images:\n");
- for(unsigned i=0; i<tex.images.size(); ++i)
- {
- const TexImageState &img = tex.images[i];
- IO::print(" Level %2d: %s\n", i, img.describe());
- }
- IO::print(" Min. filter: %s\n", describe_enum(tex.min_filter, "TextureMinFilter"));
- IO::print(" Mag. filter: %s\n", describe_enum(tex.mag_filter, "TextureMagFilter"));
- IO::print(" Wrap modes: S=%s / T=%s / R=%s\n", describe_enum(tex.wrap_s, "TextureWrapMode"),
- describe_enum(tex.wrap_t, "TextureWrapMode"), describe_enum(tex.wrap_r, "TextureWrapMode"));
- IO::print(" Compare mode: %s\n", describe_enum(tex.compare_mode, ""));
- IO::print(" Compare func: %s\n", describe_enum(tex.compare_func, "DepthFunction"));
- IO::print(" Generate mipmap: %s\n", tex.generate_mipmap);
- }
+ description = d;
+ help = h;
}
-void CommandInterpreter::cmd_buffer(const string &args)
-{
- if(args.empty())
- {
- const GlState::BufferMap &buffers = gldbg.get_glstate().get_buffers();
- IO::print("%d buffers:\n", buffers.size());
- for(GlState::BufferMap::const_iterator i=buffers.begin(); i!=buffers.end(); ++i)
- IO::print(" %d: %s\n", i->first, i->second.describe());
- }
- else
- {
- unsigned id = lexical_cast<unsigned>(args);
- const BufferState &buf = gldbg.get_glstate().get_buffer(id);
- IO::print("Buffer %d:\n", id);
- IO::print(" Size: %d bytes\n", buf.size);
- IO::print(" Usage: %s\n", describe_enum(buf.usage, ""));
- }
-}
-
-
-CommandInterpreter::Command::Command():
- func(0)
-{ }
-CommandInterpreter::Command::Command(Func f, const string &d):
- func(f),
- description(d)
+CommandInterpreter::CommandAlias::CommandAlias(Command *t):
+ target(t)
{ }
-CommandInterpreter::Command::Command(Func f, const string &d, const string &h):
- func(f),
- description(d),
- help(h)
-{ }
+void CommandInterpreter::CommandAlias::execute(const string &a)
+{
+ target->execute(a);
+}