From 00eae5ea315dce8f34ece5e1e96d43d09fb1400e Mon Sep 17 00:00:00 2001 From: Jonas Devlieghere Date: Tue, 27 Nov 2018 21:00:32 +0000 Subject: [PATCH] [Driver] Use libOption with tablegen. This patch modifies the lldb driver to use libOption for option parsing. It allows us to decouple option parsing from option processing which is important when arguments affect initialization. This was previously not possible because the debugger need to be initialized as some option interpretation (like the scripting language etc) was handled by the debugger, rather than in the driver. Differential revision: https://reviews.llvm.org/D54692 llvm-svn: 347709 --- lldb/lit/Driver/Inputs/Print0.in | 1 + lldb/lit/Driver/Inputs/Print2.in | 1 + lldb/lit/Driver/Inputs/Print4.in | 1 + lldb/lit/Driver/Inputs/Print6.in | 1 + lldb/lit/Driver/TestCommands.test | 41 ++ lldb/lit/Driver/TestNoUseColor.test | 4 + lldb/lldb.xcodeproj/project.pbxproj | 29 +- lldb/tools/driver/CMakeLists.txt | 11 +- lldb/tools/driver/Driver.cpp | 979 +++++++++++++----------------------- lldb/tools/driver/Driver.h | 23 +- lldb/tools/driver/Options.td | 218 ++++++++ 11 files changed, 661 insertions(+), 648 deletions(-) create mode 100644 lldb/lit/Driver/Inputs/Print0.in create mode 100644 lldb/lit/Driver/Inputs/Print2.in create mode 100644 lldb/lit/Driver/Inputs/Print4.in create mode 100644 lldb/lit/Driver/Inputs/Print6.in create mode 100644 lldb/lit/Driver/TestCommands.test create mode 100644 lldb/lit/Driver/TestNoUseColor.test create mode 100644 lldb/tools/driver/Options.td diff --git a/lldb/lit/Driver/Inputs/Print0.in b/lldb/lit/Driver/Inputs/Print0.in new file mode 100644 index 0000000..cb545cc1 --- /dev/null +++ b/lldb/lit/Driver/Inputs/Print0.in @@ -0,0 +1 @@ +expr 0 diff --git a/lldb/lit/Driver/Inputs/Print2.in b/lldb/lit/Driver/Inputs/Print2.in new file mode 100644 index 0000000..f51389a --- /dev/null +++ b/lldb/lit/Driver/Inputs/Print2.in @@ -0,0 +1 @@ +expr 2 diff --git a/lldb/lit/Driver/Inputs/Print4.in b/lldb/lit/Driver/Inputs/Print4.in new file mode 100644 index 0000000..a2d49f3 --- /dev/null +++ b/lldb/lit/Driver/Inputs/Print4.in @@ -0,0 +1 @@ +expr 4 diff --git a/lldb/lit/Driver/Inputs/Print6.in b/lldb/lit/Driver/Inputs/Print6.in new file mode 100644 index 0000000..dee6212 --- /dev/null +++ b/lldb/lit/Driver/Inputs/Print6.in @@ -0,0 +1 @@ +expr 6 diff --git a/lldb/lit/Driver/TestCommands.test b/lldb/lit/Driver/TestCommands.test new file mode 100644 index 0000000..3589abb --- /dev/null +++ b/lldb/lit/Driver/TestCommands.test @@ -0,0 +1,41 @@ +# RUN: %lldb -x -b \ +# RUN: -S %S/Inputs/Print0.in \ +# RUN: -O 'expr 1' \ +# RUN: -S %S/Inputs/Print2.in \ +# RUN: -O 'expr 3' \ +# RUN: -s %S/Inputs/Print4.in \ +# RUN: -o 'expr 5' \ +# RUN: -s %S/Inputs/Print6.in \ +# RUN: -o 'expr 7' \ +# RUN: | FileCheck %s +# +# RUN: %lldb -x -b \ +# RUN: -s %S/Inputs/Print4.in \ +# RUN: -o 'expr 5' \ +# RUN: -s %S/Inputs/Print6.in \ +# RUN: -o 'expr 7' \ +# RUN: -S %S/Inputs/Print0.in \ +# RUN: -O 'expr 1' \ +# RUN: -S %S/Inputs/Print2.in \ +# RUN: -O 'expr 3' \ +# RUN: | FileCheck %s +# +# RUN: %lldb -x -b \ +# RUN: -s %S/Inputs/Print4.in \ +# RUN: -S %S/Inputs/Print0.in \ +# RUN: -o 'expr 5' \ +# RUN: -O 'expr 1' \ +# RUN: -s %S/Inputs/Print6.in \ +# RUN: -S %S/Inputs/Print2.in \ +# RUN: -o 'expr 7' \ +# RUN: -O 'expr 3' \ +# RUN: | FileCheck %s + +# CHECK: (int) $0 = 0 +# CHECK: (int) $1 = 1 +# CHECK: (int) $2 = 2 +# CHECK: (int) $3 = 3 +# CHECK: (int) $4 = 4 +# CHECK: (int) $5 = 5 +# CHECK: (int) $6 = 6 +# CHECK: (int) $7 = 7 diff --git a/lldb/lit/Driver/TestNoUseColor.test b/lldb/lit/Driver/TestNoUseColor.test new file mode 100644 index 0000000..6273530 --- /dev/null +++ b/lldb/lit/Driver/TestNoUseColor.test @@ -0,0 +1,4 @@ +# RUN: %lldb --no-use-color -s %s | FileCheck %s +settings show use-color +# CHECK: use-color (boolean) = false +q diff --git a/lldb/lldb.xcodeproj/project.pbxproj b/lldb/lldb.xcodeproj/project.pbxproj index c2a07301..a58bbec 100644 --- a/lldb/lldb.xcodeproj/project.pbxproj +++ b/lldb/lldb.xcodeproj/project.pbxproj @@ -2373,6 +2373,8 @@ 260A248D15D06C4F009981B0 /* OptionValues.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OptionValues.h; path = include/lldb/Interpreter/OptionValues.h; sourceTree = ""; }; 26BC7E8610F1B85900F91463 /* Options.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Options.cpp; path = source/Interpreter/Options.cpp; sourceTree = ""; }; 26BC7D6D10F1B77400F91463 /* Options.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Options.h; path = include/lldb/Interpreter/Options.h; sourceTree = ""; }; + DD5F951A21ADE5BD00B8265A /* Options.inc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.pascal; name = Options.inc; path = build/Debug/include/Options.inc; sourceTree = ""; }; + DD5F951B21ADE5F000B8265A /* Options.td */ = {isa = PBXFileReference; lastKnownFileType = text; name = Options.td; path = tools/driver/Options.td; sourceTree = ""; }; 4C562CC21CC07DDD00C52EAC /* PDBASTParser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PDBASTParser.cpp; path = PDB/PDBASTParser.cpp; sourceTree = ""; }; 4C562CC31CC07DDD00C52EAC /* PDBASTParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PDBASTParser.h; path = PDB/PDBASTParser.h; sourceTree = ""; }; 4CA0C6CA20F929C600CFE6BB /* PDBLocationToDWARFExpression.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PDBLocationToDWARFExpression.cpp; path = PDB/PDBLocationToDWARFExpression.cpp; sourceTree = ""; }; @@ -5916,6 +5918,8 @@ 26F5C22510F3D956009D5894 /* Driver */ = { isa = PBXGroup; children = ( + DD5F951B21ADE5F000B8265A /* Options.td */, + DD5F951A21ADE5BD00B8265A /* Options.inc */, 26F5C27210F3D9E4009D5894 /* lldb-Info.plist */, 26F5C27410F3D9E4009D5894 /* Driver.h */, 26F5C27310F3D9E4009D5894 /* Driver.cpp */, @@ -7173,6 +7177,7 @@ isa = PBXNativeTarget; buildConfigurationList = 26F5C26E10F3D9C5009D5894 /* Build configuration list for PBXNativeTarget "lldb-tool" */; buildPhases = ( + DD5F951721ADD0C900B8265A /* Run Tablegen */, 26F5C26710F3D9A4009D5894 /* Sources */, 26F5C26810F3D9A4009D5894 /* Frameworks */, ); @@ -7514,9 +7519,29 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = "/bin/sh -x"; - shellScript = "/bin/rm -rf \"$INSTALL_ROOT/System/Library/PrivateFrameworks/LLDB.framework/Resources\" \"$INSTALL_ROOT/System/Library/PrivateFrameworks/LLDB.framework/Swift\""; + shellScript = "/bin/rm -rf \"$INSTALL_ROOT/System/Library/PrivateFrameworks/LLDB.framework/Resources\" \"$INSTALL_ROOT/System/Library/PrivateFrameworks/LLDB.framework/Swift\"\n"; showEnvVarsInLog = 0; }; + DD5F951721ADD0C900B8265A /* Run Tablegen */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + $SOURCE_DIR/tools/driver/Options.td, + ); + name = "Run Tablegen"; + outputFileListPaths = ( + ); + outputPaths = ( + $BUILT_PRODUCTS_DIR/Options.inc, + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "mkdir -p $BUILT_PRODUCTS_DIR/include\n$LLVM_BUILD_DIR/x86_64/bin/llvm-tblgen -I$LLVM_SOURCE_DIR/include -gen-opt-parser-defs $SRCROOT/tools/driver/Options.td -o $BUILT_PRODUCTS_DIR/include/Options.inc\n"; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -10531,7 +10556,7 @@ "$(LLVM_BUILD_DIR)/archives.txt", ); PRODUCT_NAME = lldb; - USER_HEADER_SEARCH_PATHS = "$(SRCROOT)/include $(SRCROOT)/source $(LLVM_SOURCE_DIR)/include $(LLVM_BUILD_DIR)/$(LLVM_BUILD_DIR_ARCH)/include"; + USER_HEADER_SEARCH_PATHS = "$(SRCROOT)/include $(SRCROOT)/source $(LLVM_SOURCE_DIR)/include $(LLVM_BUILD_DIR)/$(LLVM_BUILD_DIR_ARCH)/include ${LLDB_BUILD_DIR}/include"; VERSIONING_SYSTEM = "apple-generic"; }; name = Release; diff --git a/lldb/tools/driver/CMakeLists.txt b/lldb/tools/driver/CMakeLists.txt index 9e01a6b..6127fad 100644 --- a/lldb/tools/driver/CMakeLists.txt +++ b/lldb/tools/driver/CMakeLists.txt @@ -1,3 +1,7 @@ +set(LLVM_TARGET_DEFINITIONS Options.td) +tablegen(LLVM Options.inc -gen-opt-parser-defs) +add_public_tablegen_target(LLDBOptionsTableGen) + if ((CMAKE_SYSTEM_NAME MATCHES "Windows") OR (CMAKE_SYSTEM_NAME MATCHES "NetBSD" )) # These targets do not have getopt support, so they rely on the one provided by @@ -17,6 +21,7 @@ add_lldb_tool(lldb ${host_lib} LINK_COMPONENTS + Option Support ) @@ -24,4 +29,8 @@ if ( CMAKE_SYSTEM_NAME MATCHES "Windows" ) add_definitions( -DIMPORT_LIBLLDB ) endif() -add_dependencies(lldb ${LLDB_SUITE_TARGET}) +add_dependencies(lldb + ${LLDB_SUITE_TARGET} + LLDBOptionsTableGen + ${tablegen_deps} +) diff --git a/lldb/tools/driver/Driver.cpp b/lldb/tools/driver/Driver.cpp index 5b129e7..31425c1 100644 --- a/lldb/tools/driver/Driver.cpp +++ b/lldb/tools/driver/Driver.cpp @@ -9,26 +9,6 @@ #include "Driver.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// Includes for pipe() -#if defined(_WIN32) -#include -#include -#else -#include -#endif - -#include - #include "lldb/API/SBBreakpoint.h" #include "lldb/API/SBCommandInterpreter.h" #include "lldb/API/SBCommandReturnObject.h" @@ -43,18 +23,74 @@ #include "lldb/API/SBStringList.h" #include "lldb/API/SBTarget.h" #include "lldb/API/SBThread.h" + #include "llvm/ADT/StringRef.h" #include "llvm/Support/ConvertUTF.h" +#include "llvm/Support/Path.h" #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Signals.h" +#include "llvm/Support/raw_ostream.h" + +#include +#include +#include +#include +#include #include #include +#include +#include +#include +#include +#include + +// Includes for pipe() +#if defined(_WIN32) +#include +#include +#else +#include +#endif + #if !defined(__APPLE__) #include "llvm/Support/DataTypes.h" #endif using namespace lldb; +using namespace llvm; + +namespace { +enum ID { + OPT_INVALID = 0, // This is not an option ID. +#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ + HELPTEXT, METAVAR, VALUES) \ + OPT_##ID, +#include "Options.inc" +#undef OPTION +}; + +#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE; +#include "Options.inc" +#undef PREFIX + +static const opt::OptTable::Info InfoTable[] = { +#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ + HELPTEXT, METAVAR, VALUES) \ + { \ + PREFIX, NAME, HELPTEXT, \ + METAVAR, OPT_##ID, opt::Option::KIND##Class, \ + PARAM, FLAGS, OPT_##GROUP, \ + OPT_##ALIAS, ALIASARGS, VALUES}, +#include "Options.inc" +#undef OPTION +}; + +class LLDBOptTable : public opt::OptTable { +public: + LLDBOptTable() : OptTable(InfoTable) {} +}; +} // namespace static void reset_stdin_termios(); static bool g_old_stdin_termios_is_valid = false; @@ -71,110 +107,6 @@ static void reset_stdin_termios() { } } -typedef struct { - uint32_t usage_mask; // Used to mark options that can be used together. If (1 - // << n & usage_mask) != 0 - // then this option belongs to option set n. - bool required; // This option is required (in the current usage level) - const char *long_option; // Full name for this option. - int short_option; // Single character for this option. - int option_has_arg; // no_argument, required_argument or optional_argument - uint32_t completion_type; // Cookie the option class can use to do define the - // argument completion. - lldb::CommandArgumentType argument_type; // Type of argument this option takes - const char *usage_text; // Full text explaining what this options does and - // what (if any) argument to - // pass it. -} OptionDefinition; - -#define LLDB_3_TO_5 LLDB_OPT_SET_3 | LLDB_OPT_SET_4 | LLDB_OPT_SET_5 -#define LLDB_4_TO_5 LLDB_OPT_SET_4 | LLDB_OPT_SET_5 - -static constexpr OptionDefinition g_options[] = { - {LLDB_OPT_SET_1, true, "help", 'h', no_argument, 0, eArgTypeNone, - "Prints out the usage information for the LLDB debugger."}, - {LLDB_OPT_SET_2, true, "version", 'v', no_argument, 0, eArgTypeNone, - "Prints out the current version number of the LLDB debugger."}, - {LLDB_OPT_SET_3, true, "arch", 'a', required_argument, 0, - eArgTypeArchitecture, - "Tells the debugger to use the specified architecture when starting and " - "running the program. must " - "be one of the architectures for which the program was compiled."}, - {LLDB_OPT_SET_3, true, "file", 'f', required_argument, 0, eArgTypeFilename, - "Tells the debugger to use the file as the program to be " - "debugged."}, - {LLDB_OPT_SET_3, false, "core", 'c', required_argument, 0, eArgTypeFilename, - "Tells the debugger to use the fullpath to as the core file."}, - {LLDB_OPT_SET_5, true, "attach-pid", 'p', required_argument, 0, eArgTypePid, - "Tells the debugger to attach to a process with the given pid."}, - {LLDB_OPT_SET_4, true, "attach-name", 'n', required_argument, 0, - eArgTypeProcessName, - "Tells the debugger to attach to a process with the given name."}, - {LLDB_OPT_SET_4, true, "wait-for", 'w', no_argument, 0, eArgTypeNone, - "Tells the debugger to wait for a process with the given pid or name to " - "launch before attaching."}, - {LLDB_3_TO_5, false, "source", 's', required_argument, 0, eArgTypeFilename, - "Tells the debugger to read in and execute the lldb commands in the given " - "file, after any file provided on the command line has been loaded."}, - {LLDB_3_TO_5, false, "one-line", 'o', required_argument, 0, eArgTypeNone, - "Tells the debugger to execute this one-line lldb command after any file " - "provided on the command line has been loaded."}, - {LLDB_3_TO_5, false, "source-before-file", 'S', required_argument, 0, - eArgTypeFilename, - "Tells the debugger to read in and execute the lldb " - "commands in the given file, before any file provided " - "on the command line has been loaded."}, - {LLDB_3_TO_5, false, "one-line-before-file", 'O', required_argument, 0, - eArgTypeNone, - "Tells the debugger to execute this one-line lldb command " - "before any file provided on the command line has been " - "loaded."}, - {LLDB_3_TO_5, false, "one-line-on-crash", 'k', required_argument, 0, - eArgTypeNone, - "When in batch mode, tells the debugger to execute this " - "one-line lldb command if the target crashes."}, - {LLDB_3_TO_5, false, "source-on-crash", 'K', required_argument, 0, - eArgTypeFilename, - "When in batch mode, tells the debugger to source this " - "file of lldb commands if the target crashes."}, - {LLDB_3_TO_5, false, "source-quietly", 'Q', no_argument, 0, eArgTypeNone, - "Tells the debugger to execute this one-line lldb command before any file " - "provided on the command line has been loaded."}, - {LLDB_3_TO_5, false, "batch", 'b', no_argument, 0, eArgTypeNone, - "Tells the debugger to run the commands from -s, -S, -o & -O, and " - "then quit. However if any run command stopped due to a signal or crash, " - "the debugger will return to the interactive prompt at the place of the " - "crash."}, - {LLDB_3_TO_5, false, "editor", 'e', no_argument, 0, eArgTypeNone, - "Tells the debugger to open source files using the host's \"external " - "editor\" mechanism."}, - {LLDB_3_TO_5, false, "no-lldbinit", 'x', no_argument, 0, eArgTypeNone, - "Do not automatically parse any '.lldbinit' files."}, - {LLDB_3_TO_5, false, "no-use-colors", 'X', no_argument, 0, eArgTypeNone, - "Do not use colors."}, - {LLDB_OPT_SET_6, true, "python-path", 'P', no_argument, 0, eArgTypeNone, - "Prints out the path to the lldb.py file for this version of lldb."}, - {LLDB_3_TO_5, false, "script-language", 'l', required_argument, 0, - eArgTypeScriptLang, - "Tells the debugger to use the specified scripting language for " - "user-defined scripts, rather than the default. " - "Valid scripting languages that can be specified include Python, Perl, " - "Ruby and Tcl. Currently only the Python " - "extensions have been implemented."}, - {LLDB_3_TO_5, false, "debug", 'd', no_argument, 0, eArgTypeNone, - "Tells the debugger to print out extra information for debugging itself."}, - {LLDB_3_TO_5, false, "reproducer", 'z', required_argument, 0, - eArgTypeFilename, - "Tells the debugger to use the fullpath to as a reproducer."}, - {LLDB_OPT_SET_7, true, "repl", 'r', optional_argument, 0, eArgTypeNone, - "Runs lldb in REPL mode with a stub process."}, - {LLDB_OPT_SET_7, true, "repl-language", 'R', required_argument, 0, - eArgTypeNone, "Chooses the language for the REPL."}}; - -static constexpr auto g_num_options = sizeof(g_options)/sizeof(OptionDefinition); - -static const uint32_t last_option_set_with_args = 2; - Driver::Driver() : SBBroadcaster("Driver"), m_debugger(SBDebugger::Create(false)), m_option_data() { @@ -186,241 +118,14 @@ Driver::Driver() Driver::~Driver() { g_driver = NULL; } -// This function takes INDENT, which tells how many spaces to output at the -// front -// of each line; TEXT, which is the text that is to be output. It outputs the -// text, on multiple lines if necessary, to RESULT, with INDENT spaces at the -// front of each line. It breaks lines on spaces, tabs or newlines, shortening -// the line if necessary to not break in the middle of a word. It assumes that -// each output line should contain a maximum of OUTPUT_MAX_COLUMNS characters. - -void OutputFormattedUsageText(FILE *out, int indent, const char *text, - int output_max_columns) { - int len = strlen(text); - std::string text_string(text); - - // Force indentation to be reasonable. - if (indent >= output_max_columns) - indent = 0; - - // Will it all fit on one line? - - if (len + indent < output_max_columns) - // Output as a single line - fprintf(out, "%*s%s\n", indent, "", text); - else { - // We need to break it up into multiple lines. - int text_width = output_max_columns - indent - 1; - int start = 0; - int end = start; - int final_end = len; - int sub_len; - - while (end < final_end) { - // Dont start the 'text' on a space, since we're already outputting the - // indentation. - while ((start < final_end) && (text[start] == ' ')) - start++; - - end = start + text_width; - if (end > final_end) - end = final_end; - else { - // If we're not at the end of the text, make sure we break the line on - // white space. - while (end > start && text[end] != ' ' && text[end] != '\t' && - text[end] != '\n') - end--; - } - sub_len = end - start; - std::string substring = text_string.substr(start, sub_len); - fprintf(out, "%*s%s\n", indent, "", substring.c_str()); - start = end + 1; - } - } -} - -static void ShowUsage(FILE *out, Driver::OptionData data) { - uint32_t screen_width = 80; - uint32_t indent_level = 0; - const char *name = "lldb"; - - fprintf(out, "\nUsage:\n\n"); - - indent_level += 2; - - // First, show each usage level set of options, e.g. - // [options-for-level-0] - // - // [options-for-level-1] - // etc. - - uint32_t num_option_sets = 0; - - for (const auto &opt : g_options) { - uint32_t this_usage_mask = opt.usage_mask; - if (this_usage_mask == LLDB_OPT_SET_ALL) { - if (num_option_sets == 0) - num_option_sets = 1; - } else { - for (uint32_t j = 0; j < LLDB_MAX_NUM_OPTION_SETS; j++) { - if (this_usage_mask & 1 << j) { - if (num_option_sets <= j) - num_option_sets = j + 1; - } - } - } - } - - for (uint32_t opt_set = 0; opt_set < num_option_sets; opt_set++) { - uint32_t opt_set_mask; - - opt_set_mask = 1 << opt_set; - - if (opt_set > 0) - fprintf(out, "\n"); - fprintf(out, "%*s%s", indent_level, "", name); - bool is_help_line = false; - - for (const auto &opt : g_options) { - if (opt.usage_mask & opt_set_mask) { - CommandArgumentType arg_type = opt.argument_type; - const char *arg_name = - SBCommandInterpreter::GetArgumentTypeAsCString(arg_type); - // This is a bit of a hack, but there's no way to say certain options - // don't have arguments yet... - // so we do it by hand here. - if (opt.short_option == 'h') - is_help_line = true; - - if (opt.required) { - if (opt.option_has_arg == required_argument) - fprintf(out, " -%c <%s>", opt.short_option, arg_name); - else if (opt.option_has_arg == optional_argument) - fprintf(out, " -%c [<%s>]", opt.short_option, arg_name); - else - fprintf(out, " -%c", opt.short_option); - } else { - if (opt.option_has_arg == required_argument) - fprintf(out, " [-%c <%s>]", opt.short_option, arg_name); - else if (opt.option_has_arg == optional_argument) - fprintf(out, " [-%c [<%s>]]", opt.short_option, - arg_name); - else - fprintf(out, " [-%c]", opt.short_option); - } - } - } - if (!is_help_line && (opt_set <= last_option_set_with_args)) - fprintf(out, " [[--] [ ...]]"); - } - - fprintf(out, "\n\n"); - - // Now print out all the detailed information about the various options: long - // form, short form and help text: - // -- long_name - // - short - // help text - - // This variable is used to keep track of which options' info we've printed - // out, because some options can be in - // more than one usage level, but we only want to print the long form of its - // information once. - - Driver::OptionData::OptionSet options_seen; - Driver::OptionData::OptionSet::iterator pos; - - indent_level += 5; - - for (const auto &opt : g_options) { - // Only print this option if we haven't already seen it. - pos = options_seen.find(opt.short_option); - if (pos == options_seen.end()) { - CommandArgumentType arg_type = opt.argument_type; - const char *arg_name = - SBCommandInterpreter::GetArgumentTypeAsCString(arg_type); - - options_seen.insert(opt.short_option); - fprintf(out, "%*s-%c ", indent_level, "", opt.short_option); - if (arg_type != eArgTypeNone) - fprintf(out, "<%s>", arg_name); - fprintf(out, "\n"); - fprintf(out, "%*s--%s ", indent_level, "", opt.long_option); - if (arg_type != eArgTypeNone) - fprintf(out, "<%s>", arg_name); - fprintf(out, "\n"); - indent_level += 5; - OutputFormattedUsageText(out, indent_level, opt.usage_text, - screen_width); - indent_level -= 5; - fprintf(out, "\n"); - } - } - - indent_level -= 5; - - fprintf(out, "\n%*sNotes:\n", indent_level, ""); - indent_level += 5; - - fprintf(out, - "\n%*sMultiple \"-s\" and \"-o\" options can be provided. They will " - "be processed" - "\n%*sfrom left to right in order, with the source files and commands" - "\n%*sinterleaved. The same is true of the \"-S\" and \"-O\" " - "options. The before" - "\n%*sfile and after file sets can intermixed freely, the command " - "parser will" - "\n%*ssort them out. The order of the file specifiers (\"-c\", " - "\"-f\", etc.) is" - "\n%*snot significant in this regard.\n\n", - indent_level, "", indent_level, "", indent_level, "", indent_level, - "", indent_level, "", indent_level, ""); - - fprintf( - out, - "\n%*sIf you don't provide -f then the first argument will be the file " - "to be" - "\n%*sdebugged which means that '%s -- [ []]' also" - "\n%*sworks. But remember to end the options with \"--\" if any of your" - "\n%*sarguments have a \"-\" in them.\n\n", - indent_level, "", indent_level, "", name, indent_level, "", indent_level, - ""); -} - - static void BuildGetOptTable(std::vector