]>
git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/leaf/examples/print_file/print_file_result.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-result.
8 // It reads a text file in a buffer and prints it to std::cout, using LEAF to handle errors.
9 // This version does not use exception handling. The version that does use exception
10 // handling is in print_file_eh.cpp.
12 #include <boost/leaf/result.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 // First, we need an enum to define our error codes:
37 using result
= leaf::result
<T
>;
40 // We will handle all failures in our main function, but first, here are the declarations of the functions it calls, each
41 // communicating failures using result<T>:
43 // Parse the command line, return the file name.
44 result
<char const *> parse_command_line( int argc
, char const * argv
[] );
46 // Open a file for reading.
47 result
<std::shared_ptr
<FILE>> file_open( char const * file_name
);
49 // Return the size of the file.
50 result
<int> file_size( FILE & f
);
52 // Read size bytes from f into buf.
53 result
<void> file_read( FILE & f
, void * buf
, int size
);
56 // The main function, which handles all errors.
57 int main( int argc
, char const * argv
[] )
59 return leaf::try_handle_all(
63 BOOST_LEAF_AUTO(file_name
, parse_command_line(argc
,argv
));
65 auto load
= leaf::on_error( leaf::e_file_name
{file_name
} );
67 BOOST_LEAF_AUTO(f
, file_open(file_name
));
69 BOOST_LEAF_AUTO(s
, file_size(*f
));
71 std::string
buffer(1 + s
, '\0');
72 BOOST_LEAF_CHECK(file_read(*f
, &buffer
[0], buffer
.size()-1));
76 if( std::cout
.fail() )
77 return leaf::new_error(output_error
, leaf::e_errno
{errno
});
82 // Each of the lambdas below is an error handler. LEAF will consider them, in order, and call the first one that matches
83 // the available error objects.
85 // This handler will be called if the error includes:
86 // - an object of type error_code equal to open_error, and
87 // - an object of type leaf::e_errno that has .value equal to ENOENT, and
88 // - an object of type leaf::e_file_name.
89 []( leaf::match
<error_code
, open_error
>, leaf::match_value
<leaf::e_errno
, ENOENT
>, leaf::e_file_name
const & fn
)
91 std::cerr
<< "File not found: " << fn
.value
<< std::endl
;
95 // This handler will be called if the error includes:
96 // - an object of type error_code equal to open_error, and
97 // - an object of type leaf::e_errno (regardless of its .value), and
98 // - an object of type leaf::e_file_name.
99 []( leaf::match
<error_code
, open_error
>, leaf::e_errno
const & errn
, leaf::e_file_name
const & fn
)
101 std::cerr
<< "Failed to open " << fn
.value
<< ", errno=" << errn
<< std::endl
;
105 // This handler will be called if the error includes:
106 // - an object of type error_code equal to any of size_error, read_error, eof_error, and
107 // - an optional object of type leaf::e_errno (regardless of its .value), and
108 // - an object of type leaf::e_file_name.
109 []( leaf::match
<error_code
, size_error
, read_error
, eof_error
>, leaf::e_errno
const * errn
, leaf::e_file_name
const & fn
)
111 std::cerr
<< "Failed to access " << fn
.value
;
113 std::cerr
<< ", errno=" << *errn
;
114 std::cerr
<< std::endl
;
118 // This handler will be called if the error includes:
119 // - an object of type error_code equal to output_error, and
120 // - an object of type leaf::e_errno (regardless of its .value),
121 []( leaf::match
<error_code
, output_error
>, leaf::e_errno
const & errn
)
123 std::cerr
<< "Output error, errno=" << errn
<< std::endl
;
127 // This handler will be called if we've got a bad_command_line
128 []( leaf::match
<error_code
, bad_command_line
> )
130 std::cout
<< "Bad command line argument" << std::endl
;
134 // This last handler matches any error: it prints diagnostic information to help debug logic errors in the program, since it
135 // failed to match an appropriate error handler to the error condition it encountered. In this program this handler will
137 []( leaf::error_info
const & unmatched
)
140 "Unknown failure detected" << std::endl
<<
141 "Cryptic diagnostic information follows" << std::endl
<<
148 // Implementations of the functions called by main:
151 // Parse the command line, return the file name.
152 result
<char const *> parse_command_line( int argc
, char const * argv
[] )
157 return leaf::new_error(bad_command_line
);
161 // Open a file for reading.
162 result
<std::shared_ptr
<FILE>> file_open( char const * file_name
)
164 if( FILE * f
= fopen(file_name
, "rb") )
165 return std::shared_ptr
<FILE>(f
, &fclose
);
167 return leaf::new_error(open_error
, leaf::e_errno
{errno
});
171 // Return the size of the file.
172 result
<int> file_size( FILE & f
)
174 auto load
= leaf::on_error([] { return leaf::e_errno
{errno
}; });
176 if( fseek(&f
, 0, SEEK_END
) )
177 return leaf::new_error(size_error
);
181 return leaf::new_error(size_error
);
183 if( fseek(&f
,0,SEEK_SET
) )
184 return leaf::new_error(size_error
);
190 // Read size bytes from f into buf.
191 result
<void> file_read( FILE & f
, void * buf
, int size
)
193 int n
= fread(buf
, 1, size
, &f
);
196 return leaf::new_error(read_error
, leaf::e_errno
{errno
});
199 return leaf::new_error(eof_error
);
204 ////////////////////////////////////////
206 #ifdef BOOST_LEAF_NO_EXCEPTIONS
210 BOOST_LEAF_NORETURN
void throw_exception( std::exception
const & e
)
212 std::cerr
<< "Terminating due to a C++ exception under BOOST_LEAF_NO_EXCEPTIONS: " << e
.what();
216 struct source_location
;
217 BOOST_LEAF_NORETURN
void throw_exception( std::exception
const & e
, boost::source_location
const & )