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