1//===-- Options.cpp -------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "lldb/Interpreter/Options.h"
10
11#include <algorithm>
12#include <bitset>
13#include <map>
14#include <set>
15
16#include "lldb/Host/OptionParser.h"
17#include "lldb/Interpreter/CommandCompletions.h"
18#include "lldb/Interpreter/CommandInterpreter.h"
19#include "lldb/Interpreter/CommandObject.h"
20#include "lldb/Interpreter/CommandReturnObject.h"
21#include "lldb/Target/Target.h"
22#include "lldb/Utility/DiagnosticsRendering.h"
23#include "lldb/Utility/StreamString.h"
24#include "llvm/ADT/STLExtras.h"
25
26using namespace lldb;
27using namespace lldb_private;
28
29namespace lldb_private {
30
31/// An llvm::Error that represents an option parsing diagnostic.
32class OptionParseError
33 : public llvm::ErrorInfo<OptionParseError, DiagnosticError> {
34 std::vector<DiagnosticDetail> m_details;
35
36public:
37 using llvm::ErrorInfo<OptionParseError, DiagnosticError>::ErrorInfo;
38 OptionParseError(DiagnosticDetail detail)
39 : ErrorInfo(std::error_code(EINVAL, std::generic_category())),
40 m_details({detail}) {}
41 OptionParseError(const Args::ArgEntry &arg, std::string msg)
42 : ErrorInfo(std::error_code(EINVAL, std::generic_category())) {
43 DiagnosticDetail::SourceLocation sloc;
44 if (auto pos = arg.GetPos()) {
45 uint16_t len = arg.GetLength();
46 sloc = {.file: FileSpec{}, .line: 1, .column: *pos, .length: len, .hidden: false, .in_user_input: true};
47 }
48 m_details.push_back(x: DiagnosticDetail{.source_location: sloc, .severity: lldb::eSeverityError, .message: msg, .rendered: msg});
49 }
50 std::unique_ptr<CloneableError> Clone() const override {
51 return std::make_unique<OptionParseError>(args: m_details[0]);
52 }
53 llvm::ArrayRef<DiagnosticDetail> GetDetails() const override {
54 return m_details;
55 }
56 static char ID;
57};
58
59char OptionParseError::ID;
60
61} // namespace lldb_private
62
63// Options
64Options::Options() { BuildValidOptionSets(); }
65
66Options::~Options() = default;
67
68void Options::NotifyOptionParsingStarting(ExecutionContext *execution_context) {
69 m_seen_options.clear();
70 // Let the subclass reset its option values
71 OptionParsingStarting(execution_context);
72}
73
74Status
75Options::NotifyOptionParsingFinished(ExecutionContext *execution_context) {
76 return OptionParsingFinished(execution_context);
77}
78
79void Options::OptionSeen(int option_idx) { m_seen_options.insert(x: option_idx); }
80
81// Returns true is set_a is a subset of set_b; Otherwise returns false.
82
83bool Options::IsASubset(const OptionSet &set_a, const OptionSet &set_b) {
84 bool is_a_subset = true;
85 OptionSet::const_iterator pos_a;
86 OptionSet::const_iterator pos_b;
87
88 // set_a is a subset of set_b if every member of set_a is also a member of
89 // set_b
90
91 for (pos_a = set_a.begin(); pos_a != set_a.end() && is_a_subset; ++pos_a) {
92 pos_b = set_b.find(x: *pos_a);
93 if (pos_b == set_b.end())
94 is_a_subset = false;
95 }
96
97 return is_a_subset;
98}
99
100// Returns the set difference set_a - set_b, i.e. { x | ElementOf (x, set_a) &&
101// !ElementOf (x, set_b) }
102
103size_t Options::OptionsSetDiff(const OptionSet &set_a, const OptionSet &set_b,
104 OptionSet &diffs) {
105 size_t num_diffs = 0;
106 OptionSet::const_iterator pos_a;
107 OptionSet::const_iterator pos_b;
108
109 for (pos_a = set_a.begin(); pos_a != set_a.end(); ++pos_a) {
110 pos_b = set_b.find(x: *pos_a);
111 if (pos_b == set_b.end()) {
112 ++num_diffs;
113 diffs.insert(x: *pos_a);
114 }
115 }
116
117 return num_diffs;
118}
119
120// Returns the union of set_a and set_b. Does not put duplicate members into
121// the union.
122
123void Options::OptionsSetUnion(const OptionSet &set_a, const OptionSet &set_b,
124 OptionSet &union_set) {
125 OptionSet::const_iterator pos;
126 OptionSet::iterator pos_union;
127
128 // Put all the elements of set_a into the union.
129
130 for (pos = set_a.begin(); pos != set_a.end(); ++pos)
131 union_set.insert(x: *pos);
132
133 // Put all the elements of set_b that are not already there into the union.
134 for (pos = set_b.begin(); pos != set_b.end(); ++pos) {
135 pos_union = union_set.find(x: *pos);
136 if (pos_union == union_set.end())
137 union_set.insert(x: *pos);
138 }
139}
140
141// This is called in the Options constructor, though we could call it lazily if
142// that ends up being a performance problem.
143
144void Options::BuildValidOptionSets() {
145 // Check to see if we already did this.
146 if (m_required_options.size() != 0)
147 return;
148
149 // Check to see if there are any options.
150 int num_options = NumCommandOptions();
151 if (num_options == 0)
152 return;
153
154 auto opt_defs = GetDefinitions();
155 m_required_options.resize(new_size: 1);
156 m_optional_options.resize(new_size: 1);
157
158 // First count the number of option sets we've got. Ignore
159 // LLDB_ALL_OPTION_SETS...
160
161 uint32_t num_option_sets = 0;
162
163 for (const auto &def : opt_defs) {
164 uint32_t this_usage_mask = def.usage_mask;
165 if (this_usage_mask == LLDB_OPT_SET_ALL) {
166 if (num_option_sets == 0)
167 num_option_sets = 1;
168 } else {
169 for (uint32_t j = 0; j < LLDB_MAX_NUM_OPTION_SETS; j++) {
170 if (this_usage_mask & (1 << j)) {
171 if (num_option_sets <= j)
172 num_option_sets = j + 1;
173 }
174 }
175 }
176 }
177
178 if (num_option_sets > 0) {
179 m_required_options.resize(new_size: num_option_sets);
180 m_optional_options.resize(new_size: num_option_sets);
181
182 for (const auto &def : opt_defs) {
183 for (uint32_t j = 0; j < num_option_sets; j++) {
184 if (def.usage_mask & 1 << j) {
185 if (def.required)
186 m_required_options[j].insert(x: def.short_option);
187 else
188 m_optional_options[j].insert(x: def.short_option);
189 }
190 }
191 }
192 }
193}
194
195uint32_t Options::NumCommandOptions() { return GetDefinitions().size(); }
196
197Option *Options::GetLongOptions() {
198 // Check to see if this has already been done.
199 if (m_getopt_table.empty()) {
200 auto defs = GetDefinitions();
201 if (defs.empty())
202 return nullptr;
203
204 std::map<int, uint32_t> option_seen;
205
206 m_getopt_table.resize(new_size: defs.size() + 1);
207 for (size_t i = 0; i < defs.size(); ++i) {
208 const int short_opt = defs[i].short_option;
209
210 m_getopt_table[i].definition = &defs[i];
211 m_getopt_table[i].flag = nullptr;
212 m_getopt_table[i].val = short_opt;
213
214 auto [pos, inserted] = option_seen.try_emplace(k: short_opt, args&: i);
215 if (!inserted && short_opt) {
216 m_getopt_table[i].val = 0;
217 StreamString strm;
218 if (defs[i].HasShortOption())
219 Debugger::ReportError(
220 message: llvm::formatv(
221 Fmt: "option[{0}] --{1} has a short option -{2} that "
222 "conflicts with option[{3}] --{4}, short option won't "
223 "be used for --{5}",
224 Vals&: i, Vals: defs[i].long_option, Vals: short_opt, Vals&: pos->second,
225 Vals: m_getopt_table[pos->second].definition->long_option,
226 Vals: defs[i].long_option)
227 .str());
228 else
229 Debugger::ReportError(
230 message: llvm::formatv(
231 Fmt: "option[{0}] --{1} has a short option {2:x} that "
232 "conflicts with option[{3}] --{4}, short option won't "
233 "be used for --{5}",
234 Vals: (int)i, Vals: defs[i].long_option, Vals: short_opt, Vals&: pos->second,
235 Vals: m_getopt_table[pos->second].definition->long_option,
236 Vals: defs[i].long_option)
237 .str());
238 }
239 }
240
241 // getopt_long_only requires a NULL final entry in the table:
242
243 m_getopt_table.back().definition = nullptr;
244 m_getopt_table.back().flag = nullptr;
245 m_getopt_table.back().val = 0;
246 }
247
248 if (m_getopt_table.empty())
249 return nullptr;
250
251 return &m_getopt_table.front();
252}
253
254// This function takes INDENT, which tells how many spaces to output at the
255// front of each line; SPACES, which is a string containing 80 spaces; and
256// TEXT, which is the text that is to be output. It outputs the text, on
257// multiple lines if necessary, to RESULT, with INDENT spaces at the front of
258// each line. It breaks lines on spaces, tabs or newlines, shortening the line
259// if necessary to not break in the middle of a word. It assumes that each
260// output line should contain a maximum of OUTPUT_MAX_COLUMNS characters.
261
262void Options::OutputFormattedUsageText(Stream &strm,
263 const OptionDefinition &option_def,
264 uint32_t output_max_columns) {
265 std::string actual_text;
266 if (option_def.validator) {
267 const char *condition = option_def.validator->ShortConditionString();
268 if (condition) {
269 actual_text = "[";
270 actual_text.append(s: condition);
271 actual_text.append(s: "] ");
272 }
273 }
274 actual_text.append(s: option_def.usage_text);
275
276 // Will it all fit on one line?
277
278 if (static_cast<uint32_t>(actual_text.length() + strm.GetIndentLevel()) <
279 output_max_columns) {
280 // Output it as a single line.
281 strm.Indent(s: actual_text);
282 strm.EOL();
283 } else {
284 // We need to break it up into multiple lines.
285
286 int text_width = output_max_columns - strm.GetIndentLevel() - 1;
287 int start = 0;
288 int end = start;
289 int final_end = actual_text.length();
290 int sub_len;
291
292 while (end < final_end) {
293 // Don't start the 'text' on a space, since we're already outputting the
294 // indentation.
295 while ((start < final_end) && (actual_text[start] == ' '))
296 start++;
297
298 end = start + text_width;
299 if (end > final_end)
300 end = final_end;
301 else {
302 // If we're not at the end of the text, make sure we break the line on
303 // white space.
304 while (end > start && actual_text[end] != ' ' &&
305 actual_text[end] != '\t' && actual_text[end] != '\n')
306 end--;
307 }
308
309 sub_len = end - start;
310 if (start != 0)
311 strm.EOL();
312 strm.Indent();
313 assert(start < final_end);
314 assert(start + sub_len <= final_end);
315 strm.Write(src: actual_text.c_str() + start, src_len: sub_len);
316 start = end + 1;
317 }
318 strm.EOL();
319 }
320}
321
322bool Options::SupportsLongOption(const char *long_option) {
323 if (!long_option || !long_option[0])
324 return false;
325
326 auto opt_defs = GetDefinitions();
327 if (opt_defs.empty())
328 return false;
329
330 const char *long_option_name = long_option;
331 if (long_option[0] == '-' && long_option[1] == '-')
332 long_option_name += 2;
333
334 for (auto &def : opt_defs) {
335 if (!def.long_option)
336 continue;
337
338 if (strcmp(s1: def.long_option, s2: long_option_name) == 0)
339 return true;
340 }
341
342 return false;
343}
344
345enum OptionDisplayType {
346 eDisplayBestOption,
347 eDisplayShortOption,
348 eDisplayLongOption
349};
350
351static bool PrintOption(const OptionDefinition &opt_def,
352 OptionDisplayType display_type, const char *header,
353 const char *footer, bool show_optional, Stream &strm) {
354 if (display_type == eDisplayShortOption && !opt_def.HasShortOption())
355 return false;
356
357 if (header && header[0])
358 strm.PutCString(cstr: header);
359
360 if (show_optional && !opt_def.required)
361 strm.PutChar(ch: '[');
362 const bool show_short_option =
363 opt_def.HasShortOption() && display_type != eDisplayLongOption;
364 if (show_short_option)
365 strm.Printf(format: "-%c", opt_def.short_option);
366 else
367 strm.Printf(format: "--%s", opt_def.long_option);
368 switch (opt_def.option_has_arg) {
369 case OptionParser::eNoArgument:
370 break;
371 case OptionParser::eRequiredArgument:
372 strm.Printf(format: " <%s>", CommandObject::GetArgumentName(arg_type: opt_def.argument_type));
373 break;
374
375 case OptionParser::eOptionalArgument:
376 strm.Printf(format: "%s[<%s>]", show_short_option ? "" : "=",
377 CommandObject::GetArgumentName(arg_type: opt_def.argument_type));
378 break;
379 }
380 if (show_optional && !opt_def.required)
381 strm.PutChar(ch: ']');
382 if (footer && footer[0])
383 strm.PutCString(cstr: footer);
384 return true;
385}
386
387void Options::GenerateOptionUsage(Stream &strm, CommandObject &cmd,
388 uint32_t screen_width) {
389 auto opt_defs = GetDefinitions();
390 const uint32_t save_indent_level = strm.GetIndentLevel();
391 llvm::StringRef name = cmd.GetCommandName();
392 StreamString arguments_str;
393 cmd.GetFormattedCommandArguments(str&: arguments_str);
394
395 const uint32_t num_options = NumCommandOptions();
396 if (num_options == 0)
397 return;
398
399 const bool only_print_args = cmd.IsDashDashCommand();
400 if (!only_print_args)
401 strm.PutCString(cstr: "\nCommand Options Usage:\n");
402
403 strm.IndentMore(amount: 2);
404
405 // First, show each usage level set of options, e.g. <cmd> [options-for-
406 // level-0]
407 // <cmd>
408 // [options-for-level-1]
409 // etc.
410
411 if (!only_print_args) {
412 uint32_t num_option_sets = GetRequiredOptions().size();
413 for (uint32_t opt_set = 0; opt_set < num_option_sets; ++opt_set) {
414 if (opt_set > 0)
415 strm.Printf(format: "\n");
416 strm.Indent(s: name);
417
418 // Different option sets may require different args.
419 StreamString args_str;
420 uint32_t opt_set_mask = 1 << opt_set;
421 cmd.GetFormattedCommandArguments(str&: args_str, opt_set_mask);
422
423 // First go through and print all options that take no arguments as a
424 // single string. If a command has "-a" "-b" and "-c", this will show up
425 // as [-abc]
426
427 // We use a set here so that they will be sorted.
428 std::set<int> required_options;
429 std::set<int> optional_options;
430
431 for (auto &def : opt_defs) {
432 if (def.usage_mask & opt_set_mask && def.HasShortOption() &&
433 def.option_has_arg == OptionParser::eNoArgument) {
434 if (def.required) {
435 required_options.insert(x: def.short_option);
436 } else {
437 optional_options.insert(x: def.short_option);
438 }
439 }
440 }
441
442 if (!required_options.empty()) {
443 strm.PutCString(cstr: " -");
444 for (int short_option : required_options)
445 strm.PutChar(ch: short_option);
446 }
447
448 if (!optional_options.empty()) {
449 strm.PutCString(cstr: " [-");
450 for (int short_option : optional_options)
451 strm.PutChar(ch: short_option);
452 strm.PutChar(ch: ']');
453 }
454
455 // First go through and print the required options (list them up front).
456 for (auto &def : opt_defs) {
457 if (def.usage_mask & opt_set_mask && def.HasShortOption() &&
458 def.required && def.option_has_arg != OptionParser::eNoArgument)
459 PrintOption(opt_def: def, display_type: eDisplayBestOption, header: " ", footer: nullptr, show_optional: true, strm);
460 }
461
462 // Now go through again, and this time only print the optional options.
463 for (auto &def : opt_defs) {
464 if (def.usage_mask & opt_set_mask && !def.required &&
465 def.option_has_arg != OptionParser::eNoArgument)
466 PrintOption(opt_def: def, display_type: eDisplayBestOption, header: " ", footer: nullptr, show_optional: true, strm);
467 }
468
469 if (args_str.GetSize() > 0) {
470 if (cmd.WantsRawCommandString())
471 strm.Printf(format: " --");
472 strm << " " << args_str.GetString();
473 }
474 }
475 }
476
477 if ((only_print_args || cmd.WantsRawCommandString()) &&
478 arguments_str.GetSize() > 0) {
479 if (!only_print_args)
480 strm.PutChar(ch: '\n');
481 strm.Indent(s: name);
482 strm << " " << arguments_str.GetString();
483 }
484
485 if (!only_print_args) {
486 strm.Printf(format: "\n\n");
487
488 // Now print out all the detailed information about the various options:
489 // long form, short form and help text:
490 // -short <argument> ( --long_name <argument> )
491 // help text
492
493 strm.IndentMore(amount: 5);
494
495 // Put the command options in a sorted container, so we can output
496 // them alphabetically by short_option.
497 std::multimap<int, uint32_t> options_ordered;
498 for (auto def : llvm::enumerate(First&: opt_defs))
499 options_ordered.insert(
500 x: std::make_pair(x: def.value().short_option, y: def.index()));
501
502 // Go through each option, find the table entry and write out the detailed
503 // help information for that option.
504
505 bool first_option_printed = false;
506
507 for (auto pos : options_ordered) {
508 // Put a newline separation between arguments
509 if (first_option_printed)
510 strm.EOL();
511 else
512 first_option_printed = true;
513
514 OptionDefinition opt_def = opt_defs[pos.second];
515
516 strm.Indent();
517 if (opt_def.short_option && opt_def.HasShortOption()) {
518 PrintOption(opt_def, display_type: eDisplayShortOption, header: nullptr, footer: nullptr, show_optional: false,
519 strm);
520 PrintOption(opt_def, display_type: eDisplayLongOption, header: " ( ", footer: " )", show_optional: false, strm);
521 } else {
522 // Short option is not printable, just print long option
523 PrintOption(opt_def, display_type: eDisplayLongOption, header: nullptr, footer: nullptr, show_optional: false, strm);
524 }
525 strm.EOL();
526
527 strm.IndentMore(amount: 5);
528
529 if (opt_def.usage_text)
530 OutputFormattedUsageText(strm, option_def: opt_def, output_max_columns: screen_width);
531 if (!opt_def.enum_values.empty()) {
532 strm.Indent();
533 strm.Printf(format: "Values: ");
534 bool is_first = true;
535 for (const auto &enum_value : opt_def.enum_values) {
536 if (is_first) {
537 strm.Printf(format: "%s", enum_value.string_value);
538 is_first = false;
539 }
540 else
541 strm.Printf(format: " | %s", enum_value.string_value);
542 }
543 strm.EOL();
544 }
545 strm.IndentLess(amount: 5);
546 }
547 }
548
549 // Restore the indent level
550 strm.SetIndentLevel(save_indent_level);
551}
552
553llvm::Error Options::VerifyOptions() {
554 bool options_are_valid = false;
555
556 int num_levels = GetRequiredOptions().size();
557 if (num_levels) {
558 for (int i = 0; i < num_levels && !options_are_valid; ++i) {
559 // This is the correct set of options if: 1). m_seen_options contains
560 // all of m_required_options[i] (i.e. all the required options at this
561 // level are a subset of m_seen_options); AND 2). { m_seen_options -
562 // m_required_options[i] is a subset of m_options_options[i] (i.e. all
563 // the rest of m_seen_options are in the set of optional options at this
564 // level.
565
566 // Check to see if all of m_required_options[i] are a subset of
567 // m_seen_options
568 if (IsASubset(set_a: GetRequiredOptions()[i], set_b: m_seen_options)) {
569 // Construct the set difference: remaining_options = {m_seen_options} -
570 // {m_required_options[i]}
571 OptionSet remaining_options;
572 OptionsSetDiff(set_a: m_seen_options, set_b: GetRequiredOptions()[i],
573 diffs&: remaining_options);
574 // Check to see if remaining_options is a subset of
575 // m_optional_options[i]
576 if (IsASubset(set_a: remaining_options, set_b: GetOptionalOptions()[i]))
577 options_are_valid = true;
578 }
579 }
580 } else {
581 options_are_valid = true;
582 }
583
584 if (!options_are_valid)
585 return llvm::createStringError(
586 Fmt: "invalid combination of options for the given command");
587
588 return llvm::Error::success();
589}
590
591// This function is called when we have been given a potentially incomplete set
592// of options, such as when an alias has been defined (more options might be
593// added at at the time the alias is invoked). We need to verify that the
594// options in the set m_seen_options are all part of a set that may be used
595// together, but m_seen_options may be missing some of the "required" options.
596llvm::Error Options::VerifyPartialOptions() {
597 bool options_are_valid = false;
598
599 int num_levels = GetRequiredOptions().size();
600 if (num_levels) {
601 for (int i = 0; i < num_levels && !options_are_valid; ++i) {
602 // In this case we are treating all options as optional rather than
603 // required. Therefore a set of options is correct if m_seen_options is a
604 // subset of the union of m_required_options and m_optional_options.
605 OptionSet union_set;
606 OptionsSetUnion(set_a: GetRequiredOptions()[i], set_b: GetOptionalOptions()[i],
607 union_set);
608 if (IsASubset(set_a: m_seen_options, set_b: union_set))
609 options_are_valid = true;
610 }
611 }
612
613 if (!options_are_valid)
614 return llvm::createStringError(
615 Fmt: "invalid combination of options for the given command");
616
617 return llvm::Error::success();
618}
619
620bool Options::HandleOptionCompletion(CompletionRequest &request,
621 OptionElementVector &opt_element_vector,
622 CommandInterpreter &interpreter) {
623 // For now we just scan the completions to see if the cursor position is in
624 // an option or its argument. Otherwise we'll call HandleArgumentCompletion.
625 // In the future we can use completion to validate options as well if we
626 // want.
627
628 auto opt_defs = GetDefinitions();
629
630 llvm::StringRef cur_opt_str = request.GetCursorArgumentPrefix();
631
632 for (size_t i = 0; i < opt_element_vector.size(); i++) {
633 size_t opt_pos = static_cast<size_t>(opt_element_vector[i].opt_pos);
634 size_t opt_arg_pos = static_cast<size_t>(opt_element_vector[i].opt_arg_pos);
635 int opt_defs_index = opt_element_vector[i].opt_defs_index;
636 if (opt_pos == request.GetCursorIndex()) {
637 // We're completing the option itself.
638
639 if (opt_defs_index == OptionArgElement::eBareDash) {
640 // We're completing a bare dash. That means all options are open.
641 // FIXME: We should scan the other options provided and only complete
642 // options
643 // within the option group they belong to.
644 std::string opt_str = "-a";
645
646 for (auto &def : opt_defs) {
647 if (!def.short_option)
648 continue;
649 opt_str[1] = def.short_option;
650 request.AddCompletion(completion: opt_str, description: def.usage_text);
651 }
652
653 return true;
654 } else if (opt_defs_index == OptionArgElement::eBareDoubleDash) {
655 std::string full_name("--");
656 for (auto &def : opt_defs) {
657 if (!def.short_option)
658 continue;
659
660 full_name.erase(first: full_name.begin() + 2, last: full_name.end());
661 full_name.append(s: def.long_option);
662 request.AddCompletion(completion: full_name, description: def.usage_text);
663 }
664 return true;
665 } else if (opt_defs_index != OptionArgElement::eUnrecognizedArg) {
666 // We recognized it, if it an incomplete long option, complete it
667 // anyway (getopt_long_only is happy with shortest unique string, but
668 // it's still a nice thing to do.) Otherwise return The string so the
669 // upper level code will know this is a full match and add the " ".
670 const OptionDefinition &opt = opt_defs[opt_defs_index];
671 llvm::StringRef long_option = opt.long_option;
672 if (cur_opt_str.starts_with(Prefix: "--") && cur_opt_str != long_option) {
673 request.AddCompletion(completion: "--" + long_option.str(), description: opt.usage_text);
674 return true;
675 } else
676 request.AddCompletion(completion: request.GetCursorArgumentPrefix());
677 return true;
678 } else {
679 // FIXME - not handling wrong options yet:
680 // Check to see if they are writing a long option & complete it.
681 // I think we will only get in here if the long option table has two
682 // elements
683 // that are not unique up to this point. getopt_long_only does
684 // shortest unique match for long options already.
685 if (cur_opt_str.consume_front(Prefix: "--")) {
686 for (auto &def : opt_defs) {
687 llvm::StringRef long_option(def.long_option);
688 if (long_option.starts_with(Prefix: cur_opt_str))
689 request.AddCompletion(completion: "--" + long_option.str(), description: def.usage_text);
690 }
691 }
692 return true;
693 }
694
695 } else if (opt_arg_pos == request.GetCursorIndex()) {
696 // Okay the cursor is on the completion of an argument. See if it has a
697 // completion, otherwise return no matches. Note, opt_defs_index == -1
698 // means we're after an option, but that option doesn't exist. We'll
699 // end up treating that as an argument. Not sure we can do much better.
700 if (opt_defs_index != -1) {
701 HandleOptionArgumentCompletion(request, opt_element_vector, opt_element_index: i,
702 interpreter);
703 return true;
704 } else {
705 // No completion callback means no completions...
706 return true;
707 }
708
709 } else {
710 // Not the last element, keep going.
711 continue;
712 }
713 }
714 return false;
715}
716
717void Options::HandleOptionArgumentCompletion(
718 CompletionRequest &request, OptionElementVector &opt_element_vector,
719 int opt_element_index, CommandInterpreter &interpreter) {
720 auto opt_defs = GetDefinitions();
721 std::unique_ptr<SearchFilter> filter_up;
722
723 int opt_defs_index = opt_element_vector[opt_element_index].opt_defs_index;
724
725 // See if this is an enumeration type option, and if so complete it here:
726 const auto &enum_values = opt_defs[opt_defs_index].enum_values;
727 if (!enum_values.empty())
728 for (const auto &enum_value : enum_values)
729 request.TryCompleteCurrentArg(completion: enum_value.string_value);
730
731 // If this is a source file or symbol type completion, and there is a -shlib
732 // option somewhere in the supplied arguments, then make a search filter for
733 // that shared library.
734 // FIXME: Do we want to also have an "OptionType" so we don't have to match
735 // string names?
736
737 uint32_t completion_mask = opt_defs[opt_defs_index].completion_type;
738
739 if (completion_mask == 0) {
740 lldb::CommandArgumentType option_arg_type =
741 opt_defs[opt_defs_index].argument_type;
742 if (option_arg_type != eArgTypeNone) {
743 const CommandObject::ArgumentTableEntry *arg_entry =
744 CommandObject::FindArgumentDataByType(
745 arg_type: opt_defs[opt_defs_index].argument_type);
746 if (arg_entry)
747 completion_mask = arg_entry->completion_type;
748 }
749 }
750
751 if (completion_mask & lldb::eSourceFileCompletion ||
752 completion_mask & lldb::eSymbolCompletion) {
753 for (size_t i = 0; i < opt_element_vector.size(); i++) {
754 int cur_defs_index = opt_element_vector[i].opt_defs_index;
755
756 // trying to use <0 indices will definitely cause problems
757 if (cur_defs_index == OptionArgElement::eUnrecognizedArg ||
758 cur_defs_index == OptionArgElement::eBareDash ||
759 cur_defs_index == OptionArgElement::eBareDoubleDash)
760 continue;
761
762 int cur_arg_pos = opt_element_vector[i].opt_arg_pos;
763 const char *cur_opt_name = opt_defs[cur_defs_index].long_option;
764
765 // If this is the "shlib" option and there was an argument provided,
766 // restrict it to that shared library.
767 if (cur_opt_name && strcmp(s1: cur_opt_name, s2: "shlib") == 0 &&
768 cur_arg_pos != -1) {
769 const char *module_name =
770 request.GetParsedLine().GetArgumentAtIndex(idx: cur_arg_pos);
771 if (module_name) {
772 FileSpec module_spec(module_name);
773 lldb::TargetSP target_sp =
774 interpreter.GetDebugger().GetSelectedTarget();
775 // Search filters require a target...
776 if (target_sp)
777 filter_up =
778 std::make_unique<SearchFilterByModule>(args&: target_sp, args&: module_spec);
779 }
780 break;
781 }
782 }
783 }
784
785 lldb_private::CommandCompletions::InvokeCommonCompletionCallbacks(
786 interpreter, completion_mask, request, searcher: filter_up.get());
787}
788
789void OptionGroupOptions::Append(OptionGroup *group) {
790 auto group_option_defs = group->GetDefinitions();
791 for (uint32_t i = 0; i < group_option_defs.size(); ++i) {
792 m_option_infos.push_back(x: OptionInfo(group, i));
793 m_option_defs.push_back(x: group_option_defs[i]);
794 }
795}
796
797const OptionGroup *OptionGroupOptions::GetGroupWithOption(char short_opt) {
798 for (uint32_t i = 0; i < m_option_defs.size(); i++) {
799 OptionDefinition opt_def = m_option_defs[i];
800 if (opt_def.short_option == short_opt)
801 return m_option_infos[i].option_group;
802 }
803 return nullptr;
804}
805
806void OptionGroupOptions::Append(OptionGroup *group, uint32_t src_mask,
807 uint32_t dst_mask) {
808 auto group_option_defs = group->GetDefinitions();
809 for (uint32_t i = 0; i < group_option_defs.size(); ++i) {
810 if (group_option_defs[i].usage_mask & src_mask) {
811 m_option_infos.push_back(x: OptionInfo(group, i));
812 m_option_defs.push_back(x: group_option_defs[i]);
813 m_option_defs.back().usage_mask = dst_mask;
814 }
815 }
816}
817
818void OptionGroupOptions::Append(
819 OptionGroup *group, llvm::ArrayRef<llvm::StringRef> exclude_long_options) {
820 auto group_option_defs = group->GetDefinitions();
821 for (uint32_t i = 0; i < group_option_defs.size(); ++i) {
822 const auto &definition = group_option_defs[i];
823 if (llvm::is_contained(Range&: exclude_long_options, Element: definition.long_option))
824 continue;
825
826 m_option_infos.push_back(x: OptionInfo(group, i));
827 m_option_defs.push_back(x: definition);
828 }
829}
830
831void OptionGroupOptions::Finalize() {
832 m_did_finalize = true;
833}
834
835Status OptionGroupOptions::SetOptionValue(uint32_t option_idx,
836 llvm::StringRef option_value,
837 ExecutionContext *execution_context) {
838 // After calling OptionGroupOptions::Append(...), you must finalize the
839 // groups by calling OptionGroupOptions::Finlize()
840 assert(m_did_finalize);
841 Status error;
842 if (option_idx < m_option_infos.size()) {
843 error = m_option_infos[option_idx].option_group->SetOptionValue(
844 option_idx: m_option_infos[option_idx].option_index, option_value,
845 execution_context);
846
847 } else {
848 error =
849 Status::FromErrorString(str: "invalid option index"); // Shouldn't happen...
850 }
851 return error;
852}
853
854void OptionGroupOptions::OptionParsingStarting(
855 ExecutionContext *execution_context) {
856 std::set<OptionGroup *> group_set;
857 OptionInfos::iterator pos, end = m_option_infos.end();
858 for (pos = m_option_infos.begin(); pos != end; ++pos) {
859 OptionGroup *group = pos->option_group;
860 if (group_set.find(x: group) == group_set.end()) {
861 group->OptionParsingStarting(execution_context);
862 group_set.insert(x: group);
863 }
864 }
865}
866Status
867OptionGroupOptions::OptionParsingFinished(ExecutionContext *execution_context) {
868 std::set<OptionGroup *> group_set;
869 Status error;
870 OptionInfos::iterator pos, end = m_option_infos.end();
871 for (pos = m_option_infos.begin(); pos != end; ++pos) {
872 OptionGroup *group = pos->option_group;
873 if (group_set.find(x: group) == group_set.end()) {
874 error = group->OptionParsingFinished(execution_context);
875 group_set.insert(x: group);
876 if (error.Fail())
877 return error;
878 }
879 }
880 return error;
881}
882
883// OptionParser permutes the arguments while processing them, so we create a
884// temporary array holding to avoid modification of the input arguments. The
885// options themselves are never modified, but the API expects a char * anyway,
886// hence the const_cast.
887static std::vector<char *> GetArgvForParsing(const Args &args) {
888 std::vector<char *> result;
889 // OptionParser always skips the first argument as it is based on getopt().
890 result.push_back(x: const_cast<char *>("<FAKE-ARG0>"));
891 for (const Args::ArgEntry &entry : args)
892 result.push_back(x: const_cast<char *>(entry.c_str()));
893 result.push_back(x: nullptr);
894 return result;
895}
896
897// Given a permuted argument, find it's position in the original Args vector.
898static Args::const_iterator FindOriginalIter(const char *arg,
899 const Args &original) {
900 return llvm::find_if(
901 Range: original, P: [arg](const Args::ArgEntry &D) { return D.c_str() == arg; });
902}
903
904// Given a permuted argument, find it's index in the original Args vector.
905static size_t FindOriginalIndex(const char *arg, const Args &original) {
906 return std::distance(first: original.begin(), last: FindOriginalIter(arg, original));
907}
908
909// Construct a new Args object, consisting of the entries from the original
910// arguments, but in the permuted order.
911static Args ReconstituteArgsAfterParsing(llvm::ArrayRef<char *> parsed,
912 const Args &original) {
913 Args result;
914 for (const char *arg : parsed) {
915 auto pos = FindOriginalIter(arg, original);
916 assert(pos != original.end());
917 result.AppendArgument(arg_str: pos->ref(), quote_char: pos->GetQuoteChar());
918 }
919 return result;
920}
921
922static size_t FindArgumentIndexForOption(const Args &args,
923 const Option &long_option) {
924 std::string short_opt = llvm::formatv(Fmt: "-{0}", Vals: char(long_option.val)).str();
925 std::string long_opt =
926 std::string(llvm::formatv(Fmt: "--{0}", Vals: long_option.definition->long_option));
927 for (const auto &entry : llvm::enumerate(First: args)) {
928 if (entry.value().ref().starts_with(Prefix: short_opt) ||
929 entry.value().ref().starts_with(Prefix: long_opt))
930 return entry.index();
931 }
932
933 return size_t(-1);
934}
935
936static std::string BuildShortOptions(const Option *long_options) {
937 std::string storage;
938 llvm::raw_string_ostream sstr(storage);
939
940 // Leading : tells getopt to return a : for a missing option argument AND to
941 // suppress error messages.
942 sstr << ":";
943
944 for (size_t i = 0; long_options[i].definition != nullptr; ++i) {
945 if (long_options[i].flag == nullptr) {
946 sstr << (char)long_options[i].val;
947 switch (long_options[i].definition->option_has_arg) {
948 default:
949 case OptionParser::eNoArgument:
950 break;
951 case OptionParser::eRequiredArgument:
952 sstr << ":";
953 break;
954 case OptionParser::eOptionalArgument:
955 sstr << "::";
956 break;
957 }
958 }
959 }
960 return storage;
961}
962
963llvm::Expected<Args> Options::ParseAlias(const Args &args,
964 OptionArgVector *option_arg_vector,
965 std::string &input_line) {
966 Option *long_options = GetLongOptions();
967
968 if (long_options == nullptr) {
969 return llvm::createStringError(Fmt: "Invalid long options");
970 }
971
972 std::string short_options = BuildShortOptions(long_options);
973
974 Args args_copy = args;
975 std::vector<char *> argv = GetArgvForParsing(args);
976
977 std::unique_lock<std::mutex> lock;
978 OptionParser::Prepare(lock);
979 int val;
980 while (true) {
981 int long_options_index = -1;
982 val = OptionParser::Parse(argv, optstring: short_options, longopts: long_options,
983 longindex: &long_options_index);
984
985 if (val == ':') {
986 return llvm::createStringError(EC: llvm::inconvertibleErrorCode(),
987 S: "last option requires an argument");
988 }
989
990 if (val == -1)
991 break;
992
993 if (val == '?') {
994 return llvm::createStringError(Fmt: "Unknown or ambiguous option");
995 }
996
997 if (val == 0)
998 continue;
999
1000 OptionSeen(option_idx: val);
1001
1002 // Look up the long option index
1003 if (long_options_index == -1) {
1004 for (int j = 0; long_options[j].definition || long_options[j].flag ||
1005 long_options[j].val;
1006 ++j) {
1007 if (long_options[j].val == val) {
1008 long_options_index = j;
1009 break;
1010 }
1011 }
1012 }
1013
1014 // See if the option takes an argument, and see if one was supplied.
1015 if (long_options_index == -1) {
1016 return llvm::createStringError(
1017 S: llvm::formatv(Fmt: "Invalid option with value '{0}'.", Vals: char(val)).str());
1018 }
1019
1020 StreamString option_str;
1021 option_str.Printf(format: "-%c", val);
1022 const OptionDefinition *def = long_options[long_options_index].definition;
1023 int has_arg =
1024 (def == nullptr) ? OptionParser::eNoArgument : def->option_has_arg;
1025
1026 const char *option_arg = nullptr;
1027 switch (has_arg) {
1028 case OptionParser::eRequiredArgument:
1029 if (OptionParser::GetOptionArgument() == nullptr) {
1030 return llvm::createStringError(
1031 S: llvm::formatv(Fmt: "Option '{0}' is missing argument specifier.",
1032 Vals: option_str.GetString())
1033 .str());
1034 }
1035 [[fallthrough]];
1036 case OptionParser::eOptionalArgument:
1037 option_arg = OptionParser::GetOptionArgument();
1038 [[fallthrough]];
1039 case OptionParser::eNoArgument:
1040 break;
1041 default:
1042 return llvm::createStringError(
1043 S: llvm::formatv(Fmt: "error with options table; invalid value in has_arg "
1044 "field for option '{0}'.",
1045 Vals: char(val))
1046 .str());
1047 }
1048 // Find option in the argument list; also see if it was supposed to take an
1049 // argument and if one was supplied. Remove option (and argument, if
1050 // given) from the argument list. Also remove them from the
1051 // raw_input_string, if one was passed in.
1052 // Note: We also need to preserve any option argument values that were
1053 // surrounded by backticks, as we lose track of them in the
1054 // option_args_vector.
1055 size_t idx =
1056 FindArgumentIndexForOption(args: args_copy, long_option: long_options[long_options_index]);
1057 std::string option_to_insert;
1058 if (option_arg) {
1059 if (idx != size_t(-1) && has_arg) {
1060 bool arg_has_backtick = args_copy[idx + 1].GetQuoteChar() == '`';
1061 if (arg_has_backtick)
1062 option_to_insert = "`";
1063 option_to_insert += option_arg;
1064 if (arg_has_backtick)
1065 option_to_insert += "`";
1066 } else
1067 option_to_insert = option_arg;
1068 } else
1069 option_to_insert = CommandInterpreter::g_no_argument;
1070
1071 option_arg_vector->emplace_back(args: std::string(option_str.GetString()),
1072 args&: has_arg, args&: option_to_insert);
1073
1074 if (idx == size_t(-1))
1075 continue;
1076
1077 if (!input_line.empty()) {
1078 llvm::StringRef tmp_arg = args_copy[idx].ref();
1079 size_t pos = input_line.find(svt: tmp_arg);
1080 if (pos != std::string::npos)
1081 input_line.erase(pos: pos, n: tmp_arg.size());
1082 }
1083 args_copy.DeleteArgumentAtIndex(idx);
1084 if ((option_to_insert != CommandInterpreter::g_no_argument) &&
1085 (OptionParser::GetOptionArgument() != nullptr) &&
1086 (idx < args_copy.GetArgumentCount()) &&
1087 (args_copy[idx].ref() == OptionParser::GetOptionArgument())) {
1088 if (input_line.size() > 0) {
1089 size_t pos = input_line.find(str: option_to_insert);
1090 if (pos != std::string::npos)
1091 input_line.erase(pos: pos, n: option_to_insert.size());
1092 }
1093 args_copy.DeleteArgumentAtIndex(idx);
1094 }
1095 }
1096
1097 return std::move(args_copy);
1098}
1099
1100OptionElementVector Options::ParseForCompletion(const Args &args,
1101 uint32_t cursor_index) {
1102 OptionElementVector option_element_vector;
1103 Option *long_options = GetLongOptions();
1104 option_element_vector.clear();
1105
1106 if (long_options == nullptr)
1107 return option_element_vector;
1108
1109 std::string short_options = BuildShortOptions(long_options);
1110
1111 std::unique_lock<std::mutex> lock;
1112 OptionParser::Prepare(lock);
1113 OptionParser::EnableError(error: false);
1114
1115 int val;
1116 auto opt_defs = GetDefinitions();
1117
1118 std::vector<char *> dummy_vec = GetArgvForParsing(args);
1119
1120 bool failed_once = false;
1121 uint32_t dash_dash_pos = -1;
1122
1123 while (true) {
1124 bool missing_argument = false;
1125 int long_options_index = -1;
1126
1127 val = OptionParser::Parse(argv: dummy_vec, optstring: short_options, longopts: long_options,
1128 longindex: &long_options_index);
1129
1130 if (val == -1) {
1131 // When we're completing a "--" which is the last option on line,
1132 if (failed_once)
1133 break;
1134
1135 failed_once = true;
1136
1137 // If this is a bare "--" we mark it as such so we can complete it
1138 // successfully later. Handling the "--" is a little tricky, since that
1139 // may mean end of options or arguments, or the user might want to
1140 // complete options by long name. I make this work by checking whether
1141 // the cursor is in the "--" argument, and if so I assume we're
1142 // completing the long option, otherwise I let it pass to
1143 // OptionParser::Parse which will terminate the option parsing. Note, in
1144 // either case we continue parsing the line so we can figure out what
1145 // other options were passed. This will be useful when we come to
1146 // restricting completions based on what other options we've seen on the
1147 // line.
1148
1149 if (static_cast<size_t>(OptionParser::GetOptionIndex()) <
1150 dummy_vec.size() &&
1151 (strcmp(s1: dummy_vec[OptionParser::GetOptionIndex() - 1], s2: "--") == 0)) {
1152 dash_dash_pos = FindOriginalIndex(
1153 arg: dummy_vec[OptionParser::GetOptionIndex() - 1], original: args);
1154 if (dash_dash_pos == cursor_index) {
1155 option_element_vector.push_back(
1156 x: OptionArgElement(OptionArgElement::eBareDoubleDash, dash_dash_pos,
1157 OptionArgElement::eBareDoubleDash));
1158 continue;
1159 } else
1160 break;
1161 } else
1162 break;
1163 } else if (val == '?') {
1164 option_element_vector.push_back(x: OptionArgElement(
1165 OptionArgElement::eUnrecognizedArg,
1166 FindOriginalIndex(arg: dummy_vec[OptionParser::GetOptionIndex() - 1],
1167 original: args),
1168 OptionArgElement::eUnrecognizedArg));
1169 continue;
1170 } else if (val == 0) {
1171 continue;
1172 } else if (val == ':') {
1173 // This is a missing argument.
1174 val = OptionParser::GetOptionErrorCause();
1175 missing_argument = true;
1176 }
1177
1178 OptionSeen(option_idx: val);
1179
1180 // Look up the long option index
1181 if (long_options_index == -1) {
1182 for (int j = 0; long_options[j].definition || long_options[j].flag ||
1183 long_options[j].val;
1184 ++j) {
1185 if (long_options[j].val == val) {
1186 long_options_index = j;
1187 break;
1188 }
1189 }
1190 }
1191
1192 // See if the option takes an argument, and see if one was supplied.
1193 if (long_options_index >= 0) {
1194 int opt_defs_index = -1;
1195 for (size_t i = 0; i < opt_defs.size(); i++) {
1196 if (opt_defs[i].short_option != val)
1197 continue;
1198 opt_defs_index = i;
1199 break;
1200 }
1201
1202 const OptionDefinition *def = long_options[long_options_index].definition;
1203 int has_arg =
1204 (def == nullptr) ? OptionParser::eNoArgument : def->option_has_arg;
1205 switch (has_arg) {
1206 case OptionParser::eNoArgument:
1207 option_element_vector.push_back(x: OptionArgElement(
1208 opt_defs_index,
1209 FindOriginalIndex(arg: dummy_vec[OptionParser::GetOptionIndex() - 1],
1210 original: args),
1211 0));
1212 break;
1213 case OptionParser::eRequiredArgument:
1214 if (OptionParser::GetOptionArgument() != nullptr) {
1215 int arg_index;
1216 if (missing_argument)
1217 arg_index = -1;
1218 else
1219 arg_index = OptionParser::GetOptionIndex() - 2;
1220
1221 option_element_vector.push_back(x: OptionArgElement(
1222 opt_defs_index,
1223 FindOriginalIndex(arg: dummy_vec[OptionParser::GetOptionIndex() - 2],
1224 original: args),
1225 arg_index));
1226 } else {
1227 option_element_vector.push_back(x: OptionArgElement(
1228 opt_defs_index,
1229 FindOriginalIndex(arg: dummy_vec[OptionParser::GetOptionIndex() - 1],
1230 original: args),
1231 -1));
1232 }
1233 break;
1234 case OptionParser::eOptionalArgument:
1235 option_element_vector.push_back(x: OptionArgElement(
1236 opt_defs_index,
1237 FindOriginalIndex(arg: dummy_vec[OptionParser::GetOptionIndex() - 2],
1238 original: args),
1239 FindOriginalIndex(arg: dummy_vec[OptionParser::GetOptionIndex() - 1],
1240 original: args)));
1241 break;
1242 default:
1243 // The options table is messed up. Here we'll just continue
1244 option_element_vector.push_back(x: OptionArgElement(
1245 OptionArgElement::eUnrecognizedArg,
1246 FindOriginalIndex(arg: dummy_vec[OptionParser::GetOptionIndex() - 1],
1247 original: args),
1248 OptionArgElement::eUnrecognizedArg));
1249 break;
1250 }
1251 } else {
1252 option_element_vector.push_back(x: OptionArgElement(
1253 OptionArgElement::eUnrecognizedArg,
1254 FindOriginalIndex(arg: dummy_vec[OptionParser::GetOptionIndex() - 1],
1255 original: args),
1256 OptionArgElement::eUnrecognizedArg));
1257 }
1258 }
1259
1260 // Finally we have to handle the case where the cursor index points at a
1261 // single "-". We want to mark that in the option_element_vector, but only
1262 // if it is not after the "--". But it turns out that OptionParser::Parse
1263 // just ignores an isolated "-". So we have to look it up by hand here. We
1264 // only care if it is AT the cursor position. Note, a single quoted dash is
1265 // not the same as a single dash...
1266
1267 const Args::ArgEntry &cursor = args[cursor_index];
1268 if ((static_cast<int32_t>(dash_dash_pos) == -1 ||
1269 cursor_index < dash_dash_pos) &&
1270 !cursor.IsQuoted() && cursor.ref() == "-") {
1271 option_element_vector.push_back(
1272 x: OptionArgElement(OptionArgElement::eBareDash, cursor_index,
1273 OptionArgElement::eBareDash));
1274 }
1275 return option_element_vector;
1276}
1277
1278llvm::Expected<Args> Options::Parse(const Args &args,
1279 ExecutionContext *execution_context,
1280 lldb::PlatformSP platform_sp,
1281 bool require_validation) {
1282 Status error;
1283 Option *long_options = GetLongOptions();
1284 if (long_options == nullptr) {
1285 return llvm::createStringError(Fmt: "Invalid long options.");
1286 }
1287
1288 std::string short_options = BuildShortOptions(long_options);
1289 std::vector<char *> argv = GetArgvForParsing(args);
1290
1291 std::unique_lock<std::mutex> lock;
1292 OptionParser::Prepare(lock);
1293 while (true) {
1294 int long_options_index = -1;
1295 int val = OptionParser::Parse(argv, optstring: short_options, longopts: long_options,
1296 longindex: &long_options_index);
1297
1298 if (val == ':') {
1299 error = Status::FromErrorString(str: "last option requires an argument");
1300 break;
1301 }
1302
1303 if (val == -1)
1304 break;
1305
1306 // Did we get an error?
1307 if (val == '?') {
1308 // Account for "argv[0]" and that it points to the next option.
1309 int idx = OptionParser::GetOptionIndex() - 2;
1310 if (idx >= 0 && (size_t)idx < args.GetArgumentCount())
1311 error = Status::FromError(error: llvm::make_error<OptionParseError>(
1312 Args: args[idx], Args: "unknown or ambiguous option"));
1313 else
1314 error = Status("unknown or ambiguous option");
1315
1316 break;
1317 }
1318 // The option auto-set itself
1319 if (val == 0)
1320 continue;
1321
1322 OptionSeen(option_idx: val);
1323
1324 // Lookup the long option index
1325 if (long_options_index == -1) {
1326 for (int i = 0; long_options[i].definition || long_options[i].flag ||
1327 long_options[i].val;
1328 ++i) {
1329 if (long_options[i].val == val) {
1330 long_options_index = i;
1331 break;
1332 }
1333 }
1334 }
1335 // Call the callback with the option
1336 if (long_options_index >= 0 &&
1337 long_options[long_options_index].definition) {
1338 const OptionDefinition *def = long_options[long_options_index].definition;
1339
1340 if (!platform_sp) {
1341 // User did not pass in an explicit platform. Try to grab from the
1342 // execution context.
1343 TargetSP target_sp =
1344 execution_context ? execution_context->GetTargetSP() : TargetSP();
1345 platform_sp = target_sp ? target_sp->GetPlatform() : PlatformSP();
1346 }
1347 OptionValidator *validator = def->validator;
1348
1349 if (!platform_sp && require_validation) {
1350 // Caller requires validation but we cannot validate as we don't have
1351 // the mandatory platform against which to validate.
1352 return llvm::createStringError(
1353 Fmt: "cannot validate options: no platform available");
1354 }
1355
1356 bool validation_failed = false;
1357 if (platform_sp) {
1358 // Ensure we have an execution context, empty or not.
1359 ExecutionContext dummy_context;
1360 ExecutionContext *exe_ctx_p =
1361 execution_context ? execution_context : &dummy_context;
1362 if (validator && !validator->IsValid(platform&: *platform_sp, target: *exe_ctx_p)) {
1363 validation_failed = true;
1364 error = Status::FromErrorStringWithFormat(
1365 format: "Option \"%s\" invalid. %s", def->long_option,
1366 def->validator->LongConditionString());
1367 }
1368 }
1369
1370 // As long as validation didn't fail, we set the option value.
1371 if (!validation_failed)
1372 error =
1373 SetOptionValue(option_idx: long_options_index,
1374 option_arg: (def->option_has_arg == OptionParser::eNoArgument)
1375 ? nullptr
1376 : OptionParser::GetOptionArgument(),
1377 execution_context);
1378 // If the Option setting returned an error, we should stop parsing
1379 // and return the error.
1380 if (error.Fail())
1381 break;
1382 } else {
1383 error = Status::FromErrorStringWithFormat(
1384 format: "invalid option with value '%i'", val);
1385 }
1386 }
1387
1388 if (error.Fail())
1389 return error.ToError();
1390
1391 argv.pop_back();
1392 argv.erase(first: argv.begin(), last: argv.begin() + OptionParser::GetOptionIndex());
1393 return ReconstituteArgsAfterParsing(parsed: argv, original: args);
1394}
1395
1396llvm::Error lldb_private::CreateOptionParsingError(
1397 llvm::StringRef option_arg, const char short_option,
1398 llvm::StringRef long_option, llvm::StringRef additional_context) {
1399 std::string buffer;
1400 llvm::raw_string_ostream stream(buffer);
1401 stream << "Invalid value ('" << option_arg << "') for -" << short_option;
1402 if (!long_option.empty())
1403 stream << " (" << long_option << ")";
1404 if (!additional_context.empty())
1405 stream << ": " << additional_context;
1406 return llvm::createStringError(EC: llvm::inconvertibleErrorCode(), S: buffer);
1407}
1408

Provided by KDAB

Privacy Policy
Improve your Profiling and Debugging skills
Find out more

source code of lldb/source/Interpreter/Options.cpp