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