1 //Copyright (c) 2006-2009 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 program simulates errors on copying simple data files. It demonstrates
7 //typical Boost Exception usage.
8
9 //The output from this program can vary depending on the platform.
10
11 #include <boost/throw_exception.hpp>
12 #include <boost/exception/info.hpp>
13 #include <boost/exception/get_error_info.hpp>
14 #include <boost/exception/diagnostic_information.hpp>
15 #include <boost/exception/errinfo_file_open_mode.hpp>
16 #include <boost/exception/errinfo_file_handle.hpp>
17 #include <boost/exception/errinfo_file_name.hpp>
18 #include <boost/exception/errinfo_api_function.hpp>
19 #include <boost/exception/errinfo_errno.hpp>
20 #include <boost/shared_ptr.hpp>
21 #include <boost/weak_ptr.hpp>
22 #include <iostream>
23
24 typedef boost::error_info<struct tag_file_name_src,std::string> errinfo_src_file_name;
25 typedef boost::error_info<struct tag_file_name_dst,std::string> errinfo_dst_file_name;
26
27 char const data[] = "example";
28 size_t const data_size = sizeof(data);
29
30 class
31 error: //Base for all exception objects we throw.
32 public virtual std::exception,
33 public virtual boost::exception
34 {
35 public:
36
37 char const *
what() const38 what() const BOOST_NOEXCEPT_OR_NOTHROW
39 {
40 return "example_io error";
41 }
42
43 protected:
44
~error()45 ~error() BOOST_NOEXCEPT_OR_NOTHROW
46 {
47 }
48 };
49
50 struct open_error: virtual error { };
51 struct read_error: virtual error { };
52 struct write_error: virtual error { };
53 struct fopen_error: virtual open_error { };
54 struct fread_error: virtual read_error { };
55 struct fwrite_error: virtual write_error { };
56
57 boost::shared_ptr<FILE>
my_fopen(char const * name,char const * mode)58 my_fopen( char const * name, char const * mode )
59 {
60 if( FILE * f = ::fopen(name,mode) )
61 return boost::shared_ptr<FILE>(f,fclose);
62 else
63 BOOST_THROW_EXCEPTION(fopen_error() <<
64 boost::errinfo_errno (errno) <<
65 boost::errinfo_file_name(name) <<
66 boost::errinfo_file_open_mode(mode) <<
67 boost::errinfo_api_function("fopen"));
68 }
69
70 void
my_fread(void * buffer,size_t size,size_t count,boost::shared_ptr<FILE> const & stream)71 my_fread( void * buffer, size_t size, size_t count, boost::shared_ptr<FILE> const & stream )
72 {
73 assert(stream);
74 if( count!=fread(buffer,size,count,stream.get()) || ferror(stream.get()) )
75 BOOST_THROW_EXCEPTION(fread_error() <<
76 boost::errinfo_api_function("fread") <<
77 boost::errinfo_errno(errno) <<
78 boost::errinfo_file_handle(boost::weak_ptr<FILE>(stream)));
79 }
80
81 void
my_fwrite(void const * buffer,size_t size,size_t count,boost::shared_ptr<FILE> const & stream)82 my_fwrite( void const * buffer, size_t size, size_t count, boost::shared_ptr<FILE> const & stream )
83 {
84 assert(stream);
85 if( count!=fwrite(buffer,size,count,stream.get()) || ferror(stream.get()) )
86 BOOST_THROW_EXCEPTION(fwrite_error() <<
87 boost::errinfo_api_function("fwrite") <<
88 boost::errinfo_errno(errno) <<
89 boost::errinfo_file_handle(boost::weak_ptr<FILE>(stream)));
90 }
91
92 void
reset_file(char const * file_name)93 reset_file( char const * file_name )
94 {
95 (void) my_fopen(file_name,"wb");
96 }
97
98 void
create_data(char const * file_name)99 create_data( char const * file_name )
100 {
101 boost::shared_ptr<FILE> f = my_fopen(file_name,"wb");
102 my_fwrite( data, 1, data_size, f );
103 }
104
105 void
copy_data(char const * src_file_name,char const * dst_file_name)106 copy_data( char const * src_file_name, char const * dst_file_name )
107 {
108 boost::shared_ptr<FILE> src = my_fopen(src_file_name,"rb");
109 boost::shared_ptr<FILE> dst = my_fopen(dst_file_name,"wb");
110 try
111 {
112 char buffer[data_size];
113 my_fread( buffer, 1, data_size, src );
114 my_fwrite( buffer, 1, data_size, dst );
115 }
116 catch(
117 boost::exception & x )
118 {
119 if( boost::weak_ptr<FILE> const * f=boost::get_error_info<boost::errinfo_file_handle>(x) )
120 if( boost::shared_ptr<FILE> fs = f->lock() )
121 {
122 if( fs==src )
123 x << boost::errinfo_file_name(src_file_name);
124 else if( fs==dst )
125 x << boost::errinfo_file_name(dst_file_name);
126 }
127 x <<
128 errinfo_src_file_name(src_file_name) <<
129 errinfo_dst_file_name(dst_file_name);
130 throw;
131 }
132 }
133
134 void
dump_copy_info(boost::exception const & x)135 dump_copy_info( boost::exception const & x )
136 {
137 if( std::string const * src = boost::get_error_info<errinfo_src_file_name>(x) )
138 std::cerr << "Source file name: " << *src << "\n";
139 if( std::string const * dst = boost::get_error_info<errinfo_dst_file_name>(x) )
140 std::cerr << "Destination file name: " << *dst << "\n";
141 }
142
143 void
dump_file_info(boost::exception const & x)144 dump_file_info( boost::exception const & x )
145 {
146 if( std::string const * fn = boost::get_error_info<boost::errinfo_file_name>(x) )
147 std::cerr << "File name: " << *fn << "\n";
148 }
149
150 void
dump_clib_info(boost::exception const & x)151 dump_clib_info( boost::exception const & x )
152 {
153 if( int const * err=boost::get_error_info<boost::errinfo_errno>(x) )
154 std::cerr << "OS error: " << *err << "\n";
155 if( char const * const * fn=boost::get_error_info<boost::errinfo_api_function>(x) )
156 std::cerr << "Failed function: " << *fn << "\n";
157 }
158
159 void
dump_all_info(boost::exception const & x)160 dump_all_info( boost::exception const & x )
161 {
162 std::cerr << "-------------------------------------------------\n";
163 dump_copy_info(x);
164 dump_file_info(x);
165 dump_clib_info(x);
166 std::cerr << "\nOutput from diagnostic_information():\n";
167 std::cerr << diagnostic_information(x);
168 }
169
170 int
main()171 main()
172 {
173 try
174 {
175 create_data( "tmp1.txt" );
176 copy_data( "tmp1.txt", "tmp2.txt" ); //This should succeed.
177
178 reset_file( "tmp1.txt" ); //Creates empty file.
179 try
180 {
181 copy_data( "tmp1.txt", "tmp2.txt" ); //This should fail, tmp1.txt is empty.
182 }
183 catch(
184 read_error & x )
185 {
186 std::cerr << "\nCaught 'read_error' exception.\n";
187 dump_all_info(x);
188 }
189
190 remove( "tmp1.txt" );
191 remove( "tmp2.txt" );
192 try
193 {
194 copy_data( "tmp1.txt", "tmp2.txt" ); //This should fail, tmp1.txt does not exist.
195 }
196 catch(
197 open_error & x )
198 {
199 std::cerr << "\nCaught 'open_error' exception.\n";
200 dump_all_info(x);
201 }
202 }
203 catch(
204 ... )
205 {
206 std::cerr << "\nCaught unexpected exception!\n";
207 std::cerr << boost::current_exception_diagnostic_information();
208 }
209 }
210