]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/leaf/examples/print_file/print_file_result.cpp
buildsys: change download over to reef release
[ceph.git] / ceph / src / boost / libs / leaf / examples / print_file / print_file_result.cpp
1 // Copyright (c) 2018-2020 Emil Dotchevski and Reverge Studios, Inc.
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 // This is the program presented in https://boostorg.github.io/leaf/#introduction-result.
7
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.
11
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>
17 #include <iostream>
18 #include <memory>
19 #include <stdio.h>
20
21 namespace leaf = boost::leaf;
22
23
24 // First, we need an enum to define our error codes:
25 enum error_code
26 {
27 bad_command_line = 1,
28 open_error,
29 read_error,
30 size_error,
31 eof_error,
32 output_error
33 };
34
35
36 template <class T>
37 using result = leaf::result<T>;
38
39
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>:
42
43 // Parse the command line, return the file name.
44 result<char const *> parse_command_line( int argc, char const * argv[] );
45
46 // Open a file for reading.
47 result<std::shared_ptr<FILE>> file_open( char const * file_name );
48
49 // Return the size of the file.
50 result<int> file_size( FILE & f );
51
52 // Read size bytes from f into buf.
53 result<void> file_read( FILE & f, void * buf, int size );
54
55
56 // The main function, which handles all errors.
57 int main( int argc, char const * argv[] )
58 {
59 return leaf::try_handle_all(
60
61 [&]() -> result<int>
62 {
63 BOOST_LEAF_AUTO(file_name, parse_command_line(argc,argv));
64
65 auto load = leaf::on_error( leaf::e_file_name{file_name} );
66
67 BOOST_LEAF_AUTO(f, file_open(file_name));
68
69 BOOST_LEAF_AUTO(s, file_size(*f));
70
71 std::string buffer(1 + s, '\0');
72 BOOST_LEAF_CHECK(file_read(*f, &buffer[0], buffer.size()-1));
73
74 std::cout << buffer;
75 std::cout.flush();
76 if( std::cout.fail() )
77 return leaf::new_error(output_error, leaf::e_errno{errno});
78
79 return 0;
80 },
81
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.
84
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 )
90 {
91 std::cerr << "File not found: " << fn.value << std::endl;
92 return 1;
93 },
94
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 )
100 {
101 std::cerr << "Failed to open " << fn.value << ", errno=" << errn << std::endl;
102 return 2;
103 },
104
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 )
110 {
111 std::cerr << "Failed to access " << fn.value;
112 if( errn )
113 std::cerr << ", errno=" << *errn;
114 std::cerr << std::endl;
115 return 3;
116 },
117
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 )
122 {
123 std::cerr << "Output error, errno=" << errn << std::endl;
124 return 4;
125 },
126
127 // This handler will be called if we've got a bad_command_line
128 []( leaf::match<error_code, bad_command_line> )
129 {
130 std::cout << "Bad command line argument" << std::endl;
131 return 5;
132 },
133
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
136 // never be called.
137 []( leaf::error_info const & unmatched )
138 {
139 std::cerr <<
140 "Unknown failure detected" << std::endl <<
141 "Cryptic diagnostic information follows" << std::endl <<
142 unmatched;
143 return 6;
144 } );
145 }
146
147
148 // Implementations of the functions called by main:
149
150
151 // Parse the command line, return the file name.
152 result<char const *> parse_command_line( int argc, char const * argv[] )
153 {
154 if( argc==2 )
155 return argv[1];
156 else
157 return leaf::new_error(bad_command_line);
158 }
159
160
161 // Open a file for reading.
162 result<std::shared_ptr<FILE>> file_open( char const * file_name )
163 {
164 if( FILE * f = fopen(file_name, "rb") )
165 return std::shared_ptr<FILE>(f, &fclose);
166 else
167 return leaf::new_error(open_error, leaf::e_errno{errno});
168 }
169
170
171 // Return the size of the file.
172 result<int> file_size( FILE & f )
173 {
174 auto load = leaf::on_error([] { return leaf::e_errno{errno}; });
175
176 if( fseek(&f, 0, SEEK_END) )
177 return leaf::new_error(size_error);
178
179 int s = ftell(&f);
180 if( s==-1L )
181 return leaf::new_error(size_error);
182
183 if( fseek(&f,0,SEEK_SET) )
184 return leaf::new_error(size_error);
185
186 return s;
187 }
188
189
190 // Read size bytes from f into buf.
191 result<void> file_read( FILE & f, void * buf, int size )
192 {
193 int n = fread(buf, 1, size, &f);
194
195 if( ferror(&f) )
196 return leaf::new_error(read_error, leaf::e_errno{errno});
197
198 if( n!=size )
199 return leaf::new_error(eof_error);
200
201 return { };
202 }
203
204 ////////////////////////////////////////
205
206 #ifdef BOOST_LEAF_NO_EXCEPTIONS
207
208 namespace boost
209 {
210 BOOST_LEAF_NORETURN void throw_exception( std::exception const & e )
211 {
212 std::cerr << "Terminating due to a C++ exception under BOOST_LEAF_NO_EXCEPTIONS: " << e.what();
213 std::terminate();
214 }
215
216 struct source_location;
217 BOOST_LEAF_NORETURN void throw_exception( std::exception const & e, boost::source_location const & )
218 {
219 throw_exception(e);
220 }
221 }
222
223 #endif