bool TargetInstanceSettings::GetInstanceSettingsValue (const SettingEntry &entry, const ConstString &var_name, StringList &value, Error *err) { if (var_name == GetSettingNameForExpressionPrefix ()) { value.AppendString (m_expr_prefix_path.c_str(), m_expr_prefix_path.size()); } else if (var_name == GetSettingNameForExecutionLevel ()) { value.AppendString (UserSettingsController::EnumToString (entry.enum_values, m_execution_level)); } else if (var_name == GetSettingNameForExecutionMode ()) { value.AppendString (UserSettingsController::EnumToString (entry.enum_values, m_execution_mode)); } else if (var_name == GetSettingNameForExecutionOSType ()) { value.AppendString (UserSettingsController::EnumToString (entry.enum_values, m_execution_os_type)); } else { if (err) err->SetErrorStringWithFormat ("unrecognized variable name '%s'", var_name.AsCString()); return false; } return true; }
size_t OptionValueEnumeration::AutoComplete (CommandInterpreter &interpreter, const char *s, int match_start_point, int max_return_elements, bool &word_complete, StringList &matches) { word_complete = false; matches.Clear(); const uint32_t num_enumerators = m_enumerations.GetSize(); if (s && s[0]) { const size_t s_len = strlen(s); for (size_t i=0; i<num_enumerators; ++i) { const char *name = m_enumerations.GetCStringAtIndex(i); if (::strncmp(s, name, s_len) == 0) matches.AppendString(name); } } else { // only suggest "true" or "false" by default for (size_t i=0; i<num_enumerators; ++i) matches.AppendString(m_enumerations.GetCStringAtIndex(i)); } return matches.GetSize(); }
void CommandInterpreter::AproposAllSubCommands (CommandObject *cmd_obj, const char *prefix, const char *search_word, StringList &commands_found, StringList &commands_help) { CommandObject::CommandMap::const_iterator pos; CommandObject::CommandMap sub_cmd_dict = ((CommandObjectMultiword *) cmd_obj)->m_subcommand_dict; CommandObject *sub_cmd_obj; for (pos = sub_cmd_dict.begin(); pos != sub_cmd_dict.end(); ++pos) { const char * command_name = pos->first.c_str(); sub_cmd_obj = pos->second.get(); StreamString complete_command_name; complete_command_name.Printf ("%s %s", prefix, command_name); if (sub_cmd_obj->HelpTextContainsWord (search_word)) { commands_found.AppendString (complete_command_name.GetData()); commands_help.AppendString (sub_cmd_obj->GetHelp()); } if (sub_cmd_obj->IsMultiwordObject()) AproposAllSubCommands (sub_cmd_obj, complete_command_name.GetData(), search_word, commands_found, commands_help); } }
bool DoExecute(Args &command, CommandReturnObject &result) override { StringList commands; commands.AppendString("thread backtrace"); Thread *thread = m_exe_ctx.GetThreadPtr(); if (thread) { char command_buffer[256]; uint32_t frame_count = thread->GetStackFrameCount(); for (uint32_t i = 0; i < frame_count; ++i) { StackFrameSP frame = thread->GetStackFrameAtIndex(i); lldb::addr_t pc = frame->GetStackID().GetPC(); snprintf(command_buffer, sizeof(command_buffer), "disassemble --bytes --address 0x%" PRIx64, pc); commands.AppendString(command_buffer); snprintf(command_buffer, sizeof(command_buffer), "image show-unwind --address 0x%" PRIx64, pc); commands.AppendString(command_buffer); } } const FileSpec &outfile_spec = m_outfile_options.GetFile().GetCurrentValue(); if (outfile_spec) { char path[PATH_MAX]; outfile_spec.GetPath(path, sizeof(path)); uint32_t open_options = File::eOpenOptionWrite | File::eOpenOptionCanCreate | File::eOpenOptionAppend | File::eOpenOptionCloseOnExec; const bool append = m_outfile_options.GetAppend().GetCurrentValue(); if (!append) open_options |= File::eOpenOptionTruncate; StreamFileSP outfile_stream = std::make_shared<StreamFile>(); Status error = outfile_stream->GetFile().Open(path, open_options); if (error.Fail()) { result.AppendErrorWithFormat("Failed to open file '%s' for %s: %s\n", path, append ? "append" : "write", error.AsCString()); result.SetStatus(eReturnStatusFailed); return false; } result.SetImmediateOutputStream(outfile_stream); } CommandInterpreterRunOptions options; options.SetStopOnError(false); options.SetEchoCommands(true); options.SetPrintResults(true); options.SetAddToHistory(false); m_interpreter.HandleCommands(commands, &m_exe_ctx, options, result); return result.Succeeded(); }
void Log::AutoCompleteChannelName(const char *channel_name, StringList &matches) { LogChannelMap &map = GetChannelMap(); LogChannelMapIter pos, end = map.end(); for (pos = map.begin(); pos != end; ++pos) { const char *pos_channel_name = pos->first.GetCString(); if (channel_name && channel_name[0]) { if (NameMatches(channel_name, eNameMatchStartsWith, pos_channel_name)) { matches.AppendString(pos_channel_name); } } else matches.AppendString(pos_channel_name); } }
size_t FileSpec::ResolvePartialUsername (const char *partial_name, StringList &matches) { #ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER size_t extant_entries = matches.GetSize(); setpwent(); struct passwd *user_entry; const char *name_start = partial_name + 1; std::set<std::string> name_list; while ((user_entry = getpwent()) != NULL) { if (strstr(user_entry->pw_name, name_start) == user_entry->pw_name) { std::string tmp_buf("~"); tmp_buf.append(user_entry->pw_name); tmp_buf.push_back('/'); name_list.insert(tmp_buf); } } std::set<std::string>::iterator pos, end = name_list.end(); for (pos = name_list.begin(); pos != end; pos++) { matches.AppendString((*pos).c_str()); } return matches.GetSize() - extant_entries; #else // Resolving home directories is not supported, just copy the path... return 0; #endif // #ifdef LLDB_CONFIG_TILDE_RESOLVES_TO_USER }
size_t StringList::AutoComplete (const char *s, StringList &matches, size_t &exact_idx) const { matches.Clear(); exact_idx = SIZE_MAX; if (s && s[0]) { const size_t s_len = strlen (s); const size_t num_strings = m_strings.size(); for (size_t i=0; i<num_strings; ++i) { if (m_strings[i].find(s) == 0) { if (exact_idx == SIZE_MAX && m_strings[i].size() == s_len) exact_idx = matches.GetSize(); matches.AppendString (m_strings[i]); } } } else { // No string, so it matches everything matches = *this; } return matches.GetSize(); }
size_t Host::GetEnvironment(StringList &env) { char **host_env = environ; char *env_entry; size_t i; for (i = 0; (env_entry = host_env[i]) != NULL; ++i) env.AppendString(env_entry); return i; }
size_t OptionValueBoolean::AutoComplete (CommandInterpreter &interpreter, const char *s, int match_start_point, int max_return_elements, bool &word_complete, StringList &matches) { word_complete = false; matches.Clear(); struct StringEntry { const char *string; const size_t length; }; static const StringEntry g_autocomplete_entries[] = { { "true" , 4 }, { "false", 5 }, { "on" , 2 }, { "off" , 3 }, { "yes" , 3 }, { "no" , 2 }, { "1" , 1 }, { "0" , 1 }, }; const size_t k_num_autocomplete_entries = llvm::array_lengthof(g_autocomplete_entries); if (s && s[0]) { const size_t s_len = strlen(s); for (size_t i=0; i<k_num_autocomplete_entries; ++i) { if (s_len <= g_autocomplete_entries[i].length) if (::strncasecmp(s, g_autocomplete_entries[i].string, s_len) == 0) matches.AppendString(g_autocomplete_entries[i].string); } } else { // only suggest "true" or "false" by default for (size_t i=0; i<2; ++i) matches.AppendString(g_autocomplete_entries[i].string); } return matches.GetSize(); }
uint32_t ArchSpec::AutoComplete (const char *name, StringList &matches) { uint32_t i; if (name && name[0]) { for (i = 0; i < ArchSpec::kNumCores; ++i) { if (NameMatches(g_core_definitions[i].name, eNameMatchStartsWith, name)) matches.AppendString (g_core_definitions[i].name); } } else { for (i = 0; i < ArchSpec::kNumCores; ++i) matches.AppendString (g_core_definitions[i].name); } return matches.GetSize(); }
uint32_t Host::ListProcessesMatchingName (const char *name, StringList &matches, std::vector<lldb::pid_t> &pids) { uint32_t num_matches = 0; #if defined (__APPLE__) int num_pids; int size_of_pids; std::vector<int> pid_list; size_of_pids = proc_listpids(PROC_ALL_PIDS, 0, NULL, 0); if (size_of_pids == -1) return 0; num_pids = size_of_pids/sizeof(int); pid_list.resize (size_of_pids); size_of_pids = proc_listpids(PROC_ALL_PIDS, 0, &pid_list[0], size_of_pids); if (size_of_pids == -1) return 0; lldb::pid_t our_pid = getpid(); for (int i = 0; i < num_pids; i++) { struct proc_bsdinfo bsd_info; int error = proc_pidinfo (pid_list[i], PROC_PIDTBSDINFO, (uint64_t) 0, &bsd_info, PROC_PIDTBSDINFO_SIZE); if (error == 0) continue; // Don't offer to attach to zombie processes, already traced or exiting // processes, and of course, ourselves... It looks like passing the second arg of // 0 to proc_listpids will exclude zombies anyway, but that's not documented so... if (((bsd_info.pbi_flags & (PROC_FLAG_TRACED | PROC_FLAG_INEXIT)) != 0) || (bsd_info.pbi_status == SZOMB) || (bsd_info.pbi_pid == our_pid)) continue; char pid_name[MAXCOMLEN * 2 + 1]; int name_len; name_len = proc_name(bsd_info.pbi_pid, pid_name, MAXCOMLEN * 2); if (name_len == 0) continue; if (strstr(pid_name, name) != pid_name) continue; matches.AppendString (pid_name); pids.push_back (bsd_info.pbi_pid); num_matches++; } #endif return num_matches; }
int REPL::IOHandlerComplete(IOHandler &io_handler, const char *current_line, const char *cursor, const char *last_char, int skip_first_n_matches, int max_matches, StringList &matches) { matches.Clear(); llvm::StringRef line(current_line, cursor - current_line); // Complete an LLDB command if the first character is a colon... if (!line.empty() && line[0] == ':') { Debugger &debugger = m_target.GetDebugger(); // auto complete LLDB commands const char *lldb_current_line = line.substr(1).data(); return debugger.GetCommandInterpreter().HandleCompletion( lldb_current_line, cursor, last_char, skip_first_n_matches, max_matches, matches); } // Strip spaces from the line and see if we had only spaces line = line.ltrim(); if (line.empty()) { // Only spaces on this line, so just indent matches.AppendString(m_indent_str); return 1; } std::string current_code; current_code.append(m_code.CopyList()); IOHandlerEditline &editline = static_cast<IOHandlerEditline &>(io_handler); const StringList *current_lines = editline.GetCurrentLines(); if (current_lines) { const uint32_t current_line_idx = editline.GetCurrentLineIndex(); if (current_line_idx < current_lines->GetSize()) { for (uint32_t i = 0; i < current_line_idx; ++i) { const char *line_cstr = current_lines->GetStringAtIndex(i); if (line_cstr) { current_code.append("\n"); current_code.append(line_cstr); } } } } if (cursor > current_line) { current_code.append("\n"); current_code.append(current_line, cursor - current_line); } return CompleteCode(current_code, matches); }
void CommandInterpreter::FindCommandsForApropos (const char *search_word, StringList &commands_found, StringList &commands_help) { CommandObject::CommandMap::const_iterator pos; for (pos = m_command_dict.begin(); pos != m_command_dict.end(); ++pos) { const char *command_name = pos->first.c_str(); CommandObject *cmd_obj = pos->second.get(); if (cmd_obj->HelpTextContainsWord (search_word)) { commands_found.AppendString (command_name); commands_help.AppendString (cmd_obj->GetHelp()); } if (cmd_obj->IsMultiwordObject()) AproposAllSubCommands (cmd_obj, command_name, search_word, commands_found, commands_help); } }
size_t Host::GetEnvironment (StringList &env) { char *v; char **var = environ; for (; var != NULL && *var != NULL; ++var) { v = strchr(*var, (int)'-'); if (v == NULL) continue; env.AppendString(v); } return env.GetSize(); }
size_t Host::GetEnvironment(StringList &env) { // The environment block on Windows is a contiguous buffer of NULL terminated strings, // where the end of the environment block is indicated by two consecutive NULLs. LPCH environment_block = ::GetEnvironmentStrings(); env.Clear(); while (*environment_block != '\0') { llvm::StringRef current_var(environment_block); if (current_var[0] != '=') env.AppendString(current_var); environment_block += current_var.size()+1; } return env.GetSize(); }
size_t OptionValueUUID::AutoComplete (CommandInterpreter &interpreter, const char *s, int match_start_point, int max_return_elements, bool &word_complete, StringList &matches) { word_complete = false; matches.Clear(); ExecutionContext exe_ctx(interpreter.GetExecutionContext()); Target *target = exe_ctx.GetTargetPtr(); if (target) { const size_t num_modules = target->GetImages().GetSize(); if (num_modules > 0) { UUID::ValueType uuid_bytes; const size_t num_bytes_decoded = UUID::DecodeUUIDBytesFromCString(s, uuid_bytes, NULL); for (size_t i=0; i<num_modules; ++i) { ModuleSP module_sp (target->GetImages().GetModuleAtIndex(i)); if (module_sp) { const UUID &module_uuid = module_sp->GetUUID(); if (module_uuid.IsValid()) { bool add_uuid = false; if (num_bytes_decoded == 0) add_uuid = true; else add_uuid = ::memcmp(module_uuid.GetBytes(), uuid_bytes, num_bytes_decoded) == 0; if (add_uuid) { std::string uuid_str; uuid_str = module_uuid.GetAsString(); if (!uuid_str.empty()) matches.AppendString(uuid_str.c_str()); } } } } } } return matches.GetSize(); }
bool Target::SettingsController::GetGlobalVariable (const ConstString &var_name, StringList &value, Error &err) { if (var_name == GetSettingNameForDefaultArch()) { // If the arch is invalid (the default), don't show a string for it if (m_default_architecture.IsValid()) value.AppendString (m_default_architecture.GetArchitectureName()); return true; } else err.SetErrorStringWithFormat ("unrecognized variable name '%s'", var_name.AsCString()); return false; }
int CommandObject::AddNamesMatchingPartialString (CommandObject::CommandMap &in_map, const char *cmd_str, StringList &matches) { int number_added = 0; CommandDictCommandPartialMatch matcher(cmd_str); CommandObject::CommandMap::iterator matching_cmds = std::find_if (in_map.begin(), in_map.end(), matcher); while (matching_cmds != in_map.end()) { ++number_added; matches.AppendString((*matching_cmds).first.c_str()); matching_cmds = std::find_if (++matching_cmds, in_map.end(), matcher);; } return number_added; }
uint32_t PluginManager::AutoCompletePlatformName (const char *name, StringList &matches) { if (name && name[0]) { Mutex::Locker locker (GetPlatformInstancesMutex ()); PlatformInstances &instances = GetPlatformInstances (); llvm::StringRef name_sref(name); PlatformInstances::iterator pos, end = instances.end(); for (pos = instances.begin(); pos != end; ++ pos) { llvm::StringRef plugin_name (pos->name); if (plugin_name.startswith(name_sref)) matches.AppendString (plugin_name.data()); } } return matches.GetSize(); }
size_t StringList::AutoComplete(llvm::StringRef s, StringList &matches, size_t &exact_idx) const { matches.Clear(); exact_idx = SIZE_MAX; if (s.empty()) { // No string, so it matches everything matches = *this; return matches.GetSize(); } const size_t s_len = s.size(); const size_t num_strings = m_strings.size(); for (size_t i = 0; i < num_strings; ++i) { if (m_strings[i].find(s) == 0) { if (exact_idx == SIZE_MAX && m_strings[i].size() == s_len) exact_idx = matches.GetSize(); matches.AppendString(m_strings[i]); } } return matches.GetSize(); }
static int DiskFilesOrDirectories(const char *partial_file_name, bool only_directories, bool &saw_directory, StringList &matches) { // I'm going to use the "glob" function with GLOB_TILDE for user directory expansion. // If it is not defined on your host system, you'll need to implement it yourself... size_t partial_name_len = strlen(partial_file_name); if (partial_name_len >= PATH_MAX) return matches.GetSize(); // This copy of the string will be cut up into the directory part, and the remainder. end_ptr // below will point to the place of the remainder in this string. Then when we've resolved the // containing directory, and opened it, we'll read the directory contents and overwrite the // partial_name_copy starting from end_ptr with each of the matches. Thus we will preserve // the form the user originally typed. char partial_name_copy[PATH_MAX]; memcpy(partial_name_copy, partial_file_name, partial_name_len); partial_name_copy[partial_name_len] = '\0'; // We'll need to save a copy of the remainder for comparison, which we do here. char remainder[PATH_MAX]; // end_ptr will point past the last / in partial_name_copy, or if there is no slash to the beginning of the string. char *end_ptr; end_ptr = strrchr(partial_name_copy, '/'); // This will store the resolved form of the containing directory llvm::SmallString<64> containing_part; if (end_ptr == nullptr) { // There's no directory. If the thing begins with a "~" then this is a bare // user name. if (*partial_name_copy == '~') { // Nothing here but the user name. We could just put a slash on the end, // but for completeness sake we'll resolve the user name and only put a slash // on the end if it exists. llvm::SmallString<64> resolved_username(partial_name_copy); FileSpec::ResolveUsername (resolved_username); // Not sure how this would happen, a username longer than PATH_MAX? Still... if (resolved_username.size() == 0) { // The user name didn't resolve, let's look in the password database for matches. // The user name database contains duplicates, and is not in alphabetical order, so // we'll use a set to manage that for us. FileSpec::ResolvePartialUsername (partial_name_copy, matches); if (matches.GetSize() > 0) saw_directory = true; return matches.GetSize(); } else { //The thing exists, put a '/' on the end, and return it... // FIXME: complete user names here: partial_name_copy[partial_name_len] = '/'; partial_name_copy[partial_name_len+1] = '\0'; matches.AppendString(partial_name_copy); saw_directory = true; return matches.GetSize(); } } else { // The containing part is the CWD, and the whole string is the remainder. containing_part = "."; strcpy(remainder, partial_name_copy); end_ptr = partial_name_copy; } } else { if (end_ptr == partial_name_copy) { // We're completing a file or directory in the root volume. containing_part = "/"; } else { containing_part.append(partial_name_copy, end_ptr); } // Push end_ptr past the final "/" and set remainder. end_ptr++; strcpy(remainder, end_ptr); } // Look for a user name in the containing part, and if it's there, resolve it and stick the // result back into the containing_part: if (*partial_name_copy == '~') { FileSpec::ResolveUsername(containing_part); // User name doesn't exist, we're not getting any further... if (containing_part.empty()) return matches.GetSize(); } // Okay, containing_part is now the directory we want to open and look for files: size_t baselen = end_ptr - partial_name_copy; DiskFilesOrDirectoriesBaton parameters; parameters.remainder = remainder; parameters.partial_name_copy = partial_name_copy; parameters.only_directories = only_directories; parameters.saw_directory = &saw_directory; parameters.matches = &matches; parameters.end_ptr = end_ptr; parameters.baselen = baselen; FileSpec::EnumerateDirectory(containing_part.c_str(), true, true, true, DiskFilesOrDirectoriesCallback, ¶meters); return matches.GetSize(); }
static int DiskFilesOrDirectories ( const char *partial_file_name, bool only_directories, bool &saw_directory, StringList &matches ) { // I'm going to use the "glob" function with GLOB_TILDE for user directory expansion. // If it is not defined on your host system, you'll need to implement it yourself... int partial_name_len = strlen(partial_file_name); if (partial_name_len >= PATH_MAX) return matches.GetSize(); // This copy of the string will be cut up into the directory part, and the remainder. end_ptr // below will point to the place of the remainder in this string. Then when we've resolved the // containing directory, and opened it, we'll read the directory contents and overwrite the // partial_name_copy starting from end_ptr with each of the matches. Thus we will preserve // the form the user originally typed. char partial_name_copy[PATH_MAX]; memcpy(partial_name_copy, partial_file_name, partial_name_len); partial_name_copy[partial_name_len] = '\0'; // We'll need to save a copy of the remainder for comparison, which we do here. char remainder[PATH_MAX]; // end_ptr will point past the last / in partial_name_copy, or if there is no slash to the beginning of the string. char *end_ptr; end_ptr = strrchr(partial_name_copy, '/'); // This will store the resolved form of the containing directory char containing_part[PATH_MAX]; if (end_ptr == NULL) { // There's no directory. If the thing begins with a "~" then this is a bare // user name. if (*partial_name_copy == '~') { // Nothing here but the user name. We could just put a slash on the end, // but for completeness sake we'll resolve the user name and only put a slash // on the end if it exists. char resolved_username[PATH_MAX]; size_t resolved_username_len = FileSpec::ResolveUsername (partial_name_copy, resolved_username, sizeof (resolved_username)); // Not sure how this would happen, a username longer than PATH_MAX? Still... if (resolved_username_len >= sizeof (resolved_username)) return matches.GetSize(); else if (resolved_username_len == 0) { // The user name didn't resolve, let's look in the password database for matches. // The user name database contains duplicates, and is not in alphabetical order, so // we'll use a set to manage that for us. FileSpec::ResolvePartialUsername (partial_name_copy, matches); if (matches.GetSize() > 0) saw_directory = true; return matches.GetSize(); } else { //The thing exists, put a '/' on the end, and return it... // FIXME: complete user names here: partial_name_copy[partial_name_len] = '/'; partial_name_copy[partial_name_len+1] = '\0'; matches.AppendString(partial_name_copy); saw_directory = true; return matches.GetSize(); } } else { // The containing part is the CWD, and the whole string is the remainder. containing_part[0] = '.'; containing_part[1] = '\0'; strcpy(remainder, partial_name_copy); end_ptr = partial_name_copy; } } else { if (end_ptr == partial_name_copy) { // We're completing a file or directory in the root volume. containing_part[0] = '/'; containing_part[1] = '\0'; } else { size_t len = end_ptr - partial_name_copy; memcpy(containing_part, partial_name_copy, len); containing_part[len] = '\0'; } // Push end_ptr past the final "/" and set remainder. end_ptr++; strcpy(remainder, end_ptr); } // Look for a user name in the containing part, and if it's there, resolve it and stick the // result back into the containing_part: if (*partial_name_copy == '~') { size_t resolved_username_len = FileSpec::ResolveUsername(containing_part, containing_part, sizeof (containing_part)); // User name doesn't exist, we're not getting any further... if (resolved_username_len == 0 || resolved_username_len >= sizeof (containing_part)) return matches.GetSize(); } // Okay, containing_part is now the directory we want to open and look for files: lldb_utility::CleanUp <DIR *, int> dir_stream (opendir(containing_part), NULL, closedir); if (!dir_stream.is_valid()) return matches.GetSize(); struct dirent *dirent_buf; size_t baselen = end_ptr - partial_name_copy; while ((dirent_buf = readdir(dir_stream.get())) != NULL) { char *name = dirent_buf->d_name; // Omit ".", ".." and any . files if the match string doesn't start with . if (name[0] == '.') { if (name[1] == '\0') continue; else if (name[1] == '.' && name[2] == '\0') continue; else if (remainder[0] != '.') continue; } // If we found a directory, we put a "/" at the end of the name. if (remainder[0] == '\0' || strstr(dirent_buf->d_name, remainder) == name) { if (strlen(name) + baselen >= PATH_MAX) continue; strcpy(end_ptr, name); bool isa_directory = false; if (dirent_buf->d_type & DT_DIR) isa_directory = true; else if (dirent_buf->d_type & DT_LNK) { struct stat stat_buf; if ((stat(partial_name_copy, &stat_buf) == 0) && S_ISDIR(stat_buf.st_mode)) isa_directory = true; } if (isa_directory) { saw_directory = true; size_t len = strlen(partial_name_copy); partial_name_copy[len] = '/'; partial_name_copy[len + 1] = '\0'; } if (only_directories && !isa_directory) continue; matches.AppendString(partial_name_copy); } } return matches.GetSize(); }
void CompletionResult::GetDescriptions(StringList &descriptions) const { descriptions.Clear(); for (const Completion &completion : m_results) descriptions.AppendString(completion.m_descripton); }
void CompletionResult::GetMatches(StringList &matches) const { matches.Clear(); for (const Completion &completion : m_results) matches.AppendString(completion.m_completion); }
static void PrivateAutoComplete (StackFrame *frame, const std::string &partial_path, const std::string &prefix_path, // Anything that has been resolved already will be in here const CompilerType& compiler_type, StringList &matches, bool &word_complete) { // printf ("\nPrivateAutoComplete()\n\tprefix_path = '%s'\n\tpartial_path = '%s'\n", prefix_path.c_str(), partial_path.c_str()); std::string remaining_partial_path; const lldb::TypeClass type_class = compiler_type.GetTypeClass(); if (partial_path.empty()) { if (compiler_type.IsValid()) { switch (type_class) { default: case eTypeClassArray: case eTypeClassBlockPointer: case eTypeClassBuiltin: case eTypeClassComplexFloat: case eTypeClassComplexInteger: case eTypeClassEnumeration: case eTypeClassFunction: case eTypeClassMemberPointer: case eTypeClassReference: case eTypeClassTypedef: case eTypeClassVector: { matches.AppendString (prefix_path); word_complete = matches.GetSize() == 1; } break; case eTypeClassClass: case eTypeClassStruct: case eTypeClassUnion: if (prefix_path.back() != '.') matches.AppendString (prefix_path + '.'); break; case eTypeClassObjCObject: case eTypeClassObjCInterface: break; case eTypeClassObjCObjectPointer: case eTypeClassPointer: { bool omit_empty_base_classes = true; if (compiler_type.GetNumChildren (omit_empty_base_classes) > 0) matches.AppendString (prefix_path + "->"); else { matches.AppendString (prefix_path); word_complete = true; } } break; } } else { if (frame) { const bool get_file_globals = true; VariableList *variable_list = frame->GetVariableList(get_file_globals); if (variable_list) { const size_t num_variables = variable_list->GetSize(); for (size_t i=0; i<num_variables; ++i) { Variable *variable = variable_list->GetVariableAtIndex(i).get(); matches.AppendString (variable->GetName().AsCString()); } } } } } else { const char ch = partial_path[0]; switch (ch) { case '*': if (prefix_path.empty()) { PrivateAutoComplete (frame, partial_path.substr(1), std::string("*"), compiler_type, matches, word_complete); } break; case '&': if (prefix_path.empty()) { PrivateAutoComplete (frame, partial_path.substr(1), std::string("&"), compiler_type, matches, word_complete); } break; case '-': if (partial_path[1] == '>' && !prefix_path.empty()) { switch (type_class) { case lldb::eTypeClassPointer: { CompilerType pointee_type(compiler_type.GetPointeeType()); if (partial_path[2]) { // If there is more after the "->", then search deeper PrivateAutoComplete (frame, partial_path.substr(2), prefix_path + "->", pointee_type.GetCanonicalType(), matches, word_complete); } else { // Nothing after the "->", so list all members PrivateAutoCompleteMembers (frame, std::string(), std::string(), prefix_path + "->", pointee_type.GetCanonicalType(), matches, word_complete); } } break; default: break; } } break; case '.': if (compiler_type.IsValid()) { switch (type_class) { case lldb::eTypeClassUnion: case lldb::eTypeClassStruct: case lldb::eTypeClassClass: if (partial_path[1]) { // If there is more after the ".", then search deeper PrivateAutoComplete (frame, partial_path.substr(1), prefix_path + ".", compiler_type, matches, word_complete); } else { // Nothing after the ".", so list all members PrivateAutoCompleteMembers (frame, std::string(), partial_path, prefix_path + ".", compiler_type, matches, word_complete); } break; default: break; } } break; default: if (isalpha(ch) || ch == '_' || ch == '$') { const size_t partial_path_len = partial_path.size(); size_t pos = 1; while (pos < partial_path_len) { const char curr_ch = partial_path[pos]; if (isalnum(curr_ch) || curr_ch == '_' || curr_ch == '$') { ++pos; continue; } break; } std::string token(partial_path, 0, pos); remaining_partial_path = partial_path.substr(pos); if (compiler_type.IsValid()) { PrivateAutoCompleteMembers (frame, token, remaining_partial_path, prefix_path, compiler_type, matches, word_complete); } else if (frame) { // We haven't found our variable yet const bool get_file_globals = true; VariableList *variable_list = frame->GetVariableList(get_file_globals); if (!variable_list) break; const size_t num_variables = variable_list->GetSize(); for (size_t i=0; i<num_variables; ++i) { Variable *variable = variable_list->GetVariableAtIndex(i).get(); if (!variable) continue; const char *variable_name = variable->GetName().AsCString(); if (strstr(variable_name, token.c_str()) == variable_name) { if (strcmp (variable_name, token.c_str()) == 0) { Type *variable_type = variable->GetType(); if (variable_type) { CompilerType variable_compiler_type (variable_type->GetForwardCompilerType ()); PrivateAutoComplete (frame, remaining_partial_path, prefix_path + token, // Anything that has been resolved already will be in here variable_compiler_type.GetCanonicalType(), matches, word_complete); } else { matches.AppendString (prefix_path + variable_name); } } else if (remaining_partial_path.empty()) { matches.AppendString (prefix_path + variable_name); } } } } } break; } } }
static void PrivateAutoCompleteMembers (StackFrame *frame, const std::string &partial_member_name, const std::string &partial_path, const std::string &prefix_path, // Anything that has been resolved already will be in here const CompilerType& compiler_type, StringList &matches, bool &word_complete) { // We are in a type parsing child members const uint32_t num_bases = compiler_type.GetNumDirectBaseClasses(); if (num_bases > 0) { for (uint32_t i = 0; i < num_bases; ++i) { CompilerType base_class_type = compiler_type.GetDirectBaseClassAtIndex(i, nullptr); PrivateAutoCompleteMembers (frame, partial_member_name, partial_path, prefix_path, base_class_type.GetCanonicalType(), matches, word_complete); } } const uint32_t num_vbases = compiler_type.GetNumVirtualBaseClasses(); if (num_vbases > 0) { for (uint32_t i = 0; i < num_vbases; ++i) { CompilerType vbase_class_type = compiler_type.GetVirtualBaseClassAtIndex(i,nullptr); PrivateAutoCompleteMembers (frame, partial_member_name, partial_path, prefix_path, vbase_class_type.GetCanonicalType(), matches, word_complete); } } // We are in a type parsing child members const uint32_t num_fields = compiler_type.GetNumFields(); if (num_fields > 0) { for (uint32_t i = 0; i < num_fields; ++i) { std::string member_name; CompilerType member_compiler_type = compiler_type.GetFieldAtIndex (i, member_name, nullptr, nullptr, nullptr); if (partial_member_name.empty() || member_name.find(partial_member_name) == 0) { if (member_name == partial_member_name) { PrivateAutoComplete (frame, partial_path, prefix_path + member_name, // Anything that has been resolved already will be in here member_compiler_type.GetCanonicalType(), matches, word_complete); } else { matches.AppendString (prefix_path + member_name); } } } } }
static int DiskFilesOrDirectories(const llvm::Twine &partial_name, bool only_directories, StringList &matches, TildeExpressionResolver &Resolver) { matches.Clear(); llvm::SmallString<256> CompletionBuffer; llvm::SmallString<256> Storage; partial_name.toVector(CompletionBuffer); if (CompletionBuffer.size() >= PATH_MAX) return matches.GetSize(); namespace path = llvm::sys::path; llvm::StringRef SearchDir; llvm::StringRef PartialItem; if (CompletionBuffer.startswith("~")) { llvm::StringRef Buffer(CompletionBuffer); size_t FirstSep = Buffer.find_if([](char c) { return path::is_separator(c); }); llvm::StringRef Username = Buffer.take_front(FirstSep); llvm::StringRef Remainder; if (FirstSep != llvm::StringRef::npos) Remainder = Buffer.drop_front(FirstSep + 1); llvm::SmallString<256> Resolved; if (!Resolver.ResolveExact(Username, Resolved)) { // We couldn't resolve it as a full username. If there were no slashes // then this might be a partial username. We try to resolve it as such // but after that, we're done regardless of any matches. if (FirstSep == llvm::StringRef::npos) { llvm::StringSet<> MatchSet; Resolver.ResolvePartial(Username, MatchSet); for (const auto &S : MatchSet) { Resolved = S.getKey(); path::append(Resolved, path::get_separator()); matches.AppendString(Resolved); } } return matches.GetSize(); } // If there was no trailing slash, then we're done as soon as we resolve // the expression to the correct directory. Otherwise we need to continue // looking for matches within that directory. if (FirstSep == llvm::StringRef::npos) { // Make sure it ends with a separator. path::append(CompletionBuffer, path::get_separator()); matches.AppendString(CompletionBuffer); return matches.GetSize(); } // We want to keep the form the user typed, so we special case this to // search in the fully resolved directory, but CompletionBuffer keeps the // unmodified form that the user typed. Storage = Resolved; llvm::StringRef RemainderDir = path::parent_path(Remainder); if (!RemainderDir.empty()) { // Append the remaining path to the resolved directory. Storage.append(path::get_separator()); Storage.append(RemainderDir); } SearchDir = Storage; } else { SearchDir = path::parent_path(CompletionBuffer); } size_t FullPrefixLen = CompletionBuffer.size(); PartialItem = path::filename(CompletionBuffer); // path::filename() will return "." when the passed path ends with a // directory separator. We have to filter those out, but only when the // "." doesn't come from the completion request itself. if (PartialItem == "." && path::is_separator(CompletionBuffer.back())) PartialItem = llvm::StringRef(); if (SearchDir.empty()) { llvm::sys::fs::current_path(Storage); SearchDir = Storage; } assert(!PartialItem.contains(path::get_separator())); // SearchDir now contains the directory to search in, and Prefix contains the // text we want to match against items in that directory. FileSystem &fs = FileSystem::Instance(); std::error_code EC; llvm::vfs::directory_iterator Iter = fs.DirBegin(SearchDir, EC); llvm::vfs::directory_iterator End; for (; Iter != End && !EC; Iter.increment(EC)) { auto &Entry = *Iter; llvm::ErrorOr<llvm::vfs::Status> Status = fs.GetStatus(Entry.path()); if (!Status) continue; auto Name = path::filename(Entry.path()); // Omit ".", ".." if (Name == "." || Name == ".." || !Name.startswith(PartialItem)) continue; bool is_dir = Status->isDirectory(); // If it's a symlink, then we treat it as a directory as long as the target // is a directory. if (Status->isSymlink()) { FileSpec symlink_filespec(Entry.path()); FileSpec resolved_filespec; auto error = fs.ResolveSymbolicLink(symlink_filespec, resolved_filespec); if (error.Success()) is_dir = fs.IsDirectory(symlink_filespec); } if (only_directories && !is_dir) continue; // Shrink it back down so that it just has the original prefix the user // typed and remove the part of the name which is common to the located // item and what the user typed. CompletionBuffer.resize(FullPrefixLen); Name = Name.drop_front(PartialItem.size()); CompletionBuffer.append(Name); if (is_dir) { path::append(CompletionBuffer, path::get_separator()); } matches.AppendString(CompletionBuffer); } return matches.GetSize(); }