blob: f6938169daba1e3103f84a834fd9dce2e3322bb3 [file] [log] [blame]
Chris Lattnerdbab15a2001-07-23 17:17:47 +00001//===-- 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//
Chris Lattner03fe1bd2001-07-23 23:04:07 +00007// 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//
Chris Lattnerdbab15a2001-07-23 17:17:47 +000010//===----------------------------------------------------------------------===//
11
Chris Lattnercee8f9a2001-11-27 00:03:19 +000012#include "Support/CommandLine.h"
13#include "Support/STLExtras.h"
Chris Lattnerdbab15a2001-07-23 17:17:47 +000014#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
Chris Lattnerf78032f2001-11-26 18:58:34 +000021// static ensures that it will be initialized correctly before its first use.
Chris Lattnerdbab15a2001-07-23 17:17:47 +000022//
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 {
Chris Lattnerf78032f2001-11-26 18:58:34 +000033 // Add argument to the argument map!
34 getOpts().insert(make_pair(ArgName, Opt));
Chris Lattnerdbab15a2001-07-23 17:17:47 +000035 }
36}
37
38static const char *ProgramName = 0;
39static const char *ProgramOverview = 0;
40
Chris Lattnercaccd762001-10-27 05:54:17 +000041static 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
Chris Lattnerf78032f2001-11-26 18:58:34 +000069// 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//
72static 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}
Chris Lattnercaccd762001-10-27 05:54:17 +000089
Chris Lattnerdbab15a2001-07-23 17:17:47 +000090void cl::ParseCommandLineOptions(int &argc, char **argv,
Chris Lattnerf78032f2001-11-26 18:58:34 +000091 const char *Overview = 0, int Flags = 0) {
Chris Lattnerdbab15a2001-07-23 17:17:47 +000092 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?
Chris Lattner3805e4c2001-07-25 18:40:49 +0000102 map<string, Option*>::iterator I = getOpts().find("");
103 Handler = I != getOpts().end() ? I->second : 0;
Chris Lattnerdbab15a2001-07-23 17:17:47 +0000104 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;
Chris Lattnerf78032f2001-11-26 18:58:34 +0000110 while (*ArgNameEnd && *ArgNameEnd != '=')
111 ++ArgNameEnd; // Scan till end of argument name...
Chris Lattnerdbab15a2001-07-23 17:17:47 +0000112
113 Value = ArgNameEnd;
114 if (*Value) // If we have an equals sign...
115 ++Value; // Advance to value...
116
117 if (*ArgName != 0) {
Chris Lattnerf78032f2001-11-26 18:58:34 +0000118 string RealName(ArgName, ArgNameEnd);
Chris Lattner3805e4c2001-07-25 18:40:49 +0000119 // Extract arg name part
Chris Lattnerf78032f2001-11-26 18:58:34 +0000120 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
Chris Lattner3805e4c2001-07-25 18:40:49 +0000159 Handler = I != getOpts().end() ? I->second : 0;
Chris Lattnerdbab15a2001-07-23 17:17:47 +0000160 }
161 }
162
163 if (Handler == 0) {
164 cerr << "Unknown command line argument '" << argv[i] << "'. Try: "
Chris Lattnerf038acb2001-10-24 06:21:56 +0000165 << argv[0] << " --help'\n";
Chris Lattnerdbab15a2001-07-23 17:17:47 +0000166 ErrorParsing = true;
167 continue;
168 }
169
Chris Lattnercaccd762001-10-27 05:54:17 +0000170 ErrorParsing |= ProvideOption(Handler, ArgName, Value, argc, argv, i);
Chris Lattnerdbab15a2001-07-23 17:17:47 +0000171
Chris Lattnercaccd762001-10-27 05:54:17 +0000172 // 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 }
Chris Lattnerdbab15a2001-07-23 17:17:47 +0000177 }
178
Chris Lattnerdc4693d2001-07-23 23:02:45 +0000179 // 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:
Chris Lattnerf038acb2001-10-24 06:21:56 +0000185 if (I->second->getNumOccurances() == 0) {
Chris Lattnerdc4693d2001-07-23 23:02:45 +0000186 I->second->error(" must be specified at least once!");
Chris Lattnerf038acb2001-10-24 06:21:56 +0000187 ErrorParsing = true;
188 }
Chris Lattnerdc4693d2001-07-23 23:02:45 +0000189 // Fall through
190 default:
191 break;
192 }
193 }
Chris Lattnerdbab15a2001-07-23 17:17:47 +0000194
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//
206Option::Option(const char *argStr, const char *helpStr, int flags)
Chris Lattnerdc4693d2001-07-23 23:02:45 +0000207 : NumOccurances(0), Flags(flags), ArgStr(argStr), HelpStr(helpStr) {
Chris Lattnerdbab15a2001-07-23 17:17:47 +0000208 AddArgument(ArgStr, this);
209}
210
211bool 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
217bool Option::addOccurance(const char *ArgName, const string &Value) {
218 NumOccurances++; // Increment the number of times we have been seen
219
Chris Lattnerdc4693d2001-07-23 23:02:45 +0000220 switch (getNumOccurancesFlag()) {
Chris Lattnerdbab15a2001-07-23 17:17:47 +0000221 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:
Chris Lattnercaccd762001-10-27 05:54:17 +0000230 case ZeroOrMore:
231 case ConsumeAfter: break;
Chris Lattnerdbab15a2001-07-23 17:17:47 +0000232 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...
239unsigned Option::getOptionWidth() const {
240 return std::strlen(ArgStr)+6;
241}
242
243void 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
255bool 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 {
Chris Lattnerd215fd12001-10-13 06:53:19 +0000262 return error(": '" + Arg +
263 "' is invalid value for boolean argument! Try 0 or 1");
Chris Lattnerdbab15a2001-07-23 17:17:47 +0000264 }
265
266 return false;
267}
268
269//===----------------------------------------------------------------------===//
270// Integer valued command line option implementation
271//
272bool 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//
284bool String::handleOccurance(const char *ArgName, const string &Arg) {
Chris Lattner1e78f362001-07-23 19:27:24 +0000285 *this = Arg;
Chris Lattnerdbab15a2001-07-23 17:17:47 +0000286 return false;
287}
288
289//===----------------------------------------------------------------------===//
Chris Lattnerd215fd12001-10-13 06:53:19 +0000290// StringList valued command line option implementation
291//
292bool StringList::handleOccurance(const char *ArgName, const string &Arg) {
Chris Lattnercaccd762001-10-27 05:54:17 +0000293 push_back(Arg);
Chris Lattnerd215fd12001-10-13 06:53:19 +0000294 return false;
295}
296
297//===----------------------------------------------------------------------===//
Chris Lattnerdbab15a2001-07-23 17:17:47 +0000298// Enum valued command line option implementation
299//
300void 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
310void EnumBase::registerArgs() {
311 for (unsigned i = 0; i < ValueMap.size(); ++i)
312 AddArgument(ValueMap[i].first, this);
313}
314
315const 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}
320const 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
328bool 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...
339unsigned 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//
349void 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
365bool EnumFlagsBase::handleOccurance(const char *ArgName, const string &Arg) {
366 return EnumValueBase::handleOccurance("", ArgName);
367}
368
369unsigned 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
376void 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
391bool 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...
402unsigned 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//
413void 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//
425namespace {
426
427// isHidden/isReallyHidden - Predicates to be used to filter down arg lists.
428inline bool isHidden(pair<string, Option *> &OptPair) {
Chris Lattnerdc4693d2001-07-23 23:02:45 +0000429 return OptPair.second->getOptionHiddenFlag() >= Hidden;
Chris Lattnerdbab15a2001-07-23 17:17:47 +0000430}
431inline bool isReallyHidden(pair<string, Option *> &OptPair) {
Chris Lattnerdc4693d2001-07-23 23:02:45 +0000432 return OptPair.second->getOptionHiddenFlag() == ReallyHidden;
Chris Lattnerdbab15a2001-07-23 17:17:47 +0000433}
434
435class 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
489public:
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
496Help HelpOp("help", "display available options"
Chris Lattnerdc4693d2001-07-23 23:02:45 +0000497 " (--help-hidden for more)", false);
Chris Lattnerdbab15a2001-07-23 17:17:47 +0000498Help HelpHiddenOpt("help-hidden", "display all available options", true);
499
500} // End anonymous namespace