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