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