ewmscp  ..
Public Member Functions | Static Public Member Functions | Protected Member Functions | Protected Attributes | Static Protected Attributes | List of all members
options::parser Class Reference

class that contains the parser, i.e. does that option handling More...

#include <Options.h>

Collaboration diagram for options::parser:
[legend]

Public Member Functions

 parser (const std::string &aDescription="", const std::string &aTrailer="", const std::vector< std::string > &aSearchPaths={"/etc/", "~/.", "~/.config/", "./."})
 
 ~parser ()
 
bool fIsParsingDone () const
 
void fSetMessageStream (std::ostream *aStream)
 
void fSetErrorStream (std::ostream *aStream)
 
std::ostream & fGetErrorStream () const
 
void fSetHelpReturnValue (int aValue)
 
int fGetHelpReturnValue () const
 
virtual void fComplainAndLeave (bool aWithHelp=true)
 print help (if required) and exit. More...
 
void fSetAssignmentChars (char aPrimary='=', char aSecondary=':')
 
char fGetSecondaryAssignment () const
 
virtual void fRequire (const base *aOtherOption)
 
virtual void fRequire (std::vector< const base * > aOtherOptions)
 
const std::vector< std::string > & fParse (int argc, const char *argv[])
 parse the options on the command line More...
 
const std::vector< std::string > & fParse (int argc, char *argv[])
 other signature for fParse, when argv needs to be without const due to external constraints More...
 
void fHelp ()
 print help, normally automatically called by the –help option or in case of problems. More...
 
void fWriteCfgFile (const std::string &aFileName)
 
void fReadCfgFile (const std::string &aFileName, const options::internal::sourceItem &aSource, bool aMayBeAbsent=false)
 
void fSetExecutableName (const char *aName)
 
void fSetMinusMinusStartsExtraList ()
 switch on use of – to separate a trailer on the command line that is not to be parsed More...
 
const std::vector< std::string > & fGetStuffAfterMinusMinus ()
 get trailong part of command line as a vector od strings, requires that fSetMinusMinusStartsExtraList was called before parsing. More...
 
const std::string & fGetProgName () const
 

Static Public Member Functions

static parserfGetInstance ()
 get the only allwed instance of the option parser. More...
 
static void fPrintEscapedString (std::ostream &aStream, const std::string &aString)
 
static void fReCaptureEscapedString (std::string &aDest, const std::string &aSource)
 

Protected Member Functions

void fReadConfigFiles ()
 read config files if present More...
 
void fPrintOptionHelp (std::ostream &aMessageStream, const base &aOption, std::size_t aMaxName, std::size_t aMaxExplain, size_t lineLenght) const
 
void fCheckConsistency ()
 

Protected Attributes

const std::string lDescription
 
const std::string lTrailer
 
const std::vector< std::string > lSearchPaths
 
std::vector< std::string > lUnusedOptions
 
std::vector< std::string > lStuffAfterMinusMinus
 
std::set< const base * > lRequiredOptions
 
bool lMinusMinusJustEndsOptions
 
std::ostream * lMessageStream
 
std::ostream * lErrorStream
 
std::string lProgName
 
std::string lExecutableName
 
int lHelpReturnValue
 
char lPrimaryAssignment
 
char lSecondaryAssignment
 
bool lParsingIsDone
 

Static Protected Attributes

static parsergParser = nullptr
 

Detailed Description

class that contains the parser, i.e. does that option handling

once contructed with the header part and the trailer part of the help text, together with the list of search paths for config files the option parser can then be used to parse the command line options.

Definition at line 363 of file Options.h.

Constructor & Destructor Documentation

◆ parser()

options::parser::parser ( const std::string &  aDescription = "",
const std::string &  aTrailer = "",
const std::vector< std::string > &  aSearchPaths = {"/etc/", "~/.", "~/.config/", "./."} 
)

Definition at line 90 of file Options.cpp.

90  :
91  lDescription(aDescription),
92  lTrailer(aTrailer),
93  lSearchPaths(aSearchPaths),
94  lParsingIsDone(false) {
95  if (gParser != nullptr) {
96  std::cerr << "there may be only one parser" << std::endl;
97  fComplainAndLeave(false);
98  }
99  gParser = this;
100  lErrorStream = &std::cerr;
101  lMessageStream = &std::cout;
102  lHelpReturnValue = 0;
105  }

References fComplainAndLeave(), fSetAssignmentChars(), gParser, lErrorStream, lHelpReturnValue, lMessageStream, and lMinusMinusJustEndsOptions.

Here is the call graph for this function:

◆ ~parser()

options::parser::~parser ( )

Definition at line 106 of file Options.cpp.

106  {
107  gParser = nullptr;
108  }

References gParser.

Member Function Documentation

◆ fCheckConsistency()

void options::parser::fCheckConsistency ( )
protected

Definition at line 323 of file Options.cpp.

