blob: fc761587c828ce015f6f6d448b406cf399e57ea3 [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 {
73 bool remove_string = false;
74 size_t non_space = pos->find_first_not_of (k_space_characters);
75 if (non_space == std::string::npos)
76 remove_string = true; // Empty line
77 else if ((*pos)[non_space] == '#')
78 remove_string = true; // Comment line that starts with '#'
79
80 if (remove_string)
81 pos = commands.erase(pos);
82 else
83 ++pos;
84 }
85
86 if (commands.size() > 0)
87 {
88 const size_t num_commands = commands.size();
89 size_t i;
90 for (i = 0; i<num_commands; ++i)
91 {
Greg Clayton238c0a12010-09-18 01:14:36 +000092 result.GetOutputStream().Printf ("%s %s\n",
93 m_interpreter.GetPrompt(),
94 commands[i].c_str());
95 if (!m_interpreter.HandleCommand(commands[i].c_str(), false, result))
Jim Ingham767af882010-07-07 03:36:20 +000096 break;
97 }
98
99 if (i < num_commands)
100 {
101 result.AppendErrorWithFormat("Aborting source of '%s' after command '%s' failed.\n",
102 filename, commands[i].c_str());
103 result.SetStatus (eReturnStatusSuccessFinishResult);
104 }
105 else
106 {
107 success = true;
108 result.SetStatus (eReturnStatusFailed);
109 }
110 }
111 }
112 else
113 {
114 result.AppendErrorWithFormat ("File '%s' does not exist.\n", filename);
115 result.SetStatus (eReturnStatusFailed);
116 success = false;
117 }
118
119 if (success)
120 {
121 result.SetStatus (eReturnStatusSuccessFinishNoResult);
122 }
123 }
124 else
125 {
126 result.AppendErrorWithFormat("'%s' takes exactly one executable filename argument.\n", GetCommandName());
127 result.SetStatus (eReturnStatusFailed);
128 }
129 return result.Succeeded();
130
131 }
132};
133
134#pragma mark CommandObjectCommandsAlias
135//-------------------------------------------------------------------------
136// CommandObjectCommandsAlias
137//-------------------------------------------------------------------------
138
139class CommandObjectCommandsAlias : public CommandObject
140{
141public:
Greg Clayton238c0a12010-09-18 01:14:36 +0000142 CommandObjectCommandsAlias (CommandInterpreter &interpreter) :
143 CommandObject (interpreter,
144 "commands alias",
Caroline Ticeabb507a2010-09-08 21:06:11 +0000145 "Allow users to define their own debugger command abbreviations.",
146 "commands alias <new_command> <old_command> [<options-for-aliased-command>]")
Jim Ingham767af882010-07-07 03:36:20 +0000147 {
148 SetHelpLong(
149 "'alias' allows the user to create a short-cut or abbreviation for long \n\
150 commands, multi-word commands, and commands that take particular options. \n\
151 Below are some simple examples of how one might use the 'alias' command: \n\
Caroline Tice31fbb642010-09-08 22:08:58 +0000152 \n 'commands alias sc script' // Creates the abbreviation 'sc' for the 'script' \n\
153 // command. \n\
154 'commands alias bp breakpoint' // Creates the abbreviation 'bp' for the 'breakpoint' \n\
155 // command. Since breakpoint commands are two-word \n\
156 // commands, the user will still need to enter the \n\
157 // second word after 'bp', e.g. 'bp enable' or \n\
158 // 'bp delete'. \n\
159 'commands alias bpl breakpoint list' // Creates the abbreviation 'bpl' for the \n\
160 // two-word command 'breakpoint list'. \n\
Jim Ingham767af882010-07-07 03:36:20 +0000161 \nAn alias can include some options for the command, with the values either \n\
162 filled in at the time the alias is created, or specified as positional \n\
163 arguments, to be filled in when the alias is invoked. The following example \n\
164 shows how to create aliases with options: \n\
165 \n\
Caroline Tice31fbb642010-09-08 22:08:58 +0000166 'commands alias bfl breakpoint set -f %1 -l %2' \n\
Jim Ingham767af882010-07-07 03:36:20 +0000167 \nThis creates the abbreviation 'bfl' (for break-file-line), with the -f and -l \n\
168 options already part of the alias. So if the user wants to set a breakpoint \n\
169 by file and line without explicitly having to use the -f and -l options, the \n\
170 user can now use 'bfl' instead. The '%1' and '%2' are positional placeholders \n\
171 for the actual arguments that will be passed when the alias command is used. \n\
172 The number in the placeholder refers to the position/order the actual value \n\
173 occupies when the alias is used. So all the occurrences of '%1' in the alias \n\
174 will be replaced with the first argument, all the occurrences of '%2' in the \n\
175 alias will be replaced with the second argument, and so on. This also allows \n\
176 actual arguments to be used multiple times within an alias (see 'process \n\
177 launch' example below). So in the 'bfl' case, the actual file value will be \n\
178 filled in with the first argument following 'bfl' and the actual line number \n\
179 value will be filled in with the second argument. The user would use this \n\
180 alias as follows: \n\
Caroline Tice31fbb642010-09-08 22:08:58 +0000181 \n (lldb) commands alias bfl breakpoint set -f %1 -l %2 \n\
Sean Callanana3aff732010-08-09 18:50:15 +0000182 <... some time later ...> \n\
Caroline Tice31fbb642010-09-08 22:08:58 +0000183 (lldb) bfl my-file.c 137 \n\
Jim Ingham767af882010-07-07 03:36:20 +0000184 \nThis would be the same as if the user had entered \n\
185 'breakpoint set -f my-file.c -l 137'. \n\
186 \nAnother example: \n\
Caroline Tice31fbb642010-09-08 22:08:58 +0000187 \n (lldb) commands alias pltty process launch -s -o %1 -e %1 \n\
188 (lldb) pltty /dev/tty0 \n\
Sean Callanana3aff732010-08-09 18:50:15 +0000189 // becomes 'process launch -s -o /dev/tty0 -e /dev/tty0' \n\
Jim Ingham767af882010-07-07 03:36:20 +0000190 \nIf the user always wanted to pass the same value to a particular option, the \n\
191 alias could be defined with that value directly in the alias as a constant, \n\
192 rather than using a positional placeholder: \n\
Sean Callanana3aff732010-08-09 18:50:15 +0000193 \n commands alias bl3 breakpoint set -f %1 -l 3 // Always sets a breakpoint on line \n\
194 // 3 of whatever file is indicated. \n");
Jim Ingham767af882010-07-07 03:36:20 +0000195
196 }
197
198 ~CommandObjectCommandsAlias ()
199 {
200 }
201
202
203 bool
204 Execute
205 (
Jim Ingham767af882010-07-07 03:36:20 +0000206 Args& args,
207 CommandReturnObject &result
208 )
209 {
Greg Clayton54e7afa2010-07-09 20:39:50 +0000210 const size_t argc = args.GetArgumentCount();
Jim Ingham767af882010-07-07 03:36:20 +0000211
212 if (argc < 2)
Greg Clayton54e7afa2010-07-09 20:39:50 +0000213 {
Jim Ingham767af882010-07-07 03:36:20 +0000214 result.AppendError ("'alias' requires at least two arguments");
215 result.SetStatus (eReturnStatusFailed);
216 return false;
Greg Clayton54e7afa2010-07-09 20:39:50 +0000217 }
Jim Ingham767af882010-07-07 03:36:20 +0000218
219 const std::string alias_command = args.GetArgumentAtIndex(0);
220 const std::string actual_command = args.GetArgumentAtIndex(1);
221
222 args.Shift(); // Shift the alias command word off the argument vector.
223 args.Shift(); // Shift the old command word off the argument vector.
224
225 // Verify that the command is alias'able, and get the appropriate command object.
226
Greg Clayton238c0a12010-09-18 01:14:36 +0000227 if (m_interpreter.CommandExists (alias_command.c_str()))
Jim Ingham767af882010-07-07 03:36:20 +0000228 {
229 result.AppendErrorWithFormat ("'%s' is a permanent debugger command and cannot be redefined.\n",
230 alias_command.c_str());
231 result.SetStatus (eReturnStatusFailed);
232 }
233 else
234 {
Greg Clayton238c0a12010-09-18 01:14:36 +0000235 CommandObjectSP command_obj_sp(m_interpreter.GetCommandSPExact (actual_command.c_str(), true));
Jim Ingham767af882010-07-07 03:36:20 +0000236 CommandObjectSP subcommand_obj_sp;
237 bool use_subcommand = false;
238 if (command_obj_sp.get())
239 {
240 CommandObject *cmd_obj = command_obj_sp.get();
Greg Clayton54e7afa2010-07-09 20:39:50 +0000241 CommandObject *sub_cmd_obj = NULL;
Jim Ingham767af882010-07-07 03:36:20 +0000242 OptionArgVectorSP option_arg_vector_sp = OptionArgVectorSP (new OptionArgVector);
243 OptionArgVector *option_arg_vector = option_arg_vector_sp.get();
244
245 if (cmd_obj->IsMultiwordObject())
246 {
247 if (argc >= 3)
248 {
249 const std::string sub_command = args.GetArgumentAtIndex(0);
250 assert (sub_command.length() != 0);
251 subcommand_obj_sp =
252 (((CommandObjectMultiword *) cmd_obj)->GetSubcommandSP (sub_command.c_str()));
253 if (subcommand_obj_sp.get())
254 {
255 sub_cmd_obj = subcommand_obj_sp.get();
256 use_subcommand = true;
257 args.Shift(); // Shift the sub_command word off the argument vector.
258 }
259 else
260 {
261 result.AppendErrorWithFormat ("Error occurred while attempting to look up command '%s %s'.\n",
262 alias_command.c_str(), sub_command.c_str());
263 result.SetStatus (eReturnStatusFailed);
264 return false;
265 }
266 }
267 }
268
269 // Verify & handle any options/arguments passed to the alias command
270
271 if (args.GetArgumentCount () > 0)
272 {
273 if ((!use_subcommand && (cmd_obj->WantsRawCommandString()))
274 || (use_subcommand && (sub_cmd_obj->WantsRawCommandString())))
275 {
276 result.AppendErrorWithFormat ("'%s' cannot be aliased with any options or arguments.\n",
277 (use_subcommand ? sub_cmd_obj->GetCommandName()
278 : cmd_obj->GetCommandName()));
279 result.SetStatus (eReturnStatusFailed);
280 return false;
281 }
282
283 // options or arguments have been passed to the alias command, and must be
284 // verified & processed here.
285 if ((!use_subcommand && (cmd_obj->GetOptions() != NULL))
286 || (use_subcommand && (sub_cmd_obj->GetOptions() != NULL)))
287 {
288 Options *options;
289 if (use_subcommand)
290 options = sub_cmd_obj->GetOptions();
291 else
292 options = cmd_obj->GetOptions();
293 options->ResetOptionValues ();
294 args.Unshift ("dummy_arg");
295 args.ParseAliasOptions (*options, result, option_arg_vector);
296 args.Shift ();
297 if (result.Succeeded())
298 options->VerifyPartialOptions (result);
299 if (!result.Succeeded())
300 return false;
301 }
302 else
303 {
Greg Clayton54e7afa2010-07-09 20:39:50 +0000304 for (size_t i = 0; i < argc; ++i)
Jim Ingham767af882010-07-07 03:36:20 +0000305 option_arg_vector->push_back (OptionArgPair ("<argument>",
306 std::string (args.GetArgumentAtIndex (i))));
307 }
308 }
309
310 // Create the alias.
311
Greg Clayton238c0a12010-09-18 01:14:36 +0000312 if (m_interpreter.AliasExists (alias_command.c_str())
313 || m_interpreter.UserCommandExists (alias_command.c_str()))
Jim Ingham767af882010-07-07 03:36:20 +0000314 {
Greg Clayton238c0a12010-09-18 01:14:36 +0000315 OptionArgVectorSP tmp_option_arg_sp (m_interpreter.GetAliasOptions (alias_command.c_str()));
Jim Ingham767af882010-07-07 03:36:20 +0000316 if (tmp_option_arg_sp.get())
317 {
318 if (option_arg_vector->size() == 0)
Greg Clayton238c0a12010-09-18 01:14:36 +0000319 m_interpreter.RemoveAliasOptions (alias_command.c_str());
Jim Ingham767af882010-07-07 03:36:20 +0000320 }
321 result.AppendWarningWithFormat ("Overwriting existing definition for '%s'.\n",
322 alias_command.c_str());
323 }
324
325 if (use_subcommand)
Greg Clayton238c0a12010-09-18 01:14:36 +0000326 m_interpreter.AddAlias (alias_command.c_str(), subcommand_obj_sp);
Jim Ingham767af882010-07-07 03:36:20 +0000327 else
Greg Clayton238c0a12010-09-18 01:14:36 +0000328 m_interpreter.AddAlias (alias_command.c_str(), command_obj_sp);
Jim Ingham767af882010-07-07 03:36:20 +0000329 if (option_arg_vector->size() > 0)
Greg Clayton238c0a12010-09-18 01:14:36 +0000330 m_interpreter.AddOrReplaceAliasOptions (alias_command.c_str(), option_arg_vector_sp);
Jim Ingham767af882010-07-07 03:36:20 +0000331 result.SetStatus (eReturnStatusSuccessFinishNoResult);
332 }
333 else
334 {
335 result.AppendErrorWithFormat ("'%s' is not an existing command.\n", actual_command.c_str());
336 result.SetStatus (eReturnStatusFailed);
337 }
338 }
339
340 return result.Succeeded();
341 }
342};
343
344#pragma mark CommandObjectCommandsUnalias
345//-------------------------------------------------------------------------
346// CommandObjectCommandsUnalias
347//-------------------------------------------------------------------------
348
349class CommandObjectCommandsUnalias : public CommandObject
350{
351public:
Greg Clayton238c0a12010-09-18 01:14:36 +0000352 CommandObjectCommandsUnalias (CommandInterpreter &interpreter) :
353 CommandObject (interpreter,
354 "commands unalias",
Caroline Tice146292c2010-09-12 04:56:10 +0000355 "Allow the user to remove/delete a user-defined command abbreviation.",
356 "unalias <alias-name-to-be-removed>")
Jim Ingham767af882010-07-07 03:36:20 +0000357 {
358 }
359
360 ~CommandObjectCommandsUnalias()
361 {
362 }
363
364
365 bool
366 Execute
367 (
Jim Ingham767af882010-07-07 03:36:20 +0000368 Args& args,
369 CommandReturnObject &result
370 )
371 {
372 CommandObject::CommandMap::iterator pos;
373 CommandObject *cmd_obj;
374
375 if (args.GetArgumentCount() != 0)
376 {
377 const char *command_name = args.GetArgumentAtIndex(0);
Greg Clayton238c0a12010-09-18 01:14:36 +0000378 cmd_obj = m_interpreter.GetCommandObject(command_name);
Jim Ingham767af882010-07-07 03:36:20 +0000379 if (cmd_obj)
380 {
Greg Clayton238c0a12010-09-18 01:14:36 +0000381 if (m_interpreter.CommandExists (command_name))
Jim Ingham767af882010-07-07 03:36:20 +0000382 {
383 result.AppendErrorWithFormat ("'%s' is a permanent debugger command and cannot be removed.\n",
384 command_name);
385 result.SetStatus (eReturnStatusFailed);
386 }
387 else
388 {
389
Greg Clayton238c0a12010-09-18 01:14:36 +0000390 if (m_interpreter.RemoveAlias (command_name) == false)
Jim Ingham767af882010-07-07 03:36:20 +0000391 {
Greg Clayton238c0a12010-09-18 01:14:36 +0000392 if (m_interpreter.AliasExists (command_name))
Jim Ingham767af882010-07-07 03:36:20 +0000393 result.AppendErrorWithFormat ("Error occurred while attempting to unalias '%s'.\n",
394 command_name);
395 else
396 result.AppendErrorWithFormat ("'%s' is not an existing alias.\n", command_name);
397 result.SetStatus (eReturnStatusFailed);
398 }
399 else
400 result.SetStatus (eReturnStatusSuccessFinishNoResult);
401 }
402 }
403 else
404 {
405 result.AppendErrorWithFormat ("'%s' is not a known command.\nTry 'help' to see a "
406 "current list of commands.\n",
407 command_name);
408 result.SetStatus (eReturnStatusFailed);
409 }
410 }
411 else
412 {
413 result.AppendError ("must call 'unalias' with a valid alias");
414 result.SetStatus (eReturnStatusFailed);
415 }
416
417 return result.Succeeded();
418 }
419};
420
421#pragma mark CommandObjectMultiwordCommands
422
423//-------------------------------------------------------------------------
424// CommandObjectMultiwordCommands
425//-------------------------------------------------------------------------
426
427CommandObjectMultiwordCommands::CommandObjectMultiwordCommands (CommandInterpreter &interpreter) :
Greg Clayton238c0a12010-09-18 01:14:36 +0000428 CommandObjectMultiword (interpreter,
429 "commands",
Caroline Ticec1ad82e2010-09-07 22:38:08 +0000430 "A set of commands for managing or customizing the debugger commands.",
Jim Ingham767af882010-07-07 03:36:20 +0000431 "commands <subcommand> [<subcommand-options>]")
432{
Greg Clayton238c0a12010-09-18 01:14:36 +0000433 LoadSubCommand ("source", CommandObjectSP (new CommandObjectCommandsSource (interpreter)));
434 LoadSubCommand ("alias", CommandObjectSP (new CommandObjectCommandsAlias (interpreter)));
435 LoadSubCommand ("unalias", CommandObjectSP (new CommandObjectCommandsUnalias (interpreter)));
Jim Ingham767af882010-07-07 03:36:20 +0000436}
437
438CommandObjectMultiwordCommands::~CommandObjectMultiwordCommands ()
439{
440}
441