summaryrefslogtreecommitdiff
path: root/libs/pbd/pbd/filesystem.h
blob: e8073adf0ed7ae59be8e6d2e317ab6648dc7b38d (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
/*
	Copyright (C) 2007 Tim Mayberry 

	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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

/**
 * @namespace PBD::sys
 *
 * The API in this file is intended to be as close as possible to the
 * boost::filesystem API but implementing only the subset of it that is required
 * by ardour using the glib/glibmm file utility functions in the implementation.
 *
 * More information about boost::filesystem and the TR2 proposal at
 *
 * http://www.boost.org/libs/filesystem/doc/tr2_proposal.html
 *
 * Hopefully the boost::filesystem API will pass TR2 review etc and become part
 * of the C++ standard and this code can be removed, or we just end up using
 * the boost filesystem library when it matures a bit more.
 * 
 * My reasons for writing this thin wrapper instead of using glib directly or
 * using boost::filesystem immediately are:
 *
 *  - Using sys::path instead of strings and Glib::build_filename is more
 *    convenient, terse and forces correct platform agnostic path building.
 *
 *  - Using boost::filesystem on windows would mean converting between any UTF-8
 *    encoded strings(such as when selecting a file/directory in the gtk file
 *    chooser) and the native file encoding (UTF-16). It would take some time
 *    and testing to find out when this is required and the glib functions already
 *    do this if necessary.
 *
 *  - Using exceptions to indicate errors is more likely to uncover situations 
 *    where error conditions are being silently ignored(I've already encounted
 *    a few examples of this in the ardour code).
 *
 *  - Many of the glib file utility functions are not wrapped by glibmm so this
 *    also provides what I think is a better API.
 *
 *  - Using boost::filesystem directly means another library dependence and would
 *    require more testing on windows because of the character encoding issue.
 *  
 *  - The boost::filesystem API changes a bit as part of the TR2 review process etc.
 */

#ifndef __filesystem_h__
#define __filesystem_h__

#include <stdexcept>
#include <string>

namespace PBD {

namespace sys {

class path
{
public:
	path() : m_path("") { }
	path(const path & p) : m_path(p.m_path) { }
	path(const std::string & s) : m_path(s) { }
	path(const char* s) : m_path(s) { }
	
	path& operator=(const path& p) { m_path = p.m_path; return *this;}
	path& operator=(const std::string& s) { m_path = s; return *this; }
	path& operator=(const char* s) { m_path = s; return *this; }

	path& operator/=(const path& rhs);
	path& operator/=(const std::string& s);
	path& operator/=(const char* s);

	const std::string to_string() const { return m_path; }

	/**
	 * @return the last component of the path, if the path refers to
	 * a file then it will be the entire filename including any extension.
	 */
	std::string leaf () const; 

	/**
	 * @returns the directory component of a path without any trailing
	 * path separator or an empty string if the path has no directory
	 * component(branch path).
	 */
	path branch_path () const;

private:

	std::string m_path;
};

class filesystem_error : public std::runtime_error
{
	const int m_error_code;

public:
	explicit filesystem_error(const std::string & what, int error_code=0)
		: std::runtime_error(what), m_error_code(error_code) { }

	int system_error() const { return m_error_code; }
};

inline path operator/ (const path& lhs, const path& rhs)
{ return path(lhs) /= rhs; }

/// @return true if path at p exists
bool exists(const path & p);


/// @return true if path at p exists and is writable, false otherwise
bool exists_and_writable(const path & p);

/// @return true if path at p is a directory.
bool is_directory(const path & p);

/**
 * Attempt to create a directory at p as if by the glib function g_mkdir 
 * with a second argument of S_IRWXU|S_IRWXG|S_IRWXO
 * 
 * @throw filesystem_error if mkdir fails for any other reason other than
 * the directory already exists.
 *
 * @return true If the directory p was created, otherwise false
 *
 * @post is_directory(p)
 */
bool create_directory(const path & p);

/**
 * Attempt to create a directory at p as if by the glib function 
 * g_mkdir_with_parents with a second argument of S_IRWXU|S_IRWXG|S_IRWXO
 * 
 * @throw filesystem_error if g_mkdir_with_parents fails for any other 
 * reason other than the directory already exists.
 *
 * @return true If the directory at p was created, otherwise false
 *
 * @post is_directory(p)
 */
bool create_directories(const path & p);

/**
 * Attempt to delete the file at path p as if by the glib function
 * g_unlink.
 *
 * @return true if file existed prior to removing it, false if file
 * at p did not exist.
 *
 * @throw filesystem_error if removing the file failed for any other
 * reason other than the file did not exist.
 */
bool remove(const path & p);

/**
 * Renames from_path to to_path as if by the glib function g_rename.
 */
void rename (const path& from_path, const path& to_path);

/**
 * Attempt to copy the contents of the file from_path to a new file 
 * at path to_path.
 *
 * @throw filesystem_error if from_path.empty() || to_path.empty() ||
 * !exists(from_path) || !is_regular(from_path) || exists(to_path)
 */
void copy_file(const path & from_path, const path & to_path);

/**
 * Attempt to copy all regular files from from_path to a new directory.
 * This method does not recurse.
 */
void copy_files(const path & from_path, const path & to_dir);

/**
 * @return The substring of the filename component of the path, starting
 * at the beginning of the filename up to but not including the last dot.
 *
 * boost::filesystem::path::basename differs from g_path_get_basename and
 * ::basename and most other forms of basename in that it removes the
 * extension from the filename if the filename has one.
 */ 
std::string basename (const path& p);

/**
 * @return If the filename contains a dot, return a substring of the
 * filename starting the rightmost dot to the end of the string, otherwise
 * an empty string.
 *
 * @param p a file path.
 */
std::string extension (const path& p);

path get_absolute_path (const path &);

} // namespace sys

} // namespace PBD

#endif