246 lines
6.7 KiB
C++
246 lines
6.7 KiB
C++
|
// Copyright (c) 2016 Klemens D. Morgenstern
|
||
|
// Copyright (c) 2008 Beman Dawes
|
||
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||
|
|
||
|
#ifndef BOOST_PROCESS_LOCALE_HPP_
|
||
|
#define BOOST_PROCESS_LOCALE_HPP_
|
||
|
|
||
|
#include <system_error>
|
||
|
#include <boost/process/detail/config.hpp>
|
||
|
|
||
|
#if defined(BOOST_WINDOWS_API)
|
||
|
#include <boost/process/detail/windows/locale.hpp>
|
||
|
# elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) \
|
||
|
|| defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__)
|
||
|
#include <codecvt>
|
||
|
#endif
|
||
|
|
||
|
#include <locale>
|
||
|
|
||
|
namespace boost
|
||
|
{
|
||
|
namespace process
|
||
|
{
|
||
|
namespace detail
|
||
|
{
|
||
|
|
||
|
class codecvt_category_t : public std::error_category
|
||
|
{
|
||
|
public:
|
||
|
codecvt_category_t() = default;
|
||
|
const char* name() const noexcept override {return "codecvt";}
|
||
|
std::string message(int ev) const override
|
||
|
{
|
||
|
std::string str;
|
||
|
switch (ev)
|
||
|
{
|
||
|
case std::codecvt_base::ok:
|
||
|
str = "ok";
|
||
|
break;
|
||
|
case std::codecvt_base::partial:
|
||
|
str = "partial";
|
||
|
break;
|
||
|
case std::codecvt_base::error:
|
||
|
str = "error";
|
||
|
break;
|
||
|
case std::codecvt_base::noconv:
|
||
|
str = "noconv";
|
||
|
break;
|
||
|
default:
|
||
|
str = "unknown error";
|
||
|
}
|
||
|
return str;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
}
|
||
|
|
||
|
///Internally used error cateory for code conversion.
|
||
|
inline const std::error_category& codecvt_category()
|
||
|
{
|
||
|
static const ::boost::process::detail::codecvt_category_t cat;
|
||
|
return cat;
|
||
|
}
|
||
|
|
||
|
namespace detail
|
||
|
{
|
||
|
//copied from boost.filesystem
|
||
|
inline std::locale default_locale()
|
||
|
{
|
||
|
# if defined(BOOST_WINDOWS_API)
|
||
|
std::locale global_loc = std::locale();
|
||
|
return std::locale(global_loc, new boost::process::detail::windows::windows_file_codecvt);
|
||
|
# elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) \
|
||
|
|| defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__)
|
||
|
std::locale global_loc = std::locale();
|
||
|
return std::locale(global_loc, new std::codecvt_utf8<wchar_t>);
|
||
|
# else // Other POSIX
|
||
|
// Return a default locale object.
|
||
|
return std::locale();
|
||
|
# endif
|
||
|
}
|
||
|
|
||
|
inline std::locale& process_locale()
|
||
|
{
|
||
|
static std::locale loc(default_locale());
|
||
|
return loc;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
///The internally used type for code conversion.
|
||
|
typedef std::codecvt<wchar_t, char, std::mbstate_t> codecvt_type;
|
||
|
|
||
|
///Get a reference to the currently used code converter.
|
||
|
inline const codecvt_type& codecvt()
|
||
|
{
|
||
|
return std::use_facet<std::codecvt<wchar_t, char, std::mbstate_t>>(
|
||
|
detail::process_locale());
|
||
|
}
|
||
|
|
||
|
///Set the locale of the library.
|
||
|
inline std::locale imbue(const std::locale& loc)
|
||
|
{
|
||
|
std::locale temp(detail::process_locale());
|
||
|
detail::process_locale() = loc;
|
||
|
return temp;
|
||
|
}
|
||
|
|
||
|
|
||
|
namespace detail
|
||
|
{
|
||
|
|
||
|
inline std::size_t convert(const char* from,
|
||
|
const char* from_end,
|
||
|
wchar_t* to, wchar_t* to_end,
|
||
|
const ::boost::process::codecvt_type & cvt =
|
||
|
::boost::process::codecvt())
|
||
|
{
|
||
|
std::mbstate_t state = std::mbstate_t(); // perhaps unneeded, but cuts bug reports
|
||
|
const char* from_next;
|
||
|
wchar_t* to_next;
|
||
|
|
||
|
auto res = cvt.in(state, from, from_end, from_next,
|
||
|
to, to_end, to_next);
|
||
|
|
||
|
if (res != std::codecvt_base::ok)
|
||
|
throw process_error(res, ::boost::process::codecvt_category(),
|
||
|
"boost::process codecvt to wchar_t");
|
||
|
|
||
|
|
||
|
return to_next - to;
|
||
|
|
||
|
}
|
||
|
|
||
|
inline std::size_t convert(const wchar_t* from,
|
||
|
const wchar_t* from_end,
|
||
|
char* to, char* to_end,
|
||
|
const ::boost::process::codecvt_type & cvt =
|
||
|
::boost::process::codecvt())
|
||
|
{
|
||
|
std::mbstate_t state = std::mbstate_t(); // perhaps unneeded, but cuts bug reports
|
||
|
const wchar_t* from_next;
|
||
|
char* to_next;
|
||
|
|
||
|
std::codecvt_base::result res;
|
||
|
|
||
|
if ((res=cvt.out(state, from, from_end, from_next,
|
||
|
to, to_end, to_next)) != std::codecvt_base::ok)
|
||
|
throw process_error(res, ::boost::process::codecvt_category(),
|
||
|
"boost::process codecvt to char");
|
||
|
|
||
|
return to_next - to;
|
||
|
}
|
||
|
|
||
|
inline std::wstring convert(const std::string & st,
|
||
|
const ::boost::process::codecvt_type & cvt =
|
||
|
::boost::process::codecvt())
|
||
|
{
|
||
|
std::wstring out(st.size() + 10, ' '); //just to be sure
|
||
|
auto sz = convert(st.c_str(), st.c_str() + st.size(),
|
||
|
&out.front(), &out.back(), cvt);
|
||
|
|
||
|
out.resize(sz);
|
||
|
return out;
|
||
|
}
|
||
|
|
||
|
inline std::string convert(const std::wstring & st,
|
||
|
const ::boost::process::codecvt_type & cvt =
|
||
|
::boost::process::codecvt())
|
||
|
{
|
||
|
std::string out(st.size() * 2, ' '); //just to be sure
|
||
|
auto sz = convert(st.c_str(), st.c_str() + st.size(),
|
||
|
&out.front(), &out.back(), cvt);
|
||
|
|
||
|
out.resize(sz);
|
||
|
return out;
|
||
|
}
|
||
|
|
||
|
inline std::vector<wchar_t> convert(const std::vector<char> & st,
|
||
|
const ::boost::process::codecvt_type & cvt =
|
||
|
::boost::process::codecvt())
|
||
|
{
|
||
|
std::vector<wchar_t> out(st.size() + 10); //just to be sure
|
||
|
auto sz = convert(st.data(), st.data() + st.size(),
|
||
|
&out.front(), &out.back(), cvt);
|
||
|
|
||
|
out.resize(sz);
|
||
|
return out;
|
||
|
}
|
||
|
|
||
|
inline std::vector<char> convert(const std::vector<wchar_t> & st,
|
||
|
const ::boost::process::codecvt_type & cvt =
|
||
|
::boost::process::codecvt())
|
||
|
{
|
||
|
std::vector<char> out(st.size() * 2); //just to be sure
|
||
|
auto sz = convert(st.data(), st.data() + st.size(),
|
||
|
&out.front(), &out.back(), cvt);
|
||
|
|
||
|
out.resize(sz);
|
||
|
return out;
|
||
|
}
|
||
|
|
||
|
|
||
|
inline std::wstring convert(const char *begin, const char* end,
|
||
|
const ::boost::process::codecvt_type & cvt =
|
||
|
::boost::process::codecvt())
|
||
|
{
|
||
|
auto size = end-begin;
|
||
|
std::wstring out(size + 10, ' '); //just to be sure
|
||
|
using namespace std;
|
||
|
auto sz = convert(begin, end,
|
||
|
&out.front(), &out.back(), cvt);
|
||
|
out.resize(sz);
|
||
|
return out;
|
||
|
}
|
||
|
|
||
|
inline std::string convert(const wchar_t * begin, const wchar_t *end,
|
||
|
const ::boost::process::codecvt_type & cvt =
|
||
|
::boost::process::codecvt())
|
||
|
{
|
||
|
auto size = end-begin;
|
||
|
|
||
|
std::string out(size * 2, ' '); //just to be sure
|
||
|
auto sz = convert(begin, end ,
|
||
|
&out.front(), &out.back(), cvt);
|
||
|
|
||
|
out.resize(sz);
|
||
|
return out;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
#endif /* BOOST_PROCESS_LOCALE_HPP_ */
|