blob: 7f9d151e17b6d7da39f96608a9504893d4b2bb12 [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:
34 CommandObjectCommandsSource() :
35 CommandObject ("commands source",
Caroline Ticeabb507a2010-09-08 21:06:11 +000036 "Read in debugger commands from the file <filename> and execute them.",
Jim Ingham767af882010-07-07 03:36:20 +000037 "command source <filename>")
38 {
39 }
40
41 ~CommandObjectCommandsSource ()
42 {
43 }
44
45 bool
46 Execute
47 (
48 CommandInterpreter &interpreter,
49 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 {
92 result.GetOutputStream().Printf("%s %s\n", interpreter.GetPrompt(), commands[i].c_str());
93 if (!interpreter.HandleCommand(commands[i].c_str(), false, result))
94 break;
95 }
96
97 if (i < num_commands)
98 {
99 result.AppendErrorWithFormat("Aborting source of '%s' after command '%s' failed.\n",
100 filename, commands[i].c_str());
101 result.SetStatus (eReturnStatusSuccessFinishResult);
102 }
103 else
104 {
105 success = true;
106 result.SetStatus (eReturnStatusFailed);
107 }
108 }
109 }
110 else
111 {
112 result.AppendErrorWithFormat ("File '%s' does not exist.\n", filename);
113 result.SetStatus (eReturnStatusFailed);
114 success = false;
115 }
116
117 if (success)
118 {
119 result.SetStatus (eReturnStatusSuccessFinishNoResult);
120 }
121 }
122 else
123 {
124 result.AppendErrorWithFormat("'%s' takes exactly one executable filename argument.\n", GetCommandName());
125 result.SetStatus (eReturnStatusFailed);
126 }
127 return result.Succeeded();
128
129 }
130};
131
132#pragma mark CommandObjectCommandsAlias
133//-------------------------------------------------------------------------
134// CommandObjectCommandsAlias
135//-------------------------------------------------------------------------
136
137class CommandObjectCommandsAlias : public CommandObject
138{
139public:
140 CommandObjectCommandsAlias () :
141 CommandObject ("commands alias",
Caroline Ticeabb507a2010-09-08 21:06:11 +0000142 "Allow users to define their own debugger command abbreviations.",
143 "commands alias <new_command> <old_command> [<options-for-aliased-command>]")
Jim Ingham767af882010-07-07 03:36:20 +0000144 {
145 SetHelpLong(
146 "'alias' allows the user to create a short-cut or abbreviation for long \n\
147 commands, multi-word commands, and commands that take particular options. \n\
148 Below are some simple examples of how one might use the 'alias' command: \n\
Sean Callanana3aff732010-08-09 18:50:15 +0000149 \n 'command alias sc script' // Creates the abbreviation 'sc' for the 'script' \n\
150 // command. \n\
151 'command alias bp breakpoint' // Creates the abbreviation 'bp' for the 'breakpoint' \n\
152 // command. Since breakpoint commands are two-word \n\
153 // commands, the user will still need to enter the \n\
154 // second word after 'bp', e.g. 'bp enable' or \n\
155 // 'bp delete'. \n\
156 'command alias bpi breakpoint list' // Creates the abbreviation 'bpi' for the \n\
157 // two-word command 'breakpoint list'. \n\
Jim Ingham767af882010-07-07 03:36:20 +0000158 \nAn alias can include some options for the command, with the values either \n\
159 filled in at the time the alias is created, or specified as positional \n\
160 arguments, to be filled in when the alias is invoked. The following example \n\
161 shows how to create aliases with options: \n\
162 \n\
Sean Callanana3aff732010-08-09 18:50:15 +0000163 'command alias bfl breakpoint set -f %1 -l %2' \n\
Jim Ingham767af882010-07-07 03:36:20 +0000164 \nThis creates the abbreviation 'bfl' (for break-file-line), with the -f and -l \n\
165 options already part of the alias. So if the user wants to set a breakpoint \n\
166 by file and line without explicitly having to use the -f and -l options, the \n\
167 user can now use 'bfl' instead. The '%1' and '%2' are positional placeholders \n\
168 for the actual arguments that will be passed when the alias command is used. \n\
169 The number in the placeholder refers to the position/order the actual value \n\
170 occupies when the alias is used. So all the occurrences of '%1' in the alias \n\
171 will be replaced with the first argument, all the occurrences of '%2' in the \n\
172 alias will be replaced with the second argument, and so on. This also allows \n\
173 actual arguments to be used multiple times within an alias (see 'process \n\
174 launch' example below). So in the 'bfl' case, the actual file value will be \n\
175 filled in with the first argument following 'bfl' and the actual line number \n\
176 value will be filled in with the second argument. The user would use this \n\
177 alias as follows: \n\
Sean Callanana3aff732010-08-09 18:50:15 +0000178 \n (dbg) commands alias bfl breakpoint set -f %1 -l %2 \n\
179 <... some time later ...> \n\
180 (dbg) bfl my-file.c 137 \n\
Jim Ingham767af882010-07-07 03:36:20 +0000181 \nThis would be the same as if the user had entered \n\
182 'breakpoint set -f my-file.c -l 137'. \n\
183 \nAnother example: \n\
Sean Callanana3aff732010-08-09 18:50:15 +0000184 \n (dbg) commands alias pltty process launch -s -o %1 -e %1 \n\
185 (dbg) pltty /dev/tty0 \n\
186 // becomes 'process launch -s -o /dev/tty0 -e /dev/tty0' \n\
Jim Ingham767af882010-07-07 03:36:20 +0000187 \nIf the user always wanted to pass the same value to a particular option, the \n\
188 alias could be defined with that value directly in the alias as a constant, \n\
189 rather than using a positional placeholder: \n\
Sean Callanana3aff732010-08-09 18:50:15 +0000190 \n commands alias bl3 breakpoint set -f %1 -l 3 // Always sets a breakpoint on line \n\
191 // 3 of whatever file is indicated. \n");
Jim Ingham767af882010-07-07 03:36:20 +0000192
193 }
194
195 ~CommandObjectCommandsAlias ()
196 {
197 }
198
199
200 bool
201 Execute
202 (
203 CommandInterpreter &interpreter,
204 Args& args,
205 CommandReturnObject &result
206 )
207 {
Greg Clayton54e7afa2010-07-09 20:39:50 +0000208 const size_t argc = args.GetArgumentCount();
Jim Ingham767af882010-07-07 03:36:20 +0000209
210 if (argc < 2)
Greg Clayton54e7afa2010-07-09 20:39:50 +0000211 {
Jim Ingham767af882010-07-07 03:36:20 +0000212 result.AppendError ("'alias' requires at least two arguments");
213 result.SetStatus (eReturnStatusFailed);
214 return false;
Greg Clayton54e7afa2010-07-09 20:39:50 +0000215 }
Jim Ingham767af882010-07-07 03:36:20 +0000216
217 const std::string alias_command = args.GetArgumentAtIndex(0);
218 const std::string actual_command = args.GetArgumentAtIndex(1);
219
220 args.Shift(); // Shift the alias command word off the argument vector.
221 args.Shift(); // Shift the old command word off the argument vector.
222
223 // Verify that the command is alias'able, and get the appropriate command object.
224
225 if (interpreter.CommandExists (alias_command.c_str()))
226 {
227 result.AppendErrorWithFormat ("'%s' is a permanent debugger command and cannot be redefined.\n",
228 alias_command.c_str());
229 result.SetStatus (eReturnStatusFailed);
230 }
231 else
232 {
233 CommandObjectSP command_obj_sp(interpreter.GetCommandSPExact (actual_command.c_str(), true));
234 CommandObjectSP subcommand_obj_sp;
235 bool use_subcommand = false;
236 if (command_obj_sp.get())
237 {
238 CommandObject *cmd_obj = command_obj_sp.get();
Greg Clayton54e7afa2010-07-09 20:39:50 +0000239 CommandObject *sub_cmd_obj = NULL;
Jim Ingham767af882010-07-07 03:36:20 +0000240 OptionArgVectorSP option_arg_vector_sp = OptionArgVectorSP (new OptionArgVector);
241 OptionArgVector *option_arg_vector = option_arg_vector_sp.get();
242
243 if (cmd_obj->IsMultiwordObject())
244 {
245 if (argc >= 3)
246 {
247 const std::string sub_command = args.GetArgumentAtIndex(0);
248 assert (sub_command.length() != 0);
249 subcommand_obj_sp =
250 (((CommandObjectMultiword *) cmd_obj)->GetSubcommandSP (sub_command.c_str()));
251 if (subcommand_obj_sp.get())
252 {
253 sub_cmd_obj = subcommand_obj_sp.get();
254 use_subcommand = true;
255 args.Shift(); // Shift the sub_command word off the argument vector.
256 }
257 else
258 {
259 result.AppendErrorWithFormat ("Error occurred while attempting to look up command '%s %s'.\n",
260 alias_command.c_str(), sub_command.c_str());
261 result.SetStatus (eReturnStatusFailed);
262 return false;
263 }
264 }
265 }
266
267 // Verify & handle any options/arguments passed to the alias command
268
269 if (args.GetArgumentCount () > 0)
270 {
271 if ((!use_subcommand && (cmd_obj->WantsRawCommandString()))
272 || (use_subcommand && (sub_cmd_obj->WantsRawCommandString())))
273 {
274 result.AppendErrorWithFormat ("'%s' cannot be aliased with any options or arguments.\n",
275 (use_subcommand ? sub_cmd_obj->GetCommandName()
276 : cmd_obj->GetCommandName()));
277 result.SetStatus (eReturnStatusFailed);
278 return false;
279 }
280
281 // options or arguments have been passed to the alias command, and must be
282 // verified & processed here.
283 if ((!use_subcommand && (cmd_obj->GetOptions() != NULL))
284 || (use_subcommand && (sub_cmd_obj->GetOptions() != NULL)))
285 {
286 Options *options;
287 if (use_subcommand)
288 options = sub_cmd_obj->GetOptions();
289 else
290 options = cmd_obj->GetOptions();
291 options->ResetOptionValues ();
292 args.Unshift ("dummy_arg");
293 args.ParseAliasOptions (*options, result, option_arg_vector);
294 args.Shift ();
295 if (result.Succeeded())
296 options->VerifyPartialOptions (result);
297 if (!result.Succeeded())
298 return false;
299 }
300 else
301 {
Greg Clayton54e7afa2010-07-09 20:39:50 +0000302 for (size_t i = 0; i < argc; ++i)
Jim Ingham767af882010-07-07 03:36:20 +0000303 option_arg_vector->push_back (OptionArgPair ("<argument>",
304 std::string (args.GetArgumentAtIndex (i))));
305 }
306 }
307
308 // Create the alias.
309
310 if (interpreter.AliasExists (alias_command.c_str())
311 || interpreter.UserCommandExists (alias_command.c_str()))
312 {
313 OptionArgVectorSP tmp_option_arg_sp (interpreter.GetAliasOptions (alias_command.c_str()));
314 if (tmp_option_arg_sp.get())
315 {
316 if (option_arg_vector->size() == 0)
317 interpreter.RemoveAliasOptions (alias_command.c_str());
318 }
319 result.AppendWarningWithFormat ("Overwriting existing definition for '%s'.\n",
320 alias_command.c_str());
321 }
322
323 if (use_subcommand)
324 interpreter.AddAlias (alias_command.c_str(), subcommand_obj_sp);
325 else
326 interpreter.AddAlias (alias_command.c_str(), command_obj_sp);
327 if (option_arg_vector->size() > 0)
328 interpreter.AddOrReplaceAliasOptions (alias_command.c_str(), option_arg_vector_sp);
329 result.SetStatus (eReturnStatusSuccessFinishNoResult);
330 }
331 else
332 {
333 result.AppendErrorWithFormat ("'%s' is not an existing command.\n", actual_command.c_str());
334 result.SetStatus (eReturnStatusFailed);
335 }
336 }
337
338 return result.Succeeded();
339 }
340};
341
342#pragma mark CommandObjectCommandsUnalias
343//-------------------------------------------------------------------------
344// CommandObjectCommandsUnalias
345//-------------------------------------------------------------------------
346
347class CommandObjectCommandsUnalias : public CommandObject
348{
349public:
350 CommandObjectCommandsUnalias () :
351 CommandObject ("commands unalias",
352 "Allows the user to remove/delete a user-defined command abbreviation.",
353 "unalias <alias-name-to-be-removed>")
354 {
355 }
356
357 ~CommandObjectCommandsUnalias()
358 {
359 }
360
361
362 bool
363 Execute
364 (
365 CommandInterpreter &interpreter,
366 Args& args,
367 CommandReturnObject &result
368 )
369 {
370 CommandObject::CommandMap::iterator pos;
371 CommandObject *cmd_obj;
372
373 if (args.GetArgumentCount() != 0)
374 {
375 const char *command_name = args.GetArgumentAtIndex(0);
376 cmd_obj = interpreter.GetCommandObject(command_name);
377 if (cmd_obj)
378 {
379 if (interpreter.CommandExists (command_name))
380 {
381 result.AppendErrorWithFormat ("'%s' is a permanent debugger command and cannot be removed.\n",
382 command_name);
383 result.SetStatus (eReturnStatusFailed);
384 }
385 else
386 {
387
388 if (interpreter.RemoveAlias (command_name) == false)
389 {
390 if (interpreter.AliasExists (command_name))
391 result.AppendErrorWithFormat ("Error occurred while attempting to unalias '%s'.\n",
392 command_name);
393 else
394 result.AppendErrorWithFormat ("'%s' is not an existing alias.\n", command_name);
395 result.SetStatus (eReturnStatusFailed);
396 }
397 else
398 result.SetStatus (eReturnStatusSuccessFinishNoResult);
399 }
400 }
401 else
402 {
403 result.AppendErrorWithFormat ("'%s' is not a known command.\nTry 'help' to see a "
404 "current list of commands.\n",
405 command_name);
406 result.SetStatus (eReturnStatusFailed);
407 }
408 }
409 else
410 {
411 result.AppendError ("must call 'unalias' with a valid alias");
412 result.SetStatus (eReturnStatusFailed);
413 }
414
415 return result.Succeeded();
416 }
417};
418
419#pragma mark CommandObjectMultiwordCommands
420
421//-------------------------------------------------------------------------
422// CommandObjectMultiwordCommands
423//-------------------------------------------------------------------------
424
425CommandObjectMultiwordCommands::CommandObjectMultiwordCommands (CommandInterpreter &interpreter) :
426 CommandObjectMultiword ("commands",
Caroline Ticec1ad82e2010-09-07 22:38:08 +0000427 "A set of commands for managing or customizing the debugger commands.",
Jim Ingham767af882010-07-07 03:36:20 +0000428 "commands <subcommand> [<subcommand-options>]")
429{
430 LoadSubCommand (interpreter, "source", CommandObjectSP (new CommandObjectCommandsSource ()));
431 LoadSubCommand (interpreter, "alias", CommandObjectSP (new CommandObjectCommandsAlias ()));
432}
433
434CommandObjectMultiwordCommands::~CommandObjectMultiwordCommands ()
435{
436}
437