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