possibly working Win32 build; make -j broken again (see no good way to force version...
[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
154 void environment_init(int argc, char* argv[])
155 {
156   args_init(argc, argv);
157
158   {
159     char *appdata = getenv("APPDATA");
160
161     StringOutputStream home(256);
162     if(!appdata || string_empty(appdata))
163     {
164       ERROR_MESSAGE("Application Data folder not available.\n"
165         "Please install shfolder redistributable package.\n"
166         "Radiant will use C:\\ for user preferences.\n");
167       home << "C:";
168     }
169     else
170     {
171       home << PathCleaned(appdata);
172     }
173     home << "/RadiantSettings/";
174     Q_mkdir(home.c_str());
175     home_path = home.c_str();
176   }
177   {
178     // get path to the editor
179     char filename[MAX_PATH+1];
180     GetModuleFileName(0, filename, MAX_PATH);
181     char* last_separator = strrchr(filename, '\\');
182     if(last_separator != 0)
183     {
184       *(last_separator+1) = '\0';
185     }
186     else
187     {
188       filename[0] = '\0';
189     }
190     StringOutputStream app(256);
191     app << PathCleaned(filename);
192     app_path = app.c_str();
193   }
194 }
195
196 #else
197 #error "unsupported platform"
198 #endif