323  {
324  std::set<const base*> optionsThatWereSet;
325  for (auto & it : base::fGetOptionMap()) {
326  auto opt = it.second;
327  if (opt->fIsSet()) {
328  optionsThatWereSet.insert(opt);
329  }
330  }
331  if (! lRequiredOptions.empty()) {
332  std::vector<const base*> missing;
333  std::set_difference(lRequiredOptions.cbegin(), lRequiredOptions.cend(),
334  optionsThatWereSet.cbegin(), optionsThatWereSet.cend(),
335  std::inserter(missing, missing.begin()));
336  if (! missing.empty()) {
337  fGetErrorStream() << "The following options are required but were not given:";
338  for (auto opt : missing) {
339  fGetErrorStream() << " " << opt->fGetLongName();
340  }
341  fGetErrorStream() << "\n";
343  }
344  }
345  for (auto opt : optionsThatWereSet) {
346  for (auto forbidden : opt->lForbiddenOptions) {
347  if (optionsThatWereSet.count(forbidden) != 0) {
348  fGetErrorStream() << "The option " << opt->fGetLongName() << " forbids the use of " << forbidden->fGetLongName() << " but it is given.\n";
350  }
351  }
352  for (auto required : opt->lRequiredOptions) {
353  if (optionsThatWereSet.count(required) == 0) {
354  fGetErrorStream() << "The option " << opt->fGetLongName() << " requires the use of " << required->fGetLongName() << " but it is not given.\n";
356  }
357  }
358  }
359  }

References fComplainAndLeave(), fGetErrorStream(), options::base::fGetOptionMap(), and lRequiredOptions.

Referenced by fParse().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ fComplainAndLeave()

void options::parser::fComplainAndLeave ( bool  aWithHelp = true)
virtual

print help (if required) and exit.

this function can be overloaded in a class derived from parser, for example when one instead of calling exit() wants to throw an exception. as normaly the call to exit() is what is required this is the default action.

Definition at line 365 of file Options.cpp.

365  {
366  if (aWithHelp) {
367  fGetErrorStream() << "\nFor complete usage: " << fGetProgName() << " --help\n";
368  }
369  exit(1);
370  }

References fGetErrorStream(), and fGetProgName().

Referenced by fCheckConsistency(), fParse(), options::internal::fParseTimePointString(), options::internal::parseNumberAndUnit(), and parser().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ fGetErrorStream()

std::ostream & options::parser::fGetErrorStream ( ) const

Definition at line 121 of file Options.cpp.

121  {
122  return *lErrorStream;
123  }

References lErrorStream.

Referenced by fCheckConsistency(), fComplainAndLeave(), fParse(), options::internal::fParseTimePointString(), fReadCfgFile(), and options::internal::parseNumberAndUnit().

Here is the caller graph for this function:

◆ fGetHelpReturnValue()

int options::parser::fGetHelpReturnValue ( ) const
inline

Definition at line 398 of file Options.h.

398  {
399  return lHelpReturnValue;
400  };

References lHelpReturnValue.

◆ fGetInstance()

parser * options::parser::fGetInstance ( )
static

get the only allwed instance of the option parser.

Definition at line 144 of file Options.cpp.

144  {
145  return gParser;
146  }

References gParser.

Referenced by options::base::base(), options::internal::fParseTimePointString(), options::map< T >::fSetMe(), options::internal::OptionWriteCfgFile::fSetMe(), options::internal::OptionReadCfgFile< mayBeMissing >::fSetMe(), options::internal::OptionHelp::fSetMeNoarg(), options::map< T >::fWriteCfgLines(), options::map< T >::fWriteValue(), and options::internal::parseNumberAndUnit().

Here is the caller graph for this function:

◆ fGetProgName()

const std::string& options::parser::fGetProgName ( ) const
inline

Definition at line 436 of file Options.h.

436  {
437  return lProgName;
438  }

References lProgName.

Referenced by fComplainAndLeave().

Here is the caller graph for this function:

◆ fGetSecondaryAssignment()

char options::parser::fGetSecondaryAssignment ( ) const
inline

Definition at line 403 of file Options.h.

403  {
404  return lSecondaryAssignment;
405  }

References lSecondaryAssignment.

Referenced by options::map< T >::fWriteCfgLines(), and options::map< T >::fWriteValue().

Here is the caller graph for this function:

◆ fGetStuffAfterMinusMinus()

const std::vector<std::string>& options::parser::fGetStuffAfterMinusMinus ( )
inline

get trailong part of command line as a vector od strings, requires that fSetMinusMinusStartsExtraList was called before parsing.

Definition at line 433 of file Options.h.

433  {
434  return lStuffAfterMinusMinus;
435  };

References lStuffAfterMinusMinus.

Referenced by main().

Here is the caller graph for this function:

◆ fHelp()

void options::parser::fHelp ( )

print help, normally automatically called by the –help option or in case of problems.

Definition at line 724 of file Options.cpp.

