1 /*****************************************************************************\
3 * Name : critical_events *
4 * Author : Chris Koeritz *
6 *******************************************************************************
7 * Copyright (c) 1989-$now By Author. This program is free software; you can *
8 * redistribute it and/or modify it under the terms of the GNU General Public *
9 * License as published by the Free Software Foundation; either version 2 of *
10 * the License or (at your option) any later version. This is online at: *
11 * http://www.fsf.org/copyleft/gpl.html *
12 * Please send any updates to: fred@gruntose.com *
13 \*****************************************************************************/
15 #include "critical_events.h"
16 #include "program_wide_logger.h"
18 #include <application/application_shell.h>
19 #include <application/windoze_helper.h>
20 #include <basis/astring.h>
21 #include <basis/functions.h>
22 #include <basis/mutex.h>
23 #include <configuration/application_configuration.h>
24 #include <structures/static_memory_gremlin.h>
25 #include <textual/parser_bits.h>
26 #include <timely/time_stamp.h>
33 using namespace basis;
34 using namespace structures;
35 using namespace configuration;
36 using namespace textual;
37 using namespace timely;
39 const int MESSAGE_SPACE_PROVIDED = 4096;
40 // the strings should not be larger than this for diagnostic / error messages.
44 SAFE_STATIC(astring, critical_events::hidden_critical_events_dir, )
45 // define the function that holds the directory string.
47 astring default_critical_location()
49 // ensure that the critical events function logs to the appropriate place.
50 return application_configuration::get_logging_directory();
53 SAFE_STATIC(mutex, __critical_event_dir_lock, )
55 basis::un_int critical_events::system_error()
57 #if defined(__UNIX__) || defined(__GNU_WINDOWS__)
59 #elif defined(_MSC_VER)
60 return GetLastError();
62 #pragma error("hmmm: no code for error number for this operating system")
67 astring critical_events::system_error_text(basis::un_int to_name)
69 #if defined(__UNIX__) || defined(__GNU_WINDOWS__)
70 return strerror(to_name);
71 #elif defined(_MSC_VER)
72 char error_text[1000];
73 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL_POINTER, to_name,
74 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)error_text,
75 sizeof(error_text) - 1, NULL_POINTER);
76 astring to_return = error_text;
77 // trim off the ridiculous carriage return they add.
78 while ( (to_return[to_return.end()] == '\r')
79 || (to_return[to_return.end()] == '\n') )
80 to_return.zap(to_return.end(), to_return.end());
83 #pragma error("hmmm: no code for error text for this operating system")
88 astring critical_events::critical_events_directory()
90 static bool initted = false;
92 auto_synchronizer l(__critical_event_dir_lock());
94 set_critical_events_directory(default_critical_location());
98 return hidden_critical_events_dir();
101 void critical_events::set_critical_events_directory(const astring &directory)
102 { hidden_critical_events_dir() = directory; }
104 void critical_events::write_to_critical_events(const char *to_write)
106 astring filename = critical_events_directory();
107 filename += "/runtime_issues.log";
108 FILE *errfile = fopen(filename.s(), "ab");
110 astring app_name = application_configuration::application_name();
111 int indy = app_name.find('/', app_name.end(), true);
112 if (non_negative(indy)) app_name.zap(0, indy);
113 indy = app_name.find('\\', app_name.end(), true);
114 if (non_negative(indy)) app_name.zap(0, indy);
115 fprintf(errfile, "%s [%s]:%s", time_stamp::notarize(true).s(),
116 app_name.s(), parser_bits::platform_eol_to_chars());
117 fprintf(errfile, "%s%s", to_write, parser_bits::platform_eol_to_chars());
122 void critical_events::write_to_console(const char *guards_message_space)
123 { fprintf(stderr, "%s", (char *)guards_message_space); fflush(stderr); }
125 void critical_events::alert_message(const char *info, const char *title)
129 const char border = '=';
130 to_print += astring(border, int(strlen(title)) + 4);
131 to_print += parser_bits::platform_eol_to_chars();
137 to_print += parser_bits::platform_eol_to_chars();
138 to_print += astring(border, int(strlen(title)) + 4);
139 to_print += parser_bits::platform_eol_to_chars();
143 program_wide_logger::get().log(to_print, ALWAYS_PRINT);
144 fflush(NULL_POINTER); // flush all output streams.
147 void critical_events::alert_message(const astring &info) { alert_message(info.s()); }
149 void critical_events::alert_message(const astring &info, const astring &title)
150 { alert_message(info.s(), title.s()); }
152 void critical_events::make_error_message(const char *file, int line,
153 const char *error_class, const char *error_function,
154 const char *info, char *guards_message_space)
156 strcpy(guards_message_space, "\nProblem reported for \"");
157 //hmmm: only copy N chars of each into the space.
158 // say 40 for class/function each, then the space - consumed for the
159 // info. get strlen for real on the class and function name to know
160 // actual size for that computation.
161 strcat(guards_message_space, error_class);
162 strcat(guards_message_space, "::");
163 strcat(guards_message_space, error_function);
164 strcat(guards_message_space, "\"\n(invoked at line ");
166 sprintf(line_num, "%d", line);
167 strcat(guards_message_space, line_num);
168 strcat(guards_message_space, " in ");
169 strcat(guards_message_space, file);
170 strcat(guards_message_space, " at ");
171 strcat(guards_message_space, time_stamp::notarize(false).s());
172 strcat(guards_message_space, ")\n");
173 strcat(guards_message_space, info);
174 strcat(guards_message_space, "\n\n\n");
177 void critical_events::FL_deadly_error(const char *file, int line, const char *error_class,
178 const char *error_function, const char *info)
180 FL_continuable_error(file, line, error_class, error_function, info,
181 "Deadly Error Information");
183 throw "deadly_error";
184 // abort() is not as good an approach as throwing an exception. aborts are
185 // harder to track with some compilers, but all should be able to trap an
189 void critical_events::FL_deadly_error(const astring &file, int line,
190 const astring &error_class, const astring &error_function,
193 FL_deadly_error(file.s(), line, error_class.s(), error_function.s(),
197 void critical_events::FL_continuable_error_real(const char *file, int line,
198 const char *error_class, const char *error_function, const char *info,
201 char guards_message_space[MESSAGE_SPACE_PROVIDED];
202 // this routine could still fail, if the call stack is already jammed
203 // against its barrier. but if that's the case, even the simple function
204 // call might fail. in any case, we cannot deal with a stack overflow
205 // type error using this function. but we would rather deal with that
206 // than make the space static since that would cause corruption when
207 // two threads wrote errors at the same time.
208 make_error_message(file, line, error_class, error_function, info,
209 guards_message_space);
210 alert_message(guards_message_space, title);
213 void critical_events::FL_continuable_error(const char *file, int line,
214 const char *error_class, const char *error_function, const char *info,
217 FL_continuable_error_real(file, line, error_class, error_function, info, title);
220 void critical_events::FL_continuable_error(const astring &file, int line,
221 const astring &error_class, const astring &error_function,
222 const astring &info, const astring &title)
224 FL_continuable_error_real(file.s(), line, error_class.s(),
225 error_function.s(), info.s(), title.s());
228 void critical_events::FL_non_continuable_error(const char *file, int line,
229 const char *error_class, const char *error_function, const char *info,
232 FL_continuable_error_real(file, line, error_class, error_function, info,
234 exit(EXIT_FAILURE); // let the outside world know that there was a problem.
237 void critical_events::FL_non_continuable_error(const astring &file, int line,
238 const astring &error_class, const astring &error_function,
239 const astring &info, const astring &title)
241 FL_continuable_error_real(file.s(), line, error_class.s(),
242 error_function.s(), info.s(), title.s());
243 exit(EXIT_FAILURE); // let the outside world know that there was a problem.
246 void critical_events::FL_console_error(const char *file, int line, const char *error_class,
247 const char *error_function, const char *info)
249 char guards_message_space[MESSAGE_SPACE_PROVIDED];
250 make_error_message(file, line, error_class, error_function, info,
251 guards_message_space);
252 write_to_console(guards_message_space);
255 void critical_events::FL_out_of_memory_now(const char *file, int line,
256 const char *the_class_name, const char *the_func)
258 FL_non_continuable_error(file, line, the_class_name, the_func,
259 "Program stopped due to memory allocation failure.",
260 "Out of Memory Now");
263 void critical_events::implement_bounds_halt(const char *the_class_name, const char *the_func,
264 const char *value, const char *low, const char *high,
265 const char *error_addition)
268 strcpy(message, "bounds error caught");
269 strcat(message, error_addition);
270 strcat(message, ":\r\n");
271 strcat(message, value);
272 strcat(message, " is not between ");
273 strcat(message, low);
274 strcat(message, " and ");
275 strcat(message, high);
276 #ifdef ERRORS_ARE_FATAL
277 deadly_error(the_class_name, the_func, message);
279 continuable_error(the_class_name, the_func, message);