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 + "' is invalid value for boolean argument! Try 0 or 1"); 189 } 190 191 return false; 192 } 193 194 //===----------------------------------------------------------------------===// 195 // Integer valued command line option implementation 196 // 197 bool Int::handleOccurance(const char *ArgName, const string &Arg) { 198 const char *ArgStart = Arg.c_str(); 199 char *End; 200 Value = (int)strtol(ArgStart, &End, 0); 201 if (*End != 0) 202 return error(": '" + Arg + "' value invalid for integer argument!"); 203 return false; 204 } 205 206 //===----------------------------------------------------------------------===// 207 // String valued command line option implementation 208 // 209 bool String::handleOccurance(const char *ArgName, const string &Arg) { 210 *this = Arg; 211 return false; 212 } 213 214 //===----------------------------------------------------------------------===// 215 // Enum valued command line option implementation 216 // 217 void EnumBase::processValues(va_list Vals) { 218 while (const char *EnumName = va_arg(Vals, const char *)) { 219 int EnumVal = va_arg(Vals, int); 220 const char *EnumDesc = va_arg(Vals, const char *); 221 ValueMap.push_back(make_pair(EnumName, // Add value to value map 222 make_pair(EnumVal, EnumDesc))); 223 } 224 } 225 226 // registerArgs - notify the system about these new arguments 227 void EnumBase::registerArgs() { 228 for (unsigned i = 0; i < ValueMap.size(); ++i) 229 AddArgument(ValueMap[i].first, this); 230 } 231 232 const char *EnumBase::getArgName(int ID) const { 233 for (unsigned i = 0; i < ValueMap.size(); ++i) 234 if (ID == ValueMap[i].second.first) return ValueMap[i].first; 235 return ""; 236 } 237 const char *EnumBase::getArgDescription(int ID) const { 238 for (unsigned i = 0; i < ValueMap.size(); ++i) 239 if (ID == ValueMap[i].second.first) return ValueMap[i].second.second; 240 return ""; 241 } 242 243 244 245 bool EnumValueBase::handleOccurance(const char *ArgName, const string &Arg) { 246 unsigned i; 247 for (i = 0; i < ValueMap.size(); ++i) 248 if (ValueMap[i].first == Arg) break; 249 if (i == ValueMap.size()) 250 return error(": unrecognized alternative '"+Arg+"'!"); 251 Value = ValueMap[i].second.first; 252 return false; 253 } 254 255 // Return the width of the option tag for printing... 256 unsigned EnumValueBase::getOptionWidth() const { 257 unsigned BaseSize = Option::getOptionWidth(); 258 for (unsigned i = 0; i < ValueMap.size(); ++i) 259 BaseSize = max(BaseSize, std::strlen(ValueMap[i].first)+8); 260 return BaseSize; 261 } 262 263 // printOptionInfo - Print out information about this option. The 264 // to-be-maintained width is specified. 265 // 266 void EnumValueBase::printOptionInfo(unsigned GlobalWidth) const { 267 Option::printOptionInfo(GlobalWidth); 268 for (unsigned i = 0; i < ValueMap.size(); ++i) { 269 unsigned NumSpaces = GlobalWidth-strlen(ValueMap[i].first)-8; 270 cerr << " =" << ValueMap[i].first << string(NumSpaces, ' ') << " - " 271 << ValueMap[i].second.second; 272 273 if (i == 0) cerr << " (default)"; 274 cerr << endl; 275 } 276 } 277 278 //===----------------------------------------------------------------------===// 279 // Enum flags command line option implementation 280 // 281 282 bool EnumFlagsBase::handleOccurance(const char *ArgName, const string &Arg) { 283 return EnumValueBase::handleOccurance("", ArgName); 284 } 285 286 unsigned EnumFlagsBase::getOptionWidth() const { 287 unsigned BaseSize = 0; 288 for (unsigned i = 0; i < ValueMap.size(); ++i) 289 BaseSize = max(BaseSize, std::strlen(ValueMap[i].first)+6); 290 return BaseSize; 291 } 292 293 void EnumFlagsBase::printOptionInfo(unsigned GlobalWidth) const { 294 for (unsigned i = 0; i < ValueMap.size(); ++i) { 295 unsigned L = std::strlen(ValueMap[i].first); 296 cerr << " -" << ValueMap[i].first << string(GlobalWidth-L-6, ' ') << " - " 297 << ValueMap[i].second.second; 298 if (i == 0) cerr << " (default)"; 299 cerr << endl; 300 } 301 } 302 303 304 //===----------------------------------------------------------------------===// 305 // Enum list command line option implementation 306 // 307 308 bool EnumListBase::handleOccurance(const char *ArgName, const string &Arg) { 309 unsigned i; 310 for (i = 0; i < ValueMap.size(); ++i) 311 if (ValueMap[i].first == string(ArgName)) break; 312 if (i == ValueMap.size()) 313 return error(": CommandLine INTERNAL ERROR", ArgName); 314 Values.push_back(ValueMap[i].second.first); 315 return false; 316 } 317 318 // Return the width of the option tag for printing... 319 unsigned EnumListBase::getOptionWidth() const { 320 unsigned BaseSize = 0; 321 for (unsigned i = 0; i < ValueMap.size(); ++i) 322 BaseSize = max(BaseSize, std::strlen(ValueMap[i].first)+6); 323 return BaseSize; 324 } 325 326 327 // printOptionInfo - Print out information about this option. The 328 // to-be-maintained width is specified. 329 // 330 void EnumListBase::printOptionInfo(unsigned GlobalWidth) const { 331 for (unsigned i = 0; i < ValueMap.size(); ++i) { 332 unsigned L = std::strlen(ValueMap[i].first); 333 cerr << " -" << ValueMap[i].first << string(GlobalWidth-L-6, ' ') << " - " 334 << ValueMap[i].second.second << endl; 335 } 336 } 337 338 339 //===----------------------------------------------------------------------===// 340 // Help option... always automatically provided. 341 // 342 namespace { 343 344 // isHidden/isReallyHidden - Predicates to be used to filter down arg lists. 345 inline bool isHidden(pair<string, Option *> &OptPair) { 346 return OptPair.second->getOptionHiddenFlag() >= Hidden; 347 } 348 inline bool isReallyHidden(pair<string, Option *> &OptPair) { 349 return OptPair.second->getOptionHiddenFlag() == ReallyHidden; 350 } 351 352 class Help : public Option { 353 unsigned MaxArgLen; 354 const Option *EmptyArg; 355 const bool ShowHidden; 356 357 virtual bool handleOccurance(const char *ArgName, const string &Arg) { 358 // Copy Options into a vector so we can sort them as we like... 359 vector<pair<string, Option*> > Options; 360 copy(getOpts().begin(), getOpts().end(), back_inserter(Options)); 361 362 // Eliminate Hidden or ReallyHidden arguments, depending on ShowHidden 363 Options.erase(remove_if(Options.begin(), Options.end(), 364 ptr_fun(ShowHidden ? isReallyHidden : isHidden)), 365 Options.end()); 366 367 // Eliminate duplicate entries in table (from enum flags options, f.e.) 368 set<Option*> OptionSet; 369 for (unsigned i = 0; i < Options.size(); ) 370 if (OptionSet.count(Options[i].second) == 0) 371 OptionSet.insert(Options[i++].second); // Add to set 372 else 373 Options.erase(Options.begin()+i); // Erase duplicate 374 375 376 if (ProgramOverview) 377 cerr << "OVERVIEW:" << ProgramOverview << endl; 378 // TODO: Sort options by some criteria 379 380 cerr << "USAGE: " << ProgramName << " [options]\n\n"; 381 // TODO: print usage nicer 382 383 // Compute the maximum argument length... 384 MaxArgLen = 0; 385 for_each(Options.begin(), Options.end(), 386 bind_obj(this, &Help::getMaxArgLen)); 387 388 cerr << "OPTIONS:\n"; 389 for_each(Options.begin(), Options.end(), 390 bind_obj(this, &Help::printOption)); 391 392 return true; // Displaying help is cause to terminate the program 393 } 394 395 void getMaxArgLen(pair<string, Option *> OptPair) { 396 const Option *Opt = OptPair.second; 397 if (Opt->ArgStr[0] == 0) EmptyArg = Opt; // Capture the empty arg if exists 398 MaxArgLen = max(MaxArgLen, Opt->getOptionWidth()); 399 } 400 401 void printOption(pair<string, Option *> OptPair) { 402 const Option *Opt = OptPair.second; 403 Opt->printOptionInfo(MaxArgLen); 404 } 405 406 public: 407 inline Help(const char *ArgVal, const char *HelpVal, bool showHidden) 408 : Option(ArgVal, HelpVal, showHidden ? Hidden : 0), ShowHidden(showHidden) { 409 EmptyArg = 0; 410 } 411 }; 412 413 Help HelpOp("help", "display available options" 414 " (--help-hidden for more)", false); 415 Help HelpHiddenOpt("help-hidden", "display all available options", true); 416 417 } // End anonymous namespace 418