]> git.tdb.fi Git - gldbg.git/blob - source/commandinterpreter.cpp
Add help
[gldbg.git] / source / commandinterpreter.cpp
1 /* $Id$
2
3 This file is part of gldbg
4 Copyright © 2009  Mikko Rasa, Mikkosoft Productions
5 Distributed under the GPL
6 */
7
8 #include <signal.h>
9 #include <msp/core/except.h>
10 #include <msp/io/file.h>
11 #include <msp/io/print.h>
12 #include <msp/strings/lexicalcast.h>
13 #include <msp/strings/utils.h>
14 #include "commandinterpreter.h"
15 #include "gldbg.h"
16 #include "tracer.h"
17
18 using namespace std;
19 using namespace Msp;
20
21 CommandInterpreter::CommandInterpreter(GlDbg &d):
22         gldbg(d)
23 {
24         commands["help"] = Command(&CommandInterpreter::cmd_help,
25                 "Provides help on commands",
26                 "help\n"
27                 "  Displays a list of commands\n\n"
28                 "help COMMAND\n"
29                 "  Gives detailed information on a command\n");
30         commands["exit"] = Command(&CommandInterpreter::cmd_exit,
31                 "Ends the debugging session");
32
33         commands["run"] = Command(&CommandInterpreter::cmd_run,
34                 "Starts the program");
35         commands["continue"] = Command(&CommandInterpreter::cmd_continue,
36                 "Resumes program execution");
37         commands["kill"] = Command(&CommandInterpreter::cmd_kill,
38                 "Terminates the program immediately");
39         commands["signal"] = Command(&CommandInterpreter::cmd_signal,
40                 "Resumes execution with a signal",
41                 "signal NUM\n"
42                 "signal NAME\n"
43                 "  Sends the signal identified by NUM or NAME to the program and resumes\n"
44                 "  execution.  Currently recognized signal names are HUP, INT, TERM, SEGV\n"
45                 "  and TERM.\n");
46
47         commands["trace"] = Command(&CommandInterpreter::cmd_trace,
48                 "Traces GL function calls",
49                 "trace >FILE\n"
50                 "  Send trace output to FILE.  As a special case, - means stdout.\n\n"
51                 "trace {off|on}\n"
52                 "  Temporarily suspend or resume trace without closing the file.\n\n"
53                 "trace end\n"
54                 "  Terminate trace, closing the file.\n");
55 }
56
57 void CommandInterpreter::execute(const string &cmd)
58 {
59         unsigned space = cmd.find(' ');
60         string name = cmd.substr(0, space);
61         CommandMap::const_iterator i = commands.lower_bound(name);
62         if(i==commands.end() || i->first.compare(0, name.size(), name))
63                 throw KeyError("Unknown command", name);
64         if(i->first!=name)
65         {
66                 CommandMap::const_iterator j = i;
67                 if((++j)!=commands.end() && !j->first.compare(0, name.size(), name))
68                         throw KeyError("Ambiguous command", name);
69         }
70
71         string args;
72         if(space!=string::npos)
73                 args = cmd.substr(space+1);
74
75         (this->*(i->second.func))(args);
76 }
77
78 void CommandInterpreter::cmd_help(const string &args)
79 {
80         if(args.empty())
81         {
82                 for(map<string, Command>::const_iterator i=commands.begin(); i!=commands.end(); ++i)
83                         IO::print("%-10s : %s\n", i->first, i->second.description);
84         }
85         else
86         {
87                 map<string, Command>::const_iterator i = commands.find(args);
88                 if(i==commands.end())
89                         throw KeyError("Unknown command", args);
90                 IO::print("%s : %s\n", i->first, i->second.description);
91                 if(!i->second.help.empty())
92                         IO::print("\n%s", i->second.help);
93         }
94 }
95
96 void CommandInterpreter::cmd_run(const string &)
97 {
98         gldbg.launch();
99 }
100
101 void CommandInterpreter::cmd_continue(const string &)
102 {
103         gldbg.get_process().resume();
104 }
105
106 void CommandInterpreter::cmd_signal(const string &args)
107 {
108         unsigned sig = 0;
109         if(args=="HUP" || args=="SIGHUP")
110                 sig = SIGHUP;
111         else if(args=="INT" || args=="SIGINT")
112                 sig = SIGINT;
113         else if(args=="ILL" || args=="SIGILL")
114                 sig = SIGILL;
115         else if(args=="SEGV" || args=="SIGSEGV")
116                 sig = SIGSEGV;
117         else if(args=="TERM" || args=="SIGTERM")
118                 sig = SIGTERM;
119         else if(isnumrc(args))
120                 sig = lexical_cast<unsigned>(args);
121         else
122                 throw InvalidParameterValue("Invalid signal specification");
123         gldbg.get_process().resume(sig);
124 }
125
126 void CommandInterpreter::cmd_kill(const string &)
127 {
128         gldbg.get_process().kill();
129 }
130
131 void CommandInterpreter::cmd_exit(const string &)
132 {
133         gldbg.quit();
134 }
135
136 void CommandInterpreter::cmd_trace(const string &args)
137 {
138         Tracer &tracer = gldbg.get_tracer();
139         if(args[0]=='>')
140         {
141                 string fn = args.substr(1);
142                 if(fn=="-")
143                 {
144                         tracer.set_output(IO::cout);
145                         IO::print("Tracing to stdout\n");
146                 }
147                 else
148                 {
149                         tracer.set_output(new IO::File(fn, IO::M_WRITE));
150                         IO::print("Tracing to %s\n", fn);
151                 }
152         }
153         else
154         {
155                 if(args=="on")
156                 {
157                         tracer.enable();
158                         IO::print("Tracing enabled\n");
159                 }
160                 else if(args=="off")
161                 {
162                         tracer.disable();
163                         IO::print("Tracing disabled\n");
164                 }
165                 else if(args=="end")
166                 {
167                         tracer.set_output(0);
168                         IO::print("Tracing terminated\n");
169                 }
170         }
171 }
172
173
174 CommandInterpreter::Command::Command():
175         func(0)
176 { }
177
178 CommandInterpreter::Command::Command(Func f, const string &d):
179         func(f),
180         description(d)
181 { }
182
183 CommandInterpreter::Command::Command(Func f, const string &d, const string &h):
184         func(f),
185         description(d),
186         help(h)
187 { }