diff --git a/include/boost/filesystem/path.hpp b/include/boost/filesystem/path.hpp index cf705b5..37f39d0 100644 --- a/include/boost/filesystem/path.hpp +++ b/include/boost/filesystem/path.hpp @@ -121,9 +121,10 @@ namespace filesystem // multi-byte character strings which may have embedded nulls. Embedded null // support is required for some Asian languages on Windows. - // [defaults] "const codecvt_type& cvt=codecvt()" default arguments are not used - // because some compilers, such as Microsoft prior to VC++ 10, do not handle defaults - // correctly in templates. + // "const codecvt_type& cvt=codecvt()" default arguments are not used because this + // limits the impact of locale("") initialization failures on POSIX systems to programs + // that actually depend on locale(""). It further ensures that exceptions thrown + // as a result of such failues occur after main() has started, so can be caught. // ----- constructors ----- @@ -136,17 +137,9 @@ namespace filesystem typename boost::enable_if::type> >::type* =0) { - path_traits::dispatch(source, m_pathname, codecvt()); + path_traits::dispatch(source, m_pathname); } - // Overloads for the operating system API's native character type. Rationale: - // - Avoids use of codecvt() for native value_type strings. This limits the - // impact of locale("") initialization failures on POSIX systems to programs - // that actually depend on locale(""). It further ensures that exceptions thrown - // as a result of such failues occur after main() has started, so can be caught. - // This is a partial resolution of tickets 4688, 5100, and 5289. - // - A slight optimization for a common use case, particularly on POSIX since - // value_type is char and that is the most common useage. path(const value_type* s) : m_pathname(s) {} path(value_type* s) : m_pathname(s) {} path(const string_type& s) : m_pathname(s) {} @@ -154,7 +147,6 @@ namespace filesystem template path(Source const& source, const codecvt_type& cvt) - // see [defaults] note above explaining why codecvt() default arguments are not used { path_traits::dispatch(source, m_pathname, cvt); } @@ -164,9 +156,10 @@ namespace filesystem { if (begin != end) { + // convert requires contiguous string, so copy std::basic_string::value_type> s(begin, end); - path_traits::convert(s.c_str(), s.c_str()+s.size(), m_pathname, codecvt()); + path_traits::convert(s.c_str(), s.c_str()+s.size(), m_pathname); } } @@ -175,6 +168,7 @@ namespace filesystem { if (begin != end) { + // convert requires contiguous string, so copy std::basic_string::value_type> s(begin, end); path_traits::convert(s.c_str(), s.c_str()+s.size(), m_pathname, cvt); @@ -195,11 +189,11 @@ namespace filesystem operator=(Source const& source) { m_pathname.clear(); - path_traits::dispatch(source, m_pathname, codecvt()); + path_traits::dispatch(source, m_pathname); return *this; } - // value_type overloads. Same rationale as for constructors above + // value_type overloads path& operator=(const value_type* ptr) // required in case ptr overlaps *this {m_pathname = ptr; return *this;} @@ -221,7 +215,14 @@ namespace filesystem template path& assign(InputIterator begin, InputIterator end) { - return assign(begin, end, codecvt()); + m_pathname.clear(); + if (begin != end) + { + std::basic_string::value_type> + s(begin, end); + path_traits::convert(s.c_str(), s.c_str()+s.size(), m_pathname); + } + return *this; } template @@ -244,7 +245,7 @@ namespace filesystem typename boost::decay::type>, path&>::type operator+=(Source const& source) { - return concat(source, codecvt()); + return concat(source); } // value_type overloads. Same rationale as for constructors above @@ -262,7 +263,14 @@ namespace filesystem CharT tmp[2]; tmp[0] = c; tmp[1] = 0; - return concat(tmp, codecvt()); + return concat(tmp); + } + + template + path& concat(Source const& source) + { + path_traits::dispatch(source, m_pathname); + return *this; } template @@ -275,7 +283,12 @@ namespace filesystem template path& concat(InputIterator begin, InputIterator end) { - return concat(begin, end, codecvt()); + if (begin == end) + return *this; + std::basic_string::value_type> + s(begin, end); + path_traits::convert(s.c_str(), s.c_str()+s.size(), m_pathname); + return *this; } template @@ -301,7 +314,7 @@ namespace filesystem typename boost::decay::type>, path&>::type operator/=(Source const& source) { - return append(source, codecvt()); + return append(source); } path& operator/=(const value_type* ptr); @@ -312,20 +325,26 @@ namespace filesystem path& operator/=(const string_type& s) { return this->operator/=(path(s)); } path& operator/=(string_type& s) { return this->operator/=(path(s)); } + path& append(const value_type* ptr) // required in case ptr overlaps *this + { + this->operator/=(ptr); + return *this; + } + path& append(const value_type* ptr, const codecvt_type&) // required in case ptr overlaps *this { this->operator/=(ptr); return *this; } + template + path& append(Source const& source); + template path& append(Source const& source, const codecvt_type& cvt); template - path& append(InputIterator begin, InputIterator end) - { - return append(begin, end, codecvt()); - } + path& append(InputIterator begin, InputIterator end); template path& append(InputIterator begin, InputIterator end, const codecvt_type& cvt); @@ -374,7 +393,14 @@ namespace filesystem String string(const codecvt_type& cvt) const; # ifdef BOOST_WINDOWS_API - const std::string string() const { return string(codecvt()); } + const std::string string() const + { + std::string tmp; + if (!m_pathname.empty()) + path_traits::convert(&*m_pathname.begin(), &*m_pathname.begin()+m_pathname.size(), + tmp); + return tmp; + } const std::string string(const codecvt_type& cvt) const { std::string tmp; @@ -393,7 +419,14 @@ namespace filesystem const std::string& string() const { return m_pathname; } const std::string& string(const codecvt_type&) const { return m_pathname; } - const std::wstring wstring() const { return wstring(codecvt()); } + const std::wstring wstring() const + { + std::wstring tmp; + if (!m_pathname.empty()) + path_traits::convert(&*m_pathname.begin(), &*m_pathname.begin()+m_pathname.size(), + tmp); + return tmp; + } const std::wstring wstring(const codecvt_type& cvt) const { std::wstring tmp; @@ -414,7 +447,7 @@ namespace filesystem String generic_string(const codecvt_type& cvt) const; # ifdef BOOST_WINDOWS_API - const std::string generic_string() const { return generic_string(codecvt()); } + const std::string generic_string() const; const std::string generic_string(const codecvt_type& cvt) const; const std::wstring generic_wstring() const; const std::wstring generic_wstring(const codecvt_type&) const { return generic_wstring(); }; @@ -423,7 +456,7 @@ namespace filesystem // On POSIX-like systems, the generic format is the same as the native format const std::string& generic_string() const { return m_pathname; } const std::string& generic_string(const codecvt_type&) const { return m_pathname; } - const std::wstring generic_wstring() const { return wstring(codecvt()); } + const std::wstring generic_wstring() const { return wstring(); } const std::wstring generic_wstring(const codecvt_type& cvt) const { return wstring(cvt); } # endif @@ -699,9 +732,23 @@ namespace filesystem // class path member template implementation // //--------------------------------------------------------------------------------------// + template + path& path::append(InputIterator begin, InputIterator end) + { + if (begin == end) + return *this; + string_type::size_type sep_pos(m_append_separator_if_needed()); + std::basic_string::value_type> + s(begin, end); + path_traits::convert(s.c_str(), s.c_str()+s.size(), m_pathname); + if (sep_pos) + m_erase_redundant_separator(sep_pos); + return *this; + } + template path& path::append(InputIterator begin, InputIterator end, const codecvt_type& cvt) - { + { if (begin == end) return *this; string_type::size_type sep_pos(m_append_separator_if_needed()); @@ -713,6 +760,18 @@ namespace filesystem return *this; } + template + path& path::append(Source const& source) + { + if (path_traits::empty(source)) + return *this; + string_type::size_type sep_pos(m_append_separator_if_needed()); + path_traits::dispatch(source, m_pathname); + if (sep_pos) + m_erase_redundant_separator(sep_pos); + return *this; + } + template path& path::append(Source const& source, const codecvt_type& cvt) { @@ -761,7 +820,46 @@ namespace filesystem std::wstring path::generic_string(const codecvt_type& cvt) const { return generic_wstring(cvt); } + //--------------------------------------------------------------------------------------// + // path_traits convert function implementations // + // requiring path::codecvt() be visable // + //--------------------------------------------------------------------------------------// +namespace path_traits +{ // without codecvt + + inline + void convert(const char* from, + const char* from_end, // 0 for null terminated MBCS + std::wstring & to) + { + convert(from, from_end, to, path::codecvt()); + } + + inline + void convert(const wchar_t* from, + const wchar_t* from_end, // 0 for null terminated MBCS + std::string & to) + { + convert(from, from_end, to, path::codecvt()); + } + + inline + void convert(const char* from, + std::wstring & to) + { + BOOST_ASSERT(from); + convert(from, 0, to, path::codecvt()); + } + + inline + void convert(const wchar_t* from, + std::string & to) + { + BOOST_ASSERT(from); + convert(from, 0, to, path::codecvt()); + } +} // namespace path_traits } // namespace filesystem } // namespace boost diff --git a/include/boost/filesystem/path_traits.hpp b/include/boost/filesystem/path_traits.hpp index a6a2505..5441692 100644 --- a/include/boost/filesystem/path_traits.hpp +++ b/include/boost/filesystem/path_traits.hpp @@ -91,43 +91,65 @@ namespace path_traits { // value types differ ---------------------------------------------------------------// // // A from_end argument of 0 is less efficient than a known end, so use only if needed - - BOOST_FILESYSTEM_DECL - void convert(const char* from, - const char* from_end, // 0 for null terminated MBCS - std::wstring & to, - const codecvt_type& cvt); + + // with codecvt BOOST_FILESYSTEM_DECL - void convert(const wchar_t* from, - const wchar_t* from_end, // 0 for null terminated MBCS - std::string & to, - const codecvt_type& cvt); + void convert(const char* from, + const char* from_end, // 0 for null terminated MBCS + std::wstring & to, + const codecvt_type& cvt); - inline - void convert(const char* from, - std::wstring & to, - const codecvt_type& cvt) + BOOST_FILESYSTEM_DECL + void convert(const wchar_t* from, + const wchar_t* from_end, // 0 for null terminated MBCS + std::string & to, + const codecvt_type& cvt); + + inline + void convert(const char* from, + std::wstring & to, + const codecvt_type& cvt) { BOOST_ASSERT(from); convert(from, 0, to, cvt); } - inline - void convert(const wchar_t* from, - std::string & to, - const codecvt_type& cvt) + inline + void convert(const wchar_t* from, + std::string & to, + const codecvt_type& cvt) { BOOST_ASSERT(from); convert(from, 0, to, cvt); } + // without codecvt + + inline + void convert(const char* from, + const char* from_end, // 0 for null terminated MBCS + std::wstring & to); + + inline + void convert(const wchar_t* from, + const wchar_t* from_end, // 0 for null terminated MBCS + std::string & to); + + inline + void convert(const char* from, + std::wstring & to); + + inline + void convert(const wchar_t* from, + std::string & to); + // value types same -----------------------------------------------------------------// - // char + // char with codecvt - inline - void convert(const char* from, const char* from_end, std::string & to, + inline + void convert(const char* from, const char* from_end, std::string & to, const codecvt_type&) { BOOST_ASSERT(from); @@ -135,19 +157,19 @@ namespace path_traits { to.append(from, from_end); } - inline - void convert(const char* from, - std::string & to, - const codecvt_type&) + inline + void convert(const char* from, + std::string & to, + const codecvt_type&) { BOOST_ASSERT(from); to += from; } - // wchar_t + // wchar_t with codecvt - inline - void convert(const wchar_t* from, const wchar_t* from_end, std::wstring & to, + inline + void convert(const wchar_t* from, const wchar_t* from_end, std::wstring & to, const codecvt_type&) { BOOST_ASSERT(from); @@ -155,10 +177,44 @@ namespace path_traits { to.append(from, from_end); } - inline - void convert(const wchar_t* from, - std::wstring & to, - const codecvt_type&) + inline + void convert(const wchar_t* from, + std::wstring & to, + const codecvt_type&) + { + BOOST_ASSERT(from); + to += from; + } + + // char without codecvt + + inline + void convert(const char* from, const char* from_end, std::string & to) + { + BOOST_ASSERT(from); + BOOST_ASSERT(from_end); + to.append(from, from_end); + } + + inline + void convert(const char* from, std::string & to) + { + BOOST_ASSERT(from); + to += from; + } + + // wchar_t without codecvt + + inline + void convert(const wchar_t* from, const wchar_t* from_end, std::wstring & to) + { + BOOST_ASSERT(from); + BOOST_ASSERT(from_end); + to.append(from, from_end); + } + + inline + void convert(const wchar_t* from, std::wstring & to) { BOOST_ASSERT(from); to += from; @@ -166,7 +222,7 @@ namespace path_traits { // Source dispatch -----------------------------------------------------------------// - // contiguous containers + // contiguous containers with codecvt template inline void dispatch(const std::string& c, U& to, const codecvt_type& cvt) { @@ -192,12 +248,38 @@ namespace path_traits { convert(&*c.begin(), &*c.begin() + c.size(), to, cvt); } - // non-contiguous containers + // contiguous containers without codecvt + template inline + void dispatch(const std::string& c, U& to) + { + if (c.size()) + convert(&*c.begin(), &*c.begin() + c.size(), to); + } + template inline + void dispatch(const std::wstring& c, U& to) + { + if (c.size()) + convert(&*c.begin(), &*c.begin() + c.size(), to); + } + template inline + void dispatch(const std::vector& c, U& to) + { + if (c.size()) + convert(&*c.begin(), &*c.begin() + c.size(), to); + } + template inline + void dispatch(const std::vector& c, U& to) + { + if (c.size()) + convert(&*c.begin(), &*c.begin() + c.size(), to); + } + + // non-contiguous containers with codecvt template inline // disable_if aids broken compilers (IBM, old GCC, etc.) and is harmless for // conforming compilers. Replace by plain "void" at some future date (2012?) typename boost::disable_if, void>::type - dispatch(const Container & c, U& to, const codecvt_type& cvt) + dispatch(const Container & c, U& to, const codecvt_type& cvt) { if (c.size()) { @@ -208,24 +290,59 @@ namespace path_traits { // c_str template inline - void dispatch(T * const & c_str, U& to, const codecvt_type& cvt) + void dispatch(T * const & c_str, U& to, const codecvt_type& cvt) { -// std::cout << "dispatch() const T *\n"; + // std::cout << "dispatch() const T *\n"; BOOST_ASSERT(c_str); convert(c_str, to, cvt); } - + // Note: there is no dispatch on C-style arrays because the array may // contain a string smaller than the array size. BOOST_FILESYSTEM_DECL - void dispatch(const directory_entry & de, + void dispatch(const directory_entry & de, # ifdef BOOST_WINDOWS_API - std::wstring & to, + std::wstring & to, # else - std::string & to, + std::string & to, # endif - const codecvt_type&); + const codecvt_type&); + + // non-contiguous containers without codecvt + template inline + // disable_if aids broken compilers (IBM, old GCC, etc.) and is harmless for + // conforming compilers. Replace by plain "void" at some future date (2012?) + typename boost::disable_if, void>::type + dispatch(const Container & c, U& to) + { + if (c.size()) + { + std::basic_string s(c.begin(), c.end()); + convert(s.c_str(), s.c_str()+s.size(), to); + } + } + + // c_str + template inline + void dispatch(T * const & c_str, U& to) + { + // std::cout << "dispatch() const T *\n"; + BOOST_ASSERT(c_str); + convert(c_str, to); + } + + // Note: there is no dispatch on C-style arrays because the array may + // contain a string smaller than the array size. + + BOOST_FILESYSTEM_DECL + void dispatch(const directory_entry & de, +# ifdef BOOST_WINDOWS_API + std::wstring & to +# else + std::string & to +# endif + ); }}} // namespace boost::filesystem::path_traits diff --git a/src/operations.cpp b/src/operations.cpp index 8275b67..6c04ce0 100644 --- a/src/operations.cpp +++ b/src/operations.cpp @@ -1880,15 +1880,25 @@ namespace path_traits { void dispatch(const directory_entry & de, # ifdef BOOST_WINDOWS_API - std::wstring& to, + std::wstring& to, # else - std::string& to, + std::string& to, # endif - const codecvt_type &) + const codecvt_type &) { to = de.path().native(); } + void dispatch(const directory_entry & de, +# ifdef BOOST_WINDOWS_API + std::wstring& to +# else + std::string& to +# endif + ) + { + to = de.path().native(); + } } // namespace path_traits } // namespace filesystem } // namespace boost diff --git a/src/path.cpp b/src/path.cpp index d139a8e..784e31a 100644 --- a/src/path.cpp +++ b/src/path.cpp @@ -185,8 +185,15 @@ namespace filesystem # ifdef BOOST_WINDOWS_API + const std::string path::generic_string() const + { + path tmp(*this); + std::replace(tmp.m_pathname.begin(), tmp.m_pathname.end(), L'\\', L'/'); + return tmp.string(); + } + const std::string path::generic_string(const codecvt_type& cvt) const - { + { path tmp(*this); std::replace(tmp.m_pathname.begin(), tmp.m_pathname.end(), L'\\', L'/'); return tmp.string(cvt); diff --git a/src/path_traits.cpp b/src/path_traits.cpp index 06ac798..07b92c0 100644 --- a/src/path_traits.cpp +++ b/src/path_traits.cpp @@ -126,7 +126,7 @@ namespace { namespace boost { namespace filesystem { namespace path_traits { //--------------------------------------------------------------------------------------// -// convert const char* to wstring // +// convert const char* to wstring // //--------------------------------------------------------------------------------------// BOOST_FILESYSTEM_DECL