724  {
725  *lMessageStream << lProgName << ": " << lDescription << "\n";
726 
728  *lMessageStream << "Usage: " << lProgName << " [option]...";
729  for (const auto& it : internal::positional_base::fGetPositonalArgs()) {
730  *lMessageStream << " [" << it.second->fGetLongName() << "]";
731  if (it.second->fIsContainer()) {
732  *lMessageStream << "...";
733  }
734  }
735  *lMessageStream << "\n";
736  }
737 
738  size_t maxName = 0;
739  size_t maxExplain = 0;
740  size_t lineLenght = 132;
741  #ifdef IS_NONBROKEN_SYSTEM
742  {
743  struct winsize window;
744  if (ioctl(0, TIOCGWINSZ, &window) == 0) {
745  lineLenght = window.ws_col;
746  }
747  }
748  #endif
749  for (auto & it : base::fGetOptionMap()) {
750  const auto opt = it.second;
751  maxName = std::max(opt->lLongName.length(), maxName);
752  maxExplain = std::max(opt->lExplanation.length(), maxExplain);
753  }
754  for (auto & it : base::fGetOptionMap()) {
755  const auto opt = it.second;
756  if (! opt->fIsHidden()) {
757  fPrintOptionHelp(*lMessageStream, *opt, maxName, maxExplain, lineLenght);
758  }
759  }
760  if (!lSearchPaths.empty()) {
761  *lMessageStream << "Looking for config files in ";
762  for (const auto & searchPath : lSearchPaths) {
763  *lMessageStream << searchPath << " ";
764  }
765  *lMessageStream << "\n";
766  }
767 
769  *lMessageStream << std::endl;
770  }

References options::base::fGetOptionMap(), options::internal::positional_base::fGetPositonalArgs(), fPrintOptionHelp(), lDescription, lMessageStream, lProgName, lSearchPaths, and lTrailer.

Referenced by options::internal::OptionHelp::fSetMeNoarg(), and main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ fIsParsingDone()

bool options::parser::fIsParsingDone ( ) const

Definition at line 110 of file Options.cpp.

110  {
111  return lParsingIsDone;
112  }

References lParsingIsDone.

◆ fParse() [1/2]

const std::vector< std::string > & options::parser::fParse ( int  argc,
char *  argv[] 
)

other signature for fParse, when argv needs to be without const due to external constraints

Definition at line 164 of file Options.cpp.

164  {
165  return fParse(argc, const_cast<const char**>(argv));
166  }

References fParse().

Here is the call graph for this function:

◆ fParse() [2/2]

const std::vector< std::string > & options::parser::fParse ( int  argc,
const char *  argv[] 
)

parse the options on the command line

The command line is passed via the argc and argv parameres, which will reamain unchanged. Also reads config files, using fReadConfigFiles() and all files which are explicitly requested by –readCfgFile options.

Returns
vector of strings containing all the unhandled string from the original command line

Definition at line 168 of file Options.cpp.

168  {
169  if (lParsingIsDone) {
170  throw std::logic_error("parsing may be done only once");
171  }
172  lParsingIsDone = true; // we set this early, as of now now new options may be created
173  {
174  #ifdef IS_NONBROKEN_SYSTEM
175  auto buf = strdup(argv[0]);
176  lProgName = basename(buf);
177  free(buf);
178  #else
179  lProgName = argv[0];
180  #endif
181  }
182  bool firstOptionNotSeen = true;
183  try {
184  for (int i = 1; i < argc; i++) {
185  if (firstOptionNotSeen && !(argv[i][0] == '-' && argv[i][1] == '-' && internal::gOptionNoCfgFiles.lLongName.compare(argv[i] + 2) == 0)) {
187  }
188  if (argv[i][0] == '-' && argv[i][1] != '-') {
189  auto length = strlen(argv[i]);
190  for (unsigned int j = 1; j < length; j++) {
191  auto it = base::fGetShortOptionMap().find(argv[i][j]);
192  if (it == base::fGetShortOptionMap().end()) {
193  throw std::runtime_error(internal::conCat("unknown short option '", argv[i][j], "'"));
194  } else {
195  auto opt = it->second;
196  if (opt->lNargs > 0 && strlen(argv[i]) > 2) {
197  throw internal::optionError(opt, internal::conCat("run-together short options '", argv[i], "'may not use parameters"));
198  }
199  opt->fHandleOption(argc, argv, &i);
200  }
201  }
202  } else if (argv[i][0] == '-' && argv[i][1] == '-' && argv[i][2] != '-') {
203  auto length = strlen(argv[i]);
204  if (length == 2) { // end of options
205  for (i++; i < argc; i++) {
207  lUnusedOptions.push_back(argv[i]);
208  } else {
209  lStuffAfterMinusMinus.push_back(argv[i]);
210  }
211  }
212  break;
213  } else {
214  if (nullptr == strchr(argv[i], lPrimaryAssignment)) {
215  auto it = base::fGetOptionMap().find(argv[i] + 2);
216  if (it == base::fGetOptionMap().end()) {
217  throw std::runtime_error(internal::conCat("unknown long option '", argv[i], "'"));
218  }
219  auto opt = it->second;
220  opt->fHandleOption(argc, argv, &i);
221  } else {
222  auto buf = strdup(argv[i]);
223  auto equalsAt = strchr(buf, lPrimaryAssignment);
224  *equalsAt = '\0';
225  auto it = base::fGetOptionMap().find(buf + 2);
226  if (it == base::fGetOptionMap().end()) {
227  throw std::runtime_error(internal::conCat("unknown long option '", argv[i], "'"));
228  }
229  auto opt = it->second;
230  std::stringstream sbuf(equalsAt + 1);
231  opt->fSetMe(sbuf, internal::sourceItem(&internal::sourceFile::gCmdLine, i));
232  opt->fCheckRange();
233  free(buf);
234  }
235  }
236  } else {
237  lUnusedOptions.push_back(argv[i]);
238  }
239  firstOptionNotSeen = false;
240  }
241  if (firstOptionNotSeen) { // read cfg files if no options set at all
243  }
244 
246  std::list<base*> positionalArgs;
248  positionalArgs.push_back(it.second);
249  }
250  while (!lUnusedOptions.empty()) {
251  auto opt = positionalArgs.front();
252  if (opt->fIsContainer()) { // process first options from the back
253  for (;;) {
254  auto opt2 = positionalArgs.back();
255  if (opt2 == opt) {
256  break;
257  }
258  positionalArgs.pop_back();
259  auto& arg = lUnusedOptions.back();
260  std::stringstream sbuf(arg);
261  opt2->fSetMe(sbuf, internal::sourceItem(&internal::sourceFile::gCmdLine, 0));
262  opt2->fCheckRange();
263  lUnusedOptions.pop_back();
264  if (lUnusedOptions.empty()) {
265  break;
266  }
267  }
268  }
269  if (lUnusedOptions.empty()) {
270  break;
271  }
272  auto& arg = lUnusedOptions.front();
273  std::stringstream sbuf(arg);
274  opt->fSetMe(sbuf, internal::sourceItem(&internal::sourceFile::gCmdLine, 0));
275  opt->fCheckRange();
276  lUnusedOptions.erase(lUnusedOptions.begin());
277  if (! opt->fIsContainer()) {
278  positionalArgs.pop_front();
279  if (positionalArgs.empty()) {
280  break;
281  }
282  }
283  }
284  }
285  } catch (const internal::rangeError& e) {
286  fGetErrorStream() << e.what() << " in option '" << e.fGetOption().fGetLongName() << "' value '" << e.fGetBadValue() << "'\n";
287  e.fGetOption().fWriteRange(fGetErrorStream());
289  } catch (const internal::conversionError& e) {
290  fGetErrorStream() << e.what() << " in option '" << e.fGetOption().fGetLongName()
291  << "' cannot convert '" << e.fGetArgument() << "' to type '" << e.fGetType().name() << "'\n";
293  } catch (const internal::optionError& e) {
294  fGetErrorStream() << e.what() << " in option '" << e.fGetOption().fGetLongName() << "'\n";
296  } catch (std::exception& e) {
297  fGetErrorStream() << e.what() << "\n";
299  }
300 
301 
303  for (auto & it : base::fGetOptionMap()) {
304  auto opt = it.second;
305  fGetErrorStream() << "option " << opt->lLongName << " has value '";
306  opt->fWriteValue(fGetErrorStream());
307  fGetErrorStream() << "' ";
308  if (opt->lSource.fIsUnset()) {
309  fGetErrorStream() << " (default) ";
310  } else {
311  fGetErrorStream() << " from " << opt->lSource;
312  }
313  fGetErrorStream() << std::endl;
314  }
315  for (auto & unusedOption : lUnusedOptions) {
316  fGetErrorStream() << "unused option '" << unusedOption << "'" << std::endl;
317  }
318  }
320  return lUnusedOptions;
321  }

