Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/libraries/core/PathConfig.cc @ 9789

Last change on this file since 9789 was 9667, checked in by landauf, 11 years ago

merged core6 back to trunk

  • Property svn:eol-style set to native
File size: 11.2 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>
[2710]35#include <boost/filesystem.hpp>
36
37#ifdef ORXONOX_PLATFORM_WINDOWS
[2896]38#  ifndef WIN32_LEAN_AND_MEAN
39#    define WIN32_LEAN_AND_MEAN
40#  endif
[2710]41#  include <windows.h>
[3214]42#  undef min
43#  undef max
[2710]44#elif defined(ORXONOX_PLATFORM_APPLE)
45#  include <sys/param.h>
46#  include <mach-o/dyld.h>
47#else /* Linux */
48#  include <sys/types.h>
49#  include <unistd.h>
50#endif
51
52#include "SpecialConfig.h"
[8858]53#include "util/Output.h"
[2710]54#include "util/Exception.h"
[9667]55#include "config/CommandLineParser.h"
[1505]56
[8351]57// Differentiate Boost Filesystem v2 and v3
58#if (BOOST_FILESYSTEM_VERSION < 3)
59#  define BF_LEAF leaf
60#  define BF_GENERIC_STRING string
61#  define BF_NATIVE_STRING file_string
[5693]62#else
[8351]63#  define BF_LEAF path().filename().string
64#  define BF_GENERIC_STRING generic_string
65#  define BF_NATIVE_STRING string
[5693]66#endif
67
[1505]68namespace orxonox
69{
[5836]70    namespace bf = boost::filesystem;
71
[3196]72    //! Static pointer to the singleton
[5836]73    PathConfig* PathConfig::singletonPtr_s  = 0;
[2662]74
[5695]75    SetCommandLineArgument(externalDataPath, "").information("Path to the external data files");
[8729]76    SetCommandLineArgument(writingPathSuffix, "").information("Additional subfolder for config and log files");
[2710]77
[5836]78    PathConfig::PathConfig()
79        : rootPath_(*(new bf::path()))
80        , executablePath_(*(new bf::path()))
81        , modulePath_(*(new bf::path()))
82        , dataPath_(*(new bf::path()))
83        , externalDataPath_(*(new bf::path()))
84        , configPath_(*(new bf::path()))
85        , logPath_(*(new bf::path()))
[8366]86        , bBuildDirectoryRun_(false)
[3280]87    {
[5693]88        //////////////////////////
89        // FIND EXECUTABLE PATH //
90        //////////////////////////
91
[2710]92#ifdef ORXONOX_PLATFORM_WINDOWS
93        // get executable module
94        TCHAR buffer[1024];
95        if (GetModuleFileName(NULL, buffer, 1024) == 0)
96            ThrowException(General, "Could not retrieve executable path.");
97
98#elif defined(ORXONOX_PLATFORM_APPLE)
99        char buffer[1024];
[8351]100        uint32_t path_len = 1023;
[2710]101        if (_NSGetExecutablePath(buffer, &path_len))
102            ThrowException(General, "Could not retrieve executable path.");
103
104#else /* Linux */
105        /* written by Nicolai Haehnle <prefect_@gmx.net> */
106
107        /* Get our PID and build the name of the link in /proc */
108        char linkname[64]; /* /proc/<pid>/exe */
109        if (snprintf(linkname, sizeof(linkname), "/proc/%i/exe", getpid()) < 0)
110        {
111            /* This should only happen on large word systems. I'm not sure
112               what the proper response is here.
113               Since it really is an assert-like condition, aborting the
114               program seems to be in order. */
115            assert(false);
116        }
117
118        /* Now read the symbolic link */
119        char buffer[1024];
120        int ret;
121        ret = readlink(linkname, buffer, 1024);
122        /* In case of an error, leave the handling up to the caller */
123        if (ret == -1)
124            ThrowException(General, "Could not retrieve executable path.");
125
126        /* Ensure proper NUL termination */
127        buffer[ret] = 0;
128#endif
129
[8351]130        // Remove executable filename
131        executablePath_ = bf::path(buffer).branch_path();
[2710]132
[5693]133        /////////////////////
134        // SET MODULE PATH //
135        /////////////////////
136
[5836]137        if (bf::exists(executablePath_ / "orxonox_dev_build.keep_me"))
[2710]138        {
[8858]139            orxout(internal_info) << "Running from the build tree." << endl;
[8366]140            PathConfig::bBuildDirectoryRun_ = true;
[5836]141            modulePath_ = specialConfig::moduleDevDirectory;
[2710]142        }
143        else
144        {
[5693]145
[2710]146#ifdef INSTALL_COPYABLE // --> relative paths
[5693]147
[2710]148            // Also set the root path
[5836]149            bf::path relativeExecutablePath(specialConfig::defaultRuntimePath);
150            rootPath_ = executablePath_;
151            while (!bf::equivalent(rootPath_ / relativeExecutablePath, executablePath_) && !rootPath_.empty())
152                rootPath_ = rootPath_.branch_path();
153            if (rootPath_.empty())
[2710]154                ThrowException(General, "Could not derive a root directory. Might the binary installation directory contain '..' when taken relative to the installation prefix path?");
155
[5693]156            // Module path is fixed as well
[5836]157            modulePath_ = rootPath_ / specialConfig::defaultModulePath;
[5693]158
159#else
160
161            // There is no root path, so don't set it at all
162            // Module path is fixed as well
[5836]163            modulePath_ = specialConfig::moduleInstallDirectory;
[5693]164
165#endif
166        }
167    }
168
[5836]169    PathConfig::~PathConfig()
[5693]170    {
[5836]171        delete &rootPath_;
172        delete &executablePath_;
173        delete &modulePath_;
174        delete &dataPath_;
175        delete &externalDataPath_;
176        delete &configPath_;
177        delete &logPath_;
178    }
179
180    void PathConfig::setConfigurablePaths()
181    {
[8366]182        if (bBuildDirectoryRun_)
[5693]183        {
[5836]184            dataPath_         = specialConfig::dataDevDirectory;
185            configPath_       = specialConfig::configDevDirectory;
186            logPath_          = specialConfig::logDevDirectory;
187
188            // Check for data path override by the command line
[6021]189            if (!CommandLineParser::getArgument("externalDataPath")->hasDefaultValue())
[9550]190                externalDataPath_ = CommandLineParser::getValue("externalDataPath").get<std::string>();
[5836]191            else
192                externalDataPath_ = specialConfig::externalDataDevDirectory;
[5693]193        }
194        else
195        {
196
197#ifdef INSTALL_COPYABLE // --> relative paths
198
[2710]199            // Using paths relative to the install prefix, complete them
[5836]200            dataPath_   = rootPath_ / specialConfig::defaultDataPath;
201            configPath_ = rootPath_ / specialConfig::defaultConfigPath;
202            logPath_    = rootPath_ / specialConfig::defaultLogPath;
[5693]203
[2710]204#else
205
[5836]206            dataPath_  = specialConfig::dataInstallDirectory;
[2710]207
208            // Get user directory
[8351]209#ifdef ORXONOX_PLATFORM_UNIX
[2710]210            char* userDataPathPtr(getenv("HOME"));
[8351]211#else
[2710]212            char* userDataPathPtr(getenv("APPDATA"));
[8351]213#endif
[2710]214            if (userDataPathPtr == NULL)
215                ThrowException(General, "Could not retrieve user data path.");
[5836]216            bf::path userDataPath(userDataPathPtr);
[2710]217            userDataPath /= ".orxonox";
218
[5836]219            configPath_ = userDataPath / specialConfig::defaultConfigPath;
220            logPath_    = userDataPath / specialConfig::defaultLogPath;
[5693]221
[2710]222#endif
[5693]223
[2710]224        }
225
226        // Option to put all the config and log files in a separate folder
[6021]227        if (!CommandLineParser::getArgument("writingPathSuffix")->hasDefaultValue())
[2710]228        {
[9550]229            const std::string& directory(CommandLineParser::getValue("writingPathSuffix").get<std::string>());
[5836]230            configPath_ = configPath_ / directory;
231            logPath_    = logPath_    / directory;
[2710]232        }
233
[5693]234        // Create directories to avoid problems when opening files in non existent folders.
[5836]235        std::vector<std::pair<bf::path, std::string> > directories;
[8351]236        directories.push_back(std::make_pair(bf::path(configPath_), std::string("config")));
237        directories.push_back(std::make_pair(bf::path(logPath_), std::string("log")));
[2710]238
[5836]239        for (std::vector<std::pair<bf::path, std::string> >::iterator it = directories.begin();
[2710]240            it != directories.end(); ++it)
241        {
[5836]242            if (bf::exists(it->first) && !bf::is_directory(it->first))
[2710]243            {
244                ThrowException(General, std::string("The ") + it->second + " directory has been preoccupied by a file! \
[8351]245                                         Please remove " + it->first.BF_GENERIC_STRING());
[2710]246            }
[5836]247            if (bf::create_directories(it->first)) // function may not return true at all (bug?)
[2710]248            {
[8858]249                orxout(internal_info) << "Created " << it->second << " directory" << endl;
[2710]250            }
251        }
252    }
[2896]253
[5836]254    std::vector<std::string> PathConfig::getModulePaths()
[2896]255    {
[5836]256        std::vector<std::string> modulePaths;
257
258        // We search for helper files with the following extension
[6417]259        const std::string& moduleextension = specialConfig::moduleExtension;
[5836]260        size_t moduleextensionlength = moduleextension.size();
261
[8351]262#ifdef ORXONOX_PLATFORM_WINDOWS
[5836]263        // Add that path to the PATH variable in case a module depends on another one
[8351]264        const char* currentPATH = getenv("PATH");
265        std::string newPATH = modulePath_.BF_NATIVE_STRING();
266        if (currentPATH != NULL)
267            newPATH = std::string(currentPATH) + ';' + newPATH;
268        putenv(const_cast<char*>(("PATH=" + newPATH).c_str()));
269#endif
[5836]270
[6105]271        // Make sure the path exists, otherwise don't load modules
272        if (!boost::filesystem::exists(modulePath_))
273            return modulePaths;
274
[5836]275        boost::filesystem::directory_iterator file(modulePath_);
276        boost::filesystem::directory_iterator end;
277
278        // Iterate through all files
279        while (file != end)
[3370]280        {
[8351]281            std::string filename = file->BF_LEAF();
[5836]282
[8351]283            // Check if the file ends with the extension in question
[5836]284            if (filename.size() > moduleextensionlength)
285            {
286                if (filename.substr(filename.size() - moduleextensionlength) == moduleextension)
287                {
288                    // We've found a helper file
[6417]289                    const std::string& library = filename.substr(0, filename.size() - moduleextensionlength);
[8351]290                    modulePaths.push_back(getModulePathString() + library);
[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    {
[8351]301        return getInstance().rootPath_.BF_GENERIC_STRING() + '/';
[3370]302    }
[5836]303
304    /*static*/ std::string PathConfig::getExecutablePathString()
305    {
[8351]306        return getInstance().executablePath_.BF_GENERIC_STRING() + '/';
[5836]307    }
308
309    /*static*/ std::string PathConfig::getDataPathString()
310    {
[8351]311        return getInstance().dataPath_.BF_GENERIC_STRING() + '/';
[5836]312    }
313
314    /*static*/ std::string PathConfig::getExternalDataPathString()
315    {
[8351]316        return getInstance().externalDataPath_.BF_GENERIC_STRING() + '/';
[5836]317    }
318
319    /*static*/ std::string PathConfig::getConfigPathString()
320    {
[8351]321        return getInstance().configPath_.BF_GENERIC_STRING() + '/';
[5836]322    }
323
324    /*static*/ std::string PathConfig::getLogPathString()
325    {
[8351]326        return getInstance().logPath_.BF_GENERIC_STRING() + '/';
[5836]327    }
328
329    /*static*/ std::string PathConfig::getModulePathString()
330    {
[8351]331        return getInstance().modulePath_.BF_GENERIC_STRING() + '/';
[5836]332    }
[1505]333}
Note: See TracBrowser for help on using the repository browser.