C++ Utilities  4.10.0
Common C++ classes and routines used by my applications such as argument parser, IO and conversion utilities
argumentparser.h
Go to the documentation of this file.
1 #ifndef APPLICATION_UTILITIES_ARGUMENTPARSER_H
2 #define APPLICATION_UTILITIES_ARGUMENTPARSER_H
3 
4 #include "../global.h"
5 
6 #include <functional>
7 #include <initializer_list>
8 #include <limits>
9 #include <vector>
10 #ifdef DEBUG_BUILD
11 #include <cassert>
12 #endif
13 
15 
17 
18 CPP_UTILITIES_EXPORT extern const char *applicationName;
19 CPP_UTILITIES_EXPORT extern const char *applicationAuthor;
20 CPP_UTILITIES_EXPORT extern const char *applicationVersion;
21 CPP_UTILITIES_EXPORT extern const char *applicationUrl;
22 CPP_UTILITIES_EXPORT extern std::initializer_list<const char *> dependencyVersions;
23 
30 #ifndef APP_STATICALLY_LINKED
31 #define SET_DEPENDENCY_INFO ::ApplicationUtilities::dependencyVersions = DEPENCENCY_VERSIONS
32 #else
33 #define SET_DEPENDENCY_INFO ::ApplicationUtilities::dependencyVersions = STATIC_DEPENCENCY_VERSIONS
34 #endif
35 
41 #define SET_APPLICATION_INFO \
42  ::ApplicationUtilities::applicationName = APP_NAME; \
43  ::ApplicationUtilities::applicationAuthor = APP_AUTHOR; \
44  ::ApplicationUtilities::applicationVersion = APP_VERSION; \
45  ::ApplicationUtilities::applicationUrl = APP_URL; \
46  SET_DEPENDENCY_INFO
47 
48 CPP_UTILITIES_EXPORT extern void (*exitFunction)(int);
49 
50 class Argument;
51 class ArgumentParser;
53 
54 typedef std::initializer_list<Argument *> ArgumentInitializerList;
55 typedef std::vector<Argument *> ArgumentVector;
56 typedef std::function<bool(Argument *)> ArgumentPredicate;
57 
63  Ignore,
64  Warn,
65  Fail
66 };
67 
77 enum class ValueCompletionBehavior : unsigned char {
78  None = 0,
79  PreDefinedValues = 2,
80  Files = 4,
81  Directories = 8,
83  AppendEquationSign = 32,
84  InvokeCallback = 64,
85 };
86 
89 {
90  return static_cast<ValueCompletionBehavior>(static_cast<unsigned char>(lhs) | static_cast<unsigned char>(rhs));
91 }
92 
94 {
95  return static_cast<bool>(static_cast<unsigned char>(lhs) & static_cast<unsigned char>(rhs));
96 }
98 
99 Argument CPP_UTILITIES_EXPORT *firstPresentUncombinableArg(const ArgumentVector &args, const Argument *except);
100 
105  ArgumentOccurrence(std::size_t index);
106  ArgumentOccurrence(std::size_t index, const std::vector<Argument *> parentPath, Argument *parent);
107 
111  std::size_t index;
112 
116  std::vector<const char *> values;
117 
122  std::vector<Argument *> path;
123 };
124 
128 inline ArgumentOccurrence::ArgumentOccurrence(std::size_t index)
129  : index(index)
130 {
131 }
132 
141 inline ArgumentOccurrence::ArgumentOccurrence(std::size_t index, const std::vector<Argument *> parentPath, Argument *parent)
142  : index(index)
143  , path(parentPath)
144 {
145  if (parent) {
146  path.push_back(parent);
147  }
148 }
149 
151  friend ArgumentParser;
152  friend ArgumentReader;
153  friend ArgumentParserTests;
154 
155 public:
156  typedef std::function<void(const ArgumentOccurrence &)> CallbackFunction;
157 
158  Argument(const char *name, char abbreviation = '\0', const char *description = nullptr, const char *example = nullptr);
159  ~Argument();
160 
161  const char *name() const;
162  void setName(const char *name);
163  char abbreviation() const;
164  void setAbbreviation(char abbreviation);
165  const char *environmentVariable() const;
166  void setEnvironmentVariable(const char *environmentVariable);
167  const char *description() const;
168  void setDescription(const char *description);
169  const char *example() const;
170  void setExample(const char *example);
171  const std::vector<const char *> &values(std::size_t occurrence = 0) const;
172  const char *firstValue() const;
173  std::size_t requiredValueCount() const;
174  void setRequiredValueCount(std::size_t requiredValueCount);
175  const std::vector<const char *> &valueNames() const;
176  void setValueNames(std::initializer_list<const char *> valueNames);
177  void appendValueName(const char *valueName);
178  bool allRequiredValuesPresent(std::size_t occurrence = 0) const;
179  bool isPresent() const;
180  std::size_t occurrences() const;
181  std::size_t index(std::size_t occurrence) const;
182  std::size_t minOccurrences() const;
183  std::size_t maxOccurrences() const;
184  void setConstraints(std::size_t minOccurrences, std::size_t maxOccurrences);
185  const std::vector<Argument *> &path(std::size_t occurrence = 0) const;
186  bool isRequired() const;
187  void setRequired(bool required);
188  bool isCombinable() const;
189  void setCombinable(bool value);
190  bool isImplicit() const;
191  void setImplicit(bool value);
192  bool denotesOperation() const;
193  void setDenotesOperation(bool denotesOperation);
194  void setCallback(CallbackFunction callback);
195  void printInfo(std::ostream &os, unsigned char indentation = 0) const;
196  const ArgumentVector &subArguments() const;
197  void setSubArguments(const ArgumentInitializerList &subArguments);
198  void addSubArgument(Argument *arg);
199  bool hasSubArguments() const;
200  const ArgumentVector parents() const;
201  bool isMainArgument() const;
202  bool isParentPresent() const;
203  ValueCompletionBehavior valueCompletionBehaviour() const;
204  void setValueCompletionBehavior(ValueCompletionBehavior valueCompletionBehaviour);
205  const char *preDefinedCompletionValues() const;
206  void setPreDefinedCompletionValues(const char *preDefinedCompletionValues);
207  Argument *conflictsWithArgument() const;
208  Argument *wouldConflictWithArgument() const;
209  Argument *specifiedOperation() const;
210  void reset();
211  void resetRecursively();
212 
217  static constexpr std::size_t varValueCount = std::numeric_limits<std::size_t>::max();
218 
219 private:
220  const char *m_name;
221  char m_abbreviation;
222  const char *m_environmentVar;
223  const char *m_description;
224  const char *m_example;
225  std::size_t m_minOccurrences;
226  std::size_t m_maxOccurrences;
227  bool m_combinable;
228  bool m_denotesOperation;
229  std::size_t m_requiredValueCount;
230  std::vector<const char *> m_valueNames;
231  bool m_implicit;
232  std::vector<ArgumentOccurrence> m_occurrences;
233  ArgumentVector m_subArgs;
234  CallbackFunction m_callbackFunction;
235  ArgumentVector m_parents;
236  bool m_isMainArg;
237  ValueCompletionBehavior m_valueCompletionBehavior;
238  const char *m_preDefinedCompletionValues;
239 };
240 
242  friend ArgumentParserTests;
243  friend ArgumentReader;
244 
245 public:
246  ArgumentParser();
247 
248  const ArgumentVector &mainArguments() const;
249  void setMainArguments(const ArgumentInitializerList &mainArguments);
250  void addMainArgument(Argument *argument);
251  void printHelp(std::ostream &os) const;
252  void parseArgs(int argc, const char *const *argv);
253  void parseArgsOrExit(int argc, const char *const *argv);
254  void readArgs(int argc, const char *const *argv);
255  void resetArgs();
256  unsigned int actualArgumentCount() const;
257  const char *executable() const;
258  UnknownArgumentBehavior unknownArgumentBehavior() const;
259  void setUnknownArgumentBehavior(UnknownArgumentBehavior behavior);
260  Argument *defaultArgument() const;
261  void setDefaultArgument(Argument *argument);
262  Argument *specifiedOperation() const;
263  void checkConstraints();
264  void invokeCallbacks();
265  bool isUncombinableMainArgPresent() const;
266 
267 private:
268  IF_DEBUG_BUILD(void verifyArgs(const ArgumentVector &args, std::vector<char> abbreviations, std::vector<const char *> names);)
269  void printBashCompletion(int argc, const char *const *argv, unsigned int cursorPos, const ArgumentReader &reader);
270  void checkConstraints(const ArgumentVector &args);
271  static void invokeCallbacks(const ArgumentVector &args);
272 
273  ArgumentVector m_mainArgs;
274  unsigned int m_actualArgc;
275  const char *m_executable;
276  UnknownArgumentBehavior m_unknownArgBehavior;
277  Argument *m_defaultArg;
278 };
279 
285 inline const char *Argument::name() const
286 {
287  return m_name;
288 }
289 
297 inline void Argument::setName(const char *name)
298 {
299 #ifdef DEBUG_BUILD
300  if (name && *name) {
301  assert(*name != '-');
302  for (const char *c = name; *c; ++c) {
303  assert(*c != ' ' && *c != '=' && *c != '\'' && *c != '\"' && *c != '\n' && *c != '\r');
304  }
305  }
306 #endif
307  m_name = name;
308 }
309 
315 inline char Argument::abbreviation() const
316 {
317  return m_abbreviation;
318 }
319 
327 inline void Argument::setAbbreviation(char abbreviation)
328 {
329  IF_DEBUG_BUILD(assert(abbreviation != ' ' && abbreviation != '=' && abbreviation != '-' && abbreviation != '\'' && abbreviation != '"'
330  && abbreviation != '\n' && abbreviation != '\r'));
331  m_abbreviation = abbreviation;
332 }
333 
338 inline const char *Argument::environmentVariable() const
339 {
340  return m_environmentVar;
341 }
342 
347 inline void Argument::setEnvironmentVariable(const char *environmentVariable)
348 {
349  m_environmentVar = environmentVariable;
350 }
351 
357 inline const char *Argument::description() const
358 {
359  return m_description;
360 }
361 
367 inline void Argument::setDescription(const char *description)
368 {
369  m_description = description;
370 }
371 
377 inline const char *Argument::example() const
378 {
379  return m_example;
380 }
381 
387 inline void Argument::setExample(const char *example)
388 {
389  m_example = example;
390 }
391 
398 inline const std::vector<const char *> &Argument::values(std::size_t occurrence) const
399 {
400  return m_occurrences[occurrence].values;
401 }
402 
416 inline std::size_t Argument::requiredValueCount() const
417 {
418  return m_requiredValueCount;
419 }
420 
433 inline void Argument::setRequiredValueCount(std::size_t requiredValueCount)
434 {
435  m_requiredValueCount = requiredValueCount;
436 }
437 
446 inline const std::vector<const char *> &Argument::valueNames() const
447 {
448  return m_valueNames;
449 }
450 
464 inline void Argument::setValueNames(std::initializer_list<const char *> valueNames)
465 {
466  m_valueNames.assign(valueNames);
467 }
468 
475 inline void Argument::appendValueName(const char *valueName)
476 {
477  m_valueNames.emplace_back(valueName);
478 }
479 
483 inline bool Argument::allRequiredValuesPresent(std::size_t occurrence) const
484 {
485  return m_requiredValueCount == static_cast<std::size_t>(-1)
486  || (m_occurrences[occurrence].values.size() >= static_cast<std::size_t>(m_requiredValueCount));
487 }
488 
493 inline bool Argument::isImplicit() const
494 {
495  return m_implicit;
496 }
497 
502 inline void Argument::setImplicit(bool implicit)
503 {
504  m_implicit = implicit;
505 }
506 
510 inline bool Argument::isPresent() const
511 {
512  return !m_occurrences.empty();
513 }
514 
518 inline std::size_t Argument::occurrences() const
519 {
520  return m_occurrences.size();
521 }
522 
526 inline std::size_t Argument::index(std::size_t occurrence) const
527 {
528  return m_occurrences[occurrence].index;
529 }
530 
536 inline std::size_t Argument::minOccurrences() const
537 {
538  return m_minOccurrences;
539 }
540 
546 inline std::size_t Argument::maxOccurrences() const
547 {
548  return m_maxOccurrences;
549 }
550 
556 inline void Argument::setConstraints(std::size_t minOccurrences, std::size_t maxOccurrences)
557 {
558  m_minOccurrences = minOccurrences;
559  m_maxOccurrences = maxOccurrences;
560 }
561 
565 inline const std::vector<Argument *> &Argument::path(std::size_t occurrence) const
566 {
567  return m_occurrences[occurrence].path;
568 }
569 
579 inline bool Argument::isRequired() const
580 {
581  return m_minOccurrences;
582 }
583 
591 inline void Argument::setRequired(bool required)
592 {
593  if (required) {
594  if (!m_minOccurrences) {
595  m_minOccurrences = 1;
596  }
597  } else {
598  m_minOccurrences = 0;
599  }
600 }
601 
610 inline bool Argument::isCombinable() const
611 {
612  return m_combinable;
613 }
614 
623 inline void Argument::setCombinable(bool value)
624 {
625  m_combinable = value;
626 }
627 
638 inline bool Argument::denotesOperation() const
639 {
640  return m_denotesOperation;
641 }
642 
647 inline void Argument::setDenotesOperation(bool denotesOperation)
648 {
649  m_denotesOperation = denotesOperation;
650 }
651 
658 {
659  m_callbackFunction = callback;
660 }
661 
668 inline const ArgumentVector &Argument::subArguments() const
669 {
670  return m_subArgs;
671 }
672 
679 inline bool Argument::hasSubArguments() const
680 {
681  return !m_subArgs.empty();
682 }
683 
694 inline const ArgumentVector Argument::parents() const
695 {
696  return m_parents;
697 }
698 
705 inline bool Argument::isMainArgument() const
706 {
707  return m_isMainArg;
708 }
709 
714 {
715  return m_valueCompletionBehavior;
716 }
717 
722 {
723  m_valueCompletionBehavior = completionValues;
724 }
725 
729 inline const char *Argument::preDefinedCompletionValues() const
730 {
731  return m_preDefinedCompletionValues;
732 }
733 
737 inline void Argument::setPreDefinedCompletionValues(const char *preDefinedCompletionValues)
738 {
739  m_preDefinedCompletionValues = preDefinedCompletionValues;
740 }
741 
745 inline void Argument::reset()
746 {
747  m_occurrences.clear();
748 }
749 
754 inline const ArgumentVector &ArgumentParser::mainArguments() const
755 {
756  return m_mainArgs;
757 }
758 
762 inline unsigned int ArgumentParser::actualArgumentCount() const
763 {
764  return m_actualArgc;
765 }
766 
770 inline const char *ArgumentParser::executable() const
771 {
772  return m_executable;
773 }
774 
781 {
782  return m_unknownArgBehavior;
783 }
784 
791 {
792  m_unknownArgBehavior = behavior;
793 }
794 
800 {
801  return m_defaultArg;
802 }
803 
809 {
810  m_defaultArg = argument;
811 }
812 
819 {
820  checkConstraints(m_mainArgs);
821 }
822 
828 {
829  invokeCallbacks(m_mainArgs);
830 }
831 
833 public:
834  HelpArgument(ArgumentParser &parser);
835 };
836 
838 public:
839  OperationArgument(const char *name, char abbreviation = '\0', const char *description = nullptr, const char *example = nullptr);
840 };
841 
842 inline OperationArgument::OperationArgument(const char *name, char abbreviation, const char *description, const char *example)
843  : Argument(name, abbreviation, description, example)
844 {
845  setDenotesOperation(true);
846 }
847 
849 public:
850  ConfigValueArgument(const char *name, char abbreviation = '\0', const char *description = nullptr,
851  std::initializer_list<const char *> valueNames = std::initializer_list<const char *>());
852 };
853 
858  const char *name, char abbreviation, const char *description, std::initializer_list<const char *> valueNames)
859  : Argument(name, abbreviation, description)
860 {
861  setCombinable(true);
862  setRequiredValueCount(valueNames.size());
863  setValueNames(valueNames);
864 }
865 } // namespace ApplicationUtilities
866 
867 #endif // APPLICATION_UTILITIES_ARGUMENTPARSER_H
bool isMainArgument() const
Returns an indication whether the argument is used as main argument.
std::function< bool(Argument *)> ArgumentPredicate
CPP_UTILITIES_EXPORT const char * applicationUrl
Specifies the URL to the application website (used by ArgumentParser::printHelp()).
ValueCompletionBehavior
The ValueCompletionBehavior enum specifies the items to be considered when generating completion for ...
const char * preDefinedCompletionValues() const
Returns the assigned values used when generating completion for the values.
bool denotesOperation() const
Returns whether the argument denotes the operation.
UnknownArgumentBehavior unknownArgumentBehavior() const
Returns how unknown arguments are treated.
The ConfigValueArgument class is an Argument where setCombinable() is true by default.
std::initializer_list< Argument * > ArgumentInitializerList
#define IF_DEBUG_BUILD(x)
Wraps debug-only lines conveniently.
Definition: global.h:130
Argument * defaultArgument() const
Returns the default argument.
std::size_t requiredValueCount() const
Returns the number of values which are required to be given for this argument.
void setImplicit(bool value)
Sets whether the argument is an implicit argument.
const char * description() const
Returns the description of the argument.
std::size_t index
The index of the occurrence.
void setCombinable(bool value)
Sets whether this argument can be combined.
ValueCompletionBehavior valueCompletionBehaviour() const
Returns the items to be considered when generating completion for the values.
void setUnknownArgumentBehavior(UnknownArgumentBehavior behavior)
Sets how unknown arguments are treated.
const ArgumentVector parents() const
Returns the parents of this argument.
Contains currently only ArgumentParser and related classes.
std::size_t maxOccurrences() const
Returns the maximum number of occurrences.
constexpr DirectoryEntryType operator|(DirectoryEntryType lhs, DirectoryEntryType rhs)
Definition: path.h:28
bool isRequired() const
Returns an indication whether the argument is mandatory.
Argument CPP_UTILITIES_EXPORT * firstPresentUncombinableArg(const ArgumentVector &args, const Argument *except)
This function return the first present and uncombinable argument of the given list of arguments...
void setRequired(bool required)
Sets whether this argument is mandatory or not.
std::size_t index(std::size_t occurrence) const
Returns the indices of the argument&#39;s occurences which could be detected when parsing.
std::function< void(const ArgumentOccurrence &)> CallbackFunction
void setDefaultArgument(Argument *argument)
Sets the default argument.
CPP_UTILITIES_EXPORT const char * applicationVersion
Specifies the version of the application (used by ArgumentParser::printHelp()).
ConfigValueArgument(const char *name, char abbreviation='\0', const char *description=nullptr, std::initializer_list< const char *> valueNames=std::initializer_list< const char *>())
Constructs a new ConfigValueArgument with the specified parameter.
void invokeCallbacks()
Invokes all assigned callbacks.
The ArgumentParserTests class tests the ArgumentParser and Argument classes.
void checkConstraints()
Checks whether contraints are violated.
const char * name() const
Returns the name of the argument.
const std::vector< const char * > & valueNames() const
Returns the names of the requried values.
The OperationArgument class is an Argument where denotesOperation() is true by default.
void setConstraints(std::size_t minOccurrences, std::size_t maxOccurrences)
Sets the allowed number of occurrences.
const ArgumentVector & subArguments() const
Returns the secondary arguments for this argument.
std::size_t minOccurrences() const
Returns the minimum number of occurrences.
void setAbbreviation(char abbreviation)
Sets the abbreviation of the argument.
void setDescription(const char *description)
Sets the description of the argument.
void setValueCompletionBehavior(ValueCompletionBehavior valueCompletionBehaviour)
Sets the items to be considered when generating completion for the values.
void appendValueName(const char *valueName)
Appends a value name.
CPP_UTILITIES_EXPORT std::initializer_list< const char * > dependencyVersions
Specifies the dependency versions the application was linked against (used by ArgumentParser::printHe...
const std::vector< const char * > & values(std::size_t occurrence=0) const
Returns the parameter values for the specified occurrence of argument.
CPP_UTILITIES_EXPORT void(* exitFunction)(int)
Specifies a function quit the application.
const char * executable() const
Returns the name of the current executable.
std::size_t occurrences() const
Returns how often the argument could be detected when parsing.
The Argument class is a wrapper for command line argument information.
void setCallback(CallbackFunction callback)
Sets a callback function which will be called by the parser if the argument could be found and no par...
void setExample(const char *example)
Sets the a usage example for the argument.
const std::vector< Argument * > & path(std::size_t occurrence=0) const
Returns the path of the specified occurrence.
bool isCombinable() const
Returns an indication whether the argument is combinable.
void setPreDefinedCompletionValues(const char *preDefinedCompletionValues)
Assignes the values to be used when generating completion for the values.
std::vector< Argument * > path
The "path" of the occurrence (the parent elements which have been specified before).
UnknownArgumentBehavior
The UnknownArgumentBehavior enum specifies the behavior of the argument parser when an unknown argume...
OperationArgument(const char *name, char abbreviation='\0', const char *description=nullptr, const char *example=nullptr)
void setEnvironmentVariable(const char *environmentVariable)
Sets the environment variable queried when firstValue() is called.
The ArgumentOccurrence struct holds argument values for an occurrence of an argument.
CPP_UTILITIES_EXPORT const char * applicationName
Specifies the name of the application (used by ArgumentParser::printHelp()).
bool isPresent() const
Returns an indication whether the argument could be detected when parsing.
bool hasSubArguments() const
Returns an indication whether the argument has secondary arguments.
The HelpArgument class prints help information for an argument parser when present (–help...
bool allRequiredValuesPresent(std::size_t occurrence=0) const
Returns an indication whether all required values are present.
const ArgumentVector & mainArguments() const
Returns the main arguments.
void setDenotesOperation(bool denotesOperation)
Sets whether the argument denotes the operation.
char abbreviation() const
Returns the abbreviation of the argument.
const char * example() const
Returns the usage example of the argument.
void reset()
Resets occurrences (indices, values and paths).
ArgumentOccurrence(std::size_t index)
Constructs an argument occurrence for the specified index.
void setRequiredValueCount(std::size_t requiredValueCount)
Sets the number of values which are required to be given for this argument.
CPP_UTILITIES_EXPORT const char * applicationAuthor
Specifies the author of the application (used by ArgumentParser::printHelp()).
The ArgumentReader class internally encapsulates the process of reading command line arguments...
#define CPP_UTILITIES_EXPORT
Marks the symbol to be exported by the c++utilities library.
const char * environmentVariable() const
Returns the environment variable queried when firstValue() is called.
unsigned int actualArgumentCount() const
Returns the actual number of arguments that could be found when parsing.
void setName(const char *name)
Sets the name of the argument.
bool isImplicit() const
Returns an indication whether the argument is an implicit argument.
The ArgumentParser class provides a means for handling command line arguments.
void setValueNames(std::initializer_list< const char *> valueNames)
Sets the names of the requried values.
std::vector< Argument * > ArgumentVector
constexpr DirectoryEntryType operator &(DirectoryEntryType lhs, DirectoryEntryType rhs)
Definition: path.h:38
std::vector< const char * > values
The parameter values which have been specified after the occurrence of the argument.