References options::internal::conCat(), fCheckConsistency(), fComplainAndLeave(), options::internal::conversionError::fGetArgument(), options::internal::rangeError::fGetBadValue(), fGetErrorStream(), options::base::fGetLongName(), options::internal::optionError::fGetOption(), options::base::fGetOptionMap(), options::internal::positional_base::fGetPositonalArgs(), options::base::fGetShortOptionMap(), options::internal::conversionError::fGetType(), fReadConfigFiles(), options::base::fWriteRange(), options::internal::sourceFile::gCmdLine, options::internal::gOptionDebugOptions, options::internal::gOptionNoCfgFiles, lMinusMinusJustEndsOptions, lParsingIsDone, lPrimaryAssignment, lProgName, lStuffAfterMinusMinus, and lUnusedOptions.

Referenced by fParse(), and main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ fPrintEscapedString()

void options::parser::fPrintEscapedString ( std::ostream &  aStream,
const std::string &  aString 
)
static

Definition at line 376 of file Options.cpp.

376  {
377  bool delimit = aString.find_first_of(" \t,") != std::string::npos;
378  if (delimit) {
379  aStream << '\'';
380  }
381  for (auto c : aString) {
382  switch (c) {
383  case '\a':
384  aStream << "\\a";
385  break;
386  case '\b':
387  aStream << "\\b";
388  break;
389  case '\f':
390  aStream << "\\f";
391  break;
392  case '\n':
393  aStream << "\\n";
394  break;
395  case '\r':
396  aStream << "\\r";
397  break;
398  case '\t':
399  aStream << "\\t";
400  break;
401  case ' ':
402  aStream << "\\ ";
403  break;
404  case '\v':
405  aStream << "\\v";
406  break;
407  case '\\':
408  aStream << "\\\\";
409  break;
410  case '\'':
411  aStream << "\\\'";
412  break;
413  case '"':
414  aStream << "\\\"";
415  break;
416  default:
417  if (c >= ' ' && c < 127) {
418  aStream << c;
419  } else {
420  aStream << '\\' << std::oct << std::setw(3) << std::setfill('0') << static_cast<unsigned int>(c) << std::setfill(' ') << std::dec;
421  }
422  }
423  }
424  if (delimit) {
425  aStream << '\'';
426  }
427  }

Referenced by options::escapedIO::operator<<().

Here is the caller graph for this function:

◆ fPrintOptionHelp()

