ge211  2021.5.1
A student game engine
ge211_error.cxx
1 #include "ge211_error.hxx"
2 
3 #include <SDL.h>
4 #include <SDL_image.h>
5 #include <SDL_ttf.h>
6 
7 #include <iostream>
8 
9 namespace ge211 {
10 
11 namespace exceptions {
12 
13 static const char* take_sdl_error()
14 {
15  const char* result = SDL_GetError();
16  SDL_ClearError();
17  return result;
18 }
19 
20 const char* Exception_base::what() const NOEXCEPT
21 {
22  return message_->c_str();
23 }
24 
25 Exception_base::Exception_base(const std::string& message)
26  : message_{std::make_shared<std::string>(message)}
27 { }
28 
29 Environment_error::Environment_error(const std::string& message)
30  : Exception_base(message)
31 { }
32 
33 Client_logic_error::Client_logic_error(const std::string& message)
34  : Exception_base(message)
35 { }
36 
37 static std::string build_no_session_message(const std::string& action) {
39  oss << "\n\nERROR\n=====\n\n"
40  << action << " requires an active GE211 session. GE211 sessions\n"
41  << "are managed RAII-style by the ge211::Abstract_game class, so\n"
42  << "a session will be active whenever you have an instance of a\n"
43  << "class derived from Abstract_game, including within that derived\n"
44  << "game class's constructor and member functions.\n";
45 
46  return oss.str();
47 }
48 
49 Session_needed_error::Session_needed_error(const std::string& action)
50  : Client_logic_error(build_no_session_message(action))
51  , action_(action)
52 { }
53 
54 static std::string build_late_paint_message(char const* who) {
56  oss << "\n\nERROR\n=====\n\n"
57  << who
58  << ": Cannot paint to a ge211::internal::Render_sprite\n"
59  "that has already been rendered.\n";
60 
61  return oss.str();
62 }
63 
64 Late_paint_error::Late_paint_error(char const* who)
65  : Client_logic_error(build_late_paint_message(who))
66 { }
67 
68 static std::string build_sdl_error_message(const std::string& message) {
69  const char* reason = take_sdl_error();
70 
72  if (message.empty()) {
73  oss << "SDL Error";
74  if (reason[0]) {
75  oss << ": " << reason;
76  }
77  } else {
78  oss << message;
79  if (reason[0]) {
80  oss << "\n (reason from SDL: " << reason << ")";
81  }
82  }
83 
84  return oss.str();
85 }
86 
87 Host_error::Host_error(const std::string& message)
88  : Environment_error{build_sdl_error_message(message)}
89 { }
90 
91 File_error::File_error(const std::string& message)
92  : Host_error{message}
93 { }
94 
95 File_error File_error::could_not_open(const std::string& filename)
96 {
97  return File_error("Could not open: " + filename);
98 }
99 
100 Font_error::Font_error(const std::string& message)
101  : Host_error{message}
102 { }
103 
104 Font_error Font_error::could_not_load(const std::string& filename)
105 {
106  return Font_error("Could not load font: " + filename);
107 }
108 
109 Ge211_logic_error::Ge211_logic_error(const std::string& message)
110  : Environment_error("Apparent ge211 bug! " + message)
111 { }
112 
113 Image_error::Image_error(const std::string& message)
114  : Host_error{message}
115 { }
116 
117 Image_error Image_error::could_not_load(const std::string& filename)
118 {
119  return Image_error("Could not load image: " + filename);
120 }
121 
122 Mixer_error::Mixer_error(const std::string& message)
123  : Host_error{message}
124 { }
125 
126 Mixer_error Mixer_error::could_not_load(const std::string& filename)
127 {
128  return Mixer_error("Could not load music: " + filename);
129 }
130 
131 Mixer_error Mixer_error::out_of_channels()
132 {
133  return Mixer_error("Could not play effect: out of channels");
134 }
135 
136 Mixer_error Mixer_error::not_enabled()
137 {
138  return Mixer_error("Mixer is not enabled");
139 }
140 
141 }
142 
143 namespace internal {
144 
145 namespace logging {
146 
147 static const char*
148 log_level_string(Log_level level)
149 {
150  switch (level) {
151  case Log_level::debug:
152  return "debug";
153  case Log_level::info:
154  return "info";
155  case Log_level::warn:
156  return "warn";
157  case Log_level::fatal:
158  return "fatal";
159  }
160 
161  // Shouldn't happen, because switch above is exhaustive. But this
162  // makes gcc warn less.
163  return "<unknown>";
164 }
165 
167 {
168  return Log_message{std::move(reason), Log_level::debug};
169 }
170 
172 {
173  return Log_message{std::move(reason), Log_level::info};
174 }
175 
177 {
178  return Log_message{std::move(reason), Log_level::warn};
179 }
180 
182 {
183  return Log_message{std::move(reason), Log_level::fatal};
184 }
185 
187 {
188  static Logger instance;
189  return instance;
190 }
191 
193  : reason_{std::move(reason)}
194  , message_{}
195  , active_{level >= Logger::instance().level()}
196 {
197  if (active_)
198  message_ << "ge211[" << log_level_string(level) << "]: ";
199 }
200 
202  : Log_message{"", level}
203 { }
204 
206 {
207  if (active_) {
208  std::cerr << message_.str();
209  if (!reason_.empty()) std::cerr << "\n (Reason: " << reason_ << ")";
210  std::cerr << std::endl;
211  }
212 }
213 
214 } // end namespace logging
215 
216 } // end namespace internal
217 
218 namespace detail {
219 
220 using namespace internal::logging;
221 
222 Log_message info_sdl()
223 {
224  return info(take_sdl_error());
225 }
226 
227 Log_message warn_sdl()
228 {
229  return warn(take_sdl_error());
230 }
231 
232 Log_message fatal_sdl()
233 {
234  return fatal(take_sdl_error());
235 }
236 
237 } // end namespace detail
238 
239 }
240 
ge211::internal::logging::debug
Log_message debug(std::string reason="")
Returns a debug-level log message.
Definition: ge211_error.cxx:166
ge211::internal::logging::Log_message::~Log_message
virtual ~Log_message()
A Log_message has important work to do when it's destroyed.
Definition: ge211_error.cxx:205
std::string
ge211::internal::logging::warn
Log_message warn(std::string reason="")
Returns a warn-level log message.
Definition: ge211_error.cxx:176
ge211::internal::logging::info
Log_message info(std::string reason="")
Returns a info-level log message.
Definition: ge211_error.cxx:171
ge211::internal::logging::Logger::level
Log_level level() const
Returns the log level of this logger.
Definition: ge211_error.hxx:210
ge211
The game engine namespace.
Definition: ge211.hxx:4
std::cerr
ge211::exceptions::Client_logic_error
An exception that indicates that a logic error was performed by the client.
Definition: ge211_error.hxx:48
ge211::internal::logging::Logger
Right now a Logger just keeps track of the current log level.
Definition: ge211_error.hxx:207
ge211::internal::logging::Log_level
Log_level
How serious is this log message?
Definition: ge211_error.hxx:193
ge211::internal::logging::Log_message::Log_message
Log_message(Log_level level=Log_level::debug)
Construct a new Log_message with the given log level.
Definition: ge211_error.cxx:201
std::ostringstream
ge211::internal::logging::fatal
Log_message fatal(std::string reason="")
Returns a fatal-level log message.
Definition: ge211_error.cxx:181
std::internal
T internal(T... args)
std::string::empty
T empty(T... args)
std::ostringstream::str
T str(T... args)
ge211::internal::logging::Log_message
A Log_message accumulates information and then prints it all at once when it's about to be destroyed.
Definition: ge211_error.hxx:227
ge211::internal::logging::Log_level::debug
@ debug
extra debugging information
ge211::exceptions::Exception_base::what
const char * what() const override
The error message associated with the exception.
Definition: ge211_error.cxx:20
ge211::internal::logging::Logger::instance
static Logger & instance()
Returns the one and only logger instance.
Definition: ge211_error.cxx:186
ge211::exceptions::Exception_base
The root of the ge211 exception hierarchy.
Definition: ge211_error.hxx:24