FEAT 3
Finite Element Analysis Toolbox
Loading...
Searching...
No Matches
simple_arg_parser.hpp
1// FEAT3: Finite Element Analysis Toolbox, Version 3
2// Copyright (C) 2010 by Stefan Turek & the FEAT group
3// FEAT3 is released under the GNU General Public License version 3,
4// see the file 'copyright.txt' in the top level directory for details.
5
6#pragma once
7
8// includes, FEAT
9#include <kernel/util/string.hpp>
10#include <kernel/util/string_mapped.hpp>
11
12// includes, system
13#include <deque>
14#include <map>
15#include <utility>
16
17namespace FEAT
18{
140 {
141 private:
145 std::deque<String> _args;
147 std::map<String, std::pair<int, std::deque<String> > > _opts;
149 std::map<String, String> _supported;
150
151 public:
161 explicit SimpleArgParser(int argc, const char* const * const argv) :
163 _args(),
164 _opts()
165 {
166 for(int i(0); i < argc; ++i)
167 _args.push_back(String(argv[i]));
168 _process();
169 }
170
176 int num_args() const
177 {
178 return int(_args.size());
179 }
180
187 {
188 return _num_skipped_args;
189 }
190
200 String get_arg(int i) const
201 {
202 if((i < 0) || (i >= int(_args.size())))
203 return String();
204 return _args.at(std::size_t(i));
205 }
206
210 std::deque<String> skipped_args() const
211 {
212 std::deque<String> dsa;
213 for(std::size_t i(0); i < std::size_t(_num_skipped_args); ++i)
214 dsa.push_back(_args.at(i));
215 return dsa;
216 }
217
237 void support(const String& option, const String& description = String())
238 {
239 _supported.emplace(option, description);
240 }
241
268 String get_supported_help(bool double_newline = true) const
269 {
270 String s;
271 for(auto it = _supported.begin(); it != _supported.end(); ++it)
272 {
273 if(!s.empty())
274 s += (double_newline ? "\n\n" : "\n");
275 s += "--" + it->first + " " + it->second;
276 }
277 return s;
278 }
279
292 std::deque<std::pair<int,String> > query_unsupported() const
293 {
294 std::deque<std::pair<int,String> > result;
295
296 // loop over all given options
297 for(auto it = _opts.begin(); it != _opts.end(); ++it)
298 {
299 // get the option name and its index
300 String name = it->first;
301 int idx = it->second.first;
302
303 // does the option start with a triple-hyphen? if so then don't check it
304 if(name.starts_with('-'))
305 continue;
306
307 // check whether we support that option
308 if(_supported.find(name) == _supported.end())
309 {
310 // unsupported option; so push it
311 result.push_back(std::make_pair(idx, name));
312 }
313 }
314
315 // return our result
316 return result;
317 }
318
329 int check(const String& option) const
330 {
331 auto it =_opts.find(option);
332 if(it == _opts.end())
333 return -1;
334 return int(it->second.second.size());
335 }
336
356 const std::pair<int, std::deque<String> >* query(const String& option) const
357 {
358 auto it = _opts.find(option);
359 if(it == _opts.end())
360 return nullptr;
361 return &(it->second);
362 }
363
383 template<typename... Prms_>
384 int parse(const String& option, Prms_&&... prms) const
385 {
386 // try to find the option
387 auto it = _opts.find(option);
388 if(it == _opts.end())
389 return 0;
390
391 // try to parse arguments
392 return _parse(it->second, std::size_t(0), std::forward<Prms_>(prms)...);
393 }
394
407 template<typename T_>
408 T_ parse_default(const String& option, T_ default_value) const
409 {
410 T_ val(default_value);
411 return parse(option, val) == 1 ? val : default_value;
412 }
413
414 private:
416 void _process()
417 {
418 // get an option iterator
419 auto opt = _opts.end();
420
421 // we definitely skip the first argument
423
424 // loop over all arguments
425 for(int i(1); i < int(_args.size()); ++i)
426 {
427 // get the trimmed argument
428 String arg = _args.at(std::size_t(i)).trim();
429
430 // does it start with '--' ?
431 if((arg.size() > std::size_t(1)) && (arg[0] == '-') && (arg[1] == '-'))
432 {
433 // it's an option
434 String optname = arg.substr(2).trim();
435
436 // let's insert it
437 auto ik = _opts.insert(std::make_pair(optname, std::make_pair(i, std::deque<String>())));
438 opt = ik.first;
439
440 // clear existing deque
441 if(!ik.second)
442 {
443 // option was already given, so overwrite it
444 opt->second.first = i;
445 opt->second.second.clear();
446 }
447 }
448 else if(opt != _opts.end())
449 {
450 // push this argument as a parameter for the last processed option
451 opt->second.second.push_back(arg);
452 }
453 else
454 {
455 // We did not process any options yet, so we skip this argument
456 _num_skipped_args = i + 1;
457 }
458 }
459 }
460
461 template<typename Prm_>
462 int _parse_prm(const std::pair<int,std::deque<String> >& isd, std::size_t offset, Prm_&& prm) const
463 {
464 // check whether we have another parameter
465 if(offset >= isd.second.size())
466 return 0;
467
468 // try to parse the argument
469 if(isd.second.at(offset).parse(std::forward<Prm_>(prm)))
470 return +1; // success
471 else
472 return -isd.first - int(offset) - 1; // fail; return negative argument index
473 }
474
475 // overload for StringMapped
476 template<typename ValueType_>
477 int _parse_prm(const std::pair<int,std::deque<String> >& isd, std::size_t offset, StringMapped<ValueType_>&& prm) const
478 {
479 // check whether we have another parameter
480 if(offset >= isd.second.size())
481 return 0;
482
483 // try to parse the argument
484 if(prm.lookup(isd.second.at(offset)))
485 return +1; // success
486 else
487 return -isd.first - int(offset) - 1; // fail; return negative argument index
488 }
489
490 template<typename Prm1_>
491 int _parse(const std::pair<int,std::deque<String> >& isd, std::size_t offset, Prm1_&& prm1) const
492 {
493 int rtn = _parse_prm(isd, offset, std::forward<Prm1_>(prm1));
494 if(rtn > 0)
495 {
496 // parse successful; no more arguments to be parsed
497 return int(offset) + 1;
498 }
499 else if(rtn == 0)
500 {
501 // parameter missing
502 return int(offset);
503 }
504 else
505 {
506 // failed to parse
507 return rtn;
508 }
509 }
510
511 template<typename Prm1_, typename... Prms_>
512 int _parse(const std::pair<int,std::deque<String> >& isd, std::size_t offset, Prm1_&& prm1, Prms_&&... prms) const
513 {
514 int rtn = _parse_prm(isd, offset, std::forward<Prm1_>(prm1));
515 if(rtn > 0)
516 {
517 // parse successful; continue parsing remaining parameters
518 return _parse(isd, ++offset, std::forward<Prms_>(prms)...);
519 }
520 else if(rtn == 0)
521 {
522 // no more parameters, quit here
523 return int(offset);
524 }
525 else
526 {
527 // failed to parse
528 return rtn;
529 }
530 }
532 }; // class SimpleArgParser
533} // namespace FEAT
Simple argument parser implementation.
SimpleArgParser(int argc, const char *const *const argv)
Constructor.
std::map< String, String > _supported
supported option set
std::deque< String > _args
command line arguments
int num_skipped_args() const
Returns the number of arguments skipped by the parser.
int check(const String &option) const
Checks whether an option was given.
std::map< String, std::pair< int, std::deque< String > > > _opts
option-parameter map
T_ parse_default(const String &option, T_ default_value) const
Parses a single parameter of an option and returns it or, if not given, a default value.
String get_supported_help(bool double_newline=true) const
Returns a string of all supported options and their help strings.
String get_arg(int i) const
Returns an argument.
std::deque< String > skipped_args() const
Returns a deque of all arguments skipped by the parser.
const std::pair< int, std::deque< String > > * query(const String &option) const
Query the parameters of an option.
std::deque< std::pair< int, String > > query_unsupported() const
Queries all unsupported options passed in the command line.
void support(const String &option, const String &description=String())
Adds an option to the set of supported options.
int parse(const String &option, Prms_ &&... prms) const
Parses the parameters of an option.
int _num_skipped_args
number of skipped arguments
int num_args() const
Returns the total number of arguments passed in the constructor.
String class implementation.
Definition: string.hpp:46
bool starts_with(const String &head) const
Checks whether this string starts with another string.
Definition: string.hpp:731
String trim(const String &charset) const
Trims the string.
Definition: string.hpp:327
FEAT namespace.
Definition: adjactor.hpp:12