Provide access to application’s path, this include configuration, data, executable and library paths.
Provide access to various path including:
Since this library is cross-platform we need to take care of different charsets and localizations (UTF-8, UTF-16).
To support internationalization we will always consider path to be encoded in UTF-8 under Windows. We will convert them to UTF-16 to pass them to the native windows API. On Posix platform we have nothing to do.
We recommend to use boost::filesystem::path with and imbued UTF-8 locale. you could use this code in your main to initialise boost::filesystem locale once:
// create a locale with a unicode facet to convert between char(utf-8) and wchar(utf-16/utf-32)
std::locale loc(std::locale(), &qi::unicodeFacet());
// Make boost.filesystem always use the unicode facet
boost::filesystem::path::imbue(loc);
// it's although possible to set the locale as global.
// This will enable UTF8 support for iostream.
std::locale::global(loc);
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
    |   |__ models
    |       |__ nao.xml
    |       |__ romeo.xml
    |__ 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
|       |__ models
|           |__ nao.xml
|           |__ romeo.xml
|__ etc
    |__ foo
        |__ foo.cfg
Here is a list of common requirements:
Here is how it works:
--qi-sdk-prefix or the
variable QI_SDK_PREFIX.The qi::path always make sure that:
For this to work, we must make sure that
Have a look on the qi::path for more details.
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.
/*
 * 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 <boost/filesystem/fstream.hpp>
#include <vector>
#include <qi/os.hpp>
#include <qi/path.hpp>
#include <qi/application.hpp>
#include <qi/qi.hpp>
int main(int argc, char *argv[])
{
  // Get the prefix name from argv0
  // Performs various initializations.
  qi::Application app(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.
  const qi::Path fooCfgPath = qi::path::findConf("foo", "foo.cfg");
  if (fooCfgPath.empty())
  {
    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];
    // Set stream to the right charset
    boost::filesystem::ifstream ifs(fooCfgPath, std::fstream::in);
    while (! ifs.eof())
    {
      ifs.getline(buf, 250);
      std::cout << buf << std::endl;
    }
  }
  // ... Write back the configuration to userCfgPath
  const qi::Path userCfgPath = qi::path::userWritableConfPath("foo", "foo.cfg");
  std::cout << "Writing config file to: " << userCfgPath << std::endl;
  boost::filesystem::ofstream ofs(userCfgPath, std::fstream::out | std::fstream::trunc);
  ofs << "Hi, this is foo.cfg" << std::endl;
  ofs.close();
  return 0;
}