1 //===-- CommandCompletions.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 11 // C Includes 12 #include <sys/stat.h> 13 #include <dirent.h> 14 #if defined(__APPLE__) || defined(__linux__) 15 #include <pwd.h> 16 #endif 17 18 // C++ Includes 19 // Other libraries and framework includes 20 // Project includes 21 #include "lldb/Host/FileSpec.h" 22 #include "lldb/Core/FileSpecList.h" 23 #include "lldb/Core/PluginManager.h" 24 #include "lldb/Interpreter/Args.h" 25 #include "lldb/Interpreter/CommandCompletions.h" 26 #include "lldb/Interpreter/CommandInterpreter.h" 27 #include "lldb/Target/Target.h" 28 #include "lldb/Utility/CleanUp.h" 29 30 using namespace lldb_private; 31 32 CommandCompletions::CommonCompletionElement 33 CommandCompletions::g_common_completions[] = 34 { 35 {eCustomCompletion, NULL}, 36 {eSourceFileCompletion, CommandCompletions::SourceFiles}, 37 {eDiskFileCompletion, CommandCompletions::DiskFiles}, 38 {eDiskDirectoryCompletion, CommandCompletions::DiskDirectories}, 39 {eSymbolCompletion, CommandCompletions::Symbols}, 40 {eModuleCompletion, CommandCompletions::Modules}, 41 {eSettingsNameCompletion, CommandCompletions::SettingsNames}, 42 {ePlatformPluginCompletion, CommandCompletions::PlatformPluginNames}, 43 {eArchitectureCompletion, CommandCompletions::ArchitectureNames}, 44 {eNoCompletion, NULL} // This one has to be last in the list. 45 }; 46 47 bool 48 CommandCompletions::InvokeCommonCompletionCallbacks 49 ( 50 CommandInterpreter &interpreter, 51 uint32_t completion_mask, 52 const char *completion_str, 53 int match_start_point, 54 int max_return_elements, 55 SearchFilter *searcher, 56 bool &word_complete, 57 StringList &matches 58 ) 59 { 60 bool handled = false; 61 62 if (completion_mask & eCustomCompletion) 63 return false; 64 65 for (int i = 0; ; i++) 66 { 67 if (g_common_completions[i].type == eNoCompletion) 68 break; 69 else if ((g_common_completions[i].type & completion_mask) == g_common_completions[i].type 70 && g_common_completions[i].callback != NULL) 71 { 72 handled = true; 73 g_common_completions[i].callback (interpreter, 74 completion_str, 75 match_start_point, 76 max_return_elements, 77 searcher, 78 word_complete, 79 matches); 80 } 81 } 82 return handled; 83 } 84 85 int 86 CommandCompletions::SourceFiles 87 ( 88 CommandInterpreter &interpreter, 89 const char *partial_file_name, 90 int match_start_point, 91 int max_return_elements, 92 SearchFilter *searcher, 93 bool &word_complete, 94 StringList &matches 95 ) 96 { 97 word_complete = true; 98 // Find some way to switch "include support files..." 99 SourceFileCompleter completer (interpreter, 100 false, 101 partial_file_name, 102 match_start_point, 103 max_return_elements, 104 matches); 105 106 if (searcher == NULL) 107 { 108 lldb::TargetSP target_sp = interpreter.GetDebugger().GetSelectedTarget(); 109 SearchFilter null_searcher (target_sp); 110 completer.DoCompletion (&null_searcher); 111 } 112 else 113 { 114 completer.DoCompletion (searcher); 115 } 116 return matches.GetSize(); 117 } 118 119 static int 120 DiskFilesOrDirectories 121 ( 122 const char *partial_file_name, 123 bool only_directories, 124 bool &saw_directory, 125 StringList &matches 126 ) 127 { 128 // I'm going to use the "glob" function with GLOB_TILDE for user directory expansion. 129 // If it is not defined on your host system, you'll need to implement it yourself... 130 131 int partial_name_len = strlen(partial_file_name); 132 133 if (partial_name_len >= PATH_MAX) 134 return matches.GetSize(); 135 136 // This copy of the string will be cut up into the directory part, and the remainder. end_ptr 137 // below will point to the place of the remainder in this string. Then when we've resolved the 138 // containing directory, and opened it, we'll read the directory contents and overwrite the 139 // partial_name_copy starting from end_ptr with each of the matches. Thus we will preserve 140 // the form the user originally typed. 141 142 char partial_name_copy[PATH_MAX]; 143 memcpy(partial_name_copy, partial_file_name, partial_name_len); 144 partial_name_copy[partial_name_len] = '\0'; 145 146 // We'll need to save a copy of the remainder for comparison, which we do here. 147 char remainder[PATH_MAX]; 148 149 // end_ptr will point past the last / in partial_name_copy, or if there is no slash to the beginning of the string. 150 char *end_ptr; 151 152 end_ptr = strrchr(partial_name_copy, '/'); 153 154 // This will store the resolved form of the containing directory 155 char containing_part[PATH_MAX]; 156 157 if (end_ptr == NULL) 158 { 159 // There's no directory. If the thing begins with a "~" then this is a bare 160 // user name. 161 if (*partial_name_copy == '~') 162 { 163 // Nothing here but the user name. We could just put a slash on the end, 164 // but for completeness sake we'll resolve the user name and only put a slash 165 // on the end if it exists. 166 char resolved_username[PATH_MAX]; 167 size_t resolved_username_len = FileSpec::ResolveUsername (partial_name_copy, resolved_username, 168 sizeof (resolved_username)); 169 170 // Not sure how this would happen, a username longer than PATH_MAX? Still... 171 if (resolved_username_len >= sizeof (resolved_username)) 172 return matches.GetSize(); 173 else if (resolved_username_len == 0) 174 { 175 // The user name didn't resolve, let's look in the password database for matches. 176 // The user name database contains duplicates, and is not in alphabetical order, so 177 // we'll use a set to manage that for us. 178 FileSpec::ResolvePartialUsername (partial_name_copy, matches); 179 if (matches.GetSize() > 0) 180 saw_directory = true; 181 return matches.GetSize(); 182 } 183 else 184 { 185 //The thing exists, put a '/' on the end, and return it... 186 // FIXME: complete user names here: 187 partial_name_copy[partial_name_len] = '/'; 188 partial_name_copy[partial_name_len+1] = '\0'; 189 matches.AppendString(partial_name_copy); 190 saw_directory = true; 191 return matches.GetSize(); 192 } 193 } 194 else 195 { 196 // The containing part is the CWD, and the whole string is the remainder. 197 containing_part[0] = '.'; 198 containing_part[1] = '\0'; 199 strcpy(remainder, partial_name_copy); 200 end_ptr = partial_name_copy; 201 } 202 } 203 else 204 { 205 if (end_ptr == partial_name_copy) 206 { 207 // We're completing a file or directory in the root volume. 208 containing_part[0] = '/'; 209 containing_part[1] = '\0'; 210 } 211 else 212 { 213 size_t len = end_ptr - partial_name_copy; 214 memcpy(containing_part, partial_name_copy, len); 215 containing_part[len] = '\0'; 216 } 217 // Push end_ptr past the final "/" and set remainder. 218 end_ptr++; 219 strcpy(remainder, end_ptr); 220 } 221 222 // Look for a user name in the containing part, and if it's there, resolve it and stick the 223 // result back into the containing_part: 224 225 if (*partial_name_copy == '~') 226 { 227 size_t resolved_username_len = FileSpec::ResolveUsername(containing_part, 228 containing_part, 229 sizeof (containing_part)); 230 // User name doesn't exist, we're not getting any further... 231 if (resolved_username_len == 0 || resolved_username_len >= sizeof (containing_part)) 232 return matches.GetSize(); 233 } 234 235 // Okay, containing_part is now the directory we want to open and look for files: 236 237 lldb_utility::CleanUp <DIR *, int> dir_stream (opendir(containing_part), NULL, closedir); 238 if (!dir_stream.is_valid()) 239 return matches.GetSize(); 240 241 struct dirent *dirent_buf; 242 243 size_t baselen = end_ptr - partial_name_copy; 244 245 while ((dirent_buf = readdir(dir_stream.get())) != NULL) 246 { 247 char *name = dirent_buf->d_name; 248 249 // Omit ".", ".." and any . files if the match string doesn't start with . 250 if (name[0] == '.') 251 { 252 if (name[1] == '\0') 253 continue; 254 else if (name[1] == '.' && name[2] == '\0') 255 continue; 256 else if (remainder[0] != '.') 257 continue; 258 } 259 260 // If we found a directory, we put a "/" at the end of the name. 261 262 if (remainder[0] == '\0' || strstr(dirent_buf->d_name, remainder) == name) 263 { 264 if (strlen(name) + baselen >= PATH_MAX) 265 continue; 266 267 strcpy(end_ptr, name); 268 269 bool isa_directory = false; 270 if (dirent_buf->d_type & DT_DIR) 271 isa_directory = true; 272 else if (dirent_buf->d_type & DT_LNK) 273 { 274 struct stat stat_buf; 275 if ((stat(partial_name_copy, &stat_buf) == 0) && S_ISDIR(stat_buf.st_mode)) 276 isa_directory = true; 277 } 278 279 if (isa_directory) 280 { 281 saw_directory = true; 282 size_t len = strlen(partial_name_copy); 283 partial_name_copy[len] = '/'; 284 partial_name_copy[len + 1] = '\0'; 285 } 286 if (only_directories && !isa_directory) 287 continue; 288 matches.AppendString(partial_name_copy); 289 } 290 } 291 292 return matches.GetSize(); 293 } 294 295 int 296 CommandCompletions::DiskFiles 297 ( 298 CommandInterpreter &interpreter, 299 const char *partial_file_name, 300 int match_start_point, 301 int max_return_elements, 302 SearchFilter *searcher, 303 bool &word_complete, 304 StringList &matches 305 ) 306 { 307 308 int ret_val = DiskFilesOrDirectories (partial_file_name, 309 false, 310 word_complete, 311 matches); 312 word_complete = !word_complete; 313 return ret_val; 314 } 315 316 int 317 CommandCompletions::DiskDirectories 318 ( 319 CommandInterpreter &interpreter, 320 const char *partial_file_name, 321 int match_start_point, 322 int max_return_elements, 323 SearchFilter *searcher, 324 bool &word_complete, 325 StringList &matches 326 ) 327 { 328 int ret_val = DiskFilesOrDirectories (partial_file_name, 329 true, 330 word_complete, 331 matches); 332 word_complete = false; 333 return ret_val; 334 } 335 336 int 337 CommandCompletions::Modules 338 ( 339 CommandInterpreter &interpreter, 340 const char *partial_file_name, 341 int match_start_point, 342 int max_return_elements, 343 SearchFilter *searcher, 344 bool &word_complete, 345 StringList &matches 346 ) 347 { 348 word_complete = true; 349 ModuleCompleter completer (interpreter, 350 partial_file_name, 351 match_start_point, 352 max_return_elements, 353 matches); 354 355 if (searcher == NULL) 356 { 357 lldb::TargetSP target_sp = interpreter.GetDebugger().GetSelectedTarget(); 358 SearchFilter null_searcher (target_sp); 359 completer.DoCompletion (&null_searcher); 360 } 361 else 362 { 363 completer.DoCompletion (searcher); 364 } 365 return matches.GetSize(); 366 } 367 368 int 369 CommandCompletions::Symbols 370 ( 371 CommandInterpreter &interpreter, 372 const char *partial_file_name, 373 int match_start_point, 374 int max_return_elements, 375 SearchFilter *searcher, 376 bool &word_complete, 377 StringList &matches) 378 { 379 word_complete = true; 380 SymbolCompleter completer (interpreter, 381 partial_file_name, 382 match_start_point, 383 max_return_elements, 384 matches); 385 386 if (searcher == NULL) 387 { 388 lldb::TargetSP target_sp = interpreter.GetDebugger().GetSelectedTarget(); 389 SearchFilter null_searcher (target_sp); 390 completer.DoCompletion (&null_searcher); 391 } 392 else 393 { 394 completer.DoCompletion (searcher); 395 } 396 return matches.GetSize(); 397 } 398 399 int 400 CommandCompletions::SettingsNames (CommandInterpreter &interpreter, 401 const char *partial_setting_name, 402 int match_start_point, 403 int max_return_elements, 404 SearchFilter *searcher, 405 bool &word_complete, 406 StringList &matches) 407 { 408 lldb::UserSettingsControllerSP root_settings = Debugger::GetSettingsController(); 409 Args partial_setting_name_pieces = UserSettingsController::BreakNameIntoPieces (partial_setting_name); 410 411 return UserSettingsController::CompleteSettingsNames (root_settings, 412 partial_setting_name_pieces, 413 word_complete, 414 matches); 415 416 //return matches.GetSize(); 417 } 418 419 420 int 421 CommandCompletions::PlatformPluginNames (CommandInterpreter &interpreter, 422 const char *partial_name, 423 int match_start_point, 424 int max_return_elements, 425 SearchFilter *searcher, 426 bool &word_complete, 427 lldb_private::StringList &matches) 428 { 429 const uint32_t num_matches = PluginManager::AutoCompletePlatformName(partial_name, matches); 430 word_complete = num_matches == 1; 431 return num_matches; 432 } 433 434 int 435 CommandCompletions::ArchitectureNames (CommandInterpreter &interpreter, 436 const char *partial_name, 437 int match_start_point, 438 int max_return_elements, 439 SearchFilter *searcher, 440 bool &word_complete, 441 lldb_private::StringList &matches) 442 { 443 const uint32_t num_matches = ArchSpec::AutoComplete (partial_name, matches); 444 word_complete = num_matches == 1; 445 return num_matches; 446 } 447 448 449 CommandCompletions::Completer::Completer 450 ( 451 CommandInterpreter &interpreter, 452 const char *completion_str, 453 int match_start_point, 454 int max_return_elements, 455 StringList &matches 456 ) : 457 m_interpreter (interpreter), 458 m_completion_str (completion_str), 459 m_match_start_point (match_start_point), 460 m_max_return_elements (max_return_elements), 461 m_matches (matches) 462 { 463 } 464 465 CommandCompletions::Completer::~Completer () 466 { 467 468 } 469 470 //---------------------------------------------------------------------- 471 // SourceFileCompleter 472 //---------------------------------------------------------------------- 473 474 CommandCompletions::SourceFileCompleter::SourceFileCompleter 475 ( 476 CommandInterpreter &interpreter, 477 bool include_support_files, 478 const char *completion_str, 479 int match_start_point, 480 int max_return_elements, 481 StringList &matches 482 ) : 483 CommandCompletions::Completer (interpreter, completion_str, match_start_point, max_return_elements, matches), 484 m_include_support_files (include_support_files), 485 m_matching_files() 486 { 487 FileSpec partial_spec (m_completion_str.c_str(), false); 488 m_file_name = partial_spec.GetFilename().GetCString(); 489 m_dir_name = partial_spec.GetDirectory().GetCString(); 490 } 491 492 Searcher::Depth 493 CommandCompletions::SourceFileCompleter::GetDepth() 494 { 495 return eDepthCompUnit; 496 } 497 498 Searcher::CallbackReturn 499 CommandCompletions::SourceFileCompleter::SearchCallback ( 500 SearchFilter &filter, 501 SymbolContext &context, 502 Address *addr, 503 bool complete 504 ) 505 { 506 if (context.comp_unit != NULL) 507 { 508 if (m_include_support_files) 509 { 510 FileSpecList supporting_files = context.comp_unit->GetSupportFiles(); 511 for (size_t sfiles = 0; sfiles < supporting_files.GetSize(); sfiles++) 512 { 513 const FileSpec &sfile_spec = supporting_files.GetFileSpecAtIndex(sfiles); 514 const char *sfile_file_name = sfile_spec.GetFilename().GetCString(); 515 const char *sfile_dir_name = sfile_spec.GetFilename().GetCString(); 516 bool match = false; 517 if (m_file_name && sfile_file_name 518 && strstr (sfile_file_name, m_file_name) == sfile_file_name) 519 match = true; 520 if (match && m_dir_name && sfile_dir_name 521 && strstr (sfile_dir_name, m_dir_name) != sfile_dir_name) 522 match = false; 523 524 if (match) 525 { 526 m_matching_files.AppendIfUnique(sfile_spec); 527 } 528 } 529 530 } 531 else 532 { 533 const char *cur_file_name = context.comp_unit->GetFilename().GetCString(); 534 const char *cur_dir_name = context.comp_unit->GetDirectory().GetCString(); 535 536 bool match = false; 537 if (m_file_name && cur_file_name 538 && strstr (cur_file_name, m_file_name) == cur_file_name) 539 match = true; 540 541 if (match && m_dir_name && cur_dir_name 542 && strstr (cur_dir_name, m_dir_name) != cur_dir_name) 543 match = false; 544 545 if (match) 546 { 547 m_matching_files.AppendIfUnique(context.comp_unit); 548 } 549 } 550 } 551 return Searcher::eCallbackReturnContinue; 552 } 553 554 size_t 555 CommandCompletions::SourceFileCompleter::DoCompletion (SearchFilter *filter) 556 { 557 filter->Search (*this); 558 // Now convert the filelist to completions: 559 for (size_t i = 0; i < m_matching_files.GetSize(); i++) 560 { 561 m_matches.AppendString (m_matching_files.GetFileSpecAtIndex(i).GetFilename().GetCString()); 562 } 563 return m_matches.GetSize(); 564 565 } 566 567 //---------------------------------------------------------------------- 568 // SymbolCompleter 569 //---------------------------------------------------------------------- 570 571 static bool 572 regex_chars (const char comp) 573 { 574 if (comp == '[' || comp == ']' || comp == '(' || comp == ')') 575 return true; 576 else 577 return false; 578 } 579 CommandCompletions::SymbolCompleter::SymbolCompleter 580 ( 581 CommandInterpreter &interpreter, 582 const char *completion_str, 583 int match_start_point, 584 int max_return_elements, 585 StringList &matches 586 ) : 587 CommandCompletions::Completer (interpreter, completion_str, match_start_point, max_return_elements, matches) 588 { 589 std::string regex_str ("^"); 590 regex_str.append(completion_str); 591 regex_str.append(".*"); 592 std::string::iterator pos; 593 594 pos = find_if(regex_str.begin(), regex_str.end(), regex_chars); 595 while (pos < regex_str.end()) { 596 pos = regex_str.insert(pos, '\\'); 597 pos += 2; 598 pos = find_if(pos, regex_str.end(), regex_chars); 599 } 600 m_regex.Compile(regex_str.c_str()); 601 } 602 603 Searcher::Depth 604 CommandCompletions::SymbolCompleter::GetDepth() 605 { 606 return eDepthModule; 607 } 608 609 Searcher::CallbackReturn 610 CommandCompletions::SymbolCompleter::SearchCallback ( 611 SearchFilter &filter, 612 SymbolContext &context, 613 Address *addr, 614 bool complete 615 ) 616 { 617 if (context.module_sp) 618 { 619 SymbolContextList sc_list; 620 const bool include_symbols = true; 621 const bool append = true; 622 context.module_sp->FindFunctions (m_regex, include_symbols, append, sc_list); 623 624 SymbolContext sc; 625 // Now add the functions & symbols to the list - only add if unique: 626 for (uint32_t i = 0; i < sc_list.GetSize(); i++) 627 { 628 if (sc_list.GetContextAtIndex(i, sc)) 629 { 630 ConstString func_name = sc.GetFunctionName(Mangled::ePreferDemangled); 631 if (!func_name.IsEmpty()) 632 m_match_set.insert (func_name); 633 } 634 } 635 } 636 return Searcher::eCallbackReturnContinue; 637 } 638 639 size_t 640 CommandCompletions::SymbolCompleter::DoCompletion (SearchFilter *filter) 641 { 642 filter->Search (*this); 643 collection::iterator pos = m_match_set.begin(), end = m_match_set.end(); 644 for (pos = m_match_set.begin(); pos != end; pos++) 645 m_matches.AppendString((*pos).GetCString()); 646 647 return m_matches.GetSize(); 648 } 649 650 //---------------------------------------------------------------------- 651 // ModuleCompleter 652 //---------------------------------------------------------------------- 653 CommandCompletions::ModuleCompleter::ModuleCompleter 654 ( 655 CommandInterpreter &interpreter, 656 const char *completion_str, 657 int match_start_point, 658 int max_return_elements, 659 StringList &matches 660 ) : 661 CommandCompletions::Completer (interpreter, completion_str, match_start_point, max_return_elements, matches) 662 { 663 FileSpec partial_spec (m_completion_str.c_str(), false); 664 m_file_name = partial_spec.GetFilename().GetCString(); 665 m_dir_name = partial_spec.GetDirectory().GetCString(); 666 } 667 668 Searcher::Depth 669 CommandCompletions::ModuleCompleter::GetDepth() 670 { 671 return eDepthModule; 672 } 673 674 Searcher::CallbackReturn 675 CommandCompletions::ModuleCompleter::SearchCallback ( 676 SearchFilter &filter, 677 SymbolContext &context, 678 Address *addr, 679 bool complete 680 ) 681 { 682 if (context.module_sp) 683 { 684 const char *cur_file_name = context.module_sp->GetFileSpec().GetFilename().GetCString(); 685 const char *cur_dir_name = context.module_sp->GetFileSpec().GetDirectory().GetCString(); 686 687 bool match = false; 688 if (m_file_name && cur_file_name 689 && strstr (cur_file_name, m_file_name) == cur_file_name) 690 match = true; 691 692 if (match && m_dir_name && cur_dir_name 693 && strstr (cur_dir_name, m_dir_name) != cur_dir_name) 694 match = false; 695 696 if (match) 697 { 698 m_matches.AppendString (cur_file_name); 699 } 700 } 701 return Searcher::eCallbackReturnContinue; 702 } 703 704 size_t 705 CommandCompletions::ModuleCompleter::DoCompletion (SearchFilter *filter) 706 { 707 filter->Search (*this); 708 return m_matches.GetSize(); 709 } 710