180814287SRaphael Isemann //===-- Options.cpp -------------------------------------------------------===//
240af72e1SJim Ingham //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
640af72e1SJim Ingham //
740af72e1SJim Ingham //===----------------------------------------------------------------------===//
840af72e1SJim Ingham 
940af72e1SJim Ingham #include "lldb/Interpreter/Options.h"
1040af72e1SJim Ingham 
11f362c45eSCaroline Tice #include <algorithm>
12ab65b34fSGreg Clayton #include <bitset>
133bcdfc0eSGreg Clayton #include <map>
14bef55ac8SEnrico Granata #include <set>
1540af72e1SJim Ingham 
163eb2b44dSZachary Turner #include "lldb/Host/OptionParser.h"
1740af72e1SJim Ingham #include "lldb/Interpreter/CommandCompletions.h"
1840af72e1SJim Ingham #include "lldb/Interpreter/CommandInterpreter.h"
19b9c1b51eSKate Stone #include "lldb/Interpreter/CommandObject.h"
20b9c1b51eSKate Stone #include "lldb/Interpreter/CommandReturnObject.h"
2140af72e1SJim Ingham #include "lldb/Target/Target.h"
22bf9a7730SZachary Turner #include "lldb/Utility/StreamString.h"
2361f2d307SDavid Spickett #include "llvm/ADT/STLExtras.h"
2440af72e1SJim Ingham 
2540af72e1SJim Ingham using namespace lldb;
2640af72e1SJim Ingham using namespace lldb_private;
2740af72e1SJim Ingham 
2840af72e1SJim Ingham // Options
Options()298cdcd41eSTatyana Krasnukha Options::Options() { BuildValidOptionSets(); }
3040af72e1SJim Ingham 
3154d03a49STatyana Krasnukha Options::~Options() = default;
3240af72e1SJim Ingham 
NotifyOptionParsingStarting(ExecutionContext * execution_context)33b9c1b51eSKate Stone void Options::NotifyOptionParsingStarting(ExecutionContext *execution_context) {
3440af72e1SJim Ingham   m_seen_options.clear();
3532e0a750SGreg Clayton   // Let the subclass reset its option values
36e1cfbc79STodd Fiala   OptionParsingStarting(execution_context);
37f6b8b581SGreg Clayton }
38f6b8b581SGreg Clayton 
3997206d57SZachary Turner Status
NotifyOptionParsingFinished(ExecutionContext * execution_context)4097206d57SZachary Turner Options::NotifyOptionParsingFinished(ExecutionContext *execution_context) {
41e1cfbc79STodd Fiala   return OptionParsingFinished(execution_context);
4240af72e1SJim Ingham }
4340af72e1SJim Ingham 
OptionSeen(int option_idx)44b9c1b51eSKate Stone void Options::OptionSeen(int option_idx) { m_seen_options.insert(option_idx); }
4540af72e1SJim Ingham 
4640af72e1SJim Ingham // Returns true is set_a is a subset of set_b;  Otherwise returns false.
4740af72e1SJim Ingham 
IsASubset(const OptionSet & set_a,const OptionSet & set_b)48b9c1b51eSKate Stone bool Options::IsASubset(const OptionSet &set_a, const OptionSet &set_b) {
4940af72e1SJim Ingham   bool is_a_subset = true;
5040af72e1SJim Ingham   OptionSet::const_iterator pos_a;
5140af72e1SJim Ingham   OptionSet::const_iterator pos_b;
5240af72e1SJim Ingham 
53b9c1b51eSKate Stone   // set_a is a subset of set_b if every member of set_a is also a member of
54b9c1b51eSKate Stone   // set_b
5540af72e1SJim Ingham 
56b9c1b51eSKate Stone   for (pos_a = set_a.begin(); pos_a != set_a.end() && is_a_subset; ++pos_a) {
5740af72e1SJim Ingham     pos_b = set_b.find(*pos_a);
5840af72e1SJim Ingham     if (pos_b == set_b.end())
5940af72e1SJim Ingham       is_a_subset = false;
6040af72e1SJim Ingham   }
6140af72e1SJim Ingham 
6240af72e1SJim Ingham   return is_a_subset;
6340af72e1SJim Ingham }
6440af72e1SJim Ingham 
65b9c1b51eSKate Stone // Returns the set difference set_a - set_b, i.e. { x | ElementOf (x, set_a) &&
66b9c1b51eSKate Stone // !ElementOf (x, set_b) }
6740af72e1SJim Ingham 
OptionsSetDiff(const OptionSet & set_a,const OptionSet & set_b,OptionSet & diffs)68b9c1b51eSKate Stone size_t Options::OptionsSetDiff(const OptionSet &set_a, const OptionSet &set_b,
69b9c1b51eSKate Stone                                OptionSet &diffs) {
7040af72e1SJim Ingham   size_t num_diffs = 0;
7140af72e1SJim Ingham   OptionSet::const_iterator pos_a;
7240af72e1SJim Ingham   OptionSet::const_iterator pos_b;
7340af72e1SJim Ingham 
74b9c1b51eSKate Stone   for (pos_a = set_a.begin(); pos_a != set_a.end(); ++pos_a) {
7540af72e1SJim Ingham     pos_b = set_b.find(*pos_a);
76b9c1b51eSKate Stone     if (pos_b == set_b.end()) {
7740af72e1SJim Ingham       ++num_diffs;
7840af72e1SJim Ingham       diffs.insert(*pos_a);
7940af72e1SJim Ingham     }
8040af72e1SJim Ingham   }
8140af72e1SJim Ingham 
8240af72e1SJim Ingham   return num_diffs;
8340af72e1SJim Ingham }
8440af72e1SJim Ingham 
85b9c1b51eSKate Stone // Returns the union of set_a and set_b.  Does not put duplicate members into
86b9c1b51eSKate Stone // the union.
8740af72e1SJim Ingham 
OptionsSetUnion(const OptionSet & set_a,const OptionSet & set_b,OptionSet & union_set)88b9c1b51eSKate Stone void Options::OptionsSetUnion(const OptionSet &set_a, const OptionSet &set_b,
89b9c1b51eSKate Stone                               OptionSet &union_set) {
9040af72e1SJim Ingham   OptionSet::const_iterator pos;
9140af72e1SJim Ingham   OptionSet::iterator pos_union;
9240af72e1SJim Ingham 
9340af72e1SJim Ingham   // Put all the elements of set_a into the union.
9440af72e1SJim Ingham 
9540af72e1SJim Ingham   for (pos = set_a.begin(); pos != set_a.end(); ++pos)
9640af72e1SJim Ingham     union_set.insert(*pos);
9740af72e1SJim Ingham 
9840af72e1SJim Ingham   // Put all the elements of set_b that are not already there into the union.
99b9c1b51eSKate Stone   for (pos = set_b.begin(); pos != set_b.end(); ++pos) {
10040af72e1SJim Ingham     pos_union = union_set.find(*pos);
10140af72e1SJim Ingham     if (pos_union == union_set.end())
10240af72e1SJim Ingham       union_set.insert(*pos);
10340af72e1SJim Ingham   }
10440af72e1SJim Ingham }
10540af72e1SJim Ingham 
VerifyOptions(CommandReturnObject & result)106b9c1b51eSKate Stone bool Options::VerifyOptions(CommandReturnObject &result) {
10740af72e1SJim Ingham   bool options_are_valid = false;
10840af72e1SJim Ingham 
109d6ccc600SJim Ingham   int num_levels = GetRequiredOptions().size();
110b9c1b51eSKate Stone   if (num_levels) {
111b9c1b51eSKate Stone     for (int i = 0; i < num_levels && !options_are_valid; ++i) {
11205097246SAdrian Prantl       // This is the correct set of options if:  1). m_seen_options contains
11305097246SAdrian Prantl       // all of m_required_options[i] (i.e. all the required options at this
11405097246SAdrian Prantl       // level are a subset of m_seen_options); AND 2). { m_seen_options -
11505097246SAdrian Prantl       // m_required_options[i] is a subset of m_options_options[i] (i.e. all
11605097246SAdrian Prantl       // the rest of m_seen_options are in the set of optional options at this
11705097246SAdrian Prantl       // level.
11840af72e1SJim Ingham 
119b9c1b51eSKate Stone       // Check to see if all of m_required_options[i] are a subset of
120b9c1b51eSKate Stone       // m_seen_options
121b9c1b51eSKate Stone       if (IsASubset(GetRequiredOptions()[i], m_seen_options)) {
122b9c1b51eSKate Stone         // Construct the set difference: remaining_options = {m_seen_options} -
123b9c1b51eSKate Stone         // {m_required_options[i]}
12440af72e1SJim Ingham         OptionSet remaining_options;
125b9c1b51eSKate Stone         OptionsSetDiff(m_seen_options, GetRequiredOptions()[i],
126b9c1b51eSKate Stone                        remaining_options);
127b9c1b51eSKate Stone         // Check to see if remaining_options is a subset of
128b9c1b51eSKate Stone         // m_optional_options[i]
129d6ccc600SJim Ingham         if (IsASubset(remaining_options, GetOptionalOptions()[i]))
13040af72e1SJim Ingham           options_are_valid = true;
13140af72e1SJim Ingham       }
13240af72e1SJim Ingham     }
133b9c1b51eSKate Stone   } else {
13440af72e1SJim Ingham     options_are_valid = true;
13540af72e1SJim Ingham   }
13640af72e1SJim Ingham 
137b9c1b51eSKate Stone   if (options_are_valid) {
13840af72e1SJim Ingham     result.SetStatus(eReturnStatusSuccessFinishNoResult);
139b9c1b51eSKate Stone   } else {
14040af72e1SJim Ingham     result.AppendError("invalid combination of options for the given command");
14140af72e1SJim Ingham   }
14240af72e1SJim Ingham 
14340af72e1SJim Ingham   return options_are_valid;
14440af72e1SJim Ingham }
14540af72e1SJim Ingham 
146b9c1b51eSKate Stone // This is called in the Options constructor, though we could call it lazily if
14705097246SAdrian Prantl // that ends up being a performance problem.
14840af72e1SJim Ingham 
BuildValidOptionSets()149b9c1b51eSKate Stone void Options::BuildValidOptionSets() {
15040af72e1SJim Ingham   // Check to see if we already did this.
15140af72e1SJim Ingham   if (m_required_options.size() != 0)
15240af72e1SJim Ingham     return;
15340af72e1SJim Ingham 
15440af72e1SJim Ingham   // Check to see if there are any options.
15540af72e1SJim Ingham   int num_options = NumCommandOptions();
15640af72e1SJim Ingham   if (num_options == 0)
15740af72e1SJim Ingham     return;
15840af72e1SJim Ingham 
1591f0f5b5bSZachary Turner   auto opt_defs = GetDefinitions();
16040af72e1SJim Ingham   m_required_options.resize(1);
16140af72e1SJim Ingham   m_optional_options.resize(1);
16240af72e1SJim Ingham 
163b9c1b51eSKate Stone   // First count the number of option sets we've got.  Ignore
164b9c1b51eSKate Stone   // LLDB_ALL_OPTION_SETS...
16540af72e1SJim Ingham 
16640af72e1SJim Ingham   uint32_t num_option_sets = 0;
16740af72e1SJim Ingham 
1681f0f5b5bSZachary Turner   for (const auto &def : opt_defs) {
1691f0f5b5bSZachary Turner     uint32_t this_usage_mask = def.usage_mask;
170b9c1b51eSKate Stone     if (this_usage_mask == LLDB_OPT_SET_ALL) {
17140af72e1SJim Ingham       if (num_option_sets == 0)
17240af72e1SJim Ingham         num_option_sets = 1;
173b9c1b51eSKate Stone     } else {
174b9c1b51eSKate Stone       for (uint32_t j = 0; j < LLDB_MAX_NUM_OPTION_SETS; j++) {
175b9c1b51eSKate Stone         if (this_usage_mask & (1 << j)) {
17640af72e1SJim Ingham           if (num_option_sets <= j)
17740af72e1SJim Ingham             num_option_sets = j + 1;
17840af72e1SJim Ingham         }
17940af72e1SJim Ingham       }
18040af72e1SJim Ingham     }
18140af72e1SJim Ingham   }
18240af72e1SJim Ingham 
183b9c1b51eSKate Stone   if (num_option_sets > 0) {
18440af72e1SJim Ingham     m_required_options.resize(num_option_sets);
18540af72e1SJim Ingham     m_optional_options.resize(num_option_sets);
18640af72e1SJim Ingham 
1871f0f5b5bSZachary Turner     for (const auto &def : opt_defs) {
188b9c1b51eSKate Stone       for (uint32_t j = 0; j < num_option_sets; j++) {
1891f0f5b5bSZachary Turner         if (def.usage_mask & 1 << j) {
1901f0f5b5bSZachary Turner           if (def.required)
1911f0f5b5bSZachary Turner             m_required_options[j].insert(def.short_option);
19240af72e1SJim Ingham           else
1931f0f5b5bSZachary Turner             m_optional_options[j].insert(def.short_option);
19440af72e1SJim Ingham         }
19540af72e1SJim Ingham       }
19640af72e1SJim Ingham     }
19740af72e1SJim Ingham   }
19840af72e1SJim Ingham }
19940af72e1SJim Ingham 
NumCommandOptions()2001f0f5b5bSZachary Turner uint32_t Options::NumCommandOptions() { return GetDefinitions().size(); }
20140af72e1SJim Ingham 
GetLongOptions()202b9c1b51eSKate Stone Option *Options::GetLongOptions() {
20340af72e1SJim Ingham   // Check to see if this has already been done.
204b9c1b51eSKate Stone   if (m_getopt_table.empty()) {
2051f0f5b5bSZachary Turner     auto defs = GetDefinitions();
2061f0f5b5bSZachary Turner     if (defs.empty())
207d78c9576SEd Maste       return nullptr;
20840af72e1SJim Ingham 
2093bcdfc0eSGreg Clayton     std::map<int, uint32_t> option_seen;
21040af72e1SJim Ingham 
2111f0f5b5bSZachary Turner     m_getopt_table.resize(defs.size() + 1);
2121f0f5b5bSZachary Turner     for (size_t i = 0; i < defs.size(); ++i) {
2131f0f5b5bSZachary Turner       const int short_opt = defs[i].short_option;
21440af72e1SJim Ingham 
2151f0f5b5bSZachary Turner       m_getopt_table[i].definition = &defs[i];
216d78c9576SEd Maste       m_getopt_table[i].flag = nullptr;
2173bcdfc0eSGreg Clayton       m_getopt_table[i].val = short_opt;
2183bcdfc0eSGreg Clayton 
219b9c1b51eSKate Stone       if (option_seen.find(short_opt) == option_seen.end()) {
2203bcdfc0eSGreg Clayton         option_seen[short_opt] = i;
221b9c1b51eSKate Stone       } else if (short_opt) {
2223bcdfc0eSGreg Clayton         m_getopt_table[i].val = 0;
223b9c1b51eSKate Stone         std::map<int, uint32_t>::const_iterator pos =
224b9c1b51eSKate Stone             option_seen.find(short_opt);
2253bcdfc0eSGreg Clayton         StreamString strm;
226b4b83656SRaphael Isemann         if (defs[i].HasShortOption())
227*68793919SJonas Devlieghere           Debugger::ReportError(
228*68793919SJonas Devlieghere               llvm::formatv(
229*68793919SJonas Devlieghere                   "option[{0}] --{1} has a short option -{2} that "
230*68793919SJonas Devlieghere                   "conflicts with option[{3}] --{4}, short option won't "
231*68793919SJonas Devlieghere                   "be used for --{5}",
232*68793919SJonas Devlieghere                   i, defs[i].long_option, short_opt, pos->second,
233d37221dcSZachary Turner                   m_getopt_table[pos->second].definition->long_option,
234*68793919SJonas Devlieghere                   defs[i].long_option)
235*68793919SJonas Devlieghere                   .str());
2363bcdfc0eSGreg Clayton         else
237*68793919SJonas Devlieghere           Debugger::ReportError(
238*68793919SJonas Devlieghere               llvm::formatv(
239*68793919SJonas Devlieghere                   "option[{0}] --{1} has a short option {2:x} that "
240*68793919SJonas Devlieghere                   "conflicts with option[{3}] --{4}, short option won't "
241*68793919SJonas Devlieghere                   "be used for --{5}n",
2421f0f5b5bSZachary Turner                   (int)i, defs[i].long_option, short_opt, pos->second,
243d37221dcSZachary Turner                   m_getopt_table[pos->second].definition->long_option,
244*68793919SJonas Devlieghere                   defs[i].long_option)
245*68793919SJonas Devlieghere                   .str());
2461c5f186fSGreg Clayton       }
24740af72e1SJim Ingham     }
24840af72e1SJim Ingham 
249b7ad58a0SGreg Clayton     // getopt_long_only requires a NULL final entry in the table:
25040af72e1SJim Ingham 
2511f0f5b5bSZachary Turner     m_getopt_table.back().definition = nullptr;
2521f0f5b5bSZachary Turner     m_getopt_table.back().flag = nullptr;
2531f0f5b5bSZachary Turner     m_getopt_table.back().val = 0;
25440af72e1SJim Ingham   }
25540af72e1SJim Ingham 
256471b31ceSGreg Clayton   if (m_getopt_table.empty())
257d78c9576SEd Maste     return nullptr;
258471b31ceSGreg Clayton 
259471b31ceSGreg Clayton   return &m_getopt_table.front();
26040af72e1SJim Ingham }
26140af72e1SJim Ingham 
262b9c1b51eSKate Stone // This function takes INDENT, which tells how many spaces to output at the
26305097246SAdrian Prantl // front of each line; SPACES, which is a string containing 80 spaces; and
26405097246SAdrian Prantl // TEXT, which is the text that is to be output.   It outputs the text, on
265b9c1b51eSKate Stone // multiple lines if necessary, to RESULT, with INDENT spaces at the front of
26605097246SAdrian Prantl // each line.  It breaks lines on spaces, tabs or newlines, shortening the line
26705097246SAdrian Prantl // if necessary to not break in the middle of a word.  It assumes that each
26840af72e1SJim Ingham // output line should contain a maximum of OUTPUT_MAX_COLUMNS characters.
26940af72e1SJim Ingham 
OutputFormattedUsageText(Stream & strm,const OptionDefinition & option_def,uint32_t output_max_columns)270b9c1b51eSKate Stone void Options::OutputFormattedUsageText(Stream &strm,
271d37221dcSZachary Turner                                        const OptionDefinition &option_def,
272b9c1b51eSKate Stone                                        uint32_t output_max_columns) {
273d37221dcSZachary Turner   std::string actual_text;
274b9c1b51eSKate Stone   if (option_def.validator) {
275d37221dcSZachary Turner     const char *condition = option_def.validator->ShortConditionString();
276b9c1b51eSKate Stone     if (condition) {
277d37221dcSZachary Turner       actual_text = "[";
278d37221dcSZachary Turner       actual_text.append(condition);
279d37221dcSZachary Turner       actual_text.append("] ");
280d37221dcSZachary Turner     }
281d37221dcSZachary Turner   }
282d37221dcSZachary Turner   actual_text.append(option_def.usage_text);
28340af72e1SJim Ingham 
28440af72e1SJim Ingham   // Will it all fit on one line?
28540af72e1SJim Ingham 
286b9c1b51eSKate Stone   if (static_cast<uint32_t>(actual_text.length() + strm.GetIndentLevel()) <
287b9c1b51eSKate Stone       output_max_columns) {
28840af72e1SJim Ingham     // Output it as a single line.
2899dfd4e26SRaphael Isemann     strm.Indent(actual_text);
29040af72e1SJim Ingham     strm.EOL();
291b9c1b51eSKate Stone   } else {
29240af72e1SJim Ingham     // We need to break it up into multiple lines.
29340af72e1SJim Ingham 
29440af72e1SJim Ingham     int text_width = output_max_columns - strm.GetIndentLevel() - 1;
29540af72e1SJim Ingham     int start = 0;
29640af72e1SJim Ingham     int end = start;
297d37221dcSZachary Turner     int final_end = actual_text.length();
29840af72e1SJim Ingham     int sub_len;
29940af72e1SJim Ingham 
300b9c1b51eSKate Stone     while (end < final_end) {
301b9c1b51eSKate Stone       // Don't start the 'text' on a space, since we're already outputting the
302b9c1b51eSKate Stone       // indentation.
303d37221dcSZachary Turner       while ((start < final_end) && (actual_text[start] == ' '))
30440af72e1SJim Ingham         start++;
30540af72e1SJim Ingham 
30640af72e1SJim Ingham       end = start + text_width;
30740af72e1SJim Ingham       if (end > final_end)
30840af72e1SJim Ingham         end = final_end;
309b9c1b51eSKate Stone       else {
310b9c1b51eSKate Stone         // If we're not at the end of the text, make sure we break the line on
311b9c1b51eSKate Stone         // white space.
312b9c1b51eSKate Stone         while (end > start && actual_text[end] != ' ' &&
313b9c1b51eSKate Stone                actual_text[end] != '\t' && actual_text[end] != '\n')
31440af72e1SJim Ingham           end--;
31540af72e1SJim Ingham       }
31640af72e1SJim Ingham 
31740af72e1SJim Ingham       sub_len = end - start;
31840af72e1SJim Ingham       if (start != 0)
31940af72e1SJim Ingham         strm.EOL();
32040af72e1SJim Ingham       strm.Indent();
32140af72e1SJim Ingham       assert(start < final_end);
32240af72e1SJim Ingham       assert(start + sub_len <= final_end);
323d37221dcSZachary Turner       strm.Write(actual_text.c_str() + start, sub_len);
32440af72e1SJim Ingham       start = end + 1;
32540af72e1SJim Ingham     }
32640af72e1SJim Ingham     strm.EOL();
32740af72e1SJim Ingham   }
32840af72e1SJim Ingham }
32940af72e1SJim Ingham 
SupportsLongOption(const char * long_option)330b9c1b51eSKate Stone bool Options::SupportsLongOption(const char *long_option) {
3311f0f5b5bSZachary Turner   if (!long_option || !long_option[0])
3321f0f5b5bSZachary Turner     return false;
3331f0f5b5bSZachary Turner 
3341f0f5b5bSZachary Turner   auto opt_defs = GetDefinitions();
3351f0f5b5bSZachary Turner   if (opt_defs.empty())
3361f0f5b5bSZachary Turner     return false;
3371f0f5b5bSZachary Turner 
3389d3d6886SGreg Clayton   const char *long_option_name = long_option;
33952ec56ccSGreg Clayton   if (long_option[0] == '-' && long_option[1] == '-')
34052ec56ccSGreg Clayton     long_option_name += 2;
34152ec56ccSGreg Clayton 
3421f0f5b5bSZachary Turner   for (auto &def : opt_defs) {
3431f0f5b5bSZachary Turner     if (!def.long_option)
3441f0f5b5bSZachary Turner       continue;
3451f0f5b5bSZachary Turner 
3461f0f5b5bSZachary Turner     if (strcmp(def.long_option, long_option_name) == 0)
34752ec56ccSGreg Clayton       return true;
34852ec56ccSGreg Clayton   }
3491f0f5b5bSZachary Turner 
35052ec56ccSGreg Clayton   return false;
35152ec56ccSGreg Clayton }
35252ec56ccSGreg Clayton 
353b9c1b51eSKate Stone enum OptionDisplayType {
3543bcdfc0eSGreg Clayton   eDisplayBestOption,
3553bcdfc0eSGreg Clayton   eDisplayShortOption,
3563bcdfc0eSGreg Clayton   eDisplayLongOption
3573bcdfc0eSGreg Clayton };
3583bcdfc0eSGreg Clayton 
PrintOption(const OptionDefinition & opt_def,OptionDisplayType display_type,const char * header,const char * footer,bool show_optional,Stream & strm)359b9c1b51eSKate Stone static bool PrintOption(const OptionDefinition &opt_def,
360b9c1b51eSKate Stone                         OptionDisplayType display_type, const char *header,
361b9c1b51eSKate Stone                         const char *footer, bool show_optional, Stream &strm) {
362b4b83656SRaphael Isemann   if (display_type == eDisplayShortOption && !opt_def.HasShortOption())
3633bcdfc0eSGreg Clayton     return false;
3643bcdfc0eSGreg Clayton 
3653bcdfc0eSGreg Clayton   if (header && header[0])
3663bcdfc0eSGreg Clayton     strm.PutCString(header);
3673bcdfc0eSGreg Clayton 
3683bcdfc0eSGreg Clayton   if (show_optional && !opt_def.required)
3693bcdfc0eSGreg Clayton     strm.PutChar('[');
370b9c1b51eSKate Stone   const bool show_short_option =
371b4b83656SRaphael Isemann       opt_def.HasShortOption() && display_type != eDisplayLongOption;
3723bcdfc0eSGreg Clayton   if (show_short_option)
3733bcdfc0eSGreg Clayton     strm.Printf("-%c", opt_def.short_option);
3743bcdfc0eSGreg Clayton   else
3753bcdfc0eSGreg Clayton     strm.Printf("--%s", opt_def.long_option);
376b9c1b51eSKate Stone   switch (opt_def.option_has_arg) {
377e2607b50SVirgile Bello   case OptionParser::eNoArgument:
3783bcdfc0eSGreg Clayton     break;
379e2607b50SVirgile Bello   case OptionParser::eRequiredArgument:
3803bcdfc0eSGreg Clayton     strm.Printf(" <%s>", CommandObject::GetArgumentName(opt_def.argument_type));
3813bcdfc0eSGreg Clayton     break;
3823bcdfc0eSGreg Clayton 
383e2607b50SVirgile Bello   case OptionParser::eOptionalArgument:
384b9c1b51eSKate Stone     strm.Printf("%s[<%s>]", show_short_option ? "" : "=",
3853bcdfc0eSGreg Clayton                 CommandObject::GetArgumentName(opt_def.argument_type));
3863bcdfc0eSGreg Clayton     break;
3873bcdfc0eSGreg Clayton   }
3883bcdfc0eSGreg Clayton   if (show_optional && !opt_def.required)
3893bcdfc0eSGreg Clayton     strm.PutChar(']');
3903bcdfc0eSGreg Clayton   if (footer && footer[0])
3913bcdfc0eSGreg Clayton     strm.PutCString(footer);
3923bcdfc0eSGreg Clayton   return true;
3933bcdfc0eSGreg Clayton }
3943bcdfc0eSGreg Clayton 
GenerateOptionUsage(Stream & strm,CommandObject & cmd,uint32_t screen_width)395e473e79cSDavid Spickett void Options::GenerateOptionUsage(Stream &strm, CommandObject &cmd,
396b9c1b51eSKate Stone                                   uint32_t screen_width) {
3971f0f5b5bSZachary Turner   auto opt_defs = GetDefinitions();
39840af72e1SJim Ingham   const uint32_t save_indent_level = strm.GetIndentLevel();
399e473e79cSDavid Spickett   llvm::StringRef name = cmd.GetCommandName();
400e139cf23SCaroline Tice   StreamString arguments_str;
401e473e79cSDavid Spickett   cmd.GetFormattedCommandArguments(arguments_str);
40240af72e1SJim Ingham 
403091e760cSDavid Spickett   const uint32_t num_options = NumCommandOptions();
404091e760cSDavid Spickett   if (num_options == 0)
405091e760cSDavid Spickett     return;
406091e760cSDavid Spickett 
4074a94e380SDavid Spickett   const bool only_print_args = cmd.IsDashDashCommand();
408091e760cSDavid Spickett   if (!only_print_args)
40940af72e1SJim Ingham     strm.PutCString("\nCommand Options Usage:\n");
41040af72e1SJim Ingham 
41140af72e1SJim Ingham   strm.IndentMore(2);
41240af72e1SJim Ingham 
41305097246SAdrian Prantl   // First, show each usage level set of options, e.g. <cmd> [options-for-
41405097246SAdrian Prantl   // level-0]
415b9c1b51eSKate Stone   //                                                   <cmd>
416b9c1b51eSKate Stone   //                                                   [options-for-level-1]
41740af72e1SJim Ingham   //                                                   etc.
41840af72e1SJim Ingham 
419b9c1b51eSKate Stone   if (!only_print_args) {
4204a94e380SDavid Spickett     uint32_t num_option_sets = GetRequiredOptions().size();
421b9c1b51eSKate Stone     for (uint32_t opt_set = 0; opt_set < num_option_sets; ++opt_set) {
42240af72e1SJim Ingham       if (opt_set > 0)
42340af72e1SJim Ingham         strm.Printf("\n");
42440af72e1SJim Ingham       strm.Indent(name);
42540af72e1SJim Ingham 
42634ddc8dbSJohnny Chen       // Different option sets may require different args.
42734ddc8dbSJohnny Chen       StreamString args_str;
4284a94e380SDavid Spickett       uint32_t opt_set_mask = 1 << opt_set;
429e473e79cSDavid Spickett       cmd.GetFormattedCommandArguments(args_str, opt_set_mask);
43034ddc8dbSJohnny Chen 
43105097246SAdrian Prantl       // First go through and print all options that take no arguments as a
43205097246SAdrian Prantl       // single string. If a command has "-a" "-b" and "-c", this will show up
43305097246SAdrian Prantl       // as [-abc]
434ed8a705cSGreg Clayton 
435cf05de71SDavid Spickett       // We use a set here so that they will be sorted.
436cf05de71SDavid Spickett       std::set<int> required_options;
437cf05de71SDavid Spickett       std::set<int> optional_options;
438cf05de71SDavid Spickett 
4391f0f5b5bSZachary Turner       for (auto &def : opt_defs) {
440cf05de71SDavid Spickett         if (def.usage_mask & opt_set_mask && def.HasShortOption() &&
4411f0f5b5bSZachary Turner             def.option_has_arg == OptionParser::eNoArgument) {
442cf05de71SDavid Spickett           if (def.required) {
443cf05de71SDavid Spickett             required_options.insert(def.short_option);
444cf05de71SDavid Spickett           } else {
445cf05de71SDavid Spickett             optional_options.insert(def.short_option);
446ed8a705cSGreg Clayton           }
447ed8a705cSGreg Clayton         }
448ed8a705cSGreg Clayton       }
449ed8a705cSGreg Clayton 
450cf05de71SDavid Spickett       if (!required_options.empty()) {
451cf05de71SDavid Spickett         strm.PutCString(" -");
452cf05de71SDavid Spickett         for (int short_option : required_options)
453cf05de71SDavid Spickett           strm.PutChar(short_option);
454ed8a705cSGreg Clayton       }
455cf05de71SDavid Spickett 
456cf05de71SDavid Spickett       if (!optional_options.empty()) {
457cf05de71SDavid Spickett         strm.PutCString(" [-");
458cf05de71SDavid Spickett         for (int short_option : optional_options)
459cf05de71SDavid Spickett           strm.PutChar(short_option);
460ed8a705cSGreg Clayton         strm.PutChar(']');
461ed8a705cSGreg Clayton       }
462ed8a705cSGreg Clayton 
463f362c45eSCaroline Tice       // First go through and print the required options (list them up front).
4641f0f5b5bSZachary Turner       for (auto &def : opt_defs) {
465cf05de71SDavid Spickett         if (def.usage_mask & opt_set_mask && def.HasShortOption() &&
466cf05de71SDavid Spickett             def.required && def.option_has_arg != OptionParser::eNoArgument)
4671f0f5b5bSZachary Turner           PrintOption(def, eDisplayBestOption, " ", nullptr, true, strm);
468f362c45eSCaroline Tice       }
469f362c45eSCaroline Tice 
470f362c45eSCaroline Tice       // Now go through again, and this time only print the optional options.
4711f0f5b5bSZachary Turner       for (auto &def : opt_defs) {
472cf05de71SDavid Spickett         if (def.usage_mask & opt_set_mask && !def.required &&
473cf05de71SDavid Spickett             def.option_has_arg != OptionParser::eNoArgument)
4741f0f5b5bSZachary Turner           PrintOption(def, eDisplayBestOption, " ", nullptr, true, strm);
47540af72e1SJim Ingham       }
476a4c6ad19SSean Callanan 
477b9c1b51eSKate Stone       if (args_str.GetSize() > 0) {
4784a94e380SDavid Spickett         if (cmd.WantsRawCommandString())
479a4c6ad19SSean Callanan           strm.Printf(" --");
480c156427dSZachary Turner         strm << " " << args_str.GetString();
48140af72e1SJim Ingham       }
482a4c6ad19SSean Callanan     }
4834ebb8a47SEnrico Granata   }
484a4c6ad19SSean Callanan 
485e473e79cSDavid Spickett   if ((only_print_args || cmd.WantsRawCommandString()) &&
486b9c1b51eSKate Stone       arguments_str.GetSize() > 0) {
487b9c1b51eSKate Stone     if (!only_print_args)
488b9c1b51eSKate Stone       strm.PutChar('\n');
489a4c6ad19SSean Callanan     strm.Indent(name);
490c156427dSZachary Turner     strm << " " << arguments_str.GetString();
491a4c6ad19SSean Callanan   }
492a4c6ad19SSean Callanan 
493091e760cSDavid Spickett   if (!only_print_args) {
49440af72e1SJim Ingham     strm.Printf("\n\n");
49540af72e1SJim Ingham 
496b9c1b51eSKate Stone     // Now print out all the detailed information about the various options:
497b9c1b51eSKate Stone     // long form, short form and help text:
498d37221dcSZachary Turner     //   -short <argument> ( --long_name <argument> )
49940af72e1SJim Ingham     //   help text
50040af72e1SJim Ingham 
50140af72e1SJim Ingham     strm.IndentMore(5);
50240af72e1SJim Ingham 
50361f2d307SDavid Spickett     // Put the command options in a sorted container, so we can output
50461f2d307SDavid Spickett     // them alphabetically by short_option.
50561f2d307SDavid Spickett     std::multimap<int, uint32_t> options_ordered;
50661f2d307SDavid Spickett     for (auto def : llvm::enumerate(opt_defs))
50761f2d307SDavid Spickett       options_ordered.insert(
50861f2d307SDavid Spickett           std::make_pair(def.value().short_option, def.index()));
509f362c45eSCaroline Tice 
51061f2d307SDavid Spickett     // Go through each option, find the table entry and write out the detailed
51161f2d307SDavid Spickett     // help information for that option.
512f362c45eSCaroline Tice 
513b9c1b51eSKate Stone     bool first_option_printed = false;
5143bcdfc0eSGreg Clayton 
51561f2d307SDavid Spickett     for (auto pos : options_ordered) {
51640af72e1SJim Ingham       // Put a newline separation between arguments
51740af72e1SJim Ingham       if (first_option_printed)
51840af72e1SJim Ingham         strm.EOL();
5193bcdfc0eSGreg Clayton       else
5203bcdfc0eSGreg Clayton         first_option_printed = true;
52140af72e1SJim Ingham 
52261f2d307SDavid Spickett       OptionDefinition opt_def = opt_defs[pos.second];
523deaab222SCaroline Tice 
52440af72e1SJim Ingham       strm.Indent();
52561f2d307SDavid Spickett       if (opt_def.short_option && opt_def.HasShortOption()) {
52661f2d307SDavid Spickett         PrintOption(opt_def, eDisplayShortOption, nullptr, nullptr, false,
527b9c1b51eSKate Stone                     strm);
52861f2d307SDavid Spickett         PrintOption(opt_def, eDisplayLongOption, " ( ", " )", false, strm);
529b9c1b51eSKate Stone       } else {
5303bcdfc0eSGreg Clayton         // Short option is not printable, just print long option
53161f2d307SDavid Spickett         PrintOption(opt_def, eDisplayLongOption, nullptr, nullptr, false, strm);
5323bcdfc0eSGreg Clayton       }
5333bcdfc0eSGreg Clayton       strm.EOL();
53440af72e1SJim Ingham 
53540af72e1SJim Ingham       strm.IndentMore(5);
53640af72e1SJim Ingham 
53761f2d307SDavid Spickett       if (opt_def.usage_text)
53861f2d307SDavid Spickett         OutputFormattedUsageText(strm, opt_def, screen_width);
53961f2d307SDavid Spickett       if (!opt_def.enum_values.empty()) {
54040af72e1SJim Ingham         strm.Indent();
54140af72e1SJim Ingham         strm.Printf("Values: ");
5428fe53c49STatyana Krasnukha         bool is_first = true;
54361f2d307SDavid Spickett         for (const auto &enum_value : opt_def.enum_values) {
5448fe53c49STatyana Krasnukha           if (is_first) {
5458fe53c49STatyana Krasnukha             strm.Printf("%s", enum_value.string_value);
5468fe53c49STatyana Krasnukha             is_first = false;
5478fe53c49STatyana Krasnukha           }
54840af72e1SJim Ingham           else
5498fe53c49STatyana Krasnukha             strm.Printf(" | %s", enum_value.string_value);
55040af72e1SJim Ingham         }
55140af72e1SJim Ingham         strm.EOL();
55240af72e1SJim Ingham       }
55340af72e1SJim Ingham       strm.IndentLess(5);
55440af72e1SJim Ingham     }
555bef55ac8SEnrico Granata   }
55640af72e1SJim Ingham 
55740af72e1SJim Ingham   // Restore the indent level
55840af72e1SJim Ingham   strm.SetIndentLevel(save_indent_level);
55940af72e1SJim Ingham }
56040af72e1SJim Ingham 
561b9c1b51eSKate Stone // This function is called when we have been given a potentially incomplete set
56205097246SAdrian Prantl // of options, such as when an alias has been defined (more options might be
56305097246SAdrian Prantl // added at at the time the alias is invoked).  We need to verify that the
56405097246SAdrian Prantl // options in the set m_seen_options are all part of a set that may be used
56505097246SAdrian Prantl // together, but m_seen_options may be missing some of the "required" options.
56640af72e1SJim Ingham 
VerifyPartialOptions(CommandReturnObject & result)567b9c1b51eSKate Stone bool Options::VerifyPartialOptions(CommandReturnObject &result) {
56840af72e1SJim Ingham   bool options_are_valid = false;
56940af72e1SJim Ingham 
570d6ccc600SJim Ingham   int num_levels = GetRequiredOptions().size();
571b9c1b51eSKate Stone   if (num_levels) {
572b9c1b51eSKate Stone     for (int i = 0; i < num_levels && !options_are_valid; ++i) {
573b9c1b51eSKate Stone       // In this case we are treating all options as optional rather than
57405097246SAdrian Prantl       // required. Therefore a set of options is correct if m_seen_options is a
57505097246SAdrian Prantl       // subset of the union of m_required_options and m_optional_options.
57640af72e1SJim Ingham       OptionSet union_set;
577b9c1b51eSKate Stone       OptionsSetUnion(GetRequiredOptions()[i], GetOptionalOptions()[i],
578b9c1b51eSKate Stone                       union_set);
57940af72e1SJim Ingham       if (IsASubset(m_seen_options, union_set))
58040af72e1SJim Ingham         options_are_valid = true;
58140af72e1SJim Ingham     }
58240af72e1SJim Ingham   }
58340af72e1SJim Ingham 
58440af72e1SJim Ingham   return options_are_valid;
58540af72e1SJim Ingham }
58640af72e1SJim Ingham 
HandleOptionCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector,CommandInterpreter & interpreter)587a2e76c0bSRaphael Isemann bool Options::HandleOptionCompletion(CompletionRequest &request,
588a2e76c0bSRaphael Isemann                                      OptionElementVector &opt_element_vector,
589a2e76c0bSRaphael Isemann                                      CommandInterpreter &interpreter) {
59040af72e1SJim Ingham   // For now we just scan the completions to see if the cursor position is in
59140af72e1SJim Ingham   // an option or its argument.  Otherwise we'll call HandleArgumentCompletion.
59205097246SAdrian Prantl   // In the future we can use completion to validate options as well if we
59305097246SAdrian Prantl   // want.
59440af72e1SJim Ingham 
5951f0f5b5bSZachary Turner   auto opt_defs = GetDefinitions();
59640af72e1SJim Ingham 
597ac5a475bSRaphael Isemann   llvm::StringRef cur_opt_str = request.GetCursorArgumentPrefix();
59840af72e1SJim Ingham 
599b9c1b51eSKate Stone   for (size_t i = 0; i < opt_element_vector.size(); i++) {
60014f6465cSRaphael Isemann     size_t opt_pos = static_cast<size_t>(opt_element_vector[i].opt_pos);
60114f6465cSRaphael Isemann     size_t opt_arg_pos = static_cast<size_t>(opt_element_vector[i].opt_arg_pos);
60240af72e1SJim Ingham     int opt_defs_index = opt_element_vector[i].opt_defs_index;
603a2e76c0bSRaphael Isemann     if (opt_pos == request.GetCursorIndex()) {
60440af72e1SJim Ingham       // We're completing the option itself.
605d6ccc600SJim Ingham 
606b9c1b51eSKate Stone       if (opt_defs_index == OptionArgElement::eBareDash) {
607d6ccc600SJim Ingham         // We're completing a bare dash.  That means all options are open.
608b9c1b51eSKate Stone         // FIXME: We should scan the other options provided and only complete
609b9c1b51eSKate Stone         // options
610d6ccc600SJim Ingham         // within the option group they belong to.
611ac5a475bSRaphael Isemann         std::string opt_str = "-a";
612d6ccc600SJim Ingham 
6131f0f5b5bSZachary Turner         for (auto &def : opt_defs) {
6141f0f5b5bSZachary Turner           if (!def.short_option)
6151f0f5b5bSZachary Turner             continue;
6161f0f5b5bSZachary Turner           opt_str[1] = def.short_option;
6176897a814SRaphael Isemann           request.AddCompletion(opt_str, def.usage_text);
618d6ccc600SJim Ingham         }
6191f0f5b5bSZachary Turner 
620d6ccc600SJim Ingham         return true;
621b9c1b51eSKate Stone       } else if (opt_defs_index == OptionArgElement::eBareDoubleDash) {
622d6ccc600SJim Ingham         std::string full_name("--");
6231f0f5b5bSZachary Turner         for (auto &def : opt_defs) {
6241f0f5b5bSZachary Turner           if (!def.short_option)
6251f0f5b5bSZachary Turner             continue;
6261f0f5b5bSZachary Turner 
627d6ccc600SJim Ingham           full_name.erase(full_name.begin() + 2, full_name.end());
6281f0f5b5bSZachary Turner           full_name.append(def.long_option);
6296897a814SRaphael Isemann           request.AddCompletion(full_name, def.usage_text);
630d6ccc600SJim Ingham         }
631d6ccc600SJim Ingham         return true;
632b9c1b51eSKate Stone       } else if (opt_defs_index != OptionArgElement::eUnrecognizedArg) {
63305097246SAdrian Prantl         // We recognized it, if it an incomplete long option, complete it
63405097246SAdrian Prantl         // anyway (getopt_long_only is happy with shortest unique string, but
63505097246SAdrian Prantl         // it's still a nice thing to do.)  Otherwise return The string so the
63605097246SAdrian Prantl         // upper level code will know this is a full match and add the " ".
6376897a814SRaphael Isemann         const OptionDefinition &opt = opt_defs[opt_defs_index];
6386897a814SRaphael Isemann         llvm::StringRef long_option = opt.long_option;
639ac5a475bSRaphael Isemann         if (cur_opt_str.startswith("--") && cur_opt_str != long_option) {
6406897a814SRaphael Isemann           request.AddCompletion("--" + long_option.str(), opt.usage_text);
64140af72e1SJim Ingham           return true;
642ac5a475bSRaphael Isemann         } else
6437f9ac337SRaphael Isemann           request.AddCompletion(request.GetCursorArgumentPrefix());
64440af72e1SJim Ingham         return true;
645b9c1b51eSKate Stone       } else {
64640af72e1SJim Ingham         // FIXME - not handling wrong options yet:
64740af72e1SJim Ingham         // Check to see if they are writing a long option & complete it.
648b9c1b51eSKate Stone         // I think we will only get in here if the long option table has two
649b9c1b51eSKate Stone         // elements
65005097246SAdrian Prantl         // that are not unique up to this point.  getopt_long_only does
65105097246SAdrian Prantl         // shortest unique match for long options already.
652efb8b7b1SRaphael Isemann         if (cur_opt_str.consume_front("--")) {
6531f0f5b5bSZachary Turner           for (auto &def : opt_defs) {
654efb8b7b1SRaphael Isemann             llvm::StringRef long_option(def.long_option);
655efb8b7b1SRaphael Isemann             if (long_option.startswith(cur_opt_str))
6566897a814SRaphael Isemann               request.AddCompletion("--" + long_option.str(), def.usage_text);
65740af72e1SJim Ingham           }
65840af72e1SJim Ingham         }
65940af72e1SJim Ingham         return true;
66040af72e1SJim Ingham       }
66140af72e1SJim Ingham 
662a2e76c0bSRaphael Isemann     } else if (opt_arg_pos == request.GetCursorIndex()) {
66305097246SAdrian Prantl       // Okay the cursor is on the completion of an argument. See if it has a
66405097246SAdrian Prantl       // completion, otherwise return no matches.
665b9c1b51eSKate Stone       if (opt_defs_index != -1) {
6660ba85fdbSRaphael Isemann         HandleOptionArgumentCompletion(request, opt_element_vector, i,
667a2e76c0bSRaphael Isemann                                        interpreter);
66840af72e1SJim Ingham         return true;
669b9c1b51eSKate Stone       } else {
67040af72e1SJim Ingham         // No completion callback means no completions...
67140af72e1SJim Ingham         return true;
67240af72e1SJim Ingham       }
67340af72e1SJim Ingham 
674b9c1b51eSKate Stone     } else {
67540af72e1SJim Ingham       // Not the last element, keep going.
67640af72e1SJim Ingham       continue;
67740af72e1SJim Ingham     }
67840af72e1SJim Ingham   }
67940af72e1SJim Ingham   return false;
68040af72e1SJim Ingham }
68140af72e1SJim Ingham 
HandleOptionArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector,int opt_element_index,CommandInterpreter & interpreter)682494370c1SRaphael Isemann void Options::HandleOptionArgumentCompletion(
683a2e76c0bSRaphael Isemann     CompletionRequest &request, OptionElementVector &opt_element_vector,
684a2e76c0bSRaphael Isemann     int opt_element_index, CommandInterpreter &interpreter) {
6851f0f5b5bSZachary Turner   auto opt_defs = GetDefinitions();
686d5b44036SJonas Devlieghere   std::unique_ptr<SearchFilter> filter_up;
68740af72e1SJim Ingham 
68840af72e1SJim Ingham   int opt_defs_index = opt_element_vector[opt_element_index].opt_defs_index;
68940af72e1SJim Ingham 
69040af72e1SJim Ingham   // See if this is an enumeration type option, and if so complete it here:
69140af72e1SJim Ingham 
6928fe53c49STatyana Krasnukha   const auto &enum_values = opt_defs[opt_defs_index].enum_values;
69348d38ca6SRaphael Isemann   if (!enum_values.empty())
69448d38ca6SRaphael Isemann     for (const auto &enum_value : enum_values)
69593ca36d7SRaphael Isemann       request.TryCompleteCurrentArg(enum_value.string_value);
69640af72e1SJim Ingham 
69705097246SAdrian Prantl   // If this is a source file or symbol type completion, and  there is a -shlib
69805097246SAdrian Prantl   // option somewhere in the supplied arguments, then make a search filter for
69905097246SAdrian Prantl   // that shared library.
700b9c1b51eSKate Stone   // FIXME: Do we want to also have an "OptionType" so we don't have to match
701b9c1b51eSKate Stone   // string names?
70240af72e1SJim Ingham 
703ab65b34fSGreg Clayton   uint32_t completion_mask = opt_defs[opt_defs_index].completion_type;
704ab65b34fSGreg Clayton 
705b9c1b51eSKate Stone   if (completion_mask == 0) {
706b9c1b51eSKate Stone     lldb::CommandArgumentType option_arg_type =
707b9c1b51eSKate Stone         opt_defs[opt_defs_index].argument_type;
708b9c1b51eSKate Stone     if (option_arg_type != eArgTypeNone) {
709b9c1b51eSKate Stone       const CommandObject::ArgumentTableEntry *arg_entry =
710b9c1b51eSKate Stone           CommandObject::FindArgumentDataByType(
711b9c1b51eSKate Stone               opt_defs[opt_defs_index].argument_type);
712ab65b34fSGreg Clayton       if (arg_entry)
713ab65b34fSGreg Clayton         completion_mask = arg_entry->completion_type;
714ab65b34fSGreg Clayton     }
715ab65b34fSGreg Clayton   }
716ab65b34fSGreg Clayton 
717b9c1b51eSKate Stone   if (completion_mask & CommandCompletions::eSourceFileCompletion ||
718b9c1b51eSKate Stone       completion_mask & CommandCompletions::eSymbolCompletion) {
719b9c1b51eSKate Stone     for (size_t i = 0; i < opt_element_vector.size(); i++) {
72040af72e1SJim Ingham       int cur_defs_index = opt_element_vector[i].opt_defs_index;
721dadf7b29SEnrico Granata 
722dadf7b29SEnrico Granata       // trying to use <0 indices will definitely cause problems
723dadf7b29SEnrico Granata       if (cur_defs_index == OptionArgElement::eUnrecognizedArg ||
724dadf7b29SEnrico Granata           cur_defs_index == OptionArgElement::eBareDash ||
725dadf7b29SEnrico Granata           cur_defs_index == OptionArgElement::eBareDoubleDash)
726dadf7b29SEnrico Granata         continue;
727dadf7b29SEnrico Granata 
72840af72e1SJim Ingham       int cur_arg_pos = opt_element_vector[i].opt_arg_pos;
72940af72e1SJim Ingham       const char *cur_opt_name = opt_defs[cur_defs_index].long_option;
73040af72e1SJim Ingham 
73140af72e1SJim Ingham       // If this is the "shlib" option and there was an argument provided,
73240af72e1SJim Ingham       // restrict it to that shared library.
733b9c1b51eSKate Stone       if (cur_opt_name && strcmp(cur_opt_name, "shlib") == 0 &&
734b9c1b51eSKate Stone           cur_arg_pos != -1) {
735a2e76c0bSRaphael Isemann         const char *module_name =
736a2e76c0bSRaphael Isemann             request.GetParsedLine().GetArgumentAtIndex(cur_arg_pos);
737b9c1b51eSKate Stone         if (module_name) {
7388f3be7a3SJonas Devlieghere           FileSpec module_spec(module_name);
739b9c1b51eSKate Stone           lldb::TargetSP target_sp =
740b9c1b51eSKate Stone               interpreter.GetDebugger().GetSelectedTarget();
74140af72e1SJim Ingham           // Search filters require a target...
7424d122c40SGreg Clayton           if (target_sp)
74306412daeSJonas Devlieghere             filter_up =
74406412daeSJonas Devlieghere                 std::make_unique<SearchFilterByModule>(target_sp, module_spec);
74540af72e1SJim Ingham         }
74640af72e1SJim Ingham         break;
74740af72e1SJim Ingham       }
74840af72e1SJim Ingham     }
74940af72e1SJim Ingham   }
75040af72e1SJim Ingham 
751494370c1SRaphael Isemann   CommandCompletions::InvokeCommonCompletionCallbacks(
752d5b44036SJonas Devlieghere       interpreter, completion_mask, request, filter_up.get());
75340af72e1SJim Ingham }
754f6b8b581SGreg Clayton 
Append(OptionGroup * group)755b9c1b51eSKate Stone void OptionGroupOptions::Append(OptionGroup *group) {
7561f0f5b5bSZachary Turner   auto group_option_defs = group->GetDefinitions();
7571f0f5b5bSZachary Turner   for (uint32_t i = 0; i < group_option_defs.size(); ++i) {
75884c39663SGreg Clayton     m_option_infos.push_back(OptionInfo(group, i));
75984c39663SGreg Clayton     m_option_defs.push_back(group_option_defs[i]);
76084c39663SGreg Clayton   }
76184c39663SGreg Clayton }
76284c39663SGreg Clayton 
GetGroupWithOption(char short_opt)763b9c1b51eSKate Stone const OptionGroup *OptionGroupOptions::GetGroupWithOption(char short_opt) {
764b9c1b51eSKate Stone   for (uint32_t i = 0; i < m_option_defs.size(); i++) {
765e0f8f574SDaniel Malea     OptionDefinition opt_def = m_option_defs[i];
766e0f8f574SDaniel Malea     if (opt_def.short_option == short_opt)
767e0f8f574SDaniel Malea       return m_option_infos[i].option_group;
768e0f8f574SDaniel Malea   }
769d78c9576SEd Maste   return nullptr;
770e0f8f574SDaniel Malea }
771e0f8f574SDaniel Malea 
Append(OptionGroup * group,uint32_t src_mask,uint32_t dst_mask)772b9c1b51eSKate Stone void OptionGroupOptions::Append(OptionGroup *group, uint32_t src_mask,
773b9c1b51eSKate Stone                                 uint32_t dst_mask) {
7741f0f5b5bSZachary Turner   auto group_option_defs = group->GetDefinitions();
7751f0f5b5bSZachary Turner   for (uint32_t i = 0; i < group_option_defs.size(); ++i) {
776b9c1b51eSKate Stone     if (group_option_defs[i].usage_mask & src_mask) {
777ab65b34fSGreg Clayton       m_option_infos.push_back(OptionInfo(group, i));
778f6b8b581SGreg Clayton       m_option_defs.push_back(group_option_defs[i]);
779ab65b34fSGreg Clayton       m_option_defs.back().usage_mask = dst_mask;
780f6b8b581SGreg Clayton     }
781f6b8b581SGreg Clayton   }
782f6b8b581SGreg Clayton }
783f6b8b581SGreg Clayton 
Finalize()784b9c1b51eSKate Stone void OptionGroupOptions::Finalize() {
785f6b8b581SGreg Clayton   m_did_finalize = true;
786f6b8b581SGreg Clayton }
787f6b8b581SGreg Clayton 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_value,ExecutionContext * execution_context)78897206d57SZachary Turner Status OptionGroupOptions::SetOptionValue(uint32_t option_idx,
789fe11483bSZachary Turner                                           llvm::StringRef option_value,
790b9c1b51eSKate Stone                                           ExecutionContext *execution_context) {
79105097246SAdrian Prantl   // After calling OptionGroupOptions::Append(...), you must finalize the
79205097246SAdrian Prantl   // groups by calling OptionGroupOptions::Finlize()
793f6b8b581SGreg Clayton   assert(m_did_finalize);
79497206d57SZachary Turner   Status error;
795b9c1b51eSKate Stone   if (option_idx < m_option_infos.size()) {
796b9c1b51eSKate Stone     error = m_option_infos[option_idx].option_group->SetOptionValue(
797fe11483bSZachary Turner         m_option_infos[option_idx].option_index, option_value,
798fe11483bSZachary Turner         execution_context);
799ab65b34fSGreg Clayton 
800b9c1b51eSKate Stone   } else {
801f6b8b581SGreg Clayton     error.SetErrorString("invalid option index"); // Shouldn't happen...
802ab65b34fSGreg Clayton   }
803f6b8b581SGreg Clayton   return error;
804f6b8b581SGreg Clayton }
805f6b8b581SGreg Clayton 
OptionParsingStarting(ExecutionContext * execution_context)806b9c1b51eSKate Stone void OptionGroupOptions::OptionParsingStarting(
807b9c1b51eSKate Stone     ExecutionContext *execution_context) {
808ab65b34fSGreg Clayton   std::set<OptionGroup *> group_set;
809ab65b34fSGreg Clayton   OptionInfos::iterator pos, end = m_option_infos.end();
810b9c1b51eSKate Stone   for (pos = m_option_infos.begin(); pos != end; ++pos) {
811ab65b34fSGreg Clayton     OptionGroup *group = pos->option_group;
812b9c1b51eSKate Stone     if (group_set.find(group) == group_set.end()) {
813e1cfbc79STodd Fiala       group->OptionParsingStarting(execution_context);
814ab65b34fSGreg Clayton       group_set.insert(group);
815ab65b34fSGreg Clayton     }
816ab65b34fSGreg Clayton   }
817f6b8b581SGreg Clayton }
81897206d57SZachary Turner Status
OptionParsingFinished(ExecutionContext * execution_context)81997206d57SZachary Turner OptionGroupOptions::OptionParsingFinished(ExecutionContext *execution_context) {
820ab65b34fSGreg Clayton   std::set<OptionGroup *> group_set;
82197206d57SZachary Turner   Status error;
822ab65b34fSGreg Clayton   OptionInfos::iterator pos, end = m_option_infos.end();
823b9c1b51eSKate Stone   for (pos = m_option_infos.begin(); pos != end; ++pos) {
824ab65b34fSGreg Clayton     OptionGroup *group = pos->option_group;
825b9c1b51eSKate Stone     if (group_set.find(group) == group_set.end()) {
826e1cfbc79STodd Fiala       error = group->OptionParsingFinished(execution_context);
827ab65b34fSGreg Clayton       group_set.insert(group);
828f6b8b581SGreg Clayton       if (error.Fail())
829f6b8b581SGreg Clayton         return error;
830f6b8b581SGreg Clayton     }
831ab65b34fSGreg Clayton   }
832f6b8b581SGreg Clayton   return error;
833f6b8b581SGreg Clayton }
8345f56fca4SPavel Labath 
8355f56fca4SPavel Labath // OptionParser permutes the arguments while processing them, so we create a
8365f56fca4SPavel Labath // temporary array holding to avoid modification of the input arguments. The
8375f56fca4SPavel Labath // options themselves are never modified, but the API expects a char * anyway,
8385f56fca4SPavel Labath // hence the const_cast.
GetArgvForParsing(const Args & args)8395f56fca4SPavel Labath static std::vector<char *> GetArgvForParsing(const Args &args) {
8405f56fca4SPavel Labath   std::vector<char *> result;
8415f56fca4SPavel Labath   // OptionParser always skips the first argument as it is based on getopt().
8425f56fca4SPavel Labath   result.push_back(const_cast<char *>("<FAKE-ARG0>"));
8435f56fca4SPavel Labath   for (const Args::ArgEntry &entry : args)
8445f56fca4SPavel Labath     result.push_back(const_cast<char *>(entry.c_str()));
8451abaeeceSPavel Labath   result.push_back(nullptr);
8465f56fca4SPavel Labath   return result;
8475f56fca4SPavel Labath }
8485f56fca4SPavel Labath 
8495f56fca4SPavel Labath // Given a permuted argument, find it's position in the original Args vector.
FindOriginalIter(const char * arg,const Args & original)8505f56fca4SPavel Labath static Args::const_iterator FindOriginalIter(const char *arg,
8515f56fca4SPavel Labath                                              const Args &original) {
8525f56fca4SPavel Labath   return llvm::find_if(
8535f56fca4SPavel Labath       original, [arg](const Args::ArgEntry &D) { return D.c_str() == arg; });
8545f56fca4SPavel Labath }
8555f56fca4SPavel Labath 
8565f56fca4SPavel Labath // Given a permuted argument, find it's index in the original Args vector.
FindOriginalIndex(const char * arg,const Args & original)8575f56fca4SPavel Labath static size_t FindOriginalIndex(const char *arg, const Args &original) {
8585f56fca4SPavel Labath   return std::distance(original.begin(), FindOriginalIter(arg, original));
8595f56fca4SPavel Labath }
8605f56fca4SPavel Labath 
8615f56fca4SPavel Labath // Construct a new Args object, consisting of the entries from the original
8625f56fca4SPavel Labath // arguments, but in the permuted order.
ReconstituteArgsAfterParsing(llvm::ArrayRef<char * > parsed,const Args & original)8635f56fca4SPavel Labath static Args ReconstituteArgsAfterParsing(llvm::ArrayRef<char *> parsed,
8645f56fca4SPavel Labath                                          const Args &original) {
8655f56fca4SPavel Labath   Args result;
8665f56fca4SPavel Labath   for (const char *arg : parsed) {
8675f56fca4SPavel Labath     auto pos = FindOriginalIter(arg, original);
8685f56fca4SPavel Labath     assert(pos != original.end());
8690d9a201eSRaphael Isemann     result.AppendArgument(pos->ref(), pos->GetQuoteChar());
8705f56fca4SPavel Labath   }
8715f56fca4SPavel Labath   return result;
8725f56fca4SPavel Labath }
8735f56fca4SPavel Labath 
FindArgumentIndexForOption(const Args & args,const Option & long_option)8745f56fca4SPavel Labath static size_t FindArgumentIndexForOption(const Args &args,
8755f56fca4SPavel Labath                                          const Option &long_option) {
8765f56fca4SPavel Labath   std::string short_opt = llvm::formatv("-{0}", char(long_option.val)).str();
8775f56fca4SPavel Labath   std::string long_opt =
878adcd0268SBenjamin Kramer       std::string(llvm::formatv("--{0}", long_option.definition->long_option));
8795f56fca4SPavel Labath   for (const auto &entry : llvm::enumerate(args)) {
8800d9a201eSRaphael Isemann     if (entry.value().ref().startswith(short_opt) ||
8810d9a201eSRaphael Isemann         entry.value().ref().startswith(long_opt))
8825f56fca4SPavel Labath       return entry.index();
8835f56fca4SPavel Labath   }
8845f56fca4SPavel Labath 
8855f56fca4SPavel Labath   return size_t(-1);
8865f56fca4SPavel Labath }
8875f56fca4SPavel Labath 
BuildShortOptions(const Option * long_options)8881abaeeceSPavel Labath static std::string BuildShortOptions(const Option *long_options) {
8891abaeeceSPavel Labath   std::string storage;
8901abaeeceSPavel Labath   llvm::raw_string_ostream sstr(storage);
8915f56fca4SPavel Labath 
8921abaeeceSPavel Labath   // Leading : tells getopt to return a : for a missing option argument AND to
8931abaeeceSPavel Labath   // suppress error messages.
8941abaeeceSPavel Labath   sstr << ":";
8955f56fca4SPavel Labath 
8961abaeeceSPavel Labath   for (size_t i = 0; long_options[i].definition != nullptr; ++i) {
8975f56fca4SPavel Labath     if (long_options[i].flag == nullptr) {
8985f56fca4SPavel Labath       sstr << (char)long_options[i].val;
8995f56fca4SPavel Labath       switch (long_options[i].definition->option_has_arg) {
9005f56fca4SPavel Labath       default:
9015f56fca4SPavel Labath       case OptionParser::eNoArgument:
9025f56fca4SPavel Labath         break;
9035f56fca4SPavel Labath       case OptionParser::eRequiredArgument:
9045f56fca4SPavel Labath         sstr << ":";
9055f56fca4SPavel Labath         break;
9065f56fca4SPavel Labath       case OptionParser::eOptionalArgument:
9075f56fca4SPavel Labath         sstr << "::";
9085f56fca4SPavel Labath         break;
9095f56fca4SPavel Labath       }
9105f56fca4SPavel Labath     }
9115f56fca4SPavel Labath   }
9121abaeeceSPavel Labath   return std::move(sstr.str());
9131abaeeceSPavel Labath }
9141abaeeceSPavel Labath 
ParseAlias(const Args & args,OptionArgVector * option_arg_vector,std::string & input_line)9151abaeeceSPavel Labath llvm::Expected<Args> Options::ParseAlias(const Args &args,
9161abaeeceSPavel Labath                                          OptionArgVector *option_arg_vector,
9171abaeeceSPavel Labath                                          std::string &input_line) {
9181abaeeceSPavel Labath   Option *long_options = GetLongOptions();
9191abaeeceSPavel Labath 
9201abaeeceSPavel Labath   if (long_options == nullptr) {
9211abaeeceSPavel Labath     return llvm::make_error<llvm::StringError>("Invalid long options",
9221abaeeceSPavel Labath                                                llvm::inconvertibleErrorCode());
9231abaeeceSPavel Labath   }
9241abaeeceSPavel Labath 
9251abaeeceSPavel Labath   std::string short_options = BuildShortOptions(long_options);
9265f56fca4SPavel Labath 
9275f56fca4SPavel Labath   Args args_copy = args;
9285f56fca4SPavel Labath   std::vector<char *> argv = GetArgvForParsing(args);
9295f56fca4SPavel Labath 
9305f56fca4SPavel Labath   std::unique_lock<std::mutex> lock;
9315f56fca4SPavel Labath   OptionParser::Prepare(lock);
9325f56fca4SPavel Labath   int val;
93309ad8c8fSJonas Devlieghere   while (true) {
9345f56fca4SPavel Labath     int long_options_index = -1;
9351abaeeceSPavel Labath     val = OptionParser::Parse(argv, short_options, long_options,
9361abaeeceSPavel Labath                               &long_options_index);
9371abaeeceSPavel Labath 
9381abaeeceSPavel Labath     if (val == ':') {
9391abaeeceSPavel Labath       return llvm::createStringError(llvm::inconvertibleErrorCode(),
9401abaeeceSPavel Labath                                      "last option requires an argument");
9411abaeeceSPavel Labath     }
9425f56fca4SPavel Labath 
9435f56fca4SPavel Labath     if (val == -1)
9445f56fca4SPavel Labath       break;
9455f56fca4SPavel Labath 
9465f56fca4SPavel Labath     if (val == '?') {
9475f56fca4SPavel Labath       return llvm::make_error<llvm::StringError>(
9485f56fca4SPavel Labath           "Unknown or ambiguous option", llvm::inconvertibleErrorCode());
9495f56fca4SPavel Labath     }
9505f56fca4SPavel Labath 
9515f56fca4SPavel Labath     if (val == 0)
9525f56fca4SPavel Labath       continue;
9535f56fca4SPavel Labath 
9545f56fca4SPavel Labath     OptionSeen(val);
9555f56fca4SPavel Labath 
9565f56fca4SPavel Labath     // Look up the long option index
9575f56fca4SPavel Labath     if (long_options_index == -1) {
9585f56fca4SPavel Labath       for (int j = 0; long_options[j].definition || long_options[j].flag ||
9595f56fca4SPavel Labath                       long_options[j].val;
9605f56fca4SPavel Labath            ++j) {
9615f56fca4SPavel Labath         if (long_options[j].val == val) {
9625f56fca4SPavel Labath           long_options_index = j;
9635f56fca4SPavel Labath           break;
9645f56fca4SPavel Labath         }
9655f56fca4SPavel Labath       }
9665f56fca4SPavel Labath     }
9675f56fca4SPavel Labath 
9685f56fca4SPavel Labath     // See if the option takes an argument, and see if one was supplied.
9695f56fca4SPavel Labath     if (long_options_index == -1) {
9705f56fca4SPavel Labath       return llvm::make_error<llvm::StringError>(
9715f56fca4SPavel Labath           llvm::formatv("Invalid option with value '{0}'.", char(val)).str(),
9725f56fca4SPavel Labath           llvm::inconvertibleErrorCode());
9735f56fca4SPavel Labath     }
9745f56fca4SPavel Labath 
9755f56fca4SPavel Labath     StreamString option_str;
9765f56fca4SPavel Labath     option_str.Printf("-%c", val);
9775f56fca4SPavel Labath     const OptionDefinition *def = long_options[long_options_index].definition;
9785f56fca4SPavel Labath     int has_arg =
9795f56fca4SPavel Labath         (def == nullptr) ? OptionParser::eNoArgument : def->option_has_arg;
9805f56fca4SPavel Labath 
9815f56fca4SPavel Labath     const char *option_arg = nullptr;
9825f56fca4SPavel Labath     switch (has_arg) {
9835f56fca4SPavel Labath     case OptionParser::eRequiredArgument:
9845f56fca4SPavel Labath       if (OptionParser::GetOptionArgument() == nullptr) {
9855f56fca4SPavel Labath         return llvm::make_error<llvm::StringError>(
9865f56fca4SPavel Labath             llvm::formatv("Option '{0}' is missing argument specifier.",
9875f56fca4SPavel Labath                           option_str.GetString())
9885f56fca4SPavel Labath                 .str(),
9895f56fca4SPavel Labath             llvm::inconvertibleErrorCode());
9905f56fca4SPavel Labath       }
9915f56fca4SPavel Labath       LLVM_FALLTHROUGH;
9925f56fca4SPavel Labath     case OptionParser::eOptionalArgument:
9935f56fca4SPavel Labath       option_arg = OptionParser::GetOptionArgument();
9945f56fca4SPavel Labath       LLVM_FALLTHROUGH;
9955f56fca4SPavel Labath     case OptionParser::eNoArgument:
9965f56fca4SPavel Labath       break;
9975f56fca4SPavel Labath     default:
9985f56fca4SPavel Labath       return llvm::make_error<llvm::StringError>(
9995f56fca4SPavel Labath           llvm::formatv("error with options table; invalid value in has_arg "
10005f56fca4SPavel Labath                         "field for option '{0}'.",
10015f56fca4SPavel Labath                         char(val))
10025f56fca4SPavel Labath               .str(),
10035f56fca4SPavel Labath           llvm::inconvertibleErrorCode());
10045f56fca4SPavel Labath     }
10055f56fca4SPavel Labath     if (!option_arg)
10065f56fca4SPavel Labath       option_arg = "<no-argument>";
10075bbaf543SMartin Storsjö     option_arg_vector->emplace_back(std::string(option_str.GetString()),
10085bbaf543SMartin Storsjö                                     has_arg, std::string(option_arg));
10095f56fca4SPavel Labath 
101005097246SAdrian Prantl     // Find option in the argument list; also see if it was supposed to take an
101105097246SAdrian Prantl     // argument and if one was supplied.  Remove option (and argument, if
10125f56fca4SPavel Labath     // given) from the argument list.  Also remove them from the
10135f56fca4SPavel Labath     // raw_input_string, if one was passed in.
10145f56fca4SPavel Labath     size_t idx =
10155f56fca4SPavel Labath         FindArgumentIndexForOption(args_copy, long_options[long_options_index]);
10165f56fca4SPavel Labath     if (idx == size_t(-1))
10175f56fca4SPavel Labath       continue;
10185f56fca4SPavel Labath 
10195f56fca4SPavel Labath     if (!input_line.empty()) {
10200d9a201eSRaphael Isemann       auto tmp_arg = args_copy[idx].ref();
1021adcd0268SBenjamin Kramer       size_t pos = input_line.find(std::string(tmp_arg));
10225f56fca4SPavel Labath       if (pos != std::string::npos)
10235f56fca4SPavel Labath         input_line.erase(pos, tmp_arg.size());
10245f56fca4SPavel Labath     }
10255f56fca4SPavel Labath     args_copy.DeleteArgumentAtIndex(idx);
10265f56fca4SPavel Labath     if ((long_options[long_options_index].definition->option_has_arg !=
10275f56fca4SPavel Labath          OptionParser::eNoArgument) &&
10285f56fca4SPavel Labath         (OptionParser::GetOptionArgument() != nullptr) &&
10295f56fca4SPavel Labath         (idx < args_copy.GetArgumentCount()) &&
10300d9a201eSRaphael Isemann         (args_copy[idx].ref() == OptionParser::GetOptionArgument())) {
10315f56fca4SPavel Labath       if (input_line.size() > 0) {
10320d9a201eSRaphael Isemann         auto tmp_arg = args_copy[idx].ref();
1033adcd0268SBenjamin Kramer         size_t pos = input_line.find(std::string(tmp_arg));
10345f56fca4SPavel Labath         if (pos != std::string::npos)
10355f56fca4SPavel Labath           input_line.erase(pos, tmp_arg.size());
10365f56fca4SPavel Labath       }
10375f56fca4SPavel Labath       args_copy.DeleteArgumentAtIndex(idx);
10385f56fca4SPavel Labath     }
10395f56fca4SPavel Labath   }
10405f56fca4SPavel Labath 
10415f56fca4SPavel Labath   return std::move(args_copy);
10425f56fca4SPavel Labath }
10435f56fca4SPavel Labath 
ParseForCompletion(const Args & args,uint32_t cursor_index)10445f56fca4SPavel Labath OptionElementVector Options::ParseForCompletion(const Args &args,
10455f56fca4SPavel Labath                                                 uint32_t cursor_index) {
10465f56fca4SPavel Labath   OptionElementVector option_element_vector;
10475f56fca4SPavel Labath   Option *long_options = GetLongOptions();
10485f56fca4SPavel Labath   option_element_vector.clear();
10495f56fca4SPavel Labath 
10505f56fca4SPavel Labath   if (long_options == nullptr)
10515f56fca4SPavel Labath     return option_element_vector;
10525f56fca4SPavel Labath 
10531abaeeceSPavel Labath   std::string short_options = BuildShortOptions(long_options);
10545f56fca4SPavel Labath 
10555f56fca4SPavel Labath   std::unique_lock<std::mutex> lock;
10565f56fca4SPavel Labath   OptionParser::Prepare(lock);
10575f56fca4SPavel Labath   OptionParser::EnableError(false);
10585f56fca4SPavel Labath 
10595f56fca4SPavel Labath   int val;
10605f56fca4SPavel Labath   auto opt_defs = GetDefinitions();
10615f56fca4SPavel Labath 
10625f56fca4SPavel Labath   std::vector<char *> dummy_vec = GetArgvForParsing(args);
10635f56fca4SPavel Labath 
10645f56fca4SPavel Labath   bool failed_once = false;
10655f56fca4SPavel Labath   uint32_t dash_dash_pos = -1;
10665f56fca4SPavel Labath 
106709ad8c8fSJonas Devlieghere   while (true) {
10685f56fca4SPavel Labath     bool missing_argument = false;
10695f56fca4SPavel Labath     int long_options_index = -1;
10705f56fca4SPavel Labath 
10711abaeeceSPavel Labath     val = OptionParser::Parse(dummy_vec, short_options, long_options,
10721abaeeceSPavel Labath                               &long_options_index);
10735f56fca4SPavel Labath 
10745f56fca4SPavel Labath     if (val == -1) {
10755f56fca4SPavel Labath       // When we're completing a "--" which is the last option on line,
10765f56fca4SPavel Labath       if (failed_once)
10775f56fca4SPavel Labath         break;
10785f56fca4SPavel Labath 
10795f56fca4SPavel Labath       failed_once = true;
10805f56fca4SPavel Labath 
10815f56fca4SPavel Labath       // If this is a bare  "--" we mark it as such so we can complete it
10825f56fca4SPavel Labath       // successfully later.  Handling the "--" is a little tricky, since that
10835f56fca4SPavel Labath       // may mean end of options or arguments, or the user might want to
10845f56fca4SPavel Labath       // complete options by long name.  I make this work by checking whether
10855f56fca4SPavel Labath       // the cursor is in the "--" argument, and if so I assume we're
10865f56fca4SPavel Labath       // completing the long option, otherwise I let it pass to
10875f56fca4SPavel Labath       // OptionParser::Parse which will terminate the option parsing.  Note, in
10885f56fca4SPavel Labath       // either case we continue parsing the line so we can figure out what
10895f56fca4SPavel Labath       // other options were passed.  This will be useful when we come to
10905f56fca4SPavel Labath       // restricting completions based on what other options we've seen on the
10915f56fca4SPavel Labath       // line.
10925f56fca4SPavel Labath 
10935f56fca4SPavel Labath       if (static_cast<size_t>(OptionParser::GetOptionIndex()) <
10945f56fca4SPavel Labath               dummy_vec.size() &&
10955f56fca4SPavel Labath           (strcmp(dummy_vec[OptionParser::GetOptionIndex() - 1], "--") == 0)) {
10965f56fca4SPavel Labath         dash_dash_pos = FindOriginalIndex(
10975f56fca4SPavel Labath             dummy_vec[OptionParser::GetOptionIndex() - 1], args);
10985f56fca4SPavel Labath         if (dash_dash_pos == cursor_index) {
10995f56fca4SPavel Labath           option_element_vector.push_back(
11005f56fca4SPavel Labath               OptionArgElement(OptionArgElement::eBareDoubleDash, dash_dash_pos,
11015f56fca4SPavel Labath                                OptionArgElement::eBareDoubleDash));
11025f56fca4SPavel Labath           continue;
11035f56fca4SPavel Labath         } else
11045f56fca4SPavel Labath           break;
11055f56fca4SPavel Labath       } else
11065f56fca4SPavel Labath         break;
11075f56fca4SPavel Labath     } else if (val == '?') {
11085f56fca4SPavel Labath       option_element_vector.push_back(OptionArgElement(
11095f56fca4SPavel Labath           OptionArgElement::eUnrecognizedArg,
11105f56fca4SPavel Labath           FindOriginalIndex(dummy_vec[OptionParser::GetOptionIndex() - 1],
11115f56fca4SPavel Labath                             args),
11125f56fca4SPavel Labath           OptionArgElement::eUnrecognizedArg));
11135f56fca4SPavel Labath       continue;
11145f56fca4SPavel Labath     } else if (val == 0) {
11155f56fca4SPavel Labath       continue;
11165f56fca4SPavel Labath     } else if (val == ':') {
11175f56fca4SPavel Labath       // This is a missing argument.
11185f56fca4SPavel Labath       val = OptionParser::GetOptionErrorCause();
11195f56fca4SPavel Labath       missing_argument = true;
11205f56fca4SPavel Labath     }
11215f56fca4SPavel Labath 
11225f56fca4SPavel Labath     OptionSeen(val);
11235f56fca4SPavel Labath 
11245f56fca4SPavel Labath     // Look up the long option index
11255f56fca4SPavel Labath     if (long_options_index == -1) {
11265f56fca4SPavel Labath       for (int j = 0; long_options[j].definition || long_options[j].flag ||
11275f56fca4SPavel Labath                       long_options[j].val;
11285f56fca4SPavel Labath            ++j) {
11295f56fca4SPavel Labath         if (long_options[j].val == val) {
11305f56fca4SPavel Labath           long_options_index = j;
11315f56fca4SPavel Labath           break;
11325f56fca4SPavel Labath         }
11335f56fca4SPavel Labath       }
11345f56fca4SPavel Labath     }
11355f56fca4SPavel Labath 
11365f56fca4SPavel Labath     // See if the option takes an argument, and see if one was supplied.
11375f56fca4SPavel Labath     if (long_options_index >= 0) {
11385f56fca4SPavel Labath       int opt_defs_index = -1;
11395f56fca4SPavel Labath       for (size_t i = 0; i < opt_defs.size(); i++) {
11405f56fca4SPavel Labath         if (opt_defs[i].short_option != val)
11415f56fca4SPavel Labath           continue;
11425f56fca4SPavel Labath         opt_defs_index = i;
11435f56fca4SPavel Labath         break;
11445f56fca4SPavel Labath       }
11455f56fca4SPavel Labath 
11465f56fca4SPavel Labath       const OptionDefinition *def = long_options[long_options_index].definition;
11475f56fca4SPavel Labath       int has_arg =
11485f56fca4SPavel Labath           (def == nullptr) ? OptionParser::eNoArgument : def->option_has_arg;
11495f56fca4SPavel Labath       switch (has_arg) {
11505f56fca4SPavel Labath       case OptionParser::eNoArgument:
11515f56fca4SPavel Labath         option_element_vector.push_back(OptionArgElement(
11525f56fca4SPavel Labath             opt_defs_index,
11535f56fca4SPavel Labath             FindOriginalIndex(dummy_vec[OptionParser::GetOptionIndex() - 1],
11545f56fca4SPavel Labath                               args),
11555f56fca4SPavel Labath             0));
11565f56fca4SPavel Labath         break;
11575f56fca4SPavel Labath       case OptionParser::eRequiredArgument:
11585f56fca4SPavel Labath         if (OptionParser::GetOptionArgument() != nullptr) {
11595f56fca4SPavel Labath           int arg_index;
11605f56fca4SPavel Labath           if (missing_argument)
11615f56fca4SPavel Labath             arg_index = -1;
11625f56fca4SPavel Labath           else
11635f56fca4SPavel Labath             arg_index = OptionParser::GetOptionIndex() - 2;
11645f56fca4SPavel Labath 
11655f56fca4SPavel Labath           option_element_vector.push_back(OptionArgElement(
11665f56fca4SPavel Labath               opt_defs_index,
11675f56fca4SPavel Labath               FindOriginalIndex(dummy_vec[OptionParser::GetOptionIndex() - 2],
11685f56fca4SPavel Labath                                 args),
11695f56fca4SPavel Labath               arg_index));
11705f56fca4SPavel Labath         } else {
11715f56fca4SPavel Labath           option_element_vector.push_back(OptionArgElement(
11725f56fca4SPavel Labath               opt_defs_index,
11735f56fca4SPavel Labath               FindOriginalIndex(dummy_vec[OptionParser::GetOptionIndex() - 1],
11745f56fca4SPavel Labath                                 args),
11755f56fca4SPavel Labath               -1));
11765f56fca4SPavel Labath         }
11775f56fca4SPavel Labath         break;
11785f56fca4SPavel Labath       case OptionParser::eOptionalArgument:
11795f56fca4SPavel Labath         if (OptionParser::GetOptionArgument() != nullptr) {
11805f56fca4SPavel Labath           option_element_vector.push_back(OptionArgElement(
11815f56fca4SPavel Labath               opt_defs_index,
11825f56fca4SPavel Labath               FindOriginalIndex(dummy_vec[OptionParser::GetOptionIndex() - 2],
11835f56fca4SPavel Labath                                 args),
11845f56fca4SPavel Labath               FindOriginalIndex(dummy_vec[OptionParser::GetOptionIndex() - 1],
11855f56fca4SPavel Labath                                 args)));
11865f56fca4SPavel Labath         } else {
11875f56fca4SPavel Labath           option_element_vector.push_back(OptionArgElement(
11885f56fca4SPavel Labath               opt_defs_index,
11895f56fca4SPavel Labath               FindOriginalIndex(dummy_vec[OptionParser::GetOptionIndex() - 2],
11905f56fca4SPavel Labath                                 args),
11915f56fca4SPavel Labath               FindOriginalIndex(dummy_vec[OptionParser::GetOptionIndex() - 1],
11925f56fca4SPavel Labath                                 args)));
11935f56fca4SPavel Labath         }
11945f56fca4SPavel Labath         break;
11955f56fca4SPavel Labath       default:
11965f56fca4SPavel Labath         // The options table is messed up.  Here we'll just continue
11975f56fca4SPavel Labath         option_element_vector.push_back(OptionArgElement(
11985f56fca4SPavel Labath             OptionArgElement::eUnrecognizedArg,
11995f56fca4SPavel Labath             FindOriginalIndex(dummy_vec[OptionParser::GetOptionIndex() - 1],
12005f56fca4SPavel Labath                               args),
12015f56fca4SPavel Labath             OptionArgElement::eUnrecognizedArg));
12025f56fca4SPavel Labath         break;
12035f56fca4SPavel Labath       }
12045f56fca4SPavel Labath     } else {
12055f56fca4SPavel Labath       option_element_vector.push_back(OptionArgElement(
12065f56fca4SPavel Labath           OptionArgElement::eUnrecognizedArg,
12075f56fca4SPavel Labath           FindOriginalIndex(dummy_vec[OptionParser::GetOptionIndex() - 1],
12085f56fca4SPavel Labath                             args),
12095f56fca4SPavel Labath           OptionArgElement::eUnrecognizedArg));
12105f56fca4SPavel Labath     }
12115f56fca4SPavel Labath   }
12125f56fca4SPavel Labath 
12135f56fca4SPavel Labath   // Finally we have to handle the case where the cursor index points at a
121405097246SAdrian Prantl   // single "-".  We want to mark that in the option_element_vector, but only
121505097246SAdrian Prantl   // if it is not after the "--".  But it turns out that OptionParser::Parse
121605097246SAdrian Prantl   // just ignores an isolated "-".  So we have to look it up by hand here.  We
121705097246SAdrian Prantl   // only care if it is AT the cursor position. Note, a single quoted dash is
121805097246SAdrian Prantl   // not the same as a single dash...
12195f56fca4SPavel Labath 
12205f56fca4SPavel Labath   const Args::ArgEntry &cursor = args[cursor_index];
12215f56fca4SPavel Labath   if ((static_cast<int32_t>(dash_dash_pos) == -1 ||
12225f56fca4SPavel Labath        cursor_index < dash_dash_pos) &&
12230d9a201eSRaphael Isemann       !cursor.IsQuoted() && cursor.ref() == "-") {
12245f56fca4SPavel Labath     option_element_vector.push_back(
12255f56fca4SPavel Labath         OptionArgElement(OptionArgElement::eBareDash, cursor_index,
12265f56fca4SPavel Labath                          OptionArgElement::eBareDash));
12275f56fca4SPavel Labath   }
12285f56fca4SPavel Labath   return option_element_vector;
12295f56fca4SPavel Labath }
12305f56fca4SPavel Labath 
Parse(const Args & args,ExecutionContext * execution_context,lldb::PlatformSP platform_sp,bool require_validation)12315f56fca4SPavel Labath llvm::Expected<Args> Options::Parse(const Args &args,
12325f56fca4SPavel Labath                                     ExecutionContext *execution_context,
12335f56fca4SPavel Labath                                     lldb::PlatformSP platform_sp,
12345f56fca4SPavel Labath                                     bool require_validation) {
12355f56fca4SPavel Labath   Status error;
12365f56fca4SPavel Labath   Option *long_options = GetLongOptions();
12375f56fca4SPavel Labath   if (long_options == nullptr) {
12385f56fca4SPavel Labath     return llvm::make_error<llvm::StringError>("Invalid long options.",
12395f56fca4SPavel Labath                                                llvm::inconvertibleErrorCode());
12405f56fca4SPavel Labath   }
12415f56fca4SPavel Labath 
12421abaeeceSPavel Labath   std::string short_options = BuildShortOptions(long_options);
12435f56fca4SPavel Labath   std::vector<char *> argv = GetArgvForParsing(args);
12445f56fca4SPavel Labath   std::unique_lock<std::mutex> lock;
12455f56fca4SPavel Labath   OptionParser::Prepare(lock);
12465f56fca4SPavel Labath   int val;
124709ad8c8fSJonas Devlieghere   while (true) {
12485f56fca4SPavel Labath     int long_options_index = -1;
12491abaeeceSPavel Labath     val = OptionParser::Parse(argv, short_options, long_options,
12501abaeeceSPavel Labath                               &long_options_index);
1251c8e8b274SAdrian Prantl 
125234cac095SPavel Labath     if (val == ':') {
125389533764SJonas Devlieghere       error.SetErrorString("last option requires an argument");
1254c8e8b274SAdrian Prantl       break;
1255c8e8b274SAdrian Prantl     }
1256c8e8b274SAdrian Prantl 
12575f56fca4SPavel Labath     if (val == -1)
12585f56fca4SPavel Labath       break;
12595f56fca4SPavel Labath 
12605f56fca4SPavel Labath     // Did we get an error?
12615f56fca4SPavel Labath     if (val == '?') {
126289533764SJonas Devlieghere       error.SetErrorString("unknown or ambiguous option");
12635f56fca4SPavel Labath       break;
12645f56fca4SPavel Labath     }
12655f56fca4SPavel Labath     // The option auto-set itself
12665f56fca4SPavel Labath     if (val == 0)
12675f56fca4SPavel Labath       continue;
12685f56fca4SPavel Labath 
12695f56fca4SPavel Labath     OptionSeen(val);
12705f56fca4SPavel Labath 
12715f56fca4SPavel Labath     // Lookup the long option index
12725f56fca4SPavel Labath     if (long_options_index == -1) {
12735f56fca4SPavel Labath       for (int i = 0; long_options[i].definition || long_options[i].flag ||
12745f56fca4SPavel Labath                       long_options[i].val;
12755f56fca4SPavel Labath            ++i) {
12765f56fca4SPavel Labath         if (long_options[i].val == val) {
12775f56fca4SPavel Labath           long_options_index = i;
12785f56fca4SPavel Labath           break;
12795f56fca4SPavel Labath         }
12805f56fca4SPavel Labath       }
12815f56fca4SPavel Labath     }
12825f56fca4SPavel Labath     // Call the callback with the option
12835f56fca4SPavel Labath     if (long_options_index >= 0 &&
12845f56fca4SPavel Labath         long_options[long_options_index].definition) {
12855f56fca4SPavel Labath       const OptionDefinition *def = long_options[long_options_index].definition;
12865f56fca4SPavel Labath 
12875f56fca4SPavel Labath       if (!platform_sp) {
128805097246SAdrian Prantl         // User did not pass in an explicit platform.  Try to grab from the
128905097246SAdrian Prantl         // execution context.
12905f56fca4SPavel Labath         TargetSP target_sp =
12915f56fca4SPavel Labath             execution_context ? execution_context->GetTargetSP() : TargetSP();
12925f56fca4SPavel Labath         platform_sp = target_sp ? target_sp->GetPlatform() : PlatformSP();
12935f56fca4SPavel Labath       }
12945f56fca4SPavel Labath       OptionValidator *validator = def->validator;
12955f56fca4SPavel Labath 
12965f56fca4SPavel Labath       if (!platform_sp && require_validation) {
129705097246SAdrian Prantl         // Caller requires validation but we cannot validate as we don't have
129805097246SAdrian Prantl         // the mandatory platform against which to validate.
12995f56fca4SPavel Labath         return llvm::make_error<llvm::StringError>(
13005f56fca4SPavel Labath             "cannot validate options: no platform available",
13015f56fca4SPavel Labath             llvm::inconvertibleErrorCode());
13025f56fca4SPavel Labath       }
13035f56fca4SPavel Labath 
13045f56fca4SPavel Labath       bool validation_failed = false;
13055f56fca4SPavel Labath       if (platform_sp) {
13065f56fca4SPavel Labath         // Ensure we have an execution context, empty or not.
13075f56fca4SPavel Labath         ExecutionContext dummy_context;
13085f56fca4SPavel Labath         ExecutionContext *exe_ctx_p =
13095f56fca4SPavel Labath             execution_context ? execution_context : &dummy_context;
13105f56fca4SPavel Labath         if (validator && !validator->IsValid(*platform_sp, *exe_ctx_p)) {
13115f56fca4SPavel Labath           validation_failed = true;
13125f56fca4SPavel Labath           error.SetErrorStringWithFormat("Option \"%s\" invalid.  %s",
13135f56fca4SPavel Labath                                          def->long_option,
13145f56fca4SPavel Labath                                          def->validator->LongConditionString());
13155f56fca4SPavel Labath         }
13165f56fca4SPavel Labath       }
13175f56fca4SPavel Labath 
13185f56fca4SPavel Labath       // As long as validation didn't fail, we set the option value.
13195f56fca4SPavel Labath       if (!validation_failed)
13205f56fca4SPavel Labath         error =
13215f56fca4SPavel Labath             SetOptionValue(long_options_index,
13225f56fca4SPavel Labath                            (def->option_has_arg == OptionParser::eNoArgument)
13235f56fca4SPavel Labath                                ? nullptr
13245f56fca4SPavel Labath                                : OptionParser::GetOptionArgument(),
13255f56fca4SPavel Labath                            execution_context);
1326943a2481SJim Ingham       // If the Option setting returned an error, we should stop parsing
1327943a2481SJim Ingham       // and return the error.
1328943a2481SJim Ingham       if (error.Fail())
1329943a2481SJim Ingham         break;
13305f56fca4SPavel Labath     } else {
13315f56fca4SPavel Labath       error.SetErrorStringWithFormat("invalid option with value '%i'", val);
13325f56fca4SPavel Labath     }
1333f388d17dSTatyana Krasnukha   }
1334f388d17dSTatyana Krasnukha 
13355f56fca4SPavel Labath   if (error.Fail())
13365f56fca4SPavel Labath     return error.ToError();
13375f56fca4SPavel Labath 
1338c8e8b274SAdrian Prantl   argv.pop_back();
13395f56fca4SPavel Labath   argv.erase(argv.begin(), argv.begin() + OptionParser::GetOptionIndex());
13405f56fca4SPavel Labath   return ReconstituteArgsAfterParsing(argv, args);
13415f56fca4SPavel Labath }
1342