To handle fatal errors.

§1. In my beginning is my end: this lowest level of the error-handling system deals with systemic collapses.

text_stream problems_file_struct;  The actual report of Problems file
text_stream *problems_file = &problems_file_struct;  The actual report of Problems file

text_stream *probl = NULL;  Current destination of problem message text

int it_is_not_worth_adding = FALSE;  To suppress the "It may be worth adding..."

int crash_on_all_errors = FALSE;

text_stream *sigil_of_required_problem = NULL;
int sigil_of_required_problem_found = FALSE;

void Problems::Fatal::require(text_stream *sigil) {
    sigil_of_required_problem = Str::duplicate(sigil);
}

void Problems::Fatal::exit(int code) {
    if ((sigil_of_required_problem) && (sigil_of_required_problem_found == FALSE))
        exit(0);  so that the problem test case will fail in intest
    exit(code);
}

void Problems::Fatal::issue(char *message) {
    WRITE_TO(STDERR, message);
    WRITE_TO(STDERR, "\n");
    STREAM_FLUSH(STDERR);
    if (crash_on_all_errors) Problems::Fatal::force_crash();
    Problems::Fatal::exit(2);
}

void Problems::Fatal::issue_t(char *message, char *fn) {
    WRITE_TO(STDERR, message);
    WRITE_TO(STDERR, "\nOffending filename: <%s>\n", fn);
    STREAM_FLUSH(STDERR);
    if (crash_on_all_errors) Problems::Fatal::force_crash();
    Problems::Fatal::exit(2);
}

void Problems::Fatal::filename_related(char *message, filename *F) {
    WRITE_TO(STDERR, message);
    WRITE_TO(STDERR, "\nOffending filename: <%f>\n", F);
    STREAM_FLUSH(STDERR);
    if (crash_on_all_errors) Problems::Fatal::force_crash();
    Problems::Fatal::exit(2);
}

§2. Fatal errors are not necessarily a bad thing. When tracking down why Inform issues certain problem messages (especially internal errors) it can be useful to provoke a deliberate crash of the application, in order to get a stack backtrace into the GNU debugger gdb (and/or onto the system console logs). We can force this using the following variables (which main sets with the command-line switch "-gdb").

void Problems::Fatal::force_crash(void) {
    STREAM_FLUSH(STDOUT);
    STREAM_FLUSH(DL);
    WRITE_TO(STDERR,
        "*** Intentionally crashing to force stack backtrace to console logs ***\n");
    STREAM_FLUSH(STDERR);
    parse_node *PN = NULL; LOG("$T", PN->next);
    Problems::Fatal::exit(1);
}