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