Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 9553 was 9550, checked in by landauf, 12 years ago

merged testing branch back to trunk. unbelievable it took me 13 months to finish this chore…

  • 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"
[6021]55#include "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.