path.hpp 38 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016
  1. // filesystem path.hpp ---------------------------------------------------------------//
  2. // Copyright Beman Dawes 2002-2005, 2009
  3. // Copyright Vladimir Prus 2002
  4. // Distributed under the Boost Software License, Version 1.0.
  5. // See http://www.boost.org/LICENSE_1_0.txt
  6. // Library home page: http://www.boost.org/libs/filesystem
  7. // path::stem(), extension(), and replace_extension() are based on
  8. // basename(), extension(), and change_extension() from the original
  9. // filesystem/convenience.hpp header by Vladimir Prus.
  10. #ifndef BOOST_FILESYSTEM_PATH_HPP
  11. #define BOOST_FILESYSTEM_PATH_HPP
  12. #include <boost/config.hpp>
  13. # if defined( BOOST_NO_STD_WSTRING )
  14. # error Configuration not supported: Boost.Filesystem V3 and later requires std::wstring support
  15. # endif
  16. #include <boost/filesystem/config.hpp>
  17. #include <boost/filesystem/path_traits.hpp> // includes <cwchar>
  18. #include <boost/system/error_code.hpp>
  19. #include <boost/system/system_error.hpp>
  20. #include <boost/iterator/iterator_facade.hpp>
  21. #include <boost/shared_ptr.hpp>
  22. #include <boost/io/detail/quoted_manip.hpp>
  23. #include <boost/static_assert.hpp>
  24. #include <boost/functional/hash_fwd.hpp>
  25. #include <boost/type_traits/is_integral.hpp>
  26. #include <string>
  27. #include <iterator>
  28. #include <cstring>
  29. #include <iosfwd>
  30. #include <stdexcept>
  31. #include <cassert>
  32. #include <locale>
  33. #include <algorithm>
  34. #include <boost/config/abi_prefix.hpp> // must be the last #include
  35. namespace boost
  36. {
  37. namespace filesystem
  38. {
  39. //------------------------------------------------------------------------------------//
  40. // //
  41. // class path //
  42. // //
  43. //------------------------------------------------------------------------------------//
  44. class BOOST_FILESYSTEM_DECL path
  45. {
  46. public:
  47. // value_type is the character type used by the operating system API to
  48. // represent paths.
  49. # ifdef BOOST_WINDOWS_API
  50. typedef wchar_t value_type;
  51. BOOST_STATIC_CONSTEXPR value_type separator = L'/';
  52. BOOST_STATIC_CONSTEXPR value_type preferred_separator = L'\\';
  53. BOOST_STATIC_CONSTEXPR value_type dot = L'.';
  54. # else
  55. typedef char value_type;
  56. BOOST_STATIC_CONSTEXPR value_type separator = '/';
  57. BOOST_STATIC_CONSTEXPR value_type preferred_separator = '/';
  58. BOOST_STATIC_CONSTEXPR value_type dot = '.';
  59. # endif
  60. typedef std::basic_string<value_type> string_type;
  61. typedef std::codecvt<wchar_t, char,
  62. std::mbstate_t> codecvt_type;
  63. // ----- character encoding conversions -----
  64. // Following the principle of least astonishment, path input arguments
  65. // passed to or obtained from the operating system via objects of
  66. // class path behave as if they were directly passed to or
  67. // obtained from the O/S API, unless conversion is explicitly requested.
  68. //
  69. // POSIX specfies that path strings are passed unchanged to and from the
  70. // API. Note that this is different from the POSIX command line utilities,
  71. // which convert according to a locale.
  72. //
  73. // Thus for POSIX, char strings do not undergo conversion. wchar_t strings
  74. // are converted to/from char using the path locale or, if a conversion
  75. // argument is given, using a conversion object modeled on
  76. // std::wstring_convert.
  77. //
  78. // The path locale, which is global to the thread, can be changed by the
  79. // imbue() function. It is initialized to an implementation defined locale.
  80. //
  81. // For Windows, wchar_t strings do not undergo conversion. char strings
  82. // are converted using the "ANSI" or "OEM" code pages, as determined by
  83. // the AreFileApisANSI() function, or, if a conversion argument is given,
  84. // using a conversion object modeled on std::wstring_convert.
  85. //
  86. // See m_pathname comments for further important rationale.
  87. // TODO: rules needed for operating systems that use / or .
  88. // differently, or format directory paths differently from file paths.
  89. //
  90. // **********************************************************************************
  91. //
  92. // More work needed: How to handle an operating system that may have
  93. // slash characters or dot characters in valid filenames, either because
  94. // it doesn't follow the POSIX standard, or because it allows MBCS
  95. // filename encodings that may contain slash or dot characters. For
  96. // example, ISO/IEC 2022 (JIS) encoding which allows switching to
  97. // JIS x0208-1983 encoding. A valid filename in this set of encodings is
  98. // 0x1B 0x24 0x42 [switch to X0208-1983] 0x24 0x2F [U+304F Kiragana letter KU]
  99. // ^^^^
  100. // Note that 0x2F is the ASCII slash character
  101. //
  102. // **********************************************************************************
  103. // Supported source arguments: half-open iterator range, container, c-array,
  104. // and single pointer to null terminated string.
  105. // All source arguments except pointers to null terminated byte strings support
  106. // multi-byte character strings which may have embedded nulls. Embedded null
  107. // support is required for some Asian languages on Windows.
  108. // "const codecvt_type& cvt=codecvt()" default arguments are not used because this
  109. // limits the impact of locale("") initialization failures on POSIX systems to programs
  110. // that actually depend on locale(""). It further ensures that exceptions thrown
  111. // as a result of such failues occur after main() has started, so can be caught.
  112. // ----- constructors -----
  113. path() BOOST_NOEXCEPT {}
  114. path(const path& p) : m_pathname(p.m_pathname) {}
  115. template <class Source>
  116. path(Source const& source,
  117. typename boost::enable_if<path_traits::is_pathable<
  118. typename boost::decay<Source>::type> >::type* =0)
  119. {
  120. path_traits::dispatch(source, m_pathname);
  121. }
  122. path(const value_type* s) : m_pathname(s) {}
  123. path(value_type* s) : m_pathname(s) {}
  124. path(const string_type& s) : m_pathname(s) {}
  125. path(string_type& s) : m_pathname(s) {}
  126. // As of October 2015 the interaction between noexcept and =default is so troublesome
  127. // for VC++, GCC, and probably other compilers, that =default is not used with noexcept
  128. // functions. GCC is not even consistent for the same release on different platforms.
  129. # if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
  130. path(path&& p) BOOST_NOEXCEPT { m_pathname = std::move(p.m_pathname); }
  131. path& operator=(path&& p) BOOST_NOEXCEPT
  132. { m_pathname = std::move(p.m_pathname); return *this; }
  133. # endif
  134. template <class Source>
  135. path(Source const& source, const codecvt_type& cvt)
  136. {
  137. path_traits::dispatch(source, m_pathname, cvt);
  138. }
  139. template <class InputIterator>
  140. path(InputIterator begin, InputIterator end)
  141. {
  142. if (begin != end)
  143. {
  144. // convert requires contiguous string, so copy
  145. std::basic_string<typename std::iterator_traits<InputIterator>::value_type>
  146. seq(begin, end);
  147. path_traits::convert(seq.c_str(), seq.c_str()+seq.size(), m_pathname);
  148. }
  149. }
  150. template <class InputIterator>
  151. path(InputIterator begin, InputIterator end, const codecvt_type& cvt)
  152. {
  153. if (begin != end)
  154. {
  155. // convert requires contiguous string, so copy
  156. std::basic_string<typename std::iterator_traits<InputIterator>::value_type>
  157. seq(begin, end);
  158. path_traits::convert(seq.c_str(), seq.c_str()+seq.size(), m_pathname, cvt);
  159. }
  160. }
  161. // ----- assignments -----
  162. path& operator=(const path& p)
  163. {
  164. m_pathname = p.m_pathname;
  165. return *this;
  166. }
  167. template <class Source>
  168. typename boost::enable_if<path_traits::is_pathable<
  169. typename boost::decay<Source>::type>, path&>::type
  170. operator=(Source const& source)
  171. {
  172. m_pathname.clear();
  173. path_traits::dispatch(source, m_pathname);
  174. return *this;
  175. }
  176. // value_type overloads
  177. path& operator=(const value_type* ptr) // required in case ptr overlaps *this
  178. {m_pathname = ptr; return *this;}
  179. path& operator=(value_type* ptr) // required in case ptr overlaps *this
  180. {m_pathname = ptr; return *this;}
  181. path& operator=(const string_type& s) {m_pathname = s; return *this;}
  182. path& operator=(string_type& s) {m_pathname = s; return *this;}
  183. path& assign(const value_type* ptr, const codecvt_type&) // required in case ptr overlaps *this
  184. {m_pathname = ptr; return *this;}
  185. template <class Source>
  186. path& assign(Source const& source, const codecvt_type& cvt)
  187. {
  188. m_pathname.clear();
  189. path_traits::dispatch(source, m_pathname, cvt);
  190. return *this;
  191. }
  192. template <class InputIterator>
  193. path& assign(InputIterator begin, InputIterator end)
  194. {
  195. m_pathname.clear();
  196. if (begin != end)
  197. {
  198. std::basic_string<typename std::iterator_traits<InputIterator>::value_type>
  199. seq(begin, end);
  200. path_traits::convert(seq.c_str(), seq.c_str()+seq.size(), m_pathname);
  201. }
  202. return *this;
  203. }
  204. template <class InputIterator>
  205. path& assign(InputIterator begin, InputIterator end, const codecvt_type& cvt)
  206. {
  207. m_pathname.clear();
  208. if (begin != end)
  209. {
  210. std::basic_string<typename std::iterator_traits<InputIterator>::value_type>
  211. seq(begin, end);
  212. path_traits::convert(seq.c_str(), seq.c_str()+seq.size(), m_pathname, cvt);
  213. }
  214. return *this;
  215. }
  216. // ----- concatenation -----
  217. template <class Source>
  218. typename boost::enable_if<path_traits::is_pathable<
  219. typename boost::decay<Source>::type>, path&>::type
  220. operator+=(Source const& source)
  221. {
  222. return concat(source);
  223. }
  224. // value_type overloads. Same rationale as for constructors above
  225. path& operator+=(const path& p) { m_pathname += p.m_pathname; return *this; }
  226. path& operator+=(const value_type* ptr) { m_pathname += ptr; return *this; }
  227. path& operator+=(value_type* ptr) { m_pathname += ptr; return *this; }
  228. path& operator+=(const string_type& s) { m_pathname += s; return *this; }
  229. path& operator+=(string_type& s) { m_pathname += s; return *this; }
  230. path& operator+=(value_type c) { m_pathname += c; return *this; }
  231. template <class CharT>
  232. typename boost::enable_if<is_integral<CharT>, path&>::type
  233. operator+=(CharT c)
  234. {
  235. CharT tmp[2];
  236. tmp[0] = c;
  237. tmp[1] = 0;
  238. return concat(tmp);
  239. }
  240. template <class Source>
  241. path& concat(Source const& source)
  242. {
  243. path_traits::dispatch(source, m_pathname);
  244. return *this;
  245. }
  246. template <class Source>
  247. path& concat(Source const& source, const codecvt_type& cvt)
  248. {
  249. path_traits::dispatch(source, m_pathname, cvt);
  250. return *this;
  251. }
  252. template <class InputIterator>
  253. path& concat(InputIterator begin, InputIterator end)
  254. {
  255. if (begin == end)
  256. return *this;
  257. std::basic_string<typename std::iterator_traits<InputIterator>::value_type>
  258. seq(begin, end);
  259. path_traits::convert(seq.c_str(), seq.c_str()+seq.size(), m_pathname);
  260. return *this;
  261. }
  262. template <class InputIterator>
  263. path& concat(InputIterator begin, InputIterator end, const codecvt_type& cvt)
  264. {
  265. if (begin == end)
  266. return *this;
  267. std::basic_string<typename std::iterator_traits<InputIterator>::value_type>
  268. seq(begin, end);
  269. path_traits::convert(seq.c_str(), seq.c_str()+seq.size(), m_pathname, cvt);
  270. return *this;
  271. }
  272. // ----- appends -----
  273. // if a separator is added, it is the preferred separator for the platform;
  274. // slash for POSIX, backslash for Windows
  275. path& operator/=(const path& p);
  276. template <class Source>
  277. typename boost::enable_if<path_traits::is_pathable<
  278. typename boost::decay<Source>::type>, path&>::type
  279. operator/=(Source const& source)
  280. {
  281. return append(source);
  282. }
  283. path& operator/=(const value_type* ptr);
  284. path& operator/=(value_type* ptr)
  285. {
  286. return this->operator/=(const_cast<const value_type*>(ptr));
  287. }
  288. path& operator/=(const string_type& s) { return this->operator/=(path(s)); }
  289. path& operator/=(string_type& s) { return this->operator/=(path(s)); }
  290. path& append(const value_type* ptr) // required in case ptr overlaps *this
  291. {
  292. this->operator/=(ptr);
  293. return *this;
  294. }
  295. path& append(const value_type* ptr, const codecvt_type&) // required in case ptr overlaps *this
  296. {
  297. this->operator/=(ptr);
  298. return *this;
  299. }
  300. template <class Source>
  301. path& append(Source const& source);
  302. template <class Source>
  303. path& append(Source const& source, const codecvt_type& cvt);
  304. template <class InputIterator>
  305. path& append(InputIterator begin, InputIterator end);
  306. template <class InputIterator>
  307. path& append(InputIterator begin, InputIterator end, const codecvt_type& cvt);
  308. // ----- modifiers -----
  309. void clear() BOOST_NOEXCEPT { m_pathname.clear(); }
  310. path& make_preferred()
  311. # ifdef BOOST_POSIX_API
  312. { return *this; } // POSIX no effect
  313. # else // BOOST_WINDOWS_API
  314. ; // change slashes to backslashes
  315. # endif
  316. path& remove_filename();
  317. path& remove_trailing_separator();
  318. path& replace_extension(const path& new_extension = path());
  319. void swap(path& rhs) BOOST_NOEXCEPT { m_pathname.swap(rhs.m_pathname); }
  320. // ----- observers -----
  321. // For operating systems that format file paths differently than directory
  322. // paths, return values from observers are formatted as file names unless there
  323. // is a trailing separator, in which case returns are formatted as directory
  324. // paths. POSIX and Windows make no such distinction.
  325. // Implementations are permitted to return const values or const references.
  326. // The string or path returned by an observer are specified as being formatted
  327. // as "native" or "generic".
  328. //
  329. // For POSIX, these are all the same format; slashes and backslashes are as input and
  330. // are not modified.
  331. //
  332. // For Windows, native: as input; slashes and backslashes are not modified;
  333. // this is the format of the internally stored string.
  334. // generic: backslashes are converted to slashes
  335. // ----- native format observers -----
  336. const string_type& native() const BOOST_NOEXCEPT { return m_pathname; }
  337. const value_type* c_str() const BOOST_NOEXCEPT { return m_pathname.c_str(); }
  338. string_type::size_type size() const BOOST_NOEXCEPT { return m_pathname.size(); }
  339. template <class String>
  340. String string() const;
  341. template <class String>
  342. String string(const codecvt_type& cvt) const;
  343. # ifdef BOOST_WINDOWS_API
  344. const std::string string() const
  345. {
  346. std::string tmp;
  347. if (!m_pathname.empty())
  348. path_traits::convert(&*m_pathname.begin(), &*m_pathname.begin()+m_pathname.size(),
  349. tmp);
  350. return tmp;
  351. }
  352. const std::string string(const codecvt_type& cvt) const
  353. {
  354. std::string tmp;
  355. if (!m_pathname.empty())
  356. path_traits::convert(&*m_pathname.begin(), &*m_pathname.begin()+m_pathname.size(),
  357. tmp, cvt);
  358. return tmp;
  359. }
  360. // string_type is std::wstring, so there is no conversion
  361. const std::wstring& wstring() const { return m_pathname; }
  362. const std::wstring& wstring(const codecvt_type&) const { return m_pathname; }
  363. # else // BOOST_POSIX_API
  364. // string_type is std::string, so there is no conversion
  365. const std::string& string() const { return m_pathname; }
  366. const std::string& string(const codecvt_type&) const { return m_pathname; }
  367. const std::wstring wstring() const
  368. {
  369. std::wstring tmp;
  370. if (!m_pathname.empty())
  371. path_traits::convert(&*m_pathname.begin(), &*m_pathname.begin()+m_pathname.size(),
  372. tmp);
  373. return tmp;
  374. }
  375. const std::wstring wstring(const codecvt_type& cvt) const
  376. {
  377. std::wstring tmp;
  378. if (!m_pathname.empty())
  379. path_traits::convert(&*m_pathname.begin(), &*m_pathname.begin()+m_pathname.size(),
  380. tmp, cvt);
  381. return tmp;
  382. }
  383. # endif
  384. // ----- generic format observers -----
  385. // Experimental generic function returning generic formatted path (i.e. separators
  386. // are forward slashes). Motivation: simpler than a family of generic_*string
  387. // functions.
  388. path generic_path() const
  389. {
  390. # ifdef BOOST_WINDOWS_API
  391. path tmp;
  392. std::replace_copy(m_pathname.begin(), m_pathname.end(),
  393. std::back_inserter(tmp.m_pathname), L'\\', L'/');
  394. return tmp;
  395. # else
  396. return path(*this);
  397. # endif
  398. }
  399. template <class String>
  400. String generic_string() const;
  401. template <class String>
  402. String generic_string(const codecvt_type& cvt) const;
  403. # ifdef BOOST_WINDOWS_API
  404. const std::string generic_string() const;
  405. const std::string generic_string(const codecvt_type& cvt) const;
  406. const std::wstring generic_wstring() const;
  407. const std::wstring generic_wstring(const codecvt_type&) const { return generic_wstring(); };
  408. # else // BOOST_POSIX_API
  409. // On POSIX-like systems, the generic format is the same as the native format
  410. const std::string& generic_string() const { return m_pathname; }
  411. const std::string& generic_string(const codecvt_type&) const { return m_pathname; }
  412. const std::wstring generic_wstring() const { return wstring(); }
  413. const std::wstring generic_wstring(const codecvt_type& cvt) const { return wstring(cvt); }
  414. # endif
  415. // ----- compare -----
  416. int compare(const path& p) const BOOST_NOEXCEPT; // generic, lexicographical
  417. int compare(const std::string& s) const { return compare(path(s)); }
  418. int compare(const value_type* s) const { return compare(path(s)); }
  419. // ----- decomposition -----
  420. path root_path() const;
  421. path root_name() const; // returns 0 or 1 element path
  422. // even on POSIX, root_name() is non-empty() for network paths
  423. path root_directory() const; // returns 0 or 1 element path
  424. path relative_path() const;
  425. path parent_path() const;
  426. path filename() const; // returns 0 or 1 element path
  427. path stem() const; // returns 0 or 1 element path
  428. path extension() const; // returns 0 or 1 element path
  429. // ----- query -----
  430. bool empty() const BOOST_NOEXCEPT{ return m_pathname.empty(); }
  431. bool filename_is_dot() const;
  432. bool filename_is_dot_dot() const;
  433. bool has_root_path() const { return has_root_directory() || has_root_name(); }
  434. bool has_root_name() const { return !root_name().empty(); }
  435. bool has_root_directory() const { return !root_directory().empty(); }
  436. bool has_relative_path() const { return !relative_path().empty(); }
  437. bool has_parent_path() const { return !parent_path().empty(); }
  438. bool has_filename() const { return !m_pathname.empty(); }
  439. bool has_stem() const { return !stem().empty(); }
  440. bool has_extension() const { return !extension().empty(); }
  441. bool is_relative() const { return !is_absolute(); }
  442. bool is_absolute() const
  443. {
  444. # ifdef BOOST_WINDOWS_API
  445. return has_root_name() && has_root_directory();
  446. # else
  447. return has_root_directory();
  448. # endif
  449. }
  450. // ----- lexical operations -----
  451. path lexically_normal() const;
  452. path lexically_relative(const path& base) const;
  453. path lexically_proximate(const path& base) const
  454. {
  455. path tmp(lexically_relative(base));
  456. return tmp.empty() ? *this : tmp;
  457. }
  458. // ----- iterators -----
  459. class iterator;
  460. typedef iterator const_iterator;
  461. class reverse_iterator;
  462. typedef reverse_iterator const_reverse_iterator;
  463. iterator begin() const;
  464. iterator end() const;
  465. reverse_iterator rbegin() const;
  466. reverse_iterator rend() const;
  467. // ----- static member functions -----
  468. static std::locale imbue(const std::locale& loc);
  469. static const codecvt_type& codecvt();
  470. // ----- deprecated functions -----
  471. # if defined(BOOST_FILESYSTEM_DEPRECATED) && defined(BOOST_FILESYSTEM_NO_DEPRECATED)
  472. # error both BOOST_FILESYSTEM_DEPRECATED and BOOST_FILESYSTEM_NO_DEPRECATED are defined
  473. # endif
  474. # if !defined(BOOST_FILESYSTEM_NO_DEPRECATED)
  475. // recently deprecated functions supplied by default
  476. path& normalize() {
  477. path tmp(lexically_normal());
  478. m_pathname.swap(tmp.m_pathname);
  479. return *this;
  480. }
  481. path& remove_leaf() { return remove_filename(); }
  482. path leaf() const { return filename(); }
  483. path branch_path() const { return parent_path(); }
  484. path generic() const { return generic_path(); }
  485. bool has_leaf() const { return !m_pathname.empty(); }
  486. bool has_branch_path() const { return !parent_path().empty(); }
  487. bool is_complete() const { return is_absolute(); }
  488. # endif
  489. # if defined(BOOST_FILESYSTEM_DEPRECATED)
  490. // deprecated functions with enough signature or semantic changes that they are
  491. // not supplied by default
  492. const std::string file_string() const { return string(); }
  493. const std::string directory_string() const { return string(); }
  494. const std::string native_file_string() const { return string(); }
  495. const std::string native_directory_string() const { return string(); }
  496. const string_type external_file_string() const { return native(); }
  497. const string_type external_directory_string() const { return native(); }
  498. // older functions no longer supported
  499. //typedef bool (*name_check)(const std::string & name);
  500. //basic_path(const string_type& str, name_check) { operator/=(str); }
  501. //basic_path(const typename string_type::value_type* s, name_check)
  502. // { operator/=(s);}
  503. //static bool default_name_check_writable() { return false; }
  504. //static void default_name_check(name_check) {}
  505. //static name_check default_name_check() { return 0; }
  506. //basic_path& canonize();
  507. # endif
  508. //--------------------------------------------------------------------------------------//
  509. // class path private members //
  510. //--------------------------------------------------------------------------------------//
  511. private:
  512. # if defined(_MSC_VER)
  513. # pragma warning(push) // Save warning settings
  514. # pragma warning(disable : 4251) // disable warning: class 'std::basic_string<_Elem,_Traits,_Ax>'
  515. # endif // needs to have dll-interface...
  516. /*
  517. m_pathname has the type, encoding, and format required by the native
  518. operating system. Thus for POSIX and Windows there is no conversion for
  519. passing m_pathname.c_str() to the O/S API or when obtaining a path from the
  520. O/S API. POSIX encoding is unspecified other than for dot and slash
  521. characters; POSIX just treats paths as a sequence of bytes. Windows
  522. encoding is UCS-2 or UTF-16 depending on the version.
  523. */
  524. string_type m_pathname; // Windows: as input; backslashes NOT converted to slashes,
  525. // slashes NOT converted to backslashes
  526. # if defined(_MSC_VER)
  527. # pragma warning(pop) // restore warning settings.
  528. # endif
  529. string_type::size_type m_append_separator_if_needed();
  530. // Returns: If separator is to be appended, m_pathname.size() before append. Otherwise 0.
  531. // Note: An append is never performed if size()==0, so a returned 0 is unambiguous.
  532. void m_erase_redundant_separator(string_type::size_type sep_pos);
  533. string_type::size_type m_parent_path_end() const;
  534. path& m_normalize();
  535. // Was qualified; como433beta8 reports:
  536. // warning #427-D: qualified name is not allowed in member declaration
  537. friend class iterator;
  538. friend bool operator<(const path& lhs, const path& rhs);
  539. // see path::iterator::increment/decrement comment below
  540. static void m_path_iterator_increment(path::iterator & it);
  541. static void m_path_iterator_decrement(path::iterator & it);
  542. }; // class path
  543. namespace detail
  544. {
  545. BOOST_FILESYSTEM_DECL
  546. int lex_compare(path::iterator first1, path::iterator last1,
  547. path::iterator first2, path::iterator last2);
  548. BOOST_FILESYSTEM_DECL
  549. const path& dot_path();
  550. BOOST_FILESYSTEM_DECL
  551. const path& dot_dot_path();
  552. }
  553. # ifndef BOOST_FILESYSTEM_NO_DEPRECATED
  554. typedef path wpath;
  555. # endif
  556. //------------------------------------------------------------------------------------//
  557. // class path::iterator //
  558. //------------------------------------------------------------------------------------//
  559. class path::iterator
  560. : public boost::iterator_facade<
  561. path::iterator,
  562. path const,
  563. boost::bidirectional_traversal_tag >
  564. {
  565. private:
  566. friend class boost::iterator_core_access;
  567. friend class boost::filesystem::path;
  568. friend class boost::filesystem::path::reverse_iterator;
  569. friend void m_path_iterator_increment(path::iterator & it);
  570. friend void m_path_iterator_decrement(path::iterator & it);
  571. const path& dereference() const { return m_element; }
  572. bool equal(const iterator & rhs) const
  573. {
  574. return m_path_ptr == rhs.m_path_ptr && m_pos == rhs.m_pos;
  575. }
  576. // iterator_facade derived classes don't seem to like implementations in
  577. // separate translation unit dll's, so forward to class path static members
  578. void increment() { m_path_iterator_increment(*this); }
  579. void decrement() { m_path_iterator_decrement(*this); }
  580. path m_element; // current element
  581. const path* m_path_ptr; // path being iterated over
  582. string_type::size_type m_pos; // position of m_element in
  583. // m_path_ptr->m_pathname.
  584. // if m_element is implicit dot, m_pos is the
  585. // position of the last separator in the path.
  586. // end() iterator is indicated by
  587. // m_pos == m_path_ptr->m_pathname.size()
  588. }; // path::iterator
  589. //------------------------------------------------------------------------------------//
  590. // class path::reverse_iterator //
  591. //------------------------------------------------------------------------------------//
  592. class path::reverse_iterator
  593. : public boost::iterator_facade<
  594. path::reverse_iterator,
  595. path const,
  596. boost::bidirectional_traversal_tag >
  597. {
  598. public:
  599. explicit reverse_iterator(iterator itr) : m_itr(itr)
  600. {
  601. if (itr != itr.m_path_ptr->begin())
  602. m_element = *--itr;
  603. }
  604. private:
  605. friend class boost::iterator_core_access;
  606. friend class boost::filesystem::path;
  607. const path& dereference() const { return m_element; }
  608. bool equal(const reverse_iterator& rhs) const { return m_itr == rhs.m_itr; }
  609. void increment()
  610. {
  611. --m_itr;
  612. if (m_itr != m_itr.m_path_ptr->begin())
  613. {
  614. iterator tmp = m_itr;
  615. m_element = *--tmp;
  616. }
  617. }
  618. void decrement()
  619. {
  620. m_element = *m_itr;
  621. ++m_itr;
  622. }
  623. iterator m_itr;
  624. path m_element;
  625. }; // path::reverse_iterator
  626. //------------------------------------------------------------------------------------//
  627. // //
  628. // non-member functions //
  629. // //
  630. //------------------------------------------------------------------------------------//
  631. // std::lexicographical_compare would infinately recurse because path iterators
  632. // yield paths, so provide a path aware version
  633. inline bool lexicographical_compare(path::iterator first1, path::iterator last1,
  634. path::iterator first2, path::iterator last2)
  635. { return detail::lex_compare(first1, last1, first2, last2) < 0; }
  636. inline bool operator==(const path& lhs, const path& rhs) {return lhs.compare(rhs) == 0;}
  637. inline bool operator==(const path& lhs, const path::string_type& rhs) {return lhs.compare(rhs) == 0;}
  638. inline bool operator==(const path::string_type& lhs, const path& rhs) {return rhs.compare(lhs) == 0;}
  639. inline bool operator==(const path& lhs, const path::value_type* rhs) {return lhs.compare(rhs) == 0;}
  640. inline bool operator==(const path::value_type* lhs, const path& rhs) {return rhs.compare(lhs) == 0;}
  641. inline bool operator!=(const path& lhs, const path& rhs) {return lhs.compare(rhs) != 0;}
  642. inline bool operator!=(const path& lhs, const path::string_type& rhs) {return lhs.compare(rhs) != 0;}
  643. inline bool operator!=(const path::string_type& lhs, const path& rhs) {return rhs.compare(lhs) != 0;}
  644. inline bool operator!=(const path& lhs, const path::value_type* rhs) {return lhs.compare(rhs) != 0;}
  645. inline bool operator!=(const path::value_type* lhs, const path& rhs) {return rhs.compare(lhs) != 0;}
  646. // TODO: why do == and != have additional overloads, but the others don't?
  647. inline bool operator<(const path& lhs, const path& rhs) {return lhs.compare(rhs) < 0;}
  648. inline bool operator<=(const path& lhs, const path& rhs) {return !(rhs < lhs);}
  649. inline bool operator> (const path& lhs, const path& rhs) {return rhs < lhs;}
  650. inline bool operator>=(const path& lhs, const path& rhs) {return !(lhs < rhs);}
  651. inline std::size_t hash_value(const path& x)
  652. {
  653. # ifdef BOOST_WINDOWS_API
  654. std::size_t seed = 0;
  655. for(const path::value_type* it = x.c_str(); *it; ++it)
  656. hash_combine(seed, *it == '/' ? L'\\' : *it);
  657. return seed;
  658. # else // BOOST_POSIX_API
  659. return hash_range(x.native().begin(), x.native().end());
  660. # endif
  661. }
  662. inline void swap(path& lhs, path& rhs) { lhs.swap(rhs); }
  663. inline path operator/(const path& lhs, const path& rhs) { return path(lhs) /= rhs; }
  664. // inserters and extractors
  665. // use boost::io::quoted() to handle spaces in paths
  666. // use '&' as escape character to ease use for Windows paths
  667. template <class Char, class Traits>
  668. inline std::basic_ostream<Char, Traits>&
  669. operator<<(std::basic_ostream<Char, Traits>& os, const path& p)
  670. {
  671. return os
  672. << boost::io::quoted(p.template string<std::basic_string<Char> >(), static_cast<Char>('&'));
  673. }
  674. template <class Char, class Traits>
  675. inline std::basic_istream<Char, Traits>&
  676. operator>>(std::basic_istream<Char, Traits>& is, path& p)
  677. {
  678. std::basic_string<Char> str;
  679. is >> boost::io::quoted(str, static_cast<Char>('&'));
  680. p = str;
  681. return is;
  682. }
  683. // name_checks
  684. // These functions are holdovers from version 1. It isn't clear they have much
  685. // usefulness, or how to generalize them for later versions.
  686. BOOST_FILESYSTEM_DECL bool portable_posix_name(const std::string & name);
  687. BOOST_FILESYSTEM_DECL bool windows_name(const std::string & name);
  688. BOOST_FILESYSTEM_DECL bool portable_name(const std::string & name);
  689. BOOST_FILESYSTEM_DECL bool portable_directory_name(const std::string & name);
  690. BOOST_FILESYSTEM_DECL bool portable_file_name(const std::string & name);
  691. BOOST_FILESYSTEM_DECL bool native(const std::string & name);
  692. namespace detail
  693. {
  694. // For POSIX, is_directory_separator() and is_element_separator() are identical since
  695. // a forward slash is the only valid directory separator and also the only valid
  696. // element separator. For Windows, forward slash and back slash are the possible
  697. // directory separators, but colon (example: "c:foo") is also an element separator.
  698. inline bool is_directory_separator(path::value_type c) BOOST_NOEXCEPT
  699. {
  700. return c == path::separator
  701. # ifdef BOOST_WINDOWS_API
  702. || c == path::preferred_separator
  703. # endif
  704. ;
  705. }
  706. inline bool is_element_separator(path::value_type c) BOOST_NOEXCEPT
  707. {
  708. return c == path::separator
  709. # ifdef BOOST_WINDOWS_API
  710. || c == path::preferred_separator || c == L':'
  711. # endif
  712. ;
  713. }
  714. } // namespace detail
  715. //------------------------------------------------------------------------------------//
  716. // class path miscellaneous function implementations //
  717. //------------------------------------------------------------------------------------//
  718. inline path::reverse_iterator path::rbegin() const { return reverse_iterator(end()); }
  719. inline path::reverse_iterator path::rend() const { return reverse_iterator(begin()); }
  720. inline bool path::filename_is_dot() const
  721. {
  722. // implicit dot is tricky, so actually call filename(); see path::filename() example
  723. // in reference.html
  724. path p(filename());
  725. return p.size() == 1 && *p.c_str() == dot;
  726. }
  727. inline bool path::filename_is_dot_dot() const
  728. {
  729. return size() >= 2 && m_pathname[size()-1] == dot && m_pathname[size()-2] == dot
  730. && (m_pathname.size() == 2 || detail::is_element_separator(m_pathname[size()-3]));
  731. // use detail::is_element_separator() rather than detail::is_directory_separator
  732. // to deal with "c:.." edge case on Windows when ':' acts as a separator
  733. }
  734. //--------------------------------------------------------------------------------------//
  735. // class path member template implementation //
  736. //--------------------------------------------------------------------------------------//
  737. template <class InputIterator>
  738. path& path::append(InputIterator begin, InputIterator end)
  739. {
  740. if (begin == end)
  741. return *this;
  742. string_type::size_type sep_pos(m_append_separator_if_needed());
  743. std::basic_string<typename std::iterator_traits<InputIterator>::value_type>
  744. seq(begin, end);
  745. path_traits::convert(seq.c_str(), seq.c_str()+seq.size(), m_pathname);
  746. if (sep_pos)
  747. m_erase_redundant_separator(sep_pos);
  748. return *this;
  749. }
  750. template <class InputIterator>
  751. path& path::append(InputIterator begin, InputIterator end, const codecvt_type& cvt)
  752. {
  753. if (begin == end)
  754. return *this;
  755. string_type::size_type sep_pos(m_append_separator_if_needed());
  756. std::basic_string<typename std::iterator_traits<InputIterator>::value_type>
  757. seq(begin, end);
  758. path_traits::convert(seq.c_str(), seq.c_str()+seq.size(), m_pathname, cvt);
  759. if (sep_pos)
  760. m_erase_redundant_separator(sep_pos);
  761. return *this;
  762. }
  763. template <class Source>
  764. path& path::append(Source const& source)
  765. {
  766. if (path_traits::empty(source))
  767. return *this;
  768. string_type::size_type sep_pos(m_append_separator_if_needed());
  769. path_traits::dispatch(source, m_pathname);
  770. if (sep_pos)
  771. m_erase_redundant_separator(sep_pos);
  772. return *this;
  773. }
  774. template <class Source>
  775. path& path::append(Source const& source, const codecvt_type& cvt)
  776. {
  777. if (path_traits::empty(source))
  778. return *this;
  779. string_type::size_type sep_pos(m_append_separator_if_needed());
  780. path_traits::dispatch(source, m_pathname, cvt);
  781. if (sep_pos)
  782. m_erase_redundant_separator(sep_pos);
  783. return *this;
  784. }
  785. //--------------------------------------------------------------------------------------//
  786. // class path member template specializations //
  787. //--------------------------------------------------------------------------------------//
  788. template <> inline
  789. std::string path::string<std::string>() const
  790. { return string(); }
  791. template <> inline
  792. std::wstring path::string<std::wstring>() const
  793. { return wstring(); }
  794. template <> inline
  795. std::string path::string<std::string>(const codecvt_type& cvt) const
  796. { return string(cvt); }
  797. template <> inline
  798. std::wstring path::string<std::wstring>(const codecvt_type& cvt) const
  799. { return wstring(cvt); }
  800. template <> inline
  801. std::string path::generic_string<std::string>() const
  802. { return generic_string(); }
  803. template <> inline
  804. std::wstring path::generic_string<std::wstring>() const
  805. { return generic_wstring(); }
  806. template <> inline
  807. std::string path::generic_string<std::string>(const codecvt_type& cvt) const
  808. { return generic_string(cvt); }
  809. template <> inline
  810. std::wstring path::generic_string<std::wstring>(const codecvt_type& cvt) const
  811. { return generic_wstring(cvt); }
  812. //--------------------------------------------------------------------------------------//
  813. // path_traits convert function implementations //
  814. // requiring path::codecvt() be visable //
  815. //--------------------------------------------------------------------------------------//
  816. namespace path_traits
  817. { // without codecvt
  818. inline
  819. void convert(const char* from,
  820. const char* from_end, // 0 for null terminated MBCS
  821. std::wstring & to)
  822. {
  823. convert(from, from_end, to, path::codecvt());
  824. }
  825. inline
  826. void convert(const wchar_t* from,
  827. const wchar_t* from_end, // 0 for null terminated MBCS
  828. std::string & to)
  829. {
  830. convert(from, from_end, to, path::codecvt());
  831. }
  832. inline
  833. void convert(const char* from,
  834. std::wstring & to)
  835. {
  836. BOOST_ASSERT(from);
  837. convert(from, 0, to, path::codecvt());
  838. }
  839. inline
  840. void convert(const wchar_t* from,
  841. std::string & to)
  842. {
  843. BOOST_ASSERT(from);
  844. convert(from, 0, to, path::codecvt());
  845. }
  846. } // namespace path_traits
  847. } // namespace filesystem
  848. } // namespace boost
  849. //----------------------------------------------------------------------------//
  850. #include <boost/config/abi_suffix.hpp> // pops abi_prefix.hpp pragmas
  851. #endif // BOOST_FILESYSTEM_PATH_HPP