blob: 77e9ac8c8f2f78361f536ca1e7fcd39d0d82716b [file] [log] [blame]
Chris Lattner24943d22010-06-08 16:52:24 +00001//===-- 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
Jim Ingham802f8b02010-06-30 05:02:46 +000012#include <sys/stat.h>
13#include <dirent.h>
14#include <libgen.h>
15#include <glob.h>
Jim Ingham84a0d332010-07-02 00:45:55 +000016#include <pwd.h>
17#include <sys/types.h>
Jim Ingham802f8b02010-06-30 05:02:46 +000018
Chris Lattner24943d22010-06-08 16:52:24 +000019// C++ Includes
20// Other libraries and framework includes
21// Project includes
Jim Ingham84cdc152010-06-15 19:49:27 +000022#include "lldb/Interpreter/Args.h"
Chris Lattner24943d22010-06-08 16:52:24 +000023#include "lldb/Interpreter/CommandInterpreter.h"
24#include "lldb/Core/FileSpecList.h"
25#include "lldb/Target/Target.h"
26#include "lldb/Interpreter/CommandCompletions.h"
Jim Ingham84a0d332010-07-02 00:45:55 +000027#include "lldb/Core/FileSpec.h"
Chris Lattner24943d22010-06-08 16:52:24 +000028
29
30using namespace lldb_private;
31
32CommandCompletions::CommonCompletionElement
33CommandCompletions::g_common_completions[] =
34{
Jim Ingham802f8b02010-06-30 05:02:46 +000035 {eCustomCompletion, NULL},
36 {eSourceFileCompletion, CommandCompletions::SourceFiles},
37 {eDiskFileCompletion, CommandCompletions::DiskFiles},
38 {eDiskDirectoryCompletion, CommandCompletions::DiskDirectories},
39 {eSymbolCompletion, CommandCompletions::Symbols},
40 {eModuleCompletion, CommandCompletions::Modules},
41 {eNoCompletion, NULL} // This one has to be last in the list.
Chris Lattner24943d22010-06-08 16:52:24 +000042};
43
44bool
Greg Clayton63094e02010-06-23 01:19:29 +000045CommandCompletions::InvokeCommonCompletionCallbacks
46(
47 CommandInterpreter &interpreter,
48 uint32_t completion_mask,
49 const char *completion_str,
50 int match_start_point,
51 int max_return_elements,
52 SearchFilter *searcher,
Jim Ingham802f8b02010-06-30 05:02:46 +000053 bool &word_complete,
Greg Clayton63094e02010-06-23 01:19:29 +000054 StringList &matches
55)
Chris Lattner24943d22010-06-08 16:52:24 +000056{
57 bool handled = false;
58
59 if (completion_mask & eCustomCompletion)
60 return false;
61
62 for (int i = 0; ; i++)
63 {
64 if (g_common_completions[i].type == eNoCompletion)
65 break;
66 else if ((g_common_completions[i].type & completion_mask) == g_common_completions[i].type
67 && g_common_completions[i].callback != NULL)
68 {
69 handled = true;
Greg Clayton63094e02010-06-23 01:19:29 +000070 g_common_completions[i].callback (interpreter,
71 completion_str,
Chris Lattner24943d22010-06-08 16:52:24 +000072 match_start_point,
73 max_return_elements,
Chris Lattner24943d22010-06-08 16:52:24 +000074 searcher,
Jim Ingham802f8b02010-06-30 05:02:46 +000075 word_complete,
Chris Lattner24943d22010-06-08 16:52:24 +000076 matches);
77 }
78 }
79 return handled;
80}
81
82int
Greg Clayton63094e02010-06-23 01:19:29 +000083CommandCompletions::SourceFiles
84(
85 CommandInterpreter &interpreter,
86 const char *partial_file_name,
87 int match_start_point,
88 int max_return_elements,
89 SearchFilter *searcher,
Jim Ingham802f8b02010-06-30 05:02:46 +000090 bool &word_complete,
Greg Clayton63094e02010-06-23 01:19:29 +000091 StringList &matches
92)
Chris Lattner24943d22010-06-08 16:52:24 +000093{
Jim Ingham802f8b02010-06-30 05:02:46 +000094 word_complete = true;
Chris Lattner24943d22010-06-08 16:52:24 +000095 // Find some way to switch "include support files..."
Greg Clayton63094e02010-06-23 01:19:29 +000096 SourceFileCompleter completer (interpreter,
97 false,
98 partial_file_name,
99 match_start_point,
100 max_return_elements,
Chris Lattner24943d22010-06-08 16:52:24 +0000101 matches);
102
103 if (searcher == NULL)
104 {
Jim Inghamc8332952010-08-26 21:32:51 +0000105 lldb::TargetSP target_sp = interpreter.GetDebugger().GetSelectedTarget();
Chris Lattner24943d22010-06-08 16:52:24 +0000106 SearchFilter null_searcher (target_sp);
107 completer.DoCompletion (&null_searcher);
108 }
109 else
110 {
111 completer.DoCompletion (searcher);
112 }
113 return matches.GetSize();
114}
115
Jim Ingham802f8b02010-06-30 05:02:46 +0000116static int
117DiskFilesOrDirectories
118(
119 const char *partial_file_name,
120 bool only_directories,
121 bool &saw_directory,
122 StringList &matches
123)
124{
125 // I'm going to use the "glob" function with GLOB_TILDE for user directory expansion.
126 // If it is not defined on your host system, you'll need to implement it yourself...
127
128 int partial_name_len = strlen(partial_file_name);
129
130 if (partial_name_len >= PATH_MAX)
131 return matches.GetSize();
132
133 // This copy of the string will be cut up into the directory part, and the remainder. end_ptr
134 // below will point to the place of the remainder in this string. Then when we've resolved the
135 // containing directory, and opened it, we'll read the directory contents and overwrite the
136 // partial_name_copy starting from end_ptr with each of the matches. Thus we will preserve
137 // the form the user originally typed.
138
139 char partial_name_copy[PATH_MAX];
Benjamin Kramerbdbb9af2010-06-30 13:43:47 +0000140 memcpy(partial_name_copy, partial_file_name, partial_name_len);
Jim Ingham802f8b02010-06-30 05:02:46 +0000141 partial_name_copy[partial_name_len] = '\0';
142
143 // We'll need to save a copy of the remainder for comparision, which we do here.
144 char remainder[PATH_MAX];
145
146 // end_ptr will point past the last / in partial_name_copy, or if there is no slash to the beginning of the string.
147 char *end_ptr;
148
149 end_ptr = strrchr(partial_name_copy, '/');
150
151 // This will store the resolved form of the containing directory
152 char containing_part[PATH_MAX];
153
154 if (end_ptr == NULL)
155 {
156 // There's no directory. If the thing begins with a "~" then this is a bare
157 // user name.
158 if (*partial_name_copy == '~')
159 {
160 // Nothing here but the user name. We could just put a slash on the end,
Jim Ingham84a0d332010-07-02 00:45:55 +0000161 // but for completeness sake we'll resolve the user name and only put a slash
Jim Ingham802f8b02010-06-30 05:02:46 +0000162 // on the end if it exists.
Jim Ingham84a0d332010-07-02 00:45:55 +0000163 char resolved_username[PATH_MAX];
Greg Clayton54e7afa2010-07-09 20:39:50 +0000164 size_t resolved_username_len = FileSpec::ResolveUsername (partial_name_copy, resolved_username,
Jim Ingham84a0d332010-07-02 00:45:55 +0000165 sizeof (resolved_username));
166
167 // Not sure how this would happen, a username longer than PATH_MAX? Still...
168 if (resolved_username_len >= sizeof (resolved_username))
169 return matches.GetSize();
170 else if (resolved_username_len == 0)
171 {
172 // The user name didn't resolve, let's look in the password database for matches.
173 // The user name database contains duplicates, and is not in alphabetical order, so
174 // we'll use a set to manage that for us.
175
176 setpwent();
177 struct passwd *user_entry;
178 const char *name_start = partial_name_copy + 1;
179 std::set<std::string> name_list;
180
181 while ((user_entry = getpwent()) != NULL)
182 {
183 if (strstr(user_entry->pw_name, name_start) == user_entry->pw_name)
184 {
185 std::string tmp_buf("~");
186 tmp_buf.append(user_entry->pw_name);
187 tmp_buf.push_back('/');
188 name_list.insert(tmp_buf);
189 saw_directory = true;
190 }
191 }
192 std::set<std::string>::iterator pos, end = name_list.end();
193 for (pos = name_list.begin(); pos != end; pos++)
194 {
195 matches.AppendString((*pos).c_str());
196 }
197 return matches.GetSize();
198 }
199
200 //The thing exists, put a '/' on the end, and return it...
201 // FIXME: complete user names here:
202 partial_name_copy[partial_name_len] = '/';
203 partial_name_copy[partial_name_len+1] = '\0';
204 matches.AppendString(partial_name_copy);
205 saw_directory = true;
206 return matches.GetSize();
Jim Ingham802f8b02010-06-30 05:02:46 +0000207 }
208 else
209 {
210 // The containing part is the CWD, and the whole string is the remainder.
211 containing_part[0] = '.';
212 containing_part[1] = '\0';
213 strcpy(remainder, partial_name_copy);
214 end_ptr = partial_name_copy;
215 }
216 }
217 else
218 {
219 if (end_ptr == partial_name_copy)
220 {
221 // We're completing a file or directory in the root volume.
222 containing_part[0] = '/';
223 containing_part[1] = '\0';
224 }
225 else
226 {
227 size_t len = end_ptr - partial_name_copy;
228 memcpy(containing_part, partial_name_copy, len);
229 containing_part[len] = '\0';
230 }
231 // Push end_ptr past the final "/" and set remainder.
232 end_ptr++;
233 strcpy(remainder, end_ptr);
234 }
235
Jim Ingham84a0d332010-07-02 00:45:55 +0000236 // Look for a user name in the containing part, and if it's there, resolve it and stick the
Jim Ingham802f8b02010-06-30 05:02:46 +0000237 // result back into the containing_part:
238
239 if (*partial_name_copy == '~')
240 {
Greg Clayton54e7afa2010-07-09 20:39:50 +0000241 size_t resolved_username_len = FileSpec::ResolveUsername(containing_part, containing_part, sizeof (containing_part));
Jim Ingham802f8b02010-06-30 05:02:46 +0000242 // User name doesn't exist, we're not getting any further...
Greg Clayton099c7972010-07-06 16:11:44 +0000243 if (resolved_username_len == 0 || resolved_username_len >= sizeof (containing_part))
Jim Ingham802f8b02010-06-30 05:02:46 +0000244 return matches.GetSize();
Jim Ingham802f8b02010-06-30 05:02:46 +0000245 }
246
247 // Okay, containing_part is now the directory we want to open and look for files:
248
249 DIR *dir_stream;
250
251 dir_stream = opendir(containing_part);
252 if (dir_stream == NULL)
253 return matches.GetSize();
254
255 struct dirent *dirent_buf;
256
257 size_t baselen = end_ptr - partial_name_copy;
258
259 while ((dirent_buf = readdir(dir_stream)) != NULL)
260 {
261 char *name = dirent_buf->d_name;
262
263 // Omit ".", ".." and any . files if the match string doesn't start with .
264 if (name[0] == '.')
265 {
266 if (name[1] == '\0')
267 continue;
268 else if (name[1] == '.' && name[2] == '\0')
269 continue;
270 else if (remainder[0] != '.')
271 continue;
272 }
273
Jim Ingham84a0d332010-07-02 00:45:55 +0000274 // If we found a directory, we put a "/" at the end of the name.
275
Jim Ingham802f8b02010-06-30 05:02:46 +0000276 if (remainder[0] == '\0' || strstr(dirent_buf->d_name, remainder) == name)
277 {
278 if (strlen(name) + baselen >= PATH_MAX)
279 continue;
280
281 strcpy(end_ptr, name);
282
283 bool isa_directory = false;
284 if (dirent_buf->d_type & DT_DIR)
285 isa_directory = true;
286 else if (dirent_buf->d_type & DT_LNK)
287 {
288 struct stat stat_buf;
289 if ((stat(partial_name_copy, &stat_buf) == 0) && (stat_buf.st_mode & S_IFDIR))
290 isa_directory = true;
291 }
292
293 if (isa_directory)
294 {
295 saw_directory = true;
296 size_t len = strlen(partial_name_copy);
297 partial_name_copy[len] = '/';
298 partial_name_copy[len + 1] = '\0';
299 }
300 if (only_directories && !isa_directory)
301 continue;
302 matches.AppendString(partial_name_copy);
303 }
304 }
305
306 return matches.GetSize();
307}
308
309int
310CommandCompletions::DiskFiles
311(
312 CommandInterpreter &interpreter,
313 const char *partial_file_name,
314 int match_start_point,
315 int max_return_elements,
316 SearchFilter *searcher,
317 bool &word_complete,
318 StringList &matches
319)
320{
321
322 int ret_val = DiskFilesOrDirectories (partial_file_name,
323 false,
324 word_complete,
325 matches);
326 word_complete = !word_complete;
327 return ret_val;
328}
329
330int
331CommandCompletions::DiskDirectories
332(
333 CommandInterpreter &interpreter,
334 const char *partial_file_name,
335 int match_start_point,
336 int max_return_elements,
337 SearchFilter *searcher,
338 bool &word_complete,
339 StringList &matches
340)
341{
342 int ret_val = DiskFilesOrDirectories (partial_file_name,
343 true,
344 word_complete,
345 matches);
346 word_complete = false;
347 return ret_val;
348}
349
Chris Lattner24943d22010-06-08 16:52:24 +0000350int
Greg Clayton63094e02010-06-23 01:19:29 +0000351CommandCompletions::Modules
352(
353 CommandInterpreter &interpreter,
354 const char *partial_file_name,
355 int match_start_point,
356 int max_return_elements,
357 SearchFilter *searcher,
Jim Ingham802f8b02010-06-30 05:02:46 +0000358 bool &word_complete,
Greg Clayton63094e02010-06-23 01:19:29 +0000359 StringList &matches
360)
Chris Lattner24943d22010-06-08 16:52:24 +0000361{
Jim Ingham802f8b02010-06-30 05:02:46 +0000362 word_complete = true;
Greg Clayton63094e02010-06-23 01:19:29 +0000363 ModuleCompleter completer (interpreter,
364 partial_file_name,
365 match_start_point,
366 max_return_elements,
367 matches);
368
Chris Lattner24943d22010-06-08 16:52:24 +0000369 if (searcher == NULL)
370 {
Jim Inghamc8332952010-08-26 21:32:51 +0000371 lldb::TargetSP target_sp = interpreter.GetDebugger().GetSelectedTarget();
Chris Lattner24943d22010-06-08 16:52:24 +0000372 SearchFilter null_searcher (target_sp);
373 completer.DoCompletion (&null_searcher);
374 }
375 else
376 {
377 completer.DoCompletion (searcher);
378 }
379 return matches.GetSize();
380}
381
382int
Greg Clayton63094e02010-06-23 01:19:29 +0000383CommandCompletions::Symbols
384(
385 CommandInterpreter &interpreter,
386 const char *partial_file_name,
387 int match_start_point,
388 int max_return_elements,
389 SearchFilter *searcher,
Jim Ingham802f8b02010-06-30 05:02:46 +0000390 bool &word_complete,
Greg Clayton63094e02010-06-23 01:19:29 +0000391 StringList &matches)
Chris Lattner24943d22010-06-08 16:52:24 +0000392{
Jim Ingham802f8b02010-06-30 05:02:46 +0000393 word_complete = true;
Greg Clayton63094e02010-06-23 01:19:29 +0000394 SymbolCompleter completer (interpreter,
395 partial_file_name,
396 match_start_point,
397 max_return_elements,
398 matches);
Chris Lattner24943d22010-06-08 16:52:24 +0000399
400 if (searcher == NULL)
401 {
Jim Inghamc8332952010-08-26 21:32:51 +0000402 lldb::TargetSP target_sp = interpreter.GetDebugger().GetSelectedTarget();
Chris Lattner24943d22010-06-08 16:52:24 +0000403 SearchFilter null_searcher (target_sp);
404 completer.DoCompletion (&null_searcher);
405 }
406 else
407 {
408 completer.DoCompletion (searcher);
409 }
410 return matches.GetSize();
411}
412
Greg Clayton63094e02010-06-23 01:19:29 +0000413CommandCompletions::Completer::Completer
414(
415 CommandInterpreter &interpreter,
Chris Lattner24943d22010-06-08 16:52:24 +0000416 const char *completion_str,
417 int match_start_point,
418 int max_return_elements,
Chris Lattner24943d22010-06-08 16:52:24 +0000419 StringList &matches
420) :
Greg Clayton63094e02010-06-23 01:19:29 +0000421 m_interpreter (interpreter),
Chris Lattner24943d22010-06-08 16:52:24 +0000422 m_completion_str (completion_str),
423 m_match_start_point (match_start_point),
424 m_max_return_elements (max_return_elements),
Chris Lattner24943d22010-06-08 16:52:24 +0000425 m_matches (matches)
426{
427}
428
429CommandCompletions::Completer::~Completer ()
430{
431
432}
433
434//----------------------------------------------------------------------
435// SourceFileCompleter
436//----------------------------------------------------------------------
437
Greg Clayton63094e02010-06-23 01:19:29 +0000438CommandCompletions::SourceFileCompleter::SourceFileCompleter
439(
440 CommandInterpreter &interpreter,
Chris Lattner24943d22010-06-08 16:52:24 +0000441 bool include_support_files,
442 const char *completion_str,
443 int match_start_point,
444 int max_return_elements,
Chris Lattner24943d22010-06-08 16:52:24 +0000445 StringList &matches
446) :
Greg Clayton63094e02010-06-23 01:19:29 +0000447 CommandCompletions::Completer (interpreter, completion_str, match_start_point, max_return_elements, matches),
Chris Lattner24943d22010-06-08 16:52:24 +0000448 m_include_support_files (include_support_files),
449 m_matching_files()
450{
451 FileSpec partial_spec (m_completion_str.c_str());
452 m_file_name = partial_spec.GetFilename().GetCString();
453 m_dir_name = partial_spec.GetDirectory().GetCString();
454}
455
456Searcher::Depth
457CommandCompletions::SourceFileCompleter::GetDepth()
458{
459 return eDepthCompUnit;
460}
461
462Searcher::CallbackReturn
463CommandCompletions::SourceFileCompleter::SearchCallback (
464 SearchFilter &filter,
465 SymbolContext &context,
466 Address *addr,
467 bool complete
468)
469{
470 if (context.comp_unit != NULL)
471 {
472 if (m_include_support_files)
473 {
474 FileSpecList supporting_files = context.comp_unit->GetSupportFiles();
475 for (size_t sfiles = 0; sfiles < supporting_files.GetSize(); sfiles++)
476 {
477 const FileSpec &sfile_spec = supporting_files.GetFileSpecAtIndex(sfiles);
478 const char *sfile_file_name = sfile_spec.GetFilename().GetCString();
479 const char *sfile_dir_name = sfile_spec.GetFilename().GetCString();
480 bool match = false;
481 if (m_file_name && sfile_file_name
482 && strstr (sfile_file_name, m_file_name) == sfile_file_name)
483 match = true;
484 if (match && m_dir_name && sfile_dir_name
485 && strstr (sfile_dir_name, m_dir_name) != sfile_dir_name)
486 match = false;
487
488 if (match)
489 {
490 m_matching_files.AppendIfUnique(sfile_spec);
491 }
492 }
493
494 }
495 else
496 {
497 const char *cur_file_name = context.comp_unit->GetFilename().GetCString();
498 const char *cur_dir_name = context.comp_unit->GetDirectory().GetCString();
499
500 bool match = false;
501 if (m_file_name && cur_file_name
502 && strstr (cur_file_name, m_file_name) == cur_file_name)
503 match = true;
504
505 if (match && m_dir_name && cur_dir_name
506 && strstr (cur_dir_name, m_dir_name) != cur_dir_name)
507 match = false;
508
509 if (match)
510 {
511 m_matching_files.AppendIfUnique(context.comp_unit);
512 }
513 }
514 }
515 return Searcher::eCallbackReturnContinue;
516}
517
518size_t
519CommandCompletions::SourceFileCompleter::DoCompletion (SearchFilter *filter)
520{
521 filter->Search (*this);
522 // Now convert the filelist to completions:
523 for (size_t i = 0; i < m_matching_files.GetSize(); i++)
524 {
525 m_matches.AppendString (m_matching_files.GetFileSpecAtIndex(i).GetFilename().GetCString());
526 }
527 return m_matches.GetSize();
528
529}
530
531//----------------------------------------------------------------------
532// SymbolCompleter
533//----------------------------------------------------------------------
534
535static bool
536regex_chars (const char comp)
537{
538 if (comp == '[' || comp == ']' || comp == '(' || comp == ')')
539 return true;
540 else
541 return false;
542}
Greg Clayton63094e02010-06-23 01:19:29 +0000543CommandCompletions::SymbolCompleter::SymbolCompleter
544(
545 CommandInterpreter &interpreter,
Chris Lattner24943d22010-06-08 16:52:24 +0000546 const char *completion_str,
547 int match_start_point,
548 int max_return_elements,
Chris Lattner24943d22010-06-08 16:52:24 +0000549 StringList &matches
550) :
Greg Clayton63094e02010-06-23 01:19:29 +0000551 CommandCompletions::Completer (interpreter, completion_str, match_start_point, max_return_elements, matches)
Chris Lattner24943d22010-06-08 16:52:24 +0000552{
553 std::string regex_str ("^");
554 regex_str.append(completion_str);
555 regex_str.append(".*");
556 std::string::iterator pos;
557
558 pos = find_if(regex_str.begin(), regex_str.end(), regex_chars);
559 while (pos < regex_str.end()) {
560 pos = regex_str.insert(pos, '\\');
561 pos += 2;
562 pos = find_if(pos, regex_str.end(), regex_chars);
563 }
564 m_regex.Compile(regex_str.c_str());
565}
566
567Searcher::Depth
568CommandCompletions::SymbolCompleter::GetDepth()
569{
570 return eDepthModule;
571}
572
573Searcher::CallbackReturn
574CommandCompletions::SymbolCompleter::SearchCallback (
575 SearchFilter &filter,
576 SymbolContext &context,
577 Address *addr,
578 bool complete
579)
580{
581 SymbolContextList func_list;
582 SymbolContextList sym_list;
583
584 if (context.module_sp != NULL)
585 {
586 if (context.module_sp)
587 {
588 context.module_sp->FindSymbolsMatchingRegExAndType (m_regex, lldb::eSymbolTypeCode, sym_list);
589 context.module_sp->FindFunctions (m_regex, true, func_list);
590 }
591
592 SymbolContext sc;
593 // Now add the functions & symbols to the list - only add if unique:
Greg Clayton54e7afa2010-07-09 20:39:50 +0000594 for (uint32_t i = 0; i < func_list.GetSize(); i++)
Chris Lattner24943d22010-06-08 16:52:24 +0000595 {
596 if (func_list.GetContextAtIndex(i, sc))
597 {
598 if (sc.function)
599 {
600 m_match_set.insert (sc.function->GetMangled().GetDemangledName());
601 }
602 }
603 }
604
Greg Clayton54e7afa2010-07-09 20:39:50 +0000605 for (uint32_t i = 0; i < sym_list.GetSize(); i++)
Chris Lattner24943d22010-06-08 16:52:24 +0000606 {
607 if (sym_list.GetContextAtIndex(i, sc))
608 {
609 if (sc.symbol && sc.symbol->GetAddressRangePtr())
610 {
611 m_match_set.insert (sc.symbol->GetMangled().GetDemangledName());
612 }
613 }
614 }
615 }
616 return Searcher::eCallbackReturnContinue;
617}
618
619size_t
620CommandCompletions::SymbolCompleter::DoCompletion (SearchFilter *filter)
621{
622 filter->Search (*this);
623 collection::iterator pos = m_match_set.begin(), end = m_match_set.end();
624 for (pos = m_match_set.begin(); pos != end; pos++)
625 m_matches.AppendString((*pos).GetCString());
626
627 return m_matches.GetSize();
628}
629
630//----------------------------------------------------------------------
631// ModuleCompleter
632//----------------------------------------------------------------------
Greg Clayton63094e02010-06-23 01:19:29 +0000633CommandCompletions::ModuleCompleter::ModuleCompleter
634(
635 CommandInterpreter &interpreter,
Chris Lattner24943d22010-06-08 16:52:24 +0000636 const char *completion_str,
637 int match_start_point,
638 int max_return_elements,
Chris Lattner24943d22010-06-08 16:52:24 +0000639 StringList &matches
640) :
Greg Clayton63094e02010-06-23 01:19:29 +0000641 CommandCompletions::Completer (interpreter, completion_str, match_start_point, max_return_elements, matches)
Chris Lattner24943d22010-06-08 16:52:24 +0000642{
643 FileSpec partial_spec (m_completion_str.c_str());
644 m_file_name = partial_spec.GetFilename().GetCString();
645 m_dir_name = partial_spec.GetDirectory().GetCString();
646}
647
648Searcher::Depth
649CommandCompletions::ModuleCompleter::GetDepth()
650{
651 return eDepthModule;
652}
653
654Searcher::CallbackReturn
655CommandCompletions::ModuleCompleter::SearchCallback (
656 SearchFilter &filter,
657 SymbolContext &context,
658 Address *addr,
659 bool complete
660)
661{
662 if (context.module_sp != NULL)
663 {
664 const char *cur_file_name = context.module_sp->GetFileSpec().GetFilename().GetCString();
665 const char *cur_dir_name = context.module_sp->GetFileSpec().GetDirectory().GetCString();
666
667 bool match = false;
668 if (m_file_name && cur_file_name
669 && strstr (cur_file_name, m_file_name) == cur_file_name)
670 match = true;
671
672 if (match && m_dir_name && cur_dir_name
673 && strstr (cur_dir_name, m_dir_name) != cur_dir_name)
674 match = false;
675
676 if (match)
677 {
678 m_matches.AppendString (cur_file_name);
679 }
680 }
681 return Searcher::eCallbackReturnContinue;
682}
683
684size_t
685CommandCompletions::ModuleCompleter::DoCompletion (SearchFilter *filter)
686{
687 filter->Search (*this);
688 return m_matches.GetSize();
689}
690
691
692