]>
git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/leaf/examples/print_file/print_file_eh.cpp
1 // Copyright (c) 2018-2020 Emil Dotchevski and Reverge Studios, Inc.
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)
6 // This is the program presented in https://boostorg.github.io/leaf/#introduction-eh.
8 // It reads a text file in a buffer and prints it to std::cout, using LEAF to handle errors.
9 // This version uses exception handling. The version that does not use exception
10 // handling is in print_file_result.cpp.
12 #include <boost/leaf/exception.hpp>
13 #include <boost/leaf/handle_errors.hpp>
14 #include <boost/leaf/pred.hpp>
15 #include <boost/leaf/on_error.hpp>
16 #include <boost/leaf/common.hpp>
21 namespace leaf
= boost::leaf
;
24 // Exception type hierarchy.
25 struct bad_command_line
: std::exception
{ };
26 struct input_error
: std::exception
{ };
27 struct open_error
: input_error
{ };
28 struct read_error
: input_error
{ };
29 struct size_error
: input_error
{ };
30 struct eof_error
: input_error
{ };
31 struct output_error
: std::exception
{ };
34 // We will handle all failures in our main function, but first, here are the declarations of the functions it calls, each
35 // communicating failures by throwing exceptions
37 // Parse the command line, return the file name.
38 char const * parse_command_line( int argc
, char const * argv
[] );
40 // Open a file for reading.
41 std::shared_ptr
<FILE> file_open( char const * file_name
);
43 // Return the size of the file.
44 int file_size( FILE & f
);
46 // Read size bytes from f into buf.
47 void file_read( FILE & f
, void * buf
, int size
);
50 // The main function, which handles all errors.
51 int main( int argc
, char const * argv
[] )
53 return leaf::try_catch(
57 char const * file_name
= parse_command_line(argc
,argv
);
59 auto load
= leaf::on_error( leaf::e_file_name
{file_name
} );
61 std::shared_ptr
<FILE> f
= file_open(file_name
);
63 int s
= file_size(*f
);
65 std::string
buffer(1 + s
, '\0');
66 file_read(*f
, &buffer
[0], buffer
.size()-1);
70 if( std::cout
.fail() )
71 throw leaf::exception(output_error
{}, leaf::e_errno
{errno
});
76 // Each of the lambdas below is an error handler. LEAF will consider them, in order, and call the first one that matches
77 // the available error objects.
79 // This handler will be called if the error includes:
80 // - a caught exception of type open_error, and
81 // - an object of type leaf::e_errno that has .value equal to ENOENT, and
82 // - an object of type leaf::e_file_name.
83 []( open_error
&, leaf::match_value
<leaf::e_errno
, ENOENT
>, leaf::e_file_name
const & fn
)
85 std::cerr
<< "File not found: " << fn
.value
<< std::endl
;
89 // This handler will be called if the error includes:
90 // - a caught exception of type open_error, and
91 // - an object of type leaf::e_errno (regardless of its .value), and
92 // - an object of type leaf::e_file_name.
93 []( open_error
&, leaf::e_errno
const & errn
, leaf::e_file_name
const & fn
)
95 std::cerr
<< "Failed to open " << fn
.value
<< ", errno=" << errn
<< std::endl
;
99 // This handler will be called if the error includes:
100 // - a caught exception of type input_error, and
101 // - an optional object of type leaf::e_errno (regardless of its .value), and
102 // - an object of type leaf::e_file_name.
103 []( input_error
&, leaf::e_errno
const * errn
, leaf::e_file_name
const & fn
)
105 std::cerr
<< "Failed to access " << fn
.value
;
107 std::cerr
<< ", errno=" << *errn
;
108 std::cerr
<< std::endl
;
112 // This handler will be called if the error includes:
113 // - a caught exception of type std::ostream::failure, and
114 // - an object of type leaf::e_errno (regardless of its .value),
115 []( output_error
&, leaf::e_errno
const & errn
)
117 std::cerr
<< "Output error, errno=" << errn
<< std::endl
;
121 // This handler will be called if we've got a bad_command_line
122 []( bad_command_line
& )
124 std::cout
<< "Bad command line argument" << std::endl
;
128 // This last handler matches any error: it prints diagnostic information to help debug logic errors in the program, since it
129 // failed to match an appropriate error handler to the error condition it encountered. In this program this handler will
131 []( leaf::error_info
const & unmatched
)
134 "Unknown failure detected" << std::endl
<<
135 "Cryptic diagnostic information follows" << std::endl
<<
142 // Implementations of the functions called by main:
145 // Parse the command line, return the file name.
146 char const * parse_command_line( int argc
, char const * argv
[] )
151 throw leaf::exception(bad_command_line
{});
155 // Open a file for reading.
156 std::shared_ptr
<FILE> file_open( char const * file_name
)
158 if( FILE * f
= fopen(file_name
, "rb") )
159 return std::shared_ptr
<FILE>(f
, &fclose
);
161 throw leaf::exception(open_error
{}, leaf::e_errno
{errno
});
165 // Return the size of the file.
166 int file_size( FILE & f
)
168 auto load
= leaf::on_error([] { return leaf::e_errno
{errno
}; });
170 if( fseek(&f
, 0, SEEK_END
) )
171 throw leaf::exception(size_error
{});
175 throw leaf::exception(size_error
{});
177 if( fseek(&f
,0,SEEK_SET
) )
178 throw leaf::exception(size_error
{});
184 // Read size bytes from f into buf.
185 void file_read( FILE & f
, void * buf
, int size
)
187 int n
= fread(buf
, 1, size
, &f
);
190 throw leaf::exception(read_error
{}, leaf::e_errno
{errno
});
193 throw leaf::exception(eof_error
{});