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