Options.cpp revision 8b9af1caac91c9e66440370a79705a3370e0a360
1//===-- Options.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/Interpreter/Options.h"
11
12// C Includes
13// C++ Includes
14#include <bitset>
15
16// Other libraries and framework includes
17// Project includes
18#include "lldb/Interpreter/CommandObject.h"
19#include "lldb/Interpreter/CommandReturnObject.h"
20#include "lldb/Interpreter/CommandCompletions.h"
21#include "lldb/Interpreter/CommandInterpreter.h"
22#include "lldb/Core/StreamString.h"
23#include "lldb/Target/Target.h"
24
25using namespace lldb;
26using namespace lldb_private;
27
28//-------------------------------------------------------------------------
29// Options
30//-------------------------------------------------------------------------
31Options::Options () :
32    m_getopt_table ()
33{
34    BuildValidOptionSets();
35}
36
37Options::~Options ()
38{
39}
40
41
42void
43Options::ResetOptionValues ()
44{
45    m_seen_options.clear();
46}
47
48void
49Options::OptionSeen (int option_idx)
50{
51    m_seen_options.insert ((char) option_idx);
52}
53
54// Returns true is set_a is a subset of set_b;  Otherwise returns false.
55
56bool
57Options::IsASubset (const OptionSet& set_a, const OptionSet& set_b)
58{
59    bool is_a_subset = true;
60    OptionSet::const_iterator pos_a;
61    OptionSet::const_iterator pos_b;
62
63    // set_a is a subset of set_b if every member of set_a is also a member of set_b
64
65    for (pos_a = set_a.begin(); pos_a != set_a.end() && is_a_subset; ++pos_a)
66    {
67        pos_b = set_b.find(*pos_a);
68        if (pos_b == set_b.end())
69            is_a_subset = false;
70    }
71
72    return is_a_subset;
73}
74
75// Returns the set difference set_a - set_b, i.e. { x | ElementOf (x, set_a) && !ElementOf (x, set_b) }
76
77size_t
78Options::OptionsSetDiff (const OptionSet& set_a, const OptionSet& set_b, OptionSet& diffs)
79{
80    size_t num_diffs = 0;
81    OptionSet::const_iterator pos_a;
82    OptionSet::const_iterator pos_b;
83
84    for (pos_a = set_a.begin(); pos_a != set_a.end(); ++pos_a)
85    {
86        pos_b = set_b.find(*pos_a);
87        if (pos_b == set_b.end())
88        {
89            ++num_diffs;
90            diffs.insert(*pos_a);
91        }
92    }
93
94    return num_diffs;
95}
96
97// Returns the union of set_a and set_b.  Does not put duplicate members into the union.
98
99void
100Options::OptionsSetUnion (const OptionSet &set_a, const OptionSet &set_b, OptionSet &union_set)
101{
102    OptionSet::const_iterator pos;
103    OptionSet::iterator pos_union;
104
105    // Put all the elements of set_a into the union.
106
107    for (pos = set_a.begin(); pos != set_a.end(); ++pos)
108        union_set.insert(*pos);
109
110    // Put all the elements of set_b that are not already there into the union.
111    for (pos = set_b.begin(); pos != set_b.end(); ++pos)
112    {
113        pos_union = union_set.find(*pos);
114        if (pos_union == union_set.end())
115            union_set.insert(*pos);
116    }
117}
118
119bool
120Options::VerifyOptions (CommandReturnObject &result)
121{
122    bool options_are_valid = false;
123
124    int num_levels = GetRequiredOptions().size();
125    if (num_levels)
126    {
127        for (int i = 0; i < num_levels && !options_are_valid; ++i)
128        {
129            // This is the correct set of options if:  1). m_seen_options contains all of m_required_options[i]
130            // (i.e. all the required options at this level are a subset of m_seen_options); AND
131            // 2). { m_seen_options - m_required_options[i] is a subset of m_options_options[i] (i.e. all the rest of
132            // m_seen_options are in the set of optional options at this level.
133
134            // Check to see if all of m_required_options[i] are a subset of m_seen_options
135            if (IsASubset (GetRequiredOptions()[i], m_seen_options))
136            {
137                // Construct the set difference: remaining_options = {m_seen_options} - {m_required_options[i]}
138                OptionSet remaining_options;
139                OptionsSetDiff (m_seen_options, GetRequiredOptions()[i], remaining_options);
140                // Check to see if remaining_options is a subset of m_optional_options[i]
141                if (IsASubset (remaining_options, GetOptionalOptions()[i]))
142                    options_are_valid = true;
143            }
144        }
145    }
146    else
147    {
148        options_are_valid = true;
149    }
150
151    if (options_are_valid)
152    {
153        result.SetStatus (eReturnStatusSuccessFinishNoResult);
154    }
155    else
156    {
157        result.AppendError ("invalid combination of options for the given command");
158        result.SetStatus (eReturnStatusFailed);
159    }
160
161    return options_are_valid;
162}
163
164// This is called in the Options constructor, though we could call it lazily if that ends up being
165// a performance problem.
166
167void
168Options::BuildValidOptionSets ()
169{
170    // Check to see if we already did this.
171    if (m_required_options.size() != 0)
172        return;
173
174    // Check to see if there are any options.
175    int num_options = NumCommandOptions ();
176    if (num_options == 0)
177        return;
178
179    const lldb::OptionDefinition *full_options_table = GetDefinitions();
180    m_required_options.resize(1);
181    m_optional_options.resize(1);
182
183    // First count the number of option sets we've got.  Ignore LLDB_ALL_OPTION_SETS...
184
185    uint32_t num_option_sets = 0;
186
187    for (int i = 0; i < num_options; i++)
188    {
189        uint32_t this_usage_mask = full_options_table[i].usage_mask;
190        if (this_usage_mask == LLDB_OPT_SET_ALL)
191        {
192            if (num_option_sets == 0)
193                num_option_sets = 1;
194        }
195        else
196        {
197            for (int j = 0; j < LLDB_MAX_NUM_OPTION_SETS; j++)
198            {
199                if (this_usage_mask & (1 << j))
200                {
201                    if (num_option_sets <= j)
202                        num_option_sets = j + 1;
203                }
204            }
205        }
206    }
207
208    if (num_option_sets > 0)
209    {
210        m_required_options.resize(num_option_sets);
211        m_optional_options.resize(num_option_sets);
212
213        for (int i = 0; i < num_options; ++i)
214        {
215            for (int j = 0; j < num_option_sets; j++)
216            {
217                if (full_options_table[i].usage_mask & 1 << j)
218                {
219                    if (full_options_table[i].required)
220                        m_required_options[j].insert(full_options_table[i].short_option);
221                    else
222                        m_optional_options[j].insert(full_options_table[i].short_option);
223                }
224            }
225        }
226    }
227}
228
229uint32_t
230Options::NumCommandOptions ()
231{
232    const lldb::OptionDefinition *full_options_table = GetDefinitions ();
233    if (full_options_table == NULL)
234        return 0;
235
236    int i = 0;
237
238    if (full_options_table != NULL)
239    {
240        while (full_options_table[i].long_option != NULL)
241            ++i;
242    }
243
244    return i;
245}
246
247struct option *
248Options::GetLongOptions ()
249{
250    // Check to see if this has already been done.
251    if (m_getopt_table.empty())
252    {
253        // Check to see if there are any options.
254        const uint32_t num_options = NumCommandOptions();
255        if (num_options == 0)
256            return NULL;
257
258        uint32_t i;
259        uint32_t j;
260        const lldb::OptionDefinition *full_options_table = GetDefinitions();
261
262        std::bitset<256> option_seen;
263
264        m_getopt_table.resize(num_options + 1);
265        for (i = 0, j = 0; i < num_options; ++i)
266        {
267            char short_opt = full_options_table[i].short_option;
268
269            if (option_seen.test(short_opt) == false)
270            {
271                m_getopt_table[j].name    = full_options_table[i].long_option;
272                m_getopt_table[j].has_arg = full_options_table[i].option_has_arg;
273                m_getopt_table[j].flag    = NULL;
274                m_getopt_table[j].val     = full_options_table[i].short_option;
275                option_seen.set(short_opt);
276                ++j;
277            }
278        }
279
280        //getopt_long requires a NULL final entry in the table:
281
282        m_getopt_table[j].name    = NULL;
283        m_getopt_table[j].has_arg = 0;
284        m_getopt_table[j].flag    = NULL;
285        m_getopt_table[j].val     = 0;
286    }
287
288    return m_getopt_table.data();
289}
290
291
292// This function takes INDENT, which tells how many spaces to output at the front of each line; SPACES, which is
293// a string containing 80 spaces; and TEXT, which is the text that is to be output.   It outputs the text, on
294// multiple lines if necessary, to RESULT, with INDENT spaces at the front of each line.  It breaks lines on spaces,
295// tabs or newlines, shortening the line if necessary to not break in the middle of a word.  It assumes that each
296// output line should contain a maximum of OUTPUT_MAX_COLUMNS characters.
297
298
299void
300Options::OutputFormattedUsageText
301(
302    Stream &strm,
303    const char *text,
304    uint32_t output_max_columns
305)
306{
307    int len = strlen (text);
308
309    // Will it all fit on one line?
310
311    if ((len + strm.GetIndentLevel()) < output_max_columns)
312    {
313        // Output it as a single line.
314        strm.Indent (text);
315        strm.EOL();
316    }
317    else
318    {
319        // We need to break it up into multiple lines.
320
321        int text_width = output_max_columns - strm.GetIndentLevel() - 1;
322        int start = 0;
323        int end = start;
324        int final_end = strlen (text);
325        int sub_len;
326
327        while (end < final_end)
328        {
329            // Don't start the 'text' on a space, since we're already outputting the indentation.
330            while ((start < final_end) && (text[start] == ' '))
331                start++;
332
333            end = start + text_width;
334            if (end > final_end)
335                end = final_end;
336            else
337            {
338                // If we're not at the end of the text, make sure we break the line on white space.
339                while (end > start
340                       && text[end] != ' ' && text[end] != '\t' && text[end] != '\n')
341                    end--;
342            }
343
344            sub_len = end - start;
345            if (start != 0)
346                strm.EOL();
347            strm.Indent();
348            assert (start < final_end);
349            assert (start + sub_len <= final_end);
350            strm.Write(text + start, sub_len);
351            start = end + 1;
352        }
353        strm.EOL();
354    }
355}
356
357void
358Options::GenerateOptionUsage
359(
360    Stream &strm,
361    CommandObject *cmd,
362    const char *program_name)
363{
364    uint32_t screen_width = 80;
365    const lldb::OptionDefinition *full_options_table = GetDefinitions();
366    const uint32_t save_indent_level = strm.GetIndentLevel();
367    const char *name;
368
369    if (cmd)
370      name = cmd->GetCommandName();
371    else
372      name = program_name;
373
374    strm.PutCString ("\nCommand Options Usage:\n");
375
376    strm.IndentMore(2);
377
378    // First, show each usage level set of options, e.g. <cmd> [options-for-level-0]
379    //                                                   <cmd> [options-for-level-1]
380    //                                                   etc.
381
382    const uint32_t num_options = NumCommandOptions();
383    if (num_options == 0)
384        return;
385
386    int num_option_sets = GetRequiredOptions().size();
387
388    uint32_t i;
389
390    for (uint32_t opt_set = 0; opt_set < num_option_sets; ++opt_set)
391    {
392        uint32_t opt_set_mask;
393
394        opt_set_mask = 1 << opt_set;
395        if (opt_set > 0)
396            strm.Printf ("\n");
397        strm.Indent (name);
398
399        for (i = 0; i < num_options; ++i)
400        {
401            if (full_options_table[i].usage_mask & opt_set_mask)
402            {
403                // Add current option to the end of out_stream.
404
405                if (full_options_table[i].required)
406                {
407                    if (full_options_table[i].option_has_arg == required_argument)
408                    {
409                        strm.Printf (" -%c %s",
410                                    full_options_table[i].short_option,
411                                    full_options_table[i].argument_name);
412                    }
413                    else if (full_options_table[i].option_has_arg == optional_argument)
414                    {
415                        strm.Printf (" -%c [%s]",
416                                     full_options_table[i].short_option,
417                                     full_options_table[i].argument_name);
418                    }
419                    else
420                        strm.Printf (" -%c", full_options_table[i].short_option);
421                }
422                else
423                {
424                    if (full_options_table[i].option_has_arg == required_argument)
425                        strm.Printf (" [-%c %s]", full_options_table[i].short_option,
426                                           full_options_table[i].argument_name);
427                    else if (full_options_table[i].option_has_arg == optional_argument)
428                        strm.Printf (" [-%c [%s]]", full_options_table[i].short_option,
429                                           full_options_table[i].argument_name);
430                    else
431                        strm.Printf (" [-%c]", full_options_table[i].short_option);
432                }
433            }
434        }
435    }
436    strm.Printf ("\n\n");
437
438    // Now print out all the detailed information about the various options:  long form, short form and help text:
439    //   -- long_name <argument>
440    //   - short <argument>
441    //   help text
442
443    // This variable is used to keep track of which options' info we've printed out, because some options can be in
444    // more than one usage level, but we only want to print the long form of its information once.
445
446    OptionSet options_seen;
447    OptionSet::iterator pos;
448    strm.IndentMore (5);
449
450    int first_option_printed = 1;
451    for (i = 0; i < num_options; ++i)
452    {
453        // Only print out this option if we haven't already seen it.
454        pos = options_seen.find (full_options_table[i].short_option);
455        if (pos == options_seen.end())
456        {
457            // Put a newline separation between arguments
458            if (first_option_printed)
459                first_option_printed = 0;
460            else
461                strm.EOL();
462
463            options_seen.insert (full_options_table[i].short_option);
464            strm.Indent ();
465            strm.Printf ("-%c ", full_options_table[i].short_option);
466            if (full_options_table[i].argument_name != NULL)
467                strm.PutCString(full_options_table[i].argument_name);
468            strm.EOL();
469            strm.Indent ();
470            strm.Printf ("--%s ", full_options_table[i].long_option);
471            if (full_options_table[i].argument_name != NULL)
472                strm.PutCString(full_options_table[i].argument_name);
473            strm.EOL();
474
475            strm.IndentMore (5);
476
477            if (full_options_table[i].usage_text)
478                    OutputFormattedUsageText (strm,
479                                              full_options_table[i].usage_text,
480                                              screen_width);
481            if (full_options_table[i].enum_values != NULL)
482            {
483                strm.Indent ();
484                strm.Printf("Values: ");
485                for (int j = 0; full_options_table[i].enum_values[j].string_value != NULL; j++)
486                {
487                    if (j == 0)
488                        strm.Printf("%s", full_options_table[i].enum_values[j].string_value);
489                    else
490                        strm.Printf(" | %s", full_options_table[i].enum_values[j].string_value);
491                }
492                strm.EOL();
493            }
494            strm.IndentLess (5);
495        }
496    }
497
498    // Restore the indent level
499    strm.SetIndentLevel (save_indent_level);
500}
501
502// This function is called when we have been given a potentially incomplete set of
503// options, such as when an alias has been defined (more options might be added at
504// at the time the alias is invoked).  We need to verify that the options in the set
505// m_seen_options are all part of a set that may be used together, but m_seen_options
506// may be missing some of the "required" options.
507
508bool
509Options::VerifyPartialOptions (CommandReturnObject &result)
510{
511    bool options_are_valid = false;
512
513    int num_levels = GetRequiredOptions().size();
514    if (num_levels)
515      {
516        for (int i = 0; i < num_levels && !options_are_valid; ++i)
517          {
518            // In this case we are treating all options as optional rather than required.
519            // Therefore a set of options is correct if m_seen_options is a subset of the
520            // union of m_required_options and m_optional_options.
521            OptionSet union_set;
522            OptionsSetUnion (GetRequiredOptions()[i], GetOptionalOptions()[i], union_set);
523            if (IsASubset (m_seen_options, union_set))
524                options_are_valid = true;
525          }
526      }
527
528    return options_are_valid;
529}
530
531bool
532Options::HandleOptionCompletion
533(
534    CommandInterpreter &interpreter,
535    Args &input,
536    OptionElementVector &opt_element_vector,
537    int cursor_index,
538    int char_pos,
539    int match_start_point,
540    int max_return_elements,
541    lldb_private::StringList &matches
542)
543{
544    // For now we just scan the completions to see if the cursor position is in
545    // an option or its argument.  Otherwise we'll call HandleArgumentCompletion.
546    // In the future we can use completion to validate options as well if we want.
547
548    const OptionDefinition *opt_defs = GetDefinitions();
549
550    std::string cur_opt_std_str (input.GetArgumentAtIndex(cursor_index));
551    cur_opt_std_str.erase(char_pos);
552    const char *cur_opt_str = cur_opt_std_str.c_str();
553
554    for (int i = 0; i < opt_element_vector.size(); i++)
555    {
556        int opt_pos = opt_element_vector[i].opt_pos;
557        int opt_arg_pos = opt_element_vector[i].opt_arg_pos;
558        int opt_defs_index = opt_element_vector[i].opt_defs_index;
559        if (opt_pos == cursor_index)
560        {
561            // We're completing the option itself.
562
563            if (opt_defs_index == OptionArgElement::eBareDash)
564            {
565                // We're completing a bare dash.  That means all options are open.
566                // FIXME: We should scan the other options provided and only complete options
567                // within the option group they belong to.
568                char opt_str[3] = {'-', 'a', '\0'};
569
570                for (int i = 0 ; opt_defs[i].short_option != 0 ; i++)
571                {
572                    opt_str[1] = opt_defs[i].short_option;
573                    matches.AppendString (opt_str);
574                }
575                return true;
576            }
577            else if (opt_defs_index == OptionArgElement::eBareDoubleDash)
578            {
579                std::string full_name ("--");
580                for (int i = 0 ; opt_defs[i].short_option != 0 ; i++)
581                {
582                    full_name.erase(full_name.begin() + 2, full_name.end());
583                    full_name.append (opt_defs[i].long_option);
584                    matches.AppendString (full_name.c_str());
585                }
586                return true;
587            }
588            else if (opt_defs_index != OptionArgElement::eUnrecognizedArg)
589            {
590                // We recognized it, if it an incomplete long option, complete it anyway (getopt_long is
591                // happy with shortest unique string, but it's still a nice thing to do.)  Otherwise return
592                // The string so the upper level code will know this is a full match and add the " ".
593                if (cur_opt_str && strlen (cur_opt_str) > 2
594                    && cur_opt_str[0] == '-' && cur_opt_str[1] == '-'
595                    && strcmp (opt_defs[opt_defs_index].long_option, cur_opt_str) != 0)
596                {
597                        std::string full_name ("--");
598                        full_name.append (opt_defs[opt_defs_index].long_option);
599                        matches.AppendString(full_name.c_str());
600                        return true;
601                }
602                else
603                {
604                    matches.AppendString(input.GetArgumentAtIndex(cursor_index));
605                    return true;
606                }
607            }
608            else
609            {
610                // FIXME - not handling wrong options yet:
611                // Check to see if they are writing a long option & complete it.
612                // I think we will only get in here if the long option table has two elements
613                // that are not unique up to this point.  getopt_long does shortest unique match
614                // for long options already.
615
616                if (cur_opt_str && strlen (cur_opt_str) > 2
617                    && cur_opt_str[0] == '-' && cur_opt_str[1] == '-')
618                {
619                    for (int i = 0 ; opt_defs[i].short_option != 0 ; i++)
620                    {
621                        if (strstr(opt_defs[i].long_option, cur_opt_str + 2) == opt_defs[i].long_option)
622                        {
623                            std::string full_name ("--");
624                            full_name.append (opt_defs[i].long_option);
625                            // The options definitions table has duplicates because of the
626                            // way the grouping information is stored, so only add once.
627                            bool duplicate = false;
628                            for (int j = 0; j < matches.GetSize(); j++)
629                            {
630                                if (matches.GetStringAtIndex(j) == full_name)
631                                {
632                                    duplicate = true;
633                                    break;
634                                }
635                            }
636                            if (!duplicate)
637                                matches.AppendString(full_name.c_str());
638                        }
639                    }
640                }
641                return true;
642            }
643
644
645        }
646        else if (opt_arg_pos == cursor_index)
647        {
648            // Okay the cursor is on the completion of an argument.
649            // See if it has a completion, otherwise return no matches.
650
651            if (opt_defs_index != -1)
652            {
653                HandleOptionArgumentCompletion (interpreter,
654                                                input,
655                                                cursor_index,
656                                                strlen (input.GetArgumentAtIndex(cursor_index)),
657                                                opt_element_vector,
658                                                i,
659                                                match_start_point,
660                                                max_return_elements,
661                                                matches);
662                return true;
663            }
664            else
665            {
666                // No completion callback means no completions...
667                return true;
668            }
669
670        }
671        else
672        {
673            // Not the last element, keep going.
674            continue;
675        }
676    }
677    return false;
678}
679
680bool
681Options::HandleOptionArgumentCompletion
682(
683    CommandInterpreter &interpreter,
684    Args &input,
685    int cursor_index,
686    int char_pos,
687    OptionElementVector &opt_element_vector,
688    int opt_element_index,
689    int match_start_point,
690    int max_return_elements,
691    lldb_private::StringList &matches
692)
693{
694    const OptionDefinition *opt_defs = GetDefinitions();
695    std::auto_ptr<SearchFilter> filter_ap;
696
697    int opt_arg_pos = opt_element_vector[opt_element_index].opt_arg_pos;
698    int opt_defs_index = opt_element_vector[opt_element_index].opt_defs_index;
699
700    // See if this is an enumeration type option, and if so complete it here:
701
702    OptionEnumValueElement *enum_values = opt_defs[opt_defs_index].enum_values;
703    if (enum_values != NULL)
704    {
705        bool return_value = false;
706        std::string match_string(input.GetArgumentAtIndex (opt_arg_pos), input.GetArgumentAtIndex (opt_arg_pos) + char_pos);
707        for (int i = 0; enum_values[i].string_value != NULL; i++)
708        {
709            if (strstr(enum_values[i].string_value, match_string.c_str()) == enum_values[i].string_value)
710            {
711                matches.AppendString (enum_values[i].string_value);
712                return_value = true;
713            }
714        }
715        return return_value;
716    }
717
718    // If this is a source file or symbol type completion, and  there is a
719    // -shlib option somewhere in the supplied arguments, then make a search filter
720    // for that shared library.
721    // FIXME: Do we want to also have an "OptionType" so we don't have to match string names?
722
723    uint32_t completion_mask = opt_defs[opt_defs_index].completionType;
724    if (completion_mask & CommandCompletions::eSourceFileCompletion
725        || completion_mask & CommandCompletions::eSymbolCompletion)
726    {
727        for (int i = 0; i < opt_element_vector.size(); i++)
728        {
729            int cur_defs_index = opt_element_vector[i].opt_defs_index;
730            int cur_arg_pos    = opt_element_vector[i].opt_arg_pos;
731            const char *cur_opt_name = opt_defs[cur_defs_index].long_option;
732
733            // If this is the "shlib" option and there was an argument provided,
734            // restrict it to that shared library.
735            if (strcmp(cur_opt_name, "shlib") == 0 && cur_arg_pos != -1)
736            {
737                const char *module_name = input.GetArgumentAtIndex(cur_arg_pos);
738                if (module_name)
739                {
740                    FileSpec module_spec(module_name);
741                    lldb::TargetSP target_sp = interpreter.GetDebugger().GetCurrentTarget();
742                    // Search filters require a target...
743                    if (target_sp != NULL)
744                        filter_ap.reset (new SearchFilterByModule (target_sp, module_spec));
745                }
746                break;
747            }
748        }
749    }
750
751    return CommandCompletions::InvokeCommonCompletionCallbacks (interpreter,
752                                                                completion_mask,
753                                                                input.GetArgumentAtIndex (opt_arg_pos),
754                                                                match_start_point,
755                                                                max_return_elements,
756                                                                filter_ap.get(),
757                                                                matches);
758
759}
760