Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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