$OpenBSD: patch-libs_filesystem_src_path_cpp,v 1.2 2013/03/26 20:19:04 brad Exp $

Fix "std::runtime_error: locale::facet::_S_create_c_locale name not valid"
error on OpenBSD when using non-C locales.

--- libs/filesystem/src/path.cpp.orig	Mon Apr 16 09:36:28 2012
+++ libs/filesystem/src/path.cpp	Tue Mar 26 15:47:25 2013
@@ -35,7 +35,8 @@
 #ifdef BOOST_WINDOWS_API
 # include "windows_file_codecvt.hpp"
 # include <windows.h>
-#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)
+#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) || defined(__FreeBSD__) || \
+   defined(__OpenBSD__)
 # include <boost/filesystem/detail/utf8_codecvt_facet.hpp>
 #endif
 
@@ -783,147 +784,104 @@ namespace filesystem
 }  // namespace filesystem
 }  // namespace boost
 
-//--------------------------------------------------------------------------------------//
-//                                                                                      //
-//                                 detail helpers                                       //
-//                                                                                      //
-//--------------------------------------------------------------------------------------//
-
 namespace
 {
 
   //------------------------------------------------------------------------------------//
-  //                              locale helpers                                        //
+  //                                locale helpers                                      //
   //------------------------------------------------------------------------------------//
 
-#if defined(BOOST_WINDOWS_API) && defined(BOOST_FILESYSTEM_STATIC_LINK)
+  //  Prior versions of these locale and codecvt implementations tried to take advantage
+  //  of static initialization where possible, kept a local copy of the current codecvt
+  //  facet (to avoid codecvt() having to call use_facet()), and was not multi-threading
+  //  safe (again for efficiency).
+  //
+  //  This was error prone, and required different implementation techniques depending
+  //  on the compiler and also whether static or dynamic linking was used. Furthermore,
+  //  users could not easily provide their multi-threading safe wrappers because the
+  //  path interface requires the implementation itself to call codecvt() to obtain the
+  //  default facet, and the initialization of the static within path_locale() could race.
+  //
+  //  The code below is portable to all platforms, is much simpler, and hopefully will be 
+  //  much more robust. Timing tests (on Windows, using a Visual C++ release build)
+  //  indicated the current code is roughly 9% slower than the previous code, and that
+  //  seems a small price to pay for better code that is easier to use. 
 
+  //boost::detail::lightweight_mutex locale_mutex;
+
   inline std::locale default_locale()
   {
+# if defined(BOOST_WINDOWS_API)
     std::locale global_loc = std::locale();
-    std::locale loc(global_loc, new windows_file_codecvt);
-    return loc;
+    return std::locale(global_loc, new windows_file_codecvt);
+# elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) || defined(__FreeBSD__) || \
+    defined(__OpenBSD__)
+    // "All BSD system functions expect their string parameters to be in UTF-8 encoding
+    // and nothing else." See
+    // http://developer.apple.com/mac/library/documentation/MacOSX/Conceptual/BPInternational/Articles/FileEncodings.html
+    //
+    // "The kernel will reject any filename that is not a valid UTF-8 string, and it will
+    // even be normalized (to Unicode NFD) before stored on disk, at least when using HFS.
+    // The right way to deal with it would be to always convert the filename to UTF-8
+    // before trying to open/create a file." See
+    // http://lists.apple.com/archives/unix-porting/2007/Sep/msg00023.html
+    //
+    // "How a file name looks at the API level depends on the API. Current Carbon APIs
+    // handle file names as an array of UTF-16 characters; POSIX ones handle them as an
+    // array of UTF-8, which is why UTF-8 works well in Terminal. How it's stored on disk
+    // depends on the disk format; HFS+ uses UTF-16, but that's not important in most
+    // cases." See
+    // http://lists.apple.com/archives/applescript-users/2002/Sep/msg00319.html
+    //
+    // Many thanks to Peter Dimov for digging out the above references!
+
+    std::locale global_loc = std::locale();
+    return std::locale(global_loc, new boost::filesystem::detail::utf8_codecvt_facet);
+# else  // Other POSIX
+    // ISO C calls std::locale("") "the locale-specific native environment", and this
+    // locale is the default for many POSIX-based operating systems such as Linux.
+    return std::locale("");
+# endif
   }
 
   inline std::locale& path_locale()
+  // std::locale("") construction, needed on non-Apple POSIX systems, can throw
+  // (if environmental variables LC_MESSAGES or LANG are wrong, for example), so
+  // path_locale() provides lazy initialization via a local static to ensure that any 
+  // exceptions occur after main() starts and so can be caught. Furthermore,
+  // path_locale() is only called if path::codecvt() or path::imbue() are themselves
+  // actually called, ensuring that an exception will only be thrown if std::locale("")
+  // is really needed.
   {
     static std::locale loc(default_locale());
     return loc;
   }
-
-  inline const path::codecvt_type*& codecvt_facet_ptr()
-  {
-    static const std::codecvt<wchar_t, char, std::mbstate_t>*
-     facet(
-       &std::use_facet<std::codecvt<wchar_t, char, std::mbstate_t> >
-        (path_locale()));
-    return facet;
-  }
-
-#elif defined(BOOST_WINDOWS_API) && !defined(BOOST_FILESYSTEM_STATIC_LINK)
-
-  std::locale path_locale(std::locale(), new windows_file_codecvt); 
-
-  const std::codecvt<wchar_t, char, std::mbstate_t>*
-    codecvt_facet_ptr(&std::use_facet<std::codecvt<wchar_t, char, std::mbstate_t> >
-      (path_locale));
-
-#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)
-
-  // "All BSD system functions expect their string parameters to be in UTF-8 encoding
-  // and nothing else." See
-  // http://developer.apple.com/mac/library/documentation/MacOSX/Conceptual/BPInternational/Articles/FileEncodings.html
-  //
-  // "The kernel will reject any filename that is not a valid UTF-8 string, and it will
-  // even be normalized (to Unicode NFD) before stored on disk, at least when using HFS.
-  // The right way to deal with it would be to always convert the filename to UTF-8
-  // before trying to open/create a file." See
-  // http://lists.apple.com/archives/unix-porting/2007/Sep/msg00023.html
-  //
-  // "How a file name looks at the API level depends on the API. Current Carbon APIs
-  // handle file names as an array of UTF-16 characters; POSIX ones handle them as an
-  // array of UTF-8, which is why UTF-8 works well in Terminal. How it's stored on disk
-  // depends on the disk format; HFS+ uses UTF-16, but that's not important in most
-  // cases." See
-  // http://lists.apple.com/archives/applescript-users/2002/Sep/msg00319.html
-  //
-  // Many thanks to Peter Dimov for digging out the above references!
-
-  std::locale path_locale(std::locale(),
-                          new boost::filesystem::detail::utf8_codecvt_facet);
-
-  const std::codecvt<wchar_t, char, std::mbstate_t>*
-    codecvt_facet_ptr(&std::use_facet<std::codecvt<wchar_t, char, std::mbstate_t> >
-      (path_locale));
-
-#else  // Other POSIX
-
-  // ISO C calls std::locale("") "the locale-specific native environment", and this
-  // locale is the default for many POSIX-based operating systems such as Linux.
-
-  // std::locale("") construction can throw (if environmental variables LC_MESSAGES or
-  // or LANG are wrong, for example), so lazy initialization is used to ensure
-  // that exceptions occur after main() starts and so can be caught.
-
-  std::locale path_locale;  // initialized by path::codecvt() below
-  const std::codecvt<wchar_t, char, std::mbstate_t>* codecvt_facet_ptr;  // ditto
-
-# endif
-
 }  // unnamed namespace
 
 //--------------------------------------------------------------------------------------//
