1 // Copyright (c) 2016 Klemens D. Morgenstern
2 // Copyright (c) 2008 Beman Dawes
3 // Distributed under the Boost Software License, Version 1.0. (See accompanying
4 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5 
6 #ifndef BOOST_PROCESS_LOCALE_HPP_
7 #define BOOST_PROCESS_LOCALE_HPP_
8 
9 #include <system_error>
10 #include <boost/process/detail/config.hpp>
11 
12 #if defined(BOOST_WINDOWS_API)
13 #include <boost/process/detail/windows/locale.hpp>
14 # elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) \
15 || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__)
16 #include <codecvt>
17 #endif
18 
19 #include <locale>
20 
21 namespace boost
22 {
23 namespace process
24 {
25 namespace detail
26 {
27 
28 class codecvt_category_t : public std::error_category
29 {
30 public:
31     codecvt_category_t() = default;
name() const32     const char* name() const noexcept override {return "codecvt";}
message(int ev) const33     std::string message(int ev) const override
34     {
35         std::string str;
36         switch (ev)
37         {
38         case std::codecvt_base::ok:
39             str = "ok";
40             break;
41         case std::codecvt_base::partial:
42             str = "partial";
43             break;
44         case std::codecvt_base::error:
45             str = "error";
46             break;
47         case std::codecvt_base::noconv:
48             str = "noconv";
49             break;
50         default:
51             str = "unknown error";
52         }
53         return str;
54     }
55 };
56 
57 }
58 
59 ///Internally used error cateory for code conversion.
codecvt_category()60 inline const std::error_category& codecvt_category()
61 {
62     static const ::boost::process::detail::codecvt_category_t cat;
63     return cat;
64 }
65 
66 namespace detail
67 {
68 //copied from boost.filesystem
default_locale()69 inline std::locale default_locale()
70 {
71 # if defined(BOOST_WINDOWS_API)
72     std::locale global_loc = std::locale();
73     return std::locale(global_loc, new boost::process::detail::windows::windows_file_codecvt);
74 # elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) \
75 || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__HAIKU__)
76     std::locale global_loc = std::locale();
77     return std::locale(global_loc, new std::codecvt_utf8<wchar_t>);
78 # else  // Other POSIX
79     // ISO C calls std::locale("") "the locale-specific native environment", and this
80     // locale is the default for many POSIX-based operating systems such as Linux.
81     return std::locale("");
82 # endif
83 }
84 
process_locale()85 inline std::locale& process_locale()
86 {
87     static std::locale loc(default_locale());
88     return loc;
89 }
90 
91 }
92 
93 ///The internally used type for code conversion.
94 typedef std::codecvt<wchar_t, char, std::mbstate_t> codecvt_type;
95 
96 ///Get a reference to the currently used code converter.
codecvt()97 inline const codecvt_type& codecvt()
98 {
99   return std::use_facet<std::codecvt<wchar_t, char, std::mbstate_t>>(
100                 detail::process_locale());
101 }
102 
103 ///Set the locale of the library.
imbue(const std::locale & loc)104 inline std::locale imbue(const std::locale& loc)
105 {
106   std::locale temp(detail::process_locale());
107   detail::process_locale() = loc;
108   return temp;
109 }
110 
111 
112 namespace detail
113 {
114 
convert(const char * from,const char * from_end,wchar_t * to,wchar_t * to_end,const::boost::process::codecvt_type & cvt=::boost::process::codecvt ())115 inline std::size_t convert(const char* from,
116                     const char* from_end,
117                     wchar_t* to, wchar_t* to_end,
118                     const ::boost::process::codecvt_type & cvt =
119                                  ::boost::process::codecvt())
120 {
121     std::mbstate_t state  = std::mbstate_t();  // perhaps unneeded, but cuts bug reports
122     const char* from_next;
123     wchar_t* to_next;
124 
125     auto res = cvt.in(state, from, from_end, from_next,
126                  to, to_end, to_next);
127 
128     if (res != std::codecvt_base::ok)
129          throw process_error(res, ::boost::process::codecvt_category(),
130              "boost::process codecvt to wchar_t");
131 
132 
133     return to_next - to;
134 
135 }
136 
convert(const wchar_t * from,const wchar_t * from_end,char * to,char * to_end,const::boost::process::codecvt_type & cvt=::boost::process::codecvt ())137 inline std::size_t convert(const wchar_t* from,
138                     const wchar_t* from_end,
139                     char* to, char* to_end,
140                     const ::boost::process::codecvt_type & cvt =
141                                  ::boost::process::codecvt())
142 {
143     std::mbstate_t state  = std::mbstate_t();  // perhaps unneeded, but cuts bug reports
144     const wchar_t* from_next;
145     char* to_next;
146 
147     std::codecvt_base::result res;
148 
149     if ((res=cvt.out(state, from, from_end, from_next,
150            to, to_end, to_next)) != std::codecvt_base::ok)
151                throw process_error(res, ::boost::process::codecvt_category(),
152                    "boost::process codecvt to char");
153 
154     return to_next - to;
155 }
156 
convert(const std::string & st,const::boost::process::codecvt_type & cvt=::boost::process::codecvt ())157 inline std::wstring convert(const std::string & st,
158                             const ::boost::process::codecvt_type & cvt =
159                                 ::boost::process::codecvt())
160 {
161     std::wstring out(st.size() + 10, ' '); //just to be sure
162     auto sz = convert(st.c_str(), st.c_str() + st.size(),
163                       &out.front(), &out.back(), cvt);
164 
165     out.resize(sz);
166     return out;
167 }
168 
convert(const std::wstring & st,const::boost::process::codecvt_type & cvt=::boost::process::codecvt ())169 inline std::string convert(const std::wstring & st,
170                            const ::boost::process::codecvt_type & cvt =
171                                 ::boost::process::codecvt())
172 {
173     std::string out(st.size() * 2, ' '); //just to be sure
174     auto sz = convert(st.c_str(), st.c_str() + st.size(),
175                       &out.front(), &out.back(), cvt);
176 
177     out.resize(sz);
178     return out;
179 }
180 
convert(const std::vector<char> & st,const::boost::process::codecvt_type & cvt=::boost::process::codecvt ())181 inline std::vector<wchar_t> convert(const std::vector<char> & st,
182                                     const ::boost::process::codecvt_type & cvt =
183                                         ::boost::process::codecvt())
184 {
185     std::vector<wchar_t> out(st.size() + 10); //just to be sure
186     auto sz = convert(st.data(), st.data() + st.size(),
187                       &out.front(), &out.back(), cvt);
188 
189     out.resize(sz);
190     return out;
191 }
192 
convert(const std::vector<wchar_t> & st,const::boost::process::codecvt_type & cvt=::boost::process::codecvt ())193 inline std::vector<char> convert(const std::vector<wchar_t> & st,
194                                  const ::boost::process::codecvt_type & cvt =
195                                      ::boost::process::codecvt())
196 {
197     std::vector<char> out(st.size() * 2); //just to be sure
198     auto sz = convert(st.data(), st.data() + st.size(),
199                       &out.front(), &out.back(), cvt);
200 
201     out.resize(sz);
202     return out;
203 }
204 
205 
convert(const char * begin,const char * end,const::boost::process::codecvt_type & cvt=::boost::process::codecvt ())206 inline std::wstring convert(const char *begin, const char* end,
207                             const ::boost::process::codecvt_type & cvt =
208                                 ::boost::process::codecvt())
209 {
210     auto size = end-begin;
211     std::wstring out(size + 10, ' '); //just to be sure
212     using namespace std;
213     auto sz = convert(begin, end,
214                       &out.front(), &out.back(), cvt);
215     out.resize(sz);
216     return out;
217 }
218 
convert(const wchar_t * begin,const wchar_t * end,const::boost::process::codecvt_type & cvt=::boost::process::codecvt ())219 inline std::string convert(const wchar_t  * begin, const wchar_t *end,
220                            const ::boost::process::codecvt_type & cvt =
221                                 ::boost::process::codecvt())
222 {
223     auto size = end-begin;
224 
225     std::string out(size * 2, ' '); //just to be sure
226     auto sz = convert(begin, end ,
227                       &out.front(), &out.back(), cvt);
228 
229     out.resize(sz);
230     return out;
231 }
232 
233 
234 
235 
236 }
237 
238 
239 
240 }
241 }
242 
243 
244 
245 
246 #endif /* BOOST_PROCESS_LOCALE_HPP_ */
247