void options::parser::fPrintOptionHelp ( std::ostream &  aMessageStream,
const base aOption,
std::size_t  aMaxName,
std::size_t  aMaxExplain,
size_t  lineLenght 
) const
protected

Definition at line 646 of file Options.cpp.

646  {
647  std::size_t fullNameLength = 8 + aMaxName;
648  std::size_t descLength = std::min(lineLenght - 20 - fullNameLength, aMaxExplain);
649  if (aOption.lShortName != '\0') {
650  aMessageStream << " -" << aOption.lShortName << ", ";
651  } else {
652  aMessageStream << " ";
653  }
654  auto explanation = aOption.lExplanation;
655  bool firstLine = true;
656  do {
657  if (firstLine) {
658  aMessageStream << "--" << std::setw(aMaxName) << std::left << aOption.lLongName
659  << " ";
660  } else {
661  aMessageStream << " " << std::setw(aMaxName) << " " << " ";
662  }
663  if (explanation.length() > descLength) {
664  // Need to linebreak.
665  bool keepBrokenChar = false;
666  bool hardBreak = false;
667  auto breakPos = explanation.find_last_of(" -", descLength - 1);
668  if (breakPos == std::string::npos) {
669  // No space, use hard break. In this case, keep the broken character.
670  // -2 since we add a "-" separator for readability.
671  breakPos = descLength - 2;
672  hardBreak = true;
673  keepBrokenChar = true;
674  } else {
675  // We also want to keep the broken character in case it's not a whitespace.
676  if (explanation[breakPos] != ' ') {
677  breakPos++;
678  keepBrokenChar = true;
679  }
680  }
681  aMessageStream << std::setw(descLength) << std::left << explanation.substr(0, breakPos) + (hardBreak ? "-" : "");
682  explanation = explanation.substr(breakPos + (keepBrokenChar ? 0 : 1));
683  } else {
684  aMessageStream << std::setw(descLength) << std::left << explanation;
685  // Trigger delayed break.
686  explanation.clear();
687  }
688  if (firstLine) {
689  aMessageStream << " default: ";
690  aOption.fWriteValue(aMessageStream);
691  firstLine = false;
692  }
693  aMessageStream << "\n";
694  } while (explanation.length() > 0);
695  if (std::count_if(aOption.lRequiredOptions.cbegin(), aOption.lRequiredOptions.cend(),
696  [](const base * opt) {
697  return ! opt->fIsHidden();
698  })) {
699  aMessageStream << " " << std::setw(aMaxName) << " " << " Requires the following other options:\n";
700  for (auto opt : aOption.lRequiredOptions) {
701  if (opt->fIsHidden()) {
702  continue;
703  }
704  aMessageStream << " " << std::setw(aMaxName) << " " << " " << opt->fGetLongName() << "\n";
705  }
706  }
707  if (std::count_if(aOption.lForbiddenOptions.cbegin(), aOption.lForbiddenOptions.cend(),
708  [](const base * opt) {
709  return ! opt->fIsHidden();
710  })) {
711  aMessageStream << " " << std::setw(aMaxName) << " " << " Forbids the following other options:\n";
712  for (auto opt : aOption.lForbiddenOptions) {
713  if (opt->fIsHidden()) {
714  continue;
715  }
716  aMessageStream << " " << std::setw(aMaxName) << " " << " " << opt->fGetLongName() << "\n";
717  }
718  }
719  if (lRequiredOptions.count(&aOption)) {
720  aMessageStream << " " << std::setw(aMaxName) << " " << " this option is required\n";
721  }
722  }

References options::base::fGetLongName(), options::base::fIsHidden(), options::base::fWriteValue(), options::base::lExplanation, options::base::lForbiddenOptions, options::base::lLongName, options::base::lRequiredOptions, lRequiredOptions, and options::base::lShortName.

Referenced by fHelp().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ fReadCfgFile()

void options::parser::fReadCfgFile ( const std::string &  aFileName,
const options::internal::sourceItem aSource,
bool  aMayBeAbsent = false 
)

Definition at line 819 of file Options.cpp.

