]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/leaf/example/print_file/print_file_result.cpp
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / boost / libs / leaf / example / print_file / print_file_result.cpp
1 // Copyright 2018-2022 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
7 // https://boostorg.github.io/leaf/#introduction-result.
8
9 // It reads a text file in a buffer and prints it to std::cout, using LEAF to
10 // handle errors. This version does not use exception handling. The version that
11 // does use exception handling is in print_file_eh.cpp.
12
13 #include <boost/leaf.hpp>
14 #include <iostream>
15 #include <stdio.h>
16
17 namespace leaf = boost::leaf;
18
19
20 // First, we need an enum to define our error codes:
21 enum error_code
22 {
23 bad_command_line = 1,
24 open_error,
25 read_error,
26 size_error,
27 eof_error,
28 output_error
29 };
30
31
32 template <class T>
33 using result = leaf::result<T>;
34
35
36 // We will handle all failures in our main function, but first, here are the
37 // declarations of the functions it calls, each communicating failures using
38 // result<T>:
39
40 // Parse the command line, return the file name.
41 result<char const *> parse_command_line( int argc, char const * argv[] );
42
43 // Open a file for reading.
44 result<std::shared_ptr<FILE>> file_open( char const * file_name );
45
46 // Return the size of the file.
47 result<int> file_size( FILE & f );
48
49 // Read size bytes from f into buf.
50 result<void> file_read( FILE & f, void * buf, int size );
51
52
53 // The main function, which handles all errors.
54 int main( int argc, char const * argv[] )
55 {
56 return leaf::try_handle_all(
57
58 [&]() -> result<int>
59 {
60 BOOST_LEAF_AUTO(file_name, parse_command_line(argc,argv));
61
62 auto load = leaf::on_error( leaf::e_file_name{file_name} );
63
64 BOOST_LEAF_AUTO(f, file_open(file_name));
65
66 BOOST_LEAF_AUTO(s, file_size(*f));
67
68 std::string buffer(1 + s, '\0');
69 BOOST_LEAF_CHECK(file_read(*f, &buffer[0], buffer.size()-1));
70
71 std::cout << buffer;
72 std::cout.flush();
73 if( std::cout.fail() )
74 return leaf::new_error(output_error, leaf::e_errno{errno});
75
76 return 0;
77 },
78
79 // Each of the lambdas below is an error handler. LEAF will consider
80 // them, in order, and call the first one that matches the available
81 // error objects.
82
83 // This handler will be called if the error includes:
84 // - an object of type error_code equal to open_error, and
85 // - an object of type leaf::e_errno that has .value equal to ENOENT,
86 // and
87 // - an object of type leaf::e_file_name.
88 []( leaf::match<error_code, open_error>, leaf::match_value<leaf::e_errno, ENOENT>, leaf::e_file_name const & fn )
89 {
90 std::cerr << "File not found: " << fn.value << std::endl;
91 return 1;
92 },
93
94 // This handler will be called if the error includes:
95 // - an object of type error_code equal to open_error, and
96 // - an object of type leaf::e_errno (regardless of its .value), and
97 // - an object of type leaf::e_file_name.
98 []( leaf::match<error_code, open_error>, leaf::e_errno const & errn, leaf::e_file_name const & fn )
99 {
100 std::cerr << "Failed to open " << fn.value << ", errno=" << errn << std::endl;
101 return 2;
102 },
103
104 // This handler will be called if the error includes:
105 // - an object of type error_code equal to any of size_error,
106 // read_error, eof_error, and
107 // - an optional object of type leaf::e_errno (regardless of its
108 // .value), and
109 // - an object of type leaf::e_file_name.
110 []( leaf::match<error_code, size_error, read_error, eof_error>, leaf::e_errno const * errn, leaf::e_file_name const & fn )
111 {
112 std::cerr << "Failed to access " << fn.value;
113 if( errn )
114 std::cerr << ", errno=" << *errn;
115 std::cerr << std::endl;
116 return 3;
117 },
118
119 // This handler will be called if the error includes:
120 // - an object of type error_code equal to output_error, and
121 // - an object of type leaf::e_errno (regardless of its .value),
122 []( leaf::match<error_code, output_error>, leaf::e_errno const & errn )
123 {
124 std::cerr << "Output error, errno=" << errn << std::endl;
125 return 4;
126 },
127
128 // This handler will be called if we've got a bad_command_line
129 []( leaf::match<error_code, bad_command_line> )
130 {
131 std::cout << "Bad command line argument" << std::endl;
132 return 5;
133 },
134
135 // This last handler matches any error: it prints diagnostic information
136 // to help debug logic errors in the program, since it failed to match
137 // an appropriate error handler to the error condition it encountered.
138 // In this program this handler will never be called.
139 []( leaf::error_info const & unmatched )
140 {
141 std::cerr <<
142 "Unknown failure detected" << std::endl <<
143 "Cryptic diagnostic information follows" << std::endl <<
144 unmatched;
145 return 6;
146 } );
147 }
148
149
150 // Implementations of the functions called by main:
151
152
153 // Parse the command line, return the file name.
154 result<char const *> parse_command_line( int argc, char const * argv[] )
155 {
156 if( argc==2 )
157 return argv[1];
158 else
159 return leaf::new_error(bad_command_line);
160 }
161
162
163 // Open a file for reading.
164 result<std::shared_ptr<FILE>> file_open( char const * file_name )
165 {
166 if( FILE * f = fopen(file_name, "rb") )
167 return std::shared_ptr<FILE>(f, &fclose);
168 else
169 return leaf::new_error(open_error, leaf::e_errno{errno});
170 }
171
172
173 // Return the size of the file.
174 result<int> file_size( FILE & f )
175 {
176 auto load = leaf::on_error([] { return leaf::e_errno{errno}; });
177
178 if( fseek(&f, 0, SEEK_END) )
179 return leaf::new_error(size_error);
180
181 int s = ftell(&f);
182 if( s==-1L )
183 return leaf::new_error(size_error);
184
185 if( fseek(&f,0,SEEK_SET) )
186 return leaf::new_error(size_error);
187
188 return s;
189 }
190
191
192 // Read size bytes from f into buf.
193 result<void> file_read( FILE & f, void * buf, int size )
194 {
195 int n = fread(buf, 1, size, &f);
196
197 if( ferror(&f) )
198 return leaf::new_error(read_error, leaf::e_errno{errno});
199
200 if( n!=size )
201 return leaf::new_error(eof_error);
202
203 return { };
204 }
205
206 ////////////////////////////////////////
207
208 #ifdef BOOST_LEAF_NO_EXCEPTIONS
209
210 namespace boost
211 {
212 BOOST_LEAF_NORETURN void throw_exception( std::exception const & e )
213 {
214 std::cerr << "Terminating due to a C++ exception under BOOST_LEAF_NO_EXCEPTIONS: " << e.what();
215 std::terminate();
216 }
217
218 struct source_location;
219 BOOST_LEAF_NORETURN void throw_exception( std::exception const & e, boost::source_location const & )
220 {
221 throw_exception(e);
222 }
223 }
224
225 #endif