blob: ab782d6bfd0df09307984243a95ba16f65338a4c [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>
Greg Clayton8da92a72011-02-05 02:27:52 +000014#if defined(__APPLE__) || defined(__linux__)
Jim Ingham84a0d332010-07-02 00:45:55 +000015#include <pwd.h>
Greg Clayton8da92a72011-02-05 02:27:52 +000016#endif
Jim Ingham802f8b02010-06-30 05:02:46 +000017
Chris Lattner24943d22010-06-08 16:52:24 +000018// C++ Includes
19// Other libraries and framework includes
20// Project includes
Greg Clayton5f54ac32011-02-08 05:05:52 +000021#include "lldb/Host/FileSpec.h"
Greg Clayton74800612011-02-01 05:15:22 +000022#include "lldb/Core/FileSpecList.h"
Greg Clayton5e342f52011-04-13 22:47:15 +000023#include "lldb/Core/PluginManager.h"
Greg Clayton49ce8962012-08-29 21:13:06 +000024#include "lldb/Core/Module.h"
Greg Clayton74800612011-02-01 05:15:22 +000025#include "lldb/Interpreter/Args.h"
26#include "lldb/Interpreter/CommandCompletions.h"
27#include "lldb/Interpreter/CommandInterpreter.h"
Greg Clayton49ce8962012-08-29 21:13:06 +000028#include "lldb/Symbol/CompileUnit.h"
Greg Clayton74800612011-02-01 05:15:22 +000029#include "lldb/Target/Target.h"
30#include "lldb/Utility/CleanUp.h"
Chris Lattner24943d22010-06-08 16:52:24 +000031
32using namespace lldb_private;
33
34CommandCompletions::CommonCompletionElement
35CommandCompletions::g_common_completions[] =
36{
Jim Ingham802f8b02010-06-30 05:02:46 +000037 {eCustomCompletion, NULL},
38 {eSourceFileCompletion, CommandCompletions::SourceFiles},
39 {eDiskFileCompletion, CommandCompletions::DiskFiles},
40 {eDiskDirectoryCompletion, CommandCompletions::DiskDirectories},
41 {eSymbolCompletion, CommandCompletions::Symbols},
42 {eModuleCompletion, CommandCompletions::Modules},
Caroline Tice6e4c5ce2010-09-04 00:03:46 +000043 {eSettingsNameCompletion, CommandCompletions::SettingsNames},
Greg Clayton5e342f52011-04-13 22:47:15 +000044 {ePlatformPluginCompletion, CommandCompletions::PlatformPluginNames},
45 {eArchitectureCompletion, CommandCompletions::ArchitectureNames},
Jim Ingham802f8b02010-06-30 05:02:46 +000046 {eNoCompletion, NULL} // This one has to be last in the list.
Chris Lattner24943d22010-06-08 16:52:24 +000047};
48
49bool
Greg Clayton63094e02010-06-23 01:19:29 +000050CommandCompletions::InvokeCommonCompletionCallbacks
51(
52 CommandInterpreter &interpreter,
53 uint32_t completion_mask,
54 const char *completion_str,
55 int match_start_point,
56 int max_return_elements,
57 SearchFilter *searcher,
Jim Ingham802f8b02010-06-30 05:02:46 +000058 bool &word_complete,
Greg Clayton63094e02010-06-23 01:19:29 +000059 StringList &matches
60)
Chris Lattner24943d22010-06-08 16:52:24 +000061{
62 bool handled = false;
63
64 if (completion_mask & eCustomCompletion)
65 return false;
66
67 for (int i = 0; ; i++)
68 {
69 if (g_common_completions[i].type == eNoCompletion)
70 break;
71 else if ((g_common_completions[i].type & completion_mask) == g_common_completions[i].type
72 && g_common_completions[i].callback != NULL)
73 {
74 handled = true;
Greg Clayton63094e02010-06-23 01:19:29 +000075 g_common_completions[i].callback (interpreter,
76 completion_str,
Chris Lattner24943d22010-06-08 16:52:24 +000077 match_start_point,
78 max_return_elements,
Chris Lattner24943d22010-06-08 16:52:24 +000079 searcher,
Jim Ingham802f8b02010-06-30 05:02:46 +000080 word_complete,
Chris Lattner24943d22010-06-08 16:52:24 +000081 matches);
82 }
83 }
84 return handled;
85}
86
87int
Greg Clayton63094e02010-06-23 01:19:29 +000088CommandCompletions::SourceFiles
89(
90 CommandInterpreter &interpreter,
91 const char *partial_file_name,
92 int match_start_point,
93 int max_return_elements,
94 SearchFilter *searcher,
Jim Ingham802f8b02010-06-30 05:02:46 +000095 bool &word_complete,
Greg Clayton63094e02010-06-23 01:19:29 +000096 StringList &matches
97)
Chris Lattner24943d22010-06-08 16:52:24 +000098{
Jim Ingham802f8b02010-06-30 05:02:46 +000099 word_complete = true;
Chris Lattner24943d22010-06-08 16:52:24 +0000100 // Find some way to switch "include support files..."
Greg Clayton63094e02010-06-23 01:19:29 +0000101 SourceFileCompleter completer (interpreter,
102 false,
103 partial_file_name,
104 match_start_point,
105 max_return_elements,
Chris Lattner24943d22010-06-08 16:52:24 +0000106 matches);
107
108 if (searcher == NULL)
109 {
Jim Inghamc8332952010-08-26 21:32:51 +0000110 lldb::TargetSP target_sp = interpreter.GetDebugger().GetSelectedTarget();
Chris Lattner24943d22010-06-08 16:52:24 +0000111 SearchFilter null_searcher (target_sp);
112 completer.DoCompletion (&null_searcher);
113 }
114 else
115 {
116 completer.DoCompletion (searcher);
117 }
118 return matches.GetSize();
119}
120
Jim Ingham802f8b02010-06-30 05:02:46 +0000121static int
122DiskFilesOrDirectories
123(
124 const char *partial_file_name,
125 bool only_directories,
126 bool &saw_directory,
127 StringList &matches
128)
129{
130 // I'm going to use the "glob" function with GLOB_TILDE for user directory expansion.
131 // If it is not defined on your host system, you'll need to implement it yourself...
132
133 int partial_name_len = strlen(partial_file_name);
134
135 if (partial_name_len >= PATH_MAX)
136 return matches.GetSize();
137
138 // This copy of the string will be cut up into the directory part, and the remainder. end_ptr
139 // below will point to the place of the remainder in this string. Then when we've resolved the
140 // containing directory, and opened it, we'll read the directory contents and overwrite the
141 // partial_name_copy starting from end_ptr with each of the matches. Thus we will preserve
142 // the form the user originally typed.
143
144 char partial_name_copy[PATH_MAX];
Benjamin Kramerbdbb9af2010-06-30 13:43:47 +0000145 memcpy(partial_name_copy, partial_file_name, partial_name_len);
Jim Ingham802f8b02010-06-30 05:02:46 +0000146 partial_name_copy[partial_name_len] = '\0';
147
Greg Clayton5d187e52011-01-08 20:28:42 +0000148 // We'll need to save a copy of the remainder for comparison, which we do here.
Jim Ingham802f8b02010-06-30 05:02:46 +0000149 char remainder[PATH_MAX];
150
151 // end_ptr will point past the last / in partial_name_copy, or if there is no slash to the beginning of the string.
152 char *end_ptr;
153
154 end_ptr = strrchr(partial_name_copy, '/');
155
156 // This will store the resolved form of the containing directory
157 char containing_part[PATH_MAX];
158
159 if (end_ptr == NULL)
160 {
161 // There's no directory. If the thing begins with a "~" then this is a bare
162 // user name.
163 if (*partial_name_copy == '~')
164 {
165 // Nothing here but the user name. We could just put a slash on the end,
Jim Ingham84a0d332010-07-02 00:45:55 +0000166 // but for completeness sake we'll resolve the user name and only put a slash
Jim Ingham802f8b02010-06-30 05:02:46 +0000167 // on the end if it exists.
Jim Ingham84a0d332010-07-02 00:45:55 +0000168 char resolved_username[PATH_MAX];
Greg Clayton54e7afa2010-07-09 20:39:50 +0000169 size_t resolved_username_len = FileSpec::ResolveUsername (partial_name_copy, resolved_username,
Jim Ingham84a0d332010-07-02 00:45:55 +0000170 sizeof (resolved_username));
171
172 // Not sure how this would happen, a username longer than PATH_MAX? Still...
173 if (resolved_username_len >= sizeof (resolved_username))
174 return matches.GetSize();
Jim Ingham158842c2011-02-08 23:24:09 +0000175 else if (resolved_username_len == 0)
Jim Ingham84a0d332010-07-02 00:45:55 +0000176 {
177 // The user name didn't resolve, let's look in the password database for matches.
178 // The user name database contains duplicates, and is not in alphabetical order, so
179 // we'll use a set to manage that for us.
Jim Ingham158842c2011-02-08 23:24:09 +0000180 FileSpec::ResolvePartialUsername (partial_name_copy, matches);
181 if (matches.GetSize() > 0)
182 saw_directory = true;
Jim Ingham84a0d332010-07-02 00:45:55 +0000183 return matches.GetSize();
Jim Ingham158842c2011-02-08 23:24:09 +0000184 }
185 else
186 {
187 //The thing exists, put a '/' on the end, and return it...
188 // FIXME: complete user names here:
189 partial_name_copy[partial_name_len] = '/';
190 partial_name_copy[partial_name_len+1] = '\0';
191 matches.AppendString(partial_name_copy);
192 saw_directory = true;
193 return matches.GetSize();
194 }
Jim Ingham802f8b02010-06-30 05:02:46 +0000195 }
196 else
197 {
198 // The containing part is the CWD, and the whole string is the remainder.
199 containing_part[0] = '.';
200 containing_part[1] = '\0';
201 strcpy(remainder, partial_name_copy);
202 end_ptr = partial_name_copy;
203 }
204 }
205 else
206 {
207 if (end_ptr == partial_name_copy)
208 {
209 // We're completing a file or directory in the root volume.
210 containing_part[0] = '/';
211 containing_part[1] = '\0';
212 }
213 else
214 {
215 size_t len = end_ptr - partial_name_copy;
216 memcpy(containing_part, partial_name_copy, len);
217 containing_part[len] = '\0';
218 }
219 // Push end_ptr past the final "/" and set remainder.
220 end_ptr++;
221 strcpy(remainder, end_ptr);
222 }
223
Jim Ingham84a0d332010-07-02 00:45:55 +0000224 // 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 +0000225 // result back into the containing_part:
Greg Clayton8da92a72011-02-05 02:27:52 +0000226
Jim Ingham802f8b02010-06-30 05:02:46 +0000227 if (*partial_name_copy == '~')
228 {
Jim Ingham158842c2011-02-08 23:24:09 +0000229 size_t resolved_username_len = FileSpec::ResolveUsername(containing_part,
230 containing_part,
231 sizeof (containing_part));
Jim Ingham802f8b02010-06-30 05:02:46 +0000232 // User name doesn't exist, we're not getting any further...
Greg Clayton099c7972010-07-06 16:11:44 +0000233 if (resolved_username_len == 0 || resolved_username_len >= sizeof (containing_part))
Jim Ingham802f8b02010-06-30 05:02:46 +0000234 return matches.GetSize();
Jim Ingham802f8b02010-06-30 05:02:46 +0000235 }
Greg Clayton8da92a72011-02-05 02:27:52 +0000236
Jim Ingham802f8b02010-06-30 05:02:46 +0000237 // Okay, containing_part is now the directory we want to open and look for files:
Greg Clayton74800612011-02-01 05:15:22 +0000238
239 lldb_utility::CleanUp <DIR *, int> dir_stream (opendir(containing_part), NULL, closedir);
240 if (!dir_stream.is_valid())
Jim Ingham802f8b02010-06-30 05:02:46 +0000241 return matches.GetSize();
Greg Clayton74800612011-02-01 05:15:22 +0000242
Jim Ingham802f8b02010-06-30 05:02:46 +0000243 struct dirent *dirent_buf;
244
245 size_t baselen = end_ptr - partial_name_copy;
246
Greg Clayton74800612011-02-01 05:15:22 +0000247 while ((dirent_buf = readdir(dir_stream.get())) != NULL)
Jim Ingham802f8b02010-06-30 05:02:46 +0000248 {
249 char *name = dirent_buf->d_name;
250
251 // Omit ".", ".." and any . files if the match string doesn't start with .
252 if (name[0] == '.')
253 {
254 if (name[1] == '\0')
255 continue;
256 else if (name[1] == '.' && name[2] == '\0')
257 continue;
258 else if (remainder[0] != '.')
259 continue;
260 }
261
Jim Ingham84a0d332010-07-02 00:45:55 +0000262 // If we found a directory, we put a "/" at the end of the name.
263
Jim Ingham802f8b02010-06-30 05:02:46 +0000264 if (remainder[0] == '\0' || strstr(dirent_buf->d_name, remainder) == name)
265 {
266 if (strlen(name) + baselen >= PATH_MAX)
267 continue;
268
269 strcpy(end_ptr, name);
270
271 bool isa_directory = false;
272 if (dirent_buf->d_type & DT_DIR)
273 isa_directory = true;
274 else if (dirent_buf->d_type & DT_LNK)
275 {
276 struct stat stat_buf;
Jason Molendaf38b76b2011-07-08 00:38:03 +0000277 if ((stat(partial_name_copy, &stat_buf) == 0) && S_ISDIR(stat_buf.st_mode))
Jim Ingham802f8b02010-06-30 05:02:46 +0000278 isa_directory = true;
279 }
280
281 if (isa_directory)
282 {
283 saw_directory = true;
284 size_t len = strlen(partial_name_copy);
285 partial_name_copy[len] = '/';
286 partial_name_copy[len + 1] = '\0';
287 }
288 if (only_directories && !isa_directory)
289 continue;
290 matches.AppendString(partial_name_copy);
291 }
292 }
293
294 return matches.GetSize();
295}
296
297int
298CommandCompletions::DiskFiles
299(
300 CommandInterpreter &interpreter,
301 const char *partial_file_name,
302 int match_start_point,
303 int max_return_elements,
304 SearchFilter *searcher,
305 bool &word_complete,
306 StringList &matches
307)
308{
309
310 int ret_val = DiskFilesOrDirectories (partial_file_name,
311 false,
312 word_complete,
313 matches);
314 word_complete = !word_complete;
315 return ret_val;
316}
317
318int
319CommandCompletions::DiskDirectories
320(
321 CommandInterpreter &interpreter,
322 const char *partial_file_name,
323 int match_start_point,
324 int max_return_elements,
325 SearchFilter *searcher,
326 bool &word_complete,
327 StringList &matches
328)
329{
330 int ret_val = DiskFilesOrDirectories (partial_file_name,
331 true,
332 word_complete,
333 matches);
334 word_complete = false;
335 return ret_val;
336}
337
Chris Lattner24943d22010-06-08 16:52:24 +0000338int
Greg Clayton63094e02010-06-23 01:19:29 +0000339CommandCompletions::Modules
340(
341 CommandInterpreter &interpreter,
342 const char *partial_file_name,
343 int match_start_point,
344 int max_return_elements,
345 SearchFilter *searcher,
Jim Ingham802f8b02010-06-30 05:02:46 +0000346 bool &word_complete,
Greg Clayton63094e02010-06-23 01:19:29 +0000347 StringList &matches
348)
Chris Lattner24943d22010-06-08 16:52:24 +0000349{
Jim Ingham802f8b02010-06-30 05:02:46 +0000350 word_complete = true;
Greg Clayton63094e02010-06-23 01:19:29 +0000351 ModuleCompleter completer (interpreter,
352 partial_file_name,
353 match_start_point,
354 max_return_elements,
355 matches);
356
Chris Lattner24943d22010-06-08 16:52:24 +0000357 if (searcher == NULL)
358 {
Jim Inghamc8332952010-08-26 21:32:51 +0000359 lldb::TargetSP target_sp = interpreter.GetDebugger().GetSelectedTarget();
Chris Lattner24943d22010-06-08 16:52:24 +0000360 SearchFilter null_searcher (target_sp);
361 completer.DoCompletion (&null_searcher);
362 }
363 else
364 {
365 completer.DoCompletion (searcher);
366 }
367 return matches.GetSize();
368}
369
370int
Greg Clayton63094e02010-06-23 01:19:29 +0000371CommandCompletions::Symbols
372(
373 CommandInterpreter &interpreter,
374 const char *partial_file_name,
375 int match_start_point,
376 int max_return_elements,
377 SearchFilter *searcher,
Jim Ingham802f8b02010-06-30 05:02:46 +0000378 bool &word_complete,
Greg Clayton63094e02010-06-23 01:19:29 +0000379 StringList &matches)
Chris Lattner24943d22010-06-08 16:52:24 +0000380{
Jim Ingham802f8b02010-06-30 05:02:46 +0000381 word_complete = true;
Greg Clayton63094e02010-06-23 01:19:29 +0000382 SymbolCompleter completer (interpreter,
383 partial_file_name,
384 match_start_point,
385 max_return_elements,
386 matches);
Chris Lattner24943d22010-06-08 16:52:24 +0000387
388 if (searcher == NULL)
389 {
Jim Inghamc8332952010-08-26 21:32:51 +0000390 lldb::TargetSP target_sp = interpreter.GetDebugger().GetSelectedTarget();
Chris Lattner24943d22010-06-08 16:52:24 +0000391 SearchFilter null_searcher (target_sp);
392 completer.DoCompletion (&null_searcher);
393 }
394 else
395 {
396 completer.DoCompletion (searcher);
397 }
398 return matches.GetSize();
399}
400
Caroline Tice6e4c5ce2010-09-04 00:03:46 +0000401int
402CommandCompletions::SettingsNames (CommandInterpreter &interpreter,
403 const char *partial_setting_name,
404 int match_start_point,
405 int max_return_elements,
406 SearchFilter *searcher,
407 bool &word_complete,
408 StringList &matches)
409{
Greg Clayton73844aa2012-08-22 17:17:09 +0000410 // Cache the full setting name list
411 static StringList g_property_names;
412 if (g_property_names.GetSize() == 0)
413 {
414 // Generate the full setting name list on demand
415 lldb::OptionValuePropertiesSP properties_sp (interpreter.GetDebugger().GetValueProperties());
416 if (properties_sp)
417 {
418 StreamString strm;
419 properties_sp->DumpValue(NULL, strm, OptionValue::eDumpOptionName);
420 const std::string &str = strm.GetString();
421 g_property_names.SplitIntoLines(str.c_str(), str.size());
422 }
423 }
424
425 size_t exact_matches_idx = SIZE_MAX;
426 const size_t num_matches = g_property_names.AutoComplete (partial_setting_name, matches, exact_matches_idx);
Greg Clayton73844aa2012-08-22 17:17:09 +0000427 word_complete = exact_matches_idx != SIZE_MAX;
428 return num_matches;
Caroline Tice6e4c5ce2010-09-04 00:03:46 +0000429}
430
Greg Clayton5e342f52011-04-13 22:47:15 +0000431
432int
433CommandCompletions::PlatformPluginNames (CommandInterpreter &interpreter,
434 const char *partial_name,
435 int match_start_point,
436 int max_return_elements,
437 SearchFilter *searcher,
438 bool &word_complete,
439 lldb_private::StringList &matches)
440{
441 const uint32_t num_matches = PluginManager::AutoCompletePlatformName(partial_name, matches);
442 word_complete = num_matches == 1;
443 return num_matches;
444}
445
446int
447CommandCompletions::ArchitectureNames (CommandInterpreter &interpreter,
448 const char *partial_name,
449 int match_start_point,
450 int max_return_elements,
451 SearchFilter *searcher,
452 bool &word_complete,
453 lldb_private::StringList &matches)
454{
455 const uint32_t num_matches = ArchSpec::AutoComplete (partial_name, matches);
456 word_complete = num_matches == 1;
457 return num_matches;
458}
459
460
Greg Clayton63094e02010-06-23 01:19:29 +0000461CommandCompletions::Completer::Completer
462(
463 CommandInterpreter &interpreter,
Chris Lattner24943d22010-06-08 16:52:24 +0000464 const char *completion_str,
465 int match_start_point,
466 int max_return_elements,
Chris Lattner24943d22010-06-08 16:52:24 +0000467 StringList &matches
468) :
Greg Clayton63094e02010-06-23 01:19:29 +0000469 m_interpreter (interpreter),
Chris Lattner24943d22010-06-08 16:52:24 +0000470 m_completion_str (completion_str),
471 m_match_start_point (match_start_point),
472 m_max_return_elements (max_return_elements),
Chris Lattner24943d22010-06-08 16:52:24 +0000473 m_matches (matches)
474{
475}
476
477CommandCompletions::Completer::~Completer ()
478{
479
480}
481
482//----------------------------------------------------------------------
483// SourceFileCompleter
484//----------------------------------------------------------------------
485
Greg Clayton63094e02010-06-23 01:19:29 +0000486CommandCompletions::SourceFileCompleter::SourceFileCompleter
487(
488 CommandInterpreter &interpreter,
Chris Lattner24943d22010-06-08 16:52:24 +0000489 bool include_support_files,
490 const char *completion_str,
491 int match_start_point,
492 int max_return_elements,
Chris Lattner24943d22010-06-08 16:52:24 +0000493 StringList &matches
494) :
Greg Clayton63094e02010-06-23 01:19:29 +0000495 CommandCompletions::Completer (interpreter, completion_str, match_start_point, max_return_elements, matches),
Chris Lattner24943d22010-06-08 16:52:24 +0000496 m_include_support_files (include_support_files),
497 m_matching_files()
498{
Greg Clayton537a7a82010-10-20 20:54:39 +0000499 FileSpec partial_spec (m_completion_str.c_str(), false);
Chris Lattner24943d22010-06-08 16:52:24 +0000500 m_file_name = partial_spec.GetFilename().GetCString();
501 m_dir_name = partial_spec.GetDirectory().GetCString();
502}
503
504Searcher::Depth
505CommandCompletions::SourceFileCompleter::GetDepth()
506{
507 return eDepthCompUnit;
508}
509
510Searcher::CallbackReturn
511CommandCompletions::SourceFileCompleter::SearchCallback (
512 SearchFilter &filter,
513 SymbolContext &context,
514 Address *addr,
515 bool complete
516)
517{
518 if (context.comp_unit != NULL)
519 {
520 if (m_include_support_files)
521 {
522 FileSpecList supporting_files = context.comp_unit->GetSupportFiles();
523 for (size_t sfiles = 0; sfiles < supporting_files.GetSize(); sfiles++)
524 {
525 const FileSpec &sfile_spec = supporting_files.GetFileSpecAtIndex(sfiles);
526 const char *sfile_file_name = sfile_spec.GetFilename().GetCString();
527 const char *sfile_dir_name = sfile_spec.GetFilename().GetCString();
528 bool match = false;
529 if (m_file_name && sfile_file_name
530 && strstr (sfile_file_name, m_file_name) == sfile_file_name)
531 match = true;
532 if (match && m_dir_name && sfile_dir_name
533 && strstr (sfile_dir_name, m_dir_name) != sfile_dir_name)
534 match = false;
535
536 if (match)
537 {
538 m_matching_files.AppendIfUnique(sfile_spec);
539 }
540 }
541
542 }
543 else
544 {
545 const char *cur_file_name = context.comp_unit->GetFilename().GetCString();
546 const char *cur_dir_name = context.comp_unit->GetDirectory().GetCString();
547
548 bool match = false;
549 if (m_file_name && cur_file_name
550 && strstr (cur_file_name, m_file_name) == cur_file_name)
551 match = true;
552
553 if (match && m_dir_name && cur_dir_name
554 && strstr (cur_dir_name, m_dir_name) != cur_dir_name)
555 match = false;
556
557 if (match)
558 {
559 m_matching_files.AppendIfUnique(context.comp_unit);
560 }
561 }
562 }
563 return Searcher::eCallbackReturnContinue;
564}
565
566size_t
567CommandCompletions::SourceFileCompleter::DoCompletion (SearchFilter *filter)
568{
569 filter->Search (*this);
570 // Now convert the filelist to completions:
571 for (size_t i = 0; i < m_matching_files.GetSize(); i++)
572 {
573 m_matches.AppendString (m_matching_files.GetFileSpecAtIndex(i).GetFilename().GetCString());
574 }
575 return m_matches.GetSize();
576
577}
578
579//----------------------------------------------------------------------
580// SymbolCompleter
581//----------------------------------------------------------------------
582
583static bool
584regex_chars (const char comp)
585{
586 if (comp == '[' || comp == ']' || comp == '(' || comp == ')')
587 return true;
588 else
589 return false;
590}
Greg Clayton63094e02010-06-23 01:19:29 +0000591CommandCompletions::SymbolCompleter::SymbolCompleter
592(
593 CommandInterpreter &interpreter,
Chris Lattner24943d22010-06-08 16:52:24 +0000594 const char *completion_str,
595 int match_start_point,
596 int max_return_elements,
Chris Lattner24943d22010-06-08 16:52:24 +0000597 StringList &matches
598) :
Greg Clayton63094e02010-06-23 01:19:29 +0000599 CommandCompletions::Completer (interpreter, completion_str, match_start_point, max_return_elements, matches)
Chris Lattner24943d22010-06-08 16:52:24 +0000600{
601 std::string regex_str ("^");
602 regex_str.append(completion_str);
603 regex_str.append(".*");
604 std::string::iterator pos;
605
606 pos = find_if(regex_str.begin(), regex_str.end(), regex_chars);
607 while (pos < regex_str.end()) {
608 pos = regex_str.insert(pos, '\\');
609 pos += 2;
610 pos = find_if(pos, regex_str.end(), regex_chars);
611 }
612 m_regex.Compile(regex_str.c_str());
613}
614
615Searcher::Depth
616CommandCompletions::SymbolCompleter::GetDepth()
617{
618 return eDepthModule;
619}
620
621Searcher::CallbackReturn
622CommandCompletions::SymbolCompleter::SearchCallback (
623 SearchFilter &filter,
624 SymbolContext &context,
625 Address *addr,
626 bool complete
627)
628{
Greg Clayton28d5fcc2011-01-27 06:44:37 +0000629 if (context.module_sp)
Chris Lattner24943d22010-06-08 16:52:24 +0000630 {
Greg Clayton28d5fcc2011-01-27 06:44:37 +0000631 SymbolContextList sc_list;
632 const bool include_symbols = true;
Sean Callanan302d78c2012-02-10 22:52:19 +0000633 const bool include_inlines = true;
Greg Clayton28d5fcc2011-01-27 06:44:37 +0000634 const bool append = true;
Sean Callanan302d78c2012-02-10 22:52:19 +0000635 context.module_sp->FindFunctions (m_regex, include_symbols, include_inlines, append, sc_list);
Chris Lattner24943d22010-06-08 16:52:24 +0000636
637 SymbolContext sc;
638 // Now add the functions & symbols to the list - only add if unique:
Greg Clayton28d5fcc2011-01-27 06:44:37 +0000639 for (uint32_t i = 0; i < sc_list.GetSize(); i++)
Chris Lattner24943d22010-06-08 16:52:24 +0000640 {
Greg Clayton28d5fcc2011-01-27 06:44:37 +0000641 if (sc_list.GetContextAtIndex(i, sc))
Chris Lattner24943d22010-06-08 16:52:24 +0000642 {
Jim Inghama7d89512011-09-27 19:48:20 +0000643 ConstString func_name = sc.GetFunctionName(Mangled::ePreferDemangled);
644 if (!func_name.IsEmpty())
645 m_match_set.insert (func_name);
Chris Lattner24943d22010-06-08 16:52:24 +0000646 }
647 }
648 }
649 return Searcher::eCallbackReturnContinue;
650}
651
652size_t
653CommandCompletions::SymbolCompleter::DoCompletion (SearchFilter *filter)
654{
655 filter->Search (*this);
656 collection::iterator pos = m_match_set.begin(), end = m_match_set.end();
657 for (pos = m_match_set.begin(); pos != end; pos++)
658 m_matches.AppendString((*pos).GetCString());
659
660 return m_matches.GetSize();
661}
662
663//----------------------------------------------------------------------
664// ModuleCompleter
665//----------------------------------------------------------------------
Greg Clayton63094e02010-06-23 01:19:29 +0000666CommandCompletions::ModuleCompleter::ModuleCompleter
667(
668 CommandInterpreter &interpreter,
Chris Lattner24943d22010-06-08 16:52:24 +0000669 const char *completion_str,
670 int match_start_point,
671 int max_return_elements,
Chris Lattner24943d22010-06-08 16:52:24 +0000672 StringList &matches
673) :
Greg Clayton63094e02010-06-23 01:19:29 +0000674 CommandCompletions::Completer (interpreter, completion_str, match_start_point, max_return_elements, matches)
Chris Lattner24943d22010-06-08 16:52:24 +0000675{
Greg Clayton537a7a82010-10-20 20:54:39 +0000676 FileSpec partial_spec (m_completion_str.c_str(), false);
Chris Lattner24943d22010-06-08 16:52:24 +0000677 m_file_name = partial_spec.GetFilename().GetCString();
678 m_dir_name = partial_spec.GetDirectory().GetCString();
679}
680
681Searcher::Depth
682CommandCompletions::ModuleCompleter::GetDepth()
683{
684 return eDepthModule;
685}
686
687Searcher::CallbackReturn
688CommandCompletions::ModuleCompleter::SearchCallback (
689 SearchFilter &filter,
690 SymbolContext &context,
691 Address *addr,
692 bool complete
693)
694{
Greg Clayton6e0101c2011-09-17 06:21:20 +0000695 if (context.module_sp)
Chris Lattner24943d22010-06-08 16:52:24 +0000696 {
697 const char *cur_file_name = context.module_sp->GetFileSpec().GetFilename().GetCString();
698 const char *cur_dir_name = context.module_sp->GetFileSpec().GetDirectory().GetCString();
699
700 bool match = false;
701 if (m_file_name && cur_file_name
702 && strstr (cur_file_name, m_file_name) == cur_file_name)
703 match = true;
704
705 if (match && m_dir_name && cur_dir_name
706 && strstr (cur_dir_name, m_dir_name) != cur_dir_name)
707 match = false;
708
709 if (match)
710 {
711 m_matches.AppendString (cur_file_name);
712 }
713 }
714 return Searcher::eCallbackReturnContinue;
715}
716
717size_t
718CommandCompletions::ModuleCompleter::DoCompletion (SearchFilter *filter)
719{
720 filter->Search (*this);
721 return m_matches.GetSize();
722}