Index: lldb/trunk/include/lldb/Host/OptionParser.h =================================================================== --- lldb/trunk/include/lldb/Host/OptionParser.h +++ lldb/trunk/include/lldb/Host/OptionParser.h @@ -16,18 +16,17 @@ namespace lldb_private { -typedef struct Option +struct OptionDefinition; + +struct Option { - // name of long option - const char *name; - // one of no_argument, required_argument, and optional_argument: - // whether option takes an argument - int has_arg; + // The definition of the option that this refers to. + const OptionDefinition *definition; // if not NULL, set *flag to val when option found int *flag; // if flag not NULL, value to set *flag to; else return value int val; -} Option; +}; class OptionParser { Index: lldb/trunk/include/lldb/Interpreter/CommandOptionValidators.h =================================================================== --- lldb/trunk/include/lldb/Interpreter/CommandOptionValidators.h +++ lldb/trunk/include/lldb/Interpreter/CommandOptionValidators.h @@ -0,0 +1,30 @@ +//===-- CommandOptionValidators.h -------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_CommandOptionValidators_h_ +#define liblldb_CommandOptionValidators_h_ + +#include "lldb/lldb-private-types.h" + +namespace lldb_private { + +class Platform; +class ExecutionContext; + +class PosixPlatformCommandOptionValidator : public OptionValidator +{ + virtual bool IsValid(Platform &platform, ExecutionContext &target) const; + virtual const char* ShortConditionString() const; + virtual const char* LongConditionString() const; +}; + +} // namespace lldb_private + + +#endif // liblldb_CommandOptionValidators_h_ Index: lldb/trunk/include/lldb/Interpreter/Options.h =================================================================== --- lldb/trunk/include/lldb/Interpreter/Options.h +++ lldb/trunk/include/lldb/Interpreter/Options.h @@ -159,7 +159,7 @@ void OutputFormattedUsageText (Stream &strm, - const char *text, + const OptionDefinition &option_def, uint32_t output_max_columns); void @@ -301,6 +301,12 @@ int max_return_elements, bool &word_complete, StringList &matches); + + CommandInterpreter& + GetInterpreter() + { + return m_interpreter; + } protected: // This is a set of options expressed as indexes into the options table for this Option. Index: lldb/trunk/include/lldb/lldb-private-types.h =================================================================== --- lldb/trunk/include/lldb/lldb-private-types.h +++ lldb/trunk/include/lldb/lldb-private-types.h @@ -16,6 +16,9 @@ namespace lldb_private { + class Platform; + class ExecutionContext; + //---------------------------------------------------------------------- // Every register is described in detail including its name, alternate // name (optional), encoding, size in bytes and the default display @@ -55,11 +58,12 @@ struct OptionValidator { virtual ~OptionValidator() { } - virtual bool IsValid() const = 0; - virtual const char * ValidConditionString() const = 0; + virtual bool IsValid(Platform &platform, ExecutionContext &target) const = 0; + virtual const char * ShortConditionString() const = 0; + virtual const char * LongConditionString() const = 0; }; - typedef struct + struct OptionDefinition { 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. @@ -73,7 +77,7 @@ 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; + }; } // namespace lldb_private Index: lldb/trunk/source/Commands/CommandObjectPlatform.cpp =================================================================== --- lldb/trunk/source/Commands/CommandObjectPlatform.cpp +++ lldb/trunk/source/Commands/CommandObjectPlatform.cpp @@ -21,6 +21,7 @@ #include "lldb/Core/PluginManager.h" #include "lldb/Interpreter/Args.h" #include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Interpreter/CommandOptionValidators.h" #include "lldb/Interpreter/CommandReturnObject.h" #include "lldb/Interpreter/OptionGroupFile.h" #include "lldb/Interpreter/OptionGroupPlatform.h" @@ -1644,6 +1645,11 @@ CommandOptions m_options; }; +namespace +{ + PosixPlatformCommandOptionValidator g_posix_validator; +} + OptionDefinition CommandObjectPlatformProcessList::CommandOptions::g_option_table[] = { @@ -1654,10 +1660,10 @@ { LLDB_OPT_SET_5 , true , "contains" , 'c', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeProcessName , "Find processes with executable basenames that contain a string." }, { LLDB_OPT_SET_6 , true , "regex" , 'r', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeRegularExpression, "Find processes with executable basenames that match a regular expression." }, { LLDB_OPT_SET_FROM_TO(2, 6), false, "parent" , 'P', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypePid , "Find processes that have a matching parent process ID." }, -{ LLDB_OPT_SET_FROM_TO(2, 6), false, "uid" , 'u', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeUnsignedInteger , "Find processes that have a matching user ID." }, -{ LLDB_OPT_SET_FROM_TO(2, 6), false, "euid" , 'U', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeUnsignedInteger , "Find processes that have a matching effective user ID." }, -{ LLDB_OPT_SET_FROM_TO(2, 6), false, "gid" , 'g', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeUnsignedInteger , "Find processes that have a matching group ID." }, -{ LLDB_OPT_SET_FROM_TO(2, 6), false, "egid" , 'G', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeUnsignedInteger , "Find processes that have a matching effective group ID." }, +{ LLDB_OPT_SET_FROM_TO(2, 6), false, "uid" , 'u', OptionParser::eRequiredArgument, &g_posix_validator, NULL, 0, eArgTypeUnsignedInteger , "Find processes that have a matching user ID." }, +{ LLDB_OPT_SET_FROM_TO(2, 6), false, "euid" , 'U', OptionParser::eRequiredArgument, &g_posix_validator, NULL, 0, eArgTypeUnsignedInteger , "Find processes that have a matching effective user ID." }, +{ LLDB_OPT_SET_FROM_TO(2, 6), false, "gid" , 'g', OptionParser::eRequiredArgument, &g_posix_validator, NULL, 0, eArgTypeUnsignedInteger , "Find processes that have a matching group ID." }, +{ LLDB_OPT_SET_FROM_TO(2, 6), false, "egid" , 'G', OptionParser::eRequiredArgument, &g_posix_validator, NULL, 0, eArgTypeUnsignedInteger , "Find processes that have a matching effective group ID." }, { LLDB_OPT_SET_FROM_TO(2, 6), false, "arch" , 'a', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeArchitecture , "Find processes that have a matching architecture." }, { LLDB_OPT_SET_FROM_TO(1, 6), false, "show-args" , 'A', OptionParser::eNoArgument , NULL, NULL, 0, eArgTypeNone , "Show process arguments instead of the process executable basename." }, { LLDB_OPT_SET_FROM_TO(1, 6), false, "verbose" , 'v', OptionParser::eNoArgument , NULL, NULL, 0, eArgTypeNone , "Enable verbose output." }, Index: lldb/trunk/source/Interpreter/Args.cpp =================================================================== --- lldb/trunk/source/Interpreter/Args.cpp +++ lldb/trunk/source/Interpreter/Args.cpp @@ -20,6 +20,7 @@ #include "lldb/Core/StreamString.h" #include "lldb/DataFormatters/FormatManager.h" #include "lldb/Interpreter/Options.h" +#include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Interpreter/CommandReturnObject.h" #include "lldb/Target/Process.h" //#include "lldb/Target/RegisterContext.h" @@ -627,14 +628,14 @@ return error; } - for (int i=0; long_options[i].name != nullptr; ++i) + for (int i=0; long_options[i].definition != nullptr; ++i) { if (long_options[i].flag == nullptr) { if (isprint8(long_options[i].val)) { sstr << (char)long_options[i].val; - switch (long_options[i].has_arg) + switch (long_options[i].definition->option_has_arg) { default: case OptionParser::eNoArgument: break; @@ -673,7 +674,7 @@ if (long_options_index == -1) { for (int i=0; - long_options[i].name || long_options[i].has_arg || long_options[i].flag || long_options[i].val; + long_options[i].definition || long_options[i].flag || long_options[i].val; ++i) { if (long_options[i].val == val) @@ -686,8 +687,18 @@ // Call the callback with the option if (long_options_index >= 0) { - error = options.SetOptionValue(long_options_index, - long_options[long_options_index].has_arg == OptionParser::eNoArgument ? nullptr : OptionParser::GetOptionArgument()); + const OptionDefinition *def = long_options[long_options_index].definition; + CommandInterpreter &interpreter = options.GetInterpreter(); + OptionValidator *validator = def->validator; + if (validator && !validator->IsValid(*interpreter.GetPlatform(true), interpreter.GetExecutionContext())) + { + error.SetErrorStringWithFormat("Option \"%s\" invalid. %s", def->long_option, def->validator->LongConditionString()); + } + else + { + error = options.SetOptionValue(long_options_index, + (def->option_has_arg == OptionParser::eNoArgument) ? nullptr : OptionParser::GetOptionArgument()); + } } else { @@ -1222,7 +1233,7 @@ char short_buffer[3]; char long_buffer[255]; ::snprintf (short_buffer, sizeof (short_buffer), "-%c", long_options[long_options_index].val); - ::snprintf (long_buffer, sizeof (long_buffer), "--%s", long_options[long_options_index].name); + ::snprintf (long_buffer, sizeof (long_buffer), "--%s", long_options[long_options_index].definition->long_option); size_t end = GetArgumentCount (); size_t idx = 0; while (idx < end) @@ -1278,12 +1289,12 @@ return; } - for (i = 0; long_options[i].name != nullptr; ++i) + for (i = 0; long_options[i].definition != nullptr; ++i) { if (long_options[i].flag == nullptr) { sstr << (char) long_options[i].val; - switch (long_options[i].has_arg) + switch (long_options[i].definition->option_has_arg) { default: case OptionParser::eNoArgument: @@ -1328,7 +1339,7 @@ if (long_options_index == -1) { for (int j = 0; - long_options[j].name || long_options[j].has_arg || long_options[j].flag || long_options[j].val; + long_options[j].definition || long_options[j].flag || long_options[j].val; ++j) { if (long_options[j].val == val) @@ -1344,8 +1355,10 @@ { StreamString option_str; option_str.Printf ("-%c", val); + const OptionDefinition *def = long_options[long_options_index].definition; + int has_arg = (def == nullptr) ? OptionParser::eNoArgument : def->option_has_arg; - switch (long_options[long_options_index].has_arg) + switch (has_arg) { case OptionParser::eNoArgument: option_arg_vector->push_back (OptionArgPair (std::string (option_str.GetData()), @@ -1410,7 +1423,7 @@ raw_input_string.erase (pos, strlen (tmp_arg)); } ReplaceArgumentAtIndex (idx, ""); - if ((long_options[long_options_index].has_arg != OptionParser::eNoArgument) + if ((long_options[long_options_index].definition->option_has_arg != OptionParser::eNoArgument) && (OptionParser::GetOptionArgument() != nullptr) && (idx+1 < GetArgumentCount()) && (strcmp (OptionParser::GetOptionArgument(), GetArgumentAtIndex(idx+1)) == 0)) @@ -1453,12 +1466,12 @@ // to suppress error messages. sstr << ":"; - for (int i = 0; long_options[i].name != nullptr; ++i) + for (int i = 0; long_options[i].definition != nullptr; ++i) { if (long_options[i].flag == nullptr) { sstr << (char) long_options[i].val; - switch (long_options[i].has_arg) + switch (long_options[i].definition->option_has_arg) { default: case OptionParser::eNoArgument: @@ -1555,7 +1568,7 @@ if (long_options_index == -1) { for (int j = 0; - long_options[j].name || long_options[j].has_arg || long_options[j].flag || long_options[j].val; + long_options[j].definition || long_options[j].flag || long_options[j].val; ++j) { if (long_options[j].val == val) @@ -1581,7 +1594,9 @@ } } - switch (long_options[long_options_index].has_arg) + const OptionDefinition *def = long_options[long_options_index].definition; + int has_arg = (def == nullptr) ? OptionParser::eNoArgument : def->option_has_arg; + switch (has_arg) { case OptionParser::eNoArgument: option_element_vector.push_back (OptionArgElement (opt_defs_index, OptionParser::GetOptionIndex() - 1, 0)); Index: lldb/trunk/source/Interpreter/CMakeLists.txt =================================================================== --- lldb/trunk/source/Interpreter/CMakeLists.txt +++ lldb/trunk/source/Interpreter/CMakeLists.txt @@ -7,6 +7,7 @@ CommandObject.cpp CommandObjectRegexCommand.cpp CommandObjectScript.cpp + CommandOptionValidators.cpp CommandReturnObject.cpp OptionGroupArchitecture.cpp OptionGroupBoolean.cpp Index: lldb/trunk/source/Interpreter/CommandOptionValidators.cpp =================================================================== --- lldb/trunk/source/Interpreter/CommandOptionValidators.cpp +++ lldb/trunk/source/Interpreter/CommandOptionValidators.cpp @@ -0,0 +1,39 @@ +//===-- CommandOptionValidators.cpp -----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/Interpreter/CommandOptionValidators.h" + +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Target/Platform.h" + +using namespace lldb; +using namespace lldb_private; + +bool PosixPlatformCommandOptionValidator::IsValid(Platform &platform, ExecutionContext &target) const +{ + llvm::Triple::OSType os = platform.GetSystemArchitecture().GetTriple().getOS(); + switch (os) + { + // Are there any other platforms that are not POSIX-compatible? + case llvm::Triple::Win32: + return false; + default: + return true; + } +} + +const char* PosixPlatformCommandOptionValidator::ShortConditionString() const +{ + return "POSIX"; +} + +const char* PosixPlatformCommandOptionValidator::LongConditionString() const +{ + return "Option only valid for POSIX-compliant hosts."; +} Index: lldb/trunk/source/Interpreter/Options.cpp =================================================================== --- lldb/trunk/source/Interpreter/Options.cpp +++ lldb/trunk/source/Interpreter/Options.cpp @@ -277,8 +277,7 @@ { const int short_opt = opt_defs[i].short_option; - m_getopt_table[i].name = opt_defs[i].long_option; - m_getopt_table[i].has_arg = opt_defs[i].option_has_arg; + m_getopt_table[i].definition = &opt_defs[i]; m_getopt_table[i].flag = nullptr; m_getopt_table[i].val = short_opt; @@ -297,7 +296,7 @@ opt_defs[i].long_option, short_opt, pos->second, - m_getopt_table[pos->second].name, + m_getopt_table[pos->second].definition->long_option, opt_defs[i].long_option); else Host::SystemLog (Host::eSystemLogError, "option[%u] --%s has a short option 0x%x that conflicts with option[%u] --%s, short option won't be used for --%s\n", @@ -305,17 +304,16 @@ opt_defs[i].long_option, short_opt, pos->second, - m_getopt_table[pos->second].name, + m_getopt_table[pos->second].definition->long_option, opt_defs[i].long_option); } } //getopt_long_only requires a NULL final entry in the table: - m_getopt_table[i].name = nullptr; - m_getopt_table[i].has_arg = 0; - m_getopt_table[i].flag = nullptr; - m_getopt_table[i].val = 0; + m_getopt_table[i].definition = nullptr; + m_getopt_table[i].flag = nullptr; + m_getopt_table[i].val = 0; } if (m_getopt_table.empty()) @@ -336,18 +334,29 @@ Options::OutputFormattedUsageText ( Stream &strm, - const char *text, + const OptionDefinition &option_def, uint32_t output_max_columns ) { - int len = strlen (text); + std::string actual_text; + if (option_def.validator) + { + const char *condition = option_def.validator->ShortConditionString(); + if (condition) + { + actual_text = "["; + actual_text.append(condition); + actual_text.append("] "); + } + } + actual_text.append(option_def.usage_text); // Will it all fit on one line? - if (static_cast(len + strm.GetIndentLevel()) < output_max_columns) + if (static_cast(actual_text.length() + strm.GetIndentLevel()) < output_max_columns) { // Output it as a single line. - strm.Indent (text); + strm.Indent (actual_text.c_str()); strm.EOL(); } else @@ -357,13 +366,13 @@ int text_width = output_max_columns - strm.GetIndentLevel() - 1; int start = 0; int end = start; - int final_end = strlen (text); + int final_end = actual_text.length(); int sub_len; while (end < final_end) { // Don't start the 'text' on a space, since we're already outputting the indentation. - while ((start < final_end) && (text[start] == ' ')) + while ((start < final_end) && (actual_text[start] == ' ')) start++; end = start + text_width; @@ -373,7 +382,7 @@ { // 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') + && actual_text[end] != ' ' && actual_text[end] != '\t' && actual_text[end] != '\n') end--; } @@ -383,7 +392,7 @@ strm.Indent(); assert (start < final_end); assert (start + sub_len <= final_end); - strm.Write(text + start, sub_len); + strm.Write(actual_text.c_str() + start, sub_len); start = end + 1; } strm.EOL(); @@ -630,7 +639,7 @@ strm.Printf ("\n\n"); // Now print out all the detailed information about the various options: long form, short form and help text: - // --long_name ( -short ) + // -short ( --long_name ) // help text // This variable is used to keep track of which options' info we've printed out, because some options can be in @@ -683,7 +692,7 @@ if (opt_defs[i].usage_text) OutputFormattedUsageText (strm, - opt_defs[i].usage_text, + opt_defs[i], screen_width); if (opt_defs[i].enum_values != nullptr) {