1 |
/* |
2 |
ASCEND Language Interpreter |
3 |
AscPanic by Mark Thomas, created 15 May 1997 |
4 |
Copyright (C) 2005 Carnegie-Mellon University |
5 |
|
6 |
This program is free software; you can redistribute it and/or modify |
7 |
it under the terms of the GNU General Public License as published by |
8 |
the Free Software Foundation; either version 2 of the License, or |
9 |
(at your option) any later version. |
10 |
|
11 |
This program is distributed in the hope that it will be useful, |
12 |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 |
GNU General Public License for more details. |
15 |
|
16 |
You should have received a copy of the GNU General Public License |
17 |
along with this program; if not, write to the Free Software |
18 |
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
19 |
This file is part of the SLV solver. |
20 |
*/ |
21 |
|
22 |
/* removed changelog -- please consult commit comments in ViewCVS */ |
23 |
|
24 |
#include <stdarg.h> |
25 |
#include "ascConfig.h" |
26 |
#include "ascPanic.h" |
27 |
|
28 |
#define PANIC_MSG_MAXLEN 2047 |
29 |
/**< The maximum length of the panic message. |
30 |
Used to create a buffer to hold the message. |
31 |
*/ |
32 |
|
33 |
static PanicCallbackFunc f_panic_callback_func = NULL; |
34 |
/**< Holds a pointer to a callback function if registered using |
35 |
Asc_PanicSetCallback(). If NULL (the default), nothing is called. |
36 |
*/ |
37 |
|
38 |
/* |
39 |
disable the windows message box... |
40 |
#if defined(__WIN32__) |
41 |
# define USE_WIN32_FATAL_MSGBOX |
42 |
#endif |
43 |
*/ |
44 |
|
45 |
#ifdef USE_WIN32_FATAL_MSGBOX |
46 |
static int f_display_MessageBox = TRUE; |
47 |
/**< On Windows only, flag to enable/disable display of the MessageBox |
48 |
in Asc_Panic(). |
49 |
*/ |
50 |
#endif |
51 |
|
52 |
static char g_panic_outfile[PATH_MAX]; |
53 |
/**< Holds the name of the file in which to write panic messages. |
54 |
Use the Asc_PanicSetOutfile(filename) function to set it. |
55 |
*/ |
56 |
|
57 |
|
58 |
/** |
59 |
This static function does the actual output of a PANIC message. It aims |
60 |
to do a few things to ensure that the user always gets the message. |
61 |
|
62 |
@TODO We could can improve even further by integrating with some crash |
63 |
reporting facility in GNOME, etc? |
64 |
*/ |
65 |
static void asc_va_panic(const int status, const char *filename, const int line |
66 |
, const char *function, const char *fmt, const va_list args |
67 |
){ |
68 |
FILE *outfile; /* The file to save the message into */ |
69 |
int cancel = FALSE; /* If non-zero, do not call exit(). Default is to exit() */ |
70 |
char msg[PANIC_MSG_MAXLEN]; |
71 |
size_t p; |
72 |
|
73 |
/* Fail loudly if ASCERR isn't set to a file pointer -- can't use asc_assert here! */ |
74 |
assert(NULL != ASCERR); |
75 |
|
76 |
p = snprintf(msg,PANIC_MSG_MAXLEN-2,"%s:%d (%s): ",filename,line,function); |
77 |
|
78 |
/* Add the variable args to the panic message using the format "format" */ |
79 |
vsnprintf(msg+p, PANIC_MSG_MAXLEN-p-2, fmt, args ); |
80 |
|
81 |
p = strlen(msg); |
82 |
msg[p++] = '\n'; |
83 |
msg[p++] = '\0'; |
84 |
|
85 |
/* |
86 |
Always write the message to g_panic_outfile if it is not empty |
87 |
and we can actually write to that location. Print a |
88 |
message on ASCERR (if valid) saying that we did that. |
89 |
*/ |
90 |
if(( *g_panic_outfile != '\0' ) |
91 |
&& ( (outfile=fopen(g_panic_outfile,"w")) != NULL ) |
92 |
){ |
93 |
fprintf(outfile, msg); |
94 |
CONSOLE_DEBUG("Error message written to %s\n", g_panic_outfile); |
95 |
|
96 |
fclose(outfile); |
97 |
} |
98 |
|
99 |
if (NULL == f_panic_callback_func) { |
100 |
/* No panic-callback, so we reset the error handler and output to console */ |
101 |
error_reporter_set_callback(NULL); |
102 |
|
103 |
/* Print the message to the default error reporter (ASCERR) */ |
104 |
fprintf(stderr,"\n\n"); |
105 |
va_error_reporter(ASC_PROG_FATAL,filename,line,function,fmt,args); |
106 |
fprintf(stderr,"\n"); |
107 |
|
108 |
}else{ |
109 |
/* just use the callback, don't make any output */ |
110 |
cancel = (*f_panic_callback_func)(status); |
111 |
if(cancel){ |
112 |
ERROR_REPORTER_HERE(ASC_PROG_ERR, |
113 |
"AscPanic 'cancel' facility has been disabled, program will exit" |
114 |
); |
115 |
} |
116 |
} |
117 |
|
118 |
/* Display msg in a MessageBox under Windows unless turned off */ |
119 |
#ifdef USE_WIN32_FATAL_MSGBOX |
120 |
if(FALSE != f_display_MessageBox) { |
121 |
(void)MessageBeep(MB_ICONEXCLAMATION); |
122 |
MessageBox(NULL, msg, "Fatal Error in ASCEND" |
123 |
,(UINT)(MB_ICONSTOP | MB_OK | MB_TASKMODAL | MB_SETFOREGROUND) |
124 |
); |
125 |
} |
126 |
#endif |
127 |
} |
128 |
|
129 |
/** |
130 |
This is a new replacement for Asc_Panic that handles error source |
131 |
details (line, file, function) itself. |
132 |
*/ |
133 |
void asc_panic_line(const int status, const char *filename, const int line |
134 |
, const char *function, const char *fmt, ... |
135 |
){ |
136 |
va_list args; |
137 |
|
138 |
va_start(args,fmt); |
139 |
asc_va_panic(status,filename,line,function,fmt,args); |
140 |
va_end(args); |
141 |
|
142 |
#ifdef USE_WIN32_FATAL_MSGBOX |
143 |
ExitProcess((UINT)status); |
144 |
#else |
145 |
# ifndef NDEBUG |
146 |
abort(); |
147 |
# else |
148 |
exit(status); |
149 |
# endif |
150 |
#endif |
151 |
} |
152 |
|
153 |
#if defined(__GNUC__) && !defined(__STRICT_ANSI__) |
154 |
/** |
155 |
we only need this function if our platform doesn't support var-arg macros |
156 |
*/ |
157 |
void asc_panic(CONST int status, CONST CONST char *function |
158 |
,CONST char *fmt, ... |
159 |
){ |
160 |
va_list args; |
161 |
|
162 |
va_start(args,fmt); |
163 |
asc_va_panic(status,NULL,0,function,fmt,args); |
164 |
va_end(args); |
165 |
# ifdef USE_WIN32_FATAL_MSGBOX |
166 |
ExitProcess((UINT)status); |
167 |
# else |
168 |
# ifndef NDEBUG |
169 |
abort(); |
170 |
# else |
171 |
exit(status); |
172 |
# endif |
173 |
# endif |
174 |
} |
175 |
#endif |
176 |
|
177 |
void Asc_PanicSetOutfile(CONST char *filename) |
178 |
{ |
179 |
if( filename != NULL ) { |
180 |
strncpy( g_panic_outfile, filename, PATH_MAX-1 ); |
181 |
g_panic_outfile[PATH_MAX-1] = '\0'; |
182 |
} else { |
183 |
g_panic_outfile[0] = '\0'; |
184 |
} |
185 |
} |
186 |
|
187 |
PanicCallbackFunc Asc_PanicSetCallback(PanicCallbackFunc func) |
188 |
{ |
189 |
PanicCallbackFunc old_func = f_panic_callback_func; |
190 |
f_panic_callback_func = func; |
191 |
return old_func; |
192 |
} |
193 |
|
194 |
|
195 |
void Asc_PanicDisplayMessageBox(int is_displayed) |
196 |
{ |
197 |
#ifdef USE_WIN32_FATAL_MSGBOX |
198 |
f_display_MessageBox = is_displayed; |
199 |
#else |
200 |
UNUSED_PARAMETER(is_displayed); |
201 |
#endif |
202 |
} |