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