path.hpp 40 KB

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