xref: /freebsd-src/contrib/llvm-project/lldb/source/Interpreter/Options.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
15ffd83dbSDimitry Andric //===-- Options.cpp -------------------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "lldb/Interpreter/Options.h"
100b57cec5SDimitry Andric 
110b57cec5SDimitry Andric #include <algorithm>
120b57cec5SDimitry Andric #include <bitset>
130b57cec5SDimitry Andric #include <map>
140b57cec5SDimitry Andric #include <set>
150b57cec5SDimitry Andric 
160b57cec5SDimitry Andric #include "lldb/Host/OptionParser.h"
170b57cec5SDimitry Andric #include "lldb/Interpreter/CommandCompletions.h"
180b57cec5SDimitry Andric #include "lldb/Interpreter/CommandInterpreter.h"
190b57cec5SDimitry Andric #include "lldb/Interpreter/CommandObject.h"
200b57cec5SDimitry Andric #include "lldb/Interpreter/CommandReturnObject.h"
210b57cec5SDimitry Andric #include "lldb/Target/Target.h"
220b57cec5SDimitry Andric #include "lldb/Utility/StreamString.h"
2381ad6265SDimitry Andric #include "llvm/ADT/STLExtras.h"
240b57cec5SDimitry Andric 
250b57cec5SDimitry Andric using namespace lldb;
260b57cec5SDimitry Andric using namespace lldb_private;
270b57cec5SDimitry Andric 
280b57cec5SDimitry Andric // Options
29fe6060f1SDimitry Andric Options::Options() { BuildValidOptionSets(); }
300b57cec5SDimitry Andric 
31fe6060f1SDimitry Andric Options::~Options() = default;
320b57cec5SDimitry Andric 
330b57cec5SDimitry Andric void Options::NotifyOptionParsingStarting(ExecutionContext *execution_context) {
340b57cec5SDimitry Andric   m_seen_options.clear();
350b57cec5SDimitry Andric   // Let the subclass reset its option values
360b57cec5SDimitry Andric   OptionParsingStarting(execution_context);
370b57cec5SDimitry Andric }
380b57cec5SDimitry Andric 
390b57cec5SDimitry Andric Status
400b57cec5SDimitry Andric Options::NotifyOptionParsingFinished(ExecutionContext *execution_context) {
410b57cec5SDimitry Andric   return OptionParsingFinished(execution_context);
420b57cec5SDimitry Andric }
430b57cec5SDimitry Andric 
440b57cec5SDimitry Andric void Options::OptionSeen(int option_idx) { m_seen_options.insert(option_idx); }
450b57cec5SDimitry Andric 
460b57cec5SDimitry Andric // Returns true is set_a is a subset of set_b;  Otherwise returns false.
470b57cec5SDimitry Andric 
480b57cec5SDimitry Andric bool Options::IsASubset(const OptionSet &set_a, const OptionSet &set_b) {
490b57cec5SDimitry Andric   bool is_a_subset = true;
500b57cec5SDimitry Andric   OptionSet::const_iterator pos_a;
510b57cec5SDimitry Andric   OptionSet::const_iterator pos_b;
520b57cec5SDimitry Andric 
530b57cec5SDimitry Andric   // set_a is a subset of set_b if every member of set_a is also a member of
540b57cec5SDimitry Andric   // set_b
550b57cec5SDimitry Andric 
560b57cec5SDimitry Andric   for (pos_a = set_a.begin(); pos_a != set_a.end() && is_a_subset; ++pos_a) {
570b57cec5SDimitry Andric     pos_b = set_b.find(*pos_a);
580b57cec5SDimitry Andric     if (pos_b == set_b.end())
590b57cec5SDimitry Andric       is_a_subset = false;
600b57cec5SDimitry Andric   }
610b57cec5SDimitry Andric 
620b57cec5SDimitry Andric   return is_a_subset;
630b57cec5SDimitry Andric }
640b57cec5SDimitry Andric 
650b57cec5SDimitry Andric // Returns the set difference set_a - set_b, i.e. { x | ElementOf (x, set_a) &&
660b57cec5SDimitry Andric // !ElementOf (x, set_b) }
670b57cec5SDimitry Andric 
680b57cec5SDimitry Andric size_t Options::OptionsSetDiff(const OptionSet &set_a, const OptionSet &set_b,
690b57cec5SDimitry Andric                                OptionSet &diffs) {
700b57cec5SDimitry Andric   size_t num_diffs = 0;
710b57cec5SDimitry Andric   OptionSet::const_iterator pos_a;
720b57cec5SDimitry Andric   OptionSet::const_iterator pos_b;
730b57cec5SDimitry Andric 
740b57cec5SDimitry Andric   for (pos_a = set_a.begin(); pos_a != set_a.end(); ++pos_a) {
750b57cec5SDimitry Andric     pos_b = set_b.find(*pos_a);
760b57cec5SDimitry Andric     if (pos_b == set_b.end()) {
770b57cec5SDimitry Andric       ++num_diffs;
780b57cec5SDimitry Andric       diffs.insert(*pos_a);
790b57cec5SDimitry Andric     }
800b57cec5SDimitry Andric   }
810b57cec5SDimitry Andric 
820b57cec5SDimitry Andric   return num_diffs;
830b57cec5SDimitry Andric }
840b57cec5SDimitry Andric 
850b57cec5SDimitry Andric // Returns the union of set_a and set_b.  Does not put duplicate members into
860b57cec5SDimitry Andric // the union.
870b57cec5SDimitry Andric 
880b57cec5SDimitry Andric void Options::OptionsSetUnion(const OptionSet &set_a, const OptionSet &set_b,
890b57cec5SDimitry Andric                               OptionSet &union_set) {
900b57cec5SDimitry Andric   OptionSet::const_iterator pos;
910b57cec5SDimitry Andric   OptionSet::iterator pos_union;
920b57cec5SDimitry Andric 
930b57cec5SDimitry Andric   // Put all the elements of set_a into the union.
940b57cec5SDimitry Andric 
950b57cec5SDimitry Andric   for (pos = set_a.begin(); pos != set_a.end(); ++pos)
960b57cec5SDimitry Andric     union_set.insert(*pos);
970b57cec5SDimitry Andric 
980b57cec5SDimitry Andric   // Put all the elements of set_b that are not already there into the union.
990b57cec5SDimitry Andric   for (pos = set_b.begin(); pos != set_b.end(); ++pos) {
1000b57cec5SDimitry Andric     pos_union = union_set.find(*pos);
1010b57cec5SDimitry Andric     if (pos_union == union_set.end())
1020b57cec5SDimitry Andric       union_set.insert(*pos);
1030b57cec5SDimitry Andric   }
1040b57cec5SDimitry Andric }
1050b57cec5SDimitry Andric 
1060b57cec5SDimitry Andric bool Options::VerifyOptions(CommandReturnObject &result) {
1070b57cec5SDimitry Andric   bool options_are_valid = false;
1080b57cec5SDimitry Andric 
1090b57cec5SDimitry Andric   int num_levels = GetRequiredOptions().size();
1100b57cec5SDimitry Andric   if (num_levels) {
1110b57cec5SDimitry Andric     for (int i = 0; i < num_levels && !options_are_valid; ++i) {
1120b57cec5SDimitry Andric       // This is the correct set of options if:  1). m_seen_options contains
1130b57cec5SDimitry Andric       // all of m_required_options[i] (i.e. all the required options at this
1140b57cec5SDimitry Andric       // level are a subset of m_seen_options); AND 2). { m_seen_options -
1150b57cec5SDimitry Andric       // m_required_options[i] is a subset of m_options_options[i] (i.e. all
1160b57cec5SDimitry Andric       // the rest of m_seen_options are in the set of optional options at this
1170b57cec5SDimitry Andric       // level.
1180b57cec5SDimitry Andric 
1190b57cec5SDimitry Andric       // Check to see if all of m_required_options[i] are a subset of
1200b57cec5SDimitry Andric       // m_seen_options
1210b57cec5SDimitry Andric       if (IsASubset(GetRequiredOptions()[i], m_seen_options)) {
1220b57cec5SDimitry Andric         // Construct the set difference: remaining_options = {m_seen_options} -
1230b57cec5SDimitry Andric         // {m_required_options[i]}
1240b57cec5SDimitry Andric         OptionSet remaining_options;
1250b57cec5SDimitry Andric         OptionsSetDiff(m_seen_options, GetRequiredOptions()[i],
1260b57cec5SDimitry Andric                        remaining_options);
1270b57cec5SDimitry Andric         // Check to see if remaining_options is a subset of
1280b57cec5SDimitry Andric         // m_optional_options[i]
1290b57cec5SDimitry Andric         if (IsASubset(remaining_options, GetOptionalOptions()[i]))
1300b57cec5SDimitry Andric           options_are_valid = true;
1310b57cec5SDimitry Andric       }
1320b57cec5SDimitry Andric     }
1330b57cec5SDimitry Andric   } else {
1340b57cec5SDimitry Andric     options_are_valid = true;
1350b57cec5SDimitry Andric   }
1360b57cec5SDimitry Andric 
1370b57cec5SDimitry Andric   if (options_are_valid) {
1380b57cec5SDimitry Andric     result.SetStatus(eReturnStatusSuccessFinishNoResult);
1390b57cec5SDimitry Andric   } else {
1400b57cec5SDimitry Andric     result.AppendError("invalid combination of options for the given command");
1410b57cec5SDimitry Andric   }
1420b57cec5SDimitry Andric 
1430b57cec5SDimitry Andric   return options_are_valid;
1440b57cec5SDimitry Andric }
1450b57cec5SDimitry Andric 
1460b57cec5SDimitry Andric // This is called in the Options constructor, though we could call it lazily if
1470b57cec5SDimitry Andric // that ends up being a performance problem.
1480b57cec5SDimitry Andric 
1490b57cec5SDimitry Andric void Options::BuildValidOptionSets() {
1500b57cec5SDimitry Andric   // Check to see if we already did this.
1510b57cec5SDimitry Andric   if (m_required_options.size() != 0)
1520b57cec5SDimitry Andric     return;
1530b57cec5SDimitry Andric 
1540b57cec5SDimitry Andric   // Check to see if there are any options.
1550b57cec5SDimitry Andric   int num_options = NumCommandOptions();
1560b57cec5SDimitry Andric   if (num_options == 0)
1570b57cec5SDimitry Andric     return;
1580b57cec5SDimitry Andric 
1590b57cec5SDimitry Andric   auto opt_defs = GetDefinitions();
1600b57cec5SDimitry Andric   m_required_options.resize(1);
1610b57cec5SDimitry Andric   m_optional_options.resize(1);
1620b57cec5SDimitry Andric 
1630b57cec5SDimitry Andric   // First count the number of option sets we've got.  Ignore
1640b57cec5SDimitry Andric   // LLDB_ALL_OPTION_SETS...
1650b57cec5SDimitry Andric 
1660b57cec5SDimitry Andric   uint32_t num_option_sets = 0;
1670b57cec5SDimitry Andric 
1680b57cec5SDimitry Andric   for (const auto &def : opt_defs) {
1690b57cec5SDimitry Andric     uint32_t this_usage_mask = def.usage_mask;
1700b57cec5SDimitry Andric     if (this_usage_mask == LLDB_OPT_SET_ALL) {
1710b57cec5SDimitry Andric       if (num_option_sets == 0)
1720b57cec5SDimitry Andric         num_option_sets = 1;
1730b57cec5SDimitry Andric     } else {
1740b57cec5SDimitry Andric       for (uint32_t j = 0; j < LLDB_MAX_NUM_OPTION_SETS; j++) {
1750b57cec5SDimitry Andric         if (this_usage_mask & (1 << j)) {
1760b57cec5SDimitry Andric           if (num_option_sets <= j)
1770b57cec5SDimitry Andric             num_option_sets = j + 1;
1780b57cec5SDimitry Andric         }
1790b57cec5SDimitry Andric       }
1800b57cec5SDimitry Andric     }
1810b57cec5SDimitry Andric   }
1820b57cec5SDimitry Andric 
1830b57cec5SDimitry Andric   if (num_option_sets > 0) {
1840b57cec5SDimitry Andric     m_required_options.resize(num_option_sets);
1850b57cec5SDimitry Andric     m_optional_options.resize(num_option_sets);
1860b57cec5SDimitry Andric 
1870b57cec5SDimitry Andric     for (const auto &def : opt_defs) {
1880b57cec5SDimitry Andric       for (uint32_t j = 0; j < num_option_sets; j++) {
1890b57cec5SDimitry Andric         if (def.usage_mask & 1 << j) {
1900b57cec5SDimitry Andric           if (def.required)
1910b57cec5SDimitry Andric             m_required_options[j].insert(def.short_option);
1920b57cec5SDimitry Andric           else
1930b57cec5SDimitry Andric             m_optional_options[j].insert(def.short_option);
1940b57cec5SDimitry Andric         }
1950b57cec5SDimitry Andric       }
1960b57cec5SDimitry Andric     }
1970b57cec5SDimitry Andric   }
1980b57cec5SDimitry Andric }
1990b57cec5SDimitry Andric 
2000b57cec5SDimitry Andric uint32_t Options::NumCommandOptions() { return GetDefinitions().size(); }
2010b57cec5SDimitry Andric 
2020b57cec5SDimitry Andric Option *Options::GetLongOptions() {
2030b57cec5SDimitry Andric   // Check to see if this has already been done.
2040b57cec5SDimitry Andric   if (m_getopt_table.empty()) {
2050b57cec5SDimitry Andric     auto defs = GetDefinitions();
2060b57cec5SDimitry Andric     if (defs.empty())
2070b57cec5SDimitry Andric       return nullptr;
2080b57cec5SDimitry Andric 
2090b57cec5SDimitry Andric     std::map<int, uint32_t> option_seen;
2100b57cec5SDimitry Andric 
2110b57cec5SDimitry Andric     m_getopt_table.resize(defs.size() + 1);
2120b57cec5SDimitry Andric     for (size_t i = 0; i < defs.size(); ++i) {
2130b57cec5SDimitry Andric       const int short_opt = defs[i].short_option;
2140b57cec5SDimitry Andric 
2150b57cec5SDimitry Andric       m_getopt_table[i].definition = &defs[i];
2160b57cec5SDimitry Andric       m_getopt_table[i].flag = nullptr;
2170b57cec5SDimitry Andric       m_getopt_table[i].val = short_opt;
2180b57cec5SDimitry Andric 
2190b57cec5SDimitry Andric       if (option_seen.find(short_opt) == option_seen.end()) {
2200b57cec5SDimitry Andric         option_seen[short_opt] = i;
2210b57cec5SDimitry Andric       } else if (short_opt) {
2220b57cec5SDimitry Andric         m_getopt_table[i].val = 0;
2230b57cec5SDimitry Andric         std::map<int, uint32_t>::const_iterator pos =
2240b57cec5SDimitry Andric             option_seen.find(short_opt);
2250b57cec5SDimitry Andric         StreamString strm;
226e8d8bef9SDimitry Andric         if (defs[i].HasShortOption())
22781ad6265SDimitry Andric           Debugger::ReportError(
22881ad6265SDimitry Andric               llvm::formatv(
22981ad6265SDimitry Andric                   "option[{0}] --{1} has a short option -{2} that "
23081ad6265SDimitry Andric                   "conflicts with option[{3}] --{4}, short option won't "
23181ad6265SDimitry Andric                   "be used for --{5}",
23281ad6265SDimitry Andric                   i, defs[i].long_option, short_opt, pos->second,
2330b57cec5SDimitry Andric                   m_getopt_table[pos->second].definition->long_option,
23481ad6265SDimitry Andric                   defs[i].long_option)
23581ad6265SDimitry Andric                   .str());
2360b57cec5SDimitry Andric         else
23781ad6265SDimitry Andric           Debugger::ReportError(
23881ad6265SDimitry Andric               llvm::formatv(
23981ad6265SDimitry Andric                   "option[{0}] --{1} has a short option {2:x} that "
24081ad6265SDimitry Andric                   "conflicts with option[{3}] --{4}, short option won't "
241bdd1243dSDimitry Andric                   "be used for --{5}",
2420b57cec5SDimitry Andric                   (int)i, defs[i].long_option, short_opt, pos->second,
2430b57cec5SDimitry Andric                   m_getopt_table[pos->second].definition->long_option,
24481ad6265SDimitry Andric                   defs[i].long_option)
24581ad6265SDimitry Andric                   .str());
2460b57cec5SDimitry Andric       }
2470b57cec5SDimitry Andric     }
2480b57cec5SDimitry Andric 
2490b57cec5SDimitry Andric     // getopt_long_only requires a NULL final entry in the table:
2500b57cec5SDimitry Andric 
2510b57cec5SDimitry Andric     m_getopt_table.back().definition = nullptr;
2520b57cec5SDimitry Andric     m_getopt_table.back().flag = nullptr;
2530b57cec5SDimitry Andric     m_getopt_table.back().val = 0;
2540b57cec5SDimitry Andric   }
2550b57cec5SDimitry Andric 
2560b57cec5SDimitry Andric   if (m_getopt_table.empty())
2570b57cec5SDimitry Andric     return nullptr;
2580b57cec5SDimitry Andric 
2590b57cec5SDimitry Andric   return &m_getopt_table.front();
2600b57cec5SDimitry Andric }
2610b57cec5SDimitry Andric 
2620b57cec5SDimitry Andric // This function takes INDENT, which tells how many spaces to output at the
2630b57cec5SDimitry Andric // front of each line; SPACES, which is a string containing 80 spaces; and
2640b57cec5SDimitry Andric // TEXT, which is the text that is to be output.   It outputs the text, on
2650b57cec5SDimitry Andric // multiple lines if necessary, to RESULT, with INDENT spaces at the front of
2660b57cec5SDimitry Andric // each line.  It breaks lines on spaces, tabs or newlines, shortening the line
2670b57cec5SDimitry Andric // if necessary to not break in the middle of a word.  It assumes that each
2680b57cec5SDimitry Andric // output line should contain a maximum of OUTPUT_MAX_COLUMNS characters.
2690b57cec5SDimitry Andric 
2700b57cec5SDimitry Andric void Options::OutputFormattedUsageText(Stream &strm,
2710b57cec5SDimitry Andric                                        const OptionDefinition &option_def,
2720b57cec5SDimitry Andric                                        uint32_t output_max_columns) {
2730b57cec5SDimitry Andric   std::string actual_text;
2740b57cec5SDimitry Andric   if (option_def.validator) {
2750b57cec5SDimitry Andric     const char *condition = option_def.validator->ShortConditionString();
2760b57cec5SDimitry Andric     if (condition) {
2770b57cec5SDimitry Andric       actual_text = "[";
2780b57cec5SDimitry Andric       actual_text.append(condition);
2790b57cec5SDimitry Andric       actual_text.append("] ");
2800b57cec5SDimitry Andric     }
2810b57cec5SDimitry Andric   }
2820b57cec5SDimitry Andric   actual_text.append(option_def.usage_text);
2830b57cec5SDimitry Andric 
2840b57cec5SDimitry Andric   // Will it all fit on one line?
2850b57cec5SDimitry Andric 
2860b57cec5SDimitry Andric   if (static_cast<uint32_t>(actual_text.length() + strm.GetIndentLevel()) <
2870b57cec5SDimitry Andric       output_max_columns) {
2880b57cec5SDimitry Andric     // Output it as a single line.
2895ffd83dbSDimitry Andric     strm.Indent(actual_text);
2900b57cec5SDimitry Andric     strm.EOL();
2910b57cec5SDimitry Andric   } else {
2920b57cec5SDimitry Andric     // We need to break it up into multiple lines.
2930b57cec5SDimitry Andric 
2940b57cec5SDimitry Andric     int text_width = output_max_columns - strm.GetIndentLevel() - 1;
2950b57cec5SDimitry Andric     int start = 0;
2960b57cec5SDimitry Andric     int end = start;
2970b57cec5SDimitry Andric     int final_end = actual_text.length();
2980b57cec5SDimitry Andric     int sub_len;
2990b57cec5SDimitry Andric 
3000b57cec5SDimitry Andric     while (end < final_end) {
3010b57cec5SDimitry Andric       // Don't start the 'text' on a space, since we're already outputting the
3020b57cec5SDimitry Andric       // indentation.
3030b57cec5SDimitry Andric       while ((start < final_end) && (actual_text[start] == ' '))
3040b57cec5SDimitry Andric         start++;
3050b57cec5SDimitry Andric 
3060b57cec5SDimitry Andric       end = start + text_width;
3070b57cec5SDimitry Andric       if (end > final_end)
3080b57cec5SDimitry Andric         end = final_end;
3090b57cec5SDimitry Andric       else {
3100b57cec5SDimitry Andric         // If we're not at the end of the text, make sure we break the line on
3110b57cec5SDimitry Andric         // white space.
3120b57cec5SDimitry Andric         while (end > start && actual_text[end] != ' ' &&
3130b57cec5SDimitry Andric                actual_text[end] != '\t' && actual_text[end] != '\n')
3140b57cec5SDimitry Andric           end--;
3150b57cec5SDimitry Andric       }
3160b57cec5SDimitry Andric 
3170b57cec5SDimitry Andric       sub_len = end - start;
3180b57cec5SDimitry Andric       if (start != 0)
3190b57cec5SDimitry Andric         strm.EOL();
3200b57cec5SDimitry Andric       strm.Indent();
3210b57cec5SDimitry Andric       assert(start < final_end);
3220b57cec5SDimitry Andric       assert(start + sub_len <= final_end);
3230b57cec5SDimitry Andric       strm.Write(actual_text.c_str() + start, sub_len);
3240b57cec5SDimitry Andric       start = end + 1;
3250b57cec5SDimitry Andric     }
3260b57cec5SDimitry Andric     strm.EOL();
3270b57cec5SDimitry Andric   }
3280b57cec5SDimitry Andric }
3290b57cec5SDimitry Andric 
3300b57cec5SDimitry Andric bool Options::SupportsLongOption(const char *long_option) {
3310b57cec5SDimitry Andric   if (!long_option || !long_option[0])
3320b57cec5SDimitry Andric     return false;
3330b57cec5SDimitry Andric 
3340b57cec5SDimitry Andric   auto opt_defs = GetDefinitions();
3350b57cec5SDimitry Andric   if (opt_defs.empty())
3360b57cec5SDimitry Andric     return false;
3370b57cec5SDimitry Andric 
3380b57cec5SDimitry Andric   const char *long_option_name = long_option;
3390b57cec5SDimitry Andric   if (long_option[0] == '-' && long_option[1] == '-')
3400b57cec5SDimitry Andric     long_option_name += 2;
3410b57cec5SDimitry Andric 
3420b57cec5SDimitry Andric   for (auto &def : opt_defs) {
3430b57cec5SDimitry Andric     if (!def.long_option)
3440b57cec5SDimitry Andric       continue;
3450b57cec5SDimitry Andric 
3460b57cec5SDimitry Andric     if (strcmp(def.long_option, long_option_name) == 0)
3470b57cec5SDimitry Andric       return true;
3480b57cec5SDimitry Andric   }
3490b57cec5SDimitry Andric 
3500b57cec5SDimitry Andric   return false;
3510b57cec5SDimitry Andric }
3520b57cec5SDimitry Andric 
3530b57cec5SDimitry Andric enum OptionDisplayType {
3540b57cec5SDimitry Andric   eDisplayBestOption,
3550b57cec5SDimitry Andric   eDisplayShortOption,
3560b57cec5SDimitry Andric   eDisplayLongOption
3570b57cec5SDimitry Andric };
3580b57cec5SDimitry Andric 
3590b57cec5SDimitry Andric static bool PrintOption(const OptionDefinition &opt_def,
3600b57cec5SDimitry Andric                         OptionDisplayType display_type, const char *header,
3610b57cec5SDimitry Andric                         const char *footer, bool show_optional, Stream &strm) {
362e8d8bef9SDimitry Andric   if (display_type == eDisplayShortOption && !opt_def.HasShortOption())
3630b57cec5SDimitry Andric     return false;
3640b57cec5SDimitry Andric 
3650b57cec5SDimitry Andric   if (header && header[0])
3660b57cec5SDimitry Andric     strm.PutCString(header);
3670b57cec5SDimitry Andric 
3680b57cec5SDimitry Andric   if (show_optional && !opt_def.required)
3690b57cec5SDimitry Andric     strm.PutChar('[');
3700b57cec5SDimitry Andric   const bool show_short_option =
371e8d8bef9SDimitry Andric       opt_def.HasShortOption() && display_type != eDisplayLongOption;
3720b57cec5SDimitry Andric   if (show_short_option)
3730b57cec5SDimitry Andric     strm.Printf("-%c", opt_def.short_option);
3740b57cec5SDimitry Andric   else
3750b57cec5SDimitry Andric     strm.Printf("--%s", opt_def.long_option);
3760b57cec5SDimitry Andric   switch (opt_def.option_has_arg) {
3770b57cec5SDimitry Andric   case OptionParser::eNoArgument:
3780b57cec5SDimitry Andric     break;
3790b57cec5SDimitry Andric   case OptionParser::eRequiredArgument:
3800b57cec5SDimitry Andric     strm.Printf(" <%s>", CommandObject::GetArgumentName(opt_def.argument_type));
3810b57cec5SDimitry Andric     break;
3820b57cec5SDimitry Andric 
3830b57cec5SDimitry Andric   case OptionParser::eOptionalArgument:
3840b57cec5SDimitry Andric     strm.Printf("%s[<%s>]", show_short_option ? "" : "=",
3850b57cec5SDimitry Andric                 CommandObject::GetArgumentName(opt_def.argument_type));
3860b57cec5SDimitry Andric     break;
3870b57cec5SDimitry Andric   }
3880b57cec5SDimitry Andric   if (show_optional && !opt_def.required)
3890b57cec5SDimitry Andric     strm.PutChar(']');
3900b57cec5SDimitry Andric   if (footer && footer[0])
3910b57cec5SDimitry Andric     strm.PutCString(footer);
3920b57cec5SDimitry Andric   return true;
3930b57cec5SDimitry Andric }
3940b57cec5SDimitry Andric 
39581ad6265SDimitry Andric void Options::GenerateOptionUsage(Stream &strm, CommandObject &cmd,
3960b57cec5SDimitry Andric                                   uint32_t screen_width) {
3970b57cec5SDimitry Andric   auto opt_defs = GetDefinitions();
3980b57cec5SDimitry Andric   const uint32_t save_indent_level = strm.GetIndentLevel();
39981ad6265SDimitry Andric   llvm::StringRef name = cmd.GetCommandName();
4000b57cec5SDimitry Andric   StreamString arguments_str;
40181ad6265SDimitry Andric   cmd.GetFormattedCommandArguments(arguments_str);
4020b57cec5SDimitry Andric 
40304eeddc0SDimitry Andric   const uint32_t num_options = NumCommandOptions();
40404eeddc0SDimitry Andric   if (num_options == 0)
40504eeddc0SDimitry Andric     return;
40604eeddc0SDimitry Andric 
40781ad6265SDimitry Andric   const bool only_print_args = cmd.IsDashDashCommand();
40804eeddc0SDimitry Andric   if (!only_print_args)
4090b57cec5SDimitry Andric     strm.PutCString("\nCommand Options Usage:\n");
4100b57cec5SDimitry Andric 
4110b57cec5SDimitry Andric   strm.IndentMore(2);
4120b57cec5SDimitry Andric 
4130b57cec5SDimitry Andric   // First, show each usage level set of options, e.g. <cmd> [options-for-
4140b57cec5SDimitry Andric   // level-0]
4150b57cec5SDimitry Andric   //                                                   <cmd>
4160b57cec5SDimitry Andric   //                                                   [options-for-level-1]
4170b57cec5SDimitry Andric   //                                                   etc.
4180b57cec5SDimitry Andric 
4190b57cec5SDimitry Andric   if (!only_print_args) {
42081ad6265SDimitry Andric     uint32_t num_option_sets = GetRequiredOptions().size();
4210b57cec5SDimitry Andric     for (uint32_t opt_set = 0; opt_set < num_option_sets; ++opt_set) {
4220b57cec5SDimitry Andric       if (opt_set > 0)
4230b57cec5SDimitry Andric         strm.Printf("\n");
4240b57cec5SDimitry Andric       strm.Indent(name);
4250b57cec5SDimitry Andric 
4260b57cec5SDimitry Andric       // Different option sets may require different args.
4270b57cec5SDimitry Andric       StreamString args_str;
42881ad6265SDimitry Andric       uint32_t opt_set_mask = 1 << opt_set;
42981ad6265SDimitry Andric       cmd.GetFormattedCommandArguments(args_str, opt_set_mask);
4300b57cec5SDimitry Andric 
4310b57cec5SDimitry Andric       // First go through and print all options that take no arguments as a
4320b57cec5SDimitry Andric       // single string. If a command has "-a" "-b" and "-c", this will show up
4330b57cec5SDimitry Andric       // as [-abc]
4340b57cec5SDimitry Andric 
43581ad6265SDimitry Andric       // We use a set here so that they will be sorted.
43681ad6265SDimitry Andric       std::set<int> required_options;
43781ad6265SDimitry Andric       std::set<int> optional_options;
43881ad6265SDimitry Andric 
4390b57cec5SDimitry Andric       for (auto &def : opt_defs) {
44081ad6265SDimitry Andric         if (def.usage_mask & opt_set_mask && def.HasShortOption() &&
4410b57cec5SDimitry Andric             def.option_has_arg == OptionParser::eNoArgument) {
44281ad6265SDimitry Andric           if (def.required) {
44381ad6265SDimitry Andric             required_options.insert(def.short_option);
44481ad6265SDimitry Andric           } else {
44581ad6265SDimitry Andric             optional_options.insert(def.short_option);
4460b57cec5SDimitry Andric           }
4470b57cec5SDimitry Andric         }
4480b57cec5SDimitry Andric       }
4490b57cec5SDimitry Andric 
45081ad6265SDimitry Andric       if (!required_options.empty()) {
45181ad6265SDimitry Andric         strm.PutCString(" -");
45281ad6265SDimitry Andric         for (int short_option : required_options)
45381ad6265SDimitry Andric           strm.PutChar(short_option);
4540b57cec5SDimitry Andric       }
45581ad6265SDimitry Andric 
45681ad6265SDimitry Andric       if (!optional_options.empty()) {
45781ad6265SDimitry Andric         strm.PutCString(" [-");
45881ad6265SDimitry Andric         for (int short_option : optional_options)
45981ad6265SDimitry Andric           strm.PutChar(short_option);
4600b57cec5SDimitry Andric         strm.PutChar(']');
4610b57cec5SDimitry Andric       }
4620b57cec5SDimitry Andric 
4630b57cec5SDimitry Andric       // First go through and print the required options (list them up front).
4640b57cec5SDimitry Andric       for (auto &def : opt_defs) {
46581ad6265SDimitry Andric         if (def.usage_mask & opt_set_mask && def.HasShortOption() &&
46681ad6265SDimitry Andric             def.required && def.option_has_arg != OptionParser::eNoArgument)
4670b57cec5SDimitry Andric           PrintOption(def, eDisplayBestOption, " ", nullptr, true, strm);
4680b57cec5SDimitry Andric       }
4690b57cec5SDimitry Andric 
4700b57cec5SDimitry Andric       // Now go through again, and this time only print the optional options.
4710b57cec5SDimitry Andric       for (auto &def : opt_defs) {
47281ad6265SDimitry Andric         if (def.usage_mask & opt_set_mask && !def.required &&
47381ad6265SDimitry Andric             def.option_has_arg != OptionParser::eNoArgument)
4740b57cec5SDimitry Andric           PrintOption(def, eDisplayBestOption, " ", nullptr, true, strm);
4750b57cec5SDimitry Andric       }
4760b57cec5SDimitry Andric 
4770b57cec5SDimitry Andric       if (args_str.GetSize() > 0) {
47881ad6265SDimitry Andric         if (cmd.WantsRawCommandString())
4790b57cec5SDimitry Andric           strm.Printf(" --");
4800b57cec5SDimitry Andric         strm << " " << args_str.GetString();
4810b57cec5SDimitry Andric       }
4820b57cec5SDimitry Andric     }
4830b57cec5SDimitry Andric   }
4840b57cec5SDimitry Andric 
48581ad6265SDimitry Andric   if ((only_print_args || cmd.WantsRawCommandString()) &&
4860b57cec5SDimitry Andric       arguments_str.GetSize() > 0) {
4870b57cec5SDimitry Andric     if (!only_print_args)
4880b57cec5SDimitry Andric       strm.PutChar('\n');
4890b57cec5SDimitry Andric     strm.Indent(name);
4900b57cec5SDimitry Andric     strm << " " << arguments_str.GetString();
4910b57cec5SDimitry Andric   }
4920b57cec5SDimitry Andric 
49304eeddc0SDimitry Andric   if (!only_print_args) {
4940b57cec5SDimitry Andric     strm.Printf("\n\n");
4950b57cec5SDimitry Andric 
4960b57cec5SDimitry Andric     // Now print out all the detailed information about the various options:
4970b57cec5SDimitry Andric     // long form, short form and help text:
4980b57cec5SDimitry Andric     //   -short <argument> ( --long_name <argument> )
4990b57cec5SDimitry Andric     //   help text
5000b57cec5SDimitry Andric 
5010b57cec5SDimitry Andric     strm.IndentMore(5);
5020b57cec5SDimitry Andric 
50381ad6265SDimitry Andric     // Put the command options in a sorted container, so we can output
50481ad6265SDimitry Andric     // them alphabetically by short_option.
50581ad6265SDimitry Andric     std::multimap<int, uint32_t> options_ordered;
50681ad6265SDimitry Andric     for (auto def : llvm::enumerate(opt_defs))
50781ad6265SDimitry Andric       options_ordered.insert(
50881ad6265SDimitry Andric           std::make_pair(def.value().short_option, def.index()));
5090b57cec5SDimitry Andric 
51081ad6265SDimitry Andric     // Go through each option, find the table entry and write out the detailed
51181ad6265SDimitry Andric     // help information for that option.
5120b57cec5SDimitry Andric 
5130b57cec5SDimitry Andric     bool first_option_printed = false;
5140b57cec5SDimitry Andric 
51581ad6265SDimitry Andric     for (auto pos : options_ordered) {
5160b57cec5SDimitry Andric       // Put a newline separation between arguments
5170b57cec5SDimitry Andric       if (first_option_printed)
5180b57cec5SDimitry Andric         strm.EOL();
5190b57cec5SDimitry Andric       else
5200b57cec5SDimitry Andric         first_option_printed = true;
5210b57cec5SDimitry Andric 
52281ad6265SDimitry Andric       OptionDefinition opt_def = opt_defs[pos.second];
5230b57cec5SDimitry Andric 
5240b57cec5SDimitry Andric       strm.Indent();
52581ad6265SDimitry Andric       if (opt_def.short_option && opt_def.HasShortOption()) {
52681ad6265SDimitry Andric         PrintOption(opt_def, eDisplayShortOption, nullptr, nullptr, false,
5270b57cec5SDimitry Andric                     strm);
52881ad6265SDimitry Andric         PrintOption(opt_def, eDisplayLongOption, " ( ", " )", false, strm);
5290b57cec5SDimitry Andric       } else {
5300b57cec5SDimitry Andric         // Short option is not printable, just print long option
53181ad6265SDimitry Andric         PrintOption(opt_def, eDisplayLongOption, nullptr, nullptr, false, strm);
5320b57cec5SDimitry Andric       }
5330b57cec5SDimitry Andric       strm.EOL();
5340b57cec5SDimitry Andric 
5350b57cec5SDimitry Andric       strm.IndentMore(5);
5360b57cec5SDimitry Andric 
53781ad6265SDimitry Andric       if (opt_def.usage_text)
53881ad6265SDimitry Andric         OutputFormattedUsageText(strm, opt_def, screen_width);
53981ad6265SDimitry Andric       if (!opt_def.enum_values.empty()) {
5400b57cec5SDimitry Andric         strm.Indent();
5410b57cec5SDimitry Andric         strm.Printf("Values: ");
5420b57cec5SDimitry Andric         bool is_first = true;
54381ad6265SDimitry Andric         for (const auto &enum_value : opt_def.enum_values) {
5440b57cec5SDimitry Andric           if (is_first) {
5450b57cec5SDimitry Andric             strm.Printf("%s", enum_value.string_value);
5460b57cec5SDimitry Andric             is_first = false;
5470b57cec5SDimitry Andric           }
5480b57cec5SDimitry Andric           else
5490b57cec5SDimitry Andric             strm.Printf(" | %s", enum_value.string_value);
5500b57cec5SDimitry Andric         }
5510b57cec5SDimitry Andric         strm.EOL();
5520b57cec5SDimitry Andric       }
5530b57cec5SDimitry Andric       strm.IndentLess(5);
5540b57cec5SDimitry Andric     }
5550b57cec5SDimitry Andric   }
5560b57cec5SDimitry Andric 
5570b57cec5SDimitry Andric   // Restore the indent level
5580b57cec5SDimitry Andric   strm.SetIndentLevel(save_indent_level);
5590b57cec5SDimitry Andric }
5600b57cec5SDimitry Andric 
5610b57cec5SDimitry Andric // This function is called when we have been given a potentially incomplete set
5620b57cec5SDimitry Andric // of options, such as when an alias has been defined (more options might be
5630b57cec5SDimitry Andric // added at at the time the alias is invoked).  We need to verify that the
5640b57cec5SDimitry Andric // options in the set m_seen_options are all part of a set that may be used
5650b57cec5SDimitry Andric // together, but m_seen_options may be missing some of the "required" options.
5660b57cec5SDimitry Andric 
5670b57cec5SDimitry Andric bool Options::VerifyPartialOptions(CommandReturnObject &result) {
5680b57cec5SDimitry Andric   bool options_are_valid = false;
5690b57cec5SDimitry Andric 
5700b57cec5SDimitry Andric   int num_levels = GetRequiredOptions().size();
5710b57cec5SDimitry Andric   if (num_levels) {
5720b57cec5SDimitry Andric     for (int i = 0; i < num_levels && !options_are_valid; ++i) {
5730b57cec5SDimitry Andric       // In this case we are treating all options as optional rather than
5740b57cec5SDimitry Andric       // required. Therefore a set of options is correct if m_seen_options is a
5750b57cec5SDimitry Andric       // subset of the union of m_required_options and m_optional_options.
5760b57cec5SDimitry Andric       OptionSet union_set;
5770b57cec5SDimitry Andric       OptionsSetUnion(GetRequiredOptions()[i], GetOptionalOptions()[i],
5780b57cec5SDimitry Andric                       union_set);
5790b57cec5SDimitry Andric       if (IsASubset(m_seen_options, union_set))
5800b57cec5SDimitry Andric         options_are_valid = true;
5810b57cec5SDimitry Andric     }
5820b57cec5SDimitry Andric   }
5830b57cec5SDimitry Andric 
5840b57cec5SDimitry Andric   return options_are_valid;
5850b57cec5SDimitry Andric }
5860b57cec5SDimitry Andric 
5870b57cec5SDimitry Andric bool Options::HandleOptionCompletion(CompletionRequest &request,
5880b57cec5SDimitry Andric                                      OptionElementVector &opt_element_vector,
5890b57cec5SDimitry Andric                                      CommandInterpreter &interpreter) {
5900b57cec5SDimitry Andric   // For now we just scan the completions to see if the cursor position is in
5910b57cec5SDimitry Andric   // an option or its argument.  Otherwise we'll call HandleArgumentCompletion.
5920b57cec5SDimitry Andric   // In the future we can use completion to validate options as well if we
5930b57cec5SDimitry Andric   // want.
5940b57cec5SDimitry Andric 
5950b57cec5SDimitry Andric   auto opt_defs = GetDefinitions();
5960b57cec5SDimitry Andric 
5979dba64beSDimitry Andric   llvm::StringRef cur_opt_str = request.GetCursorArgumentPrefix();
5980b57cec5SDimitry Andric 
5990b57cec5SDimitry Andric   for (size_t i = 0; i < opt_element_vector.size(); i++) {
6009dba64beSDimitry Andric     size_t opt_pos = static_cast<size_t>(opt_element_vector[i].opt_pos);
6019dba64beSDimitry Andric     size_t opt_arg_pos = static_cast<size_t>(opt_element_vector[i].opt_arg_pos);
6020b57cec5SDimitry Andric     int opt_defs_index = opt_element_vector[i].opt_defs_index;
6030b57cec5SDimitry Andric     if (opt_pos == request.GetCursorIndex()) {
6040b57cec5SDimitry Andric       // We're completing the option itself.
6050b57cec5SDimitry Andric 
6060b57cec5SDimitry Andric       if (opt_defs_index == OptionArgElement::eBareDash) {
6070b57cec5SDimitry Andric         // We're completing a bare dash.  That means all options are open.
6080b57cec5SDimitry Andric         // FIXME: We should scan the other options provided and only complete
6090b57cec5SDimitry Andric         // options
6100b57cec5SDimitry Andric         // within the option group they belong to.
6119dba64beSDimitry Andric         std::string opt_str = "-a";
6120b57cec5SDimitry Andric 
6130b57cec5SDimitry Andric         for (auto &def : opt_defs) {
6140b57cec5SDimitry Andric           if (!def.short_option)
6150b57cec5SDimitry Andric             continue;
6160b57cec5SDimitry Andric           opt_str[1] = def.short_option;
6179dba64beSDimitry Andric           request.AddCompletion(opt_str, def.usage_text);
6180b57cec5SDimitry Andric         }
6190b57cec5SDimitry Andric 
6200b57cec5SDimitry Andric         return true;
6210b57cec5SDimitry Andric       } else if (opt_defs_index == OptionArgElement::eBareDoubleDash) {
6220b57cec5SDimitry Andric         std::string full_name("--");
6230b57cec5SDimitry Andric         for (auto &def : opt_defs) {
6240b57cec5SDimitry Andric           if (!def.short_option)
6250b57cec5SDimitry Andric             continue;
6260b57cec5SDimitry Andric 
6270b57cec5SDimitry Andric           full_name.erase(full_name.begin() + 2, full_name.end());
6280b57cec5SDimitry Andric           full_name.append(def.long_option);
6299dba64beSDimitry Andric           request.AddCompletion(full_name, def.usage_text);
6300b57cec5SDimitry Andric         }
6310b57cec5SDimitry Andric         return true;
6320b57cec5SDimitry Andric       } else if (opt_defs_index != OptionArgElement::eUnrecognizedArg) {
6330b57cec5SDimitry Andric         // We recognized it, if it an incomplete long option, complete it
6340b57cec5SDimitry Andric         // anyway (getopt_long_only is happy with shortest unique string, but
6350b57cec5SDimitry Andric         // it's still a nice thing to do.)  Otherwise return The string so the
6360b57cec5SDimitry Andric         // upper level code will know this is a full match and add the " ".
6379dba64beSDimitry Andric         const OptionDefinition &opt = opt_defs[opt_defs_index];
6389dba64beSDimitry Andric         llvm::StringRef long_option = opt.long_option;
6395f757f3fSDimitry Andric         if (cur_opt_str.starts_with("--") && cur_opt_str != long_option) {
6409dba64beSDimitry Andric           request.AddCompletion("--" + long_option.str(), opt.usage_text);
6410b57cec5SDimitry Andric           return true;
6429dba64beSDimitry Andric         } else
6439dba64beSDimitry Andric           request.AddCompletion(request.GetCursorArgumentPrefix());
6440b57cec5SDimitry Andric         return true;
6450b57cec5SDimitry Andric       } else {
6460b57cec5SDimitry Andric         // FIXME - not handling wrong options yet:
6470b57cec5SDimitry Andric         // Check to see if they are writing a long option & complete it.
6480b57cec5SDimitry Andric         // I think we will only get in here if the long option table has two
6490b57cec5SDimitry Andric         // elements
6500b57cec5SDimitry Andric         // that are not unique up to this point.  getopt_long_only does
6510b57cec5SDimitry Andric         // shortest unique match for long options already.
6529dba64beSDimitry Andric         if (cur_opt_str.consume_front("--")) {
6530b57cec5SDimitry Andric           for (auto &def : opt_defs) {
6549dba64beSDimitry Andric             llvm::StringRef long_option(def.long_option);
6555f757f3fSDimitry Andric             if (long_option.starts_with(cur_opt_str))
6569dba64beSDimitry Andric               request.AddCompletion("--" + long_option.str(), def.usage_text);
6570b57cec5SDimitry Andric           }
6580b57cec5SDimitry Andric         }
6590b57cec5SDimitry Andric         return true;
6600b57cec5SDimitry Andric       }
6610b57cec5SDimitry Andric 
6620b57cec5SDimitry Andric     } else if (opt_arg_pos == request.GetCursorIndex()) {
6630b57cec5SDimitry Andric       // Okay the cursor is on the completion of an argument. See if it has a
6640b57cec5SDimitry Andric       // completion, otherwise return no matches.
6650b57cec5SDimitry Andric       if (opt_defs_index != -1) {
6669dba64beSDimitry Andric         HandleOptionArgumentCompletion(request, opt_element_vector, i,
6670b57cec5SDimitry Andric                                        interpreter);
6680b57cec5SDimitry Andric         return true;
6690b57cec5SDimitry Andric       } else {
6700b57cec5SDimitry Andric         // No completion callback means no completions...
6710b57cec5SDimitry Andric         return true;
6720b57cec5SDimitry Andric       }
6730b57cec5SDimitry Andric 
6740b57cec5SDimitry Andric     } else {
6750b57cec5SDimitry Andric       // Not the last element, keep going.
6760b57cec5SDimitry Andric       continue;
6770b57cec5SDimitry Andric     }
6780b57cec5SDimitry Andric   }
6790b57cec5SDimitry Andric   return false;
6800b57cec5SDimitry Andric }
6810b57cec5SDimitry Andric 
6829dba64beSDimitry Andric void Options::HandleOptionArgumentCompletion(
6830b57cec5SDimitry Andric     CompletionRequest &request, OptionElementVector &opt_element_vector,
6840b57cec5SDimitry Andric     int opt_element_index, CommandInterpreter &interpreter) {
6850b57cec5SDimitry Andric   auto opt_defs = GetDefinitions();
6860b57cec5SDimitry Andric   std::unique_ptr<SearchFilter> filter_up;
6870b57cec5SDimitry Andric 
6880b57cec5SDimitry Andric   int opt_defs_index = opt_element_vector[opt_element_index].opt_defs_index;
6890b57cec5SDimitry Andric 
6900b57cec5SDimitry Andric   // See if this is an enumeration type option, and if so complete it here:
6910b57cec5SDimitry Andric 
6920b57cec5SDimitry Andric   const auto &enum_values = opt_defs[opt_defs_index].enum_values;
6939dba64beSDimitry Andric   if (!enum_values.empty())
6949dba64beSDimitry Andric     for (const auto &enum_value : enum_values)
6959dba64beSDimitry Andric       request.TryCompleteCurrentArg(enum_value.string_value);
6960b57cec5SDimitry Andric 
6970b57cec5SDimitry Andric   // If this is a source file or symbol type completion, and  there is a -shlib
6980b57cec5SDimitry Andric   // option somewhere in the supplied arguments, then make a search filter for
6990b57cec5SDimitry Andric   // that shared library.
7000b57cec5SDimitry Andric   // FIXME: Do we want to also have an "OptionType" so we don't have to match
7010b57cec5SDimitry Andric   // string names?
7020b57cec5SDimitry Andric 
7030b57cec5SDimitry Andric   uint32_t completion_mask = opt_defs[opt_defs_index].completion_type;
7040b57cec5SDimitry Andric 
7050b57cec5SDimitry Andric   if (completion_mask == 0) {
7060b57cec5SDimitry Andric     lldb::CommandArgumentType option_arg_type =
7070b57cec5SDimitry Andric         opt_defs[opt_defs_index].argument_type;
7080b57cec5SDimitry Andric     if (option_arg_type != eArgTypeNone) {
7090b57cec5SDimitry Andric       const CommandObject::ArgumentTableEntry *arg_entry =
7100b57cec5SDimitry Andric           CommandObject::FindArgumentDataByType(
7110b57cec5SDimitry Andric               opt_defs[opt_defs_index].argument_type);
7120b57cec5SDimitry Andric       if (arg_entry)
7130b57cec5SDimitry Andric         completion_mask = arg_entry->completion_type;
7140b57cec5SDimitry Andric     }
7150b57cec5SDimitry Andric   }
7160b57cec5SDimitry Andric 
71706c3fb27SDimitry Andric   if (completion_mask & lldb::eSourceFileCompletion ||
71806c3fb27SDimitry Andric       completion_mask & lldb::eSymbolCompletion) {
7190b57cec5SDimitry Andric     for (size_t i = 0; i < opt_element_vector.size(); i++) {
7200b57cec5SDimitry Andric       int cur_defs_index = opt_element_vector[i].opt_defs_index;
7210b57cec5SDimitry Andric 
7220b57cec5SDimitry Andric       // trying to use <0 indices will definitely cause problems
7230b57cec5SDimitry Andric       if (cur_defs_index == OptionArgElement::eUnrecognizedArg ||
7240b57cec5SDimitry Andric           cur_defs_index == OptionArgElement::eBareDash ||
7250b57cec5SDimitry Andric           cur_defs_index == OptionArgElement::eBareDoubleDash)
7260b57cec5SDimitry Andric         continue;
7270b57cec5SDimitry Andric 
7280b57cec5SDimitry Andric       int cur_arg_pos = opt_element_vector[i].opt_arg_pos;
7290b57cec5SDimitry Andric       const char *cur_opt_name = opt_defs[cur_defs_index].long_option;
7300b57cec5SDimitry Andric 
7310b57cec5SDimitry Andric       // If this is the "shlib" option and there was an argument provided,
7320b57cec5SDimitry Andric       // restrict it to that shared library.
7330b57cec5SDimitry Andric       if (cur_opt_name && strcmp(cur_opt_name, "shlib") == 0 &&
7340b57cec5SDimitry Andric           cur_arg_pos != -1) {
7350b57cec5SDimitry Andric         const char *module_name =
7360b57cec5SDimitry Andric             request.GetParsedLine().GetArgumentAtIndex(cur_arg_pos);
7370b57cec5SDimitry Andric         if (module_name) {
7380b57cec5SDimitry Andric           FileSpec module_spec(module_name);
7390b57cec5SDimitry Andric           lldb::TargetSP target_sp =
7400b57cec5SDimitry Andric               interpreter.GetDebugger().GetSelectedTarget();
7410b57cec5SDimitry Andric           // Search filters require a target...
7420b57cec5SDimitry Andric           if (target_sp)
7435ffd83dbSDimitry Andric             filter_up =
7445ffd83dbSDimitry Andric                 std::make_unique<SearchFilterByModule>(target_sp, module_spec);
7450b57cec5SDimitry Andric         }
7460b57cec5SDimitry Andric         break;
7470b57cec5SDimitry Andric       }
7480b57cec5SDimitry Andric     }
7490b57cec5SDimitry Andric   }
7500b57cec5SDimitry Andric 
75106c3fb27SDimitry Andric   lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
7520b57cec5SDimitry Andric       interpreter, completion_mask, request, filter_up.get());
7530b57cec5SDimitry Andric }
7540b57cec5SDimitry Andric 
7550b57cec5SDimitry Andric void OptionGroupOptions::Append(OptionGroup *group) {
7560b57cec5SDimitry Andric   auto group_option_defs = group->GetDefinitions();
7570b57cec5SDimitry Andric   for (uint32_t i = 0; i < group_option_defs.size(); ++i) {
7580b57cec5SDimitry Andric     m_option_infos.push_back(OptionInfo(group, i));
7590b57cec5SDimitry Andric     m_option_defs.push_back(group_option_defs[i]);
7600b57cec5SDimitry Andric   }
7610b57cec5SDimitry Andric }
7620b57cec5SDimitry Andric 
7630b57cec5SDimitry Andric const OptionGroup *OptionGroupOptions::GetGroupWithOption(char short_opt) {
7640b57cec5SDimitry Andric   for (uint32_t i = 0; i < m_option_defs.size(); i++) {
7650b57cec5SDimitry Andric     OptionDefinition opt_def = m_option_defs[i];
7660b57cec5SDimitry Andric     if (opt_def.short_option == short_opt)
7670b57cec5SDimitry Andric       return m_option_infos[i].option_group;
7680b57cec5SDimitry Andric   }
7690b57cec5SDimitry Andric   return nullptr;
7700b57cec5SDimitry Andric }
7710b57cec5SDimitry Andric 
7720b57cec5SDimitry Andric void OptionGroupOptions::Append(OptionGroup *group, uint32_t src_mask,
7730b57cec5SDimitry Andric                                 uint32_t dst_mask) {
7740b57cec5SDimitry Andric   auto group_option_defs = group->GetDefinitions();
7750b57cec5SDimitry Andric   for (uint32_t i = 0; i < group_option_defs.size(); ++i) {
7760b57cec5SDimitry Andric     if (group_option_defs[i].usage_mask & src_mask) {
7770b57cec5SDimitry Andric       m_option_infos.push_back(OptionInfo(group, i));
7780b57cec5SDimitry Andric       m_option_defs.push_back(group_option_defs[i]);
7790b57cec5SDimitry Andric       m_option_defs.back().usage_mask = dst_mask;
7800b57cec5SDimitry Andric     }
7810b57cec5SDimitry Andric   }
7820b57cec5SDimitry Andric }
7830b57cec5SDimitry Andric 
78406c3fb27SDimitry Andric void OptionGroupOptions::Append(
78506c3fb27SDimitry Andric     OptionGroup *group, llvm::ArrayRef<llvm::StringRef> exclude_long_options) {
78606c3fb27SDimitry Andric   auto group_option_defs = group->GetDefinitions();
78706c3fb27SDimitry Andric   for (uint32_t i = 0; i < group_option_defs.size(); ++i) {
78806c3fb27SDimitry Andric     const auto &definition = group_option_defs[i];
78906c3fb27SDimitry Andric     if (llvm::is_contained(exclude_long_options, definition.long_option))
79006c3fb27SDimitry Andric       continue;
79106c3fb27SDimitry Andric 
79206c3fb27SDimitry Andric     m_option_infos.push_back(OptionInfo(group, i));
79306c3fb27SDimitry Andric     m_option_defs.push_back(definition);
79406c3fb27SDimitry Andric   }
79506c3fb27SDimitry Andric }
79606c3fb27SDimitry Andric 
7970b57cec5SDimitry Andric void OptionGroupOptions::Finalize() {
7980b57cec5SDimitry Andric   m_did_finalize = true;
7990b57cec5SDimitry Andric }
8000b57cec5SDimitry Andric 
8010b57cec5SDimitry Andric Status OptionGroupOptions::SetOptionValue(uint32_t option_idx,
8020b57cec5SDimitry Andric                                           llvm::StringRef option_value,
8030b57cec5SDimitry Andric                                           ExecutionContext *execution_context) {
8040b57cec5SDimitry Andric   // After calling OptionGroupOptions::Append(...), you must finalize the
8050b57cec5SDimitry Andric   // groups by calling OptionGroupOptions::Finlize()
8060b57cec5SDimitry Andric   assert(m_did_finalize);
8070b57cec5SDimitry Andric   Status error;
8080b57cec5SDimitry Andric   if (option_idx < m_option_infos.size()) {
8090b57cec5SDimitry Andric     error = m_option_infos[option_idx].option_group->SetOptionValue(
8100b57cec5SDimitry Andric         m_option_infos[option_idx].option_index, option_value,
8110b57cec5SDimitry Andric         execution_context);
8120b57cec5SDimitry Andric 
8130b57cec5SDimitry Andric   } else {
8140b57cec5SDimitry Andric     error.SetErrorString("invalid option index"); // Shouldn't happen...
8150b57cec5SDimitry Andric   }
8160b57cec5SDimitry Andric   return error;
8170b57cec5SDimitry Andric }
8180b57cec5SDimitry Andric 
8190b57cec5SDimitry Andric void OptionGroupOptions::OptionParsingStarting(
8200b57cec5SDimitry Andric     ExecutionContext *execution_context) {
8210b57cec5SDimitry Andric   std::set<OptionGroup *> group_set;
8220b57cec5SDimitry Andric   OptionInfos::iterator pos, end = m_option_infos.end();
8230b57cec5SDimitry Andric   for (pos = m_option_infos.begin(); pos != end; ++pos) {
8240b57cec5SDimitry Andric     OptionGroup *group = pos->option_group;
8250b57cec5SDimitry Andric     if (group_set.find(group) == group_set.end()) {
8260b57cec5SDimitry Andric       group->OptionParsingStarting(execution_context);
8270b57cec5SDimitry Andric       group_set.insert(group);
8280b57cec5SDimitry Andric     }
8290b57cec5SDimitry Andric   }
8300b57cec5SDimitry Andric }
8310b57cec5SDimitry Andric Status
8320b57cec5SDimitry Andric OptionGroupOptions::OptionParsingFinished(ExecutionContext *execution_context) {
8330b57cec5SDimitry Andric   std::set<OptionGroup *> group_set;
8340b57cec5SDimitry Andric   Status error;
8350b57cec5SDimitry Andric   OptionInfos::iterator pos, end = m_option_infos.end();
8360b57cec5SDimitry Andric   for (pos = m_option_infos.begin(); pos != end; ++pos) {
8370b57cec5SDimitry Andric     OptionGroup *group = pos->option_group;
8380b57cec5SDimitry Andric     if (group_set.find(group) == group_set.end()) {
8390b57cec5SDimitry Andric       error = group->OptionParsingFinished(execution_context);
8400b57cec5SDimitry Andric       group_set.insert(group);
8410b57cec5SDimitry Andric       if (error.Fail())
8420b57cec5SDimitry Andric         return error;
8430b57cec5SDimitry Andric     }
8440b57cec5SDimitry Andric   }
8450b57cec5SDimitry Andric   return error;
8460b57cec5SDimitry Andric }
8470b57cec5SDimitry Andric 
8480b57cec5SDimitry Andric // OptionParser permutes the arguments while processing them, so we create a
8490b57cec5SDimitry Andric // temporary array holding to avoid modification of the input arguments. The
8500b57cec5SDimitry Andric // options themselves are never modified, but the API expects a char * anyway,
8510b57cec5SDimitry Andric // hence the const_cast.
8520b57cec5SDimitry Andric static std::vector<char *> GetArgvForParsing(const Args &args) {
8530b57cec5SDimitry Andric   std::vector<char *> result;
8540b57cec5SDimitry Andric   // OptionParser always skips the first argument as it is based on getopt().
8550b57cec5SDimitry Andric   result.push_back(const_cast<char *>("<FAKE-ARG0>"));
8560b57cec5SDimitry Andric   for (const Args::ArgEntry &entry : args)
8570b57cec5SDimitry Andric     result.push_back(const_cast<char *>(entry.c_str()));
8580b57cec5SDimitry Andric   result.push_back(nullptr);
8590b57cec5SDimitry Andric   return result;
8600b57cec5SDimitry Andric }
8610b57cec5SDimitry Andric 
8620b57cec5SDimitry Andric // Given a permuted argument, find it's position in the original Args vector.
8630b57cec5SDimitry Andric static Args::const_iterator FindOriginalIter(const char *arg,
8640b57cec5SDimitry Andric                                              const Args &original) {
8650b57cec5SDimitry Andric   return llvm::find_if(
8660b57cec5SDimitry Andric       original, [arg](const Args::ArgEntry &D) { return D.c_str() == arg; });
8670b57cec5SDimitry Andric }
8680b57cec5SDimitry Andric 
8690b57cec5SDimitry Andric // Given a permuted argument, find it's index in the original Args vector.
8700b57cec5SDimitry Andric static size_t FindOriginalIndex(const char *arg, const Args &original) {
8710b57cec5SDimitry Andric   return std::distance(original.begin(), FindOriginalIter(arg, original));
8720b57cec5SDimitry Andric }
8730b57cec5SDimitry Andric 
8740b57cec5SDimitry Andric // Construct a new Args object, consisting of the entries from the original
8750b57cec5SDimitry Andric // arguments, but in the permuted order.
8760b57cec5SDimitry Andric static Args ReconstituteArgsAfterParsing(llvm::ArrayRef<char *> parsed,
8770b57cec5SDimitry Andric                                          const Args &original) {
8780b57cec5SDimitry Andric   Args result;
8790b57cec5SDimitry Andric   for (const char *arg : parsed) {
8800b57cec5SDimitry Andric     auto pos = FindOriginalIter(arg, original);
8810b57cec5SDimitry Andric     assert(pos != original.end());
8829dba64beSDimitry Andric     result.AppendArgument(pos->ref(), pos->GetQuoteChar());
8830b57cec5SDimitry Andric   }
8840b57cec5SDimitry Andric   return result;
8850b57cec5SDimitry Andric }
8860b57cec5SDimitry Andric 
8870b57cec5SDimitry Andric static size_t FindArgumentIndexForOption(const Args &args,
8880b57cec5SDimitry Andric                                          const Option &long_option) {
8890b57cec5SDimitry Andric   std::string short_opt = llvm::formatv("-{0}", char(long_option.val)).str();
8900b57cec5SDimitry Andric   std::string long_opt =
8915ffd83dbSDimitry Andric       std::string(llvm::formatv("--{0}", long_option.definition->long_option));
8920b57cec5SDimitry Andric   for (const auto &entry : llvm::enumerate(args)) {
8935f757f3fSDimitry Andric     if (entry.value().ref().starts_with(short_opt) ||
8945f757f3fSDimitry Andric         entry.value().ref().starts_with(long_opt))
8950b57cec5SDimitry Andric       return entry.index();
8960b57cec5SDimitry Andric   }
8970b57cec5SDimitry Andric 
8980b57cec5SDimitry Andric   return size_t(-1);
8990b57cec5SDimitry Andric }
9000b57cec5SDimitry Andric 
9010b57cec5SDimitry Andric static std::string BuildShortOptions(const Option *long_options) {
9020b57cec5SDimitry Andric   std::string storage;
9030b57cec5SDimitry Andric   llvm::raw_string_ostream sstr(storage);
9040b57cec5SDimitry Andric 
9050b57cec5SDimitry Andric   // Leading : tells getopt to return a : for a missing option argument AND to
9060b57cec5SDimitry Andric   // suppress error messages.
9070b57cec5SDimitry Andric   sstr << ":";
9080b57cec5SDimitry Andric 
9090b57cec5SDimitry Andric   for (size_t i = 0; long_options[i].definition != nullptr; ++i) {
9100b57cec5SDimitry Andric     if (long_options[i].flag == nullptr) {
9110b57cec5SDimitry Andric       sstr << (char)long_options[i].val;
9120b57cec5SDimitry Andric       switch (long_options[i].definition->option_has_arg) {
9130b57cec5SDimitry Andric       default:
9140b57cec5SDimitry Andric       case OptionParser::eNoArgument:
9150b57cec5SDimitry Andric         break;
9160b57cec5SDimitry Andric       case OptionParser::eRequiredArgument:
9170b57cec5SDimitry Andric         sstr << ":";
9180b57cec5SDimitry Andric         break;
9190b57cec5SDimitry Andric       case OptionParser::eOptionalArgument:
9200b57cec5SDimitry Andric         sstr << "::";
9210b57cec5SDimitry Andric         break;
9220b57cec5SDimitry Andric       }
9230b57cec5SDimitry Andric     }
9240b57cec5SDimitry Andric   }
9250b57cec5SDimitry Andric   return std::move(sstr.str());
9260b57cec5SDimitry Andric }
9270b57cec5SDimitry Andric 
9280b57cec5SDimitry Andric llvm::Expected<Args> Options::ParseAlias(const Args &args,
9290b57cec5SDimitry Andric                                          OptionArgVector *option_arg_vector,
9300b57cec5SDimitry Andric                                          std::string &input_line) {
9310b57cec5SDimitry Andric   Option *long_options = GetLongOptions();
9320b57cec5SDimitry Andric 
9330b57cec5SDimitry Andric   if (long_options == nullptr) {
934*0fca6ea1SDimitry Andric     return llvm::createStringError("Invalid long options");
9350b57cec5SDimitry Andric   }
9360b57cec5SDimitry Andric 
9370b57cec5SDimitry Andric   std::string short_options = BuildShortOptions(long_options);
9380b57cec5SDimitry Andric 
9390b57cec5SDimitry Andric   Args args_copy = args;
9400b57cec5SDimitry Andric   std::vector<char *> argv = GetArgvForParsing(args);
9410b57cec5SDimitry Andric 
9420b57cec5SDimitry Andric   std::unique_lock<std::mutex> lock;
9430b57cec5SDimitry Andric   OptionParser::Prepare(lock);
9440b57cec5SDimitry Andric   int val;
9450b57cec5SDimitry Andric   while (true) {
9460b57cec5SDimitry Andric     int long_options_index = -1;
9470b57cec5SDimitry Andric     val = OptionParser::Parse(argv, short_options, long_options,
9480b57cec5SDimitry Andric                               &long_options_index);
9490b57cec5SDimitry Andric 
9500b57cec5SDimitry Andric     if (val == ':') {
9510b57cec5SDimitry Andric       return llvm::createStringError(llvm::inconvertibleErrorCode(),
9520b57cec5SDimitry Andric                                      "last option requires an argument");
9530b57cec5SDimitry Andric     }
9540b57cec5SDimitry Andric 
9550b57cec5SDimitry Andric     if (val == -1)
9560b57cec5SDimitry Andric       break;
9570b57cec5SDimitry Andric 
9580b57cec5SDimitry Andric     if (val == '?') {
959*0fca6ea1SDimitry Andric       return llvm::createStringError("Unknown or ambiguous option");
9600b57cec5SDimitry Andric     }
9610b57cec5SDimitry Andric 
9620b57cec5SDimitry Andric     if (val == 0)
9630b57cec5SDimitry Andric       continue;
9640b57cec5SDimitry Andric 
9650b57cec5SDimitry Andric     OptionSeen(val);
9660b57cec5SDimitry Andric 
9670b57cec5SDimitry Andric     // Look up the long option index
9680b57cec5SDimitry Andric     if (long_options_index == -1) {
9690b57cec5SDimitry Andric       for (int j = 0; long_options[j].definition || long_options[j].flag ||
9700b57cec5SDimitry Andric                       long_options[j].val;
9710b57cec5SDimitry Andric            ++j) {
9720b57cec5SDimitry Andric         if (long_options[j].val == val) {
9730b57cec5SDimitry Andric           long_options_index = j;
9740b57cec5SDimitry Andric           break;
9750b57cec5SDimitry Andric         }
9760b57cec5SDimitry Andric       }
9770b57cec5SDimitry Andric     }
9780b57cec5SDimitry Andric 
9790b57cec5SDimitry Andric     // See if the option takes an argument, and see if one was supplied.
9800b57cec5SDimitry Andric     if (long_options_index == -1) {
981*0fca6ea1SDimitry Andric       return llvm::createStringError(
982*0fca6ea1SDimitry Andric           llvm::formatv("Invalid option with value '{0}'.", char(val)).str());
9830b57cec5SDimitry Andric     }
9840b57cec5SDimitry Andric 
9850b57cec5SDimitry Andric     StreamString option_str;
9860b57cec5SDimitry Andric     option_str.Printf("-%c", val);
9870b57cec5SDimitry Andric     const OptionDefinition *def = long_options[long_options_index].definition;
9880b57cec5SDimitry Andric     int has_arg =
9890b57cec5SDimitry Andric         (def == nullptr) ? OptionParser::eNoArgument : def->option_has_arg;
9900b57cec5SDimitry Andric 
9910b57cec5SDimitry Andric     const char *option_arg = nullptr;
9920b57cec5SDimitry Andric     switch (has_arg) {
9930b57cec5SDimitry Andric     case OptionParser::eRequiredArgument:
9940b57cec5SDimitry Andric       if (OptionParser::GetOptionArgument() == nullptr) {
995*0fca6ea1SDimitry Andric         return llvm::createStringError(
9960b57cec5SDimitry Andric             llvm::formatv("Option '{0}' is missing argument specifier.",
9970b57cec5SDimitry Andric                           option_str.GetString())
998*0fca6ea1SDimitry Andric                 .str());
9990b57cec5SDimitry Andric       }
1000bdd1243dSDimitry Andric       [[fallthrough]];
10010b57cec5SDimitry Andric     case OptionParser::eOptionalArgument:
10020b57cec5SDimitry Andric       option_arg = OptionParser::GetOptionArgument();
1003bdd1243dSDimitry Andric       [[fallthrough]];
10040b57cec5SDimitry Andric     case OptionParser::eNoArgument:
10050b57cec5SDimitry Andric       break;
10060b57cec5SDimitry Andric     default:
1007*0fca6ea1SDimitry Andric       return llvm::createStringError(
10080b57cec5SDimitry Andric           llvm::formatv("error with options table; invalid value in has_arg "
10090b57cec5SDimitry Andric                         "field for option '{0}'.",
10100b57cec5SDimitry Andric                         char(val))
1011*0fca6ea1SDimitry Andric               .str());
10120b57cec5SDimitry Andric     }
10130b57cec5SDimitry Andric     // Find option in the argument list; also see if it was supposed to take an
10140b57cec5SDimitry Andric     // argument and if one was supplied.  Remove option (and argument, if
10150b57cec5SDimitry Andric     // given) from the argument list.  Also remove them from the
10160b57cec5SDimitry Andric     // raw_input_string, if one was passed in.
1017bdd1243dSDimitry Andric     // Note: We also need to preserve any option argument values that were
1018bdd1243dSDimitry Andric     // surrounded by backticks, as we lose track of them in the
1019bdd1243dSDimitry Andric     // option_args_vector.
10200b57cec5SDimitry Andric     size_t idx =
10210b57cec5SDimitry Andric         FindArgumentIndexForOption(args_copy, long_options[long_options_index]);
1022bdd1243dSDimitry Andric     std::string option_to_insert;
1023bdd1243dSDimitry Andric     if (option_arg) {
1024bdd1243dSDimitry Andric       if (idx != size_t(-1) && has_arg) {
1025bdd1243dSDimitry Andric         bool arg_has_backtick = args_copy[idx + 1].GetQuoteChar() == '`';
1026bdd1243dSDimitry Andric         if (arg_has_backtick)
1027bdd1243dSDimitry Andric           option_to_insert = "`";
1028bdd1243dSDimitry Andric         option_to_insert += option_arg;
1029bdd1243dSDimitry Andric         if (arg_has_backtick)
1030bdd1243dSDimitry Andric           option_to_insert += "`";
1031bdd1243dSDimitry Andric       } else
1032bdd1243dSDimitry Andric         option_to_insert = option_arg;
1033bdd1243dSDimitry Andric     } else
1034bdd1243dSDimitry Andric       option_to_insert = CommandInterpreter::g_no_argument;
1035bdd1243dSDimitry Andric 
1036bdd1243dSDimitry Andric     option_arg_vector->emplace_back(std::string(option_str.GetString()),
1037bdd1243dSDimitry Andric                                     has_arg, option_to_insert);
1038bdd1243dSDimitry Andric 
10390b57cec5SDimitry Andric     if (idx == size_t(-1))
10400b57cec5SDimitry Andric       continue;
10410b57cec5SDimitry Andric 
10420b57cec5SDimitry Andric     if (!input_line.empty()) {
1043bdd1243dSDimitry Andric       llvm::StringRef tmp_arg = args_copy[idx].ref();
10445ffd83dbSDimitry Andric       size_t pos = input_line.find(std::string(tmp_arg));
10450b57cec5SDimitry Andric       if (pos != std::string::npos)
10460b57cec5SDimitry Andric         input_line.erase(pos, tmp_arg.size());
10470b57cec5SDimitry Andric     }
10480b57cec5SDimitry Andric     args_copy.DeleteArgumentAtIndex(idx);
1049bdd1243dSDimitry Andric     if ((option_to_insert != CommandInterpreter::g_no_argument) &&
10500b57cec5SDimitry Andric         (OptionParser::GetOptionArgument() != nullptr) &&
10510b57cec5SDimitry Andric         (idx < args_copy.GetArgumentCount()) &&
10529dba64beSDimitry Andric         (args_copy[idx].ref() == OptionParser::GetOptionArgument())) {
10530b57cec5SDimitry Andric       if (input_line.size() > 0) {
1054bdd1243dSDimitry Andric         size_t pos = input_line.find(option_to_insert);
10550b57cec5SDimitry Andric         if (pos != std::string::npos)
1056bdd1243dSDimitry Andric           input_line.erase(pos, option_to_insert.size());
10570b57cec5SDimitry Andric       }
10580b57cec5SDimitry Andric       args_copy.DeleteArgumentAtIndex(idx);
10590b57cec5SDimitry Andric     }
10600b57cec5SDimitry Andric   }
10610b57cec5SDimitry Andric 
10620b57cec5SDimitry Andric   return std::move(args_copy);
10630b57cec5SDimitry Andric }
10640b57cec5SDimitry Andric 
10650b57cec5SDimitry Andric OptionElementVector Options::ParseForCompletion(const Args &args,
10660b57cec5SDimitry Andric                                                 uint32_t cursor_index) {
10670b57cec5SDimitry Andric   OptionElementVector option_element_vector;
10680b57cec5SDimitry Andric   Option *long_options = GetLongOptions();
10690b57cec5SDimitry Andric   option_element_vector.clear();
10700b57cec5SDimitry Andric 
10710b57cec5SDimitry Andric   if (long_options == nullptr)
10720b57cec5SDimitry Andric     return option_element_vector;
10730b57cec5SDimitry Andric 
10740b57cec5SDimitry Andric   std::string short_options = BuildShortOptions(long_options);
10750b57cec5SDimitry Andric 
10760b57cec5SDimitry Andric   std::unique_lock<std::mutex> lock;
10770b57cec5SDimitry Andric   OptionParser::Prepare(lock);
10780b57cec5SDimitry Andric   OptionParser::EnableError(false);
10790b57cec5SDimitry Andric 
10800b57cec5SDimitry Andric   int val;
10810b57cec5SDimitry Andric   auto opt_defs = GetDefinitions();
10820b57cec5SDimitry Andric 
10830b57cec5SDimitry Andric   std::vector<char *> dummy_vec = GetArgvForParsing(args);
10840b57cec5SDimitry Andric 
10850b57cec5SDimitry Andric   bool failed_once = false;
10860b57cec5SDimitry Andric   uint32_t dash_dash_pos = -1;
10870b57cec5SDimitry Andric 
10880b57cec5SDimitry Andric   while (true) {
10890b57cec5SDimitry Andric     bool missing_argument = false;
10900b57cec5SDimitry Andric     int long_options_index = -1;
10910b57cec5SDimitry Andric 
10920b57cec5SDimitry Andric     val = OptionParser::Parse(dummy_vec, short_options, long_options,
10930b57cec5SDimitry Andric                               &long_options_index);
10940b57cec5SDimitry Andric 
10950b57cec5SDimitry Andric     if (val == -1) {
10960b57cec5SDimitry Andric       // When we're completing a "--" which is the last option on line,
10970b57cec5SDimitry Andric       if (failed_once)
10980b57cec5SDimitry Andric         break;
10990b57cec5SDimitry Andric 
11000b57cec5SDimitry Andric       failed_once = true;
11010b57cec5SDimitry Andric 
11020b57cec5SDimitry Andric       // If this is a bare  "--" we mark it as such so we can complete it
11030b57cec5SDimitry Andric       // successfully later.  Handling the "--" is a little tricky, since that
11040b57cec5SDimitry Andric       // may mean end of options or arguments, or the user might want to
11050b57cec5SDimitry Andric       // complete options by long name.  I make this work by checking whether
11060b57cec5SDimitry Andric       // the cursor is in the "--" argument, and if so I assume we're
11070b57cec5SDimitry Andric       // completing the long option, otherwise I let it pass to
11080b57cec5SDimitry Andric       // OptionParser::Parse which will terminate the option parsing.  Note, in
11090b57cec5SDimitry Andric       // either case we continue parsing the line so we can figure out what
11100b57cec5SDimitry Andric       // other options were passed.  This will be useful when we come to
11110b57cec5SDimitry Andric       // restricting completions based on what other options we've seen on the
11120b57cec5SDimitry Andric       // line.
11130b57cec5SDimitry Andric 
11140b57cec5SDimitry Andric       if (static_cast<size_t>(OptionParser::GetOptionIndex()) <
11150b57cec5SDimitry Andric               dummy_vec.size() &&
11160b57cec5SDimitry Andric           (strcmp(dummy_vec[OptionParser::GetOptionIndex() - 1], "--") == 0)) {
11170b57cec5SDimitry Andric         dash_dash_pos = FindOriginalIndex(
11180b57cec5SDimitry Andric             dummy_vec[OptionParser::GetOptionIndex() - 1], args);
11190b57cec5SDimitry Andric         if (dash_dash_pos == cursor_index) {
11200b57cec5SDimitry Andric           option_element_vector.push_back(
11210b57cec5SDimitry Andric               OptionArgElement(OptionArgElement::eBareDoubleDash, dash_dash_pos,
11220b57cec5SDimitry Andric                                OptionArgElement::eBareDoubleDash));
11230b57cec5SDimitry Andric           continue;
11240b57cec5SDimitry Andric         } else
11250b57cec5SDimitry Andric           break;
11260b57cec5SDimitry Andric       } else
11270b57cec5SDimitry Andric         break;
11280b57cec5SDimitry Andric     } else if (val == '?') {
11290b57cec5SDimitry Andric       option_element_vector.push_back(OptionArgElement(
11300b57cec5SDimitry Andric           OptionArgElement::eUnrecognizedArg,
11310b57cec5SDimitry Andric           FindOriginalIndex(dummy_vec[OptionParser::GetOptionIndex() - 1],
11320b57cec5SDimitry Andric                             args),
11330b57cec5SDimitry Andric           OptionArgElement::eUnrecognizedArg));
11340b57cec5SDimitry Andric       continue;
11350b57cec5SDimitry Andric     } else if (val == 0) {
11360b57cec5SDimitry Andric       continue;
11370b57cec5SDimitry Andric     } else if (val == ':') {
11380b57cec5SDimitry Andric       // This is a missing argument.
11390b57cec5SDimitry Andric       val = OptionParser::GetOptionErrorCause();
11400b57cec5SDimitry Andric       missing_argument = true;
11410b57cec5SDimitry Andric     }
11420b57cec5SDimitry Andric 
11430b57cec5SDimitry Andric     OptionSeen(val);
11440b57cec5SDimitry Andric 
11450b57cec5SDimitry Andric     // Look up the long option index
11460b57cec5SDimitry Andric     if (long_options_index == -1) {
11470b57cec5SDimitry Andric       for (int j = 0; long_options[j].definition || long_options[j].flag ||
11480b57cec5SDimitry Andric                       long_options[j].val;
11490b57cec5SDimitry Andric            ++j) {
11500b57cec5SDimitry Andric         if (long_options[j].val == val) {
11510b57cec5SDimitry Andric           long_options_index = j;
11520b57cec5SDimitry Andric           break;
11530b57cec5SDimitry Andric         }
11540b57cec5SDimitry Andric       }
11550b57cec5SDimitry Andric     }
11560b57cec5SDimitry Andric 
11570b57cec5SDimitry Andric     // See if the option takes an argument, and see if one was supplied.
11580b57cec5SDimitry Andric     if (long_options_index >= 0) {
11590b57cec5SDimitry Andric       int opt_defs_index = -1;
11600b57cec5SDimitry Andric       for (size_t i = 0; i < opt_defs.size(); i++) {
11610b57cec5SDimitry Andric         if (opt_defs[i].short_option != val)
11620b57cec5SDimitry Andric           continue;
11630b57cec5SDimitry Andric         opt_defs_index = i;
11640b57cec5SDimitry Andric         break;
11650b57cec5SDimitry Andric       }
11660b57cec5SDimitry Andric 
11670b57cec5SDimitry Andric       const OptionDefinition *def = long_options[long_options_index].definition;
11680b57cec5SDimitry Andric       int has_arg =
11690b57cec5SDimitry Andric           (def == nullptr) ? OptionParser::eNoArgument : def->option_has_arg;
11700b57cec5SDimitry Andric       switch (has_arg) {
11710b57cec5SDimitry Andric       case OptionParser::eNoArgument:
11720b57cec5SDimitry Andric         option_element_vector.push_back(OptionArgElement(
11730b57cec5SDimitry Andric             opt_defs_index,
11740b57cec5SDimitry Andric             FindOriginalIndex(dummy_vec[OptionParser::GetOptionIndex() - 1],
11750b57cec5SDimitry Andric                               args),
11760b57cec5SDimitry Andric             0));
11770b57cec5SDimitry Andric         break;
11780b57cec5SDimitry Andric       case OptionParser::eRequiredArgument:
11790b57cec5SDimitry Andric         if (OptionParser::GetOptionArgument() != nullptr) {
11800b57cec5SDimitry Andric           int arg_index;
11810b57cec5SDimitry Andric           if (missing_argument)
11820b57cec5SDimitry Andric             arg_index = -1;
11830b57cec5SDimitry Andric           else
11840b57cec5SDimitry Andric             arg_index = OptionParser::GetOptionIndex() - 2;
11850b57cec5SDimitry Andric 
11860b57cec5SDimitry Andric           option_element_vector.push_back(OptionArgElement(
11870b57cec5SDimitry Andric               opt_defs_index,
11880b57cec5SDimitry Andric               FindOriginalIndex(dummy_vec[OptionParser::GetOptionIndex() - 2],
11890b57cec5SDimitry Andric                                 args),
11900b57cec5SDimitry Andric               arg_index));
11910b57cec5SDimitry Andric         } else {
11920b57cec5SDimitry Andric           option_element_vector.push_back(OptionArgElement(
11930b57cec5SDimitry Andric               opt_defs_index,
11940b57cec5SDimitry Andric               FindOriginalIndex(dummy_vec[OptionParser::GetOptionIndex() - 1],
11950b57cec5SDimitry Andric                                 args),
11960b57cec5SDimitry Andric               -1));
11970b57cec5SDimitry Andric         }
11980b57cec5SDimitry Andric         break;
11990b57cec5SDimitry Andric       case OptionParser::eOptionalArgument:
12000b57cec5SDimitry Andric         option_element_vector.push_back(OptionArgElement(
12010b57cec5SDimitry Andric             opt_defs_index,
12020b57cec5SDimitry Andric             FindOriginalIndex(dummy_vec[OptionParser::GetOptionIndex() - 2],
12030b57cec5SDimitry Andric                               args),
12040b57cec5SDimitry Andric             FindOriginalIndex(dummy_vec[OptionParser::GetOptionIndex() - 1],
12050b57cec5SDimitry Andric                               args)));
12060b57cec5SDimitry Andric         break;
12070b57cec5SDimitry Andric       default:
12080b57cec5SDimitry Andric         // The options table is messed up.  Here we'll just continue
12090b57cec5SDimitry Andric         option_element_vector.push_back(OptionArgElement(
12100b57cec5SDimitry Andric             OptionArgElement::eUnrecognizedArg,
12110b57cec5SDimitry Andric             FindOriginalIndex(dummy_vec[OptionParser::GetOptionIndex() - 1],
12120b57cec5SDimitry Andric                               args),
12130b57cec5SDimitry Andric             OptionArgElement::eUnrecognizedArg));
12140b57cec5SDimitry Andric         break;
12150b57cec5SDimitry Andric       }
12160b57cec5SDimitry Andric     } else {
12170b57cec5SDimitry Andric       option_element_vector.push_back(OptionArgElement(
12180b57cec5SDimitry Andric           OptionArgElement::eUnrecognizedArg,
12190b57cec5SDimitry Andric           FindOriginalIndex(dummy_vec[OptionParser::GetOptionIndex() - 1],
12200b57cec5SDimitry Andric                             args),
12210b57cec5SDimitry Andric           OptionArgElement::eUnrecognizedArg));
12220b57cec5SDimitry Andric     }
12230b57cec5SDimitry Andric   }
12240b57cec5SDimitry Andric 
12250b57cec5SDimitry Andric   // Finally we have to handle the case where the cursor index points at a
12260b57cec5SDimitry Andric   // single "-".  We want to mark that in the option_element_vector, but only
12270b57cec5SDimitry Andric   // if it is not after the "--".  But it turns out that OptionParser::Parse
12280b57cec5SDimitry Andric   // just ignores an isolated "-".  So we have to look it up by hand here.  We
12290b57cec5SDimitry Andric   // only care if it is AT the cursor position. Note, a single quoted dash is
12300b57cec5SDimitry Andric   // not the same as a single dash...
12310b57cec5SDimitry Andric 
12320b57cec5SDimitry Andric   const Args::ArgEntry &cursor = args[cursor_index];
12330b57cec5SDimitry Andric   if ((static_cast<int32_t>(dash_dash_pos) == -1 ||
12340b57cec5SDimitry Andric        cursor_index < dash_dash_pos) &&
12359dba64beSDimitry Andric       !cursor.IsQuoted() && cursor.ref() == "-") {
12360b57cec5SDimitry Andric     option_element_vector.push_back(
12370b57cec5SDimitry Andric         OptionArgElement(OptionArgElement::eBareDash, cursor_index,
12380b57cec5SDimitry Andric                          OptionArgElement::eBareDash));
12390b57cec5SDimitry Andric   }
12400b57cec5SDimitry Andric   return option_element_vector;
12410b57cec5SDimitry Andric }
12420b57cec5SDimitry Andric 
12430b57cec5SDimitry Andric llvm::Expected<Args> Options::Parse(const Args &args,
12440b57cec5SDimitry Andric                                     ExecutionContext *execution_context,
12450b57cec5SDimitry Andric                                     lldb::PlatformSP platform_sp,
12460b57cec5SDimitry Andric                                     bool require_validation) {
12470b57cec5SDimitry Andric   Status error;
12480b57cec5SDimitry Andric   Option *long_options = GetLongOptions();
12490b57cec5SDimitry Andric   if (long_options == nullptr) {
1250*0fca6ea1SDimitry Andric     return llvm::createStringError("Invalid long options.");
12510b57cec5SDimitry Andric   }
12520b57cec5SDimitry Andric 
12530b57cec5SDimitry Andric   std::string short_options = BuildShortOptions(long_options);
12540b57cec5SDimitry Andric   std::vector<char *> argv = GetArgvForParsing(args);
12550b57cec5SDimitry Andric   std::unique_lock<std::mutex> lock;
12560b57cec5SDimitry Andric   OptionParser::Prepare(lock);
12570b57cec5SDimitry Andric   int val;
12580b57cec5SDimitry Andric   while (true) {
12590b57cec5SDimitry Andric     int long_options_index = -1;
12600b57cec5SDimitry Andric     val = OptionParser::Parse(argv, short_options, long_options,
12610b57cec5SDimitry Andric                               &long_options_index);
12620b57cec5SDimitry Andric 
12630b57cec5SDimitry Andric     if (val == ':') {
1264e8d8bef9SDimitry Andric       error.SetErrorString("last option requires an argument");
12650b57cec5SDimitry Andric       break;
12660b57cec5SDimitry Andric     }
12670b57cec5SDimitry Andric 
12680b57cec5SDimitry Andric     if (val == -1)
12690b57cec5SDimitry Andric       break;
12700b57cec5SDimitry Andric 
12710b57cec5SDimitry Andric     // Did we get an error?
12720b57cec5SDimitry Andric     if (val == '?') {
1273e8d8bef9SDimitry Andric       error.SetErrorString("unknown or ambiguous option");
12740b57cec5SDimitry Andric       break;
12750b57cec5SDimitry Andric     }
12760b57cec5SDimitry Andric     // The option auto-set itself
12770b57cec5SDimitry Andric     if (val == 0)
12780b57cec5SDimitry Andric       continue;
12790b57cec5SDimitry Andric 
12800b57cec5SDimitry Andric     OptionSeen(val);
12810b57cec5SDimitry Andric 
12820b57cec5SDimitry Andric     // Lookup the long option index
12830b57cec5SDimitry Andric     if (long_options_index == -1) {
12840b57cec5SDimitry Andric       for (int i = 0; long_options[i].definition || long_options[i].flag ||
12850b57cec5SDimitry Andric                       long_options[i].val;
12860b57cec5SDimitry Andric            ++i) {
12870b57cec5SDimitry Andric         if (long_options[i].val == val) {
12880b57cec5SDimitry Andric           long_options_index = i;
12890b57cec5SDimitry Andric           break;
12900b57cec5SDimitry Andric         }
12910b57cec5SDimitry Andric       }
12920b57cec5SDimitry Andric     }
12930b57cec5SDimitry Andric     // Call the callback with the option
12940b57cec5SDimitry Andric     if (long_options_index >= 0 &&
12950b57cec5SDimitry Andric         long_options[long_options_index].definition) {
12960b57cec5SDimitry Andric       const OptionDefinition *def = long_options[long_options_index].definition;
12970b57cec5SDimitry Andric 
12980b57cec5SDimitry Andric       if (!platform_sp) {
12990b57cec5SDimitry Andric         // User did not pass in an explicit platform.  Try to grab from the
13000b57cec5SDimitry Andric         // execution context.
13010b57cec5SDimitry Andric         TargetSP target_sp =
13020b57cec5SDimitry Andric             execution_context ? execution_context->GetTargetSP() : TargetSP();
13030b57cec5SDimitry Andric         platform_sp = target_sp ? target_sp->GetPlatform() : PlatformSP();
13040b57cec5SDimitry Andric       }
13050b57cec5SDimitry Andric       OptionValidator *validator = def->validator;
13060b57cec5SDimitry Andric 
13070b57cec5SDimitry Andric       if (!platform_sp && require_validation) {
13080b57cec5SDimitry Andric         // Caller requires validation but we cannot validate as we don't have
13090b57cec5SDimitry Andric         // the mandatory platform against which to validate.
1310*0fca6ea1SDimitry Andric         return llvm::createStringError(
1311*0fca6ea1SDimitry Andric             "cannot validate options: no platform available");
13120b57cec5SDimitry Andric       }
13130b57cec5SDimitry Andric 
13140b57cec5SDimitry Andric       bool validation_failed = false;
13150b57cec5SDimitry Andric       if (platform_sp) {
13160b57cec5SDimitry Andric         // Ensure we have an execution context, empty or not.
13170b57cec5SDimitry Andric         ExecutionContext dummy_context;
13180b57cec5SDimitry Andric         ExecutionContext *exe_ctx_p =
13190b57cec5SDimitry Andric             execution_context ? execution_context : &dummy_context;
13200b57cec5SDimitry Andric         if (validator && !validator->IsValid(*platform_sp, *exe_ctx_p)) {
13210b57cec5SDimitry Andric           validation_failed = true;
13220b57cec5SDimitry Andric           error.SetErrorStringWithFormat("Option \"%s\" invalid.  %s",
13230b57cec5SDimitry Andric                                          def->long_option,
13240b57cec5SDimitry Andric                                          def->validator->LongConditionString());
13250b57cec5SDimitry Andric         }
13260b57cec5SDimitry Andric       }
13270b57cec5SDimitry Andric 
13280b57cec5SDimitry Andric       // As long as validation didn't fail, we set the option value.
13290b57cec5SDimitry Andric       if (!validation_failed)
13300b57cec5SDimitry Andric         error =
13310b57cec5SDimitry Andric             SetOptionValue(long_options_index,
13320b57cec5SDimitry Andric                            (def->option_has_arg == OptionParser::eNoArgument)
13330b57cec5SDimitry Andric                                ? nullptr
13340b57cec5SDimitry Andric                                : OptionParser::GetOptionArgument(),
13350b57cec5SDimitry Andric                            execution_context);
13369dba64beSDimitry Andric       // If the Option setting returned an error, we should stop parsing
13379dba64beSDimitry Andric       // and return the error.
13389dba64beSDimitry Andric       if (error.Fail())
13399dba64beSDimitry Andric         break;
13400b57cec5SDimitry Andric     } else {
13410b57cec5SDimitry Andric       error.SetErrorStringWithFormat("invalid option with value '%i'", val);
13420b57cec5SDimitry Andric     }
13430b57cec5SDimitry Andric   }
13440b57cec5SDimitry Andric 
13450b57cec5SDimitry Andric   if (error.Fail())
13460b57cec5SDimitry Andric     return error.ToError();
13470b57cec5SDimitry Andric 
13480b57cec5SDimitry Andric   argv.pop_back();
13490b57cec5SDimitry Andric   argv.erase(argv.begin(), argv.begin() + OptionParser::GetOptionIndex());
13500b57cec5SDimitry Andric   return ReconstituteArgsAfterParsing(argv, args);
13510b57cec5SDimitry Andric }
1352*0fca6ea1SDimitry Andric 
1353*0fca6ea1SDimitry Andric llvm::Error lldb_private::CreateOptionParsingError(
1354*0fca6ea1SDimitry Andric     llvm::StringRef option_arg, const char short_option,
1355*0fca6ea1SDimitry Andric     llvm::StringRef long_option, llvm::StringRef additional_context) {
1356*0fca6ea1SDimitry Andric   std::string buffer;
1357*0fca6ea1SDimitry Andric   llvm::raw_string_ostream stream(buffer);
1358*0fca6ea1SDimitry Andric   stream << "Invalid value ('" << option_arg << "') for -" << short_option;
1359*0fca6ea1SDimitry Andric   if (!long_option.empty())
1360*0fca6ea1SDimitry Andric     stream << " (" << long_option << ")";
1361*0fca6ea1SDimitry Andric   if (!additional_context.empty())
1362*0fca6ea1SDimitry Andric     stream << ": " << additional_context;
1363*0fca6ea1SDimitry Andric   return llvm::createStringError(llvm::inconvertibleErrorCode(), buffer);
1364*0fca6ea1SDimitry Andric }
1365