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