diff --git a/include/Support/CommandLine.h b/include/Support/CommandLine.h index b07b162a47b..e8a4250a894 100644 --- a/include/Support/CommandLine.h +++ b/include/Support/CommandLine.h @@ -4,8 +4,9 @@ // creating a tool. It provides a simple, minimalistic interface that is easily // extensible and supports nonlocal (library) command line options. // -// Note that rather than trying to figure out what this code does, you could try -// reading the library documentation located in docs/CommandLine.html +// Note that rather than trying to figure out what this code does, you should +// read the library documentation located in docs/CommandLine.html or looks at +// the many example usages in tools/*/*.cpp // //===----------------------------------------------------------------------===// @@ -16,45 +17,19 @@ #include #include #include +#include "boost/type_traits/object_traits.hpp" namespace cl { // Short namespace to make usage concise //===----------------------------------------------------------------------===// -// ParseCommandLineOptions - Minimalistic command line option processing entry +// ParseCommandLineOptions - Command line option processing entry point. // void cl::ParseCommandLineOptions(int &argc, char **argv, - const char *Overview = 0, - int Flags = 0); - -// ParserOptions - This set of option is use to control global behavior of the -// command line processor. -// -enum ParserOptions { - // DisableSingleLetterArgGrouping - With this option enabled, multiple letter - // options are allowed to bunch together with only a single hyphen for the - // whole group. This allows emulation of the behavior that ls uses for - // example: ls -la === ls -l -a Providing this option, disables this. - // - DisableSingleLetterArgGrouping = 0x0001, - - // EnableSingleLetterArgValue - This option allows arguments that are - // otherwise unrecognized to match single letter flags that take a value. - // This is useful for cases like a linker, where options are typically of the - // form '-lfoo' or '-L../../include' where -l or -L are the actual flags. - // - EnableSingleLetterArgValue = 0x0002, -}; - + const char *Overview = 0); //===----------------------------------------------------------------------===// -// Global flags permitted to be passed to command line arguments - -enum FlagsOptions { - NoFlags = 0x00, // Marker to make explicit that we have no flags - Default = 0x00, // Equally, marker to use the default flags - - GlobalsMask = 0x80, -}; +// Flags permitted to be passed to command line arguments +// enum NumOccurances { // Flags for the number of occurances allowed... Optional = 0x01, // Zero or One occurance @@ -62,11 +37,12 @@ enum NumOccurances { // Flags for the number of occurances allowed... Required = 0x03, // One occurance required OneOrMore = 0x04, // One or more occurances required - // ConsumeAfter - Marker for a null ("") flag that can be used to indicate - // that anything that matches the null marker starts a sequence of options - // that all get sent to the null marker. Thus, for example, all arguments - // to LLI are processed until a filename is found. Once a filename is found, - // all of the succeeding arguments are passed, unprocessed, to the null flag. + // ConsumeAfter - Indicates that this option is fed anything that follows the + // last positional argument required by the application (it is an error if + // there are zero positional arguments, and a ConsumeAfter option is used). + // Thus, for example, all arguments to LLI are processed until a filename is + // found. Once a filename is found, all of the succeeding arguments are + // passed, unprocessed, to the ConsumeAfter option. // ConsumeAfter = 0x05, @@ -87,14 +63,37 @@ enum OptionHidden { // Control whether -help shows this option HiddenMask = 0x60, }; +// Formatting flags - This controls special features that the option might have +// that cause it to be parsed differently... +// +// Prefix - This option allows arguments that are otherwise unrecognized to be +// matched by options that are a prefix of the actual value. This is useful for +// cases like a linker, where options are typically of the form '-lfoo' or +// '-L../../include' where -l or -L are the actual flags. When prefix is +// enabled, and used, the value for the flag comes from the suffix of the +// argument. +// +// Grouping - With this option enabled, multiple letter options are allowed to +// bunch together with only a single hyphen for the whole group. This allows +// emulation of the behavior that ls uses for example: ls -la === ls -l -a +// + +enum FormattingFlags { + NormalFormatting = 0x000, // Nothing special + Positional = 0x080, // Is a positional argument, no '-' required + Prefix = 0x100, // Can this option directly prefix its value? + Grouping = 0x180, // Can this option group with other options? + FormattingMask = 0x180, +}; + //===----------------------------------------------------------------------===// // Option Base class // -class Alias; +class alias; class Option { friend void cl::ParseCommandLineOptions(int &, char **, const char *, int); - friend class Alias; + friend class alias; // handleOccurances - Overriden by subclasses to handle the value passed into // an argument. Should return true if there was an error processing the @@ -111,12 +110,16 @@ class Option { virtual enum OptionHidden getOptionHiddenFlagDefault() const { return NotHidden; } + virtual enum FormattingFlags getFormattingFlagDefault() const { + return NormalFormatting; + } - int NumOccurances; // The number of times specified - const int Flags; // Flags for the argument + int NumOccurances; // The number of times specified + int Flags; // Flags for the argument public: - const char * const ArgStr; // The argument string itself (ex: "help", "o") - const char * const HelpStr; // The descriptive text message for --help + const char *ArgStr; // The argument string itself (ex: "help", "o") + const char *HelpStr; // The descriptive text message for --help + const char *ValueStr; // String describing what the value of this option is inline enum NumOccurances getNumOccurancesFlag() const { int NO = Flags & OccurancesMask; @@ -130,19 +133,54 @@ public: int OH = Flags & HiddenMask; return OH ? (enum OptionHidden)OH : getOptionHiddenFlagDefault(); } + inline enum FormattingFlags getFormattingFlag() const { + int OH = Flags & FormattingMask; + return OH ? (enum FormattingFlags)OH : getFormattingFlagDefault(); + } + + // hasArgStr - Return true if the argstr != "" + bool hasArgStr() const { return ArgStr[0] != 0; } + + //-------------------------------------------------------------------------=== + // Accessor functions set by OptionModifiers + // + void setArgStr(const char *S) { ArgStr = S; } + void setDescription(const char *S) { HelpStr = S; } + void setValueStr(const char *S) { ValueStr = S; } + + void setFlag(unsigned Flag, unsigned FlagMask) { + if (Flags & FlagMask) { + error(": Specified two settings for the same option!"); + exit(1); + } + + Flags |= Flag; + } + + void setNumOccurancesFlag(enum NumOccurances Val) { + setFlag(Val, OccurancesMask); + } + void setValueExpectedFlag(enum ValueExpected Val) { setFlag(Val, ValueMask); } + void setHiddenFlag(enum OptionHidden Val) { setFlag(Val, HiddenMask); } + void setFormattingFlag(enum FormattingFlags V) { setFlag(V, FormattingMask); } protected: - Option(const char *ArgStr, const char *Message, int Flags); - Option(int flags) : NumOccurances(0), Flags(flags), ArgStr(""), HelpStr("") {} + Option() : NumOccurances(0), Flags(0), + ArgStr(""), HelpStr(""), ValueStr("") {} public: + // addArgument - Tell the system that this Option subclass will handle all + // occurances of -ArgStr on the command line. + // + void addArgument(const char *ArgStr); + // Return the width of the option tag for printing... - virtual unsigned getOptionWidth() const; + virtual unsigned getOptionWidth() const = 0; // printOptionInfo - Print out information about this option. The // to-be-maintained width is specified. // - virtual void printOptionInfo(unsigned GlobalWidth) const; + virtual void printOptionInfo(unsigned GlobalWidth) const = 0; // addOccurance - Wrapper around handleOccurance that enforces Flags // @@ -158,100 +196,60 @@ public: //===----------------------------------------------------------------------===// -// Aliased command line option (alias this name to a preexisting name) +// Command line option modifiers that can be used to modify the behavior of +// command line option parsers... // -class Alias : public Option { - Option &AliasFor; - virtual bool handleOccurance(const char *ArgName, const std::string &Arg) { - return AliasFor.handleOccurance(AliasFor.ArgStr, Arg); - } - virtual enum OptionHidden getOptionHiddenFlagDefault() const {return Hidden;} -public: - inline Alias(const char *ArgStr, const char *Message, int Flags, - Option &aliasFor) : Option(ArgStr, Message, Flags), - AliasFor(aliasFor) {} + +// desc - Modifier to set the description shown in the --help output... +struct desc { + const char *Desc; + desc(const char *Str) : Desc(Str) {} + void apply(Option &O) const { O.setDescription(Desc); } }; -//===----------------------------------------------------------------------===// -// Boolean/flag command line option -// -class Flag : public Option { - bool &Value; - bool DValue; - virtual bool handleOccurance(const char *ArgName, const std::string &Arg); -public: - inline Flag(const char *ArgStr, const char *Message, int Flags = 0, - bool DefaultVal = false) - : Option(ArgStr, Message, Flags), Value(DValue) { - Value = DefaultVal; - } - - inline Flag(bool &UpdateVal, const char *ArgStr, const char *Message, - int Flags = 0, bool DefaultVal = false) - : Option(ArgStr, Message, Flags), Value(UpdateVal) { - Value = DefaultVal; - } - - operator const bool() const { return Value; } - inline bool operator=(bool Val) { Value = Val; return Val; } +// value_desc - Modifier to set the value description shown in the --help +// output... +struct value_desc { + const char *Desc; + value_desc(const char *Str) : Desc(Str) {} + void apply(Option &O) const { O.setValueStr(Desc); } }; - -//===----------------------------------------------------------------------===// -// Integer valued command line option +// init - Specify a default (initial) value for the command line argument, if +// the default constructor for the argument type does not give you what you +// want. This is only valid on "opt" arguments, not on "list" arguments. // -class Int : public Option { - int Value; - virtual bool handleOccurance(const char *ArgName, const std::string &Arg); - virtual enum ValueExpected getValueExpectedFlagDefault() const { - return ValueRequired; - } -public: - inline Int(const char *ArgStr, const char *Help, int Flags = 0, - int DefaultVal = 0) : Option(ArgStr, Help, Flags), - Value(DefaultVal) {} - inline operator int() const { return Value; } - inline int operator=(int Val) { Value = Val; return Val; } +template +struct initializer { + const Ty &Init; + initializer(const Ty &Val) : Init(Val) {} + + template + void apply(Opt &O) const { O.setInitialValue(Init); } }; +template +initializer init(const Ty &Val) { + return initializer(Val); +} -//===----------------------------------------------------------------------===// -// String valued command line option + +// location - Allow the user to specify which external variable they want to +// store the results of the command line argument processing into, if they don't +// want to store it in the option itself. // -class String : public Option, public std::string { - virtual bool handleOccurance(const char *ArgName, const std::string &Arg); - virtual enum ValueExpected getValueExpectedFlagDefault() const { - return ValueRequired; - } -public: - inline String(const char *ArgStr, const char *Help, int Flags = 0, - const char *DefaultVal = "") - : Option(ArgStr, Help, Flags), std::string(DefaultVal) {} +template +struct LocationClass { + Ty &Loc; + LocationClass(Ty &L) : Loc(L) {} - inline const std::string &operator=(const std::string &Val) { - return std::string::operator=(Val); - } + template + void apply(Opt &O) const { O.setLocation(O, Loc); } }; - -//===----------------------------------------------------------------------===// -// String list command line option -// -class StringList : public Option, public std::vector { - - virtual enum NumOccurances getNumOccurancesFlagDefault() const { - return ZeroOrMore; - } - virtual enum ValueExpected getValueExpectedFlagDefault() const { - return ValueRequired; - } - virtual bool handleOccurance(const char *ArgName, const std::string &Arg); - -public: - inline StringList(const char *ArgStr, const char *Help, int Flags = 0) - : Option(ArgStr, Help, Flags) {} -}; +template +LocationClass location(Ty &L) { return LocationClass(L); } //===----------------------------------------------------------------------===// @@ -260,177 +258,712 @@ public: #define clEnumVal(ENUMVAL, DESC) #ENUMVAL, ENUMVAL, DESC #define clEnumValN(ENUMVAL, FLAGNAME, DESC) FLAGNAME, ENUMVAL, DESC -// EnumBase - Base class for all enum/varargs related argument types... -class EnumBase : public Option { -protected: +// values - For custom data types, allow specifying a group of values together +// as the values that go into the mapping that the option handler uses. Note +// that the values list must always have a 0 at the end of the list to indicate +// that the list has ended. +// +template +class ValuesClass { // Use a vector instead of a map, because the lists should be short, // the overhead is less, and most importantly, it keeps them in the order // inserted so we can print our option out nicely. - std::vector > > ValueMap; - - inline EnumBase(const char *ArgStr, const char *Help, int Flags) - : Option(ArgStr, Help, Flags) {} - inline EnumBase(int Flags) : Option(Flags) {} - - // processValues - Incorporate the specifed varargs arglist into the - // ValueMap. - // + std::vector > > Values; void processValues(va_list Vals); - - // registerArgs - notify the system about these new arguments - void registerArgs(); - public: - // Turn an enum into the arg name that activates it - const char *getArgName(int ID) const; - const char *getArgDescription(int ID) const; + ValuesClass(const char *EnumName, DataType Val, const char *Desc, + va_list ValueArgs) { + // Insert the first value, which is required. + Values.push_back(std::make_pair(EnumName, std::make_pair(Val, Desc))); + + // Process the varargs portion of the values... + while (const char *EnumName = va_arg(ValueArgs, const char *)) { + DataType EnumVal = va_arg(ValueArgs, DataType); + const char *EnumDesc = va_arg(ValueArgs, const char *); + Values.push_back(std::make_pair(EnumName, // Add value to value map + std::make_pair(EnumVal, EnumDesc))); + } + } + + template + void apply(Opt &O) const { + for (unsigned i = 0, e = Values.size(); i != e; ++i) + O.getParser().addLiteralOption(Values[i].first, Values[i].second.first, + Values[i].second.second); + } }; -class EnumValueBase : public EnumBase { -protected: - inline EnumValueBase(const char *ArgStr, const char *Help, int Flags) - : EnumBase(ArgStr, Help, Flags) {} - inline EnumValueBase(int Flags) : EnumBase(Flags) {} +template +ValuesClass values(const char *Arg, DataType Val, const char *Desc, + ...) { + va_list ValueArgs; + va_start(ValueArgs, Desc); + ValuesClass Vals(Arg, Val, Desc, ValueArgs); + va_end(ValueArgs); + return Vals; +} - // handleOccurance - Set Value to the enum value specified by Arg - virtual bool handleOccurance(const char *ArgName, const std::string &Arg); + +//===----------------------------------------------------------------------===// +// parser class - Parameterizable parser for different data types. By default, +// known data types (string, int, bool) have specialized parsers, that do what +// you would expect. The default parser, used for data types that are not +// built-in, uses a mapping table to map specific options to values, which is +// used, among other things, to handle enum types. + +//-------------------------------------------------- +// generic_parser_base - This class holds all the non-generic code that we do +// not need replicated for every instance of the generic parser. This also +// allows us to put stuff into CommandLine.cpp +// +struct generic_parser_base { + virtual ~generic_parser_base() {} // Base class should have virtual-dtor + + // getNumOptions - Virtual function implemented by generic subclass to + // indicate how many entries are in Values. + // + virtual unsigned getNumOptions() const = 0; + + // getOption - Return option name N. + virtual const char *getOption(unsigned N) const = 0; + + // getDescription - Return description N + virtual const char *getDescription(unsigned N) const = 0; // Return the width of the option tag for printing... - virtual unsigned getOptionWidth() const; + virtual unsigned getOptionWidth(const Option &O) const; // printOptionInfo - Print out information about this option. The // to-be-maintained width is specified. // - virtual void printOptionInfo(unsigned GlobalWidth) const; + virtual void printOptionInfo(const Option &O, unsigned GlobalWidth) const; - // setValue - Subclasses override this when they need to receive a new value - virtual void setValue(int Val) = 0; + void initialize(Option &O) { + // All of the modifiers for the option have been processed by now, so the + // argstr field should be stable, copy it down now. + // + hasArgStr = O.hasArgStr(); + + // If there has been no argstr specified, that means that we need to add an + // argument for every possible option. This ensures that our options are + // vectored to us. + // + if (!hasArgStr) + for (unsigned i = 0, e = getNumOptions(); i != e; ++i) + O.addArgument(getOption(i)); + } + + enum ValueExpected getValueExpectedFlagDefault() const { + // If there is an ArgStr specified, then we are of the form: + // + // -opt=O2 or -opt O2 or -optO2 + // + // In which case, the value is required. Otherwise if an arg str has not + // been specified, we are of the form: + // + // -O2 or O2 or -la (where -l and -a are seperate options) + // + // If this is the case, we cannot allow a value. + // + if (hasArgStr) + return ValueRequired; + else + return ValueDisallowed; + } + +protected: + bool hasArgStr; }; -template // The enum we are representing -class Enum : public EnumValueBase { - virtual enum ValueExpected getValueExpectedFlagDefault() const { +// Default parser implementation - This implementation depends on having a +// mapping of recognized options to values of some sort. In addition to this, +// each entry in the mapping also tracks a help message that is printed with the +// command line option for --help. Because this is a simple mapping parser, the +// data type can be any unsupported type. +// +template +class parser : public generic_parser_base { + std::vector > > Values; + + // Implement virtual functions needed by generic_parser_base + unsigned getNumOptions() const { return Values.size(); } + const char *getOption(unsigned N) const { return Values[N].first; } + const char *getDescription(unsigned N) const { + return Values[N].second.second; + } + +public: + // Default implementation, requires user to populate it with values somehow. + template // parse - Return true on error. + bool parse(Opt &O, const char *ArgName, const string &Arg) { + string ArgVal; + if (hasArgStr) + ArgVal = Arg; + else + ArgVal = ArgName; + + for (unsigned i = 0, e = Values.size(); i != e; ++i) + if (ArgVal == Values[i].first) { + O.addValue(Values[i].second.first); + return false; + } + + return O.error(": Cannot find option named '" + ArgVal + "'!"); + } + + // addLiteralOption - Add an entry to the mapping table... + template + void addLiteralOption(const char *Name, const DT &V, const char *HelpStr) { + Values.push_back(std::make_pair(Name, std::make_pair((DataType)V,HelpStr))); + } +}; + + +//-------------------------------------------------- +// parser +// +template<> +class parser { + static bool parseImpl(Option &O, const string &Arg, bool &Val); +public: + + template // parse - Return true on error. + bool parse(Opt &O, const char *ArgName, const string &Arg) { + bool Val; + bool Error = parseImpl(O, Arg, Val); + if (!Error) O.addValue(Val); + return Error; + } + + enum ValueExpected getValueExpectedFlagDefault() const { + return ValueOptional; + } + + void initialize(Option &O) {} + + // Return the width of the option tag for printing... + virtual unsigned getOptionWidth(const Option &O) const; + + // printOptionInfo - Print out information about this option. The + // to-be-maintained width is specified. + // + virtual void printOptionInfo(const Option &O, unsigned GlobalWidth) const; +}; + + +//-------------------------------------------------- +// parser +// +template<> +class parser { + static bool parseImpl(Option &O, const string &Arg, int &Val); +public: + + // parse - Return true on error. + template + bool parse(Opt &O, const char *ArgName, const string &Arg) { + int Val; + bool Error = parseImpl(O, Arg, Val); + if (!Error) O.addValue(Val); + return Error; + } + + enum ValueExpected getValueExpectedFlagDefault() const { + return ValueRequired; + } + + void initialize(Option &O) {} + + // Return the width of the option tag for printing... + virtual unsigned getOptionWidth(const Option &O) const; + + // printOptionInfo - Print out information about this option. The + // to-be-maintained width is specified. + // + virtual void printOptionInfo(const Option &O, unsigned GlobalWidth) const; +}; + + +//-------------------------------------------------- +// parser +// +template<> +class parser { + static bool parseImpl(Option &O, const string &Arg, double &Val); +public: + + // parse - Return true on error. + template + bool parse(Opt &O, const char *ArgName, const string &Arg) { + double Val; + bool Error = parseImpl(O, Arg, Val); + if (!Error) O.addValue(Val); + return Error; + } + + enum ValueExpected getValueExpectedFlagDefault() const { + return ValueRequired; + } + + void initialize(Option &O) {} + + // Return the width of the option tag for printing... + virtual unsigned getOptionWidth(const Option &O) const; + + // printOptionInfo - Print out information about this option. The + // to-be-maintained width is specified. + // + virtual void printOptionInfo(const Option &O, unsigned GlobalWidth) const; +}; + +// Parser is the same as parser +template<> struct parser : public parser {}; + + + +//-------------------------------------------------- +// parser +// +template<> +struct parser { + // parse - Return true on error. + template + bool parse(Opt &O, const char *ArgName, const string &Arg) { + O.addValue(Arg); + return false; + } + enum ValueExpected getValueExpectedFlagDefault() const { return ValueRequired; } - E DVal; - E &Value; - // setValue - Subclasses override this when they need to receive a new value - virtual void setValue(int Val) { Value = (E)Val; } -public: - inline Enum(const char *ArgStr, int Flags, const char *Help, ...) - : EnumValueBase(ArgStr, Help, Flags), Value(DVal) { - va_list Values; - va_start(Values, Help); - processValues(Values); - va_end(Values); - Value = (E)ValueMap.front().second.first; // Grab default value - } - - inline Enum(E &EUpdate, const char *ArgStr, int Flags, const char *Help, ...) - : EnumValueBase(ArgStr, Help, Flags), Value(EUpdate) { - va_list Values; - va_start(Values, Help); - processValues(Values); - va_end(Values); - Value = (E)ValueMap.front().second.first; // Grab default value - } - - inline operator E() const { return Value; } - inline E operator=(E Val) { Value = Val; return Val; } -}; - - -//===----------------------------------------------------------------------===// -// Enum flags command line option -// -class EnumFlagsBase : public EnumValueBase { - virtual enum ValueExpected getValueExpectedFlagDefault() const { - return ValueDisallowed; - } -protected: - virtual bool handleOccurance(const char *ArgName, const std::string &Arg); - inline EnumFlagsBase(int Flags) : EnumValueBase(Flags) {} + void initialize(Option &O) {} // Return the width of the option tag for printing... - virtual unsigned getOptionWidth() const; + virtual unsigned getOptionWidth(const Option &O) const; // printOptionInfo - Print out information about this option. The // to-be-maintained width is specified. // - virtual void printOptionInfo(unsigned GlobalWidth) const; + virtual void printOptionInfo(const Option &O, unsigned GlobalWidth) const; }; -template // The enum we are representing -class EnumFlags : public EnumFlagsBase { - E DVal; - E &Value; - // setValue - Subclasses override this when they need to receive a new value - virtual void setValue(int Val) { Value = (E)Val; } + +//===----------------------------------------------------------------------===// +// applicator class - This class is used because we must use partial +// specialization to handle literal string arguments specially (const char* does +// not correctly respond to the apply method). Because the syntax to use this +// is a pain, we have the 'apply' method below to handle the nastiness... +// +template struct applicator { + template + static void opt(const Mod &M, Opt &O) { M.apply(O); } +}; + +// Handle const char* as a special case... +template struct applicator { + template + static void opt(const char *Str, Opt &O) { O.setArgStr(Str); } +}; +template<> struct applicator { + template + static void opt(const char *Str, Opt &O) { O.setArgStr(Str); } +}; + +template<> struct applicator { + static void opt(NumOccurances NO, Option &O) { O.setNumOccurancesFlag(NO); } +}; +template<> struct applicator { + static void opt(ValueExpected VE, Option &O) { O.setValueExpectedFlag(VE); } +}; +template<> struct applicator { + static void opt(OptionHidden OH, Option &O) { O.setHiddenFlag(OH); } +}; +template<> struct applicator { + static void opt(FormattingFlags FF, Option &O) { O.setFormattingFlag(FF); } +}; + +// apply method - Apply a modifier to an option in a type safe way. +template +void apply(const Mod &M, Opt *O) { + applicator::opt(M, *O); +} + + +//===----------------------------------------------------------------------===// +// opt_storage class + +// Default storage class definition: external storage. This implementation +// assumes the user will specify a variable to store the data into with the +// cl::location(x) modifier. +// +template +class opt_storage { + DataType *Location; // Where to store the object... + + void check() { + assert(Location != 0 && "cl::location(...) not specified for a command " + "line option with external storage!"); + } public: - inline EnumFlags(int Flags, ...) : EnumFlagsBase(Flags), Value(DVal) { - va_list Values; - va_start(Values, Flags); - processValues(Values); - va_end(Values); - registerArgs(); - Value = (E)ValueMap.front().second.first; // Grab default value - } - inline EnumFlags(E &RV, int Flags, ...) : EnumFlagsBase(Flags), Value(RV) { - va_list Values; - va_start(Values, Flags); - processValues(Values); - va_end(Values); - registerArgs(); - Value = (E)ValueMap.front().second.first; // Grab default value + opt_storage() : Location(0) {} + + bool setLocation(Option &O, DataType &L) { + if (Location) + return O.error(": cl::location(x) specified more than once!"); + Location = &L; + return false; } - inline operator E() const { return (E)Value; } - inline E operator=(E Val) { Value = Val; return Val; } + template + void setValue(const T &V) { + check(); + *Location = V; + } + + DataType &getValue() { check(); return *Location; } + const DataType &getValue() const { check(); return *Location; } +}; + + +// Define how to hold a class type object, such as a string. Since we can +// inherit from a class, we do so. This makes us exactly compatible with the +// object in all cases that it is used. +// +template +struct opt_storage : public DataType { + + template + void setValue(const T &V) { DataType::operator=(V); } + + DataType &getValue() { return *this; } + const DataType &getValue() const { return *this; } +}; + +// Define a partial specialization to handle things we cannot inherit from. In +// this case, we store an instance through containment, and overload operators +// to get at the value. +// +template +struct opt_storage { + DataType Value; + + // Make sure we initialize the value with the default constructor for the + // type. + opt_storage() : Value(DataType()) {} + + template + void setValue(const T &V) { Value = V; } + DataType &getValue() { return Value; } + DataType getValue() const { return Value; } }; //===----------------------------------------------------------------------===// -// Enum list command line option +// opt - A scalar command line option. // -class EnumListBase : public EnumBase { +template > +class opt : public Option, + public opt_storage::value>{ + ParserClass Parser; + + virtual bool handleOccurance(const char *ArgName, const std::string &Arg) { + return Parser.parse(*this, ArgName, Arg); + } + + virtual enum ValueExpected getValueExpectedFlagDefault() const { + return Parser.getValueExpectedFlagDefault(); + } + + // Forward printing stuff to the parser... + virtual unsigned getOptionWidth() const {return Parser.getOptionWidth(*this);} + virtual void printOptionInfo(unsigned GlobalWidth) const { + Parser.printOptionInfo(*this, GlobalWidth); + } + + void done() { + addArgument(ArgStr); + Parser.initialize(*this); + } +public: + // setInitialValue - Used by the cl::init modifier... + void setInitialValue(const DataType &V) { setValue(V); } + + // addValue - Used by the parser to add a value to the option + template + void addValue(const T &V) { setValue(V); } + ParserClass &getParser() { return Parser; } + + operator DataType() const { return getValue(); } + + template + DataType &operator=(const T &Val) { setValue(Val); return getValue(); } + + // One option... + template + opt(const M0t &M0) { + apply(M0, this); + done(); + } + + // Two options... + template + opt(const M0t &M0, const M1t &M1) { + apply(M0, this); apply(M1, this); + done(); + } + + // Three options... + template + opt(const M0t &M0, const M1t &M1, const M2t &M2) { + apply(M0, this); apply(M1, this); apply(M2, this); + done(); + } + // Four options... + template + opt(const M0t &M0, const M1t &M1, const M2t &M2, const M3t &M3) { + apply(M0, this); apply(M1, this); apply(M2, this); apply(M3, this); + done(); + } + // Five options... + template + opt(const M0t &M0, const M1t &M1, const M2t &M2, const M3t &M3, + const M4t &M4) { + apply(M0, this); apply(M1, this); apply(M2, this); apply(M3, this); + apply(M4, this); + done(); + } + // Six options... + template + opt(const M0t &M0, const M1t &M1, const M2t &M2, const M3t &M3, + const M4t &M4, const M5t &M5) { + apply(M0, this); apply(M1, this); apply(M2, this); apply(M3, this); + apply(M4, this); apply(M5, this); + done(); + } + // Seven options... + template + opt(const M0t &M0, const M1t &M1, const M2t &M2, const M3t &M3, + const M4t &M4, const M5t &M5, const M6t &M6) { + apply(M0, this); apply(M1, this); apply(M2, this); apply(M3, this); + apply(M4, this); apply(M5, this); apply(M6, this); + done(); + } + // Eight options... + template + opt(const M0t &M0, const M1t &M1, const M2t &M2, const M3t &M3, + const M4t &M4, const M5t &M5, const M6t &M6, const M7t &M7) { + apply(M0, this); apply(M1, this); apply(M2, this); apply(M3, this); + apply(M4, this); apply(M5, this); apply(M6, this); apply(M7, this); + done(); + } +}; + +//===----------------------------------------------------------------------===// +// list_storage class + +// Default storage class definition: external storage. This implementation +// assumes the user will specify a variable to store the data into with the +// cl::location(x) modifier. +// +template +class list_storage { + StorageClass *Location; // Where to store the object... + +public: + list_storage() : Location(0) {} + + bool setLocation(Option &O, StorageClass &L) { + if (Location) + return O.error(": cl::location(x) specified more than once!"); + Location = &L; + return false; + } + + template + void addValue(const T &V) { + assert(Location != 0 && "cl::location(...) not specified for a command " + "line option with external storage!"); + Location->push_back(V); + } +}; + + +// Define how to hold a class type object, such as a string. Since we can +// inherit from a class, we do so. This makes us exactly compatible with the +// object in all cases that it is used. +// +template +struct list_storage : public std::vector { + + template + void addValue(const T &V) { push_back(V); } +}; + + +//===----------------------------------------------------------------------===// +// list - A list of command line options. +// +template > +class list : public Option, public list_storage { + ParserClass Parser; + virtual enum NumOccurances getNumOccurancesFlagDefault() const { return ZeroOrMore; } virtual enum ValueExpected getValueExpectedFlagDefault() const { - return ValueDisallowed; + return Parser.getValueExpectedFlagDefault(); } -protected: - std::vector Values; // The options specified so far. - inline EnumListBase(int Flags) - : EnumBase(Flags) {} - virtual bool handleOccurance(const char *ArgName, const std::string &Arg); + virtual bool handleOccurance(const char *ArgName, const std::string &Arg) { + return Parser.parse(*this, ArgName, Arg); + } - // Return the width of the option tag for printing... - virtual unsigned getOptionWidth() const; + // Forward printing stuff to the parser... + virtual unsigned getOptionWidth() const {return Parser.getOptionWidth(*this);} + virtual void printOptionInfo(unsigned GlobalWidth) const { + Parser.printOptionInfo(*this, GlobalWidth); + } - // printOptionInfo - Print out information about this option. The - // to-be-maintained width is specified. - // - virtual void printOptionInfo(unsigned GlobalWidth) const; + void done() { + addArgument(ArgStr); + Parser.initialize(*this); + } public: - inline unsigned size() { return Values.size(); } + ParserClass &getParser() { return Parser; } + + // One option... + template + list(const M0t &M0) { + apply(M0, this); + done(); + } + // Two options... + template + list(const M0t &M0, const M1t &M1) { + apply(M0, this); apply(M1, this); + done(); + } + // Three options... + template + list(const M0t &M0, const M1t &M1, const M2t &M2) { + apply(M0, this); apply(M1, this); apply(M2, this); + done(); + } + // Four options... + template + list(const M0t &M0, const M1t &M1, const M2t &M2, const M3t &M3) { + apply(M0, this); apply(M1, this); apply(M2, this); apply(M3, this); + done(); + } + // Five options... + template + list(const M0t &M0, const M1t &M1, const M2t &M2, const M3t &M3, + const M4t &M4) { + apply(M0, this); apply(M1, this); apply(M2, this); apply(M3, this); + apply(M4, this); + done(); + } + // Six options... + template + list(const M0t &M0, const M1t &M1, const M2t &M2, const M3t &M3, + const M4t &M4, const M5t &M5) { + apply(M0, this); apply(M1, this); apply(M2, this); apply(M3, this); + apply(M4, this); apply(M5, this); + done(); + } + // Seven options... + template + list(const M0t &M0, const M1t &M1, const M2t &M2, const M3t &M3, + const M4t &M4, const M5t &M5, const M6t &M6) { + apply(M0, this); apply(M1, this); apply(M2, this); apply(M3, this); + apply(M4, this); apply(M5, this); apply(M6, this); + done(); + } + // Eight options... + template + list(const M0t &M0, const M1t &M1, const M2t &M2, const M3t &M3, + const M4t &M4, const M5t &M5, const M6t &M6, const M7t &M7) { + apply(M0, this); apply(M1, this); apply(M2, this); apply(M3, this); + apply(M4, this); apply(M5, this); apply(M6, this); apply(M7, this); + done(); + } }; -template // The enum we are representing -class EnumList : public EnumListBase { -public: - inline EnumList(int Flags, ...) : EnumListBase(Flags) { - va_list Values; - va_start(Values, Flags); - processValues(Values); - va_end(Values); - registerArgs(); + + +//===----------------------------------------------------------------------===// +// Aliased command line option (alias this name to a preexisting name) +// + +class alias : public Option { + Option *AliasFor; + virtual bool handleOccurance(const char *ArgName, const std::string &Arg) { + return AliasFor->handleOccurance(AliasFor->ArgStr, Arg); } - inline E operator[](unsigned i) const { return (E)Values[i]; } - inline E &operator[](unsigned i) { return (E&)Values[i]; } + // Aliases default to be hidden... + virtual enum OptionHidden getOptionHiddenFlagDefault() const {return Hidden;} + + // Handle printing stuff... + virtual unsigned getOptionWidth() const; + virtual void printOptionInfo(unsigned GlobalWidth) const; + + void done() { + if (!hasArgStr()) + error(": cl::alias must have argument name specified!"); + if (AliasFor == 0) + error(": cl::alias must have an cl::aliasopt(option) specified!"); + addArgument(ArgStr); + } +public: + void setAliasFor(Option &O) { + if (AliasFor) + error(": cl::alias must only have one cl::aliasopt(...) specified!"); + AliasFor = &O; + } + + // One option... + template + alias(const M0t &M0) : AliasFor(0) { + apply(M0, this); + done(); + } + // Two options... + template + alias(const M0t &M0, const M1t &M1) : AliasFor(0) { + apply(M0, this); apply(M1, this); + done(); + } + // Three options... + template + alias(const M0t &M0, const M1t &M1, const M2t &M2) : AliasFor(0) { + apply(M0, this); apply(M1, this); apply(M2, this); + done(); + } + // Four options... + template + alias(const M0t &M0, const M1t &M1, const M2t &M2, const M3t &M3) + : AliasFor(0) { + apply(M0, this); apply(M1, this); apply(M2, this); apply(M3, this); + done(); + } +}; + +// aliasfor - Modifier to set the option an alias aliases. +struct aliasopt { + Option &Opt; + aliasopt(Option &O) : Opt(O) {} + void apply(alias &A) const { A.setAliasFor(Opt); } }; } // End namespace cl diff --git a/include/llvm/Support/CommandLine.h b/include/llvm/Support/CommandLine.h index b07b162a47b..e8a4250a894 100644 --- a/include/llvm/Support/CommandLine.h +++ b/include/llvm/Support/CommandLine.h @@ -4,8 +4,9 @@ // creating a tool. It provides a simple, minimalistic interface that is easily // extensible and supports nonlocal (library) command line options. // -// Note that rather than trying to figure out what this code does, you could try -// reading the library documentation located in docs/CommandLine.html +// Note that rather than trying to figure out what this code does, you should +// read the library documentation located in docs/CommandLine.html or looks at +// the many example usages in tools/*/*.cpp // //===----------------------------------------------------------------------===// @@ -16,45 +17,19 @@ #include #include #include +#include "boost/type_traits/object_traits.hpp" namespace cl { // Short namespace to make usage concise //===----------------------------------------------------------------------===// -// ParseCommandLineOptions - Minimalistic command line option processing entry +// ParseCommandLineOptions - Command line option processing entry point. // void cl::ParseCommandLineOptions(int &argc, char **argv, - const char *Overview = 0, - int Flags = 0); - -// ParserOptions - This set of option is use to control global behavior of the -// command line processor. -// -enum ParserOptions { - // DisableSingleLetterArgGrouping - With this option enabled, multiple letter - // options are allowed to bunch together with only a single hyphen for the - // whole group. This allows emulation of the behavior that ls uses for - // example: ls -la === ls -l -a Providing this option, disables this. - // - DisableSingleLetterArgGrouping = 0x0001, - - // EnableSingleLetterArgValue - This option allows arguments that are - // otherwise unrecognized to match single letter flags that take a value. - // This is useful for cases like a linker, where options are typically of the - // form '-lfoo' or '-L../../include' where -l or -L are the actual flags. - // - EnableSingleLetterArgValue = 0x0002, -}; - + const char *Overview = 0); //===----------------------------------------------------------------------===// -// Global flags permitted to be passed to command line arguments - -enum FlagsOptions { - NoFlags = 0x00, // Marker to make explicit that we have no flags - Default = 0x00, // Equally, marker to use the default flags - - GlobalsMask = 0x80, -}; +// Flags permitted to be passed to command line arguments +// enum NumOccurances { // Flags for the number of occurances allowed... Optional = 0x01, // Zero or One occurance @@ -62,11 +37,12 @@ enum NumOccurances { // Flags for the number of occurances allowed... Required = 0x03, // One occurance required OneOrMore = 0x04, // One or more occurances required - // ConsumeAfter - Marker for a null ("") flag that can be used to indicate - // that anything that matches the null marker starts a sequence of options - // that all get sent to the null marker. Thus, for example, all arguments - // to LLI are processed until a filename is found. Once a filename is found, - // all of the succeeding arguments are passed, unprocessed, to the null flag. + // ConsumeAfter - Indicates that this option is fed anything that follows the + // last positional argument required by the application (it is an error if + // there are zero positional arguments, and a ConsumeAfter option is used). + // Thus, for example, all arguments to LLI are processed until a filename is + // found. Once a filename is found, all of the succeeding arguments are + // passed, unprocessed, to the ConsumeAfter option. // ConsumeAfter = 0x05, @@ -87,14 +63,37 @@ enum OptionHidden { // Control whether -help shows this option HiddenMask = 0x60, }; +// Formatting flags - This controls special features that the option might have +// that cause it to be parsed differently... +// +// Prefix - This option allows arguments that are otherwise unrecognized to be +// matched by options that are a prefix of the actual value. This is useful for +// cases like a linker, where options are typically of the form '-lfoo' or +// '-L../../include' where -l or -L are the actual flags. When prefix is +// enabled, and used, the value for the flag comes from the suffix of the +// argument. +// +// Grouping - With this option enabled, multiple letter options are allowed to +// bunch together with only a single hyphen for the whole group. This allows +// emulation of the behavior that ls uses for example: ls -la === ls -l -a +// + +enum FormattingFlags { + NormalFormatting = 0x000, // Nothing special + Positional = 0x080, // Is a positional argument, no '-' required + Prefix = 0x100, // Can this option directly prefix its value? + Grouping = 0x180, // Can this option group with other options? + FormattingMask = 0x180, +}; + //===----------------------------------------------------------------------===// // Option Base class // -class Alias; +class alias; class Option { friend void cl::ParseCommandLineOptions(int &, char **, const char *, int); - friend class Alias; + friend class alias; // handleOccurances - Overriden by subclasses to handle the value passed into // an argument. Should return true if there was an error processing the @@ -111,12 +110,16 @@ class Option { virtual enum OptionHidden getOptionHiddenFlagDefault() const { return NotHidden; } + virtual enum FormattingFlags getFormattingFlagDefault() const { + return NormalFormatting; + } - int NumOccurances; // The number of times specified - const int Flags; // Flags for the argument + int NumOccurances; // The number of times specified + int Flags; // Flags for the argument public: - const char * const ArgStr; // The argument string itself (ex: "help", "o") - const char * const HelpStr; // The descriptive text message for --help + const char *ArgStr; // The argument string itself (ex: "help", "o") + const char *HelpStr; // The descriptive text message for --help + const char *ValueStr; // String describing what the value of this option is inline enum NumOccurances getNumOccurancesFlag() const { int NO = Flags & OccurancesMask; @@ -130,19 +133,54 @@ public: int OH = Flags & HiddenMask; return OH ? (enum OptionHidden)OH : getOptionHiddenFlagDefault(); } + inline enum FormattingFlags getFormattingFlag() const { + int OH = Flags & FormattingMask; + return OH ? (enum FormattingFlags)OH : getFormattingFlagDefault(); + } + + // hasArgStr - Return true if the argstr != "" + bool hasArgStr() const { return ArgStr[0] != 0; } + + //-------------------------------------------------------------------------=== + // Accessor functions set by OptionModifiers + // + void setArgStr(const char *S) { ArgStr = S; } + void setDescription(const char *S) { HelpStr = S; } + void setValueStr(const char *S) { ValueStr = S; } + + void setFlag(unsigned Flag, unsigned FlagMask) { + if (Flags & FlagMask) { + error(": Specified two settings for the same option!"); + exit(1); + } + + Flags |= Flag; + } + + void setNumOccurancesFlag(enum NumOccurances Val) { + setFlag(Val, OccurancesMask); + } + void setValueExpectedFlag(enum ValueExpected Val) { setFlag(Val, ValueMask); } + void setHiddenFlag(enum OptionHidden Val) { setFlag(Val, HiddenMask); } + void setFormattingFlag(enum FormattingFlags V) { setFlag(V, FormattingMask); } protected: - Option(const char *ArgStr, const char *Message, int Flags); - Option(int flags) : NumOccurances(0), Flags(flags), ArgStr(""), HelpStr("") {} + Option() : NumOccurances(0), Flags(0), + ArgStr(""), HelpStr(""), ValueStr("") {} public: + // addArgument - Tell the system that this Option subclass will handle all + // occurances of -ArgStr on the command line. + // + void addArgument(const char *ArgStr); + // Return the width of the option tag for printing... - virtual unsigned getOptionWidth() const; + virtual unsigned getOptionWidth() const = 0; // printOptionInfo - Print out information about this option. The // to-be-maintained width is specified. // - virtual void printOptionInfo(unsigned GlobalWidth) const; + virtual void printOptionInfo(unsigned GlobalWidth) const = 0; // addOccurance - Wrapper around handleOccurance that enforces Flags // @@ -158,100 +196,60 @@ public: //===----------------------------------------------------------------------===// -// Aliased command line option (alias this name to a preexisting name) +// Command line option modifiers that can be used to modify the behavior of +// command line option parsers... // -class Alias : public Option { - Option &AliasFor; - virtual bool handleOccurance(const char *ArgName, const std::string &Arg) { - return AliasFor.handleOccurance(AliasFor.ArgStr, Arg); - } - virtual enum OptionHidden getOptionHiddenFlagDefault() const {return Hidden;} -public: - inline Alias(const char *ArgStr, const char *Message, int Flags, - Option &aliasFor) : Option(ArgStr, Message, Flags), - AliasFor(aliasFor) {} + +// desc - Modifier to set the description shown in the --help output... +struct desc { + const char *Desc; + desc(const char *Str) : Desc(Str) {} + void apply(Option &O) const { O.setDescription(Desc); } }; -//===----------------------------------------------------------------------===// -// Boolean/flag command line option -// -class Flag : public Option { - bool &Value; - bool DValue; - virtual bool handleOccurance(const char *ArgName, const std::string &Arg); -public: - inline Flag(const char *ArgStr, const char *Message, int Flags = 0, - bool DefaultVal = false) - : Option(ArgStr, Message, Flags), Value(DValue) { - Value = DefaultVal; - } - - inline Flag(bool &UpdateVal, const char *ArgStr, const char *Message, - int Flags = 0, bool DefaultVal = false) - : Option(ArgStr, Message, Flags), Value(UpdateVal) { - Value = DefaultVal; - } - - operator const bool() const { return Value; } - inline bool operator=(bool Val) { Value = Val; return Val; } +// value_desc - Modifier to set the value description shown in the --help +// output... +struct value_desc { + const char *Desc; + value_desc(const char *Str) : Desc(Str) {} + void apply(Option &O) const { O.setValueStr(Desc); } }; - -//===----------------------------------------------------------------------===// -// Integer valued command line option +// init - Specify a default (initial) value for the command line argument, if +// the default constructor for the argument type does not give you what you +// want. This is only valid on "opt" arguments, not on "list" arguments. // -class Int : public Option { - int Value; - virtual bool handleOccurance(const char *ArgName, const std::string &Arg); - virtual enum ValueExpected getValueExpectedFlagDefault() const { - return ValueRequired; - } -public: - inline Int(const char *ArgStr, const char *Help, int Flags = 0, - int DefaultVal = 0) : Option(ArgStr, Help, Flags), - Value(DefaultVal) {} - inline operator int() const { return Value; } - inline int operator=(int Val) { Value = Val; return Val; } +template +struct initializer { + const Ty &Init; + initializer(const Ty &Val) : Init(Val) {} + + template + void apply(Opt &O) const { O.setInitialValue(Init); } }; +template +initializer init(const Ty &Val) { + return initializer(Val); +} -//===----------------------------------------------------------------------===// -// String valued command line option + +// location - Allow the user to specify which external variable they want to +// store the results of the command line argument processing into, if they don't +// want to store it in the option itself. // -class String : public Option, public std::string { - virtual bool handleOccurance(const char *ArgName, const std::string &Arg); - virtual enum ValueExpected getValueExpectedFlagDefault() const { - return ValueRequired; - } -public: - inline String(const char *ArgStr, const char *Help, int Flags = 0, - const char *DefaultVal = "") - : Option(ArgStr, Help, Flags), std::string(DefaultVal) {} +template +struct LocationClass { + Ty &Loc; + LocationClass(Ty &L) : Loc(L) {} - inline const std::string &operator=(const std::string &Val) { - return std::string::operator=(Val); - } + template + void apply(Opt &O) const { O.setLocation(O, Loc); } }; - -//===----------------------------------------------------------------------===// -// String list command line option -// -class StringList : public Option, public std::vector { - - virtual enum NumOccurances getNumOccurancesFlagDefault() const { - return ZeroOrMore; - } - virtual enum ValueExpected getValueExpectedFlagDefault() const { - return ValueRequired; - } - virtual bool handleOccurance(const char *ArgName, const std::string &Arg); - -public: - inline StringList(const char *ArgStr, const char *Help, int Flags = 0) - : Option(ArgStr, Help, Flags) {} -}; +template +LocationClass location(Ty &L) { return LocationClass(L); } //===----------------------------------------------------------------------===// @@ -260,177 +258,712 @@ public: #define clEnumVal(ENUMVAL, DESC) #ENUMVAL, ENUMVAL, DESC #define clEnumValN(ENUMVAL, FLAGNAME, DESC) FLAGNAME, ENUMVAL, DESC -// EnumBase - Base class for all enum/varargs related argument types... -class EnumBase : public Option { -protected: +// values - For custom data types, allow specifying a group of values together +// as the values that go into the mapping that the option handler uses. Note +// that the values list must always have a 0 at the end of the list to indicate +// that the list has ended. +// +template +class ValuesClass { // Use a vector instead of a map, because the lists should be short, // the overhead is less, and most importantly, it keeps them in the order // inserted so we can print our option out nicely. - std::vector > > ValueMap; - - inline EnumBase(const char *ArgStr, const char *Help, int Flags) - : Option(ArgStr, Help, Flags) {} - inline EnumBase(int Flags) : Option(Flags) {} - - // processValues - Incorporate the specifed varargs arglist into the - // ValueMap. - // + std::vector > > Values; void processValues(va_list Vals); - - // registerArgs - notify the system about these new arguments - void registerArgs(); - public: - // Turn an enum into the arg name that activates it - const char *getArgName(int ID) const; - const char *getArgDescription(int ID) const; + ValuesClass(const char *EnumName, DataType Val, const char *Desc, + va_list ValueArgs) { + // Insert the first value, which is required. + Values.push_back(std::make_pair(EnumName, std::make_pair(Val, Desc))); + + // Process the varargs portion of the values... + while (const char *EnumName = va_arg(ValueArgs, const char *)) { + DataType EnumVal = va_arg(ValueArgs, DataType); + const char *EnumDesc = va_arg(ValueArgs, const char *); + Values.push_back(std::make_pair(EnumName, // Add value to value map + std::make_pair(EnumVal, EnumDesc))); + } + } + + template + void apply(Opt &O) const { + for (unsigned i = 0, e = Values.size(); i != e; ++i) + O.getParser().addLiteralOption(Values[i].first, Values[i].second.first, + Values[i].second.second); + } }; -class EnumValueBase : public EnumBase { -protected: - inline EnumValueBase(const char *ArgStr, const char *Help, int Flags) - : EnumBase(ArgStr, Help, Flags) {} - inline EnumValueBase(int Flags) : EnumBase(Flags) {} +template +ValuesClass values(const char *Arg, DataType Val, const char *Desc, + ...) { + va_list ValueArgs; + va_start(ValueArgs, Desc); + ValuesClass Vals(Arg, Val, Desc, ValueArgs); + va_end(ValueArgs); + return Vals; +} - // handleOccurance - Set Value to the enum value specified by Arg - virtual bool handleOccurance(const char *ArgName, const std::string &Arg); + +//===----------------------------------------------------------------------===// +// parser class - Parameterizable parser for different data types. By default, +// known data types (string, int, bool) have specialized parsers, that do what +// you would expect. The default parser, used for data types that are not +// built-in, uses a mapping table to map specific options to values, which is +// used, among other things, to handle enum types. + +//-------------------------------------------------- +// generic_parser_base - This class holds all the non-generic code that we do +// not need replicated for every instance of the generic parser. This also +// allows us to put stuff into CommandLine.cpp +// +struct generic_parser_base { + virtual ~generic_parser_base() {} // Base class should have virtual-dtor + + // getNumOptions - Virtual function implemented by generic subclass to + // indicate how many entries are in Values. + // + virtual unsigned getNumOptions() const = 0; + + // getOption - Return option name N. + virtual const char *getOption(unsigned N) const = 0; + + // getDescription - Return description N + virtual const char *getDescription(unsigned N) const = 0; // Return the width of the option tag for printing... - virtual unsigned getOptionWidth() const; + virtual unsigned getOptionWidth(const Option &O) const; // printOptionInfo - Print out information about this option. The // to-be-maintained width is specified. // - virtual void printOptionInfo(unsigned GlobalWidth) const; + virtual void printOptionInfo(const Option &O, unsigned GlobalWidth) const; - // setValue - Subclasses override this when they need to receive a new value - virtual void setValue(int Val) = 0; + void initialize(Option &O) { + // All of the modifiers for the option have been processed by now, so the + // argstr field should be stable, copy it down now. + // + hasArgStr = O.hasArgStr(); + + // If there has been no argstr specified, that means that we need to add an + // argument for every possible option. This ensures that our options are + // vectored to us. + // + if (!hasArgStr) + for (unsigned i = 0, e = getNumOptions(); i != e; ++i) + O.addArgument(getOption(i)); + } + + enum ValueExpected getValueExpectedFlagDefault() const { + // If there is an ArgStr specified, then we are of the form: + // + // -opt=O2 or -opt O2 or -optO2 + // + // In which case, the value is required. Otherwise if an arg str has not + // been specified, we are of the form: + // + // -O2 or O2 or -la (where -l and -a are seperate options) + // + // If this is the case, we cannot allow a value. + // + if (hasArgStr) + return ValueRequired; + else + return ValueDisallowed; + } + +protected: + bool hasArgStr; }; -template // The enum we are representing -class Enum : public EnumValueBase { - virtual enum ValueExpected getValueExpectedFlagDefault() const { +// Default parser implementation - This implementation depends on having a +// mapping of recognized options to values of some sort. In addition to this, +// each entry in the mapping also tracks a help message that is printed with the +// command line option for --help. Because this is a simple mapping parser, the +// data type can be any unsupported type. +// +template +class parser : public generic_parser_base { + std::vector > > Values; + + // Implement virtual functions needed by generic_parser_base + unsigned getNumOptions() const { return Values.size(); } + const char *getOption(unsigned N) const { return Values[N].first; } + const char *getDescription(unsigned N) const { + return Values[N].second.second; + } + +public: + // Default implementation, requires user to populate it with values somehow. + template // parse - Return true on error. + bool parse(Opt &O, const char *ArgName, const string &Arg) { + string ArgVal; + if (hasArgStr) + ArgVal = Arg; + else + ArgVal = ArgName; + + for (unsigned i = 0, e = Values.size(); i != e; ++i) + if (ArgVal == Values[i].first) { + O.addValue(Values[i].second.first); + return false; + } + + return O.error(": Cannot find option named '" + ArgVal + "'!"); + } + + // addLiteralOption - Add an entry to the mapping table... + template + void addLiteralOption(const char *Name, const DT &V, const char *HelpStr) { + Values.push_back(std::make_pair(Name, std::make_pair((DataType)V,HelpStr))); + } +}; + + +//-------------------------------------------------- +// parser +// +template<> +class parser { + static bool parseImpl(Option &O, const string &Arg, bool &Val); +public: + + template // parse - Return true on error. + bool parse(Opt &O, const char *ArgName, const string &Arg) { + bool Val; + bool Error = parseImpl(O, Arg, Val); + if (!Error) O.addValue(Val); + return Error; + } + + enum ValueExpected getValueExpectedFlagDefault() const { + return ValueOptional; + } + + void initialize(Option &O) {} + + // Return the width of the option tag for printing... + virtual unsigned getOptionWidth(const Option &O) const; + + // printOptionInfo - Print out information about this option. The + // to-be-maintained width is specified. + // + virtual void printOptionInfo(const Option &O, unsigned GlobalWidth) const; +}; + + +//-------------------------------------------------- +// parser +// +template<> +class parser { + static bool parseImpl(Option &O, const string &Arg, int &Val); +public: + + // parse - Return true on error. + template + bool parse(Opt &O, const char *ArgName, const string &Arg) { + int Val; + bool Error = parseImpl(O, Arg, Val); + if (!Error) O.addValue(Val); + return Error; + } + + enum ValueExpected getValueExpectedFlagDefault() const { + return ValueRequired; + } + + void initialize(Option &O) {} + + // Return the width of the option tag for printing... + virtual unsigned getOptionWidth(const Option &O) const; + + // printOptionInfo - Print out information about this option. The + // to-be-maintained width is specified. + // + virtual void printOptionInfo(const Option &O, unsigned GlobalWidth) const; +}; + + +//-------------------------------------------------- +// parser +// +template<> +class parser { + static bool parseImpl(Option &O, const string &Arg, double &Val); +public: + + // parse - Return true on error. + template + bool parse(Opt &O, const char *ArgName, const string &Arg) { + double Val; + bool Error = parseImpl(O, Arg, Val); + if (!Error) O.addValue(Val); + return Error; + } + + enum ValueExpected getValueExpectedFlagDefault() const { + return ValueRequired; + } + + void initialize(Option &O) {} + + // Return the width of the option tag for printing... + virtual unsigned getOptionWidth(const Option &O) const; + + // printOptionInfo - Print out information about this option. The + // to-be-maintained width is specified. + // + virtual void printOptionInfo(const Option &O, unsigned GlobalWidth) const; +}; + +// Parser is the same as parser +template<> struct parser : public parser {}; + + + +//-------------------------------------------------- +// parser +// +template<> +struct parser { + // parse - Return true on error. + template + bool parse(Opt &O, const char *ArgName, const string &Arg) { + O.addValue(Arg); + return false; + } + enum ValueExpected getValueExpectedFlagDefault() const { return ValueRequired; } - E DVal; - E &Value; - // setValue - Subclasses override this when they need to receive a new value - virtual void setValue(int Val) { Value = (E)Val; } -public: - inline Enum(const char *ArgStr, int Flags, const char *Help, ...) - : EnumValueBase(ArgStr, Help, Flags), Value(DVal) { - va_list Values; - va_start(Values, Help); - processValues(Values); - va_end(Values); - Value = (E)ValueMap.front().second.first; // Grab default value - } - - inline Enum(E &EUpdate, const char *ArgStr, int Flags, const char *Help, ...) - : EnumValueBase(ArgStr, Help, Flags), Value(EUpdate) { - va_list Values; - va_start(Values, Help); - processValues(Values); - va_end(Values); - Value = (E)ValueMap.front().second.first; // Grab default value - } - - inline operator E() const { return Value; } - inline E operator=(E Val) { Value = Val; return Val; } -}; - - -//===----------------------------------------------------------------------===// -// Enum flags command line option -// -class EnumFlagsBase : public EnumValueBase { - virtual enum ValueExpected getValueExpectedFlagDefault() const { - return ValueDisallowed; - } -protected: - virtual bool handleOccurance(const char *ArgName, const std::string &Arg); - inline EnumFlagsBase(int Flags) : EnumValueBase(Flags) {} + void initialize(Option &O) {} // Return the width of the option tag for printing... - virtual unsigned getOptionWidth() const; + virtual unsigned getOptionWidth(const Option &O) const; // printOptionInfo - Print out information about this option. The // to-be-maintained width is specified. // - virtual void printOptionInfo(unsigned GlobalWidth) const; + virtual void printOptionInfo(const Option &O, unsigned GlobalWidth) const; }; -template // The enum we are representing -class EnumFlags : public EnumFlagsBase { - E DVal; - E &Value; - // setValue - Subclasses override this when they need to receive a new value - virtual void setValue(int Val) { Value = (E)Val; } + +//===----------------------------------------------------------------------===// +// applicator class - This class is used because we must use partial +// specialization to handle literal string arguments specially (const char* does +// not correctly respond to the apply method). Because the syntax to use this +// is a pain, we have the 'apply' method below to handle the nastiness... +// +template struct applicator { + template + static void opt(const Mod &M, Opt &O) { M.apply(O); } +}; + +// Handle const char* as a special case... +template struct applicator { + template + static void opt(const char *Str, Opt &O) { O.setArgStr(Str); } +}; +template<> struct applicator { + template + static void opt(const char *Str, Opt &O) { O.setArgStr(Str); } +}; + +template<> struct applicator { + static void opt(NumOccurances NO, Option &O) { O.setNumOccurancesFlag(NO); } +}; +template<> struct applicator { + static void opt(ValueExpected VE, Option &O) { O.setValueExpectedFlag(VE); } +}; +template<> struct applicator { + static void opt(OptionHidden OH, Option &O) { O.setHiddenFlag(OH); } +}; +template<> struct applicator { + static void opt(FormattingFlags FF, Option &O) { O.setFormattingFlag(FF); } +}; + +// apply method - Apply a modifier to an option in a type safe way. +template +void apply(const Mod &M, Opt *O) { + applicator::opt(M, *O); +} + + +//===----------------------------------------------------------------------===// +// opt_storage class + +// Default storage class definition: external storage. This implementation +// assumes the user will specify a variable to store the data into with the +// cl::location(x) modifier. +// +template +class opt_storage { + DataType *Location; // Where to store the object... + + void check() { + assert(Location != 0 && "cl::location(...) not specified for a command " + "line option with external storage!"); + } public: - inline EnumFlags(int Flags, ...) : EnumFlagsBase(Flags), Value(DVal) { - va_list Values; - va_start(Values, Flags); - processValues(Values); - va_end(Values); - registerArgs(); - Value = (E)ValueMap.front().second.first; // Grab default value - } - inline EnumFlags(E &RV, int Flags, ...) : EnumFlagsBase(Flags), Value(RV) { - va_list Values; - va_start(Values, Flags); - processValues(Values); - va_end(Values); - registerArgs(); - Value = (E)ValueMap.front().second.first; // Grab default value + opt_storage() : Location(0) {} + + bool setLocation(Option &O, DataType &L) { + if (Location) + return O.error(": cl::location(x) specified more than once!"); + Location = &L; + return false; } - inline operator E() const { return (E)Value; } - inline E operator=(E Val) { Value = Val; return Val; } + template + void setValue(const T &V) { + check(); + *Location = V; + } + + DataType &getValue() { check(); return *Location; } + const DataType &getValue() const { check(); return *Location; } +}; + + +// Define how to hold a class type object, such as a string. Since we can +// inherit from a class, we do so. This makes us exactly compatible with the +// object in all cases that it is used. +// +template +struct opt_storage : public DataType { + + template + void setValue(const T &V) { DataType::operator=(V); } + + DataType &getValue() { return *this; } + const DataType &getValue() const { return *this; } +}; + +// Define a partial specialization to handle things we cannot inherit from. In +// this case, we store an instance through containment, and overload operators +// to get at the value. +// +template +struct opt_storage { + DataType Value; + + // Make sure we initialize the value with the default constructor for the + // type. + opt_storage() : Value(DataType()) {} + + template + void setValue(const T &V) { Value = V; } + DataType &getValue() { return Value; } + DataType getValue() const { return Value; } }; //===----------------------------------------------------------------------===// -// Enum list command line option +// opt - A scalar command line option. // -class EnumListBase : public EnumBase { +template > +class opt : public Option, + public opt_storage::value>{ + ParserClass Parser; + + virtual bool handleOccurance(const char *ArgName, const std::string &Arg) { + return Parser.parse(*this, ArgName, Arg); + } + + virtual enum ValueExpected getValueExpectedFlagDefault() const { + return Parser.getValueExpectedFlagDefault(); + } + + // Forward printing stuff to the parser... + virtual unsigned getOptionWidth() const {return Parser.getOptionWidth(*this);} + virtual void printOptionInfo(unsigned GlobalWidth) const { + Parser.printOptionInfo(*this, GlobalWidth); + } + + void done() { + addArgument(ArgStr); + Parser.initialize(*this); + } +public: + // setInitialValue - Used by the cl::init modifier... + void setInitialValue(const DataType &V) { setValue(V); } + + // addValue - Used by the parser to add a value to the option + template + void addValue(const T &V) { setValue(V); } + ParserClass &getParser() { return Parser; } + + operator DataType() const { return getValue(); } + + template + DataType &operator=(const T &Val) { setValue(Val); return getValue(); } + + // One option... + template + opt(const M0t &M0) { + apply(M0, this); + done(); + } + + // Two options... + template + opt(const M0t &M0, const M1t &M1) { + apply(M0, this); apply(M1, this); + done(); + } + + // Three options... + template + opt(const M0t &M0, const M1t &M1, const M2t &M2) { + apply(M0, this); apply(M1, this); apply(M2, this); + done(); + } + // Four options... + template + opt(const M0t &M0, const M1t &M1, const M2t &M2, const M3t &M3) { + apply(M0, this); apply(M1, this); apply(M2, this); apply(M3, this); + done(); + } + // Five options... + template + opt(const M0t &M0, const M1t &M1, const M2t &M2, const M3t &M3, + const M4t &M4) { + apply(M0, this); apply(M1, this); apply(M2, this); apply(M3, this); + apply(M4, this); + done(); + } + // Six options... + template + opt(const M0t &M0, const M1t &M1, const M2t &M2, const M3t &M3, + const M4t &M4, const M5t &M5) { + apply(M0, this); apply(M1, this); apply(M2, this); apply(M3, this); + apply(M4, this); apply(M5, this); + done(); + } + // Seven options... + template + opt(const M0t &M0, const M1t &M1, const M2t &M2, const M3t &M3, + const M4t &M4, const M5t &M5, const M6t &M6) { + apply(M0, this); apply(M1, this); apply(M2, this); apply(M3, this); + apply(M4, this); apply(M5, this); apply(M6, this); + done(); + } + // Eight options... + template + opt(const M0t &M0, const M1t &M1, const M2t &M2, const M3t &M3, + const M4t &M4, const M5t &M5, const M6t &M6, const M7t &M7) { + apply(M0, this); apply(M1, this); apply(M2, this); apply(M3, this); + apply(M4, this); apply(M5, this); apply(M6, this); apply(M7, this); + done(); + } +}; + +//===----------------------------------------------------------------------===// +// list_storage class + +// Default storage class definition: external storage. This implementation +// assumes the user will specify a variable to store the data into with the +// cl::location(x) modifier. +// +template +class list_storage { + StorageClass *Location; // Where to store the object... + +public: + list_storage() : Location(0) {} + + bool setLocation(Option &O, StorageClass &L) { + if (Location) + return O.error(": cl::location(x) specified more than once!"); + Location = &L; + return false; + } + + template + void addValue(const T &V) { + assert(Location != 0 && "cl::location(...) not specified for a command " + "line option with external storage!"); + Location->push_back(V); + } +}; + + +// Define how to hold a class type object, such as a string. Since we can +// inherit from a class, we do so. This makes us exactly compatible with the +// object in all cases that it is used. +// +template +struct list_storage : public std::vector { + + template + void addValue(const T &V) { push_back(V); } +}; + + +//===----------------------------------------------------------------------===// +// list - A list of command line options. +// +template > +class list : public Option, public list_storage { + ParserClass Parser; + virtual enum NumOccurances getNumOccurancesFlagDefault() const { return ZeroOrMore; } virtual enum ValueExpected getValueExpectedFlagDefault() const { - return ValueDisallowed; + return Parser.getValueExpectedFlagDefault(); } -protected: - std::vector Values; // The options specified so far. - inline EnumListBase(int Flags) - : EnumBase(Flags) {} - virtual bool handleOccurance(const char *ArgName, const std::string &Arg); + virtual bool handleOccurance(const char *ArgName, const std::string &Arg) { + return Parser.parse(*this, ArgName, Arg); + } - // Return the width of the option tag for printing... - virtual unsigned getOptionWidth() const; + // Forward printing stuff to the parser... + virtual unsigned getOptionWidth() const {return Parser.getOptionWidth(*this);} + virtual void printOptionInfo(unsigned GlobalWidth) const { + Parser.printOptionInfo(*this, GlobalWidth); + } - // printOptionInfo - Print out information about this option. The - // to-be-maintained width is specified. - // - virtual void printOptionInfo(unsigned GlobalWidth) const; + void done() { + addArgument(ArgStr); + Parser.initialize(*this); + } public: - inline unsigned size() { return Values.size(); } + ParserClass &getParser() { return Parser; } + + // One option... + template + list(const M0t &M0) { + apply(M0, this); + done(); + } + // Two options... + template + list(const M0t &M0, const M1t &M1) { + apply(M0, this); apply(M1, this); + done(); + } + // Three options... + template + list(const M0t &M0, const M1t &M1, const M2t &M2) { + apply(M0, this); apply(M1, this); apply(M2, this); + done(); + } + // Four options... + template + list(const M0t &M0, const M1t &M1, const M2t &M2, const M3t &M3) { + apply(M0, this); apply(M1, this); apply(M2, this); apply(M3, this); + done(); + } + // Five options... + template + list(const M0t &M0, const M1t &M1, const M2t &M2, const M3t &M3, + const M4t &M4) { + apply(M0, this); apply(M1, this); apply(M2, this); apply(M3, this); + apply(M4, this); + done(); + } + // Six options... + template + list(const M0t &M0, const M1t &M1, const M2t &M2, const M3t &M3, + const M4t &M4, const M5t &M5) { + apply(M0, this); apply(M1, this); apply(M2, this); apply(M3, this); + apply(M4, this); apply(M5, this); + done(); + } + // Seven options... + template + list(const M0t &M0, const M1t &M1, const M2t &M2, const M3t &M3, + const M4t &M4, const M5t &M5, const M6t &M6) { + apply(M0, this); apply(M1, this); apply(M2, this); apply(M3, this); + apply(M4, this); apply(M5, this); apply(M6, this); + done(); + } + // Eight options... + template + list(const M0t &M0, const M1t &M1, const M2t &M2, const M3t &M3, + const M4t &M4, const M5t &M5, const M6t &M6, const M7t &M7) { + apply(M0, this); apply(M1, this); apply(M2, this); apply(M3, this); + apply(M4, this); apply(M5, this); apply(M6, this); apply(M7, this); + done(); + } }; -template // The enum we are representing -class EnumList : public EnumListBase { -public: - inline EnumList(int Flags, ...) : EnumListBase(Flags) { - va_list Values; - va_start(Values, Flags); - processValues(Values); - va_end(Values); - registerArgs(); + + +//===----------------------------------------------------------------------===// +// Aliased command line option (alias this name to a preexisting name) +// + +class alias : public Option { + Option *AliasFor; + virtual bool handleOccurance(const char *ArgName, const std::string &Arg) { + return AliasFor->handleOccurance(AliasFor->ArgStr, Arg); } - inline E operator[](unsigned i) const { return (E)Values[i]; } - inline E &operator[](unsigned i) { return (E&)Values[i]; } + // Aliases default to be hidden... + virtual enum OptionHidden getOptionHiddenFlagDefault() const {return Hidden;} + + // Handle printing stuff... + virtual unsigned getOptionWidth() const; + virtual void printOptionInfo(unsigned GlobalWidth) const; + + void done() { + if (!hasArgStr()) + error(": cl::alias must have argument name specified!"); + if (AliasFor == 0) + error(": cl::alias must have an cl::aliasopt(option) specified!"); + addArgument(ArgStr); + } +public: + void setAliasFor(Option &O) { + if (AliasFor) + error(": cl::alias must only have one cl::aliasopt(...) specified!"); + AliasFor = &O; + } + + // One option... + template + alias(const M0t &M0) : AliasFor(0) { + apply(M0, this); + done(); + } + // Two options... + template + alias(const M0t &M0, const M1t &M1) : AliasFor(0) { + apply(M0, this); apply(M1, this); + done(); + } + // Three options... + template + alias(const M0t &M0, const M1t &M1, const M2t &M2) : AliasFor(0) { + apply(M0, this); apply(M1, this); apply(M2, this); + done(); + } + // Four options... + template + alias(const M0t &M0, const M1t &M1, const M2t &M2, const M3t &M3) + : AliasFor(0) { + apply(M0, this); apply(M1, this); apply(M2, this); apply(M3, this); + done(); + } +}; + +// aliasfor - Modifier to set the option an alias aliases. +struct aliasopt { + Option &Opt; + aliasopt(Option &O) : Opt(O) {} + void apply(alias &A) const { A.setAliasFor(Opt); } }; } // End namespace cl diff --git a/lib/Support/CommandLine.cpp b/lib/Support/CommandLine.cpp index c3f18bd1528..d11fbd7119e 100644 --- a/lib/Support/CommandLine.cpp +++ b/lib/Support/CommandLine.cpp @@ -23,6 +23,10 @@ using std::vector; using std::string; using std::cerr; +//===----------------------------------------------------------------------===// +// Basic, shared command line option processing machinery... +// + // Return the global command line option vector. Making it a function scoped // static ensures that it will be initialized correctly before its first use. // @@ -31,6 +35,11 @@ static map &getOpts() { return CommandLineOptions; } +static vector &getPositionalOpts() { + static vector Positional; + return Positional; +} + static void AddArgument(const string &ArgName, Option *Opt) { if (getOpts().find(ArgName) != getOpts().end()) { cerr << "CommandLine Error: Argument '" << ArgName @@ -72,46 +81,153 @@ static inline bool ProvideOption(Option *Handler, const char *ArgName, return Handler->addOccurance(ArgName, Value); } -// ValueGroupedArgs - Return true if the specified string is valid as a group -// of single letter arguments stuck together like the 'ls -la' case. -// -static inline bool ValidGroupedArgs(string Args) { - for (unsigned i = 0; i < Args.size(); ++i) { - map::iterator I = getOpts().find(string(1, Args[i])); - if (I == getOpts().end()) return false; // Make sure option exists +static bool ProvidePositionalOption(Option *Handler, string &Arg) { + int Dummy; + return ProvideOption(Handler, "", Arg.c_str(), 0, 0, Dummy); +} - // Grouped arguments have no value specified, make sure that if this option - // exists that it can accept no argument. - // - switch (I->second->getValueExpectedFlag()) { - case ValueDisallowed: - case ValueOptional: break; - default: return false; - } + +// Option predicates... +static inline bool isGrouping(const Option *O) { + return O->getFormattingFlag() == cl::Grouping; +} +static inline bool isPrefixedOrGrouping(const Option *O) { + return isGrouping(O) || O->getFormattingFlag() == cl::Prefix; +} + +// getOptionPred - Check to see if there are any options that satisfy the +// specified predicate with names that are the prefixes in Name. This is +// checked by progressively stripping characters off of the name, checking to +// see if there options that satisfy the predicate. If we find one, return it, +// otherwise return null. +// +static Option *getOptionPred(std::string Name, unsigned &Length, + bool (*Pred)(const Option*)) { + + map::iterator I = getOpts().find(Name); + if (I != getOpts().end() && Pred(I->second)) { + Length = Name.length(); + return I->second; } - return true; + if (Name.size() == 1) return 0; + do { + Name.erase(Name.end()-1, Name.end()); // Chop off the last character... + I = getOpts().find(Name); + + // Loop while we haven't found an option and Name still has at least two + // characters in it (so that the next iteration will not be the empty + // string... + } while ((I == getOpts().end() || !Pred(I->second)) && Name.size() > 1); + + if (I != getOpts().end() && Pred(I->second)) { + Length = Name.length(); + return I->second; // Found one! + } + return 0; // No option found! +} + +static bool RequiresValue(const Option *O) { + return O->getNumOccurancesFlag() == cl::Required || + O->getNumOccurancesFlag() == cl::OneOrMore; +} + +static bool EatsUnboundedNumberOfValues(const Option *O) { + return O->getNumOccurancesFlag() == cl::ZeroOrMore || + O->getNumOccurancesFlag() == cl::OneOrMore; } void cl::ParseCommandLineOptions(int &argc, char **argv, - const char *Overview = 0, int Flags = 0) { + const char *Overview = 0) { + assert((!getOpts().empty() || !getPositionalOpts().empty()) && + "No options specified, or ParseCommandLineOptions called more" + " than once!"); ProgramName = argv[0]; // Save this away safe and snug ProgramOverview = Overview; bool ErrorParsing = false; + map &Opts = getOpts(); + vector &PositionalOpts = getPositionalOpts(); + + // Check out the positional arguments to collect information about them. + unsigned NumPositionalRequired = 0; + Option *ConsumeAfterOpt = 0; + if (!PositionalOpts.empty()) { + if (PositionalOpts[0]->getNumOccurancesFlag() == cl::ConsumeAfter) { + assert(PositionalOpts.size() > 1 && + "Cannot specify cl::ConsumeAfter without a positional argument!"); + ConsumeAfterOpt = PositionalOpts[0]; + } + + // Calculate how many positional values are _required_. + bool UnboundedFound = false; + for (unsigned i = ConsumeAfterOpt != 0, e = PositionalOpts.size(); + i != e; ++i) { + Option *Opt = PositionalOpts[i]; + if (RequiresValue(Opt)) + ++NumPositionalRequired; + else if (ConsumeAfterOpt) { + // ConsumeAfter cannot be combined with "optional" positional options + ErrorParsing |= + Opt->error(" error - this positional option will never be matched, " + "because it does not Require a value, and a " + "cl::ConsumeAfter option is active!"); + } else if (UnboundedFound) { // This option does not "require" a value... + // Make sure this option is not specified after an option that eats all + // extra arguments, or this one will never get any! + // + ErrorParsing |= Opt->error(" error - option can never match, because " + "another positional argument will match an " + "unbounded number of values, and this option" + " does not require a value!"); + } + UnboundedFound |= EatsUnboundedNumberOfValues(Opt); + } + } + + // PositionalVals - A vector of "positional" arguments we accumulate into to + // processes at the end... + // + vector PositionalVals; + // Loop over all of the arguments... processing them. + bool DashDashFound = false; // Have we read '--'? for (int i = 1; i < argc; ++i) { Option *Handler = 0; const char *Value = ""; const char *ArgName = ""; - if (argv[i][0] != '-') { // Unnamed argument? - map::iterator I = getOpts().find(""); - Handler = I != getOpts().end() ? I->second : 0; - Value = argv[i]; - } else { // We start with a - or --, eat dashes + + // Check to see if this is a positional argument. This argument is + // considered to be positional if it doesn't start with '-', if it is "-" + // itself, or if we have see "--" already. + // + if (argv[i][0] != '-' || argv[i][1] == 0 || DashDashFound) { + // Positional argument! + if (!PositionalOpts.empty()) { + PositionalVals.push_back(argv[i]); + + // All of the positional arguments have been fulfulled, give the rest to + // the consume after option... if it's specified... + // + if (PositionalVals.size() == NumPositionalRequired && + ConsumeAfterOpt != 0) { + for (++i; i < argc; ++i) + PositionalVals.push_back(argv[i]); + break; // Handle outside of the argument processing loop... + } + + // Delay processing positional arguments until the end... + continue; + } + } else { // We start with a '-', must be an argument... ArgName = argv[i]+1; while (*ArgName == '-') ++ArgName; // Eat leading dashes + if (*ArgName == 0 && !DashDashFound) { // Is this the mythical "--"? + DashDashFound = true; // Yup, take note of that fact... + continue; // Don't try to process it as an argument iself. + } + const char *ArgNameEnd = ArgName; while (*ArgNameEnd && *ArgNameEnd != '=') ++ArgNameEnd; // Scan till end of argument name... @@ -123,46 +239,58 @@ void cl::ParseCommandLineOptions(int &argc, char **argv, if (*ArgName != 0) { string RealName(ArgName, ArgNameEnd); // Extract arg name part - map::iterator I = getOpts().find(RealName); + map::iterator I = Opts.find(RealName); - if (I == getOpts().end() && !*Value && RealName.size() > 1) { - // If grouping of single letter arguments is enabled, see if this is a - // legal grouping... - // - if (!(Flags & DisableSingleLetterArgGrouping) && - ValidGroupedArgs(RealName)) { + if (I == Opts.end() && !*Value && RealName.size() > 1) { + // Check to see if this "option" is really a prefixed or grouped + // argument... + // + unsigned Length = 0; + Option *PGOpt = getOptionPred(RealName, Length, isPrefixedOrGrouping); - for (unsigned i = 0; i < RealName.size(); ++i) { - char ArgName[2] = { 0, 0 }; int Dummy; - ArgName[0] = RealName[i]; - I = getOpts().find(ArgName); - assert(I != getOpts().end() && "ValidGroupedArgs failed!"); + // If the option is a prefixed option, then the value is simply the + // rest of the name... so fall through to later processing, by + // setting up the argument name flags and value fields. + // + if (PGOpt && PGOpt->getFormattingFlag() == cl::Prefix) { + ArgNameEnd = ArgName+Length; + Value = ArgNameEnd; + I = Opts.find(string(ArgName, ArgNameEnd)); + assert(I->second == PGOpt); + } else if (PGOpt) { + // This must be a grouped option... handle all of them now... + assert(isGrouping(PGOpt) && "Broken getOptionPred!"); + + do { + // Move current arg name out of RealName into RealArgName... + string RealArgName(RealName.begin(), RealName.begin()+Length); + RealName.erase(RealName.begin(), RealName.begin()+Length); // Because ValueRequired is an invalid flag for grouped arguments, // we don't need to pass argc/argv in... // - ErrorParsing |= ProvideOption(I->second, ArgName, "", - 0, 0, Dummy); - } - continue; - } else if (Flags & EnableSingleLetterArgValue) { - // Check to see if the first letter is a single letter argument that - // have a value that is equal to the rest of the string. If this - // is the case, recognize it now. (Example: -lfoo for a linker) - // - I = getOpts().find(string(1, RealName[0])); - if (I != getOpts().end()) { - // If we are successful, fall through to later processing, by - // setting up the argument name flags and value fields. - // - ArgNameEnd = ArgName+1; - Value = ArgNameEnd; - } - } + assert(PGOpt->getValueExpectedFlag() != cl::ValueRequired && + "Option can not be cl::Grouping AND cl::ValueRequired!"); + int Dummy; + ErrorParsing |= ProvideOption(PGOpt, RealArgName.c_str(), "", + 0, 0, Dummy); + + // Get the next grouping option... + if (!RealName.empty()) + PGOpt = getOptionPred(RealName, Length, isGrouping); + } while (!RealName.empty() && PGOpt); + + if (RealName.empty()) // Processed all of the options, move on + continue; // to the next argv[] value... + + // If RealName is not empty, that means we did not match one of the + // options! This is an error. + // + I = Opts.end(); + } } - - Handler = I != getOpts().end() ? I->second : 0; + Handler = I != Opts.end() ? I->second : 0; } } @@ -174,17 +302,63 @@ void cl::ParseCommandLineOptions(int &argc, char **argv, } ErrorParsing |= ProvideOption(Handler, ArgName, Value, argc, argv, i); + } - // If this option should consume all arguments that come after it... - if (Handler->getNumOccurancesFlag() == ConsumeAfter) { - for (++i; i < argc; ++i) - ErrorParsing |= ProvideOption(Handler, ArgName, argv[i], argc, argv, i); + // Check and handle positional arguments now... + if (NumPositionalRequired > PositionalVals.size()) { + cerr << "Not enough positional command line arguments specified!\n"; + cerr << "Must specify at least " << NumPositionalRequired + << " positional arguments: See: " << argv[0] << " --help\n"; + ErrorParsing = true; + + + } else if (ConsumeAfterOpt == 0) { + // Positional args have already been handled if ConsumeAfter is specified... + unsigned ValNo = 0, NumVals = PositionalVals.size(); + for (unsigned i = 0, e = PositionalOpts.size(); i != e; ++i) { + if (RequiresValue(PositionalOpts[i])) { + ProvidePositionalOption(PositionalOpts[i], PositionalVals[ValNo++]); + --NumPositionalRequired; // We fulfilled our duty... + } + + // If we _can_ give this option more arguments, do so now, as long as we + // do not give it values that others need. 'Done' controls whether the + // option even _WANTS_ any more. + // + bool Done = PositionalOpts[i]->getNumOccurancesFlag() == cl::Required; + while (NumVals-ValNo > NumPositionalRequired && !Done) { + switch (PositionalOpts[i]->getNumOccurancesFlag()) { + case cl::Optional: + Done = true; // Optional arguments want _at most_ one value + // FALL THROUGH + case cl::ZeroOrMore: // Zero or more will take all they can get... + case cl::OneOrMore: // One or more will take all they can get... + ProvidePositionalOption(PositionalOpts[i], PositionalVals[ValNo++]); + break; + default: + assert(0 && "Internal error, unexpected NumOccurances flag in " + "positional argument processing!"); + } + } } + } else { + assert(ConsumeAfterOpt && NumPositionalRequired <= PositionalVals.size()); + unsigned ValNo = 0; + for (unsigned j = 1, e = PositionalOpts.size(); j != e; ++j) + if (RequiresValue(PositionalOpts[j])) + ErrorParsing |= + ProvidePositionalOption(PositionalOpts[j], PositionalVals[ValNo++]); + + // Handle over all of the rest of the arguments to the + // cl::ConsumeAfter command line option... + for (; ValNo != PositionalVals.size(); ++ValNo) + ErrorParsing |= ProvidePositionalOption(ConsumeAfterOpt, + PositionalVals[ValNo]); } // Loop over args and make sure all required args are specified! - for (map::iterator I = getOpts().begin(), - E = getOpts().end(); I != E; ++I) { + for (map::iterator I = Opts.begin(), + E = Opts.end(); I != E; ++I) { switch (I->second->getNumOccurancesFlag()) { case Required: case OneOrMore: @@ -198,9 +372,10 @@ void cl::ParseCommandLineOptions(int &argc, char **argv, } } - // Free all of the memory allocated to the vector. Command line options may - // only be processed once! - getOpts().clear(); + // Free all of the memory allocated to the map. Command line options may only + // be processed once! + Opts.clear(); + PositionalOpts.clear(); // If we had an error processing our arguments, don't let the program execute if (ErrorParsing) exit(1); @@ -209,14 +384,14 @@ void cl::ParseCommandLineOptions(int &argc, char **argv, //===----------------------------------------------------------------------===// // Option Base class implementation // -Option::Option(const char *argStr, const char *helpStr, int flags) - : NumOccurances(0), Flags(flags), ArgStr(argStr), HelpStr(helpStr) { - AddArgument(ArgStr, this); -} bool Option::error(string Message, const char *ArgName = 0) { if (ArgName == 0) ArgName = ArgStr; - cerr << "-" << ArgName << " option" << Message << "\n"; + if (ArgName[0] == 0) + cerr << HelpStr; // Be nice for positional arguments + else + cerr << "-" << ArgName; + cerr << " option" << Message << "\n"; return true; } @@ -241,275 +416,303 @@ bool Option::addOccurance(const char *ArgName, const string &Value) { return handleOccurance(ArgName, Value); } +// addArgument - Tell the system that this Option subclass will handle all +// occurances of -ArgStr on the command line. +// +void Option::addArgument(const char *ArgStr) { + if (ArgStr[0]) + AddArgument(ArgStr, this); + else if (getFormattingFlag() == Positional) + getPositionalOpts().push_back(this); + else if (getNumOccurancesFlag() == ConsumeAfter) { + assert((getPositionalOpts().empty() || + getPositionalOpts().front()->getNumOccurancesFlag() != ConsumeAfter) + && "Cannot specify more than one option with cl::ConsumeAfter " + "specified!"); + getPositionalOpts().insert(getPositionalOpts().begin(), this); + } +} + + +// getValueStr - Get the value description string, using "DefaultMsg" if nothing +// has been specified yet. +// +static const char *getValueStr(const Option &O, const char *DefaultMsg) { + if (O.ValueStr[0] == 0) return DefaultMsg; + return O.ValueStr; +} + +//===----------------------------------------------------------------------===// +// cl::alias class implementation +// + // Return the width of the option tag for printing... -unsigned Option::getOptionWidth() const { +unsigned alias::getOptionWidth() const { return std::strlen(ArgStr)+6; } -void Option::printOptionInfo(unsigned GlobalWidth) const { +// Print out the option for the alias... +void alias::printOptionInfo(unsigned GlobalWidth) const { unsigned L = std::strlen(ArgStr); - if (L == 0) return; // Don't print the empty arg like this! cerr << " -" << ArgStr << string(GlobalWidth-L-6, ' ') << " - " << HelpStr << "\n"; } + //===----------------------------------------------------------------------===// -// Boolean/flag command line option implementation +// Parser Implementation code... // -bool Flag::handleOccurance(const char *ArgName, const string &Arg) { +// parser implementation +// +bool parser::parseImpl(Option &O, const string &Arg, bool &Value) { if (Arg == "" || Arg == "true" || Arg == "TRUE" || Arg == "True" || Arg == "1") { Value = true; } else if (Arg == "false" || Arg == "FALSE" || Arg == "False" || Arg == "0") { Value = false; } else { - return error(": '" + Arg + - "' is invalid value for boolean argument! Try 0 or 1"); + return O.error(": '" + Arg + + "' is invalid value for boolean argument! Try 0 or 1"); } - return false; } -//===----------------------------------------------------------------------===// -// Integer valued command line option implementation +// Return the width of the option tag for printing... +unsigned parser::getOptionWidth(const Option &O) const { + return std::strlen(O.ArgStr)+6; +} + +// printOptionInfo - Print out information about this option. The +// to-be-maintained width is specified. // -bool Int::handleOccurance(const char *ArgName, const string &Arg) { +void parser::printOptionInfo(const Option &O, unsigned GlobalWidth) const{ + unsigned L = std::strlen(O.ArgStr); + cerr << " -" << O.ArgStr << string(GlobalWidth-L-6, ' ') << " - " + << O.HelpStr << "\n"; +} + + + +// parser implementation +// +bool parser::parseImpl(Option &O, const string &Arg, int &Value) { const char *ArgStart = Arg.c_str(); char *End; Value = (int)strtol(ArgStart, &End, 0); if (*End != 0) - return error(": '" + Arg + "' value invalid for integer argument!"); - return false; -} - -//===----------------------------------------------------------------------===// -// String valued command line option implementation -// -bool String::handleOccurance(const char *ArgName, const string &Arg) { - *this = Arg; + return O.error(": '" + Arg + "' value invalid for integer argument!"); return false; } -//===----------------------------------------------------------------------===// -// StringList valued command line option implementation +// Return the width of the option tag for printing... +unsigned parser::getOptionWidth(const Option &O) const { + return std::strlen(O.ArgStr)+std::strlen(getValueStr(O, "int"))+9; +} + +// printOptionInfo - Print out information about this option. The +// to-be-maintained width is specified. // -bool StringList::handleOccurance(const char *ArgName, const string &Arg) { - push_back(Arg); +void parser::printOptionInfo(const Option &O, unsigned GlobalWidth) const{ + cerr << " -" << O.ArgStr << "=<" << getValueStr(O, "int") << ">" + << string(GlobalWidth-getOptionWidth(O), ' ') << " - " + << O.HelpStr << "\n"; +} + + +// parser implementation +// +bool parser::parseImpl(Option &O, const string &Arg, double &Value) { + const char *ArgStart = Arg.c_str(); + char *End; + Value = strtod(ArgStart, &End); + if (*End != 0) + return O.error(": '" +Arg+ "' value invalid for floating point argument!"); return false; } -//===----------------------------------------------------------------------===// -// Enum valued command line option implementation +// Return the width of the option tag for printing... +unsigned parser::getOptionWidth(const Option &O) const { + return std::strlen(O.ArgStr)+std::strlen(getValueStr(O, "number"))+9; +} + +// printOptionInfo - Print out information about this option. The +// to-be-maintained width is specified. // -void EnumBase::processValues(va_list Vals) { - while (const char *EnumName = va_arg(Vals, const char *)) { - int EnumVal = va_arg(Vals, int); - const char *EnumDesc = va_arg(Vals, const char *); - ValueMap.push_back(std::make_pair(EnumName, // Add value to value map - std::make_pair(EnumVal, EnumDesc))); +void parser::printOptionInfo(const Option &O, + unsigned GlobalWidth) const{ + cerr << " -" << O.ArgStr << "=<" << getValueStr(O, "number") << ">" + << string(GlobalWidth-getOptionWidth(O), ' ') + << " - " << O.HelpStr << "\n"; +} + + +// parser implementation +// + +// Return the width of the option tag for printing... +unsigned parser::getOptionWidth(const Option &O) const { + return std::strlen(O.ArgStr)+std::strlen(getValueStr(O, "string"))+9; +} + +// printOptionInfo - Print out information about this option. The +// to-be-maintained width is specified. +// +void parser::printOptionInfo(const Option &O, + unsigned GlobalWidth) const{ + cerr << " -" << O.ArgStr << " <" << getValueStr(O, "string") << ">" + << string(GlobalWidth-getOptionWidth(O), ' ') + << " - " << O.HelpStr << "\n"; +} + +// generic_parser_base implementation +// + +// Return the width of the option tag for printing... +unsigned generic_parser_base::getOptionWidth(const Option &O) const { + if (O.hasArgStr()) { + unsigned Size = std::strlen(O.ArgStr)+6; + for (unsigned i = 0, e = getNumOptions(); i != e; ++i) + Size = std::max(Size, (unsigned)std::strlen(getOption(i))+8); + return Size; + } else { + unsigned BaseSize = 0; + for (unsigned i = 0, e = getNumOptions(); i != e; ++i) + BaseSize = std::max(BaseSize, (unsigned)std::strlen(getOption(i))+8); + return BaseSize; } } -// registerArgs - notify the system about these new arguments -void EnumBase::registerArgs() { - for (unsigned i = 0; i < ValueMap.size(); ++i) - AddArgument(ValueMap[i].first, this); -} +// printOptionInfo - Print out information about this option. The +// to-be-maintained width is specified. +// +void generic_parser_base::printOptionInfo(const Option &O, + unsigned GlobalWidth) const { + if (O.hasArgStr()) { + unsigned L = std::strlen(O.ArgStr); + cerr << " -" << O.ArgStr << string(GlobalWidth-L-6, ' ') + << " - " << O.HelpStr << "\n"; -const char *EnumBase::getArgName(int ID) const { - for (unsigned i = 0; i < ValueMap.size(); ++i) - if (ID == ValueMap[i].second.first) return ValueMap[i].first; - return ""; -} -const char *EnumBase::getArgDescription(int ID) const { - for (unsigned i = 0; i < ValueMap.size(); ++i) - if (ID == ValueMap[i].second.first) return ValueMap[i].second.second; - return ""; -} - - - -bool EnumValueBase::handleOccurance(const char *ArgName, const string &Arg) { - unsigned i; - for (i = 0; i < ValueMap.size(); ++i) - if (ValueMap[i].first == Arg) break; - - if (i == ValueMap.size()) { - string Alternatives; - for (i = 0; i < ValueMap.size(); ++i) { - if (i) Alternatives += ", "; - Alternatives += ValueMap[i].first; + for (unsigned i = 0, e = getNumOptions(); i != e; ++i) { + unsigned NumSpaces = GlobalWidth-strlen(getOption(i))-8; + cerr << " =" << getOption(i) << string(NumSpaces, ' ') << " - " + << getDescription(i) << "\n"; + } + } else { + if (O.HelpStr[0]) + cerr << " " << O.HelpStr << "\n"; + for (unsigned i = 0, e = getNumOptions(); i != e; ++i) { + unsigned L = std::strlen(getOption(i)); + cerr << " -" << getOption(i) << string(GlobalWidth-L-8, ' ') << " - " + << getDescription(i) << "\n"; } - - return error(": unrecognized alternative '" + Arg + - "'! Alternatives are: " + Alternatives); - } - setValue(ValueMap[i].second.first); - return false; -} - -// Return the width of the option tag for printing... -unsigned EnumValueBase::getOptionWidth() const { - unsigned BaseSize = Option::getOptionWidth(); - for (unsigned i = 0; i < ValueMap.size(); ++i) - BaseSize = std::max(BaseSize, (unsigned)std::strlen(ValueMap[i].first)+8); - return BaseSize; -} - -// printOptionInfo - Print out information about this option. The -// to-be-maintained width is specified. -// -void EnumValueBase::printOptionInfo(unsigned GlobalWidth) const { - Option::printOptionInfo(GlobalWidth); - for (unsigned i = 0; i < ValueMap.size(); ++i) { - unsigned NumSpaces = GlobalWidth-strlen(ValueMap[i].first)-8; - cerr << " =" << ValueMap[i].first << string(NumSpaces, ' ') << " - " - << ValueMap[i].second.second; - - if (i == 0) cerr << " (default)"; - cerr << "\n"; - } -} - -//===----------------------------------------------------------------------===// -// Enum flags command line option implementation -// - -bool EnumFlagsBase::handleOccurance(const char *ArgName, const string &Arg) { - return EnumValueBase::handleOccurance("", ArgName); -} - -unsigned EnumFlagsBase::getOptionWidth() const { - unsigned BaseSize = 0; - for (unsigned i = 0; i < ValueMap.size(); ++i) - BaseSize = std::max(BaseSize, (unsigned)std::strlen(ValueMap[i].first)+6); - return BaseSize; -} - -void EnumFlagsBase::printOptionInfo(unsigned GlobalWidth) const { - for (unsigned i = 0; i < ValueMap.size(); ++i) { - unsigned L = std::strlen(ValueMap[i].first); - cerr << " -" << ValueMap[i].first << string(GlobalWidth-L-6, ' ') << " - " - << ValueMap[i].second.second; - if (i == 0) cerr << " (default)"; - cerr << "\n"; } } //===----------------------------------------------------------------------===// -// Enum list command line option implementation -// - -bool EnumListBase::handleOccurance(const char *ArgName, const string &Arg) { - unsigned i; - for (i = 0; i < ValueMap.size(); ++i) - if (ValueMap[i].first == string(ArgName)) break; - if (i == ValueMap.size()) - return error(": CommandLine INTERNAL ERROR", ArgName); - Values.push_back(ValueMap[i].second.first); - return false; -} - -// Return the width of the option tag for printing... -unsigned EnumListBase::getOptionWidth() const { - unsigned BaseSize = 0; - for (unsigned i = 0; i < ValueMap.size(); ++i) - BaseSize = std::max(BaseSize, (unsigned)std::strlen(ValueMap[i].first)+6); - return BaseSize; -} - - -// printOptionInfo - Print out information about this option. The -// to-be-maintained width is specified. -// -void EnumListBase::printOptionInfo(unsigned GlobalWidth) const { - for (unsigned i = 0; i < ValueMap.size(); ++i) { - unsigned L = std::strlen(ValueMap[i].first); - cerr << " -" << ValueMap[i].first << string(GlobalWidth-L-6, ' ') << " - " - << ValueMap[i].second.second << "\n"; - } -} - - -//===----------------------------------------------------------------------===// -// Help option... always automatically provided. +// --help and --help-hidden option implementation // namespace { -// isHidden/isReallyHidden - Predicates to be used to filter down arg lists. -inline bool isHidden(pair &OptPair) { - return OptPair.second->getOptionHiddenFlag() >= Hidden; -} -inline bool isReallyHidden(pair &OptPair) { - return OptPair.second->getOptionHiddenFlag() == ReallyHidden; -} - -class Help : public Option { +class HelpPrinter { unsigned MaxArgLen; const Option *EmptyArg; const bool ShowHidden; - virtual bool handleOccurance(const char *ArgName, const string &Arg) { + // isHidden/isReallyHidden - Predicates to be used to filter down arg lists. + inline static bool isHidden(pair &OptPair) { + return OptPair.second->getOptionHiddenFlag() >= Hidden; + } + inline static bool isReallyHidden(pair &OptPair) { + return OptPair.second->getOptionHiddenFlag() == ReallyHidden; + } + +public: + HelpPrinter(bool showHidden) : ShowHidden(showHidden) { + EmptyArg = 0; + } + + void operator=(bool Value) { + if (Value == false) return; + // Copy Options into a vector so we can sort them as we like... vector > Options; copy(getOpts().begin(), getOpts().end(), std::back_inserter(Options)); // Eliminate Hidden or ReallyHidden arguments, depending on ShowHidden - Options.erase(remove_if(Options.begin(), Options.end(), - std::ptr_fun(ShowHidden ? isReallyHidden : isHidden)), + Options.erase(std::remove_if(Options.begin(), Options.end(), + std::ptr_fun(ShowHidden ? isReallyHidden : isHidden)), Options.end()); // Eliminate duplicate entries in table (from enum flags options, f.e.) - std::set OptionSet; - for (unsigned i = 0; i < Options.size(); ) - if (OptionSet.count(Options[i].second) == 0) - OptionSet.insert(Options[i++].second); // Add to set - else - Options.erase(Options.begin()+i); // Erase duplicate - + { // Give OptionSet a scope + std::set OptionSet; + for (unsigned i = 0; i != Options.size(); ++i) + if (OptionSet.count(Options[i].second) == 0) + OptionSet.insert(Options[i].second); // Add new entry to set + else + Options.erase(Options.begin()+i--); // Erase duplicate + } if (ProgramOverview) cerr << "OVERVIEW:" << ProgramOverview << "\n"; - // TODO: Sort options by some criteria - cerr << "USAGE: " << ProgramName << " [options]\n\n"; - // TODO: print usage nicer + cerr << "USAGE: " << ProgramName << " [options]"; + + // Print out the positional options... + vector &PosOpts = getPositionalOpts(); + Option *CAOpt = 0; // The cl::ConsumeAfter option, if it exists... + if (!PosOpts.empty() && PosOpts[0]->getNumOccurancesFlag() == ConsumeAfter) + CAOpt = PosOpts[0]; + + for (unsigned i = CAOpt != 0, e = PosOpts.size(); i != e; ++i) { + cerr << " " << PosOpts[i]->HelpStr; + switch (PosOpts[i]->getNumOccurancesFlag()) { + case Optional: cerr << "?"; break; + case ZeroOrMore: cerr << "*"; break; + case Required: break; + case OneOrMore: cerr << "+"; break; + case ConsumeAfter: + default: + assert(0 && "Unknown NumOccurances Flag Value!"); + } + } + + // Print the consume after option info if it exists... + if (CAOpt) cerr << " " << CAOpt->HelpStr; + + cerr << "\n\n"; // Compute the maximum argument length... MaxArgLen = 0; - for_each(Options.begin(), Options.end(), - bind_obj(this, &Help::getMaxArgLen)); + for (unsigned i = 0, e = Options.size(); i != e; ++i) + MaxArgLen = std::max(MaxArgLen, Options[i].second->getOptionWidth()); cerr << "OPTIONS:\n"; - for_each(Options.begin(), Options.end(), - bind_obj(this, &Help::printOption)); + for (unsigned i = 0, e = Options.size(); i != e; ++i) + Options[i].second->printOptionInfo(MaxArgLen); - return true; // Displaying help is cause to terminate the program - } - - void getMaxArgLen(pair OptPair) { - const Option *Opt = OptPair.second; - if (Opt->ArgStr[0] == 0) EmptyArg = Opt; // Capture the empty arg if exists - MaxArgLen = std::max(MaxArgLen, Opt->getOptionWidth()); - } - - void printOption(pair OptPair) { - const Option *Opt = OptPair.second; - Opt->printOptionInfo(MaxArgLen); - } - -public: - inline Help(const char *ArgVal, const char *HelpVal, bool showHidden) - : Option(ArgVal, HelpVal, showHidden ? Hidden : 0), ShowHidden(showHidden) { - EmptyArg = 0; + // Halt the program if help information is printed + exit(1); } }; -Help HelpOp("help", "display available options" - " (--help-hidden for more)", false); -Help HelpHiddenOpt("help-hidden", "display all available options", true); + + +// Define the two HelpPrinter instances that are used to print out help, or +// help-hidden... +// +HelpPrinter NormalPrinter(false); +HelpPrinter HiddenPrinter(true); + +cl::opt > +HOp("help", cl::desc("display available options (--help-hidden for more)"), + cl::location(NormalPrinter)); + +cl::opt > +HHOp("help-hidden", cl::desc("display all available options"), + cl::location(HiddenPrinter), cl::Hidden); } // End anonymous namespace diff --git a/support/lib/Support/CommandLine.cpp b/support/lib/Support/CommandLine.cpp index c3f18bd1528..d11fbd7119e 100644 --- a/support/lib/Support/CommandLine.cpp +++ b/support/lib/Support/CommandLine.cpp @@ -23,6 +23,10 @@ using std::vector; using std::string; using std::cerr; +//===----------------------------------------------------------------------===// +// Basic, shared command line option processing machinery... +// + // Return the global command line option vector. Making it a function scoped // static ensures that it will be initialized correctly before its first use. // @@ -31,6 +35,11 @@ static map &getOpts() { return CommandLineOptions; } +static vector &getPositionalOpts() { + static vector Positional; + return Positional; +} + static void AddArgument(const string &ArgName, Option *Opt) { if (getOpts().find(ArgName) != getOpts().end()) { cerr << "CommandLine Error: Argument '" << ArgName @@ -72,46 +81,153 @@ static inline bool ProvideOption(Option *Handler, const char *ArgName, return Handler->addOccurance(ArgName, Value); } -// ValueGroupedArgs - Return true if the specified string is valid as a group -// of single letter arguments stuck together like the 'ls -la' case. -// -static inline bool ValidGroupedArgs(string Args) { - for (unsigned i = 0; i < Args.size(); ++i) { - map::iterator I = getOpts().find(string(1, Args[i])); - if (I == getOpts().end()) return false; // Make sure option exists +static bool ProvidePositionalOption(Option *Handler, string &Arg) { + int Dummy; + return ProvideOption(Handler, "", Arg.c_str(), 0, 0, Dummy); +} - // Grouped arguments have no value specified, make sure that if this option - // exists that it can accept no argument. - // - switch (I->second->getValueExpectedFlag()) { - case ValueDisallowed: - case ValueOptional: break; - default: return false; - } + +// Option predicates... +static inline bool isGrouping(const Option *O) { + return O->getFormattingFlag() == cl::Grouping; +} +static inline bool isPrefixedOrGrouping(const Option *O) { + return isGrouping(O) || O->getFormattingFlag() == cl::Prefix; +} + +// getOptionPred - Check to see if there are any options that satisfy the +// specified predicate with names that are the prefixes in Name. This is +// checked by progressively stripping characters off of the name, checking to +// see if there options that satisfy the predicate. If we find one, return it, +// otherwise return null. +// +static Option *getOptionPred(std::string Name, unsigned &Length, + bool (*Pred)(const Option*)) { + + map::iterator I = getOpts().find(Name); + if (I != getOpts().end() && Pred(I->second)) { + Length = Name.length(); + return I->second; } - return true; + if (Name.size() == 1) return 0; + do { + Name.erase(Name.end()-1, Name.end()); // Chop off the last character... + I = getOpts().find(Name); + + // Loop while we haven't found an option and Name still has at least two + // characters in it (so that the next iteration will not be the empty + // string... + } while ((I == getOpts().end() || !Pred(I->second)) && Name.size() > 1); + + if (I != getOpts().end() && Pred(I->second)) { + Length = Name.length(); + return I->second; // Found one! + } + return 0; // No option found! +} + +static bool RequiresValue(const Option *O) { + return O->getNumOccurancesFlag() == cl::Required || + O->getNumOccurancesFlag() == cl::OneOrMore; +} + +static bool EatsUnboundedNumberOfValues(const Option *O) { + return O->getNumOccurancesFlag() == cl::ZeroOrMore || + O->getNumOccurancesFlag() == cl::OneOrMore; } void cl::ParseCommandLineOptions(int &argc, char **argv, - const char *Overview = 0, int Flags = 0) { + const char *Overview = 0) { + assert((!getOpts().empty() || !getPositionalOpts().empty()) && + "No options specified, or ParseCommandLineOptions called more" + " than once!"); ProgramName = argv[0]; // Save this away safe and snug ProgramOverview = Overview; bool ErrorParsing = false; + map &Opts = getOpts(); + vector &PositionalOpts = getPositionalOpts(); + + // Check out the positional arguments to collect information about them. + unsigned NumPositionalRequired = 0; + Option *ConsumeAfterOpt = 0; + if (!PositionalOpts.empty()) { + if (PositionalOpts[0]->getNumOccurancesFlag() == cl::ConsumeAfter) { + assert(PositionalOpts.size() > 1 && + "Cannot specify cl::ConsumeAfter without a positional argument!"); + ConsumeAfterOpt = PositionalOpts[0]; + } + + // Calculate how many positional values are _required_. + bool UnboundedFound = false; + for (unsigned i = ConsumeAfterOpt != 0, e = PositionalOpts.size(); + i != e; ++i) { + Option *Opt = PositionalOpts[i]; + if (RequiresValue(Opt)) + ++NumPositionalRequired; + else if (ConsumeAfterOpt) { + // ConsumeAfter cannot be combined with "optional" positional options + ErrorParsing |= + Opt->error(" error - this positional option will never be matched, " + "because it does not Require a value, and a " + "cl::ConsumeAfter option is active!"); + } else if (UnboundedFound) { // This option does not "require" a value... + // Make sure this option is not specified after an option that eats all + // extra arguments, or this one will never get any! + // + ErrorParsing |= Opt->error(" error - option can never match, because " + "another positional argument will match an " + "unbounded number of values, and this option" + " does not require a value!"); + } + UnboundedFound |= EatsUnboundedNumberOfValues(Opt); + } + } + + // PositionalVals - A vector of "positional" arguments we accumulate into to + // processes at the end... + // + vector PositionalVals; + // Loop over all of the arguments... processing them. + bool DashDashFound = false; // Have we read '--'? for (int i = 1; i < argc; ++i) { Option *Handler = 0; const char *Value = ""; const char *ArgName = ""; - if (argv[i][0] != '-') { // Unnamed argument? - map::iterator I = getOpts().find(""); - Handler = I != getOpts().end() ? I->second : 0; - Value = argv[i]; - } else { // We start with a - or --, eat dashes + + // Check to see if this is a positional argument. This argument is + // considered to be positional if it doesn't start with '-', if it is "-" + // itself, or if we have see "--" already. + // + if (argv[i][0] != '-' || argv[i][1] == 0 || DashDashFound) { + // Positional argument! + if (!PositionalOpts.empty()) { + PositionalVals.push_back(argv[i]); + + // All of the positional arguments have been fulfulled, give the rest to + // the consume after option... if it's specified... + // + if (PositionalVals.size() == NumPositionalRequired && + ConsumeAfterOpt != 0) { + for (++i; i < argc; ++i) + PositionalVals.push_back(argv[i]); + break; // Handle outside of the argument processing loop... + } + + // Delay processing positional arguments until the end... + continue; + } + } else { // We start with a '-', must be an argument... ArgName = argv[i]+1; while (*ArgName == '-') ++ArgName; // Eat leading dashes + if (*ArgName == 0 && !DashDashFound) { // Is this the mythical "--"? + DashDashFound = true; // Yup, take note of that fact... + continue; // Don't try to process it as an argument iself. + } + const char *ArgNameEnd = ArgName; while (*ArgNameEnd && *ArgNameEnd != '=') ++ArgNameEnd; // Scan till end of argument name... @@ -123,46 +239,58 @@ void cl::ParseCommandLineOptions(int &argc, char **argv, if (*ArgName != 0) { string RealName(ArgName, ArgNameEnd); // Extract arg name part - map::iterator I = getOpts().find(RealName); + map::iterator I = Opts.find(RealName); - if (I == getOpts().end() && !*Value && RealName.size() > 1) { - // If grouping of single letter arguments is enabled, see if this is a - // legal grouping... - // - if (!(Flags & DisableSingleLetterArgGrouping) && - ValidGroupedArgs(RealName)) { + if (I == Opts.end() && !*Value && RealName.size() > 1) { + // Check to see if this "option" is really a prefixed or grouped + // argument... + // + unsigned Length = 0; + Option *PGOpt = getOptionPred(RealName, Length, isPrefixedOrGrouping); - for (unsigned i = 0; i < RealName.size(); ++i) { - char ArgName[2] = { 0, 0 }; int Dummy; - ArgName[0] = RealName[i]; - I = getOpts().find(ArgName); - assert(I != getOpts().end() && "ValidGroupedArgs failed!"); + // If the option is a prefixed option, then the value is simply the + // rest of the name... so fall through to later processing, by + // setting up the argument name flags and value fields. + // + if (PGOpt && PGOpt->getFormattingFlag() == cl::Prefix) { + ArgNameEnd = ArgName+Length; + Value = ArgNameEnd; + I = Opts.find(string(ArgName, ArgNameEnd)); + assert(I->second == PGOpt); + } else if (PGOpt) { + // This must be a grouped option... handle all of them now... + assert(isGrouping(PGOpt) && "Broken getOptionPred!"); + + do { + // Move current arg name out of RealName into RealArgName... + string RealArgName(RealName.begin(), RealName.begin()+Length); + RealName.erase(RealName.begin(), RealName.begin()+Length); // Because ValueRequired is an invalid flag for grouped arguments, // we don't need to pass argc/argv in... // - ErrorParsing |= ProvideOption(I->second, ArgName, "", - 0, 0, Dummy); - } - continue; - } else if (Flags & EnableSingleLetterArgValue) { - // Check to see if the first letter is a single letter argument that - // have a value that is equal to the rest of the string. If this - // is the case, recognize it now. (Example: -lfoo for a linker) - // - I = getOpts().find(string(1, RealName[0])); - if (I != getOpts().end()) { - // If we are successful, fall through to later processing, by - // setting up the argument name flags and value fields. - // - ArgNameEnd = ArgName+1; - Value = ArgNameEnd; - } - } + assert(PGOpt->getValueExpectedFlag() != cl::ValueRequired && + "Option can not be cl::Grouping AND cl::ValueRequired!"); + int Dummy; + ErrorParsing |= ProvideOption(PGOpt, RealArgName.c_str(), "", + 0, 0, Dummy); + + // Get the next grouping option... + if (!RealName.empty()) + PGOpt = getOptionPred(RealName, Length, isGrouping); + } while (!RealName.empty() && PGOpt); + + if (RealName.empty()) // Processed all of the options, move on + continue; // to the next argv[] value... + + // If RealName is not empty, that means we did not match one of the + // options! This is an error. + // + I = Opts.end(); + } } - - Handler = I != getOpts().end() ? I->second : 0; + Handler = I != Opts.end() ? I->second : 0; } } @@ -174,17 +302,63 @@ void cl::ParseCommandLineOptions(int &argc, char **argv, } ErrorParsing |= ProvideOption(Handler, ArgName, Value, argc, argv, i); + } - // If this option should consume all arguments that come after it... - if (Handler->getNumOccurancesFlag() == ConsumeAfter) { - for (++i; i < argc; ++i) - ErrorParsing |= ProvideOption(Handler, ArgName, argv[i], argc, argv, i); + // Check and handle positional arguments now... + if (NumPositionalRequired > PositionalVals.size()) { + cerr << "Not enough positional command line arguments specified!\n"; + cerr << "Must specify at least " << NumPositionalRequired + << " positional arguments: See: " << argv[0] << " --help\n"; + ErrorParsing = true; + + + } else if (ConsumeAfterOpt == 0) { + // Positional args have already been handled if ConsumeAfter is specified... + unsigned ValNo = 0, NumVals = PositionalVals.size(); + for (unsigned i = 0, e = PositionalOpts.size(); i != e; ++i) { + if (RequiresValue(PositionalOpts[i])) { + ProvidePositionalOption(PositionalOpts[i], PositionalVals[ValNo++]); + --NumPositionalRequired; // We fulfilled our duty... + } + + // If we _can_ give this option more arguments, do so now, as long as we + // do not give it values that others need. 'Done' controls whether the + // option even _WANTS_ any more. + // + bool Done = PositionalOpts[i]->getNumOccurancesFlag() == cl::Required; + while (NumVals-ValNo > NumPositionalRequired && !Done) { + switch (PositionalOpts[i]->getNumOccurancesFlag()) { + case cl::Optional: + Done = true; // Optional arguments want _at most_ one value + // FALL THROUGH + case cl::ZeroOrMore: // Zero or more will take all they can get... + case cl::OneOrMore: // One or more will take all they can get... + ProvidePositionalOption(PositionalOpts[i], PositionalVals[ValNo++]); + break; + default: + assert(0 && "Internal error, unexpected NumOccurances flag in " + "positional argument processing!"); + } + } } + } else { + assert(ConsumeAfterOpt && NumPositionalRequired <= PositionalVals.size()); + unsigned ValNo = 0; + for (unsigned j = 1, e = PositionalOpts.size(); j != e; ++j) + if (RequiresValue(PositionalOpts[j])) + ErrorParsing |= + ProvidePositionalOption(PositionalOpts[j], PositionalVals[ValNo++]); + + // Handle over all of the rest of the arguments to the + // cl::ConsumeAfter command line option... + for (; ValNo != PositionalVals.size(); ++ValNo) + ErrorParsing |= ProvidePositionalOption(ConsumeAfterOpt, + PositionalVals[ValNo]); } // Loop over args and make sure all required args are specified! - for (map::iterator I = getOpts().begin(), - E = getOpts().end(); I != E; ++I) { + for (map::iterator I = Opts.begin(), + E = Opts.end(); I != E; ++I) { switch (I->second->getNumOccurancesFlag()) { case Required: case OneOrMore: @@ -198,9 +372,10 @@ void cl::ParseCommandLineOptions(int &argc, char **argv, } } - // Free all of the memory allocated to the vector. Command line options may - // only be processed once! - getOpts().clear(); + // Free all of the memory allocated to the map. Command line options may only + // be processed once! + Opts.clear(); + PositionalOpts.clear(); // If we had an error processing our arguments, don't let the program execute if (ErrorParsing) exit(1); @@ -209,14 +384,14 @@ void cl::ParseCommandLineOptions(int &argc, char **argv, //===----------------------------------------------------------------------===// // Option Base class implementation // -Option::Option(const char *argStr, const char *helpStr, int flags) - : NumOccurances(0), Flags(flags), ArgStr(argStr), HelpStr(helpStr) { - AddArgument(ArgStr, this); -} bool Option::error(string Message, const char *ArgName = 0) { if (ArgName == 0) ArgName = ArgStr; - cerr << "-" << ArgName << " option" << Message << "\n"; + if (ArgName[0] == 0) + cerr << HelpStr; // Be nice for positional arguments + else + cerr << "-" << ArgName; + cerr << " option" << Message << "\n"; return true; } @@ -241,275 +416,303 @@ bool Option::addOccurance(const char *ArgName, const string &Value) { return handleOccurance(ArgName, Value); } +// addArgument - Tell the system that this Option subclass will handle all +// occurances of -ArgStr on the command line. +// +void Option::addArgument(const char *ArgStr) { + if (ArgStr[0]) + AddArgument(ArgStr, this); + else if (getFormattingFlag() == Positional) + getPositionalOpts().push_back(this); + else if (getNumOccurancesFlag() == ConsumeAfter) { + assert((getPositionalOpts().empty() || + getPositionalOpts().front()->getNumOccurancesFlag() != ConsumeAfter) + && "Cannot specify more than one option with cl::ConsumeAfter " + "specified!"); + getPositionalOpts().insert(getPositionalOpts().begin(), this); + } +} + + +// getValueStr - Get the value description string, using "DefaultMsg" if nothing +// has been specified yet. +// +static const char *getValueStr(const Option &O, const char *DefaultMsg) { + if (O.ValueStr[0] == 0) return DefaultMsg; + return O.ValueStr; +} + +//===----------------------------------------------------------------------===// +// cl::alias class implementation +// + // Return the width of the option tag for printing... -unsigned Option::getOptionWidth() const { +unsigned alias::getOptionWidth() const { return std::strlen(ArgStr)+6; } -void Option::printOptionInfo(unsigned GlobalWidth) const { +// Print out the option for the alias... +void alias::printOptionInfo(unsigned GlobalWidth) const { unsigned L = std::strlen(ArgStr); - if (L == 0) return; // Don't print the empty arg like this! cerr << " -" << ArgStr << string(GlobalWidth-L-6, ' ') << " - " << HelpStr << "\n"; } + //===----------------------------------------------------------------------===// -// Boolean/flag command line option implementation +// Parser Implementation code... // -bool Flag::handleOccurance(const char *ArgName, const string &Arg) { +// parser implementation +// +bool parser::parseImpl(Option &O, const string &Arg, bool &Value) { if (Arg == "" || Arg == "true" || Arg == "TRUE" || Arg == "True" || Arg == "1") { Value = true; } else if (Arg == "false" || Arg == "FALSE" || Arg == "False" || Arg == "0") { Value = false; } else { - return error(": '" + Arg + - "' is invalid value for boolean argument! Try 0 or 1"); + return O.error(": '" + Arg + + "' is invalid value for boolean argument! Try 0 or 1"); } - return false; } -//===----------------------------------------------------------------------===// -// Integer valued command line option implementation +// Return the width of the option tag for printing... +unsigned parser::getOptionWidth(const Option &O) const { + return std::strlen(O.ArgStr)+6; +} + +// printOptionInfo - Print out information about this option. The +// to-be-maintained width is specified. // -bool Int::handleOccurance(const char *ArgName, const string &Arg) { +void parser::printOptionInfo(const Option &O, unsigned GlobalWidth) const{ + unsigned L = std::strlen(O.ArgStr); + cerr << " -" << O.ArgStr << string(GlobalWidth-L-6, ' ') << " - " + << O.HelpStr << "\n"; +} + + + +// parser implementation +// +bool parser::parseImpl(Option &O, const string &Arg, int &Value) { const char *ArgStart = Arg.c_str(); char *End; Value = (int)strtol(ArgStart, &End, 0); if (*End != 0) - return error(": '" + Arg + "' value invalid for integer argument!"); - return false; -} - -//===----------------------------------------------------------------------===// -// String valued command line option implementation -// -bool String::handleOccurance(const char *ArgName, const string &Arg) { - *this = Arg; + return O.error(": '" + Arg + "' value invalid for integer argument!"); return false; } -//===----------------------------------------------------------------------===// -// StringList valued command line option implementation +// Return the width of the option tag for printing... +unsigned parser::getOptionWidth(const Option &O) const { + return std::strlen(O.ArgStr)+std::strlen(getValueStr(O, "int"))+9; +} + +// printOptionInfo - Print out information about this option. The +// to-be-maintained width is specified. // -bool StringList::handleOccurance(const char *ArgName, const string &Arg) { - push_back(Arg); +void parser::printOptionInfo(const Option &O, unsigned GlobalWidth) const{ + cerr << " -" << O.ArgStr << "=<" << getValueStr(O, "int") << ">" + << string(GlobalWidth-getOptionWidth(O), ' ') << " - " + << O.HelpStr << "\n"; +} + + +// parser implementation +// +bool parser::parseImpl(Option &O, const string &Arg, double &Value) { + const char *ArgStart = Arg.c_str(); + char *End; + Value = strtod(ArgStart, &End); + if (*End != 0) + return O.error(": '" +Arg+ "' value invalid for floating point argument!"); return false; } -//===----------------------------------------------------------------------===// -// Enum valued command line option implementation +// Return the width of the option tag for printing... +unsigned parser::getOptionWidth(const Option &O) const { + return std::strlen(O.ArgStr)+std::strlen(getValueStr(O, "number"))+9; +} + +// printOptionInfo - Print out information about this option. The +// to-be-maintained width is specified. // -void EnumBase::processValues(va_list Vals) { - while (const char *EnumName = va_arg(Vals, const char *)) { - int EnumVal = va_arg(Vals, int); - const char *EnumDesc = va_arg(Vals, const char *); - ValueMap.push_back(std::make_pair(EnumName, // Add value to value map - std::make_pair(EnumVal, EnumDesc))); +void parser::printOptionInfo(const Option &O, + unsigned GlobalWidth) const{ + cerr << " -" << O.ArgStr << "=<" << getValueStr(O, "number") << ">" + << string(GlobalWidth-getOptionWidth(O), ' ') + << " - " << O.HelpStr << "\n"; +} + + +// parser implementation +// + +// Return the width of the option tag for printing... +unsigned parser::getOptionWidth(const Option &O) const { + return std::strlen(O.ArgStr)+std::strlen(getValueStr(O, "string"))+9; +} + +// printOptionInfo - Print out information about this option. The +// to-be-maintained width is specified. +// +void parser::printOptionInfo(const Option &O, + unsigned GlobalWidth) const{ + cerr << " -" << O.ArgStr << " <" << getValueStr(O, "string") << ">" + << string(GlobalWidth-getOptionWidth(O), ' ') + << " - " << O.HelpStr << "\n"; +} + +// generic_parser_base implementation +// + +// Return the width of the option tag for printing... +unsigned generic_parser_base::getOptionWidth(const Option &O) const { + if (O.hasArgStr()) { + unsigned Size = std::strlen(O.ArgStr)+6; + for (unsigned i = 0, e = getNumOptions(); i != e; ++i) + Size = std::max(Size, (unsigned)std::strlen(getOption(i))+8); + return Size; + } else { + unsigned BaseSize = 0; + for (unsigned i = 0, e = getNumOptions(); i != e; ++i) + BaseSize = std::max(BaseSize, (unsigned)std::strlen(getOption(i))+8); + return BaseSize; } } -// registerArgs - notify the system about these new arguments -void EnumBase::registerArgs() { - for (unsigned i = 0; i < ValueMap.size(); ++i) - AddArgument(ValueMap[i].first, this); -} +// printOptionInfo - Print out information about this option. The +// to-be-maintained width is specified. +// +void generic_parser_base::printOptionInfo(const Option &O, + unsigned GlobalWidth) const { + if (O.hasArgStr()) { + unsigned L = std::strlen(O.ArgStr); + cerr << " -" << O.ArgStr << string(GlobalWidth-L-6, ' ') + << " - " << O.HelpStr << "\n"; -const char *EnumBase::getArgName(int ID) const { - for (unsigned i = 0; i < ValueMap.size(); ++i) - if (ID == ValueMap[i].second.first) return ValueMap[i].first; - return ""; -} -const char *EnumBase::getArgDescription(int ID) const { - for (unsigned i = 0; i < ValueMap.size(); ++i) - if (ID == ValueMap[i].second.first) return ValueMap[i].second.second; - return ""; -} - - - -bool EnumValueBase::handleOccurance(const char *ArgName, const string &Arg) { - unsigned i; - for (i = 0; i < ValueMap.size(); ++i) - if (ValueMap[i].first == Arg) break; - - if (i == ValueMap.size()) { - string Alternatives; - for (i = 0; i < ValueMap.size(); ++i) { - if (i) Alternatives += ", "; - Alternatives += ValueMap[i].first; + for (unsigned i = 0, e = getNumOptions(); i != e; ++i) { + unsigned NumSpaces = GlobalWidth-strlen(getOption(i))-8; + cerr << " =" << getOption(i) << string(NumSpaces, ' ') << " - " + << getDescription(i) << "\n"; + } + } else { + if (O.HelpStr[0]) + cerr << " " << O.HelpStr << "\n"; + for (unsigned i = 0, e = getNumOptions(); i != e; ++i) { + unsigned L = std::strlen(getOption(i)); + cerr << " -" << getOption(i) << string(GlobalWidth-L-8, ' ') << " - " + << getDescription(i) << "\n"; } - - return error(": unrecognized alternative '" + Arg + - "'! Alternatives are: " + Alternatives); - } - setValue(ValueMap[i].second.first); - return false; -} - -// Return the width of the option tag for printing... -unsigned EnumValueBase::getOptionWidth() const { - unsigned BaseSize = Option::getOptionWidth(); - for (unsigned i = 0; i < ValueMap.size(); ++i) - BaseSize = std::max(BaseSize, (unsigned)std::strlen(ValueMap[i].first)+8); - return BaseSize; -} - -// printOptionInfo - Print out information about this option. The -// to-be-maintained width is specified. -// -void EnumValueBase::printOptionInfo(unsigned GlobalWidth) const { - Option::printOptionInfo(GlobalWidth); - for (unsigned i = 0; i < ValueMap.size(); ++i) { - unsigned NumSpaces = GlobalWidth-strlen(ValueMap[i].first)-8; - cerr << " =" << ValueMap[i].first << string(NumSpaces, ' ') << " - " - << ValueMap[i].second.second; - - if (i == 0) cerr << " (default)"; - cerr << "\n"; - } -} - -//===----------------------------------------------------------------------===// -// Enum flags command line option implementation -// - -bool EnumFlagsBase::handleOccurance(const char *ArgName, const string &Arg) { - return EnumValueBase::handleOccurance("", ArgName); -} - -unsigned EnumFlagsBase::getOptionWidth() const { - unsigned BaseSize = 0; - for (unsigned i = 0; i < ValueMap.size(); ++i) - BaseSize = std::max(BaseSize, (unsigned)std::strlen(ValueMap[i].first)+6); - return BaseSize; -} - -void EnumFlagsBase::printOptionInfo(unsigned GlobalWidth) const { - for (unsigned i = 0; i < ValueMap.size(); ++i) { - unsigned L = std::strlen(ValueMap[i].first); - cerr << " -" << ValueMap[i].first << string(GlobalWidth-L-6, ' ') << " - " - << ValueMap[i].second.second; - if (i == 0) cerr << " (default)"; - cerr << "\n"; } } //===----------------------------------------------------------------------===// -// Enum list command line option implementation -// - -bool EnumListBase::handleOccurance(const char *ArgName, const string &Arg) { - unsigned i; - for (i = 0; i < ValueMap.size(); ++i) - if (ValueMap[i].first == string(ArgName)) break; - if (i == ValueMap.size()) - return error(": CommandLine INTERNAL ERROR", ArgName); - Values.push_back(ValueMap[i].second.first); - return false; -} - -// Return the width of the option tag for printing... -unsigned EnumListBase::getOptionWidth() const { - unsigned BaseSize = 0; - for (unsigned i = 0; i < ValueMap.size(); ++i) - BaseSize = std::max(BaseSize, (unsigned)std::strlen(ValueMap[i].first)+6); - return BaseSize; -} - - -// printOptionInfo - Print out information about this option. The -// to-be-maintained width is specified. -// -void EnumListBase::printOptionInfo(unsigned GlobalWidth) const { - for (unsigned i = 0; i < ValueMap.size(); ++i) { - unsigned L = std::strlen(ValueMap[i].first); - cerr << " -" << ValueMap[i].first << string(GlobalWidth-L-6, ' ') << " - " - << ValueMap[i].second.second << "\n"; - } -} - - -//===----------------------------------------------------------------------===// -// Help option... always automatically provided. +// --help and --help-hidden option implementation // namespace { -// isHidden/isReallyHidden - Predicates to be used to filter down arg lists. -inline bool isHidden(pair &OptPair) { - return OptPair.second->getOptionHiddenFlag() >= Hidden; -} -inline bool isReallyHidden(pair &OptPair) { - return OptPair.second->getOptionHiddenFlag() == ReallyHidden; -} - -class Help : public Option { +class HelpPrinter { unsigned MaxArgLen; const Option *EmptyArg; const bool ShowHidden; - virtual bool handleOccurance(const char *ArgName, const string &Arg) { + // isHidden/isReallyHidden - Predicates to be used to filter down arg lists. + inline static bool isHidden(pair &OptPair) { + return OptPair.second->getOptionHiddenFlag() >= Hidden; + } + inline static bool isReallyHidden(pair &OptPair) { + return OptPair.second->getOptionHiddenFlag() == ReallyHidden; + } + +public: + HelpPrinter(bool showHidden) : ShowHidden(showHidden) { + EmptyArg = 0; + } + + void operator=(bool Value) { + if (Value == false) return; + // Copy Options into a vector so we can sort them as we like... vector > Options; copy(getOpts().begin(), getOpts().end(), std::back_inserter(Options)); // Eliminate Hidden or ReallyHidden arguments, depending on ShowHidden - Options.erase(remove_if(Options.begin(), Options.end(), - std::ptr_fun(ShowHidden ? isReallyHidden : isHidden)), + Options.erase(std::remove_if(Options.begin(), Options.end(), + std::ptr_fun(ShowHidden ? isReallyHidden : isHidden)), Options.end()); // Eliminate duplicate entries in table (from enum flags options, f.e.) - std::set OptionSet; - for (unsigned i = 0; i < Options.size(); ) - if (OptionSet.count(Options[i].second) == 0) - OptionSet.insert(Options[i++].second); // Add to set - else - Options.erase(Options.begin()+i); // Erase duplicate - + { // Give OptionSet a scope + std::set OptionSet; + for (unsigned i = 0; i != Options.size(); ++i) + if (OptionSet.count(Options[i].second) == 0) + OptionSet.insert(Options[i].second); // Add new entry to set + else + Options.erase(Options.begin()+i--); // Erase duplicate + } if (ProgramOverview) cerr << "OVERVIEW:" << ProgramOverview << "\n"; - // TODO: Sort options by some criteria - cerr << "USAGE: " << ProgramName << " [options]\n\n"; - // TODO: print usage nicer + cerr << "USAGE: " << ProgramName << " [options]"; + + // Print out the positional options... + vector &PosOpts = getPositionalOpts(); + Option *CAOpt = 0; // The cl::ConsumeAfter option, if it exists... + if (!PosOpts.empty() && PosOpts[0]->getNumOccurancesFlag() == ConsumeAfter) + CAOpt = PosOpts[0]; + + for (unsigned i = CAOpt != 0, e = PosOpts.size(); i != e; ++i) { + cerr << " " << PosOpts[i]->HelpStr; + switch (PosOpts[i]->getNumOccurancesFlag()) { + case Optional: cerr << "?"; break; + case ZeroOrMore: cerr << "*"; break; + case Required: break; + case OneOrMore: cerr << "+"; break; + case ConsumeAfter: + default: + assert(0 && "Unknown NumOccurances Flag Value!"); + } + } + + // Print the consume after option info if it exists... + if (CAOpt) cerr << " " << CAOpt->HelpStr; + + cerr << "\n\n"; // Compute the maximum argument length... MaxArgLen = 0; - for_each(Options.begin(), Options.end(), - bind_obj(this, &Help::getMaxArgLen)); + for (unsigned i = 0, e = Options.size(); i != e; ++i) + MaxArgLen = std::max(MaxArgLen, Options[i].second->getOptionWidth()); cerr << "OPTIONS:\n"; - for_each(Options.begin(), Options.end(), - bind_obj(this, &Help::printOption)); + for (unsigned i = 0, e = Options.size(); i != e; ++i) + Options[i].second->printOptionInfo(MaxArgLen); - return true; // Displaying help is cause to terminate the program - } - - void getMaxArgLen(pair OptPair) { - const Option *Opt = OptPair.second; - if (Opt->ArgStr[0] == 0) EmptyArg = Opt; // Capture the empty arg if exists - MaxArgLen = std::max(MaxArgLen, Opt->getOptionWidth()); - } - - void printOption(pair OptPair) { - const Option *Opt = OptPair.second; - Opt->printOptionInfo(MaxArgLen); - } - -public: - inline Help(const char *ArgVal, const char *HelpVal, bool showHidden) - : Option(ArgVal, HelpVal, showHidden ? Hidden : 0), ShowHidden(showHidden) { - EmptyArg = 0; + // Halt the program if help information is printed + exit(1); } }; -Help HelpOp("help", "display available options" - " (--help-hidden for more)", false); -Help HelpHiddenOpt("help-hidden", "display all available options", true); + + +// Define the two HelpPrinter instances that are used to print out help, or +// help-hidden... +// +HelpPrinter NormalPrinter(false); +HelpPrinter HiddenPrinter(true); + +cl::opt > +HOp("help", cl::desc("display available options (--help-hidden for more)"), + cl::location(NormalPrinter)); + +cl::opt > +HHOp("help-hidden", cl::desc("display all available options"), + cl::location(HiddenPrinter), cl::Hidden); } // End anonymous namespace