Skip to content

Commit 5f24ad7

Browse files
committed
initial commit
0 parents  commit 5f24ad7

7 files changed

Lines changed: 1337 additions & 0 deletions

File tree

Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
#ifndef __STRICT_FSTREAM_HPP
2+
#define __STRICT_FSTREAM_HPP
3+
4+
#include <cassert>
5+
#include <fstream>
6+
#include <cstring>
7+
#include <string>
8+
9+
/**
10+
* This namespace defines wrappers for std::ifstream, std::ofstream, and
11+
* std::fstream objects. The wrappers perform the following steps:
12+
* - check the open modes make sense
13+
* - check that the call to open() is successful
14+
* - (for input streams) check that the opened file is peek-able
15+
* - turn on the badbit in the exception mask
16+
*/
17+
namespace strict_fstream
18+
{
19+
20+
/// Overload of error-reporting function, to enable use with VS.
21+
/// Ref: http://stackoverflow.com/a/901316/717706
22+
static std::string strerror()
23+
{
24+
std::string buff(80, '\0');
25+
#ifdef _WIN32
26+
if (strerror_s(&buff[0], buff.size(), errno) != 0)
27+
{
28+
buff = "Unknown error";
29+
}
30+
#elif (_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && ! _GNU_SOURCE || defined(__APPLE__)
31+
// XSI-compliant strerror_r()
32+
if (strerror_r(errno, &buff[0], buff.size()) != 0)
33+
{
34+
buff = "Unknown error";
35+
}
36+
#else
37+
// GNU-specific strerror_r()
38+
auto p = strerror_r(errno, &buff[0], buff.size());
39+
std::string tmp(p, std::strlen(p));
40+
std::swap(buff, tmp);
41+
#endif
42+
buff.resize(buff.find('\0'));
43+
return buff;
44+
}
45+
46+
/// Exception class thrown by failed operations.
47+
class Exception
48+
: public std::exception
49+
{
50+
public:
51+
Exception(const std::string& msg) : _msg(msg) {}
52+
const char * what() const noexcept { return _msg.c_str(); }
53+
private:
54+
std::string _msg;
55+
}; // class Exception
56+
57+
namespace detail
58+
{
59+
60+
struct static_method_holder
61+
{
62+
static std::string mode_to_string(std::ios_base::openmode mode)
63+
{
64+
static const int n_modes = 6;
65+
static const std::ios_base::openmode mode_val_v[n_modes] =
66+
{
67+
std::ios_base::in,
68+
std::ios_base::out,
69+
std::ios_base::app,
70+
std::ios_base::ate,
71+
std::ios_base::trunc,
72+
std::ios_base::binary
73+
};
74+
75+
static const char * mode_name_v[n_modes] =
76+
{
77+
"in",
78+
"out",
79+
"app",
80+
"ate",
81+
"trunc",
82+
"binary"
83+
};
84+
std::string res;
85+
for (int i = 0; i < n_modes; ++i)
86+
{
87+
if (mode & mode_val_v[i])
88+
{
89+
res += (! res.empty()? "|" : "");
90+
res += mode_name_v[i];
91+
}
92+
}
93+
if (res.empty()) res = "none";
94+
return res;
95+
}
96+
static void check_mode(const std::string& filename, std::ios_base::openmode mode)
97+
{
98+
if ((mode & std::ios_base::trunc) && ! (mode & std::ios_base::out))
99+
{
100+
throw Exception(std::string("strict_fstream: open('") + filename + "'): mode error: trunc and not out");
101+
}
102+
else if ((mode & std::ios_base::app) && ! (mode & std::ios_base::out))
103+
{
104+
throw Exception(std::string("strict_fstream: open('") + filename + "'): mode error: app and not out");
105+
}
106+
else if ((mode & std::ios_base::trunc) && (mode & std::ios_base::app))
107+
{
108+
throw Exception(std::string("strict_fstream: open('") + filename + "'): mode error: trunc and app");
109+
}
110+
}
111+
static void check_open(std::ios * s_p, const std::string& filename, std::ios_base::openmode mode)
112+
{
113+
if (s_p->fail())
114+
{
115+
throw Exception(std::string("strict_fstream: open('")
116+
+ filename + "'," + mode_to_string(mode) + "): open failed: "
117+
+ strerror());
118+
}
119+
}
120+
static void check_peek(std::istream * is_p, const std::string& filename, std::ios_base::openmode mode)
121+
{
122+
bool peek_failed = true;
123+
try
124+
{
125+
is_p->peek();
126+
peek_failed = is_p->fail();
127+
}
128+
catch (std::ios_base::failure e) {}
129+
if (peek_failed)
130+
{
131+
throw Exception(std::string("strict_fstream: open('")
132+
+ filename + "'," + mode_to_string(mode) + "): peek failed: "
133+
+ strerror());
134+
}
135+
is_p->clear();
136+
}
137+
}; // struct static_method_holder
138+
139+
} // namespace detail
140+
141+
class ifstream
142+
: public std::ifstream
143+
{
144+
public:
145+
ifstream() = default;
146+
ifstream(const std::string& filename, std::ios_base::openmode mode = std::ios_base::in)
147+
{
148+
open(filename, mode);
149+
}
150+
void open(const std::string& filename, std::ios_base::openmode mode = std::ios_base::in)
151+
{
152+
mode |= std::ios_base::in;
153+
exceptions(std::ios_base::badbit);
154+
detail::static_method_holder::check_mode(filename, mode);
155+
std::ifstream::open(filename, mode);
156+
detail::static_method_holder::check_open(this, filename, mode);
157+
detail::static_method_holder::check_peek(this, filename, mode);
158+
}
159+
}; // class ifstream
160+
161+
class ofstream
162+
: public std::ofstream
163+
{
164+
public:
165+
ofstream() = default;
166+
ofstream(const std::string& filename, std::ios_base::openmode mode = std::ios_base::out)
167+
{
168+
open(filename, mode);
169+
}
170+
void open(const std::string& filename, std::ios_base::openmode mode = std::ios_base::out)
171+
{
172+
mode |= std::ios_base::out;
173+
exceptions(std::ios_base::badbit);
174+
detail::static_method_holder::check_mode(filename, mode);
175+
std::ofstream::open(filename, mode);
176+
detail::static_method_holder::check_open(this, filename, mode);
177+
}
178+
}; // class ofstream
179+
180+
class fstream
181+
: public std::fstream
182+
{
183+
public:
184+
fstream() = default;
185+
fstream(const std::string& filename, std::ios_base::openmode mode = std::ios_base::in)
186+
{
187+
open(filename, mode);
188+
}
189+
void open(const std::string& filename, std::ios_base::openmode mode = std::ios_base::in)
190+
{
191+
if (! (mode & std::ios_base::out)) mode |= std::ios_base::in;
192+
exceptions(std::ios_base::badbit);
193+
detail::static_method_holder::check_mode(filename, mode);
194+
std::fstream::open(filename, mode);
195+
detail::static_method_holder::check_open(this, filename, mode);
196+
detail::static_method_holder::check_peek(this, filename, mode);
197+
}
198+
}; // class fstream
199+
200+
} // namespace strict_fstream
201+
202+
#endif

0 commit comments

Comments
 (0)