blob: e8d43779e5f35cf68806406f8ad5bb7a809bbfad [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
Greg Clayton40e48242011-04-20 22:55:21 +000015#include "llvm/ADT/StringRef.h"
16
Jim Ingham767af882010-07-07 03:36:20 +000017// Project includes
Jim Ingham767af882010-07-07 03:36:20 +000018#include "lldb/Core/Debugger.h"
Greg Claytond12aeab2011-04-20 16:37:46 +000019#include "lldb/Core/InputReader.h"
20#include "lldb/Interpreter/Args.h"
Jim Ingham767af882010-07-07 03:36:20 +000021#include "lldb/Interpreter/CommandInterpreter.h"
Greg Claytond12aeab2011-04-20 16:37:46 +000022#include "lldb/Interpreter/CommandObjectRegexCommand.h"
Jim Ingham767af882010-07-07 03:36:20 +000023#include "lldb/Interpreter/CommandReturnObject.h"
24#include "lldb/Interpreter/Options.h"
25
26using namespace lldb;
27using namespace lldb_private;
28
Jim Ingham767af882010-07-07 03:36:20 +000029//-------------------------------------------------------------------------
30// CommandObjectCommandsSource
31//-------------------------------------------------------------------------
32
33class CommandObjectCommandsSource : public CommandObject
34{
Jim Ingham949d5ac2011-02-18 00:54:25 +000035private:
36
37 class CommandOptions : public Options
38 {
39 public:
40
Greg Claytonf15996e2011-04-07 22:46:35 +000041 CommandOptions (CommandInterpreter &interpreter) :
42 Options (interpreter)
43 {
44 }
Jim Ingham949d5ac2011-02-18 00:54:25 +000045
46 virtual
47 ~CommandOptions (){}
48
49 virtual Error
Greg Clayton143fcc32011-04-13 00:18:08 +000050 SetOptionValue (uint32_t option_idx, const char *option_arg)
Jim Ingham949d5ac2011-02-18 00:54:25 +000051 {
52 Error error;
53 char short_option = (char) m_getopt_table[option_idx].val;
54 bool success;
55
56 switch (short_option)
57 {
58 case 'e':
59 m_stop_on_error = Args::StringToBoolean(option_arg, true, &success);
60 if (!success)
61 error.SetErrorStringWithFormat("Invalid value for stop-on-error: %s.\n", option_arg);
62 break;
63 case 'c':
64 m_stop_on_continue = Args::StringToBoolean(option_arg, true, &success);
65 if (!success)
66 error.SetErrorStringWithFormat("Invalid value for stop-on-continue: %s.\n", option_arg);
67 break;
68 default:
69 error.SetErrorStringWithFormat ("Unrecognized option '%c'.\n", short_option);
70 break;
71 }
72
73 return error;
74 }
75
76 void
Greg Clayton143fcc32011-04-13 00:18:08 +000077 OptionParsingStarting ()
Jim Ingham949d5ac2011-02-18 00:54:25 +000078 {
Jim Ingham949d5ac2011-02-18 00:54:25 +000079 m_stop_on_error = true;
80 m_stop_on_continue = true;
81 }
82
Greg Claytonb3448432011-03-24 21:19:54 +000083 const OptionDefinition*
Jim Ingham949d5ac2011-02-18 00:54:25 +000084 GetDefinitions ()
85 {
86 return g_option_table;
87 }
88
89 // Options table: Required for subclasses of Options.
90
Greg Claytonb3448432011-03-24 21:19:54 +000091 static OptionDefinition g_option_table[];
Jim Ingham949d5ac2011-02-18 00:54:25 +000092
93 // Instance variables to hold the values for command options.
94
95 bool m_stop_on_error;
96 bool m_stop_on_continue;
97 };
98
Jim Ingham949d5ac2011-02-18 00:54:25 +000099 CommandOptions m_options;
100
101 virtual Options *
102 GetOptions ()
103 {
104 return &m_options;
105 }
106
Jim Ingham767af882010-07-07 03:36:20 +0000107public:
Greg Clayton238c0a12010-09-18 01:14:36 +0000108 CommandObjectCommandsSource(CommandInterpreter &interpreter) :
109 CommandObject (interpreter,
Greg Clayton40e48242011-04-20 22:55:21 +0000110 "command source",
Greg Clayton238c0a12010-09-18 01:14:36 +0000111 "Read in debugger commands from the file <filename> and execute them.",
Greg Claytonf15996e2011-04-07 22:46:35 +0000112 NULL),
113 m_options (interpreter)
Jim Ingham767af882010-07-07 03:36:20 +0000114 {
Caroline Tice43b014a2010-10-04 22:28:36 +0000115 CommandArgumentEntry arg;
116 CommandArgumentData file_arg;
117
118 // Define the first (and only) variant of this arg.
119 file_arg.arg_type = eArgTypeFilename;
120 file_arg.arg_repetition = eArgRepeatPlain;
121
122 // There is only one variant this argument could be; put it into the argument entry.
123 arg.push_back (file_arg);
124
125 // Push the data for the first argument into the m_arguments vector.
126 m_arguments.push_back (arg);
Jim Ingham767af882010-07-07 03:36:20 +0000127 }
128
129 ~CommandObjectCommandsSource ()
130 {
131 }
132
133 bool
134 Execute
135 (
Jim Ingham767af882010-07-07 03:36:20 +0000136 Args& args,
137 CommandReturnObject &result
138 )
139 {
140 const int argc = args.GetArgumentCount();
141 if (argc == 1)
142 {
143 const char *filename = args.GetArgumentAtIndex(0);
Jim Ingham767af882010-07-07 03:36:20 +0000144
145 result.AppendMessageWithFormat ("Executing commands in '%s'.\n", filename);
146
Johnny Chena83ea882010-10-20 21:40:50 +0000147 FileSpec cmd_file (filename, true);
Jim Ingham949d5ac2011-02-18 00:54:25 +0000148 ExecutionContext *exe_ctx = NULL; // Just use the default context.
149 bool echo_commands = true;
150 bool print_results = true;
Jim Ingham767af882010-07-07 03:36:20 +0000151
Jim Ingham949d5ac2011-02-18 00:54:25 +0000152 m_interpreter.HandleCommandsFromFile (cmd_file,
153 exe_ctx,
154 m_options.m_stop_on_continue,
155 m_options.m_stop_on_error,
156 echo_commands,
157 print_results,
158 result);
Jim Ingham767af882010-07-07 03:36:20 +0000159 }
160 else
161 {
162 result.AppendErrorWithFormat("'%s' takes exactly one executable filename argument.\n", GetCommandName());
163 result.SetStatus (eReturnStatusFailed);
164 }
165 return result.Succeeded();
166
167 }
168};
169
Greg Claytonb3448432011-03-24 21:19:54 +0000170OptionDefinition
Jim Ingham949d5ac2011-02-18 00:54:25 +0000171CommandObjectCommandsSource::CommandOptions::g_option_table[] =
172{
173{ LLDB_OPT_SET_ALL, false, "stop-on-error", 'e', required_argument, NULL, 0, eArgTypeBoolean, "If true, stop executing commands on error."},
174{ LLDB_OPT_SET_ALL, false, "stop-on-continue", 'c', required_argument, NULL, 0, eArgTypeBoolean, "If true, stop executing commands on continue."},
175{ 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
176};
177
Jim Ingham767af882010-07-07 03:36:20 +0000178#pragma mark CommandObjectCommandsAlias
179//-------------------------------------------------------------------------
180// CommandObjectCommandsAlias
181//-------------------------------------------------------------------------
182
183class CommandObjectCommandsAlias : public CommandObject
184{
185public:
Greg Clayton238c0a12010-09-18 01:14:36 +0000186 CommandObjectCommandsAlias (CommandInterpreter &interpreter) :
187 CommandObject (interpreter,
Greg Clayton40e48242011-04-20 22:55:21 +0000188 "command alias",
Caroline Ticeabb507a2010-09-08 21:06:11 +0000189 "Allow users to define their own debugger command abbreviations.",
Caroline Tice43b014a2010-10-04 22:28:36 +0000190 NULL)
Jim Ingham767af882010-07-07 03:36:20 +0000191 {
192 SetHelpLong(
193 "'alias' allows the user to create a short-cut or abbreviation for long \n\
194 commands, multi-word commands, and commands that take particular options. \n\
195 Below are some simple examples of how one might use the 'alias' command: \n\
Caroline Tice31fbb642010-09-08 22:08:58 +0000196 \n 'commands alias sc script' // Creates the abbreviation 'sc' for the 'script' \n\
197 // command. \n\
198 'commands alias bp breakpoint' // Creates the abbreviation 'bp' for the 'breakpoint' \n\
199 // command. Since breakpoint commands are two-word \n\
200 // commands, the user will still need to enter the \n\
201 // second word after 'bp', e.g. 'bp enable' or \n\
202 // 'bp delete'. \n\
203 'commands alias bpl breakpoint list' // Creates the abbreviation 'bpl' for the \n\
204 // two-word command 'breakpoint list'. \n\
Jim Ingham767af882010-07-07 03:36:20 +0000205 \nAn alias can include some options for the command, with the values either \n\
206 filled in at the time the alias is created, or specified as positional \n\
207 arguments, to be filled in when the alias is invoked. The following example \n\
208 shows how to create aliases with options: \n\
209 \n\
Caroline Tice31fbb642010-09-08 22:08:58 +0000210 'commands alias bfl breakpoint set -f %1 -l %2' \n\
Jim Ingham767af882010-07-07 03:36:20 +0000211 \nThis creates the abbreviation 'bfl' (for break-file-line), with the -f and -l \n\
212 options already part of the alias. So if the user wants to set a breakpoint \n\
213 by file and line without explicitly having to use the -f and -l options, the \n\
214 user can now use 'bfl' instead. The '%1' and '%2' are positional placeholders \n\
215 for the actual arguments that will be passed when the alias command is used. \n\
216 The number in the placeholder refers to the position/order the actual value \n\
217 occupies when the alias is used. So all the occurrences of '%1' in the alias \n\
218 will be replaced with the first argument, all the occurrences of '%2' in the \n\
219 alias will be replaced with the second argument, and so on. This also allows \n\
220 actual arguments to be used multiple times within an alias (see 'process \n\
221 launch' example below). So in the 'bfl' case, the actual file value will be \n\
222 filled in with the first argument following 'bfl' and the actual line number \n\
223 value will be filled in with the second argument. The user would use this \n\
224 alias as follows: \n\
Caroline Tice31fbb642010-09-08 22:08:58 +0000225 \n (lldb) commands alias bfl breakpoint set -f %1 -l %2 \n\
Sean Callanana3aff732010-08-09 18:50:15 +0000226 <... some time later ...> \n\
Caroline Tice31fbb642010-09-08 22:08:58 +0000227 (lldb) bfl my-file.c 137 \n\
Jim Ingham767af882010-07-07 03:36:20 +0000228 \nThis would be the same as if the user had entered \n\
229 'breakpoint set -f my-file.c -l 137'. \n\
230 \nAnother example: \n\
Caroline Tice31fbb642010-09-08 22:08:58 +0000231 \n (lldb) commands alias pltty process launch -s -o %1 -e %1 \n\
232 (lldb) pltty /dev/tty0 \n\
Sean Callanana3aff732010-08-09 18:50:15 +0000233 // becomes 'process launch -s -o /dev/tty0 -e /dev/tty0' \n\
Jim Ingham767af882010-07-07 03:36:20 +0000234 \nIf the user always wanted to pass the same value to a particular option, the \n\
235 alias could be defined with that value directly in the alias as a constant, \n\
236 rather than using a positional placeholder: \n\
Sean Callanana3aff732010-08-09 18:50:15 +0000237 \n commands alias bl3 breakpoint set -f %1 -l 3 // Always sets a breakpoint on line \n\
238 // 3 of whatever file is indicated. \n");
Jim Ingham767af882010-07-07 03:36:20 +0000239
Caroline Tice43b014a2010-10-04 22:28:36 +0000240 CommandArgumentEntry arg1;
241 CommandArgumentEntry arg2;
242 CommandArgumentEntry arg3;
243 CommandArgumentData alias_arg;
244 CommandArgumentData cmd_arg;
245 CommandArgumentData options_arg;
246
247 // Define the first (and only) variant of this arg.
248 alias_arg.arg_type = eArgTypeAliasName;
249 alias_arg.arg_repetition = eArgRepeatPlain;
250
251 // There is only one variant this argument could be; put it into the argument entry.
252 arg1.push_back (alias_arg);
253
254 // Define the first (and only) variant of this arg.
255 cmd_arg.arg_type = eArgTypeCommandName;
256 cmd_arg.arg_repetition = eArgRepeatPlain;
257
258 // There is only one variant this argument could be; put it into the argument entry.
259 arg2.push_back (cmd_arg);
260
261 // Define the first (and only) variant of this arg.
262 options_arg.arg_type = eArgTypeAliasOptions;
263 options_arg.arg_repetition = eArgRepeatOptional;
264
265 // There is only one variant this argument could be; put it into the argument entry.
266 arg3.push_back (options_arg);
267
268 // Push the data for the first argument into the m_arguments vector.
269 m_arguments.push_back (arg1);
270 m_arguments.push_back (arg2);
271 m_arguments.push_back (arg3);
Jim Ingham767af882010-07-07 03:36:20 +0000272 }
273
274 ~CommandObjectCommandsAlias ()
275 {
276 }
277
Caroline Ticee0da7a52010-12-09 22:52:49 +0000278 bool
279 WantsRawCommandString ()
280 {
281 return true;
282 }
283
284 bool
285 ExecuteRawCommandString (const char *raw_command_line, CommandReturnObject &result)
286 {
287 Args args (raw_command_line);
288 std::string raw_command_string (raw_command_line);
289
290 size_t argc = args.GetArgumentCount();
291
292 if (argc < 2)
293 {
294 result.AppendError ("'alias' requires at least two arguments");
295 result.SetStatus (eReturnStatusFailed);
296 return false;
297 }
298
299 // Get the alias command.
300
301 const std::string alias_command = args.GetArgumentAtIndex (0);
302
303 // Strip the new alias name off 'raw_command_string' (leave it on args, which gets passed to 'Execute', which
304 // does the stripping itself.
305 size_t pos = raw_command_string.find (alias_command);
306 if (pos == 0)
307 {
308 raw_command_string = raw_command_string.substr (alias_command.size());
309 pos = raw_command_string.find_first_not_of (' ');
310 if ((pos != std::string::npos) && (pos > 0))
311 raw_command_string = raw_command_string.substr (pos);
312 }
313 else
314 {
315 result.AppendError ("Error parsing command string. No alias created.");
316 result.SetStatus (eReturnStatusFailed);
317 return false;
318 }
319
320
321 // Verify that the command is alias-able.
322 if (m_interpreter.CommandExists (alias_command.c_str()))
323 {
324 result.AppendErrorWithFormat ("'%s' is a permanent debugger command and cannot be redefined.\n",
325 alias_command.c_str());
326 result.SetStatus (eReturnStatusFailed);
327 return false;
328 }
329
330 // Get CommandObject that is being aliased. The command name is read from the front of raw_command_string.
331 // raw_command_string is returned with the name of the command object stripped off the front.
332 CommandObject *cmd_obj = m_interpreter.GetCommandObjectForCommand (raw_command_string);
333
334 if (!cmd_obj)
335 {
336 result.AppendErrorWithFormat ("Invalid command given to 'alias'. '%s' does not begin with a valid command."
337 " No alias created.", raw_command_string.c_str());
338 result.SetStatus (eReturnStatusFailed);
339 return false;
340 }
341 else if (!cmd_obj->WantsRawCommandString ())
342 {
343 // Note that args was initialized with the original command, and has not been updated to this point.
344 // Therefore can we pass it to the version of Execute that does not need/expect raw input in the alias.
345 return Execute (args, result);
346 }
347 else
348 {
349 // Verify & handle any options/arguments passed to the alias command
350
351 OptionArgVectorSP option_arg_vector_sp = OptionArgVectorSP (new OptionArgVector);
352 OptionArgVector *option_arg_vector = option_arg_vector_sp.get();
353
Caroline Tice5ddbe212011-05-06 21:37:15 +0000354 CommandObjectSP cmd_obj_sp = m_interpreter.GetCommandSPExact (cmd_obj->GetCommandName(), false);
355
356 if (!m_interpreter.ProcessAliasOptionsArgs (cmd_obj_sp, raw_command_string.c_str(), option_arg_vector_sp))
Caroline Ticee0da7a52010-12-09 22:52:49 +0000357 {
Caroline Tice5ddbe212011-05-06 21:37:15 +0000358 result.AppendError ("Unable to create requested alias.\n");
359 result.SetStatus (eReturnStatusFailed);
360 return false;
Caroline Ticee0da7a52010-12-09 22:52:49 +0000361 }
362
363 // Create the alias
364 if (m_interpreter.AliasExists (alias_command.c_str())
365 || m_interpreter.UserCommandExists (alias_command.c_str()))
366 {
367 OptionArgVectorSP temp_option_arg_sp (m_interpreter.GetAliasOptions (alias_command.c_str()));
368 if (temp_option_arg_sp.get())
369 {
370 if (option_arg_vector->size() == 0)
371 m_interpreter.RemoveAliasOptions (alias_command.c_str());
372 }
373 result.AppendWarningWithFormat ("Overwriting existing definition for '%s'.\n",
374 alias_command.c_str());
375 }
376
Caroline Tice56d2fc42010-12-14 18:51:39 +0000377 if (cmd_obj_sp)
378 {
379 m_interpreter.AddAlias (alias_command.c_str(), cmd_obj_sp);
380 if (option_arg_vector->size() > 0)
381 m_interpreter.AddOrReplaceAliasOptions (alias_command.c_str(), option_arg_vector_sp);
382 result.SetStatus (eReturnStatusSuccessFinishNoResult);
383 }
384 else
385 {
386 result.AppendError ("Unable to create requested alias.\n");
387 result.SetStatus (eReturnStatusFailed);
388 }
Caroline Ticee0da7a52010-12-09 22:52:49 +0000389 }
390 return result.Succeeded();
391 }
Jim Ingham767af882010-07-07 03:36:20 +0000392
393 bool
394 Execute
395 (
Jim Ingham767af882010-07-07 03:36:20 +0000396 Args& args,
397 CommandReturnObject &result
398 )
399 {
Caroline Tice8bb61f02010-09-21 23:25:40 +0000400 size_t argc = args.GetArgumentCount();
Jim Ingham767af882010-07-07 03:36:20 +0000401
402 if (argc < 2)
Greg Clayton54e7afa2010-07-09 20:39:50 +0000403 {
Jim Ingham767af882010-07-07 03:36:20 +0000404 result.AppendError ("'alias' requires at least two arguments");
405 result.SetStatus (eReturnStatusFailed);
406 return false;
Greg Clayton54e7afa2010-07-09 20:39:50 +0000407 }
Jim Ingham767af882010-07-07 03:36:20 +0000408
409 const std::string alias_command = args.GetArgumentAtIndex(0);
410 const std::string actual_command = args.GetArgumentAtIndex(1);
411
412 args.Shift(); // Shift the alias command word off the argument vector.
413 args.Shift(); // Shift the old command word off the argument vector.
414
415 // Verify that the command is alias'able, and get the appropriate command object.
416
Greg Clayton238c0a12010-09-18 01:14:36 +0000417 if (m_interpreter.CommandExists (alias_command.c_str()))
Jim Ingham767af882010-07-07 03:36:20 +0000418 {
419 result.AppendErrorWithFormat ("'%s' is a permanent debugger command and cannot be redefined.\n",
420 alias_command.c_str());
421 result.SetStatus (eReturnStatusFailed);
422 }
423 else
424 {
Greg Clayton238c0a12010-09-18 01:14:36 +0000425 CommandObjectSP command_obj_sp(m_interpreter.GetCommandSPExact (actual_command.c_str(), true));
Jim Ingham767af882010-07-07 03:36:20 +0000426 CommandObjectSP subcommand_obj_sp;
427 bool use_subcommand = false;
428 if (command_obj_sp.get())
429 {
430 CommandObject *cmd_obj = command_obj_sp.get();
Greg Clayton54e7afa2010-07-09 20:39:50 +0000431 CommandObject *sub_cmd_obj = NULL;
Jim Ingham767af882010-07-07 03:36:20 +0000432 OptionArgVectorSP option_arg_vector_sp = OptionArgVectorSP (new OptionArgVector);
433 OptionArgVector *option_arg_vector = option_arg_vector_sp.get();
434
Caroline Ticee0da7a52010-12-09 22:52:49 +0000435 while (cmd_obj->IsMultiwordObject() && args.GetArgumentCount() > 0)
Jim Ingham767af882010-07-07 03:36:20 +0000436 {
437 if (argc >= 3)
438 {
439 const std::string sub_command = args.GetArgumentAtIndex(0);
440 assert (sub_command.length() != 0);
441 subcommand_obj_sp =
442 (((CommandObjectMultiword *) cmd_obj)->GetSubcommandSP (sub_command.c_str()));
443 if (subcommand_obj_sp.get())
444 {
445 sub_cmd_obj = subcommand_obj_sp.get();
446 use_subcommand = true;
447 args.Shift(); // Shift the sub_command word off the argument vector.
Caroline Ticee0da7a52010-12-09 22:52:49 +0000448 cmd_obj = sub_cmd_obj;
Jim Ingham767af882010-07-07 03:36:20 +0000449 }
450 else
451 {
Caroline Tice5d53b622010-11-02 19:00:04 +0000452 result.AppendErrorWithFormat("'%s' is not a valid sub-command of '%s'. "
453 "Unable to create alias.\n",
454 sub_command.c_str(), actual_command.c_str());
Jim Ingham767af882010-07-07 03:36:20 +0000455 result.SetStatus (eReturnStatusFailed);
456 return false;
457 }
458 }
459 }
460
461 // Verify & handle any options/arguments passed to the alias command
462
463 if (args.GetArgumentCount () > 0)
464 {
Caroline Tice5ddbe212011-05-06 21:37:15 +0000465 CommandObjectSP tmp_sp = m_interpreter.GetCommandSPExact (cmd_obj->GetCommandName(), false);
466 if (use_subcommand)
467 tmp_sp = m_interpreter.GetCommandSPExact (sub_cmd_obj->GetCommandName(), false);
468
469 std::string args_string;
470 args.GetCommandString (args_string);
471
472 if (!m_interpreter.ProcessAliasOptionsArgs (tmp_sp, args_string.c_str(), option_arg_vector_sp))
473 {
474 result.AppendError ("Unable to create requested alias.\n");
475 result.SetStatus (eReturnStatusFailed);
476 return false;
477 }
Jim Ingham767af882010-07-07 03:36:20 +0000478 }
479
480 // Create the alias.
481
Greg Clayton238c0a12010-09-18 01:14:36 +0000482 if (m_interpreter.AliasExists (alias_command.c_str())
483 || m_interpreter.UserCommandExists (alias_command.c_str()))
Jim Ingham767af882010-07-07 03:36:20 +0000484 {
Greg Clayton238c0a12010-09-18 01:14:36 +0000485 OptionArgVectorSP tmp_option_arg_sp (m_interpreter.GetAliasOptions (alias_command.c_str()));
Jim Ingham767af882010-07-07 03:36:20 +0000486 if (tmp_option_arg_sp.get())
487 {
488 if (option_arg_vector->size() == 0)
Greg Clayton238c0a12010-09-18 01:14:36 +0000489 m_interpreter.RemoveAliasOptions (alias_command.c_str());
Jim Ingham767af882010-07-07 03:36:20 +0000490 }
491 result.AppendWarningWithFormat ("Overwriting existing definition for '%s'.\n",
492 alias_command.c_str());
493 }
494
495 if (use_subcommand)
Greg Clayton238c0a12010-09-18 01:14:36 +0000496 m_interpreter.AddAlias (alias_command.c_str(), subcommand_obj_sp);
Jim Ingham767af882010-07-07 03:36:20 +0000497 else
Greg Clayton238c0a12010-09-18 01:14:36 +0000498 m_interpreter.AddAlias (alias_command.c_str(), command_obj_sp);
Jim Ingham767af882010-07-07 03:36:20 +0000499 if (option_arg_vector->size() > 0)
Greg Clayton238c0a12010-09-18 01:14:36 +0000500 m_interpreter.AddOrReplaceAliasOptions (alias_command.c_str(), option_arg_vector_sp);
Jim Ingham767af882010-07-07 03:36:20 +0000501 result.SetStatus (eReturnStatusSuccessFinishNoResult);
502 }
503 else
504 {
505 result.AppendErrorWithFormat ("'%s' is not an existing command.\n", actual_command.c_str());
506 result.SetStatus (eReturnStatusFailed);
Caroline Ticee6866a32010-10-28 23:17:48 +0000507 return false;
Jim Ingham767af882010-07-07 03:36:20 +0000508 }
509 }
510
511 return result.Succeeded();
512 }
513};
514
515#pragma mark CommandObjectCommandsUnalias
516//-------------------------------------------------------------------------
517// CommandObjectCommandsUnalias
518//-------------------------------------------------------------------------
519
520class CommandObjectCommandsUnalias : public CommandObject
521{
522public:
Greg Clayton238c0a12010-09-18 01:14:36 +0000523 CommandObjectCommandsUnalias (CommandInterpreter &interpreter) :
524 CommandObject (interpreter,
Greg Clayton40e48242011-04-20 22:55:21 +0000525 "command unalias",
Caroline Tice146292c2010-09-12 04:56:10 +0000526 "Allow the user to remove/delete a user-defined command abbreviation.",
Caroline Tice43b014a2010-10-04 22:28:36 +0000527 NULL)
Jim Ingham767af882010-07-07 03:36:20 +0000528 {
Caroline Tice43b014a2010-10-04 22:28:36 +0000529 CommandArgumentEntry arg;
530 CommandArgumentData alias_arg;
531
532 // Define the first (and only) variant of this arg.
533 alias_arg.arg_type = eArgTypeAliasName;
534 alias_arg.arg_repetition = eArgRepeatPlain;
535
536 // There is only one variant this argument could be; put it into the argument entry.
537 arg.push_back (alias_arg);
538
539 // Push the data for the first argument into the m_arguments vector.
540 m_arguments.push_back (arg);
Jim Ingham767af882010-07-07 03:36:20 +0000541 }
542
543 ~CommandObjectCommandsUnalias()
544 {
545 }
546
547
548 bool
549 Execute
550 (
Jim Ingham767af882010-07-07 03:36:20 +0000551 Args& args,
552 CommandReturnObject &result
553 )
554 {
555 CommandObject::CommandMap::iterator pos;
556 CommandObject *cmd_obj;
557
558 if (args.GetArgumentCount() != 0)
559 {
560 const char *command_name = args.GetArgumentAtIndex(0);
Greg Clayton238c0a12010-09-18 01:14:36 +0000561 cmd_obj = m_interpreter.GetCommandObject(command_name);
Jim Ingham767af882010-07-07 03:36:20 +0000562 if (cmd_obj)
563 {
Greg Clayton238c0a12010-09-18 01:14:36 +0000564 if (m_interpreter.CommandExists (command_name))
Jim Ingham767af882010-07-07 03:36:20 +0000565 {
566 result.AppendErrorWithFormat ("'%s' is a permanent debugger command and cannot be removed.\n",
567 command_name);
568 result.SetStatus (eReturnStatusFailed);
569 }
570 else
571 {
572
Greg Clayton238c0a12010-09-18 01:14:36 +0000573 if (m_interpreter.RemoveAlias (command_name) == false)
Jim Ingham767af882010-07-07 03:36:20 +0000574 {
Greg Clayton238c0a12010-09-18 01:14:36 +0000575 if (m_interpreter.AliasExists (command_name))
Jim Ingham767af882010-07-07 03:36:20 +0000576 result.AppendErrorWithFormat ("Error occurred while attempting to unalias '%s'.\n",
577 command_name);
578 else
579 result.AppendErrorWithFormat ("'%s' is not an existing alias.\n", command_name);
580 result.SetStatus (eReturnStatusFailed);
581 }
582 else
583 result.SetStatus (eReturnStatusSuccessFinishNoResult);
584 }
585 }
586 else
587 {
588 result.AppendErrorWithFormat ("'%s' is not a known command.\nTry 'help' to see a "
589 "current list of commands.\n",
590 command_name);
591 result.SetStatus (eReturnStatusFailed);
592 }
593 }
594 else
595 {
596 result.AppendError ("must call 'unalias' with a valid alias");
597 result.SetStatus (eReturnStatusFailed);
598 }
599
600 return result.Succeeded();
601 }
602};
603
Greg Claytond12aeab2011-04-20 16:37:46 +0000604#pragma mark CommandObjectCommandsAddRegex
605//-------------------------------------------------------------------------
606// CommandObjectCommandsAddRegex
607//-------------------------------------------------------------------------
608
609class CommandObjectCommandsAddRegex : public CommandObject
610{
611public:
612 CommandObjectCommandsAddRegex (CommandInterpreter &interpreter) :
613 CommandObject (interpreter,
Greg Clayton40e48242011-04-20 22:55:21 +0000614 "command regex",
Greg Claytond12aeab2011-04-20 16:37:46 +0000615 "Allow the user to create a regular expression command.",
Greg Clayton40e48242011-04-20 22:55:21 +0000616 "command regex <cmd-name> [s/<regex>/<subst>/ ...]"),
Greg Claytond12aeab2011-04-20 16:37:46 +0000617 m_options (interpreter)
618 {
Greg Clayton40e48242011-04-20 22:55:21 +0000619 SetHelpLong(
620"This command allows the user to create powerful regular expression commands\n"
621"with substitutions. The regular expressions and substitutions are specified\n"
622"using the regular exression substitution format of:\n"
623"\n"
624" s/<regex>/<subst>/\n"
625"\n"
626"<regex> is a regular expression that can use parenthesis to capture regular\n"
627"expression input and substitute the captured matches in the output using %1\n"
628"for the first match, %2 for the second, and so on.\n"
629"\n"
630"The regular expressions can all be specified on the command line if more than\n"
631"one argument is provided. If just the command name is provided on the command\n"
632"line, then the regular expressions and substitutions can be entered on separate\n"
633" lines, followed by an empty line to terminate the command definition.\n"
634"\n"
635"EXAMPLES\n"
636"\n"
637"The following example with define a regular expression command named 'f' that\n"
638"will call 'finish' if there are no arguments, or 'frame select <frame-idx>' if\n"
639"a number follows 'f':\n"
640"(lldb) command regex f s/^$/finish/ 's/([0-9]+)/frame select %1/'\n"
641 );
Greg Claytond12aeab2011-04-20 16:37:46 +0000642 }
643
644 ~CommandObjectCommandsAddRegex()
645 {
646 }
647
648
649 bool
650 Execute (Args& args, CommandReturnObject &result)
651 {
Greg Clayton40e48242011-04-20 22:55:21 +0000652 const size_t argc = args.GetArgumentCount();
653 if (argc == 0)
Greg Claytond12aeab2011-04-20 16:37:46 +0000654 {
Greg Clayton40e48242011-04-20 22:55:21 +0000655 result.AppendError ("usage: 'commands regex <command-name> [s/<regex1>/<subst1>/ s/<regex2>/<subst2>/ ...]'\n");
656 result.SetStatus (eReturnStatusFailed);
657 }
658 else
659 {
660 Error error;
Greg Claytond12aeab2011-04-20 16:37:46 +0000661 const char *name = args.GetArgumentAtIndex(0);
Greg Claytond12aeab2011-04-20 16:37:46 +0000662 m_regex_cmd_ap.reset (new CommandObjectRegexCommand (m_interpreter,
663 name,
664 m_options.GetHelp (),
665 m_options.GetSyntax (),
666 10));
Greg Clayton40e48242011-04-20 22:55:21 +0000667
668 if (argc == 1)
Greg Claytond12aeab2011-04-20 16:37:46 +0000669 {
Greg Clayton40e48242011-04-20 22:55:21 +0000670 InputReaderSP reader_sp (new InputReader(m_interpreter.GetDebugger()));
671 if (reader_sp)
672 {
673 error =reader_sp->Initialize (CommandObjectCommandsAddRegex::InputReaderCallback,
Greg Claytond12aeab2011-04-20 16:37:46 +0000674 this, // baton
675 eInputReaderGranularityLine, // token size, to pass to callback function
Greg Clayton40e48242011-04-20 22:55:21 +0000676 NULL, // end token
Greg Claytond12aeab2011-04-20 16:37:46 +0000677 "> ", // prompt
Greg Clayton40e48242011-04-20 22:55:21 +0000678 true); // echo input
679 if (error.Success())
680 {
681 m_interpreter.GetDebugger().PushInputReader (reader_sp);
682 result.SetStatus (eReturnStatusSuccessFinishNoResult);
683 return true;
684 }
Greg Claytond12aeab2011-04-20 16:37:46 +0000685 }
686 }
Greg Clayton40e48242011-04-20 22:55:21 +0000687 else
688 {
689 for (size_t arg_idx = 1; arg_idx < argc; ++arg_idx)
690 {
691 llvm::StringRef arg_strref (args.GetArgumentAtIndex(arg_idx));
692 error = AppendRegexSubstitution (arg_strref);
693 if (error.Fail())
694 break;
695 }
696
697 if (error.Success())
698 {
699 AddRegexCommandToInterpreter();
700 }
701 }
702 if (error.Fail())
703 {
704 result.AppendError (error.AsCString());
705 result.SetStatus (eReturnStatusFailed);
706 }
Greg Claytond12aeab2011-04-20 16:37:46 +0000707 }
Greg Clayton40e48242011-04-20 22:55:21 +0000708
Greg Claytond12aeab2011-04-20 16:37:46 +0000709 return result.Succeeded();
710 }
711
Greg Clayton40e48242011-04-20 22:55:21 +0000712 Error
713 AppendRegexSubstitution (const llvm::StringRef &regex_sed)
Greg Claytond12aeab2011-04-20 16:37:46 +0000714 {
Greg Clayton40e48242011-04-20 22:55:21 +0000715 Error error;
716
717 if (m_regex_cmd_ap.get() == NULL)
Greg Claytond12aeab2011-04-20 16:37:46 +0000718 {
Greg Clayton40e48242011-04-20 22:55:21 +0000719 error.SetErrorStringWithFormat("invalid regular expression command object for: '%.*s'",
720 (int)regex_sed.size(),
721 regex_sed.data());
722 return error;
Greg Claytond12aeab2011-04-20 16:37:46 +0000723 }
Greg Clayton40e48242011-04-20 22:55:21 +0000724
725 size_t regex_sed_size = regex_sed.size();
726
727 if (regex_sed_size <= 1)
728 {
729 error.SetErrorStringWithFormat("regular expression substitution string is too short: '%.*s'",
730 (int)regex_sed.size(),
731 regex_sed.data());
732 return error;
733 }
734
735 if (regex_sed[0] != 's')
736 {
737 error.SetErrorStringWithFormat("regular expression substitution string doesn't start with 's': '%.*s'",
738 (int)regex_sed.size(),
739 regex_sed.data());
740 return error;
741 }
742 const size_t first_separator_char_pos = 1;
743 // use the char that follows 's' as the regex separator character
744 // so we can have "s/<regex>/<subst>/" or "s|<regex>|<subst>|"
745 const char separator_char = regex_sed[first_separator_char_pos];
746 const size_t second_separator_char_pos = regex_sed.find (separator_char, first_separator_char_pos + 1);
747
748 if (second_separator_char_pos == std::string::npos)
749 {
750 error.SetErrorStringWithFormat("missing second '%c' separator char after '%.*s'",
751 separator_char,
752 (int)(regex_sed.size() - first_separator_char_pos - 1),
753 regex_sed.data() + (first_separator_char_pos + 1));
754 return error;
755 }
756
757 const size_t third_separator_char_pos = regex_sed.find (separator_char, second_separator_char_pos + 1);
758
759 if (third_separator_char_pos == std::string::npos)
760 {
761 error.SetErrorStringWithFormat("missing third '%c' separator char after '%.*s'",
762 separator_char,
763 (int)(regex_sed.size() - second_separator_char_pos - 1),
764 regex_sed.data() + (second_separator_char_pos + 1));
765 return error;
766 }
767
768 if (third_separator_char_pos != regex_sed_size - 1)
769 {
770 // Make sure that everything that follows the last regex
771 // separator char
772 if (regex_sed.find_first_not_of("\t\n\v\f\r ", third_separator_char_pos + 1) != std::string::npos)
773 {
774 error.SetErrorStringWithFormat("extra data found after the '%.*s' regular expression substitution string: '%.*s'",
775 (int)third_separator_char_pos + 1,
776 regex_sed.data(),
777 (int)(regex_sed.size() - third_separator_char_pos - 1),
778 regex_sed.data() + (third_separator_char_pos + 1));
779 return error;
780 }
781
782 }
783 else if (first_separator_char_pos + 1 == second_separator_char_pos)
784 {
785 error.SetErrorStringWithFormat("<regex> can't be empty in 's%c<regex>%c<subst>%c' string: '%.*s'",
786 separator_char,
787 separator_char,
788 separator_char,
789 (int)regex_sed.size(),
790 regex_sed.data());
791 return error;
792 }
793 else if (second_separator_char_pos + 1 == third_separator_char_pos)
794 {
795 error.SetErrorStringWithFormat("<subst> can't be empty in 's%c<regex>%c<subst>%c' string: '%.*s'",
796 separator_char,
797 separator_char,
798 separator_char,
799 (int)regex_sed.size(),
800 regex_sed.data());
801 return error;
802 }
803 std::string regex(regex_sed.substr(first_separator_char_pos + 1, second_separator_char_pos - first_separator_char_pos - 1));
804 std::string subst(regex_sed.substr(second_separator_char_pos + 1, third_separator_char_pos - second_separator_char_pos - 1));
805 m_regex_cmd_ap->AddRegexCommand (regex.c_str(),
806 subst.c_str());
807 return error;
Greg Claytond12aeab2011-04-20 16:37:46 +0000808 }
809
810 void
Greg Clayton40e48242011-04-20 22:55:21 +0000811 AddRegexCommandToInterpreter()
Greg Claytond12aeab2011-04-20 16:37:46 +0000812 {
813 if (m_regex_cmd_ap.get())
814 {
815 if (m_regex_cmd_ap->HasRegexEntries())
816 {
817 CommandObjectSP cmd_sp (m_regex_cmd_ap.release());
818 m_interpreter.AddCommand(cmd_sp->GetCommandName(), cmd_sp, true);
819 }
820 }
821 }
822
Greg Clayton40e48242011-04-20 22:55:21 +0000823 void
824 InputReaderDidCancel()
825 {
826 m_regex_cmd_ap.reset();
827 }
828
Greg Claytond12aeab2011-04-20 16:37:46 +0000829 static size_t
830 InputReaderCallback (void *baton,
831 InputReader &reader,
832 lldb::InputReaderAction notification,
833 const char *bytes,
834 size_t bytes_len);
835private:
836 std::auto_ptr<CommandObjectRegexCommand> m_regex_cmd_ap;
837
838 class CommandOptions : public Options
839 {
840 public:
841
842 CommandOptions (CommandInterpreter &interpreter) :
843 Options (interpreter)
844 {
845 }
846
847 virtual
848 ~CommandOptions (){}
849
850 virtual Error
851 SetOptionValue (uint32_t option_idx, const char *option_arg)
852 {
853 Error error;
854 char short_option = (char) m_getopt_table[option_idx].val;
855
856 switch (short_option)
857 {
858 case 'h':
859 m_help.assign (option_arg);
860 break;
861 case 's':
862 m_syntax.assign (option_arg);
863 break;
864
865 default:
866 error.SetErrorStringWithFormat ("Unrecognized option '%c'.\n", short_option);
867 break;
868 }
869
870 return error;
871 }
872
873 void
874 OptionParsingStarting ()
875 {
876 m_help.clear();
877 m_syntax.clear();
878 }
879
880 const OptionDefinition*
881 GetDefinitions ()
882 {
883 return g_option_table;
884 }
885
886 // Options table: Required for subclasses of Options.
887
888 static OptionDefinition g_option_table[];
889
890 const char *
891 GetHelp ()
892 {
893 if (m_help.empty())
894 return NULL;
895 return m_help.c_str();
896 }
897 const char *
898 GetSyntax ()
899 {
900 if (m_syntax.empty())
901 return NULL;
902 return m_syntax.c_str();
903 }
904 // Instance variables to hold the values for command options.
905 protected:
906 std::string m_help;
907 std::string m_syntax;
908 };
909
910 CommandOptions m_options;
911
912 virtual Options *
913 GetOptions ()
914 {
915 return &m_options;
916 }
917
918};
919
920size_t
921CommandObjectCommandsAddRegex::InputReaderCallback (void *baton,
922 InputReader &reader,
923 lldb::InputReaderAction notification,
924 const char *bytes,
925 size_t bytes_len)
926{
927 CommandObjectCommandsAddRegex *add_regex_cmd = (CommandObjectCommandsAddRegex *) baton;
928
929 switch (notification)
930 {
931 case eInputReaderActivate:
Caroline Tice2b5e4e62011-06-15 19:35:17 +0000932 {
933 StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream ();
934 out_stream->Printf("%s\n", "Enter regular expressions in the form 's/<regex>/<subst>/' and terminate with an empty line:");
935 out_stream->Flush();
936 }
Greg Claytond12aeab2011-04-20 16:37:46 +0000937 break;
938 case eInputReaderReactivate:
939 break;
940
941 case eInputReaderDeactivate:
942 break;
Caroline Tice4a348082011-05-02 20:41:46 +0000943
944 case eInputReaderAsynchronousOutputWritten:
945 break;
946
Greg Claytond12aeab2011-04-20 16:37:46 +0000947 case eInputReaderGotToken:
Greg Clayton40e48242011-04-20 22:55:21 +0000948 while (bytes_len > 0 && (bytes[bytes_len-1] == '\r' || bytes[bytes_len-1] == '\n'))
949 --bytes_len;
Greg Claytond12aeab2011-04-20 16:37:46 +0000950 if (bytes_len == 0)
951 reader.SetIsDone(true);
952 else if (bytes)
953 {
Greg Clayton40e48242011-04-20 22:55:21 +0000954 llvm::StringRef bytes_strref (bytes, bytes_len);
955 Error error (add_regex_cmd->AppendRegexSubstitution (bytes_strref));
956 if (error.Fail())
Greg Claytond12aeab2011-04-20 16:37:46 +0000957 {
Caroline Tice2b5e4e62011-06-15 19:35:17 +0000958 StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream();
959 out_stream->Printf("error: %s\n", error.AsCString());
960 out_stream->Flush();
Greg Clayton40e48242011-04-20 22:55:21 +0000961 add_regex_cmd->InputReaderDidCancel ();
962 reader.SetIsDone (true);
Greg Claytond12aeab2011-04-20 16:37:46 +0000963 }
964 }
965 break;
966
967 case eInputReaderInterrupt:
Caroline Tice2b5e4e62011-06-15 19:35:17 +0000968 {
969 reader.SetIsDone (true);
970 StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream();
971 out_stream->PutCString("Regular expression command creations was cancelled.\n");
972 out_stream->Flush();
973 add_regex_cmd->InputReaderDidCancel ();
974 }
Greg Claytond12aeab2011-04-20 16:37:46 +0000975 break;
976
977 case eInputReaderEndOfFile:
978 reader.SetIsDone (true);
979 break;
980
981 case eInputReaderDone:
Greg Clayton40e48242011-04-20 22:55:21 +0000982 add_regex_cmd->AddRegexCommandToInterpreter();
Greg Claytond12aeab2011-04-20 16:37:46 +0000983 break;
984 }
985
986 return bytes_len;
987}
988
989
990OptionDefinition
991CommandObjectCommandsAddRegex::CommandOptions::g_option_table[] =
992{
Greg Clayton40e48242011-04-20 22:55:21 +0000993{ LLDB_OPT_SET_1, false, "help" , 'h', required_argument, NULL, 0, eArgTypeNone, "The help text to display for this command."},
Greg Claytond12aeab2011-04-20 16:37:46 +0000994{ LLDB_OPT_SET_1, false, "syntax", 's', required_argument, NULL, 0, eArgTypeNone, "A syntax string showing the typical usage syntax."},
Greg Clayton40e48242011-04-20 22:55:21 +0000995{ 0 , false, NULL , 0 , 0 , NULL, 0, eArgTypeNone, NULL }
Greg Claytond12aeab2011-04-20 16:37:46 +0000996};
997
998
Jim Ingham767af882010-07-07 03:36:20 +0000999#pragma mark CommandObjectMultiwordCommands
1000
1001//-------------------------------------------------------------------------
1002// CommandObjectMultiwordCommands
1003//-------------------------------------------------------------------------
1004
1005CommandObjectMultiwordCommands::CommandObjectMultiwordCommands (CommandInterpreter &interpreter) :
Greg Clayton238c0a12010-09-18 01:14:36 +00001006 CommandObjectMultiword (interpreter,
Greg Clayton40e48242011-04-20 22:55:21 +00001007 "command",
Caroline Ticec1ad82e2010-09-07 22:38:08 +00001008 "A set of commands for managing or customizing the debugger commands.",
Greg Clayton40e48242011-04-20 22:55:21 +00001009 "command <subcommand> [<subcommand-options>]")
Jim Ingham767af882010-07-07 03:36:20 +00001010{
Greg Clayton238c0a12010-09-18 01:14:36 +00001011 LoadSubCommand ("source", CommandObjectSP (new CommandObjectCommandsSource (interpreter)));
1012 LoadSubCommand ("alias", CommandObjectSP (new CommandObjectCommandsAlias (interpreter)));
1013 LoadSubCommand ("unalias", CommandObjectSP (new CommandObjectCommandsUnalias (interpreter)));
Greg Claytond12aeab2011-04-20 16:37:46 +00001014 LoadSubCommand ("regex", CommandObjectSP (new CommandObjectCommandsAddRegex (interpreter)));
Jim Ingham767af882010-07-07 03:36:20 +00001015}
1016
1017CommandObjectMultiwordCommands::~CommandObjectMultiwordCommands ()
1018{
1019}
1020