]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/leaf/examples/print_file/print_file_eh_error_tags.cpp
buildsys: change download over to reef release
[ceph.git] / ceph / src / boost / libs / leaf / examples / print_file / print_file_eh_error_tags.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-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 uses exception handling. The version that does not use exception
10 // handling is in print_file_result.cpp.
11
12 #include <boost/leaf/exception.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 // Error types
25 struct bad_command_line { };
26 struct input_error { };
27 struct open_error { };
28 struct read_error { };
29 struct size_error { };
30 struct eof_error { };
31 struct output_error { };
32
33
34 // We will handle all failures in our main function, but first, here are the declarations of the functions it calls, each
35 // communicating failures by throwing exceptions
36
37 // Parse the command line, return the file name.
38 char const * parse_command_line( int argc, char const * argv[] );
39
40 // Open a file for reading.
41 std::shared_ptr<FILE> file_open( char const * file_name );
42
43 // Return the size of the file.
44 int file_size( FILE & f );
45
46 // Read size bytes from f into buf.
47 void file_read( FILE & f, void * buf, int size );
48
49
50 // The main function, which handles all errors.
51 int main( int argc, char const * argv[] )
52 {
53 return leaf::try_catch(
54
55 [&]
56 {
57 char const * file_name = parse_command_line(argc,argv);
58
59 auto load = leaf::on_error( leaf::e_file_name{file_name} );
60
61 std::shared_ptr<FILE> f = file_open(file_name);
62
63 int s = file_size(*f);
64
65 std::string buffer(1 + s, '\0');
66 file_read(*f, &buffer[0], buffer.size()-1);
67
68 std::cout << buffer;
69 std::cout.flush();
70 if( std::cout.fail() )
71 throw leaf::exception(output_error{}, leaf::e_errno{errno});
72
73 return 0;
74 },
75
76 // Each of the lambdas below is an error handler. LEAF will consider them, in order, and call the first one that matches
77 // the available error objects.
78
79 // This handler will be called if the error includes:
80 // - an object of type open_error, and
81 // - an object of type leaf::e_errno that has .value equal to ENOENT, and
82 // - an object of type leaf::e_file_name.
83 []( open_error &, leaf::match_value<leaf::e_errno, ENOENT>, leaf::e_file_name const & fn )
84 {
85 std::cerr << "File not found: " << fn.value << std::endl;
86 return 1;
87 },
88
89 // This handler will be called if the error includes:
90 // - an object of type open_error, and
91 // - an object of type leaf::e_errno (regardless of its .value), and
92 // - an object of type leaf::e_file_name.
93 []( open_error &, leaf::e_errno const & errn, leaf::e_file_name const & fn )
94 {
95 std::cerr << "Failed to open " << fn.value << ", errno=" << errn << std::endl;
96 return 2;
97 },
98
99 // This handler will be called if the error includes:
100 // - an object of type input_error, and
101 // - an optional object of type leaf::e_errno (regardless of its .value), and
102 // - an object of type leaf::e_file_name.
103 []( input_error &, leaf::e_errno const * errn, leaf::e_file_name const & fn )
104 {
105 std::cerr << "Failed to access " << fn.value;
106 if( errn )
107 std::cerr << ", errno=" << *errn;
108 std::cerr << std::endl;
109 return 3;
110 },
111
112 // This handler will be called if the error includes:
113 // - an object of type output_error, and
114 // - an object of type leaf::e_errno (regardless of its .value),
115 []( output_error &, leaf::e_errno const & errn )
116 {
117 std::cerr << "Output error, errno=" << errn << std::endl;
118 return 4;
119 },
120
121 // This handler will be called if we've got a bad_command_line
122 []( bad_command_line & )
123 {
124 std::cout << "Bad command line argument" << std::endl;
125 return 5;
126 },
127
128 // This last handler matches any error: it prints diagnostic information to help debug logic errors in the program, since it
129 // failed to match an appropriate error handler to the error condition it encountered. In this program this handler will
130 // never be called.
131 []( leaf::error_info const & unmatched )
132 {
133 std::cerr <<
134 "Unknown failure detected" << std::endl <<
135 "Cryptic diagnostic information follows" << std::endl <<
136 unmatched;
137 return 6;
138 } );
139 }
140
141
142 // Implementations of the functions called by main:
143
144
145 // Parse the command line, return the file name.
146 char const * parse_command_line( int argc, char const * argv[] )
147 {
148 if( argc==2 )
149 return argv[1];
150 else
151 throw leaf::exception(bad_command_line{});
152 }
153
154
155 // Open a file for reading.
156 std::shared_ptr<FILE> file_open( char const * file_name )
157 {
158 auto load = leaf::on_error(input_error{});
159
160 if( FILE * f = fopen(file_name, "rb") )
161 return std::shared_ptr<FILE>(f, &fclose);
162 else
163 throw leaf::exception(open_error{}, leaf::e_errno{errno});
164 }
165
166
167 // Return the size of the file.
168 int file_size( FILE & f )
169 {
170 auto load = leaf::on_error(input_error{}, size_error{}, []{ return leaf::e_errno{errno}; });
171
172 if( fseek(&f, 0, SEEK_END) )
173 throw leaf::exception();
174
175 int s = ftell(&f);
176 if( s==-1L )
177 throw leaf::exception();
178
179 if( fseek(&f,0,SEEK_SET) )
180 throw leaf::exception();
181
182 return s;
183 }
184
185
186 // Read size bytes from f into buf.
187 void file_read( FILE & f, void * buf, int size )
188 {
189 auto load = leaf::on_error(input_error{});
190
191 int n = fread(buf, 1, size, &f);
192
193 if( ferror(&f) )
194 throw leaf::exception(read_error{}, leaf::e_errno{errno});
195
196 if( n!=size )
197 throw leaf::exception(eof_error{});
198 }