|
1 // boost/filesystem/convenience.hpp ----------------------------------------// |
|
2 |
|
3 // Copyright Beman Dawes, 2002-2005 |
|
4 // Copyright Vladimir Prus, 2002 |
|
5 // Use, modification, and distribution is subject to the Boost Software |
|
6 // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at |
|
7 // http://www.boost.org/LICENSE_1_0.txt) |
|
8 |
|
9 // See library home page at http://www.boost.org/libs/filesystem |
|
10 |
|
11 //----------------------------------------------------------------------------// |
|
12 |
|
13 #ifndef BOOST_FILESYSTEM_CONVENIENCE_HPP |
|
14 #define BOOST_FILESYSTEM_CONVENIENCE_HPP |
|
15 |
|
16 #include <boost/filesystem/operations.hpp> |
|
17 #include <boost/system/error_code.hpp> |
|
18 #include <vector> |
|
19 #include <stack> |
|
20 |
|
21 #include <boost/config/abi_prefix.hpp> // must be the last #include |
|
22 |
|
23 # ifndef BOOST_FILESYSTEM_NARROW_ONLY |
|
24 # define BOOST_FS_FUNC(BOOST_FS_TYPE) \ |
|
25 template<class Path> typename boost::enable_if<is_basic_path<Path>, \ |
|
26 BOOST_FS_TYPE>::type |
|
27 # define BOOST_FS_FUNC_STRING BOOST_FS_FUNC(typename Path::string_type) |
|
28 # define BOOST_FS_TYPENAME typename |
|
29 # else |
|
30 # define BOOST_FS_FUNC(BOOST_FS_TYPE) inline BOOST_FS_TYPE |
|
31 typedef boost::filesystem::path Path; |
|
32 # define BOOST_FS_FUNC_STRING inline std::string |
|
33 # define BOOST_FS_TYPENAME |
|
34 # endif |
|
35 |
|
36 namespace boost |
|
37 { |
|
38 namespace filesystem |
|
39 { |
|
40 |
|
41 BOOST_FS_FUNC(bool) create_directories(const Path& ph) |
|
42 { |
|
43 if (ph.empty() || exists(ph)) |
|
44 { |
|
45 if ( !ph.empty() && !is_directory(ph) ) |
|
46 boost::throw_exception( basic_filesystem_error<Path>( |
|
47 "boost::filesystem::create_directories", ph, |
|
48 make_error_code( boost::system::posix::file_exists ) ) ); |
|
49 return false; |
|
50 } |
|
51 |
|
52 // First create branch, by calling ourself recursively |
|
53 create_directories(ph.parent_path()); |
|
54 // Now that parent's path exists, create the directory |
|
55 create_directory(ph); |
|
56 return true; |
|
57 } |
|
58 |
|
59 # ifndef BOOST_FILESYSTEM_NO_DEPRECATED |
|
60 |
|
61 BOOST_FS_FUNC_STRING extension(const Path& ph) |
|
62 { |
|
63 typedef BOOST_FS_TYPENAME Path::string_type string_type; |
|
64 string_type filename = ph.filename(); |
|
65 |
|
66 BOOST_FS_TYPENAME string_type::size_type n = filename.rfind('.'); |
|
67 if (n != string_type::npos) |
|
68 return filename.substr(n); |
|
69 else |
|
70 return string_type(); |
|
71 } |
|
72 |
|
73 BOOST_FS_FUNC_STRING basename(const Path& ph) |
|
74 { |
|
75 typedef BOOST_FS_TYPENAME Path::string_type string_type; |
|
76 string_type filename = ph.filename(); |
|
77 BOOST_FS_TYPENAME string_type::size_type n = filename.rfind('.'); |
|
78 return filename.substr(0, n); |
|
79 } |
|
80 |
|
81 |
|
82 BOOST_FS_FUNC(Path) change_extension( const Path & ph, |
|
83 const BOOST_FS_TYPENAME Path::string_type & new_extension ) |
|
84 { return ph.parent_path() / (basename(ph) + new_extension); } |
|
85 |
|
86 # endif |
|
87 |
|
88 # ifndef BOOST_FILESYSTEM_NARROW_ONLY |
|
89 |
|
90 // "do-the-right-thing" overloads ---------------------------------------// |
|
91 |
|
92 inline bool create_directories(const path& ph) |
|
93 { return create_directories<path>(ph); } |
|
94 inline bool create_directories(const wpath& ph) |
|
95 { return create_directories<wpath>(ph); } |
|
96 |
|
97 # ifndef BOOST_FILESYSTEM_NO_DEPRECATED |
|
98 inline std::string extension(const path& ph) |
|
99 { return extension<path>(ph); } |
|
100 inline std::wstring extension(const wpath& ph) |
|
101 { return extension<wpath>(ph); } |
|
102 |
|
103 inline std::string basename(const path& ph) |
|
104 { return basename<path>( ph ); } |
|
105 inline std::wstring basename(const wpath& ph) |
|
106 { return basename<wpath>( ph ); } |
|
107 |
|
108 inline path change_extension( const path & ph, const std::string& new_ex ) |
|
109 { return change_extension<path>( ph, new_ex ); } |
|
110 inline wpath change_extension( const wpath & ph, const std::wstring& new_ex ) |
|
111 { return change_extension<wpath>( ph, new_ex ); } |
|
112 # endif |
|
113 |
|
114 # endif |
|
115 |
|
116 |
|
117 // basic_recursive_directory_iterator helpers --------------------------// |
|
118 |
|
119 namespace detail |
|
120 { |
|
121 template< class Path > |
|
122 struct recur_dir_itr_imp |
|
123 { |
|
124 typedef basic_directory_iterator< Path > element_type; |
|
125 std::stack< element_type, std::vector< element_type > > m_stack; |
|
126 int m_level; |
|
127 bool m_no_push; |
|
128 bool m_no_throw; |
|
129 |
|
130 recur_dir_itr_imp() : m_level(0), m_no_push(false), m_no_throw(false) {} |
|
131 }; |
|
132 |
|
133 } // namespace detail |
|
134 |
|
135 // basic_recursive_directory_iterator ----------------------------------// |
|
136 |
|
137 template< class Path > |
|
138 class basic_recursive_directory_iterator |
|
139 : public boost::iterator_facade< |
|
140 basic_recursive_directory_iterator<Path>, |
|
141 basic_directory_entry<Path>, |
|
142 boost::single_pass_traversal_tag > |
|
143 { |
|
144 public: |
|
145 typedef Path path_type; |
|
146 |
|
147 basic_recursive_directory_iterator(){} // creates the "end" iterator |
|
148 |
|
149 explicit basic_recursive_directory_iterator( const Path & dir_path ); |
|
150 basic_recursive_directory_iterator( const Path & dir_path, |
|
151 system::error_code & ec ); |
|
152 |
|
153 int level() const { return m_imp->m_level; } |
|
154 |
|
155 void pop(); |
|
156 void no_push() |
|
157 { |
|
158 BOOST_ASSERT( m_imp.get() && "attempt to no_push() on end iterator" ); |
|
159 m_imp->m_no_push = true; |
|
160 } |
|
161 |
|
162 file_status status() const |
|
163 { |
|
164 BOOST_ASSERT( m_imp.get() |
|
165 && "attempt to call status() on end recursive_iterator" ); |
|
166 return m_imp->m_stack.top()->status(); |
|
167 } |
|
168 |
|
169 file_status symlink_status() const |
|
170 { |
|
171 BOOST_ASSERT( m_imp.get() |
|
172 && "attempt to call symlink_status() on end recursive_iterator" ); |
|
173 return m_imp->m_stack.top()->symlink_status(); |
|
174 } |
|
175 |
|
176 private: |
|
177 |
|
178 // shared_ptr provides shallow-copy semantics required for InputIterators. |
|
179 // m_imp.get()==0 indicates the end iterator. |
|
180 boost::shared_ptr< detail::recur_dir_itr_imp< Path > > m_imp; |
|
181 |
|
182 friend class boost::iterator_core_access; |
|
183 |
|
184 typename boost::iterator_facade< |
|
185 basic_recursive_directory_iterator<Path>, |
|
186 basic_directory_entry<Path>, |
|
187 boost::single_pass_traversal_tag >::reference |
|
188 dereference() const |
|
189 { |
|
190 BOOST_ASSERT( m_imp.get() && "attempt to dereference end iterator" ); |
|
191 return *m_imp->m_stack.top(); |
|
192 } |
|
193 |
|
194 void increment(); |
|
195 |
|
196 bool equal( const basic_recursive_directory_iterator & rhs ) const |
|
197 { return m_imp == rhs.m_imp; } |
|
198 |
|
199 }; |
|
200 |
|
201 typedef basic_recursive_directory_iterator<path> recursive_directory_iterator; |
|
202 # ifndef BOOST_FILESYSTEM_NARROW_ONLY |
|
203 typedef basic_recursive_directory_iterator<wpath> wrecursive_directory_iterator; |
|
204 # endif |
|
205 |
|
206 // basic_recursive_directory_iterator implementation -------------------// |
|
207 |
|
208 // constructors |
|
209 template<class Path> |
|
210 basic_recursive_directory_iterator<Path>:: |
|
211 basic_recursive_directory_iterator( const Path & dir_path ) |
|
212 : m_imp( new detail::recur_dir_itr_imp<Path> ) |
|
213 { |
|
214 m_imp->m_stack.push( basic_directory_iterator<Path>( dir_path ) ); |
|
215 if ( m_imp->m_stack.top () == basic_directory_iterator<Path>() ) |
|
216 { m_imp.reset (); } |
|
217 } |
|
218 |
|
219 template<class Path> |
|
220 basic_recursive_directory_iterator<Path>:: |
|
221 basic_recursive_directory_iterator( const Path & dir_path, |
|
222 system::error_code & ec ) |
|
223 : m_imp( new detail::recur_dir_itr_imp<Path> ) |
|
224 { |
|
225 m_imp->m_no_throw = true; |
|
226 m_imp->m_stack.push( basic_directory_iterator<Path>( dir_path, ec ) ); |
|
227 if ( m_imp->m_stack.top () == basic_directory_iterator<Path>() ) |
|
228 { m_imp.reset (); } |
|
229 } |
|
230 |
|
231 // increment |
|
232 template<class Path> |
|
233 void basic_recursive_directory_iterator<Path>::increment() |
|
234 { |
|
235 BOOST_ASSERT( m_imp.get() && "increment on end iterator" ); |
|
236 |
|
237 static const basic_directory_iterator<Path> end_itr; |
|
238 |
|
239 if ( m_imp->m_no_push ) |
|
240 { m_imp->m_no_push = false; } |
|
241 else if ( is_directory( m_imp->m_stack.top()->status() ) ) |
|
242 { |
|
243 system::error_code ec; |
|
244 #if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x610)) |
|
245 if( m_imp->m_no_throw ) { |
|
246 m_imp->m_stack.push( |
|
247 basic_directory_iterator<Path>( *m_imp->m_stack.top(), ec ) |
|
248 ); |
|
249 } |
|
250 else { |
|
251 m_imp->m_stack.push( |
|
252 basic_directory_iterator<Path>( *m_imp->m_stack.top() ) |
|
253 ); |
|
254 } |
|
255 #else |
|
256 m_imp->m_stack.push( |
|
257 m_imp->m_no_throw |
|
258 ? basic_directory_iterator<Path>( *m_imp->m_stack.top(), ec ) |
|
259 : basic_directory_iterator<Path>( *m_imp->m_stack.top() ) ); |
|
260 #endif |
|
261 if ( m_imp->m_stack.top() != end_itr ) |
|
262 { |
|
263 ++m_imp->m_level; |
|
264 return; |
|
265 } |
|
266 m_imp->m_stack.pop(); |
|
267 } |
|
268 |
|
269 while ( !m_imp->m_stack.empty() |
|
270 && ++m_imp->m_stack.top() == end_itr ) |
|
271 { |
|
272 m_imp->m_stack.pop(); |
|
273 --m_imp->m_level; |
|
274 } |
|
275 |
|
276 if ( m_imp->m_stack.empty() ) m_imp.reset(); // done, so make end iterator |
|
277 } |
|
278 |
|
279 // pop |
|
280 template<class Path> |
|
281 void basic_recursive_directory_iterator<Path>::pop() |
|
282 { |
|
283 BOOST_ASSERT( m_imp.get() && "pop on end iterator" ); |
|
284 BOOST_ASSERT( m_imp->m_level > 0 && "pop with level < 1" ); |
|
285 |
|
286 static const basic_directory_iterator<Path> end_itr; |
|
287 |
|
288 do |
|
289 { |
|
290 m_imp->m_stack.pop(); |
|
291 --m_imp->m_level; |
|
292 } |
|
293 while ( !m_imp->m_stack.empty() |
|
294 && ++m_imp->m_stack.top() == end_itr ); |
|
295 |
|
296 if ( m_imp->m_stack.empty() ) m_imp.reset(); // done, so make end iterator |
|
297 } |
|
298 |
|
299 } // namespace filesystem |
|
300 } // namespace boost |
|
301 |
|
302 #undef BOOST_FS_FUNC_STRING |
|
303 #undef BOOST_FS_FUNC |
|
304 |
|
305 #include <boost/config/abi_suffix.hpp> // pops abi_prefix.hpp pragmas |
|
306 #endif // BOOST_FILESYSTEM_CONVENIENCE_HPP |