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