1 //===-- 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 #include "llvm/ADT/StringRef.h"
16 
17 // Project includes
18 #include "lldb/Core/Debugger.h"
19 #include "lldb/Core/InputReader.h"
20 #include "lldb/Interpreter/Args.h"
21 #include "lldb/Interpreter/CommandInterpreter.h"
22 #include "lldb/Interpreter/CommandObjectRegexCommand.h"
23 #include "lldb/Interpreter/CommandReturnObject.h"
24 #include "lldb/Interpreter/Options.h"
25 
26 using namespace lldb;
27 using namespace lldb_private;
28 
29 //-------------------------------------------------------------------------
30 // CommandObjectCommandsSource
31 //-------------------------------------------------------------------------
32 
33 class CommandObjectCommandsSource : public CommandObject
34 {
35 private:
36 
37     class CommandOptions : public Options
38     {
39     public:
40 
41         CommandOptions (CommandInterpreter &interpreter) :
42             Options (interpreter)
43         {
44         }
45 
46         virtual
47         ~CommandOptions (){}
48 
49         virtual Error
50         SetOptionValue (uint32_t option_idx, const char *option_arg)
51         {
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
77         OptionParsingStarting ()
78         {
79             m_stop_on_error = true;
80             m_stop_on_continue = true;
81         }
82 
83         const OptionDefinition*
84         GetDefinitions ()
85         {
86             return g_option_table;
87         }
88 
89         // Options table: Required for subclasses of Options.
90 
91         static OptionDefinition g_option_table[];
92 
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 
99     CommandOptions m_options;
100 
101     virtual Options *
102     GetOptions ()
103     {
104         return &m_options;
105     }
106 
107 public:
108     CommandObjectCommandsSource(CommandInterpreter &interpreter) :
109         CommandObject (interpreter,
110                        "command source",
111                        "Read in debugger commands from the file <filename> and execute them.",
112                        NULL),
113         m_options (interpreter)
114     {
115         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);
127     }
128 
129     ~CommandObjectCommandsSource ()
130     {
131     }
132 
133     bool
134     Execute
135     (
136         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);
144 
145             result.AppendMessageWithFormat ("Executing commands in '%s'.\n", filename);
146 
147             FileSpec cmd_file (filename, true);
148             ExecutionContext *exe_ctx = NULL;  // Just use the default context.
149             bool echo_commands    = true;
150             bool print_results    = true;
151 
152             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);
159         }
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 
170 OptionDefinition
171 CommandObjectCommandsSource::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 
178 #pragma mark CommandObjectCommandsAlias
179 //-------------------------------------------------------------------------
180 // CommandObjectCommandsAlias
181 //-------------------------------------------------------------------------
182 
183 class CommandObjectCommandsAlias : public CommandObject
184 {
185 public:
186     CommandObjectCommandsAlias (CommandInterpreter &interpreter) :
187         CommandObject (interpreter,
188                        "command alias",
189                        "Allow users to define their own debugger command abbreviations.",
190                        NULL)
191     {
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\
196     \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\
205     \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\
210     'commands alias bfl breakpoint set -f %1 -l %2' \n\
211     \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\
225     \n    (lldb)  commands alias bfl breakpoint set -f %1 -l %2 \n\
226     <... some time later ...> \n\
227     (lldb)  bfl my-file.c 137 \n\
228     \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\
231     \n    (lldb)  commands alias pltty  process launch -s -o %1 -e %1 \n\
232     (lldb)  pltty /dev/tty0 \n\
233            // becomes 'process launch -s -o /dev/tty0 -e /dev/tty0' \n\
234     \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\
237     \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");
239 
240         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);
272     }
273 
274     ~CommandObjectCommandsAlias ()
275     {
276     }
277 
278     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 
354             // Check to see if there's anything left in the input command string.
355             if (raw_command_string.size() > 0)
356             {
357 
358                 // Check to see if the command being aliased can take any command options.
359                 Options *options = cmd_obj->GetOptions();
360                 if (options)
361                 {
362                     // See if any options were specified as part of the alias; if so, handle them appropriately
363                     options->NotifyOptionParsingStarting ();
364                     Args tmp_args (raw_command_string.c_str());
365                     args.Unshift ("dummy_arg");
366                     args.ParseAliasOptions (*options, result, option_arg_vector, raw_command_string);
367                     args.Shift ();
368                     if (result.Succeeded())
369                         options->VerifyPartialOptions (result);
370                     if (!result.Succeeded() && result.GetStatus() != lldb::eReturnStatusStarted)
371                     {
372                         result.AppendError ("Unable to create requested alias.\n");
373                         return false;
374                     }
375                 }
376                 // Anything remaining must be plain raw input.  Push it in as a single raw input argument.
377                 if (raw_command_string.size() > 0)
378                     option_arg_vector->push_back (OptionArgPair ("<argument>",
379                                                                  OptionArgValue (-1,
380                                                                                   raw_command_string)));
381             }
382 
383             // Create the alias
384             if (m_interpreter.AliasExists (alias_command.c_str())
385                 || m_interpreter.UserCommandExists (alias_command.c_str()))
386             {
387                 OptionArgVectorSP temp_option_arg_sp (m_interpreter.GetAliasOptions (alias_command.c_str()));
388                 if (temp_option_arg_sp.get())
389                 {
390                     if (option_arg_vector->size() == 0)
391                         m_interpreter.RemoveAliasOptions (alias_command.c_str());
392                 }
393                 result.AppendWarningWithFormat ("Overwriting existing definition for '%s'.\n",
394                                                 alias_command.c_str());
395             }
396 
397             CommandObjectSP cmd_obj_sp = m_interpreter.GetCommandSPExact (cmd_obj->GetCommandName(), false);
398             if (cmd_obj_sp)
399             {
400                 m_interpreter.AddAlias (alias_command.c_str(), cmd_obj_sp);
401                 if (option_arg_vector->size() > 0)
402                     m_interpreter.AddOrReplaceAliasOptions (alias_command.c_str(), option_arg_vector_sp);
403                 result.SetStatus (eReturnStatusSuccessFinishNoResult);
404             }
405             else
406             {
407                 result.AppendError ("Unable to create requested alias.\n");
408                 result.SetStatus (eReturnStatusFailed);
409             }
410         }
411         return result.Succeeded();
412     }
413 
414     bool
415     Execute
416     (
417         Args& args,
418         CommandReturnObject &result
419     )
420     {
421         size_t argc = args.GetArgumentCount();
422 
423         if (argc < 2)
424         {
425             result.AppendError ("'alias' requires at least two arguments");
426             result.SetStatus (eReturnStatusFailed);
427             return false;
428         }
429 
430         const std::string alias_command = args.GetArgumentAtIndex(0);
431         const std::string actual_command = args.GetArgumentAtIndex(1);
432 
433         args.Shift();  // Shift the alias command word off the argument vector.
434         args.Shift();  // Shift the old command word off the argument vector.
435 
436         // Verify that the command is alias'able, and get the appropriate command object.
437 
438         if (m_interpreter.CommandExists (alias_command.c_str()))
439         {
440             result.AppendErrorWithFormat ("'%s' is a permanent debugger command and cannot be redefined.\n",
441                                          alias_command.c_str());
442             result.SetStatus (eReturnStatusFailed);
443         }
444         else
445         {
446              CommandObjectSP command_obj_sp(m_interpreter.GetCommandSPExact (actual_command.c_str(), true));
447              CommandObjectSP subcommand_obj_sp;
448              bool use_subcommand = false;
449              if (command_obj_sp.get())
450              {
451                  CommandObject *cmd_obj = command_obj_sp.get();
452                  CommandObject *sub_cmd_obj = NULL;
453                  OptionArgVectorSP option_arg_vector_sp = OptionArgVectorSP (new OptionArgVector);
454                  OptionArgVector *option_arg_vector = option_arg_vector_sp.get();
455 
456                  while (cmd_obj->IsMultiwordObject() && args.GetArgumentCount() > 0)
457                  {
458                      if (argc >= 3)
459                      {
460                          const std::string sub_command = args.GetArgumentAtIndex(0);
461                          assert (sub_command.length() != 0);
462                          subcommand_obj_sp =
463                                            (((CommandObjectMultiword *) cmd_obj)->GetSubcommandSP (sub_command.c_str()));
464                          if (subcommand_obj_sp.get())
465                          {
466                              sub_cmd_obj = subcommand_obj_sp.get();
467                              use_subcommand = true;
468                              args.Shift();  // Shift the sub_command word off the argument vector.
469                              cmd_obj = sub_cmd_obj;
470                          }
471                          else
472                          {
473                              result.AppendErrorWithFormat("'%s' is not a valid sub-command of '%s'.  "
474                                                           "Unable to create alias.\n",
475                                                           sub_command.c_str(), actual_command.c_str());
476                              result.SetStatus (eReturnStatusFailed);
477                              return false;
478                          }
479                      }
480                  }
481 
482                  // Verify & handle any options/arguments passed to the alias command
483 
484                  if (args.GetArgumentCount () > 0)
485                  {
486                      if ((!use_subcommand && (cmd_obj->GetOptions() != NULL))
487                          || (use_subcommand && (sub_cmd_obj->GetOptions() != NULL)))
488                      {
489                          Options *options;
490                          if (use_subcommand)
491                              options = sub_cmd_obj->GetOptions();
492                          else
493                              options = cmd_obj->GetOptions();
494                          options->NotifyOptionParsingStarting ();
495                          std::string empty_string;
496                          args.Unshift ("dummy_arg");
497                          args.ParseAliasOptions (*options, result, option_arg_vector, empty_string);
498                          args.Shift ();
499                          if (result.Succeeded())
500                              options->VerifyPartialOptions (result);
501                          if (!result.Succeeded() && result.GetStatus() != lldb::eReturnStatusStarted)
502                         {
503                             result.AppendError ("Unable to create requested command alias.\n");
504                             return false;
505                         }
506                      }
507 
508                      // Anything remaining in args must be a plain argument.
509 
510                      argc = args.GetArgumentCount();
511                      for (size_t i = 0; i < argc; ++i)
512                          if (strcmp (args.GetArgumentAtIndex (i), "") != 0)
513                              option_arg_vector->push_back
514                                            (OptionArgPair ("<argument>",
515                                                            OptionArgValue (-1,
516                                                                            std::string (args.GetArgumentAtIndex (i)))));
517                  }
518 
519                  // Create the alias.
520 
521                  if (m_interpreter.AliasExists (alias_command.c_str())
522                      || m_interpreter.UserCommandExists (alias_command.c_str()))
523                  {
524                      OptionArgVectorSP tmp_option_arg_sp (m_interpreter.GetAliasOptions (alias_command.c_str()));
525                      if (tmp_option_arg_sp.get())
526                      {
527                          if (option_arg_vector->size() == 0)
528                              m_interpreter.RemoveAliasOptions (alias_command.c_str());
529                      }
530                      result.AppendWarningWithFormat ("Overwriting existing definition for '%s'.\n",
531                                                      alias_command.c_str());
532                  }
533 
534                  if (use_subcommand)
535                      m_interpreter.AddAlias (alias_command.c_str(), subcommand_obj_sp);
536                  else
537                      m_interpreter.AddAlias (alias_command.c_str(), command_obj_sp);
538                  if (option_arg_vector->size() > 0)
539                      m_interpreter.AddOrReplaceAliasOptions (alias_command.c_str(), option_arg_vector_sp);
540                  result.SetStatus (eReturnStatusSuccessFinishNoResult);
541              }
542              else
543              {
544                  result.AppendErrorWithFormat ("'%s' is not an existing command.\n", actual_command.c_str());
545                  result.SetStatus (eReturnStatusFailed);
546                  return false;
547              }
548         }
549 
550         return result.Succeeded();
551     }
552 };
553 
554 #pragma mark CommandObjectCommandsUnalias
555 //-------------------------------------------------------------------------
556 // CommandObjectCommandsUnalias
557 //-------------------------------------------------------------------------
558 
559 class CommandObjectCommandsUnalias : public CommandObject
560 {
561 public:
562     CommandObjectCommandsUnalias (CommandInterpreter &interpreter) :
563         CommandObject (interpreter,
564                        "command unalias",
565                        "Allow the user to remove/delete a user-defined command abbreviation.",
566                        NULL)
567     {
568         CommandArgumentEntry arg;
569         CommandArgumentData alias_arg;
570 
571         // Define the first (and only) variant of this arg.
572         alias_arg.arg_type = eArgTypeAliasName;
573         alias_arg.arg_repetition = eArgRepeatPlain;
574 
575         // There is only one variant this argument could be; put it into the argument entry.
576         arg.push_back (alias_arg);
577 
578         // Push the data for the first argument into the m_arguments vector.
579         m_arguments.push_back (arg);
580     }
581 
582     ~CommandObjectCommandsUnalias()
583     {
584     }
585 
586 
587     bool
588     Execute
589     (
590         Args& args,
591         CommandReturnObject &result
592     )
593     {
594         CommandObject::CommandMap::iterator pos;
595         CommandObject *cmd_obj;
596 
597         if (args.GetArgumentCount() != 0)
598         {
599             const char *command_name = args.GetArgumentAtIndex(0);
600             cmd_obj = m_interpreter.GetCommandObject(command_name);
601             if (cmd_obj)
602             {
603                 if (m_interpreter.CommandExists (command_name))
604                 {
605                     result.AppendErrorWithFormat ("'%s' is a permanent debugger command and cannot be removed.\n",
606                                                   command_name);
607                     result.SetStatus (eReturnStatusFailed);
608                 }
609                 else
610                 {
611 
612                     if (m_interpreter.RemoveAlias (command_name) == false)
613                     {
614                         if (m_interpreter.AliasExists (command_name))
615                             result.AppendErrorWithFormat ("Error occurred while attempting to unalias '%s'.\n",
616                                                           command_name);
617                         else
618                             result.AppendErrorWithFormat ("'%s' is not an existing alias.\n", command_name);
619                         result.SetStatus (eReturnStatusFailed);
620                     }
621                     else
622                         result.SetStatus (eReturnStatusSuccessFinishNoResult);
623                 }
624             }
625             else
626             {
627                 result.AppendErrorWithFormat ("'%s' is not a known command.\nTry 'help' to see a "
628                                               "current list of commands.\n",
629                                              command_name);
630                 result.SetStatus (eReturnStatusFailed);
631             }
632         }
633         else
634         {
635             result.AppendError ("must call 'unalias' with a valid alias");
636             result.SetStatus (eReturnStatusFailed);
637         }
638 
639         return result.Succeeded();
640     }
641 };
642 
643 #pragma mark CommandObjectCommandsAddRegex
644 //-------------------------------------------------------------------------
645 // CommandObjectCommandsAddRegex
646 //-------------------------------------------------------------------------
647 
648 class CommandObjectCommandsAddRegex : public CommandObject
649 {
650 public:
651     CommandObjectCommandsAddRegex (CommandInterpreter &interpreter) :
652         CommandObject (interpreter,
653                        "command regex",
654                        "Allow the user to create a regular expression command.",
655                        "command regex <cmd-name> [s/<regex>/<subst>/ ...]"),
656         m_options (interpreter)
657     {
658         SetHelpLong(
659 "This command allows the user to create powerful regular expression commands\n"
660 "with substitutions. The regular expressions and substitutions are specified\n"
661 "using the regular exression substitution format of:\n"
662 "\n"
663 "    s/<regex>/<subst>/\n"
664 "\n"
665 "<regex> is a regular expression that can use parenthesis to capture regular\n"
666 "expression input and substitute the captured matches in the output using %1\n"
667 "for the first match, %2 for the second, and so on.\n"
668 "\n"
669 "The regular expressions can all be specified on the command line if more than\n"
670 "one argument is provided. If just the command name is provided on the command\n"
671 "line, then the regular expressions and substitutions can be entered on separate\n"
672 " lines, followed by an empty line to terminate the command definition.\n"
673 "\n"
674 "EXAMPLES\n"
675 "\n"
676 "The following example with define a regular expression command named 'f' that\n"
677 "will call 'finish' if there are no arguments, or 'frame select <frame-idx>' if\n"
678 "a number follows 'f':\n"
679 "(lldb) command regex f s/^$/finish/ 's/([0-9]+)/frame select %1/'\n"
680                     );
681     }
682 
683     ~CommandObjectCommandsAddRegex()
684     {
685     }
686 
687 
688     bool
689     Execute (Args& args, CommandReturnObject &result)
690     {
691         const size_t argc = args.GetArgumentCount();
692         if (argc == 0)
693         {
694             result.AppendError ("usage: 'commands regex <command-name> [s/<regex1>/<subst1>/ s/<regex2>/<subst2>/ ...]'\n");
695             result.SetStatus (eReturnStatusFailed);
696         }
697         else
698         {
699             Error error;
700             const char *name = args.GetArgumentAtIndex(0);
701             m_regex_cmd_ap.reset (new CommandObjectRegexCommand (m_interpreter,
702                                                                  name,
703                                                                  m_options.GetHelp (),
704                                                                  m_options.GetSyntax (),
705                                                                  10));
706 
707             if (argc == 1)
708             {
709                 InputReaderSP reader_sp (new InputReader(m_interpreter.GetDebugger()));
710                 if (reader_sp)
711                 {
712                     error =reader_sp->Initialize (CommandObjectCommandsAddRegex::InputReaderCallback,
713                                                   this,                         // baton
714                                                   eInputReaderGranularityLine,  // token size, to pass to callback function
715                                                   NULL,                         // end token
716                                                   "> ",                         // prompt
717                                                   true);                        // echo input
718                     if (error.Success())
719                     {
720                         m_interpreter.GetDebugger().PushInputReader (reader_sp);
721                         result.SetStatus (eReturnStatusSuccessFinishNoResult);
722                         return true;
723                     }
724                 }
725             }
726             else
727             {
728                 for (size_t arg_idx = 1; arg_idx < argc; ++arg_idx)
729                 {
730                     llvm::StringRef arg_strref (args.GetArgumentAtIndex(arg_idx));
731                     error = AppendRegexSubstitution (arg_strref);
732                     if (error.Fail())
733                         break;
734                 }
735 
736                 if (error.Success())
737                 {
738                     AddRegexCommandToInterpreter();
739                 }
740             }
741             if (error.Fail())
742             {
743                 result.AppendError (error.AsCString());
744                 result.SetStatus (eReturnStatusFailed);
745             }
746         }
747 
748         return result.Succeeded();
749     }
750 
751     Error
752     AppendRegexSubstitution (const llvm::StringRef &regex_sed)
753     {
754         Error error;
755 
756         if (m_regex_cmd_ap.get() == NULL)
757         {
758             error.SetErrorStringWithFormat("invalid regular expression command object for: '%.*s'",
759                                            (int)regex_sed.size(),
760                                            regex_sed.data());
761             return error;
762         }
763 
764         size_t regex_sed_size = regex_sed.size();
765 
766         if (regex_sed_size <= 1)
767         {
768             error.SetErrorStringWithFormat("regular expression substitution string is too short: '%.*s'",
769                                            (int)regex_sed.size(),
770                                            regex_sed.data());
771             return error;
772         }
773 
774         if (regex_sed[0] != 's')
775         {
776             error.SetErrorStringWithFormat("regular expression substitution string doesn't start with 's': '%.*s'",
777                                            (int)regex_sed.size(),
778                                            regex_sed.data());
779             return error;
780         }
781         const size_t first_separator_char_pos = 1;
782         // use the char that follows 's' as the regex separator character
783         // so we can have "s/<regex>/<subst>/" or "s|<regex>|<subst>|"
784         const char separator_char = regex_sed[first_separator_char_pos];
785         const size_t second_separator_char_pos = regex_sed.find (separator_char, first_separator_char_pos + 1);
786 
787         if (second_separator_char_pos == std::string::npos)
788         {
789             error.SetErrorStringWithFormat("missing second '%c' separator char after '%.*s'",
790                                            separator_char,
791                                            (int)(regex_sed.size() - first_separator_char_pos - 1),
792                                            regex_sed.data() + (first_separator_char_pos + 1));
793             return error;
794         }
795 
796         const size_t third_separator_char_pos = regex_sed.find (separator_char, second_separator_char_pos + 1);
797 
798         if (third_separator_char_pos == std::string::npos)
799         {
800             error.SetErrorStringWithFormat("missing third '%c' separator char after '%.*s'",
801                                            separator_char,
802                                            (int)(regex_sed.size() - second_separator_char_pos - 1),
803                                            regex_sed.data() + (second_separator_char_pos + 1));
804             return error;
805         }
806 
807         if (third_separator_char_pos != regex_sed_size - 1)
808         {
809             // Make sure that everything that follows the last regex
810             // separator char
811             if (regex_sed.find_first_not_of("\t\n\v\f\r ", third_separator_char_pos + 1) != std::string::npos)
812             {
813                 error.SetErrorStringWithFormat("extra data found after the '%.*s' regular expression substitution string: '%.*s'",
814                                                (int)third_separator_char_pos + 1,
815                                                regex_sed.data(),
816                                                (int)(regex_sed.size() - third_separator_char_pos - 1),
817                                                regex_sed.data() + (third_separator_char_pos + 1));
818                 return error;
819             }
820 
821         }
822         else if (first_separator_char_pos + 1 == second_separator_char_pos)
823         {
824             error.SetErrorStringWithFormat("<regex> can't be empty in 's%c<regex>%c<subst>%c' string: '%.*s'",
825                                            separator_char,
826                                            separator_char,
827                                            separator_char,
828                                            (int)regex_sed.size(),
829                                            regex_sed.data());
830             return error;
831         }
832         else if (second_separator_char_pos + 1 == third_separator_char_pos)
833         {
834             error.SetErrorStringWithFormat("<subst> can't be empty in 's%c<regex>%c<subst>%c' string: '%.*s'",
835                                            separator_char,
836                                            separator_char,
837                                            separator_char,
838                                            (int)regex_sed.size(),
839                                            regex_sed.data());
840             return error;
841         }
842         std::string regex(regex_sed.substr(first_separator_char_pos + 1, second_separator_char_pos - first_separator_char_pos - 1));
843         std::string subst(regex_sed.substr(second_separator_char_pos + 1, third_separator_char_pos - second_separator_char_pos - 1));
844         m_regex_cmd_ap->AddRegexCommand (regex.c_str(),
845                                          subst.c_str());
846         return error;
847     }
848 
849     void
850     AddRegexCommandToInterpreter()
851     {
852         if (m_regex_cmd_ap.get())
853         {
854             if (m_regex_cmd_ap->HasRegexEntries())
855             {
856                 CommandObjectSP cmd_sp (m_regex_cmd_ap.release());
857                 m_interpreter.AddCommand(cmd_sp->GetCommandName(), cmd_sp, true);
858             }
859         }
860     }
861 
862     void
863     InputReaderDidCancel()
864     {
865         m_regex_cmd_ap.reset();
866     }
867 
868     static size_t
869     InputReaderCallback (void *baton,
870                          InputReader &reader,
871                          lldb::InputReaderAction notification,
872                          const char *bytes,
873                          size_t bytes_len);
874 private:
875     std::auto_ptr<CommandObjectRegexCommand> m_regex_cmd_ap;
876 
877      class CommandOptions : public Options
878      {
879      public:
880 
881          CommandOptions (CommandInterpreter &interpreter) :
882             Options (interpreter)
883          {
884          }
885 
886          virtual
887          ~CommandOptions (){}
888 
889          virtual Error
890          SetOptionValue (uint32_t option_idx, const char *option_arg)
891          {
892              Error error;
893              char short_option = (char) m_getopt_table[option_idx].val;
894 
895              switch (short_option)
896              {
897                  case 'h':
898                      m_help.assign (option_arg);
899                      break;
900                  case 's':
901                      m_syntax.assign (option_arg);
902                      break;
903 
904                  default:
905                      error.SetErrorStringWithFormat ("Unrecognized option '%c'.\n", short_option);
906                      break;
907              }
908 
909              return error;
910          }
911 
912          void
913          OptionParsingStarting ()
914          {
915              m_help.clear();
916              m_syntax.clear();
917          }
918 
919          const OptionDefinition*
920          GetDefinitions ()
921          {
922              return g_option_table;
923          }
924 
925          // Options table: Required for subclasses of Options.
926 
927          static OptionDefinition g_option_table[];
928 
929          const char *
930          GetHelp ()
931          {
932              if (m_help.empty())
933                  return NULL;
934              return m_help.c_str();
935          }
936          const char *
937          GetSyntax ()
938          {
939              if (m_syntax.empty())
940                  return NULL;
941              return m_syntax.c_str();
942          }
943          // Instance variables to hold the values for command options.
944      protected:
945          std::string m_help;
946          std::string m_syntax;
947      };
948 
949      CommandOptions m_options;
950 
951      virtual Options *
952      GetOptions ()
953      {
954          return &m_options;
955      }
956 
957 };
958 
959 size_t
960 CommandObjectCommandsAddRegex::InputReaderCallback (void *baton,
961                                                     InputReader &reader,
962                                                     lldb::InputReaderAction notification,
963                                                     const char *bytes,
964                                                     size_t bytes_len)
965 {
966     CommandObjectCommandsAddRegex *add_regex_cmd = (CommandObjectCommandsAddRegex *) baton;
967 
968     switch (notification)
969     {
970         case eInputReaderActivate:
971             reader.GetDebugger().GetOutputStream().Printf("%s\n", "Enter regular expressions in the form 's/<regex>/<subst>/' and terminate with an empty line:");
972             break;
973         case eInputReaderReactivate:
974             break;
975 
976         case eInputReaderDeactivate:
977             break;
978 
979         case eInputReaderAsynchronousOutputWritten:
980             break;
981 
982         case eInputReaderGotToken:
983             while (bytes_len > 0 && (bytes[bytes_len-1] == '\r' || bytes[bytes_len-1] == '\n'))
984                 --bytes_len;
985             if (bytes_len == 0)
986                 reader.SetIsDone(true);
987             else if (bytes)
988             {
989                 llvm::StringRef bytes_strref (bytes, bytes_len);
990                 Error error (add_regex_cmd->AppendRegexSubstitution (bytes_strref));
991                 if (error.Fail())
992                 {
993                     reader.GetDebugger().GetOutputStream().Printf("error: %s\n", error.AsCString());
994                     add_regex_cmd->InputReaderDidCancel ();
995                     reader.SetIsDone (true);
996                 }
997             }
998             break;
999 
1000         case eInputReaderInterrupt:
1001             reader.SetIsDone (true);
1002             reader.GetDebugger().GetOutputStream().PutCString("Regular expression command creations was cancelled.\n");
1003             add_regex_cmd->InputReaderDidCancel ();
1004             break;
1005 
1006         case eInputReaderEndOfFile:
1007             reader.SetIsDone (true);
1008             break;
1009 
1010         case eInputReaderDone:
1011             add_regex_cmd->AddRegexCommandToInterpreter();
1012             break;
1013     }
1014 
1015     return bytes_len;
1016 }
1017 
1018 
1019 OptionDefinition
1020 CommandObjectCommandsAddRegex::CommandOptions::g_option_table[] =
1021 {
1022 { LLDB_OPT_SET_1, false, "help"  , 'h', required_argument, NULL, 0, eArgTypeNone, "The help text to display for this command."},
1023 { LLDB_OPT_SET_1, false, "syntax", 's', required_argument, NULL, 0, eArgTypeNone, "A syntax string showing the typical usage syntax."},
1024 { 0             , false,  NULL   , 0  , 0                , NULL, 0, eArgTypeNone, NULL }
1025 };
1026 
1027 
1028 #pragma mark CommandObjectMultiwordCommands
1029 
1030 //-------------------------------------------------------------------------
1031 // CommandObjectMultiwordCommands
1032 //-------------------------------------------------------------------------
1033 
1034 CommandObjectMultiwordCommands::CommandObjectMultiwordCommands (CommandInterpreter &interpreter) :
1035     CommandObjectMultiword (interpreter,
1036                             "command",
1037                             "A set of commands for managing or customizing the debugger commands.",
1038                             "command <subcommand> [<subcommand-options>]")
1039 {
1040     LoadSubCommand ("source",  CommandObjectSP (new CommandObjectCommandsSource (interpreter)));
1041     LoadSubCommand ("alias",   CommandObjectSP (new CommandObjectCommandsAlias (interpreter)));
1042     LoadSubCommand ("unalias", CommandObjectSP (new CommandObjectCommandsUnalias (interpreter)));
1043     LoadSubCommand ("regex",   CommandObjectSP (new CommandObjectCommandsAddRegex (interpreter)));
1044 }
1045 
1046 CommandObjectMultiwordCommands::~CommandObjectMultiwordCommands ()
1047 {
1048 }
1049 
1050