/*****************************************************************************\ * * * Name : critical_events * * Author : Chris Koeritz * * * ******************************************************************************* * Copyright (c) 1989-$now By Author. This program is free software; you can * * redistribute it and/or modify it under the terms of the GNU General Public * * License as published by the Free Software Foundation; either version 2 of * * the License or (at your option) any later version. This is online at: * * http://www.fsf.org/copyleft/gpl.html * * Please send any updates to: fred@gruntose.com * \*****************************************************************************/ #include "critical_events.h" #include "program_wide_logger.h" #include #include #include #include #include #include #include #include #include #include #include using namespace basis; using namespace structures; using namespace configuration; using namespace textual; using namespace timely; const int MESSAGE_SPACE_PROVIDED = 4096; // the strings should not be larger than this for diagnostic / error messages. namespace loggers { SAFE_STATIC(astring, critical_events::hidden_critical_events_dir, ) // define the function that holds the directory string. astring default_critical_location() { // ensure that the critical events function logs to the appropriate place. return application_configuration::get_logging_directory(); } SAFE_STATIC(mutex, __critical_event_dir_lock, ) basis::un_int critical_events::system_error() { #if defined(__UNIX__) || defined(__GNU_WINDOWS__) return errno; //#elif defined(_MSC_VER) // return GetLastError(); #else #pragma error("hmmm: no code for error number for this operating system") return 0; #endif } astring critical_events::system_error_text(basis::un_int to_name) { #if defined(__UNIX__) || defined(__GNU_WINDOWS__) return strerror(to_name); /* #elif defined(_MSC_VER) char error_text[1000]; FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL_POINTER, to_name, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)error_text, sizeof(error_text) - 1, NULL_POINTER); astring to_return = error_text; // trim off the ridiculous carriage return they add. while ( (to_return[to_return.end()] == '\r') || (to_return[to_return.end()] == '\n') ) to_return.zap(to_return.end(), to_return.end()); return to_return; */ #else #pragma error("hmmm: no code for error text for this operating system") return ""; #endif } astring critical_events::critical_events_directory() { static bool initted = false; if (!initted) { auto_synchronizer l(__critical_event_dir_lock()); if (!initted) { set_critical_events_directory(default_critical_location()); initted = true; } } return hidden_critical_events_dir(); } void critical_events::set_critical_events_directory(const astring &directory) { hidden_critical_events_dir() = directory; } void critical_events::write_to_critical_events(const char *to_write) { astring filename = critical_events_directory(); filename += "/runtime_issues.log"; FILE *errfile = fopen(filename.s(), "ab"); if (errfile) { astring app_name = application_configuration::application_name(); int indy = app_name.find('/', app_name.end(), true); if (non_negative(indy)) app_name.zap(0, indy); indy = app_name.find('\\', app_name.end(), true); if (non_negative(indy)) app_name.zap(0, indy); fprintf(errfile, "%s [%s]:%s", time_stamp::notarize(true).s(), app_name.s(), parser_bits::platform_eol_to_chars()); fprintf(errfile, "%s%s", to_write, parser_bits::platform_eol_to_chars()); fclose(errfile); } } void critical_events::write_to_console(const char *guards_message_space) { fprintf(stderr, "%s", (char *)guards_message_space); fflush(stderr); } void critical_events::alert_message(const char *info, const char *title) { astring to_print; if (strlen(title)) { const char border = '='; to_print += astring(border, int(strlen(title)) + 4); to_print += parser_bits::platform_eol_to_chars(); to_print += border; to_print += ' '; to_print += title; to_print += ' '; to_print += border; to_print += parser_bits::platform_eol_to_chars(); to_print += astring(border, int(strlen(title)) + 4); to_print += parser_bits::platform_eol_to_chars(); } to_print += info; program_wide_logger::get().log(to_print, ALWAYS_PRINT); fflush(NULL_POINTER); // flush all output streams. } void critical_events::alert_message(const astring &info) { alert_message(info.s()); } void critical_events::alert_message(const astring &info, const astring &title) { alert_message(info.s(), title.s()); } void critical_events::make_error_message(const char *file, int line, const char *error_class, const char *error_function, const char *info, char *guards_message_space) { strcpy(guards_message_space, "\nProblem reported for \""); //hmmm: only copy N chars of each into the space. // say 40 for class/function each, then the space - consumed for the // info. get strlen for real on the class and function name to know // actual size for that computation. strcat(guards_message_space, error_class); strcat(guards_message_space, "::"); strcat(guards_message_space, error_function); strcat(guards_message_space, "\"\n(invoked at line "); char line_num[20]; sprintf(line_num, "%d", line); strcat(guards_message_space, line_num); strcat(guards_message_space, " in "); strcat(guards_message_space, file); strcat(guards_message_space, " at "); strcat(guards_message_space, time_stamp::notarize(false).s()); strcat(guards_message_space, ")\n"); strcat(guards_message_space, info); strcat(guards_message_space, "\n\n\n"); } void critical_events::FL_deadly_error(const char *file, int line, const char *error_class, const char *error_function, const char *info) { FL_continuable_error(file, line, error_class, error_function, info, "Deadly Error Information"); CAUSE_BREAKPOINT; throw "deadly_error"; // abort() is not as good an approach as throwing an exception. aborts are // harder to track with some compilers, but all should be able to trap an // exception. } void critical_events::FL_deadly_error(const astring &file, int line, const astring &error_class, const astring &error_function, const astring &info) { FL_deadly_error(file.s(), line, error_class.s(), error_function.s(), info.s()); } void critical_events::FL_continuable_error_real(const char *file, int line, const char *error_class, const char *error_function, const char *info, const char *title) { char guards_message_space[MESSAGE_SPACE_PROVIDED]; // this routine could still fail, if the call stack is already jammed // against its barrier. but if that's the case, even the simple function // call might fail. in any case, we cannot deal with a stack overflow // type error using this function. but we would rather deal with that // than make the space static since that would cause corruption when // two threads wrote errors at the same time. make_error_message(file, line, error_class, error_function, info, guards_message_space); alert_message(guards_message_space, title); } void critical_events::FL_continuable_error(const char *file, int line, const char *error_class, const char *error_function, const char *info, const char *title) { FL_continuable_error_real(file, line, error_class, error_function, info, title); } void critical_events::FL_continuable_error(const astring &file, int line, const astring &error_class, const astring &error_function, const astring &info, const astring &title) { FL_continuable_error_real(file.s(), line, error_class.s(), error_function.s(), info.s(), title.s()); } void critical_events::FL_non_continuable_error(const char *file, int line, const char *error_class, const char *error_function, const char *info, const char *title) { FL_continuable_error_real(file, line, error_class, error_function, info, title); exit(EXIT_FAILURE); // let the outside world know that there was a problem. } void critical_events::FL_non_continuable_error(const astring &file, int line, const astring &error_class, const astring &error_function, const astring &info, const astring &title) { FL_continuable_error_real(file.s(), line, error_class.s(), error_function.s(), info.s(), title.s()); exit(EXIT_FAILURE); // let the outside world know that there was a problem. } void critical_events::FL_console_error(const char *file, int line, const char *error_class, const char *error_function, const char *info) { char guards_message_space[MESSAGE_SPACE_PROVIDED]; make_error_message(file, line, error_class, error_function, info, guards_message_space); write_to_console(guards_message_space); } void critical_events::FL_out_of_memory_now(const char *file, int line, const char *the_class_name, const char *the_func) { FL_non_continuable_error(file, line, the_class_name, the_func, "Program stopped due to memory allocation failure.", "Out of Memory Now"); } void critical_events::implement_bounds_halt(const char *the_class_name, const char *the_func, const char *value, const char *low, const char *high, const char *error_addition) { char message[400]; strcpy(message, "bounds error caught"); strcat(message, error_addition); strcat(message, ":\r\n"); strcat(message, value); strcat(message, " is not between "); strcat(message, low); strcat(message, " and "); strcat(message, high); #ifdef ERRORS_ARE_FATAL deadly_error(the_class_name, the_func, message); #else continuable_error(the_class_name, the_func, message); #endif } } //namespace.