Friday, July 30, 2010

Damn boost::program_options

I was dismayed by the awful help screen on one of our internal tools. The help message looked something like:
$ ./a.out -h 
Allowed options:
  -h [ --help ]                                                               s
                                                                              h
                          ... skipping ...
                                                                              e
                                                                              d
  -c [ --config ] arg (=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) c
                                                                              o
                                                                              n
                                                                              f
                                                                              i
                                                                              g
                                                                              u
                                                                              r
                                                                              a
                                                                              t
                                                                              i
                                                                              o
                                                                              n
                                                                              f
                                                                              i
                                                                              l
                                                                              e
Of course, this was an internal tool that is no longer being maintained. Poking at the source I found it was based on boost::program_options and was just writing the options_description to stdout. I found that troubling as I have used and recommended this library many times. The root of the problem seemed to be that the default value was based on a file on the system specified by an environment variable. On my system that path is quite long and there was only room for a description that was one character wide. I put together a quick test program to illustrate the problem:
// g++ -I/opt/local/include -L/opt/local/lib -lboost_program_options-mt boostopt.cpp

#include <cstdlib>
#include <iostream>
#include <string>

#include <boost/program_options.hpp>

using namespace std;
using namespace boost::program_options;

int
main(int argc, char **argv) {

    char *file = getenv("CONFIG");
    string config((file == NULL) ? "-" : file);

    options_description desc("Allowed options");
    desc.add_options()
        ("help,h",     "show this help message, some additional text "
                       "that is here for no other reason than to make "
                       "the message wrap when the help is printed")
        ("config,c",   value<string>(&config)->default_value(config),
                       "configuration file")
    ;

    variables_map vm;
    try {
        store(parse_command_line(argc, argv, desc), vm);
        notify(vm);
    } catch (const std::exception &e) {
        cerr << "Error: " << e.what() << endl
             << endl << desc << endl;
        return 1;
    }

    if (vm.count("help")) {
        cerr << desc << endl;
        return 2;
    }

    return 0;
}
However, to my surprise when I ran the test program I could not reproduce the issue. The output when I supply a large default value was still sane, it just wraps the description to the next line. For example:
$ env CONFIG=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ./a.out -h
Allowed options:
  -h [ --help ]                         show this help message, some additional
                                        text that is here for no other reason 
                                        than to make the message wrap when the 
                                        help is printed
  -c [ --config ] arg (=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa)
                                        configuration file
A little research showed the problem was fixed in boost 1.42.0. And sure enough, if I try with boost 1.41.0, like what the internal tool was using, I can easily reproduce the problem:
$ env CONFIG=aaa ./a.out -h
Allowed options:
  -h [ --help ]              show this help message, some additional text that 
                             is here for no other reason than to make the 
                             message wrap when the help is printed
  -c [ --config ] arg (=aaa) configuration file

$ env CONFIG=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ./a.out -h
Allowed options:
  -h [ --help ]                                                              sh
                                                                             ow
                          ... skipping ...
                                                                             te
                                                                             d
  -c [ --config ] arg (=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) co
                                                                             nf
                                                                             ig
                                                                             ur
                                                                             at
                                                                             io
                                                                             n 
                                                                             fi
                                                                             le

$ env CONFIG=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ./a.out -h 
Allowed options:
  -h [ --help ]                                                               s
                                                                              h
                          ... skipping ...
                                                                              e
                                                                              d
  -c [ --config ] arg (=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) c
                                                                              o
                                                                              n
                                                                              f
                                                                              i
                                                                              g
                                                                              u
                                                                              r
                                                                              a
                                                                              t
                                                                              i
                                                                              o
                                                                              n
                                                                              f
                                                                              i
                                                                              l
                                                                              e
And luckily for me, there isn't any work to fix the tool other than bump the version of boost it depends on.

No comments:

Post a Comment