a3bfd43f31e9c38f5bafbcaebf67ee9f2d62aee2
[xonotic/netradiant.git] / radiant / environment.cpp
1 /*
2 Copyright (C) 2001-2006, William Joseph.
3 All Rights Reserved.
4
5 This file is part of GtkRadiant.
6
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 GtkRadiant is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20 */
21
22 #include "environment.h"
23
24 #include "stream/textstream.h"
25 #include "string/string.h"
26 #include "stream/stringstream.h"
27 #include "debugging/debugging.h"
28 #include "os/path.h"
29 #include "cmdlib.h"
30
31
32 int g_argc;
33 char** g_argv;
34
35 void args_init(int argc, char* argv[])
36 {
37   int i, j, k;
38
39   for (i = 1; i < argc; i++)
40   {
41     for (k = i; k < argc; k++)
42       if (argv[k] != 0)
43         break;
44
45     if (k > i)
46     {
47       k -= i;
48       for (j = i + k; j < argc; j++)
49         argv[j-k] = argv[j];
50       argc -= k;
51     }
52   }
53
54   g_argc = argc;
55   g_argv = argv;
56 }
57
58 namespace
59 {
60   CopiedString home_path;
61   CopiedString app_path;
62 }
63
64 const char* environment_get_home_path()
65 {
66   return home_path.c_str();
67 }
68
69 const char* environment_get_app_path()
70 {
71   return app_path.c_str();
72 }
73
74
75 #if defined(POSIX)
76
77 #include <stdlib.h>
78 #include <pwd.h>
79 #include <unistd.h> 
80
81 #include <glib/gutils.h>
82
83 const char* LINK_NAME =
84 #if defined (__linux__)
85   "/proc/self/exe"
86 #else // FreeBSD and OSX
87   "/proc/curproc/file"
88 #endif
89 ;
90
91 /// brief Returns the filename of the executable belonging to the current process, or 0 if not found.
92 char* getexename(char *buf)
93 {
94   /* Now read the symbolic link */
95   int ret = readlink(LINK_NAME, buf, PATH_MAX);
96
97   if(ret == -1)
98   {
99     globalOutputStream() << "getexename: falling back to argv[0]: " << makeQuoted(g_argv[0]);
100     const char* path = realpath(g_argv[0], buf);
101     if(path == 0)
102     {
103       /* In case of an error, leave the handling up to the caller */
104       return "";
105     }
106   }
107
108   /* Ensure proper NUL termination */
109   buf[ret] = 0;
110
111   /* delete the program name */
112   *(strrchr(buf, '/')) = '\0';
113
114   // NOTE: we build app path with a trailing '/'
115   // it's a general convention in Radiant to have the slash at the end of directories
116   if (buf[strlen(buf)-1] != '/')
117   {
118     strcat(buf, "/");
119   }
120
121   return buf;
122 }
123
124 void environment_init(int argc, char* argv[])
125 {
126   // Give away unnecessary root privileges.
127   // Important: must be done before calling gtk_init().
128   char *loginname;
129   struct passwd *pw;
130   seteuid(getuid());
131   if (geteuid() == 0 && (loginname = getlogin()) != 0 &&
132       (pw = getpwnam(loginname)) != 0)
133     setuid(pw->pw_uid);
134
135   args_init(argc, argv);
136
137   {
138     StringOutputStream home(256);
139     home << DirectoryCleaned(g_get_home_dir()) << ".radiant/";
140     Q_mkdir(home.c_str());
141     home_path = home.c_str();
142   }
143   {
144     char real[PATH_MAX];
145     app_path = getexename(real);
146     ASSERT_MESSAGE(!string_empty(app_path.c_str()), "failed to deduce app path");
147   }
148 }
149
150 #elif defined(WIN32)
151
152 #include <windows.h>
153 #include <shfolder.h>
154
155 void environment_init(int argc, char* argv[])
156 {
157   args_init(argc, argv);
158
159   {
160     char appdata[MAX_PATH+1];
161     SHGetFolderPath(0, CSIDL_APPDATA, 0, 0, appdata);
162
163     StringOutputStream home(256);
164     if(string_empty(appdata))
165     {
166       ERROR_MESSAGE("Application Data folder not available.\n"
167         "Please install shfolder redistributable package.\n"
168         "Radiant will use C:\\ for user preferences.\n");
169       home << "C:";
170     }
171     else
172     {
173       home << PathCleaned(appdata);
174     }
175     home << "/RadiantSettings/";
176     Q_mkdir(home.c_str());
177     home_path = home.c_str();
178   }
179   {
180     // get path to the editor
181     char filename[MAX_PATH+1];
182     GetModuleFileName(0, filename, MAX_PATH);
183     char* last_separator = strrchr(filename, '\\');
184     if(last_separator != 0)
185     {
186       *(last_separator+1) = '\0';
187     }
188     else
189     {
190       filename[0] = '\0';
191     }
192     StringOutputStream app(256);
193     app << PathCleaned(filename);
194     app_path = app.c_str();
195   }
196 }
197
198 #else
199 #error "unsupported platform"
200 #endif