blob: 514d6a42a4fca9ee637fcd9eac72b6bea55a7933 [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.",
Caroline Tice43b014a2010-10-04 22:28:36 +000038 NULL)
Jim Ingham767af882010-07-07 03:36:20 +000039 {
Caroline Tice43b014a2010-10-04 22:28:36 +000040 CommandArgumentEntry arg;
41 CommandArgumentData file_arg;
42
43 // Define the first (and only) variant of this arg.
44 file_arg.arg_type = eArgTypeFilename;
45 file_arg.arg_repetition = eArgRepeatPlain;
46
47 // There is only one variant this argument could be; put it into the argument entry.
48 arg.push_back (file_arg);
49
50 // Push the data for the first argument into the m_arguments vector.
51 m_arguments.push_back (arg);
Jim Ingham767af882010-07-07 03:36:20 +000052 }
53
54 ~CommandObjectCommandsSource ()
55 {
56 }
57
58 bool
59 Execute
60 (
Jim Ingham767af882010-07-07 03:36:20 +000061 Args& args,
62 CommandReturnObject &result
63 )
64 {
65 const int argc = args.GetArgumentCount();
66 if (argc == 1)
67 {
68 const char *filename = args.GetArgumentAtIndex(0);
69 bool success = true;
70
71 result.AppendMessageWithFormat ("Executing commands in '%s'.\n", filename);
72
73 FileSpec cmd_file (filename);
74 if (cmd_file.Exists())
75 {
76 STLStringArray commands;
77 success = cmd_file.ReadFileLines (commands);
78
79 STLStringArray::iterator pos = commands.begin();
80
81 // Trim out any empty lines or lines that start with the comment
82 // char '#'
83 while (pos != commands.end())
84 {
Jim Ingham767af882010-07-07 03:36:20 +000085 size_t non_space = pos->find_first_not_of (k_space_characters);
Greg Claytona830adb2010-10-04 01:05:56 +000086 // Check for empty line or comment line (lines whose first
87 // non-space character is a '#')
88 if (non_space == std::string::npos || (*pos)[non_space] == '#')
Jim Ingham767af882010-07-07 03:36:20 +000089 pos = commands.erase(pos);
90 else
91 ++pos;
92 }
93
94 if (commands.size() > 0)
95 {
96 const size_t num_commands = commands.size();
97 size_t i;
98 for (i = 0; i<num_commands; ++i)
99 {
Greg Clayton238c0a12010-09-18 01:14:36 +0000100 result.GetOutputStream().Printf ("%s %s\n",
101 m_interpreter.GetPrompt(),
102 commands[i].c_str());
103 if (!m_interpreter.HandleCommand(commands[i].c_str(), false, result))
Jim Ingham767af882010-07-07 03:36:20 +0000104 break;
105 }
106
107 if (i < num_commands)
108 {
109 result.AppendErrorWithFormat("Aborting source of '%s' after command '%s' failed.\n",
110 filename, commands[i].c_str());
111 result.SetStatus (eReturnStatusSuccessFinishResult);
112 }
113 else
114 {
115 success = true;
116 result.SetStatus (eReturnStatusFailed);
117 }
118 }
119 }
120 else
121 {
122 result.AppendErrorWithFormat ("File '%s' does not exist.\n", filename);
123 result.SetStatus (eReturnStatusFailed);
124 success = false;
125 }
126
127 if (success)
128 {
129 result.SetStatus (eReturnStatusSuccessFinishNoResult);
130 }
131 }
132 else
133 {
134 result.AppendErrorWithFormat("'%s' takes exactly one executable filename argument.\n", GetCommandName());
135 result.SetStatus (eReturnStatusFailed);
136 }
137 return result.Succeeded();
138
139 }
140};
141
142#pragma mark CommandObjectCommandsAlias
143//-------------------------------------------------------------------------
144// CommandObjectCommandsAlias
145//-------------------------------------------------------------------------
146
147class CommandObjectCommandsAlias : public CommandObject
148{
149public:
Greg Clayton238c0a12010-09-18 01:14:36 +0000150 CommandObjectCommandsAlias (CommandInterpreter &interpreter) :
151 CommandObject (interpreter,
152 "commands alias",
Caroline Ticeabb507a2010-09-08 21:06:11 +0000153 "Allow users to define their own debugger command abbreviations.",
Caroline Tice43b014a2010-10-04 22:28:36 +0000154 NULL)
Jim Ingham767af882010-07-07 03:36:20 +0000155 {
156 SetHelpLong(
157 "'alias' allows the user to create a short-cut or abbreviation for long \n\
158 commands, multi-word commands, and commands that take particular options. \n\
159 Below are some simple examples of how one might use the 'alias' command: \n\
Caroline Tice31fbb642010-09-08 22:08:58 +0000160 \n 'commands alias sc script' // Creates the abbreviation 'sc' for the 'script' \n\
161 // command. \n\
162 'commands alias bp breakpoint' // Creates the abbreviation 'bp' for the 'breakpoint' \n\
163 // command. Since breakpoint commands are two-word \n\
164 // commands, the user will still need to enter the \n\
165 // second word after 'bp', e.g. 'bp enable' or \n\
166 // 'bp delete'. \n\
167 'commands alias bpl breakpoint list' // Creates the abbreviation 'bpl' for the \n\
168 // two-word command 'breakpoint list'. \n\
Jim Ingham767af882010-07-07 03:36:20 +0000169 \nAn alias can include some options for the command, with the values either \n\
170 filled in at the time the alias is created, or specified as positional \n\
171 arguments, to be filled in when the alias is invoked. The following example \n\
172 shows how to create aliases with options: \n\
173 \n\
Caroline Tice31fbb642010-09-08 22:08:58 +0000174 'commands alias bfl breakpoint set -f %1 -l %2' \n\
Jim Ingham767af882010-07-07 03:36:20 +0000175 \nThis creates the abbreviation 'bfl' (for break-file-line), with the -f and -l \n\
176 options already part of the alias. So if the user wants to set a breakpoint \n\
177 by file and line without explicitly having to use the -f and -l options, the \n\
178 user can now use 'bfl' instead. The '%1' and '%2' are positional placeholders \n\
179 for the actual arguments that will be passed when the alias command is used. \n\
180 The number in the placeholder refers to the position/order the actual value \n\
181 occupies when the alias is used. So all the occurrences of '%1' in the alias \n\
182 will be replaced with the first argument, all the occurrences of '%2' in the \n\
183 alias will be replaced with the second argument, and so on. This also allows \n\
184 actual arguments to be used multiple times within an alias (see 'process \n\
185 launch' example below). So in the 'bfl' case, the actual file value will be \n\
186 filled in with the first argument following 'bfl' and the actual line number \n\
187 value will be filled in with the second argument. The user would use this \n\
188 alias as follows: \n\
Caroline Tice31fbb642010-09-08 22:08:58 +0000189 \n (lldb) commands alias bfl breakpoint set -f %1 -l %2 \n\
Sean Callanana3aff732010-08-09 18:50:15 +0000190 <... some time later ...> \n\
Caroline Tice31fbb642010-09-08 22:08:58 +0000191 (lldb) bfl my-file.c 137 \n\
Jim Ingham767af882010-07-07 03:36:20 +0000192 \nThis would be the same as if the user had entered \n\
193 'breakpoint set -f my-file.c -l 137'. \n\
194 \nAnother example: \n\
Caroline Tice31fbb642010-09-08 22:08:58 +0000195 \n (lldb) commands alias pltty process launch -s -o %1 -e %1 \n\
196 (lldb) pltty /dev/tty0 \n\
Sean Callanana3aff732010-08-09 18:50:15 +0000197 // becomes 'process launch -s -o /dev/tty0 -e /dev/tty0' \n\
Jim Ingham767af882010-07-07 03:36:20 +0000198 \nIf the user always wanted to pass the same value to a particular option, the \n\
199 alias could be defined with that value directly in the alias as a constant, \n\
200 rather than using a positional placeholder: \n\
Sean Callanana3aff732010-08-09 18:50:15 +0000201 \n commands alias bl3 breakpoint set -f %1 -l 3 // Always sets a breakpoint on line \n\
202 // 3 of whatever file is indicated. \n");
Jim Ingham767af882010-07-07 03:36:20 +0000203
Caroline Tice43b014a2010-10-04 22:28:36 +0000204 CommandArgumentEntry arg1;
205 CommandArgumentEntry arg2;
206 CommandArgumentEntry arg3;
207 CommandArgumentData alias_arg;
208 CommandArgumentData cmd_arg;
209 CommandArgumentData options_arg;
210
211 // Define the first (and only) variant of this arg.
212 alias_arg.arg_type = eArgTypeAliasName;
213 alias_arg.arg_repetition = eArgRepeatPlain;
214
215 // There is only one variant this argument could be; put it into the argument entry.
216 arg1.push_back (alias_arg);
217
218 // Define the first (and only) variant of this arg.
219 cmd_arg.arg_type = eArgTypeCommandName;
220 cmd_arg.arg_repetition = eArgRepeatPlain;
221
222 // There is only one variant this argument could be; put it into the argument entry.
223 arg2.push_back (cmd_arg);
224
225 // Define the first (and only) variant of this arg.
226 options_arg.arg_type = eArgTypeAliasOptions;
227 options_arg.arg_repetition = eArgRepeatOptional;
228
229 // There is only one variant this argument could be; put it into the argument entry.
230 arg3.push_back (options_arg);
231
232 // Push the data for the first argument into the m_arguments vector.
233 m_arguments.push_back (arg1);
234 m_arguments.push_back (arg2);
235 m_arguments.push_back (arg3);
Jim Ingham767af882010-07-07 03:36:20 +0000236 }
237
238 ~CommandObjectCommandsAlias ()
239 {
240 }
241
242
243 bool
244 Execute
245 (
Jim Ingham767af882010-07-07 03:36:20 +0000246 Args& args,
247 CommandReturnObject &result
248 )
249 {
Caroline Tice8bb61f02010-09-21 23:25:40 +0000250 size_t argc = args.GetArgumentCount();
Jim Ingham767af882010-07-07 03:36:20 +0000251
252 if (argc < 2)
Greg Clayton54e7afa2010-07-09 20:39:50 +0000253 {
Jim Ingham767af882010-07-07 03:36:20 +0000254 result.AppendError ("'alias' requires at least two arguments");
255 result.SetStatus (eReturnStatusFailed);
256 return false;
Greg Clayton54e7afa2010-07-09 20:39:50 +0000257 }
Jim Ingham767af882010-07-07 03:36:20 +0000258
259 const std::string alias_command = args.GetArgumentAtIndex(0);
260 const std::string actual_command = args.GetArgumentAtIndex(1);
261
262 args.Shift(); // Shift the alias command word off the argument vector.
263 args.Shift(); // Shift the old command word off the argument vector.
264
265 // Verify that the command is alias'able, and get the appropriate command object.
266
Greg Clayton238c0a12010-09-18 01:14:36 +0000267 if (m_interpreter.CommandExists (alias_command.c_str()))
Jim Ingham767af882010-07-07 03:36:20 +0000268 {
269 result.AppendErrorWithFormat ("'%s' is a permanent debugger command and cannot be redefined.\n",
270 alias_command.c_str());
271 result.SetStatus (eReturnStatusFailed);
272 }
273 else
274 {
Greg Clayton238c0a12010-09-18 01:14:36 +0000275 CommandObjectSP command_obj_sp(m_interpreter.GetCommandSPExact (actual_command.c_str(), true));
Jim Ingham767af882010-07-07 03:36:20 +0000276 CommandObjectSP subcommand_obj_sp;
277 bool use_subcommand = false;
278 if (command_obj_sp.get())
279 {
280 CommandObject *cmd_obj = command_obj_sp.get();
Greg Clayton54e7afa2010-07-09 20:39:50 +0000281 CommandObject *sub_cmd_obj = NULL;
Jim Ingham767af882010-07-07 03:36:20 +0000282 OptionArgVectorSP option_arg_vector_sp = OptionArgVectorSP (new OptionArgVector);
283 OptionArgVector *option_arg_vector = option_arg_vector_sp.get();
284
285 if (cmd_obj->IsMultiwordObject())
286 {
287 if (argc >= 3)
288 {
289 const std::string sub_command = args.GetArgumentAtIndex(0);
290 assert (sub_command.length() != 0);
291 subcommand_obj_sp =
292 (((CommandObjectMultiword *) cmd_obj)->GetSubcommandSP (sub_command.c_str()));
293 if (subcommand_obj_sp.get())
294 {
295 sub_cmd_obj = subcommand_obj_sp.get();
296 use_subcommand = true;
297 args.Shift(); // Shift the sub_command word off the argument vector.
298 }
299 else
300 {
301 result.AppendErrorWithFormat ("Error occurred while attempting to look up command '%s %s'.\n",
302 alias_command.c_str(), sub_command.c_str());
303 result.SetStatus (eReturnStatusFailed);
304 return false;
305 }
306 }
307 }
308
309 // Verify & handle any options/arguments passed to the alias command
310
311 if (args.GetArgumentCount () > 0)
312 {
313 if ((!use_subcommand && (cmd_obj->WantsRawCommandString()))
314 || (use_subcommand && (sub_cmd_obj->WantsRawCommandString())))
315 {
316 result.AppendErrorWithFormat ("'%s' cannot be aliased with any options or arguments.\n",
317 (use_subcommand ? sub_cmd_obj->GetCommandName()
318 : cmd_obj->GetCommandName()));
319 result.SetStatus (eReturnStatusFailed);
320 return false;
321 }
322
323 // options or arguments have been passed to the alias command, and must be
324 // verified & processed here.
325 if ((!use_subcommand && (cmd_obj->GetOptions() != NULL))
326 || (use_subcommand && (sub_cmd_obj->GetOptions() != NULL)))
327 {
328 Options *options;
329 if (use_subcommand)
330 options = sub_cmd_obj->GetOptions();
331 else
332 options = cmd_obj->GetOptions();
333 options->ResetOptionValues ();
334 args.Unshift ("dummy_arg");
335 args.ParseAliasOptions (*options, result, option_arg_vector);
336 args.Shift ();
337 if (result.Succeeded())
338 options->VerifyPartialOptions (result);
Caroline Tice8bb61f02010-09-21 23:25:40 +0000339 if (!result.Succeeded() && result.GetStatus() != lldb::eReturnStatusStarted)
340 {
341 result.AppendError ("Unable to create requested command alias.\n");
342 }
Jim Ingham767af882010-07-07 03:36:20 +0000343 }
Caroline Tice8bb61f02010-09-21 23:25:40 +0000344
345 // Anything remaining in args must be a plain argument.
346
347 argc = args.GetArgumentCount();
348 for (size_t i = 0; i < argc; ++i)
349 option_arg_vector->push_back (OptionArgPair ("<argument>",
350 std::string (args.GetArgumentAtIndex (i))));
Jim Ingham767af882010-07-07 03:36:20 +0000351 }
352
353 // Create the alias.
354
Greg Clayton238c0a12010-09-18 01:14:36 +0000355 if (m_interpreter.AliasExists (alias_command.c_str())
356 || m_interpreter.UserCommandExists (alias_command.c_str()))
Jim Ingham767af882010-07-07 03:36:20 +0000357 {
Greg Clayton238c0a12010-09-18 01:14:36 +0000358 OptionArgVectorSP tmp_option_arg_sp (m_interpreter.GetAliasOptions (alias_command.c_str()));
Jim Ingham767af882010-07-07 03:36:20 +0000359 if (tmp_option_arg_sp.get())
360 {
361 if (option_arg_vector->size() == 0)
Greg Clayton238c0a12010-09-18 01:14:36 +0000362 m_interpreter.RemoveAliasOptions (alias_command.c_str());
Jim Ingham767af882010-07-07 03:36:20 +0000363 }
364 result.AppendWarningWithFormat ("Overwriting existing definition for '%s'.\n",
365 alias_command.c_str());
366 }
367
368 if (use_subcommand)
Greg Clayton238c0a12010-09-18 01:14:36 +0000369 m_interpreter.AddAlias (alias_command.c_str(), subcommand_obj_sp);
Jim Ingham767af882010-07-07 03:36:20 +0000370 else
Greg Clayton238c0a12010-09-18 01:14:36 +0000371 m_interpreter.AddAlias (alias_command.c_str(), command_obj_sp);
Jim Ingham767af882010-07-07 03:36:20 +0000372 if (option_arg_vector->size() > 0)
Greg Clayton238c0a12010-09-18 01:14:36 +0000373 m_interpreter.AddOrReplaceAliasOptions (alias_command.c_str(), option_arg_vector_sp);
Jim Ingham767af882010-07-07 03:36:20 +0000374 result.SetStatus (eReturnStatusSuccessFinishNoResult);
375 }
376 else
377 {
378 result.AppendErrorWithFormat ("'%s' is not an existing command.\n", actual_command.c_str());
379 result.SetStatus (eReturnStatusFailed);
380 }
381 }
382
383 return result.Succeeded();
384 }
385};
386
387#pragma mark CommandObjectCommandsUnalias
388//-------------------------------------------------------------------------
389// CommandObjectCommandsUnalias
390//-------------------------------------------------------------------------
391
392class CommandObjectCommandsUnalias : public CommandObject
393{
394public:
Greg Clayton238c0a12010-09-18 01:14:36 +0000395 CommandObjectCommandsUnalias (CommandInterpreter &interpreter) :
396 CommandObject (interpreter,
397 "commands unalias",
Caroline Tice146292c2010-09-12 04:56:10 +0000398 "Allow the user to remove/delete a user-defined command abbreviation.",
Caroline Tice43b014a2010-10-04 22:28:36 +0000399 NULL)
Jim Ingham767af882010-07-07 03:36:20 +0000400 {
Caroline Tice43b014a2010-10-04 22:28:36 +0000401 CommandArgumentEntry arg;
402 CommandArgumentData alias_arg;
403
404 // Define the first (and only) variant of this arg.
405 alias_arg.arg_type = eArgTypeAliasName;
406 alias_arg.arg_repetition = eArgRepeatPlain;
407
408 // There is only one variant this argument could be; put it into the argument entry.
409 arg.push_back (alias_arg);
410
411 // Push the data for the first argument into the m_arguments vector.
412 m_arguments.push_back (arg);
Jim Ingham767af882010-07-07 03:36:20 +0000413 }
414
415 ~CommandObjectCommandsUnalias()
416 {
417 }
418
419
420 bool
421 Execute
422 (
Jim Ingham767af882010-07-07 03:36:20 +0000423 Args& args,
424 CommandReturnObject &result
425 )
426 {
427 CommandObject::CommandMap::iterator pos;
428 CommandObject *cmd_obj;
429
430 if (args.GetArgumentCount() != 0)
431 {
432 const char *command_name = args.GetArgumentAtIndex(0);
Greg Clayton238c0a12010-09-18 01:14:36 +0000433 cmd_obj = m_interpreter.GetCommandObject(command_name);
Jim Ingham767af882010-07-07 03:36:20 +0000434 if (cmd_obj)
435 {
Greg Clayton238c0a12010-09-18 01:14:36 +0000436 if (m_interpreter.CommandExists (command_name))
Jim Ingham767af882010-07-07 03:36:20 +0000437 {
438 result.AppendErrorWithFormat ("'%s' is a permanent debugger command and cannot be removed.\n",
439 command_name);
440 result.SetStatus (eReturnStatusFailed);
441 }
442 else
443 {
444
Greg Clayton238c0a12010-09-18 01:14:36 +0000445 if (m_interpreter.RemoveAlias (command_name) == false)
Jim Ingham767af882010-07-07 03:36:20 +0000446 {
Greg Clayton238c0a12010-09-18 01:14:36 +0000447 if (m_interpreter.AliasExists (command_name))
Jim Ingham767af882010-07-07 03:36:20 +0000448 result.AppendErrorWithFormat ("Error occurred while attempting to unalias '%s'.\n",
449 command_name);
450 else
451 result.AppendErrorWithFormat ("'%s' is not an existing alias.\n", command_name);
452 result.SetStatus (eReturnStatusFailed);
453 }
454 else
455 result.SetStatus (eReturnStatusSuccessFinishNoResult);
456 }
457 }
458 else
459 {
460 result.AppendErrorWithFormat ("'%s' is not a known command.\nTry 'help' to see a "
461 "current list of commands.\n",
462 command_name);
463 result.SetStatus (eReturnStatusFailed);
464 }
465 }
466 else
467 {
468 result.AppendError ("must call 'unalias' with a valid alias");
469 result.SetStatus (eReturnStatusFailed);
470 }
471
472 return result.Succeeded();
473 }
474};
475
476#pragma mark CommandObjectMultiwordCommands
477
478//-------------------------------------------------------------------------
479// CommandObjectMultiwordCommands
480//-------------------------------------------------------------------------
481
482CommandObjectMultiwordCommands::CommandObjectMultiwordCommands (CommandInterpreter &interpreter) :
Greg Clayton238c0a12010-09-18 01:14:36 +0000483 CommandObjectMultiword (interpreter,
484 "commands",
Caroline Ticec1ad82e2010-09-07 22:38:08 +0000485 "A set of commands for managing or customizing the debugger commands.",
Jim Ingham767af882010-07-07 03:36:20 +0000486 "commands <subcommand> [<subcommand-options>]")
487{
Greg Clayton238c0a12010-09-18 01:14:36 +0000488 LoadSubCommand ("source", CommandObjectSP (new CommandObjectCommandsSource (interpreter)));
489 LoadSubCommand ("alias", CommandObjectSP (new CommandObjectCommandsAlias (interpreter)));
490 LoadSubCommand ("unalias", CommandObjectSP (new CommandObjectCommandsUnalias (interpreter)));
Jim Ingham767af882010-07-07 03:36:20 +0000491}
492
493CommandObjectMultiwordCommands::~CommandObjectMultiwordCommands ()
494{
495}
496