819  {
820  std::ifstream cfgFile(aFileName);
821  if (!cfgFile.good() && !(aMayBeAbsent && errno == ENOENT)) {
822  throw std::system_error(errno, std::system_category(),
823  internal::conCat("can't acccess config file '", aFileName , "'."));
824  }
825  auto sourceF = new internal::sourceFile(aFileName, *(aSource.fGetFile()));
826  int lineNumber = 0;
827  std::vector<std::string>* preserveWorthyStuff = nullptr;
828  bool hideNextOption = false;
829  bool disableNextOption = false;
830  try {
831  while (cfgFile.good()) {
832  std::string line;
833  std::getline(cfgFile, line);
834  lineNumber++;
835  internal::sourceItem source(sourceF, lineNumber);
836  if (line.length() == 0) {
837  hideNextOption = false;
838  disableNextOption = false;
839  continue;
840  } else if (line[0] == '#') {
841  if (line[1] == '#') {
842  if (preserveWorthyStuff == nullptr) {
843  preserveWorthyStuff = new std::vector<std::string>;
844  }
845  preserveWorthyStuff->push_back(line);
846  if (line == "## hide") {
847  hideNextOption = true;
848  } else if (line == "## disable" && ! internal::gNoCfgFileRecursion) {
849  disableNextOption = true;
850  }
851  } else if (preserveWorthyStuff != nullptr) {
852  auto equalsAt = line.find_first_of('=');
853  if (equalsAt != std::string::npos) {
854  auto optionName = line.substr(2, equalsAt - 2);
855  auto it = base::fGetOptionMap().find(optionName);
856  if (it != base::fGetOptionMap().end()) {
857  auto option = it->second;
858  option->fSetPreserveWorthyStuff(preserveWorthyStuff);
859  preserveWorthyStuff = nullptr;
860  if (hideNextOption) {
861  option->fHide();
862  }
863  if (disableNextOption) {
864  option->fDisable();
865  }
866  }
867  }
868  }
869  continue;
870  }
871  auto equalsAt = line.find_first_of('=');
872  if (equalsAt == std::string::npos || equalsAt < 1 || equalsAt == line.length()) {
873  std::string buf;
874  fReCaptureEscapedString(buf, line);
875  lUnusedOptions.push_back(buf);
876  continue;
877  }
878  auto optionName = line.substr(0, equalsAt);
879  auto it = base::fGetOptionMap().find(optionName);
880  if (it == base::fGetOptionMap().end()) {
881  throw std::runtime_error(internal::conCat("unknown option '", optionName, "'"));
882  }
883  auto option = it->second;
884  if (hideNextOption) {
885  option->fHide();
886  }
887  if (disableNextOption) {
888  option->fDisable();
889  }
890  {
891  std::stringstream sbuf(line.substr(equalsAt + 1));
892  option->fSetMe(sbuf, source);
893  if (preserveWorthyStuff != nullptr) {
894  option->fSetPreserveWorthyStuff(preserveWorthyStuff);
895  preserveWorthyStuff = nullptr;
896  }
897  option->fCheckRange();
898  }
899  }
900  } catch (const std::exception& e) {
901  fGetErrorStream() << aFileName << ":" << lineNumber << ": error: " << e.what() << "\n";
902  throw;
903  }
904 
905  cfgFile.close();
906  }

References options::internal::conCat(), fGetErrorStream(), options::internal::sourceItem::fGetFile(), options::base::fGetOptionMap(), fReCaptureEscapedString(), options::internal::gNoCfgFileRecursion, and lUnusedOptions.

Referenced by fReadConfigFiles(), and options::internal::OptionReadCfgFile< mayBeMissing >::fSetMe().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ fReadConfigFiles()

void options::parser::fReadConfigFiles ( )
protected

read config files if present

this function iterates over the list of config file search paths, replacing ~ by the home directory and then appends the program name to the path, and if a file is found it is then read as config file.

Definition at line 153 of file Options.cpp.

153  {
154  for (auto f : lSearchPaths) {
155  auto tildePosition = f.find_first_of('~');
156  if (tildePosition != std::string::npos) {
157  f.replace(tildePosition, 1, getenv("HOME"));
158  }
159  f += lProgName;
160  fReadCfgFile(f, internal::sourceItem(), true);
161  }
162  }

References f(), fReadCfgFile(), lProgName, and lSearchPaths.

Referenced by fParse().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ fReCaptureEscapedString()

void options::parser::fReCaptureEscapedString ( std::string &  aDest,
const std::string &  aSource 
)
static

Definition at line 429 of file Options.cpp.

429  {
430  std::stringstream buffer(aSource);
431  buffer >> aDest;
432  }

Referenced by fReadCfgFile().

Here is the caller graph for this function:

◆ fRequire() [1/2]

void options::parser::fRequire ( const base aOtherOption)
virtual

Definition at line 135 of file Options.cpp.

135  {
136  lRequiredOptions.insert(aOption);
137  }

References lRequiredOptions.

Referenced by main().

Here is the caller graph for this function:

◆ fRequire() [2/2]

void options::parser::fRequire ( std::vector< const base * >  aOtherOptions)
virtual

Definition at line 138 of file Options.cpp.

138  {
139  lRequiredOptions.insert(aOptions.cbegin(), aOptions.cend());
140  }

References lRequiredOptions.

◆ fSetAssignmentChars()

void options::parser::fSetAssignmentChars ( char  aPrimary = '=',
char  aSecondary = ':' 
)

Definition at line 127 of file Options.cpp.

127  {
128  lPrimaryAssignment = aPrimary;
129  lSecondaryAssignment = aSecondary;
130  }

References lPrimaryAssignment, and lSecondaryAssignment.

Referenced by parser().

Here is the caller graph for this function:

◆ fSetErrorStream()

void options::parser::fSetErrorStream ( std::ostream *  aStream)

Definition at line 118 of file Options.cpp.

118  {
119  lErrorStream = aStream;
120  }

References lErrorStream.

◆ fSetExecutableName()

void options::parser::fSetExecutableName ( const char *  aName)

Definition at line 131 of file Options.cpp.

131  {
132  lExecutableName = aName;
133  }

References lExecutableName.

Referenced by main().

Here is the caller graph for this function:

◆ fSetHelpReturnValue()

void options::parser::fSetHelpReturnValue ( int  aValue)

Definition at line 124 of file Options.cpp.

124  {
125  lHelpReturnValue = aValue;
126  }

References lHelpReturnValue.

Referenced by main().

