Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/kicklib/src/libraries/core/PathConfig.cc @ 8071

Last change on this file since 8071 was 8071, checked in by rgrieder, 13 years ago

Merged ois_update branch (before it was renamed to mac_osx) into kicklib branch.

  • Property svn:eol-style set to native
File size: 11.1 KB
RevLine 
[1505]1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *                    > www.orxonox.net <
4 *
5 *
6 *   License notice:
7 *
8 *   This program is free software; you can redistribute it and/or
9 *   modify it under the terms of the GNU General Public License
10 *   as published by the Free Software Foundation; either version 2
11 *   of the License, or (at your option) any later version.
12 *
13 *   This program is distributed in the hope that it will be useful,
14 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *   GNU General Public License for more details.
17 *
18 *   You should have received a copy of the GNU General Public License
19 *   along with this program; if not, write to the Free Software
20 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 *
22 *   Author:
[2896]23 *      Reto Grieder
[1505]24 *   Co-authors:
[2896]25 *      ...
[1505]26 *
27 */
28
[5836]29#include "PathConfig.h"
[1505]30
[1756]31#include <cassert>
[2710]32#include <cstdlib>
33#include <cstdio>
[5836]34#include <vector>
[5693]35#include <boost/version.hpp>
[2710]36#include <boost/filesystem.hpp>
37
38#ifdef ORXONOX_PLATFORM_WINDOWS
[2896]39#  ifndef WIN32_LEAN_AND_MEAN
40#    define WIN32_LEAN_AND_MEAN
41#  endif
[2710]42#  include <windows.h>
[3214]43#  undef min
44#  undef max
[2710]45#elif defined(ORXONOX_PLATFORM_APPLE)
46#  include <sys/param.h>
47#  include <mach-o/dyld.h>
48#else /* Linux */
49#  include <sys/types.h>
50#  include <unistd.h>
51#endif
52
53#include "SpecialConfig.h"
[2896]54#include "util/Debug.h"
[2710]55#include "util/Exception.h"
[6021]56#include "CommandLineParser.h"
[1505]57
[5693]58// Boost 1.36 has some issues with deprecated functions that have been omitted
59#if (BOOST_VERSION == 103600)
60#  define BOOST_LEAF_FUNCTION filename
[8066]61#elif (BOOST_FILESYSTEM_VERSION < 3)
62#  define BOOST_LEAF_FUNCTION leaf
[5693]63#else
[8066]64#  define BOOST_LEAF_FUNCTION path().filename().string
[5693]65#endif
66
[1505]67namespace orxonox
68{
[5836]69    namespace bf = boost::filesystem;
70
[3196]71    //! Static pointer to the singleton
[5836]72    PathConfig* PathConfig::singletonPtr_s  = 0;
[2662]73
[5695]74    SetCommandLineArgument(externalDataPath, "").information("Path to the external data files");
[3280]75    SetCommandLineOnlyArgument(writingPathSuffix, "").information("Additional subfolder for config and log files");
[2710]76
[5836]77    PathConfig::PathConfig()
78        : rootPath_(*(new bf::path()))
79        , executablePath_(*(new bf::path()))
80        , modulePath_(*(new bf::path()))
81        , dataPath_(*(new bf::path()))
82        , externalDataPath_(*(new bf::path()))
83        , configPath_(*(new bf::path()))
84        , logPath_(*(new bf::path()))
[3370]85        , bDevRun_(false)
[3280]86    {
[5693]87        //////////////////////////
88        // FIND EXECUTABLE PATH //
89        //////////////////////////
90
[2710]91#ifdef ORXONOX_PLATFORM_WINDOWS
92        // get executable module
93        TCHAR buffer[1024];
94        if (GetModuleFileName(NULL, buffer, 1024) == 0)
95            ThrowException(General, "Could not retrieve executable path.");
96
97#elif defined(ORXONOX_PLATFORM_APPLE)
98        char buffer[1024];
[8071]99        uint32_t path_len = 1023;
[2710]100        if (_NSGetExecutablePath(buffer, &path_len))
101            ThrowException(General, "Could not retrieve executable path.");
102
103#else /* Linux */
104        /* written by Nicolai Haehnle <prefect_@gmx.net> */
105
106        /* Get our PID and build the name of the link in /proc */
107        char linkname[64]; /* /proc/<pid>/exe */
108        if (snprintf(linkname, sizeof(linkname), "/proc/%i/exe", getpid()) < 0)
109        {
110            /* This should only happen on large word systems. I'm not sure
111               what the proper response is here.
112               Since it really is an assert-like condition, aborting the
113               program seems to be in order. */
114            assert(false);
115        }
116
117        /* Now read the symbolic link */
118        char buffer[1024];
119        int ret;
120        ret = readlink(linkname, buffer, 1024);
121        /* In case of an error, leave the handling up to the caller */
122        if (ret == -1)
123            ThrowException(General, "Could not retrieve executable path.");
124
125        /* Ensure proper NUL termination */
126        buffer[ret] = 0;
127#endif
128
[8071]129        // Remove executable filename
130        executablePath_ = bf::path(buffer).branch_path();
[2710]131
[5693]132        /////////////////////
133        // SET MODULE PATH //
134        /////////////////////
135
[5836]136        if (bf::exists(executablePath_ / "orxonox_dev_build.keep_me"))
[2710]137        {
138            COUT(1) << "Running from the build tree." << std::endl;
[5836]139            PathConfig::bDevRun_ = true;
140            modulePath_ = specialConfig::moduleDevDirectory;
[2710]141        }
142        else
143        {
[5693]144
[2710]145#ifdef INSTALL_COPYABLE // --> relative paths
[5693]146
[2710]147            // Also set the root path
[5836]148            bf::path relativeExecutablePath(specialConfig::defaultRuntimePath);
149            rootPath_ = executablePath_;
150            while (!bf::equivalent(rootPath_ / relativeExecutablePath, executablePath_) && !rootPath_.empty())
151                rootPath_ = rootPath_.branch_path();
152            if (rootPath_.empty())
[2710]153                ThrowException(General, "Could not derive a root directory. Might the binary installation directory contain '..' when taken relative to the installation prefix path?");
154
[5693]155            // Module path is fixed as well
[5836]156            modulePath_ = rootPath_ / specialConfig::defaultModulePath;
[5693]157
158#else
159
160            // There is no root path, so don't set it at all
161            // Module path is fixed as well
[5836]162            modulePath_ = specialConfig::moduleInstallDirectory;
[5693]163
164#endif
165        }
166    }
167
[5836]168    PathConfig::~PathConfig()
[5693]169    {
[5836]170        delete &rootPath_;
171        delete &executablePath_;
172        delete &modulePath_;
173        delete &dataPath_;
174        delete &externalDataPath_;
175        delete &configPath_;
176        delete &logPath_;
177    }
178
179    void PathConfig::setConfigurablePaths()
180    {
181        if (bDevRun_)
[5693]182        {
[5836]183            dataPath_         = specialConfig::dataDevDirectory;
184            configPath_       = specialConfig::configDevDirectory;
185            logPath_          = specialConfig::logDevDirectory;
186
187            // Check for data path override by the command line
[6021]188            if (!CommandLineParser::getArgument("externalDataPath")->hasDefaultValue())
189                externalDataPath_ = CommandLineParser::getValue("externalDataPath").getString();
[5836]190            else
191                externalDataPath_ = specialConfig::externalDataDevDirectory;
[5693]192        }
193        else
194        {
195
196#ifdef INSTALL_COPYABLE // --> relative paths
197
[2710]198            // Using paths relative to the install prefix, complete them
[5836]199            dataPath_   = rootPath_ / specialConfig::defaultDataPath;
200            configPath_ = rootPath_ / specialConfig::defaultConfigPath;
201            logPath_    = rootPath_ / specialConfig::defaultLogPath;
[5693]202
[2710]203#else
204
[5836]205            dataPath_  = specialConfig::dataInstallDirectory;
[2710]206
207            // Get user directory
[8071]208#ifdef ORXONOX_PLATFORM_UNIX
[2710]209            char* userDataPathPtr(getenv("HOME"));
[8071]210#elif ORXONOX_PLATFORM_APPLE
211            char* userDataPathPtr(getenv("HOME"));
212#else
[2710]213            char* userDataPathPtr(getenv("APPDATA"));
[8071]214#endif
[2710]215            if (userDataPathPtr == NULL)
216                ThrowException(General, "Could not retrieve user data path.");
[5836]217            bf::path userDataPath(userDataPathPtr);
[2710]218            userDataPath /= ".orxonox";
219
[5836]220            configPath_ = userDataPath / specialConfig::defaultConfigPath;
221            logPath_    = userDataPath / specialConfig::defaultLogPath;
[5693]222
[2710]223#endif
[5693]224
[2710]225        }
226
227        // Option to put all the config and log files in a separate folder
[6021]228        if (!CommandLineParser::getArgument("writingPathSuffix")->hasDefaultValue())
[2710]229        {
[6417]230            const std::string& directory(CommandLineParser::getValue("writingPathSuffix").getString());
[5836]231            configPath_ = configPath_ / directory;
232            logPath_    = logPath_    / directory;
[2710]233        }
234
[5693]235        // Create directories to avoid problems when opening files in non existent folders.
[5836]236        std::vector<std::pair<bf::path, std::string> > directories;
[8058]237        directories.push_back(std::make_pair(bf::path(configPath_), std::string("config")));
238        directories.push_back(std::make_pair(bf::path(logPath_), std::string("log")));
[2710]239
[5836]240        for (std::vector<std::pair<bf::path, std::string> >::iterator it = directories.begin();
[2710]241            it != directories.end(); ++it)
242        {
[5836]243            if (bf::exists(it->first) && !bf::is_directory(it->first))
[2710]244            {
245                ThrowException(General, std::string("The ") + it->second + " directory has been preoccupied by a file! \
[2759]246                                         Please remove " + it->first.string());
[2710]247            }
[5836]248            if (bf::create_directories(it->first)) // function may not return true at all (bug?)
[2710]249            {
250                COUT(4) << "Created " << it->second << " directory" << std::endl;
251            }
252        }
253    }
[2896]254
[5836]255    std::vector<std::string> PathConfig::getModulePaths()
[2896]256    {
[5836]257        std::vector<std::string> modulePaths;
258
259        // We search for helper files with the following extension
[6417]260        const std::string& moduleextension = specialConfig::moduleExtension;
[5836]261        size_t moduleextensionlength = moduleextension.size();
262
263        // Add that path to the PATH variable in case a module depends on another one
[6417]264        std::string pathVariable(getenv("PATH"));
265        putenv(const_cast<char*>(("PATH=" + pathVariable + ';' + modulePath_.string()).c_str()));
[5836]266
[6105]267        // Make sure the path exists, otherwise don't load modules
268        if (!boost::filesystem::exists(modulePath_))
269            return modulePaths;
270
[5836]271        boost::filesystem::directory_iterator file(modulePath_);
272        boost::filesystem::directory_iterator end;
273
274        // Iterate through all files
275        while (file != end)
[3370]276        {
[6417]277            const std::string& filename = file->BOOST_LEAF_FUNCTION();
[5836]278
279            // Check if the file ends with the exension in question
280            if (filename.size() > moduleextensionlength)
281            {
282                if (filename.substr(filename.size() - moduleextensionlength) == moduleextension)
283                {
284                    // We've found a helper file
[6417]285                    const std::string& library = filename.substr(0, filename.size() - moduleextensionlength);
[8066]286#if BOOST_FILESYSTEM_VERSION < 3
[5927]287                    modulePaths.push_back((modulePath_ / library).file_string());
[8066]288#else
289                    modulePaths.push_back((modulePath_ / library).string());
290#endif
[5836]291                }
292            }
293            ++file;
[3370]294        }
[5836]295
296        return modulePaths;
[2896]297    }
[3370]298
[5836]299    /*static*/ std::string PathConfig::getRootPathString()
[3370]300    {
[5836]301        return getInstance().rootPath_.string() + '/';
[3370]302    }
[5836]303
304    /*static*/ std::string PathConfig::getExecutablePathString()
305    {
306        return getInstance().executablePath_.string() + '/';
307    }
308
309    /*static*/ std::string PathConfig::getDataPathString()
310    {
311        return getInstance().dataPath_.string() + '/';
312    }
313
314    /*static*/ std::string PathConfig::getExternalDataPathString()
315    {
316        return getInstance().externalDataPath_.string() + '/';
317    }
318
319    /*static*/ std::string PathConfig::getConfigPathString()
320    {
321        return getInstance().configPath_.string() + '/';
322    }
323
324    /*static*/ std::string PathConfig::getLogPathString()
325    {
326        return getInstance().logPath_.string() + '/';
327    }
328
329    /*static*/ std::string PathConfig::getModulePathString()
330    {
331        return getInstance().modulePath_.string() + '/';
332    }
[1505]333}
Note: See TracBrowser for help on using the repository browser.