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