-//                           path::imbue implementation                                 //
+//              path::codecvt() and path::imbue() implementation                        //
 //--------------------------------------------------------------------------------------//
 
 namespace boost
 {
 namespace filesystem
 {
+  // See comments above
 
-#if defined(BOOST_WINDOWS_API) && defined(BOOST_FILESYSTEM_STATIC_LINK)
-
   const path::codecvt_type& path::codecvt()
   {
-    BOOST_ASSERT_MSG(codecvt_facet_ptr(), "codecvt_facet_ptr() facet hasn't been properly initialized");
-    return *codecvt_facet_ptr();
+    BOOST_ASSERT_MSG(&path_locale(), "boost::filesystem::path locale initialization error");
+//    boost::detail::lightweight_mutex::scoped_lock lock(locale_mutex);
+    return std::use_facet<std::codecvt<wchar_t, char, std::mbstate_t> >(path_locale());
   }
 
-  std::locale path::imbue(const std::locale & loc)
+  std::locale path::imbue(const std::locale& loc)
   {
+//    boost::detail::lightweight_mutex::scoped_lock lock(locale_mutex);
     std::locale temp(path_locale());
     path_locale() = loc;
-    codecvt_facet_ptr() =
-      &std::use_facet<std::codecvt<wchar_t, char, std::mbstate_t> >(path_locale());
     return temp;
   }
-
-#else
-
-  const path::codecvt_type& path::codecvt()
-  {
-#   if defined(BOOST_POSIX_API) && \
-      !(defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__))
-      // A local static initialized by calling path::imbue ensures that std::locale(""),
-      // which may throw, is called only if path_locale and condecvt_facet will actually
-      // be used. Thus misconfigured environmental variables will only cause an
-      // exception if a valid std::locale("") is actually needed.
-      static std::locale posix_lazy_initialization(path::imbue(std::locale("")));
-#   endif
-    return *codecvt_facet_ptr;
-  }
-
-  std::locale path::imbue(const std::locale& loc)
-  {
-    std::locale temp(path_locale);
-    path_locale = loc;
-    codecvt_facet_ptr =
-      &std::use_facet<std::codecvt<wchar_t, char, std::mbstate_t> >(path_locale);
-    return temp;
-  }
-
-
-#endif
 
 }  // namespace filesystem
 }  // namespace boost
