Eclipse SUMO - Simulation of Urban MObility
Loading...
Searching...
No Matches
strict_fstream.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <cassert>
4#include <fstream>
5#include <cstring>
6#include <string>
7#include <vector>
8
18{
19
20// Help people out a bit, it seems like this is a common recommenation since
21// musl breaks all over the place.
22#if defined(__NEED_size_t) && !defined(__MUSL__)
23#warning "It seems to be recommended to patch in a define for __MUSL__ if you use musl globally: https://www.openwall.com/lists/musl/2013/02/10/5"
24#define __MUSL__
25#endif
26
27// Workaround for broken musl implementation
28// Since musl insists that they are perfectly compatible, ironically enough,
29// they don't officially have a __musl__ or similar. But __NEED_size_t is defined in their
30// relevant header (and not in working implementations), so we can use that.
31#ifdef __MUSL__
32#warning "Working around broken strerror_r() implementation in musl, remove when musl is fixed"
33#endif
34
35// Non-gnu variants of strerror_* don't necessarily null-terminate if
36// truncating, so we have to do things manually.
37inline std::string trim_to_null(const std::vector<char> &buff)
38{
39 std::string ret(buff.begin(), buff.end());
40
41 const std::string::size_type pos = ret.find('\0');
42 if (pos == std::string::npos) {
43 ret += " [...]"; // it has been truncated
44 } else {
45 ret.resize(pos);
46 }
47 return ret;
48}
49
54static std::string strerror()
55{
56 // Can't use std::string since we're pre-C++17
57 std::vector<char> buff(256, '\0');
58
59#ifdef _WIN32
60 // Since strerror_s might set errno itself, we need to store it.
61 const int err_num = errno;
62 if (strerror_s(buff.data(), buff.size(), err_num) != 0) {
63 return trim_to_null(buff);
64 } else {
65 return "Unknown error (" + std::to_string(err_num) + ")";
66 }
67#elif ((_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600 || defined(__APPLE__)) && ! _GNU_SOURCE) || defined(__MUSL__)
68// XSI-compliant strerror_r()
69 const int err_num = errno; // See above
70 if (strerror_r(err_num, buff.data(), buff.size()) == 0) {
71 return trim_to_null(buff);
72 } else {
73 return "Unknown error (" + std::to_string(err_num) + ")";
74 }
75#else
76// GNU-specific strerror_r()
77 char * p = strerror_r(errno, &buff[0], buff.size());
78 return std::string(p, std::strlen(p));
79#endif
80}
81
84 : public std::exception
85{
86public:
87 Exception(const std::string& msg) : _msg(msg) {}
88 const char * what() const noexcept { return _msg.c_str(); }
89private:
90 std::string _msg;
91}; // class Exception
92
93namespace detail
94{
95
97{
98 static std::string mode_to_string(std::ios_base::openmode mode)
99 {
100 static const int n_modes = 6;
101 static const std::ios_base::openmode mode_val_v[n_modes] =
102 {
103 std::ios_base::in,
104 std::ios_base::out,
105 std::ios_base::app,
106 std::ios_base::ate,
107 std::ios_base::trunc,
108 std::ios_base::binary
109 };
110
111 static const char * mode_name_v[n_modes] =
112 {
113 "in",
114 "out",
115 "app",
116 "ate",
117 "trunc",
118 "binary"
119 };
120 std::string res;
121 for (int i = 0; i < n_modes; ++i)
122 {
123 if (mode & mode_val_v[i])
124 {
125 res += (! res.empty()? "|" : "");
126 res += mode_name_v[i];
127 }
128 }
129 if (res.empty()) res = "none";
130 return res;
131 }
132 static void check_mode(const std::string& filename, std::ios_base::openmode mode)
133 {
134 if ((mode & std::ios_base::trunc) && ! (mode & std::ios_base::out))
135 {
136 throw Exception(std::string("strict_fstream: open('") + filename + "'): mode error: trunc and not out");
137 }
138 else if ((mode & std::ios_base::app) && ! (mode & std::ios_base::out))
139 {
140 throw Exception(std::string("strict_fstream: open('") + filename + "'): mode error: app and not out");
141 }
142 else if ((mode & std::ios_base::trunc) && (mode & std::ios_base::app))
143 {
144 throw Exception(std::string("strict_fstream: open('") + filename + "'): mode error: trunc and app");
145 }
146 }
147 static void check_open(std::ios * s_p, const std::string& filename, std::ios_base::openmode mode)
148 {
149 if (s_p->fail())
150 {
151 throw Exception(std::string("strict_fstream: open('")
152 + filename + "'," + mode_to_string(mode) + "): open failed: "
153 + strerror());
154 }
155 }
156 static void check_peek(std::istream * is_p, const std::string& filename, std::ios_base::openmode mode)
157 {
158 bool peek_failed = true;
159 try
160 {
161 is_p->peek();
162 peek_failed = is_p->fail();
163 }
164 catch (const std::ios_base::failure &) {}
165 if (peek_failed)
166 {
167 throw Exception(std::string("strict_fstream: open('")
168 + filename + "'," + mode_to_string(mode) + "): peek failed: "
169 + strerror());
170 }
171 is_p->clear();
172 }
173}; // struct static_method_holder
174
175} // namespace detail
176
178 : public std::ifstream
179{
180public:
181 ifstream() = default;
182 ifstream(const std::string& filename, std::ios_base::openmode mode = std::ios_base::in)
183 {
184 open(filename, mode);
185 }
186 void open(const std::string& filename, std::ios_base::openmode mode = std::ios_base::in)
187 {
188 mode |= std::ios_base::in;
189 exceptions(std::ios_base::badbit);
191 std::ifstream::open(filename, mode);
192 detail::static_method_holder::check_open(this, filename, mode);
193 detail::static_method_holder::check_peek(this, filename, mode);
194 }
195}; // class ifstream
196
198 : public std::ofstream
199{
200public:
201 ofstream() = default;
202 ofstream(const std::string& filename, std::ios_base::openmode mode = std::ios_base::out)
203 {
204 open(filename, mode);
205 }
206 void open(const std::string& filename, std::ios_base::openmode mode = std::ios_base::out)
207 {
208 mode |= std::ios_base::out;
209 exceptions(std::ios_base::badbit);
211 std::ofstream::open(filename, mode);
212 detail::static_method_holder::check_open(this, filename, mode);
213 }
214}; // class ofstream
215
217 : public std::fstream
218{
219public:
220 fstream() = default;
221 fstream(const std::string& filename, std::ios_base::openmode mode = std::ios_base::in)
222 {
223 open(filename, mode);
224 }
225 void open(const std::string& filename, std::ios_base::openmode mode = std::ios_base::in)
226 {
227 if (! (mode & std::ios_base::out)) mode |= std::ios_base::in;
228 exceptions(std::ios_base::badbit);
230 std::fstream::open(filename, mode);
231 detail::static_method_holder::check_open(this, filename, mode);
232 detail::static_method_holder::check_peek(this, filename, mode);
233 }
234}; // class fstream
235
236} // namespace strict_fstream
Exception class thrown by failed operations.
Exception(const std::string &msg)
const char * what() const noexcept
fstream(const std::string &filename, std::ios_base::openmode mode=std::ios_base::in)
void open(const std::string &filename, std::ios_base::openmode mode=std::ios_base::in)
ifstream(const std::string &filename, std::ios_base::openmode mode=std::ios_base::in)
void open(const std::string &filename, std::ios_base::openmode mode=std::ios_base::in)
void open(const std::string &filename, std::ios_base::openmode mode=std::ios_base::out)
ofstream(const std::string &filename, std::ios_base::openmode mode=std::ios_base::out)
std::string trim_to_null(const std::vector< char > &buff)
static std::string strerror()
static void check_mode(const std::string &filename, std::ios_base::openmode mode)
static void check_open(std::ios *s_p, const std::string &filename, std::ios_base::openmode mode)
static std::string mode_to_string(std::ios_base::openmode mode)
static void check_peek(std::istream *is_p, const std::string &filename, std::ios_base::openmode mode)