/[ascend]/trunk/base/generic/utilities/ascPanic.c
ViewVC logotype

Contents of /trunk/base/generic/utilities/ascPanic.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 100 - (show annotations) (download) (as text)
Fri Dec 9 23:25:15 2005 UTC (18 years, 9 months ago) by jds
File MIME type: text/x-csrc
File size: 7395 byte(s)
ascMalloc now working on Linux.
Fixed minor bugs in ascPanic.c, test suite functions.
1 /*
2 * Ascend Panic
3 * by Mark Thomas
4 * Created: 1997.05.15
5 * Version: $Revision: 1.1 $
6 * Version control file: $RCSfile: ascPanic.c,v $
7 * Date last modified: $Date: 1997/07/18 11:43:21 $
8 * Last modified by: $Author: mthomas $
9 *
10 * This file is part of the Ascend Language Interpreter.
11 *
12 * Copyright (C) 1997 Carnegie Mellon University
13 *
14 * The Ascend Language Interpreter is free software; you can redistribute
15 * it and/or modify it under the terms of the GNU General Public License as
16 * published by the Free Software Foundation; either version 2 of the
17 * License, or (at your option) any later version.
18 *
19 * The Ascend Language Interpreter is distributed in hope that it will be
20 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with the program; if not, write to the Free Software Foundation,
26 * Inc., 675 Mass Ave, Cambridge, MA 02139 USA. Check the file named
27 * COPYING.
28 *
29 */
30
31 /* ChangeLog
32 *
33 * 10/13/2005 Added callback functionality & ability to cancel exit()
34 * for use in unit test. Changed sprintf's to snprintf's
35 * to avoid buffer overflow (J.D. St.Clair)
36 */
37
38 #include <stdarg.h>
39 #include "utilities/ascConfig.h"
40 #include "utilities/ascPanic.h"
41
42 /* PANIC_MSG_MAXLEN
43 * The maximum length of the panic message. Used to create a buffer
44 * to hold the message.
45 */
46 #define PANIC_MSG_MAXLEN 2047
47
48
49 /* THIS IS SUPERCEDED BY EXTERNAL UNIT TEST FOR ascPanic.c */
50 /* PANIC_TEST
51 * Define this cpp macro to build a standalone program to test the
52 * panic functions---since they shouldn't be called during normal
53 * operation: cc -DPANIC_TEST -I.. ascpanic.c -o panictest
54 *
55 * TEST_OUTPUT_GOOD is a writable file to write a panic message to
56 * TEST_OUTPUT_BAD is an unwritable file to write a panic message to
57 */
58 #ifdef PANIC_TEST
59 FILE *ASCERR = stderr;
60 #define exit(x) FPRINTF(ASCERR, "<<<call exit(%d) if !test>>>\n", (x)); return
61 #define TEST_OUTPUT_GOOD "/tmp/Asc_Panic.out"
62 #define TEST_OUTPUT_BAD "/foo/bar/baz/cow/grumble/Asc_Panic.out"
63 #endif /* PANIC_TEST */
64
65 /*
66 * f_panic_callback_func
67 * Holds a pointer to a callback function if registered using
68 * Asc_PanicSetCallback(). If NULL (the default), nothing is called.
69 */
70 static PanicCallbackFunc f_panic_callback_func = NULL;
71
72 #ifdef __WIN32__
73 /*
74 * On Windows only, flag to enable/disable display of the MessageBox
75 * in Asc_Panic().
76 */
77 static int f_display_MessageBox = TRUE;
78 #endif
79
80 /*
81 * g_panic_output
82 * Holds the name of the file in which to write panic messages.
83 * Use the Asc_PanicSetOutfile(filename) function to set it.
84 */
85 static char g_panic_outfile[PATH_MAX];
86
87
88 void Asc_Panic(CONST int status, CONST char *function,
89 CONST char *format, ...)
90 {
91 char msg[PANIC_MSG_MAXLEN]; /* The message that will be printed */
92 size_t p; /* The current length of the msg array */
93 FILE *outfile; /* The file to save the message into */
94 va_list args; /* The arguments to print */
95 int cancel = FALSE; /* If non-zero, do not call exit(). Default is to exit() */
96
97 assert(NULL != ASCERR); /* fail loudly so know can't write msg. Can't use asc_assert(). */
98 /*
99 * Give the name of the function where the panic occurred
100 */
101 if( function != NULL ) {
102 snprintf( msg, PANIC_MSG_MAXLEN-2, "ASCEND PANIC!! in function \"%s\"\n", function );
103 } else {
104 snprintf( msg, PANIC_MSG_MAXLEN-2, "ASCEND PANIC!!\n" );
105 }
106 p = strlen(msg);
107
108 /*
109 * Add the variable args to the panic message using the format "format"
110 */
111 va_start(args, format);
112 vsnprintf( (msg+p), PANIC_MSG_MAXLEN-p-2, format, args );
113 va_end(args);
114
115 p = strlen(msg);
116 msg[p++] = '\n';
117 msg[p++] = '\0';
118
119 /*
120 * Print the message to ASCERR
121 */
122 if (ASCERR != NULL)
123 FPRINTF(ASCERR, msg);
124
125 /*
126 * Write the message to g_panic_outfile if it is not empty
127 * and we can actually write to that location. Print a
128 * message on ASCERR (if valid) saying that we did that.
129 */
130 if(( g_panic_outfile[0] != '\0' )
131 && ( (outfile=fopen(g_panic_outfile,"w")) != NULL ))
132 {
133 FPRINTF(outfile, msg);
134 if( ASCERR != NULL ) {
135 FPRINTF(ASCERR, "ASCEND PANIC: Error message written to %s\n", g_panic_outfile);
136 }
137 fclose(outfile);
138 }
139
140 /*
141 * Call the registered callback function, if any.
142 */
143 if (NULL != f_panic_callback_func) {
144 cancel = (*f_panic_callback_func)(status);
145 }
146
147 #ifdef __WIN32__
148 /*
149 * Display msg in a MessageBox under Windows unless turned off
150 */
151 if (FALSE != f_display_MessageBox) {
152 (void)MessageBeep(MB_ICONEXCLAMATION);
153 MessageBox(NULL, msg, "Fatal Error in ASCEND",
154 (UINT)(MB_ICONSTOP | MB_OK | MB_TASKMODAL | MB_SETFOREGROUND));
155 }
156 if (0 == cancel)
157 ExitProcess((UINT)status);
158 #endif
159
160 if (0 == cancel)
161 exit(status);
162 }
163
164
165 void Asc_PanicSetOutfile(CONST char *filename)
166 {
167 if( filename != NULL ) {
168 strncpy( g_panic_outfile, filename, PATH_MAX-1 );
169 g_panic_outfile[PATH_MAX-1] = '\0';
170 } else {
171 g_panic_outfile[0] = '\0';
172 }
173 }
174
175 PanicCallbackFunc Asc_PanicSetCallback(PanicCallbackFunc func)
176 {
177 PanicCallbackFunc old_func = f_panic_callback_func;
178 f_panic_callback_func = func;
179 return old_func;
180 }
181
182
183 void Asc_PanicDisplayMessageBox(int TRUE_or_FALSE)
184 {
185 #ifdef __WIN32__
186 f_display_MessageBox = TRUE_or_FALSE;
187 #else
188 UNUSED_PARAMETER(TRUE_or_FALSE);
189 #endif
190 }
191
192 /* THIS IS SUPERCEDED BY EXTERNAL UNIT TEST FOR ascPanic.c */
193 #ifdef PANIC_TEST
194 /*
195 * main
196 * A test driver for Asc_Panic() and Asc_PanicSetOutfile(). Needed
197 * since we should never actually call Asc_Panic under normal
198 * operation. (HA HA!)
199 */
200 int main(void)
201 {
202 PRINTF("==>Testing Asc_Panic with no output file and single arg\n");
203 Asc_Panic(1, NULL, "Message generate by Asc_Panic, single string arg\n");
204 PRINTF("<==\n");
205
206 PRINTF("==>Testing Asc_Panic with no output file and multiple args\n");
207 Asc_Panic(2, "main",
208 "%s%s\n\t%d%s%d%s\n", "Message generated by ", "Asc_Panic,",
209 5, " string args and ", 3, " integer args");
210 PRINTF("<==\n");
211
212 PRINTF("==>Testing Asc_Panic with mismatched format/args: too many args\n");
213 Asc_Panic(3, "main",
214 "%s%s%s\n", "Message generated by ", "Asc_Panic, ",
215 "too many args", " for format");
216 PRINTF("<==\n");
217
218 PRINTF("==>Testing Asc_Panic with mismatched format/args: too few args\n");
219 Asc_Panic(4, NULL,
220 "%s%s%s%s\n", "Message generated by ", "Asc_Panic, ",
221 "too few args");
222 PRINTF("<==\n");
223
224 PRINTF("==>Testing Asc_Panic with file %s\n", TEST_OUTPUT_GOOD);
225 Asc_PanicSetOutfile(TEST_OUTPUT_GOOD);
226 Asc_Panic(5, NULL,
227 "%s%s\n\t%s%s\n", "Message generated by ", "Asc_Panic, ",
228 "should be written into ", TEST_OUTPUT_GOOD);
229 PRINTF("<==\n");
230
231 PRINTF("==>Testing Asc_Panic with file %s\n", TEST_OUTPUT_BAD);
232 Asc_PanicSetOutfile(TEST_OUTPUT_BAD);
233 Asc_Panic(6, "main",
234 "Message generated by Asc_Panic\n"
235 "\tWrite to unwritable file %s", TEST_OUTPUT_BAD);
236 PRINTF("<==\n");
237
238 PRINTF(">>End of tests\n");
239 return 0;
240 }
241 #endif /* PANIC_TEST */

john.pye@anu.edu.au
ViewVC Help
Powered by ViewVC 1.1.22