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