1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/unix/stdpaths.cpp
3 // Purpose: wxStandardPaths implementation for Unix & OpenVMS systems
4 // Author: Vadim Zeitlin
5 // Modified by:
6 // Created: 2004-10-19
7 // Copyright: (c) 2004 Vadim Zeitlin <vadim@wxwidgets.org>
8 // Licence: wxWindows licence
9 ///////////////////////////////////////////////////////////////////////////////
10
11 // ============================================================================
12 // declarations
13 // ============================================================================
14
15 // ----------------------------------------------------------------------------
16 // headers
17 // ----------------------------------------------------------------------------
18
19 // for compilers that support precompilation, includes "wx.h".
20 #include "wx/wxprec.h"
21
22
23 #if wxUSE_STDPATHS
24
25 #include "wx/stdpaths.h"
26
27 #ifndef WX_PRECOMP
28 #include "wx/app.h"
29 #include "wx/wxcrt.h"
30 #include "wx/utils.h"
31 #endif //WX_PRECOMP
32
33 #include "wx/filename.h"
34 #include "wx/log.h"
35 #include "wx/textfile.h"
36
37 #if defined( __LINUX__ ) || defined( __VMS )
38 #include <unistd.h>
39 #endif
40
41 // ============================================================================
42 // common VMS/Unix part of wxStandardPaths implementation
43 // ============================================================================
44
SetInstallPrefix(const wxString & prefix)45 void wxStandardPaths::SetInstallPrefix(const wxString& prefix)
46 {
47 m_prefix = prefix;
48 }
49
50 // Helper function returning the value of XDG_CONFIG_HOME environment variable
51 // or its default value if it is not defined.
GetXDGConfigHome()52 static wxString GetXDGConfigHome()
53 {
54 wxString dir;
55 if ( !wxGetEnv(wxS("XDG_CONFIG_HOME"), &dir) || dir.empty() )
56 dir = wxFileName::GetHomeDir() + wxS("/.config");
57 return dir;
58 }
59
GetUserConfigDir() const60 wxString wxStandardPaths::GetUserConfigDir() const
61 {
62 wxString dir;
63
64 switch ( GetFileLayout() )
65 {
66 case FileLayout_Classic:
67 dir = wxFileName::GetHomeDir();
68 break;
69
70 case FileLayout_XDG:
71 dir = GetXDGConfigHome();
72 break;
73 }
74
75 wxASSERT_MSG( !dir.empty(), wxS("unsupported file layout") );
76
77 return dir;
78 }
79
80
81 // ============================================================================
82 // wxStandardPaths implementation for VMS
83 // ============================================================================
84
85 #ifdef __VMS
86
GetInstallPrefix() const87 wxString wxStandardPaths::GetInstallPrefix() const
88 {
89 if ( m_prefix.empty() )
90 {
91 const_cast<wxStandardPaths *>(this)->m_prefix = wxT("/sys$system");
92 }
93
94 return m_prefix;
95 }
96
GetConfigDir() const97 wxString wxStandardPaths::GetConfigDir() const
98 {
99 return wxT("/sys$manager");
100 }
101
GetDataDir() const102 wxString wxStandardPaths::GetDataDir() const
103 {
104 return AppendAppInfo(GetInstallPrefix() + wxT("/sys$share"));
105 }
106
GetLocalDataDir() const107 wxString wxStandardPaths::GetLocalDataDir() const
108 {
109 return AppendAppInfo(wxT("/sys$manager"));
110 }
111
GetUserDataDir() const112 wxString wxStandardPaths::GetUserDataDir() const
113 {
114 return wxFileName::GetHomeDir();
115 }
116
GetPluginsDir() const117 wxString wxStandardPaths::GetPluginsDir() const
118 {
119 return wxString(); // TODO: this is wrong, it should return something
120 }
121
122 wxString
GetLocalizedResourcesDir(const wxString & lang,ResourceCat category) const123 wxStandardPaths::GetLocalizedResourcesDir(const wxString& lang,
124 ResourceCat category) const
125 {
126 return wxStandardPathsBase::GetLocalizedResourcesDir(lang, category);
127 }
128
GetExecutablePath() const129 wxString wxStandardPaths::GetExecutablePath() const
130 {
131 return wxStandardPathsBase::GetExecutablePath();
132 }
133
134 #else // !__VMS
135
136 // ============================================================================
137 // wxStandardPaths implementation for Unix
138 // ============================================================================
139
GetExecutablePath() const140 wxString wxStandardPaths::GetExecutablePath() const
141 {
142 #ifdef __LINUX__
143 wxString exeStr;
144
145 char buf[4096];
146 int result = readlink("/proc/self/exe", buf, WXSIZEOF(buf) - 1);
147 if ( result != -1 )
148 {
149 buf[result] = '\0'; // readlink() doesn't NUL-terminate the buffer
150
151 // if the /proc/self/exe symlink has been dropped by the kernel for
152 // some reason, then readlink() could also return success but
153 // "(deleted)" as link destination...
154 if ( strcmp(buf, "(deleted)") != 0 )
155 exeStr = wxString(buf, wxConvLibc);
156 }
157
158 if ( exeStr.empty() )
159 {
160 // UPX-specific hack: when using UPX on linux, the kernel will drop the
161 // /proc/self/exe link; in this case we try to look for a special
162 // environment variable called " " which is created by UPX to save
163 // /proc/self/exe contents. See
164 // http://sf.net/tracker/?func=detail&atid=309863&aid=1565357&group_id=9863
165 // for more information about this issue.
166 wxGetEnv(wxT(" "), &exeStr);
167 }
168
169 if ( !exeStr.empty() )
170 return exeStr;
171 #endif // __LINUX__
172
173 return wxStandardPathsBase::GetExecutablePath();
174 }
175
DetectPrefix()176 void wxStandardPaths::DetectPrefix()
177 {
178 // we can try to infer the prefix from the location of the executable
179 wxString exeStr = GetExecutablePath();
180 if ( !exeStr.empty() )
181 {
182 // consider that we're in the last "bin" subdirectory of our prefix
183 size_t pos = exeStr.rfind(wxT("/bin/"));
184 if ( pos != wxString::npos )
185 m_prefix.assign(exeStr, 0, pos);
186 }
187
188 if ( m_prefix.empty() )
189 {
190 m_prefix = wxT("/usr/local");
191 }
192 }
193
GetInstallPrefix() const194 wxString wxStandardPaths::GetInstallPrefix() const
195 {
196 if ( m_prefix.empty() )
197 {
198 wxStandardPaths *pathPtr = const_cast<wxStandardPaths *>(this);
199 pathPtr->DetectPrefix();
200 }
201
202 return m_prefix;
203 }
204
205 // ----------------------------------------------------------------------------
206 // public functions
207 // ----------------------------------------------------------------------------
208
GetConfigDir() const209 wxString wxStandardPaths::GetConfigDir() const
210 {
211 return wxT("/etc");
212 }
213
GetDataDir() const214 wxString wxStandardPaths::GetDataDir() const
215 {
216 // allow to override the location of the data directory by setting
217 // WX_APPNAME_DATA_DIR environment variable: this is very useful in
218 // practice for running well-written (and so using wxStandardPaths to find
219 // their files) wx applications without installing them
220 static const wxString
221 envOverride(
222 getenv(
223 ("WX_" + wxTheApp->GetAppName().Upper() + "_DATA_DIR").c_str()
224 )
225 );
226
227 if ( !envOverride.empty() )
228 return envOverride;
229
230 return AppendAppInfo(GetInstallPrefix() + wxT("/share"));
231 }
232
GetLocalDataDir() const233 wxString wxStandardPaths::GetLocalDataDir() const
234 {
235 return AppendAppInfo(wxT("/etc"));
236 }
237
GetUserDataDir() const238 wxString wxStandardPaths::GetUserDataDir() const
239 {
240 return AppendAppInfo(wxFileName::GetHomeDir() + wxT("/."));
241 }
242
GetPluginsDir() const243 wxString wxStandardPaths::GetPluginsDir() const
244 {
245 return AppendAppInfo(GetInstallPrefix() + wxT("/lib"));
246 }
247
248 wxString
GetLocalizedResourcesDir(const wxString & lang,ResourceCat category) const249 wxStandardPaths::GetLocalizedResourcesDir(const wxString& lang,
250 ResourceCat category) const
251 {
252 if ( category != ResourceCat_Messages )
253 return wxStandardPathsBase::GetLocalizedResourcesDir(lang, category);
254
255 return GetInstallPrefix() + wxT("/share/locale/") + lang + wxT("/LC_MESSAGES");
256 }
257
GetUserDir(Dir userDir) const258 wxString wxStandardPaths::GetUserDir(Dir userDir) const
259 {
260 // Note that we do not use the file layout here because there is no reason
261 // not to respect the XDG convention even if SetFileLayout(FileLayout_XDG)
262 // hadn't been called: we're not bound by any backwards compatibility
263 // considerations as there can't be any pre-existing config or data files
264 // in the home directory that wouldn't be found any longer after updating
265 // the version of wxWidgets used by the application.
266
267 wxLogNull logNull;
268 const wxString homeDir = wxFileName::GetHomeDir();
269 if (userDir == Dir_Cache)
270 {
271 wxString cacheDir;
272 if ( !wxGetEnv(wxS("XDG_CACHE_HOME"), &cacheDir) )
273 cacheDir = homeDir + wxS("/.cache");
274
275 return cacheDir;
276 }
277
278 const wxFileName dirsFile(GetXDGConfigHome(), wxS("user-dirs.dirs"));
279 if ( dirsFile.FileExists() )
280 {
281 wxString userDirId;
282 switch (userDir)
283 {
284 case Dir_Desktop:
285 userDirId = "XDG_DESKTOP_DIR";
286 break;
287 case Dir_Downloads:
288 userDirId = "XDG_DOWNLOAD_DIR";
289 break;
290 case Dir_Music:
291 userDirId = "XDG_MUSIC_DIR";
292 break;
293 case Dir_Pictures:
294 userDirId = "XDG_PICTURES_DIR";
295 break;
296 case Dir_Videos:
297 userDirId = "XDG_VIDEOS_DIR";
298 break;
299 default:
300 userDirId = "XDG_DOCUMENTS_DIR";
301 break;
302 }
303
304 wxTextFile textFile;
305 if ( textFile.Open(dirsFile.GetFullPath()) )
306 {
307 for ( wxString line = textFile.GetFirstLine();
308 !textFile.Eof();
309 line = textFile.GetNextLine() )
310 {
311 int pos = line.Find(userDirId);
312 if (pos != wxNOT_FOUND)
313 {
314 wxString value = line.AfterFirst(wxT('='));
315 value.Replace(wxT("$HOME"), homeDir);
316 value.Trim(true);
317 value.Trim(false);
318 // Remove quotes
319 value.Replace("\"", "", true /* replace all */);
320 if (!value.IsEmpty() && wxDirExists(value))
321 return value;
322 else
323 break;
324 }
325 }
326 }
327 }
328
329 return wxStandardPathsBase::GetUserDir(userDir);
330 }
331
332 #endif // __VMS/!__VMS
333
334 wxString
MakeConfigFileName(const wxString & basename,ConfigFileConv conv) const335 wxStandardPaths::MakeConfigFileName(const wxString& basename,
336 ConfigFileConv conv) const
337 {
338 wxFileName fn(wxEmptyString, basename);
339
340 bool addExt = false;
341
342 switch ( GetFileLayout() )
343 {
344 case FileLayout_Classic:
345 switch ( conv )
346 {
347 case ConfigFileConv_Dot:
348 fn.SetName(wxT('.') + fn.GetName());
349 break;
350
351 case ConfigFileConv_Ext:
352 addExt = true;
353 break;
354 }
355 break;
356
357 case FileLayout_XDG:
358 // Dot files are never used in XDG mode.
359 addExt = true;
360 break;
361 }
362
363 if ( addExt )
364 fn.SetExt(wxS("conf"));
365
366 return fn.GetFullName();
367 }
368
369 #endif // wxUSE_STDPATHS
370