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             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))
357             {
358                 result.AppendError ("Unable to create requested alias.\n");
359                 result.SetStatus (eReturnStatusFailed);
360                 return false;
361             }
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 
377             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             }
389         }
390         return result.Succeeded();
391     }
392 
393     bool
394     Execute
395     (
396         Args& args,
397         CommandReturnObject &result
398     )
399     {
400         size_t argc = args.GetArgumentCount();
401 
402         if (argc < 2)
403         {
404             result.AppendError ("'alias' requires at least two arguments");
405             result.SetStatus (eReturnStatusFailed);
406             return false;
407         }
408 
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 
417         if (m_interpreter.CommandExists (alias_command.c_str()))
418         {
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         {
425              CommandObjectSP command_obj_sp(m_interpreter.GetCommandSPExact (actual_command.c_str(), true));
426              CommandObjectSP subcommand_obj_sp;
427              bool use_subcommand = false;
428              if (command_obj_sp.get())
429              {
430                  CommandObject *cmd_obj = command_obj_sp.get();
431                  CommandObject *sub_cmd_obj = NULL;
432                  OptionArgVectorSP option_arg_vector_sp = OptionArgVectorSP (new OptionArgVector);
433                  OptionArgVector *option_arg_vector = option_arg_vector_sp.get();
434 
435                  while (cmd_obj->IsMultiwordObject() && args.GetArgumentCount() > 0)
436                  {
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.
448                              cmd_obj = sub_cmd_obj;
449                          }
450                          else
451                          {
452                              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());
455                              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                  {
465                     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                     }
478                  }
479 
480                  // Create the alias.
481 
482                  if (m_interpreter.AliasExists (alias_command.c_str())
483                      || m_interpreter.UserCommandExists (alias_command.c_str()))
484                  {
485                      OptionArgVectorSP tmp_option_arg_sp (m_interpreter.GetAliasOptions (alias_command.c_str()));
486                      if (tmp_option_arg_sp.get())
487                      {
488                          if (option_arg_vector->size() == 0)
489                              m_interpreter.RemoveAliasOptions (alias_command.c_str());
490                      }
491                      result.AppendWarningWithFormat ("Overwriting existing definition for '%s'.\n",
492                                                      alias_command.c_str());
493                  }
494 
495                  if (use_subcommand)
496                      m_interpreter.AddAlias (alias_command.c_str(), subcommand_obj_sp);
497                  else
498                      m_interpreter.AddAlias (alias_command.c_str(), command_obj_sp);
499                  if (option_arg_vector->size() > 0)
500                      m_interpreter.AddOrReplaceAliasOptions (alias_command.c_str(), option_arg_vector_sp);
501                  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);
507                  return false;
508              }
509         }
510 
511         return result.Succeeded();
512     }
513 };
514 
515 #pragma mark CommandObjectCommandsUnalias
516 //-------------------------------------------------------------------------
517 // CommandObjectCommandsUnalias
518 //-------------------------------------------------------------------------
519 
520 class CommandObjectCommandsUnalias : public CommandObject
521 {
522 public:
523     CommandObjectCommandsUnalias (CommandInterpreter &interpreter) :
524         CommandObject (interpreter,
525                        "command unalias",
526                        "Allow the user to remove/delete a user-defined command abbreviation.",
527                        NULL)
528     {
529         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);
541     }
542 
543     ~CommandObjectCommandsUnalias()
544     {
545     }
546 
547 
548     bool
549     Execute
550     (
551         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);
561             cmd_obj = m_interpreter.GetCommandObject(command_name);
562             if (cmd_obj)
563             {
564                 if (m_interpreter.CommandExists (command_name))
565                 {
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 
573                     if (m_interpreter.RemoveAlias (command_name) == false)
574                     {
575                         if (m_interpreter.AliasExists (command_name))
576                             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 
604 #pragma mark CommandObjectCommandsAddRegex
605 //-------------------------------------------------------------------------
606 // CommandObjectCommandsAddRegex
607 //-------------------------------------------------------------------------
608 
609 class CommandObjectCommandsAddRegex : public CommandObject
610 {
611 public:
612     CommandObjectCommandsAddRegex (CommandInterpreter &interpreter) :
613         CommandObject (interpreter,
614                        "command regex",
615                        "Allow the user to create a regular expression command.",
616                        "command regex <cmd-name> [s/<regex>/<subst>/ ...]"),
617         m_options (interpreter)
618     {
619         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                     );
642     }
643 
644     ~CommandObjectCommandsAddRegex()
645     {
646     }
647 
648 
649     bool
650     Execute (Args& args, CommandReturnObject &result)
651     {
652         const size_t argc = args.GetArgumentCount();
653         if (argc == 0)
654         {
655             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;
661             const char *name = args.GetArgumentAtIndex(0);
662             m_regex_cmd_ap.reset (new CommandObjectRegexCommand (m_interpreter,
663                                                                  name,
664                                                                  m_options.GetHelp (),
665                                                                  m_options.GetSyntax (),
666                                                                  10));
667 
668             if (argc == 1)
669             {
670                 InputReaderSP reader_sp (new InputReader(m_interpreter.GetDebugger()));
671                 if (reader_sp)
672                 {
673                     error =reader_sp->Initialize (CommandObjectCommandsAddRegex::InputReaderCallback,
674                                                   this,                         // baton
675                                                   eInputReaderGranularityLine,  // token size, to pass to callback function
676                                                   NULL,                         // end token
677                                                   "> ",                         // prompt
678                                                   true);                        // echo input
679                     if (error.Success())
680                     {
681                         m_interpreter.GetDebugger().PushInputReader (reader_sp);
682                         result.SetStatus (eReturnStatusSuccessFinishNoResult);
683                         return true;
684                     }
685                 }
686             }
687             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             }
707         }
708 
709         return result.Succeeded();
710     }
711 
712     Error
713     AppendRegexSubstitution (const llvm::StringRef &regex_sed)
714     {
715         Error error;
716 
717         if (m_regex_cmd_ap.get() == NULL)
718         {
719             error.SetErrorStringWithFormat("invalid regular expression command object for: '%.*s'",
720                                            (int)regex_sed.size(),
721                                            regex_sed.data());
722             return error;
723         }
724 
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;
808     }
809 
810     void
811     AddRegexCommandToInterpreter()
812     {
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 
823     void
824     InputReaderDidCancel()
825     {
826         m_regex_cmd_ap.reset();
827     }
828 
829     static size_t
830     InputReaderCallback (void *baton,
831                          InputReader &reader,
832                          lldb::InputReaderAction notification,
833                          const char *bytes,
834                          size_t bytes_len);
835 private:
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 
920 size_t
921 CommandObjectCommandsAddRegex::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:
932             reader.GetDebugger().GetOutputStream().Printf("%s\n", "Enter regular expressions in the form 's/<regex>/<subst>/' and terminate with an empty line:");
933             break;
934         case eInputReaderReactivate:
935             break;
936 
937         case eInputReaderDeactivate:
938             break;
939 
940         case eInputReaderAsynchronousOutputWritten:
941             break;
942 
943         case eInputReaderGotToken:
944             while (bytes_len > 0 && (bytes[bytes_len-1] == '\r' || bytes[bytes_len-1] == '\n'))
945                 --bytes_len;
946             if (bytes_len == 0)
947                 reader.SetIsDone(true);
948             else if (bytes)
949             {
950                 llvm::StringRef bytes_strref (bytes, bytes_len);
951                 Error error (add_regex_cmd->AppendRegexSubstitution (bytes_strref));
952                 if (error.Fail())
953                 {
954                     reader.GetDebugger().GetOutputStream().Printf("error: %s\n", error.AsCString());
955                     add_regex_cmd->InputReaderDidCancel ();
956                     reader.SetIsDone (true);
957                 }
958             }
959             break;
960 
961         case eInputReaderInterrupt:
962             reader.SetIsDone (true);
963             reader.GetDebugger().GetOutputStream().PutCString("Regular expression command creations was cancelled.\n");
964             add_regex_cmd->InputReaderDidCancel ();
965             break;
966 
967         case eInputReaderEndOfFile:
968             reader.SetIsDone (true);
969             break;
970 
971         case eInputReaderDone:
972             add_regex_cmd->AddRegexCommandToInterpreter();
973             break;
974     }
975 
976     return bytes_len;
977 }
978 
979 
980 OptionDefinition
981 CommandObjectCommandsAddRegex::CommandOptions::g_option_table[] =
982 {
983 { LLDB_OPT_SET_1, false, "help"  , 'h', required_argument, NULL, 0, eArgTypeNone, "The help text to display for this command."},
984 { LLDB_OPT_SET_1, false, "syntax", 's', required_argument, NULL, 0, eArgTypeNone, "A syntax string showing the typical usage syntax."},
985 { 0             , false,  NULL   , 0  , 0                , NULL, 0, eArgTypeNone, NULL }
986 };
987 
988 
989 #pragma mark CommandObjectMultiwordCommands
990 
991 //-------------------------------------------------------------------------
992 // CommandObjectMultiwordCommands
993 //-------------------------------------------------------------------------
994 
995 CommandObjectMultiwordCommands::CommandObjectMultiwordCommands (CommandInterpreter &interpreter) :
996     CommandObjectMultiword (interpreter,
997                             "command",
998                             "A set of commands for managing or customizing the debugger commands.",
999                             "command <subcommand> [<subcommand-options>]")
1000 {
1001     LoadSubCommand ("source",  CommandObjectSP (new CommandObjectCommandsSource (interpreter)));
1002     LoadSubCommand ("alias",   CommandObjectSP (new CommandObjectCommandsAlias (interpreter)));
1003     LoadSubCommand ("unalias", CommandObjectSP (new CommandObjectCommandsUnalias (interpreter)));
1004     LoadSubCommand ("regex",   CommandObjectSP (new CommandObjectCommandsAddRegex (interpreter)));
1005 }
1006 
1007 CommandObjectMultiwordCommands::~CommandObjectMultiwordCommands ()
1008 {
1009 }
1010 
1011