1 // -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*-
2
3 /******************************************************************************
4 *
5 * file: CmdLine.h
6 *
7 * Copyright (c) 2003, Michael E. Smoot .
8 * Copyright (c) 2004, Michael E. Smoot, Daniel Aarno.
9 * All rights reverved.
10 *
11 * See the file COPYING in the top directory of this distribution for
12 * more information.
13 *
14 * THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 * DEALINGS IN THE SOFTWARE.
21 *
22 *****************************************************************************/
23
24 #ifndef TCLAP_CMDLINE_H
25 #define TCLAP_CMDLINE_H
26
27 #include <tclap/SwitchArg.h>
28 #include <tclap/MultiSwitchArg.h>
29 #include <tclap/UnlabeledValueArg.h>
30 #include <tclap/UnlabeledMultiArg.h>
31
32 #include <tclap/XorHandler.h>
33 #include <tclap/HelpVisitor.h>
34 #include <tclap/VersionVisitor.h>
35 #include <tclap/IgnoreRestVisitor.h>
36
37 #include <tclap/CmdLineOutput.h>
38 #include <tclap/StdOutput.h>
39
40 #include <tclap/Constraint.h>
41 #include <tclap/ValuesConstraint.h>
42
43 #include <string>
44 #include <vector>
45 #include <list>
46 #include <iostream>
47 #include <iomanip>
48 #include <algorithm>
49 #include <stdlib.h> // Needed for exit(), which isn't defined in some envs.
50
51 namespace TCLAP {
52
DelPtr(T ptr)53 template<typename T> void DelPtr(T ptr)
54 {
55 delete ptr;
56 }
57
ClearContainer(C & c)58 template<typename C> void ClearContainer(C &c)
59 {
60 typedef typename C::value_type value_type;
61 std::for_each(c.begin(), c.end(), DelPtr<value_type>);
62 c.clear();
63 }
64
65
66 /**
67 * The base class that manages the command line definition and passes
68 * along the parsing to the appropriate Arg classes.
69 */
70 class CmdLine : public CmdLineInterface
71 {
72 protected:
73
74 /**
75 * The list of arguments that will be tested against the
76 * command line.
77 */
78 std::list<Arg*> _argList;
79
80 /**
81 * The name of the program. Set to argv[0].
82 */
83 std::string _progName;
84
85 /**
86 * A message used to describe the program. Used in the usage output.
87 */
88 std::string _message;
89
90 /**
91 * The version to be displayed with the --version switch.
92 */
93 std::string _version;
94
95 /**
96 * The number of arguments that are required to be present on
97 * the command line. This is set dynamically, based on the
98 * Args added to the CmdLine object.
99 */
100 int _numRequired;
101
102 /**
103 * The character that is used to separate the argument flag/name
104 * from the value. Defaults to ' ' (space).
105 */
106 char _delimiter;
107
108 /**
109 * The handler that manages xoring lists of args.
110 */
111 XorHandler _xorHandler;
112
113 /**
114 * A list of Args to be explicitly deleted when the destructor
115 * is called. At the moment, this only includes the three default
116 * Args.
117 */
118 std::list<Arg*> _argDeleteOnExitList;
119
120 /**
121 * A list of Visitors to be explicitly deleted when the destructor
122 * is called. At the moment, these are the Vistors created for the
123 * default Args.
124 */
125 std::list<Visitor*> _visitorDeleteOnExitList;
126
127 /**
128 * Object that handles all output for the CmdLine.
129 */
130 CmdLineOutput* _output;
131
132 /**
133 * Should CmdLine handle parsing exceptions internally?
134 */
135 bool _handleExceptions;
136
137 /**
138 * Throws an exception listing the missing args.
139 */
140 void missingArgsException();
141
142 /**
143 * Checks whether a name/flag string matches entirely matches
144 * the Arg::blankChar. Used when multiple switches are combined
145 * into a single argument.
146 * \param s - The message to be used in the usage.
147 */
148 bool _emptyCombined(const std::string& s);
149
150 /**
151 * Perform a delete ptr; operation on ptr when this object is deleted.
152 */
153 void deleteOnExit(Arg* ptr);
154
155 /**
156 * Perform a delete ptr; operation on ptr when this object is deleted.
157 */
158 void deleteOnExit(Visitor* ptr);
159
160 private:
161
162 /**
163 * Prevent accidental copying.
164 */
165 CmdLine(const CmdLine& rhs);
166 CmdLine& operator=(const CmdLine& rhs);
167
168 /**
169 * Encapsulates the code common to the constructors
170 * (which is all of it).
171 */
172 void _constructor();
173
174
175 /**
176 * Is set to true when a user sets the output object. We use this so
177 * that we don't delete objects that are created outside of this lib.
178 */
179 bool _userSetOutput;
180
181 /**
182 * Whether or not to automatically create help and version switches.
183 */
184 bool _helpAndVersion;
185
186 public:
187
188 /**
189 * Command line constructor. Defines how the arguments will be
190 * parsed.
191 * \param message - The message to be used in the usage
192 * output.
193 * \param delimiter - The character that is used to separate
194 * the argument flag/name from the value. Defaults to ' ' (space).
195 * \param version - The version number to be used in the
196 * --version switch.
197 * \param helpAndVersion - Whether or not to create the Help and
198 * Version switches. Defaults to true.
199 */
200 CmdLine(const std::string& message,
201 const char delimiter = ' ',
202 const std::string& version = "none",
203 bool helpAndVersion = true);
204
205 /**
206 * Deletes any resources allocated by a CmdLine object.
207 */
208 virtual ~CmdLine();
209
210 /**
211 * Adds an argument to the list of arguments to be parsed.
212 * \param a - Argument to be added.
213 */
214 void add( Arg& a );
215
216 /**
217 * An alternative add. Functionally identical.
218 * \param a - Argument to be added.
219 */
220 void add( Arg* a );
221
222 /**
223 * Add two Args that will be xor'd. If this method is used, add does
224 * not need to be called.
225 * \param a - Argument to be added and xor'd.
226 * \param b - Argument to be added and xor'd.
227 */
228 void xorAdd( Arg& a, Arg& b );
229
230 /**
231 * Add a list of Args that will be xor'd. If this method is used,
232 * add does not need to be called.
233 * \param xors - List of Args to be added and xor'd.
234 */
235 void xorAdd( std::vector<Arg*>& xors );
236
237 /**
238 * Parses the command line.
239 * \param argc - Number of arguments.
240 * \param argv - Array of arguments.
241 */
242 void parse(int argc, const char * const * argv);
243
244 /**
245 * Parses the command line.
246 * \param args - A vector of strings representing the args.
247 * args[0] is still the program name.
248 */
249 void parse(std::vector<std::string>& args);
250
251 /**
252 *
253 */
254 CmdLineOutput* getOutput();
255
256 /**
257 *
258 */
259 void setOutput(CmdLineOutput* co);
260
261 /**
262 *
263 */
264 std::string& getVersion();
265
266 /**
267 *
268 */
269 std::string& getProgramName();
270
271 /**
272 *
273 */
274 std::list<Arg*>& getArgList();
275
276 /**
277 *
278 */
279 XorHandler& getXorHandler();
280
281 /**
282 *
283 */
284 char getDelimiter();
285
286 /**
287 *
288 */
289 std::string& getMessage();
290
291 /**
292 *
293 */
294 bool hasHelpAndVersion();
295
296 /**
297 * Disables or enables CmdLine's internal parsing exception handling.
298 *
299 * @param state Should CmdLine handle parsing exceptions internally?
300 */
301 void setExceptionHandling(const bool state);
302
303 /**
304 * Returns the current state of the internal exception handling.
305 *
306 * @retval true Parsing exceptions are handled internally.
307 * @retval false Parsing exceptions are propagated to the caller.
308 */
309 bool getExceptionHandling() const;
310
311 /**
312 * Allows the CmdLine object to be reused.
313 */
314 void reset();
315
316 };
317
318
319 ///////////////////////////////////////////////////////////////////////////////
320 //Begin CmdLine.cpp
321 ///////////////////////////////////////////////////////////////////////////////
322
CmdLine(const std::string & m,char delim,const std::string & v,bool help)323 inline CmdLine::CmdLine(const std::string& m,
324 char delim,
325 const std::string& v,
326 bool help )
327 :
328 _argList(std::list<Arg*>()),
329 _progName("not_set_yet"),
330 _message(m),
331 _version(v),
332 _numRequired(0),
333 _delimiter(delim),
334 _xorHandler(XorHandler()),
335 _argDeleteOnExitList(std::list<Arg*>()),
336 _visitorDeleteOnExitList(std::list<Visitor*>()),
337 _output(0),
338 _handleExceptions(true),
339 _userSetOutput(false),
340 _helpAndVersion(help)
341 {
342 _constructor();
343 }
344
~CmdLine()345 inline CmdLine::~CmdLine()
346 {
347 ClearContainer(_argDeleteOnExitList);
348 ClearContainer(_visitorDeleteOnExitList);
349
350 if ( !_userSetOutput ) {
351 delete _output;
352 _output = 0;
353 }
354 }
355
_constructor()356 inline void CmdLine::_constructor()
357 {
358 _output = new StdOutput;
359
360 Arg::setDelimiter( _delimiter );
361
362 Visitor* v;
363
364 if ( _helpAndVersion )
365 {
366 v = new HelpVisitor( this, &_output );
367 SwitchArg* help = new SwitchArg("?","help",
368 "displays help",
369 false, v);
370 add( help );
371 deleteOnExit(help);
372 deleteOnExit(v);
373
374 // v = new VersionVisitor( this, &_output );
375 // SwitchArg* vers = new SwitchArg("v","version",
376 // "Displays version",
377 // false, v);
378 // add( vers );
379 // deleteOnExit(vers);
380 // deleteOnExit(v);
381 }
382
383 // v = new IgnoreRestVisitor();
384 // SwitchArg* ignore = new SwitchArg(Arg::flagStartString(),
385 // Arg::ignoreNameString(),
386 // "ignores the rest of the labeled arguments following this flag",
387 // false, v);
388 // add( ignore );
389 // deleteOnExit(ignore);
390 // deleteOnExit(v);
391 }
392
xorAdd(std::vector<Arg * > & ors)393 inline void CmdLine::xorAdd( std::vector<Arg*>& ors )
394 {
395 _xorHandler.add( ors );
396
397 for (ArgVectorIterator it = ors.begin(); it != ors.end(); it++)
398 {
399 (*it)->forceRequired();
400 (*it)->setRequireLabel( "OR required" );
401 add( *it );
402 }
403 }
404
xorAdd(Arg & a,Arg & b)405 inline void CmdLine::xorAdd( Arg& a, Arg& b )
406 {
407 std::vector<Arg*> ors;
408 ors.push_back( &a );
409 ors.push_back( &b );
410 xorAdd( ors );
411 }
412
add(Arg & a)413 inline void CmdLine::add( Arg& a )
414 {
415 add( &a );
416 }
417
add(Arg * a)418 inline void CmdLine::add( Arg* a )
419 {
420 for( ArgListIterator it = _argList.begin(); it != _argList.end(); it++ )
421 if ( *a == *(*it) )
422 throw( SpecificationException(
423 "Argument with same flag/name already exists!",
424 a->longID() ) );
425
426 a->addToList( _argList );
427
428 if ( a->isRequired() )
429 _numRequired++;
430 }
431
432
parse(int argc,const char * const * argv)433 inline void CmdLine::parse(int argc, const char * const * argv)
434 {
435 // this step is necessary so that we have easy access to
436 // mutable strings.
437 std::vector<std::string> args;
438 for (int i = 0; i < argc; i++)
439 args.push_back(argv[i]);
440
441 parse(args);
442 }
443
parse(std::vector<std::string> & args)444 inline void CmdLine::parse(std::vector<std::string>& args)
445 {
446 bool shouldExit = false;
447 int estat = 0;
448
449 try {
450 _progName = args.front();
451 args.erase(args.begin());
452
453 int requiredCount = 0;
454
455 for (int i = 0; static_cast<unsigned int>(i) < args.size(); i++)
456 {
457 bool matched = false;
458 for (ArgListIterator it = _argList.begin();
459 it != _argList.end(); it++) {
460 if ( (*it)->processArg( &i, args ) )
461 {
462 requiredCount += _xorHandler.check( *it );
463 matched = true;
464 break;
465 }
466 }
467
468 // checks to see if the argument is an empty combined
469 // switch and if so, then we've actually matched it
470 if ( !matched && _emptyCombined( args[i] ) )
471 matched = true;
472
473 if ( !matched && !Arg::ignoreRest() )
474 throw(CmdLineParseException("Couldn't find match "
475 "for argument",
476 args[i]));
477 }
478
479 if ( requiredCount < _numRequired )
480 missingArgsException();
481
482 if ( requiredCount > _numRequired )
483 throw(CmdLineParseException("Too many arguments!"));
484
485 } catch ( ArgException& e ) {
486 // If we're not handling the exceptions, rethrow.
487 if ( !_handleExceptions) {
488 throw;
489 }
490
491 try {
492 _output->failure(*this,e);
493 } catch ( ExitException &ee ) {
494 estat = ee.getExitStatus();
495 shouldExit = true;
496 }
497 } catch (ExitException &ee) {
498 // If we're not handling the exceptions, rethrow.
499 if ( !_handleExceptions) {
500 throw;
501 }
502
503 estat = ee.getExitStatus();
504 shouldExit = true;
505 }
506
507 if (shouldExit)
508 exit(estat);
509 }
510
_emptyCombined(const std::string & s)511 inline bool CmdLine::_emptyCombined(const std::string& s)
512 {
513 if ( s.length() > 0 && s[0] != Arg::flagStartChar() )
514 return false;
515
516 for ( int i = 1; static_cast<unsigned int>(i) < s.length(); i++ )
517 if ( s[i] != Arg::blankChar() )
518 return false;
519
520 return true;
521 }
522
missingArgsException()523 inline void CmdLine::missingArgsException()
524 {
525 int count = 0;
526
527 std::string missingArgList;
528 for (ArgListIterator it = _argList.begin(); it != _argList.end(); it++)
529 {
530 if ( (*it)->isRequired() && !(*it)->isSet() )
531 {
532 missingArgList += (*it)->getName();
533 missingArgList += ", ";
534 count++;
535 }
536 }
537 missingArgList = missingArgList.substr(0,missingArgList.length()-2);
538
539 std::string msg;
540 if ( count > 1 )
541 msg = "Required arguments missing: ";
542 else
543 msg = "Required argument missing: ";
544
545 msg += missingArgList;
546
547 throw(CmdLineParseException(msg));
548 }
549
deleteOnExit(Arg * ptr)550 inline void CmdLine::deleteOnExit(Arg* ptr)
551 {
552 _argDeleteOnExitList.push_back(ptr);
553 }
554
deleteOnExit(Visitor * ptr)555 inline void CmdLine::deleteOnExit(Visitor* ptr)
556 {
557 _visitorDeleteOnExitList.push_back(ptr);
558 }
559
getOutput()560 inline CmdLineOutput* CmdLine::getOutput()
561 {
562 return _output;
563 }
564
setOutput(CmdLineOutput * co)565 inline void CmdLine::setOutput(CmdLineOutput* co)
566 {
567 if ( !_userSetOutput )
568 delete _output;
569 _userSetOutput = true;
570 _output = co;
571 }
572
getVersion()573 inline std::string& CmdLine::getVersion()
574 {
575 return _version;
576 }
577
getProgramName()578 inline std::string& CmdLine::getProgramName()
579 {
580 return _progName;
581 }
582
getArgList()583 inline std::list<Arg*>& CmdLine::getArgList()
584 {
585 return _argList;
586 }
587
getXorHandler()588 inline XorHandler& CmdLine::getXorHandler()
589 {
590 return _xorHandler;
591 }
592
getDelimiter()593 inline char CmdLine::getDelimiter()
594 {
595 return _delimiter;
596 }
597
getMessage()598 inline std::string& CmdLine::getMessage()
599 {
600 return _message;
601 }
602
hasHelpAndVersion()603 inline bool CmdLine::hasHelpAndVersion()
604 {
605 return _helpAndVersion;
606 }
607
setExceptionHandling(const bool state)608 inline void CmdLine::setExceptionHandling(const bool state)
609 {
610 _handleExceptions = state;
611 }
612
getExceptionHandling()613 inline bool CmdLine::getExceptionHandling() const
614 {
615 return _handleExceptions;
616 }
617
reset()618 inline void CmdLine::reset()
619 {
620 for( ArgListIterator it = _argList.begin(); it != _argList.end(); it++ )
621 (*it)->reset();
622
623 _progName.clear();
624 }
625
626 ///////////////////////////////////////////////////////////////////////////////
627 //End CmdLine.cpp
628 ///////////////////////////////////////////////////////////////////////////////
629
630
631
632 } //namespace TCLAP
633 #endif
634