1 /* ------------------------------------------------------------------------
2 @NAME : error.c
3 @DESCRIPTION: Anything relating to reporting or recording errors and
4 warnings.
5 @GLOBALS : errclass_names
6 err_actions
7 err_handlers
8 errclass_counts
9 error_buf
10 @CALLS :
11 @CREATED : 1996/08/28, Greg Ward
12 @MODIFIED :
13 @VERSION : $Id: error.c 640 1999-11-29 01:13:10Z greg $
14 @COPYRIGHT : Copyright (c) 1996-99 by Gregory P. Ward. All rights reserved.
15
16 This file is part of the btparse library. This library is
17 free software; you can redistribute it and/or modify it under
18 the terms of the GNU Library General Public License as
19 published by the Free Software Foundation; either version 2
20 of the License, or (at your option) any later version.
21 -------------------------------------------------------------------------- */
22
23 #include "bt_config.h"
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <stdarg.h>
27 #include <string.h>
28 #include "btparse.h"
29 #include "error.h"
30 #include "my_dmalloc.h"
31
32
33 #define NUM_ERRCLASSES ((int) BTERR_INTERNAL + 1)
34
35
36 static char *errclass_names[NUM_ERRCLASSES] =
37 {
38 NULL, /* BTERR_NOTIFY */
39 "warning", /* BTERR_CONTENT */
40 "warning", /* BTERR_LEXWARN */
41 "warning", /* BTERR_USAGEWARN */
42 "error", /* BTERR_LEXERR */
43 "syntax error", /* BTERR_SYNTAX */
44 "fatal error", /* BTERR_USAGEERR */
45 "internal error" /* BTERR_INTERNAL */
46 };
47
48 static bt_erraction err_actions[NUM_ERRCLASSES] =
49 {
50 BTACT_NONE, /* BTERR_NOTIFY */
51 BTACT_NONE, /* BTERR_CONTENT */
52 BTACT_NONE, /* BTERR_LEXWARN */
53 BTACT_NONE, /* BTERR_USAGEWARN */
54 BTACT_NONE, /* BTERR_LEXERR */
55 BTACT_NONE, /* BTERR_SYNTAX */
56 BTACT_CRASH, /* BTERR_USAGEERR */
57 BTACT_ABORT /* BTERR_INTERNAL */
58 };
59
60 void print_error (bt_error *err);
61
62 static bt_err_handler err_handlers[NUM_ERRCLASSES] =
63 {
64 print_error,
65 print_error,
66 print_error,
67 print_error,
68 print_error,
69 print_error,
70 print_error,
71 print_error
72 };
73
74 static int errclass_counts[NUM_ERRCLASSES] = { 0, 0, 0, 0, 0, 0, 0, 0 };
75 static char error_buf[MAX_ERROR+1];
76
77
78 /* ----------------------------------------------------------------------
79 * Error-handling functions.
80 */
81
print_error(bt_error * err)82 void print_error (bt_error *err)
83 {
84 char * name;
85 boolean something_printed;
86
87 something_printed = FALSE;
88
89 if (err->filename)
90 {
91 fprintf (stderr, err->filename);
92 something_printed = TRUE;
93 }
94 if (err->line > 0) /* going to print a line number? */
95 {
96 if (something_printed)
97 fprintf (stderr, ", ");
98 fprintf (stderr, "line %d", err->line);
99 something_printed = TRUE;
100 }
101 if (err->item_desc && err->item > 0) /* going to print an item number? */
102 {
103 if (something_printed)
104 fprintf (stderr, ", ");
105 fprintf (stderr, "%s %d", err->item_desc, err->item);
106 something_printed = TRUE;
107 }
108
109 name = errclass_names[(int) err->class];
110 if (name)
111 {
112 if (something_printed)
113 fprintf (stderr, ", ");
114 fprintf (stderr, name);
115 something_printed = TRUE;
116 }
117
118 if (something_printed)
119 fprintf (stderr, ": ");
120
121 fprintf (stderr, "%s\n", err->message);
122
123 } /* print_error() */
124
125
126
127 /* ----------------------------------------------------------------------
128 * Error-reporting functions: these are called anywhere in the library
129 * when we encounter an error.
130 */
131
132 void
report_error(bt_errclass class,char * filename,int line,char * item_desc,int item,char * fmt,va_list arglist)133 report_error (bt_errclass class,
134 char * filename,
135 int line,
136 char * item_desc,
137 int item,
138 char * fmt,
139 va_list arglist)
140 {
141 bt_error err;
142 #if !HAVE_VSNPRINTF
143 int msg_len;
144 #endif
145
146 err.class = class;
147 err.filename = filename;
148 err.line = line;
149 err.item_desc = item_desc;
150 err.item = item;
151
152 errclass_counts[(int) class]++;
153
154
155 /*
156 * Blech -- we're writing to a static buffer because there's no easy
157 * way to know how long the error message is going to be. (Short of
158 * reimplementing printf(), or maybe printf()'ing to a dummy file
159 * and using the return value -- ugh!) The GNU C library conveniently
160 * supplies vsnprintf(), which neatly solves this problem by truncating
161 * the output string if it gets too long. (I could check for this
162 * truncation if I wanted to, but I don't think it's necessary given the
163 * ample size of the message buffer.) For non-GNU systems, though,
164 * we're stuck with using vsprintf()'s return value. This can't be
165 * trusted on all systems -- thus there's a check for it in configure.
166 * Also, this won't necessarily trigger the internal_error() if we
167 * do overflow; it's conceivable that vsprintf() itself would crash.
168 * At least doing it this way we avoid the possibility of vsprintf()
169 * silently corrupting some memory, and crashing unpredictably at some
170 * later point.
171 */
172
173 #if HAVE_VSNPRINTF
174 vsnprintf (error_buf, MAX_ERROR, fmt, arglist);
175 #else
176 msg_len = vsprintf (error_buf, fmt, arglist);
177 if (msg_len > MAX_ERROR)
178 internal_error ("static error message buffer overflowed");
179 #endif
180
181 err.message = error_buf;
182 if (err_handlers[class])
183 (*err_handlers[class]) (&err);
184
185 switch (err_actions[class])
186 {
187 case BTACT_NONE: return;
188 case BTACT_CRASH: exit (1);
189 case BTACT_ABORT: abort ();
190 default: internal_error ("invalid error action %d for class %d (%s)",
191 (int) err_actions[class],
192 (int) class, errclass_names[class]);
193 }
194
195 } /* report_error() */
196
197
198 GEN_ERRFUNC (general_error,
199 (bt_errclass class,
200 char * filename,
201 int line,
202 char * item_desc,
203 int item,
204 char * fmt,
205 ...),
206 class, filename, line, item_desc, item, fmt)
207
208 GEN_ERRFUNC (error,
209 (bt_errclass class,
210 char * filename,
211 int line,
212 char * fmt,
213 ...),
214 class, filename, line, NULL, -1, fmt)
215
216 GEN_ERRFUNC (ast_error,
217 (bt_errclass class,
218 AST * ast,
219 char * fmt,
220 ...),
221 class, ast->filename, ast->line, NULL, -1, fmt)
222
223 GEN_ERRFUNC (notify,
224 (char * fmt, ...),
225 BTERR_NOTIFY, NULL, -1, NULL, -1, fmt)
226
227 GEN_ERRFUNC (usage_warning,
228 (char * fmt, ...),
229 BTERR_USAGEWARN, NULL, -1, NULL, -1, fmt)
230
231 GEN_ERRFUNC (usage_error,
232 (char * fmt, ...),
233 BTERR_USAGEERR, NULL, -1, NULL, -1, fmt)
234
235 GEN_ERRFUNC (internal_error,
236 (char * fmt, ...),
237 BTERR_INTERNAL, NULL, -1, NULL, -1, fmt)
238
239
240 /* ======================================================================
241 * Functions to be used outside of the library
242 */
243
244 /* ------------------------------------------------------------------------
245 @NAME : bt_reset_error_counts()
246 @INPUT :
247 @OUTPUT :
248 @RETURNS :
249 @DESCRIPTION: Resets all the error counters to zero.
250 @GLOBALS :
251 @CALLS :
252 @CREATED : 1997/01/08, GPW
253 @MODIFIED :
254 -------------------------------------------------------------------------- */
bt_reset_error_counts(void)255 void bt_reset_error_counts (void)
256 {
257 int i;
258
259 for (i = 0; i < NUM_ERRCLASSES; i++)
260 errclass_counts[i] = 0;
261 }
262
263
264 /* ------------------------------------------------------------------------
265 @NAME : bt_get_error_count()
266 @INPUT : errclass
267 @OUTPUT :
268 @RETURNS :
269 @DESCRIPTION: Returns number of errors seen in the specified class.
270 @GLOBALS : errclass_counts
271 @CALLS :
272 @CREATED :
273 @MODIFIED :
274 -------------------------------------------------------------------------- */
bt_get_error_count(bt_errclass errclass)275 int bt_get_error_count (bt_errclass errclass)
276 {
277 return errclass_counts[errclass];
278 }
279
280
281 /* ------------------------------------------------------------------------
282 @NAME : bt_get_error_counts()
283 @INPUT : counts - pointer to an array big enough to hold all the counts
284 if NULL, the array will be allocated for you (and you
285 must free() it when done with it)
286 @OUTPUT :
287 @RETURNS : counts - either the passed-in pointer, or the newly-
288 allocated array if you pass in NULL
289 @DESCRIPTION: Returns a newly-allocated array with the number of errors
290 in each error class, indexed by the members of the
291 eclass_t enum.
292 @GLOBALS : errclass_counts
293 @CALLS :
294 @CREATED : 1997/01/06, GPW
295 @MODIFIED :
296 -------------------------------------------------------------------------- */
bt_get_error_counts(int * counts)297 int *bt_get_error_counts (int *counts)
298 {
299 int i;
300
301 if (counts == NULL)
302 counts = (int *) malloc (sizeof (int) * NUM_ERRCLASSES);
303 for (i = 0; i < NUM_ERRCLASSES; i++)
304 counts[i] = errclass_counts[i];
305
306 return counts;
307 }
308
309
310 /* ------------------------------------------------------------------------
311 @NAME : bt_error_status
312 @INPUT : saved_counts - an array of error counts as returned by
313 bt_get_error_counts, or NULL not to compare
314 to a previous checkpoint
315 @OUTPUT :
316 @RETURNS :
317 @DESCRIPTION: Computes a bitmap where a bit is set for each error class
318 that has more errors now than it used to have (or, if
319 saved_counts is NULL, the bit is set of there are have been
320 any errors in the corresponding error class).
321
322 Eg. "x & (1<<E_SYNTAX)" (where x is returned by bt_error_status)
323 is true if there have been any syntax errors.
324 @GLOBALS :
325 @CALLS :
326 @CREATED :
327 @MODIFIED :
328 -------------------------------------------------------------------------- */
bt_error_status(int * saved_counts)329 ushort bt_error_status (int *saved_counts)
330 {
331 int i;
332 ushort status;
333
334 status = 0;
335
336 if (saved_counts)
337 {
338 for (i = 0; i < NUM_ERRCLASSES; i++)
339 status |= ( (errclass_counts[i] > saved_counts[i]) << i);
340 }
341 else
342 {
343 for (i = 0; i < NUM_ERRCLASSES; i++)
344 status |= ( (errclass_counts[i] > 0) << i);
345 }
346
347 return status;
348 } /* bt_error_status () */
349