1 // Copyright (c) 2006, 2007 Julio M. Merino Vidal
2 // Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
3 // Copyright (c) 2009 Boris Schaeling
4 // Copyright (c) 2010 Felipe Tanus, Boris Schaeling
5 // Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
6 // Copyright (c) 2016 Klemens D. Morgenstern
7 //
8 // Distributed under the Boost Software License, Version 1.0. (See accompanying
9 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
10 
11 /**
12  * \file boost/process/execute.hpp
13  *
14  * Defines a function to execute a program.
15  */
16 
17 #ifndef BOOST_PROCESS_EXECUTE_HPP
18 #define BOOST_PROCESS_EXECUTE_HPP
19 
20 #include <boost/process/detail/config.hpp>
21 #include <boost/process/detail/traits.hpp>
22 
23 #if defined(BOOST_POSIX_API)
24 #include <boost/process/detail/posix/executor.hpp>
25 #elif defined(BOOST_WINDOWS_API)
26 #include <boost/process/detail/windows/executor.hpp>
27 #endif
28 
29 #include <boost/process/detail/basic_cmd.hpp>
30 #include <boost/process/detail/handler.hpp>
31 
32 #include <boost/fusion/view.hpp>
33 #include <boost/fusion/container.hpp>
34 #include <boost/fusion/sequence.hpp>
35 #include <boost/fusion/tuple.hpp>
36 #include <boost/fusion/algorithm/transformation/filter_if.hpp>
37 #include <boost/fusion/adapted/std_tuple.hpp>
38 #include <boost/fusion/container/vector/convert.hpp>
39 
40 #include <type_traits>
41 #include <utility>
42 
43 namespace boost { namespace process {
44 
45 class child;
46 
47 namespace detail {
48 
49 
50 template<typename ...Args>
51 struct has_wchar;
52 
53 template<typename First, typename ...Args>
54 struct has_wchar<First, Args...>
55 {
56     typedef has_wchar<Args...> next;
57     typedef typename std::remove_cv<
58                 typename std::remove_reference<First>::type>::type res_type;
59 
60     constexpr static bool my_value = is_wchar_t<res_type>::value;
61     constexpr static bool value = my_value || next::value;
62 
63     typedef std::integral_constant<bool, value> type;
64 };
65 
66 template<typename First>
67 struct has_wchar<First>
68 {
69     typedef typename std::remove_cv<
70                 typename std::remove_reference<First>::type>::type res_type;
71 
72     constexpr static bool value = is_wchar_t<res_type>::value;
73 
74     typedef std::integral_constant<bool, value> type;
75 };
76 
77 
78 #if defined(BOOST_WINDOWS_API)
79 //everything needs to be wchar_t
80 #if defined(BOOST_NO_ANSI_APIS)
81 template<bool has_wchar>
82 struct required_char_type
83 {
84     typedef wchar_t type;
85 };
86 #else
87 template<bool has_wchar> struct required_char_type;
88 template<> struct required_char_type<true>
89 {
90     typedef wchar_t type;
91 };
92 template<> struct required_char_type<false>
93 {
94     typedef char type;
95 };
96 #endif
97 
98 #elif defined(BOOST_POSIX_API)
99 template<bool has_wchar>
100 struct required_char_type
101 {
102     typedef char type;
103 };
104 #endif
105 
106 template<typename ... Args>
107 using required_char_type_t = typename required_char_type<
108                     has_wchar<Args...>::value>::type;
109 
110 
111 template<typename Iterator, typename End, typename ...Args>
112 struct make_builders_from_view
113 {
114     typedef boost::fusion::set<Args...> set;
115     typedef typename boost::fusion::result_of::deref<Iterator>::type ref_type;
116     typedef typename std::remove_reference<ref_type>::type res_type;
117     typedef typename initializer_tag<res_type>::type tag;
118     typedef typename initializer_builder<tag>::type builder_type;
119     typedef typename boost::fusion::result_of::has_key<set, builder_type> has_key;
120 
121     typedef typename boost::fusion::result_of::next<Iterator>::type next_itr;
122     typedef typename make_builders_from_view<next_itr, End>::type next;
123 
124     typedef typename
125             std::conditional<has_key::value,
126                 typename make_builders_from_view<next_itr, End, Args...>::type,
127                 typename make_builders_from_view<next_itr, End, Args..., builder_type>::type
128             >::type type;
129 
130 };
131 
132 template<typename Iterator, typename ...Args>
133 struct make_builders_from_view<Iterator, Iterator, Args...>
134 {
135     typedef boost::fusion::set<Args...> type;
136 };
137 
138 template<typename Builders>
139 struct builder_ref
140 {
141     Builders &builders;
builder_refboost::process::detail::builder_ref142     builder_ref(Builders & builders) : builders(builders) {};
143 
144     template<typename T>
operator ()boost::process::detail::builder_ref145     void operator()(T && value) const
146     {
147         typedef typename initializer_tag<typename std::remove_reference<T>::type>::type tag;
148         typedef typename initializer_builder<tag>::type builder_type;
149         boost::fusion::at_key<builder_type>(builders)(std::forward<T>(value));
150     }
151 };
152 
153 template<typename T>
154 struct get_initializers_result
155 {
156     typedef typename T::result_type type;
157 };
158 
159 template<>
160 struct get_initializers_result<boost::fusion::void_>
161 {
162     typedef boost::fusion::void_ type;
163 };
164 
165 template<typename ...Args>
166 struct helper_vector
167 {
168 
169 };
170 
171 template<typename T, typename ...Stack>
172 struct invoke_get_initializer_collect_keys;
173 
174 template<typename ...Stack>
175 struct invoke_get_initializer_collect_keys<boost::fusion::vector<>, Stack...>
176 {
177     typedef helper_vector<Stack...> type;
178 };
179 
180 
181 template<typename First, typename ...Args, typename ...Stack>
182 struct invoke_get_initializer_collect_keys<boost::fusion::vector<First, Args...>, Stack...>
183 {
184     typedef typename invoke_get_initializer_collect_keys<boost::fusion::vector<Args...>, Stack..., First>::type next;
185     typedef helper_vector<Stack...> stack_t;
186 
187     typedef typename std::conditional<std::is_same<boost::fusion::void_, First>::value,
188             stack_t, next>::type type;
189 
190 
191 };
192 
193 
194 template<typename Keys>
195 struct invoke_get_initializer;
196 
197 template<typename ...Args>
198 struct invoke_get_initializer<helper_vector<Args...>>
199 
200 {
201     typedef boost::fusion::tuple<typename get_initializers_result<Args>::type...> result_type;
202 
203     template<typename Sequence>
callboost::process::detail::invoke_get_initializer204     static result_type call(Sequence & seq)
205     {
206         return result_type(boost::fusion::at_key<Args>(seq).get_initializer()...);;
207     }
208 };
209 
210 
211 
212 
213 
214 template<typename ...Args>
215 inline boost::fusion::tuple<typename get_initializers_result<Args>::type...>
get_initializers(boost::fusion::set<Args...> & builders)216         get_initializers(boost::fusion::set<Args...> & builders)
217 {
218     //typedef boost::fusion::tuple<typename get_initializers_result<Args>::type...> return_type;
219     typedef typename invoke_get_initializer_collect_keys<boost::fusion::vector<Args...>>::type keys;
220     return invoke_get_initializer<keys>::call(builders);
221 }
222 
223 
224 template<typename Char, typename ... Args>
basic_execute_impl(Args &&...args)225 inline child basic_execute_impl(Args && ... args)
226 {
227     //create a tuple from the argument list
228     boost::fusion::tuple<typename std::remove_reference<Args>::type&...> tup(args...);
229 
230     auto inits = boost::fusion::filter_if<
231                 boost::process::detail::is_initializer<
232                     typename std::remove_reference<
233                         boost::mpl::_
234                         >::type
235                     >
236                 >(tup);
237 
238     auto others = boost::fusion::filter_if<
239                 boost::mpl::not_<
240                     boost::process::detail::is_initializer<
241                      typename std::remove_reference<
242                             boost::mpl::_
243                             >::type
244                         >
245                     >
246                 >(tup);
247 
248    // typename detail::make_builders_from_view<decltype(others)>::type builders;
249 
250     //typedef typename boost::fusion::result_of::as_vector<decltype(inits)>::type  inits_t;
251     typedef typename boost::fusion::result_of::as_vector<decltype(others)>::type others_t;
252     //  typedef decltype(others) others_t;
253     typedef typename ::boost::process::detail::make_builders_from_view<
254             typename boost::fusion::result_of::begin<others_t>::type,
255             typename boost::fusion::result_of::end  <others_t>::type>::type builder_t;
256 
257     builder_t builders;
258     ::boost::process::detail::builder_ref<builder_t> builder_ref(builders);
259 
260     boost::fusion::for_each(others, builder_ref);
261     auto other_inits = ::boost::process::detail::get_initializers(builders);
262 
263 
264     boost::fusion::joint_view<decltype(other_inits), decltype(inits)> complete_inits(other_inits, inits);
265 
266     auto exec = boost::process::detail::api::make_executor<Char>(complete_inits);
267     return exec();
268 }
269 
270 template<typename ...Args>
execute_impl(Args &&...args)271 inline child execute_impl(Args&& ... args)
272 {
273     typedef required_char_type_t<Args...> req_char_type;
274 
275     return basic_execute_impl<req_char_type>(
276         boost::process::detail::char_converter_t<req_char_type, Args>::conv(
277                 std::forward<Args>(args))...
278             );
279 }
280 
281 }}}
282 
283 
284 #endif
285