clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name Options.cpp -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model static -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/gnu/usr.bin/clang/liblldbInterpreter/obj -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/gnu/usr.bin/clang/liblldbInterpreter/../../../llvm/llvm/include -I /usr/src/gnu/usr.bin/clang/liblldbInterpreter/../include -I /usr/src/gnu/usr.bin/clang/liblldbInterpreter/obj -I /usr/src/gnu/usr.bin/clang/liblldbInterpreter/obj/../include -D NDEBUG -D __STDC_LIMIT_MACROS -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D LLVM_PREFIX="/usr" -I /usr/src/gnu/usr.bin/clang/liblldbInterpreter/../../../llvm/lldb/include -I /usr/src/gnu/usr.bin/clang/liblldbInterpreter/../../../llvm/lldb/source -I /usr/src/gnu/usr.bin/clang/liblldbInterpreter/../../../llvm/clang/include -I /usr/src/gnu/usr.bin/clang/liblldbInterpreter/obj/../include/lldb/Interpreter -internal-isystem /usr/include/c++/v1 -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wwrite-strings -Wno-missing-field-initializers -Wno-long-long -Wno-comment -std=c++14 -fdeprecated-macro -fdebug-compilation-dir=/usr/src/gnu/usr.bin/clang/liblldbInterpreter/obj -ferror-limit 19 -fvisibility-inlines-hidden -fwrapv -stack-protector 2 -fno-rtti -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c++ /usr/src/gnu/usr.bin/clang/liblldbInterpreter/../../../llvm/lldb/source/Interpreter/Options.cpp
1 | |
2 | |
3 | |
4 | |
5 | |
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/StreamString.h" |
23 | |
24 | using namespace lldb; |
25 | using namespace lldb_private; |
26 | |
27 | |
28 | Options::Options() { BuildValidOptionSets(); } |
29 | |
30 | Options::~Options() = default; |
31 | |
32 | void Options::NotifyOptionParsingStarting(ExecutionContext *execution_context) { |
33 | m_seen_options.clear(); |
34 | |
35 | OptionParsingStarting(execution_context); |
36 | } |
37 | |
38 | Status |
39 | Options::NotifyOptionParsingFinished(ExecutionContext *execution_context) { |
40 | return OptionParsingFinished(execution_context); |
41 | } |
42 | |
43 | void Options::OptionSeen(int option_idx) { m_seen_options.insert(option_idx); } |
44 | |
45 | |
46 | |
47 | bool Options::IsASubset(const OptionSet &set_a, const OptionSet &set_b) { |
48 | bool is_a_subset = true; |
49 | OptionSet::const_iterator pos_a; |
50 | OptionSet::const_iterator pos_b; |
51 | |
52 | |
53 | |
54 | |
55 | for (pos_a = set_a.begin(); pos_a != set_a.end() && is_a_subset; ++pos_a) { |
56 | pos_b = set_b.find(*pos_a); |
57 | if (pos_b == set_b.end()) |
58 | is_a_subset = false; |
59 | } |
60 | |
61 | return is_a_subset; |
62 | } |
63 | |
64 | |
65 | |
66 | |
67 | size_t Options::OptionsSetDiff(const OptionSet &set_a, const OptionSet &set_b, |
68 | OptionSet &diffs) { |
69 | size_t num_diffs = 0; |
70 | OptionSet::const_iterator pos_a; |
71 | OptionSet::const_iterator pos_b; |
72 | |
73 | for (pos_a = set_a.begin(); pos_a != set_a.end(); ++pos_a) { |
74 | pos_b = set_b.find(*pos_a); |
75 | if (pos_b == set_b.end()) { |
76 | ++num_diffs; |
77 | diffs.insert(*pos_a); |
78 | } |
79 | } |
80 | |
81 | return num_diffs; |
82 | } |
83 | |
84 | |
85 | |
86 | |
87 | void Options::OptionsSetUnion(const OptionSet &set_a, const OptionSet &set_b, |
88 | OptionSet &union_set) { |
89 | OptionSet::const_iterator pos; |
90 | OptionSet::iterator pos_union; |
91 | |
92 | |
93 | |
94 | for (pos = set_a.begin(); pos != set_a.end(); ++pos) |
95 | union_set.insert(*pos); |
96 | |
97 | |
98 | for (pos = set_b.begin(); pos != set_b.end(); ++pos) { |
99 | pos_union = union_set.find(*pos); |
100 | if (pos_union == union_set.end()) |
101 | union_set.insert(*pos); |
102 | } |
103 | } |
104 | |
105 | bool Options::VerifyOptions(CommandReturnObject &result) { |
106 | bool options_are_valid = false; |
107 | |
108 | int num_levels = GetRequiredOptions().size(); |
109 | if (num_levels) { |
110 | for (int i = 0; i < num_levels && !options_are_valid; ++i) { |
111 | |
112 | |
113 | |
114 | |
115 | |
116 | |
117 | |
118 | |
119 | |
120 | if (IsASubset(GetRequiredOptions()[i], m_seen_options)) { |
121 | |
122 | |
123 | OptionSet remaining_options; |
124 | OptionsSetDiff(m_seen_options, GetRequiredOptions()[i], |
125 | remaining_options); |
126 | |
127 | |
128 | if (IsASubset(remaining_options, GetOptionalOptions()[i])) |
129 | options_are_valid = true; |
130 | } |
131 | } |
132 | } else { |
133 | options_are_valid = true; |
134 | } |
135 | |
136 | if (options_are_valid) { |
137 | result.SetStatus(eReturnStatusSuccessFinishNoResult); |
138 | } else { |
139 | result.AppendError("invalid combination of options for the given command"); |
140 | } |
141 | |
142 | return options_are_valid; |
143 | } |
144 | |
145 | |
146 | |
147 | |
148 | void Options::BuildValidOptionSets() { |
149 | |
150 | if (m_required_options.size() != 0) |
151 | return; |
152 | |
153 | |
154 | int num_options = NumCommandOptions(); |
155 | if (num_options == 0) |
156 | return; |
157 | |
158 | auto opt_defs = GetDefinitions(); |
159 | m_required_options.resize(1); |
160 | m_optional_options.resize(1); |
161 | |
162 | |
163 | |
164 | |
165 | uint32_t num_option_sets = 0; |
166 | |
167 | for (const auto &def : opt_defs) { |
168 | uint32_t this_usage_mask = def.usage_mask; |
169 | if (this_usage_mask == LLDB_OPT_SET_ALL) { |
170 | if (num_option_sets == 0) |
171 | num_option_sets = 1; |
172 | } else { |
173 | for (uint32_t j = 0; j < LLDB_MAX_NUM_OPTION_SETS; j++) { |
174 | if (this_usage_mask & (1 << j)) { |
175 | if (num_option_sets <= j) |
176 | num_option_sets = j + 1; |
177 | } |
178 | } |
179 | } |
180 | } |
181 | |
182 | if (num_option_sets > 0) { |
183 | m_required_options.resize(num_option_sets); |
184 | m_optional_options.resize(num_option_sets); |
185 | |
186 | for (const auto &def : opt_defs) { |
187 | for (uint32_t j = 0; j < num_option_sets; j++) { |
188 | if (def.usage_mask & 1 << j) { |
189 | if (def.required) |
190 | m_required_options[j].insert(def.short_option); |
191 | else |
192 | m_optional_options[j].insert(def.short_option); |
193 | } |
194 | } |
195 | } |
196 | } |
197 | } |
198 | |
199 | uint32_t Options::NumCommandOptions() { return GetDefinitions().size(); } |
200 | |
201 | Option *Options::GetLongOptions() { |
202 | |
203 | if (m_getopt_table.empty()) { |
204 | auto defs = GetDefinitions(); |
205 | if (defs.empty()) |
206 | return nullptr; |
207 | |
208 | std::map<int, uint32_t> option_seen; |
209 | |
210 | m_getopt_table.resize(defs.size() + 1); |
211 | for (size_t i = 0; i < defs.size(); ++i) { |
212 | const int short_opt = defs[i].short_option; |
213 | |
214 | m_getopt_table[i].definition = &defs[i]; |
215 | m_getopt_table[i].flag = nullptr; |
216 | m_getopt_table[i].val = short_opt; |
217 | |
218 | if (option_seen.find(short_opt) == option_seen.end()) { |
219 | option_seen[short_opt] = i; |
220 | } else if (short_opt) { |
221 | m_getopt_table[i].val = 0; |
222 | std::map<int, uint32_t>::const_iterator pos = |
223 | option_seen.find(short_opt); |
224 | StreamString strm; |
225 | if (defs[i].HasShortOption()) |
226 | Host::SystemLog(Host::eSystemLogError, |
227 | "option[%u] --%s has a short option -%c that " |
228 | "conflicts with option[%u] --%s, short option won't " |
229 | "be used for --%s\n", |
230 | (int)i, defs[i].long_option, short_opt, pos->second, |
231 | m_getopt_table[pos->second].definition->long_option, |
232 | defs[i].long_option); |
233 | else |
234 | Host::SystemLog(Host::eSystemLogError, |
235 | "option[%u] --%s has a short option 0x%x that " |
236 | "conflicts with option[%u] --%s, short option won't " |
237 | "be used for --%s\n", |
238 | (int)i, defs[i].long_option, short_opt, pos->second, |
239 | m_getopt_table[pos->second].definition->long_option, |
240 | defs[i].long_option); |
241 | } |
242 | } |
243 | |
244 | |
245 | |
246 | m_getopt_table.back().definition = nullptr; |
247 | m_getopt_table.back().flag = nullptr; |
248 | m_getopt_table.back().val = 0; |
249 | } |
250 | |
251 | if (m_getopt_table.empty()) |
252 | return nullptr; |
253 | |
254 | return &m_getopt_table.front(); |
255 | } |
256 | |
257 | |
258 | |
259 | |
260 | |
261 | |
262 | |
263 | |
264 | |
265 | void Options::OutputFormattedUsageText(Stream &strm, |
266 | const OptionDefinition &option_def, |
267 | uint32_t output_max_columns) { |
268 | std::string actual_text; |
269 | if (option_def.validator) { |
270 | const char *condition = option_def.validator->ShortConditionString(); |
271 | if (condition) { |
272 | actual_text = "["; |
273 | actual_text.append(condition); |
274 | actual_text.append("] "); |
275 | } |
276 | } |
277 | actual_text.append(option_def.usage_text); |
278 | |
279 | |
280 | |
281 | if (static_cast<uint32_t>(actual_text.length() + strm.GetIndentLevel()) < |
282 | output_max_columns) { |
283 | |
284 | strm.Indent(actual_text); |
285 | strm.EOL(); |
286 | } else { |
287 | |
288 | |
289 | int text_width = output_max_columns - strm.GetIndentLevel() - 1; |
290 | int start = 0; |
291 | int end = start; |
292 | int final_end = actual_text.length(); |
293 | int sub_len; |
294 | |
295 | while (end < final_end) { |
296 | |
297 | |
298 | while ((start < final_end) && (actual_text[start] == ' ')) |
299 | start++; |
300 | |
301 | end = start + text_width; |
302 | if (end > final_end) |
303 | end = final_end; |
304 | else { |
305 | |
306 | |
307 | while (end > start && actual_text[end] != ' ' && |
308 | actual_text[end] != '\t' && actual_text[end] != '\n') |
309 | end--; |
310 | } |
311 | |
312 | sub_len = end - start; |
313 | if (start != 0) |
314 | strm.EOL(); |
315 | strm.Indent(); |
316 | assert(start < final_end); |
317 | assert(start + sub_len <= final_end); |
318 | strm.Write(actual_text.c_str() + start, sub_len); |
319 | start = end + 1; |
320 | } |
321 | strm.EOL(); |
322 | } |
323 | } |
324 | |
325 | bool Options::SupportsLongOption(const char *long_option) { |
326 | if (!long_option || !long_option[0]) |
327 | return false; |
328 | |
329 | auto opt_defs = GetDefinitions(); |
330 | if (opt_defs.empty()) |
331 | return false; |
332 | |
333 | const char *long_option_name = long_option; |
334 | if (long_option[0] == '-' && long_option[1] == '-') |
335 | long_option_name += 2; |
336 | |
337 | for (auto &def : opt_defs) { |
338 | if (!def.long_option) |
339 | continue; |
340 | |
341 | if (strcmp(def.long_option, long_option_name) == 0) |
342 | return true; |
343 | } |
344 | |
345 | return false; |
346 | } |
347 | |
348 | enum OptionDisplayType { |
349 | eDisplayBestOption, |
350 | eDisplayShortOption, |
351 | eDisplayLongOption |
352 | }; |
353 | |
354 | static bool PrintOption(const OptionDefinition &opt_def, |
355 | OptionDisplayType display_type, const char *header, |
356 | const char *footer, bool show_optional, Stream &strm) { |
357 | if (display_type == eDisplayShortOption && !opt_def.HasShortOption()) |
358 | return false; |
359 | |
360 | if (header && header[0]) |
361 | strm.PutCString(header); |
362 | |
363 | if (show_optional && !opt_def.required) |
364 | strm.PutChar('['); |
365 | const bool show_short_option = |
366 | opt_def.HasShortOption() && display_type != eDisplayLongOption; |
367 | if (show_short_option) |
368 | strm.Printf("-%c", opt_def.short_option); |
369 | else |
370 | strm.Printf("--%s", opt_def.long_option); |
371 | switch (opt_def.option_has_arg) { |
372 | case OptionParser::eNoArgument: |
373 | break; |
374 | case OptionParser::eRequiredArgument: |
375 | strm.Printf(" <%s>", CommandObject::GetArgumentName(opt_def.argument_type)); |
376 | break; |
377 | |
378 | case OptionParser::eOptionalArgument: |
379 | strm.Printf("%s[<%s>]", show_short_option ? "" : "=", |
380 | CommandObject::GetArgumentName(opt_def.argument_type)); |
381 | break; |
382 | } |
383 | if (show_optional && !opt_def.required) |
384 | strm.PutChar(']'); |
385 | if (footer && footer[0]) |
386 | strm.PutCString(footer); |
387 | return true; |
388 | } |
389 | |
390 | void Options::GenerateOptionUsage(Stream &strm, CommandObject *cmd, |
391 | uint32_t screen_width) { |
392 | const bool only_print_args = cmd->IsDashDashCommand(); |
393 | |
394 | auto opt_defs = GetDefinitions(); |
395 | const uint32_t save_indent_level = strm.GetIndentLevel(); |
396 | llvm::StringRef name; |
397 | |
398 | StreamString arguments_str; |
399 | |
400 | if (cmd) { |
401 | name = cmd->GetCommandName(); |
402 | cmd->GetFormattedCommandArguments(arguments_str); |
403 | } else |
404 | name = ""; |
405 | |
406 | strm.PutCString("\nCommand Options Usage:\n"); |
407 | |
408 | strm.IndentMore(2); |
409 | |
410 | |
411 | |
412 | |
413 | |
414 | |
415 | |
416 | const uint32_t num_options = NumCommandOptions(); |
417 | if (num_options == 0) |
418 | return; |
419 | |
420 | uint32_t num_option_sets = GetRequiredOptions().size(); |
421 | |
422 | uint32_t i; |
423 | |
424 | if (!only_print_args) { |
425 | for (uint32_t opt_set = 0; opt_set < num_option_sets; ++opt_set) { |
426 | uint32_t opt_set_mask; |
427 | |
428 | opt_set_mask = 1 << opt_set; |
429 | if (opt_set > 0) |
430 | strm.Printf("\n"); |
431 | strm.Indent(name); |
432 | |
433 | |
434 | StreamString args_str; |
435 | if (cmd) |
436 | cmd->GetFormattedCommandArguments(args_str, opt_set_mask); |
437 | |
438 | |
439 | |
440 | |
441 | |
442 | std::set<int> options; |
443 | std::set<int>::const_iterator options_pos, options_end; |
444 | for (auto &def : opt_defs) { |
445 | if (def.usage_mask & opt_set_mask && def.HasShortOption()) { |
446 | |
447 | |
448 | if (def.required && def.option_has_arg == OptionParser::eNoArgument) { |
449 | options.insert(def.short_option); |
450 | } |
451 | } |
452 | } |
453 | |
454 | if (!options.empty()) { |
455 | |
456 | strm.PutCString(" -"); |
457 | for (i = 0; i < 2; ++i) |
458 | for (options_pos = options.begin(), options_end = options.end(); |
459 | options_pos != options_end; ++options_pos) { |
460 | if (i == 0 && ::islower(*options_pos)) |
461 | continue; |
462 | if (i == 1 && ::isupper(*options_pos)) |
463 | continue; |
464 | strm << (char)*options_pos; |
465 | } |
466 | } |
467 | |
468 | options.clear(); |
469 | for (auto &def : opt_defs) { |
470 | if (def.usage_mask & opt_set_mask && def.HasShortOption()) { |
471 | |
472 | |
473 | if (!def.required && |
474 | def.option_has_arg == OptionParser::eNoArgument) { |
475 | options.insert(def.short_option); |
476 | } |
477 | } |
478 | } |
479 | |
480 | if (!options.empty()) { |
481 | |
482 | strm.PutCString(" [-"); |
483 | for (i = 0; i < 2; ++i) |
484 | for (options_pos = options.begin(), options_end = options.end(); |
485 | options_pos != options_end; ++options_pos) { |
486 | if (i == 0 && ::islower(*options_pos)) |
487 | continue; |
488 | if (i == 1 && ::isupper(*options_pos)) |
489 | continue; |
490 | strm << (char)*options_pos; |
491 | } |
492 | strm.PutChar(']'); |
493 | } |
494 | |
495 | |
496 | |
497 | for (auto &def : opt_defs) { |
498 | if (def.usage_mask & opt_set_mask && def.HasShortOption()) { |
499 | if (def.required && def.option_has_arg != OptionParser::eNoArgument) |
500 | PrintOption(def, eDisplayBestOption, " ", nullptr, true, strm); |
501 | } |
502 | } |
503 | |
504 | |
505 | |
506 | for (auto &def : opt_defs) { |
507 | if (def.usage_mask & opt_set_mask) { |
508 | |
509 | |
510 | if (!def.required && def.option_has_arg != OptionParser::eNoArgument) |
511 | PrintOption(def, eDisplayBestOption, " ", nullptr, true, strm); |
512 | } |
513 | } |
514 | |
515 | if (args_str.GetSize() > 0) { |
516 | if (cmd->WantsRawCommandString() && !only_print_args) |
517 | strm.Printf(" --"); |
518 | |
519 | strm << " " << args_str.GetString(); |
520 | if (only_print_args) |
521 | break; |
522 | } |
523 | } |
524 | } |
525 | |
526 | if (cmd && (only_print_args || cmd->WantsRawCommandString()) && |
527 | arguments_str.GetSize() > 0) { |
528 | if (!only_print_args) |
529 | strm.PutChar('\n'); |
530 | strm.Indent(name); |
531 | strm << " " << arguments_str.GetString(); |
532 | } |
533 | |
534 | strm.Printf("\n\n"); |
535 | |
536 | if (!only_print_args) { |
537 | |
538 | |
539 | |
540 | |
541 | |
542 | |
543 | |
544 | |
545 | |
546 | std::multimap<int, uint32_t> options_seen; |
547 | strm.IndentMore(5); |
548 | |
549 | |
550 | |
551 | |
552 | |
553 | i = 0; |
554 | for (auto &def : opt_defs) |
555 | options_seen.insert(std::make_pair(def.short_option, i++)); |
556 | |
557 | |
558 | |
559 | |
560 | |
561 | bool first_option_printed = false; |
562 | |
563 | for (auto pos : options_seen) { |
564 | i = pos.second; |
565 | |
566 | |
567 | |
568 | if (first_option_printed) |
569 | strm.EOL(); |
570 | else |
571 | first_option_printed = true; |
572 | |
573 | CommandArgumentType arg_type = opt_defs[i].argument_type; |
574 | |
575 | StreamString arg_name_str; |
576 | arg_name_str.Printf("<%s>", CommandObject::GetArgumentName(arg_type)); |
577 | |
578 | strm.Indent(); |
579 | if (opt_defs[i].short_option && opt_defs[i].HasShortOption()) { |
580 | PrintOption(opt_defs[i], eDisplayShortOption, nullptr, nullptr, false, |
581 | strm); |
582 | PrintOption(opt_defs[i], eDisplayLongOption, " ( ", " )", false, strm); |
583 | } else { |
584 | |
585 | PrintOption(opt_defs[i], eDisplayLongOption, nullptr, nullptr, false, |
586 | strm); |
587 | } |
588 | strm.EOL(); |
589 | |
590 | strm.IndentMore(5); |
591 | |
592 | if (opt_defs[i].usage_text) |
593 | OutputFormattedUsageText(strm, opt_defs[i], screen_width); |
594 | if (!opt_defs[i].enum_values.empty()) { |
595 | strm.Indent(); |
596 | strm.Printf("Values: "); |
597 | bool is_first = true; |
598 | for (const auto &enum_value : opt_defs[i].enum_values) { |
599 | if (is_first) { |
600 | strm.Printf("%s", enum_value.string_value); |
601 | is_first = false; |
602 | } |
603 | else |
604 | strm.Printf(" | %s", enum_value.string_value); |
605 | } |
606 | strm.EOL(); |
607 | } |
608 | strm.IndentLess(5); |
609 | } |
610 | } |
611 | |
612 | |
613 | strm.SetIndentLevel(save_indent_level); |
614 | } |
615 | |
616 | |
617 | |
618 | |
619 | |
620 | |
621 | |
622 | bool Options::VerifyPartialOptions(CommandReturnObject &result) { |
623 | bool options_are_valid = false; |
624 | |
625 | int num_levels = GetRequiredOptions().size(); |
626 | if (num_levels) { |
627 | for (int i = 0; i < num_levels && !options_are_valid; ++i) { |
628 | |
629 | |
630 | |
631 | OptionSet union_set; |
632 | OptionsSetUnion(GetRequiredOptions()[i], GetOptionalOptions()[i], |
633 | union_set); |
634 | if (IsASubset(m_seen_options, union_set)) |
635 | options_are_valid = true; |
636 | } |
637 | } |
638 | |
639 | return options_are_valid; |
640 | } |
641 | |
642 | bool Options::HandleOptionCompletion(CompletionRequest &request, |
643 | OptionElementVector &opt_element_vector, |
644 | CommandInterpreter &interpreter) { |
645 | |
646 | |
647 | |
648 | |
649 | |
650 | auto opt_defs = GetDefinitions(); |
651 | |
652 | llvm::StringRef cur_opt_str = request.GetCursorArgumentPrefix(); |
653 | |
654 | for (size_t i = 0; i < opt_element_vector.size(); i++) { |
655 | size_t opt_pos = static_cast<size_t>(opt_element_vector[i].opt_pos); |
656 | size_t opt_arg_pos = static_cast<size_t>(opt_element_vector[i].opt_arg_pos); |
657 | int opt_defs_index = opt_element_vector[i].opt_defs_index; |
658 | if (opt_pos == request.GetCursorIndex()) { |
659 | |
660 | |
661 | if (opt_defs_index == OptionArgElement::eBareDash) { |
662 | |
663 | |
664 | |
665 | |
666 | std::string opt_str = "-a"; |
667 | |
668 | for (auto &def : opt_defs) { |
669 | if (!def.short_option) |
670 | continue; |
671 | opt_str[1] = def.short_option; |
672 | request.AddCompletion(opt_str, def.usage_text); |
673 | } |
674 | |
675 | return true; |
676 | } else if (opt_defs_index == OptionArgElement::eBareDoubleDash) { |
677 | std::string full_name("--"); |
678 | for (auto &def : opt_defs) { |
679 | if (!def.short_option) |
680 | continue; |
681 | |
682 | full_name.erase(full_name.begin() + 2, full_name.end()); |
683 | full_name.append(def.long_option); |
684 | request.AddCompletion(full_name, def.usage_text); |
685 | } |
686 | return true; |
687 | } else if (opt_defs_index != OptionArgElement::eUnrecognizedArg) { |
688 | |
689 | |
690 | |
691 | |
692 | const OptionDefinition &opt = opt_defs[opt_defs_index]; |
693 | llvm::StringRef long_option = opt.long_option; |
694 | if (cur_opt_str.startswith("--") && cur_opt_str != long_option) { |
695 | request.AddCompletion("--" + long_option.str(), opt.usage_text); |
696 | return true; |
697 | } else |
698 | request.AddCompletion(request.GetCursorArgumentPrefix()); |
699 | return true; |
700 | } else { |
701 | |
702 | |
703 | |
704 | |
705 | |
706 | |
707 | if (cur_opt_str.consume_front("--")) { |
708 | for (auto &def : opt_defs) { |
709 | llvm::StringRef long_option(def.long_option); |
710 | if (long_option.startswith(cur_opt_str)) |
711 | request.AddCompletion("--" + long_option.str(), def.usage_text); |
712 | } |
713 | } |
714 | return true; |
715 | } |
716 | |
717 | } else if (opt_arg_pos == request.GetCursorIndex()) { |
718 | |
719 | |
720 | if (opt_defs_index != -1) { |
721 | HandleOptionArgumentCompletion(request, opt_element_vector, i, |
722 | interpreter); |
723 | return true; |
724 | } else { |
725 | |
726 | return true; |
727 | } |
728 | |
729 | } else { |
730 | |
731 | continue; |
732 | } |
733 | } |
734 | return false; |
735 | } |
736 | |
737 | void Options::HandleOptionArgumentCompletion( |
738 | CompletionRequest &request, OptionElementVector &opt_element_vector, |
739 | int opt_element_index, CommandInterpreter &interpreter) { |
740 | auto opt_defs = GetDefinitions(); |
741 | std::unique_ptr<SearchFilter> filter_up; |
742 | |
743 | int opt_defs_index = opt_element_vector[opt_element_index].opt_defs_index; |
744 | |
745 | |
746 | |
747 | const auto &enum_values = opt_defs[opt_defs_index].enum_values; |
748 | if (!enum_values.empty()) |
749 | for (const auto &enum_value : enum_values) |
750 | request.TryCompleteCurrentArg(enum_value.string_value); |
751 | |
752 | |
753 | |
754 | |
755 | |
756 | |
757 | |
758 | uint32_t completion_mask = opt_defs[opt_defs_index].completion_type; |
759 | |
760 | if (completion_mask == 0) { |
761 | lldb::CommandArgumentType option_arg_type = |
762 | opt_defs[opt_defs_index].argument_type; |
763 | if (option_arg_type != eArgTypeNone) { |
764 | const CommandObject::ArgumentTableEntry *arg_entry = |
765 | CommandObject::FindArgumentDataByType( |
766 | opt_defs[opt_defs_index].argument_type); |
767 | if (arg_entry) |
768 | completion_mask = arg_entry->completion_type; |
769 | } |
770 | } |
771 | |
772 | if (completion_mask & CommandCompletions::eSourceFileCompletion || |
773 | completion_mask & CommandCompletions::eSymbolCompletion) { |
774 | for (size_t i = 0; i < opt_element_vector.size(); i++) { |
775 | int cur_defs_index = opt_element_vector[i].opt_defs_index; |
776 | |
777 | |
778 | if (cur_defs_index == OptionArgElement::eUnrecognizedArg || |
779 | cur_defs_index == OptionArgElement::eBareDash || |
780 | cur_defs_index == OptionArgElement::eBareDoubleDash) |
781 | continue; |
782 | |
783 | int cur_arg_pos = opt_element_vector[i].opt_arg_pos; |
784 | const char *cur_opt_name = opt_defs[cur_defs_index].long_option; |
785 | |
786 | |
787 | |
788 | if (cur_opt_name && strcmp(cur_opt_name, "shlib") == 0 && |
789 | cur_arg_pos != -1) { |
790 | const char *module_name = |
791 | request.GetParsedLine().GetArgumentAtIndex(cur_arg_pos); |
792 | if (module_name) { |
793 | FileSpec module_spec(module_name); |
794 | lldb::TargetSP target_sp = |
795 | interpreter.GetDebugger().GetSelectedTarget(); |
796 | |
797 | if (target_sp) |
798 | filter_up = |
799 | std::make_unique<SearchFilterByModule>(target_sp, module_spec); |
800 | } |
801 | break; |
802 | } |
803 | } |
804 | } |
805 | |
806 | CommandCompletions::InvokeCommonCompletionCallbacks( |
807 | interpreter, completion_mask, request, filter_up.get()); |
808 | } |
809 | |
810 | void OptionGroupOptions::Append(OptionGroup *group) { |
811 | auto group_option_defs = group->GetDefinitions(); |
812 | for (uint32_t i = 0; i < group_option_defs.size(); ++i) { |
813 | m_option_infos.push_back(OptionInfo(group, i)); |
814 | m_option_defs.push_back(group_option_defs[i]); |
815 | } |
816 | } |
817 | |
818 | const OptionGroup *OptionGroupOptions::GetGroupWithOption(char short_opt) { |
819 | for (uint32_t i = 0; i < m_option_defs.size(); i++) { |
820 | OptionDefinition opt_def = m_option_defs[i]; |
821 | if (opt_def.short_option == short_opt) |
822 | return m_option_infos[i].option_group; |
823 | } |
824 | return nullptr; |
825 | } |
826 | |
827 | void OptionGroupOptions::Append(OptionGroup *group, uint32_t src_mask, |
828 | uint32_t dst_mask) { |
829 | auto group_option_defs = group->GetDefinitions(); |
830 | for (uint32_t i = 0; i < group_option_defs.size(); ++i) { |
831 | if (group_option_defs[i].usage_mask & src_mask) { |
832 | m_option_infos.push_back(OptionInfo(group, i)); |
833 | m_option_defs.push_back(group_option_defs[i]); |
834 | m_option_defs.back().usage_mask = dst_mask; |
835 | } |
836 | } |
837 | } |
838 | |
839 | void OptionGroupOptions::Finalize() { |
840 | m_did_finalize = true; |
841 | } |
842 | |
843 | Status OptionGroupOptions::SetOptionValue(uint32_t option_idx, |
844 | llvm::StringRef option_value, |
845 | ExecutionContext *execution_context) { |
846 | |
847 | |
848 | assert(m_did_finalize); |
849 | Status error; |
850 | if (option_idx < m_option_infos.size()) { |
851 | error = m_option_infos[option_idx].option_group->SetOptionValue( |
852 | m_option_infos[option_idx].option_index, option_value, |
853 | execution_context); |
854 | |
855 | } else { |
856 | error.SetErrorString("invalid option index"); |
857 | } |
858 | return error; |
859 | } |
860 | |
861 | void OptionGroupOptions::OptionParsingStarting( |
862 | ExecutionContext *execution_context) { |
863 | std::set<OptionGroup *> group_set; |
864 | OptionInfos::iterator pos, end = m_option_infos.end(); |
865 | for (pos = m_option_infos.begin(); pos != end; ++pos) { |
866 | OptionGroup *group = pos->option_group; |
867 | if (group_set.find(group) == group_set.end()) { |
868 | group->OptionParsingStarting(execution_context); |
869 | group_set.insert(group); |
870 | } |
871 | } |
872 | } |
873 | Status |
874 | OptionGroupOptions::OptionParsingFinished(ExecutionContext *execution_context) { |
875 | std::set<OptionGroup *> group_set; |
876 | Status error; |
877 | OptionInfos::iterator pos, end = m_option_infos.end(); |
878 | for (pos = m_option_infos.begin(); pos != end; ++pos) { |
879 | OptionGroup *group = pos->option_group; |
880 | if (group_set.find(group) == group_set.end()) { |
881 | error = group->OptionParsingFinished(execution_context); |
882 | group_set.insert(group); |
883 | if (error.Fail()) |
884 | return error; |
885 | } |
886 | } |
887 | return error; |
888 | } |
889 | |
890 | |
891 | |
892 | |
893 | |
894 | static std::vector<char *> GetArgvForParsing(const Args &args) { |
895 | std::vector<char *> result; |
896 | |
897 | result.push_back(const_cast<char *>("<FAKE-ARG0>")); |
898 | for (const Args::ArgEntry &entry : args) |
899 | result.push_back(const_cast<char *>(entry.c_str())); |
900 | result.push_back(nullptr); |
901 | return result; |
902 | } |
903 | |
904 | |
905 | static Args::const_iterator FindOriginalIter(const char *arg, |
906 | const Args &original) { |
907 | return llvm::find_if( |
908 | original, [arg](const Args::ArgEntry &D) { return D.c_str() == arg; }); |
909 | } |
910 | |
911 | |
912 | static size_t FindOriginalIndex(const char *arg, const Args &original) { |
913 | return std::distance(original.begin(), FindOriginalIter(arg, original)); |
914 | } |
915 | |
916 | |
917 | |
918 | static Args ReconstituteArgsAfterParsing(llvm::ArrayRef<char *> parsed, |
919 | const Args &original) { |
920 | Args result; |
921 | for (const char *arg : parsed) { |
922 | auto pos = FindOriginalIter(arg, original); |
923 | assert(pos != original.end()); |
924 | result.AppendArgument(pos->ref(), pos->GetQuoteChar()); |
925 | } |
926 | return result; |
927 | } |
928 | |
929 | static size_t FindArgumentIndexForOption(const Args &args, |
930 | const Option &long_option) { |
931 | std::string short_opt = llvm::formatv("-{0}", char(long_option.val)).str(); |
932 | std::string long_opt = |
933 | std::string(llvm::formatv("--{0}", long_option.definition->long_option)); |
| 21 | | Forming reference to null pointer |
|
934 | for (const auto &entry : llvm::enumerate(args)) { |
935 | if (entry.value().ref().startswith(short_opt) || |
936 | entry.value().ref().startswith(long_opt)) |
937 | return entry.index(); |
938 | } |
939 | |
940 | return size_t(-1); |
941 | } |
942 | |
943 | static std::string BuildShortOptions(const Option *long_options) { |
944 | std::string storage; |
945 | llvm::raw_string_ostream sstr(storage); |
946 | |
947 | |
948 | |
949 | sstr << ":"; |
950 | |
951 | for (size_t i = 0; long_options[i].definition != nullptr; ++i) { |
952 | if (long_options[i].flag == nullptr) { |
953 | sstr << (char)long_options[i].val; |
954 | switch (long_options[i].definition->option_has_arg) { |
955 | default: |
956 | case OptionParser::eNoArgument: |
957 | break; |
958 | case OptionParser::eRequiredArgument: |
959 | sstr << ":"; |
960 | break; |
961 | case OptionParser::eOptionalArgument: |
962 | sstr << "::"; |
963 | break; |
964 | } |
965 | } |
966 | } |
967 | return std::move(sstr.str()); |
968 | } |
969 | |
970 | llvm::Expected<Args> Options::ParseAlias(const Args &args, |
971 | OptionArgVector *option_arg_vector, |
972 | std::string &input_line) { |
973 | Option *long_options = GetLongOptions(); |
974 | |
975 | if (long_options == nullptr) { |
| 1 | Assuming the condition is false | |
|
| |
976 | return llvm::make_error<llvm::StringError>("Invalid long options", |
977 | llvm::inconvertibleErrorCode()); |
978 | } |
979 | |
980 | std::string short_options = BuildShortOptions(long_options); |
981 | |
982 | Args args_copy = args; |
983 | std::vector<char *> argv = GetArgvForParsing(args); |
984 | |
985 | std::unique_lock<std::mutex> lock; |
986 | OptionParser::Prepare(lock); |
987 | int val; |
988 | while (true) { |
| 3 | | Loop condition is true. Entering loop body | |
|
989 | int long_options_index = -1; |
990 | val = OptionParser::Parse(argv, short_options, long_options, |
991 | &long_options_index); |
992 | |
993 | if (val == ':') { |
| 4 | | Assuming the condition is false | |
|
| |
994 | return llvm::createStringError(llvm::inconvertibleErrorCode(), |
995 | "last option requires an argument"); |
996 | } |
997 | |
998 | if (val == -1) |
| 6 | | Assuming the condition is false | |
|
| |
999 | break; |
1000 | |
1001 | if (val == '?') { |
| 8 | | Assuming the condition is false | |
|
| |
1002 | return llvm::make_error<llvm::StringError>( |
1003 | "Unknown or ambiguous option", llvm::inconvertibleErrorCode()); |
1004 | } |
1005 | |
1006 | if (val == 0) |
| 10 | | Assuming 'val' is not equal to 0 | |
|
| |
1007 | continue; |
1008 | |
1009 | OptionSeen(val); |
1010 | |
1011 | |
1012 | if (long_options_index == -1) { |
| 12 | | Assuming the condition is false | |
|
| |
1013 | for (int j = 0; long_options[j].definition || long_options[j].flag || |
1014 | long_options[j].val; |
1015 | ++j) { |
1016 | if (long_options[j].val == val) { |
1017 | long_options_index = j; |
1018 | break; |
1019 | } |
1020 | } |
1021 | } |
1022 | |
1023 | |
1024 | if (long_options_index == -1) { |
| |
1025 | return llvm::make_error<llvm::StringError>( |
1026 | llvm::formatv("Invalid option with value '{0}'.", char(val)).str(), |
1027 | llvm::inconvertibleErrorCode()); |
1028 | } |
1029 | |
1030 | StreamString option_str; |
1031 | option_str.Printf("-%c", val); |
1032 | const OptionDefinition *def = long_options[long_options_index].definition; |
1033 | int has_arg = |
1034 | (def == nullptr) ? OptionParser::eNoArgument : def->option_has_arg; |
| 15 | | Assuming pointer value is null | |
|
| |
1035 | |
1036 | const char *option_arg = nullptr; |
1037 | switch (has_arg) { |
| 17 | | Control jumps to 'case eNoArgument:' at line 1050 | |
|
1038 | case OptionParser::eRequiredArgument: |
1039 | if (OptionParser::GetOptionArgument() == nullptr) { |
1040 | return llvm::make_error<llvm::StringError>( |
1041 | llvm::formatv("Option '{0}' is missing argument specifier.", |
1042 | option_str.GetString()) |
1043 | .str(), |
1044 | llvm::inconvertibleErrorCode()); |
1045 | } |
1046 | LLVM_FALLTHROUGH; |
1047 | case OptionParser::eOptionalArgument: |
1048 | option_arg = OptionParser::GetOptionArgument(); |
1049 | LLVM_FALLTHROUGH; |
1050 | case OptionParser::eNoArgument: |
1051 | break; |
| 18 | | Execution continues on line 1060 | |
|
1052 | default: |
1053 | return llvm::make_error<llvm::StringError>( |
1054 | llvm::formatv("error with options table; invalid value in has_arg " |
1055 | "field for option '{0}'.", |
1056 | char(val)) |
1057 | .str(), |
1058 | llvm::inconvertibleErrorCode()); |
1059 | } |
1060 | if (!option_arg) |
| |
1061 | option_arg = "<no-argument>"; |
1062 | option_arg_vector->emplace_back(std::string(option_str.GetString()), |
1063 | has_arg, std::string(option_arg)); |
1064 | |
1065 | |
1066 | |
1067 | |
1068 | |
1069 | size_t idx = |
1070 | FindArgumentIndexForOption(args_copy, long_options[long_options_index]); |
| 20 | | Calling 'FindArgumentIndexForOption' | |
|
1071 | if (idx == size_t(-1)) |
1072 | continue; |
1073 | |
1074 | if (!input_line.empty()) { |
1075 | auto tmp_arg = args_copy[idx].ref(); |
1076 | size_t pos = input_line.find(std::string(tmp_arg)); |
1077 | if (pos != std::string::npos) |
1078 | input_line.erase(pos, tmp_arg.size()); |
1079 | } |
1080 | args_copy.DeleteArgumentAtIndex(idx); |
1081 | if ((long_options[long_options_index].definition->option_has_arg != |
1082 | OptionParser::eNoArgument) && |
1083 | (OptionParser::GetOptionArgument() != nullptr) && |
1084 | (idx < args_copy.GetArgumentCount()) && |
1085 | (args_copy[idx].ref() == OptionParser::GetOptionArgument())) { |
1086 | if (input_line.size() > 0) { |
1087 | auto tmp_arg = args_copy[idx].ref(); |
1088 | size_t pos = input_line.find(std::string(tmp_arg)); |
1089 | if (pos != std::string::npos) |
1090 | input_line.erase(pos, tmp_arg.size()); |
1091 | } |
1092 | args_copy.DeleteArgumentAtIndex(idx); |
1093 | } |
1094 | } |
1095 | |
1096 | return std::move(args_copy); |
1097 | } |
1098 | |
1099 | OptionElementVector Options::ParseForCompletion(const Args &args, |
1100 | uint32_t cursor_index) { |
1101 | OptionElementVector option_element_vector; |
1102 | Option *long_options = GetLongOptions(); |
1103 | option_element_vector.clear(); |
1104 | |
1105 | if (long_options == nullptr) |
1106 | return option_element_vector; |
1107 | |
1108 | std::string short_options = BuildShortOptions(long_options); |
1109 | |
1110 | std::unique_lock<std::mutex> lock; |
1111 | OptionParser::Prepare(lock); |
1112 | OptionParser::EnableError(false); |
1113 | |
1114 | int val; |
1115 | auto opt_defs = GetDefinitions(); |
1116 | |
1117 | std::vector<char *> dummy_vec = GetArgvForParsing(args); |
1118 | |
1119 | bool failed_once = false; |
1120 | uint32_t dash_dash_pos = -1; |
1121 | |
1122 | while (true) { |
1123 | bool missing_argument = false; |
1124 | int long_options_index = -1; |
1125 | |
1126 | val = OptionParser::Parse(dummy_vec, short_options, long_options, |
1127 | &long_options_index); |
1128 | |
1129 | if (val == -1) { |
1130 | |
1131 | if (failed_once) |
1132 | break; |
1133 | |
1134 | failed_once = true; |
1135 | |
1136 | |
1137 | |
1138 | |
1139 | |
1140 | |
1141 | |
1142 | |
1143 | |
1144 | |
1145 | |
1146 | |
1147 | |
1148 | if (static_cast<size_t>(OptionParser::GetOptionIndex()) < |
1149 | dummy_vec.size() && |
1150 | (strcmp(dummy_vec[OptionParser::GetOptionIndex() - 1], "--") == 0)) { |
1151 | dash_dash_pos = FindOriginalIndex( |
1152 | dummy_vec[OptionParser::GetOptionIndex() - 1], args); |
1153 | if (dash_dash_pos == cursor_index) { |
1154 | option_element_vector.push_back( |
1155 | OptionArgElement(OptionArgElement::eBareDoubleDash, dash_dash_pos, |
1156 | OptionArgElement::eBareDoubleDash)); |
1157 | continue; |
1158 | } else |
1159 | break; |
1160 | } else |
1161 | break; |
1162 | } else if (val == '?') { |
1163 | option_element_vector.push_back(OptionArgElement( |
1164 | OptionArgElement::eUnrecognizedArg, |
1165 | FindOriginalIndex(dummy_vec[OptionParser::GetOptionIndex() - 1], |
1166 | args), |
1167 | OptionArgElement::eUnrecognizedArg)); |
1168 | continue; |
1169 | } else if (val == 0) { |
1170 | continue; |
1171 | } else if (val == ':') { |
1172 | |
1173 | val = OptionParser::GetOptionErrorCause(); |
1174 | missing_argument = true; |
1175 | } |
1176 | |
1177 | OptionSeen(val); |
1178 | |
1179 | |
1180 | if (long_options_index == -1) { |
1181 | for (int j = 0; long_options[j].definition || long_options[j].flag || |
1182 | long_options[j].val; |
1183 | ++j) { |
1184 | if (long_options[j].val == val) { |
1185 | long_options_index = j; |
1186 | break; |
1187 | } |
1188 | } |
1189 | } |
1190 | |
1191 | |
1192 | if (long_options_index >= 0) { |
1193 | int opt_defs_index = -1; |
1194 | for (size_t i = 0; i < opt_defs.size(); i++) { |
1195 | if (opt_defs[i].short_option != val) |
1196 | continue; |
1197 | opt_defs_index = i; |
1198 | break; |
1199 | } |
1200 | |
1201 | const OptionDefinition *def = long_options[long_options_index].definition; |
1202 | int has_arg = |
1203 | (def == nullptr) ? OptionParser::eNoArgument : def->option_has_arg; |
1204 | switch (has_arg) { |
1205 | case OptionParser::eNoArgument: |
1206 | option_element_vector.push_back(OptionArgElement( |
1207 | opt_defs_index, |
1208 | FindOriginalIndex(dummy_vec[OptionParser::GetOptionIndex() - 1], |
1209 | args), |
1210 | 0)); |
1211 | break; |
1212 | case OptionParser::eRequiredArgument: |
1213 | if (OptionParser::GetOptionArgument() != nullptr) { |
1214 | int arg_index; |
1215 | if (missing_argument) |
1216 | arg_index = -1; |
1217 | else |
1218 | arg_index = OptionParser::GetOptionIndex() - 2; |
1219 | |
1220 | option_element_vector.push_back(OptionArgElement( |
1221 | opt_defs_index, |
1222 | FindOriginalIndex(dummy_vec[OptionParser::GetOptionIndex() - 2], |
1223 | args), |
1224 | arg_index)); |
1225 | } else { |
1226 | option_element_vector.push_back(OptionArgElement( |
1227 | opt_defs_index, |
1228 | FindOriginalIndex(dummy_vec[OptionParser::GetOptionIndex() - 1], |
1229 | args), |
1230 | -1)); |
1231 | } |
1232 | break; |
1233 | case OptionParser::eOptionalArgument: |
1234 | if (OptionParser::GetOptionArgument() != nullptr) { |
1235 | option_element_vector.push_back(OptionArgElement( |
1236 | opt_defs_index, |
1237 | FindOriginalIndex(dummy_vec[OptionParser::GetOptionIndex() - 2], |
1238 | args), |
1239 | FindOriginalIndex(dummy_vec[OptionParser::GetOptionIndex() - 1], |
1240 | args))); |
1241 | } else { |
1242 | option_element_vector.push_back(OptionArgElement( |
1243 | opt_defs_index, |
1244 | FindOriginalIndex(dummy_vec[OptionParser::GetOptionIndex() - 2], |
1245 | args), |
1246 | FindOriginalIndex(dummy_vec[OptionParser::GetOptionIndex() - 1], |
1247 | args))); |
1248 | } |
1249 | break; |
1250 | default: |
1251 | |
1252 | option_element_vector.push_back(OptionArgElement( |
1253 | OptionArgElement::eUnrecognizedArg, |
1254 | FindOriginalIndex(dummy_vec[OptionParser::GetOptionIndex() - 1], |
1255 | args), |
1256 | OptionArgElement::eUnrecognizedArg)); |
1257 | break; |
1258 | } |
1259 | } else { |
1260 | option_element_vector.push_back(OptionArgElement( |
1261 | OptionArgElement::eUnrecognizedArg, |
1262 | FindOriginalIndex(dummy_vec[OptionParser::GetOptionIndex() - 1], |
1263 | args), |
1264 | OptionArgElement::eUnrecognizedArg)); |
1265 | } |
1266 | } |
1267 | |
1268 | |
1269 | |
1270 | |
1271 | |
1272 | |
1273 | |
1274 | |
1275 | const Args::ArgEntry &cursor = args[cursor_index]; |
1276 | if ((static_cast<int32_t>(dash_dash_pos) == -1 || |
1277 | cursor_index < dash_dash_pos) && |
1278 | !cursor.IsQuoted() && cursor.ref() == "-") { |
1279 | option_element_vector.push_back( |
1280 | OptionArgElement(OptionArgElement::eBareDash, cursor_index, |
1281 | OptionArgElement::eBareDash)); |
1282 | } |
1283 | return option_element_vector; |
1284 | } |
1285 | |
1286 | llvm::Expected<Args> Options::Parse(const Args &args, |
1287 | ExecutionContext *execution_context, |
1288 | lldb::PlatformSP platform_sp, |
1289 | bool require_validation) { |
1290 | Status error; |
1291 | Option *long_options = GetLongOptions(); |
1292 | if (long_options == nullptr) { |
1293 | return llvm::make_error<llvm::StringError>("Invalid long options.", |
1294 | llvm::inconvertibleErrorCode()); |
1295 | } |
1296 | |
1297 | std::string short_options = BuildShortOptions(long_options); |
1298 | std::vector<char *> argv = GetArgvForParsing(args); |
1299 | std::unique_lock<std::mutex> lock; |
1300 | OptionParser::Prepare(lock); |
1301 | int val; |
1302 | while (true) { |
1303 | int long_options_index = -1; |
1304 | val = OptionParser::Parse(argv, short_options, long_options, |
1305 | &long_options_index); |
1306 | |
1307 | if (val == ':') { |
1308 | error.SetErrorString("last option requires an argument"); |
1309 | break; |
1310 | } |
1311 | |
1312 | if (val == -1) |
1313 | break; |
1314 | |
1315 | |
1316 | if (val == '?') { |
1317 | error.SetErrorString("unknown or ambiguous option"); |
1318 | break; |
1319 | } |
1320 | |
1321 | if (val == 0) |
1322 | continue; |
1323 | |
1324 | OptionSeen(val); |
1325 | |
1326 | |
1327 | if (long_options_index == -1) { |
1328 | for (int i = 0; long_options[i].definition || long_options[i].flag || |
1329 | long_options[i].val; |
1330 | ++i) { |
1331 | if (long_options[i].val == val) { |
1332 | long_options_index = i; |
1333 | break; |
1334 | } |
1335 | } |
1336 | } |
1337 | |
1338 | if (long_options_index >= 0 && |
1339 | long_options[long_options_index].definition) { |
1340 | const OptionDefinition *def = long_options[long_options_index].definition; |
1341 | |
1342 | if (!platform_sp) { |
1343 | |
1344 | |
1345 | TargetSP target_sp = |
1346 | execution_context ? execution_context->GetTargetSP() : TargetSP(); |
1347 | platform_sp = target_sp ? target_sp->GetPlatform() : PlatformSP(); |
1348 | } |
1349 | OptionValidator *validator = def->validator; |
1350 | |
1351 | if (!platform_sp && require_validation) { |
1352 | |
1353 | |
1354 | return llvm::make_error<llvm::StringError>( |
1355 | "cannot validate options: no platform available", |
1356 | llvm::inconvertibleErrorCode()); |
1357 | } |
1358 | |
1359 | bool validation_failed = false; |
1360 | if (platform_sp) { |
1361 | |
1362 | ExecutionContext dummy_context; |
1363 | ExecutionContext *exe_ctx_p = |
1364 | execution_context ? execution_context : &dummy_context; |
1365 | if (validator && !validator->IsValid(*platform_sp, *exe_ctx_p)) { |
1366 | validation_failed = true; |
1367 | error.SetErrorStringWithFormat("Option \"%s\" invalid. %s", |
1368 | def->long_option, |
1369 | def->validator->LongConditionString()); |
1370 | } |
1371 | } |
1372 | |
1373 | |
1374 | if (!validation_failed) |
1375 | error = |
1376 | SetOptionValue(long_options_index, |
1377 | (def->option_has_arg == OptionParser::eNoArgument) |
1378 | ? nullptr |
1379 | : OptionParser::GetOptionArgument(), |
1380 | execution_context); |
1381 | |
1382 | |
1383 | if (error.Fail()) |
1384 | break; |
1385 | } else { |
1386 | error.SetErrorStringWithFormat("invalid option with value '%i'", val); |
1387 | } |
1388 | } |
1389 | |
1390 | if (error.Fail()) |
1391 | return error.ToError(); |
1392 | |
1393 | argv.pop_back(); |
1394 | argv.erase(argv.begin(), argv.begin() + OptionParser::GetOptionIndex()); |
1395 | return ReconstituteArgsAfterParsing(argv, args); |
1396 | } |