Update libardour GPL boilerplate and (C) from git log
[ardour.git] / libs / ardour / filesystem_paths.cc
1 /*
2  * Copyright (C) 2007-2016 Tim Mayberry <mojofunk@gmail.com>
3  * Copyright (C) 2008-2011 David Robillard <d@drobilla.net>
4  * Copyright (C) 2008-2016 Paul Davis <paul@linuxaudiosystems.com>
5  * Copyright (C) 2009-2012 Carl Hetherington <carl@carlh.net>
6  * Copyright (C) 2013-2014 John Emmas <john@creativepost.co.uk>
7  * Copyright (C) 2014-2019 Robin Gareus <robin@gareus.org>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License along
20  * with this program; if not, write to the Free Software Foundation, Inc.,
21  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22  */
23 #include <cstdlib>
24 #include <iostream>
25
26 #include "pbd/compose.h"
27 #include "pbd/error.h"
28 #include "pbd/string_convert.h"
29
30 #include <glibmm/miscutils.h>
31 #include <glibmm/fileutils.h>
32
33 #include "ardour/directory_names.h"
34 #include "ardour/filesystem_paths.h"
35
36 #include "pbd/i18n.h"
37
38 #ifdef PLATFORM_WINDOWS
39 #include "shlobj.h"
40 #include "pbd/windows_special_dirs.h"
41 #endif
42
43 using namespace PBD;
44
45 namespace ARDOUR {
46
47 using std::string;
48
49 static std::string
50 user_config_directory_name (int version = -1)
51 {
52         if (version < 0) {
53                 version = string_to<int32_t>(X_(PROGRAM_VERSION));
54         }
55
56         /* ARDOUR::Profile may not be available when this is
57            called, so rely on build-time detection of the
58            product name etc.
59         */
60
61 #ifdef USE_TRACKS_CODE_FEATURES
62         /* Tracks does not use versioned configuration folders, which may or
63            may not be problematic in the future.
64         */
65         return X_(PROGRAM_NAME);
66
67 #else
68         const string config_dir_name = string_compose ("%1%2", X_(PROGRAM_NAME), version);
69
70 #if defined (__APPLE__) || defined (PLATFORM_WINDOWS)
71         /* Use mixed-case folder name on OS X and Windows */
72         return config_dir_name;
73 #else
74         /* use lower case folder name on Linux */
75         return downcase (config_dir_name);
76 #endif
77 #endif
78 }
79
80 std::string
81 user_config_directory (int version)
82 {
83         std::string p;
84
85 #ifdef __APPLE__
86
87         p = Glib::build_filename (Glib::get_home_dir(), "Library/Preferences");
88
89 #else
90
91         const char* c = 0;
92         /* adopt freedesktop standards, and put .ardour3 into $XDG_CONFIG_HOME or ~/.config */
93         if ((c = getenv ("XDG_CONFIG_HOME")) != 0) {
94                 p = c;
95         } else {
96
97 #ifdef PLATFORM_WINDOWS
98                 // Not technically the home dir (since it needs to be a writable folder)
99                 const string home_dir = Glib::get_user_config_dir();
100 #else
101                 const string home_dir = Glib::get_home_dir();
102 #endif
103                 if (home_dir.empty ()) {
104                         error << "Unable to determine home directory" << endmsg;
105                         exit (EXIT_FAILURE);
106                 }
107                 p = home_dir;
108
109 #ifndef PLATFORM_WINDOWS
110                 p = Glib::build_filename (p, ".config");
111 #endif
112
113         }
114 #endif // end not __APPLE__
115
116         p = Glib::build_filename (p, user_config_directory_name (version));
117
118         if (version < 0) {
119                 /* Only create the user config dir if the version was negative,
120                    meaning "for the current version.
121                 */
122                 if (!Glib::file_test (p, Glib::FILE_TEST_EXISTS)) {
123                         if (g_mkdir_with_parents (p.c_str(), 0755)) {
124                                 error << string_compose (_("Cannot create Configuration directory %1 - cannot run"),
125                                                          p) << endmsg;
126                                 exit (EXIT_FAILURE);
127                         }
128                         } else if (!Glib::file_test (p, Glib::FILE_TEST_IS_DIR)) {
129                         fatal << string_compose (_("Configuration directory %1 already exists and is not a directory/folder - cannot run"),
130                                                  p) << endmsg;
131                         abort(); /*NOTREACHED*/
132                 }
133         }
134
135         return p;
136 }
137
138 std::string
139 user_cache_directory (std::string cachename)
140 {
141         std::string p;
142
143 #ifdef __APPLE__
144         p = Glib::build_filename (Glib::get_home_dir(), "Library/Caches");
145 #else
146         const char* c = 0;
147
148         /* adopt freedesktop standards, and put .ardour3 into $XDG_CACHE_HOME
149          * defaulting to or ~/.config
150          */
151         if ((c = getenv ("XDG_CACHE_HOME")) != 0) {
152                 p = c;
153         } else {
154
155 #ifdef PLATFORM_WINDOWS
156                 // Not technically the home dir (since it needs to be a writable folder)
157                 const string home_dir = Glib::get_user_data_dir();
158 #else
159                 const string home_dir = Glib::get_home_dir();
160 #endif
161                 if (home_dir.empty ()) {
162                         error << "Unable to determine home directory" << endmsg;
163                         exit (EXIT_FAILURE);
164                 }
165                 p = home_dir;
166
167 #ifndef PLATFORM_WINDOWS
168                 p = Glib::build_filename (p, ".cache");
169 #endif
170
171         }
172 #endif // end not __APPLE__
173
174         if (cachename.empty ()) {
175                 p = Glib::build_filename (p, user_config_directory_name ());
176         } else {
177                 p = Glib::build_filename (p, cachename);
178         }
179
180 #ifdef PLATFORM_WINDOWS
181          /* On Windows Glib::get_user_data_dir is the folder to use for local
182                 * (as opposed to roaming) application data.
183                 * See documentation for CSIDL_LOCAL_APPDATA.
184                 * Glib::get_user_data_dir() == GLib::get_user_config_dir()
185                 * so we add an extra subdir *below* the config dir.
186                 */
187         p = Glib::build_filename (p, "cache");
188 #endif
189
190         if (!Glib::file_test (p, Glib::FILE_TEST_EXISTS)) {
191                 if (g_mkdir_with_parents (p.c_str(), 0755)) {
192                         error << string_compose (_("Cannot create cache directory %1 - cannot run"),
193                                                    p) << endmsg;
194                         exit (EXIT_FAILURE);
195                 }
196         } else if (!Glib::file_test (p, Glib::FILE_TEST_IS_DIR)) {
197                 fatal << string_compose (_("Cache directory %1 already exists and is not a directory/folder - cannot run"),
198                                            p) << endmsg;
199                 abort(); /*NOTREACHED*/
200         }
201
202         return p;
203 }
204
205 std::string
206 ardour_dll_directory ()
207 {
208 #ifdef PLATFORM_WINDOWS
209         std::string dll_dir_path(windows_package_directory_path());
210         dll_dir_path = Glib::build_filename (dll_dir_path, "lib");
211         return Glib::build_filename (dll_dir_path, LIBARDOUR);
212 #else
213         std::string s = Glib::getenv("ARDOUR_DLL_PATH");
214         if (s.empty()) {
215                 std::cerr << _("ARDOUR_DLL_PATH not set in environment - exiting\n");
216                 ::exit (EXIT_FAILURE);
217         }
218         return s;
219 #endif
220 }
221
222 #ifdef PLATFORM_WINDOWS
223 Searchpath
224 windows_search_path ()
225 {
226         std::string dll_dir_path(windows_package_directory_path());
227         dll_dir_path = Glib::build_filename (dll_dir_path, "share");
228         return Glib::build_filename (dll_dir_path, LIBARDOUR);
229 }
230
231 std::string
232 windows_package_directory_path ()
233 {
234         char* package_dir =
235             g_win32_get_package_installation_directory_of_module (NULL);
236
237         if (package_dir == NULL) {
238                 fatal << string_compose (_("Cannot determine %1 package directory"),
239                                            PROGRAM_NAME) << endmsg;
240                 abort(); /*NOTREACHED*/
241         }
242
243         std::string package_dir_path(package_dir);
244         g_free(package_dir);
245         return package_dir_path;
246 }
247 #endif
248
249 Searchpath
250 ardour_config_search_path ()
251 {
252         static Searchpath search_path;
253
254         if (search_path.empty()) {
255                 // Start by adding the user's personal config folder
256                 search_path += user_config_directory();
257 #ifdef PLATFORM_WINDOWS
258                 // On Windows, add am intermediate configuration folder
259                 // (one that's guaranteed to be writable by all users).
260                 const gchar* const *all_users_folder = g_get_system_config_dirs();
261                 // Despite its slightly odd name, the above returns a single entry which
262                 // corresponds to 'All Users' on Windows (according to the documentation)
263
264                 if (all_users_folder) {
265                         std::string writable_all_users_path = all_users_folder[0];
266                         writable_all_users_path += "\\";
267                         writable_all_users_path += PROGRAM_NAME;
268                         writable_all_users_path += "\\.config";
269 #ifdef _WIN64
270                         writable_all_users_path += "\\win64";
271 #else
272                         writable_all_users_path += "\\win32";
273 #endif
274                         search_path += writable_all_users_path;
275                 }
276
277                 // now add a suitable config path from the bundle
278                 search_path += windows_search_path ();
279 #endif
280                 // finally, add any paths from ARDOUR_CONFIG_PATH if it exists
281                 std::string s = Glib::getenv("ARDOUR_CONFIG_PATH");
282                 if (s.empty()) {
283                         std::cerr << _("ARDOUR_CONFIG_PATH not set in environment\n");
284                 } else {
285                         search_path += Searchpath (s);
286                 }
287         }
288
289         return search_path;
290 }
291
292 Searchpath
293 ardour_data_search_path ()
294 {
295         static Searchpath search_path;
296
297         if (search_path.empty()) {
298                 search_path += user_config_directory();
299 #ifdef PLATFORM_WINDOWS
300                 search_path += windows_search_path ();
301 #endif
302                 std::string s = Glib::getenv("ARDOUR_DATA_PATH");
303                 if (s.empty()) {
304                         std::cerr << _("ARDOUR_DATA_PATH not set in environment\n");
305                 } else {
306                         search_path += Searchpath (s);
307                 }
308         }
309
310         return search_path;
311 }
312
313 string
314 been_here_before_path (int version)
315 {
316         if (version < 0) {
317                 version = atoi (PROGRAM_VERSION);
318         }
319
320         return Glib::build_filename (user_config_directory (version), string (".a") + to_string (version));
321 }
322
323
324 } // namespace ARDOUR