]> git.proxmox.com Git - ceph.git/blame - 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
CommitLineData
1e59de90 1// Copyright 2018-2022 Emil Dotchevski and Reverge Studios, Inc.
20effc67
TL
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
1e59de90
TL
6// This is the program presented in
7// https://boostorg.github.io/leaf/#introduction-result.
20effc67 8
1e59de90
TL
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.
20effc67 12
1e59de90 13#include <boost/leaf.hpp>
20effc67 14#include <iostream>
20effc67
TL
15#include <stdio.h>
16
17namespace leaf = boost::leaf;
18
19
20// First, we need an enum to define our error codes:
21enum 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
32template <class T>
33using result = leaf::result<T>;
34
35
1e59de90
TL
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>:
20effc67
TL
39
40// Parse the command line, return the file name.
41result<char const *> parse_command_line( int argc, char const * argv[] );
42
43// Open a file for reading.
44result<std::shared_ptr<FILE>> file_open( char const * file_name );
45
46// Return the size of the file.
47result<int> file_size( FILE & f );
48
49// Read size bytes from f into buf.
50result<void> file_read( FILE & f, void * buf, int size );
51
52
53// The main function, which handles all errors.
54int 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
1e59de90
TL
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.
20effc67
TL
82
83 // This handler will be called if the error includes:
84 // - an object of type error_code equal to open_error, and
1e59de90
TL
85 // - an object of type leaf::e_errno that has .value equal to ENOENT,
86 // and
20effc67
TL
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:
1e59de90
TL
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
20effc67
TL
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
1e59de90
TL
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.
20effc67
TL
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.
154result<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.
164result<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.
174result<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.
193result<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
210namespace 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