libqi  1.14.5
qi::path Developer Guide

go to the qi::path API reference.

Overview

The SDK Layout

The main idea of the qibuild-based project is that you always end up with the same layout.

For instance, right after having built you project, you end up with a directory looking like this:

Here we assume you have a foo executable which:

src
|__ foo
    |__ data
        |___ foo.data
    |__ etc
        |__ foo.cfg

build
|___
    sdk
    |__ lib
         |___ libbar.so
    |__ bin
         |__ foo

When everything is installed, you have something like:


prefix
  |__ lib
      |__ libbar.so
  |__ bin
      |__ foo
  |__ share
      |__ foo
          |__ foo.data
  |__ etc
      |__ foo
          |__ foo.cfg


The problem

Here is a list of common requirements:

The solution

Here is how it works:

Link

qi::path documentation.

Using Namespace path

Notes & Requirement

The API of qi::path always make sure that:

For this to work, we must make sure that

Have a look on the API of qi::path for more details

Reading and writing configuration files

Writing a configuration file is very different from reading one.

Let's assume the foo executable want to make sure that SPAM=42 in foo.cfg.

Here is how it works:

You can see that we ask for a list of paths when reading, but that we always write to one file.

Let's go through these steps again, assuming foo is installed in /usr/bin/foo, and foo.cfg in /usr/share/foo/foo.cfg, and that there is nothing else on the machine where foo is running.

Then each time a piece of code will ask for the foo.cfg path, it will get a list starting with ~/.config/foo/foo.cfg, so we are sure the setting SPAM=42 will be used.

Example

/*
 * Copyright (c) 2012 Aldebaran Robotics. All rights reserved.
 * Use of this source code is governed by a BSD-style license that can be
 * found in the COPYING file.
 */
#include <iostream>
#include <fstream>
#include <vector>

#include <qi/os.hpp>
#include <qi/path.hpp>
#include <qi/qi.hpp>

#include <boost/locale.hpp>
#include <boost/filesystem.hpp>
#include <locale>

int main(int argc, char *argv[])
{
  // Set the global locale to loc
  std::locale::global(boost::locale::generator().generate(""));
  // Make boost.filesystem use it
  boost::filesystem::path::imbue(std::locale());

  // Get the prefix name from argv0
  std::cout << "argv0 is: " << argv[0] << std::endl;
  // Get the prefix name from argv0
  // Performs various initializations.
  // This is usually called by qi::init()
  qi::init(argc, argv);

  // Get sdk prefix
  std::cout << "SDK prefix is: " << qi::path::sdkPrefix() << std::endl;

  // First argument is the name of the application, used
  // to build various paths later.
  std::string fooCfgPath = qi::path::findConf("foo", "foo.cfg");
  if (fooCfgPath == "")
  {
    std::cerr << "Could not find foo.cfg" << std::endl;
    std::cerr << "Looked in: " << std::endl;
    std::vector<std::string > configPaths = qi::path::confPaths("foo");
    std::vector<std::string>::const_iterator it;
    for (it = configPaths.begin(); it != configPaths.end(); ++it)
    {
      std::cerr << "\t" << *it << std::endl;
    }
  }
  else
  {
    std::cout << "Found foo.cfg: " << fooCfgPath << std::endl;
    std::cout << "Contents: " << std::endl;
    char buf[250];
    std::ifstream ifs;

    // Set stream to the right charset
    ifs.imbue(std::locale());
    ifs.open(fooCfgPath.c_str(), std::fstream::in);
    while (! ifs.eof())
    {
      ifs.getline(buf, 250);
      std::cout << buf << std::endl;
    }
    ifs.close();
  }


  // ... Write back the configuration to userCfgPath
  std::string userCfgPath = qi::path::userWritableConfPath("foo", "foo.cfg");
  std::cout << "Writing config file to: " << userCfgPath << std::endl;
  std::ofstream ofs(userCfgPath.c_str(), std::fstream::out | std::fstream::trunc);
  ofs << "Hi, this is foo.cfg" << std::endl;
  ofs.close();

  return 0;
}

Link

qi::path documentation.

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines