1c9af18a5SGreg Clayton //===-- CommandCompletions.cpp ----------------------------------*- C++ -*-===//
2c9af18a5SGreg Clayton //
3c9af18a5SGreg Clayton //                     The LLVM Compiler Infrastructure
4c9af18a5SGreg Clayton //
5c9af18a5SGreg Clayton // This file is distributed under the University of Illinois Open Source
6c9af18a5SGreg Clayton // License. See LICENSE.TXT for details.
7c9af18a5SGreg Clayton //
8c9af18a5SGreg Clayton //===----------------------------------------------------------------------===//
9c9af18a5SGreg Clayton 
10c9af18a5SGreg Clayton 
11c9af18a5SGreg Clayton // C Includes
12*558ce124SJim Ingham #include <sys/stat.h>
13*558ce124SJim Ingham #include <dirent.h>
14*558ce124SJim Ingham #include <libgen.h>
15*558ce124SJim Ingham #include <glob.h>
16*558ce124SJim Ingham 
17c9af18a5SGreg Clayton // C++ Includes
18c9af18a5SGreg Clayton // Other libraries and framework includes
19c9af18a5SGreg Clayton // Project includes
2040af72e1SJim Ingham #include "lldb/Interpreter/Args.h"
21c9af18a5SGreg Clayton #include "lldb/Interpreter/CommandInterpreter.h"
22c9af18a5SGreg Clayton #include "lldb/Core/FileSpecList.h"
23c9af18a5SGreg Clayton #include "lldb/Target/Target.h"
24c9af18a5SGreg Clayton #include "lldb/Interpreter/CommandCompletions.h"
25c9af18a5SGreg Clayton 
26c9af18a5SGreg Clayton 
27c9af18a5SGreg Clayton using namespace lldb_private;
28c9af18a5SGreg Clayton 
29c9af18a5SGreg Clayton CommandCompletions::CommonCompletionElement
30c9af18a5SGreg Clayton CommandCompletions::g_common_completions[] =
31c9af18a5SGreg Clayton {
32c9af18a5SGreg Clayton     {eCustomCompletion,          NULL},
33c9af18a5SGreg Clayton     {eSourceFileCompletion,      CommandCompletions::SourceFiles},
34*558ce124SJim Ingham     {eDiskFileCompletion,        CommandCompletions::DiskFiles},
35*558ce124SJim Ingham     {eDiskDirectoryCompletion,   CommandCompletions::DiskDirectories},
36c9af18a5SGreg Clayton     {eSymbolCompletion,          CommandCompletions::Symbols},
37c9af18a5SGreg Clayton     {eModuleCompletion,          CommandCompletions::Modules},
38c9af18a5SGreg Clayton     {eNoCompletion,              NULL}      // This one has to be last in the list.
39c9af18a5SGreg Clayton };
40c9af18a5SGreg Clayton 
41c9af18a5SGreg Clayton bool
426611103cSGreg Clayton CommandCompletions::InvokeCommonCompletionCallbacks
436611103cSGreg Clayton (
446611103cSGreg Clayton     CommandInterpreter &interpreter,
456611103cSGreg Clayton     uint32_t completion_mask,
46c9af18a5SGreg Clayton     const char *completion_str,
47c9af18a5SGreg Clayton     int match_start_point,
48c9af18a5SGreg Clayton     int max_return_elements,
49c9af18a5SGreg Clayton     SearchFilter *searcher,
50*558ce124SJim Ingham     bool &word_complete,
516611103cSGreg Clayton     StringList &matches
526611103cSGreg Clayton )
53c9af18a5SGreg Clayton {
54c9af18a5SGreg Clayton     bool handled = false;
55c9af18a5SGreg Clayton 
56c9af18a5SGreg Clayton     if (completion_mask & eCustomCompletion)
57c9af18a5SGreg Clayton         return false;
58c9af18a5SGreg Clayton 
59c9af18a5SGreg Clayton     for (int i = 0; ; i++)
60c9af18a5SGreg Clayton     {
61c9af18a5SGreg Clayton         if (g_common_completions[i].type == eNoCompletion)
62c9af18a5SGreg Clayton             break;
63c9af18a5SGreg Clayton          else if ((g_common_completions[i].type & completion_mask) == g_common_completions[i].type
64c9af18a5SGreg Clayton                    && g_common_completions[i].callback != NULL)
65c9af18a5SGreg Clayton          {
66c9af18a5SGreg Clayton             handled = true;
676611103cSGreg Clayton             g_common_completions[i].callback (interpreter,
686611103cSGreg Clayton                                               completion_str,
69c9af18a5SGreg Clayton                                               match_start_point,
70c9af18a5SGreg Clayton                                               max_return_elements,
71c9af18a5SGreg Clayton                                               searcher,
72*558ce124SJim Ingham                                               word_complete,
73c9af18a5SGreg Clayton                                               matches);
74c9af18a5SGreg Clayton         }
75c9af18a5SGreg Clayton     }
76c9af18a5SGreg Clayton     return handled;
77c9af18a5SGreg Clayton }
78c9af18a5SGreg Clayton 
79c9af18a5SGreg Clayton int
806611103cSGreg Clayton CommandCompletions::SourceFiles
816611103cSGreg Clayton (
826611103cSGreg Clayton     CommandInterpreter &interpreter,
836611103cSGreg Clayton     const char *partial_file_name,
84c9af18a5SGreg Clayton     int match_start_point,
85c9af18a5SGreg Clayton     int max_return_elements,
86c9af18a5SGreg Clayton     SearchFilter *searcher,
87*558ce124SJim Ingham     bool &word_complete,
886611103cSGreg Clayton     StringList &matches
896611103cSGreg Clayton )
90c9af18a5SGreg Clayton {
91*558ce124SJim Ingham     word_complete = true;
92c9af18a5SGreg Clayton     // Find some way to switch "include support files..."
936611103cSGreg Clayton     SourceFileCompleter completer (interpreter,
946611103cSGreg Clayton                                    false,
956611103cSGreg Clayton                                    partial_file_name,
966611103cSGreg Clayton                                    match_start_point,
976611103cSGreg Clayton                                    max_return_elements,
98c9af18a5SGreg Clayton                                    matches);
99c9af18a5SGreg Clayton 
100c9af18a5SGreg Clayton     if (searcher == NULL)
101c9af18a5SGreg Clayton     {
1026611103cSGreg Clayton         lldb::TargetSP target_sp = interpreter.GetDebugger().GetCurrentTarget();
103c9af18a5SGreg Clayton         SearchFilter null_searcher (target_sp);
104c9af18a5SGreg Clayton         completer.DoCompletion (&null_searcher);
105c9af18a5SGreg Clayton     }
106c9af18a5SGreg Clayton     else
107c9af18a5SGreg Clayton     {
108c9af18a5SGreg Clayton         completer.DoCompletion (searcher);
109c9af18a5SGreg Clayton     }
110c9af18a5SGreg Clayton     return matches.GetSize();
111c9af18a5SGreg Clayton }
112c9af18a5SGreg Clayton 
113*558ce124SJim Ingham static int
114*558ce124SJim Ingham DiskFilesOrDirectories
115*558ce124SJim Ingham (
116*558ce124SJim Ingham     const char *partial_file_name,
117*558ce124SJim Ingham     bool only_directories,
118*558ce124SJim Ingham     bool &saw_directory,
119*558ce124SJim Ingham     StringList &matches
120*558ce124SJim Ingham )
121*558ce124SJim Ingham {
122*558ce124SJim Ingham     // I'm going to  use the "glob" function with GLOB_TILDE for user directory expansion.
123*558ce124SJim Ingham     // If it is not defined on your host system, you'll need to implement it yourself...
124*558ce124SJim Ingham 
125*558ce124SJim Ingham     int partial_name_len = strlen(partial_file_name);
126*558ce124SJim Ingham 
127*558ce124SJim Ingham     if (partial_name_len >= PATH_MAX)
128*558ce124SJim Ingham         return matches.GetSize();
129*558ce124SJim Ingham 
130*558ce124SJim Ingham     // This copy of the string will be cut up into the directory part, and the remainder.  end_ptr
131*558ce124SJim Ingham     // below will point to the place of the remainder in this string.  Then when we've resolved the
132*558ce124SJim Ingham     // containing directory, and opened it, we'll read the directory contents and overwrite the
133*558ce124SJim Ingham     // partial_name_copy starting from end_ptr with each of the matches.  Thus we will preserve
134*558ce124SJim Ingham     // the form the user originally typed.
135*558ce124SJim Ingham 
136*558ce124SJim Ingham     char partial_name_copy[PATH_MAX];
137*558ce124SJim Ingham     bcopy (partial_file_name, partial_name_copy, partial_name_len);
138*558ce124SJim Ingham     partial_name_copy[partial_name_len] = '\0';
139*558ce124SJim Ingham 
140*558ce124SJim Ingham     // We'll need to save a copy of the remainder for comparision, which we do here.
141*558ce124SJim Ingham     char remainder[PATH_MAX];
142*558ce124SJim Ingham 
143*558ce124SJim Ingham     // end_ptr will point past the last / in partial_name_copy, or if there is no slash to the beginning of the string.
144*558ce124SJim Ingham     char *end_ptr;
145*558ce124SJim Ingham 
146*558ce124SJim Ingham     end_ptr = strrchr(partial_name_copy, '/');
147*558ce124SJim Ingham 
148*558ce124SJim Ingham     // This will store the resolved form of the containing directory
149*558ce124SJim Ingham     char containing_part[PATH_MAX];
150*558ce124SJim Ingham 
151*558ce124SJim Ingham     if (end_ptr == NULL)
152*558ce124SJim Ingham     {
153*558ce124SJim Ingham         // There's no directory.  If the thing begins with a "~" then this is a bare
154*558ce124SJim Ingham         // user name.
155*558ce124SJim Ingham         if (*partial_name_copy == '~')
156*558ce124SJim Ingham         {
157*558ce124SJim Ingham             // Nothing here but the user name.  We could just put a slash on the end,
158*558ce124SJim Ingham             // but for completeness sake we'll glob the user name and only put a slash
159*558ce124SJim Ingham             // on the end if it exists.
160*558ce124SJim Ingham            glob_t glob_buf;
161*558ce124SJim Ingham            if (glob (partial_name_copy, GLOB_TILDE, NULL, &glob_buf) != 0)
162*558ce124SJim Ingham                return matches.GetSize();
163*558ce124SJim Ingham 
164*558ce124SJim Ingham            //The thing exists, put a '/' on the end, and return it...
165*558ce124SJim Ingham            // FIXME: complete user names here:
166*558ce124SJim Ingham            partial_name_copy[partial_name_len] = '/';
167*558ce124SJim Ingham            partial_name_copy[partial_name_len+1] = '\0';
168*558ce124SJim Ingham            matches.AppendString(partial_name_copy);
169*558ce124SJim Ingham            globfree(&glob_buf);
170*558ce124SJim Ingham            saw_directory == true;
171*558ce124SJim Ingham            return matches.GetSize();
172*558ce124SJim Ingham         }
173*558ce124SJim Ingham         else
174*558ce124SJim Ingham         {
175*558ce124SJim Ingham             // The containing part is the CWD, and the whole string is the remainder.
176*558ce124SJim Ingham             containing_part[0] = '.';
177*558ce124SJim Ingham             containing_part[1] = '\0';
178*558ce124SJim Ingham             strcpy(remainder, partial_name_copy);
179*558ce124SJim Ingham             end_ptr = partial_name_copy;
180*558ce124SJim Ingham         }
181*558ce124SJim Ingham     }
182*558ce124SJim Ingham     else
183*558ce124SJim Ingham     {
184*558ce124SJim Ingham         if (end_ptr == partial_name_copy)
185*558ce124SJim Ingham         {
186*558ce124SJim Ingham             // We're completing a file or directory in the root volume.
187*558ce124SJim Ingham             containing_part[0] = '/';
188*558ce124SJim Ingham             containing_part[1] = '\0';
189*558ce124SJim Ingham         }
190*558ce124SJim Ingham         else
191*558ce124SJim Ingham         {
192*558ce124SJim Ingham             size_t len = end_ptr - partial_name_copy;
193*558ce124SJim Ingham             memcpy(containing_part, partial_name_copy, len);
194*558ce124SJim Ingham             containing_part[len] = '\0';
195*558ce124SJim Ingham         }
196*558ce124SJim Ingham         // Push end_ptr past the final "/" and set remainder.
197*558ce124SJim Ingham         end_ptr++;
198*558ce124SJim Ingham         strcpy(remainder, end_ptr);
199*558ce124SJim Ingham     }
200*558ce124SJim Ingham 
201*558ce124SJim Ingham     // Look for a user name in the containing part, and if it's there, glob containing_part and stick the
202*558ce124SJim Ingham     // result back into the containing_part:
203*558ce124SJim Ingham 
204*558ce124SJim Ingham     if (*partial_name_copy == '~')
205*558ce124SJim Ingham     {
206*558ce124SJim Ingham         glob_t glob_buf;
207*558ce124SJim Ingham 
208*558ce124SJim Ingham         // User name doesn't exist, we're not getting any further...
209*558ce124SJim Ingham         if (glob (containing_part, GLOB_TILDE, NULL, &glob_buf) != 0)
210*558ce124SJim Ingham             return matches.GetSize();
211*558ce124SJim Ingham 
212*558ce124SJim Ingham         if (glob_buf.gl_pathc != 1)
213*558ce124SJim Ingham         {
214*558ce124SJim Ingham             // I'm not really sure how this would happen?
215*558ce124SJim Ingham             globfree(&glob_buf);
216*558ce124SJim Ingham             return matches.GetSize();
217*558ce124SJim Ingham         }
218*558ce124SJim Ingham         strcpy(containing_part, glob_buf.gl_pathv[0]);
219*558ce124SJim Ingham         globfree(&glob_buf);
220*558ce124SJim Ingham     }
221*558ce124SJim Ingham 
222*558ce124SJim Ingham     // Okay, containing_part is now the directory we want to open and look for files:
223*558ce124SJim Ingham 
224*558ce124SJim Ingham     DIR *dir_stream;
225*558ce124SJim Ingham 
226*558ce124SJim Ingham     dir_stream = opendir(containing_part);
227*558ce124SJim Ingham     if (dir_stream == NULL)
228*558ce124SJim Ingham         return matches.GetSize();
229*558ce124SJim Ingham 
230*558ce124SJim Ingham     struct dirent *dirent_buf;
231*558ce124SJim Ingham 
232*558ce124SJim Ingham     size_t baselen = end_ptr - partial_name_copy;
233*558ce124SJim Ingham 
234*558ce124SJim Ingham     while ((dirent_buf = readdir(dir_stream)) != NULL)
235*558ce124SJim Ingham     {
236*558ce124SJim Ingham         char *name = dirent_buf->d_name;
237*558ce124SJim Ingham 
238*558ce124SJim Ingham         // Omit ".", ".." and any . files if the match string doesn't start with .
239*558ce124SJim Ingham         if (name[0] == '.')
240*558ce124SJim Ingham         {
241*558ce124SJim Ingham             if (name[1] == '\0')
242*558ce124SJim Ingham                 continue;
243*558ce124SJim Ingham             else if (name[1] == '.' && name[2] == '\0')
244*558ce124SJim Ingham                 continue;
245*558ce124SJim Ingham             else if (remainder[0] != '.')
246*558ce124SJim Ingham                 continue;
247*558ce124SJim Ingham         }
248*558ce124SJim Ingham 
249*558ce124SJim Ingham         if (remainder[0] == '\0' || strstr(dirent_buf->d_name, remainder) == name)
250*558ce124SJim Ingham         {
251*558ce124SJim Ingham             if (strlen(name) + baselen >= PATH_MAX)
252*558ce124SJim Ingham                 continue;
253*558ce124SJim Ingham 
254*558ce124SJim Ingham             strcpy(end_ptr, name);
255*558ce124SJim Ingham 
256*558ce124SJim Ingham             bool isa_directory = false;
257*558ce124SJim Ingham             if (dirent_buf->d_type & DT_DIR)
258*558ce124SJim Ingham                 isa_directory = true;
259*558ce124SJim Ingham             else if (dirent_buf->d_type & DT_LNK)
260*558ce124SJim Ingham             {
261*558ce124SJim Ingham                 struct stat stat_buf;
262*558ce124SJim Ingham                 if ((stat(partial_name_copy, &stat_buf) == 0) && (stat_buf.st_mode & S_IFDIR))
263*558ce124SJim Ingham                     isa_directory = true;
264*558ce124SJim Ingham             }
265*558ce124SJim Ingham 
266*558ce124SJim Ingham             if (isa_directory)
267*558ce124SJim Ingham             {
268*558ce124SJim Ingham                 saw_directory = true;
269*558ce124SJim Ingham                 size_t len = strlen(partial_name_copy);
270*558ce124SJim Ingham                 partial_name_copy[len] = '/';
271*558ce124SJim Ingham                 partial_name_copy[len + 1] = '\0';
272*558ce124SJim Ingham             }
273*558ce124SJim Ingham             if (only_directories && !isa_directory)
274*558ce124SJim Ingham                 continue;
275*558ce124SJim Ingham             matches.AppendString(partial_name_copy);
276*558ce124SJim Ingham         }
277*558ce124SJim Ingham     }
278*558ce124SJim Ingham 
279*558ce124SJim Ingham     return matches.GetSize();
280*558ce124SJim Ingham }
281*558ce124SJim Ingham 
282*558ce124SJim Ingham int
283*558ce124SJim Ingham CommandCompletions::DiskFiles
284*558ce124SJim Ingham (
285*558ce124SJim Ingham     CommandInterpreter &interpreter,
286*558ce124SJim Ingham     const char *partial_file_name,
287*558ce124SJim Ingham     int match_start_point,
288*558ce124SJim Ingham     int max_return_elements,
289*558ce124SJim Ingham     SearchFilter *searcher,
290*558ce124SJim Ingham     bool &word_complete,
291*558ce124SJim Ingham     StringList &matches
292*558ce124SJim Ingham )
293*558ce124SJim Ingham {
294*558ce124SJim Ingham 
295*558ce124SJim Ingham     int ret_val = DiskFilesOrDirectories (partial_file_name,
296*558ce124SJim Ingham                                           false,
297*558ce124SJim Ingham                                           word_complete,
298*558ce124SJim Ingham                                           matches);
299*558ce124SJim Ingham     word_complete = !word_complete;
300*558ce124SJim Ingham     return ret_val;
301*558ce124SJim Ingham }
302*558ce124SJim Ingham 
303*558ce124SJim Ingham int
304*558ce124SJim Ingham CommandCompletions::DiskDirectories
305*558ce124SJim Ingham (
306*558ce124SJim Ingham     CommandInterpreter &interpreter,
307*558ce124SJim Ingham     const char *partial_file_name,
308*558ce124SJim Ingham     int match_start_point,
309*558ce124SJim Ingham     int max_return_elements,
310*558ce124SJim Ingham     SearchFilter *searcher,
311*558ce124SJim Ingham     bool &word_complete,
312*558ce124SJim Ingham     StringList &matches
313*558ce124SJim Ingham )
314*558ce124SJim Ingham {
315*558ce124SJim Ingham     int ret_val =  DiskFilesOrDirectories (partial_file_name,
316*558ce124SJim Ingham                                            true,
317*558ce124SJim Ingham                                            word_complete,
318*558ce124SJim Ingham                                            matches);
319*558ce124SJim Ingham     word_complete = false;
320*558ce124SJim Ingham     return ret_val;
321*558ce124SJim Ingham }
322*558ce124SJim Ingham 
323c9af18a5SGreg Clayton int
3246611103cSGreg Clayton CommandCompletions::Modules
3256611103cSGreg Clayton (
3266611103cSGreg Clayton     CommandInterpreter &interpreter,
3276611103cSGreg Clayton     const char *partial_file_name,
328c9af18a5SGreg Clayton     int match_start_point,
329c9af18a5SGreg Clayton     int max_return_elements,
330c9af18a5SGreg Clayton     SearchFilter *searcher,
331*558ce124SJim Ingham     bool &word_complete,
3326611103cSGreg Clayton     StringList &matches
3336611103cSGreg Clayton )
334c9af18a5SGreg Clayton {
335*558ce124SJim Ingham     word_complete = true;
3366611103cSGreg Clayton     ModuleCompleter completer (interpreter,
3376611103cSGreg Clayton                                partial_file_name,
3386611103cSGreg Clayton                                match_start_point,
3396611103cSGreg Clayton                                max_return_elements,
3406611103cSGreg Clayton                                matches);
341c9af18a5SGreg Clayton 
342c9af18a5SGreg Clayton     if (searcher == NULL)
343c9af18a5SGreg Clayton     {
3446611103cSGreg Clayton         lldb::TargetSP target_sp = interpreter.GetDebugger().GetCurrentTarget();
345c9af18a5SGreg Clayton         SearchFilter null_searcher (target_sp);
346c9af18a5SGreg Clayton         completer.DoCompletion (&null_searcher);
347c9af18a5SGreg Clayton     }
348c9af18a5SGreg Clayton     else
349c9af18a5SGreg Clayton     {
350c9af18a5SGreg Clayton         completer.DoCompletion (searcher);
351c9af18a5SGreg Clayton     }
352c9af18a5SGreg Clayton     return matches.GetSize();
353c9af18a5SGreg Clayton }
354c9af18a5SGreg Clayton 
355c9af18a5SGreg Clayton int
3566611103cSGreg Clayton CommandCompletions::Symbols
3576611103cSGreg Clayton (
3586611103cSGreg Clayton     CommandInterpreter &interpreter,
3596611103cSGreg Clayton     const char *partial_file_name,
360c9af18a5SGreg Clayton     int match_start_point,
361c9af18a5SGreg Clayton     int max_return_elements,
362c9af18a5SGreg Clayton     SearchFilter *searcher,
363*558ce124SJim Ingham     bool &word_complete,
3646611103cSGreg Clayton     StringList &matches)
365c9af18a5SGreg Clayton {
366*558ce124SJim Ingham     word_complete = true;
3676611103cSGreg Clayton     SymbolCompleter completer (interpreter,
3686611103cSGreg Clayton                                partial_file_name,
3696611103cSGreg Clayton                                match_start_point,
3706611103cSGreg Clayton                                max_return_elements,
3716611103cSGreg Clayton                                matches);
372c9af18a5SGreg Clayton 
373c9af18a5SGreg Clayton     if (searcher == NULL)
374c9af18a5SGreg Clayton     {
3756611103cSGreg Clayton         lldb::TargetSP target_sp = interpreter.GetDebugger().GetCurrentTarget();
376c9af18a5SGreg Clayton         SearchFilter null_searcher (target_sp);
377c9af18a5SGreg Clayton         completer.DoCompletion (&null_searcher);
378c9af18a5SGreg Clayton     }
379c9af18a5SGreg Clayton     else
380c9af18a5SGreg Clayton     {
381c9af18a5SGreg Clayton         completer.DoCompletion (searcher);
382c9af18a5SGreg Clayton     }
383c9af18a5SGreg Clayton     return matches.GetSize();
384c9af18a5SGreg Clayton }
385c9af18a5SGreg Clayton 
3866611103cSGreg Clayton CommandCompletions::Completer::Completer
3876611103cSGreg Clayton (
3886611103cSGreg Clayton     CommandInterpreter &interpreter,
389c9af18a5SGreg Clayton     const char *completion_str,
390c9af18a5SGreg Clayton     int match_start_point,
391c9af18a5SGreg Clayton     int max_return_elements,
392c9af18a5SGreg Clayton     StringList &matches
393c9af18a5SGreg Clayton ) :
3946611103cSGreg Clayton     m_interpreter (interpreter),
395c9af18a5SGreg Clayton     m_completion_str (completion_str),
396c9af18a5SGreg Clayton     m_match_start_point (match_start_point),
397c9af18a5SGreg Clayton     m_max_return_elements (max_return_elements),
398c9af18a5SGreg Clayton     m_matches (matches)
399c9af18a5SGreg Clayton {
400c9af18a5SGreg Clayton }
401c9af18a5SGreg Clayton 
402c9af18a5SGreg Clayton CommandCompletions::Completer::~Completer ()
403c9af18a5SGreg Clayton {
404c9af18a5SGreg Clayton 
405c9af18a5SGreg Clayton }
406c9af18a5SGreg Clayton 
407c9af18a5SGreg Clayton //----------------------------------------------------------------------
408c9af18a5SGreg Clayton // SourceFileCompleter
409c9af18a5SGreg Clayton //----------------------------------------------------------------------
410c9af18a5SGreg Clayton 
4116611103cSGreg Clayton CommandCompletions::SourceFileCompleter::SourceFileCompleter
4126611103cSGreg Clayton (
4136611103cSGreg Clayton     CommandInterpreter &interpreter,
414c9af18a5SGreg Clayton     bool include_support_files,
415c9af18a5SGreg Clayton     const char *completion_str,
416c9af18a5SGreg Clayton     int match_start_point,
417c9af18a5SGreg Clayton     int max_return_elements,
418c9af18a5SGreg Clayton     StringList &matches
419c9af18a5SGreg Clayton ) :
4206611103cSGreg Clayton     CommandCompletions::Completer (interpreter, completion_str, match_start_point, max_return_elements, matches),
421c9af18a5SGreg Clayton     m_include_support_files (include_support_files),
422c9af18a5SGreg Clayton     m_matching_files()
423c9af18a5SGreg Clayton {
424c9af18a5SGreg Clayton     FileSpec partial_spec (m_completion_str.c_str());
425c9af18a5SGreg Clayton     m_file_name = partial_spec.GetFilename().GetCString();
426c9af18a5SGreg Clayton     m_dir_name = partial_spec.GetDirectory().GetCString();
427c9af18a5SGreg Clayton }
428c9af18a5SGreg Clayton 
429c9af18a5SGreg Clayton Searcher::Depth
430c9af18a5SGreg Clayton CommandCompletions::SourceFileCompleter::GetDepth()
431c9af18a5SGreg Clayton {
432c9af18a5SGreg Clayton     return eDepthCompUnit;
433c9af18a5SGreg Clayton }
434c9af18a5SGreg Clayton 
435c9af18a5SGreg Clayton Searcher::CallbackReturn
436c9af18a5SGreg Clayton CommandCompletions::SourceFileCompleter::SearchCallback (
437c9af18a5SGreg Clayton     SearchFilter &filter,
438c9af18a5SGreg Clayton     SymbolContext &context,
439c9af18a5SGreg Clayton     Address *addr,
440c9af18a5SGreg Clayton     bool complete
441c9af18a5SGreg Clayton )
442c9af18a5SGreg Clayton {
443c9af18a5SGreg Clayton     if (context.comp_unit != NULL)
444c9af18a5SGreg Clayton     {
445c9af18a5SGreg Clayton         if (m_include_support_files)
446c9af18a5SGreg Clayton         {
447c9af18a5SGreg Clayton             FileSpecList supporting_files = context.comp_unit->GetSupportFiles();
448c9af18a5SGreg Clayton             for (size_t sfiles = 0; sfiles < supporting_files.GetSize(); sfiles++)
449c9af18a5SGreg Clayton             {
450c9af18a5SGreg Clayton                 const FileSpec &sfile_spec = supporting_files.GetFileSpecAtIndex(sfiles);
451c9af18a5SGreg Clayton                 const char *sfile_file_name = sfile_spec.GetFilename().GetCString();
452c9af18a5SGreg Clayton                 const char *sfile_dir_name = sfile_spec.GetFilename().GetCString();
453c9af18a5SGreg Clayton                 bool match = false;
454c9af18a5SGreg Clayton                 if (m_file_name && sfile_file_name
455c9af18a5SGreg Clayton                     && strstr (sfile_file_name, m_file_name) == sfile_file_name)
456c9af18a5SGreg Clayton                     match = true;
457c9af18a5SGreg Clayton                 if (match && m_dir_name && sfile_dir_name
458c9af18a5SGreg Clayton                     && strstr (sfile_dir_name, m_dir_name) != sfile_dir_name)
459c9af18a5SGreg Clayton                     match = false;
460c9af18a5SGreg Clayton 
461c9af18a5SGreg Clayton                 if (match)
462c9af18a5SGreg Clayton                 {
463c9af18a5SGreg Clayton                     m_matching_files.AppendIfUnique(sfile_spec);
464c9af18a5SGreg Clayton                 }
465c9af18a5SGreg Clayton             }
466c9af18a5SGreg Clayton 
467c9af18a5SGreg Clayton         }
468c9af18a5SGreg Clayton         else
469c9af18a5SGreg Clayton         {
470c9af18a5SGreg Clayton             const char *cur_file_name = context.comp_unit->GetFilename().GetCString();
471c9af18a5SGreg Clayton             const char *cur_dir_name = context.comp_unit->GetDirectory().GetCString();
472c9af18a5SGreg Clayton 
473c9af18a5SGreg Clayton             bool match = false;
474c9af18a5SGreg Clayton             if (m_file_name && cur_file_name
475c9af18a5SGreg Clayton                 && strstr (cur_file_name, m_file_name) == cur_file_name)
476c9af18a5SGreg Clayton                 match = true;
477c9af18a5SGreg Clayton 
478c9af18a5SGreg Clayton             if (match && m_dir_name && cur_dir_name
479c9af18a5SGreg Clayton                 && strstr (cur_dir_name, m_dir_name) != cur_dir_name)
480c9af18a5SGreg Clayton                 match = false;
481c9af18a5SGreg Clayton 
482c9af18a5SGreg Clayton             if (match)
483c9af18a5SGreg Clayton             {
484c9af18a5SGreg Clayton                 m_matching_files.AppendIfUnique(context.comp_unit);
485c9af18a5SGreg Clayton             }
486c9af18a5SGreg Clayton         }
487c9af18a5SGreg Clayton     }
488c9af18a5SGreg Clayton     return Searcher::eCallbackReturnContinue;
489c9af18a5SGreg Clayton }
490c9af18a5SGreg Clayton 
491c9af18a5SGreg Clayton size_t
492c9af18a5SGreg Clayton CommandCompletions::SourceFileCompleter::DoCompletion (SearchFilter *filter)
493c9af18a5SGreg Clayton {
494c9af18a5SGreg Clayton     filter->Search (*this);
495c9af18a5SGreg Clayton     // Now convert the filelist to completions:
496c9af18a5SGreg Clayton     for (size_t i = 0; i < m_matching_files.GetSize(); i++)
497c9af18a5SGreg Clayton     {
498c9af18a5SGreg Clayton         m_matches.AppendString (m_matching_files.GetFileSpecAtIndex(i).GetFilename().GetCString());
499c9af18a5SGreg Clayton     }
500c9af18a5SGreg Clayton     return m_matches.GetSize();
501c9af18a5SGreg Clayton 
502c9af18a5SGreg Clayton }
503c9af18a5SGreg Clayton 
504c9af18a5SGreg Clayton //----------------------------------------------------------------------
505c9af18a5SGreg Clayton // SymbolCompleter
506c9af18a5SGreg Clayton //----------------------------------------------------------------------
507c9af18a5SGreg Clayton 
508c9af18a5SGreg Clayton static bool
509c9af18a5SGreg Clayton regex_chars (const char comp)
510c9af18a5SGreg Clayton {
511c9af18a5SGreg Clayton     if (comp == '[' || comp == ']' || comp == '(' || comp == ')')
512c9af18a5SGreg Clayton         return true;
513c9af18a5SGreg Clayton     else
514c9af18a5SGreg Clayton         return false;
515c9af18a5SGreg Clayton }
5166611103cSGreg Clayton CommandCompletions::SymbolCompleter::SymbolCompleter
5176611103cSGreg Clayton (
5186611103cSGreg Clayton     CommandInterpreter &interpreter,
519c9af18a5SGreg Clayton     const char *completion_str,
520c9af18a5SGreg Clayton     int match_start_point,
521c9af18a5SGreg Clayton     int max_return_elements,
522c9af18a5SGreg Clayton     StringList &matches
523c9af18a5SGreg Clayton ) :
5246611103cSGreg Clayton     CommandCompletions::Completer (interpreter, completion_str, match_start_point, max_return_elements, matches)
525c9af18a5SGreg Clayton {
526c9af18a5SGreg Clayton     std::string regex_str ("^");
527c9af18a5SGreg Clayton     regex_str.append(completion_str);
528c9af18a5SGreg Clayton     regex_str.append(".*");
529c9af18a5SGreg Clayton     std::string::iterator pos;
530c9af18a5SGreg Clayton 
531c9af18a5SGreg Clayton     pos = find_if(regex_str.begin(), regex_str.end(), regex_chars);
532c9af18a5SGreg Clayton     while (pos < regex_str.end()) {
533c9af18a5SGreg Clayton         pos = regex_str.insert(pos, '\\');
534c9af18a5SGreg Clayton         pos += 2;
535c9af18a5SGreg Clayton         pos = find_if(pos, regex_str.end(), regex_chars);
536c9af18a5SGreg Clayton     }
537c9af18a5SGreg Clayton     m_regex.Compile(regex_str.c_str());
538c9af18a5SGreg Clayton }
539c9af18a5SGreg Clayton 
540c9af18a5SGreg Clayton Searcher::Depth
541c9af18a5SGreg Clayton CommandCompletions::SymbolCompleter::GetDepth()
542c9af18a5SGreg Clayton {
543c9af18a5SGreg Clayton     return eDepthModule;
544c9af18a5SGreg Clayton }
545c9af18a5SGreg Clayton 
546c9af18a5SGreg Clayton Searcher::CallbackReturn
547c9af18a5SGreg Clayton CommandCompletions::SymbolCompleter::SearchCallback (
548c9af18a5SGreg Clayton     SearchFilter &filter,
549c9af18a5SGreg Clayton     SymbolContext &context,
550c9af18a5SGreg Clayton     Address *addr,
551c9af18a5SGreg Clayton     bool complete
552c9af18a5SGreg Clayton )
553c9af18a5SGreg Clayton {
554c9af18a5SGreg Clayton     SymbolContextList func_list;
555c9af18a5SGreg Clayton     SymbolContextList sym_list;
556c9af18a5SGreg Clayton 
557c9af18a5SGreg Clayton     if (context.module_sp != NULL)
558c9af18a5SGreg Clayton     {
559c9af18a5SGreg Clayton         if (context.module_sp)
560c9af18a5SGreg Clayton         {
561c9af18a5SGreg Clayton             context.module_sp->FindSymbolsMatchingRegExAndType (m_regex, lldb::eSymbolTypeCode, sym_list);
562c9af18a5SGreg Clayton             context.module_sp->FindFunctions (m_regex, true, func_list);
563c9af18a5SGreg Clayton         }
564c9af18a5SGreg Clayton 
565c9af18a5SGreg Clayton         SymbolContext sc;
566c9af18a5SGreg Clayton         // Now add the functions & symbols to the list - only add if unique:
567c9af18a5SGreg Clayton         for (int i = 0; i < func_list.GetSize(); i++)
568c9af18a5SGreg Clayton         {
569c9af18a5SGreg Clayton             if (func_list.GetContextAtIndex(i, sc))
570c9af18a5SGreg Clayton             {
571c9af18a5SGreg Clayton                 if (sc.function)
572c9af18a5SGreg Clayton                 {
573c9af18a5SGreg Clayton                     m_match_set.insert (sc.function->GetMangled().GetDemangledName());
574c9af18a5SGreg Clayton                 }
575c9af18a5SGreg Clayton             }
576c9af18a5SGreg Clayton         }
577c9af18a5SGreg Clayton 
578c9af18a5SGreg Clayton         for (int i = 0; i < sym_list.GetSize(); i++)
579c9af18a5SGreg Clayton         {
580c9af18a5SGreg Clayton             if (sym_list.GetContextAtIndex(i, sc))
581c9af18a5SGreg Clayton             {
582c9af18a5SGreg Clayton                 if (sc.symbol && sc.symbol->GetAddressRangePtr())
583c9af18a5SGreg Clayton                 {
584c9af18a5SGreg Clayton                     m_match_set.insert (sc.symbol->GetMangled().GetDemangledName());
585c9af18a5SGreg Clayton                 }
586c9af18a5SGreg Clayton             }
587c9af18a5SGreg Clayton         }
588c9af18a5SGreg Clayton     }
589c9af18a5SGreg Clayton     return Searcher::eCallbackReturnContinue;
590c9af18a5SGreg Clayton }
591c9af18a5SGreg Clayton 
592c9af18a5SGreg Clayton size_t
593c9af18a5SGreg Clayton CommandCompletions::SymbolCompleter::DoCompletion (SearchFilter *filter)
594c9af18a5SGreg Clayton {
595c9af18a5SGreg Clayton     filter->Search (*this);
596c9af18a5SGreg Clayton     collection::iterator pos = m_match_set.begin(), end = m_match_set.end();
597c9af18a5SGreg Clayton     for (pos = m_match_set.begin(); pos != end; pos++)
598c9af18a5SGreg Clayton         m_matches.AppendString((*pos).GetCString());
599c9af18a5SGreg Clayton 
600c9af18a5SGreg Clayton     return m_matches.GetSize();
601c9af18a5SGreg Clayton }
602c9af18a5SGreg Clayton 
603c9af18a5SGreg Clayton //----------------------------------------------------------------------
604c9af18a5SGreg Clayton // ModuleCompleter
605c9af18a5SGreg Clayton //----------------------------------------------------------------------
6066611103cSGreg Clayton CommandCompletions::ModuleCompleter::ModuleCompleter
6076611103cSGreg Clayton (
6086611103cSGreg Clayton     CommandInterpreter &interpreter,
609c9af18a5SGreg Clayton     const char *completion_str,
610c9af18a5SGreg Clayton     int match_start_point,
611c9af18a5SGreg Clayton     int max_return_elements,
612c9af18a5SGreg Clayton     StringList &matches
613c9af18a5SGreg Clayton ) :
6146611103cSGreg Clayton     CommandCompletions::Completer (interpreter, completion_str, match_start_point, max_return_elements, matches)
615c9af18a5SGreg Clayton {
616c9af18a5SGreg Clayton     FileSpec partial_spec (m_completion_str.c_str());
617c9af18a5SGreg Clayton     m_file_name = partial_spec.GetFilename().GetCString();
618c9af18a5SGreg Clayton     m_dir_name = partial_spec.GetDirectory().GetCString();
619c9af18a5SGreg Clayton }
620c9af18a5SGreg Clayton 
621c9af18a5SGreg Clayton Searcher::Depth
622c9af18a5SGreg Clayton CommandCompletions::ModuleCompleter::GetDepth()
623c9af18a5SGreg Clayton {
624c9af18a5SGreg Clayton     return eDepthModule;
625c9af18a5SGreg Clayton }
626c9af18a5SGreg Clayton 
627c9af18a5SGreg Clayton Searcher::CallbackReturn
628c9af18a5SGreg Clayton CommandCompletions::ModuleCompleter::SearchCallback (
629c9af18a5SGreg Clayton     SearchFilter &filter,
630c9af18a5SGreg Clayton     SymbolContext &context,
631c9af18a5SGreg Clayton     Address *addr,
632c9af18a5SGreg Clayton     bool complete
633c9af18a5SGreg Clayton )
634c9af18a5SGreg Clayton {
635c9af18a5SGreg Clayton     if (context.module_sp != NULL)
636c9af18a5SGreg Clayton     {
637c9af18a5SGreg Clayton         const char *cur_file_name = context.module_sp->GetFileSpec().GetFilename().GetCString();
638c9af18a5SGreg Clayton         const char *cur_dir_name = context.module_sp->GetFileSpec().GetDirectory().GetCString();
639c9af18a5SGreg Clayton 
640c9af18a5SGreg Clayton         bool match = false;
641c9af18a5SGreg Clayton         if (m_file_name && cur_file_name
642c9af18a5SGreg Clayton             && strstr (cur_file_name, m_file_name) == cur_file_name)
643c9af18a5SGreg Clayton             match = true;
644c9af18a5SGreg Clayton 
645c9af18a5SGreg Clayton         if (match && m_dir_name && cur_dir_name
646c9af18a5SGreg Clayton             && strstr (cur_dir_name, m_dir_name) != cur_dir_name)
647c9af18a5SGreg Clayton             match = false;
648c9af18a5SGreg Clayton 
649c9af18a5SGreg Clayton         if (match)
650c9af18a5SGreg Clayton         {
651c9af18a5SGreg Clayton             m_matches.AppendString (cur_file_name);
652c9af18a5SGreg Clayton         }
653c9af18a5SGreg Clayton     }
654c9af18a5SGreg Clayton     return Searcher::eCallbackReturnContinue;
655c9af18a5SGreg Clayton }
656c9af18a5SGreg Clayton 
657c9af18a5SGreg Clayton size_t
658c9af18a5SGreg Clayton CommandCompletions::ModuleCompleter::DoCompletion (SearchFilter *filter)
659c9af18a5SGreg Clayton {
660c9af18a5SGreg Clayton     filter->Search (*this);
661c9af18a5SGreg Clayton     return m_matches.GetSize();
662c9af18a5SGreg Clayton }
663c9af18a5SGreg Clayton 
664c9af18a5SGreg Clayton 
665c9af18a5SGreg Clayton 
666