1 // ==========================================================================
2 //                 SeqAn - The Library for Sequence Analysis
3 // ==========================================================================
4 // Copyright (c) 2006-2015, 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_INCLUDE_ARG_PARSE_ARGUMENT_PARSER_H_
34 #define SEQAN_INCLUDE_ARG_PARSE_ARGUMENT_PARSER_H_
35 
36 #include <seqan/map.h>
37 #include <seqan/sequence.h>
38 #include <seqan/stream.h>
39 
40 #include <seqan/arg_parse/arg_parse_type_support.h>
41 #include <seqan/arg_parse/arg_parse_argument.h>
42 #include <seqan/arg_parse/arg_parse_option.h>
43 
44 #include <seqan/arg_parse/tool_doc.h>
45 
46 #include <iostream>
47 #include <string>
48 #include <vector>
49 #include <map>
50 
51 namespace seqan {
52 
53 // ==========================================================================
54 // Forwards
55 // ==========================================================================
56 
57 // friend declaration to make addOption() and hideOption() available
58 // in ArgumentParser::init()
59 class ArgumentParser;
60 class ArgParseOption;
61 void addOption(ArgumentParser & me, ArgParseOption const & opt);
62 void hideOption(ArgumentParser & me, std::string const & name, bool hide);
63 void setValidValues(ArgumentParser & me, std::string const & name, std::string const & values);
64 
65 // Required in addOption() and addArgument().
66 inline void hideOption(ArgumentParser & me, std::string const & name, bool hide = true);
67 inline ArgParseOption & getOption(ArgumentParser & me, std::string const & name);
68 inline void setValidValues(ArgumentParser & me, std::string const & name, std::vector<std::string> const & values);
69 inline ArgParseArgument & getArgument(ArgumentParser & me, unsigned position);
70 
71 // ==========================================================================
72 // Tags, Classes, Enums
73 // ==========================================================================
74 
75 /*!
76  * @class ArgumentParser
77  * @headerfile <seqan/arg_parse.h>
78  * @brief Parse the command line.
79  *
80  * @signature class ArgumentParser;
81  *
82  * Options are stored as @link ArgParseOption @endlink and @link ArgParseArgument @endlink objects.
83  *
84  * @section Remarks
85  *
86  * See the documentation of @link ToolDoc @endlink on how to format text.  Wherever possible, formatting is added
87  * automatically for you.  You have to use formatting in the following places: (1) usage lines, (2) option help texts,
88  * (3) description and additional text sections.
89  *
90  * @section Examples
91  *
92  * The following gives a simple example of how to use the ArgumentParser class.
93  *
94  * @include demos/arg_parse/argument_parser.cpp
95  *
96  * @code{.console}
97  * $ demo_arg_parse_argument_parser in.fa out.txt --id 0
98  * Built target seqan_core
99  * Built target demo_arg_parse
100  * Verbose:     off
101  * Identity:    0
102  * Input-File:  in.fa
103  * Output-File: out.txt
104  * @endcode
105  *
106  * @see ArgParseArgument
107  * @see ArgParseOption
108  * @see ToolDoc
109  */
110 
111 /*!
112  * @fn ArgumentParser::ArgumentParser
113  * @brief Constructor
114  *
115  * @signature ArgumentParser::ArgumentParser([appName]);
116  *
117  * @param[in] appName The name of the application (<tt>std::string</tt>), defaults to <tt>argv[0]</tt>.
118  */
119 
120 /*!
121  * @enum ArgumentParser::ParseResult
122  * @brief Argument parsing result.
123  *
124  * @signature enum ArgumentParser::ParseResult;
125  *
126  * @val ArgumentParser::ParseResult ArgumentParser::PARSE_OK;
127  * @brief Parsing the program's arguments was successful and no builtin command was triggered.
128  *
129  * @val ArgumentParser::ParseResult ArgumentParser::PARSE_ERROR;
130  * @brief There were errors parsing the arguments.
131  *
132  * @val ArgumentParser::ParseResult ArgumentParser::PARSE_HELP;
133  * @brief Parsing was successful, built-in <tt>--help</tt> option was used.
134  *
135  * @val ArgumentParser::ParseResult ArgumentParser::PARSE_VERSION;
136  * @brief Parsing was successful, built-in <tt>--version</tt> option was used.
137  *
138  * @val ArgumentParser::ParseResult ArgumentParser::PARSE_WRITE_CTD;
139  * @brief Parsing was successful, built-in <tt>--write-ctd</tt> option was used.
140  *
141  * @val ArgumentParser::ParseResult ArgumentParser::PARSE_EXPORT_HELP;
142  * @brief Parsing was successful, built-in <tt>--export-help</tt> option was used.
143  */
144 
145 class ArgumentParser
146 {
147 public:
148 
149     // ----------------------------------------------------------------------------
150     // Enum ParseResult
151     // ----------------------------------------------------------------------------
152 
153     // will be used as return value of parse(..) to indicate whether parsing worked
154     enum ParseResult
155     {
156         PARSE_OK,
157         PARSE_ERROR,
158         PARSE_HELP,
159         PARSE_VERSION,
160         PARSE_WRITE_CTD,
161         PARSE_EXPORT_HELP
162     };
163 
164     // ----------------------------------------------------------------------------
165     // Class Typedefs
166     // ----------------------------------------------------------------------------
167 
168     typedef std::vector<ArgParseOption>   TOptionMap;
169     typedef std::vector<ArgParseArgument> TArgumentMap;
170     typedef Size<TOptionMap>::Type        TOptionMapSize;
171     typedef Size<TArgumentMap>::Type      TArgumentMapSize;
172 
173     typedef std::map<std::string, TOptionMapSize> TStringMap;
174     typedef std::vector<std::string>              TValueMap;
175 
176     // ----------------------------------------------------------------------------
177     // Mapping of option names to options
178     // ----------------------------------------------------------------------------
179 
180     TStringMap   shortNameMap;
181     TStringMap   longNameMap;
182     TOptionMap   optionMap;
183     TArgumentMap argumentList;
184 
185     // ----------------------------------------------------------------------------
186     // Documentation Members
187     // ----------------------------------------------------------------------------
188 
189     ToolDoc                  _toolDoc;      // the tool doc for all user specified
190                                             // text
191     std::vector<std::string> _description;  // the description which we need to
192                                             // separate to put it on top of the rest
193     std::vector<std::string> _usageText;    // the usage lines as strings, to avoid
194                                             // interference with the rest of the doc
195 
196     // ----------------------------------------------------------------------------
197     // Function init()
198     // ----------------------------------------------------------------------------
199 
init()200     void init()
201     {
202         addOption(*this, ArgParseOption("h", "help", "Displays this help message."));
203 
204         // hidden flags used for export of man pages and ctd formats
205         addOption(*this, ArgParseOption("",
206                                         "write-ctd",
207                                         "Exports the app's interface description to a .ctd file.",
208                                         ArgParseArgument::OUTPUT_FILE));
209         hideOption(*this, "write-ctd", true);
210 
211         addOption(*this, ArgParseOption("",
212                                         "export-help",
213                                         "Export help to a format. One of {'html', 'man', 'txt'}.",
214                                         ArgParseArgument::STRING,
215                                         "FORMAT"));
216         hideOption(*this, "export-help", true);
217         setValidValues(*this, "export-help", "html man txt");
218     }
219 
220     // ----------------------------------------------------------------------------
221     // Constructors
222     // ----------------------------------------------------------------------------
223 
ArgumentParser()224     ArgumentParser()
225     {
226         init();
227     }
228 
ArgumentParser(std::string const & _appName)229     ArgumentParser(std::string const & _appName)
230     {
231         setName(_toolDoc, _appName);
232         init();
233     }
234 
235 };
236 
237 // ==========================================================================
238 // Metafunctions
239 // ==========================================================================
240 
241 // ==========================================================================
242 // Functions
243 // ==========================================================================
244 
245 // ----------------------------------------------------------------------------
246 // Function hasOption()
247 // ----------------------------------------------------------------------------
248 
249 /*!
250  * @fn ArgumentParser#hasOption
251  * @headerfile <seqan/arg_parse.h>
252  * @brief Query whether a certain option is registered in the parser.
253  *
254  * @signature bool hasOption(parser, name);
255  *
256  * @param[in] parser The ArgumentParser to query.
257  * @param[in] name   The name to query for (<tt>std::string</tt>).
258  *
259  * @return bool <tt>true</tt> if there is such an option, <tt>false</tt> otherwise.
260  */
261 
hasOption(ArgumentParser const & me,std::string const & name)262 inline bool hasOption(ArgumentParser const & me, std::string const & name)
263 {
264     return hasKey(me.shortNameMap, name) || hasKey(me.longNameMap, name);
265 }
266 
267 // ----------------------------------------------------------------------------
268 // Function addOption()
269 // ----------------------------------------------------------------------------
270 
271 /*!
272  * @fn ArgumentParser#addOption
273  * @headerfile <seqan/arg_parse.h>
274  * @brief Adds an @link ArgParseOption @endlink to an ArgumentParser.
275  *
276  * @signature void addOption(parser, option);
277  *
278  * @param[in,out] parser The ArgumentParser to add the option to.
279  * @param[in]     option The ArgParseOption to add to <tt>parser</tt>.
280  */
281 
_copyValidValuesToFileExt(ArgumentParser & me,std::string const & name)282 inline void _copyValidValuesToFileExt(ArgumentParser & me, std::string const & name)
283 {
284     // Copy valid values, remove leading dots.
285     ArgParseOption & option = getOption(me, name);
286     if (isInputFileArgument(option) || isOutputFileArgument(option))
287     {
288         std::string longName = option.longName.empty() ? option.shortName : option.longName;
289         longName += "-file-ext";
290         std::vector<std::string> validValues = option.validValues;
291         for (unsigned i = 0; i < length(validValues); ++i)
292             if (!validValues[i].empty() && validValues[i][0] == '.')
293                 validValues[i].erase(0, 1);
294         setValidValues(me, longName, validValues);
295     }
296 }
297 
addOption(ArgumentParser & me,ArgParseOption const & opt)298 inline void addOption(ArgumentParser & me, ArgParseOption const & opt)
299 {
300     // check if an option with the same identifiers was already registered
301     SEQAN_CHECK(!hasOption(me, opt.shortName), "There already is an option with the name %s!", toCString(opt.shortName));
302     SEQAN_CHECK(!hasOption(me, opt.longName), "There already is an option with the name %s!", toCString(opt.longName));
303 
304     // finally append the option
305     appendValue(me.optionMap, opt);
306 
307     if (!empty(opt.shortName))
308         me.shortNameMap.insert(std::make_pair(opt.shortName, length(me.optionMap) - 1));
309     if (!empty(opt.longName))
310         me.longNameMap.insert(std::make_pair(opt.longName, length(me.optionMap) - 1));
311 
312     // handle the case of input and output option: add a string option --${name}-file-ext.
313     if (isInputFileArgument(opt) || isOutputFileArgument(opt))
314     {
315         std::string longName = opt.longName.empty() ? opt.shortName : opt.longName;
316         longName += "-file-ext";
317         std::string helpText = "Override file extension for --";
318         helpText += opt.longName;
319 
320         // Add option, copy list argument, number of allowed values.
321         addOption(me, ArgParseOption("", longName, helpText, ArgParseOption::STRING, "EXT",
322                                      isListArgument(opt), numberOfAllowedValues(opt)));
323         getOption(me, longName.c_str()).tags.push_back("file-ext-override");
324         getOption(me, longName.c_str()).tags.push_back("gkn-ignore");
325         // Hide option.
326         hideOption(me, longName);
327         // Copy valid values, remove leading dots.
328         _copyValidValuesToFileExt(me, opt.longName);
329     }
330 }
331 
332 // ----------------------------------------------------------------------------
333 // Function addArgument()
334 // ----------------------------------------------------------------------------
335 
336 /*!
337  * @fn ArgumentParser#addArgument
338  * @headerfile <seqan/arg_parse.h>
339  * @brief Adds an @link ArgParseArgument @endlink to an ArgumentParser.
340  *
341  * @signature void addArgument(parser, arg);
342  *
343  * @param[in,out] parser The ArgumentParser to add the argument to.
344  * @param[in]     arg    The ArgParseArgument to add to <tt>parser</tt>.
345  */
346 
_copyValidValuesToFileExt(ArgumentParser & me,unsigned no)347 inline void _copyValidValuesToFileExt(ArgumentParser & me, unsigned no)
348 {
349     // Copy valid values, remove leading dots.
350     ArgParseArgument & arg = getArgument(me, no);
351     if (isInputFileArgument(arg) || isOutputFileArgument(arg))
352     {
353         std::stringstream longNameSS;
354         longNameSS << "arg-" << (no + 1) << "-file-ext";
355         std::string longName = longNameSS.str();
356         std::vector<std::string> validValues = arg.validValues;
357         for (unsigned i = 0; i < length(validValues); ++i)
358             if (!validValues[i].empty() && validValues[i][0] == '.')
359                 validValues[i].erase(0, 1);
360         setValidValues(me, longName, validValues);
361     }
362 }
363 
addArgument(ArgumentParser & me,ArgParseArgument const & arg)364 inline void addArgument(ArgumentParser & me, ArgParseArgument const & arg)
365 {
366     // check previous arguments
367     //  .. lists can only be last argument
368     if (!me.argumentList.empty())
369     {
370         SEQAN_CHECK(!isListArgument(me.argumentList[me.argumentList.size() - 1]),
371                     "You cannot add an additional argument after a list argument.");
372     }
373 
374     // check current argument
375     //  .. arguments should not have default values
376     SEQAN_CHECK(arg.defaultValue.empty(), "Arguments cannot have default values.");
377     SEQAN_CHECK(arg._numberOfValues == 1, "n-Tuple of arguments are not supported.");
378 
379     me.argumentList.push_back(arg);
380 
381     // handle the case of input and output option: add a string option --${name}-file-ext.
382     if (isInputFileArgument(arg) || isOutputFileArgument(arg))
383     {
384         std::stringstream longNameSS;
385         longNameSS << "arg-" << me.argumentList.size() << "-file-ext";
386         std::string longName = longNameSS.str();
387         std::stringstream helpTextSS;
388         helpTextSS << "Override file extension for argument " << me.argumentList.size();
389         std::string helpText = helpTextSS.str();
390 
391         // Add option, copy list argument, number of allowed values.
392         addOption(me, ArgParseOption("", longName, helpText, ArgParseOption::STRING, "EXT",
393                                      isListArgument(arg), numberOfAllowedValues(arg)));
394         getOption(me, longName.c_str()).tags.push_back("file-ext-override");
395         getOption(me, longName.c_str()).tags.push_back("gkn-ignore");
396         // Hide option.
397         hideOption(me, longName);
398         // Copy valid values, remove leading dots.
399         _copyValidValuesToFileExt(me, me.argumentList.size() - 1);
400     }
401 }
402 
403 // ----------------------------------------------------------------------------
404 // Function _getOptionIndex()
405 // ----------------------------------------------------------------------------
406 // note that it is assumed that the option exists if this method is called
407 
_getOptionIndex(ArgumentParser const & me,std::string const & name)408 inline ArgumentParser::TOptionMapSize _getOptionIndex(ArgumentParser const & me,
409                                                       std::string const & name)
410 {
411     ArgumentParser::TOptionMapSize option_index;
412     if (me.shortNameMap.find(name) != me.shortNameMap.end())
413     {
414         option_index = me.shortNameMap.find(name)->second;
415     }
416     else
417     {
418         option_index = me.longNameMap.find(name)->second;
419     }
420     return option_index;
421 }
422 
423 // ----------------------------------------------------------------------------
424 // Function getOption()
425 // ----------------------------------------------------------------------------
426 
427 /*!
428  * @fn ArgumentParser#getOption
429  * @headerfile <seqan/arg_parse.h>
430  * @brief Returns a reference to the specified option.
431  *
432  * @signature TOption getOption(parser, name);
433  *
434  * @param[in] parser The parser to query.
435  * @param[in] name   The short or long name of the option (<tt>std::string</tt>).
436  *
437  * @return TOption Reference to the @link ArgParseOption @endlink with the given short or long name.
438  */
439 
getOption(ArgumentParser & me,std::string const & name)440 inline ArgParseOption & getOption(ArgumentParser & me, std::string const & name)
441 {
442     SEQAN_CHECK(hasOption(me, name), "Unknown option: %s", toCString(name));
443     return me.optionMap[_getOptionIndex(me, name)];
444 }
445 
getOption(ArgumentParser const & me,std::string const & name)446 inline ArgParseOption const & getOption(ArgumentParser const & me, std::string const & name)
447 {
448     SEQAN_CHECK(hasOption(me, name), "Unknown option: %s", toCString(name));
449     return me.optionMap[_getOptionIndex(me, name)];
450 }
451 
452 // ----------------------------------------------------------------------------
453 // Function setRequired()
454 // ----------------------------------------------------------------------------
455 
456 /*!
457  * @fn ArgumentParser#setRequired
458  * @headerfile <seqan/arg_parse.h>
459  * @brief Sets whether or not the option with the givne name is mandatory.
460  *
461  * @signature void setRequired(parser, name[, required]).
462  *
463  * @param[in,out] parser   The ArgumentParser to set the flag of.
464  * @param[in]     name     The short or long name of the option (<tt>std::string</tt>).
465  * @param[in]     required Whether or not the option is required (<tt>bool</tt>, default to <tt>true</tt>).
466  */
467 
468 inline void setRequired(ArgumentParser & me, std::string const & name, bool required = true)
469 {
470     SEQAN_CHECK(hasOption(me, name), "Unknown option: %s", toCString(name));
471     setRequired(getOption(me, name), required);
472 }
473 
474 // ----------------------------------------------------------------------------
475 // Function hideOption()
476 // ----------------------------------------------------------------------------
477 
478 /*!
479  * @fn ArgumentParser#hideOption
480  * @headerfile <seqan/arg_parse.h>
481  * @brief Hides the ArgParseOption with the given name.
482  *
483  * @signature void hideOption(parser, name[, hide]).
484  *
485  * @param[in,out] parser The ArgParseOption to the the hidden flag of.
486  * @param[in]     name   The short or long name of the option to modify.
487  * @param[in]     hide   Whether or not to hide the flag (<tt>bool</tt>, defaults to <tt>true</tt>).
488  */
489 
hideOption(ArgumentParser & me,std::string const & name,bool hide)490 inline void hideOption(ArgumentParser & me, std::string const & name, bool hide)
491 {
492     SEQAN_CHECK(hasOption(me, name), "Unknown option: %s", toCString(name));
493     hideOption(getOption(me, name), hide);
494 }
495 
496 // ----------------------------------------------------------------------------
497 // Function getArgument()
498 // ----------------------------------------------------------------------------
499 
500 /*!
501  * @fn ArgumentParser#getArgument
502  * @headerfile <seqan/arg_parse.h>
503  * @brief Returns a reference to the given positional argument.
504  *
505  * @signature TArgument getArgument(parser, pos);
506  *
507  * @param[in] parser The ArgumentParser to query.
508  * @param[in] pos    The position of the argument to return (<tt>unsigned</tt>, starting at 0).
509  *
510  * @return TArgument Reference to the @link ArgParseArgument @endlink with the given position.
511  */
512 
getArgument(ArgumentParser & me,unsigned position)513 inline ArgParseArgument & getArgument(ArgumentParser & me, unsigned position)
514 {
515     SEQAN_CHECK(position < me.argumentList.size(),
516                 "ArgumentParser: Only %d arguments available", me.argumentList.size());
517     return me.argumentList[position];
518 }
519 
getArgument(ArgumentParser const & me,unsigned position)520 inline ArgParseArgument const & getArgument(ArgumentParser const & me, unsigned position)
521 {
522     SEQAN_CHECK(position < me.argumentList.size(),
523                 "ArgumentParser: Only %d arguments available", me.argumentList.size());
524     return me.argumentList[position];
525 }
526 
527 // ----------------------------------------------------------------------------
528 // Function isSet()
529 // ----------------------------------------------------------------------------
530 
531 /*!
532  * @fn ArgumentParser#isSet
533  * @headerfile <seqan/arg_parse.h>
534  * @brief Query whether an option was set on the command line.
535  *
536  * @signature bool isSet(parser, name);
537  *
538  * @param[in] parser The ArgumentParser to query.
539  * @param[in] name   The short or long name of the option (<tt>std::string</tt>).
540  *
541  * @return bool Whether or not the option was set on the command line or not.
542  */
543 
isSet(ArgumentParser const & me,std::string const & name)544 inline bool isSet(ArgumentParser const & me, std::string const & name)
545 {
546     SEQAN_CHECK(hasOption(me, name), "Unknown option: %s", toCString(name));
547     return isSet(getOption(me, name));
548 }
549 
550 // ----------------------------------------------------------------------------
551 // Function hasDefault()
552 // ----------------------------------------------------------------------------
553 
554 /*!
555  * @fn ArgumentParser#hasDefault
556  * @headerfile <seqan/arg_parse.h>
557  * @brief Query whether an option has a default value.
558  *
559  * @signature bool hasDefault(parser, name);
560  *
561  * @param[in] parser The ArgumentParser to query.
562  * @param[in] name   The short or long name of the option (<tt>std::string</tt>).
563  *
564  * @return bool Whether or not the option has a default value.
565  */
566 
hasDefault(ArgumentParser const & me,std::string const & name)567 inline bool hasDefault(ArgumentParser const & me, std::string const & name)
568 {
569     SEQAN_CHECK(hasOption(me, name), "Unknown option: %s", toCString(name));
570     return hasDefault(getOption(me, name));
571 }
572 
573 // ----------------------------------------------------------------------------
574 // Function _allRequiredSet()
575 // ----------------------------------------------------------------------------
576 
_allRequiredSet(ArgumentParser const & me)577 inline bool _allRequiredSet(ArgumentParser const & me)
578 {
579     for (unsigned o = 0; o < length(me.optionMap); ++o)
580         if (!isSet(me.optionMap[o]) && isRequired(me.optionMap[o]))
581             return false;
582 
583     return true;
584 }
585 
586 // ----------------------------------------------------------------------------
587 // Function _allArgumentsSet()
588 // ----------------------------------------------------------------------------
589 
_allArgumentsSet(ArgumentParser const & me)590 inline bool _allArgumentsSet(ArgumentParser const & me)
591 {
592     for (unsigned a = 0; a < me.argumentList.size(); ++a)
593         if (!isSet(me.argumentList[a]))
594             return false;
595 
596     return true;
597 }
598 
599 // ----------------------------------------------------------------------------
600 // Function getOptionValue()
601 // ----------------------------------------------------------------------------
602 
603 /*!
604  * @fn ArgumentParser#getOptionValue
605  * @headerfile <seqan/arg_parse.h>
606  * @brief Retrieve the value of an option.
607  *
608  * @signature bool getOptionValue(dest, parser, name[, pos]);
609  *
610  * @param[in] dest   The variable to write the result to (the type is a template parameter and the value type of the
611  *                    option must be convertible in the type of <tt>dest</tt> for the retrieval to work, also see
612  *                    result value).
613  * @param[in] parser The ArgumentParser to get the value from.
614  * @param[in] name   The short or long name of the option (<tt>std::string</tt>).
615  * @param[in] pos    Optional position for multi-value options (<tt>unsigned</tt>, defaults to 0).
616  *
617  * @return bool <tt>true</tt> if the requested option was given on the command line and could be coverted to the type of
618  *              <tt>dest</tt>.
619  */
620 
621 template <typename TValue>
getOptionValue(TValue & val,ArgumentParser const & me,std::string const & name,unsigned argNo)622 inline bool getOptionValue(TValue & val,
623                            ArgumentParser const & me,
624                            std::string const & name,
625                            unsigned argNo)
626 {
627     SEQAN_CHECK(hasOption(me, name), "Unknown option: %s", toCString(name));
628 
629     if (isSet(me, name) || hasDefault(me, name))
630         return _convertArgumentValue(val,
631                                      getOption(me, name),
632                                      getArgumentValue(getOption(me, name), argNo));
633     else
634         return false;
635 }
636 
637 template <typename TValue>
getOptionValue(TValue & val,ArgumentParser const & me,std::string const & name)638 inline bool getOptionValue(TValue & val,
639                            ArgumentParser const & me,
640                            std::string const & name)
641 {
642     return getOptionValue(val, me, name, 0);
643 }
644 
645 // ----------------------------------------------------------------------------
646 // Function getOptionFileExtension()
647 // ----------------------------------------------------------------------------
648 
649 /*!
650  * @fn ArgumentParser#getOptionFileExtension
651  * @headerfile <seqan/arg_parse.h>
652  * @brief Retrieve the file extension of a file option.
653  *
654  * @signature std::string getOptionFileExtension(parser, name[, pos]);
655  *
656  * @param[in] parser The ArgumentParser to get the value from.
657  * @param[in] name   The short or long name of the option (<tt>std::string</tt>).
658  * @param[in] pos    Optional position for multi-value options (<tt>unsigned</tt>, defaults to 0).
659  *
660  * @return std::string The extension of the option. Empty if not set or no extension.
661  *
662  * @see ArgumentParser#getArgumentFileExtension
663  *
664  * @section Overriding File Extension on the Command Line
665  *
666  * For each option with type <tt>INPUT_FILE</tt> and <tt>OUTPUT_FILE</tt>, an option with the name
667  * <tt>${name}-file-ext</tt> is automatically added to the ArgumentParser (where <tt>${name}</tt> is the name
668  * of the original option).  The extension can be overridden by specifying the argument.  Thus, the user of
669  * the program could give the value "file.ext" to the parameter "fname" and override the extension on the
670  * command line to "ext2" as follows:
671  *
672  * @code{.console}
673  * # program_name --fname file.ext --fname-file-ext ext2
674  * @endcode
675  */
676 
677 inline std::string getOptionFileExtension(ArgumentParser const & me,
678                                           std::string const & name,
679                                           unsigned argNo = 0)
680 {
681     SEQAN_CHECK(hasOption(me, name), "Unknown option: %s", toCString(name));
682 
683     return getFileExtension(getOption(me, name), argNo);
684 }
685 
686 // ----------------------------------------------------------------------------
687 // Function getOptionValueCount()
688 // ----------------------------------------------------------------------------
689 
690 /*!
691  * @fn ArgumentParser#getOptionValueCount
692  * @headerfile <seqan/arg_parse.h>
693  * @brief Query number of values stored for the specified option.
694  *
695  * @signature unsigned getOptionValueCount(parser, name);
696  *
697  * @param[in] parser The ArgumentParser to query.
698  * @param[in] name   The short or long name of the option (<tt>string</tt>).
699  *
700  * @return unsigned The number of values for the option with the given name.
701  */
702 
getOptionValueCount(ArgumentParser const & me,std::string const & name)703 inline unsigned getOptionValueCount(ArgumentParser const & me, std::string const & name)
704 {
705     SEQAN_CHECK(hasOption(me, name), "Unknown option: %s", toCString(name));
706     return getArgumentValues(getOption(me, name)).size();
707 }
708 
709 // ----------------------------------------------------------------------------
710 // Function getArgumentValueCount()
711 // ----------------------------------------------------------------------------
712 
713 /*!
714  * @fn ArgumentParser#getArgumentValueCount
715  * @headerfile <seqan/arg_parse.h>
716  * @brief Query number of values stored for the specified argument.
717  *
718  * @signature unsigned getArgumentValueCount(parser, pos);
719  *
720  * @param[in] parser The ArgumentParser to query.
721  * @param[in] name   The position of the argument (<tt>unsigned</tt>, 0-based).
722  *
723  * @return unsigned The number of values for the argument with the given position.
724  */
725 
getArgumentValueCount(ArgumentParser const & me,unsigned argumentPosition)726 inline unsigned getArgumentValueCount(ArgumentParser const & me, unsigned argumentPosition)
727 {
728     SEQAN_CHECK(me.argumentList.size() > argumentPosition,
729                 "Argument Parser has only %d arguments.",
730                 me.argumentList.size());
731     return getArgumentValues(getArgument(me, argumentPosition)).size();
732 }
733 
734 // ----------------------------------------------------------------------------
735 // Function getArgumentValue()
736 // ----------------------------------------------------------------------------
737 
738 /*!
739  * @fn ArgumentParser#getArgumentValue
740  * @headerfile <seqan/arg_parse.h>
741  * @brief Retrieves the value of an argument given by its position.
742  *
743  * @signature bool getArgumentValue(dest, parser, pos[, no]);
744  *
745  * @param[in] dest   The variable to write the result to (the type is a template parameter and the value type of the
746  *                   argument must be convertible in the type of <tt>dest</tt> for the retrieval to work, also see
747  *                   result value).
748  * @param[in] parser The ArgumentParser to get the value from.
749  * @param[in] pos    The position of the argument to get the value of.
750  * @param[in] no     Optional position for multi-value arguments (<tt>unsigned</tt>, defaults to 0).
751  *
752  * @return bool <tt>true</tt> if the retrieval was successful, <tt>false</tt> otherwise.
753  */
754 
755 template <typename TValue>
getArgumentValue(TValue & value,ArgumentParser const & me,unsigned argumentPosition,unsigned argNo)756 inline bool getArgumentValue(TValue & value,
757                              ArgumentParser const & me,
758                              unsigned argumentPosition,
759                              unsigned argNo)
760 {
761     SEQAN_CHECK(me.argumentList.size() > argumentPosition,
762                 "Argument Parser has only %d arguments.",
763                 me.argumentList.size());
764     return _convertArgumentValue(value, getArgument(me, argumentPosition), getArgumentValue(getArgument(me, argumentPosition), argNo));
765 }
766 
767 template <typename TValue>
getArgumentValue(TValue & value,ArgumentParser const & me,unsigned argumentPosition)768 inline bool getArgumentValue(TValue & value,
769                              ArgumentParser const & me,
770                              unsigned argumentPosition)
771 {
772     return getArgumentValue(value, me, argumentPosition, 0);
773 }
774 
775 // ----------------------------------------------------------------------------
776 // Function getArgumentFileExtension()
777 // ----------------------------------------------------------------------------
778 
779 /*!
780  * @fn ArgumentParser#getArgumentFileExtension
781  * @headerfile <seqan/arg_parse.h>
782  * @brief Retrieve the file extension of a file argument.
783  *
784  * @signature std::string argumentFileExtension(parser, pos[, argNo]);
785  *
786  * @param[in] parser The ArgumentParser to get the value from.
787  * @param[in] pos    The position of the argument to query (<tt>unsigned</tt>).
788  * @param[in] argNo  Optional position for multi-value options (<tt>unsigned</tt>, defaults to 0).
789  *
790  * @return std::string The extension of the argument if any.
791  *
792  * @see ArgumentParser#getOptionFileExtension
793  *
794  * @section Overriding File Extensions on the Command Line
795  *
796  * For each argument with type <tt>INPUT_FILE</tt> and <tt>OUTPUT_FILE</tt>, an option with the index
797  * <tt>arg-${idx}-file-ext</tt> is automatically added to the ArgumentParser (where <tt>${idx}</tt> is the index
798  * of the original option).  The extension can be overridden by specifying the argument.  Thus, the user of
799  * the program could give the value "file.ext" to the parameter "0" and override the extension on the
800  * command line to "ext2" as follows:
801  *
802  * @code{.console}
803  * # program_name file.ext --arg-0-file-ext ext2
804  * @endcode
805  */
806 
807 inline std::string getArgumentFileExtension(ArgumentParser const & me,
808                                             unsigned argumentPosition,
809                                             unsigned argNo = 0)
810 {
811     SEQAN_CHECK(me.argumentList.size() > argumentPosition,
812                 "Argument Parser has only %d arguments.",
813                 me.argumentList.size());
814 
815 
816     return getFileExtension(getArgument(me, argumentPosition), argNo);
817 }
818 
819 // ----------------------------------------------------------------------------
820 // Function getOptionValues()
821 // ----------------------------------------------------------------------------
822 
823 /*!
824  * @fn ArgumentParser#getOptionValues
825  * @headerfile <seqan/arg_parse.h>
826  * @brief Returns all values of an option given on the command line.
827  *
828  * @signature TVector getOptionValues(parser, name);
829  *
830  * @param[in] parser The ArgumentParser to query.
831  * @param[in] name   The short or long name of the option to get (<tt>std::string</tt>).
832  *
833  * @return TVector The resulting values (<tt>std::vector&lt;std::string&gt;</tt>).
834  */
835 
getOptionValues(ArgumentParser const & me,std::string const & name)836 inline std::vector<std::string> const & getOptionValues(ArgumentParser const & me,
837                                                         std::string const & name)
838 {
839     SEQAN_CHECK(hasOption(me, name), "Unknown option: %s", toCString(name));
840     return getArgumentValues(getOption(me, name));
841 }
842 
843 // ----------------------------------------------------------------------------
844 // Function getArgumentValues()
845 // ----------------------------------------------------------------------------
846 
847 /*!
848  * @fn ArgumentParser#getArgumentValues
849  * @headerfile <seqan/arg_parse.h>
850  * @brief Returns all values of an argument given on the command line.
851  *
852  * @signature TVector getArgumentValues(parser, pos);
853  *
854  * @param[in] parser The ArgumentParser to query.
855  * @param[in] pos    The position of the argument (<tt>unsigned</tt>, 0-based).
856  *
857  * @return TVector The resulting values (<tt>std::vector&lt;std::string&gt;</tt>).
858  */
859 
getArgumentValues(ArgumentParser const & me,unsigned argumentPosition)860 inline std::vector<std::string> const & getArgumentValues(ArgumentParser const & me,
861                                                           unsigned argumentPosition)
862 {
863     SEQAN_CHECK(me.argumentList.size() > argumentPosition,
864                 "Argument Parser has only %d arguments.",
865                 me.argumentList.size());
866     return getArgumentValues(getArgument(me, argumentPosition));
867 }
868 
869 // ----------------------------------------------------------------------------
870 // Function setDefaultValue()
871 // ----------------------------------------------------------------------------
872 
873 /*!
874  * @fn ArgumentParser#setDefaultValue
875  * @headerfile <seqan/arg_parse.h>
876  * @brief Set the default value of an option of an ArgumentParser.
877  *
878  * @signature void setDefaultValue(parser, name, v);
879  *
880  * @param[in] parser The ArgumentParser to set the default value to.
881  * @param[in] name   The short or long name of the argument (<tt>std::string</tt>).
882  * @param[in] v      The value to set (template parameter, must be streamable into a <tt>std::stringstream</tt>).
883  */
884 
885 template <typename TValue>
setDefaultValue(ArgumentParser & me,std::string const & name,const TValue & value)886 inline void setDefaultValue(ArgumentParser & me,
887                             std::string const & name,
888                             const TValue & value)
889 {
890     SEQAN_CHECK(hasOption(me, name), "Unknown option: %s", toCString(name));
891     setDefaultValue(getOption(me, name), value);
892 }
893 
894 // ----------------------------------------------------------------------------
895 // Function addDefaultValue()
896 // ----------------------------------------------------------------------------
897 
898 /*!
899  * @fn ArgumentParser#addDefaultValue
900  * @headerfile <seqan/arg_parse.h>
901  * @brief Add/append a value to the default values for an option in an ArgumentParser.
902  *
903  * @signature void addDefaultValue(parser, name, v);
904  *
905  * @param[in,out] parser The ArgumentParser to append the default value to.
906  * @param[in]     name   The short or long name of the argument (<tt>std::string</tt>).
907  * @param[in]     v      The value to append (template parameter, must be streamable into a <tt>std::stringstream</tt>).
908  */
909 
910 template <typename TValue>
addDefaultValue(ArgumentParser & me,std::string const & name,const TValue & value)911 inline void addDefaultValue(ArgumentParser & me,
912                             std::string const & name,
913                             const TValue & value)
914 {
915     SEQAN_CHECK(hasOption(me, name), "Unknown option: %s", toCString(name));
916     addDefaultValue(getOption(me, name), value);
917 }
918 
919 // ----------------------------------------------------------------------------
920 // Function setMinValue()
921 // ----------------------------------------------------------------------------
922 
923 /*!
924  * @fn ArgumentParser#setMinValue
925  * @headerfile <seqan/arg_parse.h>
926  * @brief Set smallest allowed value for an option or argument of an ArgumentParser.
927  *
928  * @signature void setMinValue(parser, name, v);
929  * @signature void setMinValue(parser, pos, v);
930  *
931  * @param[in,out] parser The ArgumentParser to set the minimal value for.
932  * @param[in]     name   The name of the option to set the minimal value for (<tt>std::string</tt>).
933  * @param[in]     pos    The position of the argument to set the minimal value for (<tt>unsigned</tt>, 0-based).
934  * @param[in]     v      The minimal value to set (<tt>std::string</tt>).
935  *
936  * @section Remarks
937  *
938  * The option/argument must have an integer or double type.
939  */
940 
setMinValue(ArgumentParser & me,std::string const & name,std::string const & _minValue)941 inline void setMinValue(ArgumentParser & me,
942                         std::string const & name,
943                         std::string const & _minValue)
944 {
945     SEQAN_CHECK(hasOption(me, name), "Unknown option: %s", toCString(name));
946     setMinValue(getOption(me, name), _minValue);
947 }
948 
setMinValue(ArgumentParser & me,unsigned argumentPosition,std::string const & _minValue)949 inline void setMinValue(ArgumentParser & me,
950                         unsigned argumentPosition,
951                         std::string const & _minValue)
952 {
953     SEQAN_CHECK(me.argumentList.size() > argumentPosition,
954                 "Argument Parser has only %d arguments.",
955                 me.argumentList.size());
956     setMinValue(getArgument(me, argumentPosition), _minValue);
957 }
958 
959 // ----------------------------------------------------------------------------
960 // Function setMaxValue()
961 // ----------------------------------------------------------------------------
962 
963 /*!
964  * @fn ArgumentParser#setMaxValue
965  * @headerfile <seqan/arg_parse.h>
966  * @brief Set largest allowed value for an option or argument of an ArgumentParser.
967  *
968  * @signature void setMaxValue(parser, name, v);
969  * @signature void setMaxValue(parser, pos, v);
970  *
971  * @param[in,out] parser The ArgumentParser to set the maximal value for.
972  * @param[in]     name   The name of the option to set the maximal value for (<tt>std::string</tt>).
973  * @param[in]     pos    The position of the argument to set the maximal value for (<tt>unsigned</tt>, 0-based).
974  * @param[in]     v      The maximal value to set (<tt>std::string</tt>).
975  *
976  * @section Remarks
977  *
978  * The option/argument must have an integer or double type.
979  */
980 
setMaxValue(ArgumentParser & me,std::string const & name,std::string const & _maxValue)981 inline void setMaxValue(ArgumentParser & me,
982                         std::string const & name,
983                         std::string const & _maxValue)
984 {
985     SEQAN_CHECK(hasOption(me, name), "Unknown option: %s", toCString(name));
986     setMaxValue(getOption(me, name), _maxValue);
987 }
988 
setMaxValue(ArgumentParser & me,unsigned argumentPosition,std::string const & _minValue)989 inline void setMaxValue(ArgumentParser & me,
990                         unsigned argumentPosition,
991                         std::string const & _minValue)
992 {
993     SEQAN_CHECK(me.argumentList.size() > argumentPosition,
994                 "Argument Parser has only %d arguments.",
995                 me.argumentList.size());
996     setMaxValue(getArgument(me, argumentPosition), _minValue);
997 }
998 
999 // ----------------------------------------------------------------------------
1000 // Function setValidValues()
1001 // ----------------------------------------------------------------------------
1002 
1003 /*!
1004  * @fn ArgumentParser#setValidValues
1005  * @headerfile <seqan/arg_parse.h>
1006  * @brief Set valid values for an argumetn or option of an ArgumentParser.
1007  *
1008  * @signature void setValidValues(parser, name, values);
1009  * @signature void setValidValues(parser, pos, values);
1010  *
1011  * @param[in,out] parser The ArgumentParser to set the default values to.
1012  * @param[in]     name   The name of the option (<tt>std::string</tt>).
1013  * @param[in]     pos    The position of the argument (<tt>unsigned</tt>, 0-based).
1014  * @param[in]     values The values to set.  Either a <tt>std::string</tt> with the values as space-separated list
1015  *                       or a <tt>std::vector&lt;std::string&gt;</tt> with the values.
1016  */
1017 
setValidValues(ArgumentParser & me,std::string const & name,std::vector<std::string> const & values)1018 inline void setValidValues(ArgumentParser & me,
1019                            std::string const & name,
1020                            std::vector<std::string> const & values)
1021 {
1022     SEQAN_CHECK(hasOption(me, name), "Unknown option: %s", toCString(name));
1023     setValidValues(getOption(me, name), values);
1024     _copyValidValuesToFileExt(me, name);
1025 }
1026 
setValidValues(ArgumentParser & me,std::string const & name,std::string const & values)1027 inline void setValidValues(ArgumentParser & me,
1028                            std::string const & name,
1029                            std::string const & values)
1030 {
1031     SEQAN_CHECK(hasOption(me, name), "Unknown option: %s", toCString(name));
1032     setValidValues(getOption(me, name), values);
1033     _copyValidValuesToFileExt(me, name);
1034 }
1035 
setValidValues(ArgumentParser & me,unsigned argumentPosition,std::vector<std::string> const & values)1036 inline void setValidValues(ArgumentParser & me,
1037                            unsigned argumentPosition,
1038                            std::vector<std::string> const & values)
1039 {
1040     SEQAN_CHECK(me.argumentList.size() > argumentPosition,
1041                 "Argument Parser has only %d arguments.",
1042                 me.argumentList.size());
1043     setValidValues(getArgument(me, argumentPosition), values);
1044     _copyValidValuesToFileExt(me, argumentPosition);
1045 }
1046 
setValidValues(ArgumentParser & me,unsigned argumentPosition,std::string const & values)1047 inline void setValidValues(ArgumentParser & me,
1048                            unsigned argumentPosition,
1049                            std::string const & values)
1050 {
1051     SEQAN_CHECK(me.argumentList.size() > argumentPosition,
1052                 "Argument Parser has only %d arguments.",
1053                 me.argumentList.size());
1054     setValidValues(getArgument(me, argumentPosition), values);
1055     _copyValidValuesToFileExt(me, argumentPosition);
1056 }
1057 
1058 // ----------------------------------------------------------------------------
1059 // Function setHelpText()
1060 // ----------------------------------------------------------------------------
1061 
1062 /*!
1063  * @fn ArgumentParser#setHelpText
1064  * @headerfile <seqan/arg_parse.h>
1065  * @brief Set the help text of an option or argument.
1066  *
1067  * @signature void setHelpText(parser, name, text);
1068  * @signature void setHelpText(parser, pos, text);
1069  *
1070  * @param[in,out] parser The ArgumentParser object.
1071  * @param[in]     name   The name of the option to set the help text for (<tt>std::string</tt>).
1072  * @param[in]     pos    The position of the argument to set the help text for.
1073  * @param[in]     text   The string to use for the help text (<tt>std::string</tt>).
1074  */
1075 
setHelpText(ArgumentParser & me,std::string const & name,std::string const & text)1076 inline void setHelpText(ArgumentParser & me,
1077                         std::string const & name,
1078                         std::string const & text)
1079 {
1080     SEQAN_CHECK(hasOption(me, name), "Unknown option: %s", toCString(name));
1081     setHelpText(getOption(me, name), text);
1082 }
1083 
setHelpText(ArgumentParser & me,unsigned argumentPosition,std::string const & text)1084 inline void setHelpText(ArgumentParser & me,
1085                         unsigned argumentPosition,
1086                         std::string const & text)
1087 {
1088     SEQAN_CHECK(me.argumentList.size() > argumentPosition,
1089                 "Argument Parser has only %d arguments.",
1090                 me.argumentList.size());
1091     setHelpText(getArgument(me, argumentPosition), text);
1092 }
1093 
1094 // ----------------------------------------------------------------------------
1095 // Function getFileExtensions()
1096 // ----------------------------------------------------------------------------
1097 
1098 /*!
1099  * @fn ArgumentParser#getFileExtensions
1100  * @headerfile <seqan/arg_parse.h>
1101  * @brief Returns file format extension given a format tag.
1102  *
1103  * @signature TVector getFormatExtension(tag);
1104  * @signature TVector getFormatExtension(tagList);
1105  * @signature TVector getFormatExtension(tagSelector);
1106  *
1107  * @param[in] tag         A single file foramt, e.g. <tt>Fastq()</tt>.
1108  * @param[in] tagList     A list of file format (@link TagList @endlink).
1109  * @param[in] tagSelector A file format selector (@link TagSelector @endlink).
1110  *
1111  * @return TVector A <tt>std::vector&lt;std::string&gt;</tt> with the allowed file format extensions.
1112  */
1113 
1114 template <typename T>
1115 inline std::vector<std::string>
getFileExtensions(T const formatTag)1116 getFileExtensions(T const formatTag)
1117 {
1118     std::vector<std::string> extensions;
1119     _getFileExtensions(extensions, formatTag);
1120     return extensions;
1121 }
1122 
1123 
1124 }  // namespace seqan
1125 
1126 #endif // SEQAN_INCLUDE_ARG_PARSE_ARGUMENT_PARSER_H_
1127