/
ApplicationContextImpl.cpp
266 lines (215 loc) · 6.08 KB
/
ApplicationContextImpl.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
#include "ApplicationContextImpl.h"
#include <locale>
#include "string/string.h"
#include "debugging/debugging.h"
#include "itextstream.h"
#include "iregistry.h"
#include "os/path.h"
#include "os/dir.h"
#include "log/PopupErrorHandler.h"
#include "log/LogStream.h"
#include <boost/algorithm/string/predicate.hpp>
#if defined(WIN32)
#include <windows.h>
#endif
namespace radiant
{
/**
* Return the application path of the current Radiant instance.
*/
std::string ApplicationContextImpl::getApplicationPath() const
{
return _appPath;
}
std::string ApplicationContextImpl::getRuntimeDataPath() const
{
#if defined(POSIX) && defined (PKGDATADIR)
return std::string(PKGDATADIR) + "/";
#elif defined(__APPLE__)
return std::string("Resources/");
#else
return getApplicationPath();
#endif
}
std::string ApplicationContextImpl::getSettingsPath() const
{
return _settingsPath;
}
std::string ApplicationContextImpl::getBitmapsPath() const
{
return getRuntimeDataPath() + "bitmaps/";
}
const ApplicationContext::ArgumentList&
ApplicationContextImpl::getCmdLineArgs() const
{
return _cmdLineArgs;
}
std::ostream& ApplicationContextImpl::getOutputStream() const
{
return GlobalOutputStream().getStream();
}
std::ostream& ApplicationContextImpl::getWarningStream() const
{
return GlobalWarningStream().getStream();
}
std::ostream& ApplicationContextImpl::getErrorStream() const
{
return GlobalErrorStream().getStream();
}
std::mutex& ApplicationContextImpl::getStreamLock() const
{
return applog::LogStream::GetStreamLock();
}
// ============== OS-Specific Implementations go here ===================
// ================ POSIX ====================
#if defined(POSIX)
#include <stdlib.h>
#include <pwd.h>
#include <unistd.h>
namespace
{
const char* LINK_NAME =
#if defined (__linux__)
"/proc/self/exe"
#else // FreeBSD and OSX
"/proc/curproc/file"
#endif
;
/// brief Returns the filename of the executable belonging to the current process, or 0 if not found.
std::string getExecutablePath(char* argv[])
{
char buf[PATH_MAX];
// Now read the symbolic link
int ret = readlink(LINK_NAME, buf, PATH_MAX);
if (ret == -1)
{
rMessage() << "getexename: falling back to argv[0]: '" << argv[0] << "'\n";
const char* path = realpath(argv[0], buf);
if (path == nullptr)
{
// In case of an error, leave the handling up to the caller
return std::string();
}
}
/* Ensure proper NUL termination */
buf[ret] = '\0';
/* delete the program name */
*(strrchr(buf, '/')) = '\0';
// NOTE: we build app path with a trailing '/'
// it's a general convention in Radiant to have the slash at the end of directories
if (buf[strlen(buf)-1] != '/')
{
strcat(buf, "/");
}
return std::string(buf);
}
}
void ApplicationContextImpl::initialise(int argc, char* argv[]) {
// Give away unnecessary root privileges.
// Important: must be done before calling gtk_init().
char *loginname;
struct passwd *pw;
seteuid(getuid());
if (geteuid() == 0 &&
(loginname = getlogin()) != 0 &&
(pw = getpwnam(loginname)) != 0)
{
setuid(pw->pw_uid);
}
initArgs(argc, argv);
// Initialise the home directory path
std::string homedir = getenv("HOME");
std::string home = os::standardPathWithSlash(homedir) + ".darkradiant/";
os::makeDirectory(home);
_homePath = home;
{
_appPath = getExecutablePath(argv);
ASSERT_MESSAGE(!_appPath.empty(), "failed to deduce app path");
}
// Initialise the relative paths
initPaths();
}
// ================ WIN32 ====================
#elif defined(WIN32)
void ApplicationContextImpl::initialise(int argc, char* argv[])
{
initArgs(argc, argv);
// Get application data directory from environment
std::string appData = getenv("APPDATA");
if (appData.empty())
{
throw std::runtime_error(
"Critical: cannot find APPDATA environment variable."
);
}
// Construct DarkRadiant home directory
_homePath = appData + "\\DarkRadiant";
if (!os::makeDirectory(_homePath))
{
rConsoleError() << "ApplicationContextImpl: could not create home directory "
<< "'" << _homePath << "'" << std::endl;
}
{
// get path to the editor
wchar_t filename[MAX_PATH+1];
GetModuleFileName(0, filename, MAX_PATH);
wchar_t* last_separator = wcsrchr(filename, '\\');
if (last_separator != 0) {
*(last_separator+1) = '\0';
}
else {
filename[0] = '\0';
}
// convert to std::string
std::wstring wide(filename);
std::string appPathNarrow(wide.begin(), wide.end());
// Make sure we have forward slashes
_appPath = os::standardPath(appPathNarrow);
}
// Initialise the relative paths
initPaths();
}
#else
#error "unsupported platform"
#endif
// ============== OS-Specific Implementations end ===================
void ApplicationContextImpl::initArgs(int argc, char* argv[])
{
// Store the arguments locally, ignore the first one
for (int i = 1; i < argc; i++) {
_cmdLineArgs.push_back(argv[i]);
}
}
void ApplicationContextImpl::initPaths()
{
// Ensure that the homepath ends with a slash
_homePath = os::standardPathWithSlash(_homePath);
_appPath = os::standardPathWithSlash(_appPath);
// Make sure the home/settings folder exists (attempt to create it)
_settingsPath = _homePath;
if (!os::makeDirectory(_settingsPath))
{
rConsoleError() << "ApplicationContextImpl: unable to create settings path '"
<< _settingsPath << "'" << std::endl;
}
}
void ApplicationContextImpl::savePathsToRegistry() const {
GlobalRegistry().set(RKEY_APP_PATH, _appPath);
GlobalRegistry().set(RKEY_HOME_PATH, _homePath);
GlobalRegistry().set(RKEY_SETTINGS_PATH, _settingsPath);
GlobalRegistry().set(RKEY_BITMAPS_PATH, getBitmapsPath());
}
const ErrorHandlingFunction& ApplicationContextImpl::getErrorHandlingFunction() const
{
return _errorHandler;
}
void ApplicationContextImpl::initErrorHandler()
{
#ifdef _DEBUG
// Use the PopupErrorHandler, which displays a popup box
_errorHandler = radiant::PopupErrorHandler::HandleError;
// Initialise the function pointer in our binary's scope
GlobalErrorHandler() = _errorHandler;
#endif
}
} // namespace module