/* * Descent 3 * Copyright (C) 2024 Parallax Software * * 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 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . --- HISTORICAL COMMENTS FOLLOW --- * $Logfile: /DescentIII/Main/misc/error.cpp $ * $Revision: 26 $ * $Date: 10/09/01 5:40p $ * $Author: Matt $ * * Error-handling functions * * $Log: /DescentIII/Main/misc/error.cpp $ * * 26 10/09/01 5:40p Matt * Made -nocrashbox work in release build. * * 25 9/15/01 1:46p Kevin * Added -nocrashbox to suppress crash dialog box * * 24 4/19/00 5:23p Matt * From Duane for 1.4 * Changed to Mac error exit message * * 23 5/05/99 5:22p Samir * exit(0) instead of exit(1) and other stuff to see why error isn't * exiting in release? * * 22 4/14/99 1:35a Jeff * fixed case mismatched #includes * * 21 4/01/99 4:50p Matt * Took out Warning() function, chaning those calls to mprintf() * * 20 3/02/99 5:50p Kevin * Ouch. Duplicate structures existed and were conflicting. * * 19 2/15/99 1:22p Kevin * Changes for GameGauge * * 18 1/10/99 6:47a Jeff * Changes made to get linux version to compile * * 17 11/01/98 1:58a Jeff * converted the vsprintf calls to use the Pvsprintf, which is a safe * vsprintf, no buffer overflows allowed * * 16 10/18/98 8:52p Matt * Revamped debug/error system. * */ #include #include #include #include #include "mono.h" #include "pserror.h" #include "debug.h" #include "application.h" #define MAX_MSG_LEN 2000 // Debug break chain handlers void (*DebugBreak_callback_stop)() = NULL; void (*DebugBreak_callback_resume)() = NULL; // library initialized flag static bool Error_initialized = false; // message that is printed out when error occurs static char Exit_message[MAX_MSG_LEN]; static char App_title[32]; static char Exit_title_str[64]; // error message output function void error_Spew(); ////////////////////////////////////////////////////////////////////////////// // initializes error handler. bool error_Init(bool debugger, const char *app_title) { Debug_Init(debugger); Error_initialized = true; Exit_message[0] = 0; strncpy(App_title, app_title, sizeof(App_title) - 1); App_title[sizeof(App_title) - 1] = 0; strncpy(Exit_title_str, app_title, sizeof(Exit_title_str) - 1); Exit_title_str[sizeof(Exit_title_str) - 1] = 0; atexit(error_Spew); return true; } // exits the application and prints out a standard error message void Error(const char *fmt, ...) { std::va_list arglist; int exit_msg_len; strcpy(Exit_message, "Error: "); va_start(arglist, fmt); exit_msg_len = strlen(Exit_message); std::vsnprintf(Exit_message + exit_msg_len, MAX_MSG_LEN - exit_msg_len, fmt, arglist); va_end(arglist); snprintf(Exit_title_str, sizeof(Exit_title_str), "%s Error", App_title); mprintf(0, "%s\n", Exit_message); #ifdef _DEBUG int answer = IDOK; if (DebugBreak_callback_stop) (*DebugBreak_callback_stop)(); if (Debug_break) answer = Debug_ErrorBox(OSMBOX_ABORTRETRYIGNORE, Exit_title_str, Exit_message, "Press RETRY to debug."); else answer = Debug_ErrorBox(OSMBOX_OKCANCEL, Exit_title_str, Exit_message, "Press OK to exit, CANCEL to ignore this error and continue."); switch (answer) { case IDRETRY: debug_break(); // Step Out of this function to see where Error() was called // fall into ignore/cancel case case IDIGNORE: case IDCANCEL: if (DebugBreak_callback_resume) (*DebugBreak_callback_resume)(); return; case IDOK: case IDABORT: break; // do nothing, and exit below } // Clear the message, since we don't need to see it again when we exit Exit_message[0] = 0; #else if (!Error_initialized) error_Spew(); #endif // Clear the DEBUG_BREAK() callbacks SetDebugBreakHandlers(NULL, NULL); // Leave the program exit(0); } // Brings up an error message for an int3 void Int3MessageBox(const char *file, int line) { #ifndef RELEASE char title[128], message[500]; int answer; snprintf(title, sizeof(title), "%s Debug Break", App_title); snprintf(message, sizeof(message), "Int3 in %s at line %d.", file, line); if (DebugBreak_callback_stop) (*DebugBreak_callback_stop)(); answer = Debug_ErrorBox(OSMBOX_YESNO, title, message, "It's probably safe to continue. Continue?"); if (answer == IDNO) { SetDebugBreakHandlers(NULL, NULL); exit(1); } if (DebugBreak_callback_resume) (*DebugBreak_callback_resume)(); #endif } // prints out an assertion error void AssertionFailed(const char *expstr, const char *file, int line) { #ifndef RELEASE char title[128], message[500]; int answer; snprintf(title, sizeof(title), "%s Assertion Failed", App_title); snprintf(message, sizeof(message), "Assertion failed: (%s)\n\nFile %s at line %d.", expstr, file, line); if (DebugBreak_callback_stop) (*DebugBreak_callback_stop)(); answer = Debug_ErrorBox(OSMBOX_YESNO, title, message, "Continue?"); if (answer == IDNO) { SetDebugBreakHandlers(NULL, NULL); exit(1); } if (DebugBreak_callback_resume) (*DebugBreak_callback_resume)(); #endif // #ifndef RELEASE } // error message output function void error_Spew() { if (Exit_message[0]) Debug_MessageBox(OSMBOX_OK, Exit_title_str, Exit_message); } ////////////////////////////////////////////////////////////////////////////// // MESSAGE BOX SYSTEM char Messagebox_title[80] = "Message"; // Sets the title for future OutrageMessageBox() dialogs void SetMessageBoxTitle(const char *title) { strncpy(Messagebox_title, title, sizeof(Messagebox_title)); } #define BUF_LEN 1024 // Pops up a dialog box to display a message void OutrageMessageBox(const char *str, ...) { char buf[BUF_LEN]; std::va_list arglist; int nchars; va_start(arglist, str); nchars = std::vsnprintf(buf, BUF_LEN, str, arglist); va_end(arglist); if (nchars >= BUF_LEN) Debug_MessageBox(OSMBOX_OK, Messagebox_title, "The dialog that follows this one overflowed its text buffer. The program may crash."); Debug_MessageBox(OSMBOX_OK, Messagebox_title, buf); } int OutrageMessageBox(int type, const char *str, ...) { char buf[BUF_LEN]; std::va_list arglist; int os_flags = 0; int nchars; va_start(arglist, str); nchars = std::vsnprintf(buf, BUF_LEN, str, arglist); va_end(arglist); if (type == MBOX_OK) os_flags = OSMBOX_OK; else if (type == MBOX_YESNO) os_flags = OSMBOX_YESNO; else if (type == MBOX_YESNOCANCEL) os_flags = OSMBOX_YESNOCANCEL; else if (type == MBOX_ABORTRETRYIGNORE) os_flags = OSMBOX_ABORTRETRYIGNORE; else Int3(); if (nchars >= BUF_LEN) Debug_MessageBox(OSMBOX_OK, Messagebox_title, "The dialog that follows this one overflowed its text buffer. The program may crash."); return Debug_MessageBox(os_flags, Messagebox_title, buf); }