1 // ==========================================================================
2 //                 SeqAn - The Library for Sequence Analysis
3 // ==========================================================================
4 // Copyright (c) 2006-2010, Knut Reinert, FU Berlin
5 // All rights reserved.
6 //
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions are met:
9 //
10 //     * Redistributions of source code must retain the above copyright
11 //       notice, this list of conditions and the following disclaimer.
12 //     * Redistributions in binary form must reproduce the above copyright
13 //       notice, this list of conditions and the following disclaimer in the
14 //       documentation and/or other materials provided with the distribution.
15 //     * Neither the name of Knut Reinert or the FU Berlin nor the names of
16 //       its contributors may be used to endorse or promote products derived
17 //       from this software without specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 // ARE DISCLAIMED. IN NO EVENT SHALL KNUT REINERT OR THE FU BERLIN BE LIABLE
23 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
29 // DAMAGE.
30 //
31 // ==========================================================================
32 
33 #ifndef SEQAN_MISC_CMDPARSER
34 #define SEQAN_MISC_CMDPARSER
35 
36 #include <sstream>
37 #include <seqan/map.h>
38 #include <seqan/sequence.h>
39 #include <seqan/file.h>
40 
41 namespace SEQAN_NAMESPACE_MAIN
42 {
43 
44 //////////////////////////////////////////////////////////////////////////////
45 //  TODO:
46 //      * support some more formating options
47 //      * store/return error code (invalid argument, invalid option, etc.)
48 //      * support named arguments (e.g. <ARG1> -> <INPUT FILE>)
49 //////////////////////////////////////////////////////////////////////////////
50 template<typename TChar>
51 inline bool
_isDigit(TChar const c)52 _isDigit(TChar const c)
53 {
54     return (c >= '0') && (c <= '9');
55 }
56 
57 template<typename TString>
58 inline bool
_isDouble(TString const s)59 _isDouble(TString const s)
60 {
61     bool _dot = true;
62     unsigned l = length(s);
63     unsigned i = 0;
64 
65     // skip leading sign
66     if(s[i] == '-') ++i;
67     while(i < l){
68         if(!_isDigit(s[i])){
69             if(s[i] == '.' && _dot){
70                 _dot = false;
71             }else return false;
72         }
73         ++i;
74     }
75     return true;
76 }
77 
78 template<typename TString>
79 inline bool
_isInt(TString const s)80 _isInt(TString const s)
81 {
82     unsigned l = length(s);
83     unsigned i = 0;
84     // skip leading sign
85     if (s[i] == '-') ++i;
86     while(i < l){
87         if(!_isDigit(s[i])) return false;
88         ++i;
89     }
90     return true;
91 }
92 
93 //////////////////////////////////////////////////////////////////////////////
94 
95 struct OptionType
96 {
97     // TODO(holtgrew): Should be all upper case!
98     enum {
99         Bool = 1,		    // option needs no argument, value is true iff given on command line
100         Boolean = 1,		// option needs no argument, value is true iff given on command line
101         String = 2,			// argument is a string
102         Int = 4,			// ... an integer
103         Integer = 4,		// ... an integer
104         Double = 8,			// ... a float
105         Mandatory = 16,		// option must be set
106 		Label = 32,			// automatically print a label for the argument(s) on the help screen
107 		List = 64,			// option is a list of values
108         Hidden = 128		// hide this option from the help screen
109 	};
110 };
111 
112 //////////////////////////////////////////////////////////////////////////////
113 /**
114 .Class.CommandLineOption:
115 ..cat:Miscellaneous
116 ..summary:Stores information for a specific command line option.
117 ..signature:CommandLineOption
118 ..remarks:A @Class.CommandLineOption@ object can be added to a @Class.CommandLineParser@ via @Function.addOption@.
119 ..include:seqan/misc/misc_cmdparser.h
120 */
121 
122 class CommandLineOption
123 {
124 public:
125     CharString			longName;			// long option name
126     CharString			shortName;			// short option name
127 	CharString			arguments;			// argument names seperated by spaces
128 
129     CharString			helpText;			// option description
130     int					optionType;			// option type
131 	int					argumentsPerOption;	// number of arguments per option
132 
133 	String<CharString>	defaultValue;
134 	String<CharString>	value;
135 
CommandLineOption()136     CommandLineOption() {}
137 
CommandLineOption(CharString const & _short,CharString const & _long,CharString const & _help,int _type)138     CommandLineOption(
139 		CharString const & _short,
140 		CharString const & _long,
141 		CharString const & _help,
142 		int _type
143 	) :
144 		longName(_long),
145 		shortName(_short),
146 		helpText(_help),
147 		optionType(_type),
148 		argumentsPerOption(1)
149 	{
150 	}
151 
CommandLineOption(CharString const & _short,CharString const & _long,int _argumentsPerOption,CharString const & _help,int _type)152     CommandLineOption(
153 		CharString const & _short,
154 		CharString const & _long,
155 		int _argumentsPerOption,
156 		CharString const & _help,
157 		int _type
158 	) :
159 		longName(_long),
160 		shortName(_short),
161 		helpText(_help),
162 		optionType(_type),
163 		argumentsPerOption(_argumentsPerOption)
164 	{
165 	}
166 
167 	template <typename TValue>
CommandLineOption(CharString const & _short,CharString const & _long,int _argumentsPerOption,CharString const & _help,int _type,TValue const & _default)168     CommandLineOption(
169 		CharString const & _short,
170 		CharString const & _long,
171 		int _argumentsPerOption,
172 		CharString const & _help,
173 		int _type,
174 		TValue const & _default
175 	) :
176 		longName(_long),
177 		shortName(_short),
178 		helpText(_help),
179 		optionType(_type),
180 		argumentsPerOption(_argumentsPerOption)
181 	{
182 		std::stringstream strm;
183 		strm << _default;
184 		appendValue(defaultValue, strm.str());
185 		append(helpText, " (default ");
186 		append(helpText, strm.str());
187 		appendValue(helpText, ')');
188 	}
189 
190 	template <typename TValue>
CommandLineOption(CharString const & _short,CharString const & _long,CharString const & _help,int _type,TValue const & _default)191     CommandLineOption(
192 		CharString const & _short,
193 		CharString const & _long,
194 		CharString const & _help,
195 		int _type,
196 		TValue const & _default
197 	) :
198 		longName(_long),
199 		shortName(_short),
200 		helpText(_help),
201 		optionType(_type),
202 		argumentsPerOption(1)
203 	{
204 		std::stringstream strm;
205 		strm << _default;
206 		appendValue(defaultValue, strm.str());
207 		append(helpText, " (default ");
208 		append(helpText, strm.str());
209 		appendValue(helpText, ')');
210 	}
211 
212 /**
213 .Memfunc.CommandLineOption#CommandLineOption:
214 ..class:Class.CommandLineOption
215 ..summary:Constructor
216 ..signature:CommandLineOption ()
217 ..signature:CommandLineOption (shortName, longName[, argumentsPerOption], helpText, optionType[, defaultValue])
218 ..param.shortName:A @Shortcut.CharString@ containing the short-name option identifier (e.g. $"h"$ for the $-h/--help$ option).
219 Although not suggested the short-name can contain more than 1 character.
220 ...remarks:Note that the leading "-" is not passed.
221 ..param.longName:A @Shortcut.CharString@ containing the long-name option identifier (e.g. $"help"$ for the $-h/--help$ option).
222 ...type:Shortcut.CharString
223 ...remarks:Note that the leading "--" is not passed.
224 ..param.argumentsPerOption:The number of required arguments per option (e.g. if set to 3 then 3 arguments must follow the option: "-foo x1 x2 x3").
225 ...default:0 for boolean options and 1 for the rest.
226 ..param.helpText:A @Shortcut.CharString@ containing the help text associated with this option.
227 ...type:Shortcut.CharString
228 ..param.optionType:Option type. This can be the sum of the some of the following values:
229 ...tableheader:Flag|Value|Description
230 ...table:$OptionType::Bool$ or $OptionType::Boolean$|1|Option needs no argument, value is true iff given on command line
231 ...table:$OptionType::String$|2|Argument is a string
232 ...table:$OptionType::Int$ or $OptionType::Integer$|4|An integer
233 ...table:$OptionType::Double$|8|A float
234 ...table:$OptionType::Mandatory$|16|Option must be set
235 ...table:$OptionType::Label$|32|Automatically print a label for the argument(s) on the help screen
236 ...table:$OptionType::List$|64|Option is a list of values
237 ...table:$OptionType::Hidden$|128|Hide this option from the help screen
238 ..param.defaultValue:The default value of this option.
239 ...default:No default value.
240 */
241 };
242 
243 //////////////////////////////////////////////////////////////////////////////
244 /**
245 .Function.addArgumentText:
246 ..summary:Return a @Class.CommandLineOption@ object extended by an argument text.
247 ..cat:Miscellaneous
248 ..signature:addArgumentText(option, text)
249 ..param.option:A @Class.CommandLineOption@ object.
250 ...type:Class.CommandLineOption
251 ..param.text:A @Shortcut.CharString@ containing the argument text.
252 ...type:Shortcut.CharString
253 ..returns:The option extended by the argument text.
254 Instead of using $option$, the return value can be used as argument for @Function.addOption@.
255 ..remarks:The result type is a @Class.CommandLineOption@ object.
256 ..include:seqan/misc/misc_cmdparser.h
257 */
258 
259 inline CommandLineOption
addArgumentText(CommandLineOption const & opt,CharString const & text)260 addArgumentText(CommandLineOption const & opt, CharString const & text)
261 {
262 	CommandLineOption temp = opt;
263 	temp.arguments = " ";
264 	append(temp.arguments, text);
265 	return temp;
266 }
267 
268 //////////////////////////////////////////////////////////////////////////////
269 /**
270 .Function.longName:
271 ..summary:Returns the long-name of a @Class.CommandLineOption@ object.
272 ..cat:Miscellaneous
273 ..signature:longName(option)
274 ..param.option:The @Class.CommandLineOption@ object.
275 ...type:Class.CommandLineOption
276 ..returns:A @Shortcut.CharString@ holding the long name of the CommandLine Option (e.g. $help$ in case of $-h/--help$)
277 ..remarks:The result type is @Shortcut.CharString@.
278 ..include:seqan/misc/misc_cmdparser.h
279 */
280 
281 inline CharString &
longName(CommandLineOption & me)282 longName(CommandLineOption & me){
283     return me.longName;
284 }
285 
286 inline const CharString &
longName(CommandLineOption const & me)287 longName(CommandLineOption const & me){
288     return me.longName;
289 }
290 
291 /**
292 .Function.setLongName:
293 ..summary:Sets the long-name of a @Class.CommandLineOption@ object.
294 ..cat:Miscellaneous
295 ..signature:setLongName(option, newName)
296 ..param.option:The @Class.CommandLineOption@ object.
297 ...type:Class.CommandLineOption
298 ..param.newName:A @Shortcut.CharString@ containing the new long name of the option.
299 ...type:Shortcut.CharString
300 ..include:seqan/misc/misc_cmdparser.h
301 */
302 
303 inline void
setLongName(CommandLineOption & me,CharString const & newName)304 setLongName(CommandLineOption & me, CharString const & newName){
305     me.longName = newName;
306 }
307 
308 //////////////////////////////////////////////////////////////////////////////
309 /**
310 .Function.shortName:
311 ..summary:Returns the short-name of a @Class.CommandLineOption@ object.
312 ..cat:Miscellaneous
313 ..signature:shortName(option)
314 ..param.option:The @Class.CommandLineOption@ object.
315 ...type:Class.CommandLineOption
316 ..returns:A @Shortcut.CharString@ holding the short name of the CommandLine Option (e.g. $h$ in case of $-h/--help$)
317 ..remarks:The result type is @Shortcut.CharString@.
318 ..include:seqan/misc/misc_cmdparser.h
319 */
320 
321 inline CharString &
shortName(CommandLineOption & me)322 shortName(CommandLineOption & me){
323     return me.shortName;
324 }
325 
326 inline const CharString &
shortName(CommandLineOption const & me)327 shortName(CommandLineOption const & me){
328     return me.shortName;
329 }
330 
331 /**
332 .Function.setShortName:
333 ..summary:Sets the short-name of a @Class.CommandLineOption@ object.
334 ..cat:Miscellaneous
335 ..signature:setShortName(option,newName)
336 ..param.option:The @Class.CommandLineOption@ object.
337 ...type:Class.CommandLineOption
338 ..param.newName:A @Shortcut.CharString@ containing the new short name of the option.
339 ..include:seqan/misc/misc_cmdparser.h
340 */
341 
342 inline void
setShortName(CommandLineOption & me,CharString const & newName)343 setShortName(CommandLineOption & me, CharString const & newName){
344     me.shortName = newName;
345 }
346 
347 //////////////////////////////////////////////////////////////////////////////
348 /**
349 .Function.helpText:
350 ..summary:Returns the help text associated with the @Class.CommandLineOption@ object.
351 ..cat:Miscellaneous
352 ..signature:helpText(option)
353 ..param.option:The @Class.CommandLineOption@ object.
354 ...type:Class.CommandLineOption
355 ..returns:A @Shortcut.CharString@ holding the help text of the CommandLine Option
356 ..remarks:The result type is @Shortcut.CharString@.
357 ..include:seqan/misc/misc_cmdparser.h
358 */
359 inline CharString &
helpText(CommandLineOption & me)360 helpText(CommandLineOption & me){
361     return me.helpText;
362 }
363 
364 inline const CharString &
helpText(CommandLineOption const & me)365 helpText(CommandLineOption const & me){
366     return me.helpText;
367 }
368 
369 /**
370 .Function.setHelpText:
371 ..summary:Sets the help text associated with the @Class.CommandLineOption@ object.
372 ..cat:Miscellaneous
373 ..signature:setHelpText(option, newHelpText)
374 ..param.option:The @Class.CommandLineOption@ object.
375 ...type:Class.CommandLineOption
376 ..param.newHelpText:A @Shortcut.CharString@ containing the new help text.
377 ...type:Shortcut.CharString
378 ..include:seqan/misc/misc_cmdparser.h
379 */
380 inline void
setHelpText(CommandLineOption & me,CharString const & newHelp)381 setHelpText(CommandLineOption & me, CharString const & newHelp){
382     me.helpText = newHelp;
383 }
384 
385 //////////////////////////////////////////////////////////////////////////////
386 /**
387 .Function.isStringOption:
388 ..summary:Returns whether option argument can be a string.
389 ..cat:Miscellaneous
390 ..signature:isStringOption(option)
391 ..param.option:The @Class.CommandLineOption@ object.
392 ...type:Class.CommandLineOption
393 ..returns:$true$ if the option argument can be a string.
394 ..see:Memfunc.CommandLineOption#CommandLineOption.param.optionType
395 ..include:seqan/misc/misc_cmdparser.h
396 */
397 
398 inline bool
isStringOption(CommandLineOption const & me)399 isStringOption(CommandLineOption const & me)
400 {
401     return (me.optionType & OptionType::String) != 0;
402 }
403 
404 /**
405 .Function.isBooleanOption:
406 ..summary:Returns whether option is a switch.
407 ..cat:Miscellaneous
408 ..signature:isBooleanOption(option)
409 ..param.option:The @Class.CommandLineOption@ object.
410 ...type:Class.CommandLineOption
411 ..returns:$true$ if the option is a switch.
412 ..see:Memfunc.CommandLineOption#CommandLineOption.param.optionType
413 ..include:seqan/misc/misc_cmdparser.h
414 */
415 
416 inline bool
isBooleanOption(CommandLineOption const & me)417 isBooleanOption(CommandLineOption const & me)
418 {
419     return (me.optionType & OptionType::Boolean) != 0;
420 }
421 
422 /**
423 .Function.isDoubleOption:
424 ..summary:Returns whether option argument can be a double.
425 ..cat:Miscellaneous
426 ..signature:isDoubleOption(option)
427 ..param.option:The @Class.CommandLineOption@ object.
428 ...type:Class.CommandLineOption
429 ..returns:$true$ if the option argument can be a double.
430 ..see:Memfunc.CommandLineOption#CommandLineOption.param.optionType
431 ..include:seqan/misc/misc_cmdparser.h
432 */
433 
434 inline bool
isDoubleOption(CommandLineOption const & me)435 isDoubleOption(CommandLineOption const & me)
436 {
437     return (me.optionType & OptionType::Double) != 0;
438 }
439 
440 /**
441 .Function.isIntOption:
442 ..summary:Returns whether option argument can be an integer.
443 ..cat:Miscellaneous
444 ..signature:isIntOption(option)
445 ..param.option:The @Class.CommandLineOption@ object.
446 ...type:Class.CommandLineOption
447 ..returns:$true$ if the option argument can be an integer.
448 ..see:Memfunc.CommandLineOption#CommandLineOption.param.optionType
449 ..include:seqan/misc/misc_cmdparser.h
450 */
451 
452 inline bool
isIntOption(CommandLineOption const & me)453 isIntOption(CommandLineOption const & me)
454 {
455     return (me.optionType & OptionType::Int) != 0;
456 }
457 
458 /**
459 .Function.isHiddenOption:
460 ..summary:Returns whether option is hidden on the help screen.
461 ..cat:Miscellaneous
462 ..signature:isHiddenOption(option)
463 ..param.option:The @Class.CommandLineOption@ object.
464 ...type:Class.CommandLineOption
465 ..returns:$true$ if the option is hidden on the help screen.
466 ..see:Memfunc.CommandLineOption#CommandLineOption.param.optionType
467 ..include:seqan/misc/misc_cmdparser.h
468 */
469 
470 inline bool
isHiddenOption(CommandLineOption const & me)471 isHiddenOption(CommandLineOption const & me)
472 {
473     return (me.optionType & OptionType::Hidden) != 0;
474 }
475 
476 /**
477 .Function.isOptionMandatory:
478 ..summary:Returns whether option is mandatory.
479 ..cat:Miscellaneous
480 ..signature:isOptionMandatory(option)
481 ..param.option:The @Class.CommandLineOption@ object.
482 ...type:Class.CommandLineOption
483 ..returns:$true$ if the option is mandatory.
484 ..see:Memfunc.CommandLineOption#CommandLineOption.param.optionType
485 ..include:seqan/misc/misc_cmdparser.h
486 */
487 
488 inline bool
isOptionMandatory(CommandLineOption const & me)489 isOptionMandatory(CommandLineOption const & me)
490 {
491     return (me.optionType & OptionType::Mandatory) != 0;
492 }
493 
494 /**
495 .Function.isLabelOption:
496 ..summary:Returns whether an option label should be printed on the help screen.
497 ..cat:Miscellaneous
498 ..signature:isLabelOption(option)
499 ..param.option:The @Class.CommandLineOption@ object.
500 ...type:Class.CommandLineOption
501 ..returns:$true$ if an option label should be printed on the help screen.
502 ..see:Memfunc.CommandLineOption#CommandLineOption.param.optionType
503 ..include:seqan/misc/misc_cmdparser.h
504 */
505 
506 inline bool
isLabelOption(CommandLineOption const & me)507 isLabelOption(CommandLineOption const & me)
508 {
509     return (me.optionType & OptionType::Label) != 0;
510 }
511 
512 /**
513 .Function.isOptionList:
514 ..summary:Returns whether the option can be given multiple times.
515 ..cat:Miscellaneous
516 ..signature:isOptionList(option)
517 ..param.option:The @Class.CommandLineOption@ object.
518 ...type:Class.CommandLineOption
519 ..returns:$true$ if the option can be given multiple times on command line.
520 ..see:Memfunc.CommandLineOption#CommandLineOption.param.optionType
521 ..include:seqan/misc/misc_cmdparser.h
522 */
523 
524 inline bool
isOptionList(CommandLineOption const & me)525 isOptionList(CommandLineOption const & me)
526 {
527     return (me.optionType & OptionType::List) != 0;
528 }
529 
530 /**
531 .Function.setOptionType:
532 ..summary:Set the option type.
533 ..cat:Miscellaneous
534 ..signature:setOptionType(option, newOptionType)
535 ..param.option:The @Class.CommandLineOption@ object.
536 ...type:Class.CommandLineOption
537 ..param.newOptionType:Option Type.
538 ..see:Memfunc.CommandLineOption#CommandLineOption.param.optionType
539 ..include:seqan/misc/misc_cmdparser.h
540 */
541 
542 inline void
setOptionType(CommandLineOption & me,const int _newOptionType)543 setOptionType(CommandLineOption & me, const int _newOptionType)
544 {
545     me.optionType = _newOptionType;
546 }
547 
548 //////////////////////////////////////////////////////////////////////////////
549 /**
550 .Function.argumentText:
551 ..summary:Returns the argument text of a @Class.CommandLineOption@ object.
552 ..cat:Miscellaneous
553 ..signature:argumentText(option)
554 ..param.option:The @Class.CommandLineOption@ object.
555 ...type:Class.CommandLineOption
556 ..returns:A text consisting of label and help text of the option.
557 ...type:Shortcut.CharString
558 ..include:seqan/misc/misc_cmdparser.h
559 */
560 
561 inline CharString
argumentText(CommandLineOption const & me)562 argumentText(CommandLineOption const & me)
563 {
564 	if (empty(me.arguments))
565 	{
566 		CharString label;
567 		if (isLabelOption(me))
568 		{
569 			if (isStringOption(me))
570 				label = " STR";
571 			else if (isIntOption(me) || isDoubleOption(me))
572 				label = " NUM";
573 
574 			if (me.argumentsPerOption >= 2)
575 			{
576 				std::stringstream strm;
577 				if (!empty(label))
578 					for (int i = 0; i < me.argumentsPerOption; ++i)
579 						strm << label << (i + 1);
580 				return strm.str();
581 			}
582 		}
583 		return label;
584     }
585 	else
586 		return me.arguments;
587 }
588 
589 //////////////////////////////////////////////////////////////////////////////
590 
591 template <typename TStream>
592 inline void
_writeOptName(TStream & target,CommandLineOption const & me)593 _writeOptName(TStream & target, CommandLineOption const & me)
594 {
595     _streamWrite(target, empty(shortName(me)) ? "" : "-");
596     _streamWrite(target, shortName(me));
597     _streamWrite(target, (empty(shortName(me)) || empty(longName(me))) ? "" : ", ");
598     if (!empty(longName(me)))
599     {
600         _streamWrite(target, "--");
601         _streamWrite(target, longName(me));
602     }
603 }
604 
605 //////////////////////////////////////////////////////////////////////////////
606 
607 template <typename TStream>
608 inline void
write(TStream & target,CommandLineOption const & me)609 write(TStream & target, CommandLineOption const & me)
610 {
611     _streamPut(target,'\t');
612     _writeOptName(target, me);
613     _streamPut(target,'\t');
614     _streamPut(target,'\t');
615     _streamWrite(target,me.helpText);
616 }
617 
618 template <typename TStream>
619 inline TStream &
620 operator << (TStream & target, CommandLineOption const & source)
621 {
622     write(target, source);
623     return target;
624 }
625 
626 //////////////////////////////////////////////////////////////////////////////
627 /**
628 .Class.CommandLineParser:
629 ..cat:Miscellaneous
630 ..summary:Stores multiple @Class.CommandLineOption@ objects and parses the command line arguments for these options.
631 ..signature:CommandLineParser
632 ..include:seqan/misc/misc_cmdparser.h
633 */
634 
635 class CommandLineParser
636 {
637 public:
638     typedef String<CommandLineOption>           TOptionMap;
639     typedef Size<TOptionMap>::Type              TSize;
640 
641     typedef std::map<CharString, TSize>       TStringMap;
642     typedef String<CharString>                  TValueMap;
643 
644     TStringMap           shortNameMap;
645     TStringMap           longNameMap;
646     TOptionMap           optionMap;
647 
648     unsigned             required_arguments;
649     String<CharString>   arguments;
650     CharString           appName;
651 	String<CharString>   titleText;
652     String<CharString>   usageText;
653 	String<CharString>   versionText;
654 
655     unsigned line_width;
656     unsigned padding_left;
657 	unsigned short_width;
658 	unsigned long_width;
659 	unsigned full_width;
660 
661 	const CharString			null;			// empty return values
662 	const String<CharString>	nullSet;
663 
664 	friend inline void addOption(CommandLineParser & me, CommandLineOption const & opt);
665 
666 /**
667 .Memfunc.CommandLineParser#CommandLineParser:
668 ..class:Class.CommandLineParser
669 ..summary:Constructor
670 ..signature:CommandLineParser ()
671 ..signature:CommandLineParser (applicationName)
672 ..param.applicationName:A @Shortcut.CharString@ containing the name of the application.
673 ..remarks:If the name of the application is not passed to the constructor it will be extracted from the command line.
674 */
675 
CommandLineParser()676     CommandLineParser()
677 	{
678 		line_width         = 32;
679 		padding_left       = 2;
680 		short_width        = 0;
681 		long_width         = 0;
682 		full_width         = 0;
683 		required_arguments = 0;
684 		addOption(*this, CommandLineOption("h", "help", "displays this help message", OptionType::Boolean));
685 	}
686 
CommandLineParser(CharString appName)687     CommandLineParser(CharString appName)
688         : appName(appName)
689 	{
690 		line_width         = 32;
691 		padding_left       = 2;
692 		short_width        = 0;
693 		long_width         = 0;
694 		full_width         = 0;
695 		required_arguments = 0;
696 		addOption(*this, CommandLineOption("h", "help", "displays this help message", OptionType::Boolean));
697 	}
698 };
699 
700 //////////////////////////////////////////////////////////////////////////////
701 /**
702 .Function.addOption:
703 ..summary:Adds a @Class.CommandLineOption@ object to the @Class.CommandLineParser@.
704 ..cat:Miscellaneous
705 ..signature:addOption(parser, option)
706 ..param.parser:The @Class.CommandLineParser@ object.
707 ...type:Class.CommandLineParser
708 ..param.option:The new @Class.CommandLineOption@ object that should be added.
709 ...type:Class.CommandLineOption
710 ..include:seqan/misc/misc_cmdparser.h
711 */
712 
713 inline void
addOption(CommandLineParser & me,CommandLineOption const & opt)714 addOption(CommandLineParser & me, CommandLineOption const & opt)
715 {
716 	unsigned labelLen = length(argumentText(opt));
717     appendValue(me.optionMap, opt);
718     if (!empty(shortName(opt)))
719 	{
720 		insert(me.shortNameMap,shortName(opt), length(me.optionMap) - 1);
721 		unsigned width = 3 + length(shortName(opt));
722 		if (me.short_width < width)
723 			me.short_width = width;
724 		if (empty(longName(opt)))
725 		{
726 			width += 1 + length(argumentText(opt));
727 			if (me.full_width < width)
728 				me.full_width = width;
729 		}
730 	}
731     if (!empty(longName(opt)))
732 	{
733 		insert(me.longNameMap,longName(opt), length(me.optionMap) - 1);
734 		unsigned width = 3 + length(longName(opt)) + labelLen;
735 		if (me.long_width < width)
736 			me.long_width = width;
737 	}
738 }
739 
740 //////////////////////////////////////////////////////////////////////////////
741 /**
742 .Function.addLine:
743 ..summary:Adds a line of text to the help output of the @Class.CommandLineParser@.
744 ..cat:Miscellaneous
745 ..signature:addLine(parser, text)
746 ..param.parser:The @Class.CommandLineParser@ object.
747 ...type:Class.CommandLineParser
748 ..param.text:A line of text that will be added to the help output.
749 ...type:Shortcut.CharString
750 ..include:seqan/misc/misc_cmdparser.h
751 */
752 
753 template <typename TString>
754 inline void
addLine(CommandLineParser & me,TString const & line)755 addLine(CommandLineParser & me, TString const & line)
756 {
757 	addOption(me, CommandLineOption("", "", line, 0));
758 }
759 
760 //////////////////////////////////////////////////////////////////////////////
761 /**
762 .Function.addHelpLine:
763 ..summary:Adds an extra line of text below the help text of an option.
764 ..cat:Miscellaneous
765 ..signature:addHelpLine(parser, text)
766 ..param.parser:The @Class.CommandLineParser@ object.
767 ...type:Class.CommandLineParser
768 ..param.text:A line of text that will be added below the help text of an option.
769 ...type:Shortcut.CharString
770 ..include:seqan/misc/misc_cmdparser.h
771 */
772 
773 template <typename TString>
774 inline void
addHelpLine(CommandLineParser & me,TString const & line)775 addHelpLine(CommandLineParser & me, TString const & line)
776 {
777 	addOption(me, CommandLineOption("", "", line, 1));
778 }
779 
780 //////////////////////////////////////////////////////////////////////////////
781 /**
782 .Function.addSection:
783 ..summary:Adds a new section the help output of the @Class.CommandLineParser@.
784 ..cat:Miscellaneous
785 ..signature:addSection(parser, text)
786 ..param.parser:The @Class.CommandLineParser@ object.
787 ...type:Class.CommandLineParser
788 ..param.text:A section header that will be added to the help output.
789 ...type:Shortcut.CharString
790 ..include:seqan/misc/misc_cmdparser.h
791 */
792 
793 template <typename TString>
794 inline void
addSection(CommandLineParser & me,TString const & line)795 addSection(CommandLineParser & me, TString const & line)
796 {
797 	addLine(me, "");
798 	addLine(me, line);
799 }
800 
801 //////////////////////////////////////////////////////////////////////////////
802 /**
803 .Function.addTitleLine:
804 ..summary:Adds a line of text to the title output of the @Class.CommandLineParser@.
805 ..cat:Miscellaneous
806 ..signature:addTitleLine(parser, text)
807 ..param.parser:The @Class.CommandLineParser@ object.
808 ...type:Class.CommandLineParser
809 ..param.text:A text line that will be added to the title output.
810 ...type:Shortcut.CharString
811 ..include:seqan/misc/misc_cmdparser.h
812 */
813 
814 template <typename TString>
815 inline void
addTitleLine(CommandLineParser & me,TString const & line)816 addTitleLine(CommandLineParser & me, TString const & line)
817 {
818 	appendValue(me.titleText, line);
819 }
820 
821 //////////////////////////////////////////////////////////////////////////////
822 /**
823 .Function.addVersionLine:
824 ..summary:Adds a line of text to the version output of the @Class.CommandLineParser@.
825 ..cat:Miscellaneous
826 ..signature:addVersionLine(parser, text)
827 ..param.parser:The @Class.CommandLineParser@ object.
828 ...type:Class.CommandLineParser
829 ..param.text:A text line that will be added to the version output.
830 ...type:Shortcut.CharString
831 ..include:seqan/misc/misc_cmdparser.h
832 */
833 
834 template <typename TString>
835 inline void
addVersionLine(CommandLineParser & me,TString const & line)836 addVersionLine(CommandLineParser & me, TString const & line)
837 {
838 	if (empty(me.versionText))
839 		addOption(me, CommandLineOption("V", "version", "print version information", OptionType::Boolean));
840 	appendValue(me.versionText, line);
841 }
842 
843 //////////////////////////////////////////////////////////////////////////////
844 /**
845 .Function.addUsageLine:
846 ..summary:Adds a line of text to the usage output of the @Class.CommandLineParser@.
847 ..cat:Miscellaneous
848 ..signature:addUsageLine(parser, text)
849 ..param.parser:The @Class.CommandLineParser@ object.
850 ...type:Class.CommandLineParser
851 ..param.text:A text line that will be added to the usage output.
852 ...type:Shortcut.CharString
853 ..include:seqan/misc/misc_cmdparser.h
854 */
855 
856 inline void
addUsageLine(CommandLineParser & me,CharString const & line)857 addUsageLine(CommandLineParser & me, CharString const & line)
858 {
859     appendValue(me.usageText, line);
860 }
861 
862 //////////////////////////////////////////////////////////////////////////////
863 /**
864 .Function.hasOptionLong:
865 ..summary:Returns whether a certain long-name option is registered in the parser.
866 ..cat:Miscellaneous
867 ..signature:hasOptionLong(parser, optionIdentifier)
868 ..param.parser:The @Class.CommandLineParser@ object.
869 ...type:Class.CommandLineParser
870 ..param.optionIdentifier:A @Shortcut.CharString@ that identifies the long-name option.
871 ..returns:$true$ if the option is registered.
872 ..include:seqan/misc/misc_cmdparser.h
873 */
874 
875 inline bool
hasOptionLong(CommandLineParser const & me,CharString const & _long)876 hasOptionLong(CommandLineParser const & me, CharString const & _long)
877 {
878     return hasKey(me.longNameMap, _long);
879 }
880 
881 /**
882 .Function.hasOptionShort:
883 ..summary:Returns whether a certain short-name option is registered in the parser.
884 ..cat:Miscellaneous
885 ..signature:hasOptionShort(parser, optionIdentifier)
886 ..param.parser:The @Class.CommandLineParser@ object.
887 ...type:Class.CommandLineParser
888 ..param.optionIdentifier:A @Shortcut.CharString@ that identifies the short-name option.
889 ..returns:$true$ if the option is registered.
890 ..include:seqan/misc/misc_cmdparser.h
891 */
892 
893 inline bool
hasOptionShort(CommandLineParser const & me,CharString const & _short)894 hasOptionShort(CommandLineParser const & me, CharString const & _short)
895 {
896     return hasKey(me.shortNameMap, _short);
897 }
898 
899 
900 //////////////////////////////////////////////////////////////////////////////
901 /**
902 .Function.requiredArguments:
903 ..summary:Sets the number of arguments (non-parameterized options) are required by the program.
904 ..cat:Miscellaneous
905 ..signature:requiredArguments(parser, count)
906 ..param.parser:The @Class.CommandLineParser@ object.
907 ...type:Class.CommandLineParser
908 ..param.count:A $unsigned int$ defining the amount of non-parameterized options requried by the program.
909 ..include:seqan/misc/misc_cmdparser.h
910 */
911 
912 inline void
requiredArguments(CommandLineParser & me,unsigned count)913 requiredArguments(CommandLineParser & me, unsigned count)
914 {
915     me.required_arguments = count;
916 }
917 
918 
919 //////////////////////////////////////////////////////////////////////////////
920 
921 template <typename TStringSet, typename TStream>
922 inline void
_printStringSet(TStringSet const & set,TStream & target)923 _printStringSet(TStringSet const & set, TStream & target)
924 {
925     for(unsigned r = 0; r < length(set); ++r)
926     {
927         _streamWrite(target, set[r]);
928 		_streamPut(target, '\n');
929     }
930 }
931 
932 template <typename TStream>
933 inline void
_usage(CommandLineParser const & me,TStream & target)934 _usage(CommandLineParser const & me, TStream & target)
935 {
936 	_streamWrite(target, "Usage: ");
937 	if (empty(me.usageText))
938 	{
939 		_streamWrite(target, me.appName);
940 		_streamWrite(target, " [OPTION]... ");
941 		for (unsigned r = 0; r < me.required_arguments; ++r)
942 		{
943 			_streamWrite(target, "<ARG");
944 			_streamPutInt(target, r + 1);
945 			_streamWrite(target,"> ");
946 		}
947 		_streamPut(target,'\n');
948 	}
949 	else
950 	{
951 		for (unsigned r = 0; r < length(me.usageText); ++r)
952 		{
953 			if (r) _streamWrite(target, "       ");
954 			_streamWrite(target, me.appName);
955 			_streamPut(target, ' ');
956 			_streamWrite(target, me.usageText[r]);
957 			_streamPut(target,'\n');
958 		}
959 	}
960 }
961 
962 template <typename TStream>
963 inline void
_title(CommandLineParser const & me,TStream & target)964 _title(CommandLineParser const & me, TStream & target)
965 {
966 	_printStringSet(me.titleText, target);
967 }
968 
969 //////////////////////////////////////////////////////////////////////////////
970 /**
971 .Function.shortHelp:
972 ..summary:Prints a short help message for the parser to a stream
973 ..cat:Miscellaneous
974 ..signature:shortHelp(parser[, stream])
975 ..param.parser:The @Class.CommandLineParser@ object.
976 ...type:Class.CommandLineParser
977 ..param.stream:Target stream (e.g. $std::cerr$).
978 ..include:seqan/misc/misc_cmdparser.h
979 */
980 
981 template <typename TStream>
982 inline void
shortHelp(CommandLineParser const & me,TStream & target)983 shortHelp(CommandLineParser const & me, TStream & target)
984 {
985 	_title(me, target);
986     _usage(me, target);
987     _streamWrite(target, "Try '");
988     _streamWrite(target, me.appName);
989     _streamWrite(target, " --help' for more information.\n");
990 }
991 
992 template <typename TStream>
993 inline void
shortHelp(CommandLineParser const & me)994 shortHelp(CommandLineParser const & me)
995 {
996 	shortHelp(me, std::cerr);
997 }
998 
999 //////////////////////////////////////////////////////////////////////////////
1000 /**
1001 .Function.help:
1002 ..summary:Prints the complete help message for the parser to a stream.
1003 ..cat:Miscellaneous
1004 ..signature:help(parser[, stream])
1005 ..param.parser:The @Class.CommandLineParser@ object.
1006 ...type:Class.CommandLineParser
1007 ..param.stream:Target stream (e.g. $std::cerr$).
1008 ...default: $std::cerr$
1009 ..include:seqan/misc/misc_cmdparser.h
1010 */
1011 
1012 template <typename TStream>
1013 inline void
help(CommandLineParser const & me,TStream & target)1014 help(CommandLineParser const & me, TStream & target)
1015 {
1016 	_title(me, target);
1017     _streamPut(target, '\n');
1018     _usage(me,target);
1019     _streamPut(target, '\n');
1020 
1021     for (unsigned o = 0; o < length(me.optionMap); ++o)
1022     {
1023         const CommandLineOption & opt = me.optionMap[o];
1024         if (isHiddenOption(opt)) continue;								// do not print hidden options
1025 
1026 		if (opt.optionType > 0)
1027 		{
1028 			unsigned s = 0;
1029 			for (; s < me.padding_left; ++s)
1030 				_streamPut(target, ' ');
1031 
1032 			unsigned t1 = s + me.short_width;							// first tab
1033 			unsigned t2 = _max(t1 + me.long_width, me.full_width) + 1;	// second tab (one extra space looks better)
1034 
1035 			if (!empty(shortName(opt)))
1036 			{
1037 				_streamPut(target, '-');
1038 				_streamWrite(target, shortName(opt));
1039 				s += 1 + length(shortName(opt));
1040 				if (!empty(longName(opt)))
1041 				{
1042 					_streamPut(target, ',');
1043 					++s;
1044 				} else {
1045 					_streamWrite(target, argumentText(opt));
1046 					s += length(argumentText(opt));
1047 				}
1048 			}
1049 
1050 			for (; s < t1; ++s)
1051 				_streamPut(target, ' ');
1052 
1053 			if (!empty(longName(opt)))
1054 			{
1055 				_streamWrite(target, "--");
1056 				_streamWrite(target, longName(opt));
1057 				_streamWrite(target, argumentText(opt));
1058 				s += 2 + length(longName(opt)) + length(argumentText(opt));
1059 			}
1060 
1061 			for (; s < t2; ++s)
1062 				_streamPut(target, ' ');
1063 		}
1064 
1065 		_streamWrite(target, helpText(opt));
1066 
1067 /*
1068         if (s < me.line_width){
1069 			for (; s < me.line_width; ++s)
1070 				_streamPut(target, ' ');
1071             _streamWrite(target, helpText(opt));
1072         }
1073         else
1074         {
1075             _streamPut(target, '\n');
1076             s = 0;
1077 			for (; s < me.line_width; ++s)
1078 				_streamPut(target, ' ');
1079             _streamWrite(target, helpText(opt));
1080         }
1081 */
1082         _streamPut(target, '\n');
1083     }
1084 	_streamPut(target, '\n');
1085 }
1086 
1087 inline void
help(CommandLineParser const & me)1088 help(CommandLineParser const & me)
1089 {
1090     help(me, std::cerr);
1091 }
1092 
1093 //////////////////////////////////////////////////////////////////////////////
1094 /**
1095 .Function.version:
1096 ..summary:Prints a version text to a stream.
1097 ..cat:Miscellaneous
1098 ..signature:version(parser[, stream])
1099 ..param.parser:The @Class.CommandLineParser@ object.
1100 ...type:Class.CommandLineParser
1101 ..param.stream:Target stream (e.g. $std::cerr$).
1102 ...default: $std::cerr$
1103 ..include:seqan/misc/misc_cmdparser.h
1104 */
1105 
1106 template <typename TStream>
1107 inline void
version(CommandLineParser const & me,TStream & target)1108 version(CommandLineParser const & me, TStream & target)
1109 {
1110 	_printStringSet(me.versionText, target);
1111 }
1112 
1113 inline void
version(CommandLineParser const & me)1114 version(CommandLineParser const & me)
1115 {
1116     version(me,std::cerr);
1117 }
1118 
1119 //////////////////////////////////////////////////////////////////////////////
1120 /**
1121 .Function.isSetShort:
1122 ..summary:Returns whether a short-name option was set on the parsed command line.
1123 ..cat:Miscellaneous
1124 ..signature:isSetShort(parser,optionIdentifier)
1125 ..param.parser:The @Class.CommandLineParser@ object.
1126 ...type:Class.CommandLineParser
1127 ..param.optionIdentifier:A @Shortcut.CharString@ that identifies the short-name option.
1128 ..returns:$true$ if the option was set.
1129 ..include:seqan/misc/misc_cmdparser.h
1130 */
1131 
1132 inline bool
isSetShort(CommandLineParser & me,CharString const & shortName)1133 isSetShort(CommandLineParser & me, CharString const & shortName)
1134 {
1135     if (!hasKey(me.shortNameMap, shortName))
1136 		return false; // this option does not exist
1137 
1138 	// if value != "" -> value was set
1139 	return !empty(me.optionMap[cargo(me.shortNameMap, shortName)].value);
1140 }
1141 
1142 //////////////////////////////////////////////////////////////////////////////
1143 /**
1144 .Function.isSetLong:
1145 ..summary:Returns whether a long-name option was set on the parsed command line.
1146 ..cat:Miscellaneous
1147 ..signature:isSetLong(parser, optionIdentifier)
1148 ..param.parser:The @Class.CommandLineParser@ object.
1149 ...type:Class.CommandLineParser
1150 ..param.optionIdentifier:A @Shortcut.CharString@ that identifies the long-name option.
1151 ..returns:$true$ if the option was set.
1152 ..include:seqan/misc/misc_cmdparser.h
1153 */
1154 
1155 inline bool
isSetLong(CommandLineParser & me,CharString const & longName)1156 isSetLong(CommandLineParser & me,CharString const & longName)
1157 {
1158     if (!hasKey(me.longNameMap, longName))
1159 		return false; // this option does not exist
1160 
1161 	// if value != "" -> value was set
1162 	return !empty(me.optionMap[cargo(me.longNameMap, longName)].value);
1163 }
1164 
1165 //////////////////////////////////////////////////////////////////////////////
1166 
1167 inline bool
_allMandatorySet(CommandLineParser const & me)1168 _allMandatorySet(CommandLineParser const & me)
1169 {
1170     for (unsigned o = 0; o < length(me.optionMap); ++o)
1171         if (empty(me.optionMap[o].value) && isOptionMandatory(me.optionMap[o])) return false;
1172     return true;
1173 }
1174 
1175 //////////////////////////////////////////////////////////////////////////////
1176 
1177 inline CharString
_parseAppName(CharString const & candidate)1178 _parseAppName(CharString const & candidate)
1179 {
1180     int i = length(candidate) - 1;
1181 
1182     for(; i >= 0; --i)
1183         if (candidate[i] == '\\' || candidate[i] == '/')
1184             break;
1185 
1186     return suffix(candidate, i + 1);
1187 }
1188 
1189 //////////////////////////////////////////////////////////////////////////////
1190 
1191 template<typename TErrorStream>
1192 bool
_assignOptionValue(CommandLineParser & me,unsigned option_index,CharString const & val,unsigned argNo,TErrorStream & estream)1193 _assignOptionValue(CommandLineParser & me, unsigned option_index, CharString const & val, unsigned argNo, TErrorStream & estream)
1194 {
1195     // get the option object
1196     CommandLineOption & opt = me.optionMap[option_index];
1197     if(isDoubleOption(opt)){
1198         if(!_isDouble(val))
1199         {
1200             _streamWrite(estream,me.appName);
1201             _streamWrite(estream,": ");
1202             _streamWrite(estream, "\"");
1203             _streamWrite(estream, val);
1204             _streamWrite(estream, "\" is not a valid double value for '");
1205             _writeOptName(estream, opt);
1206             _streamWrite(estream, "'\n");
1207             return false;
1208         }
1209     }else if(isIntOption(opt)){
1210         if(!_isInt(val))
1211         {
1212             _streamWrite(estream,me.appName);
1213             _streamWrite(estream,": ");
1214             _streamWrite(estream, "\"");
1215             _streamWrite(estream, val);
1216             _streamWrite(estream, "\" is not a valid integer value for '");
1217             _writeOptName(estream, opt);
1218             _streamWrite(estream, "'\n");
1219             return false;
1220         }
1221     }
1222 	if (isOptionList(opt))
1223 		appendValue(opt.value, val, Generous());
1224 	else
1225 	{
1226 		if (argNo == 0) clear(opt.value);
1227 		appendValue(opt.value, val, Exact());
1228 	}
1229     return true;
1230 }
1231 
1232 template<typename TErrorStream>
1233 inline bool
_assignOptionValue(CommandLineParser & me,unsigned option_index,CharString const & val,TErrorStream & estream)1234 _assignOptionValue(CommandLineParser & me, unsigned option_index, CharString const & val, TErrorStream & estream)
1235 {
1236 	return _assignOptionValue(me, option_index, val, 0, estream);
1237 }
1238 
1239 //////////////////////////////////////////////////////////////////////////////
1240 /**
1241 .Function.parse:
1242 ..summary:Parses the command line.
1243 ..cat:Miscellaneous
1244 ..signature:parse(parser, argc, argv[, errorStream])
1245 ..param.parser:The @Class.CommandLineParser@ object.
1246 ...type:Class.CommandLineParser
1247 ..param.argc:Count of the objects on the command line.
1248 ..param.argv:Array of the different command line arguments ($const char *argv[]$).
1249 ..param.errorStream:A stream where error messages are sent to.
1250 ..remarks:Must be called before retrieving options or arguments.
1251 ..returns:$true$ if all required arguments are set and parseable and neither the help nor version argument is set.
1252 ..include:seqan/misc/misc_cmdparser.h
1253 */
1254 
1255 template<typename TErrorStream>
1256 bool
parse(CommandLineParser & me,int argc,const char * argv[],TErrorStream & estream)1257 parse(CommandLineParser & me, int argc, const char *argv[], TErrorStream & estream)
1258 {
1259     typedef Size<String<CommandLineOption> >::Type TOptionPosition;
1260     // if the appName wasn't set .. parse from command line
1261     if (empty(me.appName)) me.appName = _parseAppName(argv[0]);
1262 
1263     for (int i = 1; i < argc; ++i)
1264     {
1265         if (argv[i][0] == '-')  // this is possibly an option value
1266         {
1267             CharString inParam = argv[i];
1268             unsigned len = length(inParam);
1269 
1270             if (len == 1)
1271             {
1272                 _streamWrite(estream,me.appName);
1273                 _streamWrite(estream,": invalid option '-'\n");
1274                 return false;
1275             }
1276             else if (inParam[1] != '-') // maybe a combination of multiple bool opts
1277             {
1278                 for (unsigned s = 1; s < len; ++s)
1279 				{
1280 					unsigned e = len;
1281 					for (; s < e; --e)
1282 					{
1283 						if (hasOptionShort(me, infix(inParam, s, e)))
1284 						{
1285 							TOptionPosition option_index = cargo(me.shortNameMap, infix(inParam, s, e));
1286 							CommandLineOption const & opt = me.optionMap[option_index];
1287 							s = --e;
1288 							if (isBooleanOption(opt))
1289 								_assignOptionValue(me, option_index, "true", estream);
1290 							else
1291 							{
1292 								int firstArgIndex = 0;
1293 
1294 								if (e < len - 1)
1295 								{
1296 									// Try getting the first option argument from the remaining characters
1297 									// of this program argument. Use-case: immediately adjacent option
1298 									// values without separating space, as in `-x1` instead of `-x 1`.
1299 									if (!_assignOptionValue(me, option_index, suffix(inParam, e + 1), 0, estream)) return false;
1300 									firstArgIndex = 1;
1301 									s = len - 1;
1302 								}
1303 
1304 								if (i + opt.argumentsPerOption - firstArgIndex < argc)
1305 								{
1306 									for (int t = firstArgIndex; t < opt.argumentsPerOption; ++t)
1307 										if (!_assignOptionValue(me, option_index, argv[++i], t, estream)) return false;
1308 								}
1309 								else // no value available
1310 								{
1311 									_streamWrite(estream, me.appName);
1312 									_streamWrite(estream, ": \'");
1313 									_writeOptName(estream, opt);
1314 									_streamWrite(estream, "\' requires ");
1315 									_streamPutInt(estream, opt.argumentsPerOption);
1316 									_streamWrite(estream, " value(s)\n");
1317 									return false;
1318 								}
1319 							}
1320 						}
1321 					}
1322 					if (s == e)
1323 					{
1324                         _streamWrite(estream, me.appName);
1325                         _streamWrite(estream, ": invalid option '-");
1326                         _streamWrite(estream, suffix(inParam, s));
1327                         _streamWrite(estream, "\'\n");
1328                         return false;
1329 					}
1330 				}
1331             }
1332             else if (inParam[1] == '-') // this is a long option
1333             {
1334                 unsigned t = 2;
1335                 CharString longOpt, val;
1336                 for (; t < len && inParam[t] != '='; ++t)
1337 					appendValue(longOpt, inParam[t], Generous());
1338                 if (t < len) // this one is a --name=value option
1339 					val = suffix(inParam, t + 1);
1340 
1341                 // we may be got already a value
1342                 if (hasOptionLong(me, longOpt))
1343                 {
1344                     TOptionPosition option_index = cargo(me.longNameMap, longOpt);
1345                     CommandLineOption opt = me.optionMap[option_index];
1346 
1347                     if (!empty(val))
1348                     {
1349 						if (opt.argumentsPerOption == 1)
1350 						{
1351 							if (!_assignOptionValue(me, option_index, val, estream)) return false;
1352 						}
1353 						else
1354 						{
1355 							_streamWrite(estream, me.appName);
1356 							_streamWrite(estream, ": \'");
1357 							_writeOptName(estream, opt);
1358 							_streamWrite(estream, "\' requires ");
1359 							_streamPutInt(estream, opt.argumentsPerOption);
1360 							_streamWrite(estream, " values\n");
1361 							return false;
1362 						}
1363                     }
1364                     else if(isBooleanOption(opt))
1365                     {
1366 						_assignOptionValue(me, option_index, "true", estream);
1367                     }
1368                     else if (i + opt.argumentsPerOption < argc)
1369 					{
1370 						for (int t = 0; t < opt.argumentsPerOption; ++t)
1371 							if (!_assignOptionValue(me, option_index, argv[++i], t, estream)) return false;
1372 					}
1373 					else // no value available
1374 					{
1375 						_streamWrite(estream, me.appName);
1376 						_streamWrite(estream, ": \'");
1377 						_writeOptName(estream, opt);
1378 						_streamWrite(estream, "\' requires ");
1379 						_streamPutInt(estream, opt.argumentsPerOption);
1380 						_streamWrite(estream, " value(s)\n");
1381 						return false;
1382 					}
1383                 }
1384                 else
1385                 {
1386                     _streamWrite(estream, me.appName);
1387                     _streamWrite(estream, ": invalid option \'--");
1388                     _streamWrite(estream, longOpt);
1389                     _streamWrite(estream, "'\n");
1390                     return false;
1391                 }
1392             }
1393         }
1394         else
1395         { // this seems to be a normal argument
1396             appendValue(me.arguments,argv[i] );
1397         }
1398     }
1399 	if (isSetLong(me, "version"))
1400 	{
1401 		version(me, estream);
1402         return false;
1403 	}
1404     if (isSetLong(me, "help"))
1405     {
1406         help(me, estream);
1407         return false;
1408     }
1409 	if (argc == 1 && me.required_arguments > 0)
1410 	{
1411 		shortHelp(me, estream);	// print short help and exit
1412 		return 0;
1413 	}
1414 	return _allMandatorySet(me) && (length(me.arguments) >= me.required_arguments);
1415 }
1416 
1417 inline bool
parse(CommandLineParser & me,int argc,const char * argv[])1418 parse(CommandLineParser & me, int argc, const char *argv[])
1419 {
1420     return parse(me, argc, argv, std::cerr);
1421 }
1422 
1423 
1424 //////////////////////////////////////////////////////////////////////////////
1425 
1426 inline String<CharString> const &
_getOptionValues(CommandLineParser const & me,unsigned option_index)1427 _getOptionValues(CommandLineParser const & me, unsigned option_index)
1428 {
1429     CommandLineOption const & opt = me.optionMap[option_index];
1430 	if (empty(opt.value))
1431 		return opt.defaultValue;
1432 	else
1433 		return opt.value;
1434 }
1435 
1436 inline CharString const &
_getOptionValue(CommandLineParser const & me,unsigned option_index,unsigned argNo)1437 _getOptionValue(CommandLineParser const & me, unsigned option_index, unsigned argNo)
1438 {
1439     CommandLineOption const & opt = me.optionMap[option_index];
1440 	if (argNo < length(opt.value))
1441 		return opt.value[argNo];
1442 	else if (argNo < length(opt.defaultValue))
1443 		return opt.defaultValue[argNo];
1444 	else
1445 		return me.null;
1446 }
1447 
1448 inline CharString const &
_getOptionValue(CommandLineParser const & me,unsigned option_index)1449 _getOptionValue(CommandLineParser const & me, unsigned option_index)
1450 {
1451 	return _getOptionValue(me, option_index, 0);
1452 }
1453 
1454 //////////////////////////////////////////////////////////////////////////////
1455 
1456 inline bool
_convertOptionValue(CommandLineOption const & opt,bool & dst,CharString const & src)1457 _convertOptionValue(CommandLineOption const & opt, bool & dst, CharString const & src)
1458 {
1459     if (!isBooleanOption(opt)) return false;
1460 	dst = !empty(src);
1461 	return true;
1462 }
1463 
1464 inline bool
_convertOptionValue(CommandLineOption const & opt,int & dst,CharString const & src)1465 _convertOptionValue(CommandLineOption const & opt, int & dst, CharString const & src)
1466 {
1467     if (!isIntOption(opt)) return false;
1468 	std::istringstream stream(toCString(src));
1469 	return !(stream >> dst).fail();
1470 }
1471 
1472 inline bool
_convertOptionValue(CommandLineOption const & opt,unsigned int & dst,CharString const & src)1473 _convertOptionValue(CommandLineOption const & opt, unsigned int & dst, CharString const & src)
1474 {
1475     if (!isIntOption(opt)) return false;
1476 	std::istringstream stream(toCString(src));
1477 	return !(stream >> dst).fail();
1478 }
1479 
1480 inline bool
_convertOptionValue(CommandLineOption const & opt,__int64 & dst,CharString const & src)1481 _convertOptionValue(CommandLineOption const & opt, __int64 & dst, CharString const & src)
1482 {
1483     if (!isIntOption(opt)) return false;
1484 	std::istringstream stream(toCString(src));
1485 	return !(stream >> dst).fail();
1486 }
1487 
1488 inline bool
_convertOptionValue(CommandLineOption const & opt,__uint64 & dst,CharString const & src)1489 _convertOptionValue(CommandLineOption const & opt, __uint64 & dst, CharString const & src)
1490 {
1491     if (!isIntOption(opt)) return false;
1492 	std::istringstream stream(toCString(src));
1493 	return !(stream >> dst).fail();
1494 }
1495 
1496 inline bool
_convertOptionValue(CommandLineOption const & opt,float & dst,CharString const & src)1497 _convertOptionValue(CommandLineOption const & opt, float & dst, CharString const & src)
1498 {
1499     if (!isDoubleOption(opt)) return false;
1500 	std::istringstream stream(toCString(src));
1501 	return !(stream >> dst).fail();
1502 }
1503 
1504 inline bool
_convertOptionValue(CommandLineOption const & opt,double & dst,CharString const & src)1505 _convertOptionValue(CommandLineOption const & opt, double & dst, CharString const & src)
1506 {
1507     if (!isDoubleOption(opt)) return false;
1508 	std::istringstream stream(toCString(src));
1509 	return !(stream >> dst).fail();
1510 }
1511 
1512 template <typename TObject>
1513 inline bool
_convertOptionValue(CommandLineOption const & opt,TObject & dst,CharString const & src)1514 _convertOptionValue(CommandLineOption const & opt, TObject & dst, CharString const & src)
1515 {
1516     if (!isStringOption(opt)) return false;
1517 	assign(dst, src);
1518 	return true;
1519 }
1520 
1521 //////////////////////////////////////////////////////////////////////////////
1522 /**
1523 .Function.getOptionValueShort:
1524 ..summary:Retrieves the value of a short-name option given on the command line.
1525 ..cat:Miscellaneous
1526 ..signature:getOptionValueShort(parser, optionIdentifier[, argNo], value)
1527 ..param.parser:The @Class.CommandLineParser@ object.
1528 ...type:Class.CommandLineParser
1529 ..param.optionIdentifier:A @Shortcut.CharString@ that identifies the short-name of the option.
1530 ..param.argNo:If the option is list, the $argNo$-th list element is returned.
1531 ..param.value:The variable where the resulting value should be stored.
1532 ...remarks:The type of $value$ must be compatible the option type.
1533 ..returns: $true$ if the requested option is set and has the requested type, $false$ otherwise.
1534 ..include:seqan/misc/misc_cmdparser.h
1535 */
1536 
1537 template <typename TValue>
1538 inline bool
getOptionValueShort(CommandLineParser & me,CharString const & shortName,unsigned argNo,TValue & val)1539 getOptionValueShort(CommandLineParser & me, CharString const & shortName, unsigned argNo, TValue & val)
1540 {
1541     typedef Size<String<CommandLineOption> >::Type TOptionPosition;
1542 
1543     if (!hasOptionShort(me, shortName))
1544 	{
1545 		_streamWrite(std::cerr, me.appName);
1546 		_streamWrite(std::cerr, ": \'");
1547 		_streamWrite(std::cerr, shortName);
1548 		_streamWrite(std::cerr, "\' is not an option\n");
1549 		return false;
1550 	}
1551     TOptionPosition option_index = cargo(me.shortNameMap, shortName);
1552 	return _convertOptionValue(me.optionMap[option_index], val, _getOptionValue(me, option_index, argNo));
1553 }
1554 
1555 template <typename TValue>
1556 inline bool
getOptionValueShort(CommandLineParser & me,CharString const & shortName,TValue & val)1557 getOptionValueShort(CommandLineParser & me, CharString const & shortName, TValue & val)
1558 {
1559 	return getOptionValueShort(me, shortName, 0, val);
1560 }
1561 
1562 /**
1563 .Function.getOptionValuesShort:
1564 ..summary:Returns all values of a short-name option given on the command line.
1565 ..cat:Miscellaneous
1566 ..signature:getOptionValuesShort(parser, optionIdentifier)
1567 ..param.parser:The @Class.CommandLineParser@ object.
1568 ...type:Class.CommandLineParser
1569 ..param.optionIdentifier:A @Shortcut.CharString@ that identifies the short-name of the option.
1570 ..returns: A $String<CharString>$ of option values.
1571 ..include:seqan/misc/misc_cmdparser.h
1572 */
1573 
1574 inline String<CharString> const &
getOptionValuesShort(CommandLineParser & me,CharString const & shortName)1575 getOptionValuesShort(CommandLineParser & me,CharString const & shortName)
1576 {
1577     typedef Size<String<CommandLineOption> >::Type TOptionPosition;
1578 
1579     if (!hasOptionShort(me, shortName))
1580 	{
1581 		_streamWrite(std::cerr, me.appName);
1582 		_streamWrite(std::cerr, ": \'");
1583 		_streamWrite(std::cerr, shortName);
1584 		_streamWrite(std::cerr, "\' is not an option\n");
1585 		return me.nullSet;
1586 	}
1587     TOptionPosition option_index = cargo(me.shortNameMap, shortName);
1588 	return _getOptionValues(me, option_index);
1589 }
1590 
1591 //////////////////////////////////////////////////////////////////////////////
1592 /**
1593 .Function.getOptionValueLong:
1594 ..summary:Retrieves the value of a long-name option given on the command line.
1595 ..cat:Miscellaneous
1596 ..signature:getOptionValueLong(parser, optionIdentifier[, argNo], value)
1597 ..param.parser:The @Class.CommandLineParser@ object.
1598 ...type:Class.CommandLineParser
1599 ..param.optionIdentifier:A @Shortcut.CharString@ that identifies the long-name of the option.
1600 ..param.argNo:If the option is list, the $argNo$-th list element is returned.
1601 ..param.value:The variable where the resulting value should be stored.
1602 ...remarks:The type of $value$ must be compatible the option type.
1603 ..returns: $true$ if the requested option is set and has the requested type, $false$ otherwise.
1604 ..include:seqan/misc/misc_cmdparser.h
1605 */
1606 
1607 template <typename TValue>
1608 inline bool
getOptionValueLong(CommandLineParser & me,CharString const & longName,unsigned argNo,TValue & val)1609 getOptionValueLong(CommandLineParser & me, CharString const & longName, unsigned argNo, TValue & val)
1610 {
1611     typedef Size<String<CommandLineOption> >::Type TOptionPosition;
1612 
1613     if (!hasOptionLong(me, longName))
1614 	{
1615 		_streamWrite(std::cerr, me.appName);
1616 		_streamWrite(std::cerr, ": \'");
1617 		_streamWrite(std::cerr, longName);
1618 		_streamWrite(std::cerr, "\' is not an option\n");
1619 		return false;
1620 	}
1621     TOptionPosition option_index = cargo(me.longNameMap, longName);
1622 	return _convertOptionValue(me.optionMap[option_index], val, _getOptionValue(me, option_index, argNo));
1623 }
1624 
1625 template <typename TValue>
1626 inline bool
getOptionValueLong(CommandLineParser & me,CharString const & longName,TValue & val)1627 getOptionValueLong(CommandLineParser & me,CharString const & longName, TValue & val)
1628 {
1629 	return getOptionValueLong(me, longName, 0, val);
1630 }
1631 
1632 /**
1633 .Function.getOptionValuesLong:
1634 ..summary:Returns all values of a long-name option given on the command line.
1635 ..cat:Miscellaneous
1636 ..signature:getOptionValuesLong(parser, optionIdentifier)
1637 ..param.parser:The @Class.CommandLineParser@ object.
1638 ...type:Class.CommandLineParser
1639 ..param.optionIdentifier:A @Shortcut.CharString@ that identifies the long-name of the option.
1640 ..returns: A $String<CharString>$ of option values.
1641 ..include:seqan/misc/misc_cmdparser.h
1642 */
1643 
1644 inline String<CharString> const &
getOptionValuesLong(CommandLineParser & me,CharString const & longName)1645 getOptionValuesLong(CommandLineParser & me, CharString const & longName)
1646 {
1647     typedef Size<String<CommandLineOption> >::Type TOptionPosition;
1648 
1649     if (!hasOptionLong(me, longName))
1650 	{
1651 		_streamWrite(std::cerr, me.appName);
1652 		_streamWrite(std::cerr, ": \'");
1653 		_streamWrite(std::cerr, longName);
1654 		_streamWrite(std::cerr, "\' is not an option\n");
1655 		return me.nullSet;
1656 	}
1657     TOptionPosition option_index = cargo(me.longNameMap, longName);
1658 	return _getOptionValues(me, option_index);
1659 }
1660 
1661 //////////////////////////////////////////////////////////////////////////////
1662 /**
1663 .Function.getArgumentValue:
1664 ..summary:Returns an argument set on the command line.
1665 ..cat:Miscellaneous
1666 ..signature:getArgumentValue(parser, position)
1667 ..param.parser:The @Class.CommandLineParser@ object.
1668 ...type:Class.CommandLineParser
1669 ..param.position:A zero based $int$ indicating which argument you want to get.
1670 ..returns:The command line argument or an empty string if it doesn't exist.
1671 ...type:Shortcut.CharString
1672 ..include:seqan/misc/misc_cmdparser.h
1673 */
1674 
1675 inline CharString const &
getArgumentValue(CommandLineParser const & me,unsigned position)1676 getArgumentValue(CommandLineParser const & me, unsigned position)
1677 {
1678     if (position < length(me.arguments))
1679         return me.arguments[position];
1680     else
1681 		return me.null;
1682 }
1683 
1684 /**
1685 .Function.getArgumentValues:
1686 ..summary:Returns all arguments set on the command line.
1687 ..cat:Miscellaneous
1688 ..signature:getArgumentValues(parser)
1689 ..param.parser:The @Class.CommandLineParser@ object.
1690 ...type:Class.CommandLineParser
1691 ..returns:All command line arguments as a $String<CharString>$.
1692 ..see:Function.getArgumentValue
1693 ..include:seqan/misc/misc_cmdparser.h
1694 */
1695 
1696 inline String<CharString> const &
getArgumentValues(CommandLineParser const & me)1697 getArgumentValues(CommandLineParser const & me)
1698 {
1699 	return me.arguments;
1700 }
1701 
1702 //////////////////////////////////////////////////////////////////////////////
1703 /**
1704 .Function.argumentCount:
1705 ..summary:Returns the count of passed arguments.
1706 ..cat:Miscellaneous
1707 ..signature:argumentCount(parser)
1708 ..param.parser:The @Class.CommandLineParser@ object.
1709 ...type:Class.CommandLineParser
1710 ..include:seqan/misc/misc_cmdparser.h
1711 */
1712 
1713 inline Size<String<CharString> >::Type
argumentCount(CommandLineParser const & me)1714 argumentCount(CommandLineParser const & me)
1715 {
1716     return length(me.arguments);
1717 }
1718 
1719 
1720 } // end SEQAN_NAMESPACE_MAIN
1721 
1722 #endif
1723