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/Interpreter/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 CommandInterpreter &interpreter, 137 const char *command_line, 138 CommandReturnObject &result 139 ) 140 { 141 Args command_args(command_line); 142 return ExecuteWithOptions (interpreter, command_args, result); 143 } 144 145 bool 146 CommandObject::ParseOptions 147 ( 148 CommandInterpreter &interpreter, 149 Args& args, 150 CommandReturnObject &result 151 ) 152 { 153 // See if the subclass has options? 154 Options *options = GetOptions(); 155 if (options != NULL) 156 { 157 Error error; 158 options->ResetOptionValues(); 159 160 // ParseOptions calls getopt_long, which always skips the zero'th item in the array and starts at position 1, 161 // so we need to push a dummy value into position zero. 162 args.Unshift("dummy_string"); 163 error = args.ParseOptions (*options); 164 165 // The "dummy_string" will have already been removed by ParseOptions, 166 // so no need to remove it. 167 168 if (error.Fail() || !options->VerifyOptions (result)) 169 { 170 const char *error_cstr = error.AsCString(); 171 if (error_cstr) 172 { 173 // We got an error string, lets use that 174 result.GetErrorStream().PutCString(error_cstr); 175 } 176 else 177 { 178 // No error string, output the usage information into result 179 options->GenerateOptionUsage (result.GetErrorStream(), this); 180 } 181 // Set the return status to failed (this was an error). 182 result.SetStatus (eReturnStatusFailed); 183 return false; 184 } 185 } 186 return true; 187 } 188 bool 189 CommandObject::ExecuteWithOptions 190 ( 191 CommandInterpreter &interpreter, 192 Args& args, 193 CommandReturnObject &result 194 ) 195 { 196 for (size_t i = 0; i < args.GetArgumentCount(); ++i) 197 { 198 const char *tmp_str = args.GetArgumentAtIndex (i); 199 if (tmp_str[0] == '`') // back-quote 200 args.ReplaceArgumentAtIndex (i, interpreter.ProcessEmbeddedScriptCommands (tmp_str)); 201 } 202 203 Process *process = interpreter.GetDebugger().GetExecutionContext().process; 204 if (process == NULL) 205 { 206 if (GetFlags().IsSet(CommandObject::eFlagProcessMustBeLaunched | CommandObject::eFlagProcessMustBePaused)) 207 { 208 result.AppendError ("Process must exist."); 209 result.SetStatus (eReturnStatusFailed); 210 return false; 211 } 212 } 213 else 214 { 215 StateType state = process->GetState(); 216 217 switch (state) 218 { 219 220 case eStateAttaching: 221 case eStateLaunching: 222 case eStateSuspended: 223 case eStateCrashed: 224 case eStateStopped: 225 break; 226 227 case eStateDetached: 228 case eStateExited: 229 case eStateUnloaded: 230 if (GetFlags().IsSet(CommandObject::eFlagProcessMustBeLaunched)) 231 { 232 result.AppendError ("Process must be launched."); 233 result.SetStatus (eReturnStatusFailed); 234 return false; 235 } 236 break; 237 238 case eStateRunning: 239 case eStateStepping: 240 if (GetFlags().IsSet(CommandObject::eFlagProcessMustBePaused)) 241 { 242 result.AppendError ("Process is running. Use 'process interrupt' to pause execution."); 243 result.SetStatus (eReturnStatusFailed); 244 return false; 245 } 246 } 247 } 248 249 if (!ParseOptions (interpreter, args, result)) 250 return false; 251 252 // Call the command-specific version of 'Execute', passing it the already processed arguments. 253 return Execute (interpreter, args, result); 254 } 255 256 class CommandDictCommandPartialMatch 257 { 258 public: 259 CommandDictCommandPartialMatch (const char *match_str) 260 { 261 m_match_str = match_str; 262 } 263 bool operator() (const std::pair<std::string, lldb::CommandObjectSP> map_element) const 264 { 265 // A NULL or empty string matches everything. 266 if (m_match_str == NULL || *m_match_str == '\0') 267 return 1; 268 269 size_t found = map_element.first.find (m_match_str, 0); 270 if (found == std::string::npos) 271 return 0; 272 else 273 return found == 0; 274 } 275 276 private: 277 const char *m_match_str; 278 }; 279 280 int 281 CommandObject::AddNamesMatchingPartialString (CommandObject::CommandMap &in_map, const char *cmd_str, 282 StringList &matches) 283 { 284 int number_added = 0; 285 CommandDictCommandPartialMatch matcher(cmd_str); 286 287 CommandObject::CommandMap::iterator matching_cmds = std::find_if (in_map.begin(), in_map.end(), matcher); 288 289 while (matching_cmds != in_map.end()) 290 { 291 ++number_added; 292 matches.AppendString((*matching_cmds).first.c_str()); 293 matching_cmds = std::find_if (++matching_cmds, in_map.end(), matcher);; 294 } 295 return number_added; 296 } 297 298 int 299 CommandObject::HandleCompletion 300 ( 301 CommandInterpreter &interpreter, 302 Args &input, 303 int &cursor_index, 304 int &cursor_char_position, 305 int match_start_point, 306 int max_return_elements, 307 bool &word_complete, 308 StringList &matches 309 ) 310 { 311 if (WantsRawCommandString()) 312 { 313 // FIXME: Abstract telling the completion to insert the completion character. 314 matches.Clear(); 315 return -1; 316 } 317 else 318 { 319 // Can we do anything generic with the options? 320 Options *cur_options = GetOptions(); 321 CommandReturnObject result; 322 OptionElementVector opt_element_vector; 323 324 if (cur_options != NULL) 325 { 326 // Re-insert the dummy command name string which will have been 327 // stripped off: 328 input.Unshift ("dummy-string"); 329 cursor_index++; 330 331 332 // I stick an element on the end of the input, because if the last element is 333 // option that requires an argument, getopt_long will freak out. 334 335 input.AppendArgument ("<FAKE-VALUE>"); 336 337 input.ParseArgsForCompletion (*cur_options, opt_element_vector, cursor_index); 338 339 input.DeleteArgumentAtIndex(input.GetArgumentCount() - 1); 340 341 bool handled_by_options; 342 handled_by_options = cur_options->HandleOptionCompletion (interpreter, 343 input, 344 opt_element_vector, 345 cursor_index, 346 cursor_char_position, 347 match_start_point, 348 max_return_elements, 349 word_complete, 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 (interpreter, 357 input, 358 cursor_index, 359 cursor_char_position, 360 opt_element_vector, 361 match_start_point, 362 max_return_elements, 363 word_complete, 364 matches); 365 } 366 } 367 368 // Case insensitive version of ::strstr() 369 // Returns true if s2 is contained within s1. 370 371 static bool 372 contains_string (const char *s1, const char *s2) 373 { 374 char *locase_s1 = (char *) malloc (strlen (s1) + 1); 375 char *locase_s2 = (char *) malloc (strlen (s2) + 1); 376 int i; 377 for (i = 0; s1 && s1[i] != '\0'; i++) 378 locase_s1[i] = ::tolower (s1[i]); 379 locase_s1[i] = '\0'; 380 for (i = 0; s2 && s2[i] != '\0'; i++) 381 locase_s2[i] = ::tolower (s2[i]); 382 locase_s2[i] = '\0'; 383 384 const char *result = ::strstr (locase_s1, locase_s2); 385 free (locase_s1); 386 free (locase_s2); 387 // 'result' points into freed memory - but we're not 388 // deref'ing it so hopefully current/future compilers 389 // won't complain.. 390 391 if (result == NULL) 392 return false; 393 else 394 return true; 395 } 396 397 bool 398 CommandObject::HelpTextContainsWord (const char *search_word) 399 { 400 const char *short_help; 401 const char *long_help; 402 const char *syntax_help; 403 std::string options_usage_help; 404 405 406 bool found_word = false; 407 408 short_help = GetHelp(); 409 long_help = GetHelpLong(); 410 syntax_help = GetSyntax(); 411 412 if (contains_string (short_help, search_word)) 413 found_word = true; 414 else if (contains_string (long_help, search_word)) 415 found_word = true; 416 else if (contains_string (syntax_help, search_word)) 417 found_word = true; 418 419 if (!found_word 420 && GetOptions() != NULL) 421 { 422 StreamString usage_help; 423 GetOptions()->GenerateOptionUsage (usage_help, this); 424 if (usage_help.GetSize() > 0) 425 { 426 const char *usage_text = usage_help.GetData(); 427 if (contains_string (usage_text, search_word)) 428 found_word = true; 429 } 430 } 431 432 return found_word; 433 } 434