1 // -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*-
2 
3 /******************************************************************************
4  *
5  *  file:  Arg.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 
25 #ifndef TCLAP_ARGUMENT_H
26 #define TCLAP_ARGUMENT_H
27 
28 #ifdef HAVE_CONFIG_H
29 #include <config.h>
30 #else
31 #define HAVE_SSTREAM
32 #endif
33 
34 #include <string>
35 #include <vector>
36 #include <list>
37 #include <iostream>
38 #include <iomanip>
39 #include <cstdio>
40 
41 #if defined(HAVE_SSTREAM)
42 #include <sstream>
43 typedef std::istringstream istringstream;
44 #elif defined(HAVE_STRSTREAM)
45 #include <strstream>
46 typedef std::istrstream istringstream;
47 #else
48 #error "Need a stringstream (sstream or strstream) to compile!"
49 #endif
50 
51 #include <tclap/ArgException.h>
52 #include <tclap/Visitor.h>
53 #include <tclap/CmdLineInterface.h>
54 #include <tclap/ArgTraits.h>
55 #include <tclap/StandardTraits.h>
56 
57 namespace TCLAP {
58 
59 /**
60  * A virtual base class that defines the essential data for all arguments.
61  * This class, or one of its existing children, must be subclassed to do
62  * anything.
63  */
64 class Arg
65 {
66 	private:
67 		/**
68 		 * Prevent accidental copying.
69 		 */
70 		Arg(const Arg& rhs);
71 
72 		/**
73 		 * Prevent accidental copying.
74 		 */
75 		Arg& operator=(const Arg& rhs);
76 
77 		/**
78 		 * Indicates whether the rest of the arguments should be ignored.
79 		 */
ignoreRestRef()80 		static bool& ignoreRestRef() { static bool ign = false; return ign; }
81 
82 		/**
83 		 * The delimiter that separates an argument flag/name from the
84 		 * value.
85 		 */
delimiterRef()86 		static char& delimiterRef() { static char delim = ' '; return delim; }
87 
88 	protected:
89 
90 		/**
91 		 * The single char flag used to identify the argument.
92 		 * This value (preceded by a dash {-}), can be used to identify
93 		 * an argument on the command line.  The _flag can be blank,
94 		 * in fact this is how unlabeled args work.  Unlabeled args must
95 		 * override appropriate functions to get correct handling. Note
96 		 * that the _flag does NOT include the dash as part of the flag.
97 		 */
98 		std::string _flag;
99 
100 		/**
101 		 * A single work namd indentifying the argument.
102 		 * This value (preceded by two dashed {--}) can also be used
103 		 * to identify an argument on the command line.  Note that the
104 		 * _name does NOT include the two dashes as part of the _name. The
105 		 * _name cannot be blank.
106 		 */
107 		std::string _name;
108 
109 		/**
110 		 * Description of the argument.
111 		 */
112 		std::string _description;
113 
114 		/**
115 		 * Indicating whether the argument is required.
116 		 */
117 		bool _required;
118 
119 		/**
120 		 * Label to be used in usage description.  Normally set to
121 		 * "required", but can be changed when necessary.
122 		 */
123 		std::string _requireLabel;
124 
125 		/**
126 		 * Indicates whether a value is required for the argument.
127 		 * Note that the value may be required but the argument/value
128 		 * combination may not be, as specified by _required.
129 		 */
130 		bool _valueRequired;
131 
132 		/**
133 		 * Indicates whether the argument has been set.
134 		 * Indicates that a value on the command line has matched the
135 		 * name/flag of this argument and the values have been set accordingly.
136 		 */
137 		bool _alreadySet;
138 
139 		/**
140 		 * A pointer to a vistitor object.
141 		 * The visitor allows special handling to occur as soon as the
142 		 * argument is matched.  This defaults to NULL and should not
143 		 * be used unless absolutely necessary.
144 		 */
145 		Visitor* _visitor;
146 
147 		/**
148 		 * Whether this argument can be ignored, if desired.
149 		 */
150 		bool _ignoreable;
151 
152 		/**
153 		 * Indicates that the arg was set as part of an XOR and not on the
154 		 * command line.
155 		 */
156 		bool _xorSet;
157 
158 		bool _acceptsMultipleValues;
159 
160 		/**
161 		 * Performs the special handling described by the Vistitor.
162 		 */
163 		void _checkWithVisitor() const;
164 
165 		/**
166 		 * Primary constructor. YOU (yes you) should NEVER construct an Arg
167 		 * directly, this is a base class that is extended by various children
168 		 * that are meant to be used.  Use SwitchArg, ValueArg, MultiArg,
169 		 * UnlabeledValueArg, or UnlabeledMultiArg instead.
170 		 *
171 		 * \param flag - The flag identifying the argument.
172 		 * \param name - The name identifying the argument.
173 		 * \param desc - The description of the argument, used in the usage.
174 		 * \param req - Whether the argument is required.
175 		 * \param valreq - Whether the a value is required for the argument.
176 		 * \param v - The visitor checked by the argument. Defaults to NULL.
177 		 */
178  		Arg( const std::string& flag,
179 			 const std::string& name,
180 			 const std::string& desc,
181 			 bool req,
182 			 bool valreq,
183 			 Visitor* v = NULL );
184 
185 	public:
186 		/**
187 		 * Destructor.
188 		 */
189 		virtual ~Arg();
190 
191 		/**
192 		 * Adds this to the specified list of Args.
193 		 * \param argList - The list to add this to.
194 		 */
195 		virtual void addToList( std::list<Arg*>& argList ) const;
196 
197 		/**
198 		 * Begin ignoring arguments since the "--" argument was specified.
199 		 */
beginIgnoring()200 		static void beginIgnoring() { ignoreRestRef() = true; }
201 
202 		/**
203 		 * Whether to ignore the rest.
204 		 */
ignoreRest()205 		static bool ignoreRest() { return ignoreRestRef(); }
206 
207 		/**
208 		 * The delimiter that separates an argument flag/name from the
209 		 * value.
210 		 */
delimiter()211 		static char delimiter() { return delimiterRef(); }
212 
213 		/**
214 		 * The char used as a place holder when SwitchArgs are combined.
215 		 * Currently set to the bell char (ASCII 7).
216 		 */
blankChar()217 		static char blankChar() { return (char)7; }
218 
219 		/**
220 		 * The char that indicates the beginning of a flag.  Defaults to '-', but
221 		 * clients can define TCLAP_FLAGSTARTCHAR to override.
222 		 */
223 #ifndef TCLAP_FLAGSTARTCHAR
224 #define TCLAP_FLAGSTARTCHAR '-'
225 #endif
flagStartChar()226 		static char flagStartChar() { return TCLAP_FLAGSTARTCHAR; }
227 
228 		/**
229 		 * The sting that indicates the beginning of a flag.  Defaults to "-", but
230 		 * clients can define TCLAP_FLAGSTARTSTRING to override. Should be the same
231 		 * as TCLAP_FLAGSTARTCHAR.
232 		 */
233 #ifndef TCLAP_FLAGSTARTSTRING
234 #define TCLAP_FLAGSTARTSTRING "-"
235 #endif
flagStartString()236 		static const std::string flagStartString() { return TCLAP_FLAGSTARTSTRING; }
237 
238 		/**
239 		 * The sting that indicates the beginning of a name.  Defaults to "--", but
240 		 *  clients can define TCLAP_NAMESTARTSTRING to override.
241 		 */
242 #ifndef TCLAP_NAMESTARTSTRING
243 #define TCLAP_NAMESTARTSTRING "--"
244 #endif
nameStartString()245 		static const std::string nameStartString() { return TCLAP_NAMESTARTSTRING; }
246 
247 		/**
248 		 * The name used to identify the ignore rest argument.
249 		 */
ignoreNameString()250 		static const std::string ignoreNameString() { return "ignore_rest"; }
251 
252 		/**
253 		 * Sets the delimiter for all arguments.
254 		 * \param c - The character that delimits flags/names from values.
255 		 */
setDelimiter(char c)256 		static void setDelimiter( char c ) { delimiterRef() = c; }
257 
258 		/**
259 		 * Pure virtual method meant to handle the parsing and value assignment
260 		 * of the string on the command line.
261 		 * \param i - Pointer the the current argument in the list.
262 		 * \param args - Mutable list of strings. What is
263 		 * passed in from main.
264 		 */
265 		virtual bool processArg(int *i, std::vector<std::string>& args) = 0;
266 
267 		/**
268 		 * Operator ==.
269 		 * Equality operator. Must be virtual to handle unlabeled args.
270 		 * \param a - The Arg to be compared to this.
271 		 */
272 		virtual bool operator==(const Arg& a) const;
273 
274 		/**
275 		 * Returns the argument flag.
276 		 */
277 		const std::string& getFlag() const;
278 
279 		/**
280 		 * Returns the argument name.
281 		 */
282 		const std::string& getName() const;
283 
284 		/**
285 		 * Returns the argument description.
286 		 */
287 		std::string getDescription() const;
288 
289 		/**
290 		 * Indicates whether the argument is required.
291 		 */
292 		virtual bool isRequired() const;
293 
294 		/**
295 		 * Sets _required to true. This is used by the XorHandler.
296 		 * You really have no reason to ever use it.
297 		 */
298 		void forceRequired();
299 
300 		/**
301 		 * Sets the _alreadySet value to true.  This is used by the XorHandler.
302 		 * You really have no reason to ever use it.
303 		 */
304 		void xorSet();
305 
306 		/**
307 		 * Indicates whether a value must be specified for argument.
308 		 */
309 		bool isValueRequired() const;
310 
311 		/**
312 		 * Indicates whether the argument has already been set.  Only true
313 		 * if the arg has been matched on the command line.
314 		 */
315 		bool isSet() const;
316 
317 		/**
318 		 * Indicates whether the argument can be ignored, if desired.
319 		 */
320 		bool isIgnoreable() const;
321 
322 		/**
323 		 * A method that tests whether a string matches this argument.
324 		 * This is generally called by the processArg() method.  This
325 		 * method could be re-implemented by a child to change how
326 		 * arguments are specified on the command line.
327 		 * \param s - The string to be compared to the flag/name to determine
328 		 * whether the arg matches.
329 		 */
330 		virtual bool argMatches( const std::string& s ) const;
331 
332 		/**
333 		 * Returns a simple string representation of the argument.
334 		 * Primarily for debugging.
335 		 */
336 		virtual std::string toString() const;
337 
338 		/**
339 		 * Returns a short ID for the usage.
340 		 * \param valueId - The value used in the id.
341 		 */
342 		virtual std::string shortID( const std::string& valueId = "val" ) const;
343 
344 		/**
345 		 * Returns a long ID for the usage.
346 		 * \param valueId - The value used in the id.
347 		 */
348 		virtual std::string longID( const std::string& valueId = "val" ) const;
349 
350 		/**
351 		 * Trims a value off of the flag.
352 		 * \param flag - The string from which the flag and value will be
353 		 * trimmed. Contains the flag once the value has been trimmed.
354 		 * \param value - Where the value trimmed from the string will
355 		 * be stored.
356 		 */
357 		virtual void trimFlag( std::string& flag, std::string& value ) const;
358 
359 		/**
360 		 * Checks whether a given string has blank chars, indicating that
361 		 * it is a combined SwitchArg.  If so, return true, otherwise return
362 		 * false.
363 		 * \param s - string to be checked.
364 		 */
365 		bool _hasBlanks( const std::string& s ) const;
366 
367 		/**
368 		 * Sets the requireLabel. Used by XorHandler.  You shouldn't ever
369 		 * use this.
370 		 * \param s - Set the requireLabel to this value.
371 		 */
372 		void setRequireLabel( const std::string& s );
373 
374 		/**
375 		 * Used for MultiArgs and XorHandler to determine whether args
376 		 * can still be set.
377 		 */
378 		virtual bool allowMore();
379 
380 		/**
381 		 * Use by output classes to determine whether an Arg accepts
382 		 * multiple values.
383 		 */
384 		virtual bool acceptsMultipleValues();
385 
386 		/**
387 		 * Clears the Arg object and allows it to be reused by new
388 		 * command lines.
389 		 */
390 		 virtual void reset();
391 };
392 
393 /**
394  * Typedef of an Arg list iterator.
395  */
396 typedef std::list<Arg*>::iterator ArgListIterator;
397 
398 /**
399  * Typedef of an Arg vector iterator.
400  */
401 typedef std::vector<Arg*>::iterator ArgVectorIterator;
402 
403 /**
404  * Typedef of a Visitor list iterator.
405  */
406 typedef std::list<Visitor*>::iterator VisitorListIterator;
407 
408 /*
409  * Extract a value of type T from it's string representation contained
410  * in strVal. The ValueLike parameter used to select the correct
411  * specialization of ExtractValue depending on the value traits of T.
412  * ValueLike traits use operator>> to assign the value from strVal.
413  */
414 template<typename T> void
ExtractValue(T & destVal,const std::string & strVal,ValueLike vl)415 ExtractValue(T &destVal, const std::string& strVal, ValueLike vl)
416 {
417     static_cast<void>(vl); // Avoid warning about unused vl
418     std::istringstream is(strVal);
419 
420     int valuesRead = 0;
421     while ( is.good() ) {
422 	if ( is.peek() != EOF )
423 #ifdef TCLAP_SETBASE_ZERO
424 	    is >> std::setbase(0) >> destVal;
425 #else
426 	    is >> destVal;
427 #endif
428 	else
429 	    break;
430 
431 	valuesRead++;
432     }
433 
434     if ( is.fail() )
435 	throw( ArgParseException("Couldn't read argument value "
436 				 "from string '" + strVal + "'"));
437 
438 
439     if ( valuesRead > 1 )
440 	throw( ArgParseException("More than one valid value parsed from "
441 				 "string '" + strVal + "'"));
442 
443 }
444 
445 /*
446  * Extract a value of type T from it's string representation contained
447  * in strVal. The ValueLike parameter used to select the correct
448  * specialization of ExtractValue depending on the value traits of T.
449  * StringLike uses assignment (operator=) to assign from strVal.
450  */
451 template<typename T> void
ExtractValue(T & destVal,const std::string & strVal,StringLike sl)452 ExtractValue(T &destVal, const std::string& strVal, StringLike sl)
453 {
454     static_cast<void>(sl); // Avoid warning about unused sl
455     SetString(destVal, strVal);
456 }
457 
458 //////////////////////////////////////////////////////////////////////
459 //BEGIN Arg.cpp
460 //////////////////////////////////////////////////////////////////////
461 
Arg(const std::string & flag,const std::string & name,const std::string & desc,bool req,bool valreq,Visitor * v)462 inline Arg::Arg(const std::string& flag,
463          const std::string& name,
464          const std::string& desc,
465          bool req,
466          bool valreq,
467          Visitor* v) :
468   _flag(flag),
469   _name(name),
470   _description(desc),
471   _required(req),
472   _requireLabel("required"),
473   _valueRequired(valreq),
474   _alreadySet(false),
475   _visitor( v ),
476   _ignoreable(true),
477   _xorSet(false),
478   _acceptsMultipleValues(false)
479 {
480 	if ( _flag.length() > 1 )
481 		throw(SpecificationException(
482 				"Argument flag can only be one character long", toString() ) );
483 
484 	if ( _name != ignoreNameString() &&
485 		 ( _flag == Arg::flagStartString() ||
486 		   _flag == Arg::nameStartString() ||
487 		   _flag == " " ) )
488 		throw(SpecificationException("Argument flag cannot be either '" +
489 							Arg::flagStartString() + "' or '" +
490 							Arg::nameStartString() + "' or a space.",
491 							toString() ) );
492 
493 	if ( ( _name.substr( 0, Arg::flagStartString().length() ) == Arg::flagStartString() ) ||
494 		 ( _name.substr( 0, Arg::nameStartString().length() ) == Arg::nameStartString() ) ||
495 		 ( _name.find( " ", 0 ) != std::string::npos ) )
496 		throw(SpecificationException("Argument name begin with either '" +
497 							Arg::flagStartString() + "' or '" +
498 							Arg::nameStartString() + "' or space.",
499 							toString() ) );
500 
501 }
502 
~Arg()503 inline Arg::~Arg() { }
504 
shortID(const std::string & valueId)505 inline std::string Arg::shortID( const std::string& valueId ) const
506 {
507 	std::string id = "";
508 
509 	if ( _flag != "" )
510 		id = Arg::flagStartString() + _flag;
511 	else
512 		id = Arg::nameStartString() + _name;
513 
514 	if ( _valueRequired )
515 		id += std::string( 1, Arg::delimiter() ) + "<" + valueId  + ">";
516 
517 	if ( !_required )
518 		id = "[" + id + "]";
519 
520 	return id;
521 }
522 
longID(const std::string & valueId)523 inline std::string Arg::longID( const std::string& valueId ) const
524 {
525 	std::string id = "";
526 
527 	if ( _flag != "" )
528 	{
529 		id += Arg::flagStartString() + _flag;
530 
531 		if ( _valueRequired )
532 			id += std::string( 1, Arg::delimiter() ) + "<" + valueId + ">";
533 
534 		id += ",  ";
535 	}
536 
537 	id += Arg::nameStartString() + _name;
538 
539 	if ( _valueRequired )
540 		id += std::string( 1, Arg::delimiter() ) + "<" + valueId + ">";
541 
542 	return id;
543 
544 }
545 
546 inline bool Arg::operator==(const Arg& a) const
547 {
548 	if ( ( _flag != "" && _flag == a._flag ) || _name == a._name)
549 		return true;
550 	else
551 		return false;
552 }
553 
getDescription()554 inline std::string Arg::getDescription() const
555 {
556 	std::string desc = "";
557 	if ( _required )
558 		desc = "(" + _requireLabel + ")  ";
559 
560 //	if ( _valueRequired )
561 //		desc += "(value required)  ";
562 
563 	desc += _description;
564 	return desc;
565 }
566 
getFlag()567 inline const std::string& Arg::getFlag() const { return _flag; }
568 
getName()569 inline const std::string& Arg::getName() const { return _name; }
570 
isRequired()571 inline bool Arg::isRequired() const { return _required; }
572 
isValueRequired()573 inline bool Arg::isValueRequired() const { return _valueRequired; }
574 
isSet()575 inline bool Arg::isSet() const
576 {
577 	if ( _alreadySet && !_xorSet )
578 		return true;
579 	else
580 		return false;
581 }
582 
isIgnoreable()583 inline bool Arg::isIgnoreable() const { return _ignoreable; }
584 
setRequireLabel(const std::string & s)585 inline void Arg::setRequireLabel( const std::string& s)
586 {
587 	_requireLabel = s;
588 }
589 
argMatches(const std::string & argFlag)590 inline bool Arg::argMatches( const std::string& argFlag ) const
591 {
592 	if ( ( argFlag == Arg::flagStartString() + _flag && _flag != "" ) ||
593 	       argFlag == Arg::nameStartString() + _name )
594 		return true;
595 	else
596 		return false;
597 }
598 
toString()599 inline std::string Arg::toString() const
600 {
601 	std::string s = "";
602 
603 	if ( _flag != "" )
604 		s += Arg::flagStartString() + _flag + " ";
605 
606 	s += "(" + Arg::nameStartString() + _name + ")";
607 
608 	return s;
609 }
610 
_checkWithVisitor()611 inline void Arg::_checkWithVisitor() const
612 {
613 	if ( _visitor != NULL )
614 		_visitor->visit();
615 }
616 
617 /**
618  * Implementation of trimFlag.
619  */
trimFlag(std::string & flag,std::string & value)620 inline void Arg::trimFlag(std::string& flag, std::string& value) const
621 {
622 	int stop = 0;
623 	for ( int i = 0; static_cast<unsigned int>(i) < flag.length(); i++ )
624 		if ( flag[i] == Arg::delimiter() )
625 		{
626 			stop = i;
627 			break;
628 		}
629 
630 	if ( stop > 1 )
631 	{
632 		value = flag.substr(stop+1);
633 		flag = flag.substr(0,stop);
634 	}
635 
636 }
637 
638 /**
639  * Implementation of _hasBlanks.
640  */
_hasBlanks(const std::string & s)641 inline bool Arg::_hasBlanks( const std::string& s ) const
642 {
643 	for ( int i = 1; static_cast<unsigned int>(i) < s.length(); i++ )
644 		if ( s[i] == Arg::blankChar() )
645 			return true;
646 
647 	return false;
648 }
649 
forceRequired()650 inline void Arg::forceRequired()
651 {
652 	_required = true;
653 }
654 
xorSet()655 inline void Arg::xorSet()
656 {
657 	_alreadySet = true;
658 	_xorSet = true;
659 }
660 
661 /**
662  * Overridden by Args that need to added to the end of the list.
663  */
addToList(std::list<Arg * > & argList)664 inline void Arg::addToList( std::list<Arg*>& argList ) const
665 {
666 	argList.push_front( const_cast<Arg*>(this) );
667 }
668 
allowMore()669 inline bool Arg::allowMore()
670 {
671 	return false;
672 }
673 
acceptsMultipleValues()674 inline bool Arg::acceptsMultipleValues()
675 {
676 	return _acceptsMultipleValues;
677 }
678 
reset()679 inline void Arg::reset()
680 {
681 	_xorSet = false;
682 	_alreadySet = false;
683 }
684 
685 //////////////////////////////////////////////////////////////////////
686 //END Arg.cpp
687 //////////////////////////////////////////////////////////////////////
688 
689 } //namespace TCLAP
690 
691 #endif
692 
693