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