blob: f21938f5fe2c30038de68ad2228ae33fc151825a [file] [log] [blame]
Jim Ingham767af882010-07-07 03:36:20 +00001//===-- CommandObjectSource.cpp ---------------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "CommandObjectCommands.h"
11
12// C Includes
13// C++ Includes
14// Other libraries and framework includes
15// Project includes
16#include "lldb/Interpreter/Args.h"
17#include "lldb/Core/Debugger.h"
18#include "lldb/Interpreter/CommandInterpreter.h"
19#include "lldb/Interpreter/CommandReturnObject.h"
20#include "lldb/Interpreter/Options.h"
21
22using namespace lldb;
23using namespace lldb_private;
24
25const char *k_space_characters = "\t\n\v\f\r ";
26
27//-------------------------------------------------------------------------
28// CommandObjectCommandsSource
29//-------------------------------------------------------------------------
30
31class CommandObjectCommandsSource : public CommandObject
32{
33public:
Greg Clayton238c0a12010-09-18 01:14:36 +000034 CommandObjectCommandsSource(CommandInterpreter &interpreter) :
35 CommandObject (interpreter,
36 "commands source",
37 "Read in debugger commands from the file <filename> and execute them.",
38 "command source <filename>")
Jim Ingham767af882010-07-07 03:36:20 +000039 {
40 }
41
42 ~CommandObjectCommandsSource ()
43 {
44 }
45
46 bool
47 Execute
48 (
Jim Ingham767af882010-07-07 03:36:20 +000049 Args& args,
50 CommandReturnObject &result
51 )
52 {
53 const int argc = args.GetArgumentCount();
54 if (argc == 1)
55 {
56 const char *filename = args.GetArgumentAtIndex(0);
57 bool success = true;
58
59 result.AppendMessageWithFormat ("Executing commands in '%s'.\n", filename);
60
61 FileSpec cmd_file (filename);
62 if (cmd_file.Exists())
63 {
64 STLStringArray commands;
65 success = cmd_file.ReadFileLines (commands);
66
67 STLStringArray::iterator pos = commands.begin();
68
69 // Trim out any empty lines or lines that start with the comment
70 // char '#'
71 while (pos != commands.end())
72 {
Jim Ingham767af882010-07-07 03:36:20 +000073 size_t non_space = pos->find_first_not_of (k_space_characters);
Greg Claytona830adb2010-10-04 01:05:56 +000074 // Check for empty line or comment line (lines whose first
75 // non-space character is a '#')
76 if (non_space == std::string::npos || (*pos)[non_space] == '#')
Jim Ingham767af882010-07-07 03:36:20 +000077 pos = commands.erase(pos);
78 else
79 ++pos;
80 }
81
82 if (commands.size() > 0)
83 {
84 const size_t num_commands = commands.size();
85 size_t i;
86 for (i = 0; i<num_commands; ++i)
87 {
Greg Clayton238c0a12010-09-18 01:14:36 +000088 result.GetOutputStream().Printf ("%s %s\n",
89 m_interpreter.GetPrompt(),
90 commands[i].c_str());
91 if (!m_interpreter.HandleCommand(commands[i].c_str(), false, result))
Jim Ingham767af882010-07-07 03:36:20 +000092 break;
93 }
94
95 if (i < num_commands)
96 {
97 result.AppendErrorWithFormat("Aborting source of '%s' after command '%s' failed.\n",
98 filename, commands[i].c_str());
99 result.SetStatus (eReturnStatusSuccessFinishResult);
100 }
101 else
102 {
103 success = true;
104 result.SetStatus (eReturnStatusFailed);
105 }
106 }
107 }
108 else
109 {
110 result.AppendErrorWithFormat ("File '%s' does not exist.\n", filename);
111 result.SetStatus (eReturnStatusFailed);
112 success = false;
113 }
114
115 if (success)
116 {
117 result.SetStatus (eReturnStatusSuccessFinishNoResult);
118 }
119 }
120 else
121 {
122 result.AppendErrorWithFormat("'%s' takes exactly one executable filename argument.\n", GetCommandName());
123 result.SetStatus (eReturnStatusFailed);
124 }
125 return result.Succeeded();
126
127 }
128};
129
130#pragma mark CommandObjectCommandsAlias
131//-------------------------------------------------------------------------
132// CommandObjectCommandsAlias
133//-------------------------------------------------------------------------
134
135class CommandObjectCommandsAlias : public CommandObject
136{
137public:
Greg Clayton238c0a12010-09-18 01:14:36 +0000138 CommandObjectCommandsAlias (CommandInterpreter &interpreter) :
139 CommandObject (interpreter,
140 "commands alias",
Caroline Ticeabb507a2010-09-08 21:06:11 +0000141 "Allow users to define their own debugger command abbreviations.",
142 "commands alias <new_command> <old_command> [<options-for-aliased-command>]")
Jim Ingham767af882010-07-07 03:36:20 +0000143 {
144 SetHelpLong(
145 "'alias' allows the user to create a short-cut or abbreviation for long \n\
146 commands, multi-word commands, and commands that take particular options. \n\
147 Below are some simple examples of how one might use the 'alias' command: \n\
Caroline Tice31fbb642010-09-08 22:08:58 +0000148 \n 'commands alias sc script' // Creates the abbreviation 'sc' for the 'script' \n\
149 // command. \n\
150 'commands alias bp breakpoint' // Creates the abbreviation 'bp' for the 'breakpoint' \n\
151 // command. Since breakpoint commands are two-word \n\
152 // commands, the user will still need to enter the \n\
153 // second word after 'bp', e.g. 'bp enable' or \n\
154 // 'bp delete'. \n\
155 'commands alias bpl breakpoint list' // Creates the abbreviation 'bpl' for the \n\
156 // two-word command 'breakpoint list'. \n\
Jim Ingham767af882010-07-07 03:36:20 +0000157 \nAn alias can include some options for the command, with the values either \n\
158 filled in at the time the alias is created, or specified as positional \n\
159 arguments, to be filled in when the alias is invoked. The following example \n\
160 shows how to create aliases with options: \n\
161 \n\
Caroline Tice31fbb642010-09-08 22:08:58 +0000162 'commands alias bfl breakpoint set -f %1 -l %2' \n\
Jim Ingham767af882010-07-07 03:36:20 +0000163 \nThis creates the abbreviation 'bfl' (for break-file-line), with the -f and -l \n\
164 options already part of the alias. So if the user wants to set a breakpoint \n\
165 by file and line without explicitly having to use the -f and -l options, the \n\
166 user can now use 'bfl' instead. The '%1' and '%2' are positional placeholders \n\
167 for the actual arguments that will be passed when the alias command is used. \n\
168 The number in the placeholder refers to the position/order the actual value \n\
169 occupies when the alias is used. So all the occurrences of '%1' in the alias \n\
170 will be replaced with the first argument, all the occurrences of '%2' in the \n\
171 alias will be replaced with the second argument, and so on. This also allows \n\
172 actual arguments to be used multiple times within an alias (see 'process \n\
173 launch' example below). So in the 'bfl' case, the actual file value will be \n\
174 filled in with the first argument following 'bfl' and the actual line number \n\
175 value will be filled in with the second argument. The user would use this \n\
176 alias as follows: \n\
Caroline Tice31fbb642010-09-08 22:08:58 +0000177 \n (lldb) commands alias bfl breakpoint set -f %1 -l %2 \n\
Sean Callanana3aff732010-08-09 18:50:15 +0000178 <... some time later ...> \n\
Caroline Tice31fbb642010-09-08 22:08:58 +0000179 (lldb) bfl my-file.c 137 \n\
Jim Ingham767af882010-07-07 03:36:20 +0000180 \nThis would be the same as if the user had entered \n\
181 'breakpoint set -f my-file.c -l 137'. \n\
182 \nAnother example: \n\
Caroline Tice31fbb642010-09-08 22:08:58 +0000183 \n (lldb) commands alias pltty process launch -s -o %1 -e %1 \n\
184 (lldb) pltty /dev/tty0 \n\
Sean Callanana3aff732010-08-09 18:50:15 +0000185 // becomes 'process launch -s -o /dev/tty0 -e /dev/tty0' \n\
Jim Ingham767af882010-07-07 03:36:20 +0000186 \nIf the user always wanted to pass the same value to a particular option, the \n\
187 alias could be defined with that value directly in the alias as a constant, \n\
188 rather than using a positional placeholder: \n\
Sean Callanana3aff732010-08-09 18:50:15 +0000189 \n commands alias bl3 breakpoint set -f %1 -l 3 // Always sets a breakpoint on line \n\
190 // 3 of whatever file is indicated. \n");
Jim Ingham767af882010-07-07 03:36:20 +0000191
192 }
193
194 ~CommandObjectCommandsAlias ()
195 {
196 }
197
198
199 bool
200 Execute
201 (
Jim Ingham767af882010-07-07 03:36:20 +0000202 Args& args,
203 CommandReturnObject &result
204 )
205 {
Caroline Tice8bb61f02010-09-21 23:25:40 +0000206 size_t argc = args.GetArgumentCount();
Jim Ingham767af882010-07-07 03:36:20 +0000207
208 if (argc < 2)
Greg Clayton54e7afa2010-07-09 20:39:50 +0000209 {
Jim Ingham767af882010-07-07 03:36:20 +0000210 result.AppendError ("'alias' requires at least two arguments");
211 result.SetStatus (eReturnStatusFailed);
212 return false;
Greg Clayton54e7afa2010-07-09 20:39:50 +0000213 }
Jim Ingham767af882010-07-07 03:36:20 +0000214
215 const std::string alias_command = args.GetArgumentAtIndex(0);
216 const std::string actual_command = args.GetArgumentAtIndex(1);
217
218 args.Shift(); // Shift the alias command word off the argument vector.
219 args.Shift(); // Shift the old command word off the argument vector.
220
221 // Verify that the command is alias'able, and get the appropriate command object.
222
Greg Clayton238c0a12010-09-18 01:14:36 +0000223 if (m_interpreter.CommandExists (alias_command.c_str()))
Jim Ingham767af882010-07-07 03:36:20 +0000224 {
225 result.AppendErrorWithFormat ("'%s' is a permanent debugger command and cannot be redefined.\n",
226 alias_command.c_str());
227 result.SetStatus (eReturnStatusFailed);
228 }
229 else
230 {
Greg Clayton238c0a12010-09-18 01:14:36 +0000231 CommandObjectSP command_obj_sp(m_interpreter.GetCommandSPExact (actual_command.c_str(), true));
Jim Ingham767af882010-07-07 03:36:20 +0000232 CommandObjectSP subcommand_obj_sp;
233 bool use_subcommand = false;
234 if (command_obj_sp.get())
235 {
236 CommandObject *cmd_obj = command_obj_sp.get();
Greg Clayton54e7afa2010-07-09 20:39:50 +0000237 CommandObject *sub_cmd_obj = NULL;
Jim Ingham767af882010-07-07 03:36:20 +0000238 OptionArgVectorSP option_arg_vector_sp = OptionArgVectorSP (new OptionArgVector);
239 OptionArgVector *option_arg_vector = option_arg_vector_sp.get();
240
241 if (cmd_obj->IsMultiwordObject())
242 {
243 if (argc >= 3)
244 {
245 const std::string sub_command = args.GetArgumentAtIndex(0);
246 assert (sub_command.length() != 0);
247 subcommand_obj_sp =
248 (((CommandObjectMultiword *) cmd_obj)->GetSubcommandSP (sub_command.c_str()));
249 if (subcommand_obj_sp.get())
250 {
251 sub_cmd_obj = subcommand_obj_sp.get();
252 use_subcommand = true;
253 args.Shift(); // Shift the sub_command word off the argument vector.
254 }
255 else
256 {
257 result.AppendErrorWithFormat ("Error occurred while attempting to look up command '%s %s'.\n",
258 alias_command.c_str(), sub_command.c_str());
259 result.SetStatus (eReturnStatusFailed);
260 return false;
261 }
262 }
263 }
264
265 // Verify & handle any options/arguments passed to the alias command
266
267 if (args.GetArgumentCount () > 0)
268 {
269 if ((!use_subcommand && (cmd_obj->WantsRawCommandString()))
270 || (use_subcommand && (sub_cmd_obj->WantsRawCommandString())))
271 {
272 result.AppendErrorWithFormat ("'%s' cannot be aliased with any options or arguments.\n",
273 (use_subcommand ? sub_cmd_obj->GetCommandName()
274 : cmd_obj->GetCommandName()));
275 result.SetStatus (eReturnStatusFailed);
276 return false;
277 }
278
279 // options or arguments have been passed to the alias command, and must be
280 // verified & processed here.
281 if ((!use_subcommand && (cmd_obj->GetOptions() != NULL))
282 || (use_subcommand && (sub_cmd_obj->GetOptions() != NULL)))
283 {
284 Options *options;
285 if (use_subcommand)
286 options = sub_cmd_obj->GetOptions();
287 else
288 options = cmd_obj->GetOptions();
289 options->ResetOptionValues ();
290 args.Unshift ("dummy_arg");
291 args.ParseAliasOptions (*options, result, option_arg_vector);
292 args.Shift ();
293 if (result.Succeeded())
294 options->VerifyPartialOptions (result);
Caroline Tice8bb61f02010-09-21 23:25:40 +0000295 if (!result.Succeeded() && result.GetStatus() != lldb::eReturnStatusStarted)
296 {
297 result.AppendError ("Unable to create requested command alias.\n");
298 }
Jim Ingham767af882010-07-07 03:36:20 +0000299 }
Caroline Tice8bb61f02010-09-21 23:25:40 +0000300
301 // Anything remaining in args must be a plain argument.
302
303 argc = args.GetArgumentCount();
304 for (size_t i = 0; i < argc; ++i)
305 option_arg_vector->push_back (OptionArgPair ("<argument>",
306 std::string (args.GetArgumentAtIndex (i))));
Jim Ingham767af882010-07-07 03:36:20 +0000307 }
308
309 // Create the alias.
310
Greg Clayton238c0a12010-09-18 01:14:36 +0000311 if (m_interpreter.AliasExists (alias_command.c_str())
312 || m_interpreter.UserCommandExists (alias_command.c_str()))
Jim Ingham767af882010-07-07 03:36:20 +0000313 {
Greg Clayton238c0a12010-09-18 01:14:36 +0000314 OptionArgVectorSP tmp_option_arg_sp (m_interpreter.GetAliasOptions (alias_command.c_str()));
Jim Ingham767af882010-07-07 03:36:20 +0000315 if (tmp_option_arg_sp.get())
316 {
317 if (option_arg_vector->size() == 0)
Greg Clayton238c0a12010-09-18 01:14:36 +0000318 m_interpreter.RemoveAliasOptions (alias_command.c_str());
Jim Ingham767af882010-07-07 03:36:20 +0000319 }
320 result.AppendWarningWithFormat ("Overwriting existing definition for '%s'.\n",
321 alias_command.c_str());
322 }
323
324 if (use_subcommand)
Greg Clayton238c0a12010-09-18 01:14:36 +0000325 m_interpreter.AddAlias (alias_command.c_str(), subcommand_obj_sp);
Jim Ingham767af882010-07-07 03:36:20 +0000326 else
Greg Clayton238c0a12010-09-18 01:14:36 +0000327 m_interpreter.AddAlias (alias_command.c_str(), command_obj_sp);
Jim Ingham767af882010-07-07 03:36:20 +0000328 if (option_arg_vector->size() > 0)
Greg Clayton238c0a12010-09-18 01:14:36 +0000329 m_interpreter.AddOrReplaceAliasOptions (alias_command.c_str(), option_arg_vector_sp);
Jim Ingham767af882010-07-07 03:36:20 +0000330 result.SetStatus (eReturnStatusSuccessFinishNoResult);
331 }
332 else
333 {
334 result.AppendErrorWithFormat ("'%s' is not an existing command.\n", actual_command.c_str());
335 result.SetStatus (eReturnStatusFailed);
336 }
337 }
338
339 return result.Succeeded();
340 }
341};
342
343#pragma mark CommandObjectCommandsUnalias
344//-------------------------------------------------------------------------
345// CommandObjectCommandsUnalias
346//-------------------------------------------------------------------------
347
348class CommandObjectCommandsUnalias : public CommandObject
349{
350public:
Greg Clayton238c0a12010-09-18 01:14:36 +0000351 CommandObjectCommandsUnalias (CommandInterpreter &interpreter) :
352 CommandObject (interpreter,
353 "commands unalias",
Caroline Tice146292c2010-09-12 04:56:10 +0000354 "Allow the user to remove/delete a user-defined command abbreviation.",
355 "unalias <alias-name-to-be-removed>")
Jim Ingham767af882010-07-07 03:36:20 +0000356 {
357 }
358
359 ~CommandObjectCommandsUnalias()
360 {
361 }
362
363
364 bool
365 Execute
366 (
Jim Ingham767af882010-07-07 03:36:20 +0000367 Args& args,
368 CommandReturnObject &result
369 )
370 {
371 CommandObject::CommandMap::iterator pos;
372 CommandObject *cmd_obj;
373
374 if (args.GetArgumentCount() != 0)
375 {
376 const char *command_name = args.GetArgumentAtIndex(0);
Greg Clayton238c0a12010-09-18 01:14:36 +0000377 cmd_obj = m_interpreter.GetCommandObject(command_name);
Jim Ingham767af882010-07-07 03:36:20 +0000378 if (cmd_obj)
379 {
Greg Clayton238c0a12010-09-18 01:14:36 +0000380 if (m_interpreter.CommandExists (command_name))
Jim Ingham767af882010-07-07 03:36:20 +0000381 {
382 result.AppendErrorWithFormat ("'%s' is a permanent debugger command and cannot be removed.\n",
383 command_name);
384 result.SetStatus (eReturnStatusFailed);
385 }
386 else
387 {
388
Greg Clayton238c0a12010-09-18 01:14:36 +0000389 if (m_interpreter.RemoveAlias (command_name) == false)
Jim Ingham767af882010-07-07 03:36:20 +0000390 {
Greg Clayton238c0a12010-09-18 01:14:36 +0000391 if (m_interpreter.AliasExists (command_name))
Jim Ingham767af882010-07-07 03:36:20 +0000392 result.AppendErrorWithFormat ("Error occurred while attempting to unalias '%s'.\n",
393 command_name);
394 else
395 result.AppendErrorWithFormat ("'%s' is not an existing alias.\n", command_name);
396 result.SetStatus (eReturnStatusFailed);
397 }
398 else
399 result.SetStatus (eReturnStatusSuccessFinishNoResult);
400 }
401 }
402 else
403 {
404 result.AppendErrorWithFormat ("'%s' is not a known command.\nTry 'help' to see a "
405 "current list of commands.\n",
406 command_name);
407 result.SetStatus (eReturnStatusFailed);
408 }
409 }
410 else
411 {
412 result.AppendError ("must call 'unalias' with a valid alias");
413 result.SetStatus (eReturnStatusFailed);
414 }
415
416 return result.Succeeded();
417 }
418};
419
420#pragma mark CommandObjectMultiwordCommands
421
422//-------------------------------------------------------------------------
423// CommandObjectMultiwordCommands
424//-------------------------------------------------------------------------
425
426CommandObjectMultiwordCommands::CommandObjectMultiwordCommands (CommandInterpreter &interpreter) :
Greg Clayton238c0a12010-09-18 01:14:36 +0000427 CommandObjectMultiword (interpreter,
428 "commands",
Caroline Ticec1ad82e2010-09-07 22:38:08 +0000429 "A set of commands for managing or customizing the debugger commands.",
Jim Ingham767af882010-07-07 03:36:20 +0000430 "commands <subcommand> [<subcommand-options>]")
431{
Greg Clayton238c0a12010-09-18 01:14:36 +0000432 LoadSubCommand ("source", CommandObjectSP (new CommandObjectCommandsSource (interpreter)));
433 LoadSubCommand ("alias", CommandObjectSP (new CommandObjectCommandsAlias (interpreter)));
434 LoadSubCommand ("unalias", CommandObjectSP (new CommandObjectCommandsUnalias (interpreter)));
Jim Ingham767af882010-07-07 03:36:20 +0000435}
436
437CommandObjectMultiwordCommands::~CommandObjectMultiwordCommands ()
438{
439}
440