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