Here is the caller graph for this function:

◆ fSetMessageStream()

void options::parser::fSetMessageStream ( std::ostream *  aStream)

Definition at line 115 of file Options.cpp.

115  {
116  lMessageStream = aStream;
117  }

References lMessageStream.

Referenced by main().

Here is the caller graph for this function:

◆ fSetMinusMinusStartsExtraList()

void options::parser::fSetMinusMinusStartsExtraList ( )

switch on use of – to separate a trailer on the command line that is not to be parsed

Definition at line 372 of file Options.cpp.

372  {
374  }

References lMinusMinusJustEndsOptions.

Referenced by main().

Here is the caller graph for this function:

◆ fWriteCfgFile()

void options::parser::fWriteCfgFile ( const std::string &  aFileName)

Definition at line 771 of file Options.cpp.

771  {
772  std::ofstream cfgFile(aFileName, std::ofstream::out | std::ofstream::trunc);
773  if (lExecutableName.empty()) {
774  #ifdef IS_NONBROKEN_SYSTEM
775  char buf[128];
776  auto result = readlink("/proc/self/exe", buf, sizeof(buf));
777  if (result > 0 && result < 128 - 2 - 14) {
778  cfgFile << "#!" << buf << " --readCfgFile\n";
779  }
780  #endif
781  } else {
782  cfgFile << "#!" << lExecutableName << " --readCfgFile\n";
783  }
784  {
785  cfgFile << "# written ";
786  std::time_t t = std::time(nullptr);
787  char mbstr[100];
788  if (std::strftime(mbstr, sizeof(mbstr), "%Y-%m-%d %H:%M:%S", std::localtime(&t))) {
789  cfgFile << mbstr;
790  }
791  cfgFile << " by " << getenv("USER") << " using " << lProgName << "\n";
792  cfgFile << "# only comments started by ## will be preserved on a re-write!\n";
793  cfgFile << "# to rewrite this file for a different executable location, use:\n";
794  cfgFile << "# " << lProgName << " --noCfgFileRecursion --readCfgFile " << aFileName << " --writeCfgFile " << aFileName << "\n";
795  cfgFile << "# Assuming " << lProgName << " is in your PATH\n";
796  }
797  for (auto & it : base::fGetOptionMap()) {
798  const auto opt = it.second;
799  if (opt->lPreserveWorthyStuff != nullptr) {
800  for (const auto& line : * (opt->lPreserveWorthyStuff)) {
801  cfgFile << "\n" << line;
802  }
803  }
804  cfgFile << "\n# " << opt->lExplanation << "\n";
805  auto prefix = "";
806  if (opt->lSource.fIsUnset()) {
807  prefix = "# ";
808  }
809  opt->fWriteCfgLines(cfgFile, prefix);
810  opt->fWriteRange(cfgFile);
811  if (!opt->lSource.fIsUnset()) {
812  cfgFile << "# set from " << opt->lSource << "\n";
813  }
814  }
815  cfgFile << "#\n";
816  cfgFile.close();
817  }

References options::base::fGetOptionMap(), lExecutableName, and lProgName.

Referenced by options::internal::OptionWriteCfgFile::fSetMe().

Here is the call graph for this function:
Here is the caller graph for this function:

Member Data Documentation

◆ gParser

parser * options::parser::gParser = nullptr
staticprotected

Definition at line 365 of file Options.h.

Referenced by fGetInstance(), parser(), and ~parser().

◆ lDescription

const std::string options::parser::lDescription
protected

Definition at line 366 of file Options.h.

Referenced by fHelp().

◆ lErrorStream

std::ostream* options::parser::lErrorStream
protected

Definition at line 376 of file Options.h.

Referenced by fGetErrorStream(), fSetErrorStream(), and parser().

◆ lExecutableName

std::string options::parser::lExecutableName
protected

Definition at line 378 of file Options.h.

Referenced by fSetExecutableName(), and fWriteCfgFile().

◆ lHelpReturnValue

int options::parser::lHelpReturnValue
protected

Definition at line 379 of file Options.h.

Referenced by fGetHelpReturnValue(), fSetHelpReturnValue(), and parser().

◆ lMessageStream

std::ostream* options::parser::lMessageStream
protected

Definition at line 375 of file Options.h.

Referenced by fHelp(), fSetMessageStream(), and parser().

◆ lMinusMinusJustEndsOptions

bool options::parser::lMinusMinusJustEndsOptions
protected

Definition at line 374 of file Options.h.

Referenced by fParse(), fSetMinusMinusStartsExtraList(), and parser().

◆ lParsingIsDone

bool options::parser::lParsingIsDone
protected

Definition at line 383 of file Options.h.

Referenced by fIsParsingDone(), and fParse().

◆ lPrimaryAssignment

char options::parser::lPrimaryAssignment
protected

Definition at line 380 of file Options.h.

Referenced by fParse(), and fSetAssignmentChars().

◆ lProgName

std::string options::parser::lProgName
protected

Definition at line 377 of file Options.h.

Referenced by fGetProgName(), fHelp(), fParse(), fReadConfigFiles(), and fWriteCfgFile().

◆ lRequiredOptions

std::set<const base*> options::parser::lRequiredOptions
protected

Definition at line 372 of file Options.h.

