1 // Copyright (c) 2016 Klemens D. Morgenstern
2 //
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 
7 #ifndef BOOST_PROCESS_DETAIL_BASIC_CMD_HPP_
8 #define BOOST_PROCESS_DETAIL_BASIC_CMD_HPP_
9 
10 #include <boost/process/detail/config.hpp>
11 
12 #include <boost/process/detail/handler_base.hpp>
13 #include <boost/process/detail/traits/cmd_or_exe.hpp>
14 #include <boost/process/detail/traits/wchar_t.hpp>
15 
16 #if defined( BOOST_WINDOWS_API )
17 #include <boost/process/detail/windows/basic_cmd.hpp>
18 #include <boost/process/detail/windows/cmd.hpp>
19 #elif defined( BOOST_POSIX_API )
20 #include <boost/process/detail/posix/basic_cmd.hpp>
21 #include <boost/process/detail/posix/cmd.hpp>
22 #endif
23 
24 #include <boost/process/shell.hpp>
25 
26 #include <iterator>
27 
28 
29 namespace boost { namespace process { namespace detail {
30 
31 template<typename Char>
32 struct exe_setter_
33 {
34     typedef Char value_type;
35     typedef std::basic_string<Char> string_type;
36 
37     string_type exe_;
exe_setter_boost::process::detail::exe_setter_38     exe_setter_(string_type && str)      : exe_(std::move(str)) {}
exe_setter_boost::process::detail::exe_setter_39     exe_setter_(const string_type & str) : exe_(str) {}
40 };
41 
42 template<> struct is_wchar_t<exe_setter_<wchar_t>> : std::true_type {};
43 
44 
45 template<>
46 struct char_converter<char, exe_setter_<wchar_t>>
47 {
convboost::process::detail::char_converter48     static exe_setter_<char> conv(const exe_setter_<wchar_t> & in)
49     {
50         return {::boost::process::detail::convert(in.exe_)};
51     }
52 };
53 
54 template<>
55 struct char_converter<wchar_t, exe_setter_<char>>
56 {
convboost::process::detail::char_converter57     static exe_setter_<wchar_t> conv(const exe_setter_<char> & in)
58     {
59         return {::boost::process::detail::convert(in.exe_)};
60     }
61 };
62 
63 
64 
65 template <typename Char, bool Append >
66 struct arg_setter_
67 {
68     using value_type = Char;
69     using string_type = std::basic_string<value_type>;
70     std::vector<string_type> _args;
71 
72     typedef typename std::vector<string_type>::iterator       iterator;
73     typedef typename std::vector<string_type>::const_iterator const_iterator;
74 
75     template<typename Iterator>
arg_setter_boost::process::detail::arg_setter_76     arg_setter_(Iterator && begin, Iterator && end) : _args(begin, end) {}
77 
78     template<typename Range>
arg_setter_boost::process::detail::arg_setter_79     arg_setter_(Range && str) :
80             _args(std::begin(str),
81                   std::end(str)) {}
82 
beginboost::process::detail::arg_setter_83     iterator begin() {return _args.begin();}
endboost::process::detail::arg_setter_84     iterator end()   {return _args.end();}
beginboost::process::detail::arg_setter_85     const_iterator begin() const {return _args.begin();}
endboost::process::detail::arg_setter_86     const_iterator end()   const {return _args.end();}
arg_setter_boost::process::detail::arg_setter_87     arg_setter_(string_type & str)     : _args{{str}} {}
arg_setter_boost::process::detail::arg_setter_88     arg_setter_(string_type && s)      : _args({std::move(s)}) {}
arg_setter_boost::process::detail::arg_setter_89     arg_setter_(const string_type & s) : _args({s}) {}
arg_setter_boost::process::detail::arg_setter_90     arg_setter_(const value_type* s)   : _args({std::move(s)}) {}
91 
92     template<std::size_t Size>
arg_setter_boost::process::detail::arg_setter_93     arg_setter_(const value_type (&s) [Size]) : _args({s}) {}
94 };
95 
96 template<> struct is_wchar_t<arg_setter_<wchar_t, true >> : std::true_type {};
97 template<> struct is_wchar_t<arg_setter_<wchar_t, false>> : std::true_type {};
98 
99 template<>
100 struct char_converter<char, arg_setter_<wchar_t, true>>
101 {
convboost::process::detail::char_converter102     static arg_setter_<char, true> conv(const arg_setter_<wchar_t, true> & in)
103     {
104         std::vector<std::string> vec(in._args.size());
105         std::transform(in._args.begin(), in._args.end(), vec.begin(),
106                 [](const std::wstring & ws)
107                 {
108                     return ::boost::process::detail::convert(ws);
109                 });
110         return {vec};
111     }
112 };
113 
114 template<>
115 struct char_converter<wchar_t, arg_setter_<char, true>>
116 {
convboost::process::detail::char_converter117     static arg_setter_<wchar_t, true> conv(const arg_setter_<char, true> & in)
118     {
119         std::vector<std::wstring> vec(in._args.size());
120         std::transform(in._args.begin(), in._args.end(), vec.begin(),
121                 [](const std::string & ws)
122                 {
123                     return ::boost::process::detail::convert(ws);
124                 });
125 
126         return {vec};
127     }
128 };
129 
130 template<>
131 struct char_converter<char, arg_setter_<wchar_t, false>>
132 {
convboost::process::detail::char_converter133     static arg_setter_<char, false> conv(const arg_setter_<wchar_t, false> & in)
134     {
135         std::vector<std::string> vec(in._args.size());
136         std::transform(in._args.begin(), in._args.end(), vec.begin(),
137                 [](const std::wstring & ws)
138                 {
139                     return ::boost::process::detail::convert(ws);
140                 });
141         return {vec};    }
142 };
143 
144 template<>
145 struct char_converter<wchar_t, arg_setter_<char, false>>
146 {
convboost::process::detail::char_converter147     static arg_setter_<wchar_t, false> conv(const arg_setter_<char, false> & in)
148     {
149         std::vector<std::wstring> vec(in._args.size());
150         std::transform(in._args.begin(), in._args.end(), vec.begin(),
151                 [](const std::string & ws)
152                 {
153                     return ::boost::process::detail::convert(ws);
154                 });
155         return {vec};
156     }
157 };
158 
159 using api::exe_cmd_init;
160 
161 template<typename Char>
162 struct exe_builder
163 {
164     //set by path, because that will not be interpreted as a cmd
165     bool not_cmd = false;
166     bool shell   = false;
167     using string_type = std::basic_string<Char>;
168     string_type exe;
169     std::vector<string_type> args;
170 
operator ()boost::process::detail::exe_builder171     void operator()(const boost::filesystem::path & data)
172     {
173         not_cmd = true;
174         if (exe.empty())
175             exe = data.native();
176         else
177             args.push_back(data.native());
178     }
179 
operator ()boost::process::detail::exe_builder180     void operator()(const string_type & data)
181     {
182         if (exe.empty())
183             exe = data;
184         else
185             args.push_back(data);
186     }
operator ()boost::process::detail::exe_builder187     void operator()(const Char* data)
188     {
189         if (exe.empty())
190             exe = data;
191         else
192             args.push_back(data);
193     }
operator ()boost::process::detail::exe_builder194     void operator()(shell_) {shell = true;}
operator ()boost::process::detail::exe_builder195     void operator()(std::vector<string_type> && data)
196     {
197         if (data.empty())
198             return;
199 
200         auto itr = std::make_move_iterator(data.begin());
201         auto end = std::make_move_iterator(data.end());
202 
203         if (exe.empty())
204         {
205             exe = *itr;
206             itr++;
207         }
208         args.insert(args.end(), itr, end);
209     }
210 
operator ()boost::process::detail::exe_builder211     void operator()(const std::vector<string_type> & data)
212     {
213         if (data.empty())
214             return;
215 
216         auto itr = data.begin();
217         auto end = data.end();
218 
219         if (exe.empty())
220         {
221             exe = *itr;
222             itr++;
223         }
224         args.insert(args.end(), itr, end);
225     }
operator ()boost::process::detail::exe_builder226     void operator()(exe_setter_<Char> && data)
227     {
228         not_cmd = true;
229         exe = std::move(data.exe_);
230     }
operator ()boost::process::detail::exe_builder231     void operator()(const exe_setter_<Char> & data)
232     {
233         not_cmd = true;
234         exe = data.exe_;
235     }
operator ()boost::process::detail::exe_builder236     void operator()(arg_setter_<Char, false> && data)
237     {
238         args.assign(
239                 std::make_move_iterator(data._args.begin()),
240                 std::make_move_iterator(data._args.end()));
241     }
operator ()boost::process::detail::exe_builder242     void operator()(arg_setter_<Char, true> && data)
243     {
244         args.insert(args.end(),
245                 std::make_move_iterator(data._args.begin()),
246                 std::make_move_iterator(data._args.end()));
247     }
operator ()boost::process::detail::exe_builder248     void operator()(const arg_setter_<Char, false> & data)
249     {
250         args.assign(data._args.begin(), data._args.end());
251     }
operator ()boost::process::detail::exe_builder252     void operator()(const arg_setter_<Char, true> & data)
253     {
254         args.insert(args.end(), data._args.begin(), data._args.end());
255     }
256 
get_initializerboost::process::detail::exe_builder257     api::exe_cmd_init<Char> get_initializer()
258     {
259         if (not_cmd || !args.empty())
260         {
261             if (shell)
262                 return api::exe_cmd_init<Char>::exe_args_shell(std::move(exe), std::move(args));
263             else
264                 return api::exe_cmd_init<Char>::exe_args(std::move(exe), std::move(args));
265         }
266         else
267             if (shell)
268                 return api::exe_cmd_init<Char>::cmd_shell(std::move(exe));
269             else
270                 return api::exe_cmd_init<Char>::cmd(std::move(exe));
271 
272     }
273     typedef api::exe_cmd_init<Char> result_type;
274 };
275 
276 template<>
277 struct initializer_builder<cmd_or_exe_tag<char>>
278 {
279     typedef exe_builder<char> type;
280 };
281 
282 template<>
283 struct initializer_builder<cmd_or_exe_tag<wchar_t>>
284 {
285     typedef exe_builder<wchar_t> type;
286 };
287 
288 }}}
289 
290 
291 
292 #endif /* BOOST_PROCESS_DETAIL_EXE_BUILDER_HPP_ */
293