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 // Return a default locale object.
80 return std::locale();
81 # endif
82 }
83
process_locale()84 inline std::locale& process_locale()
85 {
86 static std::locale loc(default_locale());
87 return loc;
88 }
89
90 }
91
92 ///The internally used type for code conversion.
93 typedef std::codecvt<wchar_t, char, std::mbstate_t> codecvt_type;
94
95 ///Get a reference to the currently used code converter.
codecvt()96 inline const codecvt_type& codecvt()
97 {
98 return std::use_facet<std::codecvt<wchar_t, char, std::mbstate_t>>(
99 detail::process_locale());
100 }
101
102 ///Set the locale of the library.
imbue(const std::locale & loc)103 inline std::locale imbue(const std::locale& loc)
104 {
105 std::locale temp(detail::process_locale());
106 detail::process_locale() = loc;
107 return temp;
108 }
109
110
111 namespace detail
112 {
113
convert(const char * from,const char * from_end,wchar_t * to,wchar_t * to_end,const::boost::process::codecvt_type & cvt=::boost::process::codecvt ())114 inline std::size_t convert(const char* from,
115 const char* from_end,
116 wchar_t* to, wchar_t* to_end,
117 const ::boost::process::codecvt_type & cvt =
118 ::boost::process::codecvt())
119 {
120 std::mbstate_t state = std::mbstate_t(); // perhaps unneeded, but cuts bug reports
121 const char* from_next;
122 wchar_t* to_next;
123
124 auto res = cvt.in(state, from, from_end, from_next,
125 to, to_end, to_next);
126
127 if (res != std::codecvt_base::ok)
128 throw process_error(res, ::boost::process::codecvt_category(),
129 "boost::process codecvt to wchar_t");
130
131
132 return to_next - to;
133
134 }
135
convert(const wchar_t * from,const wchar_t * from_end,char * to,char * to_end,const::boost::process::codecvt_type & cvt=::boost::process::codecvt ())136 inline std::size_t convert(const wchar_t* from,
137 const wchar_t* from_end,
138 char* to, char* to_end,
139 const ::boost::process::codecvt_type & cvt =
140 ::boost::process::codecvt())
141 {
142 std::mbstate_t state = std::mbstate_t(); // perhaps unneeded, but cuts bug reports
143 const wchar_t* from_next;
144 char* to_next;
145
146 std::codecvt_base::result res;
147
148 if ((res=cvt.out(state, from, from_end, from_next,
149 to, to_end, to_next)) != std::codecvt_base::ok)
150 throw process_error(res, ::boost::process::codecvt_category(),
151 "boost::process codecvt to char");
152
153 return to_next - to;
154 }
155
convert(const std::string & st,const::boost::process::codecvt_type & cvt=::boost::process::codecvt ())156 inline std::wstring convert(const std::string & st,
157 const ::boost::process::codecvt_type & cvt =
158 ::boost::process::codecvt())
159 {
160 std::wstring out(st.size() + 10, ' '); //just to be sure
161 auto sz = convert(st.c_str(), st.c_str() + st.size(),
162 &out.front(), &out.back(), cvt);
163
164 out.resize(sz);
165 return out;
166 }
167
convert(const std::wstring & st,const::boost::process::codecvt_type & cvt=::boost::process::codecvt ())168 inline std::string convert(const std::wstring & st,
169 const ::boost::process::codecvt_type & cvt =
170 ::boost::process::codecvt())
171 {
172 std::string out(st.size() * 2, ' '); //just to be sure
173 auto sz = convert(st.c_str(), st.c_str() + st.size(),
174 &out.front(), &out.back(), cvt);
175
176 out.resize(sz);
177 return out;
178 }
179
convert(const std::vector<char> & st,const::boost::process::codecvt_type & cvt=::boost::process::codecvt ())180 inline std::vector<wchar_t> convert(const std::vector<char> & st,
181 const ::boost::process::codecvt_type & cvt =
182 ::boost::process::codecvt())
183 {
184 std::vector<wchar_t> out(st.size() + 10); //just to be sure
185 auto sz = convert(st.data(), st.data() + st.size(),
186 &out.front(), &out.back(), cvt);
187
188 out.resize(sz);
189 return out;
190 }
191
convert(const std::vector<wchar_t> & st,const::boost::process::codecvt_type & cvt=::boost::process::codecvt ())192 inline std::vector<char> convert(const std::vector<wchar_t> & st,
193 const ::boost::process::codecvt_type & cvt =
194 ::boost::process::codecvt())
195 {
196 std::vector<char> out(st.size() * 2); //just to be sure
197 auto sz = convert(st.data(), st.data() + st.size(),
198 &out.front(), &out.back(), cvt);
199
200 out.resize(sz);
201 return out;
202 }
203
204
convert(const char * begin,const char * end,const::boost::process::codecvt_type & cvt=::boost::process::codecvt ())205 inline std::wstring convert(const char *begin, const char* end,
206 const ::boost::process::codecvt_type & cvt =
207 ::boost::process::codecvt())
208 {
209 auto size = end-begin;
210 std::wstring out(size + 10, ' '); //just to be sure
211 using namespace std;
212 auto sz = convert(begin, end,
213 &out.front(), &out.back(), cvt);
214 out.resize(sz);
215 return out;
216 }
217
convert(const wchar_t * begin,const wchar_t * end,const::boost::process::codecvt_type & cvt=::boost::process::codecvt ())218 inline std::string convert(const wchar_t * begin, const wchar_t *end,
219 const ::boost::process::codecvt_type & cvt =
220 ::boost::process::codecvt())
221 {
222 auto size = end-begin;
223
224 std::string out(size * 2, ' '); //just to be sure
225 auto sz = convert(begin, end ,
226 &out.front(), &out.back(), cvt);
227
228 out.resize(sz);
229 return out;
230 }
231
232
233
234
235 }
236
237
238
239 }
240 }
241
242
243
244
245 #endif /* BOOST_PROCESS_LOCALE_HPP_ */
246