1

I'm working on a command line tool that can read options from:

  • The command line arguments
  • An optional configuration file

I used Boost Program Options to read those options and it works mostly fine.

My code is like so:

namespace po = boost::program_options;
namespace fs = boost::filesystem;

po::variables_map vm;
po::store(po::parse_command_line(argc, argv, options), vm);
po::store(po::parse_config_file(ifs, options, true), vm);
po::notify(vm);

However, some of these options are file path and I'd like those to be relative to the origin of the option. Here is an example of what I mean:

Let's say my tool is located in: /usr/local/bin

mytool --foo.path ../config/assets/toto.txt

After parsing, the foo.path option should be an absolute path to /usr/local/config/assets/toto.txt.

Now if I specify foo.path in a configuration file, located at /usr/local/config/myconf.cfg like so:

foo.path=assets/toto.txt

I'd like the path to be relative to the configuration file (not the execution path) and that the resulting absolute path be the same as before.

Is there a way in Boost Program Options for knowing where the value of an option came from so I could adjust the path when transforming relative paths to absolute ones ?

ereOn
  • 53,676
  • 39
  • 161
  • 238

2 Answers2

0

There is a working directory that is set by default to execution path. All relative paths (that you are trying to use in your application) interpreted according to the working directory. You have to options to reach your goals:

  1. Change working directory before interpreting relative paths from config file. If required you should restore the default value of working directory after you have completed with reading your config.
  2. Once you get some path from config you have to check if it is relative path. If so, than you should write a code to build a correct path using the home directory of you config file.
vinser52
  • 101
  • 6
  • That doesn't solve the problem. Relative paths won't magically turn to absolute paths because the current directory is changed. One needs to know the origin of the option value to apply to transform the relative path into an absolute one reliably. – ereOn Mar 18 '15 at 15:10
0

I could finally get this to work by adding context manually after each parsing phase.

The function I wrote to add context was as follow:

namespace po = boost::program_options;
namespace fs = boost::filesystem;

void make_path_absolute(
    const std::string& name,
    po::variables_map& vm,
    const fs::path& root)
{
    if (vm.count(name) > 0) {
        const auto path = vm[name].as<fs::path>();

        if (!path.empty()) {
            vm.at(name).value() = fs::absolute(path, root);
        }
    }
}

Which is used like that:

namespace po = boost::program_options;
namespace fs = boost::filesystem;

po::variables_map vm;

po::store(po::parse_command_line(argc, argv, options), vm);
make_path_absolute("foo.path", vm, fs::current_path());

po::store(po::parse_config_file(ifs, options, true), vm);
make_path_absolute("foo.path", vm, configuration_file.parent_path());

po::notify(vm);

Basically, what the call does is that it makes the path option absolute (if it isn't already) relative to the specified root. In the first case the root is the execution directory, and in the second case, it's the configuration file parent folder.

ereOn
  • 53,676
  • 39
  • 161
  • 238