Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 10542 was 10295, checked in by muemart, 10 years ago

Avoid using the system path variables on windows (also gets rid of two MSVC warnings)
The altered search path already includes the dll's directory, but it didn't work with forward slashes

  • Property svn:eol-style set to native
File size: 10.8 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
[6105]262        // Make sure the path exists, otherwise don't load modules
263        if (!boost::filesystem::exists(modulePath_))
264            return modulePaths;
265
[5836]266        boost::filesystem::directory_iterator file(modulePath_);
267        boost::filesystem::directory_iterator end;
268
269        // Iterate through all files
270        while (file != end)
[3370]271        {
[8351]272            std::string filename = file->BF_LEAF();
[5836]273
[8351]274            // Check if the file ends with the extension in question
[5836]275            if (filename.size() > moduleextensionlength)
276            {
277                if (filename.substr(filename.size() - moduleextensionlength) == moduleextension)
278                {
279                    // We've found a helper file
[6417]280                    const std::string& library = filename.substr(0, filename.size() - moduleextensionlength);
[8351]281                    modulePaths.push_back(getModulePathString() + library);
[5836]282                }
283            }
284            ++file;
[3370]285        }
[5836]286
287        return modulePaths;
[2896]288    }
[3370]289
[5836]290    /*static*/ std::string PathConfig::getRootPathString()
[3370]291    {
[8351]292        return getInstance().rootPath_.BF_GENERIC_STRING() + '/';
[3370]293    }
[5836]294
295    /*static*/ std::string PathConfig::getExecutablePathString()
296    {
[8351]297        return getInstance().executablePath_.BF_GENERIC_STRING() + '/';
[5836]298    }
299
300    /*static*/ std::string PathConfig::getDataPathString()
301    {
[8351]302        return getInstance().dataPath_.BF_GENERIC_STRING() + '/';
[5836]303    }
304
305    /*static*/ std::string PathConfig::getExternalDataPathString()
306    {
[8351]307        return getInstance().externalDataPath_.BF_GENERIC_STRING() + '/';
[5836]308    }
309
310    /*static*/ std::string PathConfig::getConfigPathString()
311    {
[8351]312        return getInstance().configPath_.BF_GENERIC_STRING() + '/';
[5836]313    }
314
315    /*static*/ std::string PathConfig::getLogPathString()
316    {
[8351]317        return getInstance().logPath_.BF_GENERIC_STRING() + '/';
[5836]318    }
319
320    /*static*/ std::string PathConfig::getModulePathString()
321    {
[8351]322        return getInstance().modulePath_.BF_GENERIC_STRING() + '/';
[5836]323    }
[1505]324}
Note: See TracBrowser for help on using the repository browser.