Referenced by fCheckConsistency(), fPrintOptionHelp(), and fRequire().

◆ lSearchPaths

const std::vector<std::string> options::parser::lSearchPaths
protected

Definition at line 368 of file Options.h.

Referenced by fHelp(), and fReadConfigFiles().

◆ lSecondaryAssignment

char options::parser::lSecondaryAssignment
protected

Definition at line 381 of file Options.h.

Referenced by fGetSecondaryAssignment(), and fSetAssignmentChars().

◆ lStuffAfterMinusMinus

std::vector<std::string> options::parser::lStuffAfterMinusMinus
protected

Definition at line 370 of file Options.h.

Referenced by fGetStuffAfterMinusMinus(), and fParse().

◆ lTrailer

const std::string options::parser::lTrailer
protected

Definition at line 367 of file Options.h.

Referenced by fHelp().

◆ lUnusedOptions

std::vector<std::string> options::parser::lUnusedOptions
protected

Definition at line 369 of file Options.h.

Referenced by fParse(), and fReadCfgFile().


The documentation for this class was generated from the following files:
options::parser::lMinusMinusJustEndsOptions
bool lMinusMinusJustEndsOptions
Definition: Options.h:374
options::parser::lMessageStream
std::ostream * lMessageStream
Definition: Options.h:375
options::parser::lUnusedOptions
std::vector< std::string > lUnusedOptions
Definition: Options.h:369
options::parser::lExecutableName
std::string lExecutableName
Definition: Options.h:378
options::parser::fParse
const std::vector< std::string > & fParse(int argc, const char *argv[])
parse the options on the command line
Definition: Options.cpp:168
options::internal::sourceItem::fGetFile
decltype(lFile) fGetFile() const
Definition: Options.h:64
options::parser::lStuffAfterMinusMinus
std::vector< std::string > lStuffAfterMinusMinus
Definition: Options.h:370
options::parser::lHelpReturnValue
int lHelpReturnValue
Definition: Options.h:379
options::parser::lSearchPaths
const std::vector< std::string > lSearchPaths
Definition: Options.h:368
options::parser::gParser
static parser * gParser
Definition: Options.h:365
options::parser::lPrimaryAssignment
char lPrimaryAssignment
Definition: Options.h:380
options::parser::fReadConfigFiles
void fReadConfigFiles()
read config files if present
Definition: Options.cpp:153
options::parser::fPrintOptionHelp
void fPrintOptionHelp(std::ostream &aMessageStream, const base &aOption, std::size_t aMaxName, std::size_t aMaxExplain, size_t lineLenght) const
Definition: Options.cpp:646
options::parser::lProgName
std::string lProgName
Definition: Options.h:377
options::parser::fReadCfgFile
void fReadCfgFile(const std::string &aFileName, const options::internal::sourceItem &aSource, bool aMayBeAbsent=false)
Definition: Options.cpp:819
options::parser::lDescription
const std::string lDescription
Definition: Options.h:366
options::parser::lSecondaryAssignment
char lSecondaryAssignment
Definition: Options.h:381
options::internal::gOptionNoCfgFiles
static single< bool > gOptionNoCfgFiles('\0', "noCfgFiles", "do not read the default config files, must be FIRST option")
standard option to suppress parsing of config files
options::internal::gOptionDebugOptions
static single< bool > gOptionDebugOptions('\0', "debugOptions", "give debug output to option parsing")
standard option for producing debug output about the options
options::internal::gNoCfgFileRecursion
static NoCfgFileRecursion gNoCfgFileRecursion
Definition: Options.cpp:643
options::parser::fReCaptureEscapedString
static void fReCaptureEscapedString(std::string &aDest, const std::string &aSource)
Definition: Options.cpp:429
options::parser::fSetAssignmentChars
void fSetAssignmentChars(char aPrimary='=', char aSecondary=':')
Definition: Options.cpp:127
options::parser::lErrorStream
std::ostream * lErrorStream
Definition: Options.h:376
options::internal::sourceFile::gCmdLine
static const sourceFile gCmdLine
Definition: Options.h:42
options::parser::fGetErrorStream
std::ostream & fGetErrorStream() const
Definition: Options.cpp:121
options::parser::fGetProgName
const std::string & fGetProgName() const
Definition: Options.h:436
options::internal::conCat
std::string conCat(const Args &... args)
Definition: Options.h:338
options::internal::positional_base::fGetPositonalArgs
static std::map< int, base * > & fGetPositonalArgs()
Definition: Options.h:349
options::base::fGetOptionMap
static std::map< std::string, base * > & fGetOptionMap()
Definition: Options.h:196
options::parser::fCheckConsistency
void fCheckConsistency()
Definition: Options.cpp:323
options::parser::lTrailer
const std::string lTrailer
Definition: Options.h:367
options::parser::lParsingIsDone
bool lParsingIsDone
Definition: Options.h:383
options::base::fGetShortOptionMap
static std::map< char, base * > & fGetShortOptionMap()
Definition: Options.h:200
options::parser::fComplainAndLeave
virtual void fComplainAndLeave(bool aWithHelp=true)
print help (if required) and exit.
Definition: Options.cpp:365
options::parser::lRequiredOptions
std::set< const base * > lRequiredOptions
Definition: Options.h:372
f
int f(int a, int line)
Definition: cctest.cpp:4