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