CommandLine.cpp revision f038acbee21cfed998451aedd00a81901d299516
1//===-- CommandLine.cpp - Command line parser implementation --------------===// 2// 3// This class implements a command line argument processor that is useful when 4// creating a tool. It provides a simple, minimalistic interface that is easily 5// extensible and supports nonlocal (library) command line options. 6// 7// Note that rather than trying to figure out what this code does, you could try 8// reading the library documentation located in docs/CommandLine.html 9// 10//===----------------------------------------------------------------------===// 11 12#include "llvm/Support/CommandLine.h" 13#include "llvm/Support/STLExtras.h" 14#include <vector> 15#include <algorithm> 16#include <map> 17#include <set> 18using namespace cl; 19 20// Return the global command line option vector. Making it a function scoped 21// static ensures that it will be initialized before its first use correctly. 22// 23static map<string, Option*> &getOpts() { 24 static map<string,Option*> CommandLineOptions; 25 return CommandLineOptions; 26} 27 28static void AddArgument(const string &ArgName, Option *Opt) { 29 if (getOpts().find(ArgName) != getOpts().end()) { 30 cerr << "CommandLine Error: Argument '" << ArgName 31 << "' specified more than once!\n"; 32 } else { 33 getOpts()[ArgName] = Opt; // Add argument to the argument map! 34 } 35} 36 37static const char *ProgramName = 0; 38static const char *ProgramOverview = 0; 39 40void cl::ParseCommandLineOptions(int &argc, char **argv, 41 const char *Overview = 0) { 42 ProgramName = argv[0]; // Save this away safe and snug 43 ProgramOverview = Overview; 44 bool ErrorParsing = false; 45 46 // Loop over all of the arguments... processing them. 47 for (int i = 1; i < argc; ++i) { 48 Option *Handler = 0; 49 const char *Value = ""; 50 const char *ArgName = ""; 51 if (argv[i][0] != '-') { // Unnamed argument? 52 map<string, Option*>::iterator I = getOpts().find(""); 53 Handler = I != getOpts().end() ? I->second : 0; 54 Value = argv[i]; 55 } else { // We start with a - or --, eat dashes 56 ArgName = argv[i]+1; 57 while (*ArgName == '-') ++ArgName; // Eat leading dashes 58 59 const char *ArgNameEnd = ArgName; 60 while (*ArgNameEnd && *ArgNameEnd != '=' && 61 *ArgNameEnd != '/') ++ArgNameEnd; // Scan till end 62 63 Value = ArgNameEnd; 64 if (*Value) // If we have an equals sign... 65 ++Value; // Advance to value... 66 67 if (*ArgName != 0) { 68 // Extract arg name part 69 map<string, Option*>::iterator I = getOpts().find(string(ArgName, ArgNameEnd)); 70 Handler = I != getOpts().end() ? I->second : 0; 71 } 72 } 73 74 if (Handler == 0) { 75 cerr << "Unknown command line argument '" << argv[i] << "'. Try: " 76 << argv[0] << " --help'\n"; 77 ErrorParsing = true; 78 continue; 79 } 80 81 // Enforce value requirements 82 switch (Handler->getValueExpectedFlag()) { 83 case ValueRequired: 84 if (Value == 0 || *Value == 0) { // No value specified? 85 if (i+1 < argc) { // Steal the next argument, like for '-o filename' 86 Value = argv[++i]; 87 } else { 88 ErrorParsing = Handler->error(" requires a value!"); 89 continue; 90 } 91 } 92 break; 93 case ValueDisallowed: 94 if (*Value != 0) { 95 ErrorParsing = Handler->error(" does not allow a value! '" + 96 string(Value) + "' specified."); 97 continue; 98 } 99 break; 100 case ValueOptional: break; 101 default: cerr << "Bad ValueMask flag! CommandLine usage error:" 102 << Handler->getValueExpectedFlag() << endl; abort(); 103 } 104 105 // Run the handler now! 106 ErrorParsing |= Handler->addOccurance(ArgName, Value); 107 } 108 109 // Loop over args and make sure all required args are specified! 110 for (map<string, Option*>::iterator I = getOpts().begin(), 111 E = getOpts().end(); I != E; ++I) { 112 switch (I->second->getNumOccurancesFlag()) { 113 case Required: 114 case OneOrMore: 115 if (I->second->getNumOccurances() == 0) { 116 I->second->error(" must be specified at least once!"); 117 ErrorParsing = true; 118 } 119 // Fall through 120 default: 121 break; 122 } 123 } 124 125 // Free all of the memory allocated to the vector. Command line options may 126 // only be processed once! 127 getOpts().clear(); 128 129 // If we had an error processing our arguments, don't let the program execute 130 if (ErrorParsing) exit(1); 131} 132 133//===----------------------------------------------------------------------===// 134// Option Base class implementation 135// 136Option::Option(const char *argStr, const char *helpStr, int flags) 137 : NumOccurances(0), Flags(flags), ArgStr(argStr), HelpStr(helpStr) { 138 AddArgument(ArgStr, this); 139} 140 141bool Option::error(string Message, const char *ArgName = 0) { 142 if (ArgName == 0) ArgName = ArgStr; 143 cerr << "-" << ArgName << " option" << Message << endl; 144 return true; 145} 146 147bool Option::addOccurance(const char *ArgName, const string &Value) { 148 NumOccurances++; // Increment the number of times we have been seen 149 150 switch (getNumOccurancesFlag()) { 151 case Optional: 152 if (NumOccurances > 1) 153 return error(": may only occur zero or one times!", ArgName); 154 break; 155 case Required: 156 if (NumOccurances > 1) 157 return error(": must occur exactly one time!", ArgName); 158 // Fall through 159 case OneOrMore: 160 case ZeroOrMore: break; 161 default: return error(": bad num occurances flag value!"); 162 } 163 164 return handleOccurance(ArgName, Value); 165} 166 167// Return the width of the option tag for printing... 168unsigned Option::getOptionWidth() const { 169 return std::strlen(ArgStr)+6; 170} 171 172void Option::printOptionInfo(unsigned GlobalWidth) const { 173 unsigned L = std::strlen(ArgStr); 174 if (L == 0) return; // Don't print the empty arg like this! 175 cerr << " -" << ArgStr << string(GlobalWidth-L-6, ' ') << " - " 176 << HelpStr << endl; 177} 178 179 180//===----------------------------------------------------------------------===// 181// Boolean/flag command line option implementation 182// 183 184bool Flag::handleOccurance(const char *ArgName, const string &Arg) { 185 if (Arg == "" || Arg == "true" || Arg == "TRUE" || Arg == "True" || 186 Arg == "1") { 187 Value = true; 188 } else if (Arg == "false" || Arg == "FALSE" || Arg == "False" || Arg == "0") { 189 Value = false; 190 } else { 191 return error(": '" + Arg + 192 "' is invalid value for boolean argument! Try 0 or 1"); 193 } 194 195 return false; 196} 197 198//===----------------------------------------------------------------------===// 199// Integer valued command line option implementation 200// 201bool Int::handleOccurance(const char *ArgName, const string &Arg) { 202 const char *ArgStart = Arg.c_str(); 203 char *End; 204 Value = (int)strtol(ArgStart, &End, 0); 205 if (*End != 0) 206 return error(": '" + Arg + "' value invalid for integer argument!"); 207 return false; 208} 209 210//===----------------------------------------------------------------------===// 211// String valued command line option implementation 212// 213bool String::handleOccurance(const char *ArgName, const string &Arg) { 214 *this = Arg; 215 return false; 216} 217 218//===----------------------------------------------------------------------===// 219// StringList valued command line option implementation 220// 221bool StringList::handleOccurance(const char *ArgName, const string &Arg) { 222 Values.push_back(Arg); 223 return false; 224} 225 226//===----------------------------------------------------------------------===// 227// Enum valued command line option implementation 228// 229void EnumBase::processValues(va_list Vals) { 230 while (const char *EnumName = va_arg(Vals, const char *)) { 231 int EnumVal = va_arg(Vals, int); 232 const char *EnumDesc = va_arg(Vals, const char *); 233 ValueMap.push_back(make_pair(EnumName, // Add value to value map 234 make_pair(EnumVal, EnumDesc))); 235 } 236} 237 238// registerArgs - notify the system about these new arguments 239void EnumBase::registerArgs() { 240 for (unsigned i = 0; i < ValueMap.size(); ++i) 241 AddArgument(ValueMap[i].first, this); 242} 243 244const char *EnumBase::getArgName(int ID) const { 245 for (unsigned i = 0; i < ValueMap.size(); ++i) 246 if (ID == ValueMap[i].second.first) return ValueMap[i].first; 247 return ""; 248} 249const char *EnumBase::getArgDescription(int ID) const { 250 for (unsigned i = 0; i < ValueMap.size(); ++i) 251 if (ID == ValueMap[i].second.first) return ValueMap[i].second.second; 252 return ""; 253} 254 255 256 257bool EnumValueBase::handleOccurance(const char *ArgName, const string &Arg) { 258 unsigned i; 259 for (i = 0; i < ValueMap.size(); ++i) 260 if (ValueMap[i].first == Arg) break; 261 if (i == ValueMap.size()) 262 return error(": unrecognized alternative '"+Arg+"'!"); 263 Value = ValueMap[i].second.first; 264 return false; 265} 266 267// Return the width of the option tag for printing... 268unsigned EnumValueBase::getOptionWidth() const { 269 unsigned BaseSize = Option::getOptionWidth(); 270 for (unsigned i = 0; i < ValueMap.size(); ++i) 271 BaseSize = max(BaseSize, std::strlen(ValueMap[i].first)+8); 272 return BaseSize; 273} 274 275// printOptionInfo - Print out information about this option. The 276// to-be-maintained width is specified. 277// 278void EnumValueBase::printOptionInfo(unsigned GlobalWidth) const { 279 Option::printOptionInfo(GlobalWidth); 280 for (unsigned i = 0; i < ValueMap.size(); ++i) { 281 unsigned NumSpaces = GlobalWidth-strlen(ValueMap[i].first)-8; 282 cerr << " =" << ValueMap[i].first << string(NumSpaces, ' ') << " - " 283 << ValueMap[i].second.second; 284 285 if (i == 0) cerr << " (default)"; 286 cerr << endl; 287 } 288} 289 290//===----------------------------------------------------------------------===// 291// Enum flags command line option implementation 292// 293 294bool EnumFlagsBase::handleOccurance(const char *ArgName, const string &Arg) { 295 return EnumValueBase::handleOccurance("", ArgName); 296} 297 298unsigned EnumFlagsBase::getOptionWidth() const { 299 unsigned BaseSize = 0; 300 for (unsigned i = 0; i < ValueMap.size(); ++i) 301 BaseSize = max(BaseSize, std::strlen(ValueMap[i].first)+6); 302 return BaseSize; 303} 304 305void EnumFlagsBase::printOptionInfo(unsigned GlobalWidth) const { 306 for (unsigned i = 0; i < ValueMap.size(); ++i) { 307 unsigned L = std::strlen(ValueMap[i].first); 308 cerr << " -" << ValueMap[i].first << string(GlobalWidth-L-6, ' ') << " - " 309 << ValueMap[i].second.second; 310 if (i == 0) cerr << " (default)"; 311 cerr << endl; 312 } 313} 314 315 316//===----------------------------------------------------------------------===// 317// Enum list command line option implementation 318// 319 320bool EnumListBase::handleOccurance(const char *ArgName, const string &Arg) { 321 unsigned i; 322 for (i = 0; i < ValueMap.size(); ++i) 323 if (ValueMap[i].first == string(ArgName)) break; 324 if (i == ValueMap.size()) 325 return error(": CommandLine INTERNAL ERROR", ArgName); 326 Values.push_back(ValueMap[i].second.first); 327 return false; 328} 329 330// Return the width of the option tag for printing... 331unsigned EnumListBase::getOptionWidth() const { 332 unsigned BaseSize = 0; 333 for (unsigned i = 0; i < ValueMap.size(); ++i) 334 BaseSize = max(BaseSize, std::strlen(ValueMap[i].first)+6); 335 return BaseSize; 336} 337 338 339// printOptionInfo - Print out information about this option. The 340// to-be-maintained width is specified. 341// 342void EnumListBase::printOptionInfo(unsigned GlobalWidth) const { 343 for (unsigned i = 0; i < ValueMap.size(); ++i) { 344 unsigned L = std::strlen(ValueMap[i].first); 345 cerr << " -" << ValueMap[i].first << string(GlobalWidth-L-6, ' ') << " - " 346 << ValueMap[i].second.second << endl; 347 } 348} 349 350 351//===----------------------------------------------------------------------===// 352// Help option... always automatically provided. 353// 354namespace { 355 356// isHidden/isReallyHidden - Predicates to be used to filter down arg lists. 357inline bool isHidden(pair<string, Option *> &OptPair) { 358 return OptPair.second->getOptionHiddenFlag() >= Hidden; 359} 360inline bool isReallyHidden(pair<string, Option *> &OptPair) { 361 return OptPair.second->getOptionHiddenFlag() == ReallyHidden; 362} 363 364class Help : public Option { 365 unsigned MaxArgLen; 366 const Option *EmptyArg; 367 const bool ShowHidden; 368 369 virtual bool handleOccurance(const char *ArgName, const string &Arg) { 370 // Copy Options into a vector so we can sort them as we like... 371 vector<pair<string, Option*> > Options; 372 copy(getOpts().begin(), getOpts().end(), back_inserter(Options)); 373 374 // Eliminate Hidden or ReallyHidden arguments, depending on ShowHidden 375 Options.erase(remove_if(Options.begin(), Options.end(), 376 ptr_fun(ShowHidden ? isReallyHidden : isHidden)), 377 Options.end()); 378 379 // Eliminate duplicate entries in table (from enum flags options, f.e.) 380 set<Option*> OptionSet; 381 for (unsigned i = 0; i < Options.size(); ) 382 if (OptionSet.count(Options[i].second) == 0) 383 OptionSet.insert(Options[i++].second); // Add to set 384 else 385 Options.erase(Options.begin()+i); // Erase duplicate 386 387 388 if (ProgramOverview) 389 cerr << "OVERVIEW:" << ProgramOverview << endl; 390 // TODO: Sort options by some criteria 391 392 cerr << "USAGE: " << ProgramName << " [options]\n\n"; 393 // TODO: print usage nicer 394 395 // Compute the maximum argument length... 396 MaxArgLen = 0; 397 for_each(Options.begin(), Options.end(), 398 bind_obj(this, &Help::getMaxArgLen)); 399 400 cerr << "OPTIONS:\n"; 401 for_each(Options.begin(), Options.end(), 402 bind_obj(this, &Help::printOption)); 403 404 return true; // Displaying help is cause to terminate the program 405 } 406 407 void getMaxArgLen(pair<string, Option *> OptPair) { 408 const Option *Opt = OptPair.second; 409 if (Opt->ArgStr[0] == 0) EmptyArg = Opt; // Capture the empty arg if exists 410 MaxArgLen = max(MaxArgLen, Opt->getOptionWidth()); 411 } 412 413 void printOption(pair<string, Option *> OptPair) { 414 const Option *Opt = OptPair.second; 415 Opt->printOptionInfo(MaxArgLen); 416 } 417 418public: 419 inline Help(const char *ArgVal, const char *HelpVal, bool showHidden) 420 : Option(ArgVal, HelpVal, showHidden ? Hidden : 0), ShowHidden(showHidden) { 421 EmptyArg = 0; 422 } 423}; 424 425Help HelpOp("help", "display available options" 426 " (--help-hidden for more)", false); 427Help HelpHiddenOpt("help-hidden", "display all available options", true); 428 429} // End anonymous namespace 430