Boost logo

Boost Users :

Subject: [Boost-users] [Program Options] terminate parsing after first positional argument
From: Stuart Pook (stuart8763_at_[hidden])
Date: 2012-07-04 11:21:16


Hello,

How can I tell Boost Program Options to stop parsing the arguments as soon as it finds a positional argument?

I'd like to be able to parse the argument list "-v chmod -R -v 600 foo" as having one argument for my program (-v) and the rest as a std::vector of std::string (including the -v).

In the attached program I have tried 2 different approaches. The first uses multitoken with the arguments "--command date -u -v", it fails because "-u" isn't known.

The second uses collect_unrecognized with "chmod -R -v 600", it doesn't work because -v is interpreted by boost and doesn't end up in the vector.

As someone said back in 2005, perhaps I'm trying to write xargs:
http://thread.gmane.org/gmane.comp.lib.boost.user/9529/focus=9641

I know that I can ask my users to write

a.out -v -- chmod -R -v 600 foo

but I don't want to do that. I want them to write "a.out -v chmod -R -v 600 foo". The first positional argument should should tell boost to stop processing.

Another slightly different question. If I have a multitoken option that takes doubles how can I get it to accept negative values? If I give my program "--floats 1 8 -4 6" where --floats starts a multitoken option that accepts double, I get an exception saying that "-4" is an unknown option.

thanks
Stuart

This is what my test program gives me with boost 1.50:

argv: dd --command date -u -v
unrecognised option '-u'
Allowed options:
  -v [ --verbose ] verbose
  --command arg command to run

2nd try
argv: dd chmod -R -v 600
I'm verbose
v: chmod -R 600
3rd try
argv: dd --floats 1 8 -4 6
unrecognised option '-4'
Allowed options:
  -v [ --verbose ] verbose
  -f [ --floats ] arg numbers

and my program (formatted to fit in 80 characters)

#include <boost/program_options.hpp>
#include <boost/range/algorithm.hpp>
#include <boost/program_options/parsers.hpp>
#include <boost/program_options/options_description.hpp>
#include <iostream>

namespace po = boost::program_options;
#define nelements(a) (sizeof (a) / sizeof (a)[0])

void print(char const * * b, char const * * e)
{
  std::cout << "argv: ";
  std::copy(b, e, std::ostream_iterator<char const *>(std::cout, " "));
  std::cout << std::endl;
}

int main(int argc, char ** argv)
{
  {
    bool verbose;
    std::vector<std::string> command;

    po::options_description desc("Allowed options");
    desc.add_options()
      ("verbose,v",
        po::bool_switch(&verbose)->default_value(false), "verbose")
      ("command", po::value<std::vector<std::string> >(&command)
        ->multitoken(), "command to run")
      ;

    char const * args[] = { "dd", "--command", "date", "-u", "-v", 0 };
    print(args, args + nelements(args) - 1);

    po::variables_map vm;
    try
    {
      po::store(po::command_line_parser(nelements(args) - 1, args)
        .options(desc).run(), vm);
      po::notify(vm);
      if (verbose)
        std::cout << "I'm verbose\n";
      std::cout << "command: ";
      boost::copy(command,
        std::ostream_iterator<std::string>(std::cout, " "));
      std::cout << std::endl;
    }
    catch (boost::program_options::unknown_option & x)
    {
      std::cerr << x.what() << "\n" << desc << "\n";
    }
  }

  std::cout << "2nd try\n";
  {
    bool verbose;

    po::options_description desc("Allowed options");
    desc.add_options()
      ("verbose,v",
        po::bool_switch(&verbose)->default_value(false), "verbose")
      ;

    char const * args[] = { "dd", "chmod", "-R", "-v", "600", 0 };
    print(args, args + nelements(args) - 1);
    po::variables_map vm;
    po::parsed_options parsed =
      po::command_line_parser(nelements(args) - 1, args).
      options(desc).allow_unregistered().run();
    try
    {
       po::store(parsed, vm);
    }
    catch (boost::program_options::unknown_option & x)
    {
      std::cerr << x.what() << "\n" << desc << "\n";
      exit(2);
    }
    po::notify(vm);
    if (verbose)
      std::cout << "I'm verbose\n";
    std::cout << "v: ";

    std::vector<std::string> v = po::collect_unrecognized(
      parsed.options,
      po::include_positional);
    boost::copy(v, std::ostream_iterator<std::string>(std::cout, " "));
    std::cout << std::endl;
  }

  std::cout << "3rd try\n";
  {
    bool verbose;
    std::vector<double> f;

    po::options_description all("Allowed options");
    all.add_options()
      ("verbose,v",
        po::bool_switch(&verbose)->default_value(false), "verbose")
      ("floats,f",
        po::value<std::vector<double> >(&f)->multitoken(), "numbers")
      ;

    char const * args[] = { "dd", "--floats", "1", "8", "-4", "6", 0 };
    print(args, args + nelements(args) - 1);
    po::variables_map vm;
    try
    {
      po::store(po::command_line_parser(nelements(args) - 1, args)
        .options(all).run(), vm);
      po::notify(vm);
      if (verbose)
        std::cout << "I'm verbose\n";
      std::cout << "floats: ";
      boost::copy(f, std::ostream_iterator<double>(std::cout, " "));
      std::cout << std::endl;
    }
    catch (boost::program_options::unknown_option & x)
    {
      std::cerr << x.what() << "\n" << all << "\n";
    }
  }
}


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net