1 //===-- CommandObject.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 "lldb/Interpreter/CommandObject.h" 11 12 #include <string> 13 #include <map> 14 15 #include <getopt.h> 16 #include <stdlib.h> 17 #include <ctype.h> 18 19 #include "lldb/Core/Address.h" 20 #include "lldb/Core/Options.h" 21 22 // These are for the Sourcename completers. 23 // FIXME: Make a separate file for the completers. 24 #include "lldb/Core/FileSpec.h" 25 #include "lldb/Core/FileSpecList.h" 26 #include "lldb/Target/Process.h" 27 #include "lldb/Target/Target.h" 28 29 #include "lldb/Interpreter/CommandInterpreter.h" 30 #include "lldb/Interpreter/CommandReturnObject.h" 31 #include "lldb/Interpreter/ScriptInterpreter.h" 32 #include "lldb/Interpreter/ScriptInterpreterPython.h" 33 34 using namespace lldb; 35 using namespace lldb_private; 36 37 //------------------------------------------------------------------------- 38 // CommandObject 39 //------------------------------------------------------------------------- 40 41 CommandObject::CommandObject (const char *name, const char *help, const char *syntax, uint32_t flags) : 42 m_cmd_name (name), 43 m_cmd_help_short (), 44 m_cmd_help_long (), 45 m_cmd_syntax (), 46 m_flags (flags) 47 { 48 if (help && help[0]) 49 m_cmd_help_short = help; 50 if (syntax && syntax[0]) 51 m_cmd_syntax = syntax; 52 } 53 54 CommandObject::~CommandObject () 55 { 56 } 57 58 const char * 59 CommandObject::GetHelp () 60 { 61 return m_cmd_help_short.c_str(); 62 } 63 64 const char * 65 CommandObject::GetHelpLong () 66 { 67 return m_cmd_help_long.c_str(); 68 } 69 70 const char * 71 CommandObject::GetSyntax () 72 { 73 return m_cmd_syntax.c_str(); 74 } 75 76 const char * 77 CommandObject::Translate () 78 { 79 //return m_cmd_func_name.c_str(); 80 return "This function is currently not implemented."; 81 } 82 83 const char * 84 CommandObject::GetCommandName () 85 { 86 return m_cmd_name.c_str(); 87 } 88 89 void 90 CommandObject::SetCommandName (const char *name) 91 { 92 m_cmd_name = name; 93 } 94 95 void 96 CommandObject::SetHelp (const char *cstr) 97 { 98 m_cmd_help_short = cstr; 99 } 100 101 void 102 CommandObject::SetHelpLong (const char *cstr) 103 { 104 m_cmd_help_long = cstr; 105 } 106 107 void 108 CommandObject::SetSyntax (const char *cstr) 109 { 110 m_cmd_syntax = cstr; 111 } 112 113 Options * 114 CommandObject::GetOptions () 115 { 116 // By default commands don't have options unless this virtual function 117 // is overridden by base classes. 118 return NULL; 119 } 120 121 Flags& 122 CommandObject::GetFlags() 123 { 124 return m_flags; 125 } 126 127 const Flags& 128 CommandObject::GetFlags() const 129 { 130 return m_flags; 131 } 132 133 bool 134 CommandObject::ExecuteCommandString 135 ( 136 const char *command_line, 137 CommandContext *context, 138 CommandInterpreter *interpreter, 139 CommandReturnObject &result 140 ) 141 { 142 Args command_args(command_line); 143 return ExecuteWithOptions (command_args, context, interpreter, result); 144 } 145 146 bool 147 CommandObject::ParseOptions 148 ( 149 Args& args, 150 CommandInterpreter *interpreter, 151 CommandReturnObject &result 152 ) 153 { 154 // See if the subclass has options? 155 Options *options = GetOptions(); 156 if (options != NULL) 157 { 158 Error error; 159 options->ResetOptionValues(); 160 161 // ParseOptions calls getopt_long, which always skips the zero'th item in the array and starts at position 1, 162 // so we need to push a dummy value into position zero. 163 args.Unshift("dummy_string"); 164 error = args.ParseOptions (*options); 165 166 // The "dummy_string" will have already been removed by ParseOptions, 167 // so no need to remove it. 168 169 if (error.Fail() || !options->VerifyOptions (result)) 170 { 171 const char *error_cstr = error.AsCString(); 172 if (error_cstr) 173 { 174 // We got an error string, lets use that 175 result.GetErrorStream().PutCString(error_cstr); 176 } 177 else 178 { 179 // No error string, output the usage information into result 180 options->GenerateOptionUsage (result.GetErrorStream(), this); 181 } 182 // Set the return status to failed (this was an error). 183 result.SetStatus (eReturnStatusFailed); 184 return false; 185 } 186 } 187 return true; 188 } 189 bool 190 CommandObject::ExecuteWithOptions 191 ( 192 Args& args, 193 CommandContext *context, 194 CommandInterpreter *interpreter, 195 CommandReturnObject &result 196 ) 197 { 198 for (size_t i = 0; i < args.GetArgumentCount(); ++i) 199 { 200 const char *tmp_str = args.GetArgumentAtIndex (i); 201 if (tmp_str[0] == '`') // back-quote 202 args.ReplaceArgumentAtIndex (i, interpreter->ProcessEmbeddedScriptCommands (tmp_str)); 203 } 204 205 Process *process = context->GetExecutionContext().process; 206 if (process == NULL) 207 { 208 if (GetFlags().IsSet(CommandObject::eFlagProcessMustBeLaunched | CommandObject::eFlagProcessMustBePaused)) 209 { 210 result.AppendError ("Process must exist."); 211 result.SetStatus (eReturnStatusFailed); 212 return false; 213 } 214 } 215 else 216 { 217 StateType state = process->GetState(); 218 219 switch (state) 220 { 221 222 case eStateAttaching: 223 case eStateLaunching: 224 case eStateSuspended: 225 case eStateCrashed: 226 case eStateStopped: 227 break; 228 229 case eStateDetached: 230 case eStateExited: 231 case eStateUnloaded: 232 if (GetFlags().IsSet(CommandObject::eFlagProcessMustBeLaunched)) 233 { 234 result.AppendError ("Process must be launched."); 235 result.SetStatus (eReturnStatusFailed); 236 return false; 237 } 238 break; 239 240 case eStateRunning: 241 case eStateStepping: 242 if (GetFlags().IsSet(CommandObject::eFlagProcessMustBePaused)) 243 { 244 result.AppendError ("Process is running. Use 'process interrupt' to pause execution."); 245 result.SetStatus (eReturnStatusFailed); 246 return false; 247 } 248 } 249 } 250 251 if (!ParseOptions (args, interpreter, result)) 252 return false; 253 254 // Call the command-specific version of 'Execute', passing it the already processed arguments. 255 return Execute (args, context, interpreter, result); 256 } 257 258 class CommandDictCommandPartialMatch 259 { 260 public: 261 CommandDictCommandPartialMatch (const char *match_str) 262 { 263 m_match_str = match_str; 264 } 265 bool operator() (const std::pair<std::string, lldb::CommandObjectSP> map_element) const 266 { 267 // A NULL or empty string matches everything. 268 if (m_match_str == NULL || *m_match_str == '\0') 269 return 1; 270 271 size_t found = map_element.first.find (m_match_str, 0); 272 if (found == std::string::npos) 273 return 0; 274 else 275 return found == 0; 276 } 277 278 private: 279 const char *m_match_str; 280 }; 281 282 int 283 CommandObject::AddNamesMatchingPartialString (CommandObject::CommandMap &in_map, const char *cmd_str, 284 StringList &matches) 285 { 286 int number_added = 0; 287 CommandDictCommandPartialMatch matcher(cmd_str); 288 289 CommandObject::CommandMap::iterator matching_cmds = std::find_if (in_map.begin(), in_map.end(), matcher); 290 291 while (matching_cmds != in_map.end()) 292 { 293 ++number_added; 294 matches.AppendString((*matching_cmds).first.c_str()); 295 matching_cmds = std::find_if (++matching_cmds, in_map.end(), matcher);; 296 } 297 return number_added; 298 } 299 300 int 301 CommandObject::HandleCompletion 302 ( 303 Args &input, 304 int &cursor_index, 305 int &cursor_char_position, 306 int match_start_point, 307 int max_return_elements, 308 CommandInterpreter *interpreter, 309 StringList &matches 310 ) 311 { 312 if (WantsRawCommandString()) 313 { 314 // FIXME: Abstract telling the completion to insert the completion character. 315 matches.Clear(); 316 return -1; 317 } 318 else 319 { 320 // Can we do anything generic with the options? 321 Options *cur_options = GetOptions(); 322 CommandReturnObject result; 323 OptionElementVector opt_element_vector; 324 325 if (cur_options != NULL) 326 { 327 // Re-insert the dummy command name string which will have been 328 // stripped off: 329 input.Unshift ("dummy-string"); 330 cursor_index++; 331 332 333 // I stick an element on the end of the input, because if the last element is 334 // option that requires an argument, getopt_long will freak out. 335 336 input.AppendArgument ("<FAKE-VALUE>"); 337 338 input.ParseArgsForCompletion (*cur_options, opt_element_vector); 339 340 input.DeleteArgumentAtIndex(input.GetArgumentCount() - 1); 341 342 bool handled_by_options; 343 handled_by_options = cur_options->HandleOptionCompletion(input, 344 opt_element_vector, 345 cursor_index, 346 cursor_char_position, 347 match_start_point, 348 max_return_elements, 349 interpreter, 350 matches); 351 if (handled_by_options) 352 return matches.GetSize(); 353 } 354 355 // If we got here, the last word is not an option or an option argument. 356 return HandleArgumentCompletion(input, 357 cursor_index, 358 cursor_char_position, 359 opt_element_vector, 360 match_start_point, 361 max_return_elements, 362 interpreter, 363 matches); 364 } 365 } 366 367 int 368 CommandObject::HandleArgumentCompletion 369 ( 370 Args &input, 371 int &cursor_index, 372 int &cursor_char_position, 373 OptionElementVector &opt_element_vector, 374 int match_start_point, 375 int max_return_elements, 376 CommandInterpreter *interpreter, 377 StringList &matches 378 ) 379 { 380 return 0; 381 } 382 383 // Case insensitive version of ::strstr() 384 // Returns true if s2 is contained within s1. 385 386 static bool 387 contains_string (const char *s1, const char *s2) 388 { 389 char *locase_s1 = (char *) malloc (strlen (s1) + 1); 390 char *locase_s2 = (char *) malloc (strlen (s2) + 1); 391 int i; 392 for (i = 0; s1 && s1[i] != '\0'; i++) 393 locase_s1[i] = ::tolower (s1[i]); 394 locase_s1[i] = '\0'; 395 for (i = 0; s2 && s2[i] != '\0'; i++) 396 locase_s2[i] = ::tolower (s2[i]); 397 locase_s2[i] = '\0'; 398 399 const char *result = ::strstr (locase_s1, locase_s2); 400 free (locase_s1); 401 free (locase_s2); 402 // 'result' points into freed memory - but we're not 403 // deref'ing it so hopefully current/future compilers 404 // won't complain.. 405 406 if (result == NULL) 407 return false; 408 else 409 return true; 410 } 411 412 bool 413 CommandObject::HelpTextContainsWord (const char *search_word) 414 { 415 const char *short_help; 416 const char *long_help; 417 const char *syntax_help; 418 std::string options_usage_help; 419 420 421 bool found_word = false; 422 423 short_help = GetHelp(); 424 long_help = GetHelpLong(); 425 syntax_help = GetSyntax(); 426 427 if (contains_string (short_help, search_word)) 428 found_word = true; 429 else if (contains_string (long_help, search_word)) 430 found_word = true; 431 else if (contains_string (syntax_help, search_word)) 432 found_word = true; 433 434 if (!found_word 435 && GetOptions() != NULL) 436 { 437 StreamString usage_help; 438 GetOptions()->GenerateOptionUsage (usage_help, this); 439 if (usage_help.GetSize() > 0) 440 { 441 const char *usage_text = usage_help.GetData(); 442 if (contains_string (usage_text, search_word)) 443 found_word = true; 444 } 445 } 446 447 return found_word; 448 } 449