Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 9609 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
Line 
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:
23 *      Reto Grieder
24 *   Co-authors:
25 *      ...
26 *
27 */
28
29#include "PathConfig.h"
30
31#include <cassert>
32#include <cstdlib>
33#include <cstdio>
34#include <vector>
35#include <boost/filesystem.hpp>
36
37#ifdef ORXONOX_PLATFORM_WINDOWS
38#  ifndef WIN32_LEAN_AND_MEAN
39#    define WIN32_LEAN_AND_MEAN
40#  endif
41#  include <windows.h>
42#  undef min
43#  undef max
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"
53#include "util/Output.h"
54#include "util/Exception.h"
55#include "CommandLineParser.h"
56
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
62#else
63#  define BF_LEAF path().filename().string
64#  define BF_GENERIC_STRING generic_string
65#  define BF_NATIVE_STRING string
66#endif
67
68namespace orxonox
69{
70    namespace bf = boost::filesystem;
71
72    //! Static pointer to the singleton
73    PathConfig* PathConfig::singletonPtr_s  = 0;
74
75    SetCommandLineArgument(externalDataPath, "").information("Path to the external data files");
76    SetCommandLineArgument(writingPathSuffix, "").information("Additional subfolder for config and log files");
77
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()))
86        , bBuildDirectoryRun_(false)
87    {
88        //////////////////////////
89        // FIND EXECUTABLE PATH //
90        //////////////////////////
91
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];
100        uint32_t path_len = 1023;
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
130        // Remove executable filename
131        executablePath_ = bf::path(buffer).branch_path();
132
133        /////////////////////
134        // SET MODULE PATH //
135        /////////////////////
136
137        if (bf::exists(executablePath_ / "orxonox_dev_build.keep_me"))
138        {
139            orxout(internal_info) << "Running from the build tree." << endl;
140            PathConfig::bBuildDirectoryRun_ = true;
141            modulePath_ = specialConfig::moduleDevDirectory;
142        }
143        else
144        {
145
146#ifdef INSTALL_COPYABLE // --> relative paths
147
148            // Also set the root path
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())
154                ThrowException(General, "Could not derive a root directory. Might the binary installation directory contain '..' when taken relative to the installation prefix path?");
155
156            // Module path is fixed as well
157            modulePath_ = rootPath_ / specialConfig::defaultModulePath;
158
159#else
160
161            // There is no root path, so don't set it at all
162            // Module path is fixed as well
163            modulePath_ = specialConfig::moduleInstallDirectory;
164
165#endif
166        }
167    }
168
169    PathConfig::~PathConfig()
170    {
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    {
182        if (bBuildDirectoryRun_)
183        {
184            dataPath_         = specialConfig::dataDevDirectory;
185            configPath_       = specialConfig::configDevDirectory;
186            logPath_          = specialConfig::logDevDirectory;
187
188            // Check for data path override by the command line
189            if (!CommandLineParser::getArgument("externalDataPath")->hasDefaultValue())
190                externalDataPath_ = CommandLineParser::getValue("externalDataPath").get<std::string>();
191            else
192                externalDataPath_ = specialConfig::externalDataDevDirectory;
193        }
194        else
195        {
196
197#ifdef INSTALL_COPYABLE // --> relative paths
198
199            // Using paths relative to the install prefix, complete them
200            dataPath_   = rootPath_ / specialConfig::defaultDataPath;
201            configPath_ = rootPath_ / specialConfig::defaultConfigPath;
202            logPath_    = rootPath_ / specialConfig::defaultLogPath;
203
204#else
205
206            dataPath_  = specialConfig::dataInstallDirectory;
207
208            // Get user directory
209#ifdef ORXONOX_PLATFORM_UNIX
210            char* userDataPathPtr(getenv("HOME"));
211#else
212            char* userDataPathPtr(getenv("APPDATA"));
213#endif
214            if (userDataPathPtr == NULL)
215                ThrowException(General, "Could not retrieve user data path.");
216            bf::path userDataPath(userDataPathPtr);
217            userDataPath /= ".orxonox";
218
219            configPath_ = userDataPath / specialConfig::defaultConfigPath;
220            logPath_    = userDataPath / specialConfig::defaultLogPath;
221
222#endif
223
224        }
225
226        // Option to put all the config and log files in a separate folder
227        if (!CommandLineParser::getArgument("writingPathSuffix")->hasDefaultValue())
228        {
229            const std::string& directory(CommandLineParser::getValue("writingPathSuffix").get<std::string>());
230            configPath_ = configPath_ / directory;
231            logPath_    = logPath_    / directory;
232        }
233
234        // Create directories to avoid problems when opening files in non existent folders.
235        std::vector<std::pair<bf::path, std::string> > directories;
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")));
238
239        for (std::vector<std::pair<bf::path, std::string> >::iterator it = directories.begin();
240            it != directories.end(); ++it)
241        {
242            if (bf::exists(it->first) && !bf::is_directory(it->first))
243            {
244                ThrowException(General, std::string("The ") + it->second + " directory has been preoccupied by a file! \
245                                         Please remove " + it->first.BF_GENERIC_STRING());
246            }
247            if (bf::create_directories(it->first)) // function may not return true at all (bug?)
248            {
249                orxout(internal_info) << "Created " << it->second << " directory" << endl;
250            }
251        }
252    }
253
254    std::vector<std::string> PathConfig::getModulePaths()
255    {
256        std::vector<std::string> modulePaths;
257
258        // We search for helper files with the following extension
259        const std::string& moduleextension = specialConfig::moduleExtension;
260        size_t moduleextensionlength = moduleextension.size();
261
262#ifdef ORXONOX_PLATFORM_WINDOWS
263        // Add that path to the PATH variable in case a module depends on another one
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
270
271        // Make sure the path exists, otherwise don't load modules
272        if (!boost::filesystem::exists(modulePath_))
273            return modulePaths;
274
275        boost::filesystem::directory_iterator file(modulePath_);
276        boost::filesystem::directory_iterator end;
277
278        // Iterate through all files
279        while (file != end)
280        {
281            std::string filename = file->BF_LEAF();
282
283            // Check if the file ends with the extension in question
284            if (filename.size() > moduleextensionlength)
285            {
286                if (filename.substr(filename.size() - moduleextensionlength) == moduleextension)
287                {
288                    // We've found a helper file
289                    const std::string& library = filename.substr(0, filename.size() - moduleextensionlength);
290                    modulePaths.push_back(getModulePathString() + library);
291                }
292            }
293            ++file;
294        }
295
296        return modulePaths;
297    }
298
299    /*static*/ std::string PathConfig::getRootPathString()
300    {
301        return getInstance().rootPath_.BF_GENERIC_STRING() + '/';
302    }
303
304    /*static*/ std::string PathConfig::getExecutablePathString()
305    {
306        return getInstance().executablePath_.BF_GENERIC_STRING() + '/';
307    }
308
309    /*static*/ std::string PathConfig::getDataPathString()
310    {
311        return getInstance().dataPath_.BF_GENERIC_STRING() + '/';
312    }
313
314    /*static*/ std::string PathConfig::getExternalDataPathString()
315    {
316        return getInstance().externalDataPath_.BF_GENERIC_STRING() + '/';
317    }
318
319    /*static*/ std::string PathConfig::getConfigPathString()
320    {
321        return getInstance().configPath_.BF_GENERIC_STRING() + '/';
322    }
323
324    /*static*/ std::string PathConfig::getLogPathString()
325    {
326        return getInstance().logPath_.BF_GENERIC_STRING() + '/';
327    }
328
329    /*static*/ std::string PathConfig::getModulePathString()
330    {
331        return getInstance().modulePath_.BF_GENERIC_STRING() + '/';
332    }
333}
Note: See TracBrowser for help on using the repository browser.