summaryrefslogtreecommitdiff
path: root/libs/ardour/filesystem_paths.cc
blob: 1d1bd125ddbbded3dfeeb9d6304bd972af8ae246 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
/*
 * Copyright (C) 2007-2016 Tim Mayberry <mojofunk@gmail.com>
 * Copyright (C) 2008-2011 David Robillard <d@drobilla.net>
 * Copyright (C) 2008-2016 Paul Davis <paul@linuxaudiosystems.com>
 * Copyright (C) 2009-2012 Carl Hetherington <carl@carlh.net>
 * Copyright (C) 2013-2014 John Emmas <john@creativepost.co.uk>
 * Copyright (C) 2014-2019 Robin Gareus <robin@gareus.org>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */
#include <cstdlib>
#include <iostream>

#include "pbd/compose.h"
#include "pbd/error.h"
#include "pbd/string_convert.h"

#include <glibmm/miscutils.h>
#include <glibmm/fileutils.h>

#include "ardour/directory_names.h"
#include "ardour/filesystem_paths.h"

#include "pbd/i18n.h"

#ifdef PLATFORM_WINDOWS
#include "shlobj.h"
#include "pbd/windows_special_dirs.h"
#endif

using namespace PBD;

namespace ARDOUR {

using std::string;

static std::string
user_config_directory_name (int version = -1)
{
	if (version < 0) {
		version = string_to<int32_t>(X_(PROGRAM_VERSION));
	}

	/* ARDOUR::Profile may not be available when this is
	   called, so rely on build-time detection of the
	   product name etc.
	*/

	const string config_dir_name = string_compose ("%1%2", X_(PROGRAM_NAME), version);

#if defined (__APPLE__) || defined (PLATFORM_WINDOWS)
	/* Use mixed-case folder name on OS X and Windows */
	return config_dir_name;
#else
	/* use lower case folder name on Linux */
	return downcase (config_dir_name);
#endif
}

std::string
user_config_directory (int version)
{
	std::string p;

#ifdef __APPLE__

	p = Glib::build_filename (Glib::get_home_dir(), "Library/Preferences");

#else

	const char* c = 0;
	/* adopt freedesktop standards, and put .ardour3 into $XDG_CONFIG_HOME or ~/.config */
	if ((c = getenv ("XDG_CONFIG_HOME")) != 0) {
		p = c;
	} else {

#ifdef PLATFORM_WINDOWS
		// Not technically the home dir (since it needs to be a writable folder)
		const string home_dir = Glib::get_user_config_dir();
#else
		const string home_dir = Glib::get_home_dir();
#endif
		if (home_dir.empty ()) {
			error << "Unable to determine home directory" << endmsg;
			exit (EXIT_FAILURE);
		}
		p = home_dir;

#ifndef PLATFORM_WINDOWS
		p = Glib::build_filename (p, ".config");
#endif

	}
#endif // end not __APPLE__

	p = Glib::build_filename (p, user_config_directory_name (version));

	if (version < 0) {
		/* Only create the user config dir if the version was negative,
		   meaning "for the current version.
		*/
		if (!Glib::file_test (p, Glib::FILE_TEST_EXISTS)) {
			if (g_mkdir_with_parents (p.c_str(), 0755)) {
				error << string_compose (_("Cannot create Configuration directory %1 - cannot run"),
				                         p) << endmsg;
				exit (EXIT_FAILURE);
			}
			} else if (!Glib::file_test (p, Glib::FILE_TEST_IS_DIR)) {
			fatal << string_compose (_("Configuration directory %1 already exists and is not a directory/folder - cannot run"),
			                         p) << endmsg;
			abort(); /*NOTREACHED*/
		}
	}

	return p;
}

std::string
user_cache_directory (std::string cachename)
{
	std::string p;

#ifdef __APPLE__
	p = Glib::build_filename (Glib::get_home_dir(), "Library/Caches");
#else
	const char* c = 0;

	/* adopt freedesktop standards, and put .ardour3 into $XDG_CACHE_HOME
	 * defaulting to or ~/.config
	 */
	if ((c = getenv ("XDG_CACHE_HOME")) != 0) {
		p = c;
	} else {

#ifdef PLATFORM_WINDOWS
		// Not technically the home dir (since it needs to be a writable folder)
		const string home_dir = Glib::get_user_data_dir();
#else
		const string home_dir = Glib::get_home_dir();
#endif
		if (home_dir.empty ()) {
			error << "Unable to determine home directory" << endmsg;
			exit (EXIT_FAILURE);
		}
		p = home_dir;

#ifndef PLATFORM_WINDOWS
		p = Glib::build_filename (p, ".cache");
#endif

	}
#endif // end not __APPLE__

	if (cachename.empty ()) {
		p = Glib::build_filename (p, user_config_directory_name ());
	} else {
		p = Glib::build_filename (p, cachename);
	}

#ifdef PLATFORM_WINDOWS
	 /* On Windows Glib::get_user_data_dir is the folder to use for local
		* (as opposed to roaming) application data.
		* See documentation for CSIDL_LOCAL_APPDATA.
		* Glib::get_user_data_dir() == GLib::get_user_config_dir()
		* so we add an extra subdir *below* the config dir.
		*/
	p = Glib::build_filename (p, "cache");
#endif

	if (!Glib::file_test (p, Glib::FILE_TEST_EXISTS)) {
		if (g_mkdir_with_parents (p.c_str(), 0755)) {
			error << string_compose (_("Cannot create cache directory %1 - cannot run"),
						   p) << endmsg;
			exit (EXIT_FAILURE);
		}
	} else if (!Glib::file_test (p, Glib::FILE_TEST_IS_DIR)) {
		fatal << string_compose (_("Cache directory %1 already exists and is not a directory/folder - cannot run"),
					   p) << endmsg;
		abort(); /*NOTREACHED*/
	}

	return p;
}

std::string
ardour_dll_directory ()
{
#ifdef PLATFORM_WINDOWS
	std::string dll_dir_path(windows_package_directory_path());
	dll_dir_path = Glib::build_filename (dll_dir_path, "lib");
	return Glib::build_filename (dll_dir_path, LIBARDOUR);
#else
	std::string s = Glib::getenv("ARDOUR_DLL_PATH");
	if (s.empty()) {
		std::cerr << _("ARDOUR_DLL_PATH not set in environment - exiting\n");
		::exit (EXIT_FAILURE);
	}
	return s;
#endif
}

#ifdef PLATFORM_WINDOWS
Searchpath
windows_search_path ()
{
	std::string dll_dir_path(windows_package_directory_path());
	dll_dir_path = Glib::build_filename (dll_dir_path, "share");
	return Glib::build_filename (dll_dir_path, LIBARDOUR);
}

std::string
windows_package_directory_path ()
{
	char* package_dir =
	    g_win32_get_package_installation_directory_of_module (NULL);

	if (package_dir == NULL) {
		fatal << string_compose (_("Cannot determine %1 package directory"),
		                           PROGRAM_NAME) << endmsg;
		abort(); /*NOTREACHED*/
	}

	std::string package_dir_path(package_dir);
	g_free(package_dir);
	return package_dir_path;
}
#endif

Searchpath
ardour_config_search_path ()
{
	static Searchpath search_path;

	if (search_path.empty()) {
		// Start by adding the user's personal config folder
		search_path += user_config_directory();
#ifdef PLATFORM_WINDOWS
		// On Windows, add am intermediate configuration folder
		// (one that's guaranteed to be writable by all users).
		const gchar* const *all_users_folder = g_get_system_config_dirs();
		// Despite its slightly odd name, the above returns a single entry which
		// corresponds to 'All Users' on Windows (according to the documentation)

		if (all_users_folder) {
			std::string writable_all_users_path = all_users_folder[0];
			writable_all_users_path += "\\";
			writable_all_users_path += PROGRAM_NAME;
			writable_all_users_path += "\\.config";
#ifdef _WIN64
			writable_all_users_path += "\\win64";
#else
			writable_all_users_path += "\\win32";
#endif
			search_path += writable_all_users_path;
		}

		// now add a suitable config path from the bundle
		search_path += windows_search_path ();
#endif
		// finally, add any paths from ARDOUR_CONFIG_PATH if it exists
		std::string s = Glib::getenv("ARDOUR_CONFIG_PATH");
		if (s.empty()) {
			std::cerr << _("ARDOUR_CONFIG_PATH not set in environment\n");
		} else {
			search_path += Searchpath (s);
		}
	}

	return search_path;
}

Searchpath
ardour_data_search_path ()
{
	static Searchpath search_path;

	if (search_path.empty()) {
		search_path += user_config_directory();
#ifdef PLATFORM_WINDOWS
		search_path += windows_search_path ();
#endif
		std::string s = Glib::getenv("ARDOUR_DATA_PATH");
		if (s.empty()) {
			std::cerr << _("ARDOUR_DATA_PATH not set in environment\n");
		} else {
			search_path += Searchpath (s);
		}
	}

	return search_path;
}

string
been_here_before_path (int version)
{
	if (version < 0) {
		version = atoi (PROGRAM_VERSION);
	}

	return Glib::build_filename (user_config_directory (version), string (".a") + to_string (version));
}


} // namespace ARDOUR