1 /*
2 BStone: A Source port of
3 Blake Stone: Aliens of Gold and Blake Stone: Planet Strike
4
5 Copyright (c) 1992-2013 Apogee Entertainment, LLC
6 Copyright (c) 2013-2015 Boris I. Bendovsky (bibendovsky@hotmail.com)
7
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation; either version 2
11 of the License, or (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the
20 Free Software Foundation, Inc.,
21 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 */
23
24
25 //
26 // Logging facility
27 //
28
29
30 #include "bstone_log.h"
31 #include <iostream>
32 #include <stdexcept>
33 #include "SDL.h"
34
35
36 const std::string& get_version_string();
37 const std::string& get_profile_dir();
38
39
40 namespace bstone {
41
42
Log()43 Log::Log() :
44 fstream_(),
45 args_(),
46 sstream_(),
47 message_(),
48 message_type_()
49 {
50 auto log_path = ::get_profile_dir() + "bstone_log.txt";
51 fstream_.open(log_path, StreamOpenMode::write);
52
53 args_.reserve(16);
54 message_.reserve(1024);
55 }
56
~Log()57 Log::~Log()
58 {
59 }
60
61 // (static)
write()62 void Log::write()
63 {
64 write(std::string());
65 }
66
67 // (static)
write_version()68 void Log::write_version()
69 {
70 clean_up();
71
72 write_internal(
73 MessageType::version,
74 "BStone version: {}",
75 ::get_version_string());
76 }
77
78 // (static)
get_local()79 Log& Log::get_local()
80 {
81 static Log log;
82 static bool is_initialized = false;
83
84 if (!is_initialized) {
85 is_initialized = true;
86
87 write("BStone Log");
88 write("==========");
89 write();
90 write("Version: {}", ::get_version_string());
91 write();
92 }
93
94 return log;
95 }
96
write_internal(const std::string & format)97 void Log::write_internal(
98 const std::string& format)
99 {
100 bool is_critical = false;
101 bool is_version = false;
102
103 switch (message_type_) {
104 case MessageType::version:
105 is_version = true;
106 message_.clear();
107 break;
108
109 case MessageType::information:
110 message_.clear();
111 break;
112
113 case MessageType::warning:
114 message_ = "WARNING: ";
115 break;
116
117 case MessageType::error:
118 message_ = "ERROR: ";
119 break;
120
121 case MessageType::critical_error:
122 is_critical = true;
123 message_ = "CRITICAL: ";
124 break;
125
126 default:
127 throw std::runtime_error("Invalid message type.");
128 }
129
130 if (args_.empty()) {
131 message_ += format;
132 } else if (!format.empty()) {
133 int i = 0;
134 char prev_char = '\0';
135 auto c_format = format.c_str();
136 int arg_index = 0;
137 while (c_format[i] != '\0') {
138 auto ch = c_format[i];
139 bool just_advance = false;
140
141 if (prev_char != '{' && ch == '{') {
142 int next_char = c_format[i + 1];
143
144 if (next_char == '}') {
145 if (arg_index < static_cast<int>(args_.size())) {
146 message_ += args_[arg_index];
147
148 i += 2;
149 arg_index += 1;
150 } else {
151 just_advance = true;
152 }
153 } else {
154 int digit = next_char - '0';
155
156 if (digit >= 0 && digit <= 9) {
157 next_char = c_format[i + 2];
158
159 if (next_char == '}') {
160 if (digit < static_cast<int>(args_.size())) {
161 message_ += args_[digit];
162 i += 3;
163 } else {
164 just_advance = true;
165 }
166 } else {
167 just_advance = true;
168 }
169 } else {
170 just_advance = true;
171 }
172 }
173 } else {
174 just_advance = true;
175 }
176
177 if (just_advance) {
178 ++i;
179 message_ += ch;
180 }
181
182 prev_char = c_format[i - 1];
183 }
184 }
185
186 std::cout << message_ << std::endl;
187
188 if (!is_version) {
189 fstream_.write_string(message_);
190 fstream_.write_octet('\n');
191 }
192
193 if (is_critical || is_version) {
194 static_cast<void>(::SDL_ShowSimpleMessageBox(
195 is_version ? SDL_MESSAGEBOX_INFORMATION : SDL_MESSAGEBOX_ERROR,
196 "BStone",
197 message_.c_str(),
198 nullptr));
199 }
200 }
201
202 // (static)
clean_up()203 void Log::clean_up()
204 {
205 auto& local = get_local();
206 local.args_.clear();
207 }
208
209
210 } // bstone
211