Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 5929 was 5929, checked in by rgrieder, 15 years ago

Merged core5 branch back to the trunk.
Key features include clean level unloading and an extended XML event system.

Two important notes:
Delete your keybindings.ini files! * or you will still get parser errors when loading the key bindings.
Delete build_dir/lib/modules/libgamestates.module! * or orxonox won't start.
Best thing to do is to delete the build folder ;)

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