wow. that was easy: git mv core nucleus
[feisty_meow.git] / nucleus / library / loggers / critical_events.cpp
diff --git a/nucleus/library/loggers/critical_events.cpp b/nucleus/library/loggers/critical_events.cpp
new file mode 100644 (file)
index 0000000..ebb60bb
--- /dev/null
@@ -0,0 +1,284 @@
+/*****************************************************************************\
+*                                                                             *
+*  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 <application/application_shell.h>
+#include <application/windoze_helper.h>
+#include <basis/astring.h>
+#include <basis/functions.h>
+#include <basis/mutex.h>
+#include <configuration/application_configuration.h>
+#include <structures/static_memory_gremlin.h>
+#include <textual/parser_bits.h>
+#include <timely/time_stamp.h>
+
+#include <stdio.h>
+#ifdef __UNIX__
+  #include <errno.h>
+#endif
+
+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__)
+  return errno;
+#elif defined(__WIN32__)
+  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__)
+  return strerror(to_name);
+#elif defined(__WIN32__)
+  char error_text[1000];
+  FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NIL, to_name,
+      MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)error_text,
+      sizeof(error_text) - 1, NIL);
+  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(NIL);  // 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.
+