12

I'm using boost::program_options library to process command line params. I need to accept a file name via -r option, in case if it is empty (-r given without params) I need to use stdin.

desc.add_options()
 ("replay,r", boost::program_options::value<std::string>(), "bla bla bla")

In this case boost wouldn't accept -r without params and throw an exception. default_value () option does not work as well as it would make library return value even if user didn't give -r option.

Any ideas how to work around?

cppalex
  • 537
  • 4
  • 11

3 Answers3

27

Please use the implicit_value method, e.g

desc.add_options()
 ("replay,r", po::value<std::string>()->implicit_value("stdin"), "bla bla bla")

This makes the option accept either 0 or 1 token, and if no tokens are provided, it will act as if 'stdin' was provided. Of course, you can pick any other implicit value -- including empty string and '-' as suggested by mch.

Vladimir Prus
  • 4,600
  • 22
  • 31
  • @Vladimir Prus, here is another question about options with no values here http://stackoverflow.com/questions/7174781/boost-program-options-notifier-for-options-with-no-value I want to be able to add notifiers for such options or write a patch to enable it. Please, comment, thanks. – Riga Aug 26 '11 at 20:21
  • Unfortunately, this does not work when an empty value is given in INI file, for some reason. – Alex Che Feb 21 '17 at 07:13
7

You could try a trick with the multitoken and zero_tokens options:

using namespace std;
namespace po = boost::program_options;

vector<string> replay;

po::options_description desc("Allowed options");
desc.add_options()
    ("replay,r", po::value< vector<string> >(&replay)->multitoken()->zero_tokens(), "bla bla bla");

po::variables_map vm;        
po::store(po::parse_command_line(argc, argv, desc), vm);
po::notify(vm);    

if (vm.count("replay"))
{
  size_t s = vm["replay"].as< vector<string> >().size();
  if (s == 0)
    cout << "replay without args" << endl;
  else if (s == 1)
    cout << "replay with one arg" << endl;
  else
    cout << "replay with multiple args" << endl;
}
else
  cout << "replay not specified" << endl;

Then just count the number of elements in the replay vector. You'll want to throw an error if multiple arguments are passed to the replay option.

Rômulo Ceccon
  • 10,081
  • 5
  • 39
  • 47
2

I don't think any command line parsing libraries allow you to have options that can either take an argument or not. If an option requires an argument, you must give one. In this case, the standard practice (in *NIX anyway) is to use '-' as a filename to denote that you want to read from standard input.

mch
  • 7,155
  • 3
  • 30
  • 34