summaryrefslogtreecommitdiff
path: root/boost/process/error.hpp
blob: f70cce6c83c7bea2074bb6653d65ca4c1a53e1b0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
// Copyright (c) 2006, 2007 Julio M. Merino Vidal
// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
// Copyright (c) 2009 Boris Schaeling
// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
// Copyright (c) 2011, 2012 Jeff Flinn, Boris Schaeling
// Copyright (c) 2016 Klemens D. Morgenstern
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#ifndef BOOST_PROCESS_DETAIL_ERROR_HPP
#define BOOST_PROCESS_DETAIL_ERROR_HPP

#include <boost/process/detail/config.hpp>
#include <boost/process/detail/traits.hpp>


#if defined(BOOST_POSIX_API)
#include <boost/process/detail/posix/handler.hpp>
#elif defined(BOOST_WINDOWS_API)
#include <boost/process/detail/windows/handler.hpp>
#endif

#include <system_error>

#include <type_traits>
#include <boost/fusion/algorithm/query/find_if.hpp>
#include <boost/fusion/sequence/intrinsic/begin.hpp>
#include <boost/fusion/sequence/intrinsic/end.hpp>
#include <boost/fusion/container/vector/convert.hpp>
#include <boost/fusion/iterator/deref.hpp>
#include <boost/fusion/sequence/comparison/equal_to.hpp>
#include <boost/fusion/container/set/convert.hpp>
#include <boost/type_index.hpp>

/** \file boost/process/error.hpp
 *
 *    Header which provides the error properties. It allows to explicitly set the error handling, the properties are:
 *
\xmlonly
<programlisting>
namespace boost {
  namespace process {
    <emphasis>unspecified</emphasis> <globalname alt="boost::process::ignore_error">ignore_error</globalname>;
    <emphasis>unspecified</emphasis> <globalname alt="boost::process::throw_on_error">throw_on_error</globalname>;
    <emphasis>unspecified</emphasis> <globalname alt="boost::process::error">error</globalname>;
    <emphasis>unspecified</emphasis> <globalname alt="boost::process::error_ref">error_ref</globalname>;
    <emphasis>unspecified</emphasis> <globalname alt="boost::process::error_code">error_code</globalname>;
  }
}
</programlisting>
\endxmlonly
 *     For error there are two aliases: error_ref and error_code
 */

namespace boost { namespace process {

namespace detail {

struct throw_on_error_ : ::boost::process::detail::api::handler_base_ext
{
    constexpr throw_on_error_() {};

    template <class Executor>
    void on_error(Executor&, const std::error_code & ec) const
    {
        throw process_error(ec, "process creation failed");
    }

    const throw_on_error_ &operator()() const {return *this;}
};

struct ignore_error_ : ::boost::process::detail::api::handler_base_ext
{
    constexpr ignore_error_() {};
};

struct set_on_error : ::boost::process::detail::api::handler_base_ext
{
    set_on_error(const set_on_error&) = default;
    explicit set_on_error(std::error_code &ec) : ec_(ec) {}

    template <class Executor>
    void on_error(Executor&, const std::error_code & ec) const
    {
        ec_ = ec;
    }

private:
    std::error_code &ec_;
};

struct error_
{
    constexpr error_() {}
    set_on_error operator()(std::error_code &ec) const {return set_on_error(ec);}
    set_on_error operator= (std::error_code &ec) const {return set_on_error(ec);}

};


template<typename T>
struct is_error_handler : std::false_type {};

template<> struct is_error_handler<set_on_error>    : std::true_type {};
template<> struct is_error_handler<throw_on_error_> : std::true_type {};
template<> struct is_error_handler<ignore_error_>   : std::true_type {};



template<typename Iterator, typename End>
struct has_error_handler_impl
{
    typedef typename boost::fusion::result_of::deref<Iterator>::type ref_type;
    typedef typename std::remove_reference<ref_type>::type res_type_;
    typedef typename std::remove_cv<res_type_>::type res_type;
    typedef typename is_error_handler<res_type>::type cond;

    typedef typename boost::fusion::result_of::next<Iterator>::type next_itr;
    typedef typename has_error_handler_impl<next_itr, End>::type next;

    typedef typename boost::mpl::or_<cond, next>::type type;
};

template<typename Iterator>
struct has_error_handler_impl<Iterator, Iterator>
{
    typedef boost::mpl::false_ type;
};


template<typename Sequence>
struct has_error_handler
{
    typedef typename boost::fusion::result_of::as_vector<Sequence>::type vector_type;

    typedef typename has_error_handler_impl<
            typename boost::fusion::result_of::begin<vector_type>::type,
            typename boost::fusion::result_of::end<  vector_type>::type
            >::type type;
};

template<typename Sequence>
struct has_ignore_error
{
    typedef typename boost::fusion::result_of::as_set<Sequence>::type set_type;
    typedef typename boost::fusion::result_of::has_key<set_type, ignore_error_>::type  type1;
    typedef typename boost::fusion::result_of::has_key<set_type, ignore_error_&>::type type2;
    typedef typename boost::fusion::result_of::has_key<set_type, const ignore_error_&>::type type3;
    typedef typename boost::mpl::or_<type1,type2, type3>::type type;
};

struct error_builder
{
    std::error_code *err;
    typedef set_on_error result_type;
    set_on_error get_initializer() {return set_on_error(*err);};
    void operator()(std::error_code & ec) {err = &ec;};
};

template<>
struct initializer_tag<std::error_code>
{
    typedef error_tag type;
};


template<>
struct initializer_builder<error_tag>
{
    typedef error_builder type;
};

}
/**The ignore_error property will disable any error handling. This can be useful
on linux, where error handling will require a pipe.*/
constexpr boost::process::detail::ignore_error_ ignore_error;
/**The throw_on_error property will enable the exception when launching a process.
It is unnecessary by default, but may be used, when an additional error_code is provided.*/
constexpr boost::process::detail::throw_on_error_ throw_on_error;
/**
The error property will set the executor to handle any errors by setting an
[std::error_code](http://en.cppreference.com/w/cpp/error/error_code).

\code{.cpp}
std::error_code ec;
system("gcc", error(ec));
\endcode

The following syntax is valid:

\code{.cpp}
error(ec);
error=ec;
\endcode

The overload version is achieved by just passing an object of
 [std::error_code](http://en.cppreference.com/w/cpp/error/error_code) to the function.


 */
constexpr boost::process::detail::error_ error;
///Alias for \xmlonly <globalname alt="boost::process::error">error</globalname> \endxmlonly .
constexpr boost::process::detail::error_ error_ref;
///Alias for \xmlonly <globalname alt="boost::process::error">error</globalname> \endxmlonly .
constexpr boost::process::detail::error_ error_code;


}}

#endif