Save templates as directories with plugin state, if
[ardour.git] / libs / pbd / pbd / filesystem.h
1 /*
2         Copyright (C) 2007 Tim Mayberry 
3
4         This program is free software; you can redistribute it and/or modify
5         it under the terms of the GNU General Public License as published by
6         the Free Software Foundation; either version 2 of the License, or
7         (at your option) any later version.
8
9         This program is distributed in the hope that it will be useful,
10         but WITHOUT ANY WARRANTY; without even the implied warranty of
11         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12         GNU General Public License for more details.
13
14         You should have received a copy of the GNU General Public License
15         along with this program; if not, write to the Free Software
16         Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18
19 /**
20  * @namespace PBD::sys
21  *
22  * The API in this file is intended to be as close as possible to the
23  * boost::filesystem API but implementing only the subset of it that is required
24  * by ardour using the glib/glibmm file utility functions in the implementation.
25  *
26  * More information about boost::filesystem and the TR2 proposal at
27  *
28  * http://www.boost.org/libs/filesystem/doc/tr2_proposal.html
29  *
30  * Hopefully the boost::filesystem API will pass TR2 review etc and become part
31  * of the C++ standard and this code can be removed, or we just end up using
32  * the boost filesystem library when it matures a bit more.
33  * 
34  * My reasons for writing this thin wrapper instead of using glib directly or
35  * using boost::filesystem immediately are:
36  *
37  *  - Using sys::path instead of strings and Glib::build_filename is more
38  *    convenient, terse and forces correct platform agnostic path building.
39  *
40  *  - Using boost::filesystem on windows would mean converting between any UTF-8
41  *    encoded strings(such as when selecting a file/directory in the gtk file
42  *    chooser) and the native file encoding (UTF-16). It would take some time
43  *    and testing to find out when this is required and the glib functions already
44  *    do this if necessary.
45  *
46  *  - Using exceptions to indicate errors is more likely to uncover situations 
47  *    where error conditions are being silently ignored(I've already encounted
48  *    a few examples of this in the ardour code).
49  *
50  *  - Many of the glib file utility functions are not wrapped by glibmm so this
51  *    also provides what I think is a better API.
52  *
53  *  - Using boost::filesystem directly means another library dependence and would
54  *    require more testing on windows because of the character encoding issue.
55  *  
56  *  - The boost::filesystem API changes a bit as part of the TR2 review process etc.
57  */
58
59 #ifndef __filesystem_h__
60 #define __filesystem_h__
61
62 #include <stdexcept>
63 #include <string>
64
65 namespace PBD {
66
67 namespace sys {
68
69 class path
70 {
71 public:
72         path() : m_path("") { }
73         path(const path & p) : m_path(p.m_path) { }
74         path(const std::string & s) : m_path(s) { }
75         path(const char* s) : m_path(s) { }
76         
77         path& operator=(const path& p) { m_path = p.m_path; return *this;}
78         path& operator=(const std::string& s) { m_path = s; return *this; }
79         path& operator=(const char* s) { m_path = s; return *this; }
80
81         path& operator/=(const path& rhs);
82         path& operator/=(const std::string& s);
83         path& operator/=(const char* s);
84
85         const std::string to_string() const { return m_path; }
86
87         /**
88          * @return the last component of the path, if the path refers to
89          * a file then it will be the entire filename including any extension.
90          */
91         std::string leaf () const; 
92
93         /**
94          * @returns the directory component of a path without any trailing
95          * path separator or an empty string if the path has no directory
96          * component(branch path).
97          */
98         path branch_path () const;
99
100 private:
101
102         std::string m_path;
103 };
104
105 class filesystem_error : public std::runtime_error
106 {
107         const int m_error_code;
108
109 public:
110         explicit filesystem_error(const std::string & what, int error_code=0)
111                 : std::runtime_error(what), m_error_code(error_code) { }
112
113         int system_error() const { return m_error_code; }
114 };
115
116 inline path operator/ (const path& lhs, const path& rhs)
117 { return path(lhs) /= rhs; }
118
119 /// @return true if path at p exists
120 bool exists(const path & p);
121
122
123 /// @return true if path at p exists and is writable, false otherwise
124 bool exists_and_writable(const path & p);
125
126 /// @return true if path at p is a directory.
127 bool is_directory(const path & p);
128
129 /**
130  * Attempt to create a directory at p as if by the glib function g_mkdir 
131  * with a second argument of S_IRWXU|S_IRWXG|S_IRWXO
132  * 
133  * @throw filesystem_error if mkdir fails for any other reason other than
134  * the directory already exists.
135  *
136  * @return true If the directory p was created, otherwise false
137  *
138  * @post is_directory(p)
139  */
140 bool create_directory(const path & p);
141
142 /**
143  * Attempt to create a directory at p as if by the glib function 
144  * g_mkdir_with_parents with a second argument of S_IRWXU|S_IRWXG|S_IRWXO
145  * 
146  * @throw filesystem_error if g_mkdir_with_parents fails for any other 
147  * reason other than the directory already exists.
148  *
149  * @return true If the directory at p was created, otherwise false
150  *
151  * @post is_directory(p)
152  */
153 bool create_directories(const path & p);
154
155 /**
156  * Attempt to delete the file at path p as if by the glib function
157  * g_unlink.
158  *
159  * @return true if file existed prior to removing it, false if file
160  * at p did not exist.
161  *
162  * @throw filesystem_error if removing the file failed for any other
163  * reason other than the file did not exist.
164  */
165 bool remove(const path & p);
166
167 /**
168  * Renames from_path to to_path as if by the glib function g_rename.
169  */
170 void rename (const path& from_path, const path& to_path);
171
172 /**
173  * Attempt to copy the contents of the file from_path to a new file 
174  * at path to_path.
175  *
176  * @throw filesystem_error if from_path.empty() || to_path.empty() ||
177  * !exists(from_path) || !is_regular(from_path) || exists(to_path)
178  */
179 void copy_file(const path & from_path, const path & to_path);
180
181 /**
182  * Attempt to copy all regular files from from_path to a new directory.
183  * This method does not recurse.
184  */
185 void copy_files(const path & from_path, const path & to_dir);
186
187 /**
188  * @return The substring of the filename component of the path, starting
189  * at the beginning of the filename up to but not including the last dot.
190  *
191  * boost::filesystem::path::basename differs from g_path_get_basename and
192  * ::basename and most other forms of basename in that it removes the
193  * extension from the filename if the filename has one.
194  */ 
195 std::string basename (const path& p);
196
197 /**
198  * @return If the filename contains a dot, return a substring of the
199  * filename starting the rightmost dot to the end of the string, otherwise
200  * an empty string.
201  *
202  * @param p a file path.
203  */
204 std::string extension (const path& p);
205
206 path get_absolute_path (const path &);
207
208 } // namespace sys
209
210 } // namespace PBD
211
212 #endif