1 /* CLI options framework, for GDB. 2 3 Copyright (C) 2017-2020 Free Software Foundation, Inc. 4 5 This file is part of GDB. 6 7 This program is free software; you can redistribute it and/or modify 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation; either version 3 of the License, or 10 (at your option) any later version. 11 12 This program is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 19 20 #include "defs.h" 21 #include "cli/cli-option.h" 22 #include "cli/cli-decode.h" 23 #include "cli/cli-utils.h" 24 #include "cli/cli-setshow.h" 25 #include "command.h" 26 #include <vector> 27 28 namespace gdb { 29 namespace option { 30 31 /* An option's value. Which field is active depends on the option's 32 type. */ 33 union option_value 34 { 35 /* For var_boolean options. */ 36 bool boolean; 37 38 /* For var_uinteger options. */ 39 unsigned int uinteger; 40 41 /* For var_zuinteger_unlimited options. */ 42 int integer; 43 44 /* For var_enum options. */ 45 const char *enumeration; 46 47 /* For var_string options. This is malloc-allocated. */ 48 char *string; 49 }; 50 51 /* Holds an options definition and its value. */ 52 struct option_def_and_value 53 { 54 /* The option definition. */ 55 const option_def &option; 56 57 /* A context. */ 58 void *ctx; 59 60 /* The option's value, if any. */ 61 gdb::optional<option_value> value; 62 63 /* Constructor. */ 64 option_def_and_value (const option_def &option_, void *ctx_, 65 gdb::optional<option_value> &&value_ = {}) 66 : option (option_), 67 ctx (ctx_), 68 value (std::move (value_)) 69 { 70 clear_value (option_, value_); 71 } 72 73 /* Move constructor. Need this because for some types the values 74 are allocated on the heap. */ 75 option_def_and_value (option_def_and_value &&rval) 76 : option (rval.option), 77 ctx (rval.ctx), 78 value (std::move (rval.value)) 79 { 80 clear_value (rval.option, rval.value); 81 } 82 83 DISABLE_COPY_AND_ASSIGN (option_def_and_value); 84 85 ~option_def_and_value () 86 { 87 if (value.has_value ()) 88 { 89 if (option.type == var_string) 90 xfree (value->string); 91 } 92 } 93 94 private: 95 96 /* Clear the option_value, without releasing it. This is used after 97 the value has been moved to some other option_def_and_value 98 instance. This is needed because for some types the value is 99 allocated on the heap, so we must clear the pointer in the 100 source, to avoid a double free. */ 101 static void clear_value (const option_def &option, 102 gdb::optional<option_value> &value) 103 { 104 if (value.has_value ()) 105 { 106 if (option.type == var_string) 107 value->string = nullptr; 108 } 109 } 110 }; 111 112 static void save_option_value_in_ctx (gdb::optional<option_def_and_value> &ov); 113 114 /* Info passed around when handling completion. */ 115 struct parse_option_completion_info 116 { 117 /* The completion word. */ 118 const char *word; 119 120 /* The tracker. */ 121 completion_tracker &tracker; 122 }; 123 124 /* If ARGS starts with "-", look for a "--" delimiter. If one is 125 found, then interpret everything up until the "--" as command line 126 options. Otherwise, interpret unknown input as the beginning of 127 the command's operands. */ 128 129 static const char * 130 find_end_options_delimiter (const char *args) 131 { 132 if (args[0] == '-') 133 { 134 const char *p = args; 135 136 p = skip_spaces (p); 137 while (*p) 138 { 139 if (check_for_argument (&p, "--")) 140 return p; 141 else 142 p = skip_to_space (p); 143 p = skip_spaces (p); 144 } 145 } 146 147 return nullptr; 148 } 149 150 /* Complete TEXT/WORD on all options in OPTIONS_GROUP. */ 151 152 static void 153 complete_on_options (gdb::array_view<const option_def_group> options_group, 154 completion_tracker &tracker, 155 const char *text, const char *word) 156 { 157 size_t textlen = strlen (text); 158 for (const auto &grp : options_group) 159 for (const auto &opt : grp.options) 160 if (strncmp (opt.name, text, textlen) == 0) 161 { 162 tracker.add_completion 163 (make_completion_match_str (opt.name, text, word)); 164 } 165 } 166 167 /* See cli-option.h. */ 168 169 void 170 complete_on_all_options (completion_tracker &tracker, 171 gdb::array_view<const option_def_group> options_group) 172 { 173 static const char opt[] = "-"; 174 complete_on_options (options_group, tracker, opt + 1, opt); 175 } 176 177 /* Parse ARGS, guided by OPTIONS_GROUP. HAVE_DELIMITER is true if the 178 whole ARGS line included the "--" options-terminator delimiter. */ 179 180 static gdb::optional<option_def_and_value> 181 parse_option (gdb::array_view<const option_def_group> options_group, 182 process_options_mode mode, 183 bool have_delimiter, 184 const char **args, 185 parse_option_completion_info *completion = nullptr) 186 { 187 if (*args == nullptr) 188 return {}; 189 else if (**args != '-') 190 { 191 if (have_delimiter) 192 error (_("Unrecognized option at: %s"), *args); 193 return {}; 194 } 195 else if (check_for_argument (args, "--")) 196 return {}; 197 198 /* Skip the initial '-'. */ 199 const char *arg = *args + 1; 200 201 const char *after = skip_to_space (arg); 202 size_t len = after - arg; 203 const option_def *match = nullptr; 204 void *match_ctx = nullptr; 205 206 for (const auto &grp : options_group) 207 { 208 for (const auto &o : grp.options) 209 { 210 if (strncmp (o.name, arg, len) == 0) 211 { 212 if (match != nullptr) 213 { 214 if (completion != nullptr && arg[len] == '\0') 215 { 216 complete_on_options (options_group, 217 completion->tracker, 218 arg, completion->word); 219 return {}; 220 } 221 222 error (_("Ambiguous option at: -%s"), arg); 223 } 224 225 match = &o; 226 match_ctx = grp.ctx; 227 228 if ((isspace (arg[len]) || arg[len] == '\0') 229 && strlen (o.name) == len) 230 break; /* Exact match. */ 231 } 232 } 233 } 234 235 if (match == nullptr) 236 { 237 if (have_delimiter || mode != PROCESS_OPTIONS_UNKNOWN_IS_OPERAND) 238 error (_("Unrecognized option at: %s"), *args); 239 240 return {}; 241 } 242 243 if (completion != nullptr && arg[len] == '\0') 244 { 245 complete_on_options (options_group, completion->tracker, 246 arg, completion->word); 247 return {}; 248 } 249 250 *args += 1 + len; 251 *args = skip_spaces (*args); 252 if (completion != nullptr) 253 completion->word = *args; 254 255 switch (match->type) 256 { 257 case var_boolean: 258 { 259 if (!match->have_argument) 260 { 261 option_value val; 262 val.boolean = true; 263 return option_def_and_value {*match, match_ctx, val}; 264 } 265 266 const char *val_str = *args; 267 int res; 268 269 if (**args == '\0' && completion != nullptr) 270 { 271 /* Complete on both "on/off" and more options. */ 272 273 if (mode == PROCESS_OPTIONS_REQUIRE_DELIMITER) 274 { 275 complete_on_enum (completion->tracker, 276 boolean_enums, val_str, val_str); 277 complete_on_all_options (completion->tracker, options_group); 278 } 279 return option_def_and_value {*match, match_ctx}; 280 } 281 else if (**args == '-') 282 { 283 /* Treat: 284 "cmd -boolean-option -another-opt..." 285 as: 286 "cmd -boolean-option on -another-opt..." 287 */ 288 res = 1; 289 } 290 else if (**args == '\0') 291 { 292 /* Treat: 293 (1) "cmd -boolean-option " 294 as: 295 (1) "cmd -boolean-option on" 296 */ 297 res = 1; 298 } 299 else 300 { 301 res = parse_cli_boolean_value (args); 302 if (res < 0) 303 { 304 const char *end = skip_to_space (*args); 305 if (completion != nullptr) 306 { 307 if (*end == '\0') 308 { 309 complete_on_enum (completion->tracker, 310 boolean_enums, val_str, val_str); 311 return option_def_and_value {*match, match_ctx}; 312 } 313 } 314 315 if (have_delimiter) 316 error (_("Value given for `-%s' is not a boolean: %.*s"), 317 match->name, (int) (end - val_str), val_str); 318 /* The user didn't separate options from operands 319 using "--", so treat this unrecognized value as the 320 start of the operands. This makes "frame apply all 321 -past-main CMD" work. */ 322 return option_def_and_value {*match, match_ctx}; 323 } 324 else if (completion != nullptr && **args == '\0') 325 { 326 /* While "cmd -boolean [TAB]" only offers "on" and 327 "off", the boolean option actually accepts "1", 328 "yes", etc. as boolean values. We complete on all 329 of those instead of BOOLEAN_ENUMS here to make 330 these work: 331 332 "p -object 1[TAB]" -> "p -object 1 " 333 "p -object ye[TAB]" -> "p -object yes " 334 335 Etc. Note that it's important that the space is 336 auto-appended. Otherwise, if we only completed on 337 on/off here, then it might look to the user like 338 "1" isn't valid, like: 339 "p -object 1[TAB]" -> "p -object 1" (i.e., nothing happens). 340 */ 341 static const char *const all_boolean_enums[] = { 342 "on", "off", 343 "yes", "no", 344 "enable", "disable", 345 "0", "1", 346 nullptr, 347 }; 348 complete_on_enum (completion->tracker, all_boolean_enums, 349 val_str, val_str); 350 return {}; 351 } 352 } 353 354 option_value val; 355 val.boolean = res; 356 return option_def_and_value {*match, match_ctx, val}; 357 } 358 case var_uinteger: 359 case var_zuinteger_unlimited: 360 { 361 if (completion != nullptr) 362 { 363 if (**args == '\0') 364 { 365 /* Convenience to let the user know what the option 366 can accept. Note there's no common prefix between 367 the strings on purpose, so that readline doesn't do 368 a partial match. */ 369 completion->tracker.add_completion 370 (make_unique_xstrdup ("NUMBER")); 371 completion->tracker.add_completion 372 (make_unique_xstrdup ("unlimited")); 373 return {}; 374 } 375 else if (startswith ("unlimited", *args)) 376 { 377 completion->tracker.add_completion 378 (make_unique_xstrdup ("unlimited")); 379 return {}; 380 } 381 } 382 383 if (match->type == var_zuinteger_unlimited) 384 { 385 option_value val; 386 val.integer = parse_cli_var_zuinteger_unlimited (args, false); 387 return option_def_and_value {*match, match_ctx, val}; 388 } 389 else 390 { 391 option_value val; 392 val.uinteger = parse_cli_var_uinteger (match->type, args, false); 393 return option_def_and_value {*match, match_ctx, val}; 394 } 395 } 396 case var_enum: 397 { 398 if (completion != nullptr) 399 { 400 const char *after_arg = skip_to_space (*args); 401 if (*after_arg == '\0') 402 { 403 complete_on_enum (completion->tracker, 404 match->enums, *args, *args); 405 if (completion->tracker.have_completions ()) 406 return {}; 407 408 /* If we don't have completions, let the 409 non-completion path throw on invalid enum value 410 below, so that completion processing stops. */ 411 } 412 } 413 414 if (check_for_argument (args, "--")) 415 { 416 /* Treat e.g., "backtrace -entry-values --" as if there 417 was no argument after "-entry-values". This makes 418 parse_cli_var_enum throw an error with a suggestion of 419 what are the valid options. */ 420 args = nullptr; 421 } 422 423 option_value val; 424 val.enumeration = parse_cli_var_enum (args, match->enums); 425 return option_def_and_value {*match, match_ctx, val}; 426 } 427 case var_string: 428 { 429 if (check_for_argument (args, "--")) 430 { 431 /* Treat e.g., "maint test-options -string --" as if there 432 was no argument after "-string". */ 433 error (_("-%s requires an argument"), match->name); 434 } 435 436 const char *arg_start = *args; 437 std::string str = extract_string_maybe_quoted (args); 438 if (*args == arg_start) 439 error (_("-%s requires an argument"), match->name); 440 441 option_value val; 442 val.string = xstrdup (str.c_str ()); 443 return option_def_and_value {*match, match_ctx, val}; 444 } 445 446 default: 447 /* Not yet. */ 448 gdb_assert_not_reached (_("option type not supported")); 449 } 450 451 return {}; 452 } 453 454 /* See cli-option.h. */ 455 456 bool 457 complete_options (completion_tracker &tracker, 458 const char **args, 459 process_options_mode mode, 460 gdb::array_view<const option_def_group> options_group) 461 { 462 const char *text = *args; 463 464 tracker.set_use_custom_word_point (true); 465 466 const char *delimiter = find_end_options_delimiter (text); 467 bool have_delimiter = delimiter != nullptr; 468 469 if (text[0] == '-' && (!have_delimiter || *delimiter == '\0')) 470 { 471 parse_option_completion_info completion_info {nullptr, tracker}; 472 473 while (1) 474 { 475 *args = skip_spaces (*args); 476 completion_info.word = *args; 477 478 if (strcmp (*args, "-") == 0) 479 { 480 complete_on_options (options_group, tracker, *args + 1, 481 completion_info.word); 482 } 483 else if (strcmp (*args, "--") == 0) 484 { 485 tracker.add_completion (make_unique_xstrdup (*args)); 486 } 487 else if (**args == '-') 488 { 489 gdb::optional<option_def_and_value> ov 490 = parse_option (options_group, mode, have_delimiter, 491 args, &completion_info); 492 if (!ov && !tracker.have_completions ()) 493 { 494 tracker.advance_custom_word_point_by (*args - text); 495 return mode == PROCESS_OPTIONS_REQUIRE_DELIMITER; 496 } 497 498 if (ov 499 && ov->option.type == var_boolean 500 && !ov->value.has_value ()) 501 { 502 /* Looked like a boolean option, but we failed to 503 parse the value. If this command requires a 504 delimiter, this value can't be the start of the 505 operands, so return true. Otherwise, if the 506 command doesn't require a delimiter return false 507 so that the caller tries to complete on the 508 operand. */ 509 tracker.advance_custom_word_point_by (*args - text); 510 return mode == PROCESS_OPTIONS_REQUIRE_DELIMITER; 511 } 512 513 /* If we parsed an option with an argument, and reached 514 the end of the input string with no trailing space, 515 return true, so that our callers don't try to 516 complete anything by themselves. E.g., this makes it 517 so that with: 518 519 (gdb) frame apply all -limit 10[TAB] 520 521 we don't try to complete on command names. */ 522 if (ov 523 && !tracker.have_completions () 524 && **args == '\0' 525 && *args > text && !isspace ((*args)[-1])) 526 { 527 tracker.advance_custom_word_point_by 528 (*args - text); 529 return true; 530 } 531 532 /* If the caller passed in a context, then it is 533 interested in the option argument values. */ 534 if (ov && ov->ctx != nullptr) 535 save_option_value_in_ctx (ov); 536 } 537 else 538 { 539 tracker.advance_custom_word_point_by 540 (completion_info.word - text); 541 542 /* If the command requires a delimiter, but we haven't 543 seen one, then return true, so that the caller 544 doesn't try to complete on whatever follows options, 545 which for these commands should only be done if 546 there's a delimiter. */ 547 if (mode == PROCESS_OPTIONS_REQUIRE_DELIMITER 548 && !have_delimiter) 549 { 550 /* If we reached the end of the input string, then 551 offer all options, since that's all the user can 552 type (plus "--"). */ 553 if (completion_info.word[0] == '\0') 554 complete_on_all_options (tracker, options_group); 555 return true; 556 } 557 else 558 return false; 559 } 560 561 if (tracker.have_completions ()) 562 { 563 tracker.advance_custom_word_point_by 564 (completion_info.word - text); 565 return true; 566 } 567 } 568 } 569 else if (delimiter != nullptr) 570 { 571 tracker.advance_custom_word_point_by (delimiter - text); 572 *args = delimiter; 573 return false; 574 } 575 576 return false; 577 } 578 579 /* Save the parsed value in the option's context. */ 580 581 static void 582 save_option_value_in_ctx (gdb::optional<option_def_and_value> &ov) 583 { 584 switch (ov->option.type) 585 { 586 case var_boolean: 587 { 588 bool value = ov->value.has_value () ? ov->value->boolean : true; 589 *ov->option.var_address.boolean (ov->option, ov->ctx) = value; 590 } 591 break; 592 case var_uinteger: 593 *ov->option.var_address.uinteger (ov->option, ov->ctx) 594 = ov->value->uinteger; 595 break; 596 case var_zuinteger_unlimited: 597 *ov->option.var_address.integer (ov->option, ov->ctx) 598 = ov->value->integer; 599 break; 600 case var_enum: 601 *ov->option.var_address.enumeration (ov->option, ov->ctx) 602 = ov->value->enumeration; 603 break; 604 case var_string: 605 *ov->option.var_address.string (ov->option, ov->ctx) 606 = ov->value->string; 607 ov->value->string = nullptr; 608 break; 609 default: 610 gdb_assert_not_reached ("unhandled option type"); 611 } 612 } 613 614 /* See cli-option.h. */ 615 616 bool 617 process_options (const char **args, 618 process_options_mode mode, 619 gdb::array_view<const option_def_group> options_group) 620 { 621 if (*args == nullptr) 622 return false; 623 624 /* If ARGS starts with "-", look for a "--" sequence. If one is 625 found, then interpret everything up until the "--" as 626 'gdb::option'-style command line options. Otherwise, interpret 627 ARGS as possibly the command's operands. */ 628 bool have_delimiter = find_end_options_delimiter (*args) != nullptr; 629 630 if (mode == PROCESS_OPTIONS_REQUIRE_DELIMITER && !have_delimiter) 631 return false; 632 633 bool processed_any = false; 634 635 while (1) 636 { 637 *args = skip_spaces (*args); 638 639 auto ov = parse_option (options_group, mode, have_delimiter, args); 640 if (!ov) 641 { 642 if (processed_any) 643 return true; 644 return false; 645 } 646 647 processed_any = true; 648 649 save_option_value_in_ctx (ov); 650 } 651 } 652 653 /* Helper for build_help. Return a fragment of a help string showing 654 OPT's possible values. Returns NULL if OPT doesn't take an 655 argument. */ 656 657 static const char * 658 get_val_type_str (const option_def &opt, std::string &buffer) 659 { 660 if (!opt.have_argument) 661 return nullptr; 662 663 switch (opt.type) 664 { 665 case var_boolean: 666 return "[on|off]"; 667 case var_uinteger: 668 case var_zuinteger_unlimited: 669 return "NUMBER|unlimited"; 670 case var_enum: 671 { 672 buffer = ""; 673 for (size_t i = 0; opt.enums[i] != nullptr; i++) 674 { 675 if (i != 0) 676 buffer += "|"; 677 buffer += opt.enums[i]; 678 } 679 return buffer.c_str (); 680 } 681 case var_string: 682 return "STRING"; 683 default: 684 return nullptr; 685 } 686 } 687 688 /* Helper for build_help. Appends an indented version of DOC into 689 HELP. */ 690 691 static void 692 append_indented_doc (const char *doc, std::string &help) 693 { 694 const char *p = doc; 695 const char *n = strchr (p, '\n'); 696 697 while (n != nullptr) 698 { 699 help += " "; 700 help.append (p, n - p + 1); 701 p = n + 1; 702 n = strchr (p, '\n'); 703 } 704 help += " "; 705 help += p; 706 } 707 708 /* Fill HELP with an auto-generated "help" string fragment for 709 OPTIONS. */ 710 711 static void 712 build_help_option (gdb::array_view<const option_def> options, 713 std::string &help) 714 { 715 std::string buffer; 716 717 for (const auto &o : options) 718 { 719 if (o.set_doc == nullptr) 720 continue; 721 722 help += " -"; 723 help += o.name; 724 725 const char *val_type_str = get_val_type_str (o, buffer); 726 if (val_type_str != nullptr) 727 { 728 help += ' '; 729 help += val_type_str; 730 } 731 help += "\n"; 732 append_indented_doc (o.set_doc, help); 733 if (o.help_doc != nullptr) 734 { 735 help += "\n"; 736 append_indented_doc (o.help_doc, help); 737 } 738 } 739 } 740 741 /* See cli-option.h. */ 742 743 std::string 744 build_help (const char *help_tmpl, 745 gdb::array_view<const option_def_group> options_group) 746 { 747 bool need_newlines = false; 748 std::string help_str; 749 750 const char *p = strstr (help_tmpl, "%OPTIONS%"); 751 help_str.assign (help_tmpl, p); 752 753 for (const auto &grp : options_group) 754 for (const auto &opt : grp.options) 755 { 756 if (need_newlines) 757 help_str += "\n\n"; 758 else 759 need_newlines = true; 760 build_help_option (opt, help_str); 761 } 762 763 p += strlen ("%OPTIONS%"); 764 help_str.append (p); 765 766 return help_str; 767 } 768 769 /* See cli-option.h. */ 770 771 void 772 add_setshow_cmds_for_options (command_class cmd_class, 773 void *data, 774 gdb::array_view<const option_def> options, 775 struct cmd_list_element **set_list, 776 struct cmd_list_element **show_list) 777 { 778 for (const auto &option : options) 779 { 780 if (option.type == var_boolean) 781 { 782 add_setshow_boolean_cmd (option.name, cmd_class, 783 option.var_address.boolean (option, data), 784 option.set_doc, option.show_doc, 785 option.help_doc, 786 nullptr, option.show_cmd_cb, 787 set_list, show_list); 788 } 789 else if (option.type == var_uinteger) 790 { 791 add_setshow_uinteger_cmd (option.name, cmd_class, 792 option.var_address.uinteger (option, data), 793 option.set_doc, option.show_doc, 794 option.help_doc, 795 nullptr, option.show_cmd_cb, 796 set_list, show_list); 797 } 798 else if (option.type == var_zuinteger_unlimited) 799 { 800 add_setshow_zuinteger_unlimited_cmd 801 (option.name, cmd_class, 802 option.var_address.integer (option, data), 803 option.set_doc, option.show_doc, 804 option.help_doc, 805 nullptr, option.show_cmd_cb, 806 set_list, show_list); 807 } 808 else if (option.type == var_enum) 809 { 810 add_setshow_enum_cmd (option.name, cmd_class, 811 option.enums, 812 option.var_address.enumeration (option, data), 813 option.set_doc, option.show_doc, 814 option.help_doc, 815 nullptr, option.show_cmd_cb, 816 set_list, show_list); 817 } 818 else if (option.type == var_string) 819 { 820 add_setshow_string_cmd (option.name, cmd_class, 821 option.var_address.string (option, data), 822 option.set_doc, option.show_doc, 823 option.help_doc, 824 nullptr, option.show_cmd_cb, 825 set_list, show_list); 826 } 827 else 828 gdb_assert_not_reached (_("option type not handled")); 829 } 830 } 831 832 } /* namespace option */ 833 } /* namespace gdb */ 834